[poincare] Sum and Product can specify their variable name

This commit is contained in:
Émilie Feral
2018-10-26 16:34:11 +02:00
parent 94721f08df
commit 31a5caff60
15 changed files with 123 additions and 90 deletions

View File

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

View File

@@ -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<double> evaluateWithNextTerm(DoublePrecision p, Evaluation<double> a, Evaluation<double> b) const override {
return templatedApproximateWithNextTerm<double>(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);
}
};

View File

@@ -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<ProductLayoutNode>())
{
replaceChildAtIndexInPlace(0, argument);
replaceChildAtIndexInPlace(1, lowerB);
replaceChildAtIndexInPlace(2, upperB);
replaceChildAtIndexInPlace(1, variable);
replaceChildAtIndexInPlace(2, lowerB);
replaceChildAtIndexInPlace(3, upperB);
}
};

View File

@@ -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<float> approximate(SinglePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { return templatedApproximate<float>(context, angleUnit); }

View File

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

View File

@@ -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<double> evaluateWithNextTerm(DoublePrecision p, Evaluation<double> a, Evaluation<double> b) const override {
return templatedApproximateWithNextTerm<double>(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);
}
};

View File

@@ -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<SumLayoutNode>())
{
replaceChildAtIndexInPlace(0, argument);
replaceChildAtIndexInPlace(1, lowerB);
replaceChildAtIndexInPlace(2, upperB);
replaceChildAtIndexInPlace(1, variable);
replaceChildAtIndexInPlace(2, lowerB);
replaceChildAtIndexInPlace(3, upperB);
}
};

View File

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

View File

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

View File

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

View File

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

View File

@@ -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<typename T>
Evaluation<T> SequenceNode::templatedApproximate(Context& context, Preferences::AngleUnit angleUnit) const {
Evaluation<T> aInput = childAtIndex(1)->approximate(T(), context, angleUnit);
Evaluation<T> bInput = childAtIndex(2)->approximate(T(), context, angleUnit);
Evaluation<T> aInput = childAtIndex(2)->approximate(T(), context, angleUnit);
Evaluation<T> 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<T>::Undefined();
}
VariableContext nContext = VariableContext("n", &context);
VariableContext nContext = VariableContext(static_cast<SymbolNode *>(childAtIndex(1))->name(), &context);
Evaluation<T> result = Complex<T>((T)emptySequenceValue());
for (int i = (int)start; i <= (int)end; i++) {
if (Expression::shouldStopProcessing()) {

View File

@@ -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<SequenceLayoutNode *>(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<SequenceLayoutNode *>(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<SequenceLayoutNode *>(this)->upperBoundLayout()->serialize(buffer+numberOfChar, bufferSize-numberOfChar, floatDisplayMode, numberOfSignificantDigits);
if (numberOfChar >= bufferSize-1) { return bufferSize-1; }
LayoutNode * argLayouts[] = {const_cast<SequenceLayoutNode *>(this)->argumentLayout(), const_cast<SequenceLayoutNode *>(this)->variableLayout(), const_cast<SequenceLayoutNode *>(this)->lowerBoundLayout(), const_cast<SequenceLayoutNode *>(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);
}
}

View File

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

View File

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