form.c revision 1.3 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 (at) baea.com.au, brett_lymn (at) 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