diff --git a/apps/statistics/multiple_data_view.cpp b/apps/statistics/multiple_data_view.cpp index 2f0203ca9..8e6def2fd 100644 --- a/apps/statistics/multiple_data_view.cpp +++ b/apps/statistics/multiple_data_view.cpp @@ -72,7 +72,7 @@ void MultipleDataView::layoutDataSubviews() { int numberDataSubviews = m_store->numberOfNonEmptySeries(); assert(numberDataSubviews > 0); KDCoordinate bannerHeight = bannerFrame().height(); - KDCoordinate subviewHeight = (bounds().height() - bannerHeight)/numberDataSubviews; + KDCoordinate subviewHeight = (bounds().height() - bannerHeight)/numberDataSubviews + 1; // +1 to make sure that all pixel rows are drawn int displayedSubviewIndex = 0; for (int i = 0; i < Store::k_numberOfSeries; i++) { if (!m_store->seriesIsEmpty(i)) { diff --git a/build/toolchain.emscripten.mak b/build/toolchain.emscripten.mak index 72d1031f5..313209791 100644 --- a/build/toolchain.emscripten.mak +++ b/build/toolchain.emscripten.mak @@ -65,7 +65,7 @@ _do_load_from_lexer \ _fun_bc_call \ _fun_builtin_var_call \ _main \ -_micropython_port_should_interrupt \ +_micropython_port_vm_hook_loop \ _mp_builtin___import__ \ _mp_builtin_input \ _mp_call_function_0 \ diff --git a/ion/src/emscripten/events_keyboard.cpp b/ion/src/emscripten/events_keyboard.cpp index fa19c3191..ce1dcc0b6 100644 --- a/ion/src/emscripten/events_keyboard.cpp +++ b/ion/src/emscripten/events_keyboard.cpp @@ -83,6 +83,13 @@ Ion::Keyboard::State Ion::Keyboard::scan() { * function setTimeout, which can be called with a value of zero. Doing so * puts the callback at the end of the queue of callbacks to be processed. */ emscripten_sleep(0); + + /* Grab this opporunity to refresh the display. In practice, this routine is + * called from micropython_port_vm_hook_loop once in a while, so this gives us + * an opportunity to refresh the display during the execution of a + * long-running Python script. */ + Ion::Display::Emscripten::refresh(); + return sKeyboardState; } diff --git a/poincare/include/poincare/char_layout.h b/poincare/include/poincare/char_layout.h index f06808ded..874f9a720 100644 --- a/poincare/include/poincare/char_layout.h +++ b/poincare/include/poincare/char_layout.h @@ -17,6 +17,7 @@ public: // CharLayout virtual void setChar(char c) { m_char = c; } + char character() const { return m_char; } const KDFont * font() const { return m_font; } void setFont(const KDFont * font) { m_font = font; } @@ -24,6 +25,7 @@ public: void moveCursorLeft(LayoutCursor * cursor, bool * shouldRecomputeLayout) override; void moveCursorRight(LayoutCursor * cursor, bool * shouldRecomputeLayout) override; int serialize(char * buffer, int bufferSize, Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const override; + bool isChar() const override { return true; } bool isCollapsable(int * numberOfOpenParenthesis, bool goingLeft) const override; // TreeNode @@ -55,8 +57,10 @@ private: class CharLayout final : public Layout { public: + CharLayout(const CharLayoutNode * n) : Layout(n) {} CharLayout(char c, const KDFont * font = KDFont::LargeFont); const KDFont * font() const { return const_cast(this)->node()->font(); } + char character() const {return const_cast(this)->node()->character();} private: using Layout::node; CharLayoutNode * node() { return static_cast(Layout::node());} diff --git a/poincare/include/poincare/layout.h b/poincare/include/poincare/layout.h index c8f2c6554..acad70aba 100644 --- a/poincare/include/poincare/layout.h +++ b/poincare/include/poincare/layout.h @@ -45,6 +45,7 @@ public: bool isMatrix() const { return const_cast(this)->node()->isMatrix(); } bool isVerticalOffset() const { return const_cast(this)->node()->isVerticalOffset(); } bool isLeftParenthesis() const { return const_cast(this)->node()->isLeftParenthesis(); } + bool isChar() const { return const_cast(this)->node()->isChar(); } bool isCollapsable(int * numberOfOpenParenthesis, bool goingLeft) const { return const_cast(this)->node()->isCollapsable(numberOfOpenParenthesis, goingLeft); } int leftCollapsingAbsorbingChildIndex() const { return const_cast(this)->node()->leftCollapsingAbsorbingChildIndex(); } int rightCollapsingAbsorbingChildIndex() const { return const_cast(this)->node()->rightCollapsingAbsorbingChildIndex(); } diff --git a/poincare/include/poincare/layout_node.h b/poincare/include/poincare/layout_node.h index c474c1c59..f9aa51d50 100644 --- a/poincare/include/poincare/layout_node.h +++ b/poincare/include/poincare/layout_node.h @@ -103,6 +103,7 @@ public: virtual bool isRightBracket() const { return false; } virtual bool isEmpty() const { return false; } virtual bool isMatrix() const { return false; } + virtual bool isChar() const { return false; } virtual bool hasUpperLeftIndex() const { return false; } virtual char XNTChar() const { LayoutNode * p = parent(); diff --git a/poincare/src/char_layout.cpp b/poincare/src/char_layout.cpp index c4813bbae..6f3431924 100644 --- a/poincare/src/char_layout.cpp +++ b/poincare/src/char_layout.cpp @@ -32,17 +32,35 @@ int CharLayoutNode::serialize(char * buffer, int bufferSize, Preferences::PrintF } bool CharLayoutNode::isCollapsable(int * numberOfOpenParenthesis, bool goingLeft) const { - if (*numberOfOpenParenthesis <= 0 - && (m_char == '+' - || m_char == '-' + if (*numberOfOpenParenthesis <= 0) { + if (m_char == '+' || m_char == '*' || m_char == Ion::Charset::MultiplicationSign || m_char == Ion::Charset::MiddleDot || m_char == Ion::Charset::Sto || m_char == '=' - || m_char == ',')) - { - return false; + || m_char == ',') + { + return false; + } + if (m_char == '-') { + /* If the expression is like 3E-200, we want '-' to be collapsable. + * Otherwise, '-' is not collapsable. */ + Layout thisRef = CharLayout(this); + Layout parent = thisRef.parent(); + if (!parent.isUninitialized()) { + int indexOfThis = parent.indexOfChild(thisRef); + if (indexOfThis > 0) { + Layout leftBrother = parent.childAtIndex(indexOfThis-1); + if (leftBrother.isChar() + && static_cast(leftBrother).character() == Ion::Charset::Exponent) + { + return true; + } + } + } + return false; + } } return true; } diff --git a/python/port/helpers.cpp b/python/port/helpers.cpp index 5da28c6a5..f49c06e3d 100644 --- a/python/port/helpers.cpp +++ b/python/port/helpers.cpp @@ -4,17 +4,28 @@ extern "C" { #include "mphalport.h" } -bool micropython_port_should_interrupt() { +void micropython_port_vm_hook_loop() { + /* This function is called very frequently by the MicroPython engine. We grab + * this opportunity to interrupt execution and/or refresh the display on + * platforms that need it. */ + + /* Doing too many things here slows down Python execution quite a lot. So we + * only do things once in a while and return as soon as possible otherwise. */ static int c = 0; - c++; - if (c%20000 != 0) { - return false; + + c = (c + 1) % 20000; + if (c != 0) { + return; } - c = 0; - Ion::Keyboard::State scan = Ion::Keyboard::scan(); - if (scan.keyDown((Ion::Keyboard::Key)mp_interrupt_char)) { + + /* Check if the user asked for an interruption from the keyboard */ + if (micropython_port_should_interrupt()) { mp_keyboard_interrupt(); - return true; } - return false; +} + +bool micropython_port_should_interrupt() { + Ion::Keyboard::State scan = Ion::Keyboard::scan(); + Ion::Keyboard::Key interruptKey = static_cast(mp_interrupt_char); + return scan.keyDown(interruptKey); } diff --git a/python/port/helpers.h b/python/port/helpers.h index 76abbde0d..73ed4c3b4 100644 --- a/python/port/helpers.h +++ b/python/port/helpers.h @@ -6,8 +6,7 @@ extern "C" { #endif #include -/* should_interrupt effectively does something once every 20000 calls. It checks - * if a key is down to raise an interruption flag. */ +void micropython_port_vm_hook_loop(); bool micropython_port_should_interrupt(); #ifdef __cplusplus diff --git a/python/port/mpconfigport.h b/python/port/mpconfigport.h index ff7fff87d..3ab2ab9b3 100644 --- a/python/port/mpconfigport.h +++ b/python/port/mpconfigport.h @@ -90,7 +90,7 @@ // (This scheme won't work if we want to mix Thumb and normal ARM code.) #define MICROPY_MAKE_POINTER_CALLABLE(p) (p) -#define MICROPY_VM_HOOK_LOOP micropython_port_should_interrupt(); +#define MICROPY_VM_HOOK_LOOP micropython_port_vm_hook_loop(); typedef intptr_t mp_int_t; // must be pointer size typedef uintptr_t mp_uint_t; // must be pointer size