[code] Dynamic toolbox that displays script functions and variables.

Change-Id: Id1494580b3832540633d3aefaf04710d21e0a44c
This commit is contained in:
Léa Saviot
2017-11-22 16:55:10 +01:00
parent 2015bcce89
commit e6b4d07cb6
19 changed files with 588 additions and 9 deletions

View File

@@ -17,6 +17,7 @@ app_objs += $(addprefix apps/code/,\
script_store.o\
script_template.o\
toolbox.o\
variable_box_controller.o\
)
i18n_files += $(addprefix apps/code/,\

View File

@@ -62,7 +62,8 @@ App::App(Container * container, Snapshot * snapshot) :
int newCursorLocation = textField->cursorLocation() + Shared::ToolboxHelpers::CursorIndexInCommand(text);
if (textField->insertTextAtLocation(text, textField->cursorLocation())) {
textField->setCursorLocation(newCursorLocation);
}})
}}),
m_variableBoxController(&m_menuController, snapshot->scriptStore())
{
}

View File

@@ -7,7 +7,7 @@
#include "menu_controller.h"
#include "script_store.h"
#include "toolbox.h"
#include "variable_box_controller.h"
namespace Code {
@@ -29,6 +29,7 @@ public:
ScriptStore m_scriptStore;
};
StackViewController * stackViewController() { return &m_codeStackViewController; }
VariableBoxController * scriptsVariableBoxController() { return &m_variableBoxController; }
Toolbox * pythonToolbox() { return &m_toolbox; }
Toolbox::Action toolboxActionForTextArea() { return m_toolboxActionForTextArea; }
Toolbox::Action toolboxActionForTextField() { return m_toolboxActionForTextField; }
@@ -40,6 +41,7 @@ private:
Toolbox m_toolbox;
Toolbox::Action m_toolboxActionForTextArea;
Toolbox::Action m_toolboxActionForTextField;
VariableBoxController m_variableBoxController;
};
}

View File

@@ -5,3 +5,4 @@ ExecuteScript = "Skript ausfuhren"
RenameScript = "Skript umbenennen"
AutoImportScript = "Automatischer Import in Konsole"
DeleteScript = "Skript loschen"
FunctionsAndVariables = "Functions and variables"

View File

@@ -5,3 +5,4 @@ ExecuteScript = "Execute script"
RenameScript = "Rename script"
AutoImportScript = "Auto import in shell"
DeleteScript = "Delete script"
FunctionsAndVariables = "Functions and variables"

View File

@@ -5,3 +5,4 @@ ExecuteScript = "Ejecutar el archivo"
RenameScript = "Renombrar el archivo"
AutoImportScript = "Importacion auto en interprete"
DeleteScript = "Eliminar el archivo"
FunctionsAndVariables = "Functions and variables"

View File

@@ -5,3 +5,4 @@ ExecuteScript = "Executer le script"
RenameScript = "Renommer le script"
AutoImportScript = "Importation auto dans la console"
DeleteScript = "Supprimer le script"
FunctionsAndVariables = "Fonctions et variables"

View File

@@ -5,3 +5,4 @@ ExecuteScript = "Executar o script"
RenameScript = "Renomear o script"
AutoImportScript = "Importacao auto no interpretador"
DeleteScript = "Eliminar o script"
FunctionsAndVariables = "Functions and variables"

View File

@@ -1,9 +1,11 @@
#include "console_controller.h"
#include "app.h"
#include "script.h"
#include "variable_box_controller.h"
#include "helpers.h"
#include <apps/i18n.h>
#include <assert.h>
#include <escher/metric.h>
extern "C" {
#include <stdlib.h>
@@ -243,6 +245,15 @@ bool ConsoleController::textFieldShouldFinishEditing(TextField * textField, Ion:
}
bool ConsoleController::textFieldDidReceiveEvent(TextField * textField, Ion::Events::Event event) {
if (event == Ion::Events::Var) {
if (!textField->isEditing()) {
textField->setEditing(true);
}
VariableBoxController * varBoxController = (static_cast<App *>(textField->app()))->scriptsVariableBoxController();
varBoxController->setTextFieldCaller(textField);
textField->app()->displayModalViewController(varBoxController, 0.f, 0.f, Metric::PopUpTopMargin, Metric::PopUpLeftMargin, 0, Metric::PopUpRightMargin);
return true;
}
const char * pythonText = Helpers::PythonTextForEvent(event);
if (pythonText == nullptr) {
return false;

View File

@@ -1,8 +1,10 @@
#include "editor_controller.h"
#include "menu_controller.h"
#include "script_parameter_controller.h"
#include "variable_box_controller.h"
#include "helpers.h"
#include <apps/code/app.h>
#include <escher/metric.h>
namespace Code {
@@ -54,6 +56,13 @@ bool EditorController::textAreaDidReceiveEvent(TextArea * textArea, Ion::Events:
return true;
}
if (event == Ion::Events::Var) {
VariableBoxController * varBoxController = (static_cast<App *>(textArea->app()))->scriptsVariableBoxController();
varBoxController->setTextAreaCaller(textArea);
textArea->app()->displayModalViewController(varBoxController, 0.f, 0.f, Metric::PopUpTopMargin, Metric::PopUpLeftMargin, 0, Metric::PopUpRightMargin);
return true;
}
if (event == Ion::Events::EXE) {
// Auto-Indent
char * text = const_cast<char *>(textArea->text());

View File

@@ -123,6 +123,10 @@ void MenuController::reloadConsole() {
m_reloadConsoleWhenBecomingFirstResponder = false;
}
void MenuController::loadPythonIfNeeded() {
m_consoleController.loadPythonEnvironment(false);
}
void MenuController::openConsoleWithScriptAtIndex(int scriptIndex) {
reloadConsole();
if (m_consoleController.loadPythonEnvironment(false)) {

View File

@@ -20,6 +20,7 @@ public:
void renameSelectedScript();
void deleteScriptAtIndex(int i);
void reloadConsole();
void loadPythonIfNeeded();
void openConsoleWithScriptAtIndex(int scriptIndex);
void scriptContentEditionDidFinish();

View File

@@ -2,6 +2,11 @@
#include "string.h"
#include <stddef.h>
extern "C" {
#include "py/lexer.h"
#include "py/nlr.h"
}
namespace Code {
constexpr char ScriptStore::k_scriptExtension[];
@@ -104,6 +109,116 @@ bool ScriptStore::isFull() {
return (numberOfScripts() >= k_maxNumberOfScripts || m_accordion.freeSpaceSize() < k_fullFreeSpaceSizeLimit);
}
void ScriptStore::scanScriptsForFunctionsAndVariables(
void * context,
FunctionCallTwoIntArgs storeFunctionsCountForScriptAtIndex,
FunctionCallOneIntOneConstCharPointerArg storeFunctionNameStartAtIndex,
FunctionCallTwoIntArgs storeGlobalVariablesCountForScriptAtIndex,
FunctionCallOneIntOneConstCharPointerArg storeGlobalVariableNameStartAtIndex
) {
int totalFunctionsCount = 0;
int totalGlobalVariablesCount = 0;
for (int scriptIndex = 0; scriptIndex < numberOfScripts(); scriptIndex++) {
// Handle lexer or parser errors with nlr.
nlr_buf_t nlr;
if (nlr_push(&nlr) == 0) {
const char * scriptContent = scriptAtIndex(scriptIndex).content();
mp_lexer_t *lex = mp_lexer_new_from_str_len(0, scriptContent, strlen(scriptContent), false);
mp_parse_tree_t parseTree = mp_parse(lex, MP_PARSE_FILE_INPUT);
mp_parse_node_t pn = parseTree.root;
if (!MP_PARSE_NODE_IS_STRUCT(pn)) {
storeFunctionsCountForScriptAtIndex(context, scriptIndex, 0);
storeGlobalVariablesCountForScriptAtIndex(context, scriptIndex, 0);
mp_parse_tree_clear(&parseTree);
nlr_pop();
continue;
}
mp_parse_node_struct_t *pns = (mp_parse_node_struct_t*)pn;
// The script is only a single function definition.
if (((uint)(MP_PARSE_NODE_STRUCT_KIND(pns))) == k_functionDefinitionParseNodeStructKind) {
const char * id = structID(pns);
if (id == nullptr) {
continue;
}
storeFunctionsCountForScriptAtIndex(context, scriptIndex, 1);
storeFunctionNameStartAtIndex(context, totalFunctionsCount, id);
totalFunctionsCount++;
storeGlobalVariablesCountForScriptAtIndex(context, scriptIndex, 0);
mp_parse_tree_clear(&parseTree);
nlr_pop();
continue;
}
// The script is only a single global variable definition.
if (((uint)(MP_PARSE_NODE_STRUCT_KIND(pns))) == k_expressionStatementParseNodeStructKind) {
const char * id = structID(pns);
if (id == nullptr) {
continue;
}
storeGlobalVariablesCountForScriptAtIndex(context, scriptIndex, 1);
storeGlobalVariableNameStartAtIndex(context, totalGlobalVariablesCount, id);
totalGlobalVariablesCount++;
storeFunctionsCountForScriptAtIndex(context, scriptIndex, 0);
mp_parse_tree_clear(&parseTree);
nlr_pop();
continue;
}
if (((uint)(MP_PARSE_NODE_STRUCT_KIND(pns))) != k_fileInput2ParseNodeStructKind) {
// The script node is not of type "file_input_2", thus it will not have main
// structures of the wanted type.
storeFunctionsCountForScriptAtIndex(context, scriptIndex, 0);
storeGlobalVariablesCountForScriptAtIndex(context, scriptIndex, 0);
mp_parse_tree_clear(&parseTree);
nlr_pop();
continue;
}
// Count the number of structs in child nodes.
int numberOfFunctionsInCurrentScript = 0;
int numberOfGlobalVariablesInCurrentScript = 0;
size_t n = MP_PARSE_NODE_STRUCT_NUM_NODES(pns);
for (size_t i = 0; i < n; i++) {
mp_parse_node_t child = pns->nodes[i];
if (MP_PARSE_NODE_IS_STRUCT(child)) {
mp_parse_node_struct_t *child_pns = (mp_parse_node_struct_t*)(child);
if (((uint)(MP_PARSE_NODE_STRUCT_KIND(child_pns))) == k_functionDefinitionParseNodeStructKind) {
const char * id = structID(child_pns);
if (id == nullptr) {
continue;
}
storeFunctionNameStartAtIndex(context, totalFunctionsCount, id);
numberOfFunctionsInCurrentScript++;
totalFunctionsCount++;
} else if (((uint)(MP_PARSE_NODE_STRUCT_KIND(child_pns))) == k_expressionStatementParseNodeStructKind) {
const char * id = structID(child_pns);
if (id == nullptr) {
continue;
}
storeGlobalVariableNameStartAtIndex(context, totalGlobalVariablesCount, id);
numberOfGlobalVariablesInCurrentScript++;
totalGlobalVariablesCount++;
}
}
}
storeFunctionsCountForScriptAtIndex(context, scriptIndex, numberOfFunctionsInCurrentScript);
storeGlobalVariablesCountForScriptAtIndex(context, scriptIndex, numberOfGlobalVariablesInCurrentScript);
mp_parse_tree_clear(&parseTree);
nlr_pop();
} else {
// The lexer or the parser failed.
storeFunctionsCountForScriptAtIndex(context, scriptIndex, 0);
storeGlobalVariablesCountForScriptAtIndex(context, scriptIndex, 0);
}
}
}
const char * ScriptStore::contentOfScript(const char * name) {
Script script = scriptNamed(name);
if (script.isNull()) {
@@ -149,4 +264,20 @@ int ScriptStore::accordionIndexOfContentOfScriptAtIndex(int index) const {
return index * Script::NumberOfStringsPerScript + 2;
}
const char * ScriptStore::structID(mp_parse_node_struct_t *structNode) {
// Find the id child node, which stores the struct's name
size_t childNodesCount = MP_PARSE_NODE_STRUCT_NUM_NODES(structNode);
if (childNodesCount < 1) {
return nullptr;
}
mp_parse_node_t child = structNode->nodes[0];
if (MP_PARSE_NODE_IS_LEAF(child)
&& MP_PARSE_NODE_LEAF_KIND(child) == MP_PARSE_NODE_ID)
{
uintptr_t arg = MP_PARSE_NODE_LEAF_ARG(child);
return qstr_str(arg);
}
return nullptr;
}
}

View File

@@ -5,6 +5,9 @@
#include "script.h"
#include "script_template.h"
#include <python/port/port.h>
extern "C" {
#include "py/parse.h"
}
namespace Code {
@@ -18,6 +21,7 @@ public:
static constexpr char k_scriptExtension[] = ".py";
static constexpr char k_defaultScriptName[] = "script.py";
static constexpr int k_maxNumberOfScripts = 8;
ScriptStore();
const Script scriptAtIndex(int index, EditableZone zone = EditableZone::None);
@@ -30,21 +34,35 @@ public:
void deleteAllScripts();
bool isFull();
/* Provide scripts content information */
typedef void (* FunctionCallTwoIntArgs)(void * context, int n1, int n2);
typedef void (* FunctionCallOneIntOneConstCharPointerArg)(void * context, int n, const char * p1);
void scanScriptsForFunctionsAndVariables(
void * context,
FunctionCallTwoIntArgs storeFunctionsCountForScriptAtIndex,
FunctionCallOneIntOneConstCharPointerArg storeFunctionNameStartAtIndex,
FunctionCallTwoIntArgs storeGlobalVariablesCountForScriptAtIndex,
FunctionCallOneIntOneConstCharPointerArg storeGlobalVariableNameStartAtIndex
);
/* MicroPython::ScriptProvider */
const char * contentOfScript(const char * name) override;
private:
static constexpr int k_maxNumberOfScripts = 8;
static constexpr int k_fullFreeSpaceSizeLimit = 50;
// If m_accordion's free space has a size smaller than
// k_fullFreeSpaceSizeLimit, we consider the script store as full.
static constexpr size_t k_scriptDataSize = 4096;
static constexpr size_t k_fileInput2ParseNodeStructKind = 1;
static constexpr size_t k_functionDefinitionParseNodeStructKind = 3;
static constexpr size_t k_expressionStatementParseNodeStructKind = 5;
bool addScriptFromTemplate(const ScriptTemplate * scriptTemplate);
bool copyStaticScriptOnFreeSpace(const ScriptTemplate * scriptTemplate);
int accordionIndexOfScriptAtIndex(int index) const;
int accordionIndexOfMarkersOfScriptAtIndex(int index) const;
int accordionIndexOfNameOfScriptAtIndex(int index) const;
int accordionIndexOfContentOfScriptAtIndex(int index) const;
const char * structID(mp_parse_node_struct_t *structNode);
char m_scriptData[k_scriptDataSize];
Accordion m_accordion;
};

View File

@@ -0,0 +1,306 @@
#include "variable_box_controller.h"
#include "script.h"
#include "../shared/toolbox_helpers.h"
#include <apps/i18n.h>
#include <assert.h>
#include <escher/buffer_text_view.h>
#include <escher/palette.h>
#include <string.h>
namespace Code {
/* ContentViewController */
VariableBoxController::ContentViewController::ContentViewController(Responder * parentResponder, MenuController * menuController, ScriptStore * scriptStore) :
ViewController(parentResponder),
m_currentDepth(0),
m_firstSelectedRow(0),
m_previousSelectedRow(0),
m_scriptFunctionsCount(-1),
m_scriptVariablesCount(-1),
m_menuController(menuController),
m_scriptStore(scriptStore),
m_selectableTableView(this, this, 0, 1, 0, 0, 0, 0, this, nullptr, false)
{
for (int i = 0; i < ScriptStore::k_maxNumberOfScripts; i++) {
m_functionDefinitionsCount[i] = 0;
m_globalVariablesCount[i] = 0;
}
for (int i = 0; i < k_functionsAndVarsNamePointersArrayLength; i++) {
m_functionNamesPointers[i] = nullptr;
m_globalVariablesNamesPointers[i] = nullptr;
}
for (int i = 0; i < k_maxNumberOfDisplayedRows; i++) {
m_leafCells[i].setFirstTextColor(KDColorBlack);
m_leafCells[i].setSecondTextColor(Palette::GreyDark);
}
}
void VariableBoxController::ContentViewController::setTextFieldCaller(TextField * textField) {
m_textFieldCaller = textField;
m_textAreaCaller = nullptr;
}
void VariableBoxController::ContentViewController::setTextAreaCaller(TextArea * textArea) {
m_textAreaCaller = textArea;
m_textFieldCaller = nullptr;
}
void VariableBoxController::ContentViewController::reloadData() {
m_selectableTableView.reloadData();
}
void VariableBoxController::ContentViewController::resetDepth() {
m_currentDepth = 0;
}
void VariableBoxController::ContentViewController::setFunctionsCountInScriptAtIndex(int functionsCount, int scriptIndex) {
assert(functionsCount >= 0);
assert(scriptIndex >= 0 && scriptIndex < ScriptStore::k_maxNumberOfScripts);
m_functionDefinitionsCount[scriptIndex] = functionsCount;
}
void VariableBoxController::ContentViewController::setFunctionNameAtIndex(const char * functionName, int functionIndex) {
assert(functionIndex >= 0 && functionIndex < k_functionsAndVarsNamePointersArrayLength);
m_functionNamesPointers[functionIndex] = functionName;
}
void VariableBoxController::ContentViewController::setGlobalVariablesCountInScriptAtIndex(int globalVariablesCount, int scriptIndex) {
assert(globalVariablesCount >= 0);
assert(scriptIndex >= 0 && scriptIndex < ScriptStore::k_maxNumberOfScripts);
m_globalVariablesCount[scriptIndex] = globalVariablesCount;
}
void VariableBoxController::ContentViewController::setGlobalVariableNameAtIndex(const char * globalVariableName, int globalVariableIndex) {
assert(globalVariableIndex >= 0 && globalVariableIndex < k_functionsAndVarsNamePointersArrayLength);
m_globalVariablesNamesPointers[globalVariableIndex] = globalVariableName;
}
const char * VariableBoxController::ContentViewController::title() {
return I18n::translate(I18n::Message::FunctionsAndVariables);
}
void VariableBoxController::ContentViewController::viewWillAppear() {
m_menuController->loadPythonIfNeeded();
for (int i = 0; i < ScriptStore::k_maxNumberOfScripts; i++) {
m_functionDefinitionsCount[i] = 0;
m_globalVariablesCount[i] = 0;
}
m_scriptStore->scanScriptsForFunctionsAndVariables(
this,
[](void * context, int scriptIndex, int functionsCount) {
VariableBoxController::ContentViewController * cvc = static_cast<VariableBoxController::ContentViewController *>(context);
cvc->setFunctionsCountInScriptAtIndex(functionsCount, scriptIndex);
},
[](void * context, int functionIndex, const char * functionName) {
VariableBoxController::ContentViewController * cvc = static_cast<VariableBoxController::ContentViewController *>(context);
cvc->setFunctionNameAtIndex(functionName, functionIndex);
},
[](void * context, int scriptIndex, int globalVariablesCount) {
VariableBoxController::ContentViewController * cvc = static_cast<VariableBoxController::ContentViewController *>(context);
cvc->setGlobalVariablesCountInScriptAtIndex(globalVariablesCount, scriptIndex);
},
[](void * context, int globalVariableIndex, const char * globalVariableName) {
VariableBoxController::ContentViewController * cvc = static_cast<VariableBoxController::ContentViewController *>(context);
cvc->setGlobalVariableNameAtIndex(globalVariableName, globalVariableIndex);
});
m_scriptFunctionsCount = 0;
m_scriptVariablesCount = 0;
for (int i = 0; i < ScriptStore::k_maxNumberOfScripts; i++) {
m_scriptFunctionsCount+= m_functionDefinitionsCount[i];
m_scriptVariablesCount+= m_globalVariablesCount[i];
}
}
void VariableBoxController::ContentViewController::viewDidDisappear() {
m_selectableTableView.deselectTable();
ViewController::viewDidDisappear();
}
void VariableBoxController::ContentViewController::didBecomeFirstResponder() {
m_selectableTableView.reloadData();
m_selectableTableView.scrollToCell(0,0);
selectCellAtLocation(0, m_firstSelectedRow);
app()->setFirstResponder(&m_selectableTableView);
}
bool VariableBoxController::ContentViewController::handleEvent(Ion::Events::Event event) {
if (event == Ion::Events::Back && m_currentDepth == 0) {
m_firstSelectedRow = 0;
app()->dismissModalViewController();
return true;
}
if (event == Ion::Events::Left && m_currentDepth == 0) {
return true;
}
if (event == Ion::Events::Back || event == Ion::Events::Left) {
assert(m_currentDepth == 1);
m_firstSelectedRow = m_previousSelectedRow;
m_selectableTableView.deselectTable();
m_currentDepth = 0;
app()->setFirstResponder(this);
return true;
}
if (event == Ion::Events::OK || event == Ion::Events::EXE || (event == Ion::Events::Right && m_currentDepth == 0)) {
if (m_currentDepth == 0) {
// Select a submenu from the Root Menu
m_previousSelectedRow = selectedRow();
m_firstSelectedRow = 0;
m_selectableTableView.deselectTable();
m_currentDepth = 1;
app()->setFirstResponder(this);
return true;
}
// Select a leaf in a submenu
m_firstSelectedRow = 0;
DoubleBufferTextCell * selectedTextCell = static_cast<DoubleBufferTextCell *>(m_selectableTableView.selectedCell());
insertTextInCaller(selectedTextCell->firstText());
m_selectableTableView.deselectTable();
m_currentDepth = 0;
app()->dismissModalViewController();
return true;
}
return false;
}
int VariableBoxController::ContentViewController::numberOfRows() {
if (m_currentDepth == 0) {
return k_numberOfMenuRows;
}
assert(m_currentDepth == 1);
if (m_previousSelectedRow == 0) {
return m_scriptFunctionsCount;
}
assert(m_previousSelectedRow == 1);
return m_scriptVariablesCount;
}
HighlightCell * VariableBoxController::ContentViewController::reusableCell(int index, int type) {
assert(type < 2);
assert(index >= 0);
if (type == k_leafType) {
assert(index < k_maxNumberOfDisplayedRows);
return &m_leafCells[index];
}
assert(type == k_nodeType);
assert(index < k_numberOfMenuRows);
return &m_nodeCells[index];
}
int VariableBoxController::ContentViewController::reusableCellCount(int type) {
assert(type < 2);
if (type == k_leafType) {
return k_maxNumberOfDisplayedRows;
}
assert (type == k_nodeType);
return k_numberOfMenuRows;
}
void VariableBoxController::ContentViewController::willDisplayCellForIndex(HighlightCell * cell, int index) {
if (m_currentDepth == 0) {
MessageTableCellWithChevron * myCell = static_cast<MessageTableCellWithChevron *>(cell);
I18n::Message nodeMessages[2] = {I18n::Message::Functions, I18n::Message::Variables};
myCell->setMessage(nodeMessages[index]);
return;
}
assert(m_currentDepth == 1);
DoubleBufferTextCell * myCell = static_cast<DoubleBufferTextCell *>(cell);
if (m_previousSelectedRow == 0) {
myCell->setFirstText(m_functionNamesPointers[index]);
int scriptIndex = -1;
int functionsCount = 0;
while (functionsCount < index + 1 && scriptIndex < ScriptStore::k_maxNumberOfScripts) {
scriptIndex++;
functionsCount+= m_functionDefinitionsCount[scriptIndex];
}
myCell->setSecondText(m_scriptStore->scriptAtIndex(scriptIndex).name());
} else {
myCell->setFirstText(m_globalVariablesNamesPointers[index]);
int scriptIndex = -1;
int globalVariablesCount = 0;
while (globalVariablesCount < index + 1 && scriptIndex < ScriptStore::k_maxNumberOfScripts) {
scriptIndex++;
globalVariablesCount+= m_globalVariablesCount[scriptIndex];
}
myCell->setSecondText(m_scriptStore->scriptAtIndex(scriptIndex).name());
}
}
KDCoordinate VariableBoxController::ContentViewController::rowHeight(int index) {
return k_rowHeight;
}
KDCoordinate VariableBoxController::ContentViewController::cumulatedHeightFromIndex(int j) {
int result = 0;
for (int k = 0; k < j; k++) {
result += rowHeight(k);
}
return result;
}
int VariableBoxController::ContentViewController::indexFromCumulatedHeight(KDCoordinate offsetY) {
int result = 0;
int j = 0;
while (result < offsetY && j < numberOfRows()) {
result += rowHeight(j++);
}
return (result < offsetY || offsetY == 0) ? j : j - 1;
}
int VariableBoxController::ContentViewController::typeAtLocation(int i, int j) {
if (m_currentDepth == 0) {
return k_nodeType;
}
return k_leafType;
}
void VariableBoxController::ContentViewController::insertTextInCaller(const char * text) {
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));
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);
}
}
VariableBoxController::VariableBoxController(MenuController * menuController, ScriptStore * scriptStore) :
StackViewController(nullptr, &m_contentViewController, KDColorWhite, Palette::PurpleBright, Palette::PurpleDark),
m_contentViewController(this, menuController, scriptStore)
{
}
void VariableBoxController::didBecomeFirstResponder() {
app()->setFirstResponder(&m_contentViewController);
}
void VariableBoxController::setTextFieldCaller(TextField * textField) {
m_contentViewController.setTextFieldCaller(textField);
}
void VariableBoxController::setTextAreaCaller(TextArea * textArea) {
m_contentViewController.setTextAreaCaller(textArea);
}
void VariableBoxController::viewWillAppear() {
StackViewController::viewWillAppear();
m_contentViewController.resetDepth();
m_contentViewController.reloadData();
}
void VariableBoxController::viewDidDisappear() {
StackViewController::viewDidDisappear();
}
}

View File

@@ -0,0 +1,83 @@
#ifndef CODE_VARIABLE_BOX_CONTROLLER_H
#define CODE_VARIABLE_BOX_CONTROLLER_H
#include <escher.h>
#include "double_buffer_text_cell.h"
#include "menu_controller.h"
#include "script_store.h"
namespace Code {
class VariableBoxController : public StackViewController {
public:
VariableBoxController(MenuController * menuController, ScriptStore * scriptStore);
void didBecomeFirstResponder() override;
void setTextFieldCaller(TextField * textField);
void setTextAreaCaller(TextArea * textArea);
void viewWillAppear() override;
void viewDidDisappear() override;
private:
class ContentViewController : public ViewController, public ListViewDataSource, public SelectableTableViewDataSource {
public:
ContentViewController(Responder * parentResponder, MenuController * menuController, ScriptStore * scriptStore);
void setTextFieldCaller(TextField * textField);
void setTextAreaCaller(TextArea * textArea);
void reloadData();
void resetDepth();
void setFunctionsCountInScriptAtIndex(int functionsCount, int scriptIndex);
void setFunctionNameAtIndex(const char * functionName, int functionIndex);
void setGlobalVariablesCountInScriptAtIndex(int scriptIndex, int globalVariablesCount);
void setGlobalVariableNameAtIndex(const char * globalVariableName, int globalVariableIndex);
/* ViewController */
const char * title() override;
View * view() override { return &m_selectableTableView; }
void viewWillAppear() override;
void viewDidDisappear() override;
/* Responder */
void didBecomeFirstResponder() override;
bool handleEvent(Ion::Events::Event event) override;
/* ListViewDataSource */
int numberOfRows() override;
HighlightCell * reusableCell(int index, int type) override;
int reusableCellCount(int type) override;
void willDisplayCellForIndex(HighlightCell * cell, int index) override;
KDCoordinate rowHeight(int j) override;
KDCoordinate cumulatedHeightFromIndex(int j) override;
int indexFromCumulatedHeight(KDCoordinate offsetY) override;
int typeAtLocation(int i, int j) override;
private:
constexpr static int k_maxNumberOfDisplayedRows = 6; //240/40
constexpr static int k_numberOfMenuRows = 2;
constexpr static KDCoordinate k_rowHeight = 40; //TODO fix
constexpr static int k_nodeType = 0;
constexpr static int k_leafType = 1;
constexpr static int k_functionsAndVarsNamePointersArrayLength = 32;
void insertTextInCaller(const char * text);
int m_currentDepth;
int m_firstSelectedRow;
int m_previousSelectedRow;
int m_scriptFunctionsCount;
int m_scriptVariablesCount;
int m_functionDefinitionsCount[ScriptStore::k_maxNumberOfScripts];
int m_globalVariablesCount[ScriptStore::k_maxNumberOfScripts];
const char * m_functionNamesPointers[k_functionsAndVarsNamePointersArrayLength];
const char * m_globalVariablesNamesPointers[k_functionsAndVarsNamePointersArrayLength];
MenuController * m_menuController;
ScriptStore * m_scriptStore;
TextField * m_textFieldCaller;
TextArea * m_textAreaCaller;
DoubleBufferTextCell m_leafCells[k_maxNumberOfDisplayedRows];
MessageTableCellWithChevron m_nodeCells[k_numberOfMenuRows];
SelectableTableView m_selectableTableView;
};
ContentViewController m_contentViewController;
};
}
#endif

View File

@@ -15,19 +15,24 @@ int CursorIndexInCommand(const char * text) {
void TextToInsertForCommandMessage(I18n::Message message, char * buffer) {
const char * messageText = I18n::translate(message);
TextToInsertForCommandText(messageText, buffer);
}
void TextToInsertForCommandText(const char * command, char * buffer) {
int currentNewTextIndex = 0;
int numberOfOpenBrackets = 0;
for (size_t i = 0; i < strlen(messageText); i++) {
if (messageText[i] == ')') {
size_t commandLength = strlen(command);
for (size_t i = 0; i < commandLength; i++) {
if (command[i] == ')') {
numberOfOpenBrackets--;
}
if (numberOfOpenBrackets == 0 || messageText[i] == ',')
if (numberOfOpenBrackets == 0 || command[i] == ',')
{
buffer[currentNewTextIndex] = messageText[i];
buffer[currentNewTextIndex] = command[i];
buffer[currentNewTextIndex + 1] = 0;
currentNewTextIndex++;
}
if (messageText[i] == '(') {
if (command[i] == '(') {
numberOfOpenBrackets++;
}
}

View File

@@ -14,7 +14,8 @@ int CursorIndexInCommand(const char * text);
void TextToInsertForCommandMessage(I18n::Message message, char * buffer);
/* Removes the arguments from a command message:
void TextToInsertForCommandText(const char * command, char * buffer);
/* Removes the arguments from a command:
* - Removes text between parentheses, except commas */
}

View File

@@ -9,6 +9,7 @@ public:
KDColor textColor = KDColorBlack, KDColor backgroundColor = KDColorWhite);
void setText(const char * text) override;
const char * text() const override;
static int maxNumberOfCharsInBuffer() { return k_maxNumberOfChar; }
private:
static constexpr int k_maxNumberOfChar = 256;
char m_buffer[k_maxNumberOfChar];