1 /*
2 * This program source code file is part of KiCad, a free EDA CAD application.
3 *
4 * Copyright (C) 2019 Ian McInerney <Ian.S.McInerney@ieee.org>
5 * Copyright (C) 2019 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 #include <confirm.h>
22 #include <cstdint>
23 #include <functional>
24 #include <kiface_base.h>
25 #include <kiway_express.h>
26 #include <lib_id.h>
27 #include <tool/actions.h>
28 #include <tool/tool_manager.h>
29
30 #include <cvpcb_mainframe.h>
31 #include <dialogs/dialog_config_equfiles.h>
32 #include <display_footprints_frame.h>
33 #include <listboxes.h>
34 #include <tools/cvpcb_actions.h>
35 #include <tools/cvpcb_control.h>
36 #include <wx/settings.h>
37
38 using namespace std::placeholders;
39
40
CVPCB_CONTROL()41 CVPCB_CONTROL::CVPCB_CONTROL() :
42 TOOL_INTERACTIVE( "cvpcb.Control" ),
43 m_frame( nullptr )
44 {
45 }
46
47
Reset(RESET_REASON aReason)48 void CVPCB_CONTROL::Reset( RESET_REASON aReason )
49 {
50 m_frame = getEditFrame<CVPCB_MAINFRAME>();
51 }
52
53
Main(const TOOL_EVENT & aEvent)54 int CVPCB_CONTROL::Main( const TOOL_EVENT& aEvent )
55 {
56 // Main loop: keep receiving events
57 while( TOOL_EVENT* evt = Wait() )
58 {
59 bool handled = false;
60
61 // The escape key maps to the cancel event, which is used to close the window
62 if( evt->IsCancel() )
63 {
64 m_frame->Close( false );
65 handled = true;
66 }
67 else if( evt->IsKeyPressed() )
68 {
69 switch( evt->KeyCode() )
70 {
71 // The right arrow moves focus to the focusable object to the right
72 case WXK_RIGHT:
73 m_toolMgr->RunAction( CVPCB_ACTIONS::changeFocusRight );
74 handled = true;
75 break;
76
77 // The left arrow moves focus to the focusable object to the left
78 case WXK_LEFT:
79 m_toolMgr->RunAction( CVPCB_ACTIONS::changeFocusLeft );
80 handled = true;
81 break;
82
83 default:
84 // Let every other key continue processing to the controls of the window
85 break;
86 }
87 }
88
89 if( !handled )
90 evt->SetPassEvent();
91 }
92
93 return 0;
94 }
95
96
ChangeFocus(const TOOL_EVENT & aEvent)97 int CVPCB_CONTROL::ChangeFocus( const TOOL_EVENT& aEvent )
98 {
99 int tmp = aEvent.Parameter<intptr_t>();
100 CVPCB_MAINFRAME::FOCUS_DIR dir =
101 static_cast<CVPCB_MAINFRAME::FOCUS_DIR>( tmp );
102
103 switch( dir )
104 {
105 case CVPCB_MAINFRAME::CHANGE_FOCUS_RIGHT:
106 switch( m_frame->GetFocusedControl() )
107 {
108 case CVPCB_MAINFRAME::CONTROL_LIBRARY:
109 m_frame->SetFocusedControl( CVPCB_MAINFRAME::CONTROL_COMPONENT );
110 break;
111
112 case CVPCB_MAINFRAME::CONTROL_COMPONENT:
113 m_frame->SetFocusedControl( CVPCB_MAINFRAME::CONTROL_FOOTPRINT );
114 break;
115
116 case CVPCB_MAINFRAME::CONTROL_FOOTPRINT:
117 m_frame->SetFocusedControl( CVPCB_MAINFRAME::CONTROL_LIBRARY );
118 break;
119
120 case CVPCB_MAINFRAME::CONTROL_NONE:
121 default:
122 break;
123 }
124
125 break;
126
127 case CVPCB_MAINFRAME::CHANGE_FOCUS_LEFT:
128 switch( m_frame->GetFocusedControl() )
129 {
130 case CVPCB_MAINFRAME::CONTROL_LIBRARY:
131 m_frame->SetFocusedControl( CVPCB_MAINFRAME::CONTROL_FOOTPRINT );
132 break;
133
134 case CVPCB_MAINFRAME::CONTROL_COMPONENT:
135 m_frame->SetFocusedControl( CVPCB_MAINFRAME::CONTROL_LIBRARY );
136 break;
137
138 case CVPCB_MAINFRAME::CONTROL_FOOTPRINT:
139 m_frame->SetFocusedControl( CVPCB_MAINFRAME::CONTROL_COMPONENT );
140 break;
141
142 case CVPCB_MAINFRAME::CONTROL_NONE:
143 default:
144 break;
145 }
146
147 break;
148
149 default:
150 break;
151 }
152
153 return 0;
154 }
155
156
ShowFootprintViewer(const TOOL_EVENT & aEvent)157 int CVPCB_CONTROL::ShowFootprintViewer( const TOOL_EVENT& aEvent )
158 {
159
160 DISPLAY_FOOTPRINTS_FRAME* fpframe = m_frame->GetFootprintViewerFrame();
161
162 if( !fpframe )
163 {
164 fpframe = (DISPLAY_FOOTPRINTS_FRAME*) m_frame->Kiway().Player(
165 FRAME_CVPCB_DISPLAY, true, m_frame );
166 fpframe->Show( true );
167 }
168 else
169 {
170 if( fpframe->IsIconized() )
171 fpframe->Iconize( false );
172
173 // The display footprint window might be buried under some other
174 // windows, so CreateScreenCmp() on an existing window would not
175 // show any difference, leaving the user confused.
176 // So we want to put it to front, second after our CVPCB_MAINFRAME.
177 // We do this by a little dance of bringing it to front then the main
178 // frame back.
179 wxWindow* focus = m_frame->FindFocus();
180
181 fpframe->Raise(); // Make sure that is visible.
182 m_frame->Raise(); // .. but still we want the focus.
183
184 if( focus )
185 focus->SetFocus();
186 }
187
188 fpframe->InitDisplay();
189
190 return 0;
191 }
192
193
ToggleFootprintFilter(const TOOL_EVENT & aEvent)194 int CVPCB_CONTROL::ToggleFootprintFilter( const TOOL_EVENT& aEvent )
195 {
196 m_frame->SetFootprintFilter(
197 static_cast<FOOTPRINTS_LISTBOX::FP_FILTER_T>( aEvent.Parameter<intptr_t>() ),
198 CVPCB_MAINFRAME::FILTER_TOGGLE );
199
200 return 0;
201 }
202
203
ShowEquFileTable(const TOOL_EVENT & aEvent)204 int CVPCB_CONTROL::ShowEquFileTable( const TOOL_EVENT& aEvent )
205 {
206 DIALOG_CONFIG_EQUFILES dlg( m_frame );
207 dlg.ShowModal();
208
209 return 0;
210 }
211
212
SaveAssociations(const TOOL_EVENT & aEvent)213 int CVPCB_CONTROL::SaveAssociations( const TOOL_EVENT& aEvent )
214 {
215 m_frame->SaveFootprintAssociation( true );
216 return 0;
217 }
218
219
ToNA(const TOOL_EVENT & aEvent)220 int CVPCB_CONTROL::ToNA( const TOOL_EVENT& aEvent )
221 {
222 int tmp = aEvent.Parameter<intptr_t>();
223 CVPCB_MAINFRAME::ITEM_DIR dir =
224 static_cast<CVPCB_MAINFRAME::ITEM_DIR>( tmp );
225
226 std::vector<unsigned int> naComp = m_frame->GetComponentIndices( CVPCB_MAINFRAME::NA_COMPONENTS );
227 std::vector<unsigned int> tempSel = m_frame->GetComponentIndices( CVPCB_MAINFRAME::SEL_COMPONENTS );
228
229 // No unassociated components
230 if( naComp.empty() )
231 return 0;
232
233 // Extract the current selection
234 unsigned int curSel = -1;
235 unsigned int newSel = -1;
236 switch( dir )
237 {
238 case CVPCB_MAINFRAME::ITEM_NEXT:
239 if( !tempSel.empty() )
240 newSel = tempSel.front();
241
242 // Find the next index in the component list
243 for( unsigned int i : naComp )
244 {
245 if( i > newSel )
246 {
247 newSel = i;
248 break;
249 }
250 }
251
252 break;
253
254 case CVPCB_MAINFRAME::ITEM_PREV:
255 if( !tempSel.empty() )
256 {
257 newSel = tempSel.front();
258 curSel = newSel - 1; // Break one before the current selection
259 }
260
261 break;
262
263 default:
264 wxASSERT_MSG( false, "Invalid direction" );
265 }
266
267 // Find the next index in the component list
268 for( unsigned int i : naComp )
269 {
270 if( i >= curSel )
271 {
272 newSel = i;
273 break;
274 }
275 }
276
277 // Set the component selection
278 m_frame->SetSelectedComponent( newSel );
279
280 return 0;
281 }
282
283
UpdateMenu(const TOOL_EVENT & aEvent)284 int CVPCB_CONTROL::UpdateMenu( const TOOL_EVENT& aEvent )
285 {
286 ACTION_MENU* actionMenu = aEvent.Parameter<ACTION_MENU*>();
287 CONDITIONAL_MENU* conditionalMenu = dynamic_cast<CONDITIONAL_MENU*>( actionMenu );
288 SELECTION dummySel;
289
290 if( conditionalMenu )
291 conditionalMenu->Evaluate( dummySel );
292
293 if( actionMenu )
294 actionMenu->UpdateAll();
295
296 return 0;
297 }
298
299
setTransitions()300 void CVPCB_CONTROL::setTransitions()
301 {
302 // Control actions
303 Go( &CVPCB_CONTROL::UpdateMenu, ACTIONS::updateMenu.MakeEvent() );
304 Go( &CVPCB_CONTROL::Main, CVPCB_ACTIONS::controlActivate.MakeEvent() );
305 Go( &CVPCB_CONTROL::ChangeFocus, CVPCB_ACTIONS::changeFocusRight.MakeEvent() );
306 Go( &CVPCB_CONTROL::ChangeFocus, CVPCB_ACTIONS::changeFocusLeft.MakeEvent() );
307
308 // Run the footprint viewer
309 Go( &CVPCB_CONTROL::ShowFootprintViewer, CVPCB_ACTIONS::showFootprintViewer.MakeEvent() );
310
311 // Management actions
312 Go( &CVPCB_CONTROL::ShowEquFileTable, CVPCB_ACTIONS::showEquFileTable.MakeEvent() );
313 Go( &CVPCB_CONTROL::SaveAssociations, CVPCB_ACTIONS::saveAssociations.MakeEvent() );
314
315 // Navigation actions
316 Go( &CVPCB_CONTROL::ToNA, CVPCB_ACTIONS::gotoNextNA.MakeEvent() );
317 Go( &CVPCB_CONTROL::ToNA, CVPCB_ACTIONS::gotoPreviousNA.MakeEvent() );
318
319 // Filter the footprints
320 Go( &CVPCB_CONTROL::ToggleFootprintFilter, CVPCB_ACTIONS::FilterFPbyFPFilters.MakeEvent() );
321 Go( &CVPCB_CONTROL::ToggleFootprintFilter, CVPCB_ACTIONS::FilterFPbyLibrary.MakeEvent() );
322 Go( &CVPCB_CONTROL::ToggleFootprintFilter, CVPCB_ACTIONS::filterFPbyPin.MakeEvent() );
323 }
324