Code

Merged in Native File Dialogs for Windows Branch
[inkscape.git] / src / ui / dialog / filedialogimpl-win32.cpp
1 /**\r
2  * Implementation of the file dialog interfaces defined in filedialog.h for Win32\r
3  *\r
4  * Authors:\r
5  *   Joel Holdsworth\r
6  *   The Inkscape Organization\r
7  *\r
8  * Copyright (C) 2004-2007 The Inkscape Organization\r
9  *\r
10  * Released under GNU GPL, read the file 'COPYING' for more information\r
11  */\r
12  \r
13 #ifdef HAVE_CONFIG_H\r
14 # include <config.h>\r
15 #endif\r
16 \r
17 #ifdef WIN32\r
18  \r
19 //General includes\r
20 #include <list>\r
21 #include <unistd.h>\r
22 #include <sys/stat.h>\r
23 #include <errno.h>\r
24 #include <set>\r
25 #include <gdk/gdkwin32.h>\r
26 #include <glib/gstdio.h>\r
27 #include <glibmm/i18n.h>\r
28 #include <gtkmm/window.h>\r
29 \r
30 //Inkscape includes\r
31 #include "inkscape.h"\r
32 #include "prefs-utils.h"\r
33 #include <dialogs/dialog-events.h>\r
34 #include <extension/input.h>\r
35 #include <extension/output.h>\r
36 #include <extension/db.h>\r
37 \r
38 #include <libnr/nr-pixops.h>\r
39 #include <libnr/nr-translate-scale-ops.h>\r
40 #include <display/nr-arena-item.h>\r
41 #include <display/nr-arena.h>\r
42 #include "sp-item.h"\r
43 #include "canvas-arena.h"\r
44 \r
45 #include "filedialog.h"\r
46 #include "filedialogimpl-win32.h"\r
47 \r
48 #include <zlib.h>\r
49 #include <cairomm/win32_surface.h>\r
50 #include <cairomm/context.h>\r
51 \r
52 using namespace std;\r
53 using namespace Glib;\r
54 using namespace Cairo;\r
55 using namespace Gdk::Cairo;\r
56 \r
57 namespace Inkscape\r
58 {\r
59 namespace UI\r
60 {\r
61 namespace Dialog\r
62 {\r
63 \r
64 const int PreviewWidening = 150;\r
65 const char PreviewWindowClassName[] = "PreviewWnd";\r
66 const unsigned long MaxPreviewFileSize = 1344; // kB\r
67 \r
68 #define IDC_SHOW_PREVIEW    1000\r
69 \r
70 // Windows 2000 version of OPENFILENAMEW\r
71 struct OPENFILENAMEEXW : public OPENFILENAMEW { \r
72   void *        pvReserved;\r
73   DWORD         dwReserved;\r
74   DWORD         FlagsEx;\r
75 };\r
76 \r
77 struct Filter\r
78 {\r
79     gunichar2* name;\r
80     glong name_length;\r
81     gunichar2* filter;\r
82     glong filter_length;\r
83     Inkscape::Extension::Extension* mod;\r
84 };\r
85 \r
86 ustring utf16_to_ustring(const wchar_t *utf16string, int utf16length = -1)\r
87 {\r
88     gchar *utf8string = g_utf16_to_utf8((const gunichar2*)utf16string,\r
89         utf16length, NULL, NULL, NULL);\r
90     ustring result(utf8string);\r
91     g_free(utf8string);\r
92     \r
93     return result;\r
94 }\r
95 \r
96 /*#########################################################################\r
97 ### F I L E     D I A L O G    B A S E    C L A S S\r
98 #########################################################################*/\r
99 \r
100 FileDialogBaseWin32::FileDialogBaseWin32(Gtk::Window &parent, \r
101         const Glib::ustring &dir, const gchar *title,\r
102         FileDialogType type, gchar const* /*preferenceBase*/) :\r
103         dialogType(type),\r
104         parent(parent),\r
105         _current_directory(dir)\r
106 {\r
107     //_mutex = NULL;\r
108     _main_loop = NULL;\r
109     \r
110     _title = (wchar_t*)g_utf8_to_utf16(title, -1, NULL, NULL, NULL);\r
111     \r
112     Glib::RefPtr<const Gdk::Window> parentWindow = parent.get_window();\r
113     g_assert(parentWindow->gobj() != NULL);\r
114     _ownerHwnd = (HWND)gdk_win32_drawable_get_handle((GdkDrawable*)parentWindow->gobj());\r
115 }\r
116 \r
117 FileDialogBaseWin32::~FileDialogBaseWin32()\r
118 {\r
119     g_free(_title);\r
120 }\r
121 \r
122 Inkscape::Extension::Extension *FileDialogBaseWin32::getSelectionType()\r
123 {\r
124     return _extension;\r
125 }\r
126 \r
127 Glib::ustring FileDialogBaseWin32::getCurrentDirectory()\r
128 {\r
129     return _current_directory;\r
130 }\r
131 \r
132 /*#########################################################################\r
133 ### F I L E    O P E N\r
134 #########################################################################*/\r
135 \r
136 bool FileOpenDialogImplWin32::_show_preview = true;\r
137 \r
138 /**\r
139  * Constructor.  Not called directly.  Use the factory.\r
140  */\r
141 FileOpenDialogImplWin32::FileOpenDialogImplWin32(Gtk::Window &parent,  \r
142                                        const Glib::ustring &dir,\r
143                                        FileDialogType fileTypes,\r
144                                        const gchar *title) :\r
145     FileDialogBaseWin32(parent, dir, title, fileTypes, "dialogs.open")\r
146 {\r
147     // Initalize to Autodetect\r
148     _extension = NULL;\r
149 \r
150     // Set our dialog type (open, import, etc...)\r
151     dialogType = fileTypes;\r
152     \r
153     _show_preview_button_bitmap = NULL;\r
154     _preview_wnd = NULL;\r
155     _file_dialog_wnd = NULL;\r
156     _base_window_proc = NULL;\r
157     \r
158     _preview_file_size = 0;\r
159     _preview_bitmap = NULL;\r
160     _preview_file_icon = NULL;\r
161     _preview_document_width = 0;\r
162     _preview_document_height = 0;\r
163     _preview_image_width = 0;\r
164     _preview_image_height = 0;\r
165     \r
166     createFilterMenu();\r
167 }\r
168 \r
169 \r
170 /**\r
171  * Destructor\r
172  */\r
173 FileOpenDialogImplWin32::~FileOpenDialogImplWin32()\r
174 {\r
175     if(_filter != NULL)\r
176         delete[] _filter;\r
177     if(_extension_map != NULL)\r
178         delete[] _extension_map;\r
179 }\r
180 \r
181 void FileOpenDialogImplWin32::createFilterMenu()\r
182 {\r
183     list<Filter> filter_list;\r
184 \r
185     // Compose the filter string\r
186     Inkscape::Extension::DB::InputList extension_list;\r
187     Inkscape::Extension::db.get_input_list(extension_list);\r
188     \r
189     ustring all_inkscape_files_filter, all_image_files_filter;\r
190     Filter all_files, all_inkscape_files, all_image_files;\r
191 \r
192     const gchar *all_files_filter_name = _("All Files");\r
193     const gchar *all_inkscape_files_filter_name = ("All Inkscape Files");\r
194     const gchar *all_image_files_filter_name = _("All Image Files");\r
195         \r
196     // Calculate the amount of memory required\r
197     int filter_count = 3;       // 3 - one for All Files, All Images and All Inkscape Files\r
198     int filter_length = 1;\r
199         \r
200     for (Inkscape::Extension::DB::InputList::iterator current_item = extension_list.begin();\r
201          current_item != extension_list.end(); current_item++)\r
202     {\r
203         Filter filter;\r
204     \r
205         Inkscape::Extension::Input *imod = *current_item;\r
206         if (imod->deactivated()) continue;\r
207                 \r
208         // Type\r
209         filter.name = g_utf8_to_utf16(imod->get_filetypename(),\r
210             -1, NULL, &filter.name_length, NULL);\r
211         \r
212         // Extension\r
213         const gchar *file_extension_name = imod->get_extension();\r
214         filter.filter = g_utf8_to_utf16(file_extension_name,\r
215             -1, NULL, &filter.filter_length, NULL);\r
216         \r
217         filter.mod = imod;\r
218         filter_list.push_back(filter);\r
219         \r
220         filter_length += filter.name_length +\r
221             filter.filter_length + 3;   // Add 3 for two \0s and a *\r
222             \r
223         // Add to the "All Inkscape Files" Entry\r
224         if(all_inkscape_files_filter.length() > 0)\r
225             all_inkscape_files_filter += ";*";\r
226         all_inkscape_files_filter += file_extension_name;\r
227         if( strncmp("image", imod->get_mimetype(), 5) == 0)\r
228         {\r
229             // Add to the "All Image Files" Entry\r
230             if(all_image_files_filter.length() > 0)\r
231                 all_image_files_filter += ";*";\r
232             all_image_files_filter += file_extension_name;\r
233         }\r
234         \r
235         filter_count++;\r
236     }\r
237     \r
238     int extension_index = 0;\r
239     _extension_map = new Inkscape::Extension::Extension*[filter_count];\r
240     \r
241     // Filter Image Files\r
242     all_image_files.name = g_utf8_to_utf16(all_image_files_filter_name,\r
243         -1, NULL, &all_image_files.name_length, NULL);\r
244     all_image_files.filter = g_utf8_to_utf16(all_image_files_filter.data(),\r
245             -1, NULL, &all_image_files.filter_length, NULL);\r
246     filter_list.push_front(all_image_files);\r
247     _extension_map[extension_index++] = NULL;\r
248     \r
249     // Filter Inkscape Files\r
250     all_inkscape_files.name = g_utf8_to_utf16(all_inkscape_files_filter_name,\r
251         -1, NULL, &all_inkscape_files.name_length, NULL);\r
252     all_inkscape_files.filter = g_utf8_to_utf16(all_inkscape_files_filter.data(),\r
253             -1, NULL, &all_inkscape_files.filter_length, NULL);\r
254     filter_list.push_front(all_inkscape_files);\r
255     _extension_map[extension_index++] = NULL;\r
256     \r
257     // Filter All Files\r
258     all_files.name = g_utf8_to_utf16(all_files_filter_name,\r
259         -1, NULL, &all_files.name_length, NULL);\r
260     all_files.filter = NULL;\r
261     all_files.filter_length = 0;\r
262     filter_list.push_front(all_files);\r
263     _extension_map[extension_index++] = NULL;\r
264     \r
265     filter_length += all_files.name_length + 3 +\r
266                     all_inkscape_files.filter_length + \r
267                     all_inkscape_files.name_length + 3 +\r
268                     all_image_files.filter_length +\r
269                     all_image_files.name_length + 3 + 1;\r
270      // Add 3 for 2*2 \0s and a *, and 1 for a trailing \0\r
271       \r
272     \r
273     _filter = new wchar_t[filter_length];\r
274     wchar_t *filterptr = _filter;\r
275     \r
276     for(list<Filter>::iterator filter_iterator = filter_list.begin();\r
277         filter_iterator != filter_list.end(); filter_iterator++)\r
278     {\r
279         const Filter &filter = *filter_iterator;\r
280         \r
281         memcpy(filterptr, filter.name, filter.name_length * 2);\r
282         filterptr += filter.name_length;\r
283         g_free(filter.name);\r
284         \r
285         *(filterptr++) = L'\0';\r
286         *(filterptr++) = L'*';\r
287         \r
288         if(filter.filter != NULL)\r
289         {\r
290             memcpy(filterptr, filter.filter, filter.filter_length * 2);\r
291             filterptr += filter.filter_length;  \r
292             g_free(filter.filter);\r
293         }\r
294     \r
295         *(filterptr++) = L'\0';\r
296         \r
297         // Associate this input extension with the file type name\r
298         _extension_map[extension_index++] = filter.mod;\r
299     }\r
300     *(filterptr++) = L'\0';\r
301     \r
302     _filterIndex = 2;\r
303 }\r
304 \r
305 void FileOpenDialogImplWin32::GetOpenFileName_thread()\r
306 {\r
307     OPENFILENAMEEXW ofn;\r
308 \r
309     g_assert(this != NULL);\r
310     //g_assert(_mutex != NULL);\r
311     g_assert(_main_loop != NULL);    \r
312         \r
313     WCHAR* current_directory_string = (WCHAR*)g_utf8_to_utf16(\r
314         _current_directory.data(), -1, NULL, NULL, NULL);\r
315         \r
316     memset(&ofn, 0, sizeof(ofn));\r
317     \r
318     // Copy the selected file name, converting from UTF-8 to UTF-16\r
319     memset(_path_string, 0, sizeof(_path_string));\r
320     gunichar2* utf16_path_string = g_utf8_to_utf16(\r
321         myFilename.data(), -1, NULL, NULL, NULL);\r
322     wcsncpy(_path_string, (wchar_t*)utf16_path_string, _MAX_PATH);\r
323     g_free(utf16_path_string);\r
324     \r
325     ofn.lStructSize = sizeof(ofn);\r
326     ofn.hwndOwner = _ownerHwnd;\r
327     ofn.lpstrFile = _path_string;\r
328     ofn.nMaxFile = _MAX_PATH;\r
329     ofn.lpstrFileTitle = NULL;\r
330     ofn.nMaxFileTitle = 0;\r
331     ofn.lpstrInitialDir = current_directory_string;\r
332     ofn.lpstrTitle = _title;\r
333     ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST | OFN_EXPLORER | OFN_ENABLEHOOK | OFN_HIDEREADONLY | OFN_ENABLESIZING;\r
334     ofn.lpstrFilter = _filter;\r
335     ofn.nFilterIndex = _filterIndex;\r
336     ofn.lpfnHook = GetOpenFileName_hookproc;\r
337     ofn.lCustData = (LPARAM)this;\r
338     \r
339     _result = GetOpenFileNameW(&ofn) != 0;\r
340     \r
341     _filterIndex = ofn.nFilterIndex;\r
342     _extension = _extension_map[ofn.nFilterIndex];\r
343 \r
344     myFilename = utf16_to_ustring(_path_string, _MAX_PATH);\r
345     \r
346     // Copy the selected file name, converting from UTF-16 to UTF-8\r
347     myFilename = utf16_to_ustring(_path_string, _MAX_PATH);\r
348     \r
349     // Tidy up\r
350     g_free(current_directory_string);\r
351     \r
352     _mutex->lock();\r
353     _finished = true;\r
354     _mutex->unlock();\r
355     //g_main_loop_quit(_main_loop);\r
356     \r
357 \r
358 }\r
359 \r
360 void FileOpenDialogImplWin32::register_preview_wnd_class()\r
361 {\r
362     HINSTANCE hInstance = GetModuleHandle(NULL);\r
363     const WNDCLASSA PreviewWndClass = \r
364     {\r
365         CS_HREDRAW | CS_VREDRAW,\r
366         preview_wnd_proc,\r
367         0,\r
368         0,\r
369         hInstance,\r
370         NULL,\r
371         LoadCursor(hInstance, IDC_ARROW),\r
372         (HBRUSH)(COLOR_BTNFACE + 1),\r
373         NULL,\r
374         PreviewWindowClassName\r
375     };\r
376 \r
377     RegisterClassA(&PreviewWndClass);\r
378 }\r
379 \r
380 UINT_PTR CALLBACK FileOpenDialogImplWin32::GetOpenFileName_hookproc(\r
381     HWND hdlg, UINT uiMsg, WPARAM, LPARAM lParam)\r
382 {\r
383     FileOpenDialogImplWin32 *pImpl = (FileOpenDialogImplWin32*)\r
384         GetWindowLongPtr(hdlg, GWLP_USERDATA);\r
385         \r
386     switch(uiMsg)\r
387     {\r
388     case WM_INITDIALOG:\r
389         {\r
390             HWND hParentWnd = GetParent(hdlg);\r
391             HINSTANCE hInstance = GetModuleHandle(NULL);\r
392             \r
393             // Make the window a bit wider\r
394             RECT rcRect;\r
395             GetWindowRect(hParentWnd, &rcRect);\r
396             MoveWindow(hParentWnd, rcRect.left, rcRect.top,\r
397                 rcRect.right - rcRect.left + PreviewWidening,\r
398                 rcRect.bottom - rcRect.top,\r
399                 FALSE);\r
400             \r
401             // Set the pointer to the object\r
402             OPENFILENAMEW *ofn = (OPENFILENAMEW*)lParam;\r
403             SetWindowLongPtr(hdlg, GWLP_USERDATA, ofn->lCustData);\r
404             SetWindowLongPtr(hParentWnd, GWLP_USERDATA, ofn->lCustData);\r
405             pImpl = (FileOpenDialogImplWin32*)ofn->lCustData;\r
406             \r
407             // Subclass the parent\r
408             pImpl->_base_window_proc = (WNDPROC)GetWindowLongPtr(hParentWnd, GWL_WNDPROC);\r
409             SetWindowLongPtr(hParentWnd, GWL_WNDPROC, (LONG_PTR)file_dialog_subclass_proc);\r
410         \r
411             // Add a button to the toolbar\r
412             pImpl->_toolbar_wnd = FindWindowEx(hParentWnd, NULL, "ToolbarWindow32", NULL);\r
413 \r
414             pImpl->_show_preview_button_bitmap = LoadBitmap(\r
415                 hInstance, MAKEINTRESOURCE(IDC_SHOW_PREVIEW));\r
416             TBADDBITMAP tbAddBitmap = {NULL, (UINT)pImpl->_show_preview_button_bitmap};            \r
417             const int iBitmapIndex = SendMessage(pImpl->_toolbar_wnd,\r
418                 TB_ADDBITMAP, 1, (LPARAM)&tbAddBitmap);\r
419     \r
420             TBBUTTON tbButton;\r
421             memset(&tbButton, 0, sizeof(TBBUTTON));\r
422             tbButton.iBitmap = iBitmapIndex;\r
423             tbButton.idCommand = IDC_SHOW_PREVIEW;\r
424             tbButton.fsState = (pImpl->_show_preview ? TBSTATE_CHECKED : 0)\r
425                 | TBSTATE_ENABLED;\r
426             tbButton.fsStyle = TBSTYLE_CHECK;\r
427             tbButton.iString = (INT_PTR)_("Show Preview");\r
428             SendMessage(pImpl->_toolbar_wnd, TB_ADDBUTTONS, 1, (LPARAM)&tbButton); \r
429             \r
430             // Create preview pane\r
431             register_preview_wnd_class();\r
432 \r
433             pImpl->_mutex->lock();\r
434             \r
435                 pImpl->_file_dialog_wnd = hParentWnd;\r
436                 \r
437                 pImpl->_preview_wnd = \r
438                     CreateWindow(PreviewWindowClassName, "",\r
439                         WS_CHILD | WS_VISIBLE,\r
440                         0, 0, 100, 100, hParentWnd, NULL, hInstance, NULL);\r
441                 SetWindowLongPtr(pImpl->_preview_wnd, GWLP_USERDATA, ofn->lCustData);\r
442                     \r
443             pImpl->_mutex->unlock();\r
444                 \r
445             pImpl->layout_dialog();\r
446         }\r
447         break;\r
448     \r
449     case WM_NOTIFY:\r
450         {\r
451         \r
452         OFNOTIFY *pOFNotify = reinterpret_cast<OFNOTIFY*>(lParam);\r
453         switch(pOFNotify->hdr.code)\r
454         {\r
455         case CDN_SELCHANGE:\r
456             {\r
457                 if(pImpl != NULL)\r
458                 {\r
459                     // Get the file name\r
460                     pImpl->_mutex->lock();\r
461                     \r
462                     SendMessage(pOFNotify->hdr.hwndFrom, CDM_GETFILEPATH,\r
463                         sizeof(pImpl->_path_string) / sizeof(wchar_t),\r
464                         (LPARAM)pImpl->_path_string);\r
465                     \r
466                     pImpl->_file_selected = true;\r
467                     \r
468                     pImpl->_mutex->unlock();\r
469                         \r
470                     //pImpl->file_selected();\r
471                 }\r
472             }\r
473             break;\r
474         }\r
475         }\r
476         break;\r
477         \r
478     case WM_CLOSE:\r
479         pImpl->_mutex->lock();\r
480         pImpl->_preview_file_size = 0;\r
481     \r
482         pImpl->_file_dialog_wnd = NULL;\r
483         DestroyWindow(pImpl->_preview_wnd);\r
484         pImpl->_preview_wnd = NULL;\r
485         DeleteObject(pImpl->_show_preview_button_bitmap);\r
486         pImpl->_show_preview_button_bitmap = NULL;\r
487         pImpl->_mutex->unlock();\r
488 \r
489         break;\r
490     }\r
491         \r
492     // Use default dialog behaviour\r
493     return 0;\r
494 }\r
495 \r
496 LRESULT CALLBACK FileOpenDialogImplWin32::file_dialog_subclass_proc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)\r
497 {\r
498     FileOpenDialogImplWin32 *pImpl = (FileOpenDialogImplWin32*)\r
499         GetWindowLongPtr(hwnd, GWLP_USERDATA);\r
500 \r
501     LRESULT lResult = CallWindowProc(pImpl->_base_window_proc, hwnd, uMsg, wParam, lParam);\r
502         \r
503     switch(uMsg)\r
504     {\r
505     case WM_SHOWWINDOW:\r
506         if(wParam != 0)\r
507             pImpl->layout_dialog();\r
508         break;\r
509         \r
510     case WM_SIZE:\r
511         pImpl->layout_dialog();\r
512         break;\r
513         \r
514     case WM_COMMAND:\r
515         if(wParam == IDC_SHOW_PREVIEW)\r
516         {\r
517             const bool enable = SendMessage(pImpl->_toolbar_wnd,\r
518                 TB_ISBUTTONCHECKED, IDC_SHOW_PREVIEW, 0) != 0;\r
519             pImpl->enable_preview(enable);\r
520         }\r
521         break;\r
522     }\r
523     \r
524     return lResult;\r
525 }\r
526 \r
527 LRESULT CALLBACK FileOpenDialogImplWin32::preview_wnd_proc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)\r
528 {\r
529     const int CaptionPadding = 4;\r
530     const int IconSize = 32;\r
531     \r
532     FileOpenDialogImplWin32 *pImpl = (FileOpenDialogImplWin32*)\r
533         GetWindowLongPtr(hwnd, GWLP_USERDATA);\r
534 \r
535     LRESULT lResult = 0;\r
536     \r
537     switch(uMsg)\r
538     {\r
539     case WM_ERASEBKGND:\r
540         // Do nothing to erase the background\r
541         //  - otherwise there'll be flicker\r
542         lResult = 1;\r
543         break;\r
544     \r
545     case WM_PAINT:\r
546         {\r
547             // Get the client rect\r
548             RECT rcClient;\r
549             GetClientRect(hwnd, &rcClient);\r
550             \r
551             // Prepare to paint\r
552             PAINTSTRUCT paint_struct;\r
553             HDC dc = BeginPaint(hwnd, &paint_struct);\r
554             \r
555             HFONT hCaptionFont = (HFONT)SendMessage(GetParent(hwnd),\r
556                     WM_GETFONT, 0, 0);\r
557             HFONT hOldFont = (HFONT)SelectObject(dc, hCaptionFont);\r
558             SetBkMode(dc, TRANSPARENT);\r
559             \r
560             pImpl->_mutex->lock();\r
561             \r
562             //FillRect(dc, &client_rect, (HBRUSH)(COLOR_HOTLIGHT+1));\r
563             if(pImpl->_path_string[0] == 0)\r
564             {\r
565                 FillRect(dc, &rcClient, (HBRUSH)(COLOR_3DFACE + 1));\r
566                 DrawText(dc, _("No file selected"), -1, &rcClient,\r
567                     DT_CENTER | DT_VCENTER | DT_NOPREFIX);\r
568             }\r
569             else if(pImpl->_preview_bitmap != NULL)\r
570             {\r
571                 BITMAP bitmap;\r
572                 GetObject(pImpl->_preview_bitmap, sizeof(bitmap), &bitmap);\r
573                 const int destX = (rcClient.right - bitmap.bmWidth) / 2;\r
574                             \r
575                 // Render the image\r
576                 HDC hSrcDC = CreateCompatibleDC(dc);\r
577                 HBITMAP hOldBitmap = (HBITMAP)SelectObject(hSrcDC, pImpl->_preview_bitmap);\r
578             \r
579                 BitBlt(dc, destX, 0, bitmap.bmWidth, bitmap.bmHeight,\r
580                     hSrcDC, 0, 0, SRCCOPY);\r
581                     \r
582                 SelectObject(hSrcDC, hOldBitmap);\r
583                 DeleteDC(hSrcDC);\r
584                 \r
585                 // Fill in the background area\r
586                 HRGN hEraseRgn = CreateRectRgn(rcClient.left, rcClient.top,\r
587                     rcClient.right, rcClient.bottom);\r
588                 HRGN hImageRgn = CreateRectRgn(destX, 0,\r
589                     destX + bitmap.bmWidth, bitmap.bmHeight);\r
590                 CombineRgn(hEraseRgn, hEraseRgn, hImageRgn, RGN_DIFF);\r
591                 \r
592                 FillRgn(dc, hEraseRgn, GetSysColorBrush(COLOR_3DFACE));\r
593                                 \r
594                 DeleteObject(hImageRgn);\r
595                 DeleteObject(hEraseRgn);\r
596                 \r
597                 // Draw the caption on\r
598                 RECT rcCaptionRect = {rcClient.left,\r
599                     rcClient.top + bitmap.bmHeight + CaptionPadding,\r
600                     rcClient.right, rcClient.bottom};\r
601                     \r
602                 WCHAR szCaption[_MAX_FNAME + 32];                \r
603                 const int iLength = pImpl->format_caption(\r
604                     szCaption, sizeof(szCaption) / sizeof(WCHAR));\r
605         \r
606                 DrawTextW(dc, szCaption, iLength, &rcCaptionRect,\r
607                     DT_CENTER | DT_TOP | DT_NOPREFIX | DT_PATH_ELLIPSIS);\r
608             }\r
609             else if(pImpl->_preview_file_icon != NULL)\r
610             {\r
611                 FillRect(dc, &rcClient, (HBRUSH)(COLOR_3DFACE + 1));\r
612                 \r
613                 // Draw the files icon\r
614                 const int destX = (rcClient.right - IconSize) / 2;\r
615                 DrawIconEx(dc, destX, 0, pImpl->_preview_file_icon,\r
616                     IconSize, IconSize, 0, NULL,\r
617                     DI_NORMAL | DI_COMPAT);\r
618                     \r
619                 // Draw the caption on\r
620                 RECT rcCaptionRect = {rcClient.left,\r
621                     rcClient.top + IconSize + CaptionPadding,\r
622                     rcClient.right, rcClient.bottom};\r
623                     \r
624                 WCHAR szFileName[_MAX_FNAME], szCaption[_MAX_FNAME + 32];\r
625                 _wsplitpath(pImpl->_path_string, NULL, NULL, szFileName, NULL);\r
626                 \r
627                 const int iLength = snwprintf(szCaption,\r
628                     sizeof(szCaption), L"%s\n%d kB",\r
629                     szFileName, pImpl->_preview_file_size);\r
630                 \r
631                 DrawTextW(dc, szCaption, iLength, &rcCaptionRect,\r
632                     DT_CENTER | DT_TOP | DT_NOPREFIX | DT_PATH_ELLIPSIS);\r
633             }\r
634             else\r
635             {\r
636                 // Can't show anything!\r
637                 FillRect(dc, &rcClient, (HBRUSH)(COLOR_3DFACE + 1));\r
638             }\r
639             \r
640             pImpl->_mutex->unlock();\r
641             \r
642             // Finish painting\r
643             SelectObject(dc, hOldFont);\r
644             EndPaint(hwnd, &paint_struct);\r
645         }\r
646         \r
647         break;\r
648         \r
649     case WM_DESTROY:\r
650         pImpl->free_preview();\r
651         break;\r
652         \r
653     default:\r
654         lResult = DefWindowProc(hwnd, uMsg, wParam, lParam);\r
655         break;\r
656     }\r
657 \r
658     return lResult;\r
659 }\r
660 \r
661 void FileOpenDialogImplWin32::enable_preview(bool enable)\r
662 {\r
663     _show_preview = enable;\r
664 \r
665     // Relayout the dialog\r
666     ShowWindow(_preview_wnd, enable ? SW_SHOW : SW_HIDE);\r
667     layout_dialog();\r
668     \r
669     // Load or unload the preview\r
670     if(enable)\r
671     {\r
672         _mutex->lock();\r
673         _file_selected = true;\r
674         _mutex->unlock();\r
675     }\r
676     else free_preview();\r
677 }\r
678 \r
679 void FileOpenDialogImplWin32::layout_dialog()\r
680 {\r
681     union RECTPOINTS\r
682     {\r
683         RECT r;\r
684         POINT p[2];\r
685     };    \r
686     \r
687     const float MaxExtentScale = 2.0f / 3.0f;\r
688     \r
689     RECT rcClient;\r
690     GetClientRect(_file_dialog_wnd, &rcClient);\r
691 \r
692     // Re-layout the dialog\r
693     HWND hFileListWnd = GetDlgItem(_file_dialog_wnd, lst2);\r
694     HWND hFolderComboWnd = GetDlgItem(_file_dialog_wnd, cmb2);\r
695     \r
696     \r
697     RECT rcFolderComboRect;\r
698     RECTPOINTS rcFileList;\r
699     GetWindowRect(hFileListWnd, &rcFileList.r);\r
700     GetWindowRect(hFolderComboWnd, &rcFolderComboRect);\r
701     const int iPadding = rcFileList.r.top - rcFolderComboRect.bottom;\r
702     MapWindowPoints(NULL, _file_dialog_wnd, rcFileList.p, 2);\r
703         \r
704     RECT rcPreview;\r
705     RECT rcBody = {rcFileList.r.left, rcFileList.r.top,\r
706         rcClient.right - iPadding, rcFileList.r.bottom};\r
707     rcFileList.r.right = rcBody.right;\r
708     \r
709     if(_show_preview)\r
710     {\r
711         rcPreview.top = rcBody.top;\r
712         rcPreview.left = rcClient.right - (rcBody.bottom - rcBody.top);\r
713         const int iMaxExtent = (int)(MaxExtentScale * (float)(rcBody.left + rcBody.right)) + iPadding / 2;\r
714         if(rcPreview.left < iMaxExtent) rcPreview.left = iMaxExtent;\r
715         rcPreview.bottom = rcBody.bottom;\r
716         rcPreview.right = rcBody.right;\r
717         \r
718         // Re-layout the preview box\r
719         _mutex->lock();\r
720 \r
721             _preview_width = rcPreview.right - rcPreview.left;\r
722             _preview_height = rcPreview.bottom - rcPreview.top;\r
723 \r
724         _mutex->unlock();\r
725         \r
726         render_preview();\r
727         \r
728         MoveWindow(_preview_wnd, rcPreview.left, rcPreview.top,\r
729             _preview_width, _preview_height, TRUE);\r
730             \r
731         rcFileList.r.right = rcPreview.left - iPadding;\r
732     }\r
733     \r
734     // Re-layout the file list box\r
735     MoveWindow(hFileListWnd, rcFileList.r.left, rcFileList.r.top,\r
736         rcFileList.r.right - rcFileList.r.left,\r
737         rcFileList.r.bottom - rcFileList.r.top, TRUE);\r
738         \r
739     // Re-layout the toolbar\r
740     RECTPOINTS rcToolBar;\r
741     GetWindowRect(_toolbar_wnd, &rcToolBar.r);\r
742     MapWindowPoints(NULL, _file_dialog_wnd, rcToolBar.p, 2);\r
743     MoveWindow(_toolbar_wnd, rcToolBar.r.left, rcToolBar.r.top, \r
744         rcToolBar.r.right - rcToolBar.r.left, rcToolBar.r.bottom - rcToolBar.r.top, TRUE); \r
745 }\r
746 \r
747 void FileOpenDialogImplWin32::file_selected()\r
748 {\r
749     // Destroy any previous previews\r
750     free_preview();\r
751     \r
752 \r
753     // Determine if the file exists\r
754     DWORD attributes = GetFileAttributesW(_path_string);\r
755     if(attributes == 0xFFFFFFFF ||\r
756         attributes == FILE_ATTRIBUTE_DIRECTORY)\r
757     {\r
758         InvalidateRect(_preview_wnd, NULL, FALSE);\r
759         return;\r
760     }\r
761 \r
762     // Check the file exists and get the file size\r
763     HANDLE file_handle = CreateFileW(_path_string, GENERIC_READ,\r
764         FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);\r
765     if(file_handle == INVALID_HANDLE_VALUE) return;    \r
766     const DWORD file_size = GetFileSize(file_handle, NULL);\r
767     if (file_size == INVALID_FILE_SIZE) return;\r
768     _preview_file_size = file_size / 1024;\r
769     CloseHandle(file_handle);\r
770         \r
771     if(_show_preview) load_preview();    \r
772 }\r
773     \r
774 void FileOpenDialogImplWin32::load_preview()\r
775 {\r
776     // Destroy any previous previews\r
777     free_preview();\r
778     \r
779     // Try to get the file icon\r
780     SHFILEINFOW fileInfo;\r
781     if(SUCCEEDED(SHGetFileInfoW(_path_string, 0, &fileInfo,\r
782         sizeof(fileInfo), SHGFI_ICON | SHGFI_LARGEICON)))\r
783         _preview_file_icon = fileInfo.hIcon;\r
784         \r
785     // Will this file be too big?\r
786     if(_preview_file_size > MaxPreviewFileSize)\r
787     {\r
788         InvalidateRect(_preview_wnd, NULL, FALSE);\r
789         return;\r
790     }\r
791 \r
792     // Prepare to render a preview\r
793     const Glib::ustring svg = ".svg";\r
794     const Glib::ustring svgz = ".svgz";\r
795     const Glib::ustring path = utf16_to_ustring(_path_string);\r
796     \r
797     bool success = false;\r
798     \r
799     _preview_document_width = _preview_document_height = 0;\r
800     \r
801     if ((dialogType == SVG_TYPES || dialogType == IMPORT_TYPES) &&\r
802             (hasSuffix(path, svg) || hasSuffix(path, svgz)))\r
803         success = set_svg_preview();\r
804     else if (isValidImageFile(path))\r
805         success = set_image_preview();\r
806     else {\r
807         // Show no preview\r
808     }\r
809     \r
810     if(success) render_preview();\r
811     \r
812     InvalidateRect(_preview_wnd, NULL, FALSE);\r
813 }\r
814 \r
815 void FileOpenDialogImplWin32::free_preview()\r
816 {\r
817     _mutex->lock();\r
818     if(_preview_bitmap != NULL)\r
819         DeleteObject(_preview_bitmap);\r
820     _preview_bitmap = NULL;\r
821     \r
822     if(_preview_file_icon != NULL)\r
823         DestroyIcon(_preview_file_icon);\r
824     _preview_file_icon = NULL;\r
825     \r
826     _preview_bitmap_image.clear();\r
827     _mutex->unlock();\r
828 }\r
829 \r
830 bool FileOpenDialogImplWin32::set_svg_preview()\r
831 {\r
832     const int PreviewSize = 512;\r
833 \r
834     gchar *utf8string = g_utf16_to_utf8((const gunichar2*)_path_string,\r
835         _MAX_PATH, NULL, NULL, NULL);\r
836     SPDocument *svgDoc = sp_document_new (utf8string, true);\r
837     g_free(utf8string);\r
838         \r
839     // Check the document loaded properly        \r
840     if(svgDoc == NULL) return false;\r
841     if(svgDoc->root == NULL)\r
842     {\r
843         sp_document_unref(svgDoc);\r
844         return false;\r
845     }\r
846     \r
847     // Get the size of the document\r
848     const double svgWidth = sp_document_width(svgDoc);\r
849     const double svgHeight = sp_document_height(svgDoc);\r
850     \r
851     // Find the minimum scale to fit the image inside the preview area\r
852     const double scaleFactorX =    PreviewSize / svgWidth;\r
853     const double scaleFactorY =    PreviewSize / svgHeight;\r
854     const double scaleFactor = (scaleFactorX > scaleFactorY) ? scaleFactorY : scaleFactorX;\r
855     \r
856     // Now get the resized values\r
857     const double scaledSvgWidth  = scaleFactor * svgWidth;\r
858     const double scaledSvgHeight = scaleFactor * svgHeight;\r
859     \r
860     NR::Rect area(NR::Point(0, 0), NR::Point(scaledSvgWidth, scaledSvgHeight));\r
861     NRRectL areaL = {0, 0, scaledSvgWidth, scaledSvgHeight};\r
862     NRRectL bbox = {0, 0, scaledSvgWidth, scaledSvgHeight};\r
863         \r
864     // write object bbox to area\r
865     NR::Maybe<NR::Rect> maybeArea(area);\r
866     sp_document_ensure_up_to_date (svgDoc);\r
867     sp_item_invoke_bbox((SPItem *) svgDoc->root, &maybeArea,\r
868         sp_item_i2r_affine((SPItem *)(svgDoc->root)), TRUE);\r
869     \r
870     NRArena *const arena = NRArena::create();\r
871         \r
872     unsigned const key = sp_item_display_key_new(1);\r
873     \r
874     NRArenaItem *root = sp_item_invoke_show((SPItem*)(svgDoc->root),\r
875         arena, key, SP_ITEM_SHOW_DISPLAY);\r
876     \r
877     NRGC gc(NULL);\r
878     nr_matrix_set_scale(&gc.transform, scaleFactor, scaleFactor);\r
879     \r
880     nr_arena_item_invoke_update (root, NULL, &gc,\r
881         NR_ARENA_ITEM_STATE_ALL, NR_ARENA_ITEM_STATE_NONE);\r
882     \r
883     // Prepare a GDI compatible NRPixBlock\r
884     NRPixBlock pixBlock;\r
885     pixBlock.size = NR_PIXBLOCK_SIZE_BIG;\r
886     pixBlock.mode = NR_PIXBLOCK_MODE_R8G8B8;\r
887     pixBlock.empty = 1;\r
888     pixBlock.visible_area.x0 = pixBlock.area.x0 = 0;\r
889     pixBlock.visible_area.y0 = pixBlock.area.y0 = 0;\r
890     pixBlock.visible_area.x1 = pixBlock.area.x1 = scaledSvgWidth;\r
891     pixBlock.visible_area.y1 = pixBlock.area.y1 = scaledSvgHeight;\r
892     pixBlock.rs = 4 * ((3 * (int)scaledSvgWidth + 3) / 4);\r
893     pixBlock.data.px = g_try_new (unsigned char, pixBlock.rs * scaledSvgHeight);\r
894     \r
895     // Fail if the pixblock failed to allocate\r
896     if(pixBlock.data.px == NULL)\r
897     {\r
898         sp_document_unref(svgDoc);\r
899         return false;\r
900     }\r
901     \r
902     memset(pixBlock.data.px, 0xFF, pixBlock.rs * scaledSvgHeight);\r
903     \r
904     memcpy(&root->bbox, &areaL, sizeof(areaL));\r
905             \r
906     // Render the image\r
907     nr_arena_item_invoke_render(NULL, root, &bbox, &pixBlock, /*0*/NR_ARENA_ITEM_RENDER_NO_CACHE);\r
908     \r
909     // Tidy up\r
910     sp_document_unref(svgDoc);\r
911     sp_item_invoke_hide((SPItem*)(svgDoc->root), key);\r
912     nr_arena_item_unref(root);\r
913     nr_object_unref((NRObject *) arena);\r
914     \r
915     // Create the GDK pixbuf\r
916     _mutex->lock();\r
917     \r
918     _preview_bitmap_image = Gdk::Pixbuf::create_from_data(\r
919         pixBlock.data.px, Gdk::COLORSPACE_RGB, false, 8,\r
920         (int)scaledSvgWidth, (int)scaledSvgHeight, pixBlock.rs,\r
921         sigc::ptr_fun(destroy_svg_rendering));\r
922 \r
923     _preview_document_width = scaledSvgWidth;\r
924     _preview_document_height = scaledSvgHeight;\r
925     _preview_image_width = svgWidth;\r
926     _preview_image_height = svgHeight;\r
927         \r
928     _mutex->unlock();\r
929         \r
930     return true;\r
931 }\r
932 \r
933 void FileOpenDialogImplWin32::destroy_svg_rendering(const guint8 *buffer)\r
934 {\r
935     g_assert(buffer != NULL);\r
936     g_free((void*)buffer);\r
937 }\r
938     \r
939 bool FileOpenDialogImplWin32::set_image_preview()\r
940 {\r
941     const Glib::ustring path = utf16_to_ustring(_path_string, _MAX_PATH);\r
942     \r
943     _mutex->lock();\r
944     _preview_bitmap_image = Gdk::Pixbuf::create_from_file(path);\r
945     if(!_preview_bitmap_image) return false;\r
946     \r
947     _preview_image_width = _preview_bitmap_image->get_width();\r
948     _preview_document_width = _preview_image_width;\r
949     _preview_image_height = _preview_bitmap_image->get_height();\r
950     _preview_document_height = _preview_image_height;\r
951     \r
952     _mutex->unlock();\r
953 \r
954     return true;\r
955 }\r
956 \r
957 void FileOpenDialogImplWin32::render_preview()\r
958 {\r
959     double x, y;\r
960     const double blurRadius = 8;\r
961     const double halfBlurRadius = blurRadius / 2;\r
962     const int shaddowOffsetX = 0;\r
963     const int shaddowOffsetY = 2;\r
964     const int pagePadding = 5;\r
965     const double shaddowAlpha = 0.75;\r
966     \r
967     // Is the preview showing?\r
968     if(!_show_preview)\r
969         return;\r
970     \r
971     // Do we have anything to render?\r
972     _mutex->lock();\r
973     \r
974     if(!_preview_bitmap_image)\r
975     {\r
976         _mutex->unlock();\r
977         return;\r
978     }\r
979         \r
980     // Tidy up any previous bitmap renderings\r
981     if(_preview_bitmap != NULL)\r
982         DeleteObject(_preview_bitmap);\r
983     _preview_bitmap = NULL;\r
984     \r
985     // Calculate the size of the caption\r
986     int captionHeight = 0;\r
987 \r
988     if(_preview_wnd != NULL)\r
989     {\r
990         RECT rcCaptionRect;\r
991         WCHAR szCaption[_MAX_FNAME + 32];                \r
992         const int iLength = format_caption(szCaption,\r
993             sizeof(szCaption) / sizeof(WCHAR));\r
994     \r
995         HDC dc = GetDC(_preview_wnd);\r
996         DrawTextW(dc, szCaption, iLength, &rcCaptionRect,\r
997             DT_CENTER | DT_TOP | DT_NOPREFIX | DT_PATH_ELLIPSIS | DT_CALCRECT);\r
998         ReleaseDC(_preview_wnd, dc);\r
999     \r
1000         captionHeight = rcCaptionRect.bottom - rcCaptionRect.top;\r
1001     }\r
1002     \r
1003     // Find the minimum scale to fit the image inside the preview area\r
1004     const double scaleFactorX =\r
1005         ((double)_preview_width - pagePadding * 2 - blurRadius)  / _preview_document_width;\r
1006     const double scaleFactorY =\r
1007         ((double)_preview_height - pagePadding * 2\r
1008         - shaddowOffsetY - halfBlurRadius - captionHeight) / _preview_document_height;\r
1009     double scaleFactor = (scaleFactorX > scaleFactorY) ? scaleFactorY : scaleFactorX;\r
1010     scaleFactor = (scaleFactor > 1.0) ? 1.0 : scaleFactor;    \r
1011     \r
1012     // Now get the resized values\r
1013     const double scaledSvgWidth  = scaleFactor * _preview_document_width;\r
1014     const double scaledSvgHeight = scaleFactor * _preview_document_height;\r
1015     \r
1016     const int svgX = pagePadding + halfBlurRadius;\r
1017     const int svgY = pagePadding;\r
1018     \r
1019     const int frameX = svgX - pagePadding;\r
1020     const int frameY = svgY - pagePadding;\r
1021     const int frameWidth = scaledSvgWidth + pagePadding * 2;\r
1022     const int frameHeight = scaledSvgHeight + pagePadding * 2;\r
1023     \r
1024     const int totalWidth = (int)ceil(frameWidth + blurRadius);\r
1025     const int totalHeight = (int)ceil(frameHeight + blurRadius);\r
1026     \r
1027     // Prepare the drawing surface\r
1028     HDC hDC = GetDC(_preview_wnd);\r
1029     HDC hMemDC = CreateCompatibleDC(hDC);\r
1030     _preview_bitmap = CreateCompatibleBitmap(hDC, totalWidth, totalHeight);\r
1031     HBITMAP hOldBitmap = (HBITMAP)SelectObject(hMemDC, _preview_bitmap);\r
1032     Cairo::RefPtr<Win32Surface> surface = Win32Surface::create(hMemDC);\r
1033     Cairo::RefPtr<Context> context = Context::create(surface);\r
1034 \r
1035     // Paint the background to match the dialog colour\r
1036     const COLORREF background = GetSysColor(COLOR_3DFACE);  \r
1037     context->set_source_rgb(\r
1038         GetRValue(background) / 255.0,\r
1039         GetGValue(background) / 255.0,\r
1040         GetBValue(background) / 255.0);\r
1041     context->paint();\r
1042      \r
1043     //----- Draw the drop shaddow -----//\r
1044     \r
1045     // Left Edge\r
1046     x = frameX + shaddowOffsetX - halfBlurRadius;\r
1047     Cairo::RefPtr<LinearGradient> leftEdgeFade = LinearGradient::create(\r
1048         x, 0.0, x + blurRadius, 0.0);\r
1049     leftEdgeFade->add_color_stop_rgba (0, 0, 0, 0, 0);\r
1050     leftEdgeFade->add_color_stop_rgba (1, 0, 0, 0, shaddowAlpha);\r
1051     context->set_source(leftEdgeFade);\r
1052     context->rectangle (x, frameY + shaddowOffsetY + halfBlurRadius,\r
1053         blurRadius, frameHeight - blurRadius);\r
1054     context->fill();\r
1055     \r
1056     // Right Edge\r
1057     x = frameX + frameWidth + shaddowOffsetX - halfBlurRadius;\r
1058     Cairo::RefPtr<LinearGradient> rightEdgeFade = LinearGradient::create(\r
1059         x, 0.0,    x + blurRadius, 0.0);\r
1060     rightEdgeFade->add_color_stop_rgba (0, 0, 0, 0, shaddowAlpha);\r
1061     rightEdgeFade->add_color_stop_rgba (1, 0, 0, 0, 0);\r
1062     context->set_source(rightEdgeFade);\r
1063     context->rectangle (frameX + frameWidth + shaddowOffsetX - halfBlurRadius,\r
1064         frameY + shaddowOffsetY + halfBlurRadius,\r
1065         blurRadius, frameHeight - blurRadius);\r
1066     context->fill();\r
1067         \r
1068     // Top Edge\r
1069     y = frameY + shaddowOffsetY - halfBlurRadius;\r
1070     Cairo::RefPtr<LinearGradient> topEdgeFade = LinearGradient::create(\r
1071         0.0, y, 0.0, y + blurRadius);\r
1072     topEdgeFade->add_color_stop_rgba (0, 0, 0, 0, 0);\r
1073     topEdgeFade->add_color_stop_rgba (1, 0, 0, 0, shaddowAlpha);\r
1074     context->set_source(topEdgeFade);\r
1075     context->rectangle (frameX + shaddowOffsetX + halfBlurRadius, y,\r
1076         frameWidth - blurRadius, blurRadius);\r
1077     context->fill();\r
1078     \r
1079     // Bottom Edge\r
1080     y = frameY + frameHeight + shaddowOffsetY - halfBlurRadius;\r
1081     Cairo::RefPtr<LinearGradient> bottomEdgeFade = LinearGradient::create(\r
1082         0.0, y,    0.0, y + blurRadius);\r
1083     bottomEdgeFade->add_color_stop_rgba (0, 0, 0, 0, shaddowAlpha);\r
1084     bottomEdgeFade->add_color_stop_rgba (1, 0, 0, 0, 0);\r
1085     context->set_source(bottomEdgeFade);\r
1086     context->rectangle (frameX + shaddowOffsetX + halfBlurRadius, y,\r
1087         frameWidth - blurRadius, blurRadius);\r
1088     context->fill();\r
1089     \r
1090     // Top Left Corner\r
1091     x = frameX + shaddowOffsetX - halfBlurRadius;\r
1092     y = frameY + shaddowOffsetY - halfBlurRadius;\r
1093     Cairo::RefPtr<RadialGradient> topLeftCornerFade = RadialGradient::create(\r
1094         x + blurRadius, y + blurRadius, 0, x + blurRadius, y + blurRadius, blurRadius);\r
1095     topLeftCornerFade->add_color_stop_rgba (0, 0, 0, 0, shaddowAlpha);\r
1096     topLeftCornerFade->add_color_stop_rgba (1, 0, 0, 0, 0);\r
1097     context->set_source(topLeftCornerFade);\r
1098     context->rectangle (x, y, blurRadius, blurRadius);\r
1099     context->fill();\r
1100     \r
1101     // Top Right Corner\r
1102     x = frameX + frameWidth + shaddowOffsetX - halfBlurRadius;\r
1103     y = frameY + shaddowOffsetY - halfBlurRadius;\r
1104     Cairo::RefPtr<RadialGradient> topRightCornerFade = RadialGradient::create(\r
1105         x, y + blurRadius, 0, x, y + blurRadius, blurRadius);\r
1106     topRightCornerFade->add_color_stop_rgba (0, 0, 0, 0, shaddowAlpha);\r
1107     topRightCornerFade->add_color_stop_rgba (1, 0, 0, 0, 0);\r
1108     context->set_source(topRightCornerFade);\r
1109     context->rectangle (x, y, blurRadius, blurRadius);\r
1110     context->fill();\r
1111     \r
1112     // Bottom Left Corner\r
1113     x = frameX + shaddowOffsetX - halfBlurRadius;\r
1114     y = frameY + frameHeight + shaddowOffsetY - halfBlurRadius;\r
1115     Cairo::RefPtr<RadialGradient> bottomLeftCornerFade = RadialGradient::create(\r
1116         x + blurRadius, y, 0, x + blurRadius, y, blurRadius);\r
1117     bottomLeftCornerFade->add_color_stop_rgba (0, 0, 0, 0, shaddowAlpha);\r
1118     bottomLeftCornerFade->add_color_stop_rgba (1, 0, 0, 0, 0);\r
1119     context->set_source(bottomLeftCornerFade);\r
1120     context->rectangle (x, y, blurRadius, blurRadius);\r
1121     context->fill();\r
1122     \r
1123     // Bottom Right Corner\r
1124     x = frameX + frameWidth + shaddowOffsetX - halfBlurRadius;\r
1125     y = frameY + frameHeight + shaddowOffsetY - halfBlurRadius;\r
1126     Cairo::RefPtr<RadialGradient> bottomRightCornerFade = RadialGradient::create(\r
1127         x, y, 0, x, y, blurRadius);\r
1128     bottomRightCornerFade->add_color_stop_rgba (0, 0, 0, 0, shaddowAlpha);\r
1129     bottomRightCornerFade->add_color_stop_rgba (1, 0, 0, 0, 0);\r
1130     context->set_source(bottomRightCornerFade);\r
1131     context->rectangle (frameX + frameWidth + shaddowOffsetX - halfBlurRadius,\r
1132         frameY + frameHeight + shaddowOffsetY - halfBlurRadius,\r
1133         blurRadius, blurRadius);\r
1134     context->fill();\r
1135     \r
1136     // Draw the frame\r
1137     context->set_line_width(1);\r
1138     context->rectangle (frameX, frameY,    frameWidth, frameHeight);\r
1139     \r
1140     context->set_source_rgb(1.0, 1.0, 1.0);\r
1141     context->fill_preserve();\r
1142     context->set_source_rgb(0.25, 0.25, 0.25);\r
1143     context->stroke_preserve();\r
1144     \r
1145     // Draw the image\r
1146     \r
1147     if(_preview_bitmap_image)    // Is the image a pixbuf?\r
1148     {\r
1149         // Set the transformation\r
1150         const Matrix matrix = {\r
1151             scaleFactor, 0,\r
1152             0, scaleFactor,\r
1153             svgX, svgY };\r
1154         context->set_matrix (matrix);\r
1155     \r
1156         // Render the image\r
1157         set_source_pixbuf (context, _preview_bitmap_image, 0, 0);\r
1158         context->paint();\r
1159         \r
1160         // Reset the transformation\r
1161         context->set_identity_matrix();\r
1162     }\r
1163     \r
1164     // Draw the inner frame\r
1165     context->set_source_rgb(0.75, 0.75, 0.75);\r
1166     context->rectangle (svgX, svgY,    scaledSvgWidth, scaledSvgHeight);\r
1167     context->stroke();\r
1168     \r
1169     _mutex->unlock();\r
1170 \r
1171     // Finish drawing\r
1172     surface->finish();\r
1173     SelectObject(hMemDC, hOldBitmap) ;\r
1174     DeleteDC(hMemDC);\r
1175     \r
1176     // Refresh the preview pane\r
1177     InvalidateRect(_preview_wnd, NULL, FALSE);\r
1178 }\r
1179 \r
1180 int FileOpenDialogImplWin32::format_caption(wchar_t *caption, int caption_size)\r
1181 {\r
1182     wchar_t szFileName[_MAX_FNAME];\r
1183     _wsplitpath(_path_string, NULL, NULL, szFileName, NULL);\r
1184                 \r
1185     return snwprintf(caption, caption_size,\r
1186         L"%s\n%d kB\n%d \xD7 %d", szFileName, _preview_file_size,\r
1187         (int)_preview_document_width, (int)_preview_document_height);\r
1188 }\r
1189 \r
1190 /**\r
1191  * Show this dialog modally.  Return true if user hits [OK]\r
1192  */\r
1193 bool\r
1194 FileOpenDialogImplWin32::show()\r
1195 {\r
1196     // We can only run one worker thread at a time\r
1197     //if(_mutex != NULL) return false;\r
1198     \r
1199     if(!Glib::thread_supported())\r
1200         Glib::thread_init();\r
1201     \r
1202     _result = false;\r
1203     _finished = false;\r
1204     _file_selected = false;\r
1205     _mutex = new Glib::Mutex();\r
1206     _main_loop = g_main_loop_new(g_main_context_default(), FALSE);\r
1207     \r
1208     if(Glib::Thread::create(sigc::mem_fun(*this, &FileOpenDialogImplWin32::GetOpenFileName_thread), true))\r
1209     {\r
1210         while(1)\r
1211         {\r
1212             g_main_context_iteration(g_main_context_default(), FALSE);\r
1213             \r
1214             if(_mutex->trylock())\r
1215             {\r
1216                 // Read mutexed data\r
1217                 const bool finished = _finished;\r
1218                 const bool is_file_selected = _file_selected;\r
1219                 _file_selected = false;\r
1220                 _mutex->unlock();\r
1221                 \r
1222                 if(finished) break;\r
1223                 if(is_file_selected) file_selected();\r
1224             }\r
1225             \r
1226             Sleep(10);\r
1227         }\r
1228         //g_main_loop_run(_main_loop);\r
1229     }\r
1230     \r
1231     // Tidy up    \r
1232     delete _mutex;\r
1233     _mutex = NULL;\r
1234         \r
1235     return _result;\r
1236 }\r
1237 \r
1238 /**\r
1239  * To Get Multiple filenames selected at-once.\r
1240  */\r
1241 std::vector<Glib::ustring>FileOpenDialogImplWin32::getFilenames()\r
1242 {\r
1243     std::vector<Glib::ustring> result;\r
1244     result.push_back(getFilename());\r
1245     return result;\r
1246 }\r
1247 \r
1248 \r
1249 /*#########################################################################\r
1250 ### F I L E    S A V E\r
1251 #########################################################################*/\r
1252 \r
1253 /**\r
1254  * Constructor\r
1255  */\r
1256 FileSaveDialogImplWin32::FileSaveDialogImplWin32(Gtk::Window &parent, \r
1257             const Glib::ustring &dir,\r
1258             FileDialogType fileTypes,\r
1259             const char *title,\r
1260             const Glib::ustring &/*default_key*/) :\r
1261     FileDialogBaseWin32(parent, dir, title, fileTypes, "dialogs.save_as")\r
1262 {\r
1263     _main_loop = NULL;\r
1264 \r
1265     createFilterMenu();\r
1266 }\r
1267 \r
1268 FileSaveDialogImplWin32::~FileSaveDialogImplWin32()\r
1269 {\r
1270 }\r
1271 \r
1272 void FileSaveDialogImplWin32::createFilterMenu()\r
1273 {\r
1274     list<Filter> filter_list;\r
1275 \r
1276     knownExtensions.clear();\r
1277 \r
1278     // Compose the filter string\r
1279     Glib::ustring all_inkscape_files_filter, all_image_files_filter;\r
1280     Inkscape::Extension::DB::OutputList extension_list;\r
1281     Inkscape::Extension::db.get_output_list(extension_list);\r
1282 \r
1283     int filter_count = 0;\r
1284     int filter_length = 0;\r
1285             \r
1286     for (Inkscape::Extension::DB::OutputList::iterator current_item = extension_list.begin();\r
1287          current_item != extension_list.end(); current_item++)\r
1288     {\r
1289         Inkscape::Extension::Output *omod = *current_item;\r
1290         if (omod->deactivated()) continue;\r
1291         \r
1292         filter_count++;\r
1293         \r
1294         Filter filter;\r
1295         \r
1296         // Extension\r
1297         const gchar *filter_extension = omod->get_extension();      \r
1298         filter.filter = g_utf8_to_utf16(\r
1299             filter_extension, -1, NULL, &filter.filter_length, NULL);    \r
1300         knownExtensions.insert( Glib::ustring(filter_extension).casefold() );\r
1301         \r
1302         // Type\r
1303         filter.name = g_utf8_to_utf16(\r
1304             omod->get_filetypename(), -1, NULL, &filter.name_length, NULL);\r
1305             \r
1306         filter.mod = omod;\r
1307                         \r
1308         filter_length += filter.name_length +\r
1309             filter.filter_length + 3;   // Add 3 for two \0s and a *\r
1310             \r
1311         filter_list.push_back(filter);\r
1312     }\r
1313      \r
1314     int extension_index = 0;\r
1315     _extension_map = new Inkscape::Extension::Extension*[filter_count];\r
1316     \r
1317     _filter = new wchar_t[filter_length];\r
1318     wchar_t *filterptr = _filter;\r
1319     \r
1320     for(list<Filter>::iterator filter_iterator = filter_list.begin();\r
1321         filter_iterator != filter_list.end(); filter_iterator++)\r
1322     {\r
1323         const Filter &filter = *filter_iterator;\r
1324     \r
1325         memcpy(filterptr, filter.name, filter.name_length * 2);\r
1326         filterptr += filter.name_length;\r
1327         g_free(filter.name);\r
1328     \r
1329         *(filterptr++) = L'\0';\r
1330         *(filterptr++) = L'*';\r
1331 \r
1332         memcpy(filterptr, filter.filter, filter.filter_length * 2);\r
1333         filterptr += filter.filter_length;\r
1334         g_free(filter.filter);\r
1335     \r
1336         *(filterptr++) = L'\0';\r
1337         \r
1338         // Associate this input extension with the file type name\r
1339         _extension_map[extension_index++] = filter.mod;\r
1340     }\r
1341     *(filterptr++) = 0;\r
1342     \r
1343     _filterIndex = 0;\r
1344 }\r
1345 \r
1346 void FileSaveDialogImplWin32::GetSaveFileName_thread()\r
1347 {\r
1348     OPENFILENAMEEXW ofn;\r
1349     \r
1350     g_assert(this != NULL);\r
1351     //g_assert(_mutex != NULL);\r
1352     g_assert(_main_loop != NULL);    \r
1353 \r
1354     gunichar2* current_directory_string = g_utf8_to_utf16(\r
1355         _current_directory.data(), -1, NULL, NULL, NULL);\r
1356     \r
1357     // Copy the selected file name, converting from UTF-8 to UTF-16\r
1358     memset(_path_string, 0, sizeof(_path_string));\r
1359     gunichar2* utf16_path_string = g_utf8_to_utf16(\r
1360         myFilename.data(), -1, NULL, NULL, NULL);\r
1361     wcsncpy(_path_string, (wchar_t*)utf16_path_string, _MAX_PATH);\r
1362     g_free(utf16_path_string);\r
1363     \r
1364     ZeroMemory(&ofn, sizeof(ofn));\r
1365     ofn.lStructSize = sizeof(ofn);\r
1366     ofn.hwndOwner = _ownerHwnd;\r
1367     ofn.lpstrFile = _path_string;\r
1368     ofn.nMaxFile = _MAX_PATH;\r
1369     ofn.nFilterIndex = _filterIndex;\r
1370     ofn.lpstrFileTitle = NULL;\r
1371     ofn.nMaxFileTitle = 0;\r
1372     ofn.lpstrInitialDir = (wchar_t*)current_directory_string;\r
1373     ofn.lpstrTitle = _title;\r
1374     ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST;\r
1375     ofn.lpstrFilter = _filter;\r
1376     ofn.nFilterIndex = _filterIndex;\r
1377     \r
1378     _result = GetSaveFileNameW(&ofn) != 0;\r
1379     \r
1380     _filterIndex = ofn.nFilterIndex;\r
1381     _extension = _extension_map[ofn.nFilterIndex];\r
1382     \r
1383     // Copy the selected file name, converting from UTF-16 to UTF-8\r
1384     myFilename = utf16_to_ustring(_path_string, _MAX_PATH);\r
1385         \r
1386     //_mutex->lock();\r
1387     //_finished = true;\r
1388     //_mutex->unlock();\r
1389     \r
1390     \r
1391     // Tidy up\r
1392     g_free(current_directory_string);\r
1393     \r
1394     g_main_loop_quit(_main_loop);\r
1395 }\r
1396 \r
1397 /**\r
1398  * Show this dialog modally.  Return true if user hits [OK]\r
1399  */\r
1400 bool\r
1401 FileSaveDialogImplWin32::show()\r
1402 {\r
1403     // We can only run one worker thread at a time\r
1404     //if(_mutex != NULL) return false;\r
1405 \r
1406     if(!Glib::thread_supported())\r
1407         Glib::thread_init();\r
1408         \r
1409     _result = false;\r
1410     //_finished = false;\r
1411     //_mutex = new Glib::Mutex();\r
1412     _main_loop = g_main_loop_new(g_main_context_default(), FALSE);\r
1413     \r
1414     if(Glib::Thread::create(sigc::mem_fun(*this, &FileSaveDialogImplWin32::GetSaveFileName_thread), true))\r
1415     {\r
1416         /*while(1)\r
1417         {\r
1418             // While the dialog runs - keep the main UI alive\r
1419             g_main_context_iteration(g_main_context_default(), FALSE);\r
1420             \r
1421             if(_mutex->trylock())\r
1422             {\r
1423                 if(_finished) break;\r
1424                 _mutex->unlock();\r
1425             }\r
1426             \r
1427             Sleep(10);\r
1428         }*/\r
1429         g_main_loop_run(_main_loop);\r
1430     }\r
1431     //delete _mutex;\r
1432     //_mutex = NULL;\r
1433         \r
1434     if(_result)\r
1435         appendExtension(myFilename, (Inkscape::Extension::Output*)_extension);\r
1436         \r
1437     return _result;   \r
1438 }\r
1439 \r
1440 void FileSaveDialogImplWin32::setSelectionType( Inkscape::Extension::Extension * /*key*/ )\r
1441 {\r
1442     // If no pointer to extension is passed in, look up based on filename extension.\r
1443     \r
1444 }\r
1445 \r
1446 }\r
1447 }\r
1448 }\r
1449 \r
1450 #endif\r
1451 \r
1452 /*\r
1453   Local Variables:\r
1454   mode:c++\r
1455   c-file-style:"stroustrup"\r
1456   c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))\r
1457   indent-tabs-mode:nil\r
1458   fill-column:99\r
1459   End:\r
1460 */\r
1461 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :\r