form.c revision 1.4 1 /* $NetBSD: form.c,v 1.4 2001/02/16 03:21:35 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 maximum page of the form.
413 */
414 int
415 form_max_page(FORM *form)
416 {
417 if (form == NULL)
418 return _formi_default_form.max_page;
419 else
420 return form->max_page;
421 }
422
423 /*
424 * Return the current page of the form.
425 */
426 int
427 form_page(FORM *form)
428 {
429 if (form == NULL)
430 return -1;
431
432 return form->page;
433 }
434
435 /*
436 * Set the current field to the field given.
437 */
438 int
439 set_current_field(FORM *form, FIELD *field)
440 {
441 if (form == NULL)
442 return E_BAD_ARGUMENT;
443
444 if (form->in_init == TRUE)
445 return E_BAD_STATE;
446
447 if (field == NULL)
448 return E_INVALID_FIELD;
449
450 if ((field->parent == NULL) || (field->parent != form))
451 return E_INVALID_FIELD; /* field is not of this form */
452
453 form->cur_field = field->index;
454 return E_OK;
455 }
456
457 /*
458 * Return the current field of the given form.
459 */
460 FIELD *
461 current_field(FORM *form)
462 {
463 if (form == NULL)
464 return NULL;
465
466 if (form->fields == NULL)
467 return NULL;
468
469 return form->fields[form->cur_field];
470 }
471
472 /*
473 * Allocate a new form with the given fields.
474 */
475 FORM *
476 new_form(FIELD **fields)
477 {
478 FORM *new;
479
480 if ((new = (FORM *) malloc(sizeof(FORM))) == NULL)
481 return NULL;
482
483
484 /* copy in the defaults... */
485 bcopy(&_formi_default_form, new, sizeof(FORM));
486
487 if (new->win == NULL)
488 new->win = stdscr; /* something for curses to write to */
489
490 if (fields != NULL) { /* attach the fields, if any */
491 if (set_form_fields(new, fields) < 0) {
492 free(new); /* field attach failed, back out */
493 return NULL;
494 }
495 }
496
497 return new;
498 }
499
500 /*
501 * Free the given form.
502 */
503 int
504 free_form(FORM *form)
505 {
506 int i;
507
508 if (form == NULL)
509 return E_BAD_ARGUMENT;
510
511 if (form->posted == TRUE)
512 return E_POSTED;
513
514 for (i = 0; i < form->field_count; i++) {
515 /* detach all the fields from the form */
516 form->fields[i]->parent = NULL;
517 form->fields[i]->index = -1;
518 }
519
520 free(form->fields);
521 free(form);
522
523 return E_OK;
524 }
525
526 /*
527 * Tell if the current field of the form has offscreen data ahead
528 */
529 int
530 data_ahead(FORM *form)
531 {
532 FIELD *cur;
533 int end;
534
535 if ((form == NULL) || (form->fields == NULL)
536 || (form->fields[0] == NULL))
537 return FALSE;
538
539 cur = form->fields[form->cur_field];
540 end = _formi_find_eol(cur->buffers[0].string,
541 cur->start_char + cur->hscroll
542 + cur->cursor_xpos);
543 if ((end - cur->start_char - cur->hscroll - cur->cursor_xpos)
544 > cur->cols)
545 return TRUE;
546
547 return FALSE;
548 }
549
550 /*
551 * Tell if current field of the form has offscreen data behind
552 */
553 int
554 data_behind(FORM *form)
555 {
556 FIELD *cur;
557
558 if ((form == NULL) || (form->fields == NULL)
559 || (form->fields[0] == NULL))
560 return FALSE;
561
562 cur = form->fields[form->cur_field];
563
564 if ((cur->start_char > 0) || (cur->hscroll > 0))
565 return TRUE;
566
567 return FALSE;
568 }
569
570 /*
571 * Position the form cursor.
572 */
573 int
574 pos_form_cursor(FORM *form)
575 {
576 FIELD *cur;
577 int row, col;
578
579 if ((form == NULL) || (form->fields == NULL) ||
580 (form->fields[0] == NULL))
581 return E_BAD_ARGUMENT;
582
583 if (form->posted != 1)
584 return E_NOT_POSTED;
585
586 if (form->subwin == NULL)
587 return E_SYSTEM_ERROR;
588
589 cur = form->fields[form->cur_field];
590 row = cur->form_row + cur->cursor_ypos;
591 col = cur->form_col + cur->cursor_xpos;
592 #ifdef DEBUG
593 fprintf(dbg, "pos_cursor: row=%d, col=%d\n", row, col);
594 #endif
595
596 wmove(form->subwin, row, col);
597
598 return E_OK;
599 }
600