The R Project SVN R

Rev

Rev 84952 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
4394 ripley 1
/*
2
 * GraphApp - Cross-Platform Graphics Programming Library.
3
 *
4
 * File: dialogs.c -- standard file dialogs and a few others.
5
 * Platform: Windows  Version: 2.42  Date: 1998/07/07
6
 *
7
 * Version: 1.00  Changes: Original version by Lachlan Patrick.
8
 * Version: 1.50  Changes: Uses new rectangles, callbacks.
9
 * Version: 2.20  Changes: Handle null strings correctly now.
10
 * Version: 2.40  Changes: Now uses YES, NO, CANCEL symbols.
11
 * Version: 2.42  Changes: Askstring fixed by Laurent Piguet.
12
 */
13
 
14
/* Copyright (C) 1993-1998 Lachlan Patrick
15
 
16
   This file is part of GraphApp, a cross-platform C graphics library.
17
 
18
   GraphApp is free software; you can redistribute it and/or modify it
19
   under the terms of the GNU Library General Public License.
20
   GraphApp is distributed in the hope that it will be useful, but
21
   WITHOUT ANY WARRANTY.
22
 
23
   See the file COPYLIB.TXT for details.
24
*/
25
 
45017 ripley 26
/* Copyright (C) 2004--2008	The R Foundation
83703 kalibera 27
   Copyright (C) 2013--2023	The R Core Team
28991 murdoch 28
 
29
   Additions for R, Chris Jackson
82766 kalibera 30
   Find and replace dialog boxes and dialog handlers.
31
   Modify find and replace for RichEdit20W.
83703 kalibera 32
   Path length limits.
83778 kalibera 33
   Update askcdstring to IFileOpenDialog (Vista).
84234 kalibera 34
   Add clickbutton, handle WM_CLOSE in askstr_dialog.
82766 kalibera 35
*/
28991 murdoch 36
 
58001 ripley 37
#ifndef _WIN32_WINNT
83778 kalibera 38
# define _WIN32_WINNT 0x0600
58001 ripley 39
#endif
40
 
42521 ripley 41
#include "win-nls.h"
4394 ripley 42
#include "internal.h"
28991 murdoch 43
#include "ga.h"
4394 ripley 44
 
38793 ripley 45
#include <shlobj.h>
83778 kalibera 46
#include <shobjidl.h>
83775 kalibera 47
#include <stdlib.h>
38793 ripley 48
 
83703 kalibera 49
#define BUFSIZE (3*65536)
22842 murdoch 50
static char strbuf[BUFSIZE];
46843 ripley 51
static wchar_t wcsbuf[65536];
4394 ripley 52
 
41793 ripley 53
static const char *filter[] = {
45017 ripley 54
    "All Files (*.*)",	"*.*",
55
    "Text Files (*.TXT)",	"*.txt",
56
    "HTML Files (*.HTM)",	"*.htm",
57
    "PNG Files (*.PNG)",	"*.png",
58
    "JPEG Files (*.JPG)",	"*.jpg",
59
    "BMP Files (*.BMP)",	"*.bmp",
60
    ""
4394 ripley 61
};
62
 
46843 ripley 63
static const wchar_t *wfilter[] = {
64
    L"All Files (*.*)",	L"*.*",
65
    L"Text Files (*.TXT)",	L"*.txt",
66
    L"HTML Files (*.HTM)",	L"*.htm",
67
    L"PNG Files (*.PNG)",	L"*.png",
68
    L"JPEG Files (*.JPG)",	L"*.jpg",
69
    L"BMP Files (*.BMP)",	L"*.bmp",
70
    L""
71
};
72
 
28854 murdoch 73
unsigned int TopmostDialogs = 0; /* May be MB_TOPMOST */
74
 
41793 ripley 75
static const char *userfilter;
46843 ripley 76
static const wchar_t *userfilterW;
77
 
45017 ripley 78
void setuserfilter(const char *uf)
79
{
80
    userfilter=uf;
4394 ripley 81
}
82
 
46843 ripley 83
void setuserfilterW(const wchar_t *uf)
84
{
85
    userfilterW=uf;
86
}
87
 
28991 murdoch 88
static HWND hModelessDlg = NULL;
89
 
83775 kalibera 90
static wchar_t *mbstowcs_malloc(const char *s)
91
{
92
    wchar_t *ws = NULL;
93
    size_t cnt = mbstowcs(NULL, s, 0);
94
    if (cnt != (size_t)-1) {
95
	cnt++;
96
	ws = (wchar_t*) malloc(cnt * sizeof(wchar_t));
97
	if (ws)
98
	    mbstowcs(ws, s, cnt);
99
    }
100
    return ws;
101
}
102
 
41793 ripley 103
int myMessageBox(HWND h, const char *text, const char *caption, UINT type)
36921 ripley 104
{
43328 ripley 105
    if(localeCP != GetACP()) {
83775 kalibera 106
	wchar_t *wtext = mbstowcs_malloc(text);
107
	wchar_t *wcaption = mbstowcs_malloc(caption);
108
	int res = 0;
109
	if (wtext && wcaption)
110
	    res = MessageBoxW(h, wtext, wcaption, type);
111
	free(wtext);
112
	free(wcaption);
113
	return res;
36921 ripley 114
    } else
115
	return MessageBoxA(h, text, caption, type);
116
}
117
 
4394 ripley 118
/*
119
 *  Error reporting dialog.
120
 */
41793 ripley 121
void apperror(const char *errstr)
4394 ripley 122
{
45017 ripley 123
    if (! errstr)
124
	errstr = "Unspecified error";
125
    myMessageBox(0, errstr, "Graphics Library Error",
126
		 MB_TASKMODAL | MB_ICONSTOP | MB_OK | TopmostDialogs);
127
    exitapp();
4394 ripley 128
}
129
 
