mirror of
https://github.com/UpsilonNumworks/Upsilon.git
synced 2026-01-18 16:27:34 +01:00
[escher] XNT button is now cyclic
This commit is contained in:
@@ -60,6 +60,7 @@ apps_src += $(addprefix apps/,\
|
||||
suspend_timer.cpp \
|
||||
timer_manager.cpp \
|
||||
title_bar_view.cpp \
|
||||
xnt_loop.cpp \
|
||||
)
|
||||
|
||||
tests_src += $(addprefix apps/,\
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
#include "shared/global_context.h"
|
||||
#include "clock_timer.h"
|
||||
#include "on_boarding/prompt_controller.h"
|
||||
#include "xnt_loop.h"
|
||||
|
||||
#include <ion/events.h>
|
||||
|
||||
@@ -48,6 +49,8 @@ public:
|
||||
void displayExamModePopUp(GlobalPreferences::ExamMode mode);
|
||||
void shutdownDueToLowBattery();
|
||||
void setShiftAlphaStatus(Ion::Events::ShiftAlphaStatus newStatus);
|
||||
CodePoint XNT(CodePoint defaultXNT, bool * shouldRemoveLastCharacter) { m_XNTLoop.XNT(defaultXNT, shouldRemoveLastCharacter); }
|
||||
void resetXNT() { m_XNTLoop.reset(); }
|
||||
OnBoarding::PromptController * promptController();
|
||||
void redrawWindow(bool force = false);
|
||||
void activateExamMode(GlobalPreferences::ExamMode examMode);
|
||||
@@ -85,6 +88,7 @@ private:
|
||||
OnBoarding::App::Snapshot m_onBoardingSnapshot;
|
||||
HardwareTest::App::Snapshot m_hardwareTestSnapshot;
|
||||
USB::App::Snapshot m_usbConnectedSnapshot;
|
||||
XNTLoop m_XNTLoop;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -129,9 +129,10 @@ VariableBoxController * App::variableBoxForInputEventHandler(InputEventHandler *
|
||||
}
|
||||
|
||||
bool App::textInputDidReceiveEvent(InputEventHandler * textInput, Ion::Events::Event event) {
|
||||
const char * pythonText = Helpers::PythonTextForEvent(event);
|
||||
if (pythonText != nullptr) {
|
||||
textInput->handleEventWithText(pythonText);
|
||||
bool shouldRemoveLastCharacter = false;
|
||||
char buffer[CodePoint::MaxCodePointCharLength + 1];
|
||||
if (Helpers::PythonTextForEvent(event, buffer, &shouldRemoveLastCharacter)) {
|
||||
textInput->handleEventWithText(buffer, false, false, shouldRemoveLastCharacter);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#include <escher/metric.h>
|
||||
#include <ion.h>
|
||||
#include "../global_preferences.h"
|
||||
#include <apps/apps_container.h>
|
||||
|
||||
using namespace Shared;
|
||||
|
||||
@@ -72,6 +73,10 @@ void EditorController::viewDidDisappear() {
|
||||
m_menuController->scriptContentEditionDidFinish();
|
||||
}
|
||||
|
||||
void EditorController::textAreaDidReceiveNoneXNTEvent() {
|
||||
AppsContainer::sharedAppsContainer()->resetXNT();
|
||||
}
|
||||
|
||||
bool EditorController::textAreaDidReceiveEvent(TextArea * textArea, Ion::Events::Event event) {
|
||||
if (App::app()->textInputDidReceiveEvent(textArea, event)) {
|
||||
return true;
|
||||
@@ -81,7 +86,6 @@ bool EditorController::textAreaDidReceiveEvent(TextArea * textArea, Ion::Events:
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
if (event == Ion::Events::Backspace && textArea->selectionIsEmpty()) {
|
||||
/* If the cursor is on the left of the text of a line, backspace one
|
||||
* indentation space at a time. */
|
||||
|
||||
@@ -30,6 +30,7 @@ public:
|
||||
TELEMETRY_ID("Editor");
|
||||
|
||||
/* TextAreaDelegate */
|
||||
void textAreaDidReceiveNoneXNTEvent() override;
|
||||
bool textAreaDidReceiveEvent(TextArea * textArea, Ion::Events::Event event) override;
|
||||
|
||||
/* InputEventHandlerDelegate */
|
||||
|
||||
@@ -1,20 +1,24 @@
|
||||
#include "helpers.h"
|
||||
#include <escher/clipboard.h>
|
||||
#include <apps/apps_container.h>
|
||||
|
||||
namespace Code {
|
||||
namespace Helpers {
|
||||
|
||||
const char * PythonTextForEvent(Ion::Events::Event event) {
|
||||
bool PythonTextForEvent(Ion::Events::Event event, char * buffer, bool * shouldRemoveLastCharacter) {
|
||||
for (size_t i=0; i<NumberOfPythonTextPairs; i++) {
|
||||
UTF8Helper::TextPair pair = PythonTextPairs[i];
|
||||
if (event.text() == pair.firstString()) {
|
||||
return pair.secondString();
|
||||
strcpy(buffer, pair.secondString());
|
||||
return true;
|
||||
}
|
||||
if (event == Ion::Events::XNT) {
|
||||
return "x";
|
||||
CodePoint XNT = AppsContainer::sharedAppsContainer()->XNT('x', shouldRemoveLastCharacter);
|
||||
buffer[UTF8Decoder::CodePointToChars(XNT, buffer, CodePoint::MaxCodePointCharLength + 1)] = 0;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
namespace Code {
|
||||
namespace Helpers {
|
||||
|
||||
const char * PythonTextForEvent(Ion::Events::Event event);
|
||||
bool PythonTextForEvent(Ion::Events::Event event, char * buffer, bool * shouldRemoveLastCharacter);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -426,14 +426,14 @@ bool PythonTextArea::handleEvent(Ion::Events::Event event) {
|
||||
return result;
|
||||
}
|
||||
|
||||
bool PythonTextArea::handleEventWithText(const char * text, bool indentation, bool forceCursorRightOfText) {
|
||||
bool PythonTextArea::handleEventWithText(const char * text, bool indentation, bool forceCursorRightOfText, bool shouldRemoveLastCharacter) {
|
||||
if (*text == 0) {
|
||||
return false;
|
||||
}
|
||||
if (m_contentView.isAutocompleting()) {
|
||||
removeAutocompletion();
|
||||
}
|
||||
bool result = TextArea::handleEventWithText(text, indentation, forceCursorRightOfText);
|
||||
bool result = TextArea::handleEventWithText(text, indentation, forceCursorRightOfText, shouldRemoveLastCharacter);
|
||||
addAutocompletion();
|
||||
return result;
|
||||
}
|
||||
@@ -493,9 +493,10 @@ bool PythonTextArea::addAutocompletionTextAtIndex(int nextIndex, int * currentIn
|
||||
|
||||
if (textToInsertLength > 0) {
|
||||
// Try to insert the text (this might fail if the buffer is full)
|
||||
if (!m_contentView.insertTextAtLocation(textToInsert, const_cast<char *>(autocompletionLocation), textToInsertLength)) {
|
||||
if (!m_contentView.isAbleToInsertTextAt(textToInsertLength, autocompletionLocation, false)) {
|
||||
return false;
|
||||
}
|
||||
m_contentView.insertTextAtLocation(textToInsert, const_cast<char *>(autocompletionLocation), textToInsertLength);
|
||||
autocompletionLocation += textToInsertLength;
|
||||
m_contentView.setAutocompleting(true);
|
||||
m_contentView.setAutocompletionEnd(autocompletionLocation);
|
||||
@@ -507,7 +508,8 @@ bool PythonTextArea::addAutocompletionTextAtIndex(int nextIndex, int * currentIn
|
||||
assert(strlen(parentheses) == parenthesesLength);
|
||||
/* If couldInsertText is false, we should not try to add the parentheses as
|
||||
* there was already not enough space to add the autocompletion. */
|
||||
if (addParentheses && m_contentView.insertTextAtLocation(parentheses, const_cast<char *>(autocompletionLocation), parenthesesLength)) {
|
||||
if (addParentheses && m_contentView.isAbleToInsertTextAt(parenthesesLength, autocompletionLocation, false)) {
|
||||
m_contentView.insertTextAtLocation(parentheses, const_cast<char *>(autocompletionLocation), parenthesesLength);
|
||||
m_contentView.setAutocompleting(true);
|
||||
m_contentView.setAutocompletionEnd(autocompletionLocation + parenthesesLength);
|
||||
return true;
|
||||
|
||||
@@ -23,7 +23,7 @@ public:
|
||||
void loadSyntaxHighlighter() { m_contentView.loadSyntaxHighlighter(); }
|
||||
void unloadSyntaxHighlighter() { m_contentView.unloadSyntaxHighlighter(); }
|
||||
bool handleEvent(Ion::Events::Event event) override;
|
||||
bool handleEventWithText(const char * text, bool indentation = false, bool forceCursorRightOfText = false) override;
|
||||
bool handleEventWithText(const char * text, bool indentation = false, bool forceCursorRightOfText = false, bool shouldRemoveLastCharacter = false) override;
|
||||
/* autocompletionType returns:
|
||||
* - EndOfIdentifier if there is currently autocompletion, or if the cursor is
|
||||
* at the end of an identifier,
|
||||
|
||||
@@ -9,6 +9,7 @@ namespace Shared {
|
||||
class ExpressionFieldDelegateApp : public TextFieldDelegateApp, public LayoutFieldDelegate {
|
||||
public:
|
||||
virtual ~ExpressionFieldDelegateApp() = default;
|
||||
void layoutFieldDidReceiveNoneXNTEvent() override { AppsContainer::sharedAppsContainer()->resetXNT(); }
|
||||
bool layoutFieldShouldFinishEditing(LayoutField * layoutField, Ion::Events::Event event) override;
|
||||
bool layoutFieldDidReceiveEvent(LayoutField * layoutField, Ion::Events::Event event) override;
|
||||
protected:
|
||||
|
||||
@@ -2,11 +2,13 @@
|
||||
#define SHARED_LAYOUT_FIELD_DELEGATE_H
|
||||
|
||||
#include "expression_field_delegate_app.h"
|
||||
#include "../apps_container.h"
|
||||
|
||||
namespace Shared {
|
||||
|
||||
class LayoutFieldDelegate : public ::LayoutFieldDelegate {
|
||||
public:
|
||||
void layoutFieldDidReceiveNoneXNTEvent() override { AppsContainer::sharedAppsContainer()->resetXNT(); }
|
||||
bool layoutFieldShouldFinishEditing(LayoutField * layoutField, Ion::Events::Event event) override;
|
||||
bool layoutFieldDidReceiveEvent(LayoutField * layoutField, Ion::Events::Event event) override;
|
||||
bool layoutFieldDidFinishEditing(LayoutField * layoutField, Poincare::Layout layoutR, Ion::Events::Event event) override;
|
||||
|
||||
@@ -2,11 +2,13 @@
|
||||
#define SHARED_TEXT_FIELD_DELEGATE_H
|
||||
|
||||
#include "text_field_delegate_app.h"
|
||||
#include "../apps_container.h"
|
||||
|
||||
namespace Shared {
|
||||
|
||||
class TextFieldDelegate : public ::TextFieldDelegate {
|
||||
public:
|
||||
void textFieldDidReceiveNoneXNTEvent() override { AppsContainer::sharedAppsContainer()->resetXNT(); }
|
||||
bool textFieldShouldFinishEditing(TextField * textField, Ion::Events::Event event) override;
|
||||
bool textFieldDidReceiveEvent(TextField * textField, Ion::Events::Event event) override;
|
||||
protected:
|
||||
|
||||
@@ -72,10 +72,12 @@ bool TextFieldDelegateApp::fieldDidReceiveEvent(EditableField * field, Responder
|
||||
if (XNTCanBeOverriden()) {
|
||||
xnt = field->XNTCodePoint(xnt);
|
||||
}
|
||||
bool shouldRemoveLastCharacter = false;
|
||||
xnt = AppsContainer::sharedAppsContainer()->XNT(xnt, &shouldRemoveLastCharacter);
|
||||
size_t length = UTF8Decoder::CodePointToChars(xnt, buffer, bufferSize);
|
||||
assert(length < bufferSize - 1);
|
||||
buffer[length] = 0;
|
||||
return field->handleEventWithText(buffer);
|
||||
return field->handleEventWithText(buffer, false, false, shouldRemoveLastCharacter);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#include "input_event_handler_delegate_app.h"
|
||||
#include <escher/text_field_delegate.h>
|
||||
#include <apps/i18n.h>
|
||||
#include "../apps_container.h"
|
||||
|
||||
class EditableField;
|
||||
|
||||
@@ -16,6 +17,7 @@ public:
|
||||
Poincare::Context * localContext() override;
|
||||
virtual bool XNTCanBeOverriden() const { return true; }
|
||||
virtual CodePoint XNT() { return 'x'; }
|
||||
virtual void textFieldDidReceiveNoneXNTEvent() override { AppsContainer::sharedAppsContainer()->resetXNT(); }
|
||||
bool textFieldShouldFinishEditing(TextField * textField, Ion::Events::Event event) override;
|
||||
bool textFieldDidReceiveEvent(TextField * textField, Ion::Events::Event event) override;
|
||||
bool isAcceptableText(const char * text);
|
||||
|
||||
22
apps/xnt_loop.cpp
Normal file
22
apps/xnt_loop.cpp
Normal file
@@ -0,0 +1,22 @@
|
||||
#include "xnt_loop.h"
|
||||
#include <assert.h>
|
||||
|
||||
CodePoint XNTLoop::XNT(CodePoint defaultCodePoint, bool * shouldRemoveLastCharacter) {
|
||||
assert(shouldRemoveLastCharacter != nullptr);
|
||||
static constexpr CodePoint XNTCodePoints[] = {'x', 'n', 't', UCodePointGreekSmallLetterTheta};
|
||||
int XNTCodePointSize = sizeof(XNTCodePoints) / sizeof(CodePoint);
|
||||
|
||||
if (m_loopIndex == -1) {
|
||||
for (int i = 0; i < XNTCodePointSize; i++) {
|
||||
if (XNTCodePoints[i] == defaultCodePoint) {
|
||||
m_loopIndex = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
*shouldRemoveLastCharacter = true;
|
||||
m_loopIndex = (m_loopIndex + 1) % XNTCodePointSize;
|
||||
}
|
||||
|
||||
return XNTCodePoints[m_loopIndex];
|
||||
}
|
||||
15
apps/xnt_loop.h
Normal file
15
apps/xnt_loop.h
Normal file
@@ -0,0 +1,15 @@
|
||||
#ifndef APPS_XNT_LOOP
|
||||
#define APPS_XNT_LOOP
|
||||
|
||||
#include <ion/unicode/code_point.h>
|
||||
|
||||
class XNTLoop {
|
||||
public:
|
||||
XNTLoop(): m_loopIndex(-1) {}
|
||||
void reset() { m_loopIndex = -1; }
|
||||
CodePoint XNT(CodePoint defaultCodePoint, bool * shouldRemoveLastCharacter);
|
||||
private:
|
||||
int m_loopIndex;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -10,7 +10,7 @@ class InputEventHandlerDelegate;
|
||||
class InputEventHandler {
|
||||
public:
|
||||
InputEventHandler(InputEventHandlerDelegate * inputEventHandlerdelegate) : m_inputEventHandlerDelegate(inputEventHandlerdelegate) {}
|
||||
virtual bool handleEventWithText(const char * text, bool indentation = false, bool forceCursorRightOfText = false) { return false; }
|
||||
virtual bool handleEventWithText(const char * text, bool indentation = false, bool forceCursorRightOfText = false, bool shouldRemoveLastCharacter = false) { return false; }
|
||||
protected:
|
||||
bool handleBoxEvent(Ion::Events::Event event);
|
||||
InputEventHandlerDelegate * m_inputEventHandlerDelegate;
|
||||
|
||||
@@ -27,12 +27,14 @@ public:
|
||||
void abortEditionAndDismiss();
|
||||
|
||||
/* TextFieldDelegate */
|
||||
void textFieldDidReceiveNoneXNTEvent() override;
|
||||
bool textFieldDidReceiveEvent(TextField * textField, Ion::Events::Event event) override;
|
||||
bool textFieldShouldFinishEditing(TextField * textField, Ion::Events::Event event) override;
|
||||
bool textFieldDidFinishEditing(TextField * textField, const char * text, Ion::Events::Event event) override;
|
||||
bool textFieldDidAbortEditing(TextField * textField) override;
|
||||
|
||||
/* LayoutFieldDelegate */
|
||||
void layoutFieldDidReceiveNoneXNTEvent() override;
|
||||
bool layoutFieldShouldFinishEditing(LayoutField * layoutField, Ion::Events::Event event) override;
|
||||
bool layoutFieldDidReceiveEvent(LayoutField * layoutField, Ion::Events::Event event) override;
|
||||
bool layoutFieldDidFinishEditing(LayoutField * layoutField, Poincare::Layout layoutR, Ion::Events::Event event) override;
|
||||
|
||||
@@ -45,7 +45,7 @@ public:
|
||||
}
|
||||
|
||||
/* Responder */
|
||||
bool handleEventWithText(const char * text, bool indentation = false, bool forceCursorRightOfText = false) override;
|
||||
bool handleEventWithText(const char * text, bool indentation = false, bool forceCursorRightOfText = false, bool shouldRemoveLastCharacter = false) override;
|
||||
bool handleEvent(Ion::Events::Event event) override;
|
||||
// TODO: factorize with TextField (see TODO of EditableField)
|
||||
bool shouldFinishEditing(Ion::Events::Event event) override;
|
||||
|
||||
@@ -9,6 +9,7 @@ class LayoutField;
|
||||
|
||||
class LayoutFieldDelegate : public ContextProvider{
|
||||
public:
|
||||
virtual void layoutFieldDidReceiveNoneXNTEvent() {};
|
||||
virtual bool layoutFieldShouldFinishEditing(LayoutField * layoutField, Ion::Events::Event event) = 0;
|
||||
virtual bool layoutFieldDidReceiveEvent(LayoutField * layoutField, Ion::Events::Event event) = 0;
|
||||
virtual bool layoutFieldDidFinishEditing(LayoutField * layoutField, Poincare::Layout layoutR, Ion::Events::Event event) { return false; }
|
||||
|
||||
@@ -16,7 +16,7 @@ public:
|
||||
TextArea(Responder * parentResponder, View * contentView, const KDFont * font = KDFont::LargeFont);
|
||||
void setDelegates(InputEventHandlerDelegate * inputEventHandlerDelegate, TextAreaDelegate * delegate) { m_inputEventHandlerDelegate = inputEventHandlerDelegate; m_delegate = delegate; }
|
||||
bool handleEvent(Ion::Events::Event event) override;
|
||||
bool handleEventWithText(const char * text, bool indentation = false, bool forceCursorRightOfText = false) override;
|
||||
bool handleEventWithText(const char * text, bool indentation = false, bool forceCursorRightOfText = false, bool shouldRemoveLastCharacter = false) override;
|
||||
void setText(char * textBuffer, size_t textBufferSize);
|
||||
|
||||
protected:
|
||||
@@ -120,7 +120,8 @@ protected:
|
||||
const char * editedText() const override { return m_text.text(); }
|
||||
size_t editedTextLength() const override { return m_text.textLength(); }
|
||||
const Text * getText() const { return &m_text; }
|
||||
bool insertTextAtLocation(const char * text, char * location, int textLength = -1) override;
|
||||
bool isAbleToInsertTextAt(int textLength, const char * location, bool shouldRemoveLastCharacter) const override;
|
||||
void insertTextAtLocation(const char * text, char * location, int textLength = -1) override;
|
||||
void moveCursorGeo(int deltaX, int deltaY);
|
||||
bool removePreviousGlyph() override;
|
||||
bool removeEndOfLine() override;
|
||||
|
||||
@@ -5,6 +5,7 @@ class TextArea;
|
||||
|
||||
class TextAreaDelegate {
|
||||
public:
|
||||
virtual void textAreaDidReceiveNoneXNTEvent() {};
|
||||
virtual bool textAreaDidReceiveEvent(TextArea * textArea, Ion::Events::Event event) = 0;
|
||||
};
|
||||
|
||||
|
||||
@@ -34,7 +34,7 @@ public:
|
||||
void setText(const char * text);
|
||||
void setEditing(bool isEditing) override { m_contentView.setEditing(isEditing); }
|
||||
CodePoint XNTCodePoint(CodePoint defaultXNTCodePoint) override;
|
||||
bool handleEventWithText(const char * text, bool indentation = false, bool forceCursorRightOfText = false) override;
|
||||
bool handleEventWithText(const char * text, bool indentation = false, bool forceCursorRightOfText = false, bool shouldRemoveLastCharacter = false) override;
|
||||
bool handleEvent(Ion::Events::Event event) override;
|
||||
constexpr static int maxBufferSize() {
|
||||
return ContentView::k_maxBufferSize;
|
||||
@@ -71,10 +71,11 @@ protected:
|
||||
void reinitDraftTextBuffer();
|
||||
void setDraftTextBufferSize(size_t size) { assert(size <= k_maxBufferSize); m_draftTextBufferSize = size; }
|
||||
size_t draftTextBufferSize() const { return m_draftTextBufferSize; }
|
||||
bool isAbleToInsertTextAt(int textLength, const char * location, bool shouldRemoveLastCharacter) const override;
|
||||
/* 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. */
|
||||
bool insertTextAtLocation(const char * text, char * location, int textLength = -1) override;
|
||||
void insertTextAtLocation(const char * text, char * location, int textLength = -1) override;
|
||||
KDSize minimalSizeForOptimalDisplay() const override;
|
||||
bool removePreviousGlyph() override;
|
||||
bool removeEndOfLine() override;
|
||||
|
||||
@@ -7,6 +7,7 @@ class TextField;
|
||||
|
||||
class TextFieldDelegate {
|
||||
public:
|
||||
virtual void textFieldDidReceiveNoneXNTEvent() {};
|
||||
virtual bool textFieldShouldFinishEditing(TextField * textField, Ion::Events::Event event) = 0;
|
||||
virtual bool textFieldDidReceiveEvent(TextField * textField, Ion::Events::Event event) = 0;
|
||||
virtual bool textFieldDidFinishEditing(TextField * textField, const char * text, Ion::Events::Event event) { return false; }
|
||||
|
||||
@@ -49,7 +49,8 @@ protected:
|
||||
|
||||
// Virtual text get/add/remove
|
||||
virtual const char * text() const = 0;
|
||||
virtual bool insertTextAtLocation(const char * text, char * location, int textLength = -1) = 0;
|
||||
virtual bool isAbleToInsertTextAt(int textLength, const char * location, bool shouldRemoveLastCharacter) const = 0;
|
||||
virtual void insertTextAtLocation(const char * text, char * location, int textLength) = 0;
|
||||
virtual bool removePreviousGlyph() = 0;
|
||||
virtual bool removeEndOfLine() = 0;
|
||||
|
||||
@@ -92,7 +93,7 @@ protected:
|
||||
/* 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. */
|
||||
bool insertTextAtLocation(const char * textBuffer, char * location);
|
||||
void insertTextAtLocation(const char * textBuffer, char * location, int textLength);
|
||||
bool removeEndOfLine();
|
||||
ContentView * contentView() {
|
||||
return const_cast<ContentView *>(nonEditableContentView());
|
||||
|
||||
@@ -58,6 +58,14 @@ bool InputViewController::textFieldDidAbortEditing(TextField * textField) {
|
||||
return true;
|
||||
}
|
||||
|
||||
void InputViewController::textFieldDidReceiveNoneXNTEvent() {
|
||||
m_textFieldDelegate->textFieldDidReceiveNoneXNTEvent();
|
||||
}
|
||||
|
||||
void InputViewController::layoutFieldDidReceiveNoneXNTEvent() {
|
||||
m_layoutFieldDelegate->layoutFieldDidReceiveNoneXNTEvent();
|
||||
}
|
||||
|
||||
bool InputViewController::textFieldDidReceiveEvent(TextField * textField, Ion::Events::Event event) {
|
||||
return m_textFieldDelegate->textFieldDidReceiveEvent(textField, event);
|
||||
}
|
||||
|
||||
@@ -355,7 +355,7 @@ void LayoutField::reload(KDSize previousSize) {
|
||||
markRectAsDirty(bounds());
|
||||
}
|
||||
|
||||
bool LayoutField::handleEventWithText(const char * text, bool indentation, bool forceCursorRightOfText) {
|
||||
bool LayoutField::handleEventWithText(const char * text, bool indentation, bool forceCursorRightOfText, bool shouldRemoveLastCharacter) {
|
||||
/* The text here can be:
|
||||
* - the result of a key pressed, such as "," or "cos(•)"
|
||||
* - the text added after a toolbox selection
|
||||
@@ -417,6 +417,9 @@ bool LayoutField::handleEventWithText(const char * text, bool indentation, bool
|
||||
if (currentNumberOfLayouts + resultLayout.numberOfDescendants(true) >= k_maxNumberOfLayouts) {
|
||||
return true;
|
||||
}
|
||||
if (shouldRemoveLastCharacter) {
|
||||
cursor->performBackspace();
|
||||
}
|
||||
insertLayoutAtCursor(resultLayout, resultExpression, forceCursorRightOfText);
|
||||
}
|
||||
return true;
|
||||
@@ -431,6 +434,9 @@ bool LayoutField::shouldFinishEditing(Ion::Events::Event event) {
|
||||
}
|
||||
|
||||
bool LayoutField::handleEvent(Ion::Events::Event event) {
|
||||
if (m_delegate && event != Ion::Events::XNT) {
|
||||
m_delegate->layoutFieldDidReceiveNoneXNTEvent();
|
||||
}
|
||||
bool didHandleEvent = false;
|
||||
KDSize previousSize = minimalSizeForOptimalDisplay();
|
||||
bool shouldRecomputeLayout = m_contentView.cursor()->showEmptyLayoutIfNeeded();
|
||||
|
||||
@@ -33,7 +33,7 @@ static inline void InsertSpacesAtLocation(int spacesCount, char * buffer, int bu
|
||||
}
|
||||
}
|
||||
|
||||
bool TextArea::handleEventWithText(const char * text, bool indentation, bool forceCursorRightOfText) {
|
||||
bool TextArea::handleEventWithText(const char * text, bool indentation, bool forceCursorRightOfText, bool shouldRemoveLastCharacter) {
|
||||
if (*text == 0) {
|
||||
return false;
|
||||
}
|
||||
@@ -123,11 +123,19 @@ bool TextArea::handleEventWithText(const char * text, bool indentation, bool for
|
||||
return false;
|
||||
}
|
||||
|
||||
// Insert the text
|
||||
if (!insertTextAtLocation(text, insertionPosition)) {
|
||||
int textLength = strlen(text);
|
||||
if (!contentView()->isAbleToInsertTextAt(textLength, insertionPosition, shouldRemoveLastCharacter)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (shouldRemoveLastCharacter) {
|
||||
removePreviousGlyph();
|
||||
insertionPosition = const_cast<char *>(cursorLocation());
|
||||
}
|
||||
|
||||
// Insert the text
|
||||
insertTextAtLocation(text, insertionPosition, textLength);
|
||||
|
||||
// Insert the indentation
|
||||
if (indentation) {
|
||||
UTF8Helper::PerformAtCodePoints(
|
||||
@@ -160,6 +168,9 @@ bool TextArea::handleEventWithText(const char * text, bool indentation, bool for
|
||||
}
|
||||
|
||||
bool TextArea::handleEvent(Ion::Events::Event event) {
|
||||
if (m_delegate != nullptr && event != Ion::Events::XNT) {
|
||||
m_delegate->textAreaDidReceiveNoneXNTEvent();
|
||||
}
|
||||
if (m_delegate != nullptr && m_delegate->textAreaDidReceiveEvent(this, event)) {
|
||||
return true;
|
||||
}
|
||||
@@ -575,12 +586,21 @@ void TextArea::ContentView::setText(char * textBuffer, size_t textBufferSize) {
|
||||
m_cursorLocation = text();
|
||||
}
|
||||
|
||||
bool TextArea::ContentView::insertTextAtLocation(const char * text, char * location, int textLength) {
|
||||
bool TextArea::ContentView::isAbleToInsertTextAt(int textLength, const char * location, bool shouldRemoveLastCharacter) const {
|
||||
int removedCharacters = 0;
|
||||
if (shouldRemoveLastCharacter) {
|
||||
UTF8Decoder decoder(m_text.text(), location);
|
||||
const char * previousGlyphPos = decoder.previousGlyphPosition();
|
||||
assert(previousGlyphPos != nullptr);
|
||||
removedCharacters = location - previousGlyphPos;
|
||||
}
|
||||
return m_text.textLength() + textLength - removedCharacters < m_text.bufferSize() && textLength != 0;
|
||||
}
|
||||
|
||||
void TextArea::ContentView::insertTextAtLocation(const char * text, char * location, int textLength) {
|
||||
int textLen = textLength < 0 ? strlen(text) : textLength;
|
||||
assert(textLen < 0 || textLen <= strlen(text));
|
||||
if (m_text.textLength() + textLen >= m_text.bufferSize() || textLen == 0) {
|
||||
return false;
|
||||
}
|
||||
assert(isAbleToInsertTextAt(textLen, location, false));
|
||||
|
||||
// Scan for \n
|
||||
bool lineBreak = UTF8Helper::HasCodePoint(text, '\n', text + textLen);
|
||||
@@ -589,7 +609,6 @@ bool TextArea::ContentView::insertTextAtLocation(const char * text, char * locat
|
||||
// Replace System parentheses (used to keep layout tree structure) by normal parentheses
|
||||
Poincare::SerializationHelper::ReplaceSystemParenthesesByUserParentheses(location, textLen);
|
||||
reloadRectFromPosition(location, lineBreak);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TextArea::ContentView::removePreviousGlyph() {
|
||||
|
||||
@@ -119,14 +119,23 @@ void TextField::ContentView::reinitDraftTextBuffer() {
|
||||
setCursorLocation(s_draftTextBuffer);
|
||||
}
|
||||
|
||||
bool TextField::ContentView::insertTextAtLocation(const char * text, char * location, int textLen) {
|
||||
bool TextField::ContentView::isAbleToInsertTextAt(int textLength, const char * location, bool shouldRemoveLastCharacter) const {
|
||||
int removedCharacters = 0;
|
||||
if (shouldRemoveLastCharacter) {
|
||||
UTF8Decoder decoder(s_draftTextBuffer, location);
|
||||
const char * previousGlyphPos = decoder.previousGlyphPosition();
|
||||
assert(previousGlyphPos != nullptr);
|
||||
removedCharacters = location - previousGlyphPos;
|
||||
}
|
||||
return m_currentDraftTextLength + textLength - removedCharacters < m_draftTextBufferSize && textLength != 0;
|
||||
}
|
||||
|
||||
void TextField::ContentView::insertTextAtLocation(const char * text, char * location, int textLen) {
|
||||
assert(m_isEditing);
|
||||
|
||||
size_t textLength = textLen < 0 ? strlen(text) : (size_t)textLen;
|
||||
// TODO when paste fails because of a too big message, create a pop-up
|
||||
if (m_currentDraftTextLength + textLength >= m_draftTextBufferSize || textLength == 0) {
|
||||
return false;
|
||||
}
|
||||
assert(isAbleToInsertTextAt(textLength, location, false));
|
||||
|
||||
memmove(location + textLength, location, (s_draftTextBuffer + m_currentDraftTextLength + 1) - location);
|
||||
|
||||
@@ -139,7 +148,6 @@ bool TextField::ContentView::insertTextAtLocation(const char * text, char * loca
|
||||
m_currentDraftTextLength += copySize-1; // Do no count the null-termination
|
||||
|
||||
reloadRectFromPosition(m_horizontalAlignment == 0.0f ? location : s_draftTextBuffer);
|
||||
return true;
|
||||
}
|
||||
|
||||
KDSize TextField::ContentView::minimalSizeForOptimalDisplay() const {
|
||||
@@ -416,6 +424,9 @@ CodePoint TextField::XNTCodePoint(CodePoint defaultXNTCodePoint) {
|
||||
|
||||
bool TextField::handleEvent(Ion::Events::Event event) {
|
||||
assert(m_delegate != nullptr);
|
||||
if (event != Ion::Events::XNT) {
|
||||
m_delegate->textFieldDidReceiveNoneXNTEvent();
|
||||
}
|
||||
size_t previousTextLength = strlen(text());
|
||||
bool didHandleEvent = false;
|
||||
if (privateHandleMoveEvent(event)) {
|
||||
@@ -486,7 +497,7 @@ bool TextField::privateHandleSelectEvent(Ion::Events::Event event) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool TextField::handleEventWithText(const char * eventText, bool indentation, bool forceCursorRightOfText) {
|
||||
bool TextField::handleEventWithText(const char * eventText, bool indentation, bool forceCursorRightOfText, bool shouldRemoveLastCharacter) {
|
||||
size_t previousTextLength = strlen(text());
|
||||
|
||||
if (!isEditing()) {
|
||||
@@ -518,7 +529,13 @@ bool TextField::handleEventWithText(const char * eventText, bool indentation, bo
|
||||
// Replace System parentheses (used to keep layout tree structure) by normal parentheses
|
||||
Poincare::SerializationHelper::ReplaceSystemParenthesesByUserParentheses(buffer);
|
||||
|
||||
if (insertTextAtLocation(buffer, const_cast<char *>(cursorLocation()))) {
|
||||
int textLength = strlen(buffer);
|
||||
if (contentView()->isAbleToInsertTextAt(textLength, cursorLocation(), shouldRemoveLastCharacter)) {
|
||||
if (shouldRemoveLastCharacter) {
|
||||
removePreviousGlyph();
|
||||
}
|
||||
|
||||
insertTextAtLocation(buffer, const_cast<char *>(cursorLocation()), textLength);
|
||||
/* 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. */
|
||||
|
||||
@@ -170,15 +170,13 @@ void TextInput::setAlignment(float horizontalAlignment, float verticalAlignment)
|
||||
contentView()->setAlignment(horizontalAlignment, verticalAlignment);
|
||||
}
|
||||
|
||||
bool TextInput::insertTextAtLocation(const char * text, char * location) {
|
||||
if (contentView()->insertTextAtLocation(text, location)) {
|
||||
/* We layout the scrollable view before scrolling to cursor because the
|
||||
* content size might have changed. */
|
||||
layoutSubviews();
|
||||
scrollToCursor();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
void TextInput::insertTextAtLocation(const char * text, char * location, int textLength) {
|
||||
assert(contentView()->isAbleToInsertTextAt(textLength, location, false));
|
||||
contentView()->insertTextAtLocation(text, location, textLength);
|
||||
/* We layout the scrollable view before scrolling to cursor because the
|
||||
* content size might have changed. */
|
||||
layoutSubviews();
|
||||
scrollToCursor();
|
||||
}
|
||||
|
||||
bool TextInput::removeEndOfLine() {
|
||||
|
||||
Reference in New Issue
Block a user