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