COSA
An Object-Oriented Platform for Arduino Programming
Menu.cpp
Go to the documentation of this file.
1 
21 #include "Menu.hh"
22 
23 void
25 {
26  uint16_t ix = *((uint16_t*) pgm_read_word(&var->value));
27  item_vec_P list = (item_vec_P) pgm_read_word(&var->list);
28  item_P item = (item_P) pgm_read_word(&list[ix]);
29  outs << (str_P) pgm_read_word(&item->name);
30 }
31 
32 void
33 Menu::print(IOStream& outs, zero_or_many_P var, bool selected, uint8_t bv)
34 {
35  if (UNLIKELY(!selected)) return;
36  uint16_t value = *((uint16_t*) pgm_read_word(&var->value));
37  item_vec_P list = (item_vec_P) pgm_read_word(&var->list);
38  item_P item = (item_P) pgm_read_word(&list[bv]);
39  if (value & _BV(bv))
40  outs << PSTR("[x] ");
41  else outs << PSTR("[ ] ");
42  outs << (str_P) pgm_read_word(&item->name);
43 }
44 
45 void
46 Menu::print(IOStream& outs, int_range_P var, bool selected)
47 {
48  int16_t* vp = (int16_t*) pgm_read_word(&var->value);
49  int16_t value = *vp;
50  outs << value;
51  if (UNLIKELY(!selected)) return;
52  outs << PSTR(" [")
53  << (int16_t) pgm_read_word(&var->low)
54  << PSTR("..")
55  << (int16_t) pgm_read_word(&var->high)
56  << PSTR("]");
57 }
58 
59 IOStream&
61 {
62  // Access the current state of the menu walker
63  Menu::item_list_P menu = walker.m_stack[walker.m_top];
64  Menu::item_vec_P list = (Menu::item_vec_P) pgm_read_word(&menu->list);
65  Menu::item_P item = &menu->item;
66  Menu::type_t type;
67 
68  // Print asterics to mark selection
69  if (walker.m_selected) outs << '*';
70 
71  // Print the name of the current menu item with parent
72  outs << (str_P) pgm_read_word(&item->name) << ':';
73  item = (Menu::item_P) pgm_read_word(&list[walker.m_ix]);
74  outs << (str_P) pgm_read_word(&item->name) << endl;
75  type = (Menu::type_t) pgm_read_byte(&item->type);
76 
77  // Print possible value of current menu item
78  switch (type) {
79  case Menu::ONE_OF:
80  // Print the one-of variable value string
81  Menu::print(outs, (Menu::one_of_P) item);
82  break;
83  case Menu::ZERO_OR_MANY:
84  // Print the zero-or-many variable when selected
85  Menu::print(outs, (Menu::zero_or_many_P) item,
86  walker.m_selected, walker.m_bv);
87  break;
88  case Menu::INT_RANGE:
89  // Print the range variable and limits when selected
90  Menu::print(outs, (Menu::int_range_P) item, walker.m_selected);
91  break;
92  default:
93  ;
94  }
95  return (outs);
96 }
97 
98 void
99 Menu::Walker::on_key_down(uint8_t nr)
100 {
101  // Access the current menu item
102  Menu::item_list_P menu = m_stack[m_top];
103  Menu::item_vec_P list = (Menu::item_vec_P) pgm_read_word(&menu->list);
104  Menu::item_P item = (Menu::item_P) pgm_read_word(&list[m_ix]);
105  Menu::type_t type = (Menu::type_t) pgm_read_byte(&item->type);
106 
107  // React to key event
108  switch (nr) {
109  case NO_KEY:
110  break;
111  case SELECT_KEY:
112  case RIGHT_KEY:
113  switch (type) {
114  case Menu::ZERO_OR_MANY:
115  // Select zero-or-many variable or toggle current item
116  {
117  if (!m_selected) {
118  m_selected = true;
119  m_bv = 0;
120  break;
121  }
123  uint16_t* vp = (uint16_t*) pgm_read_word(&var->value);
124  list = (Menu::item_vec_P) pgm_read_word(&var->list);
125  item = (Menu::item_P) pgm_read_word(&list[m_bv]);
126  uint16_t value = *vp;
127  if ((value & _BV(m_bv)) == 0)
128  *vp = (value | _BV(m_bv));
129  else
130  *vp = (value & ~_BV(m_bv));
131  }
132  break;
133  case Menu::ITEM_LIST:
134  // Walk into sub-menu
135  {
136  m_stack[++m_top] = (Menu::item_list_P) item;
137  m_ix = 0;
138  }
139  break;
140  case Menu::ACTION:
141  // Execute action and fall back to menu root
142  {
143  Menu::action_P action = (Menu::action_P) item;
144  Menu::Action* obj = (Menu::Action*) pgm_read_word(&action->obj);
145  bool res = obj->run(item);
146  m_top = 0;
147  m_ix = 0;
148  if (!res) return;
149  }
150  break;
151  default:
152  // Enter item modification mode
153  m_selected = !m_selected;
154  m_bv = 0;
155  }
156  break;
157  case LEFT_KEY:
158  // Exit item modification mode or walk back
159  if (m_selected) {
160  m_selected = false;
161  }
162  else if (m_top > 0) {
163  m_top -= 1;
164  m_ix = 0;
165  }
166  break;
167  case DOWN_KEY:
168  // Step to the next menu item or value in item modification mode
169  if (!m_selected) {
170  m_ix += 1;
171  item = (Menu::item_P) pgm_read_word(&list[m_ix]);
172  if (item == NULL) m_ix -= 1;
173  }
174  else {
175  switch (type) {
176  case Menu::ONE_OF:
177  // Step to the next enumeration value
178  {
179  Menu::one_of_P evar = (Menu::one_of_P) item;
180  uint16_t* vp = (uint16_t*) pgm_read_word(&evar->value);
181  uint16_t value = *vp + 1;
182  list = (Menu::item_vec_P) pgm_read_word(&evar->list);
183  item = (Menu::item_P) pgm_read_word(&list[value]);
184  if (item == NULL) break;
185  *vp = value;
186  }
187  break;
188  case Menu::ZERO_OR_MANY:
189  // Step to the next item
190  {
192  list = (Menu::item_vec_P) pgm_read_word(&bitset->list);
193  item = (Menu::item_P) pgm_read_word(&list[m_bv + 1]);
194  if (item == NULL) break;
195  m_bv += 1;
196  }
197  break;
198  case Menu::INT_RANGE:
199  // Decrement the integer variable if within the range
200  {
201  Menu::int_range_P range = (Menu::int_range_P) item;
202  int16_t* vp = (int16_t*) pgm_read_word(&range->value);
203  int value = *vp;
204  int low = (int) pgm_read_word(&range->low);
205  if (value == low) break;
206  *vp = value - 1;
207  }
208  break;
209  default:
210  ;
211  }
212  }
213  break;
214  case UP_KEY:
215  // Step to the previous menu item or value in item modification mode
216  if (!m_selected) {
217  if (m_ix > 0)
218  m_ix -= 1;
219  else if (m_top > 0) {
220  m_top -= 1;
221  }
222  }
223  else {
224  switch (type) {
225  case Menu::ONE_OF:
226  // Step to the previous enumeration value
227  {
228  Menu::one_of_P evar = (Menu::one_of_P) item;
229  uint16_t* vp = (uint16_t*) pgm_read_word(&evar->value);
230  uint16_t value = *vp;
231  if (value == 0) break;
232  value -= 1;
233  list = (Menu::item_vec_P) pgm_read_word(&evar->list);
234  item = (Menu::item_P) pgm_read_word(&list[value]);
235  *vp = value;
236  }
237  break;
238  case Menu::ZERO_OR_MANY:
239  // Step to the previous bitset value
240  {
241  if (m_bv == 0) {
242  m_selected = 0;
243  break;
244  }
245  m_bv -= 1;
246  }
247  break;
248  case Menu::INT_RANGE:
249  // Increment the integer variable in within range
250  {
251  Menu::int_range_P range = (Menu::int_range_P) item;
252  int16_t* vp = (int16_t*) pgm_read_word(&range->value);
253  int value = *vp;
254  int high = (int) pgm_read_word(&range->high);
255  if (value == high) break;
256  *vp = value + 1;
257  }
258  break;
259  default:
260  ;
261  }
262  }
263  break;
264  }
265 
266  // Display the new walker state
267  m_out << clear << *this;
268 }
269 
272 {
273  if (!m_selected) return (ITEM_LIST);
274  Menu::item_list_P menu = m_stack[m_top];
275  Menu::item_vec_P list = (Menu::item_vec_P) pgm_read_word(&menu->list);
276  Menu::item_P item = (Menu::item_P) pgm_read_word(&list[m_ix]);
277  Menu::type_t type = (Menu::type_t) pgm_read_byte(&item->type);
278  return (type);
279 }
280 
281 void
282 Menu::RotaryController::on_event(uint8_t type, uint16_t direction)
283 {
284  UNUSED(type);
285  if (m_walker->type() == Menu::INT_RANGE)
286  m_walker->on_key_down(direction == CW ?
289  else
290  m_walker->on_key_down(direction == CW ?
291  Menu::Walker::DOWN_KEY :
293 }
Menu integer range variable.
Definition: Menu.hh:44
type_t
Definition: Menu.hh:38
int16_t low
Range low value.
Definition: Menu.hh:89
Menu action.
Definition: Menu.hh:45
#define NULL
Definition: Types.h:101
int16_t * value
Pointer to value.
Definition: Menu.hh:91
#define PSTR(s)
Definition: Types.h:202
const item_P * item_vec_P
Definition: Menu.hh:54
item_vec_P list
Item list in program memory.
Definition: Menu.hh:66
item_vec_P list
Item list in program memory.
Definition: Menu.hh:59
virtual void on_event(uint8_t type, uint16_t direction)
Definition: Menu.cpp:282
const class prog_str * str_P
Definition: Types.h:187
const zero_or_many_t * zero_or_many_P
Definition: Menu.hh:74
Action * obj
Pointer to action handler.
Definition: Menu.hh:116
const item_t * item_P
Definition: Menu.hh:53
const item_list_t * item_list_P
Definition: Menu.hh:61
#define UNUSED(x)
Definition: ATmega328P.hh:31
type_t type
Item type tag(ITEM).
Definition: Menu.hh:50
IOStream & endl(IOStream &outs)
Definition: IOStream.hh:817
static void print(IOStream &outs, one_of_P var)
Definition: Menu.cpp:24
const action_t * action_P
Definition: Menu.hh:118
uint16_t * value
Pointer to value.
Definition: Menu.hh:67
const int_range_t * int_range_P
Definition: Menu.hh:93
const one_of_t * one_of_P
Definition: Menu.hh:69
int16_t high
Range high value.
Definition: Menu.hh:90
str_P name
Item string in program memory.
Definition: Menu.hh:51
virtual bool run(Menu::item_P item)=0
IOStream & clear(IOStream &outs)
Definition: IOStream.hh:841
#define UNLIKELY(x)
Definition: Types.h:153
Menu bitset variable (zero-or-many).
Definition: Menu.hh:42
item_t item
Item header(ITEM_LIST).
Definition: Menu.hh:58
Menu enumeration variable (one-of).
Definition: Menu.hh:41
Menu::type_t type()
Definition: Menu.cpp:271
Menu item/enum list.
Definition: Menu.hh:40