Skip to content

Commit eb71965

Browse files
committed
0.8.0.60: Implemented file type filter dropdown for custom file picker, improved keyboard polish on various file picker controls.
1 parent 186a063 commit eb71965

2 files changed

Lines changed: 122 additions & 23 deletions

File tree

src/sqlite-ce-edit/filepicker.c

Lines changed: 121 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -24,32 +24,62 @@ static int g_pickerOK = 0;
2424
static int g_pickerDone = 0;
2525
static WNDPROC g_pfnListProc = NULL;
2626
static WNDPROC g_pfnEditProc = NULL;
27+
static HWND g_hwndFilter = NULL;
28+
29+
/* Forward declarations */
30+
static void PopulateFilterCombo(const wchar_t *filter);
2731

2832
/*============================================================================
29-
** Helper: Extract extension filter (e.g., "*.db" from filter string)
33+
** Helper: Get extension from current filter selection
3034
**============================================================================*/
3135

32-
static void GetFilterExt(const wchar_t *filter, wchar_t *ext, int maxLen) {
33-
/* Filter format: "Description\0*.ext\0..." - find first *.ext */
34-
const wchar_t *p = filter;
36+
static void GetCurrentFilterExt(wchar_t *ext, int maxLen) {
37+
wchar_t item[64];
3538
ext[0] = 0;
36-
if (!p) return;
39+
if (!g_hwndFilter) return;
3740

38-
/* Skip description */
39-
while (*p) p++;
40-
p++;
41-
42-
/* Copy extension pattern */
43-
if (*p == '*' && *(p+1) == '.') {
41+
GetWindowTextW(g_hwndFilter, item, 64);
42+
/* Item is like "*.csv" or "*.*" */
43+
if (item[0] == '*' && item[1] == '.') {
4444
int i = 0;
45-
p += 2; /* Skip *. */
46-
while (*p && *p != '\0' && i < maxLen - 1) {
45+
const wchar_t *p = item + 2;
46+
while (*p && i < maxLen - 1) {
47+
if (*p == '*') { ext[0] = 0; return; } /* *.* means all */
4748
ext[i++] = *p++;
4849
}
4950
ext[i] = 0;
5051
}
5152
}
5253

54+
/*============================================================================
55+
** Populate filter combobox from filter string
56+
**============================================================================*/
57+
58+
static void PopulateFilterCombo(const wchar_t *filter) {
59+
const wchar_t *p = filter;
60+
if (!filter || !g_hwndFilter) return;
61+
62+
SendMessageW(g_hwndFilter, CB_RESETCONTENT, 0, 0);
63+
64+
/* Filter format: "Desc\0*.ext\0Desc2\0*.ext2\0\0" */
65+
while (*p) {
66+
/* Skip description */
67+
while (*p) p++;
68+
p++;
69+
if (!*p) break;
70+
/* Add pattern (e.g., "*.csv") */
71+
SendMessageW(g_hwndFilter, CB_ADDSTRING, 0, (LPARAM)p);
72+
while (*p) p++;
73+
p++;
74+
}
75+
76+
/* Add "All files" option */
77+
SendMessageW(g_hwndFilter, CB_ADDSTRING, 0, (LPARAM)L"*.*");
78+
79+
/* Select first item */
80+
SendMessageW(g_hwndFilter, CB_SETCURSEL, 0, 0);
81+
}
82+
5383
/*============================================================================
5484
** Populate file list for current directory
5585
**============================================================================*/
@@ -125,7 +155,7 @@ static void PopulateFileList(void) {
125155

126156
/* Collect files matching filter */
127157
count = 0;
128-
GetFilterExt(g_pickerFilter, ext, 32);
158+
GetCurrentFilterExt(ext, 32);
129159
if (atRoot) {
130160
if (ext[0]) {
131161
wsprintfW(pattern, L"\\*.%s", ext);
@@ -272,18 +302,50 @@ static void OnTypeAhead(wchar_t ch) {
272302

273303
static void TabNext(HWND from) {
274304
if (from == g_hwndList) SetFocus(g_hwndFilename);
275-
else if (from == g_hwndFilename) SetFocus(g_hwndOK);
305+
else if (from == g_hwndFilename) SetFocus(g_hwndFilter);
306+
else if (from == g_hwndFilter) SetFocus(g_hwndOK);
276307
else if (from == g_hwndOK) SetFocus(g_hwndCancel);
277308
else SetFocus(g_hwndList);
278309
}
279310

280311
static void TabPrev(HWND from) {
281312
if (from == g_hwndList) SetFocus(g_hwndCancel);
282313
else if (from == g_hwndFilename) SetFocus(g_hwndList);
283-
else if (from == g_hwndOK) SetFocus(g_hwndFilename);
314+
else if (from == g_hwndFilter) SetFocus(g_hwndFilename);
315+
else if (from == g_hwndOK) SetFocus(g_hwndFilter);
284316
else SetFocus(g_hwndOK);
285317
}
286318

319+
/*============================================================================
320+
** Combobox subclass for Tab/Enter/Escape handling
321+
**============================================================================*/
322+
323+
static WNDPROC g_pfnComboProc = NULL;
324+
325+
static LRESULT CALLBACK PickerComboProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
326+
if (msg == WM_KEYDOWN) {
327+
if (wParam == VK_TAB) {
328+
if (GetKeyState(VK_SHIFT) & 0x8000)
329+
TabPrev(hwnd);
330+
else
331+
TabNext(hwnd);
332+
return 0;
333+
}
334+
if (wParam == VK_RETURN) {
335+
SendMessageW(g_hwndPicker, WM_COMMAND, IDOK, 0);
336+
return 0;
337+
}
338+
if (wParam == VK_ESCAPE) {
339+
g_pickerOK = 0;
340+
PostMessage(g_hwndPicker, WM_CLOSE, 0, 0);
341+
return 0;
342+
}
343+
}
344+
if (msg == WM_CHAR && (wParam == '\t' || wParam == '\r'))
345+
return 0;
346+
return CallWindowProc(g_pfnComboProc, hwnd, msg, wParam, lParam);
347+
}
348+
287349
/*============================================================================
288350
** Edit subclass for Tab/Enter handling
289351
**============================================================================*/
@@ -327,6 +389,11 @@ static LRESULT CALLBACK PickerBtnProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM
327389
TabNext(hwnd);
328390
return 0;
329391
}
392+
if (wParam == VK_RETURN) {
393+
/* Trigger the focused button */
394+
SendMessageW(g_hwndPicker, WM_COMMAND, GetDlgCtrlID(hwnd), 0);
395+
return 0;
396+
}
330397
if (wParam == VK_ESCAPE) {
331398
g_pickerOK = 0;
332399
PostMessage(g_hwndPicker, WM_CLOSE, 0, 0);
@@ -408,17 +475,24 @@ static LRESULT CALLBACK PickerWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM
408475
wsprintfW(g_pickerResult, L"%s\\%s", g_pickerDir, filename);
409476
}
410477

411-
/* Add default extension if missing */
412-
if (g_pickerDefExt && g_pickerDefExt[0]) {
478+
/* Add extension from filter if missing */
479+
{
413480
wchar_t *p = g_pickerResult + lstrlenW(g_pickerResult);
481+
wchar_t ext[32];
414482
int hasExt = 0;
415483
while (p > g_pickerResult && *p != '\\') {
416484
if (*p == '.') { hasExt = 1; break; }
417485
p--;
418486
}
419487
if (!hasExt) {
420-
lstrcatW(g_pickerResult, L".");
421-
lstrcatW(g_pickerResult, g_pickerDefExt);
488+
GetCurrentFilterExt(ext, 32);
489+
if (ext[0]) {
490+
lstrcatW(g_pickerResult, L".");
491+
lstrcatW(g_pickerResult, ext);
492+
} else if (g_pickerDefExt && g_pickerDefExt[0]) {
493+
lstrcatW(g_pickerResult, L".");
494+
lstrcatW(g_pickerResult, g_pickerDefExt);
495+
}
422496
}
423497
}
424498

@@ -463,6 +537,11 @@ static LRESULT CALLBACK PickerWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM
463537
}
464538
return 0;
465539
}
540+
/* Filter combobox change - refresh file list */
541+
if (cmd == 103 && notify == CBN_SELCHANGE) {
542+
PopulateFileList();
543+
return 0;
544+
}
466545
break;
467546
}
468547
case WM_KEYDOWN:
@@ -494,7 +573,8 @@ int CustomFilePicker(HWND hwndOwner, wchar_t *filePath, int maxPath,
494573
WNDCLASSW wc = {0};
495574
MSG msg;
496575
RECT rc;
497-
int dlgW = 300, dlgH = 195;
576+
int dlgW = 360, dlgH = 195;
577+
int filterW = 70;
498578

499579
/* Initialize state */
500580
g_pickerResult[0] = 0;
@@ -521,6 +601,16 @@ int CustomFilePicker(HWND hwndOwner, wchar_t *filePath, int maxPath,
521601
p++;
522602
}
523603
lstrcpyW(g_pickerResult, fn);
604+
605+
/* Strip extension from pre-filled filename */
606+
{
607+
wchar_t *dot = NULL, *s = g_pickerResult;
608+
while (*s) {
609+
if (*s == '.') dot = s;
610+
s++;
611+
}
612+
if (dot) *dot = 0;
613+
}
524614
}
525615

526616
/* Register window class once */
@@ -560,11 +650,20 @@ int CustomFilePicker(HWND hwndOwner, wchar_t *filePath, int maxPath,
560650
/* Filename edit */
561651
g_hwndFilename = CreateWindowW(L"EDIT", g_pickerResult,
562652
WS_CHILD | WS_VISIBLE | WS_BORDER | ES_AUTOHSCROLL,
563-
10, 110, dlgW - 20, 22, g_hwndPicker, (HMENU)102, g_hInst, NULL);
653+
10, 116, dlgW - filterW - 25, 22, g_hwndPicker, (HMENU)102, g_hInst, NULL);
564654

565655
/* Subclass edit */
566656
g_pfnEditProc = (WNDPROC)SetWindowLong(g_hwndFilename, GWL_WNDPROC, (LONG)PickerEditProc);
567657

658+
/* Filter combobox */
659+
g_hwndFilter = CreateWindowW(L"COMBOBOX", NULL,
660+
WS_CHILD | WS_VISIBLE | WS_BORDER | CBS_DROPDOWNLIST,
661+
dlgW - filterW - 10, 116, filterW, 100, g_hwndPicker, (HMENU)103, g_hInst, NULL);
662+
PopulateFilterCombo(filter);
663+
664+
/* Subclass combobox */
665+
g_pfnComboProc = (WNDPROC)SetWindowLong(g_hwndFilter, GWL_WNDPROC, (LONG)PickerComboProc);
666+
568667
/* Buttons */
569668
g_hwndOK = CreateWindowW(L"BUTTON", saveMode ? L"Save" : L"Open",
570669
WS_CHILD | WS_VISIBLE | BS_DEFPUSHBUTTON,

src/sqlite-ce-edit/globals.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ BOOL WINAPI GetSaveFileNameW(CE_OPENFILENAME*);
8282
** Version
8383
**============================================================================*/
8484

85-
#define SQLITECEDIT_VERSION L"0.8.0.56"
85+
#define SQLITECEDIT_VERSION L"0.8.0.60"
8686

8787
/*============================================================================
8888
** Menu IDs

0 commit comments

Comments
 (0)