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
#include <memory>
21
#include <stdlib.h>
22
#include <math.h>
23
#include <string.h>
24
#include "physfsx.h"
25
#include "maths.h"
26
#include "pstypes.h"
27
#include "gr.h"
28
#include "key.h"
29
#include "ui.h"
30
#include "u_mem.h"
31
#include "func.h"
32
#include "dxxerror.h"
33
 
34
#include "compiler-range_for.h"
35
#include "d_range.h"
36
#include <memory>
37
 
38
namespace dcx {
39
 
40
#define MAX_NUM_PADS 20
41
 
42
static std::array<std::unique_ptr<UI_GADGET_BUTTON>, 17> Pad;
43
static std::array<std::unique_ptr<UI_KEYPAD>, MAX_NUM_PADS> KeyPad;
44
static int active_pad;
45
 
46
static int desc_x, desc_y;
47
 
48
static std::array<int, 17> HotKey, HotKey1;
49
 
50
int ui_pad_get_current()
51
{
52
        return active_pad;
53
}
54
 
55
void ui_pad_init()
56
{
57
        KeyPad = {};
58
        active_pad = 0;
59
}
60
 
61
void ui_pad_close()
62
{
63
        KeyPad = {};
64
}
65
 
66
typedef PHYSFSX_gets_line_t<100>::line_t keypad_input_line_t;
67
 
68
static keypad_input_line_t::const_iterator find_fake_comma(keypad_input_line_t::const_iterator i, keypad_input_line_t::const_iterator e)
69
{
70
        auto is_fake_comma = [](char c) {
71
                return !c || static_cast<uint8_t>(c) == 179;
72
        };
73
        return std::find_if(i, e, is_fake_comma);
74
}
75
 
76
template <bool append, char eor>
77
static keypad_input_line_t::const_iterator set_row(keypad_input_line_t::const_iterator i, const keypad_input_line_t::const_iterator e, UI_KEYPAD::buttontext_element_t &r)
78
{
79
        const auto oe = r.end();
80
        auto ob = r.begin();
81
        if (append)
82
                ob = std::find(ob, oe, 0);
83
        auto comma0 = find_fake_comma(i, e);
84
        if (comma0 == e)
85
                /* Start not found */
86
                return comma0;
87
        const auto comma1 = find_fake_comma(++ comma0, e);
88
        std::size_t id = std::distance(comma0, comma1);
89
        std::size_t od = std::distance(ob, oe);
90
        if (!od)
91
                /* Output buffer full */
92
                return comma1;
93
        -- od;
94
        std::size_t md = std::min(id, od);
95
        std::copy_n(comma0, md, ob);
96
        std::advance(ob, md);
97
        assert(ob != oe);
98
        if (ob == oe)
99
                -- ob;
100
        if (eor)
101
        {
102
                /* Add EOR if room */
103
                auto on = std::next(ob);
104
                if (on != oe)
105
                        *ob++ = eor;
106
        }
107
        *ob = 0;
108
        return comma1;
109
}
110
 
111
template <bool append, char eor, typename... T>
112
static keypad_input_line_t::const_iterator set_row(keypad_input_line_t::const_iterator i, const keypad_input_line_t::const_iterator e, UI_KEYPAD::buttontext_element_t &r, T &... t)
113
{
114
        return set_row<append, eor>(set_row<append, eor>(i, e, r), e, t...);
115
}
116
 
117
static void set_short_row(keypad_input_line_t::const_iterator i, const keypad_input_line_t::const_iterator e, UI_KEYPAD::buttontext_element_t &r)
118
{
119
        typedef std::reverse_iterator<keypad_input_line_t::const_iterator> reverse_iterator;
120
        const auto oe = r.end();
121
        auto ob = std::find(r.begin(), oe, 0);
122
        std::size_t od = std::distance(ob, oe);
123
        if (!od)
124
                return;
125
        -- od;
126
        auto ie = std::find(i, e, 0);
127
        auto ri = reverse_iterator(i);
128
        auto comma0 = std::find(reverse_iterator(ie), ri, 179);
129
        if (comma0 == ri)
130
                return;
131
        auto comma1 = std::find(++ comma0, ri, 180);
132
        if (comma1 == ri)
133
                return;
134
        auto bcomma1 = comma1.base();
135
        std::size_t id = std::distance(comma0.base(), bcomma1);
136
        std::size_t md = std::min(id, od);
137
        std::copy_n(bcomma1, md, ob);
138
        std::advance(ob, md);
139
        assert(ob != oe);
140
        if (ob == oe)
141
                -- ob;
142
        auto on = std::next(ob);
143
        if (on != oe)
144
                *ob++ = '\n';
145
        *ob = 0;
146
}
147
 
148
static std::unique_ptr<UI_GADGET_BUTTON> ui_create_pad_gadget(UI_DIALOG &dlg, uint_fast32_t x, uint_fast32_t y, uint_fast32_t w, uint_fast32_t h, const grs_font &font)
149
{
150
        auto r = ui_add_gadget_button(&dlg, x, y, w, h, nullptr, nullptr);
151
        r->canvas->cv_font = &font;
152
        return r;
153
}
154
 
155
void ui_pad_activate(UI_DIALOG &dlg, uint_fast32_t x, uint_fast32_t y)
156
{
157
        const uint_fast32_t bw = 56;
158
        const uint_fast32_t bh = 30;
159
        const uint_fast32_t x5 = x + 5;
160
        const uint_fast32_t y20 = y + 20;
161
        const auto &font = *ui_small_font.get();
162
        const auto fx = [=](uint_fast32_t col) {
163
                return x5 + (bw * col);
164
        };
165
        const auto fy = [=](uint_fast32_t row) {
166
                return y20 + (bh * row);
167
        };
168
        const auto fw = [=](uint_fast32_t w) {
169
                return bw * w;
170
        };
171
        const auto fh = [=](uint_fast32_t h) {
172
                return bh * h;
173
        };
174
        const auto ui_add_pad_gadget = [&dlg, &font](uint_fast32_t n, uint_fast32_t gx, uint_fast32_t gy, uint_fast32_t w, uint_fast32_t h) {
175
                Pad[n] = ui_create_pad_gadget(dlg, gx, gy, w, h, font);
176
        };
177
 
178
        int w,h,row,col, n;
179
 
180
        desc_x = x+2;
181
        desc_y = y-17;
182
 
183
        n=0; row = 0; col = 0; w = 1; h = 1;
184
        ui_add_pad_gadget(n, fx(col), fy(row), fw(w), fh(h));
185
        n=1; row = 0; col = 1; w = 1; h = 1;
186
        ui_add_pad_gadget(n, fx(col), fy(row), fw(w), fh(h));
187
        n=2; row = 0; col = 2; w = 1; h = 1;
188
        ui_add_pad_gadget(n, fx(col), fy(row), fw(w), fh(h));
189
        n=3; row = 0; col = 3; w = 1; h = 1;
190
        ui_add_pad_gadget(n, fx(col), fy(row), fw(w), fh(h));
191
        n=4; row = 1; col = 0; w = 1; h = 1;
192
        ui_add_pad_gadget(n, fx(col), fy(row), fw(w), fh(h));
193
        n=5; row = 1; col = 1; w = 1; h = 1;
194
        ui_add_pad_gadget(n, fx(col), fy(row), fw(w), fh(h));
195
        n=6; row = 1; col = 2; w = 1; h = 1;
196
        ui_add_pad_gadget(n, fx(col), fy(row), fw(w), fh(h));
197
        n=7; row = 1; col = 3; w = 1; h = 2;
198
        ui_add_pad_gadget(n, fx(col), fy(row), fw(w), fh(h));
199
        n=8; row = 2; col = 0; w = 1; h = 1;
200
        ui_add_pad_gadget(n, fx(col), fy(row), fw(w), fh(h));
201
        n=9; row = 2; col = 1; w = 1; h = 1;
202
        ui_add_pad_gadget(n, fx(col), fy(row), fw(w), fh(h));
203
        n=10; row = 2; col = 2; w = 1; h = 1;
204
        ui_add_pad_gadget(n, fx(col), fy(row), fw(w), fh(h));
205
        n=11; row = 3; col = 0; w = 1; h = 1;
206
        ui_add_pad_gadget(n, fx(col), fy(row), fw(w), fh(h));
207
        n=12; row = 3; col = 1; w = 1; h = 1;
208
        ui_add_pad_gadget(n, fx(col), fy(row), fw(w), fh(h));
209
        n=13; row = 3; col = 2; w = 1; h = 1;
210
        ui_add_pad_gadget(n, fx(col), fy(row), fw(w), fh(h));
211
        n=14; row = 3; col = 3; w = 1; h = 2;
212
        ui_add_pad_gadget(n, fx(col), fy(row), fw(w), fh(h));
213
        n=15; row = 4; col = 0; w = 2; h = 1;
214
        ui_add_pad_gadget(n, fx(col), fy(row), fw(w), fh(h));
215
        n=16; row = 4; col = 2; w = 1; h = 1;
216
        ui_add_pad_gadget(n, fx(col), fy(row), fw(w), fh(h));
217
 
218
        HotKey[0] = KEY_CTRLED + KEY_NUMLOCK;
219
        HotKey[1] = KEY_CTRLED + KEY_PADDIVIDE;
220
        HotKey[2] = KEY_CTRLED + KEY_PADMULTIPLY;
221
        HotKey[3] = KEY_CTRLED + KEY_PADMINUS;
222
        HotKey[4] = KEY_CTRLED + KEY_PAD7;
223
        HotKey[5] = KEY_CTRLED + KEY_PAD8;
224
        HotKey[6] = KEY_CTRLED + KEY_PAD9;
225
        HotKey[7] = KEY_CTRLED + KEY_PADPLUS;
226
        HotKey[8] = KEY_CTRLED + KEY_PAD4;
227
        HotKey[9] = KEY_CTRLED + KEY_PAD5;
228
        HotKey[10] = KEY_CTRLED + KEY_PAD6;
229
        HotKey[11] = KEY_CTRLED + KEY_PAD1;
230
        HotKey[12] = KEY_CTRLED + KEY_PAD2;
231
        HotKey[13] = KEY_CTRLED + KEY_PAD3;
232
        HotKey[14] = KEY_CTRLED + KEY_PADENTER;
233
        HotKey[15] = KEY_CTRLED + KEY_PAD0;
234
        HotKey[16] = KEY_CTRLED + KEY_PADPERIOD;
235
 
236
        HotKey1[0] = KEY_SHIFTED + KEY_CTRLED + KEY_NUMLOCK;
237
        HotKey1[1] = KEY_SHIFTED + KEY_CTRLED + KEY_PADDIVIDE;
238
        HotKey1[2] = KEY_SHIFTED + KEY_CTRLED + KEY_PADMULTIPLY;
239
        HotKey1[3] = KEY_SHIFTED + KEY_CTRLED + KEY_PADMINUS;
240
        HotKey1[4] = KEY_SHIFTED + KEY_CTRLED + KEY_PAD7;
241
        HotKey1[5] = KEY_SHIFTED + KEY_CTRLED + KEY_PAD8;
242
        HotKey1[6] = KEY_SHIFTED + KEY_CTRLED + KEY_PAD9;
243
        HotKey1[7] = KEY_SHIFTED + KEY_CTRLED + KEY_PADPLUS;
244
        HotKey1[8] = KEY_SHIFTED + KEY_CTRLED + KEY_PAD4;
245
        HotKey1[9] = KEY_SHIFTED + KEY_CTRLED + KEY_PAD5;
246
        HotKey1[10] = KEY_SHIFTED + KEY_CTRLED + KEY_PAD6;
247
        HotKey1[11] = KEY_SHIFTED + KEY_CTRLED + KEY_PAD1;
248
        HotKey1[12] = KEY_SHIFTED + KEY_CTRLED + KEY_PAD2;
249
        HotKey1[13] = KEY_SHIFTED + KEY_CTRLED + KEY_PAD3;
250
        HotKey1[14] = KEY_SHIFTED + KEY_CTRLED + KEY_PADENTER;
251
        HotKey1[15] = KEY_SHIFTED + KEY_CTRLED + KEY_PAD0;
252
        HotKey1[16] = KEY_SHIFTED + KEY_CTRLED + KEY_PADPERIOD;
253
 
254
        active_pad = 0;
255
 
256
}
257
 
258
 
259
void ui_pad_deactivate()
260
{
261
        range_for (auto &i, Pad)
262
        {
263
                i->text.clear();
264
        }
265
}
266
 
267
void ui_pad_draw(UI_DIALOG *dlg, int x, int y)
268
{
269
        int bh, bw;
270
 
271
        bw = 56; bh = 30;
272
 
273
        ui_dialog_set_current_canvas( dlg );
274
        ui_draw_box_in(*grd_curcanv, x, y, x+(bw * 4)+10 + 200, y+(bh * 5)+45);
275
 
276
        gr_set_default_canvas();
277
        auto &canvas = *grd_curcanv;
278
        const auto color = CWHITE;
279
        gr_urect(canvas, desc_x, desc_y, desc_x+ 56*4-1, desc_y+15, color);
280
        gr_set_fontcolor(canvas, CBLACK, CWHITE);
281
        gr_ustring(canvas, *canvas.cv_font, desc_x, desc_y, KeyPad[active_pad]->description.data());
282
}
283
 
284
static void ui_pad_set_active( int n )
285
{
286
        int np;
287
        const char * name;
288
 
289
 
290
        range_for (const int i, xrange(17u))
291
        {
292
                Pad[i]->text = KeyPad[n]->buttontext[i].data();
293
                Pad[i]->status = 1;
294
                Pad[i]->user_function = NULL;
295
                Pad[i]->dim_if_no_function = 1;
296
                Pad[i]->hotkey = -1;
297
 
298
                for (int j=0; j< KeyPad[n]->numkeys; j++ )
299
                {
300
                        if (HotKey[i] == KeyPad[n]->keycode[j] )
301
                        {
302
                                Pad[i]->hotkey =  HotKey[i];
303
                                Pad[i]->user_function = func_nget( KeyPad[n]->function_number[j], &np, &name );
304
                        }
305
                        if (HotKey1[i] == KeyPad[n]->keycode[j] )
306
                        {
307
                                Pad[i]->hotkey1 =  HotKey1[i];
308
                                Pad[i]->user_function1 = func_nget( KeyPad[n]->function_number[j], &np, &name );
309
                        }
310
                }
311
        }
312
 
313
        active_pad = n;
314
}
315
 
316
void ui_pad_goto(int n)
317
{
318
        if ( KeyPad[n] != NULL )
319
                ui_pad_set_active(n);
320
}
321
 
322
void ui_pad_goto_next()
323
{
324
        int i, si;
325
 
326
        i = active_pad + 1;
327
        si = i;
328
 
329
        while( KeyPad[i]==NULL )
330
        {
331
                i++;
332
                if (i >= MAX_NUM_PADS)
333
                        i = 0;
334
                if (i == si )
335
                        break;
336
        }
337
        ui_pad_set_active(i);
338
}
339
 
340
void ui_pad_goto_prev()
341
{
342
        int i;
343
 
344
        if (active_pad == -1 )
345
                active_pad = MAX_NUM_PADS;
346
 
347
        i = active_pad - 1;
348
        if (i<0) i= MAX_NUM_PADS - 1;
349
 
350
        while( KeyPad[i]==NULL )
351
        {
352
                i--;
353
                if (i < 0)
354
                        i = MAX_NUM_PADS-1;
355
                if (i == active_pad )
356
                        break;
357
        }
358
        ui_pad_set_active(i);
359
}
360
 
361
UI_KEYPAD::UI_KEYPAD() :
362
        numkeys(0)
363
{
364
        description.front() = 0;
365
        range_for (auto &i, buttontext)
366
                i[0] = 0;
367
}
368
 
369
int ui_pad_read( int n, const char * filename )
370
{
371
        int linenumber = 0;
372
        int keycode, functionnumber;
373
 
374
        auto infile = PHYSFSX_openReadBuffered(filename);
375
        if (!infile) {
376
                Warning( "Could not find %s\n", filename );
377
                return 0;
378
        }
379
        auto &kpn = *(KeyPad[n] = std::make_unique<UI_KEYPAD>());
380
 
381
        PHYSFSX_gets_line_t<100> buffer;
382
        while ( linenumber < 22)
383
        {
384
                PHYSFSX_fgets( buffer, infile );
385
 
386
                auto &line = buffer.line();
387
                const auto lb = line.begin();
388
                const auto le = line.end();
389
                switch( linenumber+1 )
390
                {
391
                case 1:
392
                        kpn.description.copy_if(line);
393
                        break;
394
                //===================== ROW 0 ==============================
395
                case 3:
396
                        set_row<false, '\n'>(lb, le, kpn.buttontext[0], kpn.buttontext[1], kpn.buttontext[2], kpn.buttontext[3]);
397
                        break;
398
                case 4:
399
                        set_row<true, '\n'>(lb, le, kpn.buttontext[0], kpn.buttontext[1], kpn.buttontext[2], kpn.buttontext[3]);
400
                        break;
401
                case 5:
402
                        set_row<true, 0>(lb, le, kpn.buttontext[0], kpn.buttontext[1], kpn.buttontext[2], kpn.buttontext[3]);
403
                        break;
404
                //===================== ROW 1 ==============================
405
                case 7:
406
                        set_row<false, '\n'>(lb, le, kpn.buttontext[4], kpn.buttontext[5], kpn.buttontext[6], kpn.buttontext[7]);
407
                        break;
408
                case 8:
409
                        set_row<true, '\n'>(lb, le, kpn.buttontext[4], kpn.buttontext[5], kpn.buttontext[6], kpn.buttontext[7]);
410
                        break;
411
                case 9:
412
                        set_row<true, '\n'>(set_row<true, 0>(lb, le, kpn.buttontext[4], kpn.buttontext[5], kpn.buttontext[6]), le, kpn.buttontext[7]);
413
                        break;
414
                case 10:
415
                        set_short_row(lb, le, kpn.buttontext[7]);
416
                        break;
417
                //======================= ROW 2 ==============================
418
                case 11:
419
                        set_row<true, '\n'>(set_row<false, '\n'>(lb, le, kpn.buttontext[8], kpn.buttontext[9], kpn.buttontext[10]), le, kpn.buttontext[7]);
420
                        break;
421
                case 12:
422
                        set_row<true, '\n'>(lb, le, kpn.buttontext[8], kpn.buttontext[9], kpn.buttontext[10], kpn.buttontext[7]);
423
                        break;
424
                case 13:
425
                        set_row<true, 0>(lb, le, kpn.buttontext[8], kpn.buttontext[9], kpn.buttontext[10], kpn.buttontext[7]);
426
                        break;
427
                // ====================== ROW 3 =========================
428
                case 15:
429
                        set_row<false, '\n'>(lb, le, kpn.buttontext[11], kpn.buttontext[12], kpn.buttontext[13], kpn.buttontext[14]);
430
                        break;
431
                case 16:
432
                        set_row<true, '\n'>(lb, le, kpn.buttontext[11], kpn.buttontext[12], kpn.buttontext[13], kpn.buttontext[14]);
433
                        break;
434
                case 17:
435
                        set_row<true, '\n'>(set_row<true, 0>(lb, le, kpn.buttontext[11], kpn.buttontext[12], kpn.buttontext[13]), le, kpn.buttontext[14]);
436
                        break;
437
                case 18:
438
                        set_short_row(lb, le, kpn.buttontext[14]);
439
                        break;
440
                //======================= ROW 4 =========================
441
                case 19:
442
                        set_row<true, '\n'>(set_row<false, '\n'>(lb, le, kpn.buttontext[15], kpn.buttontext[16]), le, kpn.buttontext[14]);
443
                        break;
444
                case 20:
445
                        set_row<true, '\n'>(lb, le, kpn.buttontext[15], kpn.buttontext[16], kpn.buttontext[14]);
446
                        break;
447
                case 21:
448
                        set_row<true, 0>(lb, le, kpn.buttontext[15], kpn.buttontext[16], kpn.buttontext[14]);
449
                        break;
450
                }
451
 
452
                linenumber++;  
453
        }
454
 
455
        // Get the keycodes...
456
 
457
        PHYSFSX_gets_line_t<200> line_buffer;
458
        while (PHYSFSX_fgets(line_buffer, infile))
459
        {
460
                if (!line_buffer[0])
461
                        continue;
462
                PHYSFSX_gets_line_t<100> text;
463
                sscanf(line_buffer, " %99s %99s ", text.next().data(), buffer.next().data());
464
                keycode = DecodeKeyText(text);
465
                functionnumber = func_get_index(buffer);
466
                if (functionnumber==-1)
467
                {
468
                        UserError( "Unknown function, %s, in %s\n", static_cast<const char *>(buffer), filename );
469
                } else if (keycode==-1)
470
                {
471
                        UserError( "Unknown keystroke, %s, in %s\n", static_cast<const char *>(text), filename );
472
                        //ui_messagebox( -2, -2, 1, buffer, "Ok" );
473
 
474
                } else {
475
                        kpn.keycode[kpn.numkeys] = keycode;
476
                        kpn.function_number[kpn.numkeys] = functionnumber;
477
                        kpn.numkeys++;
478
                }
479
        }
480
 
481
        return 1;
482
}
483
 
484
}