KiCad PCB EDA Suite
sel_layer.cpp
Go to the documentation of this file.
1 
5 /*
6  * This program source code file is part of KiCad, a free EDA CAD application.
7  *
8  * Copyright (C) 2013 Jean-Pierre Charras, jp.charras at wanadoo.fr
9  * Copyright (C) 1992-2021 KiCad Developers, see AUTHORS.txt for contributors.
10  *
11  * This program is free software: you can redistribute it and/or modify it
12  * under the terms of the GNU General Public License as published by the
13  * Free Software Foundation, either version 3 of the License, or (at your
14  * option) any later version.
15  *
16  * This program is distributed in the hope that it will be useful, but
17  * WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19  * General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License along
22  * with this program. If not, see <http://www.gnu.org/licenses/>.
23  */
24 
25 
26 #include <confirm.h>
27 #include <pcb_base_frame.h>
29 #include <board.h>
31 #include <router/router_tool.h>
33 
34 
35 // Column position by function:
36 #define SELECT_COLNUM 0
37 #define COLOR_COLNUM 1
38 #define LAYERNAME_COLNUM 2
39 
40 
41 /*
42  * Display a layer list using a wxGrid.
43  */
45 {
46 public:
49  {
50  m_frame = aFrame;
51  }
52 
53 protected:
55 
57  bool isLayerEnabled( LAYER_NUM aLayer ) const override
58  {
59  return m_frame->GetBoard()->IsLayerEnabled( PCB_LAYER_ID( aLayer ) );
60  }
61 
62  // Return the color index from the layer ID.
63  COLOR4D getLayerColor( LAYER_NUM aLayer ) const override
64  {
65  return m_frame->GetColorSettings()->GetColor( aLayer );
66  }
67 
68  // Return the name of the layer ID.
69  wxString getLayerName( LAYER_NUM aLayer ) const override
70  {
71  return m_frame->GetBoard()->GetLayerName( ToLAYER_ID( aLayer ) );
72  }
73 };
74 
75 
80 {
81 public:
82  PCB_ONE_LAYER_SELECTOR( PCB_BASE_FRAME* aParent, BOARD * aBrd, PCB_LAYER_ID aDefaultLayer,
83  LSET aNotAllowedLayersMask, bool aHideCheckBoxes = false );
85 
87 
88 private:
89  // Event handlers
90  void OnLeftGridCellClick( wxGridEvent& aEvent ) override;
91  void OnRightGridCellClick( wxGridEvent& aEvent ) override;
92  void OnMouseMove( wxUpdateUIEvent& aEvent ) override;
93 
94  // Will close the dialog on ESC key
95  void onCharHook( wxKeyEvent& event );
96 
97  void buildList();
98 
102  std::vector<PCB_LAYER_ID> m_layersIdLeftColumn;
103  std::vector<PCB_LAYER_ID> m_layersIdRightColumn;
104 };
105 
106 
108  PCB_LAYER_ID aDefaultLayer,
109  LSET aNotAllowedLayersMask,
110  bool aHideCheckBoxes ) :
111  PCB_LAYER_SELECTOR( aParent ),
112  DIALOG_LAYER_SELECTION_BASE( aParent )
113 {
114  m_useCalculatedSize = true;
115 
116  m_layerSelected = aDefaultLayer;
117  m_notAllowedLayersMask = aNotAllowedLayersMask;
118  m_brd = aBrd;
119 
120  m_leftGridLayers->SetCellHighlightPenWidth( 0 );
121  m_rightGridLayers->SetCellHighlightPenWidth( 0 );
122  m_leftGridLayers->SetColFormatBool( SELECT_COLNUM );
123  m_rightGridLayers->SetColFormatBool( SELECT_COLNUM );
124  buildList();
125 
126  if( aHideCheckBoxes )
127  {
128  m_leftGridLayers->HideCol( SELECT_COLNUM );
129  m_rightGridLayers->HideCol( SELECT_COLNUM );
130  }
131 
132  Connect( wxEVT_CHAR_HOOK, wxKeyEventHandler( PCB_ONE_LAYER_SELECTOR::onCharHook ) );
133 
134  Layout();
135  GetSizer()->SetSizeHints( this );
136  SetFocus();
137 }
138 
139 
141 {
142  Disconnect( wxEVT_CHAR_HOOK, wxKeyEventHandler( PCB_ONE_LAYER_SELECTOR::onCharHook ) );
143 }
144 
145 
146 void PCB_ONE_LAYER_SELECTOR::OnMouseMove( wxUpdateUIEvent& aEvent )
147 {
151 
152  wxPoint mouse_pos = wxGetMousePosition();
153  wxPoint left_pos = m_leftGridLayers->ScreenToClient( mouse_pos );
154  wxPoint right_pos = m_rightGridLayers->ScreenToClient( mouse_pos );
155 
156  if( m_leftGridLayers->HitTest( left_pos ) == wxHT_WINDOW_INSIDE )
157  {
158  int row = m_leftGridLayers->YToRow( left_pos.y );
159 
160  if( row != wxNOT_FOUND && row < static_cast<int>( m_layersIdLeftColumn.size() ) )
161  {
163  m_leftGridLayers->SelectBlock( row, LAYERNAME_COLNUM, row, LAYERNAME_COLNUM);
164  return;
165  }
166  }
167 
168  if( m_rightGridLayers->HitTest( right_pos ) == wxHT_WINDOW_INSIDE )
169  {
170  int row = m_rightGridLayers->YToRow( right_pos.y );
171 
172  if( row == wxNOT_FOUND || row >= static_cast<int>( m_layersIdRightColumn.size() ) )
173  return;
174 
176  m_rightGridLayers->SelectBlock( row, LAYERNAME_COLNUM, row, LAYERNAME_COLNUM);
177  }
178 }
179 
180 
181 void PCB_ONE_LAYER_SELECTOR::onCharHook( wxKeyEvent& event )
182 {
183  if( event.GetKeyCode() == WXK_ESCAPE )
184  Close();
185 }
186 
187 
189 {
190  wxColour bg = getLayerColor( LAYER_PCB_BACKGROUND ).ToColour();
191  int left_row = 0;
192  int right_row = 0;
193  wxString layername;
194 
195  for( LSEQ ui_seq = m_brd->GetEnabledLayers().UIOrder(); ui_seq; ++ui_seq )
196  {
197  PCB_LAYER_ID layerid = *ui_seq;
198 
199  if( m_notAllowedLayersMask[layerid] )
200  continue;
201 
202  wxColour fg = getLayerColor( layerid ).ToColour();
203  wxColour color( wxColour::AlphaBlend( fg.Red(), bg.Red(), fg.Alpha() / 255.0 ),
204  wxColour::AlphaBlend( fg.Green(), bg.Green(), fg.Alpha() / 255.0 ),
205  wxColour::AlphaBlend( fg.Blue(), bg.Blue(), fg.Alpha() / 255.0 ) );
206 
207  layername = wxT( " " ) + getLayerName( layerid );
208 
209  if( IsCopperLayer( layerid ) )
210  {
211  if( left_row )
212  m_leftGridLayers->AppendRows( 1 );
213 
214  m_leftGridLayers->SetCellBackgroundColour ( left_row, COLOR_COLNUM, color );
215  m_leftGridLayers->SetCellValue( left_row, LAYERNAME_COLNUM, layername );
216 
217  if( m_layerSelected == layerid )
218  m_leftGridLayers->SetCellValue( left_row, SELECT_COLNUM, "1" );
219 
220  m_layersIdLeftColumn.push_back( layerid );
221  left_row++;
222  }
223  else
224  {
225  if( right_row )
226  m_rightGridLayers->AppendRows( 1 );
227 
228  m_rightGridLayers->SetCellBackgroundColour( right_row, COLOR_COLNUM, color );
229  m_rightGridLayers->SetCellValue( right_row, LAYERNAME_COLNUM, layername );
230 
231  if( m_layerSelected == layerid )
232  m_rightGridLayers->SetCellValue( right_row, SELECT_COLNUM, "1" );
233 
234  m_layersIdRightColumn.push_back( layerid );
235  right_row++;
236  }
237  }
238 
239  // Show only populated lists:
240  if( left_row <= 0 )
241  m_leftGridLayers->Show( false );
242 
243  if( right_row <= 0 )
244  m_rightGridLayers->Show( false );
245 
246  // Now fix min grid column size (it also sets a minimal size)
247  m_leftGridLayers->AutoSizeColumns();
248  m_rightGridLayers->AutoSizeColumns();
249 }
250 
251 
253 {
254  m_layerSelected = m_layersIdLeftColumn[ event.GetRow() ];
255 
256  if( IsQuasiModal() )
257  EndQuasiModal( 1 );
258  else
259  EndDialog( 1 );
260 }
261 
262 
264 {
265  m_layerSelected = m_layersIdRightColumn[ event.GetRow() ];
266 
267  if( IsQuasiModal() )
268  EndQuasiModal( 2 );
269  else
270  EndDialog( 2 );
271 }
272 
273 
274 PCB_LAYER_ID PCB_BASE_FRAME::SelectOneLayer( PCB_LAYER_ID aDefaultLayer, LSET aNotAllowedLayersMask,
275  wxPoint aDlgPosition )
276 {
277  PCB_ONE_LAYER_SELECTOR dlg( this, GetBoard(), aDefaultLayer, aNotAllowedLayersMask, true );
278 
279  if( aDlgPosition != wxDefaultPosition )
280  {
281  wxSize dlgSize = dlg.GetSize();
282  aDlgPosition.x -= dlgSize.x/2;
283  aDlgPosition.y -= dlgSize.y/2;
284  dlg.SetPosition( aDlgPosition );
285  }
286 
287  if( dlg.ShowModal() != wxID_CANCEL )
288  return ToLAYER_ID( dlg.GetLayerSelection() );
289  else
290  return UNDEFINED_LAYER;
291 }
292 
293 
299 {
300 public:
302  PCB_LAYER_ID aFrontLayer, PCB_LAYER_ID aBackLayer );
303 
304  void GetLayerPair( PCB_LAYER_ID& aFrontLayer, PCB_LAYER_ID& aBackLayer )
305  {
306  aFrontLayer = m_frontLayer;
307  aBackLayer = m_backLayer;
308  }
309 
310 private:
311  void OnLeftGridCellClick( wxGridEvent& event ) override;
312  void OnRightGridCellClick( wxGridEvent& event ) override;
313 
314  void buildList();
315 
321 
322  std::vector<PCB_LAYER_ID> m_layersId;
323 };
324 
325 
327 {
328  PCB_SCREEN* screen = frame()->GetScreen();
329 
331  screen->m_Route_Layer_BOTTOM );
332 
333  if( dlg.ShowModal() == wxID_OK )
334  {
335  dlg.GetLayerPair( screen->m_Route_Layer_TOP, screen->m_Route_Layer_BOTTOM );
336 
337  // select the same layer for both layers is allowed (normal in some boards)
338  // but could be a mistake. So display an info message
339  if( screen->m_Route_Layer_TOP == screen->m_Route_Layer_BOTTOM )
340  DisplayInfoMessage( frame(), _( "Warning: top and bottom layers are same." ) );
341  }
342 
343  return 0;
344 }
345 
346 
348  PCB_BASE_FRAME* aParent, BOARD * aPcb, PCB_LAYER_ID aFrontLayer, PCB_LAYER_ID aBackLayer) :
349  PCB_LAYER_SELECTOR( aParent ),
351 {
352  m_frontLayer = aFrontLayer;
353  m_backLayer = aBackLayer;
354  m_leftRowSelected = 0;
355  m_rightRowSelected = 0;
356  m_brd = aPcb;
357 
358  m_leftGridLayers->SetCellHighlightPenWidth( 0 );
359  m_rightGridLayers->SetCellHighlightPenWidth( 0 );
360  m_leftGridLayers->SetColFormatBool( SELECT_COLNUM );
361  m_rightGridLayers->SetColFormatBool( SELECT_COLNUM );
362  buildList();
363 
364  SetFocus();
365 
366  GetSizer()->SetSizeHints( this );
367  Center();
368 }
369 
370 
372 {
373  wxColour bg = getLayerColor( LAYER_PCB_BACKGROUND ).ToColour();
374  int row = 0;
375  wxString layername;
376 
377  for( LSEQ ui_seq = m_brd->GetEnabledLayers().UIOrder(); ui_seq; ++ui_seq )
378  {
379  PCB_LAYER_ID layerid = *ui_seq;
380 
381  if( !IsCopperLayer( layerid ) )
382  continue;
383 
384  wxColour fg = getLayerColor( layerid ).ToColour();
385  wxColour color( wxColour::AlphaBlend( fg.Red(), bg.Red(), fg.Alpha() / 255.0 ),
386  wxColour::AlphaBlend( fg.Green(), bg.Green(), fg.Alpha() / 255.0 ),
387  wxColour::AlphaBlend( fg.Blue(), bg.Blue(), fg.Alpha() / 255.0 ) );
388 
389  layername = wxT( " " ) + getLayerName( layerid );
390 
391  if( row )
392  m_leftGridLayers->AppendRows( 1 );
393 
394  m_leftGridLayers->SetCellBackgroundColour( row, COLOR_COLNUM, color );
395  m_leftGridLayers->SetCellValue( row, LAYERNAME_COLNUM, layername );
396  m_layersId.push_back( layerid );
397 
398  if( m_frontLayer == layerid )
399  {
400  m_leftGridLayers->SetCellValue( row, SELECT_COLNUM, "1" );
401  m_leftGridLayers->SetGridCursor( row, COLOR_COLNUM );
402  m_leftRowSelected = row;
403  }
404 
405  if( row )
406  m_rightGridLayers->AppendRows( 1 );
407 
408  m_rightGridLayers->SetCellBackgroundColour( row, COLOR_COLNUM, color );
409  m_rightGridLayers->SetCellValue( row, LAYERNAME_COLNUM, layername );
410 
411  if( m_backLayer == layerid )
412  {
413  m_rightGridLayers->SetCellValue( row, SELECT_COLNUM, "1" );
414  m_rightRowSelected = row;
415  }
416 
417  row++;
418  }
419 
420  // Now fix min grid layer name column size (it also sets a minimal size)
421  m_leftGridLayers->AutoSizeColumn( LAYERNAME_COLNUM );
422  m_rightGridLayers->AutoSizeColumn( LAYERNAME_COLNUM );
423 }
424 
425 
427 {
428  int row = event.GetRow();
429  PCB_LAYER_ID layer = m_layersId[row];
430 
431  if( m_frontLayer == layer )
432  return;
433 
434  m_leftGridLayers->SetCellValue( m_leftRowSelected, SELECT_COLNUM, wxEmptyString );
435  m_frontLayer = layer;
436  m_leftRowSelected = row;
437  m_leftGridLayers->SetCellValue( m_leftRowSelected, SELECT_COLNUM, "1" );
438 }
439 
440 
442 {
443  int row = event.GetRow();
444  PCB_LAYER_ID layer = m_layersId[row];
445 
446  if( m_backLayer == layer )
447  return;
448 
449  m_rightGridLayers->SetCellValue( m_rightRowSelected, SELECT_COLNUM, wxEmptyString );
450  m_backLayer = layer;
451  m_rightRowSelected = row;
452  m_rightGridLayers->SetCellValue( m_rightRowSelected, SELECT_COLNUM, "1" );
453 }
PCB_LAYER_ID SelectOneLayer(PCB_LAYER_ID aDefaultLayer, LSET aNotAllowedLayersMask=LSET(), wxPoint aDlgPosition=wxDefaultPosition)
Show the dialog box for a layer selection.
Definition: sel_layer.cpp:274
Class DIALOG_LAYER_SELECTION_BASE.
const wxString GetLayerName(PCB_LAYER_ID aLayer) const
Return the name of a aLayer.
Definition: board.cpp:362
SELECT_COPPER_LAYERS_PAIR_DIALOG(PCB_BASE_FRAME *aParent, BOARD *aPcb, PCB_LAYER_ID aFrontLayer, PCB_LAYER_ID aBackLayer)
Definition: sel_layer.cpp:347
void OnRightGridCellClick(wxGridEvent &aEvent) override
Definition: sel_layer.cpp:263
PCB_BASE_FRAME * m_frame
Definition: sel_layer.cpp:54
This file is part of the common library.
#define SELECT_COLNUM
Definition: sel_layer.cpp:36
COLOR4D getLayerColor(LAYER_NUM aLayer) const override
Definition: sel_layer.cpp:63
int color
Definition: DXF_plotter.cpp:57
bool IsQuasiModal() const
Definition: dialog_shim.h:106
int LAYER_NUM
This can be replaced with int and removed.
Definition: layer_ids.h:41
wxString getLayerName(LAYER_NUM aLayer) const override
Definition: sel_layer.cpp:69
LSET GetEnabledLayers() const
A proxy function that calls the corresponding function in m_BoardSettings.
Definition: board.cpp:467
void OnLeftGridCellClick(wxGridEvent &event) override
Definition: sel_layer.cpp:426
bool IsLayerEnabled(PCB_LAYER_ID aLayer) const
A proxy function that calls the correspondent function in m_BoardSettings tests whether a given layer...
Definition: board.cpp:493
std::vector< PCB_LAYER_ID > m_layersId
Definition: sel_layer.cpp:322
Classes used in Pcbnew, CvPcb and GerbView.
PCB_BASE_EDIT_FRAME * frame() const
virtual COLOR_SETTINGS * GetColorSettings() const override
Helper to retrieve the current color settings.
void GetLayerPair(PCB_LAYER_ID &aFrontLayer, PCB_LAYER_ID &aBackLayer)
Definition: sel_layer.cpp:304
LSET is a set of PCB_LAYER_IDs.
Definition: layer_ids.h:504
void onCharHook(wxKeyEvent &event)
Definition: sel_layer.cpp:181
std::vector< PCB_LAYER_ID > m_layersIdRightColumn
Definition: sel_layer.cpp:103
void SetPosition(const wxPoint &aNewPosition)
Force the position of the dialog to a new position.
Generic, UI-independent tool event.
Definition: tool_event.h:152
Base class to build a layer list.
LAYER_NUM GetLayerSelection()
Definition: sel_layer.cpp:86
PCB_LAYER_ID m_Route_Layer_BOTTOM
Definition: pcb_screen.h:44
std::vector< PCB_LAYER_ID > m_layersIdLeftColumn
Definition: sel_layer.cpp:102
#define _(s)
LSEQ is a sequence (and therefore also a set) of PCB_LAYER_IDs.
Definition: layer_ids.h:465
bool IsCopperLayer(LAYER_NUM aLayerId)
Tests whether a layer is a copper layer.
Definition: layer_ids.h:796
BOARD * GetBoard()
#define COLOR_COLNUM
Definition: sel_layer.cpp:37
void EndQuasiModal(int retCode)
COLOR4D GetColor(int aLayer) const
PCB_LAYER_ID m_layerSelected
Definition: sel_layer.cpp:99
PCB_LAYER_SELECTOR(PCB_BASE_FRAME *aFrame)
Definition: sel_layer.cpp:47
Display a PCB layers list in a dialog to select one layer from this list.
Definition: sel_layer.cpp:79
Information pertinent to a Pcbnew printed circuit board.
Definition: board.h:190
PCB_LAYER_ID
A quick note on layer IDs:
Definition: layer_ids.h:65
PCB_SCREEN * GetScreen() const override
Return a pointer to a BASE_SCREEN or one of its derivatives.
PCB background color.
Definition: layer_ids.h:216
int SelectCopperLayerPair(const TOOL_EVENT &aEvent)
Definition: sel_layer.cpp:326
bool isLayerEnabled(LAYER_NUM aLayer) const override
Definition: sel_layer.cpp:57
#define LAYERNAME_COLNUM
Definition: sel_layer.cpp:38
BOARD * GetBoard() const
PCB_ONE_LAYER_SELECTOR(PCB_BASE_FRAME *aParent, BOARD *aBrd, PCB_LAYER_ID aDefaultLayer, LSET aNotAllowedLayersMask, bool aHideCheckBoxes=false)
Definition: sel_layer.cpp:107
Class DIALOG_COPPER_LAYER_PAIR_SELECTION_BASE.
void OnRightGridCellClick(wxGridEvent &event) override
Definition: sel_layer.cpp:441
void OnMouseMove(wxUpdateUIEvent &aEvent) override
Definition: sel_layer.cpp:146
LSEQ UIOrder() const
Definition: lset.cpp:895
void DisplayInfoMessage(wxWindow *aParent, const wxString &aMessage, const wxString &aExtraInfo)
Display an informational message box with aMessage.
Definition: confirm.cpp:307
bool m_useCalculatedSize
Definition: dialog_shim.h:203
PCB_LAYER_ID ToLAYER_ID(int aLayer)
Definition: lset.cpp:905
Base PCB main window class for Pcbnew, Gerbview, and CvPcb footprint viewer.
PCB_LAYER_ID m_Route_Layer_TOP
Definition: pcb_screen.h:43
Display a pair PCB copper layers list in a dialog to select a layer pair from these lists.
Definition: sel_layer.cpp:297
void OnLeftGridCellClick(wxGridEvent &aEvent) override
Definition: sel_layer.cpp:252
A color representation with 4 components: red, green, blue, alpha.
Definition: color4d.h:103