diff --git a/pcbnew/dialogs/dialog_plot.cpp b/pcbnew/dialogs/dialog_plot.cpp index 9d3253dd8d..43cccca7bc 100644 --- a/pcbnew/dialogs/dialog_plot.cpp +++ b/pcbnew/dialogs/dialog_plot.cpp @@ -50,6 +50,7 @@ #include #include #include +#include #include #include @@ -411,6 +412,7 @@ void DIALOG_PLOT::init_Dialog() m_frontFPPropertyPopups->SetValue( m_plotOpts.m_PDFFrontFPPropertyPopups ); m_backFPPropertyPopups->SetValue( m_plotOpts.m_PDFBackFPPropertyPopups ); m_pdfMetadata->SetValue( m_plotOpts.m_PDFMetadata ); + m_pdfSingle->SetValue( m_plotOpts.m_PDFSingle ); // Initialize a few other parameters, which can also be modified // from the drill dialog @@ -1114,6 +1116,7 @@ void DIALOG_PLOT::applyPlotSettings() tempOptions.m_PDFFrontFPPropertyPopups = m_frontFPPropertyPopups->GetValue(); tempOptions.m_PDFBackFPPropertyPopups = m_backFPPropertyPopups->GetValue(); tempOptions.m_PDFMetadata = m_pdfMetadata->GetValue(); + tempOptions.m_PDFSingle = m_pdfSingle->GetValue(); } else { @@ -1369,38 +1372,17 @@ void DIALOG_PLOT::Plot( wxCommandEvent& event ) wxBusyCursor dummy; - for( PCB_LAYER_ID layer : m_plotOpts.GetLayerSelection().UIOrder() ) + if( m_plotOpts.GetFormat() == PLOT_FORMAT::PDF && + m_plotOpts.m_PDFSingle ) { - LSEQ plotSequence; - // Base layer always gets plotted first. - plotSequence.push_back( layer ); + } - // Add selected layers from plot on all layers list in order set by user. - wxArrayInt plotOnAllLayers; - - if( m_plotAllLayersList->GetCheckedItems( plotOnAllLayers ) ) - { - size_t count = plotOnAllLayers.GetCount(); - - for( size_t i = 0; i < count; i++ ) - { - int index = plotOnAllLayers.Item( i ); - PCB_LAYER_ID client_layer = getLayerClientData( m_plotAllLayersList, index )->Layer(); - - // Don't plot the same layer more than once; - if( find( plotSequence.begin(), plotSequence.end(), client_layer ) != plotSequence.end() ) - continue; - - plotSequence.push_back( client_layer ); - } - } - - wxString layerName = board->GetLayerName( layer ); - //@todo allow controlling the sheet name and path that will be displayed in the title block - // Leave blank for now - wxString sheetName; - wxString sheetPath; + LSEQ layersToPlot = m_plotOpts.GetLayerSelection().UIOrder(); + size_t finalPageCount = 0; + for( size_t i = 0; i < layersToPlot.size(); i++ ) + { + PCB_LAYER_ID layer = layersToPlot[i]; // All copper layers that are disabled are actually selected // This is due to wonkyness in automatically selecting copper layers @@ -1411,6 +1393,30 @@ void DIALOG_PLOT::Plot( wxCommandEvent& event ) if( ( LSET::AllCuMask() & ~board->GetEnabledLayers() )[layer] ) continue; + finalPageCount++; + } + + PLOTTER* plotter = nullptr; + for( size_t i = 0, pageNum = 1; i < layersToPlot.size(); i++ ) + { + PCB_LAYER_ID layer = layersToPlot[i]; + + // All copper layers that are disabled are actually selected + // This is due to wonkyness in automatically selecting copper layers + // for plotting when adding more than two layers to a board. + // If plot options become accessible to the layers setup dialog + // please move this functionality there! + // This skips a copper layer if it is actually disabled on the board. + if( ( LSET::AllCuMask() & ~board->GetEnabledLayers() )[layer] ) + continue; + + LSEQ plotSequence = getPlotSequence( layer ); + + wxString layerName = board->GetLayerName( layer ); + //@todo allow controlling the sheet name and path that will be displayed in the title block + // Leave blank for now + wxString sheetPath; + // Pick the basename from the board file wxFileName fn( boardFilename ); @@ -1419,14 +1425,37 @@ void DIALOG_PLOT::Plot( wxCommandEvent& event ) if( m_plotOpts.GetFormat() == PLOT_FORMAT::GERBER && m_useGerberExtensions->GetValue() ) file_ext = GetGerberProtelExtension( layer ); - BuildPlotFileName( &fn, outputDir.GetPath(), layerName, file_ext ); - wxString fullname = fn.GetFullName(); - jobfile_writer.AddGbrFile( layer, fullname ); + if( m_plotOpts.GetFormat() == PLOT_FORMAT::PDF && m_plotOpts.m_PDFSingle ) + { + fn.SetExt( FILEEXT::PdfFileExtension ); + } + else + { + BuildPlotFileName( &fn, outputDir.GetPath(), layerName, file_ext ); + } + + if( m_plotOpts.GetFormat() == PLOT_FORMAT::GERBER ) + { + wxString fullname = fn.GetFullName(); + jobfile_writer.AddGbrFile( layer, fullname ); + } LOCALE_IO toggle; - PLOTTER* plotter = StartPlotBoard( board, &m_plotOpts, layer, layerName, fn.GetFullPath(), - sheetName, sheetPath ); + if( m_plotOpts.GetFormat() != PLOT_FORMAT::PDF + || !m_plotOpts.m_PDFSingle + || ( i == 0 && m_plotOpts.GetFormat() == PLOT_FORMAT::PDF + && m_plotOpts.m_PDFSingle ) ) + { + // this will only be used by pdf + wxString pageNumber = wxString::Format( "%zu", pageNum ); + wxString pageName = layerName; + wxString sheetName = layerName; + + plotter = StartPlotBoard( board, &m_plotOpts, layer, layerName, fn.GetFullPath(), + sheetName, sheetPath, pageName, pageNumber, + finalPageCount ); + } // Print diags in messages box: wxString msg; @@ -1450,12 +1479,36 @@ void DIALOG_PLOT::Plot( wxCommandEvent& event ) PlotBoardLayers( board, plotter, plotSequence, m_plotOpts ); PlotInteractiveLayer( board, plotter, m_plotOpts ); - plotter->EndPlot(); - delete plotter->RenderSettings(); - delete plotter; - msg.Printf( _( "Plotted to '%s'." ), fn.GetFullPath() ); - reporter.Report( msg, RPT_SEVERITY_ACTION ); + if( m_plotOpts.GetFormat() == PLOT_FORMAT::PDF && m_plotOpts.m_PDFSingle && + i != layersToPlot.size() - 1) + { + // this will only be used by pdf + // this will only be used by pdf + wxString pageNumber = wxString::Format( "%zu", pageNum + 1 ); + PCB_LAYER_ID nextLayer = layersToPlot[i + 1]; + wxString pageName = board->GetLayerName( nextLayer ); + wxString sheetName = layerName; + + static_cast( plotter )->ClosePage(); + static_cast( plotter )->StartPage( pageNumber, pageName ); + setupPlotterNewPDFPage( plotter, board, &m_plotOpts, sheetName, sheetPath, + pageNumber, finalPageCount ); + } + + if( m_plotOpts.GetFormat() != PLOT_FORMAT::PDF + || !m_plotOpts.m_PDFSingle + || i == layersToPlot.size()-1 ) + { + plotter->EndPlot(); + delete plotter->RenderSettings(); + delete plotter; + plotter = nullptr; + + msg.Printf( _( "Plotted to '%s'." ), fn.GetFullPath() ); + reporter.Report( msg, RPT_SEVERITY_ACTION ); + } + } else { @@ -1463,6 +1516,8 @@ void DIALOG_PLOT::Plot( wxCommandEvent& event ) reporter.Report( msg, RPT_SEVERITY_ERROR ); } + pageNum++; + wxSafeYield(); // displays report message. } @@ -1481,6 +1536,38 @@ void DIALOG_PLOT::Plot( wxCommandEvent& event ) } } +LSEQ DIALOG_PLOT::getPlotSequence( PCB_LAYER_ID aLayerToPlot ) +{ + LSEQ plotSequence; + + // Base layer always gets plotted first. + plotSequence.push_back( aLayerToPlot ); + + // Add selected layers from plot on all layers list in order set by user. + wxArrayInt plotOnAllLayers; + + if( m_plotAllLayersList->GetCheckedItems( plotOnAllLayers ) ) + { + size_t count = plotOnAllLayers.GetCount(); + + for( size_t i = 0; i < count; i++ ) + { + int index = plotOnAllLayers.Item( i ); + PCB_LAYER_ID client_layer = getLayerClientData( m_plotAllLayersList, index )->Layer(); + + // Don't plot the same layer more than once; + if( find( plotSequence.begin(), plotSequence.end(), client_layer ) + != plotSequence.end() ) + continue; + + plotSequence.push_back( client_layer ); + } + } + + return plotSequence; +} + + void DIALOG_PLOT::onRunDRC( wxCommandEvent& event ) { diff --git a/pcbnew/dialogs/dialog_plot.h b/pcbnew/dialogs/dialog_plot.h index 9b7de6930a..55a8cc80ef 100644 --- a/pcbnew/dialogs/dialog_plot.h +++ b/pcbnew/dialogs/dialog_plot.h @@ -83,6 +83,8 @@ private: void loadPlotParamsFromJob(); void transferPlotParamsToJob(); + LSEQ getPlotSequence( PCB_LAYER_ID aLayerToPlot ); + private: PCB_EDIT_FRAME* m_editFrame; LSEQ m_layerList; // List to hold CheckListBox layer numbers diff --git a/pcbnew/dialogs/dialog_plot_base.cpp b/pcbnew/dialogs/dialog_plot_base.cpp index c671d55a9c..7aa95decc5 100644 --- a/pcbnew/dialogs/dialog_plot_base.cpp +++ b/pcbnew/dialogs/dialog_plot_base.cpp @@ -1,5 +1,5 @@ /////////////////////////////////////////////////////////////////////////// -// C++ code generated with wxFormBuilder (version 4.2.1-0-g80c4cb6a) +// C++ code generated with wxFormBuilder (version 4.2.1-0-g80c4cb6) // http://www.wxformbuilder.org/ // // PLEASE DO *NOT* EDIT THIS FILE! @@ -420,7 +420,10 @@ DIALOG_PLOT_BASE::DIALOG_PLOT_BASE( wxWindow* parent, wxWindowID id, const wxStr m_pdfMetadata = new wxCheckBox( m_PDFOptionsSizer->GetStaticBox(), wxID_ANY, _("Generate metadata from AUTHOR && SUBJECT variables"), wxDefaultPosition, wxDefaultSize, 0 ); m_pdfMetadata->SetToolTip( _("Generate PDF document properties from AUTHOR and SUBJECT text variables") ); - gbSizer4->Add( m_pdfMetadata, wxGBPosition( 3, 0 ), wxGBSpan( 1, 2 ), wxBOTTOM|wxRIGHT|wxLEFT, 5 ); + gbSizer4->Add( m_pdfMetadata, wxGBPosition( 3, 0 ), wxGBSpan( 1, 2 ), wxLEFT|wxRIGHT, 5 ); + + m_pdfSingle = new wxCheckBox( m_PDFOptionsSizer->GetStaticBox(), wxID_ANY, _("Single document"), wxDefaultPosition, wxDefaultSize, 0 ); + gbSizer4->Add( m_pdfSingle, wxGBPosition( 4, 0 ), wxGBSpan( 1, 2 ), wxBOTTOM|wxLEFT|wxRIGHT, 5 ); m_PDFOptionsSizer->Add( gbSizer4, 1, wxEXPAND|wxBOTTOM, 5 ); diff --git a/pcbnew/dialogs/dialog_plot_base.fbp b/pcbnew/dialogs/dialog_plot_base.fbp index 10490af0e2..4e38e5f981 100644 --- a/pcbnew/dialogs/dialog_plot_base.fbp +++ b/pcbnew/dialogs/dialog_plot_base.fbp @@ -4301,7 +4301,7 @@ 5 2 0 - wxBOTTOM|wxRIGHT|wxLEFT + wxLEFT|wxRIGHT 3 1 @@ -4365,6 +4365,74 @@ + + 5 + 2 + 0 + wxBOTTOM|wxLEFT|wxRIGHT + 4 + 1 + + 1 + 1 + 1 + 1 + 0 + + 0 + 0 + + + + 1 + 0 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 0 + 1 + + 1 + + 0 + 0 + wxID_ANY + Single document + + 0 + + + 0 + + 1 + m_pdfSingle + 1 + + + protected + 1 + + Resizable + 1 + + + ; ; forward_declare + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + diff --git a/pcbnew/dialogs/dialog_plot_base.h b/pcbnew/dialogs/dialog_plot_base.h index fa0326c9ef..3317c33804 100644 --- a/pcbnew/dialogs/dialog_plot_base.h +++ b/pcbnew/dialogs/dialog_plot_base.h @@ -1,5 +1,5 @@ /////////////////////////////////////////////////////////////////////////// -// C++ code generated with wxFormBuilder (version 4.2.1-0-g80c4cb6a) +// C++ code generated with wxFormBuilder (version 4.2.1-0-g80c4cb6) // http://www.wxformbuilder.org/ // // PLEASE DO *NOT* EDIT THIS FILE! @@ -123,6 +123,7 @@ class DIALOG_PLOT_BASE : public DIALOG_SHIM wxCheckBox* m_frontFPPropertyPopups; wxCheckBox* m_backFPPropertyPopups; wxCheckBox* m_pdfMetadata; + wxCheckBox* m_pdfSingle; WX_HTML_REPORT_PANEL* m_messagesPanel; wxBoxSizer* m_sizerButtons; wxButton* m_buttonDRC; diff --git a/pcbnew/pcb_plot_params.cpp b/pcbnew/pcb_plot_params.cpp index 7f734e77f2..796f0bf783 100644 --- a/pcbnew/pcb_plot_params.cpp +++ b/pcbnew/pcb_plot_params.cpp @@ -140,6 +140,7 @@ PCB_PLOT_PARAMS::PCB_PLOT_PARAMS() m_PDFFrontFPPropertyPopups = true; m_PDFBackFPPropertyPopups = true; m_PDFMetadata = true; + m_PDFSingle = false; // This parameter controls if the NPTH pads will be plotted or not // it is a "local" parameter diff --git a/pcbnew/pcb_plot_params.h b/pcbnew/pcb_plot_params.h index 313d0b8d78..473b34340d 100644 --- a/pcbnew/pcb_plot_params.h +++ b/pcbnew/pcb_plot_params.h @@ -202,6 +202,7 @@ public: bool m_PDFFrontFPPropertyPopups; ///< Generate PDF property popup menus for footprints bool m_PDFBackFPPropertyPopups; ///< on front and/or back of board bool m_PDFMetadata; ///< Generate PDF metadata for SUBJECT and AUTHOR + bool m_PDFSingle; ///< Generate a single PDF file for all layers private: friend class PCB_PLOT_PARAMS_PARSER; diff --git a/pcbnew/pcbplot.h b/pcbnew/pcbplot.h index 6672e3184c..c5ff62f7db 100644 --- a/pcbnew/pcbplot.h +++ b/pcbnew/pcbplot.h @@ -157,9 +157,15 @@ private: PLOTTER* StartPlotBoard( BOARD* aBoard, const PCB_PLOT_PARAMS* aPlotOpts, int aLayer, const wxString& aLayerName, const wxString& aFullFileName, - const wxString& aSheetName, const wxString& aSheetPath ); + const wxString& aSheetName, const wxString& aSheetPath, + const wxString& aPageName = wxT( "1" ), + const wxString& aPageNumber = wxEmptyString, + const int aPageCount = 1); -/** +void setupPlotterNewPDFPage( PLOTTER* aPlotter, BOARD* aBoard, const PCB_PLOT_PARAMS* aPlotOpts, + const wxString& aSheetName, const wxString& aSheetPath, + const wxString& aPageNumber, int aPageCount ); + /** * Plot a sequence of board layer IDs. * * @param aBoard is the board to plot. diff --git a/pcbnew/plot_board_layers.cpp b/pcbnew/plot_board_layers.cpp index 21773f6c0c..5043434f36 100644 --- a/pcbnew/plot_board_layers.cpp +++ b/pcbnew/plot_board_layers.cpp @@ -1205,7 +1205,9 @@ static void ConfigureHPGLPenSizes( HPGL_PLOTTER *aPlotter, const PCB_PLOT_PARAMS */ PLOTTER* StartPlotBoard( BOARD *aBoard, const PCB_PLOT_PARAMS *aPlotOpts, int aLayer, const wxString& aLayerName, const wxString& aFullFileName, - const wxString& aSheetName, const wxString& aSheetPath ) + const wxString& aSheetName, const wxString& aSheetPath, + const wxString& aPageName, const wxString& aPageNumber, + const int aPageCount ) { wxCHECK( aBoard && aPlotOpts, nullptr ); @@ -1300,14 +1302,26 @@ PLOTTER* StartPlotBoard( BOARD *aBoard, const PCB_PLOT_PARAMS *aPlotOpts, int aL AddGerberX2Attribute( plotter, aBoard, aLayer, not useX2mode ); } - if( plotter->StartPlot( wxT( "1" ) ) ) + bool startPlotSuccess = false; + if (plotter->GetPlotterType() == PLOT_FORMAT::PDF) + { + startPlotSuccess = + static_cast( plotter )->StartPlot( aPageNumber, aPageName ); + } + else + { + startPlotSuccess = plotter->StartPlot( aPageName ); + } + + + if( startPlotSuccess ) { // Plot the frame reference if requested if( aPlotOpts->GetPlotFrameRef() ) { PlotDrawingSheet( plotter, aBoard->GetProject(), aBoard->GetTitleBlock(), - aBoard->GetPageSettings(), &aBoard->GetProperties(), wxT( "1" ), - 1, aSheetName, aSheetPath, aBoard->GetFileName(), + aBoard->GetPageSettings(), &aBoard->GetProperties(), aPageNumber, + aPageCount, aSheetName, aSheetPath, aBoard->GetFileName(), renderSettings->GetLayerColor( LAYER_DRAWINGSHEET ) ); if( aPlotOpts->GetMirror() ) @@ -1331,3 +1345,23 @@ PLOTTER* StartPlotBoard( BOARD *aBoard, const PCB_PLOT_PARAMS *aPlotOpts, int aL delete plotter; return nullptr; } + +void setupPlotterNewPDFPage( PLOTTER* aPlotter, + BOARD* aBoard, + const PCB_PLOT_PARAMS* aPlotOpts, + const wxString& aSheetName, const wxString& aSheetPath, + const wxString& aPageNumber, int aPageCount ) +{ + // Plot the frame reference if requested + if( aPlotOpts->GetPlotFrameRef() ) + { + PlotDrawingSheet( aPlotter, aBoard->GetProject(), aBoard->GetTitleBlock(), + aBoard->GetPageSettings(), &aBoard->GetProperties(), aPageNumber, + aPageCount, + aSheetName, aSheetPath, aBoard->GetFileName(), + aPlotter->RenderSettings()->GetLayerColor( LAYER_DRAWINGSHEET ) ); + + if( aPlotOpts->GetMirror() ) + initializePlotter( aPlotter, aBoard, aPlotOpts ); + } +}