[escher] XNT button is now cyclic

This commit is contained in:
Laury
2022-07-06 22:52:49 +02:00
parent 77167d1706
commit 51a5f699c3
30 changed files with 167 additions and 48 deletions

View File

@@ -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/,\

View File

@@ -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

View File

@@ -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;

View File

@@ -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. */

View File

@@ -30,6 +30,7 @@ public:
TELEMETRY_ID("Editor");
/* TextAreaDelegate */
void textAreaDidReceiveNoneXNTEvent() override;
bool textAreaDidReceiveEvent(TextArea * textArea, Ion::Events::Event event) override;
/* InputEventHandlerDelegate */

View File

@@ -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;
}
}
}

View File

@@ -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);
}
}

View File

@@ -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;

View File

@@ -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,

View File

@@ -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:

View File

@@ -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;

View File

@@ -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:

View File

@@ -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;
}

View File

@@ -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
View 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
View 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