Browse Source
Eeschema: Add Cairo printing to the Eeschema print engine. The current print engine (using wxDC draw engine) has frequently issues with each new wxWidgets version. Cairo printing engine, used for Pcbnew and Gerbview has less issues. On Eeschema, the cairo print is enabled only if the advanced config has the option "EnableEeschemaPrintCairo = 1"
newinvert
Eeschema: Add Cairo printing to the Eeschema print engine. The current print engine (using wxDC draw engine) has frequently issues with each new wxWidgets version. Cairo printing engine, used for Pcbnew and Gerbview has less issues. On Eeschema, the cairo print is enabled only if the advanced config has the option "EnableEeschemaPrintCairo = 1"
newinvert
12 changed files with 489 additions and 229 deletions
-
6common/advanced_config.cpp
-
1common/render_settings.cpp
-
9eeschema/CMakeLists.txt
-
220eeschema/printing/dialog_print_using_printer.cpp
-
0eeschema/printing/dialog_print_using_printer_base.cpp
-
0eeschema/printing/dialog_print_using_printer_base.fbp
-
0eeschema/printing/dialog_print_using_printer_base.h
-
375eeschema/printing/sch_printout.cpp
-
60eeschema/printing/sch_printout.h
-
28eeschema/sch_painter.cpp
-
4include/advanced_config.h
-
15include/render_settings.h
@ -0,0 +1,375 @@ |
|||
/*
|
|||
* This program source code file is part of KiCad, a free EDA CAD application. |
|||
* |
|||
* Copyright (C) 2023 Jean-Pierre Charras, jp.charras at wanadoo.fr |
|||
* Copyright (C) 2023 KiCad Developers, see AUTHORS.txt for contributors. |
|||
* |
|||
* This program is free software: you can redistribute it and/or modify it |
|||
* under the terms of the GNU General Public License as published by the |
|||
* Free Software Foundation, either version 3 of the License, or (at your |
|||
* option) any later version. |
|||
* |
|||
* This program is distributed in the hope that it will be useful, but |
|||
* WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
|||
* General Public License for more details. |
|||
* |
|||
* You should have received a copy of the GNU General Public License along |
|||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||
*/ |
|||
|
|||
#include "sch_printout.h"
|
|||
#include <sch_edit_frame.h>
|
|||
#include <math/vector2wx.h>
|
|||
#include <pgm_base.h>
|
|||
#include <settings/color_settings.h>
|
|||
#include <settings/settings_manager.h>
|
|||
#include <sch_painter.h>
|
|||
|
|||
#include <view/view.h>
|
|||
#include <gal/gal_print.h>
|
|||
#include <gal/graphics_abstraction_layer.h>
|
|||
#include <gal/painter.h>
|
|||
#include <zoom_defines.h>
|
|||
|
|||
#include <advanced_config.h>
|
|||
|
|||
void SCH_PRINTOUT::GetPageInfo( int* minPage, int* maxPage, int* selPageFrom, int* selPageTo ) |
|||
{ |
|||
*minPage = *selPageFrom = 1; |
|||
*maxPage = *selPageTo = m_parent->Schematic().Root().CountSheets(); |
|||
} |
|||
|
|||
|
|||
bool SCH_PRINTOUT::HasPage( int pageNum ) |
|||
{ |
|||
return m_parent->Schematic().Root().CountSheets() >= pageNum; |
|||
} |
|||
|
|||
|
|||
bool SCH_PRINTOUT::OnBeginDocument( int startPage, int endPage ) |
|||
{ |
|||
if( !wxPrintout::OnBeginDocument( startPage, endPage ) ) |
|||
return false; |
|||
|
|||
return true; |
|||
} |
|||
|
|||
|
|||
bool SCH_PRINTOUT::OnPrintPage( int page ) |
|||
{ |
|||
SCH_SHEET_LIST sheetList = m_parent->Schematic().GetSheets(); |
|||
|
|||
wxCHECK_MSG( page >= 1 && page <= (int)sheetList.size(), false, |
|||
wxT( "Cannot print invalid page number." ) ); |
|||
|
|||
wxCHECK_MSG( sheetList[ page - 1].LastScreen() != nullptr, false, |
|||
wxT( "Cannot print page with NULL screen." ) ); |
|||
|
|||
wxString msg; |
|||
msg.Printf( _( "Print page %d" ), page ); |
|||
m_parent->SetMsgPanel( msg, wxEmptyString ); |
|||
|
|||
SCH_SCREEN* screen = m_parent->GetScreen(); |
|||
SCH_SHEET_PATH oldsheetpath = m_parent->GetCurrentSheet(); |
|||
m_parent->SetCurrentSheet( sheetList[ page - 1 ] ); |
|||
m_parent->GetCurrentSheet().UpdateAllScreenReferences(); |
|||
m_parent->SetSheetNumberAndCount(); |
|||
m_parent->RecomputeIntersheetRefs(); |
|||
screen = m_parent->GetCurrentSheet().LastScreen(); |
|||
PrintPage( screen ); |
|||
m_parent->SetCurrentSheet( oldsheetpath ); |
|||
m_parent->GetCurrentSheet().UpdateAllScreenReferences(); |
|||
m_parent->SetSheetNumberAndCount(); |
|||
|
|||
return true; |
|||
} |
|||
|
|||
|
|||
int SCH_PRINTOUT::milsToIU( int aMils ) |
|||
{ |
|||
return KiROUND( aMils * schIUScale.IU_PER_MILS ); |
|||
} |
|||
|
|||
/*
|
|||
* This is the real print function: print the active screen |
|||
*/ |
|||
void SCH_PRINTOUT::PrintPage( SCH_SCREEN* aScreen ) |
|||
{ |
|||
if( !ADVANCED_CFG::GetCfg().m_EnableEeschemaPrintCairo ) |
|||
{ |
|||
// Version using print to a wxDC
|
|||
// Warning:
|
|||
// When printing many pages, changes in the current wxDC will affect all next printings
|
|||
// because all prints are using the same wxPrinterDC after creation
|
|||
// So be careful and reinit parameters, especially when using offsets.
|
|||
|
|||
VECTOR2I tmp_startvisu; |
|||
wxSize pageSizeIU; // Page size in internal units
|
|||
VECTOR2I old_org; |
|||
wxRect fitRect; |
|||
wxDC* dc = GetDC(); |
|||
|
|||
wxBusyCursor dummy; |
|||
|
|||
// Save current offsets and clip box.
|
|||
tmp_startvisu = aScreen->m_StartVisu; |
|||
old_org = aScreen->m_DrawOrg; |
|||
|
|||
SETTINGS_MANAGER& mgr = Pgm().GetSettingsManager(); |
|||
EESCHEMA_SETTINGS* cfg = m_parent->eeconfig(); |
|||
COLOR_SETTINGS* theme = mgr.GetColorSettings( cfg->m_Printing.color_theme ); |
|||
|
|||
// Change scale factor and offset to print the whole page.
|
|||
bool printDrawingSheet = cfg->m_Printing.title_block; |
|||
|
|||
pageSizeIU = ToWxSize( aScreen->GetPageSettings().GetSizeIU( schIUScale.IU_PER_MILS ) ); |
|||
FitThisSizeToPaper( pageSizeIU ); |
|||
|
|||
fitRect = GetLogicalPaperRect(); |
|||
|
|||
// When is the actual paper size does not match the schematic page size, the drawing will
|
|||
// not be centered on X or Y axis. Give a draw offset to center the schematic page on the
|
|||
// paper draw area.
|
|||
int xoffset = ( fitRect.width - pageSizeIU.x ) / 2; |
|||
int yoffset = ( fitRect.height - pageSizeIU.y ) / 2; |
|||
|
|||
// Using a wxAffineMatrix2D has a big advantage: it handles different pages orientations
|
|||
//(PORTRAIT/LANDSCAPE), but the affine matrix is not always supported
|
|||
if( dc->CanUseTransformMatrix() ) |
|||
{ |
|||
wxAffineMatrix2D matrix; // starts from a unity matrix (the current wxDC default)
|
|||
|
|||
// Check for portrait/landscape mismatch:
|
|||
if( ( fitRect.width > fitRect.height ) != ( pageSizeIU.x > pageSizeIU.y ) ) |
|||
{ |
|||
// Rotate the coordinates, and keep the draw coordinates inside the page
|
|||
matrix.Rotate( M_PI_2 ); |
|||
matrix.Translate( 0, -pageSizeIU.y ); |
|||
|
|||
// Recalculate the offsets and page sizes according to the page rotation
|
|||
std::swap( pageSizeIU.x, pageSizeIU.y ); |
|||
FitThisSizeToPaper( pageSizeIU ); |
|||
fitRect = GetLogicalPaperRect(); |
|||
|
|||
xoffset = ( fitRect.width - pageSizeIU.x ) / 2; |
|||
yoffset = ( fitRect.height - pageSizeIU.y ) / 2; |
|||
|
|||
// All the coordinates will be rotated 90 deg when printing,
|
|||
// so the X,Y offset vector must be rotated -90 deg before printing
|
|||
std::swap( xoffset, yoffset ); |
|||
std::swap( fitRect.width, fitRect.height ); |
|||
yoffset = -yoffset; |
|||
} |
|||
|
|||
matrix.Translate( xoffset, yoffset ); |
|||
dc->SetTransformMatrix( matrix ); |
|||
|
|||
fitRect.x -= xoffset; |
|||
fitRect.y -= yoffset; |
|||
} |
|||
else |
|||
{ |
|||
SetLogicalOrigin( 0, 0 ); // Reset all offset settings made previously.
|
|||
// When printing previous pages (all prints are using the same wxDC)
|
|||
OffsetLogicalOrigin( xoffset, yoffset ); |
|||
} |
|||
|
|||
dc->SetLogicalFunction( wxCOPY ); |
|||
GRResetPenAndBrush( dc ); |
|||
|
|||
COLOR4D savedBgColor = m_parent->GetDrawBgColor(); |
|||
COLOR4D bgColor = m_parent->GetColorSettings()->GetColor( LAYER_SCHEMATIC_BACKGROUND ); |
|||
|
|||
if( cfg->m_Printing.background ) |
|||
{ |
|||
if( cfg->m_Printing.use_theme && theme ) |
|||
bgColor = theme->GetColor( LAYER_SCHEMATIC_BACKGROUND ); |
|||
} |
|||
else |
|||
{ |
|||
bgColor = COLOR4D::WHITE; |
|||
} |
|||
|
|||
m_parent->SetDrawBgColor( bgColor ); |
|||
|
|||
GRSFilledRect( dc, fitRect.GetX(), fitRect.GetY(), fitRect.GetRight(), fitRect.GetBottom(), 0, |
|||
bgColor, bgColor ); |
|||
|
|||
if( cfg->m_Printing.monochrome ) |
|||
GRForceBlackPen( true ); |
|||
|
|||
KIGFX::SCH_RENDER_SETTINGS renderSettings( *m_parent->GetRenderSettings() ); |
|||
renderSettings.SetPrintDC( dc ); |
|||
|
|||
if( cfg->m_Printing.use_theme && theme ) |
|||
renderSettings.LoadColors( theme ); |
|||
|
|||
renderSettings.SetBackgroundColor( bgColor ); |
|||
|
|||
// The drawing-sheet-item print code is shared between PCBNew and Eeschema, so it's easier
|
|||
// if they just use the PCB layer.
|
|||
renderSettings.SetLayerColor( LAYER_DRAWINGSHEET, |
|||
renderSettings.GetLayerColor( LAYER_SCHEMATIC_DRAWINGSHEET ) ); |
|||
|
|||
renderSettings.SetDefaultFont( cfg->m_Appearance.default_font ); |
|||
|
|||
if( printDrawingSheet ) |
|||
{ |
|||
m_parent->PrintDrawingSheet( &renderSettings, aScreen, aScreen->Schematic()->GetProperties(), |
|||
schIUScale.IU_PER_MILS, aScreen->GetFileName(), wxEmptyString ); |
|||
} |
|||
|
|||
renderSettings.SetIsPrinting( true ); |
|||
|
|||
aScreen->Print( &renderSettings ); |
|||
|
|||
m_parent->SetDrawBgColor( savedBgColor ); |
|||
|
|||
GRForceBlackPen( false ); |
|||
|
|||
aScreen->m_StartVisu = tmp_startvisu; |
|||
aScreen->m_DrawOrg = old_org; |
|||
} |
|||
else |
|||
{ |
|||
wxDC* dc = GetDC(); |
|||
m_view = m_parent->GetCanvas()->GetView(); |
|||
KIGFX::GAL_DISPLAY_OPTIONS options; |
|||
std::unique_ptr<KIGFX::GAL_PRINT> galPrint = KIGFX::GAL_PRINT::Create( options, dc ); |
|||
KIGFX::GAL* gal = galPrint->GetGAL(); |
|||
KIGFX::PRINT_CONTEXT* printCtx = galPrint->GetPrintCtx(); |
|||
std::unique_ptr<KIGFX::SCH_PAINTER> painter = std::make_unique<KIGFX::SCH_PAINTER>( gal ); |
|||
std::unique_ptr<KIGFX::VIEW> view( m_view->DataReference() ); |
|||
|
|||
painter->SetSchematic( &m_parent->Schematic() ); |
|||
|
|||
SETTINGS_MANAGER& mgr = Pgm().GetSettingsManager(); |
|||
EESCHEMA_SETTINGS* cfg = m_parent->eeconfig(); |
|||
COLOR_SETTINGS* theme = mgr.GetColorSettings( cfg->m_Printing.color_theme ); |
|||
|
|||
// Target paper size
|
|||
wxRect pageSizePx = GetLogicalPageRect(); |
|||
const VECTOR2D pageSizeIn( (double) pageSizePx.width / dc->GetPPI().x, |
|||
(double) pageSizePx.height / dc->GetPPI().y ); |
|||
const VECTOR2D pageSizeIU( milsToIU( pageSizeIn.x * 1000 ), milsToIU( pageSizeIn.y * 1000 ) ); |
|||
|
|||
galPrint->SetSheetSize( pageSizeIn ); |
|||
|
|||
view->SetGAL( gal ); |
|||
view->SetPainter( painter.get() ); |
|||
view->SetScaleLimits( ZOOM_MAX_LIMIT_EESCHEMA, ZOOM_MIN_LIMIT_EESCHEMA ); |
|||
view->SetScale( 1.0 ); |
|||
gal->SetWorldUnitLength( SCH_WORLD_UNIT ); |
|||
|
|||
// Init the SCH_RENDER_SETTINGS used by the painter used to print schematic
|
|||
KIGFX::SCH_RENDER_SETTINGS* dstSettings = painter->GetSettings(); |
|||
|
|||
dstSettings->m_ShowPinsElectricalType = false; |
|||
|
|||
// Set the color scheme
|
|||
dstSettings->LoadColors( m_parent->GetColorSettings( false ) ); |
|||
|
|||
if( cfg->m_Printing.use_theme && theme ) |
|||
dstSettings->LoadColors( theme ); |
|||
|
|||
bool printDrawingSheet = cfg->m_Printing.title_block; |
|||
|
|||
COLOR4D bgColor = m_parent->GetColorSettings()->GetColor( LAYER_SCHEMATIC_BACKGROUND ); |
|||
|
|||
if( cfg->m_Printing.background ) |
|||
{ |
|||
if( cfg->m_Printing.use_theme && theme ) |
|||
bgColor = theme->GetColor( LAYER_SCHEMATIC_BACKGROUND ); |
|||
} |
|||
else |
|||
{ |
|||
bgColor = COLOR4D::WHITE; |
|||
} |
|||
|
|||
dstSettings->SetBackgroundColor( bgColor ); |
|||
|
|||
// The drawing-sheet-item print code is shared between PCBNew and Eeschema, so it's easier
|
|||
// if they just use the PCB layer.
|
|||
dstSettings->SetLayerColor( LAYER_DRAWINGSHEET, |
|||
dstSettings->GetLayerColor( LAYER_SCHEMATIC_DRAWINGSHEET ) ); |
|||
|
|||
dstSettings->SetDefaultFont( cfg->m_Appearance.default_font ); |
|||
|
|||
if( cfg->m_Printing.monochrome ) |
|||
{ |
|||
for( int i = 0; i < LAYER_ID_COUNT; ++i ) |
|||
dstSettings->SetLayerColor( i, COLOR4D::BLACK ); |
|||
|
|||
// In B&W mode, draw the background only in white, because any other color
|
|||
// will be replaced by a black background
|
|||
dstSettings->SetBackgroundColor( COLOR4D::WHITE ); |
|||
dstSettings->m_OverrideItemColors = true; |
|||
|
|||
// Disable print some backgrounds
|
|||
dstSettings->SetPrintBlackAndWhite( true ); |
|||
} |
|||
else // color enabled
|
|||
{ |
|||
for( int i = 0; i < LAYER_ID_COUNT; ++i ) |
|||
{ |
|||
// Cairo does not support translucent colors on PostScript surfaces
|
|||
// see 'Features support by the PostScript surface' on
|
|||
// https://www.cairographics.org/documentation/using_the_postscript_surface/
|
|||
dstSettings->SetLayerColor( i, dstSettings->GetLayerColor( i ).WithAlpha( 1.0 ) ); |
|||
} |
|||
} |
|||
|
|||
dstSettings->SetIsPrinting( true ); |
|||
|
|||
VECTOR2I sheetSizeIU = aScreen->GetPageSettings().GetSizeIU( schIUScale.IU_PER_MILS ); |
|||
BOX2I drawingAreaBBox = BOX2I( VECTOR2I( 0, 0 ), VECTOR2I( sheetSizeIU ) ); |
|||
|
|||
// When printing the board without worksheet items, move board center to the
|
|||
// drawing area center.
|
|||
//if( !m_settings.PrintBorderAndTitleBlock() )
|
|||
// drawingAreaBBox = getBoundingBox();
|
|||
|
|||
// Enable all layers and use KIGFX::TARGET_NONCACHED to force update drawings
|
|||
// for printing with current GAL instance
|
|||
for( int i = 0; i < KIGFX::VIEW::VIEW_MAX_LAYERS; ++i ) |
|||
{ |
|||
view->SetLayerVisible( i, true ); |
|||
view->SetLayerTarget( i, KIGFX::TARGET_NONCACHED ); |
|||
} |
|||
|
|||
view->SetLayerVisible( LAYER_DRAWINGSHEET, printDrawingSheet ); |
|||
|
|||
#if 0
|
|||
// Fit to page (drawingAreaBBox)
|
|||
if( m_settings.m_scale <= 0.0 ) |
|||
{ |
|||
if( drawingAreaBBox.GetWidth() == 0 || drawingAreaBBox.GetHeight() == 0 ) |
|||
{ |
|||
// Nothing to print (empty board and no worksheet)
|
|||
m_settings.m_scale = 1.0; |
|||
} |
|||
else |
|||
{ |
|||
double scaleX = (double) pageSizeIU.x / drawingAreaBBox.GetWidth(); |
|||
double scaleY = (double) pageSizeIU.y / drawingAreaBBox.GetHeight(); |
|||
m_settings.m_scale = std::min( scaleX, scaleY ); |
|||
} |
|||
} |
|||
#endif
|
|||
//setupGal( gal );
|
|||
galPrint->SetNativePaperSize( pageSizeIn, printCtx->HasNativeLandscapeRotation() ); |
|||
gal->SetLookAtPoint( drawingAreaBBox.Centre() ); |
|||
gal->SetZoomFactor( 1.0);//m_settings.m_scale );
|
|||
gal->SetClearColor( dstSettings->GetBackgroundColor() ); |
|||
gal->ClearScreen(); |
|||
|
|||
// Needed to use the same order for printing as for screen redraw
|
|||
view->UseDrawPriority( true ); |
|||
|
|||
{ |
|||
KIGFX::GAL_DRAWING_CONTEXT ctx( gal ); |
|||
view->Redraw(); |
|||
} |
|||
} |
|||
} |
@ -0,0 +1,60 @@ |
|||
/* |
|||
* This program source code file is part of KiCad, a free EDA CAD application. |
|||
* |
|||
* Copyright (C) 2023 Jean-Pierre Charras, jp.charras at wanadoo.fr |
|||
* Copyright (C) 2023 KiCad Developers, see AUTHORS.txt for contributors. |
|||
* |
|||
* This program is free software: you can redistribute it and/or modify it |
|||
* under the terms of the GNU General Public License as published by the |
|||
* Free Software Foundation, either version 3 of the License, or (at your |
|||
* option) any later version. |
|||
* |
|||
* This program is distributed in the hope that it will be useful, but |
|||
* WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
|||
* General Public License for more details. |
|||
* |
|||
* You should have received a copy of the GNU General Public License along |
|||
* with this program. If not, see <http://www.gnu.org/licenses/>. |
|||
*/ |
|||
|
|||
#pragma once |
|||
|
|||
#include <wx/print.h> |
|||
|
|||
class SCH_EDIT_FRAME; |
|||
class SCH_SCREEN; |
|||
|
|||
namespace KIGFX |
|||
{ |
|||
class GAL; |
|||
class VIEW; |
|||
class PAINTER; |
|||
}; |
|||
|
|||
/** |
|||
* Custom print out for printing schematics. |
|||
*/ |
|||
class SCH_PRINTOUT : public wxPrintout |
|||
{ |
|||
public: |
|||
SCH_PRINTOUT( SCH_EDIT_FRAME* aParent, const wxString& aTitle ) : |
|||
wxPrintout( aTitle ) |
|||
{ |
|||
//wxASSERT( aParent != nullptr ); |
|||
m_parent = aParent; |
|||
} |
|||
|
|||
bool OnPrintPage( int page ) override; |
|||
bool HasPage( int page ) override; |
|||
bool OnBeginDocument( int startPage, int endPage ) override; |
|||
void GetPageInfo( int* minPage, int* maxPage, int* selPageFrom, int* selPageTo ) override; |
|||
void PrintPage( SCH_SCREEN* aScreen ); |
|||
|
|||
private: |
|||
SCH_EDIT_FRAME* m_parent; |
|||
///< Source VIEW object (note that actual printing only refers to this object) |
|||
const KIGFX::VIEW* m_view; |
|||
|
|||
int milsToIU( int aMils ); |
|||
}; |
Write
Preview
Loading…
Cancel
Save
Reference in new issue