Fix broken name edition (@bsongis please double check)
[opentx.git] / radio / src / gui / 128x64 / navigation.cpp
bloba3a861161031cd7a357fbd8ea07195edd3a6c918
1 /*
2 * Copyright (C) OpenTX
4 * Based on code named
5 * th9x - http://code.google.com/p/th9x
6 * er9x - http://code.google.com/p/er9x
7 * gruvin9x - http://code.google.com/p/gruvin9x
9 * License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License version 2 as
13 * published by the Free Software Foundation.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
21 #include "opentx.h"
23 vertpos_t menuVerticalOffset;
24 int8_t s_editMode;
25 uint8_t noHighlightCounter;
26 uint8_t menuCalibrationState;
27 vertpos_t menuVerticalPosition;
28 horzpos_t menuHorizontalPosition;
30 #if defined(NAVIGATION_POT1)
31 int16_t p1valdiff;
32 #endif
34 #if defined(NAVIGATION_POT2)
35 int8_t p2valdiff;
36 #endif
38 int8_t checkIncDec_Ret;
40 #if defined(PCBXLITE)
41 // invert the value
42 #define DBLKEYS_PRESSED_RGT_LFT(in) ((in & ((1<<KEY_SHIFT) + (1<<KEY_UP))) == ((1<<KEY_SHIFT) + (1<<KEY_UP)))
43 // set to 0
44 #define DBLKEYS_PRESSED_UP_DWN(in) ((in & ((1<<KEY_SHIFT) + (1<<KEY_DOWN))) == ((1<<KEY_SHIFT) + (1<<KEY_DOWN)))
45 // set to max
46 #define DBLKEYS_PRESSED_RGT_UP(in) ((in & ((1<<KEY_SHIFT) + (1<<KEY_RIGHT))) == ((1<<KEY_SHIFT) + (1<<KEY_RIGHT)))
47 // set to min
48 #define DBLKEYS_PRESSED_LFT_DWN(in) ((in & ((1<<KEY_SHIFT) + (1<<KEY_LEFT))) == ((1<<KEY_SHIFT) + (1<<KEY_LEFT)))
49 #elif defined(PCBX7)
50 #define DBLKEYS_PRESSED_RGT_LFT(in) (false)
51 #define DBLKEYS_PRESSED_UP_DWN(in) (false)
52 #define DBLKEYS_PRESSED_RGT_UP(in) (false)
53 #define DBLKEYS_PRESSED_LFT_DWN(in) (false)
54 #else
55 #define DBLKEYS_PRESSED_RGT_LFT(in) ((in & (KEYS_GPIO_PIN_RIGHT + KEYS_GPIO_PIN_LEFT)) == (KEYS_GPIO_PIN_RIGHT + KEYS_GPIO_PIN_LEFT))
56 #define DBLKEYS_PRESSED_UP_DWN(in) ((in & (KEYS_GPIO_PIN_UP + KEYS_GPIO_PIN_DOWN)) == (KEYS_GPIO_PIN_UP + KEYS_GPIO_PIN_DOWN))
57 #define DBLKEYS_PRESSED_RGT_UP(in) ((in & (KEYS_GPIO_PIN_RIGHT + KEYS_GPIO_PIN_UP)) == (KEYS_GPIO_PIN_RIGHT + KEYS_GPIO_PIN_UP))
58 #define DBLKEYS_PRESSED_LFT_DWN(in) ((in & (KEYS_GPIO_PIN_LEFT + KEYS_GPIO_PIN_DOWN)) == (KEYS_GPIO_PIN_LEFT + KEYS_GPIO_PIN_DOWN))
59 #endif
61 #if defined(CPUARM)
62 INIT_STOPS(stops100, 3, -100, 0, 100)
63 INIT_STOPS(stops1000, 3, -1000, 0, 1000)
64 INIT_STOPS(stopsSwitch, 15, SWSRC_FIRST, CATEGORY_END(-SWSRC_FIRST_LOGICAL_SWITCH), CATEGORY_END(-SWSRC_FIRST_TRIM), CATEGORY_END(-SWSRC_LAST_SWITCH+1), 0, CATEGORY_END(SWSRC_LAST_SWITCH), CATEGORY_END(SWSRC_FIRST_TRIM-1), CATEGORY_END(SWSRC_FIRST_LOGICAL_SWITCH-1), SWSRC_LAST)
66 #if defined(PCBTARANIS)
67 int checkIncDecSelection = 0;
69 void onSourceLongEnterPress(const char * result)
71 if (result == STR_MENU_INPUTS)
72 checkIncDecSelection = getFirstAvailable(MIXSRC_FIRST_INPUT, MIXSRC_LAST_INPUT, isInputAvailable)+1;
73 #if defined(LUA_MODEL_SCRIPTS)
74 else if (result == STR_MENU_LUA)
75 checkIncDecSelection = getFirstAvailable(MIXSRC_FIRST_LUA, MIXSRC_LAST_LUA, isSourceAvailable);
76 #endif
77 else if (result == STR_MENU_STICKS)
78 checkIncDecSelection = MIXSRC_FIRST_STICK;
79 else if (result == STR_MENU_POTS)
80 checkIncDecSelection = MIXSRC_FIRST_POT;
81 else if (result == STR_MENU_MAX)
82 checkIncDecSelection = MIXSRC_MAX;
83 else if (result == STR_MENU_HELI)
84 checkIncDecSelection = MIXSRC_FIRST_HELI;
85 else if (result == STR_MENU_TRIMS)
86 checkIncDecSelection = MIXSRC_FIRST_TRIM;
87 else if (result == STR_MENU_SWITCHES)
88 checkIncDecSelection = MIXSRC_FIRST_SWITCH;
89 else if (result == STR_MENU_TRAINER)
90 checkIncDecSelection = MIXSRC_FIRST_TRAINER;
91 else if (result == STR_MENU_CHANNELS)
92 checkIncDecSelection = getFirstAvailable(MIXSRC_FIRST_CH, MIXSRC_LAST_CH, isSourceAvailable);
93 else if (result == STR_MENU_GVARS)
94 checkIncDecSelection = MIXSRC_FIRST_GVAR;
95 else if (result == STR_MENU_TELEMETRY) {
96 for (int i = 0; i < MAX_TELEMETRY_SENSORS; i++) {
97 TelemetrySensor * sensor = & g_model.telemetrySensors[i];
98 if (sensor->isAvailable()) {
99 checkIncDecSelection = MIXSRC_FIRST_TELEM + 3*i;
100 break;
106 void onSwitchLongEnterPress(const char * result)
108 if (result == STR_MENU_SWITCHES)
109 checkIncDecSelection = SWSRC_FIRST_SWITCH;
110 else if (result == STR_MENU_TRIMS)
111 checkIncDecSelection = SWSRC_FIRST_TRIM;
112 else if (result == STR_MENU_LOGICAL_SWITCHES)
113 checkIncDecSelection = SWSRC_FIRST_LOGICAL_SWITCH + getFirstAvailable(0, MAX_LOGICAL_SWITCHES, isLogicalSwitchAvailable);
114 else if (result == STR_MENU_OTHER)
115 checkIncDecSelection = SWSRC_ON;
116 else if (result == STR_MENU_INVERT)
117 checkIncDecSelection = SWSRC_INVERT;
119 #endif
121 #if defined(PCBX7)
122 int checkIncDec(event_t event, int val, int i_min, int i_max, unsigned int i_flags, IsValueAvailable isValueAvailable, const CheckIncDecStops &stops)
124 int newval = val;
126 #if 0 // TODO ? defined(DBLKEYS)
127 uint32_t in = KEYS_PRESSED();
128 if (!(i_flags & NO_DBLKEYS) && (EVT_KEY_MASK(event))) {
129 bool dblkey = true;
130 if (DBLKEYS_PRESSED_RGT_LFT(in)) {
131 if (!isValueAvailable || isValueAvailable(-val)) {
132 newval = -val;
135 else if (DBLKEYS_PRESSED_RGT_UP(in)) {
136 newval = (i_max > stops.max() ? stops.max() : i_max);
137 while (isValueAvailable && !isValueAvailable(newval) && newval>i_min) {
138 --newval;
141 else if (DBLKEYS_PRESSED_LFT_DWN(in)) {
142 newval = (i_min < stops.min() ? stops.min() : i_min);
143 while (isValueAvailable && !isValueAvailable(newval) && newval<i_max) {
144 ++newval;
147 else if (DBLKEYS_PRESSED_UP_DWN(in)) {
148 newval = 0;
150 else {
151 dblkey = false;
154 if (dblkey) {
155 killEvents(KEY_UP);
156 killEvents(KEY_DOWN);
157 killEvents(KEY_RIGHT);
158 killEvents(KEY_LEFT);
159 killEvents(KEY_PAGE);
160 killEvents(KEY_MENU);
161 killEvents(KEY_ENTER);
162 killEvents(KEY_EXIT);
163 event = 0;
166 #endif
168 if (s_editMode>0 && event==EVT_ROTARY_RIGHT) {
169 newval += min<int>(rotencSpeed, i_max-val);
170 while (isValueAvailable && !isValueAvailable(newval) && newval<=i_max) {
171 newval++;
173 if (newval > i_max) {
174 newval = val;
175 AUDIO_KEY_ERROR();
178 else if (s_editMode>0 && event==EVT_ROTARY_LEFT) {
179 newval -= min<int>(rotencSpeed, val-i_min);
180 while (isValueAvailable && !isValueAvailable(newval) && newval>=i_min) {
181 newval--;
183 if (newval < i_min) {
184 newval = val;
185 AUDIO_KEY_ERROR();
189 if (!READ_ONLY() && i_min==0 && i_max==1 && event==EVT_KEY_BREAK(KEY_ENTER)) {
190 s_editMode = 0;
191 newval = !val;
194 #if defined(AUTOSWITCH)
195 if (i_flags & INCDEC_SWITCH) {
196 newval = checkIncDecMovedSwitch(newval);
198 #endif
200 #if defined(AUTOSOURCE)
201 if (i_flags & INCDEC_SOURCE) {
202 if (s_editMode>0) {
203 int source = GET_MOVED_SOURCE(i_min, i_max);
204 if (source) {
205 newval = source;
207 #if defined(AUTOSWITCH)
208 else {
209 unsigned int swtch = abs(getMovedSwitch());
210 if (swtch) {
211 newval = switchToMix(swtch);
214 #endif
217 #endif
219 if (newval != val) {
220 storageDirty(i_flags & (EE_GENERAL|EE_MODEL));
221 checkIncDec_Ret = (newval > val ? 1 : -1);
223 else {
224 checkIncDec_Ret = 0;
227 if (i_flags & INCDEC_SOURCE) {
228 if (event == EVT_KEY_LONG(KEY_ENTER)) {
229 killEvents(event);
230 checkIncDecSelection = MIXSRC_NONE;
232 if (i_min <= MIXSRC_FIRST_INPUT && i_max >= MIXSRC_FIRST_INPUT) {
233 if (getFirstAvailable(MIXSRC_FIRST_INPUT, MIXSRC_LAST_INPUT, isInputAvailable) != MIXSRC_NONE) {
234 POPUP_MENU_ADD_ITEM(STR_MENU_INPUTS);
237 #if defined(LUA_MODEL_SCRIPTS)
238 if (i_min <= MIXSRC_FIRST_LUA && i_max >= MIXSRC_FIRST_LUA) {
239 if (getFirstAvailable(MIXSRC_FIRST_LUA, MIXSRC_LAST_LUA, isSourceAvailable) != MIXSRC_NONE) {
240 POPUP_MENU_ADD_ITEM(STR_MENU_LUA);
243 #endif
244 if (i_min <= MIXSRC_FIRST_STICK && i_max >= MIXSRC_FIRST_STICK) POPUP_MENU_ADD_ITEM(STR_MENU_STICKS);
245 if (i_min <= MIXSRC_FIRST_POT && i_max >= MIXSRC_FIRST_POT) POPUP_MENU_ADD_ITEM(STR_MENU_POTS);
246 if (i_min <= MIXSRC_MAX && i_max >= MIXSRC_MAX) POPUP_MENU_ADD_ITEM(STR_MENU_MAX);
247 #if defined(HELI)
248 if (i_min <= MIXSRC_FIRST_HELI && i_max >= MIXSRC_FIRST_HELI) POPUP_MENU_ADD_ITEM(STR_MENU_HELI);
249 #endif
250 if (i_min <= MIXSRC_FIRST_TRIM && i_max >= MIXSRC_FIRST_TRIM) POPUP_MENU_ADD_ITEM(STR_MENU_TRIMS);
251 if (i_min <= MIXSRC_FIRST_SWITCH && i_max >= MIXSRC_FIRST_SWITCH) POPUP_MENU_ADD_ITEM(STR_MENU_SWITCHES);
252 if (i_min <= MIXSRC_FIRST_TRAINER && i_max >= MIXSRC_FIRST_TRAINER) POPUP_MENU_ADD_ITEM(STR_MENU_TRAINER);
253 if (i_min <= MIXSRC_FIRST_CH && i_max >= MIXSRC_FIRST_CH) POPUP_MENU_ADD_ITEM(STR_MENU_CHANNELS);
254 if (i_min <= MIXSRC_FIRST_GVAR && i_max >= MIXSRC_FIRST_GVAR && isValueAvailable(MIXSRC_FIRST_GVAR)) {
255 POPUP_MENU_ADD_ITEM(STR_MENU_GVARS);
258 if (i_min <= MIXSRC_FIRST_TELEM && i_max >= MIXSRC_FIRST_TELEM) {
259 for (int i = 0; i < MAX_TELEMETRY_SENSORS; i++) {
260 TelemetrySensor * sensor = & g_model.telemetrySensors[i];
261 if (sensor->isAvailable()) {
262 POPUP_MENU_ADD_ITEM(STR_MENU_TELEMETRY);
263 break;
267 POPUP_MENU_START(onSourceLongEnterPress);
269 if (checkIncDecSelection != 0) {
270 newval = checkIncDecSelection;
271 if (checkIncDecSelection != MIXSRC_MAX)
272 s_editMode = EDIT_MODIFY_FIELD;
273 checkIncDecSelection = 0;
276 else if (i_flags & INCDEC_SWITCH) {
277 if (event == EVT_KEY_LONG(KEY_ENTER)) {
278 killEvents(event);
279 checkIncDecSelection = SWSRC_NONE;
280 if (i_min <= SWSRC_FIRST_SWITCH && i_max >= SWSRC_LAST_SWITCH) POPUP_MENU_ADD_ITEM(STR_MENU_SWITCHES);
281 if (i_min <= SWSRC_FIRST_TRIM && i_max >= SWSRC_LAST_TRIM) POPUP_MENU_ADD_ITEM(STR_MENU_TRIMS);
282 if (i_min <= SWSRC_FIRST_LOGICAL_SWITCH && i_max >= SWSRC_LAST_LOGICAL_SWITCH) {
283 for (int i = 0; i < MAX_LOGICAL_SWITCHES; i++) {
284 if (isValueAvailable && isValueAvailable(SWSRC_FIRST_LOGICAL_SWITCH+i)) {
285 POPUP_MENU_ADD_ITEM(STR_MENU_LOGICAL_SWITCHES);
286 break;
290 if (isValueAvailable && isValueAvailable(SWSRC_ON)) POPUP_MENU_ADD_ITEM(STR_MENU_OTHER);
291 if (isValueAvailable && isValueAvailable(-newval)) POPUP_MENU_ADD_ITEM(STR_MENU_INVERT);
292 POPUP_MENU_START(onSwitchLongEnterPress);
293 s_editMode = EDIT_MODIFY_FIELD;
295 if (checkIncDecSelection != 0) {
296 newval = (checkIncDecSelection == SWSRC_INVERT ? -newval : checkIncDecSelection);
297 s_editMode = EDIT_MODIFY_FIELD;
298 checkIncDecSelection = 0;
301 return newval;
303 #else
304 int checkIncDec(event_t event, int val, int i_min, int i_max, unsigned int i_flags, IsValueAvailable isValueAvailable, const CheckIncDecStops &stops)
306 int newval = val;
308 #if defined(DBLKEYS)
309 uint8_t in = KEYS_PRESSED();
310 if (!(i_flags & NO_DBLKEYS) && (EVT_KEY_MASK(event))) {
311 bool dblkey = true;
312 if (DBLKEYS_PRESSED_RGT_LFT(in)) {
313 if (!isValueAvailable || isValueAvailable(-val)) {
314 newval = -val;
317 else if (DBLKEYS_PRESSED_RGT_UP(in)) {
318 newval = (i_max > stops.max() ? stops.max() : i_max);
319 while (isValueAvailable && !isValueAvailable(newval) && newval>i_min) {
320 --newval;
323 else if (DBLKEYS_PRESSED_LFT_DWN(in)) {
324 newval = (i_min < stops.min() ? stops.min() : i_min);
325 while (isValueAvailable && !isValueAvailable(newval) && newval<i_max) {
326 ++newval;
329 else if (DBLKEYS_PRESSED_UP_DWN(in)) {
330 newval = 0;
332 else {
333 dblkey = false;
336 if (dblkey) {
337 killEvents(KEY_UP);
338 killEvents(KEY_DOWN);
339 killEvents(KEY_RIGHT);
340 killEvents(KEY_LEFT);
341 event = 0;
344 #endif
346 #if defined(PCBXLITE)
347 if (s_editMode > 0) {
348 if (event==EVT_KEY_FIRST(KEY_RIGHT) || event==EVT_KEY_REPT(KEY_RIGHT) || (s_editMode>0 && (event==EVT_KEY_FIRST(KEY_UP) || event==EVT_KEY_REPT(KEY_UP)))) {
349 #else
350 if (event==EVT_KEY_FIRST(KEY_RIGHT) || event==EVT_KEY_REPT(KEY_RIGHT) || (s_editMode>0 && (IS_ROTARY_RIGHT(event) || event==EVT_KEY_FIRST(KEY_UP) || event==EVT_KEY_REPT(KEY_UP)))) {
351 #endif
352 do {
353 newval++;
354 } while (isValueAvailable && !isValueAvailable(newval) && newval<=i_max);
356 if (newval > i_max) {
357 newval = val;
358 killEvents(event);
359 AUDIO_KEY_ERROR();
362 #if defined(PCBXLITE)
363 else if (event==EVT_KEY_FIRST(KEY_LEFT) || event==EVT_KEY_REPT(KEY_LEFT) || (s_editMode>0 && (event==EVT_KEY_FIRST(KEY_DOWN) || event==EVT_KEY_REPT(KEY_DOWN)))) {
364 #else
365 else if (event==EVT_KEY_FIRST(KEY_LEFT) || event==EVT_KEY_REPT(KEY_LEFT) || (s_editMode>0 && (IS_ROTARY_LEFT(event) || event==EVT_KEY_FIRST(KEY_DOWN) || event==EVT_KEY_REPT(KEY_DOWN)))) {
366 #endif
367 do {
368 if (IS_KEY_REPT(event) && (i_flags & INCDEC_REP10)) {
369 newval -= min(10, val-i_min);
371 else {
372 newval--;
374 } while (isValueAvailable && !isValueAvailable(newval) && newval>=i_min);
376 if (newval < i_min) {
377 newval = val;
378 killEvents(event);
379 AUDIO_KEY_ERROR();
382 #if defined(PCBXLITE)
384 #endif
386 if (!READ_ONLY() && i_min==0 && i_max==1 && (event==EVT_KEY_BREAK(KEY_ENTER) || IS_ROTARY_BREAK(event))) {
387 s_editMode = 0;
388 newval = !val;
391 #if defined(NAVIGATION_POT1)
392 // change values based on P1
393 newval -= p1valdiff;
394 p1valdiff = 0;
395 #endif
397 #if defined(AUTOSWITCH)
398 if (i_flags & INCDEC_SWITCH) {
399 newval = checkIncDecMovedSwitch(newval);
401 #endif
403 #if defined(AUTOSOURCE)
404 if (i_flags & INCDEC_SOURCE) {
405 if (s_editMode>0) {
406 int8_t source = GET_MOVED_SOURCE(i_min, i_max);
407 if (source) {
408 newval = source;
410 #if defined(AUTOSWITCH)
411 else {
412 uint8_t swtch = abs(getMovedSwitch());
413 if (swtch) {
414 newval = switchToMix(swtch);
417 #endif
420 #endif
422 if (newval != val) {
423 if (!(i_flags & NO_INCDEC_MARKS) && (newval != i_max) && (newval != i_min) && (newval==0 || newval==-100 || newval==+100) && !IS_ROTARY_EVENT(event)) {
424 pauseEvents(event); // delay before auto-repeat continues
426 AUDIO_KEY_PRESS();
427 storageDirty(i_flags & (EE_GENERAL|EE_MODEL));
428 checkIncDec_Ret = (newval > val ? 1 : -1);
430 else {
431 checkIncDec_Ret = 0;
434 #if defined(PCBXLITE)
435 if (i_flags & INCDEC_SOURCE) {
436 if (event == EVT_KEY_LONG(KEY_ENTER)) {
437 killEvents(event);
438 checkIncDecSelection = MIXSRC_NONE;
440 if (i_min <= MIXSRC_FIRST_INPUT && i_max >= MIXSRC_FIRST_INPUT) {
441 if (getFirstAvailable(MIXSRC_FIRST_INPUT, MIXSRC_LAST_INPUT, isInputAvailable) != MIXSRC_NONE) {
442 POPUP_MENU_ADD_ITEM(STR_MENU_INPUTS);
445 #if defined(LUA_MODEL_SCRIPTS)
446 if (i_min <= MIXSRC_FIRST_LUA && i_max >= MIXSRC_FIRST_LUA) {
447 if (getFirstAvailable(MIXSRC_FIRST_LUA, MIXSRC_LAST_LUA, isSourceAvailable) != MIXSRC_NONE) {
448 POPUP_MENU_ADD_ITEM(STR_MENU_LUA);
451 #endif
452 if (i_min <= MIXSRC_FIRST_STICK && i_max >= MIXSRC_FIRST_STICK) POPUP_MENU_ADD_ITEM(STR_MENU_STICKS);
453 if (i_min <= MIXSRC_FIRST_POT && i_max >= MIXSRC_FIRST_POT) POPUP_MENU_ADD_ITEM(STR_MENU_POTS);
454 if (i_min <= MIXSRC_MAX && i_max >= MIXSRC_MAX) POPUP_MENU_ADD_ITEM(STR_MENU_MAX);
455 #if defined(HELI)
456 if (i_min <= MIXSRC_FIRST_HELI && i_max >= MIXSRC_FIRST_HELI) POPUP_MENU_ADD_ITEM(STR_MENU_HELI);
457 #endif
458 if (i_min <= MIXSRC_FIRST_TRIM && i_max >= MIXSRC_FIRST_TRIM) POPUP_MENU_ADD_ITEM(STR_MENU_TRIMS);
459 if (i_min <= MIXSRC_FIRST_SWITCH && i_max >= MIXSRC_FIRST_SWITCH) POPUP_MENU_ADD_ITEM(STR_MENU_SWITCHES);
460 if (i_min <= MIXSRC_FIRST_TRAINER && i_max >= MIXSRC_FIRST_TRAINER) POPUP_MENU_ADD_ITEM(STR_MENU_TRAINER);
461 if (i_min <= MIXSRC_FIRST_CH && i_max >= MIXSRC_FIRST_CH) POPUP_MENU_ADD_ITEM(STR_MENU_CHANNELS);
462 if (i_min <= MIXSRC_FIRST_GVAR && i_max >= MIXSRC_FIRST_GVAR && isValueAvailable(MIXSRC_FIRST_GVAR)) {
463 POPUP_MENU_ADD_ITEM(STR_MENU_GVARS);
466 if (i_min <= MIXSRC_FIRST_TELEM && i_max >= MIXSRC_FIRST_TELEM) {
467 for (int i = 0; i < MAX_TELEMETRY_SENSORS; i++) {
468 TelemetrySensor * sensor = & g_model.telemetrySensors[i];
469 if (sensor->isAvailable()) {
470 POPUP_MENU_ADD_ITEM(STR_MENU_TELEMETRY);
471 break;
475 POPUP_MENU_START(onSourceLongEnterPress);
477 if (checkIncDecSelection != 0) {
478 newval = checkIncDecSelection;
479 if (checkIncDecSelection != MIXSRC_MAX)
480 s_editMode = EDIT_MODIFY_FIELD;
481 checkIncDecSelection = 0;
484 else if (i_flags & INCDEC_SWITCH) {
485 if (event == EVT_KEY_LONG(KEY_ENTER)) {
486 killEvents(event);
487 checkIncDecSelection = SWSRC_NONE;
488 if (i_min <= SWSRC_FIRST_SWITCH && i_max >= SWSRC_LAST_SWITCH) POPUP_MENU_ADD_ITEM(STR_MENU_SWITCHES);
489 if (i_min <= SWSRC_FIRST_TRIM && i_max >= SWSRC_LAST_TRIM) POPUP_MENU_ADD_ITEM(STR_MENU_TRIMS);
490 if (i_min <= SWSRC_FIRST_LOGICAL_SWITCH && i_max >= SWSRC_LAST_LOGICAL_SWITCH) {
491 for (int i = 0; i < MAX_LOGICAL_SWITCHES; i++) {
492 if (isValueAvailable && isValueAvailable(SWSRC_FIRST_LOGICAL_SWITCH+i)) {
493 POPUP_MENU_ADD_ITEM(STR_MENU_LOGICAL_SWITCHES);
494 break;
498 if (isValueAvailable && isValueAvailable(SWSRC_ON)) POPUP_MENU_ADD_ITEM(STR_MENU_OTHER);
499 if (isValueAvailable && isValueAvailable(-newval)) POPUP_MENU_ADD_ITEM(STR_MENU_INVERT);
500 POPUP_MENU_START(onSwitchLongEnterPress);
501 s_editMode = EDIT_MODIFY_FIELD;
503 if (checkIncDecSelection != 0) {
504 newval = (checkIncDecSelection == SWSRC_INVERT ? -newval : checkIncDecSelection);
505 s_editMode = EDIT_MODIFY_FIELD;
506 checkIncDecSelection = 0;
509 #endif
510 return newval;
512 #endif
513 #else
514 int16_t checkIncDec(event_t event, int16_t val, int16_t i_min, int16_t i_max, uint8_t i_flags)
516 int16_t newval = val;
518 #if defined(DBLKEYS)
519 uint8_t in = KEYS_PRESSED();
520 if (!(i_flags & NO_DBLKEYS) && (EVT_KEY_MASK(event))) {
521 bool dblkey = true;
522 if (DBLKEYS_PRESSED_RGT_LFT(in))
523 newval = -val;
524 else if (DBLKEYS_PRESSED_RGT_UP(in)) {
525 newval = (i_max > 100 ? 100 : i_max);
527 else if (DBLKEYS_PRESSED_LFT_DWN(in)) {
528 newval = (i_min < -100 ? -100 : i_min);
530 else if (DBLKEYS_PRESSED_UP_DWN(in)) {
531 newval = 0;
533 else {
534 dblkey = false;
537 if (dblkey) {
538 killEvents(KEY_UP);
539 killEvents(KEY_DOWN);
540 killEvents(KEY_RIGHT);
541 killEvents(KEY_LEFT);
542 event = 0;
545 #endif
547 if (event==EVT_KEY_FIRST(KEY_RIGHT) || event==EVT_KEY_REPT(KEY_RIGHT) || (s_editMode>0 && (IS_ROTARY_RIGHT(event) || event==EVT_KEY_FIRST(KEY_UP) || event==EVT_KEY_REPT(KEY_UP)))) {
548 newval++;
550 else if (event==EVT_KEY_FIRST(KEY_LEFT) || event==EVT_KEY_REPT(KEY_LEFT) || (s_editMode>0 && (IS_ROTARY_LEFT(event) || event==EVT_KEY_FIRST(KEY_DOWN) || event==EVT_KEY_REPT(KEY_DOWN)))) {
551 newval--;
554 if (!READ_ONLY() && i_min==0 && i_max==1 && (event==EVT_KEY_BREAK(KEY_ENTER) || IS_ROTARY_BREAK(event))) {
555 s_editMode = 0;
556 newval = !val;
559 #if defined(NAVIGATION_POT1)
560 // change values based on P1
561 newval -= p1valdiff;
562 p1valdiff = 0;
563 #endif
565 #if defined(AUTOSWITCH)
566 if (i_flags & INCDEC_SWITCH) {
567 newval = checkIncDecMovedSwitch(newval);
569 #endif
571 #if defined(AUTOSOURCE)
572 if (i_flags & INCDEC_SOURCE) {
573 if (s_editMode>0) {
574 int8_t source = GET_MOVED_SOURCE(i_min, i_max);
575 if (source) {
576 newval = source;
578 #if defined(AUTOSWITCH)
579 else {
580 uint8_t swtch = abs(getMovedSwitch());
581 if (swtch) {
582 newval = switchToMix(swtch);
585 #endif
588 #endif
590 if (newval > i_max || newval < i_min) {
591 newval = (newval > i_max ? i_max : i_min);
592 killEvents(event);
593 AUDIO_KEY_ERROR();
596 if (newval != val) {
597 if (!(i_flags & NO_INCDEC_MARKS) && (newval != i_max) && (newval != i_min) && (newval==0 || newval==-100 || newval==+100) && !IS_ROTARY_EVENT(event)) {
598 pauseEvents(event); // delay before auto-repeat continues
600 if (!IS_KEY_REPT(event)) {
601 AUDIO_KEY_PRESS();
603 storageDirty(i_flags & (EE_GENERAL|EE_MODEL));
604 checkIncDec_Ret = (newval > val ? 1 : -1);
606 else {
607 checkIncDec_Ret = 0;
609 return newval;
611 #endif
613 #if defined(CPUM64)
614 int8_t checkIncDecModel(event_t event, int8_t i_val, int8_t i_min, int8_t i_max)
616 return checkIncDec(event, i_val, i_min, i_max, EE_MODEL);
619 int8_t checkIncDecModelZero(event_t event, int8_t i_val, int8_t i_max)
621 return checkIncDecModel(event, i_val, 0, i_max);
624 int8_t checkIncDecGen(event_t event, int8_t i_val, int8_t i_min, int8_t i_max)
626 return checkIncDec(event, i_val, i_min, i_max, EE_GENERAL);
628 #endif
630 #define SCROLL_TH 64
631 #define SCROLL_POT1_TH 32
633 #if defined(CPUARM)
634 #define CURSOR_NOT_ALLOWED_IN_ROW(row) ((int8_t)MAXCOL(row) < 0)
635 #else
636 #define CURSOR_NOT_ALLOWED_IN_ROW(row) (MAXCOL(row) == TITLE_ROW)
637 #endif
639 #define INC(val, min, max) if (val<max) {val++;} else {val=min;}
640 #define DEC(val, min, max) if (val>min) {val--;} else {val=max;}
642 #if defined(CPUARM)
643 tmr10ms_t menuEntryTime;
644 #endif
646 #if defined(PCBX7)
647 #define MAXCOL_RAW(row) (horTab ? pgm_read_byte(horTab+min(row, (vertpos_t)horTabMax)) : (const uint8_t)0)
648 #define MAXCOL(row) (MAXCOL_RAW(row) >= HIDDEN_ROW ? MAXCOL_RAW(row) : (const uint8_t)(MAXCOL_RAW(row) & (~NAVIGATION_LINE_BY_LINE)))
649 #define COLATTR(row) (MAXCOL_RAW(row) == (uint8_t)-1 ? (const uint8_t)0 : (const uint8_t)(MAXCOL_RAW(row) & NAVIGATION_LINE_BY_LINE))
650 #define MENU_FIRST_LINE_EDIT (menuTab ? (MAXCOL((uint16_t)0) >= HIDDEN_ROW ? (MAXCOL((uint16_t)1) >= HIDDEN_ROW ? 2 : 1) : 0) : 0)
651 #define POS_HORZ_INIT(posVert) ((COLATTR(posVert) & NAVIGATION_LINE_BY_LINE) ? -1 : 0)
653 void check(event_t event, uint8_t curr, const MenuHandlerFunc * menuTab, uint8_t menuTabSize, const pm_uint8_t * horTab, uint8_t horTabMax, vertpos_t rowcount)
655 vertpos_t l_posVert = menuVerticalPosition;
656 horzpos_t l_posHorz = menuHorizontalPosition;
658 uint8_t maxcol = MAXCOL(l_posVert);
660 if (menuTab) {
661 int cc = curr;
662 switch (event) {
663 #if 0 // TODO
664 case EVT_KEY_LONG(KEY_MENU):
665 if (menuTab == menuTabModel) {
666 killEvents(event);
667 if (modelHasNotes()) {
668 POPUP_MENU_ADD_SD_ITEM(STR_VIEW_CHANNELS);
669 POPUP_MENU_ADD_ITEM(STR_VIEW_NOTES);
670 POPUP_MENU_START(onLongMenuPress);
672 else {
673 pushMenu(menuChannelsView);
676 break;
677 #endif
679 case EVT_KEY_LONG(KEY_PAGE):
680 if (curr > 0)
681 cc = curr - 1;
682 else
683 cc = menuTabSize-1;
684 killEvents(event);
685 break;
687 case EVT_KEY_BREAK(KEY_PAGE):
688 if (curr < (menuTabSize-1))
689 cc = curr + 1;
690 else
691 cc = 0;
692 break;
695 if (!menuCalibrationState && cc != curr) {
696 chainMenu((MenuHandlerFunc)pgm_read_adr(&menuTab[cc]));
699 // TODO if (!(flags&CHECK_FLAG_NO_SCREEN_INDEX)) {
700 drawScreenIndex(curr, menuTabSize, 0);
701 // }
703 // TODO lcdDrawFilledRect(0, 0, LCD_W, MENU_HEADER_HEIGHT, SOLID, FILL_WHITE|GREY_DEFAULT);
706 DISPLAY_PROGRESS_BAR(menuTab ? lcdLastRightPos-2*FW-((curr+1)/10*FWNUM)-2 : 20*FW+1);
708 switch (event) {
709 case EVT_ENTRY:
710 menuEntryTime = get_tmr10ms();
711 s_editMode = EDIT_MODE_INIT;
712 l_posVert = MENU_FIRST_LINE_EDIT;
713 l_posHorz = POS_HORZ_INIT(l_posVert);
714 break;
716 case EVT_ENTRY_UP:
717 menuEntryTime = get_tmr10ms();
718 s_editMode = 0;
719 l_posHorz = POS_HORZ_INIT(l_posVert);
720 break;
722 case EVT_ROTARY_BREAK:
723 if (s_editMode > 1) break;
724 if (menuHorizontalPosition < 0 && maxcol > 0 && READ_ONLY_UNLOCKED()) {
725 l_posHorz = 0;
726 AUDIO_KEY_PRESS();
728 else if (READ_ONLY_UNLOCKED()) {
729 s_editMode = (s_editMode<=0);
730 AUDIO_KEY_PRESS();
732 break;
734 case EVT_KEY_LONG(KEY_EXIT):
735 s_editMode = 0; // TODO needed? we call ENTRY_UP after which does the same
736 popMenu();
737 break;
739 case EVT_KEY_BREAK(KEY_EXIT):
740 if (s_editMode > 0) {
741 s_editMode = 0;
742 AUDIO_KEY_PRESS();
743 break;
746 if (l_posHorz >= 0 && (COLATTR(l_posVert) & NAVIGATION_LINE_BY_LINE)) {
747 l_posHorz = -1;
748 AUDIO_KEY_PRESS();
750 else {
751 uint8_t posVertInit = MENU_FIRST_LINE_EDIT;
752 if (menuVerticalOffset != 0 || l_posVert != posVertInit) {
753 menuVerticalOffset = 0;
754 l_posVert = posVertInit;
755 l_posHorz = POS_HORZ_INIT(l_posVert);
756 AUDIO_KEY_PRESS();
758 else {
759 popMenu();
762 break;
764 case EVT_ROTARY_RIGHT:
765 case EVT_KEY_FIRST(KEY_RIGHT):
766 AUDIO_KEY_PRESS();
767 // no break
768 case EVT_KEY_REPT(KEY_RIGHT):
769 if (s_editMode > 0) break; // TODO it was !=
770 if ((COLATTR(l_posVert) & NAVIGATION_LINE_BY_LINE)) {
771 if (l_posHorz >= 0) {
772 INC(l_posHorz, 0, maxcol);
773 break;
776 else {
777 if (l_posHorz < maxcol) {
778 l_posHorz++;
779 break;
781 else {
782 l_posHorz = 0;
786 do {
787 INC(l_posVert, MENU_FIRST_LINE_EDIT, rowcount-1);
788 } while (CURSOR_NOT_ALLOWED_IN_ROW(l_posVert));
790 s_editMode = 0; // if we go down, we must be in this mode
792 l_posHorz = POS_HORZ_INIT(l_posVert);
793 break;
795 case EVT_ROTARY_LEFT:
796 case EVT_KEY_FIRST(KEY_LEFT):
797 AUDIO_KEY_PRESS();
798 // no break
799 case EVT_KEY_REPT(KEY_LEFT):
800 if (s_editMode > 0) break; // TODO it was !=
801 if ((COLATTR(l_posVert) & NAVIGATION_LINE_BY_LINE)) {
802 if (l_posHorz >= 0) {
803 DEC(l_posHorz, 0, maxcol);
804 break;
807 else if (l_posHorz > 0) {
808 l_posHorz--;
809 break;
811 else {
812 l_posHorz = 0xff;
815 do {
816 DEC(l_posVert, MENU_FIRST_LINE_EDIT, rowcount-1);
817 } while (CURSOR_NOT_ALLOWED_IN_ROW(l_posVert));
819 s_editMode = 0; // if we go up, we must be in this mode
821 if ((COLATTR(l_posVert) & NAVIGATION_LINE_BY_LINE))
822 l_posHorz = -1;
823 else
824 l_posHorz = min((uint8_t)l_posHorz, MAXCOL(l_posVert));
826 break;
829 int linesCount = rowcount;
831 if (l_posVert == 0 || (l_posVert==1 && MAXCOL(vertpos_t(0)) >= HIDDEN_ROW) || (l_posVert==2 && MAXCOL(vertpos_t(0)) >= HIDDEN_ROW && MAXCOL(vertpos_t(1)) >= HIDDEN_ROW)) {
832 menuVerticalOffset = 0;
833 if (horTab) {
834 linesCount = 0;
835 for (int i=0; i<rowcount; i++) {
836 if (i>horTabMax || horTab[i] != HIDDEN_ROW) {
837 linesCount++;
842 else if (horTab) {
843 if (rowcount > NUM_BODY_LINES) {
844 while (1) {
845 vertpos_t firstLine = 0;
846 for (int numLines=0; firstLine<rowcount && numLines<menuVerticalOffset; firstLine++) {
847 if (firstLine>=horTabMax || horTab[firstLine] != HIDDEN_ROW) {
848 numLines++;
851 if (l_posVert < firstLine) {
852 menuVerticalOffset--;
854 else {
855 vertpos_t lastLine = firstLine;
856 for (int numLines=0; lastLine<rowcount && numLines<NUM_BODY_LINES; lastLine++) {
857 if (lastLine>=horTabMax || horTab[lastLine] != HIDDEN_ROW) {
858 numLines++;
861 if (l_posVert >= lastLine) {
862 menuVerticalOffset++;
864 else {
865 linesCount = menuVerticalOffset + NUM_BODY_LINES;
866 for (int i=lastLine; i<rowcount; i++) {
867 if (i>horTabMax || horTab[i] != HIDDEN_ROW) {
868 linesCount++;
871 break;
877 else {
878 if (l_posVert>=NUM_BODY_LINES+menuVerticalOffset) {
879 menuVerticalOffset = l_posVert-NUM_BODY_LINES+1;
881 else if (l_posVert<menuVerticalOffset) {
882 menuVerticalOffset = l_posVert;
886 // TODO if (name) {
887 // title(name);
888 // }
890 menuVerticalPosition = l_posVert;
891 menuHorizontalPosition = l_posHorz;
893 #else
894 #define MAXCOL(row) (horTab ? pgm_read_byte(horTab+min(row, (vertpos_t)horTabMax)) : (const uint8_t)0)
895 #define POS_HORZ_INIT(posVert) 0
897 void check(event_t event, uint8_t curr, const MenuHandlerFunc *menuTab, uint8_t menuTabSize, const pm_uint8_t *horTab, uint8_t horTabMax, vertpos_t maxrow)
899 vertpos_t l_posVert = menuVerticalPosition;
900 horzpos_t l_posHorz = menuHorizontalPosition;
902 uint8_t maxcol = MAXCOL(l_posVert);
904 #if defined(NAVIGATION_POT1)
905 // check pot 1 - if changed -> scroll values
906 static int16_t p1val;
907 static int16_t p1valprev;
908 p1valdiff = (p1val-calibratedAnalogs[CALIBRATED_POT1]) / SCROLL_POT1_TH;
909 if (p1valdiff) {
910 p1valdiff = (p1valprev-calibratedAnalogs[CALIBRATED_POT1]) / 2;
911 p1val = calibratedAnalogs[CALIBRATED_POT1];
913 p1valprev = calibratedAnalogs[CALIBRATED_POT1];
914 #endif
916 #if defined(NAVIGATION_POT2)
917 // check pot 2 - if changed -> scroll menu
918 static int16_t p2valprev;
919 p2valdiff = (p2valprev-calibratedAnalogs[CALIBRATED_POT2]) / SCROLL_TH;
920 if (p2valdiff) p2valprev = calibratedAnalogs[CALIBRATED_POT2];
921 #endif
923 #if defined(NAVIGATION_POT3)
924 // check pot 3 if changed -> cursor down/up
925 static int16_t p3valprev;
926 int8_t scrollUD = (p3valprev-calibratedAnalogs[CALIBRATED_POT3]) / SCROLL_TH;
927 if (scrollUD) p3valprev = calibratedAnalogs[CALIBRATED_POT3];
928 #else
929 #define scrollUD 0
930 #endif
932 if (p2valdiff || scrollUD || p1valdiff) backlightOn(); // on keypress turn the light on
934 if (menuTab) {
935 uint8_t attr = 0;
937 if (l_posVert==0 && !menuCalibrationState) {
938 attr = INVERS;
940 int8_t cc = curr;
942 if (p2valdiff) {
943 cc = limit((int8_t)0, (int8_t)(cc - p2valdiff), (int8_t)(menuTabSize-1));
946 switch (event) {
947 #if defined(ROTARY_ENCODER_NAVIGATION)
948 case EVT_ROTARY_BREAK:
949 if (s_editMode < 0 && maxrow > 0) {
950 s_editMode = 0;
951 // TODO ? l_posVert = (horTab && horTab[1]==0xff) ? 2 : 1;
952 l_posHorz = 0;
954 else {
955 s_editMode = -1;
957 event = 0;
958 break;
959 #endif
961 #if defined(ROTARY_ENCODER_NAVIGATION)
962 case EVT_ROTARY_LEFT:
963 if (s_editMode >= 0)
964 break;
965 #endif
966 case EVT_KEY_FIRST(KEY_LEFT):
967 if (curr > 0)
968 cc = curr - 1;
969 else
970 cc = menuTabSize-1;
971 break;
973 #if defined(ROTARY_ENCODER_NAVIGATION)
974 case EVT_ROTARY_RIGHT:
975 if (s_editMode >= 0)
976 break;
977 #endif
978 case EVT_KEY_FIRST(KEY_RIGHT):
979 if (curr < (menuTabSize-1))
980 cc = curr + 1;
981 else
982 cc = 0;
983 break;
986 if (cc != curr) {
987 chainMenu((MenuHandlerFunc)pgm_read_adr(&menuTab[cc]));
990 #if defined(ROTARY_ENCODER_NAVIGATION)
991 if (IS_ROTARY_ENCODER_NAVIGATION_ENABLE() && s_editMode < 0)
992 attr = INVERS|BLINK;
993 #endif
996 menuCalibrationState = 0;
997 drawScreenIndex(curr, menuTabSize, attr);
1001 DISPLAY_PROGRESS_BAR(menuTab ? lcdLastRightPos-2*FW-((curr+1)/10*FWNUM)-2 : 20*FW+1);
1003 if (s_editMode<=0) {
1004 if (scrollUD) {
1005 l_posVert = limit((int8_t)0, (int8_t)(l_posVert - scrollUD), (int8_t)maxrow);
1006 l_posHorz = min((uint8_t)l_posHorz, MAXCOL(l_posVert));
1009 if (p2valdiff && l_posVert>0) {
1010 l_posHorz = limit((int8_t)0, (int8_t)((uint8_t)l_posHorz - p2valdiff), (int8_t)maxcol);
1014 switch (event)
1016 case EVT_ENTRY:
1017 #if defined(CPUARM)
1018 menuEntryTime = get_tmr10ms();
1019 #endif
1020 l_posVert = 0;
1021 l_posHorz = POS_HORZ_INIT(l_posVert);
1022 #if defined(ROTARY_ENCODER_NAVIGATION)
1023 if (menuTab) {
1024 s_editMode = EDIT_MODE_INIT;
1025 break;
1027 // no break
1028 #else
1029 s_editMode = EDIT_MODE_INIT;
1030 break;
1031 #endif
1033 #if defined(ROTARY_ENCODER_NAVIGATION)
1034 case EVT_ENTRY_UP:
1035 s_editMode = 0;
1036 break;
1038 case EVT_ROTARY_BREAK:
1039 if (s_editMode > 1) break;
1040 #endif
1042 case EVT_KEY_FIRST(KEY_ENTER):
1043 if (!menuTab || l_posVert>0) {
1044 if (READ_ONLY_UNLOCKED()) {
1045 s_editMode = (s_editMode<=0);
1048 break;
1050 #if defined(ROTARY_ENCODER_NAVIGATION)
1051 case EVT_ROTARY_LONG:
1052 if (s_editMode > 1) break;
1053 killEvents(event);
1054 if (l_posVert != 0) {
1055 l_posVert = 0;
1056 s_editMode = EDIT_MODE_INIT;
1057 break;
1059 // no break
1060 #endif
1061 case EVT_KEY_LONG(KEY_EXIT):
1062 s_editMode = 0; // TODO needed? we call ENTRY_UP after which does the same
1063 popMenu();
1064 break;
1066 case EVT_KEY_BREAK(KEY_EXIT):
1067 AUDIO_KEY_PRESS();
1068 #if defined(ROTARY_ENCODER_NAVIGATION)
1069 if (s_editMode == 0)
1070 s_editMode = EDIT_MODE_INIT;
1071 else
1072 #endif
1073 if (s_editMode>0) {
1074 s_editMode = 0;
1075 break;
1078 if (l_posVert==0 || !menuTab) {
1079 popMenu(); // beeps itself
1081 else {
1082 l_posVert = 0;
1083 l_posHorz = 0;
1085 break;
1087 case EVT_KEY_REPT(KEY_RIGHT): //inc
1088 if (l_posHorz==maxcol) break;
1089 // no break
1091 case EVT_KEY_FIRST(KEY_RIGHT)://inc
1092 if (!horTab || s_editMode>0) break;
1094 #if defined(ROTARY_ENCODER_NAVIGATION)
1095 CASE_EVT_ROTARY_RIGHT
1096 if (s_editMode != 0) break;
1097 if (l_posHorz < maxcol) {
1098 l_posHorz++;
1099 break;
1101 else {
1102 l_posHorz = 0;
1103 if (!IS_ROTARY_RIGHT(event))
1104 break;
1106 #else
1107 INC(l_posHorz, 0, maxcol);
1108 break;
1109 #endif
1111 #if !defined(PCBX7)
1112 case EVT_KEY_REPT(KEY_DOWN):
1113 if (!IS_ROTARY_RIGHT(event) && l_posVert==maxrow) break;
1114 // no break
1116 case EVT_KEY_FIRST(KEY_DOWN):
1117 if (s_editMode>0) break;
1118 do {
1119 INC(l_posVert, 0, maxrow);
1120 } while (CURSOR_NOT_ALLOWED_IN_ROW(l_posVert));
1122 #if defined(ROTARY_ENCODER_NAVIGATION)
1123 s_editMode = 0; // if we go down, we must be in this mode
1124 #endif
1126 l_posHorz = min<horzpos_t>(l_posHorz, MAXCOL(l_posVert));
1127 break;
1128 #endif
1130 case EVT_KEY_REPT(KEY_LEFT): //dec
1131 if (l_posHorz==0) break;
1132 // no break
1134 case EVT_KEY_FIRST(KEY_LEFT)://dec
1135 if (!horTab || s_editMode>0) break;
1137 #if defined(ROTARY_ENCODER_NAVIGATION)
1138 CASE_EVT_ROTARY_LEFT
1139 if (s_editMode != 0) break;
1140 if (l_posHorz > 0) {
1141 l_posHorz--;
1142 break;
1144 else if (IS_ROTARY_LEFT(event) && s_editMode == 0) {
1145 l_posHorz = 0xff;
1147 else {
1148 l_posHorz = maxcol;
1149 break;
1151 #else
1152 DEC(l_posHorz, 0, maxcol);
1153 break;
1154 #endif
1156 #if !defined(PCBX7)
1157 case EVT_KEY_REPT(KEY_UP):
1158 if (!IS_ROTARY_LEFT(event) && l_posVert==0) break;
1159 // no break
1160 case EVT_KEY_FIRST(KEY_UP):
1161 if (s_editMode>0) break;
1163 do {
1164 DEC(l_posVert, 0, maxrow);
1165 } while (CURSOR_NOT_ALLOWED_IN_ROW(l_posVert));
1167 #if defined(ROTARY_ENCODER_NAVIGATION)
1168 s_editMode = 0; // if we go up, we must be in this mode
1169 #endif
1171 l_posHorz = min((uint8_t)l_posHorz, MAXCOL(l_posVert));
1172 break;
1173 #endif
1176 uint8_t maxLines = menuTab ? LCD_LINES-1 : LCD_LINES-2;
1178 #if defined(CPUARM)
1179 int linesCount = maxrow;
1180 if (l_posVert == 0 || (l_posVert==1 && MAXCOL(vertpos_t(0)) >= HIDDEN_ROW) || (l_posVert==2 && MAXCOL(vertpos_t(0)) >= HIDDEN_ROW && MAXCOL(vertpos_t(1)) >= HIDDEN_ROW)) {
1181 menuVerticalOffset = 0;
1182 if (horTab) {
1183 linesCount = 0;
1184 for (int i=0; i<maxrow; i++) {
1185 if (i>=horTabMax || horTab[i] != HIDDEN_ROW) {
1186 linesCount++;
1191 else if (horTab) {
1192 if (maxrow > maxLines) {
1193 while (1) {
1194 vertpos_t firstLine = 0;
1195 for (int numLines=0; firstLine<maxrow && numLines<menuVerticalOffset; firstLine++) {
1196 if (firstLine>=horTabMax || horTab[firstLine+1] != HIDDEN_ROW) {
1197 numLines++;
1200 if (l_posVert <= firstLine) {
1201 menuVerticalOffset--;
1203 else {
1204 vertpos_t lastLine = firstLine;
1205 for (int numLines=0; lastLine<maxrow && numLines<maxLines; lastLine++) {
1206 if (lastLine>=horTabMax || horTab[lastLine+1] != HIDDEN_ROW) {
1207 numLines++;
1210 if (l_posVert > lastLine) {
1211 menuVerticalOffset++;
1213 else {
1214 linesCount = menuVerticalOffset + maxLines;
1215 for (int i=lastLine; i<maxrow; i++) {
1216 if (i>=horTabMax || horTab[i] != HIDDEN_ROW) {
1217 linesCount++;
1220 break;
1226 #else
1227 if (l_posVert<1) {
1228 menuVerticalOffset=0;
1230 #endif
1231 else {
1232 if (l_posVert>maxLines+menuVerticalOffset) {
1233 menuVerticalOffset = l_posVert-maxLines;
1235 else if (l_posVert<=menuVerticalOffset) {
1236 menuVerticalOffset = l_posVert-1;
1240 menuVerticalPosition = l_posVert;
1241 menuHorizontalPosition = l_posHorz;
1242 #if !defined(CPUM64)
1243 // cosmetics on 9x
1244 if (menuVerticalOffset > 0) {
1245 l_posVert--;
1246 if (l_posVert == menuVerticalOffset && CURSOR_NOT_ALLOWED_IN_ROW(l_posVert)) {
1247 menuVerticalOffset = l_posVert-1;
1250 #endif
1252 #endif
1254 void check_simple(event_t event, uint8_t curr, const MenuHandlerFunc * menuTab, uint8_t menuTabSize, vertpos_t maxrow)
1256 check(event, curr, menuTab, menuTabSize, 0, 0, maxrow);
1259 void check_submenu_simple(event_t event, uint8_t maxrow)
1261 check_simple(event, 0, 0, 0, maxrow);
1264 void repeatLastCursorMove(event_t event)
1266 if (CURSOR_MOVED_LEFT(event) || CURSOR_MOVED_RIGHT(event)) {
1267 putEvent(event);
1269 else {
1270 menuHorizontalPosition = 0;