cfad47cfa3/tads3/indlg_tx3.cpp

4b825dc642cb6eb9a060e54bf8d69288fbee4904cfad47cfa334b206c65f22086bcc5d63e6f70944
1
#ifdef RCSID
2
static char RCSid[] =
3
"$Header$";
4
#endif
5
6
/* 
7
 *   Copyright (c) 1999, 2002 Michael J. Roberts.  All Rights Reserved.
8
 *   
9
 *   Please see the accompanying license file, LICENSE.TXT, for information
10
 *   on using and copying this software.  
11
 */
12
/*
13
Name
14
  indlg_tx.cpp - formatted text implementation of input_dialog
15
Function
16
  Implements the input dialog using formatted text
17
Notes
18
  Only one of indlg_tx.c or indlg_os.c should be included in a given
19
  executable.  For a text-only version, include indlg_tx.  For a version
20
  where os_input_dialog() provides a system dialog, use indlg_os instead.
21
22
  We provide a choice of input_dialog() implementations in the portable
23
  code (rather than only through the OS code) so that we can call
24
  the formatted text output routines in this version.  An OS-layer
25
  implementation could not call the formatted output routines (it would
26
  have to call os_printf directly), which would result in poor prompt
27
  formatting any time a prompt exceeded a single line of text.
28
Modified
29
  09/27/99 MJRoberts  - Creation
30
*/
31
32
33
#include "os.h"
34
#include "t3std.h"
35
#include "vmglob.h"
36
#include "vmconsol.h"
37
#include "charmap.h"
38
39
/*
40
 *   formatted text-only file prompt 
41
 */
42
int CVmConsole::input_dialog(VMG_ int /*icon_id*/,
43
                             const char *prompt, int standard_button_set,
44
                             const char **buttons, int button_count,
45
                             int default_index, int cancel_index)
