KiCad PCB EDA Suite
Loading...
Searching...
No Matches
pcb_viewer_tools.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 The KiCad Developers, see AUTHORS.txt for contributors.
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <https://www.gnu.org/licenses/>.
18 */
19
21
22#include <wx/clipbrd.h>
23
25#include <footprint.h>
28#include <kiplatform/ui.h>
29#include <pad.h>
30#include <pcb_base_frame.h>
33#include <pgm_base.h>
35#include <tool/actions.h>
36#include <tool/tool_manager.h>
38#include <tools/pcb_actions.h>
39
40
42{
43 // Populate the context menu displayed during the tool (primarily the measure tool)
44 auto activeToolCondition =
45 [this] ( const SELECTION& aSel )
46 {
47 return !frame()->ToolStackIsEmpty();
48 };
49
50 CONDITIONAL_MENU& ctxMenu = m_menu->GetMenu();
51
52 // "Cancel" goes at the top of the context menu when a tool is active
53 if( !m_isDefaultTool )
54 {
55 ctxMenu.AddItem( ACTIONS::cancelInteractive, activeToolCondition, 1 );
56 ctxMenu.AddSeparator( 1 );
57 }
58
59 ctxMenu.AddSeparator( activeToolCondition, 2 );
60
61 ctxMenu.AddItem( ACTIONS::copy, activeToolCondition, 3 );
62 ctxMenu.AddSeparator( activeToolCondition, 3 );
63
64 frame()->AddStandardSubMenus( *m_menu.get() );
65
66 return true;
67}
68
69
71{
72}
73
74
76{
77 bool do_reload_board = true; // reload board flag
78
79 // At EDA_3D_VIEWER_FRAME creation, the current board is loaded, so disable loading
80 // the current board if the 3D frame is not yet created
81 if( frame()->Get3DViewerFrame() == nullptr )
82 do_reload_board = false;
83
85
86 if( frame()->IsType( FRAME_FOOTPRINT_VIEWER )
87 || frame()->IsType( FRAME_FOOTPRINT_WIZARD ) )
88 {
89 // A stronger version of Raise() which promotes the window to its parent's level.
90 KIPLATFORM::UI::ReparentModal( draw3DFrame );
91 }
92
93 // And load or update the current board (if needed)
94 if( do_reload_board )
95 frame()->Update3DView( true, true );
96
97 return 0;
98}
99
100
101template<class T> void Flip( T& aValue )
102{
103 aValue = !aValue;
104}
105
106
108{
109 if( frame()->IsType( FRAME_PCB_EDITOR ) )
110 {
111 PCBNEW_SETTINGS* settings = GetAppSettings<PCBNEW_SETTINGS>( "pcbnew" );
112
113 switch( settings->m_AngleSnapMode )
114 {
117 default: settings->m_AngleSnapMode = LEADER_MODE::DIRECT; break;
118 }
119 }
120 else if( frame()->IsType( FRAME_FOOTPRINT_EDITOR ) )
121 {
123
124 switch( settings->m_AngleSnapMode )
125 {
128 default: settings->m_AngleSnapMode = LEADER_MODE::DIRECT; break;
129 }
130 }
131 else
132 {
134
135 switch( mode )
136 {
137 case LEADER_MODE::DIRECT: mode = LEADER_MODE::DEG45; break;
138 case LEADER_MODE::DEG45: mode = LEADER_MODE::DEG90; break;
139 default: mode = LEADER_MODE::DIRECT; break;
140 }
141 }
142
144
145 // Notify other tools/UI (toolbars) that the angle snap mode has changed
147
148 return 0;
149}
150
151
153{
156
157 for( FOOTPRINT* fp : board()->Footprints() )
158 {
159 for( PAD* pad : fp->Pads() )
161 }
162
163 canvas()->Refresh();
164
165 return 0;
166}
167
168
170{
173
174 for( FOOTPRINT* fp : board()->Footprints() )
175 {
176 for( PAD* pad : fp->Pads() )
178 }
179
180 canvas()->Refresh();
181
182 return 0;
183}
184
185
187{
190
191 for( FOOTPRINT* fp : board()->Footprints() )
192 {
193 for( BOARD_ITEM* item : fp->GraphicalItems() )
194 {
195 KICAD_T t = item->Type();
196
197 if( t == PCB_SHAPE_T || BaseType( t ) == PCB_DIMENSION_T )
198 view()->Update( item, KIGFX::REPAINT );
199 }
200 }
201
202 for( BOARD_ITEM* item : board()->Drawings() )
203 {
204 KICAD_T t = item->Type();
205
206 if( t == PCB_SHAPE_T || BaseType( t ) == PCB_DIMENSION_T || t == PCB_TARGET_T )
207 view()->Update( item, KIGFX::REPAINT );
208 }
209
210 canvas()->Refresh();
211
212 return 0;
213}
214
215
217{
220
221 for( FOOTPRINT* fp : board()->Footprints() )
222 {
223 for( PCB_FIELD* field : fp->GetFields() )
224 {
225 wxCHECK2( field, continue );
226
227 view()->Update( field, KIGFX::REPAINT );
228 }
229
230 for( BOARD_ITEM* item : fp->GraphicalItems() )
231 {
232 if( item->Type() == PCB_TEXT_T )
233 view()->Update( item, KIGFX::REPAINT );
234 }
235 }
236
237 for( BOARD_ITEM* item : board()->Drawings() )
238 {
239 KICAD_T t = item->Type();
240
241 if( t == PCB_TEXT_T || t == PCB_TEXTBOX_T || BaseType( t ) == PCB_DIMENSION_T )
242 view()->Update( item, KIGFX::REPAINT );
243 }
244
245 canvas()->Refresh();
246
247 return 0;
248}
249
250
252
253
255{
256 if( IsFootprintFrame() && !frame()->GetModel() )
257 return 0;
258
259 if( frame()->IsCurrentTool( ACTIONS::measureTool ) )
260 return 0;
261
262 auto& view = *getView();
263 auto& controls = *getViewControls();
264
265 frame()->PushTool( aEvent );
266
267 bool invertXAxis = displayOptions().m_DisplayInvertXAxis;
268 bool invertYAxis = displayOptions().m_DisplayInvertYAxis;
269
270 if( IsFootprintFrame() )
271 {
274 }
275
277 PCB_GRID_HELPER grid( m_toolMgr, frame()->GetMagneticItemsSettings() );
278 bool originSet = false;
279 EDA_UNITS units = frame()->GetUserUnits();
280 KIGFX::PREVIEW::RULER_ITEM ruler( twoPtMgr, pcbIUScale, units, invertXAxis, invertYAxis );
281
282 view.Add( &ruler );
283 view.SetVisible( &ruler, false );
284
285 auto setCursor =
286 [&]()
287 {
289 };
290
291 auto cleanup =
292 [&] ()
293 {
294 view.SetVisible( &ruler, false );
295 controls.SetAutoPan( false );
296 controls.CaptureCursor( false );
297 controls.ForceCursorPosition( false );
298 originSet = false;
299 };
300
301 Activate();
302 // Must be done after Activate() so that it gets set into the correct context
303 controls.ShowCursor( true );
304 controls.SetAutoPan( false );
305 controls.CaptureCursor( false );
306 controls.ForceCursorPosition( false );
307
308 // Set initial cursor
309 setCursor();
310
311 while( TOOL_EVENT* evt = Wait() )
312 {
313 setCursor();
314 grid.SetSnap( !evt->Modifier( MD_SHIFT ) );
315 grid.SetUseGrid( view.GetGAL()->GetGridSnapping() && !evt->DisableGridSnapping() );
316 VECTOR2I cursorPos = evt->HasPosition() ? evt->Position() : controls.GetMousePosition();
317
318 if( !evt->IsActivate() && !evt->IsCancelInteractive() )
319 {
320 // If we are switching, the canvas may not be valid any more
321 cursorPos = grid.BestSnapAnchor( cursorPos, nullptr );
322 controls.ForceCursorPosition( true, cursorPos );
323 }
324 else
325 {
326 grid.FullReset();
327 }
328
329 if( evt->IsCancelInteractive() )
330 {
331 if( originSet )
332 {
333 cleanup();
334 }
335 else if( m_isDefaultTool )
336 {
337 view.SetVisible( &ruler, false );
338 }
339 else
340 {
341 frame()->PopTool( aEvent );
342 break;
343 }
344 }
345 else if( evt->IsActivate() )
346 {
347 if( originSet )
348 cleanup();
349
350 if( evt->IsMoveTool() )
351 {
352 // leave ourselves on the stack so we come back after the move
353 break;
354 }
355 else
356 {
357 frame()->PopTool( aEvent );
358 break;
359 }
360 }
361 // click or drag starts
362 else if( !originSet && ( evt->IsDrag( BUT_LEFT ) || evt->IsClick( BUT_LEFT ) ) )
363 {
364 twoPtMgr.SetOrigin( cursorPos );
365 twoPtMgr.SetEnd( cursorPos );
366
367 controls.CaptureCursor( true );
368 controls.SetAutoPan( true );
369
370 originSet = true;
371 }
372 // second click or mouse up after drag ends
373 else if( originSet && ( evt->IsClick( BUT_LEFT ) || evt->IsMouseUp( BUT_LEFT ) ) )
374 {
375 originSet = false;
376
377 controls.SetAutoPan( false );
378 controls.CaptureCursor( false );
379 }
380 // move or drag when origin set updates rules
381 else if( originSet && ( evt->IsMotion() || evt->IsDrag( BUT_LEFT ) ) )
382 {
383 // The measurement tool always measures in a direct line; holding Shift
384 // constrains to 45° increments for convenience.
385 twoPtMgr.SetAngleSnap( evt->Modifier( MD_SHIFT ) ? LEADER_MODE::DEG45
387 twoPtMgr.SetEnd( cursorPos );
388
389 view.SetVisible( &ruler, true );
390 view.Update( &ruler, KIGFX::GEOMETRY );
391 }
392 else if( evt->IsAction( &ACTIONS::updateUnits ) )
393 {
394 if( frame()->GetUserUnits() != units )
395 {
396 units = frame()->GetUserUnits();
397 ruler.SwitchUnits( units );
398 view.Update( &ruler, KIGFX::GEOMETRY );
399 canvas()->Refresh();
400 }
401
402 evt->SetPassEvent();
403 }
404 else if( evt->IsAction( &ACTIONS::updatePreferences ) )
405 {
406 invertXAxis = displayOptions().m_DisplayInvertXAxis;
407 invertYAxis = displayOptions().m_DisplayInvertYAxis;
408
409 if( IsFootprintFrame() )
410 {
413 }
414
415 ruler.UpdateDir( invertXAxis, invertYAxis );
416
417 view.Update( &ruler, KIGFX::GEOMETRY );
418 canvas()->Refresh();
419 evt->SetPassEvent();
420 }
421 else if( evt->IsAction( &ACTIONS::copy ) )
422 {
423 if( originSet )
424 {
425 wxArrayString cursorStrings = ruler.GetDimensionStrings();
426 wxString text = wxJoin( cursorStrings, '\n' );
427
428 if( wxTheClipboard->Open() )
429 {
430 wxTheClipboard->SetData( new wxTextDataObject( text ) );
431 wxTheClipboard->Close();
432 }
433 }
434 }
435 else if( evt->IsClick( BUT_RIGHT ) )
436 {
437 m_menu->ShowContextMenu();
438 }
439 else
440 {
441 evt->SetPassEvent();
442 }
443 }
444
445 view.SetVisible( &ruler, false );
446 view.Remove( &ruler );
447
449 controls.SetAutoPan( false );
450 controls.CaptureCursor( false );
451 controls.ForceCursorPosition( false );
452 return 0;
453}
454
455
457{
459
460 // Toggle the setting
461 if( cfg )
463
464 return 0;
465}
466
467
constexpr EDA_IU_SCALE pcbIUScale
Definition base_units.h:121
static TOOL_ACTION cancelInteractive
Definition actions.h:68
static TOOL_ACTION show3DViewer
Definition actions.h:254
static TOOL_ACTION updatePreferences
Definition actions.h:272
static TOOL_ACTION copy
Definition actions.h:74
static TOOL_ACTION updateUnits
Definition actions.h:203
static TOOL_ACTION measureTool
Definition actions.h:248
A base class for any item which can be embedded within the BOARD container class, and therefore insta...
Definition board_item.h:81
void AddItem(const TOOL_ACTION &aAction, const SELECTION_CONDITION &aCondition, int aOrder=ANY_ORDER)
Add a menu entry to run a TOOL_ACTION on selected items.
void AddSeparator(int aOrder=ANY_ORDER)
Add a separator to the menu.
Create and handle a window for the 3d viewer connected to a Kiway and a pcbboard.
virtual APP_SETTINGS_BASE * config() const
Return the settings object used in SaveSettings(), and is overloaded in KICAD_MANAGER_FRAME.
void AddStandardSubMenus(TOOL_MENU &aMenu)
Construct a "basic" menu for a tool, containing only items that apply to all tools (e....
void SetCurrentCursor(KICURSOR aCursor)
Set the current cursor shape for this panel.
virtual void Refresh(bool aEraseBackground=true, const wxRect *aRect=nullptr) override
virtual void Update(const VIEW_ITEM *aItem, int aUpdateFlags) const override
For dynamic VIEWs, inform the associated VIEW that the graphical representation of this item has chan...
Definition pcb_view.cpp:87
A drawn ruler item for showing the distance between two points.
Definition ruler_item.h:42
wxArrayString GetDimensionStrings() const
Get the strings for the dimensions of the ruler.
void SwitchUnits(EDA_UNITS aUnits)
Switch the ruler units.
Definition ruler_item.h:88
void UpdateDir(bool aFlipX, bool aFlipY)
Definition ruler_item.h:90
Represent a very simple geometry manager for items that have a start and end point.
void SetOrigin(const VECTOR2I &aOrigin)
< Set the origin of the ruler (the fixed end)
void SetEnd(const VECTOR2I &aEnd)
Set the current end of the rectangle (the end that moves with the cursor.
Definition pad.h:61
LEADER_MODE m_AngleSnapMode
static TOOL_ACTION padDisplayMode
static TOOL_ACTION angleSnapModeChanged
Notification event when angle mode changes.
static TOOL_ACTION lineModeNext
Cycle through angle modes.
static TOOL_ACTION graphicsOutlines
Display footprint graphics as outlines.
static TOOL_ACTION fpAutoZoom
static TOOL_ACTION textOutlines
Display texts as lines.
static TOOL_ACTION showPadNumbers
virtual PCB_VIEWERS_SETTINGS_BASE * GetViewerSettingsBase() const
PCB_DRAW_PANEL_GAL * GetCanvas() const override
Return a pointer to GAL-based canvas of given EDA draw frame.
FOOTPRINT_EDITOR_SETTINGS * GetFootprintEditorSettings() const
EDA_3D_VIEWER_FRAME * CreateAndShow3D_Frame()
Show the 3D view frame.
virtual void Update3DView(bool aMarkDirty, bool aRefresh, const wxString *aTitle=nullptr)
Update the 3D view, if the viewer is opened by this frame.
virtual void UpdateStatusBar() override
Update the status bar information.
bool m_FootprintViewerAutoZoomOnSelect
true to use automatic zoom on fp selection
VIEWERS_DISPLAY_OPTIONS m_ViewersDisplay
bool Init() override
Init() is called once upon a registration of the tool.
bool m_isDefaultTool
Indicates no selection tool is present in the current toolset.
int FootprintAutoZoom(const TOOL_EVENT &aEvent)
Automatically zoom to fit on footprints.
PCBNEW_SETTINGS::DISPLAY_OPTIONS & displayOptions() const
void setTransitions() override
This method is meant to be overridden in order to specify handlers for events.
void Reset(RESET_REASON aReason) override
Bring the tool to a known, initial state.
PCB_BASE_FRAME * frame() const
int PadDisplayMode(const TOOL_EVENT &aEvent)
BOARD * board() const
KIGFX::PCB_VIEW * view() const
int MeasureTool(const TOOL_EVENT &aEvent)
int TextOutlines(const TOOL_EVENT &aEvent)
PCB_DRAW_PANEL_GAL * canvas() const
bool IsFootprintFrame() const
int Show3DViewer(const TOOL_EVENT &aEvent)
Show the 3D viewer.
int NextLineMode(const TOOL_EVENT &aEvent)
int GraphicOutlines(const TOOL_EVENT &aEvent)
int ShowPadNumbers(const TOOL_EVENT &aEvent)
virtual void PopTool(const TOOL_EVENT &aEvent)
Pops a tool from the stack.
virtual void PushTool(const TOOL_EVENT &aEvent)
NB: the definition of "tool" is different at the user level.
bool ToolStackIsEmpty()
KIGFX::VIEW_CONTROLS * getViewControls() const
Return the instance of VIEW_CONTROLS object used in the application.
Definition tool_base.cpp:40
TOOL_MANAGER * m_toolMgr
Definition tool_base.h:220
KIGFX::VIEW * getView() const
Returns the instance of #VIEW object used in the application.
Definition tool_base.cpp:34
RESET_REASON
Determine the reason of reset for a tool.
Definition tool_base.h:74
Generic, UI-independent tool event.
Definition tool_event.h:167
void Go(int(T::*aStateFunc)(const TOOL_EVENT &), const TOOL_EVENT_LIST &aConditions=TOOL_EVENT(TC_ANY, TA_ANY))
Define which state (aStateFunc) to go when a certain event arrives (aConditions).
std::unique_ptr< TOOL_MENU > m_menu
The functions below are not yet implemented - their interface may change.
TOOL_EVENT * Wait(const TOOL_EVENT_LIST &aEventList=TOOL_EVENT(TC_ANY, TA_ANY))
Suspend execution of the tool until an event specified in aEventList arrives.
void Activate()
Run the tool.
EDA_UNITS GetUserUnits() const
@ MEASURE
Definition cursors.h:64
@ ARROW
Definition cursors.h:42
Declaration of the eda_3d_viewer class.
EDA_UNITS
Definition eda_units.h:44
@ FRAME_PCB_EDITOR
Definition frame_type.h:38
@ FRAME_FOOTPRINT_VIEWER
Definition frame_type.h:41
@ FRAME_FOOTPRINT_WIZARD
Definition frame_type.h:42
@ FRAME_FOOTPRINT_EDITOR
Definition frame_type.h:39
LEADER_MODE
The kind of the leader line.
@ DEG45
45 Degree only
@ DIRECT
Unconstrained point-to-point.
@ DEG90
90 Degree only
@ REPAINT
Item needs to be redrawn.
Definition view_item.h:54
@ GEOMETRY
Position or shape has changed.
Definition view_item.h:51
void ReparentModal(wxNonOwnedWindow *aWindow)
Move a window's parent to be the top-level window and force the window to be on top.
Definition wxgtk/ui.cpp:181
void Flip(T &aValue)
void Flip(T &aValue)
see class PGM_BASE
T * GetAppSettings(const char *aFilename)
@ MD_SHIFT
Definition tool_event.h:139
@ BUT_LEFT
Definition tool_event.h:128
@ BUT_RIGHT
Definition tool_event.h:129
constexpr KICAD_T BaseType(const KICAD_T aType)
Return the underlying type of the given type.
Definition typeinfo.h:256
KICAD_T
The set of class identification values stored in EDA_ITEM::m_structType.
Definition typeinfo.h:71
@ PCB_SHAPE_T
class PCB_SHAPE, a segment not on copper layers
Definition typeinfo.h:81
@ PCB_TEXTBOX_T
class PCB_TEXTBOX, wrapped text on a layer
Definition typeinfo.h:86
@ PCB_TEXT_T
class PCB_TEXT, text on a layer
Definition typeinfo.h:85
@ PCB_TARGET_T
class PCB_TARGET, a target (graphic item)
Definition typeinfo.h:100
@ PCB_DIMENSION_T
class PCB_DIMENSION_BASE: abstract dimension meta-type
Definition typeinfo.h:93
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:683