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 "../wdlcstring.h"
32 #import <Cocoa/Cocoa.h>
33 static NSMutableArray *extensionsFromList(const char *extlist, const char *def_ext=NULL)
35 NSMutableArray *fileTypes = [[NSMutableArray alloc] initWithCapacity:30];
38 extlist += strlen(extlist)+1;
42 while (*extlist && *extlist != '.') extlist++;
46 lstrcpyn_safe(tmp,extlist,sizeof(tmp));
47 if (strstr(tmp,";")) strstr(tmp,";")[0]=0;
48 if (tmp[0] && tmp[0]!='*')
50 NSString *s=(NSString *)SWELL_CStringToCFString(tmp);
51 const size_t tmp_len = strlen(tmp);
52 if (def_ext && *def_ext &&
53 !strnicmp(def_ext,tmp,tmp_len) &&
54 (!def_ext[tmp_len] || def_ext[tmp_len] == ';'))
55 [fileTypes insertObject:s atIndex:0];
57 [fileTypes addObject:s];
60 while (*extlist && *extlist != ';') extlist++;
61 if (*extlist == ';') extlist++;
69 static const char *BFSF_Templ_dlgid;
70 static DLGPROC BFSF_Templ_dlgproc;
71 static struct SWELL_DialogResourceIndex *BFSF_Templ_reshead;
72 void BrowseFile_SetTemplate(const char *dlgid, DLGPROC dlgProc, struct SWELL_DialogResourceIndex *reshead)
74 BFSF_Templ_reshead=reshead;
75 BFSF_Templ_dlgid=dlgid;
76 BFSF_Templ_dlgproc=dlgProc;
79 static LRESULT fileTypeChooseProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
81 const int wndh = 22, lblw = 80, combow = 250, def_wid = lblw + 4 + combow + 4;
85 SetOpaque(hwnd,FALSE);
86 SetWindowPos(hwnd,NULL,0,0,def_wid,wndh,SWP_NOMOVE|SWP_NOZORDER);
87 SWELL_MakeSetCurParms(1,1,0,0,hwnd,true,false);
88 SWELL_MakeLabel(1,"File type:",1001,0,2,lblw,wndh,0);
89 SWELL_MakeCombo(1000, lblw + 4,0, combow, wndh,3/*CBS_DROPDOWNLIST*/);
90 SWELL_MakeSetCurParms(1,1,0,0,NULL,false,false);
92 const char *extlist = ((const char **)lParam)[0];
93 SetWindowLongPtr(hwnd,GWLP_USERDATA,(LPARAM)extlist);
94 const char *initial_file = ((const char **)lParam)[1];
96 if (initial_file) initial_file=WDL_get_fileext(initial_file);
97 const size_t initial_file_len = initial_file && *initial_file ? strlen(++initial_file) : 0;
101 HWND combo = GetDlgItem(hwnd,1000);
104 const char *next = extlist + strlen(extlist)+1;
107 if (strcmp(next,"*.*"))
109 int a = (int)SendMessage(combo,CB_ADDSTRING,0,(LPARAM)extlist);
111 // userdata for each item is pointer to un-terminated extension.
112 const char *p = next;
113 while (*p && *p != '.') p++;
115 const char *bestp = p;
117 // scan extension list for matching initial file, use that (and set default)
118 if (def_sel < 0 && initial_file) while (*p)
120 if (!strnicmp(p,initial_file,initial_file_len) && (p[initial_file_len] == ';' || !p[initial_file_len]))
128 while (*p && *p != '.') p++;
132 SendMessage(combo,CB_SETITEMDATA,a,(LPARAM)bestp);
135 extlist = next + strlen(next)+1;
136 if (!*extlist) break;
138 SendMessage(combo,CB_SETCURSEL,def_sel>=0?def_sel:0,0);
144 GetClientRect(hwnd,&r);
145 const int xpos = r.right / 2 - def_wid/2;
146 SetWindowPos(GetDlgItem(hwnd,1001),NULL, xpos,2,0,0,SWP_NOZORDER|SWP_NOSIZE);
147 SetWindowPos(GetDlgItem(hwnd,1000),NULL, xpos + lblw + 4,0,0,0,SWP_NOZORDER|SWP_NOSIZE);
152 if (LOWORD(wParam) == 1000 && HIWORD(wParam) == CBN_SELCHANGE)
154 int a = (int)SendDlgItemMessage(hwnd,1000,CB_GETCURSEL,0,0);
157 const char *extlist = (const char *)GetWindowLongPtr(hwnd,GWLP_USERDATA);
160 NSArray *fileTypes = extensionsFromList(extlist,
161 (const char *)SendDlgItemMessage(hwnd,1000,CB_GETITEMDATA,a,0));
162 if ([fileTypes count]>0)
164 NSSavePanel *par = (NSSavePanel*)[(NSView *)hwnd window];
165 if ([par isKindOfClass:[NSSavePanel class]]) [(NSSavePanel *)par setAllowedFileTypes:fileTypes];
173 return DefWindowProc(hwnd,uMsg,wParam,lParam);
177 bool BrowseForSaveFile(const char *text, const char *initialdir, const char *initialfile, const char *extlist,
178 char *fn, int fnsize)
180 NSSavePanel *panel = [NSSavePanel savePanel];
181 NSMutableArray *fileTypes = extensionsFromList(extlist);
182 NSString *title=(NSString *)SWELL_CStringToCFString(text);
183 NSString *ifn=NULL, *idir = NULL;
185 [panel setTitle:title];
186 [panel setAccessoryView:nil];
187 HWND av_parent = (HWND)panel;
189 if ([fileTypes count]>1)
191 const char *ar[2]={extlist,initialfile};
192 av_parent = SWELL_CreateDialog(NULL,0,NULL,fileTypeChooseProc,(LPARAM)ar);
193 if (!av_parent) av_parent = (HWND)panel;
197 if (BFSF_Templ_dlgproc && BFSF_Templ_dlgid) // create a child dialog and set it to the panel
199 oh=SWELL_CreateDialog(BFSF_Templ_reshead, BFSF_Templ_dlgid, av_parent, BFSF_Templ_dlgproc, 0);
200 BFSF_Templ_dlgproc=0;
203 if (av_parent != (HWND)panel)
208 GetClientRect(oh,&r1);
209 GetClientRect(av_parent,&r2);
211 SetWindowPos(oh,NULL,0,r2.bottom,0,0,SWP_NOZORDER|SWP_NOSIZE);
212 if (r2.right < r1.right) r2.right=r1.right;
213 SetWindowPos(av_parent,NULL,0,0,r2.right,r2.bottom+r1.bottom,SWP_NOZORDER|SWP_NOMOVE);
214 ShowWindow(oh,SW_SHOWNA);
218 NSWindow *oldw = [(NSView *)av_parent window];
219 [panel setAccessoryView:(NSView *)av_parent]; // we resized our accessory view
220 SendMessage(av_parent,WM_COMMAND,(CBN_SELCHANGE<<16) | 1000,0);
221 [(NSView *)av_parent setHidden:NO];
226 [panel setAllowedFileTypes:fileTypes];
229 if (initialfile && *initialfile && *initialfile != '.')
232 lstrcpyn_safe(s,initialfile,sizeof(s));
235 while (p >= s && *p != '/') p--;
239 ifn=(NSString *)SWELL_CStringToCFString(p+1);
240 idir=(NSString *)SWELL_CStringToCFString(s[0]?s:"/");
243 ifn=(NSString *)SWELL_CStringToCFString(s);
245 if (!idir && initialdir && *initialdir)
247 idir=(NSString *)SWELL_CStringToCFString(initialdir);
250 HMENU hm=SWELL_GetDefaultModalWindowMenu();
251 if (hm) hm=SWELL_DuplicateMenu(hm);
252 SWELL_SetCurrentMenu(hm);
254 NSInteger result = [panel runModalForDirectory:idir file:ifn];
255 SWELL_SetCurrentMenu(GetMenu(GetFocus()));
256 if (hm) DestroyMenu(hm);
258 if (oh) SendMessage(oh,WM_DESTROY,0,0);
259 [panel setAccessoryView:nil];
266 if (result == NSOKButton)
268 NSString *str = [panel filename];
269 if (str && fn && fnsize>0)
271 SWELL_CFStringToCString(str,fn,fnsize);
278 bool BrowseForDirectory(const char *text, const char *initialdir, char *fn, int fnsize)
280 NSOpenPanel *panel = [NSOpenPanel openPanel];
281 NSString *title=(NSString *)SWELL_CStringToCFString(text);
284 [panel setTitle:title];
285 [panel setAllowsMultipleSelection:NO];
286 [panel setCanChooseFiles:NO];
287 [panel setCanCreateDirectories:YES];
288 [panel setCanChooseDirectories:YES];
289 [panel setResolvesAliases:YES];
292 if (BFSF_Templ_dlgproc && BFSF_Templ_dlgid) // create a child dialog and set it to the panel
294 oh=SWELL_CreateDialog(BFSF_Templ_reshead, BFSF_Templ_dlgid, (HWND)panel, BFSF_Templ_dlgproc, 0);
295 BFSF_Templ_dlgproc=0;
299 if (initialdir && *initialdir)
301 idir=(NSString *)SWELL_CStringToCFString(initialdir);
304 HMENU hm=SWELL_GetDefaultModalWindowMenu();
305 if (hm) hm=SWELL_DuplicateMenu(hm);
306 SWELL_SetCurrentMenu(hm);
307 NSInteger result = [panel runModalForDirectory:idir file:nil types:nil];
308 SWELL_SetCurrentMenu(GetMenu(GetFocus()));
309 if (hm) DestroyMenu(hm);
311 if (oh) SendMessage(oh,WM_DESTROY,0,0);
312 [panel setAccessoryView:nil];
317 if (result != NSOKButton) return 0;
319 NSArray *filesToOpen = [panel filenames];
320 NSInteger count = [filesToOpen count];
322 if (!count) return 0;
324 NSString *aFile = [filesToOpen objectAtIndex:0];
325 if (!aFile) return 0;
326 SWELL_CFStringToCString(aFile,fn,fnsize);
332 char *BrowseForFiles(const char *text, const char *initialdir,
333 const char *initialfile, bool allowmul, const char *extlist)
335 NSOpenPanel *panel = [NSOpenPanel openPanel];
336 NSString *title=(NSString *)SWELL_CStringToCFString(text);
337 NSString *ifn=NULL, *idir=NULL;
338 NSMutableArray *fileTypes = extensionsFromList(extlist);
341 if (BFSF_Templ_dlgproc && BFSF_Templ_dlgid) // create a child dialog and set it to the panel
343 oh=SWELL_CreateDialog(BFSF_Templ_reshead, BFSF_Templ_dlgid, (HWND)panel, BFSF_Templ_dlgproc, 0);
344 BFSF_Templ_dlgproc=0;
348 [panel setTitle:title];
349 [panel setAllowsMultipleSelection:(allowmul?YES:NO)];
350 [panel setCanChooseFiles:YES];
351 [panel setCanChooseDirectories:NO];
352 [panel setResolvesAliases:YES];
354 if (initialfile && *initialfile)
357 lstrcpyn_safe(s,initialfile,sizeof(s));
360 while (p >= s && *p != '/') p--;
364 ifn=(NSString *)SWELL_CStringToCFString(p+1);
365 idir=(NSString *)SWELL_CStringToCFString(s[0]?s:"/");
368 ifn=(NSString *)SWELL_CStringToCFString(s);
370 if (!idir && initialdir && *initialdir)
372 idir=(NSString *)SWELL_CStringToCFString(initialdir);
375 HMENU hm=SWELL_GetDefaultModalWindowMenu();
376 if (hm) hm=SWELL_DuplicateMenu(hm);
377 SWELL_SetCurrentMenu(hm);
379 NSInteger result = [panel runModalForDirectory:idir file:ifn types:fileTypes];
381 SWELL_SetCurrentMenu(GetMenu(GetFocus()));
382 if (hm) DestroyMenu(hm);
384 if (oh) SendMessage(oh,WM_DESTROY,0,0);
385 [panel setAccessoryView:nil];
393 if (result != NSOKButton) return 0;
395 NSArray *filesToOpen = [panel filenames];
396 const NSInteger count = [filesToOpen count];
398 if (!count) return 0;
401 if (count==1||!allowmul)
403 NSString *aFile = [filesToOpen objectAtIndex:0];
404 if (!aFile) return 0;
405 SWELL_CFStringToCString(aFile,fn,sizeof(fn));
407 char *ret=(char *)malloc(strlen(fn)+2);
408 memcpy(ret,fn,strlen(fn));
416 for (NSInteger i=0; i<count; i++)
418 NSString *aFile = [filesToOpen objectAtIndex:i];
419 if (!aFile) continue;
420 SWELL_CFStringToCString(aFile,fn,sizeof(fn));
423 size_t tlen=strlen(fn)+1;
424 ret=(char *)realloc(ret,rsize+tlen+1);
427 if (rsize==1) ret[0]=0;
428 strcpy(ret+rsize,fn);
438 int MessageBox(HWND hwndParent, const char *text, const char *caption, int type)
442 NSString *tit=(NSString *)SWELL_CStringToCFString(caption?caption:"");
443 NSString *text2=(NSString *)SWELL_CStringToCFString(text?text:"");
447 NSRunAlertPanel(tit,@"%@",@"OK",@"",@"",text2);
450 else if (type == MB_OKCANCEL)
452 ret=NSRunAlertPanel(tit,@"%@",@"OK",@"Cancel",@"",text2);
456 else if (type == MB_YESNO)
458 ret=NSRunAlertPanel(tit,@"%@",@"Yes",@"No",@"",text2);
459 // printf("ret=%d\n",ret);
463 else if (type == MB_RETRYCANCEL)
465 ret=NSRunAlertPanel(tit,@"%@",@"Retry",@"Cancel",@"",text2);
466 // printf("ret=%d\n",ret);
467 if (ret) ret=IDRETRY;
470 else if (type == MB_YESNOCANCEL)
472 ret=NSRunAlertPanel(tit,@"%@",@"Yes",@"Cancel",@"No",text2);
473 if (ret == 1) ret=IDYES;
474 else if (ret==-1) ret=IDNO;