filedialogimpl-win32.cpp revision bbc7515f3cdfd18b43c5189b96397086880ef5d8
/** @file
* @brief Implementation of native file dialogs for Win32
*/
/* Authors:
* Joel Holdsworth
* The Inkscape Organization
* Abhishek Sharma
*
* Copyright (C) 2004-2008 The Inkscape Organization
*
* Released under GNU GPL, read the file 'COPYING' for more information
*/
#ifdef WIN32
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
//General includes
#include <list>
#include <unistd.h>
#include <errno.h>
#include <set>
#include <gdk/gdkwin32.h>
//Inkscape includes
#include "inkscape.h"
#include <dialogs/dialog-events.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 "display/canvas-arena.h"
#include "filedialog.h"
#include "filedialogimpl-win32.h"
#include <zlib.h>
#include <cairomm/win32_surface.h>
using namespace std;
using namespace Glib;
using namespace Cairo;
namespace Inkscape
{
namespace UI
{
namespace Dialog
{
const int PREVIEW_WIDENING = 150;
const int WINDOW_WIDTH_MINIMUM = 32;
const int WINDOW_WIDTH_FALLBACK = 450;
const int WINDOW_HEIGHT_MINIMUM = 32;
const int WINDOW_HEIGHT_FALLBACK = 360;
const char PreviewWindowClassName[] = "PreviewWnd";
#define IDC_SHOW_PREVIEW 1000
// Windows 2000 version of OPENFILENAMEW
struct OPENFILENAMEEXW : public OPENFILENAMEW {
void * pvReserved;
};
struct Filter
{
};
{
return result;
}
namespace {
{
}
return result;
}
} // namespace
/*#########################################################################
### F I L E D I A L O G B A S E C L A S S
#########################################################################*/
{
_main_loop = NULL;
_filter_index = 1;
_filter_count = 0;
}
{
}
{
return _extension;
}
{
return _current_directory;
}
/*#########################################################################
### F I L E O P E N
#########################################################################*/
bool FileOpenDialogImplWin32::_show_preview = true;
/**
* Constructor. Not called directly. Use the factory.
*/
{
// Initalize to Autodetect
_extension = NULL;
// Set our dialog type (open, import, etc...)
_preview_wnd = NULL;
_preview_file_size = 0;
_preview_image_width = 0;
_preview_emf_image = false;
}
/**
* Destructor
*/
{
delete[] _filter;
if(_extension_map != NULL)
delete[] _extension_map;
}
{
int extension_index = 0;
int filter_length = 1;
if (dialogType != EXE_TYPES) {
// Compose the filter string
// Calculate the amount of memory required
{
if (imod->deactivated()) continue;
// Type
// Extension
// Add to the "All Inkscape Files" Entry
if(all_inkscape_files_filter.length() > 0)
all_inkscape_files_filter += ";*";
{
// Add to the "All Image Files" Entry
if(all_image_files_filter.length() > 0)
all_image_files_filter += ";*";
}
// I don't know of any other way to define "bitmap" formats other than by listing them
// if you change it here, do the same change in filedialogimpl-gtkmm
if (
) {
if(all_bitmaps_filter.length() > 0)
all_bitmaps_filter += ";*";
} else {
if(all_vectors_filter.length() > 0)
all_vectors_filter += ";*";
}
filter_count++;
}
// Filter bitmap files
// Filter vector files
// Filter Image Files
// Filter Inkscape Files
// Filter All Files
all_files.filter_length = 0;
1;
// Add 3 for 2*2 \0s and a *, and 1 for a trailing \0
} else {
// Executables only
// Calculate the amount of memory required
// Filter Executable Files
// Filter All Files
all_files.filter_length = 0;
1;
// Add 3 for 2*2 \0s and a *, and 1 for a trailing \0
}
_filter = new wchar_t[filter_length];
{
*(filterptr++) = L'\0';
*(filterptr++) = L'*';
{
}
*(filterptr++) = L'\0';
// Associate this input extension with the file type name
}
*(filterptr++) = L'\0';
}
{
// Copy the selected file name, converting from UTF-8 to UTF-16
ofn.nMaxFileTitle = 0;
ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST | OFN_EXPLORER | OFN_ENABLEHOOK | OFN_HIDEREADONLY | OFN_ENABLESIZING;
// Copy the selected file name, converting from UTF-16 to UTF-8
// Tidy up
_finished = true;
}
{
const WNDCLASSA PreviewWndClass =
{
0,
0,
NULL,
NULL,
};
}
{
switch(uiMsg)
{
case WM_INITDIALOG:
{
// Set the pointer to the object
// Make the window a bit wider
// Don't show the preview when opening executable files
FALSE);
} else {
FALSE);
}
// Subclass the parent
// Add a button to the toolbar
// Create preview pane
}
}
pImpl->layout_dialog();
}
break;
case WM_NOTIFY:
{
{
case CDN_SELCHANGE:
{
{
// Get the file name
sizeof(pImpl->_path_string) / sizeof(wchar_t),
pImpl->_file_selected = true;
}
}
break;
}
}
break;
case WM_CLOSE:
pImpl->_preview_file_size = 0;
break;
}
// Use default dialog behaviour
return 0;
}
LRESULT CALLBACK FileOpenDialogImplWin32::file_dialog_subclass_proc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM 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)
{
TB_ISBUTTONCHECKED, IDC_SHOW_PREVIEW, 0) != 0;
}
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;
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
// Prepare to paint
WM_GETFONT, 0, 0);
if(pImpl->_path_string[0] == 0)
{
}
{
// Render the image
// Fill in the background area
// Draw the caption on
}
{
// Draw the files icon
// Draw the caption on
sizeof(szCaption), L"%s\n%d kB",
}
else
{
// Can't show anything!
}
// Finish painting
}
break;
case WM_DESTROY:
pImpl->free_preview();
break;
default:
break;
}
return lResult;
}
{
// Relayout the dialog
// Load or unload the preview
if(enable)
{
_file_selected = true;
}
else free_preview();
}
void FileOpenDialogImplWin32::layout_dialog()
{
union RECTPOINTS
{
RECT r;
POINT p[2];
};
// Re-layout the dialog
{
// Re-layout the preview box
}
// Re-layout the file list box
// Re-layout the toolbar
}
void FileOpenDialogImplWin32::file_selected()
{
// Destroy any previous previews
free_preview();
// Determine if the file exists
if(attributes == 0xFFFFFFFF ||
{
return;
}
// Check the file exists and get the file size
if(file_handle == INVALID_HANDLE_VALUE) return;
if (file_size == INVALID_FILE_SIZE) return;
if(_show_preview) load_preview();
}
void FileOpenDialogImplWin32::load_preview()
{
// Destroy any previous previews
free_preview();
// Try to get the file icon
// Will this file be too big?
{
return;
}
// Prepare to render a preview
bool success = false;
success = set_svg_preview();
success = set_emf_preview();
else if (isValidImageFile(path))
success = set_image_preview();
else {
// Show no preview
}
if(success) render_preview();
}
void FileOpenDialogImplWin32::free_preview()
{
if(_preview_bitmap != NULL)
if(_preview_file_icon != NULL)
_preview_emf_image = false;
}
{
const int PreviewSize = 512;
// Check the document loaded properly
{
return false;
}
// Get the size of the document
// Find the minimum scale to fit the image inside the preview area
// Now get the resized values
// write object bbox to area
svgDoc->ensureUpToDate();
// Prepare a GDI compatible NRPixBlock
// Fail if the pixblock failed to allocate
{
return false;
}
// Render the image
// Tidy up
// Create the GDK pixbuf
return true;
}
{
}
{
bool successful = false;
try {
if (_preview_bitmap_image) {
successful = true;
}
}
catch (const Gdk::PixbufError&) {}
return successful;
}
// Aldus Placeable Header ===================================================
// Since we are a 32bit app, we have to be sure this structure compiles to
// be identical to a 16 bit app's version. To do this, we use the #pragma
// to adjust packing, we use a WORD for the hmf handle, and a SMALL_RECT
// for the bbox rectangle.
#pragma pack( 2 )
typedef struct
{
} APMHEADER, *PAPMHEADER;
static HENHMETAFILE
{
// Try open as Enhanced Metafile
if (!hemf) {
// Try open as Windows Metafile
if (!hmf) {
if (dw) {
}
}
if (hmf) {
// Convert Windows Metafile to Enhanced Metafile
if (nSize) {
if (lpvData) {
if (dw) {
// Fill out a METAFILEPICT structure
// Get a reference DC
// Make an enhanced metafile from the windows metafile
// Clean up
DeleteMetaFile( hmf );
}
delete[] lpvData;
}
else {
DeleteMetaFile( hmf );
}
}
else {
DeleteMetaFile( hmf );
}
}
else {
// Try open as Aldus Placeable Metafile
if (hFile != INVALID_HANDLE_VALUE) {
if (nSize) {
if (lpvData) {
if (dw) {
// Fill out a METAFILEPICT structure
// Get a reference DC
// Create an enhanced metafile from the bits
// Clean up
}
}
delete[] lpvData;
}
}
CloseHandle( hFile );
}
}
}
return hemf;
}
{
DWORD w = 0;
DWORD h = 0;
if (hemf)
{
}
if (ok)
{
const int PreviewSize = 512;
// Get the size of the document
const double emfWidth = w;
const double emfHeight = h;
// Find the minimum scale to fit the image inside the preview area
// Now get the resized values
_preview_emf_image = true;
}
return ok;
}
{
double x, y;
const double blurRadius = 8;
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?
if(!_preview_bitmap_image && !_preview_emf_image)
{
return;
}
// Tidy up any previous bitmap renderings
if(_preview_bitmap != NULL)
// Calculate the size of the caption
int captionHeight = 0;
if(_preview_wnd != NULL)
{
}
// Find the minimum scale to fit the image inside the preview area
const double scaleFactorX =
const double scaleFactorY =
// Now get the resized values
const int svgY = pagePadding;
// Prepare the drawing surface
// Paint the background to match the dialog colour
//----- Draw the drop shaddow -----//
// Left Edge
leftEdgeFade->add_color_stop_rgba (0, 0, 0, 0, 0);
// Right Edge
// Top Edge
topEdgeFade->add_color_stop_rgba (0, 0, 0, 0, 0);
// Bottom Edge
// Top Left Corner
// Top Right Corner
// Bottom Left Corner
// Bottom Right Corner
x, y, 0, x, y, blurRadius);
// Draw the frame
context->fill_preserve();
// Draw the image
if(_preview_bitmap_image) // Is the image a pixbuf?
{
// Set the transformation
scaleFactor, 0,
0, scaleFactor,
// Render the image
// Reset the transformation
}
// Draw the inner frame
// Finish drawing
if (_preview_emf_image) {
if (hemf) {
}
}
// Refresh the preview pane
}
{
wchar_t szFileName[_MAX_FNAME];
(int)_preview_document_width, (int)_preview_document_height);
}
/**
* Show this dialog modally. Return true if user hits [OK]
*/
bool
{
// We can only run one worker thread at a time
if(!Glib::thread_supported())
Glib::thread_init();
_result = false;
_finished = false;
_file_selected = false;
if(Glib::Thread::create(sigc::mem_fun(*this, &FileOpenDialogImplWin32::GetOpenFileName_thread), true))
{
while(1)
{
{
// Read mutexed data
const bool is_file_selected = _file_selected;
_file_selected = false;
if(finished) break;
if(is_file_selected) file_selected();
}
Sleep(10);
}
}
// Tidy up
delete _mutex;
return _result;
}
/**
* To Get Multiple filenames selected at-once.
*/
{
return result;
}
/*#########################################################################
### F I L E S A V E
#########################################################################*/
/**
* Constructor
*/
const char *title,
const char *docTitle,
(save_method == Inkscape::Extension::FILE_SAVE_METHOD_SAVE_COPY) ? "dialogs.save_copy" : "dialogs.save_as"),
{
/* The code below sets the default file name */
myFilename = "";
// leaving a trailing backslash on the directory name leads to the infamous
// double-directory bug on win32
myFilename = udir.substr(0, udir.find_last_of( '.' ) ); // this removes the extension, or actually, removes everything past the last dot (hopefully this is what most people want)
}
}
{
}
{
// Compose the filter string
int filter_count = 0;
int filter_length = 1;
{
if (omod->deactivated()) continue;
filter_count++;
// Extension
// Type
}
int extension_index = 0;
_filter = new wchar_t[filter_length];
{
*(filterptr++) = L'\0';
*(filterptr++) = L'*';
*(filterptr++) = L'\0';
// Associate this input extension with the file type name
}
*(filterptr++) = 0;
}
{
// Copy the selected file name, converting from UTF-8 to UTF-16
ofn.nMaxFileTitle = 0;
// Copy the selected file name, converting from UTF-16 to UTF-8
// Tidy up
}
/**
* Show this dialog modally. Return true if user hits [OK]
*/
bool
{
if(!Glib::thread_supported())
Glib::thread_init();
_result = false;
if(_main_loop != NULL)
{
if(Glib::Thread::create(sigc::mem_fun(*this, &FileSaveDialogImplWin32::GetSaveFileName_thread), true))
if(_result)
}
return _result;
}
{
// If no pointer to extension is passed in, look up based on filename extension.
}
{
switch(uiMsg)
{
case WM_INITDIALOG:
{
if ( ydelta < 0 ) {
g_warning("Negative dialog ydelta");
ydelta = 0;
}
// Make the window a bit longer
// Note: we have a width delta of 1 because there is a suspicion that MoveWindow() to the same size causes zero-width results.
sanitizeWindowSizeParam( rcRect.right - rcRect.left, 1, WINDOW_WIDTH_MINIMUM, WINDOW_WIDTH_FALLBACK ),
sanitizeWindowSizeParam( rcRect.bottom - rcRect.top, ydelta, WINDOW_HEIGHT_MINIMUM, WINDOW_HEIGHT_FALLBACK ),
FALSE);
// It is not necessary to delete stock objects by calling DeleteObject
// Set the pointer to the object
// Create the Title label and edit control
if(pImpl->_title_label) {
}
if(pImpl->_title_edit) {
// TODO: make sure this works for Unicode
}
}
break;
case WM_DESTROY:
{
if(pImpl->_title_edit) {
char* temp_title = new char[length];
delete[] temp_title;
}
}
break;
}
// Use default dialog behaviour
return 0;
}
} } } // namespace Dialog, UI, Inkscape
#endif // ifdef WIN32
/*
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 :