📄 option_dialog.hpp
字号:
/* Copyright(c) Ben Bear 2004 */// This program is free software; you can redistribute it and/or// modify it under the terms of the GNU General Public License as// published by the Free Software Foundation; either version 2 of the// License, or (at your option) any later version.// // This program is distributed in the hope that it will be useful,// but WITHOUT ANY WARRANTY; without even the implied warranty of// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU// General Public License for more details.// // You should have received a copy of the GNU General Public License// along with this program; if not, write to the Free Software// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA// 02111-1307, USA.#ifndef __option_dialog_hpp#define __option_dialog_hpp#include <stdio.h>#include <string.h>#include <curses.h>class option_dialog{public: enum OPTION_TYPE { OPTION_RADIO, OPTION_CHECK }; private: struct OPTION { OPTION_TYPE type; const char *name; int name_len; const char **item; int item_h, item_w; int cur_item; int *value; int *tmp_val; WINDOW *box; int box_h, box_w; int box_y, box_x; }; static const int MAX_OPTIONS = 9; static const int MAX_PER_LINE = 3; static const int BOX_MIN_WIDTH = 20; static const int BOX_PRE_WIDTH = 5; static const int CHAR_RADIO = '*'; static const int CHAR_CHECK = 'x'; static const int BUTTON_OK = -1; static const int BUTTON_CANCEL = -2;private: WINDOW *dialog; int dlg_h, dlg_w; int scr_h, scr_w; const char *dlg_name; OPTION opt[MAX_OPTIONS]; int opt_num; int cur_opt; WINDOW *win_ok; WINDOW *win_cancel;public: option_dialog (const char* name) : dialog(0), dlg_name(name), opt_num(0) { getmaxyx (stdscr, scr_h, scr_w); } bool add (OPTION_TYPE type, const char* name, const char **item, int *value); bool show (); private: bool get_dialog_size (); bool new_dialog (); void new_option (int i); void del_dialog (); void show_item (bool on, int c_opt); void brower_item (int key); void select_item (); void get_value (); void set_value (bool set);};booloption_dialog::add (option_dialog::OPTION_TYPE type, const char* name, const char **item, int *value){ if ((opt_num >= MAX_OPTIONS) || ((type != OPTION_RADIO) && (type != OPTION_CHECK))) return false; OPTION& option = opt[opt_num++]; option.type = type; option.name = name; option.name_len = strlen (name); option.item = item; option.item_h = 0; option.item_w = 0; option.cur_item = 0; for (; *item != 0; ++item) { ++option.item_h; int len = strlen (*item); if (option.item_w < len) option.item_w = len; } option.value = value; option.tmp_val = 0; option.box = 0; option.box_h = option.item_h + 2; // two borders option.box_w = option.item_w + 2 + BOX_PRE_WIDTH; if (option.box_w < BOX_MIN_WIDTH) option.box_w = BOX_MIN_WIDTH; if (option.box_w < option.name_len + 4) option.box_w = option.name_len + 4; option.box_y = 0; option.box_x = 0; return true;}booloption_dialog::show (){ if (opt_num == 0) return false; get_value (); if (!new_dialog ()) { set_value (false); return false; } cur_opt = 0; for (int i = 0; i < opt_num; ++i) opt[i].cur_item = 0; show_item (true, cur_opt); int ch; do { ch = wgetch (dialog); switch (ch) { case KEY_UP: case KEY_DOWN: case KEY_LEFT: case KEY_RIGHT: case '\t': brower_item (ch); break; case ' ': select_item (); break; } if ((ch == '\n') && ((cur_opt == BUTTON_OK) || (cur_opt == BUTTON_CANCEL))) break; } while (true); del_dialog (); if (cur_opt == BUTTON_OK) { set_value (true); return true; } else { set_value (false); return false; }}booloption_dialog::new_dialog (){ int dlg_y, dlg_x; if (get_dialog_size() == false) return false; dlg_y = (scr_h - dlg_h) / 2; dlg_x = (scr_w - dlg_w) / 2; dialog = newwin (dlg_h, dlg_w, dlg_y, dlg_x); keypad (dialog, TRUE); box (dialog, 0, 0); mvwprintw (dialog, 0, (dlg_w - strlen(dlg_name)) / 2, " %s ", dlg_name); for (int i = 0; i < opt_num; ++i) new_option (i); win_ok = derwin (dialog, 1, 6, dlg_h-2, dlg_w/3-3); keypad (win_ok, TRUE); win_cancel = derwin (dialog, 1, 10, dlg_h-2, dlg_w/3*2-5); keypad (win_cancel, TRUE); mvwprintw (win_ok, 0, 0, "< OK >"); mvwprintw (win_cancel, 0, 0, "< Cancel >"); touchwin (dialog); wrefresh (dialog); return true;}booloption_dialog::get_dialog_size (){ int max_h, max_w; int cur_y, cur_x; int per_line = MAX_PER_LINE; if (opt_num == 4) per_line = 2; max_h = scr_h - 3; max_w = scr_w - 2; dlg_h = 0; dlg_w = 0; cur_y = 1; for (int i = 0; i < opt_num;) { int j = i; i += per_line; if (i > opt_num) i = opt_num; int max_line_h = 0; cur_x = 1; for (; j < i; ++j) { if (cur_x-1 + opt[j].box_w > max_w) { if (cur_x == 1) { opt[j].box_w = max_w; } else { // width overflow, new line i = j; break; } } opt[j].box_y = cur_y; opt[j].box_x = cur_x; cur_x += opt[j].box_w; if (max_line_h < opt[j].box_h) max_line_h = opt[j].box_h; } cur_y += max_line_h; if (dlg_w < cur_x-1) dlg_w = cur_x-1; } dlg_h = cur_y-1; dlg_h += 3; dlg_w += 2; if (dlg_w < 40) dlg_w = 40; if ((dlg_h <= max_h) && (dlg_w <= max_w)) return true; else return false;}voidoption_dialog::new_option (int i){ WINDOW *win = derwin (dialog, opt[i].box_h, opt[i].box_w, opt[i].box_y, opt[i].box_x); opt[i].box = win; keypad (win, TRUE); box (win, 0, 0); mvwprintw (win, 0, 1, " %s ", opt[i].name); char tmp[12]; sprintf (tmp, "%%-%ds", opt[i].box_w - 2 - BOX_PRE_WIDTH); for (int j = 0; j < opt[i].item_h; ++j) { mvwprintw (win, j+1, BOX_PRE_WIDTH+1, tmp, opt[i].item[j]); if (opt[i].type == OPTION_RADIO) { mvwprintw (win, j+1, 1, " ( ) "); if (*(opt[i].tmp_val) == j) mvwaddch (win, j+1, 3, CHAR_RADIO); } else if (opt[i].type == OPTION_CHECK) { mvwprintw (win, j+1, 1, "%s", " [ ] "); if ((opt[i].tmp_val)[j] == 1) mvwaddch (win, j+1, 3, CHAR_CHECK); } } touchwin (dialog); wrefresh (dialog);}voidoption_dialog::show_item (bool on, int c_opt){ WINDOW *win; int cur_y, cur_x, len; if (cur_opt >= 0) { win = opt[c_opt].box; cur_y = opt[c_opt].cur_item + 1; cur_x = BOX_PRE_WIDTH + 1; len = opt[c_opt].box_w - BOX_PRE_WIDTH - 2; mvwaddch (win, cur_y, cur_x-1, ' '); int type = on ? A_REVERSE : A_NORMAL; wchgat (win, len, type, 0, NULL); if (on) wmove (dialog, cur_y + opt[c_opt].box_y, opt[c_opt].box_x + 3); } else { cur_y = dlg_h-2; if (cur_opt == BUTTON_OK) { win = win_ok; cur_x = dlg_w/3-3; len = 6; } else { win = win_cancel; cur_x = dlg_w/3*2-5; len = 10; } int type = on ? A_REVERSE : A_NORMAL; wmove (win, 0, 0); wchgat (win, len, type, 0, NULL); if (on) wmove (dialog, cur_y, cur_x + 2); } touchwin (dialog); wrefresh (dialog);}voidoption_dialog::brower_item (int key){ show_item (false, cur_opt); if (cur_opt < 0) { if (key != '\t') { if (cur_opt == BUTTON_OK) cur_opt = BUTTON_CANCEL; else cur_opt = BUTTON_OK; } else { if (cur_opt == BUTTON_CANCEL) cur_opt = 0; else cur_opt = BUTTON_CANCEL; } } else { OPTION& op = opt[cur_opt]; switch (key) { case KEY_UP: if (op.cur_item > 0) --op.cur_item; else op.cur_item = op.item_h-1; break; case KEY_DOWN: if (op.cur_item < op.item_h-1) ++op.cur_item; else op.cur_item = 0; break; case KEY_LEFT: if (cur_opt == 0) cur_opt = opt_num-1; else --cur_opt; break; case KEY_RIGHT: if (cur_opt == opt_num-1) cur_opt = 0; else ++cur_opt; break; case '\t': if (cur_opt == opt_num-1) cur_opt = BUTTON_OK; else ++cur_opt; break; } } show_item (true, cur_opt);}voidoption_dialog::select_item (){ if (cur_opt < 0) return; WINDOW *win = opt[cur_opt].box; int cur_item = opt[cur_opt].cur_item; if (opt[cur_opt].type == OPTION_RADIO) { if (*opt[cur_opt].tmp_val == cur_item) return; mvwaddch (win, *opt[cur_opt].tmp_val+1, 3, ' '); *opt[cur_opt].tmp_val = cur_item; mvwaddch (win, cur_item+1, 3, CHAR_RADIO); } else if (opt[cur_opt].type == OPTION_CHECK) { opt[cur_opt].tmp_val[cur_item] = !opt[cur_opt].tmp_val[cur_item]; mvwaddch (win, cur_item+1, 3, opt[cur_opt].tmp_val[cur_item] ? CHAR_CHECK : ' '); } wmove (win, cur_item+1, 3); touchwin (dialog); wrefresh (dialog);}voidoption_dialog::del_dialog (){ for (int i = 0; i < opt_num; ++i) delwin (opt[i].box); delwin (win_ok); delwin (win_cancel); wclear (dialog); wrefresh (dialog); delwin (dialog); dialog = 0;}voidoption_dialog::get_value (){ for (int i = 0; i < opt_num; ++i) { int len; if (opt[i].type == OPTION_RADIO) len = 1; else if (opt[i].type == OPTION_CHECK) len = opt[i].item_h; opt[i].tmp_val = new int[len]; for (int j = 0; j < len; ++j) opt[i].tmp_val[j] = opt[i].value[j]; }}voidoption_dialog::set_value (bool set){ for (int i = 0; i < opt_num; ++i) { int len; if (opt[i].type == OPTION_RADIO) len = 1; else if (opt[i].type == OPTION_CHECK) len = opt[i].item_h; if (set) for (int j = 0; j < len; ++j) opt[i].value[j] = opt[i].tmp_val[j]; delete[] opt[i].tmp_val; opt[i].tmp_val = 0; }}#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -