X-Git-Url: https://git.tokkee.org/?a=blobdiff_plain;f=src%2Fui%2Fdialog%2Ffiledialogimpl-win32.cpp;h=5b2acc1decbb591df29425d49782d61812fd8e95;hb=604bbc96a26ec5381cc865aa1458b115e41201ce;hp=361df293f90c300794f4746138aaf8d2c3332fe5;hpb=3955580a5a68a873b098921626f5b9d841b964ec;p=inkscape.git diff --git a/src/ui/dialog/filedialogimpl-win32.cpp b/src/ui/dialog/filedialogimpl-win32.cpp index 361df293f..5b2acc1de 100644 --- a/src/ui/dialog/filedialogimpl-win32.cpp +++ b/src/ui/dialog/filedialogimpl-win32.cpp @@ -1,7 +1,7 @@ -/** - * Implementation of the file dialog interfaces defined in filedialog.h for Win32 - * - * Authors: +/** @file + * @brief Implementation of native file dialogs for Win32 + */ +/* Authors: * Joel Holdsworth * The Inkscape Organization * @@ -9,13 +9,12 @@ * * Released under GNU GPL, read the file 'COPYING' for more information */ +#ifdef WIN32 #ifdef HAVE_CONFIG_H # include #endif -#ifdef WIN32 - //General includes #include #include @@ -29,7 +28,6 @@ //Inkscape includes #include "inkscape.h" -#include "prefs-utils.h" #include #include #include @@ -40,7 +38,7 @@ #include #include #include "sp-item.h" -#include "canvas-arena.h" +#include "display/canvas-arena.h" #include "filedialog.h" #include "filedialogimpl-win32.h" @@ -108,7 +106,7 @@ FileDialogBaseWin32::FileDialogBaseWin32(Gtk::Window &parent, _filter_index = 1; _filter_count = 0; - + _title = (wchar_t*)g_utf8_to_utf16(title, -1, NULL, NULL, NULL); g_assert(_title != NULL); @@ -165,7 +163,8 @@ FileOpenDialogImplWin32::FileOpenDialogImplWin32(Gtk::Window &parent, _preview_document_height = 0; _preview_image_width = 0; _preview_image_height = 0; - + _preview_emf_image = false; + _mutex = NULL; createFilterMenu(); @@ -273,10 +272,10 @@ void FileOpenDialogImplWin32::createFilterMenu() all_image_files.filter_length + all_image_files.name_length + 3 + 1; // Add 3 for 2*2 \0s and a *, and 1 for a trailing \0 - + _filter = new wchar_t[filter_length]; wchar_t *filterptr = _filter; - + for(list::iterator filter_iterator = filter_list.begin(); filter_iterator != filter_list.end(); filter_iterator++) { @@ -302,7 +301,7 @@ void FileOpenDialogImplWin32::createFilterMenu() _extension_map[extension_index++] = filter.mod; } *(filterptr++) = L'\0'; - + _filter_count = extension_index; _filter_index = 2; // Select the 2nd filter in the list - 2 is NOT the 3rd } @@ -313,7 +312,7 @@ void FileOpenDialogImplWin32::GetOpenFileName_thread() g_assert(this != NULL); g_assert(_mutex != NULL); - + WCHAR* current_directory_string = (WCHAR*)g_utf8_to_utf16( _current_directory.data(), _current_directory.length(), NULL, NULL, NULL); @@ -790,6 +789,8 @@ void FileOpenDialogImplWin32::load_preview() // Prepare to render a preview const Glib::ustring svg = ".svg"; const Glib::ustring svgz = ".svgz"; + const Glib::ustring emf = ".emf"; + const Glib::ustring wmf = ".wmf"; const Glib::ustring path = utf16_to_ustring(_path_string); bool success = false; @@ -799,6 +800,8 @@ void FileOpenDialogImplWin32::load_preview() if ((dialogType == SVG_TYPES || dialogType == IMPORT_TYPES) && (hasSuffix(path, svg) || hasSuffix(path, svgz))) success = set_svg_preview(); + else if (hasSuffix(path, emf) || hasSuffix(path, wmf)) + success = set_emf_preview(); else if (isValidImageFile(path)) success = set_image_preview(); else { @@ -822,6 +825,7 @@ void FileOpenDialogImplWin32::free_preview() _preview_file_icon = NULL; _preview_bitmap_image.clear(); + _preview_emf_image = false; _mutex->unlock(); } @@ -855,15 +859,15 @@ bool FileOpenDialogImplWin32::set_svg_preview() const double scaledSvgWidth = scaleFactor * svgWidth; const double scaledSvgHeight = scaleFactor * svgHeight; - NR::Rect area(NR::Point(0, 0), NR::Point(scaledSvgWidth, scaledSvgHeight)); + Geom::Rect area(Geom::Point(0, 0), Geom::Point(scaledSvgWidth, scaledSvgHeight)); NRRectL areaL = {0, 0, scaledSvgWidth, scaledSvgHeight}; NRRectL bbox = {0, 0, scaledSvgWidth, scaledSvgHeight}; // write object bbox to area - NR::Maybe maybeArea(area); + Geom::OptRect maybeArea(area); sp_document_ensure_up_to_date (svgDoc); - sp_item_invoke_bbox((SPItem *) svgDoc->root, &maybeArea, - sp_item_i2r_affine((SPItem *)(svgDoc->root)), TRUE); + sp_item_invoke_bbox((SPItem *) svgDoc->root, maybeArea, + sp_item_i2d_affine((SPItem *)(svgDoc->root)), TRUE); NRArena *const arena = NRArena::create(); @@ -873,7 +877,7 @@ bool FileOpenDialogImplWin32::set_svg_preview() arena, key, SP_ITEM_SHOW_DISPLAY); NRGC gc(NULL); - gc.transform = NR::Matrix(NR::scale(scaleFactor, scaleFactor)); + gc.transform = Geom::Matrix(Geom::Scale(scaleFactor, scaleFactor)); nr_arena_item_invoke_update (root, NULL, &gc, NR_ARENA_ITEM_STATE_ALL, NR_ARENA_ITEM_STATE_NONE); @@ -907,7 +911,6 @@ bool FileOpenDialogImplWin32::set_svg_preview() // Tidy up sp_document_unref(svgDoc); sp_item_invoke_hide((SPItem*)(svgDoc->root), key); - nr_arena_item_unref(root); nr_object_unref((NRObject *) arena); // Create the GDK pixbuf @@ -938,18 +941,192 @@ bool FileOpenDialogImplWin32::set_image_preview() { const Glib::ustring path = utf16_to_ustring(_path_string, _MAX_PATH); + bool successful = false; + _mutex->lock(); - _preview_bitmap_image = Gdk::Pixbuf::create_from_file(path); - if(!_preview_bitmap_image) return false; - _preview_image_width = _preview_bitmap_image->get_width(); - _preview_document_width = _preview_image_width; - _preview_image_height = _preview_bitmap_image->get_height(); - _preview_document_height = _preview_image_height; + try { + _preview_bitmap_image = Gdk::Pixbuf::create_from_file(path); + if (_preview_bitmap_image) { + _preview_image_width = _preview_bitmap_image->get_width(); + _preview_document_width = _preview_image_width; + _preview_image_height = _preview_bitmap_image->get_height(); + _preview_document_height = _preview_image_height; + successful = true; + } + } + catch (const Gdk::PixbufError&) {} + catch (const Glib::FileError&) {} _mutex->unlock(); - return true; + return successful; +} + +// Aldus Placeable Header =================================================== +// Since we are a 32bit app, we have to be sure this structure compiles to +// be identical to a 16 bit app's version. To do this, we use the #pragma +// to adjust packing, we use a WORD for the hmf handle, and a SMALL_RECT +// for the bbox rectangle. +#pragma pack( push ) +#pragma pack( 2 ) +typedef struct +{ + DWORD dwKey; + WORD hmf; + SMALL_RECT bbox; + WORD wInch; + DWORD dwReserved; + WORD wCheckSum; +} APMHEADER, *PAPMHEADER; +#pragma pack( pop ) + + +static HENHMETAFILE +MyGetEnhMetaFileW( const WCHAR *filename ) +{ + // Try open as Enhanced Metafile + HENHMETAFILE hemf = GetEnhMetaFileW(filename); + + if (!hemf) { + // Try open as Windows Metafile + HMETAFILE hmf = GetMetaFileW(filename); + + METAFILEPICT mp; + HDC hDC; + + if (!hmf) { + WCHAR szTemp[MAX_PATH]; + + DWORD dw = GetShortPathNameW( filename, szTemp, MAX_PATH ); + if (dw) { + hmf = GetMetaFileW( szTemp ); + } + } + + if (hmf) { + // Convert Windows Metafile to Enhanced Metafile + DWORD nSize = GetMetaFileBitsEx( hmf, 0, NULL ); + + if (nSize) { + BYTE *lpvData = new BYTE[nSize]; + if (lpvData) { + DWORD dw = GetMetaFileBitsEx( hmf, nSize, lpvData ); + if (dw) { + // Fill out a METAFILEPICT structure + mp.mm = MM_ANISOTROPIC; + mp.xExt = 1000; + mp.yExt = 1000; + mp.hMF = NULL; + // Get a reference DC + hDC = GetDC( NULL ); + // Make an enhanced metafile from the windows metafile + hemf = SetWinMetaFileBits( nSize, lpvData, hDC, &mp ); + // Clean up + ReleaseDC( NULL, hDC ); + DeleteMetaFile( hmf ); + } + delete[] lpvData; + } + else { + DeleteMetaFile( hmf ); + } + } + else { + DeleteMetaFile( hmf ); + } + } + else { + // Try open as Aldus Placeable Metafile + HANDLE hFile; + hFile = CreateFileW( filename, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL ); + + if (hFile != INVALID_HANDLE_VALUE) { + DWORD nSize = GetFileSize( hFile, NULL ); + if (nSize) { + BYTE *lpvData = new BYTE[nSize]; + if (lpvData) { + DWORD dw = ReadFile( hFile, lpvData, nSize, &nSize, NULL ); + if (dw) { + if ( ((PAPMHEADER)lpvData)->dwKey == 0x9ac6cdd7l ) { + // Fill out a METAFILEPICT structure + mp.mm = MM_ANISOTROPIC; + mp.xExt = ((PAPMHEADER)lpvData)->bbox.Right - ((PAPMHEADER)lpvData)->bbox.Left; + mp.xExt = ( mp.xExt * 2540l ) / (DWORD)(((PAPMHEADER)lpvData)->wInch); + mp.yExt = ((PAPMHEADER)lpvData)->bbox.Bottom - ((PAPMHEADER)lpvData)->bbox.Top; + mp.yExt = ( mp.yExt * 2540l ) / (DWORD)(((PAPMHEADER)lpvData)->wInch); + mp.hMF = NULL; + // Get a reference DC + hDC = GetDC( NULL ); + // Create an enhanced metafile from the bits + hemf = SetWinMetaFileBits( nSize, lpvData+sizeof(APMHEADER), hDC, &mp ); + // Clean up + ReleaseDC( NULL, hDC ); + } + } + delete[] lpvData; + } + } + CloseHandle( hFile ); + } + } + } + + return hemf; +} + + +bool FileOpenDialogImplWin32::set_emf_preview() +{ + _mutex->lock(); + + BOOL ok = FALSE; + + DWORD w = 0; + DWORD h = 0; + + HENHMETAFILE hemf = MyGetEnhMetaFileW( _path_string ); + + if (hemf) + { + ENHMETAHEADER emh; + ZeroMemory(&emh, sizeof(emh)); + ok = GetEnhMetaFileHeader(hemf, sizeof(emh), &emh) != 0; + + w = (emh.rclFrame.right - emh.rclFrame.left); + h = (emh.rclFrame.bottom - emh.rclFrame.top); + + DeleteEnhMetaFile(hemf); + } + + if (ok) + { + const int PreviewSize = 512; + + // Get the size of the document + const double emfWidth = w; + const double emfHeight = h; + + // Find the minimum scale to fit the image inside the preview area + const double scaleFactorX = PreviewSize / emfWidth; + const double scaleFactorY = PreviewSize / emfHeight; + const double scaleFactor = (scaleFactorX > scaleFactorY) ? scaleFactorY : scaleFactorX; + + // Now get the resized values + const double scaledEmfWidth = scaleFactor * emfWidth; + const double scaledEmfHeight = scaleFactor * emfHeight; + + _preview_document_width = scaledEmfWidth; + _preview_document_height = scaledEmfHeight; + _preview_image_width = emfWidth; + _preview_image_height = emfHeight; + + _preview_emf_image = true; + } + + _mutex->unlock(); + + return ok; } void FileOpenDialogImplWin32::render_preview() @@ -969,7 +1146,7 @@ void FileOpenDialogImplWin32::render_preview() // Do we have anything to render? _mutex->lock(); - if(!_preview_bitmap_image) + if(!_preview_bitmap_image && !_preview_emf_image) { _mutex->unlock(); return; @@ -1167,6 +1344,20 @@ void FileOpenDialogImplWin32::render_preview() // Finish drawing surface->finish(); + + if (_preview_emf_image) { + HENHMETAFILE hemf = MyGetEnhMetaFileW(_path_string); + if (hemf) { + RECT rc; + rc.top = svgY+2; + rc.left = svgX+2; + rc.bottom = scaledSvgHeight-2; + rc.right = scaledSvgWidth-2; + PlayEnhMetaFile(hMemDC, hemf, &rc); + DeleteEnhMetaFile(hemf); + } + } + SelectObject(hMemDC, hOldBitmap) ; DeleteDC(hMemDC); @@ -1253,9 +1444,13 @@ FileSaveDialogImplWin32::FileSaveDialogImplWin32(Gtk::Window &parent, const Glib::ustring &dir, FileDialogType fileTypes, const char *title, - const Glib::ustring &/*default_key*/) : - FileDialogBaseWin32(parent, dir, title, fileTypes, "dialogs.save_as") + const Glib::ustring &/*default_key*/, + const char *docTitle) : + FileDialogBaseWin32(parent, dir, title, fileTypes, "dialogs.save_as"), + _title_label(NULL), + _title_edit(NULL) { + FileSaveDialog::myDocTitle = docTitle; createFilterMenu(); } @@ -1366,9 +1561,11 @@ void FileSaveDialogImplWin32::GetSaveFileName_thread() ofn.nMaxFileTitle = 0; ofn.lpstrInitialDir = current_directory_string; ofn.lpstrTitle = _title; - ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST; + ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST | OFN_EXPLORER | OFN_ENABLEHOOK; ofn.lpstrFilter = _filter; ofn.nFilterIndex = _filter_index; + ofn.lpfnHook = GetSaveFileName_hookproc; + ofn.lCustData = (LPARAM)this; _result = GetSaveFileNameW(&ofn) != 0; @@ -1396,7 +1593,7 @@ FileSaveDialogImplWin32::show() _result = false; _main_loop = g_main_loop_new(g_main_context_default(), FALSE); - + if(_main_loop != NULL) { if(Glib::Thread::create(sigc::mem_fun(*this, &FileSaveDialogImplWin32::GetSaveFileName_thread), true)) @@ -1405,7 +1602,7 @@ FileSaveDialogImplWin32::show() if(_result) appendExtension(myFilename, (Inkscape::Extension::Output*)_extension); } - + return _result; } @@ -1415,11 +1612,90 @@ void FileSaveDialogImplWin32::setSelectionType( Inkscape::Extension::Extension * } -} -} +UINT_PTR CALLBACK FileSaveDialogImplWin32::GetSaveFileName_hookproc( + HWND hdlg, UINT uiMsg, WPARAM, LPARAM lParam) +{ + FileSaveDialogImplWin32 *pImpl = (FileSaveDialogImplWin32*) + GetWindowLongPtr(hdlg, GWLP_USERDATA); + + switch(uiMsg) + { + case WM_INITDIALOG: + { + HWND hParentWnd = GetParent(hdlg); + HINSTANCE hInstance = GetModuleHandle(NULL); + + // get size/pos of typical combo box + RECT rEDT1, rCB1, rROOT, rST; + GetWindowRect(GetDlgItem(hParentWnd, cmb1), &rCB1); + GetWindowRect(GetDlgItem(hParentWnd, cmb13), &rEDT1); + GetWindowRect(GetDlgItem(hParentWnd, stc2), &rST); + GetWindowRect(hdlg, &rROOT); + int ydelta = rCB1.top - rEDT1.top; + + // Make the window a bit longer + RECT rcRect; + GetWindowRect(hParentWnd, &rcRect); + MoveWindow(hParentWnd, rcRect.left, rcRect.top, rcRect.right - rcRect.left, + rcRect.bottom - rcRect.top + ydelta, FALSE); + + // It is not necessary to delete stock objects by calling DeleteObject + HGDIOBJ dlgFont = GetStockObject(DEFAULT_GUI_FONT); + + // Set the pointer to the object + OPENFILENAMEW *ofn = (OPENFILENAMEW*)lParam; + SetWindowLongPtr(hdlg, GWLP_USERDATA, ofn->lCustData); + SetWindowLongPtr(hParentWnd, GWLP_USERDATA, ofn->lCustData); + pImpl = (FileSaveDialogImplWin32*)ofn->lCustData; + + // Create the Title label and edit control + pImpl->_title_label = CreateWindowEx(NULL, "STATIC", "Title:", + WS_VISIBLE|WS_CHILD, + CW_USEDEFAULT, CW_USEDEFAULT, rCB1.left-rST.left, rST.bottom-rST.top, + hParentWnd, NULL, hInstance, NULL); + if(pImpl->_title_label) { + if(dlgFont) SendMessage(pImpl->_title_label, WM_SETFONT, (WPARAM)dlgFont, MAKELPARAM(FALSE, 0)); + SetWindowPos(pImpl->_title_label, NULL, rST.left-rROOT.left, rST.top+ydelta-rROOT.top, + rCB1.left-rST.left, rST.bottom-rST.top, SWP_SHOWWINDOW|SWP_NOZORDER); + } + + pImpl->_title_edit = CreateWindowEx(WS_EX_CLIENTEDGE, "EDIT", "", + WS_VISIBLE|WS_CHILD|WS_TABSTOP|ES_AUTOHSCROLL, + CW_USEDEFAULT, CW_USEDEFAULT, rCB1.right-rCB1.left, rCB1.bottom-rCB1.top, + hParentWnd, NULL, hInstance, NULL); + if(pImpl->_title_edit) { + if(dlgFont) SendMessage(pImpl->_title_edit, WM_SETFONT, (WPARAM)dlgFont, MAKELPARAM(FALSE, 0)); + SetWindowPos(pImpl->_title_edit, NULL, rCB1.left-rROOT.left, rCB1.top+ydelta-rROOT.top, + rCB1.right-rCB1.left, rCB1.bottom-rCB1.top, SWP_SHOWWINDOW|SWP_NOZORDER); + // TODO: make sure this works for Unicode + SetWindowText(pImpl->_title_edit, pImpl->myDocTitle.c_str()); + } + } + break; + case WM_DESTROY: + { + if(pImpl->_title_edit) { + int length = GetWindowTextLength(pImpl->_title_edit)+1; + char* temp_title = new char[length]; + GetWindowText(pImpl->_title_edit, temp_title, length); + pImpl->myDocTitle = temp_title; + delete[] temp_title; + DestroyWindow(pImpl->_title_label); + pImpl->_title_label = NULL; + DestroyWindow(pImpl->_title_edit); + pImpl->_title_edit = NULL; + } + } + break; + } + + // Use default dialog behaviour + return 0; } -#endif +} } } // namespace Dialog, UI, Inkscape + +#endif // ifdef WIN32 /* Local Variables: @@ -1430,4 +1706,4 @@ void FileSaveDialogImplWin32::setSelectionType( Inkscape::Extension::Extension * fill-column:99 End: */ -// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 : +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :