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