KiCad PCB EDA Suite
edit_tool_move_fct.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 (C) 2013-2017 CERN
5 * Copyright (C) 2017-2022 KiCad Developers, see AUTHORS.txt for contributors.
6 * @author Maciej Suminski <[email protected]>
7 * @author Tomasz Wlostowski <[email protected]>
8 *
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License
11 * as published by the Free Software Foundation; either version 2
12 * of the License, or (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, you may find one here:
21 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
22 * or you may search the http://www.gnu.org website for the version 2 license,
23 * or you may write to the Free Software Foundation, Inc.,
24 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
25 */
26
27#include <advanced_config.h>
28#include <limits>
29#include <board.h>
31#include <footprint.h>
32#include <fp_shape.h>
33#include <collectors.h>
34#include <pcb_edit_frame.h>
36#include <kiway.h>
37#include <pcbnew_settings.h>
38#include <spread_footprints.h>
39#include <tools/pcb_actions.h>
41#include <tools/edit_tool.h>
43#include <tools/drc_tool.h>
44#include <tools/drawing_tool.h>
46#include <view/view_controls.h>
49#include <cassert>
50#include <functional>
51#include <wx/hyperlink.h>
52#include <router/router_tool.h>
55#include <board_commit.h>
56#include <pcb_group.h>
57#include <pcb_target.h>
58#include <zone_filler.h>
59#include <drc/drc_engine.h>
60#include <drc/drc_item.h>
61#include <drc/drc_rule.h>
62#include <pad.h>
65
66
67int EDIT_TOOL::Swap( const TOOL_EVENT& aEvent )
68{
69 if( isRouterActive() )
70 {
71 wxBell();
72 return 0;
73 }
74
76 []( const VECTOR2I& aPt, GENERAL_COLLECTOR& aCollector, PCB_SELECTION_TOOL* sTool )
77 {
78 sTool->FilterCollectorForMarkers( aCollector );
79 sTool->FilterCollectorForHierarchy( aCollector, true );
80 sTool->FilterCollectorForFreePads( aCollector );
81
82 // Iterate from the back so we don't have to worry about removals.
83 for( int i = aCollector.GetCount() - 1; i >= 0; --i )
84 {
85 BOARD_ITEM* item = aCollector[i];
86
87 switch( item->Type() )
88 {
89 case PCB_TRACE_T: aCollector.Remove( item ); break;
90
91 default: break;
92 }
93 }
94 },
95 true /* prompt user regarding locked items */ );
96
97 if( selection.Size() < 2 )
98 return 0;
99
100 std::vector<EDA_ITEM*> sorted = selection.GetItemsSortedBySelectionOrder();
101
102 // When editing footprints, all items have the same parent
103 if( IsFootprintEditor() )
104 {
105 m_commit->Modify( selection.Front() );
106 }
107 else
108 {
109 // Save items, so changes can be undone
110 for( EDA_ITEM* item : selection )
111 {
112 // Don't double move footprint pads, fields, etc.
113 //
114 // For PCB_GROUP_T, the parent is the board.
115 if( item->GetParent() && item->GetParent()->IsSelected() )
116 continue;
117
118 m_commit->Modify( item );
119
120 // If moving a group, record position of all the descendants for undo
121 if( item->Type() == PCB_GROUP_T )
122 {
123 PCB_GROUP* group = static_cast<PCB_GROUP*>( item );
124 group->RunOnDescendants( [&]( BOARD_ITEM* bItem )
125 {
126 m_commit->Modify( bItem );
127 });
128 }
129 }
130 }
131
132 for( size_t i = 0; i < sorted.size() - 1; i++ )
133 {
134 BOARD_ITEM* a = static_cast<BOARD_ITEM*>( sorted[i] );
135 BOARD_ITEM* b = static_cast<BOARD_ITEM*>( sorted[( i + 1 ) % sorted.size()] );
136
137 // Swap X,Y position
138 VECTOR2I aPos = a->GetPosition(), bPos = b->GetPosition();
139 std::swap( aPos, bPos );
140 a->SetPosition( aPos );
141 b->SetPosition( bPos );
142
143 // Pads need special handling to keep their offset from their parent
144 if( a->Type() == PCB_PAD_T )
145 static_cast<PAD*>( a )->SetLocalCoord();
146
147 if( b->Type() == PCB_PAD_T )
148 static_cast<PAD*>( b )->SetLocalCoord();
149
150 // Handle footprints specially. They can be flipped to the back of the board which
151 // requires a special transformation.
152 if( a->Type() == PCB_FOOTPRINT_T && b->Type() == PCB_FOOTPRINT_T )
153 {
154 FOOTPRINT* aFP = static_cast<FOOTPRINT*>( a );
155 FOOTPRINT* bFP = static_cast<FOOTPRINT*>( b );
156
157 // Flip both if needed
158 if( aFP->IsFlipped() != bFP->IsFlipped() )
159 {
160 aFP->Flip( aPos, false );
161 bFP->Flip( bPos, false );
162 }
163
164 // Set orientation
165 EDA_ANGLE aAngle = aFP->GetOrientation(), bAngle = bFP->GetOrientation();
166 std::swap( aAngle, bAngle );
167 aFP->SetOrientation( aAngle );
168 bFP->SetOrientation( bAngle );
169 }
170 // We can also do a layer swap safely for two objects of the same type,
171 // except groups which don't support layer swaps.
172 else if( a->Type() == b->Type() && a->Type() != PCB_GROUP_T )
173 {
174 // Swap layers
175 PCB_LAYER_ID aLayer = a->GetLayer(), bLayer = b->GetLayer();
176 std::swap( aLayer, bLayer );
177 a->SetLayer( aLayer );
178 b->SetLayer( bLayer );
179 }
180 }
181
182 if( !m_dragging )
183 m_commit->Push( _( "Swap" ) );
184
185 m_toolMgr->ProcessEvent( EVENTS::SelectedItemsModified );
186
187 return 0;
188}
189
190
192{
194 []( const VECTOR2I& aPt, GENERAL_COLLECTOR& aCollector, PCB_SELECTION_TOOL* sTool )
195 {
196 sTool->FilterCollectorForMarkers( aCollector );
197 sTool->FilterCollectorForHierarchy( aCollector, true );
198 sTool->FilterCollectorForFreePads( aCollector );
199
200 // Iterate from the back so we don't have to worry about removals.
201 for( int i = aCollector.GetCount() - 1; i >= 0; --i )
202 {
203 BOARD_ITEM* item = aCollector[i];
204
205 if( !dynamic_cast<FOOTPRINT*>( item ) )
206 aCollector.Remove( item );
207 }
208 },
209 true /* prompt user regarding locked items */ );
210
211 std::vector<FOOTPRINT*> footprintsToPack;
212
213 for( EDA_ITEM* item : selection )
214 footprintsToPack.push_back( static_cast<FOOTPRINT*>( item ) );
215
216 if( footprintsToPack.empty() )
217 return 0;
218
219 BOX2I footprintsBbox;
220
221 for( FOOTPRINT* item : footprintsToPack )
222 {
223 m_commit->Modify( item );
224 footprintsBbox.Merge( item->GetBoundingBox( false, false ) );
225 }
226
227 SpreadFootprints( &footprintsToPack, footprintsBbox.Normalize().GetOrigin(), false );
228
229 return doMoveSelection( aEvent, _( "Pack footprints" ) );
230}
231
232
233int EDIT_TOOL::Move( const TOOL_EVENT& aEvent )
234{
235 if( isRouterActive() )
236 {
237 wxBell();
238 return 0;
239 }
240
241 return doMoveSelection( aEvent, _( "Move" ) );
242}
243
244
245VECTOR2I EDIT_TOOL::getSafeMovement( const VECTOR2I& aMovement, const BOX2I& aSourceBBox,
246 const VECTOR2D& aBBoxOffset )
247{
248 typedef std::numeric_limits<int> coord_limits;
249
250 int max = coord_limits::max();
251 int min = -max;
252
253 double left = aBBoxOffset.x + aSourceBBox.GetPosition().x;
254 double top = aBBoxOffset.y + aSourceBBox.GetPosition().y;
255
256 double right = left + aSourceBBox.GetSize().x;
257 double bottom = top + aSourceBBox.GetSize().y;
258
259 // Do not restrict movement if bounding box is already out of bounds
260 if( left < min || top < min || right > max || bottom > max )
261 return aMovement;
262
263 // Constrain moving bounding box to coordinates limits
264 VECTOR2D tryMovement( aMovement );
265 VECTOR2D bBoxOrigin( aSourceBBox.GetPosition() + aBBoxOffset );
266 VECTOR2D clampedBBoxOrigin = GetClampedCoords( bBoxOrigin + tryMovement, COORDS_PADDING );
267
268 tryMovement = clampedBBoxOrigin - bBoxOrigin;
269
270 VECTOR2D bBoxEnd( aSourceBBox.GetEnd() + aBBoxOffset );
271 VECTOR2D clampedBBoxEnd = GetClampedCoords( bBoxEnd + tryMovement, COORDS_PADDING );
272
273 tryMovement = clampedBBoxEnd - bBoxEnd;
274
275 return GetClampedCoords<double, int>( tryMovement );
276}
277
278
279int EDIT_TOOL::doMoveSelection( const TOOL_EVENT& aEvent, const wxString& aCommitMessage )
280{
281 bool moveWithReference = aEvent.IsAction( &PCB_ACTIONS::moveWithReference );
282 bool moveIndividually = aEvent.IsAction( &PCB_ACTIONS::moveIndividually );
283
284 PCB_BASE_EDIT_FRAME* editFrame = getEditFrame<PCB_BASE_EDIT_FRAME>();
285 PCBNEW_SETTINGS* cfg = editFrame->GetPcbNewSettings();
286 BOARD* board = editFrame->GetBoard();
288 VECTOR2I originalCursorPos = controls->GetCursorPosition();
289 STATUS_TEXT_POPUP statusPopup( frame() );
290 wxString status;
291 size_t itemIdx = 0;
292
293 editFrame->PushTool( aEvent );
294
295 // Be sure that there is at least one item that we can modify. If nothing was selected before,
296 // try looking for the stuff under mouse cursor (i.e. KiCad old-style hover selection)
298 []( const VECTOR2I& aPt, GENERAL_COLLECTOR& aCollector, PCB_SELECTION_TOOL* sTool )
299 {
300 sTool->FilterCollectorForMarkers( aCollector );
301 sTool->FilterCollectorForHierarchy( aCollector, true );
302 },
303 // Prompt user regarding locked items if in board editor and in free-pad-mode (if
304 // we're not in free-pad mode we delay this until the second RequestSelection()).
306
307 if( m_dragging || selection.Empty() )
308 {
309 editFrame->PopTool( aEvent );
310 return 0;
311 }
312
313 LSET item_layers = selection.GetSelectionLayers();
314 bool is_hover = selection.IsHover(); // N.B. This must be saved before the second call
315 // to RequestSelection() below
316 VECTOR2I pickedReferencePoint;
317
318 // Now filter out pads if not in free pads mode. We cannot do this in the first
319 // RequestSelection() as we need the item_layers when a pad is the selection front.
321 {
323 []( const VECTOR2I& aPt, GENERAL_COLLECTOR& aCollector, PCB_SELECTION_TOOL* sTool )
324 {
325 sTool->FilterCollectorForMarkers( aCollector );
326 sTool->FilterCollectorForHierarchy( aCollector, true );
327 sTool->FilterCollectorForFreePads( aCollector );
328 },
329 true /* prompt user regarding locked items */ );
330 }
331
332 if( selection.Empty() )
333 {
334 editFrame->PopTool( aEvent );
335 return 0;
336 }
337
338 Activate();
339 // Must be done after Activate() so that it gets set into the correct context
340 controls->ShowCursor( true );
341 controls->SetAutoPan( true );
343
344 auto displayConstraintsMessage =
345 [editFrame]( bool constrained )
346 {
347 editFrame->DisplayConstraintsMsg( constrained ? _( "Constrain to H, V, 45" )
348 : wxT( "" ) );
349 };
350
351 auto updateStatusPopup =
352 [&]( EDA_ITEM* item, size_t ii, size_t count )
353 {
354 wxString popuptext = _( "Click to place %s (item %ld of %ld)\n"
355 "Press <esc> to cancel all; double-click to finish" );
356 wxString msg;
357
358 if( item->Type() == PCB_FOOTPRINT_T )
359 {
360 FOOTPRINT* fp = static_cast<FOOTPRINT*>( item );
361 msg = fp->GetReference();
362 }
363 else if( item->Type() == PCB_PAD_T )
364 {
365 PAD* pad = static_cast<PAD*>( item );
366 FOOTPRINT* fp = static_cast<FOOTPRINT*>( pad->GetParentFootprint() );
367 msg = wxString::Format( _( "%s pad %s" ), fp->GetReference(), pad->GetNumber() );
368 }
369 else
370 {
371 msg = item->GetTypeDesc().Lower();
372 }
373
374 statusPopup.SetText( wxString::Format( popuptext, msg, ii, count ) );
375 };
376
377 std::vector<BOARD_ITEM*> sel_items; // All the items operated on by the move below
378 std::vector<BOARD_ITEM*> orig_items; // All the original items in the selection
379
380 for( EDA_ITEM* item : selection )
381 {
382 BOARD_ITEM* boardItem = dynamic_cast<BOARD_ITEM*>( item );
383 FOOTPRINT* footprint = dynamic_cast<FOOTPRINT*>( item );
384
385 if( boardItem )
386 {
387 if( !is_hover )
388 orig_items.push_back( boardItem );
389
390 sel_items.push_back( boardItem );
391 }
392
393 if( footprint )
394 {
395 for( PAD* pad : footprint->Pads() )
396 sel_items.push_back( pad );
397
398 // Clear this flag here; it will be set by the netlist updater if the footprint is new
399 // so that it was skipped in the initial connectivity update in OnNetlistChanged
400 footprint->SetAttributes( footprint->GetAttributes() & ~FP_JUST_ADDED );
401 }
402 }
403
404 if( moveWithReference && !pickReferencePoint( _( "Select reference point for move..." ), "", "",
405 pickedReferencePoint ) )
406 {
407 if( is_hover )
409
410 editFrame->PopTool( aEvent );
411 return 0;
412 }
413
414 if( moveIndividually )
415 {
416 orig_items.clear();
417
419 orig_items.push_back( static_cast<BOARD_ITEM*>( item ) );
420
421 updateStatusPopup( orig_items[ itemIdx ], itemIdx + 1, orig_items.size() );
422 statusPopup.Popup();
423 statusPopup.Move( wxGetMousePosition() + wxPoint( 20, 20 ) );
424 canvas()->SetStatusPopup( statusPopup.GetPanel() );
425
427 m_selectionTool->AddItemToSel( orig_items[ itemIdx ] );
428
429 sel_items.clear();
430 sel_items.push_back( orig_items[ itemIdx ] );
431 }
432
433 bool restore_state = false;
434 VECTOR2I originalPos;
435 VECTOR2I totalMovement;
436 VECTOR2D bboxMovement;
437 BOX2I originalBBox;
438 bool updateBBox = true;
440 TOOL_EVENT copy = aEvent;
441 TOOL_EVENT* evt = &copy;
442 VECTOR2I prevPos;
443
444 bool hv45Mode = false;
445 bool eatFirstMouseUp = true;
446 bool hasRedrawn3D = false;
447 bool allowRedraw3D = cfg->m_Display.m_Live3DRefresh;
448 bool showCourtyardConflicts = !m_isFootprintEditor && cfg->m_ShowCourtyardCollisions;
449
450 // Used to test courtyard overlaps
451 std::unique_ptr<DRC_INTERACTIVE_COURTYARD_CLEARANCE> drc_on_move = nullptr;
452
453 if( showCourtyardConflicts )
454 {
455 std::shared_ptr<DRC_ENGINE> drcEngine = m_toolMgr->GetTool<DRC_TOOL>()->GetDRCEngine();
456 drc_on_move.reset( new DRC_INTERACTIVE_COURTYARD_CLEARANCE( drcEngine ) );
457 drc_on_move->Init( board );
458 }
459
460 displayConstraintsMessage( hv45Mode );
461
462 // Prime the pump
464
465 // Main loop: keep receiving events
466 do
467 {
468 VECTOR2I movement;
470 grid.SetSnap( !evt->Modifier( MD_SHIFT ) );
471 grid.SetUseGrid( getView()->GetGAL()->GetGridSnapping() && !evt->DisableGridSnapping() );
472
473 bool isSkip = evt->IsAction( &PCB_ACTIONS::skip ) && moveIndividually;
474
475 if( evt->IsMotion() || evt->IsDrag( BUT_LEFT ) )
476 eatFirstMouseUp = false;
477
478 if( evt->IsAction( &PCB_ACTIONS::move ) || evt->IsMotion() || evt->IsDrag( BUT_LEFT )
482 {
483 if( m_dragging && evt->Category() == TC_MOUSE )
484 {
485 bool redraw3D = false;
486
487 VECTOR2I mousePos( controls->GetMousePosition() );
488
489 m_cursor = grid.BestSnapAnchor( mousePos, item_layers, sel_items );
490
492 {
494
495 // The arrow keys are by definition SINGLE AXIS. Do not allow the other
496 // axis to be snapped to the grid.
497 if( action == ACTIONS::CURSOR_LEFT || action == ACTIONS::CURSOR_RIGHT )
498 m_cursor.y = prevPos.y;
499 else if( action == ACTIONS::CURSOR_UP || action == ACTIONS::CURSOR_DOWN )
500 m_cursor.x = prevPos.x;
501 }
502
504 originalPos = m_cursor;
505
506 if( hv45Mode )
507 {
508 VECTOR2I moveVector = m_cursor - originalPos;
509 m_cursor = originalPos + GetVectorSnapped45( moveVector );
510 }
511
512 if( updateBBox )
513 {
514 originalBBox = BOX2I();
515 bboxMovement = VECTOR2D();
516
517 for( EDA_ITEM* item : sel_items )
518 {
519 BOX2I viewBBOX = item->ViewBBox();
520
521 if( originalBBox.GetWidth() == 0 && originalBBox.GetHeight() == 0 )
522 originalBBox = viewBBOX;
523 else
524 originalBBox.Merge( viewBBOX );
525 }
526
527 updateBBox = false;
528 }
529
530 // Constrain selection bounding box to coordinates limits
531 movement = getSafeMovement( m_cursor - prevPos, originalBBox, bboxMovement );
532
533 // Apply constrained movement
534 m_cursor = prevPos + movement;
535
538
539 prevPos = m_cursor;
540 totalMovement += movement;
541 bboxMovement += movement;
542
543 // Drag items to the current cursor position
544 for( EDA_ITEM* item : sel_items )
545 {
546 // Don't double move footprint pads, fields, etc.
547 //
548 // For PCB_GROUP_T, we make sure the selection includes only the top level
549 // group and not its descendants.
550 if( !item->GetParent() || !item->GetParent()->IsSelected() )
551 static_cast<BOARD_ITEM*>( item )->Move( movement );
552
553 if( !redraw3D && item->Type() == PCB_FOOTPRINT_T )
554 redraw3D = true;
555 }
556
557 if( redraw3D && allowRedraw3D )
558 {
559 editFrame->Update3DView( false, true );
560 hasRedrawn3D = true;
561 }
562
563 if( showCourtyardConflicts && drc_on_move->m_FpInMove.size() )
564 {
565 drc_on_move->Run();
566 drc_on_move->UpdateConflicts( m_toolMgr->GetView(), true );
567 }
568
570 }
571 else if( !m_dragging && !evt->IsAction( &ACTIONS::refreshPreview ) )
572 {
573 // Prepare to start dragging
574 editFrame->HideSolderMask();
575
576 m_dragging = true;
577
578 // When editing footprints, all items have the same parent
579 if( IsFootprintEditor() )
580 {
581 m_commit->Modify( selection.Front() );
582 }
583 else
584 {
585 // Save items, so changes can be undone
586 for( EDA_ITEM* item : selection )
587 {
588 // Don't double move footprint pads, fields, etc.
589 //
590 // For PCB_GROUP_T, the parent is the board.
591 if( item->GetParent() && item->GetParent()->IsSelected() )
592 continue;
593
594 m_commit->Modify( item );
595
596 // If moving a group, record position of all the descendants for undo
597 if( item->Type() == PCB_GROUP_T )
598 {
599 PCB_GROUP* group = static_cast<PCB_GROUP*>( item );
600 group->RunOnDescendants( [&]( BOARD_ITEM* bItem )
601 {
602 m_commit->Modify( bItem );
603 });
604 }
605 }
606 }
607
608 editFrame->UndoRedoBlock( true );
610
612 {
613 // start moving with the reference point attached to the cursor
614 grid.SetAuxAxes( false );
615
616 if( hv45Mode )
617 {
618 VECTOR2I moveVector = m_cursor - originalPos;
619 m_cursor = originalPos + GetVectorSnapped45( moveVector );
620 }
621
622 movement = m_cursor - selection.GetReferencePoint();
623
624 // Drag items to the current cursor position
625 for( EDA_ITEM* item : selection )
626 {
627 // Don't double move footprint pads, fields, etc.
628 if( item->GetParent() && item->GetParent()->IsSelected() )
629 continue;
630
631 static_cast<BOARD_ITEM*>( item )->Move( movement );
632 }
633
635 }
636 else
637 {
638 for( BOARD_ITEM* item : sel_items )
639 {
640 if( showCourtyardConflicts && item->Type() == PCB_FOOTPRINT_T )
641 drc_on_move->m_FpInMove.push_back( static_cast<FOOTPRINT*>( item ) );
642 }
643
644 m_cursor = grid.BestDragOrigin( originalCursorPos, sel_items,
646
647 // Set the current cursor position to the first dragged item origin, so the
648 // movement vector could be computed later
649 if( moveWithReference )
650 {
651 selection.SetReferencePoint( pickedReferencePoint );
652 controls->ForceCursorPosition( true, pickedReferencePoint );
653 m_cursor = pickedReferencePoint;
654 }
655 else
656 {
657 // Check if user wants to warp the mouse to origin of moved object
658 if( !editFrame->GetMoveWarpsCursor() )
659 m_cursor = originalCursorPos; // No, so use original mouse pos instead
660
662 grid.SetAuxAxes( true, m_cursor );
663 }
664
665 originalPos = m_cursor;
666 }
667
668 // Update variables for bounding box collision calculations
669 updateBBox = true;
670
672
673 prevPos = m_cursor;
674 controls->SetAutoPan( true );
676 }
677
678 statusPopup.Move( wxGetMousePosition() + wxPoint( 20, 20 ) );
679
681 }
682 else if( evt->IsCancelInteractive() || evt->IsActivate() )
683 {
684 if( m_dragging && evt->IsCancelInteractive() )
685 evt->SetPassEvent( false );
686
687 restore_state = true; // Canceling the tool means that items have to be restored
688 break; // Finish
689 }
690 else if( evt->IsAction( &ACTIONS::undo ) )
691 {
692 restore_state = true; // Perform undo locally
693 break; // Finish
694 }
695 else if( evt->IsAction( &ACTIONS::doDelete ) || evt->IsAction( &ACTIONS::cut ) )
696 {
697 // Dispatch TOOL_ACTIONs
698 evt->SetPassEvent();
699 break; // finish -- there is no further processing for removed items
700 }
701 else if( evt->IsAction( &ACTIONS::duplicate ) )
702 {
703 evt->SetPassEvent();
704 break; // finish -- Duplicate tool will start a new Move with the dup'ed items
705 }
706 else if( evt->IsAction( &PCB_ACTIONS::rotateCw )
708 || evt->IsAction( &PCB_ACTIONS::flip )
710 || evt->IsAction( &PCB_ACTIONS::mirrorV ) )
711 {
712 updateBBox = true;
713 eatFirstMouseUp = false;
714 evt->SetPassEvent();
715 }
716 else if( evt->IsAction( &PCB_ACTIONS::moveExact ) )
717 {
718 // Reset positions so the Move Exactly is from the start.
719 for( EDA_ITEM* item : selection )
720 {
721 BOARD_ITEM* i = static_cast<BOARD_ITEM*>( item );
722 i->Move( -totalMovement );
723 }
724
725 break; // finish -- we moved exactly, so we are finished
726 }
727 else if( evt->IsMouseUp( BUT_LEFT ) || evt->IsClick( BUT_LEFT ) || isSkip )
728 {
729 // Eat mouse-up/-click events that leaked through from the lock dialog
730 if( eatFirstMouseUp && evt->Parameter<intptr_t>() != ACTIONS::CURSOR_CLICK )
731 {
732 eatFirstMouseUp = false;
733 continue;
734 }
735 else if( moveIndividually && m_dragging )
736 {
737 // Put skipped items back where they started
738 if( isSkip )
739 orig_items[itemIdx]->SetPosition( originalPos );
740
742
743 if( ++itemIdx < orig_items.size() )
744 {
745 BOARD_ITEM* nextItem = orig_items[itemIdx];
746
748
749 originalPos = nextItem->GetPosition();
750 m_selectionTool->AddItemToSel( nextItem );
751 selection.SetReferencePoint( originalPos );
752
753 sel_items.clear();
754 sel_items.push_back( nextItem );
755 updateStatusPopup( nextItem, itemIdx + 1, orig_items.size() );
756
757 // Pick up new item
758 m_commit->Modify( nextItem );
759 nextItem->SetPosition( controls->GetMousePosition( true ) );
760
761 continue;
762 }
763 }
764
765 break; // finish
766 }
767 else if( evt->IsDblClick( BUT_LEFT ) )
768 {
769 // The first click will move the new item, so put it back
770 if( moveIndividually )
771 orig_items[itemIdx]->SetPosition( originalPos );
772
773 break; // finish
774 }
775 else if( evt->IsAction( &PCB_ACTIONS::toggleHV45Mode ) )
776 {
777 hv45Mode = !hv45Mode;
778 displayConstraintsMessage( hv45Mode );
779 evt->SetPassEvent( false );
780 }
781 else if( ZONE_FILLER_TOOL::IsZoneFillAction( evt ) )
782 {
783 wxBell();
784 }
785 else
786 {
787 evt->SetPassEvent();
788 }
789
790 } while( ( evt = Wait() ) ); // Assignment (instead of equality test) is intentional
791
792 // Clear temporary COURTYARD_CONFLICT flag and ensure the conflict shadow is cleared
793 if( showCourtyardConflicts )
794 drc_on_move->ClearConflicts( m_toolMgr->GetView() );
795
797 controls->ShowCursor( false );
798 controls->SetAutoPan( false );
799
800 m_dragging = false;
801 editFrame->UndoRedoBlock( false );
802
803 // Discard reference point when selection is "dropped" onto the board
805
806 // Unselect all items to clear selection flags and then re-select the originally selected
807 // items (after the potential Revert()).
809
810 // TODO: there's an encapsulation leak here: this commit often has more than just the move
811 // in it; for instance it might have a paste, append board, etc. as well.
812 if( restore_state )
813 {
814 m_commit->Revert();
816
817 // Mainly for point editor, but there might be other clients that need to adjust to
818 // reverted state.
820
821 // Property panel needs to know about the reselect
823
824 if( hasRedrawn3D )
825 editFrame->Update3DView( false, true );
826 }
827 else
828 {
829 m_commit->Push( aCommitMessage );
830 m_toolMgr->RunAction( PCB_ACTIONS::selectItems, true, &orig_items );
831 }
832
833 m_toolMgr->GetTool<DRAWING_TOOL>()->UpdateStatusBar();
834 // Remove the dynamic ratsnest from the screen
836
837 editFrame->PopTool( aEvent );
839
840 return restore_state ? -1 : 0;
841}
842
BOX2< VECTOR2I > BOX2I
Definition: box2.h:847
@ CURSOR_RIGHT
Definition: actions.h:190
@ CURSOR_LEFT
Definition: actions.h:190
@ CURSOR_CLICK
Definition: actions.h:191
@ CURSOR_UP
Definition: actions.h:190
@ CURSOR_DOWN
Definition: actions.h:190
static TOOL_ACTION undo
Definition: actions.h:65
static TOOL_ACTION duplicate
Definition: actions.h:72
static TOOL_ACTION doDelete
Definition: actions.h:73
static TOOL_ACTION cut
Definition: actions.h:67
static TOOL_ACTION refreshPreview
Definition: actions.h:109
A base class for any item which can be embedded within the BOARD container class, and therefore insta...
Definition: board_item.h:70
virtual PCB_LAYER_ID GetLayer() const
Return the primary layer this item is on.
Definition: board_item.h:192
virtual void Move(const VECTOR2I &aMoveVector)
Move this object.
Definition: board_item.h:278
virtual void SetLayer(PCB_LAYER_ID aLayer)
Set the layer this item is on.
Definition: board_item.h:226
Information pertinent to a Pcbnew printed circuit board.
Definition: board.h:265
BOX2< Vec > & Normalize()
Ensure that the height and width are positive.
Definition: box2.h:119
const Vec & GetPosition() const
Definition: box2.h:184
const Vec & GetOrigin() const
Definition: box2.h:183
coord_type GetHeight() const
Definition: box2.h:188
coord_type GetWidth() const
Definition: box2.h:187
const Vec GetEnd() const
Definition: box2.h:185
const Vec & GetSize() const
Definition: box2.h:179
BOX2< Vec > & Merge(const BOX2< Vec > &aRect)
Modify the position and size of the rectangle in order to contain aRect.
Definition: box2.h:588
int GetCount() const
Return the number of objects in the list.
Definition: collector.h:81
Tool responsible for drawing graphical elements like lines, arcs, circles, etc.
Definition: drawing_tool.h:51
void DisplayConstraintsMsg(const wxString &msg)
void SetCurrentCursor(KICURSOR aCursor)
Set the current cursor shape for this panel.
void SetStatusPopup(wxWindow *aPopup)
A base class for most all the KiCad significant classes used in schematics and boards.
Definition: eda_item.h:85
virtual VECTOR2I GetPosition() const
Definition: eda_item.h:249
virtual void SetPosition(const VECTOR2I &aPos)
Definition: eda_item.h:250
wxString GetTypeDesc() const
Return a translated description of the type for this EDA_ITEM for display in user facing messages.
Definition: eda_item.cpp:301
KICAD_T Type() const
Returns the type of object.
Definition: eda_item.h:97
bool IsSelected() const
Definition: eda_item.h:106
EDA_ITEM * GetParent() const
Definition: eda_item.h:99
virtual const BOX2I ViewBBox() const override
Return the bounding box of the item covering all its layers.
Definition: eda_item.cpp:254
bool isRouterActive() const
Definition: edit_tool.cpp:327
int Swap(const TOOL_EVENT &aEvent)
Swap currently selected items' positions.
int PackAndMoveFootprints(const TOOL_EVENT &aEvent)
Try to fit selected footprints inside a minimal area and start movement.
bool pickReferencePoint(const wxString &aTooltip, const wxString &aSuccessMessage, const wxString &aCanceledMessage, VECTOR2I &aReferencePoint)
Rebuilds the ratsnest for operations that require it outside the commit rebuild.
Definition: edit_tool.cpp:2415
bool m_dragging
Definition: edit_tool.h:211
int Move(const TOOL_EVENT &aEvent)
Main loop in which events are handled.
static const unsigned int COORDS_PADDING
Definition: edit_tool.h:216
std::unique_ptr< BOARD_COMMIT > m_commit
Definition: edit_tool.h:210
VECTOR2I getSafeMovement(const VECTOR2I &aMovement, const BOX2I &aSourceBBox, const VECTOR2D &aBBoxOffset)
int doMoveSelection(const TOOL_EVENT &aEvent, const wxString &aCommitMessage)
VECTOR2I m_cursor
Definition: edit_tool.h:212
void rebuildConnectivity()
Definition: edit_tool.cpp:2583
PCB_SELECTION_TOOL * m_selectionTool
Definition: edit_tool.h:209
static const TOOL_EVENT SelectedItemsModified
Selected items were moved, this can be very high frequency on the canvas, use with care.
Definition: actions.h:213
static const TOOL_EVENT SelectedItemsMoved
Used to inform tools that the selection should temporarily be non-editable.
Definition: actions.h:216
EDA_ANGLE GetOrientation() const
Definition: footprint.h:191
void SetOrientation(const EDA_ANGLE &aNewAngle)
Definition: footprint.cpp:1808
void SetAttributes(int aAttributes)
Definition: footprint.h:251
int GetAttributes() const
Definition: footprint.h:250
bool IsFlipped() const
Definition: footprint.h:324
PADS & Pads()
Definition: footprint.h:170
void Flip(const VECTOR2I &aCentre, bool aFlipLeftRight) override
Flip this object, i.e.
Definition: footprint.cpp:1588
const wxString & GetReference() const
Definition: footprint.h:519
Used when the right click button is pressed, or when the select tool is in effect.
Definition: collectors.h:204
An interface for classes handling user events controlling the view behavior such as zooming,...
virtual void ForceCursorPosition(bool aEnabled, const VECTOR2D &aPosition=VECTOR2D(0, 0))
Place the cursor immediately at a given point.
virtual void ShowCursor(bool aEnabled)
Enable or disables display of cursor.
VECTOR2D GetCursorPosition() const
Return the current cursor position in world coordinates.
virtual VECTOR2D GetMousePosition(bool aWorldCoordinates=true) const =0
Return the current mouse pointer position.
virtual void SetCursorPosition(const VECTOR2D &aPosition, bool aWarpView=true, bool aTriggeredByArrows=false, long aArrowCommand=0)=0
Move cursor to the requested position expressed in world coordinates.
virtual void SetAutoPan(bool aEnabled)
Turn on/off auto panning (this feature is used when there is a tool active (eg.
const VC_SETTINGS & GetSettings() const
Apply VIEW_CONTROLS settings from an object.
LSET is a set of PCB_LAYER_IDs.
Definition: layer_ids.h:530
Definition: pad.h:60
void SetLocalCoord()
< Set relative coordinates.
Definition: pad.cpp:659
DISPLAY_OPTIONS m_Display
bool m_ShowCourtyardCollisions
static TOOL_ACTION toggleHV45Mode
Definition: pcb_actions.h:466
static TOOL_ACTION mirrorH
Mirroring of selected items.
Definition: pcb_actions.h:129
static TOOL_ACTION hideLocalRatsnest
Definition: pcb_actions.h:507
static TOOL_ACTION selectionClear
Clear the current selection.
Definition: pcb_actions.h:59
static TOOL_ACTION moveWithReference
move with a reference point
Definition: pcb_actions.h:116
static TOOL_ACTION moveExact
Activation of the exact move tool.
Definition: pcb_actions.h:152
static TOOL_ACTION updateLocalRatsnest
Definition: pcb_actions.h:508
static TOOL_ACTION moveIndividually
move items one-by-one
Definition: pcb_actions.h:113
static TOOL_ACTION skip
Definition: pcb_actions.h:139
static TOOL_ACTION move
move or drag an item
Definition: pcb_actions.h:110
static TOOL_ACTION mirrorV
Definition: pcb_actions.h:130
static TOOL_ACTION selectItems
Select a list of items (specified as the event parameter)
Definition: pcb_actions.h:66
static TOOL_ACTION flip
Flipping of selected objects.
Definition: pcb_actions.h:126
static TOOL_ACTION rotateCw
Rotation of selected objects.
Definition: pcb_actions.h:122
static TOOL_ACTION rotateCcw
Definition: pcb_actions.h:123
Common, abstract interface for edit frames.
void UndoRedoBlock(bool aBlock=true)
Enable/disable undo and redo operations.
PCBNEW_SETTINGS * GetPcbNewSettings() const
virtual MAGNETIC_SETTINGS * GetMagneticItemsSettings()
PCB_DRAW_PANEL_GAL * GetCanvas() const override
Return a pointer to GAL-based canvas of given EDA draw frame.
BOARD * GetBoard() const
virtual void Update3DView(bool aMarkDirty, bool aRefresh, const wxString *aTitle=nullptr)
Update the 3D view, if the viewer is opened by this frame.
A set of BOARD_ITEMs (i.e., without duplicates).
Definition: pcb_group.h:51
The selection tool: currently supports:
void FilterCollectorForMarkers(GENERAL_COLLECTOR &aCollector) const
Drop any PCB_MARKERs from the collector.
PCB_SELECTION & RequestSelection(CLIENT_SELECTION_FILTER aClientFilter, bool aConfirmLockedItems=false)
Return the current selection, filtered according to aClientFilter.
void FilterCollectorForFreePads(GENERAL_COLLECTOR &aCollector) const
Check the "allow free pads" setting and if disabled, replace any pads in the collector with their par...
SELECTION_FILTER_OPTIONS & GetFilter()
Set up handlers for various events.
void FilterCollectorForHierarchy(GENERAL_COLLECTOR &aCollector, bool aMultiselect) const
In general we don't want to select both a parent and any of it's children.
int ClearSelection(const TOOL_EVENT &aEvent)
void RebuildSelection()
Rebuild the selection from the EDA_ITEMs' selection flags.
const LSET GetSelectionLayers()
bool IsFootprintEditor() const
PCB_BASE_EDIT_FRAME * frame() const
KIGFX::VIEW_CONTROLS * controls() const
BOARD * board() const
PCB_DRAW_PANEL_GAL * canvas() const
bool m_isFootprintEditor
const PCB_SELECTION & selection() const
FOOTPRINT * footprint() const
int AddItemToSel(const TOOL_EVENT &aEvent)
const std::vector< EDA_ITEM * > GetItemsSortedBySelectionOrder() const
Definition: selection.cpp:201
VECTOR2I GetReferencePoint() const
Definition: selection.h:252
bool IsHover() const
Definition: selection.h:83
EDA_ITEM * Front() const
Definition: selection.h:208
void ClearReferencePoint()
Definition: selection.h:265
void SetReferencePoint(const VECTOR2I &aP)
Definition: selection.h:260
bool Empty() const
Checks if there is anything selected.
Definition: selection.h:109
bool HasReferencePoint() const
Definition: selection.h:247
wxWindow * GetPanel()
Definition: status_popup.h:62
virtual void Popup(wxWindow *aFocus=nullptr)
virtual void Move(const wxPoint &aWhere)
Extension of STATUS_POPUP for displaying a single line text.
Definition: status_popup.h:83
void SetText(const wxString &aText)
Display a text.
virtual void PopTool(const TOOL_EVENT &aEvent)
Pops a tool from the stack.
bool GetMoveWarpsCursor() const
Indicate that a move operation should warp the mouse pointer to the origin of the move object.
Definition: tools_holder.h:153
virtual void PushTool(const TOOL_EVENT &aEvent)
NB: the definition of "tool" is different at the user level.
KIGFX::VIEW_CONTROLS * getViewControls() const
Return the instance of VIEW_CONTROLS object used in the application.
Definition: tool_base.cpp:42
TOOL_MANAGER * m_toolMgr
Definition: tool_base.h:215
KIGFX::VIEW * getView() const
Returns the instance of #VIEW object used in the application.
Definition: tool_base.cpp:36
Generic, UI-independent tool event.
Definition: tool_event.h:156
bool DisableGridSnapping() const
Definition: tool_event.h:344
bool IsCancelInteractive() const
Indicate the event should restart/end an ongoing interactive tool's event loop (eg esc key,...
Definition: tool_event.cpp:212
T Parameter() const
Return a non-standard parameter assigned to the event.
Definition: tool_event.h:442
bool IsActivate() const
Definition: tool_event.h:318
bool IsClick(int aButtonMask=BUT_ANY) const
Definition: tool_event.cpp:200
TOOL_EVENT_CATEGORY Category() const
Returns more specific information about the type of an event.
Definition: tool_event.h:230
bool IsDrag(int aButtonMask=BUT_ANY) const
Definition: tool_event.h:288
int Modifier(int aMask=MD_MODIFIER_MASK) const
Definition: tool_event.h:339
bool IsAction(const TOOL_ACTION *aAction) const
Test if the event contains an action issued upon activation of the given TOOL_ACTION.
Definition: tool_event.cpp:88
bool IsDblClick(int aButtonMask=BUT_ANY) const
Definition: tool_event.cpp:206
void SetPassEvent(bool aPass=true)
Returns if it this event has a valid position (true for mouse events and context-menu or hotkey-based...
Definition: tool_event.h:239
bool IsMouseUp(int aButtonMask=BUT_ANY) const
Definition: tool_event.h:298
bool IsMotion() const
Definition: tool_event.h:303
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.
void PostEvent(const TOOL_EVENT &aEvent)
Put an event to the event queue to be processed at the end of event processing cycle.
bool RunAction(const std::string &aActionName, bool aNow=false, T aParam=NULL)
Run the specified action.
Definition: tool_manager.h:142
KIGFX::VIEW * GetView() const
Definition: tool_manager.h:285
static bool IsZoneFillAction(const TOOL_EVENT *aEvent)
#define _(s)
VECTOR2< T > GetVectorSnapped45(const VECTOR2< T > &aVec, bool only45=false)
Snap a vector onto the nearest 0, 45 or 90 degree line.
VECTOR2< ret_type > GetClampedCoords(const VECTOR2< in_type > &aCoords, pad_type aPadding=1u)
Clamps a vector to values that can be negated, respecting numeric limits of coordinates data type wit...
PCB_LAYER_ID
A quick note on layer IDs:
Definition: layer_ids.h:59
void Format(OUTPUTFORMATTER *out, int aNestLevel, int aCtl, const CPTREE &aTree)
Output a PTREE into s-expression format via an OUTPUTFORMATTER derivative.
Definition: ptree.cpp:200
void SpreadFootprints(std::vector< FOOTPRINT * > *aFootprints, VECTOR2I aTargetBoxPosition, bool aGroupBySheet, int aComponentGap, int aGroupGap)
Footprints (after loaded by reading a netlist for instance) are moved to be in a small free area (out...
bool m_lastKeyboardCursorPositionValid
ACTIONS::CURSOR_UP, ACTIONS::CURSOR_DOWN, etc.
long m_lastKeyboardCursorCommand
Position of the above event.
@ TC_MOUSE
Definition: tool_event.h:50
@ MD_SHIFT
Definition: tool_event.h:138
@ BUT_LEFT
Definition: tool_event.h:127
@ PCB_GROUP_T
class PCB_GROUP, a set of BOARD_ITEMs
Definition: typeinfo.h:115
@ PCB_FOOTPRINT_T
class FOOTPRINT, a footprint
Definition: typeinfo.h:86
@ PCB_PAD_T
class PAD, a pad in a footprint
Definition: typeinfo.h:87
VECTOR2< double > VECTOR2D
Definition: vector2d.h:617
VECTOR2< int > VECTOR2I
Definition: vector2d.h:618