1 /*
2 * This program source code file is part of KiCad, a free EDA CAD application.
3 *
4 * Copyright (C) 2004-2010 Jean-Pierre Charras, jp.charras at wanadoo.fr
5 * Copyright (C) 2010 SoftPLC Corporation, Dick Hollenbeck <dick@softplc.com>
6 * Copyright (C) 2018-2021 KiCad Developers, see AUTHORS.txt for contributors.
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * as published by the Free Software Foundation; either version 2
11 * of the License, or (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, you may find one here:
20 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
21 * or you may search the http://www.gnu.org website for the version 2 license,
22 * or you may write to the Free Software Foundation, Inc.,
23 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
24 */
25
26 #include <wx/checkbox.h>
27 #include <wx/filedlg.h>
28 #include <bitmaps.h>
29 #include <menus_helpers.h>
30 #include <gerbview.h>
31 #include "gerbview_draw_panel_gal.h"
32 #include <gerbview_frame.h>
33 #include <gerber_file_image_list.h>
34 #include <core/arraydim.h>
35 #include <view/view.h>
36 #include <gerbview_painter.h>
37 #include <gal/graphics_abstraction_layer.h>
38 #include <settings/settings_manager.h>
39
40 #include "layer_widget.h"
41 #include "gbr_layer_box_selector.h"
42 #include "gerbview_layer_widget.h"
43 #include "dcode_selection_box.h"
44
45
GERBER_LAYER_WIDGET(GERBVIEW_FRAME * aParent,wxWindow * aFocusOwner)46 GERBER_LAYER_WIDGET::GERBER_LAYER_WIDGET( GERBVIEW_FRAME* aParent, wxWindow* aFocusOwner ) :
47 LAYER_WIDGET( aParent, aFocusOwner ),
48 m_frame( aParent )
49 {
50 m_alwaysShowActiveLayer = false;
51
52 ReFillRender();
53
54 // Update default tabs labels for GerbView
55 SetLayersManagerTabsText( );
56
57 // handle the popup menu over the layer window.
58 m_LayerScrolledWindow->Connect( wxEVT_RIGHT_DOWN,
59 wxMouseEventHandler( GERBER_LAYER_WIDGET::onRightDownLayers ),
60 nullptr, this );
61
62 // since Popupmenu() calls this->ProcessEvent() we must call this->Connect()
63 // and not m_LayerScrolledWindow->Connect()
64 Connect( ID_LAYER_MANAGER_START, ID_LAYER_MANAGER_END, wxEVT_COMMAND_MENU_SELECTED,
65 wxCommandEventHandler( GERBER_LAYER_WIDGET::onPopupSelection ), nullptr, this );
66 }
67
68
GetImagesList()69 GERBER_FILE_IMAGE_LIST* GERBER_LAYER_WIDGET::GetImagesList()
70 {
71 return &GERBER_FILE_IMAGE_LIST::GetImagesList();
72 }
73
74
SetLayersManagerTabsText()75 void GERBER_LAYER_WIDGET::SetLayersManagerTabsText()
76 {
77 m_notebook->SetPageText( 0, _( "Layers" ) );
78 m_notebook->SetPageText( 1, _( "Items" ) );
79 }
80
ReFillRender()81 void GERBER_LAYER_WIDGET::ReFillRender()
82 {
83 ClearRenderRows();
84
85 // Fixed "Rendering" tab rows within the LAYER_WIDGET, only the initial color
86 // is changed before appending to the LAYER_WIDGET. This is an automatic variable
87 // not a static variable, change the color & state after copying from code to renderRows
88 // on the stack.
89 LAYER_WIDGET::ROW renderRows[6] = {
90
91 #define RR LAYER_WIDGET::ROW // Render Row abbreviation to reduce source width
92
93 RR( _( "DCodes" ), LAYER_DCODES, WHITE,
94 _( "Show DCodes identification" ) ),
95 RR( _( "Negative Objects" ), LAYER_NEGATIVE_OBJECTS, DARKGRAY,
96 _( "Show negative objects in this color" ) ),
97 RR(),
98 RR( _( "Grid" ), LAYER_GERBVIEW_GRID, WHITE,
99 _( "Show the (x,y) grid dots" ) ),
100 RR( _( "Drawing Sheet" ), LAYER_GERBVIEW_DRAWINGSHEET, DARKRED,
101 _( "Show drawing sheet border and title block") ),
102 RR( _( "Background" ), LAYER_GERBVIEW_BACKGROUND, BLACK,
103 _( "PCB Background" ), true, false )
104 };
105
106 for( unsigned row = 0; row < arrayDim( renderRows ); ++row )
107 {
108 if( renderRows[row].color != COLOR4D::UNSPECIFIED ) // does this row show a color?
109 renderRows[row].color = m_frame->GetVisibleElementColor( renderRows[row].id );
110
111 if( renderRows[row].id ) // if not the separator
112 renderRows[row].state = m_frame->IsElementVisible( renderRows[row].id );
113 }
114
115 AppendRenderRows( renderRows, arrayDim(renderRows) );
116 }
117
118
AddRightClickMenuItems(wxMenu * aMenu)119 void GERBER_LAYER_WIDGET::AddRightClickMenuItems( wxMenu* aMenu )
120 {
121 // Remember: menu text is capitalized (see our rules_for_capitalization_in_Kicad_UI.txt)
122 AddMenuItem( aMenu, ID_SHOW_ALL_LAYERS, _( "Show All Layers" ),
123 KiBitmap( BITMAPS::show_all_layers ) );
124
125 AddMenuItem( aMenu, ID_SHOW_NO_LAYERS_BUT_ACTIVE,
126 _( "Hide All Layers But Active" ),
127 KiBitmap( BITMAPS::select_w_layer ) );
128
129 AddMenuItem( aMenu, ID_ALWAYS_SHOW_NO_LAYERS_BUT_ACTIVE,
130 _( "Always Hide All Layers But Active" ),
131 KiBitmap( BITMAPS::select_w_layer ) );
132
133 AddMenuItem( aMenu, ID_SHOW_NO_LAYERS, _( "Hide All Layers" ),
134 KiBitmap( BITMAPS::show_no_layers ) );
135
136 aMenu->AppendSeparator();
137 AddMenuItem( aMenu, ID_SORT_GBR_LAYERS, _( "Sort Layers if X2 Mode" ),
138 KiBitmap( BITMAPS::reload ) );
139 }
140
141
onRightDownLayers(wxMouseEvent & event)142 void GERBER_LAYER_WIDGET::onRightDownLayers( wxMouseEvent& event )
143 {
144 wxMenu menu;
145
146 AddRightClickMenuItems( &menu );
147 PopupMenu( &menu );
148
149 passOnFocus();
150 }
151
152
onPopupSelection(wxCommandEvent & event)153 void GERBER_LAYER_WIDGET::onPopupSelection( wxCommandEvent& event )
154 {
155 int rowCount;
156 int menuId = event.GetId();
157 bool visible = (menuId == ID_SHOW_ALL_LAYERS) ? true : false;
158 LSET visibleLayers;
159 bool force_active_layer_visible;
160
161 switch( menuId )
162 {
163 case ID_SHOW_ALL_LAYERS:
164 case ID_SHOW_NO_LAYERS:
165 case ID_ALWAYS_SHOW_NO_LAYERS_BUT_ACTIVE:
166 case ID_SHOW_NO_LAYERS_BUT_ACTIVE:
167 // Set the display layers options. Sorting layers has no effect to these options
168 m_alwaysShowActiveLayer = ( menuId == ID_ALWAYS_SHOW_NO_LAYERS_BUT_ACTIVE );
169 force_active_layer_visible = ( menuId == ID_SHOW_NO_LAYERS_BUT_ACTIVE ||
170 menuId == ID_ALWAYS_SHOW_NO_LAYERS_BUT_ACTIVE );
171
172 // Update icons and check boxes
173 rowCount = GetLayerRowCount();
174
175 for( int row = 0; row < rowCount; ++row )
176 {
177 wxCheckBox* cb = (wxCheckBox*) getLayerComp( row, COLUMN_COLOR_LYR_CB );
178 int layer = getDecodedId( cb->GetId() );
179 bool loc_visible = visible;
180
181 if( force_active_layer_visible && (layer == m_frame->GetActiveLayer() ) )
182 loc_visible = true;
183
184 cb->SetValue( loc_visible );
185 visibleLayers[ row ] = loc_visible;
186 }
187
188 m_frame->SetVisibleLayers( visibleLayers );
189 m_frame->GetCanvas()->Refresh();
190 break;
191
192 case ID_SORT_GBR_LAYERS:
193 m_frame->SortLayersByX2Attributes();
194 break;
195 }
196 }
197
OnLayerSelected()198 bool GERBER_LAYER_WIDGET::OnLayerSelected()
199 {
200 if( !m_alwaysShowActiveLayer )
201 return false;
202
203 // postprocess after active layer selection ensure active layer visible
204 wxCommandEvent event;
205 event.SetId( ID_ALWAYS_SHOW_NO_LAYERS_BUT_ACTIVE );
206 onPopupSelection( event );
207 return true;
208 }
209
210
ReFill()211 void GERBER_LAYER_WIDGET::ReFill()
212 {
213 Freeze();
214
215 for( int layer = 0; layer < GERBER_DRAWLAYERS_COUNT; ++layer )
216 {
217 int aRow = findLayerRow( layer );
218 bool visible = true;
219 COLOR4D color = m_frame->GetLayerColor( GERBER_DRAW_LAYER( layer ) );
220 wxString msg = GetImagesList()->GetDisplayName( layer,
221 /* include layer number */ false,
222 /* Get the full name */ true );
223
224 if( m_frame->GetCanvas() )
225 visible = m_frame->GetCanvas()->GetView()->IsLayerVisible( GERBER_DRAW_LAYER( layer ) );
226 else
227 visible = m_frame->IsLayerVisible( layer );
228
229 if( aRow >= 0 )
230 {
231 updateLayerRow( findLayerRow( layer ), msg );
232 SetLayerVisible( layer, visible );
233 }
234 else
235 AppendLayerRow( LAYER_WIDGET::ROW( msg, layer, color, wxEmptyString, visible, true ) );
236 }
237
238 UpdateLayouts();
239 Thaw();
240 }
241
242
OnLayerRightClick(wxMenu & aMenu)243 void GERBER_LAYER_WIDGET::OnLayerRightClick( wxMenu& aMenu )
244 {
245 AddRightClickMenuItems( &aMenu );
246 }
247
248
OnLayerColorChange(int aLayer,const COLOR4D & aColor)249 void GERBER_LAYER_WIDGET::OnLayerColorChange( int aLayer, const COLOR4D& aColor )
250 {
251 // NOTE: Active layer in GerbView is stored as 0-indexed, but layer color is
252 // stored according to the GERBER_DRAW_LAYER() offset.
253 m_frame->SetLayerColor( GERBER_DRAW_LAYER( aLayer ), aColor );
254 m_frame->m_SelLayerBox->ResyncBitmapOnly();
255
256 KIGFX::VIEW* view = m_frame->GetCanvas()->GetView();
257 auto settings = m_frame->GetSettingsManager()->GetColorSettings();
258 view->GetPainter()->GetSettings()->LoadColors( settings );
259 view->UpdateLayerColor( GERBER_DRAW_LAYER( aLayer ) );
260
261 m_frame->GetCanvas()->Refresh();
262 }
263
264
OnLayerSelect(int aLayer)265 bool GERBER_LAYER_WIDGET::OnLayerSelect( int aLayer )
266 {
267 // the layer change from the GERBER_LAYER_WIDGET can be denied by returning
268 // false from this function.
269 int layer = m_frame->GetActiveLayer();
270
271 m_frame->SetActiveLayer( aLayer, false );
272 m_frame->syncLayerBox();
273
274 if( layer != m_frame->GetActiveLayer() )
275 {
276 if( ! OnLayerSelected() )
277 {
278 auto settings = static_cast<KIGFX::GERBVIEW_PAINTER*>
279 ( m_frame->GetCanvas()->GetView()->GetPainter() )->GetSettings();
280 int dcodeSelected = m_frame->m_DCodeSelector->GetSelectedDCodeId();
281 settings->m_dcodeHighlightValue = dcodeSelected;
282 m_frame->GetCanvas()->GetView()->UpdateAllItems( KIGFX::COLOR );
283 m_frame->GetCanvas()->Refresh();
284 }
285 }
286
287 return true;
288 }
289
290
OnLayerVisible(int aLayer,bool isVisible,bool isFinal)291 void GERBER_LAYER_WIDGET::OnLayerVisible( int aLayer, bool isVisible, bool isFinal )
292 {
293 LSET visibleLayers = m_frame->GetVisibleLayers();
294
295 visibleLayers[ aLayer ] = isVisible;
296
297 m_frame->SetVisibleLayers( visibleLayers );
298
299 if( isFinal )
300 m_frame->GetCanvas()->Refresh();
301 }
302
303
OnRenderColorChange(int aId,const COLOR4D & aColor)304 void GERBER_LAYER_WIDGET::OnRenderColorChange( int aId, const COLOR4D& aColor )
305 {
306 m_frame->SetVisibleElementColor( aId, aColor );
307
308 auto view = m_frame->GetCanvas()->GetView();
309 COLOR_SETTINGS* settings = m_frame->GetSettingsManager()->GetColorSettings();
310
311 view->GetPainter()->GetSettings()->LoadColors( settings );
312 view->UpdateLayerColor( aId );
313 view->MarkTargetDirty( KIGFX::TARGET_NONCACHED );
314 view->UpdateAllItems( KIGFX::COLOR );
315 m_frame->GetCanvas()->Refresh();
316 }
317
318
OnRenderEnable(int aId,bool isEnabled)319 void GERBER_LAYER_WIDGET::OnRenderEnable( int aId, bool isEnabled )
320 {
321 m_frame->SetElementVisibility( aId, isEnabled );
322
323 if( m_frame->GetCanvas() )
324 {
325 if( aId == LAYER_GERBVIEW_GRID )
326 {
327 m_frame->GetCanvas()->GetGAL()->SetGridVisibility( m_frame->IsGridVisible() );
328 m_frame->GetCanvas()->GetView()->MarkTargetDirty( KIGFX::TARGET_NONCACHED );
329 }
330 else
331 {
332 m_frame->GetCanvas()->GetView()->SetLayerVisible( aId, isEnabled );
333 }
334 }
335
336 m_frame->GetCanvas()->Refresh();
337 }
338
339
useAlternateBitmap(int aRow)340 bool GERBER_LAYER_WIDGET::useAlternateBitmap( int aRow )
341 {
342 return GetImagesList()->GetGbrImage( aRow ) != nullptr;
343 }
344