1
0
Fork 0
mirror of https://github.com/opentx/opentx.git synced 2025-07-20 14:55:13 +03:00
opentx/src/menus.cpp
bsongis 040160efc9 New EEPROM format 205
Introduction of differential in Mixers
Introduction of Switches as Mixer Source (FULL now removed)
Negative curves in Mixers
Optimizations in Mixer
Extended chars for localization
Swedish translations
Beep length updated
2012-03-04 17:25:35 +00:00

515 lines
13 KiB
C++

/*
* Authors (alphabetical order)
* - Bertrand Songis <bsongis@gmail.com>
* - Bryan J. Rentoul (Gruvin) <gruvin@gmail.com>
* - Cameron Weeks <th9xer@gmail.com>
* - Erez Raviv
* - Jean-Pierre Parisy
* - Karl Szmutny <shadow@privy.de>
* - Michael Blandford
* - Michal Hlavinka
* - Pat Mackenzie
* - Philip Moss
* - Rob Thomson
* - Romolo Manfredini <romolo.manfredini@gmail.com>
* - Thomas Husterer
*
* open9x is based on code named
* gruvin9x by Bryan J. Rentoul: http://code.google.com/p/gruvin9x/,
* er9x by Erez Raviv: http://code.google.com/p/er9x/,
* and the original (and ongoing) project by
* Thomas Husterer, th9x: http://code.google.com/p/th9x/
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
#include "open9x.h"
#include "templates.h"
#include "menus.h"
int16_t calibratedStick[NUM_STICKS+NUM_POTS];
uint8_t s_pgOfs;
int8_t s_editMode;
uint8_t s_noHi;
uint8_t s_noScroll;
int16_t g_chans512[NUM_CHNOUT]; // TODO not here!
void menu_lcd_onoff( uint8_t x,uint8_t y, uint8_t value, uint8_t mode )
{
lcd_putsiAtt(x, y, STR_OFFON, value, mode ? INVERS:0) ;
}
void DisplayScreenIndex(uint8_t index, uint8_t count, uint8_t attr)
{
lcd_outdezAtt(128,0,count,attr);
lcd_putcAtt(1+128-FW*(count>9 ? 3 : 2),0,'/',attr);
lcd_outdezAtt(1+128-FW*(count>9 ? 3 : 2),0,index+1,attr);
}
#if defined(NAVIGATION_RE1)
int8_t scrollRE;
int16_t p1valdiff;
#elif defined(NAVIGATION_POT1)
int16_t p1valdiff;
#endif
int8_t checkIncDec_Ret;
int16_t checkIncDec(uint8_t event, int16_t val, int16_t i_min, int16_t i_max, uint8_t i_flags)
{
int16_t newval = val;
uint8_t kpl=KEY_RIGHT, kmi=KEY_LEFT, kother = -1;
if(event & _MSK_KEY_DBL){
uint8_t hlp=kpl;
kpl=kmi;
kmi=hlp;
event=EVT_KEY_FIRST(EVT_KEY_MASK & event);
}
if(event==EVT_KEY_FIRST(kpl) || event== EVT_KEY_REPT(kpl) || (s_editMode>0 && (event==EVT_KEY_FIRST(KEY_UP) || event== EVT_KEY_REPT(KEY_UP))) ) {
newval++;
AUDIO_KEYPAD_UP();
kother=kmi;
}
else if(event==EVT_KEY_FIRST(kmi) || event== EVT_KEY_REPT(kmi) || (s_editMode>0 && (event==EVT_KEY_FIRST(KEY_DOWN) || event== EVT_KEY_REPT(KEY_DOWN))) ) {
newval--;
AUDIO_KEYPAD_DOWN();
kother=kpl;
}
if((kother != (uint8_t)-1) && keyState((EnumKeys)kother)){
newval=-val;
killEvents(kmi);
killEvents(kpl);
}
if(i_min==0 && i_max==1 && event==EVT_KEY_FIRST(KEY_MENU)) {
s_editMode = 0;
newval=!val;
killEvents(event);
}
#if defined(NAVIGATION_POT1) || defined (NAVIGATION_RE1)
//change values based on P1
newval -= p1valdiff;
#endif
if(newval > i_max)
{
newval = i_max;
killEvents(event);
AUDIO_WARNING2();
}
if(newval < i_min)
{
newval = i_min;
killEvents(event);
AUDIO_WARNING2();
}
if(newval != val){
if(newval==0) {
pauseEvents(event); // delay before auto-repeat continues
if (newval>val) // TODO check if without AUDIO it's optimized!
AUDIO_KEYPAD_UP();
else
AUDIO_KEYPAD_DOWN();
}
eeDirty(i_flags & (EE_GENERAL|EE_MODEL));
checkIncDec_Ret = (newval > val ? 1 : -1);
}
else {
checkIncDec_Ret = 0;
}
return newval;
}
int8_t checkIncDecModel(uint8_t event, int8_t i_val, int8_t i_min, int8_t i_max)
{
return checkIncDec(event,i_val,i_min,i_max,EE_MODEL);
}
int8_t checkIncDecGen(uint8_t event, int8_t i_val, int8_t i_min, int8_t i_max)
{
return checkIncDec(event,i_val,i_min,i_max,EE_GENERAL);
}
bool check_simple(uint8_t event, uint8_t curr, const MenuFuncP *menuTab, uint8_t menuTabSize, uint8_t maxrow)
{
return check(event, curr, menuTab, menuTabSize, 0, 0, maxrow);
}
bool check_submenu_simple(uint8_t event, uint8_t maxrow)
{
return check_simple(event, 0, 0, 0, maxrow);
}
#ifdef NAVIGATION_RE1
void check_rotary_encoder()
{
// check rotary encoder 1 if changed -> cursor down/up
static int16_t re1valprev;
p1valdiff = 0;
scrollRE = re1valprev - g_rotenc[0];
if (scrollRE) {
re1valprev = g_rotenc[0];
if (s_editMode > 0) {
p1valdiff = -scrollRE;
scrollRE = 0;
}
}
}
#endif
#define SCROLL_TH 64
#define SCROLL_POT1_TH 32
#ifdef NAVIGATION_RE1
#define MAXCOL(row) ((horTab && row >= 0) ? pgm_read_byte(horTab+min(row, (int8_t)horTabMax)) : (const uint8_t)0)
#else
#define MAXCOL(row) (horTab ? pgm_read_byte(horTab+min(row, horTabMax)) : (const uint8_t)0)
#endif
#define INC(val,max) if(val<max) {val++;} else {val=0;}
#define DEC(val,max) if(val>0 ) {val--;} else {val=max;}
bool check(uint8_t event, uint8_t curr, const MenuFuncP *menuTab, uint8_t menuTabSize, const pm_uint8_t *horTab, uint8_t horTabMax, uint8_t maxrow)
{
int8_t maxcol = MAXCOL(m_posVert);
#ifdef NAVIGATION_RE1
check_rotary_encoder();
if (m_posVert < 0 && (event==EVT_KEY_FIRST(BTN_RE1) || event==EVT_KEY_FIRST(KEY_MENU))) {
popMenu();
killEvents(event);
return false;
}
if (event == EVT_KEY_BREAK(BTN_RE1)) {
if (s_editMode > 0 && (maxcol & ZCHAR)) {
if (m_posHorz < maxcol-ZCHAR) {
m_posHorz++;
}
else {
s_editMode = 0;
}
}
else {
scrollRE = 0;
if (s_editMode++ > 0) s_editMode = 0;
if (s_editMode > 0 && m_posVert == 0 && menuTab) s_editMode = -1;
}
}
#else
#define scrollRE 0
#endif
#ifdef NAVIGATION_POT1
// check pot 1 - if changed -> scroll values
static int16_t p1valprev;
p1valdiff = (p1valprev-calibratedStick[6]) / SCROLL_POT1_TH;
if (p1valdiff) p1valprev = calibratedStick[6];
#endif
#ifdef NAVIGATION_POT2
// check pot 2 - if changed -> scroll menu
static int16_t p2valprev;
int8_t scrollLR = (p2valprev-calibratedStick[4]) / SCROLL_TH;
if (scrollLR) p2valprev = calibratedStick[4];
#else
#define scrollLR 0
#endif
#ifdef NAVIGATION_POT3
// check pot 3 if changed -> cursor down/up
static int16_t p3valprev;
int8_t scrollUD = (p3valprev-calibratedStick[5]) / SCROLL_TH;
if (scrollUD) p3valprev = calibratedStick[5];
#else
#define scrollUD 0
#endif
if(scrollLR || scrollUD || p1valdiff) g_LightOffCounter = g_eeGeneral.lightAutoOff*500; // on keypress turn the light on 5*100
if (menuTab) {
uint8_t attr = 0;
if (m_posVert==0 && !s_noScroll) {
attr = INVERS;
int8_t cc = curr;
if (scrollLR || (scrollRE && s_editMode < 0)) {
cc = limit((int8_t)0, (int8_t)(curr - scrollLR + scrollRE), (int8_t)(menuTabSize-1));
}
switch(event) {
case EVT_KEY_FIRST(KEY_LEFT):
if (curr > 0)
cc = curr - 1;
else
cc = menuTabSize-1;
break;
case EVT_KEY_FIRST(KEY_RIGHT):
if (curr < (menuTabSize-1))
cc = curr + 1;
else
cc = 0;
break;
}
if (cc != curr) {
chainMenu((MenuFuncP)pgm_read_adr(&menuTab[cc]));
return false;
}
}
s_noScroll = 0;
DisplayScreenIndex(curr, menuTabSize, attr);
}
#ifdef NAVIGATION_RE1
else if (m_posVert < 0) {
lcd_putsAtt(DISPLAY_W-LEN_BACK*FW, 0, STR_BACK, INVERS);
}
#endif
theFile.DisplayProgressBar(menuTab ? lcd_lastPos-2*FW-((curr+1)/10*FWNUM)-2 : 20*FW+1);
if (s_editMode<=0) {
if (scrollUD) {
m_posVert = limit((int8_t)0, (int8_t)(m_posVert - scrollUD), (int8_t)maxrow);
m_posHorz = min(m_posHorz, MAXCOL(m_posVert));
BLINK_SYNC;
}
if (scrollLR && m_posVert>0) {
m_posHorz = limit((int8_t)0, (int8_t)(m_posHorz - scrollLR), (int8_t)maxcol);
BLINK_SYNC;
}
#ifdef NAVIGATION_RE1
while (!s_editMode && scrollRE) {
if (scrollRE > 0) {
--scrollRE;
maxcol = MAXCOL(m_posVert);
if (maxcol & ZCHAR) maxcol = 0;
if (++m_posHorz > maxcol) {
if (m_posVert < maxrow) {
++m_posVert;
maxcol = MAXCOL(m_posVert); // TODO not stored into maxcol?
if (maxcol < 0) m_posVert++;
m_posHorz = 0;
}
else {
--m_posHorz;
scrollRE = 0;
}
}
}
else {
++scrollRE;
if (m_posHorz-- == 0) {
if (m_posVert-- <= 0) {
m_posVert = menuTab ? 0 : -1;
m_posHorz = 0;
scrollRE = 0;
}
else {
maxcol = MAXCOL(m_posVert);
if (maxcol < 0) { --m_posVert; maxcol = MAXCOL(m_posVert); }
m_posHorz = maxcol;
}
}
}
}
#endif
}
switch(event)
{
case EVT_ENTRY:
minit();
#ifdef NAVIGATION_RE1
if (menuTab) {
s_editMode = -1;
break;
}
// no break
#else
s_editMode = -1;
break;
#endif
#ifdef NAVIGATION_RE1
case EVT_ENTRY_UP:
s_editMode = 0;
break;
#endif
case EVT_KEY_FIRST(KEY_MENU):
if (maxcol > 0)
s_editMode = (s_editMode<=0);
break;
case EVT_KEY_LONG(KEY_EXIT):
s_editMode = 0;
popMenu();
break;
case EVT_KEY_BREAK(KEY_EXIT):
if(s_editMode>0) {
s_editMode = 0;
break;
}
if (m_posVert==0 || !menuTab) {
popMenu(); //beeps itself
}
else {
AUDIO_MENUS();
minit();
BLINK_SYNC;
}
break;
case EVT_KEY_REPT(KEY_RIGHT): //inc
if(m_posHorz==maxcol) break;
case EVT_KEY_FIRST(KEY_RIGHT)://inc
if(!horTab || s_editMode>0)break;
INC(m_posHorz,maxcol);
BLINK_SYNC;
break;
case EVT_KEY_REPT(KEY_LEFT): //dec
if(m_posHorz==0) break;
case EVT_KEY_FIRST(KEY_LEFT)://dec
if(!horTab || s_editMode>0)break;
DEC(m_posHorz,maxcol);
BLINK_SYNC;
break;
case EVT_KEY_REPT(KEY_DOWN): //inc
if(m_posVert==maxrow) break;
case EVT_KEY_FIRST(KEY_DOWN): //inc
if(s_editMode>0)break;
do {
INC(m_posVert, maxrow);
} while(MAXCOL(m_posVert) == (uint8_t)-1);
#ifdef NAVIGATION_RE1
s_editMode = 0;
#endif
m_posHorz = min(m_posHorz, MAXCOL(m_posVert));
BLINK_SYNC;
break;
case EVT_KEY_REPT(KEY_UP): //dec
if(m_posVert==0) break;
case EVT_KEY_FIRST(KEY_UP): //dec
if(s_editMode>0)break;
do {
DEC(m_posVert,maxrow);
} while(MAXCOL(m_posVert) == (uint8_t)-1);
m_posHorz = min(m_posHorz, MAXCOL(m_posVert));
BLINK_SYNC;
break;
}
uint8_t max = menuTab ? 7 : 6;
if(m_posVert<1) s_pgOfs=0;
else if(m_posVert-s_pgOfs>max) s_pgOfs = m_posVert-max;
else if(m_posVert-s_pgOfs<1) s_pgOfs = m_posVert-1;
return true;
}
MenuFuncP g_menuStack[5];
uint8_t g_menuPos[4];
uint8_t g_menuStackPtr = 0;
#ifdef NAVIGATION_RE1
int8_t m_posVert;
#else
uint8_t m_posVert;
#endif
uint8_t m_posHorz;
void popMenu()
{
if (g_menuStackPtr>0) {
g_menuStackPtr = g_menuStackPtr-1;
AUDIO_KEYPAD_UP();
m_posHorz = 0;
m_posVert = g_menuPos[g_menuStackPtr];
(*g_menuStack[g_menuStackPtr])(EVT_ENTRY_UP);
}
else {
alert(STR_MENUSERROR);
}
}
void chainMenu(MenuFuncP newMenu)
{
#ifdef NAVIGATION_RE1
s_warning = NULL;
#endif
g_menuStack[g_menuStackPtr] = newMenu;
(*newMenu)(EVT_ENTRY);
AUDIO_MENUS();
}
void pushMenu(MenuFuncP newMenu)
{
#ifdef NAVIGATION_RE1
s_warning = NULL;
#endif
g_menuPos[g_menuStackPtr] = m_posVert;
g_menuStackPtr++;
if(g_menuStackPtr >= DIM(g_menuStack))
{
g_menuStackPtr--;
alert(STR_MENUSERROR);
return;
}
AUDIO_MENUS();
g_menuStack[g_menuStackPtr] = newMenu;
(*newMenu)(EVT_ENTRY);
}
const pm_char * s_warning = 0;
void displayBox()
{
lcd_filled_rect(10, 16, 108, 40, SOLID, WHITE);
lcd_rect(10, 16, 108, 40);
lcd_puts(16, 3*FH, s_warning);
// could be a place for a s_warning_info
}
#ifdef NAVIGATION_RE1
int8_t *s_inflight_value = NULL;
int8_t s_inflight_min;
int8_t s_inflight_max;
int8_t s_inflight_shift;
uint8_t s_inflight_bitshift;
const pm_char *s_inflight_label;
void checkInFlightIncDecModel(uint8_t event, int8_t *value, int8_t i_min, int8_t i_max, int8_t i_shift, const pm_char *label, uint8_t bitshift)
{
*value = (((uint8_t)(*value)) & ((1 << bitshift) - 1)) + ((i_shift + checkIncDecModel(event, (((uint8_t)(*value)) >> bitshift)-i_shift, i_min, i_max)) << bitshift);
if (event == EVT_KEY_LONG(BTN_RE1)) {
if (value == s_inflight_value) {
s_inflight_value = NULL;
}
else {
s_inflight_value = value;
s_inflight_min = i_min;
s_inflight_max = i_max;
s_inflight_shift = i_shift;
s_inflight_label = label;
s_inflight_bitshift = bitshift;
}
}
}
#endif