2017年3月19日星期日

A simple program with NCURSES panel and menu libraries

The HTML Version codes was generated by CodeColorizer.

#include <ncurses.h>
#include <menu.h>
#include <panel.h>
#include <stdlib.h>
#include <string.h>

#define COLOR_MAIN_SCREEN           1

#define MENU_MARKER                 "->"

#define TOTAL_MENU_WINDOWS          1

#define MENU_INDEX_MAIN             0

typedef struct _menu_window_data_ {
    WINDOW          *win;
    MENU            *menu;
    PANEL           *panel;
    ITEM            **item_list;
    int             total_items;
} MENU_WIN_DATA;

MENU_WIN_DATA menu_window_list[TOTAL_MENU_WINDOWS];

void move_to_center(MENU_WIN_DATA *win_data) {
    int     width, height;
    int     scr_width, scr_height;
    
    getmaxyx(stdscr, scr_height, scr_width);
    getmaxyx(win_data->win, height, width);
    
    move_panel(win_data->panel, (scr_height - height) / 2, (scr_width - width) / 2);    
}

void hide_menu_window(MENU_WIN_DATA *win_data) {
    hide_panel(win_data->panel);    
}

void show_menu_window(MENU_WIN_DATA *win_data) {
    show_panel(win_data->panel);    
}

void create_menu_window(MENU_WIN_DATA *win_data, const char **menu_content, int total_items) {    
    win_data->total_items = total_items;
    
    // create a menu    
    win_data->item_list = (ITEM**)calloc(win_data->total_items + 1, sizeof(ITEM*));
    
    int width = 0;
    
    for(int i=0; i<win_data->total_items; i++) {
        win_data->item_list[i] = new_item(menu_content[i], "");
        int len = strlen(menu_content[i]);
        if(len > width) {
            width = len;
        }
    } // i loop
    win_data->item_list[win_data->total_items] = (ITEM*)NULL;
    
    win_data->menu = new_menu(win_data->item_list);
    set_menu_mark(win_data->menu, MENU_MARKER);    
    width += strlen(MENU_MARKER);
    
    // create a window for the menu
    win_data->win = newwin(win_data->total_items + 2, width + 2, 0, 0);
    keypad(win_data->win, TRUE);
    box(win_data->win, 0, 0);
    
    // create a panel for the window
    win_data->panel = new_panel(win_data->win);
            
    // assign the window to the menu
    set_menu_win(win_data->menu, win_data->win);
    set_menu_sub(win_data->menu, derwin(win_data->win, win_data->total_items + 1, width, 1, 1));
    
    // show the menu    
    post_menu(win_data->menu);    
}

void cleanup_menu_window(MENU_WIN_DATA *win_data) {
    del_panel(win_data->panel);
    
    unpost_menu(win_data->menu);
    free_menu(win_data->menu);

    for(int i=0; i<win_data->total_items; i++) {
        free_item(win_data->item_list[i]);
    }
    
    free(win_data->item_list);
    
    delwin(win_data->win);
    
    win_data->win = 0;
    win_data->panel = 0;
    win_data->menu = 0;
    win_data->item_list = 0;
    win_data->total_items = 0;
}

void cleanup_menu_windows() {
    
    for(int i=0; i<TOTAL_MENU_WINDOWS; i++) {
        cleanup_menu_window(&menu_window_list[i]);
    } // i loop
}

int main() {
    initscr();
    
    cbreak();
    noecho();
    raw();
    keypad(stdscr, TRUE);   // enable function keys
    curs_set(0);            // hide the cursor
    
    if(has_colors()) {
        start_color();
        
        init_pair(COLOR_MAIN_SCREEN, COLOR_WHITE, COLOR_BLUE);
        
        bkgd(COLOR_PAIR(COLOR_MAIN_SCREEN) | '.');
    }
    
    const char *main_menu_content[] = { "Item #1", "Item #2", "Exit" };
    
    create_menu_window(&menu_window_list[MENU_INDEX_MAIN], main_menu_content, 3);
    move_to_center(&menu_window_list[MENU_INDEX_MAIN]);
    
    // input loop
    int current_selection = 0;
    int run_flag = 1;
    int c;
    
    do {
        // display panels
        update_panels();
        doupdate();
        
        // get user's input
        c = getch();
        
        switch(c) {
        case KEY_UP:
            if(current_selection > 0) {
                menu_driver(menu_window_list[MENU_INDEX_MAIN].menu, REQ_UP_ITEM);
                current_selection--;
            }
            break;
        case KEY_DOWN:
            if(current_selection < menu_window_list[MENU_INDEX_MAIN].total_items - 1) {
                menu_driver(menu_window_list[MENU_INDEX_MAIN].menu, REQ_DOWN_ITEM);
                current_selection++;
            }
            break;
        case 10:    // Enter key
        {            
            if(current_selection == menu_window_list[MENU_INDEX_MAIN].total_items - 1) {
                // Exit
                run_flag = 0;
            }
        }
            break;
        default:            
            break;
        }
    } while(run_flag);
    
    cleanup_menu_windows();
    
    endwin();
    return 0;
}