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