 #define MENU_BG2            ILI9341_BLACK
 #define MENU_FG             ILI9341_BLACK
 
+// constants for the menu system
+#define MENUITEM_HEIGHT     35
+#define MAXMENUITEMROWS     5
+
+// macro to get number of elements in an array
+#define ALEN(a)    (sizeof(a)/sizeof((a)[0]))
+
 // the VFO states
 enum VFOState
 {

}

//-----------------------------------------------
// Setup the whole shebang.
//-----------------------------------------------
void setup(void)
{
  Serial.begin(115200);

  // read touch position, add DOWN event to event queue
  ts_read(&last_x, &last_y);
  event_push(event_Down, last_x, last_y);
}

//////////////////////////////////////////////////////////////////////////////
// Code to handle the PixelVFO menus
//////////////////////////////////////////////////////////////////////////////

// handler for selection of an item
typedef void (*ItemAction)(struct Menu *, int);

// structure defining a menu item
struct MenuItem
{
  const char *title;          // menu item display text
  struct Menu *menu;          // if not NULL, submenu to pass to show_menu()
  ItemAction action;          // if not NULL, address of action function
};

// A structure defining a menu
struct Menu
{
  const char *title;          // title displayed on menu page
  int num_items;              // number of items in the array below
  struct MenuItem **items;    // array of pointers to MenuItem data
};

//----------------------------------------
// dump a MenuItem to the console
// only called from dump_menu()
//----------------------------------------

void dump_menuitem(struct MenuItem *menuitem)
{
  Serial.printf(F("  menuitem address=%08x\n"), menuitem);
  Serial.printf(F("  title=%s\n"), menuitem->title);
  Serial.printf(F("  menu=%08x\n"), menuitem->menu);
  Serial.printf(F("  action=%08x\n"), menuitem->action);
}

//----------------------------------------
// dump a Menu and contained MenuItems to the console
//----------------------------------------

void dump_menu(const char *msg, struct Menu *menu)
{
  Serial.printf(F("----------------- Menu --------------------\n"));
  Serial.printf(F("%s\n"), msg);
  Serial.printf(F("menu address=%08x\n"), menu);
  Serial.printf(F("  title=%s\n"), menu->title);
  Serial.printf(F("  num_items=%d\n"), menu->num_items);
  Serial.printf(F("  items address=%08x\n"), menu->items);
  
  for (int i = 0; i < menu->num_items; ++i)
    dump_menuitem(menu->items[i]);
    
  Serial.printf(F("^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n"));
}

//----------------------------------------
// Handle the menu 'BACK' hotspot.
//     pointer to the hotspot we are actioning
//     arg     the integer arg from the menu handler
//----------------------------------------

bool hs_menuback_handler(HotSpot *hs, int arg)
{
  
}

//----------------------------------------
// Handle the menu 'select menuitem' hotspot
//     pointer to the hotspot we are actioning
//     row     index number of the menuitem row selected
//----------------------------------------

bool hs_menuitem_handler(HotSpot *hs, int row)
{
  
}

//----------------------------------------
// Draw a menu on the screen.
//     menu  pointer to a Menu structure
// Only draws the top row.
//----------------------------------------

void menu_draw(struct Menu *menu)
{
  // clear screen and write menu title on upper row
#if 0
  tft.clear();
  tft.setCursor(0, 0);
  tft.print(menu->title);
#endif
}

//----------------------------------------
// Draw a standard menuitem on the screen.
//     menu      pointer to a Menu structure
//     item_num  the item number to show
//     row       menu row to draw menuitem on
// Custome menuitems are drawn by their handler.
//----------------------------------------

void menuitem_draw(struct Menu *menu, int item_num, int row)
{
  // figure out max length of item strings
  int max_len = 0;
  int row_offset = MENUITEM_HEIGHT*row;

  for (int i = 0; i < menu->num_items; ++ i)
  {
    int16_t x1;
    int16_t y1;
    uint16_t w;
    uint16_t h;
    
    tft.getTextBounds((char *) menu->items[i]->title, 30, 30, &x1, &y1, &w, &h);

    if (w > max_len)
        max_len = w;
  }

  // write indexed item on lower row, right-justified
  tft.fillRect(0, 2, ts_width, DEPTH_FREQ_DISPLAY+row_offset, SCREEN_BG);
  
  tft.setCursor(max_len, DEPTH_FREQ_DISPLAY+row_offset);
  tft.print(menu->items[item_num]->title);
}

// menu HotSpot definitions
HotSpot hs_menu[] =
{
  {0, 0, ts_width, DEPTH_FREQ_DISPLAY, hs_menuback_handler, 0},
  {0, DEPTH_FREQ_DISPLAY+MENUITEM_HEIGHT*0, ts_width, MENUITEM_HEIGHT, hs_menuitem_handler, 0},
  {0, DEPTH_FREQ_DISPLAY+MENUITEM_HEIGHT*1, ts_width, MENUITEM_HEIGHT, hs_menuitem_handler, 1},
  {0, DEPTH_FREQ_DISPLAY+MENUITEM_HEIGHT*2, ts_width, MENUITEM_HEIGHT, hs_menuitem_handler, 2},
  {0, DEPTH_FREQ_DISPLAY+MENUITEM_HEIGHT*3, ts_width, MENUITEM_HEIGHT, hs_menuitem_handler, 3},
  {0, DEPTH_FREQ_DISPLAY+MENUITEM_HEIGHT*4, ts_width, MENUITEM_HEIGHT, hs_menuitem_handler, 4},
};  
//----------------------------------------
// Handle a menu.
//     menu      pointer to a defining Menu structure
//
// Handle events in the loop here.
// This code doesn't see events handled in any *_action() routine.
//----------------------------------------

void menu_show(struct Menu *menu)
{
  int item_num = 0;     // index of the menuitem to show

  // draw the menu page
  menu_draw(menu);
  for (int row = 0; row < min(MAXMENUITEMROWS, menu->num_items); ++row)
  {
      menuitem_draw(menu, item_num, row);
  }

  // get rid of any stray events to this point
  event_flush();

  while (true)
  {
    // handle any pending event
    if (event_pending() > 0)
    {
      // get next event and handle it
      VFOEvent *event = event_pop();
      Serial.printf(F("menu_show loop: event=%s\n"), event2display(event));

      switch (event->event)
      {
        case event_Down:
          Serial.printf(F("Event %s\n"), event2display(event));
          if (hs_handletouch(event->x, event->y, hs_menu, MenuHSLen))
          {
            Serial.printf(F("hs_handletouch() returned 'true', refreshing display\n"));
            draw_screen();
            freq_show();
            //event_flush();
          }
          break;
        case event_None:
          return;
        default:
          abort("Unrecognized event!?");
      }
    }
  }
}

//----------------------------------------
// Show that *something* happened.
// Flash the screen in a possibly eye-catching way.
//----------------------------------------

void display_flash(void)
{
  Serial.printf("display_flash: called\n");
}

//////////////////////////////////////////////////////////////////////////////
