ncurses 4.1
[ncurses.git] / form / frm_def.c
1 /*-----------------------------------------------------------------------------+
2 |           The ncurses form library is  Copyright (C) 1995-1997               |
3 |             by Juergen Pfeifer <Juergen.Pfeifer@T-Online.de>                 |
4 |                          All Rights Reserved.                                |
5 |                                                                              |
6 | Permission to use, copy, modify, and distribute this software and its        |
7 | documentation for any purpose and without fee is hereby granted, provided    |
8 | that the above copyright notice appear in all copies and that both that      |
9 | copyright notice and this permission notice appear in supporting             |
10 | documentation, and that the name of the above listed copyright holder(s) not |
11 | be used in advertising or publicity pertaining to distribution of the        |
12 | software without specific, written prior permission.                         | 
13 |                                                                              |
14 | THE ABOVE LISTED COPYRIGHT HOLDER(S) DISCLAIM ALL WARRANTIES WITH REGARD TO  |
15 | THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FIT-  |
16 | NESS, IN NO EVENT SHALL THE ABOVE LISTED COPYRIGHT HOLDER(S) BE LIABLE FOR   |
17 | ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RE- |
18 | SULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, |
19 | NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH    |
20 | THE USE OR PERFORMANCE OF THIS SOFTWARE.                                     |
21 +-----------------------------------------------------------------------------*/
22
23 #include "form.priv.h"
24
25 MODULE_ID("$Id: frm_def.c,v 1.4 1997/05/01 16:47:54 juergen Exp $")
26
27 /* this can't be readonly */
28 static FORM default_form = {
29   0,                                    /* status     */
30   0,                                    /* rows       */
31   0,                                    /* cols       */
32   0,                                    /* currow     */
33   0,                                    /* curcol     */
34   0,                                    /* toprow     */
35   0,                                    /* begincol   */
36   -1,                                   /* maxfield   */
37   -1,                                   /* maxpage    */
38   -1,                                   /* curpage    */
39   ALL_FORM_OPTS,                        /* opts       */
40   (WINDOW *)0,                          /* win        */
41   (WINDOW *)0,                          /* sub        */
42   (WINDOW *)0,                          /* w          */
43   (FIELD **)0,                          /* field      */
44   (FIELD *)0,                           /* current    */
45   (_PAGE *)0,                           /* page       */
46   (char *)0,                            /* usrptr     */
47   NULL,                                 /* forminit   */
48   NULL,                                 /* formterm   */
49   NULL,                                 /* fieldinit  */
50   NULL                                  /* fieldterm  */
51 };
52
53 FORM *_nc_Default_Form = &default_form;
54 \f
55 /*---------------------------------------------------------------------------
56 |   Facility      :  libnform  
57 |   Function      :  static FIELD *Insert_Field_By_Position(
58 |                                     FIELD *new_field, 
59 |                                     FIELD *head )
60 |   
61 |   Description   :  Insert new_field into sorted fieldlist with head "head"
62 |                    and return new head of sorted fieldlist. Sorting
63 |                    criteria is (row,column). This is a circular list.
64 |
65 |   Return Values :  New head of sorted fieldlist
66 +--------------------------------------------------------------------------*/
67 static FIELD *Insert_Field_By_Position(FIELD *newfield, FIELD *head)
68 {
69   FIELD *current, *newhead;
70   
71   assert(newfield);
72
73   if (!head)
74     { /* empty list is trivial */
75       newhead = newfield->snext = newfield->sprev = newfield;
76     }
77   else
78     {
79       newhead = current = head;
80       while((current->frow < newfield->frow) || 
81             ((current->frow==newfield->frow) && 
82              (current->fcol < newfield->fcol)) )
83         {
84           current = current->snext;
85           if (current==head)
86             { /* We cycled through. Reset head to indicate that */
87               head = (FIELD *)0;
88               break;
89             }
90         }
91       /* we leave the loop with current pointing to the field after newfield*/
92       newfield->snext    = current;
93       newfield->sprev    = current->sprev;
94       newfield->snext->sprev = newfield;
95       newfield->sprev->snext = newfield;
96       if (current==head) 
97         newhead = newfield;
98     }
99   return(newhead);
100 }
101
102 /*---------------------------------------------------------------------------
103 |   Facility      :  libnform  
104 |   Function      :  static void Disconnect_Fields(FORM *form)
105 |   
106 |   Description   :  Break association between form and array of fields.
107 |
108 |   Return Values :  -
109 +--------------------------------------------------------------------------*/
110 static void Disconnect_Fields( FORM * form )
111 {
112   FIELD **fields;
113   
114   assert(form && form->field);
115
116   for(fields=form->field;*fields;fields++)
117     {
118       if (form == (*fields)->form) 
119         (*fields)->form = (FORM *)0;
120     }
121   
122   form->rows = form->cols = 0;
123   form->maxfield = form->maxpage = -1;
124   form->field = (FIELD **)0;
125   if (form->page) 
126     free(form->page);
127   form->page = (_PAGE *)0;
128 }       
129
130 /*---------------------------------------------------------------------------
131 |   Facility      :  libnform  
132 |   Function      :  static int Connect_Fields(FORM *form, FIELD **fields)
133 |   
134 |   Description   :  Set association between form and array of fields.
135 |
136 |   Return Values :  E_OK            - no error
137 |                    E_CONNECTED     - a field is already connected
138 |                    E_BAD_ARGUMENT  - Invalid form pointer or field array
139 |                    E_SYSTEM_ERROR  - not enough memory
140 +--------------------------------------------------------------------------*/
141 static int Connect_Fields(FORM  * form, FIELD ** fields)
142 {
143   int field_cnt, j;
144   int page_nr;
145   int maximum_row_in_field, maximum_col_in_field;
146   _PAGE *pg;
147   
148   assert(form);
149
150   form->field    = fields;
151   form->maxfield = 0;
152   form->maxpage  = 0;
153
154   if (!fields)
155     RETURN(E_OK);
156   
157   page_nr = 0;
158   /* store formpointer in fields and count pages */
159   for(field_cnt=0;fields[field_cnt];field_cnt++)
160     {
161       if (fields[field_cnt]->form) 
162         RETURN(E_CONNECTED);
163       if ( field_cnt==0 || 
164           (fields[field_cnt]->status & _NEWPAGE)) 
165         page_nr++;
166       fields[field_cnt]->form = form;
167     }   
168   if (field_cnt==0)
169     RETURN(E_BAD_ARGUMENT);
170   
171   /* allocate page structures */
172   if ( (pg = (_PAGE *)malloc(page_nr * sizeof(_PAGE))) != (_PAGE *)0 )
173     {
174       form->page = pg;
175     }
176   else
177     RETURN(E_SYSTEM_ERROR);
178   
179   /* Cycle through fields and calculate page boundaries as well as
180      size of the form */
181   for(j=0;j<field_cnt;j++)
182     {
183       if (j==0) 
184         pg->pmin = j;
185       else
186         {
187           if (fields[j]->status & _NEWPAGE)
188             {
189               pg->pmax = j-1;
190               pg++;
191               pg->pmin = j;
192             }
193         }
194       
195       maximum_row_in_field = fields[j]->frow + fields[j]->rows;
196       maximum_col_in_field = fields[j]->fcol + fields[j]->cols;
197       
198       if (form->rows < maximum_row_in_field) 
199         form->rows = maximum_row_in_field;
200       if (form->cols < maximum_col_in_field) 
201         form->cols = maximum_col_in_field;
202     }
203   
204   pg->pmax       = field_cnt-1;
205   form->maxfield = field_cnt;
206   form->maxpage  = page_nr; 
207   
208   /* Sort fields on form pages */
209   for(page_nr = 0;page_nr < form->maxpage; page_nr++)
210     {
211       FIELD *fld = (FIELD *)0;
212       for(j = form->page[page_nr].pmin;j <= form->page[page_nr].pmax;j++)
213         {
214           fields[j]->index = j;
215           fields[j]->page  = page_nr;
216           fld = Insert_Field_By_Position(fields[j],fld);
217         }
218       form->page[page_nr].smin = fld->index;
219       form->page[page_nr].smax = fld->sprev->index;
220     }
221   RETURN(E_OK);
222 }
223
224 /*---------------------------------------------------------------------------
225 |   Facility      :  libnform  
226 |   Function      :  static int Associate_Fields(FORM *form, FIELD **fields)
227 |   
228 |   Description   :  Set association between form and array of fields. 
229 |                    If there are fields, position to first active field.
230 |
231 |   Return Values :  E_OK            - success
232 |                    any other       - error occured
233 +--------------------------------------------------------------------------*/
234 INLINE static int Associate_Fields(FORM  *form, FIELD **fields)
235 {
236   int res = Connect_Fields(form,fields);
237   if (res == E_OK)
238     {
239       if (form->maxpage>0)
240         {
241           form->curpage = 0;
242           form_driver(form,FIRST_ACTIVE_MAGIC);
243         }
244       else
245         {
246           form->curpage = -1;
247           form->current = (FIELD *)0;
248         } 
249     }
250   return(res);
251 }
252                             
253 /*---------------------------------------------------------------------------
254 |   Facility      :  libnform  
255 |   Function      :  FORM *new_form( FIELD **fields )
256 |   
257 |   Description   :  Create new form with given array of fields.
258 |
259 |   Return Values :  Pointer to form. NULL if error occured.
260 +--------------------------------------------------------------------------*/
261 FORM *new_form(FIELD ** fields)
262 {       
263   int err = E_SYSTEM_ERROR;
264
265   FORM *form = (FORM *)malloc(sizeof(FORM));
266   
267   if (form)
268     {
269       *form = *_nc_Default_Form;
270       if ((err=Associate_Fields(form,fields))!=E_OK)
271         {
272           free_form(form);
273           form = (FORM *)0;
274         }
275     }
276
277   if (!form)
278     SET_ERROR(err);
279   
280   return(form);
281 }
282
283 /*---------------------------------------------------------------------------
284 |   Facility      :  libnform  
285 |   Function      :  int free_form( FORM *form )
286 |   
287 |   Description   :  Release internal memory associated with form.
288 |
289 |   Return Values :  E_OK           - no error
290 |                    E_BAD_ARGUMENT - invalid form pointer
291 |                    E_POSTED       - form is posted
292 +--------------------------------------------------------------------------*/
293 int free_form(FORM * form)
294 {
295   if ( !form )  
296     RETURN(E_BAD_ARGUMENT);
297
298   if ( form->status & _POSTED)  
299     RETURN(E_POSTED);
300   
301   Disconnect_Fields( form );
302   if (form->page) 
303     free(form->page);
304   free(form);
305   
306   RETURN(E_OK);
307 }
308
309 /*---------------------------------------------------------------------------
310 |   Facility      :  libnform  
311 |   Function      :  int set_form_fields( FORM *form, FIELD **fields )
312 |   
313 |   Description   :  Set a new association of an array of fields to a form
314 |
315 |   Return Values :  E_OK              - no error
316 |                    E_BAD_ARGUMENT    - invalid form pointer
317 |                    E_POSTED          - form is posted
318 +--------------------------------------------------------------------------*/
319 int set_form_fields(FORM  * form, FIELD ** fields)
320 {
321   FIELD **old;
322   int res;
323   
324   if ( !form )  
325     RETURN(E_BAD_ARGUMENT);
326
327   if ( form->status & _POSTED ) 
328     RETURN(E_POSTED);
329   
330   old = form->field;
331   Disconnect_Fields( form );
332   
333   if( (res = Associate_Fields( form, fields )) != E_OK )
334     Connect_Fields( form, old );
335   
336   RETURN(res);
337 }
338         
339 /*---------------------------------------------------------------------------
340 |   Facility      :  libnform  
341 |   Function      :  FIELD **form_fields( const FORM *form )
342 |   
343 |   Description   :  Retrieve array of fields
344 |
345 |   Return Values :  Pointer to field array
346 +--------------------------------------------------------------------------*/
347 FIELD **form_fields(const FORM * form)
348 {
349   return (Normalize_Form( form )->field);
350 }
351
352 /*---------------------------------------------------------------------------
353 |   Facility      :  libnform  
354 |   Function      :  int field_count( const FORM *form )
355 |   
356 |   Description   :  Retrieve number of fields
357 |
358 |   Return Values :  Number of fields, -1 if none are defined
359 +--------------------------------------------------------------------------*/
360 int field_count(const FORM * form)
361 {
362   return (Normalize_Form( form )->maxfield);
363 }
364
365 /*---------------------------------------------------------------------------
366 |   Facility      :  libnform  
367 |   Function      :  int scale_form( const FORM *form, int *rows, int *cols )
368 |   
369 |   Description   :  Retrieve size of form
370 |
371 |   Return Values :  E_OK              - no error
372 |                    E_BAD_ARGUMENT    - invalid form pointer
373 |                    E_NOT_CONNECTED   - no fields connected to form
374 +--------------------------------------------------------------------------*/
375 int scale_form(const FORM * form, int * rows, int * cols)
376 {
377   if ( !form )
378     RETURN(E_BAD_ARGUMENT);
379
380   if ( !(form->field) )
381     RETURN(E_NOT_CONNECTED);
382   
383   if (rows) 
384     *rows = form->rows;
385   if (cols) 
386     *cols = form->cols;
387   
388   RETURN(E_OK);
389 }
390
391 /* frm_def.c ends here */