From 249b15750ae1912119f151f06a5df7e4928fffbb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Mon, 28 May 2018 11:45:12 +0200 Subject: [PATCH] [apps/stats] Display all non empty series in calculation --- apps/statistics/calculation_controller.cpp | 146 ++++++++++++++++----- apps/statistics/calculation_controller.h | 32 +++-- apps/statistics/store.cpp | 14 ++ apps/statistics/store.h | 1 + escher/src/table_view.cpp | 2 +- 5 files changed, 155 insertions(+), 40 deletions(-) diff --git a/apps/statistics/calculation_controller.cpp b/apps/statistics/calculation_controller.cpp index f21897058..0be21c480 100644 --- a/apps/statistics/calculation_controller.cpp +++ b/apps/statistics/calculation_controller.cpp @@ -13,8 +13,10 @@ namespace Statistics { CalculationController::CalculationController(Responder * parentResponder, ButtonRowController * header, Store * store) : TabTableController(parentResponder, this), ButtonRowDelegate(header, nullptr), - m_titleCells{}, + m_seriesTitleCells{}, + m_calculationTitleCells{}, m_calculationCells{}, + m_hideableCell(nullptr), m_store(store) { } @@ -35,28 +37,62 @@ Responder * CalculationController::defaultController() { // TableViewDataSource +int CalculationController::numberOfColumns() { + return 1 + m_store->numberOfNonEmptySeries(); +} + void CalculationController::willDisplayCellAtLocation(HighlightCell * cell, int i, int j) { - EvenOddCell * myCell = (EvenOddCell *)cell; - myCell->setEven(j%2 == 0); - myCell->setHighlighted(i == selectedColumn() && j == selectedRow()); - if (i == 0) { - I18n::Message titles[k_totalNumberOfRows] = {I18n::Message::TotalSize, I18n::Message::Minimum, I18n::Message::Maximum, I18n::Message::Range, I18n::Message::Mean, I18n::Message::StandardDeviationSigma, I18n::Message::Deviation, I18n::Message::FirstQuartile, I18n::Message::ThirdQuartile, I18n::Message::Median, I18n::Message::InterquartileRange, I18n::Message::Sum, I18n::Message::SquareSum, I18n::Message::SampleStandardDeviationS}; - EvenOddMessageTextCell * myCell = (EvenOddMessageTextCell *)cell; - myCell->setMessage(titles[j]); - } else { - CalculPointer calculationMethods[k_totalNumberOfRows] = {&Store::sumOfOccurrences, &Store::minValue, - &Store::maxValue, &Store::range, &Store::mean, &Store::standardDeviation, &Store::variance, &Store::firstQuartile, - &Store::thirdQuartile, &Store::median, &Store::quartileRange, &Store::sum, &Store::squaredValueSum, &Store::sampleStandardDeviation}; - double calculation = (m_store->*calculationMethods[j])(0); //TODO - EvenOddBufferTextCell * myCell = (EvenOddBufferTextCell *)cell; - char buffer[PrintFloat::bufferSizeForFloatsWithPrecision(Constant::LargeNumberOfSignificantDigits)]; - PrintFloat::convertFloatToText(calculation, buffer, PrintFloat::bufferSizeForFloatsWithPrecision(Constant::LargeNumberOfSignificantDigits), Constant::LargeNumberOfSignificantDigits); - myCell->setText(buffer); + EvenOddCell * evenOddCell = (EvenOddCell *)cell; + evenOddCell->setEven(j%2 == 0); + evenOddCell->setHighlighted(i == selectedColumn() && j == selectedRow()); + if (i == 0 && j == 0) { + return; } + if (j == 0) { + // Display a series title cell + int seriesNumber = m_store->indexOfKthNonEmptySeries(i-1); + char titleBuffer[] = {'V', static_cast('0'+seriesNumber), '/', 'N', static_cast('0'+seriesNumber), 0}; + KDColor colors[] = {Palette::Red, Palette::Blue, Palette::Green}; + StoreTitleCell * storeTitleCell = static_cast(cell); + storeTitleCell->setText(titleBuffer); + storeTitleCell->setColor(colors[seriesNumber]); + return; + } + if (i == 0) { + // Display a calculation title cell + I18n::Message titles[k_totalNumberOfRows] = { + I18n::Message::TotalSize, + I18n::Message::Minimum, + I18n::Message::Maximum, + I18n::Message::Range, + I18n::Message::Mean, + I18n::Message::StandardDeviationSigma, + I18n::Message::Deviation, + I18n::Message::FirstQuartile, + I18n::Message::ThirdQuartile, + I18n::Message::Median, + I18n::Message::InterquartileRange, + I18n::Message::Sum, + I18n::Message::SquareSum, + I18n::Message::SampleStandardDeviationS}; + EvenOddMessageTextCell * evenOddMessageCell = static_cast(cell); + evenOddMessageCell->setMessage(titles[j-1]); + return; + } + // Display a calculation cell + CalculPointer calculationMethods[k_totalNumberOfRows] = {&Store::sumOfOccurrences, &Store::minValue, + &Store::maxValue, &Store::range, &Store::mean, &Store::standardDeviation, &Store::variance, &Store::firstQuartile, + &Store::thirdQuartile, &Store::median, &Store::quartileRange, &Store::sum, &Store::squaredValueSum, &Store::sampleStandardDeviation}; + int seriesIndex = m_store->indexOfKthNonEmptySeries(i-1); + double calculation = (m_store->*calculationMethods[j-1])(seriesIndex); + EvenOddBufferTextCell * calculationCell = static_cast(cell); + char buffer[PrintFloat::bufferSizeForFloatsWithPrecision(Constant::LargeNumberOfSignificantDigits)]; + PrintFloat::convertFloatToText(calculation, buffer, PrintFloat::bufferSizeForFloatsWithPrecision(Constant::LargeNumberOfSignificantDigits), Constant::LargeNumberOfSignificantDigits); + calculationCell->setText(buffer); } KDCoordinate CalculationController::columnWidth(int i) { - return i == 0 ? k_titleCellWidth : Ion::Display::Width - Metric::CommonRightMargin - Metric::CommonLeftMargin-k_titleCellWidth; + return i == 0 ? k_calculationTitleCellWidth : k_calculationCellWidth; } KDCoordinate CalculationController::cumulatedWidthFromIndex(int i) { @@ -85,12 +121,45 @@ int CalculationController::indexFromCumulatedHeight(KDCoordinate offsetY) { } HighlightCell * CalculationController::reusableCell(int index, int type) { - assert(index < k_totalNumberOfRows); - return type == 0 ? static_cast(m_titleCells[index]) : static_cast(m_calculationCells[index]); + assert(index >= 0 && index < reusableCellCount(type)); + if (type == k_hideableCellType) { + return m_hideableCell; + } + if (type == k_calculationTitleCellType) { + return static_cast(m_calculationTitleCells[index]); + } + if (type == k_seriesTitleCellType) { + return static_cast(m_seriesTitleCells[index]); + } + assert(type == k_calculationCellType); + return static_cast(m_calculationCells[index]); +} + +int CalculationController::reusableCellCount(int type) { + if (type == k_hideableCellType) { + return 1; + } + if (type == k_calculationTitleCellType) { + return k_numberOfCalculationTitleCells; + } + if (type == k_seriesTitleCellType) { + return k_numberOfSeriesTitleCells; + } + assert(type == k_calculationCellType); + return k_numberOfCalculationCells; } int CalculationController::typeAtLocation(int i, int j) { - return i; + if (i == 0 && j == 0) { + return k_hideableCellType; + } + if (i == 0) { + return k_calculationTitleCellType; + } + if (j == 0) { + return k_seriesTitleCellType; + } + return k_calculationCellType; } // ViewController @@ -105,7 +174,7 @@ bool CalculationController::handleEvent(Ion::Events::Event event) { app()->setFirstResponder(tabController()); return true; } - if (event == Ion::Events::Copy && selectedColumn() == 1) { + if (event == Ion::Events::Copy && selectedColumn() > 0 && selectedRow() > 0) { EvenOddBufferTextCell * myCell = (EvenOddBufferTextCell *)selectableTableView()->selectedCell(); Clipboard::sharedClipboard()->store(myCell->text()); return true; @@ -115,7 +184,7 @@ bool CalculationController::handleEvent(Ion::Events::Event event) { void CalculationController::didBecomeFirstResponder() { if (selectedRow() == -1) { - selectCellAtLocation(0, 0); + selectCellAtLocation(0, 1); } else { selectCellAtLocation(selectedColumn(), selectedRow()); } @@ -129,23 +198,40 @@ Responder * CalculationController::tabController() const { } View * CalculationController::loadView() { - for (int i = 0; i < k_maxNumberOfDisplayableRows; i++) { - m_titleCells[i] = new EvenOddMessageTextCell(KDText::FontSize::Small); - m_titleCells[i]->setAlignment(1.0f, 0.5f); + for (int i = 0; i < k_numberOfSeriesTitleCells; i++) { + m_seriesTitleCells[i] = new StoreTitleCell(FunctionTitleCell::Orientation::HorizontalIndicator, KDText::FontSize::Small); + m_seriesTitleCells[i]->setSeparatorRight(true); + } + for (int i = 0; i < k_numberOfCalculationTitleCells; i++) { + m_calculationTitleCells[i] = new EvenOddMessageTextCell(KDText::FontSize::Small); + m_calculationTitleCells[i]->setAlignment(1.0f, 0.5f); + } + for (int i = 0; i < k_numberOfCalculationCells; i++) { m_calculationCells[i] = new EvenOddBufferTextCell(KDText::FontSize::Small); m_calculationCells[i]->setTextColor(Palette::GreyDark); } - return TabTableController::loadView(); + m_hideableCell = new HideableEvenOddCell(); + m_hideableCell->setHide(true); + View * result = TabTableController::loadView(); + return result; } void CalculationController::unloadView(View * view) { - for (int i = 0; i < k_maxNumberOfDisplayableRows; i++) { - delete m_titleCells[i]; - m_titleCells[i] = nullptr; + for (int i = 0; i < k_numberOfSeriesTitleCells; i++) { + delete m_seriesTitleCells[i]; + m_seriesTitleCells[i] = nullptr; + } + for (int i = 0; i < k_numberOfCalculationTitleCells; i++) { + delete m_calculationTitleCells[i]; + m_calculationTitleCells[i] = nullptr; + } + for (int i = 0; i < k_numberOfCalculationCells; i++) { delete m_calculationCells[i]; m_calculationCells[i] = nullptr; } + delete m_hideableCell; + m_hideableCell = nullptr; TabTableController::unloadView(view); } diff --git a/apps/statistics/calculation_controller.h b/apps/statistics/calculation_controller.h index d682720cf..056acab2f 100644 --- a/apps/statistics/calculation_controller.h +++ b/apps/statistics/calculation_controller.h @@ -3,6 +3,8 @@ #include #include "store.h" +#include "../shared/hideable_even_odd_cell.h" +#include "../shared/store_title_cell.h" #include "../shared/tab_table_controller.h" namespace Statistics { @@ -19,7 +21,7 @@ public: // TableViewDataSource int numberOfRows() override { return k_totalNumberOfRows; } - int numberOfColumns() override { return 2; } + int numberOfColumns() override; void willDisplayCellAtLocation(HighlightCell * cell, int i, int j) override; KDCoordinate columnWidth(int i) override; KDCoordinate rowHeight(int j) override { return k_cellHeight; } @@ -28,26 +30,38 @@ public: KDCoordinate cumulatedWidthFromIndex(int i) override; int indexFromCumulatedWidth(KDCoordinate offsetX) override; HighlightCell * reusableCell(int index, int type) override; - int reusableCellCount(int type) override { return k_maxNumberOfDisplayableRows; } + int reusableCellCount(int type) override; int typeAtLocation(int i, int j) override; // ViewController const char * title() override; - ViewController::DisplayParameter displayParameter() override { return ViewController::DisplayParameter::DoNotShowOwnTitle; } // Responder bool handleEvent(Ion::Events::Event event) override; void didBecomeFirstResponder() override; private: + static constexpr int k_totalNumberOfRows = 15; + static constexpr int k_maxNumberOfDisplayableRows = 11; + static constexpr int k_numberOfCalculationCells = 3 * k_maxNumberOfDisplayableRows; + static constexpr int k_numberOfSeriesTitleCells = 3; + static constexpr int k_numberOfCalculationTitleCells = k_maxNumberOfDisplayableRows; + + static constexpr int k_calculationTitleCellType = 0; + static constexpr int k_calculationCellType = 1; + static constexpr int k_seriesTitleCellType = 2; + static constexpr int k_hideableCellType = 3; + static constexpr KDCoordinate k_cellHeight = 20; + static constexpr KDCoordinate k_calculationTitleCellWidth = 175; + static constexpr KDCoordinate k_calculationCellWidth = 50; + Responder * tabController() const override; View * loadView() override; void unloadView(View * view) override; - constexpr static int k_totalNumberOfRows = 14; - constexpr static int k_maxNumberOfDisplayableRows = 11; - static constexpr KDCoordinate k_cellHeight = 20; - static constexpr KDCoordinate k_titleCellWidth = 175; - EvenOddMessageTextCell * m_titleCells[k_maxNumberOfDisplayableRows]; - EvenOddBufferTextCell * m_calculationCells[k_maxNumberOfDisplayableRows]; + + Shared::StoreTitleCell * m_seriesTitleCells[k_numberOfSeriesTitleCells]; + EvenOddMessageTextCell * m_calculationTitleCells[k_numberOfCalculationTitleCells]; + EvenOddBufferTextCell * m_calculationCells[k_numberOfCalculationCells]; + Shared::HideableEvenOddCell * m_hideableCell; Store * m_store; }; diff --git a/apps/statistics/store.cpp b/apps/statistics/store.cpp index 1dbd34aff..35704df36 100644 --- a/apps/statistics/store.cpp +++ b/apps/statistics/store.cpp @@ -99,6 +99,20 @@ bool Store::seriesIsEmpty(int i) { return sumOfOccurrences(i) == 0; } +int Store::indexOfKthNonEmptySeries(int k) { + assert(k >= 0 && k < numberOfNonEmptySeries()); + int nonEmptySeriesCount = 0; + for (int i = 0; i < k_numberOfSeries; i++) { + if (!seriesIsEmpty(i)) { + if (nonEmptySeriesCount == k) { + return i; + } + nonEmptySeriesCount++; + } + } + assert(false); + return 0; +} /* Calculation */ diff --git a/apps/statistics/store.h b/apps/statistics/store.h index ba1ce5cc8..94b389f00 100644 --- a/apps/statistics/store.h +++ b/apps/statistics/store.h @@ -25,6 +25,7 @@ public: bool isEmpty(); int numberOfNonEmptySeries(); bool seriesIsEmpty(int i); + int indexOfKthNonEmptySeries(int k); // Calculation double sumOfOccurrences(int series); diff --git a/escher/src/table_view.cpp b/escher/src/table_view.cpp index 333eb0f6e..194ad58c4 100644 --- a/escher/src/table_view.cpp +++ b/escher/src/table_view.cpp @@ -160,7 +160,7 @@ View * TableView::ContentView::subviewAtIndex(int index) { } void TableView::ContentView::layoutSubviews() { - for (int index=0; index