1 /*
2 * This program source code file is part of KiCad, a free EDA CAD application.
3 *
4 * Copyright (C) 2017 Jon Evans <jon@craftyjon.com>
5 * Copyright (C) 2017-2021 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
21
22 #include <eda_item.h>
23 #include <bitmaps.h>
24 #include <class_draw_panel_gal.h>
25 #include <dialogs/dialog_layers_select_to_pcb.h>
26 #include <gestfich.h>
27 #include <gerber_file_image.h>
28 #include <gerbview_id.h>
29 #include "gerbview_inspection_tool.h"
30 #include "gerbview_actions.h"
31 #include <painter.h>
32 #include <pgm_base.h>
33 #include <preview_items/ruler_item.h>
34 #include <preview_items/selection_area.h>
35 #include <tool/tool_event.h>
36 #include <tool/tool_manager.h>
37 #include <view/view.h>
38 #include <view/view_controls.h>
39 #include <view/view_group.h>
40 #include <wx/msgdlg.h>
41 #include <wx/textdlg.h>
42 #include <wx/choicdlg.h>
43
44
GERBVIEW_INSPECTION_TOOL()45 GERBVIEW_INSPECTION_TOOL::GERBVIEW_INSPECTION_TOOL() :
46 TOOL_INTERACTIVE( "gerbview.Inspection" ),
47 m_frame( nullptr )
48 {
49 }
50
51
~GERBVIEW_INSPECTION_TOOL()52 GERBVIEW_INSPECTION_TOOL::~GERBVIEW_INSPECTION_TOOL()
53 {
54 }
55
56
Init()57 bool GERBVIEW_INSPECTION_TOOL::Init()
58 {
59 return true;
60 }
61
62
Reset(RESET_REASON aReason)63 void GERBVIEW_INSPECTION_TOOL::Reset( RESET_REASON aReason )
64 {
65 m_frame = getEditFrame<GERBVIEW_FRAME>();
66 }
67
68
ShowDCodes(const TOOL_EVENT & aEvent)69 int GERBVIEW_INSPECTION_TOOL::ShowDCodes( const TOOL_EVENT& aEvent )
70 {
71 int ii, jj;
72 wxString Line;
73 wxArrayString list;
74 int curr_layer = m_frame->GetActiveLayer();
75
76 double scale = 1.0;
77 wxString units;
78
79 switch( m_frame->GetUserUnits() )
80 {
81 case EDA_UNITS::MILLIMETRES:
82 scale = IU_PER_MM;
83 units = "mm";
84 break;
85
86 case EDA_UNITS::INCHES:
87 scale = IU_PER_MILS * 1000;
88 units = "in";
89 break;
90
91 case EDA_UNITS::MILS:
92 scale = IU_PER_MILS;
93 units = "mil";
94 break;
95
96 default:
97 wxASSERT_MSG( false, "Invalid units" );
98 }
99
100 for( unsigned int layer = 0; layer < m_frame->ImagesMaxCount(); ++layer )
101 {
102 GERBER_FILE_IMAGE* gerber = m_frame->GetGbrImage( layer );
103
104 if( !gerber )
105 continue;
106
107 if( gerber->GetDcodesCount() == 0 )
108 continue;
109
110 if( curr_layer == static_cast<int>( layer ) )
111 Line.Printf( wxT( "*** Active layer (%2.2d) ***" ), layer + 1 );
112 else
113 Line.Printf( wxT( "*** layer %2.2d ***" ), layer + 1 );
114
115 list.Add( Line );
116
117 for( ii = 0, jj = 1; ii < TOOLS_MAX_COUNT; ii++ )
118 {
119 D_CODE* pt_D_code = gerber->GetDCODE( ii + FIRST_DCODE );
120
121 if( pt_D_code == nullptr )
122 continue;
123
124 if( !pt_D_code->m_InUse && !pt_D_code->m_Defined )
125 continue;
126
127 Line.Printf( wxT( "tool %2.2d: D%2.2d V %.4f %s H %.4f %s %s attribute '%s'" ),
128 jj,
129 pt_D_code->m_Num_Dcode,
130 pt_D_code->m_Size.y / scale, units,
131 pt_D_code->m_Size.x / scale, units,
132 D_CODE::ShowApertureType( pt_D_code->m_Shape ),
133 pt_D_code->m_AperFunction.IsEmpty()? wxT( "none" ) : pt_D_code->m_AperFunction
134 );
135
136 if( !pt_D_code->m_Defined )
137 Line += wxT( " (not defined)" );
138
139 if( pt_D_code->m_InUse )
140 Line += wxT( " (in use)" );
141
142 list.Add( Line );
143 jj++;
144 }
145 }
146
147 wxSingleChoiceDialog dlg( m_frame, wxEmptyString, _( "D Codes" ), list, (void**) nullptr,
148 wxCHOICEDLG_STYLE & ~wxCANCEL );
149
150 dlg.ShowModal();
151
152 return 0;
153 }
154
155
ShowSource(const TOOL_EVENT & aEvent)156 int GERBVIEW_INSPECTION_TOOL::ShowSource( const TOOL_EVENT& aEvent )
157 {
158 int layer = m_frame->GetActiveLayer();
159 GERBER_FILE_IMAGE* gerber_layer = m_frame->GetGbrImage( layer );
160
161 if( gerber_layer )
162 {
163 wxString editorname = Pgm().GetTextEditor();
164
165 if( !editorname.IsEmpty() )
166 {
167 wxFileName fn( gerber_layer->m_FileName );
168
169 // Call the editor only if the Gerber/drill source file is available.
170 // This is not always the case, because it can be a temporary file
171 // if it comes from a zip archive.
172 if( !fn.FileExists() )
173 {
174 wxString msg;
175 msg.Printf( _( "Source file '%s' not found." ), fn.GetFullPath() );
176 wxMessageBox( msg );
177 }
178 else
179 {
180 ExecuteFile( editorname, fn.GetFullPath() );
181 }
182 }
183 else
184 {
185 wxMessageBox( _( "No text editor selected in KiCad. Please choose one." ) );
186 }
187 }
188 else
189 {
190 wxString msg;
191 msg.Printf( _( "No file loaded on the active layer %d." ), layer + 1 );
192 wxMessageBox( msg );
193 }
194
195 return 0;
196 }
197
198
199 using KIGFX::PREVIEW::TWO_POINT_GEOMETRY_MANAGER;
200
201
MeasureTool(const TOOL_EVENT & aEvent)202 int GERBVIEW_INSPECTION_TOOL::MeasureTool( const TOOL_EVENT& aEvent )
203 {
204 KIGFX::VIEW_CONTROLS& controls = *getViewControls();
205 bool originSet = false;
206 TWO_POINT_GEOMETRY_MANAGER twoPtMgr;
207 EDA_UNITS units = m_frame->GetUserUnits();
208 KIGFX::PREVIEW::RULER_ITEM ruler( twoPtMgr, units, false, false );
209
210 std::string tool = aEvent.GetCommandStr().get();
211 m_frame->PushTool( tool );
212
213 auto setCursor =
214 [&]()
215 {
216 m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::MEASURE );
217 };
218
219 auto cleanup =
220 [&] ()
221 {
222 getView()->SetVisible( &ruler, false );
223 controls.SetAutoPan( false );
224 controls.CaptureCursor( false );
225 originSet = false;
226 };
227
228 Activate();
229 // Must be done after Activate() so that it gets set into the correct context
230 controls.ShowCursor( true );
231 // Set initial cursor
232 setCursor();
233
234 getView()->Add( &ruler );
235 getView()->SetVisible( &ruler, false );
236
237 while( TOOL_EVENT* evt = Wait() )
238 {
239 setCursor();
240 const VECTOR2I cursorPos = controls.GetCursorPosition();
241
242 if( evt->IsCancelInteractive() )
243 {
244 if( originSet )
245 {
246 cleanup();
247 }
248 else
249 {
250 m_frame->PopTool( tool );
251 break;
252 }
253 }
254 else if( evt->IsActivate() )
255 {
256 if( originSet )
257 cleanup();
258
259 if( evt->IsMoveTool() )
260 {
261 // leave ourselves on the stack so we come back after the move
262 break;
263 }
264 else
265 {
266 m_frame->PopTool( tool );
267 break;
268 }
269 }
270 else if( !originSet && ( evt->IsDrag( BUT_LEFT ) || evt->IsClick( BUT_LEFT ) ) )
271 {
272 // click or drag starts
273 twoPtMgr.SetOrigin( cursorPos );
274 twoPtMgr.SetEnd( cursorPos );
275
276 controls.CaptureCursor( true );
277 controls.SetAutoPan( true );
278
279 originSet = true;
280 }
281 else if( originSet && ( evt->IsClick( BUT_LEFT ) || evt->IsMouseUp( BUT_LEFT ) ) )
282 {
283 // second click or mouse up after drag ends
284 originSet = false;
285
286 controls.SetAutoPan( false );
287 controls.CaptureCursor( false );
288 }
289 else if( originSet && ( evt->IsMotion() || evt->IsDrag( BUT_LEFT ) ) )
290 {
291 // move or drag when origin set updates rules
292 twoPtMgr.SetAngleSnap( evt->Modifier( MD_SHIFT ) );
293 twoPtMgr.SetEnd( cursorPos );
294
295 getView()->SetVisible( &ruler, true );
296 getView()->Update( &ruler, KIGFX::GEOMETRY );
297 }
298 else if( evt->IsAction( &ACTIONS::updateUnits ) )
299 {
300 if( m_frame->GetUserUnits() != units )
301 {
302 units = m_frame->GetUserUnits();
303 ruler.SwitchUnits( units );
304 getView()->Update( &ruler, KIGFX::GEOMETRY );
305 }
306 evt->SetPassEvent();
307 }
308 else if( evt->IsClick( BUT_RIGHT ) )
309 {
310 m_menu.ShowContextMenu( m_frame->GetCurrentSelection() );
311 }
312 else
313 {
314 evt->SetPassEvent();
315 }
316 }
317
318 getView()->SetVisible( &ruler, false );
319 getView()->Remove( &ruler );
320
321 m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::ARROW );
322 return 0;
323 }
324
325
setTransitions()326 void GERBVIEW_INSPECTION_TOOL::setTransitions()
327 {
328 Go( &GERBVIEW_INSPECTION_TOOL::ShowSource, GERBVIEW_ACTIONS::showSource.MakeEvent() );
329 Go( &GERBVIEW_INSPECTION_TOOL::ShowDCodes, GERBVIEW_ACTIONS::showDCodes.MakeEvent() );
330 Go( &GERBVIEW_INSPECTION_TOOL::MeasureTool, ACTIONS::measureTool.MakeEvent() );
331 }
332