diff --git a/apps/statistics/Makefile b/apps/statistics/Makefile index 99a2f0115..890e0d0da 100644 --- a/apps/statistics/Makefile +++ b/apps/statistics/Makefile @@ -12,6 +12,7 @@ app_objs += $(addprefix apps/statistics/,\ histogram_controller.o\ histogram_parameter_controller.o\ histogram_view.o\ + multiple_boxes_view.o\ multiple_data_view.o\ multiple_data_view_controller.o\ multiple_histograms_view.o\ diff --git a/apps/statistics/box_controller.cpp b/apps/statistics/box_controller.cpp index edc3c581a..a5b104a50 100644 --- a/apps/statistics/box_controller.cpp +++ b/apps/statistics/box_controller.cpp @@ -7,84 +7,48 @@ using namespace Poincare; namespace Statistics { BoxController::BoxController(Responder * parentResponder, ButtonRowController * header, Store * store, BoxView::Quantile * selectedQuantile) : - ViewController(parentResponder), + MultipleDataViewController(parentResponder, store, (int *)(selectedQuantile)), ButtonRowDelegate(header, nullptr), - m_boxBannerView(), - m_view(store, &m_boxBannerView, selectedQuantile), - m_store(store), - m_selectedSeries(0) + m_view(store, selectedQuantile) { } -bool BoxController::isEmpty() const { - for (int i = 0; i < Shared::FloatPairStore::k_numberOfSeries; i++) { - if (m_store->sumOfOccurrences(i) == 0) { - return true; - } +bool BoxController::moveSelectionHorizontally(int deltaIndex) { + int selectedQuantile = (int)m_view.dataViewAtIndex(selectedSeries())->selectedQuantile(); + int nextSelectedQuantile = selectedQuantile + deltaIndex; + if (m_view.dataViewAtIndex(selectedSeries())->selectQuantile(nextSelectedQuantile)) { + reloadBannerView(); + return true; } return false; } -I18n::Message BoxController::emptyMessage() { - return I18n::Message::NoDataToPlot; -} - -Responder * BoxController::defaultController() { - return tabController(); -} - const char * BoxController::title() { return I18n::translate(I18n::Message::BoxTab); } -void BoxController::viewWillAppear() { - m_view.selectMainView(true); - reloadBannerView(); - m_view.reload(); -} - -bool BoxController::handleEvent(Ion::Events::Event event) { - if (event == Ion::Events::Up) { - m_view.selectMainView(false); - app()->setFirstResponder(tabController()); - return true; - } - if (event == Ion::Events::Left || event == Ion::Events::Right) { - int nextSelectedQuantile = event == Ion::Events::Left ? (int)m_view.selectedQuantile()-1 : (int)m_view.selectedQuantile()+1; - if (m_view.selectQuantile(nextSelectedQuantile)) { - reloadBannerView(); - return true; - } - return false; - } - return false; -} - -void BoxController::didBecomeFirstResponder() { - m_view.selectMainView(true); - m_view.reload(); -} - -void BoxController::willExitResponderChain(Responder * nextFirstResponder) { - if (nextFirstResponder == tabController()) { - m_view.selectMainView(false); - m_view.reload(); - } -} - Responder * BoxController::tabController() const { return (parentResponder()->parentResponder()->parentResponder()); } void BoxController::reloadBannerView() { + if (selectedSeries() < 0) { + return; + } + + int selectedQuantile = (int)m_view.dataViewAtIndex(selectedSeries())->selectedQuantile(); + + // Set calculation name I18n::Message calculationName[5] = {I18n::Message::Minimum, I18n::Message::FirstQuartile, I18n::Message::Median, I18n::Message::ThirdQuartile, I18n::Message::Maximum}; - m_boxBannerView.setMessageAtIndex(calculationName[(int)m_view.selectedQuantile()], 0); + m_view.editableBannerView()->setMessageAtIndex(calculationName[selectedQuantile], 0); + + // Set calculation result char buffer[PrintFloat::bufferSizeForFloatsWithPrecision(Constant::LargeNumberOfSignificantDigits)]; CalculPointer calculationMethods[5] = {&Store::minValue, &Store::firstQuartile, &Store::median, &Store::thirdQuartile, &Store::maxValue}; - double calculation = (m_store->*calculationMethods[(int)m_view.selectedQuantile()])(m_selectedSeries); + double calculation = (m_store->*calculationMethods[selectedQuantile])(selectedSeries()); PrintFloat::convertFloatToText(calculation, buffer, PrintFloat::bufferSizeForFloatsWithPrecision(Constant::LargeNumberOfSignificantDigits), Constant::LargeNumberOfSignificantDigits); - m_boxBannerView.setLegendAtIndex(buffer, 1); + m_view.editableBannerView()->setLegendAtIndex(buffer, 1); } } diff --git a/apps/statistics/box_controller.h b/apps/statistics/box_controller.h index 215f11f63..2ee62a35e 100644 --- a/apps/statistics/box_controller.h +++ b/apps/statistics/box_controller.h @@ -3,37 +3,24 @@ #include #include "store.h" -#include "box_view.h" -#include "box_banner_view.h" +#include "multiple_boxes_view.h" +#include "multiple_data_view_controller.h" namespace Statistics { -class BoxController : public ViewController, public ButtonRowDelegate, public AlternateEmptyViewDelegate { +class BoxController : public MultipleDataViewController, public ButtonRowDelegate { public: BoxController(Responder * parentResponder, ButtonRowController * header, Store * store, BoxView::Quantile * selectedQuantile); - // AlternateEmptyViewDelegate - bool isEmpty() const override; - I18n::Message emptyMessage() override; - Responder * defaultController() override; + MultipleDataView * multipleDataView() override { return &m_view; } + bool moveSelectionHorizontally(int deltaIndex) override; // ViewController const char * title() override; - View * view() override { return &m_view; } - void viewWillAppear() override; - ViewController::DisplayParameter displayParameter() override { return ViewController::DisplayParameter::DoNotShowOwnTitle; } - - // Responder - bool handleEvent(Ion::Events::Event event) override; - void didBecomeFirstResponder() override; - void willExitResponderChain(Responder * nextFirstResponder) override; private: - Responder * tabController() const; - void reloadBannerView(); - BoxBannerView m_boxBannerView; - BoxView m_view; - Store * m_store; - int m_selectedSeries; + Responder * tabController() const override; + void reloadBannerView() override; + MultipleBoxesView m_view; }; } diff --git a/apps/statistics/box_view.cpp b/apps/statistics/box_view.cpp index 5dda1c82b..9eecc62bc 100644 --- a/apps/statistics/box_view.cpp +++ b/apps/statistics/box_view.cpp @@ -6,13 +6,14 @@ using namespace Shared; namespace Statistics { -BoxView::BoxView(Store * store, BannerView * bannerView, Quantile * selectedQuantile) : +BoxView::BoxView(Store * store, int series, Shared::BannerView * bannerView, Quantile * selectedQuantile, KDColor color) : CurveView(&m_boxRange, nullptr, bannerView, nullptr), m_store(store), m_boxRange(BoxRange(store)), m_labels{}, + m_series(series), m_selectedQuantile(selectedQuantile), - m_series(0) + m_selectedHistogramColor(color) { } diff --git a/apps/statistics/box_view.h b/apps/statistics/box_view.h index a9dd4d2a7..8e5ab039d 100644 --- a/apps/statistics/box_view.h +++ b/apps/statistics/box_view.h @@ -19,10 +19,10 @@ public: ThirdQuartile = 3, Max = 4 }; - BoxView(Store * store, Shared::BannerView * bannerView, Quantile * selectedQuantile); + BoxView(Store * store, int series, Shared::BannerView * bannerView, Quantile * selectedQuantile, KDColor color); Quantile selectedQuantile() const { return *m_selectedQuantile; } bool selectQuantile(int selectedQuantile); - void setSeries(int series) { m_series = series; } + int series() const { return m_series; } // CurveView void reload() override; @@ -34,8 +34,9 @@ private: Store * m_store; BoxRange m_boxRange; char m_labels[k_maxNumberOfXLabels][Poincare::PrintFloat::bufferSizeForFloatsWithPrecision(Constant::ShortNumberOfSignificantDigits)]; - Quantile * m_selectedQuantile; int m_series; + Quantile * m_selectedQuantile; + KDColor m_selectedHistogramColor; }; } diff --git a/apps/statistics/multiple_boxes_view.cpp b/apps/statistics/multiple_boxes_view.cpp new file mode 100644 index 000000000..2fe56e6a8 --- /dev/null +++ b/apps/statistics/multiple_boxes_view.cpp @@ -0,0 +1,34 @@ +#include "multiple_boxes_view.h" +#include + +using namespace Shared; + +namespace Statistics { + +MultipleBoxesView::MultipleBoxesView(Store * store, BoxView::Quantile * selectedQuantile) : + MultipleDataView(store), + m_boxView1(store, 0, nullptr, selectedQuantile, Palette::Red), + m_boxView2(store, 1, nullptr, selectedQuantile, Palette::Blue), + m_boxView3(store, 2, nullptr, selectedQuantile, Palette::Green), + // TODO Share colors with stats/store_controller + m_bannerView() +{ + for (int i = 0; i < Store::k_numberOfSeries; i++) { + BoxView * boxView = dataViewAtIndex(i); + boxView->setDisplayBannerView(false); + //histView->setDisplayLabels(false); //TODO + } +} + +BoxView * MultipleBoxesView::dataViewAtIndex(int index) { + assert(index >= 0 && index < 3); + BoxView * views[] = {&m_boxView1, &m_boxView2, &m_boxView3}; + return views[index]; +} + +int MultipleBoxesView::seriesOfSubviewAtIndex(int index) { + assert(index >= 0 && index < numberOfSubviews() - 1); + return static_cast(subviewAtIndex(index))->series(); +} + +} diff --git a/apps/statistics/multiple_boxes_view.h b/apps/statistics/multiple_boxes_view.h new file mode 100644 index 000000000..e6b85335b --- /dev/null +++ b/apps/statistics/multiple_boxes_view.h @@ -0,0 +1,28 @@ +#ifndef STATISTICS_MULTIPLE_BOXES_VIEW_H +#define STATISTICS_MULTIPLE_BOXES_VIEW_H + +#include +#include "store.h" +#include "box_view.h" +#include "box_banner_view.h" +#include "multiple_data_view.h" + +namespace Statistics { + +class MultipleBoxesView : public MultipleDataView { +public: + MultipleBoxesView(Store * store, BoxView::Quantile * selectedQuantile); + // MultipleDataView + int seriesOfSubviewAtIndex(int index) override; + const BoxBannerView * bannerView() const override { return &m_bannerView; } + BoxView * dataViewAtIndex(int index) override; +private: + BoxView m_boxView1; + BoxView m_boxView2; + BoxView m_boxView3; + BoxBannerView m_bannerView; +}; + +} + +#endif diff --git a/apps/statistics/multiple_data_view_controller.cpp b/apps/statistics/multiple_data_view_controller.cpp index 02c2e9269..ca6aaf5e8 100644 --- a/apps/statistics/multiple_data_view_controller.cpp +++ b/apps/statistics/multiple_data_view_controller.cpp @@ -14,10 +14,6 @@ MultipleDataViewController::MultipleDataViewController(Responder * parentRespond { } -MultipleDataView * MultipleDataViewController::multipleDataView() { - return static_cast(view()); -} - bool MultipleDataViewController::isEmpty() const { return m_store->isEmpty(); }