Files
wxWidgets/src/gtk/print.cpp
Vadim Zeitlin 691745ab41 Add a public wxModalDialogHook class for intercepting modal dialogs.
Extract wxModalDialogHook from wx/testing.h into its own wx/modalhook.h,
extend it to allow to be notified not only about showing modal dialogs but
also about dismissing them and document it and show its use in the dialogs
sample.

Also replace all the WX_TESTING_SHOW_MODAL_HOOK macros occurrences with
WX_HOOK_MODAL_DIALOG.

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@74037 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
2013-05-20 13:15:41 +00:00

2382 lines
82 KiB
C++

/////////////////////////////////////////////////////////////////////////////
// Name: src/gtk/print.cpp
// Author: Anthony Bretaudeau
// Purpose: GTK printing support
// Created: 2007-08-25
// RCS-ID: $Id$
// 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/dcprint.h"
#include "wx/icon.h"
#include "wx/math.h"
#include "wx/image.h"
#include "wx/module.h"
#include "wx/crt.h"
#endif
#include "wx/fontutil.h"
#include "wx/dynlib.h"
#include "wx/paper.h"
#include "wx/scopeguard.h"
#include "wx/modalhook.h"
#include <gtk/gtk.h>
#if GTK_CHECK_VERSION(2,14,0)
#include <gtk/gtkunixprint.h>
#else
#include <gtk/gtkpagesetupunixdialog.h>
#endif
#if wxUSE_GRAPHICS_CONTEXT
#include "wx/graphics.h"
#endif
#include "wx/link.h"
wxFORCE_LINK_THIS_MODULE(gtk_print)
#if wxUSE_LIBGNOMEPRINT
#include "wx/gtk/gnome/gprint.h"
#endif
#include "wx/gtk/private/object.h"
// Useful 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(wxCLASSINFO(wxGnomePrintModule));
#endif
}
bool OnInit();
void OnExit() {}
private:
DECLARE_DYNAMIC_CLASS(wxGtkPrintModule)
};
bool wxGtkPrintModule::OnInit()
{
#ifndef __WXGTK3__
if (gtk_check_version(2,10,0) == NULL)
#endif
{
wxPrintFactory::SetPrintFactory( new wxGtkPrintFactory );
}
return true;
}
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 * WXUNUSED(parent),
wxPrintData * WXUNUSED(data))
{
return NULL;
}
wxDCImpl* wxGtkPrintFactory::CreatePrinterDCImpl( wxPrinterDC *owner, const wxPrintData& data )
{
return new wxGtkPrinterDCImpl( owner, 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 objects to GTK printing callback functions.
struct wxPrinterToGtkData
{
wxGtkPrinter * printer;
wxPrintout * printout;
};
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 * WXUNUSED(operation),
GtkPrintContext * WXUNUSED(context),
gpointer user_data)
{
wxPrintout *printout = (wxPrintout *) user_data;
printout->OnEndPrinting();
}
}
//----------------------------------------------------------------------------
// wxGtkPrintNativeData
//----------------------------------------------------------------------------
IMPLEMENT_CLASS(wxGtkPrintNativeData, wxPrintNativeDataBase)
wxGtkPrintNativeData::wxGtkPrintNativeData()
{
m_config = gtk_print_settings_new();
m_job = NULL;
m_context = NULL;
}
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;
int resolution = gtk_print_settings_get_resolution(m_config);
if ( resolution > 0 )
{
// if resolution is explicitly set, use it
data.SetQuality(resolution);
}
else // use more vague "quality"
{
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);
data.SetPrinterName(gtk_print_settings_get_printer(m_config));
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;
}
gtk_print_settings_set_printer(m_config, data.GetPrinterName().utf8_str());
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()
{
WX_HOOK_MODAL_DIALOG();
// 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);
}
GtkPrintOperation * const printOp = native->GetPrintJob();
// If the settings are OK, we restore it.
if (settings != NULL)
gtk_print_operation_set_print_settings (printOp, settings);
gtk_print_operation_set_default_page_setup (printOp, native->GetPageSetupFromSettings(settings));
// Show the dialog if needed.
GError* gError = NULL;
GtkPrintOperationResult response = gtk_print_operation_run
(
printOp,
GetShowDialog()
? GTK_PRINT_OPERATION_ACTION_PRINT_DIALOG
: GTK_PRINT_OPERATION_ACTION_PRINT,
m_parent
? GTK_WINDOW(gtk_widget_get_toplevel(m_parent->m_widget))
: NULL,
&gError
);
// Does everything went well?
if (response == GTK_PRINT_OPERATION_RESULT_CANCEL)
{
return wxID_CANCEL;
}
else if (response == GTK_PRINT_OPERATION_RESULT_ERROR)
{
wxLogError(_("Error while printing: ") + wxString(gError ? gError->message : "???"));
g_error_free (gError);
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(printOp);
native->SetPrintConfig(newSettings);
data.ConvertFromNative();
// Set PrintDialogData variables
m_printDialogData.SetPrintData(data);
m_printDialogData.SetCollate(data.GetCollate());
m_printDialogData.SetNoCopies(data.GetNoCopies());
m_printDialogData.SetPrintToFile(data.GetPrinterName() == "Print to File");
// 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_RANGES:
{// 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);
if (num_ranges >= 1)
{
m_printDialogData.SetFromPage( range[0].start );
m_printDialogData.SetToPage( range[0].end );
}
else {
m_printDialogData.SetAllPages( true );
m_printDialogData.SetFromPage( 0 );
m_printDialogData.SetToPage( 9999 );
}
break;}
case GTK_PRINT_PAGES_ALL:
default:
m_printDialogData.SetAllPages( true );
m_printDialogData.SetFromPage( 0 );
m_printDialogData.SetToPage( 9999 );
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()
{
WX_HOOK_MODAL_DIALOG();
// 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);
}
}
// Set selected printer
gtk_print_settings_set(nativeData, "format-for-printer",
gtk_print_settings_get_printer(nativeData));
// Create custom dialog
wxString title(GetTitle());
if ( title.empty() )
title = _("Page Setup");
GtkWidget *
dlg = gtk_page_setup_unix_dialog_new(title.utf8_str(),
m_parent
? GTK_WINDOW(m_parent->m_widget)
: NULL);
gtk_page_setup_unix_dialog_set_print_settings(
GTK_PAGE_SETUP_UNIX_DIALOG(dlg), nativeData);
gtk_page_setup_unix_dialog_set_page_setup(
GTK_PAGE_SETUP_UNIX_DIALOG(dlg), oldPageSetup);
int result = gtk_dialog_run(GTK_DIALOG(dlg));
gtk_widget_hide(dlg);
switch ( result )
{
case GTK_RESPONSE_OK:
case GTK_RESPONSE_APPLY:
{
// Store Selected Printer Name
gtk_print_settings_set_printer
(
nativeData,
gtk_print_settings_get(nativeData, "format-for-printer")
);
wxGtkObject<GtkPageSetup>
newPageSetup(gtk_page_setup_unix_dialog_get_page_setup(
GTK_PAGE_SETUP_UNIX_DIALOG(dlg)));
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)));
}
result = wxID_OK;
}
break;
default:
case GTK_RESPONSE_CANCEL:
result = wxID_CANCEL;
break;
}
gtk_widget_destroy(dlg);
return result;
}
//----------------------------------------------------------------------------
// 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();
wxGtkObject<GtkPrintOperation> printOp(gtk_print_operation_new());
native->SetPrintJob(printOp);
wxON_BLOCK_EXIT_OBJ1(*native, wxGtkPrintNativeData::SetPrintJob,
static_cast<GtkPrintOperation*>(NULL));
wxPrinterToGtkData dataToSend;
dataToSend.printer = this;
dataToSend.printout = printout;
// These Gtk signals are caught 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);
// This is used to setup the DC and
// show the dialog if desired
wxGtkPrintDialog dialog( parent, &m_printDialogData );
dialog.SetPrintDC(m_dc);
dialog.SetShowDialog(prompt);
// doesn't necessarily show
int ret = dialog.ShowModal();
if (ret == wxID_CANCEL)
{
sm_lastError = wxPRINTER_CANCELLED;
}
if (ret == wxID_NO)
{
sm_lastError = wxPRINTER_ERROR;
wxFAIL_MSG(_("The print dialog returned an error."));
}
return (sm_lastError == wxPRINTER_NO_ERROR);
}
void wxGtkPrinter::BeginPrint(wxPrintout *printout, GtkPrintOperation *operation, GtkPrintContext *context)
{
wxPrintData printdata = GetPrintDialogData().GetPrintData();
wxGtkPrintNativeData *native = (wxGtkPrintNativeData*) printdata.GetNativeData();
// We need to update printdata with the new data from the dialog and we
// have to do this here because this method needs this new data and we
// cannot update it earlier
native->SetPrintConfig(gtk_print_operation_get_print_settings(operation));
printdata.ConvertFromNative();
SetPrintContext(context);
native->SetPrintContext( context );
wxPrinterDC *printDC = new wxPrinterDC( printdata );
m_dc = printDC;
if (!m_dc->IsOk())
{
if (sm_lastError != wxPRINTER_CANCELLED)
{
sm_lastError = wxPRINTER_ERROR;
wxFAIL_MSG(_("The wxGtkPrinterDC cannot be used."));
}
return;
}
printout->SetPPIScreen(wxGetDisplayPPI());
printout->SetPPIPrinter( printDC->GetResolution(),
printDC->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<num_ranges; i++)
{
if (range[i].end < range[i].start) range[i].end = range[i].start;
if (range[i].start < minPage-1) range[i].start = minPage-1;
if (range[i].end > 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 * WXUNUSED(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.
if (num_ranges >= 1)
{
startPage = range[0].start + 1;
endPage = range[0].end + 1;
}
else {
startPage = minPage;
endPage = maxPage;
}
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 );
dialog.SetPrintDC(m_dc);
dialog.SetShowDialog(true);
int 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 wxPrinterDC( m_printDialogData.GetPrintData() );
}
bool wxGtkPrinter::Setup( wxWindow * WXUNUSED(parent) )
{
// Obsolete, for backward compatibility.
return false;
}
//-----------------------------------------------------------------------------
// wxGtkPrinterDC
//-----------------------------------------------------------------------------
#define wxCAIRO_SCALE 1
#if wxCAIRO_SCALE
#define XLOG2DEV(x) LogicalToDeviceX(x)
#define XLOG2DEVREL(x) LogicalToDeviceXRel(x)
#define YLOG2DEV(x) LogicalToDeviceY(x)
#define YLOG2DEVREL(x) LogicalToDeviceYRel(x)
#else
#define XLOG2DEV(x) ((double)(LogicalToDeviceX(x)) * m_DEV2PS)
#define XLOG2DEVREL(x) ((double)(LogicalToDeviceXRel(x)) * m_DEV2PS)
#define YLOG2DEV(x) ((double)(LogicalToDeviceY(x)) * m_DEV2PS)
#define YLOG2DEVREL(x) ((double)(LogicalToDeviceYRel(x)) * m_DEV2PS)
#endif
IMPLEMENT_ABSTRACT_CLASS(wxGtkPrinterDCImpl, wxDCImpl)
wxGtkPrinterDCImpl::wxGtkPrinterDCImpl(wxPrinterDC *owner, const wxPrintData& data)
: wxDCImpl( owner )
{
m_printData = data;
wxGtkPrintNativeData *native =
(wxGtkPrintNativeData*) m_printData.GetNativeData();
m_gpc = native->GetPrintContext();
// Match print quality to resolution (high = 1200dpi)
m_resolution = m_printData.GetQuality(); // (int) gtk_print_context_get_dpi_x( m_gpc );
if (m_resolution < 0)
m_resolution = (1 << (m_resolution+4)) *150;
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 );
#if wxCAIRO_SCALE
m_PS2DEV = 1.0;
m_DEV2PS = 1.0;
#else
m_PS2DEV = (double)m_resolution / 72.0;
m_DEV2PS = 72.0 / (double)m_resolution;
#endif
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.
}
wxGtkPrinterDCImpl::~wxGtkPrinterDCImpl()
{
g_object_unref(m_context);
g_object_unref(m_layout);
}
bool wxGtkPrinterDCImpl::IsOk() const
{
return m_gpc != NULL;
}
void* wxGtkPrinterDCImpl::GetCairoContext() const
{
return (void*) cairo_reference( m_cairo );
}
void* wxGtkPrinterDCImpl::GetHandle() const
{
return GetCairoContext();
}
bool wxGtkPrinterDCImpl::DoFloodFill(wxCoord WXUNUSED(x1),
wxCoord WXUNUSED(y1),
const wxColour& WXUNUSED(col),
wxFloodFillStyle WXUNUSED(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 wxGtkPrinterDCImpl::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;
const double r2 = (w/2)*(w/2)+(h/2)*(h/2);
double radius = sqrt(r2);
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 (XLOG2DEV(xC+xR), YLOG2DEV(yC+yR), 0, XLOG2DEV(xC+xR), YLOG2DEV(yC+yR), radius * m_DEV2PS );
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, XLOG2DEV(xR), YLOG2DEV(yR), XLOG2DEVREL(w), YLOG2DEVREL(h) );
cairo_fill(m_cairo);
cairo_pattern_destroy(gradient);
CalcBoundingBox(xR, yR);
CalcBoundingBox(xR+w, yR+h);
}
void wxGtkPrinterDCImpl::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 (XLOG2DEV(x), YLOG2DEV(y), XLOG2DEV(x+w), YLOG2DEV(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, XLOG2DEV(x), YLOG2DEV(y), XLOG2DEVREL(w), YLOG2DEVREL(h) );
cairo_fill(m_cairo);
cairo_pattern_destroy(gradient);
CalcBoundingBox(x, y);
CalcBoundingBox(x+w, y+h);
}
bool wxGtkPrinterDCImpl::DoGetPixel(wxCoord WXUNUSED(x1),
wxCoord WXUNUSED(y1),
wxColour * WXUNUSED(col)) const
{
wxFAIL_MSG(_("not implemented"));
return false;
}
void wxGtkPrinterDCImpl::DoDrawLine(wxCoord x1, wxCoord y1, wxCoord x2, wxCoord y2)
{
if ( m_pen.IsTransparent() )
return;
SetPen( m_pen );
cairo_move_to ( m_cairo, XLOG2DEV(x1), YLOG2DEV(y1) );
cairo_line_to ( m_cairo, XLOG2DEV(x2), YLOG2DEV(y2) );
cairo_stroke ( m_cairo );
CalcBoundingBox( x1, y1 );
CalcBoundingBox( x2, y2 );
}
void wxGtkPrinterDCImpl::DoCrossHair(wxCoord x, wxCoord y)
{
int w, h;
DoGetSize(&w, &h);
SetPen(m_pen);
cairo_move_to (m_cairo, XLOG2DEV(x), 0);
cairo_line_to (m_cairo, XLOG2DEV(x), YLOG2DEVREL(h));
cairo_move_to (m_cairo, 0, YLOG2DEV(y));
cairo_line_to (m_cairo, XLOG2DEVREL(w), YLOG2DEV(y));
cairo_stroke (m_cairo);
CalcBoundingBox( 0, 0 );
CalcBoundingBox( w, h );
}
void wxGtkPrinterDCImpl::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_new_path(m_cairo);
cairo_arc_negative ( m_cairo, XLOG2DEV(xc), YLOG2DEV(yc), XLOG2DEVREL((int)radius), alpha1, alpha2);
cairo_line_to(m_cairo, XLOG2DEV(xc), YLOG2DEV(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 wxGtkPrinterDCImpl::DoDrawEllipticArc(wxCoord x,wxCoord y,wxCoord w,wxCoord h,double sa,double ea)
{
cairo_save( m_cairo );
cairo_new_path(m_cairo);
cairo_translate( m_cairo, XLOG2DEV((wxCoord) (x + w / 2.)), XLOG2DEV((wxCoord) (y + h / 2.)) );
double scale = (double)YLOG2DEVREL(h) / (double) XLOG2DEVREL(w);
cairo_scale( m_cairo, 1.0, scale );
cairo_arc_negative ( m_cairo, 0, 0, XLOG2DEVREL(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 wxGtkPrinterDCImpl::DoDrawPoint(wxCoord x, wxCoord y)
{
if ( m_pen.IsTransparent() )
return;
SetPen( m_pen );
cairo_move_to ( m_cairo, XLOG2DEV(x), YLOG2DEV(y) );
cairo_line_to ( m_cairo, XLOG2DEV(x), YLOG2DEV(y) );
cairo_stroke ( m_cairo );
CalcBoundingBox( x, y );
}
void wxGtkPrinterDCImpl::DoDrawLines(int n, const wxPoint points[], wxCoord xoffset, wxCoord yoffset)
{
if ( m_pen.IsTransparent() )
return;
if (n <= 0) return;
SetPen (m_pen);
int i;
for ( i =0; i<n ; i++ )
CalcBoundingBox( points[i].x+xoffset, points[i].y+yoffset);
cairo_move_to ( m_cairo, XLOG2DEV(points[0].x+xoffset), YLOG2DEV(points[0].y+yoffset) );
for (i = 1; i < n; i++)
cairo_line_to ( m_cairo, XLOG2DEV(points[i].x+xoffset), YLOG2DEV(points[i].y+yoffset) );
cairo_stroke ( m_cairo);
}
void wxGtkPrinterDCImpl::DoDrawPolygon(int n, const wxPoint points[],
wxCoord xoffset, wxCoord yoffset,
wxPolygonFillMode fillStyle)
{
if (n==0) return;
cairo_save(m_cairo);
if (fillStyle == wxWINDING_RULE)
cairo_set_fill_rule( m_cairo, CAIRO_FILL_RULE_WINDING);
else
cairo_set_fill_rule( m_cairo, CAIRO_FILL_RULE_EVEN_ODD);
int x = points[0].x + xoffset;
int y = points[0].y + yoffset;
cairo_new_path(m_cairo);
cairo_move_to( m_cairo, XLOG2DEV(x), YLOG2DEV(y) );
int i;
for (i = 1; i < n; i++)
{
int xx = points[i].x + xoffset;
int yy = points[i].y + yoffset;
cairo_line_to( m_cairo, XLOG2DEV(xx), YLOG2DEV(yy) );
}
cairo_close_path(m_cairo);
SetBrush( m_brush );
cairo_fill_preserve( m_cairo );
SetPen (m_pen);
cairo_stroke( m_cairo );
CalcBoundingBox( x, y );
cairo_restore(m_cairo);
}
void wxGtkPrinterDCImpl::DoDrawPolyPolygon(int n, const int count[], const wxPoint points[],
wxCoord xoffset, wxCoord yoffset,
wxPolygonFillMode fillStyle)
{
wxDCImpl::DoDrawPolyPolygon( n, count, points, xoffset, yoffset, fillStyle );
}
void wxGtkPrinterDCImpl::DoDrawRectangle(wxCoord x, wxCoord y, wxCoord width, wxCoord height)
{
width--;
height--;
cairo_new_path(m_cairo);
cairo_rectangle ( m_cairo, XLOG2DEV(x), YLOG2DEV(y), XLOG2DEVREL(width), YLOG2DEVREL(height));
SetBrush( m_brush );
cairo_fill_preserve( m_cairo );
SetPen (m_pen);
cairo_stroke( m_cairo );
CalcBoundingBox( x, y );
CalcBoundingBox( x + width, y + height );
}
void wxGtkPrinterDCImpl::DoDrawRoundedRectangle(wxCoord x, wxCoord y, wxCoord width, wxCoord height, double radius)
{
width--;
height--;
if (radius < 0.0) radius = - radius * ((width < height) ? width : height);
wxCoord dd = 2 * (wxCoord) radius;
if (dd > 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,XLOG2DEV(x + rad),YLOG2DEV(y));
cairo_curve_to(m_cairo,
XLOG2DEV(x + rad),YLOG2DEV(y),
XLOG2DEV(x),YLOG2DEV(y),
XLOG2DEV(x),YLOG2DEV(y + rad));
cairo_line_to(m_cairo,XLOG2DEV(x),YLOG2DEV(y + height - rad));
cairo_curve_to(m_cairo,
XLOG2DEV(x),YLOG2DEV(y + height - rad),
XLOG2DEV(x),YLOG2DEV(y + height),
XLOG2DEV(x + rad),YLOG2DEV(y + height));
cairo_line_to(m_cairo,XLOG2DEV(x + width - rad),YLOG2DEV(y + height));
cairo_curve_to(m_cairo,
XLOG2DEV(x + width - rad),YLOG2DEV(y + height),
XLOG2DEV(x + width),YLOG2DEV(y + height),
XLOG2DEV(x + width),YLOG2DEV(y + height - rad));
cairo_line_to(m_cairo,XLOG2DEV(x + width),YLOG2DEV(y + rad));
cairo_curve_to(m_cairo,
XLOG2DEV(x + width),YLOG2DEV(y + rad),
XLOG2DEV(x + width),YLOG2DEV(y),
XLOG2DEV(x + width - rad),YLOG2DEV(y));
cairo_line_to(m_cairo,XLOG2DEV(x + rad),YLOG2DEV(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 wxGtkPrinterDCImpl::DoDrawEllipse(wxCoord x, wxCoord y, wxCoord width, wxCoord height)
{
width--;
height--;
cairo_save (m_cairo);
cairo_new_path(m_cairo);
cairo_translate (m_cairo, XLOG2DEV((wxCoord) (x + width / 2.)), YLOG2DEV((wxCoord) (y + height / 2.)));
cairo_scale(m_cairo, 1, (double)YLOG2DEVREL(height)/(double)XLOG2DEVREL(width));
cairo_arc ( m_cairo, 0, 0, XLOG2DEVREL(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 wxGtkPrinterDCImpl::DoDrawSpline(const wxPointList *points)
{
SetPen (m_pen);
double c, d, x1, y1, x2, y2, x3, y3;
wxPoint *p, *q;
wxPointList::compatibility_iterator node = points->GetFirst();
p = node->GetData();
x1 = p->x;
y1 = p->y;
node = node->GetNext();
p = 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, XLOG2DEV((wxCoord)x1), YLOG2DEV((wxCoord)y1) );
cairo_line_to( m_cairo, XLOG2DEV((wxCoord)x3), YLOG2DEV((wxCoord)y3) );
CalcBoundingBox( (wxCoord)x1, (wxCoord)y1 );
CalcBoundingBox( (wxCoord)x3, (wxCoord)y3 );
node = node->GetNext();
while (node)
{
q = 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,
XLOG2DEV((wxCoord)x1), YLOG2DEV((wxCoord)y1),
XLOG2DEV((wxCoord)x2), YLOG2DEV((wxCoord)y2),
XLOG2DEV((wxCoord)x3), YLOG2DEV((wxCoord)y3) );
CalcBoundingBox( (wxCoord)x1, (wxCoord)y1 );
CalcBoundingBox( (wxCoord)x3, (wxCoord)y3 );
node = node->GetNext();
}
cairo_line_to ( m_cairo, XLOG2DEV((wxCoord)c), YLOG2DEV((wxCoord)d) );
cairo_stroke( m_cairo );
}
#endif // wxUSE_SPLINES
bool wxGtkPrinterDCImpl::DoBlit(wxCoord xdest, wxCoord ydest,
wxCoord width, wxCoord height,
wxDC *source, wxCoord xsrc, wxCoord ysrc,
wxRasterOperationMode rop, bool useMask,
wxCoord WXUNUSED_UNLESS_DEBUG(xsrcMask),
wxCoord WXUNUSED_UNLESS_DEBUG(ysrcMask))
{
wxASSERT_MSG( xsrcMask == wxDefaultCoord && ysrcMask == wxDefaultCoord,
wxT("mask coordinates are not supported") );
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.
GetOwner()->DrawBitmap( bitmap, xdest, ydest, useMask );
return true;
}
void wxGtkPrinterDCImpl::DoDrawIcon( const wxIcon& icon, wxCoord x, wxCoord y )
{
DoDrawBitmap( icon, x, y, true );
}
void wxGtkPrinterDCImpl::DoDrawBitmap( const wxBitmap& bitmap, wxCoord x, wxCoord y, bool useMask )
{
wxCHECK_RET( bitmap.IsOk(), wxT("Invalid bitmap in wxGtkPrinterDCImpl::DoDrawBitmap"));
x = wxCoord(XLOG2DEV(x));
y = wxCoord(YLOG2DEV(y));
int bw = bitmap.GetWidth();
int bh = bitmap.GetHeight();
#ifndef __WXGTK3__
wxBitmap bmpSource = bitmap; // we need a non-const instance.
if (!useMask && !bitmap.HasPixbuf() && bitmap.GetMask())
bmpSource.SetMask(NULL);
#endif
cairo_save(m_cairo);
// Prepare to draw the image.
cairo_translate(m_cairo, x, y);
// Scale the image
wxDouble scaleX = (wxDouble) XLOG2DEVREL(bw) / (wxDouble) bw;
wxDouble scaleY = (wxDouble) YLOG2DEVREL(bh) / (wxDouble) bh;
cairo_scale(m_cairo, scaleX, scaleY);
#ifdef __WXGTK3__
bitmap.Draw(m_cairo, 0, 0, useMask, &m_textForegroundColour, &m_textBackgroundColour);
#else
gdk_cairo_set_source_pixbuf(m_cairo, bmpSource.GetPixbuf(), 0, 0);
cairo_pattern_set_filter(cairo_get_source(m_cairo), CAIRO_FILTER_NEAREST);
// Use the original size here since the context is scaled already.
cairo_rectangle(m_cairo, 0, 0, bw, bh);
// Fill the rectangle using the pattern.
cairo_fill(m_cairo);
#endif
CalcBoundingBox(0,0);
CalcBoundingBox(bw,bh);
cairo_restore(m_cairo);
}
void wxGtkPrinterDCImpl::DoDrawText(const wxString& text, wxCoord x, wxCoord y )
{
DoDrawRotatedText( text, x, y, 0.0 );
}
void wxGtkPrinterDCImpl::DoDrawRotatedText(const wxString& text, wxCoord x, wxCoord y, double angle)
{
double xx = XLOG2DEV(x);
double yy = YLOG2DEV(y);
angle = -angle;
const wxScopedCharBuffer data = text.utf8_str();
pango_layout_set_text(m_layout, data, data.length());
const bool setAttrs = m_font.GTKSetPangoAttrs(m_layout);
if (m_textForegroundColour.IsOk())
{
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;
}
}
// Draw layout.
cairo_move_to (m_cairo, xx, yy);
cairo_save( m_cairo );
if (fabs(angle) > 0.00001)
cairo_rotate( m_cairo, angle*DEG2RAD );
cairo_scale(m_cairo, m_scaleX, m_scaleY);
int w,h;
pango_layout_get_pixel_size( m_layout, &w, &h );
if ( m_backgroundMode == wxBRUSHSTYLE_SOLID )
{
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_set_source_rgba( m_cairo, redPS, greenPS, bluePS, alphaPS );
cairo_rectangle(m_cairo, 0, 0, w, h); // still in cairo units
cairo_fill(m_cairo);
cairo_restore(m_cairo);
}
pango_cairo_update_layout (m_cairo, m_layout);
pango_cairo_show_layout (m_cairo, m_layout);
cairo_restore( m_cairo );
if (setAttrs)
{
// Undo underline attributes setting
pango_layout_set_attributes(m_layout, NULL);
}
// Back to device units:
CalcBoundingBox (x, y);
CalcBoundingBox (x + w, y + h);
}
void wxGtkPrinterDCImpl::Clear()
{
// Clear does nothing for printing, but keep the code
// for later reuse
/*
cairo_save(m_cairo);
cairo_set_operator (m_cairo, CAIRO_OPERATOR_SOURCE);
SetBrush(m_backgroundBrush);
cairo_paint(m_cairo);
cairo_restore(m_cairo);
*/
}
void wxGtkPrinterDCImpl::SetFont( const wxFont& font )
{
m_font = font;
if (m_font.IsOk())
{
if (m_fontdesc)
pango_font_description_free( m_fontdesc );
m_fontdesc = pango_font_description_copy( m_font.GetNativeFontInfo()->description );
float size = pango_font_description_get_size( m_fontdesc );
size = size * GetFontPointSizeAdjustment(72.0);
pango_font_description_set_size( m_fontdesc, (gint)size );
pango_layout_set_font_description( m_layout, m_fontdesc );
}
}
void wxGtkPrinterDCImpl::SetPen( const wxPen& pen )
{
if (!pen.IsOk()) return;
m_pen = pen;
double width;
if (m_pen.GetWidth() <= 0)
width = 0.1;
else
width = (double) m_pen.GetWidth();
cairo_set_line_width( m_cairo, width * m_DEV2PS * m_scaleX );
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 wxPENSTYLE_DOT: cairo_set_dash( m_cairo, dotted, 2, 0 ); break;
case wxPENSTYLE_SHORT_DASH: cairo_set_dash( m_cairo, short_dashed, 2, 0 ); break;
case wxPENSTYLE_LONG_DASH: cairo_set_dash( m_cairo, long_dashed, 2, 0 ); break;
case wxPENSTYLE_DOT_DASH: cairo_set_dash( m_cairo, dotted_dashed, 4, 0 ); break;
case wxPENSTYLE_USER_DASH:
{
wxDash *wx_dashes;
int num = m_pen.GetDashes (&wx_dashes);
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 wxPENSTYLE_SOLID:
case wxPENSTYLE_TRANSPARENT:
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 wxGtkPrinterDCImpl::SetBrush( const wxBrush& brush )
{
if (!brush.IsOk()) return;
m_brush = brush;
if (m_brush.GetStyle() == wxBRUSHSTYLE_TRANSPARENT)
{
cairo_set_source_rgba( m_cairo, 0, 0, 0, 0 );
m_currentRed = 0;
m_currentBlue = 0;
m_currentGreen = 0;
m_currentAlpha = 0;
return;
}
// 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 wxBRUSHSTYLE_CROSS_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 wxBRUSHSTYLE_BDIAGONAL_HATCH:
cairo_move_to(cr, 0, 10);
cairo_line_to(cr, 10, 0);
break;
case wxBRUSHSTYLE_FDIAGONAL_HATCH:
cairo_move_to(cr, 0, 0);
cairo_line_to(cr, 10, 10);
break;
case wxBRUSHSTYLE_CROSSDIAG_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 wxBRUSHSTYLE_HORIZONTAL_HATCH:
cairo_move_to(cr, 0, 5);
cairo_line_to(cr, 10, 5);
break;
case wxBRUSHSTYLE_VERTICAL_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 wxGtkPrinterDCImpl::SetLogicalFunction( wxRasterOperationMode 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 wxGtkPrinterDCImpl::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 wxGtkPrinterDCImpl::SetBackgroundMode(int mode)
{
if (mode == wxBRUSHSTYLE_SOLID)
m_backgroundMode = wxBRUSHSTYLE_SOLID;
else
m_backgroundMode = wxBRUSHSTYLE_TRANSPARENT;
}
void wxGtkPrinterDCImpl::DoSetClippingRegion(wxCoord x, wxCoord y, wxCoord width, wxCoord height)
{
cairo_rectangle ( m_cairo, XLOG2DEV(x), YLOG2DEV(y), XLOG2DEVREL(width), YLOG2DEVREL(height));
cairo_clip(m_cairo);
wxDCImpl::DoSetClippingRegion(x, y, width, height);
}
void wxGtkPrinterDCImpl::DestroyClippingRegion()
{
cairo_reset_clip(m_cairo);
}
bool wxGtkPrinterDCImpl::StartDoc(const wxString& WXUNUSED(message))
{
return true;
}
void wxGtkPrinterDCImpl::EndDoc()
{
return;
}
void wxGtkPrinterDCImpl::StartPage()
{
// Notice that we may change the Cairo transformation matrix only here and
// not before (e.g. in wxGtkPrinterDCImpl ctor as we used to do) in order
// to not affect _gtk_print_context_rotate_according_to_orientation() which
// is used in GTK+ itself and wouldn't work correctly if we applied these
// transformations before it is called.
// By default the origin of the Cairo context is in the upper left
// corner of the printable area. We need to translate it so that it
// is in the upper left corner of the paper (without margins)
GtkPageSetup *setup = gtk_print_context_get_page_setup( m_gpc );
gdouble ml, mt;
ml = gtk_page_setup_get_left_margin (setup, GTK_UNIT_POINTS);
mt = gtk_page_setup_get_top_margin (setup, GTK_UNIT_POINTS);
cairo_translate(m_cairo, -ml, -mt);
#if wxCAIRO_SCALE
cairo_scale( m_cairo, 72.0 / (double)m_resolution, 72.0 / (double)m_resolution );
#endif
}
void wxGtkPrinterDCImpl::EndPage()
{
return;
}
wxCoord wxGtkPrinterDCImpl::GetCharHeight() const
{
pango_layout_set_text( m_layout, "H", 1 );
int w,h;
pango_layout_get_pixel_size( m_layout, &w, &h );
return wxRound( h * m_PS2DEV );
}
wxCoord wxGtkPrinterDCImpl::GetCharWidth() const
{
pango_layout_set_text( m_layout, "H", 1 );
int w,h;
pango_layout_get_pixel_size( m_layout, &w, &h );
return wxRound( w * m_PS2DEV );
}
void wxGtkPrinterDCImpl::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;
}
cairo_save( m_cairo );
cairo_scale(m_cairo, m_scaleX, m_scaleY);
// Set layout's text
const wxScopedCharBuffer dataUTF8 = string.utf8_str();
gint oldSize=0;
if ( theFont )
{
// scale the font and apply it
PangoFontDescription *desc = theFont->GetNativeFontInfo()->description;
oldSize = pango_font_description_get_size(desc);
const float size = oldSize * GetFontPointSizeAdjustment(72.0);
pango_font_description_set_size(desc, (gint)size);
pango_layout_set_font_description(m_layout, desc);
}
pango_layout_set_text( m_layout, dataUTF8, strlen(dataUTF8) );
int h;
pango_layout_get_pixel_size( m_layout, width, &h );
if ( height )
*height = h;
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);
}
if ( theFont )
{
// restore font and reset font's size back
pango_layout_set_font_description(m_layout, m_fontdesc);
PangoFontDescription *desc = theFont->GetNativeFontInfo()->description;
pango_font_description_set_size(desc, oldSize);
}
cairo_restore( m_cairo );
}
void wxGtkPrinterDCImpl::DoGetSize(int* width, int* height) const
{
GtkPageSetup *setup = gtk_print_context_get_page_setup( m_gpc );
if (width)
*width = wxRound( (double)gtk_page_setup_get_paper_width( setup, GTK_UNIT_POINTS ) * (double)m_resolution / 72.0 );
if (height)
*height = wxRound( (double)gtk_page_setup_get_paper_height( setup, GTK_UNIT_POINTS ) * (double)m_resolution / 72.0 );
}
void wxGtkPrinterDCImpl::DoGetSizeMM(int *width, int *height) const
{
GtkPageSetup *setup = gtk_print_context_get_page_setup( m_gpc );
if (width)
*width = wxRound( gtk_page_setup_get_paper_width( setup, GTK_UNIT_MM ) );
if (height)
*height = wxRound( gtk_page_setup_get_paper_height( setup, GTK_UNIT_MM ) );
}
wxSize wxGtkPrinterDCImpl::GetPPI() const
{
return wxSize( (int)m_resolution, (int)m_resolution );
}
void wxGtkPrinterDCImpl::SetPrintData(const wxPrintData& data)
{
m_printData = data;
}
// overridden for wxPrinterDC Impl
wxRect wxGtkPrinterDCImpl::GetPaperRect() const
{
// Does GtkPrint support printer margins?
int w = 0;
int h = 0;
DoGetSize( &w, &h );
return wxRect( 0,0,w,h );
}
int wxGtkPrinterDCImpl::GetResolution() const
{
return m_resolution;
}
// ----------------------------------------------------------------------------
// Print preview
// ----------------------------------------------------------------------------
IMPLEMENT_CLASS(wxGtkPrintPreview, wxPrintPreviewBase)
void wxGtkPrintPreview::Init(wxPrintout * WXUNUSED(printout),
wxPrintout * WXUNUSED(printoutForPrinting),
wxPrintData *data)
{
// convert wxPrintQuality to resolution (input pointer can be NULL)
wxPrintQuality quality = data ? data->GetQuality() : wxPRINT_QUALITY_MEDIUM;
switch ( quality )
{
case wxPRINT_QUALITY_HIGH:
m_resolution = 1200;
break;
case wxPRINT_QUALITY_LOW:
m_resolution = 300;
break;
case wxPRINT_QUALITY_DRAFT:
m_resolution = 150;
break;
default:
if ( quality > 0 )
{
// positive values directly indicate print resolution
m_resolution = quality;
break;
}
wxFAIL_MSG( "unknown print quality" );
// fall through
case wxPRINT_QUALITY_MEDIUM:
m_resolution = 600;
break;
}
DetermineScaling();
}
wxGtkPrintPreview::wxGtkPrintPreview(wxPrintout *printout,
wxPrintout *printoutForPrinting,
wxPrintDialogData *data)
: wxPrintPreviewBase(printout, printoutForPrinting, data)
{
Init(printout, printoutForPrinting, data ? &data->GetPrintData() : NULL);
}
wxGtkPrintPreview::wxGtkPrintPreview(wxPrintout *printout,
wxPrintout *printoutForPrinting,
wxPrintData *data)
: wxPrintPreviewBase(printout, printoutForPrinting, data)
{
Init(printout, printoutForPrinting, data);
}
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)
{
const wxSize screenPPI = wxGetDisplayPPI();
int logPPIScreenX = screenPPI.GetWidth();
int logPPIScreenY = screenPPI.GetHeight();
int logPPIPrinterX = m_resolution;
int logPPIPrinterY = m_resolution;
m_previewPrintout->SetPPIScreen( logPPIScreenX, logPPIScreenY );
m_previewPrintout->SetPPIPrinter( logPPIPrinterX, logPPIPrinterY );
// Get width and height in points (1/72th of an inch)
wxSize sizeDevUnits(paper->GetSizeDeviceUnits());
sizeDevUnits.x = wxRound((double)sizeDevUnits.x * (double)m_resolution / 72.0);
sizeDevUnits.y = wxRound((double)sizeDevUnits.y * (double)m_resolution / 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(logPPIScreenX) / logPPIPrinterX;
m_previewScaleY = float(logPPIScreenY) / logPPIPrinterY;
}
}
#endif
// wxUSE_GTKPRINT