Numworks Epsilon  1.4.1
Graphing Calculator Operating System
histogram_controller.cpp
Go to the documentation of this file.
1 #include "histogram_controller.h"
2 #include "../apps_container.h"
3 #include "app.h"
4 #include <cmath>
5 #include <assert.h>
6 #include <float.h>
7 
8 using namespace Poincare;
9 using namespace Shared;
10 
11 namespace Statistics {
12 
13 HistogramController::HistogramController(Responder * parentResponder, ButtonRowController * header, Store * store, uint32_t * storeVersion, uint32_t * barVersion, uint32_t * rangeVersion, int * selectedBarIndex) :
14  ViewController(parentResponder),
15  ButtonRowDelegate(header, nullptr),
16  m_bannerView(),
17  m_view(store, &m_bannerView),
18  m_settingButton(this, I18n::Message::HistogramSet, Invocation([](void * context, void * sender) {
19  HistogramController * histogramController = (HistogramController *) context;
20  StackViewController * stack = ((StackViewController *)histogramController->stackController());
21  stack->push(histogramController->histogramParameterController());
22  }, this)),
23  m_store(store),
24  m_storeVersion(storeVersion),
25  m_barVersion(barVersion),
26  m_rangeVersion(rangeVersion),
27  m_selectedBarIndex(selectedBarIndex),
28  m_histogramParameterController(nullptr, store)
29 {
30 }
31 
33  return I18n::translate(I18n::Message::HistogramTab);
34 }
35 
37  return &m_view;
38 }
39 
42  return stack;
43 }
44 
46  return &m_histogramParameterController;
47 }
48 
50  if (event == Ion::Events::Down) {
51  if (!m_view.isMainViewSelected()) {
53  m_view.selectMainView(true);
54  reloadBannerView();
55  m_view.reload();
56  app()->setFirstResponder(this);
57  return true;
58  }
59  return false;
60  }
61  if (event == Ion::Events::Up) {
62  if (!m_view.isMainViewSelected()) {
64  app()->setFirstResponder(tabController());
65  return true;
66  }
67  m_view.selectMainView(false);
69  return true;
70  }
71  if (m_view.isMainViewSelected() && (event == Ion::Events::Left || event == Ion::Events::Right)) {
72  int direction = event == Ion::Events::Left ? -1 : 1;
73  if (moveSelection(direction)) {
74  reloadBannerView();
75  m_view.reload();
76  }
77  return true;
78  }
79  return false;
80 }
81 
83  uint32_t storeChecksum = m_store->storeChecksum();
84  if (*m_storeVersion != storeChecksum) {
85  *m_storeVersion = storeChecksum;
86  initBarParameters();
87  }
88  uint32_t barChecksum = m_store->barChecksum();
89  if (*m_barVersion != barChecksum) {
90  *m_barVersion = barChecksum;
91  initRangeParameters();
92  }
93  uint32_t rangeChecksum = m_store->rangeChecksum();
94  if (*m_rangeVersion != rangeChecksum) {
95  *m_rangeVersion = rangeChecksum;
96  initBarSelection();
97  reloadBannerView();
98  }
99  if (!m_view.isMainViewSelected()) {
101  } else {
102  m_view.setHighlight(m_store->startOfBarAtIndex(*m_selectedBarIndex), m_store->endOfBarAtIndex(*m_selectedBarIndex));
103  }
104 }
105 
107  if (isEmpty()) {
108  return 0;
109  }
110  return 1;
111 }
113  return (Button *)&m_settingButton;
114 }
115 
117  if (m_store->sumOfColumn(1) == 0) {
118  return true;
119  }
120  return false;
121 }
122 
124  return I18n::Message::NoDataToPlot;
125 }
126 
128  return tabController();
129 }
130 
132  if (!m_view.isMainViewSelected()) {
133  m_view.selectMainView(true);
134  header()->setSelectedButton(-1);
135  }
136  reloadBannerView();
137  m_view.reload();
138 }
139 
141  if (nextFirstResponder == nullptr || nextFirstResponder == tabController()) {
142  m_view.selectMainView(false);
143  header()->setSelectedButton(-1);
144  m_view.reload();
145  }
146 }
147 
148 Responder * HistogramController::tabController() const {
150 }
151 
152 void HistogramController::reloadBannerView() {
153  char buffer[k_maxNumberOfCharacters+ PrintFloat::bufferSizeForFloatsWithPrecision(Constant::LargeNumberOfSignificantDigits)*2];
154  int numberOfChar = 0;
155  const char * legend = " [";
156  int legendLength = strlen(legend);
157  strlcpy(buffer, legend, legendLength+1);
158  numberOfChar += legendLength;
159  double lowerBound = m_store->startOfBarAtIndex(*m_selectedBarIndex);
160  numberOfChar += PrintFloat::convertFloatToText<double>(lowerBound, buffer+numberOfChar, PrintFloat::bufferSizeForFloatsWithPrecision(Constant::LargeNumberOfSignificantDigits), Constant::LargeNumberOfSignificantDigits);
161  buffer[numberOfChar++] = ';';
162  double upperBound = m_store->endOfBarAtIndex(*m_selectedBarIndex);
163  numberOfChar += PrintFloat::convertFloatToText<double>(upperBound, buffer+numberOfChar, PrintFloat::bufferSizeForFloatsWithPrecision(Constant::LargeNumberOfSignificantDigits), Constant::LargeNumberOfSignificantDigits);
164  buffer[numberOfChar++] = '[';
165  legend = " ";
166  legendLength = strlen(legend);
167  strlcpy(buffer+numberOfChar, legend, legendLength+1);
168  buffer[k_maxIntervalLegendLength] = 0;
169  m_bannerView.setLegendAtIndex(buffer, 1);
170 
171  numberOfChar = 0;
172  legend = ": ";
173  legendLength = strlen(legend);
174  strlcpy(buffer, legend, legendLength+1);
175  numberOfChar += legendLength;
176  double size = m_store->heightOfBarAtIndex(*m_selectedBarIndex);
177  numberOfChar += PrintFloat::convertFloatToText<double>(size, buffer+numberOfChar, PrintFloat::bufferSizeForFloatsWithPrecision(Constant::LargeNumberOfSignificantDigits), Constant::LargeNumberOfSignificantDigits);
178  legend = " ";
179  legendLength = strlen(legend);
180  strlcpy(buffer+numberOfChar, legend, legendLength+1);
181  buffer[k_maxLegendLength] = 0;
182  m_bannerView.setLegendAtIndex(buffer, 3);
183 
184  numberOfChar = 0;
185  legend = ": ";
186  legendLength = strlen(legend);
187  strlcpy(buffer, legend, legendLength+1);
188  numberOfChar += legendLength;
189  double frequency = size/m_store->sumOfColumn(1);
190  numberOfChar += PrintFloat::convertFloatToText<double>(frequency, buffer+numberOfChar, PrintFloat::bufferSizeForFloatsWithPrecision(Constant::LargeNumberOfSignificantDigits), Constant::LargeNumberOfSignificantDigits);
191  legend = " ";
192  legendLength = strlen(legend);
193  strlcpy(buffer+numberOfChar, legend, legendLength+1);
194  buffer[k_maxLegendLength] = 0;
195  m_bannerView.setLegendAtIndex(buffer, 5);
196 }
197 
198 bool HistogramController::moveSelection(int deltaIndex) {
199  int newSelectedBarIndex = *m_selectedBarIndex;
200  if (deltaIndex > 0) {
201  do {
202  newSelectedBarIndex++;
203  } while (m_store->heightOfBarAtIndex(newSelectedBarIndex) == 0 && newSelectedBarIndex < m_store->numberOfBars());
204  } else {
205  do {
206  newSelectedBarIndex--;
207  } while (m_store->heightOfBarAtIndex(newSelectedBarIndex) == 0 && newSelectedBarIndex >= 0);
208  }
209  if (newSelectedBarIndex >= 0 && newSelectedBarIndex < m_store->numberOfBars() && *m_selectedBarIndex != newSelectedBarIndex) {
210  *m_selectedBarIndex = newSelectedBarIndex;
211  m_view.setHighlight(m_store->startOfBarAtIndex(*m_selectedBarIndex), m_store->endOfBarAtIndex(*m_selectedBarIndex));
212  m_store->scrollToSelectedBarIndex(*m_selectedBarIndex);
213  return true;
214  }
215  return false;
216 }
217 
218 void HistogramController::initRangeParameters() {
219  float min = m_store->firstDrawnBarAbscissa();
220  float max = m_store->maxValue();
221  float barWidth = m_store->barWidth();
222  float xMin = min;
223  float xMax = max + barWidth;
224  /* if a bar is represented by less than one pixel, we cap xMax */
225  if ((xMax - xMin)/barWidth > k_maxNumberOfBarsPerWindow) {
226  xMax = xMin + k_maxNumberOfBarsPerWindow*barWidth;
227  }
228  /* Edge case */
229  if (xMin >= xMax) {
230  xMax = xMin + 10.0f*barWidth;
231  }
232  m_store->setXMin(xMin - Store::k_displayLeftMarginRatio*(xMax-xMin));
233  m_store->setXMax(xMax + Store::k_displayRightMarginRatio*(xMax-xMin));
234  float yMax = -FLT_MAX;
235  for (int index = 0; index < m_store->numberOfBars(); index++) {
236  float size = m_store->heightOfBarAtIndex(index);
237  if (size > yMax) {
238  yMax = size;
239  }
240  }
241  yMax = yMax/m_store->sumOfColumn(1);
242  yMax = yMax < 0 ? 1 : yMax;
244  m_store->setYMax(yMax*(1.0f+Store::k_displayTopMarginRatio));
245 }
246 
247 void HistogramController::initBarParameters() {
248  float min = m_store->minValue();
249  float max = m_store->maxValue();
250  max = min >= max ? min + std::pow(10.0f, std::floor(std::log10(std::fabs(min)))-1.0f) : max;
251  m_store->setFirstDrawnBarAbscissa(min);
252  float barWidth = m_store->computeGridUnit(CurveViewRange::Axis::X, min, max);
253  if (barWidth <= 0.0f) {
254  barWidth = 1.0f;
255  }
256  m_store->setBarWidth(barWidth);
257 }
258 
259 void HistogramController::initBarSelection() {
260  *m_selectedBarIndex = 0;
261  while ((m_store->heightOfBarAtIndex(*m_selectedBarIndex) == 0 ||
262  m_store->startOfBarAtIndex(*m_selectedBarIndex) < m_store->firstDrawnBarAbscissa()) && *m_selectedBarIndex < m_store->numberOfBars()) {
263  *m_selectedBarIndex = *m_selectedBarIndex+1;
264  }
265  if (*m_selectedBarIndex >= m_store->numberOfBars()) {
266  /* No bar is after m_firstDrawnBarAbscissa, so we select the first bar */
267  *m_selectedBarIndex = 0;
268  while (m_store->heightOfBarAtIndex(*m_selectedBarIndex) == 0 && *m_selectedBarIndex < m_store->numberOfBars()) {
269  *m_selectedBarIndex = *m_selectedBarIndex+1;
270  }
271  }
272  m_store->scrollToSelectedBarIndex(*m_selectedBarIndex);
273 }
274 
275 }
void setLegendAtIndex(char *text, int index)
Definition: banner_view.cpp:7
bool isMainViewSelected() const
Definition: curve_view.cpp:42
Definition: i18n.h:6
static constexpr float k_displayLeftMarginRatio
Definition: store.h:45
void setFirstDrawnBarAbscissa(double firstDrawnBarAbscissa)
Definition: store.cpp:44
uint32_t barChecksum()
Definition: store.cpp:20
static constexpr float k_displayRightMarginRatio
Definition: store.h:43
double maxValue()
Definition: store.cpp:98
void push(ViewController *vc, KDColor textColor=Palette::SubTab, KDColor backgroundColor=KDColorWhite, KDColor separatorColor=Palette::GreyBright)
Responder * parentResponder() const
Definition: responder.cpp:12
constexpr Event Up
Definition: events.h:62
double barWidth()
Definition: store.cpp:29
constexpr Event Down
Definition: events.h:63
Button * buttonAtIndex(int index, ButtonRowController::Position position) const override
size_t strlcpy(char *dst, const char *src, size_t len)
Definition: strlcpy.c:3
double heightOfBarAtIndex(int index)
Definition: store.cpp:48
double firstDrawnBarAbscissa()
Definition: store.cpp:40
bool handleEvent(Ion::Events::Event event) override
double numberOfBars()
Definition: store.cpp:69
double endOfBarAtIndex(int index)
Definition: store.cpp:65
static constexpr float k_displayBottomMarginRatio
Definition: store.h:44
#define fabs(x)
Definition: math.h:178
double minValue()
Definition: store.cpp:108
enum Message uint16_t enum Language uint16_t const char * translate(Message m, Language l=(Language) 0)
Definition: i18n.cpp:5
#define FLT_MAX
Definition: float.h:6
size_t strlen(const char *s)
Definition: strlen.c:3
ButtonRowController * header()
unsigned int uint32_t
Definition: stdint.h:6
static constexpr float k_displayTopMarginRatio
Definition: store.h:42
void setBarWidth(double barWidth)
Definition: store.cpp:33
I18n::Message emptyMessage() override
#define pow(x, y)
Definition: math.h:190
static constexpr int LargeNumberOfSignificantDigits
Definition: constant.h:6
#define log10(x)
Definition: math.h:186
virtual uint32_t rangeChecksum()
constexpr Event Left
Definition: events.h:61
bool setSelectedButton(int selectedButton)
float computeGridUnit(Axis axis, float min, float max)
int numberOfButtons(ButtonRowController::Position) const override
void setFirstResponder(Responder *responder)
Definition: app.cpp:62
Definition: view.h:23
constexpr Event Right
Definition: events.h:64
void willExitResponderChain(Responder *nextFirstResponder) override
void selectMainView(bool mainViewSelected)
Definition: curve_view.cpp:46
bool scrollToSelectedBarIndex(int index)
Definition: store.cpp:74
StackViewController * stackController()
Responder * defaultController() override
void setHighlight(float start, float end)
App * app()
Definition: responder.cpp:77
#define floor(x)
Definition: math.h:179
Definition: button.h:10
double startOfBarAtIndex(int index)
Definition: store.cpp:60
HistogramParameterController * histogramParameterController()