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