Advertisement
ripred

menu.h

Jan 14th, 2023 (edited)
1,015
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 8.03 KB | None | 0 0
  1. /*\
  2. |*| menu.h
  3. |*|
  4. |*| (c) 2022 Trent M. Wyatt.
  5. |*| companion file for Reverse Geocache Box project
  6. |*|
  7. \*/
  8.  
  9. #if !defined(MENU_H_INC)
  10. #define MENU_H_INC
  11.  
  12. enum entry_t : uint8_t
  13. {
  14.     FUNC = 0,
  15.     MENU = 1,
  16.      INT = 2
  17. };
  18.  
  19. struct lcd_menu_t;
  20.  
  21. struct variant_t
  22. {
  23.     union {
  24.         void      (*func)();
  25.         lcd_menu_t *menu;
  26.         int         ival;
  27.     }       value{0};
  28.     entry_t type{INT};
  29.  
  30.     variant_t() : value{0}, type{INT} { }
  31.  
  32.     variant_t(void(*func)()) : type{FUNC} {
  33.         value.func = func;
  34.     }
  35.  
  36.     variant_t(lcd_menu_t *menu) : type{MENU} {
  37.         value.menu = menu;
  38.     }
  39.  
  40.     variant_t(int val) : type{INT} {
  41.         value.ival = val;
  42.     }
  43.  
  44.     variant_t const & operator = (void (*func)())
  45.     {
  46.         (*this).value.func = func;
  47.         type = FUNC;
  48.         return *this;
  49.     }
  50.  
  51.     variant_t const & operator = (lcd_menu_t *menu)
  52.     {
  53.         (*this).value.menu = menu;
  54.         type = MENU;
  55.         return *this;
  56.     }
  57.  
  58.     variant_t const & operator = (int ival)
  59.     {
  60.         (*this).value.ival = ival;
  61.         type = INT;
  62.         return *this;
  63.     }
  64.  
  65. }; // variant_t
  66.  
  67. struct menu_t
  68. {
  69.     char      txt[17]{0};
  70.     variant_t value{0};
  71.     int       minv{0};
  72.     int       maxv{0};
  73.  
  74.     menu_t() : txt(""), value(0), minv(0), maxv(0) { }
  75.     menu_t(   void(*func)()) : txt(""), value(func), minv(0), maxv(0) { }
  76.     menu_t(lcd_menu_t *menu) : txt(""), value(menu), minv(0), maxv(0) { }
  77.     menu_t(           int n) : txt(""), value(   n), minv(0), maxv(0) { }
  78.  
  79.     menu_t(char const *t,            int n, int in = 0, int ax = 0) : value(   n), minv(in), maxv(ax) { strncpy(txt, t, sizeof(txt)); }
  80.     menu_t(char const *t,   void (*func)(), int in = 0, int ax = 0) : value(func), minv(in), maxv(ax) { strncpy(txt, t, sizeof(txt)); }
  81.     menu_t(char const *t, lcd_menu_t *menu, int in = 0, int ax = 0) : value(menu), minv(in), maxv(ax) { strncpy(txt, t, sizeof(txt)); }
  82. };
  83.  
  84. // the interface to update the display with the current menu
  85. using disp_fptr_t = void (*)(char const *,char const *);
  86.  
  87. // the interface to get menu input from the user
  88. // the user can input one of 6 choices: left, right, up, down, select, and cancel:
  89. enum choice_t { Invalid, Left, Right, Up, Down, Select, Cancel };
  90.  
  91. using input_fptr_t = choice_t (*)(char const *prompt);
  92.  
  93. struct lcd_menu_t
  94. {
  95.     menu_t      menu[2];
  96.     uint8_t     cur     : 1,    // the current menu choice
  97.                 use_num : 1;    // use numbers in menus when true
  98.     disp_fptr_t fptr{nullptr};  // the display update function
  99.  
  100.  
  101.     lcd_menu_t() : cur(0), use_num(false)
  102.     {
  103.         for (menu_t &entry : menu) {
  104.             entry.txt[0] = '\0';
  105.             entry.value = 0;
  106.             entry.minv = 0;
  107.             entry.maxv = 0;
  108.         }
  109.  
  110.     } // lcd_menu_t
  111.  
  112.     lcd_menu_t(menu_t m1, menu_t m2) : cur(0), use_num(false) {
  113.         menu[0] = m1;
  114.         menu[1] = m2;
  115.     }
  116.    
  117.    
  118.     lcd_menu_t(char *msg1, void(*func1)(), char *msg2, void(*func2)())
  119.     {
  120.         strncpy(menu[0].txt, msg1, sizeof(menu[0].txt));
  121.         menu[0].value = func1;
  122.         strncpy(menu[1].txt, msg2, sizeof(menu[1].txt));
  123.         menu[1].value = func2;
  124.  
  125.     } // lcd_menu_t
  126.  
  127.     lcd_menu_t(char *msg1, lcd_menu_t *menu1, char *msg2, lcd_menu_t *menu2)
  128.     {
  129.         strncpy(menu[0].txt, msg1, sizeof(menu[0].txt));
  130.         menu[0].value = menu1;
  131.         strncpy(menu[1].txt, msg2, sizeof(menu[1].txt));
  132.         menu[1].value = menu2;
  133.  
  134.     } // lcd_menu_t
  135.  
  136.     lcd_menu_t(char const *msg1, void(*func1)(), char const *msg2, void(*func2)())
  137.     {
  138.         strncpy(menu[0].txt, msg1, sizeof(menu[0].txt));
  139.         menu[0].value = func1;
  140.         strncpy(menu[1].txt, msg2, sizeof(menu[1].txt));
  141.         menu[1].value = func2;
  142.  
  143.     } // lcd_menu_t
  144.  
  145.     lcd_menu_t(char const *msg1, lcd_menu_t *menu1, char const *msg2, lcd_menu_t *menu2)
  146.     {
  147.         strncpy(menu[0].txt, msg1, sizeof(menu[0].txt));
  148.         menu[0].value = menu1;
  149.         strncpy(menu[1].txt, msg2, sizeof(menu[1].txt));
  150.         menu[1].value = menu2;
  151.  
  152.     } // lcd_menu_t
  153.  
  154.     int next()
  155.     {
  156.         return cur = !cur;
  157.  
  158.     } // next
  159.  
  160.     lcd_menu_t &exec() {
  161.         switch (menu[cur].value.type) {
  162.             case FUNC:
  163.                 if (menu[cur].value.value.func != nullptr) {
  164.                     menu[cur].value.value.func();
  165.                 }
  166.                 break;
  167.  
  168.             case MENU:
  169.                 if (menu[cur].value.value.menu != nullptr) {
  170.                     *this = *(menu[cur].value.value.menu);
  171.                 }
  172.                 break;
  173.  
  174.             case INT:
  175.                 break;
  176.         }
  177.  
  178.         return *this;
  179.  
  180.     } // exec
  181.  
  182.     lcd_menu_t &run(input_fptr_t inp, disp_fptr_t update) {
  183.         lcd_menu_t parents[8]{};
  184.         int parent = 0;
  185.         parents[parent] = *this;
  186.  
  187.         int orig = menu[cur].value.value.ival;
  188.         bool editing = false;
  189.  
  190.         do {
  191.             char line1[32] = "", line2[32] = "", buff[16];
  192.             strcpy(line1, use_num ? "1 " : "");
  193.             strcpy(line2, use_num ? "2 " : "");
  194.             strcat(line1, menu[0].txt);
  195.             strcat(line2, menu[1].txt);
  196.             if (menu[0].value.type == INT) {
  197.                 sprintf(buff, "%d", menu[0].value.value.ival);
  198.                 strcat(line1, buff);
  199.             }
  200.             if (menu[1].value.type == INT) {
  201.                 sprintf(buff, "%d", menu[1].value.value.ival);
  202.                 strcat(line2, buff);
  203.             }
  204.             strncat(0 == cur ? line1 : line2, "*", sizeof(line1));
  205.             update(line1, line2);
  206.  
  207.             if (editing) {
  208.                 choice_t choice = inp("U,D,S,C:");
  209.                 switch (choice) {
  210.                     case Up:
  211.                         if (menu[cur].value.value.ival < menu[cur].maxv)
  212.                             menu[cur].value.value.ival++;
  213.                         break;
  214.  
  215.                     case Down:
  216.                         if (menu[cur].value.value.ival > menu[cur].minv)
  217.                             menu[cur].value.value.ival--;
  218.                         break;
  219.  
  220.                     case Select:
  221.                         editing = false;
  222.                         break;
  223.  
  224.                     case Cancel:
  225.                         menu[cur].value.value.ival = orig;
  226.                         editing = false;
  227.                         break;
  228.  
  229.                     case    Left:
  230.                     case   Right:
  231.                     case Invalid:
  232.                         break;
  233.                 }
  234.  
  235.             } // editing
  236.             else {
  237.                 choice_t choice = inp("Choose:");
  238.                 switch (choice) {
  239.                     case Down:
  240.                     case   Up:
  241.                         next();
  242.                         break;
  243.  
  244.                     case Select:
  245.                         switch (menu[cur].value.type) {
  246.                             case INT:   // it has a value - edit it
  247.                                 orig = menu[cur].value.value.ival;
  248.                                 editing = true;
  249.                                 break;
  250.                             case MENU:  // it has a menu - switch to it
  251.                                 parents[parent++] = *this;
  252.                                 exec();
  253.                                 break;
  254.                             case FUNC:  // it has a function - call it
  255.                                 exec();
  256.                                 break;
  257.                         }
  258.                         break;
  259.  
  260.                     case Cancel:
  261.                         if (parent > 0) {
  262.                             *(parents[parent-1].menu[parents[parent-1].cur].value.value.menu) = *this;
  263.                             *this = parents[--parent];
  264.                         }
  265.                         break;
  266.  
  267.                     case    Left:
  268.                     case   Right:
  269.                     case Invalid:
  270.                         break;
  271.                 }
  272.  
  273.             } // !editing
  274.  
  275.         } while (true);
  276.  
  277.     } // run
  278.  
  279. };
  280.  
  281. #endif // MENU_H_INC
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement