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