cfad47cfa3/tads2/indlg_tx.c

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.c - input dialog - formatted text-only version
15
Function
16
  Implements the input dialog function using formatted text
17
Notes
18
  Only one of indlg_tx or indlg_os should be included in a given
19
  executable.  The choice depends on whether a system-level dialog
20
  is available or not.  If no system-level dialog is available,
21
  include indlg_tx, which provides an implementation using formatted
22
  text.  If a system-level dialog is available, use indlg_os, which
23
  calls os_input_dialog().
24
25
  This file exists in the portable layer, rather than in the OS layer,
26
  so that we can provide an implementation using formatted text.  An
27
  OS-layer implementation could not provide formatted text.
28
Modified
29
  09/27/99 MJRoberts  - Creation
30
*/
31
32
#include <stdio.h>
33
#include <string.h>
34
#include <ctype.h>
35
36
#include "std.h"
37
#include "os.h"
38
#include "tio.h"
39
40
/* ------------------------------------------------------------------------ */
41
/*
42
 *   Text-mode os_input_dialog implementation 
43
 */
44
int tio_input_dialog(int icon_id, const char *prompt,
45
                     int standard_button_set,
46
                     const char **buttons, int button_count,
47
                     int default_index, int cancel_index)
48
{
49
    /* ignore the icon ID - we can't display an icon in text mode */
50
    VARUSED(icon_id);
51
52
    /* keep going until we get a valid response */
53
    for (;;)
54
    {
55
        int i;
56
        char buf[256];
57
        const char *p;
58
        const char *cur;
59
        char *resp;
60
        int match_cnt;
61
        int last_found;
62
        static const struct
63
        {
64
            const char *buttons[3];
65
            int button_count;
66
        } std_btns[] =
67
        {
68
            { { "&OK" },                    1 },
69
            { { "&OK", "&Cancel" },         2 },
70
            { { "&Yes", "&No" },            2 },
71
            { { "&Yes", "&No", "&Cancel" }, 3 }
72
        };
73
74
        /* 
75
         *   if we have a standard button set selected, get our button
76
         *   labels 
77
         */
78
        switch(standard_button_set)
79
        {
80
        case 0:
81
            /* use the explicit buttons provided */
82
            break;
83
84
        case OS_INDLG_OK:
85
            i = 0;
86
87
        use_std_btns:
88
            /* use the selected standard button set */
89
            buttons = (const char **)std_btns[i].buttons;
90
            button_count = std_btns[i].button_count;
91
            break;
92
93
        case OS_INDLG_OKCANCEL:
94
            i = 1;
95
            goto use_std_btns;
96
97
        case OS_INDLG_YESNO:
98
            i = 2;
99
            goto use_std_btns;
100
101
        case OS_INDLG_YESNOCANCEL:
102
            i = 3;
103
            goto use_std_btns;
104
105
        default:
106
            /* 
107
             *   we don't recognize other standard button sets - return an
108
             *   error 
109
             */
110
            return 0;
111
        }
112
113
        /* 
114
         *   if there are no buttons defined, they'll never be able to
115
         *   respond, so we'd just loop forever - rather than let that
116
         *   happen, return failure 
117
         */
118
        if (button_count == 0)
119
            return 0;
120
121
        /* display a newline and the prompt string */
122
        outformat("\\n");
123
        outformat((char *)prompt);
124
        outformat(" ");
125
126
        /* display the response */
127
        for (i = 0 ; i < button_count ; ++i)
128
        {
129
            /* 
130
             *   display a slash to separate responses, if this isn't the
131
             *   first one 
132
             */
133
            if (i != 0)
134
                outformat("/");
135
136
            /* get the current button */
137
            cur = buttons[i];
138
139
            /* 
140
             *   Look for a "&" in the response string.  If we find it,
141
             *   remove the "&" and enclose the shortcut key in parens.  
142
             */
143
            for (p = cur ; *p != '&' && *p != '\0' ; ++p) ;
144
145
            /* if we found the "&", put the next character in parens */
146
            if (*p == '&')
147
            {
148
                /* reformat the response string */
149
                sprintf(buf, "%.*s(%c)%s", (int)(p - cur), cur, *(p+1), p+2);
150
151
                /* display it */
152
                outformat(buf);
153
            }
154
            else
155
            {
156
                /* no '&' - just display the response string as-is */
157
                outformat((char *)cur);
158
            }
159
        }
160
161
        /* if we're in HTML mode, switch to input font */
162
        if (tio_is_html_mode())
163
            outformat("<font face='TADS-Input'>");
164
165
        /* read the response */
166
        getstring(" >", buf, sizeof(buf));
167
168
        /* if we're in HTML mode, close the input font tag */
169
        if (tio_is_html_mode())
170
            outformat("</font>");
171
172
        /* skip any leading spaces in the reply */
173
        for (resp = buf ; t_isspace(*resp) ; ++resp) ;
174
175
        /* if it's one character, check it against the shortcut keys */
176
        if (strlen(resp) == 1)
177
        {
178
            /* scan the responses */
179
            for (i = 0 ; i < button_count ; ++i)
180
            {
181
                /* look for a '&' in this button */
182
                for (p = buttons[i] ; *p != '&' && *p != '\0' ; ++p) ;
183
184
                /* if we found the '&', check the shortcut */
185
                if (*p == '&' && toupper(*(p+1)) == toupper(*resp))
186
                {
187
                    /* 
188
                     *   this is the one - return the current index
189
                     *   (bumping it by one to get a 1-based value) 
190
                     */
191
                    return i + 1;
192
                }
193
            }
194
        }
195
196
        /* 
197
         *   Either it's not a one-character reply, or it didn't match a
198
         *   short-cut - check it against the leading substrings of the
199
         *   responses.  If it matches exactly one of the responses in its
200
         *   leading substring, use that response.  
201
         */
202
        for (i = 0, match_cnt = 0 ; i < button_count ; ++i)
203
        {
204
            const char *p1;
205
            const char *p2;
206
207
            /* 
208
             *   compare this response to the user's response; skip any
209
             *   '&' in the button label 
210
             */
211
            for (p1 = resp, p2 = buttons[i] ; *p1 != '\0' && *p2 != '\0' ;
212
                 ++p1, ++p2)
213
            {
214
                /* if this is a '&' in the button label, skip it */
215
                if (*p2 == '&')
216
                    ++p2;
217
218
                /* if these characters don't match, it's no match */
219
                if (toupper(*p1) != toupper(*p2))
220
                    break;
221
            }
222
223
            /* 
224
             *   if we reached the end of the user's response, we have a
225
             *   match in the leading substring - count it and remember
226
             *   this as the last one, but keep looking, since we need to
227
             *   make sure we don't have any other matches 
228
             */
229
            if (*p1 == '\0')
230
            {
231
                ++match_cnt;
232
                last_found = i;
233
            }
234
        }
235
        
236
        /* 
237
         *   if we found exactly one match, return it (adjusting to a
238
         *   1-based index); if we found more or less than one match, it's
239
         *   not a valid response, so start over with a new prompt 
240
         */
241
        if (match_cnt == 1)
242
            return last_found + 1;
243
    }
244
}
245