From 239e702d37ffca2be5d1e9b517cee4fbdb60d0fe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Wed, 25 Oct 2017 17:11:41 +0200 Subject: [PATCH] [code] Navigation in the console history. The user can copy previous commands or results, into the clipboard or in the console prompt. Change-Id: I280fff2d4937f4d17ab6c8907d6e5c359a322372 --- apps/calculation/history_view_cell.cpp | 12 +++--- apps/calculation/history_view_cell.h | 1 - apps/code/console_controller.cpp | 48 ++++++++++++++++++++--- apps/code/console_controller.h | 10 +++-- apps/code/console_edit_cell.cpp | 6 +++ apps/code/console_edit_cell.h | 1 + apps/code/console_line_cell.cpp | 5 ++- apps/code/script_parameter_controller.cpp | 1 + 8 files changed, 66 insertions(+), 18 deletions(-) diff --git a/apps/calculation/history_view_cell.cpp b/apps/calculation/history_view_cell.cpp index 671de7047..d99b90b13 100644 --- a/apps/calculation/history_view_cell.cpp +++ b/apps/calculation/history_view_cell.cpp @@ -34,16 +34,16 @@ void HistoryViewCell::layoutSubviews() { KDCoordinate width = bounds().width(); KDCoordinate height = bounds().height(); KDSize inputSize = m_inputView.minimalSizeForOptimalDisplay(); - if (inputSize.width() + k_digitHorizontalMargin > width) { - m_inputView.setFrame(KDRect(k_digitHorizontalMargin, k_digitVerticalMargin, width - k_digitHorizontalMargin, inputSize.height())); + if (inputSize.width() + Metric::HistoryHorizontalMargin > width) { + m_inputView.setFrame(KDRect(Metric::HistoryHorizontalMargin, k_digitVerticalMargin, width - Metric::HistoryHorizontalMargin, inputSize.height())); } else { - m_inputView.setFrame(KDRect(k_digitHorizontalMargin, k_digitVerticalMargin, inputSize.width(), inputSize.height())); + m_inputView.setFrame(KDRect(Metric::HistoryHorizontalMargin, k_digitVerticalMargin, inputSize.width(), inputSize.height())); } KDSize outputSize = m_outputView.minimalSizeForOptimalDisplay(); - if (outputSize.width() + k_digitHorizontalMargin > width) { - m_outputView.setFrame(KDRect(k_digitHorizontalMargin, inputSize.height() + 2*k_digitVerticalMargin, width - k_digitHorizontalMargin, height - inputSize.height() - 3*k_digitVerticalMargin)); + if (outputSize.width() + Metric::HistoryHorizontalMargin > width) { + m_outputView.setFrame(KDRect(Metric::HistoryHorizontalMargin, inputSize.height() + 2*k_digitVerticalMargin, width - Metric::HistoryHorizontalMargin, height - inputSize.height() - 3*k_digitVerticalMargin)); } else { - m_outputView.setFrame(KDRect(width - outputSize.width() - k_digitHorizontalMargin, inputSize.height() + 2*k_digitVerticalMargin, outputSize.width(), height - inputSize.height() - 3*k_digitVerticalMargin)); + m_outputView.setFrame(KDRect(width - outputSize.width() - Metric::HistoryHorizontalMargin, inputSize.height() + 2*k_digitVerticalMargin, outputSize.width(), height - inputSize.height() - 3*k_digitVerticalMargin)); } } diff --git a/apps/calculation/history_view_cell.h b/apps/calculation/history_view_cell.h index 048613ec9..1d876c937 100644 --- a/apps/calculation/history_view_cell.h +++ b/apps/calculation/history_view_cell.h @@ -22,7 +22,6 @@ public: void layoutSubviews() override; void didBecomeFirstResponder() override; bool handleEvent(Ion::Events::Event event) override; - constexpr static KDCoordinate k_digitHorizontalMargin = 10; constexpr static KDCoordinate k_digitVerticalMargin = 5; SubviewType selectedSubviewType(); void setSelectedSubviewType(HistoryViewCell::SubviewType subviewType); diff --git a/apps/code/console_controller.cpp b/apps/code/console_controller.cpp index acad96b7b..a6cf81563 100644 --- a/apps/code/console_controller.cpp +++ b/apps/code/console_controller.cpp @@ -1,7 +1,7 @@ #include "console_controller.h" #include "script.h" -#include #include "app.h" +#include #include extern "C" { @@ -12,9 +12,10 @@ namespace Code { ConsoleController::ConsoleController(Responder * parentResponder, ScriptStore * scriptStore) : ViewController(parentResponder), + SelectableTableViewDataSource(), TextFieldDelegate(), m_rowHeight(KDText::charSize(k_fontSize).height()), - m_tableView(this, this, 0, 0), + m_selectableTableView(this, this, 0, 1, 0, Metric::CommonRightMargin, 3, Metric::HistoryHorizontalMargin, this, this, true, true, KDColorWhite), m_editCell(this, this), m_pythonHeap(nullptr), m_scriptStore(scriptStore) @@ -67,7 +68,7 @@ void ConsoleController::runAndPrintForCommand(const char * command) { runCode(command); flushOutputAccumulationBufferToStore(); m_consoleStore.deleteLastLineIfEmpty(); - m_tableView.reloadData(); + m_selectableTableView.reloadData(); m_editCell.setEditing(true); } @@ -83,8 +84,8 @@ void ConsoleController::removeExtensionIfAny(char * name) { void ConsoleController::viewWillAppear() { assert(pythonEnvironmentIsLoaded()); - m_tableView.reloadData(); - m_tableView.scrollToCell(0, m_consoleStore.numberOfLines()); + m_selectableTableView.reloadData(); + m_selectableTableView.selectCellAtLocation(0, m_consoleStore.numberOfLines()); m_editCell.setEditing(true); } @@ -92,6 +93,34 @@ void ConsoleController::didBecomeFirstResponder() { app()->setFirstResponder(&m_editCell); } +bool ConsoleController::handleEvent(Ion::Events::Event event) { + if (event == Ion::Events::Up) { + if (m_consoleStore.numberOfLines() > 0 && m_selectableTableView.selectedRow() > 0) { + m_editCell.setEditing(false); + m_editCell.setText(""); + m_selectableTableView.selectCellAtLocation(0, m_consoleStore.numberOfLines()-1); + app()->setFirstResponder(&m_selectableTableView); + return true; + } + } else if (event == Ion::Events::OK || event == Ion::Events::EXE) { + if (m_consoleStore.numberOfLines() > 0) { + const char * text = m_consoleStore.lineAtIndex(m_selectableTableView.selectedRow()).text(); + m_editCell.setEditing(true); + m_selectableTableView.selectCellAtLocation(0, m_consoleStore.numberOfLines()); + app()->setFirstResponder(&m_editCell); + m_editCell.setText(text); + return true; + } + } else if (event == Ion::Events::Copy) { + int row = m_selectableTableView.selectedRow(); + if (row < m_consoleStore.numberOfLines()) { + Clipboard::sharedClipboard()->store(m_consoleStore.lineAtIndex(row).text()); + return true; + } + } + return false; +} + int ConsoleController::numberOfRows() { return m_consoleStore.numberOfLines()+1; } @@ -146,6 +175,13 @@ void ConsoleController::willDisplayCellAtLocation(HighlightCell * cell, int i, i } } +void ConsoleController::tableViewDidChangeSelection(SelectableTableView * t, int previousSelectedCellX, int previousSelectedCellY) { + if (t->selectedRow() == m_consoleStore.numberOfLines()) { + m_editCell.setEditing(true); + app()->setFirstResponder(&m_editCell); + } +} + bool ConsoleController::textFieldShouldFinishEditing(TextField * textField, Ion::Events::Event event) { return event == Ion::Events::OK || event == Ion::Events::EXE; } @@ -157,7 +193,7 @@ bool ConsoleController::textFieldDidReceiveEvent(TextField * textField, Ion::Eve bool ConsoleController::textFieldDidFinishEditing(TextField * textField, const char * text, Ion::Events::Event event) { runAndPrintForCommand(text); textField->setText(""); - m_tableView.scrollToCell(0, m_consoleStore.numberOfLines()); + m_selectableTableView.selectCellAtLocation(0, m_consoleStore.numberOfLines()); return true; } diff --git a/apps/code/console_controller.h b/apps/code/console_controller.h index 048dd622d..918fef2af 100644 --- a/apps/code/console_controller.h +++ b/apps/code/console_controller.h @@ -11,7 +11,7 @@ namespace Code { -class ConsoleController : public ViewController, public ListViewDataSource, public ScrollViewDataSource, public TextFieldDelegate, public MicroPython::ExecutionEnvironment { +class ConsoleController : public ViewController, public ListViewDataSource, public SelectableTableViewDataSource, public SelectableTableViewDelegate, public TextFieldDelegate, public MicroPython::ExecutionEnvironment { public: static constexpr KDText::FontSize k_fontSize = KDText::FontSize::Large; @@ -31,9 +31,10 @@ public: void removeExtensionIfAny(char * name); // ViewController - View * view() override { return &m_tableView; } + View * view() override { return &m_selectableTableView; } void viewWillAppear() override; void didBecomeFirstResponder() override; + bool handleEvent(Ion::Events::Event event) override; // ListViewDataSource int numberOfRows() override; @@ -45,6 +46,9 @@ public: int typeAtLocation(int i, int j) override; void willDisplayCellAtLocation(HighlightCell * cell, int i, int j) override; + // SelectableTableViewDelegate + void tableViewDidChangeSelection(SelectableTableView * t, int previousSelectedCellX, int previousSelectedCellY) override; + // TextFieldDelegate bool textFieldShouldFinishEditing(TextField * textField, Ion::Events::Event event) override; bool textFieldDidReceiveEvent(TextField * textField, Ion::Events::Event event) override; @@ -68,7 +72,7 @@ private: int firstNewLineCharIndex(const char * text, size_t length); int m_rowHeight; ConsoleStore m_consoleStore; - TableView m_tableView; + SelectableTableView m_selectableTableView; ConsoleLineCell m_cells[k_numberOfLineCells]; ConsoleEditCell m_editCell; char * m_pythonHeap; diff --git a/apps/code/console_edit_cell.cpp b/apps/code/console_edit_cell.cpp index 674ecbe1a..bd4558afd 100644 --- a/apps/code/console_edit_cell.cpp +++ b/apps/code/console_edit_cell.cpp @@ -9,6 +9,8 @@ namespace Code { ConsoleEditCell::ConsoleEditCell(Responder * parentResponder, TextFieldDelegate * delegate) : HighlightCell(), Responder(parentResponder), + m_textBuffer{0}, + m_draftTextBuffer{0}, m_promptView(ConsoleController::k_fontSize, I18n::Message::ConsolePrompt, 0, 0.5), m_textField(this, m_textBuffer, m_draftTextBuffer, TextField::maxBufferSize(), delegate, true, ConsoleController::k_fontSize) { @@ -41,4 +43,8 @@ void ConsoleEditCell::setEditing(bool isEditing) { m_textField.setEditing(isEditing); } +void ConsoleEditCell::setText(const char * text) { + m_textField.setText(text); +} + } diff --git a/apps/code/console_edit_cell.h b/apps/code/console_edit_cell.h index c075648fb..a1cd1bbcb 100644 --- a/apps/code/console_edit_cell.h +++ b/apps/code/console_edit_cell.h @@ -23,6 +23,7 @@ public: // Edit cell void setEditing(bool isEditing); + void setText(const char * text); private: char m_textBuffer[TextField::maxBufferSize()]; diff --git a/apps/code/console_line_cell.cpp b/apps/code/console_line_cell.cpp index 733b00431..c26eb2440 100644 --- a/apps/code/console_line_cell.cpp +++ b/apps/code/console_line_cell.cpp @@ -13,13 +13,14 @@ ConsoleLineCell::ConsoleLineCell() : } void ConsoleLineCell::drawRect(KDContext * ctx, KDRect rect) const { + KDColor textBackgroundColor = isHighlighted() ? Palette::Select : KDColorWhite; ctx->fillRect(bounds(), KDColorWhite); if (m_line.type() == ConsoleLine::Type::Command) { ctx->drawString(I18n::translate(I18n::Message::ConsolePrompt), KDPointZero, ConsoleController::k_fontSize); KDCoordinate chevronsWidth = KDText::stringSize(I18n::translate(I18n::Message::ConsolePrompt), ConsoleController::k_fontSize).width(); - ctx->drawString(m_line.text(), KDPoint(chevronsWidth, KDCoordinate(0)), ConsoleController::k_fontSize); + ctx->drawString(m_line.text(), KDPoint(chevronsWidth, KDCoordinate(0)), ConsoleController::k_fontSize, KDColorBlack, textBackgroundColor); } else { - ctx->drawString(m_line.text(), KDPointZero, ConsoleController::k_fontSize); + ctx->drawString(m_line.text(), KDPointZero, ConsoleController::k_fontSize, KDColorBlack, textBackgroundColor); } } diff --git a/apps/code/script_parameter_controller.cpp b/apps/code/script_parameter_controller.cpp index 80de773de..1b17e6344 100644 --- a/apps/code/script_parameter_controller.cpp +++ b/apps/code/script_parameter_controller.cpp @@ -60,6 +60,7 @@ bool ScriptParameterController::handleEvent(Ion::Events::Event event) { m_autoImport = !m_autoImport; m_selectableTableView.reloadData(); m_menuController->reloadConsole(); + app()->setFirstResponder(&m_selectableTableView); return true; case 3: dismissScriptParameterController();