Multi-Level Menu Construction Method Based on C Language

1. Task Entry

static void task_ui(void){    // Display this page    // Use Page function to find the page and call the disp function of that page.    PageV( "idle" )->disp( NULL );    while(1)    {        // Use Page function to find the page and call the run function of that page.        Page( "idle" )->run( NULL,PNULL );        vTaskDelay(100);    }}

2. Create a UI Task

static TaskHandle_t task_ui_Handle = NULL;/* Create listener handle */void do_create_ui_task(void){    BaseType_t xReturn = pdPASS;/* Define a return value for creation information, default is pdPASS */    /* Create AppTaskCreate task */    xReturn = thread_create(task_ui, "task_ui", 1024, NULL, 2,    &task_ui_Handle);    if(pdPASS == xReturn)    {        printf("do_create_ui_task success! \r\n");    }    else    {        printf("Error:do_create_ui_task! \r\n");    }        printf("do_create_ui_task \t:mem_get_free -> %d B \r\n",mem_get_free());}

Note: The above task is called in the task scheduler.3. Organize Page Structure and Attributes

typedef struct PageAction {    char* name; // Page name    void (*run)(uint8_t dat,uint8_t *ch); // Page call (including display call)    void (*disp)(uint8_t mouse); // Display call (provided to other files to display the page)    uint8_t (*get_input_event)(void); // Get input event    uint8_t mouse; // General cursor descriptor}page_t;

4. Construct and Fill a Page

Below is a background setting screen for a gaming machine device(the idle page:(The screen isLCD12864)

/*-------------------------------------------------------------------------------*/// Display English interfacestatic void disp_english(uint8_t mouse ){  lcd->line1(" welcome ");  lcd->line2(" ");  lcd->line3("MENU -> setting");  lcd->line4("Back -> clear error");}// Display Chinese interfacestatic void disp_chinese(uint8_t mouse ){  lcd->line1(" 欢迎使用 ");  lcd->line2(" ");  lcd->line3("菜单 -> 设置");  lcd->line4("返回 -> 清错");}// Display functionstatic void disp(uint8_t mouse){  uint8_t language = gamedat[_P1_]->language;  if( language == Chinese )    disp_chinese( mouse );  else    disp_english( mouse );}/*-------------------------------------------------------------------------*/// Get input eventstatic uint8_t get_input_event(void){  return get_keyboard_event();}/*-------------------------------------------------------------------------*/// Page call (including display call)static void run(u8 dat,u8 *ch){  extern void clr_err_tsmt_logic( uint8_t id );  extern void clr_err_score_to_gift( uint8_t road );  uint8_t ipEvent = get_input_event();  if( ipEvent == _key_none ) return ; // If there is no key event, exit this function  audio_1->req_play_file( _em_key ); // Request to play key sound  // Wait for key event, if it is the menu key, perform page depth adjustment  if( _key_menu == ipEvent )  {    // Notify all players to stop the game    suspend_game_logic();    // Enter deep page (select player id) (Note, the page is blocking)    PageV( "selt_item")->run( NULL,PNULL );    // Reset system    __set_FAULTMASK(1);    NVIC_SystemReset();  }  else if( _key_back == ipEvent )  {      // Notify all players to clear errors      for(uint8_t id=0;id<MAX_Road;id++)      {        clr_err_score_to_gift( id ); // Clear error - component - "Score Exchange Gift"        clr_err_tsmt_logic( id ); // Clear error - component - Ball Launcher      }      PRT_LOG("req clr_err \r\n");   }}/*--------------------------------------------------------------------------*/// The above functions are organized into a structurestatic page_t page = {  .name = "idle",  .run = run,  .disp = disp,  .get_input_event = get_input_event,  .mouse = 0,};page_t* idle_page = &page;

Other pages are also designed in this way, such as the above required jump to the“selt_item” page, its code is as follows:

/*-------------------------------------------------------------------------*/// Display Chinese interfacestatic void disp_chinese(uint8_t mouse){  static uint8_t color = 0;  uint8_t i = 0;  uint8_t id = 0 ;  lcd->line1(" 选择项目 ");  lcd->line2(" ");  switch( mouse )  {    case 0:lcd->line3(" <- P1 -> ");break;    case 1:lcd->line3(" <- P2 -> ");break;    case 2:lcd->line3(" <- P3 -> ");break;    case 3:lcd->line3(" <-查看数据-> ");break;    default:break;  }  lcd->line4(" ");}// Display English interfacestatic void disp_english(uint8_t mouse){  static uint8_t color = 0;  uint8_t i = 0;  uint8_t id = 0 ;  lcd->line1("Select entry: ");  lcd->line2(" ");  switch( mouse )  {    case 0:lcd->line3(" <- P1 -> ");break;    case 1:lcd->line3(" <- P2 -> ");break;    case 2:lcd->line3(" <- P3 -> ");break;    case 3:lcd->line3(" <-cat data -> ");break;    default:break;   }  lcd->line4(" ");}// Display interfacestatic void disp(uint8_t mouse){  if( gamedat[_P1_]->language == Chinese )     disp_chinese( mouse );  else    disp_english( mouse );}/*------------------------------------------------------------------------*/// Get input eventstatic uint8_t get_input_event(void){  return get_keyboard_event();}/*------------------------------------------------------------------------*/// Timed refresh displaystatic time_t otick = 0;static time_t ntick = 0;static void screen_tick( time_t tick ){  ntick = timtick->get();  if( tick >( ntick - otick ) ) return;   otick = ntick;  disp( page->mouse );}/*--------------------------------------------------------------------------*/// Page call (including display call)static void run(u8 dat,u8 *ch){  u8 ipEvent = 0;  this_page = &selt_item_page;  this_page->mouse = 0;  // suspend_seg_coroutine(); // Suspend digital tube  lcd->clr_screen();  PRT_LOG("_p_selt_id->run() \r\n ");  while(1)  {    // Timed refresh page display    screen_tick( 200 );    ipEvent = get_input_event();    if( ipEvent == _key_none ) continue;    audio_1->req_play_file( _em_key ); // Request to play key sound    switch( ipEvent )    {      case _key_up: // Increase parameter value      case _key_dn: // Decrease parameter value         mouse_move( this_page,ipEvent );         break;      case _key_menu:// Enter deep interface          do_key_menu( this_page,ipEvent );      break;      case _key_back://          goto __exit_page;          default:      break;}// Store datagdat_opt->data_store.write_player_data( _P1_,gamedat[_P1_] );gdat_opt->data_store.write_player_data( _P2_,gamedat[_P2_] );

The remaining pages will not be displayed.

5. Implement Page Manager

Organize these pages with an array:

// Declare external file pagesextern page_t* idle_page;extern page_t* selt_item_page;static page_t* page_list[]={  idle_page,  selt_item_page,  //...};

Implement a function to find the corresponding page from this array by name:

// Get the number of elements in the array#define ITEM_NUM(items) sizeof(items) / sizeof(items[0])page_t* Page( char* name ){
  page_t* page =NULL;  for( int i=0;i<(ITEM_NUM(page_list);i++ )  {    if( 0 == strncmp( name,page_list[i]->name ,strlen( page_list[i]->name ) ) )    {// Found, the string matches, found the corresponding page      page = page_list[i];      return page;    }  }  // If no corresponding page is found, return NULL   return NULL;}

Leave a Comment