The JUCE cross-platform C++ framework, with DISTRHO/KXStudio specific changes
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

338 lines
11KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library - "Jules' Utility Class Extensions"
  4. Copyright 2004-9 by Raw Material Software Ltd.
  5. ------------------------------------------------------------------------------
  6. JUCE can be redistributed and/or modified under the terms of the GNU General
  7. Public License (Version 2), as published by the Free Software Foundation.
  8. A copy of the license is included in the JUCE distribution, or can be found
  9. online at www.gnu.org/licenses.
  10. JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
  11. WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  12. A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  13. ------------------------------------------------------------------------------
  14. To release a closed-source product which uses JUCE, commercial licenses are
  15. available: visit www.rawmaterialsoftware.com/juce for more information.
  16. ==============================================================================
  17. */
  18. // (This file gets included by juce_win32_NativeCode.cpp, rather than being
  19. // compiled on its own).
  20. #if JUCE_INCLUDED_FILE
  21. //==============================================================================
  22. static const void* defaultDirPath = 0;
  23. static String returnedString; // need this to get non-existent pathnames from the directory chooser
  24. static Component* currentExtraFileWin = 0;
  25. static bool areThereAnyAlwaysOnTopWindows()
  26. {
  27. for (int i = Desktop::getInstance().getNumComponents(); --i >= 0;)
  28. {
  29. Component* c = Desktop::getInstance().getComponent (i);
  30. if (c != 0 && c->isAlwaysOnTop() && c->isShowing())
  31. return true;
  32. }
  33. return false;
  34. }
  35. static int CALLBACK browseCallbackProc (HWND hWnd, UINT msg, LPARAM lParam, LPARAM /*lpData*/)
  36. {
  37. if (msg == BFFM_INITIALIZED)
  38. {
  39. SendMessage (hWnd, BFFM_SETSELECTIONW, TRUE, (LPARAM) defaultDirPath);
  40. }
  41. else if (msg == BFFM_VALIDATEFAILEDW)
  42. {
  43. returnedString = (LPCWSTR) lParam;
  44. }
  45. else if (msg == BFFM_VALIDATEFAILEDA)
  46. {
  47. returnedString = (const char*) lParam;
  48. }
  49. return 0;
  50. }
  51. void juce_setWindowStyleBit (HWND h, const int styleType, const int feature, const bool bitIsSet) throw();
  52. static UINT_PTR CALLBACK openCallback (HWND hdlg, UINT uiMsg, WPARAM /*wParam*/, LPARAM lParam)
  53. {
  54. if (currentExtraFileWin != 0)
  55. {
  56. if (uiMsg == WM_INITDIALOG)
  57. {
  58. HWND dialogH = GetParent (hdlg);
  59. jassert (dialogH != 0);
  60. if (dialogH == 0)
  61. dialogH = hdlg;
  62. RECT r, cr;
  63. GetWindowRect (dialogH, &r);
  64. GetClientRect (dialogH, &cr);
  65. SetWindowPos (dialogH, 0,
  66. r.left, r.top,
  67. currentExtraFileWin->getWidth() + jmax (150, r.right - r.left),
  68. jmax (150, r.bottom - r.top),
  69. SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOZORDER);
  70. currentExtraFileWin->setBounds (cr.right, cr.top, currentExtraFileWin->getWidth(), cr.bottom - cr.top);
  71. currentExtraFileWin->getChildComponent(0)->setBounds (0, 0, currentExtraFileWin->getWidth(), currentExtraFileWin->getHeight());
  72. SetParent ((HWND) currentExtraFileWin->getWindowHandle(), (HWND) dialogH);
  73. juce_setWindowStyleBit ((HWND)currentExtraFileWin->getWindowHandle(), GWL_STYLE, WS_CHILD, (dialogH != 0));
  74. juce_setWindowStyleBit ((HWND)currentExtraFileWin->getWindowHandle(), GWL_STYLE, WS_POPUP, (dialogH == 0));
  75. }
  76. else if (uiMsg == WM_NOTIFY)
  77. {
  78. LPOFNOTIFY ofn = (LPOFNOTIFY) lParam;
  79. if (ofn->hdr.code == CDN_SELCHANGE)
  80. {
  81. FilePreviewComponent* comp = (FilePreviewComponent*) currentExtraFileWin->getChildComponent(0);
  82. if (comp != 0)
  83. {
  84. TCHAR path [MAX_PATH * 2];
  85. path[0] = 0;
  86. CommDlg_OpenSave_GetFilePath (GetParent (hdlg), (LPARAM) &path, MAX_PATH);
  87. const String fn ((const WCHAR*) path);
  88. comp->selectedFileChanged (File (fn));
  89. }
  90. }
  91. }
  92. }
  93. return 0;
  94. }
  95. class FPComponentHolder : public Component
  96. {
  97. public:
  98. FPComponentHolder()
  99. {
  100. setVisible (true);
  101. setOpaque (true);
  102. }
  103. ~FPComponentHolder()
  104. {
  105. }
  106. void paint (Graphics& g)
  107. {
  108. g.fillAll (Colours::lightgrey);
  109. }
  110. private:
  111. FPComponentHolder (const FPComponentHolder&);
  112. const FPComponentHolder& operator= (const FPComponentHolder&);
  113. };
  114. //==============================================================================
  115. void FileChooser::showPlatformDialog (OwnedArray<File>& results,
  116. const String& title,
  117. const File& currentFileOrDirectory,
  118. const String& filter,
  119. bool selectsDirectory,
  120. bool isSaveDialogue,
  121. bool warnAboutOverwritingExistingFiles,
  122. bool selectMultipleFiles,
  123. FilePreviewComponent* extraInfoComponent)
  124. {
  125. const int numCharsAvailable = 32768;
  126. MemoryBlock filenameSpace ((numCharsAvailable + 1) * sizeof (WCHAR), true);
  127. WCHAR* const fname = (WCHAR*) filenameSpace.getData();
  128. int fnameIdx = 0;
  129. JUCE_TRY
  130. {
  131. // use a modal window as the parent for this dialog box
  132. // to block input from other app windows
  133. const Rectangle mainMon (Desktop::getInstance().getMainMonitorArea());
  134. Component w (String::empty);
  135. w.setBounds (mainMon.getX() + mainMon.getWidth() / 4,
  136. mainMon.getY() + mainMon.getHeight() / 4,
  137. 0, 0);
  138. w.setOpaque (true);
  139. w.setAlwaysOnTop (areThereAnyAlwaysOnTopWindows());
  140. w.addToDesktop (0);
  141. if (extraInfoComponent == 0)
  142. w.enterModalState();
  143. String initialDir;
  144. if (currentFileOrDirectory.isDirectory())
  145. {
  146. initialDir = currentFileOrDirectory.getFullPathName();
  147. }
  148. else
  149. {
  150. currentFileOrDirectory.getFileName().copyToBuffer (fname, numCharsAvailable);
  151. initialDir = currentFileOrDirectory.getParentDirectory().getFullPathName();
  152. }
  153. if (currentExtraFileWin->isValidComponent())
  154. {
  155. jassertfalse
  156. return;
  157. }
  158. if (selectsDirectory)
  159. {
  160. LPITEMIDLIST list = 0;
  161. filenameSpace.fillWith (0);
  162. {
  163. BROWSEINFO bi;
  164. zerostruct (bi);
  165. bi.hwndOwner = (HWND) w.getWindowHandle();
  166. bi.pszDisplayName = fname;
  167. bi.lpszTitle = title;
  168. bi.lpfn = browseCallbackProc;
  169. #ifdef BIF_USENEWUI
  170. bi.ulFlags = BIF_USENEWUI | BIF_VALIDATE;
  171. #else
  172. bi.ulFlags = 0x50;
  173. #endif
  174. defaultDirPath = (const WCHAR*) initialDir;
  175. list = SHBrowseForFolder (&bi);
  176. if (! SHGetPathFromIDListW (list, fname))
  177. {
  178. fname[0] = 0;
  179. returnedString = String::empty;
  180. }
  181. }
  182. LPMALLOC al;
  183. if (list != 0 && SUCCEEDED (SHGetMalloc (&al)))
  184. al->Free (list);
  185. defaultDirPath = 0;
  186. if (returnedString.isNotEmpty())
  187. {
  188. const String stringFName (fname);
  189. results.add (new File (File (stringFName).getSiblingFile (returnedString)));
  190. returnedString = String::empty;
  191. return;
  192. }
  193. }
  194. else
  195. {
  196. DWORD flags = OFN_EXPLORER | OFN_PATHMUSTEXIST | OFN_NOCHANGEDIR | OFN_HIDEREADONLY;
  197. if (warnAboutOverwritingExistingFiles)
  198. flags |= OFN_OVERWRITEPROMPT;
  199. if (selectMultipleFiles)
  200. flags |= OFN_ALLOWMULTISELECT;
  201. if (extraInfoComponent != 0)
  202. {
  203. flags |= OFN_ENABLEHOOK;
  204. currentExtraFileWin = new FPComponentHolder();
  205. currentExtraFileWin->addAndMakeVisible (extraInfoComponent);
  206. currentExtraFileWin->setSize (jlimit (20, 800, extraInfoComponent->getWidth()),
  207. extraInfoComponent->getHeight());
  208. currentExtraFileWin->addToDesktop (0);
  209. currentExtraFileWin->enterModalState();
  210. }
  211. {
  212. WCHAR filters [1024];
  213. zeromem (filters, sizeof (filters));
  214. filter.copyToBuffer (filters, 1024);
  215. filter.copyToBuffer (filters + filter.length() + 1,
  216. 1022 - filter.length());
  217. OPENFILENAMEW of;
  218. zerostruct (of);
  219. #ifdef OPENFILENAME_SIZE_VERSION_400W
  220. of.lStructSize = OPENFILENAME_SIZE_VERSION_400W;
  221. #else
  222. of.lStructSize = sizeof (of);
  223. #endif
  224. of.hwndOwner = (HWND) w.getWindowHandle();
  225. of.lpstrFilter = filters;
  226. of.nFilterIndex = 1;
  227. of.lpstrFile = fname;
  228. of.nMaxFile = numCharsAvailable;
  229. of.lpstrInitialDir = initialDir;
  230. of.lpstrTitle = title;
  231. of.Flags = flags;
  232. if (extraInfoComponent != 0)
  233. of.lpfnHook = &openCallback;
  234. if (isSaveDialogue)
  235. {
  236. if (! GetSaveFileName (&of))
  237. fname[0] = 0;
  238. else
  239. fnameIdx = of.nFileOffset;
  240. }
  241. else
  242. {
  243. if (! GetOpenFileName (&of))
  244. fname[0] = 0;
  245. else
  246. fnameIdx = of.nFileOffset;
  247. }
  248. }
  249. }
  250. }
  251. #if JUCE_CATCH_UNHANDLED_EXCEPTIONS
  252. catch (...)
  253. {
  254. fname[0] = 0;
  255. }
  256. #endif
  257. deleteAndZero (currentExtraFileWin);
  258. const WCHAR* const files = fname;
  259. if (selectMultipleFiles && fnameIdx > 0 && files [fnameIdx - 1] == 0)
  260. {
  261. const WCHAR* filename = files + fnameIdx;
  262. while (*filename != 0)
  263. {
  264. const String filepath (String (files) + T("\\") + String (filename));
  265. results.add (new File (filepath));
  266. filename += CharacterFunctions::length (filename) + 1;
  267. }
  268. }
  269. else if (files[0] != 0)
  270. {
  271. results.add (new File (files));
  272. }
  273. }
  274. #endif