diff --git a/apps/code/console_controller.cpp b/apps/code/console_controller.cpp index 4316725b1..4e916904e 100644 --- a/apps/code/console_controller.cpp +++ b/apps/code/console_controller.cpp @@ -134,7 +134,27 @@ const char * ConsoleController::inputText(const char * prompt) { const char * previousPrompt = m_editCell.promptText(); m_editCell.setPrompt(promptText); - m_editCell.setText(""); + + /* The user will input some text that is stored in the edit cell. When the + * input is finished, we want to clear that cell and return the input text. + * We choose to shift the input in the edit cell and put a null char in first + * position, so that the cell seems cleared but we can still use it to store + * the input. + * To do so, we need to reduce the cell buffer size by one, so that the input + * can be shifted afterwards, even if it has maxSize. + * + * Illustration of a input sequence: + * | | | | | | | | | <- the edit cell buffer + * |0| | | | | | |X| <- clear and reduce the size + * |a|0| | | | | |X| <- user input + * |a|b|0| | | | |X| <- user input + * |a|b|c|0| | | |X| <- user input + * |a|b|c|d|0| | |X| <- last user input + * | |a|b|c|d|0| | | <- increase the buffer size and shift the user input by one + * |0|a|b|c|d|0| | | <- put a zero in first position: the edit cell seems empty + */ + + m_editCell.clearAndReduceSize(); // Reload the history m_selectableTableView.reloadData(); @@ -147,16 +167,18 @@ const char * ConsoleController::inputText(const char * prompt) { return c->inputRunLoopActive(); }, this); - // Handle the input text + // Print the prompt and the input text if (promptText != nullptr) { printText(promptText, s - promptText); } const char * text = m_editCell.text(); - printText(text, strlen(text)); + size_t textSize = strlen(text); + printText(text, textSize); flushOutputAccumulationBufferToStore(); + // Clear the edit cell and return the input + text = m_editCell.shiftCurrentTextAndClear(); m_editCell.setPrompt(previousPrompt); - m_editCell.setText(""); refreshPrintOutput(); return text; diff --git a/apps/code/console_edit_cell.cpp b/apps/code/console_edit_cell.cpp index e5a4a2708..30e0472fb 100644 --- a/apps/code/console_edit_cell.cpp +++ b/apps/code/console_edit_cell.cpp @@ -55,4 +55,21 @@ bool ConsoleEditCell::insertText(const char * text) { return m_textField.handleEventWithText(text); } +void ConsoleEditCell::clearAndReduceSize() { + setText(""); + size_t previousBufferSize = m_textField.draftTextBufferSize(); + assert(previousBufferSize > 1); + m_textField.setDraftTextBufferSize(previousBufferSize - 1); +} + +const char * ConsoleEditCell::shiftCurrentTextAndClear() { + size_t previousBufferSize = m_textField.draftTextBufferSize(); + m_textField.setDraftTextBufferSize(previousBufferSize + 1); + char * textFieldBuffer = m_textField.draftTextBuffer(); + char * newTextPosition = textFieldBuffer + 1; + strlcpy(newTextPosition, textFieldBuffer, previousBufferSize); + textFieldBuffer[0] = 0; + return newTextPosition; +} + } diff --git a/apps/code/console_edit_cell.h b/apps/code/console_edit_cell.h index fb781565e..18f16ba55 100644 --- a/apps/code/console_edit_cell.h +++ b/apps/code/console_edit_cell.h @@ -34,6 +34,8 @@ public: bool insertText(const char * text); void setPrompt(const char * prompt); const char * promptText() const { return m_promptView.text(); } + void clearAndReduceSize(); + const char * shiftCurrentTextAndClear(); private: PointerTextView m_promptView; TextField m_textField; diff --git a/escher/include/escher/text_field.h b/escher/include/escher/text_field.h index 603c66b11..4f0a8928a 100644 --- a/escher/include/escher/text_field.h +++ b/escher/include/escher/text_field.h @@ -28,6 +28,8 @@ public: void reinitDraftTextBuffer() { m_contentView.reinitDraftTextBuffer(); } bool isEditing() const override; char * draftTextBuffer() const { return const_cast(m_contentView.editedText()); } + void setDraftTextBufferSize(size_t size) { m_contentView.setDraftTextBufferSize(size); } + size_t draftTextBufferSize() const { return m_contentView.draftTextBufferSize(); } size_t draftTextLength() const; void setText(const char * text); void setEditing(bool isEditing) override { m_contentView.setEditing(isEditing); } @@ -42,8 +44,19 @@ public: bool shouldFinishEditing(Ion::Events::Event event) override; const KDFont * font() const { return m_contentView.font(); } protected: + class ContentView : public TextInput::ContentView { public: + /* In some app (ie Calculation), text fields record expression results whose + * lengths can reach 70 (ie + * [[1.234567e-123*e^(1.234567e-123*i), 1.234567e-123*e^(1.234567e-123*i)]]). + * In order to be able to record those output text, k_maxBufferSize must be + * over 70. + * Furthermore, we want ot be able to write an adjacency matrix of size 10 + * so we need at least 2 brackets + 10 * (2 brackets + 10 digits + 9 commas) + * = 212 characters. */ + constexpr static int k_maxBufferSize = 220; + ContentView(char * textBuffer, size_t textBufferSize, size_t draftTextBufferSize, const KDFont * font, float horizontalAlignment, float verticalAlignment, KDColor textColor, KDColor backgroundColor); void setBackgroundColor(KDColor backgroundColor); KDColor backgroundColor() const { return m_backgroundColor; } @@ -56,7 +69,8 @@ protected: void setText(const char * text); void setEditing(bool isEditing); void reinitDraftTextBuffer(); - void setDraftTextBufferSize(size_t size) { m_draftTextBufferSize = size; } + void setDraftTextBufferSize(size_t size) { assert(size <= k_maxBufferSize); m_draftTextBufferSize = size; } + size_t draftTextBufferSize() const { return m_draftTextBufferSize; } /* If the text to be appended is too long to be added without overflowing the * buffer, nothing is done (not even adding few letters from the text to reach * the maximum buffer capacity) and false is returned. */ @@ -67,15 +81,6 @@ protected: void willModifyTextBuffer(); void didModifyTextBuffer(); size_t deleteSelection() override; - /* In some app (ie Calculation), text fields record expression results whose - * lengths can reach 70 (ie - * [[1.234567e-123*e^(1.234567e-123*i), 1.234567e-123*e^(1.234567e-123*i)]]). - * In order to be able to record those output text, k_maxBufferSize must be - * over 70. - * Furthermore, we want ot be able to write an adjacency matrix of size 10 - * so we need at least 2 brackets + 10 * (2 brackets + 10 digits + 9 commas) - * = 212 characters. */ - constexpr static int k_maxBufferSize = 220; private: void layoutSubviews(bool force = false) override; KDRect glyphFrameAtPosition(const char * buffer, const char * position) const override; @@ -87,8 +92,10 @@ protected: KDColor m_textColor; KDColor m_backgroundColor; }; + const ContentView * nonEditableContentView() const override { return &m_contentView; } ContentView m_contentView; + private: bool privateHandleEvent(Ion::Events::Event event); bool privateHandleMoveEvent(Ion::Events::Event event);