Skip to content

Commit 33e0130

Browse files
committed
FEAT: implemented request-dir on Windows
related to: Oldes/Rebol-wishes#29
1 parent d5efc5e commit 33e0130

File tree

5 files changed

+140
-4
lines changed

5 files changed

+140
-4
lines changed

src/boot/natives.reb

+16-4
Original file line numberDiff line numberDiff line change
@@ -936,11 +936,23 @@ evoke: native [
936936

937937
request-file: native [
938938
{Asks user to select a file and returns full file path (or block of paths).}
939-
/save "File save mode"
939+
/save "File save mode"
940940
/multi "Allows multiple file selection, returned as a block"
941-
/file name [file!] "Default file name or directory"
942-
/title text [string!] "Window title"
943-
/filter list [block!] "Block of filters (filter-name filter)"
941+
/file "Default file name or directory"
942+
name [file!]
943+
/title "Window title"
944+
text [string!]
945+
/filter "Block of filters (filter-name filter)"
946+
list [block!]
947+
]
948+
949+
request-dir: native [
950+
{Asks user to select a directory and returns full directory path (or block of paths).}
951+
/title "Change heading on request"
952+
text [string!]
953+
/dir "Set starting directory"
954+
name [file!]
955+
/keep "Keep previous directory path"
944956
]
945957

946958
ascii?: native [

src/core/n-io.c

+59
Original file line numberDiff line numberDiff line change
@@ -973,6 +973,65 @@ static REBSER *Read_All_File(char *fname)
973973

974974
return ser ? R_RET : R_NONE;
975975
#else
976+
Trap0(RE_FEATURE_NA);
977+
return R_NONE;
978+
#endif
979+
}
980+
981+
982+
/***********************************************************************
983+
**
984+
*/ REBNATIVE(request_dir)
985+
/*
986+
***********************************************************************/
987+
{
988+
#ifdef TO_WINDOWS
989+
REBRFR fr = {0};
990+
REBSER *ser;
991+
REBINT n;
992+
993+
fr.files = OS_MAKE(MAX_DIR_REQ_BUF);
994+
fr.len = MAX_DIR_REQ_BUF/sizeof(REBCHR) - 4; // reserve for trailing slash and null
995+
fr.files[0] = 0;
996+
997+
DISABLE_GC;
998+
999+
if (D_REF(ARG_REQUEST_DIR_DIR)) {
1000+
ser = Value_To_OS_Path(D_ARG(ARG_REQUEST_DIR_NAME), TRUE);
1001+
fr.dir = (REBCHR*)(ser->data);
1002+
n = ser->tail;
1003+
if (fr.dir[n-1] != OS_DIR_SEP) {
1004+
if (n+2 > fr.len) n = fr.len - 2;
1005+
COPY_STR(fr.files, (REBCHR*)(ser->data), n);
1006+
fr.files[n] = 0;
1007+
}
1008+
}
1009+
1010+
if (D_REF(ARG_REQUEST_DIR_TITLE))
1011+
fr.title = Val_Str_To_OS(D_ARG(ARG_REQUEST_DIR_TEXT));
1012+
else
1013+
fr.title = L"Select Folder";
1014+
1015+
if (D_REF(ARG_REQUEST_DIR_KEEP)) SET_FLAG(fr.flags, FRF_KEEP);
1016+
1017+
if (OS_REQUEST_DIR(&fr)) {
1018+
REBCNT len = (REBCNT)LEN_STR(fr.files);
1019+
// Windows may return path without trailing slash, so just add it if missing
1020+
if (fr.files[len-1] != '\\') {
1021+
fr.files[len++] = '\\';
1022+
fr.files[len ] = 0;
1023+
}
1024+
ser = To_REBOL_Path(fr.files, len, OS_WIDE, 0);
1025+
Set_Series(REB_FILE, D_RET, ser);
1026+
} else
1027+
ser = 0;
1028+
1029+
ENABLE_GC;
1030+
OS_FREE(fr.files);
1031+
1032+
return ser ? R_RET : R_NONE;
1033+
#else
1034+
Trap0(RE_FEATURE_NA);
9761035
return R_NONE;
9771036
#endif
9781037
}

src/include/reb-filereq.h

+1
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
***********************************************************************/
2828

2929
#define MAX_FILE_REQ_BUF (16*1024)
30+
#define MAX_DIR_REQ_BUF ( 1*1024) // windows has path limit 260 chars by default
3031

3132
#pragma pack(4)
3233
typedef struct Reb_File_Requestor {

src/os/win32/host-lib.c

+63
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@
5656
#include <stdio.h>
5757
#include <windows.h>
5858
#include <process.h>
59+
#include <ShlObj.h> // used for OS_Request_Dir
5960

6061
#include "reb-host.h"
6162
#include "host-lib.h"
@@ -1331,3 +1332,65 @@ static void *Task_Ready;
13311332
return ret;
13321333
}
13331334

1335+
static LPITEMIDLIST lpLastBrowseFolder = NULL;
1336+
static BOOL bBrowseFolderInit = FALSE;
1337+
static BFFCALLBACK BrowseCallbackProc(HWND hwnd, UINT uMsg, LPARAM lParam, LPARAM lpData) {
1338+
// Using this callback to set default folder.
1339+
// The SendMessage in BFFM_SELCHANGED is there to update focus on the directory
1340+
// Without it it would select the folder on init, but the folder could not be visible.
1341+
REBOOL set = FALSE;
1342+
1343+
switch (uMsg) {
1344+
case BFFM_INITIALIZED:
1345+
bBrowseFolderInit = TRUE;
1346+
set = TRUE;
1347+
break;
1348+
case BFFM_SELCHANGED:
1349+
if (bBrowseFolderInit) {
1350+
bBrowseFolderInit = FALSE;
1351+
set = TRUE;
1352+
}
1353+
break;
1354+
}
1355+
if (lpData && set) {
1356+
SendMessage(hwnd, BFFM_SETSELECTION, lpLastBrowseFolder != lpData, lpData);
1357+
}
1358+
return 0;
1359+
}
1360+
/***********************************************************************
1361+
**
1362+
*/ REBOOL OS_Request_Dir(REBRFR *fr)
1363+
/*
1364+
***********************************************************************/
1365+
{
1366+
BROWSEINFO bInfo = {0};
1367+
REBOOL keep = GET_FLAG(fr->flags, FRF_KEEP);
1368+
REBCHR *dir = fr->dir;
1369+
1370+
//bInfo.hwndOwner = Owner window // Must find a way to set this
1371+
bInfo.pidlRoot = NULL;
1372+
bInfo.pszDisplayName = fr->files; // Address of a buffer to receive the name of the folder selected by the user
1373+
bInfo.lpszTitle = fr->title; // Title of the dialog
1374+
bInfo.ulFlags = BIF_USENEWUI | BIF_RETURNONLYFSDIRS;
1375+
bInfo.lpfn = BrowseCallbackProc;
1376+
// start in dir location is used /dir
1377+
// else use last keeped result if used /keep
1378+
// else NULL if no /keep and /dir is there
1379+
bInfo.lParam = (dir) ? dir : (keep) ? lpLastBrowseFolder : NULL;
1380+
bInfo.iImage = -1;
1381+
1382+
LPITEMIDLIST lpItem = SHBrowseForFolder( &bInfo);
1383+
if(lpItem == NULL) {
1384+
// nothing selected
1385+
return FALSE;
1386+
}
1387+
if (keep) {
1388+
// release last result if there was any
1389+
if(lpLastBrowseFolder)
1390+
CoTaskMemFree(lpLastBrowseFolder);
1391+
// and store result for next request
1392+
lpLastBrowseFolder = lpItem;
1393+
}
1394+
SHGetPathFromIDList(lpItem, fr->files);
1395+
return TRUE;
1396+
}

src/tools/make-headers.reb

+1
Original file line numberDiff line numberDiff line change
@@ -348,6 +348,7 @@ acts: load %../boot/natives.reb
348348
foreach word [
349349
checksum
350350
request-file
351+
request-dir
351352
] [make-arg-enums word]
352353

353354
;?? output

0 commit comments

Comments
 (0)