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