46
{
47
    /* keep going until we get a valid response */
48
    for (;;)
49
    {
50
        int i;
51
        char buf[256];
52
        const char *p;
53
        const char *cur;
54
        char *resp;
55
        int match_cnt;
56
        int last_found;
57
        static const struct
58
        {
59
            const char *buttons[3];
60
            int button_count;
61
        } std_btns[] =
62
        {
63
            { { "&OK" },                    1 },
64
            { { "&OK", "&Cancel" },         2 },
65
            { { "&Yes", "&No" },            2 },
66
            { { "&Yes", "&No", "&Cancel" }, 3 }
67
        };
68
69
        /* 
70
         *   if we have a standard button set selected, get our button
71
         *   labels 
72
         */
73
        switch(standard_button_set)
74
        {
75
        case 0:
76
            /* use the explicit buttons provided */
77
            break;
78
79
        case OS_INDLG_OK:
80
            i = 0;
81
82
        use_std_btns:
83
            /* use the selected standard button set */
84
            buttons = (const char **)std_btns[i].buttons;
85
            button_count = std_btns[i].button_count;
86
            break;
87
88
        case OS_INDLG_OKCANCEL:
89
            i = 1;
90
            goto use_std_btns;
91
92
        case OS_INDLG_YESNO:
93
            i = 2;
94
            goto use_std_btns;
95
96
        case OS_INDLG_YESNOCANCEL:
97
            i = 3;
98
            goto use_std_btns;
99
100
        default:
101
            /* 
102
             *   we don't recognize other standard button sets - return an
103
             *   error 
104
             */
105
            return 0;
106
        }
107
108
        /* 
109
         *   if there are no buttons defined, they'll never be able to
110
         *   respond, so we'd just loop forever - rather than let that
111
         *   happen, return failure 
112
         */
113
        if (button_count == 0)
114
            return 0;
115
116
        /* display a newline and the prompt string */
117
        format_text(vmg_ "\n");
118
        format_text(vmg_ prompt);
119
        format_text(vmg_ " ");
120
121
        /* display the response */
122
        for (i = 0 ; i < button_count ; ++i)
123
        {
124
            /* 
125
             *   display a slash to separate responses, if this isn't the
126
             *   first one 
127
             */
128
            if (i != 0)
129
                format_text(vmg_ "/");
130
131
            /* get the current button */
132
            cur = buttons[i];
133
134
            /* 
135
             *   Look for a "&" in the response string.  If we find it,
136
             *   remove the "&" and enclose the shortcut key in parens.  
137
             */
138
            for (p = cur ; *p != '\0' && *p != '&' ;
139
                 p = utf8_ptr::s_inc((char *)p)) ;
140
141
            /* if we found the "&", put the next character in parens */
142
            if (*p != '\0')
143
            {
144
                size_t pre_len;
145
                size_t post_len;
146
147
                /* 
148
                 *   note the length of the part up to the '&', but limit it
149
                 *   to avoid overflowing the buffer 
150
                 */
151
                pre_len = p - cur;
152
                if (pre_len > sizeof(buf) - 5)
153
                    pre_len = sizeof(buf) - 5;
154
155
                /* 
156
                 *   note the length of the part after the '&', limiting it
157
                 *   as well 
158
                 */
159
                post_len = strlen(p+2);
160
                if (post_len > sizeof(buf) - 5 - pre_len)
161
                    post_len = sizeof(buf) - 5 - pre_len;
162
163
                /* reformat the response string */
164
                sprintf(buf, "%.*s(%c)%.*s",
165
                        (int)pre_len, cur, *(p + 1), (int)post_len, p + 2);
166
167
                /* display it */
168
                format_text(vmg_ buf);
169
            }
170
            else
171
            {
172
                /* no '&' - just display the response string as-is */
173
                format_text(vmg_ cur);
174
            }
175
        }
176
177
        /* switch to input font */
178
        format_text(vmg_ "<font face='TADS-Input'>");
179
180
        /* read the response */
181
        format_text(vmg_ " >");
182
        read_line(vmg_ buf, sizeof(buf));
183
184
        /* close the input font tag */
185
        format_text(vmg_ "</font>");
186
187
        /* skip any leading spaces in the reply */
188
        for (resp = buf ; isspace(*resp) ; ++resp) ;
189
190
        /* if it's one character, check it against the shortcut keys */
191
        if (strlen(resp) == 1)
192
        {
193
            /* scan the responses */
194
            for (i = 0 ; i < button_count ; ++i)
195
            {
196
                /* look for a '&' in this button */
197
                for (p = buttons[i] ; *p != '&' && *p != '\0' ; ++p) ;
198
199
                /* if we found the '&', check the shortcut */
200
                if (*p == '&' && toupper(*(p+1)) == toupper(*resp))
201
                {
202
                    /* 
203
                     *   this is the one - return the current index
204
                     *   (bumping it by one to get a 1-based value) 
205
                     */
206
                    return i + 1;
207
                }
208
            }
209
        }
210
211
        /* 
212
         *   Either it's not a one-character reply, or it didn't match a
213
         *   short-cut - check it against the leading substrings of the
214
         *   responses.  If it matches exactly one of the responses in its
215
         *   leading substring, use that response.  
216
         */
217
        for (i = 0, match_cnt = 0 ; i < button_count ; ++i)
218
        {
219
            const char *p1;
220
            const char *p2;
221
222
            /* 
223
             *   compare this response to the user's response; skip any
224
             *   '&' in the button label 
225
             */
226
            for (p1 = resp, p2 = buttons[i] ; *p1 != '\0' && *p2 != '\0' ;
227
                 ++p1, ++p2)
228
            {
229
                /* if this is a '&' in the button label, skip it */
230
                if (*p2 == '&')
231
                    ++p2;
232
233
                /* if these characters don't match, it's no match */
234
                if (toupper(*p1) != toupper(*p2))
235
                    break;
236
            }
237
238
            /* 
239
             *   if we reached the end of the user's response, we have a
240
             *   match in the leading substring - count it and remember
241
             *   this as the last one, but keep looking, since we need to
242
             *   make sure we don't have any other matches 
243
             */
244
            if (*p1 == '\0')
245
            {
246
                ++match_cnt;
247
                last_found = i;
248
            }
249
        }
250
        
251
        /* 
252
         *   if we found exactly one match, return it (adjusting to a
253
         *   1-based index); if we found more or less than one match, it's
254
         *   not a valid response, so start over with a new prompt 
255
         */
256
        if (match_cnt == 1)
257
            return last_found + 1;
258
    }
259
}
260