From 0f52335183a9b842f1a1a2cbe33d9778c500afe0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Tue, 24 Sep 2019 17:12:37 +0200 Subject: [PATCH 001/680] [apps/code] Fix syntaxic coloration This fixes the coloration of: "123\n"+1 "\n\n"+1 For strings, lex->vstr.len gave the wrong value because it had already translated escaped chars, so "\n" would be one char long. --- apps/code/python_text_area.cpp | 44 ++++++++-------------------------- 1 file changed, 10 insertions(+), 34 deletions(-) diff --git a/apps/code/python_text_area.cpp b/apps/code/python_text_area.cpp index c7e958aab..07ced50cd 100644 --- a/apps/code/python_text_area.cpp +++ b/apps/code/python_text_area.cpp @@ -1,5 +1,6 @@ #include "python_text_area.h" #include "app.h" +#include extern "C" { #include "py/nlr.h" @@ -39,40 +40,15 @@ static inline KDColor TokenColor(mp_token_kind_t tokenKind) { return KDColorBlack; } -static inline size_t TokenLength(mp_lexer_t * lex) { - if (lex->tok_kind == MP_TOKEN_STRING) { - return lex->vstr.len + 2; - } - if (lex->vstr.len > 0) { - return lex->vstr.len; - } - switch (lex->tok_kind) { - case MP_TOKEN_OP_DBL_STAR: - case MP_TOKEN_OP_DBL_SLASH: - case MP_TOKEN_OP_DBL_LESS: - case MP_TOKEN_OP_DBL_MORE: - case MP_TOKEN_OP_LESS_EQUAL: - case MP_TOKEN_OP_MORE_EQUAL: - case MP_TOKEN_OP_DBL_EQUAL: - case MP_TOKEN_OP_NOT_EQUAL: - case MP_TOKEN_DEL_PLUS_EQUAL: - case MP_TOKEN_DEL_MINUS_EQUAL: - case MP_TOKEN_DEL_STAR_EQUAL: - case MP_TOKEN_DEL_SLASH_EQUAL: - case MP_TOKEN_DEL_PERCENT_EQUAL: - case MP_TOKEN_DEL_AMPERSAND_EQUAL: - case MP_TOKEN_DEL_PIPE_EQUAL: - case MP_TOKEN_DEL_CARET_EQUAL: - case MP_TOKEN_DEL_MINUS_MORE: - return 2; - case MP_TOKEN_DEL_DBL_SLASH_EQUAL: - case MP_TOKEN_DEL_DBL_MORE_EQUAL: - case MP_TOKEN_DEL_DBL_LESS_EQUAL: - case MP_TOKEN_DEL_DBL_STAR_EQUAL: - return 3; - default: - return 1; +static inline size_t TokenLength(mp_lexer_t * lex, const char * tokenPosition) { + /* The lexer stores the beginning of the current token and of the next token, + * so we just use that. */ + if (lex->line > 1) { + /* The next token is on the next line, so we cannot just make the difference + * of the columns. */ + return UTF8Helper::CodePointSearch(tokenPosition, '\n') - tokenPosition; } + return lex->column - lex->tok_column; } void PythonTextArea::ContentView::loadSyntaxHighlighter() { @@ -133,7 +109,7 @@ void PythonTextArea::ContentView::drawLine(KDContext * ctx, int line, const char while (lex->tok_kind != MP_TOKEN_NEWLINE && lex->tok_kind != MP_TOKEN_END) { tokenFrom = firstNonSpace + lex->tok_column - 1; - tokenLength = TokenLength(lex); + tokenLength = TokenLength(lex, tokenFrom); LOG_DRAW("Draw \"%.*s\" for token %d\n", tokenLength, tokenFrom, lex->tok_kind); drawStringAt(ctx, line, UTF8Helper::GlyphOffsetAtCodePoint(text, tokenFrom), From 78eea601c753e9d08053b4cd823f47e5e2250b08 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Tue, 24 Sep 2019 18:37:20 +0200 Subject: [PATCH 002/680] [ion/device] Prevent the user from leaving DFU during software download We prevent the use of the Back key to leave DFU after a flash erase operation. This way, we prevent the user from interrupting a software download. After every software download, the calculator resets, which unlocks the "exit on pressing back" --- ion/src/device/shared/usb/calculator.cpp | 2 +- ion/src/device/shared/usb/calculator.h | 1 + ion/src/device/shared/usb/dfu_interface.cpp | 1 + ion/src/device/shared/usb/dfu_interface.h | 11 ++++++++++- 4 files changed, 13 insertions(+), 2 deletions(-) diff --git a/ion/src/device/shared/usb/calculator.cpp b/ion/src/device/shared/usb/calculator.cpp index 84fed03c5..73d6bf579 100644 --- a/ion/src/device/shared/usb/calculator.cpp +++ b/ion/src/device/shared/usb/calculator.cpp @@ -20,7 +20,7 @@ void Calculator::PollAndReset(bool exitWithKeyboard) { Ion::Device::Keyboard::activateRow(exitKeyRow); - while (!(exitWithKeyboard && Ion::Device::Keyboard::columnIsActive(exitKeyColumn)) && + while (!(exitWithKeyboard && !c.isErasingAndWriting() && Ion::Device::Keyboard::columnIsActive(exitKeyColumn)) && Ion::USB::isPlugged() && !c.isSoftDisconnected()) { c.poll(); diff --git a/ion/src/device/shared/usb/calculator.h b/ion/src/device/shared/usb/calculator.h index d35ba2a24..2532356e3 100644 --- a/ion/src/device/shared/usb/calculator.h +++ b/ion/src/device/shared/usb/calculator.h @@ -115,6 +115,7 @@ public: { } uint32_t addressPointer() const { return m_dfuInterface.addressPointer(); } + bool isErasingAndWriting() const { return m_dfuInterface.isErasingAndWriting(); } protected: virtual Descriptor * descriptor(uint8_t type, uint8_t index) override; virtual void setActiveConfiguration(uint8_t configurationIndex) override { diff --git a/ion/src/device/shared/usb/dfu_interface.cpp b/ion/src/device/shared/usb/dfu_interface.cpp index 5316f7b46..2b98274b4 100644 --- a/ion/src/device/shared/usb/dfu_interface.cpp +++ b/ion/src/device/shared/usb/dfu_interface.cpp @@ -209,6 +209,7 @@ void DFUInterface::eraseMemoryIfNeeded() { return; } + willErase(); if (m_erasePage == Flash::TotalNumberOfSectors()) { Flash::MassErase(); } else { diff --git a/ion/src/device/shared/usb/dfu_interface.h b/ion/src/device/shared/usb/dfu_interface.h index d36694dba..0ae25d874 100644 --- a/ion/src/device/shared/usb/dfu_interface.h +++ b/ion/src/device/shared/usb/dfu_interface.h @@ -27,12 +27,14 @@ public: m_largeBuffer{0}, m_largeBufferLength(0), m_writeAddress(0), - m_bInterfaceAlternateSetting(bInterfaceAlternateSetting) + m_bInterfaceAlternateSetting(bInterfaceAlternateSetting), + m_isErasingAndWriting(false) { } uint32_t addressPointer() const { return m_addressPointer; } void wholeDataReceivedCallback(SetupPacket * request, uint8_t * transferBuffer, uint16_t * transferBufferLength) override; void wholeDataSentCallback(SetupPacket * request, uint8_t * transferBuffer, uint16_t * transferBufferLength) override; + bool isErasingAndWriting() const { return m_isErasingAndWriting; } protected: void setActiveInterfaceAlternative(uint8_t interfaceAlternativeIndex) override { @@ -151,6 +153,12 @@ private: bool dfuAbort(uint16_t * transferBufferLength); // Leave DFU void leaveDFUAndReset(); + /* Erase and Write state. After starting the erase of flash memory, the user + * can no longer leave DFU mode by pressing the Back key of the keyboard. This + * way, we prevent the user from interrupting a software download. After every + * software download, the calculator resets, which unlocks the "exit on + * pressing back". */ + void willErase() { m_isErasingAndWriting = true; } Device * m_device; Status m_status; @@ -162,6 +170,7 @@ private: uint16_t m_largeBufferLength; uint32_t m_writeAddress; uint8_t m_bInterfaceAlternateSetting; + bool m_isErasingAndWriting; }; } From 9480bcacd54b47d8cae7b536424dc2212d372795 Mon Sep 17 00:00:00 2001 From: Ruben Dashyan Date: Tue, 17 Sep 2019 13:52:16 +0200 Subject: [PATCH 003/680] [apps/*/expression_model] Make expressionAddress private --- apps/sequence/sequence.h | 6 ++---- apps/shared/continuous_function.h | 3 +-- apps/shared/expression_model.h | 2 +- apps/solver/equation.h | 2 +- 4 files changed, 5 insertions(+), 8 deletions(-) diff --git a/apps/sequence/sequence.h b/apps/sequence/sequence.h index b866d4fb2..9647b9ba8 100644 --- a/apps/sequence/sequence.h +++ b/apps/sequence/sequence.h @@ -121,18 +121,16 @@ private: }; class DefinitionModel : public SequenceModel { - public: - void * expressionAddress(const Ion::Storage::Record * record) const override; private: + void * expressionAddress(const Ion::Storage::Record * record) const override; size_t expressionSize(const Ion::Storage::Record * record) const override; void buildName(Sequence * sequence) override; }; class InitialConditionModel : public SequenceModel { - public: - void * expressionAddress(const Ion::Storage::Record * record) const override; private: void updateMetaData(const Ion::Storage::Record * record, size_t newSize) override; + void * expressionAddress(const Ion::Storage::Record * record) const override; size_t expressionSize(const Ion::Storage::Record * record) const override; void buildName(Sequence * sequence) override; virtual int conditionIndex() const = 0; diff --git a/apps/shared/continuous_function.h b/apps/shared/continuous_function.h index 47dc04ddd..2f07d327e 100644 --- a/apps/shared/continuous_function.h +++ b/apps/shared/continuous_function.h @@ -106,9 +106,8 @@ private: //char m_expression[0]; }; class Model : public ExpressionModel { - public: - void * expressionAddress(const Ion::Storage::Record * record) const override; private: + void * expressionAddress(const Ion::Storage::Record * record) const override; size_t expressionSize(const Ion::Storage::Record * record) const override; }; size_t metaDataSize() const override { return sizeof(RecordDataBuffer); } diff --git a/apps/shared/expression_model.h b/apps/shared/expression_model.h index 87bade87c..eef47590f 100644 --- a/apps/shared/expression_model.h +++ b/apps/shared/expression_model.h @@ -23,7 +23,6 @@ public: // Property bool isCircularlyDefined(const Ion::Storage::Record * record, Poincare::Context * context) const; - virtual void * expressionAddress(const Ion::Storage::Record * record) const = 0; virtual void tidy() const; protected: @@ -33,6 +32,7 @@ protected: mutable Poincare::Layout m_layout; private: virtual void updateNewDataWithExpression(Ion::Storage::Record * record, const Poincare::Expression & expressionToStore, void * expressionAddress, size_t expressionToStoreSize, size_t previousExpressionSize); + virtual void * expressionAddress(const Ion::Storage::Record * record) const = 0; virtual size_t expressionSize(const Ion::Storage::Record * record) const = 0; mutable int m_circular; }; diff --git a/apps/solver/equation.h b/apps/solver/equation.h index 63fe1b11e..5add58440 100644 --- a/apps/solver/equation.h +++ b/apps/solver/equation.h @@ -19,8 +19,8 @@ private: public: Poincare::Expression standardForm(const Ion::Storage::Record * record, Poincare::Context * context) const; void tidy() const override; - void * expressionAddress(const Ion::Storage::Record * record) const override; private: + void * expressionAddress(const Ion::Storage::Record * record) const override; size_t expressionSize(const Ion::Storage::Record * record) const override; mutable Poincare::Expression m_standardForm; }; From 5750d005747c9cbb4b9250bb1bb61861087e38ab Mon Sep 17 00:00:00 2001 From: Ruben Dashyan Date: Wed, 18 Sep 2019 11:52:27 +0200 Subject: [PATCH 004/680] [apps/shared] Remove redundant call to isCircularlyDefined ExpressionModel::expressionReduced does already call isCircularlyDefined and returns undef if true. The isCircularlyDefined method is then made private. --- apps/shared/continuous_function.cpp | 2 +- apps/shared/expression_model.h | 4 +--- apps/shared/expression_model_handle.h | 1 - 3 files changed, 2 insertions(+), 5 deletions(-) diff --git a/apps/shared/continuous_function.cpp b/apps/shared/continuous_function.cpp index 6ce8aad6e..8ea2ca131 100644 --- a/apps/shared/continuous_function.cpp +++ b/apps/shared/continuous_function.cpp @@ -276,7 +276,7 @@ ContinuousFunction::RecordDataBuffer * ContinuousFunction::recordData() const { template Coordinate2D ContinuousFunction::templatedApproximateAtParameter(T t, Poincare::Context * context) const { - if (isCircularlyDefined(context) || t < tMin() || t > tMax()) { + if (t < tMin() || t > tMax()) { return Coordinate2D(plotType() == PlotType::Cartesian ? t : NAN, NAN); } constexpr int bufferSize = CodePoint::MaxCodePointCharLength + 1; diff --git a/apps/shared/expression_model.h b/apps/shared/expression_model.h index eef47590f..989432045 100644 --- a/apps/shared/expression_model.h +++ b/apps/shared/expression_model.h @@ -21,9 +21,6 @@ public: Ion::Storage::Record::ErrorStatus setContent(Ion::Storage::Record * record, const char * c, CodePoint symbol = 0); Ion::Storage::Record::ErrorStatus setExpressionContent(Ion::Storage::Record * record, const Poincare::Expression & newExpression); - // Property - bool isCircularlyDefined(const Ion::Storage::Record * record, Poincare::Context * context) const; - virtual void tidy() const; protected: // Setters helper @@ -34,6 +31,7 @@ private: virtual void updateNewDataWithExpression(Ion::Storage::Record * record, const Poincare::Expression & expressionToStore, void * expressionAddress, size_t expressionToStoreSize, size_t previousExpressionSize); virtual void * expressionAddress(const Ion::Storage::Record * record) const = 0; virtual size_t expressionSize(const Ion::Storage::Record * record) const = 0; + bool isCircularlyDefined(const Ion::Storage::Record * record, Poincare::Context * context) const; mutable int m_circular; }; diff --git a/apps/shared/expression_model_handle.h b/apps/shared/expression_model_handle.h index 585974c4d..7456ef3ad 100644 --- a/apps/shared/expression_model_handle.h +++ b/apps/shared/expression_model_handle.h @@ -16,7 +16,6 @@ public: void text(char * buffer, size_t bufferSize) const { return model()->text(this, buffer, bufferSize, symbol()); } virtual Poincare::Expression expressionReduced(Poincare::Context * context) const { return model()->expressionReduced(this, context); } Poincare::Expression expressionClone() const { return model()->expressionClone(this); } - bool isCircularlyDefined(Poincare::Context * context) const { return model()->isCircularlyDefined(this, context); } Poincare::Layout layout() { return model()->layout(this, symbol()); } /* Here, isDefined is the exact contrary of isEmpty. However, for Sequence * inheriting from ExpressionModelHandle, isEmpty and isDefined have not exactly From 34aa27ea08461efd96608cff540172d10f379207 Mon Sep 17 00:00:00 2001 From: Ruben Dashyan Date: Wed, 18 Sep 2019 11:55:57 +0200 Subject: [PATCH 005/680] [apps/shared/continuous_function] Simplify templatedApproximateAtParameter --- apps/shared/continuous_function.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/shared/continuous_function.cpp b/apps/shared/continuous_function.cpp index 8ea2ca131..9a7ae63ea 100644 --- a/apps/shared/continuous_function.cpp +++ b/apps/shared/continuous_function.cpp @@ -283,11 +283,11 @@ Coordinate2D ContinuousFunction::templatedApproximateAtParameter(T t, Poincar char unknown[bufferSize]; Poincare::SerializationHelper::CodePoint(unknown, bufferSize, UCodePointUnknownX); PlotType type = plotType(); - if (type == PlotType::Cartesian || type == PlotType::Polar) { - return Coordinate2D(t, PoincareHelpers::ApproximateWithValueForSymbol(expressionReduced(context), unknown, t, context)); - } - assert(type == PlotType::Parametric); Expression e = expressionReduced(context); + if (type != PlotType::Parametric) { + assert(type == PlotType::Cartesian || type == PlotType::Polar); + return Coordinate2D(t, PoincareHelpers::ApproximateWithValueForSymbol(e, unknown, t, context)); + } assert(e.type() == ExpressionNode::Type::Matrix); assert(static_cast(e).numberOfRows() == 2); assert(static_cast(e).numberOfColumns() == 1); From a52fd2c697bdf6123857eab9df00232d263f19a2 Mon Sep 17 00:00:00 2001 From: Ruben Dashyan Date: Wed, 25 Sep 2019 15:05:28 +0200 Subject: [PATCH 006/680] [apps/graph/graph_view] Do not draw the functions with undef expression --- apps/graph/graph/graph_view.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/apps/graph/graph/graph_view.cpp b/apps/graph/graph/graph_view.cpp index 3a09ba708..30a353231 100644 --- a/apps/graph/graph/graph_view.cpp +++ b/apps/graph/graph/graph_view.cpp @@ -29,6 +29,13 @@ void GraphView::drawRect(KDContext * ctx, KDRect rect) const { Ion::Storage::Record record = functionStore->activeRecordAtIndex(i); ExpiringPointer f = functionStore->modelForRecord(record);; Shared::ContinuousFunction::PlotType type = f->plotType(); + Poincare::Expression e = f->expressionReduced(context()); + if (e.isUndefined() || ( + type == Shared::ContinuousFunction::PlotType::Parametric && + e.childAtIndex(0).isUndefined() && + e.childAtIndex(1).isUndefined())) { + continue; + } float tmin = f->tMin(); float tmax = f->tMax(); /* The step is a fraction of tmax-tmin. We will evaluate the function at From 7539a0dc376863999e94e189222c26fd70810ccd Mon Sep 17 00:00:00 2001 From: Ruben Dashyan Date: Tue, 17 Sep 2019 10:48:12 +0200 Subject: [PATCH 007/680] [poincare/symbol] Remove SymbolNode::isUnknown unnecessary parameter --- poincare/include/poincare/symbol.h | 4 ++-- poincare/src/symbol.cpp | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/poincare/include/poincare/symbol.h b/poincare/include/poincare/symbol.h index e80f66836..38690da62 100644 --- a/poincare/include/poincare/symbol.h +++ b/poincare/include/poincare/symbol.h @@ -40,7 +40,7 @@ public: Evaluation approximate(SinglePrecision p, Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit) const override { return templatedApproximate(context, complexFormat, angleUnit); } Evaluation approximate(DoublePrecision p, Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit) const override { return templatedApproximate(context, complexFormat, angleUnit); } - bool isUnknown(CodePoint unknownSymbol) const; + bool isUnknown() const; private: char m_name[0]; // MUST be the last member variable @@ -61,7 +61,7 @@ public: static Symbol Ans() { return Symbol::Builder(k_ans, k_ansLength); } // Symbol properties - bool isSystemSymbol() const { return node()->isUnknown(UCodePointUnknownX); } + bool isSystemSymbol() const { return node()->isUnknown(); } const char * name() const { return node()->name(); } static bool isSeriesSymbol(const char * c); static bool isRegressionSymbol(const char * c); diff --git a/poincare/src/symbol.cpp b/poincare/src/symbol.cpp index 625523b2d..7ba4a5a9d 100644 --- a/poincare/src/symbol.cpp +++ b/poincare/src/symbol.cpp @@ -67,11 +67,11 @@ int SymbolNode::getVariables(Context * context, isVariableTest isVariable, char } float SymbolNode::characteristicXRange(Context * context, Preferences::AngleUnit angleUnit) const { - return isUnknown(UCodePointUnknownX) ? NAN : 0.0f; + return isUnknown() ? NAN : 0.0f; } Layout SymbolNode::createLayout(Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const { - assert(!isUnknown(UCodePointUnknownX)); + assert(!isUnknown()); // TODO return Parse(m_name).createLayout() ? // Special case for the symbol names: u(n), u(n+1), v(n), v(n+1), w(n), w(n+1) const char * sequenceIndex[] = {"n", "n+1"}; @@ -126,8 +126,8 @@ Evaluation SymbolNode::templatedApproximate(Context * context, Preferences::C return e.node()->approximate(T(), context, complexFormat, angleUnit); } -bool SymbolNode::isUnknown(CodePoint unknownSymbol) const { - bool result = UTF8Helper::CodePointIs(m_name, unknownSymbol); +bool SymbolNode::isUnknown() const { + bool result = UTF8Helper::CodePointIs(m_name, UCodePointUnknownX); if (result) { assert(m_name[1] == 0); } From 47ed5814a2d6af3cf6eaeab1754ab209699dd521 Mon Sep 17 00:00:00 2001 From: Ruben Dashyan Date: Wed, 25 Sep 2019 14:26:55 +0200 Subject: [PATCH 008/680] [poincare] Remove hasReplaceableSymbols --- poincare/include/poincare/expression.h | 5 ++--- poincare/include/poincare/expression_node.h | 2 +- poincare/include/poincare/function.h | 4 ++-- poincare/include/poincare/symbol.h | 4 ++-- poincare/src/expression.cpp | 22 +++++++-------------- poincare/src/expression_node.cpp | 4 ++-- poincare/src/function.cpp | 7 ++++--- poincare/src/symbol.cpp | 7 ++++--- 8 files changed, 24 insertions(+), 31 deletions(-) diff --git a/poincare/include/poincare/expression.h b/poincare/include/poincare/expression.h index b1abfac91..6aabac330 100644 --- a/poincare/include/poincare/expression.h +++ b/poincare/include/poincare/expression.h @@ -326,9 +326,8 @@ protected: /* Properties */ int getPolynomialCoefficients(Context * context, const char * symbolName, Expression coefficients[]) const { return node()->getPolynomialCoefficients(context, symbolName, coefficients); } Expression defaultReplaceSymbolWithExpression(const SymbolAbstract & symbol, const Expression expression); - bool hasReplaceableSymbols(Context * context) const; - Expression shallowReplaceReplaceableSymbols(Context * context) { return node()->shallowReplaceReplaceableSymbols(context); } - Expression defaultReplaceReplaceableSymbols(Context * context); + Expression shallowReplaceReplaceableSymbols(Context * context, bool * didReplace) { return node()->shallowReplaceReplaceableSymbols(context, didReplace); } + Expression defaultReplaceReplaceableSymbols(Context * context, bool * didReplace); /* Simplification */ void beautifyAndApproximateScalar(Expression * simplifiedExpression, Expression * approximateExpression, ExpressionNode::ReductionContext userReductionContext, Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit); diff --git a/poincare/include/poincare/expression_node.h b/poincare/include/poincare/expression_node.h index 96d8ebe96..0b9af9239 100644 --- a/poincare/include/poincare/expression_node.h +++ b/poincare/include/poincare/expression_node.h @@ -162,7 +162,7 @@ public: /*!*/ virtual Expression setSign(Sign s, ReductionContext reductionContext); virtual int polynomialDegree(Context * context, const char * symbolName) const; /*!*/ virtual int getPolynomialCoefficients(Context * context, const char * symbolName, Expression coefficients[]) const; - /*!*/ virtual Expression shallowReplaceReplaceableSymbols(Context * context); + /*!*/ virtual Expression shallowReplaceReplaceableSymbols(Context * context, bool * didReplace); typedef bool (*isVariableTest)(const char * c); virtual int getVariables(Context * context, isVariableTest isVariable, char * variables, int maxSizeVariable) const; virtual float characteristicXRange(Context * context, Preferences::AngleUnit angleUnit) const; diff --git a/poincare/include/poincare/function.h b/poincare/include/poincare/function.h index d89e6fc96..65b0b99e4 100644 --- a/poincare/include/poincare/function.h +++ b/poincare/include/poincare/function.h @@ -38,7 +38,7 @@ private: int serialize(char * buffer, int bufferSize, Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const override; // Simplification Expression shallowReduce(ReductionContext reductionContext) override; - Expression shallowReplaceReplaceableSymbols(Context * context) override; + Expression shallowReplaceReplaceableSymbols(Context * context, bool * didReplace) override; LayoutShape leftLayoutShape() const override { return strlen(m_name) > 1 ? LayoutShape::MoreLetters : LayoutShape::OneLetter; }; LayoutShape rightLayoutShape() const override { return LayoutShape::BoundaryPunctuation; } @@ -57,7 +57,7 @@ public: // Simplification Expression replaceSymbolWithExpression(const SymbolAbstract & symbol, const Expression & expression); Expression shallowReduce(ExpressionNode::ReductionContext reductionContext); - Expression shallowReplaceReplaceableSymbols(Context * context); + Expression shallowReplaceReplaceableSymbols(Context * context, bool * didReplace); private: //VariableContext unknownXContext(Context & parentContext) const; }; diff --git a/poincare/include/poincare/symbol.h b/poincare/include/poincare/symbol.h index 38690da62..35db17fc1 100644 --- a/poincare/include/poincare/symbol.h +++ b/poincare/include/poincare/symbol.h @@ -33,7 +33,7 @@ public: /* Simplification */ Expression shallowReduce(ReductionContext reductionContext) override; - Expression shallowReplaceReplaceableSymbols(Context * context) override; + Expression shallowReplaceReplaceableSymbols(Context * context, bool * didReplace) override; LayoutShape leftLayoutShape() const override; /* Approximation */ @@ -70,7 +70,7 @@ public: Expression shallowReduce(ExpressionNode::ReductionContext reductionContext); Expression replaceSymbolWithExpression(const SymbolAbstract & symbol, const Expression & expression); int getPolynomialCoefficients(Context * context, const char * symbolName, Expression coefficients[]) const; - Expression shallowReplaceReplaceableSymbols(Context * context); + Expression shallowReplaceReplaceableSymbols(Context * context, bool * didReplace); private: SymbolNode * node() const { return static_cast(Expression::node()); } }; diff --git a/poincare/src/expression.cpp b/poincare/src/expression.cpp index 5e3652b2a..55c35d8c6 100644 --- a/poincare/src/expression.cpp +++ b/poincare/src/expression.cpp @@ -339,20 +339,10 @@ void Expression::defaultSetChildrenInPlace(Expression other) { } } -bool Expression::hasReplaceableSymbols(Context * context) const { - return recursivelyMatches([](const Expression e, Context * context) { - return (e.type() == ExpressionNode::Type::Symbol - && !static_cast(e).isSystemSymbol() - && !context->expressionForSymbolAbstract(static_cast(e), false).isUninitialized()) - || (e.type() == ExpressionNode::Type::Function - && !context->expressionForSymbolAbstract(static_cast(e), false).isUninitialized()); - }, context, false); -} - -Expression Expression::defaultReplaceReplaceableSymbols(Context * context) { +Expression Expression::defaultReplaceReplaceableSymbols(Context * context, bool * didReplace) { int nbChildren = numberOfChildren(); for (int i = 0; i < nbChildren; i++) { - childAtIndex(i).shallowReplaceReplaceableSymbols(context); + childAtIndex(i).shallowReplaceReplaceableSymbols(context, didReplace); } return *this; } @@ -672,14 +662,16 @@ Expression Expression::ExpressionWithoutSymbols(Expression e, Context * context) sSymbolReplacementsCountLock = true; unlock = true; } - while (e.hasReplaceableSymbols(context)) { + bool didReplace; + do { replacementCount++; if (replacementCount > k_maxSymbolReplacementsCount) { e = Expression(); break; } - e = e.shallowReplaceReplaceableSymbols(context); - } + didReplace = false; + e = e.shallowReplaceReplaceableSymbols(context, &didReplace); + } while (didReplace); if (unlock) { sSymbolReplacementsCountLock = false; } diff --git a/poincare/src/expression_node.cpp b/poincare/src/expression_node.cpp index c69dfadd2..1bd70c4fc 100644 --- a/poincare/src/expression_node.cpp +++ b/poincare/src/expression_node.cpp @@ -36,8 +36,8 @@ int ExpressionNode::getPolynomialCoefficients(Context * context, const char * sy return Expression(this).defaultGetPolynomialCoefficients(context, symbolName, coefficients); } -Expression ExpressionNode::shallowReplaceReplaceableSymbols(Context * context) { - return Expression(this).defaultReplaceReplaceableSymbols(context); +Expression ExpressionNode::shallowReplaceReplaceableSymbols(Context * context, bool * didReplace) { + return Expression(this).defaultReplaceReplaceableSymbols(context, didReplace); } int ExpressionNode::getVariables(Context * context, isVariableTest isVariable, char * variables, int maxSizeVariable) const { diff --git a/poincare/src/function.cpp b/poincare/src/function.cpp index 406f8446c..25a463b3b 100644 --- a/poincare/src/function.cpp +++ b/poincare/src/function.cpp @@ -66,8 +66,8 @@ Expression FunctionNode::shallowReduce(ReductionContext reductionContext) { return Function(this).shallowReduce(reductionContext); // This uses Symbol::shallowReduce } -Expression FunctionNode::shallowReplaceReplaceableSymbols(Context * context) { - return Function(this).shallowReplaceReplaceableSymbols(context); +Expression FunctionNode::shallowReplaceReplaceableSymbols(Context * context, bool * didReplace) { + return Function(this).shallowReplaceReplaceableSymbols(context, didReplace); } Evaluation FunctionNode::approximate(SinglePrecision p, Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit) const { @@ -128,7 +128,7 @@ Expression Function::shallowReduce(ExpressionNode::ReductionContext reductionCon return *this; } -Expression Function::shallowReplaceReplaceableSymbols(Context * context) { +Expression Function::shallowReplaceReplaceableSymbols(Context * context, bool * didReplace) { Expression e = context->expressionForSymbolAbstract(*this, true); if (e.isUninitialized()) { return *this; @@ -145,6 +145,7 @@ Expression Function::shallowReplaceReplaceableSymbols(Context * context) { } e.replaceSymbolWithExpression(Symbol::Builder(UCodePointUnknownX), childAtIndex(0)); replaceWithInPlace(e); + *didReplace = true; return e; } diff --git a/poincare/src/symbol.cpp b/poincare/src/symbol.cpp index 7ba4a5a9d..b06756e9f 100644 --- a/poincare/src/symbol.cpp +++ b/poincare/src/symbol.cpp @@ -103,8 +103,8 @@ Expression SymbolNode::shallowReduce(ReductionContext reductionContext) { return Symbol(this).shallowReduce(reductionContext); } -Expression SymbolNode::shallowReplaceReplaceableSymbols(Context * context) { - return Symbol(this).shallowReplaceReplaceableSymbols(context); +Expression SymbolNode::shallowReplaceReplaceableSymbols(Context * context, bool * didReplace) { + return Symbol(this).shallowReplaceReplaceableSymbols(context, didReplace); } ExpressionNode::LayoutShape SymbolNode::leftLayoutShape() const { @@ -224,7 +224,7 @@ int Symbol::getPolynomialCoefficients(Context * context, const char * symbolName return 0; } -Expression Symbol::shallowReplaceReplaceableSymbols(Context * context) { +Expression Symbol::shallowReplaceReplaceableSymbols(Context * context, bool * didReplace) { if (isSystemSymbol()) { return *this; } @@ -243,6 +243,7 @@ Expression Symbol::shallowReplaceReplaceableSymbols(Context * context) { return replaceWithUndefinedInPlace(); } replaceWithInPlace(e); + *didReplace = true; return e; } From dd80be026d22cee7352191a86db7b373dc86a896 Mon Sep 17 00:00:00 2001 From: Ruben Dashyan Date: Wed, 25 Sep 2019 15:30:10 +0200 Subject: [PATCH 009/680] [poincare] Rename shallowReplaceReplaceableSymbols to deep... --- poincare/include/poincare/expression.h | 2 +- poincare/include/poincare/expression_node.h | 2 +- poincare/include/poincare/function.h | 4 ++-- poincare/include/poincare/symbol.h | 4 ++-- poincare/src/expression.cpp | 4 ++-- poincare/src/expression_node.cpp | 2 +- poincare/src/function.cpp | 6 +++--- poincare/src/symbol.cpp | 6 +++--- 8 files changed, 15 insertions(+), 15 deletions(-) diff --git a/poincare/include/poincare/expression.h b/poincare/include/poincare/expression.h index 6aabac330..05e649fb7 100644 --- a/poincare/include/poincare/expression.h +++ b/poincare/include/poincare/expression.h @@ -326,7 +326,7 @@ protected: /* Properties */ int getPolynomialCoefficients(Context * context, const char * symbolName, Expression coefficients[]) const { return node()->getPolynomialCoefficients(context, symbolName, coefficients); } Expression defaultReplaceSymbolWithExpression(const SymbolAbstract & symbol, const Expression expression); - Expression shallowReplaceReplaceableSymbols(Context * context, bool * didReplace) { return node()->shallowReplaceReplaceableSymbols(context, didReplace); } + Expression deepReplaceReplaceableSymbols(Context * context, bool * didReplace) { return node()->deepReplaceReplaceableSymbols(context, didReplace); } Expression defaultReplaceReplaceableSymbols(Context * context, bool * didReplace); /* Simplification */ diff --git a/poincare/include/poincare/expression_node.h b/poincare/include/poincare/expression_node.h index 0b9af9239..b26ef318a 100644 --- a/poincare/include/poincare/expression_node.h +++ b/poincare/include/poincare/expression_node.h @@ -162,7 +162,7 @@ public: /*!*/ virtual Expression setSign(Sign s, ReductionContext reductionContext); virtual int polynomialDegree(Context * context, const char * symbolName) const; /*!*/ virtual int getPolynomialCoefficients(Context * context, const char * symbolName, Expression coefficients[]) const; - /*!*/ virtual Expression shallowReplaceReplaceableSymbols(Context * context, bool * didReplace); + /*!*/ virtual Expression deepReplaceReplaceableSymbols(Context * context, bool * didReplace); typedef bool (*isVariableTest)(const char * c); virtual int getVariables(Context * context, isVariableTest isVariable, char * variables, int maxSizeVariable) const; virtual float characteristicXRange(Context * context, Preferences::AngleUnit angleUnit) const; diff --git a/poincare/include/poincare/function.h b/poincare/include/poincare/function.h index 65b0b99e4..1891d84e2 100644 --- a/poincare/include/poincare/function.h +++ b/poincare/include/poincare/function.h @@ -38,7 +38,7 @@ private: int serialize(char * buffer, int bufferSize, Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const override; // Simplification Expression shallowReduce(ReductionContext reductionContext) override; - Expression shallowReplaceReplaceableSymbols(Context * context, bool * didReplace) override; + Expression deepReplaceReplaceableSymbols(Context * context, bool * didReplace) override; LayoutShape leftLayoutShape() const override { return strlen(m_name) > 1 ? LayoutShape::MoreLetters : LayoutShape::OneLetter; }; LayoutShape rightLayoutShape() const override { return LayoutShape::BoundaryPunctuation; } @@ -57,7 +57,7 @@ public: // Simplification Expression replaceSymbolWithExpression(const SymbolAbstract & symbol, const Expression & expression); Expression shallowReduce(ExpressionNode::ReductionContext reductionContext); - Expression shallowReplaceReplaceableSymbols(Context * context, bool * didReplace); + Expression deepReplaceReplaceableSymbols(Context * context, bool * didReplace); private: //VariableContext unknownXContext(Context & parentContext) const; }; diff --git a/poincare/include/poincare/symbol.h b/poincare/include/poincare/symbol.h index 35db17fc1..393b552f2 100644 --- a/poincare/include/poincare/symbol.h +++ b/poincare/include/poincare/symbol.h @@ -33,7 +33,7 @@ public: /* Simplification */ Expression shallowReduce(ReductionContext reductionContext) override; - Expression shallowReplaceReplaceableSymbols(Context * context, bool * didReplace) override; + Expression deepReplaceReplaceableSymbols(Context * context, bool * didReplace) override; LayoutShape leftLayoutShape() const override; /* Approximation */ @@ -70,7 +70,7 @@ public: Expression shallowReduce(ExpressionNode::ReductionContext reductionContext); Expression replaceSymbolWithExpression(const SymbolAbstract & symbol, const Expression & expression); int getPolynomialCoefficients(Context * context, const char * symbolName, Expression coefficients[]) const; - Expression shallowReplaceReplaceableSymbols(Context * context, bool * didReplace); + Expression deepReplaceReplaceableSymbols(Context * context, bool * didReplace); private: SymbolNode * node() const { return static_cast(Expression::node()); } }; diff --git a/poincare/src/expression.cpp b/poincare/src/expression.cpp index 55c35d8c6..23bca3ef0 100644 --- a/poincare/src/expression.cpp +++ b/poincare/src/expression.cpp @@ -342,7 +342,7 @@ void Expression::defaultSetChildrenInPlace(Expression other) { Expression Expression::defaultReplaceReplaceableSymbols(Context * context, bool * didReplace) { int nbChildren = numberOfChildren(); for (int i = 0; i < nbChildren; i++) { - childAtIndex(i).shallowReplaceReplaceableSymbols(context, didReplace); + childAtIndex(i).deepReplaceReplaceableSymbols(context, didReplace); } return *this; } @@ -670,7 +670,7 @@ Expression Expression::ExpressionWithoutSymbols(Expression e, Context * context) break; } didReplace = false; - e = e.shallowReplaceReplaceableSymbols(context, &didReplace); + e = e.deepReplaceReplaceableSymbols(context, &didReplace); } while (didReplace); if (unlock) { sSymbolReplacementsCountLock = false; diff --git a/poincare/src/expression_node.cpp b/poincare/src/expression_node.cpp index 1bd70c4fc..350c223db 100644 --- a/poincare/src/expression_node.cpp +++ b/poincare/src/expression_node.cpp @@ -36,7 +36,7 @@ int ExpressionNode::getPolynomialCoefficients(Context * context, const char * sy return Expression(this).defaultGetPolynomialCoefficients(context, symbolName, coefficients); } -Expression ExpressionNode::shallowReplaceReplaceableSymbols(Context * context, bool * didReplace) { +Expression ExpressionNode::deepReplaceReplaceableSymbols(Context * context, bool * didReplace) { return Expression(this).defaultReplaceReplaceableSymbols(context, didReplace); } diff --git a/poincare/src/function.cpp b/poincare/src/function.cpp index 25a463b3b..14b9e3109 100644 --- a/poincare/src/function.cpp +++ b/poincare/src/function.cpp @@ -66,8 +66,8 @@ Expression FunctionNode::shallowReduce(ReductionContext reductionContext) { return Function(this).shallowReduce(reductionContext); // This uses Symbol::shallowReduce } -Expression FunctionNode::shallowReplaceReplaceableSymbols(Context * context, bool * didReplace) { - return Function(this).shallowReplaceReplaceableSymbols(context, didReplace); +Expression FunctionNode::deepReplaceReplaceableSymbols(Context * context, bool * didReplace) { + return Function(this).deepReplaceReplaceableSymbols(context, didReplace); } Evaluation FunctionNode::approximate(SinglePrecision p, Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit) const { @@ -128,7 +128,7 @@ Expression Function::shallowReduce(ExpressionNode::ReductionContext reductionCon return *this; } -Expression Function::shallowReplaceReplaceableSymbols(Context * context, bool * didReplace) { +Expression Function::deepReplaceReplaceableSymbols(Context * context, bool * didReplace) { Expression e = context->expressionForSymbolAbstract(*this, true); if (e.isUninitialized()) { return *this; diff --git a/poincare/src/symbol.cpp b/poincare/src/symbol.cpp index b06756e9f..d235f7a3b 100644 --- a/poincare/src/symbol.cpp +++ b/poincare/src/symbol.cpp @@ -103,8 +103,8 @@ Expression SymbolNode::shallowReduce(ReductionContext reductionContext) { return Symbol(this).shallowReduce(reductionContext); } -Expression SymbolNode::shallowReplaceReplaceableSymbols(Context * context, bool * didReplace) { - return Symbol(this).shallowReplaceReplaceableSymbols(context, didReplace); +Expression SymbolNode::deepReplaceReplaceableSymbols(Context * context, bool * didReplace) { + return Symbol(this).deepReplaceReplaceableSymbols(context, didReplace); } ExpressionNode::LayoutShape SymbolNode::leftLayoutShape() const { @@ -224,7 +224,7 @@ int Symbol::getPolynomialCoefficients(Context * context, const char * symbolName return 0; } -Expression Symbol::shallowReplaceReplaceableSymbols(Context * context, bool * didReplace) { +Expression Symbol::deepReplaceReplaceableSymbols(Context * context, bool * didReplace) { if (isSystemSymbol()) { return *this; } From 3183ca7d7ec4692ecefb2d348a0f6ceb3a403024 Mon Sep 17 00:00:00 2001 From: Ruben Dashyan Date: Mon, 16 Sep 2019 16:34:40 +0200 Subject: [PATCH 010/680] Replace Poincare::Function unknown earlier (in Context) --- apps/shared/global_context.cpp | 9 ++++++++- poincare/src/function.cpp | 5 ----- poincare/src/store.cpp | 24 +++--------------------- poincare/src/symbol_abstract.cpp | 3 --- 4 files changed, 11 insertions(+), 30 deletions(-) diff --git a/apps/shared/global_context.cpp b/apps/shared/global_context.cpp index 6f214a5f9..418ed78c4 100644 --- a/apps/shared/global_context.cpp +++ b/apps/shared/global_context.cpp @@ -52,6 +52,9 @@ void GlobalContext::setExpressionForSymbolAbstract(const Expression & expression SetExpressionForActualSymbol(finalExpression, symbol, record); } else { assert(symbol.type() == ExpressionNode::Type::Function); + Expression child = symbol.childAtIndex(0); + assert(child.type() == ExpressionNode::Type::Symbol); + finalExpression = finalExpression.replaceSymbolWithExpression(static_cast(child), Symbol::Builder(UCodePointUnknownX)); SetExpressionForFunction(finalExpression, symbol, record); } } @@ -79,7 +82,11 @@ const Expression GlobalContext::ExpressionForFunction(const SymbolAbstract & sym } /* An function record value has metadata before the expression. To get the * expression, use the function record handle. */ - return ContinuousFunction(r).expressionClone(); + Expression e = ContinuousFunction(r).expressionClone(); + if (!e.isUninitialized()) { + e = e.replaceSymbolWithExpression(Symbol::Builder(UCodePointUnknownX), symbol.childAtIndex(0)); + } + return e; } Ion::Storage::Record::ErrorStatus GlobalContext::SetExpressionForActualSymbol(const Expression & expression, const SymbolAbstract & symbol, Ion::Storage::Record previousRecord) { diff --git a/poincare/src/function.cpp b/poincare/src/function.cpp index 14b9e3109..c5bdf51b3 100644 --- a/poincare/src/function.cpp +++ b/poincare/src/function.cpp @@ -101,10 +101,6 @@ Expression Function::replaceSymbolWithExpression(const SymbolAbstract & symbol, childAtIndex(0).replaceSymbolWithExpression(symbol, expression); if (symbol.type() == ExpressionNode::Type::Function && strcmp(name(), symbol.name()) == 0) { Expression value = expression.clone(); - // Replace the unknown in the new expression by the function's child - Symbol xSymbol = Symbol::Builder(UCodePointUnknownX); - Expression xValue = childAtIndex(0); - value = value.replaceSymbolWithExpression(xSymbol, xValue); Expression p = parent(); if (!p.isUninitialized() && p.node()->childAtIndexNeedsUserParentheses(value, p.indexOfChild(*this))) { value = Parenthesis::Builder(value); @@ -143,7 +139,6 @@ Expression Function::deepReplaceReplaceableSymbols(Context * context, bool * did { return replaceWithUndefinedInPlace(); } - e.replaceSymbolWithExpression(Symbol::Builder(UCodePointUnknownX), childAtIndex(0)); replaceWithInPlace(e); *didReplace = true; return e; diff --git a/poincare/src/store.cpp b/poincare/src/store.cpp index 4e894bc85..1f26a4669 100644 --- a/poincare/src/store.cpp +++ b/poincare/src/store.cpp @@ -67,31 +67,13 @@ Expression Store::shallowReduce(ExpressionNode::ReductionContext reductionContex } Expression Store::storeValueForSymbol(Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit) const { - Expression finalValue; - if (symbol().type() == ExpressionNode::Type::Function) { - // In tata + 2 ->f(tata), replace tata with xUnknown symbol - assert(symbol().childAtIndex(0).type() == ExpressionNode::Type::Symbol); - Expression userDefinedUnknown = symbol().childAtIndex(0); - Symbol xUnknown = Symbol::Builder(UCodePointUnknownX); - finalValue = childAtIndex(0).replaceSymbolWithExpression(static_cast(userDefinedUnknown), xUnknown); - } else { - assert(symbol().type() == ExpressionNode::Type::Symbol); - finalValue = childAtIndex(0); - } - assert(!finalValue.isUninitialized()); - context->setExpressionForSymbolAbstract(finalValue, symbol()); - Expression storedExpression = context->expressionForSymbolAbstract(symbol(), true); + assert(!value().isUninitialized()); + context->setExpressionForSymbolAbstract(value(), symbol()); + Expression storedExpression = context->expressionForSymbolAbstract(symbol(), false); if (storedExpression.isUninitialized()) { return Undefined::Builder(); } - if (symbol().type() == ExpressionNode::Type::Function) { - // Replace the xUnknown symbol with the variable initially used - assert(symbol().childAtIndex(0).type() == ExpressionNode::Type::Symbol); - Expression userDefinedUnknown = symbol().childAtIndex(0); - Symbol xUnknown = Symbol::Builder(UCodePointUnknownX); - storedExpression = storedExpression.replaceSymbolWithExpression(xUnknown, static_cast(userDefinedUnknown)); - } return storedExpression; } diff --git a/poincare/src/symbol_abstract.cpp b/poincare/src/symbol_abstract.cpp index 244e0e86d..a6754aeec 100644 --- a/poincare/src/symbol_abstract.cpp +++ b/poincare/src/symbol_abstract.cpp @@ -64,9 +64,6 @@ Expression SymbolAbstract::Expand(const SymbolAbstract & symbol, Context * conte /* Replace all the symbols iteratively. This prevents a memory failure when * symbols are defined circularly. */ e = Expression::ExpressionWithoutSymbols(e, context); - if (!e.isUninitialized() && isFunction) { - e = e.replaceSymbolWithExpression(Symbol::Builder(UCodePointUnknownX), symbol.childAtIndex(0)); - } return e; } From fc392d4e81f372527f08bfb7f1ed26ad90abb8e0 Mon Sep 17 00:00:00 2001 From: Ruben Dashyan Date: Mon, 16 Sep 2019 16:53:57 +0200 Subject: [PATCH 011/680] [poincare/function] Remove old TODO --- poincare/include/poincare/function.h | 2 -- poincare/src/function.cpp | 31 ---------------------------- 2 files changed, 33 deletions(-) diff --git a/poincare/include/poincare/function.h b/poincare/include/poincare/function.h index 1891d84e2..bfc0d4a59 100644 --- a/poincare/include/poincare/function.h +++ b/poincare/include/poincare/function.h @@ -58,8 +58,6 @@ public: Expression replaceSymbolWithExpression(const SymbolAbstract & symbol, const Expression & expression); Expression shallowReduce(ExpressionNode::ReductionContext reductionContext); Expression deepReplaceReplaceableSymbols(Context * context, bool * didReplace); -private: - //VariableContext unknownXContext(Context & parentContext) const; }; } diff --git a/poincare/src/function.cpp b/poincare/src/function.cpp index c5bdf51b3..d8ee6add4 100644 --- a/poincare/src/function.cpp +++ b/poincare/src/function.cpp @@ -144,35 +144,4 @@ Expression Function::deepReplaceReplaceableSymbols(Context * context, bool * did return e; } -// TODO: should we avoid replacing unknown X in-place but use a context instead? -#if 0 -VariableContext Function::unknownXContext(Context & parentContext) const { - Symbol unknownXSymbol = Symbol::Builder(UCodePointUnknownX); - Expression child = childAtIndex(0); - const char x[] = {UCodePointUnknownX, 0}; // UGLY, use decoder - /* COMMENT */ - if (child.type() == ExpressionNode::Type::Symbol && static_cast(child).isSystemSymbol()) { - return parentContext; - } - - VariableContext xContext = VariableContext(x, &parentContext); - - /* If the parentContext already has an expression for UnknownX, we have to - * replace in childAtIndex(0) any occurence of UnknownX by its value in - * parentContext. That way, we handle: evaluatin f(x-1) with x = 2 & f:x->x^2 */ - Expression unknownXValue = parentContext.expressionForSymbolAbstract(unknownXSymbol, true); - if (!unknownXValue.isUninitialized()) { - xContext = static_cast(parentContext); // copy the parentContext - child.replaceSymbolWithExpression(unknownXSymbol, unknownXValue); - } - /* We here assert that child contains no occurrence of UnknownX to avoid - * creating an infinite loop (for instance: unknownXSymbol = unknownXSymbol+2). */ - assert(!child.recursivelyMatches([](const Expression e, Context * context, bool replaceSymbol) { - return e.type() == ExpressionNode::Type::Symbol && static_cast(e).isSystemSymbol(); - }, parentContext, false)); - xContext.setExpressionForSymbolAbstract(child, unknownXSymbol, xContext); - return xContext; -} -#endif - } From b728fb8a1b292edaefc7ee7b3bca0c6cbf9a3283 Mon Sep 17 00:00:00 2001 From: Ruben Dashyan Date: Wed, 25 Sep 2019 10:14:30 +0200 Subject: [PATCH 012/680] [poincare/symbol_abstract] No need to clone the expression for a Function Already cloned in the global context. --- poincare/src/function.cpp | 2 +- poincare/src/symbol_abstract.cpp | 5 +---- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/poincare/src/function.cpp b/poincare/src/function.cpp index d8ee6add4..706bad731 100644 --- a/poincare/src/function.cpp +++ b/poincare/src/function.cpp @@ -125,7 +125,7 @@ Expression Function::shallowReduce(ExpressionNode::ReductionContext reductionCon } Expression Function::deepReplaceReplaceableSymbols(Context * context, bool * didReplace) { - Expression e = context->expressionForSymbolAbstract(*this, true); + Expression e = context->expressionForSymbolAbstract(*this, false); if (e.isUninitialized()) { return *this; } diff --git a/poincare/src/symbol_abstract.cpp b/poincare/src/symbol_abstract.cpp index a6754aeec..41c2bfc6b 100644 --- a/poincare/src/symbol_abstract.cpp +++ b/poincare/src/symbol_abstract.cpp @@ -57,10 +57,7 @@ bool SymbolAbstract::matches(const SymbolAbstract & symbol, ExpressionTest test, } Expression SymbolAbstract::Expand(const SymbolAbstract & symbol, Context * context, bool clone) { - bool isFunction = symbol.type() == ExpressionNode::Type::Function; - /* Always clone the expression for Function because we are going to alter e - * by replacing all UnknownX in it. */ - Expression e = context->expressionForSymbolAbstract(symbol, clone || isFunction); + Expression e = context->expressionForSymbolAbstract(symbol, clone); /* Replace all the symbols iteratively. This prevents a memory failure when * symbols are defined circularly. */ e = Expression::ExpressionWithoutSymbols(e, context); From c3cf5c1ef40f7bab555026403a8c52c7f12c0735 Mon Sep 17 00:00:00 2001 From: Ruben Dashyan Date: Thu, 26 Sep 2019 10:29:00 +0200 Subject: [PATCH 013/680] Rename UCodePointUnknownX to UCodePointUnknown --- apps/sequence/sequence.cpp | 2 +- apps/shared/continuous_function.cpp | 14 +++++++------- apps/shared/expression_model.cpp | 6 +++--- apps/shared/global_context.cpp | 4 ++-- ion/include/ion/unicode/code_point.h | 2 +- poincare/src/symbol.cpp | 2 +- poincare/src/trigonometry.cpp | 2 +- poincare/test/context.cpp | 10 +++++----- poincare/test/expression_properties.cpp | 22 +++++++++++----------- 9 files changed, 32 insertions(+), 32 deletions(-) diff --git a/apps/sequence/sequence.cpp b/apps/sequence/sequence.cpp index ca2a372bc..71448682e 100644 --- a/apps/sequence/sequence.cpp +++ b/apps/sequence/sequence.cpp @@ -129,7 +129,7 @@ T Sequence::approximateToNextRank(int n, SequenceContext * sqctx) const { constexpr int bufferSize = CodePoint::MaxCodePointCharLength + 1; char unknownN[bufferSize]; - Poincare::SerializationHelper::CodePoint(unknownN, bufferSize, UCodePointUnknownX); + Poincare::SerializationHelper::CodePoint(unknownN, bufferSize, UCodePointUnknown); CacheContext ctx = CacheContext(sqctx); // Hold values u(n), u(n-1), u(n-2), v(n), v(n-1), v(n-2)... diff --git a/apps/shared/continuous_function.cpp b/apps/shared/continuous_function.cpp index 9a7ae63ea..b37499950 100644 --- a/apps/shared/continuous_function.cpp +++ b/apps/shared/continuous_function.cpp @@ -165,9 +165,9 @@ void ContinuousFunction::setPlotType(PlotType newPlotType, Poincare::Preferences Expression e = expressionClone(); // Change y(t) to [t y(t)] Matrix newExpr = Matrix::Builder(); - newExpr.addChildAtIndexInPlace(Symbol::Builder(UCodePointUnknownX), 0, 0); + newExpr.addChildAtIndexInPlace(Symbol::Builder(UCodePointUnknown), 0, 0); // if y(t) was not uninitialized, insert [t 2t] to set an example - e = e.isUninitialized() ? Multiplication::Builder(Rational::Builder(2), Symbol::Builder(UCodePointUnknownX)) : e; + e = e.isUninitialized() ? Multiplication::Builder(Rational::Builder(2), Symbol::Builder(UCodePointUnknown)) : e; newExpr.addChildAtIndexInPlace(e, newExpr.numberOfChildren(), newExpr.numberOfChildren()); newExpr.setDimensions(2, 1); setExpressionContent(newExpr); @@ -237,7 +237,7 @@ double ContinuousFunction::approximateDerivative(double x, Poincare::Context * c if (x < tMin() || x > tMax()) { return NAN; } - Poincare::Derivative derivative = Poincare::Derivative::Builder(expressionReduced(context).clone(), Symbol::Builder(UCodePointUnknownX), Poincare::Float::Builder(x)); // derivative takes ownership of Poincare::Float::Builder(x) and the clone of expression + Poincare::Derivative derivative = Poincare::Derivative::Builder(expressionReduced(context).clone(), Symbol::Builder(UCodePointUnknown), Poincare::Float::Builder(x)); // derivative takes ownership of Poincare::Float::Builder(x) and the clone of expression /* TODO: when we approximate derivative, we might want to simplify the * derivative here. However, we might want to do it once for all x (to avoid * lagging in the derivative table. */ @@ -281,7 +281,7 @@ Coordinate2D ContinuousFunction::templatedApproximateAtParameter(T t, Poincar } constexpr int bufferSize = CodePoint::MaxCodePointCharLength + 1; char unknown[bufferSize]; - Poincare::SerializationHelper::CodePoint(unknown, bufferSize, UCodePointUnknownX); + Poincare::SerializationHelper::CodePoint(unknown, bufferSize, UCodePointUnknown); PlotType type = plotType(); Expression e = expressionReduced(context); if (type != PlotType::Parametric) { @@ -312,7 +312,7 @@ Coordinate2D ContinuousFunction::nextIntersectionFrom(double start, doub assert(plotType() == PlotType::Cartesian); constexpr int bufferSize = CodePoint::MaxCodePointCharLength + 1; char unknownX[bufferSize]; - SerializationHelper::CodePoint(unknownX, bufferSize, UCodePointUnknownX); + SerializationHelper::CodePoint(unknownX, bufferSize, UCodePointUnknown); double domainMin = maxDouble(tMin(), eDomainMin); double domainMax = minDouble(tMax(), eDomainMax); if (step > 0.0f) { @@ -329,7 +329,7 @@ Coordinate2D ContinuousFunction::nextPointOfInterestFrom(double start, d assert(plotType() == PlotType::Cartesian); constexpr int bufferSize = CodePoint::MaxCodePointCharLength + 1; char unknownX[bufferSize]; - SerializationHelper::CodePoint(unknownX, bufferSize, UCodePointUnknownX); + SerializationHelper::CodePoint(unknownX, bufferSize, UCodePointUnknown); if (step > 0.0f) { start = maxDouble(start, tMin()); max = minDouble(max, tMax()); @@ -344,7 +344,7 @@ Poincare::Expression ContinuousFunction::sumBetweenBounds(double start, double e assert(plotType() == PlotType::Cartesian); start = maxDouble(start, tMin()); end = minDouble(end, tMax()); - return Poincare::Integral::Builder(expressionReduced(context).clone(), Poincare::Symbol::Builder(UCodePointUnknownX), Poincare::Float::Builder(start), Poincare::Float::Builder(end)); // Integral takes ownership of args + return Poincare::Integral::Builder(expressionReduced(context).clone(), Poincare::Symbol::Builder(UCodePointUnknown), Poincare::Float::Builder(start), Poincare::Float::Builder(end)); // Integral takes ownership of args /* TODO: when we approximate integral, we might want to simplify the integral * here. However, we might want to do it once for all x (to avoid lagging in * the derivative table. */ diff --git a/apps/shared/expression_model.cpp b/apps/shared/expression_model.cpp index dcdb5d347..732d85001 100644 --- a/apps/shared/expression_model.cpp +++ b/apps/shared/expression_model.cpp @@ -27,7 +27,7 @@ void ExpressionModel::text(const Storage::Record * record, char * buffer, size_t buffer[0] = 0; } else { if (symbol != 0 && !e.isUninitialized()) { - e = e.replaceSymbolWithExpression(Symbol::Builder(UCodePointUnknownX), Symbol::Builder(symbol)); + e = e.replaceSymbolWithExpression(Symbol::Builder(UCodePointUnknown), Symbol::Builder(symbol)); } e.serialize(buffer, bufferSize); } @@ -67,7 +67,7 @@ Layout ExpressionModel::layout(const Storage::Record * record, CodePoint symbol) if (m_layout.isUninitialized()) { Expression clone = expressionClone(record); if (!clone.isUninitialized() && symbol != 0) { - clone = clone.replaceSymbolWithExpression(Symbol::Builder(UCodePointUnknownX), Symbol::Builder(symbol)); + clone = clone.replaceSymbolWithExpression(Symbol::Builder(UCodePointUnknown), Symbol::Builder(symbol)); } m_layout = PoincareHelpers::CreateLayout(clone); if (m_layout.isUninitialized()) { @@ -134,7 +134,7 @@ Poincare::Expression ExpressionModel::BuildExpressionFromText(const char * c, Co // Compute the expression to store, without replacing symbols expressionToStore = Expression::Parse(c); if (!expressionToStore.isUninitialized() && symbol != 0) { - expressionToStore = expressionToStore.replaceSymbolWithExpression(Symbol::Builder(symbol), Symbol::Builder(UCodePointUnknownX)); + expressionToStore = expressionToStore.replaceSymbolWithExpression(Symbol::Builder(symbol), Symbol::Builder(UCodePointUnknown)); } } return expressionToStore; diff --git a/apps/shared/global_context.cpp b/apps/shared/global_context.cpp index 418ed78c4..1cc5bc09f 100644 --- a/apps/shared/global_context.cpp +++ b/apps/shared/global_context.cpp @@ -54,7 +54,7 @@ void GlobalContext::setExpressionForSymbolAbstract(const Expression & expression assert(symbol.type() == ExpressionNode::Type::Function); Expression child = symbol.childAtIndex(0); assert(child.type() == ExpressionNode::Type::Symbol); - finalExpression = finalExpression.replaceSymbolWithExpression(static_cast(child), Symbol::Builder(UCodePointUnknownX)); + finalExpression = finalExpression.replaceSymbolWithExpression(static_cast(child), Symbol::Builder(UCodePointUnknown)); SetExpressionForFunction(finalExpression, symbol, record); } } @@ -84,7 +84,7 @@ const Expression GlobalContext::ExpressionForFunction(const SymbolAbstract & sym * expression, use the function record handle. */ Expression e = ContinuousFunction(r).expressionClone(); if (!e.isUninitialized()) { - e = e.replaceSymbolWithExpression(Symbol::Builder(UCodePointUnknownX), symbol.childAtIndex(0)); + e = e.replaceSymbolWithExpression(Symbol::Builder(UCodePointUnknown), symbol.childAtIndex(0)); } return e; } diff --git a/ion/include/ion/unicode/code_point.h b/ion/include/ion/unicode/code_point.h index 52708cfed..837ead4cd 100644 --- a/ion/include/ion/unicode/code_point.h +++ b/ion/include/ion/unicode/code_point.h @@ -19,7 +19,7 @@ private: static constexpr CodePoint UCodePointNull = 0x0; // 0x1 represents soh. It is not used, so we can use it for another purpose. -static constexpr CodePoint UCodePointUnknownX = 0x1; +static constexpr CodePoint UCodePointUnknown = 0x1; static constexpr CodePoint UCodePointTabulation = 0x9; static constexpr CodePoint UCodePointLineFeed = 0xa; diff --git a/poincare/src/symbol.cpp b/poincare/src/symbol.cpp index d235f7a3b..ba424b3a0 100644 --- a/poincare/src/symbol.cpp +++ b/poincare/src/symbol.cpp @@ -127,7 +127,7 @@ Evaluation SymbolNode::templatedApproximate(Context * context, Preferences::C } bool SymbolNode::isUnknown() const { - bool result = UTF8Helper::CodePointIs(m_name, UCodePointUnknownX); + bool result = UTF8Helper::CodePointIs(m_name, UCodePointUnknown); if (result) { assert(m_name[1] == 0); } diff --git a/poincare/src/trigonometry.cpp b/poincare/src/trigonometry.cpp index fcf87327c..dd802f97b 100644 --- a/poincare/src/trigonometry.cpp +++ b/poincare/src/trigonometry.cpp @@ -58,7 +58,7 @@ float Trigonometry::characteristicXRange(const Expression & e, Context * context constexpr int bufferSize = CodePoint::MaxCodePointCharLength + 1; char x[bufferSize]; - SerializationHelper::CodePoint(x, bufferSize, UCodePointUnknownX); + SerializationHelper::CodePoint(x, bufferSize, UCodePointUnknown); int d = e.childAtIndex(0).polynomialDegree(context, x); if (d < 0 || d > 1) { diff --git a/poincare/test/context.cpp b/poincare/test/context.cpp index 1923b877b..323a8101d 100644 --- a/poincare/test/context.cpp +++ b/poincare/test/context.cpp @@ -189,11 +189,11 @@ QUIZ_CASE(poincare_context_user_variable_functions_approximation_with_value_for_ constexpr int bufferSize = CodePoint::MaxCodePointCharLength + 1; char x[bufferSize]; - Poincare::SerializationHelper::CodePoint(x, bufferSize, UCodePointUnknownX); + Poincare::SerializationHelper::CodePoint(x, bufferSize, UCodePointUnknown); - assert_parsed_expression_approximates_with_value_for_symbol(Function::Builder("f", 1, Subtraction::Builder(Symbol::Builder(UCodePointUnknownX), Rational::Builder(2))), x, 5.0, 9.0); + assert_parsed_expression_approximates_with_value_for_symbol(Function::Builder("f", 1, Subtraction::Builder(Symbol::Builder(UCodePointUnknown), Rational::Builder(2))), x, 5.0, 9.0); // Approximate f(?-1)+f(?+1) with ? = 3 - assert_parsed_expression_approximates_with_value_for_symbol(Addition::Builder(Function::Builder("f", 1, Subtraction::Builder(Symbol::Builder(UCodePointUnknownX), Rational::Builder(1))), Function::Builder("f", 1, Addition::Builder(Symbol::Builder(UCodePointUnknownX), Rational::Builder(1)))), x, 3.0, 20.0); + assert_parsed_expression_approximates_with_value_for_symbol(Addition::Builder(Function::Builder("f", 1, Subtraction::Builder(Symbol::Builder(UCodePointUnknown), Rational::Builder(1))), Function::Builder("f", 1, Addition::Builder(Symbol::Builder(UCodePointUnknown), Rational::Builder(1)))), x, 3.0, 20.0); // Clean the storage for other tests Ion::Storage::sharedStorage()->recordNamed("f.func").destroy(); @@ -202,9 +202,9 @@ QUIZ_CASE(poincare_context_user_variable_functions_approximation_with_value_for_ assert_simplify("√(-1)×√(-1)→f(x)"); // Approximate f(?) with ? = 5 // Cartesian - assert_parsed_expression_approximates_with_value_for_symbol(Function::Builder("f", 1, Symbol::Builder(UCodePointUnknownX)), x, 1.0, -1.0); + assert_parsed_expression_approximates_with_value_for_symbol(Function::Builder("f", 1, Symbol::Builder(UCodePointUnknown)), x, 1.0, -1.0); // Real - assert_parsed_expression_approximates_with_value_for_symbol(Function::Builder("f", 1, Symbol::Builder(UCodePointUnknownX)), x, 1.0, (double)NAN, Real); + assert_parsed_expression_approximates_with_value_for_symbol(Function::Builder("f", 1, Symbol::Builder(UCodePointUnknown)), x, 1.0, (double)NAN, Real); // Clean the storage for other tests Ion::Storage::sharedStorage()->recordNamed("f.func").destroy(); diff --git a/poincare/test/expression_properties.cpp b/poincare/test/expression_properties.cpp index e2f7697e9..afa85d849 100644 --- a/poincare/test/expression_properties.cpp +++ b/poincare/test/expression_properties.cpp @@ -243,30 +243,30 @@ void assert_reduced_expression_has_characteristic_range(Expression e, float rang QUIZ_CASE(poincare_properties_characteristic_range) { // cos(x), degree - assert_reduced_expression_has_characteristic_range(Cosine::Builder(Symbol::Builder(UCodePointUnknownX)), 360.0f); + assert_reduced_expression_has_characteristic_range(Cosine::Builder(Symbol::Builder(UCodePointUnknown)), 360.0f); // cos(-x), degree - assert_reduced_expression_has_characteristic_range(Cosine::Builder(Opposite::Builder(Symbol::Builder(UCodePointUnknownX))), 360.0f); + assert_reduced_expression_has_characteristic_range(Cosine::Builder(Opposite::Builder(Symbol::Builder(UCodePointUnknown))), 360.0f); // cos(x), radian - assert_reduced_expression_has_characteristic_range(Cosine::Builder(Symbol::Builder(UCodePointUnknownX)), 2.0f*M_PI, Preferences::AngleUnit::Radian); + assert_reduced_expression_has_characteristic_range(Cosine::Builder(Symbol::Builder(UCodePointUnknown)), 2.0f*M_PI, Preferences::AngleUnit::Radian); // cos(-x), radian - assert_reduced_expression_has_characteristic_range(Cosine::Builder(Opposite::Builder(Symbol::Builder(UCodePointUnknownX))), 2.0f*M_PI, Preferences::AngleUnit::Radian); + assert_reduced_expression_has_characteristic_range(Cosine::Builder(Opposite::Builder(Symbol::Builder(UCodePointUnknown))), 2.0f*M_PI, Preferences::AngleUnit::Radian); // sin(9x+10), degree - assert_reduced_expression_has_characteristic_range(Sine::Builder(Addition::Builder(Multiplication::Builder(Rational::Builder(9),Symbol::Builder(UCodePointUnknownX)),Rational::Builder(10))), 40.0f); + assert_reduced_expression_has_characteristic_range(Sine::Builder(Addition::Builder(Multiplication::Builder(Rational::Builder(9),Symbol::Builder(UCodePointUnknown)),Rational::Builder(10))), 40.0f); // sin(9x+10)+cos(x/2), degree - assert_reduced_expression_has_characteristic_range(Addition::Builder(Sine::Builder(Addition::Builder(Multiplication::Builder(Rational::Builder(9),Symbol::Builder(UCodePointUnknownX)),Rational::Builder(10))),Cosine::Builder(Division::Builder(Symbol::Builder(UCodePointUnknownX),Rational::Builder(2)))), 720.0f); + assert_reduced_expression_has_characteristic_range(Addition::Builder(Sine::Builder(Addition::Builder(Multiplication::Builder(Rational::Builder(9),Symbol::Builder(UCodePointUnknown)),Rational::Builder(10))),Cosine::Builder(Division::Builder(Symbol::Builder(UCodePointUnknown),Rational::Builder(2)))), 720.0f); // sin(9x+10)+cos(x/2), radian - assert_reduced_expression_has_characteristic_range(Addition::Builder(Sine::Builder(Addition::Builder(Multiplication::Builder(Rational::Builder(9),Symbol::Builder(UCodePointUnknownX)),Rational::Builder(10))),Cosine::Builder(Division::Builder(Symbol::Builder(UCodePointUnknownX),Rational::Builder(2)))), 4.0f*M_PI, Preferences::AngleUnit::Radian); + assert_reduced_expression_has_characteristic_range(Addition::Builder(Sine::Builder(Addition::Builder(Multiplication::Builder(Rational::Builder(9),Symbol::Builder(UCodePointUnknown)),Rational::Builder(10))),Cosine::Builder(Division::Builder(Symbol::Builder(UCodePointUnknown),Rational::Builder(2)))), 4.0f*M_PI, Preferences::AngleUnit::Radian); // x, degree - assert_reduced_expression_has_characteristic_range(Symbol::Builder(UCodePointUnknownX), NAN); + assert_reduced_expression_has_characteristic_range(Symbol::Builder(UCodePointUnknown), NAN); // cos(3)+2, degree assert_reduced_expression_has_characteristic_range(Addition::Builder(Cosine::Builder(Rational::Builder(3)),Rational::Builder(2)), 0.0f); // log(cos(40x), degree - assert_reduced_expression_has_characteristic_range(CommonLogarithm::Builder(Cosine::Builder(Multiplication::Builder(Rational::Builder(40),Symbol::Builder(UCodePointUnknownX)))), 9.0f); + assert_reduced_expression_has_characteristic_range(CommonLogarithm::Builder(Cosine::Builder(Multiplication::Builder(Rational::Builder(40),Symbol::Builder(UCodePointUnknown)))), 9.0f); // cos(cos(x)), degree - assert_reduced_expression_has_characteristic_range(Cosine::Builder((Expression)Cosine::Builder(Symbol::Builder(UCodePointUnknownX))), 360.0f); + assert_reduced_expression_has_characteristic_range(Cosine::Builder((Expression)Cosine::Builder(Symbol::Builder(UCodePointUnknown))), 360.0f); // f(x) with f : x --> cos(x), degree assert_simplify("cos(x)→f(x)"); - assert_reduced_expression_has_characteristic_range(Function::Builder("f",1,Symbol::Builder(UCodePointUnknownX)), 360.0f); + assert_reduced_expression_has_characteristic_range(Function::Builder("f",1,Symbol::Builder(UCodePointUnknown)), 360.0f); Ion::Storage::sharedStorage()->recordNamed("f.func").destroy(); } From a3053acac406037dee19481d5773d9ff4e9a83a0 Mon Sep 17 00:00:00 2001 From: Ruben Dashyan Date: Thu, 26 Sep 2019 17:27:27 +0200 Subject: [PATCH 014/680] [apps/shared/expression_model] Add TODOs for later --- apps/shared/expression_model.cpp | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/apps/shared/expression_model.cpp b/apps/shared/expression_model.cpp index 732d85001..c9429bad9 100644 --- a/apps/shared/expression_model.cpp +++ b/apps/shared/expression_model.cpp @@ -41,6 +41,26 @@ bool ExpressionModel::isCircularlyDefined(const Storage::Record * record, Poinca } Expression ExpressionModel::expressionReduced(const Storage::Record * record, Poincare::Context * context) const { + /* TODO + * By calling isCircularlyDefined and then Simplify, the expression tree is + * browsed twice. Note that Simplify does ALMOST the job of + * isCircularlyDefined, since Simplify reduces the expression, replaces the + * symbols it encounters (see SymbolAbstract::Expand). isCircularlyDefined + * should probably be removed. The difficulty relies in the ambiguous + * conventions about the values returned or set when a symbol has no proper + * expression: for example, + * - GlobalContext::expressionForSymbolAbstract returns an uninitialized + * expression, + * - so do Expression::ExpressionWithoutSymbols and SymbolAbstract::Expand, + * - Expression::deepReplaceReplaceableSymbols leaves unchanged the symbols, + * whose expression is uninitialized, but returns Undefined if the + * expression for a symbol contains the symbol itself, + * - Symbol::shallowReduce and Function::shallowReduce return Undefined or + * the expression unaltered according to symbolic-computation setting, + * - expressionReduced returns Undefined if the expression + * isCircularlyDefined but leaves the expression unchanged if Simplify + * returns an uninitialized expression... + */ if (m_expression.isUninitialized()) { assert(record->fullName() != nullptr); if (isCircularlyDefined(record, context)) { @@ -61,6 +81,13 @@ Expression ExpressionModel::expressionClone(const Storage::Record * record) cons assert(record->fullName() != nullptr); /* A new Expression has to be created at each call (because it might be tempered with after calling) */ return Expression::ExpressionFromAddress(expressionAddress(record), expressionSize(record)); + /* TODO + * The substitution of UCodePointUnknown back and forth is done in the + * methods text, setContent (through BuildExpressionFromText), layout and + * also in GlobalContext::expressionForSymbolAbstract and + * GlobalContext::setExpressionForSymbolAbstract. When getting the + * expression, the substitutions may probably be gathered here. + */ } Layout ExpressionModel::layout(const Storage::Record * record, CodePoint symbol) const { From 76304604249f980546e5f45969e5a32566342dee Mon Sep 17 00:00:00 2001 From: Ruben Dashyan Date: Mon, 30 Sep 2019 10:23:36 +0200 Subject: [PATCH 015/680] [apps/code] Add methods on lists to python toolbox catalog --- apps/code/catalog.de.i18n | 10 ++++++++++ apps/code/catalog.en.i18n | 10 ++++++++++ apps/code/catalog.es.i18n | 10 ++++++++++ apps/code/catalog.fr.i18n | 10 ++++++++++ apps/code/catalog.pt.i18n | 10 ++++++++++ apps/code/catalog.universal.i18n | 10 ++++++++++ apps/code/python_toolbox.cpp | 10 ++++++++++ 7 files changed, 70 insertions(+) diff --git a/apps/code/catalog.de.i18n b/apps/code/catalog.de.i18n index fa6a0999d..7d77c3d82 100644 --- a/apps/code/catalog.de.i18n +++ b/apps/code/catalog.de.i18n @@ -12,6 +12,7 @@ PythonSingleQuote = "Einfaches Anführungszeichen" PythonAbs = "Absolute/r Wert/Größe" PythonAcos = "Arkuskosinus" PythonAcosh = "Hyperbelkosinus" +PythonAppend = "Add an item to the end of the list" PythonAsin = "Arkussinus" PythonAsinh = "Hyperbelsinus" PythonAtan = "Arkustangens" @@ -20,12 +21,15 @@ PythonAtanh = "Hyperbeltangens" PythonBin = "Ganzzahl nach binär konvertieren" PythonCeil = "Aufrundung" PythonChoice = "Zufallszahl aus der Liste" +PythonClear = "Empty the list" PythonCmathFunction = "cmath-Modul-Funktionspräfix" PythonColor = "Definiere eine RGB-Farbe" PythonComplex = "a+ib zurückgeben" +PythonCopy = "Returns a copy of the list" PythonCopySign = "Return x with the sign of y" PythonCos = "Kosinus" PythonCosh = "Hyperbolic cosine" +PythonCount = "Count the number of occurrences" PythonDegrees = "Convert x from radians to degrees" PythonDivMod = "Quotient and remainder" PythonDrawString = "Display a text from pixel (x,y)" @@ -55,7 +59,9 @@ PythonImportFromKandinsky = "Import kandinsky module" PythonImportFromRandom = "Import random module" PythonImportFromMath = "Import math module" PythonImportFromTurtle = "Import turtle module" +PythonIndex = "Index of the first occurrence" PythonInput = "Prompt a value" +PythonInsert = "Insert an item" PythonInt = "Convert x to an integer" PythonIsFinite = "Check if x is finite" PythonIsInfinite = "Check if x is infinity" @@ -75,6 +81,7 @@ PythonOct = "Convert integer to octal" PythonPhase = "Phase of z" PythonConstantPi = "3.141592653589794" PythonPolar = "z in polar coordinates" +PythonPop = "Remove and return an item" PythonPower = "x raised to the power y" PythonPrint = "Print object" PythonRadians = "Convert x from degrees to radians" @@ -85,11 +92,14 @@ PythonRandrange = "Random number in range(start, stop)" PythonRangeStartStop = "List from start to stop-1" PythonRangeStop = "List from 0 to stop-1" PythonRect = "z in cartesian coordinates" +PythonRemove = "Remove the first occurrence of x" +PythonReverse = "Reverse the elements of the list" PythonRound = "Round to n digits" PythonSeed = "Initialize random number generator" PythonSetPixel = "Color pixel (x,y)" PythonSin = "Sine" PythonSinh = "Hyperbolic sine" +PythonSort = "Sort a list" PythonSorted = "Sort a list" PythonSqrt = "Square root" PythonSum = "Sum the items of a list" diff --git a/apps/code/catalog.en.i18n b/apps/code/catalog.en.i18n index 312851e59..c387f97ed 100644 --- a/apps/code/catalog.en.i18n +++ b/apps/code/catalog.en.i18n @@ -12,6 +12,7 @@ PythonSingleQuote = "Single quote" PythonAbs = "Absolute value/Magnitude" PythonAcos = "Arc cosine" PythonAcosh = "Arc hyperbolic cosine" +PythonAppend = "Add an item to the end of the list" PythonAsin = "Arc sine" PythonAsinh = "Arc hyperbolic sine" PythonAtan = "Arc tangent" @@ -20,12 +21,15 @@ PythonAtanh = "Arc hyperbolic tangent" PythonBin = "Convert integer to binary" PythonCeil = "Ceiling" PythonChoice = "Random number in the list" +PythonClear = "Empty the list" PythonCmathFunction = "cmath module function prefix" PythonColor = "Define a rgb color" PythonComplex = "Return a+ib" +PythonCopy = "Returns a copy of the list" PythonCopySign = "Return x with the sign of y" PythonCos = "Cosine" PythonCosh = "Hyperbolic cosine" +PythonCount = "Count the number of occurrences" PythonDegrees = "Convert x from radians to degrees" PythonDivMod = "Quotient and remainder" PythonDrawString = "Display a text from pixel (x,y)" @@ -55,7 +59,9 @@ PythonImportFromKandinsky = "Import kandinsky module" PythonImportFromRandom = "Import random module" PythonImportFromMath = "Import math module" PythonImportFromTurtle = "Import turtle module" +PythonIndex = "Index of the first occurrence" PythonInput = "Prompt a value" +PythonInsert = "Insert an item" PythonInt = "Convert x to an integer" PythonIsFinite = "Check if x is finite" PythonIsInfinite = "Check if x is infinity" @@ -75,6 +81,7 @@ PythonOct = "Convert integer to octal" PythonPhase = "Phase of z" PythonConstantPi = "3.141592653589794" PythonPolar = "z in polar coordinates" +PythonPop = "Remove and return an item" PythonPower = "x raised to the power y" PythonPrint = "Print object" PythonRadians = "Convert x from degrees to radians" @@ -85,11 +92,14 @@ PythonRandrange = "Random number in range(start, stop)" PythonRangeStartStop = "List from start to stop-1" PythonRangeStop = "List from 0 to stop-1" PythonRect = "z in cartesian coordinates" +PythonRemove = "Remove the first occurrence of x" +PythonReverse = "Reverse the elements of the list" PythonRound = "Round to n digits" PythonSeed = "Initialize random number generator" PythonSetPixel = "Color pixel (x,y)" PythonSin = "Sine" PythonSinh = "Hyperbolic sine" +PythonSort = "Sort a list" PythonSorted = "Sort a list" PythonSqrt = "Square root" PythonSum = "Sum the items of a list" diff --git a/apps/code/catalog.es.i18n b/apps/code/catalog.es.i18n index 312851e59..c387f97ed 100644 --- a/apps/code/catalog.es.i18n +++ b/apps/code/catalog.es.i18n @@ -12,6 +12,7 @@ PythonSingleQuote = "Single quote" PythonAbs = "Absolute value/Magnitude" PythonAcos = "Arc cosine" PythonAcosh = "Arc hyperbolic cosine" +PythonAppend = "Add an item to the end of the list" PythonAsin = "Arc sine" PythonAsinh = "Arc hyperbolic sine" PythonAtan = "Arc tangent" @@ -20,12 +21,15 @@ PythonAtanh = "Arc hyperbolic tangent" PythonBin = "Convert integer to binary" PythonCeil = "Ceiling" PythonChoice = "Random number in the list" +PythonClear = "Empty the list" PythonCmathFunction = "cmath module function prefix" PythonColor = "Define a rgb color" PythonComplex = "Return a+ib" +PythonCopy = "Returns a copy of the list" PythonCopySign = "Return x with the sign of y" PythonCos = "Cosine" PythonCosh = "Hyperbolic cosine" +PythonCount = "Count the number of occurrences" PythonDegrees = "Convert x from radians to degrees" PythonDivMod = "Quotient and remainder" PythonDrawString = "Display a text from pixel (x,y)" @@ -55,7 +59,9 @@ PythonImportFromKandinsky = "Import kandinsky module" PythonImportFromRandom = "Import random module" PythonImportFromMath = "Import math module" PythonImportFromTurtle = "Import turtle module" +PythonIndex = "Index of the first occurrence" PythonInput = "Prompt a value" +PythonInsert = "Insert an item" PythonInt = "Convert x to an integer" PythonIsFinite = "Check if x is finite" PythonIsInfinite = "Check if x is infinity" @@ -75,6 +81,7 @@ PythonOct = "Convert integer to octal" PythonPhase = "Phase of z" PythonConstantPi = "3.141592653589794" PythonPolar = "z in polar coordinates" +PythonPop = "Remove and return an item" PythonPower = "x raised to the power y" PythonPrint = "Print object" PythonRadians = "Convert x from degrees to radians" @@ -85,11 +92,14 @@ PythonRandrange = "Random number in range(start, stop)" PythonRangeStartStop = "List from start to stop-1" PythonRangeStop = "List from 0 to stop-1" PythonRect = "z in cartesian coordinates" +PythonRemove = "Remove the first occurrence of x" +PythonReverse = "Reverse the elements of the list" PythonRound = "Round to n digits" PythonSeed = "Initialize random number generator" PythonSetPixel = "Color pixel (x,y)" PythonSin = "Sine" PythonSinh = "Hyperbolic sine" +PythonSort = "Sort a list" PythonSorted = "Sort a list" PythonSqrt = "Square root" PythonSum = "Sum the items of a list" diff --git a/apps/code/catalog.fr.i18n b/apps/code/catalog.fr.i18n index 847a45b43..70d14481f 100644 --- a/apps/code/catalog.fr.i18n +++ b/apps/code/catalog.fr.i18n @@ -12,6 +12,7 @@ PythonSingleQuote = "Apostrophe" PythonAbs = "Valeur absolue/Module" PythonAcos = "Arc cosinus" PythonAcosh = "Arc cosinus hyperbolique" +PythonAppend = "Insérer à la fin de la liste" PythonAsin = "Arc sinus" PythonAsinh = "Arc sinus hyperbolique" PythonAtan = "Arc tangente" @@ -20,12 +21,15 @@ PythonAtanh = "Arc tangente hyperbolique" PythonBin = "Conversion d'un entier en binaire" PythonCeil = "Plafond" PythonChoice = "Nombre aléatoire dans la liste" +PythonClear = "Vider la liste" PythonCmathFunction = "Préfixe fonction du module cmath" PythonColor = "Définit une couleur rvb" PythonComplex = "Renvoie a+ib" +PythonCopy = "Renvoie une copie de la liste" PythonCopySign = "Renvoie x avec le signe de y" PythonCos = "Cosinus" PythonCosh = "Cosinus hyperbolique" +PythonCount = "Compte le nombre d'occurrences" PythonDegrees = "Conversion de radians en degrés" PythonDivMod = "Quotient et reste" PythonDrawString = "Affiche un texte au pixel (x,y)" @@ -55,7 +59,9 @@ PythonImportFromKandinsky = "Importation du module kandinsky" PythonImportFromRandom = "Importation du module random" PythonImportFromMath = "Importation du module math" PythonImportFromTurtle = "Importation du module turtle" +PythonIndex = "Indice de la première occurrence" PythonInput = "Entrer une valeur" +PythonInsert = "Insérer un élément" PythonInt = "Conversion en entier" PythonIsFinite = "Teste si x est fini" PythonIsInfinite = "Teste si x est infini" @@ -75,6 +81,7 @@ PythonOct = "Conversion en octal" PythonPhase = "Argument de z" PythonConstantPi = "3.141592653589793" PythonPolar = "Conversion en polaire" +PythonPop = "Supprimer et renvoyer un élément" PythonPower = "x à la puissance y" PythonPrint = "Affiche l'objet" PythonRadians = "Conversion de degrés en radians" @@ -85,11 +92,14 @@ PythonRandrange = "Nombre dans range(start, stop)" PythonRangeStartStop = "Liste de start à stop-1" PythonRangeStop = "Liste de 0 à stop-1" PythonRect = "Conversion en algébrique" +PythonRemove = "Supprimer la première occurrence de x" +PythonReverse = "Inverse les éléments de la liste" PythonRound = "Arrondi à n décimales" PythonSeed = "Initialiser générateur aléatoire" PythonSetPixel = "Colore le pixel (x,y)" PythonSin = "Sinus" PythonSinh = "Sinus hyperbolique" +PythonSort = "Tri d'une liste" PythonSorted = "Tri d'une liste" PythonSqrt = "Racine carrée" PythonSum = "Somme des éléments d'une liste" diff --git a/apps/code/catalog.pt.i18n b/apps/code/catalog.pt.i18n index e77aaf28b..d72dc291b 100644 --- a/apps/code/catalog.pt.i18n +++ b/apps/code/catalog.pt.i18n @@ -12,6 +12,7 @@ PythonReal = "Real part of z" PythonAbs = "Absolute value/Magnitude" PythonAcos = "Arc cosine" PythonAcosh = "Arc hyperbolic cosine" +PythonAppend = "Add an item to the end of the list" PythonAsin = "Arc sine" PythonAsinh = "Arc hyperbolic sine" PythonAtan = "Arc tangent" @@ -20,12 +21,15 @@ PythonAtanh = "Arc hyperbolic tangent" PythonBin = "Convert integer to binary" PythonCeil = "Ceiling" PythonChoice = "Random number in the list" +PythonClear = "Empty the list" PythonCmathFunction = "cmath module function prefix" PythonColor = "Define a rgb color" PythonComplex = "Return a+ib" +PythonCopy = "Returns a copy of the list" PythonCopySign = "Return x with the sign of y" PythonCos = "Cosine" PythonCosh = "Hyperbolic cosine" +PythonCount = "Count the number of occurrences" PythonDegrees = "Convert x from radians to degrees" PythonDivMod = "Quotient and remainder" PythonDrawString = "Display a text from pixel (x,y)" @@ -55,7 +59,9 @@ PythonImportFromKandinsky = "Import kandinsky module" PythonImportFromRandom = "Import random module" PythonImportFromMath = "Import math module" PythonImportFromTurtle = "Import turtle module" +PythonIndex = "Index of the first occurrence" PythonInput = "Prompt a value" +PythonInsert = "Insert an item" PythonInt = "Convert x to an integer" PythonIsFinite = "Check if x is finite" PythonIsInfinite = "Check if x is infinity" @@ -75,6 +81,7 @@ PythonOct = "Convert integer to octal" PythonPhase = "Phase of z" PythonConstantPi = "3.141592653589794" PythonPolar = "z in polar coordinates" +PythonPop = "Remove and return an item" PythonPower = "x raised to the power y" PythonPrint = "Print object" PythonRadians = "Convert x from degrees to radians" @@ -85,11 +92,14 @@ PythonRandrange = "Random number in range(start, stop)" PythonRangeStartStop = "List from start to stop-1" PythonRangeStop = "List from 0 to stop-1" PythonRect = "z in cartesian coordinates" +PythonRemove = "Remove the first occurrence of x" +PythonReverse = "Reverse the elements of the list" PythonRound = "Round to n digits" PythonSeed = "Initialize random number generator" PythonSetPixel = "Color pixel (x,y)" PythonSin = "Sine" PythonSinh = "Hyperbolic sine" +PythonSort = "Sort a list" PythonSorted = "Sort a list" PythonSqrt = "Square root" PythonSum = "Sum the items of a list" diff --git a/apps/code/catalog.universal.i18n b/apps/code/catalog.universal.i18n index 24f35baba..6baa571a5 100644 --- a/apps/code/catalog.universal.i18n +++ b/apps/code/catalog.universal.i18n @@ -10,6 +10,7 @@ PythonCommand1J = "1j" PythonCommandAbs = "abs(x)" PythonCommandAcos = "acos(x)" PythonCommandAcosh = "acosh(x)" +PythonCommandAppend = "append(x)" PythonCommandAsin = "asin(x)" PythonCommandAsinh = "asinh(x)" PythonCommandAtan = "atan(x)" @@ -18,15 +19,18 @@ PythonCommandAtanh = "atanh(x)" PythonCommandBin = "bin(x)" PythonCommandCeil = "ceil(x)" PythonCommandChoice = "choice(list)" +PythonCommandClear = "clear()" PythonCommandCmathFunction = "cmath.function" PythonCommandCmathFunctionWithoutArg = "cmath.\x11" PythonCommandColor = "color(r,g,b)" PythonCommandComplex = "complex(a,b)" PythonCommandConstantPi = "pi" +PythonCommandCopy = "copy()" PythonCommandCopySign = "copysign(x,y)" PythonCommandCos = "cos(x)" PythonCommandCosComplex = "cos(z)" PythonCommandCosh = "cosh(x)" +PythonCommandCount = "count(x)" PythonCommandDegrees = "degrees(x)" PythonCommandDivMod = "divmod(a,b)" PythonCommandDrawString = "draw_string(\"text\",x,y)" @@ -59,7 +63,9 @@ PythonCommandImportKandinsky = "import kandinsky" PythonCommandImportRandom = "import random" PythonCommandImportMath = "import math" PythonCommandImportTurtle = "import turtle" +PythonCommandIndex = "index(x,start,end)" PythonCommandInput = "input(\"text\")" +PythonCommandInsert = "insert(i,x)" PythonCommandInt = "int(x)" PythonCommandIsFinite = "isfinite(x)" PythonCommandIsInfinite = "isinf(x)" @@ -81,6 +87,7 @@ PythonCommandModf = "modf(x)" PythonCommandOct = "oct(x)" PythonCommandPhase = "phase(z)" PythonCommandPolar = "polar(z)" +PythonCommandPop = "pop(i)" PythonCommandPower = "pow(x,y)" PythonCommandPrint = "print(object)" PythonCommandRadians = "radians(x)" @@ -94,12 +101,15 @@ PythonCommandRangeStop = "range(stop)" PythonCommandReal = "z.real" PythonCommandRealWithoutArg = "\x11.real" PythonCommandRect = "rect(r, arg)" +PythonCommandRemove = "remove(x)" +PythonCommandReverse = "reverse()" PythonCommandRound = "round(x, n)" PythonCommandSeed = "seed(x)" PythonCommandSetPixel = "set_pixel(x,y,color)" PythonCommandSin = "sin(x)" PythonCommandSinComplex = "sin(z)" PythonCommandSinh = "sinh(x)" +PythonCommandSort = "sort()" PythonCommandSorted = "sorted(list)" PythonCommandSqrt = "sqrt(x)" PythonCommandSqrtComplex = "sqrt(z)" diff --git a/apps/code/python_toolbox.cpp b/apps/code/python_toolbox.cpp index 55989b01d..a22c14730 100644 --- a/apps/code/python_toolbox.cpp +++ b/apps/code/python_toolbox.cpp @@ -188,6 +188,7 @@ 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::PythonCommandAppend, I18n::Message::PythonAppend), ToolboxMessageTree::Leaf(I18n::Message::PythonCommandAsin, I18n::Message::PythonAsin), ToolboxMessageTree::Leaf(I18n::Message::PythonCommandAsinh, I18n::Message::PythonAsinh), ToolboxMessageTree::Leaf(I18n::Message::PythonCommandAtan, I18n::Message::PythonAtan), @@ -201,12 +202,15 @@ const ToolboxMessageTree catalogChildren[] = { ToolboxMessageTree::Leaf(I18n::Message::PythonCommandCeil, I18n::Message::PythonCeil), ToolboxMessageTree::Leaf(I18n::Message::PythonCommandChoice, I18n::Message::PythonChoice), ToolboxMessageTree::Leaf(I18n::Message::PythonTurtleCommandCircle, I18n::Message::PythonTurtleCircle), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandClear, I18n::Message::PythonClear, false), ToolboxMessageTree::Leaf(I18n::Message::PythonCommandCmathFunction, I18n::Message::PythonCmathFunction, false, I18n::Message::PythonCommandCmathFunctionWithoutArg), ToolboxMessageTree::Leaf(I18n::Message::PythonCommandColor, I18n::Message::PythonColor), ToolboxMessageTree::Leaf(I18n::Message::PythonCommandComplex, I18n::Message::PythonComplex), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandCopy, I18n::Message::PythonCopy, false), ToolboxMessageTree::Leaf(I18n::Message::PythonCommandCopySign, I18n::Message::PythonCopySign), ToolboxMessageTree::Leaf(I18n::Message::PythonCommandCos, I18n::Message::PythonCos), ToolboxMessageTree::Leaf(I18n::Message::PythonCommandCosh, I18n::Message::PythonCosh), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandCount, I18n::Message::PythonCount), ToolboxMessageTree::Leaf(I18n::Message::PythonCommandDegrees, I18n::Message::PythonDegrees), ToolboxMessageTree::Leaf(I18n::Message::PythonCommandDivMod, I18n::Message::PythonDivMod), ToolboxMessageTree::Leaf(I18n::Message::PythonCommandDrawString, I18n::Message::PythonDrawString), @@ -242,7 +246,9 @@ const ToolboxMessageTree catalogChildren[] = { ToolboxMessageTree::Leaf(I18n::Message::PythonCommandImportMath, I18n::Message::PythonImportMath, false), ToolboxMessageTree::Leaf(I18n::Message::PythonCommandImportRandom, I18n::Message::PythonImportRandom, false), ToolboxMessageTree::Leaf(I18n::Message::PythonCommandImportTurtle, I18n::Message::PythonImportTurtle, false), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandIndex, I18n::Message::PythonIndex), ToolboxMessageTree::Leaf(I18n::Message::PythonCommandInput, I18n::Message::PythonInput), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandInsert, I18n::Message::PythonInsert), ToolboxMessageTree::Leaf(I18n::Message::PythonCommandInt, I18n::Message::PythonInt), ToolboxMessageTree::Leaf(I18n::Message::PythonTurtleCommandIsdown, I18n::Message::PythonTurtleIsdown, false), ToolboxMessageTree::Leaf(I18n::Message::PythonCommandIsFinite, I18n::Message::PythonIsFinite), @@ -269,6 +275,7 @@ const ToolboxMessageTree catalogChildren[] = { ToolboxMessageTree::Leaf(I18n::Message::PythonCommandConstantPi, I18n::Message::PythonConstantPi, false), ToolboxMessageTree::Leaf(I18n::Message::PythonTurtleCommandPink, I18n::Message::PythonTurtlePink, false), ToolboxMessageTree::Leaf(I18n::Message::PythonCommandPolar, I18n::Message::PythonPolar), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandPop, I18n::Message::PythonPop), ToolboxMessageTree::Leaf(I18n::Message::PythonTurtleCommandPosition, I18n::Message::PythonTurtlePosition, false), ToolboxMessageTree::Leaf(I18n::Message::PythonCommandPower, I18n::Message::PythonPower), ToolboxMessageTree::Leaf(I18n::Message::PythonCommandPrint, I18n::Message::PythonPrint), @@ -282,7 +289,9 @@ const ToolboxMessageTree catalogChildren[] = { ToolboxMessageTree::Leaf(I18n::Message::PythonCommandRangeStop, I18n::Message::PythonRangeStop), ToolboxMessageTree::Leaf(I18n::Message::PythonCommandRect, I18n::Message::PythonRect), ToolboxMessageTree::Leaf(I18n::Message::PythonTurtleCommandRed, I18n::Message::PythonTurtleRed, false), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandRemove, I18n::Message::PythonRemove), ToolboxMessageTree::Leaf(I18n::Message::PythonTurtleCommandReset, I18n::Message::PythonTurtleReset, false), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandReverse, I18n::Message::PythonReverse, false), ToolboxMessageTree::Leaf(I18n::Message::PythonTurtleCommandRight, I18n::Message::PythonTurtleRight), ToolboxMessageTree::Leaf(I18n::Message::PythonCommandRound, I18n::Message::PythonRound), ToolboxMessageTree::Leaf(I18n::Message::PythonTurtleCommandSetheading, I18n::Message::PythonTurtleSetheading), @@ -291,6 +300,7 @@ const ToolboxMessageTree catalogChildren[] = { 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), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandSort, I18n::Message::PythonSort, false), ToolboxMessageTree::Leaf(I18n::Message::PythonCommandSorted, I18n::Message::PythonSorted), ToolboxMessageTree::Leaf(I18n::Message::PythonTurtleCommandSpeed, I18n::Message::PythonTurtleSpeed), ToolboxMessageTree::Leaf(I18n::Message::PythonCommandSqrt, I18n::Message::PythonSqrt), From 227c9a8d68c79386c75112a5f5b94964d7dcb223 Mon Sep 17 00:00:00 2001 From: Ruben Dashyan Date: Mon, 30 Sep 2019 11:33:20 +0200 Subject: [PATCH 016/680] [apps/calculation/edit_expression_controller] Inline view() in header --- apps/calculation/edit_expression_controller.cpp | 4 ---- apps/calculation/edit_expression_controller.h | 2 +- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/apps/calculation/edit_expression_controller.cpp b/apps/calculation/edit_expression_controller.cpp index f631b8f84..2f91b15c2 100644 --- a/apps/calculation/edit_expression_controller.cpp +++ b/apps/calculation/edit_expression_controller.cpp @@ -48,10 +48,6 @@ EditExpressionController::EditExpressionController(Responder * parentResponder, m_cacheBuffer[0] = 0; } -View * EditExpressionController::view() { - return &m_contentView; -} - void EditExpressionController::insertTextBody(const char * text) { ((ContentView *)view())->expressionField()->handleEventWithText(text, false, true); } diff --git a/apps/calculation/edit_expression_controller.h b/apps/calculation/edit_expression_controller.h index 159679468..3ad0b4f66 100644 --- a/apps/calculation/edit_expression_controller.h +++ b/apps/calculation/edit_expression_controller.h @@ -16,7 +16,7 @@ class HistoryController; class EditExpressionController : public ViewController, public Shared::TextFieldDelegate, public Shared::LayoutFieldDelegate { public: EditExpressionController(Responder * parentResponder, InputEventHandlerDelegate * inputEventHandlerDelegate, HistoryController * historyController, CalculationStore * calculationStore); - View * view() override; + View * view() override { return &m_contentView; } void didBecomeFirstResponder() override; void viewDidDisappear() override; void insertTextBody(const char * text); From 59e6c9d324d66ab13bc0428c52a88ba00314d5eb Mon Sep 17 00:00:00 2001 From: Ruben Dashyan Date: Mon, 30 Sep 2019 11:38:48 +0200 Subject: [PATCH 017/680] [apps/calculation/edit_expression_controller] view() does not return nullptr --- apps/calculation/edit_expression_controller.cpp | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/apps/calculation/edit_expression_controller.cpp b/apps/calculation/edit_expression_controller.cpp index 2f91b15c2..fb404c937 100644 --- a/apps/calculation/edit_expression_controller.cpp +++ b/apps/calculation/edit_expression_controller.cpp @@ -94,12 +94,10 @@ bool EditExpressionController::layoutFieldDidAbortEditing(::LayoutField * layout void EditExpressionController::layoutFieldDidChangeSize(::LayoutField * layoutField) { /* Reload the view only if the ExpressionField height actually changes, i.e. * not if the height is already maximal and stays maximal. */ - if (view()) { - bool newInputViewHeightIsMaximal = static_cast(view())->expressionField()->heightIsMaximal(); - if (!m_inputViewHeightIsMaximal || !newInputViewHeightIsMaximal) { - m_inputViewHeightIsMaximal = newInputViewHeightIsMaximal; - reloadView(); - } + bool newInputViewHeightIsMaximal = static_cast(view())->expressionField()->heightIsMaximal(); + if (!m_inputViewHeightIsMaximal || !newInputViewHeightIsMaximal) { + m_inputViewHeightIsMaximal = newInputViewHeightIsMaximal; + reloadView(); } } From 491a93d8f1bc316e0f169b75b0d5271291b0a97b Mon Sep 17 00:00:00 2001 From: Ruben Dashyan Date: Mon, 30 Sep 2019 11:40:14 +0200 Subject: [PATCH 018/680] [apps/calculation/edit_expression_controller] Access view more directly --- .../edit_expression_controller.cpp | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/apps/calculation/edit_expression_controller.cpp b/apps/calculation/edit_expression_controller.cpp index fb404c937..d0b673ab5 100644 --- a/apps/calculation/edit_expression_controller.cpp +++ b/apps/calculation/edit_expression_controller.cpp @@ -49,14 +49,14 @@ EditExpressionController::EditExpressionController(Responder * parentResponder, } void EditExpressionController::insertTextBody(const char * text) { - ((ContentView *)view())->expressionField()->handleEventWithText(text, false, true); + m_contentView.expressionField()->handleEventWithText(text, false, true); } void EditExpressionController::didBecomeFirstResponder() { int lastRow = m_calculationStore->numberOfCalculations() > 0 ? m_calculationStore->numberOfCalculations()-1 : 0; m_historyController->scrollToCell(0, lastRow); - ((ContentView *)view())->expressionField()->setEditing(true, false); - Container::activeApp()->setFirstResponder(((ContentView *)view())->expressionField()); + m_contentView.expressionField()->setEditing(true, false); + Container::activeApp()->setFirstResponder(m_contentView.expressionField()); } bool EditExpressionController::textFieldDidReceiveEvent(::TextField * textField, Ion::Events::Event event) { @@ -94,7 +94,7 @@ bool EditExpressionController::layoutFieldDidAbortEditing(::LayoutField * layout void EditExpressionController::layoutFieldDidChangeSize(::LayoutField * layoutField) { /* Reload the view only if the ExpressionField height actually changes, i.e. * not if the height is already maximal and stays maximal. */ - bool newInputViewHeightIsMaximal = static_cast(view())->expressionField()->heightIsMaximal(); + bool newInputViewHeightIsMaximal = m_contentView.expressionField()->heightIsMaximal(); if (!m_inputViewHeightIsMaximal || !newInputViewHeightIsMaximal) { m_inputViewHeightIsMaximal = newInputViewHeightIsMaximal; reloadView(); @@ -102,10 +102,10 @@ void EditExpressionController::layoutFieldDidChangeSize(::LayoutField * layoutFi } void EditExpressionController::reloadView() { - ((ContentView *)view())->reload(); + m_contentView.reload(); m_historyController->reload(); if (m_historyController->numberOfRows() > 0) { - ((ContentView *)view())->mainView()->scrollToCell(0, m_historyController->numberOfRows()-1); + m_contentView.mainView()->scrollToCell(0, m_historyController->numberOfRows()-1); } } @@ -119,13 +119,13 @@ bool EditExpressionController::inputViewDidReceiveEvent(Ion::Events::Event event } m_calculationStore->push(m_cacheBuffer, myApp->localContext()); m_historyController->reload(); - ((ContentView *)view())->mainView()->scrollToCell(0, m_historyController->numberOfRows()-1); + m_contentView.mainView()->scrollToCell(0, m_historyController->numberOfRows()-1); return true; } if (event == Ion::Events::Up) { if (m_calculationStore->numberOfCalculations() > 0) { m_cacheBuffer[0] = 0; - ((ContentView *)view())->expressionField()->setEditing(false, false); + m_contentView.expressionField()->setEditing(false, false); Container::activeApp()->setFirstResponder(m_historyController); } return true; @@ -143,15 +143,15 @@ bool EditExpressionController::inputViewDidFinishEditing(const char * text, Layo } m_calculationStore->push(m_cacheBuffer, textFieldDelegateApp()->localContext()); m_historyController->reload(); - ((ContentView *)view())->mainView()->scrollToCell(0, m_historyController->numberOfRows()-1); - ((ContentView *)view())->expressionField()->setEditing(true, true); + m_contentView.mainView()->scrollToCell(0, m_historyController->numberOfRows()-1); + m_contentView.expressionField()->setEditing(true, true); return true; } bool EditExpressionController::inputViewDidAbortEditing(const char * text) { if (text != nullptr) { - ((ContentView *)view())->expressionField()->setEditing(true, true); - ((ContentView *)view())->expressionField()->setText(text); + m_contentView.expressionField()->setEditing(true, true); + m_contentView.expressionField()->setText(text); } return false; } From 0055a59c750e07eca0d99ac5869b0328053516d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Mon, 30 Sep 2019 15:09:03 +0200 Subject: [PATCH 019/680] [apps/banner_view] Fix minimalSizeForOptimalDisplay Should not use m_frame as it may not be set properly. By default, a banner view wants to take the whole screen width This fixes the following scenario : Draw the polar curve r=12. When navigating from the tab to the graph, the curve was visibly redrawn because the banner view height was not computed properly. --- apps/shared/banner_view.cpp | 10 +++++++--- apps/shared/banner_view.h | 3 ++- apps/shared/curve_view.cpp | 1 + 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/apps/shared/banner_view.cpp b/apps/shared/banner_view.cpp index bd556f6f8..3bbd4d4ab 100644 --- a/apps/shared/banner_view.cpp +++ b/apps/shared/banner_view.cpp @@ -17,7 +17,11 @@ void BannerView::drawRect(KDContext * ctx, KDRect rect) const { } KDSize BannerView::minimalSizeForOptimalDisplay() const { - return KDSize(0, HeightGivenNumberOfLines(numberOfLines())); + return KDSize(Ion::Display::Width, minimalHeightForOptimalDisplayGivenWidth(Ion::Display::Width)); +} + +KDCoordinate BannerView::minimalHeightForOptimalDisplayGivenWidth(KDCoordinate width) const { + return HeightGivenNumberOfLines(numberOfLinesGivenWidth(width)); } void BannerView::layoutSubviews() { @@ -61,9 +65,9 @@ void BannerView::layoutSubviews() { } } -int BannerView::numberOfLines() const { +int BannerView::numberOfLinesGivenWidth(KDCoordinate width) const { int lineNumber = 1; - const KDCoordinate lineWidth = m_frame.width(); + const KDCoordinate lineWidth = width; KDCoordinate remainingWidth = lineWidth; for (int i = 0; i < numberOfSubviews(); i++) { KDCoordinate subviewWidth = const_cast(this)->subviewAtIndex(i)->minimalSizeForOptimalDisplay().width(); diff --git a/apps/shared/banner_view.h b/apps/shared/banner_view.h index 4bcf14f94..2f16a9e57 100644 --- a/apps/shared/banner_view.h +++ b/apps/shared/banner_view.h @@ -10,6 +10,7 @@ public: static KDCoordinate HeightGivenNumberOfLines(int linesCount); void drawRect(KDContext * ctx, KDRect rect) const override; KDSize minimalSizeForOptimalDisplay() const override; + KDCoordinate minimalHeightForOptimalDisplayGivenWidth(KDCoordinate width) const; void reload() { layoutSubviews(); } static constexpr const KDFont * Font() { return KDFont::SmallFont; } static constexpr KDColor TextColor() { return KDColorBlack; } @@ -19,7 +20,7 @@ private: int numberOfSubviews() const override = 0; View * subviewAtIndex(int index) override = 0; void layoutSubviews() override; - int numberOfLines() const; + int numberOfLinesGivenWidth(KDCoordinate width) const; }; } diff --git a/apps/shared/curve_view.cpp b/apps/shared/curve_view.cpp index 16d12d719..7eb87cf9b 100644 --- a/apps/shared/curve_view.cpp +++ b/apps/shared/curve_view.cpp @@ -752,6 +752,7 @@ KDRect CurveView::cursorFrame() { KDRect CurveView::bannerFrame() { KDRect bannerFrame = KDRectZero; if (bannerIsVisible()) { + assert(bounds().width() == Ion::Display::Width); // Else the bannerHeight will not be properly computed KDCoordinate bannerHeight = m_bannerView->minimalSizeForOptimalDisplay().height(); bannerFrame = KDRect(0, bounds().height()- bannerHeight, bounds().width(), bannerHeight); } From a233b0262348cdf644a27b846a993c5f9e844647 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Mon, 30 Sep 2019 10:53:05 +0200 Subject: [PATCH 020/680] [apps/regression] Better coef initialisation for trigonometric_model It improves the trigonometric fit of x = {0.0, 0.975, 1.97, 2.945, 3.971, 4.887, 5.924, 6.964, 7.979, 8.974, 9.998}; y = {-23.784, -23.322, -28.322, -18.422, -4.813206, 7.146241, 16.631, 16.632, 9.209189, -6.050863, -19.659}; --- apps/regression/model/model.cpp | 16 +++++++++----- apps/regression/model/model.h | 1 + apps/regression/model/trigonometric_model.cpp | 22 +++++++++++++++++++ apps/regression/model/trigonometric_model.h | 4 +++- 4 files changed, 36 insertions(+), 7 deletions(-) diff --git a/apps/regression/model/model.cpp b/apps/regression/model/model.cpp index d949b1571..bcbb14b19 100644 --- a/apps/regression/model/model.cpp +++ b/apps/regression/model/model.cpp @@ -33,14 +33,18 @@ double Model::levelSet(double * modelCoefficients, double xMin, double step, dou void Model::fit(Store * store, int series, double * modelCoefficients, Poincare::Context * context) { if (dataSuitableForFit(store, series)) { - for (int i = 0; i < numberOfCoefficients(); i++) { - modelCoefficients[i] = k_initialCoefficientValue; - } + initCoefficientsForFit(modelCoefficients, k_initialCoefficientValue, false, store, series); fitLevenbergMarquardt(store, series, modelCoefficients, context); } else { - for (int i = 0; i < numberOfCoefficients(); i++) { - modelCoefficients[i] = NAN; - } + initCoefficientsForFit(modelCoefficients, NAN, true); + } +} + +void Model::initCoefficientsForFit(double * modelCoefficients, double defaultValue, bool forceDefaultValue, Store * store, int series) const { + assert(defaultValue || (store != nullptr && series >= 0 && series < Store::k_numberOfSeries && !store->seriesIsEmpty(series))); + int nbCoef = numberOfCoefficients(); + for (int i = 0; i < nbCoef; i++) { + modelCoefficients[i] = defaultValue; } } diff --git a/apps/regression/model/model.h b/apps/regression/model/model.h index b45247961..4c2550946 100644 --- a/apps/regression/model/model.h +++ b/apps/regression/model/model.h @@ -39,6 +39,7 @@ public: virtual int bannerLinesCount() const { return 2; } protected: // Fit + virtual void initCoefficientsForFit(double * modelCoefficients, double defaultValue, bool forceDefaultValue, Store * store = nullptr, int series = -1) const; virtual bool dataSuitableForFit(Store * store, int series) const; constexpr static const KDFont * k_layoutFont = KDFont::SmallFont; Poincare::Layout m_layout; diff --git a/apps/regression/model/trigonometric_model.cpp b/apps/regression/model/trigonometric_model.cpp index 166af2be4..b65110481 100644 --- a/apps/regression/model/trigonometric_model.cpp +++ b/apps/regression/model/trigonometric_model.cpp @@ -1,4 +1,5 @@ #include "trigonometric_model.h" +#include #include "../../shared/poincare_helpers.h" #include #include @@ -69,6 +70,27 @@ double TrigonometricModel::partialDerivate(double * modelCoefficients, int deriv return 0.0; } +void TrigonometricModel::initCoefficientsForFit(double * modelCoefficients, double defaultValue, bool forceDefaultValue, Store * store, int series) const { + if (forceDefaultValue) { + Model::initCoefficientsForFit(modelCoefficients, defaultValue, forceDefaultValue); + return; + } + assert(store != nullptr && series >= 0 && series < Store::k_numberOfSeries && !store->seriesIsEmpty(series)); + for (int i = 1; i < k_numberOfCoefficients - 1; i++) { + modelCoefficients[i] = defaultValue; + } + /* We try a better initialization than the default value. We hope that this + * will improve the gradient descent to find correct coefficients. + * + * Init the "amplitude" coefficient. We take twice the standard deviation, + * because for a normal law, this interval contains 99.73% of the values. We + * do not take half of the apmlitude of the series, because this would be too + * dependant on outliers. */ + modelCoefficients[0] = 3.0*store->standardDeviationOfColumn(series, 1); + // Init the "y delta" coefficient + modelCoefficients[k_numberOfCoefficients - 1] = store->meanOfColumn(series, 1); +} + Expression TrigonometricModel::expression(double * modelCoefficients) { double a = modelCoefficients[0]; double b = modelCoefficients[1]; diff --git a/apps/regression/model/trigonometric_model.h b/apps/regression/model/trigonometric_model.h index a22bf69a0..c3fdad8f0 100644 --- a/apps/regression/model/trigonometric_model.h +++ b/apps/regression/model/trigonometric_model.h @@ -12,9 +12,11 @@ public: I18n::Message formulaMessage() const override { return I18n::Message::TrigonometricRegressionFormula; } double evaluate(double * modelCoefficients, double x) const override; double partialDerivate(double * modelCoefficients, int derivateCoefficientIndex, double x) const override; - int numberOfCoefficients() const override { return 4; } + int numberOfCoefficients() const override { return k_numberOfCoefficients; } int bannerLinesCount() const override { return 4; } private: + static constexpr int k_numberOfCoefficients = 4; + void initCoefficientsForFit(double * modelCoefficients, double defaultValue, bool forceDefaultValue, Store * store = nullptr, int series = -1) const override; Poincare::Expression expression(double * modelCoefficients) override; }; From 463b44f055dd0cfd76d0dcf69e6beea21bab3ce7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Tue, 1 Oct 2019 11:53:47 +0200 Subject: [PATCH 021/680] [poincare/nth_root_layout] isSquareRoot --- poincare/include/poincare/nth_root_layout.h | 2 ++ poincare/src/nth_root_layout.cpp | 27 +++++++++++++-------- 2 files changed, 19 insertions(+), 10 deletions(-) diff --git a/poincare/include/poincare/nth_root_layout.h b/poincare/include/poincare/nth_root_layout.h index 5eb5b97c0..2af308d5b 100644 --- a/poincare/include/poincare/nth_root_layout.h +++ b/poincare/include/poincare/nth_root_layout.h @@ -19,6 +19,8 @@ public: m_hasIndex(hasIndex) {} + bool isSquareRoot() const; + // Layout Type type() const override { return Type::NthRootLayout; } diff --git a/poincare/src/nth_root_layout.cpp b/poincare/src/nth_root_layout.cpp index ac4a9e147..b04f8168a 100644 --- a/poincare/src/nth_root_layout.cpp +++ b/poincare/src/nth_root_layout.cpp @@ -21,6 +21,17 @@ const uint8_t radixPixel[NthRootLayoutNode::k_leftRadixHeight][NthRootLayoutNode {0xFF, 0xFF, 0xFF, 0xFF, 0xCB} }; +bool NthRootLayoutNode::isSquareRoot() const { + if (!m_hasIndex) { + return true; + } + assert((const_cast(this))->indexLayout() != nullptr); + if ((const_cast(this))->indexLayout()->isEmpty()) { + return true; + } + return false; +} + void NthRootLayoutNode::moveCursorLeft(LayoutCursor * cursor, bool * shouldRecomputeLayout) { if (cursor->layoutNode() == radicandLayout() && cursor->position() == LayoutCursor::Position::Left) @@ -149,17 +160,13 @@ void NthRootLayoutNode::deleteBeforeCursor(LayoutCursor * cursor) { } int NthRootLayoutNode::serialize(char * buffer, int bufferSize, Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const { - if (m_hasIndex) { - assert((const_cast(this))->indexLayout()); - if ((const_cast(this))->indexLayout()->isEmpty()) { - // Case: root(x,empty): Write "'SquareRootSymbol'('radicandLayout')" - return SerializationHelper::Prefix(this, buffer, bufferSize, floatDisplayMode, numberOfSignificantDigits, SquareRoot::s_functionHelper.name(), true, 0); - } - // Case: root(x,n) - return SerializationHelper::Prefix(this, buffer, bufferSize, floatDisplayMode, numberOfSignificantDigits, NthRoot::s_functionHelper.name(), true); + if (isSquareRoot()) { + /* Case: squareRoot(x) or root(x,empty): + * Write "SquareRootSymbol(radicandLayout) */ + return SerializationHelper::Prefix(this, buffer, bufferSize, floatDisplayMode, numberOfSignificantDigits, SquareRoot::s_functionHelper.name(), true, 0); } - // Case: squareRoot(x) - return SerializationHelper::Prefix(this, buffer, bufferSize, floatDisplayMode, numberOfSignificantDigits, SquareRoot::s_functionHelper.name(), true); + // Case: root(x,n) + return SerializationHelper::Prefix(this, buffer, bufferSize, floatDisplayMode, numberOfSignificantDigits, NthRoot::s_functionHelper.name(), true); } KDSize NthRootLayoutNode::computeSize() { From 83fde09370963e14186e1bca76f8de1d876a73bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Tue, 1 Oct 2019 11:54:13 +0200 Subject: [PATCH 022/680] [poincare] Fix serializing/parsing of layout x|2| Would give the fucntion xabs(2) --- poincare/src/horizontal_layout.cpp | 53 +++++++++++++++++++++++--- poincare/test/layout_to_expression.cpp | 27 +++++++++++++ 2 files changed, 75 insertions(+), 5 deletions(-) diff --git a/poincare/src/horizontal_layout.cpp b/poincare/src/horizontal_layout.cpp index b2b45f614..8a5702fe6 100644 --- a/poincare/src/horizontal_layout.cpp +++ b/poincare/src/horizontal_layout.cpp @@ -1,6 +1,7 @@ #include #include #include +#include #include namespace Poincare { @@ -180,14 +181,56 @@ LayoutNode * HorizontalLayoutNode::layoutToPointWhenInserting(Expression * corre } int HorizontalLayoutNode::serialize(char * buffer, int bufferSize, Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const { - if (numberOfChildren() == 0) { - if (bufferSize == 0) { - return -1; - } + if (bufferSize == 0) { + return -1; + } + int childrenCount = numberOfChildren(); + if (childrenCount == 0 || bufferSize == 1) { buffer[0] = 0; return 0; } - return SerializationHelper::Infix(this, buffer, bufferSize, floatDisplayMode, numberOfSignificantDigits, ""); + + int numberOfChar = 0; + // Write the children, adding multiplication signs if needed + LayoutNode * currentChild = childAtIndex(0); + LayoutNode * nextChild = nullptr; + for (int i = 0; i < childrenCount; i++) { + // Write the child + numberOfChar+= currentChild->serialize(buffer + numberOfChar, bufferSize - numberOfChar, floatDisplayMode, numberOfSignificantDigits); + if (i != childrenCount - 1) { + nextChild = childAtIndex(i+1); + // Write the multiplication sign if needed + LayoutNode::Type nextChildType = nextChild->type(); + if ((nextChildType == LayoutNode::Type::AbsoluteValueLayout + || nextChildType == LayoutNode::Type::BinomialCoefficientLayout + || nextChildType == LayoutNode::Type::CeilingLayout + || nextChildType == LayoutNode::Type::ConjugateLayout + || nextChildType == LayoutNode::Type::CeilingLayout + || nextChildType == LayoutNode::Type::FloorLayout + || nextChildType == LayoutNode::Type::IntegralLayout + || (nextChildType == LayoutNode::Type::NthRootLayout + && !static_cast(nextChild)->isSquareRoot()) + || nextChildType == LayoutNode::Type::ProductLayout + || nextChildType == LayoutNode::Type::SumLayout) + && currentChild->canBeOmittedMultiplicationLeftFactor()) + { + assert(nextChildType != LayoutNode::Type::HorizontalLayout); + numberOfChar += SerializationHelper::CodePoint(buffer+numberOfChar, bufferSize - numberOfChar, '*'); + if (numberOfChar >= bufferSize-1) { + assert(buffer[bufferSize - 1] == 0); + return bufferSize - 1; + } + } + } + currentChild = nextChild; + } + if (numberOfChar >= bufferSize-1) { + assert(buffer[bufferSize - 1] == 0); + return bufferSize - 1; + } + + assert(buffer[numberOfChar] == 0); + return numberOfChar; } bool HorizontalLayoutNode::hasText() const { diff --git a/poincare/test/layout_to_expression.cpp b/poincare/test/layout_to_expression.cpp index 5c66ac181..56ba8077b 100644 --- a/poincare/test/layout_to_expression.cpp +++ b/poincare/test/layout_to_expression.cpp @@ -492,4 +492,31 @@ QUIZ_CASE(poincare_layout_to_expression_parsable) { VerticalOffsetLayoutNode::Position::Superscript)); e = Multiplication::Builder(Rational::Builder(2),Power::Builder(Constant::Builder(UCodePointScriptSmallE), Rational::Builder(3))); assert_parsed_layout_is(l, e); + + // x|2| + l = HorizontalLayout::Builder( + CodePointLayout::Builder('x'), + AbsoluteValueLayout::Builder( + CodePointLayout::Builder('2'))); + e = Multiplication::Builder( + Symbol::Builder('x'), + AbsoluteValue::Builder(Rational::Builder(2))); + assert_parsed_layout_is(l, e); + + // x int(7, x, 4, 5) + l = HorizontalLayout::Builder( + CodePointLayout::Builder('x'), + IntegralLayout::Builder( + CodePointLayout::Builder('7'), + CodePointLayout::Builder('x'), + CodePointLayout::Builder('4'), + CodePointLayout::Builder('5'))); + e = Multiplication::Builder( + Symbol::Builder('x'), + Integral::Builder( + Rational::Builder(7), + Symbol::Builder('x'), + Rational::Builder(4), + Rational::Builder(5))); + assert_parsed_layout_is(l, e); } From 16885e6be8e6da7ede6cf1ac03ffb27f4e712771 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Tue, 1 Oct 2019 11:55:07 +0200 Subject: [PATCH 023/680] [poincare/tree_node] Coding style --- poincare/include/poincare/tree_node.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/poincare/include/poincare/tree_node.h b/poincare/include/poincare/tree_node.h index 667e7a722..045252f3f 100644 --- a/poincare/include/poincare/tree_node.h +++ b/poincare/include/poincare/tree_node.h @@ -98,7 +98,7 @@ public: * 4 * * */ - virtual bool childNeedsSystemParenthesesAtSerialization(const TreeNode * child) const { return false; }; + virtual bool childNeedsSystemParenthesesAtSerialization(const TreeNode * child) const { return false; } template class Iterator { From 9e6c3c7a268e6022685631b23acd544757eed552 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Tue, 1 Oct 2019 11:55:30 +0200 Subject: [PATCH 024/680] [poincare/code_point_layout] Fix typo in canBeOmittedMultiplicationLeftFactor --- poincare/src/code_point_layout.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/poincare/src/code_point_layout.cpp b/poincare/src/code_point_layout.cpp index 9d8a01fb6..606310393 100644 --- a/poincare/src/code_point_layout.cpp +++ b/poincare/src/code_point_layout.cpp @@ -84,7 +84,7 @@ bool CodePointLayoutNode::canBeOmittedMultiplicationLeftFactor() const { if (isMultiplicationCodePoint()) { return false; } - return LayoutNode::canBeOmittedMultiplicationRightFactor(); + return LayoutNode::canBeOmittedMultiplicationLeftFactor(); } bool CodePointLayoutNode::canBeOmittedMultiplicationRightFactor() const { From 310e1ab82977ac2c26c8adf8784d731e7147537e Mon Sep 17 00:00:00 2001 From: Ruben Dashyan Date: Tue, 1 Oct 2019 09:54:25 +0200 Subject: [PATCH 025/680] [apps/calculation/edit_expression_controller] Make ContentView View-specific methods private --- apps/calculation/edit_expression_controller.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/apps/calculation/edit_expression_controller.h b/apps/calculation/edit_expression_controller.h index 3ad0b4f66..24fbca013 100644 --- a/apps/calculation/edit_expression_controller.h +++ b/apps/calculation/edit_expression_controller.h @@ -39,11 +39,10 @@ private: void reload(); TableView * mainView() { return m_mainView; } ExpressionField * expressionField() { return &m_expressionField; } - /* View */ + private: int numberOfSubviews() const override { return 2; } View * subviewAtIndex(int index) override; void layoutSubviews() override; - private: TableView * m_mainView; ExpressionField m_expressionField; }; From 737d76471bfbc8d71543d9822e7403a0edd02ae3 Mon Sep 17 00:00:00 2001 From: Ruben Dashyan Date: Tue, 1 Oct 2019 09:55:43 +0200 Subject: [PATCH 026/680] [escher/layout_field] Remove unused accessor --- escher/include/escher/layout_field.h | 1 - 1 file changed, 1 deletion(-) diff --git a/escher/include/escher/layout_field.h b/escher/include/escher/layout_field.h index 1fefd2688..71f05fe6c 100644 --- a/escher/include/escher/layout_field.h +++ b/escher/include/escher/layout_field.h @@ -66,7 +66,6 @@ private: KDRect cursorRect() { return m_cursorView.frame(); } Poincare::LayoutCursor * cursor() { return &m_cursor; } const ExpressionView * expressionView() const { return &m_expressionView; } - ExpressionView * editableExpressionView() { return &m_expressionView; } void clearLayout(); /* View */ KDSize minimalSizeForOptimalDisplay() const override; From 063cc66ba278a8619d55f3440eb608e927a3e62e Mon Sep 17 00:00:00 2001 From: Ruben Dashyan Date: Tue, 1 Oct 2019 09:58:10 +0200 Subject: [PATCH 027/680] [escher/layout_field] Make protected methods private LayoutField has no derived class --- escher/include/escher/layout_field.h | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/escher/include/escher/layout_field.h b/escher/include/escher/layout_field.h index 71f05fe6c..db35b7b85 100644 --- a/escher/include/escher/layout_field.h +++ b/escher/include/escher/layout_field.h @@ -43,14 +43,12 @@ public: return m_delegate->layoutFieldShouldFinishEditing(this, event); } -protected: - void reload(KDSize previousSize); - virtual bool privateHandleEvent(Ion::Events::Event event); - bool privateHandleMoveEvent(Ion::Events::Event event, bool * shouldRecomputeLayout); - private: constexpr static int k_maxNumberOfLayouts = 220; static_assert(k_maxNumberOfLayouts == TextField::maxBufferSize(), "Maximal number of layouts in a layout field should be equal to max number of char in text field"); + void reload(KDSize previousSize); + virtual bool privateHandleEvent(Ion::Events::Event event); + bool privateHandleMoveEvent(Ion::Events::Event event, bool * shouldRecomputeLayout); void scrollRightOfLayout(Poincare::Layout layoutR); void scrollToBaselinedRect(KDRect rect, KDCoordinate baseline); void insertLayoutAtCursor(Poincare::Layout layoutR, Poincare::Expression correspondingExpression, bool forceCursorRightOfLayout = false); From ecd6cb29f1849df1475f5af29dc53fc0754d00e4 Mon Sep 17 00:00:00 2001 From: Ruben Dashyan Date: Tue, 1 Oct 2019 13:55:03 +0200 Subject: [PATCH 028/680] [escher/expression_field] Rename k_textFieldHeight to k_minimalHeight That constant has nothing to do with TextField. It is the minimal height of ExpressionField. --- escher/include/escher/expression_field.h | 2 +- escher/src/expression_field.cpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/escher/include/escher/expression_field.h b/escher/include/escher/expression_field.h index 0c4c1dc43..f072c3791 100644 --- a/escher/include/escher/expression_field.h +++ b/escher/include/escher/expression_field.h @@ -39,7 +39,7 @@ public: private: static constexpr int k_textFieldBufferSize = TextField::maxBufferSize(); - static constexpr KDCoordinate k_textFieldHeight = 37; + static constexpr KDCoordinate k_minimalHeight = 37; static constexpr KDCoordinate k_horizontalMargin = 5; static constexpr KDCoordinate k_verticalMargin = 5; constexpr static KDCoordinate k_separatorThickness = Metric::CellSeparatorThickness; diff --git a/escher/src/expression_field.cpp b/escher/src/expression_field.cpp index 129893c13..c9c87a32d 100644 --- a/escher/src/expression_field.cpp +++ b/escher/src/expression_field.cpp @@ -113,9 +113,9 @@ bool ExpressionField::handleEventWithText(const char * text, bool indentation, b KDCoordinate ExpressionField::inputViewHeight() const { return k_separatorThickness - + (editionIsInTextField() ? k_textFieldHeight : + + (editionIsInTextField() ? k_minimalHeight : minCoordinate(maximalHeight(), - maxCoordinate(k_textFieldHeight, m_layoutField.minimalSizeForOptimalDisplay().height()))); + maxCoordinate(k_minimalHeight, m_layoutField.minimalSizeForOptimalDisplay().height()))); } KDCoordinate ExpressionField::maximalHeight() const { From 1c668dca52b0944069236a2b6fa31ee82c44c22b Mon Sep 17 00:00:00 2001 From: Ruben Dashyan Date: Tue, 1 Oct 2019 13:59:47 +0200 Subject: [PATCH 029/680] [escher/layout_field] Remove unused enum class --- escher/include/escher/layout_field.h | 4 ---- 1 file changed, 4 deletions(-) diff --git a/escher/include/escher/layout_field.h b/escher/include/escher/layout_field.h index db35b7b85..1f5723c4a 100644 --- a/escher/include/escher/layout_field.h +++ b/escher/include/escher/layout_field.h @@ -68,10 +68,6 @@ private: /* View */ KDSize minimalSizeForOptimalDisplay() const override; private: - enum class Position { - Top, - Bottom - }; int numberOfSubviews() const override { return 2; } View * subviewAtIndex(int index) override; void layoutSubviews() override; From f85658f5e65d9f7049ec9515dfc986ecfa1d8c9d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Wed, 2 Oct 2019 10:49:40 +0200 Subject: [PATCH 030/680] [escher/view] Inline some view methods --- escher/include/escher/view.h | 18 ++++++++---------- escher/src/view.cpp | 20 -------------------- 2 files changed, 8 insertions(+), 30 deletions(-) diff --git a/escher/include/escher/view.h b/escher/include/escher/view.h index 442c53b40..a5fa14056 100644 --- a/escher/include/escher/view.h +++ b/escher/include/escher/view.h @@ -30,7 +30,7 @@ class View { friend class TransparentView; friend class Shared::RoundCursorView; public: - View(); + View() : m_frame(KDRectZero), m_superview(nullptr), m_dirtyRect(KDRectZero) {} virtual ~View() { for (int i = 0; i < numberOfSubviews(); i++) { View * subview = subviewAtIndex(i); @@ -49,7 +49,9 @@ public: /* The drawRect method should be implemented by each View subclass. In a * typical drawRect implementation, a subclass will make drawing calls to the * Kandinsky library using the provided context. */ - virtual void drawRect(KDContext * ctx, KDRect rect) const; + virtual void drawRect(KDContext * ctx, KDRect rect) const { + // By default, a view doesn't do anything, it's transparent + } void setSize(KDSize size); void setFrame(KDRect frame); @@ -58,7 +60,7 @@ public: KDRect bounds() const; View * subview(int index); - virtual KDSize minimalSizeForOptimalDisplay() const; + virtual KDSize minimalSizeForOptimalDisplay() const { return KDSizeZero; } #if ESCHER_VIEW_LOGGING friend std::ostream &operator<<(std::ostream &os, View &view); @@ -80,13 +82,9 @@ protected: #endif KDRect m_frame; private: - virtual int numberOfSubviews() const { - return 0; - } - virtual View * subviewAtIndex(int index) { - return nullptr; - } - virtual void layoutSubviews(); + virtual int numberOfSubviews() const { return 0; } + virtual View * subviewAtIndex(int index) { return nullptr; } + virtual void layoutSubviews(bool force = false) {} virtual const Window * window() const; KDRect redraw(KDRect rect, KDRect forceRedrawRect = KDRectZero); KDPoint absoluteOrigin() const; diff --git a/escher/src/view.cpp b/escher/src/view.cpp index 829a77779..2542aa0f3 100644 --- a/escher/src/view.cpp +++ b/escher/src/view.cpp @@ -3,18 +3,6 @@ extern "C" { } #include -View::View() : - m_frame(KDRectZero), - m_superview(nullptr), - m_dirtyRect(KDRectZero) -{ -} - -void View::drawRect(KDContext * ctx, KDRect rect) const { - // By default, a view doesn't do anything - // It's transparent! -} - const Window * View::window() const { if (m_superview == nullptr) { return nullptr; @@ -167,14 +155,6 @@ KDRect View::absoluteVisibleFrame() const { } } -KDSize View::minimalSizeForOptimalDisplay() const { - return KDSizeZero; -} - -void View::layoutSubviews() { -} - - #if ESCHER_VIEW_LOGGING const char * View::className() const { return "View"; From 9f018eb9d907dd01c0c79d6c06a55da50ca2522d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Wed, 2 Oct 2019 11:22:49 +0200 Subject: [PATCH 031/680] [escher/view] setFrame and layoutSubviews can be forced --- apps/apps_container.cpp | 4 +- apps/apps_window.cpp | 6 +-- apps/apps_window.h | 2 +- .../edit_expression_controller.cpp | 6 +-- apps/calculation/edit_expression_controller.h | 2 +- apps/calculation/history_view_cell.cpp | 13 +++-- apps/calculation/history_view_cell.h | 2 +- apps/code/console_edit_cell.cpp | 6 +-- apps/code/console_edit_cell.h | 2 +- apps/code/console_line_cell.cpp | 10 ++-- apps/code/console_line_cell.h | 2 +- apps/code/editor_view.cpp | 14 +++--- apps/code/editor_view.h | 2 +- apps/code/script_name_cell.cpp | 5 +- apps/code/script_name_cell.h | 2 +- apps/exam_pop_up_controller.cpp | 14 +++--- apps/exam_pop_up_controller.h | 2 +- .../list/text_field_function_title_cell.cpp | 4 +- .../list/text_field_function_title_cell.h | 2 +- apps/graph/values/abscissa_title_cell.cpp | 4 +- apps/graph/values/abscissa_title_cell.h | 2 +- ...interval_parameter_selector_controller.cpp | 2 +- .../hardware_test/battery_test_controller.cpp | 8 ++-- apps/hardware_test/battery_test_controller.h | 2 +- apps/hardware_test/code_128b_view.cpp | 2 +- apps/hardware_test/code_128b_view.h | 2 +- .../colors_lcd_test_controller.cpp | 4 +- .../colors_lcd_test_controller.h | 2 +- .../lcd_data_test_controller.cpp | 6 +-- apps/hardware_test/lcd_data_test_controller.h | 2 +- .../lcd_timing_test_controller.cpp | 6 +-- .../lcd_timing_test_controller.h | 2 +- apps/hardware_test/led_test_controller.cpp | 10 ++-- apps/hardware_test/led_test_controller.h | 2 +- apps/hardware_test/pop_up_controller.cpp | 16 +++---- apps/hardware_test/pop_up_controller.h | 2 +- apps/hardware_test/vblank_test_controller.cpp | 4 +- apps/hardware_test/vblank_test_controller.h | 2 +- apps/home/app_cell.cpp | 6 +-- apps/home/app_cell.h | 2 +- apps/home/controller.cpp | 4 +- apps/home/controller.h | 2 +- apps/on_boarding/logo_view.cpp | 4 +- apps/on_boarding/logo_view.h | 2 +- apps/on_boarding/pop_up_controller.cpp | 6 +-- apps/on_boarding/pop_up_controller.h | 2 +- apps/probability/calculation_cell.cpp | 6 +-- apps/probability/calculation_cell.h | 2 +- apps/probability/calculation_controller.cpp | 8 ++-- apps/probability/calculation_controller.h | 2 +- apps/probability/cell.cpp | 8 ++-- apps/probability/cell.h | 2 +- apps/probability/distribution_controller.cpp | 6 +-- apps/probability/distribution_controller.h | 2 +- apps/probability/image_cell.cpp | 4 +- apps/probability/image_cell.h | 2 +- apps/probability/parameters_controller.cpp | 12 ++--- apps/probability/parameters_controller.h | 2 +- apps/probability/responder_image_cell.cpp | 4 +- apps/probability/responder_image_cell.h | 2 +- apps/regression/column_title_cell.cpp | 6 +-- apps/regression/column_title_cell.h | 2 +- ...double_buffer_text_cell_with_separator.cpp | 6 +-- ...d_double_buffer_text_cell_with_separator.h | 2 +- apps/sequence/sequence_title_cell.cpp | 4 +- apps/sequence/sequence_title_cell.h | 2 +- ...cell_with_editable_text_with_separator.cpp | 4 +- ...e_cell_with_editable_text_with_separator.h | 2 +- apps/shared/banner_view.cpp | 4 +- apps/shared/banner_view.h | 2 +- apps/shared/buffer_function_title_cell.cpp | 4 +- apps/shared/buffer_function_title_cell.h | 2 +- .../buffer_text_view_with_text_field.cpp | 6 +-- .../shared/buffer_text_view_with_text_field.h | 2 +- apps/shared/button_with_separator.cpp | 4 +- apps/shared/button_with_separator.h | 2 +- apps/shared/cursor_view.h | 2 +- apps/shared/curve_view.cpp | 8 ++-- apps/shared/curve_view.h | 2 +- apps/shared/function_expression_cell.cpp | 4 +- apps/shared/function_expression_cell.h | 2 +- apps/shared/message_view.cpp | 6 +-- apps/shared/message_view.h | 2 +- apps/shared/round_cursor_view.cpp | 6 +-- apps/shared/round_cursor_view.h | 2 +- ...ble_exact_approximate_expressions_cell.cpp | 4 +- ...lable_exact_approximate_expressions_cell.h | 2 +- ...ble_exact_approximate_expressions_view.cpp | 10 ++-- ...lable_exact_approximate_expressions_view.h | 2 +- .../separator_even_odd_buffer_text_cell.cpp | 9 +++- .../separator_even_odd_buffer_text_cell.h | 2 +- apps/shared/store_cell.cpp | 4 +- apps/shared/store_cell.h | 2 +- apps/shared/store_controller.cpp | 6 +-- apps/shared/store_controller.h | 2 +- apps/shared/store_title_cell.cpp | 4 +- apps/shared/store_title_cell.h | 2 +- apps/shared/sum_graph_controller.cpp | 20 ++++---- apps/shared/sum_graph_controller.h | 4 +- apps/shared/zoom_parameter_controller.cpp | 16 +++---- apps/shared/zoom_parameter_controller.h | 4 +- apps/shift_alpha_lock_view.cpp | 6 +-- apps/shift_alpha_lock_view.h | 2 +- apps/solver/equation_list_view.cpp | 8 ++-- apps/solver/equation_list_view.h | 2 +- apps/solver/interval_controller.cpp | 8 ++-- apps/solver/interval_controller.h | 2 +- apps/solver/solutions_controller.cpp | 10 ++-- apps/solver/solutions_controller.h | 2 +- apps/statistics/multiple_boxes_view.cpp | 6 +-- apps/statistics/multiple_boxes_view.h | 2 +- apps/statistics/multiple_data_view.cpp | 20 ++++---- apps/statistics/multiple_data_view.h | 6 +-- apps/statistics/multiple_histograms_view.cpp | 2 +- apps/statistics/multiple_histograms_view.h | 2 +- apps/title_bar_view.cpp | 14 +++--- apps/title_bar_view.h | 2 +- apps/variable_box_empty_controller.cpp | 6 +-- apps/variable_box_empty_controller.h | 2 +- .../escher/alternate_empty_view_controller.h | 2 +- escher/include/escher/bank_view_controller.h | 4 +- escher/include/escher/button.h | 2 +- escher/include/escher/button_row_controller.h | 2 +- escher/include/escher/editable_text_cell.h | 2 +- .../escher/even_odd_buffer_text_cell.h | 2 +- .../escher/even_odd_cell_with_ellipsis.h | 2 +- .../escher/even_odd_editable_text_cell.h | 2 +- .../include/escher/even_odd_expression_cell.h | 2 +- .../escher/even_odd_message_text_cell.h | 2 +- escher/include/escher/expression_field.h | 2 +- escher/include/escher/layout_field.h | 6 +-- .../message_table_cell_with_editable_text.h | 2 +- escher/include/escher/modal_view_controller.h | 2 +- escher/include/escher/scroll_view.h | 8 ++-- escher/include/escher/stack_view_controller.h | 2 +- escher/include/escher/tab_view.h | 2 +- escher/include/escher/tab_view_controller.h | 2 +- escher/include/escher/table_cell.h | 2 +- escher/include/escher/table_view.h | 4 +- escher/include/escher/text_field.h | 2 +- escher/include/escher/text_input.h | 2 +- escher/include/escher/view.h | 2 +- escher/include/escher/warning_controller.h | 2 +- escher/include/escher/window.h | 2 +- .../src/alternate_empty_view_controller.cpp | 6 +-- escher/src/button.cpp | 4 +- escher/src/button_row_controller.cpp | 8 ++-- escher/src/editable_text_cell.cpp | 5 +- escher/src/even_odd_buffer_text_cell.cpp | 4 +- escher/src/even_odd_cell_with_ellipsis.cpp | 4 +- escher/src/even_odd_editable_text_cell.cpp | 4 +- escher/src/even_odd_expression_cell.cpp | 4 +- escher/src/even_odd_message_text_cell.cpp | 4 +- escher/src/expression_field.cpp | 10 ++-- escher/src/layout_field.cpp | 12 ++--- .../message_table_cell_with_editable_text.cpp | 11 +++-- escher/src/modal_view_controller.cpp | 8 ++-- escher/src/scroll_view.cpp | 48 +++++++++---------- escher/src/stack_view_controller.cpp | 8 ++-- escher/src/tab_view.cpp | 4 +- escher/src/tab_view_controller.cpp | 6 +-- escher/src/table_cell.cpp | 19 +++++--- escher/src/table_view.cpp | 10 ++-- escher/src/text_field.cpp | 6 +-- escher/src/text_input.cpp | 4 +- escher/src/view.cpp | 8 ++-- escher/src/warning_controller.cpp | 8 ++-- escher/src/window.cpp | 4 +- 168 files changed, 421 insertions(+), 405 deletions(-) diff --git a/apps/apps_container.cpp b/apps/apps_container.cpp index 5656aecb9..dc1e6af37 100644 --- a/apps/apps_container.cpp +++ b/apps/apps_container.cpp @@ -32,7 +32,7 @@ AppsContainer::AppsContainer() : m_hardwareTestSnapshot(), m_usbConnectedSnapshot() { - m_emptyBatteryWindow.setFrame(KDRect(0, 0, Ion::Display::Width, Ion::Display::Height)); + m_emptyBatteryWindow.setFrame(KDRect(0, 0, Ion::Display::Width, Ion::Display::Height), false); #if __EMSCRIPTEN__ /* AppsContainer::poincareCircuitBreaker uses Ion::Keyboard::scan(), which * calls emscripten_sleep. If we set the poincare circuit breaker, we would @@ -208,7 +208,7 @@ bool AppsContainer::switchTo(App::Snapshot * snapshot) { void AppsContainer::run() { KDRect screenRect = KDRect(0, 0, Ion::Display::Width, Ion::Display::Height); - window()->setFrame(screenRect); + window()->setFrame(screenRect, false); /* We push a white screen here, because fetching the exam mode takes some time * and it is visible when reflashing a N0100 (there is some noise on the * screen before the logo appears). */ diff --git a/apps/apps_window.cpp b/apps/apps_window.cpp index f3457f515..68a150133 100644 --- a/apps/apps_window.cpp +++ b/apps/apps_window.cpp @@ -58,11 +58,11 @@ View * AppsWindow::subviewAtIndex(int index) { return m_contentView; } -void AppsWindow::layoutSubviews() { +void AppsWindow::layoutSubviews(bool force) { KDCoordinate titleHeight = m_hideTitleBarView ? 0 : Metric::TitleBarHeight; - m_titleBarView.setFrame(KDRect(0, 0, bounds().width(), titleHeight)); + m_titleBarView.setFrame(KDRect(0, 0, bounds().width(), titleHeight), force); if (m_contentView != nullptr) { - m_contentView->setFrame(KDRect(0, titleHeight, bounds().width(), bounds().height()-titleHeight)); + m_contentView->setFrame(KDRect(0, titleHeight, bounds().width(), bounds().height()-titleHeight), force); } } diff --git a/apps/apps_window.h b/apps/apps_window.h index 093d63d74..08f1bb651 100644 --- a/apps/apps_window.h +++ b/apps/apps_window.h @@ -17,7 +17,7 @@ public: void hideTitleBarView(bool hide); private: int numberOfSubviews() const override; - void layoutSubviews() override; + void layoutSubviews(bool force = false) override; View * subviewAtIndex(int index) override; TitleBarView m_titleBarView; bool m_hideTitleBarView; diff --git a/apps/calculation/edit_expression_controller.cpp b/apps/calculation/edit_expression_controller.cpp index d0b673ab5..d72b7fc20 100644 --- a/apps/calculation/edit_expression_controller.cpp +++ b/apps/calculation/edit_expression_controller.cpp @@ -25,12 +25,12 @@ View * EditExpressionController::ContentView::subviewAtIndex(int index) { return &m_expressionField; } -void EditExpressionController::ContentView::layoutSubviews() { +void EditExpressionController::ContentView::layoutSubviews(bool force) { KDCoordinate inputViewFrameHeight = m_expressionField.minimalSizeForOptimalDisplay().height(); KDRect mainViewFrame(0, 0, bounds().width(), bounds().height() - inputViewFrameHeight); - m_mainView->setFrame(mainViewFrame); + m_mainView->setFrame(mainViewFrame, force); KDRect inputViewFrame(0, bounds().height() - inputViewFrameHeight, bounds().width(), inputViewFrameHeight); - m_expressionField.setFrame(inputViewFrame); + m_expressionField.setFrame(inputViewFrame, force); } void EditExpressionController::ContentView::reload() { diff --git a/apps/calculation/edit_expression_controller.h b/apps/calculation/edit_expression_controller.h index 24fbca013..2fadd126d 100644 --- a/apps/calculation/edit_expression_controller.h +++ b/apps/calculation/edit_expression_controller.h @@ -42,7 +42,7 @@ private: private: int numberOfSubviews() const override { return 2; } View * subviewAtIndex(int index) override; - void layoutSubviews() override; + void layoutSubviews(bool force = false) override; TableView * m_mainView; ExpressionField m_expressionField; }; diff --git a/apps/calculation/history_view_cell.cpp b/apps/calculation/history_view_cell.cpp index e7e6c8d8a..901795896 100644 --- a/apps/calculation/history_view_cell.cpp +++ b/apps/calculation/history_view_cell.cpp @@ -120,22 +120,21 @@ View * HistoryViewCell::subviewAtIndex(int index) { return views[index]; } -void HistoryViewCell::layoutSubviews() { +void HistoryViewCell::layoutSubviews(bool force) { KDCoordinate maxFrameWidth = bounds().width(); KDSize inputSize = m_inputView.minimalSizeForOptimalDisplay(); m_inputView.setFrame(KDRect( - 0, - 0, + 0, 0, minCoordinate(maxFrameWidth, inputSize.width()), - inputSize.height() - )); + inputSize.height()), + force); KDSize outputSize = m_scrollableOutputView.minimalSizeForOptimalDisplay(); m_scrollableOutputView.setFrame(KDRect( maxCoordinate(0, maxFrameWidth - outputSize.width()), inputSize.height(), minCoordinate(maxFrameWidth, outputSize.width()), - outputSize.height() - )); + outputSize.height()), + force); } void HistoryViewCell::setCalculation(Calculation * calculation, bool expanded) { diff --git a/apps/calculation/history_view_cell.h b/apps/calculation/history_view_cell.h index e1c0f099d..80d9ee593 100644 --- a/apps/calculation/history_view_cell.h +++ b/apps/calculation/history_view_cell.h @@ -43,7 +43,7 @@ public: void setCalculation(Calculation * calculation, bool expanded = false); int numberOfSubviews() const override; View * subviewAtIndex(int index) override; - void layoutSubviews() override; + void layoutSubviews(bool force = false) override; void didBecomeFirstResponder() override; bool handleEvent(Ion::Events::Event event) override; Shared::ScrollableExactApproximateExpressionsView * outputView(); diff --git a/apps/code/console_edit_cell.cpp b/apps/code/console_edit_cell.cpp index e2472d8fe..d1b55c9d5 100644 --- a/apps/code/console_edit_cell.cpp +++ b/apps/code/console_edit_cell.cpp @@ -27,10 +27,10 @@ View * ConsoleEditCell::subviewAtIndex(int index) { } } -void ConsoleEditCell::layoutSubviews() { +void ConsoleEditCell::layoutSubviews(bool force) { KDSize promptSize = m_promptView.minimalSizeForOptimalDisplay(); - m_promptView.setFrame(KDRect(KDPointZero, promptSize.width(), bounds().height())); - m_textField.setFrame(KDRect(KDPoint(promptSize.width(), KDCoordinate(0)), bounds().width() - promptSize.width(), bounds().height())); + m_promptView.setFrame(KDRect(KDPointZero, promptSize.width(), bounds().height()), force); + m_textField.setFrame(KDRect(KDPoint(promptSize.width(), KDCoordinate(0)), bounds().width() - promptSize.width(), bounds().height()), force); } void ConsoleEditCell::didBecomeFirstResponder() { diff --git a/apps/code/console_edit_cell.h b/apps/code/console_edit_cell.h index e98cfba46..2d8fcabb1 100644 --- a/apps/code/console_edit_cell.h +++ b/apps/code/console_edit_cell.h @@ -16,7 +16,7 @@ public: // View int numberOfSubviews() const override; View * subviewAtIndex(int index) override; - void layoutSubviews() override; + void layoutSubviews(bool force = false) override; // Responder void didBecomeFirstResponder() override; diff --git a/apps/code/console_line_cell.cpp b/apps/code/console_line_cell.cpp index b0181b6a0..784875875 100644 --- a/apps/code/console_line_cell.cpp +++ b/apps/code/console_line_cell.cpp @@ -77,16 +77,16 @@ View * ConsoleLineCell::subviewAtIndex(int index) { return &m_scrollableView; } -void ConsoleLineCell::layoutSubviews() { +void ConsoleLineCell::layoutSubviews(bool force) { if (m_line.isCommand()) { KDSize promptSize = ConsoleController::k_font->stringSize(I18n::translate(I18n::Message::ConsolePrompt)); - m_promptView.setFrame(KDRect(KDPointZero, promptSize.width(), bounds().height())); - m_scrollableView.setFrame(KDRect(KDPoint(promptSize.width(), 0), bounds().width() - promptSize.width(), bounds().height())); + m_promptView.setFrame(KDRect(KDPointZero, promptSize.width(), bounds().height()), force); + m_scrollableView.setFrame(KDRect(KDPoint(promptSize.width(), 0), bounds().width() - promptSize.width(), bounds().height()), force); return; } assert(m_line.isResult()); - m_promptView.setFrame(KDRectZero); - m_scrollableView.setFrame(bounds()); + m_promptView.setFrame(KDRectZero, force); + m_scrollableView.setFrame(bounds(), force); } void ConsoleLineCell::didBecomeFirstResponder() { diff --git a/apps/code/console_line_cell.h b/apps/code/console_line_cell.h index 8cb3ef58a..8a740b913 100644 --- a/apps/code/console_line_cell.h +++ b/apps/code/console_line_cell.h @@ -30,7 +30,7 @@ public: /* View */ int numberOfSubviews() const override; View * subviewAtIndex(int index) override; - void layoutSubviews() override; + void layoutSubviews(bool force = false) override; /* Responder */ void didBecomeFirstResponder() override; diff --git a/apps/code/editor_view.cpp b/apps/code/editor_view.cpp index 4138b5221..23fcbf9c5 100644 --- a/apps/code/editor_view.cpp +++ b/apps/code/editor_view.cpp @@ -34,17 +34,17 @@ void EditorView::didBecomeFirstResponder() { Container::activeApp()->setFirstResponder(&m_textArea); } -void EditorView::layoutSubviews() { +void EditorView::layoutSubviews(bool force) { m_gutterView.setOffset(0); KDCoordinate gutterWidth = m_gutterView.minimalSizeForOptimalDisplay().width(); - m_gutterView.setFrame(KDRect(0, 0, gutterWidth, bounds().height())); + m_gutterView.setFrame(KDRect(0, 0, gutterWidth, bounds().height()), force); m_textArea.setFrame(KDRect( - gutterWidth, - 0, - bounds().width()-gutterWidth, - bounds().height() - )); + gutterWidth, + 0, + bounds().width()-gutterWidth, + bounds().height()), + force); } /* EditorView::GutterView */ diff --git a/apps/code/editor_view.h b/apps/code/editor_view.h index 7e4d85ece..817bc5218 100644 --- a/apps/code/editor_view.h +++ b/apps/code/editor_view.h @@ -26,7 +26,7 @@ public: private: int numberOfSubviews() const override; View * subviewAtIndex(int index) override; - void layoutSubviews() override; + void layoutSubviews(bool force = false) override; class GutterView : public View { public: diff --git a/apps/code/script_name_cell.cpp b/apps/code/script_name_cell.cpp index 26792e7f2..d451df130 100644 --- a/apps/code/script_name_cell.cpp +++ b/apps/code/script_name_cell.cpp @@ -29,12 +29,13 @@ void ScriptNameCell::didBecomeFirstResponder() { Container::activeApp()->setFirstResponder(&m_textField); } -void ScriptNameCell::layoutSubviews() { +void ScriptNameCell::layoutSubviews(bool force) { KDRect cellBounds = bounds(); m_textField.setFrame(KDRect(cellBounds.x() + k_leftMargin, cellBounds.y(), cellBounds.width() - k_leftMargin, - cellBounds.height())); + cellBounds.height()), + force); } } diff --git a/apps/code/script_name_cell.h b/apps/code/script_name_cell.h index ec9831bd8..dfa2c1d36 100644 --- a/apps/code/script_name_cell.h +++ b/apps/code/script_name_cell.h @@ -48,7 +48,7 @@ private: assert(index == 0); return &m_textField; } - void layoutSubviews() override; + void layoutSubviews(bool force = false) override; Shared::TextFieldWithExtension m_textField; char m_textBody[TextField::maxBufferSize()]; diff --git a/apps/exam_pop_up_controller.cpp b/apps/exam_pop_up_controller.cpp index dfe068ef2..79e73fd40 100644 --- a/apps/exam_pop_up_controller.cpp +++ b/apps/exam_pop_up_controller.cpp @@ -129,14 +129,14 @@ View * ExamPopUpController::ContentView::subviewAtIndex(int index) { } } -void ExamPopUpController::ContentView::layoutSubviews() { +void ExamPopUpController::ContentView::layoutSubviews(bool force) { KDCoordinate height = bounds().height(); KDCoordinate width = bounds().width(); KDCoordinate textHeight = KDFont::SmallFont->glyphSize().height(); - m_warningTextView.setFrame(KDRect(0, k_topMargin, width, textHeight)); - m_messageTextView1.setFrame(KDRect(0, k_topMargin+k_paragraphHeight+textHeight, width, textHeight)); - m_messageTextView2.setFrame(KDRect(0, k_topMargin+k_paragraphHeight+2*textHeight, width, textHeight)); - m_messageTextView3.setFrame(KDRect(0, k_topMargin+k_paragraphHeight+3*textHeight, width, textHeight)); - m_cancelButton.setFrame(KDRect(k_buttonMargin, height-k_buttonMargin-k_buttonHeight, (width-3*k_buttonMargin)/2, k_buttonHeight)); - m_okButton.setFrame(KDRect(2*k_buttonMargin+(width-3*k_buttonMargin)/2, height-k_buttonMargin-k_buttonHeight, (width-3*k_buttonMargin)/2, k_buttonHeight)); + m_warningTextView.setFrame(KDRect(0, k_topMargin, width, textHeight), force); + m_messageTextView1.setFrame(KDRect(0, k_topMargin+k_paragraphHeight+textHeight, width, textHeight), force); + m_messageTextView2.setFrame(KDRect(0, k_topMargin+k_paragraphHeight+2*textHeight, width, textHeight), force); + m_messageTextView3.setFrame(KDRect(0, k_topMargin+k_paragraphHeight+3*textHeight, width, textHeight), force); + m_cancelButton.setFrame(KDRect(k_buttonMargin, height-k_buttonMargin-k_buttonHeight, (width-3*k_buttonMargin)/2, k_buttonHeight), force); + m_okButton.setFrame(KDRect(2*k_buttonMargin+(width-3*k_buttonMargin)/2, height-k_buttonMargin-k_buttonHeight, (width-3*k_buttonMargin)/2, k_buttonHeight), force); } diff --git a/apps/exam_pop_up_controller.h b/apps/exam_pop_up_controller.h index 0249e9d3f..61a644a60 100644 --- a/apps/exam_pop_up_controller.h +++ b/apps/exam_pop_up_controller.h @@ -37,7 +37,7 @@ private: constexpr static KDCoordinate k_paragraphHeight = 20; int numberOfSubviews() const override; View * subviewAtIndex(int index) override; - void layoutSubviews() override; + void layoutSubviews(bool force = false) override; HighContrastButton m_cancelButton; HighContrastButton m_okButton; MessageTextView m_warningTextView; diff --git a/apps/graph/list/text_field_function_title_cell.cpp b/apps/graph/list/text_field_function_title_cell.cpp index ecd7a7567..a1d138e24 100644 --- a/apps/graph/list/text_field_function_title_cell.cpp +++ b/apps/graph/list/text_field_function_title_cell.cpp @@ -52,9 +52,9 @@ void TextFieldFunctionTitleCell::setHorizontalAlignment(float alignment) { m_textField.setAlignment(alignment, verticalAlignment()); } -void TextFieldFunctionTitleCell::layoutSubviews() { +void TextFieldFunctionTitleCell::layoutSubviews(bool force) { KDRect frame = subviewFrame(); - m_textField.setFrame(frame); + m_textField.setFrame(frame, force); KDCoordinate maxTextFieldX = frame.width() - m_textField.minimalSizeForOptimalDisplay().width(); float horizontalAlignment = maxFloat( 0.0f, diff --git a/apps/graph/list/text_field_function_title_cell.h b/apps/graph/list/text_field_function_title_cell.h index 0d2b95d9b..dd76523e5 100644 --- a/apps/graph/list/text_field_function_title_cell.h +++ b/apps/graph/list/text_field_function_title_cell.h @@ -34,7 +34,7 @@ public: assert(index == 0); return &m_textField; } - void layoutSubviews() override; + void layoutSubviews(bool force = false) override; // Responder void didBecomeFirstResponder() override; diff --git a/apps/graph/values/abscissa_title_cell.cpp b/apps/graph/values/abscissa_title_cell.cpp index bd174fccd..59ed57aa8 100644 --- a/apps/graph/values/abscissa_title_cell.cpp +++ b/apps/graph/values/abscissa_title_cell.cpp @@ -12,8 +12,8 @@ void AbscissaTitleCell::drawRect(KDContext * ctx, KDRect rect) const { } } -void AbscissaTitleCell::layoutSubviews() { - m_messageTextView.setFrame(rectWithoutSeparator(bounds())); +void AbscissaTitleCell::layoutSubviews(bool force) { + m_messageTextView.setFrame(rectWithoutSeparator(bounds()), force); } void AbscissaTitleCell::didSetSeparator() { diff --git a/apps/graph/values/abscissa_title_cell.h b/apps/graph/values/abscissa_title_cell.h index 6c786c638..fd1ca6f1a 100644 --- a/apps/graph/values/abscissa_title_cell.h +++ b/apps/graph/values/abscissa_title_cell.h @@ -10,7 +10,7 @@ class AbscissaTitleCell : public EvenOddMessageTextCell, public Shared::Separabl public: AbscissaTitleCell() : EvenOddMessageTextCell(), Separable() {} void drawRect(KDContext * ctx, KDRect rect) const override; - void layoutSubviews() override; + void layoutSubviews(bool force = false) override; private: void didSetSeparator() override; }; diff --git a/apps/graph/values/interval_parameter_selector_controller.cpp b/apps/graph/values/interval_parameter_selector_controller.cpp index 67c2f57a1..80cd68f74 100644 --- a/apps/graph/values/interval_parameter_selector_controller.cpp +++ b/apps/graph/values/interval_parameter_selector_controller.cpp @@ -20,7 +20,7 @@ void IntervalParameterSelectorController::viewDidDisappear() { /* Deselect the table properly because it needs to be relayouted the next time * it appears: the number of rows might change according to the plot type. */ m_selectableTableView.deselectTable(false); - m_selectableTableView.setFrame(KDRectZero); + m_selectableTableView.setFrame(KDRectZero, false); } void IntervalParameterSelectorController::didBecomeFirstResponder() { diff --git a/apps/hardware_test/battery_test_controller.cpp b/apps/hardware_test/battery_test_controller.cpp index 997a99ea1..37dbd6549 100644 --- a/apps/hardware_test/battery_test_controller.cpp +++ b/apps/hardware_test/battery_test_controller.cpp @@ -94,11 +94,11 @@ void BatteryTestController::ContentView::setColor(KDColor color) { m_batteryChargingView.setBackgroundColor(color); } -void BatteryTestController::ContentView::layoutSubviews() { - m_batteryStateView.setFrame(KDRect(0, 0, Ion::Display::Width, Ion::Display::Height/2)); +void BatteryTestController::ContentView::layoutSubviews(bool force) { + m_batteryStateView.setFrame(KDRect(0, 0, Ion::Display::Width, Ion::Display::Height/2), force); KDSize textSize = KDFont::SmallFont->glyphSize(); - m_batteryLevelView.setFrame(KDRect(0, Ion::Display::Height-2*textSize.height(), Ion::Display::Width, textSize.height())); - m_batteryChargingView.setFrame(KDRect(0, Ion::Display::Height-textSize.height(), Ion::Display::Width, textSize.height())); + m_batteryLevelView.setFrame(KDRect(0, Ion::Display::Height-2*textSize.height(), Ion::Display::Width, textSize.height()), force); + m_batteryChargingView.setFrame(KDRect(0, Ion::Display::Height-textSize.height(), Ion::Display::Width, textSize.height()), force); } int BatteryTestController::ContentView::numberOfSubviews() const { diff --git a/apps/hardware_test/battery_test_controller.h b/apps/hardware_test/battery_test_controller.h index 723155abb..2d30757ab 100644 --- a/apps/hardware_test/battery_test_controller.h +++ b/apps/hardware_test/battery_test_controller.h @@ -21,7 +21,7 @@ private: constexpr static int k_maxNumberOfCharacters = 20; void setColor(KDColor color) override; private: - void layoutSubviews() override; + void layoutSubviews(bool force = false) override; int numberOfSubviews() const override; View * subviewAtIndex(int index) override; constexpr static int k_margin = 4; diff --git a/apps/hardware_test/code_128b_view.cpp b/apps/hardware_test/code_128b_view.cpp index 75d011ab6..9d1a30636 100644 --- a/apps/hardware_test/code_128b_view.cpp +++ b/apps/hardware_test/code_128b_view.cpp @@ -20,7 +20,7 @@ void Code128BView::setData(const char * data) { markRectAsDirty(bounds()); } -void Code128BView::layoutSubviews() { +void Code128BView::layoutSubviews(bool force) { updateModuleWidth(); } diff --git a/apps/hardware_test/code_128b_view.h b/apps/hardware_test/code_128b_view.h index c437e8e27..a6894a946 100644 --- a/apps/hardware_test/code_128b_view.h +++ b/apps/hardware_test/code_128b_view.h @@ -10,7 +10,7 @@ public: Code128BView(); void drawRect(KDContext * ctx, KDRect rect) const override; void setData(const char * data); - void layoutSubviews() override; + void layoutSubviews(bool force = false) override; private: static constexpr KDCoordinate k_outlineThickness = 1; static constexpr KDCoordinate k_charPatternWidth = 11; diff --git a/apps/hardware_test/colors_lcd_test_controller.cpp b/apps/hardware_test/colors_lcd_test_controller.cpp index 25a14f535..cc2ce7f43 100644 --- a/apps/hardware_test/colors_lcd_test_controller.cpp +++ b/apps/hardware_test/colors_lcd_test_controller.cpp @@ -33,8 +33,8 @@ void ColorsLCDTestController::ContentView::setColor(KDColor color) { m_colorsLCDStateView.setBackgroundColor(color); } -void ColorsLCDTestController::ContentView::layoutSubviews() { - m_colorsLCDStateView.setFrame(KDRect(0, 0, Ion::Display::Width, Ion::Display::Height)); +void ColorsLCDTestController::ContentView::layoutSubviews(bool force) { + m_colorsLCDStateView.setFrame(KDRect(0, 0, Ion::Display::Width, Ion::Display::Height), force); } } diff --git a/apps/hardware_test/colors_lcd_test_controller.h b/apps/hardware_test/colors_lcd_test_controller.h index 91cd15e73..005b7a8d8 100644 --- a/apps/hardware_test/colors_lcd_test_controller.h +++ b/apps/hardware_test/colors_lcd_test_controller.h @@ -22,7 +22,7 @@ private: BufferTextView * colorsLCDStateTextView() { return &m_colorsLCDStateView; } void setColor(KDColor color) override; private: - void layoutSubviews() override; + void layoutSubviews(bool force = false) override; int numberOfSubviews() const override { return 1; } View * subviewAtIndex(int index) override { assert(index == 0); diff --git a/apps/hardware_test/lcd_data_test_controller.cpp b/apps/hardware_test/lcd_data_test_controller.cpp index fbc2cb364..06bbd81bf 100644 --- a/apps/hardware_test/lcd_data_test_controller.cpp +++ b/apps/hardware_test/lcd_data_test_controller.cpp @@ -46,9 +46,9 @@ void LCDDataTestController::ContentView::setStatus(bool success, int numberOfErr m_lcdNumberPixelFailuresView.setText(buffer); } -void LCDDataTestController::ContentView::layoutSubviews() { - m_lcdDataStateView.setFrame(KDRect(0, 0, Ion::Display::Width, Ion::Display::Height)); - m_lcdNumberPixelFailuresView.setFrame(KDRect(10, 10, Ion::Display::Width, 20)); +void LCDDataTestController::ContentView::layoutSubviews(bool force) { + m_lcdDataStateView.setFrame(KDRect(0, 0, Ion::Display::Width, Ion::Display::Height), force); + m_lcdNumberPixelFailuresView.setFrame(KDRect(10, 10, Ion::Display::Width, 20), force); } } diff --git a/apps/hardware_test/lcd_data_test_controller.h b/apps/hardware_test/lcd_data_test_controller.h index 2d261b3b6..507edaa8a 100644 --- a/apps/hardware_test/lcd_data_test_controller.h +++ b/apps/hardware_test/lcd_data_test_controller.h @@ -24,7 +24,7 @@ private: private: constexpr static const char * k_lcdDataPassTest = "LCD DATA: OK"; constexpr static const char * k_lcdDataFailTest = "LCD DATA: FAIL"; - void layoutSubviews() override; + void layoutSubviews(bool force = false) override; int numberOfSubviews() const override { return 2; } View * subviewAtIndex(int index) override { assert(index >= 0 && index < 2); diff --git a/apps/hardware_test/lcd_timing_test_controller.cpp b/apps/hardware_test/lcd_timing_test_controller.cpp index 61492a729..fbdb193cf 100644 --- a/apps/hardware_test/lcd_timing_test_controller.cpp +++ b/apps/hardware_test/lcd_timing_test_controller.cpp @@ -47,9 +47,9 @@ void LCDTimingTestController::ContentView::setStatus(bool success, int numberOfE m_lcdNumberGlyphFailuresView.setText(buffer); } -void LCDTimingTestController::ContentView::layoutSubviews() { - m_lcdTimingStateView.setFrame(KDRect(0, 0, Ion::Display::Width, Ion::Display::Height)); - m_lcdNumberGlyphFailuresView.setFrame(KDRect(10, 10, Ion::Display::Width, 20)); +void LCDTimingTestController::ContentView::layoutSubviews(bool force) { + m_lcdTimingStateView.setFrame(KDRect(0, 0, Ion::Display::Width, Ion::Display::Height), force); + m_lcdNumberGlyphFailuresView.setFrame(KDRect(10, 10, Ion::Display::Width, 20), force); } } diff --git a/apps/hardware_test/lcd_timing_test_controller.h b/apps/hardware_test/lcd_timing_test_controller.h index 17cfbf386..75bf7fccc 100644 --- a/apps/hardware_test/lcd_timing_test_controller.h +++ b/apps/hardware_test/lcd_timing_test_controller.h @@ -25,7 +25,7 @@ private: private: constexpr static const char * k_lcdTimingPassTest = "LCD TIMING: OK"; constexpr static const char * k_lcdTimingFailTest = "LCD TIMING: FAIL"; - void layoutSubviews() override; + void layoutSubviews(bool force = false) override; int numberOfSubviews() const override { return 2; } View * subviewAtIndex(int index) override { assert(index >= 0 && index < 2); diff --git a/apps/hardware_test/led_test_controller.cpp b/apps/hardware_test/led_test_controller.cpp index 07b3917b1..54c3ec549 100644 --- a/apps/hardware_test/led_test_controller.cpp +++ b/apps/hardware_test/led_test_controller.cpp @@ -58,12 +58,12 @@ SolidColorView * LEDTestController::ContentView::LEDColorIndicatorView() { return &m_ledColorIndicatorView; } -void LEDTestController::ContentView::layoutSubviews() { +void LEDTestController::ContentView::layoutSubviews(bool force) { KDSize ledSize = m_ledView.minimalSizeForOptimalDisplay(); - m_ledView.setFrame(KDRect((Ion::Display::Width-ledSize.width()-k_indicatorSize-k_indicatorMargin)/2, k_arrowLength+2*k_arrowMargin, ledSize.width(), ledSize.height())); - m_ledColorIndicatorView.setFrame(KDRect((Ion::Display::Width-k_indicatorSize)/2+k_indicatorMargin/2+ledSize.width()/2, k_arrowLength+2*k_arrowMargin, k_indicatorSize, k_indicatorSize)); - m_ledColorOutlineView.setFrame(KDRect((Ion::Display::Width-k_indicatorSize)/2+k_indicatorMargin/2+ledSize.width()/2-1, k_arrowLength+2*k_arrowMargin-1, k_indicatorSize+2, k_indicatorSize+2)); - m_arrowView.setFrame(KDRect(0, k_arrowMargin, bounds().width(), k_arrowLength)); + m_ledView.setFrame(KDRect((Ion::Display::Width-ledSize.width()-k_indicatorSize-k_indicatorMargin)/2, k_arrowLength+2*k_arrowMargin, ledSize.width(), ledSize.height()), force); + m_ledColorIndicatorView.setFrame(KDRect((Ion::Display::Width-k_indicatorSize)/2+k_indicatorMargin/2+ledSize.width()/2, k_arrowLength+2*k_arrowMargin, k_indicatorSize, k_indicatorSize), force); + m_ledColorOutlineView.setFrame(KDRect((Ion::Display::Width-k_indicatorSize)/2+k_indicatorMargin/2+ledSize.width()/2-1, k_arrowLength+2*k_arrowMargin-1, k_indicatorSize+2, k_indicatorSize+2), force); + m_arrowView.setFrame(KDRect(0, k_arrowMargin, bounds().width(), k_arrowLength), force); } int LEDTestController::ContentView::numberOfSubviews() const { diff --git a/apps/hardware_test/led_test_controller.h b/apps/hardware_test/led_test_controller.h index 92d74ed0b..6c339f206 100644 --- a/apps/hardware_test/led_test_controller.h +++ b/apps/hardware_test/led_test_controller.h @@ -18,7 +18,7 @@ private: ContentView(); SolidColorView * LEDColorIndicatorView(); private: - void layoutSubviews() override; + void layoutSubviews(bool force = false) override; int numberOfSubviews() const override; View * subviewAtIndex(int index) override; SolidColorView m_ledColorIndicatorView; diff --git a/apps/hardware_test/pop_up_controller.cpp b/apps/hardware_test/pop_up_controller.cpp index 24a0592b5..76afaa19b 100644 --- a/apps/hardware_test/pop_up_controller.cpp +++ b/apps/hardware_test/pop_up_controller.cpp @@ -100,17 +100,17 @@ View * PopUpController::ContentView::subviewAtIndex(int index) { } } -void PopUpController::ContentView::layoutSubviews() { +void PopUpController::ContentView::layoutSubviews(bool force) { KDCoordinate height = bounds().height(); KDCoordinate width = bounds().width(); KDCoordinate textHeight = KDFont::SmallFont->glyphSize().height(); - m_warningTextView.setFrame(KDRect(0, k_topMargin, width, textHeight)); - m_messageTextView1.setFrame(KDRect(0, k_topMargin+k_paragraphHeight+textHeight, width, textHeight)); - m_messageTextView2.setFrame(KDRect(0, k_topMargin+k_paragraphHeight+2*textHeight, width, textHeight)); - m_messageTextView3.setFrame(KDRect(0, k_topMargin+k_paragraphHeight+3*textHeight, width, textHeight)); - m_messageTextView4.setFrame(KDRect(0, k_topMargin+k_paragraphHeight+4*textHeight, width, textHeight)); - m_cancelButton.setFrame(KDRect(k_buttonMargin, height-k_buttonMargin-k_buttonHeight, (width-3*k_buttonMargin)/2, k_buttonHeight)); - m_okButton.setFrame(KDRect(2*k_buttonMargin+(width-3*k_buttonMargin)/2, height-k_buttonMargin-k_buttonHeight, (width-3*k_buttonMargin)/2, k_buttonHeight)); + m_warningTextView.setFrame(KDRect(0, k_topMargin, width, textHeight), force); + m_messageTextView1.setFrame(KDRect(0, k_topMargin+k_paragraphHeight+textHeight, width, textHeight), force); + m_messageTextView2.setFrame(KDRect(0, k_topMargin+k_paragraphHeight+2*textHeight, width, textHeight), force); + m_messageTextView3.setFrame(KDRect(0, k_topMargin+k_paragraphHeight+3*textHeight, width, textHeight), force); + m_messageTextView4.setFrame(KDRect(0, k_topMargin+k_paragraphHeight+4*textHeight, width, textHeight), force); + m_cancelButton.setFrame(KDRect(k_buttonMargin, height-k_buttonMargin-k_buttonHeight, (width-3*k_buttonMargin)/2, k_buttonHeight), force); + m_okButton.setFrame(KDRect(2*k_buttonMargin+(width-3*k_buttonMargin)/2, height-k_buttonMargin-k_buttonHeight, (width-3*k_buttonMargin)/2, k_buttonHeight), force); } } diff --git a/apps/hardware_test/pop_up_controller.h b/apps/hardware_test/pop_up_controller.h index bdaa8f1ee..b04724e95 100644 --- a/apps/hardware_test/pop_up_controller.h +++ b/apps/hardware_test/pop_up_controller.h @@ -25,7 +25,7 @@ private: constexpr static KDCoordinate k_paragraphHeight = 20; int numberOfSubviews() const override; View * subviewAtIndex(int index) override; - void layoutSubviews() override; + void layoutSubviews(bool force = false) override; Button m_cancelButton; Button m_okButton; MessageTextView m_warningTextView; diff --git a/apps/hardware_test/vblank_test_controller.cpp b/apps/hardware_test/vblank_test_controller.cpp index 9736c921c..57845dfa7 100644 --- a/apps/hardware_test/vblank_test_controller.cpp +++ b/apps/hardware_test/vblank_test_controller.cpp @@ -33,8 +33,8 @@ void VBlankTestController::ContentView::setColor(KDColor color) { m_vBlankStateView.setBackgroundColor(color); } -void VBlankTestController::ContentView::layoutSubviews() { - m_vBlankStateView.setFrame(KDRect(0, 0, Ion::Display::Width, Ion::Display::Height)); +void VBlankTestController::ContentView::layoutSubviews(bool force) { + m_vBlankStateView.setFrame(KDRect(0, 0, Ion::Display::Width, Ion::Display::Height), force); } } diff --git a/apps/hardware_test/vblank_test_controller.h b/apps/hardware_test/vblank_test_controller.h index 951394586..f13bae303 100644 --- a/apps/hardware_test/vblank_test_controller.h +++ b/apps/hardware_test/vblank_test_controller.h @@ -22,7 +22,7 @@ private: BufferTextView * vBlankStateTextView() { return &m_vBlankStateView; } void setColor(KDColor color) override; private: - void layoutSubviews() override; + void layoutSubviews(bool force = false) override; int numberOfSubviews() const override { return 1; } View * subviewAtIndex(int index) override { assert(index == 0); diff --git a/apps/home/app_cell.cpp b/apps/home/app_cell.cpp index 1b2c1ad8c..cb2875589 100644 --- a/apps/home/app_cell.cpp +++ b/apps/home/app_cell.cpp @@ -25,10 +25,10 @@ View * AppCell::subviewAtIndex(int index) { return views[index]; } -void AppCell::layoutSubviews() { - m_iconView.setFrame(KDRect((bounds().width()-k_iconWidth)/2, k_iconMargin, k_iconWidth,k_iconHeight)); +void AppCell::layoutSubviews(bool force) { + m_iconView.setFrame(KDRect((bounds().width()-k_iconWidth)/2, k_iconMargin, k_iconWidth,k_iconHeight), force); KDSize nameSize = m_nameView.minimalSizeForOptimalDisplay(); - m_nameView.setFrame(KDRect((bounds().width()-nameSize.width())/2-k_nameWidthMargin, bounds().height()-nameSize.height() - 2*k_nameHeightMargin, nameSize.width()+2*k_nameWidthMargin, nameSize.height()+2*k_nameHeightMargin)); + m_nameView.setFrame(KDRect((bounds().width()-nameSize.width())/2-k_nameWidthMargin, bounds().height()-nameSize.height() - 2*k_nameHeightMargin, nameSize.width()+2*k_nameWidthMargin, nameSize.height()+2*k_nameHeightMargin), force); } void AppCell::setAppDescriptor(::App::Descriptor * descriptor) { diff --git a/apps/home/app_cell.h b/apps/home/app_cell.h index 19dabf6fe..73cb7e0f9 100644 --- a/apps/home/app_cell.h +++ b/apps/home/app_cell.h @@ -12,7 +12,7 @@ public: int numberOfSubviews() const override; View * subviewAtIndex(int index) override; - void layoutSubviews() override; + void layoutSubviews(bool force = false) override; void setVisible(bool visible); void reloadCell() override; diff --git a/apps/home/controller.cpp b/apps/home/controller.cpp index 00c2f287a..c6fa7bdcf 100644 --- a/apps/home/controller.cpp +++ b/apps/home/controller.cpp @@ -45,8 +45,8 @@ View * Controller::ContentView::subviewAtIndex(int index) { return &m_selectableTableView; } -void Controller::ContentView::layoutSubviews() { - m_selectableTableView.setFrame(bounds()); +void Controller::ContentView::layoutSubviews(bool force) { + m_selectableTableView.setFrame(bounds(), force); } Controller::Controller(Responder * parentResponder, SelectableTableViewDataSource * selectionDataSource) : diff --git a/apps/home/controller.h b/apps/home/controller.h index 4c354bfb5..363b2d93d 100644 --- a/apps/home/controller.h +++ b/apps/home/controller.h @@ -36,7 +36,7 @@ private: private: int numberOfSubviews() const override; View * subviewAtIndex(int index) override; - void layoutSubviews() override; + void layoutSubviews(bool force = false) override; SelectableTableView m_selectableTableView; }; static constexpr KDCoordinate k_sideMargin = 4; diff --git a/apps/on_boarding/logo_view.cpp b/apps/on_boarding/logo_view.cpp index 2756012b0..dd76b95b9 100644 --- a/apps/on_boarding/logo_view.cpp +++ b/apps/on_boarding/logo_view.cpp @@ -23,8 +23,8 @@ View * LogoView::subviewAtIndex(int index) { return &m_logoView; } -void LogoView::layoutSubviews() { - m_logoView.setFrame(KDRect((Ion::Display::Width - ImageStore::LogoIcon->width())/2, (Ion::Display::Height - ImageStore::LogoIcon->height())/2, ImageStore::LogoIcon->width(), ImageStore::LogoIcon->height())); +void LogoView::layoutSubviews(bool force) { + m_logoView.setFrame(KDRect((Ion::Display::Width - ImageStore::LogoIcon->width())/2, (Ion::Display::Height - ImageStore::LogoIcon->height())/2, ImageStore::LogoIcon->width(), ImageStore::LogoIcon->height()), force); } } diff --git a/apps/on_boarding/logo_view.h b/apps/on_boarding/logo_view.h index b1d1650d5..7cbfc62a6 100644 --- a/apps/on_boarding/logo_view.h +++ b/apps/on_boarding/logo_view.h @@ -12,7 +12,7 @@ public: private: int numberOfSubviews() const override; View * subviewAtIndex(int index) override; - void layoutSubviews() override; + void layoutSubviews(bool force = false) override; ImageView m_logoView; }; diff --git a/apps/on_boarding/pop_up_controller.cpp b/apps/on_boarding/pop_up_controller.cpp index 4a057a2b4..c63328b9e 100644 --- a/apps/on_boarding/pop_up_controller.cpp +++ b/apps/on_boarding/pop_up_controller.cpp @@ -30,7 +30,7 @@ View * PopUpController::MessageViewWithSkip::subviewAtIndex(int index) { return nullptr; } -void PopUpController::MessageViewWithSkip::layoutSubviews() { +void PopUpController::MessageViewWithSkip::layoutSubviews(bool force) { // Layout the main message MessageView::layoutSubviews(); // Layout the "skip (OK)" @@ -38,8 +38,8 @@ void PopUpController::MessageViewWithSkip::layoutSubviews() { KDCoordinate width = bounds().width(); KDCoordinate textHeight = KDFont::SmallFont->glyphSize().height(); KDSize okSize = m_okView.minimalSizeForOptimalDisplay(); - m_skipView.setFrame(KDRect(0, height-k_bottomMargin-textHeight, width-okSize.width()-k_okMargin-k_skipMargin, textHeight)); - m_okView.setFrame(KDRect(width - okSize.width()-k_okMargin, height-okSize.height()-k_okMargin, okSize)); + m_skipView.setFrame(KDRect(0, height-k_bottomMargin-textHeight, width-okSize.width()-k_okMargin-k_skipMargin, textHeight), force); + m_okView.setFrame(KDRect(width - okSize.width()-k_okMargin, height-okSize.height()-k_okMargin, okSize), force); } PopUpController::PopUpController(I18n::Message * messages, KDColor * colors, uint8_t numberOfMessages) : diff --git a/apps/on_boarding/pop_up_controller.h b/apps/on_boarding/pop_up_controller.h index 9f1b3d78b..f092e8853 100644 --- a/apps/on_boarding/pop_up_controller.h +++ b/apps/on_boarding/pop_up_controller.h @@ -20,7 +20,7 @@ private: protected: int numberOfSubviews() const override; View * subviewAtIndex(int index) override; - void layoutSubviews() override; + void layoutSubviews(bool force = false) override; private: constexpr static KDCoordinate k_bottomMargin = 13; constexpr static KDCoordinate k_okMargin = 10; diff --git a/apps/probability/calculation_cell.cpp b/apps/probability/calculation_cell.cpp index ed1981723..d073fd537 100644 --- a/apps/probability/calculation_cell.cpp +++ b/apps/probability/calculation_cell.cpp @@ -67,10 +67,10 @@ View * CalculationCell::subviewAtIndex(int index) { return &m_calculation; } -void CalculationCell::layoutSubviews() { +void CalculationCell::layoutSubviews(bool force) { KDSize textSize = m_text.minimalSizeForOptimalDisplay(); - m_text.setFrame(KDRect(k_margin, 0, textSize.width(), bounds().height())); - m_calculation.setFrame(KDRect(2*k_margin+textSize.width()+ResponderImageCell::k_outline, ResponderImageCell::k_outline, calculationCellWidth(), ImageCell::k_height)); + m_text.setFrame(KDRect(k_margin, 0, textSize.width(), bounds().height()), force); + m_calculation.setFrame(KDRect(2*k_margin+textSize.width()+ResponderImageCell::k_outline, ResponderImageCell::k_outline, calculationCellWidth(), ImageCell::k_height), force); } KDCoordinate CalculationCell::calculationCellWidth() const { diff --git a/apps/probability/calculation_cell.h b/apps/probability/calculation_cell.h index f9432d895..7b78f46ea 100644 --- a/apps/probability/calculation_cell.h +++ b/apps/probability/calculation_cell.h @@ -22,7 +22,7 @@ private: constexpr static KDCoordinate k_margin = 5; int numberOfSubviews() const override; View * subviewAtIndex(int index) override; - void layoutSubviews() override; + void layoutSubviews(bool force = false) override; KDCoordinate calculationCellWidth() const; MessageTextView m_text; EditableTextCell m_calculation; diff --git a/apps/probability/calculation_controller.cpp b/apps/probability/calculation_controller.cpp index 1c2a1b097..a19c66ba8 100644 --- a/apps/probability/calculation_controller.cpp +++ b/apps/probability/calculation_controller.cpp @@ -46,12 +46,12 @@ View * CalculationController::ContentView::subviewAtIndex(int index) { return &m_distributionCurveView; } -void CalculationController::ContentView::layoutSubviews() { +void CalculationController::ContentView::layoutSubviews(bool force) { KDCoordinate titleHeight = KDFont::SmallFont->glyphSize().height()+k_titleHeightMargin; - m_titleView.setFrame(KDRect(0, 0, bounds().width(), titleHeight)); + m_titleView.setFrame(KDRect(0, 0, bounds().width(), titleHeight), force); KDCoordinate calculationHeight = ResponderImageCell::k_oneCellHeight+2*k_tableMargin; - m_selectableTableView->setFrame(KDRect(0, titleHeight, bounds().width(), calculationHeight)); - m_distributionCurveView.setFrame(KDRect(0, titleHeight+calculationHeight, bounds().width(), bounds().height() - calculationHeight - titleHeight)); + m_selectableTableView->setFrame(KDRect(0, titleHeight, bounds().width(), calculationHeight), force); + m_distributionCurveView.setFrame(KDRect(0, titleHeight+calculationHeight, bounds().width(), bounds().height() - calculationHeight - titleHeight), force); } CalculationController::CalculationController(Responder * parentResponder, InputEventHandlerDelegate * inputEventHandlerDelegate, Distribution * distribution, Calculation * calculation) : diff --git a/apps/probability/calculation_controller.h b/apps/probability/calculation_controller.h index 4c49dd9a0..77484a364 100644 --- a/apps/probability/calculation_controller.h +++ b/apps/probability/calculation_controller.h @@ -58,7 +58,7 @@ private: constexpr static KDCoordinate k_titleHeightMargin = 5; int numberOfSubviews() const override; View * subviewAtIndex(int index) override; - void layoutSubviews() override; + void layoutSubviews(bool force = false) override; MessageTextView m_titleView; SelectableTableView * m_selectableTableView; DistributionCurveView m_distributionCurveView; diff --git a/apps/probability/cell.cpp b/apps/probability/cell.cpp index a78a116f2..5e9a80b03 100644 --- a/apps/probability/cell.cpp +++ b/apps/probability/cell.cpp @@ -26,12 +26,12 @@ View * Cell::subviewAtIndex(int index) { return &m_chevronView; } -void Cell::layoutSubviews() { +void Cell::layoutSubviews(bool force) { KDCoordinate width = bounds().width(); KDCoordinate height = bounds().height(); - m_labelView.setFrame(KDRect(1+k_iconWidth+2*k_iconMargin, 1, width-2-k_iconWidth-2*k_iconMargin - k_chevronWidth, height-2)); - m_iconView.setFrame(KDRect(1+k_iconMargin, (height - k_iconHeight)/2, k_iconWidth, k_iconHeight)); - m_chevronView.setFrame(KDRect(width-1-k_chevronWidth-k_chevronMargin, 1, k_chevronWidth, height - 2)); + m_labelView.setFrame(KDRect(1+k_iconWidth+2*k_iconMargin, 1, width-2-k_iconWidth-2*k_iconMargin - k_chevronWidth, height-2), force); + m_iconView.setFrame(KDRect(1+k_iconMargin, (height - k_iconHeight)/2, k_iconWidth, k_iconHeight), force); + m_chevronView.setFrame(KDRect(width-1-k_chevronWidth-k_chevronMargin, 1, k_chevronWidth, height - 2), force); } void Cell::reloadCell() { diff --git a/apps/probability/cell.h b/apps/probability/cell.h index ef692b573..ef980f38d 100644 --- a/apps/probability/cell.h +++ b/apps/probability/cell.h @@ -20,7 +20,7 @@ private: constexpr static KDCoordinate k_chevronMargin = 10; int numberOfSubviews() const override; View * subviewAtIndex(int index) override; - void layoutSubviews() override; + void layoutSubviews(bool force = false) override; MessageTextView m_labelView; ImageView m_iconView; /* TODO: One day, we would rather store a mask (8bits/pixel) instead of two diff --git a/apps/probability/distribution_controller.cpp b/apps/probability/distribution_controller.cpp index ec89a49ac..0ceabf157 100644 --- a/apps/probability/distribution_controller.cpp +++ b/apps/probability/distribution_controller.cpp @@ -47,10 +47,10 @@ View * DistributionController::ContentView::subviewAtIndex(int index) { return m_selectableTableView; } -void DistributionController::ContentView::layoutSubviews() { +void DistributionController::ContentView::layoutSubviews(bool force) { KDCoordinate titleHeight = KDFont::SmallFont->glyphSize().height()+k_titleMargin; - m_titleView.setFrame(KDRect(0, 0, bounds().width(), titleHeight)); - m_selectableTableView->setFrame(KDRect(0, titleHeight, bounds().width(), bounds().height()-titleHeight)); + m_titleView.setFrame(KDRect(0, 0, bounds().width(), titleHeight), force); + m_selectableTableView->setFrame(KDRect(0, titleHeight, bounds().width(), bounds().height()-titleHeight), force); } static I18n::Message sMessages[] = { diff --git a/apps/probability/distribution_controller.h b/apps/probability/distribution_controller.h index d81fca8c7..580f55a36 100644 --- a/apps/probability/distribution_controller.h +++ b/apps/probability/distribution_controller.h @@ -29,7 +29,7 @@ private: private: int numberOfSubviews() const override; View * subviewAtIndex(int index) override; - void layoutSubviews() override; + void layoutSubviews(bool force = false) override; MessageTextView m_titleView;; SelectableTableView * m_selectableTableView; }; diff --git a/apps/probability/image_cell.cpp b/apps/probability/image_cell.cpp index dae9db792..abe33fe05 100644 --- a/apps/probability/image_cell.cpp +++ b/apps/probability/image_cell.cpp @@ -35,8 +35,8 @@ View * ImageCell::subviewAtIndex(int index) { return &m_iconView; } -void ImageCell::layoutSubviews() { - m_iconView.setFrame(bounds()); +void ImageCell::layoutSubviews(bool force) { + m_iconView.setFrame(bounds(), force); } } diff --git a/apps/probability/image_cell.h b/apps/probability/image_cell.h index bb65869c4..24daee8e8 100644 --- a/apps/probability/image_cell.h +++ b/apps/probability/image_cell.h @@ -15,7 +15,7 @@ public: private: int numberOfSubviews() const override; View * subviewAtIndex(int index) override; - void layoutSubviews() override; + void layoutSubviews(bool force = false) override; ImageView m_iconView; const Image * m_icon; const Image * m_focusedIcon; diff --git a/apps/probability/parameters_controller.cpp b/apps/probability/parameters_controller.cpp index 3d655dd69..dbafded4a 100644 --- a/apps/probability/parameters_controller.cpp +++ b/apps/probability/parameters_controller.cpp @@ -50,19 +50,19 @@ View * ParametersController::ContentView::subviewAtIndex(int index) { return &m_secondParameterDefinition; } -void ParametersController::ContentView::layoutSubviews() { +void ParametersController::ContentView::layoutSubviews(bool force) { KDCoordinate titleHeight = KDFont::SmallFont->glyphSize().height()+k_titleMargin; - m_titleView.setFrame(KDRect(0, 0, bounds().width(), titleHeight)); + m_titleView.setFrame(KDRect(0, 0, bounds().width(), titleHeight), force); KDCoordinate tableHeight = m_selectableTableView->minimalSizeForOptimalDisplay().height(); - m_selectableTableView->setFrame(KDRect(0, titleHeight, bounds().width(), tableHeight)); + m_selectableTableView->setFrame(KDRect(0, titleHeight, bounds().width(), tableHeight), force); KDCoordinate textHeight = KDFont::SmallFont->glyphSize().height(); KDCoordinate defOrigin = (titleHeight+tableHeight)/2+(bounds().height()-textHeight)/2; - m_secondParameterDefinition.setFrame(KDRectZero); + m_secondParameterDefinition.setFrame(KDRectZero, force); if (m_numberOfParameters == 2) { defOrigin = (titleHeight+tableHeight)/2+(bounds().height()-2*textHeight-k_textMargin)/2; - m_secondParameterDefinition.setFrame(KDRect(0, defOrigin+textHeight+k_textMargin, bounds().width(), textHeight)); + m_secondParameterDefinition.setFrame(KDRect(0, defOrigin+textHeight+k_textMargin, bounds().width(), textHeight), force); } - m_firstParameterDefinition.setFrame(KDRect(0, defOrigin, bounds().width(), textHeight)); + m_firstParameterDefinition.setFrame(KDRect(0, defOrigin, bounds().width(), textHeight), force); } /* Parameters Controller */ diff --git a/apps/probability/parameters_controller.h b/apps/probability/parameters_controller.h index 390b3099d..86e92f9cb 100644 --- a/apps/probability/parameters_controller.h +++ b/apps/probability/parameters_controller.h @@ -31,7 +31,7 @@ private: ContentView(Responder * parentResponder, SelectableTableView * selectableTableView); void drawRect(KDContext * ctx, KDRect rect) const override; MessageTextView * parameterDefinitionAtIndex(int index); - void layoutSubviews() override; + void layoutSubviews(bool force = false) override; void setNumberOfParameters(int numberOfParameters); private: constexpr static KDCoordinate k_textMargin = 5; diff --git a/apps/probability/responder_image_cell.cpp b/apps/probability/responder_image_cell.cpp index a23b65309..263c9369d 100644 --- a/apps/probability/responder_image_cell.cpp +++ b/apps/probability/responder_image_cell.cpp @@ -46,8 +46,8 @@ View * ResponderImageCell::subviewAtIndex(int index) { return &m_imageCell; } -void ResponderImageCell::layoutSubviews() { - m_imageCell.setFrame(KDRect(k_outline, k_outline, bounds().width()-2*k_outline, bounds().height()-2*k_outline)); +void ResponderImageCell::layoutSubviews(bool force) { + m_imageCell.setFrame(KDRect(k_outline, k_outline, bounds().width()-2*k_outline, bounds().height()-2*k_outline), force); } } diff --git a/apps/probability/responder_image_cell.h b/apps/probability/responder_image_cell.h index acb8ad584..88341f0c7 100644 --- a/apps/probability/responder_image_cell.h +++ b/apps/probability/responder_image_cell.h @@ -25,7 +25,7 @@ public: private: int numberOfSubviews() const override; View * subviewAtIndex(int index) override; - void layoutSubviews() override; + void layoutSubviews(bool force = false) override; ImageCell m_imageCell; CalculationTypeController m_calculationTypeController; }; diff --git a/apps/regression/column_title_cell.cpp b/apps/regression/column_title_cell.cpp index 3a97fb4da..a858715cf 100644 --- a/apps/regression/column_title_cell.cpp +++ b/apps/regression/column_title_cell.cpp @@ -14,11 +14,11 @@ void ColumnTitleCell::drawRect(KDContext * ctx, KDRect rect) const { ctx->fillRect(KDRect(Metric::TableSeparatorThickness, 0, bounds().width(), k_colorIndicatorThickness), m_functionColor); } -void ColumnTitleCell::layoutSubviews() { +void ColumnTitleCell::layoutSubviews(bool force) { KDCoordinate width = bounds().width() - Metric::TableSeparatorThickness; KDCoordinate height = bounds().height(); - m_firstBufferTextView.setFrame(KDRect(Metric::TableSeparatorThickness, k_colorIndicatorThickness, width/2, height - k_colorIndicatorThickness)); - m_secondBufferTextView.setFrame(KDRect(Metric::TableSeparatorThickness + width/2, k_colorIndicatorThickness, width - width/2, height - k_colorIndicatorThickness)); + m_firstBufferTextView.setFrame(KDRect(Metric::TableSeparatorThickness, k_colorIndicatorThickness, width/2, height - k_colorIndicatorThickness), force); + m_secondBufferTextView.setFrame(KDRect(Metric::TableSeparatorThickness + width/2, k_colorIndicatorThickness, width - width/2, height - k_colorIndicatorThickness), force); } } diff --git a/apps/regression/column_title_cell.h b/apps/regression/column_title_cell.h index fa85817a1..d0a14ca49 100644 --- a/apps/regression/column_title_cell.h +++ b/apps/regression/column_title_cell.h @@ -14,7 +14,7 @@ public: } virtual void setColor(KDColor color); void drawRect(KDContext * ctx, KDRect rect) const override; - void layoutSubviews() override; + void layoutSubviews(bool force = false) override; private: constexpr static KDCoordinate k_colorIndicatorThickness = 2; KDColor m_functionColor; diff --git a/apps/regression/even_odd_double_buffer_text_cell_with_separator.cpp b/apps/regression/even_odd_double_buffer_text_cell_with_separator.cpp index 96fbe5b25..e87e506b7 100644 --- a/apps/regression/even_odd_double_buffer_text_cell_with_separator.cpp +++ b/apps/regression/even_odd_double_buffer_text_cell_with_separator.cpp @@ -88,11 +88,11 @@ View * EvenOddDoubleBufferTextCellWithSeparator::subviewAtIndex(int index) { return &m_secondBufferTextView; } -void EvenOddDoubleBufferTextCellWithSeparator::layoutSubviews() { +void EvenOddDoubleBufferTextCellWithSeparator::layoutSubviews(bool force) { KDCoordinate width = bounds().width() - Metric::TableSeparatorThickness; KDCoordinate height = bounds().height(); - m_firstBufferTextView.setFrame(KDRect(Metric::TableSeparatorThickness, 0, width/2, height)); - m_secondBufferTextView.setFrame(KDRect(Metric::TableSeparatorThickness + width/2, 0, width - width/2, height)); + m_firstBufferTextView.setFrame(KDRect(Metric::TableSeparatorThickness, 0, width/2, height), force); + m_secondBufferTextView.setFrame(KDRect(Metric::TableSeparatorThickness + width/2, 0, width - width/2, height), force); } bool EvenOddDoubleBufferTextCellWithSeparator::handleEvent(Ion::Events::Event event) { diff --git a/apps/regression/even_odd_double_buffer_text_cell_with_separator.h b/apps/regression/even_odd_double_buffer_text_cell_with_separator.h index 8f7c8c260..7e263eae3 100644 --- a/apps/regression/even_odd_double_buffer_text_cell_with_separator.h +++ b/apps/regression/even_odd_double_buffer_text_cell_with_separator.h @@ -25,7 +25,7 @@ public: void drawRect(KDContext * ctx, KDRect rect) const override; int numberOfSubviews() const override; View * subviewAtIndex(int index) override; - void layoutSubviews() override; + void layoutSubviews(bool force = false) override; bool handleEvent(Ion::Events::Event event) override; protected: bool m_firstTextSelected; diff --git a/apps/sequence/sequence_title_cell.cpp b/apps/sequence/sequence_title_cell.cpp index e2357959d..f1802b10a 100644 --- a/apps/sequence/sequence_title_cell.cpp +++ b/apps/sequence/sequence_title_cell.cpp @@ -52,11 +52,11 @@ View * SequenceTitleCell::subviewAtIndex(int index) { return &m_titleTextView; } -void SequenceTitleCell::layoutSubviews() { +void SequenceTitleCell::layoutSubviews(bool force) { if (m_orientation == Orientation::VerticalIndicator) { m_titleTextView.setAlignment(k_verticalOrientationHorizontalAlignment, verticalAlignment()); } - m_titleTextView.setFrame(subviewFrame()); + m_titleTextView.setFrame(subviewFrame(), force); } float SequenceTitleCell::verticalAlignmentGivenExpressionBaselineAndRowHeight(KDCoordinate expressionBaseline, KDCoordinate rowHeight) const { diff --git a/apps/sequence/sequence_title_cell.h b/apps/sequence/sequence_title_cell.h index bcebbd4a9..b858fe1a0 100644 --- a/apps/sequence/sequence_title_cell.h +++ b/apps/sequence/sequence_title_cell.h @@ -25,7 +25,7 @@ private: static constexpr float k_verticalOrientationHorizontalAlignment = 0.9f; int numberOfSubviews() const override; View * subviewAtIndex(int index) override; - void layoutSubviews() override; + void layoutSubviews(bool force = false) override; float verticalAlignmentGivenExpressionBaselineAndRowHeight(KDCoordinate expressionBaseline, KDCoordinate rowHeight) const override; EvenOddExpressionCell m_titleTextView; }; diff --git a/apps/settings/sub_menu/message_table_cell_with_editable_text_with_separator.cpp b/apps/settings/sub_menu/message_table_cell_with_editable_text_with_separator.cpp index 44cf13d25..4057f005c 100644 --- a/apps/settings/sub_menu/message_table_cell_with_editable_text_with_separator.cpp +++ b/apps/settings/sub_menu/message_table_cell_with_editable_text_with_separator.cpp @@ -27,8 +27,8 @@ View * MessageTableCellWithEditableTextWithSeparator::subviewAtIndex(int index) return &m_cell; } -void MessageTableCellWithEditableTextWithSeparator::layoutSubviews() { - m_cell.setFrame(KDRect(0, k_margin, bounds().width(), bounds().height()-k_margin)); +void MessageTableCellWithEditableTextWithSeparator::layoutSubviews(bool force) { + m_cell.setFrame(KDRect(0, k_margin, bounds().width(), bounds().height()-k_margin), force); } } diff --git a/apps/settings/sub_menu/message_table_cell_with_editable_text_with_separator.h b/apps/settings/sub_menu/message_table_cell_with_editable_text_with_separator.h index 148da96e5..49e2c8ef0 100644 --- a/apps/settings/sub_menu/message_table_cell_with_editable_text_with_separator.h +++ b/apps/settings/sub_menu/message_table_cell_with_editable_text_with_separator.h @@ -20,7 +20,7 @@ private: constexpr static KDCoordinate k_separatorThickness = Metric::CellSeparatorThickness; int numberOfSubviews() const override; View * subviewAtIndex(int index) override; - void layoutSubviews() override; + void layoutSubviews(bool force = false) override; MessageTableCellWithEditableText m_cell; }; diff --git a/apps/shared/banner_view.cpp b/apps/shared/banner_view.cpp index 3bbd4d4ab..40d89738f 100644 --- a/apps/shared/banner_view.cpp +++ b/apps/shared/banner_view.cpp @@ -24,7 +24,7 @@ KDCoordinate BannerView::minimalHeightForOptimalDisplayGivenWidth(KDCoordinate w return HeightGivenNumberOfLines(numberOfLinesGivenWidth(width)); } -void BannerView::layoutSubviews() { +void BannerView::layoutSubviews(bool force) { if (m_frame.isEmpty()) { /* If the frame has not been set yet, there is no point in layouting the * subviews. @@ -52,7 +52,7 @@ void BannerView::layoutSubviews() { subviewPreviousLine = subviewAtIndex(j); KDCoordinate width = subviewPreviousLine->minimalSizeForOptimalDisplay().width() + remainingWidth/nbOfSubviewsOnLine + (j == i-1) * roundingError; KDCoordinate height = subviewPreviousLine->minimalSizeForOptimalDisplay().height(); - subviewPreviousLine->setFrame(KDRect(x, y, width, height)); + subviewPreviousLine->setFrame(KDRect(x, y, width, height), force); x += width; } // Next line diff --git a/apps/shared/banner_view.h b/apps/shared/banner_view.h index 2f16a9e57..86f00cbea 100644 --- a/apps/shared/banner_view.h +++ b/apps/shared/banner_view.h @@ -19,7 +19,7 @@ private: static constexpr KDCoordinate LineSpacing = 2; int numberOfSubviews() const override = 0; View * subviewAtIndex(int index) override = 0; - void layoutSubviews() override; + void layoutSubviews(bool force = false) override; int numberOfLinesGivenWidth(KDCoordinate width) const; }; diff --git a/apps/shared/buffer_function_title_cell.cpp b/apps/shared/buffer_function_title_cell.cpp index ef9b53e8d..aaf56cbc9 100644 --- a/apps/shared/buffer_function_title_cell.cpp +++ b/apps/shared/buffer_function_title_cell.cpp @@ -37,8 +37,8 @@ View * BufferFunctionTitleCell::subviewAtIndex(int index) { return &m_bufferTextView; } -void BufferFunctionTitleCell::layoutSubviews() { - m_bufferTextView.setFrame(bufferTextViewFrame()); +void BufferFunctionTitleCell::layoutSubviews(bool force) { + m_bufferTextView.setFrame(bufferTextViewFrame(), force); } KDRect BufferFunctionTitleCell::bufferTextViewFrame() const { diff --git a/apps/shared/buffer_function_title_cell.h b/apps/shared/buffer_function_title_cell.h index 1ee507ade..6d59c14af 100644 --- a/apps/shared/buffer_function_title_cell.h +++ b/apps/shared/buffer_function_title_cell.h @@ -20,7 +20,7 @@ public: } int numberOfSubviews() const override; View * subviewAtIndex(int index) override; - void layoutSubviews() override; + void layoutSubviews(bool force = false) override; protected: KDRect bufferTextViewFrame() const; EvenOddBufferTextCell * bufferTextView() { return &m_bufferTextView; } diff --git a/apps/shared/buffer_text_view_with_text_field.cpp b/apps/shared/buffer_text_view_with_text_field.cpp index 78aff5867..2bf40a873 100644 --- a/apps/shared/buffer_text_view_with_text_field.cpp +++ b/apps/shared/buffer_text_view_with_text_field.cpp @@ -50,9 +50,9 @@ View * BufferTextViewWithTextField::subviewAtIndex(int index) { return views[index]; } -void BufferTextViewWithTextField::layoutSubviews() { - m_bufferTextView.setFrame(KDRect(Metric::TitleBarExternHorizontalMargin, 0, k_bufferTextWidth, bounds().height())); - m_textField.setFrame(textFieldFrame()); +void BufferTextViewWithTextField::layoutSubviews(bool force) { + m_bufferTextView.setFrame(KDRect(Metric::TitleBarExternHorizontalMargin, 0, k_bufferTextWidth, bounds().height()), force); + m_textField.setFrame(textFieldFrame(), force); } KDRect BufferTextViewWithTextField::textFieldFrame() const { diff --git a/apps/shared/buffer_text_view_with_text_field.h b/apps/shared/buffer_text_view_with_text_field.h index f3b207168..64dda0e8d 100644 --- a/apps/shared/buffer_text_view_with_text_field.h +++ b/apps/shared/buffer_text_view_with_text_field.h @@ -20,7 +20,7 @@ private: constexpr static KDCoordinate k_borderWidth = 1; int numberOfSubviews() const override { return 2; } View * subviewAtIndex(int index) override; - void layoutSubviews() override; + void layoutSubviews(bool force = false) override; KDRect textFieldFrame() const; BufferTextView m_bufferTextView; TextField m_textField; diff --git a/apps/shared/button_with_separator.cpp b/apps/shared/button_with_separator.cpp index a4d6dec1c..faf1fe013 100644 --- a/apps/shared/button_with_separator.cpp +++ b/apps/shared/button_with_separator.cpp @@ -20,8 +20,8 @@ void ButtonWithSeparator::drawRect(KDContext * ctx, KDRect rect) const { } -void ButtonWithSeparator::layoutSubviews() { +void ButtonWithSeparator::layoutSubviews(bool force) { KDCoordinate width = bounds().width(); KDCoordinate height = bounds().height(); - m_messageTextView.setFrame(KDRect(k_lineThickness, k_margin + k_lineThickness, width-2*k_lineThickness, height - 4*k_lineThickness-k_margin)); + m_messageTextView.setFrame(KDRect(k_lineThickness, k_margin + k_lineThickness, width-2*k_lineThickness, height - 4*k_lineThickness-k_margin), force); } diff --git a/apps/shared/button_with_separator.h b/apps/shared/button_with_separator.h index e6337b9bb..7f2685902 100644 --- a/apps/shared/button_with_separator.h +++ b/apps/shared/button_with_separator.h @@ -10,7 +10,7 @@ public: private: constexpr static KDCoordinate k_margin = 5; constexpr static KDCoordinate k_lineThickness = 1; - void layoutSubviews() override; + void layoutSubviews(bool force = false) override; }; #endif diff --git a/apps/shared/cursor_view.h b/apps/shared/cursor_view.h index f0b662954..4590950b2 100644 --- a/apps/shared/cursor_view.h +++ b/apps/shared/cursor_view.h @@ -7,7 +7,7 @@ namespace Shared { class CursorView : public View { public: - virtual void setCursorFrame(KDRect frame) { View::setFrame(frame); } + virtual void setCursorFrame(KDRect frame, bool force) { View::setFrame(frame, force); } void drawRect(KDContext * ctx, KDRect rect) const override; KDSize minimalSizeForOptimalDisplay() const override; private: diff --git a/apps/shared/curve_view.cpp b/apps/shared/curve_view.cpp index 7eb87cf9b..ed7cacfe1 100644 --- a/apps/shared/curve_view.cpp +++ b/apps/shared/curve_view.cpp @@ -722,15 +722,15 @@ void CurveView::stampAtLocation(KDContext * ctx, KDRect rect, float pxf, float p ctx->blendRectWithMask(stampRect, color, (const uint8_t *)shiftedMask, workingBuffer); } -void CurveView::layoutSubviews() { +void CurveView::layoutSubviews(bool force) { if (m_curveViewCursor != nullptr && m_cursorView != nullptr) { - m_cursorView->setCursorFrame(cursorFrame()); + m_cursorView->setCursorFrame(cursorFrame(), force); } if (m_bannerView != nullptr) { - m_bannerView->setFrame(bannerFrame()); + m_bannerView->setFrame(bannerFrame(), force); } if (m_okView != nullptr) { - m_okView->setFrame(okFrame()); + m_okView->setFrame(okFrame(), force); } } diff --git a/apps/shared/curve_view.h b/apps/shared/curve_view.h index 1c4ac72b8..c33f9badf 100644 --- a/apps/shared/curve_view.h +++ b/apps/shared/curve_view.h @@ -94,7 +94,7 @@ private: * function shifts the stamp (by blending adjacent pixel colors) to draw with * anti alising. */ void stampAtLocation(KDContext * ctx, KDRect rect, float pxf, float pyf, KDColor color) const; - void layoutSubviews() override; + void layoutSubviews(bool force = false) override; KDRect cursorFrame(); KDRect bannerFrame(); KDRect okFrame(); diff --git a/apps/shared/function_expression_cell.cpp b/apps/shared/function_expression_cell.cpp index 950ccc2a3..72c4ada5b 100644 --- a/apps/shared/function_expression_cell.cpp +++ b/apps/shared/function_expression_cell.cpp @@ -18,9 +18,9 @@ void FunctionExpressionCell::drawRect(KDContext * ctx, KDRect rect) const { } -void FunctionExpressionCell::layoutSubviews() { +void FunctionExpressionCell::layoutSubviews(bool force) { KDRect expressionFrame(m_leftMargin, 0, bounds().width() - m_leftMargin - m_rightMargin, bounds().height()-k_separatorThickness); - m_expressionView.setFrame(expressionFrame); + m_expressionView.setFrame(expressionFrame, force); } } diff --git a/apps/shared/function_expression_cell.h b/apps/shared/function_expression_cell.h index 34fc1a2f1..842842688 100644 --- a/apps/shared/function_expression_cell.h +++ b/apps/shared/function_expression_cell.h @@ -10,7 +10,7 @@ public: FunctionExpressionCell() : EvenOddExpressionCell() {} KDSize minimalSizeForOptimalDisplay() const override; void drawRect(KDContext * ctx, KDRect rect) const override; - void layoutSubviews() override; + void layoutSubviews(bool force = false) override; private: constexpr static KDCoordinate k_separatorThickness = Metric::CellSeparatorThickness; }; diff --git a/apps/shared/message_view.cpp b/apps/shared/message_view.cpp index 8b5396ee3..819c8dafe 100644 --- a/apps/shared/message_view.cpp +++ b/apps/shared/message_view.cpp @@ -23,15 +23,15 @@ View * MessageView::subviewAtIndex(int index) { return &(m_messageTextViews[index]); } -void MessageView::layoutSubviews() { +void MessageView::layoutSubviews(bool force) { if (m_numberOfMessages == 0) { return; } KDCoordinate width = bounds().width(); KDCoordinate titleHeight = m_messageTextViews[0].minimalSizeForOptimalDisplay().height(); KDCoordinate textHeight = KDFont::SmallFont->glyphSize().height(); - m_messageTextViews[0].setFrame(KDRect(0, k_titleMargin, width, titleHeight)); + m_messageTextViews[0].setFrame(KDRect(0, k_titleMargin, width, titleHeight), force); for (uint8_t i = 1; i < m_numberOfMessages; i++) { - m_messageTextViews[i].setFrame(KDRect(0, k_paragraphHeight + (i-1) * textHeight, width, textHeight)); + m_messageTextViews[i].setFrame(KDRect(0, k_paragraphHeight + (i-1) * textHeight, width, textHeight), force); } } diff --git a/apps/shared/message_view.h b/apps/shared/message_view.h index bcd110a4d..41fb9e648 100644 --- a/apps/shared/message_view.h +++ b/apps/shared/message_view.h @@ -10,7 +10,7 @@ public: protected: int numberOfSubviews() const override { return m_numberOfMessages; } View * subviewAtIndex(int index) override; - void layoutSubviews() override; + void layoutSubviews(bool force = false) override; private: constexpr static KDCoordinate k_titleMargin = 40; constexpr static KDCoordinate k_paragraphHeight = 90; diff --git a/apps/shared/round_cursor_view.cpp b/apps/shared/round_cursor_view.cpp index f3e33078c..d3f6316ce 100644 --- a/apps/shared/round_cursor_view.cpp +++ b/apps/shared/round_cursor_view.cpp @@ -35,11 +35,11 @@ void RoundCursorView::setColor(KDColor color) { markRectAsDirty(bounds()); } -void RoundCursorView::setCursorFrame(KDRect f) { +void RoundCursorView::setCursorFrame(KDRect f, bool force) { #if GRAPH_CURSOR_SPEEDUP /* TODO This is quite dirty (we are out of the dirty tracking and we assume * the cursor is the upmost view) but it works well. */ - if (m_frame == f) { + if (m_frame == f && !force) { return; } /* We want to avoid drawing the curve just because the cursor has been @@ -51,7 +51,7 @@ void RoundCursorView::setCursorFrame(KDRect f) { return; } #endif - CursorView::setCursorFrame(f); + CursorView::setCursorFrame(f, force); } #ifdef GRAPH_CURSOR_SPEEDUP diff --git a/apps/shared/round_cursor_view.h b/apps/shared/round_cursor_view.h index b84d7e07b..8bde981ed 100644 --- a/apps/shared/round_cursor_view.h +++ b/apps/shared/round_cursor_view.h @@ -13,7 +13,7 @@ public: void drawRect(KDContext * ctx, KDRect rect) const override; KDSize minimalSizeForOptimalDisplay() const override; void setColor(KDColor color); - void setCursorFrame(KDRect frame) override; + void setCursorFrame(KDRect frame, bool force) override; #ifdef GRAPH_CURSOR_SPEEDUP void resetMemoization() const { m_underneathPixelBufferLoaded = false; } #endif diff --git a/apps/shared/scrollable_exact_approximate_expressions_cell.cpp b/apps/shared/scrollable_exact_approximate_expressions_cell.cpp index a3f912ea2..da4bb9881 100644 --- a/apps/shared/scrollable_exact_approximate_expressions_cell.cpp +++ b/apps/shared/scrollable_exact_approximate_expressions_cell.cpp @@ -43,8 +43,8 @@ View * ScrollableExactApproximateExpressionsCell::subviewAtIndex(int index) { return &m_view; } -void ScrollableExactApproximateExpressionsCell::layoutSubviews() { - m_view.setFrame(bounds()); +void ScrollableExactApproximateExpressionsCell::layoutSubviews(bool force) { + m_view.setFrame(bounds(), force); } } diff --git a/apps/shared/scrollable_exact_approximate_expressions_cell.h b/apps/shared/scrollable_exact_approximate_expressions_cell.h index 39c232b16..dfaf7bd20 100644 --- a/apps/shared/scrollable_exact_approximate_expressions_cell.h +++ b/apps/shared/scrollable_exact_approximate_expressions_cell.h @@ -24,7 +24,7 @@ public: private: int numberOfSubviews() const override; View * subviewAtIndex(int index) override; - void layoutSubviews() override; + void layoutSubviews(bool force = false) override; ScrollableExactApproximateExpressionsView m_view; }; diff --git a/apps/shared/scrollable_exact_approximate_expressions_view.cpp b/apps/shared/scrollable_exact_approximate_expressions_view.cpp index 4415804a0..548f827ef 100644 --- a/apps/shared/scrollable_exact_approximate_expressions_view.cpp +++ b/apps/shared/scrollable_exact_approximate_expressions_view.cpp @@ -94,11 +94,11 @@ View * ScrollableExactApproximateExpressionsView::ContentCell::subviewAtIndex(in return views[index]; } -void ScrollableExactApproximateExpressionsView::ContentCell::layoutSubviews() { +void ScrollableExactApproximateExpressionsView::ContentCell::layoutSubviews(bool force) { KDCoordinate height = bounds().height(); KDSize rightExpressionSize = m_rightExpressionView.minimalSizeForOptimalDisplay(); if (numberOfSubviews() == 1) { - m_rightExpressionView.setFrame(KDRect(0, 0, rightExpressionSize.width(), height)); + m_rightExpressionView.setFrame(KDRect(0, 0, rightExpressionSize.width(), height), force); return; } KDCoordinate leftBaseline = m_leftExpressionView.layout().baseline(); @@ -106,9 +106,9 @@ void ScrollableExactApproximateExpressionsView::ContentCell::layoutSubviews() { KDCoordinate baseline = maxCoordinate(leftBaseline, rightBaseline); KDSize leftExpressionSize = m_leftExpressionView.minimalSizeForOptimalDisplay(); KDSize approximateSignSize = m_approximateSign.minimalSizeForOptimalDisplay(); - m_leftExpressionView.setFrame(KDRect(0, baseline-leftBaseline, leftExpressionSize)); - m_rightExpressionView.setFrame(KDRect(2*Metric::CommonLargeMargin+leftExpressionSize.width()+approximateSignSize.width(), baseline-rightBaseline, rightExpressionSize)); - m_approximateSign.setFrame(KDRect(Metric::CommonLargeMargin+leftExpressionSize.width(), baseline-approximateSignSize.height()/2, approximateSignSize)); + m_leftExpressionView.setFrame(KDRect(0, baseline-leftBaseline, leftExpressionSize), force); + m_rightExpressionView.setFrame(KDRect(2*Metric::CommonLargeMargin+leftExpressionSize.width()+approximateSignSize.width(), baseline-rightBaseline, rightExpressionSize), force); + m_approximateSign.setFrame(KDRect(Metric::CommonLargeMargin+leftExpressionSize.width(), baseline-approximateSignSize.height()/2, approximateSignSize), force); } ScrollableExactApproximateExpressionsView::ScrollableExactApproximateExpressionsView(Responder * parentResponder) : diff --git a/apps/shared/scrollable_exact_approximate_expressions_view.h b/apps/shared/scrollable_exact_approximate_expressions_view.h index b24dd9fa6..45573275f 100644 --- a/apps/shared/scrollable_exact_approximate_expressions_view.h +++ b/apps/shared/scrollable_exact_approximate_expressions_view.h @@ -54,7 +54,7 @@ private: void setSelectedSubviewPosition(SubviewPosition subviewPosition); bool displayLeftExpression() const { return m_displayLeftExpression; } void setDisplayLeftExpression(bool display); - void layoutSubviews() override; + void layoutSubviews(bool force = false) override; int numberOfSubviews() const override; Poincare::Layout layout() const override; private: diff --git a/apps/shared/separator_even_odd_buffer_text_cell.cpp b/apps/shared/separator_even_odd_buffer_text_cell.cpp index 10eb5ef83..3117a2f64 100644 --- a/apps/shared/separator_even_odd_buffer_text_cell.cpp +++ b/apps/shared/separator_even_odd_buffer_text_cell.cpp @@ -11,9 +11,14 @@ void SeparatorEvenOddBufferTextCell::drawRect(KDContext * ctx, KDRect rect) cons ctx->fillRect(separatorRect, Shared::HideableEvenOddEditableTextCell::hideColor()); } -void SeparatorEvenOddBufferTextCell::layoutSubviews() { +void SeparatorEvenOddBufferTextCell::layoutSubviews(bool force) { KDRect boundsThis = bounds(); - m_bufferTextView.setFrame(KDRect(boundsThis.left() + Metric::TableSeparatorThickness + k_horizontalMargin, boundsThis.top(), boundsThis.width() - Metric::TableSeparatorThickness - 2*k_horizontalMargin, boundsThis.height())); + KDRect frame = KDRect( + boundsThis.left() + Metric::TableSeparatorThickness + k_horizontalMargin, + boundsThis.top(), + boundsThis.width() - Metric::TableSeparatorThickness - 2*k_horizontalMargin, + boundsThis.height()); + m_bufferTextView.setFrame(frame, force); } } diff --git a/apps/shared/separator_even_odd_buffer_text_cell.h b/apps/shared/separator_even_odd_buffer_text_cell.h index eba84ffef..0a5371f0a 100644 --- a/apps/shared/separator_even_odd_buffer_text_cell.h +++ b/apps/shared/separator_even_odd_buffer_text_cell.h @@ -10,7 +10,7 @@ class SeparatorEvenOddBufferTextCell : public EvenOddBufferTextCell { public: using EvenOddBufferTextCell::EvenOddBufferTextCell; void drawRect(KDContext * ctx, KDRect rect) const override; - void layoutSubviews() override; + void layoutSubviews(bool force = false) override; private: constexpr static KDCoordinate k_rightMargin = Metric::CellMargin; }; diff --git a/apps/shared/store_cell.cpp b/apps/shared/store_cell.cpp index 8fe040e25..89fc90ae3 100644 --- a/apps/shared/store_cell.cpp +++ b/apps/shared/store_cell.cpp @@ -10,9 +10,9 @@ void StoreCell::drawRect(KDContext * ctx, KDRect rect) const { } } -void StoreCell::layoutSubviews() { +void StoreCell::layoutSubviews(bool force) { KDRect boundsThis = bounds(); - editableTextCell()->setFrame(rectWithoutSeparator(KDRect(boundsThis.left(), boundsThis.top(), boundsThis.width() - k_rightMargin, boundsThis.height()))); + editableTextCell()->setFrame(rectWithoutSeparator(KDRect(boundsThis.left(), boundsThis.top(), boundsThis.width() - k_rightMargin, boundsThis.height())), force); } void StoreCell::didSetSeparator() { diff --git a/apps/shared/store_cell.h b/apps/shared/store_cell.h index c6642f3e9..5e1a0c260 100644 --- a/apps/shared/store_cell.h +++ b/apps/shared/store_cell.h @@ -13,7 +13,7 @@ public: Separable() {} void drawRect(KDContext * ctx, KDRect rect) const override; - void layoutSubviews() override; + void layoutSubviews(bool force = false) override; private: static constexpr KDCoordinate k_rightMargin = Metric::CellMargin; void didSetSeparator() override; diff --git a/apps/shared/store_controller.cpp b/apps/shared/store_controller.cpp index 876b7682e..c9fff64e4 100644 --- a/apps/shared/store_controller.cpp +++ b/apps/shared/store_controller.cpp @@ -44,10 +44,10 @@ View * StoreController::ContentView::subviewAtIndex(int index) { return views[index]; } -void StoreController::ContentView::layoutSubviews() { +void StoreController::ContentView::layoutSubviews(bool force) { KDRect dataViewFrame(0, 0, bounds().width(), bounds().height() - (m_displayFormulaInputView ? k_formulaInputHeight : 0)); - m_dataView.setFrame(dataViewFrame); - m_formulaInputView.setFrame(formulaFrame()); + m_dataView.setFrame(dataViewFrame, force); + m_formulaInputView.setFrame(formulaFrame(), force); } KDRect StoreController::ContentView::formulaFrame() const { diff --git a/apps/shared/store_controller.h b/apps/shared/store_controller.h index 3158e4715..33eb9de69 100644 --- a/apps/shared/store_controller.h +++ b/apps/shared/store_controller.h @@ -64,7 +64,7 @@ protected: static constexpr KDCoordinate k_formulaInputHeight = 31; int numberOfSubviews() const override { return 1 + m_displayFormulaInputView; } View * subviewAtIndex(int index) override; - void layoutSubviews() override; + void layoutSubviews(bool force = false) override; KDRect formulaFrame() const; StoreSelectableTableView m_dataView; BufferTextViewWithTextField m_formulaInputView; diff --git a/apps/shared/store_title_cell.cpp b/apps/shared/store_title_cell.cpp index 473db9912..6a99e60f1 100644 --- a/apps/shared/store_title_cell.cpp +++ b/apps/shared/store_title_cell.cpp @@ -10,8 +10,8 @@ void StoreTitleCell::drawRect(KDContext * ctx, KDRect rect) const { ctx->fillRect(r, m_separatorLeft ? HideableEvenOddEditableTextCell::hideColor() : backgroundColor()); } -void StoreTitleCell::layoutSubviews() { - bufferTextView()->setFrame(rectWithoutSeparator(bufferTextViewFrame())); +void StoreTitleCell::layoutSubviews(bool force) { + bufferTextView()->setFrame(rectWithoutSeparator(bufferTextViewFrame()), force); } void StoreTitleCell::didSetSeparator() { diff --git a/apps/shared/store_title_cell.h b/apps/shared/store_title_cell.h index 05899c24f..375c261eb 100644 --- a/apps/shared/store_title_cell.h +++ b/apps/shared/store_title_cell.h @@ -13,7 +13,7 @@ public: Separable() {} void drawRect(KDContext * ctx, KDRect rect) const override; - void layoutSubviews() override; + void layoutSubviews(bool force = false) override; private: void didSetSeparator() override; }; diff --git a/apps/shared/sum_graph_controller.cpp b/apps/shared/sum_graph_controller.cpp index babf74e0e..fe3aa001e 100644 --- a/apps/shared/sum_graph_controller.cpp +++ b/apps/shared/sum_graph_controller.cpp @@ -174,7 +174,7 @@ KDSize SumGraphController::LegendView::minimalSizeForOptimalDisplay() const { void SumGraphController::LegendView::setLegendMessage(I18n::Message message, Step step) { m_legend.setMessage(message); - layoutSubviews(step); + layoutSubviews(step, false); } void SumGraphController::LegendView::setEditableZone(double d) { @@ -226,7 +226,7 @@ void SumGraphController::LegendView::setSumSymbol(Step step, double start, doubl } else { m_sum.setAlignment(0.0f, 0.5f); } - layoutSubviews(step); + layoutSubviews(step, false); } View * SumGraphController::LegendView::subviewAtIndex(int index) { @@ -240,21 +240,21 @@ View * SumGraphController::LegendView::subviewAtIndex(int index) { return &m_legend; } -void SumGraphController::LegendView::layoutSubviews() { - layoutSubviews(Step::FirstParameter); +void SumGraphController::LegendView::layoutSubviews(bool force) { + layoutSubviews(Step::FirstParameter, force); } -void SumGraphController::LegendView::layoutSubviews(Step step) { +void SumGraphController::LegendView::layoutSubviews(Step step, bool force) { KDCoordinate width = bounds().width(); KDCoordinate heigth = bounds().height(); KDSize legendSize = m_legend.minimalSizeForOptimalDisplay(); if (legendSize.width() > 0) { - m_sum.setFrame(KDRect(0, k_symbolHeightMargin, width-legendSize.width(), m_sum.minimalSizeForOptimalDisplay().height())); - m_legend.setFrame(KDRect(width-legendSize.width(), 0, legendSize.width(), heigth)); + m_sum.setFrame(KDRect(0, k_symbolHeightMargin, width-legendSize.width(), m_sum.minimalSizeForOptimalDisplay().height()), force); + m_legend.setFrame(KDRect(width-legendSize.width(), 0, legendSize.width(), heigth), force); } else { - m_sum.setFrame(bounds()); - m_legend.setFrame(KDRectZero); + m_sum.setFrame(bounds(), force); + m_legend.setFrame(KDRectZero, force); } KDRect frame = (step == Step::Result) ? KDRectZero : KDRect( @@ -262,7 +262,7 @@ void SumGraphController::LegendView::layoutSubviews(Step step) { k_symbolHeightMargin + k_sigmaHeight/2 - (step == Step::SecondParameter) * editableZoneHeight(), editableZoneWidth(), editableZoneHeight() ); - m_editableZone.setFrame(frame); + m_editableZone.setFrame(frame, force); } } diff --git a/apps/shared/sum_graph_controller.h b/apps/shared/sum_graph_controller.h index 0915616a5..b6fcad81a 100644 --- a/apps/shared/sum_graph_controller.h +++ b/apps/shared/sum_graph_controller.h @@ -65,8 +65,8 @@ private: constexpr static KDCoordinate k_sigmaHeight = 18; int numberOfSubviews() const override { return 3; } View * subviewAtIndex(int index) override; - void layoutSubviews() override; - void layoutSubviews(Step step); + void layoutSubviews(bool force = false) override; + void layoutSubviews(Step step, bool force); ExpressionView m_sum; Poincare::Layout m_sumLayout; MessageTextView m_legend; diff --git a/apps/shared/zoom_parameter_controller.cpp b/apps/shared/zoom_parameter_controller.cpp index 29ecc8c92..22d053271 100644 --- a/apps/shared/zoom_parameter_controller.cpp +++ b/apps/shared/zoom_parameter_controller.cpp @@ -102,10 +102,10 @@ View * ZoomParameterController::ContentView::subviewAtIndex(int index) { return &m_legendView; } -void ZoomParameterController::ContentView::layoutSubviews() { +void ZoomParameterController::ContentView::layoutSubviews(bool force) { assert(bounds().height() == ZoomParameterController::k_standardViewHeight); - m_curveView->setFrame(KDRect(0, 0, bounds().width(), bounds().height() - k_legendHeight)); - m_legendView.setFrame(KDRect(0, bounds().height() - k_legendHeight, bounds().width(), k_legendHeight)); + m_curveView->setFrame(KDRect(0, 0, bounds().width(), bounds().height() - k_legendHeight), force); + m_legendView.setFrame(KDRect(0, bounds().height() - k_legendHeight, bounds().width(), k_legendHeight), force); } CurveView * ZoomParameterController::ContentView::curveView() { @@ -146,22 +146,22 @@ View * ZoomParameterController::ContentView::LegendView::subviewAtIndex(int inde return &m_legendPictograms[index-k_numberOfLegends]; } -void ZoomParameterController::ContentView::LegendView::layoutSubviews() { +void ZoomParameterController::ContentView::LegendView::layoutSubviews(bool force) { KDCoordinate height = bounds().height(); KDCoordinate xOrigin = 0; KDCoordinate legendWidth = m_legends[0].minimalSizeForOptimalDisplay().width(); - m_legends[0].setFrame(KDRect(xOrigin, 0, legendWidth, height)); + m_legends[0].setFrame(KDRect(xOrigin, 0, legendWidth, height), force); xOrigin += legendWidth; for (int i = 0; i < k_numberOfTokens - 2; i++) { - m_legendPictograms[i].setFrame(KDRect(xOrigin, 0, k_tokenWidth, height)); + m_legendPictograms[i].setFrame(KDRect(xOrigin, 0, k_tokenWidth, height), force); xOrigin += k_tokenWidth; } xOrigin = bounds().width()/2; for (int i = 1; i < k_numberOfLegends; i++) { KDCoordinate legendWidth = m_legends[i].minimalSizeForOptimalDisplay().width(); - m_legends[i].setFrame(KDRect(xOrigin, 0, legendWidth, height)); + m_legends[i].setFrame(KDRect(xOrigin, 0, legendWidth, height), force); xOrigin += legendWidth; - m_legendPictograms[k_numberOfTokens - 3 + i].setFrame(KDRect(xOrigin, 0, k_tokenWidth, height)); + m_legendPictograms[k_numberOfTokens - 3 + i].setFrame(KDRect(xOrigin, 0, k_tokenWidth, height), force); xOrigin += k_tokenWidth; } } diff --git a/apps/shared/zoom_parameter_controller.h b/apps/shared/zoom_parameter_controller.h index 13751a1b2..3d4f566c7 100644 --- a/apps/shared/zoom_parameter_controller.h +++ b/apps/shared/zoom_parameter_controller.h @@ -23,7 +23,7 @@ private: public: constexpr static KDCoordinate k_legendHeight = 30; ContentView(CurveView * curveView); - void layoutSubviews() override; + void layoutSubviews(bool force = false) override; CurveView * curveView(); private: class LegendView : public View { @@ -34,7 +34,7 @@ private: constexpr static int k_numberOfLegends = 3; constexpr static int k_numberOfTokens = 6; constexpr static KDCoordinate k_tokenWidth = 10; - void layoutSubviews() override; + void layoutSubviews(bool force = false) override; int numberOfSubviews() const override; View * subviewAtIndex(int index) override; MessageTextView m_legends[k_numberOfLegends]; diff --git a/apps/shift_alpha_lock_view.cpp b/apps/shift_alpha_lock_view.cpp index ae811e1d3..246ae8ab4 100644 --- a/apps/shift_alpha_lock_view.cpp +++ b/apps/shift_alpha_lock_view.cpp @@ -65,10 +65,10 @@ View * ShiftAlphaLockView::subviewAtIndex(int index) { return &m_lockView; } -void ShiftAlphaLockView::layoutSubviews() { +void ShiftAlphaLockView::layoutSubviews(bool force) { KDSize modifierSize = KDFont::SmallFont->stringSize(I18n::translate(I18n::Message::Alpha)); - m_shiftAlphaView.setFrame(KDRect(bounds().width() - modifierSize.width(), (bounds().height()- modifierSize.height())/2, modifierSize)); + m_shiftAlphaView.setFrame(KDRect(bounds().width() - modifierSize.width(), (bounds().height()- modifierSize.height())/2, modifierSize), force); KDSize lockSize = m_lockView.minimalSizeForOptimalDisplay(); - m_lockView.setFrame(KDRect(bounds().width() - modifierSize.width() - lockSize.width() - k_lockRightMargin, (bounds().height()- lockSize.height())/2, lockSize)); + m_lockView.setFrame(KDRect(bounds().width() - modifierSize.width() - lockSize.width() - k_lockRightMargin, (bounds().height()- lockSize.height())/2, lockSize), force); } diff --git a/apps/shift_alpha_lock_view.h b/apps/shift_alpha_lock_view.h index b3b0bd05d..0e0d85d60 100644 --- a/apps/shift_alpha_lock_view.h +++ b/apps/shift_alpha_lock_view.h @@ -14,7 +14,7 @@ public: private: constexpr static KDCoordinate k_lockRightMargin = 5; int numberOfSubviews() const override; - void layoutSubviews() override; + void layoutSubviews(bool force = false) override; View * subviewAtIndex(int index) override; LockView m_lockView; MessageTextView m_shiftAlphaView; diff --git a/apps/solver/equation_list_view.cpp b/apps/solver/equation_list_view.cpp index 7253374cd..6edfd4092 100644 --- a/apps/solver/equation_list_view.cpp +++ b/apps/solver/equation_list_view.cpp @@ -47,8 +47,8 @@ void EquationListView::didBecomeFirstResponder() { Container::activeApp()->setFirstResponder(&m_listView); } -void EquationListView::layoutSubviews() { - m_listView.setFrame(KDRect(0, 0, bounds().width(), bounds().height())); +void EquationListView::layoutSubviews(bool force) { + m_listView.setFrame(KDRect(0, 0, bounds().width(), bounds().height()), force); if (m_braceStyle != BraceStyle::None) { KDCoordinate braceWidth = m_braceView.minimalSizeForOptimalDisplay().width(); KDCoordinate braceHeight = m_listView.minimalSizeForOptimalDisplay().height()-2*k_margin; @@ -56,9 +56,9 @@ void EquationListView::layoutSubviews() { m_braceView.setSize(KDSize(braceWidth, braceHeight)); KDCoordinate scrollBraceHeight = m_listView.minimalSizeForOptimalDisplay().height()-offset().y(); scrollBraceHeight = m_braceStyle == BraceStyle::OneRowShort ? scrollBraceHeight - Metric::StoreRowHeight : scrollBraceHeight; - m_scrollBraceView.setFrame(KDRect(0, 0, k_braceTotalWidth, scrollBraceHeight)); + m_scrollBraceView.setFrame(KDRect(0, 0, k_braceTotalWidth, scrollBraceHeight), force); } else { - m_scrollBraceView.setFrame(KDRectZero); + m_scrollBraceView.setFrame(KDRectZero, force); } } diff --git a/apps/solver/equation_list_view.h b/apps/solver/equation_list_view.h index 9363c7fe6..a4392ae99 100644 --- a/apps/solver/equation_list_view.h +++ b/apps/solver/equation_list_view.h @@ -23,7 +23,7 @@ public: } constexpr static KDCoordinate k_margin = 10; constexpr static KDCoordinate k_braceTotalWidth = 30;//2*k_margin+BraceView::k_braceWidth; - void layoutSubviews() override; + void layoutSubviews(bool force = false) override; private: int numberOfSubviews() const override; View * subviewAtIndex(int index) override; diff --git a/apps/solver/interval_controller.cpp b/apps/solver/interval_controller.cpp index cb452a0ce..5f1addd34 100644 --- a/apps/solver/interval_controller.cpp +++ b/apps/solver/interval_controller.cpp @@ -32,11 +32,11 @@ View * IntervalController::ContentView::subviewAtIndex(int index) { return m_selectableTableView; } -void IntervalController::ContentView::layoutSubviews() { +void IntervalController::ContentView::layoutSubviews(bool force) { KDCoordinate textHeight = KDFont::SmallFont->glyphSize().height(); - m_instructions0.setFrame(KDRect(0, k_topMargin/2-textHeight, bounds().width(), textHeight)); - m_instructions1.setFrame(KDRect(0, k_topMargin/2, bounds().width(), textHeight)); - m_selectableTableView->setFrame(KDRect(0, k_topMargin, bounds().width(), bounds().height()-k_topMargin)); + m_instructions0.setFrame(KDRect(0, k_topMargin/2-textHeight, bounds().width(), textHeight), force); + m_instructions1.setFrame(KDRect(0, k_topMargin/2, bounds().width(), textHeight), force); + m_selectableTableView->setFrame(KDRect(0, k_topMargin, bounds().width(), bounds().height()-k_topMargin), force); } /* IntervalController Controller */ diff --git a/apps/solver/interval_controller.h b/apps/solver/interval_controller.h index 206f86fd1..ba4f98d21 100644 --- a/apps/solver/interval_controller.h +++ b/apps/solver/interval_controller.h @@ -29,7 +29,7 @@ private: constexpr static KDCoordinate k_topMargin = 50; int numberOfSubviews() const override; View * subviewAtIndex(int index) override; - void layoutSubviews() override; + void layoutSubviews(bool force = false) override; MessageTextView m_instructions0; MessageTextView m_instructions1; SelectableTableView * m_selectableTableView; diff --git a/apps/solver/solutions_controller.cpp b/apps/solver/solutions_controller.cpp index db0657eeb..77997262e 100644 --- a/apps/solver/solutions_controller.cpp +++ b/apps/solver/solutions_controller.cpp @@ -59,14 +59,14 @@ View * SolutionsController::ContentView::subviewAtIndex(int index) { return &m_selectableTableView; } -void SolutionsController::ContentView::layoutSubviews() { +void SolutionsController::ContentView::layoutSubviews(bool force) { if (m_displayWarningMoreSolutions) { KDCoordinate textHeight = KDFont::SmallFont->glyphSize().height(); - m_warningMessageView0.setFrame(KDRect(0, k_topMargin/2-textHeight, bounds().width(), textHeight)); - m_warningMessageView1.setFrame(KDRect(0, k_topMargin/2, bounds().width(), textHeight)); - m_selectableTableView.setFrame(KDRect(0, k_topMargin, bounds().width(), bounds().height()-k_topMargin)); + m_warningMessageView0.setFrame(KDRect(0, k_topMargin/2-textHeight, bounds().width(), textHeight), force); + m_warningMessageView1.setFrame(KDRect(0, k_topMargin/2, bounds().width(), textHeight), force); + m_selectableTableView.setFrame(KDRect(0, k_topMargin, bounds().width(), bounds().height()-k_topMargin), force); } else { - m_selectableTableView.setFrame(bounds()); + m_selectableTableView.setFrame(bounds(), force); } } diff --git a/apps/solver/solutions_controller.h b/apps/solver/solutions_controller.h index 33208d7c2..8b366339d 100644 --- a/apps/solver/solutions_controller.h +++ b/apps/solver/solutions_controller.h @@ -47,7 +47,7 @@ private: constexpr static KDCoordinate k_topMargin = 50; int numberOfSubviews() const override; View * subviewAtIndex(int index) override; - void layoutSubviews() override; + void layoutSubviews(bool force = false) override; MessageTextView m_warningMessageView0; MessageTextView m_warningMessageView1; SelectableTableView m_selectableTableView; diff --git a/apps/statistics/multiple_boxes_view.cpp b/apps/statistics/multiple_boxes_view.cpp index 5fdb64c60..a19fc8bfc 100644 --- a/apps/statistics/multiple_boxes_view.cpp +++ b/apps/statistics/multiple_boxes_view.cpp @@ -26,7 +26,7 @@ int MultipleBoxesView::seriesOfSubviewAtIndex(int index) { return static_cast(subviewAtIndex(index))->series(); } -void MultipleBoxesView::layoutDataSubviews() { +void MultipleBoxesView::layoutDataSubviews(bool force) { int numberOfDataSubviews = m_store->numberOfNonEmptySeries(); assert(numberOfDataSubviews > 0); KDCoordinate bannerHeight = bannerFrame().height(); @@ -35,11 +35,11 @@ void MultipleBoxesView::layoutDataSubviews() { for (int i = 0; i < Store::k_numberOfSeries; i++) { if (!m_store->seriesIsEmpty(i)) { KDRect frame = KDRect(0, displayedSubviewIndex*subviewHeight, bounds().width(), subviewHeight); - dataViewAtIndex(i)->setFrame(frame); + dataViewAtIndex(i)->setFrame(frame, force); displayedSubviewIndex++; } } - m_axisView.setFrame(KDRect(0, displayedSubviewIndex*subviewHeight, bounds().width(), bounds().height() - bannerHeight - displayedSubviewIndex*subviewHeight)); + m_axisView.setFrame(KDRect(0, displayedSubviewIndex*subviewHeight, bounds().width(), bounds().height() - bannerHeight - displayedSubviewIndex*subviewHeight), force); } void MultipleBoxesView::reload() { diff --git a/apps/statistics/multiple_boxes_view.h b/apps/statistics/multiple_boxes_view.h index 3333907a3..3eb6d32c8 100644 --- a/apps/statistics/multiple_boxes_view.h +++ b/apps/statistics/multiple_boxes_view.h @@ -19,7 +19,7 @@ public: int seriesOfSubviewAtIndex(int index) override; BoxBannerView * bannerView() override { return &m_bannerView; } BoxView * dataViewAtIndex(int index) override; - void layoutDataSubviews() override; + void layoutDataSubviews(bool force) override; void reload() override; // View diff --git a/apps/statistics/multiple_data_view.cpp b/apps/statistics/multiple_data_view.cpp index 5caed52eb..c8ad4f1b5 100644 --- a/apps/statistics/multiple_data_view.cpp +++ b/apps/statistics/multiple_data_view.cpp @@ -7,7 +7,7 @@ namespace Statistics { void MultipleDataView::setDisplayBanner(bool display) { m_displayBanner = display; - layoutBanner(); + layoutBanner(false); } void MultipleDataView::reload() { @@ -66,14 +66,14 @@ View * MultipleDataView::subviewAtIndex(int index) { return nullptr; } -void MultipleDataView::layoutSubviews() { +void MultipleDataView::layoutSubviews(bool force) { // We need to set the banner width first, so its height can be computed - bannerView()->setFrame(KDRect(0, 0, bounds().width(), 0)); - layoutDataSubviews(); - layoutBanner(); + bannerView()->setFrame(KDRect(0, 0, bounds().width(), 0), force); + layoutDataSubviews(force); + layoutBanner(force); } -void MultipleDataView::layoutDataSubviews() { +void MultipleDataView::layoutDataSubviews(bool force) { int numberDataSubviews = m_store->numberOfNonEmptySeries(); assert(numberDataSubviews > 0); KDCoordinate bannerHeight = bannerView()->minimalSizeForOptimalDisplay().height(); @@ -83,7 +83,7 @@ void MultipleDataView::layoutDataSubviews() { if (!m_store->seriesIsEmpty(i)) { CurveView * dataView = dataViewAtIndex(i); KDRect frame = KDRect(0, displayedSubviewIndex*subviewHeight, bounds().width(), subviewHeight); - dataView->setFrame(frame); + dataView->setFrame(frame, force); displayedSubviewIndex++; } } @@ -100,13 +100,13 @@ KDRect MultipleDataView::bannerFrame() const { return frame; } -void MultipleDataView::layoutBanner() { +void MultipleDataView::layoutBanner(bool force) { KDCoordinate bannerHeight = bannerView()->minimalSizeForOptimalDisplay().height(); if (m_displayBanner) { - bannerView()->setFrame(bannerFrame()); + bannerView()->setFrame(bannerFrame(), force); } else { KDRect frame = KDRect(0, bounds().height() - bannerHeight, bounds().width(), 0); - bannerView()->setFrame(frame); + bannerView()->setFrame(frame, force); } } diff --git a/apps/statistics/multiple_data_view.h b/apps/statistics/multiple_data_view.h index e2b9eae0b..40c3dcf72 100644 --- a/apps/statistics/multiple_data_view.h +++ b/apps/statistics/multiple_data_view.h @@ -32,14 +32,14 @@ public: int numberOfSubviews() const override; protected: virtual Shared::BannerView * bannerView() = 0; - void layoutSubviews() override; - virtual void layoutDataSubviews(); + void layoutSubviews(bool force = false) override; + virtual void layoutDataSubviews(bool force); View * subviewAtIndex(int index) override; virtual void changeDataViewSelection(int index, bool select); KDRect bannerFrame() const; Store * m_store; private: - void layoutBanner(); + void layoutBanner(bool force); void drawRect(KDContext * ctx, KDRect rect) const override; bool m_displayBanner; }; diff --git a/apps/statistics/multiple_histograms_view.cpp b/apps/statistics/multiple_histograms_view.cpp index b96c2ade1..d5c18899f 100644 --- a/apps/statistics/multiple_histograms_view.cpp +++ b/apps/statistics/multiple_histograms_view.cpp @@ -31,7 +31,7 @@ int MultipleHistogramsView::seriesOfSubviewAtIndex(int index) { return static_cast(subviewAtIndex(index))->series(); } -void MultipleHistogramsView::layoutSubviews() { +void MultipleHistogramsView::layoutSubviews(bool force) { MultipleDataView::layoutSubviews(); int numberHistogramSubviews = m_store->numberOfNonEmptySeries(); assert(numberHistogramSubviews > 0); diff --git a/apps/statistics/multiple_histograms_view.h b/apps/statistics/multiple_histograms_view.h index de41f0d3b..d5cdbb36b 100644 --- a/apps/statistics/multiple_histograms_view.h +++ b/apps/statistics/multiple_histograms_view.h @@ -19,7 +19,7 @@ public: HistogramBannerView * bannerView() override { return &m_bannerView; } HistogramView * dataViewAtIndex(int index) override; private: - void layoutSubviews() override; + void layoutSubviews(bool force = false) override; void changeDataViewSelection(int index, bool select) override; HistogramView m_histogramView1; HistogramView m_histogramView2; diff --git a/apps/title_bar_view.cpp b/apps/title_bar_view.cpp index 53cee9ab5..ed6be0b4a 100644 --- a/apps/title_bar_view.cpp +++ b/apps/title_bar_view.cpp @@ -61,23 +61,23 @@ View * TitleBarView::subviewAtIndex(int index) { return &m_batteryView; } -void TitleBarView::layoutSubviews() { +void TitleBarView::layoutSubviews(bool force) { /* We here cheat to layout the main title. The application title is written * with upper cases. But, as upper letters are on the same baseline as lower * letters, they seem to be slightly above when they are perferctly centered * (because their glyph never cross the baseline). To avoid this effect, we * translate the frame of the title downwards.*/ - m_titleView.setFrame(KDRect(0, 2, bounds().width(), bounds().height()-2)); - m_preferenceView.setFrame(KDRect(Metric::TitleBarExternHorizontalMargin, 0, m_preferenceView.minimalSizeForOptimalDisplay().width(), bounds().height())); + m_titleView.setFrame(KDRect(0, 2, bounds().width(), bounds().height()-2), force); + m_preferenceView.setFrame(KDRect(Metric::TitleBarExternHorizontalMargin, 0, m_preferenceView.minimalSizeForOptimalDisplay().width(), bounds().height()), force); KDSize batterySize = m_batteryView.minimalSizeForOptimalDisplay(); - m_batteryView.setFrame(KDRect(bounds().width() - batterySize.width() - Metric::TitleBarExternHorizontalMargin, (bounds().height()- batterySize.height())/2, batterySize)); + m_batteryView.setFrame(KDRect(bounds().width() - batterySize.width() - Metric::TitleBarExternHorizontalMargin, (bounds().height()- batterySize.height())/2, batterySize), force); if (GlobalPreferences::sharedGlobalPreferences()->isInExamMode()) { - m_examModeIconView.setFrame(KDRect(k_examIconMargin, (bounds().height() - k_examIconHeight)/2, k_examIconWidth, k_examIconHeight)); + m_examModeIconView.setFrame(KDRect(k_examIconMargin, (bounds().height() - k_examIconHeight)/2, k_examIconWidth, k_examIconHeight), force); } else { - m_examModeIconView.setFrame(KDRectZero); + m_examModeIconView.setFrame(KDRectZero, force); } KDSize shiftAlphaLockSize = m_shiftAlphaLockView.minimalSizeForOptimalDisplay(); - m_shiftAlphaLockView.setFrame(KDRect(bounds().width()-batterySize.width()-Metric::TitleBarExternHorizontalMargin-k_alphaRightMargin-shiftAlphaLockSize.width(), (bounds().height()- shiftAlphaLockSize.height())/2, shiftAlphaLockSize)); + m_shiftAlphaLockView.setFrame(KDRect(bounds().width()-batterySize.width()-Metric::TitleBarExternHorizontalMargin-k_alphaRightMargin-shiftAlphaLockSize.width(), (bounds().height()- shiftAlphaLockSize.height())/2, shiftAlphaLockSize), force); } void TitleBarView::refreshPreferences() { diff --git a/apps/title_bar_view.h b/apps/title_bar_view.h index 646b34415..c0b6517f6 100644 --- a/apps/title_bar_view.h +++ b/apps/title_bar_view.h @@ -23,7 +23,7 @@ private: constexpr static KDCoordinate k_examIconHeight = 9; constexpr static KDCoordinate k_examIconMargin = 93; int numberOfSubviews() const override; - void layoutSubviews() override; + void layoutSubviews(bool force = false) override; View * subviewAtIndex(int index) override; MessageTextView m_titleView; BatteryView m_batteryView; diff --git a/apps/variable_box_empty_controller.cpp b/apps/variable_box_empty_controller.cpp index 207642236..6ceb2f452 100644 --- a/apps/variable_box_empty_controller.cpp +++ b/apps/variable_box_empty_controller.cpp @@ -42,20 +42,20 @@ View * VariableBoxEmptyController::VariableBoxEmptyView::subviewAtIndex(int inde return &m_messages[index-1]; } -void VariableBoxEmptyController::VariableBoxEmptyView::layoutSubviews() { +void VariableBoxEmptyController::VariableBoxEmptyView::layoutSubviews(bool force) { KDCoordinate width = bounds().width(); KDCoordinate height = bounds().height(); KDCoordinate textHeight = k_font->glyphSize().height(); KDCoordinate layoutHeight = m_layoutExample.minimalSizeForOptimalDisplay().height(); KDCoordinate margin = (height - k_numberOfMessages*textHeight-layoutHeight)/2; - m_layoutExample.setFrame(KDRect(0, margin+k_layoutRowIndex*textHeight, width, layoutHeight)); + m_layoutExample.setFrame(KDRect(0, margin+k_layoutRowIndex*textHeight, width, layoutHeight), force); KDCoordinate currentHeight = 0; for (uint8_t i = 0; i < k_numberOfMessages; i++) { if (i == k_layoutRowIndex) { currentHeight += layoutHeight; } KDCoordinate h = i == 0 || i == k_numberOfMessages - 1 ? textHeight+margin : textHeight; - m_messages[i].setFrame(KDRect(0, currentHeight, width, h)); + m_messages[i].setFrame(KDRect(0, currentHeight, width, h), force); currentHeight += h; } } diff --git a/apps/variable_box_empty_controller.h b/apps/variable_box_empty_controller.h index b799c6ca9..39719ab07 100644 --- a/apps/variable_box_empty_controller.h +++ b/apps/variable_box_empty_controller.h @@ -28,7 +28,7 @@ private: private: int numberOfSubviews() const override; View * subviewAtIndex(int index) override; - void layoutSubviews() override; + void layoutSubviews(bool force = false) override; constexpr static int k_layoutRowIndex = 2; MessageTextView m_messages[k_numberOfMessages]; ExpressionView m_layoutExample; diff --git a/escher/include/escher/alternate_empty_view_controller.h b/escher/include/escher/alternate_empty_view_controller.h index 1e16d58fc..734cee60c 100644 --- a/escher/include/escher/alternate_empty_view_controller.h +++ b/escher/include/escher/alternate_empty_view_controller.h @@ -21,7 +21,7 @@ private: ContentView(ViewController * mainViewController, AlternateEmptyViewDelegate * delegate); ViewController * mainViewController() const; AlternateEmptyViewDelegate * alternateEmptyViewDelegate() const; - void layoutSubviews() override; + void layoutSubviews(bool force = false) override; private: int numberOfSubviews() const override; View * subviewAtIndex(int index) override; diff --git a/escher/include/escher/bank_view_controller.h b/escher/include/escher/bank_view_controller.h index 90f7270da..d68b9207b 100644 --- a/escher/include/escher/bank_view_controller.h +++ b/escher/include/escher/bank_view_controller.h @@ -31,8 +31,8 @@ private: assert(index == 0); return m_subview; } - void layoutSubviews() override { - m_subview->setFrame(bounds()); + void layoutSubviews(bool force = false) override { + m_subview->setFrame(bounds(), force); } View * m_subview; }; diff --git a/escher/include/escher/button.h b/escher/include/escher/button.h index a163b00a9..f773c5bfc 100644 --- a/escher/include/escher/button.h +++ b/escher/include/escher/button.h @@ -27,7 +27,7 @@ private: constexpr static KDCoordinate k_horizontalMarginLarge = 20; int numberOfSubviews() const override; View * subviewAtIndex(int index) override; - void layoutSubviews() override; + void layoutSubviews(bool force = false) override; Invocation m_invocation; const KDFont * m_font; }; diff --git a/escher/include/escher/button_row_controller.h b/escher/include/escher/button_row_controller.h index dcba3c98f..9006c74bf 100644 --- a/escher/include/escher/button_row_controller.h +++ b/escher/include/escher/button_row_controller.h @@ -45,7 +45,7 @@ private: void reload(); int numberOfSubviews() const override; View * subviewAtIndex(int index) override; - void layoutSubviews() override; + void layoutSubviews(bool force = false) override; void drawRect(KDContext * ctx, KDRect rect) const override; bool setSelectedButton(int selectedButton); int selectedButton() const { return m_selectedButton; } diff --git a/escher/include/escher/editable_text_cell.h b/escher/include/escher/editable_text_cell.h index d2e4df5ee..9aa14217e 100644 --- a/escher/include/escher/editable_text_cell.h +++ b/escher/include/escher/editable_text_cell.h @@ -26,7 +26,7 @@ public: } int numberOfSubviews() const override; View * subviewAtIndex(int index) override; - void layoutSubviews() override; + void layoutSubviews(bool force = false) override; void didBecomeFirstResponder() override; KDSize minimalSizeForOptimalDisplay() const override; private: diff --git a/escher/include/escher/even_odd_buffer_text_cell.h b/escher/include/escher/even_odd_buffer_text_cell.h index eed6f6b2a..917ce71d7 100644 --- a/escher/include/escher/even_odd_buffer_text_cell.h +++ b/escher/include/escher/even_odd_buffer_text_cell.h @@ -26,7 +26,7 @@ protected: static constexpr KDCoordinate k_horizontalMargin = Metric::CellMargin; int numberOfSubviews() const override; View * subviewAtIndex(int index) override; - void layoutSubviews() override; + void layoutSubviews(bool force = false) override; BufferTextView m_bufferTextView; }; diff --git a/escher/include/escher/even_odd_cell_with_ellipsis.h b/escher/include/escher/even_odd_cell_with_ellipsis.h index 971950159..858130760 100644 --- a/escher/include/escher/even_odd_cell_with_ellipsis.h +++ b/escher/include/escher/even_odd_cell_with_ellipsis.h @@ -14,7 +14,7 @@ private: assert(index==0); return &m_ellipsisView; } - void layoutSubviews() override; + void layoutSubviews(bool force = false) override; EllipsisView m_ellipsisView; }; diff --git a/escher/include/escher/even_odd_editable_text_cell.h b/escher/include/escher/even_odd_editable_text_cell.h index f19f9e7d3..b462144c6 100644 --- a/escher/include/escher/even_odd_editable_text_cell.h +++ b/escher/include/escher/even_odd_editable_text_cell.h @@ -21,7 +21,7 @@ public: private: int numberOfSubviews() const override; View * subviewAtIndex(int index) override; - void layoutSubviews() override; + void layoutSubviews(bool force = false) override; EditableTextCell m_editableCell; }; diff --git a/escher/include/escher/even_odd_expression_cell.h b/escher/include/escher/even_odd_expression_cell.h index 5a63bfc36..f558ed9b6 100644 --- a/escher/include/escher/even_odd_expression_cell.h +++ b/escher/include/escher/even_odd_expression_cell.h @@ -23,7 +23,7 @@ public: protected: int numberOfSubviews() const override; View * subviewAtIndex(int index) override; - void layoutSubviews() override; + void layoutSubviews(bool force = false) override; ExpressionView m_expressionView; KDCoordinate m_leftMargin; KDCoordinate m_rightMargin; diff --git a/escher/include/escher/even_odd_message_text_cell.h b/escher/include/escher/even_odd_message_text_cell.h index 4b5e3c63e..9cb246b07 100644 --- a/escher/include/escher/even_odd_message_text_cell.h +++ b/escher/include/escher/even_odd_message_text_cell.h @@ -18,7 +18,7 @@ protected: constexpr static KDCoordinate k_horizontalMargin = Metric::CellMargin; int numberOfSubviews() const override; View * subviewAtIndex(int index) override; - void layoutSubviews() override; + void layoutSubviews(bool force = false) override; MessageTextView m_messageTextView; }; diff --git a/escher/include/escher/expression_field.h b/escher/include/escher/expression_field.h index f072c3791..8b1310fbb 100644 --- a/escher/include/escher/expression_field.h +++ b/escher/include/escher/expression_field.h @@ -30,7 +30,7 @@ public: /* View */ int numberOfSubviews() const override { return 1; } View * subviewAtIndex(int index) override; - void layoutSubviews() override; + void layoutSubviews(bool force = false) override; void drawRect(KDContext * ctx, KDRect rect) const override; KDSize minimalSizeForOptimalDisplay() const override; diff --git a/escher/include/escher/layout_field.h b/escher/include/escher/layout_field.h index 1f5723c4a..c3716b4be 100644 --- a/escher/include/escher/layout_field.h +++ b/escher/include/escher/layout_field.h @@ -60,7 +60,7 @@ private: bool setEditing(bool isEditing); // returns True if LayoutField should reload void setBackgroundColor(KDColor c) { m_expressionView.setBackgroundColor(c); } void setCursor(Poincare::LayoutCursor cursor) { m_cursor = cursor; } - void cursorPositionChanged() { layoutCursorSubview(); } + void cursorPositionChanged() { layoutCursorSubview(false); } KDRect cursorRect() { return m_cursorView.frame(); } Poincare::LayoutCursor * cursor() { return &m_cursor; } const ExpressionView * expressionView() const { return &m_expressionView; } @@ -70,8 +70,8 @@ private: private: int numberOfSubviews() const override { return 2; } View * subviewAtIndex(int index) override; - void layoutSubviews() override; - void layoutCursorSubview(); + void layoutSubviews(bool force = false) override; + void layoutCursorSubview(bool force); Poincare::LayoutCursor m_cursor; ExpressionView m_expressionView; TextCursorView m_cursorView; diff --git a/escher/include/escher/message_table_cell_with_editable_text.h b/escher/include/escher/message_table_cell_with_editable_text.h index 089d165fc..54e0e19c6 100644 --- a/escher/include/escher/message_table_cell_with_editable_text.h +++ b/escher/include/escher/message_table_cell_with_editable_text.h @@ -28,7 +28,7 @@ public: void setAccessoryText(const char * text); void setTextColor(KDColor color) override; private: - void layoutSubviews() override; + void layoutSubviews(bool force = false) override; TextField m_textField; char m_textBody[Poincare::PrintFloat::k_maxFloatCharSize]; }; diff --git a/escher/include/escher/modal_view_controller.h b/escher/include/escher/modal_view_controller.h index 1bce427ad..3de43abbb 100644 --- a/escher/include/escher/modal_view_controller.h +++ b/escher/include/escher/modal_view_controller.h @@ -28,7 +28,7 @@ private: void setMainView(View * regularView); int numberOfSubviews() const override; View * subviewAtIndex(int index) override; - void layoutSubviews() override; + void layoutSubviews(bool force = false) override; void presentModalView(View * modalView, float verticalAlignment, float horizontalAlignment, KDCoordinate topMargin, KDCoordinate leftMargin, KDCoordinate bottomMargin, KDCoordinate rightMargin); void dismissModalView(); diff --git a/escher/include/escher/scroll_view.h b/escher/include/escher/scroll_view.h index 920860fc7..e2c2635ea 100644 --- a/escher/include/escher/scroll_view.h +++ b/escher/include/escher/scroll_view.h @@ -35,7 +35,7 @@ public: virtual ~Decorator() = default; virtual int numberOfIndicators() const { return 0; } virtual View * indicatorAtIndex(int index) { assert(false); return nullptr; } - virtual KDRect layoutIndicators(KDSize content, KDPoint offset, KDRect frame, KDRect * dirtyRect1, KDRect * dirtyRect2) { return frame; } + virtual KDRect layoutIndicators(KDSize content, KDPoint offset, KDRect frame, KDRect * dirtyRect1, KDRect * dirtyRect2, bool force) { return frame; } virtual void setBackgroundColor(KDColor c) {} }; @@ -44,7 +44,7 @@ public: BarDecorator() : m_verticalBar(), m_horizontalBar() {} int numberOfIndicators() const override { return 2; } View * indicatorAtIndex(int index) override; - KDRect layoutIndicators(KDSize content, KDPoint offset, KDRect frame, KDRect * dirtyRect1, KDRect * dirtyRect2) override; + KDRect layoutIndicators(KDSize content, KDPoint offset, KDRect frame, KDRect * dirtyRect1, KDRect * dirtyRect2, bool force) override; ScrollViewVerticalBar * verticalBar() { return &m_verticalBar; } ScrollViewHorizontalBar * horizontalBar() { return &m_horizontalBar; } private: @@ -63,7 +63,7 @@ public: {} int numberOfIndicators() const override { return 4; } View * indicatorAtIndex(int index) override; - KDRect layoutIndicators(KDSize content, KDPoint offset, KDRect frame, KDRect * dirtyRect1, KDRect * dirtyRect2) override; + KDRect layoutIndicators(KDSize content, KDPoint offset, KDRect frame, KDRect * dirtyRect1, KDRect * dirtyRect2, bool force) override; void setBackgroundColor(KDColor c) override; private: ScrollViewArrow m_topArrow; @@ -96,7 +96,7 @@ protected: return m_frame.height() - m_topMargin - m_bottomMargin; } KDRect visibleContentRect(); - void layoutSubviews() override; + void layoutSubviews(bool force = false) override; virtual KDSize contentSize() const { return m_contentView->minimalSizeForOptimalDisplay(); } #if ESCHER_VIEW_LOGGING virtual const char * className() const override; diff --git a/escher/include/escher/stack_view_controller.h b/escher/include/escher/stack_view_controller.h index 7675072c4..47addd0ea 100644 --- a/escher/include/escher/stack_view_controller.h +++ b/escher/include/escher/stack_view_controller.h @@ -57,7 +57,7 @@ private: private: int numberOfSubviews() const override; View * subviewAtIndex(int index) override; - void layoutSubviews() override; + void layoutSubviews(bool force = false) override; StackView m_stackViews[kMaxNumberOfStacks]; View * m_contentView; diff --git a/escher/include/escher/tab_view.h b/escher/include/escher/tab_view.h index ab662d356..ebfaba6af 100644 --- a/escher/include/escher/tab_view.h +++ b/escher/include/escher/tab_view.h @@ -27,7 +27,7 @@ private: constexpr static KDCoordinate k_activeTabHeight = 5; int numberOfSubviews() const override; View * subviewAtIndex(int index) override; - void layoutSubviews() override; + void layoutSubviews(bool force = false) override; constexpr static uint8_t k_maxNumberOfTabs = 4; TabViewCell m_cells[k_maxNumberOfTabs]; diff --git a/escher/include/escher/tab_view_controller.h b/escher/include/escher/tab_view_controller.h index f7bed6244..11d193b38 100644 --- a/escher/include/escher/tab_view_controller.h +++ b/escher/include/escher/tab_view_controller.h @@ -37,7 +37,7 @@ private: private: int numberOfSubviews() const override; View * subviewAtIndex(int index) override; - void layoutSubviews() override; + void layoutSubviews(bool force = false) override; View * m_activeView; }; diff --git a/escher/include/escher/table_cell.h b/escher/include/escher/table_cell.h index 8058a090d..e5f7cb730 100644 --- a/escher/include/escher/table_cell.h +++ b/escher/include/escher/table_cell.h @@ -20,7 +20,7 @@ public: protected: int numberOfSubviews() const override; View * subviewAtIndex(int index) override; - void layoutSubviews() override; + void layoutSubviews(bool force = false) override; constexpr static KDCoordinate k_separatorThickness = Metric::CellSeparatorThickness; private: constexpr static KDCoordinate k_accessoryBottomMargin = 3; diff --git a/escher/include/escher/table_view.h b/escher/include/escher/table_view.h index 5c16a8c30..b7eb77ae5 100644 --- a/escher/include/escher/table_view.h +++ b/escher/include/escher/table_view.h @@ -25,7 +25,7 @@ protected: const char * className() const override; #endif TableViewDataSource * dataSource(); - void layoutSubviews() override; + void layoutSubviews(bool force = false) override; class ContentView : public View { public: ContentView(TableView * tableView, TableViewDataSource * dataSource, KDCoordinate horizontalCellOverlap, KDCoordinate verticalCellOverlap); @@ -42,7 +42,7 @@ protected: int numberOfDisplayableRows() const; int numberOfDisplayableColumns() const; KDRect cellFrame(int i, int j) const; - void layoutSubviews() override; + void layoutSubviews(bool force = false) override; protected: #if ESCHER_VIEW_LOGGING const char * className() const override; diff --git a/escher/include/escher/text_field.h b/escher/include/escher/text_field.h index 2c6e97211..1bc8efbdf 100644 --- a/escher/include/escher/text_field.h +++ b/escher/include/escher/text_field.h @@ -75,7 +75,7 @@ protected: * = 212 characters. */ constexpr static int k_maxBufferSize = 220; private: - void layoutSubviews() override; + void layoutSubviews(bool force = false) override; KDRect glyphFrameAtPosition(const char * buffer, const char * position) const override; bool m_isEditing; char * m_textBuffer; diff --git a/escher/include/escher/text_input.h b/escher/include/escher/text_input.h index 633fcd790..90cd79a1e 100644 --- a/escher/include/escher/text_input.h +++ b/escher/include/escher/text_input.h @@ -34,7 +34,7 @@ protected: virtual bool removeEndOfLine() = 0; KDRect cursorRect(); protected: - virtual void layoutSubviews() override; + virtual void layoutSubviews(bool force = false) override; void reloadRectFromPosition(const char * position, bool lineBreak = false); virtual KDRect glyphFrameAtPosition(const char * buffer, const char * position) const = 0; TextCursorView m_cursorView; diff --git a/escher/include/escher/view.h b/escher/include/escher/view.h index a5fa14056..e0cd46d34 100644 --- a/escher/include/escher/view.h +++ b/escher/include/escher/view.h @@ -54,7 +54,7 @@ public: } void setSize(KDSize size); - void setFrame(KDRect frame); + void setFrame(KDRect frame, bool force); KDPoint pointFromPointInView(View * view, KDPoint point); KDRect bounds() const; diff --git a/escher/include/escher/warning_controller.h b/escher/include/escher/warning_controller.h index 464e1509a..c9cbec7f8 100644 --- a/escher/include/escher/warning_controller.h +++ b/escher/include/escher/warning_controller.h @@ -20,7 +20,7 @@ private: void setLabels(I18n::Message message1, I18n::Message message2); int numberOfSubviews() const override; View * subviewAtIndex(int index) override; - void layoutSubviews() override; + void layoutSubviews(bool force = false) override; KDSize minimalSizeForOptimalDisplay() const override; private: constexpr static KDCoordinate k_topAndBottomMargin = 20; diff --git a/escher/include/escher/window.h b/escher/include/escher/window.h index 931f07e3e..553b386f4 100644 --- a/escher/include/escher/window.h +++ b/escher/include/escher/window.h @@ -13,7 +13,7 @@ protected: const char * className() const override; #endif virtual int numberOfSubviews() const override; - virtual void layoutSubviews() override; + virtual void layoutSubviews(bool force = false) override; virtual View * subviewAtIndex(int index) override; View * m_contentView; private: diff --git a/escher/src/alternate_empty_view_controller.cpp b/escher/src/alternate_empty_view_controller.cpp index 9dc3c33d4..be61f67f2 100644 --- a/escher/src/alternate_empty_view_controller.cpp +++ b/escher/src/alternate_empty_view_controller.cpp @@ -22,11 +22,11 @@ View * AlternateEmptyViewController::ContentView::subviewAtIndex(int index) { return m_mainViewController->view(); } -void AlternateEmptyViewController::ContentView::layoutSubviews() { +void AlternateEmptyViewController::ContentView::layoutSubviews(bool force) { if (alternateEmptyViewDelegate()->isEmpty()) { - m_delegate->emptyView()->setFrame(bounds()); + m_delegate->emptyView()->setFrame(bounds(), force); } else { - m_mainViewController->view()->setFrame(bounds()); + m_mainViewController->view()->setFrame(bounds(), force); } } diff --git a/escher/src/button.cpp b/escher/src/button.cpp index 3c9551f2e..91a09c318 100644 --- a/escher/src/button.cpp +++ b/escher/src/button.cpp @@ -24,8 +24,8 @@ View * Button::subviewAtIndex(int index) { return &m_messageTextView; } -void Button::layoutSubviews() { - m_messageTextView.setFrame(bounds()); +void Button::layoutSubviews(bool force) { + m_messageTextView.setFrame(bounds(), force); } bool Button::handleEvent(Ion::Events::Event event) { diff --git a/escher/src/button_row_controller.cpp b/escher/src/button_row_controller.cpp index 479d1c140..4a0633764 100644 --- a/escher/src/button_row_controller.cpp +++ b/escher/src/button_row_controller.cpp @@ -49,12 +49,12 @@ View * ButtonRowController::ContentView::subviewAtIndex(int index) { } } -void ButtonRowController::ContentView::layoutSubviews() { +void ButtonRowController::ContentView::layoutSubviews(bool force) { /* Position the main view */ if (numberOfButtons() == 0) { KDCoordinate margin = m_position == Position::Top ? 1 : 0; KDRect mainViewFrame(0, margin, bounds().width(), bounds().height()-margin); - m_mainViewController->view()->setFrame(mainViewFrame); + m_mainViewController->view()->setFrame(mainViewFrame, force); return; } KDCoordinate rowHeight; @@ -65,7 +65,7 @@ void ButtonRowController::ContentView::layoutSubviews() { } KDCoordinate frameOrigin = m_position == Position::Top ? rowHeight+1 : 0; KDRect mainViewFrame(0, frameOrigin, bounds().width(), bounds().height() - rowHeight - 1); - m_mainViewController->view()->setFrame(mainViewFrame); + m_mainViewController->view()->setFrame(mainViewFrame, force); /* Position buttons */ int nbOfButtons = numberOfButtons(); @@ -88,7 +88,7 @@ void ButtonRowController::ContentView::layoutSubviews() { Button * button = buttonAtIndex(i); KDCoordinate buttonWidth = button->minimalSizeForOptimalDisplay().width(); KDRect buttonFrame(currentXOrigin, yOrigin, buttonWidth, buttonHeight); - button->setFrame(buttonFrame); + button->setFrame(buttonFrame, force); currentXOrigin += buttonWidth + widthMargin; } } diff --git a/escher/src/editable_text_cell.cpp b/escher/src/editable_text_cell.cpp index 98f47e1ad..85960ef75 100644 --- a/escher/src/editable_text_cell.cpp +++ b/escher/src/editable_text_cell.cpp @@ -43,12 +43,13 @@ View * EditableTextCell::subviewAtIndex(int index) { return &m_textField; } -void EditableTextCell::layoutSubviews() { +void EditableTextCell::layoutSubviews(bool force) { KDRect cellBounds = bounds(); m_textField.setFrame(KDRect(cellBounds.x() + m_leftMargin, cellBounds.y() + m_topMargin, cellBounds.width() - m_leftMargin - m_rightMargin, - cellBounds.height() - m_topMargin - m_bottomMargin)); + cellBounds.height() - m_topMargin - m_bottomMargin), + force); } void EditableTextCell::didBecomeFirstResponder() { diff --git a/escher/src/even_odd_buffer_text_cell.cpp b/escher/src/even_odd_buffer_text_cell.cpp index 48e3ba1ea..f5c2d7968 100644 --- a/escher/src/even_odd_buffer_text_cell.cpp +++ b/escher/src/even_odd_buffer_text_cell.cpp @@ -38,8 +38,8 @@ View * EvenOddBufferTextCell::subviewAtIndex(int index) { return &m_bufferTextView; } -void EvenOddBufferTextCell::layoutSubviews() { +void EvenOddBufferTextCell::layoutSubviews(bool force) { KDRect boundsThis = bounds(); KDRect boundsBuffer = KDRect(boundsThis.left() + k_horizontalMargin, boundsThis.top(), boundsThis.width() - 2*k_horizontalMargin, boundsThis.height()); - m_bufferTextView.setFrame(boundsBuffer); + m_bufferTextView.setFrame(boundsBuffer, force); } diff --git a/escher/src/even_odd_cell_with_ellipsis.cpp b/escher/src/even_odd_cell_with_ellipsis.cpp index 4a43cc5f9..53a85c298 100644 --- a/escher/src/even_odd_cell_with_ellipsis.cpp +++ b/escher/src/even_odd_cell_with_ellipsis.cpp @@ -5,6 +5,6 @@ EvenOddCellWithEllipsis::EvenOddCellWithEllipsis() : { } -void EvenOddCellWithEllipsis::layoutSubviews() { - m_ellipsisView.setFrame(bounds()); +void EvenOddCellWithEllipsis::layoutSubviews(bool force) { + m_ellipsisView.setFrame(bounds(), force); } diff --git a/escher/src/even_odd_editable_text_cell.cpp b/escher/src/even_odd_editable_text_cell.cpp index 1f1c96030..819b05892 100644 --- a/escher/src/even_odd_editable_text_cell.cpp +++ b/escher/src/even_odd_editable_text_cell.cpp @@ -32,8 +32,8 @@ View * EvenOddEditableTextCell::subviewAtIndex(int index) { return &m_editableCell; } -void EvenOddEditableTextCell::layoutSubviews() { - m_editableCell.setFrame(bounds()); +void EvenOddEditableTextCell::layoutSubviews(bool force) { + m_editableCell.setFrame(bounds(), force); } void EvenOddEditableTextCell::didBecomeFirstResponder() { diff --git a/escher/src/even_odd_expression_cell.cpp b/escher/src/even_odd_expression_cell.cpp index 8709cc829..0ceaeb51c 100644 --- a/escher/src/even_odd_expression_cell.cpp +++ b/escher/src/even_odd_expression_cell.cpp @@ -65,6 +65,6 @@ View * EvenOddExpressionCell::subviewAtIndex(int index) { return &m_expressionView; } -void EvenOddExpressionCell::layoutSubviews() { - m_expressionView.setFrame(KDRect(m_leftMargin, 0, bounds().width() - m_leftMargin - m_rightMargin, bounds().height())); +void EvenOddExpressionCell::layoutSubviews(bool force) { + m_expressionView.setFrame(KDRect(m_leftMargin, 0, bounds().width() - m_leftMargin - m_rightMargin, bounds().height()), force); } diff --git a/escher/src/even_odd_message_text_cell.cpp b/escher/src/even_odd_message_text_cell.cpp index 359a8b38b..873ad9285 100644 --- a/escher/src/even_odd_message_text_cell.cpp +++ b/escher/src/even_odd_message_text_cell.cpp @@ -35,7 +35,7 @@ View * EvenOddMessageTextCell::subviewAtIndex(int index) { return &m_messageTextView; } -void EvenOddMessageTextCell::layoutSubviews() { +void EvenOddMessageTextCell::layoutSubviews(bool force) { KDRect boundsThis = bounds(); - m_messageTextView.setFrame(KDRect(k_horizontalMargin, 0, boundsThis.width() - 2*k_horizontalMargin, boundsThis.height())); + m_messageTextView.setFrame(KDRect(k_horizontalMargin, 0, boundsThis.width() - 2*k_horizontalMargin, boundsThis.height()), force); } diff --git a/escher/src/expression_field.cpp b/escher/src/expression_field.cpp index c9c87a32d..7d274ed8f 100644 --- a/escher/src/expression_field.cpp +++ b/escher/src/expression_field.cpp @@ -62,15 +62,15 @@ View * ExpressionField::subviewAtIndex(int index) { return &m_layoutField; } -void ExpressionField::layoutSubviews() { +void ExpressionField::layoutSubviews(bool force) { KDRect inputViewFrame(0, k_separatorThickness, bounds().width(), bounds().height() - k_separatorThickness); if (editionIsInTextField()) { - m_textField.setFrame(inputViewFrame); - m_layoutField.setFrame(KDRectZero); + m_textField.setFrame(inputViewFrame, force); + m_layoutField.setFrame(KDRectZero, force); return; } - m_layoutField.setFrame(inputViewFrame); - m_textField.setFrame(KDRectZero); + m_layoutField.setFrame(inputViewFrame, force); + m_textField.setFrame(KDRectZero, force); } void ExpressionField::reload() { diff --git a/escher/src/layout_field.cpp b/escher/src/layout_field.cpp index 705631002..27ac646b5 100644 --- a/escher/src/layout_field.cpp +++ b/escher/src/layout_field.cpp @@ -53,14 +53,14 @@ View * LayoutField::ContentView::subviewAtIndex(int index) { return m_views[index]; } -void LayoutField::ContentView::layoutSubviews() { - m_expressionView.setFrame(bounds()); - layoutCursorSubview(); +void LayoutField::ContentView::layoutSubviews(bool force) { + m_expressionView.setFrame(bounds(), force); + layoutCursorSubview(force); } -void LayoutField::ContentView::layoutCursorSubview() { +void LayoutField::ContentView::layoutCursorSubview(bool force) { if (!m_isEditing) { - m_cursorView.setFrame(KDRectZero); + m_cursorView.setFrame(KDRectZero, force); return; } KDPoint expressionViewOrigin = m_expressionView.absoluteDrawingOrigin(); @@ -77,7 +77,7 @@ void LayoutField::ContentView::layoutCursorSubview() { cursorX += pointedLayoutR.layoutSize().width(); } KDPoint cursorTopLeftPosition(cursorX, expressionViewOrigin.y() + cursoredExpressionViewOrigin.y() + pointedLayoutR.baseline() - m_cursor.baseline()); - m_cursorView.setFrame(KDRect(cursorTopLeftPosition, LayoutCursor::k_cursorWidth, m_cursor.cursorHeight())); + m_cursorView.setFrame(KDRect(cursorTopLeftPosition, LayoutCursor::k_cursorWidth, m_cursor.cursorHeight()), force); } void LayoutField::setEditing(bool isEditing) { diff --git a/escher/src/message_table_cell_with_editable_text.cpp b/escher/src/message_table_cell_with_editable_text.cpp index 64b1d1629..09c7d49a0 100644 --- a/escher/src/message_table_cell_with_editable_text.cpp +++ b/escher/src/message_table_cell_with_editable_text.cpp @@ -46,12 +46,17 @@ void MessageTableCellWithEditableText::setTextColor(KDColor color) { MessageTableCell::setTextColor(color); } -void MessageTableCellWithEditableText::layoutSubviews() { - TableCell::layoutSubviews(); +void MessageTableCellWithEditableText::layoutSubviews(bool force) { + TableCell::layoutSubviews(force); KDSize textFieldSize = m_textField.minimalSizeForOptimalDisplay(); KDSize labelSize = labelView()->minimalSizeForOptimalDisplay(); /* Handle textfield that has no defined width (as their width evolves with * the length of edited text */ textFieldSize = KDSize(bounds().width() - 2*k_separatorThickness - labelSize.width()-2*k_labelMargin-k_accessoryMargin, textFieldSize.height()); - m_textField.setFrame(KDRect(bounds().width() - textFieldSize.width() - k_separatorThickness-k_accessoryMargin, (bounds().height()-textFieldSize.height()-k_accessoryMargin)/2, textFieldSize.width(), textFieldSize.height()+k_accessoryMargin)); + m_textField.setFrame(KDRect( + bounds().width() - textFieldSize.width() - k_separatorThickness-k_accessoryMargin, + (bounds().height()-textFieldSize.height()-k_accessoryMargin)/2, + textFieldSize.width(), + textFieldSize.height()+k_accessoryMargin), + force); } diff --git a/escher/src/modal_view_controller.cpp b/escher/src/modal_view_controller.cpp index 699d75436..57e3d5c1a 100644 --- a/escher/src/modal_view_controller.cpp +++ b/escher/src/modal_view_controller.cpp @@ -54,15 +54,15 @@ KDRect ModalViewController::ContentView::modalViewFrame() const { return modalViewFrame; } -void ModalViewController::ContentView::layoutSubviews() { +void ModalViewController::ContentView::layoutSubviews(bool force) { assert(m_regularView != nullptr); - m_regularView->setFrame(bounds()); + m_regularView->setFrame(bounds(), force); if (m_isDisplayingModal) { assert(m_currentModalView != nullptr); - m_currentModalView->setFrame(modalViewFrame()); + m_currentModalView->setFrame(modalViewFrame(), force); } else { if (m_currentModalView) { - m_currentModalView->setFrame(KDRectZero); + m_currentModalView->setFrame(KDRectZero, force); } } } diff --git a/escher/src/scroll_view.cpp b/escher/src/scroll_view.cpp index e6947cde7..834aae7c0 100644 --- a/escher/src/scroll_view.cpp +++ b/escher/src/scroll_view.cpp @@ -93,20 +93,20 @@ KDRect ScrollView::visibleContentRect() { m_frame.height() - m_topMargin - m_bottomMargin); } -void ScrollView::layoutSubviews() { +void ScrollView::layoutSubviews(bool force) { KDRect r1 = KDRectZero; KDRect r2 = KDRectZero; - KDRect innerFrame = decorator()->layoutIndicators(minimalSizeForOptimalDisplay(), contentOffset(), bounds(), &r1, &r2); + KDRect innerFrame = decorator()->layoutIndicators(minimalSizeForOptimalDisplay(), contentOffset(), bounds(), &r1, &r2, force); if (!r1.isEmpty()) { markRectAsDirty(r1); } if (!r2.isEmpty()) { markRectAsDirty(r2); } - m_innerView.setFrame(innerFrame); + m_innerView.setFrame(innerFrame, force); KDPoint absoluteOffset = contentOffset().opposite().translatedBy(KDPoint(m_leftMargin - innerFrame.x(), m_topMargin - innerFrame.y())); KDRect contentFrame = KDRect(absoluteOffset, contentSize()); - m_contentView->setFrame(contentFrame); + m_contentView->setFrame(contentFrame, force); } void ScrollView::setContentOffset(KDPoint offset, bool forceRelayout) { @@ -136,7 +136,7 @@ View * ScrollView::BarDecorator::indicatorAtIndex(int index) { return &m_horizontalBar; } -KDRect ScrollView::BarDecorator::layoutIndicators(KDSize content, KDPoint offset, KDRect frame, KDRect * dirtyRect1, KDRect * dirtyRect2) { +KDRect ScrollView::BarDecorator::layoutIndicators(KDSize content, KDPoint offset, KDRect frame, KDRect * dirtyRect1, KDRect * dirtyRect2, bool force) { bool hBarWasVisible = m_horizontalBar.visible(); bool hBarIsVisible = m_horizontalBar.update(content.width(), offset.x(), frame.width()); bool vBarWasVisible = m_verticalBar.visible(); @@ -152,13 +152,13 @@ KDRect ScrollView::BarDecorator::layoutIndicators(KDSize content, KDPoint offset /* If the two indicators are visible, we leave an empty rectangle in the right * bottom corner. Otherwise, the only indicator uses all the height/width. */ m_verticalBar.setFrame(KDRect( - frame.width() - vBarFrameBreadth, 0, - vBarFrameBreadth, frame.height() - hBarFrameBreadth - )); + frame.width() - vBarFrameBreadth, 0, + vBarFrameBreadth, frame.height() - hBarFrameBreadth), + force); m_horizontalBar.setFrame(KDRect( - 0, frame.height() - hBarFrameBreadth, - frame.width() - vBarFrameBreadth, hBarFrameBreadth - )); + 0, frame.height() - hBarFrameBreadth, + frame.width() - vBarFrameBreadth, hBarFrameBreadth), + force); return frame; } @@ -176,7 +176,7 @@ View * ScrollView::ArrowDecorator::indicatorAtIndex(int index) { } } -KDRect ScrollView::ArrowDecorator::layoutIndicators(KDSize content, KDPoint offset, KDRect frame, KDRect * dirtyRect1, KDRect * dirtyRect2) { +KDRect ScrollView::ArrowDecorator::layoutIndicators(KDSize content, KDPoint offset, KDRect frame, KDRect * dirtyRect1, KDRect * dirtyRect2, bool force) { // There is no need to dirty the rects KDSize arrowSize = KDFont::LargeFont->glyphSize(); KDCoordinate topArrowFrameBreadth = arrowSize.height() * m_topArrow.update(0 < offset.y()); @@ -184,21 +184,21 @@ KDRect ScrollView::ArrowDecorator::layoutIndicators(KDSize content, KDPoint offs KDCoordinate bottomArrowFrameBreadth = arrowSize.height() * m_bottomArrow.update(offset.y() + frame.height() < content.height()); KDCoordinate leftArrowFrameBreadth = arrowSize.width() * m_leftArrow.update(0 < offset.x()); m_topArrow.setFrame(KDRect( - 0, 0, - frame.width(), topArrowFrameBreadth - )); + 0, 0, + frame.width(), topArrowFrameBreadth), + force); m_rightArrow.setFrame(KDRect( - frame.width() - rightArrowFrameBreadth, 0, - rightArrowFrameBreadth, frame.height() - )); + frame.width() - rightArrowFrameBreadth, 0, + rightArrowFrameBreadth, frame.height()), + force); m_bottomArrow.setFrame(KDRect( - 0, frame.height() - bottomArrowFrameBreadth, - frame.width(), bottomArrowFrameBreadth - )); + 0, frame.height() - bottomArrowFrameBreadth, + frame.width(), bottomArrowFrameBreadth), + force); m_leftArrow.setFrame(KDRect( - 0, 0, - leftArrowFrameBreadth, frame.height() - )); + 0, 0, + leftArrowFrameBreadth, frame.height()), + force); return KDRect( frame.x() + leftArrowFrameBreadth, frame.y() + topArrowFrameBreadth, diff --git a/escher/src/stack_view_controller.cpp b/escher/src/stack_view_controller.cpp index f19ee1261..8aa337d17 100644 --- a/escher/src/stack_view_controller.cpp +++ b/escher/src/stack_view_controller.cpp @@ -36,20 +36,20 @@ void StackViewController::ControllerView::popStack() { m_numberOfStacks--; } -void StackViewController::ControllerView::layoutSubviews() { +void StackViewController::ControllerView::layoutSubviews(bool force) { KDCoordinate width = m_frame.width(); if (m_displayStackHeaders) { for (int i=0; i 0 ? 1 : 0; - KDRect contentViewFrame = KDRect( 0, + KDRect contentViewFrame = KDRect(0, m_displayStackHeaders * (m_numberOfStacks * Metric::StackTitleHeight + separatorHeight), width, m_frame.height() - m_displayStackHeaders * m_numberOfStacks * Metric::StackTitleHeight); - m_contentView->setFrame(contentViewFrame); + m_contentView->setFrame(contentViewFrame, force); } } diff --git a/escher/src/tab_view.cpp b/escher/src/tab_view.cpp index 46c458810..e0c9691ee 100644 --- a/escher/src/tab_view.cpp +++ b/escher/src/tab_view.cpp @@ -66,7 +66,7 @@ View * TabView::subviewAtIndex(int index) { return &m_cells[index]; } -void TabView::layoutSubviews() { +void TabView::layoutSubviews(bool force) { KDCoordinate emptyWidth = bounds().width(); for (int i=0; isetFrame(activeViewFrame); + m_activeView->setFrame(activeViewFrame, force); } } diff --git a/escher/src/table_cell.cpp b/escher/src/table_cell.cpp index 14a2a3de3..40e70235b 100644 --- a/escher/src/table_cell.cpp +++ b/escher/src/table_cell.cpp @@ -38,7 +38,7 @@ View * TableCell::subviewAtIndex(int index) { * margins (like ExpressionView), sometimes the subview has no margins (like * MessageView) which prevents us to handle margins only here. */ -void TableCell::layoutSubviews() { +void TableCell::layoutSubviews(bool force) { KDCoordinate width = bounds().width(); KDCoordinate height = bounds().height(); View * label = labelView(); @@ -50,14 +50,16 @@ void TableCell::layoutSubviews() { k_separatorThickness+k_labelMargin, k_separatorThickness+Metric::TableCellLabelTopMargin, width-2*k_separatorThickness-k_labelMargin, - labelSize.height())); + labelSize.height()), + force); break; default: label->setFrame(KDRect( k_separatorThickness+k_labelMargin, k_separatorThickness, labelSize.width(), - height - 2*k_separatorThickness)); + height - 2*k_separatorThickness), + force); break; } } @@ -70,7 +72,8 @@ void TableCell::layoutSubviews() { k_separatorThickness+k_accessoryMargin, height-k_separatorThickness-accessorySize.height()-k_accessoryBottomMargin, width-2*k_separatorThickness - k_accessoryMargin, - accessorySize.height())); + accessorySize.height()), + force); break; default: // In some cases, the accessory view cannot take all the size it can @@ -81,13 +84,15 @@ void TableCell::layoutSubviews() { wantedX, k_separatorThickness, accessorySize.width(), - height-2*k_separatorThickness)); + height-2*k_separatorThickness), + force); } else { accessory->setFrame(KDRect( minX, k_separatorThickness, accessorySize.width(), - height-2*k_separatorThickness)); + height-2*k_separatorThickness), + force); } break; } @@ -97,7 +102,7 @@ void TableCell::layoutSubviews() { KDSize accessorySize = accessory->minimalSizeForOptimalDisplay(); KDSize subAccessorySize = subAccessory->minimalSizeForOptimalDisplay(); subAccessory->setFrame(KDRect(width-k_separatorThickness-k_accessoryMargin-accessorySize.width()-subAccessorySize.width(), k_separatorThickness, - subAccessorySize.width(), height-2*k_separatorThickness)); + subAccessorySize.width(), height-2*k_separatorThickness), force); } } diff --git a/escher/src/table_view.cpp b/escher/src/table_view.cpp index 1172ecbf0..f4c72317e 100644 --- a/escher/src/table_view.cpp +++ b/escher/src/table_view.cpp @@ -33,7 +33,7 @@ const char * TableView::className() const { } #endif -void TableView::layoutSubviews() { +void TableView::layoutSubviews(bool force) { /* On the one hand, ScrollView::layoutSubviews() * calls setFrame(...) over m_contentView, * which typically calls layoutSubviews() over m_contentView. @@ -49,8 +49,8 @@ void TableView::layoutSubviews() { * FIXME: * Finally, this solution is not optimal at all since * layoutSubviews is called twice over m_contentView. */ - m_contentView.layoutSubviews(); - ScrollView::layoutSubviews(); + m_contentView.layoutSubviews(force); + ScrollView::layoutSubviews(force); } void TableView::reloadCellAtLocation(int i, int j) { @@ -166,7 +166,7 @@ View * TableView::ContentView::subviewAtIndex(int index) { return m_dataSource->reusableCell(typeIndex, type); } -void TableView::ContentView::layoutSubviews() { +void TableView::ContentView::layoutSubviews(bool force) { /* The number of subviews might change during the layouting so it needs to be * recomputed at each step of the for loop. */ for (int index = 0; index < numberOfSubviews(); index++) { @@ -174,7 +174,7 @@ void TableView::ContentView::layoutSubviews() { int i = absoluteColumnNumberFromSubviewIndex(index); int j = absoluteRowNumberFromSubviewIndex(index); m_dataSource->willDisplayCellAtLocation((HighlightCell *)cell, i, j); - cell->setFrame(cellFrame(i,j)); + cell->setFrame(cellFrame(i,j), force); } } diff --git a/escher/src/text_field.cpp b/escher/src/text_field.cpp index 78bf2dbe3..267fb18d6 100644 --- a/escher/src/text_field.cpp +++ b/escher/src/text_field.cpp @@ -209,12 +209,12 @@ void TextField::ContentView::didModifyTextBuffer() { layoutSubviews(); } -void TextField::ContentView::layoutSubviews() { +void TextField::ContentView::layoutSubviews(bool force) { if (!m_isEditing) { - m_cursorView.setFrame(KDRectZero); + m_cursorView.setFrame(KDRectZero, force); return; } - TextInput::ContentView::layoutSubviews(); + TextInput::ContentView::layoutSubviews(force); } KDRect TextField::ContentView::glyphFrameAtPosition(const char * buffer, const char * position) const { diff --git a/escher/src/text_input.cpp b/escher/src/text_input.cpp index cb9789a93..b3c392efa 100644 --- a/escher/src/text_input.cpp +++ b/escher/src/text_input.cpp @@ -25,8 +25,8 @@ KDRect TextInput::ContentView::cursorRect() { return glyphFrameAtPosition(editedText(), m_cursorLocation); } -void TextInput::ContentView::layoutSubviews() { - m_cursorView.setFrame(cursorRect()); +void TextInput::ContentView::layoutSubviews(bool force) { + m_cursorView.setFrame(cursorRect(), force); } void TextInput::ContentView::reloadRectFromPosition(const char * position, bool lineBreak) { diff --git a/escher/src/view.cpp b/escher/src/view.cpp index 2542aa0f3..6dcfb4b76 100644 --- a/escher/src/view.cpp +++ b/escher/src/view.cpp @@ -93,11 +93,11 @@ View * View::subview(int index) { } void View::setSize(KDSize size) { - setFrame(KDRect(m_frame.origin(), size)); + setFrame(KDRect(m_frame.origin(), size), false); } -void View::setFrame(KDRect frame) { - if (frame == m_frame) { +void View::setFrame(KDRect frame, bool force) { + if (frame == m_frame && !force) { return; } /* CAUTION: This code is not resilient to multiple consecutive setFrame() @@ -121,7 +121,7 @@ void View::setFrame(KDRect frame) { // FIXME: m_dirtyRect = bounds(); would be more correct (in case the view is being shrinked) if (!m_frame.isEmpty()) { - layoutSubviews(); + layoutSubviews(force); } } diff --git a/escher/src/warning_controller.cpp b/escher/src/warning_controller.cpp index 07bc18f22..a07c11dbf 100644 --- a/escher/src/warning_controller.cpp +++ b/escher/src/warning_controller.cpp @@ -25,18 +25,18 @@ View * WarningController::ContentView::subviewAtIndex(int index) { return views[index]; } -void WarningController::ContentView::layoutSubviews() { +void WarningController::ContentView::layoutSubviews(bool force) { if (numberOfSubviews() == 1) { - m_textView1.setFrame(bounds()); + m_textView1.setFrame(bounds(), force); m_textView1.setAlignment(k_middleAlignment, k_middleAlignment); return; } assert(numberOfSubviews() == 2); KDRect fullBounds = bounds(); KDCoordinate halfHeight = fullBounds.height()/2; - m_textView1.setFrame(KDRect(fullBounds.topLeft(), fullBounds.width(), halfHeight)); + m_textView1.setFrame(KDRect(fullBounds.topLeft(), fullBounds.width(), halfHeight), force); m_textView1.setAlignment(k_middleAlignment, k_shiftedAlignment); - m_textView2.setFrame(KDRect(fullBounds.left(), fullBounds.top()+halfHeight, fullBounds.width(), halfHeight)); + m_textView2.setFrame(KDRect(fullBounds.left(), fullBounds.top()+halfHeight, fullBounds.width(), halfHeight), force); } KDSize WarningController::ContentView::minimalSizeForOptimalDisplay() const { diff --git a/escher/src/window.cpp b/escher/src/window.cpp index 15807f017..b516571c4 100644 --- a/escher/src/window.cpp +++ b/escher/src/window.cpp @@ -31,9 +31,9 @@ View * Window::subviewAtIndex(int index) { return m_contentView; } -void Window::layoutSubviews() { +void Window::layoutSubviews(bool force) { if (m_contentView != nullptr) { - m_contentView->setFrame(bounds()); + m_contentView->setFrame(bounds(), force); } } From 0630ae55c70abcfd5427a9ba4ae47ac4a122e6d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Wed, 2 Oct 2019 11:48:03 +0200 Subject: [PATCH 032/680] [apps/escher] Force expressionField relayout when size changed Scenario: in Calculations and in Graph, edit the layout field by adding many parentheses. When the layout field has maximal height but the parentheses are bigger than it, ther is a margin that appears at the bottom, because we did not relayout the layout field to optimize redrawing. We need to force the relayout, otherwise as the layout field stays we the same frame, the relayouting is not properly done. --- apps/calculation/edit_expression_controller.cpp | 7 +++++++ escher/src/input_view_controller.cpp | 7 +++++++ 2 files changed, 14 insertions(+) diff --git a/apps/calculation/edit_expression_controller.cpp b/apps/calculation/edit_expression_controller.cpp index d72b7fc20..7b60010a2 100644 --- a/apps/calculation/edit_expression_controller.cpp +++ b/apps/calculation/edit_expression_controller.cpp @@ -98,6 +98,13 @@ void EditExpressionController::layoutFieldDidChangeSize(::LayoutField * layoutFi if (!m_inputViewHeightIsMaximal || !newInputViewHeightIsMaximal) { m_inputViewHeightIsMaximal = newInputViewHeightIsMaximal; reloadView(); + } else { + /* The input view is already at maximal size so we do not need to relayout + * the view underneath, but the view inside the input view might still need + * to be relayouted. + * We force the relayout because the frame stays the same but we need to + * propagate a relayout to the content of the field scroll view. */ + m_contentView.expressionField()->layoutSubviews(true); } } diff --git a/escher/src/input_view_controller.cpp b/escher/src/input_view_controller.cpp index 766ad58ae..669c7e60c 100644 --- a/escher/src/input_view_controller.cpp +++ b/escher/src/input_view_controller.cpp @@ -92,6 +92,13 @@ void InputViewController::layoutFieldDidChangeSize(LayoutField * layoutField) { if (!m_inputViewHeightIsMaximal || !newInputViewHeightIsMaximal) { m_inputViewHeightIsMaximal = newInputViewHeightIsMaximal; reloadModalViewController(); + } else { + /* The input view is already at maximal size so we do not need to relayout + * the view underneath, but the view inside the input view might still need + * to be relayouted. + * We force the relayout because the frame stays the same but we need to + * propagate a relayout to the content of the field scroll view. */ + m_expressionFieldController.expressionField()->layoutSubviews(true); } } From 8644d28a0ea3f3e90955ffd0b9784a8284860885 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Wed, 2 Oct 2019 12:02:49 +0200 Subject: [PATCH 033/680] [escher] Force relayouting in a table view --- escher/src/table_view.cpp | 19 ++----------------- 1 file changed, 2 insertions(+), 17 deletions(-) diff --git a/escher/src/table_view.cpp b/escher/src/table_view.cpp index f4c72317e..b98bc909a 100644 --- a/escher/src/table_view.cpp +++ b/escher/src/table_view.cpp @@ -34,23 +34,8 @@ const char * TableView::className() const { #endif void TableView::layoutSubviews(bool force) { - /* On the one hand, ScrollView::layoutSubviews() - * calls setFrame(...) over m_contentView, - * which typically calls layoutSubviews() over m_contentView. - * However, if the frame happens to be unchanged, - * setFrame(...) does not call layoutSubviews. - * On the other hand, calling only m_contentView.layoutSubviews() - * does not relayout ScrollView when the offset - * or the content's size changes. - * For those reasons, we call both of them explicitly. - * Besides, one must call layoutSubviews() over - * m_contentView first, in order to reload the table's data, - * otherwise the table's size might be miscomputed... - * FIXME: - * Finally, this solution is not optimal at all since - * layoutSubviews is called twice over m_contentView. */ - m_contentView.layoutSubviews(force); - ScrollView::layoutSubviews(force); + // We force the layoutSubviews in case the frame did not change. + ScrollView::layoutSubviews(true); } void TableView::reloadCellAtLocation(int i, int j) { From 984bfca68ea2f1a7c6ec938c8da239c31965e63a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Wed, 2 Oct 2019 12:14:02 +0200 Subject: [PATCH 034/680] [escher] ScrollView TODO comment --- escher/include/escher/scroll_view.h | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/escher/include/escher/scroll_view.h b/escher/include/escher/scroll_view.h index e2c2635ea..a5790af32 100644 --- a/escher/include/escher/scroll_view.h +++ b/escher/include/escher/scroll_view.h @@ -6,6 +6,13 @@ #include class ScrollView : public View { + +/* TODO: Should we add a reload method that forces the relayouting of the + * subviews? Or should ScrollView::setFrame always force the layouting of the + * subviews ? Because the scroll view frame might not change but its content + * might need to be relayouted. + * cf TableView, InputViewController, EditExpressionController. */ + public: ScrollView(View * contentView, ScrollViewDataSource * dataSource); ScrollView(ScrollView&& other); From 973c2149d42ba89f5845d4c3196d8c8fb22275b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Wed, 2 Oct 2019 15:33:09 +0200 Subject: [PATCH 035/680] [ion/battery] Battery level has some hysteresis This prevents a blinking battery pictogra wwhen the battery level is at the limit between two states. --- ion/include/ion/battery.h | 11 +++++---- ion/src/device/shared/drivers/battery.cpp | 28 ++++++++++++++++------- 2 files changed, 26 insertions(+), 13 deletions(-) diff --git a/ion/include/ion/battery.h b/ion/include/ion/battery.h index 5540b4479..d1be1f8a0 100644 --- a/ion/include/ion/battery.h +++ b/ion/include/ion/battery.h @@ -1,6 +1,7 @@ #ifndef ION_BATTERY_H #define ION_BATTERY_H +#include /* * * RAIN = External input impedance should be <= to @@ -16,11 +17,11 @@ namespace Battery { bool isCharging(); -enum class Charge { - EMPTY, - LOW, - SOMEWHERE_INBETWEEN, - FULL +enum class Charge : uint8_t { + EMPTY = 0, + LOW = 1, + SOMEWHERE_INBETWEEN = 2, + FULL = 3 }; Charge level(); diff --git a/ion/src/device/shared/drivers/battery.cpp b/ion/src/device/shared/drivers/battery.cpp index 64c393f46..779454096 100644 --- a/ion/src/device/shared/drivers/battery.cpp +++ b/ion/src/device/shared/drivers/battery.cpp @@ -22,16 +22,28 @@ bool isCharging() { } Charge level() { - if (voltage() < 3.6f) { - return Charge::EMPTY; + static Charge previousLevel = Charge::FULL; + + + // Get the current voltage + float currentVoltage = voltage(); + + constexpr static int numberOfChargeStates = 4; + constexpr static int numberOfThresholds = numberOfChargeStates - 1; + constexpr float hysteresis = 0.02f; + const float thresholds[numberOfThresholds] = {3.6f + hysteresis, 3.7f, 3.8f}; // We do not want to lower the threshold for empty battery, so we add the hysteresis to it + int nextLevel = -1; + for (int i = 0; i < numberOfThresholds; i++) { + if (currentVoltage < thresholds[i] + hysteresis * (i < (int)previousLevel ? -1.0f : 1.0f)) { + nextLevel = i; + break; + } } - if (voltage() < 3.7f) { - return Charge::LOW; + if (nextLevel < 0) { + nextLevel = (int) Charge::FULL; } - if (voltage() < 3.8f) { - return Charge::SOMEWHERE_INBETWEEN; - } - return Charge::FULL; + previousLevel = (Charge)nextLevel; + return previousLevel; } float voltage() { From b9bc9008ac0ea76644ada6a79bd7c5e10b0c1bdc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Tue, 24 Sep 2019 14:37:47 +0200 Subject: [PATCH 036/680] [ion] Detect long repeated events This will be use for instance to sroll faster if the user presses the directional keys for a long time --- ion/include/ion/events.h | 2 ++ ion/src/shared/events_keyboard.cpp | 15 +++++++++++++++ ion/src/shared/events_modifier.cpp | 10 +++++++++- 3 files changed, 26 insertions(+), 1 deletion(-) diff --git a/ion/include/ion/events.h b/ion/include/ion/events.h index ed70f4968..ae6d30f69 100644 --- a/ion/include/ion/events.h +++ b/ion/include/ion/events.h @@ -55,6 +55,8 @@ ShiftAlphaStatus shiftAlphaStatus(); void setShiftAlphaStatus(ShiftAlphaStatus s); bool isShiftActive(); bool isAlphaActive(); +void setLongRepetition(bool longRepetition); +bool isLongRepetition(); void updateModifiersFromEvent(Event e); // Plain diff --git a/ion/src/shared/events_keyboard.cpp b/ion/src/shared/events_keyboard.cpp index a9a186275..916f9b999 100644 --- a/ion/src/shared/events_keyboard.cpp +++ b/ion/src/shared/events_keyboard.cpp @@ -20,8 +20,10 @@ static bool sleepWithTimeout(int duration, int * timeout) { Event sLastEvent = Events::None; Keyboard::State sLastKeyboardState; bool sEventIsRepeating = 0; +int sEventRepetitionCount = 0; constexpr int delayBeforeRepeat = 200; constexpr int delayBetweenRepeat = 50; +constexpr int numberOfRepetitionsBeforeLongRepetition = 20; static bool canRepeatEvent(Event e) { return (e == Events::Left || e == Events::Up || e == Events::Down || e == Events::Right || e == Events::Backspace); @@ -29,6 +31,11 @@ static bool canRepeatEvent(Event e) { Event getPlatformEvent(); +void resetLongRepetition() { + sEventRepetitionCount = 0; + setLongRepetition(false); +} + Event getEvent(int * timeout) { assert(*timeout > delayBeforeRepeat); assert(*timeout > delayBetweenRepeat); @@ -47,6 +54,7 @@ Event getEvent(int * timeout) { if (keysSeenTransitionningFromUpToDown != 0) { sEventIsRepeating = false; + resetLongRepetition(); /* The key that triggered the event corresponds to the first non-zero bit * in "match". This is a rather simple logic operation for the which many * processors have an instruction (ARM thumb uses CLZ). @@ -62,6 +70,7 @@ Event getEvent(int * timeout) { if (sleepWithTimeout(10, timeout)) { // Timeout occured + resetLongRepetition(); return Events::None; } time += 10; @@ -73,6 +82,12 @@ Event getEvent(int * timeout) { if (time >= delay) { sEventIsRepeating = true; sLastKeyboardState = state; + if (sEventRepetitionCount < numberOfRepetitionsBeforeLongRepetition) { + sEventRepetitionCount++; + if (sEventRepetitionCount == numberOfRepetitionsBeforeLongRepetition) { + setLongRepetition(true); + } + } return sLastEvent; } } diff --git a/ion/src/shared/events_modifier.cpp b/ion/src/shared/events_modifier.cpp index 959350c8b..9ef033c4f 100644 --- a/ion/src/shared/events_modifier.cpp +++ b/ion/src/shared/events_modifier.cpp @@ -5,6 +5,7 @@ namespace Ion { namespace Events { static ShiftAlphaStatus sShiftAlphaStatus = ShiftAlphaStatus::Default; +static bool sLongRepetition = false; ShiftAlphaStatus shiftAlphaStatus() { return sShiftAlphaStatus; @@ -16,7 +17,14 @@ bool isShiftActive() { bool isAlphaActive() { return sShiftAlphaStatus == ShiftAlphaStatus::Alpha || sShiftAlphaStatus == ShiftAlphaStatus::ShiftAlpha || sShiftAlphaStatus == ShiftAlphaStatus::AlphaLock || sShiftAlphaStatus == ShiftAlphaStatus::ShiftAlphaLock; -; +} + +void setLongRepetition(bool longRepetition) { + sLongRepetition = longRepetition; +} + +bool isLongRepetition() { + return sLongRepetition; } void setShiftAlphaStatus(ShiftAlphaStatus s) { From 1434158beec033a35622206598a266f869834dd8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Tue, 24 Sep 2019 14:38:39 +0200 Subject: [PATCH 037/680] [apps/graph] Faster curve navigation after some time If the user presses the LEft/Right keys for a long time, the cursor will move faster. --- apps/graph/graph/calculation_graph_controller.cpp | 2 +- apps/graph/graph/calculation_graph_controller.h | 2 +- apps/graph/graph/graph_controller.cpp | 4 ++-- apps/graph/graph/graph_controller.h | 2 +- apps/graph/graph/graph_controller_helper.cpp | 13 ++++++------- apps/graph/graph/graph_controller_helper.h | 2 +- apps/graph/graph/tangent_graph_controller.cpp | 2 +- apps/graph/graph/tangent_graph_controller.h | 2 +- apps/regression/graph_controller.cpp | 2 +- apps/regression/graph_controller.h | 2 +- apps/sequence/graph/graph_controller.cpp | 2 +- apps/sequence/graph/graph_controller.h | 2 +- .../simple_interactive_curve_view_controller.cpp | 2 +- .../simple_interactive_curve_view_controller.h | 2 +- 14 files changed, 20 insertions(+), 21 deletions(-) diff --git a/apps/graph/graph/calculation_graph_controller.cpp b/apps/graph/graph/calculation_graph_controller.cpp index 292de3dac..43622b255 100644 --- a/apps/graph/graph/calculation_graph_controller.cpp +++ b/apps/graph/graph/calculation_graph_controller.cpp @@ -70,7 +70,7 @@ bool CalculationGraphController::handleEnter() { return true; } -bool CalculationGraphController::moveCursorHorizontally(int direction) { +bool CalculationGraphController::moveCursorHorizontally(int direction, bool fast) { Coordinate2D newPointOfInterest = computeNewPointOfInterestFromAbscissa(m_cursor->x(), direction); if (std::isnan(newPointOfInterest.x1())) { return false; diff --git a/apps/graph/graph/calculation_graph_controller.h b/apps/graph/graph/calculation_graph_controller.h index a400f56ab..1586bd149 100644 --- a/apps/graph/graph/calculation_graph_controller.h +++ b/apps/graph/graph/calculation_graph_controller.h @@ -33,7 +33,7 @@ private: bool handleZoom(Ion::Events::Event event) override { return false; } bool handleLeftRightEvent(Ion::Events::Event event) override; bool handleEnter() override; - bool moveCursorHorizontally(int direction) override; + bool moveCursorHorizontally(int direction, bool fast = false) override; Shared::InteractiveCurveViewRange * interactiveCurveViewRange() override { return m_graphRange; } Shared::CurveView * curveView() override { return m_graphView; } }; diff --git a/apps/graph/graph/graph_controller.cpp b/apps/graph/graph/graph_controller.cpp index 22b754337..0d206ad9e 100644 --- a/apps/graph/graph/graph_controller.cpp +++ b/apps/graph/graph/graph_controller.cpp @@ -169,9 +169,9 @@ void GraphController::reloadBannerView() { reloadDerivativeInBannerViewForCursorOnFunction(m_cursor, record); } -bool GraphController::moveCursorHorizontally(int direction) { +bool GraphController::moveCursorHorizontally(int direction, bool fast) { Ion::Storage::Record record = functionStore()->activeRecordAtIndex(indexFunctionSelectedByCursor()); - return privateMoveCursorHorizontally(m_cursor, direction, m_graphRange, k_numberOfCursorStepsInGradUnit, record); + return privateMoveCursorHorizontally(m_cursor, direction, m_graphRange, k_numberOfCursorStepsInGradUnit, record, fast); } int GraphController::nextCurveIndexVertically(bool goingUp, int currentSelectedCurve, Poincare::Context * context) const { diff --git a/apps/graph/graph/graph_controller.h b/apps/graph/graph/graph_controller.h index 74f2f1105..8860dd245 100644 --- a/apps/graph/graph/graph_controller.h +++ b/apps/graph/graph/graph_controller.h @@ -27,7 +27,7 @@ private: void selectFunctionWithCursor(int functionIndex) override; BannerView * bannerView() override { return &m_bannerView; } void reloadBannerView() override; - bool moveCursorHorizontally(int direction) override; + bool moveCursorHorizontally(int direction, bool fast = false) override; int nextCurveIndexVertically(bool goingUp, int currentSelectedCurve, Poincare::Context * context) const override; double defaultCursorT(Ion::Storage::Record record) override; Shared::InteractiveCurveViewRange * interactiveCurveViewRange() override { return m_graphRange; } diff --git a/apps/graph/graph/graph_controller_helper.cpp b/apps/graph/graph/graph_controller_helper.cpp index 39e0b35d3..0c21be79c 100644 --- a/apps/graph/graph/graph_controller_helper.cpp +++ b/apps/graph/graph/graph_controller_helper.cpp @@ -12,7 +12,7 @@ namespace Graph { static inline double minDouble(double x, double y) { return x < y ? x : y; } static inline double maxDouble(double x, double y) { return x > y ? x : y; } -bool GraphControllerHelper::privateMoveCursorHorizontally(Shared::CurveViewCursor * cursor, int direction, Shared::InteractiveCurveViewRange * range, int numberOfStepsInGradUnit, Ion::Storage::Record record) { +bool GraphControllerHelper::privateMoveCursorHorizontally(Shared::CurveViewCursor * cursor, int direction, Shared::InteractiveCurveViewRange * range, int numberOfStepsInGradUnit, Ion::Storage::Record record, bool fast) { ExpiringPointer function = App::app()->functionStore()->modelForRecord(record); double tCursorPosition = cursor->t(); double t = tCursorPosition; @@ -28,13 +28,12 @@ bool GraphControllerHelper::privateMoveCursorHorizontally(Shared::CurveViewCurso } function = App::app()->functionStore()->modelForRecord(record); // Reload the expiring pointer double dir = (direction > 0 ? 1.0 : -1.0); - ContinuousFunction::PlotType type = function->plotType(); - if (type == ContinuousFunction::PlotType::Cartesian) { - t += dir * range->xGridUnit()/numberOfStepsInGradUnit; - } else { - assert(type == ContinuousFunction::PlotType::Polar || type == ContinuousFunction::PlotType::Parametric); - t += dir * (tMax-tMin)/k_definitionDomainDivisor; + double step = function->plotType() == ContinuousFunction::PlotType::Cartesian ? range->xGridUnit()/numberOfStepsInGradUnit : (tMax-tMin)/k_definitionDomainDivisor; + if (fast) { + // TODO Navigate quicker the longer the user presses? (slow start) + step *= 5.0; } + t += dir * step; t = maxDouble(tMin, minDouble(tMax, t)); Coordinate2D xy = function->evaluateXYAtParameter(t, App::app()->localContext()); cursor->moveTo(t, xy.x1(), xy.x2()); diff --git a/apps/graph/graph/graph_controller_helper.h b/apps/graph/graph/graph_controller_helper.h index 8f8e2a7b7..dcc6daf02 100644 --- a/apps/graph/graph/graph_controller_helper.h +++ b/apps/graph/graph/graph_controller_helper.h @@ -11,7 +11,7 @@ class App; class GraphControllerHelper { protected: - bool privateMoveCursorHorizontally(Shared::CurveViewCursor * cursor, int direction, Shared::InteractiveCurveViewRange * range, int numberOfStepsInGradUnit, Ion::Storage::Record record); + bool privateMoveCursorHorizontally(Shared::CurveViewCursor * cursor, int direction, Shared::InteractiveCurveViewRange * range, int numberOfStepsInGradUnit, Ion::Storage::Record record, bool fast = false); void reloadDerivativeInBannerViewForCursorOnFunction(Shared::CurveViewCursor * cursor, Ion::Storage::Record record); virtual BannerView * bannerView() = 0; private: diff --git a/apps/graph/graph/tangent_graph_controller.cpp b/apps/graph/graph/tangent_graph_controller.cpp index de88c4fe3..e6bb93a4d 100644 --- a/apps/graph/graph/tangent_graph_controller.cpp +++ b/apps/graph/graph/tangent_graph_controller.cpp @@ -89,7 +89,7 @@ void TangentGraphController::reloadBannerView() { m_bannerView->reload(); } -bool TangentGraphController::moveCursorHorizontally(int direction) { +bool TangentGraphController::moveCursorHorizontally(int direction, bool fast) { return privateMoveCursorHorizontally(m_cursor, direction, m_graphRange, k_numberOfCursorStepsInGradUnit, m_record); } diff --git a/apps/graph/graph/tangent_graph_controller.h b/apps/graph/graph/tangent_graph_controller.h index a1652e0de..7e3103203 100644 --- a/apps/graph/graph/tangent_graph_controller.h +++ b/apps/graph/graph/tangent_graph_controller.h @@ -23,7 +23,7 @@ private: Shared::CurveView * curveView() override { return m_graphView; } BannerView * bannerView() override { return m_bannerView; }; void reloadBannerView() override; - bool moveCursorHorizontally(int direction) override; + bool moveCursorHorizontally(int direction, bool fast = false) override; bool handleEnter() override; GraphView * m_graphView; BannerView * m_bannerView; diff --git a/apps/regression/graph_controller.cpp b/apps/regression/graph_controller.cpp index a78abf7e9..3164fc8be 100644 --- a/apps/regression/graph_controller.cpp +++ b/apps/regression/graph_controller.cpp @@ -232,7 +232,7 @@ void GraphController::reloadBannerView() { m_bannerView.reload(); } -bool GraphController::moveCursorHorizontally(int direction) { +bool GraphController::moveCursorHorizontally(int direction, bool fast) { if (*m_selectedDotIndex >= 0) { int dotSelected = m_store->nextDot(*m_selectedSeriesIndex, direction, *m_selectedDotIndex); if (dotSelected >= 0 && dotSelected < m_store->numberOfPairsOfSeries(*m_selectedSeriesIndex)) { diff --git a/apps/regression/graph_controller.h b/apps/regression/graph_controller.h index ad6c10529..0c35ad9ab 100644 --- a/apps/regression/graph_controller.h +++ b/apps/regression/graph_controller.h @@ -25,7 +25,7 @@ public: int selectedSeriesIndex() const { return *m_selectedSeriesIndex; } // moveCursorHorizontally and Vertically are public to be used in tests - bool moveCursorHorizontally(int direction) override; + bool moveCursorHorizontally(int direction, bool fast = false) override; bool moveCursorVertically(int direction) override; private: diff --git a/apps/sequence/graph/graph_controller.cpp b/apps/sequence/graph/graph_controller.cpp index d77870675..c2c4b8fea 100644 --- a/apps/sequence/graph/graph_controller.cpp +++ b/apps/sequence/graph/graph_controller.cpp @@ -81,7 +81,7 @@ bool GraphController::handleEnter() { return FunctionGraphController::handleEnter(); } -bool GraphController::moveCursorHorizontally(int direction) { +bool GraphController::moveCursorHorizontally(int direction, bool fast) { double xCursorPosition = std::round(m_cursor->x()); if (direction < 0 && xCursorPosition <= 0) { return false; diff --git a/apps/sequence/graph/graph_controller.h b/apps/sequence/graph/graph_controller.h index f0e4bb118..da0e64006 100644 --- a/apps/sequence/graph/graph_controller.h +++ b/apps/sequence/graph/graph_controller.h @@ -25,7 +25,7 @@ public: private: Shared::XYBannerView * bannerView() override { return &m_bannerView; } bool handleEnter() override; - bool moveCursorHorizontally(int direction) override; + bool moveCursorHorizontally(int direction, bool fast = false) override; double defaultCursorT(Ion::Storage::Record record) override; CurveViewRange * interactiveCurveViewRange() override { return m_graphRange; } SequenceStore * functionStore() const override { return static_cast(Shared::FunctionGraphController::functionStore()); } diff --git a/apps/shared/simple_interactive_curve_view_controller.cpp b/apps/shared/simple_interactive_curve_view_controller.cpp index cfde9ec6d..46a4673b1 100644 --- a/apps/shared/simple_interactive_curve_view_controller.cpp +++ b/apps/shared/simple_interactive_curve_view_controller.cpp @@ -45,7 +45,7 @@ bool SimpleInteractiveCurveViewController::handleZoom(Ion::Events::Event event) bool SimpleInteractiveCurveViewController::handleLeftRightEvent(Ion::Events::Event event) { int direction = event == Ion::Events::Left ? -1 : 1; - if (moveCursorHorizontally(direction)) { + if (moveCursorHorizontally(direction, Ion::Events::isLongRepetition())) { interactiveCurveViewRange()->panToMakePointVisible( m_cursor->x(), m_cursor->y(), cursorTopMarginRatio(), k_cursorRightMarginRatio, cursorBottomMarginRatio(), k_cursorLeftMarginRatio diff --git a/apps/shared/simple_interactive_curve_view_controller.h b/apps/shared/simple_interactive_curve_view_controller.h index bf772dfde..fd30d2998 100644 --- a/apps/shared/simple_interactive_curve_view_controller.h +++ b/apps/shared/simple_interactive_curve_view_controller.h @@ -30,7 +30,7 @@ protected: /* the result of moveCursorVertically/Horizontally means: * false -> the cursor cannot move in this direction * true -> the cursor moved */ - virtual bool moveCursorHorizontally(int direction) { return false; }; + virtual bool moveCursorHorizontally(int direction, bool fast = false) { return false; } virtual InteractiveCurveViewRange * interactiveCurveViewRange() = 0; virtual CurveView * curveView() = 0; virtual bool handleEnter() = 0; From 4a41ec0fdae5dfdc8d5b861d41f90ca0ad7fc108 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Fri, 4 Oct 2019 09:41:08 +0200 Subject: [PATCH 038/680] [apps] GlobalPreferences: add font (Large or Small) --- apps/global_preferences.h | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/apps/global_preferences.h b/apps/global_preferences.h index a7d0790ea..ff0d5fb36 100644 --- a/apps/global_preferences.h +++ b/apps/global_preferences.h @@ -21,19 +21,23 @@ public: void setShowPopUp(bool showPopUp) { m_showPopUp = showPopUp; } int brightnessLevel() const { return m_brightnessLevel; } void setBrightnessLevel(int brightnessLevel); + const KDFont * font() const { return m_font; } + void setFont(const KDFont * font) { m_font = font; } constexpr static int NumberOfBrightnessStates = 5; private: GlobalPreferences() : m_language(I18n::Language::EN), m_examMode(ExamMode::Unknown), m_showPopUp(true), - m_brightnessLevel(Ion::Backlight::MaxBrightness) {} + m_brightnessLevel(Ion::Backlight::MaxBrightness), + m_font(KDFont::LargeFont) {} I18n::Language m_language; static_assert((int8_t)GlobalPreferences::ExamMode::Off == 0, "GlobalPreferences::isInExamMode() is not right"); static_assert((int8_t)GlobalPreferences::ExamMode::Unknown < 0, "GlobalPreferences::isInExamMode() is not right"); mutable ExamMode m_examMode; bool m_showPopUp; int m_brightnessLevel; + const KDFont * m_font; }; #endif From 39a6fdaf1c38e41876011bbb9f2035f2b107811b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Fri, 4 Oct 2019 10:40:51 +0200 Subject: [PATCH 039/680] [apps/settings] MainController: get rid of magic numbers --- apps/settings/main_controller.cpp | 26 +++++++++++++------------- apps/settings/main_controller.h | 13 +++++++++++++ 2 files changed, 26 insertions(+), 13 deletions(-) diff --git a/apps/settings/main_controller.cpp b/apps/settings/main_controller.cpp index 74ba5787c..e479266fe 100644 --- a/apps/settings/main_controller.cpp +++ b/apps/settings/main_controller.cpp @@ -66,13 +66,13 @@ bool MainController::handleEvent(Ion::Events::Event event) { if (event == Ion::Events::OK || event == Ion::Events::EXE || event == Ion::Events::Right) { GenericSubController * subController = nullptr; int rowIndex = selectedRow(); - if (rowIndex == 1) { + if (rowIndex == k_indexOfDisplayModeCell) { subController = &m_displayModeController; - } else if (rowIndex == 4 || rowIndex == 5) { + } else if (rowIndex == k_indexOfBrightnessCell || rowIndex == k_indexOfLanguageCell) { assert(false); - } else if (rowIndex == 6) { + } else if (rowIndex == k_indexOfExamModeCell) { subController = &m_examModeController; - } else if (rowIndex == 7 + hasPrompt()) { + } else if (rowIndex == k_indexOfAboutCell + hasPrompt()) { subController = &m_aboutController; } else { subController = &m_preferencesController; @@ -123,10 +123,10 @@ int MainController::reusableCellCount(int type) { } int MainController::typeAtLocation(int i, int j) { - if (j == 4) { + if (j == k_indexOfBrightnessCell) { return 1; } - if (hasPrompt() && j == 7) { + if (hasPrompt() && j == k_indexOfPopUpCell) { return 2; } return 0; @@ -137,18 +137,18 @@ void MainController::willDisplayCellForIndex(HighlightCell * cell, int index) { Preferences * preferences = Preferences::sharedPreferences(); MessageTableCell * myCell = (MessageTableCell *)cell; myCell->setMessage(model()->children(index)->label()); - if (index == 4) { + if (index == k_indexOfBrightnessCell) { MessageTableCellWithGauge * myGaugeCell = (MessageTableCellWithGauge *)cell; GaugeView * myGauge = (GaugeView *)myGaugeCell->accessoryView(); myGauge->setLevel((float)globalPreferences->brightnessLevel()/(float)Ion::Backlight::MaxBrightness); return; } - if (index == 5) { + if (index == k_indexOfLanguageCell) { int index = (int)globalPreferences->language()-1; static_cast(cell)->setSubtitle(I18n::LanguageNames[index]); return; } - if (hasPrompt() && index == 7) { + if (hasPrompt() && index == k_indexOfPopUpCell) { MessageTableCellWithSwitch * mySwitchCell = (MessageTableCellWithSwitch *)cell; SwitchView * mySwitch = (SwitchView *)mySwitchCell->accessoryView(); mySwitch->setState(globalPreferences->showPopUp()); @@ -157,16 +157,16 @@ void MainController::willDisplayCellForIndex(HighlightCell * cell, int index) { MessageTableCellWithChevronAndMessage * myTextCell = (MessageTableCellWithChevronAndMessage *)cell; int childIndex = -1; switch (index) { - case 0: + case k_indexOfAngleUnitCell: childIndex = (int)preferences->angleUnit(); break; - case 1: + case k_indexOfDisplayModeCell: childIndex = (int)preferences->displayMode(); break; - case 2: + case k_indexOfEditionModeCell: childIndex = (int)preferences->editionMode(); break; - case 3: + case k_indexOfComplexFormatCell: childIndex = (int)preferences->complexFormat(); break; } diff --git a/apps/settings/main_controller.h b/apps/settings/main_controller.h index 32db50c66..91187be6f 100644 --- a/apps/settings/main_controller.h +++ b/apps/settings/main_controller.h @@ -27,6 +27,19 @@ public: void willDisplayCellForIndex(HighlightCell * cell, int index) override; void viewWillAppear() override; private: + constexpr static int k_indexOfAngleUnitCell = 0; + constexpr static int k_indexOfDisplayModeCell = k_indexOfAngleUnitCell + 1; + constexpr static int k_indexOfEditionModeCell = k_indexOfDisplayModeCell + 1; + constexpr static int k_indexOfComplexFormatCell = k_indexOfEditionModeCell + 1; + constexpr static int k_indexOfBrightnessCell = k_indexOfComplexFormatCell + 1; + constexpr static int k_indexOfLanguageCell = k_indexOfBrightnessCell + 1; + constexpr static int k_indexOfExamModeCell = k_indexOfLanguageCell + 1; + /* Pop-up cell and About cell are located at the same index because pop-up + * cell is optional. We must always correct k_indexOfAboutCell with + * hasPrompt() (TODO: make hasPrompt() constexpr and correct + * k_indexOfAboutCell) */ + constexpr static int k_indexOfPopUpCell = k_indexOfExamModeCell + 1; + constexpr static int k_indexOfAboutCell = k_indexOfExamModeCell + 1; static const SettingsMessageTree * model(); StackViewController * stackController() const; I18n::Message promptMessage() const; From d48006f994a29fe235e380718ba7b82662e89e18 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Fri, 4 Oct 2019 11:15:13 +0200 Subject: [PATCH 040/680] [apps/settings] Add messages about font sizes --- apps/settings/base.de.i18n | 3 +++ apps/settings/base.en.i18n | 3 +++ apps/settings/base.es.i18n | 3 +++ apps/settings/base.fr.i18n | 3 +++ apps/settings/base.pt.i18n | 3 +++ 5 files changed, 15 insertions(+) diff --git a/apps/settings/base.de.i18n b/apps/settings/base.de.i18n index 248ffa473..24153f83b 100644 --- a/apps/settings/base.de.i18n +++ b/apps/settings/base.de.i18n @@ -22,6 +22,9 @@ Real = "Reel " Cartesian = "Algebraische " Polar = "Polar " Brightness = "Helligkeit" +FontSizes = "Python Schriftgröße" +LargeFont = "Große " +SmallFont = "Kleine " SoftwareVersion = "Softwareversion" SerialNumber = "Seriennummer" UpdatePopUp = "Erinnerung: Update" diff --git a/apps/settings/base.en.i18n b/apps/settings/base.en.i18n index 3683e54ce..b3cfa8804 100644 --- a/apps/settings/base.en.i18n +++ b/apps/settings/base.en.i18n @@ -22,6 +22,9 @@ Real = "Real " Cartesian = "Cartesian " Polar = "Polar " Brightness = "Brightness" +FontSizes = "Python font size" +LargeFont = "Large " +SmallFont = "Small " SoftwareVersion = "Software version" SerialNumber = "Serial number" UpdatePopUp = "Update pop-up" diff --git a/apps/settings/base.es.i18n b/apps/settings/base.es.i18n index 06240e3f3..72318ace0 100644 --- a/apps/settings/base.es.i18n +++ b/apps/settings/base.es.i18n @@ -22,6 +22,9 @@ Real = "Real " Cartesian = "Binómica " Polar = "Polar " Brightness = "Brillo" +FontSizes = "Tipografía Python" +LargeFont = "Grande " +SmallFont = "Pequeño " SoftwareVersion = "Versión de software" SerialNumber = "Número serie" UpdatePopUp = "Pop-up de actualización" diff --git a/apps/settings/base.fr.i18n b/apps/settings/base.fr.i18n index c11f9fa9a..629984364 100644 --- a/apps/settings/base.fr.i18n +++ b/apps/settings/base.fr.i18n @@ -22,6 +22,9 @@ Real = "Réel " Cartesian = "Algébrique " Polar = "Exponentielle " Brightness = "Luminosité" +FontSizes = "Police Python" +LargeFont = "Grand " +SmallFont = "Petit " SoftwareVersion = "Version du logiciel" SerialNumber = "Numéro série" UpdatePopUp = "Rappel mise à jour" diff --git a/apps/settings/base.pt.i18n b/apps/settings/base.pt.i18n index e2783fc7f..08d5e4b9e 100644 --- a/apps/settings/base.pt.i18n +++ b/apps/settings/base.pt.i18n @@ -22,6 +22,9 @@ Real = "Real " Cartesian = "Cartesiana " Polar = "Polar " Brightness = "Brilho" +FontSizes = "Tipografia Python" +LargeFont = "Grande " +SmallFont = "Pequeno " SoftwareVersion = "Versão do software" SerialNumber = "Número serie" UpdatePopUp = "Alertas de atualização" From b3d45833d0a0ebd04def5dc126cabd935926a565 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Fri, 4 Oct 2019 11:15:42 +0200 Subject: [PATCH 041/680] [apps/settings] Add a menu "Font size" in settings --- apps/settings/main_controller.cpp | 3 +++ apps/settings/main_controller.h | 3 ++- apps/settings/main_controller_prompt_beta.cpp | 4 +++- apps/settings/main_controller_prompt_none.cpp | 4 +++- apps/settings/main_controller_prompt_update.cpp | 4 +++- .../settings/sub_menu/preferences_controller.cpp | 16 ++++++++++++++++ 6 files changed, 30 insertions(+), 4 deletions(-) diff --git a/apps/settings/main_controller.cpp b/apps/settings/main_controller.cpp index e479266fe..dd8d5e9cb 100644 --- a/apps/settings/main_controller.cpp +++ b/apps/settings/main_controller.cpp @@ -169,6 +169,9 @@ void MainController::willDisplayCellForIndex(HighlightCell * cell, int index) { case k_indexOfComplexFormatCell: childIndex = (int)preferences->complexFormat(); break; + case k_indexOfFontCell: + childIndex = GlobalPreferences::sharedGlobalPreferences()->font() == KDFont::LargeFont ? 0 : 1; + break; } I18n::Message message = childIndex >= 0 ? model()->children(index)->children(childIndex)->label() : I18n::Message::Default; myTextCell->setSubtitle(message); diff --git a/apps/settings/main_controller.h b/apps/settings/main_controller.h index 91187be6f..28a8283da 100644 --- a/apps/settings/main_controller.h +++ b/apps/settings/main_controller.h @@ -32,7 +32,8 @@ private: constexpr static int k_indexOfEditionModeCell = k_indexOfDisplayModeCell + 1; constexpr static int k_indexOfComplexFormatCell = k_indexOfEditionModeCell + 1; constexpr static int k_indexOfBrightnessCell = k_indexOfComplexFormatCell + 1; - constexpr static int k_indexOfLanguageCell = k_indexOfBrightnessCell + 1; + constexpr static int k_indexOfFontCell = k_indexOfBrightnessCell + 1; + constexpr static int k_indexOfLanguageCell = k_indexOfFontCell + 1; constexpr static int k_indexOfExamModeCell = k_indexOfLanguageCell + 1; /* Pop-up cell and About cell are located at the same index because pop-up * cell is optional. We must always correct k_indexOfAboutCell with diff --git a/apps/settings/main_controller_prompt_beta.cpp b/apps/settings/main_controller_prompt_beta.cpp index 0ba86a359..ca33b62cf 100644 --- a/apps/settings/main_controller_prompt_beta.cpp +++ b/apps/settings/main_controller_prompt_beta.cpp @@ -7,6 +7,7 @@ constexpr SettingsMessageTree s_modelAngleChildren[3] = {SettingsMessageTree(I18 constexpr SettingsMessageTree s_modelEditionModeChildren[2] = {SettingsMessageTree(I18n::Message::Edition2D), SettingsMessageTree(I18n::Message::EditionLinear)}; constexpr SettingsMessageTree s_modelFloatDisplayModeChildren[4] = {SettingsMessageTree(I18n::Message::Decimal), SettingsMessageTree(I18n::Message::Scientific), SettingsMessageTree(I18n::Message::Engineering), SettingsMessageTree(I18n::Message::SignificantFigures)}; constexpr SettingsMessageTree s_modelComplexFormatChildren[3] = {SettingsMessageTree(I18n::Message::Real), SettingsMessageTree(I18n::Message::Cartesian), SettingsMessageTree(I18n::Message::Polar)}; +constexpr SettingsMessageTree s_modelFontChildren[2] = {SettingsMessageTree(I18n::Message::LargeFont), SettingsMessageTree(I18n::Message::SmallFont)}; constexpr SettingsMessageTree s_modelExamChildren[2] = {SettingsMessageTree(I18n::Message::ActivateExamMode), SettingsMessageTree(I18n::Message::ActivateDutchExamMode)}; constexpr SettingsMessageTree s_modelAboutChildren[3] = {SettingsMessageTree(I18n::Message::SoftwareVersion), SettingsMessageTree(I18n::Message::SerialNumber), SettingsMessageTree(I18n::Message::FccId)}; @@ -16,12 +17,13 @@ constexpr SettingsMessageTree s_modelMenu[] = SettingsMessageTree(I18n::Message::EditionMode, s_modelEditionModeChildren, 2), SettingsMessageTree(I18n::Message::ComplexFormat, s_modelComplexFormatChildren, 3), SettingsMessageTree(I18n::Message::Brightness), + SettingsMessageTree(I18n::Message::FontSizes, s_modelFontChildren, 2), SettingsMessageTree(I18n::Message::Language), SettingsMessageTree(I18n::Message::ExamMode, s_modelExamChildren, 2), SettingsMessageTree(I18n::Message::BetaPopUp), SettingsMessageTree(I18n::Message::About, s_modelAboutChildren, 3)}; -constexpr SettingsMessageTree s_model = SettingsMessageTree(I18n::Message::SettingsApp, s_modelMenu, 9); +constexpr SettingsMessageTree s_model = SettingsMessageTree(I18n::Message::SettingsApp, s_modelMenu, 10); I18n::Message MainController::promptMessage() const { return I18n::Message::BetaPopUp; diff --git a/apps/settings/main_controller_prompt_none.cpp b/apps/settings/main_controller_prompt_none.cpp index 9595b235c..da0c08f45 100644 --- a/apps/settings/main_controller_prompt_none.cpp +++ b/apps/settings/main_controller_prompt_none.cpp @@ -8,6 +8,7 @@ constexpr SettingsMessageTree s_modelAngleChildren[3] = {SettingsMessageTree(I18 constexpr SettingsMessageTree s_modelEditionModeChildren[2] = {SettingsMessageTree(I18n::Message::Edition2D), SettingsMessageTree(I18n::Message::EditionLinear)}; constexpr SettingsMessageTree s_modelFloatDisplayModeChildren[4] = {SettingsMessageTree(I18n::Message::Decimal), SettingsMessageTree(I18n::Message::Scientific), SettingsMessageTree(I18n::Message::Engineering), SettingsMessageTree(I18n::Message::SignificantFigures)}; constexpr SettingsMessageTree s_modelComplexFormatChildren[3] = {SettingsMessageTree(I18n::Message::Real), SettingsMessageTree(I18n::Message::Cartesian), SettingsMessageTree(I18n::Message::Polar)}; +constexpr SettingsMessageTree s_modelFontChildren[2] = {SettingsMessageTree(I18n::Message::LargeFont), SettingsMessageTree(I18n::Message::SmallFont)}; constexpr SettingsMessageTree s_modelExamChildren[2] = {SettingsMessageTree(I18n::Message::ActivateExamMode), SettingsMessageTree(I18n::Message::ActivateDutchExamMode)}; constexpr SettingsMessageTree s_modelAboutChildren[3] = {SettingsMessageTree(I18n::Message::SoftwareVersion), SettingsMessageTree(I18n::Message::SerialNumber), SettingsMessageTree(I18n::Message::FccId)}; @@ -17,11 +18,12 @@ constexpr SettingsMessageTree s_modelMenu[] = SettingsMessageTree(I18n::Message::EditionMode, s_modelEditionModeChildren, 2), SettingsMessageTree(I18n::Message::ComplexFormat, s_modelComplexFormatChildren, 3), SettingsMessageTree(I18n::Message::Brightness), + SettingsMessageTree(I18n::Message::FontSizes, s_modelFontChildren, 2), SettingsMessageTree(I18n::Message::Language), SettingsMessageTree(I18n::Message::ExamMode, s_modelExamChildren, 2), SettingsMessageTree(I18n::Message::About, s_modelAboutChildren, 3)}; -constexpr SettingsMessageTree s_model = SettingsMessageTree(I18n::Message::SettingsApp, s_modelMenu, 8); +constexpr SettingsMessageTree s_model = SettingsMessageTree(I18n::Message::SettingsApp, s_modelMenu, 9); I18n::Message MainController::promptMessage() const { return I18n::Message::Default; diff --git a/apps/settings/main_controller_prompt_update.cpp b/apps/settings/main_controller_prompt_update.cpp index 1bd728f3e..153924afc 100644 --- a/apps/settings/main_controller_prompt_update.cpp +++ b/apps/settings/main_controller_prompt_update.cpp @@ -7,6 +7,7 @@ constexpr SettingsMessageTree s_modelAngleChildren[3] = {SettingsMessageTree(I18 constexpr SettingsMessageTree s_modelEditionModeChildren[2] = {SettingsMessageTree(I18n::Message::Edition2D), SettingsMessageTree(I18n::Message::EditionLinear)}; constexpr SettingsMessageTree s_modelFloatDisplayModeChildren[4] = {SettingsMessageTree(I18n::Message::Decimal), SettingsMessageTree(I18n::Message::Scientific), SettingsMessageTree(I18n::Message::Engineering), SettingsMessageTree(I18n::Message::SignificantFigures)}; constexpr SettingsMessageTree s_modelComplexFormatChildren[3] = {SettingsMessageTree(I18n::Message::Real), SettingsMessageTree(I18n::Message::Cartesian), SettingsMessageTree(I18n::Message::Polar)}; +constexpr SettingsMessageTree s_modelFontChildren[2] = {SettingsMessageTree(I18n::Message::LargeFont), SettingsMessageTree(I18n::Message::SmallFont)}; constexpr SettingsMessageTree s_modelExamChildren[2] = {SettingsMessageTree(I18n::Message::ActivateExamMode), SettingsMessageTree(I18n::Message::ActivateDutchExamMode)}; constexpr SettingsMessageTree s_modelAboutChildren[3] = {SettingsMessageTree(I18n::Message::SoftwareVersion), SettingsMessageTree(I18n::Message::SerialNumber), SettingsMessageTree(I18n::Message::FccId)}; @@ -16,12 +17,13 @@ constexpr SettingsMessageTree s_modelMenu[] = SettingsMessageTree(I18n::Message::EditionMode, s_modelEditionModeChildren, 2), SettingsMessageTree(I18n::Message::ComplexFormat, s_modelComplexFormatChildren, 3), SettingsMessageTree(I18n::Message::Brightness), + SettingsMessageTree(I18n::Message::FontSizes, s_modelFontChildren, 2), SettingsMessageTree(I18n::Message::Language), SettingsMessageTree(I18n::Message::ExamMode, s_modelExamChildren, 2), SettingsMessageTree(I18n::Message::UpdatePopUp), SettingsMessageTree(I18n::Message::About, s_modelAboutChildren, 3)}; -constexpr SettingsMessageTree s_model = SettingsMessageTree(I18n::Message::SettingsApp, s_modelMenu, 9); +constexpr SettingsMessageTree s_model = SettingsMessageTree(I18n::Message::SettingsApp, s_modelMenu, 10); I18n::Message MainController::promptMessage() const { return I18n::Message::UpdatePopUp; diff --git a/apps/settings/sub_menu/preferences_controller.cpp b/apps/settings/sub_menu/preferences_controller.cpp index 609b190a2..83e9720de 100644 --- a/apps/settings/sub_menu/preferences_controller.cpp +++ b/apps/settings/sub_menu/preferences_controller.cpp @@ -106,6 +106,16 @@ Layout PreferencesController::layoutForPreferences(I18n::Message message) { VerticalOffsetLayout::Builder(LayoutHelper::String(superscript, strlen(superscript), k_layoutFont), VerticalOffsetLayoutNode::Position::Superscript) ); } + + // Font size + case I18n::Message::LargeFont: + case I18n::Message::SmallFont: + { + const char * text = "abc"; + const KDFont * font = message == I18n::Message::LargeFont ? KDFont::LargeFont : KDFont::SmallFont; + return LayoutHelper::String(text, strlen(text), font); + } + default: assert(false); return Layout(); @@ -141,7 +151,10 @@ void PreferencesController::setPreferenceWithValueIndex(I18n::Message message, i preferences->setEditionMode((Preferences::EditionMode)valueIndex); } else if (message == I18n::Message::ComplexFormat) { preferences->setComplexFormat((Preferences::ComplexFormat)valueIndex); + } else if (message == I18n::Message::FontSizes) { + GlobalPreferences::sharedGlobalPreferences()->setFont(valueIndex == 0 ? KDFont::LargeFont : KDFont::SmallFont); } + } int PreferencesController::valueIndexForPreference(I18n::Message message) const { @@ -158,6 +171,9 @@ int PreferencesController::valueIndexForPreference(I18n::Message message) const if (message == I18n::Message::ComplexFormat) { return (int)preferences->complexFormat(); } + if (message == I18n::Message::FontSizes) { + return GlobalPreferences::sharedGlobalPreferences()->font() == KDFont::LargeFont ? 0 : 1; + } return 0; } From c2dabf6510c27d5e4e355c36ad953d66b55aa8aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Fri, 4 Oct 2019 11:40:42 +0200 Subject: [PATCH 042/680] [apps/code] Choose console text size from GlobalPreferences --- apps/code/console_controller.cpp | 5 +++-- apps/code/console_controller.h | 2 -- apps/code/console_edit_cell.cpp | 5 +++-- apps/code/console_line_cell.cpp | 9 +++++---- 4 files changed, 11 insertions(+), 10 deletions(-) diff --git a/apps/code/console_controller.cpp b/apps/code/console_controller.cpp index 1041630f9..d8e8a2ee6 100644 --- a/apps/code/console_controller.cpp +++ b/apps/code/console_controller.cpp @@ -5,7 +5,8 @@ #include #include #include -#include "../apps_container.h" +#include +#include extern "C" { #include @@ -27,7 +28,7 @@ ConsoleController::ConsoleController(Responder * parentResponder, App * pythonDe TextFieldDelegate(), MicroPython::ExecutionEnvironment(), m_pythonDelegate(pythonDelegate), - m_rowHeight(k_font->glyphSize().height()), + m_rowHeight(GlobalPreferences::sharedGlobalPreferences()->font()->glyphSize().height()), m_importScriptsWhenViewAppears(false), m_selectableTableView(this, this, this, this), m_editCell(this, pythonDelegate, this), diff --git a/apps/code/console_controller.h b/apps/code/console_controller.h index 1c32f4f04..60dcf67b5 100644 --- a/apps/code/console_controller.h +++ b/apps/code/console_controller.h @@ -16,8 +16,6 @@ class App; class ConsoleController : public ViewController, public ListViewDataSource, public SelectableTableViewDataSource, public SelectableTableViewDelegate, public TextFieldDelegate, public MicroPython::ExecutionEnvironment { public: - static constexpr const KDFont * k_font = KDFont::LargeFont; - ConsoleController(Responder * parentResponder, App * pythonDelegate, ScriptStore * scriptStore #if EPSILON_GETOPT , bool m_lockOnConsole diff --git a/apps/code/console_edit_cell.cpp b/apps/code/console_edit_cell.cpp index d1b55c9d5..e5a4a2708 100644 --- a/apps/code/console_edit_cell.cpp +++ b/apps/code/console_edit_cell.cpp @@ -2,6 +2,7 @@ #include "console_controller.h" #include #include +#include #include namespace Code { @@ -9,8 +10,8 @@ namespace Code { ConsoleEditCell::ConsoleEditCell(Responder * parentResponder, InputEventHandlerDelegate * inputEventHandlerDelegate, TextFieldDelegate * delegate) : HighlightCell(), Responder(parentResponder), - m_promptView(ConsoleController::k_font, nullptr, 0, 0.5), - m_textField(this, nullptr, TextField::maxBufferSize(), TextField::maxBufferSize(), inputEventHandlerDelegate, delegate, ConsoleController::k_font) + m_promptView(GlobalPreferences::sharedGlobalPreferences()->font(), nullptr, 0, 0.5), + m_textField(this, nullptr, TextField::maxBufferSize(), TextField::maxBufferSize(), inputEventHandlerDelegate, delegate, GlobalPreferences::sharedGlobalPreferences()->font()) { } diff --git a/apps/code/console_line_cell.cpp b/apps/code/console_line_cell.cpp index 784875875..99042762b 100644 --- a/apps/code/console_line_cell.cpp +++ b/apps/code/console_line_cell.cpp @@ -3,6 +3,7 @@ #include #include #include +#include namespace Code { @@ -18,11 +19,11 @@ void ConsoleLineCell::ScrollableConsoleLineView::ConsoleLineView::setLine(Consol void ConsoleLineCell::ScrollableConsoleLineView::ConsoleLineView::drawRect(KDContext * ctx, KDRect rect) const { ctx->fillRect(bounds(), KDColorWhite); - ctx->drawString(m_line->text(), KDPointZero, ConsoleController::k_font, textColor(m_line), isHighlighted()? Palette::Select : KDColorWhite); + ctx->drawString(m_line->text(), KDPointZero, GlobalPreferences::sharedGlobalPreferences()->font(), textColor(m_line), isHighlighted()? Palette::Select : KDColorWhite); } KDSize ConsoleLineCell::ScrollableConsoleLineView::ConsoleLineView::minimalSizeForOptimalDisplay() const { - return ConsoleController::k_font->stringSize(m_line->text()); + return GlobalPreferences::sharedGlobalPreferences()->font()->stringSize(m_line->text()); } ConsoleLineCell::ScrollableConsoleLineView::ScrollableConsoleLineView(Responder * parentResponder) : @@ -34,7 +35,7 @@ ConsoleLineCell::ScrollableConsoleLineView::ScrollableConsoleLineView(Responder ConsoleLineCell::ConsoleLineCell(Responder * parentResponder) : HighlightCell(), Responder(parentResponder), - m_promptView(ConsoleController::k_font, I18n::Message::ConsolePrompt, 0, 0.5), + m_promptView(GlobalPreferences::sharedGlobalPreferences()->font(), I18n::Message::ConsolePrompt, 0, 0.5), m_scrollableView(this), m_line() { @@ -79,7 +80,7 @@ View * ConsoleLineCell::subviewAtIndex(int index) { void ConsoleLineCell::layoutSubviews(bool force) { if (m_line.isCommand()) { - KDSize promptSize = ConsoleController::k_font->stringSize(I18n::translate(I18n::Message::ConsolePrompt)); + KDSize promptSize = GlobalPreferences::sharedGlobalPreferences()->font()->stringSize(I18n::translate(I18n::Message::ConsolePrompt)); m_promptView.setFrame(KDRect(KDPointZero, promptSize.width(), bounds().height()), force); m_scrollableView.setFrame(KDRect(KDPoint(promptSize.width(), 0), bounds().width() - promptSize.width(), bounds().height()), force); return; From 3627dc0c0f97100374198ce13fa17a68f1161404 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Fri, 4 Oct 2019 11:41:07 +0200 Subject: [PATCH 043/680] [apps/code] Choose editor font size from GlobalPreferences --- apps/code/editor_view.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/apps/code/editor_view.cpp b/apps/code/editor_view.cpp index 23fcbf9c5..03c695da9 100644 --- a/apps/code/editor_view.cpp +++ b/apps/code/editor_view.cpp @@ -1,4 +1,5 @@ #include "editor_view.h" +#include #include #include @@ -6,13 +7,11 @@ namespace Code { /* EditorView */ -static constexpr const KDFont * editorFont = KDFont::LargeFont; - EditorView::EditorView(Responder * parentResponder, App * pythonDelegate) : Responder(parentResponder), View(), - m_textArea(parentResponder, pythonDelegate, editorFont), - m_gutterView(editorFont) + m_textArea(parentResponder, pythonDelegate, GlobalPreferences::sharedGlobalPreferences()->font()), + m_gutterView(GlobalPreferences::sharedGlobalPreferences()->font()) { m_textArea.setScrollViewDelegate(this); } From 953c9dfe64c7b20b4dd9ccb7e9d85607ca9488f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Fri, 4 Oct 2019 14:19:59 +0200 Subject: [PATCH 044/680] [apps/settings] Create a parent class CellWithSeparator to MessageTableCellWithEditableTextWithSeparator for future factorization --- apps/settings/Makefile | 2 +- apps/settings/cell_with_separator.cpp | 30 ++++++++++++++++ apps/settings/cell_with_separator.h | 27 +++++++++++++++ ...e_cell_with_editable_text_with_separator.h | 18 ++++------ .../sub_menu/display_mode_controller.h | 2 +- ...cell_with_editable_text_with_separator.cpp | 34 ------------------- 6 files changed, 65 insertions(+), 48 deletions(-) create mode 100644 apps/settings/cell_with_separator.cpp create mode 100644 apps/settings/cell_with_separator.h rename apps/settings/{sub_menu => }/message_table_cell_with_editable_text_with_separator.h (50%) delete mode 100644 apps/settings/sub_menu/message_table_cell_with_editable_text_with_separator.cpp diff --git a/apps/settings/Makefile b/apps/settings/Makefile index 5726653c7..1170109a9 100644 --- a/apps/settings/Makefile +++ b/apps/settings/Makefile @@ -3,6 +3,7 @@ app_headers += apps/settings/app.h app_settings_src = $(addprefix apps/settings/,\ app.cpp \ + cell_with_separator.cpp \ main_controller.cpp \ settings_message_tree.cpp \ sub_menu/about_controller.cpp \ @@ -10,7 +11,6 @@ app_settings_src = $(addprefix apps/settings/,\ sub_menu/exam_mode_controller.cpp \ sub_menu/generic_sub_controller.cpp \ sub_menu/language_controller.cpp \ - sub_menu/message_table_cell_with_editable_text_with_separator.cpp \ sub_menu/preferences_controller.cpp \ ) diff --git a/apps/settings/cell_with_separator.cpp b/apps/settings/cell_with_separator.cpp new file mode 100644 index 000000000..c7a51605b --- /dev/null +++ b/apps/settings/cell_with_separator.cpp @@ -0,0 +1,30 @@ +#include "cell_with_separator.h" + +namespace Settings { + +void CellWithSeparator::setHighlighted(bool highlight) { + cell()->setHighlighted(highlight); + HighlightCell::setHighlighted(highlight); +} + +void CellWithSeparator::drawRect(KDContext * ctx, KDRect rect) const { + //ctx->fillRect(KDRect(0, 0, bounds().width(), k_separatorThickness), Palette::GreyBright); + KDCoordinate height = bounds().height(); + ctx->fillRect(KDRect(0, m_separatorBelow ? height - k_margin : Metric::CellSeparatorThickness, bounds().width(), k_margin), Palette::WallScreen); +} + +int CellWithSeparator::numberOfSubviews() const { + return 1; +} + +View * CellWithSeparator::subviewAtIndex(int index) { + assert(index == 0); + return cell(); +} + +void CellWithSeparator::layoutSubviews(bool force) { + KDRect frame = KDRect(0, m_separatorBelow ? 0 : k_margin, bounds().width(), bounds().height()-k_margin); + cell()->setFrame(frame, force); +} + +} diff --git a/apps/settings/cell_with_separator.h b/apps/settings/cell_with_separator.h new file mode 100644 index 000000000..978ad7aee --- /dev/null +++ b/apps/settings/cell_with_separator.h @@ -0,0 +1,27 @@ +#ifndef SETTINGS_CELL_WITH_SEPARATOR_H +#define SETTINGS_CELL_WITH_SEPARATOR_H + +#include + +namespace Settings { + +class CellWithSeparator : public HighlightCell { +public: + CellWithSeparator(bool separatorBelow) : + m_separatorBelow(separatorBelow) {} + void setHighlighted(bool highlight) override; + void drawRect(KDContext * ctx, KDRect rect) const override; + void reloadCell() override { cell()->reloadCell(); } + Responder * responder() override { return cell()->responder(); } + constexpr static KDCoordinate k_margin = 10; +private: + int numberOfSubviews() const override; + View * subviewAtIndex(int index) override; + void layoutSubviews(bool force = false) override; + virtual HighlightCell * cell() = 0; + bool m_separatorBelow; +}; + +} + +#endif diff --git a/apps/settings/sub_menu/message_table_cell_with_editable_text_with_separator.h b/apps/settings/message_table_cell_with_editable_text_with_separator.h similarity index 50% rename from apps/settings/sub_menu/message_table_cell_with_editable_text_with_separator.h rename to apps/settings/message_table_cell_with_editable_text_with_separator.h index 49e2c8ef0..2146bb982 100644 --- a/apps/settings/sub_menu/message_table_cell_with_editable_text_with_separator.h +++ b/apps/settings/message_table_cell_with_editable_text_with_separator.h @@ -1,26 +1,20 @@ #ifndef SETTINGS_MESSAGE_TABLE_CELL_WITH_EDITABLE_TEXT_WITH_SEPARATOR_H #define SETTINGS_MESSAGE_TABLE_CELL_WITH_EDITABLE_TEXT_WITH_SEPARATOR_H -#include +#include "cell_with_separator.h" namespace Settings { -class MessageTableCellWithEditableTextWithSeparator : public HighlightCell { +class MessageTableCellWithEditableTextWithSeparator : public CellWithSeparator { public: - MessageTableCellWithEditableTextWithSeparator(Responder * parentResponder = nullptr, InputEventHandlerDelegate * inputEventHandlerDelegate = nullptr, TextFieldDelegate * textFieldDelegate = nullptr, I18n::Message message = (I18n::Message)0); - void drawRect(KDContext * ctx, KDRect rect) const override; - void setHighlighted(bool highlight) override; - void reloadCell() override { m_cell.reloadCell(); } - Responder * responder() override { return m_cell.responder(); } + MessageTableCellWithEditableTextWithSeparator(Responder * parentResponder = nullptr, InputEventHandlerDelegate * inputEventHandlerDelegate = nullptr, TextFieldDelegate * textFieldDelegate = nullptr, I18n::Message message = (I18n::Message)0) : + CellWithSeparator(false), + m_cell(parentResponder, inputEventHandlerDelegate, textFieldDelegate, message) {} const char * text() const override { return m_cell.text(); } Poincare::Layout layout() const override{ return m_cell.layout(); } MessageTableCellWithEditableText * messageTableCellWithEditableText() { return &m_cell; } - constexpr static KDCoordinate k_margin = 10; private: - constexpr static KDCoordinate k_separatorThickness = Metric::CellSeparatorThickness; - int numberOfSubviews() const override; - View * subviewAtIndex(int index) override; - void layoutSubviews(bool force = false) override; + HighlightCell * cell() override { return &m_cell; } MessageTableCellWithEditableText m_cell; }; diff --git a/apps/settings/sub_menu/display_mode_controller.h b/apps/settings/sub_menu/display_mode_controller.h index fc0a8ef6d..1d58a9f1b 100644 --- a/apps/settings/sub_menu/display_mode_controller.h +++ b/apps/settings/sub_menu/display_mode_controller.h @@ -2,7 +2,7 @@ #define SETTINGS_DISPLAY_MODE_CONTROLLER_H #include "preferences_controller.h" -#include "message_table_cell_with_editable_text_with_separator.h" +#include "../message_table_cell_with_editable_text_with_separator.h" #include "../../shared/parameter_text_field_delegate.h" namespace Settings { diff --git a/apps/settings/sub_menu/message_table_cell_with_editable_text_with_separator.cpp b/apps/settings/sub_menu/message_table_cell_with_editable_text_with_separator.cpp deleted file mode 100644 index 4057f005c..000000000 --- a/apps/settings/sub_menu/message_table_cell_with_editable_text_with_separator.cpp +++ /dev/null @@ -1,34 +0,0 @@ -#include "message_table_cell_with_editable_text_with_separator.h" - -namespace Settings { - -MessageTableCellWithEditableTextWithSeparator::MessageTableCellWithEditableTextWithSeparator(Responder * parentResponder, InputEventHandlerDelegate * inputEventHandlerDelegate, TextFieldDelegate * textFieldDelegate, I18n::Message message) : - HighlightCell(), - m_cell(parentResponder, inputEventHandlerDelegate, textFieldDelegate, message) -{ -} - -void MessageTableCellWithEditableTextWithSeparator::setHighlighted(bool highlight) { - m_cell.setHighlighted(highlight); - HighlightCell::setHighlighted(highlight); -} - -void MessageTableCellWithEditableTextWithSeparator::drawRect(KDContext * ctx, KDRect rect) const { - ctx->fillRect(KDRect(0, 0, bounds().width(), k_separatorThickness), Palette::GreyBright); - ctx->fillRect(KDRect(0, k_separatorThickness, bounds().width(), k_margin-k_separatorThickness), Palette::WallScreen); -} - -int MessageTableCellWithEditableTextWithSeparator::numberOfSubviews() const { - return 1; -} - -View * MessageTableCellWithEditableTextWithSeparator::subviewAtIndex(int index) { - assert(index == 0); - return &m_cell; -} - -void MessageTableCellWithEditableTextWithSeparator::layoutSubviews(bool force) { - m_cell.setFrame(KDRect(0, k_margin, bounds().width(), bounds().height()-k_margin), force); -} - -} From f7fc8da94df5d9596af2c291ba455279dcbb4803 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Fri, 4 Oct 2019 14:21:17 +0200 Subject: [PATCH 045/680] [apps/settings] Use a MessageTableCellWithGaugeWithSeparator in the main controller to mimic two tables --- apps/settings/main_controller.cpp | 22 ++++++++++++++----- apps/settings/main_controller.h | 3 ++- ...age_table_cell_with_gauge_with_separator.h | 22 +++++++++++++++++++ 3 files changed, 41 insertions(+), 6 deletions(-) create mode 100644 apps/settings/message_table_cell_with_gauge_with_separator.h diff --git a/apps/settings/main_controller.cpp b/apps/settings/main_controller.cpp index dd8d5e9cb..73293c6b7 100644 --- a/apps/settings/main_controller.cpp +++ b/apps/settings/main_controller.cpp @@ -90,15 +90,25 @@ int MainController::numberOfRows() const { }; KDCoordinate MainController::rowHeight(int j) { + if (j == k_indexOfBrightnessCell) { + return Metric::ParameterCellHeight + CellWithSeparator::k_margin; + } return Metric::ParameterCellHeight; } KDCoordinate MainController::cumulatedHeightFromIndex(int j) { - return j*rowHeight(0); + KDCoordinate height = j * rowHeight(0); + if (j > k_indexOfBrightnessCell) { + height += CellWithSeparator::k_margin; + } + return height; } int MainController::indexFromCumulatedHeight(KDCoordinate offsetY) { - return offsetY/rowHeight(0); + if (offsetY < rowHeight(0)*k_indexOfBrightnessCell + CellWithSeparator::k_margin) { + return offsetY/rowHeight(0); + } + return (offsetY - CellWithSeparator::k_margin)/rowHeight(0); } HighlightCell * MainController::reusableCell(int index, int type) { @@ -135,14 +145,16 @@ int MainController::typeAtLocation(int i, int j) { void MainController::willDisplayCellForIndex(HighlightCell * cell, int index) { GlobalPreferences * globalPreferences = GlobalPreferences::sharedGlobalPreferences(); Preferences * preferences = Preferences::sharedPreferences(); - MessageTableCell * myCell = (MessageTableCell *)cell; - myCell->setMessage(model()->children(index)->label()); + I18n::Message title = model()->children(index)->label(); if (index == k_indexOfBrightnessCell) { - MessageTableCellWithGauge * myGaugeCell = (MessageTableCellWithGauge *)cell; + MessageTableCellWithGaugeWithSeparator * myGaugeCell = (MessageTableCellWithGaugeWithSeparator *)cell; + myGaugeCell->setMessage(title); GaugeView * myGauge = (GaugeView *)myGaugeCell->accessoryView(); myGauge->setLevel((float)globalPreferences->brightnessLevel()/(float)Ion::Backlight::MaxBrightness); return; } + MessageTableCell * myCell = (MessageTableCell *)cell; + myCell->setMessage(title); if (index == k_indexOfLanguageCell) { int index = (int)globalPreferences->language()-1; static_cast(cell)->setSubtitle(I18n::LanguageNames[index]); diff --git a/apps/settings/main_controller.h b/apps/settings/main_controller.h index 28a8283da..cd7df0b0e 100644 --- a/apps/settings/main_controller.h +++ b/apps/settings/main_controller.h @@ -3,6 +3,7 @@ #include #include "settings_message_tree.h" +#include "message_table_cell_with_gauge_with_separator.h" #include "sub_menu/about_controller.h" #include "sub_menu/display_mode_controller.h" #include "sub_menu/exam_mode_controller.h" @@ -47,7 +48,7 @@ private: bool hasPrompt() const { return promptMessage() != I18n::Message::Default; } constexpr static int k_numberOfSimpleChevronCells = 7; MessageTableCellWithChevronAndMessage m_cells[k_numberOfSimpleChevronCells]; - MessageTableCellWithGauge m_brightnessCell; + MessageTableCellWithGaugeWithSeparator m_brightnessCell; MessageTableCellWithSwitch m_popUpCell; SelectableTableView m_selectableTableView; PreferencesController m_preferencesController; diff --git a/apps/settings/message_table_cell_with_gauge_with_separator.h b/apps/settings/message_table_cell_with_gauge_with_separator.h new file mode 100644 index 000000000..c3d30d7fc --- /dev/null +++ b/apps/settings/message_table_cell_with_gauge_with_separator.h @@ -0,0 +1,22 @@ +#ifndef SETTINGS_MESSAGE_TABLE_WITH_GAUGE_WITH_SEPARATOR_H +#define SETTINGS_MESSAGE_TABLE_WITH_GAUGE_WITH_SEPARATOR_H + +#include "cell_with_separator.h" + +namespace Settings { + +class MessageTableCellWithGaugeWithSeparator : public CellWithSeparator { +public: + MessageTableCellWithGaugeWithSeparator(I18n::Message message, const KDFont * font) : + CellWithSeparator(true), + m_cell(message, font) {} + View * accessoryView() const { return m_cell.accessoryView(); } + void setMessage(I18n::Message message) { return m_cell.setMessage(message); } +private: + HighlightCell * cell() override { return &m_cell; } + MessageTableCellWithGauge m_cell; +}; + +} + +#endif From e550712ccc0343d13ad46fd0f7cf836b9145c8a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Fri, 4 Oct 2019 15:04:36 +0200 Subject: [PATCH 046/680] [apps/settings] Separation is always below the CellWithSeparator --- apps/settings/cell_with_separator.cpp | 7 ++----- apps/settings/cell_with_separator.h | 4 +--- .../message_table_cell_with_editable_text_with_separator.h | 2 +- .../message_table_cell_with_gauge_with_separator.h | 2 +- 4 files changed, 5 insertions(+), 10 deletions(-) diff --git a/apps/settings/cell_with_separator.cpp b/apps/settings/cell_with_separator.cpp index c7a51605b..7f421ce28 100644 --- a/apps/settings/cell_with_separator.cpp +++ b/apps/settings/cell_with_separator.cpp @@ -8,9 +8,7 @@ void CellWithSeparator::setHighlighted(bool highlight) { } void CellWithSeparator::drawRect(KDContext * ctx, KDRect rect) const { - //ctx->fillRect(KDRect(0, 0, bounds().width(), k_separatorThickness), Palette::GreyBright); - KDCoordinate height = bounds().height(); - ctx->fillRect(KDRect(0, m_separatorBelow ? height - k_margin : Metric::CellSeparatorThickness, bounds().width(), k_margin), Palette::WallScreen); + ctx->fillRect(KDRect(0, Metric::CellSeparatorThickness, bounds().width(), k_margin), Palette::WallScreen); } int CellWithSeparator::numberOfSubviews() const { @@ -23,8 +21,7 @@ View * CellWithSeparator::subviewAtIndex(int index) { } void CellWithSeparator::layoutSubviews(bool force) { - KDRect frame = KDRect(0, m_separatorBelow ? 0 : k_margin, bounds().width(), bounds().height()-k_margin); - cell()->setFrame(frame, force); + cell()->setFrame(KDRect(0, k_margin, bounds().width(), bounds().height()-k_margin), force); } } diff --git a/apps/settings/cell_with_separator.h b/apps/settings/cell_with_separator.h index 978ad7aee..b27eef9a7 100644 --- a/apps/settings/cell_with_separator.h +++ b/apps/settings/cell_with_separator.h @@ -7,8 +7,7 @@ namespace Settings { class CellWithSeparator : public HighlightCell { public: - CellWithSeparator(bool separatorBelow) : - m_separatorBelow(separatorBelow) {} + CellWithSeparator() {} void setHighlighted(bool highlight) override; void drawRect(KDContext * ctx, KDRect rect) const override; void reloadCell() override { cell()->reloadCell(); } @@ -19,7 +18,6 @@ private: View * subviewAtIndex(int index) override; void layoutSubviews(bool force = false) override; virtual HighlightCell * cell() = 0; - bool m_separatorBelow; }; } diff --git a/apps/settings/message_table_cell_with_editable_text_with_separator.h b/apps/settings/message_table_cell_with_editable_text_with_separator.h index 2146bb982..fdc33df7a 100644 --- a/apps/settings/message_table_cell_with_editable_text_with_separator.h +++ b/apps/settings/message_table_cell_with_editable_text_with_separator.h @@ -8,7 +8,7 @@ namespace Settings { class MessageTableCellWithEditableTextWithSeparator : public CellWithSeparator { public: MessageTableCellWithEditableTextWithSeparator(Responder * parentResponder = nullptr, InputEventHandlerDelegate * inputEventHandlerDelegate = nullptr, TextFieldDelegate * textFieldDelegate = nullptr, I18n::Message message = (I18n::Message)0) : - CellWithSeparator(false), + CellWithSeparator(), m_cell(parentResponder, inputEventHandlerDelegate, textFieldDelegate, message) {} const char * text() const override { return m_cell.text(); } Poincare::Layout layout() const override{ return m_cell.layout(); } diff --git a/apps/settings/message_table_cell_with_gauge_with_separator.h b/apps/settings/message_table_cell_with_gauge_with_separator.h index c3d30d7fc..fa1dd1210 100644 --- a/apps/settings/message_table_cell_with_gauge_with_separator.h +++ b/apps/settings/message_table_cell_with_gauge_with_separator.h @@ -8,7 +8,7 @@ namespace Settings { class MessageTableCellWithGaugeWithSeparator : public CellWithSeparator { public: MessageTableCellWithGaugeWithSeparator(I18n::Message message, const KDFont * font) : - CellWithSeparator(true), + CellWithSeparator(), m_cell(message, font) {} View * accessoryView() const { return m_cell.accessoryView(); } void setMessage(I18n::Message message) { return m_cell.setMessage(message); } From 7a49e23e3b0b14d8a6c908a995034b48ceeb2a80 Mon Sep 17 00:00:00 2001 From: Ruben Dashyan Date: Tue, 1 Oct 2019 17:44:12 +0200 Subject: [PATCH 047/680] [apps/calculation] Factor HistoryController::reload --- apps/calculation/edit_expression_controller.cpp | 5 ----- apps/calculation/edit_expression_controller.h | 1 - apps/calculation/history_controller.cpp | 7 +++++++ 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/apps/calculation/edit_expression_controller.cpp b/apps/calculation/edit_expression_controller.cpp index 7b60010a2..0e17a0bcf 100644 --- a/apps/calculation/edit_expression_controller.cpp +++ b/apps/calculation/edit_expression_controller.cpp @@ -111,9 +111,6 @@ void EditExpressionController::layoutFieldDidChangeSize(::LayoutField * layoutFi void EditExpressionController::reloadView() { m_contentView.reload(); m_historyController->reload(); - if (m_historyController->numberOfRows() > 0) { - m_contentView.mainView()->scrollToCell(0, m_historyController->numberOfRows()-1); - } } bool EditExpressionController::inputViewDidReceiveEvent(Ion::Events::Event event, bool shouldDuplicateLastCalculation) { @@ -126,7 +123,6 @@ bool EditExpressionController::inputViewDidReceiveEvent(Ion::Events::Event event } m_calculationStore->push(m_cacheBuffer, myApp->localContext()); m_historyController->reload(); - m_contentView.mainView()->scrollToCell(0, m_historyController->numberOfRows()-1); return true; } if (event == Ion::Events::Up) { @@ -150,7 +146,6 @@ bool EditExpressionController::inputViewDidFinishEditing(const char * text, Layo } m_calculationStore->push(m_cacheBuffer, textFieldDelegateApp()->localContext()); m_historyController->reload(); - m_contentView.mainView()->scrollToCell(0, m_historyController->numberOfRows()-1); m_contentView.expressionField()->setEditing(true, true); return true; } diff --git a/apps/calculation/edit_expression_controller.h b/apps/calculation/edit_expression_controller.h index 2fadd126d..298f0def2 100644 --- a/apps/calculation/edit_expression_controller.h +++ b/apps/calculation/edit_expression_controller.h @@ -10,7 +10,6 @@ #include "calculation_store.h" namespace Calculation { -class HistoryController; /* TODO: implement a split view */ class EditExpressionController : public ViewController, public Shared::TextFieldDelegate, public Shared::LayoutFieldDelegate { diff --git a/apps/calculation/history_controller.cpp b/apps/calculation/history_controller.cpp index 2f300aaef..b3fb5b2ce 100644 --- a/apps/calculation/history_controller.cpp +++ b/apps/calculation/history_controller.cpp @@ -20,6 +20,13 @@ HistoryController::HistoryController(Responder * parentResponder, CalculationSto void HistoryController::reload() { m_selectableTableView.reloadData(); + /* TODO + * Replace the following by selectCellAtLocation in order to avoid laying out + * the table view twice. + */ + if (numberOfRows() > 0) { + m_selectableTableView.scrollToCell(0, numberOfRows()-1); + } } void HistoryController::didBecomeFirstResponder() { From b624e47ccb88d051b20caa7ede7ad36fc3633d3e Mon Sep 17 00:00:00 2001 From: Ruben Dashyan Date: Tue, 1 Oct 2019 17:49:24 +0200 Subject: [PATCH 048/680] [apps/calculation/edit_expression_controller] Remove dummy viewDidDisappear HistoryController does not override ViewController's default viewDidDisappear. --- apps/calculation/edit_expression_controller.cpp | 4 ---- apps/calculation/edit_expression_controller.h | 1 - 2 files changed, 5 deletions(-) diff --git a/apps/calculation/edit_expression_controller.cpp b/apps/calculation/edit_expression_controller.cpp index 0e17a0bcf..992a3dee8 100644 --- a/apps/calculation/edit_expression_controller.cpp +++ b/apps/calculation/edit_expression_controller.cpp @@ -158,8 +158,4 @@ bool EditExpressionController::inputViewDidAbortEditing(const char * text) { return false; } -void EditExpressionController::viewDidDisappear() { - m_historyController->viewDidDisappear(); -} - } diff --git a/apps/calculation/edit_expression_controller.h b/apps/calculation/edit_expression_controller.h index 298f0def2..42c949323 100644 --- a/apps/calculation/edit_expression_controller.h +++ b/apps/calculation/edit_expression_controller.h @@ -17,7 +17,6 @@ public: EditExpressionController(Responder * parentResponder, InputEventHandlerDelegate * inputEventHandlerDelegate, HistoryController * historyController, CalculationStore * calculationStore); View * view() override { return &m_contentView; } void didBecomeFirstResponder() override; - void viewDidDisappear() override; void insertTextBody(const char * text); /* TextFieldDelegate */ From b832a9e9f4a8f4b0e273d02825d71cca007abeec Mon Sep 17 00:00:00 2001 From: Ruben Dashyan Date: Tue, 1 Oct 2019 18:07:15 +0200 Subject: [PATCH 049/680] [apps/calculation/edit_expression_controller] Define viewWillAppear --- apps/calculation/edit_expression_controller.cpp | 2 -- apps/calculation/history_controller.cpp | 10 ++++++---- apps/calculation/history_controller.h | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/apps/calculation/edit_expression_controller.cpp b/apps/calculation/edit_expression_controller.cpp index 992a3dee8..41a63a854 100644 --- a/apps/calculation/edit_expression_controller.cpp +++ b/apps/calculation/edit_expression_controller.cpp @@ -53,8 +53,6 @@ void EditExpressionController::insertTextBody(const char * text) { } void EditExpressionController::didBecomeFirstResponder() { - int lastRow = m_calculationStore->numberOfCalculations() > 0 ? m_calculationStore->numberOfCalculations()-1 : 0; - m_historyController->scrollToCell(0, lastRow); m_contentView.expressionField()->setEditing(true, false); Container::activeApp()->setFirstResponder(m_contentView.expressionField()); } diff --git a/apps/calculation/history_controller.cpp b/apps/calculation/history_controller.cpp index b3fb5b2ce..d96789e4c 100644 --- a/apps/calculation/history_controller.cpp +++ b/apps/calculation/history_controller.cpp @@ -18,6 +18,12 @@ HistoryController::HistoryController(Responder * parentResponder, CalculationSto } } +void HistoryController::viewWillAppear() { + int rowsCount = numberOfRows(); + int lastRow = (rowsCount > 0) * (rowsCount - 1); + selectCellAtLocation(0, lastRow); +} + void HistoryController::reload() { m_selectableTableView.reloadData(); /* TODO @@ -168,10 +174,6 @@ int HistoryController::typeAtLocation(int i, int j) { return 0; } -void HistoryController::scrollToCell(int i, int j) { - m_selectableTableView.scrollToCell(i, j); -} - HistoryViewCell * HistoryController::historyViewCellDidChangeSelection() { /* Update the whole table as the height of the selected cell row might have * changed. */ diff --git a/apps/calculation/history_controller.h b/apps/calculation/history_controller.h index f75c20015..06d108c8d 100644 --- a/apps/calculation/history_controller.h +++ b/apps/calculation/history_controller.h @@ -14,6 +14,7 @@ class HistoryController : public ViewController, public ListViewDataSource, publ public: HistoryController(Responder * parentResponder, CalculationStore * calculationStore); View * view() override { return &m_selectableTableView; } + void viewWillAppear() override; bool handleEvent(Ion::Events::Event event) override; void didBecomeFirstResponder() override; void willExitResponderChain(Responder * nextFirstResponder) override; @@ -25,7 +26,6 @@ public: KDCoordinate rowHeight(int j) override; int typeAtLocation(int i, int j) override; void tableViewDidChangeSelection(SelectableTableView * t, int previousSelectedCellX, int previousSelectedCellY, bool withinTemporarySelection = false) override; - void scrollToCell(int i, int j); private: int storeIndex(int i) { return numberOfRows() - i - 1; } Shared::ExpiringPointer calculationAtIndex(int i); From 3bc35323586d2f04c0dada91046cb47daef31240 Mon Sep 17 00:00:00 2001 From: Ruben Dashyan Date: Thu, 10 Oct 2019 15:09:32 +0200 Subject: [PATCH 050/680] [escher/expression_field] Replace maximalHeight() by k_maximalHeight To harmonize with k_minimalHeight --- escher/include/escher/expression_field.h | 2 +- escher/src/expression_field.cpp | 8 ++------ 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/escher/include/escher/expression_field.h b/escher/include/escher/expression_field.h index 8b1310fbb..1c2c701aa 100644 --- a/escher/include/escher/expression_field.h +++ b/escher/include/escher/expression_field.h @@ -40,11 +40,11 @@ public: private: static constexpr int k_textFieldBufferSize = TextField::maxBufferSize(); static constexpr KDCoordinate k_minimalHeight = 37; + static constexpr KDCoordinate k_maximalHeight = 0.6*Ion::Display::Height; static constexpr KDCoordinate k_horizontalMargin = 5; static constexpr KDCoordinate k_verticalMargin = 5; constexpr static KDCoordinate k_separatorThickness = Metric::CellSeparatorThickness; KDCoordinate inputViewHeight() const; - KDCoordinate maximalHeight() const; TextField m_textField; LayoutField m_layoutField; }; diff --git a/escher/src/expression_field.cpp b/escher/src/expression_field.cpp index 7d274ed8f..268d20507 100644 --- a/escher/src/expression_field.cpp +++ b/escher/src/expression_field.cpp @@ -100,7 +100,7 @@ bool ExpressionField::isEmpty() const { } bool ExpressionField::heightIsMaximal() const { - return inputViewHeight() == k_separatorThickness + maximalHeight(); + return inputViewHeight() == k_separatorThickness + k_maximalHeight; } bool ExpressionField::handleEventWithText(const char * text, bool indentation, bool forceCursorRightOfText) { @@ -114,10 +114,6 @@ bool ExpressionField::handleEventWithText(const char * text, bool indentation, b KDCoordinate ExpressionField::inputViewHeight() const { return k_separatorThickness + (editionIsInTextField() ? k_minimalHeight : - minCoordinate(maximalHeight(), + minCoordinate(k_maximalHeight, maxCoordinate(k_minimalHeight, m_layoutField.minimalSizeForOptimalDisplay().height()))); } - -KDCoordinate ExpressionField::maximalHeight() const { - return 0.6*Ion::Display::Height; -} From 40d75ffefa1d248c9524556da5549ef070bd3046 Mon Sep 17 00:00:00 2001 From: Ruben Dashyan Date: Thu, 10 Oct 2019 16:19:28 +0200 Subject: [PATCH 051/680] [escher/expression_field] Remove unused reload() method --- escher/include/escher/expression_field.h | 1 - escher/src/expression_field.cpp | 5 ----- 2 files changed, 6 deletions(-) diff --git a/escher/include/escher/expression_field.h b/escher/include/escher/expression_field.h index 1c2c701aa..6e3faf5b2 100644 --- a/escher/include/escher/expression_field.h +++ b/escher/include/escher/expression_field.h @@ -21,7 +21,6 @@ public: * use text() there... TODO: change text() for fillTextInBuffer?*/ const char * text(); void setText(const char * text); - void reload(); bool editionIsInTextField() const; bool isEmpty() const; bool heightIsMaximal() const; diff --git a/escher/src/expression_field.cpp b/escher/src/expression_field.cpp index 268d20507..fb8fcf7df 100644 --- a/escher/src/expression_field.cpp +++ b/escher/src/expression_field.cpp @@ -73,11 +73,6 @@ void ExpressionField::layoutSubviews(bool force) { m_textField.setFrame(KDRectZero, force); } -void ExpressionField::reload() { - layoutSubviews(); - markRectAsDirty(bounds()); -} - void ExpressionField::drawRect(KDContext * ctx, KDRect rect) const { // Draw the separator ctx->fillRect(KDRect(0, 0, bounds().width(), k_separatorThickness), Palette::GreyMiddle); From 7fce83d1dd954d504ac223bef3988095ab333fbc Mon Sep 17 00:00:00 2001 From: Ruben Dashyan Date: Thu, 10 Oct 2019 16:42:25 +0200 Subject: [PATCH 052/680] [escher/expression_field] Detect whether view's height did change by memoizing the height Such changes used to be detected only when the height was equal to the maximal allowed value, by detecting whether the height shifted from or to that maximal value. For that purpose, a boolean was memoized in InputViewController and in Calculation::EditExpressionController. --- apps/calculation/edit_expression_controller.cpp | 11 ++++------- apps/calculation/edit_expression_controller.h | 1 - escher/include/escher/expression_field.h | 4 +++- escher/include/escher/input_view_controller.h | 1 - escher/src/expression_field.cpp | 12 ++++++++++-- escher/src/input_view_controller.cpp | 11 ++++------- 6 files changed, 21 insertions(+), 19 deletions(-) diff --git a/apps/calculation/edit_expression_controller.cpp b/apps/calculation/edit_expression_controller.cpp index 41a63a854..df76015ab 100644 --- a/apps/calculation/edit_expression_controller.cpp +++ b/apps/calculation/edit_expression_controller.cpp @@ -42,8 +42,7 @@ EditExpressionController::EditExpressionController(Responder * parentResponder, ViewController(parentResponder), m_historyController(historyController), m_calculationStore(calculationStore), - m_contentView(this, (TableView *)m_historyController->view(), inputEventHandlerDelegate, this, this), - m_inputViewHeightIsMaximal(false) + m_contentView(this, (TableView *)m_historyController->view(), inputEventHandlerDelegate, this, this) { m_cacheBuffer[0] = 0; } @@ -90,11 +89,9 @@ bool EditExpressionController::layoutFieldDidAbortEditing(::LayoutField * layout } void EditExpressionController::layoutFieldDidChangeSize(::LayoutField * layoutField) { - /* Reload the view only if the ExpressionField height actually changes, i.e. - * not if the height is already maximal and stays maximal. */ - bool newInputViewHeightIsMaximal = m_contentView.expressionField()->heightIsMaximal(); - if (!m_inputViewHeightIsMaximal || !newInputViewHeightIsMaximal) { - m_inputViewHeightIsMaximal = newInputViewHeightIsMaximal; + if (m_contentView.expressionField()->inputViewHeightDidChange()) { + /* Reload the whole view only if the ExpressionField's height did actually + * change. */ reloadView(); } else { /* The input view is already at maximal size so we do not need to relayout diff --git a/apps/calculation/edit_expression_controller.h b/apps/calculation/edit_expression_controller.h index 42c949323..0259f8795 100644 --- a/apps/calculation/edit_expression_controller.h +++ b/apps/calculation/edit_expression_controller.h @@ -53,7 +53,6 @@ private: HistoryController * m_historyController; CalculationStore * m_calculationStore; ContentView m_contentView; - bool m_inputViewHeightIsMaximal; }; } diff --git a/escher/include/escher/expression_field.h b/escher/include/escher/expression_field.h index 6e3faf5b2..bdbec1afa 100644 --- a/escher/include/escher/expression_field.h +++ b/escher/include/escher/expression_field.h @@ -23,7 +23,7 @@ public: void setText(const char * text); bool editionIsInTextField() const; bool isEmpty() const; - bool heightIsMaximal() const; + bool inputViewHeightDidChange(); bool handleEventWithText(const char * text, bool indentation = false, bool forceCursorRightOfText = false); /* View */ @@ -35,6 +35,7 @@ public: /* Responder */ bool handleEvent(Ion::Events::Event event) override; + void didBecomeFirstResponder() override; private: static constexpr int k_textFieldBufferSize = TextField::maxBufferSize(); @@ -44,6 +45,7 @@ private: static constexpr KDCoordinate k_verticalMargin = 5; constexpr static KDCoordinate k_separatorThickness = Metric::CellSeparatorThickness; KDCoordinate inputViewHeight() const; + KDCoordinate m_inputViewMemoizedHeight; TextField m_textField; LayoutField m_layoutField; }; diff --git a/escher/include/escher/input_view_controller.h b/escher/include/escher/input_view_controller.h index 2867c6959..5d0bd9197 100644 --- a/escher/include/escher/input_view_controller.h +++ b/escher/include/escher/input_view_controller.h @@ -64,7 +64,6 @@ private: InputEventHandlerDelegate * m_inputEventHandlerDelegate; TextFieldDelegate * m_textFieldDelegate; LayoutFieldDelegate * m_layoutFieldDelegate; - bool m_inputViewHeightIsMaximal; }; #endif diff --git a/escher/src/expression_field.cpp b/escher/src/expression_field.cpp index fb8fcf7df..9c7dbab8a 100644 --- a/escher/src/expression_field.cpp +++ b/escher/src/expression_field.cpp @@ -8,6 +8,7 @@ static inline KDCoordinate maxCoordinate(KDCoordinate x, KDCoordinate y) { retur ExpressionField::ExpressionField(Responder * parentResponder, InputEventHandlerDelegate * inputEventHandlerDelegate, TextFieldDelegate * textFieldDelegate, LayoutFieldDelegate * layoutFieldDelegate) : Responder(parentResponder), View(), + m_inputViewMemoizedHeight(0), m_textField(parentResponder, nullptr, k_textFieldBufferSize, k_textFieldBufferSize, inputEventHandlerDelegate, textFieldDelegate, KDFont::LargeFont, 0.0f, 0.5f, KDColorBlack, KDColorWhite), m_layoutField(parentResponder, inputEventHandlerDelegate, layoutFieldDelegate) { @@ -82,6 +83,10 @@ bool ExpressionField::handleEvent(Ion::Events::Event event) { return editionIsInTextField() ? m_textField.handleEvent(event) : m_layoutField.handleEvent(event); } +void ExpressionField::didBecomeFirstResponder() { + m_inputViewMemoizedHeight = inputViewHeight(); +} + KDSize ExpressionField::minimalSizeForOptimalDisplay() const { return KDSize(0, inputViewHeight()); } @@ -94,8 +99,11 @@ bool ExpressionField::isEmpty() const { return editionIsInTextField() ? (m_textField.draftTextLength() == 0) : !m_layoutField.hasText(); } -bool ExpressionField::heightIsMaximal() const { - return inputViewHeight() == k_separatorThickness + k_maximalHeight; +bool ExpressionField::inputViewHeightDidChange() { + KDCoordinate newHeight = inputViewHeight(); + bool didChange = m_inputViewMemoizedHeight != newHeight; + m_inputViewMemoizedHeight = newHeight; + return didChange; } bool ExpressionField::handleEventWithText(const char * text, bool indentation, bool forceCursorRightOfText) { diff --git a/escher/src/input_view_controller.cpp b/escher/src/input_view_controller.cpp index 669c7e60c..2947054a7 100644 --- a/escher/src/input_view_controller.cpp +++ b/escher/src/input_view_controller.cpp @@ -20,8 +20,7 @@ InputViewController::InputViewController(Responder * parentResponder, ViewContro m_failureAction(Invocation(nullptr, nullptr)), m_inputEventHandlerDelegate(inputEventHandlerDelegate), m_textFieldDelegate(textFieldDelegate), - m_layoutFieldDelegate(layoutFieldDelegate), - m_inputViewHeightIsMaximal(false) + m_layoutFieldDelegate(layoutFieldDelegate) { } @@ -86,11 +85,9 @@ bool InputViewController::layoutFieldDidAbortEditing(LayoutField * layoutField) } void InputViewController::layoutFieldDidChangeSize(LayoutField * layoutField) { - /* Reload the view only if the ExpressionField height actually changes, i.e. - * not if the height is already maximal and stays maximal. */ - bool newInputViewHeightIsMaximal = m_expressionFieldController.expressionField()->heightIsMaximal(); - if (!m_inputViewHeightIsMaximal || !newInputViewHeightIsMaximal) { - m_inputViewHeightIsMaximal = newInputViewHeightIsMaximal; + if (m_expressionFieldController.expressionField()->inputViewHeightDidChange()) { + /* Reload the whole view only if the ExpressionField's height did actually + * change. */ reloadModalViewController(); } else { /* The input view is already at maximal size so we do not need to relayout From d604df85b2064ede20cd60ca139818c18d57afe7 Mon Sep 17 00:00:00 2001 From: Ruben Dashyan Date: Thu, 10 Oct 2019 17:31:33 +0200 Subject: [PATCH 053/680] [escher/layout_field] Remove magic number --- escher/src/layout_field.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/escher/src/layout_field.cpp b/escher/src/layout_field.cpp index 27ac646b5..6a6a5444b 100644 --- a/escher/src/layout_field.cpp +++ b/escher/src/layout_field.cpp @@ -48,7 +48,7 @@ KDSize LayoutField::ContentView::minimalSizeForOptimalDisplay() const { } View * LayoutField::ContentView::subviewAtIndex(int index) { - assert(index >= 0 && index < 2); + assert(0 <= index && index < numberOfSubviews()); View * m_views[] = {&m_expressionView, &m_cursorView}; return m_views[index]; } From 89ea31d1908c3d59a86764353428439f012f6698 Mon Sep 17 00:00:00 2001 From: Ruben Dashyan Date: Thu, 10 Oct 2019 17:33:16 +0200 Subject: [PATCH 054/680] [eshcer/layout_field] Factor handleEvent --- escher/src/layout_field.cpp | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/escher/src/layout_field.cpp b/escher/src/layout_field.cpp index 6a6a5444b..c27a6e882 100644 --- a/escher/src/layout_field.cpp +++ b/escher/src/layout_field.cpp @@ -101,8 +101,6 @@ void LayoutField::reload(KDSize previousSize) { if (m_delegate && previousSize.height() != newSize.height()) { m_delegate->layoutFieldDidChangeSize(this); } - m_contentView.cursorPositionChanged(); - scrollToCursor(); markRectAsDirty(bounds()); } @@ -180,12 +178,11 @@ bool LayoutField::handleEvent(Ion::Events::Event event) { return false; } shouldRecomputeLayout = didHideLayouts || shouldRecomputeLayout; - if (!shouldRecomputeLayout) { - m_contentView.cursorPositionChanged(); - scrollToCursor(); - } else { + if (shouldRecomputeLayout) { reload(previousSize); } + m_contentView.cursorPositionChanged(); + scrollToCursor(); return true; } From bc0b5c092ae68cccf36018f277901b52a99aba18 Mon Sep 17 00:00:00 2001 From: Ruben Dashyan Date: Thu, 10 Oct 2019 17:34:22 +0200 Subject: [PATCH 055/680] [escher/layout_field] Factor insertLayoutAtCursor --- escher/src/layout_field.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/escher/src/layout_field.cpp b/escher/src/layout_field.cpp index c27a6e882..a282e1e3c 100644 --- a/escher/src/layout_field.cpp +++ b/escher/src/layout_field.cpp @@ -358,11 +358,10 @@ void LayoutField::insertLayoutAtCursor(Layout layoutR, Poincare::Expression corr } assert(!cursorMergedLayout.isUninitialized()); m_contentView.cursor()->setLayout(cursorMergedLayout); - m_contentView.cursor()->setPosition(LayoutCursor::Position::Right); } else if (!layoutWillBeMerged) { m_contentView.cursor()->setLayout(layoutR); - m_contentView.cursor()->setPosition(LayoutCursor::Position::Right); } + m_contentView.cursor()->setPosition(LayoutCursor::Position::Right); // Handle matrices cursor->layoutReference().addGreySquaresToAllMatrixAncestors(); From 8cb2b9925437506c84408ee15442b3f1deda252d Mon Sep 17 00:00:00 2001 From: Ruben Dashyan Date: Fri, 3 May 2019 16:08:59 +0200 Subject: [PATCH 056/680] [apps/graph/calculation_graph_controller] Remove handleLeftRightEvent --- apps/graph/graph/calculation_graph_controller.cpp | 10 +++------- apps/graph/graph/calculation_graph_controller.h | 1 - 2 files changed, 3 insertions(+), 8 deletions(-) diff --git a/apps/graph/graph/calculation_graph_controller.cpp b/apps/graph/graph/calculation_graph_controller.cpp index 43622b255..0adcfc2d3 100644 --- a/apps/graph/graph/calculation_graph_controller.cpp +++ b/apps/graph/graph/calculation_graph_controller.cpp @@ -57,13 +57,6 @@ ContinuousFunctionStore * CalculationGraphController::functionStore() const { return App::app()->functionStore(); } -bool CalculationGraphController::handleLeftRightEvent(Ion::Events::Event event) { - if (!m_isActive) { - return false; - } - return SimpleInteractiveCurveViewController::handleLeftRightEvent(event); -} - bool CalculationGraphController::handleEnter() { StackViewController * stack = static_cast(parentResponder()); stack->pop(); @@ -71,6 +64,9 @@ bool CalculationGraphController::handleEnter() { } bool CalculationGraphController::moveCursorHorizontally(int direction, bool fast) { + if (!m_isActive) { + return false; + } Coordinate2D newPointOfInterest = computeNewPointOfInterestFromAbscissa(m_cursor->x(), direction); if (std::isnan(newPointOfInterest.x1())) { return false; diff --git a/apps/graph/graph/calculation_graph_controller.h b/apps/graph/graph/calculation_graph_controller.h index 1586bd149..46f861ddf 100644 --- a/apps/graph/graph/calculation_graph_controller.h +++ b/apps/graph/graph/calculation_graph_controller.h @@ -31,7 +31,6 @@ protected: bool m_isActive; private: bool handleZoom(Ion::Events::Event event) override { return false; } - bool handleLeftRightEvent(Ion::Events::Event event) override; bool handleEnter() override; bool moveCursorHorizontally(int direction, bool fast = false) override; Shared::InteractiveCurveViewRange * interactiveCurveViewRange() override { return m_graphRange; } From 2fb6824947d7a37556ffb7e145b186227dc628b4 Mon Sep 17 00:00:00 2001 From: Ruben Dashyan Date: Fri, 10 May 2019 14:22:12 +0200 Subject: [PATCH 057/680] [apps/shared/interactive_curve_view_controller] Rewrite comment about addMargin --- .../interactive_curve_view_controller.cpp | 43 ++++++++----------- 1 file changed, 17 insertions(+), 26 deletions(-) diff --git a/apps/shared/interactive_curve_view_controller.cpp b/apps/shared/interactive_curve_view_controller.cpp index aa3a0e31c..2480f24c1 100644 --- a/apps/shared/interactive_curve_view_controller.cpp +++ b/apps/shared/interactive_curve_view_controller.cpp @@ -35,38 +35,29 @@ InteractiveCurveViewController::InteractiveCurveViewController(Responder * paren { } -float InteractiveCurveViewController::addMargin(float x, float range, bool isVertical, bool isMin) { - /* We are adding margins. Let's name: - * - The current range: rangeBefore - * - The next range: rangeAfter - * - The bottom margin ratio with which we will evaluate if a point is too - * low on the screen: bottomRatioAfter - * - The bottom margin ratio with which we will evaluate if a point is too - * high on the screen: topRatioAfter - * - The ratios we need to use to create the margins: bottomRatioBefore and - * topRatioBefore - * - * We want to add margins so that: - * bottomRatioAfter*rangeAfter == bottomRatioBefore * rangeBefore - * topRatioAfter*rangeAfter == topRatioBefore * rangeBefore - * Knowing that: - * rangeAfter = (1+bottomRatioBefore+topRatioBefore)*rangeBefore - * - * We thus have: - * bottomRatioBefore = bottomRatioAfter / (1-bottomRatioAfter-topRatioAfter) - * topRatioBefore = topRatioAfter / (1-bottomRatioAfter-topRatioAfter) - * - * If we just used bottomRatioBefore = bottomRatioAfter and - * topRatioBefore = topRatioAfter, we would create too small margins and the - * controller might need to pan right after a Y auto calibration. */ - +float InteractiveCurveViewController::addMargin(float y, float range, bool isVertical, bool isMin) { + /* The provided min or max range limit y is altered by adding a margin. + * In pixels, the view's height occupied by the vertical range is equal to + * viewHeight - topMargin - bottomMargin. + * Hence one pixel must correspond to + * range / (viewHeight - topMargin - bottomMargin). + * Finally, adding topMargin pixels of margin, say at the top, comes down + * to adding + * range * topMargin / (viewHeight - topMargin - bottomMargin) + * which is equal to + * range * topMarginRatio / ( 1 - topMarginRatio - bottomMarginRatio) + * where + * topMarginRation = topMargin / viewHeight + * bottomMarginRatio = bottomMargin / viewHeight. + * The same goes horizontally. + */ float topMarginRatio = isVertical ? cursorTopMarginRatio() : k_cursorRightMarginRatio; float bottomMarginRatio = isVertical ? cursorBottomMarginRatio() : k_cursorLeftMarginRatio; assert(topMarginRatio + bottomMarginRatio < 1); // Assertion so that the formula is correct float ratioDenominator = 1 - bottomMarginRatio - topMarginRatio; float ratio = isMin ? -bottomMarginRatio : topMarginRatio; ratio = ratio / ratioDenominator; - return x+ratio*range; + return y + ratio * range; } const char * InteractiveCurveViewController::title() { From 89aa0ac302f6fd0e9a9bdba4e9a62340982c0e07 Mon Sep 17 00:00:00 2001 From: Ruben Dashyan Date: Mon, 14 Oct 2019 10:32:27 +0200 Subject: [PATCH 058/680] [apps/regression/graph_controller] Clean moveCursorHorizontally --- apps/regression/graph_controller.cpp | 29 +++++++++++++--------------- 1 file changed, 13 insertions(+), 16 deletions(-) diff --git a/apps/regression/graph_controller.cpp b/apps/regression/graph_controller.cpp index 3164fc8be..7c7061fac 100644 --- a/apps/regression/graph_controller.cpp +++ b/apps/regression/graph_controller.cpp @@ -233,27 +233,24 @@ void GraphController::reloadBannerView() { } bool GraphController::moveCursorHorizontally(int direction, bool fast) { + double x; + double y; if (*m_selectedDotIndex >= 0) { int dotSelected = m_store->nextDot(*m_selectedSeriesIndex, direction, *m_selectedDotIndex); if (dotSelected >= 0 && dotSelected < m_store->numberOfPairsOfSeries(*m_selectedSeriesIndex)) { - *m_selectedDotIndex = dotSelected; - double x = m_store->get(*m_selectedSeriesIndex, 0, *m_selectedDotIndex); - double y = m_store->get(*m_selectedSeriesIndex, 1, *m_selectedDotIndex); - m_cursor->moveTo(x, x, y); - return true; + x = m_store->get(*m_selectedSeriesIndex, 0, *m_selectedDotIndex); + y = m_store->get(*m_selectedSeriesIndex, 1, *m_selectedDotIndex); + } else if (dotSelected == m_store->numberOfPairsOfSeries(*m_selectedSeriesIndex)) { + x = m_store->meanOfColumn(*m_selectedSeriesIndex, 0); + y = m_store->meanOfColumn(*m_selectedSeriesIndex, 1); + } else { + return false } - if (dotSelected == m_store->numberOfPairsOfSeries(*m_selectedSeriesIndex)) { - *m_selectedDotIndex = dotSelected; - double x = m_store->meanOfColumn(*m_selectedSeriesIndex, 0); - double y = m_store->meanOfColumn(*m_selectedSeriesIndex, 1); - m_cursor->moveTo(x, x, y); - return true; - } - return false; + *m_selectedDotIndex = dotSelected; + } else { + x = m_cursor->x() + direction * m_store->xGridUnit()/k_numberOfCursorStepsInGradUnit; + y = yValue(*m_selectedSeriesIndex, x, globalContext()); } - double x = direction > 0 ? m_cursor->x() + m_store->xGridUnit()/k_numberOfCursorStepsInGradUnit : - m_cursor->x() - m_store->xGridUnit()/k_numberOfCursorStepsInGradUnit; - double y = yValue(*m_selectedSeriesIndex, x, globalContext()); m_cursor->moveTo(x, x, y); return true; } From 3a19939a64409f412da2eec793d73665f5dd02b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Tue, 15 Oct 2019 15:35:56 +0200 Subject: [PATCH 059/680] [apps/regression] Missing ; --- apps/regression/graph_controller.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/regression/graph_controller.cpp b/apps/regression/graph_controller.cpp index 7c7061fac..f3e7fd5d0 100644 --- a/apps/regression/graph_controller.cpp +++ b/apps/regression/graph_controller.cpp @@ -244,7 +244,7 @@ bool GraphController::moveCursorHorizontally(int direction, bool fast) { x = m_store->meanOfColumn(*m_selectedSeriesIndex, 0); y = m_store->meanOfColumn(*m_selectedSeriesIndex, 1); } else { - return false + return false; } *m_selectedDotIndex = dotSelected; } else { From 7f4dd1255aee96fb1be5fca2a65c76525d04ed52 Mon Sep 17 00:00:00 2001 From: Ruben Dashyan Date: Tue, 15 Oct 2019 16:06:18 +0200 Subject: [PATCH 060/680] Revert "[escher/layout_field] Factor insertLayoutAtCursor" This reverts commit b06cac4fcce0c1ab3fedd6c44846983962316749. --- escher/src/layout_field.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/escher/src/layout_field.cpp b/escher/src/layout_field.cpp index a282e1e3c..c27a6e882 100644 --- a/escher/src/layout_field.cpp +++ b/escher/src/layout_field.cpp @@ -358,10 +358,11 @@ void LayoutField::insertLayoutAtCursor(Layout layoutR, Poincare::Expression corr } assert(!cursorMergedLayout.isUninitialized()); m_contentView.cursor()->setLayout(cursorMergedLayout); + m_contentView.cursor()->setPosition(LayoutCursor::Position::Right); } else if (!layoutWillBeMerged) { m_contentView.cursor()->setLayout(layoutR); + m_contentView.cursor()->setPosition(LayoutCursor::Position::Right); } - m_contentView.cursor()->setPosition(LayoutCursor::Position::Right); // Handle matrices cursor->layoutReference().addGreySquaresToAllMatrixAncestors(); From 5787d50a4552921f2299dfbd5e03d0b9e0737d75 Mon Sep 17 00:00:00 2001 From: Ruben Dashyan Date: Tue, 15 Oct 2019 16:31:26 +0200 Subject: [PATCH 061/680] Revert "[apps/calculation/edit_expression_controller] Define viewWillAppear" This reverts commit 960736203ff2f816688868e3397d178d931fa3c3. --- apps/calculation/edit_expression_controller.cpp | 2 ++ apps/calculation/history_controller.cpp | 10 ++++------ apps/calculation/history_controller.h | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/apps/calculation/edit_expression_controller.cpp b/apps/calculation/edit_expression_controller.cpp index df76015ab..37aeb7973 100644 --- a/apps/calculation/edit_expression_controller.cpp +++ b/apps/calculation/edit_expression_controller.cpp @@ -52,6 +52,8 @@ void EditExpressionController::insertTextBody(const char * text) { } void EditExpressionController::didBecomeFirstResponder() { + int lastRow = m_calculationStore->numberOfCalculations() > 0 ? m_calculationStore->numberOfCalculations()-1 : 0; + m_historyController->scrollToCell(0, lastRow); m_contentView.expressionField()->setEditing(true, false); Container::activeApp()->setFirstResponder(m_contentView.expressionField()); } diff --git a/apps/calculation/history_controller.cpp b/apps/calculation/history_controller.cpp index d96789e4c..b3fb5b2ce 100644 --- a/apps/calculation/history_controller.cpp +++ b/apps/calculation/history_controller.cpp @@ -18,12 +18,6 @@ HistoryController::HistoryController(Responder * parentResponder, CalculationSto } } -void HistoryController::viewWillAppear() { - int rowsCount = numberOfRows(); - int lastRow = (rowsCount > 0) * (rowsCount - 1); - selectCellAtLocation(0, lastRow); -} - void HistoryController::reload() { m_selectableTableView.reloadData(); /* TODO @@ -174,6 +168,10 @@ int HistoryController::typeAtLocation(int i, int j) { return 0; } +void HistoryController::scrollToCell(int i, int j) { + m_selectableTableView.scrollToCell(i, j); +} + HistoryViewCell * HistoryController::historyViewCellDidChangeSelection() { /* Update the whole table as the height of the selected cell row might have * changed. */ diff --git a/apps/calculation/history_controller.h b/apps/calculation/history_controller.h index 06d108c8d..f75c20015 100644 --- a/apps/calculation/history_controller.h +++ b/apps/calculation/history_controller.h @@ -14,7 +14,6 @@ class HistoryController : public ViewController, public ListViewDataSource, publ public: HistoryController(Responder * parentResponder, CalculationStore * calculationStore); View * view() override { return &m_selectableTableView; } - void viewWillAppear() override; bool handleEvent(Ion::Events::Event event) override; void didBecomeFirstResponder() override; void willExitResponderChain(Responder * nextFirstResponder) override; @@ -26,6 +25,7 @@ public: KDCoordinate rowHeight(int j) override; int typeAtLocation(int i, int j) override; void tableViewDidChangeSelection(SelectableTableView * t, int previousSelectedCellX, int previousSelectedCellY, bool withinTemporarySelection = false) override; + void scrollToCell(int i, int j); private: int storeIndex(int i) { return numberOfRows() - i - 1; } Shared::ExpiringPointer calculationAtIndex(int i); From 2c497d4f55140d41acf6b5f221045ab510d2068d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Wed, 16 Oct 2019 10:45:48 +0200 Subject: [PATCH 062/680] Revert "[escher] Force relayouting in a table view" This reverts commit 94281b906d5135f4d3181ca248f572e32be9119c. The commit created a lot of blinking in the calculation history (for instance for multiple lines of 56) + "the table's size might be miscomputed" due to the layouting order (but we have not searched for an example of such a miscomputation) --- escher/src/table_view.cpp | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/escher/src/table_view.cpp b/escher/src/table_view.cpp index b98bc909a..f4c72317e 100644 --- a/escher/src/table_view.cpp +++ b/escher/src/table_view.cpp @@ -34,8 +34,23 @@ const char * TableView::className() const { #endif void TableView::layoutSubviews(bool force) { - // We force the layoutSubviews in case the frame did not change. - ScrollView::layoutSubviews(true); + /* On the one hand, ScrollView::layoutSubviews() + * calls setFrame(...) over m_contentView, + * which typically calls layoutSubviews() over m_contentView. + * However, if the frame happens to be unchanged, + * setFrame(...) does not call layoutSubviews. + * On the other hand, calling only m_contentView.layoutSubviews() + * does not relayout ScrollView when the offset + * or the content's size changes. + * For those reasons, we call both of them explicitly. + * Besides, one must call layoutSubviews() over + * m_contentView first, in order to reload the table's data, + * otherwise the table's size might be miscomputed... + * FIXME: + * Finally, this solution is not optimal at all since + * layoutSubviews is called twice over m_contentView. */ + m_contentView.layoutSubviews(force); + ScrollView::layoutSubviews(force); } void TableView::reloadCellAtLocation(int i, int j) { From 3747b5a4b0d29c145ba950051662b8f7f242dfec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Thu, 21 Nov 2019 15:04:44 +0100 Subject: [PATCH 063/680] [apps/regression] Virtualize only the specialized part of initCoefs --- apps/regression/model/model.cpp | 23 ++++++++++++------- apps/regression/model/model.h | 3 ++- apps/regression/model/trigonometric_model.cpp | 6 +---- apps/regression/model/trigonometric_model.h | 2 +- 4 files changed, 19 insertions(+), 15 deletions(-) diff --git a/apps/regression/model/model.cpp b/apps/regression/model/model.cpp index bcbb14b19..13f711574 100644 --- a/apps/regression/model/model.cpp +++ b/apps/regression/model/model.cpp @@ -40,14 +40,6 @@ void Model::fit(Store * store, int series, double * modelCoefficients, Poincare: } } -void Model::initCoefficientsForFit(double * modelCoefficients, double defaultValue, bool forceDefaultValue, Store * store, int series) const { - assert(defaultValue || (store != nullptr && series >= 0 && series < Store::k_numberOfSeries && !store->seriesIsEmpty(series))); - int nbCoef = numberOfCoefficients(); - for (int i = 0; i < nbCoef; i++) { - modelCoefficients[i] = defaultValue; - } -} - bool Model::dataSuitableForFit(Store * store, int series) const { if (!store->seriesNumberOfAbscissaeGreaterOrEqualTo(series, numberOfCoefficients())) { return false; @@ -209,5 +201,20 @@ int Model::solveLinearSystem(double * solutions, double * coefficients, double * return 0; } +void Model::initCoefficientsForFit(double * modelCoefficients, double defaultValue, bool forceDefaultValue, Store * store, int series) const { + assert(forceDefaultValue || (store != nullptr && series >= 0 && series < Store::k_numberOfSeries && !store->seriesIsEmpty(series))); + if (forceDefaultValue) { + Model::specializedInitCoefficientsForFit(modelCoefficients, defaultValue); + } else { + specializedInitCoefficientsForFit(modelCoefficients, defaultValue, store, series); + } } +void Model::specializedInitCoefficientsForFit(double * modelCoefficients, double defaultValue, Store * store, int series) const { + const int nbCoef = numberOfCoefficients(); + for (int i = 0; i < nbCoef; i++) { + modelCoefficients[i] = defaultValue; + } +} + +} diff --git a/apps/regression/model/model.h b/apps/regression/model/model.h index 4c2550946..c018a3528 100644 --- a/apps/regression/model/model.h +++ b/apps/regression/model/model.h @@ -39,7 +39,6 @@ public: virtual int bannerLinesCount() const { return 2; } protected: // Fit - virtual void initCoefficientsForFit(double * modelCoefficients, double defaultValue, bool forceDefaultValue, Store * store = nullptr, int series = -1) const; virtual bool dataSuitableForFit(Store * store, int series) const; constexpr static const KDFont * k_layoutFont = KDFont::SmallFont; Poincare::Layout m_layout; @@ -62,6 +61,8 @@ private: double alphaCoefficient(Store * store, int series, double * modelCoefficients, int k, int l) const; double betaCoefficient(Store * store, int series, double * modelCoefficients, int k) const; int solveLinearSystem(double * solutions, double * coefficients, double * constants, int solutionDimension, Poincare::Context * context); + void initCoefficientsForFit(double * modelCoefficients, double defaultValue, bool forceDefaultValue, Store * store = nullptr, int series = -1) const; + virtual void specializedInitCoefficientsForFit(double * modelCoefficients, double defaultValue, Store * store = nullptr, int series = -1) const; }; } diff --git a/apps/regression/model/trigonometric_model.cpp b/apps/regression/model/trigonometric_model.cpp index b65110481..f32f2c66b 100644 --- a/apps/regression/model/trigonometric_model.cpp +++ b/apps/regression/model/trigonometric_model.cpp @@ -70,11 +70,7 @@ double TrigonometricModel::partialDerivate(double * modelCoefficients, int deriv return 0.0; } -void TrigonometricModel::initCoefficientsForFit(double * modelCoefficients, double defaultValue, bool forceDefaultValue, Store * store, int series) const { - if (forceDefaultValue) { - Model::initCoefficientsForFit(modelCoefficients, defaultValue, forceDefaultValue); - return; - } +void TrigonometricModel::specializedInitCoefficientsForFit(double * modelCoefficients, double defaultValue, Store * store, int series) const { assert(store != nullptr && series >= 0 && series < Store::k_numberOfSeries && !store->seriesIsEmpty(series)); for (int i = 1; i < k_numberOfCoefficients - 1; i++) { modelCoefficients[i] = defaultValue; diff --git a/apps/regression/model/trigonometric_model.h b/apps/regression/model/trigonometric_model.h index c3fdad8f0..83ed05113 100644 --- a/apps/regression/model/trigonometric_model.h +++ b/apps/regression/model/trigonometric_model.h @@ -16,7 +16,7 @@ public: int bannerLinesCount() const override { return 4; } private: static constexpr int k_numberOfCoefficients = 4; - void initCoefficientsForFit(double * modelCoefficients, double defaultValue, bool forceDefaultValue, Store * store = nullptr, int series = -1) const override; + void specializedInitCoefficientsForFit(double * modelCoefficients, double defaultValue, Store * store, int series) const override; Poincare::Expression expression(double * modelCoefficients) override; }; From a8ead6b66e82405e7f79566b3bb81327f701af79 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Thu, 21 Nov 2019 15:05:46 +0100 Subject: [PATCH 064/680] [apps/regression] Better initialisation of logistic model coefficients It provides a better fit for: x = {0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0} y = {5.0, 9.0, 40.0, 64.0, 144.0, 200.0, 269.0, 278.0, 290.0, 295.0} (coeffs should be {64.9, 1.0, 297.4}) --- apps/regression/model/logistic_model.cpp | 13 +++++++++++++ apps/regression/model/logistic_model.h | 2 ++ 2 files changed, 15 insertions(+) diff --git a/apps/regression/model/logistic_model.cpp b/apps/regression/model/logistic_model.cpp index 5ffe02a48..f74db8f3d 100644 --- a/apps/regression/model/logistic_model.cpp +++ b/apps/regression/model/logistic_model.cpp @@ -1,4 +1,5 @@ #include "logistic_model.h" +#include "../store.h" #include #include #include @@ -81,4 +82,16 @@ double LogisticModel::partialDerivate(double * modelCoefficients, int derivateCo return 0.0; } +void LogisticModel::specializedInitCoefficientsForFit(double * modelCoefficients, double defaultValue, Store * store, int series) const { + assert(store != nullptr && series >= 0 && series < Store::k_numberOfSeries && !store->seriesIsEmpty(series)); + modelCoefficients[0] = defaultValue; + modelCoefficients[1] = defaultValue; + /* If the data is a standard logistic function, the ordinates are between 0 + * and c. Twice the standard vertical deviation is a rough estimate of c + * that is "close enough" to c to seed the coefficient, without being too + * dependent on outliers.*/ + modelCoefficients[2] = 2.0*store->standardDeviationOfColumn(series, 1); +} + + } diff --git a/apps/regression/model/logistic_model.h b/apps/regression/model/logistic_model.h index aa338e88e..fbdca27e9 100644 --- a/apps/regression/model/logistic_model.h +++ b/apps/regression/model/logistic_model.h @@ -15,6 +15,8 @@ public: double partialDerivate(double * modelCoefficients, int derivateCoefficientIndex, double x) const override; int numberOfCoefficients() const override { return 3; } int bannerLinesCount() const override { return 3; } +private: + void specializedInitCoefficientsForFit(double * modelCoefficients, double defaultValue, Store * store, int series) const override; }; } From 4e6378fe18b51b9edcaebdab455c4c094f33d3ba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Thu, 21 Nov 2019 11:26:50 +0100 Subject: [PATCH 065/680] [test/regression] Add a logistic test --- apps/regression/test/model.cpp | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/apps/regression/test/model.cpp b/apps/regression/test/model.cpp index d03f42fa0..732e69a7d 100644 --- a/apps/regression/test/model.cpp +++ b/apps/regression/test/model.cpp @@ -99,11 +99,18 @@ QUIZ_CASE(power_regression) { // No case for trigonometric regression, because it has no unique solution -/* This data was generated without the random error, otherwise it did not pass - * the test. */ + QUIZ_CASE(logistic_regression) { - double x[] = {2.3, 5.6, 1.1, 4.3}; - double y[] = {3.948, 4.694, 2.184, 4.656}; - double coefficients[] = {6, 1.5, 4.7}; - assert_regression_is(x, y, 4, Model::Type::Logistic, coefficients); + /* This data was generated without the random error, otherwise it did not pass + * the test. */ + double x1[] = {2.3, 5.6, 1.1, 4.3}; + double y1[] = {3.948, 4.694, 2.184, 4.656}; + double coefficients1[] = {6, 1.5, 4.7}; + assert_regression_is(x1, y1, 4, Model::Type::Logistic, coefficients1); + + // This data produced a wrong fit before + double x2[] = {0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0}; + double y2[] = {5.0, 9.0, 40.0, 64.0, 144.0, 200.0, 269.0, 278.0, 290.0, 295.0}; + double coefficients2[] = {64.9, 1.0, 297.4}; + assert_regression_is(x2, y2, 10, Model::Type::Logistic, coefficients2); } From 6ff28bf5ea01759fded33c49890e82e26204ae8f Mon Sep 17 00:00:00 2001 From: Ruben Dashyan Date: Thu, 7 Nov 2019 15:34:06 +0100 Subject: [PATCH 066/680] [poincare/addition] Do not recompute the number of children in shallowBeautify --- poincare/src/addition.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/poincare/src/addition.cpp b/poincare/src/addition.cpp index 182a06cca..ab849187f 100644 --- a/poincare/src/addition.cpp +++ b/poincare/src/addition.cpp @@ -94,7 +94,8 @@ Expression Addition::shallowBeautify(ExpressionNode::ReductionContext reductionC * 1+R(2) --> R(2)+1 */ sortChildrenInPlace([](const ExpressionNode * e1, const ExpressionNode * e2, bool canBeInterrupted) { return ExpressionNode::SimplificationOrder(e1, e2, false, canBeInterrupted); }, reductionContext.context(), true); - for (int i = 0; i < numberOfChildren(); i++) { + int nbChildren = numberOfChildren(); + for (int i = 0; i < nbChildren; i++) { // Try to make the child i positive if any negative numeral factor is found Expression subtractant = childAtIndex(i).makePositiveAnyNegativeNumeralFactor(reductionContext); if (subtractant.isUninitialized()) @@ -113,6 +114,7 @@ Expression Addition::shallowBeautify(ExpressionNode::ReductionContext reductionC /* CAUTION: we removed a child. So we need to decrement i to make sure * the next iteration is actually on the next child. */ i--; + nbChildren--; Subtraction s = Subtraction::Builder(leftSibling, subtractant); /* We stole subtractant from this which replaced it by a ghost. We thus * need to put the subtraction at the previous index of subtractant, which From 5d1cc521f4ac9e77e6416263c47f65a4d397aaf4 Mon Sep 17 00:00:00 2001 From: Ruben Dashyan Date: Thu, 7 Nov 2019 15:35:41 +0100 Subject: [PATCH 067/680] [poincare/expression] Mark nbChildren variable as const in deepBeautify --- poincare/src/expression.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/poincare/src/expression.cpp b/poincare/src/expression.cpp index 23bca3ef0..897e013fd 100644 --- a/poincare/src/expression.cpp +++ b/poincare/src/expression.cpp @@ -737,7 +737,7 @@ Expression Expression::deepReduce(ExpressionNode::ReductionContext reductionCont Expression Expression::deepBeautify(ExpressionNode::ReductionContext reductionContext) { Expression e = shallowBeautify(reductionContext); - int nbChildren = e.numberOfChildren(); + const int nbChildren = e.numberOfChildren(); for (int i = 0; i < nbChildren; i++) { Expression child = e.childAtIndex(i); child = child.deepBeautify(reductionContext); From 3271fc90a4b095a0e13f7d3d39263067e3612293 Mon Sep 17 00:00:00 2001 From: Ruben Dashyan Date: Wed, 20 Nov 2019 11:59:39 +0100 Subject: [PATCH 068/680] [poincare/test] Clean header inclusions --- poincare/test/approximation.cpp | 7 ------- poincare/test/arithmetic.cpp | 4 ---- poincare/test/context.cpp | 3 --- poincare/test/expression_order.cpp | 6 +----- poincare/test/expression_properties.cpp | 4 ---- poincare/test/expression_serialization.cpp | 3 --- poincare/test/expression_to_layout.cpp | 3 --- poincare/test/helper.cpp | 1 - poincare/test/helpers.cpp | 2 -- poincare/test/ieee754.cpp | 7 ++----- poincare/test/integer.cpp | 5 ----- poincare/test/layout.cpp | 5 ----- poincare/test/layout_cursor.cpp | 1 - poincare/test/layout_serialization.cpp | 7 ++----- poincare/test/layout_to_expression.cpp | 5 ----- poincare/test/parsing.cpp | 3 --- poincare/test/print_float.cpp | 7 ------- poincare/test/print_int.cpp | 2 -- poincare/test/rational.cpp | 5 ----- poincare/test/simplification.cpp | 9 +-------- poincare/test/tree/tree_handle.cpp | 1 - 21 files changed, 6 insertions(+), 84 deletions(-) diff --git a/poincare/test/approximation.cpp b/poincare/test/approximation.cpp index d6573c8d7..d57065930 100644 --- a/poincare/test/approximation.cpp +++ b/poincare/test/approximation.cpp @@ -1,12 +1,5 @@ -#include -#include -#include -#include #include -#include -#include #include "helper.h" -#include "./tree/helpers.h" using namespace Poincare; diff --git a/poincare/test/arithmetic.cpp b/poincare/test/arithmetic.cpp index 99db22a3c..d8a9ad9c7 100644 --- a/poincare/test/arithmetic.cpp +++ b/poincare/test/arithmetic.cpp @@ -1,8 +1,4 @@ -#include -#include -#include #include -#include #include #include "helper.h" diff --git a/poincare/test/context.cpp b/poincare/test/context.cpp index 323a8101d..a5c0c5326 100644 --- a/poincare/test/context.cpp +++ b/poincare/test/context.cpp @@ -1,6 +1,3 @@ -#include -#include -#include #include #include #include "helper.h" diff --git a/poincare/test/expression_order.cpp b/poincare/test/expression_order.cpp index 59ec0dc6c..adf4ed1be 100644 --- a/poincare/test/expression_order.cpp +++ b/poincare/test/expression_order.cpp @@ -1,8 +1,4 @@ -#include #include -#include -#include -#include #include "helper.h" using namespace Poincare; @@ -79,7 +75,7 @@ void assert_multiplication_or_addition_is_ordered_as(Expression e1, Expression e &globalContext, true); } else { - assert(e1.type() == ExpressionNode::Type::Addition); + quiz_assert(e1.type() == ExpressionNode::Type::Addition); static_cast(e1).sortChildrenInPlace( [](const ExpressionNode * e1, const ExpressionNode * e2, bool canBeInterrupted) { return ExpressionNode::SimplificationOrder(e1, e2, false, canBeInterrupted); }, &globalContext, diff --git a/poincare/test/expression_properties.cpp b/poincare/test/expression_properties.cpp index afa85d849..2296092e3 100644 --- a/poincare/test/expression_properties.cpp +++ b/poincare/test/expression_properties.cpp @@ -1,9 +1,5 @@ -#include #include -#include -#include #include "helper.h" -#include "tree/helpers.h" using namespace Poincare; diff --git a/poincare/test/expression_serialization.cpp b/poincare/test/expression_serialization.cpp index abe0d4c4a..618af624b 100644 --- a/poincare/test/expression_serialization.cpp +++ b/poincare/test/expression_serialization.cpp @@ -1,6 +1,3 @@ -#include -#include -#include #include "helper.h" using namespace Poincare; diff --git a/poincare/test/expression_to_layout.cpp b/poincare/test/expression_to_layout.cpp index bff29d596..045cb3b0f 100644 --- a/poincare/test/expression_to_layout.cpp +++ b/poincare/test/expression_to_layout.cpp @@ -1,8 +1,5 @@ -#include -#include #include #include "helper.h" -#include "tree/helpers.h" using namespace Poincare; diff --git a/poincare/test/helper.cpp b/poincare/test/helper.cpp index d79d8b27d..d733ab22e 100644 --- a/poincare/test/helper.cpp +++ b/poincare/test/helper.cpp @@ -1,7 +1,6 @@ #include "helper.h" #include #include -#include using namespace Poincare; diff --git a/poincare/test/helpers.cpp b/poincare/test/helpers.cpp index 0032649d1..9c6c9b3f8 100644 --- a/poincare/test/helpers.cpp +++ b/poincare/test/helpers.cpp @@ -1,5 +1,3 @@ -#include -#include #include #include "helper.h" diff --git a/poincare/test/ieee754.cpp b/poincare/test/ieee754.cpp index 800dbc9fc..85bdee9d4 100644 --- a/poincare/test/ieee754.cpp +++ b/poincare/test/ieee754.cpp @@ -1,9 +1,6 @@ -#include #include #include -#include #include -#include #include #include "helper.h" @@ -26,8 +23,8 @@ QUIZ_CASE(ieee754_next_and_previous) { assert_next_and_previous_IEEE754_is(-0.0f, 0.0f); assert_next_and_previous_IEEE754_is(-1.4E-45f, -0.0f); assert_next_and_previous_IEEE754_is(-3.4359738E10f, -3.43597363E10f); - assert(IEEE754::next(3.4028235E38f) == INFINITY); - assert(IEEE754::previous(-3.4028235E38f) == -INFINITY); + quiz_assert(IEEE754::next(3.4028235E38f) == INFINITY); + quiz_assert(IEEE754::previous(-3.4028235E38f) == -INFINITY); assert_next_and_previous_IEEE754_is(0.0f, 4.94065645841246544176568792868E-324); assert_next_and_previous_IEEE754_is(INFINITY, INFINITY); diff --git a/poincare/test/integer.cpp b/poincare/test/integer.cpp index 2d1cf098e..d58da4a47 100644 --- a/poincare/test/integer.cpp +++ b/poincare/test/integer.cpp @@ -1,8 +1,3 @@ -#include -#include -#include - -#include "tree/helpers.h" #include "helper.h" using namespace Poincare; diff --git a/poincare/test/layout.cpp b/poincare/test/layout.cpp index aad8ea97b..983184abb 100644 --- a/poincare/test/layout.cpp +++ b/poincare/test/layout.cpp @@ -1,10 +1,5 @@ -#include #include -#include -#include -#include #include "helper.h" -#include "./tree/helpers.h" using namespace Poincare; diff --git a/poincare/test/layout_cursor.cpp b/poincare/test/layout_cursor.cpp index f97f6505a..de87d2afe 100644 --- a/poincare/test/layout_cursor.cpp +++ b/poincare/test/layout_cursor.cpp @@ -1,4 +1,3 @@ -#include #include #include "helper.h" diff --git a/poincare/test/layout_serialization.cpp b/poincare/test/layout_serialization.cpp index 5a07238ef..4e0115faa 100644 --- a/poincare/test/layout_serialization.cpp +++ b/poincare/test/layout_serialization.cpp @@ -1,14 +1,11 @@ -#include -#include -#include #include #include "helper.h" using namespace Poincare; QUIZ_CASE(poincare_layout_serialization) { - assert(UCodePointLeftSystemParenthesis == 0x12); - assert(UCodePointRightSystemParenthesis == 0x13); + quiz_assert(UCodePointLeftSystemParenthesis == 0x12); + quiz_assert(UCodePointRightSystemParenthesis == 0x13); // AbsoluteValueLayout assert_layout_serialize_to( diff --git a/poincare/test/layout_to_expression.cpp b/poincare/test/layout_to_expression.cpp index 56ba8077b..f991c0b8a 100644 --- a/poincare/test/layout_to_expression.cpp +++ b/poincare/test/layout_to_expression.cpp @@ -1,10 +1,5 @@ -#include #include -#include -#include -#include #include "helper.h" -#include "./tree/helpers.h" using namespace Poincare; diff --git a/poincare/test/parsing.cpp b/poincare/test/parsing.cpp index 560714caa..dc11804ef 100644 --- a/poincare/test/parsing.cpp +++ b/poincare/test/parsing.cpp @@ -1,8 +1,5 @@ #include #include -#include -#include -#include #include #include "tree/helpers.h" #include "helper.h" diff --git a/poincare/test/print_float.cpp b/poincare/test/print_float.cpp index b5ea82238..56c0aca6f 100644 --- a/poincare/test/print_float.cpp +++ b/poincare/test/print_float.cpp @@ -1,12 +1,5 @@ -#include -#include -#include -#include -#include #include -#include #include -#include #include #include "helper.h" diff --git a/poincare/test/print_int.cpp b/poincare/test/print_int.cpp index 0edd100de..a91fd4ded 100644 --- a/poincare/test/print_int.cpp +++ b/poincare/test/print_int.cpp @@ -1,6 +1,4 @@ -#include #include -#include #include "helper.h" using namespace Poincare; diff --git a/poincare/test/rational.cpp b/poincare/test/rational.cpp index 35b878032..0b481c485 100644 --- a/poincare/test/rational.cpp +++ b/poincare/test/rational.cpp @@ -1,9 +1,4 @@ -#include -#include -#include -#include #include "helper.h" -#include "tree/helpers.h" using namespace Poincare; diff --git a/poincare/test/simplification.cpp b/poincare/test/simplification.cpp index 86a546098..8b18db527 100644 --- a/poincare/test/simplification.cpp +++ b/poincare/test/simplification.cpp @@ -1,12 +1,5 @@ -#include -#include -#include -#include -#include -#include -#include +#include #include "helper.h" -#include "./tree/helpers.h" using namespace Poincare; diff --git a/poincare/test/tree/tree_handle.cpp b/poincare/test/tree/tree_handle.cpp index ff66ba727..421bafb25 100644 --- a/poincare/test/tree/tree_handle.cpp +++ b/poincare/test/tree/tree_handle.cpp @@ -2,7 +2,6 @@ #include #include #include -#include #include "blob_node.h" #include "pair_node.h" From caa7e6fbbff111f6a513264ee4f22f1b4ed1e773 Mon Sep 17 00:00:00 2001 From: Ruben Dashyan Date: Thu, 21 Nov 2019 10:43:22 +0100 Subject: [PATCH 069/680] [poincare/test/helper] Print richer information when test fails --- poincare/test/helper.cpp | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/poincare/test/helper.cpp b/poincare/test/helper.cpp index d733ab22e..4f62cac12 100644 --- a/poincare/test/helper.cpp +++ b/poincare/test/helper.cpp @@ -44,7 +44,30 @@ void assert_parsed_expression_process_to(const char * expression, const char * r constexpr int bufferSize = 500; char buffer[bufferSize]; m.serialize(buffer, bufferSize, DecimalMode, numberOfSignifiantDigits); - quiz_assert_print_if_failure(strcmp(buffer, result) == 0, expression); + const bool test = strcmp(buffer, result) == 0; + char information[bufferSize] = ""; + if (!test) { + char * position = information; + size_t remainingLength = bufferSize; + static constexpr size_t numberOfPieces = 6; + const char * piecesOfInformation[numberOfPieces] = { + " ", + expression, + "\n processed to\n ", + buffer, + "\n instead of\n ", + result, + }; + for (size_t piece = 0; piece < numberOfPieces; piece++) { + const size_t length = strlcpy(position, piecesOfInformation[piece], remainingLength); + if (length > remainingLength) { + break; + } + remainingLength -= length; + position += length; + } + } + quiz_assert_print_if_failure(test, information); } Poincare::Expression parse_expression(const char * expression, bool addParentheses) { From ab80741838e550fb8fb8a3885aeae8c22d092aea Mon Sep 17 00:00:00 2001 From: Ruben Dashyan Date: Thu, 31 Oct 2019 14:28:48 +0100 Subject: [PATCH 070/680] [poincare/test/simplification] Remove redundant tests --- poincare/test/simplification.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/poincare/test/simplification.cpp b/poincare/test/simplification.cpp index 8b18db527..1e3fba405 100644 --- a/poincare/test/simplification.cpp +++ b/poincare/test/simplification.cpp @@ -108,7 +108,6 @@ QUIZ_CASE(poincare_simplification_addition) { assert_parsed_expression_simplify_to("1+2", "3"); assert_parsed_expression_simplify_to("1+2+3+4+5+6+7", "28"); assert_parsed_expression_simplify_to("(0+0)", "0"); - assert_parsed_expression_simplify_to("2+A", "A+2"); assert_parsed_expression_simplify_to("1+2+3+4+5+A+6+7", "A+28"); assert_parsed_expression_simplify_to("1+A+2+B+3", "A+B+6"); assert_parsed_expression_simplify_to("-2+6", "4"); @@ -142,7 +141,6 @@ QUIZ_CASE(poincare_simplification_multiplication) { assert_parsed_expression_simplify_to("3×A^4×B^x×B^2×(A^2+2)×2×1.2", "\u001236×A^6×B^\u0012x+2\u0013+72×A^4×B^\u0012x+2\u0013\u0013/5"); assert_parsed_expression_simplify_to("A×(B+C)×(D+3)", "3×A×B+3×A×C+A×B×D+A×C×D"); assert_parsed_expression_simplify_to("A/B", "A/B"); - assert_parsed_expression_simplify_to("(A×B)^2", "A^2×B^2"); assert_parsed_expression_simplify_to("(1/2)×A/B", "A/\u00122×B\u0013"); assert_parsed_expression_simplify_to("1+2+3+4+5+6", "21"); assert_parsed_expression_simplify_to("1-2+3-4+5-6", "-3"); @@ -168,7 +166,6 @@ QUIZ_CASE(poincare_simplification_multiplication) { assert_parsed_expression_simplify_to("A^3×B×A^(-3)", "B"); assert_parsed_expression_simplify_to("A^3×A^(-3)", "1"); assert_parsed_expression_simplify_to("2^π×(1/2)^π", "1"); - assert_parsed_expression_simplify_to("A^3×A^(-3)", "1"); assert_parsed_expression_simplify_to("(x+1)×(x+2)", "x^2+3×x+2"); assert_parsed_expression_simplify_to("(x+1)×(x-1)", "x^2-1"); assert_parsed_expression_simplify_to("11π/(22π+11π)", "1/3"); From 967343f75de0e5ee550f67ab80bbd9c4ed8d5450 Mon Sep 17 00:00:00 2001 From: Ruben Dashyan Date: Wed, 30 Oct 2019 16:31:36 +0100 Subject: [PATCH 071/680] [poincare/parser] Remove IsReservedName unused parameter The function is only called in apps/shared/function. --- poincare/src/parsing/parser.cpp | 4 ++-- poincare/src/parsing/parser.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/poincare/src/parsing/parser.cpp b/poincare/src/parsing/parser.cpp index 8305d5eb9..79948c3c5 100644 --- a/poincare/src/parsing/parser.cpp +++ b/poincare/src/parsing/parser.cpp @@ -17,8 +17,8 @@ Expression Parser::parse() { return Expression(); } -bool Parser::IsReservedName(const char * name, size_t nameLength, const Expression::FunctionHelper * const * * functionHelper) { - return IsReservedFunctionName(name, nameLength, functionHelper) +bool Parser::IsReservedName(const char * name, size_t nameLength) { + return IsReservedFunctionName(name, nameLength) || IsSpecialIdentifierName(name, nameLength); } diff --git a/poincare/src/parsing/parser.h b/poincare/src/parsing/parser.h index 25fedf107..3366cc4a7 100644 --- a/poincare/src/parsing/parser.h +++ b/poincare/src/parsing/parser.h @@ -30,7 +30,7 @@ public: Expression parse(); Status getStatus() const { return m_status; } - static bool IsReservedName(const char * name, size_t nameLength, const Expression::FunctionHelper * const * * functionHelper = nullptr); + static bool IsReservedName(const char * name, size_t nameLength); private: static bool IsReservedFunctionName(const char * name, size_t nameLength, const Expression::FunctionHelper * const * * functionHelper = nullptr); From 4ef46b4fdb94917e44619abbaf1000ba49ffe804 Mon Sep 17 00:00:00 2001 From: Ruben Dashyan Date: Wed, 30 Oct 2019 16:40:21 +0100 Subject: [PATCH 072/680] [poincare/parser] IsReservedFunctionName returns a pointer and is hence renamed GetReservedFunction --- poincare/src/parsing/parser.cpp | 13 +++++++------ poincare/src/parsing/parser.h | 2 +- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/poincare/src/parsing/parser.cpp b/poincare/src/parsing/parser.cpp index 79948c3c5..6b8ac7a98 100644 --- a/poincare/src/parsing/parser.cpp +++ b/poincare/src/parsing/parser.cpp @@ -18,13 +18,13 @@ Expression Parser::parse() { } bool Parser::IsReservedName(const char * name, size_t nameLength) { - return IsReservedFunctionName(name, nameLength) + return GetReservedFunction(name, nameLength) != nullptr || IsSpecialIdentifierName(name, nameLength); } // Private -bool Parser::IsReservedFunctionName(const char * name, size_t nameLength, const Expression::FunctionHelper * const * * functionHelper) { +const Expression::FunctionHelper * const * Parser::GetReservedFunction(const char * name, size_t nameLength) { const Expression::FunctionHelper * const * reservedFunction = &s_reservedFunctions[0]; assert(reservedFunction < s_reservedFunctionsUpperBound); int nameDifference = Token::CompareNonNullTerminatedName(name, nameLength, (**reservedFunction).name()); @@ -32,10 +32,10 @@ bool Parser::IsReservedFunctionName(const char * name, size_t nameLength, const reservedFunction++; nameDifference = Token::CompareNonNullTerminatedName(name, nameLength, (**reservedFunction).name()); } - if (functionHelper != nullptr) { - *functionHelper = reservedFunction; + if (reservedFunction < s_reservedFunctionsUpperBound && nameDifference == 0) { + return reservedFunction; } - return (reservedFunction < s_reservedFunctionsUpperBound && nameDifference == 0); + return nullptr; } bool Parser::IsSpecialIdentifierName(const char * name, size_t nameLength) { @@ -327,7 +327,8 @@ void Parser::parseBang(Expression & leftHandSide, Token::Type stoppingType) { } bool Parser::currentTokenIsReservedFunction(const Expression::FunctionHelper * const * * functionHelper) const { - return IsReservedFunctionName(m_currentToken.text(), m_currentToken.length(), functionHelper); + *functionHelper = GetReservedFunction(m_currentToken.text(), m_currentToken.length()); + return *functionHelper != nullptr; } bool Parser::currentTokenIsSpecialIdentifier() const { diff --git a/poincare/src/parsing/parser.h b/poincare/src/parsing/parser.h index 3366cc4a7..d7df5bb7c 100644 --- a/poincare/src/parsing/parser.h +++ b/poincare/src/parsing/parser.h @@ -33,7 +33,7 @@ public: static bool IsReservedName(const char * name, size_t nameLength); private: - static bool IsReservedFunctionName(const char * name, size_t nameLength, const Expression::FunctionHelper * const * * functionHelper = nullptr); + static const Expression::FunctionHelper * const * GetReservedFunction(const char * name, size_t nameLength); static bool IsSpecialIdentifierName(const char * name, size_t nameLength); Expression parseUntil(Token::Type stoppingType); From 9a3e0e9bd32b9f8134b43e0b39f2b991973f6073 Mon Sep 17 00:00:00 2001 From: Ruben Dashyan Date: Wed, 30 Oct 2019 16:57:03 +0100 Subject: [PATCH 073/680] [poincare/parser] Simplify GetReservedFunction --- poincare/src/parsing/parser.cpp | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/poincare/src/parsing/parser.cpp b/poincare/src/parsing/parser.cpp index 6b8ac7a98..ce8165c97 100644 --- a/poincare/src/parsing/parser.cpp +++ b/poincare/src/parsing/parser.cpp @@ -25,15 +25,16 @@ bool Parser::IsReservedName(const char * name, size_t nameLength) { // Private const Expression::FunctionHelper * const * Parser::GetReservedFunction(const char * name, size_t nameLength) { - const Expression::FunctionHelper * const * reservedFunction = &s_reservedFunctions[0]; - assert(reservedFunction < s_reservedFunctionsUpperBound); - int nameDifference = Token::CompareNonNullTerminatedName(name, nameLength, (**reservedFunction).name()); - while (reservedFunction < s_reservedFunctionsUpperBound && nameDifference > 0) { + const Expression::FunctionHelper * const * reservedFunction = s_reservedFunctions; + while (reservedFunction < s_reservedFunctionsUpperBound) { + int nameDifference = Token::CompareNonNullTerminatedName(name, nameLength, (**reservedFunction).name()); + if (nameDifference == 0) { + return reservedFunction; + } + if (nameDifference < 0) { + break; + } reservedFunction++; - nameDifference = Token::CompareNonNullTerminatedName(name, nameLength, (**reservedFunction).name()); - } - if (reservedFunction < s_reservedFunctionsUpperBound && nameDifference == 0) { - return reservedFunction; } return nullptr; } From 55e01fbfd45e232447b658a9d0d9cabd5a9a9ad4 Mon Sep 17 00:00:00 2001 From: Ruben Dashyan Date: Wed, 30 Oct 2019 17:31:10 +0100 Subject: [PATCH 074/680] [poincare/parser] Remove currentTokenIsReservedFunction and currentTokenIsSpecialIdentifier Use GetReservedFunction and IsSpecialIdentifierName instead. --- poincare/src/parsing/parser.cpp | 21 ++++----------------- poincare/src/parsing/parser.h | 4 +--- 2 files changed, 5 insertions(+), 20 deletions(-) diff --git a/poincare/src/parsing/parser.cpp b/poincare/src/parsing/parser.cpp index ce8165c97..9667bc0f3 100644 --- a/poincare/src/parsing/parser.cpp +++ b/poincare/src/parsing/parser.cpp @@ -274,8 +274,7 @@ void Parser::parseStore(Expression & leftHandSide, Token::Type stoppingType) { } // At this point, m_currentToken is Token::Store. popToken(); - const Expression::FunctionHelper * const * functionHelper; - if (!m_currentToken.is(Token::Identifier) || currentTokenIsReservedFunction(&functionHelper) || currentTokenIsSpecialIdentifier()) { + if (!m_currentToken.is(Token::Identifier) || IsReservedName(m_currentToken.text(), m_currentToken.length())) { m_status = Status::Error; // The right-hand side of Token::Store must be symbol or function that is not reserved. return; } @@ -327,15 +326,6 @@ void Parser::parseBang(Expression & leftHandSide, Token::Type stoppingType) { isThereImplicitMultiplication(); } -bool Parser::currentTokenIsReservedFunction(const Expression::FunctionHelper * const * * functionHelper) const { - *functionHelper = GetReservedFunction(m_currentToken.text(), m_currentToken.length()); - return *functionHelper != nullptr; -} - -bool Parser::currentTokenIsSpecialIdentifier() const { - return IsSpecialIdentifierName(m_currentToken.text(), m_currentToken.length()); -} - void Parser::parseConstant(Expression & leftHandSide, Token::Type stoppingType) { leftHandSide = Constant::Builder(m_currentToken.codePoint()); isThereImplicitMultiplication(); @@ -469,13 +459,10 @@ void Parser::parseIdentifier(Expression & leftHandSide, Token::Type stoppingType m_status = Status::Error; //FIXME return; } - const Expression::FunctionHelper * const * functionHelper; - /* If m_currentToken corresponds to a reserved function, the method - * currentTokenIsReservedFunction will make functionHelper point to an - * element of s_reservedFunctions. */ - if (currentTokenIsReservedFunction(&functionHelper)) { + const Expression::FunctionHelper * const * functionHelper = GetReservedFunction(m_currentToken.text(), m_currentToken.length()); + if (functionHelper != nullptr) { parseReservedFunction(leftHandSide, functionHelper); - } else if (currentTokenIsSpecialIdentifier()) { + } else if (IsSpecialIdentifierName(m_currentToken.text(), m_currentToken.length())) { parseSpecialIdentifier(leftHandSide); } else { parseCustomIdentifier(leftHandSide, m_currentToken.text(), m_currentToken.length()); diff --git a/poincare/src/parsing/parser.h b/poincare/src/parsing/parser.h index d7df5bb7c..93d3c11c5 100644 --- a/poincare/src/parsing/parser.h +++ b/poincare/src/parsing/parser.h @@ -70,9 +70,7 @@ private: Expression parseVector(); Expression parseFunctionParameters(); Expression parseCommaSeparatedList(); - bool currentTokenIsReservedFunction(const Expression::FunctionHelper * const * * functionHelper) const; void parseReservedFunction(Expression & leftHandSide, const Expression::FunctionHelper * const * functionHelper); - bool currentTokenIsSpecialIdentifier() const; void parseSpecialIdentifier(Expression & leftHandSide); void parseSequence(Expression & leftHandSide, const char name, Token::Type leftDelimiter, Token::Type rightDelimiter); void parseCustomIdentifier(Expression & leftHandSide, const char * name, size_t length); @@ -149,7 +147,7 @@ private: &SquareRoot::s_functionHelper }; static constexpr const Expression::FunctionHelper * const * s_reservedFunctionsUpperBound = s_reservedFunctions + (sizeof(s_reservedFunctions)/sizeof(Expression::FunctionHelper *)); - /* The method currentTokenIsReservedFunction passes through the successive + /* The method GetReservedFunction passes through the successive * entries of the above array in order to determine whether m_currentToken * corresponds to an entry. As a helper, the static constexpr * s_reservedFunctionsUpperBound marks the end of the array. */ From 1556e2daad9e857ea303ee14d6b8e3e12b5696e8 Mon Sep 17 00:00:00 2001 From: Ruben Dashyan Date: Thu, 31 Oct 2019 17:24:53 +0100 Subject: [PATCH 075/680] [poincare/power] Simplify denominator --- poincare/src/power.cpp | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/poincare/src/power.cpp b/poincare/src/power.cpp index d94699392..e90cb4203 100644 --- a/poincare/src/power.cpp +++ b/poincare/src/power.cpp @@ -892,17 +892,16 @@ Expression Power::shallowBeautify(ExpressionNode::ReductionContext reductionCont // Simplification Expression Power::denominator(ExpressionNode::ReductionContext reductionContext) const { - // Clone the power - Expression clone = Power::Builder(childAtIndex(0).clone(), childAtIndex(1).clone()); + Expression pow = clone(); // If the power is of form x^(-y), denominator should be x^y - Expression positiveIndex = clone.childAtIndex(1).makePositiveAnyNegativeNumeralFactor(reductionContext); + Expression positiveIndex = pow.childAtIndex(1).makePositiveAnyNegativeNumeralFactor(reductionContext); if (!positiveIndex.isUninitialized()) { - // if y was -1, clone is now x^1, denominator is then only x - // we cannot shallowReduce the clone as it is not attached to its parent yet + // if y was -1, pow is now x^1, denominator is then only x + // we cannot shallowReduce the pow as it is not attached to its parent yet if (positiveIndex.isRationalOne()) { - return clone.childAtIndex(0); + return pow.childAtIndex(0); } - return clone; + return pow; } return Expression(); } From 4bdc2043c8ecab4e18e8f00b79c3678b19b3c0e1 Mon Sep 17 00:00:00 2001 From: Ruben Dashyan Date: Thu, 31 Oct 2019 17:56:14 +0100 Subject: [PATCH 076/680] [poincare/power] coding style in denominator --- poincare/src/power.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/poincare/src/power.cpp b/poincare/src/power.cpp index e90cb4203..c0741bdc3 100644 --- a/poincare/src/power.cpp +++ b/poincare/src/power.cpp @@ -895,15 +895,15 @@ Expression Power::denominator(ExpressionNode::ReductionContext reductionContext) Expression pow = clone(); // If the power is of form x^(-y), denominator should be x^y Expression positiveIndex = pow.childAtIndex(1).makePositiveAnyNegativeNumeralFactor(reductionContext); - if (!positiveIndex.isUninitialized()) { - // if y was -1, pow is now x^1, denominator is then only x - // we cannot shallowReduce the pow as it is not attached to its parent yet - if (positiveIndex.isRationalOne()) { - return pow.childAtIndex(0); - } - return pow; + if (positiveIndex.isUninitialized()) { + return Expression(); } - return Expression(); + // we cannot shallowReduce pow as it is not attached to its parent yet + // if y was -1, pow is now x^1, denominator is then only x + if (positiveIndex.isRationalOne()) { + return pow.childAtIndex(0); + } + return pow; } Expression Power::simplifyPowerPower(ExpressionNode::ReductionContext reductionContext) { From e4820a52f79ac1cc235185d6112270876eb61e7c Mon Sep 17 00:00:00 2001 From: Ruben Dashyan Date: Thu, 17 Oct 2019 14:32:20 +0200 Subject: [PATCH 077/680] [poincare/symbol_abstract] Make nodeSize private --- poincare/include/poincare/symbol_abstract.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/poincare/include/poincare/symbol_abstract.h b/poincare/include/poincare/symbol_abstract.h index 4159b1162..8424abf3e 100644 --- a/poincare/include/poincare/symbol_abstract.h +++ b/poincare/include/poincare/symbol_abstract.h @@ -46,7 +46,7 @@ public: } #endif -protected: +private: virtual size_t nodeSize() const = 0; }; From 87c1f4f39cda718c671b405071e987263a2675e9 Mon Sep 17 00:00:00 2001 From: Ruben Dashyan Date: Thu, 17 Oct 2019 14:21:56 +0200 Subject: [PATCH 078/680] [poincare] Remove redundancy TreeNode::serialize(char * buffer, int bufferSize, ...) returns the number of chars it did write in buffer, null-terminating char excluded. strlcpy(char * dst, const char * src, size_t len) returns the length of src. Hence the min. The case where bufferSize equals 0 does not need to be handled separately since it is already contained in the min. --- poincare/src/constant.cpp | 3 --- poincare/src/symbol.cpp | 3 --- poincare/src/undefined.cpp | 3 --- poincare/src/unreal.cpp | 3 --- 4 files changed, 12 deletions(-) diff --git a/poincare/src/constant.cpp b/poincare/src/constant.cpp index f1eca17ff..441762470 100644 --- a/poincare/src/constant.cpp +++ b/poincare/src/constant.cpp @@ -65,9 +65,6 @@ Layout ConstantNode::createLayout(Preferences::PrintFloatMode floatDisplayMode, } int ConstantNode::serialize(char * buffer, int bufferSize, Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const { - if (bufferSize == 0) { - return -1; - } return minInt(strlcpy(buffer, m_name, bufferSize), bufferSize - 1); } diff --git a/poincare/src/symbol.cpp b/poincare/src/symbol.cpp index ba424b3a0..5c37bb281 100644 --- a/poincare/src/symbol.cpp +++ b/poincare/src/symbol.cpp @@ -93,9 +93,6 @@ Layout SymbolNode::createLayout(Preferences::PrintFloatMode floatDisplayMode, in } int SymbolNode::serialize(char * buffer, int bufferSize, Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const { - if (bufferSize == 0) { - return -1; - } return minInt(bufferSize - 1, strlcpy(buffer, m_name, bufferSize)); } diff --git a/poincare/src/undefined.cpp b/poincare/src/undefined.cpp index 4e9a10b06..0a7a8c1a6 100644 --- a/poincare/src/undefined.cpp +++ b/poincare/src/undefined.cpp @@ -25,9 +25,6 @@ Layout UndefinedNode::createLayout(Preferences::PrintFloatMode floatDisplayMode, } int UndefinedNode::serialize(char * buffer, int bufferSize, Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const { - if (bufferSize == 0) { - return -1; - } return minInt(strlcpy(buffer, Undefined::Name(), bufferSize), bufferSize - 1); } diff --git a/poincare/src/unreal.cpp b/poincare/src/unreal.cpp index c46f3f1a4..ca2a9ddd8 100644 --- a/poincare/src/unreal.cpp +++ b/poincare/src/unreal.cpp @@ -15,9 +15,6 @@ Layout UnrealNode::createLayout(Preferences::PrintFloatMode floatDisplayMode, in } int UnrealNode::serialize(char * buffer, int bufferSize, Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const { - if (bufferSize == 0) { - return -1; - } return minInt(strlcpy(buffer, Unreal::Name(), bufferSize), bufferSize - 1); } From f0bfb41cab497f78b25b0db9e6b47b15855c8385 Mon Sep 17 00:00:00 2001 From: Ruben Dashyan Date: Thu, 17 Oct 2019 14:40:44 +0200 Subject: [PATCH 079/680] [poincare/symbol_abstract] Factor serialize --- poincare/include/poincare/constant.h | 1 - poincare/include/poincare/symbol.h | 1 - poincare/include/poincare/symbol_abstract.h | 3 +++ poincare/src/constant.cpp | 6 ------ poincare/src/symbol.cpp | 6 ------ poincare/src/symbol_abstract.cpp | 6 ++++++ 6 files changed, 9 insertions(+), 14 deletions(-) diff --git a/poincare/include/poincare/constant.h b/poincare/include/poincare/constant.h index f1e024e1a..9ce7ab4fa 100644 --- a/poincare/include/poincare/constant.h +++ b/poincare/include/poincare/constant.h @@ -31,7 +31,6 @@ public: /* Layout */ Layout createLayout(Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const override; - int serialize(char * buffer, int bufferSize, Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const override; /* Approximation */ Evaluation approximate(SinglePrecision p, Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit) const override { return templatedApproximate(context, complexFormat, angleUnit); } diff --git a/poincare/include/poincare/symbol.h b/poincare/include/poincare/symbol.h index 393b552f2..bfc37f337 100644 --- a/poincare/include/poincare/symbol.h +++ b/poincare/include/poincare/symbol.h @@ -29,7 +29,6 @@ public: /* Layout */ Layout createLayout(Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const override; - int serialize(char * buffer, int bufferSize, Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const override; /* Simplification */ Expression shallowReduce(ReductionContext reductionContext) override; diff --git a/poincare/include/poincare/symbol_abstract.h b/poincare/include/poincare/symbol_abstract.h index 8424abf3e..ab3f53fa3 100644 --- a/poincare/include/poincare/symbol_abstract.h +++ b/poincare/include/poincare/symbol_abstract.h @@ -48,6 +48,9 @@ public: private: virtual size_t nodeSize() const = 0; + + // Layout + int serialize(char * buffer, int bufferSize, Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const override; }; /* WARNING: symbol abstract cannot have any virtual methods. Otherwise, diff --git a/poincare/src/constant.cpp b/poincare/src/constant.cpp index 441762470..4c6977e34 100644 --- a/poincare/src/constant.cpp +++ b/poincare/src/constant.cpp @@ -14,8 +14,6 @@ namespace Poincare { -static inline int minInt(int x, int y) { return x < y ? x : y; } - ConstantNode::ConstantNode(const char * newName, int length) : SymbolAbstractNode() { strlcpy(const_cast(name()), newName, length+1); } @@ -64,10 +62,6 @@ Layout ConstantNode::createLayout(Preferences::PrintFloatMode floatDisplayMode, return LayoutHelper::String(m_name, strlen(m_name)); } -int ConstantNode::serialize(char * buffer, int bufferSize, Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const { - return minInt(strlcpy(buffer, m_name, bufferSize), bufferSize - 1); -} - template Evaluation ConstantNode::templatedApproximate(Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit) const { if (isIComplex()) { diff --git a/poincare/src/symbol.cpp b/poincare/src/symbol.cpp index 5c37bb281..d6b3661dd 100644 --- a/poincare/src/symbol.cpp +++ b/poincare/src/symbol.cpp @@ -16,8 +16,6 @@ namespace Poincare { -static inline int minInt(int x, int y) { return x < y ? x : y; } - constexpr char Symbol::k_ans[]; SymbolNode::SymbolNode(const char * newName, int length) : SymbolAbstractNode() { @@ -92,10 +90,6 @@ Layout SymbolNode::createLayout(Preferences::PrintFloatMode floatDisplayMode, in return LayoutHelper::String(m_name, strlen(m_name)); } -int SymbolNode::serialize(char * buffer, int bufferSize, Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const { - return minInt(bufferSize - 1, strlcpy(buffer, m_name, bufferSize)); -} - Expression SymbolNode::shallowReduce(ReductionContext reductionContext) { return Symbol(this).shallowReduce(reductionContext); } diff --git a/poincare/src/symbol_abstract.cpp b/poincare/src/symbol_abstract.cpp index 41c2bfc6b..59587a364 100644 --- a/poincare/src/symbol_abstract.cpp +++ b/poincare/src/symbol_abstract.cpp @@ -12,6 +12,8 @@ namespace Poincare { +static inline int minInt(int x, int y) { return x < y ? x : y; } + size_t SymbolAbstractNode::size() const { return nodeSize() + strlen(name()) + 1; } @@ -38,6 +40,10 @@ int SymbolAbstractNode::simplificationOrderSameType(const ExpressionNode * e, bo return strcmp(name(), static_cast(e)->name()); } +int SymbolAbstractNode::serialize(char * buffer, int bufferSize, Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const { + return minInt(strlcpy(buffer, name(), bufferSize), bufferSize - 1); +} + template T SymbolAbstract::Builder(const char * name, int length) { size_t size = sizeof(U) + length + 1; From c238c5f736d8527bd77a46db6dd0850bdcb23734 Mon Sep 17 00:00:00 2001 From: Ruben Dashyan Date: Thu, 17 Oct 2019 14:47:16 +0200 Subject: [PATCH 080/680] [poincare/symbol_abstract] Remove unnecessary friend class Store --- poincare/include/poincare/symbol.h | 1 - poincare/include/poincare/symbol_abstract.h | 1 - 2 files changed, 2 deletions(-) diff --git a/poincare/include/poincare/symbol.h b/poincare/include/poincare/symbol.h index bfc37f337..7be80fc78 100644 --- a/poincare/include/poincare/symbol.h +++ b/poincare/include/poincare/symbol.h @@ -49,7 +49,6 @@ private: class Symbol final : public SymbolAbstract { friend class Expression; - friend class Store; friend class SymbolNode; public: static constexpr int k_ansLength = 3; diff --git a/poincare/include/poincare/symbol_abstract.h b/poincare/include/poincare/symbol_abstract.h index ab3f53fa3..7639c30ad 100644 --- a/poincare/include/poincare/symbol_abstract.h +++ b/poincare/include/poincare/symbol_abstract.h @@ -24,7 +24,6 @@ namespace Poincare { * */ class SymbolAbstractNode : public ExpressionNode { - friend class Store; public: virtual const char * name() const = 0; size_t size() const override; From 961a0f5f2bfbebfead341747bea42f7700daa8e6 Mon Sep 17 00:00:00 2001 From: Ruben Dashyan Date: Thu, 17 Oct 2019 14:49:01 +0200 Subject: [PATCH 081/680] [poincare/constant] Simplify shallowReduce --- poincare/src/constant.cpp | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/poincare/src/constant.cpp b/poincare/src/constant.cpp index 4c6977e34..f1e607196 100644 --- a/poincare/src/constant.cpp +++ b/poincare/src/constant.cpp @@ -99,12 +99,11 @@ Expression Constant::shallowReduce(ExpressionNode::ReductionContext reductionCon result = Unreal::Builder(); } else if (reductionContext.target() == ExpressionNode::ReductionTarget::User && isI) { result = ComplexCartesian::Builder(Rational::Builder(0), Rational::Builder(1)); + } else { + return *this; } - if (!result.isUninitialized()) { - replaceWithInPlace(result); - return result; - } - return *this; + replaceWithInPlace(result); + return result; } template Evaluation ConstantNode::templatedApproximate(Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit) const; From 686b74cfe41fd7f044bc4ed7dc27c0a26adcc99e Mon Sep 17 00:00:00 2001 From: Ruben Dashyan Date: Mon, 28 Oct 2019 11:41:23 +0100 Subject: [PATCH 082/680] [poincare/constant] Remove unused parameters from templatedApproximate --- poincare/include/poincare/constant.h | 6 +++--- poincare/src/constant.cpp | 4 +--- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/poincare/include/poincare/constant.h b/poincare/include/poincare/constant.h index 9ce7ab4fa..591ca7e2d 100644 --- a/poincare/include/poincare/constant.h +++ b/poincare/include/poincare/constant.h @@ -33,8 +33,8 @@ public: Layout createLayout(Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const override; /* Approximation */ - Evaluation approximate(SinglePrecision p, Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit) const override { return templatedApproximate(context, complexFormat, angleUnit); } - Evaluation approximate(DoublePrecision p, Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit) const override { return templatedApproximate(context, complexFormat, angleUnit); } + Evaluation approximate(SinglePrecision p, Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit) const override { return templatedApproximate(); } + Evaluation approximate(DoublePrecision p, Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit) const override { return templatedApproximate(); } /* Symbol properties */ bool isPi() const { return isConstantCodePoint(UCodePointGreekSmallLetterPi); } @@ -53,7 +53,7 @@ private: char m_name[0]; // MUST be the last member variable size_t nodeSize() const override { return sizeof(ConstantNode); } - template Evaluation templatedApproximate(Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit) const; + template Evaluation templatedApproximate() const; bool isConstantCodePoint(CodePoint c) const; }; diff --git a/poincare/src/constant.cpp b/poincare/src/constant.cpp index f1e607196..40729429c 100644 --- a/poincare/src/constant.cpp +++ b/poincare/src/constant.cpp @@ -63,7 +63,7 @@ Layout ConstantNode::createLayout(Preferences::PrintFloatMode floatDisplayMode, } template -Evaluation ConstantNode::templatedApproximate(Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit) const { +Evaluation ConstantNode::templatedApproximate() const { if (isIComplex()) { return Complex::Builder(0.0, 1.0); } @@ -106,6 +106,4 @@ Expression Constant::shallowReduce(ExpressionNode::ReductionContext reductionCon return result; } -template Evaluation ConstantNode::templatedApproximate(Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit) const; -template Evaluation ConstantNode::templatedApproximate(Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit) const; } From 70c9d063a23d389c0b5288402a3d6ed08d0c4f3f Mon Sep 17 00:00:00 2001 From: Ruben Dashyan Date: Mon, 14 Oct 2019 14:48:34 +0200 Subject: [PATCH 083/680] [poincare/symbol] Use replaceWithInPlace in shallowReduce --- poincare/src/symbol.cpp | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/poincare/src/symbol.cpp b/poincare/src/symbol.cpp index d6b3661dd..aad298986 100644 --- a/poincare/src/symbol.cpp +++ b/poincare/src/symbol.cpp @@ -151,11 +151,9 @@ bool Symbol::isRegressionSymbol(const char * c) { } Expression Symbol::shallowReduce(ExpressionNode::ReductionContext reductionContext) { - Expression parentExpression = parent(); { Expression current = *this; - Expression p = parentExpression; - + Expression p = parent(); while (!p.isUninitialized()) { if (p.isParameteredExpression()) { int index = p.indexOfChild(current); @@ -185,9 +183,7 @@ Expression Symbol::shallowReduce(ExpressionNode::ReductionContext reductionConte } result = Undefined::Builder(); } - if (!parentExpression.isUninitialized()) { - parentExpression.replaceChildInPlace(*this, result); - } + replaceWithInPlace(result); // The stored expression is as entered by the user, so we need to call reduce return result.deepReduce(reductionContext); } From 95c72358315ea3100fca6d00a9aab93bfd1b9dc2 Mon Sep 17 00:00:00 2001 From: Ruben Dashyan Date: Tue, 19 Nov 2019 10:59:54 +0100 Subject: [PATCH 084/680] [poincare] Align implementation of shallowReduce in Symbol and Function --- poincare/src/function.cpp | 18 +++++++++--------- poincare/src/symbol.cpp | 3 +-- 2 files changed, 10 insertions(+), 11 deletions(-) diff --git a/poincare/src/function.cpp b/poincare/src/function.cpp index 706bad731..e222c4e16 100644 --- a/poincare/src/function.cpp +++ b/poincare/src/function.cpp @@ -112,16 +112,16 @@ Expression Function::replaceSymbolWithExpression(const SymbolAbstract & symbol, } Expression Function::shallowReduce(ExpressionNode::ReductionContext reductionContext) { - Function f(*this); - Expression e = SymbolAbstract::Expand(f, reductionContext.context(), true); - if (!e.isUninitialized()) { - replaceWithInPlace(e); - return e.deepReduce(reductionContext); + Expression result = SymbolAbstract::Expand(*this, reductionContext.context(), true); + if (result.isUninitialized()) { + if (reductionContext.symbolicComputation()) { + return *this; + } + result = Undefined::Builder(); } - if (!reductionContext.symbolicComputation()) { - return replaceWithUndefinedInPlace(); - } - return *this; + replaceWithInPlace(result); + // The stored expression is as entered by the user, so we need to call reduce + return result.deepReduce(reductionContext); } Expression Function::deepReplaceReplaceableSymbols(Context * context, bool * didReplace) { diff --git a/poincare/src/symbol.cpp b/poincare/src/symbol.cpp index aad298986..1ac631ffe 100644 --- a/poincare/src/symbol.cpp +++ b/poincare/src/symbol.cpp @@ -175,8 +175,7 @@ Expression Symbol::shallowReduce(ExpressionNode::ReductionContext reductionConte } } - Symbol s = *this; - Expression result = SymbolAbstract::Expand(s, reductionContext.context(), true); + Expression result = SymbolAbstract::Expand(*this, reductionContext.context(), true); if (result.isUninitialized()) { if (reductionContext.symbolicComputation()) { return *this; From c9d337d536b91ecb5520791dea42f3ffb5aa93be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Tue, 26 Nov 2019 10:45:40 +0100 Subject: [PATCH 085/680] py/builtinimport: Raise exception on empty name. --- python/src/py/builtinimport.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/python/src/py/builtinimport.c b/python/src/py/builtinimport.c index 1a333b540..bb88f2ace 100644 --- a/python/src/py/builtinimport.c +++ b/python/src/py/builtinimport.c @@ -334,6 +334,10 @@ mp_obj_t mp_builtin___import__(size_t n_args, const mp_obj_t *args) { mod_len = new_mod_l; } + if (mod_len == 0) { + mp_raise_ValueError(NULL); + } + // check if module already exists qstr module_name_qstr = mp_obj_str_get_qstr(module_name); mp_obj_t module_obj = mp_module_get(module_name_qstr); From d0a65b01c0a8eb3c09b1a5706f5b2897975176c1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Tue, 26 Nov 2019 10:47:32 +0100 Subject: [PATCH 086/680] py/qstr: Raise exception in qstr_from_strn if str to intern is too long. --- python/src/py/qstr.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/python/src/py/qstr.c b/python/src/py/qstr.c index e6f86401a..29ffcae40 100644 --- a/python/src/py/qstr.c +++ b/python/src/py/qstr.c @@ -31,6 +31,7 @@ #include "py/mpstate.h" #include "py/qstr.h" #include "py/gc.h" +#include "py/runtime.h" // NOTE: we are using linear arrays to store and search for qstr's (unique strings, interned strings) // ultimately we will replace this with a static hash table of some kind @@ -192,12 +193,17 @@ qstr qstr_from_str(const char *str) { } qstr qstr_from_strn(const char *str, size_t len) { - assert(len < (1 << (8 * MICROPY_QSTR_BYTES_IN_LEN))); QSTR_ENTER(); qstr q = qstr_find_strn(str, len); if (q == 0) { // qstr does not exist in interned pool so need to add it + // check that len is not too big + if (len >= (1 << (8 * MICROPY_QSTR_BYTES_IN_LEN))) { + QSTR_EXIT(); + mp_raise_msg(&mp_type_RuntimeError, "name too long"); + } + // compute number of bytes needed to intern this string size_t n_bytes = MICROPY_QSTR_BYTES_IN_HASH + MICROPY_QSTR_BYTES_IN_LEN + len + 1; From d1e93a291861b3845584a18e733518e950897f1e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Mon, 2 Dec 2019 12:13:32 +0100 Subject: [PATCH 087/680] [python] Python stack: fix limit --- python/port/port.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/python/port/port.cpp b/python/port/port.cpp index 163aefd24..9e77ced31 100644 --- a/python/port/port.cpp +++ b/python/port/port.cpp @@ -101,11 +101,15 @@ extern "C" { void MicroPython::init(void * heapStart, void * heapEnd) { #if MP_PORT_USE_STACK_SYMBOLS mp_stack_set_top(&_stack_start); - mp_stack_set_limit(&_stack_start - &_stack_end); + size_t stackLimitInBytes = (char *)&_stack_start - (char *)&_stack_end; + mp_stack_set_limit(stackLimitInBytes); #else volatile int stackTop; mp_stack_set_top((void *)(&stackTop)); - mp_stack_set_limit(8192); + /* The stack limit is set to roughly mimic the maximal recursion depth of the + * device - and actually to be slightly less to be sure not to beat the device + * performance. */ + mp_stack_set_limit(29152); #endif gc_init(heapStart, heapEnd); mp_init(); From 4b58efbc0a23d412d983e1f23af44200b44129c7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Mon, 2 Dec 2019 12:19:31 +0100 Subject: [PATCH 088/680] [python] Fix stack boundary on the device --- python/port/port.cpp | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/python/port/port.cpp b/python/port/port.cpp index 9e77ced31..7fa7a4044 100644 --- a/python/port/port.cpp +++ b/python/port/port.cpp @@ -99,13 +99,20 @@ extern "C" { } void MicroPython::init(void * heapStart, void * heapEnd) { + volatile int stackTop; + void * stackTopAddress = (void *)(&stackTop); + /* We delimit the stack part that will be used by Python. The stackTop is the + * address of the first object that can be allocated on Python stack. This + * boundaries are used: + * - by gc_collect to determine where to collect roots of the objects that + * must be kept on the heap + * - to check if the maximal recursion depth has been reached. */ #if MP_PORT_USE_STACK_SYMBOLS - mp_stack_set_top(&_stack_start); - size_t stackLimitInBytes = (char *)&_stack_start - (char *)&_stack_end; + mp_stack_set_top(stackTopAddress); + size_t stackLimitInBytes = (char *)stackTopAddress - (char *)&_stack_end; mp_stack_set_limit(stackLimitInBytes); #else - volatile int stackTop; - mp_stack_set_top((void *)(&stackTop)); + mp_stack_set_top(stackTopAddress); /* The stack limit is set to roughly mimic the maximal recursion depth of the * device - and actually to be slightly less to be sure not to beat the device * performance. */ From 37061b9cb5669f662b0b27884d4c6993fb2f5d68 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Mon, 2 Dec 2019 14:47:47 +0100 Subject: [PATCH 089/680] [python] Fix gc_collect to be sure to get unaligned pointers --- python/port/mod/turtle/modturtle.cpp | 7 ++++++- python/port/port.cpp | 19 +++++++++++++++++-- 2 files changed, 23 insertions(+), 3 deletions(-) diff --git a/python/port/mod/turtle/modturtle.cpp b/python/port/mod/turtle/modturtle.cpp index 44c78c0e4..e8fb50a66 100644 --- a/python/port/mod/turtle/modturtle.cpp +++ b/python/port/mod/turtle/modturtle.cpp @@ -8,7 +8,12 @@ static Turtle sTurtle; void modturtle_gc_collect() { // Mark the shared sTurtle object as a GC root - gc_collect_root((void **)&sTurtle, sizeof(Turtle)/sizeof(void *)); + for (size_t i = 0; i < sizeof(void *); i++) { + // See comment in port.cpp: gc_collect implementation + char * turtleWithOffset = (char *)&sTurtle + i; + size_t turtleLengthInAddressSize = (sizeof(Turtle) - i + sizeof(void *) - 1)/sizeof(void *); + gc_collect_root((void **)turtleWithOffset, turtleLengthInAddressSize); + } } void modturtle_view_did_disappear() { diff --git a/python/port/port.cpp b/python/port/port.cpp index 7fa7a4044..9fcdddc6a 100644 --- a/python/port/port.cpp +++ b/python/port/port.cpp @@ -156,7 +156,7 @@ void gc_collect(void) { /* To compute the stack length: * regs * <-----------> - * STACK -> ...| | | | | |--|--|--|--| | | | | | | + * STACK <- ...| | | | | |--|--|--|--| | | | | | | * ^®s ^python_stack_top * */ @@ -178,7 +178,22 @@ void gc_collect(void) { } /* Memory error detectors might find an error here as they might split regs * and stack memory zones. */ - gc_collect_root(scanStart, stackLengthInByte/sizeof(void *)); + for (size_t i = 0; i < sizeof(void *); i++) { + /* Objects on the stack are not necessarily aligned on sizeof(void *), + * which is also true for pointers refering to the heap. MicroPython + * gc_collect_root expects a table of void * that will be scanned every + * sizeof(void *) step. So we have to scan the stack repetitively with a + * increasing offset to be sure to check every byte for a heap address. + * If some memory can be reinterpreted as a pointer in the heap, gc_collect_root + * will prevent the destruction of the pointed heap memory. At worst (if + * the interpreted pointer was in fact an unaligned object or uninitialized + * memory), we will just keep extra objects in the heap which is not optimal + * but does not cause any crash. */ + char * scanStartWithOffset = (char *)scanStart + i; + // Ensure to round the length to the ceiling + size_t stackLengthInAddressSize = (stackLengthInByte - i + sizeof(void *) - 1)/sizeof(void *); + gc_collect_root((void **)scanStartWithOffset, stackLengthInAddressSize); + } gc_collect_end(); } From ea3f23cb09b4de8599590e086d43d11f38bbc664 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Tue, 26 Nov 2019 11:43:39 +0100 Subject: [PATCH 090/680] [poincare/tree_pool] Fix and add assertions on TreePool::node(id) --- poincare/include/poincare/tree_pool.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/poincare/include/poincare/tree_pool.h b/poincare/include/poincare/tree_pool.h index a124964e3..36bce5366 100644 --- a/poincare/include/poincare/tree_pool.h +++ b/poincare/include/poincare/tree_pool.h @@ -27,7 +27,8 @@ public: // Node TreeNode * node(int identifier) const { - assert(identifier >= 0 && identifier <= MaxNumberOfNodes); + assert(identifier >= 0 && identifier < MaxNumberOfNodes); + assert(m_nodeForIdentifier[identifier] != nullptr); return m_nodeForIdentifier[identifier]; } From 23dafffcdca98241b31749b40b7d8f0ee0d5ec3a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Tue, 26 Nov 2019 11:51:58 +0100 Subject: [PATCH 091/680] [poincare/tree_pool] TODO comment about not needed cleaning --- poincare/src/tree_pool.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/poincare/src/tree_pool.cpp b/poincare/src/tree_pool.cpp index 66b385fa4..6fff87edf 100644 --- a/poincare/src/tree_pool.cpp +++ b/poincare/src/tree_pool.cpp @@ -15,7 +15,7 @@ TreePool * TreePool::SharedStaticPool = nullptr; void TreePool::freeIdentifier(int identifier) { if (identifier >= 0 && identifier < MaxNumberOfNodes) { - m_nodeForIdentifier[identifier] = nullptr; + m_nodeForIdentifier[identifier] = nullptr; // TODO: We do not really need to do this, but it cleaner... m_identifiers.push(identifier); } } From 6a62f2300093c82cae34d326c791706ff0c0ae9a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Tue, 26 Nov 2019 16:19:49 +0100 Subject: [PATCH 092/680] [poincare/tree_pool] Replace test with assertion --- poincare/src/tree_pool.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/poincare/src/tree_pool.cpp b/poincare/src/tree_pool.cpp index 6fff87edf..476c102ab 100644 --- a/poincare/src/tree_pool.cpp +++ b/poincare/src/tree_pool.cpp @@ -149,7 +149,8 @@ void TreePool::discardTreeNode(TreeNode * node) { void TreePool::registerNode(TreeNode * node) { int nodeID = node->identifier(); - if (nodeID >= 0 && nodeID < MaxNumberOfNodes) { + if (nodeID >= 0) { + assert(nodeID < MaxNumberOfNodes); m_nodeForIdentifier[nodeID] = node; } } From 0a1c6a3d1debcfe34d11ac1765316785f1f61236 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Tue, 26 Nov 2019 16:33:26 +0100 Subject: [PATCH 093/680] [poincare/tree_pool] Store node offsets, not node pointers This saves place because we store uint16_t, not uint32_t --- liba/include/stdint.h | 2 ++ poincare/include/poincare/tree_pool.h | 9 ++++++--- poincare/src/tree_pool.cpp | 14 ++++++++++---- 3 files changed, 18 insertions(+), 7 deletions(-) diff --git a/liba/include/stdint.h b/liba/include/stdint.h index ef904e710..1b6397153 100644 --- a/liba/include/stdint.h +++ b/liba/include/stdint.h @@ -26,6 +26,8 @@ typedef int64_t int_fast64_t; typedef uint8_t uint_least8_t; +#define UINT16_MAX 0xffff + #define INT16_MAX 0x7fff #define INT16_MIN (-INT16_MAX-1) diff --git a/poincare/include/poincare/tree_pool.h b/poincare/include/poincare/tree_pool.h index 36bce5366..60cd9a70d 100644 --- a/poincare/include/poincare/tree_pool.h +++ b/poincare/include/poincare/tree_pool.h @@ -28,8 +28,7 @@ public: // Node TreeNode * node(int identifier) const { assert(identifier >= 0 && identifier < MaxNumberOfNodes); - assert(m_nodeForIdentifier[identifier] != nullptr); - return m_nodeForIdentifier[identifier]; + return const_cast(reinterpret_cast(m_alignedBuffer + m_nodeForIdentifierOffset[identifier])); } // Pool memory @@ -52,6 +51,8 @@ public: private: constexpr static int BufferSize = 32768; constexpr static int MaxNumberOfNodes = BufferSize/sizeof(TreeNode); + constexpr static int k_maxNodeOffset = BufferSize/ByteAlignment; + static TreePool * SharedStaticPool; // TreeNode @@ -144,7 +145,9 @@ private: AlignedNodeBuffer m_alignedBuffer[BufferSize/ByteAlignment]; char * m_cursor; IdentifierStack m_identifiers; - TreeNode * m_nodeForIdentifier[MaxNumberOfNodes]; + uint16_t m_nodeForIdentifierOffset[MaxNumberOfNodes]; + static_assert(k_maxNodeOffset < UINT16_MAX && sizeof(m_nodeForIdentifierOffset[0]) == sizeof(uint16_t), + "The tree pool node offsets in m_nodeForIdentifierOffset cannot be written with the chosen data size (uint16_t)"); }; } diff --git a/poincare/src/tree_pool.cpp b/poincare/src/tree_pool.cpp index 476c102ab..360588443 100644 --- a/poincare/src/tree_pool.cpp +++ b/poincare/src/tree_pool.cpp @@ -15,7 +15,11 @@ TreePool * TreePool::SharedStaticPool = nullptr; void TreePool::freeIdentifier(int identifier) { if (identifier >= 0 && identifier < MaxNumberOfNodes) { - m_nodeForIdentifier[identifier] = nullptr; // TODO: We do not really need to do this, but it cleaner... + /* We could clean m_nodeForIdentifierOffset[identifier] to a default offset + * (for instance BufferSize) to be able to return nullptr when we access an + * inexisting cleaned node. However, transforming a default offset to a + * nullptr tree node adds one check per "get node", which is quite + * unefficient. We thus do nothing. */ m_identifiers.push(identifier); } } @@ -135,7 +139,7 @@ void TreePool::dealloc(TreeNode * node, size_t size) { ); m_cursor -= size; - // Step 2: Update m_nodeForIdentifier for all nodes downstream + // Step 2: Update m_nodeForIdentifierOffset for all nodes downstream updateNodeForIdentifierFromNode(node); } @@ -151,13 +155,15 @@ void TreePool::registerNode(TreeNode * node) { int nodeID = node->identifier(); if (nodeID >= 0) { assert(nodeID < MaxNumberOfNodes); - m_nodeForIdentifier[nodeID] = node; + assert((((char *)node) - ((char *)m_alignedBuffer)) / ByteAlignment < k_maxNodeOffset); // Check that the offset can be stored in a uint16_t + m_nodeForIdentifierOffset[nodeID] = (((char *)node) - (char *)m_alignedBuffer)/ByteAlignment; } } void TreePool::updateNodeForIdentifierFromNode(TreeNode * node) { for (TreeNode * n : Nodes(node)) { - m_nodeForIdentifier[n->identifier()] = n; + assert((((char *)node) - ((char *)m_alignedBuffer))/ByteAlignment < k_maxNodeOffset); // Check that the offset can be stored in a uint16_t + m_nodeForIdentifierOffset[n->identifier()] = (((char *)n) - (char *)m_alignedBuffer)/ByteAlignment; } } From ed211f185aa399ed271aa001c4d70642b6c59a57 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Wed, 27 Nov 2019 09:46:02 +0100 Subject: [PATCH 094/680] [poincare/tree_pool] Use uint16_t for node identifiers, not int --- poincare/include/poincare/tree_handle.h | 14 +++++++------- poincare/include/poincare/tree_node.h | 14 +++++++------- poincare/include/poincare/tree_pool.h | 19 ++++++++++--------- poincare/src/tree_handle.cpp | 4 ++-- poincare/src/tree_node.cpp | 4 ++-- poincare/src/tree_pool.cpp | 4 ++-- 6 files changed, 30 insertions(+), 29 deletions(-) diff --git a/poincare/include/poincare/tree_handle.h b/poincare/include/poincare/tree_handle.h index 8166635b4..341cc9818 100644 --- a/poincare/include/poincare/tree_handle.h +++ b/poincare/include/poincare/tree_handle.h @@ -62,7 +62,7 @@ public: /* Clone */ TreeHandle clone() const; - int identifier() const { return m_identifier; } + uint16_t identifier() const { return m_identifier; } TreeNode * node() const; int nodeRetainCount() const { return node()->retainCount(); } size_t size() const; @@ -79,7 +79,7 @@ public: int indexOfChild(TreeHandle t) const; TreeHandle parent() const; TreeHandle childAtIndex(int i) const; - void setParentIdentifier(int id) { node()->setParentIdentifier(id); } + void setParentIdentifier(uint16_t id) { node()->setParentIdentifier(id); } void deleteParentIdentifier() { node()->deleteParentIdentifier(); } void deleteParentIdentifierInChildren() { node()->deleteParentIdentifierInChildren(); } void incrementNumberOfChildren(int increment = 1) { node()->incrementNumberOfChildren(increment); } @@ -110,7 +110,7 @@ protected: /* Constructor */ TreeHandle(const TreeNode * node); // Un-inlining this constructor actually inscreases the firmware size - TreeHandle(int nodeIndentifier = TreeNode::NoNodeIdentifier) : m_identifier(nodeIndentifier) { + TreeHandle(uint16_t nodeIndentifier = TreeNode::NoNodeIdentifier) : m_identifier(nodeIndentifier) { if (hasNode(nodeIndentifier)) { node()->retain(); } @@ -124,10 +124,10 @@ protected: static TreeHandle BuildWithGhostChildren(TreeNode * node); - void setIdentifierAndRetain(int newId); + void setIdentifierAndRetain(uint16_t newId); void setTo(const TreeHandle & tr); - static bool hasNode(int identifier) { return identifier > TreeNode::NoNodeIdentifier; } + static bool hasNode(uint16_t identifier) { return identifier > TreeNode::NoNodeIdentifier; } /* Hierarchy operations */ // Add @@ -137,7 +137,7 @@ protected: void removeChildInPlace(TreeHandle t, int childNumberOfChildren); void removeChildrenInPlace(int currentNumberOfChildren); - int m_identifier; + uint16_t m_identifier; private: template @@ -146,7 +146,7 @@ private: void detachFromParent(); // Add ghost children on layout construction void buildGhostChildren(); - void release(int identifier); + void release(uint16_t identifier); }; } diff --git a/poincare/include/poincare/tree_node.h b/poincare/include/poincare/tree_node.h index 045252f3f..74714770b 100644 --- a/poincare/include/poincare/tree_node.h +++ b/poincare/include/poincare/tree_node.h @@ -39,16 +39,16 @@ constexpr static int ByteAlignment = sizeof(AlignedNodeBuffer); class TreeNode { friend class TreePool; public: - static constexpr int NoNodeIdentifier = -1; + static constexpr uint16_t NoNodeIdentifier = -1; // Constructor and destructor virtual ~TreeNode() {} // Attributes - void setParentIdentifier(int parentID) { m_parentIdentifier = parentID; } + void setParentIdentifier(uint16_t parentID) { m_parentIdentifier = parentID; } void deleteParentIdentifier() { m_parentIdentifier = NoNodeIdentifier; } virtual size_t size() const = 0; - int identifier() const { return m_identifier; } + uint16_t identifier() const { return m_identifier; } int retainCount() const { return m_referenceCounter; } size_t deepSize(int realNumberOfChildren) const; @@ -59,7 +59,7 @@ public: void setReferenceCounter(int refCount) { m_referenceCounter = refCount; } void retain() { m_referenceCounter++; } void release(int currentNumberOfChildren); - void rename(int identifier, bool unregisterPreviousIdentifier); + void rename(uint16_t identifier, bool unregisterPreviousIdentifier); // Hierarchy virtual TreeNode * parent() const; @@ -182,9 +182,9 @@ private: void updateParentIdentifierInChildren() const { changeParentIdentifierInChildren(m_identifier); } - void changeParentIdentifierInChildren(int id) const; - int16_t m_identifier; - int16_t m_parentIdentifier; + void changeParentIdentifierInChildren(uint16_t id) const; + uint16_t m_identifier; + uint16_t m_parentIdentifier; int8_t m_referenceCounter; }; diff --git a/poincare/include/poincare/tree_pool.h b/poincare/include/poincare/tree_pool.h index 60cd9a70d..a2a8bbaa8 100644 --- a/poincare/include/poincare/tree_pool.h +++ b/poincare/include/poincare/tree_pool.h @@ -26,7 +26,7 @@ public: TreePool() : m_cursor(buffer()) {} // Node - TreeNode * node(int identifier) const { + TreeNode * node(uint16_t identifier) const { assert(identifier >= 0 && identifier < MaxNumberOfNodes); return const_cast(reinterpret_cast(m_alignedBuffer + m_nodeForIdentifierOffset[identifier])); } @@ -111,31 +111,32 @@ private: void moveNodes(TreeNode * destination, TreeNode * source, size_t moveLength); // Identifiers - int generateIdentifier() { return m_identifiers.pop(); } - void freeIdentifier(int identifier); + uint16_t generateIdentifier() { return m_identifiers.pop(); } + void freeIdentifier(uint16_t identifier); class IdentifierStack final { public: IdentifierStack() : m_currentIndex(0) { - for (int i = 0; i < MaxNumberOfNodes; i++) { + for (uint16_t i = 0; i < MaxNumberOfNodes; i++) { push(i); } } - void push(int i) { + void push(uint16_t i) { assert(m_currentIndex >= 0 && m_currentIndex < MaxNumberOfNodes); m_availableIdentifiers[m_currentIndex++] = i; } - int pop() { + uint16_t pop() { if (m_currentIndex == 0) { assert(false); - return -1; + return 0; } assert(m_currentIndex > 0 && m_currentIndex <= MaxNumberOfNodes); return m_availableIdentifiers[--m_currentIndex]; } private: - int m_currentIndex; - int m_availableIdentifiers[MaxNumberOfNodes]; + uint16_t m_currentIndex; + uint16_t m_availableIdentifiers[MaxNumberOfNodes]; + static_assert(MaxNumberOfNodes < INT16_MAX && sizeof(m_availableIdentifiers[0] == sizeof(uint16_t)), "Tree node identifiers do not have the right data size."); }; void freePoolFromNode(TreeNode * firstNodeToDiscard); diff --git a/poincare/src/tree_handle.cpp b/poincare/src/tree_handle.cpp index 0b4f93780..75b371691 100644 --- a/poincare/src/tree_handle.cpp +++ b/poincare/src/tree_handle.cpp @@ -228,7 +228,7 @@ TreeHandle TreeHandle::BuildWithGhostChildren(TreeNode * node) { return TreeHandle(node); } -void TreeHandle::setIdentifierAndRetain(int newId) { +void TreeHandle::setIdentifierAndRetain(uint16_t newId) { m_identifier = newId; if (!isUninitialized()) { node()->retain(); @@ -246,7 +246,7 @@ void TreeHandle::setTo(const TreeHandle & tr) { release(currentId); } -void TreeHandle::release(int identifier) { +void TreeHandle::release(uint16_t identifier) { if (!hasNode(identifier)) { return; } diff --git a/poincare/src/tree_node.cpp b/poincare/src/tree_node.cpp index 3036690b6..fa75b9503 100644 --- a/poincare/src/tree_node.cpp +++ b/poincare/src/tree_node.cpp @@ -15,7 +15,7 @@ void TreeNode::release(int currentNumberOfChildren) { } } -void TreeNode::rename(int identifier, bool unregisterPreviousIdentifier) { +void TreeNode::rename(uint16_t identifier, bool unregisterPreviousIdentifier) { if (unregisterPreviousIdentifier) { /* The previous identifier should not always be unregistered. For instance, * if the node is a clone and still has the original node's identifier, @@ -183,7 +183,7 @@ size_t TreeNode::deepSize(int realNumberOfChildren) const { reinterpret_cast(this); } -void TreeNode::changeParentIdentifierInChildren(int id) const { +void TreeNode::changeParentIdentifierInChildren(uint16_t id) const { for (TreeNode * c : directChildren()) { c->setParentIdentifier(id); } diff --git a/poincare/src/tree_pool.cpp b/poincare/src/tree_pool.cpp index 360588443..9bc42772d 100644 --- a/poincare/src/tree_pool.cpp +++ b/poincare/src/tree_pool.cpp @@ -13,7 +13,7 @@ namespace Poincare { TreePool * TreePool::SharedStaticPool = nullptr; -void TreePool::freeIdentifier(int identifier) { +void TreePool::freeIdentifier(uint16_t identifier) { if (identifier >= 0 && identifier < MaxNumberOfNodes) { /* We could clean m_nodeForIdentifierOffset[identifier] to a default offset * (for instance BufferSize) to be able to return nullptr when we access an @@ -144,7 +144,7 @@ void TreePool::dealloc(TreeNode * node, size_t size) { } void TreePool::discardTreeNode(TreeNode * node) { - int nodeIdentifier = node->identifier(); + uint16_t nodeIdentifier = node->identifier(); size_t size = node->size(); node->~TreeNode(); dealloc(node, size); From a2a0abdcef0b3d2656606e2579f8c2f0f9ca47bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Mon, 2 Dec 2019 14:21:01 +0100 Subject: [PATCH 095/680] [poincare/TreeNode] Fix hasNode --- poincare/include/poincare/integer.h | 5 ++--- poincare/include/poincare/tree_handle.h | 2 +- poincare/include/poincare/tree_node.h | 3 ++- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/poincare/include/poincare/integer.h b/poincare/include/poincare/integer.h index a9a07e19b..294a5ed78 100644 --- a/poincare/include/poincare/integer.h +++ b/poincare/include/poincare/integer.h @@ -58,7 +58,7 @@ public: Integer(double_native_int_t i); Integer(const char * digits, size_t length, bool negative); Integer(const char * digits) : Integer(digits, strlen(digits), false) {} - static Integer Overflow(bool negative) { return Integer(OverflowIdentifier, negative); } + static Integer Overflow(bool negative) { return Integer(TreeNode::OverflowIdentifier, negative); } #if POINCARE_TREE_LOG void logInteger(std::ostream & stream) const { @@ -108,7 +108,7 @@ public: /* An integer can have (k_maxNumberOfDigits + 1) digits: either when it is an * overflow, or when we want to have one more digit than usual to compute a * big division. */ - bool isOverflow() const { return m_identifier == OverflowIdentifier; } + bool isOverflow() const { return m_identifier == TreeNode::OverflowIdentifier; } static int NumberOfBase10DigitsWithoutSign(const Integer & i); bool isOne() const { return (numberOfDigits() == 1 && digit(0) == 1 && !m_negative); }; bool isTwo() const { return (numberOfDigits() == 1 && digit(0) == 2 && !m_negative); }; @@ -140,7 +140,6 @@ public: constexpr static int k_maxNumberOfDigits = 32; private: constexpr static int k_maxNumberOfDigitsBase10 = 308; // (2^32)^k_maxNumberOfDigits ~ 1E308 - static constexpr int OverflowIdentifier = TreeNode::NoNodeIdentifier - 1; // Constructors Integer(native_uint_t * digits, uint16_t numberOfDigits, bool negative); diff --git a/poincare/include/poincare/tree_handle.h b/poincare/include/poincare/tree_handle.h index 341cc9818..44690899c 100644 --- a/poincare/include/poincare/tree_handle.h +++ b/poincare/include/poincare/tree_handle.h @@ -127,7 +127,7 @@ protected: void setIdentifierAndRetain(uint16_t newId); void setTo(const TreeHandle & tr); - static bool hasNode(uint16_t identifier) { return identifier > TreeNode::NoNodeIdentifier; } + static bool hasNode(uint16_t identifier) { return identifier < TreeNode::NoNodeIdentifier; } /* Hierarchy operations */ // Add diff --git a/poincare/include/poincare/tree_node.h b/poincare/include/poincare/tree_node.h index 74714770b..f46d6ff9a 100644 --- a/poincare/include/poincare/tree_node.h +++ b/poincare/include/poincare/tree_node.h @@ -39,7 +39,8 @@ constexpr static int ByteAlignment = sizeof(AlignedNodeBuffer); class TreeNode { friend class TreePool; public: - static constexpr uint16_t NoNodeIdentifier = -1; + static constexpr uint16_t NoNodeIdentifier = -2; + static constexpr uint16_t OverflowIdentifier = TreeNode::NoNodeIdentifier + 1; // Used for Integer // Constructor and destructor virtual ~TreeNode() {} From 5853e96947cfe937f3f15f831dca24a95892ac14 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Tue, 3 Dec 2019 14:36:52 +0100 Subject: [PATCH 096/680] [apps/code] Remove EditorController::m_areaBuffer This was a very large buffer that took a lot of RAM space (the size of the storage). Instead of having it, we just move the available space of the storage at the end of the edited script, and move it back when the edition finishes. This is slower but saves a lot of space. --- apps/code/editor_controller.cpp | 40 ++++++++++++++++----------------- apps/code/editor_controller.h | 5 ----- apps/code/script.cpp | 2 +- apps/code/script.h | 2 +- apps/code/script_store.cpp | 4 ++-- ion/include/ion/storage.h | 4 ++++ ion/src/shared/storage.cpp | 23 +++++++++++++++++++ 7 files changed, 51 insertions(+), 29 deletions(-) diff --git a/apps/code/editor_controller.cpp b/apps/code/editor_controller.cpp index aba355959..a5c7e9a1b 100644 --- a/apps/code/editor_controller.cpp +++ b/apps/code/editor_controller.cpp @@ -20,18 +20,31 @@ EditorController::EditorController(MenuController * menuController, App * python void EditorController::setScript(Script script) { m_script = script; - Script::Data scriptData = m_script.value(); - size_t availableScriptSize = scriptData.size + Ion::Storage::sharedStorage()->availableSize(); - assert(sizeof(m_areaBuffer) >= availableScriptSize); - // We cannot use strlcpy as the first char reprensenting the importation status can be 0. - memcpy(m_areaBuffer, (const char *)scriptData.buffer, scriptData.size); - m_editorView.setText(m_areaBuffer+1, availableScriptSize-1); // 1 char is taken by the importation status flag + + /* We edit the script direclty in the storage buffer. We thus put all the + * storage available space at the end of the current edited script and we set + * its size. + * + * |****|****|m_script|****|**********|¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨| + * available space + * is transformed to: + * + * |****|****|m_script|¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨|****|**********| + * available space + * + * */ + + size_t newScriptSize = Ion::Storage::sharedStorage()->putAvailableSpaceAtEndOfRecord(m_script); + m_editorView.setText(const_cast(m_script.scriptContent()), newScriptSize - Script::k_importationStatusSize); } // TODO: this should be done in textAreaDidFinishEditing maybe?? bool EditorController::handleEvent(Ion::Events::Event event) { if (event == Ion::Events::OK || event == Ion::Events::Back || event == Ion::Events::Home) { - saveScript(); + Ion::Storage::Record::Data scriptValue = m_script.value(); + Ion::Storage::sharedStorage()->getAvailableSpaceFromEndOfRecord( + m_script, + scriptValue.size - Script::k_importationStatusSize - (strlen(m_script.scriptContent()) + 1)); // TODO optimize number of script fetches stackController()->pop(); return event != Ion::Events::Home; } @@ -52,12 +65,6 @@ void EditorController::viewDidDisappear() { } bool EditorController::textAreaDidReceiveEvent(TextArea * textArea, Ion::Events::Event event) { - if (event == Ion::Events::Var) { - /* We save the script before displaying the Variable box to add new - * functions or variables. */ - saveScript(); - return false; - } if (App::app()->textInputDidReceiveEvent(textArea, event)) { return true; } @@ -118,11 +125,4 @@ StackViewController * EditorController::stackController() { return static_cast(parentResponder()); } -void EditorController::saveScript() { - size_t sizeOfValue = strlen(m_areaBuffer+1)+1+1; // size of scriptContent + size of importation status - Script::ErrorStatus err = m_script.setValue({.buffer=m_areaBuffer, .size=sizeOfValue}); - assert(err != Script::ErrorStatus::NotEnoughSpaceAvailable && err != Script::ErrorStatus::RecordDoesNotExist); // This should not happen as we set the text area according to the available space in the Kallax - (void) err; -} - } diff --git a/apps/code/editor_controller.h b/apps/code/editor_controller.h index 284bf1af3..3b8d87980 100644 --- a/apps/code/editor_controller.h +++ b/apps/code/editor_controller.h @@ -34,12 +34,7 @@ public: private: StackViewController * stackController(); - void saveScript(); EditorView m_editorView; - /* m_areaBuffer first character is dedicated to the importation status. - * Thereby, we avoid wasteful copy while adding the Script to the storage - * (in order to add the importation status char before the areaBuffer). */ - char m_areaBuffer[Ion::Storage::k_storageSize]; // this could be slightly optimize Script m_script; MenuController * m_menuController; }; diff --git a/apps/code/script.cpp b/apps/code/script.cpp index 12a88c976..5ebb87c96 100644 --- a/apps/code/script.cpp +++ b/apps/code/script.cpp @@ -77,7 +77,7 @@ void Script::toggleImportationStatus() { setValue(d); } -const char * Script::readContent() const { +const char * Script::scriptContent() const { assert(!isNull()); Data d = value(); return (const char *)d.buffer + k_importationStatusSize; diff --git a/apps/code/script.h b/apps/code/script.h index 4ab639c13..fc10352f3 100644 --- a/apps/code/script.h +++ b/apps/code/script.h @@ -26,7 +26,7 @@ public: Script(Ion::Storage::Record r) : Record(r) {} bool importationStatus() const; void toggleImportationStatus(); - const char * readContent() const; + const char * scriptContent() const; }; } diff --git a/apps/code/script_store.cpp b/apps/code/script_store.cpp index 9ef37ce03..705ba3506 100644 --- a/apps/code/script_store.cpp +++ b/apps/code/script_store.cpp @@ -38,7 +38,7 @@ void ScriptStore::scanScriptsForFunctionsAndVariables(void * context, ScanCallba // Handle lexer or parser errors with nlr. nlr_buf_t nlr; if (nlr_push(&nlr) == 0) { - const char * scriptContent = scriptAtIndex(scriptIndex).readContent(); + const char * scriptContent = scriptAtIndex(scriptIndex).scriptContent(); if (scriptContent == nullptr) { continue; } @@ -120,7 +120,7 @@ const char * ScriptStore::contentOfScript(const char * name) { if (script.isNull()) { return nullptr; } - return script.readContent(); + return script.scriptContent(); } Script::ErrorStatus ScriptStore::addScriptFromTemplate(const ScriptTemplate * scriptTemplate) { diff --git a/ion/include/ion/storage.h b/ion/include/ion/storage.h index 41c7001de..4e9157d4e 100644 --- a/ion/include/ion/storage.h +++ b/ion/include/ion/storage.h @@ -17,6 +17,8 @@ class Storage { public: typedef uint16_t record_size_t; constexpr static size_t k_storageSize = 16384; + static_assert(UINT16_MAX >= k_storageSize, "record_size_t not big enough"); + static Storage * sharedStorage(); constexpr static char k_dotChar = '.'; @@ -90,6 +92,8 @@ public: #endif size_t availableSize(); + size_t putAvailableSpaceAtEndOfRecord(Record r); + void getAvailableSpaceFromEndOfRecord(Record r, size_t recordAvailableSpace); uint32_t checksum(); // Delegate diff --git a/ion/src/shared/storage.cpp b/ion/src/shared/storage.cpp index cf0b19826..fbca7c5d8 100644 --- a/ion/src/shared/storage.cpp +++ b/ion/src/shared/storage.cpp @@ -117,6 +117,29 @@ size_t Storage::availableSize() { return k_storageSize-(endBuffer()-m_buffer)-sizeof(record_size_t); } +size_t Storage::putAvailableSpaceAtEndOfRecord(Storage::Record r) { + char * p = pointerOfRecord(r); + size_t previousRecordSize = sizeOfRecordStarting(p); + size_t availableStorageSize = availableSize(); + char * nextRecord = p + previousRecordSize; + memmove(nextRecord + availableStorageSize, + nextRecord, + (m_buffer + k_storageSize - availableStorageSize) - nextRecord); + size_t newRecordSize = previousRecordSize + availableStorageSize; + overrideSizeAtPosition(p, (record_size_t)newRecordSize); + return newRecordSize; +} + +void Storage::getAvailableSpaceFromEndOfRecord(Record r, size_t recordAvailableSpace) { + char * p = pointerOfRecord(r); + size_t previousRecordSize = sizeOfRecordStarting(p); + char * nextRecord = p + previousRecordSize; + memmove(nextRecord - recordAvailableSpace, + nextRecord, + m_buffer + k_storageSize - nextRecord); + overrideSizeAtPosition(p, (record_size_t)(previousRecordSize - recordAvailableSpace)); +} + uint32_t Storage::checksum() { return Ion::crc32Byte((const uint8_t *) m_buffer, endBuffer()-m_buffer); } From 7e801906b8ba13f34219dea2a3f8b95940a12ed8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Tue, 3 Dec 2019 15:26:45 +0100 Subject: [PATCH 097/680] [test/ion] Add Storage available space moving test --- ion/test/storage.cpp | 359 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 359 insertions(+) diff --git a/ion/test/storage.cpp b/ion/test/storage.cpp index faef89702..65f5b4d9f 100644 --- a/ion/test/storage.cpp +++ b/ion/test/storage.cpp @@ -141,3 +141,362 @@ QUIZ_CASE(ion_storage_valid_renaming) { quiz_assert(newRetreivedRecord == Storage::Record()); quiz_assert(Storage::sharedStorage()->availableSize() == initialStorageAvailableStage); } + +QUIZ_CASE(ion_storage_available_space_moving) { + const char * extensionRecord = "record1"; + const char * baseNameRecord1 = "ionTestStorage1"; + const char * dataRecord1 = "This is a test to ensure one can edit a record in the shared storage - first record."; + const char * baseNameRecord2 = "ionTestStorage2"; + const char * dataRecord2 = "This is a test to ensure one can edit a record in the shared storage - second record."; + const char * baseNameRecord3 = "ionTestStorage3"; + const char * baseNameRecord4 = "ionTestStorage4"; + const char * dataRecord3 = R"( +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + +aaaaaaaaaaaaaaaaaaaaa + +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + +aaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaa + +aaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaa +aaaaaaa +aaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaa +aaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + +aaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaa +aaaaaaaaaaaa +aaaaaaaaaaaa +aaaaaaaaa +aaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaa +aaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaa + +aaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaa + +aaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + +aaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaa +aaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaa +aaaa +aaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + +aaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaa +aaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaa +aaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaa +aaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaa + +aaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaa +aaaa +aaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaa +aaaa +aaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaa +aaaa +aaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + +aaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + +aaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + +aaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaa +aaaaaaaaa +aaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaa +aaaaaaaaa +aaaaaaaaaaaaaaaa +aaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaa +aaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaa + + + + +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaa + +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaa +aaaaaa)"; + + // Put the records in the store + Storage::Record::ErrorStatus error = putRecordInSharedStorage(baseNameRecord1, extensionRecord, dataRecord1); + quiz_assert(error == Storage::Record::ErrorStatus::None); + error = putRecordInSharedStorage(baseNameRecord2, extensionRecord, dataRecord2); + quiz_assert(error == Storage::Record::ErrorStatus::None); + error = putRecordInSharedStorage(baseNameRecord3, extensionRecord, dataRecord3); + quiz_assert(error == Storage::Record::ErrorStatus::None); + error = putRecordInSharedStorage(baseNameRecord4, extensionRecord, dataRecord3); + quiz_assert(error == Storage::Record::ErrorStatus::None); + + // Retreive the record + Storage::Record retreivedRecord1 = Storage::sharedStorage()->recordBaseNamedWithExtension(baseNameRecord1, extensionRecord); + Storage::Record retreivedRecord2 = Storage::sharedStorage()->recordBaseNamedWithExtension(baseNameRecord2, extensionRecord); + Storage::Record retreivedRecord3 = Storage::sharedStorage()->recordBaseNamedWithExtension(baseNameRecord3, extensionRecord); + Storage::Record retreivedRecord4 = Storage::sharedStorage()->recordBaseNamedWithExtension(baseNameRecord4, extensionRecord); + + // Put the the available space at the end of the first record and remove it + size_t availableSpace = Storage::sharedStorage()->availableSize(); + uint32_t checksumBeforeChanges = Storage::sharedStorage()->checksum(); + Storage::sharedStorage()->putAvailableSpaceAtEndOfRecord(retreivedRecord1); + Storage::sharedStorage()->getAvailableSpaceFromEndOfRecord(retreivedRecord1, availableSpace); + quiz_assert(Storage::sharedStorage()->availableSize() == availableSpace); + quiz_assert(Storage::sharedStorage()->checksum() == checksumBeforeChanges); + + // Destroy it + retreivedRecord1.destroy(); + retreivedRecord2.destroy(); + retreivedRecord3.destroy(); + retreivedRecord4.destroy(); +} From c1b792c23d5ed5854ec7bb576ecadfd2701e25ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Tue, 3 Dec 2019 17:16:46 +0100 Subject: [PATCH 098/680] [apps/code] Get out of script edition on usb enumeration The storage needs to be in a clean state --- apps/code/editor_controller.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/apps/code/editor_controller.cpp b/apps/code/editor_controller.cpp index a5c7e9a1b..c1646ce2e 100644 --- a/apps/code/editor_controller.cpp +++ b/apps/code/editor_controller.cpp @@ -40,13 +40,15 @@ void EditorController::setScript(Script script) { // TODO: this should be done in textAreaDidFinishEditing maybe?? bool EditorController::handleEvent(Ion::Events::Event event) { - if (event == Ion::Events::OK || event == Ion::Events::Back || event == Ion::Events::Home) { + if (event == Ion::Events::OK || event == Ion::Events::Back || event == Ion::Events::Home || event == Ion::Events::USBEnumeration) { + /* Exit the edition on USB enumeration, because the storage needs to be in a + * "clean" state (with all records packed at the beginning of the storage) */ Ion::Storage::Record::Data scriptValue = m_script.value(); Ion::Storage::sharedStorage()->getAvailableSpaceFromEndOfRecord( m_script, scriptValue.size - Script::k_importationStatusSize - (strlen(m_script.scriptContent()) + 1)); // TODO optimize number of script fetches stackController()->pop(); - return event != Ion::Events::Home; + return event != Ion::Events::Home && event != Ion::Events::USBEnumeration; } return false; } From 4ffcace0244b0053389a5fe7eca468f92edebba3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Tue, 3 Dec 2019 17:31:36 +0100 Subject: [PATCH 099/680] [ion/storage] Add TODO about code optimization --- ion/src/shared/storage.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ion/src/shared/storage.cpp b/ion/src/shared/storage.cpp index fbca7c5d8..8ce6a5ce7 100644 --- a/ion/src/shared/storage.cpp +++ b/ion/src/shared/storage.cpp @@ -114,6 +114,8 @@ void Storage::log() { #endif size_t Storage::availableSize() { + /* TODO maybe do: availableSize(char ** endBuffer) to get the endBuffer if it + * is needed after calling availableSize */ return k_storageSize-(endBuffer()-m_buffer)-sizeof(record_size_t); } From 0209c6d2d45f8764777a05bcb874de01a4c5d53d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Mon, 2 Dec 2019 14:37:45 +0100 Subject: [PATCH 100/680] [ion/storage] Increase size to 32K --- ion/include/ion/storage.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ion/include/ion/storage.h b/ion/include/ion/storage.h index 4e9157d4e..097006362 100644 --- a/ion/include/ion/storage.h +++ b/ion/include/ion/storage.h @@ -16,7 +16,8 @@ class StorageDelegate; class Storage { public: typedef uint16_t record_size_t; - constexpr static size_t k_storageSize = 16384; + + constexpr static size_t k_storageSize = 32768; static_assert(UINT16_MAX >= k_storageSize, "record_size_t not big enough"); static Storage * sharedStorage(); From e984277d662a500d41507a56d093d2ddf11ffb17 Mon Sep 17 00:00:00 2001 From: Ruben Dashyan Date: Mon, 16 Dec 2019 11:30:36 +0100 Subject: [PATCH 101/680] [poincare/multiplication] shallowBeautify and denominator call new splitIntoNormalForm --- poincare/include/poincare/multiplication.h | 4 +- poincare/src/multiplication.cpp | 147 ++++++++------------- 2 files changed, 59 insertions(+), 92 deletions(-) diff --git a/poincare/include/poincare/multiplication.h b/poincare/include/poincare/multiplication.h index 09d2e9d2c..6fe8ec2c4 100644 --- a/poincare/include/poincare/multiplication.h +++ b/poincare/include/poincare/multiplication.h @@ -102,10 +102,8 @@ private: static bool TermHasNumeralBase(const Expression & e); static bool TermHasNumeralExponent(const Expression & e); static const Expression CreateExponent(Expression e); - /* Warning: mergeNegativePower doesnot always return a multiplication: - * *(b^-1,c^-1) -> (bc)^-1 */ - Expression mergeNegativePower(ExpressionNode::ReductionContext reductionContext); static inline const Expression Base(const Expression e); + void splitIntoNormalForm(Expression & numerator, Expression & denominator, ExpressionNode::ReductionContext reductionContext) const; }; } diff --git a/poincare/src/multiplication.cpp b/poincare/src/multiplication.cpp index 62e500494..e6af9cd94 100644 --- a/poincare/src/multiplication.cpp +++ b/poincare/src/multiplication.cpp @@ -271,7 +271,6 @@ Expression Multiplication::shallowReduce(ExpressionNode::ReductionContext reduct Expression Multiplication::shallowBeautify(ExpressionNode::ReductionContext reductionContext) { /* Beautifying a Multiplication consists in several possible operations: * - Add Opposite ((-3)*x -> -(3*x), useful when printing fractions) - * - Adding parenthesis if needed (a*(b+c) is not a*b+c) * - Creating a Division if there's either a term with a power of -1 (a.b^(-1) * shall become a/b) or a non-integer rational term (3/2*a -> (3*a)/2). */ @@ -285,61 +284,27 @@ Expression Multiplication::shallowBeautify(ExpressionNode::ReductionContext redu return std::move(o); } - /* Step 2: Merge negative powers: a*b^(-1)*c^(-pi)*d = a*(b*c^pi)^(-1) - * This also turns 2/3*a into 2*a*3^(-1) */ - Expression thisExp = mergeNegativePower(reductionContext); - if (thisExp.type() == ExpressionNode::Type::Power) { - return thisExp.shallowBeautify(reductionContext); + Expression numer; + Expression denom; + splitIntoNormalForm(numer, denom, reductionContext); + Expression result; + + // Step 2: Create a Division if relevant + if (!numer.isUninitialized()) { + result = numer; } - assert(thisExp.type() == ExpressionNode::Type::Multiplication); - - // Step 3: Create a Division if needed - for (int i = 0; i < numberOfChildren(); i++) { - Expression childI = thisExp.childAtIndex(i); - if (!(childI.type() == ExpressionNode::Type::Power && childI.childAtIndex(1).type() == ExpressionNode::Type::Rational && childI.childAtIndex(1).convert().isMinusOne())) { - continue; - } - - // Let's remove the denominator-to-be from this - Expression denominatorOperand = childI.childAtIndex(0); - removeChildInPlace(childI, childI.numberOfChildren()); - - Expression numeratorOperand = shallowReduce(reductionContext); - // Delete unnecessary parentheses on numerator - if (numeratorOperand.type() == ExpressionNode::Type::Parenthesis) { - Expression numeratorChild0 = numeratorOperand.childAtIndex(0); - numeratorOperand.replaceWithInPlace(numeratorChild0); - numeratorOperand = numeratorChild0; - } - Division d = Division::Builder(); - numeratorOperand.replaceWithInPlace(d); - d.replaceChildAtIndexInPlace(0, numeratorOperand); - d.replaceChildAtIndexInPlace(1, denominatorOperand); - return d.shallowBeautify(reductionContext); + if (!denom.isUninitialized()) { + result = Division::Builder(result.isUninitialized() ? Rational::Builder(1) : result, denom); } - return thisExp; + replaceWithInPlace(result); + return result; } Expression Multiplication::denominator(ExpressionNode::ReductionContext reductionContext) const { - // Merge negative power: a*b^-1*c^(-Pi)*d = a*(b*c^Pi)^-1 - // WARNING: we do not want to change the expression but to create a new one. - Multiplication thisClone = clone().convert(); - Expression e = thisClone.mergeNegativePower(reductionContext); - if (e.type() == ExpressionNode::Type::Power) { - return e.denominator(reductionContext); - } else { - assert(e.type() == ExpressionNode::Type::Multiplication); - for (int i = 0; i < e.numberOfChildren(); i++) { - // a*b^(-1)*... -> a*.../b - if (e.childAtIndex(i).type() == ExpressionNode::Type::Power - && e.childAtIndex(i).childAtIndex(1).type() == ExpressionNode::Type::Rational - && e.childAtIndex(i).childAtIndex(1).convert().isMinusOne()) - { - return e.childAtIndex(i).childAtIndex(0); - } - } - } - return Expression(); + Expression numer; + Expression denom; + splitIntoNormalForm(numer, denom, reductionContext); + return denom; } Expression Multiplication::privateShallowReduce(ExpressionNode::ReductionContext reductionContext, bool shouldExpand, bool canBeInterrupted) { @@ -855,48 +820,52 @@ bool Multiplication::TermHasNumeralExponent(const Expression & e) { return false; } -Expression Multiplication::mergeNegativePower(ExpressionNode::ReductionContext reductionContext) { - /* mergeNegativePower groups all factors that are power of form a^(-b) together - * for instance, a^(-1)*b^(-c)*c = c*(a*b^c)^(-1) */ - Multiplication m = Multiplication::Builder(); - // Special case for rational p/q: if q != 1, q should be at denominator - if (childAtIndex(0).type() == ExpressionNode::Type::Rational && !childAtIndex(0).convert().isInteger()) { - Rational r = childAtIndex(0).convert(); - m.addChildAtIndexInPlace(Rational::Builder(r.integerDenominator()), 0, m.numberOfChildren()); - if (r.signedIntegerNumerator().isOne()) { - removeChildAtIndexInPlace(0); - } else { - replaceChildAtIndexInPlace(0, Rational::Builder(r.signedIntegerNumerator())); - } - } - int i = 0; - // Look for power of form a^(-b) - while (i < numberOfChildren()) { - if (childAtIndex(i).type() == ExpressionNode::Type::Power) { - Expression p = childAtIndex(i); - Expression positivePIndex = p.childAtIndex(1).makePositiveAnyNegativeNumeralFactor(reductionContext); - if (!positivePIndex.isUninitialized()) { - // Remove a^(-b) from the Multiplication - removeChildAtIndexInPlace(i); - // Add a^b to m - m.addChildAtIndexInPlace(p, m.numberOfChildren(), m.numberOfChildren()); - if (p.childAtIndex(1).isRationalOne()) { - p.replaceWithInPlace(p.childAtIndex(0)); - } - // We do not increment i because we removed one child from the Multiplication - continue; +void Multiplication::splitIntoNormalForm(Expression & numerator, Expression & denominator, ExpressionNode::ReductionContext reductionContext) const { + Multiplication mNumerator = Multiplication::Builder(); + Multiplication mDenominator = Multiplication::Builder(); + int numberOfFactorsInNumerator = 0; + int numberOfFactorsInDenominator = 0; + const int numberOfFactors = numberOfChildren(); + for (int i = 0; i < numberOfFactors; i++) { + Expression factor = childAtIndex(i).clone(); + ExpressionNode::Type factorType = factor.type(); + Expression factorsNumerator; + Expression factorsDenominator; + if (factorType == ExpressionNode::Type::Rational) { + Rational r = static_cast(factor); + Integer rNum = r.signedIntegerNumerator(); + if (!rNum.isOne()) { + factorsNumerator = Rational::Builder(rNum); } + Integer rDen = r.integerDenominator(); + if (!rDen.isOne()) { + factorsDenominator = Rational::Builder(rDen); + } + } else if (factorType == ExpressionNode::Type::Power) { + Expression fd = factor.denominator(reductionContext); + if (fd.isUninitialized()) { + factorsNumerator = factor; + } else { + factorsDenominator = fd; + } + } else { + factorsNumerator = factor; + } + if (!factorsNumerator.isUninitialized()) { + mNumerator.addChildAtIndexInPlace(factorsNumerator, numberOfFactorsInNumerator, numberOfFactorsInNumerator); + numberOfFactorsInNumerator++; + } + if (!factorsDenominator.isUninitialized()) { + mDenominator.addChildAtIndexInPlace(factorsDenominator, numberOfFactorsInDenominator, numberOfFactorsInDenominator); + numberOfFactorsInDenominator++; } - i++; } - if (m.numberOfChildren() == 0) { - return *this; + if (numberOfFactorsInNumerator) { + numerator = mNumerator.squashUnaryHierarchyInPlace(); + } + if (numberOfFactorsInDenominator) { + denominator = mDenominator.squashUnaryHierarchyInPlace(); } - m.sortChildrenInPlace([](const ExpressionNode * e1, const ExpressionNode * e2, bool canBeInterrupted) { return ExpressionNode::SimplificationOrder(e1, e2, true, canBeInterrupted); }, reductionContext.context(), true); - Power p = Power::Builder(m.squashUnaryHierarchyInPlace(), Rational::Builder(-1)); - addChildAtIndexInPlace(p, 0, numberOfChildren()); - sortChildrenInPlace([](const ExpressionNode * e1, const ExpressionNode * e2, bool canBeInterrupted) { return ExpressionNode::SimplificationOrder(e1, e2, true, canBeInterrupted); }, reductionContext.context(), true); - return squashUnaryHierarchyInPlace(); } const Expression Multiplication::Base(const Expression e) { From 431356087235ff336ebe435e6834b1b337a486de Mon Sep 17 00:00:00 2001 From: Ruben Dashyan Date: Thu, 19 Dec 2019 11:33:37 +0100 Subject: [PATCH 102/680] [poincare/tree_pool] Remove redundancy The first condition generally implies the second (if size > 0). If size == 0 then there is nothing to alloc. --- poincare/src/tree_pool.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/poincare/src/tree_pool.cpp b/poincare/src/tree_pool.cpp index 9bc42772d..4fcafa5a9 100644 --- a/poincare/src/tree_pool.cpp +++ b/poincare/src/tree_pool.cpp @@ -118,7 +118,7 @@ int TreePool::numberOfNodes() const { void * TreePool::alloc(size_t size) { size = Helpers::AlignedSize(size, ByteAlignment); - if (m_cursor >= buffer() + BufferSize || m_cursor + size > buffer() + BufferSize) { + if (m_cursor + size > buffer() + BufferSize) { ExceptionCheckpoint::Raise(); } void * result = m_cursor; From ff4879abb16d9e0bebd4aa029b6996f404ea33eb Mon Sep 17 00:00:00 2001 From: Ruben Dashyan Date: Thu, 19 Dec 2019 14:21:01 +0100 Subject: [PATCH 103/680] [poincare/tree_pool] Factor updateNodeForIdentifierFromNode Hence fixing typo in assertion --- poincare/src/tree_pool.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/poincare/src/tree_pool.cpp b/poincare/src/tree_pool.cpp index 4fcafa5a9..d06adb9f4 100644 --- a/poincare/src/tree_pool.cpp +++ b/poincare/src/tree_pool.cpp @@ -162,8 +162,7 @@ void TreePool::registerNode(TreeNode * node) { void TreePool::updateNodeForIdentifierFromNode(TreeNode * node) { for (TreeNode * n : Nodes(node)) { - assert((((char *)node) - ((char *)m_alignedBuffer))/ByteAlignment < k_maxNodeOffset); // Check that the offset can be stored in a uint16_t - m_nodeForIdentifierOffset[n->identifier()] = (((char *)n) - (char *)m_alignedBuffer)/ByteAlignment; + registerNode(n); } } From 78f1270752e234688212e8f1349e7ef64827b874 Mon Sep 17 00:00:00 2001 From: Ruben Dashyan Date: Thu, 19 Dec 2019 14:23:22 +0100 Subject: [PATCH 104/680] [poincare/tree_pool] Correct identifier type in registerNode --- poincare/src/tree_pool.cpp | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/poincare/src/tree_pool.cpp b/poincare/src/tree_pool.cpp index d06adb9f4..4935c1d96 100644 --- a/poincare/src/tree_pool.cpp +++ b/poincare/src/tree_pool.cpp @@ -152,12 +152,10 @@ void TreePool::discardTreeNode(TreeNode * node) { } void TreePool::registerNode(TreeNode * node) { - int nodeID = node->identifier(); - if (nodeID >= 0) { - assert(nodeID < MaxNumberOfNodes); - assert((((char *)node) - ((char *)m_alignedBuffer)) / ByteAlignment < k_maxNodeOffset); // Check that the offset can be stored in a uint16_t - m_nodeForIdentifierOffset[nodeID] = (((char *)node) - (char *)m_alignedBuffer)/ByteAlignment; - } + uint16_t nodeID = node->identifier(); + assert(nodeID < MaxNumberOfNodes); + assert((((char *)node) - ((char *)m_alignedBuffer)) / ByteAlignment < k_maxNodeOffset); // Check that the offset can be stored in a uint16_t + m_nodeForIdentifierOffset[nodeID] = (((char *)node) - (char *)m_alignedBuffer)/ByteAlignment; } void TreePool::updateNodeForIdentifierFromNode(TreeNode * node) { From ad938aed488bbf3dd3fb4069631900710f89c784 Mon Sep 17 00:00:00 2001 From: Ruben Dashyan Date: Thu, 19 Dec 2019 14:28:04 +0100 Subject: [PATCH 105/680] [poincare/tree_pool] Factor expression in registerNode --- poincare/src/tree_pool.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/poincare/src/tree_pool.cpp b/poincare/src/tree_pool.cpp index 4935c1d96..1b3cf9dae 100644 --- a/poincare/src/tree_pool.cpp +++ b/poincare/src/tree_pool.cpp @@ -154,8 +154,9 @@ void TreePool::discardTreeNode(TreeNode * node) { void TreePool::registerNode(TreeNode * node) { uint16_t nodeID = node->identifier(); assert(nodeID < MaxNumberOfNodes); - assert((((char *)node) - ((char *)m_alignedBuffer)) / ByteAlignment < k_maxNodeOffset); // Check that the offset can be stored in a uint16_t - m_nodeForIdentifierOffset[nodeID] = (((char *)node) - (char *)m_alignedBuffer)/ByteAlignment; + const int nodeOffset = (((char *)node) - (char *)m_alignedBuffer)/ByteAlignment; + assert(nodeOffset < k_maxNodeOffset); // Check that the offset can be stored in a uint16_t + m_nodeForIdentifierOffset[nodeID] = nodeOffset; } void TreePool::updateNodeForIdentifierFromNode(TreeNode * node) { From 51cc6a4d71441b7c8b38efc8216557426ae4a9cd Mon Sep 17 00:00:00 2001 From: Ruben Dashyan Date: Wed, 13 Nov 2019 11:24:24 +0100 Subject: [PATCH 106/680] [poincare/layout_helper] Simplify Infix and Prefix --- poincare/src/layout_helper.cpp | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/poincare/src/layout_helper.cpp b/poincare/src/layout_helper.cpp index 4716e1da5..57dd3a6ef 100644 --- a/poincare/src/layout_helper.cpp +++ b/poincare/src/layout_helper.cpp @@ -11,13 +11,12 @@ namespace Poincare { Layout LayoutHelper::Infix(const Expression & expression, Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits, const char * operatorName) { - int numberOfChildren = expression.numberOfChildren(); - assert(numberOfChildren > 1); HorizontalLayout result = HorizontalLayout::Builder(); - result.addOrMergeChildAtIndex(expression.childAtIndex(0).createLayout(floatDisplayMode, numberOfSignificantDigits), 0, true); - for (int i = 1; i < numberOfChildren; i++) { - size_t operatorLength = strlen(operatorName); - if (operatorLength > 0) { + const size_t operatorLength = strlen(operatorName); + const int numberOfChildren = expression.numberOfChildren(); + assert(numberOfChildren > 1); + for (int i = 0; i < numberOfChildren; i++) { + if (i > 0 && operatorLength > 0) { result.addOrMergeChildAtIndex(String(operatorName, operatorLength), result.numberOfChildren(), true); } result.addOrMergeChildAtIndex( @@ -35,13 +34,12 @@ Layout LayoutHelper::Prefix(const Expression & expression, Preferences::PrintFlo // Create the layout of arguments separated by commas. HorizontalLayout args = HorizontalLayout::Builder(); - int numberOfChildren = expression.numberOfChildren(); - if (numberOfChildren > 0) { - args.addOrMergeChildAtIndex(expression.childAtIndex(0).createLayout(floatDisplayMode, numberOfSignificantDigits), 0, true); - for (int i = 1; i < numberOfChildren; i++) { + const int numberOfChildren = expression.numberOfChildren(); + for (int i = 0; i < numberOfChildren; i++) { + if (i > 0) { args.addChildAtIndex(CodePointLayout::Builder(','), args.numberOfChildren(), args.numberOfChildren(), nullptr); - args.addOrMergeChildAtIndex(expression.childAtIndex(i).createLayout(floatDisplayMode, numberOfSignificantDigits), args.numberOfChildren(), true); } + args.addOrMergeChildAtIndex(expression.childAtIndex(i).createLayout(floatDisplayMode, numberOfSignificantDigits), args.numberOfChildren(), true); } // Add the parenthesed arguments. result.addOrMergeChildAtIndex(Parentheses(args, false), result.numberOfChildren(), true); From e0bbc73b8b5170250f2c238785d87a7a954375fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Mon, 6 Jan 2020 10:53:55 +0100 Subject: [PATCH 107/680] [apps/regression] Fix code cleaning --- apps/regression/graph_controller.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/regression/graph_controller.cpp b/apps/regression/graph_controller.cpp index f3e7fd5d0..78f8ea350 100644 --- a/apps/regression/graph_controller.cpp +++ b/apps/regression/graph_controller.cpp @@ -238,8 +238,8 @@ bool GraphController::moveCursorHorizontally(int direction, bool fast) { if (*m_selectedDotIndex >= 0) { int dotSelected = m_store->nextDot(*m_selectedSeriesIndex, direction, *m_selectedDotIndex); if (dotSelected >= 0 && dotSelected < m_store->numberOfPairsOfSeries(*m_selectedSeriesIndex)) { - x = m_store->get(*m_selectedSeriesIndex, 0, *m_selectedDotIndex); - y = m_store->get(*m_selectedSeriesIndex, 1, *m_selectedDotIndex); + x = m_store->get(*m_selectedSeriesIndex, 0, dotSelected); + y = m_store->get(*m_selectedSeriesIndex, 1, dotSelected); } else if (dotSelected == m_store->numberOfPairsOfSeries(*m_selectedSeriesIndex)) { x = m_store->meanOfColumn(*m_selectedSeriesIndex, 0); y = m_store->meanOfColumn(*m_selectedSeriesIndex, 1); From d64321d116817b201f4492598391be0dcb245c0a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Mon, 6 Jan 2020 16:45:00 +0100 Subject: [PATCH 108/680] [apps/code] Remove useless class member in ConsoleController --- apps/code/console_controller.cpp | 3 +-- apps/code/console_controller.h | 1 - 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/apps/code/console_controller.cpp b/apps/code/console_controller.cpp index d8e8a2ee6..42cd951de 100644 --- a/apps/code/console_controller.cpp +++ b/apps/code/console_controller.cpp @@ -28,7 +28,6 @@ ConsoleController::ConsoleController(Responder * parentResponder, App * pythonDe TextFieldDelegate(), MicroPython::ExecutionEnvironment(), m_pythonDelegate(pythonDelegate), - m_rowHeight(GlobalPreferences::sharedGlobalPreferences()->font()->glyphSize().height()), m_importScriptsWhenViewAppears(false), m_selectableTableView(this, this, this, this), m_editCell(this, pythonDelegate, this), @@ -202,7 +201,7 @@ int ConsoleController::numberOfRows() const { } KDCoordinate ConsoleController::rowHeight(int j) { - return m_rowHeight; + return GlobalPreferences::sharedGlobalPreferences()->font()->glyphSize().height(); } KDCoordinate ConsoleController::cumulatedHeightFromIndex(int j) { diff --git a/apps/code/console_controller.h b/apps/code/console_controller.h index 60dcf67b5..a29e435e2 100644 --- a/apps/code/console_controller.h +++ b/apps/code/console_controller.h @@ -84,7 +84,6 @@ private: size_t firstNewLineCharIndex(const char * text, size_t length); StackViewController * stackViewController(); App * m_pythonDelegate; - int m_rowHeight; bool m_importScriptsWhenViewAppears; ConsoleStore m_consoleStore; SelectableTableView m_selectableTableView; From 4025d757345c5f1935dac78efd409b687e3b5a3a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Mon, 6 Jan 2020 16:58:35 +0100 Subject: [PATCH 109/680] [apps/code] Fix number of displayable rows in ConsoleController --- apps/code/console_controller.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/code/console_controller.h b/apps/code/console_controller.h index a29e435e2..538f1d21b 100644 --- a/apps/code/console_controller.h +++ b/apps/code/console_controller.h @@ -76,7 +76,8 @@ private: static constexpr size_t k_maxImportCommandSize = 5 + 9 + TextField::maxBufferSize(); // strlen(k_importCommand1) + strlen(k_importCommand2) + TextField::maxBufferSize() static constexpr int LineCellType = 0; static constexpr int EditCellType = 1; - static constexpr int k_numberOfLineCells = 15; // May change depending on the screen height + 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; void flushOutputAccumulationBufferToStore(); void appendTextToOutputAccumulationBuffer(const char * text, size_t length); From 0a21ed2cfb71d354525ed78bae1c1c5a2956915a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Thu, 10 Oct 2019 13:33:11 +0200 Subject: [PATCH 110/680] [liba] strlcpy third argument in size, not length --- liba/include/string.h | 2 +- liba/src/strlcpy.c | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/liba/include/string.h b/liba/include/string.h index 64a237111..a03942ded 100644 --- a/liba/include/string.h +++ b/liba/include/string.h @@ -14,7 +14,7 @@ void * memset(void * b, int c, size_t len); char * strchr(const char * s, int c); int strcmp(const char * s1, const char * s2); int strncmp(const char * s1, const char * s2, size_t n); -size_t strlcpy(char * dst, const char * src, size_t len); +size_t strlcpy(char * dst, const char * src, size_t dstSize); size_t strlen(const char * s); LIBA_END_DECLS diff --git a/liba/src/strlcpy.c b/liba/src/strlcpy.c index 9e835379e..b8e1a9422 100644 --- a/liba/src/strlcpy.c +++ b/liba/src/strlcpy.c @@ -1,11 +1,11 @@ #include -size_t strlcpy(char * dst, const char * src, size_t len) { - if (len == 0) { +size_t strlcpy(char * dst, const char * src, size_t dstSize) { + if (dstSize == 0) { return strlen(src); } const char * cur = src; - const char * end = src+len-1; + const char * end = src+dstSize-1; while (*cur != 0 && cur < end) { *dst++ = *cur++; } From 14cc6ffc59228726984f9d1a7f9100ad2b05ff65 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Thu, 10 Oct 2019 13:43:32 +0200 Subject: [PATCH 111/680] [escher/text_area] Select and copy --- apps/code/python_text_area.cpp | 19 ++++- apps/code/python_text_area.h | 2 +- escher/include/escher/clipboard.h | 2 +- escher/include/escher/solid_text_area.h | 6 +- escher/include/escher/text_area.h | 4 +- escher/include/escher/text_input.h | 12 ++- escher/src/clipboard.cpp | 6 +- escher/src/solid_text_area.cpp | 8 +- escher/src/text_area.cpp | 107 +++++++++++++++++++----- escher/src/text_input.cpp | 53 ++++++++++++ 10 files changed, 180 insertions(+), 39 deletions(-) diff --git a/apps/code/python_text_area.cpp b/apps/code/python_text_area.cpp index 07ced50cd..5a6a4d1d8 100644 --- a/apps/code/python_text_area.cpp +++ b/apps/code/python_text_area.cpp @@ -18,6 +18,7 @@ constexpr KDColor KeywordColor = KDColor::RGB24(0xFF000C); constexpr KDColor OperatorColor = KDColor::RGB24(0xd73a49); constexpr KDColor StringColor = KDColor::RGB24(0x032f62); constexpr KDColor BackgroundColor = KDColorWhite; +constexpr KDColor HighlightColor = KDColorRed; //TODO LEA static inline const char * minPointer(const char * x, const char * y) { return x < y ? x : y; } @@ -71,7 +72,7 @@ void PythonTextArea::ContentView::clearRect(KDContext * ctx, KDRect rect) const #define LOG_DRAW(...) #endif -void PythonTextArea::ContentView::drawLine(KDContext * ctx, int line, const char * text, size_t byteLength, int fromColumn, int toColumn) const { +void PythonTextArea::ContentView::drawLine(KDContext * ctx, int line, const char * text, size_t byteLength, int fromColumn, int toColumn, const char * selectionStart, const char * selectionEnd) const { LOG_DRAW("Drawing \"%.*s\"\n", byteLength, text); if (!m_pythonDelegate->isPythonUser(this)) { @@ -84,7 +85,10 @@ void PythonTextArea::ContentView::drawLine(KDContext * ctx, int line, const char lineStart, minPointer(text + byteLength, lineEnd) - lineStart, StringColor, - BackgroundColor + BackgroundColor, + selectionStart, + selectionEnd, + HighlightColor ); return; } @@ -116,7 +120,10 @@ void PythonTextArea::ContentView::drawLine(KDContext * ctx, int line, const char tokenFrom, tokenLength, TokenColor(lex->tok_kind), - BackgroundColor + BackgroundColor, + selectionStart, + selectionEnd, + HighlightColor ); mp_lexer_to_next(lex); @@ -131,7 +138,11 @@ void PythonTextArea::ContentView::drawLine(KDContext * ctx, int line, const char tokenFrom, text + byteLength - tokenFrom, CommentColor, - BackgroundColor); + BackgroundColor, + selectionStart, + selectionEnd, + HighlightColor + ); } mp_lexer_free(lex); diff --git a/apps/code/python_text_area.h b/apps/code/python_text_area.h index a16b5006b..277d0fba3 100644 --- a/apps/code/python_text_area.h +++ b/apps/code/python_text_area.h @@ -27,7 +27,7 @@ protected: void loadSyntaxHighlighter(); void unloadSyntaxHighlighter(); void clearRect(KDContext * ctx, KDRect rect) const override; - void drawLine(KDContext * ctx, int line, const char * text, size_t length, int fromColumn, int toColumn) const override; + void drawLine(KDContext * ctx, int line, const char * text, size_t length, int fromColumn, int toColumn, const char * selectionStart, const char * selectionEnd) const override; KDRect dirtyRectFromPosition(const char * position, bool lineBreak) const override; private: App * m_pythonDelegate; diff --git a/escher/include/escher/clipboard.h b/escher/include/escher/clipboard.h index 674e5e5f4..46a105e9a 100644 --- a/escher/include/escher/clipboard.h +++ b/escher/include/escher/clipboard.h @@ -7,7 +7,7 @@ class Clipboard { public: static Clipboard * sharedClipboard(); - void store(const char * storedText); + void store(const char * storedText, int length = -1); const char * storedText() const { return m_textBuffer; } void reset(); private: diff --git a/escher/include/escher/solid_text_area.h b/escher/include/escher/solid_text_area.h index e38ffe498..aa4b7c003 100644 --- a/escher/include/escher/solid_text_area.h +++ b/escher/include/escher/solid_text_area.h @@ -18,14 +18,16 @@ protected: ContentView(const KDFont * font, KDColor textColor, KDColor backgroundColor) : TextArea::ContentView(font), m_textColor(textColor), - m_backgroundColor(backgroundColor) + m_backgroundColor(backgroundColor), + m_backgroundHighlightColor(KDColorRed) //TODO LEA { } void clearRect(KDContext * ctx, KDRect rect) const override; - void drawLine(KDContext * ctx, int line, const char * text, size_t length, int fromColumn, int toColumn) const override; + void drawLine(KDContext * ctx, int line, const char * text, size_t length, int fromColumn, int toColumn, const char * selectionStart, const char * selectionEnd) const override; private: KDColor m_textColor; KDColor m_backgroundColor; + KDColor m_backgroundHighlightColor; }; private: diff --git a/escher/include/escher/text_area.h b/escher/include/escher/text_area.h index f4bc36f48..237d603d9 100644 --- a/escher/include/escher/text_area.h +++ b/escher/include/escher/text_area.h @@ -105,8 +105,8 @@ protected: m_cursorLocation = m_text.text(); } void drawRect(KDContext * ctx, KDRect rect) const override; - void drawStringAt(KDContext * ctx, int line, int column, const char * text, size_t length, KDColor textColor, KDColor backgroundColor) const; - virtual void drawLine(KDContext * ctx, int line, const char * text, size_t length, int fromColumn, int toColumn) const = 0; + void drawStringAt(KDContext * ctx, int line, int column, const char * text, size_t length, KDColor textColor, KDColor backgroundColor, const char * selectionStart, const char * selectionEnd, KDColor backgroundHighlightColor) const; + virtual void drawLine(KDContext * ctx, int line, const char * text, size_t length, int fromColumn, int toColumn, const char * selectionStart, const char * selectionEnd) const = 0; virtual void clearRect(KDContext * ctx, KDRect rect) const = 0; KDSize minimalSizeForOptimalDisplay() const override; void setText(char * textBuffer, size_t textBufferSize); diff --git a/escher/include/escher/text_input.h b/escher/include/escher/text_input.h index 90cd79a1e..32436b996 100644 --- a/escher/include/escher/text_input.h +++ b/escher/include/escher/text_input.h @@ -20,6 +20,8 @@ protected: public: ContentView(const KDFont * font) : View(), + m_selectionStart(nullptr), + m_selectionEnd(nullptr), m_cursorView(), m_font(font), m_cursorLocation(nullptr) @@ -33,14 +35,21 @@ protected: virtual bool removePreviousGlyph() = 0; virtual bool removeEndOfLine() = 0; KDRect cursorRect(); + const char * selectionStart() const { return m_selectionStart; } + const char * selectionEnd() const { return m_selectionEnd; } + void addSelection(const char * left, const char * right); + bool resetSelection(); // returns true if the selection was indeed reset + bool currentSelectionIsEmpty() const; + const char * m_selectionStart; + const char * m_selectionEnd; protected: virtual void layoutSubviews(bool force = false) override; void reloadRectFromPosition(const char * position, bool lineBreak = false); virtual KDRect glyphFrameAtPosition(const char * buffer, const char * position) const = 0; + virtual KDRect dirtyRectFromPosition(const char * position, bool lineBreak) const; TextCursorView m_cursorView; const KDFont * m_font; const char * m_cursorLocation; - virtual KDRect dirtyRectFromPosition(const char * position, bool lineBreak) const; private: int numberOfSubviews() const override { return 1; } View * subviewAtIndex(int index) override { @@ -62,6 +71,7 @@ protected: virtual const ContentView * nonEditableContentView() const = 0; bool moveCursorLeft(); bool moveCursorRight(); + bool selectLeftRight(bool left); private: virtual void willSetCursorLocation(const char * * location) {} virtual bool privateRemoveEndOfLine(); diff --git a/escher/src/clipboard.cpp b/escher/src/clipboard.cpp index 3996a9ffd..446211c4b 100644 --- a/escher/src/clipboard.cpp +++ b/escher/src/clipboard.cpp @@ -2,12 +2,14 @@ static Clipboard s_clipboard; +static inline int minInt(int x, int y) { return x < y ? x : y; } + Clipboard * Clipboard::sharedClipboard() { return &s_clipboard; } -void Clipboard::store(const char * storedText) { - strlcpy(m_textBuffer, storedText, TextField::maxBufferSize()); +void Clipboard::store(const char * storedText, int length) { + strlcpy(m_textBuffer, storedText, length == -1 ? TextField::maxBufferSize() : minInt(TextField::maxBufferSize(), length + 1)); } void Clipboard::reset() { diff --git a/escher/src/solid_text_area.cpp b/escher/src/solid_text_area.cpp index b115c9f99..c035618b1 100644 --- a/escher/src/solid_text_area.cpp +++ b/escher/src/solid_text_area.cpp @@ -6,7 +6,7 @@ void SolidTextArea::ContentView::clearRect(KDContext * ctx, KDRect rect) const { ctx->fillRect(rect, m_backgroundColor); } -void SolidTextArea::ContentView::drawLine(KDContext * ctx, int line, const char * text, size_t length, int fromColumn, int toColumn) const { +void SolidTextArea::ContentView::drawLine(KDContext * ctx, int line, const char * text, size_t length, int fromColumn, int toColumn, const char * selectionStart, const char * selectionEnd) const { drawStringAt( ctx, line, @@ -14,6 +14,8 @@ void SolidTextArea::ContentView::drawLine(KDContext * ctx, int line, const char text + fromColumn, minInt(length - fromColumn, toColumn - fromColumn), m_textColor, - m_backgroundColor - ); + m_backgroundColor, + selectionStart, + selectionEnd, + m_backgroundHighlightColor); } diff --git a/escher/src/text_area.cpp b/escher/src/text_area.cpp index 0b61fa3cf..3baed8f3e 100644 --- a/escher/src/text_area.cpp +++ b/escher/src/text_area.cpp @@ -8,7 +8,9 @@ #include #include +static inline const char * maxPointer(const char * x, const char * y) { return x > y ? x : y; } static inline const char * minPointer(const char * x, const char * y) { return x < y ? x : y; } +static inline size_t minSizeT(size_t x, size_t y) { return x < y ? x : y; } /* TextArea */ @@ -96,32 +98,67 @@ bool TextArea::handleEventWithText(const char * text, bool indentation, bool for bool TextArea::handleEvent(Ion::Events::Event event) { if (m_delegate != nullptr && m_delegate->textAreaDidReceiveEvent(this, event)) { return true; - } else if (handleBoxEvent(event)) { + } + if (handleBoxEvent(event)) { return true; - } else if (event == Ion::Events::Left) { + } + if (event == Ion::Events::ShiftLeft || event == Ion::Events::ShiftRight) { + if (event == Ion::Events::ShiftLeft) { + selectLeftRight(true); + } else if (event == Ion::Events::ShiftRight) { + selectLeftRight(false); + } + scrollToCursor(); //TODO LEA remove? + return true; + } + + if (event == Ion::Events::Left) { + if (contentView()->resetSelection()) { + return true; + } return TextInput::moveCursorLeft(); - } else if (event == Ion::Events::Right) { + } + if (event == Ion::Events::Right) { + if (contentView()->resetSelection()) { + return true; + } return TextInput::moveCursorRight(); - } else if (event == Ion::Events::Up) { + } + if (event == Ion::Events::Backspace) { + contentView()->resetSelection(); + return removePreviousGlyph(); + } + if (event.hasText()) { + contentView()->resetSelection(); + return handleEventWithText(event.text()); + } + if (event == Ion::Events::EXE) { + contentView()->resetSelection(); + return handleEventWithText("\n"); + } + if (event == Ion::Events::Copy) { + if (contentView()->currentSelectionIsEmpty()) { + return false; + } + const char * start = contentView()->selectionStart(); + Clipboard::sharedClipboard()->store(start, contentView()->selectionEnd() - start); + return true; + } + if (event == Ion::Events::Paste) { + //TODO LEA + return handleEventWithText(Clipboard::sharedClipboard()->storedText()); + } + if (event == Ion::Events::Up) { + contentView()->resetSelection(); contentView()->moveCursorGeo(0, -1); } else if (event == Ion::Events::Down) { + contentView()->resetSelection(); contentView()->moveCursorGeo(0, 1); - } else if (event == Ion::Events::ShiftLeft) { - contentView()->moveCursorGeo(-INT_MAX/2, 0); - } else if (event == Ion::Events::ShiftRight) { - contentView()->moveCursorGeo(INT_MAX/2, 0); - } else if (event == Ion::Events::Backspace) { - return removePreviousGlyph(); - } else if (event.hasText()) { - return handleEventWithText(event.text()); - } else if (event == Ion::Events::EXE) { - return handleEventWithText("\n"); } else if (event == Ion::Events::Clear) { + //TODO LEA if (!contentView()->removeEndOfLine()) { contentView()->removeStartOfLine(); } - } else if (event == Ion::Events::Paste) { - return handleEventWithText(Clipboard::sharedClipboard()->storedText()); } else { return false; } @@ -141,11 +178,11 @@ int TextArea::indentationBeforeCursor() const { * another code point, until reaching the beginning of the line. */ UTF8Helper::PerformAtCodePoints(const_cast