ubitx-v5d-xcvr/ubitx_iop/menu.h
Rob French 0a8e91c4a7 Revamped the fledgling menu system using the Embedded Template Library.
It works!

Started building up configuration menus.  Compiles, haven't tested yet.
Still learning about how to use the ETL/STL.
2020-06-11 23:50:50 -05:00

365 lines
8.4 KiB
C++

//======================================================================
// menu.h
//======================================================================
#ifndef __menu_h__
#define __menu_h__
//#include "etl_profile.h"
//#include <ArduinoSTL.h>
#include "etl/array.h"
#include "etl/cstring.h"
#include "etl/delegate.h"
//#include <vector>
#include <initializer_list>
#include "rig.h"
#include "tx_audio_proc.h"
extern SpeechCompressor speechCompressor; // This should be somewhere else.
// 16 characters on display
const int MAX_TEXT_LEN = 16;
const int max_text_len = 16;
const char MENU_SELECTED_CHAR = '>';
const char menu_selection_char = '>';
const char blankLine[17] = " ";
typedef etl::string<max_text_len> Menu_string;
//======================================================================
// Menu_item
//======================================================================
class Menu_item {
public:
Menu_item(): parent_link(nullptr) {}
virtual ~Menu_item() {}
virtual const Menu_string& title() const = 0;
virtual void get_title(Menu_string& outstr) const = 0;
virtual void get_text(Menu_string& outstr) const = 0;
virtual Menu_item* select() = 0;
virtual Menu_item* altSelect() = 0;
virtual Menu_item* exit() = 0;
virtual Menu_item* prev() = 0;
virtual Menu_item* next() = 0;
void set_parent(Menu_item* item) {
parent_link = item;
}
const Menu_item* parent() const {
return parent_link;
}
private:
Menu_item* parent_link;
};
//======================================================================
// List_menu
//======================================================================
const int MAX_LISTMENU_TITLE_LEN = 15;
//const int max_size_of_list_menu = 20; // arbitrary...
template <const size_t SIZE>
class List_menu : public Menu_item {
public:
List_menu(const char* title, etl::array<const Menu_item*, SIZE> items):
Menu_item(), list_title(title), list_items(items), index(0) {
for (auto element : list_items) {
element->set_parent(this);
}
}
virtual const Menu_string& title() const {
return list_title;
}
virtual void get_title(Menu_string& outstr) const {
outstr.assign(list_title);
}
virtual void get_text(Menu_string& outstr) const {
list_items[index]->get_text(outstr);
}
virtual Menu_item* select()
{
return list_items[index];
}
virtual Menu_item* altSelect()
{
return this;
}
virtual Menu_item* exit()
{
return parent();
}
virtual Menu_item* prev()
{
if (--index < 0) {
index += list_items.size();
}
return this;
}
virtual Menu_item* next()
{
index = ++index % list_items.size();
return this;
}
private:
Menu_string list_title;
etl::array<const Menu_item*, SIZE> list_items;
int index;
};
//======================================================================
// Config_parm
//======================================================================
typedef etl::delegate<void(void)> Update_func;
template<typename T>
class Config_parm : public Menu_item {
public:
Config_parm(const char* title, T& parm, T min, T max, T step, Update_func f):
Menu_item(), parm_title(title), parameter(parm), min_val(min), max_val(max), step_val(step), on_update(f) {}
virtual const Menu_string& title() const {
return parm_title;
}
virtual void get_title(Menu_string& outstr) const {
outstr.assign(parm_title);
}
virtual void get_text(Menu_string& outstr) const = 0;
virtual Menu_item* select() {
on_update();
return parent();
}
virtual Menu_item* altSelect() {
on_update();
return this;
}
virtual Menu_item* exit() {
return parent();
}
virtual Menu_item* prev() {
parameter -= step_val;
if (parameter < min_val) {
parameter = min_val;
}
return this;
}
virtual Menu_item* next() {
parameter += step_val;
if (parameter > max_val) {
parameter = max_val;
}
return this;
}
const T& value() const {
return parameter;
}
private:
Menu_string parm_title;
T& parameter;
T min_val;
T max_val;
T step_val;
Update_func on_update;
};
class Parm_int : public Config_parm<int> {
public:
Parm_int(const char* title, int parm, int min, int max, int step, Update_func f):
Config_parm(title, parm, min, max, step, f) {}
virtual void get_text(Menu_string& outstr) const {
snprintf(outstr.data(), max_text_len+1, "%-*s %3d", max_text_len-4, title().data(), value());
}
};
class Parm_float : public Config_parm<float> {
public:
Parm_float(const char* title, float parm, float min, float max, float step, Update_func f):
Config_parm(title, parm, min, max, step, f) {}
virtual void get_text(Menu_string& outstr) const {
snprintf(outstr.data(), max_text_len+1, "%-*s %5.2f", max_text_len-6, title().data(), value());
}
};
//======================================================================
const char modeID[] = {'s', 'S', 'c', 'C', 'd', 'D', 't', 'T'};
const char* const filterID[NUM_RIG_MODES][NUM_RX_FILTERS] = {
{"2.8", "2.4", "1.8"}, // LSB
{"2.8", "2.4", "1.8"}, // USB
{"1.0", "500", "250"}, // CWL
{"1.0", "500", "250"}, // CWU
{"2.8", "2.4", "500"}, // DGL
{"2.8", "2.4", "500"}, // DGU
{"2.8", "2.4", "1.8"}, // TTL
{"2.8", "2.4", "1.8"}, // TTU
};
//======================================================================
// Top_menu
//======================================================================
class Main_menu : public Menu_item {
public:
Main_menu(Rig& rig): menu_title("Main Menu"), rig(rig), adjust_tx(false), comp_on(false) {}
virtual const Menu_string& title() const {
return menu_title;
}
virtual void get_title(Menu_string& outstr) const {
outstr.assign(menu_title);
}
virtual void get_text(Menu_string& outstr) const {
char text[max_text_len+1];
sprintf(text, "%1cR:%3s %1cT:%3s ",
adjust_tx ? ' ' : menu_selection_char,
filterID[rig.modeNum()][rig.filterNum()],
adjust_tx ? menu_selection_char : ' ',
rig.isSSBMode() && comp_on ? "CMP" : " ");
outstr.assign(text);
}
/*
virtual void update() {
sprintf(_text0, "%1cR:%3s %1cT:%3s ",
_adjust_tx ? ' ' : MENU_SELECTED_CHAR,
filterID[_rig.modeNum()][_rig.filterNum()],
_adjust_tx ? MENU_SELECTED_CHAR : ' ',
_rig.isSSBMode() && _comp_on ? "CMP" : " ");
if ((strcmp(_text0, _text1) != 0) || _dirty) {
if (_visible) {
sendIOPMenuDisplay(_text0);
USBDEBUG("updating menu:");
USBDEBUG(_text0);
} else {
sendIOPMenuInactive();
USBDEBUG("deactivating menu");
}
_dirty = false;
strncpy(_text1, _text0, MAX_TEXT_LEN);
}
}
*/
virtual Menu_item* select() {
adjust_tx = !adjust_tx;
return this;
}
virtual Menu_item* altSelect() {
return this;
}
virtual Menu_item* exit() {
return nullptr;
}
virtual Menu_item* prev() {
if (adjust_tx) {
if (rig.isSSBMode()) {
comp_on = !comp_on;
if (comp_on)
speechCompressor.enable();
else
speechCompressor.disable();
}
} else {
rig.switchRxFilter(true);
}
return this;
}
virtual Menu_item* next() {
if (adjust_tx) {
if (rig.isSSBMode()) {
comp_on = !comp_on;
if (comp_on)
speechCompressor.enable();
else
speechCompressor.disable();
}
} else {
rig.switchRxFilter();
}
return this;
}
private:
Menu_string menu_title;
Rig& rig;
bool adjust_tx;
bool comp_on;
};
/*
public class MenuItem {
public:
MenuItem(bool active = true, int timeout = 0): _active(active), _timeout(timeout), _elapsed(0) {}
void update() {
if ((_timeout > 0) && (_elapsed > _timeout)) {
_active = false;
}
}
inline void activate() { _active = true; _elapsed = 0; }
inline void deactivate() { _active = false; }
virtual MenuItem* accept();
virtual MenuItem* reject();
virtual MenuItem* next();
virtual MenuItem* prev();
private:
bool _active;
int _timeout;
elapsedMillis _elapsed;
};
public class SSBMenu {
public:
private:
};
public class DigiMenu {
public:
private:
}
public class CWMenu {
public:
private:
};
*/
#endif
//======================================================================
// EOF
//======================================================================