index 280fc52a6e1f3a0cb8507ef0d5d817a38e0e15b8..2196ef0de4091acde803385591acc35def231f8e 100644 (file)
-/**
- * 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
*
*
* Released under GNU GPL, read the file 'COPYING' for more information
*/
+#ifdef WIN32
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
-#ifdef WIN32
-
//General includes
#include <list>
#include <unistd.h>
//Inkscape includes
#include "inkscape.h"
-#include "prefs-utils.h"
#include <dialogs/dialog-events.h>
#include <extension/input.h>
#include <extension/output.h>
#include <display/nr-arena-item.h>
#include <display/nr-arena.h>
#include "sp-item.h"
-#include "canvas-arena.h"
+#include "display/canvas-arena.h"
#include "filedialog.h"
#include "filedialogimpl-win32.h"
_filter_index = 1;
_filter_count = 0;
-
+
_title = (wchar_t*)g_utf8_to_utf16(title, -1, NULL, NULL, NULL);
g_assert(_title != NULL);
_preview_document_height = 0;
_preview_image_width = 0;
_preview_image_height = 0;
-
+ _preview_emf_image = false;
+
_mutex = NULL;
createFilterMenu();
Inkscape::Extension::DB::InputList extension_list;
Inkscape::Extension::db.get_input_list(extension_list);
- ustring all_inkscape_files_filter, all_image_files_filter;
- Filter all_files, all_inkscape_files, all_image_files;
+ ustring all_inkscape_files_filter, all_image_files_filter, all_vectors_filter, all_bitmaps_filter;
+ Filter all_files, all_inkscape_files, all_image_files, all_vectors, all_bitmaps;
const gchar *all_files_filter_name = N_("All Files");
const gchar *all_inkscape_files_filter_name = N_("All Inkscape Files");
- const gchar *all_image_files_filter_name = N_("All Image Files");
+ const gchar *all_image_files_filter_name = N_("All Images");
+ const gchar *all_vectors_filter_name = N_("All Vectors");
+ const gchar *all_bitmaps_filter_name = N_("All Bitmaps");
// Calculate the amount of memory required
- int filter_count = 3; // 3 - one for All Files, All Images and All Inkscape Files
+ int filter_count = 5; // 5 - one for each filter type
int filter_length = 1;
for (Inkscape::Extension::DB::InputList::iterator current_item = extension_list.begin();
all_image_files_filter += file_extension_name;
}
+ // I don't know of any other way to define "bitmap" formats other than by listing them
+ // if you change it here, do the same change in filedialogimpl-gtkmm
+ if (
+ strncmp("image/png", imod->get_mimetype(), 9)==0 ||
+ strncmp("image/jpeg", imod->get_mimetype(), 10)==0 ||
+ strncmp("image/gif", imod->get_mimetype(), 9)==0 ||
+ strncmp("image/x-icon", imod->get_mimetype(), 12)==0 ||
+ strncmp("image/x-navi-animation", imod->get_mimetype(), 22)==0 ||
+ strncmp("image/x-cmu-raster", imod->get_mimetype(), 18)==0 ||
+ strncmp("image/x-xpixmap", imod->get_mimetype(), 15)==0 ||
+ strncmp("image/bmp", imod->get_mimetype(), 9)==0 ||
+ strncmp("image/vnd.wap.wbmp", imod->get_mimetype(), 18)==0 ||
+ strncmp("image/tiff", imod->get_mimetype(), 10)==0 ||
+ strncmp("image/x-xbitmap", imod->get_mimetype(), 15)==0 ||
+ strncmp("image/x-tga", imod->get_mimetype(), 11)==0 ||
+ strncmp("image/x-pcx", imod->get_mimetype(), 11)==0
+ ) {
+ if(all_bitmaps_filter.length() > 0)
+ all_bitmaps_filter += ";*";
+ all_bitmaps_filter += file_extension_name;
+ } else {
+ if(all_vectors_filter.length() > 0)
+ all_vectors_filter += ";*";
+ all_vectors_filter += file_extension_name;
+ }
+
filter_count++;
}
int extension_index = 0;
_extension_map = new Inkscape::Extension::Extension*[filter_count];
+ // Filter bitmap files
+ all_bitmaps.name = g_utf8_to_utf16(all_bitmaps_filter_name,
+ -1, NULL, &all_bitmaps.name_length, NULL);
+ all_bitmaps.filter = g_utf8_to_utf16(all_bitmaps_filter.data(),
+ -1, NULL, &all_bitmaps.filter_length, NULL);
+ all_bitmaps.mod = NULL;
+ filter_list.push_front(all_bitmaps);
+
+ // Filter vector files
+ all_vectors.name = g_utf8_to_utf16(all_vectors_filter_name,
+ -1, NULL, &all_vectors.name_length, NULL);
+ all_vectors.filter = g_utf8_to_utf16(all_vectors_filter.data(),
+ -1, NULL, &all_vectors.filter_length, NULL);
+ all_vectors.mod = NULL;
+ filter_list.push_front(all_vectors);
+
// Filter Image Files
all_image_files.name = g_utf8_to_utf16(all_image_files_filter_name,
-1, NULL, &all_image_files.name_length, NULL);
all_inkscape_files.filter_length +
all_inkscape_files.name_length + 3 +
all_image_files.filter_length +
- all_image_files.name_length + 3 + 1;
+ all_image_files.name_length + 3 +
+ all_vectors.filter_length +
+ all_vectors.name_length + 3 +
+ all_bitmaps.filter_length +
+ all_bitmaps.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<Filter>::iterator filter_iterator = filter_list.begin();
filter_iterator != filter_list.end(); filter_iterator++)
{
_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
}
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);
@@ -560,9 +608,12 @@ LRESULT CALLBACK FileOpenDialogImplWin32::preview_wnd_proc(HWND hwnd, UINT uMsg,
if(pImpl->_path_string[0] == 0)
{
+ WCHAR* noFileText=(WCHAR*)g_utf8_to_utf16(_("No file selected"),
+ -1, NULL, NULL, NULL);
FillRect(dc, &rcClient, (HBRUSH)(COLOR_3DFACE + 1));
- DrawText(dc, _("No file selected"), -1, &rcClient,
+ DrawTextW(dc, noFileText, -1, &rcClient,
DT_CENTER | DT_VCENTER | DT_NOPREFIX);
+ g_free(noFileText);
}
else if(pImpl->_preview_bitmap != NULL)
{
// 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;
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 {
_preview_file_icon = NULL;
_preview_bitmap_image.clear();
+ _preview_emf_image = false;
_mutex->unlock();
}
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<NR::Rect> 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();
arena, key, SP_ITEM_SHOW_DISPLAY);
NRGC gc(NULL);
- nr_matrix_set_scale(&gc.transform, 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);
// 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
{
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()
// Do we have anything to render?
_mutex->lock();
- if(!_preview_bitmap_image)
+ if(!_preview_bitmap_image && !_preview_emf_image)
{
_mutex->unlock();
return;
// 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);
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,
+ const Inkscape::Extension::FileSaveMethod save_method) :
+ FileDialogBaseWin32(parent, dir, title, fileTypes,
+ (save_method == Inkscape::Extension::FILE_SAVE_METHOD_SAVE_COPY) ? "dialogs.save_copy" : "dialogs.save_as"),
+ _title_label(NULL),
+ _title_edit(NULL)
{
+ FileSaveDialog::myDocTitle = docTitle;
createFilterMenu();
}
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;
_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))
if(_result)
appendExtension(myFilename, (Inkscape::Extension::Output*)_extension);
}
-
+
return _result;
}
@@ -1415,11 +1666,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 +1760,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 :