1/**************************************************************************** 2 * Copyright (c) 2003-2006,2008 Free Software Foundation, Inc. * 3 * * 4 * Permission is hereby granted, free of charge, to any person obtaining a * 5 * copy of this software and associated documentation files (the * 6 * "Software"), to deal in the Software without restriction, including * 7 * without limitation the rights to use, copy, modify, merge, publish, * 8 * distribute, distribute with modifications, sublicense, and/or sell * 9 * copies of the Software, and to permit persons to whom the Software is * 10 * furnished to do so, subject to the following conditions: * 11 * * 12 * The above copyright notice and this permission notice shall be included * 13 * in all copies or substantial portions of the Software. * 14 * * 15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * 16 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * 17 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * 18 * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, * 19 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR * 20 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR * 21 * THE USE OR OTHER DEALINGS IN THE SOFTWARE. * 22 * * 23 * Except as contained in this notice, the name(s) of the above copyright * 24 * holders shall not be used in advertising or otherwise to promote the * 25 * sale, use or other dealings in this Software without prior written * 26 * authorization. * 27 ****************************************************************************/ 28/* 29 * $Id: edit_field.c,v 1.14 2008/10/18 20:40:20 tom Exp $ 30 * 31 * A wrapper for form_driver() which keeps track of the user's editing changes 32 * for each field, and makes the result available as a null-terminated string 33 * in field_buffer(field,1). 34 * 35 * Thomas Dickey - 2003/4/26. 36 */ 37 38#include <test.priv.h> 39 40#if USE_LIBFORM 41 42#include <edit_field.h> 43 44static struct { 45 int code; 46 int result; 47 const char *help; 48} commands[] = { 49 50 { 51 CTRL('A'), REQ_NEXT_CHOICE, "" 52 }, 53 { 54 CTRL('B'), REQ_PREV_WORD, "go to previous word" 55 }, 56 { 57 CTRL('C'), REQ_CLR_EOL, "clear to end of line" 58 }, 59 { 60 CTRL('D'), REQ_DOWN_FIELD, "move downward to field" 61 }, 62 { 63 CTRL('E'), REQ_END_FIELD, "go to end of field" 64 }, 65 { 66 CTRL('F'), REQ_NEXT_PAGE, "go to next page" 67 }, 68 { 69 CTRL('G'), REQ_DEL_WORD, "delete current word" 70 }, 71 { 72 CTRL('H'), REQ_DEL_PREV, "delete previous character" 73 }, 74 { 75 CTRL('I'), REQ_INS_CHAR, "insert character" 76 }, 77 { 78 CTRL('K'), REQ_CLR_EOF, "clear to end of field" 79 }, 80 { 81 CTRL('L'), REQ_LEFT_FIELD, "go to field to left" 82 }, 83 { 84 CTRL('M'), REQ_NEW_LINE, "insert/overlay new line" 85 }, 86 { 87 CTRL('N'), REQ_NEXT_FIELD, "go to next field" 88 }, 89 { 90 CTRL('O'), REQ_INS_LINE, "insert blank line at cursor" 91 }, 92 { 93 CTRL('P'), REQ_PREV_FIELD, "go to previous field" 94 }, 95 { 96 CTRL('Q'), MY_QUIT, "exit form" 97 }, 98 { 99 CTRL('R'), REQ_RIGHT_FIELD, "go to field to right" 100 }, 101 { 102 CTRL('S'), REQ_BEG_FIELD, "go to beginning of field" 103 }, 104 { 105 CTRL('T'), MY_EDT_MODE, "toggle O_EDIT mode, clear field status", 106 }, 107 { 108 CTRL('U'), REQ_UP_FIELD, "move upward to field" 109 }, 110 { 111 CTRL('V'), REQ_DEL_CHAR, "delete character" 112 }, 113 { 114 CTRL('W'), REQ_NEXT_WORD, "go to next word" 115 }, 116 { 117 CTRL('X'), REQ_CLR_FIELD, "clear field" 118 }, 119 { 120 CTRL('Y'), REQ_DEL_LINE, "delete line" 121 }, 122 { 123 CTRL('Z'), REQ_PREV_CHOICE, "" 124 }, 125 { 126 CTRL('['), MY_QUIT, "exit form" 127 }, 128 { 129 CTRL(']'), MY_INS_MODE, "toggle REQ_INS_MODE/REQ_OVL_MODE", 130 }, 131 { 132 KEY_F(1), MY_HELP, "show this screen", 133 }, 134 { 135 KEY_BACKSPACE, REQ_DEL_PREV, "delete previous character" 136 }, 137 { 138 KEY_DOWN, REQ_DOWN_CHAR, "move down 1 character" 139 }, 140 { 141 KEY_END, REQ_LAST_FIELD, "go to last field" 142 }, 143 { 144 KEY_HOME, REQ_FIRST_FIELD, "go to first field" 145 }, 146 { 147 KEY_LEFT, REQ_LEFT_CHAR, "move left 1 character" 148 }, 149 { 150 KEY_LL, REQ_LAST_FIELD, "go to last field" 151 }, 152 { 153 KEY_NEXT, REQ_NEXT_FIELD, "go to next field" 154 }, 155 { 156 KEY_NPAGE, REQ_NEXT_PAGE, "go to next page" 157 }, 158 { 159 KEY_PPAGE, REQ_PREV_PAGE, "go to previous page" 160 }, 161 { 162 KEY_PREVIOUS, REQ_PREV_FIELD, "go to previous field" 163 }, 164 { 165 KEY_RIGHT, REQ_RIGHT_CHAR, "move right 1 character" 166 }, 167 { 168 KEY_UP, REQ_UP_CHAR, "move up 1 character" 169 } 170}; 171 172static WINDOW *old_window; 173 174static void 175begin_popup(void) 176{ 177 doupdate(); 178 old_window = dupwin(curscr); 179} 180 181static void 182end_popup(void) 183{ 184 touchwin(old_window); 185 wnoutrefresh(old_window); 186 doupdate(); 187 delwin(old_window); 188} 189 190/* 191 * Display a temporary window listing the keystroke-commands we recognize. 192 */ 193void 194help_edit_field(void) 195{ 196 int x0 = 4; 197 int y0 = 2; 198 int y1 = 0; 199 int y2 = 0; 200 int wide = COLS - ((x0 + 1) * 2); 201 int high = LINES - ((y0 + 1) * 2); 202 WINDOW *help = newwin(high, wide, y0, x0); 203 WINDOW *data = newpad(2 + SIZEOF(commands), wide - 4); 204 unsigned n; 205 int ch = ERR; 206 207 begin_popup(); 208 209 keypad(help, TRUE); 210 keypad(data, TRUE); 211 waddstr(data, "Defined form edit/traversal keys:\n"); 212 for (n = 0; n < SIZEOF(commands); ++n) { 213 const char *name; 214#ifdef NCURSES_VERSION 215 if ((name = form_request_name(commands[n].result)) == 0) 216#endif 217 name = commands[n].help; 218 wprintw(data, "%s -- %s\n", 219 keyname(commands[n].code), 220 name != 0 ? name : commands[n].help); 221 } 222 waddstr(data, "Arrow keys move within a field as you would expect."); 223 y2 = getcury(data); 224 225 do { 226 switch (ch) { 227 case KEY_HOME: 228 y1 = 0; 229 break; 230 case KEY_END: 231 y1 = y2; 232 break; 233 case KEY_PREVIOUS: 234 case KEY_PPAGE: 235 if (y1 > 0) { 236 y1 -= high / 2; 237 if (y1 < 0) 238 y1 = 0; 239 } else { 240 beep(); 241 } 242 break; 243 case KEY_NEXT: 244 case KEY_NPAGE: 245 if (y1 < y2) { 246 y1 += high / 2; 247 if (y1 >= y2) 248 y1 = y2; 249 } else { 250 beep(); 251 } 252 break; 253 case CTRL('P'): 254 case KEY_UP: 255 if (y1 > 0) 256 --y1; 257 else 258 beep(); 259 break; 260 case CTRL('N'): 261 case KEY_DOWN: 262 if (y1 < y2) 263 ++y1; 264 else 265 beep(); 266 break; 267 default: 268 beep(); 269 break; 270 case ERR: 271 break; 272 } 273 werase(help); 274 box(help, 0, 0); 275 wnoutrefresh(help); 276 pnoutrefresh(data, y1, 0, y0 + 1, x0 + 1, high, wide); 277 doupdate(); 278 } while ((ch = wgetch(data)) != ERR && ch != QUIT && ch != ESCAPE); 279 werase(help); 280 wrefresh(help); 281 delwin(help); 282 delwin(data); 283 284 end_popup(); 285} 286 287static int 288offset_in_field(FORM * form) 289{ 290 FIELD *field = current_field(form); 291 return form->curcol + form->currow * field->dcols; 292} 293 294static void 295inactive_field(FIELD * f) 296{ 297 void *ptr = field_userptr(f); 298 set_field_back(f, (chtype) ptr); 299} 300 301int 302edit_field(FORM * form, int *result) 303{ 304 int ch = wgetch(form_win(form)); 305 int status; 306 FIELD *before; 307 unsigned n; 308 char lengths[80]; 309 int length; 310 char *buffer; 311 int before_row = form->currow; 312 int before_col = form->curcol; 313 int before_off = offset_in_field(form); 314 315 before = current_field(form); 316 set_field_back(before, A_NORMAL); 317 if (ch <= KEY_MAX) { 318 set_field_back(before, A_REVERSE); 319 } else if (ch <= MAX_FORM_COMMAND) { 320 inactive_field(before); 321 } 322 323 *result = ch; 324 for (n = 0; n < SIZEOF(commands); ++n) { 325 if (commands[n].code == ch) { 326 *result = commands[n].result; 327 break; 328 } 329 } 330 331 status = form_driver(form, *result); 332 333 if (status == E_OK) { 334 bool modified = TRUE; 335 336 length = 0; 337 if ((buffer = field_buffer(before, 1)) != 0) 338 length = atoi(buffer); 339 if (length < before_off) 340 length = before_off; 341 switch (*result) { 342 case REQ_CLR_EOF: 343 length = before_off; 344 break; 345 case REQ_CLR_EOL: 346 if (before_row + 1 == before->rows) 347 length = before_off; 348 break; 349 case REQ_CLR_FIELD: 350 length = 0; 351 break; 352 case REQ_DEL_CHAR: 353 if (length > before_off) 354 --length; 355 break; 356 case REQ_DEL_PREV: 357 if (length > 0) { 358 if (before_col > 0) { 359 --length; 360 } else if (before_row > 0) { 361 length -= before->cols + before_col; 362 } 363 } 364 break; 365 case REQ_NEW_LINE: 366 length += before->cols; 367 break; 368#if 0 369 /* FIXME: finish these */ 370 case REQ_DEL_LINE: /* delete line */ 371 case REQ_DEL_WORD: /* delete word at cursor */ 372 case REQ_INS_CHAR: /* insert blank char at cursor */ 373 case REQ_INS_LINE: /* insert blank line at cursor */ 374 case REQ_INS_MODE: /* begin insert mode */ 375 case REQ_OVL_MODE: /* begin overlay mode */ 376#endif 377 /* ignore all of the motion commands */ 378 case REQ_SCR_BCHAR: /* FALLTHRU */ 379 case REQ_SCR_BHPAGE: /* FALLTHRU */ 380 case REQ_SCR_BLINE: /* FALLTHRU */ 381 case REQ_SCR_BPAGE: /* FALLTHRU */ 382 case REQ_SCR_FCHAR: /* FALLTHRU */ 383 case REQ_SCR_FHPAGE: /* FALLTHRU */ 384 case REQ_SCR_FLINE: /* FALLTHRU */ 385 case REQ_SCR_FPAGE: /* FALLTHRU */ 386 case REQ_SCR_HBHALF: /* FALLTHRU */ 387 case REQ_SCR_HBLINE: /* FALLTHRU */ 388 case REQ_SCR_HFHALF: /* FALLTHRU */ 389 case REQ_SCR_HFLINE: /* FALLTHRU */ 390 case REQ_BEG_FIELD: /* FALLTHRU */ 391 case REQ_BEG_LINE: /* FALLTHRU */ 392 case REQ_DOWN_CHAR: /* FALLTHRU */ 393 case REQ_DOWN_FIELD: /* FALLTHRU */ 394 case REQ_END_FIELD: /* FALLTHRU */ 395 case REQ_END_LINE: /* FALLTHRU */ 396 case REQ_FIRST_FIELD: /* FALLTHRU */ 397 case REQ_FIRST_PAGE: /* FALLTHRU */ 398 case REQ_LAST_FIELD: /* FALLTHRU */ 399 case REQ_LAST_PAGE: /* FALLTHRU */ 400 case REQ_LEFT_CHAR: /* FALLTHRU */ 401 case REQ_LEFT_FIELD: /* FALLTHRU */ 402 case REQ_NEXT_CHAR: /* FALLTHRU */ 403 case REQ_NEXT_CHOICE: /* FALLTHRU */ 404 case REQ_NEXT_FIELD: /* FALLTHRU */ 405 case REQ_NEXT_LINE: /* FALLTHRU */ 406 case REQ_NEXT_PAGE: /* FALLTHRU */ 407 case REQ_NEXT_WORD: /* FALLTHRU */ 408 case REQ_PREV_CHAR: /* FALLTHRU */ 409 case REQ_PREV_CHOICE: /* FALLTHRU */ 410 case REQ_PREV_FIELD: /* FALLTHRU */ 411 case REQ_PREV_LINE: /* FALLTHRU */ 412 case REQ_PREV_PAGE: /* FALLTHRU */ 413 case REQ_PREV_WORD: /* FALLTHRU */ 414 case REQ_RIGHT_CHAR: /* FALLTHRU */ 415 case REQ_RIGHT_FIELD: /* FALLTHRU */ 416 case REQ_SFIRST_FIELD: /* FALLTHRU */ 417 case REQ_SLAST_FIELD: /* FALLTHRU */ 418 case REQ_SNEXT_FIELD: /* FALLTHRU */ 419 case REQ_SPREV_FIELD: /* FALLTHRU */ 420 case REQ_UP_CHAR: /* FALLTHRU */ 421 case REQ_UP_FIELD: /* FALLTHRU */ 422 case REQ_VALIDATION: /* FALLTHRU */ 423 modified = FALSE; 424 break; 425 426 default: 427 modified = FALSE; 428 if (ch >= MIN_FORM_COMMAND) { 429 beep(); 430 } else if (isprint(ch)) { 431 modified = TRUE; 432 } 433 break; 434 } 435 436 /* 437 * If we do not force a re-validation, then field_buffer 0 will 438 * be lagging by one character. 439 */ 440 if (modified && form_driver(form, REQ_VALIDATION) == E_OK && *result 441 < MIN_FORM_COMMAND) 442 ++length; 443 444 sprintf(lengths, "%d", length); 445 set_field_buffer(before, 1, lengths); 446 } 447 448 if (current_field(form) != before) 449 inactive_field(before); 450 return status; 451} 452#else 453 454extern void no_edit_field(void); 455 456void 457no_edit_field(void) 458{ 459} 460 461#endif 462