#include #include "layout/char_layout.h" #include "layout/horizontal_layout.h" #include "layout/left_parenthesis_layout.h" #include "layout/right_parenthesis_layout.h" #include "layout/vertical_offset_layout.h" #include namespace Poincare { ExpressionLayout * LayoutEngine::createInfixLayout(const Expression * expression, PrintFloat::Mode floatDisplayMode, int numberOfSignificantDigits, const char * operatorName) { int numberOfOperands = expression->numberOfOperands(); assert(numberOfOperands > 1); HorizontalLayout * result = new HorizontalLayout(); result->addOrMergeChildAtIndex(expression->operand(0)->createLayout(floatDisplayMode, numberOfSignificantDigits), 0, true); for (int i = 1; i < numberOfOperands; i++) { result->addOrMergeChildAtIndex(createStringLayout(operatorName, strlen(operatorName)), result->numberOfChildren(), true); result->addOrMergeChildAtIndex( expression->operand(i)->type() == Expression::Type::Opposite ? createParenthesedLayout(expression->operand(i)->createLayout(floatDisplayMode, numberOfSignificantDigits), false) : expression->operand(i)->createLayout(floatDisplayMode, numberOfSignificantDigits), result->numberOfChildren(), true); } return result; } ExpressionLayout * LayoutEngine::createPrefixLayout(const Expression * expression, PrintFloat::Mode floatDisplayMode, int numberOfSignificantDigits, const char * operatorName) { HorizontalLayout * result = new HorizontalLayout(); // Add the operator name. result->addOrMergeChildAtIndex(createStringLayout(operatorName, strlen(operatorName)), 0, true); // Create the layout of arguments separated by commas. ExpressionLayout * args = nullptr; int numberOfOperands = expression->numberOfOperands(); if (numberOfOperands > 0) { args = new HorizontalLayout(); HorizontalLayout * horizontalArgs = static_cast(args); horizontalArgs->addOrMergeChildAtIndex(expression->operand(0)->createLayout(floatDisplayMode, numberOfSignificantDigits), 0, true); for (int i = 1; i < numberOfOperands; i++) { horizontalArgs->addChildAtIndex(new CharLayout(','), args->numberOfChildren()); horizontalArgs->addOrMergeChildAtIndex(expression->operand(i)->createLayout(floatDisplayMode, numberOfSignificantDigits), horizontalArgs->numberOfChildren(), true); } } // Add the parenthesed arguments. result->addOrMergeChildAtIndex(createParenthesedLayout(args, false), result->numberOfChildren(), true); return result; } ExpressionLayout * LayoutEngine::createParenthesedLayout(ExpressionLayout * layout, bool cloneLayout) { HorizontalLayout * result = new HorizontalLayout(); result->addChildAtIndex(new LeftParenthesisLayout(), 0); if (layout != nullptr) { result->addOrMergeChildAtIndex(cloneLayout ? layout->clone() : layout, 1, true); } result->addChildAtIndex(new RightParenthesisLayout(), result->numberOfChildren()); return result; } ExpressionLayout * LayoutEngine::createStringLayout(const char * buffer, int bufferSize, KDText::FontSize fontSize) { assert(bufferSize > 0); HorizontalLayout * resultLayout = new HorizontalLayout(); for (int i = 0; i < bufferSize; i++) { resultLayout->addChildAtIndex(new CharLayout(buffer[i], fontSize), i); } return resultLayout; } ExpressionLayout * LayoutEngine::createLogLayout(ExpressionLayout * argument, ExpressionLayout * index) { HorizontalLayout * resultLayout = static_cast(createStringLayout("log", 3)); VerticalOffsetLayout * offsetLayout = new VerticalOffsetLayout(index, VerticalOffsetLayout::Type::Subscript, false); resultLayout->addChildAtIndex(offsetLayout, resultLayout->numberOfChildren()); resultLayout->addOrMergeChildAtIndex(createParenthesedLayout(argument, false), resultLayout->numberOfChildren(), true); return resultLayout; } int LayoutEngine::writeInfixExpressionTextInBuffer(const Expression * expression, char * buffer, int bufferSize, PrintFloat::Mode floatDisplayMode, int numberOfDigits, const char * operatorName) { return writeInfixExpressionOrExpressionLayoutTextInBuffer(expression, nullptr, buffer, bufferSize,floatDisplayMode, numberOfDigits, operatorName, 0, -1, [](const char * operatorName) { return true; }); } int LayoutEngine::writePrefixExpressionTextInBuffer(const Expression * expression, char * buffer, int bufferSize, PrintFloat::Mode floatDisplayMode, int numberOfDigits, const char * operatorName) { return writePrefixExpressionOrExpressionLayoutTextInBuffer(expression, nullptr, buffer, bufferSize, floatDisplayMode, numberOfDigits, operatorName); } int LayoutEngine::writeInfixExpressionLayoutTextInBuffer(const ExpressionLayout * expressionLayout, char * buffer, int bufferSize, const char * operatorName, int firstChildIndex, int lastChildIndex, ChildNeedsParenthesis childNeedsParenthesis) { return writeInfixExpressionOrExpressionLayoutTextInBuffer(nullptr, expressionLayout, buffer, bufferSize, PrintFloat::Mode::Decimal, PrintFloat::k_numberOfStoredSignificantDigits, operatorName, firstChildIndex, lastChildIndex, childNeedsParenthesis); } int LayoutEngine::writePrefixExpressionLayoutTextInBuffer(const ExpressionLayout * expressionLayout, char * buffer, int bufferSize, const char * operatorName, bool writeFirstChild) { return writePrefixExpressionOrExpressionLayoutTextInBuffer(nullptr, expressionLayout, buffer, bufferSize, PrintFloat::Mode::Decimal, PrintFloat::k_numberOfStoredSignificantDigits, operatorName, writeFirstChild); } int LayoutEngine::writeInfixExpressionOrExpressionLayoutTextInBuffer(const Expression * expression, const ExpressionLayout * expressionLayout, char * buffer, int bufferSize, PrintFloat::Mode floatDisplayMode, int numberOfDigits, const char * operatorName, int firstChildIndex, int lastChildIndex, ChildNeedsParenthesis childNeedsParenthesis) { assert(expression != nullptr || expressionLayout != nullptr); if (bufferSize == 0) { return -1; } buffer[bufferSize-1] = 0; int numberOfChar = 0; int numberOfOperands = (expression != nullptr) ? expression->numberOfOperands() : expressionLayout->numberOfChildren(); assert(numberOfOperands > 0); if (numberOfChar >= bufferSize-1) { return bufferSize-1; } if ((expression != nullptr && expression->operand(firstChildIndex)->needParenthesisWithParent(expression)) || (expression == nullptr && childNeedsParenthesis(operatorName))) { buffer[numberOfChar++] = '('; if (numberOfChar >= bufferSize-1) { return bufferSize-1; } } numberOfChar += (expression != nullptr) ? expression->operand(firstChildIndex)->writeTextInBuffer(buffer+numberOfChar, bufferSize-numberOfChar, floatDisplayMode, numberOfDigits) : expressionLayout->child(firstChildIndex)->writeTextInBuffer(buffer+numberOfChar, bufferSize-numberOfChar); if (numberOfChar >= bufferSize-1) { return bufferSize-1; } if ((expression != nullptr && expression->operand(firstChildIndex)->needParenthesisWithParent(expression)) || (expression == nullptr && childNeedsParenthesis(operatorName))) { buffer[numberOfChar++] = ')'; if (numberOfChar >= bufferSize-1) { return bufferSize-1; } } int lastIndex = lastChildIndex < 0 ? numberOfOperands - 1 : lastChildIndex; for (int i = firstChildIndex + 1; i < lastIndex+1; i++) { if (numberOfChar >= bufferSize-1) { return bufferSize-1; } numberOfChar += strlcpy(buffer+numberOfChar, operatorName, bufferSize-numberOfChar); if (numberOfChar >= bufferSize-1) { return bufferSize-1; } if ((expression != nullptr && expression->operand(i)->needParenthesisWithParent(expression)) || (expression == nullptr && childNeedsParenthesis(operatorName))) { buffer[numberOfChar++] = '('; if (numberOfChar >= bufferSize-1) { return bufferSize-1; } } numberOfChar += (expression != nullptr) ? expression->operand(i)->writeTextInBuffer(buffer+numberOfChar, bufferSize-numberOfChar, floatDisplayMode, numberOfDigits) : expressionLayout->child(i)->writeTextInBuffer(buffer+numberOfChar, bufferSize-numberOfChar); if (numberOfChar >= bufferSize-1) { return bufferSize-1; } if ((expression != nullptr && expression->operand(i)->needParenthesisWithParent(expression)) || (expression == nullptr && childNeedsParenthesis(operatorName))) { buffer[numberOfChar++] = ')'; if (numberOfChar >= bufferSize-1) { return bufferSize-1; } } } buffer[numberOfChar] = 0; return numberOfChar; } int LayoutEngine::writePrefixExpressionOrExpressionLayoutTextInBuffer(const Expression * expression, const ExpressionLayout * expressionLayout, char * buffer, int bufferSize, PrintFloat::Mode floatDisplayMode, int numberOfDigits, const char * operatorName, bool writeFirstChild) { assert(expression != nullptr || expressionLayout != nullptr); if (bufferSize == 0) { return -1; } buffer[bufferSize-1] = 0; int numberOfChar = strlcpy(buffer, operatorName, bufferSize); if (numberOfChar >= bufferSize-1) { return bufferSize-1; } buffer[numberOfChar++] = '('; if (numberOfChar >= bufferSize-1) { return bufferSize-1; } int numberOfOperands = (expression != nullptr) ? expression->numberOfOperands() : expressionLayout->numberOfChildren(); if (numberOfOperands > 0) { if (!writeFirstChild) { assert(numberOfOperands > 1); } int firstOperandIndex = writeFirstChild ? 0 : 1; numberOfChar += (expression != nullptr) ? expression->operand(firstOperandIndex)->writeTextInBuffer(buffer+numberOfChar, bufferSize-numberOfChar, floatDisplayMode, numberOfDigits) : expressionLayout->child(firstOperandIndex)->writeTextInBuffer(buffer+numberOfChar, bufferSize-numberOfChar); if (numberOfChar >= bufferSize-1) { return bufferSize-1; } for (int i = firstOperandIndex + 1; i < numberOfOperands; i++) { buffer[numberOfChar++] = ','; if (numberOfChar >= bufferSize-1) { return bufferSize-1; } numberOfChar += (expression != nullptr) ? expression->operand(i)->writeTextInBuffer(buffer+numberOfChar, bufferSize-numberOfChar, floatDisplayMode, numberOfDigits) : expressionLayout->child(i)->writeTextInBuffer(buffer+numberOfChar, bufferSize-numberOfChar); if (numberOfChar >= bufferSize-1) { return bufferSize-1; } } } buffer[numberOfChar++] = ')'; buffer[numberOfChar] = 0; return numberOfChar; } int LayoutEngine::writeOneCharInBuffer(char * buffer, int bufferSize, char charToWrite) { if (bufferSize == 0) { return -1; } buffer[bufferSize-1] = 0; if (bufferSize == 1) { return 0; } buffer[0] = charToWrite; buffer[1] = 0; return 1; } }