Subversion Repositories Games.Descent

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
1 pmbaty 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