41793 ripley 130
void askok(const char *info)
4394 ripley 131
{
45017 ripley 132
    if (! info)
133
	info = "";
134
    myMessageBox(0, info, "Information",
135
		 MB_TASKMODAL | MB_ICONINFORMATION | MB_OK | TopmostDialogs);
4394 ripley 136
}
137
 
41793 ripley 138
int askokcancel(const char *question)
4394 ripley 139
{
45017 ripley 140
    int result;
4394 ripley 141
 
45017 ripley 142
    if (! question)
143
	question = "";
144
    result = myMessageBox(0, question, G_("Question"),
145
			  MB_TASKMODAL | MB_ICONQUESTION | MB_OKCANCEL | TopmostDialogs);
4394 ripley 146
 
45017 ripley 147
    switch (result) {
148
    case IDOK: result = YES; break;
149
    case IDCANCEL:
150
    default: result = CANCEL; break;
151
    }
152
    return result;
4394 ripley 153
}
154
 
41793 ripley 155
int askyesno(const char *question)
4394 ripley 156
{
45017 ripley 157
    int result;
4394 ripley 158
 
45017 ripley 159
    if (! question)
160
	question = "";
161
    result = myMessageBox(0, question, G_("Question"),
162
			  MB_TASKMODAL | MB_ICONQUESTION | MB_YESNO | TopmostDialogs);
4394 ripley 163
 
45017 ripley 164
    switch (result) {
165
    case IDYES: result = YES; break;
166
    case IDNO:  result = NO; break;
167
    default: result = CANCEL; break;
168
    }
169
    return result;
4394 ripley 170
}
171
 
41793 ripley 172
int askyesnocancel(const char *question)
4394 ripley 173
{
45017 ripley 174
    int result;
4394 ripley 175
 
45017 ripley 176
    if (! question)
177
	question = "";
178
    result = myMessageBox(0, question, G_("Question"),
179
			  MB_TASKMODAL | MB_ICONQUESTION | MB_YESNOCANCEL | MB_SETFOREGROUND | TopmostDialogs);
4394 ripley 180
 
45017 ripley 181
    switch (result) {
182
    case IDYES: result = YES; break;
183
    case IDNO:  result = NO; break;
184
    case IDCANCEL:
185
    default: result = CANCEL; break;
186
    }
187
    return result;
4394 ripley 188
}
189
 
46843 ripley 190
/* This should always have a native encoded name, so don't need Unicode here */
83775 kalibera 191
static char *cod = NULL; /*current open directory*/
4394 ripley 192
 
84952 kalibera 193
static char *getCurrentDirectory(void)
83775 kalibera 194
{
195
    DWORD rc;
196
    char *cwd = NULL;
197
 
198
    rc = GetCurrentDirectory(0, NULL);
199
    if (rc) {
200
        cwd = (char *)malloc(rc);
201
        if (cwd) {
202
            DWORD rc1 = GetCurrentDirectory(rc, cwd);
203
            if (rc1 <= 0 || rc1 >= rc) {
204
                free(cwd);
205
                cwd = NULL;
206
            }
207
	}
208
    }
209
    return cwd;
210
}
211
 
84952 kalibera 212
static wchar_t *getCurrentDirectoryW(void)
83775 kalibera 213
{
214
    DWORD rc;
215
    wchar_t *cwd = NULL;
216
 
217
    rc = GetCurrentDirectoryW(0, NULL);
218
    if (rc) {
219
        cwd = (wchar_t *)malloc(rc * sizeof(wchar_t));
220
        if (cwd) {
221
            DWORD rc1 = GetCurrentDirectoryW(rc, cwd);
222
            if (rc1 <= 0 || rc1 >= rc) {
223
                free(cwd);
224
                cwd = NULL;
225
            }
226
	}
227
    }
228
    return cwd;
229
}
230
 
231
/* returns 0 on error */
232
static int savecod(void)
233
{
234
    char *cwd = getCurrentDirectory();
235
    /* This could fail if the Unicode name is not a native name */
236
    if (cwd) {
237
	if (cod) free(cod);
238
	cod = cwd;
239
    }
240
    return cwd ? 1 : 0;
241
}
242
 
84952 kalibera 243
void askchangedir(void)
4394 ripley 244
{
83778 kalibera 245
    char *s, *msg;
4606 ripley 246
 
83775 kalibera 247
    /* set cod to current directory */
248
    savecod();
33088 ripley 249
    s = askcdstring(G_(" Change working directory to:"), cod);
4606 ripley 250
    if (s && (SetCurrentDirectory(s) == FALSE)) {
83778 kalibera 251
	char *format = G_("Unable to set '%s' as working directory");
252
	size_t nb;
253
	nb = snprintf(NULL, 0, format, s);
254
	msg = (char*) malloc(nb + 1);
255
	if (msg) {
256
	    snprintf(msg, nb + 1,  format, s);
257
	    askok(msg);
258
	    free(msg);
259
	}
4606 ripley 260
    }
261
    /* in every case reset cod (to new directory if all went ok
46843 ripley 262
       or to old since user may have edited it) */
83775 kalibera 263
    savecod();
4394 ripley 264
}
265
 
41793 ripley 266
char *askfilename(const char *title, const char *default_name)
4394 ripley 267
{
45017 ripley 268
    if (*askfilenames(title, default_name, 0, userfilter?userfilter:filter[0], 0,
269
		      strbuf, BUFSIZE, NULL)) return strbuf;
270
    else return NULL;
4394 ripley 271
}
272
 
41793 ripley 273
char *askfilenamewithdir(const char *title, const char *default_name, const char *dir)
37592 murdoch 274
{
46843 ripley 275
    if (*askfilenames(title, default_name, 0, 
276
		      userfilter ? userfilter : filter[0], 0,
45017 ripley 277
		      strbuf, BUFSIZE, dir)) return strbuf;
278
    else return NULL;
37592 murdoch 279
}
280
 
41793 ripley 281
char *askfilenames(const char *title, const char *default_name, int multi,
282
		   const char *filters, int filterindex,
38990 ripley 283
		   char *strbuf, int bufsize,
41793 ripley 284
		   const char *dir)
