From f3d632c462c7342742eec6ca6b85f4b3248d5227 Mon Sep 17 00:00:00 2001 From: Laury Date: Tue, 15 Feb 2022 22:24:50 +0100 Subject: [PATCH] [apps/calculation] Add a "ctrl-z" system --- apps/calculation/calculation_store.cpp | 41 +++++++++++++++---- apps/calculation/calculation_store.h | 7 +++- .../edit_expression_controller.cpp | 9 ++++ apps/calculation/edit_expression_controller.h | 1 + apps/calculation/history_controller.h | 1 + ion/include/ion/events.h | 1 + .../keyboard/layout_B2/layout_events.cpp | 4 +- .../keyboard/layout_B3/layout_events.cpp | 4 +- 8 files changed, 55 insertions(+), 13 deletions(-) diff --git a/apps/calculation/calculation_store.cpp b/apps/calculation/calculation_store.cpp index a2ae0b3e8..55a87653b 100644 --- a/apps/calculation/calculation_store.cpp +++ b/apps/calculation/calculation_store.cpp @@ -16,14 +16,24 @@ CalculationStore::CalculationStore(char * buffer, int size) : m_buffer(buffer), m_bufferSize(size), m_calculationAreaEnd(m_buffer), - m_numberOfCalculations(0) + m_numberOfCalculations(0), + m_trashIndex(-1) { assert(m_buffer != nullptr); assert(m_bufferSize > 0); } -// Returns an expiring pointer to the calculation of index i +// Returns an expiring pointer to the calculation of index i, and ignore the trash ExpiringPointer CalculationStore::calculationAtIndex(int i) { + if (m_trashIndex == -1 || i < m_trashIndex) { + return realCalculationAtIndex(i); + } else { + return realCalculationAtIndex(i + 1); + } +} + +// Returns an expiring pointer to the real calculation of index i +ExpiringPointer CalculationStore::realCalculationAtIndex(int i) { assert(i >= 0 && i < m_numberOfCalculations); // m_buffer is the address of the oldest calculation in calculation store Calculation * c = (Calculation *) m_buffer; @@ -36,12 +46,13 @@ ExpiringPointer CalculationStore::calculationAtIndex(int i) { // Pushes an expression in the store ExpiringPointer CalculationStore::push(const char * text, Context * context, HeightComputer heightComputer) { + emptyTrash(); /* Compute ans now, before the buffer is updated and before the calculation * might be deleted */ Expression ans = ansExpression(context); /* Prepare the buffer for the new calculation - *The minimal size to store the new calculation is the minimal size of a calculation plus the pointer to its end */ + * The minimal size to store the new calculation is the minimal size of a calculation plus the pointer to its end */ int minSize = Calculation::MinimalSize() + sizeof(Calculation *); assert(m_bufferSize > minSize); while (remainingBufferSize() < minSize) { @@ -132,15 +143,23 @@ ExpiringPointer CalculationStore::push(const char * text, Context * // Delete the calculation of index i void CalculationStore::deleteCalculationAtIndex(int i) { + if (m_trashIndex != -1) { + emptyTrash(); + } + m_trashIndex = i; +} + +// Delete the calculation of index i, internal algorithm +void CalculationStore::realDeleteCalculationAtIndex(int i) { assert(i >= 0 && i < m_numberOfCalculations); if (i == 0) { - ExpiringPointer lastCalculationPointer = calculationAtIndex(0); + ExpiringPointer lastCalculationPointer = realCalculationAtIndex(0); m_calculationAreaEnd = (char *)(lastCalculationPointer.pointer()); m_numberOfCalculations--; return; } - char * calcI = (char *)calculationAtIndex(i).pointer(); - char * nextCalc = (char *) calculationAtIndex(i-1).pointer(); + char * calcI = (char *)realCalculationAtIndex(i).pointer(); + char * nextCalc = (char *) realCalculationAtIndex(i-1).pointer(); assert(m_calculationAreaEnd >= nextCalc); size_t slidingSize = m_calculationAreaEnd - nextCalc; // Slide the i-1 most recent calculations right after the i+1'th @@ -200,6 +219,12 @@ bool CalculationStore::pushSerializeExpression(Expression e, char * location, ch return expressionIsPushed; } +void CalculationStore::emptyTrash() { + if (m_trashIndex != -1) { + realDeleteCalculationAtIndex(m_trashIndex); + m_trashIndex = -1; + } +} Shared::ExpiringPointer CalculationStore::emptyStoreAndPushUndef(Context * context, HeightComputer heightComputer) { @@ -211,9 +236,9 @@ Shared::ExpiringPointer CalculationStore::emptyStoreAndPushUndef(Co // Recompute memoized pointers to the calculations after index i void CalculationStore::recomputeMemoizedPointersAfterCalculationIndex(int index) { - assert(index < m_numberOfCalculations); + assert(index < numberOfCalculations()); // Clear pointer and recompute new ones - Calculation * c = calculationAtIndex(index).pointer(); + Calculation * c = realCalculationAtIndex(index).pointer(); Calculation * nextCalc; while (index != 0) { nextCalc = c->next(); diff --git a/apps/calculation/calculation_store.h b/apps/calculation/calculation_store.h index 53bc3fdf4..134a9fbb8 100644 --- a/apps/calculation/calculation_store.h +++ b/apps/calculation/calculation_store.h @@ -41,11 +41,15 @@ public: void deleteCalculationAtIndex(int i); void deleteAll(); int remainingBufferSize() const { assert(m_calculationAreaEnd >= m_buffer); return m_bufferSize - (m_calculationAreaEnd - m_buffer) - m_numberOfCalculations*sizeof(Calculation*); } - int numberOfCalculations() const { return m_numberOfCalculations; } + int numberOfCalculations() const { return m_numberOfCalculations - (m_trashIndex != -1); } Poincare::Expression ansExpression(Poincare::Context * context); int bufferSize() { return m_bufferSize; } + void reinsertTrash() { m_trashIndex = -1; } private: + void emptyTrash(); + Shared::ExpiringPointer realCalculationAtIndex(int i); + void realDeleteCalculationAtIndex(int i); class CalculationIterator { public: @@ -70,6 +74,7 @@ private: int m_bufferSize; const char * m_calculationAreaEnd; int m_numberOfCalculations; + int m_trashIndex; size_t deleteOldestCalculation(); char * addressOfPointerToCalculationOfIndex(int i) {return m_buffer + m_bufferSize - (m_numberOfCalculations - i)*sizeof(Calculation *);} diff --git a/apps/calculation/edit_expression_controller.cpp b/apps/calculation/edit_expression_controller.cpp index 7f747d359..9d999bf19 100644 --- a/apps/calculation/edit_expression_controller.cpp +++ b/apps/calculation/edit_expression_controller.cpp @@ -68,6 +68,15 @@ void EditExpressionController::memoizeInput() { *m_cacheBufferInformation = m_contentView.expressionField()->moveCursorAndDumpContent(m_cacheBuffer, k_cacheBufferSize); } +bool EditExpressionController::handleEvent(Ion::Events::Event event) { + if (event == Ion::Events::ShiftBack) { + m_historyController->reinsertTrash(); + m_historyController->reload(); + return true; + } + return false; +} + void EditExpressionController::viewWillAppear() { m_historyController->viewWillAppear(); } diff --git a/apps/calculation/edit_expression_controller.h b/apps/calculation/edit_expression_controller.h index 32a6ec84c..9e788faa3 100644 --- a/apps/calculation/edit_expression_controller.h +++ b/apps/calculation/edit_expression_controller.h @@ -31,6 +31,7 @@ public: void insertTextBody(const char * text); void restoreInput(); void memoizeInput(); + bool handleEvent(Ion::Events::Event event) override; /* TextFieldDelegate */ bool textFieldDidReceiveEvent(::TextField * textField, Ion::Events::Event event) override; diff --git a/apps/calculation/history_controller.h b/apps/calculation/history_controller.h index b919e823c..8b7c3bf53 100644 --- a/apps/calculation/history_controller.h +++ b/apps/calculation/history_controller.h @@ -35,6 +35,7 @@ public: int typeAtLocation(int i, int j) override; void setSelectedSubviewType(SubviewType subviewType, bool sameCell, int previousSelectedX = -1, int previousSelectedY = -1) override; void tableViewDidChangeSelectionAndDidScroll(SelectableTableView * t, int previousSelectedCellX, int previousSelectedCellY, bool withinTemporarySelection = false) override; + void reinsertTrash() { m_calculationStore->reinsertTrash(); } private: int storeIndex(int i) { return numberOfRows() - i - 1; } Shared::ExpiringPointer calculationAtIndex(int i); diff --git a/ion/include/ion/events.h b/ion/include/ion/events.h index 4dccae5be..394271cf2 100644 --- a/ion/include/ion/events.h +++ b/ion/include/ion/events.h @@ -142,6 +142,7 @@ constexpr Event ShiftRight = Event::ShiftKey(Keyboard::Key::Right); constexpr Event ShiftUp = Event::ShiftKey(Keyboard::Key::Up); constexpr Event ShiftDown = Event::ShiftKey(Keyboard::Key::Down); constexpr Event ShiftOK = Event::ShiftKey(Keyboard::Key::OK); +constexpr Event ShiftBack = Event::ShiftKey(Keyboard::Key::Back); constexpr Event AlphaLock = Event::ShiftKey(Keyboard::Key::Alpha); constexpr Event Cut = Event::ShiftKey(Keyboard::Key::XNT); diff --git a/ion/src/shared/keyboard/layout_B2/layout_events.cpp b/ion/src/shared/keyboard/layout_B2/layout_events.cpp index 6ff1b74b7..035d45090 100644 --- a/ion/src/shared/keyboard/layout_B2/layout_events.cpp +++ b/ion/src/shared/keyboard/layout_B2/layout_events.cpp @@ -16,7 +16,7 @@ const EventData s_dataForEvent[4 * Event::PageSize] = { T("1"), T("2"), T("3"), T("+"), T("-"), U(), T("0"), T("."), T("ᴇ"), TL(), TL(), U(), // Shift - TL(), TL(), TL(), TL(), TL(), U(), + TL(), TL(), TL(), TL(), TL(), TL(), TL(), U(), U(), U(), U(), U(), U(), U(), TL(), TL(), TL(), TL(), T("["), T("]"), T("{"), T("}"), T("_"), T("→"), @@ -61,7 +61,7 @@ const char * const s_nameForEvent[255] = { "One", "Two", "Three", "Plus", "Minus", nullptr, "Zero", "Dot", "EE", "Ans", "EXE", nullptr, //Shift, - "ShiftLeft", "ShiftUp", "ShiftDown", "ShiftRight", "ShiftOK", nullptr, + "ShiftLeft", "ShiftUp", "ShiftDown", "ShiftRight", "ShiftOK", "ShiftBack", "ShiftHome", nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, "AlphaLock", "Cut", "Copy", "Paste", "Clear", "LeftBracket", "RightBracket", "LeftBrace", "RightBrace", "Underscore", "Sto", diff --git a/ion/src/shared/keyboard/layout_B3/layout_events.cpp b/ion/src/shared/keyboard/layout_B3/layout_events.cpp index 6ccf51c3b..2ea81e4a7 100644 --- a/ion/src/shared/keyboard/layout_B3/layout_events.cpp +++ b/ion/src/shared/keyboard/layout_B3/layout_events.cpp @@ -16,7 +16,7 @@ const EventData s_dataForEvent[4 * Event::PageSize] = { T("1"), T("2"), T("3"), T("+"), T("-"), U(), T("0"), T("."), T("ᴇ"), TL(), TL(), U(), // Shift - TL(), TL(), TL(), TL(), TL(), U(), + TL(), TL(), TL(), TL(), TL(), TL(), TL(), U(), U(), U(), U(), U(), U(), U(), TL(), TL(), TL(), TL(), T("["), T("]"), T("{"), T("}"), T("_"), T("→"), @@ -61,7 +61,7 @@ const char * const s_nameForEvent[255] = { "One", "Two", "Three", "Plus", "Minus", nullptr, "Zero", "Dot", "EE", "Ans", "EXE", nullptr, //Shift, - "ShiftLeft", "ShiftUp", "ShiftDown", "ShiftRight", "ShiftOK", nullptr, + "ShiftLeft", "ShiftUp", "ShiftDown", "ShiftRight", "ShiftOK", "ShiftBack", "ShiftHome", nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, "AlphaLock", "Cut", "Copy", "Paste", "Clear", "LeftBracket", "RightBracket", "LeftBrace", "RightBrace", "Underscore", "Sto",