ncurses 6.0 - patch 20170624
[ncurses.git] / c++ / cursesm.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: cursesm.h,v 1.30 2014/08/09 22:06:18 Adam.Jiang Exp $
35
36 #ifndef NCURSES_CURSESM_H_incl
37 #define NCURSES_CURSESM_H_incl 1
38
39 #include <cursesp.h>
40
41 extern "C" {
42 #  include <menu.h>
43 }
44 //
45 // -------------------------------------------------------------------------
46 // This wraps the ITEM type of <menu.h>
47 // -------------------------------------------------------------------------
48 //
49 class NCURSES_IMPEXP NCursesMenuItem
50 {
51   friend class NCursesMenu;
52
53 protected:
54   ITEM *item;
55
56   inline void OnError (int err) const THROW2(NCursesException const, NCursesMenuException) {
57     if (err != E_OK)
58       THROW(new NCursesMenuException (err));
59   }
60
61 public:
62   NCursesMenuItem (const char* p_name     = NULL,
63                    const char* p_descript = NULL)
64     : item(0)
65   {
66     item = p_name ? ::new_item (p_name, p_descript) : STATIC_CAST(ITEM*)(0);
67     if (p_name && !item)
68       OnError (E_SYSTEM_ERROR);
69   }
70   // Create an item. If you pass both parameters as NULL, a delimiting
71   // item is constructed which can be used to terminate a list of
72   // NCursesMenu objects.
73
74   NCursesMenuItem& operator=(const NCursesMenuItem& rhs)
75   {
76     if (this != &rhs) {
77       *this = rhs;
78     }
79     return *this;
80   }
81
82   NCursesMenuItem(const NCursesMenuItem& rhs)
83     : item(0)
84   {
85     (void) rhs;
86   }
87
88   virtual ~NCursesMenuItem ();
89   // Release the items memory
90
91   inline const char* name () const {
92     return ::item_name (item);
93   }
94   // Name of the item
95
96   inline const char* description () const {
97     return ::item_description (item);
98   }
99   // Description of the item
100
101   inline int (index) (void) const {
102     return ::item_index (item);
103   }
104   // Index of the item in an item array (or -1)
105
106   inline void options_on (Item_Options opts) {
107     OnError (::item_opts_on (item, opts));
108   }
109   // Switch on the items options
110
111   inline void options_off (Item_Options opts) {
112     OnError (::item_opts_off (item, opts));
113   }
114   // Switch off the item's option
115
116   inline Item_Options options () const {
117     return ::item_opts (item);
118   }
119   // Retrieve the items options
120
121   inline void set_options (Item_Options opts) {
122     OnError (::set_item_opts (item, opts));
123   }
124   // Set the items options
125
126   inline void set_value (bool f) {
127     OnError (::set_item_value (item,f));
128   }
129   // Set/Reset the items selection state
130
131   inline bool value () const {
132     return ::item_value (item);
133   }
134   // Retrieve the items selection state
135
136   inline bool visible () const {
137     return ::item_visible (item);
138   }
139   // Retrieve visibility of the item
140
141   virtual bool action();
142   // Perform an action associated with this item; you may use this in an
143   // user supplied driver for a menu; you may derive from this class and
144   // overload action() to supply items with different actions.
145   // If an action returns true, the menu will be exited. The default action
146   // is to do nothing.
147 };
148
149 // Prototype for an items callback function.
150 typedef bool ITEMCALLBACK(NCursesMenuItem&);
151
152 // If you don't like to create a child class for individual items to
153 // overload action(), you may use this class and provide a callback
154 // function pointer for items.
155 class NCURSES_IMPEXP NCursesMenuCallbackItem : public NCursesMenuItem
156 {
157 private:
158   ITEMCALLBACK* p_fct;
159
160 public:
161   NCursesMenuCallbackItem(ITEMCALLBACK* fct       = NULL,
162                           const char* p_name      = NULL,
163                           const char* p_descript  = NULL )
164     : NCursesMenuItem (p_name, p_descript),
165       p_fct (fct) {
166   }
167
168   NCursesMenuCallbackItem& operator=(const NCursesMenuCallbackItem& rhs)
169   {
170     if (this != &rhs) {
171       *this = rhs;
172     }
173     return *this;
174   }
175
176   NCursesMenuCallbackItem(const NCursesMenuCallbackItem& rhs)
177     : NCursesMenuItem(rhs),
178       p_fct(0)
179   {
180   }
181
182   virtual ~NCursesMenuCallbackItem();
183
184   bool action();
185 };
186
187   // This are the built-in hook functions in this C++ binding. In C++ we use
188   // virtual member functions (see below On_..._Init and On_..._Termination)
189   // to provide this functionality in an object oriented manner.
190 extern "C" {
191   void _nc_xx_mnu_init(MENU *);
192   void _nc_xx_mnu_term(MENU *);
193   void _nc_xx_itm_init(MENU *);
194   void _nc_xx_itm_term(MENU *);
195 }
196
197 //
198 // -------------------------------------------------------------------------
199 // This wraps the MENU type of <menu.h>
200 // -------------------------------------------------------------------------
201 //
202 class NCURSES_IMPEXP NCursesMenu : public NCursesPanel
203 {
204 protected:
205   MENU *menu;
206
207 private:
208   NCursesWindow* sub;   // the subwindow object
209   bool b_sub_owner;     // is this our own subwindow?
210   bool b_framed;        // has the menu a border?
211   bool b_autoDelete;    // Delete items when deleting menu?
212
213   NCursesMenuItem** my_items; // The array of items for this menu
214
215   // This structure is used for the menu's user data field to link the
216   // MENU* to the C++ object and to provide extra space for a user pointer.
217   typedef struct {
218     void*              m_user;      // the pointer for the user's data
219     const NCursesMenu* m_back;      // backward pointer to C++ object
220     const MENU*        m_owner;
221   } UserHook;
222
223   // Get the backward pointer to the C++ object from a MENU
224   static inline NCursesMenu* getHook(const MENU *m) {
225     UserHook* hook = STATIC_CAST(UserHook*)(::menu_userptr(m));
226     assert(hook != 0 && hook->m_owner==m);
227     return const_cast<NCursesMenu*>(hook->m_back);
228   }
229
230   friend void _nc_xx_mnu_init(MENU *);
231   friend void _nc_xx_mnu_term(MENU *);
232   friend void _nc_xx_itm_init(MENU *);
233   friend void _nc_xx_itm_term(MENU *);
234
235   // Calculate ITEM* array for the menu
236   ITEM** mapItems(NCursesMenuItem* nitems[]);
237
238 protected:
239   // internal routines
240   inline void set_user(void *user) {
241     UserHook* uptr = STATIC_CAST(UserHook*)(::menu_userptr (menu));
242     assert (uptr != 0 && uptr->m_back==this && uptr->m_owner==menu);
243     uptr->m_user = user;
244   }
245
246   inline void *get_user() {
247     UserHook* uptr = STATIC_CAST(UserHook*)(::menu_userptr (menu));
248     assert (uptr != 0 && uptr->m_back==this && uptr->m_owner==menu);
249     return uptr->m_user;
250   }
251
252   void InitMenu (NCursesMenuItem* menu[],
253                  bool with_frame,
254                  bool autoDeleteItems);
255
256   inline void OnError (int err) const THROW2(NCursesException const, NCursesMenuException) {
257     if (err != E_OK)
258       THROW(new NCursesMenuException (this, err));
259   }
260
261   // this wraps the menu_driver call.
262   virtual int driver (int c) ;
263
264   // 'Internal' constructor to create a menu without association to
265   // an array of items.
266   NCursesMenu( int  nlines,
267                int  ncols,
268                int  begin_y = 0,
269                int  begin_x = 0)
270     : NCursesPanel(nlines,ncols,begin_y,begin_x),
271       menu (STATIC_CAST(MENU*)(0)),
272       sub(0),
273       b_sub_owner(0),
274       b_framed(0),
275       b_autoDelete(0),
276       my_items(0)
277   {
278   }
279
280 public:
281   // Make a full window size menu
282   NCursesMenu (NCursesMenuItem* Items[],
283                bool with_frame=FALSE,        // Reserve space for a frame?
284                bool autoDelete_Items=FALSE)  // Autocleanup of Items?
285     : NCursesPanel(),
286       menu(0),
287       sub(0),
288       b_sub_owner(0),
289       b_framed(0),
290       b_autoDelete(0),
291       my_items(0)
292   {
293       InitMenu(Items, with_frame, autoDelete_Items);
294   }
295
296   // Make a menu with a window of this size.
297   NCursesMenu (NCursesMenuItem* Items[],
298                int  nlines,
299                int  ncols,
300                int  begin_y = 0,
301                int  begin_x = 0,
302                bool with_frame=FALSE,        // Reserve space for a frame?
303                bool autoDelete_Items=FALSE)  // Autocleanup of Items?
304     : NCursesPanel(nlines, ncols, begin_y, begin_x),
305       menu(0),
306       sub(0),
307       b_sub_owner(0),
308       b_framed(0),
309       b_autoDelete(0),
310       my_items(0)
311   {
312       InitMenu(Items, with_frame, autoDelete_Items);
313   }
314
315   NCursesMenu& operator=(const NCursesMenu& rhs)
316   {
317     if (this != &rhs) {
318       *this = rhs;
319       NCursesPanel::operator=(rhs);
320     }
321     return *this;
322   }
323
324   NCursesMenu(const NCursesMenu& rhs)
325     : NCursesPanel(rhs),
326       menu(rhs.menu),
327       sub(rhs.sub),
328       b_sub_owner(rhs.b_sub_owner),
329       b_framed(rhs.b_framed),
330       b_autoDelete(rhs.b_autoDelete),
331       my_items(rhs.my_items)
332   {
333   }
334
335   virtual ~NCursesMenu ();
336
337   // Retrieve the menus subwindow
338   inline NCursesWindow& subWindow() const {
339     assert(sub!=NULL);
340     return *sub;
341   }
342
343   // Set the menus subwindow
344   void setSubWindow(NCursesWindow& sub);
345
346   // Set these items for the menu
347   inline void setItems(NCursesMenuItem* Items[]) {
348     OnError(::set_menu_items(menu,mapItems(Items)));
349   }
350
351   // Remove the menu from the screen
352   inline void unpost (void) {
353     OnError (::unpost_menu (menu));
354   }
355
356   // Post the menu to the screen if flag is true, unpost it otherwise
357   inline void post(bool flag = TRUE) {
358     flag ? OnError (::post_menu(menu)) : OnError (::unpost_menu (menu));
359   }
360
361   // Get the numer of rows and columns for this menu
362   inline void scale (int& mrows, int& mcols) const  {
363     OnError (::scale_menu (menu, &mrows, &mcols));
364   }
365
366   // Set the format of this menu
367   inline void set_format(int mrows, int mcols) {
368     OnError (::set_menu_format(menu, mrows, mcols));
369   }
370
371   // Get the format of this menu
372   inline void menu_format(int& rows,int& ncols) {
373     ::menu_format(menu,&rows,&ncols);
374   }
375
376   // Items of the menu
377   inline NCursesMenuItem* items() const {
378     return *my_items;
379   }
380
381   // Get the number of items in this menu
382   inline int count() const {
383     return ::item_count(menu);
384   }
385
386   // Get the current item (i.e. the one the cursor is located)
387   inline NCursesMenuItem* current_item() const {
388     return my_items[::item_index(::current_item(menu))];
389   }
390
391   // Get the marker string
392   inline const char* mark() const {
393     return ::menu_mark(menu);
394   }
395
396   // Set the marker string
397   inline void set_mark(const char *marker) {
398     OnError (::set_menu_mark (menu, marker));
399   }
400
401   // Get the name of the request code c
402   inline static const char* request_name(int c) {
403     return ::menu_request_name(c);
404   }
405
406   // Get the current pattern
407   inline char* pattern() const {
408     return ::menu_pattern(menu);
409   }
410
411   // true if there is a pattern match, false otherwise.
412   bool set_pattern (const char *pat);
413
414   // set the default attributes for the menu
415   // i.e. set fore, back and grey attribute
416   virtual void setDefaultAttributes();
417
418   // Get the menus background attributes
419   inline chtype back() const {
420     return ::menu_back(menu);
421   }
422
423   // Get the menus foreground attributes
424   inline chtype fore() const {
425     return ::menu_fore(menu);
426   }
427
428   // Get the menus grey attributes (used for unselectable items)
429   inline chtype grey() const {
430     return ::menu_grey(menu);
431   }
432
433   // Set the menus background attributes
434   inline chtype set_background(chtype a) {
435     return ::set_menu_back(menu,a);
436   }
437
438   // Set the menus foreground attributes
439   inline chtype set_foreground(chtype a) {
440     return ::set_menu_fore(menu,a);
441   }
442
443   // Set the menus grey attributes (used for unselectable items)
444   inline chtype set_grey(chtype a) {
445     return ::set_menu_grey(menu,a);
446   }
447
448   inline void options_on (Menu_Options opts) {
449     OnError (::menu_opts_on (menu,opts));
450   }
451
452   inline void options_off(Menu_Options opts) {
453     OnError (::menu_opts_off(menu,opts));
454   }
455
456   inline Menu_Options options() const {
457     return ::menu_opts(menu);
458   }
459
460   inline void set_options (Menu_Options opts) {
461     OnError (::set_menu_opts (menu,opts));
462   }
463
464   inline int pad() const {
465     return ::menu_pad(menu);
466   }
467
468   inline void set_pad (int padch) {
469     OnError (::set_menu_pad (menu, padch));
470   }
471
472   // Position the cursor to the current item
473   inline void position_cursor () const {
474     OnError (::pos_menu_cursor (menu));
475   }
476
477   // Set the current item
478   inline void set_current(NCursesMenuItem& I) {
479     OnError (::set_current_item(menu, I.item));
480   }
481
482   // Get the current top row of the menu
483   inline int top_row (void) const {
484     return ::top_row (menu);
485   }
486
487   // Set the current top row of the menu
488   inline void set_top_row (int row) {
489     OnError (::set_top_row (menu, row));
490   }
491
492   // spacing control
493   // Set the spacing for the menu
494   inline void setSpacing(int spc_description,
495                          int spc_rows,
496                          int spc_columns) {
497     OnError(::set_menu_spacing(menu,
498                                spc_description,
499                                spc_rows,
500                                spc_columns));
501   }
502
503   // Get the spacing info for the menu
504   inline void Spacing(int& spc_description,
505                       int& spc_rows,
506                       int& spc_columns) const {
507     OnError(::menu_spacing(menu,
508                            &spc_description,
509                            &spc_rows,
510                            &spc_columns));
511   }
512
513   // Decorations
514   inline void frame(const char *title=NULL, const char* btitle=NULL) {
515     if (b_framed)
516       NCursesPanel::frame(title,btitle);
517     else
518       OnError(E_SYSTEM_ERROR);
519   }
520
521   inline void boldframe(const char *title=NULL, const char* btitle=NULL) {
522     if (b_framed)
523       NCursesPanel::boldframe(title,btitle);
524     else
525       OnError(E_SYSTEM_ERROR);
526   }
527
528   inline void label(const char *topLabel, const char *bottomLabel) {
529     if (b_framed)
530       NCursesPanel::label(topLabel,bottomLabel);
531     else
532       OnError(E_SYSTEM_ERROR);
533   }
534
535   // -----
536   // Hooks
537   // -----
538
539   // Called after the menu gets repositioned in its window.
540   // This is especially true if the menu is posted.
541   virtual void On_Menu_Init();
542
543   // Called before the menu gets repositioned in its window.
544   // This is especially true if the menu is unposted.
545   virtual void On_Menu_Termination();
546
547   // Called after the item became the current item
548   virtual void On_Item_Init(NCursesMenuItem& item);
549
550   // Called before this item is left as current item.
551   virtual void On_Item_Termination(NCursesMenuItem& item);
552
553   // Provide a default key virtualization. Translate the keyboard
554   // code c into a menu request code.
555   // The default implementation provides a hopefully straightforward
556   // mapping for the most common keystrokes and menu requests.
557   virtual int virtualize(int c);
558
559
560   // Operators
561   inline NCursesMenuItem* operator[](int i) const {
562     if ( (i < 0) || (i >= ::item_count (menu)) )
563       OnError (E_BAD_ARGUMENT);
564     return (my_items[i]);
565   }
566
567   // Perform the menu's operation
568   // Return the item where you left the selection mark for a single
569   // selection menu, or NULL for a multivalued menu.
570   virtual NCursesMenuItem* operator()(void);
571
572   // --------------------
573   // Exception handlers
574   // Called by operator()
575   // --------------------
576
577   // Called if the request is denied
578   virtual void On_Request_Denied(int c) const;
579
580   // Called if the item is not selectable
581   virtual void On_Not_Selectable(int c) const;
582
583   // Called if pattern doesn't match
584   virtual void On_No_Match(int c) const;
585
586   // Called if the command is unknown
587   virtual void On_Unknown_Command(int c) const;
588
589 };
590 //
591 // -------------------------------------------------------------------------
592 // This is the typical C++ typesafe way to allow to attach
593 // user data to an item of a menu. Its assumed that the user
594 // data belongs to some class T. Use T as template argument
595 // to create a UserItem.
596 // -------------------------------------------------------------------------
597 //
598 template<class T> class NCURSES_IMPEXP NCursesUserItem : public NCursesMenuItem
599 {
600 public:
601   NCursesUserItem (const char* p_name,
602                    const char* p_descript = NULL,
603                    const T* p_UserData    = STATIC_CAST(T*)(0))
604     : NCursesMenuItem (p_name, p_descript) {
605       if (item)
606         OnError (::set_item_userptr (item, const_cast<void *>(reinterpret_cast<const void*>(p_UserData))));
607   }
608
609   virtual ~NCursesUserItem() {}
610
611   inline const T* UserData (void) const {
612     return reinterpret_cast<const T*>(::item_userptr (item));
613   };
614
615   inline virtual void setUserData(const T* p_UserData) {
616     if (item)
617       OnError (::set_item_userptr (item, const_cast<void *>(reinterpret_cast<const void *>(p_UserData))));
618   }
619 };
620 //
621 // -------------------------------------------------------------------------
622 // The same mechanism is used to attach user data to a menu
623 // -------------------------------------------------------------------------
624 //
625 template<class T> class NCURSES_IMPEXP NCursesUserMenu : public NCursesMenu
626 {
627 protected:
628   NCursesUserMenu( int  nlines,
629                    int  ncols,
630                    int  begin_y = 0,
631                    int  begin_x = 0,
632                    const T* p_UserData = STATIC_CAST(T*)(0))
633     : NCursesMenu(nlines,ncols,begin_y,begin_x) {
634       if (menu)
635         set_user (const_cast<void *>(reinterpret_cast<const void*>(p_UserData)));
636   }
637
638 public:
639   NCursesUserMenu (NCursesMenuItem* Items[],
640                    const T* p_UserData = STATIC_CAST(T*)(0),
641                    bool with_frame=FALSE,
642                    bool autoDelete_Items=FALSE)
643     : NCursesMenu (Items, with_frame, autoDelete_Items) {
644       if (menu)
645         set_user (const_cast<void *>(reinterpret_cast<const void*>(p_UserData)));
646   };
647
648   NCursesUserMenu (NCursesMenuItem* Items[],
649                    int nlines,
650                    int ncols,
651                    int begin_y = 0,
652                    int begin_x = 0,
653                    const T* p_UserData = STATIC_CAST(T*)(0),
654                    bool with_frame=FALSE)
655     : NCursesMenu (Items, nlines, ncols, begin_y, begin_x, with_frame) {
656       if (menu)
657         set_user (const_cast<void *>(reinterpret_cast<const void*>(p_UserData)));
658   };
659
660   virtual ~NCursesUserMenu() {
661   };
662
663   inline T* UserData (void) {
664     return reinterpret_cast<T*>(get_user ());
665   };
666
667   inline virtual void setUserData (const T* p_UserData) {
668     if (menu)
669       set_user (const_cast<void *>(reinterpret_cast<const void*>(p_UserData)));
670   }
671 };
672
673 #endif /* NCURSES_CURSESM_H_incl */