22842 murdoch 285
{
83775 kalibera 286
    int i, succeeded;
88859 kalibera 287
    OPENFILENAME ofn = { 0 };
83775 kalibera 288
    char *cwd;
45927 murdoch 289
    HWND prev = GetFocus();
38990 ripley 290
 
45017 ripley 291
    if (!default_name) default_name = "";
292
    strcpy(strbuf, default_name);
83775 kalibera 293
    cwd = getCurrentDirectory();
294
    if (!cod) savecod();
22842 murdoch 295
 
45017 ripley 296
    ofn.lStructSize     = sizeof(OPENFILENAME);
297
    ofn.hwndOwner       = current_window ? current_window->handle : 0;
298
    ofn.hInstance       = 0;
299
    ofn.lpstrFilter     = filters;
300
    ofn.lpstrCustomFilter = NULL;
301
    ofn.nMaxCustFilter  = 0;
302
    ofn.nFilterIndex    = filterindex;
303
    ofn.lpstrFile       = strbuf;
304
    ofn.nMaxFile        = bufsize;
305
    ofn.lpstrFileTitle  = NULL;
306
    ofn.nMaxFileTitle   = _MAX_FNAME + _MAX_EXT;
46843 ripley 307
    ofn.lpstrInitialDir = dir ? dir : cod;
45017 ripley 308
    ofn.lpstrTitle      = title;
309
    ofn.Flags           = OFN_CREATEPROMPT | OFN_HIDEREADONLY | OFN_EXPLORER;
310
    if (multi) ofn.Flags |= OFN_ALLOWMULTISELECT;
311
    ofn.nFileOffset     = 0;
312
    ofn.nFileExtension  = 0;
313
    ofn.lpstrDefExt     = "*";
314
    ofn.lCustData       = 0L;
315
    ofn.lpfnHook        = NULL;
316
    ofn.lpTemplateName  = NULL;
22842 murdoch 317
 
83775 kalibera 318
    succeeded = (GetOpenFileName(&ofn) != 0);
319
    if(!dir) savecod();
320
    SetCurrentDirectory(cwd);
321
    free(cwd);
322
 
323
    if (!succeeded) { /* error or cancelled by user */
45017 ripley 324
	strbuf[0] = 0;
325
	strbuf[1] = 0;
326
    } else {
327
	for (i = 0; i <  10; i++) if (peekevent()) doevent();
328
    }
45927 murdoch 329
    SetFocus(prev);
330
    return strbuf;
22842 murdoch 331
}
332
 
46843 ripley 333
wchar_t *askfilenameW(const char *title, const char *default_name)
334
{
83775 kalibera 335
    wchar_t wtitle[1000], *wdef_name;
46843 ripley 336
 
337
    mbstowcs(wtitle, title, 1000);
83775 kalibera 338
    wdef_name = mbstowcs_malloc(default_name ? default_name : "");
339
    if (!wdef_name)
340
	return NULL;
341
 
342
    wchar_t res = *askfilenamesW(wtitle, wdef_name, 0, 
46843 ripley 343
		       userfilterW ? userfilterW : wfilter[0], 0,
83775 kalibera 344
		       NULL);
345
    free(wdef_name);
346
    if (res) return wcsbuf;
46843 ripley 347
    else return NULL;
348
}
349
 
350
wchar_t *askfilenamesW(const wchar_t *title, const wchar_t *default_name,
351
		       int multi,
352
		       const wchar_t *filters, int filterindex,
353
		       const wchar_t *dir)
354
{
83775 kalibera 355
    int i, succeeded;
88859 kalibera 356
    OPENFILENAMEW ofn = { 0 };
83775 kalibera 357
    char *cwd;
358
    wchar_t *wcod;
46843 ripley 359
    HWND prev = GetFocus();
360
 
361
    if (!default_name) default_name = L"";
68288 murdoch 362
    memset(wcsbuf, 0, sizeof(wcsbuf));
46843 ripley 363
    wcscpy(wcsbuf, default_name);
83775 kalibera 364
    cwd = getCurrentDirectory();
365
 
366
    if (!cod) {
367
	if (!dir)
368
	    wcod = getCurrentDirectoryW();
369
	else {
370
	    wcod = (wchar_t*) malloc((wcslen(dir) + 1) * sizeof(wchar_t));
371
	    if (wcod)
372
		wcscpy(wcod, dir);
373
	}
46843 ripley 374
    } else
83775 kalibera 375
	wcod = mbstowcs_malloc(cod);
376
    if (!wcod) {
377
        wcsbuf[0] = 0;
378
        wcsbuf[1] = 0;
379
	return wcsbuf;
380
    }
46843 ripley 381
 
382
    ofn.lStructSize     = sizeof(OPENFILENAME);
383
    ofn.hwndOwner       = current_window ? current_window->handle : 0;
384
    ofn.hInstance       = 0;
385
    ofn.lpstrFilter     = filters;
386
    ofn.lpstrCustomFilter = NULL;
387
    ofn.nMaxCustFilter  = 0;
388
    ofn.nFilterIndex    = filterindex;
389
    ofn.lpstrFile       = wcsbuf;
390
    ofn.nMaxFile        = 65520; /* precaution against overflow */
391
    ofn.lpstrFileTitle  = NULL;
392
    ofn.nMaxFileTitle   = _MAX_FNAME + _MAX_EXT;
393
    ofn.lpstrInitialDir = wcod;
394
    ofn.lpstrTitle      = title;
395
    ofn.Flags           = OFN_CREATEPROMPT | OFN_HIDEREADONLY | OFN_EXPLORER;
396
    if (multi) ofn.Flags |= OFN_ALLOWMULTISELECT;
397
    ofn.nFileOffset     = 0;
398
    ofn.nFileExtension  = 0;
399
    ofn.lpstrDefExt     = L"*";
400
    ofn.lCustData       = 0L;
401
    ofn.lpfnHook        = NULL;
402
    ofn.lpTemplateName  = NULL;
403
 
83775 kalibera 404
    succeeded = (GetOpenFileNameW(&ofn) != 0);
405
    free(wcod);
406
    if (!savecod()) {
46843 ripley 407
	/* This could fail if the Unicode name is not a native name */
83775 kalibera 408
	if (cod)
409
	    free(cod);
410
	cod = cwd;
46843 ripley 411
	SetCurrentDirectory(cwd);
83775 kalibera 412
    } else {
413
	SetCurrentDirectory(cwd);
414
	free(cwd);
415
    }
416
 
417
    if (!succeeded) { /* error or cancelled by user */
46843 ripley 418
	wcsbuf[0] = 0;
419
	wcsbuf[1] = 0;
420
    } else {
421
	for (i = 0; i <  10; i++) if (peekevent()) doevent();
422
    }
423
    SetFocus(prev);
424
    return wcsbuf;
425
}
426
 
