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