1 /* $NetBSD: form.c,v 1.14 2003/03/09 00:57:18 lukem Exp $ */
4 * Copyright (c) 1998-1999 Brett Lymn
5 * (blymn@baea.com.au, brett_lymn@yahoo.com.au)
8 * This code has been donated to The NetBSD Foundation by the Author.
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
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
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.
32 #include <sys/cdefs.h>
33 __RCSID("$NetBSD: form.c,v 1.14 2003/03/09 00:57:18 lukem Exp $");
38 #include "internals.h"
40 extern FIELD _formi_default_field
;
42 FORM _formi_default_form
= {
43 FALSE
, /* true if performing a init or term function */
44 FALSE
, /* the form is posted */
45 FALSE
, /* make field list circular if true */
46 NULL
, /* window for the form */
47 NULL
, /* subwindow for the form */
48 NULL
, /* use this window for output */
49 NULL
, /* user defined pointer */
50 0, /* options for the form */
51 NULL
, /* function called when form posted and
53 NULL
, /* function called when form is unposted and
55 NULL
, /* function called when form posted and after
56 current field changes */
57 NULL
, /* function called when form unposted and
58 before current field changes */
59 0, /* number of fields attached */
60 0, /* current field */
61 0, /* current page of form */
62 0, /* number of pages in the form */
63 NULL
, /* dynamic array of fields that start
65 {NULL
, NULL
}, /* sorted field list */
66 NULL
/* array of fields attached to this form. */
70 * Set the window associated with the form
73 set_form_win(FORM
*form
, WINDOW
*win
)
76 _formi_default_form
.win
= win
;
77 _formi_default_form
.scrwin
= win
;
79 if (form
->posted
== TRUE
)
91 * Return the window used by the given form
97 return _formi_default_form
.win
;
103 * Set the subwindow for the form.
106 set_form_sub(FORM
*form
, WINDOW
*window
)
109 _formi_default_form
.subwin
= window
;
110 _formi_default_form
.scrwin
= window
;
112 if (form
->posted
== TRUE
)
115 form
->subwin
= window
;
116 form
->scrwin
= window
;
124 * Return the subwindow for the given form.
130 return _formi_default_form
.subwin
;
136 * Return the minimum size required to contain the form.
139 scale_form(FORM
*form
, int *rows
, int *cols
)
141 int i
, max_row
, max_col
, temp
;
143 if ((form
->fields
== NULL
) || (form
->fields
[0] == NULL
))
144 return E_NOT_CONNECTED
;
149 for (i
= 0; i
< form
->field_count
; i
++) {
150 temp
= form
->fields
[i
]->form_row
+ form
->fields
[i
]->rows
;
151 max_row
= (temp
> max_row
)? temp
: max_row
;
152 temp
= form
->fields
[i
]->form_col
+ form
->fields
[i
]->cols
;
153 max_col
= (temp
> max_col
)? temp
: max_col
;
163 * Set the user defined pointer for the form given.
166 set_form_userptr(FORM
*form
, void *ptr
)
169 _formi_default_form
.userptr
= ptr
;
177 * Return the user defined pointer associated with the given form.
180 form_userptr(FORM
*form
)
184 return _formi_default_form
.userptr
;
186 return form
->userptr
;
190 * Set the form options to the given ones.
193 set_form_opts(FORM
*form
, Form_Options options
)
196 _formi_default_form
.opts
= options
;
198 form
->opts
= options
;
204 * Turn the given options on for the form.
207 form_opts_on(FORM
*form
, Form_Options options
)
210 _formi_default_form
.opts
|= options
;
212 form
->opts
|= options
;
218 * Turn the given options off for the form.
221 form_opts_off(FORM
*form
, Form_Options options
)
224 _formi_default_form
.opts
&= ~options
;
226 form
->opts
&= ~options
;
233 * Return the options set for the given form.
236 form_opts(FORM
*form
)
239 return _formi_default_form
.opts
;
245 * Set the form init function for the given form
248 set_form_init(FORM
*form
, Form_Hook func
)
251 _formi_default_form
.form_init
= func
;
253 form
->form_init
= func
;
259 * Return the init function associated with the given form.
262 form_init(FORM
*form
)
265 return _formi_default_form
.form_init
;
267 return form
->form_init
;
271 * Set the function to be called on form termination.
274 set_form_term(FORM
*form
, Form_Hook function
)
277 _formi_default_form
.form_term
= function
;
279 form
->form_term
= function
;
285 * Return the function defined for the termination function.
288 form_term(FORM
*form
)
292 return _formi_default_form
.form_term
;
294 return form
->form_term
;
299 * Attach the given fields to the form.
302 set_form_fields(FORM
*form
, FIELD
**fields
)
304 int num_fields
= 0, i
, maxpg
= 1, status
;
307 return E_BAD_ARGUMENT
;
309 if (form
->posted
== TRUE
)
313 return E_BAD_ARGUMENT
;
315 while (fields
[num_fields
] != NULL
) {
316 if ((fields
[num_fields
]->parent
!= NULL
) &&
317 (fields
[num_fields
]->parent
!= form
))
322 /* disconnect old fields, if any */
323 if (form
->fields
!= NULL
) {
324 for (i
= 0; i
< form
->field_count
; i
++) {
325 form
->fields
[i
]->parent
= NULL
;
326 form
->fields
[i
]->index
= -1;
330 /* kill old page pointers if any */
331 if (form
->page_starts
!= NULL
)
332 free(form
->page_starts
);
334 form
->field_count
= num_fields
;
336 /* now connect the new fields to the form */
337 for (i
= 0; i
< num_fields
; i
++) {
338 fields
[i
]->parent
= form
;
339 fields
[i
]->index
= i
;
340 /* set the page number of the field */
341 if (fields
[i
]->page_break
== 1)
343 fields
[i
]->page
= maxpg
;
346 form
->fields
= fields
;
348 form
->max_page
= maxpg
;
349 if ((status
= _formi_find_pages(form
)) != E_OK
)
352 /* sort the fields and set the navigation pointers */
353 _formi_sort_fields(form
);
354 _formi_stitch_fields(form
);
360 * Return the fields attached to the form given.
363 form_fields(FORM
*form
)
372 * Return the number of fields attached to the given form.
375 field_count(FORM
*form
)
380 return form
->field_count
;
384 * Move the given field to the row and column given.
387 move_field(FIELD
*fptr
, int frow
, int fcol
)
389 FIELD
*field
= (fptr
== NULL
) ? &_formi_default_field
: fptr
;
391 if (field
->parent
!= NULL
)
394 field
->form_row
= frow
;
395 field
->form_col
= fcol
;
401 * Set the page of the form to the given page.
404 set_form_page(FORM
*form
, int page
)
407 return E_BAD_ARGUMENT
;
409 if (form
->in_init
== TRUE
)
412 if (page
> form
->max_page
)
413 return E_BAD_ARGUMENT
;
420 * Return the maximum page of the form.
423 form_max_page(FORM
*form
)
426 return _formi_default_form
.max_page
;
428 return form
->max_page
;
432 * Return the current page of the form.
435 form_page(FORM
*form
)
438 return E_BAD_ARGUMENT
;
444 * Set the current field to the field given.
447 set_current_field(FORM
*form
, FIELD
*field
)
450 return E_BAD_ARGUMENT
;
452 if (form
->in_init
== TRUE
)
456 return E_INVALID_FIELD
;
458 if ((field
->parent
== NULL
) || (field
->parent
!= form
))
459 return E_INVALID_FIELD
; /* field is not of this form */
461 form
->cur_field
= field
->index
;
463 /* XXX update page if posted??? */
468 * Return the current field of the given form.
471 current_field(FORM
*form
)
476 if (form
->fields
== NULL
)
479 return form
->fields
[form
->cur_field
];
483 * Allocate a new form with the given fields.
486 new_form(FIELD
**fields
)
490 if ((new = (FORM
*) malloc(sizeof(FORM
))) == NULL
)
494 /* copy in the defaults... */
495 bcopy(&_formi_default_form
, new, sizeof(FORM
));
497 if (new->win
== NULL
)
498 new->scrwin
= stdscr
; /* something for curses to write to */
500 if (fields
!= NULL
) { /* attach the fields, if any */
501 if (set_form_fields(new, fields
) < 0) {
502 free(new); /* field attach failed, back out */
511 * Free the given form.
514 free_form(FORM
*form
)
519 return E_BAD_ARGUMENT
;
521 if (form
->posted
== TRUE
)
524 for (i
= 0; i
< form
->field_count
; i
++) {
525 /* detach all the fields from the form */
526 form
->fields
[i
]->parent
= NULL
;
527 form
->fields
[i
]->index
= -1;
536 * Tell if the current field of the form has offscreen data ahead
539 data_ahead(FORM
*form
)
543 if ((form
== NULL
) || (form
->fields
== NULL
)
544 || (form
->fields
[0] == NULL
))
547 cur
= form
->fields
[form
->cur_field
];
550 if (cur
->cur_line
->expanded
> cur
->cols
)
557 * Tell if current field of the form has offscreen data behind
560 data_behind(FORM
*form
)
564 if ((form
== NULL
) || (form
->fields
== NULL
)
565 || (form
->fields
[0] == NULL
))
568 cur
= form
->fields
[form
->cur_field
];
570 if (cur
->start_char
> 0)
577 * Position the form cursor.
580 pos_form_cursor(FORM
*form
)
585 if ((form
== NULL
) || (form
->fields
== NULL
) ||
586 (form
->fields
[0] == NULL
))
587 return E_BAD_ARGUMENT
;
589 if (form
->posted
!= 1)
592 cur
= form
->fields
[form
->cur_field
];
596 /* if the field is public then show the cursor pos */
597 if ((cur
->opts
& O_PUBLIC
) == O_PUBLIC
) {
598 row
+= cur
->cursor_ypos
;
599 col
+= cur
->cursor_xpos
;
600 if (cur
->cursor_xpos
>= cur
->cols
) {
607 fprintf(dbg
, "pos_cursor: row=%d, col=%d\n", row
, col
);
610 wmove(form
->scrwin
, row
, col
);