From: joncruz Date: Mon, 25 Feb 2008 05:29:06 +0000 (+0000) Subject: Line-end fix X-Git-Url: https://git.tokkee.org/?a=commitdiff_plain;h=6bffd52160c0be8ad7b402099c7e1c70eeed4556;p=inkscape.git Line-end fix --- diff --git a/src/2geom/angle.h b/src/2geom/angle.h index 4d548ab49..05364fb22 100644 --- a/src/2geom/angle.h +++ b/src/2geom/angle.h @@ -1,50 +1,50 @@ -/** - * \file angle.h - * \brief Various trigoniometric helper functions - * - * Authors: - * Johan Engelen - * - * Copyright (C) 2007 authors - * - * This library is free software; you can redistribute it and/or - * modify it either under the terms of the GNU Lesser General Public - * License version 2.1 as published by the Free Software Foundation - * (the "LGPL") or, at your option, under the terms of the Mozilla - * Public License Version 1.1 (the "MPL"). If you do not alter this - * notice, a recipient may use your version of this file under either - * the MPL or the LGPL. - * - * You should have received a copy of the LGPL along with this library - * in the file COPYING-LGPL-2.1; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * You should have received a copy of the MPL along with this library - * in the file COPYING-MPL-1.1 - * - * The contents of this file are subject to the Mozilla Public License - * Version 1.1 (the "License"); you may not use this file except in - * compliance with the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY - * OF ANY KIND, either express or implied. See the LGPL or the MPL for - * the specific language governing rights and limitations. - * - */ - -#ifndef LIB2GEOM_SEEN_ANGLE_H -#define LIB2GEOM_SEEN_ANGLE_H - -namespace Geom { - -#ifndef M_PI -# define M_PI 3.14159265358979323846 -#endif - -inline double deg_to_rad(double deg) { return deg*M_PI/180.0;} - -inline double rad_to_deg(double rad) { return rad*180.0/M_PI;} - -} - -#endif +/** + * \file angle.h + * \brief Various trigoniometric helper functions + * + * Authors: + * Johan Engelen + * + * Copyright (C) 2007 authors + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + */ + +#ifndef LIB2GEOM_SEEN_ANGLE_H +#define LIB2GEOM_SEEN_ANGLE_H + +namespace Geom { + +#ifndef M_PI +# define M_PI 3.14159265358979323846 +#endif + +inline double deg_to_rad(double deg) { return deg*M_PI/180.0;} + +inline double rad_to_deg(double rad) { return rad*180.0/M_PI;} + +} + +#endif diff --git a/src/2geom/poly-dk-solve.cpp b/src/2geom/poly-dk-solve.cpp index 87d238f14..fdc1cefe5 100644 --- a/src/2geom/poly-dk-solve.cpp +++ b/src/2geom/poly-dk-solve.cpp @@ -1,64 +1,64 @@ -#include "poly-dk-solve.h" -#include - -/*** implementation of the Durand-Kerner method. seems buggy*/ - -std::complex evalu(Poly const & p, std::complex x) { - std::complex result = 0; - std::complex xx = 1; - - for(unsigned i = 0; i < p.size(); i++) { - result += p[i]*xx; - xx *= x; - } - return result; -} - -std::vector > DK(Poly const & ply, const double tol) { - std::vector > roots; - const int N = ply.degree(); - - std::complex b(0.4, 0.9); - std::complex p = 1; - for(int i = 0; i < N; i++) { - roots.push_back(p); - p *= b; - } - assert(roots.size() == ply.degree()); - - double error = 0; - int i; - for( i = 0; i < 30; i++) { - error = 0; - for(int r_i = 0; r_i < N; r_i++) { - std::complex denom = 1; - std::complex R = roots[r_i]; - for(int d_i = 0; d_i < N; d_i++) { - if(r_i != d_i) - denom *= R-roots[d_i]; - } - assert(norm(denom) != 0); - std::complex dr = evalu(ply, R)/denom; - error += norm(dr); - roots[r_i] = R - dr; - } - /*std::copy(roots.begin(), roots.end(), std::ostream_iterator >(std::cout, ",\t")); - std::cout << std::endl;*/ - if(error < tol) - break; - } - //std::cout << error << ", " << i<< std::endl; - return roots; -} - - -/* - 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:encoding=utf-8:textwidth=99 : +#include "poly-dk-solve.h" +#include + +/*** implementation of the Durand-Kerner method. seems buggy*/ + +std::complex evalu(Poly const & p, std::complex x) { + std::complex result = 0; + std::complex xx = 1; + + for(unsigned i = 0; i < p.size(); i++) { + result += p[i]*xx; + xx *= x; + } + return result; +} + +std::vector > DK(Poly const & ply, const double tol) { + std::vector > roots; + const int N = ply.degree(); + + std::complex b(0.4, 0.9); + std::complex p = 1; + for(int i = 0; i < N; i++) { + roots.push_back(p); + p *= b; + } + assert(roots.size() == ply.degree()); + + double error = 0; + int i; + for( i = 0; i < 30; i++) { + error = 0; + for(int r_i = 0; r_i < N; r_i++) { + std::complex denom = 1; + std::complex R = roots[r_i]; + for(int d_i = 0; d_i < N; d_i++) { + if(r_i != d_i) + denom *= R-roots[d_i]; + } + assert(norm(denom) != 0); + std::complex dr = evalu(ply, R)/denom; + error += norm(dr); + roots[r_i] = R - dr; + } + /*std::copy(roots.begin(), roots.end(), std::ostream_iterator >(std::cout, ",\t")); + std::cout << std::endl;*/ + if(error < tol) + break; + } + //std::cout << error << ", " << i<< std::endl; + return roots; +} + + +/* + 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:encoding=utf-8:textwidth=99 : diff --git a/src/2geom/poly-laguerre-solve.cpp b/src/2geom/poly-laguerre-solve.cpp index 921ec3e3b..766f16eda 100644 --- a/src/2geom/poly-laguerre-solve.cpp +++ b/src/2geom/poly-laguerre-solve.cpp @@ -1,147 +1,147 @@ -#include "poly-laguerre-solve.h" -#include - -typedef std::complex cdouble; - -cdouble laguerre_internal_complex(Poly const & p, - double x0, - double tol, - bool & quad_root) { - cdouble a = 2*tol; - cdouble xk = x0; - double n = p.degree(); - quad_root = false; - const unsigned shuffle_rate = 10; - static double shuffle[] = {0, 0.5, 0.25, 0.75, 0.125, 0.375, 0.625, 0.875, 1.0}; - unsigned shuffle_counter = 0; - while(std::norm(a) > (tol*tol)) { - //std::cout << "xk = " << xk << std::endl; - cdouble b = p.back(); - cdouble d = 0, f = 0; - double err = abs(b); - double abx = abs(xk); - for(int j = p.size()-2; j >= 0; j--) { - f = xk*f + d; - d = xk*d + b; - b = xk*b + p[j]; - err = abs(b) + abx*err; - } - - err *= 1e-7; // magic epsilon for convergence, should be computed from tol - - cdouble px = b; - if(abs(b) < err) - return xk; - //if(std::norm(px) < tol*tol) - // return xk; - cdouble G = d / px; - cdouble H = G*G - f / px; - - //std::cout << "G = " << G << "H = " << H; - cdouble radicand = (n - 1)*(n*H-G*G); - //assert(radicand.real() > 0); - if(radicand.real() < 0) - quad_root = true; - //std::cout << "radicand = " << radicand << std::endl; - if(G.real() < 0) // here we try to maximise the denominator avoiding cancellation - a = - sqrt(radicand); - else - a = sqrt(radicand); - //std::cout << "a = " << a << std::endl; - a = n / (a + G); - //std::cout << "a = " << a << std::endl; - if(shuffle_counter % shuffle_rate == 0) - ;//a *= shuffle[shuffle_counter / shuffle_rate]; - xk -= a; - shuffle_counter++; - if(shuffle_counter >= 90) - break; - } - //std::cout << "xk = " << xk << std::endl; - return xk; -} - -double laguerre_internal(Poly const & p, - Poly const & pp, - Poly const & ppp, - double x0, - double tol, - bool & quad_root) { - double a = 2*tol; - double xk = x0; - double n = p.degree(); - quad_root = false; - while(a*a > (tol*tol)) { - //std::cout << "xk = " << xk << std::endl; - double px = p(xk); - if(px*px < tol*tol) - return xk; - double G = pp(xk) / px; - double H = G*G - ppp(xk) / px; - - //std::cout << "G = " << G << "H = " << H; - double radicand = (n - 1)*(n*H-G*G); - assert(radicand > 0); - //std::cout << "radicand = " << radicand << std::endl; - if(G < 0) // here we try to maximise the denominator avoiding cancellation - a = - sqrt(radicand); - else - a = sqrt(radicand); - //std::cout << "a = " << a << std::endl; - a = n / (a + G); - //std::cout << "a = " << a << std::endl; - xk -= a; - } - //std::cout << "xk = " << xk << std::endl; - return xk; -} - - -std::vector -laguerre(Poly p, const double tol) { - std::vector solutions; - //std::cout << "p = " << p << " = "; - while(p.size() > 1) - { - double x0 = 0; - bool quad_root = false; - cdouble sol = laguerre_internal_complex(p, x0, tol, quad_root); - //if(abs(sol) > 1) break; - Poly dvs; - if(quad_root) { - dvs.push_back((sol*conj(sol)).real()); - dvs.push_back(-(sol + conj(sol)).real()); - dvs.push_back(1.0); - //std::cout << "(" << dvs << ")"; - //solutions.push_back(sol); - //solutions.push_back(conj(sol)); - } else { - //std::cout << sol << std::endl; - dvs.push_back(-sol.real()); - dvs.push_back(1.0); - solutions.push_back(sol); - //std::cout << "(" << dvs << ")"; - } - Poly r; - p = divide(p, dvs, r); - //std::cout << r << std::endl; - } - return solutions; -} - -std::vector -laguerre_real_interval(Poly const & ply, - const double lo, const double hi, - const double tol) { -} - -/* - 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:encoding=utf-8:textwidth=99 : +#include "poly-laguerre-solve.h" +#include + +typedef std::complex cdouble; + +cdouble laguerre_internal_complex(Poly const & p, + double x0, + double tol, + bool & quad_root) { + cdouble a = 2*tol; + cdouble xk = x0; + double n = p.degree(); + quad_root = false; + const unsigned shuffle_rate = 10; + static double shuffle[] = {0, 0.5, 0.25, 0.75, 0.125, 0.375, 0.625, 0.875, 1.0}; + unsigned shuffle_counter = 0; + while(std::norm(a) > (tol*tol)) { + //std::cout << "xk = " << xk << std::endl; + cdouble b = p.back(); + cdouble d = 0, f = 0; + double err = abs(b); + double abx = abs(xk); + for(int j = p.size()-2; j >= 0; j--) { + f = xk*f + d; + d = xk*d + b; + b = xk*b + p[j]; + err = abs(b) + abx*err; + } + + err *= 1e-7; // magic epsilon for convergence, should be computed from tol + + cdouble px = b; + if(abs(b) < err) + return xk; + //if(std::norm(px) < tol*tol) + // return xk; + cdouble G = d / px; + cdouble H = G*G - f / px; + + //std::cout << "G = " << G << "H = " << H; + cdouble radicand = (n - 1)*(n*H-G*G); + //assert(radicand.real() > 0); + if(radicand.real() < 0) + quad_root = true; + //std::cout << "radicand = " << radicand << std::endl; + if(G.real() < 0) // here we try to maximise the denominator avoiding cancellation + a = - sqrt(radicand); + else + a = sqrt(radicand); + //std::cout << "a = " << a << std::endl; + a = n / (a + G); + //std::cout << "a = " << a << std::endl; + if(shuffle_counter % shuffle_rate == 0) + ;//a *= shuffle[shuffle_counter / shuffle_rate]; + xk -= a; + shuffle_counter++; + if(shuffle_counter >= 90) + break; + } + //std::cout << "xk = " << xk << std::endl; + return xk; +} + +double laguerre_internal(Poly const & p, + Poly const & pp, + Poly const & ppp, + double x0, + double tol, + bool & quad_root) { + double a = 2*tol; + double xk = x0; + double n = p.degree(); + quad_root = false; + while(a*a > (tol*tol)) { + //std::cout << "xk = " << xk << std::endl; + double px = p(xk); + if(px*px < tol*tol) + return xk; + double G = pp(xk) / px; + double H = G*G - ppp(xk) / px; + + //std::cout << "G = " << G << "H = " << H; + double radicand = (n - 1)*(n*H-G*G); + assert(radicand > 0); + //std::cout << "radicand = " << radicand << std::endl; + if(G < 0) // here we try to maximise the denominator avoiding cancellation + a = - sqrt(radicand); + else + a = sqrt(radicand); + //std::cout << "a = " << a << std::endl; + a = n / (a + G); + //std::cout << "a = " << a << std::endl; + xk -= a; + } + //std::cout << "xk = " << xk << std::endl; + return xk; +} + + +std::vector +laguerre(Poly p, const double tol) { + std::vector solutions; + //std::cout << "p = " << p << " = "; + while(p.size() > 1) + { + double x0 = 0; + bool quad_root = false; + cdouble sol = laguerre_internal_complex(p, x0, tol, quad_root); + //if(abs(sol) > 1) break; + Poly dvs; + if(quad_root) { + dvs.push_back((sol*conj(sol)).real()); + dvs.push_back(-(sol + conj(sol)).real()); + dvs.push_back(1.0); + //std::cout << "(" << dvs << ")"; + //solutions.push_back(sol); + //solutions.push_back(conj(sol)); + } else { + //std::cout << sol << std::endl; + dvs.push_back(-sol.real()); + dvs.push_back(1.0); + solutions.push_back(sol); + //std::cout << "(" << dvs << ")"; + } + Poly r; + p = divide(p, dvs, r); + //std::cout << r << std::endl; + } + return solutions; +} + +std::vector +laguerre_real_interval(Poly const & ply, + const double lo, const double hi, + const double tol) { +} + +/* + 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:encoding=utf-8:textwidth=99 : diff --git a/src/2geom/sweep.cpp b/src/2geom/sweep.cpp index 96104ea90..08674ab2f 100644 --- a/src/2geom/sweep.cpp +++ b/src/2geom/sweep.cpp @@ -1,104 +1,104 @@ -#include "sweep.h" - -#include - -namespace Geom { - -std::vector > sweep_bounds(std::vector rs) { - std::vector events; events.reserve(rs.size()*2); - std::vector > pairs(rs.size()); - - for(unsigned i = 0; i < rs.size(); i++) { - events.push_back(Event(rs[i].left(), i, false)); - events.push_back(Event(rs[i].right(), i, true)); - } - std::sort(events.begin(), events.end()); - - std::vector open; - for(unsigned i = 0; i < events.size(); i++) { - unsigned ix = events[i].ix; - if(events[i].closing) { - std::vector::iterator iter = std::find(open.begin(), open.end(), ix); - //if(iter != open.end()) - open.erase(iter); - } else { - for(unsigned j = 0; j < open.size(); j++) { - unsigned jx = open[j]; - if(rs[jx][Y].intersects(rs[ix][Y])) { - pairs[jx].push_back(ix); - } - } - open.push_back(ix); - } - } - return pairs; -} - -std::vector > sweep_bounds(std::vector a, std::vector b) { - std::vector > pairs(a.size()); - if(a.empty() || b.empty()) return pairs; - std::vector events[2]; - events[0].reserve(a.size()*2); - events[1].reserve(b.size()*2); - - for(unsigned n = 0; n < 2; n++) { - unsigned sz = n ? b.size() : a.size(); - events[n].reserve(sz*2); - for(unsigned i = 0; i < sz; i++) { - events[n].push_back(Event(n ? b[i].left() : a[i].left(), i, false)); - events[n].push_back(Event(n ? b[i].right() : a[i].right(), i, true)); - } - std::sort(events[n].begin(), events[n].end()); - } - - std::vector open[2]; - bool n = events[1].front() < events[0].front(); - for(unsigned i[] = {0,0}; i[n] < events[n].size();) { - unsigned ix = events[n][i[n]].ix; - bool closing = events[n][i[n]].closing; - //std::cout << n << "[" << ix << "] - " << (closing ? "closer" : "opener") << "\n"; - if(closing) { - open[n].erase(std::find(open[n].begin(), open[n].end(), ix)); - } else { - if(n) { - //n = 1 - //opening a B, add to all open a - for(unsigned j = 0; j < open[0].size(); j++) { - unsigned jx = open[0][j]; - if(a[jx][Y].intersects(b[ix][Y])) { - pairs[jx].push_back(ix); - } - } - } else { - //n = 0 - //opening an A, add all open b - for(unsigned j = 0; j < open[1].size(); j++) { - unsigned jx = open[1][j]; - if(b[jx][Y].intersects(a[ix][Y])) { - pairs[ix].push_back(jx); - } - } - } - open[n].push_back(ix); - } - i[n]++; - n = (events[!n][i[!n]] < events[n][i[n]]) ? !n : n; - } - return pairs; -} - -//Fake cull, until the switch to the real sweep is made. -std::vector > fake_cull(unsigned a, unsigned b) { - std::vector > ret; - - std::vector all; - for(unsigned j = 0; j < b; j++) - all.push_back(j); - - for(unsigned i = 0; i < a; i++) - ret.push_back(all); - - return ret; -} - -} +#include "sweep.h" + +#include + +namespace Geom { + +std::vector > sweep_bounds(std::vector rs) { + std::vector events; events.reserve(rs.size()*2); + std::vector > pairs(rs.size()); + + for(unsigned i = 0; i < rs.size(); i++) { + events.push_back(Event(rs[i].left(), i, false)); + events.push_back(Event(rs[i].right(), i, true)); + } + std::sort(events.begin(), events.end()); + + std::vector open; + for(unsigned i = 0; i < events.size(); i++) { + unsigned ix = events[i].ix; + if(events[i].closing) { + std::vector::iterator iter = std::find(open.begin(), open.end(), ix); + //if(iter != open.end()) + open.erase(iter); + } else { + for(unsigned j = 0; j < open.size(); j++) { + unsigned jx = open[j]; + if(rs[jx][Y].intersects(rs[ix][Y])) { + pairs[jx].push_back(ix); + } + } + open.push_back(ix); + } + } + return pairs; +} + +std::vector > sweep_bounds(std::vector a, std::vector b) { + std::vector > pairs(a.size()); + if(a.empty() || b.empty()) return pairs; + std::vector events[2]; + events[0].reserve(a.size()*2); + events[1].reserve(b.size()*2); + + for(unsigned n = 0; n < 2; n++) { + unsigned sz = n ? b.size() : a.size(); + events[n].reserve(sz*2); + for(unsigned i = 0; i < sz; i++) { + events[n].push_back(Event(n ? b[i].left() : a[i].left(), i, false)); + events[n].push_back(Event(n ? b[i].right() : a[i].right(), i, true)); + } + std::sort(events[n].begin(), events[n].end()); + } + + std::vector open[2]; + bool n = events[1].front() < events[0].front(); + for(unsigned i[] = {0,0}; i[n] < events[n].size();) { + unsigned ix = events[n][i[n]].ix; + bool closing = events[n][i[n]].closing; + //std::cout << n << "[" << ix << "] - " << (closing ? "closer" : "opener") << "\n"; + if(closing) { + open[n].erase(std::find(open[n].begin(), open[n].end(), ix)); + } else { + if(n) { + //n = 1 + //opening a B, add to all open a + for(unsigned j = 0; j < open[0].size(); j++) { + unsigned jx = open[0][j]; + if(a[jx][Y].intersects(b[ix][Y])) { + pairs[jx].push_back(ix); + } + } + } else { + //n = 0 + //opening an A, add all open b + for(unsigned j = 0; j < open[1].size(); j++) { + unsigned jx = open[1][j]; + if(b[jx][Y].intersects(a[ix][Y])) { + pairs[ix].push_back(jx); + } + } + } + open[n].push_back(ix); + } + i[n]++; + n = (events[!n][i[!n]] < events[n][i[n]]) ? !n : n; + } + return pairs; +} + +//Fake cull, until the switch to the real sweep is made. +std::vector > fake_cull(unsigned a, unsigned b) { + std::vector > ret; + + std::vector all; + for(unsigned j = 0; j < b; j++) + all.push_back(j); + + for(unsigned i = 0; i < a; i++) + ret.push_back(all); + + return ret; +} + +} diff --git a/src/helper/pixbuf-ops.h b/src/helper/pixbuf-ops.h index d87f4fa25..a985be297 100644 --- a/src/helper/pixbuf-ops.h +++ b/src/helper/pixbuf-ops.h @@ -1,27 +1,27 @@ -#ifndef __SP_PIXBUF_OPS_H__ -#define __SP_PIXBUF_OPS_H__ - -/* - * Helpers for SPItem -> gdk_pixbuf related stuff - * - * Authors: - * John Cliff - * - * Copyright (C) 2008 John Cliff - * - * Released under GNU GPL, read the file 'COPYING' for more information - */ - +#ifndef __SP_PIXBUF_OPS_H__ +#define __SP_PIXBUF_OPS_H__ + +/* + * Helpers for SPItem -> gdk_pixbuf related stuff + * + * Authors: + * John Cliff + * + * Copyright (C) 2008 John Cliff + * + * Released under GNU GPL, read the file 'COPYING' for more information + */ + #include -struct SPDocument; - -bool sp_export_jpg_file (SPDocument *doc, gchar const *filename, double x0, double y0, double x1, double y1, - unsigned int width, unsigned int height, double xdpi, double ydpi, unsigned long bgcolor, double quality, GSList *items_only = NULL); - -GdkPixbuf* sp_generate_internal_bitmap(SPDocument *doc, gchar const *filename, - double x0, double y0, double x1, double y1, - unsigned width, unsigned height, double xdpi, double ydpi, - unsigned long bgcolor, GSList *items_only = NULL); - -#endif +struct SPDocument; + +bool sp_export_jpg_file (SPDocument *doc, gchar const *filename, double x0, double y0, double x1, double y1, + unsigned int width, unsigned int height, double xdpi, double ydpi, unsigned long bgcolor, double quality, GSList *items_only = NULL); + +GdkPixbuf* sp_generate_internal_bitmap(SPDocument *doc, gchar const *filename, + double x0, double y0, double x1, double y1, + unsigned width, unsigned height, double xdpi, double ydpi, + unsigned long bgcolor, GSList *items_only = NULL); + +#endif diff --git a/src/libnr/nr-convert2geom.h b/src/libnr/nr-convert2geom.h index c9ae68bd1..7741e7782 100644 --- a/src/libnr/nr-convert2geom.h +++ b/src/libnr/nr-convert2geom.h @@ -1,38 +1,38 @@ -#ifndef INKSCAPE_LIBNR_CONVERT2GEOM_H -#define INKSCAPE_LIBNR_CONVERT2GEOM_H - -/* - * Converts between NR and 2Geom types. - * -* Copyright (C) Johan Engelen 2008 - * - * Released under GNU GPL, read the file 'COPYING' for more information - */ - -#include <2geom/matrix.h> -#include -#include <2geom/d2.h> -#include - -inline Geom::Matrix to_2geom(NR::Matrix const & mat) { - Geom::Matrix mat2geom(mat[0], mat[1], mat[2], mat[3], mat[4], mat[5]); - return mat2geom; -} - -inline NR::Rect from_2geom(Geom::Rect const & rect2geom) { - NR::Rect rect(rect2geom.min(), rect2geom.max()); - return rect; -} - -#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:encoding=utf-8:textwidth=99 : +#ifndef INKSCAPE_LIBNR_CONVERT2GEOM_H +#define INKSCAPE_LIBNR_CONVERT2GEOM_H + +/* + * Converts between NR and 2Geom types. + * +* Copyright (C) Johan Engelen 2008 + * + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +#include <2geom/matrix.h> +#include +#include <2geom/d2.h> +#include + +inline Geom::Matrix to_2geom(NR::Matrix const & mat) { + Geom::Matrix mat2geom(mat[0], mat[1], mat[2], mat[3], mat[4], mat[5]); + return mat2geom; +} + +inline NR::Rect from_2geom(Geom::Rect const & rect2geom) { + NR::Rect rect(rect2geom.min(), rect2geom.max()); + return rect; +} + +#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:encoding=utf-8:textwidth=99 : diff --git a/src/ui/dialog/filedialogimpl-win32.cpp b/src/ui/dialog/filedialogimpl-win32.cpp index f67e12b87..e47154649 100644 --- a/src/ui/dialog/filedialogimpl-win32.cpp +++ b/src/ui/dialog/filedialogimpl-win32.cpp @@ -1,1461 +1,1461 @@ -/** - * Implementation of the file dialog interfaces defined in filedialog.h for Win32 - * - * Authors: - * Joel Holdsworth - * The Inkscape Organization - * - * Copyright (C) 2004-2008 The Inkscape Organization - * - * Released under GNU GPL, read the file 'COPYING' for more information - */ - -#ifdef HAVE_CONFIG_H -# include -#endif - -#ifdef WIN32 - -//General includes -#include -#include -#include -#include -#include -#include -#include -#include -#include - -//Inkscape includes -#include "inkscape.h" -#include "prefs-utils.h" -#include -#include -#include -#include - -#include -#include -#include -#include -#include "sp-item.h" -#include "canvas-arena.h" - -#include "filedialog.h" -#include "filedialogimpl-win32.h" - -#include -#include -#include - -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 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_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::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(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 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 surface = Win32Surface::create(hMemDC); - Cairo::RefPtr 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 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 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 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 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 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 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 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 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::vectorFileOpenDialogImplWin32::getFilenames() -{ - std::vector 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_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::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 : +/** + * Implementation of the file dialog interfaces defined in filedialog.h for Win32 + * + * Authors: + * Joel Holdsworth + * The Inkscape Organization + * + * Copyright (C) 2004-2008 The Inkscape Organization + * + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#ifdef WIN32 + +//General includes +#include +#include +#include +#include +#include +#include +#include +#include +#include + +//Inkscape includes +#include "inkscape.h" +#include "prefs-utils.h" +#include +#include +#include +#include + +#include +#include +#include +#include +#include "sp-item.h" +#include "canvas-arena.h" + +#include "filedialog.h" +#include "filedialogimpl-win32.h" + +#include +#include +#include + +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 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_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::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(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 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 surface = Win32Surface::create(hMemDC); + Cairo::RefPtr 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 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 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 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 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 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 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 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 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::vectorFileOpenDialogImplWin32::getFilenames() +{ + std::vector 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_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::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 index cf696c229..fd0d1c259 100644 --- a/src/ui/dialog/filedialogimpl-win32.h +++ b/src/ui/dialog/filedialogimpl-win32.h @@ -1,348 +1,348 @@ -/** - * Implementation of the file dialog interfaces defined in filedialog.h for Win32 - * - * Authors: - * Joel Holdsworth - * The Inkscape Organization - * - * Copyright (C) 2004-2008 The Inkscape Organization - * - * Released under GNU GPL, read the file 'COPYING' for more information - */ - -#ifdef WIN32 - -#include "gc-core.h" -#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 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 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 _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 : +/** + * Implementation of the file dialog interfaces defined in filedialog.h for Win32 + * + * Authors: + * Joel Holdsworth + * The Inkscape Organization + * + * Copyright (C) 2004-2008 The Inkscape Organization + * + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +#ifdef WIN32 + +#include "gc-core.h" +#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 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 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 _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 :