41793 ripley 427
int countFilenames(const char *list)
22842 murdoch 428
{
45017 ripley 429
    const char *temp;
430
    int count;
431
    count = 0;
432
    for (temp = list; *temp; temp += strlen(temp)+1) count++;
433
    return count;
22842 murdoch 434
}
435
 
41793 ripley 436
char *askfilesave(const char *title, const char *default_name)
4394 ripley 437
{
8707 ripley 438
    return askfilesavewithdir(title, default_name, NULL);
439
}
440
 
46843 ripley 441
wchar_t *askfilesaveW(const char *title, const char *default_name) 
8707 ripley 442
{
83775 kalibera 443
    int i, succeeded;
88859 kalibera 444
    OPENFILENAMEW ofn = { 0 };
83775 kalibera 445
    wchar_t *cwd, *wdef_name, wtitle[1000];
46843 ripley 446
 
83775 kalibera 447
    wdef_name = mbstowcs_malloc(default_name ? default_name : "");
448
    if (!wdef_name)
449
	return NULL;
450
 
46843 ripley 451
    wcscpy(wcsbuf, wdef_name);
452
    mbstowcs(wtitle, title, 1000);
453
 
454
    ofn.lStructSize     = sizeof(OPENFILENAME);
455
    ofn.hwndOwner       = current_window ? current_window->handle : 0;
456
    ofn.hInstance       = 0;
457
    ofn.lpstrFilter     = userfilterW ? userfilterW : wfilter[0];
458
    ofn.lpstrCustomFilter = NULL;
459
    ofn.nMaxCustFilter  = 0;
460
    ofn.nFilterIndex    = 0;
461
    ofn.lpstrFile       = wcsbuf;
83703 kalibera 462
    ofn.nMaxFile        = 65520; /* precaution against overflow */
46843 ripley 463
    ofn.lpstrFileTitle  = NULL;
464
    ofn.nMaxFileTitle   = _MAX_FNAME + _MAX_EXT;
83775 kalibera 465
    cwd = getCurrentDirectoryW();
466
    if (cwd)
46843 ripley 467
	ofn.lpstrInitialDir = cwd;
468
    else
469
	ofn.lpstrInitialDir = NULL;
470
    ofn.lpstrTitle      = wtitle;
471
    ofn.Flags           = OFN_OVERWRITEPROMPT |
472
	OFN_NOCHANGEDIR | OFN_HIDEREADONLY;
473
    ofn.nFileOffset     = 0;
474
    ofn.nFileExtension  = 0;
475
    ofn.lpstrDefExt     = NULL;
476
    ofn.lCustData       = 0L;
477
    ofn.lpfnHook        = NULL;
478
    ofn.lpTemplateName  = NULL;
479
 
83775 kalibera 480
    succeeded = (GetSaveFileNameW(&ofn) != 0);
481
    free(wdef_name);
482
    if (cwd)
483
	free(cwd);
484
    if (!succeeded)
46843 ripley 485
	return NULL;
486
    else {
487
	for (i = 0; i < 10; i++) if (peekevent()) doevent();
488
	return wcsbuf;
489
    }
490
}
491
 
492
char *askfilesavewithdir(const char *title, const char *default_name,
493
			 const char *dir)
494
{
83775 kalibera 495
    int i, succeeded;
88859 kalibera 496
    OPENFILENAME ofn = { 0 };
83775 kalibera 497
    char *cwd, *defext = NULL;
4394 ripley 498
 
45017 ripley 499
    if (!default_name) default_name = "";
500
    else if(default_name[0] == '|') {
501
	defext = (char *)default_name + 2;
502
	default_name = "";
503
    }
504
    strcpy(strbuf, default_name);
4394 ripley 505
 
45017 ripley 506
    ofn.lStructSize     = sizeof(OPENFILENAME);
507
    ofn.hwndOwner       = current_window ? current_window->handle : 0;
508
    ofn.hInstance       = 0;
509
    ofn.lpstrFilter     = userfilter?userfilter:filter[0];
510
    ofn.lpstrCustomFilter = NULL;
511
    ofn.nMaxCustFilter  = 0;
512
    ofn.nFilterIndex    = 0;
513
    ofn.lpstrFile       = strbuf;
514
    ofn.nMaxFile        = BUFSIZE;
515
    ofn.lpstrFileTitle  = NULL;
516
    ofn.nMaxFileTitle   = _MAX_FNAME + _MAX_EXT;
517
    if(dir && strlen(dir) > 0) {
83775 kalibera 518
	/* FIXME: is the copy needed? */
519
	cwd = (char *)malloc(strlen(dir) + 1);
520
	if (!cwd)
521
	    return NULL;
45017 ripley 522
	strcpy(cwd, dir);
46843 ripley 523
	/* This should have been set to use backslashes in the caller */
45017 ripley 524
	ofn.lpstrInitialDir = cwd;
525
    } else {
83775 kalibera 526
	cwd = getCurrentDirectory();
527
	ofn.lpstrInitialDir = cwd;
45017 ripley 528
    }
529
    ofn.lpstrTitle      = title;
530
    ofn.Flags           = OFN_OVERWRITEPROMPT |
531
	OFN_NOCHANGEDIR | OFN_HIDEREADONLY;
532
    ofn.nFileOffset     = 0;
533
    ofn.nFileExtension  = 0;
534
    ofn.lpstrDefExt     = defext;
535
    ofn.lCustData       = 0L;
536
    ofn.lpfnHook        = NULL;
537
    ofn.lpTemplateName  = NULL;
4394 ripley 538
 
83775 kalibera 539
    succeeded = (GetSaveFileName(&ofn) != 0);
540
    if (cwd)
541
	free(cwd);
542
    if (!succeeded)
45017 ripley 543
	return NULL;
544
    else {
545
	for (i = 0; i < 10; i++) if (peekevent()) doevent();
546
	return strbuf;
547
    }
4394 ripley 548
}
549
 
