KiCad PCB EDA Suite
swap_layers.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) 2007-2014 Jean-Pierre Charras, jp.charras at wanadoo.fr
5  * Copyright (C) 1992-2012 KiCad Developers, see AUTHORS.txt for contributors.
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, you may find one here:
19  * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
20  * or you may search the http://www.gnu.org website for the version 2 license,
21  * or you may write to the Free Software Foundation, Inc.,
22  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
23  */
24 
30 #include <fctsys.h>
31 #include <class_drawpanel.h>
32 #include <wxPcbStruct.h>
33 #include <dialog_shim.h>
34 
35 #include <class_board.h>
36 #include <class_track.h>
37 #include <class_drawsegment.h>
38 
39 #include <pcbnew.h>
40 
41 #include <wx/statline.h>
42 
43 
44 #define NO_CHANGE PCB_LAYER_ID(-3)
45 
46 
51 };
52 
53 
55 {
56 public:
58  // ~SWAP_LAYERS_DIALOG() { };
59 
60 private:
62  wxBoxSizer* OuterBoxSizer;
63  wxBoxSizer* MainBoxSizer;
64  wxFlexGridSizer* FlexColumnBoxSizer;
65  wxStaticText* label;
66  wxButton* Button;
67  wxStaticText* text;
68  wxStaticLine* Line;
69  wxStdDialogButtonSizer* StdDialogButtonSizer;
70 
71  PCB_LAYER_ID* m_callers_nlayers; // DIM() is PCB_LAYER_ID_COUNT
73 
74  void Sel_Layer( wxCommandEvent& event );
75  void OnOkClick( wxCommandEvent& event );
76  void OnCancelClick( wxCommandEvent& event );
77 
78  DECLARE_EVENT_TABLE()
79 };
80 
81 
82 BEGIN_EVENT_TABLE( SWAP_LAYERS_DIALOG, wxDialog )
84  wxEVT_COMMAND_BUTTON_CLICKED, SWAP_LAYERS_DIALOG::Sel_Layer )
85 
86  EVT_BUTTON( wxID_OK, SWAP_LAYERS_DIALOG::OnOkClick )
87 
88  EVT_BUTTON( wxID_CANCEL, SWAP_LAYERS_DIALOG::OnCancelClick )
89 END_EVENT_TABLE()
90 
91 
93  DIALOG_SHIM( parent, -1, _( "Swap Layers:" ), wxPoint( -1, -1 ),
94  wxDefaultSize, wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER ),
95  m_callers_nlayers( aArray )
96 {
97  memset( layer_list, 0, sizeof( layer_list ) );
98 
99  BOARD* board = parent->GetBoard();
100 
101  OuterBoxSizer = NULL;
102  MainBoxSizer = NULL;
103  FlexColumnBoxSizer = NULL;
104  label = NULL;
105  Button = NULL;
106  text = NULL;
107  Line = NULL;
108  StdDialogButtonSizer = NULL;
109 
110  m_Parent = parent;
111 
112  int item_ID;
113  wxSize goodSize;
114 
115  /* Experimentation has shown that buttons in the Windows version can be
116  * 20 pixels wide and 20 pixels high, but that they need to be 26 pixels
117  * wide and 26 pixels high in the Linux version. (And although the
118  * dimensions of those buttons could be set to 26 pixels wide and 26
119  * pixels high in both of those versions, that would result in a dialog
120  * box which would be excessively high in the Windows version.)
121  */
122 #ifdef __WINDOWS__
123  int w = 20;
124  int h = 20;
125 #else
126  int w = 26;
127  int h = 26;
128 #endif
129 
130  /* As currently implemented, the dimensions of the buttons in the Mac
131  * version are also 26 pixels wide and 26 pixels high. If appropriate,
132  * the above code should be modified as required in the event that those
133  * buttons should be some other size in that version.
134  */
135 
136  OuterBoxSizer = new wxBoxSizer( wxVERTICAL );
137  SetSizer( OuterBoxSizer );
138 
139  MainBoxSizer = new wxBoxSizer( wxHORIZONTAL );
140  OuterBoxSizer->Add( MainBoxSizer, 1, wxGROW | wxLEFT | wxRIGHT | wxTOP, 5 );
141 
142  for( unsigned layer = 0; layer < DIM( layer_list ); ++layer )
143  {
144  // Provide a vertical line to separate the two FlexGrid sizers
145  if( layer == 32 )
146  {
147  Line = new wxStaticLine( this,
148  -1,
149  wxDefaultPosition,
150  wxDefaultSize,
151  wxLI_VERTICAL );
152  MainBoxSizer->Add( Line, 0, wxGROW | wxLEFT | wxRIGHT, 5 );
153  }
154 
155  // Provide a separate FlexGrid sizer for every sixteen sets of controls
156  if( layer % 16 == 0 )
157  {
158  /* Each layer has an associated static text string (to identify
159  * that layer), a button (for invoking a child dialog box to
160  * change which layer that the layer is mapped to), and a second
161  * static text string (to depict which layer that the layer has
162  * been mapped to). Each of those items are placed into the left
163  * hand column, middle column, and right hand column (respectively)
164  * of the Flexgrid sizer, and the color of the second text string
165  * is set to fuchsia or blue (to respectively indicate whether the
166  * layer has been swapped to another layer or is not being swapped
167  * at all). (Experimentation has shown that if a text control is
168  * used to depict which layer that each layer is mapped to (instead
169  * of a static text string), then those controls do not behave in
170  * a fully satisfactory manner in the Linux version. Even when the
171  * read-only attribute is specified for all of those controls, they
172  * can still be selected when the arrow keys or Tab key is used
173  * to step through all of the controls within the dialog box, and
174  * directives to set the foreground color of the text of each such
175  * control to blue (to indicate that the text is of a read-only
176  * nature) are disregarded.)
177  *
178  * Specify a FlexGrid sizer with sixteen rows and three columns.
179  */
180  FlexColumnBoxSizer = new wxFlexGridSizer( 16, 3, 0, 0 );
181 
182  // Specify that all of the rows can be expanded.
183  for( int jj = 0; jj < 16; jj++ )
184  {
185  FlexColumnBoxSizer->AddGrowableRow( jj );
186  }
187 
188  // Specify that (just) the right-hand column can be expanded.
189  FlexColumnBoxSizer->AddGrowableCol( 2 );
190 
191  MainBoxSizer->Add( FlexColumnBoxSizer, 1, wxGROW | wxTOP, 5 );
192  }
193 
194  /* Provide a text string to identify this layer (with trailing spaces
195  * within that string being purged).
196  */
197  label = new wxStaticText( this, wxID_STATIC, board->GetLayerName( ToLAYER_ID( layer ) ),
198  wxDefaultPosition, wxDefaultSize,
199  wxALIGN_RIGHT );
200 
201  FlexColumnBoxSizer->Add( label, 0,
202  wxALIGN_RIGHT | wxALIGN_CENTER_VERTICAL |
203  wxLEFT | wxBOTTOM,
204  5 );
205 
206  // Provide a button for this layer (which will invoke a child dialog box)
207  item_ID = ID_BUTTON_0 + layer;
208 
209  Button = new wxButton( this, item_ID, wxT( "..." ), wxDefaultPosition,
210  wxSize( w, h ), 0 );
211  FlexColumnBoxSizer->Add( Button, 0,
212  wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL |
213  wxLEFT | wxBOTTOM, 5 );
214 
215  /* Provide another text string to specify which layer that this layer
216  * is mapped to, set the initial text to "No Change" (to indicate that
217  * this layer is currently unmapped to any other layer), and set the
218  * foreground color of the text to blue (which also indicates that the
219  * layer is currently unmapped to any other layer).
220  */
221  item_ID = ID_TEXT_0 + layer;
222 
223  /* When the first of these text strings is being added, determine
224  * what size is necessary to to be able to display the longest
225  * string without truncation. Then use that size as the
226  * minimum size for all text strings. (If the minimum
227  * size is not this size, strings can be truncated after
228  * some other layer is selected.)
229  */
230  if( layer == 0 )
231  {
232  text = new wxStaticText( this, item_ID, board->GetLayerName( PCB_LAYER_ID( 0 ) ),
233  wxDefaultPosition, wxDefaultSize, 0 );
234  goodSize = text->GetSize();
235 
236  for( unsigned jj = 1; jj < DIM( layer_list ); ++jj )
237  {
238  text->SetLabel( board->GetLayerName( ToLAYER_ID( jj ) ) );
239 
240  if( goodSize.x < text->GetSize().x )
241  goodSize.x = text->GetSize().x;
242  }
243 
244  text->SetLabel( _( "No Change" ) );
245 
246  if( goodSize.x < text->GetSize().x )
247  goodSize.x = text->GetSize().x;
248  }
249  else
250  {
251  text = new wxStaticText( this, item_ID, _( "No Change" ),
252  wxDefaultPosition, wxDefaultSize, 0 );
253  }
254 
255  text->SetMinSize( goodSize );
256  FlexColumnBoxSizer->Add( text, 1,
257  wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL |
258  wxLEFT | wxRIGHT | wxBOTTOM, 5 );
259  layer_list[layer] = text;
260  }
261 
262  /* Provide spacers to occupy otherwise blank cells within the second
263  * FlexGrid sizer. (Becuse there are three columns, three spacers
264  * are thus required for each unused row.)
265  for( int ii = 3 * NB_PCB_LAYERS; ii < 96; ii++ )
266  {
267  FlexColumnBoxSizer->Add( 5, h, 0, wxALIGN_CENTER_HORIZONTAL |
268  wxALIGN_CENTER_VERTICAL | wxLEFT |
269  wxRIGHT | wxBOTTOM, 5 );
270  }
271  */
272 
273  // Provide a line to separate the controls which have been provided so far
274  // from the OK and Cancel buttons (which will be provided after this line)
275  Line = new wxStaticLine( this, -1, wxDefaultPosition, wxDefaultSize, wxLI_HORIZONTAL );
276  OuterBoxSizer->Add( Line, 0, wxGROW | wxLEFT | wxRIGHT | wxTOP, 5 );
277 
278  // Provide a StdDialogButtonSizer to accommodate the OK and Cancel buttons;
279  // using that type of sizer results in those buttons being automatically
280  // located in positions appropriate for each (OS) version of KiCad.
281  StdDialogButtonSizer = new wxStdDialogButtonSizer;
282  OuterBoxSizer->Add( StdDialogButtonSizer, 0, wxGROW | wxALL, 10 );
283 
284  Button = new wxButton( this, wxID_OK, _( "&OK" ), wxDefaultPosition, wxDefaultSize, 0 );
285  Button->SetDefault();
286  StdDialogButtonSizer->AddButton( Button );
287 
288  Button = new wxButton( this, wxID_CANCEL, _( "&Cancel" ),
289  wxDefaultPosition, wxDefaultSize, 0 );
290  StdDialogButtonSizer->AddButton( Button );
291  StdDialogButtonSizer->Realize();
292 
293  // Resize the dialog
294  if( GetSizer() )
295  {
296  GetSizer()->SetSizeHints( this );
297  }
298 
299  Center();
300 }
301 
302 
303 void SWAP_LAYERS_DIALOG::Sel_Layer( wxCommandEvent& event )
304 {
305  int ii;
306 
307  ii = event.GetId();
308 
309  if( ii < ID_BUTTON_0 || ii >= ID_BUTTON_0 + PCB_LAYER_ID_COUNT )
310  return;
311 
312  ii = event.GetId() - ID_BUTTON_0;
313 
314  PCB_LAYER_ID layer = m_callers_nlayers[ii];
315 
316  LSET notallowed_mask = IsCopperLayer( ii ) ? LSET::AllNonCuMask() : LSET::AllCuMask();
317 
318  layer = m_Parent->SelectLayer( layer == NO_CHANGE ? ToLAYER_ID( ii ): layer, notallowed_mask );
319 
320  if( !IsValidLayer( layer ) )
321  return;
322 
323  if( layer != m_callers_nlayers[ii] )
324  {
325  m_callers_nlayers[ii] = layer;
326 
327  if( layer == NO_CHANGE || layer == ii )
328  {
329  layer_list[ii]->SetLabel( _( "No Change" ) );
330 
331  // Change the text color to blue (to highlight
332  // that this layer is *not* being swapped)
333  layer_list[ii]->SetForegroundColour( *wxBLUE );
334  }
335  else
336  {
337  layer_list[ii]->SetLabel( m_Parent->GetBoard()->GetLayerName( layer ) );
338 
339  // Change the text color to fuchsia (to highlight
340  // that this layer *is* being swapped)
341  layer_list[ii]->SetForegroundColour( wxColour( 255, 0, 128 ) );
342  }
343  }
344 }
345 
346 
347 void SWAP_LAYERS_DIALOG::OnCancelClick( wxCommandEvent& event )
348 {
349  EndModal( -1 );
350 }
351 
352 
353 void SWAP_LAYERS_DIALOG::OnOkClick( wxCommandEvent& event )
354 {
355  EndModal( 1 );
356 }
357 
358 
359 void PCB_EDIT_FRAME::Swap_Layers( wxCommandEvent& event )
360 {
361  PCB_LAYER_ID new_layer[PCB_LAYER_ID_COUNT];
362 
363  for( unsigned i = 0; i < DIM( new_layer ); ++i )
364  new_layer[i] = NO_CHANGE;
365 
366  SWAP_LAYERS_DIALOG dlg( this, new_layer );
367 
368  if( dlg.ShowModal() != 1 )
369  return; // (Canceled dialog box returns -1 instead)
370 
371  // Change traces.
372  for( TRACK* segm = GetBoard()->m_Track; segm; segm = segm->Next() )
373  {
374  OnModify();
375 
376  if( segm->Type() == PCB_VIA_T )
377  {
378  VIA* via = (VIA*) segm;
379 
380  if( via->GetViaType() == VIA_THROUGH )
381  continue;
382 
383  PCB_LAYER_ID top_layer, bottom_layer;
384 
385  via->LayerPair( &top_layer, &bottom_layer );
386 
387  if( new_layer[bottom_layer] != NO_CHANGE )
388  bottom_layer = new_layer[bottom_layer];
389 
390  if( new_layer[top_layer] != NO_CHANGE )
391  top_layer = new_layer[top_layer];
392 
393  via->SetLayerPair( top_layer, bottom_layer );
394  }
395  else
396  {
397  int jj = segm->GetLayer();
398 
399  if( new_layer[jj] != NO_CHANGE )
400  segm->SetLayer( new_layer[jj] );
401  }
402  }
403 
404  // Change zones.
405  for( TRACK* segm = GetBoard()->m_Zone; segm; segm = segm->Next() )
406  {
407  OnModify();
408  int jj = segm->GetLayer();
409 
410  if( new_layer[jj] != NO_CHANGE )
411  segm->SetLayer( new_layer[jj] );
412  }
413 
414  // Change other segments.
415  for( auto item : GetBoard()->Drawings() )
416  {
417  if( item->Type() == PCB_LINE_T )
418  {
419  OnModify();
420 
421  DRAWSEGMENT* drawsegm = (DRAWSEGMENT*) item;
422  int jj = drawsegm->GetLayer();
423 
424  if( new_layer[jj] != NO_CHANGE )
425  drawsegm->SetLayer( new_layer[jj] );
426  }
427  }
428 
429  m_canvas->Refresh( true );
430 }
static LSET AllCuMask(int aCuLayerCount=MAX_CU_LAYERS)
Function AllCuMask returns a mask holding the requested number of Cu PCB_LAYER_IDs.
Definition: lset.cpp:639
#define DIM(x)
of elements in an array
Definition: macros.h:98
wxStaticText * layer_list[PCB_LAYER_ID_COUNT]
Definition: swap_layers.cpp:72
virtual void OnModify() override
Function OnModify must be called after a board change to set the modified flag.
Definition: pcbframe.cpp:994
SWAP_LAYERS_DIALOG(PCB_BASE_FRAME *parent, PCB_LAYER_ID *aArray)
wxFlexGridSizer * FlexColumnBoxSizer
Definition: swap_layers.cpp:64
virtual void Refresh(bool eraseBackground=true, const wxRect *rect=NULL) override
Definition: draw_panel.cpp:326
virtual void SetLayer(PCB_LAYER_ID aLayer)
Function SetLayer sets the layer this item is on.
#define NO_CHANGE
Definition: swap_layers.cpp:44
Class BOARD to handle a board.
void OnCancelClick(wxCommandEvent &event)
static LSET AllNonCuMask()
Function AllNonCuMask returns a mask holding all layer minus CU layers.
Definition: lset.cpp:662
BOARD * GetBoard() const
swap_layer_id
Definition: swap_layers.cpp:47
Class DIALOG_SHIM may sit in the inheritance tree between wxDialog and any class written by wxFormBui...
Definition: dialog_shim.h:60
void Swap_Layers(wxCommandEvent &event)
wxStaticText * label
Definition: swap_layers.cpp:65
void Sel_Layer(wxCommandEvent &event)
Functions relatives to tracks, vias and segments used to fill zones.
BOARD_ITEM * Next() const
bool IsValidLayer(LAYER_NUM aLayerId)
Function IsValidLayer tests whether a given integer is a valid layer index, i.e.
PCB_LAYER_ID
A quick note on layer IDs:
Class LSET is a set of PCB_LAYER_IDs.
wxStaticText * text
Definition: swap_layers.cpp:67
VIATYPE_T GetViaType() const
Definition: class_track.h:439
const wxString GetLayerName(PCB_LAYER_ID aLayer) const
Function GetLayerName returns the name of a layer given by aLayer.
void SetLayerPair(PCB_LAYER_ID aTopLayer, PCB_LAYER_ID aBottomLayer)
Function SetLayerPair For a via m_Layer contains the top layer, the other layer is in m_BottomLayer...
void LayerPair(PCB_LAYER_ID *top_layer, PCB_LAYER_ID *bottom_layer) const
Function LayerPair Return the 2 layers used by the via (the via actually uses all layers between thes...
EVT_COMMAND_RANGE(ID_BUTTON_0, ID_BUTTON_0+PCB_LAYER_ID_COUNT-1, wxEVT_COMMAND_BUTTON_CLICKED, SWAP_LAYERS_DIALOG::Sel_Layer) SWAP_LAYERS_DIALOG
Definition: swap_layers.cpp:83
void OnOkClick(wxCommandEvent &event)
EDA_DRAW_PANEL * m_canvas
The area to draw on.
Definition: draw_frame.h:92
wxStdDialogButtonSizer * StdDialogButtonSizer
Definition: swap_layers.cpp:69
PCB_LAYER_ID GetLayer() const
Function GetLayer returns the primary layer this item is on.
TRACK * Next() const
Definition: class_track.h:98
PCB_LAYER_ID * m_callers_nlayers
Definition: swap_layers.cpp:71
Class to handle a graphic segment.
Class BOARD holds information pertinent to a Pcbnew printed circuit board.
Definition: class_board.h:169
wxBoxSizer * OuterBoxSizer
Definition: swap_layers.cpp:62
virtual BOARD * GetBoard() const
Function GetBoard returns the BOARD in which this BOARD_ITEM resides, or NULL if none.
bool IsCopperLayer(LAYER_NUM aLayerId)
Function IsCopperLayer tests whether a layer is a copper layer.
PCB_BASE_FRAME * m_Parent
Definition: swap_layers.cpp:61
class VIA, a via (like a track segment on a copper layer)
Definition: typeinfo.h:108
DLIST< TRACK > m_Track
Definition: class_board.h:246
class DRAWSEGMENT, a segment not on copper layers
Definition: typeinfo.h:103
wxStaticLine * Line
Definition: swap_layers.cpp:68
wxBoxSizer * MainBoxSizer
Definition: swap_layers.cpp:63
PCB_LAYER_ID SelectLayer(PCB_LAYER_ID aDefaultLayer, LSET aNotAllowedLayersMask=LSET(), wxPoint aDlgPosition=wxDefaultPosition)
Install the dialog box for layer selection.
Definition: sel_layer.cpp:221
PCB_LAYER_ID ToLAYER_ID(int aLayer)
Definition: lset.cpp:767
class PCB_BASE_FRAME basic PCB main window class for Pcbnew, Gerbview, and CvPcb footprint viewer...