form.c revision 1.1 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 (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 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