diff options
| author | Joel Holdsworth <joel@airwebreathe.org.uk> | 2008-02-23 12:56:59 +0000 |
|---|---|---|
| committer | joelholdsworth <joelholdsworth@users.sourceforge.net> | 2008-02-23 12:56:59 +0000 |
| commit | 9d8ae74ac16a9a8023c476ad0dc7f95792abe7f5 (patch) | |
| tree | 7f13097645af6641b3351decc199fb9c8c87f8a8 /src | |
| parent | partial fix sent by jfb for bug #188814 (diff) | |
| download | inkscape-9d8ae74ac16a9a8023c476ad0dc7f95792abe7f5.tar.gz inkscape-9d8ae74ac16a9a8023c476ad0dc7f95792abe7f5.zip | |
Merged in Native File Dialogs for Windows Branch
(bzr r4830)
Diffstat (limited to 'src')
| -rw-r--r-- | src/dialogs/filedialog-win32.cpp | 381 | ||||
| -rw-r--r-- | src/file.cpp | 99 | ||||
| -rw-r--r-- | src/inkscape.rc | 3 | ||||
| -rw-r--r-- | src/inkview.rc | 2 | ||||
| -rw-r--r-- | src/ui/dialog/filedialog.cpp | 103 | ||||
| -rw-r--r-- | src/ui/dialog/filedialog.h | 65 | ||||
| -rw-r--r-- | src/ui/dialog/filedialogimpl-gtkmm.cpp | 118 | ||||
| -rw-r--r-- | src/ui/dialog/filedialogimpl-gtkmm.h | 43 | ||||
| -rw-r--r-- | src/ui/dialog/filedialogimpl-win32.cpp | 1461 | ||||
| -rw-r--r-- | src/ui/dialog/filedialogimpl-win32.h | 348 |
10 files changed, 2046 insertions, 577 deletions
diff --git a/src/dialogs/filedialog-win32.cpp b/src/dialogs/filedialog-win32.cpp deleted file mode 100644 index ca9ce5f6c..000000000 --- a/src/dialogs/filedialog-win32.cpp +++ /dev/null @@ -1,381 +0,0 @@ - -#ifdef HAVE_CONFIG_H -# include <config.h> -#endif -#include "filedialog.h" - -//#include "extension/internal/win32.h" - -#include <windows.h> - -#include <glib.h> - -#include <extension/extension.h> -#include <extension/db.h> - -#define UNSAFE_SCRATCH_BUFFER_SIZE 4096 - -namespace Inkscape -{ -namespace UI -{ -namespace Dialogs -{ - -/*################################# -# U T I L I T Y -#################################*/ -static gboolean -win32_is_os_wide() -{ - static gboolean initialized = FALSE; - static gboolean is_wide = FALSE; - static OSVERSIONINFOA osver; - - if ( !initialized ) - { - BOOL result; - - initialized = TRUE; - - memset (&osver, 0, sizeof(OSVERSIONINFOA)); - osver.dwOSVersionInfoSize = sizeof(OSVERSIONINFOA); - result = GetVersionExA (&osver); - if (result) - { - if (osver.dwPlatformId == VER_PLATFORM_WIN32_NT) - is_wide = TRUE; - } - // If we can't even call to get the version, fall back to ANSI API - } - - return is_wide; -} - -/*################################# -# F I L E O P E N -#################################*/ - -struct FileOpenNativeData_def { - char *dir; - FileDialogType fileTypes; - char *title; -}; - -FileOpenDialog::FileOpenDialog( - const char *dir, FileDialogType fileTypes, const char *title) { - - nativeData = (FileOpenNativeData *) - g_malloc(sizeof (FileOpenNativeData)); - if ( !nativeData ) { - // do we want exceptions? - return; - } - - if ( !dir ) - dir = ""; - nativeData->dir = g_strdup(dir); - nativeData->fileTypes = fileTypes; - nativeData->title = g_strdup(title); - - extension = NULL; - filename = NULL; -} - - - -FileOpenDialog::~FileOpenDialog() { - - //do any cleanup here - if ( nativeData ) { - g_free(nativeData->dir); - g_free(nativeData->title); - g_free(nativeData); - } - - if (filename) g_free(filename); - extension = NULL; -} - - - -bool -FileOpenDialog::show() { - - if ( !nativeData ) { - //error - return FALSE; - } - - gint retval = FALSE; - - - //Jon's UNICODE patch - if ( win32_is_os_wide() ) { - gunichar2 fnbufW[UNSAFE_SCRATCH_BUFFER_SIZE * sizeof(gunichar2)] = {0}; - gunichar2* dirW = - g_utf8_to_utf16( nativeData->dir, -1, NULL, NULL, NULL ); - gunichar2 *filterW = (gunichar2 *) L""; - if ( nativeData->fileTypes == SVG_TYPES ) - filterW = (gunichar2 *) L"SVG files\0*.svg;*.svgz\0All files\0*\0"; - else if ( nativeData->fileTypes == IMPORT_TYPES ) - filterW = (gunichar2 *) L"Image files\0*.svg;*.png;*.jpg;*.jpeg;*.bmp;*.gif;*.tiff;*.xpm\0" - L"SVG files\0*.svg\0" - L"All files\0*\0"; - gunichar2* titleW = - g_utf8_to_utf16( nativeData->title, -1, NULL, NULL, NULL ); - OPENFILENAMEW ofn = { - sizeof (OPENFILENAMEW), - NULL, // hwndOwner - NULL, // hInstance - (const WCHAR *)filterW, // lpstrFilter - NULL, // lpstrCustomFilter - 0, // nMaxCustFilter - 1, // nFilterIndex - (WCHAR *)fnbufW, // lpstrFile - sizeof (fnbufW) / sizeof(WCHAR), // nMaxFile - NULL, // lpstrFileTitle - 0, // nMaxFileTitle - (const WCHAR *)dirW, // lpstrInitialDir - (const WCHAR *)titleW, // lpstrTitle - OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST | OFN_HIDEREADONLY | OFN_NOCHANGEDIR, // Flags - 0, // nFileOffset - 0, // nFileExtension - NULL, // lpstrDefExt - 0, // lCustData - NULL, // lpfnHook - NULL // lpTemplateName - }; - - retval = GetOpenFileNameW (&ofn); - if (retval) - filename = g_utf16_to_utf8( fnbufW, -1, NULL, NULL, NULL ); - - g_free( dirW ); - g_free( titleW ); - - } else { - gchar *dir = nativeData->dir; - gchar *title = nativeData->title; - gchar fnbuf[UNSAFE_SCRATCH_BUFFER_SIZE] = {0}; - - gchar *filter = ""; - if ( nativeData->fileTypes == SVG_TYPES ) - filter = "SVG files\0*.svg;*.svgz\0All files\0*\0"; - else if ( nativeData->fileTypes == IMPORT_TYPES ) - filter = "Image files\0*.svg;*.png;*.jpg;*.jpeg;*.bmp;*.gif;*.tiff;*.xpm\0" - "SVG files\0*.svg\0" - "All files\0*\0"; - - OPENFILENAMEA ofn = { - sizeof (OPENFILENAMEA), - NULL, // hwndOwner - NULL, // hInstance - (const CHAR *)filter, // lpstrFilter - NULL, // lpstrCustomFilter - 0, // nMaxCustFilter - 1, // nFilterIndex - fnbuf, // lpstrFile - sizeof (fnbuf), // nMaxFile - NULL, // lpstrFileTitle - 0, // nMaxFileTitle - (const CHAR *)dir, // lpstrInitialDir - (const CHAR *)title, // lpstrTitle - OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST | OFN_HIDEREADONLY | OFN_NOCHANGEDIR, // Flags - 0, // nFileOffset - 0, // nFileExtension - NULL, // lpstrDefExt - 0, // lCustData - NULL, // lpfnHook - NULL // lpTemplateName - }; - - retval = GetOpenFileNameA (&ofn); - if ( retval ) { - filename = g_strdup( fnbuf ); - /* ### We need to try something like this instead: - GError *err = NULL; - filename = g_filename_to_utf8(fnbuf, -1, NULL, NULL, &err); - if ( !filename && err ) { - g_warning("Charset conversion in show()[%d]%s\n", - err->code, err->message); - } - */ - } - } - - if ( !retval ) { - //int errcode = CommDlgExtendedError(); - return FALSE; - } - - return TRUE; - -} - - - -/*################################# -# F I L E S A V E -#################################*/ - -struct FileSaveNativeData_def { - OPENFILENAME ofn; - gchar filter[UNSAFE_SCRATCH_BUFFER_SIZE]; - gchar fnbuf[4096]; -}; - - - -FileSaveDialog::FileSaveDialog( - const char *dir, FileDialogType fileTypes, const char *title, const char * default_key) { - - nativeData = (FileSaveNativeData *) - g_malloc(sizeof (FileSaveNativeData)); - if ( !nativeData ) { - //do we want exceptions? - return; - } - - extension = NULL; - filename = NULL; - - int default_item = 0; - - GSList* extension_list = Inkscape::Extension::db.get_output_list(); - g_assert (extension_list != NULL); - - /* Make up the filter string for the save dialogue using the list - ** of available output types. - */ - - gchar *p = nativeData->filter; - int N = UNSAFE_SCRATCH_BUFFER_SIZE; - - int n = 1; - for (GSList* i = g_slist_next (extension_list); i != NULL; i = g_slist_next(i)) { - - Inkscape::Extension::DB::IOExtensionDescription* d = - reinterpret_cast<Inkscape::Extension::DB::IOExtensionDescription*>(i->data); - - if (!d->sensitive) - continue; - - int w = snprintf (p, N, "%s", d->name); - N -= w + 1; - p += w + 1; - - w = snprintf (p, N, "*"); - N -= w + 1; - p += w + 1; - - g_assert (N >= 0); - - /* Look to see if this extension is the default */ - if (default_key && - d->extension->get_id() && - strcmp (default_key, d->extension->get_id()) == 0) { - default_item = n; - extension = d->extension; - } - - n++; - } - - *p = '\0'; - - nativeData->fnbuf[0] = '\0'; - - if (dir) { - /* We must check that dir is not something like - ** c:\foo\ (ie with a trailing \). If it is, - ** GetSaveFileName will give an error. - */ - int n = strlen(dir); - if (n > 0 && dir[n - 1] != '\\') { - strncpy(nativeData->fnbuf, dir, sizeof(nativeData->fnbuf)); - } - } - - OPENFILENAME ofn = { - sizeof (OPENFILENAME), - NULL, // hwndOwner - NULL, // hInstance - nativeData->filter, // lpstrFilter - NULL, // lpstrCustomFilter - 0, // nMaxCustFilter - default_item, // nFilterIndex - nativeData->fnbuf, // lpstrFile - sizeof (nativeData->fnbuf), // nMaxFile - NULL, // lpstrFileTitle - 0, // nMaxFileTitle - (const CHAR *)dir, // lpstrInitialDir - (const CHAR *)title, // lpstrTitle - OFN_HIDEREADONLY | OFN_NOCHANGEDIR, // Flags - 0, // nFileOffset - 0, // nFileExtension - NULL, // lpstrDefExt - 0, // lCustData - NULL, // lpfnHook - NULL // lpTemplateName - }; - - nativeData->ofn = ofn; -} - -FileSaveDialog::~FileSaveDialog() { - - //do any cleanup here - g_free(nativeData); - if (filename) g_free(filename); - extension = NULL; -} - -bool -FileSaveDialog::show() { - - if (!nativeData) - return FALSE; - int retval = GetSaveFileName (&(nativeData->ofn)); - if (!retval) { - //int errcode = CommDlgExtendedError(); - return FALSE; - } - - GSList* extension_list = Inkscape::Extension::db.get_output_list(); - g_assert (extension_list != NULL); - - /* Work out which extension corresponds to the user's choice of - ** file type. - */ - int n = nativeData->ofn.nFilterIndex - 1; - GSList* i = g_slist_next (extension_list); - - while (n > 0 && i) { - n--; - i = g_slist_next(i); - } - - Inkscape::Extension::DB::IOExtensionDescription* d = - reinterpret_cast<Inkscape::Extension::DB::IOExtensionDescription*>(i->data); - - extension = d->extension; - - filename = g_strdup (nativeData->fnbuf); - return TRUE; -} - - - - - - - - -} //namespace Dialogs -} //namespace UI -} //namespace Inkscape - - - - diff --git a/src/file.cpp b/src/file.cpp index c3e7e7583..b41d61426 100644 --- a/src/file.cpp +++ b/src/file.cpp @@ -367,8 +367,6 @@ void dump_ustr(Glib::ustring const &ustr) g_message("---------------"); } -static Inkscape::UI::Dialog::FileOpenDialog *openDialogInstance = NULL; - /** * Display an file Open selector. Open a document if OK is pressed. * Can select single or multiple files for opening. @@ -376,76 +374,85 @@ static Inkscape::UI::Dialog::FileOpenDialog *openDialogInstance = NULL; void sp_file_open_dialog(Gtk::Window &parentWindow, gpointer /*object*/, gpointer /*data*/) { - //# Get the current directory for finding files - Glib::ustring open_path; - char *attr = (char *)prefs_get_string_attribute("dialogs.open", "path"); - if (attr) - open_path = attr; - - + static Glib::ustring open_path; + + if(open_path.empty()) + { + gchar const *attr = prefs_get_string_attribute("dialogs.open", "path"); + if (attr) + open_path = attr; + } + //# Test if the open_path directory exists if (!Inkscape::IO::file_test(open_path.c_str(), (GFileTest)(G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR))) open_path = ""; - + //# If no open path, default to our home directory - if (open_path.size() < 1) - { + if (open_path.empty()) + { open_path = g_get_home_dir(); open_path.append(G_DIR_SEPARATOR_S); - } - + } + //# Create a dialog if we don't already have one - if (!openDialogInstance) { - openDialogInstance = + Inkscape::UI::Dialog::FileOpenDialog *openDialogInstance = Inkscape::UI::Dialog::FileOpenDialog::create( - parentWindow, - open_path, + parentWindow, open_path, Inkscape::UI::Dialog::SVG_TYPES, - (char const *)_("Select file to open")); - } - - + _("Select file to open")); + //# Show the dialog bool const success = openDialogInstance->show(); + + //# Save the folder the user selected for later + open_path = openDialogInstance->getCurrentDirectory(); + if (!success) + { + delete openDialogInstance; return; - + } + //# User selected something. Get name and type Glib::ustring fileName = openDialogInstance->getFilename(); + Inkscape::Extension::Extension *selection = openDialogInstance->getSelectionType(); - - //# Code to check & open iff multiple files. - std::vector<Glib::ustring> flist=openDialogInstance->getFilenames(); - + + //# Code to check & open if multiple files. + std::vector<Glib::ustring> flist = openDialogInstance->getFilenames(); + + //# We no longer need the file dialog object - delete it + delete openDialogInstance; + openDialogInstance = NULL; + //# Iterate through filenames if more than 1 if (flist.size() > 1) + { + for (unsigned int i = 0; i < flist.size(); i++) { - for (unsigned int i=1 ; i<flist.size() ; i++) - { - Glib::ustring fName = flist[i]; - - if (Glib::file_test(fileName, Glib::FILE_TEST_IS_DIR)) { - Glib::ustring newFileName = Glib::filename_to_utf8(fName); + fileName = flist[i]; + + Glib::ustring newFileName = Glib::filename_to_utf8(fileName); if ( newFileName.size() > 0 ) - fName = newFileName; + fileName = newFileName; else g_warning( "ERROR CONVERTING OPEN FILENAME TO UTF-8" ); #ifdef INK_DUMP_FILENAME_CONV - g_message("Opening File %s\n",fileName); + g_message("Opening File %s\n", fileName.c_str()); #endif sp_file_open(fileName, selection); - } } + return; } - if (fileName.size() > 0) { - + if (!fileName.empty()) + { Glib::ustring newFileName = Glib::filename_to_utf8(fileName); if ( newFileName.size() > 0) @@ -699,7 +706,7 @@ sp_file_save_dialog(Gtk::Window &parentWindow, SPDocument *doc, bool is_copy) if ( save_loc_local.size() > 0) save_loc = save_loc_local; - + //# Show the SaveAs dialog char const * dialog_title; if (is_copy) { @@ -712,20 +719,12 @@ sp_file_save_dialog(Gtk::Window &parentWindow, SPDocument *doc, bool is_copy) parentWindow, save_loc, Inkscape::UI::Dialog::SVG_TYPES, - (char const *) _("Select file to save to"), + dialog_title, default_extension ); - - saveDialog->change_title(dialog_title); + saveDialog->setSelectionType(extension); - - // allow easy access to the user's own templates folder - gchar *templates = profile_path ("templates"); - if (Inkscape::IO::file_test(templates, (GFileTest)(G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR))) { - dynamic_cast<Gtk::FileChooser *>(saveDialog)->add_shortcut_folder(templates); - } - g_free (templates); - + bool success = saveDialog->show(); if (!success) { delete saveDialog; diff --git a/src/inkscape.rc b/src/inkscape.rc index 3e5b61548..d48b68c43 100644 --- a/src/inkscape.rc +++ b/src/inkscape.rc @@ -25,3 +25,6 @@ BEGIN VALUE "Translation", 1033, 437 END END + +1000 BITMAP "./show-preview.bmp" + diff --git a/src/inkview.rc b/src/inkview.rc index 245bdc68b..9f643eb4c 100644 --- a/src/inkview.rc +++ b/src/inkview.rc @@ -25,3 +25,5 @@ BEGIN VALUE "Translation", 1033, 437
END
END
+
+1000 BITMAP "./show-preview.bmp"
diff --git a/src/ui/dialog/filedialog.cpp b/src/ui/dialog/filedialog.cpp index c3ca49c99..103b62485 100644 --- a/src/ui/dialog/filedialog.cpp +++ b/src/ui/dialog/filedialog.cpp @@ -14,6 +14,7 @@ #include "filedialog.h" #include "filedialogimpl-gtkmm.h" +#include "filedialogimpl-win32.h" #include "gc-core.h" #include <dialogs/dialog-events.h> @@ -26,6 +27,49 @@ namespace Dialog { /*######################################################################### +### U T I L I T Y +#########################################################################*/ + +bool hasSuffix(const Glib::ustring &str, const Glib::ustring &ext) +{ + int strLen = str.length(); + int extLen = ext.length(); + if (extLen > strLen) + return false; + int strpos = strLen-1; + for (int extpos = extLen-1 ; extpos>=0 ; extpos--, strpos--) + { + Glib::ustring::value_type ch = str[strpos]; + if (ch != ext[extpos]) + { + if ( ((ch & 0xff80) != 0) || + static_cast<Glib::ustring::value_type>( g_ascii_tolower( static_cast<gchar>(0x07f & ch) ) ) != ext[extpos] ) + { + return false; + } + } + } + return true; +} + +bool isValidImageFile(const Glib::ustring &fileName) +{ + std::vector<Gdk::PixbufFormat>formats = Gdk::Pixbuf::get_formats(); + for (unsigned int i=0; i<formats.size(); i++) + { + Gdk::PixbufFormat format = formats[i]; + std::vector<Glib::ustring>extensions = format.get_extensions(); + for (unsigned int j=0; j<extensions.size(); j++) + { + Glib::ustring ext = extensions[j]; + if (hasSuffix(fileName, ext)) + return true; + } + } + return false; +} + +/*######################################################################### ### F I L E O P E N #########################################################################*/ @@ -35,10 +79,20 @@ namespace Dialog FileOpenDialog *FileOpenDialog::create(Gtk::Window &parentWindow, const Glib::ustring &path, FileDialogType fileTypes, - const Glib::ustring &title) + const char *title) { +#ifdef WIN32 + FileOpenDialog *dialog = new FileOpenDialogImplWin32(parentWindow, path, fileTypes, title); +#else FileOpenDialog *dialog = new FileOpenDialogImplGtk(parentWindow, path, fileTypes, title); - return dialog; +#endif + + return dialog; +} + +Glib::ustring FileOpenDialog::getFilename() +{ + return myFilename; } //######################################################################## @@ -51,13 +105,54 @@ FileOpenDialog *FileOpenDialog::create(Gtk::Window &parentWindow, FileSaveDialog *FileSaveDialog::create(Gtk::Window& parentWindow, const Glib::ustring &path, FileDialogType fileTypes, - const Glib::ustring &title, + const char *title, const Glib::ustring &default_key) { +#ifdef WIN32 + FileSaveDialog *dialog = new FileSaveDialogImplWin32(parentWindow, path, fileTypes, title, default_key); +#else FileSaveDialog *dialog = new FileSaveDialogImplGtk(parentWindow, path, fileTypes, title, default_key); +#endif return dialog; } +Glib::ustring FileSaveDialog::getFilename() +{ + return myFilename; +} + +//void FileSaveDialog::change_path(const Glib::ustring& path) +//{ +// myFilename = path; +//} + +void FileSaveDialog::appendExtension(Glib::ustring& path, Inkscape::Extension::Output* outputExtension) +{ + try { + bool appendExtension = true; + Glib::ustring utf8Name = Glib::filename_to_utf8( path ); + Glib::ustring::size_type pos = utf8Name.rfind('.'); + if ( pos != Glib::ustring::npos ) { + Glib::ustring trail = utf8Name.substr( pos ); + Glib::ustring foldedTrail = trail.casefold(); + if ( (trail == ".") + | (foldedTrail != Glib::ustring( outputExtension->get_extension() ).casefold() + && ( knownExtensions.find(foldedTrail) != knownExtensions.end() ) ) ) { + utf8Name = utf8Name.erase( pos ); + } else { + appendExtension = false; + } + } + + if (appendExtension) { + utf8Name = utf8Name + outputExtension->get_extension(); + myFilename = Glib::filename_from_utf8( utf8Name ); + } + } catch ( Glib::ConvertError& e ) { + // ignore + } +} + //######################################################################## //# F I L E E X P O R T //######################################################################## @@ -68,7 +163,7 @@ FileSaveDialog *FileSaveDialog::create(Gtk::Window& parentWindow, FileExportDialog *FileExportDialog::create(Gtk::Window& parentWindow, const Glib::ustring &path, FileDialogType fileTypes, - const Glib::ustring &title, + const char *title, const Glib::ustring &default_key) { FileExportDialog *dialog = new FileExportDialogImpl(parentWindow, path, fileTypes, title, default_key); diff --git a/src/ui/dialog/filedialog.h b/src/ui/dialog/filedialog.h index 75c6f0080..a3d5c0ea9 100644 --- a/src/ui/dialog/filedialog.h +++ b/src/ui/dialog/filedialog.h @@ -16,17 +16,16 @@ #include <glibmm.h> #include <vector> +#include <set> #include <gtkmm.h> namespace Inkscape { namespace Extension { class Extension; +class Output; } } - - - namespace Inkscape { namespace UI @@ -34,8 +33,6 @@ namespace UI namespace Dialog { - - /** * Used for setting filters and options, and * reading them back from user selections. @@ -54,12 +51,18 @@ typedef enum { SVG_NAMESPACE_WITH_EXTENSIONS } FileDialogSelectionType; + /** - * Architecture-specific data + * Return true if the string ends with the given suffix */ -typedef struct FileOpenNativeData_def FileOpenNativeData; +bool hasSuffix(const Glib::ustring &str, const Glib::ustring &ext); /** + * Return true if the image is loadable by Gdk, else false + */ +bool isValidImageFile(const Glib::ustring &fileName); + +/** * This class provides an implementation-independent API for * file "Open" dialogs. Using a standard interface obviates the need * for ugly #ifdefs in file open code @@ -87,7 +90,7 @@ public: static FileOpenDialog *create(Gtk::Window& parentWindow, const Glib::ustring &path, FileDialogType fileTypes, - const Glib::ustring &title); + const char *title); /** @@ -100,7 +103,7 @@ public: * Show an OpenFile file selector. * @return the selected path if user selected one, else NULL */ - virtual bool show() =0; + virtual bool show() = 0; /** * Return the 'key' (filetype) of the selection, if any @@ -109,10 +112,18 @@ public: */ virtual Inkscape::Extension::Extension * getSelectionType() = 0; - virtual Glib::ustring getFilename () =0; - - virtual std::vector<Glib::ustring> getFilenames () = 0; + Glib::ustring getFilename(); + virtual std::vector<Glib::ustring> getFilenames() = 0; + + virtual Glib::ustring getCurrentDirectory() = 0; + +protected: + /** + * Filename that was given + */ + Glib::ustring myFilename; + }; //FileOpenDialog @@ -146,9 +157,9 @@ public: * @param key a list of file types from which the user can select */ static FileSaveDialog *create(Gtk::Window& parentWindow, - const Glib::ustring &path, + const Glib::ustring &path, FileDialogType fileTypes, - const Glib::ustring &title, + const char *title, const Glib::ustring &default_key); @@ -174,17 +185,27 @@ public: virtual void setSelectionType( Inkscape::Extension::Extension * key ) = 0; - virtual Glib::ustring getFilename () =0; - /** - * Change the window title. + * Get the file name chosen by the user. Valid after an [OK] */ - virtual void change_title(const Glib::ustring& title) =0; + Glib::ustring getFilename (); + + virtual Glib::ustring getCurrentDirectory() = 0; +protected: + + /** + * Filename that was given + */ + Glib::ustring myFilename; + /** - * Change the default save path location. + * List of known file extensions. */ - virtual void change_path(const Glib::ustring& path) =0; + std::set<Glib::ustring> knownExtensions; + + + void appendExtension(Glib::ustring& path, Inkscape::Extension::Output* outputExtension); }; //FileSaveDialog @@ -226,9 +247,9 @@ public: * @param key a list of file types from which the user can select */ static FileExportDialog *create(Gtk::Window& parentWindow, - const Glib::ustring &path, + const Glib::ustring &path, FileDialogType fileTypes, - const Glib::ustring &title, + const char *title, const Glib::ustring &default_key); diff --git a/src/ui/dialog/filedialogimpl-gtkmm.cpp b/src/ui/dialog/filedialogimpl-gtkmm.cpp index a1773d39a..1405e11aa 100644 --- a/src/ui/dialog/filedialogimpl-gtkmm.cpp +++ b/src/ui/dialog/filedialogimpl-gtkmm.cpp @@ -495,55 +495,6 @@ void SVGPreview::showTooLarge(long fileLength) } - -/** - * Return true if the string ends with the given suffix - */ -static bool -hasSuffix(Glib::ustring &str, Glib::ustring &ext) -{ - int strLen = str.length(); - int extLen = ext.length(); - if (extLen > strLen) - return false; - int strpos = strLen-1; - for (int extpos = extLen-1 ; extpos>=0 ; extpos--, strpos--) - { - Glib::ustring::value_type ch = str[strpos]; - if (ch != ext[extpos]) - { - if ( ((ch & 0xff80) != 0) || - static_cast<Glib::ustring::value_type>( g_ascii_tolower( static_cast<gchar>(0x07f & ch) ) ) != ext[extpos] ) - { - return false; - } - } - } - return true; -} - - -/** - * Return true if the image is loadable by Gdk, else false - */ -static bool -isValidImageFile(Glib::ustring &fileName) -{ - std::vector<Gdk::PixbufFormat>formats = Gdk::Pixbuf::get_formats(); - for (unsigned int i=0; i<formats.size(); i++) - { - Gdk::PixbufFormat format = formats[i]; - std::vector<Glib::ustring>extensions = format.get_extensions(); - for (unsigned int j=0; j<extensions.size(); j++) - { - Glib::ustring ext = extensions[j]; - if (hasSuffix(fileName, ext)) - return true; - } - } - return false; -} - bool SVGPreview::set(Glib::ustring &fileName, int dialogType) { @@ -677,7 +628,7 @@ void FileDialogBaseGtk::_updatePreviewCallback() return; } - svgPreview.set(fileName, dialogType); + svgPreview.set(fileName, _dialogType); } @@ -692,7 +643,7 @@ FileOpenDialogImplGtk::FileOpenDialogImplGtk(Gtk::Window& parentWindow, const Glib::ustring &dir, FileDialogType fileTypes, const Glib::ustring &title) : - FileDialogBaseGtk(parentWindow, title, fileTypes, "dialogs.open") + FileDialogBaseGtk(parentWindow, title, Gtk::FILE_CHOOSER_ACTION_OPEN, fileTypes, "dialogs.open") { @@ -712,7 +663,7 @@ FileOpenDialogImplGtk::FileOpenDialogImplGtk(Gtk::Window& parentWindow, myFilename = ""; /* Set our dialog type (open, import, etc...)*/ - dialogType = fileTypes; + _dialogType = fileTypes; /* Set the pwd and/or the filename */ @@ -864,7 +815,7 @@ FileOpenDialogImplGtk::getSelectionType() Glib::ustring FileOpenDialogImplGtk::getFilename (void) { - return g_strdup(myFilename.c_str()); + return myFilename; } @@ -881,7 +832,10 @@ std::vector<Glib::ustring>FileOpenDialogImplGtk::getFilenames() return result; } - +Glib::ustring FileOpenDialogImplGtk::getCurrentDirectory() +{ + return get_current_folder(); +} @@ -915,7 +869,7 @@ FileSaveDialogImplGtk::FileSaveDialogImplGtk( Gtk::Window &parentWindow, myFilename = ""; /* Set our dialog type (save, export, etc...)*/ - dialogType = fileTypes; + _dialogType = fileTypes; /* Set the pwd and/or the filename */ if (dir.size() > 0) @@ -974,7 +928,13 @@ FileSaveDialogImplGtk::FileSaveDialogImplGtk( Gtk::Window &parentWindow, expander->set_expanded(true); } - + // allow easy access to the user's own templates folder + gchar *templates = profile_path ("templates"); + if (Inkscape::IO::file_test(templates, (GFileTest)(G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR))) + add_shortcut_folder(templates); + g_free (templates); + + //if (extension == NULL) // checkbox.set_sensitive(FALSE); @@ -1179,22 +1139,17 @@ void FileSaveDialogImplGtk::setSelectionType( Inkscape::Extension::Extension * k } } - -/** - * Get the file name chosen by the user. Valid after an [OK] - */ -Glib::ustring -FileSaveDialogImplGtk::getFilename() +Glib::ustring FileSaveDialogImplGtk::getCurrentDirectory() { - return myFilename; + return get_current_folder(); } -void +/*void FileSaveDialogImplGtk::change_title(const Glib::ustring& title) { - this->set_title(title); -} + set_title(title); +}*/ /** * Change the default save path location. @@ -1202,7 +1157,8 @@ FileSaveDialogImplGtk::change_title(const Glib::ustring& title) void FileSaveDialogImplGtk::change_path(const Glib::ustring& path) { - myFilename = path; + myFilename = path; + if (Glib::file_test(myFilename, Glib::FILE_TEST_IS_DIR)) { //fprintf(stderr,"set_current_folder(%s)\n",myFilename.c_str()); set_current_folder(myFilename); @@ -1243,30 +1199,8 @@ void FileSaveDialogImplGtk::updateNameAndExtension() Inkscape::Extension::Output* newOut = extension ? dynamic_cast<Inkscape::Extension::Output*>(extension) : 0; if ( fileTypeCheckbox.get_active() && newOut ) { - try { - bool appendExtension = true; - Glib::ustring utf8Name = Glib::filename_to_utf8( myFilename ); - Glib::ustring::size_type pos = utf8Name.rfind('.'); - if ( pos != Glib::ustring::npos ) { - Glib::ustring trail = utf8Name.substr( pos ); - Glib::ustring foldedTrail = trail.casefold(); - if ( (trail == ".") - | (foldedTrail != Glib::ustring( newOut->get_extension() ).casefold() - && ( knownExtensions.find(foldedTrail) != knownExtensions.end() ) ) ) { - utf8Name = utf8Name.erase( pos ); - } else { - appendExtension = false; - } - } - - if (appendExtension) { - utf8Name = utf8Name + newOut->get_extension(); - myFilename = Glib::filename_from_utf8( utf8Name ); - change_path(myFilename); - } - } catch ( Glib::ConvertError& e ) { - // ignore - } + // Append the file extension if it's not already present + appendExtension(myFilename, newOut); } } @@ -1402,7 +1336,7 @@ FileExportDialogImpl::FileExportDialogImpl( Gtk::Window& parentWindow, myFilename = ""; /* Set our dialog type (save, export, etc...)*/ - dialogType = fileTypes; + _dialogType = fileTypes; /* Set the pwd and/or the filename */ if (dir.size()>0) diff --git a/src/ui/dialog/filedialogimpl-gtkmm.h b/src/ui/dialog/filedialogimpl-gtkmm.h index e5058d0c2..5bac9aa5b 100644 --- a/src/ui/dialog/filedialogimpl-gtkmm.h +++ b/src/ui/dialog/filedialogimpl-gtkmm.h @@ -23,7 +23,6 @@ #include <unistd.h> #include <sys/stat.h> #include <errno.h> -#include <set> #include <libxml/parser.h> #include <libxml/tree.h> @@ -164,10 +163,10 @@ public: * */ FileDialogBaseGtk(Gtk::Window& parentWindow, const Glib::ustring &title, - FileDialogType type, gchar const* preferenceBase) : - Gtk::FileChooserDialog(parentWindow, title), + Gtk::FileChooserAction dialogType, FileDialogType type, gchar const* preferenceBase) : + Gtk::FileChooserDialog(parentWindow, title, dialogType), preferenceBase(preferenceBase ? preferenceBase : "unknown"), - dialogType(type) + _dialogType(type) { internalSetup(); } @@ -175,11 +174,11 @@ public: /** * */ - FileDialogBaseGtk(Gtk::Window& parentWindow, const Glib::ustring &title, + FileDialogBaseGtk(Gtk::Window& parentWindow, const char *title, Gtk::FileChooserAction dialogType, FileDialogType type, gchar const* preferenceBase) : Gtk::FileChooserDialog(parentWindow, title, dialogType), preferenceBase(preferenceBase ? preferenceBase : "unknown"), - dialogType(type) + _dialogType(type) { internalSetup(); } @@ -197,14 +196,16 @@ protected: /** * What type of 'open' are we? (open, import, place, etc) */ - FileDialogType dialogType; + FileDialogType _dialogType; /** * Our svg preview widget */ SVGPreview svgPreview; - //# Child widgets + /** + * Child widgets + */ Gtk::CheckButton previewCheckbox; private: @@ -248,7 +249,9 @@ public: Glib::ustring getFilename(); - std::vector<Glib::ustring> getFilenames (); + std::vector<Glib::ustring> getFilenames(); + + Glib::ustring getCurrentDirectory(); private: @@ -267,11 +270,6 @@ private: */ Inkscape::Extension::Extension *extension; - /** - * Filename that was given - */ - Glib::ustring myFilename; - }; @@ -300,14 +298,13 @@ public: Inkscape::Extension::Extension *getSelectionType(); virtual void setSelectionType( Inkscape::Extension::Extension * key ); - Glib::ustring getFilename(); + Glib::ustring getCurrentDirectory(); - void change_title(const Glib::ustring& title); +private: + //void change_title(const Glib::ustring& title); void change_path(const Glib::ustring& path); void updateNameAndExtension(); -private: - /** * Fix to allow the user to type the file name */ @@ -351,16 +348,6 @@ private: * Callback for user input into fileNameEntry */ void fileNameEntryChangedCallback(); - - /** - * Filename that was given - */ - Glib::ustring myFilename; - - /** - * List of known file extensions. - */ - std::set<Glib::ustring> knownExtensions; }; diff --git a/src/ui/dialog/filedialogimpl-win32.cpp b/src/ui/dialog/filedialogimpl-win32.cpp new file mode 100644 index 000000000..63301862d --- /dev/null +++ b/src/ui/dialog/filedialogimpl-win32.cpp @@ -0,0 +1,1461 @@ +/**
+ * Implementation of the file dialog interfaces defined in filedialog.h for Win32
+ *
+ * Authors:
+ * Joel Holdsworth
+ * The Inkscape Organization
+ *
+ * Copyright (C) 2004-2007 The Inkscape Organization
+ *
+ * Released under GNU GPL, read the file 'COPYING' for more information
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#ifdef WIN32
+
+//General includes
+#include <list>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <set>
+#include <gdk/gdkwin32.h>
+#include <glib/gstdio.h>
+#include <glibmm/i18n.h>
+#include <gtkmm/window.h>
+
+//Inkscape includes
+#include "inkscape.h"
+#include "prefs-utils.h"
+#include <dialogs/dialog-events.h>
+#include <extension/input.h>
+#include <extension/output.h>
+#include <extension/db.h>
+
+#include <libnr/nr-pixops.h>
+#include <libnr/nr-translate-scale-ops.h>
+#include <display/nr-arena-item.h>
+#include <display/nr-arena.h>
+#include "sp-item.h"
+#include "canvas-arena.h"
+
+#include "filedialog.h"
+#include "filedialogimpl-win32.h"
+
+#include <zlib.h>
+#include <cairomm/win32_surface.h>
+#include <cairomm/context.h>
+
+using namespace std;
+using namespace Glib;
+using namespace Cairo;
+using namespace Gdk::Cairo;
+
+namespace Inkscape
+{
+namespace UI
+{
+namespace Dialog
+{
+
+const int PreviewWidening = 150;
+const char PreviewWindowClassName[] = "PreviewWnd";
+const unsigned long MaxPreviewFileSize = 1344; // kB
+
+#define IDC_SHOW_PREVIEW 1000
+
+// Windows 2000 version of OPENFILENAMEW
+struct OPENFILENAMEEXW : public OPENFILENAMEW {
+ void * pvReserved;
+ DWORD dwReserved;
+ DWORD FlagsEx;
+};
+
+struct Filter
+{
+ gunichar2* name;
+ glong name_length;
+ gunichar2* filter;
+ glong filter_length;
+ Inkscape::Extension::Extension* mod;
+};
+
+ustring utf16_to_ustring(const wchar_t *utf16string, int utf16length = -1)
+{
+ gchar *utf8string = g_utf16_to_utf8((const gunichar2*)utf16string,
+ utf16length, NULL, NULL, NULL);
+ ustring result(utf8string);
+ g_free(utf8string);
+
+ return result;
+}
+
+/*#########################################################################
+### F I L E D I A L O G B A S E C L A S S
+#########################################################################*/
+
+FileDialogBaseWin32::FileDialogBaseWin32(Gtk::Window &parent,
+ const Glib::ustring &dir, const gchar *title,
+ FileDialogType type, gchar const* /*preferenceBase*/) :
+ dialogType(type),
+ parent(parent),
+ _current_directory(dir)
+{
+ //_mutex = NULL;
+ _main_loop = NULL;
+
+ _title = (wchar_t*)g_utf8_to_utf16(title, -1, NULL, NULL, NULL);
+
+ Glib::RefPtr<const Gdk::Window> parentWindow = parent.get_window();
+ g_assert(parentWindow->gobj() != NULL);
+ _ownerHwnd = (HWND)gdk_win32_drawable_get_handle((GdkDrawable*)parentWindow->gobj());
+}
+
+FileDialogBaseWin32::~FileDialogBaseWin32()
+{
+ g_free(_title);
+}
+
+Inkscape::Extension::Extension *FileDialogBaseWin32::getSelectionType()
+{
+ return _extension;
+}
+
+Glib::ustring FileDialogBaseWin32::getCurrentDirectory()
+{
+ return _current_directory;
+}
+
+/*#########################################################################
+### F I L E O P E N
+#########################################################################*/
+
+bool FileOpenDialogImplWin32::_show_preview = true;
+
+/**
+ * Constructor. Not called directly. Use the factory.
+ */
+FileOpenDialogImplWin32::FileOpenDialogImplWin32(Gtk::Window &parent,
+ const Glib::ustring &dir,
+ FileDialogType fileTypes,
+ const gchar *title) :
+ FileDialogBaseWin32(parent, dir, title, fileTypes, "dialogs.open")
+{
+ // Initalize to Autodetect
+ _extension = NULL;
+
+ // Set our dialog type (open, import, etc...)
+ dialogType = fileTypes;
+
+ _show_preview_button_bitmap = NULL;
+ _preview_wnd = NULL;
+ _file_dialog_wnd = NULL;
+ _base_window_proc = NULL;
+
+ _preview_file_size = 0;
+ _preview_bitmap = NULL;
+ _preview_file_icon = NULL;
+ _preview_document_width = 0;
+ _preview_document_height = 0;
+ _preview_image_width = 0;
+ _preview_image_height = 0;
+
+ createFilterMenu();
+}
+
+
+/**
+ * Destructor
+ */
+FileOpenDialogImplWin32::~FileOpenDialogImplWin32()
+{
+ if(_filter != NULL)
+ delete[] _filter;
+ if(_extension_map != NULL)
+ delete[] _extension_map;
+}
+
+void FileOpenDialogImplWin32::createFilterMenu()
+{
+ list<Filter> filter_list;
+
+ // Compose the filter string
+ 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;
+
+ const gchar *all_files_filter_name = _("All Files");
+ const gchar *all_inkscape_files_filter_name = ("All Inkscape Files");
+ const gchar *all_image_files_filter_name = _("All Image Files");
+
+ // Calculate the amount of memory required
+ int filter_count = 3; // 3 - one for All Files, All Images and All Inkscape Files
+ int filter_length = 1;
+
+ for (Inkscape::Extension::DB::InputList::iterator current_item = extension_list.begin();
+ current_item != extension_list.end(); current_item++)
+ {
+ Filter filter;
+
+ Inkscape::Extension::Input *imod = *current_item;
+ if (imod->deactivated()) continue;
+
+ // Type
+ filter.name = g_utf8_to_utf16(imod->get_filetypename(),
+ -1, NULL, &filter.name_length, NULL);
+
+ // Extension
+ const gchar *file_extension_name = imod->get_extension();
+ filter.filter = g_utf8_to_utf16(file_extension_name,
+ -1, NULL, &filter.filter_length, NULL);
+
+ filter.mod = imod;
+ filter_list.push_back(filter);
+
+ filter_length += filter.name_length +
+ filter.filter_length + 3; // Add 3 for two \0s and a *
+
+ // Add to the "All Inkscape Files" Entry
+ if(all_inkscape_files_filter.length() > 0)
+ all_inkscape_files_filter += ";*";
+ all_inkscape_files_filter += file_extension_name;
+ if( strncmp("image", imod->get_mimetype(), 5) == 0)
+ {
+ // Add to the "All Image Files" Entry
+ if(all_image_files_filter.length() > 0)
+ all_image_files_filter += ";*";
+ all_image_files_filter += file_extension_name;
+ }
+
+ filter_count++;
+ }
+
+ int extension_index = 0;
+ _extension_map = new Inkscape::Extension::Extension*[filter_count];
+
+ // 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_image_files.filter = g_utf8_to_utf16(all_image_files_filter.data(),
+ -1, NULL, &all_image_files.filter_length, NULL);
+ filter_list.push_front(all_image_files);
+ _extension_map[extension_index++] = NULL;
+
+ // Filter Inkscape Files
+ all_inkscape_files.name = g_utf8_to_utf16(all_inkscape_files_filter_name,
+ -1, NULL, &all_inkscape_files.name_length, NULL);
+ all_inkscape_files.filter = g_utf8_to_utf16(all_inkscape_files_filter.data(),
+ -1, NULL, &all_inkscape_files.filter_length, NULL);
+ filter_list.push_front(all_inkscape_files);
+ _extension_map[extension_index++] = NULL;
+
+ // Filter All Files
+ all_files.name = g_utf8_to_utf16(all_files_filter_name,
+ -1, NULL, &all_files.name_length, NULL);
+ all_files.filter = NULL;
+ all_files.filter_length = 0;
+ filter_list.push_front(all_files);
+ _extension_map[extension_index++] = NULL;
+
+ filter_length += all_files.name_length + 3 +
+ all_inkscape_files.filter_length +
+ all_inkscape_files.name_length + 3 +
+ 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<Filter>::iterator filter_iterator = filter_list.begin();
+ filter_iterator != filter_list.end(); filter_iterator++)
+ {
+ const Filter &filter = *filter_iterator;
+
+ memcpy(filterptr, filter.name, filter.name_length * 2);
+ filterptr += filter.name_length;
+ g_free(filter.name);
+
+ *(filterptr++) = L'\0';
+ *(filterptr++) = L'*';
+
+ if(filter.filter != NULL)
+ {
+ memcpy(filterptr, filter.filter, filter.filter_length * 2);
+ filterptr += filter.filter_length;
+ g_free(filter.filter);
+ }
+
+ *(filterptr++) = L'\0';
+
+ // Associate this input extension with the file type name
+ _extension_map[extension_index++] = filter.mod;
+ }
+ *(filterptr++) = L'\0';
+
+ _filterIndex = 2;
+}
+
+void FileOpenDialogImplWin32::GetOpenFileName_thread()
+{
+ OPENFILENAMEEXW ofn;
+
+ g_assert(this != NULL);
+ //g_assert(_mutex != NULL);
+ g_assert(_main_loop != NULL);
+
+ WCHAR* current_directory_string = (WCHAR*)g_utf8_to_utf16(
+ _current_directory.data(), -1, NULL, NULL, NULL);
+
+ memset(&ofn, 0, sizeof(ofn));
+
+ // Copy the selected file name, converting from UTF-8 to UTF-16
+ memset(_path_string, 0, sizeof(_path_string));
+ gunichar2* utf16_path_string = g_utf8_to_utf16(
+ myFilename.data(), -1, NULL, NULL, NULL);
+ wcsncpy(_path_string, (wchar_t*)utf16_path_string, _MAX_PATH);
+ g_free(utf16_path_string);
+
+ ofn.lStructSize = sizeof(ofn);
+ ofn.hwndOwner = _ownerHwnd;
+ ofn.lpstrFile = _path_string;
+ ofn.nMaxFile = _MAX_PATH;
+ ofn.lpstrFileTitle = NULL;
+ ofn.nMaxFileTitle = 0;
+ ofn.lpstrInitialDir = current_directory_string;
+ ofn.lpstrTitle = _title;
+ ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST | OFN_EXPLORER | OFN_ENABLEHOOK | OFN_HIDEREADONLY | OFN_ENABLESIZING;
+ ofn.lpstrFilter = _filter;
+ ofn.nFilterIndex = _filterIndex;
+ ofn.lpfnHook = GetOpenFileName_hookproc;
+ ofn.lCustData = (LPARAM)this;
+
+ _result = GetOpenFileNameW(&ofn) != 0;
+
+ _filterIndex = ofn.nFilterIndex;
+ _extension = _extension_map[ofn.nFilterIndex];
+
+ myFilename = utf16_to_ustring(_path_string, _MAX_PATH);
+
+ // Copy the selected file name, converting from UTF-16 to UTF-8
+ myFilename = utf16_to_ustring(_path_string, _MAX_PATH);
+
+ // Tidy up
+ g_free(current_directory_string);
+
+ _mutex->lock();
+ _finished = true;
+ _mutex->unlock();
+ //g_main_loop_quit(_main_loop);
+
+
+}
+
+void FileOpenDialogImplWin32::register_preview_wnd_class()
+{
+ HINSTANCE hInstance = GetModuleHandle(NULL);
+ const WNDCLASSA PreviewWndClass =
+ {
+ CS_HREDRAW | CS_VREDRAW,
+ preview_wnd_proc,
+ 0,
+ 0,
+ hInstance,
+ NULL,
+ LoadCursor(hInstance, IDC_ARROW),
+ (HBRUSH)(COLOR_BTNFACE + 1),
+ NULL,
+ PreviewWindowClassName
+ };
+
+ RegisterClassA(&PreviewWndClass);
+}
+
+UINT_PTR CALLBACK FileOpenDialogImplWin32::GetOpenFileName_hookproc(
+ HWND hdlg, UINT uiMsg, WPARAM, LPARAM lParam)
+{
+ FileOpenDialogImplWin32 *pImpl = (FileOpenDialogImplWin32*)
+ GetWindowLongPtr(hdlg, GWLP_USERDATA);
+
+ switch(uiMsg)
+ {
+ case WM_INITDIALOG:
+ {
+ HWND hParentWnd = GetParent(hdlg);
+ HINSTANCE hInstance = GetModuleHandle(NULL);
+
+ // Make the window a bit wider
+ RECT rcRect;
+ GetWindowRect(hParentWnd, &rcRect);
+ MoveWindow(hParentWnd, rcRect.left, rcRect.top,
+ rcRect.right - rcRect.left + PreviewWidening,
+ rcRect.bottom - rcRect.top,
+ FALSE);
+
+ // Set the pointer to the object
+ OPENFILENAMEW *ofn = (OPENFILENAMEW*)lParam;
+ SetWindowLongPtr(hdlg, GWLP_USERDATA, ofn->lCustData);
+ SetWindowLongPtr(hParentWnd, GWLP_USERDATA, ofn->lCustData);
+ pImpl = (FileOpenDialogImplWin32*)ofn->lCustData;
+
+ // Subclass the parent
+ pImpl->_base_window_proc = (WNDPROC)GetWindowLongPtr(hParentWnd, GWL_WNDPROC);
+ SetWindowLongPtr(hParentWnd, GWL_WNDPROC, (LONG_PTR)file_dialog_subclass_proc);
+
+ // Add a button to the toolbar
+ pImpl->_toolbar_wnd = FindWindowEx(hParentWnd, NULL, "ToolbarWindow32", NULL);
+
+ pImpl->_show_preview_button_bitmap = LoadBitmap(
+ hInstance, MAKEINTRESOURCE(IDC_SHOW_PREVIEW));
+ TBADDBITMAP tbAddBitmap = {NULL, (UINT)pImpl->_show_preview_button_bitmap};
+ const int iBitmapIndex = SendMessage(pImpl->_toolbar_wnd,
+ TB_ADDBITMAP, 1, (LPARAM)&tbAddBitmap);
+
+ TBBUTTON tbButton;
+ memset(&tbButton, 0, sizeof(TBBUTTON));
+ tbButton.iBitmap = iBitmapIndex;
+ tbButton.idCommand = IDC_SHOW_PREVIEW;
+ tbButton.fsState = (pImpl->_show_preview ? TBSTATE_CHECKED : 0)
+ | TBSTATE_ENABLED;
+ tbButton.fsStyle = TBSTYLE_CHECK;
+ tbButton.iString = (INT_PTR)_("Show Preview");
+ SendMessage(pImpl->_toolbar_wnd, TB_ADDBUTTONS, 1, (LPARAM)&tbButton);
+
+ // Create preview pane
+ register_preview_wnd_class();
+
+ pImpl->_mutex->lock();
+
+ pImpl->_file_dialog_wnd = hParentWnd;
+
+ pImpl->_preview_wnd =
+ CreateWindow(PreviewWindowClassName, "",
+ WS_CHILD | WS_VISIBLE,
+ 0, 0, 100, 100, hParentWnd, NULL, hInstance, NULL);
+ SetWindowLongPtr(pImpl->_preview_wnd, GWLP_USERDATA, ofn->lCustData);
+
+ pImpl->_mutex->unlock();
+
+ pImpl->layout_dialog();
+ }
+ break;
+
+ case WM_NOTIFY:
+ {
+
+ OFNOTIFY *pOFNotify = reinterpret_cast<OFNOTIFY*>(lParam);
+ switch(pOFNotify->hdr.code)
+ {
+ case CDN_SELCHANGE:
+ {
+ if(pImpl != NULL)
+ {
+ // Get the file name
+ pImpl->_mutex->lock();
+
+ SendMessage(pOFNotify->hdr.hwndFrom, CDM_GETFILEPATH,
+ sizeof(pImpl->_path_string) / sizeof(wchar_t),
+ (LPARAM)pImpl->_path_string);
+
+ pImpl->_file_selected = true;
+
+ pImpl->_mutex->unlock();
+
+ //pImpl->file_selected();
+ }
+ }
+ break;
+ }
+ }
+ break;
+
+ case WM_CLOSE:
+ pImpl->_mutex->lock();
+ pImpl->_preview_file_size = 0;
+
+ pImpl->_file_dialog_wnd = NULL;
+ DestroyWindow(pImpl->_preview_wnd);
+ pImpl->_preview_wnd = NULL;
+ DeleteObject(pImpl->_show_preview_button_bitmap);
+ pImpl->_show_preview_button_bitmap = NULL;
+ pImpl->_mutex->unlock();
+
+ break;
+ }
+
+ // Use default dialog behaviour
+ return 0;
+}
+
+LRESULT CALLBACK FileOpenDialogImplWin32::file_dialog_subclass_proc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+ FileOpenDialogImplWin32 *pImpl = (FileOpenDialogImplWin32*)
+ GetWindowLongPtr(hwnd, GWLP_USERDATA);
+
+ LRESULT lResult = CallWindowProc(pImpl->_base_window_proc, hwnd, uMsg, wParam, lParam);
+
+ switch(uMsg)
+ {
+ case WM_SHOWWINDOW:
+ if(wParam != 0)
+ pImpl->layout_dialog();
+ break;
+
+ case WM_SIZE:
+ pImpl->layout_dialog();
+ break;
+
+ case WM_COMMAND:
+ if(wParam == IDC_SHOW_PREVIEW)
+ {
+ const bool enable = SendMessage(pImpl->_toolbar_wnd,
+ TB_ISBUTTONCHECKED, IDC_SHOW_PREVIEW, 0) != 0;
+ pImpl->enable_preview(enable);
+ }
+ break;
+ }
+
+ return lResult;
+}
+
+LRESULT CALLBACK FileOpenDialogImplWin32::preview_wnd_proc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+ const int CaptionPadding = 4;
+ const int IconSize = 32;
+
+ FileOpenDialogImplWin32 *pImpl = (FileOpenDialogImplWin32*)
+ GetWindowLongPtr(hwnd, GWLP_USERDATA);
+
+ LRESULT lResult = 0;
+
+ switch(uMsg)
+ {
+ case WM_ERASEBKGND:
+ // Do nothing to erase the background
+ // - otherwise there'll be flicker
+ lResult = 1;
+ break;
+
+ case WM_PAINT:
+ {
+ // Get the client rect
+ RECT rcClient;
+ GetClientRect(hwnd, &rcClient);
+
+ // Prepare to paint
+ PAINTSTRUCT paint_struct;
+ HDC dc = BeginPaint(hwnd, &paint_struct);
+
+ HFONT hCaptionFont = (HFONT)SendMessage(GetParent(hwnd),
+ WM_GETFONT, 0, 0);
+ HFONT hOldFont = (HFONT)SelectObject(dc, hCaptionFont);
+ SetBkMode(dc, TRANSPARENT);
+
+ pImpl->_mutex->lock();
+
+ //FillRect(dc, &client_rect, (HBRUSH)(COLOR_HOTLIGHT+1));
+ if(pImpl->_path_string[0] == 0)
+ {
+ FillRect(dc, &rcClient, (HBRUSH)(COLOR_3DFACE + 1));
+ DrawText(dc, _("No file selected"), -1, &rcClient,
+ DT_CENTER | DT_VCENTER | DT_NOPREFIX);
+ }
+ else if(pImpl->_preview_bitmap != NULL)
+ {
+ BITMAP bitmap;
+ GetObject(pImpl->_preview_bitmap, sizeof(bitmap), &bitmap);
+ const int destX = (rcClient.right - bitmap.bmWidth) / 2;
+
+ // Render the image
+ HDC hSrcDC = CreateCompatibleDC(dc);
+ HBITMAP hOldBitmap = (HBITMAP)SelectObject(hSrcDC, pImpl->_preview_bitmap);
+
+ BitBlt(dc, destX, 0, bitmap.bmWidth, bitmap.bmHeight,
+ hSrcDC, 0, 0, SRCCOPY);
+
+ SelectObject(hSrcDC, hOldBitmap);
+ DeleteDC(hSrcDC);
+
+ // Fill in the background area
+ HRGN hEraseRgn = CreateRectRgn(rcClient.left, rcClient.top,
+ rcClient.right, rcClient.bottom);
+ HRGN hImageRgn = CreateRectRgn(destX, 0,
+ destX + bitmap.bmWidth, bitmap.bmHeight);
+ CombineRgn(hEraseRgn, hEraseRgn, hImageRgn, RGN_DIFF);
+
+ FillRgn(dc, hEraseRgn, GetSysColorBrush(COLOR_3DFACE));
+
+ DeleteObject(hImageRgn);
+ DeleteObject(hEraseRgn);
+
+ // Draw the caption on
+ RECT rcCaptionRect = {rcClient.left,
+ rcClient.top + bitmap.bmHeight + CaptionPadding,
+ rcClient.right, rcClient.bottom};
+
+ WCHAR szCaption[_MAX_FNAME + 32];
+ const int iLength = pImpl->format_caption(
+ szCaption, sizeof(szCaption) / sizeof(WCHAR));
+
+ DrawTextW(dc, szCaption, iLength, &rcCaptionRect,
+ DT_CENTER | DT_TOP | DT_NOPREFIX | DT_PATH_ELLIPSIS);
+ }
+ else if(pImpl->_preview_file_icon != NULL)
+ {
+ FillRect(dc, &rcClient, (HBRUSH)(COLOR_3DFACE + 1));
+
+ // Draw the files icon
+ const int destX = (rcClient.right - IconSize) / 2;
+ DrawIconEx(dc, destX, 0, pImpl->_preview_file_icon,
+ IconSize, IconSize, 0, NULL,
+ DI_NORMAL | DI_COMPAT);
+
+ // Draw the caption on
+ RECT rcCaptionRect = {rcClient.left,
+ rcClient.top + IconSize + CaptionPadding,
+ rcClient.right, rcClient.bottom};
+
+ WCHAR szFileName[_MAX_FNAME], szCaption[_MAX_FNAME + 32];
+ _wsplitpath(pImpl->_path_string, NULL, NULL, szFileName, NULL);
+
+ const int iLength = snwprintf(szCaption,
+ sizeof(szCaption), L"%s\n%d kB",
+ szFileName, pImpl->_preview_file_size);
+
+ DrawTextW(dc, szCaption, iLength, &rcCaptionRect,
+ DT_CENTER | DT_TOP | DT_NOPREFIX | DT_PATH_ELLIPSIS);
+ }
+ else
+ {
+ // Can't show anything!
+ FillRect(dc, &rcClient, (HBRUSH)(COLOR_3DFACE + 1));
+ }
+
+ pImpl->_mutex->unlock();
+
+ // Finish painting
+ SelectObject(dc, hOldFont);
+ EndPaint(hwnd, &paint_struct);
+ }
+
+ break;
+
+ case WM_DESTROY:
+ pImpl->free_preview();
+ break;
+
+ default:
+ lResult = DefWindowProc(hwnd, uMsg, wParam, lParam);
+ break;
+ }
+
+ return lResult;
+}
+
+void FileOpenDialogImplWin32::enable_preview(bool enable)
+{
+ _show_preview = enable;
+
+ // Relayout the dialog
+ ShowWindow(_preview_wnd, enable ? SW_SHOW : SW_HIDE);
+ layout_dialog();
+
+ // Load or unload the preview
+ if(enable)
+ {
+ _mutex->lock();
+ _file_selected = true;
+ _mutex->unlock();
+ }
+ else free_preview();
+}
+
+void FileOpenDialogImplWin32::layout_dialog()
+{
+ union RECTPOINTS
+ {
+ RECT r;
+ POINT p[2];
+ };
+
+ const float MaxExtentScale = 2.0f / 3.0f;
+
+ RECT rcClient;
+ GetClientRect(_file_dialog_wnd, &rcClient);
+
+ // Re-layout the dialog
+ HWND hFileListWnd = GetDlgItem(_file_dialog_wnd, lst2);
+ HWND hFolderComboWnd = GetDlgItem(_file_dialog_wnd, cmb2);
+
+
+ RECT rcFolderComboRect;
+ RECTPOINTS rcFileList;
+ GetWindowRect(hFileListWnd, &rcFileList.r);
+ GetWindowRect(hFolderComboWnd, &rcFolderComboRect);
+ const int iPadding = rcFileList.r.top - rcFolderComboRect.bottom;
+ MapWindowPoints(NULL, _file_dialog_wnd, rcFileList.p, 2);
+
+ RECT rcPreview;
+ RECT rcBody = {rcFileList.r.left, rcFileList.r.top,
+ rcClient.right - iPadding, rcFileList.r.bottom};
+ rcFileList.r.right = rcBody.right;
+
+ if(_show_preview)
+ {
+ rcPreview.top = rcBody.top;
+ rcPreview.left = rcClient.right - (rcBody.bottom - rcBody.top);
+ const int iMaxExtent = (int)(MaxExtentScale * (float)(rcBody.left + rcBody.right)) + iPadding / 2;
+ if(rcPreview.left < iMaxExtent) rcPreview.left = iMaxExtent;
+ rcPreview.bottom = rcBody.bottom;
+ rcPreview.right = rcBody.right;
+
+ // Re-layout the preview box
+ _mutex->lock();
+
+ _preview_width = rcPreview.right - rcPreview.left;
+ _preview_height = rcPreview.bottom - rcPreview.top;
+
+ _mutex->unlock();
+
+ render_preview();
+
+ MoveWindow(_preview_wnd, rcPreview.left, rcPreview.top,
+ _preview_width, _preview_height, TRUE);
+
+ rcFileList.r.right = rcPreview.left - iPadding;
+ }
+
+ // Re-layout the file list box
+ MoveWindow(hFileListWnd, rcFileList.r.left, rcFileList.r.top,
+ rcFileList.r.right - rcFileList.r.left,
+ rcFileList.r.bottom - rcFileList.r.top, TRUE);
+
+ // Re-layout the toolbar
+ RECTPOINTS rcToolBar;
+ GetWindowRect(_toolbar_wnd, &rcToolBar.r);
+ MapWindowPoints(NULL, _file_dialog_wnd, rcToolBar.p, 2);
+ MoveWindow(_toolbar_wnd, rcToolBar.r.left, rcToolBar.r.top,
+ rcToolBar.r.right - rcToolBar.r.left, rcToolBar.r.bottom - rcToolBar.r.top, TRUE);
+}
+
+void FileOpenDialogImplWin32::file_selected()
+{
+ // Destroy any previous previews
+ free_preview();
+
+
+ // Determine if the file exists
+ DWORD attributes = GetFileAttributesW(_path_string);
+ if(attributes == 0xFFFFFFFF ||
+ attributes == FILE_ATTRIBUTE_DIRECTORY)
+ {
+ InvalidateRect(_preview_wnd, NULL, FALSE);
+ return;
+ }
+
+ // Check the file exists and get the file size
+ HANDLE file_handle = CreateFileW(_path_string, GENERIC_READ,
+ FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
+ if(file_handle == INVALID_HANDLE_VALUE) return;
+ const DWORD file_size = GetFileSize(file_handle, NULL);
+ if (file_size == INVALID_FILE_SIZE) return;
+ _preview_file_size = file_size / 1024;
+ CloseHandle(file_handle);
+
+ if(_show_preview) load_preview();
+}
+
+void FileOpenDialogImplWin32::load_preview()
+{
+ // Destroy any previous previews
+ free_preview();
+
+ // Try to get the file icon
+ SHFILEINFOW fileInfo;
+ if(SUCCEEDED(SHGetFileInfoW(_path_string, 0, &fileInfo,
+ sizeof(fileInfo), SHGFI_ICON | SHGFI_LARGEICON)))
+ _preview_file_icon = fileInfo.hIcon;
+
+ // Will this file be too big?
+ if(_preview_file_size > MaxPreviewFileSize)
+ {
+ InvalidateRect(_preview_wnd, NULL, FALSE);
+ return;
+ }
+
+ // Prepare to render a preview
+ const Glib::ustring svg = ".svg";
+ const Glib::ustring svgz = ".svgz";
+ const Glib::ustring path = utf16_to_ustring(_path_string);
+
+ bool success = false;
+
+ _preview_document_width = _preview_document_height = 0;
+
+ if ((dialogType == SVG_TYPES || dialogType == IMPORT_TYPES) &&
+ (hasSuffix(path, svg) || hasSuffix(path, svgz)))
+ success = set_svg_preview();
+ else if (isValidImageFile(path))
+ success = set_image_preview();
+ else {
+ // Show no preview
+ }
+
+ if(success) render_preview();
+
+ InvalidateRect(_preview_wnd, NULL, FALSE);
+}
+
+void FileOpenDialogImplWin32::free_preview()
+{
+ _mutex->lock();
+ if(_preview_bitmap != NULL)
+ DeleteObject(_preview_bitmap);
+ _preview_bitmap = NULL;
+
+ if(_preview_file_icon != NULL)
+ DestroyIcon(_preview_file_icon);
+ _preview_file_icon = NULL;
+
+ _preview_bitmap_image.clear();
+ _mutex->unlock();
+}
+
+bool FileOpenDialogImplWin32::set_svg_preview()
+{
+ const int PreviewSize = 512;
+
+ gchar *utf8string = g_utf16_to_utf8((const gunichar2*)_path_string,
+ _MAX_PATH, NULL, NULL, NULL);
+ SPDocument *svgDoc = sp_document_new (utf8string, true);
+ g_free(utf8string);
+
+ // Check the document loaded properly
+ if(svgDoc == NULL) return false;
+ if(svgDoc->root == NULL)
+ {
+ sp_document_unref(svgDoc);
+ return false;
+ }
+
+ // Get the size of the document
+ const double svgWidth = sp_document_width(svgDoc);
+ const double svgHeight = sp_document_height(svgDoc);
+
+ // Find the minimum scale to fit the image inside the preview area
+ const double scaleFactorX = PreviewSize / svgWidth;
+ const double scaleFactorY = PreviewSize / svgHeight;
+ const double scaleFactor = (scaleFactorX > scaleFactorY) ? scaleFactorY : scaleFactorX;
+
+ // Now get the resized values
+ const double scaledSvgWidth = scaleFactor * svgWidth;
+ const double scaledSvgHeight = scaleFactor * svgHeight;
+
+ NR::Rect area(NR::Point(0, 0), NR::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);
+ sp_document_ensure_up_to_date (svgDoc);
+ sp_item_invoke_bbox((SPItem *) svgDoc->root, &maybeArea,
+ sp_item_i2r_affine((SPItem *)(svgDoc->root)), TRUE);
+
+ NRArena *const arena = NRArena::create();
+
+ unsigned const key = sp_item_display_key_new(1);
+
+ NRArenaItem *root = sp_item_invoke_show((SPItem*)(svgDoc->root),
+ arena, key, SP_ITEM_SHOW_DISPLAY);
+
+ NRGC gc(NULL);
+ nr_matrix_set_scale(&gc.transform, scaleFactor, scaleFactor);
+
+ nr_arena_item_invoke_update (root, NULL, &gc,
+ NR_ARENA_ITEM_STATE_ALL, NR_ARENA_ITEM_STATE_NONE);
+
+ // Prepare a GDI compatible NRPixBlock
+ NRPixBlock pixBlock;
+ pixBlock.size = NR_PIXBLOCK_SIZE_BIG;
+ pixBlock.mode = NR_PIXBLOCK_MODE_R8G8B8;
+ pixBlock.empty = 1;
+ pixBlock.visible_area.x0 = pixBlock.area.x0 = 0;
+ pixBlock.visible_area.y0 = pixBlock.area.y0 = 0;
+ pixBlock.visible_area.x1 = pixBlock.area.x1 = scaledSvgWidth;
+ pixBlock.visible_area.y1 = pixBlock.area.y1 = scaledSvgHeight;
+ pixBlock.rs = 4 * ((3 * (int)scaledSvgWidth + 3) / 4);
+ pixBlock.data.px = g_try_new (unsigned char, pixBlock.rs * scaledSvgHeight);
+
+ // Fail if the pixblock failed to allocate
+ if(pixBlock.data.px == NULL)
+ {
+ sp_document_unref(svgDoc);
+ return false;
+ }
+
+ memset(pixBlock.data.px, 0xFF, pixBlock.rs * scaledSvgHeight);
+
+ memcpy(&root->bbox, &areaL, sizeof(areaL));
+
+ // Render the image
+ nr_arena_item_invoke_render(NULL, root, &bbox, &pixBlock, /*0*/NR_ARENA_ITEM_RENDER_NO_CACHE);
+
+ // 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
+ _mutex->lock();
+
+ _preview_bitmap_image = Gdk::Pixbuf::create_from_data(
+ pixBlock.data.px, Gdk::COLORSPACE_RGB, false, 8,
+ (int)scaledSvgWidth, (int)scaledSvgHeight, pixBlock.rs,
+ sigc::ptr_fun(destroy_svg_rendering));
+
+ _preview_document_width = scaledSvgWidth;
+ _preview_document_height = scaledSvgHeight;
+ _preview_image_width = svgWidth;
+ _preview_image_height = svgHeight;
+
+ _mutex->unlock();
+
+ return true;
+}
+
+void FileOpenDialogImplWin32::destroy_svg_rendering(const guint8 *buffer)
+{
+ g_assert(buffer != NULL);
+ g_free((void*)buffer);
+}
+
+bool FileOpenDialogImplWin32::set_image_preview()
+{
+ const Glib::ustring path = utf16_to_ustring(_path_string, _MAX_PATH);
+
+ _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;
+
+ _mutex->unlock();
+
+ return true;
+}
+
+void FileOpenDialogImplWin32::render_preview()
+{
+ double x, y;
+ const double blurRadius = 8;
+ const double halfBlurRadius = blurRadius / 2;
+ const int shaddowOffsetX = 0;
+ const int shaddowOffsetY = 2;
+ const int pagePadding = 5;
+ const double shaddowAlpha = 0.75;
+
+ // Is the preview showing?
+ if(!_show_preview)
+ return;
+
+ // Do we have anything to render?
+ _mutex->lock();
+
+ if(!_preview_bitmap_image)
+ {
+ _mutex->unlock();
+ return;
+ }
+
+ // Tidy up any previous bitmap renderings
+ if(_preview_bitmap != NULL)
+ DeleteObject(_preview_bitmap);
+ _preview_bitmap = NULL;
+
+ // Calculate the size of the caption
+ int captionHeight = 0;
+
+ if(_preview_wnd != NULL)
+ {
+ RECT rcCaptionRect;
+ WCHAR szCaption[_MAX_FNAME + 32];
+ const int iLength = format_caption(szCaption,
+ sizeof(szCaption) / sizeof(WCHAR));
+
+ HDC dc = GetDC(_preview_wnd);
+ DrawTextW(dc, szCaption, iLength, &rcCaptionRect,
+ DT_CENTER | DT_TOP | DT_NOPREFIX | DT_PATH_ELLIPSIS | DT_CALCRECT);
+ ReleaseDC(_preview_wnd, dc);
+
+ captionHeight = rcCaptionRect.bottom - rcCaptionRect.top;
+ }
+
+ // Find the minimum scale to fit the image inside the preview area
+ const double scaleFactorX =
+ ((double)_preview_width - pagePadding * 2 - blurRadius) / _preview_document_width;
+ const double scaleFactorY =
+ ((double)_preview_height - pagePadding * 2
+ - shaddowOffsetY - halfBlurRadius - captionHeight) / _preview_document_height;
+ double scaleFactor = (scaleFactorX > scaleFactorY) ? scaleFactorY : scaleFactorX;
+ scaleFactor = (scaleFactor > 1.0) ? 1.0 : scaleFactor;
+
+ // Now get the resized values
+ const double scaledSvgWidth = scaleFactor * _preview_document_width;
+ const double scaledSvgHeight = scaleFactor * _preview_document_height;
+
+ const int svgX = pagePadding + halfBlurRadius;
+ const int svgY = pagePadding;
+
+ const int frameX = svgX - pagePadding;
+ const int frameY = svgY - pagePadding;
+ const int frameWidth = scaledSvgWidth + pagePadding * 2;
+ const int frameHeight = scaledSvgHeight + pagePadding * 2;
+
+ const int totalWidth = (int)ceil(frameWidth + blurRadius);
+ const int totalHeight = (int)ceil(frameHeight + blurRadius);
+
+ // Prepare the drawing surface
+ HDC hDC = GetDC(_preview_wnd);
+ HDC hMemDC = CreateCompatibleDC(hDC);
+ _preview_bitmap = CreateCompatibleBitmap(hDC, totalWidth, totalHeight);
+ HBITMAP hOldBitmap = (HBITMAP)SelectObject(hMemDC, _preview_bitmap);
+ Cairo::RefPtr<Win32Surface> surface = Win32Surface::create(hMemDC);
+ Cairo::RefPtr<Context> context = Context::create(surface);
+
+ // Paint the background to match the dialog colour
+ const COLORREF background = GetSysColor(COLOR_3DFACE);
+ context->set_source_rgb(
+ GetRValue(background) / 255.0,
+ GetGValue(background) / 255.0,
+ GetBValue(background) / 255.0);
+ context->paint();
+
+ //----- Draw the drop shaddow -----//
+
+ // Left Edge
+ x = frameX + shaddowOffsetX - halfBlurRadius;
+ Cairo::RefPtr<LinearGradient> leftEdgeFade = LinearGradient::create(
+ x, 0.0, x + blurRadius, 0.0);
+ leftEdgeFade->add_color_stop_rgba (0, 0, 0, 0, 0);
+ leftEdgeFade->add_color_stop_rgba (1, 0, 0, 0, shaddowAlpha);
+ context->set_source(leftEdgeFade);
+ context->rectangle (x, frameY + shaddowOffsetY + halfBlurRadius,
+ blurRadius, frameHeight - blurRadius);
+ context->fill();
+
+ // Right Edge
+ x = frameX + frameWidth + shaddowOffsetX - halfBlurRadius;
+ Cairo::RefPtr<LinearGradient> rightEdgeFade = LinearGradient::create(
+ x, 0.0, x + blurRadius, 0.0);
+ rightEdgeFade->add_color_stop_rgba (0, 0, 0, 0, shaddowAlpha);
+ rightEdgeFade->add_color_stop_rgba (1, 0, 0, 0, 0);
+ context->set_source(rightEdgeFade);
+ context->rectangle (frameX + frameWidth + shaddowOffsetX - halfBlurRadius,
+ frameY + shaddowOffsetY + halfBlurRadius,
+ blurRadius, frameHeight - blurRadius);
+ context->fill();
+
+ // Top Edge
+ y = frameY + shaddowOffsetY - halfBlurRadius;
+ Cairo::RefPtr<LinearGradient> topEdgeFade = LinearGradient::create(
+ 0.0, y, 0.0, y + blurRadius);
+ topEdgeFade->add_color_stop_rgba (0, 0, 0, 0, 0);
+ topEdgeFade->add_color_stop_rgba (1, 0, 0, 0, shaddowAlpha);
+ context->set_source(topEdgeFade);
+ context->rectangle (frameX + shaddowOffsetX + halfBlurRadius, y,
+ frameWidth - blurRadius, blurRadius);
+ context->fill();
+
+ // Bottom Edge
+ y = frameY + frameHeight + shaddowOffsetY - halfBlurRadius;
+ Cairo::RefPtr<LinearGradient> bottomEdgeFade = LinearGradient::create(
+ 0.0, y, 0.0, y + blurRadius);
+ bottomEdgeFade->add_color_stop_rgba (0, 0, 0, 0, shaddowAlpha);
+ bottomEdgeFade->add_color_stop_rgba (1, 0, 0, 0, 0);
+ context->set_source(bottomEdgeFade);
+ context->rectangle (frameX + shaddowOffsetX + halfBlurRadius, y,
+ frameWidth - blurRadius, blurRadius);
+ context->fill();
+
+ // Top Left Corner
+ x = frameX + shaddowOffsetX - halfBlurRadius;
+ y = frameY + shaddowOffsetY - halfBlurRadius;
+ Cairo::RefPtr<RadialGradient> topLeftCornerFade = RadialGradient::create(
+ x + blurRadius, y + blurRadius, 0, x + blurRadius, y + blurRadius, blurRadius);
+ topLeftCornerFade->add_color_stop_rgba (0, 0, 0, 0, shaddowAlpha);
+ topLeftCornerFade->add_color_stop_rgba (1, 0, 0, 0, 0);
+ context->set_source(topLeftCornerFade);
+ context->rectangle (x, y, blurRadius, blurRadius);
+ context->fill();
+
+ // Top Right Corner
+ x = frameX + frameWidth + shaddowOffsetX - halfBlurRadius;
+ y = frameY + shaddowOffsetY - halfBlurRadius;
+ Cairo::RefPtr<RadialGradient> topRightCornerFade = RadialGradient::create(
+ x, y + blurRadius, 0, x, y + blurRadius, blurRadius);
+ topRightCornerFade->add_color_stop_rgba (0, 0, 0, 0, shaddowAlpha);
+ topRightCornerFade->add_color_stop_rgba (1, 0, 0, 0, 0);
+ context->set_source(topRightCornerFade);
+ context->rectangle (x, y, blurRadius, blurRadius);
+ context->fill();
+
+ // Bottom Left Corner
+ x = frameX + shaddowOffsetX - halfBlurRadius;
+ y = frameY + frameHeight + shaddowOffsetY - halfBlurRadius;
+ Cairo::RefPtr<RadialGradient> bottomLeftCornerFade = RadialGradient::create(
+ x + blurRadius, y, 0, x + blurRadius, y, blurRadius);
+ bottomLeftCornerFade->add_color_stop_rgba (0, 0, 0, 0, shaddowAlpha);
+ bottomLeftCornerFade->add_color_stop_rgba (1, 0, 0, 0, 0);
+ context->set_source(bottomLeftCornerFade);
+ context->rectangle (x, y, blurRadius, blurRadius);
+ context->fill();
+
+ // Bottom Right Corner
+ x = frameX + frameWidth + shaddowOffsetX - halfBlurRadius;
+ y = frameY + frameHeight + shaddowOffsetY - halfBlurRadius;
+ Cairo::RefPtr<RadialGradient> bottomRightCornerFade = RadialGradient::create(
+ x, y, 0, x, y, blurRadius);
+ bottomRightCornerFade->add_color_stop_rgba (0, 0, 0, 0, shaddowAlpha);
+ bottomRightCornerFade->add_color_stop_rgba (1, 0, 0, 0, 0);
+ context->set_source(bottomRightCornerFade);
+ context->rectangle (frameX + frameWidth + shaddowOffsetX - halfBlurRadius,
+ frameY + frameHeight + shaddowOffsetY - halfBlurRadius,
+ blurRadius, blurRadius);
+ context->fill();
+
+ // Draw the frame
+ context->set_line_width(1);
+ context->rectangle (frameX, frameY, frameWidth, frameHeight);
+
+ context->set_source_rgb(1.0, 1.0, 1.0);
+ context->fill_preserve();
+ context->set_source_rgb(0.25, 0.25, 0.25);
+ context->stroke_preserve();
+
+ // Draw the image
+
+ if(_preview_bitmap_image) // Is the image a pixbuf?
+ {
+ // Set the transformation
+ const Matrix matrix = {
+ scaleFactor, 0,
+ 0, scaleFactor,
+ svgX, svgY };
+ context->set_matrix (matrix);
+
+ // Render the image
+ set_source_pixbuf (context, _preview_bitmap_image, 0, 0);
+ context->paint();
+
+ // Reset the transformation
+ context->set_identity_matrix();
+ }
+
+ // Draw the inner frame
+ context->set_source_rgb(0.75, 0.75, 0.75);
+ context->rectangle (svgX, svgY, scaledSvgWidth, scaledSvgHeight);
+ context->stroke();
+
+ _mutex->unlock();
+
+ // Finish drawing
+ surface->finish();
+ SelectObject(hMemDC, hOldBitmap) ;
+ DeleteDC(hMemDC);
+
+ // Refresh the preview pane
+ InvalidateRect(_preview_wnd, NULL, FALSE);
+}
+
+int FileOpenDialogImplWin32::format_caption(wchar_t *caption, int caption_size)
+{
+ wchar_t szFileName[_MAX_FNAME];
+ _wsplitpath(_path_string, NULL, NULL, szFileName, NULL);
+
+ return snwprintf(caption, caption_size,
+ L"%s\n%d kB\n%d \xD7 %d", szFileName, _preview_file_size,
+ (int)_preview_document_width, (int)_preview_document_height);
+}
+
+/**
+ * Show this dialog modally. Return true if user hits [OK]
+ */
+bool
+FileOpenDialogImplWin32::show()
+{
+ // We can only run one worker thread at a time
+ //if(_mutex != NULL) return false;
+
+ if(!Glib::thread_supported())
+ Glib::thread_init();
+
+ _result = false;
+ _finished = false;
+ _file_selected = false;
+ _mutex = new Glib::Mutex();
+ _main_loop = g_main_loop_new(g_main_context_default(), FALSE);
+
+ if(Glib::Thread::create(sigc::mem_fun(*this, &FileOpenDialogImplWin32::GetOpenFileName_thread), true))
+ {
+ while(1)
+ {
+ g_main_context_iteration(g_main_context_default(), FALSE);
+
+ if(_mutex->trylock())
+ {
+ // Read mutexed data
+ const bool finished = _finished;
+ const bool is_file_selected = _file_selected;
+ _file_selected = false;
+ _mutex->unlock();
+
+ if(finished) break;
+ if(is_file_selected) file_selected();
+ }
+
+ Sleep(10);
+ }
+ //g_main_loop_run(_main_loop);
+ }
+
+ // Tidy up
+ delete _mutex;
+ _mutex = NULL;
+
+ return _result;
+}
+
+/**
+ * To Get Multiple filenames selected at-once.
+ */
+std::vector<Glib::ustring>FileOpenDialogImplWin32::getFilenames()
+{
+ std::vector<Glib::ustring> result;
+ result.push_back(getFilename());
+ return result;
+}
+
+
+/*#########################################################################
+### F I L E S A V E
+#########################################################################*/
+
+/**
+ * Constructor
+ */
+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")
+{
+ _main_loop = NULL;
+
+ createFilterMenu();
+}
+
+FileSaveDialogImplWin32::~FileSaveDialogImplWin32()
+{
+}
+
+void FileSaveDialogImplWin32::createFilterMenu()
+{
+ list<Filter> filter_list;
+
+ knownExtensions.clear();
+
+ // Compose the filter string
+ Glib::ustring all_inkscape_files_filter, all_image_files_filter;
+ Inkscape::Extension::DB::OutputList extension_list;
+ Inkscape::Extension::db.get_output_list(extension_list);
+
+ int filter_count = 0;
+ int filter_length = 0;
+
+ for (Inkscape::Extension::DB::OutputList::iterator current_item = extension_list.begin();
+ current_item != extension_list.end(); current_item++)
+ {
+ Inkscape::Extension::Output *omod = *current_item;
+ if (omod->deactivated()) continue;
+
+ filter_count++;
+
+ Filter filter;
+
+ // Extension
+ const gchar *filter_extension = omod->get_extension();
+ filter.filter = g_utf8_to_utf16(
+ filter_extension, -1, NULL, &filter.filter_length, NULL);
+ knownExtensions.insert( Glib::ustring(filter_extension).casefold() );
+
+ // Type
+ filter.name = g_utf8_to_utf16(
+ omod->get_filetypename(), -1, NULL, &filter.name_length, NULL);
+
+ filter.mod = omod;
+
+ filter_length += filter.name_length +
+ filter.filter_length + 3; // Add 3 for two \0s and a *
+
+ filter_list.push_back(filter);
+ }
+
+ int extension_index = 0;
+ _extension_map = new Inkscape::Extension::Extension*[filter_count];
+
+ _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++)
+ {
+ const Filter &filter = *filter_iterator;
+
+ memcpy(filterptr, filter.name, filter.name_length * 2);
+ filterptr += filter.name_length;
+ g_free(filter.name);
+
+ *(filterptr++) = L'\0';
+ *(filterptr++) = L'*';
+
+ memcpy(filterptr, filter.filter, filter.filter_length * 2);
+ filterptr += filter.filter_length;
+ g_free(filter.filter);
+
+ *(filterptr++) = L'\0';
+
+ // Associate this input extension with the file type name
+ _extension_map[extension_index++] = filter.mod;
+ }
+ *(filterptr++) = 0;
+
+ _filterIndex = 0;
+}
+
+void FileSaveDialogImplWin32::GetSaveFileName_thread()
+{
+ OPENFILENAMEEXW ofn;
+
+ g_assert(this != NULL);
+ //g_assert(_mutex != NULL);
+ g_assert(_main_loop != NULL);
+
+ gunichar2* current_directory_string = g_utf8_to_utf16(
+ _current_directory.data(), -1, NULL, NULL, NULL);
+
+ // Copy the selected file name, converting from UTF-8 to UTF-16
+ memset(_path_string, 0, sizeof(_path_string));
+ gunichar2* utf16_path_string = g_utf8_to_utf16(
+ myFilename.data(), -1, NULL, NULL, NULL);
+ wcsncpy(_path_string, (wchar_t*)utf16_path_string, _MAX_PATH);
+ g_free(utf16_path_string);
+
+ ZeroMemory(&ofn, sizeof(ofn));
+ ofn.lStructSize = sizeof(ofn);
+ ofn.hwndOwner = _ownerHwnd;
+ ofn.lpstrFile = _path_string;
+ ofn.nMaxFile = _MAX_PATH;
+ ofn.nFilterIndex = _filterIndex;
+ ofn.lpstrFileTitle = NULL;
+ ofn.nMaxFileTitle = 0;
+ ofn.lpstrInitialDir = (wchar_t*)current_directory_string;
+ ofn.lpstrTitle = _title;
+ ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST;
+ ofn.lpstrFilter = _filter;
+ ofn.nFilterIndex = _filterIndex;
+
+ _result = GetSaveFileNameW(&ofn) != 0;
+
+ _filterIndex = ofn.nFilterIndex;
+ _extension = _extension_map[ofn.nFilterIndex];
+
+ // Copy the selected file name, converting from UTF-16 to UTF-8
+ myFilename = utf16_to_ustring(_path_string, _MAX_PATH);
+
+ //_mutex->lock();
+ //_finished = true;
+ //_mutex->unlock();
+
+
+ // Tidy up
+ g_free(current_directory_string);
+
+ g_main_loop_quit(_main_loop);
+}
+
+/**
+ * Show this dialog modally. Return true if user hits [OK]
+ */
+bool
+FileSaveDialogImplWin32::show()
+{
+ // We can only run one worker thread at a time
+ //if(_mutex != NULL) return false;
+
+ if(!Glib::thread_supported())
+ Glib::thread_init();
+
+ _result = false;
+ //_finished = false;
+ //_mutex = new Glib::Mutex();
+ _main_loop = g_main_loop_new(g_main_context_default(), FALSE);
+
+ if(Glib::Thread::create(sigc::mem_fun(*this, &FileSaveDialogImplWin32::GetSaveFileName_thread), true))
+ {
+ /*while(1)
+ {
+ // While the dialog runs - keep the main UI alive
+ g_main_context_iteration(g_main_context_default(), FALSE);
+
+ if(_mutex->trylock())
+ {
+ if(_finished) break;
+ _mutex->unlock();
+ }
+
+ Sleep(10);
+ }*/
+ g_main_loop_run(_main_loop);
+ }
+ //delete _mutex;
+ //_mutex = NULL;
+
+ if(_result)
+ appendExtension(myFilename, (Inkscape::Extension::Output*)_extension);
+
+ return _result;
+}
+
+void FileSaveDialogImplWin32::setSelectionType( Inkscape::Extension::Extension * /*key*/ )
+{
+ // If no pointer to extension is passed in, look up based on filename extension.
+
+}
+
+}
+}
+}
+
+#endif
+
+/*
+ Local Variables:
+ mode:c++
+ c-file-style:"stroustrup"
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
+ indent-tabs-mode:nil
+ fill-column:99
+ End:
+*/
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :
diff --git a/src/ui/dialog/filedialogimpl-win32.h b/src/ui/dialog/filedialogimpl-win32.h new file mode 100644 index 000000000..1b69c1993 --- /dev/null +++ b/src/ui/dialog/filedialogimpl-win32.h @@ -0,0 +1,348 @@ +/**
+ * Implementation of the file dialog interfaces defined in filedialog.h for Win32
+ *
+ * Authors:
+ * Joel Holdsworth
+ * The Inkscape Organization
+ *
+ * Copyright (C) 2004-2007 The Inkscape Organization
+ *
+ * Released under GNU GPL, read the file 'COPYING' for more information
+ */
+
+#ifdef WIN32
+
+#include "gc-core.h"
+#include <windows.h>
+
+namespace Inkscape
+{
+namespace UI
+{
+namespace Dialog
+{
+
+/*#########################################################################
+### F I L E D I A L O G B A S E C L A S S
+#########################################################################*/
+
+/// This class is the base implementation of a MS Windows
+/// file dialog.
+class FileDialogBaseWin32
+{
+protected:
+ /// Abstract Constructor
+ /// @param parent The parent window for the dialog
+ /// @param dir The directory to begin browing from
+ /// @param title The title caption for the dialog in UTF-8
+ /// @param type The dialog type
+ /// @param preferenceBase The preferences key
+ FileDialogBaseWin32(Gtk::Window &parent, const Glib::ustring &dir,
+ const char *title, FileDialogType type,
+ gchar const *preferenceBase);
+
+ /// Destructor
+ ~FileDialogBaseWin32();
+
+public:
+
+ /// Gets the currently selected extension. Valid after an [OK]
+ /// @return Returns a pointer to the selected extension, or NULL
+ /// if the selected filter requires an automatic type detection
+ Inkscape::Extension::Extension* getSelectionType();
+
+ /// Get the path of the current directory
+ Glib::ustring getCurrentDirectory();
+
+protected:
+ /// The dialog type
+ FileDialogType dialogType;
+
+ /// This mutex is used to ensure that the worker thread
+ /// that calls GetOpenFileName cannot collide with the
+ /// main Inkscape thread
+ Glib::Mutex *_mutex;
+
+ /// This flag is set true when the GetOpenFileName call
+ /// has returned
+ bool _finished;
+
+ /// A pointer to the GTK main-loop context object. This
+ /// is used to keep the rest of the inkscape UI running
+ /// while the file dialog is displayed
+ GMainLoop *_main_loop;
+
+ /// The result of the call to GetOpenFileName. If true
+ /// the user clicked OK, if false the user clicked cancel
+ bool _result;
+
+ /// The parent window
+ Gtk::Window &parent;
+
+ /// The windows handle of the parent window
+ HWND _ownerHwnd;
+
+ /// The path of the directory that is currently being
+ /// browsed
+ Glib::ustring _current_directory;
+
+ /// The title of the dialog in UTF-16
+ wchar_t *_title;
+
+ /// The path of the currently selected file in UTF-16
+ wchar_t _path_string[_MAX_PATH];
+
+ /// The filter string for GetOpenFileName in UTF-16
+ wchar_t *_filter;
+
+ /// The index of the currently selected filter
+ int _filterIndex;
+
+ /// An array of the extensions associated with the
+ /// file types of each filter. So the Nth entry of
+ /// this array corresponds to the extension of the Nth
+ /// filter in the list. NULL if no specific extension is
+ /// specified/
+ Inkscape::Extension::Extension **_extension_map;
+
+ /// The currently selected extension. Valid after an [OK]
+ Inkscape::Extension::Extension *_extension;
+};
+
+
+/*#########################################################################
+### F I L E O P E N
+#########################################################################*/
+
+/// An Inkscape compatible wrapper around MS Windows GetOpenFileName API
+class FileOpenDialogImplWin32 : public FileOpenDialog, public FileDialogBaseWin32
+{
+public:
+ /// Constructor
+ /// @param parent The parent window for the dialog
+ /// @param dir The directory to begin browing from
+ /// @param title The title caption for the dialog in UTF-8
+ /// @param type The dialog type
+ FileOpenDialogImplWin32(Gtk::Window &parent,
+ const Glib::ustring &dir,
+ FileDialogType fileTypes,
+ const char *title);
+
+ /// Destructor
+ virtual ~FileOpenDialogImplWin32();
+
+ /// Shows the file dialog, and blocks until a file
+ /// has been selected.
+ /// @return Returns true if the the user selected a
+ /// file, or false if the user pressed cancel.
+ bool show();
+
+ /// Gets a list of the selected file names
+ /// @return Returns an STL vector filled with the
+ /// GTK names of the selected files
+ std::vector<Glib::ustring> getFilenames();
+
+ /// Get the path of the current directory
+ virtual Glib::ustring getCurrentDirectory()
+ { return FileDialogBaseWin32::getCurrentDirectory(); }
+
+ /// Gets the currently selected extension. Valid after an [OK]
+ /// @return Returns a pointer to the selected extension, or NULL
+ /// if the selected filter requires an automatic type detection
+ virtual Inkscape::Extension::Extension* getSelectionType()
+ { return FileDialogBaseWin32::getSelectionType(); }
+
+private:
+
+ /// Create a filter menu for this type of dialog
+ void createFilterMenu();
+
+ /// The handle of the preview pane window
+ HWND _preview_wnd;
+
+ /// The handle of the file dialog window
+ HWND _file_dialog_wnd;
+
+ /// A pointer to the standard window proc of the
+ /// unhooked file dialog
+ WNDPROC _base_window_proc;
+
+ /// The handle of the bitmap of the "show preview"
+ /// toggle button
+ HBITMAP _show_preview_button_bitmap;
+
+ /// The handle of the toolbar's window
+ HWND _toolbar_wnd;
+
+ /// This flag is set true when the preview should be
+ /// shown, or false when it should be hidden
+ static bool _show_preview;
+
+
+ /// The current width of the preview pane in pixels
+ int _preview_width;
+
+ /// The current height of the preview pane in pixels
+ int _preview_height;
+
+ /// The handle of the windows to display within the
+ /// preview pane, or NULL if no image should be displayed
+ HBITMAP _preview_bitmap;
+
+ /// The windows shell icon for the selected file
+ HICON _preview_file_icon;
+
+ /// The size of the preview file in kilobytes
+ unsigned long _preview_file_size;
+
+
+ /// The width of the document to be shown in the preview panel
+ double _preview_document_width;
+
+ /// The width of the document to be shown in the preview panel
+ double _preview_document_height;
+
+ /// The width of the rendered preview image in pixels
+ int _preview_image_width;
+
+ /// The height of the rendered preview image in pixels
+ int _preview_image_height;
+
+ /// A GDK Pixbuf of the rendered preview to be displayed
+ Glib::RefPtr<Gdk::Pixbuf> _preview_bitmap_image;
+
+ /// This flag is set true if a file has been selected
+ bool _file_selected;
+
+
+ /// The controller function for the thread which calls
+ /// GetOpenFileName
+ void GetOpenFileName_thread();
+
+ /// Registers the Windows Class of the preview panel window
+ static void register_preview_wnd_class();
+
+ /// A message proc which is called by the standard dialog
+ /// proc
+ static UINT_PTR CALLBACK GetOpenFileName_hookproc(HWND hdlg, UINT uiMsg, WPARAM wParam, LPARAM lParam);
+
+ /// A message proc which wraps the standard dialog proc,
+ /// but intercepts some calls
+ static LRESULT CALLBACK file_dialog_subclass_proc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
+
+ /// The message proc for the preview panel window
+ static LRESULT CALLBACK preview_wnd_proc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
+
+ /// Lays out the controls in the file dialog given it's
+ /// current size
+ /// GetOpenFileName thread only.
+ void layout_dialog();
+
+ /// Enables or disables the file preview.
+ /// GetOpenFileName thread only.
+ void enable_preview(bool enable);
+
+ /// This function is called in the App thread when a file had
+ /// been selected
+ void file_selected();
+
+ /// Loads and renders the unshrunk preview image.
+ /// Main app thread only.
+ void load_preview();
+
+ /// Frees all the allocated objects associated with the file
+ /// currently being previewed
+ /// Main app thread only.
+ void free_preview();
+
+ /// Loads preview for an SVG or SVGZ file.
+ /// Main app thread only.
+ /// @return Returns true if the SVG loaded successfully
+ bool set_svg_preview();
+
+ /// A callback to allow this class to dispose of the
+ /// memory block of the rendered SVG bitmap
+ /// @buffer buffer The buffer to free
+ static void destroy_svg_rendering(const guint8 *buffer);
+
+ /// Loads the preview for a raster image
+ /// Main app thread only.
+ /// @return Returns true if the image loaded successfully
+ bool set_image_preview();
+
+ /// Renders the unshrunk preview image to a windows HTBITMAP
+ /// which can be painted in the preview pain.
+ /// Main app thread only.
+ void render_preview();
+
+ /// Formats the caption in UTF-16 for the preview image
+ /// @param caption The buffer to format the caption string into
+ /// @param caption_size The number of wchar_ts in the caption buffer
+ /// @return Returns the number of characters in caption string
+ int format_caption(wchar_t *caption, int caption_size);
+};
+
+
+/*#########################################################################
+### F I L E S A V E
+#########################################################################*/
+
+/// An Inkscape compatible wrapper around MS Windows GetSaveFileName API
+class FileSaveDialogImplWin32 : public FileSaveDialog, public FileDialogBaseWin32
+{
+
+public:
+ FileSaveDialogImplWin32(Gtk::Window &parent,
+ const Glib::ustring &dir,
+ FileDialogType fileTypes,
+ const char *title,
+ const Glib::ustring &default_key);
+
+ /// Destructor
+ virtual ~FileSaveDialogImplWin32();
+
+ /// Shows the file dialog, and blocks until a file
+ /// has been selected.
+ /// @return Returns true if the the user selected a
+ /// file, or false if the user pressed cancel.
+ bool show();
+
+ /// Get the path of the current directory
+ virtual Glib::ustring getCurrentDirectory()
+ { return FileDialogBaseWin32::getCurrentDirectory(); }
+
+ /// Gets the currently selected extension. Valid after an [OK]
+ /// @return Returns a pointer to the selected extension, or NULL
+ /// if the selected filter requires an automatic type detection
+ virtual Inkscape::Extension::Extension* getSelectionType()
+ { return FileDialogBaseWin32::getSelectionType(); }
+
+ virtual void setSelectionType( Inkscape::Extension::Extension *key );
+
+private:
+
+ /**
+ * Create a filter menu for this type of dialog
+ */
+ void createFilterMenu();
+
+ void GetSaveFileName_thread();
+};
+
+
+}
+}
+}
+
+#endif
+
+/*
+ Local Variables:
+ mode:c++
+ c-file-style:"stroustrup"
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
+ indent-tabs-mode:nil
+ fill-column:99
+ End:
+*/
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :
|
