ncurses 5.9 - patch 20130928
[ncurses.git] / c++ / cursesf.h
1 // * This makes emacs happy -*-Mode: C++;-*-
2 /****************************************************************************
3  * Copyright (c) 1998-2011,2012 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.31 2012/12/29 21:49:58 tom 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 *>(p_UserData));
677   }
678
679 public:
680   NCursesUserForm (NCursesFormField* Fields[],
681                    const T* p_UserData = STATIC_CAST(T*)(0),
682                    bool with_frame=FALSE,
683                    bool autoDelete_Fields=FALSE)
684     : NCursesForm (Fields, with_frame, autoDelete_Fields) {
685       if (form)
686         set_user (const_cast<void *>(p_UserData));
687   };
688
689   NCursesUserForm (NCursesFormField* Fields[],
690                    int nlines,
691                    int ncols,
692                    int begin_y = 0,
693                    int begin_x = 0,
694                    const T* p_UserData = STATIC_CAST(T*)(0),
695                    bool with_frame=FALSE,
696                    bool autoDelete_Fields=FALSE)
697     : NCursesForm (Fields, nlines, ncols, begin_y, begin_x,
698                    with_frame, autoDelete_Fields) {
699       if (form)
700         set_user (const_cast<void *>(p_UserData));
701   };
702
703   virtual ~NCursesUserForm() {
704   };
705
706   inline T* UserData (void) const {
707     return reinterpret_cast<T*>(get_user ());
708   };
709
710   inline virtual void setUserData (const T* p_UserData) {
711     if (form)
712       set_user (const_cast<void *>(p_UserData));
713   }
714
715 };
716 //
717 // -------------------------------------------------------------------------
718 // Builtin Fieldtypes
719 // -------------------------------------------------------------------------
720 //
721 class NCURSES_IMPEXP Alpha_Field : public NCursesFieldType
722 {
723 private:
724   int min_field_width;
725
726   void set(NCursesFormField& f) {
727     OnError(::set_field_type(f.get_field(),fieldtype,min_field_width));
728   }
729
730 public:
731   Alpha_Field(int width)
732     : NCursesFieldType(TYPE_ALPHA),
733       min_field_width(width) {
734   }
735 };
736
737 class NCURSES_IMPEXP Alphanumeric_Field : public NCursesFieldType
738 {
739 private:
740   int min_field_width;
741
742   void set(NCursesFormField& f) {
743     OnError(::set_field_type(f.get_field(),fieldtype,min_field_width));
744   }
745
746 public:
747   Alphanumeric_Field(int width)
748     : NCursesFieldType(TYPE_ALNUM),
749       min_field_width(width) {
750   }
751 };
752
753 class NCURSES_IMPEXP Integer_Field : public NCursesFieldType
754 {
755 private:
756   int precision;
757   long lower_limit, upper_limit;
758
759   void set(NCursesFormField& f) {
760     OnError(::set_field_type(f.get_field(),fieldtype,
761                              precision,lower_limit,upper_limit));
762   }
763
764 public:
765   Integer_Field(int prec, long low=0L, long high=0L)
766     : NCursesFieldType(TYPE_INTEGER),
767       precision(prec), lower_limit(low), upper_limit(high) {
768   }
769 };
770
771 class NCURSES_IMPEXP Numeric_Field : public NCursesFieldType
772 {
773 private:
774   int precision;
775   double lower_limit, upper_limit;
776
777   void set(NCursesFormField& f) {
778     OnError(::set_field_type(f.get_field(),fieldtype,
779                              precision,lower_limit,upper_limit));
780   }
781
782 public:
783   Numeric_Field(int prec, double low=0.0, double high=0.0)
784     : NCursesFieldType(TYPE_NUMERIC),
785       precision(prec), lower_limit(low), upper_limit(high) {
786   }
787 };
788
789 class NCURSES_IMPEXP Regular_Expression_Field : public NCursesFieldType
790 {
791 private:
792   char* regex;
793
794   void set(NCursesFormField& f) {
795     OnError(::set_field_type(f.get_field(),fieldtype,regex));
796   }
797
798   void copy_regex(const char *source)
799   {
800     regex = new char[1 + ::strlen(source)];
801     (::strcpy)(regex, source);
802   }
803
804 public:
805   Regular_Expression_Field(const char *expr)
806     : NCursesFieldType(TYPE_REGEXP),
807       regex(NULL)
808   {
809     copy_regex(expr);
810   }
811
812   Regular_Expression_Field& operator=(const Regular_Expression_Field& rhs)
813   {
814     if (this != &rhs) {
815       *this = rhs;
816       copy_regex(rhs.regex);
817       NCursesFieldType::operator=(rhs);
818     }
819     return *this;
820   }
821
822   Regular_Expression_Field(const Regular_Expression_Field& rhs)
823     : NCursesFieldType(rhs),
824       regex(NULL)
825   {
826     copy_regex(rhs.regex);
827   }
828
829   ~Regular_Expression_Field() {
830     delete[] regex;
831   }
832 };
833
834 class NCURSES_IMPEXP Enumeration_Field : public NCursesFieldType
835 {
836 private:
837   const char** list;
838   int case_sensitive;
839   int non_unique_matches;
840
841   void set(NCursesFormField& f) {
842     OnError(::set_field_type(f.get_field(),fieldtype,
843                              list,case_sensitive,non_unique_matches));
844   }
845 public:
846   Enumeration_Field(const char* enums[],
847                     bool case_sens=FALSE,
848                     bool non_unique=FALSE)
849     : NCursesFieldType(TYPE_ENUM),
850       list(enums),
851       case_sensitive(case_sens ? -1 : 0),
852       non_unique_matches(non_unique ? -1 : 0) {
853   }
854
855   Enumeration_Field& operator=(const Enumeration_Field& rhs)
856   {
857     if (this != &rhs) {
858       *this = rhs;
859       NCursesFieldType::operator=(rhs);
860     }
861     return *this;
862   }
863
864   Enumeration_Field(const Enumeration_Field& rhs)
865     : NCursesFieldType(rhs),
866       list(rhs.list),
867       case_sensitive(rhs.case_sensitive),
868       non_unique_matches(rhs.non_unique_matches)
869   {
870   }
871 };
872
873 class NCURSES_IMPEXP IPV4_Address_Field : public NCursesFieldType
874 {
875 private:
876   void set(NCursesFormField& f) {
877     OnError(::set_field_type(f.get_field(),fieldtype));
878   }
879
880 public:
881   IPV4_Address_Field() : NCursesFieldType(TYPE_IPV4) {
882   }
883 };
884
885 extern "C" {
886   bool _nc_xx_fld_fcheck(FIELD *, const void*);
887   bool _nc_xx_fld_ccheck(int c, const void *);
888   void* _nc_xx_fld_makearg(va_list*);
889 }
890
891 //
892 // -------------------------------------------------------------------------
893 // Abstract base class for User-Defined Fieldtypes
894 // -------------------------------------------------------------------------
895 //
896 class NCURSES_IMPEXP UserDefinedFieldType : public NCursesFieldType
897 {
898   friend class UDF_Init; // Internal helper to set up statics
899 private:
900   // For all C++ defined fieldtypes we need only one generic lowlevel
901   // FIELDTYPE* element.
902   static FIELDTYPE* generic_fieldtype;
903
904 protected:
905   // This are the functions required by the low level libforms functions
906   // to construct a fieldtype.
907   friend bool _nc_xx_fld_fcheck(FIELD *, const void*);
908   friend bool _nc_xx_fld_ccheck(int c, const void *);
909   friend void* _nc_xx_fld_makearg(va_list*);
910
911   void set(NCursesFormField& f) {
912     OnError(::set_field_type(f.get_field(),fieldtype,&f));
913   }
914
915 protected:
916   // Redefine this function to do a field validation. The argument
917   // is a reference to the field you should validate.
918   virtual bool field_check(NCursesFormField& f) = 0;
919
920   // Redefine this function to do a character validation. The argument
921   // is the character to be validated.
922   virtual bool char_check (int c) = 0;
923
924 public:
925   UserDefinedFieldType() : NCursesFieldType(generic_fieldtype) {
926   }
927 };
928
929 extern "C" {
930   bool _nc_xx_next_choice(FIELD*, const void *);
931   bool _nc_xx_prev_choice(FIELD*, const void *);
932 }
933
934 //
935 // -------------------------------------------------------------------------
936 // Abstract base class for User-Defined Fieldtypes with Choice functions
937 // -------------------------------------------------------------------------
938 //
939 class NCURSES_IMPEXP UserDefinedFieldType_With_Choice : public UserDefinedFieldType
940 {
941   friend class UDF_Init; // Internal helper to set up statics
942 private:
943   // For all C++ defined fieldtypes with choice functions we need only one
944   // generic lowlevel FIELDTYPE* element.
945   static FIELDTYPE* generic_fieldtype_with_choice;
946
947   // This are the functions required by the low level libforms functions
948   // to construct a fieldtype with choice functions.
949   friend bool _nc_xx_next_choice(FIELD*, const void *);
950   friend bool _nc_xx_prev_choice(FIELD*, const void *);
951
952 protected:
953   // Redefine this function to do the retrieval of the next choice value.
954   // The argument is a reference to the field tobe examined.
955   virtual bool next    (NCursesFormField& f) = 0;
956
957   // Redefine this function to do the retrieval of the previous choice value.
958   // The argument is a reference to the field tobe examined.
959   virtual bool previous(NCursesFormField& f) = 0;
960
961 public:
962   UserDefinedFieldType_With_Choice() {
963     fieldtype = generic_fieldtype_with_choice;
964   }
965 };
966
967 #endif /* NCURSES_CURSESF_H_incl */