From 5ca6b7dbf8839c9d4c3a03c753c9618d7616c26c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Mon, 9 Mar 2020 16:26:24 +0100 Subject: [PATCH 01/33] [poincare/code_point_layout] Fix collapsing Scenario: Enter "(12/34 * 10)" then press "Divide" -> the numerator of the division was not the whole parenthesed expression --- poincare/src/code_point_layout.cpp | 32 +++++++++++++++--------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/poincare/src/code_point_layout.cpp b/poincare/src/code_point_layout.cpp index b85913194..5d32863b1 100644 --- a/poincare/src/code_point_layout.cpp +++ b/poincare/src/code_point_layout.cpp @@ -58,22 +58,22 @@ bool CodePointLayoutNode::isCollapsable(int * numberOfOpenParenthesis, bool goin } return false; } - } - if (isMultiplicationCodePoint()) { - /* We want '*' to be collapsable only if the following brother is not a - * fraction, so that the user can write intuitively "1/2 * 3/4". */ - Layout thisRef = CodePointLayout(this); - Layout parent = thisRef.parent(); - if (!parent.isUninitialized()) { - int indexOfThis = parent.indexOfChild(thisRef); - Layout brother; - if (indexOfThis > 0 && goingLeft) { - brother = parent.childAtIndex(indexOfThis-1); - } else if (indexOfThis < parent.numberOfChildren() - 1 && !goingLeft) { - brother = parent.childAtIndex(indexOfThis+1); - } - if (!brother.isUninitialized() && brother.type() == LayoutNode::Type::FractionLayout) { - return false; + if (isMultiplicationCodePoint()) { + /* We want '*' to be collapsable only if the following brother is not a + * fraction, so that the user can write intuitively "1/2 * 3/4". */ + Layout thisRef = CodePointLayout(this); + Layout parent = thisRef.parent(); + if (!parent.isUninitialized()) { + int indexOfThis = parent.indexOfChild(thisRef); + Layout brother; + if (indexOfThis > 0 && goingLeft) { + brother = parent.childAtIndex(indexOfThis-1); + } else if (indexOfThis < parent.numberOfChildren() - 1 && !goingLeft) { + brother = parent.childAtIndex(indexOfThis+1); + } + if (!brother.isUninitialized() && brother.type() == LayoutNode::Type::FractionLayout) { + return false; + } } } } From cf84a307680029fdfd1cbb2f4bf0791d9cf54f8c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Wed, 4 Mar 2020 10:17:00 +0100 Subject: [PATCH 02/33] [poincare/absolute_value] ShallowReduce done in double, not float This fixes abs(-2.3*10^-39) that returned a negative value --- poincare/src/absolute_value.cpp | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/poincare/src/absolute_value.cpp b/poincare/src/absolute_value.cpp index 18bbafe14..bf4aee0d1 100644 --- a/poincare/src/absolute_value.cpp +++ b/poincare/src/absolute_value.cpp @@ -50,21 +50,21 @@ Expression AbsoluteValue::shallowReduce(ExpressionNode::ReductionContext reducti } // |x| = ±x if x is real if (c.isReal(reductionContext.context())) { - float app = c.node()->approximate(float(), reductionContext.context(), reductionContext.complexFormat(), reductionContext.angleUnit()).toScalar(); - if (!std::isnan(app) && - ((c.isNumber() && app >= 0) || app >= Expression::Epsilon())) { - /* abs(a) = a with a >= 0 - * To check that a > 0, if a is a number we can use float comparison; - * in other cases, we are more conservative and rather check that - * a > epsilon ~ 1E-7 to avoid potential error due to float precision. */ - replaceWithInPlace(c); - return c; - } else if (!std::isnan(app) && - ((c.isNumber() && app < 0.0f) || app <= -Expression::Epsilon())) { - // abs(a) = -a with a < 0 (same comment as above to check that a < 0) - Multiplication m = Multiplication::Builder(Rational::Builder(-1), c); - replaceWithInPlace(m); - return m.shallowReduce(reductionContext); + double app = c.node()->approximate(double(), reductionContext.context(), reductionContext.complexFormat(), reductionContext.angleUnit()).toScalar(); + if (!std::isnan(app)) { + if ((c.isNumber() && app >= 0) || app >= Expression::Epsilon()) { + /* abs(a) = a with a >= 0 + * To check that a > 0, if a is a number we can use float comparison; + * in other cases, we are more conservative and rather check that + * a > epsilon ~ 1E-7 to avoid potential error due to float precision. */ + replaceWithInPlace(c); + return c; + } else if ((c.isNumber() && app < 0.0f) || app <= -Expression::Epsilon()) { + // abs(a) = -a with a < 0 (same comment as above to check that a < 0) + Multiplication m = Multiplication::Builder(Rational::Builder(-1), c); + replaceWithInPlace(m); + return m.shallowReduce(reductionContext); + } } } // |a+ib| = sqrt(a^2+b^2) From c1215063ee9f7a9c877a7e78d8ebccdf01c2c45f Mon Sep 17 00:00:00 2001 From: Romain Goyet Date: Mon, 9 Mar 2020 22:22:21 -0400 Subject: [PATCH 03/33] Small fixes to the documentation --- docs/build/index.md | 2 +- docs/index.md | 15 +++++++-------- docs/ion/index.md | 10 +++++----- .../{expression_tree.svg => expression-tree.svg} | 0 docs/poincare/index.md | 5 ++--- 5 files changed, 15 insertions(+), 17 deletions(-) rename docs/poincare/{expression_tree.svg => expression-tree.svg} (100%) diff --git a/docs/build/index.md b/docs/build/index.md index f704da2d1..b34fd48ca 100644 --- a/docs/build/index.md +++ b/docs/build/index.md @@ -54,7 +54,7 @@ git clone https://github.com/numworks/epsilon.git ## Run Epsilon on your computer -Once the SDK has been installed, just open your terminal (Msys2, Terminal.app, xterm, etc...) and type the following commands: +Once the SDK has been installed, just open your terminal (Msys2, Terminal.app, xterm…) and type the following commands: ``` make PLATFORM=simulator clean diff --git a/docs/index.md b/docs/index.md index 509364255..edc128688 100644 --- a/docs/index.md +++ b/docs/index.md @@ -46,12 +46,11 @@ The choice of a programming language is a controversial topic. Not all of them c - It is a [system](https://en.wikipedia.org/wiki/System_programming_language) programming language, which is something we need since we have to write some low-level code. - It has excellent tooling: several extremly high-quality compilers -- It is used for several high-profile projects LLVM, WebKit, MySQL, Photoshop, etc... This ensures a strong ecosystem of tools, code and documentation. +- It is used for several high-profile projects LLVM, WebKit, MySQL, Photoshop… This ensures a strong ecosystem of tools, code and documentation. - It easily allows Object-Oriented Programming, which is a convenient abstraction. - Of course knowing a tool means knowing its limits. C++ isn't exempt of defaults: -- It *is* a complicated language. The C++ 11 specification is 1300 pages long. +- It *is* a complicated language. The C++ 11 specification is 1'300 pages long. - It allows for a lot of abstractions, which is a double-edged sword. It can allow for some very tricky code, and it's very easy to have complex operations being run without noticing. If you want to contribute to Epsilon, you'll need to learn some C++. @@ -66,7 +65,7 @@ The stack memory is possibly the most used area of memory. It contains all local #### Heap memory -Unfortunately, local variables can't answer all use cases, and sometimes one need to allocate memory that lives longer than a function call. This is traditionally done by using a pair of *malloc* / *free* functions. +Unfortunately, local variables can't answer all use cases, and sometimes one need to allocate memory that lives longer than a function call. This is traditionally done by using a pair of `malloc` / `free` functions. This raises a lot of potential problems that can trigger unpredictable dynamic behaviors: @@ -77,7 +76,7 @@ This raises a lot of potential problems that can trigger unpredictable dynamic b
Memory allocation has to be contiguous. So the allocation algorithm has to use a smart heuristic to ensure that it will not fragment its allocated space too much.
-Some automatic memory management solutions do exist (garbage collection, smart pointers), but they all come with a cost. We decided to manually manage dynamic memory, but to use it as sparingly as possible. +We decided to avoid `malloc` altogether and to use a mix of static allocation and a pool of relocatable garbage-collected nodes for manipulating mathematical expressions. ### Writing code that runs on the bare metal @@ -90,8 +89,8 @@ In practice, this means that the firmware will need to know in advance how the m - Where will we store read-only variables? - Where will the code live in memory? -The firmware will also need to take special care of the system initialization. There is no such thing as a "main" function on a firmware. Instead, on Cortex-M4 devices, after reset the CPU simply jumps to the address contained at address 0x00000000 (which happens to be the first bytes of flash memory). So if your firmware starts by 0x12345678, code execution will start at address 0x12345678. +The firmware will also need to take special care of the system initialization. There is no such thing as a "main" function on a firmware. Instead, on Cortex-M devices, after reset the CPU simply jumps to the address contained at address 0x00000000 (which happens to be the first bytes of flash memory). So if your firmware starts by 0x12345678, code execution will start at address 0x12345678. -Enforcing such a careful memory layout would be an impossible job without the proper tool. Fortunately, embedded linkers can be scripted and allow this kind of tailor-made configuration. You'll find Epsilon's linker script in "ion/src/device/boot/flash.ld" - it is heavily commented and should be self-explanatory. +Enforcing such a careful memory layout would be an impossible job without the proper tool. Fortunately, embedded linkers can be scripted and allow this kind of tailor-made configuration. You'll find Epsilon's linker script in [ion/src/device/n0110/flash.ld](https://github.com/numworks/epsilon/blob/master/ion/src/device/n0110/flash.ld) - it is heavily commented and should be self-explanatory. -That being said, there are additional things the OS usually takes care of which we need to do ourselves : for example, initialize global variables to zero. This is done in the "ion/src/device/boot/rt0.cpp" file, which is worth reading too. +That being said, there are additional things the OS usually takes care of which we need to do ourselves : for example, initialize global variables to zero. This is done in the [ion/src/device/shared/boot/rt0.cpp](https://github.com/numworks/epsilon/blob/master/ion/src/device/shared/boot/rt0.cpp) file, which is worth reading too. diff --git a/docs/ion/index.md b/docs/ion/index.md index 9d87c5458..c09205d95 100644 --- a/docs/ion/index.md +++ b/docs/ion/index.md @@ -11,25 +11,25 @@ By providing multiple implementations of the Ion functions, we therefore can get ## Device -This is the reference platform corresponding to the actual device. To really understand what the code is doing, you'll need to refer to our Electrical Engineering pages. Among other thing, Ion is responsible for handling the boot process and the memory layout of the code on the device: +This is the reference platform corresponding to the actual device. To really understand what the code is doing, you'll need to refer to our [Electrical Engineering](https://www.numworks.com/resources/engineering/hardware/electrical/) pages. Among other thing, Ion is responsible for handling the boot process and the memory layout of the code on the device: ### Boot -On boot, the Cortex core interprets the beginning of Flash memory as an array of addresses, each having a specific meaning. For example, the first value gives the address of the stack and the second one the address the processor jumps to right after reset. This list of addresses is called the ISR table. +On boot, the Cortex core interprets the beginning of Flash memory as an array of addresses, each having a specific meaning. For example, the first value gives the address of the stack and the second one the address the processor jumps to right after reset. This list of addresses is called the [ISR table](https://github.com/numworks/epsilon/blob/master/ion/src/device/shared/boot/isr.c). ### Memory layout -Like we saw in the previous paragraph, the MCU has a specific memory layout (for example, Flash starts at address 0x08000000) and expects certain values at certain addresses. To ensure the firmware is laid out in memory exactly how the processor expects it, we use a custom linker script. +Like we saw in the previous paragraph, the MCU has a specific memory layout (for example, Flash starts at address 0x08000000) and expects certain values at certain addresses. To ensure the firmware is laid out in memory exactly how the processor expects it, we use a custom [linker script](https://github.com/numworks/epsilon/blob/master/ion/src/device/n0110/flash.ld). ## Simulator -The simulator platform implements Ion calls using the FLTK library. The result is a native GUI program that can run under a variety of operating systems such as Windows, macOS or most Linux distributions. +The simulator platform implements Ion calls using the [SDL](https://www.libsdl.org/) library. The result is a native GUI program that can run under a variety of operating systems such as Windows, macOS or most Linux distributions. It's very practical to code using the simulator, but one has to pay attention to the differences from an actual device: it'll be significantly faster, and will have a lot more memory. So code written using the simulator should always be thoroughly tested on an actual device. ## Emscripten -The emscripten platform implements Ion calls for a Web browser. This lets us build a version of Epsilon that can run directly in a browser, as shown in our online simulator. The C++ code is transpiled to JavaScript using Emscripten, and then packaged in a webpage. +The emscripten platform implements Ion calls for a Web browser. This lets us build a version of Epsilon that can run directly in a browser, as shown in our [online simulator](https://www.numworks.com/simulator/). The C++ code is transpiled to JavaScript using Emscripten, and then packaged in a webpage. Building on Emscripten takes quite a lot of time so you will most likely not want to use it for development purposes. But obviously it's a very neat feature for end users who can give the calculator a spin straight from their browser. diff --git a/docs/poincare/expression_tree.svg b/docs/poincare/expression-tree.svg similarity index 100% rename from docs/poincare/expression_tree.svg rename to docs/poincare/expression-tree.svg diff --git a/docs/poincare/index.md b/docs/poincare/index.md index f1ada84eb..0e08b9cb2 100644 --- a/docs/poincare/index.md +++ b/docs/poincare/index.md @@ -1,5 +1,5 @@ --- -title: Poincare +title: Poincaré --- # Poincaré @@ -9,7 +9,7 @@ Poincare takes text input such as `1+2*3` and turns it into a tree structure, th Each node of a tree represents either an operator or a value. All nodes have a type (`Type::Addition`, `Type::Multiplication`...) and some also store a value (ie `Type::Rational`). -![A example expression tree of Epsilon software](<%= p "expression_tree.svg" %>){:class="img-right"} +![A example expression tree of Epsilon software](<%= p "expression-tree.svg" %>){:class="img-right"} According to their types, expressions are childless (`Type::Rational`) or store pointers to their children (we call those children operands). To ease tree traversal, each node also keeps a pointer to its parent: that information is somewhat redundant but makes dealing with the expression tree much easier. `Multiplication` and `Addition` are the only type that can hold an infinite number of operands. Other expressions have a fixed number of operands: for instance, an `AbsoluteValue` will only ever have one child. ## RTTI: Run-time type information @@ -43,7 +43,6 @@ To sort those operands, we defined an order on expressions with the following fe * The order relationship is depth-first recursive: if two expressions are equal in type and values, we compare their operands starting with the last. * To compare two expressions, we first sort their commutative children to ensure the unicity of expression representations. This guarantees that the order is total on expressions. - ![Order relationship on expressions](<%= p "order.svg" %>){:class="img-responsive"} In the example, both root nodes are r so we compare their last operands. Both are equal to $$\pi$$ so we compare the next operands. As 3 > 2, we can conclude on the order relation between the expressions. From fccd72b7573f10531637fc2042e0f231e8fb458d Mon Sep 17 00:00:00 2001 From: Ruben Dashyan Date: Mon, 2 Mar 2020 14:54:37 +0100 Subject: [PATCH 04/33] [apps/sequence/sequence] Do not memoize nameLayout Fixes the following bug: In the graph tab of the Sequence app, compute the sum of the terms of a sequence from 1 to 9 and then from 1 to 10. The Layout is memoized after the first time and mispositioned the second time since it is not recomputed. --- apps/sequence/sequence.cpp | 12 ++++-------- apps/sequence/sequence.h | 6 +++--- 2 files changed, 7 insertions(+), 11 deletions(-) diff --git a/apps/sequence/sequence.cpp b/apps/sequence/sequence.cpp index e97f8d390..64643ace1 100644 --- a/apps/sequence/sequence.cpp +++ b/apps/sequence/sequence.cpp @@ -28,7 +28,6 @@ void Sequence::tidy() { m_firstInitialCondition.tidyName(); m_secondInitialCondition.tidy(); m_secondInitialCondition.tidyName(); - m_nameLayout = Layout(); } Sequence::Type Sequence::type() const { @@ -81,13 +80,10 @@ void Sequence::setInitialRank(int rank) { } Poincare::Layout Sequence::nameLayout() { - if (m_nameLayout.isUninitialized()) { - m_nameLayout = HorizontalLayout::Builder( - CodePointLayout::Builder(fullName()[0], KDFont::SmallFont), - VerticalOffsetLayout::Builder(CodePointLayout::Builder(symbol(), KDFont::SmallFont), VerticalOffsetLayoutNode::Position::Subscript) - ); - } - return m_nameLayout; + return HorizontalLayout::Builder( + CodePointLayout::Builder(fullName()[0], KDFont::SmallFont), + VerticalOffsetLayout::Builder(CodePointLayout::Builder(symbol(), KDFont::SmallFont), VerticalOffsetLayoutNode::Position::Subscript) + ); } bool Sequence::isDefined() { diff --git a/apps/sequence/sequence.h b/apps/sequence/sequence.h index e7901de68..d5b5c56a5 100644 --- a/apps/sequence/sequence.h +++ b/apps/sequence/sequence.h @@ -24,8 +24,9 @@ public: DoubleRecurrence = 2 }; Sequence(Ion::Storage::Record record = Record()) : - Function(record), - m_nameLayout() {} + Function(record) + { + } I18n::Message parameterMessageName() const override; CodePoint symbol() const override { return 'n'; } void tidy() override; @@ -153,7 +154,6 @@ private: DefinitionModel m_definition; FirstInitialConditionModel m_firstInitialCondition; SecondInitialConditionModel m_secondInitialCondition; - Poincare::Layout m_nameLayout; }; } From 7a633b1e7591ac298c5325ca452feac9c590394e Mon Sep 17 00:00:00 2001 From: Ruben Dashyan Date: Mon, 2 Mar 2020 15:04:45 +0100 Subject: [PATCH 05/33] [apps/sequence/sequence] SequenceModel's name method need not be virtual --- apps/sequence/sequence.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/sequence/sequence.h b/apps/sequence/sequence.h index d5b5c56a5..d8e2a5f6d 100644 --- a/apps/sequence/sequence.h +++ b/apps/sequence/sequence.h @@ -112,7 +112,7 @@ private: public: SequenceModel() : Shared::ExpressionModel(), m_name() {} void tidyName() { m_name = Poincare::Layout(); } - virtual Poincare::Layout name(Sequence * sequence); + Poincare::Layout name(Sequence * sequence); protected: virtual void buildName(Sequence * sequence) = 0; Poincare::Layout m_name; From e1624c79aaab5288fd449476df331e9673a12f91 Mon Sep 17 00:00:00 2001 From: Ruben Dashyan Date: Fri, 28 Feb 2020 10:55:15 +0100 Subject: [PATCH 06/33] [apps/shared/sum_graph_controller] Class doesn't need to hold m_sumLayout --- apps/shared/sum_graph_controller.cpp | 14 +++++++------- apps/shared/sum_graph_controller.h | 1 - 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/apps/shared/sum_graph_controller.cpp b/apps/shared/sum_graph_controller.cpp index f7a72048a..2db803aad 100644 --- a/apps/shared/sum_graph_controller.cpp +++ b/apps/shared/sum_graph_controller.cpp @@ -157,7 +157,6 @@ void SumGraphController::reloadBannerView() { SumGraphController::LegendView::LegendView(SumGraphController * controller, InputEventHandlerDelegate * inputEventHandlerDelegate, CodePoint sumSymbol) : m_sum(0.0f, 0.5f, KDColorBlack, Palette::GreyMiddle), - m_sumLayout(), m_legend(k_font, I18n::Message::Default, 0.0f, 0.5f, KDColorBlack, Palette::GreyMiddle), m_editableZone(controller, m_textBuffer, k_editableZoneBufferSize, TextField::maxBufferSize(), inputEventHandlerDelegate, controller, k_font, 0.0f, 0.5f, KDColorBlack, Palette::GreyMiddle), m_sumSymbol(sumSymbol) @@ -190,14 +189,15 @@ void SumGraphController::LegendView::setSumSymbol(Step step, double start, doubl assert(step == Step::Result || functionLayout.isUninitialized()); constexpr int sigmaLength = 2; const CodePoint sigma[sigmaLength] = {' ', m_sumSymbol}; + Poincare::Layout sumLayout; if (step == Step::FirstParameter) { - m_sumLayout = LayoutHelper::CodePointString(sigma, sigmaLength); + sumLayout = LayoutHelper::CodePointString(sigma, sigmaLength); } else if (step == Step::SecondParameter) { constexpr int precision = Preferences::MediumNumberOfSignificantDigits; constexpr int bufferSize = PrintFloat::charSizeForFloatsWithPrecision(precision); char buffer[bufferSize]; PoincareHelpers::ConvertFloatToTextWithDisplayMode(start, buffer, bufferSize, precision, Preferences::PrintFloatMode::Decimal); - m_sumLayout = CondensedSumLayout::Builder( + sumLayout = CondensedSumLayout::Builder( LayoutHelper::CodePointString(sigma, sigmaLength), LayoutHelper::String(buffer, strlen(buffer), k_font), EmptyLayout::Builder(EmptyLayoutNode::Color::Yellow, false, k_font, false)); @@ -210,18 +210,18 @@ void SumGraphController::LegendView::setSumSymbol(Step step, double start, doubl Layout start = LayoutHelper::String(buffer, strlen(buffer), k_font); PoincareHelpers::ConvertFloatToTextWithDisplayMode(end, buffer, bufferSize, precision, Preferences::PrintFloatMode::Decimal); Layout end = LayoutHelper::String(buffer, strlen(buffer), k_font); - m_sumLayout = CondensedSumLayout::Builder( + sumLayout = CondensedSumLayout::Builder( LayoutHelper::CodePointString(sigma, sigmaLength), start, end); strlcpy(buffer, "= ", 3); PoincareHelpers::ConvertFloatToText(result, buffer+2, bufferSize-2, precision); - m_sumLayout = HorizontalLayout::Builder( - m_sumLayout, + sumLayout = HorizontalLayout::Builder( + sumLayout, functionLayout, LayoutHelper::String(buffer, strlen(buffer), k_font)); } - m_sum.setLayout(m_sumLayout); + m_sum.setLayout(sumLayout); if (step == Step::Result) { m_sum.setAlignment(0.5f, 0.5f); } else { diff --git a/apps/shared/sum_graph_controller.h b/apps/shared/sum_graph_controller.h index 8042117b2..c8ba87936 100644 --- a/apps/shared/sum_graph_controller.h +++ b/apps/shared/sum_graph_controller.h @@ -69,7 +69,6 @@ private: void layoutSubviews(bool force = false) override; void layoutSubviews(Step step, bool force); ExpressionView m_sum; - Poincare::Layout m_sumLayout; MessageTextView m_legend; TextField m_editableZone; char m_textBuffer[k_editableZoneBufferSize]; From 6b527d3b00e6aa7806dccb2bc5c010cd1bffca2a Mon Sep 17 00:00:00 2001 From: Ruben Dashyan Date: Fri, 28 Feb 2020 11:47:12 +0100 Subject: [PATCH 07/33] [apps/shared/sum_graph_controller] Rename setSumSymbol to setSumLayout --- apps/shared/sum_graph_controller.cpp | 4 ++-- apps/shared/sum_graph_controller.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/shared/sum_graph_controller.cpp b/apps/shared/sum_graph_controller.cpp index 2db803aad..06b8ed49a 100644 --- a/apps/shared/sum_graph_controller.cpp +++ b/apps/shared/sum_graph_controller.cpp @@ -150,7 +150,7 @@ void SumGraphController::reloadBannerView() { m_legendView.setEditableZone(m_cursor->x()); result = NAN; } - m_legendView.setSumSymbol(m_step, m_startSum, endSum, result, functionLayout); + m_legendView.setSumLayout(m_step, m_startSum, endSum, result, functionLayout); } /* Legend View */ @@ -185,7 +185,7 @@ void SumGraphController::LegendView::setEditableZone(double d) { m_editableZone.setText(buffer); } -void SumGraphController::LegendView::setSumSymbol(Step step, double start, double end, double result, Layout functionLayout) { +void SumGraphController::LegendView::setSumLayout(Step step, double start, double end, double result, Layout functionLayout) { assert(step == Step::Result || functionLayout.isUninitialized()); constexpr int sigmaLength = 2; const CodePoint sigma[sigmaLength] = {' ', m_sumSymbol}; diff --git a/apps/shared/sum_graph_controller.h b/apps/shared/sum_graph_controller.h index c8ba87936..de57d7691 100644 --- a/apps/shared/sum_graph_controller.h +++ b/apps/shared/sum_graph_controller.h @@ -55,7 +55,7 @@ private: void drawRect(KDContext * ctx, KDRect rect) const override; void setLegendMessage(I18n::Message message, Step step); void setEditableZone(double d); - void setSumSymbol(Step step, double start, double end, double result, Poincare::Layout functionLayout); + void setSumLayout(Step step, double start, double end, double result, Poincare::Layout functionLayout); private: constexpr static KDCoordinate k_editableZoneBufferSize = Poincare::PrintFloat::k_maxFloatCharSize; constexpr static KDCoordinate k_legendHeight = 35; From 24fa8b28a9fd3ff58f85363ab2acc6351dc32e38 Mon Sep 17 00:00:00 2001 From: Ruben Dashyan Date: Fri, 28 Feb 2020 11:47:51 +0100 Subject: [PATCH 08/33] [apps/shared/sum_graph_controller] In LegendView::setSumLayout, factor m_sum.setAlignment --- apps/shared/sum_graph_controller.cpp | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/apps/shared/sum_graph_controller.cpp b/apps/shared/sum_graph_controller.cpp index 06b8ed49a..26d487733 100644 --- a/apps/shared/sum_graph_controller.cpp +++ b/apps/shared/sum_graph_controller.cpp @@ -222,11 +222,7 @@ void SumGraphController::LegendView::setSumLayout(Step step, double start, doubl LayoutHelper::String(buffer, strlen(buffer), k_font)); } m_sum.setLayout(sumLayout); - if (step == Step::Result) { - m_sum.setAlignment(0.5f, 0.5f); - } else { - m_sum.setAlignment(0.0f, 0.5f); - } + m_sum.setAlignment(0.5f * (step == Step::Result), 0.5f); layoutSubviews(step, false); } From 7ee8c31c7019a281ccadca3e53490b41d3f29e3f Mon Sep 17 00:00:00 2001 From: Ruben Dashyan Date: Fri, 28 Feb 2020 13:57:17 +0100 Subject: [PATCH 09/33] [apps/shared/sum_graph_controller] In LegendView::setSumLayout, factor sum symbol layout --- apps/shared/sum_graph_controller.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/apps/shared/sum_graph_controller.cpp b/apps/shared/sum_graph_controller.cpp index 26d487733..6314f9e51 100644 --- a/apps/shared/sum_graph_controller.cpp +++ b/apps/shared/sum_graph_controller.cpp @@ -189,16 +189,15 @@ void SumGraphController::LegendView::setSumLayout(Step step, double start, doubl assert(step == Step::Result || functionLayout.isUninitialized()); constexpr int sigmaLength = 2; const CodePoint sigma[sigmaLength] = {' ', m_sumSymbol}; - Poincare::Layout sumLayout; + Poincare::Layout sumLayout = LayoutHelper::CodePointString(sigma, sigmaLength); if (step == Step::FirstParameter) { - sumLayout = LayoutHelper::CodePointString(sigma, sigmaLength); } else if (step == Step::SecondParameter) { constexpr int precision = Preferences::MediumNumberOfSignificantDigits; constexpr int bufferSize = PrintFloat::charSizeForFloatsWithPrecision(precision); char buffer[bufferSize]; PoincareHelpers::ConvertFloatToTextWithDisplayMode(start, buffer, bufferSize, precision, Preferences::PrintFloatMode::Decimal); sumLayout = CondensedSumLayout::Builder( - LayoutHelper::CodePointString(sigma, sigmaLength), + sumLayout, LayoutHelper::String(buffer, strlen(buffer), k_font), EmptyLayout::Builder(EmptyLayoutNode::Color::Yellow, false, k_font, false)); } else { @@ -211,7 +210,7 @@ void SumGraphController::LegendView::setSumLayout(Step step, double start, doubl PoincareHelpers::ConvertFloatToTextWithDisplayMode(end, buffer, bufferSize, precision, Preferences::PrintFloatMode::Decimal); Layout end = LayoutHelper::String(buffer, strlen(buffer), k_font); sumLayout = CondensedSumLayout::Builder( - LayoutHelper::CodePointString(sigma, sigmaLength), + sumLayout, start, end); strlcpy(buffer, "= ", 3); From 04794dd26f2d6ede003eccdc2925343eb7d8f203 Mon Sep 17 00:00:00 2001 From: Ruben Dashyan Date: Fri, 28 Feb 2020 14:00:38 +0100 Subject: [PATCH 10/33] [apps/shared/sum_graph_controller] Uniformize number of significant digits --- apps/shared/sum_graph_controller.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/shared/sum_graph_controller.cpp b/apps/shared/sum_graph_controller.cpp index 6314f9e51..dfc0e32c5 100644 --- a/apps/shared/sum_graph_controller.cpp +++ b/apps/shared/sum_graph_controller.cpp @@ -201,7 +201,7 @@ void SumGraphController::LegendView::setSumLayout(Step step, double start, doubl LayoutHelper::String(buffer, strlen(buffer), k_font), EmptyLayout::Builder(EmptyLayoutNode::Color::Yellow, false, k_font, false)); } else { - constexpr int precision = Preferences::LargeNumberOfSignificantDigits; + constexpr int precision = Preferences::MediumNumberOfSignificantDigits; constexpr int sizeForPrecision = PrintFloat::charSizeForFloatsWithPrecision(precision); constexpr int bufferSize = 2 + sizeForPrecision; char buffer[bufferSize]; From 0a92579571dcf529dca92ee7996055b1ff0ebd0a Mon Sep 17 00:00:00 2001 From: Ruben Dashyan Date: Fri, 28 Feb 2020 14:07:59 +0100 Subject: [PATCH 11/33] [apps/shared/sum_graph_controller] Fix variable type --- apps/shared/sum_graph_controller.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/shared/sum_graph_controller.h b/apps/shared/sum_graph_controller.h index de57d7691..3119d9577 100644 --- a/apps/shared/sum_graph_controller.h +++ b/apps/shared/sum_graph_controller.h @@ -57,7 +57,7 @@ private: void setEditableZone(double d); void setSumLayout(Step step, double start, double end, double result, Poincare::Layout functionLayout); private: - constexpr static KDCoordinate k_editableZoneBufferSize = Poincare::PrintFloat::k_maxFloatCharSize; + constexpr static size_t k_editableZoneBufferSize = Poincare::PrintFloat::k_maxFloatCharSize; constexpr static KDCoordinate k_legendHeight = 35; constexpr static const KDFont * k_font = KDFont::SmallFont; static KDCoordinate editableZoneWidth() { return 12*k_font->glyphSize().width(); } From 55bb3f677aa3c246b7fc658c3b3e823782fde675 Mon Sep 17 00:00:00 2001 From: Ruben Dashyan Date: Fri, 28 Feb 2020 14:51:27 +0100 Subject: [PATCH 12/33] [apps/shared/sum_graph_controller] In LegendView::setSumLayout, simplify equal sign --- apps/shared/sum_graph_controller.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/apps/shared/sum_graph_controller.cpp b/apps/shared/sum_graph_controller.cpp index dfc0e32c5..ff3e13a39 100644 --- a/apps/shared/sum_graph_controller.cpp +++ b/apps/shared/sum_graph_controller.cpp @@ -202,8 +202,7 @@ void SumGraphController::LegendView::setSumLayout(Step step, double start, doubl EmptyLayout::Builder(EmptyLayoutNode::Color::Yellow, false, k_font, false)); } else { constexpr int precision = Preferences::MediumNumberOfSignificantDigits; - constexpr int sizeForPrecision = PrintFloat::charSizeForFloatsWithPrecision(precision); - constexpr int bufferSize = 2 + sizeForPrecision; + constexpr int bufferSize = PrintFloat::charSizeForFloatsWithPrecision(precision); char buffer[bufferSize]; PoincareHelpers::ConvertFloatToTextWithDisplayMode(start, buffer, bufferSize, precision, Preferences::PrintFloatMode::Decimal); Layout start = LayoutHelper::String(buffer, strlen(buffer), k_font); @@ -213,11 +212,11 @@ void SumGraphController::LegendView::setSumLayout(Step step, double start, doubl sumLayout, start, end); - strlcpy(buffer, "= ", 3); - PoincareHelpers::ConvertFloatToText(result, buffer+2, bufferSize-2, precision); + PoincareHelpers::ConvertFloatToText(result, buffer, bufferSize, precision); sumLayout = HorizontalLayout::Builder( sumLayout, functionLayout, + LayoutHelper::String("= ", 2, k_font), LayoutHelper::String(buffer, strlen(buffer), k_font)); } m_sum.setLayout(sumLayout); From f0ef84b3bc1385862b76aa5c7f9750aeed5ec864 Mon Sep 17 00:00:00 2001 From: Ruben Dashyan Date: Fri, 28 Feb 2020 15:56:04 +0100 Subject: [PATCH 13/33] [apps/shared/sum_graph_controller] In LegendView::setSumLayout, factor Layout building --- apps/shared/sum_graph_controller.cpp | 38 +++++++++++++--------------- 1 file changed, 17 insertions(+), 21 deletions(-) diff --git a/apps/shared/sum_graph_controller.cpp b/apps/shared/sum_graph_controller.cpp index ff3e13a39..6f9797c97 100644 --- a/apps/shared/sum_graph_controller.cpp +++ b/apps/shared/sum_graph_controller.cpp @@ -190,34 +190,30 @@ void SumGraphController::LegendView::setSumLayout(Step step, double start, doubl constexpr int sigmaLength = 2; const CodePoint sigma[sigmaLength] = {' ', m_sumSymbol}; Poincare::Layout sumLayout = LayoutHelper::CodePointString(sigma, sigmaLength); - if (step == Step::FirstParameter) { - } else if (step == Step::SecondParameter) { + if (step != Step::FirstParameter) { constexpr int precision = Preferences::MediumNumberOfSignificantDigits; constexpr int bufferSize = PrintFloat::charSizeForFloatsWithPrecision(precision); char buffer[bufferSize]; + Layout endLayout; + if (step == Step::SecondParameter) { + endLayout = EmptyLayout::Builder(EmptyLayoutNode::Color::Yellow, false, k_font, false); + } else { + PoincareHelpers::ConvertFloatToTextWithDisplayMode(end, buffer, bufferSize, precision, Preferences::PrintFloatMode::Decimal); + endLayout = LayoutHelper::String(buffer, strlen(buffer), k_font); + } PoincareHelpers::ConvertFloatToTextWithDisplayMode(start, buffer, bufferSize, precision, Preferences::PrintFloatMode::Decimal); sumLayout = CondensedSumLayout::Builder( sumLayout, LayoutHelper::String(buffer, strlen(buffer), k_font), - EmptyLayout::Builder(EmptyLayoutNode::Color::Yellow, false, k_font, false)); - } else { - constexpr int precision = Preferences::MediumNumberOfSignificantDigits; - constexpr int bufferSize = PrintFloat::charSizeForFloatsWithPrecision(precision); - char buffer[bufferSize]; - PoincareHelpers::ConvertFloatToTextWithDisplayMode(start, buffer, bufferSize, precision, Preferences::PrintFloatMode::Decimal); - Layout start = LayoutHelper::String(buffer, strlen(buffer), k_font); - PoincareHelpers::ConvertFloatToTextWithDisplayMode(end, buffer, bufferSize, precision, Preferences::PrintFloatMode::Decimal); - Layout end = LayoutHelper::String(buffer, strlen(buffer), k_font); - sumLayout = CondensedSumLayout::Builder( - sumLayout, - start, - end); - PoincareHelpers::ConvertFloatToText(result, buffer, bufferSize, precision); - sumLayout = HorizontalLayout::Builder( - sumLayout, - functionLayout, - LayoutHelper::String("= ", 2, k_font), - LayoutHelper::String(buffer, strlen(buffer), k_font)); + endLayout); + if (step == Step::Result) { + PoincareHelpers::ConvertFloatToText(result, buffer, bufferSize, precision); + sumLayout = HorizontalLayout::Builder( + sumLayout, + functionLayout, + LayoutHelper::String("= ", 2, k_font), + LayoutHelper::String(buffer, strlen(buffer), k_font)); + } } m_sum.setLayout(sumLayout); m_sum.setAlignment(0.5f * (step == Step::Result), 0.5f); From afb1d18d65af767cac392c9fa23e40f298e981b1 Mon Sep 17 00:00:00 2001 From: Ruben Dashyan Date: Mon, 2 Mar 2020 18:00:19 +0100 Subject: [PATCH 14/33] [apps/shared/sum_graph_controller] Factor constexpr --- apps/shared/sum_graph_controller.cpp | 17 ++++++----------- apps/shared/sum_graph_controller.h | 2 ++ 2 files changed, 8 insertions(+), 11 deletions(-) diff --git a/apps/shared/sum_graph_controller.cpp b/apps/shared/sum_graph_controller.cpp index 6f9797c97..ac5ce035e 100644 --- a/apps/shared/sum_graph_controller.cpp +++ b/apps/shared/sum_graph_controller.cpp @@ -3,7 +3,6 @@ #include #include #include -#include #include "poincare_helpers.h" #include @@ -178,10 +177,8 @@ void SumGraphController::LegendView::setLegendMessage(I18n::Message message, Ste } void SumGraphController::LegendView::setEditableZone(double d) { - constexpr int precision = Preferences::MediumNumberOfSignificantDigits; - constexpr int bufferSize = PrintFloat::charSizeForFloatsWithPrecision(precision); - char buffer[bufferSize]; - PoincareHelpers::ConvertFloatToTextWithDisplayMode(d, buffer, bufferSize, precision, Preferences::PrintFloatMode::Decimal); + char buffer[k_valuesBufferSize]; + PoincareHelpers::ConvertFloatToTextWithDisplayMode(d, buffer, k_valuesBufferSize, k_valuesPrecision, Preferences::PrintFloatMode::Decimal); m_editableZone.setText(buffer); } @@ -191,23 +188,21 @@ void SumGraphController::LegendView::setSumLayout(Step step, double start, doubl const CodePoint sigma[sigmaLength] = {' ', m_sumSymbol}; Poincare::Layout sumLayout = LayoutHelper::CodePointString(sigma, sigmaLength); if (step != Step::FirstParameter) { - constexpr int precision = Preferences::MediumNumberOfSignificantDigits; - constexpr int bufferSize = PrintFloat::charSizeForFloatsWithPrecision(precision); - char buffer[bufferSize]; + char buffer[k_valuesBufferSize]; Layout endLayout; if (step == Step::SecondParameter) { endLayout = EmptyLayout::Builder(EmptyLayoutNode::Color::Yellow, false, k_font, false); } else { - PoincareHelpers::ConvertFloatToTextWithDisplayMode(end, buffer, bufferSize, precision, Preferences::PrintFloatMode::Decimal); + PoincareHelpers::ConvertFloatToTextWithDisplayMode(end, buffer, k_valuesBufferSize, k_valuesPrecision, Preferences::PrintFloatMode::Decimal); endLayout = LayoutHelper::String(buffer, strlen(buffer), k_font); } - PoincareHelpers::ConvertFloatToTextWithDisplayMode(start, buffer, bufferSize, precision, Preferences::PrintFloatMode::Decimal); + PoincareHelpers::ConvertFloatToTextWithDisplayMode(start, buffer, k_valuesBufferSize, k_valuesPrecision, Preferences::PrintFloatMode::Decimal); sumLayout = CondensedSumLayout::Builder( sumLayout, LayoutHelper::String(buffer, strlen(buffer), k_font), endLayout); if (step == Step::Result) { - PoincareHelpers::ConvertFloatToText(result, buffer, bufferSize, precision); + PoincareHelpers::ConvertFloatToText(result, buffer, k_valuesBufferSize, k_valuesPrecision); sumLayout = HorizontalLayout::Builder( sumLayout, functionLayout, diff --git a/apps/shared/sum_graph_controller.h b/apps/shared/sum_graph_controller.h index 3119d9577..e876f23c8 100644 --- a/apps/shared/sum_graph_controller.h +++ b/apps/shared/sum_graph_controller.h @@ -58,6 +58,8 @@ private: void setSumLayout(Step step, double start, double end, double result, Poincare::Layout functionLayout); private: constexpr static size_t k_editableZoneBufferSize = Poincare::PrintFloat::k_maxFloatCharSize; + constexpr static int k_valuesPrecision = Poincare::Preferences::MediumNumberOfSignificantDigits; + constexpr static int k_valuesBufferSize = Poincare::PrintFloat::charSizeForFloatsWithPrecision(k_valuesPrecision); constexpr static KDCoordinate k_legendHeight = 35; constexpr static const KDFont * k_font = KDFont::SmallFont; static KDCoordinate editableZoneWidth() { return 12*k_font->glyphSize().width(); } From aa4a33d84940252e511dc83fe3281fcf05f39a7d Mon Sep 17 00:00:00 2001 From: Ruben Dashyan Date: Tue, 3 Mar 2020 10:11:01 +0100 Subject: [PATCH 15/33] [poincare/layout_node] Remove unused method --- poincare/include/poincare/layout_node.h | 1 - poincare/src/layout_node.cpp | 10 ---------- 2 files changed, 11 deletions(-) diff --git a/poincare/include/poincare/layout_node.h b/poincare/include/poincare/layout_node.h index 5ec8855c3..afad9aae1 100644 --- a/poincare/include/poincare/layout_node.h +++ b/poincare/include/poincare/layout_node.h @@ -61,7 +61,6 @@ public: // Rendering void draw(KDContext * ctx, KDPoint p, KDColor expressionColor = KDColorBlack, KDColor backgroundColor = KDColorWhite, Layout * selectionStart = nullptr, Layout * selectionEnd = nullptr, KDColor selectionColor = KDColorRed); - KDPoint origin(); KDPoint absoluteOrigin(); KDSize layoutSize(); KDCoordinate baseline(); diff --git a/poincare/src/layout_node.cpp b/poincare/src/layout_node.cpp index 2c50dd9a6..7c33a2f3d 100644 --- a/poincare/src/layout_node.cpp +++ b/poincare/src/layout_node.cpp @@ -39,16 +39,6 @@ void LayoutNode::draw(KDContext * ctx, KDPoint p, KDColor expressionColor, KDCol } } -KDPoint LayoutNode::origin() { - LayoutNode * p = parent(); - if (p == nullptr) { - return absoluteOrigin(); - } else { - return KDPoint(absoluteOrigin().x() - p->absoluteOrigin().x(), - absoluteOrigin().y() - p->absoluteOrigin().y()); - } -} - KDPoint LayoutNode::absoluteOrigin() { LayoutNode * p = parent(); if (!m_positioned) { From ed98218e7bb4e911eaa934024610de57347f2264 Mon Sep 17 00:00:00 2001 From: Ruben Dashyan Date: Tue, 3 Mar 2020 14:05:58 +0100 Subject: [PATCH 16/33] [poincare/grid_layout] Explicit the making of a protected member as public --- poincare/include/poincare/grid_layout.h | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/poincare/include/poincare/grid_layout.h b/poincare/include/poincare/grid_layout.h index 91890c5b0..8a7534386 100644 --- a/poincare/include/poincare/grid_layout.h +++ b/poincare/include/poincare/grid_layout.h @@ -95,9 +95,7 @@ public: static GridLayout Builder() { return TreeHandle::NAryBuilder(); } void setDimensions(int rows, int columns); - void addChildAtIndex(Layout l, int index, int currentNumberOfChildren, LayoutCursor * cursor) { - Layout::addChildAtIndex(l, index, currentNumberOfChildren, cursor); - } + using Layout::addChildAtIndex; int numberOfRows() const { return node()->numberOfRows(); } int numberOfColumns() const { return node()->numberOfColumns(); } private: From 8337e36f46f9d1a0f55c5698e683440d084ff310 Mon Sep 17 00:00:00 2001 From: Ruben Dashyan Date: Wed, 4 Mar 2020 14:48:20 +0100 Subject: [PATCH 17/33] [apps/shared/*_cursor_view] CursorView inherits from TransparentView so that CursorView tells its superview to redrawn in the background, except the RoundCursorView. --- apps/shared/cursor_view.h | 4 ++-- apps/shared/round_cursor_view.cpp | 4 ++++ apps/shared/round_cursor_view.h | 1 + 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/apps/shared/cursor_view.h b/apps/shared/cursor_view.h index 4590950b2..c0f5c6062 100644 --- a/apps/shared/cursor_view.h +++ b/apps/shared/cursor_view.h @@ -1,11 +1,11 @@ #ifndef SHARED_CURSOR_VIEW_H #define SHARED_CURSOR_VIEW_H -#include +#include namespace Shared { -class CursorView : public View { +class CursorView : public TransparentView { public: virtual void setCursorFrame(KDRect frame, bool force) { View::setFrame(frame, force); } void drawRect(KDContext * ctx, KDRect rect) const override; diff --git a/apps/shared/round_cursor_view.cpp b/apps/shared/round_cursor_view.cpp index 5355f544b..ecc0fad09 100644 --- a/apps/shared/round_cursor_view.cpp +++ b/apps/shared/round_cursor_view.cpp @@ -49,6 +49,10 @@ void RoundCursorView::setCursorFrame(KDRect f, bool force) { CursorView::setCursorFrame(f, force); } +void RoundCursorView::markRectAsDirty(KDRect rect) { + View::markRectAsDirty(rect); +} + #ifdef GRAPH_CURSOR_SPEEDUP bool RoundCursorView::eraseCursorIfPossible() { if (!m_underneathPixelBufferLoaded) { diff --git a/apps/shared/round_cursor_view.h b/apps/shared/round_cursor_view.h index 001113406..eff1f93c3 100644 --- a/apps/shared/round_cursor_view.h +++ b/apps/shared/round_cursor_view.h @@ -24,6 +24,7 @@ public: void resetMemoization() const { m_underneathPixelBufferLoaded = false; } #endif private: + void markRectAsDirty(KDRect rect) override; #ifdef GRAPH_CURSOR_SPEEDUP bool eraseCursorIfPossible(); #endif From d64e58b9dc5490d0e4ac23b65af11ec62eb414af Mon Sep 17 00:00:00 2001 From: Ruben Dashyan Date: Wed, 4 Mar 2020 14:50:57 +0100 Subject: [PATCH 18/33] [escher/transparent_view] Remove redundancy --- escher/src/transparent_view.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/escher/src/transparent_view.cpp b/escher/src/transparent_view.cpp index 9f85ecd80..631910362 100644 --- a/escher/src/transparent_view.cpp +++ b/escher/src/transparent_view.cpp @@ -2,7 +2,7 @@ void TransparentView::markRectAsDirty(KDRect rect) { if (m_superview) { - m_superview->markRectAsDirty(KDRect(rect.translatedBy(m_frame.origin()))); + m_superview->markRectAsDirty(rect.translatedBy(m_frame.origin())); } View::markRectAsDirty(rect); } From 037fa088e986ac57a7ef1ca7022683c2ddeb5698 Mon Sep 17 00:00:00 2001 From: Ruben Dashyan Date: Wed, 4 Mar 2020 14:51:45 +0100 Subject: [PATCH 19/33] [escher/transparent_view] markRectAsDirty is protected as it is in View. --- escher/include/escher/transparent_view.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/escher/include/escher/transparent_view.h b/escher/include/escher/transparent_view.h index 582e20eac..6f7865f54 100644 --- a/escher/include/escher/transparent_view.h +++ b/escher/include/escher/transparent_view.h @@ -4,7 +4,7 @@ #include class TransparentView : public View { -public: +protected: void markRectAsDirty(KDRect rect) override; }; From 1ca902c129f400051a7d57a73b571b72ea0a61da Mon Sep 17 00:00:00 2001 From: Ruben Dashyan Date: Tue, 10 Mar 2020 10:43:51 +0100 Subject: [PATCH 20/33] [apps/shared/round_cursor_view] Comment about markRectAsDirty --- apps/shared/round_cursor_view.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/apps/shared/round_cursor_view.cpp b/apps/shared/round_cursor_view.cpp index ecc0fad09..790817b7d 100644 --- a/apps/shared/round_cursor_view.cpp +++ b/apps/shared/round_cursor_view.cpp @@ -50,6 +50,10 @@ void RoundCursorView::setCursorFrame(KDRect f, bool force) { } void RoundCursorView::markRectAsDirty(KDRect rect) { + /* The CursorView class inherits from TransparentView, so does + * RoundCursorView. The method markRectAsDirty is thus overriden to avoid + * marking as dirty the background of the RoundCursorView in its superview. + */ View::markRectAsDirty(rect); } From 79f3ee43bc8a38b97ff395f3d3620ef64369ad42 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Tue, 10 Mar 2020 10:59:21 +0100 Subject: [PATCH 21/33] [poincare/parser] log_ is not a special identifier anymore The change was made a few commits ago, but this was forgotten --- poincare/src/parsing/parser.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/poincare/src/parsing/parser.cpp b/poincare/src/parsing/parser.cpp index 2475a7583..a015c7104 100644 --- a/poincare/src/parsing/parser.cpp +++ b/poincare/src/parsing/parser.cpp @@ -51,8 +51,7 @@ bool Parser::IsSpecialIdentifierName(const char * name, size_t nameLength) { Token::CompareNonNullTerminatedName(name, nameLength, "w_") == 0 || Token::CompareNonNullTerminatedName(name, nameLength, "u") == 0 || Token::CompareNonNullTerminatedName(name, nameLength, "v") == 0 || - Token::CompareNonNullTerminatedName(name, nameLength, "w") == 0 || - Token::CompareNonNullTerminatedName(name, nameLength, "log_") == 0 + Token::CompareNonNullTerminatedName(name, nameLength, "w") == 0 ); } From ef249b0bdbd9e7e218e2e41afd0cd36d6c06af19 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Tue, 10 Mar 2020 11:10:49 +0100 Subject: [PATCH 22/33] [poincare/parser] parseSpecialId must go through one of the subcases Otherwise we might go through the method without creating leftHandSide --- poincare/src/parsing/parser.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/poincare/src/parsing/parser.cpp b/poincare/src/parsing/parser.cpp index a015c7104..5329e8141 100644 --- a/poincare/src/parsing/parser.cpp +++ b/poincare/src/parsing/parser.cpp @@ -444,10 +444,10 @@ void Parser::parseSpecialIdentifier(Expression & leftHandSide) { leftHandSide = Undefined::Builder(); } else if (m_currentToken.compareTo(Unreal::Name()) == 0) { leftHandSide = Unreal::Builder(); - } else if (m_currentToken.compareTo("u") == 0 - || m_currentToken.compareTo("v") == 0 - || m_currentToken.compareTo("w") == 0) - { + } else { + assert(m_currentToken.compareTo("u") == 0 + || m_currentToken.compareTo("v") == 0 + || m_currentToken.compareTo("w") == 0); /* Special case for sequences (e.g. "u(n)", "u{n}", ...) * We know that m_currentToken.text()[0] is either 'u', 'v' or 'w', so we do * not need to pass a code point to parseSequence. */ From 2bf83c43a84c8f7624e34bb62b44ccc568e13a46 Mon Sep 17 00:00:00 2001 From: Romain Goyet Date: Tue, 10 Mar 2020 18:29:01 -0400 Subject: [PATCH 23/33] [apps/shared] Factorize CurveView::label There was a lot of code duplication. I removed the initialization of xLabel{} and yLabels{} because those are scratch buffers that shouldn't be accessed before being written to anyway. --- .../additional_outputs/complex_graph_cell.cpp | 2 +- .../additional_outputs/complex_graph_cell.h | 9 +---- .../trigonometry_graph_cell.h | 1 - apps/regression/graph_view.cpp | 15 +------- apps/regression/graph_view.h | 7 +--- apps/shared/Makefile | 1 + apps/shared/curve_view.h | 2 +- apps/shared/function_graph_view.cpp | 8 +--- apps/shared/function_graph_view.h | 7 +--- apps/shared/labeled_curve_view.cpp | 31 ++++++++++++++++ apps/shared/labeled_curve_view.h | 37 +++++++++++++++++++ apps/statistics/box_axis_view.cpp | 4 -- apps/statistics/box_axis_view.h | 9 ++--- apps/statistics/box_view.h | 1 - apps/statistics/histogram_view.cpp | 7 +--- apps/statistics/histogram_view.h | 5 +-- 16 files changed, 86 insertions(+), 60 deletions(-) create mode 100644 apps/shared/labeled_curve_view.cpp create mode 100644 apps/shared/labeled_curve_view.h diff --git a/apps/calculation/additional_outputs/complex_graph_cell.cpp b/apps/calculation/additional_outputs/complex_graph_cell.cpp index aabe9b630..e4249e8f2 100644 --- a/apps/calculation/additional_outputs/complex_graph_cell.cpp +++ b/apps/calculation/additional_outputs/complex_graph_cell.cpp @@ -6,7 +6,7 @@ using namespace Poincare; namespace Calculation { ComplexGraphView::ComplexGraphView(ComplexModel * complexModel) : - CurveView(complexModel), + LabeledCurveView(complexModel), m_complex(complexModel) { } diff --git a/apps/calculation/additional_outputs/complex_graph_cell.h b/apps/calculation/additional_outputs/complex_graph_cell.h index bf440202f..7777c9991 100644 --- a/apps/calculation/additional_outputs/complex_graph_cell.h +++ b/apps/calculation/additional_outputs/complex_graph_cell.h @@ -1,24 +1,19 @@ #ifndef CALCULATION_ADDITIONAL_OUTPUTS_COMPLEX_GRAPH_CELL_H #define CALCULATION_ADDITIONAL_OUTPUTS_COMPLEX_GRAPH_CELL_H -#include "../../shared/curve_view.h" +#include "../../shared/labeled_curve_view.h" #include "complex_model.h" #include "illustration_cell.h" namespace Calculation { -class ComplexGraphView : public Shared::CurveView { +class ComplexGraphView : public Shared::LabeledCurveView { public: ComplexGraphView(ComplexModel * complexModel); void drawRect(KDContext * ctx, KDRect rect) const override; private: - char * label(Axis axis, int index) const override { - return (axis == Axis::Horizontal ? (char *)m_xLabels[index] : (char *)m_yLabels[index]); - } // '-' + significant digits + ".E-" + 2 digits (the represented dot is a float, so it is bounded by 1E38 and 1E-38 size_t labelMaxGlyphLengthSize() const override { return 1 + Poincare::Preferences::VeryShortNumberOfSignificantDigits + 3 + 2; } - char m_xLabels[k_maxNumberOfXLabels][k_labelBufferMaxSize]; - char m_yLabels[k_maxNumberOfYLabels][k_labelBufferMaxSize]; ComplexModel * m_complex; }; diff --git a/apps/calculation/additional_outputs/trigonometry_graph_cell.h b/apps/calculation/additional_outputs/trigonometry_graph_cell.h index 1bf126707..aea81926a 100644 --- a/apps/calculation/additional_outputs/trigonometry_graph_cell.h +++ b/apps/calculation/additional_outputs/trigonometry_graph_cell.h @@ -12,7 +12,6 @@ public: TrigonometryGraphView(TrigonometryModel * model); void drawRect(KDContext * ctx, KDRect rect) const override; private: - char * label(Axis axis, int index) const override { return nullptr; } TrigonometryModel * m_model; }; diff --git a/apps/regression/graph_view.cpp b/apps/regression/graph_view.cpp index afdbdab0c..3b7b1371a 100644 --- a/apps/regression/graph_view.cpp +++ b/apps/regression/graph_view.cpp @@ -9,10 +9,8 @@ using namespace Shared; namespace Regression { GraphView::GraphView(Store * store, CurveViewCursor * cursor, BannerView * bannerView, Shared::CursorView * cursorView) : - CurveView(store, cursor, bannerView, cursorView), - m_store(store), - m_xLabels{}, - m_yLabels{} + LabeledCurveView(store, cursor, bannerView, cursorView), + m_store(store) { } @@ -41,13 +39,4 @@ void GraphView::drawRect(KDContext * ctx, KDRect rect) const { } } -char * GraphView::label(Axis axis, int index) const { - if (axis == Axis::Vertical) { - assert(index < k_maxNumberOfXLabels); - return (char *)m_yLabels[index]; - } - assert(index < k_maxNumberOfYLabels); - return (char *)m_xLabels[index]; -} - } diff --git a/apps/regression/graph_view.h b/apps/regression/graph_view.h index 17269ad1c..22db0b635 100644 --- a/apps/regression/graph_view.h +++ b/apps/regression/graph_view.h @@ -3,19 +3,16 @@ #include "store.h" #include "../constant.h" -#include "../shared/curve_view.h" +#include "../shared/labeled_curve_view.h" namespace Regression { -class GraphView : public Shared::CurveView { +class GraphView : public Shared::LabeledCurveView { public: GraphView(Store * store, Shared::CurveViewCursor * cursor, Shared::BannerView * bannerView, Shared::CursorView * cursorView); void drawRect(KDContext * ctx, KDRect rect) const override; private: - char * label(Axis axis, int index) const override; Store * m_store; - char m_xLabels[k_maxNumberOfXLabels][k_labelBufferMaxSize]; - char m_yLabels[k_maxNumberOfYLabels][k_labelBufferMaxSize]; }; } diff --git a/apps/shared/Makefile b/apps/shared/Makefile index e97b68ed0..98e4a8fe6 100644 --- a/apps/shared/Makefile +++ b/apps/shared/Makefile @@ -45,6 +45,7 @@ app_shared_src = $(addprefix apps/shared/,\ interactive_curve_view_controller.cpp \ interval.cpp \ interval_parameter_controller.cpp \ + labeled_curve_view.cpp \ language_controller.cpp \ layout_field_delegate.cpp \ list_parameter_controller.cpp \ diff --git a/apps/shared/curve_view.h b/apps/shared/curve_view.h index 2512ec432..99d4ddd07 100644 --- a/apps/shared/curve_view.h +++ b/apps/shared/curve_view.h @@ -100,7 +100,7 @@ private: float min(Axis axis) const; float max(Axis axis) const; float gridUnit(Axis axis) const; - virtual char * label(Axis axis, int index) const = 0; + virtual char * label(Axis axis, int index) const { return nullptr; } virtual size_t labelMaxGlyphLengthSize() const { return k_labelBufferMaxGlyphLength; } int numberOfLabels(Axis axis) const; /* Recursively join two dots (dichotomy). The method stops when the diff --git a/apps/shared/function_graph_view.cpp b/apps/shared/function_graph_view.cpp index ee8cd73fc..587a49fcb 100644 --- a/apps/shared/function_graph_view.cpp +++ b/apps/shared/function_graph_view.cpp @@ -8,13 +8,11 @@ namespace Shared { FunctionGraphView::FunctionGraphView(InteractiveCurveViewRange * graphRange, CurveViewCursor * cursor, BannerView * bannerView, CursorView * cursorView) : - CurveView(graphRange, cursor, bannerView, cursorView), + LabeledCurveView(graphRange, cursor, bannerView, cursorView), m_selectedRecord(), m_highlightedStart(NAN), m_highlightedEnd(NAN), m_shouldColorHighlighted(false), - m_xLabels{}, - m_yLabels{}, m_context(nullptr) { } @@ -67,10 +65,6 @@ void FunctionGraphView::setAreaHighlightColor(bool highlightColor) { } } -char * FunctionGraphView::label(Axis axis, int index) const { - return (axis == Axis::Horizontal ? (char *)m_xLabels[index] : (char *)m_yLabels[index]); -} - void FunctionGraphView::reloadBetweenBounds(float start, float end) { if (start == end) { return; diff --git a/apps/shared/function_graph_view.h b/apps/shared/function_graph_view.h index 0ec2f11cf..4e3f0a55a 100644 --- a/apps/shared/function_graph_view.h +++ b/apps/shared/function_graph_view.h @@ -2,14 +2,14 @@ #define SHARED_FUNCTION_GRAPH_VIEW_H #include -#include "curve_view.h" +#include "labeled_curve_view.h" #include "function.h" #include "../constant.h" #include "interactive_curve_view_range.h" namespace Shared { -class FunctionGraphView : public CurveView { +class FunctionGraphView : public LabeledCurveView { public: FunctionGraphView(InteractiveCurveViewRange * graphRange, CurveViewCursor * cursor, BannerView * bannerView, CursorView * cursorView); @@ -26,9 +26,6 @@ protected: float m_highlightedEnd; bool m_shouldColorHighlighted; private: - char * label(Axis axis, int index) const override; - char m_xLabels[k_maxNumberOfXLabels][k_labelBufferMaxSize]; - char m_yLabels[k_maxNumberOfYLabels][k_labelBufferMaxSize]; Poincare::Context * m_context; }; diff --git a/apps/shared/labeled_curve_view.cpp b/apps/shared/labeled_curve_view.cpp new file mode 100644 index 000000000..2a10c6655 --- /dev/null +++ b/apps/shared/labeled_curve_view.cpp @@ -0,0 +1,31 @@ +#include "labeled_curve_view.h" + +namespace Shared { + +char * HorizontallyLabeledCurveView::label(Axis axis, int index) const { + if (axis == Axis::Horizontal) { + assert(index < k_maxNumberOfXLabels); + return m_xLabels[index]; + } + return nullptr; +} + +char * VerticallyLabeledCurveView::label(Axis axis, int index) const { + if (axis == Axis::Vertical) { + assert(index < k_maxNumberOfYLabels); + return m_yLabels[index]; + } + return nullptr; +} + +char * LabeledCurveView::label(Axis axis, int index) const { + if (axis == Axis::Horizontal) { + assert(index < k_maxNumberOfXLabels); + return m_xLabels[index]; + } else { + assert(index < k_maxNumberOfYLabels); + return m_yLabels[index]; + } +} + +} diff --git a/apps/shared/labeled_curve_view.h b/apps/shared/labeled_curve_view.h new file mode 100644 index 000000000..cc094702b --- /dev/null +++ b/apps/shared/labeled_curve_view.h @@ -0,0 +1,37 @@ +#ifndef SHARED_LABELED_CURVE_VIEW_H +#define SHARED_LABELED_CURVE_VIEW_H + +#include "curve_view.h" + +/* This CurveView subclass provides label storage for common use cases */ + +namespace Shared { + +class HorizontallyLabeledCurveView : public CurveView { +public: + using CurveView::CurveView; +private: + char * label(Axis axis, int index) const override; + mutable char m_xLabels[k_maxNumberOfXLabels][k_labelBufferMaxSize]; +}; + +class VerticallyLabeledCurveView : public CurveView { +public: + using CurveView::CurveView; +private: + char * label(Axis axis, int index) const override; + mutable char m_yLabels[k_maxNumberOfYLabels][k_labelBufferMaxSize]; +}; + +class LabeledCurveView : public CurveView { +public: + using CurveView::CurveView; +private: + char * label(Axis axis, int index) const override; + mutable char m_xLabels[k_maxNumberOfXLabels][k_labelBufferMaxSize]; + mutable char m_yLabels[k_maxNumberOfYLabels][k_labelBufferMaxSize]; +}; + +} + +#endif diff --git a/apps/statistics/box_axis_view.cpp b/apps/statistics/box_axis_view.cpp index 61ecfd092..3d898c738 100644 --- a/apps/statistics/box_axis_view.cpp +++ b/apps/statistics/box_axis_view.cpp @@ -12,8 +12,4 @@ void BoxAxisView::drawRect(KDContext * ctx, KDRect rect) const { drawLabelsAndGraduations(ctx, rect, Axis::Horizontal, false, false, true, k_axisMargin); } -char * BoxAxisView::label(Axis axis, int index) const { - return axis == Axis::Vertical ? nullptr : (char *)m_labels[index]; -} - } diff --git a/apps/statistics/box_axis_view.h b/apps/statistics/box_axis_view.h index 2fbfe0df8..b3caef60d 100644 --- a/apps/statistics/box_axis_view.h +++ b/apps/statistics/box_axis_view.h @@ -3,24 +3,21 @@ #include "box_range.h" #include "store.h" -#include "../shared/curve_view.h" +#include "../shared/labeled_curve_view.h" #include "../constant.h" #include namespace Statistics { -class BoxAxisView : public Shared::CurveView { +class BoxAxisView : public Shared::HorizontallyLabeledCurveView { public: BoxAxisView(Store * store) : - CurveView(&m_boxRange), - m_labels{}, + HorizontallyLabeledCurveView(&m_boxRange), m_boxRange(BoxRange(store)) {} void drawRect(KDContext * ctx, KDRect rect) const override; private: constexpr static KDCoordinate k_axisMargin = 3; - char * label(Axis axis, int index) const override; - char m_labels[k_maxNumberOfXLabels][k_labelBufferMaxSize]; BoxRange m_boxRange; }; diff --git a/apps/statistics/box_view.h b/apps/statistics/box_view.h index 6ce1a9275..b95cbbc29 100644 --- a/apps/statistics/box_view.h +++ b/apps/statistics/box_view.h @@ -37,7 +37,6 @@ private: static constexpr KDCoordinate k_quantileBarWidth = 2; KDCoordinate boxLowerBoundPixel() const; KDCoordinate boxUpperBoundPixel() const; - char * label(Axis axis, int index) const override { return nullptr; } Store * m_store; BoxRange m_boxRange; int m_series; diff --git a/apps/statistics/histogram_view.cpp b/apps/statistics/histogram_view.cpp index 5f0caa14d..9b1d028f4 100644 --- a/apps/statistics/histogram_view.cpp +++ b/apps/statistics/histogram_view.cpp @@ -8,10 +8,9 @@ using namespace Shared; namespace Statistics { HistogramView::HistogramView(HistogramController * controller, Store * store, int series, Shared::BannerView * bannerView, KDColor selectedHistogramColor, KDColor notSelectedHistogramColor, KDColor selectedBarColor) : - CurveView(store, nullptr, bannerView, nullptr), + HorizontallyLabeledCurveView(store, nullptr, bannerView, nullptr), m_controller(controller), m_store(store), - m_labels{}, m_highlightedBarStart(NAN), m_highlightedBarEnd(NAN), m_series(series), @@ -63,10 +62,6 @@ void HistogramView::setHighlight(float start, float end) { } } -char * HistogramView::label(Axis axis, int index) const { - return axis == Axis::Vertical ? nullptr : (char *)m_labels[index]; -} - float HistogramView::EvaluateHistogramAtAbscissa(float abscissa, void * model, void * context) { Store * store = (Store *)model; float totalSize = ((float *)context)[0]; diff --git a/apps/statistics/histogram_view.h b/apps/statistics/histogram_view.h index 32117ffde..c6859097c 100644 --- a/apps/statistics/histogram_view.h +++ b/apps/statistics/histogram_view.h @@ -5,13 +5,13 @@ #include #include "store.h" #include "../constant.h" -#include "../shared/curve_view.h" +#include "../shared/labeled_curve_view.h" namespace Statistics { class HistogramController; -class HistogramView : public Shared::CurveView { +class HistogramView : public Shared::HorizontallyLabeledCurveView { public: HistogramView(HistogramController * controller, Store * store, int series, Shared::BannerView * bannerView, KDColor selectedHistogramColor = Palette::Select, KDColor notSelectedHistogramColor = Palette::GreyMiddle, KDColor selectedBarColor = Palette::YellowDark); int series() const { return m_series; } @@ -21,7 +21,6 @@ public: void setHighlight(float start, float end); void setDisplayLabels(bool display) { m_displayLabels = display; } private: - char * label(Axis axis, int index) const override; HistogramController * m_controller; Store * m_store; char m_labels[k_maxNumberOfXLabels][k_labelBufferMaxSize]; From aab89749349a74a0e066972db93f3fe1b3599586 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Wed, 4 Mar 2020 13:23:29 +0100 Subject: [PATCH 24/33] [apps] Memoize five model checksums --- apps/graph/app.cpp | 2 +- apps/graph/graph/graph_controller.cpp | 4 ++-- apps/graph/graph/graph_controller.h | 2 +- apps/regression/app.cpp | 4 +++- apps/regression/app.h | 3 +++ apps/regression/graph_controller.cpp | 4 ++-- apps/regression/graph_controller.h | 2 +- apps/sequence/app.cpp | 2 +- apps/sequence/graph/graph_controller.cpp | 4 ++-- apps/sequence/graph/graph_controller.h | 2 +- apps/shared/function_app.cpp | 2 ++ apps/shared/function_app.h | 3 +++ apps/shared/function_graph_controller.cpp | 4 ++-- apps/shared/function_graph_controller.h | 2 +- apps/shared/interactive_curve_view_controller.cpp | 3 ++- apps/shared/interactive_curve_view_controller.h | 3 ++- 16 files changed, 29 insertions(+), 17 deletions(-) diff --git a/apps/graph/app.cpp b/apps/graph/app.cpp index 510b133f5..227aa1c0e 100644 --- a/apps/graph/app.cpp +++ b/apps/graph/app.cpp @@ -54,7 +54,7 @@ App::App(Snapshot * snapshot) : m_listFooter(&m_listHeader, &m_listController, &m_listController, ButtonRowController::Position::Bottom, ButtonRowController::Style::EmbossedGrey), m_listHeader(&m_listStackViewController, &m_listFooter, &m_listController), m_listStackViewController(&m_tabViewController, &m_listHeader), - m_graphController(&m_graphAlternateEmptyViewController, this, snapshot->graphRange(), snapshot->cursor(), snapshot->indexFunctionSelectedByCursor(), snapshot->modelVersion(), snapshot->rangeVersion(), snapshot->angleUnitVersion(), &m_graphHeader), + m_graphController(&m_graphAlternateEmptyViewController, this, snapshot->graphRange(), snapshot->cursor(), snapshot->indexFunctionSelectedByCursor(), snapshot->modelVersion(), snapshot->previousModelsVersions(), snapshot->rangeVersion(), snapshot->angleUnitVersion(), &m_graphHeader), m_graphAlternateEmptyViewController(&m_graphHeader, &m_graphController, &m_graphController), m_graphHeader(&m_graphStackViewController, &m_graphAlternateEmptyViewController, &m_graphController), m_graphStackViewController(&m_tabViewController, &m_graphHeader), diff --git a/apps/graph/graph/graph_controller.cpp b/apps/graph/graph/graph_controller.cpp index 9f45f3eff..74cc400dc 100644 --- a/apps/graph/graph/graph_controller.cpp +++ b/apps/graph/graph/graph_controller.cpp @@ -11,8 +11,8 @@ static inline float maxFloat(float x, float y) { return x > y ? x : y; } 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; } -GraphController::GraphController(Responder * parentResponder, ::InputEventHandlerDelegate * inputEventHandlerDelegate, Shared::InteractiveCurveViewRange * curveViewRange, CurveViewCursor * cursor, int * indexFunctionSelectedByCursor, uint32_t * modelVersion, uint32_t * rangeVersion, Poincare::Preferences::AngleUnit * angleUnitVersion, ButtonRowController * header) : - FunctionGraphController(parentResponder, inputEventHandlerDelegate, header, curveViewRange, &m_view, cursor, indexFunctionSelectedByCursor, modelVersion, rangeVersion, angleUnitVersion), +GraphController::GraphController(Responder * parentResponder, ::InputEventHandlerDelegate * inputEventHandlerDelegate, Shared::InteractiveCurveViewRange * curveViewRange, CurveViewCursor * cursor, int * indexFunctionSelectedByCursor, uint32_t * modelVersion, uint32_t * previousModelsVersions, uint32_t * rangeVersion, Poincare::Preferences::AngleUnit * angleUnitVersion, ButtonRowController * header) : + FunctionGraphController(parentResponder, inputEventHandlerDelegate, header, curveViewRange, &m_view, cursor, indexFunctionSelectedByCursor, modelVersion, previousModelsVersions, rangeVersion, angleUnitVersion), m_bannerView(this, inputEventHandlerDelegate, this), m_view(curveViewRange, m_cursor, &m_bannerView, &m_cursorView), m_graphRange(curveViewRange), diff --git a/apps/graph/graph/graph_controller.h b/apps/graph/graph/graph_controller.h index 8860dd245..84240fcd3 100644 --- a/apps/graph/graph/graph_controller.h +++ b/apps/graph/graph/graph_controller.h @@ -15,7 +15,7 @@ namespace Graph { class GraphController : public Shared::FunctionGraphController, public GraphControllerHelper { public: - GraphController(Responder * parentResponder, ::InputEventHandlerDelegate * inputEventHandlerDelegate, Shared::InteractiveCurveViewRange * curveViewRange, Shared::CurveViewCursor * cursor, int * indexFunctionSelectedByCursor, uint32_t * modelVersion, uint32_t * rangeVersion, Poincare::Preferences::AngleUnit * angleUnitVersion, ButtonRowController * header); + GraphController(Responder * parentResponder, ::InputEventHandlerDelegate * inputEventHandlerDelegate, Shared::InteractiveCurveViewRange * curveViewRange, Shared::CurveViewCursor * cursor, int * indexFunctionSelectedByCursor, uint32_t * modelVersion, uint32_t * previousModelsVersions, uint32_t * rangeVersion, Poincare::Preferences::AngleUnit * angleUnitVersion, ButtonRowController * header); I18n::Message emptyMessage() override; void viewWillAppear() override; bool displayDerivativeInBanner() const { return m_displayDerivativeInBanner; } diff --git a/apps/regression/app.cpp b/apps/regression/app.cpp index 26058d22b..bfe05df33 100644 --- a/apps/regression/app.cpp +++ b/apps/regression/app.cpp @@ -27,6 +27,7 @@ App::Snapshot::Snapshot() : m_rangeVersion(0), m_selectedSeriesIndex(-1) { + assert(m_previousModelsVersions[0] == 0); } App * App::Snapshot::unpack(Container * container) { @@ -36,6 +37,7 @@ App * App::Snapshot::unpack(Container * container) { void App::Snapshot::reset() { m_store.deleteAllPairs(); m_modelVersion = 0; + memset(m_previousModelsVersions, 0, sizeof(m_previousModelsVersions[0])*sNumberOfMemoizedModelVersions); m_rangeVersion = 0; setActiveTab(0); } @@ -55,7 +57,7 @@ App::App(Snapshot * snapshot, Poincare::Context * parentContext) : m_calculationController(&m_calculationAlternateEmptyViewController, &m_calculationHeader, snapshot->store()), m_calculationAlternateEmptyViewController(&m_calculationHeader, &m_calculationController, &m_calculationController), m_calculationHeader(&m_tabViewController, &m_calculationAlternateEmptyViewController, &m_calculationController), - m_graphController(&m_graphAlternateEmptyViewController, this, &m_graphHeader, snapshot->store(), snapshot->cursor(), snapshot->modelVersion(), snapshot->rangeVersion(), snapshot->graphSelectedDotIndex(), snapshot->selectedSeriesIndex()), + m_graphController(&m_graphAlternateEmptyViewController, this, &m_graphHeader, snapshot->store(), snapshot->cursor(), snapshot->modelVersion(), snapshot->previousModelsVersions(), snapshot->rangeVersion(), snapshot->graphSelectedDotIndex(), snapshot->selectedSeriesIndex()), m_graphAlternateEmptyViewController(&m_graphHeader, &m_graphController, &m_graphController), m_graphHeader(&m_graphStackViewController, &m_graphAlternateEmptyViewController, &m_graphController), m_graphStackViewController(&m_tabViewController, &m_graphHeader), diff --git a/apps/regression/app.h b/apps/regression/app.h index 698479abb..460e63f3a 100644 --- a/apps/regression/app.h +++ b/apps/regression/app.h @@ -21,6 +21,7 @@ public: }; class Snapshot : public ::App::Snapshot, public TabViewDataSource { public: + static constexpr size_t sNumberOfMemoizedModelVersions = 5; // TODO LEA factorize with Shared::FunctionApp Snapshot(); App * unpack(Container * container) override; void reset() override; @@ -30,6 +31,7 @@ public: int * graphSelectedDotIndex() { return &m_graphSelectedDotIndex; } int * selectedSeriesIndex() { return &m_selectedSeriesIndex; } uint32_t * modelVersion() { return &m_modelVersion; } + uint32_t * previousModelsVersions() { return m_previousModelsVersions; } uint32_t * rangeVersion() { return &m_rangeVersion; } private: void tidy() override; @@ -37,6 +39,7 @@ public: Shared::CurveViewCursor m_cursor; int m_graphSelectedDotIndex; uint32_t m_modelVersion; + uint32_t m_previousModelsVersions[sNumberOfMemoizedModelVersions]; uint32_t m_rangeVersion; int m_selectedSeriesIndex; }; diff --git a/apps/regression/graph_controller.cpp b/apps/regression/graph_controller.cpp index b59809bca..973c90734 100644 --- a/apps/regression/graph_controller.cpp +++ b/apps/regression/graph_controller.cpp @@ -14,8 +14,8 @@ static inline int maxInt(int x, int y) { return x > y ? x : y; } namespace Regression { -GraphController::GraphController(Responder * parentResponder, InputEventHandlerDelegate * inputEventHandlerDelegate, ButtonRowController * header, Store * store, CurveViewCursor * cursor, uint32_t * modelVersion, uint32_t * rangeVersion, int * selectedDotIndex, int * selectedSeriesIndex) : - InteractiveCurveViewController(parentResponder, inputEventHandlerDelegate, header, store, &m_view, cursor, modelVersion, rangeVersion), +GraphController::GraphController(Responder * parentResponder, InputEventHandlerDelegate * inputEventHandlerDelegate, ButtonRowController * header, Store * store, CurveViewCursor * cursor, uint32_t * modelVersion, uint32_t * previousModelsVersions, uint32_t * rangeVersion, int * selectedDotIndex, int * selectedSeriesIndex) : + InteractiveCurveViewController(parentResponder, inputEventHandlerDelegate, header, store, &m_view, cursor, modelVersion, previousModelsVersions, rangeVersion), m_crossCursorView(), m_roundCursorView(), m_bannerView(this, inputEventHandlerDelegate, this), diff --git a/apps/regression/graph_controller.h b/apps/regression/graph_controller.h index f1c257a12..6926854c5 100644 --- a/apps/regression/graph_controller.h +++ b/apps/regression/graph_controller.h @@ -16,7 +16,7 @@ namespace Regression { class GraphController : public Shared::InteractiveCurveViewController { public: - GraphController(Responder * parentResponder, InputEventHandlerDelegate * inputEventHandlerDelegate, ButtonRowController * header, Store * store, Shared::CurveViewCursor * cursor, uint32_t * modelVersion, uint32_t * rangeVersion, int * selectedDotIndex, int * selectedSeriesIndex); + GraphController(Responder * parentResponder, InputEventHandlerDelegate * inputEventHandlerDelegate, ButtonRowController * header, Store * store, Shared::CurveViewCursor * cursor, uint32_t * modelVersion, uint32_t * previousModelsVersions, uint32_t * rangeVersion, int * selectedDotIndex, int * selectedSeriesIndex); ViewController * initialisationParameterController() override; bool isEmpty() const override; I18n::Message emptyMessage() override; diff --git a/apps/sequence/app.cpp b/apps/sequence/app.cpp index 40b27f0fb..505f0c9fe 100644 --- a/apps/sequence/app.cpp +++ b/apps/sequence/app.cpp @@ -51,7 +51,7 @@ App::App(Snapshot * snapshot) : m_listFooter(&m_listHeader, &m_listController, &m_listController, ButtonRowController::Position::Bottom, ButtonRowController::Style::EmbossedGrey), m_listHeader(nullptr, &m_listFooter, &m_listController), m_listStackViewController(&m_tabViewController, &m_listHeader), - m_graphController(&m_graphAlternateEmptyViewController, this, snapshot->functionStore(), snapshot->graphRange(), snapshot->cursor(), snapshot->indexFunctionSelectedByCursor(), snapshot->modelVersion(), snapshot->rangeVersion(), snapshot->angleUnitVersion(), &m_graphHeader), + m_graphController(&m_graphAlternateEmptyViewController, this, snapshot->functionStore(), snapshot->graphRange(), snapshot->cursor(), snapshot->indexFunctionSelectedByCursor(), snapshot->modelVersion(), snapshot->previousModelsVersions(), snapshot->rangeVersion(), snapshot->angleUnitVersion(), &m_graphHeader), m_graphAlternateEmptyViewController(&m_graphHeader, &m_graphController, &m_graphController), m_graphHeader(&m_graphStackViewController, &m_graphAlternateEmptyViewController, &m_graphController), m_graphStackViewController(&m_tabViewController, &m_graphHeader), diff --git a/apps/sequence/graph/graph_controller.cpp b/apps/sequence/graph/graph_controller.cpp index c2c4b8fea..8e14c64c8 100644 --- a/apps/sequence/graph/graph_controller.cpp +++ b/apps/sequence/graph/graph_controller.cpp @@ -11,8 +11,8 @@ namespace Sequence { static inline int minInt(int x, int y) { return (x < y ? x : y); } static inline int maxInt(int x, int y) { return (x > y ? x : y); } -GraphController::GraphController(Responder * parentResponder, ::InputEventHandlerDelegate * inputEventHandlerDelegate, SequenceStore * sequenceStore, CurveViewRange * graphRange, CurveViewCursor * cursor, int * indexFunctionSelectedByCursor, uint32_t * modelVersion, uint32_t * rangeVersion, Preferences::AngleUnit * angleUnitVersion, ButtonRowController * header) : - FunctionGraphController(parentResponder, inputEventHandlerDelegate, header, graphRange, &m_view, cursor, indexFunctionSelectedByCursor, modelVersion, rangeVersion, angleUnitVersion), +GraphController::GraphController(Responder * parentResponder, ::InputEventHandlerDelegate * inputEventHandlerDelegate, SequenceStore * sequenceStore, CurveViewRange * graphRange, CurveViewCursor * cursor, int * indexFunctionSelectedByCursor, uint32_t * modelVersion, uint32_t * previousModelsVersions, uint32_t * rangeVersion, Preferences::AngleUnit * angleUnitVersion, ButtonRowController * header) : + FunctionGraphController(parentResponder, inputEventHandlerDelegate, header, graphRange, &m_view, cursor, indexFunctionSelectedByCursor, modelVersion, previousModelsVersions, rangeVersion, angleUnitVersion), m_bannerView(this, inputEventHandlerDelegate, this), m_view(sequenceStore, graphRange, m_cursor, &m_bannerView, &m_cursorView), m_graphRange(graphRange), diff --git a/apps/sequence/graph/graph_controller.h b/apps/sequence/graph/graph_controller.h index da0e64006..2177bc230 100644 --- a/apps/sequence/graph/graph_controller.h +++ b/apps/sequence/graph/graph_controller.h @@ -14,7 +14,7 @@ namespace Sequence { class GraphController final : public Shared::FunctionGraphController { public: - GraphController(Responder * parentResponder, ::InputEventHandlerDelegate * inputEventHandlerDelegate, SequenceStore * sequenceStore, CurveViewRange * graphRange, Shared::CurveViewCursor * cursor, int * indexFunctionSelectedByCursor, uint32_t * modelVersion, uint32_t * rangeVersion, Poincare::Preferences::AngleUnit * angleUnitVersion, ButtonRowController * header); + GraphController(Responder * parentResponder, ::InputEventHandlerDelegate * inputEventHandlerDelegate, SequenceStore * sequenceStore, CurveViewRange * graphRange, Shared::CurveViewCursor * cursor, int * indexFunctionSelectedByCursor, uint32_t * modelVersion, uint32_t * previousModelsVersions, uint32_t * rangeVersion, Poincare::Preferences::AngleUnit * angleUnitVersion, ButtonRowController * header); I18n::Message emptyMessage() override; void viewWillAppear() override; TermSumController * termSumController() { return &m_termSumController; } diff --git a/apps/shared/function_app.cpp b/apps/shared/function_app.cpp index 7cede0ee8..3861d0b3e 100644 --- a/apps/shared/function_app.cpp +++ b/apps/shared/function_app.cpp @@ -11,11 +11,13 @@ FunctionApp::Snapshot::Snapshot() : m_rangeVersion(0), m_angleUnitVersion(Preferences::AngleUnit::Radian) { + assert(m_previousModelsVersions[0] == 0); } void FunctionApp::Snapshot::reset() { m_indexFunctionSelectedByCursor = 0; m_modelVersion = 0; + memset(m_previousModelsVersions, 0, sizeof(m_previousModelsVersions[0])*sNumberOfMemoizedModelVersions); m_rangeVersion = 0; setActiveTab(0); } diff --git a/apps/shared/function_app.h b/apps/shared/function_app.h index ffec00c31..9fc842d8d 100644 --- a/apps/shared/function_app.h +++ b/apps/shared/function_app.h @@ -12,9 +12,11 @@ class FunctionApp : public ExpressionFieldDelegateApp { public: class Snapshot : public ::App::Snapshot, public TabViewDataSource { public: + static constexpr size_t sNumberOfMemoizedModelVersions = 5; Snapshot(); CurveViewCursor * cursor() { return &m_cursor; } uint32_t * modelVersion() { return &m_modelVersion; } + uint32_t * previousModelsVersions() { return m_previousModelsVersions; } uint32_t * rangeVersion() { return &m_rangeVersion; } Poincare::Preferences::AngleUnit * angleUnitVersion() { return &m_angleUnitVersion; } virtual FunctionStore * functionStore() = 0; @@ -26,6 +28,7 @@ public: private: int m_indexFunctionSelectedByCursor; uint32_t m_modelVersion; + uint32_t m_previousModelsVersions[sNumberOfMemoizedModelVersions]; uint32_t m_rangeVersion; Poincare::Preferences::AngleUnit m_angleUnitVersion; }; diff --git a/apps/shared/function_graph_controller.cpp b/apps/shared/function_graph_controller.cpp index cf70f677d..0f2b57d7f 100644 --- a/apps/shared/function_graph_controller.cpp +++ b/apps/shared/function_graph_controller.cpp @@ -15,8 +15,8 @@ static inline float maxFloat(float x, float y) { return x > y ? x : y; } 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; } -FunctionGraphController::FunctionGraphController(Responder * parentResponder, InputEventHandlerDelegate * inputEventHandlerDelegate, ButtonRowController * header, InteractiveCurveViewRange * interactiveRange, CurveView * curveView, CurveViewCursor * cursor, int * indexFunctionSelectedByCursor, uint32_t * modelVersion, uint32_t * rangeVersion, Preferences::AngleUnit * angleUnitVersion) : - InteractiveCurveViewController(parentResponder, inputEventHandlerDelegate, header, interactiveRange, curveView, cursor, modelVersion, rangeVersion), +FunctionGraphController::FunctionGraphController(Responder * parentResponder, InputEventHandlerDelegate * inputEventHandlerDelegate, ButtonRowController * header, InteractiveCurveViewRange * interactiveRange, CurveView * curveView, CurveViewCursor * cursor, int * indexFunctionSelectedByCursor, uint32_t * modelVersion, uint32_t * previousModelsVersions, uint32_t * rangeVersion, Preferences::AngleUnit * angleUnitVersion) : + InteractiveCurveViewController(parentResponder, inputEventHandlerDelegate, header, interactiveRange, curveView, cursor, modelVersion, previousModelsVersions, rangeVersion), m_initialisationParameterController(this, interactiveRange), m_angleUnitVersion(angleUnitVersion), m_indexFunctionSelectedByCursor(indexFunctionSelectedByCursor) diff --git a/apps/shared/function_graph_controller.h b/apps/shared/function_graph_controller.h index e111c4234..af3d0dd61 100644 --- a/apps/shared/function_graph_controller.h +++ b/apps/shared/function_graph_controller.h @@ -13,7 +13,7 @@ namespace Shared { class FunctionGraphController : public InteractiveCurveViewController, public FunctionBannerDelegate { public: - FunctionGraphController(Responder * parentResponder, InputEventHandlerDelegate * inputEventHandlerDelegate, ButtonRowController * header, InteractiveCurveViewRange * interactiveRange, CurveView * curveView, CurveViewCursor * cursor, int * indexFunctionSelectedByCursor, uint32_t * modelVersion, uint32_t * rangeVersion, Poincare::Preferences::AngleUnit * angleUnitVersion); + FunctionGraphController(Responder * parentResponder, InputEventHandlerDelegate * inputEventHandlerDelegate, ButtonRowController * header, InteractiveCurveViewRange * interactiveRange, CurveView * curveView, CurveViewCursor * cursor, int * indexFunctionSelectedByCursor, uint32_t * modelVersion, uint32_t * previousModelsVersions, uint32_t * rangeVersion, Poincare::Preferences::AngleUnit * angleUnitVersion); bool isEmpty() const override; ViewController * initialisationParameterController() override; void didBecomeFirstResponder() override; diff --git a/apps/shared/interactive_curve_view_controller.cpp b/apps/shared/interactive_curve_view_controller.cpp index f1bc67391..f0ba3448b 100644 --- a/apps/shared/interactive_curve_view_controller.cpp +++ b/apps/shared/interactive_curve_view_controller.cpp @@ -7,10 +7,11 @@ using namespace Poincare; namespace Shared { -InteractiveCurveViewController::InteractiveCurveViewController(Responder * parentResponder, InputEventHandlerDelegate * inputEventHandlerDelegate, ButtonRowController * header, InteractiveCurveViewRange * interactiveRange, CurveView * curveView, CurveViewCursor * cursor, uint32_t * modelVersion, uint32_t * rangeVersion) : +InteractiveCurveViewController::InteractiveCurveViewController(Responder * parentResponder, InputEventHandlerDelegate * inputEventHandlerDelegate, ButtonRowController * header, InteractiveCurveViewRange * interactiveRange, CurveView * curveView, CurveViewCursor * cursor, uint32_t * modelVersion, uint32_t * previousModelsVersions, uint32_t * rangeVersion) : SimpleInteractiveCurveViewController(parentResponder, cursor), ButtonRowDelegate(header, nullptr), m_modelVersion(modelVersion), + m_previousModelsVersions(previousModelsVersions), m_rangeVersion(rangeVersion), m_rangeParameterController(this, inputEventHandlerDelegate, interactiveRange), m_zoomParameterController(this, interactiveRange, curveView), diff --git a/apps/shared/interactive_curve_view_controller.h b/apps/shared/interactive_curve_view_controller.h index 58a72a792..bda9f2e76 100644 --- a/apps/shared/interactive_curve_view_controller.h +++ b/apps/shared/interactive_curve_view_controller.h @@ -12,7 +12,7 @@ namespace Shared { class InteractiveCurveViewController : public SimpleInteractiveCurveViewController, public InteractiveCurveViewRangeDelegate, public ButtonRowDelegate, public AlternateEmptyViewDefaultDelegate { public: - InteractiveCurveViewController(Responder * parentResponder, InputEventHandlerDelegate * inputEventHandlerDelegate, ButtonRowController * header, InteractiveCurveViewRange * interactiveRange, CurveView * curveView, CurveViewCursor * cursor, uint32_t * modelVersion, uint32_t * rangeVersion); + InteractiveCurveViewController(Responder * parentResponder, InputEventHandlerDelegate * inputEventHandlerDelegate, ButtonRowController * header, InteractiveCurveViewRange * interactiveRange, CurveView * curveView, CurveViewCursor * cursor, uint32_t * modelVersion, uint32_t * previousModelsVersions, uint32_t * rangeVersion); const char * title() override; bool handleEvent(Ion::Events::Event event) override; @@ -67,6 +67,7 @@ private: virtual bool shouldSetDefaultOnModelChange() const { return false; } uint32_t * m_modelVersion; + uint32_t * m_previousModelsVersions; uint32_t * m_rangeVersion; RangeParameterController m_rangeParameterController; ZoomParameterController m_zoomParameterController; From 53705fb33338c215af558d341854b4a8bcaf2c44 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Wed, 4 Mar 2020 14:41:18 +0100 Subject: [PATCH 25/33] [apps/graph_ctrlr] Reload range if no previous model is present We memoize the checksum of the x first models, and we check that one of these models is still present when the graph view appears. If so, we do not reload the range, other wise we reload it. Scenario: f(t) = [t^2 t+1] in parametric Display the graph f(x) = 1 on ]-inf;0] g(x) = 2 on [0;inf[ Display the graph -> the range did not change --- apps/regression/app.cpp | 3 +- apps/regression/app.h | 3 +- apps/regression/graph_controller.cpp | 4 +++ apps/regression/graph_controller.h | 3 ++ apps/regression/store.h | 4 +++ apps/shared/function_app.cpp | 3 +- apps/shared/function_app.h | 4 +-- apps/shared/function_graph_controller.cpp | 4 +++ apps/shared/function_graph_controller.h | 3 ++ apps/shared/function_store.cpp | 7 ++++ apps/shared/function_store.h | 1 + .../interactive_curve_view_controller.cpp | 34 ++++++++++++++++++- .../interactive_curve_view_controller.h | 4 +++ 13 files changed, 70 insertions(+), 7 deletions(-) diff --git a/apps/regression/app.cpp b/apps/regression/app.cpp index bfe05df33..de483ded2 100644 --- a/apps/regression/app.cpp +++ b/apps/regression/app.cpp @@ -37,7 +37,8 @@ App * App::Snapshot::unpack(Container * container) { void App::Snapshot::reset() { m_store.deleteAllPairs(); m_modelVersion = 0; - memset(m_previousModelsVersions, 0, sizeof(m_previousModelsVersions[0])*sNumberOfMemoizedModelVersions); + assert(sizeof(m_previousModelsVersions) == sizeof(uint32_t) * GraphController::sNumberOfMemoizedModelVersions); + memset(m_previousModelsVersions, 0, sizeof(m_previousModelsVersions)); m_rangeVersion = 0; setActiveTab(0); } diff --git a/apps/regression/app.h b/apps/regression/app.h index 460e63f3a..f697d4a49 100644 --- a/apps/regression/app.h +++ b/apps/regression/app.h @@ -21,7 +21,6 @@ public: }; class Snapshot : public ::App::Snapshot, public TabViewDataSource { public: - static constexpr size_t sNumberOfMemoizedModelVersions = 5; // TODO LEA factorize with Shared::FunctionApp Snapshot(); App * unpack(Container * container) override; void reset() override; @@ -39,7 +38,7 @@ public: Shared::CurveViewCursor m_cursor; int m_graphSelectedDotIndex; uint32_t m_modelVersion; - uint32_t m_previousModelsVersions[sNumberOfMemoizedModelVersions]; + uint32_t m_previousModelsVersions[GraphController::sNumberOfMemoizedModelVersions]; uint32_t m_rangeVersion; int m_selectedSeriesIndex; }; diff --git a/apps/regression/graph_controller.cpp b/apps/regression/graph_controller.cpp index 973c90734..afa38abfe 100644 --- a/apps/regression/graph_controller.cpp +++ b/apps/regression/graph_controller.cpp @@ -351,6 +351,10 @@ uint32_t GraphController::modelVersion() { return m_store->storeChecksum(); } +uint32_t GraphController::modelVersionAtIndex(size_t i) { + return m_store->seriesChecksumAtIndex(i); +} + uint32_t GraphController::rangeVersion() { return m_store->rangeChecksum(); } diff --git a/apps/regression/graph_controller.h b/apps/regression/graph_controller.h index 6926854c5..6d434f500 100644 --- a/apps/regression/graph_controller.h +++ b/apps/regression/graph_controller.h @@ -16,6 +16,7 @@ namespace Regression { class GraphController : public Shared::InteractiveCurveViewController { public: + static constexpr size_t sNumberOfMemoizedModelVersions = Store::k_numberOfSeries; GraphController(Responder * parentResponder, InputEventHandlerDelegate * inputEventHandlerDelegate, ButtonRowController * header, Store * store, Shared::CurveViewCursor * cursor, uint32_t * modelVersion, uint32_t * previousModelsVersions, uint32_t * rangeVersion, int * selectedDotIndex, int * selectedSeriesIndex); ViewController * initialisationParameterController() override; bool isEmpty() const override; @@ -43,7 +44,9 @@ private: // InteractiveCurveViewController void initCursorParameters() override; uint32_t modelVersion() override; + uint32_t modelVersionAtIndex(size_t i) override; uint32_t rangeVersion() override; + size_t numberOfMemoizedVersions() const override { return sNumberOfMemoizedModelVersions; } int selectedCurveIndex() const override { return *m_selectedSeriesIndex; } bool closestCurveIndexIsSuitable(int newIndex, int currentIndex) const override; Poincare::Coordinate2D xyValues(int curveIndex, double x, Poincare::Context * context) const override; diff --git a/apps/regression/store.h b/apps/regression/store.h index dfdc682c1..757ed2b95 100644 --- a/apps/regression/store.h +++ b/apps/regression/store.h @@ -35,6 +35,10 @@ public: assert((int)m_regressionTypes[series] >= 0 && (int)m_regressionTypes[series] < Model::k_numberOfModels); return regressionModel((int)m_regressionTypes[series]); } + uint32_t seriesChecksumAtIndex(size_t i) { + assert(i < k_numberOfSeries); + return m_seriesChecksum[i]; + } // Dots /* Return the closest dot to abscissa x above the regression curve if diff --git a/apps/shared/function_app.cpp b/apps/shared/function_app.cpp index 3861d0b3e..0b7a95454 100644 --- a/apps/shared/function_app.cpp +++ b/apps/shared/function_app.cpp @@ -17,7 +17,8 @@ FunctionApp::Snapshot::Snapshot() : void FunctionApp::Snapshot::reset() { m_indexFunctionSelectedByCursor = 0; m_modelVersion = 0; - memset(m_previousModelsVersions, 0, sizeof(m_previousModelsVersions[0])*sNumberOfMemoizedModelVersions); + assert(sizeof(m_previousModelsVersions) == sizeof(uint32_t) * FunctionGraphController::sNumberOfMemoizedModelVersions); + memset(m_previousModelsVersions, 0, sizeof(m_previousModelsVersions)); m_rangeVersion = 0; setActiveTab(0); } diff --git a/apps/shared/function_app.h b/apps/shared/function_app.h index 9fc842d8d..d15e4c5e8 100644 --- a/apps/shared/function_app.h +++ b/apps/shared/function_app.h @@ -2,6 +2,7 @@ #define SHARED_FUNCTION_APP_H #include "expression_field_delegate_app.h" +#include "function_graph_controller.h" #include "function_store.h" #include "curve_view_cursor.h" #include "values_controller.h" @@ -12,7 +13,6 @@ class FunctionApp : public ExpressionFieldDelegateApp { public: class Snapshot : public ::App::Snapshot, public TabViewDataSource { public: - static constexpr size_t sNumberOfMemoizedModelVersions = 5; Snapshot(); CurveViewCursor * cursor() { return &m_cursor; } uint32_t * modelVersion() { return &m_modelVersion; } @@ -28,7 +28,7 @@ public: private: int m_indexFunctionSelectedByCursor; uint32_t m_modelVersion; - uint32_t m_previousModelsVersions[sNumberOfMemoizedModelVersions]; + uint32_t m_previousModelsVersions[FunctionGraphController::sNumberOfMemoizedModelVersions]; uint32_t m_rangeVersion; Poincare::Preferences::AngleUnit m_angleUnitVersion; }; diff --git a/apps/shared/function_graph_controller.cpp b/apps/shared/function_graph_controller.cpp index 0f2b57d7f..f851f65ef 100644 --- a/apps/shared/function_graph_controller.cpp +++ b/apps/shared/function_graph_controller.cpp @@ -183,6 +183,10 @@ uint32_t FunctionGraphController::modelVersion() { return functionStore()->storeChecksum(); } +uint32_t FunctionGraphController::modelVersionAtIndex(size_t i) { + return functionStore()->storeChecksumAtIndex(i); +} + uint32_t FunctionGraphController::rangeVersion() { return interactiveCurveViewRange()->rangeChecksum(); } diff --git a/apps/shared/function_graph_controller.h b/apps/shared/function_graph_controller.h index af3d0dd61..fcb15ae57 100644 --- a/apps/shared/function_graph_controller.h +++ b/apps/shared/function_graph_controller.h @@ -13,6 +13,7 @@ namespace Shared { class FunctionGraphController : public InteractiveCurveViewController, public FunctionBannerDelegate { public: + static constexpr size_t sNumberOfMemoizedModelVersions = 5; FunctionGraphController(Responder * parentResponder, InputEventHandlerDelegate * inputEventHandlerDelegate, ButtonRowController * header, InteractiveCurveViewRange * interactiveRange, CurveView * curveView, CurveViewCursor * cursor, int * indexFunctionSelectedByCursor, uint32_t * modelVersion, uint32_t * previousModelsVersions, uint32_t * rangeVersion, Poincare::Preferences::AngleUnit * angleUnitVersion); bool isEmpty() const override; ViewController * initialisationParameterController() override; @@ -49,7 +50,9 @@ private: // InteractiveCurveViewController bool moveCursorVertically(int direction) override; uint32_t modelVersion() override; + uint32_t modelVersionAtIndex(size_t i) override; uint32_t rangeVersion() override; + size_t numberOfMemoizedVersions() const override { return sNumberOfMemoizedModelVersions; } InitialisationParameterController m_initialisationParameterController; Poincare::Preferences::AngleUnit * m_angleUnitVersion; diff --git a/apps/shared/function_store.cpp b/apps/shared/function_store.cpp index 77ed25132..7a05715a2 100644 --- a/apps/shared/function_store.cpp +++ b/apps/shared/function_store.cpp @@ -6,4 +6,11 @@ uint32_t FunctionStore::storeChecksum() { return Ion::Storage::sharedStorage()->checksum(); } +uint32_t FunctionStore::storeChecksumAtIndex(size_t i) { + if (numberOfActiveFunctions() <= i) { + return 0; + } + return activeRecordAtIndex(i).checksum(); +} + } diff --git a/apps/shared/function_store.h b/apps/shared/function_store.h index 2790f6703..03e57ef58 100644 --- a/apps/shared/function_store.h +++ b/apps/shared/function_store.h @@ -13,6 +13,7 @@ class FunctionStore : public ExpressionModelStore { public: FunctionStore() : ExpressionModelStore() {} uint32_t storeChecksum(); + uint32_t storeChecksumAtIndex(size_t i); int numberOfActiveFunctions() const { return numberOfModelsSatisfyingTest(&isFunctionActive, nullptr); } diff --git a/apps/shared/interactive_curve_view_controller.cpp b/apps/shared/interactive_curve_view_controller.cpp index f0ba3448b..997149852 100644 --- a/apps/shared/interactive_curve_view_controller.cpp +++ b/apps/shared/interactive_curve_view_controller.cpp @@ -133,11 +133,43 @@ Responder * InteractiveCurveViewController::defaultController() { return tabController(); } +bool InteractiveCurveViewController::previousModelsWereAllDeleted() { + bool result = true; + const int modelsCount = numberOfCurves(); + const int memoizationCount = numberOfMemoizedVersions(); + + // Look for a current model that is the same as in the previous version + for (int i = 0; i < modelsCount; i++) { + uint32_t currentVersion = modelVersionAtIndex(i); + for (int j = 0; j < memoizationCount; j++) { + uint32_t * previousVersion = m_previousModelsVersions + j; + if (currentVersion == *previousVersion) { + result = false; + break; + } + } + if (!result) { + break; + } + } + + // Update the memoization + for (int i = 0; i < memoizationCount; i++) { + uint32_t * previousVersion = m_previousModelsVersions + i; + uint32_t newVersion = modelVersionAtIndex(i); + if (*previousVersion != newVersion) { + *previousVersion = newVersion; + } + } + return result; +} + void InteractiveCurveViewController::viewWillAppear() { SimpleInteractiveCurveViewController::viewWillAppear(); uint32_t newModelVersion = modelVersion(); if (*m_modelVersion != newModelVersion) { - if (*m_modelVersion == 0 || numberOfCurves() == 1 || shouldSetDefaultOnModelChange()) { + // Put previousModelsWereAllDeleted first to update the model versions + if (previousModelsWereAllDeleted() || *m_modelVersion == 0 || numberOfCurves() == 1 || shouldSetDefaultOnModelChange()) { interactiveCurveViewRange()->setDefault(); } *m_modelVersion = newModelVersion; diff --git a/apps/shared/interactive_curve_view_controller.h b/apps/shared/interactive_curve_view_controller.h index bda9f2e76..9ef048f18 100644 --- a/apps/shared/interactive_curve_view_controller.h +++ b/apps/shared/interactive_curve_view_controller.h @@ -28,6 +28,8 @@ public: Responder * defaultController() override; + bool previousModelsWereAllDeleted(); + void viewWillAppear() override; void viewDidDisappear() override; void willExitResponderChain(Responder * nextFirstResponder) override; @@ -39,6 +41,7 @@ protected: virtual void initCursorParameters() = 0; virtual bool moveCursorVertically(int direction) = 0; virtual uint32_t modelVersion() = 0; + virtual uint32_t modelVersionAtIndex(size_t i) = 0; virtual uint32_t rangeVersion() = 0; bool isCursorVisible(); @@ -66,6 +69,7 @@ private: float addMargin(float x, float range, bool isVertical, bool isMin) override; virtual bool shouldSetDefaultOnModelChange() const { return false; } + virtual size_t numberOfMemoizedVersions() const = 0; uint32_t * m_modelVersion; uint32_t * m_previousModelsVersions; uint32_t * m_rangeVersion; From 702772a7c96301a1a0d6a06d7a3bc58c0943ee1c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Tue, 10 Mar 2020 15:13:22 +0100 Subject: [PATCH 26/33] [apps/reg] Store::m_seriesChecksum is Snapshot::m_prevModelsVersions Share these objects instead of duplicating them --- apps/regression/app.cpp | 5 +---- apps/regression/app.h | 3 +-- apps/regression/graph_controller.cpp | 3 ++- apps/regression/graph_controller.h | 3 +-- apps/regression/store.cpp | 18 +++++++++++++----- apps/regression/store.h | 7 +++---- 6 files changed, 21 insertions(+), 18 deletions(-) diff --git a/apps/regression/app.cpp b/apps/regression/app.cpp index de483ded2..9331fdefc 100644 --- a/apps/regression/app.cpp +++ b/apps/regression/app.cpp @@ -27,7 +27,6 @@ App::Snapshot::Snapshot() : m_rangeVersion(0), m_selectedSeriesIndex(-1) { - assert(m_previousModelsVersions[0] == 0); } App * App::Snapshot::unpack(Container * container) { @@ -35,10 +34,8 @@ App * App::Snapshot::unpack(Container * container) { } void App::Snapshot::reset() { - m_store.deleteAllPairs(); + m_store.reset(); m_modelVersion = 0; - assert(sizeof(m_previousModelsVersions) == sizeof(uint32_t) * GraphController::sNumberOfMemoizedModelVersions); - memset(m_previousModelsVersions, 0, sizeof(m_previousModelsVersions)); m_rangeVersion = 0; setActiveTab(0); } diff --git a/apps/regression/app.h b/apps/regression/app.h index f697d4a49..2c529af77 100644 --- a/apps/regression/app.h +++ b/apps/regression/app.h @@ -30,7 +30,7 @@ public: int * graphSelectedDotIndex() { return &m_graphSelectedDotIndex; } int * selectedSeriesIndex() { return &m_selectedSeriesIndex; } uint32_t * modelVersion() { return &m_modelVersion; } - uint32_t * previousModelsVersions() { return m_previousModelsVersions; } + uint32_t * previousModelsVersions() { return m_store.seriesChecksum(); } uint32_t * rangeVersion() { return &m_rangeVersion; } private: void tidy() override; @@ -38,7 +38,6 @@ public: Shared::CurveViewCursor m_cursor; int m_graphSelectedDotIndex; uint32_t m_modelVersion; - uint32_t m_previousModelsVersions[GraphController::sNumberOfMemoizedModelVersions]; uint32_t m_rangeVersion; int m_selectedSeriesIndex; }; diff --git a/apps/regression/graph_controller.cpp b/apps/regression/graph_controller.cpp index afa38abfe..b6b54aaf1 100644 --- a/apps/regression/graph_controller.cpp +++ b/apps/regression/graph_controller.cpp @@ -352,7 +352,8 @@ uint32_t GraphController::modelVersion() { } uint32_t GraphController::modelVersionAtIndex(size_t i) { - return m_store->seriesChecksumAtIndex(i); + assert(i < numberOfMemoizedVersions()); + return *(m_store->seriesChecksum() + i); } uint32_t GraphController::rangeVersion() { diff --git a/apps/regression/graph_controller.h b/apps/regression/graph_controller.h index 6d434f500..30e722552 100644 --- a/apps/regression/graph_controller.h +++ b/apps/regression/graph_controller.h @@ -16,7 +16,6 @@ namespace Regression { class GraphController : public Shared::InteractiveCurveViewController { public: - static constexpr size_t sNumberOfMemoizedModelVersions = Store::k_numberOfSeries; GraphController(Responder * parentResponder, InputEventHandlerDelegate * inputEventHandlerDelegate, ButtonRowController * header, Store * store, Shared::CurveViewCursor * cursor, uint32_t * modelVersion, uint32_t * previousModelsVersions, uint32_t * rangeVersion, int * selectedDotIndex, int * selectedSeriesIndex); ViewController * initialisationParameterController() override; bool isEmpty() const override; @@ -46,7 +45,7 @@ private: uint32_t modelVersion() override; uint32_t modelVersionAtIndex(size_t i) override; uint32_t rangeVersion() override; - size_t numberOfMemoizedVersions() const override { return sNumberOfMemoizedModelVersions; } + size_t numberOfMemoizedVersions() const override { return Store::k_numberOfSeries; } int selectedCurveIndex() const override { return *m_selectedSeriesIndex; } bool closestCurveIndexIsSuitable(int newIndex, int currentIndex) const override; Poincare::Coordinate2D xyValues(int curveIndex, double x, Poincare::Context * context) const override; diff --git a/apps/regression/store.cpp b/apps/regression/store.cpp index 0afd7941a..98f703bd5 100644 --- a/apps/regression/store.cpp +++ b/apps/regression/store.cpp @@ -19,13 +19,14 @@ static_assert(Store::k_numberOfSeries == 3, "Number of series changed, Regressio Store::Store() : InteractiveCurveViewRange(), DoublePairStore(), - m_seriesChecksum{0, 0, 0}, m_angleUnit(Poincare::Preferences::AngleUnit::Degree) { - for (int i = 0; i < k_numberOfSeries; i++) { - m_regressionTypes[i] = Model::Type::Linear; - m_regressionChanged[i] = false; - } + resetMemoization(); +} + +void Store::reset() { + deleteAllPairs(); + resetMemoization(); } void Store::tidy() { @@ -188,6 +189,13 @@ double Store::doubleCastedNumberOfPairsOfSeries(int series) const { return DoublePairStore::numberOfPairsOfSeries(series); } +void Store::resetMemoization() { + assert(((int)Model::Type::Linear) == 0); + memset(m_seriesChecksum, 0, sizeof(m_seriesChecksum)); + memset(m_regressionTypes, 0, sizeof(m_regressionTypes)); + memset(m_regressionChanged, 0, sizeof(m_regressionChanged)); +} + float Store::maxValueOfColumn(int series, int i) const { float maxColumn = -FLT_MAX; for (int k = 0; k < numberOfPairsOfSeries(series); k++) { diff --git a/apps/regression/store.h b/apps/regression/store.h index 757ed2b95..2cc6f600f 100644 --- a/apps/regression/store.h +++ b/apps/regression/store.h @@ -22,6 +22,7 @@ class Store : public Shared::InteractiveCurveViewRange, public Shared::DoublePai public: Store(); + void reset(); // Clean pool void tidy(); @@ -35,10 +36,7 @@ public: assert((int)m_regressionTypes[series] >= 0 && (int)m_regressionTypes[series] < Model::k_numberOfModels); return regressionModel((int)m_regressionTypes[series]); } - uint32_t seriesChecksumAtIndex(size_t i) { - assert(i < k_numberOfSeries); - return m_seriesChecksum[i]; - } + uint32_t * seriesChecksum() { return m_seriesChecksum; } // Dots /* Return the closest dot to abscissa x above the regression curve if @@ -74,6 +72,7 @@ public: double squaredCorrelationCoefficient(int series) const; private: constexpr static float k_displayHorizontalMarginRatio = 0.05f; + void resetMemoization(); float maxValueOfColumn(int series, int i) const; //TODO LEA why float ? float minValueOfColumn(int series, int i) const; //TODO LEA why float ? Model * regressionModel(int index); From 8168a125e6739772ef9aaf89d5b41701e116f9c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Wed, 11 Mar 2020 12:01:45 +0100 Subject: [PATCH 27/33] [apps/statistics] Remove unused variable in HistogramView It is unused as HistogramView now inherits Shared::HorizontallyLabeledCurveView --- apps/statistics/histogram_view.h | 1 - 1 file changed, 1 deletion(-) diff --git a/apps/statistics/histogram_view.h b/apps/statistics/histogram_view.h index c6859097c..f72cbac1a 100644 --- a/apps/statistics/histogram_view.h +++ b/apps/statistics/histogram_view.h @@ -23,7 +23,6 @@ public: private: HistogramController * m_controller; Store * m_store; - char m_labels[k_maxNumberOfXLabels][k_labelBufferMaxSize]; static float EvaluateHistogramAtAbscissa(float abscissa, void * model, void * context); float m_highlightedBarStart; float m_highlightedBarEnd; From a7d419c4bd7e0a1d8c5eceed23e023ae339d8712 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Tue, 11 Feb 2020 10:49:49 +0100 Subject: [PATCH 28/33] [ion/emscripten] Get physical keyboard events in scan() --- ion/src/simulator/shared/keyboard_sdl.cpp | 43 +++++++++++++++++++++-- 1 file changed, 41 insertions(+), 2 deletions(-) diff --git a/ion/src/simulator/shared/keyboard_sdl.cpp b/ion/src/simulator/shared/keyboard_sdl.cpp index 4940c2c98..4d3b1a928 100644 --- a/ion/src/simulator/shared/keyboard_sdl.cpp +++ b/ion/src/simulator/shared/keyboard_sdl.cpp @@ -22,6 +22,36 @@ void IonSimulatorKeyboardKeyUp(int keyNumber) { namespace Ion { namespace Keyboard { +#if EPSILON_SDL_SCREEN_ONLY + class KeySDLKeyPair { + public: + constexpr KeySDLKeyPair(Ion::Keyboard::Key key, SDL_Scancode SDLKey) : + m_key(key), + m_SDLKey(SDLKey) + {} + Ion::Keyboard::Key key() const { return m_key; } + SDL_Scancode SDLKey() const { return m_SDLKey; } + private: + Ion::Keyboard::Key m_key; + SDL_Scancode m_SDLKey; + }; + + constexpr static KeySDLKeyPair sKeyPairs[] = { + KeySDLKeyPair(Ion::Keyboard::Key::Down, SDL_SCANCODE_DOWN), + KeySDLKeyPair(Ion::Keyboard::Key::Up, SDL_SCANCODE_UP), + KeySDLKeyPair(Ion::Keyboard::Key::Left, SDL_SCANCODE_LEFT), + KeySDLKeyPair(Ion::Keyboard::Key::Right, SDL_SCANCODE_RIGHT), + KeySDLKeyPair(Ion::Keyboard::Key::Shift, SDL_SCANCODE_LSHIFT), + KeySDLKeyPair(Ion::Keyboard::Key::Shift, SDL_SCANCODE_RSHIFT), + KeySDLKeyPair(Ion::Keyboard::Key::EXE, SDL_SCANCODE_RETURN), + KeySDLKeyPair(Ion::Keyboard::Key::Back, SDL_SCANCODE_ESCAPE), + KeySDLKeyPair(Ion::Keyboard::Key::Toolbox, SDL_SCANCODE_TAB), + KeySDLKeyPair(Ion::Keyboard::Key::Backspace, SDL_SCANCODE_BACKSPACE) + }; + + constexpr int sNumberOfKeyPairs = sizeof(sKeyPairs)/sizeof(KeySDLKeyPair); +#endif + State scan() { // We need to tell SDL to get new state from the host OS SDL_PumpEvents(); @@ -33,8 +63,17 @@ State scan() { Simulator::Main::refresh(); #if EPSILON_SDL_SCREEN_ONLY - // In this case, keyboard states will be sent over another channel - return sKeyboardState; + /* In this case, keyboard states will be sent over another channel, but we + * still need to catch the physical keyboard events */ + const uint8_t * SDLstate = SDL_GetKeyboardState(NULL); + State state = sKeyboardState; + for (int i = 0; i < sNumberOfKeyPairs; i++) { + KeySDLKeyPair pair = sKeyPairs[i]; + if (SDLstate[pair.SDLKey()]) { + state.setKey(pair.key()); + } + } + return state; #else // Start with a "clean" state State state; From 18f3054b50923b38067568f4b42e97dc33731ed7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Thu, 20 Feb 2020 14:41:40 +0100 Subject: [PATCH 29/33] [ion/simulator/web] Do not duplicate events in scan and getPlatformEvent Some events were caught by bith scan() and getPlatformEvent() --- ion/src/simulator/shared/events_keyboard.cpp | 5 ++ ion/src/simulator/shared/keyboard_sdl.cpp | 67 ++++++++++++-------- ion/src/simulator/shared/platform.h | 2 + 3 files changed, 47 insertions(+), 27 deletions(-) diff --git a/ion/src/simulator/shared/events_keyboard.cpp b/ion/src/simulator/shared/events_keyboard.cpp index 02bd8b4a1..2a581a574 100644 --- a/ion/src/simulator/shared/events_keyboard.cpp +++ b/ion/src/simulator/shared/events_keyboard.cpp @@ -204,6 +204,11 @@ Event getPlatformEvent() { return Termination; } if (event.type == SDL_KEYDOWN) { +#if EPSILON_SDL_SCREEN_ONLY + if (IonSimulatorSDLKeyDetectedByScan(event.key.keysym.scancode)) { + continue; + } +#endif return eventFromSDLKeyboardEvent(event.key); } if (event.type == SDL_TEXTINPUT) { diff --git a/ion/src/simulator/shared/keyboard_sdl.cpp b/ion/src/simulator/shared/keyboard_sdl.cpp index 4d3b1a928..589d21a49 100644 --- a/ion/src/simulator/shared/keyboard_sdl.cpp +++ b/ion/src/simulator/shared/keyboard_sdl.cpp @@ -17,41 +17,54 @@ void IonSimulatorKeyboardKeyUp(int keyNumber) { Ion::Keyboard::Key key = static_cast(keyNumber); sKeyboardState.clearKey(key); } -#endif namespace Ion { namespace Keyboard { -#if EPSILON_SDL_SCREEN_ONLY - class KeySDLKeyPair { - public: - constexpr KeySDLKeyPair(Ion::Keyboard::Key key, SDL_Scancode SDLKey) : - m_key(key), - m_SDLKey(SDLKey) - {} - Ion::Keyboard::Key key() const { return m_key; } - SDL_Scancode SDLKey() const { return m_SDLKey; } - private: - Ion::Keyboard::Key m_key; - SDL_Scancode m_SDLKey; - }; +class KeySDLKeyPair { +public: + constexpr KeySDLKeyPair(Ion::Keyboard::Key key, SDL_Scancode SDLKey) : + m_key(key), + m_SDLKey(SDLKey) + {} + Ion::Keyboard::Key key() const { return m_key; } + SDL_Scancode SDLKey() const { return m_SDLKey; } +private: + Ion::Keyboard::Key m_key; + SDL_Scancode m_SDLKey; +}; - constexpr static KeySDLKeyPair sKeyPairs[] = { - KeySDLKeyPair(Ion::Keyboard::Key::Down, SDL_SCANCODE_DOWN), - KeySDLKeyPair(Ion::Keyboard::Key::Up, SDL_SCANCODE_UP), - KeySDLKeyPair(Ion::Keyboard::Key::Left, SDL_SCANCODE_LEFT), - KeySDLKeyPair(Ion::Keyboard::Key::Right, SDL_SCANCODE_RIGHT), - KeySDLKeyPair(Ion::Keyboard::Key::Shift, SDL_SCANCODE_LSHIFT), - KeySDLKeyPair(Ion::Keyboard::Key::Shift, SDL_SCANCODE_RSHIFT), - KeySDLKeyPair(Ion::Keyboard::Key::EXE, SDL_SCANCODE_RETURN), - KeySDLKeyPair(Ion::Keyboard::Key::Back, SDL_SCANCODE_ESCAPE), - KeySDLKeyPair(Ion::Keyboard::Key::Toolbox, SDL_SCANCODE_TAB), - KeySDLKeyPair(Ion::Keyboard::Key::Backspace, SDL_SCANCODE_BACKSPACE) - }; +constexpr static KeySDLKeyPair sKeyPairs[] = { + KeySDLKeyPair(Ion::Keyboard::Key::Down, SDL_SCANCODE_DOWN), + KeySDLKeyPair(Ion::Keyboard::Key::Up, SDL_SCANCODE_UP), + KeySDLKeyPair(Ion::Keyboard::Key::Left, SDL_SCANCODE_LEFT), + KeySDLKeyPair(Ion::Keyboard::Key::Right, SDL_SCANCODE_RIGHT), + KeySDLKeyPair(Ion::Keyboard::Key::Shift, SDL_SCANCODE_LSHIFT), + KeySDLKeyPair(Ion::Keyboard::Key::Shift, SDL_SCANCODE_RSHIFT), + KeySDLKeyPair(Ion::Keyboard::Key::EXE, SDL_SCANCODE_RETURN), + KeySDLKeyPair(Ion::Keyboard::Key::Back, SDL_SCANCODE_ESCAPE), + KeySDLKeyPair(Ion::Keyboard::Key::Toolbox, SDL_SCANCODE_TAB), + KeySDLKeyPair(Ion::Keyboard::Key::Backspace, SDL_SCANCODE_BACKSPACE) +}; - constexpr int sNumberOfKeyPairs = sizeof(sKeyPairs)/sizeof(KeySDLKeyPair); +constexpr int sNumberOfKeyPairs = sizeof(sKeyPairs)/sizeof(KeySDLKeyPair); + +} +} + +bool IonSimulatorSDLKeyDetectedByScan(SDL_Scancode key) { + for (int i = 0; i < Ion::Keyboard::sNumberOfKeyPairs; i++) { + if (key == Ion::Keyboard::sKeyPairs[i].SDLKey()) { + return true; + } + } + return false; +} #endif +namespace Ion { +namespace Keyboard { + State scan() { // We need to tell SDL to get new state from the host OS SDL_PumpEvents(); diff --git a/ion/src/simulator/shared/platform.h b/ion/src/simulator/shared/platform.h index 0dcb4e74c..c6e27bbee 100644 --- a/ion/src/simulator/shared/platform.h +++ b/ion/src/simulator/shared/platform.h @@ -20,6 +20,8 @@ void IonSimulatorKeyboardKeyUp(int keyNumber); void IonSimulatorEventsPushEvent(int eventNumber); +bool IonSimulatorSDLKeyDetectedByScan(SDL_Scancode key); + #endif void IonSimulatorCallbackDidRefresh(); From 4a4ba52e385f7b645b978d5c18aef669cb9746e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Mon, 24 Feb 2020 11:41:18 +0100 Subject: [PATCH 30/33] [ion/events] Better handling of Shift on the web target --- ion/include/ion/events.h | 1 + ion/src/shared/events_modifier.cpp | 10 ++++++++++ ion/src/simulator/shared/events_keyboard.cpp | 16 ++++++++++++++++ 3 files changed, 27 insertions(+) diff --git a/ion/include/ion/events.h b/ion/include/ion/events.h index bba153a96..058bdfcbc 100644 --- a/ion/include/ion/events.h +++ b/ion/include/ion/events.h @@ -53,6 +53,7 @@ Event getEvent(int * timeout); ShiftAlphaStatus shiftAlphaStatus(); void setShiftAlphaStatus(ShiftAlphaStatus s); +void removeShift(); bool isShiftActive(); bool isAlphaActive(); void setLongRepetition(bool longRepetition); diff --git a/ion/src/shared/events_modifier.cpp b/ion/src/shared/events_modifier.cpp index 90fa01a97..f2bc8b61f 100644 --- a/ion/src/shared/events_modifier.cpp +++ b/ion/src/shared/events_modifier.cpp @@ -11,6 +11,16 @@ ShiftAlphaStatus shiftAlphaStatus() { return sShiftAlphaStatus; } +void removeShift() { + if (sShiftAlphaStatus == ShiftAlphaStatus::Shift) { + sShiftAlphaStatus = ShiftAlphaStatus::Default; + } else if (sShiftAlphaStatus == ShiftAlphaStatus::ShiftAlpha ) { + sShiftAlphaStatus = ShiftAlphaStatus::Alpha; + } else if (sShiftAlphaStatus == ShiftAlphaStatus::ShiftAlphaLock) { + sShiftAlphaStatus = ShiftAlphaStatus::AlphaLock; + } +} + bool isShiftActive() { return sShiftAlphaStatus == ShiftAlphaStatus::Shift || sShiftAlphaStatus == ShiftAlphaStatus::ShiftAlpha || sShiftAlphaStatus == ShiftAlphaStatus::ShiftAlphaLock; } diff --git a/ion/src/simulator/shared/events_keyboard.cpp b/ion/src/simulator/shared/events_keyboard.cpp index 2a581a574..0ba9dff6a 100644 --- a/ion/src/simulator/shared/events_keyboard.cpp +++ b/ion/src/simulator/shared/events_keyboard.cpp @@ -64,6 +64,12 @@ namespace Ion { namespace Events { static Event eventFromSDLKeyboardEvent(SDL_KeyboardEvent event) { + /* If an event is detected, we want to remove the Shift modifier to mimic the + * device behaviour. If no event was detected, we restore the previous + * ShiftAlphaStatus. */ + Ion::Events::ShiftAlphaStatus previousShiftAlphaStatus = Ion::Events::shiftAlphaStatus(); + Ion::Events::removeShift(); + if (event.keysym.mod & KMOD_CTRL) { switch (event.keysym.sym) { case SDLK_BACKSPACE: @@ -156,6 +162,8 @@ static Event eventFromSDLKeyboardEvent(SDL_KeyboardEvent event) { case SDLK_AC_BACK: return Termination; } + // No event was detected, restore the previous ShiftAlphaStatus. + Ion::Events::setShiftAlphaStatus(previousShiftAlphaStatus); return None; } @@ -180,6 +188,14 @@ static Event eventFromSDLTextInputEvent(SDL_TextInputEvent event) { } char character = event.text[0]; if (character >= 32 && character < 127) { +#if EPSILON_SDL_SCREEN_ONLY + /* We remove the shift, otherwise it might stay activated when it shouldn't. + * For instance on a French keyboard, to input "1", we first press "Shift" + * (which activates the Shift modifier on the calculator), then we press + * "&", transformed by eventFromSDLTextInputEvent into the text "1". If we + * do not remove the Shift here, it would still be pressed afterwards. */ + Ion::Events::removeShift(); +#endif return sEventForASCIICharAbove32[character-32]; } return None; From 124225899294723040ff0b4dc2805c6ff8902c09 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Tue, 25 Feb 2020 11:21:59 +0100 Subject: [PATCH 31/33] [ion] Handle key events in all simulators as in EPSILON_SDL_SCREEN_ONLY This way, physical keyboard events can be caught by python on all simulators --- ion/src/simulator/shared/events_keyboard.cpp | 4 - ion/src/simulator/shared/keyboard_sdl.cpp | 82 +++++++++----------- ion/src/simulator/shared/platform.h | 7 +- 3 files changed, 39 insertions(+), 54 deletions(-) diff --git a/ion/src/simulator/shared/events_keyboard.cpp b/ion/src/simulator/shared/events_keyboard.cpp index 0ba9dff6a..81638970d 100644 --- a/ion/src/simulator/shared/events_keyboard.cpp +++ b/ion/src/simulator/shared/events_keyboard.cpp @@ -188,14 +188,12 @@ static Event eventFromSDLTextInputEvent(SDL_TextInputEvent event) { } char character = event.text[0]; if (character >= 32 && character < 127) { -#if EPSILON_SDL_SCREEN_ONLY /* We remove the shift, otherwise it might stay activated when it shouldn't. * For instance on a French keyboard, to input "1", we first press "Shift" * (which activates the Shift modifier on the calculator), then we press * "&", transformed by eventFromSDLTextInputEvent into the text "1". If we * do not remove the Shift here, it would still be pressed afterwards. */ Ion::Events::removeShift(); -#endif return sEventForASCIICharAbove32[character-32]; } return None; @@ -220,11 +218,9 @@ Event getPlatformEvent() { return Termination; } if (event.type == SDL_KEYDOWN) { -#if EPSILON_SDL_SCREEN_ONLY if (IonSimulatorSDLKeyDetectedByScan(event.key.keysym.scancode)) { continue; } -#endif return eventFromSDLKeyboardEvent(event.key); } if (event.type == SDL_TEXTINPUT) { diff --git a/ion/src/simulator/shared/keyboard_sdl.cpp b/ion/src/simulator/shared/keyboard_sdl.cpp index 589d21a49..a1b173719 100644 --- a/ion/src/simulator/shared/keyboard_sdl.cpp +++ b/ion/src/simulator/shared/keyboard_sdl.cpp @@ -17,6 +17,7 @@ void IonSimulatorKeyboardKeyUp(int keyNumber) { Ion::Keyboard::Key key = static_cast(keyNumber); sKeyboardState.clearKey(key); } +#endif namespace Ion { namespace Keyboard { @@ -49,6 +50,42 @@ constexpr static KeySDLKeyPair sKeyPairs[] = { constexpr int sNumberOfKeyPairs = sizeof(sKeyPairs)/sizeof(KeySDLKeyPair); +State scan() { + // We need to tell SDL to get new state from the host OS + SDL_PumpEvents(); + + // Notify callbacks in case we need to do something + IonSimulatorCallbackDidScanKeyboard(); + + // Grab this opportunity to refresh the display if needed + Simulator::Main::refresh(); + + // Start with a "clean" state + State state; +#if EPSILON_SDL_SCREEN_ONLY + // In this case, keyboard states are sent over another channel. + state = sKeyboardState; +#else + // Register a key for the mouse, if any + SDL_Point p; + Uint32 mouseState = SDL_GetMouseState(&p.x, &p.y); + if (mouseState & SDL_BUTTON(SDL_BUTTON_LEFT)) { + Key k = Simulator::Layout::keyAt(&p); + state.setKey(k); + } +#endif + + // Catch the physical keyboard events + const uint8_t * SDLstate = SDL_GetKeyboardState(NULL); + for (int i = 0; i < sNumberOfKeyPairs; i++) { + KeySDLKeyPair pair = sKeyPairs[i]; + if (SDLstate[pair.SDLKey()]) { + state.setKey(pair.key()); + } + } + return state; +} + } } @@ -60,48 +97,3 @@ bool IonSimulatorSDLKeyDetectedByScan(SDL_Scancode key) { } return false; } -#endif - -namespace Ion { -namespace Keyboard { - -State scan() { - // We need to tell SDL to get new state from the host OS - SDL_PumpEvents(); - - // Notify callbacks in case we need to do something - IonSimulatorCallbackDidScanKeyboard(); - - // Grab this opportunity to refresh the display if needed - Simulator::Main::refresh(); - -#if EPSILON_SDL_SCREEN_ONLY - /* In this case, keyboard states will be sent over another channel, but we - * still need to catch the physical keyboard events */ - const uint8_t * SDLstate = SDL_GetKeyboardState(NULL); - State state = sKeyboardState; - for (int i = 0; i < sNumberOfKeyPairs; i++) { - KeySDLKeyPair pair = sKeyPairs[i]; - if (SDLstate[pair.SDLKey()]) { - state.setKey(pair.key()); - } - } - return state; -#else - // Start with a "clean" state - State state; - - // Register a key for the mouse, if any - SDL_Point p; - Uint32 mouseState = SDL_GetMouseState(&p.x, &p.y); - if (mouseState & SDL_BUTTON(SDL_BUTTON_LEFT)) { - Key k = Simulator::Layout::keyAt(&p); - state.setKey(k); - } - - return state; -#endif -} - -} -} diff --git a/ion/src/simulator/shared/platform.h b/ion/src/simulator/shared/platform.h index c6e27bbee..494c83c23 100644 --- a/ion/src/simulator/shared/platform.h +++ b/ion/src/simulator/shared/platform.h @@ -2,6 +2,7 @@ #define ION_SIMULATOR_PLATFORM_H #include +#include #ifdef __cplusplus extern "C" { @@ -14,16 +15,12 @@ SDL_Texture * IonSimulatorLoadImage(SDL_Renderer * renderer, const char * identi char * IonSimulatorGetLanguageCode(); #if EPSILON_SDL_SCREEN_ONLY - void IonSimulatorKeyboardKeyDown(int keyNumber); void IonSimulatorKeyboardKeyUp(int keyNumber); - void IonSimulatorEventsPushEvent(int eventNumber); - -bool IonSimulatorSDLKeyDetectedByScan(SDL_Scancode key); - #endif +bool IonSimulatorSDLKeyDetectedByScan(SDL_Scancode key); void IonSimulatorCallbackDidRefresh(); void IonSimulatorCallbackDidScanKeyboard(); From 9ab3558cfee43e1bc374169420a3f65b147eb884 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Tue, 25 Feb 2020 15:03:45 +0100 Subject: [PATCH 32/33] [ion/events_keyboard] Remove unused cases --- ion/src/simulator/shared/events_keyboard.cpp | 36 -------------------- 1 file changed, 36 deletions(-) diff --git a/ion/src/simulator/shared/events_keyboard.cpp b/ion/src/simulator/shared/events_keyboard.cpp index 81638970d..913fd79e9 100644 --- a/ion/src/simulator/shared/events_keyboard.cpp +++ b/ion/src/simulator/shared/events_keyboard.cpp @@ -72,8 +72,6 @@ static Event eventFromSDLKeyboardEvent(SDL_KeyboardEvent event) { if (event.keysym.mod & KMOD_CTRL) { switch (event.keysym.sym) { - case SDLK_BACKSPACE: - return Clear; case SDLK_x: return Cut; case SDLK_c: @@ -94,14 +92,8 @@ static Event eventFromSDLKeyboardEvent(SDL_KeyboardEvent event) { } } switch (event.keysym.sym) { - case SDLK_ESCAPE: - return Home; - case SDLK_RETURN: - return OK; case SDLK_v: return Var; - case SDLK_BACKSPACE: - return Clear; case SDLK_x: return Exp; case SDLK_n: @@ -130,35 +122,7 @@ static Event eventFromSDLKeyboardEvent(SDL_KeyboardEvent event) { return Ans; } } - if (event.keysym.mod & KMOD_SHIFT) { - switch(event.keysym.sym) { - case SDLK_UP: - return ShiftUp; - case SDLK_DOWN: - return ShiftDown; - case SDLK_LEFT: - return ShiftLeft; - case SDLK_RIGHT: - return ShiftRight; - } - } switch(event.keysym.sym) { - case SDLK_UP: - return Up; - case SDLK_DOWN: - return Down; - case SDLK_LEFT: - return Left; - case SDLK_RIGHT: - return Right; - case SDLK_RETURN: - return EXE; - case SDLK_ESCAPE: - return Back; - case SDLK_TAB: - return Toolbox; - case SDLK_BACKSPACE: - return Backspace; case SDLK_AC_BACK: return Termination; } From 90f2e5beed7f0a23db50b72e6de79a7fa147d03c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Thu, 27 Feb 2020 11:26:07 +0100 Subject: [PATCH 33/33] [ion/sdl] Do not process more than one buffered event Scenario: Make an infinite loop script (while 1 : 1+1) and run it. Input 1234567 then press Back to interrupt the infinite loop -> the script execution stops, then 1234567 is input in the input line, which is quite weird. It is even weirder when the key pressed during the [script execution / a long computation] result in navigation inside the calculator apps. --- ion/src/simulator/shared/events_keyboard.cpp | 25 ++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/ion/src/simulator/shared/events_keyboard.cpp b/ion/src/simulator/shared/events_keyboard.cpp index 913fd79e9..61fe0f972 100644 --- a/ion/src/simulator/shared/events_keyboard.cpp +++ b/ion/src/simulator/shared/events_keyboard.cpp @@ -171,6 +171,7 @@ Event getPlatformEvent() { } #endif SDL_Event event; + Event result = None; while (SDL_PollEvent(&event)) { // The while is important: it'll do a fast-pass over all useless SDL events if (event.type == SDL_WINDOWEVENT) { @@ -179,19 +180,35 @@ Event getPlatformEvent() { } } if (event.type == SDL_QUIT) { - return Termination; + result = Termination; + break; } if (event.type == SDL_KEYDOWN) { if (IonSimulatorSDLKeyDetectedByScan(event.key.keysym.scancode)) { continue; } - return eventFromSDLKeyboardEvent(event.key); + result = eventFromSDLKeyboardEvent(event.key); + break; } if (event.type == SDL_TEXTINPUT) { - return eventFromSDLTextInputEvent(event.text); + result = eventFromSDLTextInputEvent(event.text); + break; } } - return None; + if (result != None) { + /* When events are not being processed - for instance when a Python script + * is being executed - SDL puts all ingoing events in a queue. + * When events processing goes back to normal, all the queued events are + * processed, which can result in weird behaviours (for instance, really + * fast navigation in the calculator, "instantanate" text input, ...). + * These behaviours are even more visible if the script contains an infinite + * loop. + * To prevent that, we flush all queued events after encountering a non-null + * event -> the first event from the queue will still be processed, but not + * the subsequent ones. */ + SDL_FlushEvents(0, UINT32_MAX); + } + return result; } }