diff --git a/apps/shared.universal.i18n b/apps/shared.universal.i18n index 5dddef7d7..7dbcabbe0 100644 --- a/apps/shared.universal.i18n +++ b/apps/shared.universal.i18n @@ -50,7 +50,7 @@ PermuteCommandWithArg = "permute(n,r)" P = "p" Prediction95CommandWithArg = "prediction95(p,n)" PredictionCommandWithArg = "prediction(p,n)" -ProductCommandWithArg = "product(f(n),nmin,nmax)" +ProductCommandWithArg = "product(f(n),n,nmin,nmax)" QuoCommandWithArg = "quo(p,q)" RandintCommandWithArg = "randint(a,b)" RandomCommandWithArg = "random()" @@ -65,7 +65,7 @@ Shift = "shift" Sigma = "σ" SinhCommandWithArg = "sinh(x)" SortCommandWithArg = "sort<(L)" -SumCommandWithArg = "sum(f(n),nmin,nmax)" +SumCommandWithArg = "sum(f(n),n,nmin,nmax)" Sxy = "Σxy" TanhCommandWithArg = "tanh(x)" TraceCommandWithArg = "trace(M)" diff --git a/poincare/include/poincare/product.h b/poincare/include/poincare/product.h index 38c3adb92..292803e31 100644 --- a/poincare/include/poincare/product.h +++ b/poincare/include/poincare/product.h @@ -19,7 +19,7 @@ public: private: const char * name() const override { return "product"; } float emptySequenceValue() const override { return 1.0f; } - Layout createSequenceLayout(Layout argumentLayout, Layout subscriptLayout, Layout superscriptLayout) const override; + Layout createSequenceLayout(Layout argumentLayout, Layout symbolLayout, Layout subscriptLayout, Layout superscriptLayout) const override; Evaluation evaluateWithNextTerm(DoublePrecision p, Evaluation a, Evaluation b) const override { return templatedApproximateWithNextTerm(a, b); } @@ -34,10 +34,11 @@ friend class ProductNode; public: Product(); Product(const ProductNode * n) : Expression(n) {} - Product(Expression operand0, Expression operand1, Expression operand2) : Product() { + Product(Expression operand0, Expression operand1, Expression operand2, Expression op) : Product() { replaceChildAtIndexInPlace(0, operand0); replaceChildAtIndexInPlace(1, operand1); replaceChildAtIndexInPlace(2, operand2); + replaceChildAtIndexInPlace(3, operand2); } }; diff --git a/poincare/include/poincare/product_layout.h b/poincare/include/poincare/product_layout.h index 2d52454a4..8eb2adccd 100644 --- a/poincare/include/poincare/product_layout.h +++ b/poincare/include/poincare/product_layout.h @@ -25,12 +25,13 @@ private: class ProductLayout final : public Layout { public: - ProductLayout(Layout argument, Layout lowerB, Layout upperB) : + ProductLayout(Layout argument, Layout variable, Layout lowerB, Layout upperB) : Layout(TreePool::sharedPool()->createTreeNode()) { replaceChildAtIndexInPlace(0, argument); - replaceChildAtIndexInPlace(1, lowerB); - replaceChildAtIndexInPlace(2, upperB); + replaceChildAtIndexInPlace(1, variable); + replaceChildAtIndexInPlace(2, lowerB); + replaceChildAtIndexInPlace(3, upperB); } }; diff --git a/poincare/include/poincare/sequence.h b/poincare/include/poincare/sequence.h index c787952a2..d702c0ace 100644 --- a/poincare/include/poincare/sequence.h +++ b/poincare/include/poincare/sequence.h @@ -10,13 +10,13 @@ namespace Poincare { class SequenceNode : public ExpressionNode { public: - int numberOfChildren() const override { return 3; } + int numberOfChildren() const override { return 4; } private: Layout createLayout(Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const override; int serialize(char * buffer, int bufferSize, Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const override { return SerializationHelper::Prefix(this, buffer, bufferSize, floatDisplayMode, numberOfSignificantDigits, name()); } - virtual Layout createSequenceLayout(Layout subscriptLayout, Layout superscriptLayout, Layout argumentLayout) const = 0; + virtual Layout createSequenceLayout(Layout argumentLayout, Layout symbolLayout, Layout subscriptLayout, Layout superscriptLayout) const = 0; virtual const char * name() const = 0; /* Approximation */ Evaluation approximate(SinglePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { return templatedApproximate(context, angleUnit); } diff --git a/poincare/include/poincare/sequence_layout.h b/poincare/include/poincare/sequence_layout.h index c49e8a264..59ef8d34d 100644 --- a/poincare/include/poincare/sequence_layout.h +++ b/poincare/include/poincare/sequence_layout.h @@ -23,15 +23,15 @@ public: char XNTChar() const override { return 'n'; } // TreeNode - int numberOfChildren() const override { return 3; } + int numberOfChildren() const override { return 4; } protected: constexpr static KDCoordinate k_boundHeightMargin = 2; constexpr static KDCoordinate k_argumentWidthMargin = 2; constexpr static const KDFont * k_font = KDFont::LargeFont; - constexpr static char k_nEquals[] = {'n', '=', 0}; + constexpr static char k_equal[] = {'=', 0}; - KDSize lowerBoundSizeWithNEquals(); + KDSize lowerBoundSizeWithVariableEquals(); // LayoutNode KDSize computeSize() override; @@ -40,9 +40,13 @@ protected: int writeDerivedClassInBuffer(const char * operatorName, char * buffer, int bufferSize, Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const; LayoutNode * argumentLayout() { return childAtIndex(0); } - LayoutNode * lowerBoundLayout() { return childAtIndex(1); } - LayoutNode * upperBoundLayout() { return childAtIndex(2); } + LayoutNode * variableLayout() { return childAtIndex(1); } + LayoutNode * lowerBoundLayout() { return childAtIndex(2); } + LayoutNode * upperBoundLayout() { return childAtIndex(3); } void render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) override; +private: + KDCoordinate completeLowerBoundX(); + KDCoordinate subscriptBaseline(); }; } diff --git a/poincare/include/poincare/sum.h b/poincare/include/poincare/sum.h index 4ed6fc62b..7befcd894 100644 --- a/poincare/include/poincare/sum.h +++ b/poincare/include/poincare/sum.h @@ -19,7 +19,7 @@ public: private: const char * name() const override { return "sum"; } float emptySequenceValue() const override { return 0.0f; } - Layout createSequenceLayout(Layout argumentLayout, Layout subscriptLayout, Layout superscriptLayout) const override; + Layout createSequenceLayout(Layout argumentLayout, Layout symbolLayout, Layout subscriptLayout, Layout superscriptLayout) const override; Evaluation evaluateWithNextTerm(DoublePrecision p, Evaluation a, Evaluation b) const override { return templatedApproximateWithNextTerm(a, b); } @@ -34,10 +34,11 @@ friend class SumNode; public: Sum(); Sum(const SumNode * n) : Expression(n) {} - Sum(Expression operand0, Expression operand1, Expression operand2) : Sum() { + Sum(Expression operand0, Expression operand1, Expression operand2, Expression operand3) : Sum() { replaceChildAtIndexInPlace(0, operand0); replaceChildAtIndexInPlace(1, operand1); replaceChildAtIndexInPlace(2, operand2); + replaceChildAtIndexInPlace(3, operand3); } }; diff --git a/poincare/include/poincare/sum_layout.h b/poincare/include/poincare/sum_layout.h index 9e4420ac1..f201a8e69 100644 --- a/poincare/include/poincare/sum_layout.h +++ b/poincare/include/poincare/sum_layout.h @@ -23,12 +23,13 @@ private: class SumLayout final : public Layout { public: - SumLayout(Layout argument, Layout lowerB, Layout upperB) : + SumLayout(Layout argument, Layout variable, Layout lowerB, Layout upperB) : Layout(TreePool::sharedPool()->createTreeNode()) { replaceChildAtIndexInPlace(0, argument); - replaceChildAtIndexInPlace(1, lowerB); - replaceChildAtIndexInPlace(2, upperB); + replaceChildAtIndexInPlace(1, variable); + replaceChildAtIndexInPlace(2, lowerB); + replaceChildAtIndexInPlace(3, upperB); } }; diff --git a/poincare/src/expression_lexer.l b/poincare/src/expression_lexer.l index 29d797b5c..15ab126d6 100644 --- a/poincare/src/expression_lexer.l +++ b/poincare/src/expression_lexer.l @@ -115,7 +115,7 @@ atanh { *yylval = HyperbolicArcTangent(); return FUNCTION; } binomial { *yylval = BinomialCoefficient(); return FUNCTION; } ceil { *yylval = Ceiling(); return FUNCTION; } confidence { *yylval = ConfidenceInterval(); return FUNCTION; } -diff { *yylval = Derivative(); return DIFF_FUNCTION; } +diff { *yylval = Derivative(); return VARIABLE_DEPENDENT_FUNCTION; } dim { *yylval = MatrixDimension(); return FUNCTION; } conj { *yylval = Conjugate(); return FUNCTION; } det { *yylval = Determinant(); return FUNCTION; } @@ -126,7 +126,7 @@ floor { *yylval = Floor(); return FUNCTION; } frac { *yylval = FracPart(); return FUNCTION; } gcd { *yylval = GreatCommonDivisor(); return FUNCTION; } im { *yylval = ImaginaryPart(); return FUNCTION; } -int { *yylval = Integral(); return INT_FUNCTION; } +int { *yylval = Integral(); return VARIABLE_DEPENDENT_FUNCTION; } inverse { *yylval = MatrixInverse(); return FUNCTION; } lcm { *yylval = LeastCommonMultiple(); return FUNCTION; } ln { *yylval = NaperianLogarithm(); return FUNCTION; } @@ -135,7 +135,7 @@ log\_\{ { return LOG_FUNCTION_TWO_ARGUMENTS; } permute { *yylval = PermuteCoefficient(); return FUNCTION; } prediction95 { *yylval = PredictionInterval(); return FUNCTION; } prediction { *yylval = SimplePredictionInterval(); return FUNCTION; } -product { *yylval = Product(); return FUNCTION; } +product { *yylval = Product(); return VARIABLE_DEPENDENT_FUNCTION; } quo { *yylval = DivisionQuotient(); return FUNCTION; } random { *yylval = Random(); return FUNCTION; } randint { *yylval = Randint(); return FUNCTION; } @@ -145,7 +145,7 @@ root { *yylval = NthRoot(); return FUNCTION; } round { *yylval = Round(); return FUNCTION; } sin { *yylval = Sine(); return FUNCTION; } sinh { *yylval = HyperbolicSine(); return FUNCTION; } -sum { *yylval = Sum(); return FUNCTION; } +sum { *yylval = Sum(); return VARIABLE_DEPENDENT_FUNCTION; } tan { *yylval = Tangent(); return FUNCTION; } tanh { *yylval = HyperbolicTangent(); return FUNCTION; } trace { *yylval = MatrixTrace(); return FUNCTION; } diff --git a/poincare/src/expression_parser.y b/poincare/src/expression_parser.y index 7fb4866f3..69ed98e9f 100644 --- a/poincare/src/expression_parser.y +++ b/poincare/src/expression_parser.y @@ -73,7 +73,7 @@ using namespace Poincare; %nonassoc RIGHT_BRACKET %nonassoc LEFT_BRACE %nonassoc RIGHT_BRACE -%nonassoc FUNCTION LOG_FUNCTION LOG_FUNCTION_TWO_ARGUMENTS DIFF_FUNCTION INT_FUNCTION +%nonassoc FUNCTION LOG_FUNCTION LOG_FUNCTION_TWO_ARGUMENTS VARIABLE_DEPENDENT_FUNCTION %left COMMA %nonassoc UNDERSCORE %nonassoc DIGITS @@ -134,8 +134,7 @@ term : TERM { $$ = $1; } /* Special case for logarithm, as we do not at first if it needs 1 or 2 children */ | LOG_FUNCTION lstData RIGHT_PARENTHESIS { if ($2.numberOfChildren() == 1) { $$ = Logarithm($2.childAtIndex(0)); } else if ($2.numberOfChildren() == 2) { $$ = Logarithm($2.childAtIndex(0), $2.childAtIndex(1));} else { YYERROR; } ; } | LOG_FUNCTION_TWO_ARGUMENTS exp RIGHT_BRACE LEFT_PARENTHESIS exp RIGHT_PARENTHESIS { $$ = Logarithm($5, $2); } - | DIFF_FUNCTION LEFT_PARENTHESIS lstData RIGHT_PARENTHESIS { if ($$.numberOfChildren() != ($3.numberOfChildren())) { YYERROR; } ; if ($3.childAtIndex(1).type() != ExpressionNode::Type::Symbol) { YYERROR; } ; $$ = $1; $$.setChildrenInPlace($3); } - | INT_FUNCTION LEFT_PARENTHESIS lstData RIGHT_PARENTHESIS { if ($$.numberOfChildren() != ($3.numberOfChildren())) { YYERROR; } ; if ($3.childAtIndex(1).type() != ExpressionNode::Type::Symbol && $3.childAtIndex(1).type() != ExpressionNode::Type::EmptyExpression ) { YYERROR; } ; $$ = $1; $$.setChildrenInPlace($3); } + | VARIABLE_DEPENDENT_FUNCTION LEFT_PARENTHESIS lstData RIGHT_PARENTHESIS { if ($$.numberOfChildren() != ($3.numberOfChildren())) { YYERROR; } ; if ($3.childAtIndex(1).type() != ExpressionNode::Type::Symbol && $3.childAtIndex(1).type() != ExpressionNode::Type::EmptyExpression ) { YYERROR; } ; $$ = $1; $$.setChildrenInPlace($3); } | LEFT_PARENTHESIS exp RIGHT_PARENTHESIS { $$ = Parenthesis($2); } /* MATRICES_ARE_DEFINED */ | LEFT_BRACKET mtxData RIGHT_BRACKET { $$ = $2; } diff --git a/poincare/src/product.cpp b/poincare/src/product.cpp index 96c7d3f98..440ac6676 100644 --- a/poincare/src/product.cpp +++ b/poincare/src/product.cpp @@ -9,8 +9,8 @@ extern "C" { namespace Poincare { -Layout ProductNode::createSequenceLayout(Layout argumentLayout, Layout subscriptLayout, Layout superscriptLayout) const { - return ProductLayout(argumentLayout, subscriptLayout, superscriptLayout); +Layout ProductNode::createSequenceLayout(Layout argumentLayout, Layout symbolLayout, Layout subscriptLayout, Layout superscriptLayout) const { + return ProductLayout(argumentLayout, symbolLayout, subscriptLayout, superscriptLayout); } template diff --git a/poincare/src/product_layout.cpp b/poincare/src/product_layout.cpp index 8202e5844..8be05d651 100644 --- a/poincare/src/product_layout.cpp +++ b/poincare/src/product_layout.cpp @@ -13,7 +13,7 @@ int ProductLayoutNode::serialize(char * buffer, int bufferSize, Preferences::Pri void ProductLayoutNode::render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) { // Compute sizes. KDSize upperBoundSize = upperBoundLayout()->layoutSize(); - KDSize lowerBoundNEqualsSize = lowerBoundSizeWithNEquals(); + KDSize lowerBoundNEqualsSize = lowerBoundSizeWithVariableEquals(); // Render the Product symbol. ctx->fillRect(KDRect(p.x() + max(max(0, (upperBoundSize.width()-k_symbolWidth)/2), (lowerBoundNEqualsSize.width()-k_symbolWidth)/2), diff --git a/poincare/src/sequence.cpp b/poincare/src/sequence.cpp index 2d1f8f4de..f5e1aad0e 100644 --- a/poincare/src/sequence.cpp +++ b/poincare/src/sequence.cpp @@ -12,19 +12,19 @@ extern "C" { namespace Poincare { Layout SequenceNode::createLayout(Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const { - return createSequenceLayout(childAtIndex(0)->createLayout(floatDisplayMode, numberOfSignificantDigits), childAtIndex(1)->createLayout(floatDisplayMode, numberOfSignificantDigits), childAtIndex(2)->createLayout(floatDisplayMode, numberOfSignificantDigits)); + return createSequenceLayout(childAtIndex(0)->createLayout(floatDisplayMode, numberOfSignificantDigits), childAtIndex(1)->createLayout(floatDisplayMode, numberOfSignificantDigits), childAtIndex(2)->createLayout(floatDisplayMode, numberOfSignificantDigits), childAtIndex(3)->createLayout(floatDisplayMode, numberOfSignificantDigits)); } template Evaluation SequenceNode::templatedApproximate(Context& context, Preferences::AngleUnit angleUnit) const { - Evaluation aInput = childAtIndex(1)->approximate(T(), context, angleUnit); - Evaluation bInput = childAtIndex(2)->approximate(T(), context, angleUnit); + Evaluation aInput = childAtIndex(2)->approximate(T(), context, angleUnit); + Evaluation bInput = childAtIndex(3)->approximate(T(), context, angleUnit); T start = aInput.toScalar(); T end = bInput.toScalar(); if (std::isnan(start) || std::isnan(end) || start != (int)start || end != (int)end || end - start > k_maxNumberOfSteps) { return Complex::Undefined(); } - VariableContext nContext = VariableContext("n", &context); + VariableContext nContext = VariableContext(static_cast(childAtIndex(1))->name(), &context); Evaluation result = Complex((T)emptySequenceValue()); for (int i = (int)start; i <= (int)end; i++) { if (Expression::shouldStopProcessing()) { diff --git a/poincare/src/sequence_layout.cpp b/poincare/src/sequence_layout.cpp index b7c37f051..c4754beff 100644 --- a/poincare/src/sequence_layout.cpp +++ b/poincare/src/sequence_layout.cpp @@ -9,20 +9,34 @@ namespace Poincare { static inline KDCoordinate max(KDCoordinate x, KDCoordinate y) { return x > y ? x : y; } -constexpr char SequenceLayoutNode::k_nEquals[]; +constexpr char SequenceLayoutNode::k_equal[]; void SequenceLayoutNode::moveCursorLeft(LayoutCursor * cursor, bool * shouldRecomputeLayout) { - if (cursor->position() == LayoutCursor::Position::Left - && (cursor->layoutNode() == lowerBoundLayout() - || cursor->layoutNode() == upperBoundLayout())) + if (cursor->layoutNode() == upperBoundLayout()) { - // Case: Left of the bounds. Go Left of the sequence. + assert(cursor->position() == LayoutCursor::Position::Left); + // Case: Left of the upper bound. Go Left of the sequence. cursor->setLayoutNode(this); return; } - if (cursor->position() == LayoutCursor::Position::Left - && cursor->layoutNode() == argumentLayout()) + if (cursor->layoutNode() == lowerBoundLayout()) { + assert(cursor->position() == LayoutCursor::Position::Left); + // Case: Left of the lower bound. Go Right of the variable name. + cursor->setLayoutNode(variableLayout()); + cursor->setPosition(LayoutCursor::Position::Right); + return; + } + if (cursor->layoutNode() == variableLayout()) + { + assert(cursor->position() == LayoutCursor::Position::Left); + // Case: Left of the variable name. Go Left of the sequence. + cursor->setLayoutNode(this); + return; + } + if (cursor->layoutNode() == argumentLayout()) + { + assert(cursor->position() == LayoutCursor::Position::Left); // Case: Left of the argument. Go Right of the lower bound. cursor->setLayoutNode(lowerBoundLayout()); cursor->setPosition(LayoutCursor::Position::Right); @@ -44,18 +58,26 @@ void SequenceLayoutNode::moveCursorLeft(LayoutCursor * cursor, bool * shouldReco } void SequenceLayoutNode::moveCursorRight(LayoutCursor * cursor, bool * shouldRecomputeLayout) { - if (cursor->position() == LayoutCursor::Position::Right - && (cursor->layoutNode() == lowerBoundLayout() - || cursor->layoutNode() == upperBoundLayout())) + if (cursor->layoutNode() == lowerBoundLayout() + || cursor->layoutNode() == upperBoundLayout()) { + assert(cursor->position() == LayoutCursor::Position::Right); // Case: Right of the bounds. Go Left of the argument. cursor->setLayoutNode(argumentLayout()); cursor->setPosition(LayoutCursor::Position::Left); return; } - if (cursor->position() == LayoutCursor::Position::Right - && cursor->layoutNode() == argumentLayout()) + if (cursor->layoutNode() == variableLayout()) { + assert(cursor->position() == LayoutCursor::Position::Right); + // Case: Right of the variable name. Go Left of the lower bound. + cursor->setLayoutNode(lowerBoundLayout()); + cursor->setPosition(LayoutCursor::Position::Left); + return; + } + if (cursor->layoutNode() == argumentLayout()) + { + assert(cursor->position() == LayoutCursor::Position::Right); // Case: Right of the argument. Go Right. cursor->setLayoutNode(this); return; @@ -75,8 +97,8 @@ void SequenceLayoutNode::moveCursorRight(LayoutCursor * cursor, bool * shouldRec } void SequenceLayoutNode::moveCursorUp(LayoutCursor * cursor, bool * shouldRecomputeLayout, bool equivalentPositionVisited) { - if (cursor->layoutNode()->hasAncestor(lowerBoundLayout(), true)) { - // If the cursor is inside the lower bound, move it to the upper bound + if (cursor->layoutNode()->hasAncestor(lowerBoundLayout(), true) || cursor->layoutNode()->hasAncestor(variableLayout(), true)) { + // If the cursor is inside the lower bound or inside the variable name, move it to the upper bound upperBoundLayout()->moveCursorUpInDescendants(cursor, shouldRecomputeLayout); return; } @@ -119,16 +141,25 @@ void SequenceLayoutNode::deleteBeforeCursor(LayoutCursor * cursor) { // Protected +KDSize SequenceLayoutNode::lowerBoundSizeWithVariableEquals() { + KDSize variableSize = variableLayout()->layoutSize(); + KDSize lowerBoundSize = lowerBoundLayout()->layoutSize(); + KDSize equalSize = k_font->stringSize(k_equal); + return KDSize( + variableSize.width() + equalSize.width() + lowerBoundSize.width(), + subscriptBaseline() + max(max(variableSize.height() - variableLayout()->baseline(), lowerBoundSize.height() - lowerBoundLayout()->baseline()), equalSize.height()/2)); +} + KDSize SequenceLayoutNode::computeSize() { - KDSize nEqualslowerBoundSize = lowerBoundSizeWithNEquals(); + KDSize totalLowerBoundSize = lowerBoundSizeWithVariableEquals(); KDSize upperBoundSize = upperBoundLayout()->layoutSize(); KDSize argumentSize = argumentLayout()->layoutSize(); KDSize argumentSizeWithParentheses = KDSize( argumentSize.width() + 2*ParenthesisLayoutNode::ParenthesisWidth(), ParenthesisLayoutNode::HeightGivenChildHeight(argumentSize.height())); KDSize result = KDSize( - max(max(k_symbolWidth, nEqualslowerBoundSize.width()), upperBoundSize.width())+k_argumentWidthMargin+argumentSizeWithParentheses.width(), - baseline() + max(k_symbolHeight/2+k_boundHeightMargin+nEqualslowerBoundSize.height(), argumentSizeWithParentheses.height() - argumentLayout()->baseline())); + max(max(k_symbolWidth, totalLowerBoundSize.width()), upperBoundSize.width())+k_argumentWidthMargin+argumentSizeWithParentheses.width(), + baseline() + max(k_symbolHeight/2+k_boundHeightMargin+totalLowerBoundSize.height(), argumentSizeWithParentheses.height() - argumentLayout()->baseline())); return result; } @@ -137,21 +168,22 @@ KDCoordinate SequenceLayoutNode::computeBaseline() { } KDPoint SequenceLayoutNode::positionOfChild(LayoutNode * l) { - KDSize nEqualslowerBoundSize = lowerBoundSizeWithNEquals(); - KDSize nEqualsSize = k_font->stringSize(k_nEquals); + KDSize variableSize = variableLayout()->layoutSize(); + KDSize equalSize = k_font->stringSize(k_equal); KDSize upperBoundSize = upperBoundLayout()->layoutSize(); KDCoordinate x = 0; KDCoordinate y = 0; - if (l == lowerBoundLayout()) { - x = nEqualsSize.width() + - max(max(0, (k_symbolWidth-nEqualslowerBoundSize.width())/2), - (upperBoundSize.width()-nEqualslowerBoundSize.width())/2); - y = baseline() + k_symbolHeight/2 + k_boundHeightMargin; + if (l == variableLayout()) { + x = completeLowerBoundX(); + y = baseline() + k_symbolHeight/2 + k_boundHeightMargin + subscriptBaseline() - variableLayout()->baseline(); + } else if (l == lowerBoundLayout()) { + x = completeLowerBoundX() + equalSize.width() + variableSize.width(); + y = baseline() + k_symbolHeight/2 + k_boundHeightMargin + subscriptBaseline() - lowerBoundLayout()->baseline(); } else if (l == upperBoundLayout()) { - x = max(max(0, (k_symbolWidth-upperBoundSize.width())/2), (nEqualslowerBoundSize.width()-upperBoundSize.width())/2); + x = max(max(0, (k_symbolWidth-upperBoundSize.width())/2), (lowerBoundSizeWithVariableEquals().width()-upperBoundSize.width())/2); y = baseline() - (k_symbolHeight+1)/2- k_boundHeightMargin-upperBoundSize.height(); } else if (l == argumentLayout()) { - x = max(max(k_symbolWidth, nEqualslowerBoundSize.width()), upperBoundSize.width())+k_argumentWidthMargin+ParenthesisLayoutNode::ParenthesisWidth(); + x = max(max(k_symbolWidth, lowerBoundSizeWithVariableEquals().width()), upperBoundSize.width())+k_argumentWidthMargin+ParenthesisLayoutNode::ParenthesisWidth(); y = baseline() - argumentLayout()->baseline(); } else { assert(false); @@ -174,25 +206,16 @@ int SequenceLayoutNode::writeDerivedClassInBuffer(const char * operatorName, cha buffer[numberOfChar++] = '('; if (numberOfChar >= bufferSize-1) { return bufferSize-1; } - // Write the argument - numberOfChar += const_cast(this)->argumentLayout()->serialize(buffer+numberOfChar, bufferSize-numberOfChar, floatDisplayMode, numberOfSignificantDigits); - if (numberOfChar >= bufferSize-1) { return bufferSize-1; } - - // Write the comma - buffer[numberOfChar++] = ','; - if (numberOfChar >= bufferSize-1) { return bufferSize-1; } - - // Write the lower bound - numberOfChar += const_cast(this)->lowerBoundLayout()->serialize(buffer+numberOfChar, bufferSize-numberOfChar, floatDisplayMode, numberOfSignificantDigits); - if (numberOfChar >= bufferSize-1) { return bufferSize-1; } - - // Write the comma - buffer[numberOfChar++] = ','; - if (numberOfChar >= bufferSize-1) { return bufferSize-1; } - - // Write the upper bound - numberOfChar += const_cast(this)->upperBoundLayout()->serialize(buffer+numberOfChar, bufferSize-numberOfChar, floatDisplayMode, numberOfSignificantDigits); - if (numberOfChar >= bufferSize-1) { return bufferSize-1; } + LayoutNode * argLayouts[] = {const_cast(this)->argumentLayout(), const_cast(this)->variableLayout(), const_cast(this)->lowerBoundLayout(), const_cast(this)->upperBoundLayout()}; + for (uint8_t i = 0; i < sizeof(argLayouts)/sizeof(argLayouts[0]); i++) { + if (i != 0) { + // Write the comma + buffer[numberOfChar++] = ','; + if (numberOfChar >= bufferSize-1) { return bufferSize-1; } + } + numberOfChar += argLayouts[i]->serialize(buffer+numberOfChar, bufferSize-numberOfChar, floatDisplayMode, numberOfSignificantDigits); + if (numberOfChar >= bufferSize-1) { return bufferSize-1; } + } // Write the closing parenthesis buffer[numberOfChar++] = ')'; @@ -201,9 +224,10 @@ int SequenceLayoutNode::writeDerivedClassInBuffer(const char * operatorName, cha } void SequenceLayoutNode::render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) { - // Render the "n=" - KDPoint nEqualsPosition = positionOfChild(lowerBoundLayout()).translatedBy(KDPoint(-k_font->stringSize(k_nEquals).width(), 0)); - ctx->drawString(k_nEquals, p.translatedBy(nEqualsPosition), k_font, expressionColor, backgroundColor); + // Render the "=" + KDSize variableSize = variableLayout()->layoutSize(); + KDPoint equalPosition = positionOfChild(variableLayout()).translatedBy(KDPoint(variableSize.width(), variableLayout()->baseline()-k_font->stringSize(k_equal).height()/2)); + ctx->drawString(k_equal, p.translatedBy(equalPosition), k_font, expressionColor, backgroundColor); // Render the parentheses KDCoordinate argumentWithParenthesesHeight = ParenthesisLayoutNode::HeightGivenChildHeight(argumentLayout()->layoutSize().height()); @@ -220,12 +244,14 @@ void SequenceLayoutNode::render(KDContext * ctx, KDPoint p, KDColor expressionCo RightParenthesisLayoutNode::RenderWithChildHeight(argumentWithParenthesesHeight, ctx, rightParenthesisPoint, expressionColor, backgroundColor); } -KDSize SequenceLayoutNode::lowerBoundSizeWithNEquals() { - KDSize lowerBoundSize = lowerBoundLayout()->layoutSize(); - KDSize nEqualsSize = k_font->stringSize(k_nEquals); - return KDSize( - nEqualsSize.width() + lowerBoundSize.width(), - max(nEqualsSize.height(), lowerBoundSize.height())); +KDCoordinate SequenceLayoutNode::completeLowerBoundX() { + KDSize upperBoundSize = upperBoundLayout()->layoutSize(); + return max(max(0, (k_symbolWidth-lowerBoundSizeWithVariableEquals().width())/2), + (upperBoundSize.width()-lowerBoundSizeWithVariableEquals().width())/2); +} + +KDCoordinate SequenceLayoutNode::subscriptBaseline() { + return max(max(variableLayout()->baseline(), lowerBoundLayout()->baseline()), k_font->stringSize(k_equal).height()/2); } } diff --git a/poincare/src/sum.cpp b/poincare/src/sum.cpp index e3e03acb0..76aa4f29f 100644 --- a/poincare/src/sum.cpp +++ b/poincare/src/sum.cpp @@ -11,8 +11,8 @@ extern "C" { namespace Poincare { -Layout SumNode::createSequenceLayout(Layout argumentLayout, Layout subscriptLayout, Layout superscriptLayout) const { - return SumLayout(argumentLayout, subscriptLayout, superscriptLayout); +Layout SumNode::createSequenceLayout(Layout argumentLayout, Layout symbolLayout, Layout subscriptLayout, Layout superscriptLayout) const { + return SumLayout(argumentLayout, symbolLayout, subscriptLayout, superscriptLayout); } template diff --git a/poincare/src/sum_layout.cpp b/poincare/src/sum_layout.cpp index 59c9ddf48..9c9a079e8 100644 --- a/poincare/src/sum_layout.cpp +++ b/poincare/src/sum_layout.cpp @@ -32,7 +32,7 @@ int SumLayoutNode::serialize(char * buffer, int bufferSize, Preferences::PrintFl void SumLayoutNode::render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) { // Computes sizes. KDSize upperBoundSize = upperBoundLayout()->layoutSize(); - KDSize lowerBoundNEqualsSize = lowerBoundSizeWithNEquals(); + KDSize lowerBoundNEqualsSize = lowerBoundSizeWithVariableEquals(); // Render the Sum symbol. KDColor workingBuffer[k_symbolWidth*k_symbolHeight];