📄 cursesd.cc
字号:
#ifdef UI_NCURSES/* * cursesd.cc (C) 1995 Ralf W. Stephan <ralf@ark.franken.de> * cursesd is derived from the dialog package * Original AUTHOR of dialog : Savio Lam (lam836@cs.cuhk.hk) * Stuart Herbert - S.Herbert@sheffield.ac.uk: radiolist extension * Alessandro Rubini - rubini@ipvvis.unipv.it: merged checklist/radio * Ralf W. Stephan <ralf@ark.franken.de> : merged checklist/menubox * * 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., 675 Mass Ave, Cambridge, MA 02139, USA. *///----------------------------------------------------------------------------// NOTE: The cursesd source doesn't use any of the menu- or form-functions// available with ncurses-1.9.4 and above. It better should, as these// libraries are very powerful and flexible. So PLEASE see cursesd as// an example what is possible without them, although a soon obsolete one. //// Also, there is a problem with the textbox/inputbox combo when having// input a search_string in textbox which I can't figure out. This// should easily disappear when we use forms for the inputbox. RWS//----------------------------------------------------------------------------#pragma implementation#include <unistd.h>#include <fcntl.h>#include <string.h>#include <ctype.h>#include "cursesd.h"/* * Attribute values, default is for mono display */static chtype attributes[] ={ A_NORMAL, /* screen_attr */ A_NORMAL, /* shadow_attr */ A_REVERSE, /* dialog_attr */ A_REVERSE, /* title_attr */ A_REVERSE, /* border_attr */ A_BOLD, /* button_active_attr */ A_DIM, /* button_inactive_attr */ A_UNDERLINE, /* button_key_active_attr */ A_UNDERLINE, /* button_key_inactive_attr */ A_NORMAL, /* button_label_active_attr */ A_NORMAL, /* button_label_inactive_attr */ A_REVERSE, /* inputbox_attr */ A_REVERSE, /* inputbox_border_attr */ A_REVERSE, /* searchbox_attr */ A_REVERSE, /* searchbox_title_attr */ A_REVERSE, /* searchbox_border_attr */ A_REVERSE, /* position_indicator_attr */ A_REVERSE, /* menubox_attr */ A_REVERSE, /* menubox_border_attr */ A_REVERSE, /* item_attr */ A_NORMAL, /* item_selected_attr */ A_REVERSE, /* tag_attr */ A_REVERSE, /* tag_selected_attr */ A_NORMAL, /* tag_key_attr */ A_BOLD, /* tag_key_selected_attr */ A_REVERSE, /* check_attr */ A_REVERSE, /* check_selected_attr */ A_REVERSE, /* uarrow_attr */ A_REVERSE /* darrow_attr */};/* * Table of color values */static int color_table[][3] ={ {6, 4, 1}, {0, 0, 1}, {0, 7, 0}, {3, 7, 1}, {7, 7, 1}, {7, 4, 1}, {0, 7, 0}, {7, 4, 1}, {1, 7, 0}, {3, 4, 1}, {0, 7, 1}, {0, 7, 0}, {0, 7, 0}, {0, 7, 0}, {3, 7, 1}, {7, 7, 1}, {3, 7, 1}, {0, 7, 0}, {7, 7, 1}, {0, 7, 0}, {7, 4, 1}, {3, 7, 1}, {3, 4, 1}, {1, 7, 1}, {1, 4, 1}, {0, 7, 0}, {7, 4, 1}, {2, 7, 1}, {2, 7, 1},};enum NCD_attr{ screen_attr=0, shadow_attr, dialog_attr, title_attr, border_attr, button_active_attr, button_inactive_attr, button_key_active_attr, button_key_inactive_attr, button_label_active_attr, button_label_inactive_attr, inputbox_attr, inputbox_border_attr, searchbox_attr, searchbox_title_attr, searchbox_border_attr, position_indicator_attr, menubox_attr, menubox_border_attr, item_attr, item_selected_attr, tag_attr, tag_selected_attr, tag_key_attr, tag_key_selected_attr, check_attr, check_selected_attr, uarrow_attr, darrow_attr, attribute_count };//----------------------------NCursesDialog------------------------------NCursesDialog::NCursesDialog (int x, int y, int h, int w, const char* t): NCursesPanel(h,w,y,x), height_(h), width_(w), str_max_len_(2048), title_(t){ keypad (TRUE); cbreak (); noecho (); color_setup (); draw_box (0,0,width_,height_,dialog_attr,border_attr,title_); refresh ();}NCursesDialog::~NCursesDialog(){ nocbreak(); leaveok(TRUE); echo();}//-----------------------------private------------------------------------static inline chtype a (NCD_attr att) { return attributes[att]; }/* * Setup for color display */void NCursesDialog::color_setup (){ if (!has_colors ()) return; start_color (); /* Initialize color pairs */ for (int i = 0; i < attribute_count; i++) init_pair (i + 1, color_table[i][0], color_table[i][1]); /* Setup color attributes */ for (int i = 0; i < attribute_count; i++) attributes[i] = (color_table[i][2]? A_BOLD : 0) | COLOR_PAIR(i + 1);}//----------------------------protected------------------------------------/* * Draw a rectangular box with line drawing characters */// Could be optimized by first clear()ing then walking around the box. RWS//void NCursesDialog::draw_box (int x, int y, int w, int h, int i, int o, const char* title=0){ const chtype border = a(NCD_attr(o)); const chtype box = a(NCD_attr(i)); attrset (0); for (int i = 0; i < h; i++) { move (i+y,x); for (int j = 0; j < w; j++) if (!i && !j) addch (border | ACS_ULCORNER); else if (i == h - 1 && !j) addch (border | ACS_LLCORNER); else if (!i && j == w - 1) addch (box | ACS_URCORNER); else if (i == h - 1 && j == w - 1) addch (box | ACS_LRCORNER); else if (!i) addch (border | ACS_HLINE); else if (i == h - 1) addch (box | ACS_HLINE); else if (!j) addch (border | ACS_VLINE); else if (j == w - 1) addch (box | ACS_VLINE); else addch (box | ' '); } if (title) { attrset (a(title_attr)); move (0,(w-strlen(title_))/2-1); addstr (title); }}/* * Print a string of text in a window, automatically wrap around to the * next line if the string is too long to fit on one line. Note that the * string may contain "\n" to represent a newline character or the real * newline '\n', but in that case, auto wrap around will be disabled. */void NCursesDialog::print_autowrap (const char *prompt, int width, int y, int x){ if (strlen(prompt) >= str_max_len_) { cerr << "NCursesDialog::str_max_len_ exceeded.\n"; exit(1); } // throw char tempstr [str_max_len_ + 1]; strcpy (tempstr, prompt); if (strstr (tempstr, "\\n") || strchr (tempstr, '\n')) { // Prompt contains "\n" or '\n' char* word = tempstr; int cur_y = y; move (cur_y, x); while (1) { char* bnl_pos = strstr (word, "\\n"); char* nl_pos = strchr (word, '\n'); if (!bnl_pos && !nl_pos) break; else if (!bnl_pos) { // No more "\n" bnl_pos = nl_pos; *bnl_pos = '\0'; } else if (!nl_pos) *bnl_pos++ = '\0'; // No more '\n' else { // Prompt contains both "\n" and '\n' if (strlen(bnl_pos) <= strlen(nl_pos)) { bnl_pos = nl_pos; *bnl_pos = '\0'; } else *bnl_pos++ = '\0'; } addstr (word); word = bnl_pos + 1; move (++cur_y, x); } addstr (word); } else if (strlen (tempstr) <= width - x * 2) { // If prompt is short move (y, (width - strlen (tempstr)) / 2); addstr (tempstr); } else { int cur_x = x, cur_y = y; // Print prompt word by word, wrap bool first = true; // around if necessary char *word; while ((word = strtok (first ? tempstr : 0, " ")) != 0) { if (first) // First iteration first = 0; if (cur_x + strlen (word) > width) { cur_y++; // wrap to next line cur_x = x; } move (cur_y, cur_x); addstr (word); getyx (cur_y, cur_x); cur_x++; } }}void NCursesDialog::button_bar(){ attrset (a(border_attr)); move (height_ - 3, 0); addch (ACS_LTEE); for (int i = 0; i < width_ - 2; i++) addch (ACS_HLINE); attrset (a(dialog_attr)); addch (ACS_RTEE); move (height_ - 2, 1); for (int i = 0; i < width_ - 2; i++) addch (' ');}/* * Print a button */void NCursesDialog::print_button (const char *label, int y, int x, bool selected){ move (y, x); attrset (selected ? a(button_active_attr) : a(button_inactive_attr)); addstr ("<"); int temp = strspn (label, " "); label += temp; attrset (selected ? a(button_label_active_attr) : a(button_label_inactive_attr)); for (int i = 0; i < temp; i++) addch (' '); attrset (selected ? a(button_key_active_attr) : a(button_key_inactive_attr)); addch (label[0]); attrset (selected ? a(button_label_active_attr) : a(button_label_inactive_attr)); addstr (label + 1); attrset (selected ? a(button_active_attr) : a(button_inactive_attr)); addstr (">"); move (y, x + temp + 1);}//---------------------------NCmsgbox-------------------------------/* * Display a message box. Program will pause and display an "OK" button * if the parameter 'pause' is non-zero. */NCmsgbox::NCmsgbox (const char *title, const char *prompt, int x, int y, int height, int width, bool pause=true): NCursesDialog (x,y,height,width,title){ keypad (TRUE); attrset(a(dialog_attr)); print_autowrap (prompt, width - 2, 1, 2); if (pause) { button_bar(); print_button (" OK ", height - 2, width / 2 - 4, true); } refresh();}NCmsgbox::~NCmsgbox() {}bool NCmsgbox::getkey(){ int key=0; while (key != 0x1b && key != 0x0d && key != ' ') key = getch (); return key != 0x1b;}//-----------------------------NCyesno---------------------------------/* * Display a dialog box with two buttons - Yes and No */NCyesno::NCyesno (const char *title, const char *prompt, int x, int y, int height, int width): NCursesDialog (x,y,height,width,title){ keypad (TRUE); button_bar(); attrset(a(dialog_attr)); print_autowrap (prompt, width - 2, 1, 3); int x = width / 2 - 10; int y = height - 2; print_button (" No ", y, x + 13, FALSE); print_button (" Yes ", y, x, TRUE); refresh (); int button = 0; while (1) { key_ = getch (); switch (key_) { case 'Y': case 'y': key_=0; return; case 'N': case 'n': key_=1; return; case 0x09: case KEY_UP: case KEY_DOWN: case KEY_LEFT: case KEY_RIGHT: if (!button) { button = 1; /* "No" button selected */ print_button (" Yes ", y, x, FALSE); print_button (" No ", y, x + 13, TRUE); } else { button = 0; /* "Yes" button selected */ print_button (" No ", y, x + 13, FALSE); print_button (" Yes ", y, x, TRUE); } refresh (); break; case ' ': case 0x0a: case 0x0d: key_=button; return; case 0x1b: key_=-1; return; } }}NCyesno::~NCyesno() {}//==========================NCchecklist======================================NCchecklist::NCchecklist (const char *title, const char *prompt, int x, int y, int height, int width, int list_height, int item_no, const char * const * items, bool radio_flag=false, bool menu_flag=false) : NCursesDialog (x,y,height,width,title), list_(0){ int key = 0, button = 0, choice = -1, scroll = 0; int status [item_no]; choices_ = new bool[item_no]; for (int i = 0; i < item_no; i++) { bool b = !strcasecmp (items[i * 3 + 2], "on"); choices_[i] = b; status[i] = b; if (choices_[i] && choice<0) choice_ = choice = i; } if (!radio_flag && !menu_flag) choice_ = choice = 0; int max_choice = list_height <? item_no; keypad (TRUE); button_bar(); attrset (a(dialog_attr)); print_autowrap (prompt, width - 2, 1, 3); int list_width = width - 6; int cur_x, cur_y; getyx (cur_y, cur_x); int box_y = cur_y + 1; int box_x = (width - list_width) / 2 - 1; /* create new window for the list */ list_ = new NCursesWindow (*this, list_height, list_width, y + box_y + 1, x + box_x + 1); list_->keypad (TRUE); /* draw a box around the list items */ draw_box (box_x, box_y, list_width + 2, list_height + 2, menubox_border_attr, menubox_attr); check_x = 0; item_x = 0; /* Find length of longest item in order to center checklist */ for (int i = 0; i < item_no; i++) { check_x = (check_x >? strlen (items[i * 3]) + strlen (items[i * 3 + 1]) + 6); item_x = (item_x >? strlen (items[i * 3])); } check_x = (list_width - check_x) / 2; item_x = check_x + item_x + 6; /* Print the list */ for (int i = 0; i < max_choice; i++) print_item (list_, items[i * 3], items[i * 3 + 1], status[i], i, i == choice, radio_flag, menu_flag); list_->noutrefresh (); if (list_height < item_no) { attrset (a(darrow_attr)); move (box_y + list_height + 1, box_x + check_x + 5); addch (ACS_DARROW); move (box_y + list_height + 1, box_x + check_x + 6); addstr ("(+)"); } x = width / 2 - 11; y = height - 2; print_button ("Cancel", y, x + 14, FALSE); print_button (" OK ", y, x, TRUE); refresh (); while (key != 0x1b) { key = getch (); /* Check if key pressed matches first character of any item tag in list */ int tmp=max_choice; for (int i = 0; i < max_choice; i++) if (toupper (key) == toupper (items[(scroll + i) * 3][0])) { tmp=i; break; } if (tmp < max_choice || (key >= '1' && key <= ('9' <? ('0' + max_choice))) || key == KEY_UP || key == KEY_DOWN || key == ' ' || key == '+' || key == '-' ) { if (key >= '1' && key <= ('9' <? ('0' + max_choice))) tmp = key - '1'; else if (key == KEY_UP || key == '-') { if (!choice) { if (!scroll) continue; /* Scroll list down */ getyx (cur_y, cur_x); if (list_height > 1) { /* De-highlight current first item */ print_item (list_, items[scroll * 3], items[scroll * 3 + 1], status[scroll], 0, FALSE, radio_flag, menu_flag); list_->scrollok (TRUE); list_->scrl (-1); list_->scrollok (FALSE); } scroll--;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -