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