📄 formbox.c
字号:
/* * $Id: formbox.c,v 1.26 2003/11/26 18:52:30 tom Exp $ * * formbox.c -- implements the form (i.e, some pairs label/editbox) * * AUTHOR: Valery Reznic (valery_reznic@users.sourceforge.net) * and: Thomas E. Dickey * * 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. */#include "dialog.h"#define LLEN(n) ((n) * FORMBOX_TAGS)#define ItemName(i) items[LLEN(i) + 0]#define ItemNameY(i) items[LLEN(i) + 1]#define ItemNameX(i) items[LLEN(i) + 2]#define ItemText(i) items[LLEN(i) + 3]#define ItemTextY(i) items[LLEN(i) + 4]#define ItemTextX(i) items[LLEN(i) + 5]#define ItemTextFLen(i) items[LLEN(i) + 6]#define ItemTextILen(i) items[LLEN(i) + 7]#define ItemHelp(i) (dialog_vars.item_help ? items[LLEN(i) + 8] : "")typedef struct { char *name; /* the field label */ int name_len; /* ...its length */ int name_y; /* ...its y-ordinate */ int name_x; /* ...its x-ordinate */ char *text; /* the field contents */ int text_len; /* ...its length on the screen */ int text_y; /* ...its y-ordinate */ int text_x; /* ...its x-ordinate */ int text_flen; /* ...its length on screen, or 0 if no input allowed */ int text_ilen; /* ...its limit on amount to be entered */ char *help; /* help-message, if any */} FORM_ELT;static boolin_window(WINDOW *win, int scrollamt, int y){ return (y >= scrollamt && y - scrollamt < getmaxy(win));}static boolok_move(WINDOW *win, int scrollamt, int y, int x){ return in_window(win, scrollamt, y) && (wmove(win, y - scrollamt, x) != ERR);}/* * Print form item */static intprint_item(WINDOW *win, FORM_ELT * elt, int scrollamt, bool choice){ int count = 0; int len; if (ok_move(win, scrollamt, elt->name_y, elt->name_x)) { len = elt->name_len; len = MIN(len, getmaxx(win) - elt->name_x); if (len > 0) { wattrset(win, menubox_attr); (void) wprintw(win, "%-*s", len, elt->name); count = 1; } } if (elt->text_flen && ok_move(win, scrollamt, elt->text_y, elt->text_x)) { len = elt->text_flen; len = MIN(len, getmaxx(win) - elt->text_x); if (len > 0) { wattrset(win, choice ? form_active_text_attr : form_text_attr); (void) wprintw(win, "%-*s", len, elt->text); count = 1; } } return count;}/* * Print the entire form. */static voidprint_form(WINDOW *win, FORM_ELT * elt, int total, int scrollamt, int choice){ int n; int count = 0; for (n = 0; n < total; ++n) { count += print_item(win, elt + n, scrollamt, n == choice); } if (count) { wbkgdset(win, menubox_attr); wclrtobot(win); (void) wnoutrefresh(win); }}static intset_choice(FORM_ELT elt[], int choice, int item_no){ int i; if (elt[choice].text_flen > 0) return choice; for (i = 0; i < item_no; i++) { if (elt[i].text_flen > 0) return i; } dlg_exiterr("No field has flen > 0\n"); return -1; /* Dummy, to make compiler happy */}/* * Find the last y-value in the form. */static intform_limit(FORM_ELT elt[]){ int n; int limit = 0; for (n = 0; elt[n].name != 0; ++n) { if (limit < elt[n].name_y) limit = elt[n].name_y; if (limit < elt[n].text_y) limit = elt[n].text_y; } return limit;}/* * Tab to the next field. */static booltab_next(WINDOW *win, FORM_ELT elt[], int item_no, int stepsize, int *choice, int *scrollamt){ int old_choice = *choice; int old_scroll = *scrollamt; bool wrapped = FALSE; do { *choice += stepsize; if (*choice < 0) { *choice = item_no - 1; wrapped = TRUE; } if (*choice >= item_no) { *choice = 0; wrapped = TRUE; } if (elt[*choice].text_flen > 0) { int lo = MIN(elt[*choice].name_y, elt[*choice].text_y); int hi = MAX(elt[*choice].name_y, elt[*choice].text_y); if (old_choice == *choice) break; print_item(win, elt + old_choice, *scrollamt, FALSE); if (*scrollamt < lo + 1 - getmaxy(win)) *scrollamt = lo + 1 - getmaxy(win); if (*scrollamt > hi) *scrollamt = hi; /* * If we have to scroll to show a wrap-around, it does get * confusing. Just give up rather than scroll. Tab'ing to the * next field in a multi-column form is a different matter. Scroll * for that. */ if (*scrollamt != old_scroll) { if (wrapped) { beep(); *scrollamt = old_scroll; *choice = old_choice; } else { scrollok(win, TRUE); wscrl(win, *scrollamt - old_scroll); scrollok(win, FALSE); } } break; } } while (*choice != old_choice); return (old_choice != *choice) || (old_scroll != *scrollamt);}/* * Scroll to the next page, putting the choice at the first editable field * in that page. Note that fields are not necessarily in top-to-bottom order, * nor is there necessarily a field on each row of the window. */static boolscroll_next(WINDOW *win, FORM_ELT elt[], int stepsize, int *choice, int *scrollamt){ int old_choice = *choice; int old_scroll = *scrollamt; int old_row = MIN(elt[old_choice].text_y, elt[old_choice].name_y); int target = old_scroll + stepsize; int n; if (stepsize < 0) { if (old_row != old_scroll) target = old_scroll; else target = old_scroll + stepsize; if (target < 0) target = 0; } else { int limit = form_limit(elt); if (target > limit) target = limit; } for (n = 0; elt[n].name != 0; ++n) { if (elt[n].text_flen > 0) { int new_row = MIN(elt[n].text_y, elt[n].name_y); if (abs(new_row - target) < abs(old_row - target)) { old_row = new_row; *choice = n; } } } if (old_choice != *choice) print_item(win, elt + old_choice, *scrollamt, FALSE); *scrollamt = *choice; if (*scrollamt != old_scroll) { scrollok(win, TRUE); wscrl(win, *scrollamt - old_scroll); scrollok(win, FALSE); } return (old_choice != *choice) || (old_scroll != *scrollamt);}static FORM_ELT *init_fe(char **items, int item_no, int *min_height, int *min_width){ FORM_ELT *elt; int i; int min_w = 0; int min_h = 0; /* * Note that elt[item_no].name is null, since we allocate an extra item. */ elt = (FORM_ELT *) calloc(item_no + 1, sizeof(FORM_ELT)); assert_ptr(elt, "dialog_form"); for (i = 0; i < item_no; ++i) { int name_y = atoi(ItemNameY(i)); int name_x = atoi(ItemNameX(i)); int name_len = strlen(ItemName(i)); int text_y = atoi(ItemTextY(i)); int text_x = atoi(ItemTextX(i)); int text_flen = atoi(ItemTextFLen(i)); int text_ilen = atoi(ItemTextILen(i)); /* * Special value '0' for text_flen: no input allowed * Special value '0' for text_ilen: 'be as text_flen' */ if (text_ilen == 0) text_ilen = text_flen; if (text_flen != 0 && text_flen < text_ilen) text_ilen = MIN(text_ilen, text_flen); min_h = MAX(min_h, name_y); min_h = MAX(min_h, text_y); min_w = MAX(min_w, name_x + name_len); min_w = MAX(min_w, text_x + text_flen); elt[i].name = ItemName(i); elt[i].name_len = strlen(elt[i].name); elt[i].name_y = name_y - 1; elt[i].name_x = name_x - 1; elt[i].text = ItemText(i); elt[i].text_len = (elt[i].text_flen ? elt[i].text_flen : (int) strlen(elt[i].text)); elt[i].text_y = text_y - 1; elt[i].text_x = text_x - 1; elt[i].text_flen = text_flen; elt[i].text_ilen = text_ilen; elt[i].help = ItemHelp(i); if (text_flen > 0) { elt[i].text = malloc(text_ilen + 1); assert_ptr(elt[i].text, "dialog_form"); sprintf(elt[i].text, "%.*s", text_ilen, ItemText(i)); } } *min_height = min_h; *min_width = min_w; return elt;}/* * Display a form for fulfill a number of fields */intdialog_form(const char *title, const char *cprompt, int height, int width, int form_height, int item_no, char **items){#define sTEXT -1 int form_width;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -