From a19377ad5e61145caa7b67bedf470ef4c1236717 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Wed, 8 Nov 2017 13:14:09 +0100 Subject: [PATCH] [code] Default numbered script names (e.g. script1.py) When the script name is empty after renaming a script, a default new name is given. We look for the first available scriptI.py name, with 0addNewScript()) { + m_selectableTableView.reloadData(); renameScriptAtIndex(m_scriptStore->numberOfScripts()-1); + return; } m_selectableTableView.reloadData(); } void MenuController::renameScriptAtIndex(int i) { assert(i>=0 && inumberOfScripts()); + static_cast(const_cast(app()->container()))->setShiftAlphaStatus(Ion::Events::ShiftAlphaStatus::AlphaLock); EvenOddEditableTextCell * myCell = static_cast(m_selectableTableView.selectedCell()); + app()->setFirstResponder(myCell); myCell->setHighlighted(false); const char * previousText = myCell->editableTextCell()->textField()->text(); myCell->editableTextCell()->textField()->setEditing(true); myCell->editableTextCell()->textField()->setText(previousText); myCell->editableTextCell()->textField()->setCursorLocation(strlen(previousText) - strlen(ScriptStore::k_scriptExtension)); - app()->setFirstResponder(myCell); - static_cast(const_cast(app()->container()))->setShiftAlphaStatus(Ion::Events::ShiftAlphaStatus::AlphaLock); -} + } void MenuController::deleteScriptAtIndex(int i) { m_scriptStore->deleteScriptAtIndex(i); @@ -172,17 +174,27 @@ bool MenuController::textFieldShouldFinishEditing(TextField * textField, Ion::Ev } bool MenuController::textFieldDidReceiveEvent(TextField * textField, Ion::Events::Event event) { - if (event == Ion::Events::Right - && textField->isEditing() - && textField->cursorLocation() > textField->textLength() - strlen(ScriptStore::k_scriptExtension) -1) - { - return true; + if (event == Ion::Events::Right && textField->isEditing()) { + int scriptExtensionLength = strlen(ScriptStore::k_scriptExtension); + if (textField->cursorLocation() > textField->textLength() - scriptExtensionLength - 1) { + return true; + } } return false; } bool MenuController::textFieldDidFinishEditing(TextField * textField, const char * text, Ion::Events::Event event) { - if (m_scriptStore->renameScriptAtIndex(m_selectableTableView.selectedRow(), text)) { + const char * newName; + char numberedDefaultName[k_defaultScriptNameMaxSize]; + if (strlen(text) <= strlen(ScriptStore::k_scriptExtension)) { + // The user entered an empty name. Use a numbered default script name. + numberedDefaultScriptName(numberedDefaultName); + newName = const_cast(numberedDefaultName); + } else { + newName = text; + } + if (m_scriptStore->renameScriptAtIndex(m_selectableTableView.selectedRow(), newName)) { + textField->setText(newName); int currentRow = m_selectableTableView.selectedRow(); if (event == Ion::Events::Down && currentRow < numberOfRows() - 1) { m_selectableTableView.selectCellAtLocation(m_selectableTableView.selectedColumn(), currentRow + 1); @@ -194,19 +206,62 @@ bool MenuController::textFieldDidFinishEditing(TextField * textField, const char app()->setFirstResponder(&m_selectableTableView); static_cast(const_cast(app()->container()))->setShiftAlphaStatus(Ion::Events::ShiftAlphaStatus::Default); return true; - } else { - // TODO: add pop up to explain to the user that the name is too long. - return false; } + // TODO: add pop up to explain to the user that the name is too long. + return false; } bool MenuController::textFieldDidAbortEditing(TextField * textField, const char * text) { + if (strlen(text) <= strlen(ScriptStore::k_scriptExtension)) { + // The previous text was an empty name. Use a numbered default script name. + char numberedDefaultName[k_defaultScriptNameMaxSize]; + numberedDefaultScriptName(numberedDefaultName); + m_scriptStore->renameScriptAtIndex(m_selectableTableView.selectedRow(), const_cast(numberedDefaultName)); + m_selectableTableView.reloadData(); + } m_selectableTableView.selectCellAtLocation(m_selectableTableView.selectedColumn(), m_selectableTableView.selectedRow()); app()->setFirstResponder(&m_selectableTableView); static_cast(const_cast(app()->container()))->setShiftAlphaStatus(Ion::Events::ShiftAlphaStatus::Default); return true; } +void MenuController::numberedDefaultScriptName(char * buffer) { + bool foundNewScriptNumber = false; + int currentScriptNumber = 1; + char newName[k_defaultScriptNameMaxSize]; + memcpy(newName, ScriptStore::k_defaultScriptName, strlen(ScriptStore::k_defaultScriptName)+1); + // We will only name scripts from script1.py to script99.py. + while (!foundNewScriptNumber && currentScriptNumber < 100) { + // Change the number in the script name. + intToText(currentScriptNumber, &newName[strlen(ScriptStore::k_defaultScriptName)-strlen(ScriptStore::k_scriptExtension)]); + memcpy(&newName[strlen(newName)], ScriptStore::k_scriptExtension, strlen(ScriptStore::k_scriptExtension)+1); + if (m_scriptStore->scriptNamed(const_cast(newName)).isNull()) { + foundNewScriptNumber = true; + } + currentScriptNumber++; + } + if (foundNewScriptNumber) { + memcpy(buffer, newName, strlen(newName)+1); + return; + } + memcpy(buffer, ScriptStore::k_defaultScriptName, strlen(ScriptStore::k_defaultScriptName)+1); +} + +void MenuController::intToText(int i, char * buffer) { + // We only support integers from 0 to 99 + // buffer should have the space for three chars. + assert(i>=0); + assert(i<100); + if (i/10 == 0) { + buffer[0] = i+'0'; + buffer[1] = 0; + return; + } + buffer[0] = i/10+'0'; + buffer[1] = i-10*(i/10)+'0'; + buffer[2] = 0; +} + StackViewController * MenuController::stackViewController() { return static_cast(parentResponder()->parentResponder()); } diff --git a/apps/code/menu_controller.h b/apps/code/menu_controller.h index 0d57562a8..5d785b669 100644 --- a/apps/code/menu_controller.h +++ b/apps/code/menu_controller.h @@ -59,6 +59,14 @@ private: static constexpr int AddScriptCellType = 0; static constexpr int ScriptCellType = 1; static constexpr KDCoordinate k_rowHeight = 50; //TODO create common parent class with Shared::ListController + static constexpr int k_defaultScriptNameMaxSize = 9 + 2 + 1; + // k_defaultScriptNameMaxSize is the length of a name between script1.py and + // script99.py. + // 9 = strlen("script.py") + // 2 = maxLength of integers between 1 and 99. + // 1 = length of null terminating char. + void numberedDefaultScriptName(char * buffer); + void intToText(int i, char * buffer); ScriptStore * m_scriptStore; EvenOddEditableTextCell m_scriptCells[k_maxNumberOfDisplayableScriptCells]; /* In the initializer list of the MenuController constructor, we initialize diff --git a/apps/code/script_store.h b/apps/code/script_store.h index aaf40b455..38ed5cf77 100644 --- a/apps/code/script_store.h +++ b/apps/code/script_store.h @@ -17,6 +17,7 @@ public: }; static constexpr char k_scriptExtension[] = ".py"; + static constexpr char k_defaultScriptName[] = "script.py"; ScriptStore(); const Script scriptAtIndex(int index, EditableZone zone = EditableZone::None); @@ -32,7 +33,6 @@ public: const char * contentOfScript(const char * name) override; private: - static constexpr char k_defaultScriptName[] = ".py"; static constexpr size_t k_scriptDataSize = 1024; bool addScriptFromTemplate(const ScriptTemplate * scriptTemplate); bool copyStaticScriptOnFreeSpace(const ScriptTemplate * scriptTemplate); diff --git a/apps/code/script_template.cpp b/apps/code/script_template.cpp index 179bde3c8..02183ba3e 100644 --- a/apps/code/script_template.cpp +++ b/apps/code/script_template.cpp @@ -2,7 +2,8 @@ namespace Code { -constexpr ScriptTemplate emptyScriptTemplate(".py", R"()"); +constexpr ScriptTemplate emptyScriptTemplate(".py", R"(from math import * +)"); constexpr ScriptTemplate factorialScriptTemplate("factorial.py", R"(def factorial(n): if n == 0: