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