550
/*
551
 *  Input a string using a dialog box.
552
 */
553
 
554
/*
555
 *  Dialog information structure:
556
 */
45017 ripley 557
#define NOT_CHOSEN_YET -2
4394 ripley 558
 
45017 ripley 559
typedef struct dialog_data_class {
560
    int	hit;
561
    char *	result;
562
    label	question;
563
    field	text, pass;
564
    button	yes, no, cancel;
565
} dialog_data;
4394 ripley 566
 
45017 ripley 567
#define data(w) ((dialog_data *) (getdata(w)))
4394 ripley 568
 
569
/*
570
 *  Some strings to use:
571
 */
37809 ripley 572
/*	static char * OKAY_STRING	= "OK";
4394 ripley 573
	static char * CANCEL_STRING	= "Cancel";
37809 ripley 574
	static char * BROWSE_STRING	= "Browse"; */
4394 ripley 575
 
45017 ripley 576
static const char * QUESTION_TITLE	= "Question";
577
static const char * PASSWORD_TITLE	= "Password Entry";
4394 ripley 578
 
579
static void add_data(window w)
580
{
45017 ripley 581
    dialog_data *d;
4394 ripley 582
 
45017 ripley 583
    d = create (dialog_data);
584
    if (! d)
585
	return;
586
    d->hit = NOT_CHOSEN_YET;
4394 ripley 587
 
45017 ripley 588
    setdata(w, d);
4394 ripley 589
}
590
 
591
static char * get_dialog_string(window w)
592
{
45017 ripley 593
    dialog_data *d = data(w);
4394 ripley 594
 
45017 ripley 595
    if (d->hit < YES) /* cancelled */
596
	return NULL;
597
    del_string(d->result);
598
    if (d->text)	/* question dialog */
599
	d->result = new_string(GA_gettext(d->text));
4394 ripley 600
 
45017 ripley 601
    return d->result;
4394 ripley 602
}
603
 
604
static void hit_button(control c)
605
{
45017 ripley 606
    window w = parentwindow(c);
607
    dialog_data *d = data(w);
608
    int value = getvalue(c);
4394 ripley 609
 
45017 ripley 610
    d->hit = value;
611
    hide(w);
4394 ripley 612
}
613
 
614
static void hit_key(window w, int key)
615
{
45017 ripley 616
    button btn;
617
    char *name = NULL;
4394 ripley 618
 
45017 ripley 619
    w = parentwindow(w);
4394 ripley 620
 
45017 ripley 621
    if (data(w) == NULL)
622
	return;
4394 ripley 623
 
45017 ripley 624
    if ((btn = data(w)->yes) != NULL) {
625
	name = getname(btn);
626
	if ((key == '\n') || (tolower(name[0]) == tolower(key)))
627
	{
628
	    flashcontrol(btn);
629
	    activatecontrol(btn);
630
	    return;
4394 ripley 631
	}
45017 ripley 632
    }
4394 ripley 633
 
45017 ripley 634
    if ((btn = data(w)->cancel) != NULL) {
635
	name = getname(btn);
636
	if ((key == ESC) || (tolower(name[0]) == tolower(key)))
637
	{
638
	    flashcontrol(btn);
639
	    activatecontrol(btn);
640
	    return;
4394 ripley 641
	}
45017 ripley 642
    }
4394 ripley 643
 
45017 ripley 644
    if ((btn = data(w)->no) != NULL) {
645
	name = getname(btn);
646
	if ((key == ESC) || (tolower(name[0]) == tolower(key)))
647
	{
648
	    flashcontrol(btn);
649
	    activatecontrol(btn);
650
	    return;
4394 ripley 651
	}
45017 ripley 652
    }
4394 ripley 653
 
654
}
655
 
656
/*
657
 *  Handle the events from a message dialog, hide the window afterwards.
658
 */
659
static int handle_message_dialog(window w)
660
{
45017 ripley 661
    window old;
662
    dialog_data *d = data(w);
4394 ripley 663
 
45017 ripley 664
    old = currentdrawing();
665
    d->hit = NOT_CHOSEN_YET;
4394 ripley 666
 
45017 ripley 667
    show(w);
668
    while (d->hit == NOT_CHOSEN_YET) {
64106 murdoch 669
	waitevent();
45017 ripley 670
	doevent();
671
    }
672
    hide(w);
4394 ripley 673
 
45017 ripley 674
    if (old) drawto(old);
4394 ripley 675
 
45017 ripley 676
    return d->hit;
4394 ripley 677
}
678
 
84234 kalibera 679
void clickbutton(window w, button b) {
680
    sendmessage(w->handle, WM_COMMAND,
681
	(BN_CLICKED << 16) | GetWindowLong(b->handle, GWL_ID),
682
	b->handle);
683
}
684
 
685
static void askstr_dialog_close(window win)
686
{
687
    dialog_data *d;
688
 
689
    d = data(win);
690
    clickbutton(win, d->cancel);
691
}
692
 
