From fa034c4511b0b3e9d7cfc9eb170ed063be92ca90 Mon Sep 17 00:00:00 2001 From: Robert Roebling Date: Wed, 5 Sep 2007 21:34:08 +0000 Subject: [PATCH] Add support for GTK print, modified from patch 1782055 git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@48578 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775 --- Makefile.in | 41 +- build/bakefiles/files.bkl | 2 + include/wx/gtk/print.h | 400 ++++++ src/generic/prntdlgg.cpp | 4 +- src/gtk/print.cpp | 2414 +++++++++++++++++++++++++++++++++++++ 5 files changed, 2847 insertions(+), 14 deletions(-) create mode 100644 include/wx/gtk/print.h create mode 100644 src/gtk/print.cpp diff --git a/Makefile.in b/Makefile.in index 16db1b6152..c249f0ce67 100644 --- a/Makefile.in +++ b/Makefile.in @@ -2344,6 +2344,7 @@ COND_TOOLKIT_GTK_TOOLKIT_VERSION_2_GUI_HDR = \ wx/gtk/gauge.h \ wx/gtk/gnome/gprint.h \ wx/gtk/gnome/gvfs.h \ + wx/gtk/print.h \ wx/gtk/listbox.h \ wx/gtk/mdi.h \ wx/gtk/menu.h \ @@ -4534,6 +4535,7 @@ COND_TOOLKIT_GTK_TOOLKIT_VERSION_2___GUI_SRC_OBJECTS = \ monodll_gauge.o \ monodll_gprint.o \ monodll_gvfs.o \ + monodll_print.o \ monodll_listbox.o \ monodll_mdi.o \ monodll_menu.o \ @@ -6380,6 +6382,7 @@ COND_TOOLKIT_GTK_TOOLKIT_VERSION_2___GUI_SRC_OBJECTS_1 = \ monolib_gauge.o \ monolib_gprint.o \ monolib_gvfs.o \ + monolib_print.o \ monolib_listbox.o \ monolib_mdi.o \ monolib_menu.o \ @@ -8500,6 +8503,7 @@ COND_TOOLKIT_GTK_TOOLKIT_VERSION_2___GUI_SRC_OBJECTS_2 = \ coredll_gauge.o \ coredll_gprint.o \ coredll_gvfs.o \ + coredll_print.o \ coredll_listbox.o \ coredll_mdi.o \ coredll_menu.o \ @@ -9956,6 +9960,7 @@ COND_TOOLKIT_GTK_TOOLKIT_VERSION_2___GUI_SRC_OBJECTS_3 = \ corelib_gauge.o \ corelib_gprint.o \ corelib_gvfs.o \ + corelib_print.o \ corelib_listbox.o \ corelib_mdi.o \ corelib_menu.o \ @@ -13961,9 +13966,6 @@ monodll_regiong.o: $(srcdir)/src/generic/regiong.cpp $(MONODLL_ODEP) monodll_gsockpm.o: $(srcdir)/src/os2/gsockpm.cpp $(MONODLL_ODEP) $(CXXC) -c -o $@ $(MONODLL_CXXFLAGS) $(srcdir)/src/os2/gsockpm.cpp -monodll_print.o: $(srcdir)/src/os2/print.cpp $(MONODLL_ODEP) - $(CXXC) -c -o $@ $(MONODLL_CXXFLAGS) $(srcdir)/src/os2/print.cpp - monodll_colschem.o: $(srcdir)/src/univ/colschem.cpp $(MONODLL_ODEP) $(CXXC) -c -o $@ $(MONODLL_CXXFLAGS) $(srcdir)/src/univ/colschem.cpp @@ -16589,6 +16591,12 @@ monodll_sound_sdl.o: $(srcdir)/src/unix/sound_sdl.cpp $(MONODLL_ODEP) @COND_USE_GUI_1_WXUNIV_1@monodll_gauge.o: $(srcdir)/src/univ/gauge.cpp $(MONODLL_ODEP) @COND_USE_GUI_1_WXUNIV_1@ $(CXXC) -c -o $@ $(MONODLL_CXXFLAGS) $(srcdir)/src/univ/gauge.cpp +@COND_TOOLKIT_GTK_TOOLKIT_VERSION_2_USE_GUI_1_WXUNIV_0@monodll_print.o: $(srcdir)/src/gtk/print.cpp $(MONODLL_ODEP) +@COND_TOOLKIT_GTK_TOOLKIT_VERSION_2_USE_GUI_1_WXUNIV_0@ $(CXXC) -c -o $@ $(MONODLL_CXXFLAGS) $(srcdir)/src/gtk/print.cpp + +@COND_TOOLKIT_PM_USE_GUI_1_WXUNIV_0@monodll_print.o: $(srcdir)/src/os2/print.cpp $(MONODLL_ODEP) +@COND_TOOLKIT_PM_USE_GUI_1_WXUNIV_0@ $(CXXC) -c -o $@ $(MONODLL_CXXFLAGS) $(srcdir)/src/os2/print.cpp + @COND_TOOLKIT_GTK_TOOLKIT_VERSION_2_USE_GUI_1_WXUNIV_0@monodll_listbox.o: $(srcdir)/src/gtk/listbox.cpp $(MONODLL_ODEP) @COND_TOOLKIT_GTK_TOOLKIT_VERSION_2_USE_GUI_1_WXUNIV_0@ $(CXXC) -c -o $@ $(MONODLL_CXXFLAGS) $(srcdir)/src/gtk/listbox.cpp @@ -18293,9 +18301,6 @@ monolib_regiong.o: $(srcdir)/src/generic/regiong.cpp $(MONOLIB_ODEP) monolib_gsockpm.o: $(srcdir)/src/os2/gsockpm.cpp $(MONOLIB_ODEP) $(CXXC) -c -o $@ $(MONOLIB_CXXFLAGS) $(srcdir)/src/os2/gsockpm.cpp -monolib_print.o: $(srcdir)/src/os2/print.cpp $(MONOLIB_ODEP) - $(CXXC) -c -o $@ $(MONOLIB_CXXFLAGS) $(srcdir)/src/os2/print.cpp - monolib_colschem.o: $(srcdir)/src/univ/colschem.cpp $(MONOLIB_ODEP) $(CXXC) -c -o $@ $(MONOLIB_CXXFLAGS) $(srcdir)/src/univ/colschem.cpp @@ -20921,6 +20926,12 @@ monolib_sound_sdl.o: $(srcdir)/src/unix/sound_sdl.cpp $(MONOLIB_ODEP) @COND_USE_GUI_1_WXUNIV_1@monolib_gauge.o: $(srcdir)/src/univ/gauge.cpp $(MONOLIB_ODEP) @COND_USE_GUI_1_WXUNIV_1@ $(CXXC) -c -o $@ $(MONOLIB_CXXFLAGS) $(srcdir)/src/univ/gauge.cpp +@COND_TOOLKIT_GTK_TOOLKIT_VERSION_2_USE_GUI_1_WXUNIV_0@monolib_print.o: $(srcdir)/src/gtk/print.cpp $(MONOLIB_ODEP) +@COND_TOOLKIT_GTK_TOOLKIT_VERSION_2_USE_GUI_1_WXUNIV_0@ $(CXXC) -c -o $@ $(MONOLIB_CXXFLAGS) $(srcdir)/src/gtk/print.cpp + +@COND_TOOLKIT_PM_USE_GUI_1_WXUNIV_0@monolib_print.o: $(srcdir)/src/os2/print.cpp $(MONOLIB_ODEP) +@COND_TOOLKIT_PM_USE_GUI_1_WXUNIV_0@ $(CXXC) -c -o $@ $(MONOLIB_CXXFLAGS) $(srcdir)/src/os2/print.cpp + @COND_TOOLKIT_GTK_TOOLKIT_VERSION_2_USE_GUI_1_WXUNIV_0@monolib_listbox.o: $(srcdir)/src/gtk/listbox.cpp $(MONOLIB_ODEP) @COND_TOOLKIT_GTK_TOOLKIT_VERSION_2_USE_GUI_1_WXUNIV_0@ $(CXXC) -c -o $@ $(MONOLIB_CXXFLAGS) $(srcdir)/src/gtk/listbox.cpp @@ -23960,9 +23971,6 @@ coredll_regiong.o: $(srcdir)/src/generic/regiong.cpp $(COREDLL_ODEP) coredll_gsockpm.o: $(srcdir)/src/os2/gsockpm.cpp $(COREDLL_ODEP) $(CXXC) -c -o $@ $(COREDLL_CXXFLAGS) $(srcdir)/src/os2/gsockpm.cpp -coredll_print.o: $(srcdir)/src/os2/print.cpp $(COREDLL_ODEP) - $(CXXC) -c -o $@ $(COREDLL_CXXFLAGS) $(srcdir)/src/os2/print.cpp - coredll_colschem.o: $(srcdir)/src/univ/colschem.cpp $(COREDLL_ODEP) $(CXXC) -c -o $@ $(COREDLL_CXXFLAGS) $(srcdir)/src/univ/colschem.cpp @@ -25799,6 +25807,12 @@ coredll_win32.o: $(srcdir)/src/univ/themes/win32.cpp $(COREDLL_ODEP) @COND_USE_GUI_1_WXUNIV_1@coredll_gauge.o: $(srcdir)/src/univ/gauge.cpp $(COREDLL_ODEP) @COND_USE_GUI_1_WXUNIV_1@ $(CXXC) -c -o $@ $(COREDLL_CXXFLAGS) $(srcdir)/src/univ/gauge.cpp +@COND_TOOLKIT_GTK_TOOLKIT_VERSION_2_USE_GUI_1_WXUNIV_0@coredll_print.o: $(srcdir)/src/gtk/print.cpp $(COREDLL_ODEP) +@COND_TOOLKIT_GTK_TOOLKIT_VERSION_2_USE_GUI_1_WXUNIV_0@ $(CXXC) -c -o $@ $(COREDLL_CXXFLAGS) $(srcdir)/src/gtk/print.cpp + +@COND_TOOLKIT_PM_USE_GUI_1_WXUNIV_0@coredll_print.o: $(srcdir)/src/os2/print.cpp $(COREDLL_ODEP) +@COND_TOOLKIT_PM_USE_GUI_1_WXUNIV_0@ $(CXXC) -c -o $@ $(COREDLL_CXXFLAGS) $(srcdir)/src/os2/print.cpp + @COND_TOOLKIT_GTK_TOOLKIT_VERSION_2_USE_GUI_1_WXUNIV_0@coredll_listbox.o: $(srcdir)/src/gtk/listbox.cpp $(COREDLL_ODEP) @COND_TOOLKIT_GTK_TOOLKIT_VERSION_2_USE_GUI_1_WXUNIV_0@ $(CXXC) -c -o $@ $(COREDLL_CXXFLAGS) $(srcdir)/src/gtk/listbox.cpp @@ -26918,9 +26932,6 @@ corelib_regiong.o: $(srcdir)/src/generic/regiong.cpp $(CORELIB_ODEP) corelib_gsockpm.o: $(srcdir)/src/os2/gsockpm.cpp $(CORELIB_ODEP) $(CXXC) -c -o $@ $(CORELIB_CXXFLAGS) $(srcdir)/src/os2/gsockpm.cpp -corelib_print.o: $(srcdir)/src/os2/print.cpp $(CORELIB_ODEP) - $(CXXC) -c -o $@ $(CORELIB_CXXFLAGS) $(srcdir)/src/os2/print.cpp - corelib_colschem.o: $(srcdir)/src/univ/colschem.cpp $(CORELIB_ODEP) $(CXXC) -c -o $@ $(CORELIB_CXXFLAGS) $(srcdir)/src/univ/colschem.cpp @@ -28757,6 +28768,12 @@ corelib_win32.o: $(srcdir)/src/univ/themes/win32.cpp $(CORELIB_ODEP) @COND_USE_GUI_1_WXUNIV_1@corelib_gauge.o: $(srcdir)/src/univ/gauge.cpp $(CORELIB_ODEP) @COND_USE_GUI_1_WXUNIV_1@ $(CXXC) -c -o $@ $(CORELIB_CXXFLAGS) $(srcdir)/src/univ/gauge.cpp +@COND_TOOLKIT_GTK_TOOLKIT_VERSION_2_USE_GUI_1_WXUNIV_0@corelib_print.o: $(srcdir)/src/gtk/print.cpp $(CORELIB_ODEP) +@COND_TOOLKIT_GTK_TOOLKIT_VERSION_2_USE_GUI_1_WXUNIV_0@ $(CXXC) -c -o $@ $(CORELIB_CXXFLAGS) $(srcdir)/src/gtk/print.cpp + +@COND_TOOLKIT_PM_USE_GUI_1_WXUNIV_0@corelib_print.o: $(srcdir)/src/os2/print.cpp $(CORELIB_ODEP) +@COND_TOOLKIT_PM_USE_GUI_1_WXUNIV_0@ $(CXXC) -c -o $@ $(CORELIB_CXXFLAGS) $(srcdir)/src/os2/print.cpp + @COND_TOOLKIT_GTK_TOOLKIT_VERSION_2_USE_GUI_1_WXUNIV_0@corelib_listbox.o: $(srcdir)/src/gtk/listbox.cpp $(CORELIB_ODEP) @COND_TOOLKIT_GTK_TOOLKIT_VERSION_2_USE_GUI_1_WXUNIV_0@ $(CXXC) -c -o $@ $(CORELIB_CXXFLAGS) $(srcdir)/src/gtk/listbox.cpp diff --git a/build/bakefiles/files.bkl b/build/bakefiles/files.bkl index 2b48015a98..8325476eff 100644 --- a/build/bakefiles/files.bkl +++ b/build/bakefiles/files.bkl @@ -1056,6 +1056,7 @@ IMPORTANT: please read docs/tech/tn0016.txt before modifying this file! src/gtk/gauge.cpp src/gtk/gnome/gprint.cpp src/gtk/gnome/gvfs.cpp + src/gtk/print.cpp src/gtk/listbox.cpp src/gtk/mdi.cpp src/gtk/menu.cpp @@ -1106,6 +1107,7 @@ IMPORTANT: please read docs/tech/tn0016.txt before modifying this file! wx/gtk/gauge.h wx/gtk/gnome/gprint.h wx/gtk/gnome/gvfs.h + wx/gtk/print.h wx/gtk/listbox.h wx/gtk/mdi.h wx/gtk/menu.h diff --git a/include/wx/gtk/print.h b/include/wx/gtk/print.h new file mode 100644 index 0000000000..ae98de2e71 --- /dev/null +++ b/include/wx/gtk/print.h @@ -0,0 +1,400 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: wx/gtk/print.h +// Author: Anthony Bretaudeau +// Purpose: GTK printing support +// Created: 2007-08-25 +// RCS-ID: $Id: print.h,v 1 2007-08-25 05:44:44 PC Exp $ +// Copyright: (c) 2007 wxWidgets development team +// Licence: wxWindows Licence +///////////////////////////////////////////////////////////////////////////// + +#ifndef _WX_GTK_PRINT_H_ +#define _WX_GTK_PRINT_H_ + +#include "wx/defs.h" + +#if wxUSE_GTKPRINT + +#include "wx/print.h" +#include "wx/printdlg.h" +#include "wx/prntbase.h" +#include "wx/dc.h" + +typedef struct _GtkPrintOperation GtkPrintOperation; +typedef struct _GtkPrintContext GtkPrintContext; +typedef struct _GtkPrintSettings GtkPrintSettings; +typedef struct _GtkPageSetup GtkPageSetup; + +typedef struct _cairo cairo_t; + +//---------------------------------------------------------------------------- +// wxGtkPrintFactory +//---------------------------------------------------------------------------- + +class wxGtkPrintFactory: public wxPrintFactory +{ +public: + virtual wxPrinterBase *CreatePrinter( wxPrintDialogData *data ); + + virtual wxPrintPreviewBase *CreatePrintPreview( wxPrintout *preview, + wxPrintout *printout = NULL, + wxPrintDialogData *data = NULL ); + virtual wxPrintPreviewBase *CreatePrintPreview( wxPrintout *preview, + wxPrintout *printout, + wxPrintData *data ); + + virtual wxPrintDialogBase *CreatePrintDialog( wxWindow *parent, + wxPrintDialogData *data = NULL ); + virtual wxPrintDialogBase *CreatePrintDialog( wxWindow *parent, + wxPrintData *data ); + + virtual wxPageSetupDialogBase *CreatePageSetupDialog( wxWindow *parent, + wxPageSetupDialogData * data = NULL ); + + virtual wxDC* CreatePrinterDC( const wxPrintData& data ); + + virtual bool HasPrintSetupDialog(); + virtual wxDialog *CreatePrintSetupDialog( wxWindow *parent, wxPrintData *data ); + virtual bool HasOwnPrintToFile(); + virtual bool HasPrinterLine(); + virtual wxString CreatePrinterLine(); + virtual bool HasStatusLine(); + virtual wxString CreateStatusLine(); + + virtual wxPrintNativeDataBase *CreatePrintNativeData(); +}; + +//---------------------------------------------------------------------------- +// wxGtkPrintDialog +//---------------------------------------------------------------------------- + +class WXDLLIMPEXP_CORE wxGtkPrintDialog: public wxPrintDialogBase +{ +public: + wxGtkPrintDialog( wxWindow *parent, + wxPrintDialogData* data = NULL ); + wxGtkPrintDialog( wxWindow *parent, wxPrintData* data); + virtual ~wxGtkPrintDialog(); + + wxPrintData& GetPrintData() + { return m_printDialogData.GetPrintData(); } + wxPrintDialogData& GetPrintDialogData() + { return m_printDialogData; } + + wxDC *GetPrintDC() { return m_dc; } + void SetPrintDC(wxDC * printDC) { m_dc = printDC; } + + virtual int ShowModal(); + + virtual bool Validate() { return true; } + virtual bool TransferDataToWindow() { return true; } + virtual bool TransferDataFromWindow() { return true; } + + void SetShowDialog(bool show) { m_showDialog = show; } + bool GetShowDialog() { return m_showDialog; } + +protected: + // Implement some base class methods to do nothing to avoid asserts and + // GTK warnings, since this is not a real wxDialog. + virtual void DoSetSize(int WXUNUSED(x), int WXUNUSED(y), + int WXUNUSED(width), int WXUNUSED(height), + int WXUNUSED(sizeFlags) = wxSIZE_AUTO) {} + virtual void DoMoveWindow(int WXUNUSED(x), int WXUNUSED(y), + int WXUNUSED(width), int WXUNUSED(height)) {} + +private: + wxPrintDialogData m_printDialogData; + wxWindow *m_parent; + bool m_showDialog; + wxDC *m_dc; + + DECLARE_DYNAMIC_CLASS(wxGtkPrintDialog) +}; + +//---------------------------------------------------------------------------- +// wxGtkPageSetupDialog +//---------------------------------------------------------------------------- + +class WXDLLIMPEXP_CORE wxGtkPageSetupDialog: public wxPageSetupDialogBase +{ +public: + wxGtkPageSetupDialog( wxWindow *parent, + wxPageSetupDialogData* data = NULL ); + virtual ~wxGtkPageSetupDialog(); + + virtual wxPageSetupDialogData& GetPageSetupDialogData() { return m_pageDialogData; } + + virtual int ShowModal(); + + virtual bool Validate() { return true; } + virtual bool TransferDataToWindow() { return true; } + virtual bool TransferDataFromWindow() { return true; } + +protected: + // Implement some base class methods to do nothing to avoid asserts and + // GTK warnings, since this is not a real wxDialog. + virtual void DoSetSize(int WXUNUSED(x), int WXUNUSED(y), + int WXUNUSED(width), int WXUNUSED(height), + int WXUNUSED(sizeFlags) = wxSIZE_AUTO) {} + virtual void DoMoveWindow(int WXUNUSED(x), int WXUNUSED(y), + int WXUNUSED(width), int WXUNUSED(height)) {} + +private: + wxPageSetupDialogData m_pageDialogData; + wxWindow *m_parent; + + DECLARE_DYNAMIC_CLASS(wxGtkPageSetupDialog) +}; + +//---------------------------------------------------------------------------- +// wxGtkPrinter +//---------------------------------------------------------------------------- + +class WXDLLIMPEXP_CORE wxGtkPrinter : public wxPrinterBase +{ +public: + wxGtkPrinter(wxPrintDialogData *data = NULL); + virtual ~wxGtkPrinter(); + + virtual bool Print(wxWindow *parent, + wxPrintout *printout, + bool prompt = true); + virtual wxDC* PrintDialog(wxWindow *parent); + virtual bool Setup(wxWindow *parent); + + GtkPrintContext *GetPrintContext() { return m_gpc; } + void SetPrintContext(GtkPrintContext *context) {m_gpc = context;} + void BeginPrint(wxPrintout *printout, GtkPrintOperation *operation, GtkPrintContext *context); + void DrawPage(wxPrintout *printout, GtkPrintOperation *operation, GtkPrintContext *context, int page_nr); + +private: + GtkPrintContext *m_gpc; + bool m_showDialog; + wxDC *m_dc; + + DECLARE_DYNAMIC_CLASS(wxGtkPrinter) + DECLARE_NO_COPY_CLASS(wxGtkPrinter) +}; + +//---------------------------------------------------------------------------- +// wxGtkPrintNativeData +//---------------------------------------------------------------------------- + +class WXDLLIMPEXP_CORE wxGtkPrintNativeData : public wxPrintNativeDataBase +{ +public: + wxGtkPrintNativeData(); + virtual ~wxGtkPrintNativeData(); + + virtual bool TransferTo( wxPrintData &data ); + virtual bool TransferFrom( const wxPrintData &data ); + + virtual bool Ok() const { return IsOk(); } + virtual bool IsOk() const { return true; } + + GtkPrintSettings* GetPrintConfig() { return m_config; } + void SetPrintConfig( GtkPrintSettings * config ); + + void SetPrintJob( GtkPrintOperation *job ) { m_job = job; } + GtkPrintOperation* GetPrintJob() { return m_job; } + + GtkPrintContext *GetPrintContext() { return m_context; } + void SetPrintContext(GtkPrintContext *context) {m_context = context; } + + + GtkPageSetup* GetPageSetupFromSettings(GtkPrintSettings* settings); + void SetPageSetupToSettings(GtkPrintSettings* settings, GtkPageSetup* page_setup); + +private: + GtkPrintSettings *m_config; + GtkPrintOperation *m_job; + GtkPrintContext *m_context; + + DECLARE_DYNAMIC_CLASS(wxGtkPrintNativeData) +}; + +//----------------------------------------------------------------------------- +// wxGtkPrintDC +//----------------------------------------------------------------------------- + +class WXDLLIMPEXP_CORE wxGtkPrintDC: public wxDC +{ +public: + wxGtkPrintDC( const wxPrintData& data ); + virtual ~wxGtkPrintDC(); + + bool Ok() const { return IsOk(); } + bool IsOk() const; + + bool CanDrawBitmap() const { return true; } + void Clear(); + void SetFont( const wxFont& font ); + void SetPen( const wxPen& pen ); + void SetBrush( const wxBrush& brush ); + void SetLogicalFunction( int function ); + void SetBackground( const wxBrush& brush ); + void DestroyClippingRegion(); + bool StartDoc(const wxString& message); + void EndDoc(); + void StartPage(); + void EndPage(); + wxCoord GetCharHeight() const; + wxCoord GetCharWidth() const; + bool CanGetTextExtent() const { return true; } + wxSize GetPPI() const; + void SetLogicalOrigin( wxCoord x, wxCoord y ); + void SetDeviceOrigin( wxCoord x, wxCoord y ); + virtual int GetDepth() const { return 24; } + void SetBackgroundMode(int WXUNUSED(mode)); + void SetPalette(const wxPalette& WXUNUSED(palette)) { } + static void SetResolution(int ppi); + static int GetResolution(); + void DrawScaledBitmap(const wxBitmap &bmp, wxCoord x, wxCoord y, wxCoord w, wxCoord h, + bool useMask = false, int quality = wxIMAGE_QUALITY_NORMAL) + { DoDrawScaledBitmap( bmp, x, y, w, h, useMask, quality ); } + void DrawScaledBitmap(const wxBitmap &bmp, const wxPoint& pt, const wxSize& sz, + bool useMask = false, int quality = wxIMAGE_QUALITY_NORMAL) + { DoDrawScaledBitmap( bmp, pt.x, pt.y, sz.x, sz.y, useMask, quality ); } + void DrawScaledBitmap(const wxBitmap &bmp, const wxRect& rect, + bool useMask = false, int quality = wxIMAGE_QUALITY_NORMAL) + { DoDrawScaledBitmap( bmp, rect.x, rect.y, rect.width, rect.height, useMask, quality ); } + +protected: + bool DoFloodFill(wxCoord x1, wxCoord y1, const wxColour &col, int style=wxFLOOD_SURFACE ); + void DoGradientFillConcentric(const wxRect& rect, const wxColour& initialColour, const wxColour& destColour, const wxPoint& circleCenter); + void DoGradientFillLinear(const wxRect& rect, const wxColour& initialColour, const wxColour& destColour, wxDirection nDirection = wxEAST); + bool DoGetPixel(wxCoord x1, wxCoord y1, wxColour *col) const; + void DoDrawLine(wxCoord x1, wxCoord y1, wxCoord x2, wxCoord y2); + void DoCrossHair(wxCoord x, wxCoord y); + void DoDrawArc(wxCoord x1,wxCoord y1,wxCoord x2,wxCoord y2,wxCoord xc,wxCoord yc); + void DoDrawEllipticArc(wxCoord x,wxCoord y,wxCoord w,wxCoord h,double sa,double ea); + void DoDrawPoint(wxCoord x, wxCoord y); + void DoDrawLines(int n, wxPoint points[], wxCoord xoffset = 0, wxCoord yoffset = 0); + void DoDrawPolygon(int n, wxPoint points[], wxCoord xoffset = 0, wxCoord yoffset = 0, int fillStyle=wxODDEVEN_RULE); + void DoDrawPolyPolygon(int n, int count[], wxPoint points[], wxCoord xoffset = 0, wxCoord yoffset = 0, int fillStyle=wxODDEVEN_RULE); + void DoDrawRectangle(wxCoord x, wxCoord y, wxCoord width, wxCoord height); + void DoDrawRoundedRectangle(wxCoord x, wxCoord y, wxCoord width, wxCoord height, double radius = 20.0); + void DoDrawEllipse(wxCoord x, wxCoord y, wxCoord width, wxCoord height); +#if wxUSE_SPLINES + void DoDrawSpline(wxList *points); +#endif // wxUSE_SPLINES + bool DoBlit(wxCoord xdest, wxCoord ydest, wxCoord width, wxCoord height, + wxDC *source, wxCoord xsrc, wxCoord ysrc, int rop = wxCOPY, bool useMask = false, + wxCoord xsrcMask = wxDefaultCoord, wxCoord ysrcMask = wxDefaultCoord); + void DoDrawIcon( const wxIcon& icon, wxCoord x, wxCoord y ); + void DoDrawBitmap( const wxBitmap& bitmap, wxCoord x, wxCoord y, bool useMask = false ); + void DoDrawScaledBitmap( const wxBitmap& bitmap, wxCoord x, wxCoord y, wxCoord w, wxCoord h, bool useMask = false, int quality = wxIMAGE_QUALITY_NORMAL ); + void DoDrawText(const wxString& text, wxCoord x, wxCoord y ); + void DoDrawRotatedText(const wxString& text, wxCoord x, wxCoord y, double angle); + void DoSetClippingRegion(wxCoord x, wxCoord y, wxCoord width, wxCoord height); + void DoSetClippingRegionAsRegion( const wxRegion &WXUNUSED(clip) ) { } + void DoGetTextExtent(const wxString& string, wxCoord *x, wxCoord *y, + wxCoord *descent = (wxCoord *) NULL, + wxCoord *externalLeading = (wxCoord *) NULL, + const wxFont *theFont = (wxFont *) NULL ) const; + void DoGetSize(int* width, int* height) const; + void DoGetSizeMM(int *width, int *height) const; + + wxPrintData& GetPrintData() { return m_printData; } + void SetPrintData(const wxPrintData& data); + + void ComputeScaleAndOrigin(); + +private: + static float ms_PSScaleFactor; + + wxPrintData m_printData; + PangoContext *m_context; + PangoLayout *m_layout; + PangoFontDescription *m_fontdesc; + cairo_t *m_cairo; + + unsigned char m_currentRed; + unsigned char m_currentGreen; + unsigned char m_currentBlue; + unsigned char m_currentAlpha; + + int m_deviceOffsetY; + int m_deviceOffsetX; + + GtkPrintContext *m_gpc; + static int ms_resolution; + + wxCoord DeviceToLogicalX(wxCoord x) const + { + int addValue = 0; + if (m_signX == -1) addValue = m_deviceOffsetX - m_deviceOriginX; // right to left + else addValue = m_deviceOriginX;// left to right + return (wxCoord) ((double)(x - addValue) * m_signX + m_logicalOriginX); + } + wxCoord DeviceToLogicalXRel(wxCoord x) const + { + return x; + } + wxCoord DeviceToLogicalY(wxCoord y) const + { + int addValue = 0; + if (m_signY == -1) addValue = m_deviceOffsetY - m_deviceOriginY; // bottom to up + else addValue = m_deviceOriginY;// up to bottom + return (wxCoord) ((double)(y - addValue) * m_signY + m_logicalOriginY); + } + wxCoord DeviceToLogicalYRel(wxCoord y) const + { + return y; + } + wxCoord LogicalToDeviceX(wxCoord x) const + { + int addValue = 0; + if (m_signX == -1) addValue = m_deviceOffsetX - m_deviceOriginX; // right to left + else addValue = m_deviceOriginX;// left to right + return (wxCoord) ((double)(x - m_logicalOriginX) * m_signX + addValue); + } + wxCoord LogicalToDeviceXRel(wxCoord x) const + { + return x; + } + wxCoord LogicalToDeviceY(wxCoord y) const + { + int addValue = 0; + if (m_signY == -1) addValue = m_deviceOffsetY - m_deviceOriginY; // bottom to up + else addValue = m_deviceOriginY;// up to bottom + return (wxCoord) ((double)(y - m_logicalOriginY) * m_signY + addValue); + } + wxCoord LogicalToDeviceYRel(wxCoord y) const + { + return y; + } + + DECLARE_DYNAMIC_CLASS(wxGtkPrintDC) + DECLARE_NO_COPY_CLASS(wxGtkPrintDC) +}; + +// ---------------------------------------------------------------------------- +// wxGtkPrintPreview: programmer creates an object of this class to preview a +// wxPrintout. +// ---------------------------------------------------------------------------- + +class WXDLLIMPEXP_CORE wxGtkPrintPreview : public wxPrintPreviewBase +{ +public: + wxGtkPrintPreview(wxPrintout *printout, + wxPrintout *printoutForPrinting = (wxPrintout *) NULL, + wxPrintDialogData *data = (wxPrintDialogData *) NULL); + wxGtkPrintPreview(wxPrintout *printout, + wxPrintout *printoutForPrinting, + wxPrintData *data); + + virtual ~wxGtkPrintPreview(); + + virtual bool Print(bool interactive); + virtual void DetermineScaling(); + +private: + void Init(wxPrintout *printout, wxPrintout *printoutForPrinting); + + DECLARE_CLASS(wxGtkPrintPreview) +}; + +#endif + +#endif diff --git a/src/generic/prntdlgg.cpp b/src/generic/prntdlgg.cpp index 110cb87ea3..02f1434937 100644 --- a/src/generic/prntdlgg.cpp +++ b/src/generic/prntdlgg.cpp @@ -68,8 +68,8 @@ #endif #if wxUSE_GTKPRINT - // #include "wx/link.h" - // wxFORCE_LINK_MODULE(gtk_print) + #include "wx/link.h" + wxFORCE_LINK_MODULE(gtk_print) #endif // ---------------------------------------------------------------------------- diff --git a/src/gtk/print.cpp b/src/gtk/print.cpp new file mode 100644 index 0000000000..d3c20a3d0b --- /dev/null +++ b/src/gtk/print.cpp @@ -0,0 +1,2414 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: wx/gtk/print.cpp +// Author: Anthony Bretaudeau +// Purpose: GTK printing support +// Created: 2007-08-25 +// RCS-ID: $Id: print.cpp,v 1 2007-08-25 05:44:44 PC Exp $ +// Copyright: (c) 2007 wxWidgets development team +// Licence: wxWindows Licence +///////////////////////////////////////////////////////////////////////////// + +// For compilers that support precompilation, includes "wx/wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ +#pragma hdrstop +#endif + +#if wxUSE_GTKPRINT + +#include "wx/gtk/print.h" + +#ifndef WX_PRECOMP +#include "wx/log.h" +#include "wx/dcmemory.h" +#include "wx/icon.h" +#include "wx/math.h" +#include "wx/image.h" +#include "wx/module.h" +#endif + +#include "wx/fontutil.h" +#include "wx/gtk/private.h" +#include "wx/dynlib.h" +#include "wx/paper.h" +#include "wx/rawbmp.h" + +#include +#include + +#include "wx/link.h" +wxFORCE_LINK_THIS_MODULE(gtk_print) + +#if wxUSE_LIBGNOMEPRINT +#include "wx/gtk/gnome/gprint.h" +#endif + +// Usefull to convert angles from/to Rad to/from Deg. +static const double RAD2DEG = 180.0 / M_PI; +static const double DEG2RAD = M_PI / 180.0; + +//---------------------------------------------------------------------------- +// wxGtkPrintModule +// Initialized when starting the app : if it successfully load the gtk-print framework, +// it uses it. If not, it falls back to gnome print (see /gtk/gnome/gprint.cpp) then +// to postscript if gnomeprint is not available. +//---------------------------------------------------------------------------- + +class wxGtkPrintModule: public wxModule +{ +public: + wxGtkPrintModule() + { +#if wxUSE_LIBGNOMEPRINT + // This module must be initialized AFTER gnomeprint's one + AddDependency(CLASSINFO(wxGnomePrintModule)); +#endif + } + bool OnInit(); + void OnExit(); + +private: + DECLARE_DYNAMIC_CLASS(wxGtkPrintModule) +}; + +bool wxGtkPrintModule::OnInit() +{ + if (gtk_check_version(2,10,0) == NULL) + wxPrintFactory::SetPrintFactory( new wxGtkPrintFactory ); + + return true; +} + +void wxGtkPrintModule::OnExit() +{ +} + +IMPLEMENT_DYNAMIC_CLASS(wxGtkPrintModule, wxModule) + + +//---------------------------------------------------------------------------- +// wxGtkPrintFactory +//---------------------------------------------------------------------------- + +wxPrinterBase* wxGtkPrintFactory::CreatePrinter( wxPrintDialogData *data ) +{ + return new wxGtkPrinter( data ); +} + +wxPrintPreviewBase *wxGtkPrintFactory::CreatePrintPreview( wxPrintout *preview, + wxPrintout *printout, + wxPrintDialogData *data ) +{ + return new wxGtkPrintPreview( preview, printout, data ); +} + +wxPrintPreviewBase *wxGtkPrintFactory::CreatePrintPreview( wxPrintout *preview, + wxPrintout *printout, + wxPrintData *data ) +{ + return new wxGtkPrintPreview( preview, printout, data ); +} + +wxPrintDialogBase *wxGtkPrintFactory::CreatePrintDialog( wxWindow *parent, + wxPrintDialogData *data ) +{ + return new wxGtkPrintDialog( parent, data ); +} + +wxPrintDialogBase *wxGtkPrintFactory::CreatePrintDialog( wxWindow *parent, + wxPrintData *data ) +{ + return new wxGtkPrintDialog( parent, data ); +} + +wxPageSetupDialogBase *wxGtkPrintFactory::CreatePageSetupDialog( wxWindow *parent, + wxPageSetupDialogData * data ) +{ + return new wxGtkPageSetupDialog( parent, data ); +} + +bool wxGtkPrintFactory::HasPrintSetupDialog() +{ + return false; +} + +wxDialog *wxGtkPrintFactory::CreatePrintSetupDialog( wxWindow *parent, wxPrintData *data ) +{ + return NULL; +} + +wxDC* wxGtkPrintFactory::CreatePrinterDC( const wxPrintData& data ) +{ + return new wxGtkPrintDC(data); +} + +bool wxGtkPrintFactory::HasOwnPrintToFile() +{ + return true; +} + +bool wxGtkPrintFactory::HasPrinterLine() +{ + return true; +} + +wxString wxGtkPrintFactory::CreatePrinterLine() +{ + // redundant now + return wxEmptyString; +} + +bool wxGtkPrintFactory::HasStatusLine() +{ + // redundant now + return true; +} + +wxString wxGtkPrintFactory::CreateStatusLine() +{ + // redundant now + return wxEmptyString; +} + +wxPrintNativeDataBase *wxGtkPrintFactory::CreatePrintNativeData() +{ + return new wxGtkPrintNativeData; +} + +//---------------------------------------------------------------------------- +// Callback functions for Gtk Printings. +//---------------------------------------------------------------------------- + +// We use it to pass useful objets to gtk printing callback functions. +typedef struct +{ + wxGtkPrinter * printer; + wxPrintout * printout; +} +wxPrinterToGtkData; + +extern "C" +{ + static void gtk_begin_print_callback (GtkPrintOperation *operation, GtkPrintContext *context, gpointer user_data) + { + wxPrinterToGtkData *data = (wxPrinterToGtkData *) user_data; + + data->printer->BeginPrint(data->printout, operation, context); + } + + static void gtk_draw_page_print_callback (GtkPrintOperation *operation, GtkPrintContext *context, gint page_nr, gpointer user_data) + { + wxPrinterToGtkData *data = (wxPrinterToGtkData *) user_data; + + data->printer->DrawPage(data->printout, operation, context, page_nr); + } + + static void gtk_end_print_callback (GtkPrintOperation *operation, GtkPrintContext *context, gpointer user_data) + { + wxPrintout *printout = (wxPrintout *) user_data; + + printout->OnEndPrinting(); + } + + static gboolean gtk_preview_print_callback (GtkPrintOperation *operation, GtkPrintOperationPreview *preview, GtkPrintContext *context, GtkWindow *parent, gpointer user_data) + { + wxPrintout *printout = (wxPrintout *) user_data; + + printout->SetIsPreview(true); + + /* We create a cairo context with 72dpi resolution. This resolution is only used for positionning. */ + cairo_t *cairo = gdk_cairo_create(GTK_WIDGET(parent)->window); + gtk_print_context_set_cairo_context(context, cairo, 72, 72); + + return false; + } +} + +//---------------------------------------------------------------------------- +// wxGtkPrintNativeData +//---------------------------------------------------------------------------- + +IMPLEMENT_CLASS(wxGtkPrintNativeData, wxPrintNativeDataBase) + +wxGtkPrintNativeData::wxGtkPrintNativeData() +{ + m_config = gtk_print_settings_new(); +} + +wxGtkPrintNativeData::~wxGtkPrintNativeData() +{ + g_object_unref (m_config); +} + +// Convert datas stored in m_config to a wxPrintData. +// Called by wxPrintData::ConvertFromNative(). +bool wxGtkPrintNativeData::TransferTo( wxPrintData &data ) +{ + if(!m_config) + return false; + + GtkPrintQuality quality = gtk_print_settings_get_quality(m_config); + if (quality == GTK_PRINT_QUALITY_HIGH) + data.SetQuality(wxPRINT_QUALITY_HIGH); + else if (quality == GTK_PRINT_QUALITY_LOW) + data.SetQuality(wxPRINT_QUALITY_LOW); + else if (quality == GTK_PRINT_QUALITY_DRAFT) + data.SetQuality(wxPRINT_QUALITY_DRAFT); + else + data.SetQuality(wxPRINT_QUALITY_MEDIUM); + + data.SetNoCopies(gtk_print_settings_get_n_copies(m_config)); + + data.SetColour(gtk_print_settings_get_use_color(m_config)); + + switch (gtk_print_settings_get_duplex(m_config)) + { + case GTK_PRINT_DUPLEX_SIMPLEX: data.SetDuplex (wxDUPLEX_SIMPLEX); + break; + + case GTK_PRINT_DUPLEX_HORIZONTAL: data.SetDuplex (wxDUPLEX_HORIZONTAL); + break; + + default: + case GTK_PRINT_DUPLEX_VERTICAL: data.SetDuplex (wxDUPLEX_VERTICAL); + break; + } + + GtkPageOrientation orientation = gtk_print_settings_get_orientation (m_config); + if (orientation == GTK_PAGE_ORIENTATION_PORTRAIT) + { + data.SetOrientation(wxPORTRAIT); + data.SetOrientationReversed(false); + } + else if (orientation == GTK_PAGE_ORIENTATION_LANDSCAPE) + { + data.SetOrientation(wxLANDSCAPE); + data.SetOrientationReversed(false); + } + else if (orientation == GTK_PAGE_ORIENTATION_REVERSE_PORTRAIT) + { + data.SetOrientation(wxPORTRAIT); + data.SetOrientationReversed(true); + } + else if (orientation == GTK_PAGE_ORIENTATION_REVERSE_LANDSCAPE) + { + data.SetOrientation(wxLANDSCAPE); + data.SetOrientationReversed(true); + } + + data.SetCollate(gtk_print_settings_get_collate (m_config)); + + // Paper formats : these are the most common paper formats. + GtkPaperSize *paper_size = gtk_print_settings_get_paper_size (m_config); + if (!paper_size) + data.SetPaperId(wxPAPER_NONE); + else if (gtk_paper_size_is_equal(paper_size,gtk_paper_size_new (GTK_PAPER_NAME_A3))) + data.SetPaperId(wxPAPER_A3); + else if (gtk_paper_size_is_equal(paper_size,gtk_paper_size_new (GTK_PAPER_NAME_A4))) + data.SetPaperId(wxPAPER_A4); + else if (gtk_paper_size_is_equal(paper_size,gtk_paper_size_new (GTK_PAPER_NAME_A5))) + data.SetPaperId(wxPAPER_A5); + else if (gtk_paper_size_is_equal(paper_size,gtk_paper_size_new (GTK_PAPER_NAME_B5))) + data.SetPaperId(wxPAPER_B5); + else if (gtk_paper_size_is_equal(paper_size,gtk_paper_size_new (GTK_PAPER_NAME_LETTER))) + data.SetPaperId(wxPAPER_LETTER); + else if (gtk_paper_size_is_equal(paper_size,gtk_paper_size_new (GTK_PAPER_NAME_LEGAL))) + data.SetPaperId(wxPAPER_LEGAL); + else if (gtk_paper_size_is_equal(paper_size,gtk_paper_size_new (GTK_PAPER_NAME_EXECUTIVE))) + data.SetPaperId(wxPAPER_EXECUTIVE); + else if (gtk_paper_size_is_equal(paper_size,gtk_paper_size_new ( (const gchar*)"na_number-10"))) + data.SetPaperId(wxPAPER_ENV_10); + else if (gtk_paper_size_is_equal(paper_size,gtk_paper_size_new ( (const gchar*)"iso-c5"))) + data.SetPaperId(wxPAPER_ENV_C5); + else if (gtk_paper_size_is_equal(paper_size,gtk_paper_size_new ( (const gchar*)"iso-c6"))) + data.SetPaperId(wxPAPER_ENV_C6); + else if (gtk_paper_size_is_equal(paper_size,gtk_paper_size_new ( (const gchar*)"jis-b5"))) + data.SetPaperId(wxPAPER_B5_TRANSVERSE); + else if (gtk_paper_size_is_equal(paper_size,gtk_paper_size_new ( (const gchar*)"iso-b5"))) + data.SetPaperId(wxPAPER_ENV_B5); + else if (gtk_paper_size_is_equal(paper_size,gtk_paper_size_new ( (const gchar*)"na_monarch"))) + data.SetPaperId(wxPAPER_ENV_MONARCH); + else if (gtk_paper_size_is_equal(paper_size,gtk_paper_size_new ( (const gchar*)"engineering-c"))) + data.SetPaperId( wxPAPER_CSHEET); + else if (gtk_paper_size_is_equal(paper_size,gtk_paper_size_new ( (const gchar*)"engineering-d"))) + data.SetPaperId( wxPAPER_DSHEET); + else if (gtk_paper_size_is_equal(paper_size,gtk_paper_size_new ( (const gchar*)"engineering-e"))) + data.SetPaperId( wxPAPER_ESHEET); + else if (gtk_paper_size_is_equal(paper_size,gtk_paper_size_new ( (const gchar*)"letter"))) + data.SetPaperId( wxPAPER_LETTERSMALL); + else if (gtk_paper_size_is_equal(paper_size,gtk_paper_size_new ( (const gchar*)"engineering-b"))) + data.SetPaperId( wxPAPER_TABLOID); + else if (gtk_paper_size_is_equal(paper_size,gtk_paper_size_new ( (const gchar*)"ledger"))) + data.SetPaperId( wxPAPER_LEDGER); + else if (gtk_paper_size_is_equal(paper_size,gtk_paper_size_new ( (const gchar*)"statement"))) + data.SetPaperId( wxPAPER_STATEMENT); + else if (gtk_paper_size_is_equal(paper_size,gtk_paper_size_new ( GTK_PAPER_NAME_A4 ))) + data.SetPaperId( wxPAPER_A4SMALL); + else if (gtk_paper_size_is_equal(paper_size,gtk_paper_size_new ( (const gchar*)"iso-b4"))) + data.SetPaperId( wxPAPER_B4); + else if (gtk_paper_size_is_equal(paper_size,gtk_paper_size_new ( (const gchar*)"folio"))) + data.SetPaperId( wxPAPER_FOLIO); + else if (gtk_paper_size_is_equal(paper_size,gtk_paper_size_new ( (const gchar*)"quarto"))) + data.SetPaperId( wxPAPER_QUARTO); + else if (gtk_paper_size_is_equal(paper_size,gtk_paper_size_new ( (const gchar*)"10x14"))) + data.SetPaperId( wxPAPER_10X14); + else if (gtk_paper_size_is_equal(paper_size,gtk_paper_size_new ( (const gchar*)"ledger"))) + data.SetPaperId( wxPAPER_11X17); + else if (gtk_paper_size_is_equal(paper_size,gtk_paper_size_new ( (const gchar*)"letter"))) + data.SetPaperId( wxPAPER_NOTE); + else if (gtk_paper_size_is_equal(paper_size,gtk_paper_size_new ( (const gchar*)"na-number-9-envelope"))) + data.SetPaperId( wxPAPER_ENV_9); + else if (gtk_paper_size_is_equal(paper_size,gtk_paper_size_new ( (const gchar*)"number-11"))) + data.SetPaperId( wxPAPER_ENV_11); + else if (gtk_paper_size_is_equal(paper_size,gtk_paper_size_new ( (const gchar*)"number-12"))) + data.SetPaperId( wxPAPER_ENV_12); + else if (gtk_paper_size_is_equal(paper_size,gtk_paper_size_new ( (const gchar*)"number-14"))) + data.SetPaperId( wxPAPER_ENV_14); + else if (gtk_paper_size_is_equal(paper_size,gtk_paper_size_new ( (const gchar*)"iso-designated"))) + data.SetPaperId( wxPAPER_ENV_DL); + else if (gtk_paper_size_is_equal(paper_size,gtk_paper_size_new ( (const gchar*)"iso-c3"))) + data.SetPaperId( wxPAPER_ENV_C3); + else if (gtk_paper_size_is_equal(paper_size,gtk_paper_size_new ( (const gchar*)"iso-c4"))) + data.SetPaperId( wxPAPER_ENV_C4); + else if (gtk_paper_size_is_equal(paper_size,gtk_paper_size_new ( (const gchar*)"c6/c5"))) + data.SetPaperId( wxPAPER_ENV_C65); + else if (gtk_paper_size_is_equal(paper_size,gtk_paper_size_new ( (const gchar*)"iso-b4"))) + data.SetPaperId( wxPAPER_ENV_B4); + else if (gtk_paper_size_is_equal(paper_size,gtk_paper_size_new ( (const gchar*)"iso-b6"))) + data.SetPaperId( wxPAPER_ENV_B6); + else if (gtk_paper_size_is_equal(paper_size,gtk_paper_size_new ( (const gchar*)"Italian"))) + data.SetPaperId( wxPAPER_ENV_ITALY); + else if (gtk_paper_size_is_equal(paper_size,gtk_paper_size_new ( (const gchar*)"personal"))) + data.SetPaperId( wxPAPER_ENV_PERSONAL); + else if (gtk_paper_size_is_equal(paper_size,gtk_paper_size_new ( (const gchar*)"fanfold-us"))) + data.SetPaperId( wxPAPER_FANFOLD_US); + else if (gtk_paper_size_is_equal(paper_size,gtk_paper_size_new ( (const gchar*)"fanfold-European"))) + data.SetPaperId( wxPAPER_FANFOLD_STD_GERMAN); + else if (gtk_paper_size_is_equal(paper_size,gtk_paper_size_new ( (const gchar*)"foolscap"))) + data.SetPaperId( wxPAPER_FANFOLD_LGL_GERMAN); + else + data.SetPaperId(wxPAPER_NONE); + return true; +} + +// Put datas given by the wxPrintData into m_config. +// Called by wxPrintData::ConvertToNative(). +bool wxGtkPrintNativeData::TransferFrom( const wxPrintData &data ) +{ + if(!m_config) + return false; + + wxPrintQuality quality = data.GetQuality(); + if (quality == wxPRINT_QUALITY_HIGH) + gtk_print_settings_set_quality (m_config, GTK_PRINT_QUALITY_HIGH); + else if (quality == wxPRINT_QUALITY_MEDIUM) + gtk_print_settings_set_quality (m_config, GTK_PRINT_QUALITY_NORMAL); + else if (quality == wxPRINT_QUALITY_LOW) + gtk_print_settings_set_quality (m_config, GTK_PRINT_QUALITY_LOW); + else if (quality == wxPRINT_QUALITY_DRAFT) + gtk_print_settings_set_quality (m_config, GTK_PRINT_QUALITY_DRAFT); + else if (quality > 1) + gtk_print_settings_set_resolution (m_config, quality); + else + gtk_print_settings_set_quality (m_config, GTK_PRINT_QUALITY_NORMAL); + + gtk_print_settings_set_n_copies(m_config, data.GetNoCopies()); + + gtk_print_settings_set_use_color(m_config, data.GetColour()); + + switch (data.GetDuplex()) + { + case wxDUPLEX_SIMPLEX: gtk_print_settings_set_duplex (m_config, GTK_PRINT_DUPLEX_SIMPLEX); + break; + + case wxDUPLEX_HORIZONTAL: gtk_print_settings_set_duplex (m_config, GTK_PRINT_DUPLEX_HORIZONTAL); + break; + + default: + case wxDUPLEX_VERTICAL: gtk_print_settings_set_duplex (m_config, GTK_PRINT_DUPLEX_VERTICAL); + break; + } + + if (!data.IsOrientationReversed()) + { + if (data.GetOrientation() == wxLANDSCAPE) + gtk_print_settings_set_orientation (m_config, GTK_PAGE_ORIENTATION_LANDSCAPE); + else + gtk_print_settings_set_orientation (m_config, GTK_PAGE_ORIENTATION_PORTRAIT); + } + else { + if (data.GetOrientation() == wxLANDSCAPE) + gtk_print_settings_set_orientation (m_config, GTK_PAGE_ORIENTATION_REVERSE_LANDSCAPE); + else + gtk_print_settings_set_orientation (m_config, GTK_PAGE_ORIENTATION_REVERSE_PORTRAIT); + } + + gtk_print_settings_set_collate (m_config, data.GetCollate()); + + // Paper formats: these are the most common paper formats. + switch (data.GetPaperId()) + { + case wxPAPER_A3: gtk_print_settings_set_paper_size(m_config, gtk_paper_size_new (GTK_PAPER_NAME_A3)); + break; + case wxPAPER_A4: gtk_print_settings_set_paper_size(m_config, gtk_paper_size_new (GTK_PAPER_NAME_A4)); + break; + case wxPAPER_A5: gtk_print_settings_set_paper_size(m_config, gtk_paper_size_new (GTK_PAPER_NAME_A5)); + break; + case wxPAPER_B5_TRANSVERSE: gtk_print_settings_set_paper_size(m_config, gtk_paper_size_new ((const gchar*) "jis-b5")); + break; + case wxPAPER_B5: gtk_print_settings_set_paper_size(m_config, gtk_paper_size_new (GTK_PAPER_NAME_B5)); + break; + case wxPAPER_LETTER: gtk_print_settings_set_paper_size(m_config, gtk_paper_size_new (GTK_PAPER_NAME_LETTER)); + break; + case wxPAPER_LEGAL: gtk_print_settings_set_paper_size(m_config, gtk_paper_size_new (GTK_PAPER_NAME_LEGAL)); + break; + case wxPAPER_EXECUTIVE: gtk_print_settings_set_paper_size(m_config, gtk_paper_size_new (GTK_PAPER_NAME_EXECUTIVE)); + break; + case wxPAPER_ENV_10: gtk_print_settings_set_paper_size(m_config, gtk_paper_size_new ((const gchar*) "na_number-10")); + break; + case wxPAPER_ENV_C5: gtk_print_settings_set_paper_size(m_config, gtk_paper_size_new ((const gchar*) "iso-c5")); + break; + case wxPAPER_ENV_C6: gtk_print_settings_set_paper_size(m_config, gtk_paper_size_new ((const gchar*) "iso-c6")); + break; + case wxPAPER_ENV_B5: gtk_print_settings_set_paper_size(m_config, gtk_paper_size_new ((const gchar*) "iso-c5b5")); + break; + case wxPAPER_ENV_MONARCH: gtk_print_settings_set_paper_size(m_config, gtk_paper_size_new ((const gchar*) "na_monarch")); + break; + case wxPAPER_CSHEET: gtk_print_settings_set_paper_size(m_config, gtk_paper_size_new ((const gchar*) "engineering-c")); + break; + case wxPAPER_DSHEET: gtk_print_settings_set_paper_size(m_config, gtk_paper_size_new ((const gchar*) "engineering-d")); + break; + case wxPAPER_ESHEET: gtk_print_settings_set_paper_size(m_config, gtk_paper_size_new ((const gchar*) "engineering-e")); + break; + case wxPAPER_LETTERSMALL: gtk_print_settings_set_paper_size(m_config, gtk_paper_size_new ((const gchar*) "letter")); + break; + case wxPAPER_TABLOID: gtk_print_settings_set_paper_size(m_config, gtk_paper_size_new ((const gchar*) "engineering-b")); + break; + case wxPAPER_LEDGER: gtk_print_settings_set_paper_size(m_config, gtk_paper_size_new ((const gchar*) "ledger")); + break; + case wxPAPER_STATEMENT: gtk_print_settings_set_paper_size(m_config, gtk_paper_size_new ((const gchar*) "statement")); + break; + case wxPAPER_A4SMALL: gtk_print_settings_set_paper_size(m_config, gtk_paper_size_new (GTK_PAPER_NAME_A4)); + break; + case wxPAPER_B4: gtk_print_settings_set_paper_size(m_config, gtk_paper_size_new ((const gchar*) "iso-b4")); + break; + case wxPAPER_FOLIO: gtk_print_settings_set_paper_size(m_config, gtk_paper_size_new ((const gchar*) "folio")); + break; + case wxPAPER_QUARTO: gtk_print_settings_set_paper_size(m_config, gtk_paper_size_new ((const gchar*) "quarto")); + break; + case wxPAPER_10X14: gtk_print_settings_set_paper_size(m_config, gtk_paper_size_new ((const gchar*) "10x14")); + break; + case wxPAPER_11X17: gtk_print_settings_set_paper_size(m_config, gtk_paper_size_new ((const gchar*) "ledger")); + break; + case wxPAPER_NOTE: gtk_print_settings_set_paper_size(m_config, gtk_paper_size_new ((const gchar*) "letter")); + break; + case wxPAPER_ENV_9: gtk_print_settings_set_paper_size(m_config, gtk_paper_size_new ((const gchar*) "na-number-9-envelope")); + break; + case wxPAPER_ENV_11: gtk_print_settings_set_paper_size(m_config, gtk_paper_size_new ((const gchar*) "number-11")); + break; + case wxPAPER_ENV_12: gtk_print_settings_set_paper_size(m_config, gtk_paper_size_new ((const gchar*) "number-12")); + break; + case wxPAPER_ENV_14: gtk_print_settings_set_paper_size(m_config, gtk_paper_size_new ((const gchar*) "number-14")); + break; + case wxPAPER_ENV_DL: gtk_print_settings_set_paper_size(m_config, gtk_paper_size_new ((const gchar*) "iso-designated")); + break; + case wxPAPER_ENV_C3: gtk_print_settings_set_paper_size(m_config, gtk_paper_size_new ((const gchar*) "iso-c3")); + break; + case wxPAPER_ENV_C4: gtk_print_settings_set_paper_size(m_config, gtk_paper_size_new ((const gchar*) "iso-c4")); + break; + case wxPAPER_ENV_C65: gtk_print_settings_set_paper_size(m_config, gtk_paper_size_new ((const gchar*) "c6/c5")); + break; + case wxPAPER_ENV_B4: gtk_print_settings_set_paper_size(m_config, gtk_paper_size_new ((const gchar*) "iso-b4")); + break; + case wxPAPER_ENV_B6: gtk_print_settings_set_paper_size(m_config, gtk_paper_size_new ((const gchar*) "iso-b6")); + break; + case wxPAPER_ENV_ITALY: gtk_print_settings_set_paper_size(m_config, gtk_paper_size_new ((const gchar*) "Italian")); + break; + case wxPAPER_ENV_PERSONAL: gtk_print_settings_set_paper_size(m_config, gtk_paper_size_new ((const gchar*) "personal")); + break; + case wxPAPER_FANFOLD_US: gtk_print_settings_set_paper_size(m_config, gtk_paper_size_new ((const gchar*) "fanfold-us")); + break; + case wxPAPER_FANFOLD_STD_GERMAN: gtk_print_settings_set_paper_size(m_config, gtk_paper_size_new ((const gchar*) "fanfold-European")); + break; + case wxPAPER_FANFOLD_LGL_GERMAN: gtk_print_settings_set_paper_size(m_config, gtk_paper_size_new ((const gchar*) "foolscap")); + break; + case wxPAPER_NONE: + default: break; + } + + return true; +} + +void wxGtkPrintNativeData::SetPrintConfig( GtkPrintSettings * config ) +{ + if (config) + m_config = gtk_print_settings_copy(config); +} + +// Extract page setup from settings. +GtkPageSetup* wxGtkPrintNativeData::GetPageSetupFromSettings(GtkPrintSettings* settings) +{ + GtkPageSetup* page_setup = gtk_page_setup_new(); + gtk_page_setup_set_orientation (page_setup, gtk_print_settings_get_orientation (settings)); + + GtkPaperSize *paper_size = gtk_print_settings_get_paper_size (settings); + if (paper_size != NULL) + gtk_page_setup_set_paper_size_and_default_margins (page_setup, paper_size); + + return page_setup; +} + +// Insert page setup into a given GtkPrintSettings. +void wxGtkPrintNativeData::SetPageSetupToSettings(GtkPrintSettings* settings, GtkPageSetup* page_setup) +{ + gtk_print_settings_set_orientation ( settings, gtk_page_setup_get_orientation (page_setup)); + gtk_print_settings_set_paper_size ( settings, gtk_page_setup_get_paper_size (page_setup)); +} + +//---------------------------------------------------------------------------- +// wxGtkPrintDialog +//---------------------------------------------------------------------------- + +IMPLEMENT_CLASS(wxGtkPrintDialog, wxPrintDialogBase) + +wxGtkPrintDialog::wxGtkPrintDialog( wxWindow *parent, wxPrintDialogData *data ) + : wxPrintDialogBase(parent, wxID_ANY, _("Print"), + wxPoint(0, 0), wxSize(600, 600), + wxDEFAULT_DIALOG_STYLE | + wxTAB_TRAVERSAL) +{ + if (data) + m_printDialogData = *data; + + m_parent = parent; + SetShowDialog(true); +} + +wxGtkPrintDialog::wxGtkPrintDialog( wxWindow *parent, wxPrintData *data ) + : wxPrintDialogBase(parent, wxID_ANY, _("Print"), + wxPoint(0, 0), wxSize(600, 600), + wxDEFAULT_DIALOG_STYLE | + wxTAB_TRAVERSAL) +{ + if (data) + m_printDialogData = *data; + + m_parent = parent; + SetShowDialog(true); +} + + +wxGtkPrintDialog::~wxGtkPrintDialog() +{ +} + +// This is called even if we actually don't want the dialog to appear. +int wxGtkPrintDialog::ShowModal() +{ + GtkPrintOperationResult response; + + // We need to restore the settings given in the constructor. + wxPrintData data = m_printDialogData.GetPrintData(); + wxGtkPrintNativeData *native = + (wxGtkPrintNativeData*) data.GetNativeData(); + data.ConvertToNative(); + + GtkPrintSettings * settings = native->GetPrintConfig(); + + // We have to restore pages to print here because they're stored in a wxPrintDialogData and ConvertToNative only works for wxPrintData. + int fromPage = m_printDialogData.GetFromPage(); + int toPage = m_printDialogData.GetToPage(); + if (m_printDialogData.GetSelection()) + gtk_print_settings_set_print_pages(settings, GTK_PRINT_PAGES_CURRENT); + else if (m_printDialogData.GetAllPages()) + gtk_print_settings_set_print_pages(settings, GTK_PRINT_PAGES_ALL); + else { + gtk_print_settings_set_print_pages(settings, GTK_PRINT_PAGES_RANGES); + GtkPageRange *range; + range = g_new (GtkPageRange, 1); + range[0].start = fromPage-1; + range[0].end = (toPage >= fromPage) ? toPage-1 : fromPage-1; + gtk_print_settings_set_page_ranges (settings, range, 1); + } + + // If the settings are OK, we restore it. + if (settings != NULL) + gtk_print_operation_set_print_settings (native->GetPrintJob(), settings); + gtk_print_operation_set_default_page_setup (native->GetPrintJob(), native->GetPageSetupFromSettings(settings)); + + // Show the dialog if needed. + GError* gError = NULL; + if (GetShowDialog()) + response = gtk_print_operation_run (native->GetPrintJob(), GTK_PRINT_OPERATION_ACTION_PRINT_DIALOG, GTK_WINDOW(gtk_widget_get_toplevel(m_parent->m_widget) ), &gError); + else + response = gtk_print_operation_run (native->GetPrintJob(), GTK_PRINT_OPERATION_ACTION_PRINT, (GtkWindow *) m_parent, &gError); + + // Does everything went well? + if (response == GTK_PRINT_OPERATION_RESULT_CANCEL) + { + return wxID_CANCEL; + } + else if (response == GTK_PRINT_OPERATION_RESULT_ERROR) + { + g_error_free (gError); + wxLogError(_("Error while printing: ") + wxString::Format(_("%s"), gError->message)); + return wxID_NO; // We use wxID_NO because there is no wxID_ERROR available + } + + // Now get the settings and save it. + GtkPrintSettings* newSettings = gtk_print_operation_get_print_settings (native->GetPrintJob()); + native->SetPrintConfig(newSettings); + data.ConvertFromNative(); + + // Same problem as a few lines before. + switch (gtk_print_settings_get_print_pages(newSettings)) + { + case GTK_PRINT_PAGES_CURRENT: + m_printDialogData.SetSelection( true ); + break; + case GTK_PRINT_PAGES_ALL: + m_printDialogData.SetAllPages( true ); + m_printDialogData.SetFromPage( 0 ); + m_printDialogData.SetToPage( 9999 ); + break; + case GTK_PRINT_PAGES_RANGES: + default: + // wxWidgets doesn't support multiple ranges, so we can only save the first one even if the user wants to print others. + // For example, the user enters "1-3;5-7" in the dialog: pages 1-3 and 5-7 will be correctly printed when the user + // will hit "OK" button. However we can only save 1-3 in the print data. + gint num_ranges = 0; + GtkPageRange* range; + range = gtk_print_settings_get_page_ranges (newSettings, &num_ranges); + m_printDialogData.SetFromPage( range[0].start ); + m_printDialogData.SetToPage( range[0].end ); + break; + } + + return wxID_OK; +} + +//---------------------------------------------------------------------------- +// wxGtkPageSetupDialog +//---------------------------------------------------------------------------- + +IMPLEMENT_CLASS(wxGtkPageSetupDialog, wxPageSetupDialogBase) + +wxGtkPageSetupDialog::wxGtkPageSetupDialog( wxWindow *parent, + wxPageSetupDialogData* data ) +{ + if (data) + m_pageDialogData = *data; + + m_parent = parent; +} + +wxGtkPageSetupDialog::~wxGtkPageSetupDialog() +{ +} + +int wxGtkPageSetupDialog::ShowModal() +{ + // Get the config. + m_pageDialogData.GetPrintData().ConvertToNative(); + wxGtkPrintNativeData *native = (wxGtkPrintNativeData*) m_pageDialogData.GetPrintData().GetNativeData(); + GtkPrintSettings* nativeData = native->GetPrintConfig(); + + // We only need the pagesetup data which are part of the settings. + GtkPageSetup* oldPageSetup = native->GetPageSetupFromSettings(nativeData); + + // If the user used a custom paper format the last time he printed, we have to restore it too. + if (m_pageDialogData.GetPrintData().GetPaperId() == wxPAPER_NONE) + { + wxSize customPaperSize = m_pageDialogData.GetPaperSize(); + if (customPaperSize.GetWidth() > 0 && customPaperSize.GetHeight() > 0) + { + wxString title = _("Custom size"); + GtkPaperSize* customSize = gtk_paper_size_new_custom ("custom", title.mb_str(), (gdouble) customPaperSize.GetWidth(), (gdouble) customPaperSize.GetHeight(), GTK_UNIT_MM); + gtk_page_setup_set_paper_size_and_default_margins (oldPageSetup, customSize); + g_object_unref(customSize); + } + } + + // Now show the dialog. + GtkPageSetup* newPageSetup = gtk_print_run_page_setup_dialog (GTK_WINDOW(m_parent->m_widget), + oldPageSetup, + nativeData); + + int ret; + if (newPageSetup != oldPageSetup) + { + native->SetPageSetupToSettings(nativeData, newPageSetup); + m_pageDialogData.GetPrintData().ConvertFromNative(); + + // Store custom paper format if any. + if (m_pageDialogData.GetPrintData().GetPaperId() == wxPAPER_NONE) + { + gdouble ml,mr,mt,mb,pw,ph; + ml = gtk_page_setup_get_left_margin (newPageSetup, GTK_UNIT_MM); + mr = gtk_page_setup_get_right_margin (newPageSetup, GTK_UNIT_MM); + mt = gtk_page_setup_get_top_margin (newPageSetup, GTK_UNIT_MM); + mb = gtk_page_setup_get_bottom_margin (newPageSetup, GTK_UNIT_MM); + + pw = gtk_page_setup_get_paper_width (newPageSetup, GTK_UNIT_MM); + ph = gtk_page_setup_get_paper_height (newPageSetup, GTK_UNIT_MM); + + m_pageDialogData.SetMarginTopLeft( wxPoint( (int)(ml+0.5), (int)(mt+0.5)) ); + m_pageDialogData.SetMarginBottomRight( wxPoint( (int)(mr+0.5), (int)(mb+0.5)) ); + + m_pageDialogData.SetPaperSize( wxSize( (int)(pw+0.5), (int)(ph+0.5) ) ); + } + + ret = wxID_OK; + } + else + { + ret = wxID_CANCEL; + } + + return ret; +} + +//---------------------------------------------------------------------------- +// wxGtkPrinter +//---------------------------------------------------------------------------- + +IMPLEMENT_CLASS(wxGtkPrinter, wxPrinterBase) + +wxGtkPrinter::wxGtkPrinter( wxPrintDialogData *data ) : + wxPrinterBase( data ) +{ + m_gpc = NULL; + + if (data) + m_printDialogData = *data; +} + +wxGtkPrinter::~wxGtkPrinter() +{ +} + +bool wxGtkPrinter::Print(wxWindow *parent, wxPrintout *printout, bool prompt ) +{ + if (!printout) + { + sm_lastError = wxPRINTER_ERROR; + return false; + } + + // Let's correct the PageInfo just in case the app gives wrong values. + int fromPage, toPage; + int minPage, maxPage; + printout->GetPageInfo(&minPage, &maxPage, &fromPage, &toPage); + m_printDialogData.SetAllPages(true); + + if (minPage < 1) minPage = 1; + if (maxPage < 1) maxPage = 9999; + if (maxPage < minPage) maxPage = minPage; + + m_printDialogData.SetMinPage(minPage); + m_printDialogData.SetMaxPage(maxPage); + if (fromPage != 0) + { + if (fromPage < minPage) fromPage = minPage; + else if (fromPage > maxPage) fromPage = maxPage; + m_printDialogData.SetFromPage(fromPage); + } + if (toPage != 0) + { + m_printDialogData.SetToPage(toPage); + if (toPage > maxPage) toPage = maxPage; + else if (toPage < minPage) toPage = minPage; + } + + if (((minPage != fromPage) && fromPage != 0) || ((maxPage != toPage) && toPage != 0)) m_printDialogData.SetAllPages(false); + + + wxPrintData printdata = GetPrintDialogData().GetPrintData(); + wxGtkPrintNativeData *native = (wxGtkPrintNativeData*) printdata.GetNativeData(); + + GtkPrintOperation *printOp = gtk_print_operation_new (); + + native->SetPrintJob( printOp ); + + printout->SetIsPreview(false); + + wxPrinterToGtkData dataToSend; + dataToSend.printer = this; + dataToSend.printout = printout; + + // These Gtk signals are catched here. + g_signal_connect (printOp, "begin-print", G_CALLBACK (gtk_begin_print_callback), &dataToSend); + g_signal_connect (printOp, "draw-page", G_CALLBACK (gtk_draw_page_print_callback), &dataToSend); + g_signal_connect (printOp, "end-print", G_CALLBACK (gtk_end_print_callback), printout); + g_signal_connect (printOp, "preview", G_CALLBACK (gtk_preview_print_callback), printout); + + m_showDialog = true; + if (!prompt) + m_showDialog = false; + + // PrintDialog returns a wxDC but we created it before so we don't need it anymore: we just delete it. + wxDC* uselessdc = PrintDialog( parent ); + delete uselessdc; + + g_object_unref (printOp); + + return (sm_lastError == wxPRINTER_NO_ERROR); +} + +void wxGtkPrinter::BeginPrint(wxPrintout *printout, GtkPrintOperation *operation, GtkPrintContext *context) +{ + wxPrintData printdata = GetPrintDialogData().GetPrintData(); + wxGtkPrintNativeData *native = (wxGtkPrintNativeData*) printdata.GetNativeData(); + + SetPrintContext(context); + native->SetPrintContext( context ); + + m_dc = new wxGtkPrintDC( printdata ); + + if (!m_dc->IsOk()) + { + if (sm_lastError != wxPRINTER_CANCELLED) + { + sm_lastError = wxPRINTER_ERROR; + wxFAIL_MSG(_("The wxGtkPrintDC cannot be used.")); + } + return; + } + wxSize ScreenPixels = wxGetDisplaySize(); + wxSize ScreenMM = wxGetDisplaySizeMM(); + + printout->SetPPIScreen( (int) ((ScreenPixels.GetWidth() * 25.4) / ScreenMM.GetWidth()), + (int) ((ScreenPixels.GetHeight() * 25.4) / ScreenMM.GetHeight()) ); + printout->SetPPIPrinter( wxGtkPrintDC::GetResolution(), + wxGtkPrintDC::GetResolution() ); + + printout->SetDC(m_dc); + + int w, h; + m_dc->GetSize(&w, &h); + printout->SetPageSizePixels((int)w, (int)h); + printout->SetPaperRectPixels(wxRect(0, 0, w, h)); + int mw, mh; + m_dc->GetSizeMM(&mw, &mh); + printout->SetPageSizeMM((int)mw, (int)mh); + printout->OnPreparePrinting(); + + // Get some parameters from the printout, if defined. + int fromPage, toPage; + int minPage, maxPage; + printout->GetPageInfo(&minPage, &maxPage, &fromPage, &toPage); + + if (maxPage == 0) + { + sm_lastError = wxPRINTER_ERROR; + wxFAIL_MSG(_("wxPrintout::GetPageInfo gives a null maxPage.")); + return; + } + + printout->OnBeginPrinting(); + + int numPages = 0; + + // If we're not previewing we need to calculate the number of pages to print. + // If we're previewing, Gtk Print will render every pages without wondering about the page ranges the user may + // have defined in the dialog. So the number of pages is the maximum available. + if (!printout->IsPreview()) + { + GtkPrintSettings * settings = gtk_print_operation_get_print_settings (operation); + switch (gtk_print_settings_get_print_pages(settings)) + { + case GTK_PRINT_PAGES_CURRENT: + numPages = 1; + break; + case GTK_PRINT_PAGES_RANGES: + {gint num_ranges = 0; + GtkPageRange* range; + int i; + range = gtk_print_settings_get_page_ranges (settings, &num_ranges); + for (i=0; i maxPage-1) range[i].end = maxPage-1; + if (range[i].start > maxPage-1) range[i].start = maxPage-1; + numPages += range[i].end - range[i].start + 1; + } + gtk_print_settings_set_page_ranges (settings, range, 1); + break;} + case GTK_PRINT_PAGES_ALL: + default: + numPages = maxPage - minPage + 1; + break; + } + } + else numPages = maxPage - minPage + 1; + + gtk_print_operation_set_n_pages(operation, numPages); +} + +void wxGtkPrinter::DrawPage(wxPrintout *printout, GtkPrintOperation *operation, GtkPrintContext *context, int page_nr) +{ + int fromPage, toPage, minPage, maxPage, startPage, endPage; + printout->GetPageInfo(&minPage, &maxPage, &fromPage, &toPage); + + int numPageToDraw = page_nr + minPage; + if (numPageToDraw < minPage) numPageToDraw = minPage; + if (numPageToDraw > maxPage) numPageToDraw = maxPage; + + GtkPrintSettings * settings = gtk_print_operation_get_print_settings (operation); + switch (gtk_print_settings_get_print_pages(settings)) + { + case GTK_PRINT_PAGES_CURRENT: + g_object_get_property((GObject*) operation, (const gchar *) "current-page", (GValue*) &startPage); + g_object_get_property((GObject*) operation, (const gchar *) "current-page", (GValue*) &endPage); + break; + case GTK_PRINT_PAGES_RANGES: + {gint num_ranges = 0; + GtkPageRange* range; + range = gtk_print_settings_get_page_ranges (settings, &num_ranges); + // We don't need to verify these values as it has already been done in wxGtkPrinter::BeginPrint. + startPage = range[0].start + 1; + endPage = range[0].end + 1; + break;} + case GTK_PRINT_PAGES_ALL: + default: + startPage = minPage; + endPage = maxPage; + break; + } + + if(numPageToDraw == startPage) + { + if (!printout->OnBeginDocument(startPage, endPage)) + { + wxLogError(_("Could not start printing.")); + sm_lastError = wxPRINTER_ERROR; + } + } + + // The app can render the page numPageToDraw. + if (printout->HasPage(numPageToDraw)) + { + m_dc->StartPage(); + printout->OnPrintPage(numPageToDraw); + m_dc->EndPage(); + } + + + if(numPageToDraw == endPage) + { + printout->OnEndDocument(); + } +} + +wxDC* wxGtkPrinter::PrintDialog( wxWindow *parent ) +{ + wxGtkPrintDialog dialog( parent, &m_printDialogData ); + int ret; + + dialog.SetPrintDC(m_dc); + + dialog.SetShowDialog(m_showDialog); + + ret = dialog.ShowModal(); + + if (ret == wxID_CANCEL) + { + sm_lastError = wxPRINTER_CANCELLED; + return NULL; + } + if (ret == wxID_NO) + { + sm_lastError = wxPRINTER_ERROR; + wxFAIL_MSG(_("The print dialog returned an error.")); + return NULL; + } + + m_printDialogData = dialog.GetPrintDialogData(); + return new wxGtkPrintDC( m_printDialogData.GetPrintData() ); +} + +bool wxGtkPrinter::Setup( wxWindow *parent ) +{ + // Obsolete, for backward compatibility. + return false; +} + +//----------------------------------------------------------------------------- +// wxGtkPrintDC +//----------------------------------------------------------------------------- + +IMPLEMENT_CLASS(wxGtkPrintDC, wxDC) + +// Define the default resolution for this DC. This resolution is just used for positioning as the cairo context is scalable. +int wxGtkPrintDC::ms_resolution = 72; + +wxGtkPrintDC::wxGtkPrintDC( const wxPrintData& data ) +{ + m_printData = data; + + wxGtkPrintNativeData *native = + (wxGtkPrintNativeData*) m_printData.GetNativeData(); + + m_gpc = native->GetPrintContext(); + + ms_resolution = (int) gtk_print_context_get_dpi_x(m_gpc); + m_context = gtk_print_context_create_pango_context( m_gpc ); + m_layout = gtk_print_context_create_pango_layout ( m_gpc ); + m_fontdesc = pango_font_description_from_string( "Sans 12" ); + + m_cairo = gtk_print_context_get_cairo_context ( m_gpc ); + + m_currentRed = 0; + m_currentBlue = 0; + m_currentGreen = 0; + + m_signX = 1; // default x-axis left to right. + m_signY = 1; // default y-axis bottom up -> top down. + + GetSize( &m_deviceOffsetX, &m_deviceOffsetY ); +} + +wxGtkPrintDC::~wxGtkPrintDC() +{ + g_object_unref(m_context); + g_object_unref(m_layout); +} + +bool wxGtkPrintDC::IsOk() const +{ + return true; +} + +void wxGtkPrintDC::ComputeScaleAndOrigin() +{ + // Called when the scale and/or origin of the context has to be changed. + m_scaleX = m_logicalScaleX * m_userScaleX; + m_scaleY = m_logicalScaleY * m_userScaleY; + + cairo_translate(m_cairo, m_deviceOriginX, m_deviceOriginY); + cairo_scale(m_cairo, m_scaleX, m_scaleY ); +} + +bool wxGtkPrintDC::DoFloodFill(wxCoord x1, wxCoord y1, const wxColour &col, int style ) +{ + // We can't access the given coord as a cairo context is scalable, ie a coord doesn't mean anything in this context. + wxFAIL_MSG(_("not implemented")); + return false; +} + +void wxGtkPrintDC::DoGradientFillConcentric(const wxRect& rect, const wxColour& initialColour, const wxColour& destColour, const wxPoint& circleCenter) +{ + wxCoord xC = circleCenter.x; + wxCoord yC = circleCenter.y; + wxCoord xR = rect.x; + wxCoord yR = rect.y; + wxCoord w = rect.width; + wxCoord h = rect.height; + + double radius = sqrt((w/2)*(w/2)+(h/2)*(h/2)); + + unsigned char redI = initialColour.Red(); + unsigned char blueI = initialColour.Blue(); + unsigned char greenI = initialColour.Green(); + unsigned char alphaI = initialColour.Alpha(); + unsigned char redD = destColour.Red(); + unsigned char blueD = destColour.Blue(); + unsigned char greenD = destColour.Green(); + unsigned char alphaD = destColour.Alpha(); + + double redIPS = (double)(redI) / 255.0; + double blueIPS = (double)(blueI) / 255.0; + double greenIPS = (double)(greenI) / 255.0; + double alphaIPS = (double)(alphaI) / 255.0; + double redDPS = (double)(redD) / 255.0; + double blueDPS = (double)(blueD) / 255.0; + double greenDPS = (double)(greenD) / 255.0; + double alphaDPS = (double)(alphaD) / 255.0; + + // Create a pattern with the gradient. + cairo_pattern_t* gradient; + gradient = cairo_pattern_create_radial (LogicalToDeviceX(xC+xR), LogicalToDeviceY(yC+yR), 0, LogicalToDeviceX(xC+xR), LogicalToDeviceY(yC+yR), radius); + cairo_pattern_add_color_stop_rgba (gradient, 0.0, redIPS, greenIPS, blueIPS, alphaIPS); + cairo_pattern_add_color_stop_rgba (gradient, 1.0, redDPS, greenDPS, blueDPS, alphaDPS); + + // Fill the rectangle with this pattern. + cairo_set_source(m_cairo, gradient); + cairo_rectangle (m_cairo, LogicalToDeviceX(xR), LogicalToDeviceY(yR), LogicalToDeviceXRel(w), LogicalToDeviceYRel(h) ); + cairo_fill(m_cairo); + + cairo_pattern_destroy(gradient); + + CalcBoundingBox(xR, yR); + CalcBoundingBox(xR+w, yR+h); +} + +void wxGtkPrintDC::DoGradientFillLinear(const wxRect& rect, const wxColour& initialColour, const wxColour& destColour, wxDirection nDirection) +{ + wxCoord x = rect.x; + wxCoord y = rect.y; + wxCoord w = rect.width; + wxCoord h = rect.height; + + unsigned char redI = initialColour.Red(); + unsigned char blueI = initialColour.Blue(); + unsigned char greenI = initialColour.Green(); + unsigned char alphaI = initialColour.Alpha(); + unsigned char redD = destColour.Red(); + unsigned char blueD = destColour.Blue(); + unsigned char greenD = destColour.Green(); + unsigned char alphaD = destColour.Alpha(); + + double redIPS = (double)(redI) / 255.0; + double blueIPS = (double)(blueI) / 255.0; + double greenIPS = (double)(greenI) / 255.0; + double alphaIPS = (double)(alphaI) / 255.0; + double redDPS = (double)(redD) / 255.0; + double blueDPS = (double)(blueD) / 255.0; + double greenDPS = (double)(greenD) / 255.0; + double alphaDPS = (double)(alphaD) / 255.0; + + // Create a pattern with the gradient. + cairo_pattern_t* gradient; + gradient = cairo_pattern_create_linear (LogicalToDeviceX(x), LogicalToDeviceY(y), LogicalToDeviceX(x+w), LogicalToDeviceY(y)); + + if (nDirection == wxWEST) + { + cairo_pattern_add_color_stop_rgba (gradient, 0.0, redDPS, greenDPS, blueDPS, alphaDPS); + cairo_pattern_add_color_stop_rgba (gradient, 1.0, redIPS, greenIPS, blueIPS, alphaIPS); + } + else { + cairo_pattern_add_color_stop_rgba (gradient, 0.0, redIPS, greenIPS, blueIPS, alphaIPS); + cairo_pattern_add_color_stop_rgba (gradient, 1.0, redDPS, greenDPS, blueDPS, alphaDPS); + } + + // Fill the rectangle with this pattern. + cairo_set_source(m_cairo, gradient); + cairo_rectangle (m_cairo, LogicalToDeviceX(x), LogicalToDeviceY(y), LogicalToDeviceXRel(w), LogicalToDeviceYRel(h) ); + cairo_fill(m_cairo); + + cairo_pattern_destroy(gradient); + + CalcBoundingBox(x, y); + CalcBoundingBox(x+w, y+h); +} + +bool wxGtkPrintDC::DoGetPixel(wxCoord x1, wxCoord y1, wxColour *col) const +{ + // We can't access the given coord as a cairo context is scalable, ie a coord doesn't mean anything in this context. + wxFAIL_MSG(_("not implemented")); + return false; +} + +void wxGtkPrintDC::DoDrawLine(wxCoord x1, wxCoord y1, wxCoord x2, wxCoord y2) +{ + if (m_pen.GetStyle() == wxTRANSPARENT) return; + + SetPen( m_pen ); + cairo_move_to ( m_cairo, LogicalToDeviceX(x1), LogicalToDeviceY(y1) ); + cairo_line_to ( m_cairo, LogicalToDeviceX(x2), LogicalToDeviceY(y2) ); + cairo_stroke ( m_cairo ); + + CalcBoundingBox( x1, y1 ); + CalcBoundingBox( x2, y2 ); +} + +void wxGtkPrintDC::DoCrossHair(wxCoord x, wxCoord y) +{ + int *w, *h; + w = new int; + h = new int; + DoGetSize(w, h); + + SetPen(m_pen); + + cairo_move_to (m_cairo, LogicalToDeviceX(x), 0); + cairo_line_to (m_cairo, LogicalToDeviceX(x), *h); + cairo_move_to (m_cairo, 0, LogicalToDeviceY(y)); + cairo_line_to (m_cairo, *w, LogicalToDeviceY(y)); + + cairo_stroke (m_cairo); + CalcBoundingBox( 0, 0 ); + CalcBoundingBox( *w, *h ); + + delete w; + delete h; +} + +void wxGtkPrintDC::DoDrawArc(wxCoord x1,wxCoord y1,wxCoord x2,wxCoord y2,wxCoord xc,wxCoord yc) +{ + double dx = x1 - xc; + double dy = y1 - yc; + double radius = sqrt((double)(dx*dx+dy*dy)); + + double alpha1, alpha2; + if (x1 == x2 && y1 == y2) + { + alpha1 = 0.0; + alpha2 = 360.0; + } + else + if (radius == 0.0) + { + alpha1 = alpha2 = 0.0; + } + else + { + alpha1 = (x1 - xc == 0) ? + (y1 - yc < 0) ? 90.0 : -90.0 : + atan2(double(y1-yc), double(x1-xc)) * RAD2DEG; + alpha2 = (x2 - xc == 0) ? + (y2 - yc < 0) ? 90.0 : -90.0 : + atan2(double(y2-yc), double(x2-xc)) * RAD2DEG; + + while (alpha1 <= 0) alpha1 += 360; + while (alpha2 <= 0) alpha2 += 360; // adjust angles to be between. + while (alpha1 > 360) alpha1 -= 360; // 0 and 360 degree. + while (alpha2 > 360) alpha2 -= 360; + } + + alpha1 *= DEG2RAD; + alpha2 *= DEG2RAD; + + cairo_arc_negative ( m_cairo, LogicalToDeviceX(xc), LogicalToDeviceY(yc), LogicalToDeviceXRel((int)radius), alpha1, alpha2); + cairo_line_to(m_cairo, LogicalToDeviceX(xc), LogicalToDeviceY(yc)); + cairo_close_path (m_cairo); + + SetBrush( m_brush ); + cairo_fill_preserve( m_cairo ); + + SetPen (m_pen); + cairo_stroke( m_cairo ); + + CalcBoundingBox (x1, y1); + CalcBoundingBox (xc, yc); + CalcBoundingBox (x2, y2); +} + +void wxGtkPrintDC::DoDrawEllipticArc(wxCoord x,wxCoord y,wxCoord w,wxCoord h,double sa,double ea) +{ + cairo_save( m_cairo ); + + cairo_translate( m_cairo, LogicalToDeviceX((wxCoord) (x + w / 2.)), LogicalToDeviceX((wxCoord) (y + h / 2.)) ); + double scale = (double)LogicalToDeviceYRel(h) / (double) LogicalToDeviceXRel(w); + cairo_scale( m_cairo, 1.0, scale ); + + cairo_arc_negative ( m_cairo, 0, 0, LogicalToDeviceXRel(w/2), -sa*DEG2RAD, -ea*DEG2RAD); + + SetPen (m_pen); + cairo_stroke_preserve( m_cairo ); + + cairo_line_to(m_cairo, 0,0); + + SetBrush( m_brush ); + cairo_fill( m_cairo ); + + cairo_restore( m_cairo ); + + CalcBoundingBox( x, y); + CalcBoundingBox( x+w, y+h ); +} + +void wxGtkPrintDC::DoDrawPoint(wxCoord x, wxCoord y) +{ + if (m_pen.GetStyle() == wxTRANSPARENT) return; + + SetPen( m_pen ); + + cairo_move_to ( m_cairo, LogicalToDeviceX(x), LogicalToDeviceY(y) ); + cairo_line_to ( m_cairo, LogicalToDeviceX(x), LogicalToDeviceY(y) ); + cairo_stroke ( m_cairo ); + + CalcBoundingBox( x, y ); +} + +void wxGtkPrintDC::DoDrawLines(int n, wxPoint points[], wxCoord xoffset, wxCoord yoffset) +{ + if (m_pen.GetStyle() == wxTRANSPARENT) return; + + if (n <= 0) return; + + SetPen (m_pen); + + int i; + for ( i =0; i width) dd = width; + if (dd > height) dd = height; + radius = dd / 2; + + wxCoord rad = (wxCoord) radius; + + cairo_new_path(m_cairo); + cairo_move_to(m_cairo,LogicalToDeviceX(x + rad),LogicalToDeviceY(y)); + cairo_curve_to(m_cairo, + LogicalToDeviceX(x + rad),LogicalToDeviceY(y), + LogicalToDeviceX(x),LogicalToDeviceY(y), + LogicalToDeviceX(x),LogicalToDeviceY(y + rad)); + cairo_line_to(m_cairo,LogicalToDeviceX(x),LogicalToDeviceY(y + height - rad)); + cairo_curve_to(m_cairo, + LogicalToDeviceX(x),LogicalToDeviceY(y + height - rad), + LogicalToDeviceX(x),LogicalToDeviceY(y + height), + LogicalToDeviceX(x + rad),LogicalToDeviceY(y + height)); + cairo_line_to(m_cairo,LogicalToDeviceX(x + width - rad),LogicalToDeviceY(y + height)); + cairo_curve_to(m_cairo, + LogicalToDeviceX(x + width - rad),LogicalToDeviceY(y + height), + LogicalToDeviceX(x + width),LogicalToDeviceY(y + height), + LogicalToDeviceX(x + width),LogicalToDeviceY(y + height - rad)); + cairo_line_to(m_cairo,LogicalToDeviceX(x + width),LogicalToDeviceY(y + rad)); + cairo_curve_to(m_cairo, + LogicalToDeviceX(x + width),LogicalToDeviceY(y + rad), + LogicalToDeviceX(x + width),LogicalToDeviceY(y), + LogicalToDeviceX(x + width - rad),LogicalToDeviceY(y)); + cairo_line_to(m_cairo,LogicalToDeviceX(x + rad),LogicalToDeviceY(y)); + cairo_close_path(m_cairo); + + SetBrush(m_brush); + cairo_fill_preserve(m_cairo); + + SetPen(m_pen); + cairo_stroke(m_cairo); + + CalcBoundingBox(x,y); + CalcBoundingBox(x+width,y+height); +} + +void wxGtkPrintDC::DoDrawEllipse(wxCoord x, wxCoord y, wxCoord width, wxCoord height) +{ + cairo_save (m_cairo); + + cairo_translate (m_cairo, LogicalToDeviceX((wxCoord) (x + width / 2.)), LogicalToDeviceY((wxCoord) (y + height / 2.))); + cairo_scale(m_cairo, 1, (double)LogicalToDeviceYRel(height)/(double)LogicalToDeviceXRel(width)); + cairo_arc ( m_cairo, 0, 0, LogicalToDeviceXRel(width/2), 0, 2 * M_PI); + + SetBrush( m_brush ); + cairo_fill_preserve( m_cairo ); + + SetPen (m_pen); + cairo_stroke( m_cairo ); + + CalcBoundingBox( x, y ); + CalcBoundingBox( x + width, y + height ); + + cairo_restore (m_cairo); +} + +#if wxUSE_SPLINES +void wxGtkPrintDC::DoDrawSpline(wxList *points) +{ + SetPen (m_pen); + + double c, d, x1, y1, x2, y2, x3, y3; + wxPoint *p, *q; + + wxList::compatibility_iterator node = points->GetFirst(); + p = (wxPoint *)node->GetData(); + x1 = p->x; + y1 = p->y; + + node = node->GetNext(); + p = (wxPoint *)node->GetData(); + c = p->x; + d = p->y; + x3 = + (double)(x1 + c) / 2; + y3 = + (double)(y1 + d) / 2; + + cairo_new_path( m_cairo ); + cairo_move_to( m_cairo, LogicalToDeviceX((wxCoord)x1), LogicalToDeviceY((wxCoord)y1) ); + cairo_line_to( m_cairo, LogicalToDeviceX((wxCoord)x3), LogicalToDeviceY((wxCoord)y3) ); + + CalcBoundingBox( (wxCoord)x1, (wxCoord)y1 ); + CalcBoundingBox( (wxCoord)x3, (wxCoord)y3 ); + + node = node->GetNext(); + while (node) + { + q = (wxPoint *)node->GetData(); + + x1 = x3; + y1 = y3; + x2 = c; + y2 = d; + c = q->x; + d = q->y; + x3 = (double)(x2 + c) / 2; + y3 = (double)(y2 + d) / 2; + + cairo_curve_to(m_cairo, + LogicalToDeviceX((wxCoord)x1), LogicalToDeviceY((wxCoord)y1), + LogicalToDeviceX((wxCoord)x2), LogicalToDeviceY((wxCoord)y2), + LogicalToDeviceX((wxCoord)x3), LogicalToDeviceY((wxCoord)y3) ); + + CalcBoundingBox( (wxCoord)x1, (wxCoord)y1 ); + CalcBoundingBox( (wxCoord)x3, (wxCoord)y3 ); + + node = node->GetNext(); + } + + cairo_line_to ( m_cairo, LogicalToDeviceX((wxCoord)c), LogicalToDeviceY((wxCoord)d) ); + + cairo_stroke( m_cairo ); +} +#endif // wxUSE_SPLINES + +bool wxGtkPrintDC::DoBlit(wxCoord xdest, wxCoord ydest, wxCoord width, wxCoord height, + wxDC *source, wxCoord xsrc, wxCoord ysrc, int rop, bool useMask, + wxCoord xsrcMask, wxCoord ysrcMask) +{ + wxCHECK_MSG( source, false, wxT("invalid source dc") ); + + // Blit into a bitmap. + wxBitmap bitmap( width, height ); + wxMemoryDC memDC; + memDC.SelectObject(bitmap); + memDC.Blit(0, 0, width, height, source, xsrc, ysrc, rop); + memDC.SelectObject(wxNullBitmap); + + // Draw bitmap. scaling and positioning is done there. + DrawBitmap( bitmap, xdest, ydest, useMask ); + + return true; +} + +void wxGtkPrintDC::DoDrawIcon( const wxIcon& icon, wxCoord x, wxCoord y ) +{ + DoDrawBitmap( icon, x, y, true ); +} + +void wxGtkPrintDC::DoDrawBitmap( const wxBitmap& bitmap, wxCoord x, wxCoord y, bool useMask ) +{ + wxCHECK_RET( bitmap.IsOk(), wxT("Invalid bitmap in wxGtkPrintDC::DoDrawBitmap")); + + cairo_surface_t* surface; + x = LogicalToDeviceX(x); + y = LogicalToDeviceY(y); + int bw = bitmap.GetWidth(); + int bh = bitmap.GetHeight(); + wxBitmap bmpSource = bitmap; // we need a non-const instance. + unsigned char* buffer = new unsigned char[bw*bh*4]; + wxUint32* data = (wxUint32*)buffer; + + wxMask *mask = NULL; + if (useMask) mask = bmpSource.GetMask(); + + // Create a surface object and copy the bitmap pixel data to it. If the image has alpha (or a mask represented as alpha) + // then we'll use a different format and iterator than if it doesn't. + if (bmpSource.HasAlpha() || mask) + { + surface = cairo_image_surface_create_for_data( + buffer, CAIRO_FORMAT_ARGB32, bw, bh, bw*4); + wxAlphaPixelData pixData(bmpSource, wxPoint(0,0), wxSize(bw, bh)); + wxCHECK_RET( pixData, wxT("Failed to gain raw access to bitmap data.")); + + wxAlphaPixelData::Iterator p(pixData); + int y, x; + for (y=0; ystart_index = 0; + a->end_index = datalen; + pango_attr_list_insert(attrs, a); + pango_layout_set_attributes(m_layout, attrs); + pango_attr_list_unref(attrs); + } + + if (m_textForegroundColour.Ok()) + { + unsigned char red = m_textForegroundColour.Red(); + unsigned char blue = m_textForegroundColour.Blue(); + unsigned char green = m_textForegroundColour.Green(); + unsigned char alpha = m_textForegroundColour.Alpha(); + + if (!(red == m_currentRed && green == m_currentGreen && blue == m_currentBlue && alpha == m_currentAlpha)) + { + double redPS = (double)(red) / 255.0; + double bluePS = (double)(blue) / 255.0; + double greenPS = (double)(green) / 255.0; + double alphaPS = (double)(alpha) / 255.0; + + cairo_set_source_rgba( m_cairo, redPS, greenPS, bluePS, alphaPS ); + + m_currentRed = red; + m_currentBlue = blue; + m_currentGreen = green; + m_currentAlpha = alpha; + } + } + + int w,h; + + if (fabs(m_scaleY - 1.0) > 0.00001) + { + // If there is a user or actually any scale applied to the device context, scale the font. + + // Scale font description. + gint oldSize = pango_font_description_get_size( m_fontdesc ); + double size = oldSize; + size = size * m_scaleY; + pango_font_description_set_size( m_fontdesc, (gint)size ); + + // Actually apply scaled font. + pango_layout_set_font_description( m_layout, m_fontdesc ); + + pango_layout_get_pixel_size( m_layout, &w, &h ); + w = LogicalToDeviceXRel(w); + h = LogicalToDeviceYRel(h); + + if ( m_backgroundMode == wxSOLID ) + { + unsigned char red = m_textBackgroundColour.Red(); + unsigned char blue = m_textBackgroundColour.Blue(); + unsigned char green = m_textBackgroundColour.Green(); + unsigned char alpha = m_textBackgroundColour.Alpha(); + + double redPS = (double)(red) / 255.0; + double bluePS = (double)(blue) / 255.0; + double greenPS = (double)(green) / 255.0; + double alphaPS = (double)(alpha) / 255.0; + + cairo_save(m_cairo); + cairo_translate(m_cairo, x, y); + cairo_set_source_rgba( m_cairo, redPS, greenPS, bluePS, alphaPS ); + cairo_rotate(m_cairo,angle*DEG2RAD); + cairo_rectangle(m_cairo, 0, 0, w, h); + cairo_fill(m_cairo); + cairo_restore(m_cairo); + } + + // Draw layout. + cairo_move_to (m_cairo, x, y); + if (fabs(angle) > 0.00001) + { + cairo_save( m_cairo ); + cairo_rotate( m_cairo, angle*DEG2RAD ); + pango_cairo_update_layout (m_cairo, m_layout); + pango_cairo_show_layout (m_cairo, m_layout); + cairo_restore( m_cairo ); + } + else + { + pango_cairo_update_layout (m_cairo, m_layout); + pango_cairo_show_layout (m_cairo, m_layout); + } + + // Reset unscaled size. + pango_font_description_set_size( m_fontdesc, oldSize ); + + // Actually apply unscaled font. + pango_layout_set_font_description( m_layout, m_fontdesc ); + } + else + { + pango_layout_get_pixel_size( m_layout, &w, &h ); + + if ( m_backgroundMode == wxSOLID ) + { + unsigned char red = m_textBackgroundColour.Red(); + unsigned char blue = m_textBackgroundColour.Blue(); + unsigned char green = m_textBackgroundColour.Green(); + unsigned char alpha = m_textBackgroundColour.Alpha(); + + double redPS = (double)(red) / 255.0; + double bluePS = (double)(blue) / 255.0; + double greenPS = (double)(green) / 255.0; + double alphaPS = (double)(alpha) / 255.0; + + cairo_save(m_cairo); + cairo_translate(m_cairo, x, y); + cairo_set_source_rgba( m_cairo, redPS, greenPS, bluePS, alphaPS ); + cairo_rotate(m_cairo,angle*DEG2RAD); + cairo_rectangle(m_cairo, 0, 0, w, h); + cairo_fill(m_cairo); + cairo_restore(m_cairo); + } + + // Draw layout. + cairo_move_to (m_cairo, x, y); + if (fabs(angle) > 0.00001) + { + cairo_save( m_cairo ); + cairo_rotate( m_cairo, angle*DEG2RAD ); + pango_cairo_update_layout (m_cairo, m_layout); + pango_cairo_show_layout (m_cairo, m_layout); + cairo_restore( m_cairo ); + } + else + { + pango_cairo_update_layout (m_cairo, m_layout); + pango_cairo_show_layout (m_cairo, m_layout); + } + } + + if (underlined) + { + // Undo underline attributes setting + pango_layout_set_attributes(m_layout, NULL); + } + + CalcBoundingBox (x,y); + CalcBoundingBox (x + w, y + h); +} + +void wxGtkPrintDC::Clear() +{ + cairo_save(m_cairo); + cairo_set_operator (m_cairo, CAIRO_OPERATOR_SOURCE); + SetBrush(m_backgroundBrush); + cairo_paint(m_cairo); + cairo_restore(m_cairo); +} + +void wxGtkPrintDC::SetFont( const wxFont& font ) +{ + m_font = font; + + if (m_font.Ok()) + { + if (m_fontdesc) + pango_font_description_free( m_fontdesc ); + + m_fontdesc = pango_font_description_copy( m_font.GetNativeFontInfo()->description ); + + pango_layout_set_font_description( m_layout, m_fontdesc ); + } +} + +void wxGtkPrintDC::SetPen( const wxPen& pen ) +{ + if (!pen.Ok()) return; + + m_pen = pen; + + double width = (double) m_pen.GetWidth(); + if (width == 0) width = 0.1; + + cairo_set_line_width( m_cairo, LogicalToDeviceXRel( (wxCoord) (1000 * width )) / 1000.0f ); + static const double dotted[] = {2.0, 5.0}; + static const double short_dashed[] = {4.0, 4.0}; + static const double long_dashed[] = {4.0, 8.0}; + static const double dotted_dashed[] = {6.0, 6.0, 2.0, 6.0}; + + switch (m_pen.GetStyle()) + { + case wxDOT: cairo_set_dash( m_cairo, dotted, 1, 0 ); break; + case wxSHORT_DASH: cairo_set_dash( m_cairo, short_dashed, 1, 0 ); break; + case wxLONG_DASH: cairo_set_dash( m_cairo, long_dashed, 1, 0 ); break; + case wxDOT_DASH: cairo_set_dash( m_cairo, dotted_dashed, 3, 0 ); break; + case wxUSER_DASH: + { + wxDash *wx_dashes; + int num = m_pen.GetDashes (&wx_dashes) - 1; + gdouble *g_dashes = g_new( gdouble, num ); + int i; + for (i = 0; i < num; ++i) + g_dashes[i] = (gdouble) wx_dashes[i]; + cairo_set_dash( m_cairo, g_dashes, num, 0); + g_free( g_dashes ); + } + break; + case wxSOLID: + case wxTRANSPARENT: + default: cairo_set_dash( m_cairo, NULL, 0, 0 ); break; + } + + switch (m_pen.GetCap()) + { + case wxCAP_PROJECTING: cairo_set_line_cap (m_cairo, CAIRO_LINE_CAP_SQUARE); break; + case wxCAP_BUTT: cairo_set_line_cap (m_cairo, CAIRO_LINE_CAP_BUTT); break; + case wxCAP_ROUND: + default: cairo_set_line_cap (m_cairo, CAIRO_LINE_CAP_ROUND); break; + } + + switch (m_pen.GetJoin()) + { + case wxJOIN_BEVEL: cairo_set_line_join (m_cairo, CAIRO_LINE_JOIN_BEVEL); break; + case wxJOIN_MITER: cairo_set_line_join (m_cairo, CAIRO_LINE_JOIN_MITER); break; + case wxJOIN_ROUND: + default: cairo_set_line_join (m_cairo, CAIRO_LINE_JOIN_ROUND); break; + } + + unsigned char red = m_pen.GetColour().Red(); + unsigned char blue = m_pen.GetColour().Blue(); + unsigned char green = m_pen.GetColour().Green(); + unsigned char alpha = m_pen.GetColour().Alpha(); + + if (!(red == m_currentRed && green == m_currentGreen && blue == m_currentBlue && alpha == m_currentAlpha)) + { + double redPS = (double)(red) / 255.0; + double bluePS = (double)(blue) / 255.0; + double greenPS = (double)(green) / 255.0; + double alphaPS = (double)(alpha) / 255.0; + + cairo_set_source_rgba( m_cairo, redPS, greenPS, bluePS, alphaPS ); + + m_currentRed = red; + m_currentBlue = blue; + m_currentGreen = green; + m_currentAlpha = alpha; + } +} + +void wxGtkPrintDC::SetBrush( const wxBrush& brush ) +{ + if (!brush.Ok()) return; + + m_brush = brush; + + // Brush colour. + unsigned char red = m_brush.GetColour().Red(); + unsigned char blue = m_brush.GetColour().Blue(); + unsigned char green = m_brush.GetColour().Green(); + unsigned char alpha = m_brush.GetColour().Alpha(); + + double redPS = (double)(red) / 255.0; + double bluePS = (double)(blue) / 255.0; + double greenPS = (double)(green) / 255.0; + double alphaPS = (double)(alpha) / 255.0; + + if (!(red == m_currentRed && green == m_currentGreen && blue == m_currentBlue && alpha == m_currentAlpha)) + { + cairo_set_source_rgba( m_cairo, redPS, greenPS, bluePS, alphaPS ); + + m_currentRed = red; + m_currentBlue = blue; + m_currentGreen = green; + m_currentAlpha = alpha; + } + + if (m_brush.IsHatch()) + { + cairo_t * cr; + cairo_surface_t *surface; + surface = cairo_surface_create_similar(cairo_get_target(m_cairo),CAIRO_CONTENT_COLOR_ALPHA,10,10); + cr = cairo_create(surface); + cairo_set_line_cap(cr, CAIRO_LINE_CAP_SQUARE); + cairo_set_line_width(cr, 1); + cairo_set_line_join(cr,CAIRO_LINE_JOIN_MITER); + + switch (m_brush.GetStyle()) + { + case wxCROSS_HATCH: + cairo_move_to(cr, 5, 0); + cairo_line_to(cr, 5, 10); + cairo_move_to(cr, 0, 5); + cairo_line_to(cr, 10, 5); + break; + case wxBDIAGONAL_HATCH: + cairo_move_to(cr, 0, 10); + cairo_line_to(cr, 10, 0); + break; + case wxFDIAGONAL_HATCH: + cairo_move_to(cr, 0, 0); + cairo_line_to(cr, 10, 10); + break; + case wxCROSSDIAG_HATCH: + cairo_move_to(cr, 0, 0); + cairo_line_to(cr, 10, 10); + cairo_move_to(cr, 10, 0); + cairo_line_to(cr, 0, 10); + break; + case wxHORIZONTAL_HATCH: + cairo_move_to(cr, 0, 5); + cairo_line_to(cr, 10, 5); + break; + case wxVERTICAL_HATCH: + cairo_move_to(cr, 5, 0); + cairo_line_to(cr, 5, 10); + break; + default: + wxFAIL_MSG(_("Couldn't get hatch style from wxBrush.")); + } + + cairo_set_source_rgba(cr, redPS, greenPS, bluePS, alphaPS); + cairo_stroke (cr); + + cairo_destroy(cr); + cairo_pattern_t * pattern = cairo_pattern_create_for_surface (surface); + cairo_surface_destroy(surface); + cairo_pattern_set_extend (pattern, CAIRO_EXTEND_REPEAT); + cairo_set_source(m_cairo, pattern); + cairo_pattern_destroy(pattern); + } +} + +void wxGtkPrintDC::SetLogicalFunction( int function ) +{ + if (function == wxCLEAR) + cairo_set_operator (m_cairo, CAIRO_OPERATOR_CLEAR); + else if (function == wxOR) + cairo_set_operator (m_cairo, CAIRO_OPERATOR_OUT); + else if (function == wxNO_OP) + cairo_set_operator (m_cairo, CAIRO_OPERATOR_DEST); + else if (function == wxAND) + cairo_set_operator (m_cairo, CAIRO_OPERATOR_ADD); + else if (function == wxSET) + cairo_set_operator (m_cairo, CAIRO_OPERATOR_SATURATE); + else if (function == wxXOR) + cairo_set_operator (m_cairo, CAIRO_OPERATOR_XOR); + else // wxCOPY or anything else. + cairo_set_operator (m_cairo, CAIRO_OPERATOR_SOURCE); +} + +void wxGtkPrintDC::SetBackground( const wxBrush& brush ) +{ + m_backgroundBrush = brush; + cairo_save(m_cairo); + cairo_set_operator (m_cairo, CAIRO_OPERATOR_DEST_OVER); + + SetBrush(m_backgroundBrush); + cairo_paint(m_cairo); + cairo_restore(m_cairo); +} + +void wxGtkPrintDC::SetBackgroundMode(int mode) +{ + if (mode == wxSOLID) m_backgroundMode = wxSOLID; + else m_backgroundMode = wxTRANSPARENT; +} + +void wxGtkPrintDC::DoSetClippingRegion(wxCoord x, wxCoord y, wxCoord width, wxCoord height) +{ + cairo_rectangle ( m_cairo, LogicalToDeviceX(x), LogicalToDeviceY(y), LogicalToDeviceXRel(width), LogicalToDeviceYRel(height)); + cairo_clip(m_cairo); +} + +void wxGtkPrintDC::DestroyClippingRegion() +{ + cairo_reset_clip(m_cairo); +} + +bool wxGtkPrintDC::StartDoc(const wxString& message) +{ + return true; +} + +void wxGtkPrintDC::EndDoc() +{ + return; +} + +void wxGtkPrintDC::StartPage() +{ + return; +} + +void wxGtkPrintDC::EndPage() +{ + return; +} + +wxCoord wxGtkPrintDC::GetCharHeight() const +{ + pango_layout_set_text( m_layout, "H", 1 ); + + int w,h; + pango_layout_get_pixel_size( m_layout, &w, &h ); + + return DeviceToLogicalYRel(h); +} + +wxCoord wxGtkPrintDC::GetCharWidth() const +{ + pango_layout_set_text( m_layout, "H", 1 ); + + int w,h; + pango_layout_get_pixel_size( m_layout, &w, &h ); + + return DeviceToLogicalXRel(w); +} + +void wxGtkPrintDC::DoGetTextExtent(const wxString& string, wxCoord *width, wxCoord *height, + wxCoord *descent, + wxCoord *externalLeading, + const wxFont *theFont ) const +{ + if ( width ) + *width = 0; + if ( height ) + *height = 0; + if ( descent ) + *descent = 0; + if ( externalLeading ) + *externalLeading = 0; + + if (string.empty()) + { + return; + } + + // Set layout's text + // FIXME-UTF8: wouldn't be needed if utf8_str() always returned a buffer +#if wxUSE_UNICODE_UTF8 + const char *dataUTF8 = string.utf8_str(); +#else + const wxCharBuffer dataUTF8 = string.utf8_str(); +#endif + + PangoFontDescription *desc = m_fontdesc; + if (theFont) desc = theFont->GetNativeFontInfo()->description; + + gint oldSize = pango_font_description_get_size( desc ); + double size = oldSize; + size = size * m_scaleY; + pango_font_description_set_size( desc, (gint)size ); + + // apply scaled font + pango_layout_set_font_description( m_layout, desc ); + + pango_layout_set_text( m_layout, dataUTF8, strlen(dataUTF8) ); + + int w, h; + pango_layout_get_pixel_size( m_layout, &w, &h ); + + if (width) + *width = (wxCoord)(w / m_scaleX); + if (height) + *height = (wxCoord)(h / m_scaleY); + if (descent) + { + PangoLayoutIter *iter = pango_layout_get_iter(m_layout); + int baseline = pango_layout_iter_get_baseline(iter); + pango_layout_iter_free(iter); + *descent = h - PANGO_PIXELS(baseline); + } + + // Reset unscaled size. + pango_font_description_set_size( desc, oldSize ); + + // Reset unscaled font. + pango_layout_set_font_description( m_layout, m_fontdesc ); +} + +void wxGtkPrintDC::DoGetSize(int* width, int* height) const +{ + if (width) + *width = (int) (gtk_print_context_get_width( m_gpc ) + 0.5); + if (height) + *height = (int) (gtk_print_context_get_height( m_gpc ) + 0.5); +} + +void wxGtkPrintDC::DoGetSizeMM(int *width, int *height) const +{ + // This function takes margins into consideration. + gdouble w = gtk_page_setup_get_page_width( gtk_print_context_get_page_setup( m_gpc ), GTK_UNIT_MM); + gdouble h = gtk_page_setup_get_page_height( gtk_print_context_get_page_setup( m_gpc ), GTK_UNIT_MM); + + if (width) + *width = (int) (w + 0.5); + if (height) + *height = (int) (h + 0.5); +} + +wxSize wxGtkPrintDC::GetPPI() const +{ + gdouble xDpi = gtk_print_context_get_dpi_x( m_gpc ); + gdouble yDpi = gtk_print_context_get_dpi_y( m_gpc ); + return wxSize((int) xDpi,(int) yDpi); +} + +void wxGtkPrintDC::SetLogicalOrigin( wxCoord x, wxCoord y ) +{ + wxDC::SetLogicalOrigin( x, y ); +} + +void wxGtkPrintDC::SetDeviceOrigin( wxCoord x, wxCoord y ) +{ + wxDC::SetDeviceOrigin( x, y ); +} + +void wxGtkPrintDC::SetPrintData(const wxPrintData& data) +{ + m_printData = data; + + if (m_printData.GetOrientation() == wxPORTRAIT) + GetSize( &m_deviceOffsetX, &m_deviceOffsetY ); + else + GetSize( &m_deviceOffsetY, &m_deviceOffsetX ); +} + +void wxGtkPrintDC::SetResolution(int ppi) +{ + // We can't change ppi of the GtkPrintContext. + ms_resolution = ppi; +} + +int wxGtkPrintDC::GetResolution() +{ + return ms_resolution; +} + +// ---------------------------------------------------------------------------- +// Print preview +// ---------------------------------------------------------------------------- + +IMPLEMENT_CLASS(wxGtkPrintPreview, wxPrintPreviewBase) + +void wxGtkPrintPreview::Init(wxPrintout * WXUNUSED(printout), + wxPrintout * WXUNUSED(printoutForPrinting)) +{ + DetermineScaling(); +} + +wxGtkPrintPreview::wxGtkPrintPreview(wxPrintout *printout, + wxPrintout *printoutForPrinting, + wxPrintDialogData *data) + : wxPrintPreviewBase(printout, printoutForPrinting, data) +{ + Init(printout, printoutForPrinting); +} + +wxGtkPrintPreview::wxGtkPrintPreview(wxPrintout *printout, + wxPrintout *printoutForPrinting, + wxPrintData *data) + : wxPrintPreviewBase(printout, printoutForPrinting, data) +{ + Init(printout, printoutForPrinting); +} + +wxGtkPrintPreview::~wxGtkPrintPreview() +{ +} + +bool wxGtkPrintPreview::Print(bool interactive) +{ + if (!m_printPrintout) + return false; + + wxPrinter printer(& m_printDialogData); + return printer.Print(m_previewFrame, m_printPrintout, interactive); +} + +void wxGtkPrintPreview::DetermineScaling() +{ + wxPaperSize paperType = m_printDialogData.GetPrintData().GetPaperId(); + + wxPrintPaperType *paper = wxThePrintPaperDatabase->FindPaperType(paperType); + if (!paper) + paper = wxThePrintPaperDatabase->FindPaperType(wxPAPER_A4); + + if (paper) + { + wxSize ScreenPixels = wxGetDisplaySize(); + wxSize ScreenMM = wxGetDisplaySizeMM(); + + m_previewPrintout->SetPPIScreen( (int) ((ScreenPixels.GetWidth() * 25.4) / ScreenMM.GetWidth()), + (int) ((ScreenPixels.GetHeight() * 25.4) / ScreenMM.GetHeight()) ); + m_previewPrintout->SetPPIPrinter(wxGtkPrintDC::GetResolution(), wxGtkPrintDC::GetResolution()); + // Get width and height in points (1/72th of an inch) + wxSize sizeDevUnits(paper->GetSizeDeviceUnits()); + + sizeDevUnits.x = (wxCoord)((float)sizeDevUnits.x * wxGtkPrintDC::GetResolution() / 72.0); + sizeDevUnits.y = (wxCoord)((float)sizeDevUnits.y * wxGtkPrintDC::GetResolution() / 72.0); + wxSize sizeTenthsMM(paper->GetSize()); + wxSize sizeMM(sizeTenthsMM.x / 10, sizeTenthsMM.y / 10); + + // If in landscape mode, we need to swap the width and height. + if ( m_printDialogData.GetPrintData().GetOrientation() == wxLANDSCAPE ) + { + m_pageWidth = sizeDevUnits.y; + m_pageHeight = sizeDevUnits.x; + m_previewPrintout->SetPageSizeMM(sizeMM.y, sizeMM.x); + } + else + { + m_pageWidth = sizeDevUnits.x; + m_pageHeight = sizeDevUnits.y; + m_previewPrintout->SetPageSizeMM(sizeMM.x, sizeMM.y); + } + m_previewPrintout->SetPageSizePixels(m_pageWidth, m_pageHeight); + m_previewPrintout->SetPaperRectPixels(wxRect(0, 0, m_pageWidth, m_pageHeight)); + + // At 100%, the page should look about page-size on the screen. + m_previewScaleX = (float)0.8 * 72.0 / (float)wxGtkPrintDC::GetResolution(); + m_previewScaleY = m_previewScaleX; + } +} + +#endif + // wxUSE_GTKPRINT -- 2.45.2