1 /* $NetBSD: form.c,v 1.10 2001/07/08 13:02:29 blymn Exp $ */ 2 3 /*- 4 * Copyright (c) 1998-1999 Brett Lymn 5 * (blymn@baea.com.au, brett_lymn@yahoo.com.au) 6 * All rights reserved. 7 * 8 * This code has been donated to The NetBSD Foundation by the Author. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. The name of the author may not be used to endorse or promote products 16 * derived from this software without specific prior written permission 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 * 29 coda test. 30 * 31 */ 32 33 #include <stdlib.h> 34 #include <strings.h> 35 #include <form.h> 36 #include "internals.h" 37 38 extern FIELD _formi_default_field; 39 40 FORM _formi_default_form = { 41 FALSE, /* true if performing a init or term function */ 42 FALSE, /* the form is posted */ 43 FALSE, /* make field list circular if true */ 44 NULL, /* window for the form */ 45 NULL, /* subwindow for the form */ 46 NULL, /* use this window for output */ 47 NULL, /* user defined pointer */ 48 0, /* options for the form */ 49 NULL, /* function called when form posted and 50 after page change */ 51 NULL, /* function called when form is unposted and 52 before page change */ 53 NULL, /* function called when form posted and after 54 current field changes */ 55 NULL, /* function called when form unposted and 56 before current field changes */ 57 0, /* number of fields attached */ 58 0, /* current field */ 59 0, /* current page of form */ 60 0, /* number of pages in the form */ 61 NULL, /* dynamic array of fields that start 62 the pages */ 63 {NULL, NULL}, /* sorted field list */ 64 NULL /* array of fields attached to this form. */ 65 }; 66 67 /* 68 * Set the window associated with the form 69 */ 70 int 71 set_form_win(FORM *form, WINDOW *win) 72 { 73 if (form == NULL) { 74 _formi_default_form.win = win; 75 _formi_default_form.scrwin = win; 76 } else { 77 if (form->posted == TRUE) 78 return E_POSTED; 79 else { 80 form->win = win; 81 form->scrwin = win; 82 } 83 } 84 85 return E_OK; 86 } 87 88 /* 89 * Return the window used by the given form 90 */ 91 WINDOW * 92 form_win(FORM *form) 93 { 94 if (form == NULL) 95 return _formi_default_form.win; 96 else 97 return form->win; 98 } 99 100 /* 101 * Set the subwindow for the form. 102 */ 103 int 104 set_form_sub(FORM *form, WINDOW *window) 105 { 106 if (form == NULL) { 107 _formi_default_form.subwin = window; 108 _formi_default_form.scrwin = window; 109 } else { 110 if (form->posted == TRUE) 111 return E_POSTED; 112 else { 113 form->subwin = window; 114 form->scrwin = window; 115 } 116 } 117 118 return E_OK; 119 } 120 121 /* 122 * Return the subwindow for the given form. 123 */ 124 WINDOW * 125 form_sub(FORM *form) 126 { 127 if (form == NULL) 128 return _formi_default_form.subwin; 129 else 130 return form->subwin; 131 } 132 133 /* 134 * Return the minimum size required to contain the form. 135 */ 136 int 137 scale_form(FORM *form, int *rows, int *cols) 138 { 139 int i, max_row, max_col, temp; 140 141 if ((form->fields == NULL) || (form->fields[0] == NULL)) 142 return E_NOT_CONNECTED; 143 144 max_row = 0; 145 max_col = 0; 146 147 for (i = 0; i < form->field_count; i++) { 148 temp = form->fields[i]->form_row + form->fields[i]->rows; 149 max_row = (temp > max_row)? temp : max_row; 150 temp = form->fields[i]->form_col + form->fields[i]->cols; 151 max_col = (temp > max_col)? temp : max_col; 152 } 153 154 (*rows) = max_row; 155 (*cols) = max_col; 156 157 return E_OK; 158 } 159 160 /* 161 * Set the user defined pointer for the form given. 162 */ 163 int 164 set_form_userptr(FORM *form, void *ptr) 165 { 166 if (form == NULL) 167 _formi_default_form.userptr = ptr; 168 else 169 form->userptr = ptr; 170 171 return E_OK; 172 } 173 174 /* 175 * Return the user defined pointer associated with the given form. 176 */ 177 void * 178 form_userptr(FORM *form) 179 { 180 181 if (form == NULL) 182 return _formi_default_form.userptr; 183 else 184 return form->userptr; 185 } 186 187 /* 188 * Set the form options to the given ones. 189 */ 190 int 191 set_form_opts(FORM *form, Form_Options options) 192 { 193 if (form == NULL) 194 _formi_default_form.opts = options; 195 else 196 form->opts = options; 197 198 return E_OK; 199 } 200 201 /* 202 * Turn the given options on for the form. 203 */ 204 int 205 form_opts_on(FORM *form, Form_Options options) 206 { 207 if (form == NULL) 208 _formi_default_form.opts |= options; 209 else 210 form->opts |= options; 211 212 return E_OK; 213 } 214 215 /* 216 * Turn the given options off for the form. 217 */ 218 int 219 form_opts_off(FORM *form, Form_Options options) 220 { 221 if (form == NULL) 222 _formi_default_form.opts &= ~options; 223 else 224 form->opts &= ~options; 225 226 227 return E_OK; 228 } 229 230 /* 231 * Return the options set for the given form. 232 */ 233 Form_Options 234 form_opts(FORM *form) 235 { 236 if (form == NULL) 237 return _formi_default_form.opts; 238 else 239 return form->opts; 240 } 241 242 /* 243 * Set the form init function for the given form 244 */ 245 int 246 set_form_init(FORM *form, Form_Hook func) 247 { 248 if (form == NULL) 249 _formi_default_form.form_init = func; 250 else 251 form->form_init = func; 252 253 return E_OK; 254 } 255 256 /* 257 * Return the init function associated with the given form. 258 */ 259 Form_Hook 260 form_init(FORM *form) 261 { 262 if (form == NULL) 263 return _formi_default_form.form_init; 264 else 265 return form->form_init; 266 } 267 268 /* 269 * Set the function to be called on form termination. 270 */ 271 int 272 set_form_term(FORM *form, Form_Hook function) 273 { 274 if (form == NULL) 275 _formi_default_form.form_term = function; 276 else 277 form->form_term = function; 278 279 return E_OK; 280 } 281 282 /* 283 * Return the function defined for the termination function. 284 */ 285 Form_Hook 286 form_term(FORM *form) 287 { 288 289 if (form == NULL) 290 return _formi_default_form.form_term; 291 else 292 return form->form_term; 293 } 294 295 296 /* 297 * Attach the given fields to the form. 298 */ 299 int 300 set_form_fields(FORM *form, FIELD **fields) 301 { 302 int num_fields = 0, i, maxpg = 1, status; 303 304 if (form == NULL) 305 return E_BAD_ARGUMENT; 306 307 if (form->posted == TRUE) 308 return E_POSTED; 309 310 if (fields == NULL) 311 return E_BAD_ARGUMENT; 312 313 while (fields[num_fields] != NULL) { 314 if ((fields[num_fields]->parent != NULL) && 315 (fields[num_fields]->parent != form)) 316 return E_CONNECTED; 317 num_fields++; 318 } 319 320 /* disconnect old fields, if any */ 321 if (form->fields != NULL) { 322 for (i = 0; i < form->field_count; i++) { 323 form->fields[i]->parent = NULL; 324 form->fields[i]->index = -1; 325 } 326 } 327 328 /* kill old page pointers if any */ 329 if (form->page_starts != NULL) 330 free(form->page_starts); 331 332 form->field_count = num_fields; 333 334 /* now connect the new fields to the form */ 335 for (i = 0; i < num_fields; i++) { 336 fields[i]->parent = form; 337 fields[i]->index = i; 338 /* set the page number of the field */ 339 if (fields[i]->page_break == 1) 340 maxpg++; 341 fields[i]->page = maxpg; 342 } 343 344 form->fields = fields; 345 form->cur_field = 0; 346 form->max_page = maxpg; 347 if ((status = _formi_find_pages(form)) != E_OK) 348 return status; 349 350 /* sort the fields and set the navigation pointers */ 351 _formi_sort_fields(form); 352 _formi_stitch_fields(form); 353 354 return E_OK; 355 } 356 357 /* 358 * Return the fields attached to the form given. 359 */ 360 FIELD ** 361 form_fields(FORM *form) 362 { 363 if (form == NULL) 364 return NULL; 365 366 return form->fields; 367 } 368 369 /* 370 * Return the number of fields attached to the given form. 371 */ 372 int 373 field_count(FORM *form) 374 { 375 if (form == NULL) 376 return -1; 377 378 return form->field_count; 379 } 380 381 /* 382 * Move the given field to the row and column given. 383 */ 384 int 385 move_field(FIELD *fptr, int frow, int fcol) 386 { 387 FIELD *field = (fptr == NULL) ? &_formi_default_field : fptr; 388 389 if (field->parent != NULL) 390 return E_CONNECTED; 391 392 field->form_row = frow; 393 field->form_col = fcol; 394 395 return E_OK; 396 } 397 398 /* 399 * Set the page of the form to the given page. 400 */ 401 int 402 set_form_page(FORM *form, int page) 403 { 404 if (form == NULL) 405 return E_BAD_ARGUMENT; 406 407 if (form->in_init == TRUE) 408 return E_BAD_STATE; 409 410 if (page > form->max_page) 411 return E_BAD_ARGUMENT; 412 413 form->page = page; 414 return E_OK; 415 } 416 417 /* 418 * Return the maximum page of the form. 419 */ 420 int 421 form_max_page(FORM *form) 422 { 423 if (form == NULL) 424 return _formi_default_form.max_page; 425 else 426 return form->max_page; 427 } 428 429 /* 430 * Return the current page of the form. 431 */ 432 int 433 form_page(FORM *form) 434 { 435 if (form == NULL) 436 return E_BAD_ARGUMENT; 437 438 return form->page; 439 } 440 441 /* 442 * Set the current field to the field given. 443 */ 444 int 445 set_current_field(FORM *form, FIELD *field) 446 { 447 if (form == NULL) 448 return E_BAD_ARGUMENT; 449 450 if (form->in_init == TRUE) 451 return E_BAD_STATE; 452 453 if (field == NULL) 454 return E_INVALID_FIELD; 455 456 if ((field->parent == NULL) || (field->parent != form)) 457 return E_INVALID_FIELD; /* field is not of this form */ 458 459 form->cur_field = field->index; 460 461 /* XXX update page if posted??? */ 462 return E_OK; 463 } 464 465 /* 466 * Return the current field of the given form. 467 */ 468 FIELD * 469 current_field(FORM *form) 470 { 471 if (form == NULL) 472 return NULL; 473 474 if (form->fields == NULL) 475 return NULL; 476 477 return form->fields[form->cur_field]; 478 } 479 480 /* 481 * Allocate a new form with the given fields. 482 */ 483 FORM * 484 new_form(FIELD **fields) 485 { 486 FORM *new; 487 488 if ((new = (FORM *) malloc(sizeof(FORM))) == NULL) 489 return NULL; 490 491 492 /* copy in the defaults... */ 493 bcopy(&_formi_default_form, new, sizeof(FORM)); 494 495 if (new->win == NULL) 496 new->scrwin = stdscr; /* something for curses to write to */ 497 498 if (fields != NULL) { /* attach the fields, if any */ 499 if (set_form_fields(new, fields) < 0) { 500 free(new); /* field attach failed, back out */ 501 return NULL; 502 } 503 } 504 505 return new; 506 } 507 508 /* 509 * Free the given form. 510 */ 511 int 512 free_form(FORM *form) 513 { 514 int i; 515 516 if (form == NULL) 517 return E_BAD_ARGUMENT; 518 519 if (form->posted == TRUE) 520 return E_POSTED; 521 522 for (i = 0; i < form->field_count; i++) { 523 /* detach all the fields from the form */ 524 form->fields[i]->parent = NULL; 525 form->fields[i]->index = -1; 526 } 527 528 free(form->fields); 529 free(form); 530 531 return E_OK; 532 } 533 534 /* 535 * Tell if the current field of the form has offscreen data ahead 536 */ 537 int 538 data_ahead(FORM *form) 539 { 540 FIELD *cur; 541 542 if ((form == NULL) || (form->fields == NULL) 543 || (form->fields[0] == NULL)) 544 return FALSE; 545 546 cur = form->fields[form->cur_field]; 547 548 /*XXXX wrong */ 549 if (cur->lines[cur->start_line + cur->cursor_ypos].length > cur->cols) 550 return TRUE; 551 552 return FALSE; 553 } 554 555 /* 556 * Tell if current field of the form has offscreen data behind 557 */ 558 int 559 data_behind(FORM *form) 560 { 561 FIELD *cur; 562 563 if ((form == NULL) || (form->fields == NULL) 564 || (form->fields[0] == NULL)) 565 return FALSE; 566 567 cur = form->fields[form->cur_field]; 568 569 if (cur->start_char > 0) 570 return TRUE; 571 572 return FALSE; 573 } 574 575 /* 576 * Position the form cursor. 577 */ 578 int 579 pos_form_cursor(FORM *form) 580 { 581 FIELD *cur; 582 int row, col; 583 584 if ((form == NULL) || (form->fields == NULL) || 585 (form->fields[0] == NULL)) 586 return E_BAD_ARGUMENT; 587 588 if (form->posted != 1) 589 return E_NOT_POSTED; 590 591 cur = form->fields[form->cur_field]; 592 row = cur->form_row; 593 col = cur->form_col; 594 595 /* if the field is public then show the cursor pos */ 596 if ((cur->opts & O_PUBLIC) == O_PUBLIC) { 597 row += cur->cursor_ypos; 598 col += cur->cursor_xpos; 599 if (cur->cursor_xpos >= cur->cols) { 600 col = cur->form_col; 601 row++; 602 } 603 } 604 605 #ifdef DEBUG 606 fprintf(dbg, "pos_cursor: row=%d, col=%d\n", row, col); 607 #endif 608 609 wmove(form->scrwin, row, col); 610 611 return E_OK; 612 } 613