KiCad PCB EDA Suite
appearance_controls.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) 2020 Jon Evans <jon@craftyjon.com>
5  * Copyright (C) 2020 KiCad Developers, see AUTHORS.txt for contributors.
6  *
7  * This program is free software: you can redistribute it and/or modify it
8  * under the terms of the GNU General Public License as published by the
9  * Free Software Foundation, either version 3 of the License, or (at your
10  * option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful, but
13  * WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15  * General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License along
18  * with this program. If not, see <http://www.gnu.org/licenses/>.
19  */
20 
22 
23 #include <bitmaps.h>
24 #include <class_board.h>
25 #include <dialog_helpers.h>
26 #include <footprint_edit_frame.h>
27 #include <menus_helpers.h>
28 #include <pcb_display_options.h>
29 #include <pcb_edit_frame.h>
30 #include <pcb_painter.h>
31 #include <pcbnew_settings.h>
33 #include <tool/tool_manager.h>
34 #include <tools/pcb_actions.h>
35 #include <widgets/bitmap_button.h>
36 #include <widgets/bitmap_toggle.h>
38 #include <widgets/color_swatch.h>
42 #include <widgets/indicator_icon.h>
43 #include <widgets/infobar.h>
44 #include <widgets/wx_grid.h>
45 #include <wx/hyperlink.h>
46 #include <wx/statline.h>
47 
48 
49 NET_GRID_TABLE::NET_GRID_TABLE( PCB_BASE_FRAME* aFrame, wxColor aBackgroundColor ) :
50  wxGridTableBase(),
51  m_frame( aFrame )
52 {
53  m_defaultAttr = new wxGridCellAttr;
54  m_defaultAttr->SetBackgroundColour( aBackgroundColor );
55 
56  m_labelAttr = new wxGridCellAttr;
57  m_labelAttr->SetRenderer( new GRID_CELL_ESCAPED_TEXT_RENDERER );
58  m_labelAttr->SetBackgroundColour( aBackgroundColor );
59 }
60 
61 
63 {
64  m_defaultAttr->DecRef();
65  m_labelAttr->DecRef();
66 }
67 
68 
69 wxGridCellAttr* NET_GRID_TABLE::GetAttr( int aRow, int aCol, wxGridCellAttr::wxAttrKind )
70 {
71  switch( aCol )
72  {
73  case COL_COLOR:
74  m_defaultAttr->IncRef();
75  return m_defaultAttr;
76 
77  case COL_VISIBILITY:
78  m_defaultAttr->IncRef();
79  return m_defaultAttr;
80 
81  case COL_LABEL:
82  m_labelAttr->IncRef();
83  return m_labelAttr;
84 
85  default:
86  wxFAIL;
87  return nullptr;
88  }
89 }
90 
91 
92 wxString NET_GRID_TABLE::GetValue( int aRow, int aCol )
93 {
94  wxASSERT( static_cast<size_t>( aRow ) < m_nets.size() );
95 
96  switch( aCol )
97  {
98  case COL_COLOR:
99  return m_nets[aRow].color.ToWxString( wxC2S_CSS_SYNTAX );
100 
101  case COL_VISIBILITY:
102  return m_nets[aRow].visible ? "1" : "0";
103 
104  case COL_LABEL:
105  return m_nets[aRow].name;
106 
107  default:
108  return wxEmptyString;
109  }
110 }
111 
112 
113 void NET_GRID_TABLE::SetValue( int aRow, int aCol, const wxString& aValue )
114 {
115  wxASSERT( static_cast<size_t>( aRow ) < m_nets.size() );
116 
117  NET_GRID_ENTRY& net = m_nets[aRow];
118 
119  switch( aCol )
120  {
121  case COL_COLOR:
122  net.color.SetFromWxString( aValue );
123  updateNetColor( net );
124  break;
125 
126  case COL_VISIBILITY:
127  net.visible = ( aValue != "0" );
128  updateNetVisibility( net );
129  break;
130 
131  case COL_LABEL:
132  net.name = aValue;
133  break;
134 
135  default:
136  break;
137  }
138 }
139 
140 
141 wxString NET_GRID_TABLE::GetTypeName( int aRow, int aCol )
142 {
143  switch( aCol )
144  {
145  case COL_COLOR:
146  return wxT( "COLOR4D" );
147 
148  case COL_VISIBILITY:
149  return wxGRID_VALUE_BOOL;
150 
151  case COL_LABEL:
152  default:
153  return wxGRID_VALUE_STRING;
154  }
155 }
156 
157 
158 bool NET_GRID_TABLE::GetValueAsBool( int aRow, int aCol )
159 {
160  wxASSERT( static_cast<size_t>( aRow ) < m_nets.size() );
161  wxASSERT( aCol == COL_VISIBILITY );
162 
163  return m_nets[aRow].visible;
164 }
165 
166 
167 void NET_GRID_TABLE::SetValueAsBool( int aRow, int aCol, bool aValue )
168 {
169  wxASSERT( static_cast<size_t>( aRow ) < m_nets.size() );
170  wxASSERT( aCol == COL_VISIBILITY );
171 
172  m_nets[aRow].visible = aValue;
173  updateNetVisibility( m_nets[aRow] );
174 }
175 
176 
177 void* NET_GRID_TABLE::GetValueAsCustom( int aRow, int aCol, const wxString& aTypeName )
178 {
179  wxASSERT( aCol == COL_COLOR );
180  wxASSERT( aTypeName == wxT( "COLOR4D" ) );
181  wxASSERT( static_cast<size_t>( aRow ) < m_nets.size() );
182 
183  return ColorToVoid( m_nets[aRow].color );
184 }
185 
186 
187 void NET_GRID_TABLE::SetValueAsCustom( int aRow, int aCol, const wxString& aTypeName, void* aValue )
188 {
189  wxASSERT( aCol == COL_COLOR );
190  wxASSERT( aTypeName == wxT( "COLOR4D" ) );
191  wxASSERT( static_cast<size_t>( aRow ) < m_nets.size() );
192 
193  m_nets[aRow].color = VoidToColor( aValue );
194  updateNetColor( m_nets[aRow] );
195 
196  if( GetView() )
197  {
198  wxGridTableMessage msg( this, wxGRIDTABLE_REQUEST_VIEW_GET_VALUES );
199  GetView()->ProcessTableMessage( msg );
200  }
201 }
202 
203 
205 {
206  wxASSERT( static_cast<size_t>( aRow ) < m_nets.size() );
207  return m_nets[aRow];
208 }
209 
210 
211 int NET_GRID_TABLE::GetRowByNetcode( int aCode ) const
212 {
213  auto it = std::find_if( m_nets.cbegin(), m_nets.cend(),
214  [aCode]( const NET_GRID_ENTRY& aEntry )
215  {
216  return aEntry.code == aCode;
217  } );
218 
219  if( it == m_nets.cend() )
220  return -1;
221 
222  return std::distance( m_nets.cbegin(), it );
223 }
224 
225 
227 {
228  BOARD* board = m_frame->GetBoard();
229  const NETNAMES_MAP& nets = board->GetNetInfo().NetsByName();
230 
231  KIGFX::PCB_RENDER_SETTINGS* rs = static_cast<KIGFX::PCB_RENDER_SETTINGS*>(
233 
234  std::set<int>& hiddenNets = rs->GetHiddenNets();
235  std::map<int, KIGFX::COLOR4D>& netColors = rs->GetNetColorMap();
236 
237  int deleted = m_nets.size();
238  m_nets.clear();
239 
240  if( GetView() )
241  {
242  wxGridTableMessage msg( this, wxGRIDTABLE_NOTIFY_ROWS_DELETED, 0, deleted );
243  GetView()->ProcessTableMessage( msg );
244  }
245 
246  for( const std::pair<const wxString, NETINFO_ITEM*>& pair : nets )
247  {
248  int netCode = pair.second->GetNet();
249 
250  if( netCode > 0 )
251  {
252  COLOR4D color = netColors.count( netCode ) ? netColors.at( netCode ) :
253  COLOR4D::UNSPECIFIED;
254 
255  bool visible = hiddenNets.count( netCode ) == 0;
256 
257  m_nets.emplace_back( NET_GRID_ENTRY( netCode, pair.first, color, visible ) );
258  }
259  }
260 
261  // TODO(JE) move to ::Compare so we can re-sort easily
262  std::sort( m_nets.begin(), m_nets.end(),
263  []( const NET_GRID_ENTRY& a, const NET_GRID_ENTRY& b )
264  {
265  return a.name < b.name;
266  } );
267 
268  if( GetView() )
269  {
270  wxGridTableMessage msg( this, wxGRIDTABLE_NOTIFY_ROWS_APPENDED, m_nets.size() );
271  GetView()->ProcessTableMessage( msg );
272  }
273 }
274 
275 
277 {
278  for( NET_GRID_ENTRY& net : m_nets )
279  {
280  net.visible = true;
281  updateNetVisibility( net );
282  }
283 
284  if( GetView() )
285  GetView()->ForceRefresh();
286 }
287 
288 
290 {
291  for( NET_GRID_ENTRY& net : m_nets )
292  {
293  net.visible = ( net.code == aNet.code );
294  updateNetVisibility( net );
295  }
296 
297  if( GetView() )
298  GetView()->ForceRefresh();
299 }
300 
301 
303 {
305  m_frame->GetToolManager()->RunAction( action, true, aNet.code );
306 }
307 
308 
310 {
311  KIGFX::PCB_RENDER_SETTINGS* rs = static_cast<KIGFX::PCB_RENDER_SETTINGS*>(
313 
314  std::map<int, KIGFX::COLOR4D>& netColors = rs->GetNetColorMap();
315 
316  if( aNet.color != COLOR4D::UNSPECIFIED )
317  netColors[aNet.code] = aNet.color;
318  else
319  netColors.erase( aNet.code );
320 
323  m_frame->GetCanvas()->Refresh();
324 }
325 
326 
329 
330 #define RR APPEARANCE_CONTROLS::APPEARANCE_SETTING // Render Row abbreviation to reduce source width
331 
332  // text id tooltip opacity slider
333  RR( _( "Tracks" ), LAYER_TRACKS, _( "Show tracks" ), true ),
334  RR( _( "Vias" ), LAYER_VIAS, _( "Show all vias" ), true ),
335  RR( _( "Pads" ), LAYER_PADS, _( "Show all pads" ), true ),
336  RR( _( "Zones" ), LAYER_ZONES, _( "Show copper zones" ), true ),
337  RR(),
338  RR( _( "Footprints Front" ), LAYER_MOD_FR, _( "Show footprints that are on board's front" ) ),
339  RR( _( "Footprints Back" ), LAYER_MOD_BK, _( "Show footprints that are on board's back" ) ),
340  RR( _( "Through-hole Pads" ),LAYER_PADS_TH, _( "Show through-hole pads" ) ),
341  RR( _( "Values" ), LAYER_MOD_VALUES, _( "Show footprint values" ) ),
342  RR( _( "References" ), LAYER_MOD_REFERENCES, _( "Show footprint references" ) ),
343  RR( _( "Footprint Text" ), LAYER_MOD_TEXT_FR, _( "Show all footprint text" ) ),
344  RR( _( "Hidden Text" ), LAYER_MOD_TEXT_INVISIBLE, _( "Show footprint text marked as invisible" ) ),
345  RR(),
346  RR(),
347  RR( _( "Ratsnest" ), LAYER_RATSNEST, _( "Show unconnected nets as a ratsnest") ),
348  RR( _( "No-Connects" ), LAYER_NO_CONNECTS, _( "Show a marker on pads which have no net connected" ) ),
349  RR( _( "DRC Warnings" ), LAYER_DRC_WARNING, _( "DRC violations with a Warning severity" ) ),
350  RR( _( "DRC Errors" ), LAYER_DRC_ERROR, _( "DRC violations with an Error severity" ) ),
351  RR( _( "DRC Exclusions" ), LAYER_DRC_EXCLUSION, _( "DRC violations which have been individually excluded" ) ),
352  RR( _( "Anchors" ), LAYER_ANCHOR, _( "Show footprint and text origins as a cross" ) ),
353  RR( _( "Worksheet" ), LAYER_WORKSHEET, _( "Show worksheet" ) ),
354  RR( _( "Grid" ), LAYER_GRID, _( "Show the (x,y) grid dots" ) )
355 };
356 
358 static std::set<int> s_allowedInFpEditor =
359  {
360  LAYER_TRACKS,
361  LAYER_VIAS,
362  LAYER_PADS,
363  LAYER_ZONES,
368  LAYER_GRID
369  };
370 
371 // These are the built-in layer presets that cannot be deleted
372 
374 
376 
377 LAYER_PRESET APPEARANCE_CONTROLS::presetAllCopper( _( "All Copper Layers" ),
378  LSET::AllCuMask().set( Edge_Cuts ) );
379 
380 LAYER_PRESET APPEARANCE_CONTROLS::presetInnerCopper( _( "Inner Copper Layers" ),
381  LSET::InternalCuMask().set( Edge_Cuts ) );
382 
384  LSET::FrontMask().set( Edge_Cuts ) );
385 
388 
390  LSET::BackMask().set( Edge_Cuts ) );
391 
394 
395 
397  bool aFpEditorMode ) :
398  APPEARANCE_CONTROLS_BASE( aParent ),
399  m_frame( aParent ),
400  m_focusOwner( aFocusOwner ),
401  m_board( nullptr ),
402  m_isFpEditor( aFpEditorMode ),
403  m_currentPreset( nullptr ),
404  m_lastSelectedUserPreset( nullptr ),
405  m_layerContextMenu( nullptr )
406 {
407  int indicatorSize = ConvertDialogToPixels( wxSize( 6, 6 ) ).x;
408  m_iconProvider = new ROW_ICON_PROVIDER( indicatorSize );
409  int pointSize = wxSystemSettings::GetFont( wxSYS_DEFAULT_GUI_FONT ).GetPointSize();
410  int screenHeight = wxSystemSettings::GetMetric( wxSYS_SCREEN_Y );
411 
412  m_layerPanelColour = m_panelLayers->GetBackgroundColour().ChangeLightness( 110 );
413 
414  m_layersOuterSizer = new wxBoxSizer( wxVERTICAL );
415  m_windowLayers->SetSizer( m_layersOuterSizer );
416  m_windowLayers->SetScrollRate( 0, 5 );
417  m_windowLayers->Bind( wxEVT_SET_FOCUS, &APPEARANCE_CONTROLS::OnSetFocus, this );
418 
419  m_objectsOuterSizer = new wxBoxSizer( wxVERTICAL );
421  m_windowObjects->SetScrollRate( 0, 5 );
422  m_windowObjects->Bind( wxEVT_SET_FOCUS, &APPEARANCE_CONTROLS::OnSetFocus, this );
423 
424  createControls();
425 
428 
431 
432  m_txtNetFilter->SetHint( _( "Filter nets" ) );
433 
434  if( screenHeight <= 900 && pointSize >= indicatorSize )
435  pointSize = pointSize * 8 / 10;
436 
437  m_pointSize = pointSize;
438  wxFont font = m_notebook->GetFont();
439 
440 #ifdef __WXMAC__
441  font.SetPointSize( m_pointSize );
442  m_notebook->SetFont( font );
443 #endif
444 
445  auto setHighContrastMode =
446  [&]( HIGH_CONTRAST_MODE aMode )
447  {
449  opts.m_ContrastModeDisplay = aMode;
450 
451  m_frame->SetDisplayOptions( opts );
452  passOnFocus();
453  };
454 
455  m_rbHighContrastNormal->Bind( wxEVT_RADIOBUTTON,
456  [=]( wxCommandEvent& aEvent )
457  {
458  setHighContrastMode( HIGH_CONTRAST_MODE::NORMAL );
459  } );
460 
461  m_rbHighContrastDim->Bind( wxEVT_RADIOBUTTON,
462  [=]( wxCommandEvent& aEvent )
463  {
464  setHighContrastMode( HIGH_CONTRAST_MODE::DIMMED );
465  } );
466 
467  m_rbHighContrastOff->Bind( wxEVT_RADIOBUTTON,
468  [=]( wxCommandEvent& aEvent )
469  {
470  setHighContrastMode( HIGH_CONTRAST_MODE::HIDDEN );
471  } );
472 
473  m_cbLayerPresets->Bind( wxEVT_CHOICE, &APPEARANCE_CONTROLS::onLayerPresetChanged, this );
474 
475  m_btnNetInspector->Bind( wxEVT_BUTTON,
476  [&]( wxCommandEvent& aEvent )
477  {
479  passOnFocus();
480  } );
481 
482  m_btnConfigureNetClasses->Bind( wxEVT_BUTTON,
483  [&]( wxCommandEvent& aEvent )
484  {
485  // This panel should only be visible in the PCB_EDIT_FRAME anyway
486  if( PCB_EDIT_FRAME* editframe = dynamic_cast<PCB_EDIT_FRAME*>( m_frame ) )
487  editframe->ShowBoardSetupDialog( _( "Net Classes" ) );
488 
489  passOnFocus();
490  } );
491 
492  m_cbFlipBoard->SetValue( m_frame->GetCanvas()->GetView()->IsMirroredX() );
493  m_cbFlipBoard->Bind( wxEVT_CHECKBOX,
494  [&]( wxCommandEvent& aEvent )
495  {
497  } );
498 
501 
502  m_netsGrid->RegisterDataType( wxT( "bool" ), m_toggleGridRenderer, new wxGridCellBoolEditor );
503 
504  // TODO(JE) Update background color of swatch renderer when theme changes
505  m_netsGrid->RegisterDataType( wxT( "COLOR4D" ),
508 
509  m_netsTable = new NET_GRID_TABLE( m_frame, m_panelNets->GetBackgroundColour() );
510  m_netsGrid->SetTable( m_netsTable, true );
512 
513  m_netsGrid->SetSelectionMode( wxGrid::wxGridSelectRows );
514  m_netsGrid->SetSelectionForeground( m_netsGrid->GetDefaultCellTextColour() );
515  m_netsGrid->SetSelectionBackground( m_panelNets->GetBackgroundColour() );
516 
517  const int cellPadding = 6;
518 #ifdef __WXMAC__
519  const int rowHeightPadding = 5;
520 #else
521  const int rowHeightPadding = 3;
522 #endif
523 
524  wxSize size = ConvertDialogToPixels( SWATCH_SIZE_SMALL_DU );
525  m_netsGrid->SetColSize( NET_GRID_TABLE::COL_COLOR, size.x + cellPadding );
526 
527  size = KiBitmap( visibility_xpm ).GetSize();
528  m_netsGrid->SetColSize( NET_GRID_TABLE::COL_VISIBILITY, size.x + cellPadding );
529 
530  m_netsGrid->SetDefaultCellFont( font );
531  m_netsGrid->SetDefaultRowSize( font.GetPixelSize().y + rowHeightPadding );
532 
533  m_netsGrid->GetGridWindow()->Bind( wxEVT_MOTION,
535 
536  // To handle middle click on color swatches
537  m_netsGrid->GetGridWindow()->Bind( wxEVT_MIDDLE_UP,
539 
540  m_netsGrid->ShowScrollbars( wxSHOW_SB_NEVER, wxSHOW_SB_DEFAULT );
541  m_netclassScrolledWindow->ShowScrollbars( wxSHOW_SB_NEVER, wxSHOW_SB_DEFAULT );
542 
543  if( m_isFpEditor )
544  m_notebook->RemovePage( 2 );
545 
547  rebuildObjects();
548  OnBoardChanged();
549 
550  Bind( wxEVT_COMMAND_MENU_SELECTED, &APPEARANCE_CONTROLS::OnLayerContextMenu, this,
552 }
553 
554 
556 {
557  delete m_iconProvider;
558 }
559 
560 
562 {
563  // Create layer display options
565  _( "Layer Display Options" ) );
567  m_paneLayerDisplayOptions->SetBackgroundColour( m_notebook->GetThemeBackgroundColour() );
568 
569  wxWindow* layerDisplayPane = m_paneLayerDisplayOptions->GetPane();
570 
571  wxBoxSizer* layerDisplayOptionsSizer;
572  layerDisplayOptionsSizer = new wxBoxSizer( wxVERTICAL );
573 
574  m_staticTextContrastModeTitle = new wxStaticText( layerDisplayPane, wxID_ANY,
575  _( "Non-active layers:" ), wxDefaultPosition,
576  wxDefaultSize, 0 );
577  m_staticTextContrastModeTitle->Wrap( -1 );
578  layerDisplayOptionsSizer->Add( m_staticTextContrastModeTitle, 0,
579  wxEXPAND | wxBOTTOM | wxLEFT, 2 );
580 
581  wxBoxSizer* contrastModeSizer;
582  contrastModeSizer = new wxBoxSizer( wxHORIZONTAL );
583 
584  m_rbHighContrastNormal = new wxRadioButton( layerDisplayPane, wxID_ANY, _( "Normal" ),
585  wxDefaultPosition, wxDefaultSize, wxRB_GROUP );
586  m_rbHighContrastNormal->SetValue( true );
587  m_rbHighContrastNormal->SetToolTip( _( "Non-active layers will be shown in full color" ) );
588 
589  contrastModeSizer->Add( m_rbHighContrastNormal, 0, wxRIGHT, 4 );
590 
591  m_rbHighContrastDim = new wxRadioButton( layerDisplayPane, wxID_ANY, _( "Dim" ),
592  wxDefaultPosition, wxDefaultSize, 0 );
593  m_rbHighContrastDim->SetToolTip( _( "Non-active layers will be dimmed" ) );
594 
595  contrastModeSizer->Add( m_rbHighContrastDim, 0, wxRIGHT | wxLEFT, 10 );
596 
597  m_rbHighContrastOff = new wxRadioButton( layerDisplayPane, wxID_ANY, _( "Hide" ),
598  wxDefaultPosition, wxDefaultSize, 0 );
599  m_rbHighContrastOff->SetToolTip( _( "Non-active layers will be hidden" ) );
600 
601  contrastModeSizer->Add( m_rbHighContrastOff, 0, 0, 5 );
602 
603  layerDisplayOptionsSizer->Add( contrastModeSizer, 0, wxEXPAND, 5 );
604 
605  m_layerDisplaySeparator = new wxStaticLine( layerDisplayPane, wxID_ANY, wxDefaultPosition,
606  wxDefaultSize, wxLI_HORIZONTAL );
607  layerDisplayOptionsSizer->Add( m_layerDisplaySeparator, 0, wxEXPAND | wxTOP | wxBOTTOM, 5 );
608 
609  m_cbFlipBoard = new wxCheckBox( layerDisplayPane, wxID_ANY, _( "Flip board view" ),
610  wxDefaultPosition, wxDefaultSize, 0 );
611  layerDisplayOptionsSizer->Add( m_cbFlipBoard, 0, 0, 5 );
612 
613  layerDisplayPane->SetSizer( layerDisplayOptionsSizer );
614  layerDisplayPane->Layout();
615  layerDisplayOptionsSizer->Fit( layerDisplayPane );
616 
617  m_panelLayersSizer->Add( m_paneLayerDisplayOptions, 0, wxEXPAND | wxTOP, 5 );
618 
619  m_paneLayerDisplayOptions->Bind( WX_COLLAPSIBLE_PANE_CHANGED,
620  [&]( wxCommandEvent& aEvent )
621  {
622  Freeze();
623  m_panelLayers->Fit();
624  m_sizerOuter->Layout();
625  Thaw();
626  } );
627 
628  // Create net display options
629 
631  _( "Net Display Options" ) );
633  m_paneNetDisplayOptions->SetBackgroundColour( m_notebook->GetThemeBackgroundColour() );
634 
635  wxWindow* netDisplayPane = m_paneNetDisplayOptions->GetPane();
636  wxBoxSizer* netDisplayOptionsSizer = new wxBoxSizer( wxVERTICAL );
637 
639 
640  m_txtNetDisplayTitle = new wxStaticText( netDisplayPane, wxID_ANY, _( "Net colors:" ),
641  wxDefaultPosition, wxDefaultSize, 0 );
642  m_txtNetDisplayTitle->Wrap( -1 );
643  m_txtNetDisplayTitle->SetToolTip( _( "Choose when to show net and netclass colors" ) );
644 
645  netDisplayOptionsSizer->Add( m_txtNetDisplayTitle, 0, wxEXPAND | wxBOTTOM | wxLEFT, 2 );
646 
647  wxBoxSizer* netColorSizer = new wxBoxSizer( wxHORIZONTAL );
648 
649  m_rbNetColorAll = new wxRadioButton( netDisplayPane, wxID_ANY, _( "All" ), wxDefaultPosition,
650  wxDefaultSize, wxRB_GROUP );
651  m_rbNetColorAll->SetToolTip( _( "Net and netclass colors are shown on all copper items" ) );
652 
653  netColorSizer->Add( m_rbNetColorAll, 0, wxRIGHT, 10 );
654 
655  m_rbNetColorRatsnest = new wxRadioButton( netDisplayPane, wxID_ANY, _( "Ratsnest" ),
656  wxDefaultPosition, wxDefaultSize, 0 );
657  m_rbNetColorRatsnest->SetValue( true );
658  m_rbNetColorRatsnest->SetToolTip( _( "Net and netclass colors are shown on the ratsnest only" ) );
659 
660  netColorSizer->Add( m_rbNetColorRatsnest, 0, wxRIGHT, 4 );
661 
662  m_rbNetColorOff = new wxRadioButton( netDisplayPane, wxID_ANY, _( "None" ), wxDefaultPosition,
663  wxDefaultSize, 0 );
664  m_rbNetColorOff->SetToolTip( _( "Net and netclass colors are not shown" ) );
665 
666  netColorSizer->Add( m_rbNetColorOff, 0, 0, 5 );
667 
668  netDisplayOptionsSizer->Add( netColorSizer, 0, wxEXPAND | wxBOTTOM, 5 );
669 
671 
672  m_txtRatsnestVisibility = new wxStaticText( netDisplayPane, wxID_ANY, _( "Ratsnest display:" ),
673  wxDefaultPosition, wxDefaultSize, 0 );
674  m_txtRatsnestVisibility->Wrap( -1 );
675  m_txtRatsnestVisibility->SetToolTip( _( "Choose what ratsnest lines to display" ) );
676 
677  netDisplayOptionsSizer->Add( m_txtRatsnestVisibility, 0, wxEXPAND | wxBOTTOM | wxLEFT, 2 );
678 
679  wxBoxSizer* ratsnestDisplayModeSizer = new wxBoxSizer( wxHORIZONTAL );
680 
681  m_rbRatsnestAllLayers = new wxRadioButton( netDisplayPane, wxID_ANY, _( "All layers" ),
682  wxDefaultPosition, wxDefaultSize, wxRB_GROUP );
683  m_rbRatsnestAllLayers->SetToolTip( _( "Ratsnest lines are shown to items on all layers" ) );
684  m_rbRatsnestAllLayers->SetValue( true );
685 
686  ratsnestDisplayModeSizer->Add( m_rbRatsnestAllLayers, 0, wxRIGHT, 10 );
687 
688  m_rbRatsnestVisibleLayers = new wxRadioButton( netDisplayPane, wxID_ANY, _( "Visible layers" ),
689  wxDefaultPosition, wxDefaultSize, 0 );
690  m_rbRatsnestVisibleLayers->SetToolTip( _( "Ratsnest lines are shown to items on visible layers" ) );
691 
692  ratsnestDisplayModeSizer->Add( m_rbRatsnestVisibleLayers, 0, wxRIGHT, 4 );
693 
694  netDisplayOptionsSizer->Add( ratsnestDisplayModeSizer, 0, wxEXPAND | wxBOTTOM, 5 );
695 
697 
698  netDisplayPane->SetSizer( netDisplayOptionsSizer );
699  netDisplayPane->Layout();
700  netDisplayOptionsSizer->Fit( netDisplayPane );
701 
702  m_netsTabOuterSizer->Add( m_paneNetDisplayOptions, 0, wxEXPAND | wxTOP, 5 );
703 
704  m_paneNetDisplayOptions->Bind( WX_COLLAPSIBLE_PANE_CHANGED,
705  [&]( wxCommandEvent& aEvent )
706  {
707  Freeze();
708  m_panelNetsAndClasses->Fit();
709  m_sizerOuter->Layout();
710  passOnFocus();
711  Thaw();
712  } );
713 
714  m_rbNetColorAll->Bind( wxEVT_RADIOBUTTON, &APPEARANCE_CONTROLS::onNetColorModeChanged, this );
715  m_rbNetColorOff->Bind( wxEVT_RADIOBUTTON, &APPEARANCE_CONTROLS::onNetColorModeChanged, this );
716  m_rbNetColorRatsnest->Bind( wxEVT_RADIOBUTTON,
718 
719  m_rbRatsnestAllLayers->Bind( wxEVT_RADIOBUTTON,
721  m_rbRatsnestVisibleLayers->Bind( wxEVT_RADIOBUTTON,
723 }
724 
725 
727 {
728  wxSize size( 220, 480 );
729  // TODO(JE) appropriate logic
730  return size;
731 }
732 
733 
734 void APPEARANCE_CONTROLS::OnNotebookPageChanged( wxNotebookEvent& aEvent )
735 {
736  // Work around wxMac issue where the notebook pages are blank
737 #ifdef __WXMAC__
738  int page = aEvent.GetSelection();
739 
740  if( page >= 0 )
741  m_notebook->ChangeSelection( static_cast<unsigned>( page ) );
742 #endif
743 
744 #ifndef __WXMSW__
745  // Because wxWidgets is broken and will send click events to children of the collapsible
746  // panes even if they are collapsed without this
747  Freeze();
748  m_panelLayers->Fit();
749  m_panelNetsAndClasses->Fit();
750  m_sizerOuter->Layout();
751  Thaw();
752 #endif
753 
754  Bind( wxEVT_IDLE, &APPEARANCE_CONTROLS::idleFocusHandler, this );
755 }
756 
757 
758 void APPEARANCE_CONTROLS::idleFocusHandler( wxIdleEvent& aEvent )
759 {
760  passOnFocus();
761  Unbind( wxEVT_IDLE, &APPEARANCE_CONTROLS::idleFocusHandler, this );
762 }
763 
764 
765 void APPEARANCE_CONTROLS::OnSetFocus( wxFocusEvent& aEvent )
766 {
767 #ifdef __WXMSW__
768  // In wxMSW, buttons won't process events unless they have focus, so we'll let it take the
769  // focus and give it back to the parent in the button event handler.
770  if( wxBitmapButton* btn = dynamic_cast<wxBitmapButton*>( aEvent.GetEventObject() ) )
771  {
772  wxCommandEvent evt( wxEVT_BUTTON );
773  wxPostEvent( btn, evt );
774  }
775 #endif
776 
777  passOnFocus();
778  aEvent.Skip();
779 }
780 
781 
782 void APPEARANCE_CONTROLS::OnSize( wxSizeEvent& aEvent )
783 {
784  aEvent.Skip();
785 }
786 
787 
788 void APPEARANCE_CONTROLS::OnNetGridClick( wxGridEvent& event )
789 {
790  int row = event.GetRow();
791  int col = event.GetCol();
792 
793  switch( col )
794  {
796  m_netsTable->SetValueAsBool( row, col, !m_netsTable->GetValueAsBool( row, col ) );
797  m_netsGrid->ForceRefresh();
798  break;
799 
800  default:
801  break;
802  }
803 }
804 
805 
807 {
808  int row = event.GetRow();
809  int col = event.GetCol();
810 
811  switch( col )
812  {
814  m_netsGrid->GetCellEditor( row, col )->BeginEdit( row, col, m_netsGrid );
815  break;
816 
817  default:
818  break;
819  }
820 }
821 
822 
824 {
825  m_netsGrid->SelectRow( event.GetRow() );
826 
827  wxString netName = m_netsGrid->GetCellValue( event.GetRow(), NET_GRID_TABLE::COL_LABEL );
828  wxMenu menu;
829 
830  menu.Append( new wxMenuItem( &menu, ID_SET_NET_COLOR,
831  _( "Set net color" ), wxEmptyString, wxITEM_NORMAL ) );
832  menu.Append( new wxMenuItem( &menu, ID_HIGHLIGHT_NET,
833  wxString::Format( _( "Highlight %s" ), netName ),
834  wxEmptyString, wxITEM_NORMAL ) );
835  menu.Append( new wxMenuItem( &menu, ID_SELECT_NET,
836  wxString::Format( _( "Select tracks and vias in %s" ), netName ),
837  wxEmptyString, wxITEM_NORMAL ) );
838  menu.Append( new wxMenuItem( &menu, ID_DESELECT_NET,
839  wxString::Format( _( "Deselect tracks and vias in %s" ), netName ),
840  wxEmptyString, wxITEM_NORMAL ) );
841 
842  menu.AppendSeparator();
843 
844  menu.Append( new wxMenuItem( &menu, ID_SHOW_ALL_NETS,
845  _( "Show all nets" ), wxEmptyString, wxITEM_NORMAL ) );
846  menu.Append( new wxMenuItem( &menu, ID_HIDE_OTHER_NETS,
847  _( "Hide all other nets" ), wxEmptyString,
848  wxITEM_NORMAL ) );
849 
850  menu.Bind( wxEVT_COMMAND_MENU_SELECTED,
852 
853  PopupMenu( &menu );
854 }
855 
856 
857 void APPEARANCE_CONTROLS::OnNetGridMouseEvent( wxMouseEvent& aEvent )
858 {
859  wxPoint pos = m_netsGrid->CalcUnscrolledPosition( aEvent.GetPosition() );
860  wxGridCellCoords cell = m_netsGrid->XYToCell( pos );
861 
862  if( aEvent.Moving() || aEvent.Entering() )
863  {
864  aEvent.Skip();
865 
866  if( !cell )
867  {
868  m_netsGrid->GetGridWindow()->UnsetToolTip();
869  return;
870  }
871 
872  if( cell == m_hoveredCell )
873  return;
874 
875  m_hoveredCell = cell;
876 
877  NET_GRID_ENTRY& net = m_netsTable->GetEntry( cell.GetRow() );
878 
879  wxString name = net.name;
880  wxString showOrHide = net.visible ? _( "Click to hide ratsnest for %s" )
881  : _( "Click to show ratsnest for %s" );
882  wxString tip;
883 
884  if( cell.GetCol() == NET_GRID_TABLE::COL_VISIBILITY )
885  tip.Printf( showOrHide, name );
886  else if( cell.GetCol() == NET_GRID_TABLE::COL_COLOR )
887  tip = _( "Left double click or middle click for color change, "
888  "right click for menu" );
889 
890  m_netsGrid->GetGridWindow()->SetToolTip( tip );
891  }
892  else if( aEvent.Leaving() )
893  {
894  m_netsGrid->UnsetToolTip();
895  aEvent.Skip();
896  }
897  else if( aEvent.Dragging() )
898  {
899  // not allowed
900  CallAfter( [&]()
901  {
902  m_netsGrid->ClearSelection();
903  } );
904  }
905  else if( aEvent.ButtonUp( wxMOUSE_BTN_MIDDLE ) && !!cell )
906  {
907  int row = cell.GetRow();
908  int col = cell.GetCol();
909 
910  if(col == NET_GRID_TABLE::COL_COLOR )
911  m_netsGrid->GetCellEditor( row, col )->BeginEdit( row, col, m_netsGrid );
912 
913  aEvent.Skip();
914  }
915  else
916  {
917  aEvent.Skip();
918  }
919 }
920 
921 
923 {
924  Freeze();
925  rebuildLayers();
929  rebuildNets();
932 
934 
935  m_board = m_frame->GetBoard();
936 
937  if( m_board )
938  m_board->AddListener( this );
939 
940  Thaw();
941  Refresh();
942 }
943 
944 
946 {
948 }
949 
950 
952 {
953  if( aBoardItem->Type() == PCB_NETINFO_T )
955 }
956 
957 
959 {
960  if( aBoardItem->Type() == PCB_NETINFO_T )
962 }
963 
964 
966 {
967  if( aBoardItem->Type() == PCB_NETINFO_T )
969 }
970 
971 
972 
974 {
975  Freeze();
976  rebuildNets();
977  Thaw();
978 }
979 
980 
982 {
985 }
986 
987 
989 {
990  for( const std::unique_ptr<APPEARANCE_SETTING>& setting : m_layerSettings )
991  {
992  setting->ctl_panel->SetBackgroundColour( m_layerPanelColour );
993  setting->ctl_indicator->SetIndicatorState( ROW_ICON_PROVIDER::STATE::OFF );
994  }
995 
996  wxChar r, g, b;
997 
998  r = m_layerPanelColour.Red();
999  g = m_layerPanelColour.Green();
1000  b = m_layerPanelColour.Blue();
1001 
1002  if( r < 240 || g < 240 || b < 240 )
1003  {
1004  r = wxChar( std::min( (int) r + 15, 255 ) );
1005  g = wxChar( std::min( (int) g + 15, 255 ) );
1006  b = wxChar( std::min( (int) b + 15, 255 ) );
1007  }
1008  else
1009  {
1010  r = wxChar( std::max( (int) r - 15, 0 ) );
1011  g = wxChar( std::max( (int) g - 15, 0 ) );
1012  b = wxChar( std::max( (int) b - 15, 0 ) );
1013  }
1014 
1015  PCB_LAYER_ID current = m_frame->GetActiveLayer();
1016  APPEARANCE_SETTING* newSetting = m_layerSettingsMap[ current ];
1017 
1018  newSetting->ctl_panel->SetBackgroundColour( wxColour( r, g, b ) );
1020 
1021  Refresh();
1022 }
1023 
1024 
1025 void APPEARANCE_CONTROLS::SetLayerVisible( LAYER_NUM aLayer, bool isVisible )
1026 {
1027  LSET visible = getVisibleLayers();
1028  PCB_LAYER_ID layer = ToLAYER_ID( aLayer );
1029 
1030  if( visible.test( layer ) == isVisible )
1031  return;
1032 
1033  visible.set( layer, isVisible );
1034  setVisibleLayers( visible );
1035 
1036  m_frame->GetCanvas()->GetView()->SetLayerVisible( layer, isVisible );
1037 
1039 }
1040 
1041 
1043 {
1044  if( m_objectSettingsMap.count( aLayer ) )
1045  {
1046  APPEARANCE_SETTING* setting = m_objectSettingsMap.at( aLayer );
1047  setting->ctl_visibility->SetValue( isVisible );
1048  }
1049 
1050  m_frame->GetCanvas()->GetView()->SetLayerVisible( aLayer, isVisible );
1051  m_frame->GetCanvas()->Refresh();
1052 }
1053 
1054 
1056 {
1057  if( m_isFpEditor )
1058  {
1059  KIGFX::VIEW* view = m_frame->GetCanvas()->GetView();
1060 
1061  for( PCB_LAYER_ID layer : LSET::AllLayersMask().Seq() )
1062  view->SetLayerVisible( layer, aLayers.Contains( layer ) );
1063  }
1064  else
1065  {
1066  m_frame->GetBoard()->SetVisibleLayers( aLayers );
1067  }
1068 }
1069 
1070 
1072 {
1073  if( m_isFpEditor )
1074  {
1075  KIGFX::VIEW* view = m_frame->GetCanvas()->GetView();
1076 
1077  for( size_t i = 0; i < aLayers.size(); i++ )
1078  view->SetLayerVisible( GAL_LAYER_ID_START + GAL_LAYER_ID( i ), aLayers.test( i ) );
1079  }
1080  else
1081  {
1082  m_frame->GetBoard()->SetVisibleElements( aLayers );
1083  }
1084 }
1085 
1086 
1088 {
1089  if( m_isFpEditor )
1090  {
1091  KIGFX::VIEW* view = m_frame->GetCanvas()->GetView();
1092  LSET set;
1093 
1094  for( PCB_LAYER_ID layer : LSET::AllLayersMask().Seq() )
1095  set.set( layer, view->IsLayerVisible( layer ) );
1096 
1097  return set;
1098  }
1099  else
1100  {
1101  return m_frame->GetBoard()->GetVisibleLayers();
1102  }
1103 }
1104 
1105 
1107 {
1108  if( m_isFpEditor )
1109  {
1110  KIGFX::VIEW* view = m_frame->GetCanvas()->GetView();
1111  GAL_SET set;
1112  set.reset();
1113 
1114  for( size_t i = 0; i < set.size(); i++ )
1115  set.set( i, view->IsLayerVisible( GAL_LAYER_ID_START + GAL_LAYER_ID( i ) ) );
1116 
1117  return set;
1118  }
1119  else
1120  {
1121  return m_frame->GetBoard()->GetVisibleElements();
1122  }
1123 }
1124 
1125 
1127 {
1128  // TODO(JE) Is this even needed if the layer alphas are getting directly updated?
1129  // Maybe we just need the "down" arrow to indicate if the alpha is below 1
1130 
1131 #if 0
1132  static constexpr double alphaEpsilon = 0.04;
1133 
1134  PCB_LAYER_ID current = m_frame->GetActiveLayer();
1136  KIGFX::PCB_PAINTER* painter =
1137  static_cast<KIGFX::PCB_PAINTER*>( m_frame->GetCanvas()->GetView()->GetPainter() );
1138  KIGFX::PCB_RENDER_SETTINGS* rs = painter->GetSettings();
1139 
1140  for( APPEARANCE_SETTING& setting : m_layerSettings )
1141  {
1142  if( !setting.ctl_indicator )
1143  continue;
1144 
1145  COLOR4D layerColor = theme->GetColor( setting.id );
1146  COLOR4D screenColor = rs->GetLayerColor( setting.id );
1147 
1148  if( std::abs( screenColor.a - layerColor.a ) > alphaEpsilon )
1149  {
1150  if( screenColor.a < layerColor.a )
1151  setting.ctl_indicator->SetIndicatorState( ROW_ICON_PROVIDER::STATE::DOWN );
1152  else
1153  setting.ctl_indicator->SetIndicatorState( ROW_ICON_PROVIDER::STATE::UP );
1154  }
1155  else
1156  {
1157  setting.ctl_indicator->SetIndicatorState( setting.id == current ?
1159  ROW_ICON_PROVIDER::STATE::OFF );
1160  }
1161  }
1162 #endif
1163 }
1164 
1165 
1167 {
1168  const PCB_DISPLAY_OPTIONS& options = m_frame->GetDisplayOptions();
1169 
1170  switch( options.m_ContrastModeDisplay )
1171  {
1172  case HIGH_CONTRAST_MODE::NORMAL: m_rbHighContrastNormal->SetValue( true ); break;
1173  case HIGH_CONTRAST_MODE::DIMMED: m_rbHighContrastDim->SetValue( true ); break;
1174  case HIGH_CONTRAST_MODE::HIDDEN: m_rbHighContrastOff->SetValue( true ); break;
1175  }
1176 
1177  switch( options.m_NetColorMode )
1178  {
1179  case NET_COLOR_MODE::ALL: m_rbNetColorAll->SetValue( true ); break;
1180  case NET_COLOR_MODE::RATSNEST: m_rbNetColorRatsnest->SetValue( true ); break;
1181  case NET_COLOR_MODE::OFF: m_rbNetColorOff->SetValue( true ); break;
1182  }
1183 
1184  m_cbFlipBoard->SetValue( m_frame->GetCanvas()->GetView()->IsMirroredX() );
1185 
1186  if( !m_isFpEditor )
1187  {
1188  if( options.m_RatsnestMode == RATSNEST_MODE::ALL )
1189  m_rbRatsnestAllLayers->SetValue( true );
1190  else
1191  m_rbRatsnestVisibleLayers->SetValue( true );
1192 
1193  wxASSERT( m_objectSettingsMap.count( LAYER_RATSNEST ) );
1195  ratsnest->ctl_visibility->SetValue( options.m_ShowGlobalRatsnest );
1196  }
1197 }
1198 
1199 
1200 std::vector<LAYER_PRESET> APPEARANCE_CONTROLS::GetUserLayerPresets() const
1201 {
1202  std::vector<LAYER_PRESET> ret;
1203 
1204  for( const auto& pair : m_layerPresets )
1205  if( !pair.second.readOnly )
1206  ret.emplace_back( pair.second );
1207 
1208  return ret;
1209 }
1210 
1211 
1212 void APPEARANCE_CONTROLS::SetUserLayerPresets( std::vector<LAYER_PRESET>& aPresetList )
1213 {
1214  // Reset to defaults
1216 
1217  for( const LAYER_PRESET& preset : aPresetList )
1218  {
1219  if( m_layerPresets.count( preset.name ) )
1220  continue;
1221 
1222  m_layerPresets[preset.name] = preset;
1223 
1224  m_presetMRU.Add( preset.name );
1225  }
1226 
1228 }
1229 
1230 
1232 {
1233  m_layerPresets.clear();
1234  m_presetMRU.clear();
1235 
1236  // Load the read-only defaults
1239  presetBackAssembly } )
1240  {
1241  m_layerPresets[preset.name] = preset;
1242  m_layerPresets[preset.name].readOnly = true;
1243 
1244  m_presetMRU.Add( preset.name );
1245  }
1246 }
1247 
1248 
1249 void APPEARANCE_CONTROLS::ApplyLayerPreset( const wxString& aPresetName )
1250 {
1251  updateLayerPresetSelection( aPresetName );
1252 
1253  wxCommandEvent dummy;
1255 }
1256 
1257 
1259 {
1260  if( m_layerPresets.count( aPreset.name ) )
1261  m_currentPreset = &m_layerPresets[aPreset.name];
1262  else
1263  m_currentPreset = nullptr;
1264 
1266  : nullptr;
1267 
1268  updateLayerPresetSelection( aPreset.name );
1269  doApplyLayerPreset( aPreset );
1270 }
1271 
1272 
1274 {
1275  BOARD* board = m_frame->GetBoard();
1276  LSET enabled = board->GetEnabledLayers();
1277  LSET visible = getVisibleLayers();
1278 
1280  COLOR4D bgColor = theme->GetColor( LAYER_PCB_BACKGROUND );
1281  bool firstLayer = true;
1282  bool readOnly = theme->IsReadOnly();
1283 
1284 #ifdef __WXMAC__
1285  wxSizerItem* m_windowLayersSizerItem = m_panelLayersSizer->GetItem( m_windowLayers );
1286  m_windowLayersSizerItem->SetFlag( m_windowLayersSizerItem->GetFlag() & ~wxTOP );
1287 #endif
1288 
1289  m_layerSettings.clear();
1290  m_layersOuterSizer->Clear( true );
1291 
1292  auto appendLayer =
1293  [&]( std::unique_ptr<APPEARANCE_SETTING>& aSetting )
1294  {
1295  int layer = aSetting->id;
1296 
1297  wxPanel* panel = new wxPanel( m_windowLayers, layer );
1298  wxBoxSizer* sizer = new wxBoxSizer( wxHORIZONTAL );
1299  panel->SetSizer( sizer );
1300 
1301  panel->SetBackgroundColour( m_layerPanelColour );
1302 
1303  aSetting->visible = visible[layer];
1304 
1305  // TODO(JE) consider restyling this indicator
1306  INDICATOR_ICON* indicator = new INDICATOR_ICON( panel, *m_iconProvider,
1307  ROW_ICON_PROVIDER::STATE::OFF,
1308  layer );
1309 
1310  COLOR_SWATCH* swatch = new COLOR_SWATCH( panel, COLOR4D::UNSPECIFIED, layer,
1311  bgColor, theme->GetColor( layer ),
1312  SWATCH_SMALL );
1313  swatch->SetToolTip( _( "Double click or middle click for color change, "
1314  "right click for menu" ) );
1315 
1316  BITMAP_TOGGLE* btn_visible = new BITMAP_TOGGLE( panel, layer,
1319  aSetting->visible );
1320  btn_visible->SetToolTip( _( "Show or hide this layer" ) );
1321 
1322  wxStaticText* label = new wxStaticText( panel, layer, aSetting->label );
1323  label->Wrap( -1 );
1324  label->SetToolTip( aSetting->tooltip );
1325 
1326  int topMargin = firstLayer ? 2 : 1;
1327  firstLayer = false;
1328 
1329  sizer->AddSpacer( 1 );
1330  sizer->Add( indicator, 0, wxALIGN_CENTER_VERTICAL | wxTOP, topMargin );
1331  sizer->AddSpacer( 5 );
1332  sizer->Add( swatch, 0, wxALIGN_CENTER_VERTICAL | wxTOP, topMargin );
1333  sizer->AddSpacer( 6 );
1334  sizer->Add( btn_visible, 0, wxALIGN_CENTER_VERTICAL | wxTOP, topMargin );
1335  sizer->AddSpacer( 5 );
1336  sizer->Add( label, 1, wxALIGN_CENTER_VERTICAL | wxTOP, topMargin );
1337 
1338  m_layersOuterSizer->Add( panel, 0, wxEXPAND, 0 );
1339 
1340  aSetting->ctl_panel = panel;
1341  aSetting->ctl_indicator = indicator;
1342  aSetting->ctl_visibility = btn_visible;
1343  aSetting->ctl_color = swatch;
1344  aSetting->ctl_text = label;
1345 
1346  panel->Bind( wxEVT_LEFT_DOWN, &APPEARANCE_CONTROLS::onLayerClick, this );
1347  indicator->Bind( wxEVT_LEFT_DOWN, &APPEARANCE_CONTROLS::onLayerClick, this );
1348  swatch->Bind( wxEVT_LEFT_DOWN, &APPEARANCE_CONTROLS::onLayerClick, this );
1349  label->Bind( wxEVT_LEFT_DOWN, &APPEARANCE_CONTROLS::onLayerClick, this );
1350 
1351  btn_visible->Bind( TOGGLE_CHANGED,
1352  [&]( wxCommandEvent& aEvent )
1353  {
1354  wxObject* btn = aEvent.GetEventObject();
1355  int layId = static_cast<wxWindow*>( btn )->GetId();
1356  bool isVisible = aEvent.GetInt();
1357 
1358  wxASSERT( layId >= 0 && layId < PCB_LAYER_ID_COUNT );
1359 
1361  {
1362  static_cast<BITMAP_TOGGLE*>( btn )->SetValue( !isVisible );
1363  return;
1364  }
1365 
1366  onLayerVisibilityChanged( static_cast<PCB_LAYER_ID>( layId ),
1367  isVisible, true );
1368  } );
1369 
1370  swatch->Bind( COLOR_SWATCH_CHANGED, &APPEARANCE_CONTROLS::OnColorSwatchChanged,
1371  this );
1373  this ) );
1374  swatch->SetReadOnly( readOnly );
1375 
1376  auto rightClickHandler =
1377  [&]( wxMouseEvent& aEvent )
1378  {
1379  wxASSERT( m_layerContextMenu );
1380  PopupMenu( m_layerContextMenu );
1381  passOnFocus();
1382  };
1383 
1384  panel->Bind( wxEVT_RIGHT_DOWN, rightClickHandler );
1385  indicator->Bind( wxEVT_RIGHT_DOWN, rightClickHandler );
1386  swatch->Bind( wxEVT_RIGHT_DOWN, rightClickHandler );
1387  btn_visible->Bind( wxEVT_RIGHT_DOWN, rightClickHandler );
1388  label->Bind( wxEVT_RIGHT_DOWN, rightClickHandler );
1389  };
1390 
1391  wxString dsc;
1392 
1393  // show all coppers first, with front on top, back on bottom, then technical layers
1394  for( LSEQ cu_stack = enabled.CuStack(); cu_stack; ++cu_stack )
1395  {
1396  PCB_LAYER_ID layer = *cu_stack;
1397 
1398  switch( layer )
1399  {
1400  case F_Cu: dsc = _( "Front copper layer" ); break;
1401  case B_Cu: dsc = _( "Back copper layer" ); break;
1402  default: dsc = _( "Inner copper layer" ); break;
1403  }
1404 
1405  m_layerSettings.emplace_back(
1406  std::make_unique<APPEARANCE_SETTING>( board->GetLayerName( layer ), layer, dsc ) );
1407 
1408  std::unique_ptr<APPEARANCE_SETTING>& setting = m_layerSettings.back();
1409 
1410  m_layerSettingsMap[layer] = setting.get();
1411 
1412  appendLayer( setting );
1413 
1415  {
1416  setting->ctl_text->Disable();
1417  setting->ctl_color->SetToolTip( wxEmptyString );
1418  }
1419  }
1420 
1421  // technical layers are shown in this order:
1422  // Because they are static, wxGetTranslation must be explicitly
1423  // called for tooltips.
1424  static const struct {
1425  PCB_LAYER_ID layerId;
1426  wxString tooltip;
1427  } non_cu_seq[] = {
1428  { F_Adhes, _( "Adhesive on board's front" ) },
1429  { B_Adhes, _( "Adhesive on board's back" ) },
1430  { F_Paste, _( "Solder paste on board's front" ) },
1431  { B_Paste, _( "Solder paste on board's back" ) },
1432  { F_SilkS, _( "Silkscreen on board's front" ) },
1433  { B_SilkS, _( "Silkscreen on board's back" ) },
1434  { F_Mask, _( "Solder mask on board's front" ) },
1435  { B_Mask, _( "Solder mask on board's back" ) },
1436  { Dwgs_User, _( "Explanatory drawings" ) },
1437  { Cmts_User, _( "Explanatory comments" ) },
1438  { Eco1_User, _( "User defined meaning" ) },
1439  { Eco2_User, _( "User defined meaning" ) },
1440  { Edge_Cuts, _( "Board's perimeter definition" ) },
1441  { Margin, _( "Board's edge setback outline" ) },
1442  { F_CrtYd, _( "Footprint courtyards on board's front" ) },
1443  { B_CrtYd, _( "Footprint courtyards on board's back" ) },
1444  { F_Fab, _( "Footprint assembly on board's front" ) },
1445  { B_Fab, _( "Footprint assembly on board's back" ) },
1446  { User_1, _( "User defined layer 1" ) },
1447  { User_2, _( "User defined layer 2" ) },
1448  { User_3, _( "User defined layer 3" ) },
1449  { User_4, _( "User defined layer 4" ) },
1450  { User_5, _( "User defined layer 5" ) },
1451  { User_6, _( "User defined layer 6" ) },
1452  { User_7, _( "User defined layer 7" ) },
1453  { User_8, _( "User defined layer 8" ) },
1454  { User_9, _( "User defined layer 9" ) },
1455  };
1456 
1457  for( const auto& entry : non_cu_seq )
1458  {
1459  PCB_LAYER_ID layer = entry.layerId;
1460 
1461  if( !enabled[layer] )
1462  continue;
1463 
1464  m_layerSettings.emplace_back( std::make_unique<APPEARANCE_SETTING>(
1465  board->GetLayerName( layer ), layer, wxGetTranslation( entry.tooltip ) ) );
1466 
1467  std::unique_ptr<APPEARANCE_SETTING>& setting = m_layerSettings.back();
1468 
1469  m_layerSettingsMap[layer] = setting.get();
1470 
1471  appendLayer( setting );
1472 
1474  {
1475  setting->ctl_text->Disable();
1476  setting->ctl_color->SetToolTip( wxEmptyString );
1477  }
1478  }
1479 
1480  m_layersOuterSizer->AddSpacer( 10 );
1481  m_windowLayers->SetBackgroundColour( m_layerPanelColour );
1482  m_windowLayers->Layout();
1483 }
1484 
1485 
1487 {
1488  delete m_layerContextMenu;
1489  m_layerContextMenu = new wxMenu;
1490 
1492  _( "Show All Copper Layers" ),
1495  _( "Hide All Copper Layers" ),
1497 
1498  m_layerContextMenu->AppendSeparator();
1499 
1501  _( "Hide All Layers But Active" ),
1503 
1504  m_layerContextMenu->AppendSeparator();
1505 
1506  AddMenuItem( m_layerContextMenu, ID_SHOW_ALL_NON_COPPER, _( "Show All Non Copper Layers" ),
1508 
1509  AddMenuItem( m_layerContextMenu, ID_HIDE_ALL_NON_COPPER, _( "Hide All Non Copper Layers" ),
1511 
1512  m_layerContextMenu->AppendSeparator();
1513 
1514  AddMenuItem( m_layerContextMenu, ID_PRESET_ALL_LAYERS, _( "Show All Layers" ),
1516 
1517  AddMenuItem( m_layerContextMenu, ID_PRESET_NO_LAYERS, _( "Hide All Layers" ),
1519 
1520  m_layerContextMenu->AppendSeparator();
1521 
1523  _( "Show Only Front Assembly Layers" ), KiBitmap( shape_3d_xpm ) );
1524 
1525  AddMenuItem( m_layerContextMenu, ID_PRESET_FRONT, _( "Show Only Front Layers" ),
1527 
1528  // Only show the internal layer option if internal layers are enabled
1529  if( m_frame->GetBoard()->GetCopperLayerCount() > 2 )
1530  {
1531  AddMenuItem( m_layerContextMenu, ID_PRESET_INNER_COPPER, _( "Show Only Inner Layers" ),
1533  }
1534 
1535  AddMenuItem( m_layerContextMenu, ID_PRESET_BACK, _( "Show Only Back Layers" ),
1537 
1538  AddMenuItem( m_layerContextMenu, ID_PRESET_BACK_ASSEMBLY, _( "Show Only Back Assembly Layers" ),
1540 }
1541 
1542 
1543 void APPEARANCE_CONTROLS::OnLayerContextMenu( wxCommandEvent& aEvent )
1544 {
1545  BOARD* board = m_frame->GetBoard();
1546  LSET visible = getVisibleLayers();
1547 
1548  PCB_LAYER_ID current = m_frame->GetActiveLayer();
1549 
1550  switch( aEvent.GetId() )
1551  {
1552  case ID_PRESET_NO_LAYERS:
1554  return;
1555 
1556  case ID_PRESET_ALL_LAYERS:
1558  return;
1559 
1561  {
1562  visible |= presetAllCopper.layers;
1563  setVisibleLayers( visible );
1564  break;
1565  }
1566 
1569  SetLayerVisible( current, true );
1570  break;
1571 
1573  {
1574  visible &= ~presetAllCopper.layers;
1575 
1576  if( !visible.test( current ) )
1577  m_frame->SetActiveLayer( *visible.Seq().begin() );
1578 
1579  setVisibleLayers( visible );
1580  break;
1581  }
1582 
1584  {
1585  visible &= presetAllCopper.layers;
1586 
1587  if( !visible.test( current ) )
1588  m_frame->SetActiveLayer( *visible.Seq().begin() );
1589 
1590  setVisibleLayers( visible );
1591  break;
1592  }
1593 
1595  {
1596  visible |= ~presetAllCopper.layers;
1597 
1598  setVisibleLayers( visible );
1599  break;
1600  }
1601 
1604  return;
1605 
1606  case ID_PRESET_FRONT:
1608  return;
1609 
1612  return;
1613 
1614  case ID_PRESET_BACK:
1616  return;
1617 
1620  return;
1621  }
1622 
1625 
1626  if( !m_isFpEditor )
1627  m_frame->GetCanvas()->SyncLayersVisibility( board );
1628 
1629  m_frame->GetCanvas()->Refresh();
1630 }
1631 
1632 
1634 {
1635  return m_notebook->GetSelection();
1636 }
1637 
1638 
1640 {
1641  size_t max = m_notebook->GetPageCount();
1642 
1643  if( aTab >= 0 && static_cast<size_t>( aTab ) < max )
1644  m_notebook->SetSelection( aTab );
1645 }
1646 
1647 
1649 {
1651  bool readOnly = theme->IsReadOnly();
1652  LSET visible = getVisibleLayers();
1653  GAL_SET objects = getVisibleObjects();
1654 
1655  Freeze();
1656 
1657  for( std::unique_ptr<APPEARANCE_SETTING>& setting : m_layerSettings )
1658  {
1659  LAYER_NUM layer = setting->id;
1660 
1661  if( setting->ctl_visibility )
1662  setting->ctl_visibility->SetValue( visible[layer] );
1663 
1664  if( setting->ctl_color )
1665  {
1666  const COLOR4D& color = theme->GetColor( layer );
1667  setting->ctl_color->SetSwatchColor( color, false );
1668  setting->ctl_color->SetReadOnly( readOnly );
1669  }
1670  }
1671 
1672  for( std::unique_ptr<APPEARANCE_SETTING>& setting : m_objectSettings )
1673  {
1674  GAL_LAYER_ID layer = static_cast<GAL_LAYER_ID>( setting->id );
1675 
1676  if( setting->ctl_visibility )
1677  setting->ctl_visibility->SetValue( objects.Contains( layer ) );
1678 
1679  if( setting->ctl_color )
1680  {
1681  const COLOR4D& color = theme->GetColor( layer );
1682  setting->ctl_color->SetSwatchColor( color, false );
1683  setting->ctl_color->SetReadOnly( readOnly );
1684  }
1685  }
1686 
1687  // Update indicators and panel background colors
1688  OnLayerChanged();
1689 
1690  Thaw();
1691 
1692  m_windowLayers->Refresh();
1693 }
1694 
1695 
1696 void APPEARANCE_CONTROLS::onLayerClick( wxMouseEvent& aEvent )
1697 {
1698  auto eventSource = static_cast<wxWindow*>( aEvent.GetEventObject() );
1699 
1700  PCB_LAYER_ID layer = ToLAYER_ID( eventSource->GetId() );
1701 
1702  if( m_isFpEditor && LSET::ForbiddenFootprintLayers().test( layer ) )
1703  return;
1704 
1705  m_frame->SetActiveLayer( layer );
1706  passOnFocus();
1707 }
1708 
1709 
1711  bool isFinal )
1712 {
1713  LSET visibleLayers = getVisibleLayers();
1714 
1715  if( visibleLayers.test( aLayer ) != isVisible )
1716  {
1717  visibleLayers.set( aLayer, isVisible );
1718 
1719  setVisibleLayers( visibleLayers );
1720 
1721  m_frame->GetCanvas()->GetView()->SetLayerVisible( aLayer, isVisible );
1722  }
1723 
1725 
1726  if( isFinal )
1727  m_frame->GetCanvas()->Refresh();
1728 }
1729 
1730 
1732  bool isFinal )
1733 {
1734  // Special-case controls
1735  switch( aLayer )
1736  {
1737  case LAYER_RATSNEST:
1738  {
1739  // don't touch the layers. ratsnest is enabled on per-item basis.
1741  m_frame->GetCanvas()->GetView()->SetLayerVisible( aLayer, true );
1742 
1743  if( m_frame->IsType( FRAME_PCB_EDITOR ) )
1744  {
1746  opt.m_ShowGlobalRatsnest = isVisible;
1747  m_frame->SetDisplayOptions( opt );
1749  }
1750 
1751  break;
1752  }
1753 
1754  case LAYER_GRID:
1755  m_frame->SetGridVisibility( isVisible );
1756  m_frame->GetCanvas()->Refresh();
1758  break;
1759 
1760  case LAYER_MOD_TEXT_FR:
1761  // Because Footprint Text is a meta-control that also can disable values/references,
1762  // drag them along here so that the user is less likely to be confused.
1763  onObjectVisibilityChanged( LAYER_MOD_REFERENCES, isVisible, false );
1764  onObjectVisibilityChanged( LAYER_MOD_VALUES, isVisible, false );
1765  m_objectSettingsMap[LAYER_MOD_REFERENCES]->ctl_visibility->SetValue( isVisible );
1766  m_objectSettingsMap[LAYER_MOD_VALUES]->ctl_visibility->SetValue( isVisible );
1767  break;
1768 
1769  default:
1770  break;
1771  }
1772 
1773  GAL_SET visible = getVisibleObjects();
1774 
1775  if( visible.Contains( aLayer ) != isVisible )
1776  {
1777  visible.set( aLayer, isVisible );
1778  setVisibleObjects( visible );
1779  m_frame->GetCanvas()->GetView()->SetLayerVisible( aLayer, isVisible );
1781  }
1782 
1783  if( isFinal )
1784  {
1785  m_frame->GetCanvas()->Refresh();
1786  passOnFocus();
1787  }
1788 }
1789 
1790 
1792 {
1794  COLOR4D bgColor = theme->GetColor( LAYER_PCB_BACKGROUND );
1795  GAL_SET visible = getVisibleObjects();
1796  int swatchWidth = m_windowObjects->ConvertDialogToPixels( wxSize( 8, 0 ) ).x;
1797  int labelWidth = 0;
1798 
1799  m_objectSettings.clear();
1800  m_objectsOuterSizer->Clear( true );
1801  m_objectsOuterSizer->AddSpacer( 5 );
1802 
1803  auto appendObject =
1804  [&]( const std::unique_ptr<APPEARANCE_SETTING>& aSetting )
1805  {
1806  wxBoxSizer* sizer = new wxBoxSizer( wxHORIZONTAL );
1807  int layer = aSetting->id;
1808 
1809  aSetting->visible = visible.Contains( ToGalLayer( layer ) );
1810  COLOR4D color = theme->GetColor( layer );
1811  COLOR4D defColor = theme->GetDefaultColor( layer );
1812 
1813  if( color != COLOR4D::UNSPECIFIED )
1814  {
1815  COLOR_SWATCH* swatch = new COLOR_SWATCH( m_windowObjects, color, layer,
1816  bgColor, defColor, SWATCH_SMALL );
1817  swatch->SetToolTip( _( "Left double click or middle click for color change, "
1818  "right click for menu" ) );
1819 
1820  sizer->Add( swatch, 0, wxALIGN_CENTER_VERTICAL, 0 );
1821  aSetting->ctl_color = swatch;
1822 
1823  swatch->Bind( COLOR_SWATCH_CHANGED,
1825  }
1826  else
1827  {
1828  sizer->AddSpacer( swatchWidth );
1829  }
1830 
1831  BITMAP_TOGGLE* btn_visible = new BITMAP_TOGGLE( m_windowObjects, layer,
1834  aSetting->visible );
1835 
1836  wxString tip;
1837  tip.Printf( _( "Show or hide %s" ), aSetting->label.Lower() );
1838  btn_visible->SetToolTip( tip );
1839 
1840  aSetting->ctl_visibility = btn_visible;
1841 
1842  sizer->AddSpacer( 5 );
1843 
1844  btn_visible->Bind( TOGGLE_CHANGED,
1845  [&]( wxCommandEvent& aEvent )
1846  {
1847  int id = static_cast<wxWindow*>( aEvent.GetEventObject() )->GetId();
1848  bool isVisible = aEvent.GetInt();
1849  onObjectVisibilityChanged( ToGalLayer( id ), isVisible, true );
1850  } );
1851 
1852  wxStaticText* label = new wxStaticText( m_windowObjects, layer, aSetting->label );
1853  label->Wrap( -1 );
1854  label->SetToolTip( aSetting->tooltip );
1855 
1856  if( aSetting->can_control_opacity )
1857  {
1858  label->SetMinSize( wxSize( labelWidth, -1 ) );
1859 #ifdef __WXMAC__
1860  sizer->Add( btn_visible, 0, wxALIGN_CENTER_VERTICAL | wxBOTTOM, 10 );
1861  sizer->AddSpacer( 5 );
1862  sizer->Add( label, 0, wxALIGN_CENTER_VERTICAL | wxBOTTOM, 10 );
1863 #else
1864  sizer->Add( btn_visible, 0, wxALIGN_CENTER_VERTICAL, 0 );
1865  sizer->AddSpacer( 5 );
1866  sizer->Add( label, 0, wxALIGN_CENTER_VERTICAL, 0 );
1867 #endif
1868 
1869  wxSlider* slider = new wxSlider( m_windowObjects, wxID_ANY, 100, 0, 100,
1870  wxDefaultPosition, wxDefaultSize,
1871  wxSL_HORIZONTAL );
1872 #ifdef __WXMAC__
1873  slider->SetMinSize( wxSize( 80, 22 ) );
1874 #else
1875  slider->SetMinSize( wxSize( 80, -1 ) );
1876 #endif
1877 
1878  tip.Printf( _( "Set opacity of %s" ), aSetting->label.Lower() );
1879  slider->SetToolTip( tip );
1880 
1881  sizer->Add( slider, 1, wxALIGN_CENTER_VERTICAL | wxLEFT | wxRIGHT, 5 );
1882  aSetting->ctl_opacity = slider;
1883 
1884  auto opacitySliderHandler =
1885  [=]( wxCommandEvent& aEvent )
1886  {
1887  wxSlider* ctrl = static_cast<wxSlider*>( aEvent.GetEventObject() );
1888  int value = ctrl->GetValue();
1889  onObjectOpacitySlider( layer, value / 100.0f );
1890  };
1891 
1892  slider->Bind( wxEVT_SCROLL_CHANGED, opacitySliderHandler );
1893  slider->Bind( wxEVT_SCROLL_THUMBTRACK, opacitySliderHandler );
1894  slider->Bind( wxEVT_SET_FOCUS, &APPEARANCE_CONTROLS::OnSetFocus, this );
1895  }
1896  else
1897  {
1898  sizer->Add( btn_visible, 0, wxALIGN_CENTER_VERTICAL, 0 );
1899  sizer->AddSpacer( 5 );
1900  sizer->Add( label, 0, wxALIGN_CENTER_VERTICAL, 0 );
1901  }
1902 
1903  aSetting->ctl_text = label;
1904  m_objectsOuterSizer->Add( sizer, 0, wxEXPAND | wxLEFT | wxRIGHT, 5 );
1905  m_objectsOuterSizer->AddSpacer( 1 );
1906  };
1907 
1908  for( const APPEARANCE_SETTING& s_setting : s_objectSettings )
1909  {
1910  if( m_isFpEditor && !s_allowedInFpEditor.count( s_setting.id ) )
1911  continue;
1912 
1913  if( !s_setting.spacer )
1914  {
1915  m_objectSettings.emplace_back( std::make_unique<APPEARANCE_SETTING>( s_setting ) );
1916 
1917  std::unique_ptr<APPEARANCE_SETTING>& setting = m_objectSettings.back();
1918 
1919  // Because s_render_rows is created static, we must explicitly call
1920  // wxGetTranslation for texts which are internationalized (tool tips
1921  // and item names)
1922  setting->tooltip = wxGetTranslation( s_setting.tooltip );
1923  setting->label = wxGetTranslation( s_setting.label );
1924 
1925  if( setting->can_control_opacity )
1926  {
1927  int width = m_windowObjects->GetTextExtent( setting->label ).x;
1928  labelWidth = std::max( labelWidth, width );
1929  }
1930 
1931  m_objectSettingsMap[ToGalLayer( setting->id )] = setting.get();
1932  }
1933  }
1934 
1935  for( const std::unique_ptr<APPEARANCE_SETTING>& setting : m_objectSettings )
1936  {
1937  if( setting->spacer )
1938  m_objectsOuterSizer->AddSpacer( m_pointSize );
1939  else
1940  appendObject( setting );
1941  }
1942 
1943  m_objectsOuterSizer->Layout();
1944 }
1945 
1946 
1948 {
1949  GAL_SET visible = getVisibleObjects();
1950 
1952 
1953  for( std::unique_ptr<APPEARANCE_SETTING>& setting : m_objectSettings )
1954  {
1955  if( setting->spacer )
1956  continue;
1957 
1958  GAL_LAYER_ID layer = ToGalLayer( setting->id );
1959 
1960  if( setting->ctl_visibility )
1961  setting->ctl_visibility->SetValue( visible.Contains( layer ) );
1962 
1963  if( setting->ctl_color )
1964  {
1965  COLOR4D color = m_frame->GetColorSettings()->GetColor( setting->id );
1966  setting->ctl_color->SetSwatchColor( color, false );
1967  }
1968  }
1969 
1970  wxASSERT( m_objectSettingsMap.count( LAYER_TRACKS )
1971  && m_objectSettingsMap.count( LAYER_VIAS )
1972  && m_objectSettingsMap.count( LAYER_PADS )
1973  && m_objectSettingsMap.count( LAYER_ZONES ) );
1974 
1975  m_objectSettingsMap[LAYER_TRACKS]->ctl_opacity->SetValue( opts.m_TrackOpacity * 100 );
1976  m_objectSettingsMap[LAYER_VIAS]->ctl_opacity->SetValue( opts.m_ViaOpacity * 100 );
1977  m_objectSettingsMap[LAYER_PADS]->ctl_opacity->SetValue( opts.m_PadOpacity * 100 );
1978  m_objectSettingsMap[LAYER_ZONES]->ctl_opacity->SetValue( opts.m_ZoneOpacity * 100 );
1979 }
1980 
1981 
1983 {
1984  BOARD* board = m_frame->GetBoard();
1986  COLOR4D bgColor = theme->GetColor( LAYER_PCB_BACKGROUND );
1987 
1988  // If the board isn't fully loaded, we can't yet rebuild
1989  if( !board->GetProject() )
1990  return;
1991 
1992  KIGFX::PCB_RENDER_SETTINGS* rs = static_cast<KIGFX::PCB_RENDER_SETTINGS*>(
1994 
1995  std::map<wxString, KIGFX::COLOR4D>& netclassColors = rs->GetNetclassColorMap();
1996 
1997  m_netclassOuterSizer->Clear( true );
1998 
1999  auto appendNetclass =
2000  [&]( int aId, const NETCLASSPTR& aClass, bool isDefaultClass = false )
2001  {
2002  wxString name = aClass->GetName();
2003 
2004  m_netclassSettings.emplace_back( std::make_unique<APPEARANCE_SETTING>() );
2005  APPEARANCE_SETTING* setting = m_netclassSettings.back().get();
2006  m_netclassSettingsMap[name] = setting;
2007 
2008  setting->ctl_panel = new wxPanel( m_netclassScrolledWindow, aId );
2009  wxBoxSizer* sizer = new wxBoxSizer( wxHORIZONTAL );
2010  setting->ctl_panel->SetSizer( sizer );
2011  COLOR4D color = netclassColors.count( name ) ? netclassColors.at( name ) :
2012  COLOR4D::UNSPECIFIED;
2013 
2014  setting->ctl_color = new COLOR_SWATCH( setting->ctl_panel, color, aId, bgColor,
2015  COLOR4D::UNSPECIFIED, SWATCH_SMALL );
2016  setting->ctl_color->SetToolTip( _( "Left double click or middle click for color "
2017  "change, right click for menu" ) );
2018 
2019  setting->ctl_color->Bind( COLOR_SWATCH_CHANGED,
2021 
2022  // Default netclass can't have an override color
2023  if( isDefaultClass )
2024  setting->ctl_color->Hide();
2025 
2026  setting->ctl_visibility =
2027  new BITMAP_TOGGLE( setting->ctl_panel, aId, KiBitmap( visibility_xpm ),
2028  KiBitmap( visibility_off_xpm ), true );
2029 
2030  wxString tip;
2031  tip.Printf( _( "Show or hide ratsnest for nets in %s" ), name );
2032  setting->ctl_visibility->SetToolTip( tip );
2033 
2034  setting->ctl_text = new wxStaticText( setting->ctl_panel, aId, name );
2035  setting->ctl_text->Wrap( -1 );
2036 
2037  int flags = wxALIGN_CENTER_VERTICAL;
2038 
2039  sizer->Add( setting->ctl_color, 0, flags | wxRESERVE_SPACE_EVEN_IF_HIDDEN, 5 );
2040  sizer->AddSpacer( 7 );
2041  sizer->Add( setting->ctl_visibility, 0, flags, 5 );
2042  sizer->AddSpacer( 3 );
2043  sizer->Add( setting->ctl_text, 1, flags, 5 );
2044 
2045  m_netclassOuterSizer->Add( setting->ctl_panel, 0, wxEXPAND, 5 );
2046  m_netclassOuterSizer->AddSpacer( 1 );
2047 
2048  setting->ctl_visibility->Bind( TOGGLE_CHANGED,
2050  this );
2051 
2052  auto menuHandler =
2053  [&, name, isDefaultClass]( wxMouseEvent& aEvent )
2054  {
2056 
2057  wxMenu menu;
2058 
2059  if( !isDefaultClass)
2060  {
2061  menu.Append( new wxMenuItem( &menu, ID_SET_NET_COLOR,
2062  _( "Set netclass color" ), wxEmptyString,
2063  wxITEM_NORMAL ) );
2064  }
2065 
2066  menu.Append( new wxMenuItem( &menu, ID_HIGHLIGHT_NET,
2067  wxString::Format( _( "Highlight nets in %s" ), name ),
2068  wxEmptyString, wxITEM_NORMAL ) );
2069  menu.Append( new wxMenuItem( &menu, ID_SELECT_NET,
2070  wxString::Format( _( "Select tracks and vias in %s" ),
2071  name ),
2072  wxEmptyString, wxITEM_NORMAL ) );
2073  menu.Append( new wxMenuItem( &menu, ID_DESELECT_NET,
2074  wxString::Format( _( "Deselect tracks and vias in %s" ),
2075  name ),
2076  wxEmptyString, wxITEM_NORMAL ) );
2077 
2078  menu.AppendSeparator();
2079 
2080  menu.Append( new wxMenuItem( &menu, ID_SHOW_ALL_NETS,
2081  _( "Show all netclasses" ), wxEmptyString,
2082  wxITEM_NORMAL ) );
2083  menu.Append( new wxMenuItem( &menu, ID_HIDE_OTHER_NETS,
2084  _( "Hide all other netclasses" ), wxEmptyString,
2085  wxITEM_NORMAL ) );
2086 
2087  menu.Bind( wxEVT_COMMAND_MENU_SELECTED,
2089 
2090  PopupMenu( &menu );
2091  };
2092 
2093  setting->ctl_panel->Bind( wxEVT_RIGHT_DOWN, menuHandler );
2094  setting->ctl_visibility->Bind( wxEVT_RIGHT_DOWN, menuHandler );
2095  setting->ctl_color->Bind( wxEVT_RIGHT_DOWN, menuHandler );
2096  setting->ctl_text->Bind( wxEVT_RIGHT_DOWN, menuHandler );
2097  };
2098 
2099  const NETCLASS_MAP& classes = board->GetDesignSettings().GetNetClasses().NetClasses();
2100 
2101  std::vector<wxString> names;
2102 
2103  for( const auto& pair : classes )
2104  names.emplace_back( pair.first );
2105 
2106  std::sort( names.begin(), names.end() );
2107 
2108  m_netclassIdMap.clear();
2109 
2110  int idx = wxID_HIGHEST;
2111 
2112  NETCLASSPTR defaultClass = board->GetDesignSettings().GetNetClasses().GetDefault();
2113 
2114  m_netclassIdMap[idx] = defaultClass->GetName();
2115  appendNetclass( idx++, defaultClass, true );
2116 
2117  for( const wxString& name : names )
2118  {
2119  m_netclassIdMap[idx] = name;
2120  appendNetclass( idx++, classes.at( name ) );
2121  }
2122 
2123  m_netclassOuterSizer->Layout();
2124 
2125  m_netsTable->Rebuild();
2126  m_panelNets->GetSizer()->Layout();
2127 }
2128 
2129 
2131 {
2132  m_cbLayerPresets->Clear();
2133 
2134  for( std::pair<const wxString, LAYER_PRESET>& pair : m_layerPresets )
2135  m_cbLayerPresets->Append( pair.first, static_cast<void*>( &pair.second ) );
2136 
2137  m_cbLayerPresets->Append( wxT( "-----" ) );
2138  m_cbLayerPresets->Append( _( "Save preset..." ) );
2139  m_cbLayerPresets->Append( _( "Delete preset..." ) );
2140 
2141  m_cbLayerPresets->SetSelection( 0 );
2142 
2143  // At least the build in presets should always be present
2144  wxASSERT( !m_layerPresets.empty() );
2145 
2146  // Default preset: all layers
2148 }
2149 
2150 
2152 {
2153  LSET visibleLayers = getVisibleLayers();
2154  GAL_SET visibleObjects = getVisibleObjects();
2155 
2156  auto it = std::find_if( m_layerPresets.begin(), m_layerPresets.end(),
2157  [&]( const std::pair<const wxString, LAYER_PRESET>& aPair )
2158  {
2159  return ( aPair.second.layers == visibleLayers
2160  && aPair.second.renderLayers == visibleObjects );
2161  } );
2162 
2163  if( it != m_layerPresets.end() )
2164  m_cbLayerPresets->SetStringSelection( it->first );
2165  else
2166  m_cbLayerPresets->SetSelection( m_cbLayerPresets->GetCount() - 3 ); // separator
2167 
2168  m_currentPreset = static_cast<LAYER_PRESET*>(
2169  m_cbLayerPresets->GetClientData( m_cbLayerPresets->GetSelection() ) );
2170 }
2171 
2172 
2174 {
2175  int idx = m_cbLayerPresets->FindString( aName );
2176 
2177  if( idx >= 0 && m_cbLayerPresets->GetSelection() != idx )
2178  {
2179  m_cbLayerPresets->SetSelection( idx );
2180  m_currentPreset = static_cast<LAYER_PRESET*>( m_cbLayerPresets->GetClientData( idx ) );
2181  }
2182  else if( idx < 0 )
2183  {
2184  m_cbLayerPresets->SetSelection( m_cbLayerPresets->GetCount() - 3 ); // separator
2185  }
2186 }
2187 
2188 
2189 void APPEARANCE_CONTROLS::onLayerPresetChanged( wxCommandEvent& aEvent )
2190 {
2191  int count = m_cbLayerPresets->GetCount();
2192  int index = m_cbLayerPresets->GetSelection();
2193 
2194  auto resetSelection =
2195  [&]()
2196  {
2197  if( m_currentPreset )
2198  m_cbLayerPresets->SetStringSelection( m_currentPreset->name );
2199  else
2200  m_cbLayerPresets->SetSelection( count - 3 );
2201  };
2202 
2203  if( index == count - 3 )
2204  {
2205  // Separator: reject the selection
2206  resetSelection();
2207  return;
2208  }
2209  else if( index == count - 2 )
2210  {
2211  // Save current state to new preset
2212  wxString name;
2213 
2216 
2217  wxTextEntryDialog dlg( this, _( "Layer preset name:" ), _( "Save Layer Preset" ), name );
2218 
2219  if( dlg.ShowModal() != wxID_OK )
2220  {
2221  resetSelection();
2222  return;
2223  }
2224 
2225  name = dlg.GetValue();
2226  bool exists = m_layerPresets.count( name );
2227 
2228  if( !exists )
2231 
2232  LAYER_PRESET* preset = &m_layerPresets[name];
2233  m_currentPreset = preset;
2234 
2235  if( !exists )
2236  index = m_cbLayerPresets->Insert( name, index - 1, static_cast<void*>( preset ) );
2237  else
2238  index = m_cbLayerPresets->FindString( name );
2239 
2240  m_cbLayerPresets->SetSelection( index );
2241 
2242  m_presetMRU.Insert( name, 0 );
2243 
2244  return;
2245  }
2246  else if( index == count - 1 )
2247  {
2248  // Delete a preset
2249  wxArrayString headers;
2250  std::vector<wxArrayString> items;
2251 
2252  headers.Add( _( "Presets" ) );
2253 
2254  for( std::pair<const wxString, LAYER_PRESET>& pair : m_layerPresets )
2255  {
2256  if( !pair.second.readOnly )
2257  {
2258  wxArrayString item;
2259  item.Add( pair.first );
2260  items.emplace_back( item );
2261  }
2262  }
2263 
2264  EDA_LIST_DIALOG dlg( m_frame, _( "Delete Preset" ), headers, items, wxEmptyString );
2265  dlg.SetListLabel( _( "Select preset:" ) );
2266 
2267  if( dlg.ShowModal() == wxID_OK )
2268  {
2269  wxString presetName = dlg.GetTextSelection();
2270 
2271  m_layerPresets.erase( presetName );
2272 
2273  m_cbLayerPresets->Delete( m_cbLayerPresets->FindString( presetName ) );
2274  m_cbLayerPresets->SetSelection( m_cbLayerPresets->GetCount() - 3 );
2275  m_currentPreset = nullptr;
2276 
2277  m_presetMRU.Remove( presetName );
2278  }
2279 
2280  resetSelection();
2281  return;
2282  }
2283 
2284  LAYER_PRESET* preset = static_cast<LAYER_PRESET*>( m_cbLayerPresets->GetClientData( index ) );
2285  m_currentPreset = preset;
2286 
2287  m_lastSelectedUserPreset = ( !preset || preset->readOnly ) ? nullptr : preset;
2288 
2289  if( preset )
2290  doApplyLayerPreset( *preset );
2291 
2292  if( !m_currentPreset->name.IsEmpty() )
2293  {
2294  m_presetMRU.Remove( m_currentPreset->name );
2295  m_presetMRU.Insert( m_currentPreset->name, 0 );
2296  }
2297 
2298  passOnFocus();
2299 }
2300 
2301 
2303 {
2304  BOARD* board = m_frame->GetBoard();
2305 
2306  setVisibleLayers( aPreset.layers );
2307  setVisibleObjects( aPreset.renderLayers );
2308 
2309  // If the preset doesn't have an explicit active layer to restore, we can at least
2310  // force the active layer to be something in the preset's layer set
2311  PCB_LAYER_ID activeLayer = UNSELECTED_LAYER;
2312 
2313  if( aPreset.activeLayer != UNSELECTED_LAYER )
2314  activeLayer = aPreset.activeLayer;
2315  else if( aPreset.layers.any() && !aPreset.layers.test( m_frame->GetActiveLayer() ) )
2316  activeLayer = *aPreset.layers.Seq().begin();
2317 
2318  LSET boardLayers = board->GetLayerSet();
2319 
2320  if( activeLayer != UNSELECTED_LAYER && boardLayers.Contains( activeLayer ) )
2321  m_frame->SetActiveLayer( activeLayer );
2322 
2323  if( !m_isFpEditor )
2324  m_frame->GetCanvas()->SyncLayersVisibility( board );
2325 
2326  m_frame->GetCanvas()->Refresh();
2327 
2329 }
2330 
2331 
2332 void APPEARANCE_CONTROLS::OnColorSwatchChanged( wxCommandEvent& aEvent )
2333 {
2334  COLOR_SWATCH* swatch = static_cast<COLOR_SWATCH*>( aEvent.GetEventObject() );
2335  COLOR4D newColor = swatch->GetSwatchColor();
2336  LAYER_NUM layer = swatch->GetId();
2337 
2339  cs->SetColor( layer, newColor );
2340 
2342 
2343  KIGFX::VIEW* view = m_frame->GetCanvas()->GetView();
2344  view->UpdateLayerColor( layer );
2345  view->UpdateLayerColor( GetNetnameLayer( layer ) );
2346 
2347  // Update the bitmap of the layer box
2348  if( m_frame->IsType( FRAME_PCB_EDITOR ) )
2349  static_cast<PCB_EDIT_FRAME*>( m_frame )->ReCreateLayerBox( false );
2350 
2351  m_frame->GetCanvas()->Refresh();
2352 
2353  if( layer == LAYER_PCB_BACKGROUND )
2354  m_frame->SetDrawBgColor( newColor );
2355 
2356  passOnFocus();
2357 }
2358 
2359 
2360 void APPEARANCE_CONTROLS::onObjectOpacitySlider( int aLayer, float aOpacity )
2361 {
2363 
2364  switch( aLayer )
2365  {
2366  case static_cast<int>( LAYER_TRACKS ): options.m_TrackOpacity = aOpacity; break;
2367  case static_cast<int>( LAYER_VIAS ): options.m_ViaOpacity = aOpacity; break;
2368  case static_cast<int>( LAYER_PADS ): options.m_PadOpacity = aOpacity; break;
2369  case static_cast<int>( LAYER_ZONES ): options.m_ZoneOpacity = aOpacity; break;
2370  default: return;
2371  }
2372 
2373  m_frame->SetDisplayOptions( options );
2374  passOnFocus();
2375 }
2376 
2377 
2378 void APPEARANCE_CONTROLS::onNetContextMenu( wxCommandEvent& aEvent )
2379 {
2380  wxASSERT( m_netsGrid->GetSelectedRows().size() == 1 );
2381 
2382  int row = m_netsGrid->GetSelectedRows()[0];
2383  NET_GRID_ENTRY& net = m_netsTable->GetEntry( row );
2384 
2385  m_netsGrid->ClearSelection();
2386 
2387  switch( aEvent.GetId() )
2388  {
2389  case ID_SET_NET_COLOR:
2390  {
2391  wxGridCellEditor* editor = m_netsGrid->GetCellEditor( row, NET_GRID_TABLE::COL_COLOR );
2392  editor->BeginEdit( row, NET_GRID_TABLE::COL_COLOR, m_netsGrid );
2393  break;
2394  }
2395 
2396  case ID_HIGHLIGHT_NET:
2397  {
2399  m_frame->GetCanvas()->Refresh();
2400  break;
2401  }
2402 
2403  case ID_SELECT_NET:
2404  {
2406  m_frame->GetCanvas()->Refresh();
2407  break;
2408  }
2409 
2410  case ID_DESELECT_NET:
2411  {
2413  m_frame->GetCanvas()->Refresh();
2414  break;
2415  }
2416 
2417  case ID_SHOW_ALL_NETS:
2419  break;
2420 
2421  case ID_HIDE_OTHER_NETS:
2422  m_netsTable->HideOtherNets( net );
2423  break;
2424 
2425  default:
2426  break;
2427  }
2428 
2429  passOnFocus();
2430 }
2431 
2432 
2434 {
2435  wxString className = netclassNameFromEvent( aEvent );
2436  bool show = aEvent.GetInt();
2437  showNetclass( className, show );
2438  passOnFocus();
2439 }
2440 
2441 
2442 void APPEARANCE_CONTROLS::showNetclass( const wxString& aClassName, bool aShow )
2443 {
2444  BOARD* board = m_frame->GetBoard();
2445  NETINFO_LIST& nets = board->GetNetInfo();
2446  NETCLASSES& classes = board->GetDesignSettings().GetNetClasses();
2447  NETCLASSPTR netclass = classes.Find( aClassName );
2448  TOOL_MANAGER* manager = m_frame->GetToolManager();
2449 
2450  if( !netclass )
2451  return;
2452 
2453  NETCLASS* defaultClass = classes.GetDefaultPtr();
2454 
2455  if( netclass == classes.GetDefault() )
2456  {
2457  const TOOL_ACTION& action = aShow ? PCB_ACTIONS::showNet : PCB_ACTIONS::hideNet;
2458 
2459  for( NETINFO_ITEM* net : nets )
2460  {
2461  if( net->GetNetClass() == defaultClass )
2462  {
2463  manager->RunAction( action, true, net->GetNet() );
2464 
2465  int row = m_netsTable->GetRowByNetcode( net->GetNet() );
2466 
2467  if( row >= 0 )
2469  }
2470  }
2471  }
2472  else
2473  {
2474  const TOOL_ACTION& action = aShow ? PCB_ACTIONS::showNet : PCB_ACTIONS::hideNet;
2475 
2476  for( const wxString& member : *netclass )
2477  {
2478  if( NETINFO_ITEM* net = nets.GetNetItem( member ) )
2479  {
2480  int code = net->GetNet();
2481  manager->RunAction( action, true, code );
2482 
2483  int row = m_netsTable->GetRowByNetcode( code );
2484 
2485  if( row >= 0 )
2487  }
2488  }
2489  }
2490 
2491  m_netsGrid->ForceRefresh();
2492 }
2493 
2494 
2495 void APPEARANCE_CONTROLS::onNetclassColorChanged( wxCommandEvent& aEvent )
2496 {
2497  KIGFX::PCB_RENDER_SETTINGS* rs = static_cast<KIGFX::PCB_RENDER_SETTINGS*>(
2499 
2500  std::map<wxString, KIGFX::COLOR4D>& netclassColors = rs->GetNetclassColorMap();
2501 
2502  COLOR_SWATCH* swatch = static_cast<COLOR_SWATCH*>( aEvent.GetEventObject() );
2503  wxString className = netclassNameFromEvent( aEvent );
2504 
2505  netclassColors[className] = swatch->GetSwatchColor();
2506 
2509  m_frame->GetCanvas()->Refresh();
2510 }
2511 
2512 
2514 {
2515  COLOR_SWATCH* s = static_cast<COLOR_SWATCH*>( aEvent.GetEventObject() );
2516  int classId = s->GetId();
2517 
2518  wxASSERT( m_netclassIdMap.count( classId ) );
2519  return m_netclassIdMap.at( classId );
2520 }
2521 
2522 
2523 void APPEARANCE_CONTROLS::onNetColorModeChanged( wxCommandEvent& aEvent )
2524 {
2526 
2527  if( m_rbNetColorAll->GetValue() )
2529  else if( m_rbNetColorRatsnest->GetValue() )
2531  else
2533 
2534  m_frame->SetDisplayOptions( options );
2536  passOnFocus();
2537 }
2538 
2539 
2540 void APPEARANCE_CONTROLS::onRatsnestModeChanged( wxCommandEvent& aEvent )
2541 {
2543 
2544  if( m_rbRatsnestAllLayers->GetValue() )
2546  else
2548 
2549  m_frame->SetDisplayOptions( options );
2551  passOnFocus();
2552 }
2553 
2554 
2555 void APPEARANCE_CONTROLS::onNetclassContextMenu( wxCommandEvent& aEvent )
2556 {
2557  KIGFX::VIEW* view = m_frame->GetCanvas()->GetView();
2559  static_cast<KIGFX::PCB_RENDER_SETTINGS*>( view->GetPainter()->GetSettings() );
2560 
2561  BOARD* board = m_frame->GetBoard();
2562  NETINFO_LIST& nets = board->GetNetInfo();
2563  NETCLASSES& classes = board->GetDesignSettings().GetNetClasses();
2564  NETCLASSPTR netclass = classes.Find( m_contextMenuNetclass );
2565 
2568 
2569  NETCLASSPTR defaultClass = classes.GetDefault();
2570  wxString defaultClassName = defaultClass->GetName();
2571 
2572  auto runOnNetsOfClass =
2573  [&]( NETCLASSPTR aClass, std::function<void( NETINFO_ITEM* )> aFunction )
2574  {
2575  if( aClass == defaultClass )
2576  {
2577  for( NETINFO_ITEM* net : nets )
2578  if( net->GetNetClass() == defaultClass.get() )
2579  aFunction( net );
2580  }
2581  else
2582  {
2583  for( const wxString& netName : *aClass )
2584  aFunction( nets.GetNetItem( netName ) );
2585  }
2586  };
2587 
2588  switch( aEvent.GetId() )
2589  {
2590  case ID_SET_NET_COLOR:
2591  {
2592  if( setting )
2593  {
2594  setting->ctl_color->GetNewSwatchColor();
2595 
2596  COLOR4D color = setting->ctl_color->GetSwatchColor();
2597 
2598  std::map<wxString, KIGFX::COLOR4D>& netclassColors = rs->GetNetclassColorMap();
2599 
2600  if( color != COLOR4D::UNSPECIFIED )
2601  netclassColors[m_contextMenuNetclass] = color;
2602  else
2603  netclassColors.erase( m_contextMenuNetclass );
2604 
2605  view->UpdateAllLayersColor();
2606  }
2607 
2608  break;
2609  }
2610 
2611  case ID_HIGHLIGHT_NET:
2612  {
2613  if( netclass )
2614  {
2615  runOnNetsOfClass( netclass,
2616  [&]( NETINFO_ITEM* aItem )
2617  {
2618  if( !aItem )
2619  return;
2620 
2621  static bool first = true;
2622  int code = aItem->GetNet();
2623 
2624  if( first )
2625  {
2626  board->SetHighLightNet( code );
2627  rs->SetHighlight( true, code );
2628  first = false;
2629  }
2630  else
2631  {
2632  board->SetHighLightNet( code, true );
2633  rs->SetHighlight( true, code, true );
2634  }
2635  } );
2636 
2637  view->UpdateAllLayersColor();
2638  board->HighLightON();
2639  }
2640  break;
2641  }
2642 
2643  case ID_SELECT_NET:
2644  case ID_DESELECT_NET:
2645  {
2646  if( netclass )
2647  {
2648  TOOL_ACTION& action = aEvent.GetId() == ID_SELECT_NET ? PCB_ACTIONS::selectNet :
2650  runOnNetsOfClass( netclass,
2651  [&]( NETINFO_ITEM* aItem )
2652  {
2653  if( !aItem )
2654  return;
2655 
2656  int code = aItem->GetNet();
2657  m_frame->GetToolManager()->RunAction( action, true, code );
2658  } );
2659  }
2660  break;
2661  }
2662 
2663  case ID_SHOW_ALL_NETS:
2664  {
2665  showNetclass( defaultClassName );
2666  wxASSERT( m_netclassSettingsMap.count( defaultClassName ) );
2667  m_netclassSettingsMap.at( defaultClassName )->ctl_visibility->SetValue( true );
2668 
2669  for( const auto& pair : classes.NetClasses() )
2670  {
2671  showNetclass( pair.first );
2672 
2673  if( m_netclassSettingsMap.count( pair.first ) )
2674  m_netclassSettingsMap.at( pair.first )->ctl_visibility->SetValue( true );
2675  }
2676 
2677  break;
2678  }
2679 
2680  case ID_HIDE_OTHER_NETS:
2681  {
2682  bool showDefault = m_contextMenuNetclass == defaultClassName;
2683  showNetclass( defaultClassName, showDefault );
2684  wxASSERT( m_netclassSettingsMap.count( defaultClassName ) );
2685  m_netclassSettingsMap.at( defaultClassName )->ctl_visibility->SetValue( showDefault );
2686 
2687  for( const auto& pair : classes.NetClasses() )
2688  {
2689  bool show = pair.first == m_contextMenuNetclass;
2690 
2691  showNetclass( pair.first, show );
2692 
2693  if( m_netclassSettingsMap.count( pair.first ) )
2694  m_netclassSettingsMap.at( pair.first )->ctl_visibility->SetValue( show );
2695  }
2696 
2697  break;
2698  }
2699 
2700  default:
2701  break;
2702  }
2703 
2705  m_frame->GetCanvas()->Refresh();
2706 
2707  m_contextMenuNetclass.clear();
2708 }
2709 
2710 
2712 {
2713  m_focusOwner->SetFocus();
2714 }
2715 
2716 
2718 {
2719  WX_INFOBAR* infobar = m_frame->GetInfoBar();
2720 
2721  wxHyperlinkCtrl* button = new wxHyperlinkCtrl( infobar, wxID_ANY, _( "Open Preferences" ),
2722  wxEmptyString );
2723 
2724  button->Bind( wxEVT_COMMAND_HYPERLINK, std::function<void( wxHyperlinkEvent& aEvent )>(
2725  [&]( wxHyperlinkEvent& aEvent )
2726  {
2727  wxCommandEvent dummy;
2729  } ) );
2730 
2731  infobar->RemoveAllButtons();
2732  infobar->AddButton( button );
2733  infobar->AddCloseButton();
2734 
2735  infobar->ShowMessageFor( _( "The current color theme is read-only. Create a new theme in "
2736  "Preferences to enable color editing." ),
2737  10000, wxICON_INFORMATION );
2738 }
static std::set< int > s_allowedInFpEditor
These GAL layers are shown in the Objects tab in the footprint editor.
void OnSize(wxSizeEvent &aEvent) override
static LSET AllCuMask(int aCuLayerCount=MAX_CU_LAYERS)
Return a mask holding the requested number of Cu PCB_LAYER_IDs.
Definition: lset.cpp:749
void ShowMessageFor(const wxString &aMessage, int aTime, int aFlags=wxICON_INFORMATION)
Show the infobar with the provided message and icon for a specific period of time.
Definition: infobar.cpp:109
static LAYER_PRESET presetFrontAssembly
void AddListener(BOARD_LISTENER *aListener)
Add a listener to the board to receive calls whenever something on the board has been modified.
A saved set of layers that are visible.
std::set< int > & GetHiddenNets()
Definition: pcb_painter.h:184
bool SetBackgroundColour(const wxColour &aColor) override
void SetIndicatorState(ICON_ID aIconId)
Sets the row indiciator to the given state.
void onObjectOpacitySlider(int aLayer, float aOpacity)
LSEQ CuStack() const
Return a sequence of copper layers in starting from the front/top and extending to the back/bottom.
Definition: lset.cpp:169
show a marker on pads with no nets
std::map< PCB_LAYER_ID, APPEARANCE_SETTING * > m_layerSettingsMap
void AddButton(wxButton *aButton)
Add an already created button to the infobar.
Definition: infobar.cpp:185
void OnNetGridMouseEvent(wxMouseEvent &aEvent)
#define RR
Icon provider for the "standard" row indicators, for example in layer selection lists.
KIGFX::COLOR4D GetSwatchColor() const
wxString GetTextSelection(int aColumn=0)
Function GetTextSelection return the selected text from aColumn in the wxListCtrl in the dialog.
static COLOR4D VoidToColor(void *aColor)
Class APPEARANCE_CONTROLS_BASE.
NETCLASSPTR Find(const wxString &aName) const
Function Find searches this container for a NETCLASS given by aName.
Definition: netclass.cpp:132
const wxString GetLayerName(PCB_LAYER_ID aLayer) const
Return the name of a aLayer.
void OnBoardItemRemoved(BOARD &aBoard, BOARD_ITEM *aBoardItem) override
void * GetValueAsCustom(int aRow, int aCol, const wxString &aTypeName) override
void HideOtherNets(const NET_GRID_ENTRY &aNet)
void ApplyLayerPreset(const wxString &aPresetName)
Ratsnest lines are drawn to items on visible layers only.
multilayer pads, usually with holes
#define ON
int GetNetnameLayer(int aLayer)
Returns a netname layer corresponding to the given layer.
WX_COLLAPSIBLE_PANE * m_paneLayerDisplayOptions
void SetValueAsCustom(int aRow, int aCol, const wxString &aTypeName, void *aValue) override
BOARD_ITEM is a base class for any item which can be embedded within the BOARD container class,...
static LSET ForbiddenFootprintLayers()
Layers which are not allowed within footprint definitions.
Definition: lset.cpp:880
std::vector< std::unique_ptr< APPEARANCE_SETTING > > m_layerSettings
GAL_LAYER_ID ToGalLayer(int aInteger)
static TOOL_ACTION hideNet
Definition: pcb_actions.h:445
const BITMAP_OPAQUE options_generic_xpm[1]
wxMenuItem * AddMenuItem(wxMenu *aMenu, int aId, const wxString &aText, const wxBitmap &aImage, wxItemKind aType=wxITEM_NORMAL)
Function AddMenuItem is an inline helper function to create and insert a menu item with an icon into ...
Definition: bitmap.cpp:234
double m_TrackOpacity
Opacity override for all tracks.
anchor of items having an anchor point (texts, footprints)
void SetTabIndex(int aTab)
Sets the current notebook tab
Control for copper zone opacity/visibility (color ignored)
NETCLASS_MAP & NetClasses()
Provide public access to m_NetClasses so it gets swigged.
Definition: netclass.h:302
LAYER_PRESET * m_lastSelectedUserPreset
The last user (non-read-only) preset selected by the user.
virtual COLOR_SETTINGS * GetColorSettings() override
Helper to retrieve the current color settings.
std::map< wxString, KIGFX::COLOR4D > & GetNetclassColorMap()
Definition: pcb_painter.h:180
PCB_DRAW_PANEL_GAL * GetCanvas() const override
Return a pointer to GAL-based canvas of given EDA draw frame.
std::map< int, wxString > m_netclassIdMap
Stores wxIDs for each netclass for control event mapping.
static TOOL_ACTION selectNet
Selects all connections belonging to a single net.
Definition: pcb_actions.h:80
bool Contains(PCB_LAYER_ID aLayer)
See if the layer set contains a PCB layer.
void onNetColorModeChanged(wxCommandEvent &aEvent)
int color
Definition: DXF_plotter.cpp:60
wxRadioButton * m_rbNetColorOff
double m_ViaOpacity
Opacity override for all types of via.
wxStaticLine * m_layerDisplaySeparator
void idleFocusHandler(wxIdleEvent &aEvent)
const BITMAP_OPAQUE show_no_copper_layers_xpm[1]
const BITMAP_OPAQUE select_layer_pair_xpm[1]
Net/netclass colors are shown on all net copper.
Net/netclass colors are shown on ratsnest lines only.
wxRadioButton * m_rbRatsnestAllLayers
show footprints on back
PROJECT * GetProject() const
Definition: class_board.h:397
GAL_LAYER_ID
GAL layers are "virtual" layers, i.e.
LSET GetVisibleLayers() const
A proxy function that calls the correspondent function in m_BoardSettings Returns a bit-mask of all t...
bool RunAction(const std::string &aActionName, bool aNow=false, T aParam=NULL)
Function RunAction() Runs the specified action.
Definition: tool_manager.h:141
COLOR4D color
void SetVisibleElements(const GAL_SET &aMask)
A proxy function that calls the correspondent function in m_BoardSettings changes the bit-mask of vis...
show footprints values (when texts are visibles)
static void * ColorToVoid(COLOR4D &aColor)
BOARD_DESIGN_SETTINGS & GetDesignSettings() const
Definition: class_board.h:558
EDA_LIST_DIALOG.
const NETINFO_LIST & GetNetInfo() const
Definition: class_board.h:724
NET_GRID_TABLE(PCB_BASE_FRAME *aFrame, wxColor aBackgroundColor)
void SetValue(bool aValue)
Set the checkbox state
wxRadioButton * m_rbHighContrastOff
void SetDisplayOptions(const PCB_DISPLAY_OPTIONS &aOptions)
LSET GetEnabledLayers() const
A proxy function that calls the corresponding function in m_BoardSettings Returns a bit-mask of all t...
wxGridCellAttr * m_defaultAttr
void SetDrawBgColor(COLOR4D aColor) override
void OnNetGridClick(wxGridEvent &event) override
void SetReadOnly(bool aReadOnly=true)
Definition: color_swatch.h:104
void SetTable(wxGridTableBase *table, bool aTakeOwnership=false)
Hide wxGrid's SetTable() method with one which doesn't mess up the grid column widths when setting th...
Definition: wx_grid.cpp:65
int code
LSEQ Seq(const PCB_LAYER_ID *aWishListSequence, unsigned aCount) const
Return an LSEQ from the union of this LSET and a desired sequence.
Definition: lset.cpp:410
void OnLayerChanged()
Updates the widget when the active board layer is changed
PCB_PAINTER Contains methods for drawing PCB-specific items.
Definition: pcb_painter.h:260
const PCB_DISPLAY_OPTIONS & GetDisplayOptions() const
Function GetDisplayOptions Display options control the way tracks, vias, outlines and other things ar...
GAL_SET renderLayers
Render layers (e.g. object types) that are visible.
static LSET FrontMask()
Return a mask holding all technical layers and the external CU layer on front side.
Definition: lset.cpp:866
PCB_LAYER_ID activeLayer
Optional layer to set active when this preset is loaded.
void SetReadOnlyCallback(std::function< void()> aCallback)
Registers a handler for when the user tries to interact with a read-only swatch.
Definition: color_swatch.h:108
std::map< GAL_LAYER_ID, APPEARANCE_SETTING * > m_objectSettingsMap
const BITMAP_OPAQUE show_all_copper_layers_xpm[1]
PAINTER * GetPainter() const
Function GetPainter() Returns the painter object used by the view for drawing VIEW_ITEMS.
Definition: view.h:201
A checkbox control except with custom bitmaps for the checked and unchecked states.
Definition: bitmap_toggle.h:41
void RedrawRatsnest()
Forces refresh of the ratsnest visual representation
bool visible
wxScrolledWindow * m_netclassScrolledWindow
Ratsnest lines are drawn to items on all layers (default)
Auxiliary rendering target (noncached)
Definition: definitions.h:49
PCB_BASE_FRAME * m_frame
const NETNAMES_MAP & NetsByName() const
Function GetPadCount.
Definition: netinfo.h:471
void OnBoardChanged()
Updates the panel contents from the application and board models
show footprints on front
virtual PCB_LAYER_ID GetActiveLayer() const
wxString name
A name for this layer set.
void onRatsnestModeChanged(wxCommandEvent &aEvent)
PCB_RENDER_SETTINGS Stores PCB specific render settings.
Definition: pcb_painter.h:64
TOOL_MANAGER.
Definition: tool_manager.h:51
void showNetclass(const wxString &aClassName, bool aShow=true)
wxBitmap KiBitmap(BITMAP_DEF aBitmap)
Construct a wxBitmap from a memory record, held in a BITMAP_DEF.
Definition: bitmap.cpp:82
RATSNEST_MODE m_RatsnestMode
Ratsnest draw mode (all layers vs only visible layers)
static LSET BackAssembly()
Return a complete set of all bottom assembly layers which is all B_SilkS and B_Mask.
Definition: lset.cpp:695
PCB_DISPLAY_OPTIONS handles display options like enable/disable some optional drawings.
Non-active layers are shown normally (no high-contrast mode)
PCB_LAYER_ID
A quick note on layer IDs:
representing a row indicator icon for use in places like the layer widget
double a
Alpha component.
Definition: color4d.h:377
void OnBoardNetSettingsChanged(BOARD &aBoard) override
LSET is a set of PCB_LAYER_IDs.
static LAYER_PRESET presetNoLayers
NETCLASSES is a container for NETCLASS instances.
Definition: netclass.h:224
void OnNetGridDoubleClick(wxGridEvent &event) override
GRID_BITMAP_TOGGLE_RENDERER * m_toggleGridRenderer
const BITMAP_OPAQUE show_all_back_layers_xpm[1]
bool readOnly
True if this is a read-only (built-in) preset.
void onNetclassVisibilityChanged(wxCommandEvent &aEvent)
void OnBoardItemChanged(BOARD &aBoard, BOARD_ITEM *aBoardItem) override
void Refresh()
Update the board display after modifying it by a python script (note: it is automatically called by a...
const BITMAP_OPAQUE select_w_layer_xpm[1]
virtual PCB_RENDER_SETTINGS * GetSettings() override
Definition: pcb_painter.h:272
const BITMAP_OPAQUE list_nets_xpm[1]
Definition: list_nets.cpp:41
void MarkTargetDirty(int aTarget)
Function MarkTargetDirty() Sets or clears target 'dirty' flag.
Definition: view.h:571
wxGridCellAttr * m_labelAttr
NETINFO_LIST is a container class for NETINFO_ITEM elements, which are the nets.
Definition: netinfo.h:422
std::map< wxString, APPEARANCE_SETTING * > m_netclassSettingsMap
void SetVisibleLayers(LSET aLayerMask)
A proxy function that calls the correspondent function in m_BoardSettings changes the bit-mask of vis...
std::map< wxString, LAYER_PRESET > m_layerPresets
GAL_SET GetVisibleElements() const
Returns a set of all the element categories that are visible.
void OnSetFocus(wxFocusEvent &aEvent) override
ROW_ICON_PROVIDER * m_iconProvider
void setVisibleLayers(LSET aLayers)
void doApplyLayerPreset(const LAYER_PRESET &aPreset)
Meta control for all pads opacity/visibility (color ignored)
NETCLASS handles a collection of nets and the parameters used to route or test these nets.
Definition: netclass.h:49
HIGH_CONTRAST_MODE
Determines how inactive layers should be displayed.
const BITMAP_OPAQUE shape_3d_back_xpm[1]
COLOR4D GetDefaultColor(int aLayer)
Helper for storing and iterating over GAL_LAYER_IDs.
static LSET InternalCuMask()
Return a complete set of internal copper layers which is all Cu layers except F_Cu and B_Cu.
Definition: lset.cpp:709
const BITMAP_OPAQUE show_all_layers_xpm[1]
LAYER_PRESET * m_currentPreset
Helper dialog and control classes.
wxRadioButton * m_rbHighContrastNormal
static GAL_SET DefaultVisible()
Definition: lset.cpp:925
void SetPadding(int aPadding)
Set the amount of padding present on each side of the bitmap.
void onLayerClick(wxMouseEvent &aEvent)
wxStaticText * m_txtNetDisplayTitle
void onNetContextMenu(wxCommandEvent &aEvent)
static LSET FrontAssembly()
Return a complete set of all top assembly layers which is all F_SilkS and F_Mask.
Definition: lset.cpp:681
HIGH_CONTRAST_MODE m_ContrastModeDisplay
How inactive layers are displayed.
wxBoxSizer * m_objectsOuterSizer
NETCLASSES & GetNetClasses() const
static LSET AllLayersMask()
Definition: lset.cpp:786
void SetLayerVisible(int aLayer, bool aVisible=true)
Function SetLayerVisible() Controls the visibility of a particular layer.
Definition: view.h:385
const BITMAP_OPAQUE visibility_xpm[1]
Definition: visibility.cpp:29
wxGridCellAttr * GetAttr(int aRow, int aCol, wxGridCellAttr::wxAttrKind) override
virtual void SetActiveLayer(PCB_LAYER_ID aLayer)
LSET layers
Board layers that are visible.
NETCLASS * GetDefaultPtr() const
Definition: netclass.h:271
void SyncLayersVisibility(const BOARD *aBoard)
Function SyncLayersVisibility Updates "visibility" property of each layer of a given BOARD.
void SetUserLayerPresets(std::vector< LAYER_PRESET > &aPresetList)
Updates the current layer presets from those saved in the project file
int GetTabIndex() const
Returns the index of the current tab (0-2)
Container for an appearance setting (can control a single board layer, or GAL layer,...
virtual KIGFX::PCB_VIEW * GetView() const override
Function GetView() Returns a pointer to the VIEW instance used in the panel.
APPEARANCE_CONTROLS(PCB_BASE_FRAME *aParent, wxWindow *aFocusOwner, bool aFpEditor=false)
const BITMAP_OPAQUE shape_3d_xpm[1]
Definition: shape_3d.cpp:36
std::vector< LAYER_PRESET > GetUserLayerPresets() const
Returns a list of the layer presets created by the user
void OnBoardItemAdded(BOARD &aBoard, BOARD_ITEM *aBoardItem) override
std::vector< std::unique_ptr< APPEARANCE_SETTING > > m_netclassSettings
void RemoveAllButtons()
Remove all the buttons that have been added by the user.
Definition: infobar.cpp:226
LSEQ is a sequence (and therefore also a set) of PCB_LAYER_IDs.
virtual void Refresh(bool aEraseBackground=true, const wxRect *aRect=NULL) override
Update the board display after modifying it by a python script (note: it is automatically called by a...
double m_ZoneOpacity
Opacity override for filled zone areas.
void UpdateColors()
Updates the color settings in the painter and GAL.
int LAYER_NUM
This can be replaced with int and removed.
void onLayerPresetChanged(wxCommandEvent &aEvent) override
bool IsMirroredX() const
Function IsMirroredX() Returns true if view is flipped across the X axis.
Definition: view.h:232
wxRadioButton * m_rbHighContrastDim
layer for drc markers which have been individually excluded
NET_GRID_ENTRY & GetEntry(int aRow)
bool GetValueAsBool(int aRow, int aCol) override
layer for drc markers with SEVERITY_WARNING
int GetRowByNetcode(int aCode) const
void UpdateLayerColor(int aLayer)
Function UpdateLayerColor() Applies the new coloring scheme held by RENDER_SETTINGS in case that it h...
Definition: view.cpp:755
void SetValueAsBool(int aRow, int aCol, bool aValue) override
void updateLayerPresetSelection(const wxString &aName)
A modified version of the wxInfoBar class that allows us to:
Definition: infobar.h:70
virtual RENDER_SETTINGS * GetSettings()=0
Function GetAdapter Returns pointer to current settings that are going to be used when drawing items.
static LAYER_PRESET presetInnerCopper
COLOR4D GetColor(int aLayer) const
NETINFO_ITEM handles the data for a net.
Definition: netinfo.h:65
double m_PadOpacity
Opacity override for SMD pads and PTHs.
static TOOL_ACTION showNet
Definition: pcb_actions.h:446
int GetId() const
Returns the unique id of the TOOL_ACTION object.
Definition: tool_action.h:94
Meta control for all vias opacity/visibility.
static TOOL_ACTION highlightNet
Definition: pcb_actions.h:440
bool IsType(FRAME_T aType) const
void SetHighlight(bool aEnabled, int aNetcode=-1, bool aMulti=false)
Function SetHighlight Turns on/off highlighting - it may be done for the active layer or the specifie...
const char * name
Definition: DXF_plotter.cpp:59
void Format(OUTPUTFORMATTER *out, int aNestLevel, int aCtl, CPTREE &aTree)
Function Format outputs a PTREE into s-expression format via an OUTPUTFORMATTER derivative.
Definition: ptree.cpp:201
static LIB_PART * dummy()
Used to draw a dummy shape when a LIB_PART is not found in library.
int GetNet() const
Function GetNet.
Definition: netinfo.h:223
static LAYER_PRESET presetBackAssembly
Information pertinent to a Pcbnew printed circuit board.
Definition: class_board.h:186
void setVisibleObjects(GAL_SET aObjects)
std::vector< std::unique_ptr< APPEARANCE_SETTING > > m_objectSettings
void SetBitmap(const wxBitmap &aBmp)
Set the bitmap shown when the button is enabled.
#define _(s)
Definition: 3d_actions.cpp:33
Net (and netclass) colors are not shown.
static TOOL_ACTION listNets
Definition: pcb_actions.h:337
A toggle button renderer for a wxGrid, similar to BITMAP_TOGGLE.
class NETINFO_ITEM, a description of a net
Definition: typeinfo.h:108
Represents a single user action.
Definition: tool_action.h:44
NET_GRID_TABLE * m_netsTable
wxString GetTypeName(int aRow, int aCol) override
int GetCopperLayerCount() const
wxString netclassNameFromEvent(wxEvent &aEvent)
static float distance(const SFVEC2UI &a, const SFVEC2UI &b)
wxString GetValue(int aRow, int aCol) override
PCB_EDIT_FRAME is the main frame for Pcbnew.
Class representing a simple color swatch, of the kind used to set layer colors.
Definition: color_swatch.h:57
void SetValue(int aRow, int aCol, const wxString &aValue) override
void OnNotebookPageChanged(wxNotebookEvent &event) override
bool IsReadOnly() const
Definition: json_settings.h:74
void onObjectVisibilityChanged(GAL_LAYER_ID aLayer, bool isVisible, bool isFinal)
void onNetclassColorChanged(wxCommandEvent &aEvent)
static LSET BackMask()
Return a mask holding all technical layers and the external CU layer on back side.
Definition: lset.cpp:873
static const wxSize SWATCH_SIZE_SMALL_DU(8, 6)
static TOOL_ACTION deselectNet
Removes all connections belonging to a single net from the active selection.
Definition: pcb_actions.h:83
void OnPreferences(wxCommandEvent &event)
wxString name
void GetNewSwatchColor()
Prompt for a new colour, using the colour picker dialog.
Color settings are a bit different than most of the settings objects in that there can be more than o...
wxGridCellCoords m_hoveredCell
Grid cell that is being hovered over, for tooltips.
NETCLASSPTR GetDefault() const
Function GetDefault.
Definition: netclass.h:266
WX_INFOBAR * GetInfoBar()
wxBoxSizer * m_layersOuterSizer
std::vector< NET_GRID_ENTRY > m_nets
void SetLayerVisible(LAYER_NUM aLayer, bool isVisible)
Manually update visibility for a given layer
const BITMAP_OPAQUE show_all_front_layers_xpm[1]
wxString m_contextMenuNetclass
The name of the netclass that was right-clicked.
TOOL_MANAGER * GetToolManager() const
Return the MVC controller.
Definition: tools_holder.h:76
void onNetclassContextMenu(wxCommandEvent &aEvent)
Non-active layers are dimmed (old high-contrast mode)
void OnNetGridRightClick(wxGridEvent &event) override
std::map< int, KIGFX::COLOR4D > & GetNetColorMap()
Definition: pcb_painter.h:182
static TOOL_ACTION flipBoard
Definition: pcb_actions.h:291
BOARD * GetBoard() const
PCB_BASE_FRAME * m_frame
void OnColorSwatchChanged(wxCommandEvent &aEvent)
VIEW.
Definition: view.h:63
void onLayerVisibilityChanged(PCB_LAYER_ID aLayer, bool isVisible, bool isFinal)
void OnLayerContextMenu(wxCommandEvent &aEvent)
NETINFO_ITEM * GetNetItem(int aNetCode) const
Function GetItem.
void UpdateAllLayersColor()
Function UpdateAllLayersColor() Applies the new coloring scheme to all layers.
Definition: view.cpp:776
void Collapse(bool aCollapse=true)
static LAYER_PRESET presetFront
void OnColorThemeChanged()
Updates the colors on all the widgets from the new chosen color theme
wxStaticText * m_txtRatsnestVisibility
A better wxCollapsiblePane that.
static LAYER_PRESET presetAllCopper
void updateNetColor(const NET_GRID_ENTRY &aNet)
static const APPEARANCE_SETTING s_objectSettings[]
Template for object appearance settings.
Definition of PCB_DISPLAY_OPTIONS class.
void OnLayerAlphaChanged()
Updates the manual layer alpha overrides
static LAYER_PRESET presetAllLayers
PCB_LAYER_ID ToLAYER_ID(int aLayer)
Definition: lset.cpp:897
virtual void SetGridVisibility(bool aVisible)
PCB_BASE_FRAME basic PCB main window class for Pcbnew, Gerbview, and CvPcb footprint viewer.
const BITMAP_OPAQUE visibility_off_xpm[1]
void updateNetVisibility(const NET_GRID_ENTRY &aNet)
void SetColLabelSize(int aHeight)
Hide wxGrid's SetColLabelSize() method with one which makes sure the size is tall enough for the syst...
Definition: wx_grid.cpp:49
show footprints references (when texts are visibles)
wxStaticText * m_staticTextContrastModeTitle
layer for drc markers with SEVERITY_ERROR
virtual LSET GetLayerSet() const
Function GetLayerSet returns a std::bitset of all layers on which the item physically resides.
void SetObjectVisible(GAL_LAYER_ID aLayer, bool isVisible=true)
const BITMAP_OPAQUE show_no_layers_xpm[1]
A text renderer that can unescape text for display This is useful where it's desired to keep the unde...
WX_COLLAPSIBLE_PANE * m_paneNetDisplayOptions
NET_COLOR_MODE m_NetColorMode
How to use color overrides on specific nets and netclasses.
KICAD_T Type() const
Function Type()
Definition: eda_item.h:182
wxRadioButton * m_rbRatsnestVisibleLayers
void SetColor(int aLayer, COLOR4D aColor)
bool IsLayerVisible(int aLayer) const
Function IsLayerVisible() Returns information about visibility of a particular layer.
Definition: view.h:402
void AddCloseButton(const wxString &aTooltip=_("Hide this message."))
Add the default close button to the infobar on the right side.
Definition: infobar.cpp:216
static LAYER_PRESET presetBack
wxRadioButton * m_rbNetColorRatsnest
COLOR4D is the color representation with 4 components: red, green, blue, alpha.
Definition: color4d.h:100
wxRadioButton * m_rbNetColorAll
void SetListLabel(const wxString &aLabel)
bool Contains(GAL_LAYER_ID aPos)