41793 ripley 693
static window init_askstr_dialog(const char *title, const char *question,
694
				 const char *default_str)
4394 ripley 695
{
45017 ripley 696
    window win;
697
    dialog_data *d;
698
    int tw, bw, h, middle;
4394 ripley 699
 
45017 ripley 700
    if (! question)
701
	question= "";
702
    if (! default_str)
703
	default_str = "";
4394 ripley 704
 
45017 ripley 705
    tw = strwidth(SystemFont, G_("Cancel")) * 8;
706
    h = getheight(SystemFont);
4394 ripley 707
 
45017 ripley 708
    if (tw < 150) tw = 150;
4394 ripley 709
 
45017 ripley 710
    win = newwindow(title, rect(0,0,tw+30,h*9+12),
711
		    Titlebar | Centered | Modal);
712
    setbackground(win, dialog_bg());
713
    add_data(win);
714
    d = data(win);
715
    d->question = newlabel(question, rect(10,h,tw+4,h*2+2),
716
			   AlignLeft);
717
    if (title == PASSWORD_TITLE)
718
	d->text = newpassword(default_str, rect(10,h*4,tw+4,h*3/2));
719
    else
720
	d->text = newfield(default_str, rect(10,h*4,tw+4,h*3/2));
4394 ripley 721
 
45017 ripley 722
    middle = (tw+30)/2;
723
    bw = strwidth(SystemFont, G_("Cancel")) * 3/2;
4394 ripley 724
 
45017 ripley 725
    d->yes = newbutton(G_("OK"),
726
		       rect(middle-bw-10, h*7, bw, h+10), hit_button);
727
    setvalue(d->yes, YES);
4394 ripley 728
 
45017 ripley 729
    d->cancel = newbutton(G_("Cancel"),
730
			  rect(middle+10, h*7, bw, h+10), hit_button);
731
    setvalue(d->cancel, CANCEL);
4394 ripley 732
 
84234 kalibera 733
    setclose(win, askstr_dialog_close);
45017 ripley 734
    setkeydown(win, hit_key);
4394 ripley 735
 
45017 ripley 736
    return win;
4394 ripley 737
}
738
 
41793 ripley 739
char *askstring(const char *question, const char *default_str)
4394 ripley 740
{
45017 ripley 741
    static window win = NULL;
742
    window prev = current_window;
4394 ripley 743
 
45017 ripley 744
    if (! win)
745
	win = init_askstr_dialog(QUESTION_TITLE, question, default_str);
746
    else {
747
	settext(data(win)->question, question);
748
	settext(data(win)->text, default_str);
749
    }
750
    if (TopmostDialogs & MB_TOPMOST)
751
	BringToTop(win, 1);
752
    handle_message_dialog(win);
753
    current_window = prev;
28854 murdoch 754
 
45017 ripley 755
    return get_dialog_string(win);
4394 ripley 756
}
757
 
41793 ripley 758
char *askcdstring(const char *question, const char *default_str)
4606 ripley 759
{
83778 kalibera 760
    HRESULT res;
761
    IFileOpenDialog *fileOpen = NULL;
762
    IShellItem *dirsi = NULL;
763
    DWORD flags = 0;
83910 kalibera 764
    int ok = 0;
83778 kalibera 765
    wchar_t *wquestion, *wdefault_str, *wdir = NULL;
766
    size_t nb;
45017 ripley 767
 
83778 kalibera 768
    wquestion = mbstowcs_malloc(question);
769
    wdefault_str = mbstowcs_malloc(default_str);
4606 ripley 770
 
83778 kalibera 771
    res = CoCreateInstance(&CLSID_FileOpenDialog, NULL, CLSCTX_INPROC_SERVER,
772
                     &IID_IFileOpenDialog, (void **)&fileOpen);
773
 
774
    if (SUCCEEDED(res) && fileOpen && wquestion && wdefault_str) {
775
	ok = SUCCEEDED(fileOpen->lpVtbl->GetOptions(fileOpen, &flags));
776
	flags |= FOS_PICKFOLDERS | FOS_FILEMUSTEXIST |
777
		 FOS_NOCHANGEDIR;
778
	flags &= ~FOS_ALLOWMULTISELECT & ~FOS_OVERWRITEPROMPT &
779
		 ~FOS_ALLNONSTORAGEITEMS;
780
	ok = ok && SUCCEEDED(fileOpen->lpVtbl->SetOptions(fileOpen, flags));
781
	ok = ok && SUCCEEDED(fileOpen->lpVtbl->SetTitle(fileOpen, wquestion));
782
	ok = ok && SUCCEEDED(fileOpen->lpVtbl->SetFileName(fileOpen,
783
	                                                   wdefault_str));
28854 murdoch 784
 
83778 kalibera 785
	ok = ok && SUCCEEDED(fileOpen->lpVtbl->Show(fileOpen, NULL));
786
	ok = ok && SUCCEEDED(fileOpen->lpVtbl->GetResult(fileOpen, &dirsi));
787
	ok = ok && SUCCEEDED(dirsi->lpVtbl->GetDisplayName(dirsi,
788
	                                                   SIGDN_FILESYSPATH,
789
	                                                   &wdir));
790
	if (ok && dirsi) {
791
	    nb = wcstombs(strbuf, wdir, BUFSIZE);
792
	    if (nb == (size_t)-1 || nb >= BUFSIZE) {
793
		strbuf[0] = 0;
794
		ok = 0;
795
	    }
796
	}
43863 murdoch 797
    }
83778 kalibera 798
    if (wdir)
799
	CoTaskMemFree(wdir);
800
    if (dirsi)
801
	dirsi->lpVtbl->Release(dirsi);
802
    if (fileOpen)
803
	fileOpen->lpVtbl->Release(fileOpen);
804
    if (wquestion)
805
	free(wquestion);
806
    if (wdefault_str)
807
	free(wdefault_str);
808
    return ok ? strbuf : NULL; 
4606 ripley 809
}
810
 
