Numworks Epsilon  1.4.1
Graphing Calculator Operating System
calculation_controller.cpp
Go to the documentation of this file.
2 #include "../constant.h"
3 #include "../apps_container.h"
4 #include "app.h"
9 #include "images/calcul1_icon.h"
10 #include "images/calcul2_icon.h"
11 #include "images/calcul3_icon.h"
12 #include "images/calcul4_icon.h"
13 #include "images/focused_calcul1_icon.h"
14 #include "images/focused_calcul2_icon.h"
15 #include "images/focused_calcul3_icon.h"
16 #include "images/focused_calcul4_icon.h"
17 #include <assert.h>
18 #include <cmath>
19 
20 using namespace Poincare;
21 using namespace Shared;
22 
23 namespace Probability {
24 
25 CalculationController::ContentView::ContentView(SelectableTableView * selectableTableView, Law * law, Calculation * calculation) :
26  m_titleView(KDText::FontSize::Small, I18n::Message::ComputeProbability, 0.5f, 0.5f, Palette::GreyDark, Palette::WallScreen),
27  m_selectableTableView(selectableTableView),
28  m_lawCurveView(law, calculation)
29 {
30 }
31 
32 int CalculationController::ContentView::numberOfSubviews() const {
33  return 3;
34 }
35 
36 View * CalculationController::ContentView::subviewAtIndex(int index) {
37  assert(index >= 0 && index < 3);
38  if (index == 0) {
39  return &m_titleView;
40  }
41  if (index == 1) {
42  return m_selectableTableView;
43  }
44  return &m_lawCurveView;
45 }
46 
47 void CalculationController::ContentView::layoutSubviews() {
48  KDCoordinate titleHeight = KDText::charSize(KDText::FontSize::Small).height()+k_titleHeightMargin;
49  m_titleView.setFrame(KDRect(0, 0, bounds().width(), titleHeight));
50  KDCoordinate calculationHeight = ResponderImageCell::k_oneCellHeight+2*k_tableMargin;
51  m_selectableTableView->setFrame(KDRect(0, titleHeight, bounds().width(), calculationHeight));
52  m_lawCurveView.setFrame(KDRect(0, titleHeight+calculationHeight, bounds().width(), bounds().height() - calculationHeight - titleHeight));
53 }
54 
55 CalculationController::CalculationController(Responder * parentResponder, Law * law, Calculation * calculation) :
56  ViewController(parentResponder),
57  m_contentView(&m_selectableTableView, law, calculation),
58  m_selectableTableView(this),
59  m_imageCell(&m_selectableTableView, law, calculation, this),
60  m_draftTextBuffer{},
61  m_calculation(calculation),
62  m_law(law)
63 {
64  assert(law != nullptr);
65  assert(calculation != nullptr);
66  m_selectableTableView.setMargins(k_tableMargin);
67  m_selectableTableView.setVerticalCellOverlap(0);
68  m_selectableTableView.setShowsIndicators(false);
69  m_selectableTableView.setBackgroundColor(KDColorWhite);
70 
71 
72  for (int i = 0; i < k_numberOfCalculationCells; i++) {
73  m_calculationCells[i].editableTextCell()->setParentResponder(&m_selectableTableView);
74  m_calculationCells[i].editableTextCell()->textField()->setDelegate(this);
75  m_calculationCells[i].editableTextCell()->textField()->setDraftTextBuffer(m_draftTextBuffer);
76  }
77 }
78 
80  App::Snapshot * snapshot = (App::Snapshot *)app()->snapshot();
82  updateTitle();
84  m_selectableTableView.reloadData();
85 }
86 
88  app()->setFirstResponder(&m_selectableTableView);
89 }
90 
92  if (event == Ion::Events::Copy && selectedColumn() > 0) {
93  CalculationCell * myCell = static_cast<CalculationCell *>(m_selectableTableView.selectedCell());
95  return true;
96  }
97  return false;
98 }
99 
101  return &m_contentView;
102 }
103 
105  return m_titleBuffer;
106 }
107 
110  selectCellAtLocation(1, 0);
111 }
112 
114  m_selectableTableView.deselectTable();
116 }
117 
119  return 1;
120 }
121 
123  return m_calculation->numberOfParameters()+1;
124 }
125 
126 /* WARNING: we set one type per cell to be able to deduce the column width from
127  * the cell minimalSizeForOptimalDisplay. Otherwise, we can not know which cell
128  * to interrogate to get the column width and we neither can call
129  * tableView->cellAtLocation as this function depends on the
130  * numberOfDisplaybleRows which depends on the column width! */
131 
133  if (i == 0) {
134  return m_imageCell.minimalSizeForOptimalDisplay().width();
135  }
136  // WARNING: that is possible only because we know which view cell corresponds to which cell
137  return m_calculationCells[i-1].minimalSizeForOptimalDisplay().width();
138 }
139 
142 }
143 
145  int result = 0;
146  for (int k = 0; k < j; k++) {
147  result += columnWidth(k);
148  }
149  return result;
150 }
151 
153  int result = 0;
154  int i = 0;
155  while (result < offsetX && i < numberOfColumns()) {
156  result += columnWidth(i++);
157  }
158  return (result < offsetX || offsetX == 0) ? i : i - 1;
159 }
160 
162  return rowHeight(0) * j;
163 }
164 
166  KDCoordinate height = rowHeight(0);
167  if (height == 0) {
168  return 0;
169  }
170  return (offsetY - 1) / height;
171 }
172 
174  assert(index == 0);
175  switch(type) {
176  case 0:
177  return &m_imageCell;
178  default:
179  return &m_calculationCells[type-1];
180  }
181 }
182 
184  return 1;
185 }
186 
188  return i;
189 }
190 
192  if (i == 0) {
193  ResponderImageCell * myCell = static_cast<ResponderImageCell *>(cell);
194  const Image * images[CalculationTypeController::k_numberOfImages] = {ImageStore::Calcul1Icon, ImageStore::Calcul2Icon, ImageStore::Calcul3Icon, ImageStore::Calcul4Icon};
195  const Image * focusedImages[CalculationTypeController::k_numberOfImages] = {ImageStore::FocusedCalcul1Icon, ImageStore::FocusedCalcul2Icon, ImageStore::FocusedCalcul3Icon, ImageStore::FocusedCalcul4Icon};
196  myCell->setImage(images[(int)m_calculation->type()], focusedImages[(int)m_calculation->type()]);
197  } else {
198  CalculationCell * myCell = static_cast<CalculationCell *>(cell);
199  myCell->messageTextView()->setMessage(m_calculation->legendForParameterAtIndex(i-1));
200  bool calculationCellIsResponder = true;
201  if ((m_law->type() != Law::Type::Normal && i == 3) || (m_calculation->type() == Calculation::Type::Discrete && i == 2)) {
202  calculationCellIsResponder = false;
203  }
204  myCell->setResponder(calculationCellIsResponder);
205  TextField * field = static_cast<CalculationCell *>(cell)->editableTextCell()->textField();
206  if (field->isEditing()) {
207  return;
208  }
209  char buffer[PrintFloat::bufferSizeForFloatsWithPrecision(Constant::LargeNumberOfSignificantDigits)];
210  PrintFloat::convertFloatToText<double>(m_calculation->parameterAtIndex(i-1), buffer, PrintFloat::bufferSizeForFloatsWithPrecision(Constant::LargeNumberOfSignificantDigits), Constant::LargeNumberOfSignificantDigits, PrintFloat::Mode::Decimal);
211  field->setText(buffer);
212  }
213 }
214 
215 bool CalculationController::textFieldDidHandleEvent(::TextField * textField, bool returnValue, bool textHasChanged) {
216  if (returnValue && textHasChanged) {
217  /* We do not reload the responder because the first responder might be the
218  * toolbox (or the variable box) and reloading the responder would corrupt
219  * the first responder. */
220  bool shouldUpdateFirstResponder = app()->firstResponder() == textField;
221  m_selectableTableView.reloadData(shouldUpdateFirstResponder);
222  // The textField frame might have increased which forces to reload the textField scroll
223  textField->scrollToCursor();
224  }
225  return returnValue;
226 }
227 
229  return TextFieldDelegate::textFieldShouldFinishEditing(textField, event)
230  || (event == Ion::Events::Right && textField->cursorLocation() == textField->draftTextLength() && selectedColumn() < m_calculation->numberOfParameters())
231  || (event == Ion::Events::Left && textField->cursorLocation() == 0);
232 }
233 
235  App * probaApp = (App *)app();
236  Context * globalContext = probaApp->container()->globalContext();
237  double floatBody = Expression::approximateToScalar<double>(text, *globalContext);
238  if (std::isnan(floatBody) || std::isinf(floatBody)) {
239  app()->displayWarning(I18n::Message::UndefinedValue);
240  return false;
241  }
242  if (m_calculation->type() != Calculation::Type::FiniteIntegral && selectedColumn() == 2) {
243  if (floatBody < 0.0) {
244  floatBody = 0.0;
245  }
246  if (floatBody > 1.0) {
247  floatBody = 1.0;
248  }
249  }
250  if (!m_law->isContinuous() && (selectedColumn() == 1 || m_calculation->type() == Calculation::Type::FiniteIntegral)) {
251  floatBody = std::round(floatBody);
252  }
253  m_calculation->setParameterAtIndex(floatBody, selectedColumn()-1);
254  if (event == Ion::Events::Right || event == Ion::Events::Left) {
255  m_selectableTableView.handleEvent(event);
256  }
257  reload();
258  return true;
259 }
260 
262  m_contentView.lawCurveView()->reload();
263 }
264 
266  m_selectableTableView.reloadData();
268 }
269 
270 void CalculationController::setCalculationAccordingToIndex(int index, bool forceReinitialisation) {
271  if ((int)m_calculation->type() == index && !forceReinitialisation) {
272  return;
273  }
274  m_calculation->~Calculation();
275  switch (index) {
276  case 0:
277  new(m_calculation) LeftIntegralCalculation();
278  break;
279  case 1:
280  new(m_calculation) FiniteIntegralCalculation();
281  break;
282  case 2:
283  new(m_calculation) RightIntegralCalculation();
284  break;
285  case 3:
286  new(m_calculation) DiscreteCalculation();
287  break;
288  default:
289  return;
290  }
291  m_calculation->setLaw(m_law);
292 }
293 
294 TextFieldDelegateApp * CalculationController::textFieldDelegateApp() {
295  return (App *)app();
296 }
297 
298 void CalculationController::updateTitle() {
299  int currentChar = 0;
300  for (int index = 0; index < m_law->numberOfParameter(); index++) {
301  m_titleBuffer[currentChar++] = I18n::translate(m_law->parameterNameAtIndex(index))[0];
302  strlcpy(m_titleBuffer+currentChar, " = ", 4);
303  currentChar += 3;
304  char buffer[PrintFloat::bufferSizeForFloatsWithPrecision(Constant::ShortNumberOfSignificantDigits)];
305  PrintFloat::convertFloatToText<double>(m_law->parameterValueAtIndex(index), buffer, PrintFloat::bufferSizeForFloatsWithPrecision(Constant::ShortNumberOfSignificantDigits), Constant::ShortNumberOfSignificantDigits, PrintFloat::Mode::Decimal);
306  strlcpy(m_titleBuffer+currentChar, buffer, strlen(buffer)+1);
307  currentChar += strlen(buffer);
308  m_titleBuffer[currentChar++] = ' ';
309  }
310  m_titleBuffer[currentChar-1] = 0;
311 }
312 
313 }
bool isEditing() const
Definition: text_field.cpp:175
virtual bool isContinuous() const =0
virtual double parameterAtIndex(int index)=0
Definition: i18n.h:6
EditableTextCell * editableTextCell()
#define assert(e)
Definition: assert.h:9
int indexFromCumulatedWidth(KDCoordinate offsetX) override
#define isinf(x)
Definition: math.h:44
virtual I18n::Message parameterNameAtIndex(int index)=0
HighlightCell * selectedCell()
static constexpr KDCoordinate k_oneCellHeight
KDCoordinate cumulatedHeightFromIndex(int j) override
void setText(const char *text)
Definition: text_field.cpp:184
size_t cursorLocation() const
Definition: text_input.h:19
int16_t KDCoordinate
Definition: coordinate.h:6
constexpr KDCoordinate width() const
Definition: size.h:10
KDSize minimalSizeForOptimalDisplay() const override
bool textFieldShouldFinishEditing(TextField *textField, Ion::Events::Event event) override
void willDisplayCellAtLocation(HighlightCell *cell, int i, int j) override
bool textFieldDidFinishEditing(TextField *textField, const char *text, Ion::Events::Event event) override
Snapshot * snapshot()
Definition: app.cpp:41
size_t strlcpy(char *dst, const char *src, size_t len)
Definition: strlcpy.c:3
TextField * textField()
Definition: image.h:6
Definition: text.h:8
virtual int numberOfParameter()=0
static constexpr int ShortNumberOfSignificantDigits
Definition: constant.h:8
virtual float parameterValueAtIndex(int index)=0
void setCalculationAccordingToIndex(int index, bool forceReinitialisation=false)
virtual ~Calculation()=default
void store(const char *storedText)
Definition: clipboard.cpp:9
void reloadData(bool setFirstResponder=true)
enum Message uint16_t enum Language uint16_t const char * translate(Message m, Language l=(Language) 0)
Definition: i18n.cpp:5
virtual I18n::Message legendForParameterAtIndex(int index)=0
constexpr KDColor KDColorWhite
Definition: color.h:42
KDCoordinate columnWidth(int i) override
size_t strlen(const char *s)
Definition: strlen.c:3
bool textFieldDidHandleEvent(TextField *textField, bool returnValue, bool textHasChanged) override
void displayWarning(I18n::Message warningMessage)
Definition: app.cpp:97
#define round(x)
Definition: math.h:192
void setMessage(I18n::Message message)
Poincare::Context * globalContext()
HighlightCell * reusableCell(int index, int type) override
virtual void viewWillAppear()
virtual Type type() const =0
static constexpr int LargeNumberOfSignificantDigits
Definition: constant.h:6
KDSize minimalSizeForOptimalDisplay() const override
#define isnan(x)
Definition: math.h:43
Responder * firstResponder()
Definition: app.cpp:58
void setResponder(bool shouldbeResponder)
constexpr Event Left
Definition: events.h:61
const char * text() const
Definition: text_input.h:14
KDCoordinate rowHeight(int j) override
MessageTextView * messageTextView()
constexpr Event Copy
Definition: events.h:123
Definition: rect.h:26
CalculationController(Responder *parentResponder, Law *law, Calculation *calculation)
size_t draftTextLength() const
Definition: text_field.cpp:179
void setImage(const Image *image, const Image *focusedImage)
void setFirstResponder(Responder *responder)
Definition: app.cpp:62
int indexFromCumulatedHeight(KDCoordinate offsetY) override
Definition: view.h:23
constexpr Event Right
Definition: events.h:64
virtual bool textFieldShouldFinishEditing(TextField *textField, Ion::Events::Event event)=0
virtual bool handleEvent(Ion::Events::Event event) override
static Clipboard * sharedClipboard()
Definition: clipboard.cpp:5
static constexpr KDSize charSize(FontSize size=FontSize::Large)
Definition: text.h:16
void didEnterResponderChain(Responder *previousResponder) override
virtual void viewDidDisappear()
App * app()
Definition: responder.cpp:77
virtual int numberOfParameters()=0
void setActivePage(Page activePage)
Definition: app.cpp:62
virtual Type type()=0
bool handleEvent(Ion::Events::Event event) override
virtual void setParameterAtIndex(double f, int index)=0
void scrollToCursor() override
Definition: text_field.cpp:296
KDCoordinate cumulatedWidthFromIndex(int i) override
constexpr KDCoordinate height() const
Definition: size.h:11
Definition: palette.h:6