1 /* $NetBSD: form.c,v 1.3 2001/01/16 01:02:47 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 withough 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, /* user defined pointer */ 47 0, /* options for the form */ 48 NULL, /* function called when form posted and 49 after page change */ 50 NULL, /* function called when form is unposted and 51 before page change */ 52 NULL, /* function called when form posted and after 53 current field changes */ 54 NULL, /* function called when form unposted and 55 before current field changes */ 56 0, /* number of fields attached */ 57 0, /* current field */ 58 0, /* current page of form */ 59 0, /* number of pages in the form */ 60 0, /* libform made the window */ 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 else { 76 if (form->posted == TRUE) 77 return E_POSTED; 78 else 79 form->win = win; 80 } 81 82 return E_OK; 83 } 84 85 /* 86 * Return the window used by the given form 87 */ 88 WINDOW * 89 form_win(FORM *form) 90 { 91 if (form == NULL) 92 return _formi_default_form.win; 93 else 94 return form->win; 95 } 96 97 /* 98 * Set the subwindow for the form. 99 */ 100 int 101 set_form_sub(FORM *form, WINDOW *window) 102 { 103 if (form == NULL) 104 _formi_default_form.subwin = window; 105 else { 106 if (form->posted == TRUE) 107 return E_POSTED; 108 else 109 form->subwin = window; 110 } 111 112 return E_OK; 113 } 114 115 /* 116 * Return the subwindow for the given form. 117 */ 118 WINDOW * 119 form_sub(FORM *form) 120 { 121 if (form == NULL) 122 return _formi_default_form.subwin; 123 else 124 return form->subwin; 125 } 126 127 /* 128 * Return the minimum size required to contain the form. 129 */ 130 int 131 scale_form(FORM *form, int *rows, int *cols) 132 { 133 int i, max_row, max_col, temp; 134 135 if ((form->fields == NULL) || (form->fields[0] == NULL)) 136 return E_NOT_CONNECTED; 137 138 max_row = 0; 139 max_col = 0; 140 141 for (i = 0; i < form->field_count; i++) { 142 temp = form->fields[i]->form_row + form->fields[i]->rows; 143 max_row = (temp > max_row)? temp : max_row; 144 temp = form->fields[i]->form_col + form->fields[i]->cols; 145 max_col = (temp > max_col)? temp : max_col; 146 } 147 148 (*rows) = max_row; 149 (*cols) = max_col; 150 151 return E_OK; 152 } 153 154 /* 155 * Set the user defined pointer for the form given. 156 */ 157 int 158 set_form_userptr(FORM *form, void *ptr) 159 { 160 if (form == NULL) 161 _formi_default_form.userptr = ptr; 162 else 163 form->userptr = ptr; 164 165 return E_OK; 166 } 167 168 /* 169 * Return the user defined pointer associated with the given form. 170 */ 171 void * 172 form_userptr(FORM *form) 173 { 174 175 if (form == NULL) 176 return _formi_default_form.userptr; 177 else 178 return form->userptr; 179 } 180 181 /* 182 * Set the form options to the given ones. 183 */ 184 int 185 set_form_opts(FORM *form, Form_Options options) 186 { 187 if (form == NULL) 188 _formi_default_form.opts = options; 189 else 190 form->opts = options; 191 192 return E_OK; 193 } 194 195 /* 196 * Turn the given options on for the form. 197 */ 198 int 199 form_opts_on(FORM *form, Form_Options options) 200 { 201 if (form == NULL) 202 _formi_default_form.opts |= options; 203 else 204 form->opts |= options; 205 206 return E_OK; 207 } 208 209 /* 210 * Turn the given options off for the form. 211 */ 212 int 213 form_opts_off(FORM *form, Form_Options options) 214 { 215 if (form == NULL) 216 _formi_default_form.opts &= ~options; 217 else 218 form->opts &= ~options; 219 220 221 return E_OK; 222 } 223 224 /* 225 * Return the options set for the given form. 226 */ 227 Form_Options 228 form_opts(FORM *form) 229 { 230 if (form == NULL) 231 return _formi_default_form.opts; 232 else 233 return form->opts; 234 } 235 236 /* 237 * Set the form init function for the given form 238 */ 239 int 240 set_form_init(FORM *form, Form_Hook func) 241 { 242 if (form == NULL) 243 _formi_default_form.form_init = func; 244 else 245 form->form_init = func; 246 247 return E_OK; 248 } 249 250 /* 251 * Return the init function associated with the given form. 252 */ 253 Form_Hook 254 form_init(FORM *form) 255 { 256 if (form == NULL) 257 return _formi_default_form.form_init; 258 else 259 return form->form_init; 260 } 261 262 /* 263 * Set the function to be called on form termination. 264 */ 265 int 266 set_form_term(FORM *form, Form_Hook function) 267 { 268 if (form == NULL) 269 _formi_default_form.form_term = function; 270 else 271 form->form_term = function; 272 273 return E_OK; 274 } 275 276 /* 277 * Return the function defined for the termination function. 278 */ 279 Form_Hook 280 form_term(FORM *form) 281 { 282 283 if (form == NULL) 284 return _formi_default_form.form_term; 285 else 286 return form->form_term; 287 } 288 289 290 /* 291 * Attach the given fields to the form. 292 */ 293 int 294 set_form_fields(FORM *form, FIELD **fields) 295 { 296 int num_fields = 0, i, maxpg = 1, status; 297 298 if (form == NULL) 299 return E_BAD_ARGUMENT; 300 301 if (form->posted == TRUE) 302 return E_POSTED; 303 304 if (fields == NULL) 305 return E_BAD_ARGUMENT; 306 307 while (fields[num_fields] != NULL) { 308 if ((fields[num_fields]->parent != NULL) && 309 (fields[num_fields]->parent != form)) 310 return E_CONNECTED; 311 num_fields++; 312 } 313 314 /* disconnect old fields, if any */ 315 if (form->fields != NULL) { 316 for (i = 0; i < form->field_count; i++) { 317 form->fields[i]->parent = NULL; 318 form->fields[i]->index = -1; 319 } 320 } 321 322 /* kill old page pointers if any */ 323 if (form->page_starts != NULL) 324 free(form->page_starts); 325 326 form->field_count = num_fields; 327 328 /* now connect the new fields to the form */ 329 for (i = 0; i < num_fields; i++) { 330 fields[i]->parent = form; 331 fields[i]->index = i; 332 /* set the page number of the field */ 333 if (fields[i]->page_break == 1) 334 maxpg++; 335 fields[i]->page = maxpg; 336 } 337 338 form->fields = fields; 339 form->cur_field = 0; 340 form->max_page = maxpg; 341 if ((status = _formi_find_pages(form)) != E_OK) 342 return status; 343 344 /* sort the fields and set the navigation pointers */ 345 _formi_sort_fields(form); 346 _formi_stitch_fields(form); 347 348 return E_OK; 349 } 350 351 /* 352 * Return the fields attached to the form given. 353 */ 354 FIELD ** 355 form_fields(FORM *form) 356 { 357 if (form == NULL) 358 return NULL; 359 360 return form->fields; 361 } 362 363 /* 364 * Return the number of fields attached to the given form. 365 */ 366 int 367 field_count(FORM *form) 368 { 369 if (form == NULL) 370 return -1; 371 372 return form->field_count; 373 } 374 375 /* 376 * Move the given field to the row and column given. 377 */ 378 int 379 move_field(FIELD *fptr, int frow, int fcol) 380 { 381 FIELD *field = (fptr == NULL) ? &_formi_default_field : fptr; 382 383 if (field->parent != NULL) 384 return E_CONNECTED; 385 386 field->form_row = frow; 387 field->form_col = fcol; 388 389 return E_OK; 390 } 391 392 /* 393 * Set the page of the form to the given page. 394 */ 395 int 396 set_form_page(FORM *form, int page) 397 { 398 if (form == NULL) 399 return E_BAD_ARGUMENT; 400 401 if (form->in_init == TRUE) 402 return E_BAD_STATE; 403 404 if (page > form->max_page) 405 return E_BAD_ARGUMENT; 406 407 form->page = page; 408 return E_OK; 409 } 410 411 /* 412 * Return the current page of the form. 413 */ 414 int 415 form_page(FORM *form) 416 { 417 if (form == NULL) 418 return -1; 419 420 return form->page; 421 } 422 423 /* 424 * Set the current field to the field given. 425 */ 426 int 427 set_current_field(FORM *form, FIELD *field) 428 { 429 if (form == NULL) 430 return E_BAD_ARGUMENT; 431 432 if (form->in_init == TRUE) 433 return E_BAD_STATE; 434 435 if (field == NULL) 436 return E_INVALID_FIELD; 437 438 if ((field->parent == NULL) || (field->parent != form)) 439 return E_INVALID_FIELD; /* field is not of this form */ 440 441 form->cur_field = field->index; 442 return E_OK; 443 } 444 445 /* 446 * Return the current field of the given form. 447 */ 448 FIELD * 449 current_field(FORM *form) 450 { 451 if (form == NULL) 452 return NULL; 453 454 if (form->fields == NULL) 455 return NULL; 456 457 return form->fields[form->cur_field]; 458 } 459 460 /* 461 * Allocate a new form with the given fields. 462 */ 463 FORM * 464 new_form(FIELD **fields) 465 { 466 FORM *new; 467 468 if ((new = (FORM *) malloc(sizeof(FORM))) == NULL) 469 return NULL; 470 471 472 /* copy in the defaults... */ 473 bcopy(&_formi_default_form, new, sizeof(FORM)); 474 475 if (new->win == NULL) 476 new->win = stdscr; /* something for curses to write to */ 477 478 if (fields != NULL) { /* attach the fields, if any */ 479 if (set_form_fields(new, fields) < 0) { 480 free(new); /* field attach failed, back out */ 481 return NULL; 482 } 483 } 484 485 return new; 486 } 487 488 /* 489 * Free the given form. 490 */ 491 int 492 free_form(FORM *form) 493 { 494 int i; 495 496 if (form == NULL) 497 return E_BAD_ARGUMENT; 498 499 if (form->posted == TRUE) 500 return E_POSTED; 501 502 for (i = 0; i < form->field_count; i++) { 503 /* detach all the fields from the form */ 504 form->fields[i]->parent = NULL; 505 form->fields[i]->index = -1; 506 } 507 508 free(form->fields); 509 free(form); 510 511 return E_OK; 512 } 513 514 /* 515 * Tell if the current field of the form has offscreen data ahead 516 */ 517 int 518 data_ahead(FORM *form) 519 { 520 FIELD *cur; 521 int end; 522 523 if ((form == NULL) || (form->fields == NULL) 524 || (form->fields[0] == NULL)) 525 return FALSE; 526 527 cur = form->fields[form->cur_field]; 528 end = _formi_find_eol(cur->buffers[0].string, 529 cur->start_char + cur->hscroll 530 + cur->cursor_xpos); 531 if ((end - cur->start_char - cur->hscroll - cur->cursor_xpos) 532 > cur->cols) 533 return TRUE; 534 535 return FALSE; 536 } 537 538 /* 539 * Tell if current field of the form has offscreen data behind 540 */ 541 int 542 data_behind(FORM *form) 543 { 544 FIELD *cur; 545 546 if ((form == NULL) || (form->fields == NULL) 547 || (form->fields[0] == NULL)) 548 return FALSE; 549 550 cur = form->fields[form->cur_field]; 551 552 if ((cur->start_char > 0) || (cur->hscroll > 0)) 553 return TRUE; 554 555 return FALSE; 556 } 557 558 /* 559 * Position the form cursor. 560 */ 561 int 562 pos_form_cursor(FORM *form) 563 { 564 FIELD *cur; 565 int row, col; 566 567 if ((form == NULL) || (form->fields == NULL) || 568 (form->fields[0] == NULL)) 569 return E_BAD_ARGUMENT; 570 571 if (form->posted != 1) 572 return E_NOT_POSTED; 573 574 if (form->subwin == NULL) 575 return E_SYSTEM_ERROR; 576 577 cur = form->fields[form->cur_field]; 578 row = cur->form_row + cur->cursor_ypos; 579 col = cur->form_col + cur->cursor_xpos; 580 #ifdef DEBUG 581 fprintf(dbg, "pos_cursor: row=%d, col=%d\n", row, col); 582 #endif 583 584 wmove(form->subwin, row, col); 585 586 return E_OK; 587 } 588