41793 ripley 811
char *askpassword(const char *question, const char *default_str)
4394 ripley 812
{
45017 ripley 813
    static window win = NULL;
814
    window prev = current_window;
4394 ripley 815
 
45017 ripley 816
    if (! win)
817
	win = init_askstr_dialog(PASSWORD_TITLE, question, default_str);
818
    else {
819
	settext(data(win)->question, question);
820
	settext(data(win)->text, default_str);
821
    }
822
    if (TopmostDialogs & MB_TOPMOST)
823
	BringToTop(win, 1);
824
    handle_message_dialog(win);
825
    current_window = prev;
28854 murdoch 826
 
45017 ripley 827
    return get_dialog_string(win);
4394 ripley 828
}
829
 
41793 ripley 830
char *askUserPass(const char *title)
22785 ripley 831
{
832
    static window win = NULL;
833
    dialog_data *d;
834
    window prev = current_window;
835
 
836
    if (! win) {
837
	int tw, bw, h, middle;
838
 
37809 ripley 839
	tw = strwidth(SystemFont, G_("Cancel")) * 8;
22785 ripley 840
	h = getheight(SystemFont);
841
	if (tw < 150) tw = 150;
842
	win = newwindow(title, rect(0, 0, tw+30, h*9+12),
843
			Titlebar | Centered | Modal);
45017 ripley 844
	setbackground(win, dialog_bg());
22785 ripley 845
	add_data(win);
846
	d = data(win);
33088 ripley 847
	d->question = newlabel(G_("User"), rect(10, h, tw+4, h*2+2), AlignLeft);
848
	bw = strwidth(SystemFont, G_("Password"));
22785 ripley 849
	d->text = newfield("", rect(20+bw, h, tw-6-bw, h*3/2));
33093 ripley 850
	newlabel(_("Password"), rect(10, h*4, tw+4, h*2+2), AlignLeft);
22785 ripley 851
	d->pass = newpassword("", rect(20+bw, h*4, tw-6-bw, h*3/2));
852
	middle = (tw+30)/2;
37809 ripley 853
	bw = strwidth(SystemFont, G_("Cancel")) * 3/2;
22785 ripley 854
 
37809 ripley 855
	d->yes = newbutton(G_("OK"),
856
			   rect(middle-bw-10, h*7, bw, h+10), hit_button);
22785 ripley 857
	setvalue(d->yes, YES);
858
 
37809 ripley 859
	d->cancel = newbutton(G_("Cancel"),
860
			      rect(middle+10, h*7, bw, h+10), hit_button);
22785 ripley 861
	setvalue(d->cancel, CANCEL);
862
 
863
	setkeydown(win, hit_key);
864
    } else {
865
	d = data(win);
866
	settext(d->text, "");
867
	settext(d->pass, "");
868
    }
28854 murdoch 869
    if (TopmostDialogs & MB_TOPMOST)
870
	BringToTop(win, 1);
22785 ripley 871
    handle_message_dialog(win);
872
    current_window = prev;
873
    {
874
	char *user, *pass;
875
	static char buf[1000];
876
	if (d->hit < YES) /* cancelled */ return "";
39274 ripley 877
	if (d->text) user = new_string(GA_gettext(d->text));
22785 ripley 878
	else return "";
39274 ripley 879
	if (d->pass) pass = new_string(GA_gettext(d->pass));
22785 ripley 880
	else return "";
25313 ripley 881
	snprintf(buf, 1000, "%s:%s", user, pass);
22785 ripley 882
	return buf;
883
    }
884
    return ""; /* -Wall */
885
}
28991 murdoch 886
 
84952 kalibera 887
int modeless_active(void)
28991 murdoch 888
{
889
    if (hModelessDlg)
890
	return 1;
891
    return 0;
892
}
893
 
894
PROTECTED
84952 kalibera 895
HWND get_modeless(void)
28991 murdoch 896
{
897
    return hModelessDlg;
898
}
899
 
45017 ripley 900
void finddialog(textbox t)
901
{
28991 murdoch 902
    static FINDREPLACE fr;
903
    static char szFindWhat[80];
904
 
905
    fr.lStructSize = sizeof(fr);
906
    fr.hwndOwner = t->handle;
907
    fr.lpstrFindWhat = szFindWhat;
908
    fr.wFindWhatLen = 80;
909
    fr.Flags = FR_DOWN;
910
    fr.lCustData        = 0 ;
911
    fr.lpfnHook         = NULL ;
912
    fr.lpTemplateName   = NULL ;
913
 
914
    hModelessDlg = FindText(&fr);
915
}
916
 
45017 ripley 917
void replacedialog(textbox t)
918
{
28991 murdoch 919
    static FINDREPLACE fr;
920
    static char szFindWhat[80];
921
    static char szReplaceWith[80];
922
 
923
    fr.lStructSize = sizeof(fr);
924
    fr.hwndOwner = t->handle;
925
    fr.lpstrFindWhat = szFindWhat;
926
    fr.lpstrReplaceWith = szReplaceWith;
927
    fr.wFindWhatLen = 80;
928
    fr.wReplaceWithLen = 80;
929
    fr.Flags = FR_DOWN;
930
    fr.lCustData        = 0 ;
931
    fr.lpfnHook         = NULL ;
932
    fr.lpTemplateName   = NULL ;
933
 
934
    hModelessDlg = ReplaceText(&fr);
935
}
936
 
937
 
43889 ripley 938
#include <richedit.h>
28991 murdoch 939
/* Find and select a string in a rich edit control */
940
 
41793 ripley 941
static int richeditfind(HWND hwnd, char *what, int matchcase,
942
			int wholeword, int down)
