Merge pull request #110 from tesselode/fixes
[wdl/wdl-ol.git] / WDL / swell / swell-miscdlg.mm
blob687b4c9b012b25db7ad29fe9418e8497b1607910
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.
19   
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.
25   */
28 #ifndef SWELL_PROVIDED_BY_APP
30 #include "swell.h"
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];
36         while (*extlist)
37         {
38                 extlist += strlen(extlist)+1;
39                 if (!*extlist) break; 
40                 while (*extlist)
41                 {
42                         while (*extlist && *extlist != '.') extlist++;
43                         if (!*extlist) break;
44                         extlist++;
45                         char tmp[32];
46                         lstrcpyn_safe(tmp,extlist,sizeof(tmp));
47                         if (strstr(tmp,";")) strstr(tmp,";")[0]=0;
48                         if (tmp[0] && tmp[0]!='*')
49                         {
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];
56                                 else
57                                   [fileTypes addObject:s];
58                                 [s release];
59                         }
60                         while (*extlist && *extlist != ';') extlist++;
61                         if (*extlist == ';') extlist++;
62                 }
63                 extlist++;
64         }
65         
66         return fileTypes;
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;
82   switch (uMsg)
83   {
84     case WM_CREATE:
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);
91       {
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;
99         int def_sel = -1;
101         HWND combo = GetDlgItem(hwnd,1000);
102         while (*extlist)
103         {
104           const char *next = extlist + strlen(extlist)+1;
105           if (!*next) break;
107           if (strcmp(next,"*.*"))
108           {
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++;
114             if (*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)
119             {
120               if (!strnicmp(p,initial_file,initial_file_len) && (p[initial_file_len] == ';' || !p[initial_file_len])) 
121               {
122                 bestp = p;
123                 def_sel = a;
124                 break;
125               }
126               else
127               {
128                 while (*p && *p != '.') p++;
129                 if (*p) p++;
130               }
131             }
132             SendMessage(combo,CB_SETITEMDATA,a,(LPARAM)bestp);
133           }
135           extlist = next + strlen(next)+1;
136           if (!*extlist) break;
137         }
138         SendMessage(combo,CB_SETCURSEL,def_sel>=0?def_sel:0,0);
139       }
140     return 0;
141     case WM_SIZE:
142       {
143         RECT r;
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);
149       }
150     return 0;
151     case WM_COMMAND:
152       if (LOWORD(wParam) == 1000 && HIWORD(wParam) == CBN_SELCHANGE)
153       {
154         int a = (int)SendDlgItemMessage(hwnd,1000,CB_GETCURSEL,0,0);
155         if (a>=0)
156         {
157           const char *extlist = (const char *)GetWindowLongPtr(hwnd,GWLP_USERDATA);
158           if (extlist)
159           {
160             NSArray *fileTypes = extensionsFromList(extlist,
161                 (const char *)SendDlgItemMessage(hwnd,1000,CB_GETITEMDATA,a,0));
162             if ([fileTypes count]>0) 
163             {
164               NSSavePanel *par = (NSSavePanel*)[(NSView *)hwnd window];
165               if ([par isKindOfClass:[NSSavePanel class]]) [(NSSavePanel *)par setAllowedFileTypes:fileTypes];
166             }
167             [fileTypes release];
168           }
169         }
170       }
171     return 0;
172   }
173   return DefWindowProc(hwnd,uMsg,wParam,lParam);
176 // return true
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)
190   {
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;
194   }
196   HWND oh=NULL;
197   if (BFSF_Templ_dlgproc && BFSF_Templ_dlgid) // create a child dialog and set it to the panel
198   {
199     oh=SWELL_CreateDialog(BFSF_Templ_reshead, BFSF_Templ_dlgid, av_parent, BFSF_Templ_dlgproc, 0);
200     BFSF_Templ_dlgproc=0;
201     BFSF_Templ_dlgid=0;
202   }
203   if (av_parent != (HWND)panel) 
204   {
205     if (oh) 
206     { 
207       RECT r1,r2;
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);
215     }
216     oh = av_parent;
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];
222     [oldw release];
223   }
224   else
225   {
226     [panel setAllowedFileTypes:fileTypes];
227   }
229   if (initialfile && *initialfile && *initialfile != '.')
230   {
231     char s[2048];
232     lstrcpyn_safe(s,initialfile,sizeof(s));
233     char *p=s;
234     while (*p) p++;
235     while (p >= s && *p != '/') p--;
236     if (p>=s)
237     {
238       *p=0;
239       ifn=(NSString *)SWELL_CStringToCFString(p+1);
240       idir=(NSString *)SWELL_CStringToCFString(s[0]?s:"/");
241     }
242     else 
243       ifn=(NSString *)SWELL_CStringToCFString(s);
244   }
245   if (!idir && initialdir && *initialdir)
246   {
247     idir=(NSString *)SWELL_CStringToCFString(initialdir);
248   }
249         
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);
257   
258   if (oh) SendMessage(oh,WM_DESTROY,0,0);
259   [panel setAccessoryView:nil];
261   [title release];
262   [fileTypes release];
263   [idir release];
264   [ifn release];
265         
266   if (result == NSOKButton)
267   {
268     NSString *str = [panel filename];
269     if (str && fn && fnsize>0) 
270     {
271       SWELL_CFStringToCString(str,fn,fnsize);
272       return fn[0] != 0;
273     }
274   }
275   return false;
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); 
282   NSString *idir=NULL;
284   [panel setTitle:title];
285   [panel setAllowsMultipleSelection:NO];
286   [panel setCanChooseFiles:NO];
287   [panel setCanCreateDirectories:YES];
288   [panel setCanChooseDirectories:YES];
289   [panel setResolvesAliases:YES];
291   HWND oh=NULL;
292   if (BFSF_Templ_dlgproc && BFSF_Templ_dlgid) // create a child dialog and set it to the panel
293   {
294     oh=SWELL_CreateDialog(BFSF_Templ_reshead, BFSF_Templ_dlgid, (HWND)panel, BFSF_Templ_dlgproc, 0);
295     BFSF_Templ_dlgproc=0;
296     BFSF_Templ_dlgid=0;
297   }
298         
299   if (initialdir && *initialdir)
300   {
301     idir=(NSString *)SWELL_CStringToCFString(initialdir);
302   }
303         
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);
310         
311   if (oh) SendMessage(oh,WM_DESTROY,0,0);
312   [panel setAccessoryView:nil];
313   
314   [idir release];
315   [title release];
316         
317   if (result != NSOKButton) return 0;
318         
319   NSArray *filesToOpen = [panel filenames];
320   NSInteger count = [filesToOpen count];
321                 
322   if (!count) return 0;
323                 
324   NSString *aFile = [filesToOpen objectAtIndex:0];
325   if (!aFile) return 0;
326   SWELL_CFStringToCString(aFile,fn,fnsize);
327   fn[fnsize-1]=0;
328   return 1;
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);      
340   HWND oh=NULL;
341   if (BFSF_Templ_dlgproc && BFSF_Templ_dlgid) // create a child dialog and set it to the panel
342   {
343     oh=SWELL_CreateDialog(BFSF_Templ_reshead, BFSF_Templ_dlgid, (HWND)panel, BFSF_Templ_dlgproc, 0);
344     BFSF_Templ_dlgproc=0;
345     BFSF_Templ_dlgid=0;
346   }
348   [panel setTitle:title];
349   [panel setAllowsMultipleSelection:(allowmul?YES:NO)];
350   [panel setCanChooseFiles:YES];
351   [panel setCanChooseDirectories:NO];
352   [panel setResolvesAliases:YES];
353         
354   if (initialfile && *initialfile)
355   {
356     char s[2048];
357     lstrcpyn_safe(s,initialfile,sizeof(s));
358     char *p=s;
359     while (*p) p++;
360     while (p >= s && *p != '/') p--;
361     if (p>=s)
362     {
363       *p=0;
364       ifn=(NSString *)SWELL_CStringToCFString(p+1);
365       idir=(NSString *)SWELL_CStringToCFString(s[0]?s:"/");
366     }
367     else 
368       ifn=(NSString *)SWELL_CStringToCFString(s);
369   }
370   if (!idir && initialdir && *initialdir)
371   {
372     idir=(NSString *)SWELL_CStringToCFString(initialdir);
373   }
374         
375   HMENU hm=SWELL_GetDefaultModalWindowMenu();
376   if (hm) hm=SWELL_DuplicateMenu(hm);
377   SWELL_SetCurrentMenu(hm);
378   
379   NSInteger result = [panel runModalForDirectory:idir file:ifn types:fileTypes];
381   SWELL_SetCurrentMenu(GetMenu(GetFocus()));
382   if (hm) DestroyMenu(hm);
383         
384   if (oh) SendMessage(oh,WM_DESTROY,0,0);
385   [panel setAccessoryView:nil];
386   
387   [ifn release];
388   [idir release];
389         
390   [fileTypes release];
391   [title release];
392         
393   if (result != NSOKButton) return 0;
394         
395   NSArray *filesToOpen = [panel filenames];
396   const NSInteger count = [filesToOpen count];
397                 
398   if (!count) return 0;
399                 
400   char fn[2048];
401   if (count==1||!allowmul)
402   {
403     NSString *aFile = [filesToOpen objectAtIndex:0];
404     if (!aFile) return 0;
405     SWELL_CFStringToCString(aFile,fn,sizeof(fn));
406     fn[sizeof(fn)-1]=0;
407     char *ret=(char *)malloc(strlen(fn)+2);
408     memcpy(ret,fn,strlen(fn));
409     ret[strlen(fn)]=0;
410     ret[strlen(fn)+1]=0;
411     return ret;
412   }
413                 
414   size_t rsize=1;
415   char *ret=0;
416   for (NSInteger i=0; i<count; i++) 
417   {
418     NSString *aFile = [filesToOpen objectAtIndex:i];
419     if (!aFile) continue;
420     SWELL_CFStringToCString(aFile,fn,sizeof(fn));
421     fn[sizeof(fn)-1]=0;
422                 
423     size_t tlen=strlen(fn)+1;
424     ret=(char *)realloc(ret,rsize+tlen+1);
425     if (!ret) return 0;
426     
427     if (rsize==1) ret[0]=0;
428     strcpy(ret+rsize,fn);
429     rsize+=tlen;
430     ret[rsize]=0;
431   }     
432   return ret;
438 int MessageBox(HWND hwndParent, const char *text, const char *caption, int type)
440   NSInteger ret=0;
442   NSString *tit=(NSString *)SWELL_CStringToCFString(caption?caption:""); 
443   NSString *text2=(NSString *)SWELL_CStringToCFString(text?text:"");
444   
445   if (type == MB_OK)
446   {
447     NSRunAlertPanel(tit,@"%@",@"OK",@"",@"",text2);
448     ret=IDOK;
449   }     
450   else if (type == MB_OKCANCEL)
451   {
452     ret=NSRunAlertPanel(tit,@"%@",@"OK",@"Cancel",@"",text2);
453     if (ret) ret=IDOK;
454     else ret=IDCANCEL;
455   }
456   else if (type == MB_YESNO)
457   {
458     ret=NSRunAlertPanel(tit,@"%@",@"Yes",@"No",@"",text2);
459   //  printf("ret=%d\n",ret);
460     if (ret) ret=IDYES;
461     else ret=IDNO;
462   }
463   else if (type == MB_RETRYCANCEL)
464   {
465     ret=NSRunAlertPanel(tit,@"%@",@"Retry",@"Cancel",@"",text2);
466 //    printf("ret=%d\n",ret);
467     if (ret) ret=IDRETRY;
468     else ret=IDCANCEL;
469   }
470   else if (type == MB_YESNOCANCEL)
471   {
472     ret=NSRunAlertPanel(tit,@"%@",@"Yes",@"Cancel",@"No",text2);
473     if (ret == 1) ret=IDYES;
474     else if (ret==-1) ret=IDNO;
475     else ret=IDCANCEL;
476   }
477   
478   [text2 release];
479   [tit release];
480   
481   return (int)ret; 
484 #endif