// SPDX-License-Identifier: GPL-2.0-or-later /** @file * @brief Implementation of native file dialogs for Win32 */ /* Authors: * Joel Holdsworth * The Inkscape Organization * * Copyright (C) 2004-2008 The Inkscape Organization * * Released under GNU GPL v2+, read the file 'COPYING' for more information. */ #include #ifdef _WIN32 #include "filedialogimpl-gtkmm.h" #include "inkgc/gc-core.h" #include #include #include 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 browsing 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; /// 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. /// This value must be greater than or equal to 1, /// and less than or equal to _filter_count. unsigned int _filter_index; /// The number of filters registered unsigned int _filter_count; /// 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 browsing 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 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 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(); } /// Add a custom file filter menu item /// @param name - Name of the filter (such as "Javscript") /// @param pattern - File filtering pattern (such as "*.js") /// Use the FileDialogType::CUSTOM_TYPE in constructor to not include other file types virtual void addFilterMenu(Glib::ustring name, Glib::ustring pattern); private: /// Create 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 _preview_bitmap_image; /// This flag is set true if a file has been selected bool _file_selected; /// This flag is set true when the GetOpenFileName call /// has returned bool _finished; /// This mutex is used to ensure that the worker thread /// that calls GetOpenFileName cannot collide with the /// main Inkscape thread std::unique_ptr _mutex; /// 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(); /// Loads the preview for a meta file /// Main app thread only. /// @return Returns true if the image loaded successfully bool set_emf_preview(); /// This flag is set true when a meta file is previewed bool _preview_emf_image; /// 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, const char *docTitle, const Inkscape::Extension::FileSaveMethod save_method); /// Destructor virtual ~FileSaveDialogImplWin32(); /// Shows the file dialog, and blocks until a file /// has been selected. /// @return Returns true if 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 ); virtual void addFileType(Glib::ustring name, Glib::ustring pattern); private: /// A handle to the title label and edit box HWND _title_label; HWND _title_edit; /// Create a filter menu for this type of dialog void createFilterMenu(); // SaveAs or SaveAsCopy Inkscape::Extension::FileSaveMethod save_method; /// The controller function for the thread which calls /// GetSaveFileName void GetSaveFileName_thread(); /// A message proc which is called by the standard dialog /// proc static UINT_PTR CALLBACK GetSaveFileName_hookproc(HWND hdlg, UINT uiMsg, WPARAM wParam, LPARAM lParam); }; } } } #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:fileencoding=utf-8:textwidth=99 :