mirror of
https://github.com/UpsilonNumworks/Upsilon.git
synced 2026-03-18 21:30:38 +01:00
[Git] Fix conflicts
This commit is contained in:
@@ -24,13 +24,8 @@ void ComplexGraphView::drawRect(KDContext * ctx, KDRect rect) const {
|
||||
float imag = m_complex->imag();
|
||||
|
||||
assert(!std::isnan(real) && !std::isnan(imag) && !std::isinf(real) && !std::isinf(imag));
|
||||
/* Draw the segment from the origin to the dot (real, imag) of equation
|
||||
* x(t) = t*real and y(t) = t*imag with t in [0,1] */
|
||||
drawCurve(ctx, rect, 0.0f, 1.0f, 0.01f,
|
||||
[](float t, void * model, void * context) {
|
||||
ComplexModel * complexModel = (ComplexModel *)model;
|
||||
return Poincare::Coordinate2D<float>(complexModel->real()*t, complexModel->imag()*t);
|
||||
}, m_complex, nullptr, false, Palette::GreyDark, false);
|
||||
// Draw the segment from the origin to the dot (real, imag)
|
||||
drawSegment(ctx, rect, 0.0f, 0.0f, m_complex->real(), m_complex->imag(), Palette::GreyDark, false);
|
||||
|
||||
/* Draw the partial ellipse indicating the angle θ
|
||||
* - the ellipse parameters are a = |real|/5 and b = |imag|/5,
|
||||
@@ -66,8 +61,8 @@ void ComplexGraphView::drawRect(KDContext * ctx, KDRect rect) const {
|
||||
}, ¶meters, &th, false, Palette::GreyDark, false);
|
||||
|
||||
// Draw dashed segment to indicate real and imaginary
|
||||
drawSegment(ctx, rect, Axis::Vertical, real, 0.0f, imag, Palette::Red, 1, 3);
|
||||
drawSegment(ctx, rect, Axis::Horizontal, imag, 0.0f, real, Palette::Red, 1, 3);
|
||||
drawHorizontalOrVerticalSegment(ctx, rect, Axis::Vertical, real, 0.0f, imag, Palette::Red, 1, 3);
|
||||
drawHorizontalOrVerticalSegment(ctx, rect, Axis::Horizontal, imag, 0.0f, real, Palette::Red, 1, 3);
|
||||
|
||||
// Draw complex position on the plan
|
||||
drawDot(ctx, rect, real, imag, Palette::Red, Size::Large);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -13,12 +13,15 @@ PythonAbs = "Absolute/r Wert/Größe"
|
||||
PythonAcos = "Arkuskosinus"
|
||||
PythonAcosh = "Hyperbelkosinus"
|
||||
PythonAppend = "Hängt x an das Ende der Liste"
|
||||
PythonArrow = "Arrow from (x,y) to (x+dx,y+dy)"
|
||||
PythonAsin = "Arkussinus"
|
||||
PythonAsinh = "Hyperbelsinus"
|
||||
PythonAtan = "Arkustangens"
|
||||
PythonAtan2 = "Gib atan(y/x)"
|
||||
PythonAtanh = "Hyperbeltangens"
|
||||
PythonBin = "Ganzzahl nach binär"
|
||||
PythonAxis = "Set axes to (xmin,xmax,ymin,ymax)"
|
||||
PythonBar = "Draw a bar plot with x values"
|
||||
PythonBin = "Ganzzahl nach binär konvertieren"
|
||||
PythonCeil = "Aufrundung"
|
||||
PythonChoice = "Zufallszahl aus der Liste"
|
||||
PythonClear = "Leere die Liste"
|
||||
@@ -46,12 +49,15 @@ PythonFrExp = "Rest und Exponent von x"
|
||||
PythonGamma = "Gammafunktion"
|
||||
PythonGetPixel = "Farbe von Pixel (x,y)"
|
||||
PythonGetrandbits = "Ganzzahl mit k zufälligen Bits"
|
||||
PythonGrid = "Toggle the visibility of the grid"
|
||||
PythonHex = "Ganzzahl zu Hexadecimal"
|
||||
PythonHist = "Draw the histogram of x"
|
||||
PythonImportCmath = "cmath Modul importieren"
|
||||
PythonImportIon = "ion Modul importieren"
|
||||
PythonImportKandinsky = "kandinsky Modul importieren"
|
||||
PythonImportRandom = "random Modul importieren"
|
||||
PythonImportMath = "math Modul importieren"
|
||||
PythonImportMatplotlibPyplot = "Import matplotlib.pyplot module"
|
||||
PythonImportTime = "time Modul importieren"
|
||||
PythonImportTurtle = "turtle Modul importieren"
|
||||
PythonIndex = "Index, bei dem x zuerst vorkommt"
|
||||
@@ -117,12 +123,14 @@ PythonLog = "Logarithm to base a"
|
||||
PythonLog10 = "Logarithm to base 10"
|
||||
PythonLog2 = "Logarithm to base 2"
|
||||
PythonMathFunction = "math module function prefix"
|
||||
PythonMatplotlibPyplotFunction = "matplotlib.pyplot module prefix"
|
||||
PythonMax = "Maximum"
|
||||
PythonMin = "Minimum"
|
||||
PythonModf = "Fractional and integer parts of x"
|
||||
PythonMonotonic = "Value of a monotonic clock"
|
||||
PythonOct = "Convert integer to octal"
|
||||
PythonPhase = "Phase of z"
|
||||
PythonPlot = "Plot y versus x as lines"
|
||||
PythonPolar = "z in polar coordinates"
|
||||
PythonPop = "Remove and return the last item"
|
||||
PythonPower = "x raised to the power y"
|
||||
@@ -138,9 +146,11 @@ PythonRect = "z in cartesian coordinates"
|
||||
PythonRemove = "Remove the first occurrence of x"
|
||||
PythonReverse = "Reverse the elements of the list"
|
||||
PythonRound = "Round to n digits"
|
||||
PythonScatter = "Draw a scatter plot of y versus x"
|
||||
PythonSeed = "Initialize random number generator"
|
||||
PythonSetPixel = "Color pixel (x,y)"
|
||||
PythonSin = "Sinus"
|
||||
PythonShow = "Display the figure"
|
||||
PythonSin = "Sine"
|
||||
PythonSinh = "Hyperbolic sine"
|
||||
PythonSleep = "Suspend the execution for t seconds"
|
||||
PythonSort = "Sort the list"
|
||||
@@ -148,6 +158,7 @@ PythonSqrt = "Wurzel"
|
||||
PythonSum = "Sum the items of a list"
|
||||
PythonTan = "Tangens"
|
||||
PythonTanh = "Hyperbolic tangent"
|
||||
PythonText = "Display a text at (x,y) coordinates"
|
||||
PythonTimeFunction = "time module function prefix"
|
||||
PythonTrunc = "x truncated to an integer"
|
||||
PythonTurtleBackward = "Move backward by x pixels"
|
||||
|
||||
@@ -13,11 +13,14 @@ PythonAbs = "Absolute value/Magnitude"
|
||||
PythonAcos = "Arc cosine"
|
||||
PythonAcosh = "Arc hyperbolic cosine"
|
||||
PythonAppend = "Add x to the end of the list"
|
||||
PythonArrow = "Arrow from (x,y) to (x+dx,y+dy)"
|
||||
PythonAsin = "Arc sine"
|
||||
PythonAsinh = "Arc hyperbolic sine"
|
||||
PythonAtan = "Arc tangent"
|
||||
PythonAtan2 = "Return atan(y/x)"
|
||||
PythonAtanh = "Arc hyperbolic tangent"
|
||||
PythonAxis = "Set axes to (xmin,xmax,ymin,ymax)"
|
||||
PythonBar = "Draw a bar plot with x values"
|
||||
PythonBin = "Convert integer to binary"
|
||||
PythonCeil = "Ceiling"
|
||||
PythonChoice = "Random number in the list"
|
||||
@@ -46,12 +49,15 @@ PythonFrExp = "Mantissa and exponent of x"
|
||||
PythonGamma = "Gamma function"
|
||||
PythonGetPixel = "Return pixel (x,y) color"
|
||||
PythonGetrandbits = "Integer with k random bits"
|
||||
PythonGrid = "Toggle the visibility of the grid"
|
||||
PythonHex = "Convert integer to hexadecimal"
|
||||
PythonHist = "Draw the histogram of x"
|
||||
PythonImportCmath = "Import cmath module"
|
||||
PythonImportIon = "Import ion module"
|
||||
PythonImportKandinsky = "Import kandinsky module"
|
||||
PythonImportRandom = "Import random module"
|
||||
PythonImportMath = "Import math module"
|
||||
PythonImportMatplotlibPyplot = "Import matplotlib.pyplot module"
|
||||
PythonImportTime = "Import time module"
|
||||
PythonImportTurtle = "Import turtle module"
|
||||
PythonIndex = "Index of the first x occurrence"
|
||||
@@ -117,12 +123,14 @@ PythonLog = "Logarithm to base a"
|
||||
PythonLog10 = "Logarithm to base 10"
|
||||
PythonLog2 = "Logarithm to base 2"
|
||||
PythonMathFunction = "math module function prefix"
|
||||
PythonMatplotlibPyplotFunction = "matplotlib.pyplot module prefix"
|
||||
PythonMax = "Maximum"
|
||||
PythonMin = "Minimum"
|
||||
PythonModf = "Fractional and integer parts of x"
|
||||
PythonMonotonic = "Value of a monotonic clock"
|
||||
PythonOct = "Convert integer to octal"
|
||||
PythonPhase = "Phase of z"
|
||||
PythonPlot = "Plot y versus x as lines"
|
||||
PythonPolar = "z in polar coordinates"
|
||||
PythonPop = "Remove and return the last item"
|
||||
PythonPower = "x raised to the power y"
|
||||
@@ -138,8 +146,10 @@ PythonRect = "z in cartesian coordinates"
|
||||
PythonRemove = "Remove the first occurrence of x"
|
||||
PythonReverse = "Reverse the elements of the list"
|
||||
PythonRound = "Round to n digits"
|
||||
PythonScatter = "Draw a scatter plot of y versus x"
|
||||
PythonSeed = "Initialize random number generator"
|
||||
PythonSetPixel = "Color pixel (x,y)"
|
||||
PythonShow = "Display the figure"
|
||||
PythonSin = "Sine"
|
||||
PythonSinh = "Hyperbolic sine"
|
||||
PythonSleep = "Suspend the execution for t seconds"
|
||||
@@ -148,6 +158,7 @@ PythonSqrt = "Square root"
|
||||
PythonSum = "Sum the items of a list"
|
||||
PythonTan = "Tangent"
|
||||
PythonTanh = "Hyperbolic tangent"
|
||||
PythonText = "Display a text at (x,y) coordinates"
|
||||
PythonTimeFunction = "time module function prefix"
|
||||
PythonTrunc = "x truncated to an integer"
|
||||
PythonTurtleBackward = "Move backward by x pixels"
|
||||
|
||||
@@ -13,11 +13,14 @@ PythonAbs = "Absolute value/Magnitude"
|
||||
PythonAcos = "Arc cosine"
|
||||
PythonAcosh = "Arc hyperbolic cosine"
|
||||
PythonAppend = "Add x to the end of the list"
|
||||
PythonArrow = "Arrow from (x,y) to (x+dx,y+dy)"
|
||||
PythonAsin = "Arc sine"
|
||||
PythonAsinh = "Arc hyperbolic sine"
|
||||
PythonAtan = "Arc tangent"
|
||||
PythonAtan2 = "Return atan(y/x)"
|
||||
PythonAtanh = "Arc hyperbolic tangent"
|
||||
PythonAxis = "Set axes to (xmin,xmax,ymin,ymax)"
|
||||
PythonBar = "Draw a bar plot with x values"
|
||||
PythonBin = "Convert integer to binary"
|
||||
PythonCeil = "Ceiling"
|
||||
PythonChoice = "Random number in the list"
|
||||
@@ -46,12 +49,15 @@ PythonFrExp = "Mantissa and exponent of x"
|
||||
PythonGamma = "Gamma function"
|
||||
PythonGetPixel = "Return pixel (x,y) color"
|
||||
PythonGetrandbits = "Integer with k random bits"
|
||||
PythonGrid = "Toggle the visibility of the grid"
|
||||
PythonHex = "Convert integer to hexadecimal"
|
||||
PythonHist = "Draw the histogram of x"
|
||||
PythonImportCmath = "Import cmath module"
|
||||
PythonImportIon = "Import ion module"
|
||||
PythonImportKandinsky = "Import kandinsky module"
|
||||
PythonImportRandom = "Import random module"
|
||||
PythonImportMath = "Import math module"
|
||||
PythonImportMatplotlibPyplot = "Import matplotlib.pyplot module"
|
||||
PythonImportTime = "Import time module"
|
||||
PythonImportTurtle = "Import turtle module"
|
||||
PythonIndex = "Index of the first x occurrence"
|
||||
@@ -117,12 +123,14 @@ PythonLog = "Logarithm to base a"
|
||||
PythonLog10 = "Logarithm to base 10"
|
||||
PythonLog2 = "Logarithm to base 2"
|
||||
PythonMathFunction = "math module function prefix"
|
||||
PythonMatplotlibPyplotFunction = "matplotlib.pyplot module prefix"
|
||||
PythonMax = "Maximum"
|
||||
PythonMin = "Minimum"
|
||||
PythonModf = "Fractional and integer parts of x"
|
||||
PythonMonotonic = "Value of a monotonic clock"
|
||||
PythonOct = "Convert integer to octal"
|
||||
PythonPhase = "Phase of z"
|
||||
PythonPlot = "Plot y versus x as lines"
|
||||
PythonPolar = "z in polar coordinates"
|
||||
PythonPop = "Remove and return the last item"
|
||||
PythonPower = "x raised to the power y"
|
||||
@@ -138,8 +146,10 @@ PythonRect = "z in cartesian coordinates"
|
||||
PythonRemove = "Remove the first occurrence of x"
|
||||
PythonReverse = "Reverse the elements of the list"
|
||||
PythonRound = "Round to n digits"
|
||||
PythonScatter = "Draw a scatter plot of y versus x"
|
||||
PythonSeed = "Initialize random number generator"
|
||||
PythonSetPixel = "Color pixel (x,y)"
|
||||
PythonShow = "Display the figure"
|
||||
PythonSin = "Sine"
|
||||
PythonSinh = "Hyperbolic sine"
|
||||
PythonSleep = "Suspend the execution for t seconds"
|
||||
@@ -148,6 +158,7 @@ PythonSqrt = "Square root"
|
||||
PythonSum = "Sum the items of a list"
|
||||
PythonTan = "Tangent"
|
||||
PythonTanh = "Hyperbolic tangent"
|
||||
PythonText = "Display a text at (x,y) coordinates"
|
||||
PythonTimeFunction = "time module function prefix"
|
||||
PythonTrunc = "x truncated to an integer"
|
||||
PythonTurtleBackward = "Move backward by x pixels"
|
||||
|
||||
@@ -13,11 +13,14 @@ PythonAbs = "Valeur absolue/Module"
|
||||
PythonAcos = "Arc cosinus"
|
||||
PythonAcosh = "Arc cosinus hyperbolique"
|
||||
PythonAppend = "Insère x à la fin de la liste"
|
||||
PythonArrow = "Flèche de (x,y) à (x+dx,y+dy)"
|
||||
PythonAsin = "Arc sinus"
|
||||
PythonAsinh = "Arc sinus hyperbolique"
|
||||
PythonAtan = "Arc tangente"
|
||||
PythonAtan2 = "Calcul de atan(y/x)"
|
||||
PythonAtanh = "Arc tangente hyperbolique"
|
||||
PythonAxis = "Met les axes (xmin,xmax,ymin,ymax)"
|
||||
PythonBar = "Diagramme en barres de la liste x"
|
||||
PythonBin = "Conversion d'un entier en binaire"
|
||||
PythonCeil = "Plafond"
|
||||
PythonChoice = "Nombre aléatoire dans la liste"
|
||||
@@ -46,12 +49,15 @@ PythonFrExp = "Mantisse et exposant de x : (m,e)"
|
||||
PythonGamma = "Fonction gamma"
|
||||
PythonGetPixel = "Renvoie la couleur du pixel (x,y)"
|
||||
PythonGetrandbits = "Nombre aléatoire sur k bits"
|
||||
PythonGrid = "Affiche ou masque la grille"
|
||||
PythonHex = "Conversion entier en hexadécimal"
|
||||
PythonHist = "Histogramme de la liste x"
|
||||
PythonImportCmath = "Importation du module cmath"
|
||||
PythonImportIon = "Importation du module ion"
|
||||
PythonImportKandinsky = "Importation du module kandinsky"
|
||||
PythonImportRandom = "Importation du module random"
|
||||
PythonImportMath = "Importation du module math"
|
||||
PythonImportMatplotlibPyplot = "Importation de matplotlib.pyplot"
|
||||
PythonImportTurtle = "Importation du module turtle"
|
||||
PythonImportTime = "Importation du module time"
|
||||
PythonIndex = "Indice première occurrence de x"
|
||||
@@ -117,12 +123,14 @@ PythonLog = "Logarithme de base a"
|
||||
PythonLog10 = "Logarithme décimal"
|
||||
PythonLog2 = "Logarithme de base 2"
|
||||
PythonMathFunction = "Préfixe fonction du module math"
|
||||
PythonMatplotlibPyplotFunction = "Préfixe du module matplotlib.pyplot"
|
||||
PythonMax = "Maximum"
|
||||
PythonMin = "Minimum"
|
||||
PythonModf = "Parties fractionnaire et entière"
|
||||
PythonMonotonic = "Renvoie la valeur de l'horloge"
|
||||
PythonOct = "Conversion en octal"
|
||||
PythonPhase = "Argument de z"
|
||||
PythonPlot = "Trace y en fonction de x"
|
||||
PythonPolar = "Conversion en polaire"
|
||||
PythonPop = "Supprime le dernier élément"
|
||||
PythonPower = "x à la puissance y"
|
||||
@@ -138,8 +146,10 @@ PythonRect = "Conversion en algébrique"
|
||||
PythonRemove = "Supprime le premier x de la liste"
|
||||
PythonReverse = "Inverse les éléments de la liste"
|
||||
PythonRound = "Arrondi à n décimales"
|
||||
PythonScatter = "Nuage des points (x,y)"
|
||||
PythonSeed = "Initialiser générateur aléatoire"
|
||||
PythonSetPixel = "Colore le pixel (x,y)"
|
||||
PythonShow = "Affiche la figure"
|
||||
PythonSin = "Sinus"
|
||||
PythonSinh = "Sinus hyperbolique"
|
||||
PythonSleep = "Suspend l'exécution t secondes"
|
||||
@@ -148,6 +158,7 @@ PythonSqrt = "Racine carrée"
|
||||
PythonSum = "Somme des éléments de la liste"
|
||||
PythonTan = "Tangente"
|
||||
PythonTanh = "Tangente hyperbolique"
|
||||
PythonText = "Affiche un texte en (x,y)"
|
||||
PythonTimeFunction = "Préfixe fonction module time"
|
||||
PythonTrunc = "Troncature entière"
|
||||
PythonTurtleBackward = "Recule de x pixels"
|
||||
|
||||
@@ -13,11 +13,14 @@ PythonAbs = "Absolute value/Magnitude"
|
||||
PythonAcos = "Arc cosine"
|
||||
PythonAcosh = "Arc hyperbolic cosine"
|
||||
PythonAppend = "Add x to the end of the list"
|
||||
PythonArrow = "Arrow from (x,y) to (x+dx,y+dy)"
|
||||
PythonAsin = "Arc sine"
|
||||
PythonAsinh = "Arc hyperbolic sine"
|
||||
PythonAtan = "Arc tangent"
|
||||
PythonAtan2 = "Return atan(y/x)"
|
||||
PythonAtanh = "Arc hyperbolic tangent"
|
||||
PythonAxis = "Set axes to (xmin,xmax,ymin,ymax)"
|
||||
PythonBar = "Draw a bar plot with x values"
|
||||
PythonBin = "Convert integer to binary"
|
||||
PythonCeil = "Ceiling"
|
||||
PythonChoice = "Random number in the list"
|
||||
@@ -46,12 +49,15 @@ PythonFrExp = "Mantissa and exponent of x"
|
||||
PythonGamma = "Gamma function"
|
||||
PythonGetPixel = "Return pixel (x,y) color"
|
||||
PythonGetrandbits = "Integer with k random bits"
|
||||
PythonGrid = "Toggle the visibility of the grid"
|
||||
PythonHex = "Convert integer to hexadecimal"
|
||||
PythonHist = "Draw the histogram of x"
|
||||
PythonImportCmath = "Import cmath module"
|
||||
PythonImportIon = "Import ion module"
|
||||
PythonImportKandinsky = "Import kandinsky module"
|
||||
PythonImportRandom = "Import random module"
|
||||
PythonImportMath = "Import math module"
|
||||
PythonImportMatplotlibPyplot = "Import matplotlib.pyplot module"
|
||||
PythonImportTime = "Import time module"
|
||||
PythonImportTurtle = "Import turtle module"
|
||||
PythonIndex = "Index of the first x occurrence"
|
||||
@@ -117,12 +123,14 @@ PythonLog = "Logarithm to base a"
|
||||
PythonLog10 = "Logarithm to base 10"
|
||||
PythonLog2 = "Logarithm to base 2"
|
||||
PythonMathFunction = "math module function prefix"
|
||||
PythonMatplotlibPyplotFunction = "matplotlib.pyplot module prefix"
|
||||
PythonMax = "Maximum"
|
||||
PythonMin = "Minimum"
|
||||
PythonModf = "Fractional and integer parts of x"
|
||||
PythonMonotonic = "Value of a monotonic clock"
|
||||
PythonOct = "Convert integer to octal"
|
||||
PythonPhase = "Phase of z"
|
||||
PythonPlot = "Plot y versus x as lines"
|
||||
PythonPolar = "z in polar coordinates"
|
||||
PythonPop = "Remove and return the last item"
|
||||
PythonPower = "x raised to the power y"
|
||||
@@ -138,8 +146,10 @@ PythonRect = "z in cartesian coordinates"
|
||||
PythonRemove = "Remove the first occurrence of x"
|
||||
PythonReverse = "Reverse the elements of the list"
|
||||
PythonRound = "Round to n digits"
|
||||
PythonScatter = "Draw a scatter plot of y versus x"
|
||||
PythonSeed = "Initialize random number generator"
|
||||
PythonSetPixel = "Color pixel (x,y)"
|
||||
PythonShow = "Display the figure"
|
||||
PythonSin = "Sine"
|
||||
PythonSinh = "Hyperbolic sine"
|
||||
PythonSleep = "Suspend the execution for t seconds"
|
||||
@@ -148,6 +158,7 @@ PythonSqrt = "Square root"
|
||||
PythonSum = "Sum the items of a list"
|
||||
PythonTan = "Tangent"
|
||||
PythonTanh = "Hyperbolic tangent"
|
||||
PythonText = "Display a text at (x,y) coordinates"
|
||||
PythonTimeFunction = "time module function prefix"
|
||||
PythonTrunc = "x truncated to an integer"
|
||||
PythonTurtleBackward = "Move backward by x pixels"
|
||||
|
||||
@@ -12,11 +12,15 @@ PythonCommandAcos = "acos(x)"
|
||||
PythonCommandAcosh = "acosh(x)"
|
||||
PythonCommandAppend = "list.append(x)"
|
||||
PythonCommandAppendWithoutArg = ".append(\x11)"
|
||||
PythonCommandArrow = "arrow(x,y,dx,dy)"
|
||||
PythonCommandAsin = "asin(x)"
|
||||
PythonCommandAsinh = "asinh(x)"
|
||||
PythonCommandAtan = "atan(x)"
|
||||
PythonCommandAtan2 = "atan2(y,x)"
|
||||
PythonCommandAtanh = "atanh(x)"
|
||||
PythonCommandAxis = "axis((xmin,xmax,ymin,ymax))"
|
||||
PythonCommandAxisWithoutArg = "axis(\x11)"
|
||||
PythonCommandBar = "bar(x,height)"
|
||||
PythonCommandBin = "bin(x)"
|
||||
PythonCommandCeil = "ceil(x)"
|
||||
PythonCommandChoice = "choice(list)"
|
||||
@@ -52,13 +56,16 @@ PythonCommandFrExp = "frexp(x)"
|
||||
PythonCommandGamma = "gamma(x)"
|
||||
PythonCommandGetPixel = "get_pixel(x,y)"
|
||||
PythonCommandGetrandbits = "getrandbits(k)"
|
||||
PythonCommandGrid = "grid()"
|
||||
PythonCommandHex = "hex(x)"
|
||||
PythonCommandHist = "hist(x,bins)"
|
||||
PythonCommandImag = "z.imag"
|
||||
PythonCommandImagWithoutArg = ".imag"
|
||||
PythonCommandImportFromCmath = "from cmath import *"
|
||||
PythonCommandImportFromIon = "from ion import *"
|
||||
PythonCommandImportFromKandinsky = "from kandinsky import *"
|
||||
PythonCommandImportFromMath = "from math import *"
|
||||
PythonCommandImportFromMatplotlibPyplot = "from matplotlib.pyplot import *"
|
||||
PythonCommandImportFromRandom = "from random import *"
|
||||
PythonCommandImportFromTime = "from time import *"
|
||||
PythonCommandImportFromTurtle = "from turtle import *"
|
||||
@@ -66,6 +73,7 @@ PythonCommandImportCmath = "import cmath"
|
||||
PythonCommandImportIon = "import ion"
|
||||
PythonCommandImportKandinsky = "import kandinsky"
|
||||
PythonCommandImportMath = "import math"
|
||||
PythonCommandImportMatplotlibPyplot = "import matplotlib.pyplot"
|
||||
PythonCommandImportRandom = "import random"
|
||||
PythonCommandImportTime = "import time"
|
||||
PythonCommandImportTurtle = "import turtle"
|
||||
@@ -138,12 +146,15 @@ PythonCommandLog2 = "log2(x)"
|
||||
PythonCommandLogComplex = "log(z,a)"
|
||||
PythonCommandMathFunction = "math.function"
|
||||
PythonCommandMathFunctionWithoutArg = "math.\x11"
|
||||
PythonCommandMatplotlibPyplotFunction = "matplotlib.pyplot.function"
|
||||
PythonCommandMatplotlibPyplotFunctionWithoutArg = "matplotlib.pyplot.\x11"
|
||||
PythonCommandMax = "max(list)"
|
||||
PythonCommandMin = "min(list)"
|
||||
PythonCommandModf = "modf(x)"
|
||||
PythonCommandMonotonic = "monotonic()"
|
||||
PythonCommandOct = "oct(x)"
|
||||
PythonCommandPhase = "phase(z)"
|
||||
PythonCommandPlot = "plot(x,y)"
|
||||
PythonCommandPolar = "polar(z)"
|
||||
PythonCommandPop = "list.pop()"
|
||||
PythonCommandPopWithoutArg = ".pop()"
|
||||
@@ -165,8 +176,10 @@ PythonCommandRemoveWithoutArg = ".remove(\x11)"
|
||||
PythonCommandReverse = "list.reverse()"
|
||||
PythonCommandReverseWithoutArg = ".reverse()"
|
||||
PythonCommandRound = "round(x, n)"
|
||||
PythonCommandScatter = "scatter(x,y)"
|
||||
PythonCommandSeed = "seed(x)"
|
||||
PythonCommandSetPixel = "set_pixel(x,y,color)"
|
||||
PythonCommandShow = "show()"
|
||||
PythonCommandSin = "sin(x)"
|
||||
PythonCommandSinComplex = "sin(z)"
|
||||
PythonCommandSinh = "sinh(x)"
|
||||
@@ -179,6 +192,7 @@ PythonCommandSqrtComplex = "sqrt(z)"
|
||||
PythonCommandSum = "sum(list)"
|
||||
PythonCommandTan = "tan(x)"
|
||||
PythonCommandTanh = "tanh(x)"
|
||||
PythonCommandText = "text(x,y,\"text\")"
|
||||
PythonCommandTimeFunction = "time.function"
|
||||
PythonCommandTimeFunctionWithoutArg = "time.\x11"
|
||||
PythonCommandTrunc = "trunc(x)"
|
||||
|
||||
@@ -34,9 +34,8 @@ ConsoleController::ConsoleController(Responder * parentResponder, App * pythonDe
|
||||
m_selectableTableView(this, this, this, this),
|
||||
m_editCell(this, pythonDelegate, this),
|
||||
m_scriptStore(scriptStore),
|
||||
m_sandboxController(this, this),
|
||||
m_inputRunLoopActive(false),
|
||||
m_preventEdition(false)
|
||||
m_sandboxController(this),
|
||||
m_inputRunLoopActive(false)
|
||||
#if EPSILON_GETOPT
|
||||
, m_locked(lockOnConsole)
|
||||
#endif
|
||||
@@ -82,14 +81,12 @@ void ConsoleController::runAndPrintForCommand(const char * command) {
|
||||
assert(m_outputAccumulationBuffer[0] == '\0');
|
||||
|
||||
// Draw the console before running the code
|
||||
m_preventEdition = true;
|
||||
m_editCell.setText("");
|
||||
m_editCell.setPrompt("");
|
||||
refreshPrintOutput();
|
||||
|
||||
runCode(storedCommand);
|
||||
|
||||
m_preventEdition = false;
|
||||
m_editCell.setPrompt(sStandardPromptText);
|
||||
m_editCell.setEditing(true);
|
||||
|
||||
@@ -108,9 +105,7 @@ const char * ConsoleController::inputText(const char * prompt) {
|
||||
m_inputRunLoopActive = true;
|
||||
|
||||
// Hide the sandbox if it is displayed
|
||||
if (sandboxIsDisplayed()) {
|
||||
hideSandbox();
|
||||
}
|
||||
hideAnyDisplayedViewController();
|
||||
|
||||
const char * promptText = prompt;
|
||||
char * s = const_cast<char *>(prompt);
|
||||
@@ -157,8 +152,7 @@ const char * ConsoleController::inputText(const char * prompt) {
|
||||
m_editCell.clearAndReduceSize();
|
||||
|
||||
// Reload the history
|
||||
m_selectableTableView.reloadData();
|
||||
m_selectableTableView.selectCellAtLocation(0, m_consoleStore.numberOfLines());
|
||||
reloadData(true);
|
||||
appsContainer->redrawWindow();
|
||||
|
||||
// Launch a new input loop
|
||||
@@ -191,14 +185,21 @@ void ConsoleController::viewWillAppear() {
|
||||
m_importScriptsWhenViewAppears = false;
|
||||
autoImport();
|
||||
}
|
||||
m_selectableTableView.reloadData();
|
||||
m_selectableTableView.selectCellAtLocation(0, m_consoleStore.numberOfLines());
|
||||
m_editCell.setEditing(true);
|
||||
m_editCell.setText("");
|
||||
|
||||
reloadData(true);
|
||||
}
|
||||
|
||||
void ConsoleController::didBecomeFirstResponder() {
|
||||
Container::activeApp()->setFirstResponder(&m_editCell);
|
||||
if (!isDisplayingViewController()) {
|
||||
Container::activeApp()->setFirstResponder(&m_editCell);
|
||||
} else {
|
||||
/* A view controller might be displayed: for example, when pushing the
|
||||
* console on the stack controller, we auto-import scripts during the
|
||||
* 'viewWillAppear' and then we set the console as first responder. The
|
||||
* sandbox or the matplotlib controller might have been pushed in the
|
||||
* auto-import. */
|
||||
Container::activeApp()->setFirstResponder(stackViewController()->topViewController());
|
||||
}
|
||||
}
|
||||
|
||||
bool ConsoleController::handleEvent(Ion::Events::Event event) {
|
||||
@@ -347,11 +348,8 @@ bool ConsoleController::textFieldDidFinishEditing(TextField * textField, const c
|
||||
}
|
||||
telemetryReportEvent("Console", text);
|
||||
runAndPrintForCommand(text);
|
||||
if (!sandboxIsDisplayed()) {
|
||||
m_selectableTableView.reloadData();
|
||||
m_editCell.setEditing(true);
|
||||
textField->setText("");
|
||||
m_selectableTableView.selectCellAtLocation(0, m_consoleStore.numberOfLines());
|
||||
if (!isDisplayingViewController()) {
|
||||
reloadData(true);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -378,37 +376,53 @@ bool ConsoleController::textFieldDidAbortEditing(TextField * textField) {
|
||||
return true;
|
||||
}
|
||||
|
||||
void ConsoleController::displaySandbox() {
|
||||
if (sandboxIsDisplayed()) {
|
||||
return;
|
||||
}
|
||||
stackViewController()->push(&m_sandboxController);
|
||||
}
|
||||
|
||||
void ConsoleController::hideSandbox() {
|
||||
if (!sandboxIsDisplayed()) {
|
||||
return;
|
||||
}
|
||||
m_sandboxController.hide();
|
||||
}
|
||||
|
||||
void ConsoleController::resetSandbox() {
|
||||
if (!sandboxIsDisplayed()) {
|
||||
if (stackViewController()->topViewController() != sandbox()) {
|
||||
return;
|
||||
}
|
||||
m_sandboxController.reset();
|
||||
}
|
||||
|
||||
void ConsoleController::refreshPrintOutput() {
|
||||
if (sandboxIsDisplayed()) {
|
||||
void ConsoleController::displayViewController(ViewController * controller) {
|
||||
if (stackViewController()->topViewController() == controller) {
|
||||
return;
|
||||
}
|
||||
hideAnyDisplayedViewController();
|
||||
stackViewController()->push(controller);
|
||||
}
|
||||
|
||||
void ConsoleController::hideAnyDisplayedViewController() {
|
||||
if (!isDisplayingViewController()) {
|
||||
return;
|
||||
}
|
||||
stackViewController()->pop();
|
||||
}
|
||||
|
||||
bool ConsoleController::isDisplayingViewController() {
|
||||
/* The StackViewController model state is the best way to know wether the
|
||||
* console is displaying a View Controller (Sandbox or Matplotlib). Indeed,
|
||||
* keeping a boolean or a pointer raises the issue of when updating it - when
|
||||
* 'viewWillAppear' or when 'didEnterResponderChain' - in both cases, the
|
||||
* state would be wrong at some point... */
|
||||
return stackViewController()->depth() > 2;
|
||||
}
|
||||
|
||||
void ConsoleController::refreshPrintOutput() {
|
||||
if (!isDisplayingViewController()) {
|
||||
reloadData(false);
|
||||
AppsContainer::sharedAppsContainer()->redrawWindow();
|
||||
}
|
||||
}
|
||||
|
||||
void ConsoleController::reloadData(bool isEditing) {
|
||||
m_selectableTableView.reloadData();
|
||||
m_selectableTableView.selectCellAtLocation(0, m_consoleStore.numberOfLines());
|
||||
if (m_preventEdition) {
|
||||
if (isEditing) {
|
||||
m_editCell.setEditing(true);
|
||||
m_editCell.setText("");
|
||||
} else {
|
||||
m_editCell.setEditing(false);
|
||||
}
|
||||
AppsContainer::sharedAppsContainer()->redrawWindow();
|
||||
}
|
||||
|
||||
/* printText is called by the Python machine.
|
||||
@@ -457,12 +471,11 @@ void ConsoleController::printText(const char * text, size_t length) {
|
||||
}
|
||||
|
||||
void ConsoleController::autoImportScript(Script script, bool force) {
|
||||
if (sandboxIsDisplayed()) {
|
||||
/* The sandbox might be displayed, for instance if we are auto-importing
|
||||
* several scripts that draw at importation. In this case, we want to remove
|
||||
* the sandbox. */
|
||||
hideSandbox();
|
||||
}
|
||||
/* The sandbox might be displayed, for instance if we are auto-importing
|
||||
* several scripts that draw at importation. In this case, we want to remove
|
||||
* the sandbox. */
|
||||
hideAnyDisplayedViewController();
|
||||
|
||||
if (script.importationStatus() || force) {
|
||||
// Step 1 - Create the command "from scriptName import *".
|
||||
|
||||
@@ -488,11 +501,8 @@ void ConsoleController::autoImportScript(Script script, bool force) {
|
||||
// Step 2 - Run the command
|
||||
runAndPrintForCommand(command);
|
||||
}
|
||||
if (!sandboxIsDisplayed() && force) {
|
||||
m_selectableTableView.reloadData();
|
||||
m_selectableTableView.selectCellAtLocation(0, m_consoleStore.numberOfLines());
|
||||
m_editCell.setEditing(true);
|
||||
m_editCell.setText("");
|
||||
if (!isDisplayingViewController() && force) {
|
||||
reloadData(true);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -61,9 +61,10 @@ public:
|
||||
bool textFieldDidAbortEditing(TextField * textField) override;
|
||||
|
||||
// MicroPython::ExecutionEnvironment
|
||||
void displaySandbox() override;
|
||||
void hideSandbox() override;
|
||||
ViewController * sandbox() override { return &m_sandboxController; }
|
||||
void resetSandbox() override;
|
||||
void displayViewController(ViewController * controller) override;
|
||||
void hideAnyDisplayedViewController() override;
|
||||
void refreshPrintOutput() override;
|
||||
void printText(const char * text, size_t length) override;
|
||||
const char * inputText(const char * prompt) override;
|
||||
@@ -82,6 +83,8 @@ private:
|
||||
static constexpr int k_numberOfLineCells = (Ion::Display::Height - Metric::TitleBarHeight) / 14 + 2; // 14 = KDFont::SmallFont->glyphSize().height()
|
||||
// k_numberOfLineCells = (240 - 18)/14 ~ 15.9. The 0.1 cell can be above and below the 15 other cells so we add +2 cells.
|
||||
static constexpr int k_outputAccumulationBufferSize = 100;
|
||||
bool isDisplayingViewController();
|
||||
void reloadData(bool isEditing);
|
||||
void flushOutputAccumulationBufferToStore();
|
||||
void appendTextToOutputAccumulationBuffer(const char * text, size_t length);
|
||||
void emptyOutputAccumulationBuffer();
|
||||
@@ -103,7 +106,6 @@ private:
|
||||
SandboxController m_sandboxController;
|
||||
bool m_inputRunLoopActive;
|
||||
bool m_autoImportScripts;
|
||||
bool m_preventEdition;
|
||||
#if EPSILON_GETOPT
|
||||
bool m_locked;
|
||||
#endif
|
||||
|
||||
@@ -92,30 +92,6 @@ const ToolboxMessageTree MathModuleChildren[] = {
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandLgamma, I18n::Message::PythonLgamma)
|
||||
};
|
||||
|
||||
const ToolboxMessageTree KandinskyModuleChildren[] = {
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandImportKandinsky, I18n::Message::PythonImportKandinsky, false),
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandImportFromKandinsky, I18n::Message::PythonImportKandinsky, false),
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandKandinskyFunction, I18n::Message::PythonKandinskyFunction, false, I18n::Message::PythonCommandKandinskyFunctionWithoutArg),
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandGetPixel, I18n::Message::PythonGetPixel),
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandSetPixel, I18n::Message::PythonSetPixel),
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandColor, I18n::Message::PythonColor),
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandDrawString, I18n::Message::PythonDrawString),
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandFillRect, I18n::Message::PythonFillRect)
|
||||
};
|
||||
|
||||
const ToolboxMessageTree RandomModuleChildren[] = {
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandImportRandom, I18n::Message::PythonImportRandom, false),
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandImportFromRandom, I18n::Message::PythonImportRandom, false),
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandRandomFunction, I18n::Message::PythonRandomFunction, false, I18n::Message::PythonCommandRandomFunctionWithoutArg),
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandGetrandbits, I18n::Message::PythonGetrandbits),
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandSeed, I18n::Message::PythonSeed),
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandRandrange, I18n::Message::PythonRandrange),
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandRandint, I18n::Message::PythonRandint),
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandChoice, I18n::Message::PythonChoice),
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandRandom, I18n::Message::PythonRandom, false),
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandUniform, I18n::Message::PythonUniform)
|
||||
};
|
||||
|
||||
const ToolboxMessageTree CMathModuleChildren[] = {
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandImportCmath, I18n::Message::PythonImportCmath, false),
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandImportFromCmath, I18n::Message::PythonImportCmath, false),
|
||||
@@ -132,6 +108,21 @@ const ToolboxMessageTree CMathModuleChildren[] = {
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandSinComplex, I18n::Message::PythonSin)
|
||||
};
|
||||
|
||||
const ToolboxMessageTree MatplotlibPyplotModuleChildren[] = {
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandImportMatplotlibPyplot, I18n::Message::PythonImportMatplotlibPyplot, false),
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandImportFromMatplotlibPyplot, I18n::Message::PythonImportMatplotlibPyplot, false),
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandMatplotlibPyplotFunction, I18n::Message::PythonMatplotlibPyplotFunction, false, I18n::Message::PythonCommandMatplotlibPyplotFunctionWithoutArg),
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandArrow, I18n::Message::PythonArrow),
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandAxis, I18n::Message::PythonAxis, false, I18n::Message::PythonCommandAxisWithoutArg),
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandBar, I18n::Message::PythonBar),
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandGrid, I18n::Message::PythonGrid),
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandHist, I18n::Message::PythonHist),
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandPlot, I18n::Message::PythonPlot),
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandScatter, I18n::Message::PythonScatter),
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandShow, I18n::Message::PythonShow),
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandText, I18n::Message::PythonText)
|
||||
};
|
||||
|
||||
const ToolboxMessageTree TurtleModuleChildren[] = {
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandImportTurtle, I18n::Message::PythonImportTurtle, false),
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandImportFromTurtle, I18n::Message::PythonImportTurtle, false),
|
||||
@@ -167,6 +158,30 @@ const ToolboxMessageTree TurtleModuleChildren[] = {
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonTurtleCommandGrey, I18n::Message::PythonTurtleGrey, false)
|
||||
};
|
||||
|
||||
const ToolboxMessageTree RandomModuleChildren[] = {
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandImportRandom, I18n::Message::PythonImportRandom, false),
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandImportFromRandom, I18n::Message::PythonImportRandom, false),
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandRandomFunction, I18n::Message::PythonRandomFunction, false, I18n::Message::PythonCommandRandomFunctionWithoutArg),
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandGetrandbits, I18n::Message::PythonGetrandbits),
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandSeed, I18n::Message::PythonSeed),
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandRandrange, I18n::Message::PythonRandrange),
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandRandint, I18n::Message::PythonRandint),
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandChoice, I18n::Message::PythonChoice),
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandRandom, I18n::Message::PythonRandom, false),
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandUniform, I18n::Message::PythonUniform)
|
||||
};
|
||||
|
||||
const ToolboxMessageTree KandinskyModuleChildren[] = {
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandImportKandinsky, I18n::Message::PythonImportKandinsky, false),
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandImportFromKandinsky, I18n::Message::PythonImportKandinsky, false),
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandKandinskyFunction, I18n::Message::PythonKandinskyFunction, false, I18n::Message::PythonCommandKandinskyFunctionWithoutArg),
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandGetPixel, I18n::Message::PythonGetPixel),
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandSetPixel, I18n::Message::PythonSetPixel),
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandColor, I18n::Message::PythonColor),
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandDrawString, I18n::Message::PythonDrawString),
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandFillRect, I18n::Message::PythonFillRect)
|
||||
};
|
||||
|
||||
const ToolboxMessageTree IonModuleChildren[] = {
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandImportIon, I18n::Message::PythonImportIon, false),
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandImportFromIon, I18n::Message::PythonImportIon, false),
|
||||
@@ -231,8 +246,9 @@ const ToolboxMessageTree TimeModuleChildren[] = {
|
||||
const ToolboxMessageTree modulesChildren[] = {
|
||||
ToolboxMessageTree::Node(I18n::Message::MathModule, MathModuleChildren),
|
||||
ToolboxMessageTree::Node(I18n::Message::CmathModule, CMathModuleChildren),
|
||||
ToolboxMessageTree::Node(I18n::Message::RandomModule, RandomModuleChildren),
|
||||
ToolboxMessageTree::Node(I18n::Message::MatplotlibPyplotModule, MatplotlibPyplotModuleChildren),
|
||||
ToolboxMessageTree::Node(I18n::Message::TurtleModule, TurtleModuleChildren),
|
||||
ToolboxMessageTree::Node(I18n::Message::RandomModule, RandomModuleChildren),
|
||||
ToolboxMessageTree::Node(I18n::Message::KandinskyModule, KandinskyModuleChildren),
|
||||
ToolboxMessageTree::Node(I18n::Message::IonModule, IonModuleChildren),
|
||||
ToolboxMessageTree::Node(I18n::Message::TimeModule, TimeModuleChildren)
|
||||
@@ -251,12 +267,15 @@ const ToolboxMessageTree catalogChildren[] = {
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandAbs, I18n::Message::PythonAbs),
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandAcos, I18n::Message::PythonAcos),
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandAcosh, I18n::Message::PythonAcosh),
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandArrow, I18n::Message::PythonArrow),
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandAsin, I18n::Message::PythonAsin),
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandAsinh, I18n::Message::PythonAsinh),
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandAtan, I18n::Message::PythonAtan),
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandAtan2, I18n::Message::PythonAtan2),
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandAtanh, I18n::Message::PythonAtanh),
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandAxis, I18n::Message::PythonAxis, false, I18n::Message::PythonCommandAxisWithoutArg),
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonTurtleCommandBackward, I18n::Message::PythonTurtleBackward),
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandBar, I18n::Message::PythonBar),
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandBin, I18n::Message::PythonBin),
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonTurtleCommandBlack, I18n::Message::PythonTurtleBlack, false),
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonTurtleCommandBlue, I18n::Message::PythonTurtleBlue, false),
|
||||
@@ -290,6 +309,7 @@ const ToolboxMessageTree catalogChildren[] = {
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandImportFromIon, I18n::Message::PythonImportIon, false),
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandImportFromKandinsky, I18n::Message::PythonImportKandinsky, false),
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandImportFromMath, I18n::Message::PythonImportMath, false),
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandImportFromMatplotlibPyplot, I18n::Message::PythonImportMatplotlibPyplot, false),
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandImportFromRandom, I18n::Message::PythonImportRandom, false),
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandImportFromTurtle, I18n::Message::PythonImportTurtle, false),
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandImportFromTime, I18n::Message::PythonImportTime, false),
|
||||
@@ -299,13 +319,16 @@ const ToolboxMessageTree catalogChildren[] = {
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonTurtleCommandGoto, I18n::Message::PythonTurtleGoto),
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonTurtleCommandGreen, I18n::Message::PythonTurtleGreen, false),
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonTurtleCommandGrey, I18n::Message::PythonTurtleGrey, false),
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandGrid, I18n::Message::PythonGrid),
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonTurtleCommandHeading, I18n::Message::PythonTurtleHeading, false),
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandHex, I18n::Message::PythonHex),
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonTurtleCommandHideturtle, I18n::Message::PythonTurtleHideturtle, false),
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandHist, I18n::Message::PythonHist),
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandImportCmath, I18n::Message::PythonImportCmath, false),
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandImportIon, I18n::Message::PythonImportIon, false),
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandImportKandinsky, I18n::Message::PythonImportKandinsky, false),
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandImportMath, I18n::Message::PythonImportMath, false),
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandImportMatplotlibPyplot, I18n::Message::PythonImportMatplotlibPyplot, false),
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandImportRandom, I18n::Message::PythonImportRandom, false),
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandImportTurtle, I18n::Message::PythonImportTurtle, false),
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandImportTime, I18n::Message::PythonImportTime, false),
|
||||
@@ -335,6 +358,7 @@ const ToolboxMessageTree catalogChildren[] = {
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandLog10, I18n::Message::PythonLog10),
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandLog2, I18n::Message::PythonLog2),
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandMathFunction, I18n::Message::PythonMathFunction, false, I18n::Message::PythonCommandMathFunctionWithoutArg),
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandMatplotlibPyplotFunction, I18n::Message::PythonMatplotlibPyplotFunction, false, I18n::Message::PythonCommandMatplotlibPyplotFunctionWithoutArg),
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandMax, I18n::Message::PythonMax),
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandMin, I18n::Message::PythonMin),
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandModf, I18n::Message::PythonModf),
|
||||
@@ -350,6 +374,7 @@ const ToolboxMessageTree catalogChildren[] = {
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandPolar, I18n::Message::PythonPolar),
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonTurtleCommandPosition, I18n::Message::PythonTurtlePosition, false),
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandPower, I18n::Message::PythonPower),
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandPlot, I18n::Message::PythonPlot),
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandPrint, I18n::Message::PythonPrint),
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonTurtleCommandPurple, I18n::Message::PythonTurtlePurple, false),
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandRadians, I18n::Message::PythonRadians),
|
||||
@@ -364,9 +389,11 @@ const ToolboxMessageTree catalogChildren[] = {
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonTurtleCommandReset, I18n::Message::PythonTurtleReset, false),
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonTurtleCommandRight, I18n::Message::PythonTurtleRight),
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandRound, I18n::Message::PythonRound),
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandScatter, I18n::Message::PythonScatter),
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonTurtleCommandSetheading, I18n::Message::PythonTurtleSetheading),
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandSetPixel, I18n::Message::PythonSetPixel),
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandSeed, I18n::Message::PythonSeed),
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandShow, I18n::Message::PythonShow),
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonTurtleCommandShowturtle, I18n::Message::PythonTurtleShowturtle, false),
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandSin, I18n::Message::PythonSin),
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandSinh, I18n::Message::PythonSinh),
|
||||
@@ -377,6 +404,7 @@ const ToolboxMessageTree catalogChildren[] = {
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandSum, I18n::Message::PythonSum),
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandTan, I18n::Message::PythonTan),
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandTanh, I18n::Message::PythonTanh),
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandText, I18n::Message::PythonText),
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandTimeFunction, I18n::Message::PythonTimeFunction, false, I18n::Message::PythonCommandTimeFunctionWithoutArg),
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandTrunc, I18n::Message::PythonTrunc),
|
||||
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandTurtleFunction, I18n::Message::PythonTurtleFunction, false, I18n::Message::PythonCommandTurtleFunctionWithoutArg),
|
||||
|
||||
@@ -1,14 +1,16 @@
|
||||
#include "sandbox_controller.h"
|
||||
#include <apps/apps_container.h>
|
||||
|
||||
extern "C" {
|
||||
#include <python/port/mod/turtle/modturtle.h>
|
||||
}
|
||||
|
||||
namespace Code {
|
||||
|
||||
SandboxController::SandboxController(Responder * parentResponder, MicroPython::ExecutionEnvironment * executionEnvironment) :
|
||||
SandboxController::SandboxController(Responder * parentResponder) :
|
||||
ViewController(parentResponder),
|
||||
m_solidColorView(Palette::CodeBackground),
|
||||
m_executionEnvironment(executionEnvironment)
|
||||
m_solidColorView(Palette::CodeBackground)
|
||||
{
|
||||
assert(executionEnvironment != nullptr);
|
||||
}
|
||||
|
||||
StackViewController * SandboxController::stackViewController() {
|
||||
@@ -20,19 +22,12 @@ void SandboxController::reset() {
|
||||
redrawWindow();
|
||||
}
|
||||
|
||||
void SandboxController::hide() {
|
||||
stackViewController()->pop();
|
||||
}
|
||||
|
||||
void SandboxController::viewWillAppear() {
|
||||
assert(m_executionEnvironment != nullptr);
|
||||
m_executionEnvironment->setSandboxIsDisplayed(true);
|
||||
redrawWindow();
|
||||
}
|
||||
|
||||
void SandboxController::viewDidDisappear() {
|
||||
assert(m_executionEnvironment != nullptr);
|
||||
m_executionEnvironment->setSandboxIsDisplayed(false);
|
||||
modturtle_view_did_disappear();
|
||||
}
|
||||
|
||||
bool SandboxController::handleEvent(Ion::Events::Event event) {
|
||||
|
||||
@@ -11,10 +11,9 @@ namespace Code {
|
||||
|
||||
class SandboxController : public ViewController {
|
||||
public:
|
||||
SandboxController(Responder * parentResponder, MicroPython::ExecutionEnvironment * executionEnvironment);
|
||||
SandboxController(Responder * parentResponder);
|
||||
StackViewController * stackViewController();
|
||||
void reset();
|
||||
void hide();
|
||||
|
||||
// ViewController
|
||||
View * view() override { return &m_solidColorView; }
|
||||
@@ -26,7 +25,6 @@ public:
|
||||
private:
|
||||
void redrawWindow();
|
||||
SolidColorView m_solidColorView;
|
||||
MicroPython::ExecutionEnvironment * m_executionEnvironment;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -19,6 +19,7 @@ bool ScriptStore::ScriptNameIsFree(const char * baseName) {
|
||||
ScriptStore::ScriptStore()
|
||||
{
|
||||
addScriptFromTemplate(ScriptTemplate::Squares());
|
||||
addScriptFromTemplate(ScriptTemplate::Parabola());
|
||||
addScriptFromTemplate(ScriptTemplate::Mandelbrot());
|
||||
addScriptFromTemplate(ScriptTemplate::Polynomial());
|
||||
}
|
||||
|
||||
@@ -53,6 +53,37 @@ def roots(a,b,c):
|
||||
else:
|
||||
return None)");
|
||||
|
||||
constexpr ScriptTemplate parabolaScriptTemplate("parabola.py", "\x01" R"(from matplotlib.pyplot import *
|
||||
from math import *
|
||||
|
||||
g=9.81
|
||||
|
||||
def x(t,v_0,alpha):
|
||||
return v_0*cos(alpha)*t
|
||||
def y(t,v_0,alpha,h_0):
|
||||
return -0.5*g*t**2+v_0*sin(alpha)*t+h_0
|
||||
|
||||
def vx(v_0,alpha):
|
||||
return v_0*cos(alpha)
|
||||
def vy(t,v_0,alpha):
|
||||
return -g*t+v_0*sin(alpha)
|
||||
|
||||
def t_max(v_0,alpha,h_0):
|
||||
return (v_0*sin(alpha)+sqrt((v_0**2)*(sin(alpha)**2)+2*g*h_0))/g
|
||||
|
||||
def simulation(v_0=15,alpha=pi/4,h_0=2):
|
||||
tMax=t_max(v_0,alpha,h_0)
|
||||
accuracy=1/10**(floor(log10(tMax))-1)
|
||||
T_MAX=floor(tMax*accuracy)+1
|
||||
X=[x(t/accuracy,v_0,alpha) for t in range(T_MAX)]
|
||||
Y=[y(t/accuracy,v_0,alpha,h_0) for t in range(T_MAX)]
|
||||
VX=[vx(v_0,alpha) for t in range(T_MAX)]
|
||||
VY=[vy(t/accuracy,v_0,alpha) for t in range(T_MAX)]
|
||||
for i in range(T_MAX):
|
||||
arrow(X[i],Y[i],VX[i]/accuracy,VY[i]/accuracy)
|
||||
grid()
|
||||
show())");
|
||||
|
||||
const ScriptTemplate * ScriptTemplate::Empty() {
|
||||
return &emptyScriptTemplate;
|
||||
}
|
||||
@@ -69,4 +100,8 @@ const ScriptTemplate * ScriptTemplate::Polynomial() {
|
||||
return &polynomialScriptTemplate;
|
||||
}
|
||||
|
||||
const ScriptTemplate * ScriptTemplate::Parabola() {
|
||||
return ¶bolaScriptTemplate;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ public:
|
||||
static const ScriptTemplate * Squares();
|
||||
static const ScriptTemplate * Mandelbrot();
|
||||
static const ScriptTemplate * Polynomial();
|
||||
static const ScriptTemplate * Parabola();
|
||||
const char * name() const { return m_name; }
|
||||
const char * content() const { return m_value+1; }
|
||||
const char * value() const { return m_value; }
|
||||
|
||||
@@ -2,6 +2,7 @@ CmathModule = "cmath"
|
||||
IonModule = "ion"
|
||||
KandinskyModule = "kandinsky"
|
||||
MathModule = "math"
|
||||
MatplotlibPyplotModule = "matplotlib.pyplot"
|
||||
TimeModule = "time"
|
||||
TurtleModule = "turtle"
|
||||
ForLoopMenu = "For"
|
||||
|
||||
@@ -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; }
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,6 +31,7 @@ Ion::Storage::Record::ErrorStatus SequenceStore::addEmptyModel() {
|
||||
const char * name = firstAvailableName(&nameIndex);
|
||||
assert(name);
|
||||
// Choose the corresponding color
|
||||
assert(nameIndex < Palette::numberOfDataColors());
|
||||
KDColor color = Palette::DataColor[nameIndex];
|
||||
Sequence::RecordDataBuffer data(color);
|
||||
// m_sequences
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
app_shared_test_src = $(addprefix apps/shared/,\
|
||||
continuous_function.cpp\
|
||||
curve_view_range.cpp \
|
||||
curve_view.cpp \
|
||||
dots.cpp \
|
||||
double_pair_store.cpp \
|
||||
expression_model.cpp \
|
||||
expression_model_handle.cpp \
|
||||
@@ -9,8 +11,11 @@ app_shared_test_src = $(addprefix apps/shared/,\
|
||||
global_context.cpp \
|
||||
interactive_curve_view_range_delegate.cpp \
|
||||
interactive_curve_view_range.cpp \
|
||||
labeled_curve_view.cpp \
|
||||
memoized_curve_view_range.cpp \
|
||||
range_1D.cpp \
|
||||
zoom_and_pan_curve_view_controller.cpp \
|
||||
zoom_curve_view_controller.cpp \
|
||||
)
|
||||
|
||||
app_shared_src = $(addprefix apps/shared/,\
|
||||
@@ -18,9 +23,7 @@ app_shared_src = $(addprefix apps/shared/,\
|
||||
buffer_function_title_cell.cpp \
|
||||
buffer_text_view_with_text_field.cpp \
|
||||
button_with_separator.cpp \
|
||||
dots.cpp \
|
||||
cursor_view.cpp \
|
||||
curve_view.cpp \
|
||||
curve_view_cursor.cpp \
|
||||
editable_cell_table_view_controller.cpp \
|
||||
expression_field_delegate_app.cpp \
|
||||
@@ -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 \
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -6,16 +6,6 @@ using namespace Poincare;
|
||||
|
||||
namespace Shared {
|
||||
|
||||
SimpleInteractiveCurveViewController::SimpleInteractiveCurveViewController(Responder * parentResponder, CurveViewCursor * cursor) :
|
||||
ViewController(parentResponder),
|
||||
m_cursor(cursor)
|
||||
{
|
||||
}
|
||||
|
||||
View * SimpleInteractiveCurveViewController::view() {
|
||||
return curveView();
|
||||
}
|
||||
|
||||
bool SimpleInteractiveCurveViewController::handleEvent(Ion::Events::Event event) {
|
||||
if (event == Ion::Events::Plus || event == Ion::Events::Minus) {
|
||||
return handleZoom(event);
|
||||
@@ -36,13 +26,6 @@ bool SimpleInteractiveCurveViewController::textFieldDidReceiveEvent(TextField *
|
||||
return TextFieldDelegate::textFieldDidReceiveEvent(textField, event);
|
||||
}
|
||||
|
||||
bool SimpleInteractiveCurveViewController::handleZoom(Ion::Events::Event event) {
|
||||
float ratio = event == Ion::Events::Plus ? 2.0f/3.0f : 3.0f/2.0f;
|
||||
interactiveCurveViewRange()->zoom(ratio, m_cursor->x(), m_cursor->y());
|
||||
curveView()->reload();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SimpleInteractiveCurveViewController::handleLeftRightEvent(Ion::Events::Event event) {
|
||||
int direction = event == Ion::Events::Left ? -1 : 1;
|
||||
if (moveCursorHorizontally(direction, Ion::Events::isLongRepetition())) {
|
||||
|
||||
@@ -1,21 +1,17 @@
|
||||
#ifndef SHARED_SIMPLE_INTERACTIVE_CURVE_VIEW_CONTROLLER_H
|
||||
#define SHARED_SIMPLE_INTERACTIVE_CURVE_VIEW_CONTROLLER_H
|
||||
|
||||
#include <escher/view_controller.h>
|
||||
#include "text_field_delegate.h"
|
||||
#include "interactive_curve_view_range.h"
|
||||
#include "curve_view_cursor.h"
|
||||
#include "curve_view.h"
|
||||
#include "zoom_curve_view_controller.h"
|
||||
|
||||
namespace Shared {
|
||||
|
||||
/* SimpleInteractiveCurveViewController is a View controller with a cursor that
|
||||
* can handles zoom in/out and left and right events. */
|
||||
|
||||
class SimpleInteractiveCurveViewController : public ViewController, public TextFieldDelegate {
|
||||
class SimpleInteractiveCurveViewController : public ZoomCurveViewController, public TextFieldDelegate {
|
||||
public:
|
||||
SimpleInteractiveCurveViewController(Responder * parentResponder, CurveViewCursor * cursor);
|
||||
View * view() override;
|
||||
SimpleInteractiveCurveViewController(Responder * parentResponder, CurveViewCursor * cursor) : ZoomCurveViewController(parentResponder), m_cursor(cursor) {}
|
||||
bool handleEvent(Ion::Events::Event event) override;
|
||||
bool textFieldDidReceiveEvent(TextField * textField, Ion::Events::Event event) override;
|
||||
protected:
|
||||
@@ -24,15 +20,15 @@ protected:
|
||||
virtual float cursorTopMarginRatio() { return 0.07f; } // (cursorHeight/2)/(graphViewHeight-1)
|
||||
virtual float cursorBottomMarginRatio() = 0; // (cursorHeight/2+bannerHeight)/(graphViewHeight-1)
|
||||
constexpr static float k_numberOfCursorStepsInGradUnit = 5.0f;
|
||||
virtual bool handleZoom(Ion::Events::Event event);
|
||||
// ZoomCurveViewController
|
||||
float xFocus() override { return m_cursor->x(); }
|
||||
float yFocus() override { return m_cursor->y(); }
|
||||
virtual bool handleLeftRightEvent(Ion::Events::Event event);
|
||||
virtual void reloadBannerView() = 0;
|
||||
/* the result of moveCursorVertically/Horizontally means:
|
||||
* false -> the cursor cannot move in this direction
|
||||
* true -> the cursor moved */
|
||||
virtual bool moveCursorHorizontally(int direction, bool fast = false) { return false; }
|
||||
virtual InteractiveCurveViewRange * interactiveCurveViewRange() = 0;
|
||||
virtual CurveView * curveView() = 0;
|
||||
virtual bool handleEnter() = 0;
|
||||
CurveViewCursor * m_cursor;
|
||||
};
|
||||
|
||||
35
apps/shared/zoom_and_pan_curve_view_controller.cpp
Normal file
35
apps/shared/zoom_and_pan_curve_view_controller.cpp
Normal file
@@ -0,0 +1,35 @@
|
||||
#include "zoom_and_pan_curve_view_controller.h"
|
||||
#include <cmath>
|
||||
#include <assert.h>
|
||||
|
||||
using namespace Poincare;
|
||||
|
||||
namespace Shared {
|
||||
|
||||
bool ZoomAndPanCurveViewController::handleEvent(Ion::Events::Event event) {
|
||||
if (event == Ion::Events::Left || event == Ion::Events::Right || event == Ion::Events::Up || event == Ion::Events::Down) {
|
||||
return handlePan(event);
|
||||
}
|
||||
return ZoomCurveViewController::handleEvent(event);
|
||||
}
|
||||
|
||||
bool ZoomAndPanCurveViewController::handlePan(Ion::Events::Event event) {
|
||||
float xMove = 0.0f;
|
||||
float yMove = 0.0f;
|
||||
if (event == Ion::Events::Up) {
|
||||
yMove = interactiveCurveViewRange()->yGridUnit();
|
||||
} else if (event == Ion::Events::Down) {
|
||||
yMove = -interactiveCurveViewRange()->yGridUnit();
|
||||
} else if (event == Ion::Events::Left) {
|
||||
xMove = -interactiveCurveViewRange()->xGridUnit();
|
||||
} else {
|
||||
assert(event == Ion::Events::Right);
|
||||
xMove = interactiveCurveViewRange()->xGridUnit();
|
||||
}
|
||||
interactiveCurveViewRange()->panWithVector(xMove, yMove);
|
||||
curveView()->reload();
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
23
apps/shared/zoom_and_pan_curve_view_controller.h
Normal file
23
apps/shared/zoom_and_pan_curve_view_controller.h
Normal file
@@ -0,0 +1,23 @@
|
||||
#ifndef SHARED_ZOOM_AND_PAN_CURVE_VIEW_CONTROLLER_H
|
||||
#define SHARED_ZOOM_AND_PAN_CURVE_VIEW_CONTROLLER_H
|
||||
|
||||
#include "zoom_curve_view_controller.h"
|
||||
|
||||
namespace Shared {
|
||||
|
||||
/* ZoomAndPanCurveViewController is a View controller with a cursor that can
|
||||
* handles zoom in/out and directional pan events. */
|
||||
|
||||
class ZoomAndPanCurveViewController : public ZoomCurveViewController {
|
||||
public:
|
||||
ZoomAndPanCurveViewController(Responder * parentResponder) : ZoomCurveViewController(parentResponder) {}
|
||||
bool handleEvent(Ion::Events::Event event) override;
|
||||
protected:
|
||||
virtual bool handlePan(Ion::Events::Event event);
|
||||
float xFocus() override { return interactiveCurveViewRange()->xCenter(); }
|
||||
float yFocus() override { return interactiveCurveViewRange()->yCenter(); }
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
23
apps/shared/zoom_curve_view_controller.cpp
Normal file
23
apps/shared/zoom_curve_view_controller.cpp
Normal file
@@ -0,0 +1,23 @@
|
||||
#include "zoom_curve_view_controller.h"
|
||||
#include <cmath>
|
||||
#include <assert.h>
|
||||
|
||||
using namespace Poincare;
|
||||
|
||||
namespace Shared {
|
||||
|
||||
bool ZoomCurveViewController::handleEvent(Ion::Events::Event event) {
|
||||
if (event == Ion::Events::Plus || event == Ion::Events::Minus) {
|
||||
return handleZoom(event);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ZoomCurveViewController::handleZoom(Ion::Events::Event event) {
|
||||
float ratio = event == Ion::Events::Plus ? 2.0f/3.0f : 3.0f/2.0f;
|
||||
interactiveCurveViewRange()->zoom(ratio, xFocus(), yFocus());
|
||||
curveView()->reload();
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
30
apps/shared/zoom_curve_view_controller.h
Normal file
30
apps/shared/zoom_curve_view_controller.h
Normal file
@@ -0,0 +1,30 @@
|
||||
#ifndef SHARED_ZOOM_CURVE_VIEW_CONTROLLER_H
|
||||
#define SHARED_ZOOM_CURVE_VIEW_CONTROLLER_H
|
||||
|
||||
#include <escher/view_controller.h>
|
||||
#include "interactive_curve_view_range.h"
|
||||
#include "curve_view_cursor.h"
|
||||
#include "curve_view.h"
|
||||
|
||||
namespace Shared {
|
||||
|
||||
/* ZoomCurveViewController is a View controller with a cursor that can handles
|
||||
* zoom in/out events. */
|
||||
|
||||
class ZoomCurveViewController : public ViewController {
|
||||
public:
|
||||
ZoomCurveViewController(Responder * parentResponder) : ViewController(parentResponder) {}
|
||||
View * view() override { return curveView(); }
|
||||
bool handleEvent(Ion::Events::Event event) override;
|
||||
protected:
|
||||
virtual bool handleZoom(Ion::Events::Event event);
|
||||
virtual InteractiveCurveViewRange * interactiveCurveViewRange() = 0;
|
||||
virtual CurveView * curveView() = 0;
|
||||
virtual float xFocus() = 0;
|
||||
virtual float yFocus() = 0;
|
||||
CurveViewCursor * m_cursor;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -5,7 +5,7 @@
|
||||
namespace Shared {
|
||||
|
||||
ZoomParameterController::ZoomParameterController(Responder * parentResponder, InteractiveCurveViewRange * interactiveRange, CurveView * curveView) :
|
||||
ViewController(parentResponder),
|
||||
ZoomAndPanCurveViewController(parentResponder),
|
||||
m_contentView(curveView),
|
||||
m_interactiveRange(interactiveRange)
|
||||
{
|
||||
@@ -15,45 +15,6 @@ const char * ZoomParameterController::title() {
|
||||
return I18n::translate(I18n::Message::Zoom);
|
||||
}
|
||||
|
||||
View * ZoomParameterController::view() {
|
||||
return &m_contentView;
|
||||
}
|
||||
|
||||
bool ZoomParameterController::handleEvent(Ion::Events::Event event) {
|
||||
if (event == Ion::Events::Plus) {
|
||||
m_interactiveRange->zoom(2.0f/3.0f, m_interactiveRange->xCenter(), m_interactiveRange->yCenter());
|
||||
m_contentView.curveView()->reload();
|
||||
return true;
|
||||
}
|
||||
if (event == Ion::Events::Minus) {
|
||||
m_interactiveRange->zoom(3.0f/2.0f, m_interactiveRange->xCenter(), m_interactiveRange->yCenter());
|
||||
m_contentView.curveView()->reload();
|
||||
return true;
|
||||
}
|
||||
if (event == Ion::Events::Up) {
|
||||
m_interactiveRange->panWithVector(0.0f, m_interactiveRange->yGridUnit());
|
||||
m_contentView.curveView()->reload();
|
||||
return true;
|
||||
}
|
||||
if (event == Ion::Events::Down) {
|
||||
m_interactiveRange->panWithVector(0.0f, -m_interactiveRange->yGridUnit());
|
||||
m_contentView.curveView()->reload();
|
||||
return true;
|
||||
}
|
||||
if (event == Ion::Events::Left) {
|
||||
m_interactiveRange->panWithVector(-m_interactiveRange->xGridUnit(), 0.0f);
|
||||
m_contentView.curveView()->reload();
|
||||
return true;
|
||||
}
|
||||
if (event == Ion::Events::Right) {
|
||||
m_interactiveRange->panWithVector(m_interactiveRange->xGridUnit(), 0.0f);
|
||||
m_contentView.curveView()->reload();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void ZoomParameterController::viewWillAppear() {
|
||||
ViewController::viewWillAppear();
|
||||
m_contentView.curveView()->setOkView(nullptr);
|
||||
|
||||
@@ -1,25 +1,23 @@
|
||||
#ifndef SHARED_ZOOM_PARAMETER_CONTROLLER_H
|
||||
#define SHARED_ZOOM_PARAMETER_CONTROLLER_H
|
||||
|
||||
#include <escher.h>
|
||||
#include "interactive_curve_view_range.h"
|
||||
#include "curve_view.h"
|
||||
#include "zoom_and_pan_curve_view_controller.h"
|
||||
#include <apps/i18n.h>
|
||||
|
||||
namespace Shared {
|
||||
|
||||
class ZoomParameterController : public ViewController {
|
||||
class ZoomParameterController : public ZoomAndPanCurveViewController {
|
||||
public:
|
||||
ZoomParameterController(Responder * parentResponder, InteractiveCurveViewRange * interactiveCurveViewRange, CurveView * curveView);
|
||||
const char * title() override;
|
||||
View * view() override;
|
||||
bool handleEvent(Ion::Events::Event event) override;
|
||||
View * view() override { return &m_contentView; }
|
||||
void viewWillAppear() override;
|
||||
void viewDidDisappear() override;
|
||||
void didBecomeFirstResponder() override;
|
||||
TELEMETRY_ID("Zoom");
|
||||
private:
|
||||
constexpr static KDCoordinate k_standardViewHeight = 175;
|
||||
|
||||
class ContentView : public View {
|
||||
public:
|
||||
constexpr static KDCoordinate k_legendHeight = 30;
|
||||
@@ -46,7 +44,13 @@ private:
|
||||
CurveView * m_curveView;
|
||||
LegendView m_legendView;
|
||||
};
|
||||
|
||||
void adaptCurveRange(bool viewWillAppear);
|
||||
|
||||
// ZoomAndPanCurveViewController
|
||||
InteractiveCurveViewRange * interactiveCurveViewRange() override { return m_interactiveRange; }
|
||||
CurveView * curveView() override { return m_contentView.curveView(); }
|
||||
|
||||
ContentView m_contentView;
|
||||
InteractiveCurveViewRange * m_interactiveRange;
|
||||
};
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
44
escher/include/escher/palette.h
Normal file
44
escher/include/escher/palette.h
Normal 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
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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 \
|
||||
|
||||
@@ -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)
|
||||
|
||||
13
python/port/mod/matplotlib/modmatplotlib.cpp
Normal file
13
python/port/mod/matplotlib/modmatplotlib.cpp
Normal 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;
|
||||
}
|
||||
3
python/port/mod/matplotlib/modmatplotlib.h
Normal file
3
python/port/mod/matplotlib/modmatplotlib.h
Normal file
@@ -0,0 +1,3 @@
|
||||
#include <py/obj.h>
|
||||
|
||||
mp_obj_t modmatplotlib___init__();
|
||||
18
python/port/mod/matplotlib/modmatplotlib_table.c
Normal file
18
python/port/mod/matplotlib/modmatplotlib_table.c
Normal 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,
|
||||
};
|
||||
33
python/port/mod/matplotlib/modpyplot_table.c
Normal file
33
python/port/mod/matplotlib/modpyplot_table.c
Normal 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,
|
||||
};
|
||||
362
python/port/mod/matplotlib/pyplot/modpyplot.cpp
Normal file
362
python/port/mod/matplotlib/pyplot/modpyplot.cpp
Normal 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;
|
||||
}
|
||||
15
python/port/mod/matplotlib/pyplot/modpyplot.h
Normal file
15
python/port/mod/matplotlib/pyplot/modpyplot.h
Normal 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();
|
||||
33
python/port/mod/matplotlib/pyplot/modpyplot_table.c
Normal file
33
python/port/mod/matplotlib/pyplot/modpyplot_table.c
Normal 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,
|
||||
};
|
||||
14
python/port/mod/matplotlib/pyplot/plot_controller.cpp
Normal file
14
python/port/mod/matplotlib/pyplot/plot_controller.cpp
Normal 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();
|
||||
}
|
||||
|
||||
}
|
||||
27
python/port/mod/matplotlib/pyplot/plot_controller.h
Normal file
27
python/port/mod/matplotlib/pyplot/plot_controller.h
Normal 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
|
||||
219
python/port/mod/matplotlib/pyplot/plot_store.cpp
Normal file
219
python/port/mod/matplotlib/pyplot/plot_store.cpp
Normal 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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
142
python/port/mod/matplotlib/pyplot/plot_store.h
Normal file
142
python/port/mod/matplotlib/pyplot/plot_store.h
Normal 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
|
||||
80
python/port/mod/matplotlib/pyplot/plot_view.cpp
Normal file
80
python/port/mod/matplotlib/pyplot/plot_view.cpp
Normal 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
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
24
python/port/mod/matplotlib/pyplot/plot_view.h
Normal file
24
python/port/mod/matplotlib/pyplot/plot_view.h
Normal 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
|
||||
@@ -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) }, \
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user