1 /* Cockos SWELL (Simple/Small Win32 Emulation Layer for Linux/OSX)
2 Copyright (C) 2006 and later, Cockos, Inc.
4 This software is provided 'as-is', without any express or implied
5 warranty. In no event will the authors be held liable for any damages
6 arising from the use of this software.
8 Permission is granted to anyone to use this software for any purpose,
9 including commercial applications, and to alter it and redistribute it
10 freely, subject to the following restrictions:
12 1. The origin of this software must not be misrepresented; you must not
13 claim that you wrote the original software. If you use this software
14 in a product, an acknowledgment in the product documentation would be
15 appreciated but is not required.
16 2. Altered source versions must be plainly marked as such, and must not be
17 misrepresented as being the original software.
18 3. This notice may not be removed or altered from any source distribution.
21 This file provides basic APIs for browsing for files, directories, and messageboxes.
23 These APIs don't all match the Windows equivelents, but are close enough to make it not too much trouble.
28 #ifndef SWELL_PROVIDED_BY_APP
31 #include "swell-internal.h"
32 #include "swell-dlggen.h"
34 #include "../wdlcstring.h"
35 #include "../assocarray.h"
39 #include "../lineparse.h"
40 #define WDL_HASSTRINGS_EXPORT static
41 #include "../has_strings.h"
43 static const char *BFSF_Templ_dlgid
;
44 static DLGPROC BFSF_Templ_dlgproc
;
45 static struct SWELL_DialogResourceIndex
*BFSF_Templ_reshead
;
46 void BrowseFile_SetTemplate(const char *dlgid
, DLGPROC dlgProc
, struct SWELL_DialogResourceIndex
*reshead
)
48 BFSF_Templ_reshead
=reshead
;
49 BFSF_Templ_dlgid
=dlgid
;
50 BFSF_Templ_dlgproc
=dlgProc
;
53 class BrowseFile_State
56 static char s_sortrev
;
57 enum modeEnum
{ SAVE
=0,OPEN
, OPENMULTI
, OPENDIR
};
59 BrowseFile_State(const char *_cap
, const char *_idir
, const char *_ifile
, const char *_el
, modeEnum _mode
, char *_fnout
, int _fnout_sz
) :
60 caption(_cap
), initialdir(_idir
), initialfile(_ifile
), extlist(_el
), mode(_mode
),
61 sortcol(0), sortrev(0),
62 fnout(_fnout
), fnout_sz(_fnout_sz
), viewlist_store(16384), viewlist(4096)
71 const char *initialdir
;
72 const char *initialfile
;
76 char sortcol
, sortrev
;
78 char *fnout
; // if NULL this will be malloced by the window
85 int type
; // 1 = directory, 2 = file
87 void format_date(char *buf
, int bufsz
)
90 if (date
> 0 && date
< WDL_INT64_CONST(0x793406fff))
92 struct tm
*a
=localtime(&date
);
93 if (a
) strftime(buf
,bufsz
,"%c",a
);
97 void format_size(char *buf
, int bufsz
)
101 lstrcpyn_safe(buf
,"<DIR>",bufsz
);
105 static const char *tab
[]={ "bytes","KB","MB","GB" };
110 snprintf(buf
,bufsz
,"%d %s",(int)s
,tab
[0]);
115 do { w
++; lf
= (int)(s
&1023); s
/=1024; } while (s
>= 1024 && w
<4);
116 snprintf(buf
,bufsz
,"%d.%d %s",(int)s
,(int)((lf
*10.0)/1024.0+0.5),tab
[w
-1]);
121 char *format_all(char *buf
, int bufsz
)
123 char dstr
[128],sstr
[128];
124 format_date(dstr
,sizeof(dstr
));
125 format_size(sstr
,sizeof(sstr
));
126 snprintf(buf
,bufsz
,"%s\t%s\t%s",WDL_get_filepart(name
),dstr
,sstr
);
132 void viewlist_clear()
134 rec
*l
= viewlist_store
.Get();
135 const int n
= viewlist_store
.GetSize();
136 for (int x
= 0; x
< n
; x
++) free(l
[x
].name
);
137 viewlist_store
.Resize(0);
140 WDL_TypedBuf
<rec
> viewlist_store
;
141 WDL_PtrList
<rec
> viewlist
;
142 void viewlist_sort(const char *filter
)
148 const bool no_filter
= !*filter
|| !WDL_makeSearchFilter(filter
,&lp
);
149 for (int x
=0;x
<viewlist_store
.GetSize();x
++)
151 rec
*r
= viewlist_store
.Get()+x
;
153 if (no_filter
|| WDL_hasStrings(r
->format_all(tmp
,sizeof(tmp
)),&lp
))
158 if (viewlist
.GetSize()>1)
159 qsort(viewlist
.GetList(), viewlist
.GetSize(),sizeof(rec
*),
160 sortcol
== 1 ? sortFunc_sz
:
161 sortcol
== 2 ? sortFunc_date
:
164 static int sortFunc_fn(const void *_a
, const void *_b
)
166 const rec
*a
= *(const rec
* const*)_a
, *b
= *(const rec
* const*)_b
;
167 int d
= a
->type
- b
->type
;
169 d
= stricmp(a
->name
,b
->name
);
170 return s_sortrev
? -d
: d
;
172 static int sortFunc_date(const void *_a
, const void *_b
)
174 const rec
*a
= *(const rec
* const*)_a
, *b
= *(const rec
* const*)_b
;
175 if (a
->date
!= b
->date
) return s_sortrev
? (a
->date
>b
->date
?-1:1) : (a
->date
>b
->date
?1:-1);
176 return stricmp(a
->name
,b
->name
);
178 static int sortFunc_sz(const void *_a
, const void *_b
)
180 const rec
*a
= *(const rec
* const *)_a
, *b
= *(const rec
* const *)_b
;
181 int d
= a
->type
- b
->type
;
182 if (d
) return s_sortrev
? -d
: d
;
183 if (a
->size
!= b
->size
) return s_sortrev
? (a
->size
>b
->size
?-1:1) : (a
->size
>b
->size
?1:-1);
184 return stricmp(a
->name
,b
->name
);
188 void scan_path(const char *path
, const char *filterlist
, bool dir_only
)
191 DIR *dir
= opendir(path
);
195 while (NULL
!= (ent
= readdir(dir
)))
197 if (ent
->d_name
[0] == '.') continue;
198 bool is_dir
= (ent
->d_type
== DT_DIR
);
199 if (ent
->d_type
== DT_UNKNOWN
)
201 snprintf(tmp
,sizeof(tmp
),"%s/%s",path
,ent
->d_name
);
202 DIR *d
= opendir(tmp
);
203 if (d
) { is_dir
= true; closedir(d
); }
205 else if (ent
->d_type
== DT_LNK
)
207 snprintf(tmp
,sizeof(tmp
),"%s/%s",path
,ent
->d_name
);
208 char *rp
= realpath(tmp
,NULL
);
211 DIR *d
= opendir(rp
);
212 if (d
) { is_dir
= true; closedir(d
); }
216 if (!dir_only
|| is_dir
)
218 if (filterlist
&& *filterlist
&& !is_dir
)
220 const char *f
= filterlist
;
224 while (*nf
&& *nf
!= ';') nf
++;
228 while (nw
< nf
&& *nw
!= '*') nw
++;
230 if ((nw
!=nf
|| f
+strlen(ent
->d_name
) == nw
) && !strncasecmp(ent
->d_name
,f
,nw
-f
))
232 // matched leading text
241 if (!*f
|| *f
== ';' || (*f
== '.' && f
[1] == '*')) break;
242 size_t l
= strlen(ent
->d_name
);
243 if (f
+l
> nf
&& !strncasecmp(ent
->d_name
+ l
- (nf
-f
), f
,nf
-f
)) break;
246 while (*f
== ';') f
++;
248 if (!*f
) continue; // did not match
250 snprintf(tmp
,sizeof(tmp
),"%s/%s",path
,ent
->d_name
);
251 struct stat64 st
={0,};
254 rec r
= { st
.st_size
, st
.st_mtime
, strdup(ent
->d_name
), is_dir
?1:2 } ;
255 viewlist_store
.Add(&r
,1);
264 char BrowseFile_State::s_sortrev
;
266 static void preprocess_user_path(char *buf
, int bufsz
)
270 char *tmp
= strdup(buf
+1);
271 if (buf
[1] == '/' || !buf
[1])
273 char *p
= getenv("HOME");
274 if (p
&& *p
) snprintf(buf
,bufsz
,"%s%s",p
,tmp
);
278 snprintf(buf
,bufsz
,"/home/%s",tmp
); // if someone wants to write code to lookup homedirs, please, go right ahead!
284 static LRESULT WINAPI
swellFileSelectProc(HWND hwnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
286 enum { IDC_EDIT
=0x100, IDC_LABEL
, IDC_CHILD
, IDC_DIR
, IDC_LIST
, IDC_EXT
, IDC_PARENTBUTTON
, IDC_FILTER
};
287 enum { WM_UPD
=WM_USER
+100 };
288 const int maxPathLen
= 2048;
289 const char *multiple_files
= "(multiple files)";
293 if (lParam
) // swell-specific
295 SetWindowLong(hwnd
,GWL_WNDPROC
,(LPARAM
)SwellDialogDefaultWindowProc
);
296 SetWindowLong(hwnd
,DWL_DLGPROC
,(LPARAM
)swellFileSelectProc
);
298 SetWindowLong(hwnd
,GWL_STYLE
, GetWindowLong(hwnd
,GWL_STYLE
)|WS_THICKFRAME
);
300 SetWindowLongPtr(hwnd
,GWLP_USERDATA
,lParam
);
301 BrowseFile_State
*parms
= (BrowseFile_State
*)lParam
;
302 if (parms
->caption
) SetWindowText(hwnd
,parms
->caption
);
304 SWELL_MakeSetCurParms(1,1,0,0,hwnd
,false,false);
306 HWND edit
= SWELL_MakeEditField(IDC_EDIT
, 0,0,0,0, 0);
308 parms
->mode
== BrowseFile_State::OPENDIR
? "Choose directory" :
309 parms
->mode
== BrowseFile_State::SAVE
? "Save" : "Open",
312 SWELL_MakeButton(0, "Cancel", IDCANCEL
,0,0,0,0, 0);
313 HWND dir
= SWELL_MakeCombo(IDC_DIR
, 0,0,0,0, 0);
314 SWELL_MakeButton(0, "..", IDC_PARENTBUTTON
, 0,0,0,0, 0);
315 SWELL_MakeEditField(IDC_FILTER
, 0,0,0,0, 0);
317 const char *ent
= parms
->mode
== BrowseFile_State::OPENDIR
? "dir_browser" : "file_browser";
319 GetPrivateProfileString(".swell",ent
,"", tmp
,sizeof(tmp
),"");
320 int x
=0,y
=0,w
=0,h
=0, c1
=0,c2
=0,c3
=0;
321 int flag
= SWP_NOMOVE
| SWP_NOACTIVATE
| SWP_NOZORDER
;
323 sscanf(tmp
,"%d %d %d %d %d %d %d",&x
,&y
,&w
,&h
,&c1
,&c2
,&c3
) >= 4)
325 if (w
< 100) w
=SWELL_UI_SCALE(600);
326 if (h
< 100) h
=SWELL_UI_SCALE(400);
328 if (c1
+ c2
+ c3
< w
/2)
330 c1
=SWELL_UI_SCALE(280);
331 c2
=SWELL_UI_SCALE(120);
332 c3
=SWELL_UI_SCALE(140);
335 HWND list
= SWELL_MakeControl("",IDC_LIST
,"SysListView32",LVS_REPORT
|LVS_SHOWSELALWAYS
|
336 (parms
->mode
== BrowseFile_State::OPENMULTI
? 0 : LVS_SINGLESEL
)|
337 LVS_OWNERDATA
|WS_BORDER
|WS_TABSTOP
,0,0,0,0,0);
340 LVCOLUMN c
={LVCF_TEXT
|LVCF_WIDTH
, 0, c1
, (char*)"Filename" };
341 ListView_InsertColumn(list
,0,&c
);
343 c
.pszText
= (char*) "Size";
344 ListView_InsertColumn(list
,1,&c
);
346 c
.pszText
= (char*) "Date";
347 ListView_InsertColumn(list
,2,&c
);
348 HWND hdr
= ListView_GetHeader(list
);
350 memset(&hi
,0,sizeof(hi
));
351 hi
.mask
= HDI_FORMAT
;
352 hi
.fmt
= parms
->sortrev
? HDF_SORTDOWN
: HDF_SORTUP
;
353 Header_SetItem(hdr
,parms
->sortcol
,&hi
);
355 HWND extlist
= (parms
->extlist
&& *parms
->extlist
) ? SWELL_MakeCombo(IDC_EXT
, 0,0,0,0, CBS_DROPDOWNLIST
) : NULL
;
358 const char *p
= parms
->extlist
;
364 int a
= SendMessage(extlist
,CB_ADDSTRING
,0,(LPARAM
)rd
);
365 SendMessage(extlist
,CB_SETITEMDATA
,a
,(LPARAM
)p
);
368 SendMessage(extlist
,CB_SETCURSEL
,0,0);
371 SWELL_MakeLabel(-1,parms
->mode
== BrowseFile_State::OPENDIR
? "Directory: " : "File:",IDC_LABEL
, 0,0,0,0, 0);
373 if (BFSF_Templ_dlgid
&& BFSF_Templ_dlgproc
)
375 HWND dlg
= SWELL_CreateDialog(BFSF_Templ_reshead
, BFSF_Templ_dlgid
, hwnd
, BFSF_Templ_dlgproc
, 0);
376 if (dlg
) SetWindowLong(dlg
,GWL_ID
,IDC_CHILD
);
377 BFSF_Templ_dlgproc
=0;
381 SWELL_MakeSetCurParms(1,1,0,0,NULL
,false,false);
385 char buf
[maxPathLen
];
386 const char *filepart
= "";
387 if (parms
->initialfile
&& *parms
->initialfile
&& strcmp(parms
->initialfile
,"."))
389 lstrcpyn_safe(buf
,parms
->initialfile
,sizeof(buf
));
390 char *p
= (char *)WDL_get_filepart(buf
);
398 filepart
= parms
->initialfile
;
405 if (parms
->initialdir
&& *parms
->initialdir
&& strcmp(parms
->initialdir
,"."))
407 lstrcpyn_safe(buf
,parms
->initialdir
,sizeof(buf
));
409 else getcwd(buf
,sizeof(buf
));
412 SetWindowText(edit
,filepart
);
413 SendMessage(hwnd
, WM_UPD
, IDC_DIR
, (LPARAM
)buf
);
416 if (list
) SetWindowPos(list
,HWND_BOTTOM
,0,0,0,0,SWP_NOMOVE
|SWP_NOSIZE
|SWP_NOACTIVATE
);
417 SetWindowPos(hwnd
,NULL
,x
,y
, w
,h
, flag
);
418 SendMessage(hwnd
,WM_UPD
,1,0);
419 SendMessage(edit
,EM_SETSEL
,0,(LPARAM
)-1);
425 BrowseFile_State
*parms
= (BrowseFile_State
*)GetWindowLongPtr(hwnd
,GWLP_USERDATA
);
429 GetWindowRect(hwnd
,&r
);
430 HWND list
= GetDlgItem(hwnd
,IDC_LIST
);
431 const int c1
= ListView_GetColumnWidth(list
,0);
432 const int c2
= ListView_GetColumnWidth(list
,1);
433 const int c3
= ListView_GetColumnWidth(list
,2);
435 snprintf(tmp
,sizeof(tmp
),"%d %d %d %d %d %d %d",r
.left
,r
.top
,r
.right
-r
.left
,r
.bottom
-r
.top
,c1
,c2
,c3
);
436 const char *ent
= parms
->mode
== BrowseFile_State::OPENDIR
? "dir_browser" : "file_browser";
437 WritePrivateProfileString(".swell",ent
, tmp
, "");
444 case IDC_DIR
: // update directory combo box -- destroys buffer pointed to by lParam
447 char *path
= (char*)lParam
;
448 HWND combo
=GetDlgItem(hwnd
,IDC_DIR
);
449 SendMessage(combo
,CB_RESETCONTENT
,0,0);
450 WDL_remove_trailing_dirchars(path
);
453 SendMessage(combo
,CB_ADDSTRING
,0,(LPARAM
)path
);
454 WDL_remove_filepart(path
);
455 WDL_remove_trailing_dirchars(path
);
457 SendMessage(combo
,CB_ADDSTRING
,0,(LPARAM
)"/");
458 SendMessage(combo
,CB_SETCURSEL
,0,0);
463 BrowseFile_State
*parms
= (BrowseFile_State
*)GetWindowLongPtr(hwnd
,GWLP_USERDATA
);
466 SetDlgItemText(hwnd
,IDC_FILTER
,"");
469 char buf
[maxPathLen
];
470 const char *filt
= NULL
;
472 int a
= (int) SendDlgItemMessage(hwnd
,IDC_EXT
,CB_GETCURSEL
,0,0);
473 if (a
>=0) filt
= (const char *)SendDlgItemMessage(hwnd
,IDC_EXT
,CB_GETITEMDATA
,a
,0);
475 GetDlgItemText(hwnd
,IDC_DIR
,buf
,sizeof(buf
));
476 preprocess_user_path(buf
,sizeof(buf
));
478 if (buf
[0]) parms
->scan_path(buf
, filt
, parms
->mode
== BrowseFile_State::OPENDIR
);
479 else parms
->viewlist_clear();
480 HWND list
= GetDlgItem(hwnd
,IDC_LIST
);
481 ListView_SetItemCount(list
, 0); // clear selection
483 parms
->viewlist_sort("");
484 ListView_SetItemCount(list
, parms
->viewlist
.GetSize());
485 ListView_RedrawItems(list
,0, parms
->viewlist
.GetSize());
491 case WM_GETMINMAXINFO
:
493 LPMINMAXINFO p
=(LPMINMAXINFO
)lParam
;
494 p
->ptMinTrackSize
.x
= 300;
495 p
->ptMinTrackSize
.y
= 300;
500 BrowseFile_State
*parms
= (BrowseFile_State
*)GetWindowLongPtr(hwnd
,GWLP_USERDATA
);
501 // reposition controls
503 GetClientRect(hwnd
,&r
);
504 const int buth
= SWELL_UI_SCALE(24), cancelbutw
= SWELL_UI_SCALE(50), okbutw
= SWELL_UI_SCALE(parms
->mode
== BrowseFile_State::OPENDIR
? 120 : 50);
505 const int xborder
= SWELL_UI_SCALE(4), yborder
=SWELL_UI_SCALE(8);
506 const int fnh
= SWELL_UI_SCALE(20), fnlblw
= SWELL_UI_SCALE(parms
->mode
== BrowseFile_State::OPENDIR
? 70 : 50);
507 const int ypad
= SWELL_UI_SCALE(4);
509 int ypos
= r
.bottom
- ypad
- buth
;
511 SetWindowPos(GetDlgItem(hwnd
,IDCANCEL
), NULL
, xpos
-= cancelbutw
+ xborder
, ypos
, cancelbutw
,buth
, SWP_NOZORDER
|SWP_NOACTIVATE
);
512 SetWindowPos(GetDlgItem(hwnd
,IDOK
), NULL
, xpos
-= okbutw
+ xborder
, ypos
, okbutw
,buth
, SWP_NOZORDER
|SWP_NOACTIVATE
);
514 HWND emb
= GetDlgItem(hwnd
,IDC_CHILD
);
518 GetClientRect(emb
,&sr
);
519 if (ypos
> r
.bottom
-ypad
-sr
.bottom
) ypos
= r
.bottom
-ypad
-sr
.bottom
;
520 SetWindowPos(emb
,NULL
, xborder
,ypos
, xpos
- xborder
*2, sr
.bottom
, SWP_NOZORDER
|SWP_NOACTIVATE
);
521 ShowWindow(emb
,SW_SHOWNA
);
524 HWND filt
= GetDlgItem(hwnd
,IDC_EXT
);
527 SetWindowPos(filt
, NULL
, xborder
*2 + fnlblw
, ypos
-= fnh
+ yborder
, r
.right
-fnlblw
-xborder
*3, fnh
, SWP_NOZORDER
|SWP_NOACTIVATE
);
530 SetWindowPos(GetDlgItem(hwnd
,IDC_EDIT
), NULL
, xborder
*2 + fnlblw
, ypos
-= fnh
+ yborder
, r
.right
-fnlblw
-xborder
*3, fnh
, SWP_NOZORDER
|SWP_NOACTIVATE
);
531 SetWindowPos(GetDlgItem(hwnd
,IDC_LABEL
), NULL
, xborder
, ypos
, fnlblw
, fnh
, SWP_NOZORDER
|SWP_NOACTIVATE
);
532 const int comboh
= g_swell_ctheme
.combo_height
;
533 const int filterw
= wdl_max(r
.right
/8, SWELL_UI_SCALE(50));
534 SetWindowPos(GetDlgItem(hwnd
,IDC_DIR
), NULL
, xborder
, yborder
/2,
535 r
.right
-xborder
*4 - comboh
- filterw
, comboh
, SWP_NOZORDER
|SWP_NOACTIVATE
);
537 SetWindowPos(GetDlgItem(hwnd
,IDC_PARENTBUTTON
),NULL
,
538 r
.right
-xborder
*2-comboh
- filterw
,yborder
/2,
539 comboh
,comboh
,SWP_NOZORDER
|SWP_NOACTIVATE
);
541 SetWindowPos(GetDlgItem(hwnd
,IDC_FILTER
),NULL
,
542 r
.right
-xborder
-filterw
,yborder
/2 + (comboh
-fnh
)/2,
543 filterw
,fnh
,SWP_NOZORDER
|SWP_NOACTIVATE
);
545 SetWindowPos(GetDlgItem(hwnd
,IDC_LIST
), NULL
, xborder
, g_swell_ctheme
.combo_height
+yborder
, r
.right
-xborder
*2, ypos
- (g_swell_ctheme
.combo_height
+yborder
) - yborder
, SWP_NOZORDER
|SWP_NOACTIVATE
);
552 BrowseFile_State
*parms
= (BrowseFile_State
*)GetWindowLongPtr(hwnd
,GWLP_USERDATA
);
556 GetDlgItemText(hwnd
,IDC_FILTER
,buf
,sizeof(buf
));
557 parms
->viewlist_sort(buf
);
558 HWND list
= GetDlgItem(hwnd
,IDC_LIST
);
559 ListView_SetItemCount(list
, parms
->viewlist
.GetSize());
560 ListView_RedrawItems(list
,0, parms
->viewlist
.GetSize());
565 switch (LOWORD(wParam
))
568 if (HIWORD(wParam
) == EN_CHANGE
)
571 SetTimer(hwnd
,1,250,NULL
);
575 if (HIWORD(wParam
) == CBN_SELCHANGE
)
577 SendMessage(hwnd
,WM_UPD
,1,0);
580 case IDC_PARENTBUTTON
:
582 int a
= (int) SendDlgItemMessage(hwnd
,IDC_DIR
,CB_GETCURSEL
,0,0);
585 SendDlgItemMessage(hwnd
,IDC_DIR
,CB_SETCURSEL
,a
+1,0);
589 char buf
[maxPathLen
];
590 GetDlgItemText(hwnd
,IDC_DIR
,buf
,sizeof(buf
));
591 preprocess_user_path(buf
,sizeof(buf
));
592 WDL_remove_filepart(buf
);
593 SetDlgItemText(hwnd
,IDC_DIR
,buf
);
595 SendMessage(hwnd
,WM_UPD
,1,0);
599 if (HIWORD(wParam
) == CBN_SELCHANGE
)
601 SendMessage(hwnd
,WM_UPD
,1,0);
604 case IDCANCEL
: EndDialog(hwnd
,0); return 0;
607 char buf
[maxPathLen
], msg
[2048];
608 GetDlgItemText(hwnd
,IDC_DIR
,buf
,sizeof(buf
));
609 preprocess_user_path(buf
,sizeof(buf
));
611 if (GetFocus() == GetDlgItem(hwnd
,IDC_DIR
))
613 DIR *dir
= opendir(buf
);
616 //snprintf(msg,sizeof(msg),"Path does not exist:\r\n\r\n%s",buf);
617 //MessageBox(hwnd,msg,"Path not found",MB_OK);
622 SendMessage(hwnd
,WM_UPD
,1,0);
623 SendMessage(hwnd
, WM_UPD
, IDC_DIR
, (LPARAM
)buf
);
624 HWND e
= GetDlgItem(hwnd
,IDC_EDIT
);
625 SendMessage(e
,EM_SETSEL
,0,(LPARAM
)-1);
630 size_t buflen
= strlen(buf
);
631 if (!buflen
) strcpy(buf
,"/");
634 if (buflen
> sizeof(buf
)-2) buflen
= sizeof(buf
)-2;
635 if (buf
[buflen
-1]!='/') { buf
[buflen
++] = '/'; buf
[buflen
]=0; }
637 GetDlgItemText(hwnd
,IDC_EDIT
,msg
,sizeof(msg
));
638 preprocess_user_path(msg
,sizeof(msg
));
640 BrowseFile_State
*parms
= (BrowseFile_State
*)GetWindowLongPtr(hwnd
,GWLP_USERDATA
);
642 if (parms
->mode
== BrowseFile_State::OPENMULTI
&& (cnt
=ListView_GetSelectedCount(GetDlgItem(hwnd
,IDC_LIST
)))>1 && (!*msg
|| !strcmp(msg
,multiple_files
)))
644 HWND list
= GetDlgItem(hwnd
,IDC_LIST
);
645 WDL_TypedBuf
<char> fs
;
646 fs
.Set(buf
,strlen(buf
)+1);
647 int a
= ListView_GetNextItem(list
,-1,LVNI_SELECTED
);
648 while (a
!= -1 && fs
.GetSize() < 4096*4096 && cnt
--)
650 if (a
< 0 || a
>= parms
->viewlist
.GetSize()) break;
651 const struct BrowseFile_State::rec
*rec
= parms
->viewlist
.Get(a
);
654 fs
.Add(rec
->name
,strlen(rec
->name
)+1);
655 a
= ListView_GetNextItem(list
,a
,LVNI_SELECTED
);
659 parms
->fnout
= (char*)malloc(fs
.GetSize());
660 if (parms
->fnout
) memcpy(parms
->fnout
,fs
.Get(),fs
.GetSize());
667 if (msg
[0] == '.' && (msg
[1] == '.' || msg
[1] == 0))
671 int a
= (int) SendDlgItemMessage(hwnd
,IDC_DIR
,CB_GETCURSEL
,0,0);
672 if (a
>=0) SendDlgItemMessage(hwnd
,IDC_DIR
,CB_SETCURSEL
,a
+1,0);
674 SetDlgItemText(hwnd
,IDC_EDIT
,"");
675 SendMessage(hwnd
,WM_UPD
,1,0);
678 else if (msg
[0] == '/') lstrcpyn_safe(buf
,msg
,sizeof(buf
));
679 else lstrcatn(buf
,msg
,sizeof(buf
));
684 case BrowseFile_State::OPENDIR
:
685 if (!buf
[0]) return 0;
688 // navigate to directory if filepart set
690 DIR *dir
= opendir(buf
);
693 snprintf(msg
,sizeof(msg
),"Error opening directory:\r\n\r\n%s\r\n\r\nCreate?",buf
);
694 if (MessageBox(hwnd
,msg
,"Create directory?",MB_OKCANCEL
)==IDCANCEL
) return 0;
695 CreateDirectory(buf
,NULL
);
698 if (!dir
) { MessageBox(hwnd
,"Error creating directory","Error",MB_OK
); return 0; }
700 SendMessage(hwnd
, WM_UPD
, IDC_DIR
, (LPARAM
)buf
);
701 SetDlgItemText(hwnd
,IDC_EDIT
,"");
702 SendMessage(hwnd
,WM_UPD
,1,0);
708 DIR *dir
= opendir(buf
);
713 case BrowseFile_State::SAVE
:
714 if (!buf
[0]) return 0;
717 struct stat64 st
={0,};
718 DIR *dir
= opendir(buf
);
722 SendMessage(hwnd
, WM_UPD
, IDC_DIR
, (LPARAM
)buf
);
723 SetDlgItemText(hwnd
,IDC_EDIT
,"");
724 SendMessage(hwnd
,WM_UPD
,1,0);
727 if (buf
[strlen(buf
)-1] == '/') goto treatAsDir
;
728 if (!stat64(buf
,&st
))
730 snprintf(msg
,sizeof(msg
),"File exists:\r\n\r\n%s\r\n\r\nOverwrite?",buf
);
731 if (MessageBox(hwnd
,msg
,"Overwrite file?",MB_OKCANCEL
)==IDCANCEL
) return 0;
736 if (!buf
[0]) return 0;
739 struct stat64 st
={0,};
740 DIR *dir
= opendir(buf
);
744 SendMessage(hwnd
, WM_UPD
, IDC_DIR
, (LPARAM
)buf
);
745 SetDlgItemText(hwnd
,IDC_EDIT
,"");
746 SendMessage(hwnd
,WM_UPD
,1,0);
751 //snprintf(msg,sizeof(msg),"File does not exist:\r\n\r\n%s",buf);
752 //MessageBox(hwnd,msg,"File not found",MB_OK);
760 lstrcpyn_safe(parms
->fnout
,buf
,parms
->fnout_sz
);
764 size_t l
= strlen(buf
);
765 parms
->fnout
= (char*)calloc(l
+2,1);
766 memcpy(parms
->fnout
,buf
,l
);
775 LPNMHDR l
=(LPNMHDR
)lParam
;
776 if (l
->code
== LVN_GETDISPINFO
)
778 BrowseFile_State
*parms
= (BrowseFile_State
*)GetWindowLongPtr(hwnd
,GWLP_USERDATA
);
779 NMLVDISPINFO
*lpdi
= (NMLVDISPINFO
*) lParam
;
780 const int idx
=lpdi
->item
.iItem
;
781 if (l
->idFrom
== IDC_LIST
&& parms
)
783 struct BrowseFile_State::rec
*rec
= parms
->viewlist
.Get(idx
);
784 if (rec
&& rec
->name
)
786 if (lpdi
->item
.mask
&LVIF_TEXT
)
788 switch (lpdi
->item
.iSubItem
)
791 lstrcpyn_safe(lpdi
->item
.pszText
,rec
->name
,lpdi
->item
.cchTextMax
);
794 rec
->format_size(lpdi
->item
.pszText
,lpdi
->item
.cchTextMax
);
797 rec
->format_date(lpdi
->item
.pszText
,lpdi
->item
.cchTextMax
);
804 else if (l
->code
== LVN_ODFINDITEM
)
807 else if (l
->code
== LVN_ITEMCHANGED
)
809 const int selidx
= ListView_GetNextItem(l
->hwndFrom
, -1, LVNI_SELECTED
);
810 BrowseFile_State
*parms
= (BrowseFile_State
*)GetWindowLongPtr(hwnd
,GWLP_USERDATA
);
811 if (selidx
>=0 && parms
)
813 if (parms
->mode
== BrowseFile_State::OPENMULTI
&& ListView_GetSelectedCount(l
->hwndFrom
)>1)
815 SetDlgItemText(hwnd
,IDC_EDIT
,multiple_files
);
819 struct BrowseFile_State::rec
*rec
= parms
->viewlist
.Get(selidx
);
822 SetDlgItemText(hwnd
,IDC_EDIT
,rec
->name
);
827 else if (l
->code
== NM_DBLCLK
)
829 SendMessage(hwnd
,WM_COMMAND
,IDOK
,0);
831 else if (l
->code
== LVN_COLUMNCLICK
)
833 NMLISTVIEW
* lv
= (NMLISTVIEW
*) l
;
834 BrowseFile_State
*parms
= (BrowseFile_State
*)GetWindowLongPtr(hwnd
,GWLP_USERDATA
);
835 parms
->sortrev
=!parms
->sortrev
;
836 char lcol
= parms
->sortcol
;
837 if ((int)parms
->sortcol
!= lv
->iSubItem
)
839 parms
->sortcol
= (char)lv
->iSubItem
;
843 HWND hdr
= ListView_GetHeader(l
->hwndFrom
);
845 memset(&hi
,0,sizeof(hi
));
846 hi
.mask
= HDI_FORMAT
;
847 Header_SetItem(hdr
,lcol
,&hi
);
848 hi
.fmt
= parms
->sortrev
? HDF_SORTDOWN
: HDF_SORTUP
;
849 Header_SetItem(hdr
,parms
->sortcol
,&hi
);
851 parms
->viewlist_sort(NULL
);
852 ListView_RedrawItems(l
->hwndFrom
,0, parms
->viewlist
.GetSize());
857 if (lParam
== FVIRTKEY
&& wParam
== VK_F5
)
859 SendMessage(hwnd
,WM_UPD
,1,0);
862 else if (lParam
== FVIRTKEY
&& wParam
== VK_BACK
&&
863 GetFocus() == GetDlgItem(hwnd
,IDC_LIST
))
865 SendMessage(hwnd
,WM_COMMAND
,IDC_PARENTBUTTON
,0);
868 else if (lParam
== FVIRTKEY
&& wParam
== VK_RETURN
&&
869 GetFocus() == GetDlgItem(hwnd
,IDC_LIST
))
871 SendMessage(hwnd
,WM_COMMAND
,IDOK
,0);
880 bool BrowseForSaveFile(const char *text
, const char *initialdir
, const char *initialfile
, const char *extlist
,
881 char *fn
, int fnsize
)
883 BrowseFile_State
state( text
, initialdir
, initialfile
, extlist
, BrowseFile_State::SAVE
, fn
, fnsize
);
884 if (!DialogBoxParam(NULL
,NULL
,GetForegroundWindow(),swellFileSelectProc
,(LPARAM
)&state
)) return false;
885 if (fn
&& fnsize
> 0 && extlist
&& *extlist
&& WDL_get_fileext(fn
)[0] != '.')
887 const char *erd
= extlist
+strlen(extlist
)+1;
888 if (*erd
== '*' && erd
[1] == '.') // add default extension
890 const char *a
= (erd
+=1);
891 while (*erd
&& *erd
!= ';') erd
++;
892 if (erd
> a
+1) snprintf_append(fn
,fnsize
,"%.*s",(int)(erd
-a
),a
);
899 bool BrowseForDirectory(const char *text
, const char *initialdir
, char *fn
, int fnsize
)
901 BrowseFile_State
state( text
, initialdir
, initialdir
, NULL
, BrowseFile_State::OPENDIR
, fn
, fnsize
);
902 return !!DialogBoxParam(NULL
,NULL
,GetForegroundWindow(),swellFileSelectProc
,(LPARAM
)&state
);
906 char *BrowseForFiles(const char *text
, const char *initialdir
,
907 const char *initialfile
, bool allowmul
, const char *extlist
)
909 BrowseFile_State
state( text
, initialdir
, initialfile
, extlist
,
910 allowmul
? BrowseFile_State::OPENMULTI
: BrowseFile_State::OPEN
, NULL
, 0 );
911 return DialogBoxParam(NULL
,NULL
,GetForegroundWindow(),swellFileSelectProc
,(LPARAM
)&state
) ? state
.fnout
: NULL
;
915 static LRESULT WINAPI
swellMessageBoxProc(HWND hwnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
917 enum { IDC_LABEL
=0x100 };
918 const int button_spacing
= 8;
922 if (lParam
) // swell-specific
924 SetWindowLong(hwnd
,GWL_WNDPROC
,(LPARAM
)SwellDialogDefaultWindowProc
);
925 SetWindowLong(hwnd
,DWL_DLGPROC
,(LPARAM
)swellMessageBoxProc
);
926 void **parms
= (void **)lParam
;
927 if (parms
[1]) SetWindowText(hwnd
,(const char*)parms
[1]);
931 const char *buttons
[3] = { "OK", "", "" };
932 int button_ids
[3] = {IDOK
,0,0};
935 int mode
= ((int)(INT_PTR
)parms
[2]);
936 if (mode
== MB_RETRYCANCEL
) { buttons
[0]="Retry"; button_ids
[0]=IDRETRY
; }
937 if (mode
== MB_YESNO
|| mode
== MB_YESNOCANCEL
) { buttons
[0]="Yes"; button_ids
[0] = IDYES
; buttons
[nbuttons
] = "No"; button_ids
[nbuttons
] = IDNO
; nbuttons
++; }
938 if (mode
== MB_OKCANCEL
|| mode
== MB_YESNOCANCEL
|| mode
== MB_RETRYCANCEL
) { buttons
[nbuttons
] = "Cancel"; button_ids
[nbuttons
] = IDCANCEL
; nbuttons
++; }
940 SWELL_MakeSetCurParms(1,1,0,0,hwnd
,false,false);
941 RECT labsize
= {0,0,300,20};
942 HWND lab
= SWELL_MakeLabel(-1,parms
[0] ? (const char *)parms
[0] : "", IDC_LABEL
, 0,0,10,10,SS_CENTER
); //we'll resize this manually
946 DrawText(dc
,(const char *)parms
[0],-1,&labsize
,DT_CALCRECT
|DT_NOPREFIX
);// if dc isnt valid yet, try anyway
949 const int sc10
= SWELL_UI_SCALE(10);
950 const int sc8
= SWELL_UI_SCALE(8);
952 labsize
.bottom
+= sc10
+ sc8
;
955 int button_height
=0, button_total_w
=0;;
956 const int bspace
= SWELL_UI_SCALE(button_spacing
);
957 for (x
= 0; x
< nbuttons
; x
++)
960 DrawText(dc
,buttons
[x
],-1,&r
,DT_CALCRECT
|DT_NOPREFIX
|DT_SINGLELINE
);
961 button_sizes
[x
] = r
.right
-r
.left
+ sc10
;
962 button_total_w
+= button_sizes
[x
] + (x
? bspace
: 0);
963 if (r
.bottom
-r
.top
+sc10
> button_height
) button_height
= r
.bottom
-r
.top
+sc10
;
966 if (labsize
.right
< button_total_w
+sc8
*2) labsize
.right
= button_total_w
+sc8
*2;
968 int xpos
= labsize
.right
/2 - button_total_w
/2;
969 for (x
= 0; x
< nbuttons
; x
++)
971 SWELL_MakeButton(!x
,buttons
[x
],button_ids
[x
],xpos
,labsize
.bottom
,button_sizes
[x
],button_height
,0);
972 xpos
+= button_sizes
[x
] + bspace
;
975 if (dc
) ReleaseDC(lab
,dc
);
976 SWELL_MakeSetCurParms(1,1,0,0,NULL
,false,false);
977 SetWindowPos(hwnd
,NULL
,0,0,
978 labsize
.right
+ sc8
*2,labsize
.bottom
+ button_height
+ sc8
,SWP_NOACTIVATE
|SWP_NOZORDER
|SWP_NOMOVE
);
979 if (lab
) SetWindowPos(lab
,NULL
,sc8
,0,labsize
.right
,labsize
.bottom
,SWP_NOACTIVATE
|SWP_NOZORDER
);
980 SetFocus(GetDlgItem(hwnd
,button_ids
[0]));
986 GetClientRect(hwnd
,&r
);
987 HWND h
= GetWindow(hwnd
,GW_CHILD
);
989 HWND tab
[8],lbl
=NULL
;
990 int tabsz
=0, bxwid
=0, button_height
=0;
991 while (h
&& n
-- && tabsz
<8)
993 int idx
= GetWindowLong(h
,GWL_ID
);
994 if (idx
== IDCANCEL
|| idx
== IDOK
|| idx
== IDNO
|| idx
== IDYES
|| idx
== IDRETRY
)
997 GetClientRect(h
,&tr
);
999 w
[tabsz
++] = tr
.right
- tr
.left
;
1000 button_height
= tr
.bottom
-tr
.top
;
1001 bxwid
+= tr
.right
-tr
.left
;
1002 } else if (idx
==IDC_LABEL
) lbl
=h
;
1003 h
= GetWindow(h
,GW_HWNDNEXT
);
1005 const int bspace
= SWELL_UI_SCALE(button_spacing
), sc8
= SWELL_UI_SCALE(8);
1006 if (lbl
) SetWindowPos(h
,NULL
,sc8
,0,r
.right
,r
.bottom
- sc8
- button_height
, SWP_NOZORDER
|SWP_NOACTIVATE
);
1007 int xo
= r
.right
/2 - (bxwid
+ (tabsz
-1)*bspace
)/2;
1008 for (int x
=0; x
<tabsz
; x
++)
1010 SetWindowPos(tab
[x
],NULL
,xo
,r
.bottom
- button_height
- sc8
, 0,0, SWP_NOSIZE
|SWP_NOZORDER
|SWP_NOACTIVATE
);
1011 xo
+= w
[x
] + bspace
;
1016 if (LOWORD(wParam
) && HIWORD(wParam
) == BN_CLICKED
)
1018 EndDialog(hwnd
,LOWORD(wParam
));
1022 if (GetDlgItem(hwnd
,IDCANCEL
)) EndDialog(hwnd
,IDCANCEL
);
1023 else if (GetDlgItem(hwnd
,IDNO
)) EndDialog(hwnd
,IDNO
);
1024 else EndDialog(hwnd
,IDOK
);
1030 int MessageBox(HWND hwndParent
, const char *text
, const char *caption
, int type
)
1032 #ifndef SWELL_LICE_GDI
1033 printf("MessageBox: %s %s\n",text
,caption
);
1035 const void *parms
[4]= {text
,caption
,(void*)(INT_PTR
)type
} ;
1036 return DialogBoxParam(NULL
,NULL
,hwndParent
,swellMessageBoxProc
,(LPARAM
)parms
);
1046 else if (type
== MB_OKCANCEL
)
1052 else if (type
== MB_YESNO
)
1058 else if (type
== MB_RETRYCANCEL
)
1062 if (ret
) ret
=IDRETRY
;
1065 else if (type
== MB_YESNOCANCEL
)
1069 if (ret
== 1) ret
=IDYES
;
1070 else if (ret
==-1) ret
=IDNO
;
1078 #ifdef SWELL_LICE_GDI
1079 struct ChooseColor_State
{
1088 // we need to make a more accurate LICE_HSV2RGB pair, this one is lossy, doh
1089 static LRESULT WINAPI
swellColorSelectProc(HWND hwnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
1091 static int s_reent
,s_vmode
;
1092 static int wndw
, custsz
, buth
, border
, butw
, edh
, edlw
, edew
, vsize
, psize
, yt
;
1095 wndw
= SWELL_UI_SCALE(400);
1096 custsz
= SWELL_UI_SCALE(20);
1097 butw
= SWELL_UI_SCALE(50);
1098 buth
= SWELL_UI_SCALE(24);
1099 border
= SWELL_UI_SCALE(4);
1100 edh
= SWELL_UI_SCALE(20);
1101 edlw
= SWELL_UI_SCALE(16);
1102 edew
= SWELL_UI_SCALE(40);
1103 vsize
= SWELL_UI_SCALE(40);
1104 psize
= border
+edlw
+ edew
;
1105 yt
= border
+ psize
+ border
+ (edh
+ border
)*6;
1108 const int customperrow
= (wndw
-border
)/(custsz
+border
);
1112 if (lParam
) // swell-specific
1114 SetWindowLong(hwnd
,GWL_WNDPROC
,(LPARAM
)SwellDialogDefaultWindowProc
);
1115 SetWindowLong(hwnd
,DWL_DLGPROC
,(LPARAM
)swellColorSelectProc
);
1116 SetWindowLongPtr(hwnd
,GWLP_USERDATA
,lParam
);
1118 SetWindowText(hwnd
,"Choose Color");
1120 SWELL_MakeSetCurParms(1,1,0,0,hwnd
,false,false);
1122 SWELL_MakeButton(0, "OK", IDOK
,0,0,0,0, 0);
1123 SWELL_MakeButton(0, "Cancel", IDCANCEL
,0,0,0,0, 0);
1125 static const char * const lbl
[] = { "R","G","B","H","S","V"};
1126 for (int x
=0;x
<6;x
++)
1128 SWELL_MakeLabel(0,lbl
[x
], 0x100+x
, 0,0,0,0, 0);
1129 SWELL_MakeEditField(0x200+x
, 0,0,0,0, 0);
1132 ChooseColor_State
*cs
= (ChooseColor_State
*)GetWindowLongPtr(hwnd
,GWLP_USERDATA
);
1133 SWELL_MakeSetCurParms(1,1,0,0,NULL
,false,false);
1134 int nrows
= ((cs
?cs
->ncustom
: 0 ) + customperrow
-1)/wdl_max(customperrow
,1);
1135 SetWindowPos(hwnd
,NULL
,0,0, wndw
,
1136 yt
+ buth
+ border
+ nrows
* (custsz
+border
),
1137 SWP_NOZORDER
|SWP_NOMOVE
);
1138 SendMessage(hwnd
,WM_USER
+100,0,3);
1141 case WM_LBUTTONDOWN
:
1142 case WM_RBUTTONDOWN
:
1144 ChooseColor_State
*cs
= (ChooseColor_State
*)GetWindowLongPtr(hwnd
,GWLP_USERDATA
);
1147 GetClientRect(hwnd
,&r
);
1148 const int xt
= r
.right
- edew
- edlw
- border
*3;
1150 const int y
= GET_Y_LPARAM(lParam
);
1151 const int x
= GET_X_LPARAM(lParam
);
1152 if (x
< xt
&& y
< yt
)
1154 s_vmode
= x
>= xt
-vsize
;
1160 if (cs
->custom
&& cs
->ncustom
&& y
>= yt
&& y
< r
.bottom
- buth
- border
)
1162 int row
= (y
-yt
) / (custsz
+border
), rowoffs
= (y
-yt
) % (custsz
+border
);
1163 if (rowoffs
< custsz
)
1165 int col
= (x
-border
) / (custsz
+border
), coloffs
= (x
-border
) % (custsz
+border
);
1166 if (coloffs
< custsz
)
1168 col
+= customperrow
*row
;
1169 if (col
>= 0 && col
< cs
->ncustom
)
1171 if (uMsg
== WM_LBUTTONDOWN
)
1173 LICE_RGB2HSV(GetRValue(cs
->custom
[col
]),GetGValue(cs
->custom
[col
]),GetBValue(cs
->custom
[col
]),&cs
->h
,&cs
->s
,&cs
->v
);
1174 SendMessage(hwnd
,WM_USER
+100,0,3);
1179 LICE_HSV2RGB(cs
->h
,cs
->s
,cs
->v
,&rv
,&gv
,&bv
);
1180 cs
->custom
[col
] = RGB(rv
,gv
,bv
);
1181 InvalidateRect(hwnd
,NULL
,FALSE
);
1192 if (GetCapture()==hwnd
)
1195 GetClientRect(hwnd
,&r
);
1196 const int xt
= r
.right
- edew
- edlw
- border
*3;
1197 ChooseColor_State
*cs
= (ChooseColor_State
*)GetWindowLongPtr(hwnd
,GWLP_USERDATA
);
1199 int var
= 255 - (GET_Y_LPARAM(lParam
) - border
)*256 / (yt
-border
*2);
1201 else if (var
>255)var
=255;
1207 SendMessage(hwnd
,WM_USER
+100,0,3);
1212 int hue
= (GET_X_LPARAM(lParam
) - border
)*384 / (xt
-border
- vsize
);
1214 else if (hue
>383) hue
=383;
1215 if (cs
->h
!= hue
|| cs
->s
!= var
)
1219 SendMessage(hwnd
,WM_USER
+100,0,3);
1231 ChooseColor_State
*cs
= (ChooseColor_State
*)GetWindowLongPtr(hwnd
,GWLP_USERDATA
);
1232 if (cs
&& BeginPaint(hwnd
,&ps
))
1235 GetClientRect(hwnd
,&r
);
1236 const int xt
= r
.right
- edew
- edlw
- border
*3;
1237 if (cs
->custom
&& cs
->ncustom
)
1241 for (int x
= 0; x
< cs
->ncustom
; x
++)
1243 HBRUSH br
= CreateSolidBrush(cs
->custom
[x
]);
1244 RECT tr
={xpos
,ypos
,xpos
+custsz
, ypos
+custsz
};
1245 FillRect(ps
.hdc
,&tr
,br
);
1248 xpos
+= border
+custsz
;
1249 if (xpos
+custsz
>= r
.right
)
1252 ypos
+= border
+ custsz
;
1259 LICE_HSV2RGB(cs
->h
,cs
->s
,cs
->v
,&rr
,&g
,&b
);
1260 HBRUSH br
= CreateSolidBrush(RGB(rr
,g
,b
));
1261 RECT tr
={r
.right
- border
- psize
, border
, r
.right
-border
, border
+psize
};
1262 FillRect(ps
.hdc
,&tr
,br
);
1266 if (!cs
->bm
) cs
->bm
= new LICE_SysBitmap(xt
-border
,yt
-border
);
1267 else cs
->bm
->resize(xt
-border
,yt
-border
);
1269 int x1
= xt
- border
- vsize
;
1272 const int ysz
= yt
-border
*2;
1273 const int vary
= ysz
- 1 - (ysz
* cs
->v
)/256;
1275 for (int y
= 0; y
< ysz
; y
++)
1277 LICE_pixel
*wr
= cs
->bm
->getBits() + cs
->bm
->getRowSpan() * y
;
1278 const int sat
= 255 - y
*256/ysz
;
1279 double xx
=0.0, dx
=384.0/x1
;
1281 for (x
= 0; x
< x1
; x
++)
1283 *wr
++ = LICE_HSV2Pix((int)(xx
+0.5),sat
,var
,255);
1286 LICE_pixel p
= LICE_HSV2Pix(cs
->h
,cs
->s
,sat
^ (y
==vary
? 128 : 0),255);
1287 for (;x
< xt
-border
;x
++) *wr
++ = p
;
1289 LICE_pixel p
= LICE_HSV2Pix(cs
->h
,cs
->s
,(128+cs
->v
)&255,255);
1290 const int saty
= ysz
- 1 - (ysz
* cs
->s
)/256;
1291 const int huex
= (x1
*cs
->h
)/384;
1292 LICE_Line(cs
->bm
,huex
,saty
-4,huex
,saty
+4,p
,.75f
,LICE_BLIT_MODE_COPY
,false);
1293 LICE_Line(cs
->bm
,huex
-4,saty
,huex
+4,saty
,p
,.75f
,LICE_BLIT_MODE_COPY
,false);
1295 BitBlt(ps
.hdc
,border
,border
,xt
-border
,ysz
,cs
->bm
->getDC(),0,0,SRCCOPY
);
1302 case WM_GETMINMAXINFO
:
1304 LPMINMAXINFO p
=(LPMINMAXINFO
)lParam
;
1305 p
->ptMinTrackSize
.x
= 300;
1306 p
->ptMinTrackSize
.y
= 300;
1311 ChooseColor_State
*cs
= (ChooseColor_State
*)GetWindowLongPtr(hwnd
,GWLP_USERDATA
);
1318 LICE_HSV2RGB(t
[3],t
[4],t
[5],t
,t
+1,t
+2);
1320 for (int x
=0;x
<6;x
++) if (lParam
& ((x
<3)?1:2)) SetDlgItemInt(hwnd
,0x200+x
,x
==3 ? t
[x
]*360/384 : t
[x
],FALSE
);
1322 InvalidateRect(hwnd
,NULL
,FALSE
);
1329 GetClientRect(hwnd
,&r
);
1330 int tx
= r
.right
- edew
-edlw
-border
*2, ty
= border
*2 + psize
;
1331 for (int x
=0;x
<6;x
++)
1333 SetWindowPos(GetDlgItem(hwnd
,0x100+x
),NULL
,tx
, ty
, edlw
, edh
, SWP_NOZORDER
|SWP_NOACTIVATE
);
1334 SetWindowPos(GetDlgItem(hwnd
,0x200+x
),NULL
,tx
+edlw
+border
, ty
, edew
, edh
, SWP_NOZORDER
|SWP_NOACTIVATE
);
1338 r
.right
-= border
+ butw
;
1339 r
.bottom
-= border
+ buth
;
1340 SetWindowPos(GetDlgItem(hwnd
,IDCANCEL
), NULL
, r
.right
, r
.bottom
, butw
, buth
, SWP_NOZORDER
|SWP_NOACTIVATE
);
1341 r
.right
-= border
*2 + butw
;
1342 SetWindowPos(GetDlgItem(hwnd
,IDOK
), NULL
, r
.right
, r
.bottom
, butw
, buth
, SWP_NOZORDER
|SWP_NOACTIVATE
);
1347 switch (LOWORD(wParam
))
1363 const bool ishsv
= LOWORD(wParam
) >= 0x203;
1364 int offs
= ishsv
? 0x203 : 0x200;
1366 int h
= GetDlgItemInt(hwnd
,offs
++,&t
,FALSE
);
1368 int s
= GetDlgItemInt(hwnd
,offs
++,&t
,FALSE
);
1370 int v
= GetDlgItemInt(hwnd
,offs
++,&t
,FALSE
);
1373 ChooseColor_State
*cs
= (ChooseColor_State
*)GetWindowLongPtr(hwnd
,GWLP_USERDATA
);
1376 if (h
<0) h
=0; else if (h
>255) h
=255;
1377 if (s
<0) s
=0; else if (s
>255) s
=255;
1378 if (v
<0) v
=0; else if (v
>255) v
=255;
1379 LICE_RGB2HSV(h
,s
,v
,&h
,&s
,&v
);
1384 if (h
<0) h
=0; else if (h
>384) h
=384;
1385 if (s
<0) s
=0; else if (s
>255) s
=255;
1386 if (v
<0) v
=0; else if (v
>255) v
=255;
1395 SendMessage(hwnd
,WM_USER
+100,0,ishsv
?1:2);
1404 #endif //SWELL_LICE_GDI
1406 bool SWELL_ChooseColor(HWND h
, int *val
, int ncustom
, int *custom
)
1408 #ifdef SWELL_LICE_GDI
1409 ChooseColor_State state
= { ncustom
, custom
};
1410 int c
= val
? *val
: 0;
1411 LICE_RGB2HSV(GetRValue(c
),GetGValue(c
),GetBValue(c
),&state
.h
,&state
.s
,&state
.v
);
1412 bool rv
= DialogBoxParam(NULL
,NULL
,h
,swellColorSelectProc
,(LPARAM
)&state
)!=0;
1417 LICE_HSV2RGB(state
.h
,state
.s
,state
.v
,&r
,&g
,&b
);
1426 #if defined(SWELL_FREETYPE) && defined(SWELL_LICE_GDI)
1428 struct FontChooser_State
1434 ~FontChooser_State()
1436 DeleteObject(hFont
);
1441 WDL_FastString lastfn
;
1444 extern const char *swell_last_font_filename
;
1445 const char *swell_enumFontFiles(int x
);
1446 int swell_getLineLength(const char *buf
, int *post_skip
, int wrap_maxwid
, HDC hdc
);
1448 static LRESULT WINAPI
swellFontChooserProc(HWND hwnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
1450 enum { IDC_LIST
=0x100, IDC_FACE
, IDC_SIZE
, IDC_WEIGHT
, IDC_ITALIC
};
1451 enum { preview_h
= 90, _border
= 4, _buth
= 24 };
1456 if (lParam
) // swell-specific
1458 SetWindowLong(hwnd
,GWL_WNDPROC
,(LPARAM
)SwellDialogDefaultWindowProc
);
1459 SetWindowLong(hwnd
,DWL_DLGPROC
,(LPARAM
)swellFontChooserProc
);
1460 SetWindowLongPtr(hwnd
,GWLP_USERDATA
,lParam
);
1462 SetWindowText(hwnd
,"Choose Font");
1464 SWELL_MakeSetCurParms(1,1,0,0,hwnd
,false,false);
1466 SWELL_MakeButton(0, "OK", IDOK
,0,0,0,0, 0);
1467 SWELL_MakeButton(0, "Cancel", IDCANCEL
,0,0,0,0, 0);
1468 SWELL_MakeListBox(IDC_LIST
,0,0,0,0, LBS_OWNERDRAWFIXED
);
1469 SWELL_MakeEditField(IDC_FACE
, 0,0,0,0, 0);
1470 SWELL_MakeEditField(IDC_SIZE
, 0,0,0,0, 0);
1471 SWELL_MakeCombo(IDC_WEIGHT
, 0,0,0,0, CBS_DROPDOWNLIST
);
1472 SWELL_MakeCheckBox("Italic",IDC_ITALIC
,0,0,0,0, 0);
1474 SendDlgItemMessage(hwnd
,IDC_WEIGHT
,CB_ADDSTRING
,0,(LPARAM
)"Normal");
1475 SendDlgItemMessage(hwnd
,IDC_WEIGHT
,CB_ADDSTRING
,0,(LPARAM
)"Bold");
1476 SendDlgItemMessage(hwnd
,IDC_WEIGHT
,CB_ADDSTRING
,0,(LPARAM
)"Light");
1478 SWELL_MakeSetCurParms(1,1,0,0,NULL
,false,false);
1480 SetWindowPos(hwnd
,NULL
,0,0, 550,380, SWP_NOZORDER
|SWP_NOMOVE
);
1482 WDL_StringKeyedArray
<char> list
;
1483 const char *fontfile
;
1485 for (x
=0; (fontfile
=swell_enumFontFiles(x
)); x
++)
1488 lstrcpyn_safe(buf
,WDL_get_filepart(fontfile
),sizeof(buf
));
1490 while (*tmp
&& *tmp
!= '-' && *tmp
!= '.') tmp
++;
1492 if (*buf
) list
.AddUnsorted(buf
,true);
1495 FontChooser_State
*cs
= (FontChooser_State
*)lParam
;
1496 bool italics
= cs
->font
.lfItalic
!=0;
1497 int wt
= cs
->font
.lfWeight
;
1498 const char *lp
=NULL
;
1500 for (x
=0;x
<list
.GetSize();x
++)
1503 if (list
.Enumerate(x
,&p
) && p
)
1505 if (!stricmp(p
,cs
->font
.lfFaceName
))
1506 SendDlgItemMessage(hwnd
,IDC_LIST
,LB_SETCURSEL
,cnt
,0);
1509 if (lp
&& !strncmp(p
,lp
,ll
=strlen(lp
)))
1511 // if this is an extension of the last one, skip
1512 const char *trail
= p
+ll
;
1513 if (strlen(trail
)<=2)
1515 for (int y
=0;y
<2;y
++)
1518 if (c
>0) c
=toupper(c
);
1519 if (c
== 'B' || c
== 'I' || c
== 'L') trail
++;
1524 if (!strnicmp(trail
,"Bold",4)) trail
+=4;
1525 else if (!strnicmp(trail
,"Light",5)) trail
+=5;
1526 else if (!strnicmp(trail
,"Italic",6)) trail
+=6;
1527 else if (!strnicmp(trail
,"Oblique",7)) trail
+=7;
1530 if (!*trail
) continue;
1533 SendDlgItemMessage(hwnd
,IDC_LIST
,LB_ADDSTRING
,0,(LPARAM
)p
);
1537 SetDlgItemText(hwnd
,IDC_FACE
,cs
->font
.lfFaceName
);
1538 SetDlgItemInt(hwnd
,IDC_SIZE
,cs
->font
.lfHeight
< 0 ? -cs
->font
.lfHeight
: cs
->font
.lfHeight
,TRUE
);
1539 SendDlgItemMessage(hwnd
,IDC_WEIGHT
,CB_SETCURSEL
,wt
<=FW_LIGHT
? 2 : wt
< FW_BOLD
? 0 : 1,0);
1541 CheckDlgButton(hwnd
,IDC_ITALIC
,BST_CHECKED
);
1546 DRAWITEMSTRUCT
*di
=(DRAWITEMSTRUCT
*)lParam
;
1547 FontChooser_State
*cs
= (FontChooser_State
*)GetWindowLongPtr(hwnd
,GWLP_USERDATA
);
1548 if (cs
&& di
->CtlID
== IDC_LIST
)
1552 SendDlgItemMessage(hwnd
,IDC_LIST
,LB_GETTEXT
,di
->itemID
,(WPARAM
)buf
);
1555 HFONT font
= CreateFont(g_swell_ctheme
.default_font_size
, 0, 0, 0, cs
->font
.lfWeight
, cs
->font
.lfItalic
,
1556 FALSE
, FALSE
, ANSI_CHARSET
, OUT_DEFAULT_PRECIS
, CLIP_DEFAULT_PRECIS
, DEFAULT_QUALITY
, DEFAULT_PITCH
, buf
);
1558 HGDIOBJ oldFont
= SelectObject(di
->hDC
,font
);
1559 DrawText(di
->hDC
,buf
,-1,&di
->rcItem
,DT_VCENTER
|DT_LEFT
|DT_NOPREFIX
);
1560 wchar_t tmp
[] = {'a','A','z','Z'};
1561 unsigned short ind
[4];
1562 GetGlyphIndicesW(di
->hDC
,tmp
,4,ind
,0);
1563 SelectObject(di
->hDC
,oldFont
);
1566 for (x
=0;x
<4 && ind
[x
]==0xffff;x
++);
1569 RECT r
= di
->rcItem
;
1571 DrawText(di
->hDC
,buf
,-1,&r
,DT_VCENTER
|DT_RIGHT
|DT_NOPREFIX
);
1582 FontChooser_State
*cs
= (FontChooser_State
*)GetWindowLongPtr(hwnd
,GWLP_USERDATA
);
1583 if (cs
&& BeginPaint(hwnd
,&ps
))
1586 GetClientRect(hwnd
,&r
);
1588 const int border
= SWELL_UI_SCALE(_border
);
1589 const int buth
= SWELL_UI_SCALE(_buth
);
1590 const int ph
= SWELL_UI_SCALE(preview_h
);
1593 r
.bottom
-= border
*2 + buth
;
1594 r
.top
= r
.bottom
- ph
;
1596 HFONT f
= CreateFontIndirect(&cs
->font
);
1597 HBRUSH br
= CreateSolidBrush(RGB(255,255,255));
1598 FillRect(ps
.hdc
,&r
,br
);
1600 SetTextColor(ps
.hdc
,RGB(0,0,0));
1601 SetBkMode(ps
.hdc
,TRANSPARENT
);
1604 if (swell_last_font_filename
)
1606 r
.bottom
-= DrawText(ps
.hdc
,swell_last_font_filename
,-1,&r
,DT_BOTTOM
|DT_NOPREFIX
|DT_SINGLELINE
|DT_RIGHT
);
1609 HGDIOBJ oldFont
= SelectObject(ps
.hdc
,f
);
1611 extern const char *g_swell_fontpangram
;
1612 const char *str
= g_swell_fontpangram
;
1614 // thanks, http://dailypangram.tumblr.com/ :)
1615 if (!str
) str
= "Strangely, aerobic exercise doesn’t quite work with improvised free jazz.";
1619 int sk
=0, lb
=swell_getLineLength(str
, &sk
, r
.right
-r
.left
, ps
.hdc
);
1620 if (!lb
&&!sk
) break;
1621 if (lb
>0) r
.top
+= DrawText(ps
.hdc
,str
,lb
,&r
,DT_TOP
|DT_LEFT
|DT_NOPREFIX
|DT_SINGLELINE
);
1626 SelectObject(ps
.hdc
,oldFont
);
1635 case WM_GETMINMAXINFO
:
1637 LPMINMAXINFO p
=(LPMINMAXINFO
)lParam
;
1638 p
->ptMinTrackSize
.x
= 400;
1639 p
->ptMinTrackSize
.y
= 300;
1645 GetClientRect(hwnd
,&r
);
1646 const int border
= SWELL_UI_SCALE(_border
);
1647 const int buth
= SWELL_UI_SCALE(_buth
);
1648 const int butw
= SWELL_UI_SCALE(50);
1649 const int edh
= SWELL_UI_SCALE(20);
1650 const int size_w
= SWELL_UI_SCALE(50);
1651 const int wt_w
= SWELL_UI_SCALE(80);
1652 const int italic_w
= SWELL_UI_SCALE(60);
1657 r
.bottom
-= border
+ buth
;
1658 SetWindowPos(GetDlgItem(hwnd
,IDCANCEL
), NULL
, r
.right
- butw
, r
.bottom
, butw
, buth
, SWP_NOZORDER
|SWP_NOACTIVATE
);
1659 SetWindowPos(GetDlgItem(hwnd
,IDOK
), NULL
, r
.right
- border
- butw
*2, r
.bottom
, butw
, buth
, SWP_NOZORDER
|SWP_NOACTIVATE
);
1660 r
.bottom
-= SWELL_UI_SCALE(preview_h
) + border
;
1661 int psz
=wdl_max(g_swell_ctheme
.combo_height
,edh
);
1662 r
.bottom
-= psz
+ border
;
1663 SetWindowPos(GetDlgItem(hwnd
,IDC_FACE
),NULL
,r
.left
,r
.bottom
+ (psz
-edh
)/2,
1664 r
.right
-r
.left
- size_w
-wt_w
-italic_w
- border
*3, edh
, SWP_NOZORDER
|SWP_NOACTIVATE
);
1665 SetWindowPos(GetDlgItem(hwnd
,IDC_SIZE
),NULL
,r
.right
-size_w
-wt_w
-italic_w
-border
*2,r
.bottom
+ (psz
-edh
)/2,
1666 size_w
, edh
, SWP_NOZORDER
|SWP_NOACTIVATE
);
1667 SetWindowPos(GetDlgItem(hwnd
,IDC_WEIGHT
),NULL
,r
.right
-wt_w
-italic_w
-border
,r
.bottom
+ (psz
-g_swell_ctheme
.combo_height
)/2,
1668 wt_w
, g_swell_ctheme
.combo_height
, SWP_NOZORDER
|SWP_NOACTIVATE
);
1669 SetWindowPos(GetDlgItem(hwnd
,IDC_ITALIC
),NULL
,r
.right
-italic_w
,r
.bottom
+ (psz
-edh
)/2,
1670 italic_w
, edh
, SWP_NOZORDER
|SWP_NOACTIVATE
);
1672 SetWindowPos(GetDlgItem(hwnd
,IDC_LIST
), NULL
, border
, border
, r
.right
, r
.bottom
- border
*2, SWP_NOZORDER
|SWP_NOACTIVATE
);
1678 switch (LOWORD(wParam
))
1681 if (HIWORD(wParam
) == LBN_SELCHANGE
)
1683 int idx
= (int) SendDlgItemMessage(hwnd
,IDC_LIST
,LB_GETCURSEL
,0,0);
1688 SendDlgItemMessage(hwnd
,IDC_LIST
,LB_GETTEXT
,idx
,(WPARAM
)buf
);
1689 if (buf
[0]) SetDlgItemText(hwnd
,IDC_FACE
,buf
);
1698 FontChooser_State
*cs
= (FontChooser_State
*)GetWindowLongPtr(hwnd
,GWLP_USERDATA
);
1701 if (LOWORD(wParam
) == IDC_FACE
)
1702 GetDlgItemText(hwnd
,IDC_FACE
,cs
->font
.lfFaceName
,sizeof(cs
->font
.lfFaceName
));
1703 else if (LOWORD(wParam
) == IDC_SIZE
)
1706 int a
= GetDlgItemInt(hwnd
,IDC_SIZE
,&t
,FALSE
);
1709 if (cs
->font
.lfHeight
< 0) cs
->font
.lfHeight
= -a
;
1710 else cs
->font
.lfHeight
= a
;
1713 else if (LOWORD(wParam
) == IDC_ITALIC
) cs
->font
.lfItalic
= IsDlgButtonChecked(hwnd
,IDC_ITALIC
) ? 1:0;
1714 else if (LOWORD(wParam
) == IDC_WEIGHT
&& HIWORD(wParam
) == CBN_SELCHANGE
)
1716 int idx
= (int) SendDlgItemMessage(hwnd
,IDC_WEIGHT
,CB_GETCURSEL
,0,0);
1717 if (idx
==0) cs
->font
.lfWeight
= FW_NORMAL
;
1718 else if (idx
==1) cs
->font
.lfWeight
= FW_BOLD
;
1719 else if (idx
==2) cs
->font
.lfWeight
= FW_LIGHT
;
1721 InvalidateRect(hwnd
,NULL
,FALSE
);
1738 void *swell_MatchFont(const char *lfFaceName
, int weight
, int italic
, const char **fnOut
);
1742 bool SWELL_ChooseFont(HWND h
, LOGFONT
*lf
)
1744 #if defined(SWELL_FREETYPE) && defined(SWELL_LICE_GDI)
1745 FontChooser_State state
;
1748 bool rv
= DialogBoxParam(NULL
,NULL
,h
,swellFontChooserProc
,(LPARAM
)&state
)!=0;