KiCad PCB EDA Suite
dialog_print_pcbnew.cpp
Go to the documentation of this file.
1 /*
2  * This program source code file is part of KiCad, a free EDA CAD application.
3  *
4  * Copyright (C) 2010-2016 Jean-Pierre Charras, jean-pierre.charras at wanadoo.fr
5  * Copyright (C) 1992-2019 KiCad Developers, see AUTHORS.txt for contributors.
6  * Copyright (C) 2018 CERN
7  * Author: Maciej Suminski <maciej.suminski@cern.ch>
8  *
9  * This program is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU General Public License
11  * as published by the Free Software Foundation; either version 2
12  * of the License, or (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, you may find one here:
21  * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
22  * or you may search the http://www.gnu.org website for the version 2 license,
23  * or you may write to the Free Software Foundation, Inc.,
24  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
25  */
26 
27 #include <fctsys.h>
28 #include <kiface_i.h>
29 #include <confirm.h>
30 #include <base_units.h>
31 #include <pcbnew.h>
32 #include <pcbplot.h>
33 #include <class_board.h>
34 #include <tool/tool_manager.h>
35 #include <tools/pcb_actions.h>
36 #include <tools/pcbnew_control.h>
37 #include <dialog_print_generic.h>
38 #include <pcbnew_printout.h>
39 
41 {
42 public:
45 
46 private:
48  {
49  wxASSERT( dynamic_cast<PCBNEW_PRINTOUT_SETTINGS*>( m_settings ) );
50  return static_cast<PCBNEW_PRINTOUT_SETTINGS*>( m_settings );
51  }
52 
53  bool TransferDataToWindow() override;
54 
55  void createExtraOptions();
56  void createLeftPanel();
57 
58  void onSelectAllClick( wxCommandEvent& event );
59  void onDeselectAllClick( wxCommandEvent& event );
60 
62  void setListBoxValue( wxCheckListBox* aList, bool aValue );
63 
65  bool isLayerEnabled( unsigned int aLayer ) const;
66 
68  void enableLayer( unsigned int aLayer, bool aValue );
69 
71  int setLayerSetFromList();
72 
73  void saveSettings() override;
74 
75  wxPrintout* createPrintout( const wxString& aTitle ) override
76  {
77  return new PCBNEW_PRINTOUT( m_parent->GetBoard(), *settings(),
78  m_parent->GetCanvas()->GetView(), aTitle );
79  }
80 
82 
83  // List of existing board layers in wxCheckListBox, with the board layers id:
84  std::pair<wxCheckListBox*, int> m_layers[PCB_LAYER_ID_COUNT];
85 
86  // Extra widgets
87  wxCheckListBox* m_listTechLayers;
88  wxCheckListBox* m_listCopperLayers;
89  wxButton* m_buttonSelectAll;
91  wxCheckBox* m_checkboxNoEdge;
92  wxCheckBox* m_checkboxMirror;
93  wxChoice* m_drillMarksChoice;
94  wxRadioBox* m_boxPagination;
95 };
96 
97 
99  DIALOG_PRINT_GENERIC( aParent, aSettings ), m_parent( aParent )
100 {
102  memset( m_layers, 0, sizeof( m_layers ) );
103 
105  createLeftPanel();
106 }
107 
108 
110 {
112  return false;
113 
114  BOARD* board = m_parent->GetBoard();
115 
116  // Create layer list
117  for( LSEQ seq = board->GetEnabledLayers().UIOrder(); seq; ++seq )
118  {
119  PCB_LAYER_ID layer = *seq;
120  int checkIndex;
121 
122  if( IsCopperLayer( layer ) )
123  {
124  checkIndex = m_listCopperLayers->Append( board->GetLayerName( layer ) );
125  m_layers[layer] = std::make_pair( m_listCopperLayers, checkIndex );
126  }
127  else
128  {
129  checkIndex = m_listTechLayers->Append( board->GetLayerName( layer ) );
130  m_layers[layer] = std::make_pair( m_listTechLayers, checkIndex );
131  }
132 
133  m_layers[layer].first->Check( checkIndex, settings()->m_layerSet.test( layer ) );
134  }
135 
136  m_checkboxMirror->SetValue( settings()->m_mirror );
137  m_checkboxNoEdge->SetValue( settings()->m_noEdgeLayer );
138  m_titleBlock->SetValue( settings()->m_titleBlock );
139 
140  // Options to plot pads and vias holes
141  m_drillMarksChoice->SetSelection( settings()->m_drillMarks );
142 
143  // Print all layers one one page or separately
144  m_boxPagination->SetSelection( settings()->m_pagination );
145 
146  // Update the dialog layout when layers are added
147  GetSizer()->Fit( this );
148 
149  return true;
150 }
151 
152 
154 {
155  wxGridBagSizer* optionsSizer = getOptionsSizer();
156  wxStaticBox* box = getOptionsBox();
157  int rows = optionsSizer->GetEffectiveRowsCount();
158  int cols = optionsSizer->GetEffectiveColsCount();
159 
160  // Drill marks option
161  auto drillMarksLabel = new wxStaticText( box, wxID_ANY, _( "Drill marks:" ) );
162  std::vector<wxString> drillMarkChoices =
163  { _( "No drill mark" ), _( "Small mark" ), _( "Real drill" ) };
164  m_drillMarksChoice = new wxChoice( box, wxID_ANY, wxDefaultPosition,
165  wxDefaultSize, drillMarkChoices.size(), drillMarkChoices.data(), 0 );
166  m_drillMarksChoice->SetSelection( 0 );
167 
168  // Print mirrored
169  m_checkboxMirror = new wxCheckBox( box, wxID_ANY, _( "Print mirrored" ) );
170 
171  // Pagination
172  std::vector<wxString> pagesOption = { _( "One page per layer" ), _( "All layers on single page" ) };
173  m_boxPagination = new wxRadioBox( box, wxID_ANY, _( "Pagination" ), wxDefaultPosition,
174  wxDefaultSize, pagesOption.size(), pagesOption.data(), 1, wxRA_SPECIFY_COLS );
175  m_boxPagination->SetSelection( 0 );
176 
177  // Sizer layout
178  optionsSizer->Add( drillMarksLabel, wxGBPosition( rows, 0 ), wxGBSpan( 1, 1 ),
179  wxBOTTOM | wxRIGHT | wxLEFT | wxALIGN_CENTER_VERTICAL, 5 );
180  optionsSizer->Add( m_drillMarksChoice, wxGBPosition( rows, 1 ), wxGBSpan( 1, cols - 1 ),
181  wxBOTTOM | wxRIGHT | wxLEFT, 5 );
182  optionsSizer->Add( m_checkboxMirror, wxGBPosition( rows + 1, 0 ), wxGBSpan( 1, cols ),
183  wxBOTTOM | wxRIGHT | wxLEFT, 5 );
184  optionsSizer->Add( m_boxPagination, wxGBPosition( rows + 2, 0 ), wxGBSpan( 1, cols ), wxALL | wxEXPAND, 5 );
185 }
186 
187 
189 {
190  wxStaticBoxSizer* sbLayersSizer = new wxStaticBoxSizer( new wxStaticBox( this,
191  wxID_ANY, _( "Included Layers" ) ), wxVERTICAL );
192 
193  // Copper layer list
194  auto copperLabel = new wxStaticText( sbLayersSizer->GetStaticBox(), wxID_ANY, _( "Copper layers:" ) );
195  m_listCopperLayers = new wxCheckListBox( sbLayersSizer->GetStaticBox(), wxID_ANY );
196 
197  wxBoxSizer* sizerLeft = new wxBoxSizer( wxVERTICAL );
198  sizerLeft->Add( copperLabel, 0, wxRIGHT | wxLEFT, 5 );
199  sizerLeft->Add( m_listCopperLayers, 1, wxEXPAND | wxBOTTOM | wxRIGHT | wxLEFT, 5 );
200 
201 
202  // Technical layer list
203  auto technicalLabel = new wxStaticText( sbLayersSizer->GetStaticBox(), wxID_ANY, _( "Technical layers:" ) );
204  m_listTechLayers = new wxCheckListBox( sbLayersSizer->GetStaticBox(), wxID_ANY );
205 
206  wxBoxSizer* sizerRight = new wxBoxSizer( wxVERTICAL );
207  sizerRight->Add( technicalLabel, 0, wxRIGHT | wxLEFT, 5 );
208  sizerRight->Add( m_listTechLayers, 1, wxEXPAND | wxBOTTOM | wxRIGHT | wxLEFT, 5 );
209 
210 
211  // Layer list layout
212  wxBoxSizer* bLayerListsSizer = new wxBoxSizer( wxHORIZONTAL );
213  bLayerListsSizer->Add( sizerLeft, 1, wxEXPAND, 5 );
214  bLayerListsSizer->Add( sizerRight, 1, wxEXPAND, 5 );
215 
216 
217  // Select/Unselect all buttons
218  m_buttonSelectAll = new wxButton( sbLayersSizer->GetStaticBox(), wxID_ANY, _( "Select all" ) );
219  m_buttonDeselectAll = new wxButton( sbLayersSizer->GetStaticBox(), wxID_ANY, _( "Deselect all" ) );
220 
221  m_buttonSelectAll->Connect( wxEVT_COMMAND_BUTTON_CLICKED,
222  wxCommandEventHandler( DIALOG_PRINT_PCBNEW::onSelectAllClick ), NULL, this );
223  m_buttonDeselectAll->Connect( wxEVT_COMMAND_BUTTON_CLICKED,
224  wxCommandEventHandler( DIALOG_PRINT_PCBNEW::onDeselectAllClick ), NULL, this );
225 
226  wxBoxSizer* buttonSizer = new wxBoxSizer( wxHORIZONTAL );
227  buttonSizer->Add( m_buttonSelectAll, 1, wxALL, 5 );
228  buttonSizer->Add( m_buttonDeselectAll, 1, wxALL, 5 );
229 
230 
231  // Exclude Edge.Pcb layer checkbox
232  m_checkboxNoEdge = new wxCheckBox( sbLayersSizer->GetStaticBox(), wxID_ANY, _( "Exclude PCB edge layer" ) );
233  m_checkboxNoEdge->SetToolTip( _("Exclude contents of Edges_Pcb layer from all other layers") );
234 
235  // Static box sizer layout
236  sbLayersSizer->Add( bLayerListsSizer, 1, wxALL | wxEXPAND, 5 );
237  sbLayersSizer->Add( buttonSizer, 0, wxALL | wxEXPAND, 5 );
238  sbLayersSizer->Add( m_checkboxNoEdge, 0, wxALL | wxEXPAND, 5 );
239 
240  getMainSizer()->Insert( 0, sbLayersSizer, 1, wxEXPAND );
241 }
242 
243 
244 void DIALOG_PRINT_PCBNEW::onSelectAllClick( wxCommandEvent& event )
245 {
248 }
249 
250 
251 void DIALOG_PRINT_PCBNEW::onDeselectAllClick( wxCommandEvent& event )
252 {
255 }
256 
257 
258 void DIALOG_PRINT_PCBNEW::setListBoxValue( wxCheckListBox* aList, bool aValue )
259 {
260  for( unsigned int i = 0; i < aList->GetCount(); ++i )
261  aList->Check( i, aValue );
262 }
263 
264 
265 bool DIALOG_PRINT_PCBNEW::isLayerEnabled( unsigned int aLayer ) const
266 {
267  wxCHECK( aLayer < arrayDim( m_layers ), false );
268  const auto& layerInfo = m_layers[aLayer];
269 
270  if( layerInfo.first )
271  return layerInfo.first->IsChecked( layerInfo.second );
272 
273  return false;
274 }
275 
276 
277 void DIALOG_PRINT_PCBNEW::enableLayer( unsigned int aLayer, bool aValue )
278 {
279  wxCHECK( aLayer < arrayDim( m_layers ), /* void */ );
280  const auto& layerInfo = m_layers[aLayer];
281  layerInfo.first->Check( layerInfo.second, aValue );
282 }
283 
284 
286 {
287  settings()->m_layerSet = LSET();
288  int& pageCount = settings()->m_pageCount;
289  pageCount = 0;
290 
291  for( unsigned int layer = 0; layer < arrayDim( m_layers ); ++layer )
292  {
293  if( isLayerEnabled( layer ) )
294  {
295  ++pageCount;
296  settings()->m_layerSet.set( layer );
297  }
298  }
299 
300  // In Pcbnew force the EDGE layer to be printed or not with the other layers
301  settings()->m_noEdgeLayer = m_checkboxNoEdge->IsChecked();
302 
303  // All layers on one page (only if there is at least one layer selected)
304  if( m_boxPagination->GetSelection() != 0 && pageCount > 0 )
305  pageCount = 1;
306 
307  return pageCount;
308 }
309 
310 
312 {
314 
317 
318  settings()->m_pagination = m_boxPagination->GetSelection() == 0
320 
321  settings()->m_mirror = m_checkboxMirror->GetValue();
322 
324 }
325 
326 
327 int PCBNEW_CONTROL::Print( const TOOL_EVENT& aEvent )
328 {
329  // Selection affects the origin item visibility
331 
333  DIALOG_PRINT_PCBNEW dlg( (PCB_BASE_EDIT_FRAME*) m_frame, &settings );
334 
335  if( m_editModules )
336  dlg.ForcePrintBorder( false );
337 
338  dlg.ShowModal();
339 
340  return 0;
341 }
342 
343 
static TOOL_ACTION selectionClear
Clears the current selection.
Definition: pcb_actions.h:73
bool m_noEdgeLayer
Disable board outline on each page.
void onDeselectAllClick(wxCommandEvent &event)
const wxString GetLayerName(PCB_LAYER_ID aLayer) const
Function GetLayerName returns the name of a layer given by aLayer.
Implementation of conversion functions that require both schematic and board internal units.
This file is part of the common library.
int setLayerSetFromList()
Update layerset basing on the selected layers
std::pair< wxCheckListBox *, int > m_layers[PCB_LAYER_ID_COUNT]
PCB_DRAW_PANEL_GAL * GetCanvas() const override
Return a pointer to GAL-based canvas of given EDA draw frame.
void saveSettings() override
void enableLayer(unsigned int aLayer, bool aValue)
Enable/disable layer in a listbox
wxPrintout * createPrintout(const wxString &aTitle) override
Create a printout with a requested title.
TOOL_MANAGER * m_toolMgr
Definition: tool_base.h:219
wxConfigBase * KifaceSettings() const
Definition: kiface_i.h:103
bool RunAction(const std::string &aActionName, bool aNow=false, T aParam=NULL)
Function RunAction() Runs the specified action.
Definition: tool_manager.h:109
bool isLayerEnabled(unsigned int aLayer) const
Check whether a layer is enabled in a listbox
wxCheckListBox * m_listCopperLayers
LSET GetEnabledLayers() const
Function GetEnabledLayers is a proxy function that calls the corresponding function in m_BoardSetting...
wxStaticBox * getOptionsBox()
KIFACE_I & Kiface()
Global KIFACE_I "get" accessor.
Definition: kicad.cpp:51
void onSelectAllClick(wxCommandEvent &event)
PCB_BASE_FRAME * m_frame
Pointer to the currently used edit frame.
Board plot function definition file.
PCB_LAYER_ID
A quick note on layer IDs:
Class LSET is a set of PCB_LAYER_IDs.
bool m_mirror
Print mirrored.
PCB_BASE_EDIT_FRAME * m_parent
DIALOG_PRINT_PCBNEW(PCB_BASE_EDIT_FRAME *aParent, PCBNEW_PRINTOUT_SETTINGS *aSettings)
PRINTOUT_SETTINGS * m_settings
Class TOOL_EVENT.
Definition: tool_event.h:168
wxCheckListBox * m_listTechLayers
void setListBoxValue(wxCheckListBox *aList, bool aValue)
(Un)checks all items in a checklist box
#define _(s)
virtual KIGFX::PCB_VIEW * GetView() const override
Function GetView() Returns a pointer to the VIEW instance used in the panel.
Class LSEQ is a sequence (and therefore also a set) of PCB_LAYER_IDs.
constexpr std::size_t arrayDim(T const (&)[N]) noexcept
Definition: macros.h:108
bool TransferDataToWindow() override
bool TransferDataToWindow() override
Common, abstract interface for edit frames.
Class BOARD holds information pertinent to a Pcbnew printed circuit board.
Definition: class_board.h:161
int m_pageCount
Number of pages to print.
Definition: printout.h:47
PCBNEW_PRINTOUT_SETTINGS * settings() const
size_t i
Definition: json11.cpp:597
const PAGE_INFO & GetPageSettings() const override
enum PCBNEW_PRINTOUT_SETTINGS::PAGINATION_T m_pagination
Pagination.
bool IsCopperLayer(LAYER_NUM aLayerId)
Function IsCopperLayer tests whether a layer is a copper layer.
enum PCBNEW_PRINTOUT_SETTINGS::DRILL_MARK_SHAPE_T m_drillMarks
Drill marks shape.
wxGridBagSizer * getOptionsSizer()
BOARD * GetBoard() const
LSEQ UIOrder() const
Definition: lset.cpp:803
int Print(const TOOL_EVENT &aEvent)
LSET m_layerSet
Layers to print.