KiCad PCB EDA Suite
Loading...
Searching...
No Matches
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-2023 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 <functional>
28#include <limits>
29#include <kiplatform/ui.h>
30#include <board.h>
31#include <board_commit.h>
34#include <pad.h>
35#include <pcb_group.h>
36#include <pcb_generator.h>
37#include <pcb_edit_frame.h>
38#include <spread_footprints.h>
39#include <tools/pcb_actions.h>
41#include <tools/edit_tool.h>
43#include <tools/drc_tool.h>
45#include <router/router_tool.h>
47#include <zone_filler.h>
48#include <drc/drc_engine.h>
49#include <drc/drc_item.h>
50#include <drc/drc_rule.h>
52#include <view/view_controls.h>
53
54
55int EDIT_TOOL::Swap( const TOOL_EVENT& aEvent )
56{
57 if( isRouterActive() )
58 {
59 wxBell();
60 return 0;
61 }
62
64 []( const VECTOR2I& aPt, GENERAL_COLLECTOR& aCollector, PCB_SELECTION_TOOL* sTool )
65 {
66 sTool->FilterCollectorForMarkers( aCollector );
67 sTool->FilterCollectorForHierarchy( aCollector, true );
68 sTool->FilterCollectorForFreePads( aCollector );
69
70 // Iterate from the back so we don't have to worry about removals.
71 for( int i = aCollector.GetCount() - 1; i >= 0; --i )
72 {
73 BOARD_ITEM* item = aCollector[i];
74
75 if( item->Type() == PCB_TRACE_T )
76 aCollector.Remove( item );
77 }
78 },
79 true /* prompt user regarding locked items */ );
80
81 if( selection.Size() < 2 )
82 return 0;
83
84 BOARD_COMMIT localCommit( this );
85 BOARD_COMMIT* commit = dynamic_cast<BOARD_COMMIT*>( aEvent.Commit() );
86
87 if( !commit )
88 commit = &localCommit;
89
90 std::vector<EDA_ITEM*> sorted = selection.GetItemsSortedBySelectionOrder();
91
92 // Save items, so changes can be undone
93 for( EDA_ITEM* item : selection )
94 {
95 if( !item->IsNew() && !item->IsMoving() )
96 commit->Modify( item );
97 }
98
99 for( size_t i = 0; i < sorted.size() - 1; i++ )
100 {
101 EDA_ITEM* edaItemA = sorted[i];
102 EDA_ITEM* edaItemB = sorted[( i + 1 ) % sorted.size()];
103
104 if( !edaItemA->IsBOARD_ITEM() || !edaItemB->IsBOARD_ITEM() )
105 continue;
106
107 BOARD_ITEM* a = static_cast<BOARD_ITEM*>( edaItemA );
108 BOARD_ITEM* b = static_cast<BOARD_ITEM*>( edaItemB );
109
110 // Swap X,Y position
111 VECTOR2I aPos = a->GetPosition(), bPos = b->GetPosition();
112 std::swap( aPos, bPos );
113 a->SetPosition( aPos );
114 b->SetPosition( bPos );
115
116 // Handle footprints specially. They can be flipped to the back of the board which
117 // requires a special transformation.
118 if( a->Type() == PCB_FOOTPRINT_T && b->Type() == PCB_FOOTPRINT_T )
119 {
120 FOOTPRINT* aFP = static_cast<FOOTPRINT*>( a );
121 FOOTPRINT* bFP = static_cast<FOOTPRINT*>( b );
122
123 // Store initial orientation of footprints, before flipping them.
124 EDA_ANGLE aAngle = aFP->GetOrientation();
125 EDA_ANGLE bAngle = bFP->GetOrientation();
126
127 // Flip both if needed
128 if( aFP->IsFlipped() != bFP->IsFlipped() )
129 {
130 aFP->Flip( aPos, FLIP_DIRECTION::TOP_BOTTOM );
131 bFP->Flip( bPos, FLIP_DIRECTION::TOP_BOTTOM );
132 }
133
134 // Set orientation
135 std::swap( aAngle, bAngle );
136 aFP->SetOrientation( aAngle );
137 bFP->SetOrientation( bAngle );
138 }
139 // We can also do a layer swap safely for two objects of the same type,
140 // except groups which don't support layer swaps.
141 else if( a->Type() == b->Type() && a->Type() != PCB_GROUP_T )
142 {
143 // Swap layers
144 PCB_LAYER_ID aLayer = a->GetLayer(), bLayer = b->GetLayer();
145 std::swap( aLayer, bLayer );
146 a->SetLayer( aLayer );
147 b->SetLayer( bLayer );
148 }
149 }
150
151 if( !localCommit.Empty() )
152 localCommit.Push( _( "Swap" ) );
153
155
156 return 0;
157}
158
159
161{
162 if( isRouterActive() || m_dragging )
163 {
164 wxBell();
165 return 0;
166 }
167
168 BOARD_COMMIT commit( this );
170 []( const VECTOR2I& aPt, GENERAL_COLLECTOR& aCollector, PCB_SELECTION_TOOL* sTool )
171 {
172 sTool->FilterCollectorForMarkers( aCollector );
173 sTool->FilterCollectorForHierarchy( aCollector, true );
174 sTool->FilterCollectorForFreePads( aCollector, true );
175
176 // Iterate from the back so we don't have to worry about removals.
177 for( int i = aCollector.GetCount() - 1; i >= 0; --i )
178 {
179 BOARD_ITEM* item = aCollector[i];
180
181 if( !dynamic_cast<FOOTPRINT*>( item ) )
182 aCollector.Remove( item );
183 }
184 },
185 true /* prompt user regarding locked items */ );
186
187 std::vector<FOOTPRINT*> footprintsToPack;
188
189 for( EDA_ITEM* item : selection )
190 footprintsToPack.push_back( static_cast<FOOTPRINT*>( item ) );
191
192 if( footprintsToPack.empty() )
193 return 0;
194
195 BOX2I footprintsBbox;
196
197 for( FOOTPRINT* item : footprintsToPack )
198 {
199 commit.Modify( item );
200 item->SetFlags( IS_MOVING );
201 footprintsBbox.Merge( item->GetBoundingBox( false ) );
202 }
203
204 SpreadFootprints( &footprintsToPack, footprintsBbox.Normalize().GetOrigin(), false );
205
206 if( doMoveSelection( aEvent, &commit, true ) )
207 commit.Push( _( "Pack Footprints" ) );
208 else
209 commit.Revert();
210
211 return 0;
212}
213
214
215int EDIT_TOOL::Move( const TOOL_EVENT& aEvent )
216{
217 if( isRouterActive() || m_dragging )
218 {
219 wxBell();
220 return 0;
221 }
222
223 if( BOARD_COMMIT* commit = dynamic_cast<BOARD_COMMIT*>( aEvent.Commit() ) )
224 {
225 wxCHECK( aEvent.SynchronousState(), 0 );
226 aEvent.SynchronousState()->store( STS_RUNNING );
227
228 if( doMoveSelection( aEvent, commit, true ) )
229 aEvent.SynchronousState()->store( STS_FINISHED );
230 else
231 aEvent.SynchronousState()->store( STS_CANCELLED );
232 }
233 else
234 {
235 BOARD_COMMIT localCommit( this );
236
237 if( doMoveSelection( aEvent, &localCommit, false ) )
238 localCommit.Push( _( "Move" ) );
239 else
240 localCommit.Revert();
241 }
242
243 // Notify point editor. (While doMoveSelection() will re-select the items and post this
244 // event, it's done before the edit flags are cleared in BOARD_COMMIT::Push() so the point
245 // editor doesn't fire up.)
247
248 return 0;
249}
250
251
252VECTOR2I EDIT_TOOL::getSafeMovement( const VECTOR2I& aMovement, const BOX2I& aSourceBBox,
253 const VECTOR2D& aBBoxOffset )
254{
255 typedef std::numeric_limits<int> coord_limits;
256
257 static const double max = coord_limits::max() - (int) COORDS_PADDING;
258 static const double min = -max;
259
260 BOX2D testBox( aSourceBBox.GetPosition(), aSourceBBox.GetSize() );
261 testBox.Offset( aBBoxOffset );
262
263 // Do not restrict movement if bounding box is already out of bounds
264 if( testBox.GetLeft() < min || testBox.GetTop() < min || testBox.GetRight() > max
265 || testBox.GetBottom() > max )
266 {
267 return aMovement;
268 }
269
270 testBox.Offset( aMovement );
271
272 if( testBox.GetLeft() < min )
273 testBox.Offset( min - testBox.GetLeft(), 0 );
274
275 if( max < testBox.GetRight() )
276 testBox.Offset( -( testBox.GetRight() - max ), 0 );
277
278 if( testBox.GetTop() < min )
279 testBox.Offset( 0, min - testBox.GetTop() );
280
281 if( max < testBox.GetBottom() )
282 testBox.Offset( 0, -( testBox.GetBottom() - max ) );
283
284 return KiROUND( testBox.GetPosition() - aBBoxOffset - aSourceBBox.GetPosition() );
285}
286
287
288bool EDIT_TOOL::doMoveSelection( const TOOL_EVENT& aEvent, BOARD_COMMIT* aCommit, bool aAutoStart )
289{
290 const bool moveWithReference = aEvent.IsAction( &PCB_ACTIONS::moveWithReference );
291 const bool moveIndividually = aEvent.IsAction( &PCB_ACTIONS::moveIndividually );
292
293 PCB_BASE_EDIT_FRAME* editFrame = getEditFrame<PCB_BASE_EDIT_FRAME>();
294 PCBNEW_SETTINGS* cfg = editFrame->GetPcbNewSettings();
295 BOARD* board = editFrame->GetBoard();
297 VECTOR2I originalCursorPos = controls->GetCursorPosition();
298 std::unique_ptr<STATUS_TEXT_POPUP> statusPopup;
299 wxString status;
300 size_t itemIdx = 0;
301
302 // Be sure that there is at least one item that we can modify. If nothing was selected before,
303 // try looking for the stuff under mouse cursor (i.e. KiCad old-style hover selection)
305 []( const VECTOR2I& aPt, GENERAL_COLLECTOR& aCollector, PCB_SELECTION_TOOL* sTool )
306 {
307 sTool->FilterCollectorForMarkers( aCollector );
308 sTool->FilterCollectorForHierarchy( aCollector, true );
309 sTool->FilterCollectorForFreePads( aCollector );
310 sTool->FilterCollectorForTableCells( aCollector );
311 },
312 true /* prompt user regarding locked items */ );
313
314 if( m_dragging || selection.Empty() )
315 return false;
316
317 editFrame->PushTool( aEvent );
318 Activate();
319
320 // Must be done after Activate() so that it gets set into the correct context
321 controls->ShowCursor( true );
322 controls->SetAutoPan( true );
323 controls->ForceCursorPosition( false );
324
325 auto displayConstraintsMessage =
326 [editFrame]( bool constrained )
327 {
328 editFrame->DisplayConstraintsMsg( constrained ? _( "Constrain to H, V, 45" )
329 : wxString( wxT( "" ) ) );
330 };
331
332 auto updateStatusPopup =
333 [&]( EDA_ITEM* item, size_t ii, size_t count )
334 {
335 wxString popuptext = _( "Click to place %s (item %zu of %zu)\n"
336 "Press <esc> to cancel all; double-click to finish" );
337 wxString msg;
338
339 if( item->Type() == PCB_FOOTPRINT_T )
340 {
341 FOOTPRINT* fp = static_cast<FOOTPRINT*>( item );
342 msg = fp->GetReference();
343 }
344 else if( item->Type() == PCB_PAD_T )
345 {
346 PAD* pad = static_cast<PAD*>( item );
347 FOOTPRINT* fp = pad->GetParentFootprint();
348 msg = wxString::Format( _( "%s pad %s" ), fp->GetReference(), pad->GetNumber() );
349 }
350 else
351 {
352 msg = item->GetTypeDesc().Lower();
353 }
354
355 if( !statusPopup )
356 statusPopup = std::make_unique<STATUS_TEXT_POPUP>( frame() );
357
358 statusPopup->SetText( wxString::Format( popuptext, msg, ii, count ) );
359 };
360
361 std::vector<BOARD_ITEM*> sel_items; // All the items operated on by the move below
362 std::vector<BOARD_ITEM*> orig_items; // All the original items in the selection
363
364 for( EDA_ITEM* item : selection )
365 {
366 if( item->IsBOARD_ITEM() )
367 {
368 BOARD_ITEM* boardItem = static_cast<BOARD_ITEM*>( item );
369
370 if( !selection.IsHover() )
371 orig_items.push_back( boardItem );
372
373 sel_items.push_back( boardItem );
374 }
375
376 if( item->Type() == PCB_FOOTPRINT_T )
377 {
378 FOOTPRINT* footprint = static_cast<FOOTPRINT*>( item );
379
380 for( PAD* pad : footprint->Pads() )
381 sel_items.push_back( pad );
382
383 // Clear this flag here; it will be set by the netlist updater if the footprint is new
384 // so that it was skipped in the initial connectivity update in OnNetlistChanged
385 footprint->SetAttributes( footprint->GetAttributes() & ~FP_JUST_ADDED );
386 }
387 }
388
389 VECTOR2I pickedReferencePoint;
390
391 if( moveWithReference && !pickReferencePoint( _( "Select reference point for move..." ), "", "",
392 pickedReferencePoint ) )
393 {
394 if( selection.IsHover() )
396
397 editFrame->PopTool( aEvent );
398 return false;
399 }
400
401 if( moveIndividually )
402 {
403 orig_items.clear();
404
405 for( EDA_ITEM* item : selection.GetItemsSortedBySelectionOrder() )
406 {
407 if( item->IsBOARD_ITEM() )
408 orig_items.push_back( static_cast<BOARD_ITEM*>( item ) );
409 }
410
411 updateStatusPopup( orig_items[ itemIdx ], itemIdx + 1, orig_items.size() );
412 statusPopup->Popup();
413 statusPopup->Move( KIPLATFORM::UI::GetMousePosition() + wxPoint( 20, 20 ) );
414 canvas()->SetStatusPopup( statusPopup->GetPanel() );
415
417 m_selectionTool->AddItemToSel( orig_items[ itemIdx ] );
418
419 sel_items.clear();
420 sel_items.push_back( orig_items[ itemIdx ] );
421 }
422
423 bool restore_state = false;
424 VECTOR2I originalPos;
425 VECTOR2D bboxMovement;
426 BOX2I originalBBox;
427 bool updateBBox = true;
428 LSET layers( { editFrame->GetActiveLayer() } );
430 TOOL_EVENT copy = aEvent;
431 TOOL_EVENT* evt = &copy;
432 VECTOR2I prevPos;
433 bool enableLocalRatsnest = true;
434
435 bool hv45Mode = false;
436 bool eatFirstMouseUp = true;
437 bool allowRedraw3D = cfg->m_Display.m_Live3DRefresh;
438 bool showCourtyardConflicts = !m_isFootprintEditor && cfg->m_ShowCourtyardCollisions;
439
440 // Used to test courtyard overlaps
441 std::unique_ptr<DRC_INTERACTIVE_COURTYARD_CLEARANCE> drc_on_move = nullptr;
442
443 if( showCourtyardConflicts )
444 {
445 std::shared_ptr<DRC_ENGINE> drcEngine = m_toolMgr->GetTool<DRC_TOOL>()->GetDRCEngine();
446 drc_on_move.reset( new DRC_INTERACTIVE_COURTYARD_CLEARANCE( drcEngine ) );
447 drc_on_move->Init( board );
448 }
449
450 displayConstraintsMessage( hv45Mode );
451
452 // Prime the pump
454
455 // Main loop: keep receiving events
456 do
457 {
458 VECTOR2I movement;
459 editFrame->GetCanvas()->SetCurrentCursor( KICURSOR::MOVING );
460 grid.SetSnap( !evt->Modifier( MD_SHIFT ) );
461 grid.SetUseGrid( getView()->GetGAL()->GetGridSnapping() && !evt->DisableGridSnapping() );
462
463 bool isSkip = evt->IsAction( &PCB_ACTIONS::skip ) && moveIndividually;
464
465 if( evt->IsMotion() || evt->IsDrag( BUT_LEFT ) )
466 eatFirstMouseUp = false;
467
468 if( evt->IsAction( &PCB_ACTIONS::move ) || evt->IsMotion() || evt->IsDrag( BUT_LEFT )
472 {
473 if( m_dragging && evt->Category() == TC_MOUSE )
474 {
475 bool redraw3D = false;
476
477 VECTOR2I mousePos( controls->GetMousePosition() );
478
479 m_cursor = grid.BestSnapAnchor( mousePos, layers,
480 grid.GetSelectionGrid( selection ), sel_items );
481
483 {
484 long action = controls->GetSettings().m_lastKeyboardCursorCommand;
485
486 // The arrow keys are by definition SINGLE AXIS. Do not allow the other
487 // axis to be snapped to the grid.
488 if( action == ACTIONS::CURSOR_LEFT || action == ACTIONS::CURSOR_RIGHT )
489 m_cursor.y = prevPos.y;
490 else if( action == ACTIONS::CURSOR_UP || action == ACTIONS::CURSOR_DOWN )
491 m_cursor.x = prevPos.x;
492 }
493
494 if( !selection.HasReferencePoint() )
495 originalPos = m_cursor;
496
497 if( hv45Mode )
498 {
499 VECTOR2I moveVector = m_cursor - originalPos;
500 m_cursor = originalPos + GetVectorSnapped45( moveVector );
501 }
502
503 if( updateBBox )
504 {
505 originalBBox = BOX2I();
506 bboxMovement = VECTOR2D();
507
508 for( EDA_ITEM* item : sel_items )
509 {
510 originalBBox.Merge( item->ViewBBox() );
511 }
512
513 updateBBox = false;
514 }
515
516 // Constrain selection bounding box to coordinates limits
517 movement = getSafeMovement( m_cursor - prevPos, originalBBox, bboxMovement );
518
519 // Apply constrained movement
520 m_cursor = prevPos + movement;
521
522 controls->ForceCursorPosition( true, m_cursor );
523 selection.SetReferencePoint( m_cursor );
524
525 prevPos = m_cursor;
526 bboxMovement += movement;
527
528 // Drag items to the current cursor position
529 for( EDA_ITEM* item : sel_items )
530 {
531 // Don't double move child items.
532 if( !item->GetParent() || !item->GetParent()->IsSelected() )
533 static_cast<BOARD_ITEM*>( item )->Move( movement );
534
535 if( item->Type() == PCB_GENERATOR_T && sel_items.size() == 1 )
536 {
538 static_cast<PCB_GENERATOR*>( item ) );
539 }
540
541 if( item->Type() == PCB_FOOTPRINT_T )
542 redraw3D = true;
543 }
544
545 if( redraw3D && allowRedraw3D )
546 editFrame->Update3DView( false, true );
547
548 if( showCourtyardConflicts && drc_on_move->m_FpInMove.size() )
549 {
550 drc_on_move->Run();
551 drc_on_move->UpdateConflicts( m_toolMgr->GetView(), true );
552 }
553
555 }
556 else if( !m_dragging && ( aAutoStart || !evt->IsAction( &ACTIONS::refreshPreview ) ) )
557 {
558 // Prepare to start dragging
559 editFrame->HideSolderMask();
560
561 m_dragging = true;
562
563 for( EDA_ITEM* item : selection )
564 {
565 if( item->GetParent() && item->GetParent()->IsSelected() )
566 continue;
567
568 if( !item->IsNew() && !item->IsMoving() )
569 {
570 if( item->Type() == PCB_GENERATOR_T && sel_items.size() == 1 )
571 {
572 enableLocalRatsnest = false;
573
575 static_cast<PCB_GENERATOR*>( item ) );
576 }
577 else
578 {
579 aCommit->Modify( item );
580 }
581
582 item->SetFlags( IS_MOVING );
583
584 static_cast<BOARD_ITEM*>( item )->RunOnDescendants(
585 [&]( BOARD_ITEM* bItem )
586 {
587 item->SetFlags( IS_MOVING );
588 } );
589 }
590 }
591
592 m_cursor = controls->GetCursorPosition();
593
594 if( selection.HasReferencePoint() )
595 {
596 // start moving with the reference point attached to the cursor
597 grid.SetAuxAxes( false );
598
599 if( hv45Mode )
600 {
601 VECTOR2I moveVector = m_cursor - originalPos;
602 m_cursor = originalPos + GetVectorSnapped45( moveVector );
603 }
604
605 movement = m_cursor - selection.GetReferencePoint();
606
607 // Drag items to the current cursor position
608 for( EDA_ITEM* item : selection )
609 {
610 // Don't double move footprint pads, fields, etc.
611 if( item->GetParent() && item->GetParent()->IsSelected() )
612 continue;
613
614 static_cast<BOARD_ITEM*>( item )->Move( movement );
615 }
616
617 selection.SetReferencePoint( m_cursor );
618 }
619 else
620 {
621 if( showCourtyardConflicts )
622 {
623 std::vector<FOOTPRINT*>& FPs = drc_on_move->m_FpInMove;
624
625 for( BOARD_ITEM* item : sel_items )
626 {
627 if( item->Type() == PCB_FOOTPRINT_T )
628 FPs.push_back( static_cast<FOOTPRINT*>( item ) );
629
630 item->RunOnDescendants(
631 [&]( BOARD_ITEM* descendent )
632 {
633 if( descendent->Type() == PCB_FOOTPRINT_T )
634 FPs.push_back( static_cast<FOOTPRINT*>( descendent ) );
635 } );
636 }
637 }
638
639 m_cursor = grid.BestDragOrigin( originalCursorPos, sel_items,
640 grid.GetSelectionGrid( selection ),
642
643 // Set the current cursor position to the first dragged item origin, so the
644 // movement vector could be computed later
645 if( moveWithReference )
646 {
647 selection.SetReferencePoint( pickedReferencePoint );
648 controls->ForceCursorPosition( true, pickedReferencePoint );
649 m_cursor = pickedReferencePoint;
650 }
651 else
652 {
653 // Check if user wants to warp the mouse to origin of moved object
654 if( !editFrame->GetMoveWarpsCursor() )
655 m_cursor = originalCursorPos; // No, so use original mouse pos instead
656
657 selection.SetReferencePoint( m_cursor );
658 grid.SetAuxAxes( true, m_cursor );
659 }
660
661 originalPos = m_cursor;
662 }
663
664 // Update variables for bounding box collision calculations
665 updateBBox = true;
666
667 controls->SetCursorPosition( m_cursor, false );
668
669 prevPos = m_cursor;
670 controls->SetAutoPan( true );
672 }
673
674 if( statusPopup )
675 statusPopup->Move( KIPLATFORM::UI::GetMousePosition() + wxPoint( 20, 20 ) );
676
677 if( enableLocalRatsnest )
679 }
680 else if( evt->IsCancelInteractive() || evt->IsActivate() )
681 {
682 if( m_dragging && evt->IsCancelInteractive() )
683 evt->SetPassEvent( false );
684
685 restore_state = true; // Canceling the tool means that items have to be restored
686 break; // Finish
687 }
688 else if( evt->IsClick( BUT_RIGHT ) )
689 {
691 }
692 else if( evt->IsAction( &ACTIONS::undo ) || evt->IsAction( &ACTIONS::doDelete ) )
693 {
694 restore_state = true; // Perform undo locally
695 break; // Finish
696 }
697 else if( evt->IsAction( &ACTIONS::duplicate ) || evt->IsAction( &ACTIONS::cut ) )
698 {
699 }
700 else if( evt->IsAction( &PCB_ACTIONS::rotateCw )
702 || evt->IsAction( &PCB_ACTIONS::flip )
704 || evt->IsAction( &PCB_ACTIONS::mirrorV ) )
705 {
706 updateBBox = true;
707 eatFirstMouseUp = false;
708 evt->SetPassEvent();
709 }
710 else if( evt->IsMouseUp( BUT_LEFT ) || evt->IsClick( BUT_LEFT ) || isSkip )
711 {
712 // Eat mouse-up/-click events that leaked through from the lock dialog
713 if( eatFirstMouseUp && !evt->IsAction( &ACTIONS::cursorClick ) )
714 {
715 eatFirstMouseUp = false;
716 continue;
717 }
718 else if( moveIndividually && m_dragging )
719 {
720 // Put skipped items back where they started
721 if( isSkip )
722 orig_items[itemIdx]->SetPosition( originalPos );
723
724 view()->Update( orig_items[itemIdx] );
726
727 if( ++itemIdx < orig_items.size() )
728 {
729 BOARD_ITEM* nextItem = orig_items[itemIdx];
730
732
733 originalPos = nextItem->GetPosition();
734 m_selectionTool->AddItemToSel( nextItem );
735 selection.SetReferencePoint( originalPos );
736
737 sel_items.clear();
738 sel_items.push_back( nextItem );
739 updateStatusPopup( nextItem, itemIdx + 1, orig_items.size() );
740
741 // Pick up new item
742 aCommit->Modify( nextItem );
743 nextItem->Move( controls->GetCursorPosition( true ) - nextItem->GetPosition() );
744
745 continue;
746 }
747 }
748
749 break; // finish
750 }
751 else if( evt->IsDblClick( BUT_LEFT ) )
752 {
753 // The first click will move the new item, so put it back
754 if( moveIndividually )
755 orig_items[itemIdx]->SetPosition( originalPos );
756
757 break; // finish
758 }
759 else if( evt->IsAction( &PCB_ACTIONS::toggleHV45Mode ) )
760 {
761 hv45Mode = !hv45Mode;
762 displayConstraintsMessage( hv45Mode );
763 evt->SetPassEvent( false );
764 }
771 || evt->IsAction( &ACTIONS::redo ) )
772 {
773 wxBell();
774 }
775 else
776 {
777 evt->SetPassEvent();
778 }
779
780 } while( ( evt = Wait() ) ); // Assignment (instead of equality test) is intentional
781
782 // Clear temporary COURTYARD_CONFLICT flag and ensure the conflict shadow is cleared
783 if( showCourtyardConflicts )
784 drc_on_move->ClearConflicts( m_toolMgr->GetView() );
785
786 controls->ForceCursorPosition( false );
787 controls->ShowCursor( false );
788 controls->SetAutoPan( false );
789
790 m_dragging = false;
791
792 // Discard reference point when selection is "dropped" onto the board
793 selection.ClearReferencePoint();
794
795 // Unselect all items to clear selection flags and then re-select the originally selected
796 // items.
798
799 if( restore_state )
800 {
801 if( sel_items.size() == 1 && sel_items.back()->Type() == PCB_GENERATOR_T )
802 {
804 static_cast<PCB_GENERATOR*>( sel_items.back() ) );
805 }
806 }
807 else
808 {
809 if( sel_items.size() == 1 && sel_items.back()->Type() == PCB_GENERATOR_T )
810 {
812 static_cast<PCB_GENERATOR*>( sel_items.back() ) );
813 }
814
815 EDA_ITEMS oItems( orig_items.begin(), orig_items.end() );
817 }
818
819 // Remove the dynamic ratsnest from the screen
821
822 editFrame->PopTool( aEvent );
823 editFrame->GetCanvas()->SetCurrentCursor( KICURSOR::ARROW );
824
825 return !restore_state;
826}
827
BOX2< VECTOR2I > BOX2I
Definition: box2.h:922
constexpr BOX2I KiROUND(const BOX2D &aBoxD)
Definition: box2.h:990
@ CURSOR_RIGHT
Definition: actions.h:258
@ CURSOR_LEFT
Definition: actions.h:256
@ CURSOR_UP
Definition: actions.h:252
@ CURSOR_DOWN
Definition: actions.h:254
static TOOL_ACTION undo
Definition: actions.h:68
static TOOL_ACTION duplicate
Definition: actions.h:77
static TOOL_ACTION doDelete
Definition: actions.h:78
static TOOL_ACTION cursorClick
Definition: actions.h:169
static TOOL_ACTION redo
Definition: actions.h:69
static TOOL_ACTION cut
Definition: actions.h:70
static TOOL_ACTION refreshPreview
Definition: actions.h:149
virtual void Push(const wxString &aMessage=wxEmptyString, int aCommitFlags=0) override
Revert the commit by restoring the modified items state.
virtual void Revert() override
A base class for any item which can be embedded within the BOARD container class, and therefore insta...
Definition: board_item.h:79
virtual PCB_LAYER_ID GetLayer() const
Return the primary layer this item is on.
Definition: board_item.h:237
virtual void Move(const VECTOR2I &aMoveVector)
Move this object.
Definition: board_item.h:342
virtual void SetLayer(PCB_LAYER_ID aLayer)
Set the layer this item is on.
Definition: board_item.h:288
Information pertinent to a Pcbnew printed circuit board.
Definition: board.h:290
constexpr const Vec & GetPosition() const
Definition: box2.h:211
constexpr BOX2< Vec > & Normalize()
Ensure that the height and width are positive.
Definition: box2.h:146
constexpr BOX2< Vec > & Merge(const BOX2< Vec > &aRect)
Modify the position and size of the rectangle in order to contain aRect.
Definition: box2.h:658
constexpr coord_type GetLeft() const
Definition: box2.h:228
constexpr const Vec & GetOrigin() const
Definition: box2.h:210
constexpr coord_type GetRight() const
Definition: box2.h:217
constexpr const SizeVec & GetSize() const
Definition: box2.h:206
constexpr coord_type GetTop() const
Definition: box2.h:229
constexpr void Offset(coord_type dx, coord_type dy)
Definition: box2.h:259
constexpr coord_type GetBottom() const
Definition: box2.h:222
int GetCount() const
Return the number of objects in the list.
Definition: collector.h:81
COMMIT & Modify(EDA_ITEM *aItem, BASE_SCREEN *aScreen=nullptr)
Create an undo entry for an item that has been already modified.
Definition: commit.h:105
bool Empty() const
Returns status of an item.
Definition: commit.h:144
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:89
virtual VECTOR2I GetPosition() const
Definition: eda_item.h:243
virtual void SetPosition(const VECTOR2I &aPos)
Definition: eda_item.h:244
wxString GetTypeDesc() const
Return a translated description of the type for this EDA_ITEM for display in user facing messages.
Definition: eda_item.cpp:323
void SetFlags(EDA_ITEM_FLAGS aMask)
Definition: eda_item.h:127
KICAD_T Type() const
Returns the type of object.
Definition: eda_item.h:101
bool IsSelected() const
Definition: eda_item.h:110
EDA_ITEM * GetParent() const
Definition: eda_item.h:103
virtual const BOX2I ViewBBox() const override
Return the bounding box of the item covering all its layers.
Definition: eda_item.cpp:276
bool IsMoving() const
Definition: eda_item.h:108
bool IsNew() const
Definition: eda_item.h:107
bool isRouterActive() const
Definition: edit_tool.cpp:507
bool doMoveSelection(const TOOL_EVENT &aEvent, BOARD_COMMIT *aCommit, bool aAutoStart)
Rebuilds the ratsnest for operations that require it outside the commit rebuild.
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)
Definition: edit_tool.cpp:3130
bool m_dragging
Definition: edit_tool.h:240
int Move(const TOOL_EVENT &aEvent)
Main loop in which events are handled.
static const unsigned int COORDS_PADDING
Definition: edit_tool.h:245
VECTOR2I getSafeMovement(const VECTOR2I &aMovement, const BOX2I &aSourceBBox, const VECTOR2D &aBBoxOffset)
VECTOR2I m_cursor
Definition: edit_tool.h:241
void rebuildConnectivity()
Removes all items from the set which are children of other PCB_GROUP or PCB_GENERATOR items in the se...
Definition: edit_tool.cpp:3429
PCB_SELECTION_TOOL * m_selectionTool
Definition: edit_tool.h:239
static const TOOL_EVENT SelectedEvent
Definition: actions.h:292
static const TOOL_EVENT SelectedItemsModified
Selected items were moved, this can be very high frequency on the canvas, use with care.
Definition: actions.h:299
static const TOOL_EVENT SelectedItemsMoved
Used to inform tools that the selection should temporarily be non-editable.
Definition: actions.h:302
EDA_ANGLE GetOrientation() const
Definition: footprint.h:227
void SetOrientation(const EDA_ANGLE &aNewAngle)
Definition: footprint.cpp:2411
void SetAttributes(int aAttributes)
Definition: footprint.h:291
std::deque< PAD * > & Pads()
Definition: footprint.h:206
int GetAttributes() const
Definition: footprint.h:290
bool IsFlipped() const
Definition: footprint.h:391
void Flip(const VECTOR2I &aCentre, FLIP_DIRECTION aFlipDirection) override
Flip this object, i.e.
Definition: footprint.cpp:2283
const wxString & GetReference() const
Definition: footprint.h:602
Used when the right click button is pressed, or when the select tool is in effect.
Definition: collectors.h:202
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:91
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.
bool IsBOARD_ITEM() const
Definition: view_item.h:100
LSET is a set of PCB_LAYER_IDs.
Definition: lset.h:36
Definition: pad.h:54
DISPLAY_OPTIONS m_Display
bool m_ShowCourtyardCollisions
static TOOL_ACTION toggleHV45Mode
Definition: pcb_actions.h:524
static TOOL_ACTION mirrorH
Mirroring of selected items.
Definition: pcb_actions.h:139
static TOOL_ACTION genPushEdit
Definition: pcb_actions.h:291
static TOOL_ACTION hideLocalRatsnest
Definition: pcb_actions.h:568
static TOOL_ACTION genStartEdit
Definition: pcb_actions.h:289
static TOOL_ACTION selectionClear
Clear the current selection.
Definition: pcb_actions.h:68
static TOOL_ACTION moveWithReference
move with a reference point
Definition: pcb_actions.h:126
static TOOL_ACTION moveExact
Activation of the exact move tool.
Definition: pcb_actions.h:183
static TOOL_ACTION copyWithReference
copy command with manual reference point selection
Definition: pcb_actions.h:129
static TOOL_ACTION positionRelativeInteractively
Definition: pcb_actions.h:328
static TOOL_ACTION genUpdateEdit
Definition: pcb_actions.h:290
static TOOL_ACTION updateLocalRatsnest
Definition: pcb_actions.h:569
static TOOL_ACTION moveIndividually
move items one-by-one
Definition: pcb_actions.h:123
static TOOL_ACTION positionRelative
Definition: pcb_actions.h:327
static TOOL_ACTION skip
Definition: pcb_actions.h:149
static TOOL_ACTION move
move or drag an item
Definition: pcb_actions.h:120
static TOOL_ACTION mirrorV
Definition: pcb_actions.h:140
static TOOL_ACTION selectItems
Select a list of items (specified as the event parameter)
Definition: pcb_actions.h:76
static TOOL_ACTION flip
Flipping of selected objects.
Definition: pcb_actions.h:136
static TOOL_ACTION rotateCw
Rotation of selected objects.
Definition: pcb_actions.h:132
static TOOL_ACTION rotateCcw
Definition: pcb_actions.h:133
static TOOL_ACTION genRevertEdit
Definition: pcb_actions.h:292
Common, abstract interface for edit frames.
PCBNEW_SETTINGS * GetPcbNewSettings() const
virtual PCB_LAYER_ID GetActiveLayer() 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.
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, bool aForcePromotion=false) const
Check the "allow free pads" setting and if disabled, replace any pads in the collector with their par...
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.
PCB_SELECTION_FILTER_OPTIONS & GetFilter()
Set up handlers for various events.
int ClearSelection(const TOOL_EVENT &aEvent)
void FilterCollectorForTableCells(GENERAL_COLLECTOR &aCollector) const
Promote any table cell selections to the whole table.
T * frame() const
KIGFX::PCB_VIEW * view() 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)
bool IsHover() const
Definition: selection.h:84
int Size() const
Returns the number of selected parts.
Definition: selection.h:116
std::vector< EDA_ITEM * > GetItemsSortedBySelectionOrder() const
Definition: selection.cpp:265
void ClearReferencePoint()
Definition: selection.cpp:186
void SetReferencePoint(const VECTOR2I &aP)
Definition: selection.cpp:180
bool Empty() const
Checks if there is anything selected.
Definition: selection.h:110
bool HasReferencePoint() const
Definition: selection.h:211
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:150
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:218
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:167
bool DisableGridSnapping() const
Definition: tool_event.h:363
bool IsCancelInteractive() const
Indicate the event should restart/end an ongoing interactive tool's event loop (eg esc key,...
Definition: tool_event.cpp:221
bool IsActivate() const
Definition: tool_event.h:337
COMMIT * Commit() const
Returns information about difference between current mouse cursor position and the place where draggi...
Definition: tool_event.h:275
bool IsClick(int aButtonMask=BUT_ANY) const
Definition: tool_event.cpp:209
TOOL_EVENT_CATEGORY Category() const
Returns more specific information about the type of an event.
Definition: tool_event.h:243
bool IsDrag(int aButtonMask=BUT_ANY) const
Definition: tool_event.h:307
int Modifier(int aMask=MD_MODIFIER_MASK) const
Definition: tool_event.h:358
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:82
bool IsDblClick(int aButtonMask=BUT_ANY) const
Definition: tool_event.cpp:215
std::atomic< SYNCRONOUS_TOOL_STATE > * SynchronousState() const
Definition: tool_event.h:272
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:252
bool IsMouseUp(int aButtonMask=BUT_ANY) const
Definition: tool_event.h:317
bool IsMotion() const
Definition: tool_event.h:322
TOOL_MENU & GetToolMenu()
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.
bool ProcessEvent(const TOOL_EVENT &aEvent)
Propagate an event to tools that requested events of matching type(s).
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, T aParam)
Run the specified action immediately, pausing the current action to run the new one.
Definition: tool_manager.h:150
bool PostAction(const std::string &aActionName, T aParam)
Run the specified action after the current action (coroutine) ends.
Definition: tool_manager.h:235
bool RunSynchronousAction(const TOOL_ACTION &aAction, COMMIT *aCommit, T aParam)
Run the specified action immediately, pausing the current action to run the new one.
Definition: tool_manager.h:197
KIGFX::VIEW * GetView() const
Definition: tool_manager.h:391
void ShowContextMenu(SELECTION &aSelection)
Helper function to set and immediately show a CONDITIONAL_MENU in concert with the given SELECTION.
Definition: tool_menu.cpp:57
static bool IsZoneFillAction(const TOOL_EVENT *aEvent)
#define _(s)
std::vector< EDA_ITEM * > EDA_ITEMS
Define list of drawing items for screens.
Definition: eda_item.h:536
#define IS_MOVING
Item being moved.
a few functions useful in geometry calculations.
VECTOR2< T > GetVectorSnapped45(const VECTOR2< T > &aVec, bool only45=false)
Snap a vector onto the nearest 0, 45 or 90 degree line.
PCB_LAYER_ID
A quick note on layer IDs:
Definition: layer_ids.h:60
wxPoint GetMousePosition()
Returns the mouse position in screen coordinates.
Definition: wxgtk/ui.cpp:620
Class to handle a set of BOARD_ITEMs.
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:54
@ MD_SHIFT
Definition: tool_event.h:142
@ STS_CANCELLED
Definition: tool_event.h:160
@ STS_FINISHED
Definition: tool_event.h:159
@ STS_RUNNING
Definition: tool_event.h:158
@ BUT_LEFT
Definition: tool_event.h:131
@ BUT_RIGHT
Definition: tool_event.h:132
@ PCB_GENERATOR_T
class PCB_GENERATOR, generator on a layer
Definition: typeinfo.h:91
@ PCB_GROUP_T
class PCB_GROUP, a set of BOARD_ITEMs
Definition: typeinfo.h:110
@ 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:690