Blame view

build4/epsilon-master/apps/code/editor_controller.cpp 5.1 KB
6663b6c9   adorian   projet complet av...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
  #include "editor_controller.h"
  #include "menu_controller.h"
  #include "script_parameter_controller.h"
  #include "variable_box_controller.h"
  #include <apps/code/app.h>
  #include <escher/metric.h>
  #include <ion.h>
  
  namespace Code {
  
  EditorController::EditorController(MenuController * menuController) :
    ViewController(nullptr),
    m_editorView(this),
    m_areaBuffer(nullptr),
    m_script(Ion::Storage::Record()),
    m_menuController(menuController)
  {
    m_editorView.setTextAreaDelegate(this);
  }
  
  EditorController::~EditorController() {
    delete m_areaBuffer;
    m_areaBuffer = nullptr;
  }
  
  void EditorController::setScript(Script script) {
    m_script = script;
    const char * scriptBody = m_script.readContent();
    size_t scriptBodySize = strlen(scriptBody)+1;
    size_t availableScriptSize = scriptBodySize + Ion::Storage::sharedStorage()->availableSize();
    assert(m_areaBuffer == nullptr);
    m_areaBuffer = new char[availableScriptSize];
    strlcpy(m_areaBuffer, scriptBody, scriptBodySize);
    m_editorView.setText(m_areaBuffer, availableScriptSize);
  }
  
  // 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) {
      Script::ErrorStatus err = m_script.writeContent(m_areaBuffer, strlen(m_areaBuffer)+1);
      if (err == Script::ErrorStatus::NotEnoughSpaceAvailable || err == Script::ErrorStatus::RecordDoesNotExist) {
        assert(false); // This should not happen as we set the text area according to the available space in the Kallax
      } else {
        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(strlen(m_editorView.text()));
  }
  
  void EditorController::viewDidDisappear() {
    m_menuController->scriptContentEditionDidFinish();
    delete[] m_areaBuffer;
    m_areaBuffer = nullptr;
    m_editorView.unloadSyntaxHighlighter();
  }
  
  bool EditorController::textAreaDidReceiveEvent(TextArea * textArea, Ion::Events::Event event) {
    if (static_cast<App *>(textArea->app())->textInputDidReceiveEvent(textArea, event)) {
      return true;
    }
    if (event == Ion::Events::EXE) {
      // Auto-Indent
      char * text = const_cast<char *>(textArea->text());
      int charBeforeCursorIndex = textArea->cursorLocation()-1;
      int indentationSize = 0;
      // Indent more if the previous line ends with ':'.
      if (charBeforeCursorIndex >= 0 && text[charBeforeCursorIndex] == ':') {
        indentationSize += k_indentationSpacesNumber;
      }
      // Compute the indentation of the current line.
      int indentationIndex = charBeforeCursorIndex;
      while (indentationIndex >= 0 && text[indentationIndex] != '\n') {
        indentationIndex--;
      }
      if (indentationIndex >= 0) {
        indentationIndex++;
        while (text[indentationIndex] == ' ') {
          indentationSize++;
          indentationIndex++;
        }
      }
      char * indentationBuffer = new char [indentationSize+2];
      indentationBuffer[0] = '\n';
      for (int i = 0; i < indentationSize; i++) {
        indentationBuffer[i+1] = ' ';
      }
      indentationBuffer[indentationSize+1] = 0;
      textArea->handleEventWithText(indentationBuffer);
      delete[] indentationBuffer;
      return true;
    }
  
    if (event == Ion::Events::Backspace) {
      // If the cursor is on the left of the text of a line,
      // backspace one intentation space at a time.
      char * text = const_cast<char *>(textArea->text());
      int charBeforeCursorIndex = textArea->cursorLocation()-1;
      int indentationSize = 0;
      while (charBeforeCursorIndex >= 0 && text[charBeforeCursorIndex] == ' ') {
        charBeforeCursorIndex--;
        indentationSize++;
      }
      if (charBeforeCursorIndex >= 0 && text[charBeforeCursorIndex] == '\n'
          && indentationSize >= k_indentationSpacesNumber)
      {
        for (int i = 0; i < k_indentationSpacesNumber; i++) {
          textArea->removeChar();
        }
        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.
      char * text = const_cast<char *>(textArea->text());
      int charBeforeCursorIndex = textArea->cursorLocation()-1;
      while (charBeforeCursorIndex >= 0 && text[charBeforeCursorIndex] == ' ') {
        charBeforeCursorIndex--;
      }
      if (charBeforeCursorIndex >= 0 && text[charBeforeCursorIndex] == '\n') {
        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;
  }
  
  Toolbox * EditorController::toolboxForTextInput(TextInput * textInput) {
    Code::App * codeApp = static_cast<Code::App *>(app());
    return codeApp->pythonToolbox();
  }
  
  StackViewController * EditorController::stackController() {
    return static_cast<StackViewController *>(parentResponder());
  }
  
  }