1 /*
2  * This program source code file is part of KiCad, a free EDA CAD application.
3  *
4  * Copyright (C) 2012 Jean-Pierre Charras, jean-pierre.charras@ujf-grenoble.fr
5  * Copyright (C) 2012 SoftPLC Corporation, Dick Hollenbeck <dick@softplc.com>
6  * Copyright (C) 2012 Wayne Stambaugh <stambaughw@gmail.com>
7  * Copyright (C) 1992-2021 KiCad Developers, see AUTHORS.txt for contributors.
8  *
9  * This program is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU General Public License
11  * as published by the Free Software Foundation; either version 2
12  * of the License, or (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, you may find one here:
21  * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
22  * or you may search the http://www.gnu.org website for the version 2 license,
23  * or you may write to the Free Software Foundation, Inc.,
24  * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
25  */
26 
27 #include <memory>
28 
29 #include <advanced_config.h>
30 #include <bitmaps.h>
31 #include <board.h>
32 #include <board_design_settings.h>
33 #include <kiface_base.h>
34 #include <macros.h>
35 #include <pcb_edit_frame.h>
36 #include <pcb_layer_box_selector.h>
37 #include <pcbnew_id.h>
38 #include <pcbnew_settings.h>
39 #include <pgm_base.h>
40 #include <router/pns_routing_settings.h>
41 #include <router/router_tool.h>
42 #include <settings/color_settings.h>
43 #include <tool/action_toolbar.h>
44 #include <tool/actions.h>
45 #include <tool/common_tools.h>
46 #include <tool/tool_manager.h>
47 #include <tools/pcb_actions.h>
48 #include <tools/pcb_selection_tool.h>
49 #include <widgets/appearance_controls.h>
50 #include <widgets/wx_aui_utils.h>
51 #include <wx/wupdlock.h>
52 #include <wx/dcmemory.h>
53 #include <wx/choice.h>
54 
55 #include "../scripting/python_scripting.h"
56 
57 
58 /* Data to build the layer pair indicator button */
59 static std::unique_ptr<wxBitmap> LayerPairBitmap;
60 
61 #define BM_LAYERICON_SIZE 24
62 static const char s_BitmapLayerIcon[BM_LAYERICON_SIZE][BM_LAYERICON_SIZE] =
63 {
64     // 0 = draw pixel with white
65     // 1 = draw pixel with black
66     // 2 = draw pixel with top layer from router pair
67     // 3 = draw pixel with bottom layer from router pair
68     { 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 1, 0, 3, 3, 3, 3, 3 },
69     { 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 1, 0, 3, 3, 3, 3, 3 },
70     { 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 1, 0, 3, 3, 3, 3, 3, 3 },
71     { 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 1, 0, 3, 3, 3, 3, 3, 3 },
72     { 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 1, 0, 3, 3, 3, 3, 3, 3, 3 },
73     { 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 1, 0, 3, 3, 3, 3, 3, 3, 3 },
74     { 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 1, 0, 3, 3, 3, 3, 3, 3, 3, 3 },
75     { 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 1, 0, 3, 3, 3, 3, 3, 3, 3, 3 },
76     { 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 1, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3 },
77     { 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 1, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3 },
78     { 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 1, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 },
79     { 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 1, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 },
80     { 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 1, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 },
81     { 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 1, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 },
82     { 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 1, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 },
83     { 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 1, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 },
84     { 2, 2, 2, 2, 2, 2, 2, 2, 0, 1, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 },
85     { 2, 2, 2, 2, 2, 2, 2, 2, 0, 1, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 },
86     { 2, 2, 2, 2, 2, 2, 2, 0, 1, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 },
87     { 2, 2, 2, 2, 2, 2, 2, 0, 1, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 },
88     { 2, 2, 2, 2, 2, 2, 0, 1, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 },
89     { 2, 2, 2, 2, 2, 2, 0, 1, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 },
90     { 2, 2, 2, 2, 2, 0, 1, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 },
91     { 2, 2, 2, 2, 2, 0, 1, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 },
92 };
93 
94 static COLOR4D ICON_WHITE { 0.86, 0.86, 0.86, 1.0 };
95 static COLOR4D ICON_BLACK { 0.28, 0.28, 0.28, 1.0 };
96 
97 
PrepareLayerIndicator(bool aForceRebuild)98 void PCB_EDIT_FRAME::PrepareLayerIndicator( bool aForceRebuild )
99 {
100     int        ii, jj;
101     COLOR4D    top_color, bottom_color, background_color;
102     bool       change = aForceRebuild;
103 
104     int requested_scale = Pgm().GetCommonSettings()->m_Appearance.icon_scale;
105 
106     if( m_prevIconVal.previous_requested_scale != requested_scale )
107     {
108         m_prevIconVal.previous_requested_scale = requested_scale;
109         change = true;
110     }
111 
112     top_color = GetColorSettings()->GetColor( GetScreen()->m_Route_Layer_TOP );
113 
114     if( m_prevIconVal.previous_Route_Layer_TOP_color != top_color )
115     {
116         m_prevIconVal.previous_Route_Layer_TOP_color = top_color;
117         change = true;
118     }
119 
120     bottom_color = GetColorSettings()->GetColor( GetScreen()->m_Route_Layer_BOTTOM );
121 
122     if( m_prevIconVal.previous_Route_Layer_BOTTOM_color != bottom_color )
123     {
124         m_prevIconVal.previous_Route_Layer_BOTTOM_color = bottom_color;
125         change = true;
126     }
127 
128     background_color = GetColorSettings()->GetColor( LAYER_PCB_BACKGROUND );
129 
130     if( m_prevIconVal.previous_background_color != background_color )
131     {
132         m_prevIconVal.previous_background_color = background_color;
133         change = true;
134     }
135 
136     if( change || !LayerPairBitmap )
137     {
138         LayerPairBitmap = std::make_unique<wxBitmap>( 24, 24 );
139 
140         // Draw the icon, with colors according to the router's layer pair
141         wxMemoryDC iconDC;
142         iconDC.SelectObject( *LayerPairBitmap );
143         wxBrush    brush;
144         wxPen      pen;
145         int buttonColor = -1;
146 
147         brush.SetStyle( wxBRUSHSTYLE_SOLID );
148         brush.SetColour( background_color.WithAlpha(1.0).ToColour() );
149         iconDC.SetBrush( brush );
150         iconDC.DrawRectangle( 0, 0, BM_LAYERICON_SIZE, BM_LAYERICON_SIZE );
151 
152         for( ii = 0; ii < BM_LAYERICON_SIZE; ii++ )
153         {
154             for( jj = 0; jj < BM_LAYERICON_SIZE; jj++ )
155             {
156                 if( s_BitmapLayerIcon[ii][jj] != buttonColor )
157                 {
158                     switch( s_BitmapLayerIcon[ii][jj] )
159                     {
160                     default:
161                     case 0: pen.SetColour( ICON_WHITE.ToColour() );   break;
162                     case 1: pen.SetColour( ICON_BLACK.ToColour() );   break;
163                     case 2: pen.SetColour( top_color.ToColour() );    break;
164                     case 3: pen.SetColour( bottom_color.ToColour() ); break;
165                     }
166 
167                     buttonColor = s_BitmapLayerIcon[ii][jj];
168                     iconDC.SetPen( pen );
169                 }
170 
171                 iconDC.DrawPoint( jj, ii );
172             }
173         }
174 
175         // Deselect the bitmap from the DC in order to delete the MemoryDC safely without
176         // deleting the bitmap
177         iconDC.SelectObject( wxNullBitmap );
178 
179         // Scale the bitmap
180         const int scale = ( requested_scale <= 0 ) ? KiIconScale( this ) : requested_scale;
181         wxImage image = LayerPairBitmap->ConvertToImage();
182 
183         // "NEAREST" causes less mixing of colors
184         image.Rescale( scale * image.GetWidth() / 4, scale * image.GetHeight() / 4,
185                        wxIMAGE_QUALITY_NEAREST );
186 
187         LayerPairBitmap = std::make_unique<wxBitmap>( image );
188 
189         if( m_mainToolBar )
190         {
191             m_mainToolBar->SetToolBitmap( PCB_ACTIONS::selectLayerPair, *LayerPairBitmap );
192             m_mainToolBar->Refresh();
193         }
194     }
195 }
196 
197 
ReCreateHToolbar()198 void PCB_EDIT_FRAME::ReCreateHToolbar()
199 {
200     // Note:
201     // To rebuild the aui toolbar, the more easy way is to clear ( calling m_mainToolBar.Clear() )
202     // all wxAuiToolBarItems.
203     // However the wxAuiToolBarItems are not the owners of controls managed by
204     // them and therefore do not delete them
205     // So we do not recreate them after clearing the tools.
206 
207     wxWindowUpdateLocker dummy( this );
208 
209     if( m_mainToolBar )
210     {
211         m_mainToolBar->ClearToolbar();
212     }
213     else
214     {
215         m_mainToolBar = new ACTION_TOOLBAR( this, ID_H_TOOLBAR, wxDefaultPosition, wxDefaultSize,
216                                             KICAD_AUI_TB_STYLE | wxAUI_TB_HORZ_LAYOUT |
217                                             wxAUI_TB_HORIZONTAL );
218         m_mainToolBar->SetAuiManager( &m_auimgr );
219 
220         // The layer indicator is special, so we register a callback directly that will
221         // regenerate the bitmap instead of using the conditions system.
222         auto layerIndicatorUpdate =
223             [this] ( wxUpdateUIEvent& )
224             {
225                 PrepareLayerIndicator();
226             };
227 
228         Bind( wxEVT_UPDATE_UI, layerIndicatorUpdate, PCB_ACTIONS::selectLayerPair.GetUIId() );
229     }
230 
231     // Set up toolbar
232     if( Kiface().IsSingle() )
233     {
234         m_mainToolBar->Add( ACTIONS::doNew );
235         m_mainToolBar->Add( ACTIONS::open );
236     }
237 
238     m_mainToolBar->Add( ACTIONS::save );
239 
240     m_mainToolBar->AddScaledSeparator( this );
241     m_mainToolBar->Add( PCB_ACTIONS::boardSetup );
242 
243     m_mainToolBar->AddScaledSeparator( this );
244     m_mainToolBar->Add( ACTIONS::pageSettings );
245     m_mainToolBar->Add( ACTIONS::print );
246     m_mainToolBar->Add( ACTIONS::plot );
247 
248     m_mainToolBar->AddScaledSeparator( this );
249     m_mainToolBar->Add( ACTIONS::undo );
250     m_mainToolBar->Add( ACTIONS::redo );
251 
252     m_mainToolBar->AddScaledSeparator( this );
253     m_mainToolBar->Add( ACTIONS::find );
254 
255     m_mainToolBar->AddScaledSeparator( this );
256     m_mainToolBar->Add( ACTIONS::zoomRedraw );
257     m_mainToolBar->Add( ACTIONS::zoomInCenter );
258     m_mainToolBar->Add( ACTIONS::zoomOutCenter );
259     m_mainToolBar->Add( ACTIONS::zoomFitScreen );
260     m_mainToolBar->Add( ACTIONS::zoomFitObjects );
261     m_mainToolBar->Add( ACTIONS::zoomTool, ACTION_TOOLBAR::TOGGLE, ACTION_TOOLBAR::CANCEL );
262 
263     m_mainToolBar->AddScaledSeparator( this );
264     m_mainToolBar->Add( PCB_ACTIONS::rotateCcw );
265     m_mainToolBar->Add( PCB_ACTIONS::rotateCw );
266     m_mainToolBar->Add( PCB_ACTIONS::group );
267     m_mainToolBar->Add( PCB_ACTIONS::ungroup );
268     m_mainToolBar->Add( PCB_ACTIONS::lock );
269     m_mainToolBar->Add( PCB_ACTIONS::unlock );
270 
271     m_mainToolBar->AddScaledSeparator( this );
272     m_mainToolBar->Add( ACTIONS::showFootprintEditor );
273     m_mainToolBar->Add( ACTIONS::showFootprintBrowser );
274 
275     m_mainToolBar->AddScaledSeparator( this );
276 
277     if( !Kiface().IsSingle() )
278         m_mainToolBar->Add( ACTIONS::updatePcbFromSchematic );
279     else
280         m_mainToolBar->Add( PCB_ACTIONS::importNetlist );
281 
282     m_mainToolBar->Add( PCB_ACTIONS::runDRC );
283 
284     m_mainToolBar->AddScaledSeparator( this );
285 
286     if( m_SelLayerBox == nullptr )
287     {
288         m_SelLayerBox = new PCB_LAYER_BOX_SELECTOR( m_mainToolBar, ID_TOOLBARH_PCB_SELECT_LAYER );
289         m_SelLayerBox->SetBoardFrame( this );
290     }
291 
292     ReCreateLayerBox( false );
293     m_mainToolBar->AddControl( m_SelLayerBox );
294 
295     m_mainToolBar->Add( PCB_ACTIONS::selectLayerPair );
296     PrepareLayerIndicator( true );    // Force rebuild of the bitmap with the active layer colors
297 
298     m_mainToolBar->AddScaledSeparator( this );
299     m_mainToolBar->Add( PCB_ACTIONS::showEeschema );
300 
301     // Access to the scripting console
302     if( SCRIPTING::IsWxAvailable() )
303     {
304         m_mainToolBar->AddScaledSeparator( this );
305         m_mainToolBar->Add( PCB_ACTIONS::showPythonConsole, ACTION_TOOLBAR::TOGGLE );
306         AddActionPluginTools();
307     }
308 
309     // Go through and ensure the comboboxes are the correct size, since the strings in the
310     // box could have changed widths.
311     m_mainToolBar->UpdateControlWidth( ID_TOOLBARH_PCB_SELECT_LAYER );
312 
313     // after adding the buttons to the toolbar, must call Realize() to reflect the changes
314     m_mainToolBar->KiRealize();
315 }
316 
317 
ReCreateOptToolbar()318 void PCB_EDIT_FRAME::ReCreateOptToolbar()
319 {
320     // Note:
321     // To rebuild the aui toolbar, the more easy way is to clear ( calling m_mainToolBar.Clear() )
322     // all wxAuiToolBarItems.
323     // However the wxAuiToolBarItems are not the owners of controls managed by
324     // them and therefore do not delete them
325     // So we do not recreate them after clearing the tools.
326 
327     wxWindowUpdateLocker dummy( this );
328 
329     if( m_optionsToolBar )
330     {
331         m_optionsToolBar->ClearToolbar();
332     }
333     else
334     {
335         m_optionsToolBar = new ACTION_TOOLBAR( this, ID_OPT_TOOLBAR,
336                                                wxDefaultPosition, wxDefaultSize,
337                                                KICAD_AUI_TB_STYLE | wxAUI_TB_VERTICAL );
338         m_optionsToolBar->SetAuiManager( &m_auimgr );
339     }
340 
341     m_optionsToolBar->Add( ACTIONS::toggleGrid,               ACTION_TOOLBAR::TOGGLE );
342 
343     m_optionsToolBar->Add( PCB_ACTIONS::togglePolarCoords,    ACTION_TOOLBAR::TOGGLE );
344     m_optionsToolBar->Add( ACTIONS::inchesUnits,              ACTION_TOOLBAR::TOGGLE );
345     m_optionsToolBar->Add( ACTIONS::milsUnits,                ACTION_TOOLBAR::TOGGLE );
346     m_optionsToolBar->Add( ACTIONS::millimetersUnits,         ACTION_TOOLBAR::TOGGLE );
347     m_optionsToolBar->Add( ACTIONS::toggleCursorStyle,        ACTION_TOOLBAR::TOGGLE );
348 
349     m_optionsToolBar->AddScaledSeparator( this );
350     m_optionsToolBar->Add( PCB_ACTIONS::showRatsnest,         ACTION_TOOLBAR::TOGGLE );
351     m_optionsToolBar->Add( PCB_ACTIONS::ratsnestLineMode,     ACTION_TOOLBAR::TOGGLE );
352 
353     m_optionsToolBar->AddScaledSeparator( this );
354     m_optionsToolBar->Add( ACTIONS::highContrastMode,         ACTION_TOOLBAR::TOGGLE );
355     m_optionsToolBar->Add( PCB_ACTIONS::toggleNetHighlight,   ACTION_TOOLBAR::TOGGLE );
356 
357     m_optionsToolBar->AddScaledSeparator( this );
358     m_optionsToolBar->Add( PCB_ACTIONS::zoneDisplayFilled,    ACTION_TOOLBAR::TOGGLE );
359     m_optionsToolBar->Add( PCB_ACTIONS::zoneDisplayOutline,   ACTION_TOOLBAR::TOGGLE );
360 
361     if( ADVANCED_CFG::GetCfg().m_ExtraZoneDisplayModes )
362     {
363         m_optionsToolBar->Add( PCB_ACTIONS::zoneDisplayFractured,    ACTION_TOOLBAR::TOGGLE );
364         m_optionsToolBar->Add( PCB_ACTIONS::zoneDisplayTriangulated, ACTION_TOOLBAR::TOGGLE );
365     }
366 
367     m_optionsToolBar->AddScaledSeparator( this );
368     m_optionsToolBar->Add( PCB_ACTIONS::padDisplayMode,       ACTION_TOOLBAR::TOGGLE );
369     m_optionsToolBar->Add( PCB_ACTIONS::viaDisplayMode,       ACTION_TOOLBAR::TOGGLE );
370     m_optionsToolBar->Add( PCB_ACTIONS::trackDisplayMode,     ACTION_TOOLBAR::TOGGLE );
371 
372     // Tools to show/hide toolbars:
373     m_optionsToolBar->AddScaledSeparator( this );
374     m_optionsToolBar->Add( PCB_ACTIONS::showLayersManager,    ACTION_TOOLBAR::TOGGLE  );
375 
376     PCB_SELECTION_TOOL*          selTool = m_toolManager->GetTool<PCB_SELECTION_TOOL>();
377     std::unique_ptr<ACTION_MENU> gridMenu = std::make_unique<ACTION_MENU>( false, selTool );
378     gridMenu->Add( ACTIONS::gridProperties );
379     m_optionsToolBar->AddToolContextMenu( ACTIONS::toggleGrid, std::move( gridMenu ) );
380 
381     m_optionsToolBar->KiRealize();
382 }
383 
384 
ReCreateVToolbar()385 void PCB_EDIT_FRAME::ReCreateVToolbar()
386 {
387     wxWindowUpdateLocker dummy( this );
388 
389     if( m_drawToolBar )
390     {
391         m_drawToolBar->ClearToolbar();
392     }
393     else
394     {
395         m_drawToolBar = new ACTION_TOOLBAR( this, ID_V_TOOLBAR, wxDefaultPosition, wxDefaultSize,
396                                             KICAD_AUI_TB_STYLE | wxAUI_TB_VERTICAL );
397         m_drawToolBar->SetAuiManager( &m_auimgr );
398     }
399 
400     // Groups contained on this toolbar
401     static ACTION_GROUP* dimensionGroup = nullptr;
402     static ACTION_GROUP* originGroup    = nullptr;
403     static ACTION_GROUP* routingGroup   = nullptr;
404     static ACTION_GROUP* tuneGroup      = nullptr;
405 
406     if( !dimensionGroup )
407     {
408         dimensionGroup = new ACTION_GROUP( "group.pcbDimensions",
409                                            { &PCB_ACTIONS::drawAlignedDimension,
410                                              &PCB_ACTIONS::drawOrthogonalDimension,
411                                              &PCB_ACTIONS::drawCenterDimension,
412                                              &PCB_ACTIONS::drawLeader } );
413     }
414 
415     if( !originGroup )
416     {
417         originGroup = new ACTION_GROUP( "group.pcbOrigins",
418                                         { &PCB_ACTIONS::drillOrigin,
419                                           &PCB_ACTIONS::gridSetOrigin } );
420     }
421 
422     if( !routingGroup )
423     {
424         routingGroup = new ACTION_GROUP( "group.pcbRouting",
425                                         { &PCB_ACTIONS::routeSingleTrack,
426                                           &PCB_ACTIONS::routeDiffPair } );
427     }
428 
429     if( !tuneGroup )
430     {
431         tuneGroup = new ACTION_GROUP( "group.pcbTune",
432                                       { &PCB_ACTIONS::routerTuneSingleTrace,
433                                         &PCB_ACTIONS::routerTuneDiffPair,
434                                         &PCB_ACTIONS::routerTuneDiffPairSkew } );
435     }
436 
437     m_drawToolBar->Add( ACTIONS::selectionTool,            ACTION_TOOLBAR::TOGGLE );
438     m_drawToolBar->Add( PCB_ACTIONS::localRatsnestTool,    ACTION_TOOLBAR::TOGGLE );
439 
440     m_drawToolBar->AddScaledSeparator( this );
441     m_drawToolBar->Add( PCB_ACTIONS::placeFootprint,       ACTION_TOOLBAR::TOGGLE );
442     m_drawToolBar->AddGroup( routingGroup,                 ACTION_TOOLBAR::TOGGLE );
443     m_drawToolBar->AddGroup( tuneGroup,                    ACTION_TOOLBAR::TOGGLE );
444     m_drawToolBar->Add( PCB_ACTIONS::drawVia,              ACTION_TOOLBAR::TOGGLE );
445     m_drawToolBar->Add( PCB_ACTIONS::drawZone,             ACTION_TOOLBAR::TOGGLE );
446     m_drawToolBar->Add( PCB_ACTIONS::drawRuleArea,         ACTION_TOOLBAR::TOGGLE );
447 
448     m_drawToolBar->AddScaledSeparator( this );
449     m_drawToolBar->Add( PCB_ACTIONS::drawLine,             ACTION_TOOLBAR::TOGGLE );
450     m_drawToolBar->Add( PCB_ACTIONS::drawArc,              ACTION_TOOLBAR::TOGGLE );
451     m_drawToolBar->Add( PCB_ACTIONS::drawRectangle,        ACTION_TOOLBAR::TOGGLE );
452     m_drawToolBar->Add( PCB_ACTIONS::drawCircle,           ACTION_TOOLBAR::TOGGLE );
453     m_drawToolBar->Add( PCB_ACTIONS::drawPolygon,          ACTION_TOOLBAR::TOGGLE );
454     m_drawToolBar->Add( PCB_ACTIONS::placeText,            ACTION_TOOLBAR::TOGGLE );
455     m_drawToolBar->AddGroup( dimensionGroup,               ACTION_TOOLBAR::TOGGLE );
456     m_drawToolBar->Add( PCB_ACTIONS::placeTarget,          ACTION_TOOLBAR::TOGGLE );
457     m_drawToolBar->Add( ACTIONS::deleteTool,               ACTION_TOOLBAR::TOGGLE );
458 
459     m_drawToolBar->AddScaledSeparator( this );
460     m_drawToolBar->AddGroup( originGroup,                  ACTION_TOOLBAR::TOGGLE );
461     m_drawToolBar->Add( ACTIONS::measureTool,              ACTION_TOOLBAR::TOGGLE );
462 
463     PCB_SELECTION_TOOL* selTool   = m_toolManager->GetTool<PCB_SELECTION_TOOL>();
464 
465     auto makeRouteMenu =
466             [&]()
467             {
468                 std::unique_ptr<ACTION_MENU> routeMenu =
469                         std::make_unique<ACTION_MENU>( false, selTool );
470 
471                 routeMenu->Add( PCB_ACTIONS::routerHighlightMode,  ACTION_MENU::CHECK );
472                 routeMenu->Add( PCB_ACTIONS::routerShoveMode,      ACTION_MENU::CHECK );
473                 routeMenu->Add( PCB_ACTIONS::routerWalkaroundMode, ACTION_MENU::CHECK );
474 
475                 routeMenu->AppendSeparator();
476                 routeMenu->Add( PCB_ACTIONS::routerSettingsDialog );
477 
478                 return routeMenu;
479             };
480 
481     m_drawToolBar->AddToolContextMenu( PCB_ACTIONS::routeSingleTrack, makeRouteMenu() );
482     m_drawToolBar->AddToolContextMenu( PCB_ACTIONS::routeDiffPair, makeRouteMenu() );
483 
484     auto makeTuneMenu =
485         [&]()
486         {
487             std::unique_ptr<ACTION_MENU> tuneMenu = std::make_unique<ACTION_MENU>( false, selTool );
488             tuneMenu->Add( PCB_ACTIONS::lengthTunerSettingsDialog );
489             return tuneMenu;
490         };
491 
492     m_drawToolBar->AddToolContextMenu( PCB_ACTIONS::routerTuneSingleTrace, makeTuneMenu() );
493     m_drawToolBar->AddToolContextMenu( PCB_ACTIONS::routerTuneDiffPair, makeTuneMenu() );
494     m_drawToolBar->AddToolContextMenu( PCB_ACTIONS::routerTuneDiffPairSkew, makeTuneMenu() );
495 
496     std::unique_ptr<ACTION_MENU> zoneMenu = std::make_unique<ACTION_MENU>( false, selTool );
497     zoneMenu->Add( PCB_ACTIONS::zoneFillAll );
498     zoneMenu->Add( PCB_ACTIONS::zoneUnfillAll );
499     m_drawToolBar->AddToolContextMenu( PCB_ACTIONS::drawZone, std::move( zoneMenu ) );
500 
501     std::unique_ptr<ACTION_MENU> lineMenu = std::make_unique<ACTION_MENU>( false, selTool );
502     m_drawToolBar->AddToolContextMenu( PCB_ACTIONS::drawLine, std::move( lineMenu ) );
503 
504     m_drawToolBar->KiRealize();
505 }
506 
507 
ReCreateAuxiliaryToolbar()508 void PCB_EDIT_FRAME::ReCreateAuxiliaryToolbar()
509 {
510     wxWindowUpdateLocker dummy( this );
511 
512     if( m_auxiliaryToolBar )
513     {
514         m_auxiliaryToolBar->ClearToolbar();
515     }
516     else
517     {
518         m_auxiliaryToolBar = new ACTION_TOOLBAR( this, ID_AUX_TOOLBAR, wxDefaultPosition,
519                                                  wxDefaultSize,
520                                                  KICAD_AUI_TB_STYLE | wxAUI_TB_HORZ_LAYOUT );
521         m_auxiliaryToolBar->SetAuiManager( &m_auimgr );
522     }
523 
524     /* Set up toolbar items */
525 
526     // Creates box to display and choose tracks widths:
527     if( m_SelTrackWidthBox == nullptr )
528         m_SelTrackWidthBox = new wxChoice( m_auxiliaryToolBar, ID_AUX_TOOLBAR_PCB_TRACK_WIDTH,
529                                            wxDefaultPosition, wxDefaultSize, 0, nullptr );
530 
531     UpdateTrackWidthSelectBox( m_SelTrackWidthBox );
532     m_auxiliaryToolBar->AddControl( m_SelTrackWidthBox );
533     m_SelTrackWidthBox->SetToolTip( _( "Select the default width for new tracks. Note that this "
534                                        "width can be overridden by the board minimum width, or by "
535                                        "the width of an existing track if the 'Use Existing Track "
536                                        "Width' feature is enabled." ) );
537 
538     m_auxiliaryToolBar->AddTool( ID_AUX_TOOLBAR_PCB_SELECT_AUTO_WIDTH, wxEmptyString,
539                                  KiScaledBitmap( BITMAPS::auto_track_width, this ),
540                                  _( "When routing from an existing track use its width instead "
541                                     "of the current width setting" ),
542                                  wxITEM_CHECK );
543 
544     m_auxiliaryToolBar->AddScaledSeparator( this );
545 
546     // Creates box to display and choose vias diameters:
547 
548     if( m_SelViaSizeBox == nullptr )
549         m_SelViaSizeBox = new wxChoice( m_auxiliaryToolBar, ID_AUX_TOOLBAR_PCB_VIA_SIZE,
550                                         wxDefaultPosition, wxDefaultSize, 0, nullptr );
551 
552     UpdateViaSizeSelectBox( m_SelViaSizeBox );
553     m_auxiliaryToolBar->AddControl( m_SelViaSizeBox );
554 
555     // Add the box to display and select the current grid size:
556     m_auxiliaryToolBar->AddScaledSeparator( this );
557 
558     if( m_gridSelectBox == nullptr )
559         m_gridSelectBox = new wxChoice( m_auxiliaryToolBar, ID_ON_GRID_SELECT,
560                                         wxDefaultPosition, wxDefaultSize, 0, nullptr );
561 
562     UpdateGridSelectBox();
563 
564     m_auxiliaryToolBar->AddControl( m_gridSelectBox );
565 
566     //  Add the box to display and select the current Zoom
567     m_auxiliaryToolBar->AddScaledSeparator( this );
568 
569     if( m_zoomSelectBox == nullptr )
570         m_zoomSelectBox = new wxChoice( m_auxiliaryToolBar, ID_ON_ZOOM_SELECT,
571                                         wxDefaultPosition, wxDefaultSize, 0, nullptr );
572 
573     UpdateZoomSelectBox();
574     m_auxiliaryToolBar->AddControl( m_zoomSelectBox );
575 
576     // Go through and ensure the comboboxes are the correct size, since the strings in the
577     // box could have changed widths.
578     m_auxiliaryToolBar->UpdateControlWidth( ID_AUX_TOOLBAR_PCB_TRACK_WIDTH );
579     m_auxiliaryToolBar->UpdateControlWidth( ID_AUX_TOOLBAR_PCB_VIA_SIZE );
580     m_auxiliaryToolBar->UpdateControlWidth( ID_ON_ZOOM_SELECT );
581     m_auxiliaryToolBar->UpdateControlWidth( ID_ON_GRID_SELECT );
582 
583     // after adding the buttons to the toolbar, must call Realize()
584     m_auxiliaryToolBar->KiRealize();
585 }
586 
587 
UpdateToolbarControlSizes()588 void PCB_EDIT_FRAME::UpdateToolbarControlSizes()
589 {
590     if( m_mainToolBar )
591     {
592         // Update the item widths
593         m_mainToolBar->UpdateControlWidth( ID_TOOLBARH_PCB_SELECT_LAYER );
594     }
595 
596     if( m_auxiliaryToolBar )
597     {
598         // Update the item widths
599         m_auxiliaryToolBar->UpdateControlWidth( ID_AUX_TOOLBAR_PCB_TRACK_WIDTH );
600         m_auxiliaryToolBar->UpdateControlWidth( ID_AUX_TOOLBAR_PCB_VIA_SIZE );
601         m_auxiliaryToolBar->UpdateControlWidth( ID_ON_ZOOM_SELECT );
602         m_auxiliaryToolBar->UpdateControlWidth( ID_ON_GRID_SELECT );
603     }
604 }
605 
606 
ComboBoxUnits(EDA_UNITS aUnits,double aValue,bool aIncludeLabel=true)607 static wxString ComboBoxUnits( EDA_UNITS aUnits, double aValue, bool aIncludeLabel = true )
608 {
609     wxString      text;
610     const wxChar* format;
611 
612     switch( aUnits )
613     {
614     default:                     wxASSERT_MSG( false, "Invalid unit" ); KI_FALLTHROUGH;
615     case EDA_UNITS::UNSCALED:    format = wxT( "%.0f" );                break;
616     case EDA_UNITS::MILLIMETRES: format = wxT( "%.3f" );                break;
617     case EDA_UNITS::MILS:        format = wxT( "%.2f" );                break;
618     case EDA_UNITS::INCHES:      format = wxT( "%.5f" );                break;
619     }
620 
621     text.Printf( format, To_User_Unit( aUnits, aValue ) );
622 
623     if( aIncludeLabel )
624     {
625         text += " ";
626         text += GetAbbreviatedUnitsLabel( aUnits, EDA_DATA_TYPE::DISTANCE );
627     }
628 
629     return text;
630 }
631 
632 
UpdateTrackWidthSelectBox(wxChoice * aTrackWidthSelectBox,bool aEdit)633 void PCB_EDIT_FRAME::UpdateTrackWidthSelectBox( wxChoice* aTrackWidthSelectBox, bool aEdit )
634 {
635     if( aTrackWidthSelectBox == nullptr )
636         return;
637 
638     EDA_UNITS primaryUnit;
639     EDA_UNITS secondaryUnit;
640 
641     GetUnitPair( primaryUnit, secondaryUnit );
642 
643     wxString msg;
644 
645     aTrackWidthSelectBox->Clear();
646 
647     aTrackWidthSelectBox->Append( _( "Track: use netclass width" ) );
648 
649     for( unsigned ii = 1; ii < GetDesignSettings().m_TrackWidthList.size(); ii++ )
650     {
651         int size = GetDesignSettings().m_TrackWidthList[ii];
652 
653         msg.Printf( _( "Track: %s (%s)" ), ComboBoxUnits( primaryUnit, size ),
654                                            ComboBoxUnits( secondaryUnit, size ) );
655 
656         aTrackWidthSelectBox->Append( msg );
657     }
658 
659     if( aEdit )
660     {
661         aTrackWidthSelectBox->Append( wxT( "---" ) );
662         aTrackWidthSelectBox->Append( _( "Edit Pre-defined Sizes..." ) );
663     }
664 
665     if( GetDesignSettings().GetTrackWidthIndex() >= GetDesignSettings().m_TrackWidthList.size() )
666         GetDesignSettings().SetTrackWidthIndex( 0 );
667 
668     aTrackWidthSelectBox->SetSelection( GetDesignSettings().GetTrackWidthIndex() );
669 }
670 
671 
UpdateViaSizeSelectBox(wxChoice * aViaSizeSelectBox,bool aEdit)672 void PCB_EDIT_FRAME::UpdateViaSizeSelectBox( wxChoice* aViaSizeSelectBox, bool aEdit )
673 {
674     if( aViaSizeSelectBox == nullptr )
675         return;
676 
677     aViaSizeSelectBox->Clear();
678 
679     COMMON_TOOLS* cmnTool  = m_toolManager->GetTool<COMMON_TOOLS>();
680 
681     EDA_UNITS primaryUnit   = GetUserUnits();
682     EDA_UNITS secondaryUnit = EDA_UNITS::MILS;
683 
684     if( EDA_UNIT_UTILS::IsImperialUnit( primaryUnit ) )
685     {
686         if( cmnTool )
687             secondaryUnit = cmnTool->GetLastMetricUnits();
688         else
689             secondaryUnit = EDA_UNITS::MILLIMETRES;
690     }
691     else
692     {
693         if( cmnTool )
694             secondaryUnit = cmnTool->GetLastImperialUnits();
695         else
696             secondaryUnit = EDA_UNITS::MILS;
697     }
698 
699     aViaSizeSelectBox->Append( _( "Via: use netclass sizes" ) );
700 
701     for( unsigned ii = 1; ii < GetDesignSettings().m_ViasDimensionsList.size(); ii++ )
702     {
703         VIA_DIMENSION viaDimension = GetDesignSettings().m_ViasDimensionsList[ii];
704         wxString      msg, priStr, secStr;
705 
706         double diam = viaDimension.m_Diameter;
707         double hole = viaDimension.m_Drill;
708 
709         if( hole > 0 )
710         {
711             priStr = ComboBoxUnits( primaryUnit, diam, false ) + " / "
712                         + ComboBoxUnits( primaryUnit, hole, true );
713             secStr = ComboBoxUnits( secondaryUnit, diam, false ) + " / "
714                         + ComboBoxUnits( secondaryUnit, hole, true );
715         }
716         else
717         {
718             priStr = ComboBoxUnits( primaryUnit, diam, true );
719             secStr = ComboBoxUnits( secondaryUnit, diam, true );
720         }
721 
722         msg.Printf( _( "Via: %s (%s)" ), priStr, secStr );
723 
724         aViaSizeSelectBox->Append( msg );
725     }
726 
727     if( aEdit )
728     {
729         aViaSizeSelectBox->Append( wxT( "---" ) );
730         aViaSizeSelectBox->Append( _( "Edit Pre-defined Sizes..." ) );
731     }
732 
733     if( GetDesignSettings().GetViaSizeIndex() >= GetDesignSettings().m_ViasDimensionsList.size() )
734         GetDesignSettings().SetViaSizeIndex( 0 );
735 
736     aViaSizeSelectBox->SetSelection( GetDesignSettings().GetViaSizeIndex() );
737 }
738 
739 
ReCreateLayerBox(bool aForceResizeToolbar)740 void PCB_EDIT_FRAME::ReCreateLayerBox( bool aForceResizeToolbar )
741 {
742     if( m_SelLayerBox == nullptr || m_mainToolBar == nullptr )
743         return;
744 
745     m_SelLayerBox->SetToolTip( _( "+/- to switch" ) );
746     m_SelLayerBox->Resync();
747 
748     if( aForceResizeToolbar )
749         UpdateToolbarControlSizes();
750 }
751 
752 
ToggleLayersManager()753 void PCB_EDIT_FRAME::ToggleLayersManager()
754 {
755     PCBNEW_SETTINGS* settings      = GetPcbNewSettings();
756     wxAuiPaneInfo&   layersManager = m_auimgr.GetPane( "LayersManager" );
757     wxAuiPaneInfo&   selectionFilter = m_auimgr.GetPane( "SelectionFilter" );
758 
759     // show auxiliary Vertical layers and visibility manager toolbar
760     m_show_layer_manager_tools = !m_show_layer_manager_tools;
761     layersManager.Show( m_show_layer_manager_tools );
762     selectionFilter.Show( m_show_layer_manager_tools );
763 
764     if( m_show_layer_manager_tools )
765     {
766         SetAuiPaneSize( m_auimgr, layersManager, settings->m_AuiPanels.right_panel_width, -1 );
767     }
768     else
769     {
770         settings->m_AuiPanels.right_panel_width = m_appearancePanel->GetSize().x;
771         m_auimgr.Update();
772     }
773 }
774 
775 
OnUpdateSelectTrackWidth(wxUpdateUIEvent & aEvent)776 void PCB_EDIT_FRAME::OnUpdateSelectTrackWidth( wxUpdateUIEvent& aEvent )
777 {
778     if( aEvent.GetId() == ID_AUX_TOOLBAR_PCB_TRACK_WIDTH )
779     {
780         BOARD_DESIGN_SETTINGS& bds = GetDesignSettings();
781         int                    sel;
782 
783         if( bds.UseCustomTrackViaSize() )
784             sel = wxNOT_FOUND;
785         else
786             sel = bds.GetTrackWidthIndex();
787 
788         if( m_SelTrackWidthBox->GetSelection() != sel )
789             m_SelTrackWidthBox->SetSelection( sel );
790     }
791 }
792 
793 
OnUpdateSelectViaSize(wxUpdateUIEvent & aEvent)794 void PCB_EDIT_FRAME::OnUpdateSelectViaSize( wxUpdateUIEvent& aEvent )
795 {
796     if( aEvent.GetId() == ID_AUX_TOOLBAR_PCB_VIA_SIZE )
797     {
798         BOARD_DESIGN_SETTINGS& bds = GetDesignSettings();
799         int                    sel = 0;
800 
801         if( bds.UseCustomTrackViaSize() )
802             sel = wxNOT_FOUND;
803         else
804             sel = bds.GetViaSizeIndex();
805 
806         if( m_SelViaSizeBox->GetSelection() != sel )
807             m_SelViaSizeBox->SetSelection( sel );
808     }
809 }
810 
811 
OnUpdateSelectAutoWidth(wxUpdateUIEvent & aEvent)812 void PCB_EDIT_FRAME::OnUpdateSelectAutoWidth( wxUpdateUIEvent& aEvent )
813 {
814     BOARD_DESIGN_SETTINGS& bds = GetDesignSettings();
815 
816     aEvent.Check( bds.m_UseConnectedTrackWidth );
817 }
818 
819 
OnUpdateLayerSelectBox(wxUpdateUIEvent & aEvent)820 void PCB_EDIT_FRAME::OnUpdateLayerSelectBox( wxUpdateUIEvent& aEvent )
821 {
822     if( m_SelLayerBox->GetLayerSelection() != GetActiveLayer() )
823         m_SelLayerBox->SetLayerSelection( GetActiveLayer() );
824 }
825