Subversion Repositories Games.Descent

Rev

Blame | Last modification | View Log | Download | RSS feed

  1. /*
  2.  * Portions of this file are copyright Rebirth contributors and licensed as
  3.  * described in COPYING.txt.
  4.  * Portions of this file are copyright Parallax Software and licensed
  5.  * according to the Parallax license below.
  6.  * See COPYING.txt for license details.
  7.  
  8. THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX
  9. SOFTWARE CORPORATION ("PARALLAX").  PARALLAX, IN DISTRIBUTING THE CODE TO
  10. END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A
  11. ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS
  12. IN USING, DISPLAYING,  AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS
  13. SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE
  14. FREE PURPOSES.  IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE
  15. CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES.  THE END-USER UNDERSTANDS
  16. AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE.
  17. COPYRIGHT 1993-1999 PARALLAX SOFTWARE CORPORATION.  ALL RIGHTS RESERVED.
  18. */
  19.  
  20. /*
  21.  *
  22.  * Routines for menus.
  23.  *
  24.  */
  25.  
  26. #pragma once
  27.  
  28. #include "fwd-event.h"
  29.  
  30. #ifdef __cplusplus
  31. #include <cstdint>
  32. #include <algorithm>
  33. #include <memory>
  34. #include <stdexcept>
  35. #include <tuple>
  36. #include <type_traits>
  37. #include <utility>
  38. #include "fwd-window.h"
  39. #include "varutil.h"
  40. #include "dxxsconf.h"
  41. #include "dsx-ns.h"
  42. #include "fmtcheck.h"
  43. #include "ntstring.h"
  44.  
  45. struct newmenu;
  46. struct listbox;
  47.  
  48. enum nm_type : uint8_t
  49. {
  50.         NM_TYPE_MENU = 0,   // A menu item... when enter is hit on this, newmenu_do returns this item number
  51.         NM_TYPE_INPUT = 1,   // An input box... fills the text field in, and you need to fill in text_len field.
  52.         NM_TYPE_CHECK = 2,   // A check box. Set and get its status by looking at flags field (1=on, 0=off)
  53.         NM_TYPE_RADIO = 3,   // Same as check box, but only 1 in a group can be set at a time. Set group fields.
  54.         NM_TYPE_TEXT = 4,   // A line of text that does nothing.
  55.         NM_TYPE_NUMBER = 5,   // A numeric entry counter.  Changes value from min_value to max_value;
  56.         NM_TYPE_INPUT_MENU = 6,   // A inputbox that you hit Enter to edit, when done, hit enter and menu leaves.
  57.         NM_TYPE_SLIDER = 7,   // A slider from min_value to max_value. Draws with text_len chars.
  58. };
  59.  
  60. #define NM_MAX_TEXT_LEN     255
  61.  
  62. class newmenu_item
  63. {
  64.         struct input_common_type
  65.         {
  66.                 int text_len;
  67.                 /* Only used by imenu, but placing it in imenu_specific_type
  68.                  * makes newmenu_item non-POD.  Some users expect newmenu_item
  69.                  * to be POD.  Placing group here does not increase overall size
  70.                  * since number_slider_common_type also has two int members.
  71.                  */
  72.                 int group;
  73.         };
  74.         struct input_specific_type : input_common_type
  75.         {
  76.                 static constexpr std::integral_constant<unsigned, NM_TYPE_INPUT> nm_type{};
  77.         };
  78.         struct radio_specific_type
  79.         {
  80.                 static constexpr std::integral_constant<unsigned, NM_TYPE_RADIO> nm_type{};
  81.                 int group;          // What group this belongs to for radio buttons.
  82.         };
  83.         struct number_slider_common_type
  84.         {
  85.                 int min_value;
  86.                 int max_value;
  87.         };
  88.         struct number_specific_type : number_slider_common_type
  89.         {
  90.                 static constexpr std::integral_constant<unsigned, NM_TYPE_NUMBER> nm_type{};
  91.         };
  92.         struct imenu_specific_type : input_common_type
  93.         {
  94.                 static constexpr std::integral_constant<unsigned, NM_TYPE_INPUT_MENU> nm_type{};
  95.         };
  96.         struct slider_specific_type : number_slider_common_type
  97.         {
  98.                 static constexpr std::integral_constant<unsigned, NM_TYPE_SLIDER> nm_type{};
  99.         };
  100.         template <typename T, unsigned expected_type = T::nm_type>
  101.                 T &get_union_member(T &v)
  102.                 {
  103. #ifdef DXX_CONSTANT_TRUE
  104.                         if (DXX_CONSTANT_TRUE(type != expected_type))
  105.                                 DXX_ALWAYS_ERROR_FUNCTION(dxx_newmenu_trap_invalid_type, "invalid type access");
  106. #endif
  107.                         if (type != expected_type)
  108.                                 throw std::runtime_error("invalid type access");
  109.                         return v;
  110.                 }
  111. public:
  112.         int     value;          // For checkboxes and radio buttons, this is 1 if marked initially, else 0
  113.         union {
  114.                 input_specific_type nm_private_input;
  115.                 radio_specific_type nm_private_radio;
  116.                 number_specific_type nm_private_number;
  117.                 imenu_specific_type nm_private_imenu;
  118.                 slider_specific_type nm_private_slider;
  119.         };
  120.         input_specific_type &input() {
  121.                 return get_union_member(nm_private_input);
  122.         }
  123.         radio_specific_type &radio() {
  124.                 return get_union_member(nm_private_radio);
  125.         }
  126.         number_specific_type &number() {
  127.                 return get_union_member(nm_private_number);
  128.         }
  129.         imenu_specific_type &imenu() {
  130.                 return get_union_member(nm_private_imenu);
  131.         }
  132.         slider_specific_type &slider() {
  133.                 return get_union_member(nm_private_slider);
  134.         }
  135.         number_slider_common_type *number_or_slider() {
  136.                 return (type == nm_private_number.nm_type || type == nm_private_slider.nm_type)
  137.                         ? &nm_private_number
  138.                         : nullptr;
  139.         }
  140.         input_common_type *input_or_menu() {
  141.                 return (type == nm_private_input.nm_type || type == nm_private_imenu.nm_type)
  142.                         ? &nm_private_input
  143.                         : nullptr;
  144.         }
  145.         char    *text;          // The text associated with this item.
  146.         // The rest of these are used internally by by the menu system, so don't set 'em!!
  147.         short   x, y;
  148.         short   w, h;
  149.         short   right_offset;
  150.         nm_type type;           // What kind of item this is, see NM_TYPE_????? defines
  151.         ntstring<NM_MAX_TEXT_LEN> saved_text;
  152. };
  153.  
  154. namespace dcx {
  155. template <typename T>
  156. using newmenu_subfunction_t = int(*)(newmenu *menu,const d_event &event, T *userdata);
  157. using newmenu_subfunction = newmenu_subfunction_t<void>;
  158.  
  159. class unused_newmenu_userdata_t;
  160. constexpr newmenu_subfunction_t<const unused_newmenu_userdata_t> unused_newmenu_subfunction = nullptr;
  161. constexpr const unused_newmenu_userdata_t *unused_newmenu_userdata = nullptr;
  162. }
  163.  
  164. int newmenu_do2(const char *title, const char *subtitle, uint_fast32_t nitems, newmenu_item *item, newmenu_subfunction subfunction, void *userdata, int citem, const char *filename);
  165.  
  166. // Pass an array of newmenu_items and it processes the menu. It will
  167. // return a -1 if Esc is pressed, otherwise, it returns the index of
  168. // the item that was current when Enter was was selected.
  169. // The subfunction function accepts standard events, plus additional
  170. // NEWMENU events in future.  Just pass NULL if you don't want this,
  171. // or return 0 where you don't want to override the default behaviour.
  172. // Title draws big, Subtitle draw medium sized.  You can pass NULL for
  173. // either/both of these if you don't want them.
  174. // Same as above, only you can pass through what background bitmap to use.
  175. template <typename T>
  176. int newmenu_do2(const char *const title, const char *const subtitle, const uint_fast32_t nitems, newmenu_item *const item, const newmenu_subfunction_t<T> subfunction, T *const userdata, const int citem, const char *const filename)
  177. {
  178.         return newmenu_do2(title, subtitle, nitems, item, reinterpret_cast<newmenu_subfunction>(subfunction), static_cast<void *>(userdata), citem, filename);
  179. }
  180.  
  181. template <typename T>
  182. int newmenu_do2(const char *const title, const char *const subtitle, const uint_fast32_t nitems, newmenu_item *const item, const newmenu_subfunction_t<const T> subfunction, const T *const userdata, const int citem, const char *const filename)
  183. {
  184.         return newmenu_do2(title, subtitle, nitems, item, reinterpret_cast<newmenu_subfunction>(subfunction), static_cast<void *>(const_cast<T *>(userdata)), citem, filename);
  185. }
  186.  
  187. template <typename T>
  188. static inline int newmenu_do(const char *const title, const char *const subtitle, const uint_fast32_t nitems, newmenu_item *const item, const newmenu_subfunction_t<T> subfunction, T *const userdata)
  189. {
  190.         return newmenu_do2( title, subtitle, nitems, item, subfunction, userdata, 0, NULL );
  191. }
  192.  
  193. template <std::size_t N, typename T>
  194. static inline int newmenu_do(const char *const title, const char *const subtitle, std::array<newmenu_item, N> &items, const newmenu_subfunction_t<T> subfunction, T *const userdata)
  195. {
  196.         return newmenu_do(title, subtitle, items.size(), &items.front(), subfunction, userdata);
  197. }
  198.  
  199. // Same as above, only you can pass through what item is initially selected.
  200. template <typename T>
  201. static inline int newmenu_do1(const char *const title, const char *const subtitle, const uint_fast32_t nitems, newmenu_item *const item, const newmenu_subfunction_t<T> subfunction, T *const userdata, const int citem)
  202. {
  203.         return newmenu_do2( title, subtitle, nitems, item, subfunction, userdata, citem, NULL );
  204. }
  205.  
  206. #ifdef dsx
  207. namespace dsx {
  208. newmenu *newmenu_do4( const char * title, const char * subtitle, uint_fast32_t nitems, newmenu_item * item, newmenu_subfunction subfunction, void *userdata, int citem, const char * filename, int TinyMode, int TabsFlag );
  209.  
  210. static inline newmenu *newmenu_do3( const char * title, const char * subtitle, uint_fast32_t nitems, newmenu_item * item, newmenu_subfunction subfunction, void *userdata, int citem, const char * filename )
  211. {
  212.         return newmenu_do4( title, subtitle, nitems, item, subfunction, userdata, citem, filename, 0, 0 );
  213. }
  214.  
  215. // Same as above, but returns menu instead of citem
  216. template <typename T>
  217. static newmenu *newmenu_do3(const char *const title, const char *const subtitle, const uint_fast32_t nitems, newmenu_item *const item, const newmenu_subfunction_t<T> subfunction, T *const userdata, const int citem, const char *const filename)
  218. {
  219.         return newmenu_do3(title, subtitle, nitems, item, reinterpret_cast<newmenu_subfunction>(subfunction), static_cast<void *>(userdata), citem, filename);
  220. }
  221.  
  222. template <typename T>
  223. static newmenu *newmenu_do3(const char *const title, const char *const subtitle, const uint_fast32_t nitems, newmenu_item *const item, const newmenu_subfunction_t<const T> subfunction, const T *const userdata, const int citem, const char *const filename)
  224. {
  225.         return newmenu_do3(title, subtitle, nitems, item, reinterpret_cast<newmenu_subfunction>(subfunction), static_cast<void *>(const_cast<T *>(userdata)), citem, filename);
  226. }
  227.  
  228. static inline newmenu *newmenu_dotiny( const char * title, const char * subtitle, uint_fast32_t nitems, newmenu_item * item, int TabsFlag, newmenu_subfunction subfunction, void *userdata )
  229. {
  230.         return newmenu_do4( title, subtitle, nitems, item, subfunction, userdata, 0, NULL, 1, TabsFlag );
  231. }
  232.  
  233. // Tiny menu with GAME_FONT
  234. template <typename T>
  235. static newmenu *newmenu_dotiny(const char *const title, const char *const subtitle, const uint_fast32_t nitems, newmenu_item *const item, const int TabsFlag, const newmenu_subfunction_t<T> subfunction, T *const userdata)
  236. {
  237.         return newmenu_dotiny(title, subtitle, nitems, item, TabsFlag, reinterpret_cast<newmenu_subfunction>(subfunction), static_cast<void *>(userdata));
  238. }
  239. }
  240. #endif
  241.  
  242. // Basically the same as do2 but sets reorderitems flag for weapon priority menu a bit redundant to get lose of a global variable but oh well...
  243. void newmenu_doreorder(const char * title, const char * subtitle, uint_fast32_t nitems, newmenu_item *item);
  244.  
  245. // Sample Code:
  246. /*
  247. {
  248.         int mmn;
  249.         newmenu_item mm[8];
  250.         char xtext[21];
  251.  
  252.         strcpy( xtext, "John" );
  253.  
  254.         mm[0].type=NM_TYPE_MENU; mm[0].text="Play game";
  255.         mm[1].type=NM_TYPE_INPUT; mm[1].text=xtext; mm[1].text_len=20;
  256.         mm[2].type=NM_TYPE_CHECK; mm[2].value=0; mm[2].text="check box";
  257.         mm[3].type=NM_TYPE_TEXT; mm[3].text="-pickone-";
  258.         mm[4].type=NM_TYPE_RADIO; mm[4].value=1; mm[4].group=0; mm[4].text="Radio #1";
  259.         mm[5].type=NM_TYPE_RADIO; mm[5].value=1; mm[5].group=0; mm[5].text="Radio #2";
  260.         mm[6].type=NM_TYPE_RADIO; mm[6].value=1; mm[6].group=0; mm[6].text="Radio #3";
  261.         mm[7].type=NM_TYPE_PERCENT; mm[7].value=50; mm[7].text="Volume";
  262.  
  263.         mmn = newmenu_do("Descent", "Sample Menu", 8, mm, NULL );
  264. }
  265.  
  266. */
  267.  
  268. // This function pops up a messagebox and returns which choice was selected...
  269. // Example:
  270. // nm_messagebox( "Title", "Subtitle", 2, "Ok", "Cancel", "There are %d objects", nobjects );
  271. // Returns 0 through nchoices-1.
  272. //int nm_messagebox(const char *title, int nchoices, ...);
  273. #define nm_messagebox(T,N,...)  nm_messagebox_a##N((T), ##__VA_ARGS__)
  274. #define nm_messagebox_a1(T,A1                           ,F,...) vnm_messagebox_aN(T,nm_messagebox_tie(A1                        ),F,##__VA_ARGS__)
  275. #define nm_messagebox_a2(T,A1,A2                        ,F,...) vnm_messagebox_aN(T,nm_messagebox_tie(A1,A2                     ),F,##__VA_ARGS__)
  276. #define nm_messagebox_a3(T,A1,A2,A3                     ,F,...) vnm_messagebox_aN(T,nm_messagebox_tie(A1,A2,A3          ),F,##__VA_ARGS__)
  277. #define nm_messagebox_a4(T,A1,A2,A3,A4          ,F,...) vnm_messagebox_aN(T,nm_messagebox_tie(A1,A2,A3,A4       ),F,##__VA_ARGS__)
  278. #define nm_messagebox_a5(T,A1,A2,A3,A4,A5       ,F,...) vnm_messagebox_aN(T,nm_messagebox_tie(A1,A2,A3,A4,A5),F,##__VA_ARGS__)
  279.  
  280. typedef cstring_tie<5> nm_messagebox_tie;
  281.  
  282. int nm_messagebox_str(const char *title, const nm_messagebox_tie &tie, const char *str) __attribute_nonnull((3));
  283. int vnm_messagebox_aN(const char *title, const nm_messagebox_tie &tie, const char *format, ...) __attribute_format_printf(3, 4);
  284. #define vnm_messagebox_aN(A1,A2,F,...)  dxx_call_printf_checked(vnm_messagebox_aN,nm_messagebox_str,(A1,A2),(F),##__VA_ARGS__)
  285.  
  286. newmenu_item *newmenu_get_items(newmenu *menu);
  287. int newmenu_get_nitems(newmenu *menu);
  288. int newmenu_get_citem(newmenu *menu);
  289. void nm_draw_background(grs_canvas &, int x1, int y1, int x2, int y2);
  290. void nm_restore_background(int x, int y, int w, int h);
  291.  
  292. extern const char *Newmenu_allowed_chars;
  293.  
  294. // Example listbox callback function...
  295. // int lb_callback( int * citem, int *nitems, char * items[], int *keypress )
  296. // {
  297. //      int i;
  298. //
  299. //      if ( *keypress = KEY_CTRLED+KEY_D )     {
  300. //              if ( *nitems > 1 )      {
  301. //                      unlink( items[*citem] );                // Delete the file
  302. //                      for (i=*citem; i<*nitems-1; i++ )       {
  303. //                              items[i] = items[i+1];
  304. //                      }
  305. //                      *nitems = *nitems - 1;
  306. //                      free( items[*nitems] );
  307. //                      items[*nitems] = NULL;
  308. //                      return 1;       // redraw;
  309. //              }
  310. //                      *keypress = 0;
  311. //      }
  312. //      return 0;
  313. // }
  314.  
  315. window *listbox_get_window(listbox *lb);
  316. extern const char **listbox_get_items(listbox *lb);
  317. extern int listbox_get_citem(listbox *lb);
  318. extern void listbox_delete_item(listbox *lb, int item);
  319.  
  320. namespace dcx {
  321. template <typename T>
  322. using listbox_subfunction_t = window_event_result (*)(listbox *menu,const d_event &event, T *userdata);
  323.  
  324. class unused_listbox_userdata_t;
  325. constexpr listbox_subfunction_t<const unused_listbox_userdata_t> *unused_listbox_subfunction = nullptr;
  326. constexpr const unused_listbox_userdata_t *unused_listbox_userdata = nullptr;
  327. }
  328.  
  329. listbox *newmenu_listbox1(const char * title, uint_fast32_t nitems, const char *items[], int allow_abort_flag, int default_item, listbox_subfunction_t<void> listbox_callback, void *userdata);
  330.  
  331. template <typename T>
  332. listbox *newmenu_listbox1(const char *const title, const uint_fast32_t nitems, const char *items[], const int allow_abort_flag, const int default_item, const listbox_subfunction_t<T> listbox_callback, T *const userdata)
  333. {
  334.         return newmenu_listbox1(title, nitems, items, allow_abort_flag, default_item, reinterpret_cast<listbox_subfunction_t<void>>(listbox_callback), static_cast<void *>(userdata));
  335. }
  336.  
  337. template <typename T>
  338. listbox *newmenu_listbox1(const char *const title, const uint_fast32_t nitems, const char *items[], const int allow_abort_flag, const int default_item, const listbox_subfunction_t<T> listbox_callback, std::unique_ptr<T> userdata)
  339. {
  340.         auto r = newmenu_listbox1(title, nitems, items, allow_abort_flag, default_item, reinterpret_cast<listbox_subfunction_t<void>>(listbox_callback), static_cast<void *>(userdata.get()));
  341.         userdata.release();
  342.         return r;
  343. }
  344.  
  345. template <typename T>
  346. listbox *newmenu_listbox(const char *const title, const uint_fast32_t nitems, const char *items[], const int allow_abort_flag, const listbox_subfunction_t<T> listbox_callback, T *const userdata)
  347. {
  348.         return newmenu_listbox1(title, nitems, items, allow_abort_flag, 0, reinterpret_cast<listbox_subfunction_t<void>>(listbox_callback), static_cast<void *>(userdata));
  349. }
  350.  
  351. //should be called whenever the palette changes
  352. extern void newmenu_free_background();
  353.  
  354. static inline void nm_set_item_menu(newmenu_item &ni, const char *text)
  355. {
  356.         ni.type = NM_TYPE_MENU;
  357.         ni.text = const_cast<char *>(text);
  358. }
  359.  
  360. __attribute_nonnull()
  361. __attribute_warn_unused_result
  362. static inline newmenu_item nm_item_menu(const char *text)
  363. {
  364.         newmenu_item i;
  365.         return nm_set_item_menu(i, text), i;
  366. }
  367.  
  368. __attribute_nonnull()
  369. static inline void nm_set_item_input(newmenu_item &ni, unsigned len, char *text)
  370. {
  371.         ni.type = NM_TYPE_INPUT;
  372.         ni.text = text;
  373.         ni.input().text_len = len - 1;
  374. }
  375.  
  376. template <std::size_t len>
  377. static inline void nm_set_item_input(newmenu_item &ni, char (&text)[len])
  378. {
  379.         nm_set_item_input(ni, len, text);
  380. }
  381.  
  382. template <std::size_t len>
  383. static inline void nm_set_item_input(newmenu_item &ni, std::array<char, len> &text)
  384. {
  385.         nm_set_item_input(ni, len, text.data());
  386. }
  387.  
  388. template <typename... T>
  389. __attribute_warn_unused_result
  390. static inline newmenu_item nm_item_input(T &&... t)
  391. {
  392.         newmenu_item i;
  393.         return nm_set_item_input(i, std::forward<T>(t)...), i;
  394. }
  395.  
  396. __attribute_nonnull()
  397. static inline void nm_set_item_checkbox(newmenu_item &ni, const char *text, unsigned checked)
  398. {
  399.         ni.type = NM_TYPE_CHECK;
  400.         ni.text = const_cast<char *>(text);
  401.         ni.value = checked;
  402. }
  403.  
  404. __attribute_nonnull()
  405. static inline void nm_set_item_text(newmenu_item &ni, const char *text)
  406. {
  407.         ni.type = NM_TYPE_TEXT;
  408.         ni.text = const_cast<char *>(text);
  409. }
  410.  
  411. __attribute_nonnull()
  412. __attribute_warn_unused_result
  413. static inline newmenu_item nm_item_text(const char *text)
  414. {
  415.         newmenu_item i;
  416.         return nm_set_item_text(i, text), i;
  417. }
  418.  
  419. __attribute_nonnull()
  420. static inline void nm_set_item_radio(newmenu_item &ni, const char *text, unsigned checked, unsigned grp)
  421. {
  422.         ni.type = NM_TYPE_RADIO;
  423.         ni.text = const_cast<char *>(text);
  424.         ni.value = checked;
  425.         auto &radio = ni.radio();
  426.         radio.group = grp;
  427. }
  428.  
  429. __attribute_nonnull()
  430. static inline void nm_set_item_number(newmenu_item &ni, const char *text, unsigned now, unsigned low, unsigned high)
  431. {
  432.         ni.type = NM_TYPE_NUMBER;
  433.         ni.text = const_cast<char *>(text);
  434.         ni.value = now;
  435.         auto &number = ni.number();
  436.         number.min_value = low;
  437.         number.max_value = high;
  438. }
  439.  
  440. __attribute_nonnull()
  441. static inline void nm_set_item_slider(newmenu_item &ni, const char *text, unsigned now, unsigned low, unsigned high)
  442. {
  443.         ni.type = NM_TYPE_SLIDER;
  444.         ni.text = const_cast<char *>(text);
  445.         ni.value = now;
  446.         auto &slider = ni.slider();
  447.         slider.min_value = low;
  448.         slider.max_value = high;
  449. }
  450.  
  451. #define NORMAL_CHECK_BOX    "\201"
  452. #define CHECKED_CHECK_BOX   "\202"
  453.  
  454. #define NORMAL_RADIO_BOX    "\177"
  455. #define CHECKED_RADIO_BOX   "\200"
  456. #define CURSOR_STRING       "_"
  457. #define SLIDER_LEFT         "\203"  // 131
  458. #define SLIDER_RIGHT        "\204"  // 132
  459. #define SLIDER_MIDDLE       "\205"  // 133
  460. #define SLIDER_MARKER       "\206"  // 134
  461.  
  462. #define BORDERX (15*(SWIDTH/320))
  463. #define BORDERY (15*(SHEIGHT/200))
  464.  
  465. #define DXX_NEWMENU_VARIABLE    m
  466. #define DXX_MENUITEM(VERB, TYPE, ...)   DXX_MENUITEM_V_##VERB(TYPE, ## __VA_ARGS__)
  467. #define DXX_MENUITEM_V_ENUM(TYPE,S,OPT,...)     OPT,
  468. #define DXX_MENUITEM_V_COUNT(TYPE,...)  +1
  469. #define DXX_MENUITEM_V_ADD(TYPE,S,OPT,...)      DXX_MENUITEM_V_ADD_T_##TYPE(S, OPT, ## __VA_ARGS__)
  470. #define DXX_MENUITEM_V_READ(TYPE,S,OPT,...)     DXX_MENUITEM_V_READ_T_##TYPE(S, OPT, ## __VA_ARGS__)
  471. #define DXX_MENUITEM_V_ADD_T_CHECK(S,OPT,V)     \
  472.         nm_set_item_checkbox(((DXX_NEWMENU_VARIABLE)[(OPT)]), (S), (V));
  473. #define DXX_MENUITEM_V_ADD_T_FCHECK(S,OPT,V,F)  DXX_MENUITEM_V_ADD_T_CHECK(S,OPT,(V) & (F))
  474. #define DXX_MENUITEM_V_ADD_T_RADIO(S,OPT,C,G)   \
  475.         nm_set_item_radio(((DXX_NEWMENU_VARIABLE)[(OPT)]), (S), (C), (G));
  476. #define DXX_MENUITEM_V_ADD_T_NUMBER(S,OPT,V,MIN,MAX)    \
  477.         nm_set_item_number(((DXX_NEWMENU_VARIABLE)[(OPT)]), (S), (V), (MIN), (MAX));
  478. #define DXX_MENUITEM_V_ADD_T_SLIDER(S,OPT,V,MIN,MAX)    \
  479.         nm_set_item_slider(((DXX_NEWMENU_VARIABLE)[(OPT)]), (S), (V), (MIN), (MAX));
  480. #define DXX_MENUITEM_V_ADD_T_SCALE_SLIDER(S,OPT,V,MIN,MAX,SCALE)        \
  481.         DXX_MENUITEM_V_ADD_T_SLIDER((S),(OPT),(V) / (SCALE),(MIN),(MAX))
  482. #define DXX_MENUITEM_V_ADD_T_MENU(S,OPT)        \
  483.         nm_set_item_menu(((DXX_NEWMENU_VARIABLE)[(OPT)]), (S));
  484. #define DXX_MENUITEM_V_ADD_T_TEXT(S,OPT)        \
  485.         nm_set_item_text(((DXX_NEWMENU_VARIABLE)[(OPT)]), (S));
  486. #define DXX_MENUITEM_V_ADD_T_INPUT(S,OPT)       \
  487.         nm_set_item_input(((DXX_NEWMENU_VARIABLE)[(OPT)]),(S));
  488. #define DXX_MENUITEM_V_READ_T_CHECK(S,OPT,V)    \
  489.         (V) = (DXX_NEWMENU_VARIABLE)[(OPT)].value;
  490. #define DXX_MENUITEM_V_READ_T_FCHECK(S,OPT,V,F) \
  491.         ( DXX_BEGIN_COMPOUND_STATEMENT {        \
  492.                 auto &dxx_menuitem_read_fcheck_v = (V); \
  493.                 const auto dxx_menuitem_read_fcheck_f = (F);    \
  494.                 if ((DXX_NEWMENU_VARIABLE)[(OPT)].value)        \
  495.                         dxx_menuitem_read_fcheck_v |= dxx_menuitem_read_fcheck_f;       \
  496.                 else    \
  497.                         dxx_menuitem_read_fcheck_v &= ~dxx_menuitem_read_fcheck_f;      \
  498.         } DXX_END_COMPOUND_STATEMENT );
  499. #define DXX_MENUITEM_V_READ_T_RADIO(S,OPT,C,G)  /* handled specially */
  500. #define DXX_MENUITEM_V_READ_T_NUMBER(S,OPT,V,MIN,MAX)   \
  501.         (V) = (DXX_NEWMENU_VARIABLE)[(OPT)].value;
  502. #define DXX_MENUITEM_V_READ_T_SLIDER(S,OPT,V,MIN,MAX)   \
  503.         (V) = (DXX_NEWMENU_VARIABLE)[(OPT)].value;
  504. #define DXX_MENUITEM_V_READ_T_SCALE_SLIDER(S,OPT,V,MIN,MAX,SCALE)       \
  505.         (V) = (DXX_NEWMENU_VARIABLE)[(OPT)].value * (SCALE);
  506. #define DXX_MENUITEM_V_READ_T_MENU(S,OPT)       /* handled specially */
  507. #define DXX_MENUITEM_V_READ_T_TEXT(S,OPT)       /* handled specially */
  508. #define DXX_MENUITEM_V_READ_T_INPUT(S,OPT)      /* handled specially */
  509.  
  510. template <typename T, typename B>
  511. class menu_bit_wrapper_t
  512. {
  513.         using M = decltype(std::declval<const T &>() & std::declval<B>());
  514.         std::tuple<T &, B> m_data;
  515.         enum
  516.         {
  517.                 m_mask = 0,
  518.                 m_bit = 1,
  519.         };
  520.         T &get_mask()
  521.         {
  522.                 return std::get<m_mask>(m_data);
  523.         }
  524.         const T &get_mask() const
  525.         {
  526.                 return std::get<m_mask>(m_data);
  527.         }
  528.         B get_bit() const
  529.         {
  530.                 return std::get<m_bit>(m_data);
  531.         }
  532. public:
  533.         constexpr menu_bit_wrapper_t(T &t, B bit) :
  534.                 m_data(t, bit)
  535.         {
  536.         }
  537.         constexpr operator M() const
  538.         {
  539.                 return get_mask() & get_bit();
  540.         }
  541.         menu_bit_wrapper_t &operator=(const bool n)
  542.         {
  543.                 auto &m = get_mask();
  544.                 const auto b = get_bit();
  545.                 if (n)
  546.                         m |= b;
  547.                 else
  548.                         m &= ~b;
  549.                 return *this;
  550.         }
  551. };
  552.  
  553. template <typename T, typename B>
  554. static constexpr menu_bit_wrapper_t<T, B> menu_bit_wrapper(T &t, B b)
  555. {
  556.         return {t, b};
  557. }
  558.  
  559. template <unsigned B, typename T>
  560. class menu_number_bias_wrapper_t
  561. {
  562.         std::tuple<T &, std::integral_constant<unsigned, B>> m_data;
  563. #define m_value std::get<0>(m_data)
  564. #define m_bias  std::get<1>(m_data)
  565. public:
  566.         constexpr menu_number_bias_wrapper_t(T &t) :
  567.                 m_data(t, {})
  568.         {
  569.         }
  570.         constexpr operator T() const
  571.         {
  572.                 return m_value + m_bias;
  573.         }
  574.         menu_number_bias_wrapper_t &operator=(const T n)
  575.         {
  576.                 m_value = n - m_bias;
  577.                 return *this;
  578.         }
  579. #undef m_bias
  580. #undef m_value
  581. };
  582.  
  583. template <unsigned B, typename T>
  584. static constexpr menu_number_bias_wrapper_t<B, T> menu_number_bias_wrapper(T &t)
  585. {
  586.         return t;
  587. }
  588.  
  589. #endif
  590.