// Unix terminal demo of weemenu. #include #include #include #include #include #include #include #include "weemenu.h" using std::cout; using std::cerr; using std::endl; using std::flush; const int stdin_fd = 1; int n = 0; bool done = false; // Super cheesy, but should be fine for now. struct my_noncurses { static void clear(void *) { cout << "\n\n\n\n\033[H\033[2J"; } static void print(void *, int y, const char *s) { if (-4 <= y && y <= 4) cout << s; } static void println(void *, int y, const char *line) { if (-4 <= y && y <= 4) cout << line << " \n"; } static void update(void *) { cout << flush; } }; template struct my_menu { static void main_tree(menu_t& m) { // Menu item actions: if (m.item("Increment")) n++; if (m.item("Decrement")) n--; // Dynamic menu item labels: char buf[12]; sprintf(buf, "n = %d", n); if (m.item(buf)) n = 0; // Nested menus: if (m.nest("Quit")) { if (m.item("Don't quit")) m.go_to_root(); if (m.item("Really quit")) done = true; m.end(); } // Arbitrarily nested menus, up to 8 levels: if (m.nest("Enter tunnel")) { if (m.nest("Open door")) { if (m.nest("Use key")) { m.item("Turn clockwise"); if (m.nest("Turn counterclockwise")) { if (m.item("You are home!")) m.go_to_root(); m.end(); } m.end(); } m.item("Use lock pick"); m.end(); } if (m.nest("Cross stream")) { if (m.item("You drowned.")) m.go_to_root(); m.end(); } m.end(); } // Dynamically generated menu items (but be careful! You can get // warped to some other menu if the structure of some menu up the // tree from you changes): if (m.nest("The N items")) { for (int i = 0; i < n; i++) { sprintf(buf, "item %d", i); m.item(buf); } m.end(); } if (m.item("n ← 100")) n = 100; m.end(); } }; void interact_with_menus() { weemenu >, 5> menu; while (!done) { menu.draw(); // This busywaits, checking the keyboard at 50Hz: char c; while (0 == read(stdin_fd, &c, 1)) usleep(20*1000); switch (c) { case 'h': case 'D': menu.left(); break; case 'j': case 'B': menu.down(); break; case 'k': case 'A': menu.up(); break; case 'l': case 'C': menu.right(); break; default: /* no op */ break; } } cout << "sizeof menu is " << sizeof(menu) << "\n"; } static void panic(const char *reason) { cerr << "panic: " << reason << endl; abort(); } /* because curses makes me curse; ganked from my actor.c */ static struct termios my_cbreak(int fd) { struct termios new_termios, old_termios; if (tcgetattr(fd, &old_termios) < 0) panic("tcgetattr"); new_termios = old_termios; new_termios.c_lflag &= ~(ECHO | ICANON); new_termios.c_cc[VMIN] = 0; new_termios.c_cc[VTIME] = 0; if (tcsetattr(fd, TCSANOW, &new_termios) < 0) panic("tcsetattr"); return old_termios; } int main(int argc, char **argv) { struct termios old_termios = my_cbreak(stdin_fd); interact_with_menus(); tcsetattr(stdin_fd, TCSANOW, &old_termios); return 0; }