8873eca341c5748b94aa5fcae0127e757497c012
[ncurses.git] / c++ / cursesm.h
1 // * This makes emacs happy -*-Mode: C++;-*-
2 /****************************************************************************
3  * Copyright (c) 1998,1999,2000 Free Software Foundation, Inc.              *
4  *                                                                          *
5  * Permission is hereby granted, free of charge, to any person obtaining a  *
6  * copy of this software and associated documentation files (the            *
7  * "Software"), to deal in the Software without restriction, including      *
8  * without limitation the rights to use, copy, modify, merge, publish,      *
9  * distribute, distribute with modifications, sublicense, and/or sell       *
10  * copies of the Software, and to permit persons to whom the Software is    *
11  * furnished to do so, subject to the following conditions:                 *
12  *                                                                          *
13  * The above copyright notice and this permission notice shall be included  *
14  * in all copies or substantial portions of the Software.                   *
15  *                                                                          *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS  *
17  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF               *
18  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.   *
19  * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,   *
20  * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR    *
21  * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR    *
22  * THE USE OR OTHER DEALINGS IN THE SOFTWARE.                               *
23  *                                                                          *
24  * Except as contained in this notice, the name(s) of the above copyright   *
25  * holders shall not be used in advertising or otherwise to promote the     *
26  * sale, use or other dealings in this Software without prior written       *
27  * authorization.                                                           *
28  ****************************************************************************/
29
30 /****************************************************************************
31  *   Author: Juergen Pfeifer, 1997                                          *
32  *   Contact: http://www.familiepfeifer.de/Contact.aspx?Lang=en             *
33  ****************************************************************************/
34
35 // $Id: cursesm.h,v 1.16 2002/07/06 15:47:52 juergen Exp $
36
37 #ifndef NCURSES_CURSESM_H_incl
38 #define NCURSES_CURSESM_H_incl 1
39
40 #include <cursesp.h>
41
42 extern "C" {
43 #  include <menu.h>
44 }
45 //
46 // -------------------------------------------------------------------------
47 // This wraps the ITEM type of <menu.h>
48 // -------------------------------------------------------------------------
49 //
50 class NCURSES_IMPEXP NCursesMenuItem {
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 = p_name ? ::new_item (p_name, p_descript) : (ITEM*)0; 
65     if (p_name && !item)
66       OnError (E_SYSTEM_ERROR);
67   }
68   // Create an item. If you pass both parameters as NULL, a delimiting
69   // item is constructed which can be used to terminate a list of
70   // NCursesMenu objects.
71   
72   virtual ~NCursesMenuItem ();
73   // Release the items memory
74
75   inline const char* name () const {
76     return ::item_name (item);
77   }
78   // Name of the item
79
80   inline const char* description () const {
81     return ::item_description (item);
82   }
83   // Description of the item
84   
85   inline int (index) (void) const {
86     return ::item_index (item);
87   }
88   // Index of the item in an item array (or -1)
89
90   inline void options_on (Item_Options options) {
91     OnError (::item_opts_on (item, options));
92   }
93   // Switch on the items options
94
95   inline void options_off (Item_Options options) {
96     OnError (::item_opts_off (item, options));
97   }
98   // Switch off the item's option
99
100   inline Item_Options options () const {
101     return ::item_opts (item);
102   }
103   // Retrieve the items options
104
105   inline void set_options (Item_Options options) {
106     OnError (::set_item_opts (item, options));
107   }
108   // Set the items options
109
110   inline void set_value (bool f) {
111     OnError (::set_item_value (item,f));
112   }
113   // Set/Reset the items selection state
114
115   inline bool value () const {
116     return ::item_value (item);
117   }
118   // Retrieve the items selection state
119   
120   inline bool visible () const {
121     return ::item_visible (item);
122   }
123   // Retrieve visibility of the item
124
125   virtual bool action();
126   // Perform an action associated with this item; you may use this in an
127   // user supplied driver for a menu; you may derive from this class and
128   // overload action() to supply items with different actions.
129   // If an action returns true, the menu will be exited. The default action
130   // is to do nothing.
131 };
132
133 // Prototype for an items callback function.
134 typedef bool ITEMCALLBACK(NCursesMenuItem&);
135
136 // If you don't like to create a child class for individual items to
137 // overload action(), you may use this class and provide a callback
138 // function pointer for items.
139 class NCURSES_IMPEXP NCursesMenuCallbackItem : public NCursesMenuItem {
140 private:
141   ITEMCALLBACK* p_fct;
142
143 public:
144   NCursesMenuCallbackItem(ITEMCALLBACK* fct       = NULL,
145                           const char* p_name      = NULL,
146                           const char* p_descript  = NULL )
147     : NCursesMenuItem (p_name, p_descript),
148       p_fct (fct) {
149   }
150   
151   virtual ~NCursesMenuCallbackItem();
152
153   bool action();
154 };
155 //
156 // -------------------------------------------------------------------------
157 // This wraps the MENU type of <menu.h>
158 // -------------------------------------------------------------------------
159 //
160 class NCURSES_IMPEXP NCursesMenu : public NCursesPanel {
161 protected:
162   MENU *menu;
163
164 private:
165   NCursesWindow* sub;   // the subwindow object
166   bool b_sub_owner;     // is this our own subwindow?
167   bool b_framed;        // has the menu a border?
168   bool b_autoDelete;    // Delete items when deleting menu?
169
170   NCursesMenuItem** my_items; // The array of items for this menu
171
172   // This structure is used for the menu's user data field to link the
173   // MENU* to the C++ object and to provide extra space for a user pointer.
174   typedef struct {
175     void*              m_user;      // the pointer for the user's data
176     const NCursesMenu* m_back;      // backward pointer to C++ object
177     const MENU*        m_owner;
178   } UserHook;
179
180   // Get the backward pointer to the C++ object from a MENU
181   static inline NCursesMenu* getHook(const MENU *m) {
182     UserHook* hook = (UserHook*)::menu_userptr(m);
183     assert(hook != 0 && hook->m_owner==m);
184     return (NCursesMenu*)(hook->m_back);
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   static void mnu_init(MENU *);
191   static void mnu_term(MENU *);
192   static void itm_init(MENU *);
193   static void itm_term(MENU *);
194   
195   // Calculate ITEM* array for the menu
196   ITEM** mapItems(NCursesMenuItem* nitems[]);
197   
198 protected:
199   // internal routines 
200   inline void set_user(void *user) {
201     UserHook* uptr = (UserHook*)::menu_userptr (menu);
202     assert (uptr != 0 && uptr->m_back==this && uptr->m_owner==menu);
203     uptr->m_user = user;
204   }
205
206   inline void *get_user() {
207     UserHook* uptr = (UserHook*)::menu_userptr (menu);
208     assert (uptr != 0 && uptr->m_back==this && uptr->m_owner==menu);
209     return uptr->m_user;
210   }  
211   
212   void InitMenu (NCursesMenuItem* menu[],
213                  bool with_frame,
214                  bool autoDeleteItems);
215
216   inline void OnError (int err) const THROWS(NCursesMenuException) {
217     if (err != E_OK)
218       THROW(new NCursesMenuException (this, err));
219   }
220   
221   // this wraps the menu_driver call.
222   virtual int driver (int c) ;
223   
224   // 'Internal' constructor to create a menu without association to
225   // an array of items.
226   NCursesMenu( int  lines, 
227                int  cols, 
228                int  begin_y = 0, 
229                int  begin_x = 0) 
230     : NCursesPanel(lines,cols,begin_y,begin_x), 
231       menu ((MENU*)0) {
232   }
233
234 public:
235   // Make a full window size menu
236   NCursesMenu (NCursesMenuItem* Items[],
237                bool with_frame=FALSE,        // Reserve space for a frame?
238                bool autoDelete_Items=FALSE)  // Autocleanup of Items?
239     : NCursesPanel() {
240       InitMenu(Items, with_frame, autoDelete_Items);
241   }
242
243   // Make a menu with a window of this size.
244   NCursesMenu (NCursesMenuItem* Items[], 
245                int  lines, 
246                int  cols, 
247                int  begin_y = 0, 
248                int  begin_x = 0,
249                bool with_frame=FALSE,        // Reserve space for a frame?
250                bool autoDelete_Items=FALSE)  // Autocleanup of Items?
251     : NCursesPanel(lines, cols, begin_y, begin_x) {
252       InitMenu(Items, with_frame, autoDelete_Items);
253   }
254
255   virtual ~NCursesMenu ();
256
257   // Retrieve the menus subwindow
258   inline NCursesWindow& subWindow() const {
259     assert(sub!=NULL);
260     return *sub;
261   }
262
263   // Set the menus subwindow
264   void setSubWindow(NCursesWindow& sub);
265
266   // Set these items for the menu
267   inline void setItems(NCursesMenuItem* Items[]) {
268     OnError(::set_menu_items(menu,mapItems(Items)));    
269   }
270
271   // Remove the menu from the screen
272   inline void unpost (void) { 
273     OnError (::unpost_menu (menu)); 
274   }
275   
276   // Post the menu to the screen if flag is true, unpost it otherwise
277   inline void post(bool flag = TRUE) {
278     flag ? OnError (::post_menu(menu)) : OnError (::unpost_menu (menu)); 
279   }
280
281   // Get the numer of rows and columns for this menu
282   inline void scale (int& mrows, int& mcols) const  {
283     OnError (::scale_menu (menu, &mrows, &mcols));
284   }
285
286   // Set the format of this menu
287   inline void set_format(int mrows, int mcols) {
288     OnError (::set_menu_format(menu, mrows, mcols));
289   }
290   
291   // Get the format of this menu
292   inline void menu_format(int& rows,int& cols) { 
293     ::menu_format(menu,&rows,&cols); 
294   }
295   
296   // Items of the menu
297   inline NCursesMenuItem* items() const {
298     return *my_items; 
299   }
300
301   // Get the number of items in this menu
302   inline int count() const {
303     return ::item_count(menu); 
304   }
305
306   // Get the current item (i.e. the one the cursor is located)
307   inline NCursesMenuItem* current_item() const {
308     return my_items[::item_index(::current_item(menu))];
309   }
310   
311   // Get the marker string
312   inline const char* mark() const {
313     return ::menu_mark(menu);
314   }
315
316   // Set the marker string
317   inline void set_mark(const char *mark) {
318     OnError (::set_menu_mark (menu, mark));
319   }
320
321   // Get the name of the request code c
322   inline static const char* request_name(int c) {
323     return ::menu_request_name(c);
324   }
325
326   // Get the current pattern
327   inline char* pattern() const {
328     return ::menu_pattern(menu);
329   }
330
331   // true if there is a pattern match, false otherwise.
332   bool set_pattern (const char *pat);
333
334   // set the default attributes for the menu
335   // i.e. set fore, back and grey attribute
336   virtual void setDefaultAttributes();
337
338   // Get the menus background attributes
339   inline chtype back() const {
340     return ::menu_back(menu);
341   }
342
343   // Get the menus foreground attributes
344   inline chtype fore() const {
345     return ::menu_fore(menu);
346   }
347
348   // Get the menus grey attributes (used for unselectable items)
349   inline chtype grey() const {
350     return ::menu_grey(menu);
351   }
352
353   // Set the menus background attributes
354   inline chtype set_background(chtype a) {
355     return ::set_menu_back(menu,a);
356   }
357
358   // Set the menus foreground attributes
359   inline chtype set_foreground(chtype a) {
360     return ::set_menu_fore(menu,a);
361   }
362
363   // Set the menus grey attributes (used for unselectable items)
364   inline chtype set_grey(chtype a) {
365     return ::set_menu_grey(menu,a);
366   }
367   
368   inline void options_on (Menu_Options opts) {
369     OnError (::menu_opts_on (menu,opts));
370   }
371
372   inline void options_off(Menu_Options opts) {
373     OnError (::menu_opts_off(menu,opts));
374   }
375
376   inline Menu_Options options() const {
377     return ::menu_opts(menu);
378   }
379   
380   inline void set_options (Menu_Options opts) {
381     OnError (::set_menu_opts (menu,opts));
382   }
383
384   inline int pad() const {
385     return ::menu_pad(menu);
386   }
387
388   inline void set_pad (int padch) {
389     OnError (::set_menu_pad (menu, padch));
390   }
391   
392   // Position the cursor to the current item
393   inline void position_cursor () const {
394     OnError (::pos_menu_cursor (menu));
395   }
396
397   // Set the current item
398   inline void set_current(NCursesMenuItem& I) {
399     OnError (::set_current_item(menu, I.item));
400   }
401
402   // Get the current top row of the menu
403   inline int top_row (void) const {
404     return ::top_row (menu);
405   }
406
407   // Set the current top row of the menu
408   inline void set_top_row (int row) {
409     OnError (::set_top_row (menu, row));
410   }
411
412   // spacing control
413   // Set the spacing for the menu
414   inline void setSpacing(int spc_description,
415                          int spc_rows,
416                          int spc_columns) {
417     OnError(::set_menu_spacing(menu,
418                                spc_description,
419                                spc_rows,
420                                spc_columns));
421   }
422   
423   // Get the spacing info for the menu
424   inline void Spacing(int& spc_description,
425                       int& spc_rows,
426                       int& spc_columns) const {
427     OnError(::menu_spacing(menu,
428                            &spc_description,
429                            &spc_rows,
430                            &spc_columns));
431   }
432
433   // Decorations
434   inline void frame(const char *title=NULL, const char* btitle=NULL) {
435     if (b_framed)
436       NCursesPanel::frame(title,btitle);
437     else
438       OnError(E_SYSTEM_ERROR);
439   }
440
441   inline void boldframe(const char *title=NULL, const char* btitle=NULL) {
442     if (b_framed)
443       NCursesPanel::boldframe(title,btitle);
444     else
445       OnError(E_SYSTEM_ERROR);
446   }
447   
448   inline void label(const char *topLabel, const char *bottomLabel) {
449     if (b_framed)
450       NCursesPanel::label(topLabel,bottomLabel);
451     else
452       OnError(E_SYSTEM_ERROR);
453   }
454
455   // -----
456   // Hooks
457   // -----
458
459   // Called after the menu gets repositioned in its window.
460   // This is especially true if the menu is posted.
461   virtual void On_Menu_Init();
462
463   // Called before the menu gets repositioned in its window.
464   // This is especially true if the menu is unposted.
465   virtual void On_Menu_Termination();
466
467   // Called after the item became the current item
468   virtual void On_Item_Init(NCursesMenuItem& item);
469
470   // Called before this item is left as current item.
471   virtual void On_Item_Termination(NCursesMenuItem& item);
472   
473   // Provide a default key virtualization. Translate the keyboard
474   // code c into a menu request code.
475   // The default implementation provides a hopefully straightforward
476   // mapping for the most common keystrokes and menu requests.
477   virtual int virtualize(int c);
478
479
480   // Operators
481   inline NCursesMenuItem* operator[](int i) const {
482     if ( (i < 0) || (i >= ::item_count (menu)) )
483       OnError (E_BAD_ARGUMENT);
484     return (my_items[i]);
485   }
486
487   // Perform the menu's operation
488   // Return the item where you left the selection mark for a single
489   // selection menu, or NULL for a multivalued menu.
490   virtual NCursesMenuItem* operator()(void);
491
492   // --------------------
493   // Exception handlers
494   // Called by operator()
495   // --------------------
496
497   // Called if the request is denied
498   virtual void On_Request_Denied(int c) const;
499   
500   // Called if the item is not selectable
501   virtual void On_Not_Selectable(int c) const;
502
503   // Called if pattern doesn't match
504   virtual void On_No_Match(int c) const;
505
506   // Called if the command is unknown
507   virtual void On_Unknown_Command(int c) const;
508
509 };
510 //
511 // -------------------------------------------------------------------------
512 // This is the typical C++ typesafe way to allow to attach
513 // user data to an item of a menu. Its assumed that the user
514 // data belongs to some class T. Use T as template argument
515 // to create a UserItem.
516 // -------------------------------------------------------------------------
517 //
518 template<class T> class NCURSES_IMPEXP NCursesUserItem : public NCursesMenuItem
519 {
520 public:
521   NCursesUserItem (const char* p_name,
522                    const char* p_descript = NULL,
523                    const T* p_UserData    = (T*)0)
524     : NCursesMenuItem (p_name, p_descript) {
525       if (item)
526         OnError (::set_item_userptr (item, (void *)p_UserData));
527   };
528
529   virtual ~NCursesUserItem() {};
530
531   inline const T* UserData (void) const {
532     return (const T*)::item_userptr (item);
533   };
534
535   inline virtual void setUserData(const T* p_UserData) {
536     if (item)
537       OnError (::set_item_userptr (item, (void *)p_UserData));
538   }
539 };
540 //
541 // -------------------------------------------------------------------------
542 // The same mechanism is used to attach user data to a menu
543 // -------------------------------------------------------------------------
544 //
545 template<class T> class NCURSES_IMPEXP NCursesUserMenu : public NCursesMenu
546 {
547 protected:
548   NCursesUserMenu( int  lines, 
549                    int  cols, 
550                    int  begin_y = 0, 
551                    int  begin_x = 0,
552                    const T* p_UserData = (T*)0) 
553     : NCursesMenu(lines,cols,begin_y,begin_x) {
554       if (menu)
555         set_user ((void *)p_UserData);
556   }
557
558 public:
559   NCursesUserMenu (NCursesMenuItem Items[],
560                    const T* p_UserData = (T*)0,
561                    bool with_frame=FALSE,
562                    bool autoDelete_Items=FALSE)
563     : NCursesMenu (Items, with_frame, autoDelete_Items) {
564       if (menu)
565         set_user ((void *)p_UserData);
566   };
567   
568   NCursesUserMenu (NCursesMenuItem Items[],
569                    int lines, 
570                    int cols, 
571                    int begin_y = 0, 
572                    int begin_x = 0,
573                    const T* p_UserData = (T*)0,
574                    bool with_frame=FALSE)
575     : NCursesMenu (Items, lines, cols, begin_y, begin_x, with_frame) {
576       if (menu)
577         set_user ((void *)p_UserData);
578   };  
579   
580   virtual ~NCursesUserMenu() {
581   };
582   
583   inline T* UserData (void) const {
584     return (T*)get_user ();
585   };
586
587   inline virtual void setUserData (const T* p_UserData) {
588     if (menu)
589       set_user ((void *)p_UserData);
590   }
591 };
592
593 #endif // NCURSES_CURSESM_H_incl