cursesm.h 19 KB

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