blob: f8f9665d9d247e8eacb0101758c3d23020b90d9c [file] [log] [blame]
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05301// * This makes emacs happy -*-Mode: C++;-*-
2/****************************************************************************
Steve Kondikae271bc2015-11-15 02:50:53 +01003 * Copyright (c) 1998-2012,2014 Free Software Foundation, Inc. *
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05304 * *
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
Steve Kondikae271bc2015-11-15 02:50:53 +010034// $Id: cursesm.h,v 1.30 2014/08/09 22:06:18 Adam.Jiang Exp $
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +053035
36#ifndef NCURSES_CURSESM_H_incl
37#define NCURSES_CURSESM_H_incl 1
38
39#include <cursesp.h>
40
41extern "C" {
42# include <menu.h>
43}
44//
45// -------------------------------------------------------------------------
46// This wraps the ITEM type of <menu.h>
47// -------------------------------------------------------------------------
48//
49class NCURSES_IMPEXP NCursesMenuItem
50{
51 friend class NCursesMenu;
52
53protected:
54 ITEM *item;
55
Steve Kondikae271bc2015-11-15 02:50:53 +010056 inline void OnError (int err) const THROW2(NCursesException const, NCursesMenuException) {
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +053057 if (err != E_OK)
58 THROW(new NCursesMenuException (err));
59 }
60
61public:
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 {
Steve Kondikae271bc2015-11-15 02:50:53 +010085 (void) rhs;
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +053086 }
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.
150typedef 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.
155class NCURSES_IMPEXP NCursesMenuCallbackItem : public NCursesMenuItem
156{
157private:
158 ITEMCALLBACK* p_fct;
159
160public:
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.
190extern "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//
202class NCURSES_IMPEXP NCursesMenu : public NCursesPanel
203{
204protected:
205 MENU *menu;
206
207private:
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
238protected:
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
Steve Kondikae271bc2015-11-15 02:50:53 +0100256 inline void OnError (int err) const THROW2(NCursesException const, NCursesMenuException) {
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530257 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
280public:
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//
598template<class T> class NCURSES_IMPEXP NCursesUserItem : public NCursesMenuItem
599{
600public:
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//
625template<class T> class NCURSES_IMPEXP NCursesUserMenu : public NCursesMenu
626{
627protected:
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)
Steve Kondikae271bc2015-11-15 02:50:53 +0100635 set_user (const_cast<void *>(reinterpret_cast<const void*>(p_UserData)));
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530636 }
637
638public:
Steve Kondikae271bc2015-11-15 02:50:53 +0100639 NCursesUserMenu (NCursesMenuItem* Items[],
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530640 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)
Steve Kondikae271bc2015-11-15 02:50:53 +0100645 set_user (const_cast<void *>(reinterpret_cast<const void*>(p_UserData)));
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530646 };
647
Steve Kondikae271bc2015-11-15 02:50:53 +0100648 NCursesUserMenu (NCursesMenuItem* Items[],
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530649 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)
Steve Kondikae271bc2015-11-15 02:50:53 +0100657 set_user (const_cast<void *>(reinterpret_cast<const void*>(p_UserData)));
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530658 };
659
660 virtual ~NCursesUserMenu() {
661 };
662
Steve Kondikae271bc2015-11-15 02:50:53 +0100663 inline T* UserData (void) {
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530664 return reinterpret_cast<T*>(get_user ());
665 };
666
667 inline virtual void setUserData (const T* p_UserData) {
668 if (menu)
Steve Kondikae271bc2015-11-15 02:50:53 +0100669 set_user (const_cast<void *>(reinterpret_cast<const void*>(p_UserData)));
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530670 }
671};
672
673#endif /* NCURSES_CURSESM_H_incl */