KiCad PCB EDA Suite
Loading...
Searching...
No Matches
appearance_controls_3D.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) 2023 CERN
5 * Copyright (C) 2023-2024 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 <confirm.h>
25#include <pgm_base.h>
26#include <dpi_scaling_common.h>
27#include <eda_list_dialog.h>
28#include <pcb_display_options.h>
29#include <eda_3d_viewer_frame.h>
30#include <pcbnew_settings.h>
31#include <project.h>
34#include <tool/tool_manager.h>
35#include <tools/pcb_actions.h>
41#include <wx/bmpbuttn.h>
42#include <wx/sizer.h>
43#include <wx/textdlg.h>
44#include <wx/checkbox.h>
45
46#include <../3d_rendering/opengl/render_3d_opengl.h>
47
48
49#define RR APPEARANCE_CONTROLS_3D::APPEARANCE_SETTING_3D // Render Row abbreviation to reduce source width
50
53
54 // text id tooltip
55 RR( _HKI( "Board Body" ), LAYER_3D_BOARD, _HKI( "Show board body" ) ),
56 RR( _HKI( "F.Cu" ), LAYER_3D_COPPER_TOP, _HKI( "Show front copper / surface finish color" ) ),
57 RR( _HKI( "B.Cu" ), LAYER_3D_COPPER_BOTTOM, _HKI( "Show back copper / surface finish color" ) ),
58 RR( _HKI( "Adhesive" ), LAYER_3D_ADHESIVE, _HKI( "Show adhesive" ) ),
59 RR( _HKI( "Solder Paste" ), LAYER_3D_SOLDERPASTE, _HKI( "Show solder paste" ) ),
60 RR( _HKI( "F.Silkscreen" ), LAYER_3D_SILKSCREEN_TOP, _HKI( "Show front silkscreen" ) ),
61 RR( _HKI( "B.Silkscreen" ), LAYER_3D_SILKSCREEN_BOTTOM, _HKI( "Show back silkscreen" ) ),
62 RR( _HKI( "F.Mask" ), LAYER_3D_SOLDERMASK_TOP, _HKI( "Show front solder mask" ) ),
63 RR( _HKI( "B.Mask" ), LAYER_3D_SOLDERMASK_BOTTOM, _HKI( "Show back solder mask" ) ),
64 RR( _HKI( "User.Drawings" ), LAYER_3D_USER_DRAWINGS, _HKI( "Show user drawings layer" ) ),
65 RR( _HKI( "User.Comments" ), LAYER_3D_USER_COMMENTS, _HKI( "Show user comments layer" ) ),
66 RR( _HKI( "User.Eco1" ), LAYER_3D_USER_ECO1, _HKI( "Show user ECO1 layer" ) ),
67 RR( _HKI( "User.Eco2" ), LAYER_3D_USER_ECO2, _HKI( "Show user ECO2 layer" ) ),
68 RR(),
69 RR( _HKI( "Through-hole Models" ), LAYER_3D_TH_MODELS, EDA_3D_ACTIONS::showTHT ),
74 RR( _HKI( "Model Bounding Boxes" ), LAYER_3D_BOUNDING_BOXES, EDA_3D_ACTIONS::showBBoxes ),
75 RR(),
76 RR( _HKI( "Values" ), LAYER_FP_VALUES, _HKI( "Show footprint values" ) ),
77 RR( _HKI( "References" ), LAYER_FP_REFERENCES, _HKI( "Show footprint references" ) ),
78 RR( _HKI( "Footprint Text" ), LAYER_FP_TEXT, _HKI( "Show all footprint text" ) ),
79 RR( _HKI( "Off-board Silkscreen" ), LAYER_3D_OFF_BOARD_SILK, _HKI( "Do not clip silk layers to board outline" ) ),
80 RR(),
82 RR( _HKI( "Background Start" ), LAYER_3D_BACKGROUND_TOP, _HKI( "Background gradient start color" ) ),
83 RR( _HKI( "Background End" ), LAYER_3D_BACKGROUND_BOTTOM, _HKI( "Background gradient end color" ) ),
84};
85
86// The list of IDs that can have colors coming from the board stackup, and cannot be
87// modified if use colors from stackup is activated
92 };
93
95 wxWindow* aFocusOwner ) :
97 m_frame( aParent ),
98 m_focusOwner( aFocusOwner ),
99 m_lastSelectedViewport( nullptr )
100{
101 DPI_SCALING_COMMON dpi( nullptr, m_frame );
102
103 int indicatorSize = ConvertDialogToPixels( wxSize( 6, 6 ) ).x / dpi.GetContentScaleFactor();
104 int screenHeight = wxSystemSettings::GetMetric( wxSYS_SCREEN_Y );
105 m_pointSize = wxSystemSettings::GetFont( wxSYS_DEFAULT_GUI_FONT ).GetPointSize();
106
107 m_layerPanelColour = m_panelLayers->GetBackgroundColour().ChangeLightness( 110 );
108 SetBorders( true, false, false, false );
109
110 m_layersOuterSizer = new wxBoxSizer( wxVERTICAL );
112 m_windowLayers->SetScrollRate( 0, 5 );
113 m_windowLayers->Bind( wxEVT_SET_FOCUS, &APPEARANCE_CONTROLS_3D::OnSetFocus, this );
114
115 m_envOuterSizer = new wxBoxSizer( wxVERTICAL );
116
117 wxFont infoFont = KIUI::GetInfoFont( this );
118 m_panelLayers->SetFont( infoFont );
119 m_windowLayers->SetFont( infoFont );
120 m_presetsLabel->SetFont( infoFont );
121 m_viewportsLabel->SetFont( infoFont );
122
123 // Create display options
124 m_cbUseBoardStackupColors = new wxCheckBox( m_panelLayers, wxID_ANY,
125 _( "Use board stackup colors" ) );
126 m_cbUseBoardStackupColors->SetFont( infoFont );
127
128 m_cbUseBoardStackupColors->Bind( wxEVT_CHECKBOX,
129 [this]( wxCommandEvent& aEvent )
130 {
132 cfg->m_UseStackupColors = aEvent.IsChecked();
133
136 m_frame->NewDisplay( true );
137 } );
138
139 m_panelLayersSizer->Add( m_cbUseBoardStackupColors, 0, wxEXPAND | wxTOP | wxLEFT | wxRIGHT, 7 );
140
141 m_cbLayerPresets->SetToolTip( wxString::Format( _( "Save and restore color and visibility "
142 "combinations.\n"
143 "Use %s+Tab to activate selector.\n"
144 "Successive Tabs while holding %s down will "
145 "cycle through presets in the popup." ),
148
149 m_cbViewports->SetToolTip( wxString::Format( _( "Save and restore camera position and zoom.\n"
150 "Use %s+Tab to activate selector.\n"
151 "Successive Tabs while holding %s down will "
152 "cycle through viewports in the popup." ),
155
156 if( screenHeight <= 900 && m_pointSize >= indicatorSize )
157 m_pointSize = m_pointSize * 8 / 10;
158
160
161 m_toggleGridRenderer = new GRID_BITMAP_TOGGLE_RENDERER( KiBitmap( BITMAPS::visibility ),
162 KiBitmap( BITMAPS::visibility_off ) );
163
164 m_frame->Bind( EDA_LANG_CHANGED, &APPEARANCE_CONTROLS_3D::OnLanguageChanged, this );
165}
166
167
169{
170 m_frame->Unbind( EDA_LANG_CHANGED, &APPEARANCE_CONTROLS_3D::OnLanguageChanged, this );
171}
172
173
175{
176 DPI_SCALING_COMMON dpi( nullptr, m_frame );
177 wxSize size( 220 * dpi.GetScaleFactor(), 480 * dpi.GetScaleFactor() );
178 return size;
179}
180
181
182void APPEARANCE_CONTROLS_3D::OnSetFocus( wxFocusEvent& aEvent )
183{
184#ifdef __WXMSW__
185 // In wxMSW, buttons won't process events unless they have focus, so we'll let it take the
186 // focus and give it back to the parent in the button event handler.
187 if( wxBitmapButton* btn = dynamic_cast<wxBitmapButton*>( aEvent.GetEventObject() ) )
188 {
189 wxCommandEvent evt( wxEVT_BUTTON );
190 wxPostEvent( btn, evt );
191 }
192#endif
193
194 passOnFocus();
195 aEvent.Skip();
196}
197
198
199void APPEARANCE_CONTROLS_3D::OnSize( wxSizeEvent& aEvent )
200{
201 aEvent.Skip();
202}
203
204
206{
207 Freeze();
208
210 m_cbUseBoardStackupColors->SetLabel( _( "Use board stackup colors" ) );
213
214 Thaw();
215 Refresh();
216}
217
218
219void APPEARANCE_CONTROLS_3D::OnLanguageChanged( wxCommandEvent& aEvent )
220{
222
223 aEvent.Skip();
224}
225
226
228{
229 // This is essentially a list of hacks because DarkMode isn't yet implemented inside
230 // wxWidgets.
231 //
232 // The individual wxPanels, COLOR_SWATCHes and GRID_CELL_COLOR_RENDERERs should really be
233 // overriding some virtual method or responding to some wxWidgets event so that the parent
234 // doesn't have to know what it contains. But, that's not where we are, so... :shrug:
235
236 m_layerPanelColour = m_panelLayers->GetBackgroundColour().ChangeLightness( 110 );
237
238 m_windowLayers->SetBackgroundColour( m_layerPanelColour );
239
240 for( wxSizerItem* child : m_layersOuterSizer->GetChildren() )
241 {
242 if( child && child->GetWindow() )
243 child->GetWindow()->SetBackgroundColour( m_layerPanelColour );
244 }
245}
246
247
249{
251
254}
255
256
257void APPEARANCE_CONTROLS_3D::ApplyLayerPreset( const wxString& aPresetName )
258{
259 if( aPresetName == FOLLOW_PCB || aPresetName == FOLLOW_PLOT_SETTINGS )
260 {
261 m_frame->GetAdapter().m_Cfg->m_CurrentPreset = aPresetName;
263 m_frame->NewDisplay( true );
264 }
265 else if( LAYER_PRESET_3D* preset = m_frame->GetAdapter().m_Cfg->FindPreset( aPresetName ) )
266 {
267 doApplyLayerPreset( *preset );
268 }
269
270 // Move to front of MRU list
271 if( m_presetMRU.Index( aPresetName ) != wxNOT_FOUND )
272 m_presetMRU.Remove( aPresetName );
273
274 m_presetMRU.Insert( aPresetName, 0 );
275
276 updateLayerPresetWidget( aPresetName );
277}
278
279
280std::vector<VIEWPORT3D> APPEARANCE_CONTROLS_3D::GetUserViewports() const
281{
282 std::vector<VIEWPORT3D> ret;
283
284 for( const auto& [name, viewport] : m_viewports )
285 ret.emplace_back( viewport );
286
287 return ret;
288}
289
290
291void APPEARANCE_CONTROLS_3D::SetUserViewports( std::vector<VIEWPORT3D>& aViewportList )
292{
293 m_viewports.clear();
294
295 for( const VIEWPORT3D& viewport : aViewportList )
296 {
297 if( m_viewports.count( viewport.name ) )
298 continue;
299
300 m_viewports[viewport.name] = viewport;
301
302 m_viewportMRU.Add( viewport.name );
303 }
304
306
307 // Now is as good a time as any to initialize the layer presets as well.
309
310 m_presetMRU.Add( FOLLOW_PCB );
312
313 for( const LAYER_PRESET_3D& preset : m_frame->GetAdapter().m_Cfg->m_LayerPresets )
314 m_presetMRU.Add( preset.name );
315}
316
317
318void APPEARANCE_CONTROLS_3D::ApplyViewport( const wxString& aViewportName )
319{
320 int idx = m_cbViewports->FindString( aViewportName );
321
322 if( idx >= 0 && idx < (int)m_cbViewports->GetCount() - 3 /* separator */ )
323 {
324 m_cbViewports->SetSelection( idx );
325 m_lastSelectedViewport = static_cast<VIEWPORT3D*>( m_cbViewports->GetClientData( idx ) );
326 }
327 else
328 {
329 m_cbViewports->SetSelection( m_cbViewports->GetCount() - 3 ); // separator
330 m_lastSelectedViewport = nullptr;
331 }
332
335}
336
337
338void APPEARANCE_CONTROLS_3D::OnLayerVisibilityChanged( int aLayer, bool isVisible )
339{
340 std::bitset<LAYER_3D_END> visibleLayers = m_frame->GetAdapter().GetVisibleLayers();
341 const std::map<int, COLOR4D>& colors = m_frame->GetAdapter().GetLayerColors();
342 bool killFollow = false;
343 bool doFastRefresh = false; // true to just refresh the display
344
345 // Special-case controls
346 switch( aLayer )
347 {
348 case LAYER_FP_TEXT:
349 // Because Footprint Text is a meta-control that also can disable values/references,
350 // drag them along here so that the user is less likely to be confused.
351 if( !isVisible )
352 {
353 visibleLayers.set( LAYER_FP_REFERENCES, false );
354 visibleLayers.set( LAYER_FP_VALUES, false );
355 }
356
357 visibleLayers.set( LAYER_FP_TEXT, isVisible );
358 killFollow = true;
359 break;
360
362 case LAYER_FP_VALUES:
363 // In case that user changes Footprint Value/References when the Footprint Text
364 // meta-control is disabled, we should put it back on.
365 if( isVisible )
366 visibleLayers.set( LAYER_FP_TEXT, true );
367
368 visibleLayers.set( aLayer, isVisible );
369 killFollow = true;
370 break;
371
372 case LAYER_3D_BOARD:
385 visibleLayers.set( aLayer, isVisible );
386 killFollow = true;
387 break;
388
394 doFastRefresh = true;
395 visibleLayers.set( aLayer, isVisible );
396 break;
397
398 default:
399 visibleLayers.set( aLayer, isVisible );
400 break;
401 }
402
403 m_frame->GetAdapter().SetVisibleLayers( visibleLayers );
404 m_frame->GetAdapter().SetLayerColors( colors );
405
406 const wxString& currentPreset = m_frame->GetAdapter().m_Cfg->m_CurrentPreset;
407
408 if( ( currentPreset != FOLLOW_PCB && currentPreset != FOLLOW_PLOT_SETTINGS ) || killFollow )
410
412
413 if( doFastRefresh && m_frame->GetAdapter().m_Cfg->m_Render.engine == RENDER_ENGINE::OPENGL )
414 {
415 RENDER_3D_OPENGL* renderer =
416 static_cast<RENDER_3D_OPENGL*>( m_frame->GetCanvas()->GetCurrentRender() );
417 renderer->Load3dModelsIfNeeded();
419 }
420 else
421 {
422 m_frame->NewDisplay( true );
423 }
424}
425
426
428{
429 std::bitset<LAYER_3D_END> visibleLayers = m_frame->GetAdapter().GetVisibleLayers();
430 std::map<int, COLOR4D> colors = m_frame->GetAdapter().GetLayerColors();
431
432 m_frame->GetAdapter().SetVisibleLayers( visibleLayers );
433 m_frame->GetAdapter().SetLayerColors( colors );
434
435 int layer = aSwatch->GetId();
436 COLOR4D newColor = aSwatch->GetSwatchColor();
437
438 colors[ layer ] = newColor;
439
440 if( layer == LAYER_3D_COPPER_TOP )
441 colors[ LAYER_3D_COPPER_BOTTOM ] = newColor;
442 else if( layer == LAYER_3D_COPPER_BOTTOM )
443 colors[ LAYER_3D_COPPER_TOP ] = newColor;
444
445 m_frame->GetAdapter().SetLayerColors( colors );
446
448
449 m_frame->NewDisplay( true );
450}
451
452
454{
455 int swatchWidth = m_windowLayers->ConvertDialogToPixels( wxSize( 8, 0 ) ).x;
456
457 std::bitset<LAYER_3D_END> visibleLayers = m_frame->GetAdapter().GetVisibleLayers();
458 std::map<int, COLOR4D> colors = m_frame->GetAdapter().GetLayerColors();
459 std::map<int, COLOR4D> defaultColors = m_frame->GetAdapter().GetDefaultColors();
460
461 m_layerSettings.clear();
462 m_layersOuterSizer->Clear( true );
463 m_layersOuterSizer->AddSpacer( 5 );
464
465 m_envOuterSizer->Clear( true );
466
467 auto appendLayer =
468 [&]( const std::unique_ptr<APPEARANCE_SETTING_3D>& aSetting )
469 {
470 wxBoxSizer* sizer = new wxBoxSizer( wxHORIZONTAL );
471 int layer = aSetting->m_Id;
472
473 aSetting->m_Visible = visibleLayers.test( layer );
474
475 if( colors.count( layer ) )
476 {
477 COLOR_SWATCH* swatch = new COLOR_SWATCH( m_windowLayers, colors[ layer ], layer,
478 COLOR4D::WHITE, defaultColors[ layer ],
479 SWATCH_SMALL );
480 swatch->SetToolTip( _( "Left double click or middle click to change color" ) );
481
482 swatch->SetReadOnlyCallback(
483 [this]()
484 {
485 WX_INFOBAR* infobar = m_frame->GetInfoBar();
486
487 infobar->RemoveAllButtons();
488 infobar->AddCloseButton();
489
490 infobar->ShowMessageFor( _( "Uncheck 'Use board stackup colors' to "
491 "allow color editing." ),
492 10000, wxICON_INFORMATION );
493 } );
494
495 sizer->Add( swatch, 0, wxALIGN_CENTER_VERTICAL, 0 );
496 aSetting->m_Ctl_color = swatch;
497
498 swatch->Bind( COLOR_SWATCH_CHANGED,
499 [this]( wxCommandEvent& event )
500 {
501 auto swatch = static_cast<COLOR_SWATCH*>( event.GetEventObject() );
502 onColorSwatchChanged( swatch );
503
504 passOnFocus();
505 } );
506 }
507 else
508 {
509 sizer->AddSpacer( swatchWidth );
510 }
511
512 sizer->AddSpacer( 5 );
513
514 wxStaticText* label = new wxStaticText( m_windowLayers, layer, aSetting->GetLabel() );
515 label->Wrap( -1 );
516 label->SetToolTip( aSetting->GetTooltip() );
517
518 if( layer == LAYER_3D_BACKGROUND_TOP || layer == LAYER_3D_BACKGROUND_BOTTOM )
519 {
520 sizer->AddSpacer( swatchWidth );
521 }
522 else
523 {
524 BITMAP_TOGGLE* btn_visible = new BITMAP_TOGGLE( m_windowLayers, layer,
525 KiBitmap( BITMAPS::visibility ),
526 KiBitmap( BITMAPS::visibility_off ),
527 aSetting->m_Visible );
528
529 btn_visible->Bind( TOGGLE_CHANGED,
530 [this]( wxCommandEvent& aEvent )
531 {
532 int id = static_cast<wxWindow*>( aEvent.GetEventObject() )->GetId();
533 bool isVisible = aEvent.GetInt();
534 OnLayerVisibilityChanged( id, isVisible );
535
536 passOnFocus();
537 } );
538
539 wxString tip;
540 tip.Printf( _( "Show or hide %s" ), aSetting->GetLabel().Lower() );
541 btn_visible->SetToolTip( tip );
542
543 aSetting->m_Ctl_visibility = btn_visible;
544 sizer->Add( btn_visible, 0, wxALIGN_CENTER_VERTICAL, 0 );
545 }
546
547 sizer->AddSpacer( 5 );
548 sizer->Add( label, 0, wxALIGN_CENTER_VERTICAL, 0 );
549
550 m_layersOuterSizer->Add( sizer, 0, wxEXPAND | wxLEFT | wxRIGHT, 5 );
551 m_layersOuterSizer->AddSpacer( 2 );
552 };
553
554 for( const APPEARANCE_SETTING_3D& s_setting : s_layerSettings )
555 {
556 m_layerSettings.emplace_back( std::make_unique<APPEARANCE_SETTING_3D>( s_setting ) );
557 std::unique_ptr<APPEARANCE_SETTING_3D>& setting = m_layerSettings.back();
558
559 if( setting->m_Spacer )
560 m_layersOuterSizer->AddSpacer( m_pointSize );
561 else
562 appendLayer( setting );
563
564 m_layerSettingsMap[setting->m_Id] = setting.get();
565 }
566
567 m_sizerOuter->Layout();
568}
569
570
572{
574 std::bitset<LAYER_3D_END> visibleLayers = m_frame->GetAdapter().GetVisibleLayers();
575 std::map<int, COLOR4D> colors = m_frame->GetAdapter().GetLayerColors();
576
577 for( std::unique_ptr<APPEARANCE_SETTING_3D>& setting : m_layerSettings )
578 {
579 if( setting->m_Spacer )
580 continue;
581
582 if( setting->m_Ctl_visibility )
583 setting->m_Ctl_visibility->SetValue( visibleLayers.test( setting->m_Id ) );
584
585 if( setting->m_Ctl_color )
586 {
587 setting->m_Ctl_color->SetSwatchColor( colors[ setting->m_Id ], false );
588
589 // if cfg->m_UseStackupColors is set, board colors cannot be modified locally, but
590 // other colors can be
591 if( std::find( inStackupColors.begin(), inStackupColors.end(), setting->m_Id )
592 != inStackupColors.end() )
593 {
594 if( cfg )
595 setting->m_Ctl_color->SetReadOnly( cfg->m_UseStackupColors );
596 }
597 }
598 }
599
600 if( cfg )
602}
603
604
606{
607 m_presetsLabel->SetLabel( wxString::Format( _( "Presets (%s+Tab):" ),
609
610 m_cbLayerPresets->Clear();
611
612 // Build the layers preset list.
613
614 m_cbLayerPresets->Append( _( "Follow PCB Editor" ) );
615 m_cbLayerPresets->Append( _( "Follow PCB Plot Settings" ) );
616
617 for( const LAYER_PRESET_3D& preset : m_frame->GetAdapter().m_Cfg->m_LayerPresets )
618 m_cbLayerPresets->Append( preset.name );
619
620 m_cbLayerPresets->Append( wxT( "---" ) );
621 m_cbLayerPresets->Append( _( "Save preset..." ) );
622 m_cbLayerPresets->Append( _( "Delete preset..." ) );
623
625}
626
627
629{
630 m_frame->GetAdapter().m_Cfg->m_CurrentPreset = wxEmptyString;
631
632 std::vector<LAYER_PRESET_3D>& presets = m_frame->GetAdapter().m_Cfg->m_LayerPresets;
633 std::bitset<LAYER_3D_END> visibleLayers = m_frame->GetAdapter().GetVisibleLayers();
634 std::map<int, COLOR4D> colors = m_frame->GetAdapter().GetLayerColors();
635
636 auto it = std::find_if(
637 presets.begin(), presets.end(),
638 [&]( const LAYER_PRESET_3D& aPreset )
639 {
640 if( aPreset.name.Lower() == _( "legacy colors" )
641 && m_cbUseBoardStackupColors->GetValue() )
642 {
643 return false;
644 }
645
646 for( int layer = LAYER_3D_BOARD; layer < LAYER_3D_END; ++layer )
647 {
648 if( aPreset.layers.test( layer ) != visibleLayers.test( layer ) )
649 return false;
650 }
651
652 for( int layer : { LAYER_FP_REFERENCES, LAYER_FP_VALUES, LAYER_FP_TEXT } )
653 {
654 if( aPreset.layers.test( layer ) != visibleLayers.test( layer ) )
655 return false;
656 }
657
658 for( int layer = LAYER_3D_START + 1; layer < LAYER_3D_END; ++layer )
659 {
660 auto it1 = aPreset.colors.find( layer );
661 auto it2 = colors.find( layer );
662
663 if( it1 != aPreset.colors.end() && it2 != colors.end() && *it1 != *it2 )
664 return false;
665 }
666
667 return true;
668 } );
669
670 if( it != presets.end() )
671 {
672 m_frame->GetAdapter().m_Cfg->m_CurrentPreset = it->name;
673 m_cbLayerPresets->SetStringSelection( it->name );
674 }
675 else
676 {
677 m_cbLayerPresets->SetSelection( m_cbLayerPresets->GetCount() - 3 ); // separator
678 }
679}
680
681
683{
684 if( aName == FOLLOW_PCB )
685 m_cbLayerPresets->SetSelection( 0 );
686 else if( aName == FOLLOW_PLOT_SETTINGS )
687 m_cbLayerPresets->SetSelection( 1 );
688 else if( !m_cbLayerPresets->SetStringSelection( aName ) )
689 m_cbLayerPresets->SetSelection( m_cbLayerPresets->GetCount() - 3 ); // separator
690}
691
692
694{
696 int count = m_cbLayerPresets->GetCount();
697 int index = m_cbLayerPresets->GetSelection();
698 wxString name;
699
700 auto resetSelection =
701 [&]()
702 {
704 };
705
706 if( index == 0 )
707 {
709 cfg->m_CurrentPreset = name;
711 m_frame->NewDisplay( true );
712 }
713 else if( index == 1 )
714 {
716 cfg->m_CurrentPreset = name;
718 m_frame->NewDisplay( true );
719 }
720 else if( index == count - 3 )
721 {
722 // Separator: reject the selection
723 resetSelection();
724 return;
725 }
726 else if( index == count - 2 )
727 {
728 wxTextEntryDialog dlg( wxGetTopLevelParent( this ), _( "Layer preset name:" ),
729 _( "Save Layer Preset" ) );
730
731 if( dlg.ShowModal() != wxID_OK )
732 {
733 resetSelection();
734 return;
735 }
736
737 std::bitset<LAYER_3D_END> visibleLayers = m_frame->GetAdapter().GetVisibleLayers();
738 std::map<int, COLOR4D> colors = m_frame->GetAdapter().GetLayerColors();
739
740 name = dlg.GetValue();
741
742 if( LAYER_PRESET_3D* preset = cfg->FindPreset( name ) )
743 {
744 if( !IsOK( wxGetTopLevelParent( this ), _( "Overwrite existing preset?" ) ) )
745 {
746 resetSelection();
747 return;
748 }
749
750 preset->layers = visibleLayers;
751 preset->colors = colors;
752 m_cbLayerPresets->SetSelection( m_cbLayerPresets->FindString( name ) );
753 }
754 else
755 {
756 cfg->m_LayerPresets.emplace_back( name, visibleLayers, colors );
757 m_cbLayerPresets->SetSelection( m_cbLayerPresets->Insert( name, index - 1 ) );
758 }
759
760 cfg->m_CurrentPreset = name;
761 m_presetMRU.Insert( name, 0 );
762
763 return;
764 }
765 else if( index == count - 1 )
766 {
767 wxArrayString headers;
768 std::vector<wxArrayString> items;
769
770 headers.Add( _( "Presets" ) );
771
772 for( LAYER_PRESET_3D& preset : cfg->m_LayerPresets )
773 {
774 wxArrayString item;
775 item.Add( preset.name );
776 items.emplace_back( item );
777 }
778
779 EDA_LIST_DIALOG dlg( m_frame, _( "Delete Preset" ), headers, items );
780 dlg.SetListLabel( _( "Select preset:" ) );
781
782 if( dlg.ShowModal() == wxID_OK )
783 {
784 name = dlg.GetTextSelection();
785
786 if( m_cbLayerPresets->FindString( name ) != wxNOT_FOUND )
787 m_cbLayerPresets->Delete( m_cbLayerPresets->FindString( name ) );
788
790 [name]( const LAYER_PRESET_3D& preset )
791 {
792 return preset.name == name;
793 } );
794
795 if( cfg->m_CurrentPreset == name )
796 cfg->m_CurrentPreset = wxEmptyString;
797
798 m_presetMRU.Remove( name );
799 }
800
801 resetSelection();
802 return;
803 }
804 else if( LAYER_PRESET_3D* preset = cfg->FindPreset( m_cbLayerPresets->GetStringSelection() ) )
805 {
806 name = preset->name;
807 doApplyLayerPreset( *preset );
808 }
809
810 // Move to front of MRU list
811 if( m_presetMRU.Index( name ) != wxNOT_FOUND )
812 m_presetMRU.Remove( name );
813
814 m_presetMRU.Insert( name, 0 );
815
816 passOnFocus();
817}
818
819
821{
822 BOARD_ADAPTER& adapter = m_frame->GetAdapter();
823
824 adapter.m_Cfg->m_CurrentPreset = aPreset.name;
825 adapter.SetVisibleLayers( aPreset.layers );
826 adapter.SetLayerColors( aPreset.colors );
827
828 if( aPreset.name.Lower() == _( "legacy colors" ) )
829 adapter.m_Cfg->m_UseStackupColors = false;
830
832 m_frame->NewDisplay( true );
833}
834
835
837{
838 m_viewportsLabel->SetLabel( wxString::Format( _( "Viewports (%s+Tab):" ),
840
841 m_cbViewports->Clear();
842
843 for( std::pair<const wxString, VIEWPORT3D>& pair : m_viewports )
844 m_cbViewports->Append( pair.first, static_cast<void*>( &pair.second ) );
845
846 m_cbViewports->Append( wxT( "---" ) );
847 m_cbViewports->Append( _( "Save viewport..." ) );
848 m_cbViewports->Append( _( "Delete viewport..." ) );
849
850 m_cbViewports->SetSelection( m_cbViewports->GetCount() - 3 );
851 m_lastSelectedViewport = nullptr;
852}
853
854
855void APPEARANCE_CONTROLS_3D::onViewportChanged( wxCommandEvent& aEvent )
856{
857 int count = m_cbViewports->GetCount();
858 int index = m_cbViewports->GetSelection();
859
860 if( index >= 0 && index < count - 3 )
861 {
862 VIEWPORT3D* viewport = static_cast<VIEWPORT3D*>( m_cbViewports->GetClientData( index ) );
863
864 wxCHECK( viewport, /* void */ );
865
866 doApplyViewport( *viewport );
867
868 if( !viewport->name.IsEmpty() )
869 {
870 m_viewportMRU.Remove( viewport->name );
871 m_viewportMRU.Insert( viewport->name, 0 );
872 }
873 }
874 else if( index == count - 2 )
875 {
876 // Save current state to new preset
877 wxString name;
878
879 wxTextEntryDialog dlg( wxGetTopLevelParent( this ), _( "Viewport name:" ),
880 _( "Save Viewport" ), name );
881
882 if( dlg.ShowModal() != wxID_OK )
883 {
885 m_cbViewports->SetStringSelection( m_lastSelectedViewport->name );
886 else
887 m_cbViewports->SetSelection( m_cbViewports->GetCount() - 3 );
888
889 return;
890 }
891
892 name = dlg.GetValue();
893 bool exists = m_viewports.count( name );
894
895 if( !exists )
896 {
898
899 index = m_cbViewports->Insert( name, index-1, static_cast<void*>( &m_viewports[name] ) );
900 }
901 else
902 {
904 index = m_cbViewports->FindString( name );
905 m_viewportMRU.Remove( name );
906 }
907
908 m_cbViewports->SetSelection( index );
909 m_viewportMRU.Insert( name, 0 );
910
911 return;
912 }
913 else if( index == count - 1 )
914 {
915 // Delete an existing viewport
916 wxArrayString headers;
917 std::vector<wxArrayString> items;
918
919 headers.Add( _( "Viewports" ) );
920
921 for( std::pair<const wxString, VIEWPORT3D>& pair : m_viewports )
922 {
923 wxArrayString item;
924 item.Add( pair.first );
925 items.emplace_back( item );
926 }
927
928 EDA_LIST_DIALOG dlg( m_frame, _( "Delete Viewport" ), headers, items );
929 dlg.SetListLabel( _( "Select viewport:" ) );
930
931 if( dlg.ShowModal() == wxID_OK )
932 {
933 wxString viewportName = dlg.GetTextSelection();
934 int idx = m_cbViewports->FindString( viewportName );
935
936 if( idx != wxNOT_FOUND )
937 {
938 m_viewports.erase( viewportName );
939 m_cbViewports->Delete( idx );
940 m_viewportMRU.Remove( viewportName );
941 }
942 }
943
945 m_cbViewports->SetStringSelection( m_lastSelectedViewport->name );
946 else
947 m_cbViewports->SetSelection( m_cbViewports->GetCount() - 3 );
948
949 return;
950 }
951
952 passOnFocus();
953}
954
955
956void APPEARANCE_CONTROLS_3D::onUpdateViewportsCb( wxUpdateUIEvent& aEvent )
957{
958 int count = m_cbViewports->GetCount();
959 int index = m_cbViewports->GetSelection();
960
961 if( index >= 0 && index < count - 3 )
962 {
963 VIEWPORT3D* viewport = static_cast<VIEWPORT3D*>( m_cbViewports->GetClientData( index ) );
964
965 wxCHECK( viewport, /* void */ );
966
967 if( m_frame->GetCurrentCamera().GetViewMatrix() != viewport->matrix )
968 m_cbViewports->SetSelection( -1 );
969 }
970}
971
972
974{
976
977 if( m_frame->GetAdapter().m_Cfg->m_Render.engine == RENDER_ENGINE::OPENGL )
979 else
981}
982
983
985{
986 m_focusOwner->SetFocus();
987}
988
989
const char * name
Definition: DXF_plotter.cpp:57
static std::vector< int > inStackupColors
#define RR
wxBitmap KiBitmap(BITMAPS aBitmap, int aHeightTag)
Construct a wxBitmap from an image identifier Returns the image from the active theme if the image ha...
Definition: bitmap.cpp:104
Container for an appearance setting (can control a layer class, object type, etc.)
Class APPEARANCE_CONTROLS_3D_BASE.
void OnLanguageChanged(wxCommandEvent &aEvent)
GRID_BITMAP_TOGGLE_RENDERER * m_toggleGridRenderer
void onLayerPresetChanged(wxCommandEvent &aEvent) override
void updateLayerPresetWidget(const wxString &aName)
std::vector< VIEWPORT3D > GetUserViewports() const
Update the current viewports from those saved in the project file.
void ApplyViewport(const wxString &aPresetName)
void onColorSwatchChanged(COLOR_SWATCH *aSwatch)
APPEARANCE_CONTROLS_3D(EDA_3D_VIEWER_FRAME *aParent, wxWindow *aFocusOwner)
std::vector< std::unique_ptr< APPEARANCE_SETTING_3D > > m_layerSettings
std::map< int, APPEARANCE_SETTING_3D * > m_layerSettingsMap
static const APPEARANCE_SETTING_3D s_layerSettings[]
Template for object appearance settings.
void doApplyLayerPreset(const LAYER_PRESET_3D &aPreset)
EDA_3D_VIEWER_FRAME * m_frame
void onUpdateViewportsCb(wxUpdateUIEvent &aEvent) override
void OnSetFocus(wxFocusEvent &aEvent) override
void OnLayerVisibilityChanged(int aLayer, bool isVisible)
void OnSize(wxSizeEvent &aEvent) override
void doApplyViewport(const VIEWPORT3D &aViewport)
std::map< wxString, VIEWPORT3D > m_viewports
void ApplyLayerPreset(const wxString &aPresetName)
void onViewportChanged(wxCommandEvent &aEvent) override
void SetUserViewports(std::vector< VIEWPORT3D > &aPresetList)
A checkbox control except with custom bitmaps for the checked and unchecked states.
Definition: bitmap_toggle.h:45
Helper class to handle information needed to display 3D board.
Definition: board_adapter.h:73
void SetVisibleLayers(const std::bitset< LAYER_3D_END > &aLayers)
std::map< int, COLOR4D > GetLayerColors() const
std::bitset< LAYER_3D_END > GetVisibleLayers() const
void SetLayerColors(const std::map< int, COLOR4D > &aColors)
EDA_3D_VIEWER_SETTINGS * m_Cfg
std::map< int, COLOR4D > GetDefaultColors() const
const glm::mat4 & GetViewMatrix() const
Definition: camera.cpp:509
void SetViewMatrix(glm::mat4 aViewMatrix)
Set the affine matrix to be applied to a transformation camera.
Definition: camera.cpp:515
A simple color swatch of the kind used to set layer colors.
Definition: color_swatch.h:57
KIGFX::COLOR4D GetSwatchColor() const
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:125
Class to handle configuration and automatic determination of the DPI scale to use for canvases.
double GetContentScaleFactor() const override
Get the content scale factor, which may be different from the scale factor on some platforms.
double GetScaleFactor() const override
Get the DPI scale from all known sources in order:
static TOOL_ACTION showNotInPosFile
static TOOL_ACTION showTHT
static TOOL_ACTION showDNP
static TOOL_ACTION showSMD
static TOOL_ACTION showVirtual
static TOOL_ACTION showBBoxes
static TOOL_ACTION showAxis
RENDER_3D_BASE * GetCurrentRender() const
void RenderRaytracingRequest()
Request to render the current view in Raytracing mode.
void Request_refresh(bool aRedrawImmediately=true)
Schedule a refresh update of the canvas.
Create and handle a window for the 3d viewer connected to a Kiway and a pcbboard.
BOARD_ADAPTER & GetAdapter() override
void NewDisplay(bool aForceImmediateRedraw=false)
Reload and refresh (rebuild) the 3D scene.
CAMERA & GetCurrentCamera() override
EDA_3D_CANVAS * GetCanvas()
LAYER_PRESET_3D * FindPreset(const wxString &aName)
std::vector< LAYER_PRESET_3D > m_LayerPresets
WX_INFOBAR * GetInfoBar()
A dialog which shows:
wxString GetTextSelection(int aColumn=0)
Return the selected text from aColumn in the wxListCtrl in the dialog.
void SetListLabel(const wxString &aLabel)
A toggle button renderer for a wxGrid, similar to BITMAP_TOGGLE.
A color representation with 4 components: red, green, blue, alpha.
Definition: color4d.h:104
Object to render the board using openGL.
void Load3dModelsIfNeeded()
Load footprint models if they are not already loaded, i.e.
A modified version of the wxInfoBar class that allows us to:
Definition: wx_infobar.h:75
void RemoveAllButtons()
Remove all the buttons that have been added by the user.
Definition: wx_infobar.cpp:301
void ShowMessageFor(const wxString &aMessage, int aTime, int aFlags=wxICON_INFORMATION, MESSAGE_TYPE aType=WX_INFOBAR::MESSAGE_TYPE::GENERIC)
Show the infobar with the provided message and icon for a specific period of time.
Definition: wx_infobar.cpp:140
void AddCloseButton(const wxString &aTooltip=_("Hide this message."))
Add the default close button to the infobar on the right side.
Definition: wx_infobar.cpp:291
void SetBorders(bool aLeft, bool aRight, bool aTop, bool aBottom)
Definition: wx_panel.h:39
@ SWATCH_SMALL
Definition: color_swatch.h:40
bool IsOK(wxWindow *aParent, const wxString &aMessage)
Display a yes/no dialog with aMessage and returns the user response.
Definition: confirm.cpp:360
This file is part of the common library.
#define _HKI(x)
#define _(s)
Declaration of the eda_3d_viewer class.
#define FOLLOW_PLOT_SETTINGS
#define FOLLOW_PCB
#define VIEWPORT_SWITCH_KEY
#define PRESET_SWITCH_KEY
wxString KeyNameFromKeyCode(int aKeycode, bool *aIsFound)
Return the key name from the key code.
@ LAYER_3D_SOLDERMASK_TOP
Definition: layer_ids.h:459
@ LAYER_3D_BOUNDING_BOXES
Definition: layer_ids.h:472
@ LAYER_3D_START
Definition: layer_ids.h:449
@ LAYER_3D_ADHESIVE
Definition: layer_ids.h:461
@ LAYER_3D_SMD_MODELS
Definition: layer_ids.h:467
@ LAYER_3D_BACKGROUND_TOP
Definition: layer_ids.h:452
@ LAYER_3D_USER_COMMENTS
Definition: layer_ids.h:462
@ LAYER_3D_SOLDERMASK_BOTTOM
Definition: layer_ids.h:458
@ LAYER_3D_BOARD
Definition: layer_ids.h:453
@ LAYER_3D_USER_ECO1
Definition: layer_ids.h:464
@ LAYER_3D_USER_ECO2
Definition: layer_ids.h:465
@ LAYER_3D_TH_MODELS
Definition: layer_ids.h:466
@ LAYER_3D_AXES
Definition: layer_ids.h:471
@ LAYER_3D_SILKSCREEN_TOP
Definition: layer_ids.h:457
@ LAYER_3D_VIRTUAL_MODELS
Definition: layer_ids.h:468
@ LAYER_3D_MODELS_MARKED_DNP
Definition: layer_ids.h:470
@ LAYER_3D_COPPER_TOP
Definition: layer_ids.h:454
@ LAYER_3D_SOLDERPASTE
Definition: layer_ids.h:460
@ LAYER_3D_OFF_BOARD_SILK
Definition: layer_ids.h:473
@ LAYER_3D_MODELS_NOT_IN_POS
Definition: layer_ids.h:469
@ LAYER_3D_USER_DRAWINGS
Definition: layer_ids.h:463
@ LAYER_3D_COPPER_BOTTOM
Definition: layer_ids.h:455
@ LAYER_3D_BACKGROUND_BOTTOM
Definition: layer_ids.h:451
@ LAYER_3D_SILKSCREEN_BOTTOM
Definition: layer_ids.h:456
@ LAYER_3D_END
Definition: layer_ids.h:475
@ LAYER_FP_REFERENCES
show footprints references (when texts are visible)
Definition: layer_ids.h:215
@ LAYER_FP_TEXT
Definition: layer_ids.h:202
@ LAYER_FP_VALUES
show footprints values (when texts are visible)
Definition: layer_ids.h:214
KICOMMON_API wxFont GetInfoFont(wxWindow *aWindow)
Definition: ui_common.cpp:151
void delete_if(_Container &__c, _Function &&__f)
Deletes all values from __c for which __f returns true.
Definition: kicad_algo.h:174
void Refresh()
Update the board display after modifying it by a python script (note: it is automatically called by a...
see class PGM_BASE
wxString name
A name for this layer set.
std::bitset< LAYER_3D_END > layers
std::map< int, KIGFX::COLOR4D > colors