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 The 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
49#define RR APPEARANCE_CONTROLS_3D::APPEARANCE_SETTING_3D
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 ),
72 RR( _HKI( "Models not in POS File" ), LAYER_3D_MODELS_NOT_IN_POS,
75 RR( _HKI( "Model Bounding Boxes" ), LAYER_3D_BOUNDING_BOXES, EDA_3D_ACTIONS::showBBoxes ),
76 RR(),
77 RR( _HKI( "Values" ), LAYER_FP_VALUES, _HKI( "Show footprint values" ) ),
78 RR( _HKI( "References" ), LAYER_FP_REFERENCES, _HKI( "Show footprint references" ) ),
79 RR( _HKI( "Footprint Text" ), LAYER_FP_TEXT, _HKI( "Show all footprint text" ) ),
80 RR( _HKI( "Off-board Silkscreen" ), LAYER_3D_OFF_BOARD_SILK,
81 _HKI( "Do not clip silk layers to board outline" ) ),
82 RR(),
84 RR( _HKI( "Background Start" ), LAYER_3D_BACKGROUND_TOP,
85 _HKI( "Background gradient start color" ) ),
86 RR( _HKI( "Background End" ), LAYER_3D_BACKGROUND_BOTTOM,
87 _HKI( "Background gradient end color" ) ),
88};
89
90// The list of IDs that can have colors coming from the board stackup, and cannot be
91// modified if use colors from stackup is activated
96 };
97
99 wxWindow* aFocusOwner ) :
101 m_frame( aParent ),
102 m_focusOwner( aFocusOwner ),
103 m_lastSelectedViewport( nullptr )
104{
105 DPI_SCALING_COMMON dpi( nullptr, m_frame );
106
107 int screenHeight = wxSystemSettings::GetMetric( wxSYS_SCREEN_Y );
108 m_pointSize = wxSystemSettings::GetFont( wxSYS_DEFAULT_GUI_FONT ).GetPointSize();
109
110 m_layerPanelColour = m_panelLayers->GetBackgroundColour().ChangeLightness( 110 );
111 SetBorders( true, false, false, false );
112
113 m_layersOuterSizer = new wxBoxSizer( wxVERTICAL );
115 m_windowLayers->SetScrollRate( 0, 5 );
116 m_windowLayers->Bind( wxEVT_SET_FOCUS, &APPEARANCE_CONTROLS_3D::OnSetFocus, this );
117
118 m_envOuterSizer = new wxBoxSizer( wxVERTICAL );
119
120 wxFont infoFont = KIUI::GetInfoFont( this );
121 m_panelLayers->SetFont( infoFont );
122 m_windowLayers->SetFont( infoFont );
123 m_presetsLabel->SetFont( infoFont );
124 m_viewportsLabel->SetFont( infoFont );
125
126 // Create display options
127 m_cbUseBoardStackupColors = new wxCheckBox( m_panelLayers, wxID_ANY,
128 _( "Use board stackup colors" ) );
129 m_cbUseBoardStackupColors->SetFont( infoFont );
130
131 m_cbUseBoardStackupColors->Bind( wxEVT_CHECKBOX,
132 [this]( wxCommandEvent& aEvent )
133 {
135 cfg->m_UseStackupColors = aEvent.IsChecked();
136
139 m_frame->NewDisplay( true );
140 } );
141
142 m_cbUseBoardEditorCopperColors = new wxCheckBox( m_panelLayers, wxID_ANY,
143 _( "Use board editor copper colors" ) );
144 m_cbUseBoardEditorCopperColors->SetFont( infoFont );
146 _( "Use the board editor copper colors (openGL only)" ) );
147
148 m_cbUseBoardEditorCopperColors->Bind( wxEVT_CHECKBOX,
149 [this]( wxCommandEvent& aEvent )
150 {
152 cfg->m_Render.use_board_editor_copper_colors = aEvent.IsChecked();
153
156 m_frame->NewDisplay( true );
157 } );
158
159
160 m_panelLayersSizer->Add( m_cbUseBoardStackupColors, 0, wxEXPAND | wxTOP | wxLEFT | wxRIGHT, 7 );
162 wxEXPAND | wxTOP | wxLEFT | wxRIGHT, 7 );
163
164 m_cbLayerPresets->SetToolTip( wxString::Format( _( "Save and restore color and visibility "
165 "combinations.\n"
166 "Use %s+Tab to activate selector.\n"
167 "Successive Tabs while holding %s down will "
168 "cycle through presets in the popup." ),
171
172 m_cbViewports->SetToolTip( wxString::Format( _( "Save and restore camera position and zoom.\n"
173 "Use %s+Tab to activate selector.\n"
174 "Successive Tabs while holding %s down will "
175 "cycle through viewports in the popup." ),
178
179 if( screenHeight <= 900 && m_pointSize >= FromDIP( KIUI::c_IndicatorSizeDIP ) )
180 m_pointSize = m_pointSize * 8 / 10;
181
183
185 KiBitmapBundle( BITMAPS::visibility ), KiBitmapBundle( BITMAPS::visibility_off ) );
186
187 m_frame->Bind( EDA_LANG_CHANGED, &APPEARANCE_CONTROLS_3D::OnLanguageChanged, this );
188}
189
190
192{
193 m_frame->Unbind( EDA_LANG_CHANGED, &APPEARANCE_CONTROLS_3D::OnLanguageChanged, this );
194}
195
196
198{
199 DPI_SCALING_COMMON dpi( nullptr, m_frame );
200 wxSize size( 220 * dpi.GetScaleFactor(), 480 * dpi.GetScaleFactor() );
201 return size;
202}
203
204
205void APPEARANCE_CONTROLS_3D::OnSetFocus( wxFocusEvent& aEvent )
206{
207#ifdef __WXMSW__
208 // In wxMSW, buttons won't process events unless they have focus, so we'll let it take the
209 // focus and give it back to the parent in the button event handler.
210 if( wxBitmapButton* btn = dynamic_cast<wxBitmapButton*>( aEvent.GetEventObject() ) )
211 {
212 wxCommandEvent evt( wxEVT_BUTTON );
213 wxPostEvent( btn, evt );
214 }
215#endif
216
217 passOnFocus();
218 aEvent.Skip();
219}
220
221
222void APPEARANCE_CONTROLS_3D::OnSize( wxSizeEvent& aEvent )
223{
224 aEvent.Skip();
225}
226
227
229{
230 Freeze();
231
233 m_cbUseBoardStackupColors->SetLabel( _( "Use board stackup colors" ) );
236
237 Thaw();
238 Refresh();
239}
240
241
242void APPEARANCE_CONTROLS_3D::OnLanguageChanged( wxCommandEvent& aEvent )
243{
245
246 aEvent.Skip();
247}
248
249
251{
252 // This is essentially a list of hacks because DarkMode isn't yet implemented inside
253 // wxWidgets.
254 //
255 // The individual wxPanels, COLOR_SWATCHes and GRID_CELL_COLOR_RENDERERs should really be
256 // overriding some virtual method or responding to some wxWidgets event so that the parent
257 // doesn't have to know what it contains. But, that's not where we are, so... :shrug:
258
259 m_layerPanelColour = m_panelLayers->GetBackgroundColour().ChangeLightness( 110 );
260
261 m_windowLayers->SetBackgroundColour( m_layerPanelColour );
262
263 for( wxSizerItem* child : m_layersOuterSizer->GetChildren() )
264 {
265 if( child && child->GetWindow() )
266 child->GetWindow()->SetBackgroundColour( m_layerPanelColour );
267 }
268}
269
270
272{
274
277}
278
279
280void APPEARANCE_CONTROLS_3D::ApplyLayerPreset( const wxString& aPresetName )
281{
282 if( aPresetName == FOLLOW_PCB || aPresetName == FOLLOW_PLOT_SETTINGS )
283 {
284 m_frame->GetAdapter().m_Cfg->m_CurrentPreset = aPresetName;
286 m_frame->NewDisplay( true );
287 }
288 else if( LAYER_PRESET_3D* preset = m_frame->GetAdapter().m_Cfg->FindPreset( aPresetName ) )
289 {
290 doApplyLayerPreset( *preset );
291 }
292
293 // Move to front of MRU list
294 if( m_presetMRU.Index( aPresetName ) != wxNOT_FOUND )
295 m_presetMRU.Remove( aPresetName );
296
297 m_presetMRU.Insert( aPresetName, 0 );
298
299 updateLayerPresetWidget( aPresetName );
300}
301
302
303std::vector<VIEWPORT3D> APPEARANCE_CONTROLS_3D::GetUserViewports() const
304{
305 std::vector<VIEWPORT3D> ret;
306
307 for( const auto& [name, viewport] : m_viewports )
308 ret.emplace_back( viewport );
309
310 return ret;
311}
312
313
314void APPEARANCE_CONTROLS_3D::SetUserViewports( std::vector<VIEWPORT3D>& aViewportList )
315{
316 m_viewports.clear();
317
318 for( const VIEWPORT3D& viewport : aViewportList )
319 {
320 if( m_viewports.count( viewport.name ) )
321 continue;
322
323 m_viewports[viewport.name] = viewport;
324
325 m_viewportMRU.Add( viewport.name );
326 }
327
329
330 // Now is as good a time as any to initialize the layer presets as well.
332
333 m_presetMRU.Add( FOLLOW_PCB );
335
336 for( const LAYER_PRESET_3D& preset : m_frame->GetAdapter().m_Cfg->m_LayerPresets )
337 m_presetMRU.Add( preset.name );
338}
339
340
341void APPEARANCE_CONTROLS_3D::ApplyViewport( const wxString& aViewportName )
342{
343 int idx = m_cbViewports->FindString( aViewportName );
344
345 if( idx >= 0 && idx < (int)m_cbViewports->GetCount() - 3 /* separator */ )
346 {
347 m_cbViewports->SetSelection( idx );
348 m_lastSelectedViewport = static_cast<VIEWPORT3D*>( m_cbViewports->GetClientData( idx ) );
349 }
350 else
351 {
352 m_cbViewports->SetSelection( m_cbViewports->GetCount() - 3 ); // separator
353 m_lastSelectedViewport = nullptr;
354 }
355
358}
359
360
361void APPEARANCE_CONTROLS_3D::OnLayerVisibilityChanged( int aLayer, bool isVisible )
362{
363 std::bitset<LAYER_3D_END> visibleLayers = m_frame->GetAdapter().GetVisibleLayers();
364 const std::map<int, COLOR4D>& colors = m_frame->GetAdapter().GetLayerColors();
365 bool killFollow = false;
366 bool doFastRefresh = false; // true to just refresh the display
367
368 // Special-case controls
369 switch( aLayer )
370 {
371 case LAYER_FP_TEXT:
372 // Because Footprint Text is a meta-control that also can disable values/references,
373 // drag them along here so that the user is less likely to be confused.
374 if( !isVisible )
375 {
376 visibleLayers.set( LAYER_FP_REFERENCES, false );
377 visibleLayers.set( LAYER_FP_VALUES, false );
378 }
379
380 visibleLayers.set( LAYER_FP_TEXT, isVisible );
381 killFollow = true;
382 break;
383
385 case LAYER_FP_VALUES:
386 // In case that user changes Footprint Value/References when the Footprint Text
387 // meta-control is disabled, we should put it back on.
388 if( isVisible )
389 visibleLayers.set( LAYER_FP_TEXT, true );
390
391 visibleLayers.set( aLayer, isVisible );
392 killFollow = true;
393 break;
394
395 case LAYER_3D_BOARD:
408 visibleLayers.set( aLayer, isVisible );
409 killFollow = true;
410 break;
411
417 doFastRefresh = true;
418 visibleLayers.set( aLayer, isVisible );
419 break;
420
421 default:
422 visibleLayers.set( aLayer, isVisible );
423 break;
424 }
425
426 m_frame->GetAdapter().SetVisibleLayers( visibleLayers );
427 m_frame->GetAdapter().SetLayerColors( colors );
428
429 const wxString& currentPreset = m_frame->GetAdapter().m_Cfg->m_CurrentPreset;
430
431 if( ( currentPreset != FOLLOW_PCB && currentPreset != FOLLOW_PLOT_SETTINGS ) || killFollow )
433
435
436 if( doFastRefresh && m_frame->GetAdapter().m_Cfg->m_Render.engine == RENDER_ENGINE::OPENGL )
437 {
438 RENDER_3D_OPENGL* renderer =
439 static_cast<RENDER_3D_OPENGL*>( m_frame->GetCanvas()->GetCurrentRender() );
440 renderer->Load3dModelsIfNeeded();
442 }
443 else
444 {
445 m_frame->NewDisplay( true );
446 }
447}
448
449
451{
452 std::bitset<LAYER_3D_END> visibleLayers = m_frame->GetAdapter().GetVisibleLayers();
453 std::map<int, COLOR4D> colors = m_frame->GetAdapter().GetLayerColors();
454
455 m_frame->GetAdapter().SetVisibleLayers( visibleLayers );
456 m_frame->GetAdapter().SetLayerColors( colors );
457
458 int layer = aSwatch->GetId();
459 COLOR4D newColor = aSwatch->GetSwatchColor();
460
461 colors[ layer ] = newColor;
462
463 if( layer == LAYER_3D_COPPER_TOP )
464 colors[ LAYER_3D_COPPER_BOTTOM ] = newColor;
465 else if( layer == LAYER_3D_COPPER_BOTTOM )
466 colors[ LAYER_3D_COPPER_TOP ] = newColor;
467
468 m_frame->GetAdapter().SetLayerColors( colors );
469
471
472 m_frame->NewDisplay( true );
473}
474
475
477{
478 int swatchWidth = m_windowLayers->ConvertDialogToPixels( wxSize( 8, 0 ) ).x;
479
480 std::bitset<LAYER_3D_END> visibleLayers = m_frame->GetAdapter().GetVisibleLayers();
481 std::map<int, COLOR4D> colors = m_frame->GetAdapter().GetLayerColors();
482 std::map<int, COLOR4D> defaultColors = m_frame->GetAdapter().GetDefaultColors();
483
484 m_layerSettings.clear();
485 m_layersOuterSizer->Clear( true );
486 m_layersOuterSizer->AddSpacer( 5 );
487
488 m_envOuterSizer->Clear( true );
489
490 auto appendLayer =
491 [&]( const std::unique_ptr<APPEARANCE_SETTING_3D>& aSetting )
492 {
493 wxBoxSizer* sizer = new wxBoxSizer( wxHORIZONTAL );
494 int layer = aSetting->m_Id;
495
496 aSetting->m_Visible = visibleLayers.test( layer );
497
498 if( colors.count( layer ) )
499 {
500 COLOR_SWATCH* swatch = new COLOR_SWATCH( m_windowLayers, colors[ layer ], layer,
501 COLOR4D::WHITE, defaultColors[ layer ],
502 SWATCH_SMALL );
503 swatch->SetToolTip( _( "Left double click or middle click to change color" ) );
504
505 swatch->SetReadOnlyCallback(
506 [this]()
507 {
508 WX_INFOBAR* infobar = m_frame->GetInfoBar();
509
510 infobar->RemoveAllButtons();
511 infobar->AddCloseButton();
512
513 infobar->ShowMessageFor( _( "Uncheck 'Use board stackup colors' to "
514 "allow color editing." ),
515 10000, wxICON_INFORMATION );
516 } );
517
518 sizer->Add( swatch, 0, wxALIGN_CENTER_VERTICAL, 0 );
519 aSetting->m_Ctl_color = swatch;
520
521 swatch->Bind( COLOR_SWATCH_CHANGED,
522 [this]( wxCommandEvent& event )
523 {
524 auto swatch = static_cast<COLOR_SWATCH*>( event.GetEventObject() );
525 onColorSwatchChanged( swatch );
526
527 passOnFocus();
528 } );
529 }
530 else
531 {
532 sizer->AddSpacer( swatchWidth );
533 }
534
535 sizer->AddSpacer( 5 );
536
537 wxStaticText* label = new wxStaticText( m_windowLayers, layer,
538 aSetting->GetLabel() );
539 label->Wrap( -1 );
540 label->SetToolTip( aSetting->GetTooltip() );
541
542 if( layer == LAYER_3D_BACKGROUND_TOP || layer == LAYER_3D_BACKGROUND_BOTTOM )
543 {
544 sizer->AddSpacer( swatchWidth );
545 }
546 else
547 {
548 BITMAP_TOGGLE* btn_visible = new BITMAP_TOGGLE(
549 m_windowLayers, layer, KiBitmapBundle( BITMAPS::visibility ),
550 KiBitmapBundle( BITMAPS::visibility_off ), aSetting->m_Visible );
551
552 btn_visible->Bind( TOGGLE_CHANGED,
553 [this]( wxCommandEvent& aEvent )
554 {
555 int id = static_cast<wxWindow*>( aEvent.GetEventObject() )->GetId();
556 bool isVisible = aEvent.GetInt();
557 OnLayerVisibilityChanged( id, isVisible );
558
559 passOnFocus();
560 } );
561
562 wxString tip;
563 tip.Printf( _( "Show or hide %s" ), aSetting->GetLabel().Lower() );
564 btn_visible->SetToolTip( tip );
565
566 aSetting->m_Ctl_visibility = btn_visible;
567 sizer->Add( btn_visible, 0, wxALIGN_CENTER_VERTICAL, 0 );
568 }
569
570 sizer->AddSpacer( 5 );
571 sizer->Add( label, 0, wxALIGN_CENTER_VERTICAL, 0 );
572
573 m_layersOuterSizer->Add( sizer, 0, wxEXPAND | wxLEFT | wxRIGHT, 5 );
574 m_layersOuterSizer->AddSpacer( 2 );
575 };
576
577 for( const APPEARANCE_SETTING_3D& s_setting : s_layerSettings )
578 {
579 m_layerSettings.emplace_back( std::make_unique<APPEARANCE_SETTING_3D>( s_setting ) );
580 std::unique_ptr<APPEARANCE_SETTING_3D>& setting = m_layerSettings.back();
581
582 if( setting->m_Spacer )
583 m_layersOuterSizer->AddSpacer( m_pointSize );
584 else
585 appendLayer( setting );
586
587 m_layerSettingsMap[setting->m_Id] = setting.get();
588 }
589
590 m_sizerOuter->Layout();
591}
592
593
595{
597 std::bitset<LAYER_3D_END> visibleLayers = m_frame->GetAdapter().GetVisibleLayers();
598 std::map<int, COLOR4D> colors = m_frame->GetAdapter().GetLayerColors();
599
600 for( std::unique_ptr<APPEARANCE_SETTING_3D>& setting : m_layerSettings )
601 {
602 if( setting->m_Spacer )
603 continue;
604
605 if( setting->m_Ctl_visibility )
606 setting->m_Ctl_visibility->SetValue( visibleLayers.test( setting->m_Id ) );
607
608 if( setting->m_Ctl_color )
609 {
610 setting->m_Ctl_color->SetSwatchColor( colors[ setting->m_Id ], false );
611
612 // if cfg->m_UseStackupColors is set, board colors cannot be modified locally, but
613 // other colors can be
614 if( std::find( inStackupColors.begin(), inStackupColors.end(), setting->m_Id )
615 != inStackupColors.end() )
616 {
617 if( cfg )
618 setting->m_Ctl_color->SetReadOnly( cfg->m_UseStackupColors );
619 }
620 }
621 }
622
623 if( cfg )
624 {
627 }
628}
629
630
632{
633 m_presetsLabel->SetLabel( wxString::Format( _( "Presets (%s+Tab):" ),
635
636 m_cbLayerPresets->Clear();
637
638 // Build the layers preset list.
639
640 m_cbLayerPresets->Append( _( "Follow PCB Editor" ) );
641 m_cbLayerPresets->Append( _( "Follow PCB Plot Settings" ) );
642
643 for( const LAYER_PRESET_3D& preset : m_frame->GetAdapter().m_Cfg->m_LayerPresets )
644 m_cbLayerPresets->Append( preset.name );
645
646 m_cbLayerPresets->Append( wxT( "---" ) );
647 m_cbLayerPresets->Append( _( "Save preset..." ) );
648 m_cbLayerPresets->Append( _( "Delete preset..." ) );
649
651}
652
653
655{
656 m_frame->GetAdapter().m_Cfg->m_CurrentPreset = wxEmptyString;
657
658 std::vector<LAYER_PRESET_3D>& presets = m_frame->GetAdapter().m_Cfg->m_LayerPresets;
659 std::bitset<LAYER_3D_END> visibleLayers = m_frame->GetAdapter().GetVisibleLayers();
660 std::map<int, COLOR4D> colors = m_frame->GetAdapter().GetLayerColors();
661
662 auto it = std::find_if(
663 presets.begin(), presets.end(),
664 [&]( const LAYER_PRESET_3D& aPreset )
665 {
666 if( aPreset.name.Lower() == _( "legacy colors" )
667 && m_cbUseBoardStackupColors->GetValue() )
668 {
669 return false;
670 }
671
672 for( int layer = LAYER_3D_BOARD; layer < LAYER_3D_END; ++layer )
673 {
674 if( aPreset.layers.test( layer ) != visibleLayers.test( layer ) )
675 return false;
676 }
677
678 for( int layer : { LAYER_FP_REFERENCES, LAYER_FP_VALUES, LAYER_FP_TEXT } )
679 {
680 if( aPreset.layers.test( layer ) != visibleLayers.test( layer ) )
681 return false;
682 }
683
684 for( int layer = LAYER_3D_START + 1; layer < LAYER_3D_END; ++layer )
685 {
686 auto it1 = aPreset.colors.find( layer );
687 auto it2 = colors.find( layer );
688
689 if( it1 != aPreset.colors.end() && it2 != colors.end() && *it1 != *it2 )
690 return false;
691 }
692
693 return true;
694 } );
695
696 if( it != presets.end() )
697 {
698 m_frame->GetAdapter().m_Cfg->m_CurrentPreset = it->name;
699 m_cbLayerPresets->SetStringSelection( it->name );
700 }
701 else
702 {
703 m_cbLayerPresets->SetSelection( m_cbLayerPresets->GetCount() - 3 ); // separator
704 }
705}
706
707
709{
710 if( aName == FOLLOW_PCB )
711 m_cbLayerPresets->SetSelection( 0 );
712 else if( aName == FOLLOW_PLOT_SETTINGS )
713 m_cbLayerPresets->SetSelection( 1 );
714 else if( !m_cbLayerPresets->SetStringSelection( aName ) )
715 m_cbLayerPresets->SetSelection( m_cbLayerPresets->GetCount() - 3 ); // separator
716}
717
718
720{
722 int count = m_cbLayerPresets->GetCount();
723 int index = m_cbLayerPresets->GetSelection();
724 wxString name;
725
726 auto resetSelection =
727 [&]()
728 {
730 };
731
732 if( index == 0 )
733 {
735 cfg->m_CurrentPreset = name;
737 m_frame->NewDisplay( true );
738 }
739 else if( index == 1 )
740 {
742 cfg->m_CurrentPreset = name;
744 m_frame->NewDisplay( true );
745 }
746 else if( index == count - 3 )
747 {
748 // Separator: reject the selection
749 resetSelection();
750 return;
751 }
752 else if( index == count - 2 )
753 {
754 wxTextEntryDialog dlg( wxGetTopLevelParent( this ), _( "Layer preset name:" ),
755 _( "Save Layer Preset" ) );
756
757 if( dlg.ShowModal() != wxID_OK )
758 {
759 resetSelection();
760 return;
761 }
762
763 std::bitset<LAYER_3D_END> visibleLayers = m_frame->GetAdapter().GetVisibleLayers();
764 std::map<int, COLOR4D> colors = m_frame->GetAdapter().GetLayerColors();
765
766 name = dlg.GetValue();
767
768 if( LAYER_PRESET_3D* preset = cfg->FindPreset( name ) )
769 {
770 if( !IsOK( wxGetTopLevelParent( this ), _( "Overwrite existing preset?" ) ) )
771 {
772 resetSelection();
773 return;
774 }
775
776 preset->layers = visibleLayers;
777 preset->colors = colors;
778 m_cbLayerPresets->SetSelection( m_cbLayerPresets->FindString( name ) );
779 }
780 else
781 {
782 cfg->m_LayerPresets.emplace_back( name, visibleLayers, colors );
783 m_cbLayerPresets->SetSelection( m_cbLayerPresets->Insert( name, index - 1 ) );
784 }
785
786 cfg->m_CurrentPreset = name;
787 m_presetMRU.Insert( name, 0 );
788
789 return;
790 }
791 else if( index == count - 1 )
792 {
793 wxArrayString headers;
794 std::vector<wxArrayString> items;
795
796 headers.Add( _( "Presets" ) );
797
798 for( LAYER_PRESET_3D& preset : cfg->m_LayerPresets )
799 {
800 wxArrayString item;
801 item.Add( preset.name );
802 items.emplace_back( item );
803 }
804
805 EDA_LIST_DIALOG dlg( m_frame, _( "Delete Preset" ), headers, items );
806 dlg.SetListLabel( _( "Select preset:" ) );
807
808 if( dlg.ShowModal() == wxID_OK )
809 {
810 name = dlg.GetTextSelection();
811
812 if( m_cbLayerPresets->FindString( name ) != wxNOT_FOUND )
813 m_cbLayerPresets->Delete( m_cbLayerPresets->FindString( name ) );
814
816 [name]( const LAYER_PRESET_3D& preset )
817 {
818 return preset.name == name;
819 } );
820
821 if( cfg->m_CurrentPreset == name )
822 cfg->m_CurrentPreset = wxEmptyString;
823
824 m_presetMRU.Remove( name );
825 }
826
827 resetSelection();
828 return;
829 }
830 else if( LAYER_PRESET_3D* preset = cfg->FindPreset( m_cbLayerPresets->GetStringSelection() ) )
831 {
832 name = preset->name;
833 doApplyLayerPreset( *preset );
834 }
835
836 // Move to front of MRU list
837 if( m_presetMRU.Index( name ) != wxNOT_FOUND )
838 m_presetMRU.Remove( name );
839
840 m_presetMRU.Insert( name, 0 );
841
842 passOnFocus();
843}
844
845
847{
848 BOARD_ADAPTER& adapter = m_frame->GetAdapter();
849
850 adapter.m_Cfg->m_CurrentPreset = aPreset.name;
851 adapter.SetVisibleLayers( aPreset.layers );
852 adapter.SetLayerColors( aPreset.colors );
853
854 if( aPreset.name.Lower() == _( "legacy colors" ) )
855 adapter.m_Cfg->m_UseStackupColors = false;
856
858 m_frame->NewDisplay( true );
859}
860
861
863{
864 m_viewportsLabel->SetLabel( wxString::Format( _( "Viewports (%s+Tab):" ),
866
867 m_cbViewports->Clear();
868
869 for( std::pair<const wxString, VIEWPORT3D>& pair : m_viewports )
870 m_cbViewports->Append( pair.first, static_cast<void*>( &pair.second ) );
871
872 m_cbViewports->Append( wxT( "---" ) );
873 m_cbViewports->Append( _( "Save viewport..." ) );
874 m_cbViewports->Append( _( "Delete viewport..." ) );
875
876 m_cbViewports->SetSelection( m_cbViewports->GetCount() - 3 );
877 m_lastSelectedViewport = nullptr;
878}
879
880
881void APPEARANCE_CONTROLS_3D::onViewportChanged( wxCommandEvent& aEvent )
882{
883 int count = m_cbViewports->GetCount();
884 int index = m_cbViewports->GetSelection();
885
886 if( index >= 0 && index < count - 3 )
887 {
888 VIEWPORT3D* viewport = static_cast<VIEWPORT3D*>( m_cbViewports->GetClientData( index ) );
889
890 wxCHECK( viewport, /* void */ );
891
892 doApplyViewport( *viewport );
893
894 if( !viewport->name.IsEmpty() )
895 {
896 m_viewportMRU.Remove( viewport->name );
897 m_viewportMRU.Insert( viewport->name, 0 );
898 }
899 }
900 else if( index == count - 2 )
901 {
902 // Save current state to new preset
903 wxString name;
904
905 wxTextEntryDialog dlg( wxGetTopLevelParent( this ), _( "Viewport name:" ),
906 _( "Save Viewport" ), name );
907
908 if( dlg.ShowModal() != wxID_OK )
909 {
911 m_cbViewports->SetStringSelection( m_lastSelectedViewport->name );
912 else
913 m_cbViewports->SetSelection( m_cbViewports->GetCount() - 3 );
914
915 return;
916 }
917
918 name = dlg.GetValue();
919 bool exists = m_viewports.count( name );
920
921 if( !exists )
922 {
924
925 index = m_cbViewports->Insert( name, index-1,
926 static_cast<void*>( &m_viewports[name] ) );
927 }
928 else
929 {
931 index = m_cbViewports->FindString( name );
932 m_viewportMRU.Remove( name );
933 }
934
935 m_cbViewports->SetSelection( index );
936 m_viewportMRU.Insert( name, 0 );
937
938 return;
939 }
940 else if( index == count - 1 )
941 {
942 // Delete an existing viewport
943 wxArrayString headers;
944 std::vector<wxArrayString> items;
945
946 headers.Add( _( "Viewports" ) );
947
948 for( std::pair<const wxString, VIEWPORT3D>& pair : m_viewports )
949 {
950 wxArrayString item;
951 item.Add( pair.first );
952 items.emplace_back( item );
953 }
954
955 EDA_LIST_DIALOG dlg( m_frame, _( "Delete Viewport" ), headers, items );
956 dlg.SetListLabel( _( "Select viewport:" ) );
957
958 if( dlg.ShowModal() == wxID_OK )
959 {
960 wxString viewportName = dlg.GetTextSelection();
961 int idx = m_cbViewports->FindString( viewportName );
962
963 if( idx != wxNOT_FOUND )
964 {
965 m_viewports.erase( viewportName );
966 m_cbViewports->Delete( idx );
967 m_viewportMRU.Remove( viewportName );
968 }
969 }
970
972 m_cbViewports->SetStringSelection( m_lastSelectedViewport->name );
973 else
974 m_cbViewports->SetSelection( m_cbViewports->GetCount() - 3 );
975
976 return;
977 }
978
979 passOnFocus();
980}
981
982
983void APPEARANCE_CONTROLS_3D::onUpdateViewportsCb( wxUpdateUIEvent& aEvent )
984{
985 int count = m_cbViewports->GetCount();
986 int index = m_cbViewports->GetSelection();
987
988 if( index >= 0 && index < count - 3 )
989 {
990 VIEWPORT3D* viewport = static_cast<VIEWPORT3D*>( m_cbViewports->GetClientData( index ) );
991
992 wxCHECK( viewport, /* void */ );
993
994 if( m_frame->GetCurrentCamera().GetViewMatrix() != viewport->matrix )
995 m_cbViewports->SetSelection( -1 );
996 }
997}
998
999
1001{
1003
1004 if( m_frame->GetAdapter().m_Cfg->m_Render.engine == RENDER_ENGINE::OPENGL )
1006 else
1008}
1009
1010
1012{
1013 m_focusOwner->SetFocus();
1014}
1015
1016
const char * name
Definition: DXF_plotter.cpp:59
static std::vector< int > inStackupColors
#define RR
Render Row abbreviation to reduce source width.
wxBitmapBundle KiBitmapBundle(BITMAPS aBitmap)
Definition: bitmap.cpp:110
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
Return a list of viewports created by the user.
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
wxCheckBox * m_cbUseBoardEditorCopperColors
void ApplyLayerPreset(const wxString &aPresetName)
void onViewportChanged(wxCommandEvent &aEvent) override
void SetUserViewports(std::vector< VIEWPORT3D > &aPresetList)
Update the current viewports from those saved in the project file.
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
Build a color list which is used to store colors layers.
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:510
void SetViewMatrix(glm::mat4 aViewMatrix)
Set the affine matrix to be applied to a transformation camera.
Definition: camera.cpp:516
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)
Register a handler for when the user tries to interact with a read-only swatch.
Definition: color_swatch.h:126
int ShowModal() override
Class to handle configuration and automatic determination of the DPI scale to use for canvases.
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.
void NewDisplay(bool aForceImmediateRedraw=false)
Reload and refresh (rebuild) the 3D scene.
EDA_3D_CANVAS * GetCanvas()
BOARD_ADAPTER & GetAdapter()
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:76
void RemoveAllButtons()
Remove all the buttons that have been added by the user.
Definition: wx_infobar.cpp:320
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:139
void AddCloseButton(const wxString &aTooltip=_("Hide this message."))
Add the default close button to the infobar on the right side.
Definition: wx_infobar.cpp:310
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:250
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:510
@ LAYER_3D_BOUNDING_BOXES
Definition: layer_ids.h:523
@ LAYER_3D_START
Definition: layer_ids.h:500
@ LAYER_3D_ADHESIVE
Definition: layer_ids.h:512
@ LAYER_3D_SMD_MODELS
Definition: layer_ids.h:518
@ LAYER_3D_BACKGROUND_TOP
Definition: layer_ids.h:503
@ LAYER_3D_USER_COMMENTS
Definition: layer_ids.h:513
@ LAYER_3D_SOLDERMASK_BOTTOM
Definition: layer_ids.h:509
@ LAYER_3D_BOARD
Definition: layer_ids.h:504
@ LAYER_3D_USER_ECO1
Definition: layer_ids.h:515
@ LAYER_3D_USER_ECO2
Definition: layer_ids.h:516
@ LAYER_3D_TH_MODELS
Definition: layer_ids.h:517
@ LAYER_3D_AXES
Definition: layer_ids.h:522
@ LAYER_3D_SILKSCREEN_TOP
Definition: layer_ids.h:508
@ LAYER_3D_VIRTUAL_MODELS
Definition: layer_ids.h:519
@ LAYER_3D_MODELS_MARKED_DNP
Definition: layer_ids.h:521
@ LAYER_3D_COPPER_TOP
Definition: layer_ids.h:505
@ LAYER_3D_SOLDERPASTE
Definition: layer_ids.h:511
@ LAYER_3D_OFF_BOARD_SILK
Definition: layer_ids.h:524
@ LAYER_3D_MODELS_NOT_IN_POS
Definition: layer_ids.h:520
@ LAYER_3D_USER_DRAWINGS
Definition: layer_ids.h:514
@ LAYER_3D_COPPER_BOTTOM
Definition: layer_ids.h:506
@ LAYER_3D_BACKGROUND_BOTTOM
Definition: layer_ids.h:502
@ LAYER_3D_SILKSCREEN_BOTTOM
Definition: layer_ids.h:507
@ LAYER_3D_END
Definition: layer_ids.h:526
@ LAYER_FP_REFERENCES
Show footprints references (when texts are visible).
Definition: layer_ids.h:228
@ LAYER_FP_TEXT
Definition: layer_ids.h:202
@ LAYER_FP_VALUES
Show footprints values (when texts are visible).
Definition: layer_ids.h:225
KICOMMON_API wxFont GetInfoFont(wxWindow *aWindow)
Definition: ui_common.cpp:155
const int c_IndicatorSizeDIP
Definition: ui_common.h:52
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