Numworks Epsilon  1.4.1
Graphing Calculator Operating System
variable_box_controller.cpp
Go to the documentation of this file.
2 #include "constant.h"
3 #include <escher/metric.h>
4 #include <assert.h>
5 
6 using namespace Poincare;
7 
8 /* ContentViewController */
9 
10 VariableBoxController::ContentViewController::ContentViewController(Responder * parentResponder, GlobalContext * context) :
11  ViewController(parentResponder),
12  m_context(context),
13  m_textFieldCaller(nullptr),
14  m_firstSelectedRow(0),
15  m_previousSelectedRow(0),
16  m_currentPage(Page::RootMenu),
17  m_selectableTableView(this)
18 {
19  m_selectableTableView.setMargins(0);
20  m_selectableTableView.setShowsIndicators(false);
21 }
22 
23 const char * VariableBoxController::ContentViewController::title() {
24  return I18n::translate(I18n::Message::Variables);
25 }
26 
27 View * VariableBoxController::ContentViewController::view() {
28  return &m_selectableTableView;
29 }
30 
31 void VariableBoxController::ContentViewController::didBecomeFirstResponder() {
32  m_selectableTableView.reloadData();
33  m_selectableTableView.scrollToCell(0,0);
34  selectCellAtLocation(0, m_firstSelectedRow);
35  app()->setFirstResponder(&m_selectableTableView);
36 }
37 
38 bool VariableBoxController::ContentViewController::handleEvent(Ion::Events::Event event) {
39 #if MATRIX_VARIABLES
40  if (event == Ion::Events::Back && m_currentPage == Page::RootMenu) {
41 #else
42  if (event == Ion::Events::Back && m_currentPage == Page::Scalar) {
43 #endif
44  m_firstSelectedRow = 0;
45  app()->dismissModalViewController();
46  return true;
47  }
48  if (event == Ion::Events::Back || event == Ion::Events::Left) {
49  m_firstSelectedRow = m_previousSelectedRow;
50 #if MATRIX_VARIABLES
51  m_selectableTableView.deselectTable();
52  m_currentPage = Page::RootMenu;
53 #endif
54  app()->setFirstResponder(this);
55  return true;
56  }
57  if (event == Ion::Events::OK || event == Ion::Events::EXE || (event == Ion::Events::Right && m_currentPage == Page::RootMenu)) {
58  if (m_currentPage == Page::RootMenu) {
59  m_previousSelectedRow = selectedRow();
60  m_firstSelectedRow = 0;
61  m_selectableTableView.deselectTable();
62  m_currentPage = pageAtIndex(m_previousSelectedRow);
63  app()->setFirstResponder(this);
64  return true;
65  }
66  m_firstSelectedRow = 0;
67  char label[3];
68  putLabelAtIndexInBuffer(selectedRow(), label);
69  const char * editedText = label;
70  m_textFieldCaller->handleEventWithText(editedText);
71 #if MATRIX_VARIABLES
72  m_selectableTableView.deselectTable();
73  m_currentPage = Page::RootMenu;
74 #endif
75  app()->dismissModalViewController();
76  return true;
77  }
78  if (event == Ion::Events::Backspace && m_currentPage != Page::RootMenu) {
79  if (m_currentPage == Page::Scalar) {
80  const Symbol symbol('A'+selectedRow());
81  m_context->setExpressionForSymbolName(nullptr, &symbol, *m_context);
82  }
83  if (m_currentPage == Page::Matrix) {
84  const Symbol symbol = Symbol::matrixSymbol('0'+(char)selectedRow());
85  m_context->setExpressionForSymbolName(nullptr, &symbol, *m_context);
86  }
87  m_selectableTableView.reloadData();
88  return true;
89  }
90  return false;
91 }
92 
94  switch (m_currentPage) {
95  case Page::RootMenu:
96  return k_numberOfMenuRows;
97  case Page::Scalar:
98  return GlobalContext::k_maxNumberOfScalarExpressions;
99 #if LIST_VARIABLES
100  case Page::List:
101  return GlobalContext::k_maxNumberOfListExpressions;
102 #endif
103  case Page::Matrix:
104  return GlobalContext::k_maxNumberOfMatrixExpressions;
105  default:
106  return 0;
107  }
108 }
109 
110 HighlightCell * VariableBoxController::ContentViewController::reusableCell(int index, int type) {
111  assert(type < 2);
112  assert(index >= 0);
113  if (type == 0) {
114  assert(index < k_maxNumberOfDisplayedRows);
115  return &m_leafCells[index];
116  }
117  assert(index < k_numberOfMenuRows);
118  return &m_nodeCells[index];
119 }
120 
121 int VariableBoxController::ContentViewController::reusableCellCount(int type) {
122  assert(type < 2);
123  if (type == 0) {
124  return k_maxNumberOfDisplayedRows;
125  }
126  return k_numberOfMenuRows;
127 }
128 
129 void VariableBoxController::ContentViewController::willDisplayCellForIndex(HighlightCell * cell, int index) {
130  if (m_currentPage == Page::RootMenu) {
131  I18n::Message label = nodeLabelAtIndex(index);
132  MessageTableCell * myCell = (MessageTableCell *)cell;
133  myCell->setMessage(label);
134  return;
135  }
136  VariableBoxLeafCell * myCell = (VariableBoxLeafCell *)cell;
137  char label[3];
138  putLabelAtIndexInBuffer(index, label);
139  myCell->setLabel(label);
140  const Expression * evaluation = expressionForIndex(index);
141  if (m_currentPage == Page::Scalar) {
142  myCell->displayExpression(false);
143  char buffer[PrintFloat::bufferSizeForFloatsWithPrecision(Constant::LargeNumberOfSignificantDigits)];
144  evaluation->writeTextInBuffer(buffer, PrintFloat::bufferSizeForFloatsWithPrecision(Constant::LargeNumberOfSignificantDigits));
145  myCell->setSubtitle(buffer);
146  return;
147  }
148  myCell->displayExpression(true);
149  if (evaluation) {
150  /* TODO: implement list contexts */
151  // TODO: handle matrix and scalar!
152  ExpressionLayout * layout = expressionLayoutForIndex(index);
153  const Matrix * matrixEvaluation = static_cast<const Matrix *>(evaluation);
154  myCell->setExpressionLayout(layout);
155  char buffer[2*PrintFloat::bufferSizeForFloatsWithPrecision(2)+1];
156  int numberOfChars = PrintFloat::convertFloatToText<float>(matrixEvaluation->numberOfRows(), buffer, PrintFloat::bufferSizeForFloatsWithPrecision(2), 2, PrintFloat::Mode::Decimal);
157  buffer[numberOfChars++] = 'x';
158  PrintFloat::convertFloatToText<float>(matrixEvaluation->numberOfColumns(), buffer+numberOfChars, PrintFloat::bufferSizeForFloatsWithPrecision(2), 2, PrintFloat::Mode::Decimal);
159  myCell->setSubtitle(buffer);
160  } else {
161  myCell->setExpressionLayout(nullptr);
162  myCell->setSubtitle(I18n::translate(I18n::Message::Empty));
163  }
164 }
165 
166 KDCoordinate VariableBoxController::ContentViewController::rowHeight(int index) {
167  if (m_currentPage == Page::RootMenu || m_currentPage == Page::Scalar) {
169  }
170  ExpressionLayout * expressionLayout = expressionLayoutForIndex(index);
171  if (expressionLayout) {
172  return expressionLayout->size().height()+k_leafMargin;
173  }
175 }
176 
177 KDCoordinate VariableBoxController::ContentViewController::cumulatedHeightFromIndex(int j) {
178  int result = 0;
179  for (int k = 0; k < j; k++) {
180  result += rowHeight(k);
181  }
182  return result;
183 }
184 
185 int VariableBoxController::ContentViewController::indexFromCumulatedHeight(KDCoordinate offsetY) {
186  int result = 0;
187  int j = 0;
188  while (result < offsetY && j < numberOfRows()) {
189  result += rowHeight(j++);
190  }
191  return (result < offsetY || offsetY == 0) ? j : j - 1;
192 }
193 
194 int VariableBoxController::ContentViewController::typeAtLocation(int i, int j) {
195  if (m_currentPage == Page::RootMenu) {
196  return 1;
197  }
198  return 0;
199 }
200 
201 const Expression * VariableBoxController::ContentViewController::expressionForIndex(int index) {
202  if (m_currentPage == Page::Scalar) {
203  const Symbol symbol = Symbol('A'+index);
204  return m_context->expressionForSymbol(&symbol);
205  }
206  if (m_currentPage == Page::Matrix) {
207  const Symbol symbol = Symbol::matrixSymbol('0'+(char)index);
208  return m_context->expressionForSymbol(&symbol);
209  }
210 #if LIST_VARIABLES
211  if (m_currentPage == Page::List) {
212  return nullptr;
213  }
214 #endif
215  return nullptr;
216 }
217 
218 ExpressionLayout * VariableBoxController::ContentViewController::expressionLayoutForIndex(int index) {
219  if (m_currentPage == Page::Matrix) {
220  const Symbol symbol = Symbol::matrixSymbol('0'+(char)index);
221  return m_context->expressionLayoutForSymbol(&symbol);
222  }
223 #if LIST_VARIABLES
224  if (m_currentPage == Page::List) {
225  return nullptr;
226  }
227 #endif
228  return nullptr;
229 }
230 
231 VariableBoxController::ContentViewController::Page VariableBoxController::ContentViewController::pageAtIndex(int index) {
232 #if LIST_VARIABLES
233  Page pages[3] = {Page::Scalar, Page::List, Page::Matrix};
234 #else
235  Page pages[2] = {Page::Scalar, Page::Matrix};
236 #endif
237  return pages[index];
238 }
239 
240 void VariableBoxController::ContentViewController::putLabelAtIndexInBuffer(int index, char * buffer) {
241  if (m_currentPage == Page::Scalar) {
242  buffer[0] = 'A' + index;
243  buffer[1] = 0;
244  }
245 #if LIST_VARIABLES
246  if (m_currentPage == Page::List) {
247  buffer[0] = 'L';
248  buffer[1] = '0' + index;
249  buffer[2] = 0;
250  }
251 #endif
252  if (m_currentPage == Page::Matrix) {
253  buffer[0] = 'M';
254  buffer[1] = '0' + index;
255  buffer[2] = 0;
256  }
257 }
258 
259 I18n::Message VariableBoxController::ContentViewController::nodeLabelAtIndex(int index) {
260  assert(m_currentPage == Page::RootMenu);
261 #if LIST_VARIABLES
262  I18n::Message labels[3] = {I18n::Message::Number, I18n::Message::List, I18n::Message::Matrix};
263 #else
264  I18n::Message labels[2] = {I18n::Message::Number, I18n::Message::Matrix};
265 #endif
266  return labels[index];
267 }
268 
269 void VariableBoxController::ContentViewController::setTextFieldCaller(TextField * textField) {
270  m_textFieldCaller = textField;
271 }
272 
273 void VariableBoxController::ContentViewController::reloadData() {
274  m_selectableTableView.reloadData();
275 }
276 
277 void VariableBoxController::ContentViewController::resetPage() {
278 #if MATRIX_VARIABLES
279  m_currentPage = Page::RootMenu;
280 #else
281  m_currentPage = Page::Scalar;
282 #endif
283 }
284 
285 void VariableBoxController::ContentViewController::viewDidDisappear() {
286  m_selectableTableView.deselectTable();
288 }
289 
291  StackViewController(nullptr, &m_contentViewController, KDColorWhite, Palette::PurpleBright, Palette::PurpleDark),
292  m_contentViewController(this, context)
293 {
294 }
295 
297  app()->setFirstResponder(&m_contentViewController);
298 }
299 
301  m_contentViewController.setTextFieldCaller(textField);
302 }
303 
306  m_contentViewController.resetPage();
307  m_contentViewController.reloadData();
308 }
309 
312 }
int numberOfColumns() const
Definition: matrix.cpp:40
void setTextFieldCaller(TextField *textField)
#define assert(e)
Definition: assert.h:9
constexpr Event EXE
Definition: events.h:114
int16_t KDCoordinate
Definition: coordinate.h:6
void setLabel(const char *text)
constexpr Event Back
Definition: events.h:66
enum Message uint16_t enum Language uint16_t const char * translate(Message m, Language l=(Language) 0)
Definition: i18n.cpp:5
void viewDidDisappear() override
constexpr KDColor KDColorWhite
Definition: color.h:42
void setExpressionLayout(Poincare::ExpressionLayout *expressionLayout)
void displayExpression(bool displayExpression)
static constexpr int LargeNumberOfSignificantDigits
Definition: constant.h:6
int numberOfRows() const
Definition: matrix.cpp:36
constexpr Event Left
Definition: events.h:61
void setMessage(I18n::Message message)
void setFirstResponder(Responder *responder)
Definition: app.cpp:62
Definition: view.h:23
static constexpr KDCoordinate ToolboxRowHeight
Definition: metric.h:27
constexpr Event Right
Definition: events.h:64
VariableBoxController(MenuController *menuController, ScriptStore *scriptStore)
virtual void viewDidDisappear()
void setSubtitle(const char *text)
constexpr uint8_t numberOfRows
Definition: keyboard.h:35
App * app()
Definition: responder.cpp:77
constexpr Event OK
Definition: events.h:65
virtual int writeTextInBuffer(char *buffer, int bufferSize, int numberOfSignificantDigits=PrintFloat::k_numberOfStoredSignificantDigits) const =0
constexpr Event Backspace
Definition: events.h:76
constexpr KDCoordinate height() const
Definition: size.h:11
Definition: palette.h:6