89f0cbe9dd34d585152063f287a147400529a836
[ncurses.git] / c++ / cursesf.h
1 // * This makes emacs happy -*-Mode: C++;-*-
2 /****************************************************************************
3  * Copyright (c) 1998,1999 Free Software Foundation, Inc.                   *
4  *                                                                          *
5  * Permission is hereby granted, free of charge, to any person obtaining a  *
6  * copy of this software and associated documentation files (the            *
7  * "Software"), to deal in the Software without restriction, including      *
8  * without limitation the rights to use, copy, modify, merge, publish,      *
9  * distribute, distribute with modifications, sublicense, and/or sell       *
10  * copies of the Software, and to permit persons to whom the Software is    *
11  * furnished to do so, subject to the following conditions:                 *
12  *                                                                          *
13  * The above copyright notice and this permission notice shall be included  *
14  * in all copies or substantial portions of the Software.                   *
15  *                                                                          *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS  *
17  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF               *
18  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.   *
19  * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,   *
20  * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR    *
21  * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR    *
22  * THE USE OR OTHER DEALINGS IN THE SOFTWARE.                               *
23  *                                                                          *
24  * Except as contained in this notice, the name(s) of the above copyright   *
25  * holders shall not be used in advertising or otherwise to promote the     *
26  * sale, use or other dealings in this Software without prior written       *
27  * authorization.                                                           *
28  ****************************************************************************/
29
30 /****************************************************************************
31  *   Author: Juergen Pfeifer <juergen.pfeifer@gmx.net> 1997                 *
32  ****************************************************************************/
33
34 // $Id: cursesf.h,v 1.11 1999/10/30 23:59:37 tom Exp $
35
36 #ifndef _CURSESF_H
37 #define _CURSESF_H
38
39 #include <cursesp.h>
40
41 extern "C" {
42 #  include <form.h>
43 }
44 //
45 // -------------------------------------------------------------------------
46 // The abstract base class for buitin and user defined Fieldtypes.
47 // -------------------------------------------------------------------------
48 //
49 class NCursesFormField; // forward declaration
50
51 // Class to represent builtin field types as well as C++ written new
52 // fieldtypes (see classes UserDefineFieldType...
53 class NCursesFieldType {
54   friend class NCursesFormField;
55
56 protected:
57   FIELDTYPE* fieldtype;
58
59   inline void OnError(int err) const THROWS(NCursesFormException) {
60     if (err!=E_OK)
61       THROW(new NCursesFormException (err));
62   }
63
64   NCursesFieldType(FIELDTYPE *f) : fieldtype(f) {
65   }
66
67   virtual ~NCursesFieldType() {}
68
69   // Set the fields f fieldtype to this one.
70   virtual void set(NCursesFormField& f) = 0;
71
72 public:
73   NCursesFieldType() : fieldtype((FIELDTYPE*)0) {
74   }
75 };
76
77 //
78 // -------------------------------------------------------------------------
79 // The class representing a forms field, wrapping the lowlevel FIELD struct
80 // -------------------------------------------------------------------------
81 //
82 class NCursesFormField {
83   friend class NCursesForm;
84
85 protected:
86   FIELD *field;              // lowlevel structure
87   NCursesFieldType* ftype;   // Associated field type
88
89   // Error handler
90   inline void OnError (int err) const THROWS(NCursesFormException) {
91     if (err != E_OK)
92       THROW(new NCursesFormException (err));
93   }
94   
95 public:
96   // Create a 'Null' field. Can be used to delimit a field list
97   NCursesFormField() 
98     : field((FIELD*)0), ftype((NCursesFieldType*)0) {
99   }
100
101   // Create a new field
102   NCursesFormField (int rows,
103                     int cols,
104                     int first_row = 0,
105                     int first_col = 0,
106                     int offscreen_rows = 0,
107                     int additional_buffers = 0) 
108     : ftype((NCursesFieldType*)0) {
109       field = ::new_field(rows,cols,first_row,first_col,
110                           offscreen_rows, additional_buffers);
111       if (!field)
112         OnError(errno);
113   }
114   
115   virtual ~NCursesFormField ();
116
117   // Duplicate the field at a new position
118   inline NCursesFormField* dup(int first_row, int first_col) {
119     NCursesFormField* f = new NCursesFormField();
120     if (!f)
121       OnError(E_SYSTEM_ERROR);
122     else {
123       f->ftype = ftype;
124       f->field = ::dup_field(field,first_row,first_col);
125       if (!f->field)
126         OnError(errno);
127     }
128     return f;
129   }
130
131   // Link the field to a new location
132   inline NCursesFormField* link(int first_row, int first_col) {
133     NCursesFormField* f = new NCursesFormField();
134     if (!f)
135       OnError(E_SYSTEM_ERROR);
136     else {
137       f->ftype = ftype;
138       f->field = ::link_field(field,first_row,first_col);
139       if (!f->field)
140         OnError(errno);
141     }
142     return f;
143   }
144
145   // Get the lowlevel field representation
146   inline FIELD* get_field() const {
147     return field;
148   }
149
150   // Retrieve info about the field
151   inline void info(int& rows, int& cols,
152                    int& first_row, int& first_col,
153                    int& offscreen_rows, int& additional_buffers) const {
154     OnError(::field_info(field, &rows, &cols,
155                          &first_row, &first_col,
156                          &offscreen_rows, &additional_buffers));
157   }
158
159   // Retrieve info about the fields dynamic properties.
160   inline void dynamic_info(int& dynamic_rows, int& dynamic_cols,
161                            int& max_growth) const {
162     OnError(::dynamic_field_info(field, &dynamic_rows, &dynamic_cols,
163                                  &max_growth));
164   }
165
166   // For a dynamic field you may set the maximum growth limit.
167   // A zero means unlimited growth.
168   inline void set_maximum_growth(int growth = 0) {
169     OnError(::set_max_field(field,growth));
170   }
171
172   // Move the field to a new position
173   inline void move(int row, int col) {
174     OnError(::move_field(field,row,col));
175   }
176
177   // Mark the field to start a new page
178   inline void new_page(bool pageFlag = FALSE) {
179     OnError(::set_new_page(field,pageFlag));
180   }
181
182   // Retrieve whether or not the field starts a new page.
183   inline bool is_new_page() const {
184     return ::new_page(field);
185   }
186
187   // Set the justification for the field
188   inline void set_justification(int just) {
189     OnError(::set_field_just(field,just));
190   }
191
192   // Retrieve the fields justification
193   inline int justification() const {
194     return ::field_just(field);
195   }
196   // Set the foreground attribute for the field
197   inline void set_foreground(chtype fore) {
198     OnError(::set_field_fore(field,fore));
199   }
200
201   // Retrieve the fields foreground attribute
202   inline chtype fore() const {
203     return ::field_fore(field);
204   }
205
206   // Set the background attribute for the field
207   inline void set_background(chtype back) {
208     OnError(::set_field_back(field,back));
209   }
210
211   // Retrieve the fields background attribute
212   inline chtype back() const {
213     return ::field_back(field);
214   }
215
216   // Set the padding character for the field
217   inline void set_pad_character(int pad) {
218     OnError(::set_field_pad(field,pad));
219   }
220
221   // Retrieve the fields padding character
222   inline int pad() const {
223     return ::field_pad(field);
224   }
225
226   // Switch on the fields options
227   inline void options_on (Field_Options options) {
228     OnError (::field_opts_on (field, options));
229   }
230
231   // Switch off the fields options
232   inline void options_off (Field_Options options) {
233     OnError (::field_opts_off (field, options));
234   }
235
236   // Retrieve the fields options
237   inline Field_Options options () const {
238     return ::field_opts (field);
239   }
240
241   // Set the fields options
242   inline void set_options (Field_Options options) {
243     OnError (::set_field_opts (field, options));
244   }
245
246   // Mark the field as changed
247   inline void set_changed(bool changeFlag = TRUE) {
248     OnError(::set_field_status(field,changeFlag));
249   }
250
251   // Test whether or not the field is marked as changed
252   inline bool changed() const {
253     return ::field_status(field);
254   }
255
256   // Return the index of the field in the field array of a form
257   // or -1 if the field is not associated to a form
258   inline int (index)() const {
259     return ::field_index(field);
260   }
261
262   // Store a value in a fields buffer. The default buffer is nr. 0
263   inline void set_value(const char *val, int buffer = 0) {
264     OnError(::set_field_buffer(field,buffer,val));
265   }
266
267   // Retrieve the value of a fields buffer. The defaukt buffer is nr. 0
268   inline char* value(int buffer = 0) const {
269     return ::field_buffer(field,buffer);
270   }
271
272   // Set the validation type of the field.
273   inline void set_fieldtype(NCursesFieldType& f) {
274     ftype = &f;
275     f.set(*this); // A good friend may do that...
276   }
277
278   // Retrieve the validation type of the field.
279   inline NCursesFieldType* fieldtype() const {
280     return ftype;
281   }
282
283 };
284
285 //
286 // -------------------------------------------------------------------------
287 // The class representing a form, wrapping the lowlevel FORM struct
288 // -------------------------------------------------------------------------
289 //
290 class NCursesForm : public NCursesPanel {
291 protected:
292   FORM* form;  // the lowlevel structure
293
294 private:
295   NCursesWindow* sub;   // the subwindow object
296   bool b_sub_owner;     // is this our own subwindow?
297   bool b_framed;        // has the form a border?
298   bool b_autoDelete;    // Delete fields when deleting form?
299
300   NCursesFormField** my_fields; // The array of fields for this form
301
302   // This structure is used for the form's user data field to link the
303   // FORM* to the C++ object and to provide extra space for a user pointer.
304   typedef struct {
305     void*              m_user;      // the pointer for the user's data
306     const NCursesForm* m_back;      // backward pointer to C++ object
307     const FORM*        m_owner;
308   } UserHook;
309
310   // Get the backward pointer to the C++ object from a FORM
311   static inline NCursesForm* getHook(const FORM *f) {
312     UserHook* hook = (UserHook*)::form_userptr(f);
313     assert(hook != 0 && hook->m_owner==f);
314     return (NCursesForm*)(hook->m_back);
315   }
316
317   // This are the built-in hook functions in this C++ binding. In C++ we use
318   // virtual member functions (see below On_..._Init and On_..._Termination)
319   // to provide this functionality in an object oriented manner.
320   static void frm_init(FORM *);
321   static void frm_term(FORM *);
322   static void fld_init(FORM *);
323   static void fld_term(FORM *);
324   
325   // Calculate FIELD* array for the menu
326   FIELD** mapFields(NCursesFormField* nfields[]);
327
328 protected:  
329   // internal routines 
330   inline void set_user(void *user) {
331     UserHook* uptr = (UserHook*)::form_userptr (form);
332     assert (uptr != 0 && uptr->m_back==this && uptr->m_owner==form);
333     uptr->m_user = user;
334   }
335
336   inline void *get_user() {
337     UserHook* uptr = (UserHook*)::form_userptr (form);
338     assert (uptr != 0 && uptr->m_back==this && uptr->m_owner==form);
339     return uptr->m_user;
340   }  
341   
342   void InitForm (NCursesFormField* Fields[],
343                  bool with_frame,
344                  bool autoDeleteFields);
345
346   inline void OnError (int err) const THROWS(NCursesFormException) {
347     if (err != E_OK)
348       THROW(new NCursesFormException (err));
349   }
350
351   // this wraps the form_driver call.
352   virtual int driver (int c) ;
353
354   // 'Internal' constructor, builds an object without association to a
355   // field array.
356   NCursesForm( int  lines, 
357                int  cols, 
358                int  begin_y = 0, 
359                int  begin_x = 0) 
360     : NCursesPanel(lines,cols,begin_y,begin_x), 
361       form ((FORM*)0) {
362   }
363   
364 public:
365   // Create form for the default panel.
366   NCursesForm (NCursesFormField* Fields[],
367                bool with_frame=FALSE,         // reserve space for a frame?
368                bool autoDelete_Fields=FALSE)  // do automatic cleanup?
369     : NCursesPanel() {
370     InitForm(Fields, with_frame, autoDelete_Fields);
371   }
372
373   // Create a form in a panel with the given position and size.
374   NCursesForm (NCursesFormField* Fields[],
375                int  lines, 
376                int  cols, 
377                int  begin_y, 
378                int  begin_x,
379                bool with_frame=FALSE,        // reserve space for a frame?
380                bool autoDelete_Fields=FALSE) // do automatic cleanup?
381     : NCursesPanel(lines, cols, begin_y, begin_x) {
382       InitForm(Fields, with_frame, autoDelete_Fields);
383   }
384
385   virtual ~NCursesForm();
386
387   // Set the default attributes for the form
388   virtual void setDefaultAttributes();
389
390   // Retrieve current field of the form.
391   inline NCursesFormField* current_field() const {
392     return my_fields[::field_index(::current_field(form))];
393   }
394
395   // Set the forms subwindow
396   void setSubWindow(NCursesWindow& sub);
397
398   // Set these fields for the form
399   inline void setFields(NCursesFormField* Fields[]) {
400     OnError(::set_form_fields(form,mapFields(Fields)));    
401   }
402
403   // Remove the form from the screen
404   inline void unpost (void) { 
405     OnError (::unpost_form (form)); 
406   }
407   
408   // Post the form to the screen if flag is true, unpost it otherwise
409   inline void post(bool flag = TRUE) {
410     OnError (flag ? ::post_form(form) : ::unpost_form (form)); 
411   }
412
413   // Decorations
414   inline void frame(const char *title=NULL, const char* btitle=NULL) {
415     if (b_framed)
416       NCursesPanel::frame(title,btitle);
417     else
418       OnError(E_SYSTEM_ERROR);
419   }
420
421   inline void boldframe(const char *title=NULL, const char* btitle=NULL) {
422     if (b_framed)
423       NCursesPanel::boldframe(title,btitle);
424     else
425       OnError(E_SYSTEM_ERROR);
426   }
427   
428   inline void label(const char *topLabel, const char *bottomLabel) {
429     if (b_framed)
430       NCursesPanel::label(topLabel,bottomLabel);
431     else
432       OnError(E_SYSTEM_ERROR);
433   }
434
435   // -----
436   // Hooks
437   // -----
438
439   // Called after the form gets repositioned in its window.
440   // This is especially true if the form is posted.
441   virtual void On_Form_Init();
442
443   // Called before the form gets repositioned in its window.
444   // This is especially true if the form is unposted.
445   virtual void On_Form_Termination();
446
447   // Called after the field became the current field
448   virtual void On_Field_Init(NCursesFormField& field);
449
450   // Called before this field is left as current field.
451   virtual void On_Field_Termination(NCursesFormField& field);
452
453   // Calculate required window size for the form.
454   void scale(int& rows, int& cols) const {
455     OnError(::scale_form(form,&rows,&cols));
456   }
457
458   // Retrieve number of fields in the form.
459   int count() const {
460     return ::field_count(form);
461   }
462
463   // Make the page the current page of the form.
464   void set_page(int page) {
465     OnError(::set_form_page(form,page));
466   }
467
468   // Retrieve current page number
469   int page() const {
470     return ::form_page(form);
471   }
472
473   // Switch on the forms options
474   inline void options_on (Form_Options options) {
475     OnError (::form_opts_on (form, options));
476   }
477
478   // Switch off the forms options
479   inline void options_off (Form_Options options) {
480     OnError (::form_opts_off (form, options));
481   }
482
483   // Retrieve the forms options
484   inline Form_Options options () const {
485     return ::form_opts (form);
486   }
487
488   // Set the forms options
489   inline void set_options (Form_Options options) {
490     OnError (::set_form_opts (form, options));
491   }
492
493   // Are there more data in the current field after the data shown
494   inline bool data_ahead() const {
495     return ::data_ahead(form);
496   }
497
498   // Are there more data in the current field before the data shown
499   inline bool data_behind() const {
500     return ::data_behind(form);
501   }
502
503   // Position the cursor to the current field
504   inline void position_cursor () {
505     OnError (::pos_form_cursor (form));
506   }
507   // Set the current field
508   inline void set_current(NCursesFormField& F) {
509     OnError (::set_current_field(form, F.field));
510   }
511
512   // Provide a default key virtualization. Translate the keyboard
513   // code c into a form request code.
514   // The default implementation provides a hopefully straightforward
515   // mapping for the most common keystrokes and form requests.
516   virtual int virtualize(int c);
517
518   // Operators
519   inline NCursesFormField* operator[](int i) const {
520     if ( (i < 0) || (i >= ::field_count (form)) )
521       OnError (E_BAD_ARGUMENT);
522     return my_fields[i];
523   }
524
525   // Perform the menu's operation
526   // Return the field where you left the form.
527   virtual NCursesFormField* operator()(void);
528
529   // Exception handlers. The default is a Beep.
530   virtual void On_Request_Denied(int c) const;
531   virtual void On_Invalid_Field(int c) const;
532   virtual void On_Unknown_Command(int c) const;
533
534 };
535
536 //
537 // -------------------------------------------------------------------------
538 // This is the typical C++ typesafe way to allow to attach
539 // user data to a field of a form. Its assumed that the user
540 // data belongs to some class T. Use T as template argument
541 // to create a UserField.
542 // -------------------------------------------------------------------------
543 template<class T> class NCursesUserField : public NCursesFormField
544 {
545 public:
546   NCursesUserField (int rows,
547                     int cols,
548                     int first_row = 0,
549                     int first_col = 0,
550                     const T* p_UserData = (T*)0,
551                     int offscreen_rows = 0,
552                     int additional_buffers = 0)
553     : NCursesFormField (rows, cols,
554                         first_row, first_col,
555                         offscreen_rows, additional_buffers) {
556       if (field)
557         OnError(::set_field_userptr(field,(void *)p_UserData));
558   }
559
560   virtual ~NCursesUserField() {};
561
562   inline const T* UserData (void) const {
563     return (const T*)::field_userptr (field);
564   }
565
566   inline virtual void setUserData(const T* p_UserData) {
567     if (field)
568       OnError (::set_field_userptr (field, (void *)p_UserData));
569   }
570 };
571 //
572 // -------------------------------------------------------------------------
573 // The same mechanism is used to attach user data to a form
574 // -------------------------------------------------------------------------
575 //
576 template<class T> class NCursesUserForm : public NCursesForm
577 {
578 protected:
579   // 'Internal' constructor, builds an object without association to a
580   // field array.
581   NCursesUserForm( int  lines, 
582                    int  cols, 
583                    int  begin_y = 0, 
584                    int  begin_x = 0,
585                    const T* p_UserData = (T*)0) 
586     : NCursesForm(lines,cols,begin_y,begin_x) {
587       if (form)
588         set_user ((void *)p_UserData);
589   }
590
591 public:
592   NCursesUserForm (NCursesFormField Fields[], 
593                    bool with_frame=FALSE,
594                    bool autoDelete_Fields=FALSE)
595     : NCursesForm (Fields, with_frame, autoDelete_Fields) {
596   };
597
598   NCursesUserForm (NCursesFormField Fields[],
599                    const T* p_UserData = (T*)0,
600                    bool with_frame=FALSE,
601                    bool autoDelete_Fields=FALSE)
602     : NCursesForm (Fields, with_frame, autoDelete_Fields) {
603       if (form)
604         set_user ((void *)p_UserData);
605   };
606   
607   NCursesUserForm (NCursesFormField Fields[],
608                    int lines, 
609                    int cols, 
610                    int begin_y = 0, 
611                    int begin_x = 0,
612                    const T* p_UserData = (T*)0,
613                    bool with_frame=FALSE,
614                    bool autoDelete_Fields=FALSE)
615     : NCursesForm (Fields, lines, cols, begin_y, begin_x,
616                    with_frame, autoDelete_Fields) {
617       if (form)
618         set_user ((void *)p_UserData);
619   };  
620   
621   virtual ~NCursesUserForm() {
622   };
623   
624   inline T* UserData (void) const {
625     return (T*)get_user ();
626   };
627
628   inline virtual void setUserData (const T* p_UserData) {
629     if (form)
630       set_user ((void *)p_UserData);
631   }
632
633 };
634 //
635 // -------------------------------------------------------------------------
636 // Builtin Fieldtypes
637 // -------------------------------------------------------------------------
638 //
639 class Alpha_Field : public NCursesFieldType {
640 private:
641   int min_field_width;
642
643   void set(NCursesFormField& f) {
644     OnError(::set_field_type(f.get_field(),fieldtype,min_field_width));
645   }
646
647 public:
648   Alpha_Field(int width) 
649     : NCursesFieldType(TYPE_ALPHA),
650       min_field_width(width) {
651   }
652 };
653
654 class Alphanumeric_Field : public NCursesFieldType {
655 private:
656   int min_field_width;
657
658   void set(NCursesFormField& f) {
659     OnError(::set_field_type(f.get_field(),fieldtype,min_field_width));
660   }
661
662 public:
663   Alphanumeric_Field(int width) 
664     : NCursesFieldType(TYPE_ALNUM),
665       min_field_width(width) {
666   }
667 };
668
669 class Integer_Field : public NCursesFieldType {
670 private:
671   int precision;
672   long lower_limit, upper_limit;
673
674   void set(NCursesFormField& f) {
675     OnError(::set_field_type(f.get_field(),fieldtype,
676                              precision,lower_limit,upper_limit));
677   }
678
679 public:
680   Integer_Field(int prec, long low=0L, long high=0L)
681     : NCursesFieldType(TYPE_INTEGER), 
682       precision(prec), lower_limit(low), upper_limit(high) {
683   }
684 };
685
686 class Numeric_Field : public NCursesFieldType {
687 private:
688   int precision;
689   double lower_limit, upper_limit;
690
691   void set(NCursesFormField& f) {
692     OnError(::set_field_type(f.get_field(),fieldtype,
693                              precision,lower_limit,upper_limit));
694   }
695
696 public:
697   Numeric_Field(int prec, double low=0.0, double high=0.0)
698     : NCursesFieldType(TYPE_NUMERIC), 
699       precision(prec), lower_limit(low), upper_limit(high) {
700   }
701 };
702
703 class Regular_Expression_Field : public NCursesFieldType {
704 private:
705   char* regex;
706
707   void set(NCursesFormField& f) {
708     OnError(::set_field_type(f.get_field(),fieldtype,regex));
709   }
710
711 public:
712   Regular_Expression_Field(const char *expr)
713     : NCursesFieldType(TYPE_REGEXP) {
714       regex = new char[1+::strlen(expr)];
715       (strcpy)(regex,expr);
716   }
717
718   ~Regular_Expression_Field() {
719     delete[] regex;
720   }
721 };
722
723 class Enumeration_Field : public NCursesFieldType {
724 private:
725   char** list;
726   int case_sensitive;
727   int non_unique_matches;
728
729   void set(NCursesFormField& f) {
730     OnError(::set_field_type(f.get_field(),fieldtype,
731                              list,case_sensitive,non_unique_matches));
732   }
733 public:
734   Enumeration_Field(char* enums[],
735                     bool case_sens=FALSE,
736                     bool non_unique=FALSE)
737     : NCursesFieldType(TYPE_ENUM),
738       list(enums),
739       case_sensitive(case_sens?-1:0),
740       non_unique_matches(non_unique?-1:0) {
741   }
742 };
743
744 class IPV4_Address_Field : public NCursesFieldType {
745 private:
746   void set(NCursesFormField& f) {
747     OnError(::set_field_type(f.get_field(),fieldtype));
748   }
749
750 public:
751   IPV4_Address_Field() : NCursesFieldType(TYPE_IPV4) {
752   }
753 };
754 //
755 // -------------------------------------------------------------------------
756 // Abstract base class for User-Defined Fieldtypes
757 // -------------------------------------------------------------------------
758 //
759 class UserDefinedFieldType : public NCursesFieldType {
760   friend class UDF_Init; // Internal helper to set up statics 
761 private:
762   // For all C++ defined fieldtypes we need only one generic lowlevel
763   // FIELDTYPE* element.
764   static FIELDTYPE* generic_fieldtype; 
765
766 protected:
767   // This are the functions required by the low level libforms functions
768   // to construct a fieldtype.
769   static bool fcheck(FIELD *, const void*);
770   static bool ccheck(int c, const void *);
771   static void* makearg(va_list*);
772
773   void set(NCursesFormField& f) {
774     OnError(::set_field_type(f.get_field(),fieldtype,&f));
775   }
776
777 protected:
778   // Redefine this function to do a field validation. The argument
779   // is a reference to the field you should validate.
780   virtual bool field_check(NCursesFormField& f) = 0;
781
782   // Redefine this function to do a character validation. The argument
783   // is the character to be validated.
784   virtual bool char_check (int c) = 0;
785
786 public:
787   UserDefinedFieldType() : NCursesFieldType(generic_fieldtype) {
788   }
789 };
790 //
791 // -------------------------------------------------------------------------
792 // Abstract base class for User-Defined Fieldtypes with Choice functions
793 // -------------------------------------------------------------------------
794 //
795 class UserDefinedFieldType_With_Choice : public UserDefinedFieldType {
796   friend class UDF_Init; // Internal helper to set up statics 
797 private:
798   // For all C++ defined fieldtypes with choice functions we need only one 
799   // generic lowlevel FIELDTYPE* element.
800   static FIELDTYPE* generic_fieldtype_with_choice;
801
802   // This are the functions required by the low level libforms functions
803   // to construct a fieldtype with choice functions.
804   static bool next_choice(FIELD*, const void *);
805   static bool prev_choice(FIELD*, const void *);
806
807 protected:
808   // Redefine this function to do the retrieval of the next choice value.
809   // The argument is a reference to the field tobe examined.
810   virtual bool next    (NCursesFormField& f) = 0;
811
812   // Redefine this function to do the retrieval of the previous choice value.
813   // The argument is a reference to the field tobe examined.
814   virtual bool previous(NCursesFormField& f) = 0;
815
816 public:
817   UserDefinedFieldType_With_Choice() {
818     fieldtype = generic_fieldtype_with_choice;
819   }
820 };
821
822 #endif // _CURSESF_H
823