mirror of
https://github.com/UpsilonNumworks/Upsilon.git
synced 2026-03-18 21:30:38 +01:00
[apps][escher] Add methods 'handleEventWithText' in TextField and
TextArea to fix bug in probability (adding a toolbox text from the calculations controller)
This commit is contained in:
committed by
EmilieNumworks
parent
7fcf77ce23
commit
576caa039f
@@ -61,8 +61,7 @@ const char * EditExpressionController::textBody() {
|
||||
void EditExpressionController::insertTextBody(const char * text) {
|
||||
TextField * tf = ((ContentView *)view())->textField();
|
||||
tf->setEditing(true, false);
|
||||
tf->insertTextAtLocation(text, tf->cursorLocation());
|
||||
tf->setCursorLocation(tf->cursorLocation() + strlen(text));
|
||||
tf->handleEventWithText(text);
|
||||
}
|
||||
|
||||
bool EditExpressionController::handleEvent(Ion::Events::Event event) {
|
||||
|
||||
@@ -13,9 +13,7 @@ bool TextField::handleEvent(Ion::Events::Event event) {
|
||||
return false;
|
||||
}
|
||||
if (event == Ion::Events::Ans) {
|
||||
insertTextAtLocation("ans", cursorLocation());
|
||||
setCursorLocation(cursorLocation() + strlen("ans"));
|
||||
return true;
|
||||
return handleEventWithText("ans");
|
||||
}
|
||||
if (isEditing() && draftTextLength() == 0 &&
|
||||
(event == Ion::Events::Multiplication ||
|
||||
@@ -24,8 +22,7 @@ bool TextField::handleEvent(Ion::Events::Event event) {
|
||||
event == Ion::Events::Square ||
|
||||
event == Ion::Events::Division ||
|
||||
event == Ion::Events::Sto)) {
|
||||
insertTextAtLocation("ans", cursorLocation());
|
||||
setCursorLocation(cursorLocation() + strlen("ans"));
|
||||
handleEventWithText("ans");
|
||||
}
|
||||
return(::TextField::handleEvent(event));
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
#include "app.h"
|
||||
#include "../apps_container.h"
|
||||
#include "code_icon.h"
|
||||
#include "../shared/toolbox_helpers.h"
|
||||
#include "../i18n.h"
|
||||
|
||||
namespace Code {
|
||||
@@ -80,27 +79,12 @@ App::App(Container * container, Snapshot * snapshot) :
|
||||
m_codeStackViewController(&m_modalViewController, &m_listFooter),
|
||||
m_toolboxActionForTextArea([](void * sender, const char * text) {
|
||||
TextArea * textArea = static_cast<TextArea *>(sender);
|
||||
int previousCursorLocation = textArea->cursorLocation();
|
||||
if (textArea->insertTextWithIndentation(text)) {
|
||||
// insertText() also moves the cursor. We need to re-move it to the
|
||||
// position we want (which is after the first parenthesis or before the
|
||||
// first point).
|
||||
int deltaCursorLocation = - textArea->cursorLocation() + previousCursorLocation + Shared::ToolboxHelpers::CursorIndexInCommand(text);
|
||||
// WARNING: This is a dirty and only works because the cursor location we
|
||||
// want is always on the first line of the text we insert. Because of the
|
||||
// auto indentation, it would be difficult to compute the wanted cursor
|
||||
// location on other lines of the text.
|
||||
textArea->moveCursor(deltaCursorLocation);
|
||||
}}),
|
||||
textArea->handleEventWithText(text, true);
|
||||
}),
|
||||
m_toolboxActionForTextField([](void * sender, const char * text) {
|
||||
TextField * textField = static_cast<TextField *>(sender);
|
||||
if (!textField->isEditing()) {
|
||||
textField->setEditing(true);
|
||||
}
|
||||
int newCursorLocation = textField->cursorLocation() + Shared::ToolboxHelpers::CursorIndexInCommand(text);
|
||||
if (textField->insertTextAtLocation(text, textField->cursorLocation())) {
|
||||
textField->setCursorLocation(newCursorLocation);
|
||||
}}),
|
||||
textField->handleEventWithText(text);
|
||||
}),
|
||||
m_variableBoxController(&m_menuController, snapshot->scriptStore())
|
||||
{
|
||||
}
|
||||
|
||||
@@ -276,12 +276,7 @@ bool ConsoleController::textFieldDidReceiveEvent(TextField * textField, Ion::Eve
|
||||
if (pythonText == nullptr) {
|
||||
return false;
|
||||
}
|
||||
if (textField->insertTextAtLocation(pythonText, textField->cursorLocation())) {
|
||||
textField->setCursorLocation(textField->cursorLocation()+strlen(pythonText));
|
||||
if (pythonText[strlen(pythonText)-1] == ')') {
|
||||
textField->setCursorLocation(textField->cursorLocation()-1);
|
||||
}
|
||||
}
|
||||
textField->handleEventWithText(pythonText);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -52,10 +52,7 @@ void ConsoleEditCell::setPrompt(const char * prompt) {
|
||||
}
|
||||
|
||||
bool ConsoleEditCell::insertText(const char * text) {
|
||||
bool didCopy = m_textField.insertTextAtLocation(text, m_textField.cursorLocation());
|
||||
if (didCopy) {
|
||||
m_textField.setCursorLocation(m_textField.cursorLocation() + strlen(text));
|
||||
}
|
||||
return didCopy;
|
||||
}
|
||||
return m_textField.handleEventWithText(text);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -33,7 +33,7 @@ void EditorController::didBecomeFirstResponder() {
|
||||
}
|
||||
|
||||
void EditorController::viewWillAppear() {
|
||||
m_textArea.moveCursor(strlen(m_textArea.text() - m_textArea.cursorLocation()));
|
||||
m_textArea.setCursorLocation(strlen(m_textArea.text()));
|
||||
}
|
||||
|
||||
void EditorController::viewDidDisappear() {
|
||||
@@ -47,12 +47,7 @@ bool EditorController::textAreaShouldFinishEditing(TextArea * textArea, Ion::Eve
|
||||
bool EditorController::textAreaDidReceiveEvent(TextArea * textArea, Ion::Events::Event event) {
|
||||
const char * pythonText = Helpers::PythonTextForEvent(event);
|
||||
if (pythonText != nullptr) {
|
||||
if (!textArea->insertText(pythonText)) {
|
||||
return false;
|
||||
}
|
||||
if (pythonText[strlen(pythonText)-1] == ')') {
|
||||
textArea->moveCursor(-1);
|
||||
}
|
||||
textArea->handleEventWithText(pythonText);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -84,10 +79,13 @@ bool EditorController::textAreaDidReceiveEvent(TextArea * textArea, Ion::Events:
|
||||
indentationIndex++;
|
||||
}
|
||||
}
|
||||
textArea->insertText("\n");
|
||||
char indentationBuffer[indentationSize+2]; // FIXME
|
||||
indentationBuffer[0] = '\n';
|
||||
for (int i = 0; i < indentationSize; i++) {
|
||||
textArea->insertText(" ");
|
||||
indentationBuffer[i+1] = ' ';
|
||||
}
|
||||
indentationBuffer[indentationSize+1] = 0;
|
||||
textArea->handleEventWithText(indentationBuffer);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -118,9 +116,12 @@ bool EditorController::textAreaDidReceiveEvent(TextArea * textArea, Ion::Events:
|
||||
charBeforeCursorIndex--;
|
||||
}
|
||||
if (charBeforeCursorIndex >= 0 && text[charBeforeCursorIndex] == '\n') {
|
||||
char indentationBuffer[k_indentationSpacesNumber+1];
|
||||
for (int i = 0; i < k_indentationSpacesNumber; i++) {
|
||||
textArea->insertText(" ");
|
||||
indentationBuffer[i] = ' ';
|
||||
}
|
||||
indentationBuffer[k_indentationSpacesNumber] = 0;
|
||||
textArea->handleEventWithText(indentationBuffer);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -336,7 +336,7 @@ bool MenuController::textFieldDidAbortEditing(TextField * textField, const char
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MenuController::textFieldDidHandleEvent(TextField * textField, Ion::Events::Event event, bool returnValue, bool textHasChanged) {
|
||||
bool MenuController::textFieldDidHandleEvent(TextField * textField, bool returnValue, bool textHasChanged) {
|
||||
int scriptExtensionLength = strlen(ScriptStore::k_scriptExtension);
|
||||
if (textField->isEditing() && textField->cursorLocation() > textField->draftTextLength() - scriptExtensionLength) {
|
||||
textField->setCursorLocation(textField->draftTextLength() - scriptExtensionLength);
|
||||
|
||||
@@ -57,7 +57,7 @@ public:
|
||||
bool textFieldDidReceiveEvent(TextField * textField, Ion::Events::Event event) override;
|
||||
bool textFieldDidFinishEditing(TextField * textField, const char * text, Ion::Events::Event event) override;
|
||||
bool textFieldDidAbortEditing(TextField * textField, const char * text) override;
|
||||
bool textFieldDidHandleEvent(TextField * textField, Ion::Events::Event event, bool returnValue, bool textHasChanged) override;
|
||||
bool textFieldDidHandleEvent(TextField * textField, bool returnValue, bool textHasChanged) override;
|
||||
Toolbox * toolboxForTextField(TextField * textField) override { return nullptr; }
|
||||
|
||||
/* ButtonRowDelegate */
|
||||
|
||||
@@ -122,19 +122,11 @@ void VariableBoxController::ContentViewController::insertTextInCaller(const char
|
||||
char commandBuffer[strlen(text)+1];
|
||||
Shared::ToolboxHelpers::TextToInsertForCommandText(text, commandBuffer);
|
||||
if (m_textFieldCaller != nullptr) {
|
||||
if (!m_textFieldCaller->isEditing()) {
|
||||
m_textFieldCaller->setEditing(true);
|
||||
}
|
||||
int previousCursorLocation = m_textFieldCaller->cursorLocation();
|
||||
m_textFieldCaller->insertTextAtLocation(commandBuffer, previousCursorLocation);
|
||||
m_textFieldCaller->setCursorLocation(previousCursorLocation + Shared::ToolboxHelpers::CursorIndexInCommand(commandBuffer));
|
||||
m_textFieldCaller->handleEventWithText(commandBuffer);
|
||||
return;
|
||||
}
|
||||
if (m_textAreaCaller != nullptr) {
|
||||
int previousCursorLocation = m_textAreaCaller->cursorLocation();
|
||||
m_textAreaCaller->insertText(commandBuffer);
|
||||
int deltaCursorLocation = - m_textAreaCaller->cursorLocation() + previousCursorLocation + Shared::ToolboxHelpers::CursorIndexInCommand(commandBuffer);
|
||||
m_textAreaCaller->moveCursor(deltaCursorLocation);
|
||||
m_textAreaCaller->handleEventWithText(commandBuffer);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -113,14 +113,9 @@ bool MathToolbox::selectLeaf(ToolboxMessageTree * selectedMessageTree) {
|
||||
m_selectableTableView.deselectTable();
|
||||
ToolboxMessageTree * messageTree = selectedMessageTree;
|
||||
const char * editedText = I18n::translate(messageTree->insertedText());
|
||||
if (!sender()->isEditing()) {
|
||||
sender()->setEditing(true);
|
||||
}
|
||||
char strippedEditedText[strlen(editedText)];
|
||||
Shared::ToolboxHelpers::TextToInsertForCommandMessage(messageTree->insertedText(), strippedEditedText);
|
||||
sender()->insertTextAtLocation(strippedEditedText, sender()->cursorLocation());
|
||||
int newCursorLocation = sender()->cursorLocation() + Shared::ToolboxHelpers::CursorIndexInCommand(strippedEditedText);
|
||||
sender()->setCursorLocation(newCursorLocation);
|
||||
sender()->handleEventWithText(strippedEditedText);
|
||||
app()->dismissModalViewController();
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -206,7 +206,7 @@ void CalculationController::willDisplayCellAtLocation(HighlightCell * cell, int
|
||||
}
|
||||
}
|
||||
|
||||
bool CalculationController::textFieldDidHandleEvent(::TextField * textField, Ion::Events::Event event, bool returnValue, bool textHasChanged) {
|
||||
bool CalculationController::textFieldDidHandleEvent(::TextField * textField, bool returnValue, bool textHasChanged) {
|
||||
if (returnValue && textHasChanged) {
|
||||
/* We do not reload the responder because the first responder might be the
|
||||
* toolbox (or the variable box) and reloading the responder would corrupt
|
||||
|
||||
@@ -40,7 +40,7 @@ public:
|
||||
void willDisplayCellAtLocation(HighlightCell * cell, int i, int j) override;
|
||||
|
||||
/* TextField delegate */
|
||||
bool textFieldDidHandleEvent(TextField * textField, Ion::Events::Event event, bool returnValue, bool textHasChanged) override;
|
||||
bool textFieldDidHandleEvent(TextField * textField, bool returnValue, bool textHasChanged) override;
|
||||
bool textFieldShouldFinishEditing(TextField * textField, Ion::Events::Event event) override;
|
||||
bool textFieldDidFinishEditing(TextField * textField, const char * text, Ion::Events::Event event) override;
|
||||
|
||||
|
||||
@@ -112,8 +112,7 @@ bool SequenceToolbox::selectAddedCell(int selectedRow){
|
||||
currentChar += strlen(subscriptLayout->text());
|
||||
buffer[currentChar++] = ')';
|
||||
buffer[currentChar] = 0;
|
||||
sender()->insertTextAtLocation(buffer, sender()->cursorLocation());
|
||||
sender()->setCursorLocation(sender()->cursorLocation()+currentChar);
|
||||
sender()->handleEventWithText(buffer);
|
||||
app()->dismissModalViewController();
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -102,9 +102,7 @@ bool TextFieldDelegateApp::textFieldDidReceiveEvent(TextField * textField, Ion::
|
||||
textField->setEditing(true);
|
||||
}
|
||||
const char * xnt = privateXNT(textField);
|
||||
textField->insertTextAtLocation(xnt, textField->cursorLocation());
|
||||
textField->setCursorLocation(textField->cursorLocation()+strlen(xnt));
|
||||
return true;
|
||||
return textField->handleEventWithText(xnt);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -65,11 +65,7 @@ bool VariableBoxController::ContentViewController::handleEvent(Ion::Events::Even
|
||||
char label[3];
|
||||
putLabelAtIndexInBuffer(selectedRow(), label);
|
||||
const char * editedText = label;
|
||||
if (!m_textFieldCaller->isEditing()) {
|
||||
m_textFieldCaller->setEditing(true);
|
||||
}
|
||||
m_textFieldCaller->insertTextAtLocation(editedText, m_textFieldCaller->cursorLocation());
|
||||
m_textFieldCaller->setCursorLocation(m_textFieldCaller->cursorLocation() + strlen(editedText));
|
||||
m_textFieldCaller->handleEventWithText(editedText);
|
||||
#if MATRIX_VARIABLES
|
||||
m_selectableTableView.deselectTable();
|
||||
m_currentPage = Page::RootMenu;
|
||||
|
||||
@@ -67,6 +67,7 @@ objs += $(addprefix escher/src/,\
|
||||
text_cursor_view.o\
|
||||
text_area.o\
|
||||
text_field.o\
|
||||
text_input_helpers.o\
|
||||
text_view.o\
|
||||
tiled_view.o\
|
||||
timer.o\
|
||||
|
||||
@@ -63,6 +63,7 @@
|
||||
#include <escher/text_area_delegate.h>
|
||||
#include <escher/text_field.h>
|
||||
#include <escher/text_field_delegate.h>
|
||||
#include <escher/text_input_helpers.h>
|
||||
#include <escher/text_view.h>
|
||||
#include <escher/tab_view_controller.h>
|
||||
#include <escher/tab_view_data_source.h>
|
||||
|
||||
@@ -15,14 +15,15 @@ public:
|
||||
void setDelegate(TextAreaDelegate * delegate) { m_delegate = delegate; }
|
||||
Toolbox * toolbox() override;
|
||||
bool handleEvent(Ion::Events::Event event) override;
|
||||
bool handleEventWithText(const char * text, bool indentation = false);
|
||||
void setText(char * textBuffer, size_t textBufferSize);
|
||||
bool insertText(const char * textBuffer) { return m_contentView.insertText(textBuffer); }
|
||||
bool insertTextWithIndentation(const char * textBuffer);
|
||||
bool insertTextAtLocation(const char * textBuffer, int location) { return m_contentView.insertTextAtLocation(textBuffer, location); }
|
||||
bool insertTextWithIndentation(const char * textBuffer, int location);
|
||||
int indentationBeforeCursor() const;
|
||||
void removeChar() { m_contentView.removeChar(); }
|
||||
bool removeChar();
|
||||
const char * text() const { return m_contentView.text(); }
|
||||
int cursorLocation() const { return m_contentView.cursorLocation(); }
|
||||
void moveCursor(int deltaX);
|
||||
bool setCursorLocation(int location);
|
||||
private:
|
||||
class Text {
|
||||
public:
|
||||
@@ -97,8 +98,8 @@ private:
|
||||
const char * text() const;
|
||||
const Text * getText() const { return &m_text; }
|
||||
int cursorLocation() const { return m_cursorIndex; }
|
||||
bool insertText(const char * text);
|
||||
void moveCursorIndex(int deltaX);
|
||||
bool insertTextAtLocation(const char * text, int location);
|
||||
void setCursorLocation(int cursorLocation);
|
||||
void moveCursorGeo(int deltaX, int deltaY);
|
||||
void removeChar();
|
||||
bool removeEndOfLine();
|
||||
|
||||
@@ -30,6 +30,7 @@ public:
|
||||
* the maximum buffer capacity) and false is returned. */
|
||||
bool insertTextAtLocation(const char * text, int location);
|
||||
KDSize minimalSizeForOptimalDisplay() const override;
|
||||
bool handleEventWithText(const char * text);
|
||||
bool handleEvent(Ion::Events::Event event) override;
|
||||
bool textFieldShouldFinishEditing(Ion::Events::Event event);
|
||||
constexpr static int maxBufferSize() {
|
||||
|
||||
@@ -9,7 +9,7 @@ public:
|
||||
virtual bool textFieldDidReceiveEvent(TextField * textField, Ion::Events::Event event) = 0;
|
||||
virtual bool textFieldDidFinishEditing(TextField * textField, const char * text, Ion::Events::Event event) { return false; };
|
||||
virtual bool textFieldDidAbortEditing(TextField * textField, const char * text) {return false;};
|
||||
virtual bool textFieldDidHandleEvent(TextField * textField, Ion::Events::Event event, bool returnValue, bool textHasChanged) { return returnValue; };
|
||||
virtual bool textFieldDidHandleEvent(TextField * textField, bool returnValue, bool textHasChanged) { return returnValue; };
|
||||
virtual Toolbox * toolboxForTextField(TextField * textField) = 0;
|
||||
};
|
||||
|
||||
|
||||
16
escher/include/escher/text_input_helpers.h
Normal file
16
escher/include/escher/text_input_helpers.h
Normal file
@@ -0,0 +1,16 @@
|
||||
#ifndef ESCHER_TEXT_INPUT_HELPERS_H
|
||||
#define ESCHER_TEXT_INPUT_HELPERS_H
|
||||
|
||||
#include <escher/i18n.h>
|
||||
|
||||
namespace TextInputHelpers {
|
||||
|
||||
int CursorIndexInCommand(const char * text);
|
||||
/* Returns the index of the cursor position in a Command, which is the smallest
|
||||
* index between :
|
||||
* - After the first open parenthesis
|
||||
* - The end of the text */
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,5 +1,6 @@
|
||||
#include <escher/text_area.h>
|
||||
#include <escher/clipboard.h>
|
||||
#include <escher/text_input_helpers.h>
|
||||
|
||||
#include <stddef.h>
|
||||
#include <assert.h>
|
||||
@@ -227,18 +228,18 @@ const char * TextArea::TextArea::ContentView::text() const {
|
||||
return m_text.text();
|
||||
}
|
||||
|
||||
bool TextArea::TextArea::ContentView::insertText(const char * text) {
|
||||
bool TextArea::TextArea::ContentView::insertTextAtLocation(const char * text, int location) {
|
||||
int textSize = strlen(text);
|
||||
if (m_text.textLength() + textSize >= m_text.bufferSize() || textSize == 0) {
|
||||
return false;
|
||||
}
|
||||
bool lineBreak = false;
|
||||
int currentLocation = location;
|
||||
while (*text != 0) {
|
||||
lineBreak |= *text == '\n';
|
||||
m_text.insertChar(*text++, m_cursorIndex++);
|
||||
m_text.insertChar(*text++, currentLocation++);
|
||||
}
|
||||
layoutSubviews(); // Reposition the cursor
|
||||
markRectAsDirty(dirtyRectFromCursorPosition(m_cursorIndex-1, lineBreak));
|
||||
markRectAsDirty(dirtyRectFromCursorPosition(currentLocation-1, lineBreak));
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -295,14 +296,10 @@ void TextArea::TextArea::ContentView::moveCursorGeo(int deltaX, int deltaY) {
|
||||
layoutSubviews();
|
||||
}
|
||||
|
||||
void TextArea::TextArea::ContentView::moveCursorIndex(int deltaX) {
|
||||
assert(deltaX == -1 || deltaX == 1);
|
||||
if (deltaX == -1 && m_cursorIndex>0) {
|
||||
m_cursorIndex--;
|
||||
}
|
||||
if (deltaX == 1 && m_text[m_cursorIndex] != 0) {
|
||||
m_cursorIndex++;
|
||||
}
|
||||
void TextArea::TextArea::ContentView::setCursorLocation(int location) {
|
||||
int adjustedLocation = location < 0 ? 0 : location;
|
||||
adjustedLocation = adjustedLocation > (signed int)m_text.textLength() ? (signed int)m_text.textLength() : adjustedLocation;
|
||||
m_cursorIndex = adjustedLocation;
|
||||
layoutSubviews();
|
||||
}
|
||||
|
||||
@@ -334,35 +331,44 @@ Toolbox * TextArea::toolbox() {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool TextArea::handleEventWithText(const char * text, bool indentation) {
|
||||
int nextCursorLocation = cursorLocation();
|
||||
if ((indentation && insertTextWithIndentation(text, cursorLocation())) || insertTextAtLocation(text, cursorLocation())) {
|
||||
nextCursorLocation += TextInputHelpers::CursorIndexInCommand(text);
|
||||
}
|
||||
setCursorLocation(nextCursorLocation);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TextArea::handleEvent(Ion::Events::Event event) {
|
||||
if (m_delegate != nullptr && m_delegate->textAreaDidReceiveEvent(this, event)) {
|
||||
} else if (Responder::handleEvent(event)) {
|
||||
// The only event Responder handles is 'Toolbox' displaying.
|
||||
return true;
|
||||
} else if (event == Ion::Events::Left) {
|
||||
m_contentView.moveCursorIndex(-1);
|
||||
return setCursorLocation(cursorLocation()-1);
|
||||
} else if (event == Ion::Events::Right) {
|
||||
m_contentView.moveCursorIndex(1);
|
||||
return setCursorLocation(cursorLocation()+1);
|
||||
} else if (event == Ion::Events::Up) {
|
||||
m_contentView.moveCursorGeo(0, -1);
|
||||
} else if (event == Ion::Events::Down) {
|
||||
m_contentView.moveCursorGeo(0, 1);
|
||||
} else if (event == Ion::Events::ShiftLeft) {
|
||||
m_contentView.moveCursorGeo(-INT_MAX/2, 0);
|
||||
m_contentView.moveCursorGeo(-INT_MAX/2, 0);
|
||||
} else if (event == Ion::Events::ShiftRight) {
|
||||
m_contentView.moveCursorGeo(INT_MAX/2, 0);
|
||||
m_contentView.moveCursorGeo(INT_MAX/2, 0);
|
||||
} else if (event == Ion::Events::Backspace) {
|
||||
removeChar();
|
||||
return removeChar();
|
||||
} else if (event.hasText()) {
|
||||
insertText(event.text());
|
||||
return handleEventWithText(event.text());
|
||||
} else if (event == Ion::Events::EXE) {
|
||||
insertText("\n");
|
||||
return handleEventWithText("\n");
|
||||
} else if (event == Ion::Events::Clear) {
|
||||
if (!m_contentView.removeEndOfLine()) {
|
||||
m_contentView.removeStartOfLine();
|
||||
}
|
||||
} else if (event == Ion::Events::Paste) {
|
||||
insertText(Clipboard::sharedClipboard()->storedText());
|
||||
return handleEventWithText(Clipboard::sharedClipboard()->storedText());
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
@@ -382,9 +388,9 @@ void TextArea::setText(char * textBuffer, size_t textBufferSize) {
|
||||
m_contentView.moveCursorGeo(0, 0);
|
||||
}
|
||||
|
||||
bool TextArea::insertTextWithIndentation(const char * textBuffer) {
|
||||
bool TextArea::insertTextWithIndentation(const char * textBuffer, int location) {
|
||||
int indentation = indentationBeforeCursor();
|
||||
char spaceString[indentation+1];
|
||||
char spaceString[indentation+1]; // WOUHOU
|
||||
for (int i = 0; i < indentation; i++) {
|
||||
spaceString[i] = ' ';
|
||||
}
|
||||
@@ -400,11 +406,13 @@ bool TextArea::insertTextWithIndentation(const char * textBuffer) {
|
||||
if (m_contentView.getText()->textLength() + textSize + totalIndentationSize >= m_contentView.getText()->bufferSize() || textSize == 0) {
|
||||
return false;
|
||||
}
|
||||
int currentLocation = location;
|
||||
for (size_t i = 0; i < strlen(textBuffer); i++) {
|
||||
const char charString[] = {textBuffer[i], 0};
|
||||
insertText(charString);
|
||||
insertTextAtLocation(charString, currentLocation++);
|
||||
if (textBuffer[i] == '\n') {
|
||||
insertText(spaceString);
|
||||
insertTextAtLocation(spaceString, currentLocation);
|
||||
currentLocation += strlen(spaceString);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
@@ -424,11 +432,14 @@ int TextArea::indentationBeforeCursor() const {
|
||||
return indentationSize;
|
||||
}
|
||||
|
||||
void TextArea::moveCursor(int deltaX) {
|
||||
int sign = deltaX > 0? 1 : -1;
|
||||
int numberSteps = deltaX * sign;
|
||||
for (int i = 0; i < numberSteps; i++) {
|
||||
m_contentView.moveCursorIndex(sign);
|
||||
}
|
||||
bool TextArea::setCursorLocation(int location) {
|
||||
m_contentView.setCursorLocation(location);
|
||||
scrollToContentRect(m_contentView.cursorRect(), true);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TextArea::removeChar() {
|
||||
m_contentView.removeChar();
|
||||
scrollToContentRect(m_contentView.cursorRect(), true);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#include <escher/text_field.h>
|
||||
#include <escher/text_input_helpers.h>
|
||||
#include <escher/clipboard.h>
|
||||
#include <assert.h>
|
||||
|
||||
@@ -277,10 +278,6 @@ bool TextField::insertTextAtLocation(const char * text, int location) {
|
||||
}
|
||||
|
||||
bool TextField::privateHandleEvent(Ion::Events::Event event) {
|
||||
assert(m_delegate != nullptr);
|
||||
if (m_delegate->textFieldDidReceiveEvent(this, event)) {
|
||||
return true;
|
||||
}
|
||||
if (Responder::handleEvent(event)) {
|
||||
/* The only event Responder handles is 'Toolbox' displaying. In that case,
|
||||
* the text field is forced into editing mode. */
|
||||
@@ -342,20 +339,6 @@ bool TextField::privateHandleEvent(Ion::Events::Event event) {
|
||||
deleteCharPrecedingCursor();
|
||||
return true;
|
||||
}
|
||||
if (event.hasText()) {
|
||||
if (!isEditing()) {
|
||||
setEditing(true);
|
||||
}
|
||||
int nextCursorLocation = draftTextLength();
|
||||
if (insertTextAtLocation(event.text(), cursorLocation())) {
|
||||
/* All events whose text is longer than 2 have parenthesis. In these cases,
|
||||
* we want to position the cursor before the last parenthesis */
|
||||
int cursorDelta = strlen(event.text()) > 2 ? -1 : 0;
|
||||
nextCursorLocation = cursorLocation() + strlen(event.text()) + cursorDelta;
|
||||
}
|
||||
setCursorLocation(nextCursorLocation);
|
||||
return true;
|
||||
}
|
||||
if (event == Ion::Events::Back && isEditing()) {
|
||||
setEditing(false);
|
||||
reloadScroll();
|
||||
@@ -377,18 +360,6 @@ bool TextField::privateHandleEvent(Ion::Events::Event event) {
|
||||
setEditing(true, true);
|
||||
return true;
|
||||
}
|
||||
if (event == Ion::Events::Paste) {
|
||||
if (!isEditing()) {
|
||||
setEditing(true);
|
||||
}
|
||||
int nextCursorLocation = draftTextLength();
|
||||
if (insertTextAtLocation(Clipboard::sharedClipboard()->storedText(), cursorLocation())) {
|
||||
nextCursorLocation = cursorLocation() + strlen(Clipboard::sharedClipboard()->storedText());
|
||||
}
|
||||
setCursorLocation(nextCursorLocation);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -415,9 +386,18 @@ bool TextField::textFieldShouldFinishEditing(Ion::Events::Event event) {
|
||||
|
||||
bool TextField::handleEvent(Ion::Events::Event event) {
|
||||
assert(m_delegate != nullptr);
|
||||
if (m_delegate->textFieldDidReceiveEvent(this, event)) {
|
||||
return true;
|
||||
}
|
||||
if (event.hasText()) {
|
||||
return handleEventWithText(event.text());
|
||||
}
|
||||
if (event == Ion::Events::Paste) {
|
||||
return handleEventWithText(Clipboard::sharedClipboard()->storedText());
|
||||
}
|
||||
size_t previousTextLength = strlen(text());
|
||||
bool didHandleEvent = privateHandleEvent(event);
|
||||
return m_delegate->textFieldDidHandleEvent(this, event, didHandleEvent, strlen(text()) != previousTextLength);
|
||||
return m_delegate->textFieldDidHandleEvent(this, didHandleEvent, strlen(text()) != previousTextLength);
|
||||
}
|
||||
|
||||
void TextField::scrollToCursor() {
|
||||
@@ -426,3 +406,19 @@ void TextField::scrollToCursor() {
|
||||
}
|
||||
scrollToContentRect(m_contentView.cursorRect(), true);
|
||||
}
|
||||
|
||||
bool TextField::handleEventWithText(const char * eventText) {
|
||||
size_t previousTextLength = strlen(text());
|
||||
if (!isEditing()) {
|
||||
setEditing(true);
|
||||
}
|
||||
int nextCursorLocation = draftTextLength();
|
||||
if (insertTextAtLocation(eventText, cursorLocation())) {
|
||||
/* The cursor position depends on the text as we sometimes want to
|
||||
* position the cursor at the end of the text and sometimes after the
|
||||
* first parenthesis. */
|
||||
nextCursorLocation = cursorLocation() + TextInputHelpers::CursorIndexInCommand(eventText);
|
||||
}
|
||||
setCursorLocation(nextCursorLocation);
|
||||
return m_delegate->textFieldDidHandleEvent(this, true, strlen(text()) != previousTextLength);
|
||||
}
|
||||
|
||||
17
escher/src/text_input_helpers.cpp
Normal file
17
escher/src/text_input_helpers.cpp
Normal file
@@ -0,0 +1,17 @@
|
||||
#include <escher/text_input_helpers.h>
|
||||
#include <string.h>
|
||||
|
||||
namespace TextInputHelpers {
|
||||
|
||||
int CursorIndexInCommand(const char * text) {
|
||||
for (size_t i = 0; i < strlen(text)-1; i++) {
|
||||
if (text[i] == '(' || text[i] == '\'') {
|
||||
if (text[i+1] == ')' || text[i+1] == '\'') {
|
||||
return i + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
return strlen(text);
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user