#include "calculation_controller.h" #include "../constant.h" #include "../apps_container.h" #include "../../poincare/src/layout/baseline_relative_layout.h" #include "../../poincare/src/layout/string_layout.h" #include #include using namespace Poincare; using namespace Shared; namespace Regression { CalculationController::CalculationController(Responder * parentResponder, ButtonRowController * header, Store * store) : TabTableController(parentResponder, this, Metric::CommonTopMargin, Metric::CommonRightMargin, Metric::CommonBottomMargin, Metric::CommonLeftMargin, this, true), ButtonRowDelegate(header, nullptr), m_titleCells{EvenOddMessageTextCell(KDText::FontSize::Small), EvenOddMessageTextCell(KDText::FontSize::Small), EvenOddMessageTextCell(KDText::FontSize::Small), EvenOddMessageTextCell(KDText::FontSize::Small), EvenOddMessageTextCell(KDText::FontSize::Small), EvenOddMessageTextCell(KDText::FontSize::Small), EvenOddMessageTextCell(KDText::FontSize::Small), EvenOddMessageTextCell(KDText::FontSize::Small), EvenOddMessageTextCell(KDText::FontSize::Small), EvenOddMessageTextCell(KDText::FontSize::Small)}, m_r2TitleCell(1.0f, 0.5f), m_columnTitleCell(EvenOddDoubleBufferTextCell(&m_selectableTableView)), m_calculationCells{EvenOddBufferTextCell(KDText::FontSize::Small), EvenOddBufferTextCell(KDText::FontSize::Small), EvenOddBufferTextCell(KDText::FontSize::Small), EvenOddBufferTextCell(KDText::FontSize::Small), EvenOddBufferTextCell(KDText::FontSize::Small)}, m_store(store) { for (int k = 0; k < k_maxNumberOfDisplayableRows/2; k++) { m_calculationCells[k].setTextColor(Palette::GreyDark); m_doubleCalculationCells[k].setTextColor(Palette::GreyDark); m_doubleCalculationCells[k].setParentResponder(&m_selectableTableView); } m_r2Layout = new BaselineRelativeLayout(new StringLayout("r", 1, KDText::FontSize::Small), new StringLayout("2", 1, KDText::FontSize::Small), BaselineRelativeLayout::Type::Superscript); } CalculationController::~CalculationController() { if (m_r2Layout) { delete m_r2Layout; m_r2Layout = nullptr; } } const char * CalculationController::title() { return I18n::translate(I18n::Message::StatTab); } bool CalculationController::handleEvent(Ion::Events::Event event) { if (event == Ion::Events::Up) { m_selectableTableView.deselectTable(); app()->setFirstResponder(tabController()); return true; } return false; } void CalculationController::didBecomeFirstResponder() { if (m_selectableTableView.selectedRow() == -1) { m_selectableTableView.selectCellAtLocation(1, 0); } else { m_selectableTableView.selectCellAtLocation(m_selectableTableView.selectedColumn(), m_selectableTableView.selectedRow()); } TabTableController::didBecomeFirstResponder(); } void CalculationController::tableViewDidChangeSelection(SelectableTableView * t, int previousSelectedCellX, int previousSelectedCellY) { /* To prevent selecting cell with no content (top left corner of the table), * as soon as the selected cell is the top left corner, we either reselect * the previous cell or select the tab controller depending on from which cell * the selection comes. This trick does not create an endless loop as the * previous cell cannot be the top left corner cell if it also is the * selected one. */ if (t->selectedRow() == 0 && t->selectedColumn() == 0) { if (previousSelectedCellX == 0 && previousSelectedCellY == 1) { m_selectableTableView.deselectTable(); app()->setFirstResponder(tabController()); } else { t->selectCellAtLocation(previousSelectedCellX, previousSelectedCellY); } } if (t->selectedColumn() == 1 && t->selectedRow() >= 0 && t->selectedRow() < 6) { EvenOddDoubleBufferTextCell * myCell = (EvenOddDoubleBufferTextCell *)t->cellAtLocation(t->selectedColumn(), t->selectedRow()); bool firstSubCellSelected = true; if (previousSelectedCellX == 1 && previousSelectedCellY >= 0 && previousSelectedCellY < 6) { EvenOddDoubleBufferTextCell * myPreviousCell = (EvenOddDoubleBufferTextCell *)t->cellAtLocation(previousSelectedCellX, previousSelectedCellY); firstSubCellSelected = myPreviousCell->firstTextSelected(); } myCell->selectFirstText(firstSubCellSelected); app()->setFirstResponder(myCell); } else { if (previousSelectedCellX == 1 && previousSelectedCellY >= 0 && previousSelectedCellY < 6) { EvenOddDoubleBufferTextCell * myPreviousCell = (EvenOddDoubleBufferTextCell *)t->cellAtLocation(previousSelectedCellX, previousSelectedCellY); if (app()->firstResponder()->commonAncestorWith(myPreviousCell) == myPreviousCell) { app()->setFirstResponder(t); } } } } bool CalculationController::isEmpty() const { if (m_store->numberOfPairs() == 0) { return true; } return false; } I18n::Message CalculationController::emptyMessage() { return I18n::Message::NoValueToCompute; } Responder * CalculationController::defaultController() { return tabController(); } int CalculationController::numberOfRows() { return k_totalNumberOfRows; } int CalculationController::numberOfColumns() { return k_totalNumberOfColumns; } void CalculationController::willDisplayCellAtLocation(HighlightCell * cell, int i, int j) { EvenOddCell * myCell = (EvenOddCell *)cell; myCell->setEven(j%2 == 0); myCell->setHighlighted(i == m_selectableTableView.selectedColumn() && j == m_selectableTableView.selectedRow()); if (j == 0 && i > 0) { EvenOddDoubleBufferTextCell * myCell = (EvenOddDoubleBufferTextCell *)cell; myCell->setFirstText("x"); myCell->setSecondText("y"); return; } if (i == 0) { if (j == 10) { EvenOddExpressionCell * myCell = (EvenOddExpressionCell *)cell; myCell->setExpression(m_r2Layout); return; } EvenOddMessageTextCell * myCell = (EvenOddMessageTextCell *)cell; if (j == 0) { myCell->setMessage(I18n::Message::Default); return; } myCell->setAlignment(1.0f, 0.5f); I18n::Message titles[k_totalNumberOfRows-1] = {I18n::Message::Mean, I18n::Message::Sum, I18n::Message::SquareSum, I18n::Message::StandardDeviation, I18n::Message::Deviation, I18n::Message::NumberOfDots, I18n::Message::Covariance, I18n::Message::Sxy, I18n::Message::R, I18n::Message::Default}; myCell->setMessage(titles[j-1]); return; } if (i == 1 && j > 0 && j < 6) { ArgCalculPointer calculationMethods[(k_totalNumberOfRows-1)/2] = {&Store::meanOfColumn, &Store::sumOfColumn, &Store::squaredValueSumOfColumn, &Store::standardDeviationOfColumn, &Store::varianceOfColumn}; float calculation1 = (m_store->*calculationMethods[j-1])(0); float calculation2 = (m_store->*calculationMethods[j-1])(1); EvenOddDoubleBufferTextCell * myCell = (EvenOddDoubleBufferTextCell *)cell; char buffer[Complex::bufferSizeForFloatsWithPrecision(Constant::LargeNumberOfSignificantDigits)]; Complex::convertFloatToText(calculation1, buffer, Complex::bufferSizeForFloatsWithPrecision(Constant::LargeNumberOfSignificantDigits), Constant::LargeNumberOfSignificantDigits); myCell->setFirstText(buffer); Complex::convertFloatToText(calculation2, buffer, Complex::bufferSizeForFloatsWithPrecision(Constant::LargeNumberOfSignificantDigits), Constant::LargeNumberOfSignificantDigits); myCell->setSecondText(buffer); return; } if (i == 1 && j > 5) { CalculPointer calculationMethods[(k_totalNumberOfRows-1)/2] = {&Store::numberOfPairs, &Store::covariance, &Store::columnProductSum, &Store::correlationCoefficient, &Store::squaredCorrelationCoefficient}; float calculation = (m_store->*calculationMethods[j-6])(); EvenOddBufferTextCell * myCell = (EvenOddBufferTextCell *)cell; char buffer[Complex::bufferSizeForFloatsWithPrecision(Constant::LargeNumberOfSignificantDigits)]; Complex::convertFloatToText(calculation, buffer, Complex::bufferSizeForFloatsWithPrecision(Constant::LargeNumberOfSignificantDigits), Constant::LargeNumberOfSignificantDigits); myCell->setText(buffer); return; } } KDCoordinate CalculationController::columnWidth(int i) { return k_cellWidth; } KDCoordinate CalculationController::rowHeight(int j) { return k_cellHeight; } HighlightCell * CalculationController::reusableCell(int index, int type) { if (type == 0) { assert(index < k_maxNumberOfDisplayableRows); return &m_titleCells[index]; } if (type == 1) { assert(index == 0); return &m_r2TitleCell; } if (type == 2) { assert(index == 0); return &m_columnTitleCell; } if (type == 3) { assert(index < k_totalNumberOfRows/2); return &m_doubleCalculationCells[index]; } assert(index < k_totalNumberOfRows/2); return &m_calculationCells[index]; } int CalculationController::reusableCellCount(int type) { if (type == 0) { return k_maxNumberOfDisplayableRows; } if (type == 1) { return 1; } if (type == 2) { return 1; } if (type == 3) { return k_maxNumberOfDisplayableRows/2; } return k_maxNumberOfDisplayableRows/2; } int CalculationController::typeAtLocation(int i, int j) { if (i == 0 && j == 10) { return 1; } if (i == 0) { return 0; } if (j == 0) { return 2; } if (j > 0 && j < 6) { return 3; } return 4; } Responder * CalculationController::tabController() const { return (parentResponder()->parentResponder()->parentResponder()); } }