#include "editor_controller.h" #include "menu_controller.h" #include "script_parameter_controller.h" #include "app.h" #include #include using namespace Shared; namespace Code { EditorController::EditorController(MenuController * menuController, App * pythonDelegate) : ViewController(nullptr), m_editorView(this, pythonDelegate), m_script(Ion::Storage::Record()), m_menuController(menuController) { m_editorView.setTextAreaDelegates(this, this); } void EditorController::setScript(Script script) { m_script = script; Script::Data scriptData = m_script.value(); size_t availableScriptSize = scriptData.size + Ion::Storage::sharedStorage()->availableSize(); assert(sizeof(m_areaBuffer) >= availableScriptSize); // We cannot use strlcpy as the first char reprensenting the importation status can be 0. memcpy(m_areaBuffer, (const char *)scriptData.buffer, scriptData.size); m_editorView.setText(m_areaBuffer+1, availableScriptSize-1); // 1 char is taken by the importation status flag } // TODO: this should be done in textAreaDidFinishEditing maybe?? bool EditorController::handleEvent(Ion::Events::Event event) { if (event == Ion::Events::OK || event == Ion::Events::Back || event == Ion::Events::Home) { saveScript(); stackController()->pop(); return event != Ion::Events::Home; } return false; } void EditorController::didBecomeFirstResponder() { app()->setFirstResponder(&m_editorView); } void EditorController::viewWillAppear() { m_editorView.loadSyntaxHighlighter(); m_editorView.setCursorLocation(m_editorView.text() + strlen(m_editorView.text())); } void EditorController::viewDidDisappear() { m_menuController->scriptContentEditionDidFinish(); } bool EditorController::textAreaDidReceiveEvent(TextArea * textArea, Ion::Events::Event event) { if (event == Ion::Events::Var) { /* We save the script before displaying the Variable box to add new * functions or variables. */ saveScript(); return false; } if (app()->textInputDidReceiveEvent(textArea, event)) { return true; } if (event == Ion::Events::EXE) { textArea->handleEventWithText("\n", true, false); return true; } if (event == Ion::Events::Backspace) { /* If the cursor is on the left of the text of a line, backspace one * indentation space at a time. */ const char * text = textArea->text(); const char * cursorLocation = textArea->cursorLocation(); const char * firstNonSpace = UTF8Helper::NotCodePointSearch(text, ' ', true, cursorLocation); assert(firstNonSpace >= text); bool cursorIsPrecededOnTheLineBySpacesOnly = false; size_t numberOfSpaces = cursorLocation - firstNonSpace; if (UTF8Helper::CodePointIs(firstNonSpace, '\n')) { cursorIsPrecededOnTheLineBySpacesOnly = true; numberOfSpaces -= UTF8Decoder::CharSizeOfCodePoint('\n'); } else if (firstNonSpace == text) { cursorIsPrecededOnTheLineBySpacesOnly = true; } numberOfSpaces = numberOfSpaces / UTF8Decoder::CharSizeOfCodePoint(' '); if (cursorIsPrecededOnTheLineBySpacesOnly && numberOfSpaces >= k_indentationSpacesNumber) { for (int i = 0; i < k_indentationSpacesNumber; i++) { textArea->removePreviousGlyph(); } return true; } } else if (event == Ion::Events::Space) { /* If the cursor is on the left of the text of a line, a space triggers an * indentation. */ const char * text = textArea->text(); const char * firstNonSpace = UTF8Helper::NotCodePointSearch(text, ' ', true, textArea->cursorLocation()); assert(firstNonSpace >= text); if (UTF8Helper::CodePointIs(firstNonSpace, '\n')) { assert(UTF8Decoder::CharSizeOfCodePoint(' ') == 1); char indentationBuffer[k_indentationSpacesNumber+1]; for (int i = 0; i < k_indentationSpacesNumber; i++) { indentationBuffer[i] = ' '; } indentationBuffer[k_indentationSpacesNumber] = 0; textArea->handleEventWithText(indentationBuffer); return true; } } return false; } VariableBoxController * EditorController::variableBoxForInputEventHandler(InputEventHandler * textInput) { VariableBoxController * varBox = app()->variableBoxController(); varBox->loadFunctionsAndVariables(); return varBox; } InputEventHandlerDelegateApp * EditorController::inputEventHandlerDelegateApp() { return app(); } StackViewController * EditorController::stackController() { return static_cast(parentResponder()); } void EditorController::saveScript() { size_t sizeOfValue = strlen(m_areaBuffer+1)+1+1; // size of scriptContent + size of importation status Script::ErrorStatus err = m_script.setValue({.buffer=m_areaBuffer, .size=sizeOfValue}); assert(err != Script::ErrorStatus::NotEnoughSpaceAvailable && err != Script::ErrorStatus::RecordDoesNotExist); // This should not happen as we set the text area according to the available space in the Kallax (void) err; } }