1 /**************************************************************************** 2 * Copyright 2020 Thomas E. Dickey * 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: dup_field.c,v 1.1 2020/03/21 19:28:36 tom Exp $ 30 * 31 * Demonstrate move_field(). 32 */ 33 34 #include <test.priv.h> 35 36 #if USE_LIBFORM 37 38 #include <edit_field.h> 39 #include <popup_msg.h> 40 41 #define MY_DEMO EDIT_FIELD('f') 42 43 static char empty[] = ""; 44 static FIELD *all_fields[100]; 45 46 /* *INDENT-OFF* */ 47 static struct { 48 int code; 49 int result; 50 const char *help; 51 } commands[] = { 52 { CTRL('A'), REQ_BEG_FIELD, "go to beginning of field" }, 53 { CTRL('D'), REQ_DOWN_FIELD, "move downward to field" }, 54 { CTRL('E'), REQ_END_FIELD, "go to end of field" }, 55 { CTRL('G'), MY_DEMO, "move current field with cursor keys" }, 56 { CTRL('H'), REQ_DEL_PREV, "delete previous character" }, 57 { CTRL('I'), REQ_NEXT_FIELD, "go to next field" }, 58 { CTRL('K'), REQ_CLR_EOF, "clear to end of field" }, 59 { CTRL('N'), REQ_NEXT_FIELD, "go to next field" }, 60 { CTRL('P'), REQ_PREV_FIELD, "go to previous field" }, 61 { CTRL('Q'), MY_QUIT, "exit form" }, 62 { CTRL('U'), REQ_UP_FIELD, "move upward to field" }, 63 { CTRL('W'), REQ_NEXT_WORD, "go to next word" }, 64 { CTRL('X'), REQ_CLR_FIELD, "clear field" }, 65 { CTRL('['), MY_QUIT, "exit form" }, 66 { KEY_F(1), MY_HELP, "show this screen", }, 67 { KEY_BACKSPACE, REQ_DEL_PREV, "delete previous character" }, 68 { KEY_BTAB, REQ_PREV_FIELD, "go to previous field" }, 69 { KEY_DOWN, REQ_DOWN_CHAR, "move down 1 character" }, 70 { KEY_END, REQ_LAST_FIELD, "go to last field" }, 71 { KEY_HOME, REQ_FIRST_FIELD, "go to first field" }, 72 { KEY_LEFT, REQ_LEFT_CHAR, "move left 1 character" }, 73 { KEY_NEXT, REQ_NEXT_FIELD, "go to next field" }, 74 { KEY_PREVIOUS, REQ_PREV_FIELD, "go to previous field" }, 75 { KEY_RIGHT, REQ_RIGHT_CHAR, "move right 1 character" }, 76 { KEY_UP, REQ_UP_CHAR, "move up 1 character" } 77 }; 78 /* *INDENT-ON* */ 79 80 static void 81 my_help_edit_field(void) 82 { 83 int used = 0; 84 unsigned n; 85 char **msgs = typeCalloc(char *, 3 + SIZEOF(commands)); 86 87 msgs[used++] = strdup("Defined form edit/traversal keys:"); 88 for (n = 0; n < SIZEOF(commands); ++n) { 89 char *msg; 90 const char *name; 91 const char *code = keyname(commands[n].code); 92 size_t need = 5; 93 #ifdef NCURSES_VERSION 94 if ((name = form_request_name(commands[n].result)) == 0) 95 #endif 96 name = commands[n].help; 97 need = 5 + strlen(code) + strlen(name); 98 msg = typeMalloc(char, need); 99 _nc_SPRINTF(msg, _nc_SLIMIT(need) "%s -- %s", code, name); 100 msgs[used++] = msg; 101 } 102 msgs[used++] = 103 strdup("Arrow keys move within a field as you would expect."); 104 msgs[used] = 0; 105 popup_msg2(stdscr, msgs); 106 for (n = 0; msgs[n] != 0; ++n) { 107 free(msgs[n]); 108 } 109 free(msgs); 110 } 111 112 static void 113 do_demo(FORM *form) 114 { 115 } 116 117 static FIELD * 118 make_label(const char *label, int frow, int fcol) 119 { 120 FIELD *f = new_field(1, (int) strlen(label), frow, fcol, 0, 0); 121 122 if (f) { 123 set_field_buffer(f, 0, label); 124 set_field_opts(f, (int) ((unsigned) field_opts(f) & ~O_ACTIVE)); 125 } 126 return (f); 127 } 128 129 static FIELD * 130 make_field(int frow, int fcol, int rows, int cols) 131 { 132 FIELD *f = new_field(rows, cols, frow, fcol, 0, 1); 133 134 if (f) { 135 set_field_back(f, A_UNDERLINE); 136 init_edit_field(f, empty); 137 } 138 return (f); 139 } 140 141 static void 142 erase_form(FORM *f) 143 { 144 WINDOW *w = form_win(f); 145 WINDOW *s = form_sub(f); 146 147 unpost_form(f); 148 werase(w); 149 wrefresh(w); 150 delwin(s); 151 delwin(w); 152 } 153 154 static int 155 my_form_driver(FORM *form, int c) 156 { 157 switch (c) { 158 case MY_QUIT: 159 if (form_driver(form, REQ_VALIDATION) == E_OK) 160 return (TRUE); 161 break; 162 case MY_HELP: 163 my_help_edit_field(); 164 break; 165 case MY_DEMO: 166 do_demo(form); 167 break; 168 default: 169 beep(); 170 break; 171 } 172 return (FALSE); 173 } 174 175 static FieldAttrs * 176 my_field_attrs(FIELD *f) 177 { 178 return (FieldAttrs *) field_userptr(f); 179 } 180 181 static int 182 buffer_length(FIELD *f) 183 { 184 return my_field_attrs(f)->row_lengths[0]; 185 } 186 187 static void 188 set_buffer_length(FIELD *f, int length) 189 { 190 my_field_attrs(f)->row_lengths[0] = length; 191 } 192 193 static int 194 offset_in_field(FORM *form) 195 { 196 FIELD *field = current_field(form); 197 int currow, curcol; 198 199 form_getyx(form, currow, curcol); 200 return curcol + currow * (int) field->dcols; 201 } 202 203 static void 204 inactive_field(FIELD *f) 205 { 206 set_field_back(f, my_field_attrs(f)->background); 207 } 208 209 static int 210 my_edit_field(FORM *form, int *result) 211 { 212 int ch = wgetch(form_win(form)); 213 int status; 214 FIELD *before; 215 unsigned n; 216 int length; 217 int before_row; 218 int before_col; 219 int before_off = offset_in_field(form); 220 221 form_getyx(form, before_row, before_col); 222 before = current_field(form); 223 set_field_back(before, A_NORMAL); 224 if (ch <= KEY_MAX) { 225 set_field_back(before, A_REVERSE); 226 } else if (ch <= MAX_FORM_COMMAND) { 227 inactive_field(before); 228 } 229 230 *result = ch; 231 for (n = 0; n < SIZEOF(commands); ++n) { 232 if (commands[n].code == ch) { 233 *result = commands[n].result; 234 break; 235 } 236 } 237 238 status = form_driver(form, *result); 239 240 if (status == E_OK) { 241 bool modified = TRUE; 242 243 length = buffer_length(before); 244 if (length < before_off) 245 length = before_off; 246 switch (*result) { 247 case REQ_CLR_EOF: 248 length = before_off; 249 break; 250 case REQ_CLR_EOL: 251 if ((int) (before_row + 1) == (int) (before->rows)) 252 length = before_off; 253 break; 254 case REQ_CLR_FIELD: 255 length = 0; 256 break; 257 case REQ_DEL_CHAR: 258 if (length > before_off) 259 --length; 260 break; 261 case REQ_DEL_PREV: 262 if (length > 0) { 263 if (before_col > 0) { 264 --length; 265 } else if (before_row > 0) { 266 length -= (int) before->cols + before_col; 267 } 268 } 269 break; 270 case REQ_NEW_LINE: 271 length += (int) before->cols; 272 break; 273 274 default: 275 modified = (ch < MIN_FORM_COMMAND 276 && isprint(ch)); 277 break; 278 } 279 280 /* 281 * If we do not force a re-validation, then field_buffer 0 will 282 * be lagging by one character. 283 */ 284 if (modified && form_driver(form, REQ_VALIDATION) == E_OK && *result 285 < MIN_FORM_COMMAND) 286 ++length; 287 288 set_buffer_length(before, length); 289 } 290 291 if (current_field(form) != before) 292 inactive_field(before); 293 return status; 294 } 295 296 static void 297 demo_forms(void) 298 { 299 FORM *form; 300 int c; 301 unsigned n = 0; 302 const char *fname; 303 304 /* describe the form */ 305 all_fields[n++] = make_label("Sample Form", 0, 15); 306 307 fname = "Last Name"; 308 all_fields[n++] = make_label(fname, 2, 0); 309 all_fields[n++] = make_field(3, 0, 1, 18); 310 set_field_type(all_fields[n - 1], TYPE_ALPHA, 1); 311 312 fname = "First Name"; 313 all_fields[n++] = make_label(fname, 2, 20); 314 all_fields[n++] = make_field(3, 20, 1, 12); 315 set_field_type(all_fields[n - 1], TYPE_ALPHA, 1); 316 317 fname = "Middle Name"; 318 all_fields[n++] = make_label(fname, 2, 34); 319 all_fields[n++] = make_field(3, 34, 1, 12); 320 set_field_type(all_fields[n - 1], TYPE_ALPHA, 1); 321 322 fname = "Comments"; 323 all_fields[n++] = make_label(fname, 5, 0); 324 all_fields[n++] = make_field(6, 0, 4, 46); 325 init_edit_field(all_fields[n - 1], empty); 326 327 all_fields[n] = (FIELD *) 0; 328 329 if ((form = new_form(all_fields)) != 0) { 330 int finished = 0; 331 332 post_form(form); 333 334 while (!finished) { 335 switch (my_edit_field(form, &c)) { 336 case E_OK: 337 break; 338 case E_UNKNOWN_COMMAND: 339 finished = my_form_driver(form, c); 340 break; 341 default: 342 beep(); 343 break; 344 } 345 } 346 347 erase_form(form); 348 349 free_form(form); 350 } 351 for (c = 0; all_fields[c] != 0; c++) { 352 free_edit_field(all_fields[c]); 353 free_field(all_fields[c]); 354 } 355 noraw(); 356 nl(); 357 } 358 359 int 360 main(void) 361 { 362 setlocale(LC_ALL, ""); 363 364 initscr(); 365 cbreak(); 366 noecho(); 367 raw(); 368 nonl(); /* lets us read ^M's */ 369 intrflush(stdscr, FALSE); 370 keypad(stdscr, TRUE); 371 372 if (has_colors()) { 373 start_color(); 374 init_pair(1, COLOR_WHITE, COLOR_BLUE); 375 init_pair(2, COLOR_GREEN, COLOR_BLACK); 376 init_pair(3, COLOR_CYAN, COLOR_BLACK); 377 bkgd((chtype) COLOR_PAIR(1)); 378 refresh(); 379 } 380 381 demo_forms(); 382 383 endwin(); 384 ExitProgram(EXIT_SUCCESS); 385 } 386 387 #else 388 int 389 main(void) 390 { 391 printf("This program requires the curses form library\n"); 392 ExitProgram(EXIT_FAILURE); 393 } 394 #endif 395