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