28991 murdoch 943
{
944
    long start, end;
945
    CHARRANGE sel;
946
    WPARAM w = 0;
88859 kalibera 947
    FINDTEXTEXW ft = { 0 };
28991 murdoch 948
    sendmessage (hwnd, EM_EXGETSEL, 0, &sel) ;
949
    start = sel.cpMin;
950
    end = sel.cpMax;
82766 kalibera 951
 
952
    /* RichEdit20W (see newrichtextarea) requires a Unicode string. */
83775 kalibera 953
    wchar_t *wwhat = mbstowcs_malloc(what);
954
    if (!wwhat)
955
	return 0;
82766 kalibera 956
    ft.lpstrText = wwhat;
957
 
28991 murdoch 958
    ft.chrgText.cpMin = start;
959
    ft.chrgText.cpMax = end;
960
    if (down) {
961
	w = w | FR_DOWN;
962
	ft.chrg.cpMin = end;
963
	ft.chrg.cpMax = -1;
964
    }
965
    else {
966
	ft.chrg.cpMin = start;
967
	ft.chrg.cpMax = 0;
968
    }
969
    if (matchcase) w = w | FR_MATCHCASE;
970
    if (wholeword) w = w | FR_WHOLEWORD;
82768 kalibera 971
    /* The cast is necessary, because EM_FINDTEXTEXW returns LONG (32-bit),
972
       but the rest of the 64-bit LRESULT is undefined (not all 1s for -1).
973
       Checking chrgText.cpMin and chrgText.cpMax is for safety only:
974
       returning 1 here by accident instead of 0 would lead to infinite loop
975
       during replace all. */
82774 kalibera 976
    long res = (LONG) sendmessage (hwnd, EM_FINDTEXTEXW, w, &ft);
82766 kalibera 977
    if (res == -1 || (ft.chrgText.cpMin == -1 && ft.chrgText.cpMax == -1)) {
978
	free(wwhat);
28991 murdoch 979
	return 0;
82766 kalibera 980
    } else {
28991 murdoch 981
	sendmessage (hwnd, EM_EXSETSEL, 0, &(ft.chrgText));
82768 kalibera 982
	sendmessage (hwnd, EM_SCROLLCARET, 0, 0);
28991 murdoch 983
    }
82766 kalibera 984
    free(wwhat);
28991 murdoch 985
    return 1;
986
}
987
 
41793 ripley 988
static int richeditreplace(HWND hwnd, char *what, char *replacewith,
989
			   int matchcase, int wholeword, int down)
28991 murdoch 990
{
991
    /* If current selection is the find string, replace it and find next */
992
    long start, end;
993
    CHARRANGE sel;
82766 kalibera 994
    wchar_t *wbuf;
28991 murdoch 995
    textbox t = find_by_handle(hwnd);
31401 murdoch 996
    if (t) {
997
	sendmessage (hwnd, EM_EXGETSEL, 0, &sel) ;
998
	start = sel.cpMin;
999
	end = sel.cpMax;
1000
	if (start < end) {
82766 kalibera 1001
	    /* RichEdit20W (see newrichtextarea) produces a Unicode string. */
83775 kalibera 1002
	    wchar_t *wwhat = mbstowcs_malloc(what);
82766 kalibera 1003
	    wbuf = (wchar_t *) malloc((end - start + 1)*sizeof(wchar_t));
83775 kalibera 1004
	    if (!wwhat || !wbuf)
1005
		return 0;
82766 kalibera 1006
	    sendmessage(hwnd, EM_GETSELTEXT, 0, wbuf);
1007
 
1008
	    if (!wcscmp(wbuf, wwhat)) {
31401 murdoch 1009
		checklimittext(t, strlen(replacewith) - strlen(what) + 2);
1010
		sendmessage (hwnd, EM_REPLACESEL, 1, replacewith);
1011
	    }
82766 kalibera 1012
	    free(wwhat);	
1013
	    free(wbuf);
28991 murdoch 1014
	}
31401 murdoch 1015
	/* else just find next */
1016
	if (richeditfind(hwnd, what, matchcase, wholeword, down))
1017
	    return 1;
28991 murdoch 1018
    }
1019
    return 0;
1020
}
1021
 
1022
PROTECTED
1023
void handle_findreplace(HWND hwnd, LPFINDREPLACE pfr)
1024
{
1025
    CHARRANGE sel;
1026
    int matchcase=0, wholeword=0, down=0;
1027
    char buf[100];
1028
    if (pfr->Flags & FR_MATCHCASE) matchcase = 1;
1029
    if (pfr->Flags & FR_WHOLEWORD) wholeword = 1;
1030
    if (pfr->Flags & FR_DOWN) down = 1;
1031
 
1032
    if (pfr->Flags & FR_FINDNEXT) {
1033
	if (!richeditfind(hwnd, pfr->lpstrFindWhat, matchcase, wholeword, down)) {
33088 ripley 1034
	    snprintf(buf, 100, G_("\"%s\" not found"), pfr->lpstrFindWhat);
28991 murdoch 1035
	    askok(buf);
1036
	}
1037
    }
1038
    else if (pfr->Flags & FR_REPLACE) {
1039
	if (!richeditreplace(hwnd, pfr->lpstrFindWhat, pfr->lpstrReplaceWith, matchcase, wholeword, down)) {
33088 ripley 1040
	    snprintf(buf, 100, G_("\"%s\" not found"), pfr->lpstrFindWhat);
28991 murdoch 1041
	    askok(buf);
1042
	}
1043
    }
1044
    else if (pfr->Flags & FR_REPLACEALL) {
1045
	/* replace all in the whole buffer then return to original selection state */
1046
	sendmessage (hwnd, EM_EXGETSEL, 0, &sel) ;
1047
	sendmessage (hwnd, EM_SETSEL, 0, 0) ;
1048
	while ( richeditreplace(hwnd, pfr->lpstrFindWhat, pfr->lpstrReplaceWith, matchcase, wholeword, down) ) ;
1049
	sendmessage (hwnd, EM_EXSETSEL, 0, &sel) ;
1050
    }
1051
 
1052
    else if (pfr->Flags & FR_DIALOGTERM)
1053
	hModelessDlg = NULL;
1054
}