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