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