Files
Upsilon/apps/variable_box_controller.cpp
Léa Saviot eadf4a018a [escher] New handling of stack view headers in StackViewController.
A boolean in ViewController states if the ViewController wants MaximumSpace (do
not show any stack view headers), or if it does not want to add its own title to
the stack view headers. If the ViewController's title is null, it is not added
to the stack view headers.
By default, ButtonRowControllers do not want to add their title (because they
are only used for now in TabViews, where the title is already displayed in the
tab).

Change-Id: I9e4c64b845262e4d44eb03cf769950f9c9e67a3a
2017-11-17 11:59:50 +01:00

303 lines
9.6 KiB
C++

#include "variable_box_controller.h"
#include "constant.h"
#include <assert.h>
using namespace Poincare;
/* ContentViewController */
VariableBoxController::ContentViewController::ContentViewController(Responder * parentResponder, GlobalContext * context) :
ViewController(parentResponder),
m_context(context),
m_firstSelectedRow(0),
m_previousSelectedRow(0),
m_currentPage(Page::RootMenu),
m_selectableTableView(this, this, 0, 1, 0, 0, 0, 0, this, nullptr, false)
{
}
const char * VariableBoxController::ContentViewController::title() {
return I18n::translate(I18n::Message::Variables);
}
View * VariableBoxController::ContentViewController::view() {
return &m_selectableTableView;
}
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 MATRIX_VARIABLES
if (event == Ion::Events::Back && m_currentPage == Page::RootMenu) {
#else
if (event == Ion::Events::Back && m_currentPage == Page::Scalar) {
#endif
m_firstSelectedRow = 0;
app()->dismissModalViewController();
return true;
}
if (event == Ion::Events::Back || event == Ion::Events::Left) {
m_firstSelectedRow = m_previousSelectedRow;
#if MATRIX_VARIABLES
m_selectableTableView.deselectTable();
m_currentPage = Page::RootMenu;
#endif
app()->setFirstResponder(this);
return true;
}
if (event == Ion::Events::OK || event == Ion::Events::EXE || (event == Ion::Events::Right && m_currentPage == Page::RootMenu)) {
if (m_currentPage == Page::RootMenu) {
m_previousSelectedRow = selectedRow();
m_firstSelectedRow = 0;
m_selectableTableView.deselectTable();
m_currentPage = pageAtIndex(m_previousSelectedRow);
app()->setFirstResponder(this);
return true;
}
m_firstSelectedRow = 0;
char label[3];
putLabelAtIndexInBuffer(selectedRow(), label);
const char * editedText = label;
if (!m_textFieldCaller->isEditing()) {
m_textFieldCaller->setEditing(true);
}
m_textFieldCaller->insertTextAtLocation(editedText, m_textFieldCaller->cursorLocation());
m_textFieldCaller->setCursorLocation(m_textFieldCaller->cursorLocation() + strlen(editedText));
#if MATRIX_VARIABLES
m_selectableTableView.deselectTable();
m_currentPage = Page::RootMenu;
#endif
app()->dismissModalViewController();
return true;
}
if (event == Ion::Events::Backspace && m_currentPage != Page::RootMenu) {
if (m_currentPage == Page::Scalar) {
const Symbol symbol = Symbol('A'+selectedRow());
m_context->setExpressionForSymbolName(nullptr, &symbol);
}
if (m_currentPage == Page::Matrix) {
const Symbol symbol = Symbol::matrixSymbol('0'+(char)selectedRow());
m_context->setExpressionForSymbolName(nullptr, &symbol);
}
m_selectableTableView.reloadData();
return true;
}
return false;
}
int VariableBoxController::ContentViewController::numberOfRows() {
switch (m_currentPage) {
case Page::RootMenu:
return k_numberOfMenuRows;
case Page::Scalar:
return GlobalContext::k_maxNumberOfScalarExpressions;
#if LIST_VARIABLES
case Page::List:
return GlobalContext::k_maxNumberOfListExpressions;
#endif
case Page::Matrix:
return GlobalContext::k_maxNumberOfMatrixExpressions;
default:
return 0;
}
}
HighlightCell * VariableBoxController::ContentViewController::reusableCell(int index, int type) {
assert(type < 2);
assert(index >= 0);
if (type == 0) {
assert(index < k_maxNumberOfDisplayedRows);
return &m_leafCells[index];
}
assert(index < k_numberOfMenuRows);
return &m_nodeCells[index];
}
int VariableBoxController::ContentViewController::reusableCellCount(int type) {
assert(type < 2);
if (type == 0) {
return k_maxNumberOfDisplayedRows;
}
return k_numberOfMenuRows;
}
void VariableBoxController::ContentViewController::willDisplayCellForIndex(HighlightCell * cell, int index) {
if (m_currentPage == Page::RootMenu) {
I18n::Message label = nodeLabelAtIndex(index);
MessageTableCell * myCell = (MessageTableCell *)cell;
myCell->setMessage(label);
return;
}
VariableBoxLeafCell * myCell = (VariableBoxLeafCell *)cell;
char label[3];
putLabelAtIndexInBuffer(index, label);
myCell->setLabel(label);
const Evaluation<double> * evaluation = expressionForIndex(index);
if (m_currentPage == Page::Scalar) {
myCell->displayExpression(false);
char buffer[PrintFloat::bufferSizeForFloatsWithPrecision(Constant::LargeNumberOfSignificantDigits)];
evaluation->writeTextInBuffer(buffer, PrintFloat::bufferSizeForFloatsWithPrecision(Constant::LargeNumberOfSignificantDigits));
myCell->setSubtitle(buffer);
return;
}
myCell->displayExpression(true);
if (evaluation) {
/* TODO: implement list contexts */
myCell->setExpression(evaluation);
char buffer[2*PrintFloat::bufferSizeForFloatsWithPrecision(2)+1];
int numberOfChars = Complex<float>::convertFloatToText(evaluation->numberOfRows(), buffer, PrintFloat::bufferSizeForFloatsWithPrecision(2), 2, Expression::FloatDisplayMode::Decimal);
buffer[numberOfChars++] = 'x';
Complex<float>::convertFloatToText(evaluation->numberOfColumns(), buffer+numberOfChars, PrintFloat::bufferSizeForFloatsWithPrecision(2), 2, Expression::FloatDisplayMode::Decimal);
myCell->setSubtitle(buffer);
} else {
myCell->setExpression(nullptr);
myCell->setSubtitle(I18n::translate(I18n::Message::Empty));
}
}
KDCoordinate VariableBoxController::ContentViewController::rowHeight(int index) {
if (m_currentPage == Page::RootMenu) {
return k_nodeRowHeight;
}
if (m_currentPage == Page::Scalar) {
return k_leafRowHeight;
}
const Evaluation<double> * expression = expressionForIndex(index);
if (expression) {
ExpressionLayout * layout = expression->createLayout();
KDCoordinate expressionHeight = layout->size().height();
delete layout;
return expressionHeight+k_leafMargin;
}
return k_leafRowHeight;
}
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_currentPage == Page::RootMenu) {
return 1;
}
return 0;
}
const Evaluation<double> * VariableBoxController::ContentViewController::expressionForIndex(int index) {
if (m_currentPage == Page::Scalar) {
const Symbol symbol = Symbol('A'+index);
return m_context->evaluationForSymbol(&symbol);
}
if (m_currentPage == Page::Matrix) {
const Symbol symbol = Symbol::matrixSymbol('0'+(char)index);
return m_context->evaluationForSymbol(&symbol);
}
#if LIST_VARIABLES
if (m_currentPage == Page::List) {
return nullptr;
}
#endif
return nullptr;
}
VariableBoxController::ContentViewController::Page VariableBoxController::ContentViewController::pageAtIndex(int index) {
#if LIST_VARIABLES
Page pages[3] = {Page::Scalar, Page::List, Page::Matrix};
#else
Page pages[2] = {Page::Scalar, Page::Matrix};
#endif
return pages[index];
}
void VariableBoxController::ContentViewController::putLabelAtIndexInBuffer(int index, char * buffer) {
if (m_currentPage == Page::Scalar) {
buffer[0] = 'A' + index;
buffer[1] = 0;
}
#if LIST_VARIABLES
if (m_currentPage == Page::List) {
buffer[0] = 'L';
buffer[1] = '0' + index;
buffer[2] = 0;
}
#endif
if (m_currentPage == Page::Matrix) {
buffer[0] = 'M';
buffer[1] = '0' + index;
buffer[2] = 0;
}
}
I18n::Message VariableBoxController::ContentViewController::nodeLabelAtIndex(int index) {
assert(m_currentPage == Page::RootMenu);
#if LIST_VARIABLES
I18n::Message labels[3] = {I18n::Message::Number, I18n::Message::List, I18n::Message::Matrix};
#else
I18n::Message labels[2] = {I18n::Message::Number, I18n::Message::Matrix};
#endif
return labels[index];
}
void VariableBoxController::ContentViewController::setTextFieldCaller(TextField * textField) {
m_textFieldCaller = textField;
}
void VariableBoxController::ContentViewController::reloadData() {
m_selectableTableView.reloadData();
}
void VariableBoxController::ContentViewController::resetPage() {
#if MATRIX_VARIABLES
m_currentPage = Page::RootMenu;
#else
m_currentPage = Page::Scalar;
#endif
}
void VariableBoxController::ContentViewController::viewDidDisappear() {
m_selectableTableView.deselectTable();
ViewController::viewDidDisappear();
}
VariableBoxController::VariableBoxController(GlobalContext * context) :
StackViewController(nullptr, &m_contentViewController, KDColorWhite, Palette::PurpleBright, Palette::PurpleDark),
m_contentViewController(this, context)
{
}
void VariableBoxController::didBecomeFirstResponder() {
app()->setFirstResponder(&m_contentViewController);
}
void VariableBoxController::setTextFieldCaller(TextField * textField) {
m_contentViewController.setTextFieldCaller(textField);
}
void VariableBoxController::viewWillAppear() {
StackViewController::viewWillAppear();
m_contentViewController.resetPage();
m_contentViewController.reloadData();
}
void VariableBoxController::viewDidDisappear() {
StackViewController::viewDidDisappear();
}