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