/* * This program source code file is part of KiCad, a free EDA CAD application. * * Copyright (C) 2010-2016 Jean-Pierre Charras, jean-pierre.charras at wanadoo.fr * Copyright (C) 1992-2016 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 2 * 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, you may find one here: * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html * or you may search the http://www.gnu.org website for the version 2 license, * or you may write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ // Set this to 1 if you want to test PostScript printing under MSW. //#define wxTEST_POSTSCRIPT_IN_MSW 1 #include #include #include #include #include #include #include #include #include #include #include #define PEN_WIDTH_MAX_VALUE ( KiROUND( 5 * IU_PER_MM ) ) #define PEN_WIDTH_MIN_VALUE ( KiROUND( 0.005 * IU_PER_MM ) ) extern int g_DrawDefaultLineThickness; // Local variables static double s_ScaleList[] = { 0, 0.5, 0.7, 0.999, 1.0, 1.4, 2.0, 3.0, 4.0 }; // Define min et max reasonable values for print scale #define MIN_SCALE 0.01 #define MAX_SCALE 100.0 // static print data and page setup data, to remember settings during the session static wxPrintData* s_PrintData; static wxPageSetupDialogData* s_pageSetupData = (wxPageSetupDialogData*) NULL; static PRINT_PARAMETERS s_Parameters; /** * Dialog to print schematic. Class derived from DIALOG_PRINT_USING_PRINTER_BASE * created by wxFormBuilder */ class DIALOG_PRINT_USING_PRINTER : public DIALOG_PRINT_USING_PRINTER_BASE { public: DIALOG_PRINT_USING_PRINTER( PCB_EDIT_FRAME* parent ); bool IsMirrored() { return m_Print_Mirror->IsChecked(); } bool ExcludeEdges() { return m_Exclude_Edges_Pcb->IsChecked(); } bool PrintUsingSinglePage() { return m_PagesOption->GetSelection(); } int SetLayerSetFromListSelection(); private: PCB_EDIT_FRAME* m_parent; wxConfigBase* m_config; // the list of existing board layers in wxCheckListBox, with the // board layers id: std::pair m_boxSelectLayer[LAYER_ID_COUNT]; static bool m_ExcludeEdgeLayer; void OnCloseWindow( wxCloseEvent& event ); void OnPageSetup( wxCommandEvent& event ); void OnPrintPreview( wxCommandEvent& event ); void OnPrintButtonClick( wxCommandEvent& event ); void OnScaleSelectionClick( wxCommandEvent& event ); void OnButtonCancelClick( wxCommandEvent& event ) { Close(); } void OnInitDlg( wxInitDialogEvent& event ) { // Call the default wxDialog handler of a wxInitDialogEvent TransferDataToWindow(); // Now all widgets have the size fixed, call FinishDialogSettings FinishDialogSettings(); } void SetPrintParameters( ); void SetPenWidth(); void initValues( ); }; bool DIALOG_PRINT_USING_PRINTER::m_ExcludeEdgeLayer; void PCB_EDIT_FRAME::ToPrinter( wxCommandEvent& event ) { const PAGE_INFO& pageInfo = GetPageSettings(); if( s_PrintData == NULL ) // First print { s_PrintData = new wxPrintData(); if( !s_PrintData->Ok() ) { DisplayError( this, _( "Error Init Printer info" ) ); } s_PrintData->SetQuality( wxPRINT_QUALITY_HIGH ); // Default resolution = HIGH; } if( s_pageSetupData == NULL ) s_pageSetupData = new wxPageSetupDialogData( *s_PrintData ); s_pageSetupData->SetPaperId( pageInfo.GetPaperId() ); s_pageSetupData->GetPrintData().SetOrientation( pageInfo.GetWxOrientation() ); if( pageInfo.IsCustom() ) { if( pageInfo.IsPortrait() ) s_pageSetupData->SetPaperSize( wxSize( Mils2mm( pageInfo.GetWidthMils() ), Mils2mm( pageInfo.GetHeightMils() ) ) ); else s_pageSetupData->SetPaperSize( wxSize( Mils2mm( pageInfo.GetHeightMils() ), Mils2mm( pageInfo.GetWidthMils() ) ) ); } *s_PrintData = s_pageSetupData->GetPrintData(); DIALOG_PRINT_USING_PRINTER dlg( this ); dlg.ShowModal(); } DIALOG_PRINT_USING_PRINTER::DIALOG_PRINT_USING_PRINTER( PCB_EDIT_FRAME* parent ) : DIALOG_PRINT_USING_PRINTER_BASE( parent ) { m_parent = parent; m_config = Kiface().KifaceSettings(); memset( m_boxSelectLayer, 0, sizeof( m_boxSelectLayer ) ); initValues( ); #ifdef __WXMAC__ /* Problems with modal on wx-2.9 - Anyway preview is standard for OSX */ m_buttonPreview->Hide(); #endif } void DIALOG_PRINT_USING_PRINTER::initValues( ) { wxString msg; BOARD* board = m_parent->GetBoard(); s_Parameters.m_PageSetupData = s_pageSetupData; // Create layer list. LSEQ seq = board->GetEnabledLayers().UIOrder(); for( ; seq; ++seq ) { LAYER_ID layer = *seq; int checkIndex; if( IsCopperLayer( layer ) ) { checkIndex = m_CopperLayersList->Append( board->GetLayerName( layer ) ); m_boxSelectLayer[layer] = std::make_pair( m_CopperLayersList, checkIndex ); } else { checkIndex = m_TechnicalLayersList->Append( board->GetLayerName( layer ) ); m_boxSelectLayer[layer] = std::make_pair( m_TechnicalLayersList, checkIndex ); } if( m_config ) { wxString layerKey; layerKey.Printf( OPTKEY_LAYERBASE, layer ); bool option; if( m_config->Read( layerKey, &option ) ) m_boxSelectLayer[layer].first->Check( checkIndex, option ); } } // Option for excluding contents of "Edges Pcb" layer m_Exclude_Edges_Pcb->Show( true ); // Read the scale adjust option int scale_idx = 4; // default selected scale = ScaleList[4] = 1.000 if( m_config ) { m_config->Read( OPTKEY_PRINT_X_FINESCALE_ADJ, &s_Parameters.m_XScaleAdjust ); m_config->Read( OPTKEY_PRINT_Y_FINESCALE_ADJ, &s_Parameters.m_YScaleAdjust ); m_config->Read( OPTKEY_PRINT_SCALE, &scale_idx ); m_config->Read( OPTKEY_PRINT_PAGE_FRAME, &s_Parameters.m_Print_Sheet_Ref, 1); m_config->Read( OPTKEY_PRINT_MONOCHROME_MODE, &s_Parameters.m_Print_Black_and_White, 1); m_config->Read( OPTKEY_PRINT_PAGE_PER_LAYER, &s_Parameters.m_OptionPrintPage, 0); int tmp; m_config->Read( OPTKEY_PRINT_PADS_DRILL, &tmp, PRINT_PARAMETERS::SMALL_DRILL_SHAPE ); s_Parameters.m_DrillShapeOpt = (PRINT_PARAMETERS::DrillShapeOptT) tmp; // Test for a reasonable scale value. Set to 1 if problem if( s_Parameters.m_XScaleAdjust < MIN_SCALE || s_Parameters.m_YScaleAdjust < MIN_SCALE || s_Parameters.m_XScaleAdjust > MAX_SCALE || s_Parameters.m_YScaleAdjust > MAX_SCALE ) s_Parameters.m_XScaleAdjust = s_Parameters.m_YScaleAdjust = 1.0; } m_ScaleOption->SetSelection( scale_idx ); scale_idx = m_ScaleOption->GetSelection(); s_Parameters.m_PrintScale = s_ScaleList[scale_idx]; m_Print_Mirror->SetValue(s_Parameters.m_PrintMirror); m_Exclude_Edges_Pcb->SetValue(m_ExcludeEdgeLayer); m_Print_Sheet_Ref->SetValue( s_Parameters.m_Print_Sheet_Ref ); // Options to plot pads and vias holes m_Drill_Shape_Opt->SetSelection( s_Parameters.m_DrillShapeOpt ); if( s_Parameters.m_Print_Black_and_White ) m_ModeColorOption->SetSelection( 1 ); else m_ModeColorOption->SetSelection( 0 ); m_PagesOption->SetSelection(s_Parameters.m_OptionPrintPage); s_Parameters.m_PenDefaultSize = g_DrawDefaultLineThickness; AddUnitSymbol( *m_TextPenWidth, g_UserUnit ); m_DialogPenWidth->SetValue( StringFromValue( g_UserUnit, s_Parameters.m_PenDefaultSize ) ); // Create scale adjust option msg.Printf( wxT( "%f" ), s_Parameters.m_XScaleAdjust ); m_FineAdjustXscaleOpt->SetValue( msg ); msg.Printf( wxT( "%f" ), s_Parameters.m_YScaleAdjust ); m_FineAdjustYscaleOpt->SetValue( msg ); bool enable = (s_Parameters.m_PrintScale == 1.0); m_FineAdjustXscaleOpt->Enable(enable); m_FineAdjustYscaleOpt->Enable(enable); } int DIALOG_PRINT_USING_PRINTER::SetLayerSetFromListSelection() { int page_count = 0; s_Parameters.m_PrintMaskLayer = LSET(); for( unsigned ii = 0; ii < DIM(m_boxSelectLayer); ++ii ) { if( !m_boxSelectLayer[ii].first ) continue; if( m_boxSelectLayer[ii].first->IsChecked( m_boxSelectLayer[ii].second ) ) { page_count++; s_Parameters.m_PrintMaskLayer.set( ii ); } } // In Pcbnew force the EDGE layer to be printed or not with the other layers m_ExcludeEdgeLayer = m_Exclude_Edges_Pcb->IsChecked(); if( m_ExcludeEdgeLayer ) s_Parameters.m_Flags = 0; else s_Parameters.m_Flags = 1; if( PrintUsingSinglePage() ) page_count = 1; s_Parameters.m_PageCount = page_count; return page_count; } void DIALOG_PRINT_USING_PRINTER::OnCloseWindow( wxCloseEvent& event ) { SetPrintParameters(); if( m_config ) { ConfigBaseWriteDouble( m_config, OPTKEY_PRINT_X_FINESCALE_ADJ, s_Parameters.m_XScaleAdjust ); ConfigBaseWriteDouble( m_config, OPTKEY_PRINT_Y_FINESCALE_ADJ, s_Parameters.m_YScaleAdjust ); m_config->Write( OPTKEY_PRINT_SCALE, m_ScaleOption->GetSelection() ); m_config->Write( OPTKEY_PRINT_PAGE_FRAME, s_Parameters.m_Print_Sheet_Ref); m_config->Write( OPTKEY_PRINT_MONOCHROME_MODE, s_Parameters.m_Print_Black_and_White); m_config->Write( OPTKEY_PRINT_PAGE_PER_LAYER, s_Parameters.m_OptionPrintPage ); m_config->Write( OPTKEY_PRINT_PADS_DRILL, (long) s_Parameters.m_DrillShapeOpt ); wxString layerKey; for( unsigned layer = 0; layer < DIM(m_boxSelectLayer); ++layer ) { if( !m_boxSelectLayer[layer].first ) continue; layerKey.Printf( OPTKEY_LAYERBASE, layer ); m_config->Write( layerKey, m_boxSelectLayer[layer].first->IsChecked( m_boxSelectLayer[layer].second ) ); } } EndModal( 0 ); } void DIALOG_PRINT_USING_PRINTER::SetPrintParameters( ) { PCB_PLOT_PARAMS plot_opts = m_parent->GetPlotSettings(); s_Parameters.m_PrintMirror = m_Print_Mirror->GetValue(); s_Parameters.m_Print_Sheet_Ref = m_Print_Sheet_Ref->GetValue(); s_Parameters.m_Print_Black_and_White = m_ModeColorOption->GetSelection() != 0; s_Parameters.m_DrillShapeOpt = (PRINT_PARAMETERS::DrillShapeOptT) m_Drill_Shape_Opt->GetSelection(); s_Parameters.m_OptionPrintPage = m_PagesOption->GetSelection() != 0; SetLayerSetFromListSelection(); int idx = m_ScaleOption->GetSelection(); s_Parameters.m_PrintScale = s_ScaleList[idx]; plot_opts.SetScale( s_Parameters.m_PrintScale ); if( m_FineAdjustXscaleOpt ) { if( s_Parameters.m_XScaleAdjust > MAX_SCALE || s_Parameters.m_YScaleAdjust > MAX_SCALE ) DisplayInfoMessage( NULL, _( "Warning: Scale option set to a very large value" ) ); m_FineAdjustXscaleOpt->GetValue().ToDouble( &s_Parameters.m_XScaleAdjust ); } if( m_FineAdjustYscaleOpt ) { // Test for a reasonable scale value if( s_Parameters.m_XScaleAdjust < MIN_SCALE || s_Parameters.m_YScaleAdjust < MIN_SCALE ) DisplayInfoMessage( NULL, _( "Warning: Scale option set to a very small value" ) ); m_FineAdjustYscaleOpt->GetValue().ToDouble( &s_Parameters.m_YScaleAdjust ); } plot_opts.SetFineScaleAdjustX( s_Parameters.m_XScaleAdjust ); plot_opts.SetFineScaleAdjustY( s_Parameters.m_YScaleAdjust ); m_parent->SetPlotSettings( plot_opts ); SetPenWidth(); } void DIALOG_PRINT_USING_PRINTER::SetPenWidth() { // Get the new pen width value, and verify min et max value // NOTE: s_Parameters.m_PenDefaultSize is in internal units s_Parameters.m_PenDefaultSize = ValueFromTextCtrl( *m_DialogPenWidth ); if( s_Parameters.m_PenDefaultSize > PEN_WIDTH_MAX_VALUE ) { s_Parameters.m_PenDefaultSize = PEN_WIDTH_MAX_VALUE; } if( s_Parameters.m_PenDefaultSize < PEN_WIDTH_MIN_VALUE ) { s_Parameters.m_PenDefaultSize = PEN_WIDTH_MIN_VALUE; } g_DrawDefaultLineThickness = s_Parameters.m_PenDefaultSize; m_DialogPenWidth->SetValue( StringFromValue( g_UserUnit, s_Parameters.m_PenDefaultSize ) ); } void DIALOG_PRINT_USING_PRINTER::OnScaleSelectionClick( wxCommandEvent& event ) { double scale = s_ScaleList[m_ScaleOption->GetSelection()]; bool enable = (scale == 1.0); if( m_FineAdjustXscaleOpt ) m_FineAdjustXscaleOpt->Enable(enable); if( m_FineAdjustYscaleOpt ) m_FineAdjustYscaleOpt->Enable(enable); } void DIALOG_PRINT_USING_PRINTER::OnPageSetup( wxCommandEvent& event ) { wxPageSetupDialog pageSetupDialog( this, s_pageSetupData ); pageSetupDialog.ShowModal(); (*s_PrintData) = pageSetupDialog.GetPageSetupDialogData().GetPrintData(); (*s_pageSetupData) = pageSetupDialog.GetPageSetupDialogData(); } void DIALOG_PRINT_USING_PRINTER::OnPrintPreview( wxCommandEvent& event ) { SetPrintParameters( ); // If no layer selected, we have no plot. prompt user if it happens // because he could think there is a bug in Pcbnew: if( s_Parameters.m_PrintMaskLayer == 0 ) { DisplayError( this, _( "No layer selected" ) ); return; } // Pass two printout objects: for preview, and possible printing. wxString title = _( "Print Preview" ); wxPrintPreview* preview = new wxPrintPreview( new BOARD_PRINTOUT_CONTROLLER( s_Parameters, m_parent, title ), new BOARD_PRINTOUT_CONTROLLER( s_Parameters, m_parent, title ), s_PrintData ); if( preview == NULL ) { DisplayError( this, wxT( "An error occurred attempting to show the print preview window." ) ); return; } // Uses the parent position and size. wxPoint WPos = m_parent->GetPosition(); wxSize WSize = m_parent->GetSize(); preview->SetZoom( 100 ); wxPreviewFrame* frame = new wxPreviewFrame( preview, this, title, WPos, WSize ); frame->SetMinSize( wxSize( 550, 350 ) ); frame->Center(); // On wxGTK, set the flag wxTOPLEVEL_EX_DIALOG is mandatory, if we want // close the frame using the X box in caption, when the preview frame is run // from a dialog frame->SetExtraStyle( frame->GetExtraStyle() | wxTOPLEVEL_EX_DIALOG ); // We use here wxPreviewFrame_WindowModal option to make the wxPrintPreview frame // modal for its caller only. // An other reason is the fact when closing the frame without this option, // all top level frames are reenabled. // With this option, only the parent is reenabled. // Reenabling all top level frames should be made by the parent dialog. frame->InitializeWithModality( wxPreviewFrame_WindowModal ); frame->Raise(); // Needed on Ubuntu/Unity to display the frame frame->Show( true ); } void DIALOG_PRINT_USING_PRINTER::OnPrintButtonClick( wxCommandEvent& event ) { SetPrintParameters( ); // If no layer selected, we have no plot. prompt user if it happens // because he could think there is a bug in Pcbnew: if( s_Parameters.m_PrintMaskLayer == 0 ) { DisplayError( this, _( "No layer selected." ) ); return; } wxPrintDialogData printDialogData( *s_PrintData ); printDialogData.SetMaxPage( s_Parameters.m_PageCount ); wxPrinter printer( &printDialogData ); wxString title = _( "Print" ); BOARD_PRINTOUT_CONTROLLER printout( s_Parameters, m_parent, title ); if( !printer.Print( this, &printout, true ) ) { if( wxPrinter::GetLastError() == wxPRINTER_ERROR ) DisplayError( this, _( "There was a problem printing." ) ); return; } else { *s_PrintData = printer.GetPrintDialogData().GetPrintData(); } }