Numworks Epsilon  1.4.1
Graphing Calculator Operating System
sum_graph_controller.cpp
Go to the documentation of this file.
1 #include "sum_graph_controller.h"
2 #include "../apps_container.h"
3 #include "../../poincare/src/layout/condensed_sum_layout.h"
4 #include "../../poincare/src/layout/string_layout.h"
5 #include "../../poincare/src/layout/horizontal_layout.h"
6 
7 #include <assert.h>
8 #include <cmath>
9 #include <stdlib.h>
10 
11 using namespace Poincare;
12 
13 namespace Shared {
14 
15 SumGraphController::SumGraphController(Responder * parentResponder, FunctionGraphView * graphView, InteractiveCurveViewRange * range, CurveViewCursor * cursor, char sumSymbol) :
16  SimpleInteractiveCurveViewController(parentResponder, range, graphView, cursor),
17  m_step(Step::FirstParameter),
18  m_startSum(NAN),
19  m_endSum(NAN),
20  m_function(nullptr),
21  m_graphRange(range),
22  m_graphView(graphView),
23  m_legendView(this, sumSymbol),
24  m_cursorView()
25 {
26 }
27 
29  m_graphRange->panToMakePointVisible(m_cursor->x(), m_cursor->y(), k_cursorTopMarginRatio, k_cursorRightMarginRatio, k_cursorBottomMarginRatio, k_cursorLeftMarginRatio);
30  m_graphView->setBannerView(&m_legendView);
31  m_graphView->setCursorView(&m_cursorView);
32  m_graphView->setOkView(nullptr);
33  m_graphView->selectMainView(true);
34  m_graphView->setAreaHighlightColor(false);
35  m_graphView->setAreaHighlight(NAN, NAN);
36  m_graphView->reload();
37 
38  m_startSum = m_cursor->x();
39  m_endSum = NAN;
41  m_legendView.setLegendMessage(legendMessageAtStep(Step::FirstParameter), Step::FirstParameter);
42  m_legendView.setEditableZone(m_startSum);
43  m_legendView.setSumSymbol(m_step);
44 }
45 
46 
47 void SumGraphController::didEnterResponderChain(Responder * previousFirstResponder) {
48  app()->setFirstResponder(m_legendView.textField());
49 }
50 
52  if (event == Ion::Events::Plus || event == Ion::Events::Minus) {
53  return handleZoom(event);
54  }
55  if ((int)m_step > 1 && event != Ion::Events::OK && event != Ion::Events::EXE && event != Ion::Events::Back) {
56  return false;
57  }
58  if (event == Ion::Events::Left && !m_legendView.textField()->isEditing()) {
59  if ((int)m_step > 0 && m_startSum >= m_cursor->x()) {
60  return false;
61  }
62  if (moveCursorHorizontallyToPosition(cursorNextStep(m_cursor->x(), -1))) {
63  m_graphView->reload();
64  return true;
65  }
66  return false;
67  }
68  if (event == Ion::Events::Right && !m_legendView.textField()->isEditing()) {
69  if (moveCursorHorizontallyToPosition(cursorNextStep(m_cursor->x(), 1))) {
70  m_graphView->reload();
71  return true;
72  }
73  return false;
74  }
75  if (event == Ion::Events::OK || event == Ion::Events::EXE) {
76  return handleEnter();
77  }
78  if (event == Ion::Events::Back && (int)m_step > 0) {
79  m_step = (Step)((int)m_step-1);
80  m_legendView.setLegendMessage(legendMessageAtStep(m_step), m_step);
82  app()->setFirstResponder(m_legendView.textField());
83  m_graphView->setAreaHighlightColor(false);
84  m_graphView->setCursorView(&m_cursorView);
85  m_endSum = m_cursor->x();
86  m_legendView.setEditableZone(m_endSum);
87  m_legendView.setSumSymbol(m_step, m_startSum);
88  }
90  m_graphView->setAreaHighlight(NAN,NAN);
92  m_legendView.setLegendMessage(legendMessageAtStep(m_step), m_step);
93  m_legendView.setEditableZone(m_startSum);
94  m_legendView.setSumSymbol(m_step);
95  m_graphView->reload();
96  }
97  return true;
98  }
99  return false;
100 }
101 
104  if (m_function == nullptr) {
105  return false;
106  }
107  double y = m_function->evaluateAtAbscissa(x, myApp->localContext());
108  m_cursor->moveTo(x, y);
109  if (m_step == Step::FirstParameter) {
110  m_startSum = m_cursor->x();
111  m_legendView.setEditableZone(m_startSum);
112  }
113  if (m_step == Step::SecondParameter) {
114  m_graphView->setAreaHighlight(m_startSum, m_cursor->x());
115  m_endSum = m_cursor->x();
116  m_legendView.setEditableZone(m_endSum);
117  }
118  m_graphRange->panToMakePointVisible(x, y, k_cursorTopMarginRatio, k_cursorRightMarginRatio, k_cursorBottomMarginRatio, k_cursorLeftMarginRatio);
119  return true;
120 }
121 
123  m_graphView->selectFunction(function);
124  m_function = function;
125 }
126 
128  AppsContainer * appsContainer = ((TextFieldDelegateApp *)app())->container();
129  Context * globalContext = appsContainer->globalContext();
130  double floatBody = Expression::approximateToScalar<double>(text, *globalContext);
131  if (std::isnan(floatBody) || std::isinf(floatBody)) {
132  app()->displayWarning(I18n::Message::UndefinedValue);
133  return false;
134  }
135  if (m_step == Step::SecondParameter && floatBody < m_startSum) {
136  app()->displayWarning(I18n::Message::ForbiddenValue);
137  return false;
138  }
139  if (moveCursorHorizontallyToPosition(floatBody)) {
140  handleEnter();
141  m_graphView->reload();
142  return true;
143  }
144  app()->displayWarning(I18n::Message::ForbiddenValue);
145  return false;
146 }
147 
148 bool SumGraphController::textFieldDidAbortEditing(TextField * textField, const char * text) {
149  char buffer[PrintFloat::bufferSizeForFloatsWithPrecision(Constant::MediumNumberOfSignificantDigits)];
150  double parameter = NAN;
151  switch(m_step) {
153  parameter = m_startSum;
154  break;
156  parameter = m_endSum;
157  break;
158  default:
159  assert(false);
160  }
161  PrintFloat::convertFloatToText<double>(parameter, buffer, PrintFloat::bufferSizeForFloatsWithPrecision(Constant::MediumNumberOfSignificantDigits), Constant::MediumNumberOfSignificantDigits, PrintFloat::Mode::Decimal);
162  textField->setText(buffer);
163  return true;
164 }
165 
167  if ((event == Ion::Events::OK || event == Ion::Events::EXE) && !textField->isEditing()) {
168  return handleEnter();
169  }
170  if (m_step == Step::Result) {
171  return handleEvent(event);
172  }
173  return TextFieldDelegate::textFieldDidReceiveEvent(textField, event);
174 }
175 
176 bool SumGraphController::handleEnter() {
177  if (m_step == Step::Result) {
179  stack->pop();
180  return true;
181  }
182  if (m_step == Step::FirstParameter) {
184  m_graphView->setAreaHighlight(m_startSum,m_startSum);
185  m_endSum = m_cursor->x();
186  m_legendView.setEditableZone(m_endSum);
187  m_legendView.setSumSymbol(m_step, m_startSum);
188  m_legendView.setLegendMessage(legendMessageAtStep(m_step), m_step);
189  return true;
190  }
191  m_step = (Step)((int)m_step+1);
192  TextFieldDelegateApp * myApp = static_cast<TextFieldDelegateApp *>(app());
193  double sum = m_function->sumBetweenBounds(m_startSum, m_endSum, myApp->localContext());
194  m_legendView.setSumSymbol(m_step, m_startSum, m_endSum, sum, createFunctionLayout(m_function->name()));
195  m_legendView.setLegendMessage(I18n::Message::Default, m_step);
196  m_graphView->setAreaHighlightColor(true);
197  m_graphView->setCursorView(nullptr);
198  myApp->setFirstResponder(this);
199  return true;
200 }
201 
202 /* Legend View */
203 
204 SumGraphController::LegendView::LegendView(SumGraphController * controller, char sumSymbol) :
205  m_sum(0.0f, 0.5f, KDColorBlack, Palette::GreyMiddle),
206  m_sumLayout(nullptr),
207  m_legend(KDText::FontSize::Small, I18n::Message::Default, 0.0f, 0.5f, KDColorBlack, Palette::GreyMiddle),
208  m_editableZone(controller, m_draftText, m_draftText, TextField::maxBufferSize(), controller, false, KDText::FontSize::Small, 0.0f, 0.5f, KDColorBlack, Palette::GreyMiddle),
209  m_sumSymbol(sumSymbol)
210 {
211  m_draftText[0] = 0;
212 }
213 
214 SumGraphController::LegendView::~LegendView() {
215  if (m_sumLayout != nullptr) {
216  delete m_sumLayout;
217  m_sumLayout = nullptr;
218  }
219 }
220 
221 void SumGraphController::LegendView::drawRect(KDContext * ctx, KDRect rect) const {
222  ctx->fillRect(bounds(), Palette::GreyMiddle);
223 }
224 
225 KDSize SumGraphController::LegendView::minimalSizeForOptimalDisplay() const {
226  return KDSize(0, k_legendHeight);
227 }
228 
229 void SumGraphController::LegendView::setLegendMessage(I18n::Message message, Step step) {
230  m_legend.setMessage(message);
231  layoutSubviews(step);
232 }
233 
234 void SumGraphController::LegendView::setEditableZone(double d) {
235  char buffer[PrintFloat::bufferSizeForFloatsWithPrecision(Constant::MediumNumberOfSignificantDigits)];
236  PrintFloat::convertFloatToText<double>(d, buffer, PrintFloat::bufferSizeForFloatsWithPrecision(Constant::MediumNumberOfSignificantDigits), Constant::MediumNumberOfSignificantDigits, PrintFloat::Mode::Decimal);
237  m_editableZone.setText(buffer);
238 }
239 
240 void SumGraphController::LegendView::setSumSymbol(Step step, double start, double end, double result, ExpressionLayout * functionLayout) {
241  assert(step == Step::Result || functionLayout == nullptr);
242  if (m_sumLayout) {
243  delete m_sumLayout;
244  m_sumLayout = nullptr;
245  }
246  const char sigma[] = {' ', m_sumSymbol};
247  if (step == Step::FirstParameter) {
248  m_sumLayout = new StringLayout(sigma, sizeof(sigma));
249  } else if (step == Step::SecondParameter) {
250  char buffer[PrintFloat::bufferSizeForFloatsWithPrecision(Constant::MediumNumberOfSignificantDigits)];
251  PrintFloat::convertFloatToText<double>(start, buffer, PrintFloat::bufferSizeForFloatsWithPrecision(Constant::MediumNumberOfSignificantDigits), Constant::MediumNumberOfSignificantDigits, PrintFloat::Mode::Decimal);
252  m_sumLayout = new CondensedSumLayout(new StringLayout(sigma, sizeof(sigma)), new StringLayout(buffer, strlen(buffer), KDText::FontSize::Small), nullptr);
253  } else {
254  char buffer[2+PrintFloat::bufferSizeForFloatsWithPrecision(Constant::LargeNumberOfSignificantDigits)];
255  PrintFloat::convertFloatToText<double>(start, buffer, PrintFloat::bufferSizeForFloatsWithPrecision(Constant::LargeNumberOfSignificantDigits), Constant::LargeNumberOfSignificantDigits, PrintFloat::Mode::Decimal);
257  PrintFloat::convertFloatToText<double>(end, buffer, PrintFloat::bufferSizeForFloatsWithPrecision(Constant::LargeNumberOfSignificantDigits), Constant::LargeNumberOfSignificantDigits, PrintFloat::Mode::Decimal);
258  ExpressionLayout * end = new StringLayout(buffer, strlen(buffer), KDText::FontSize::Small);
259  m_sumLayout = new CondensedSumLayout(new StringLayout(sigma, sizeof(sigma)), start, end);
260 
261  ExpressionLayout * childrenLayouts[3];
262  strlcpy(buffer, "= ", 3);
263  PrintFloat::convertFloatToText<double>(result, buffer+2, PrintFloat::bufferSizeForFloatsWithPrecision(Constant::LargeNumberOfSignificantDigits), Constant::LargeNumberOfSignificantDigits);
264  childrenLayouts[2] = new StringLayout(buffer, strlen(buffer), KDText::FontSize::Small);
265  childrenLayouts[1] = functionLayout;
266  childrenLayouts[0] = m_sumLayout;
267  m_sumLayout = new HorizontalLayout(childrenLayouts, 3);
268  }
269  m_sum.setExpression(m_sumLayout);
270  if (step == Step::Result) {
271  m_sum.setAlignment(0.5f, 0.5f);
272  } else {
273  m_sum.setAlignment(0.0f, 0.5f);
274  }
275  layoutSubviews(step);
276 }
277 
278 int SumGraphController::LegendView::numberOfSubviews() const {
279  return 3;
280 }
281 
282 View * SumGraphController::LegendView::subviewAtIndex(int index) {
283  assert(index >= 0 && index < 3);
284  if (index == 0) {
285  return &m_sum;
286  }
287  if (index == 1) {
288  return &m_editableZone;
289  }
290  return &m_legend;
291 }
292 
293 void SumGraphController::LegendView::layoutSubviews() {
294  layoutSubviews(Step::FirstParameter);
295 }
296 
297 void SumGraphController::LegendView::layoutSubviews(Step step) {
298  KDCoordinate width = bounds().width();
299  KDCoordinate heigth = bounds().height();
300  KDSize legendSize = m_legend.minimalSizeForOptimalDisplay();
301 
302  if (legendSize.width() > 0) {
303  m_sum.setFrame(KDRect(0, k_symbolHeightMargin, width-legendSize.width(), m_sum.minimalSizeForOptimalDisplay().height()));
304  m_legend.setFrame(KDRect(width-legendSize.width(), 0, legendSize.width(), heigth));
305  } else {
306  m_sum.setFrame(bounds());
307  m_legend.setFrame(KDRectZero);
308  }
309 
310  KDSize largeCharSize = KDText::charSize();
311  switch(step) {
312  case Step::FirstParameter:
313  m_editableZone.setFrame(KDRect(2*largeCharSize.width(), k_symbolHeightMargin+k_sigmaHeight/2, k_editableZoneWidth, k_editableZoneHeight));
314  return;
315  case Step::SecondParameter:
316  m_editableZone.setFrame(KDRect(2*largeCharSize.width(), k_symbolHeightMargin+k_sigmaHeight/2-k_editableZoneHeight, k_editableZoneWidth, k_editableZoneHeight));
317  return;
318  default:
319  m_editableZone.setFrame(KDRectZero);
320  }
321 }
322 
323 }
constexpr Event Plus
Definition: events.h:107
bool textFieldDidFinishEditing(TextField *textField, const char *text, Ion::Events::Event event) override
bool isEditing() const
Definition: text_field.cpp:175
#define NAN
Definition: math.h:30
Definition: i18n.h:6
#define assert(e)
Definition: assert.h:9
#define isinf(x)
Definition: math.h:44
static constexpr int MediumNumberOfSignificantDigits
Definition: constant.h:7
constexpr Event Minus
Definition: events.h:108
void setText(const char *text)
Definition: text_field.cpp:184
constexpr Event EXE
Definition: events.h:114
int16_t KDCoordinate
Definition: coordinate.h:6
constexpr KDCoordinate width() const
Definition: size.h:10
Responder * parentResponder() const
Definition: responder.cpp:12
void setBannerView(View *bannerView)
Definition: curve_view.cpp:71
void setOkView(View *okView)
Definition: curve_view.cpp:77
size_t strlcpy(char *dst, const char *src, size_t len)
Definition: strlcpy.c:3
virtual double sumBetweenBounds(double start, double end, Poincare::Context *context) const =0
Definition: text.h:8
constexpr Event Back
Definition: events.h:66
virtual Poincare::Context * localContext()
Definition: size.h:6
size_t strlen(const char *s)
Definition: strlen.c:3
bool textFieldDidAbortEditing(TextField *textField, const char *text) override
void displayWarning(I18n::Message warningMessage)
Definition: app.cpp:97
void didEnterResponderChain(Responder *previousFirstResponder) override
InteractiveCurveViewRange * m_graphRange
Poincare::Context * globalContext()
static constexpr int LargeNumberOfSignificantDigits
Definition: constant.h:6
void setAreaHighlight(float start, float end)
const char * name() const
Definition: function.cpp:68
constexpr KDColor KDColorBlack
Definition: color.h:41
#define false
Definition: stdbool.h:9
void moveTo(double x, double y)
#define isnan(x)
Definition: math.h:43
static constexpr KDColor GreyMiddle
Definition: palette.h:14
bool textFieldDidReceiveEvent(TextField *textField, Ion::Events::Event event) override
constexpr Event Left
Definition: events.h:61
void start()
Definition: rt0.cpp:31
void panToMakePointVisible(float x, float y, float topMarginRatio, float rightMarginRatio, float bottomMarginRation, float leftMarginRation)
constexpr KDRect KDRectZero
Definition: rect.h:70
Definition: rect.h:26
void fillRect(KDRect rect, KDColor color)
Definition: context_rect.cpp:8
bool textFieldDidReceiveEvent(TextField *textField, Ion::Events::Event event) override
virtual float evaluateAtAbscissa(float x, Poincare::Context *context) const
Definition: function.h:30
void setCursorView(View *cursorView)
Definition: curve_view.cpp:64
void setFirstResponder(Responder *responder)
Definition: app.cpp:62
Definition: view.h:23
constexpr Event Right
Definition: events.h:64
virtual void reload()
Definition: curve_view.cpp:25
void selectMainView(bool mainViewSelected)
Definition: curve_view.cpp:46
void setFunction(Function *function)
static constexpr KDSize charSize(FontSize size=FontSize::Large)
Definition: text.h:16
void selectFunction(Function *function)
App * app()
Definition: responder.cpp:77
constexpr Event OK
Definition: events.h:65
virtual void setAreaHighlightColor(bool highlightColor)
bool handleEvent(Ion::Events::Event event) override
virtual bool moveCursorHorizontallyToPosition(double position)
Definition: palette.h:6