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 <advanced_config.h>
28#include <limits>
29#include <board.h>
31#include <footprint.h>
32#include <pcb_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 // Handle footprints specially. They can be flipped to the back of the board which
144 // requires a special transformation.
145 if( a->Type() == PCB_FOOTPRINT_T && b->Type() == PCB_FOOTPRINT_T )
146 {
147 FOOTPRINT* aFP = static_cast<FOOTPRINT*>( a );
148 FOOTPRINT* bFP = static_cast<FOOTPRINT*>( b );
149
150 // Flip both if needed
151 if( aFP->IsFlipped() != bFP->IsFlipped() )
152 {
153 aFP->Flip( aPos, false );
154 bFP->Flip( bPos, false );
155 }
156
157 // Set orientation
158 EDA_ANGLE aAngle = aFP->GetOrientation(), bAngle = bFP->GetOrientation();
159 std::swap( aAngle, bAngle );
160 aFP->SetOrientation( aAngle );
161 bFP->SetOrientation( bAngle );
162 }
163 // We can also do a layer swap safely for two objects of the same type,
164 // except groups which don't support layer swaps.
165 else if( a->Type() == b->Type() && a->Type() != PCB_GROUP_T )
166 {
167 // Swap layers
168 PCB_LAYER_ID aLayer = a->GetLayer(), bLayer = b->GetLayer();
169 std::swap( aLayer, bLayer );
170 a->SetLayer( aLayer );
171 b->SetLayer( bLayer );
172 }
173 }
174
175 if( !m_dragging )
176 m_commit->Push( _( "Swap" ) );
177
178 m_toolMgr->ProcessEvent( EVENTS::SelectedItemsModified );
179
180 return 0;
181}
182
183
185{
187 []( const VECTOR2I& aPt, GENERAL_COLLECTOR& aCollector, PCB_SELECTION_TOOL* sTool )
188 {
189 sTool->FilterCollectorForMarkers( aCollector );
190 sTool->FilterCollectorForHierarchy( aCollector, true );
191 sTool->FilterCollectorForFreePads( aCollector );
192
193 // Iterate from the back so we don't have to worry about removals.
194 for( int i = aCollector.GetCount() - 1; i >= 0; --i )
195 {
196 BOARD_ITEM* item = aCollector[i];
197
198 if( !dynamic_cast<FOOTPRINT*>( item ) )
199 aCollector.Remove( item );
200 }
201 },
202 true /* prompt user regarding locked items */ );
203
204 std::vector<FOOTPRINT*> footprintsToPack;
205
206 for( EDA_ITEM* item : selection )
207 footprintsToPack.push_back( static_cast<FOOTPRINT*>( item ) );
208
209 if( footprintsToPack.empty() )
210 return 0;
211
212 BOX2I footprintsBbox;
213
214 for( FOOTPRINT* item : footprintsToPack )
215 {
216 m_commit->Modify( item );
217 footprintsBbox.Merge( item->GetBoundingBox( false, false ) );
218 }
219
220 SpreadFootprints( &footprintsToPack, footprintsBbox.Normalize().GetOrigin(), false );
221
222 return doMoveSelection( aEvent, _( "Pack footprints" ) );
223}
224
225
226int EDIT_TOOL::Move( const TOOL_EVENT& aEvent )
227{
228 if( isRouterActive() || m_dragging )
229 {
230 wxBell();
231 return 0;
232 }
233
234 return doMoveSelection( aEvent, _( "Move" ) );
235}
236
237
238VECTOR2I EDIT_TOOL::getSafeMovement( const VECTOR2I& aMovement, const BOX2I& aSourceBBox,
239 const VECTOR2D& aBBoxOffset )
240{
241 typedef std::numeric_limits<int> coord_limits;
242
243 int max = coord_limits::max();
244 int min = -max;
245
246 double left = aBBoxOffset.x + aSourceBBox.GetPosition().x;
247 double top = aBBoxOffset.y + aSourceBBox.GetPosition().y;
248
249 double right = left + aSourceBBox.GetSize().x;
250 double bottom = top + aSourceBBox.GetSize().y;
251
252 // Do not restrict movement if bounding box is already out of bounds
253 if( left < min || top < min || right > max || bottom > max )
254 return aMovement;
255
256 // Constrain moving bounding box to coordinates limits
257 VECTOR2D tryMovement( aMovement );
258 VECTOR2D bBoxOrigin( aSourceBBox.GetPosition() + aBBoxOffset );
259 VECTOR2D clampedBBoxOrigin = GetClampedCoords( bBoxOrigin + tryMovement, COORDS_PADDING );
260
261 tryMovement = clampedBBoxOrigin - bBoxOrigin;
262
263 VECTOR2D bBoxEnd( aSourceBBox.GetEnd() + aBBoxOffset );
264 VECTOR2D clampedBBoxEnd = GetClampedCoords( bBoxEnd + tryMovement, COORDS_PADDING );
265
266 tryMovement = clampedBBoxEnd - bBoxEnd;
267
268 return GetClampedCoords<double, int>( tryMovement );
269}
270
271
272int EDIT_TOOL::doMoveSelection( const TOOL_EVENT& aEvent, const wxString& aCommitMessage )
273{
274 bool moveWithReference = aEvent.IsAction( &PCB_ACTIONS::moveWithReference );
275 bool moveIndividually = aEvent.IsAction( &PCB_ACTIONS::moveIndividually );
276
277 PCB_BASE_EDIT_FRAME* editFrame = getEditFrame<PCB_BASE_EDIT_FRAME>();
278 PCBNEW_SETTINGS* cfg = editFrame->GetPcbNewSettings();
279 BOARD* board = editFrame->GetBoard();
281 VECTOR2I originalCursorPos = controls->GetCursorPosition();
282 STATUS_TEXT_POPUP statusPopup( frame() );
283 wxString status;
284 size_t itemIdx = 0;
285
286 // Be sure that there is at least one item that we can modify. If nothing was selected before,
287 // try looking for the stuff under mouse cursor (i.e. KiCad old-style hover selection)
289 []( const VECTOR2I& aPt, GENERAL_COLLECTOR& aCollector, PCB_SELECTION_TOOL* sTool )
290 {
291 sTool->FilterCollectorForMarkers( aCollector );
292 sTool->FilterCollectorForHierarchy( aCollector, true );
293 },
294 // Prompt user regarding locked items if in board editor and in free-pad-mode (if
295 // we're not in free-pad mode we delay this until the second RequestSelection()).
297
298 if( m_dragging || selection.Empty() )
299 return 0;
300
301 LSET item_layers = selection.GetSelectionLayers();
302 bool is_hover = selection.IsHover(); // N.B. This must be saved before the second call
303 // to RequestSelection() below
304 VECTOR2I pickedReferencePoint;
305
306 // Now filter out pads if not in free pads mode. We cannot do this in the first
307 // RequestSelection() as we need the item_layers when a pad is the selection front.
309 {
311 []( const VECTOR2I& aPt, GENERAL_COLLECTOR& aCollector, PCB_SELECTION_TOOL* sTool )
312 {
313 sTool->FilterCollectorForMarkers( aCollector );
314 sTool->FilterCollectorForHierarchy( aCollector, true );
315 sTool->FilterCollectorForFreePads( aCollector );
316 },
317 true /* prompt user regarding locked items */ );
318 }
319
320 if( selection.Empty() )
321 {
322 return 0;
323 }
324
325 editFrame->PushTool( aEvent );
326 Activate();
327
328 // Must be done after Activate() so that it gets set into the correct context
329 controls->ShowCursor( true );
330 controls->SetAutoPan( true );
331 controls->ForceCursorPosition( false );
332
333 auto displayConstraintsMessage =
334 [editFrame]( bool constrained )
335 {
336 editFrame->DisplayConstraintsMsg( constrained ? _( "Constrain to H, V, 45" )
337 : wxString( wxT( "" ) ) );
338 };
339
340 auto updateStatusPopup =
341 [&]( EDA_ITEM* item, size_t ii, size_t count )
342 {
343 wxString popuptext = _( "Click to place %s (item %ld of %ld)\n"
344 "Press <esc> to cancel all; double-click to finish" );
345 wxString msg;
346
347 if( item->Type() == PCB_FOOTPRINT_T )
348 {
349 FOOTPRINT* fp = static_cast<FOOTPRINT*>( item );
350 msg = fp->GetReference();
351 }
352 else if( item->Type() == PCB_PAD_T )
353 {
354 PAD* pad = static_cast<PAD*>( item );
355 FOOTPRINT* fp = pad->GetParentFootprint();
356 msg = wxString::Format( _( "%s pad %s" ), fp->GetReference(), pad->GetNumber() );
357 }
358 else
359 {
360 msg = item->GetTypeDesc().Lower();
361 }
362
363 statusPopup.SetText( wxString::Format( popuptext, msg, ii, count ) );
364 };
365
366 std::vector<BOARD_ITEM*> sel_items; // All the items operated on by the move below
367 std::vector<BOARD_ITEM*> orig_items; // All the original items in the selection
368
369 for( EDA_ITEM* item : selection )
370 {
371 BOARD_ITEM* boardItem = dynamic_cast<BOARD_ITEM*>( item );
372 FOOTPRINT* footprint = dynamic_cast<FOOTPRINT*>( item );
373
374 if( boardItem )
375 {
376 if( !is_hover )
377 orig_items.push_back( boardItem );
378
379 sel_items.push_back( boardItem );
380 }
381
382 if( footprint )
383 {
384 for( PAD* pad : footprint->Pads() )
385 sel_items.push_back( pad );
386
387 // Clear this flag here; it will be set by the netlist updater if the footprint is new
388 // so that it was skipped in the initial connectivity update in OnNetlistChanged
389 footprint->SetAttributes( footprint->GetAttributes() & ~FP_JUST_ADDED );
390 }
391 }
392
393 if( moveWithReference && !pickReferencePoint( _( "Select reference point for move..." ), "", "",
394 pickedReferencePoint ) )
395 {
396 if( is_hover )
398
399 editFrame->PopTool( aEvent );
400 return 0;
401 }
402
403 if( moveIndividually )
404 {
405 orig_items.clear();
406
407 for( EDA_ITEM* item : selection.GetItemsSortedBySelectionOrder() )
408 orig_items.push_back( static_cast<BOARD_ITEM*>( item ) );
409
410 updateStatusPopup( orig_items[ itemIdx ], itemIdx + 1, orig_items.size() );
411 statusPopup.Popup();
412 statusPopup.Move( wxGetMousePosition() + wxPoint( 20, 20 ) );
413 canvas()->SetStatusPopup( statusPopup.GetPanel() );
414
416 m_selectionTool->AddItemToSel( orig_items[ itemIdx ] );
417
418 sel_items.clear();
419 sel_items.push_back( orig_items[ itemIdx ] );
420 }
421
422 bool restore_state = false;
423 VECTOR2I originalPos;
424 VECTOR2I totalMovement;
425 VECTOR2D bboxMovement;
426 BOX2I originalBBox;
427 bool updateBBox = true;
429 TOOL_EVENT copy = aEvent;
430 TOOL_EVENT* evt = &copy;
431 VECTOR2I prevPos;
432
433 bool hv45Mode = false;
434 bool eatFirstMouseUp = true;
435 bool hasRedrawn3D = false;
436 bool allowRedraw3D = cfg->m_Display.m_Live3DRefresh;
437 bool showCourtyardConflicts = !m_isFootprintEditor && cfg->m_ShowCourtyardCollisions;
438
439 // Used to test courtyard overlaps
440 std::unique_ptr<DRC_INTERACTIVE_COURTYARD_CLEARANCE> drc_on_move = nullptr;
441
442 if( showCourtyardConflicts )
443 {
444 std::shared_ptr<DRC_ENGINE> drcEngine = m_toolMgr->GetTool<DRC_TOOL>()->GetDRCEngine();
445 drc_on_move.reset( new DRC_INTERACTIVE_COURTYARD_CLEARANCE( drcEngine ) );
446 drc_on_move->Init( board );
447 }
448
449 displayConstraintsMessage( hv45Mode );
450
451 // Prime the pump
453
454 // Main loop: keep receiving events
455 do
456 {
457 VECTOR2I movement;
458 editFrame->GetCanvas()->SetCurrentCursor( KICURSOR::MOVING );
459 grid.SetSnap( !evt->Modifier( MD_SHIFT ) );
460 grid.SetUseGrid( getView()->GetGAL()->GetGridSnapping() && !evt->DisableGridSnapping() );
461
462 bool isSkip = evt->IsAction( &PCB_ACTIONS::skip ) && moveIndividually;
463
464 if( evt->IsMotion() || evt->IsDrag( BUT_LEFT ) )
465 eatFirstMouseUp = false;
466
467 if( evt->IsAction( &PCB_ACTIONS::move ) || evt->IsMotion() || evt->IsDrag( BUT_LEFT )
471 {
472 if( m_dragging && evt->Category() == TC_MOUSE )
473 {
474 bool redraw3D = false;
475
476 VECTOR2I mousePos( controls->GetMousePosition() );
477
478 m_cursor = grid.BestSnapAnchor( mousePos, item_layers, sel_items );
479
481 {
482 long action = controls->GetSettings().m_lastKeyboardCursorCommand;
483
484 // The arrow keys are by definition SINGLE AXIS. Do not allow the other
485 // axis to be snapped to the grid.
486 if( action == ACTIONS::CURSOR_LEFT || action == ACTIONS::CURSOR_RIGHT )
487 m_cursor.y = prevPos.y;
488 else if( action == ACTIONS::CURSOR_UP || action == ACTIONS::CURSOR_DOWN )
489 m_cursor.x = prevPos.x;
490 }
491
492 if( !selection.HasReferencePoint() )
493 originalPos = m_cursor;
494
495 if( hv45Mode )
496 {
497 VECTOR2I moveVector = m_cursor - originalPos;
498 m_cursor = originalPos + GetVectorSnapped45( moveVector );
499 }
500
501 if( updateBBox )
502 {
503 originalBBox = BOX2I();
504 bboxMovement = VECTOR2D();
505
506 for( EDA_ITEM* item : sel_items )
507 {
508 BOX2I viewBBOX = item->ViewBBox();
509
510 if( originalBBox.GetWidth() == 0 && originalBBox.GetHeight() == 0 )
511 originalBBox = viewBBOX;
512 else
513 originalBBox.Merge( viewBBOX );
514 }
515
516 updateBBox = false;
517 }
518
519 // Constrain selection bounding box to coordinates limits
520 movement = getSafeMovement( m_cursor - prevPos, originalBBox, bboxMovement );
521
522 // Apply constrained movement
523 m_cursor = prevPos + movement;
524
525 controls->ForceCursorPosition( true, m_cursor );
526 selection.SetReferencePoint( m_cursor );
527
528 prevPos = m_cursor;
529 totalMovement += movement;
530 bboxMovement += movement;
531
532 // Drag items to the current cursor position
533 for( EDA_ITEM* item : sel_items )
534 {
535 // Don't double move footprint pads, fields, etc.
536 //
537 // For PCB_GROUP_T, we make sure the selection includes only the top level
538 // group and not its descendants.
539 if( !item->GetParent() || !item->GetParent()->IsSelected() )
540 static_cast<BOARD_ITEM*>( item )->Move( movement );
541
542 if( !redraw3D && item->Type() == PCB_FOOTPRINT_T )
543 redraw3D = true;
544 }
545
546 if( redraw3D && allowRedraw3D )
547 {
548 editFrame->Update3DView( false, true );
549 hasRedrawn3D = true;
550 }
551
552 if( showCourtyardConflicts && drc_on_move->m_FpInMove.size() )
553 {
554 drc_on_move->Run();
555 drc_on_move->UpdateConflicts( m_toolMgr->GetView(), true );
556 }
557
559 }
560 else if( !m_dragging && !evt->IsAction( &ACTIONS::refreshPreview ) )
561 {
562 // Prepare to start dragging
563 editFrame->HideSolderMask();
564
565 m_dragging = true;
566
567 // When editing footprints, all items have the same parent
568 if( IsFootprintEditor() )
569 {
570 m_commit->Modify( selection.Front() );
571 }
572 else
573 {
574 // Save items, so changes can be undone
575 for( EDA_ITEM* item : selection )
576 {
577 // Don't double move footprint pads, fields, etc.
578 //
579 // For PCB_GROUP_T, the parent is the board.
580 if( item->GetParent() && item->GetParent()->IsSelected() )
581 continue;
582
583 m_commit->Modify( item );
584
585 // If moving a group, record position of all the descendants for undo
586 if( item->Type() == PCB_GROUP_T )
587 {
588 PCB_GROUP* group = static_cast<PCB_GROUP*>( item );
589 group->RunOnDescendants( [&]( BOARD_ITEM* bItem )
590 {
591 m_commit->Modify( bItem );
592 });
593 }
594 }
595 }
596
597 editFrame->UndoRedoBlock( true );
598 m_cursor = controls->GetCursorPosition();
599
600 if( selection.HasReferencePoint() )
601 {
602 // start moving with the reference point attached to the cursor
603 grid.SetAuxAxes( false );
604
605 if( hv45Mode )
606 {
607 VECTOR2I moveVector = m_cursor - originalPos;
608 m_cursor = originalPos + GetVectorSnapped45( moveVector );
609 }
610
611 movement = m_cursor - selection.GetReferencePoint();
612
613 // Drag items to the current cursor position
614 for( EDA_ITEM* item : selection )
615 {
616 // Don't double move footprint pads, fields, etc.
617 if( item->GetParent() && item->GetParent()->IsSelected() )
618 continue;
619
620 static_cast<BOARD_ITEM*>( item )->Move( movement );
621 }
622
623 selection.SetReferencePoint( m_cursor );
624 }
625 else
626 {
627 for( BOARD_ITEM* item : sel_items )
628 {
629 if( showCourtyardConflicts && item->Type() == PCB_FOOTPRINT_T )
630 drc_on_move->m_FpInMove.push_back( static_cast<FOOTPRINT*>( item ) );
631 }
632
633 m_cursor = grid.BestDragOrigin( originalCursorPos, sel_items,
635
636 // Set the current cursor position to the first dragged item origin, so the
637 // movement vector could be computed later
638 if( moveWithReference )
639 {
640 selection.SetReferencePoint( pickedReferencePoint );
641 controls->ForceCursorPosition( true, pickedReferencePoint );
642 m_cursor = pickedReferencePoint;
643 }
644 else
645 {
646 // Check if user wants to warp the mouse to origin of moved object
647 if( !editFrame->GetMoveWarpsCursor() )
648 m_cursor = originalCursorPos; // No, so use original mouse pos instead
649
650 selection.SetReferencePoint( m_cursor );
651 grid.SetAuxAxes( true, m_cursor );
652 }
653
654 originalPos = m_cursor;
655 }
656
657 // Update variables for bounding box collision calculations
658 updateBBox = true;
659
660 controls->SetCursorPosition( m_cursor, false );
661
662 prevPos = m_cursor;
663 controls->SetAutoPan( true );
665 }
666
667 statusPopup.Move( wxGetMousePosition() + wxPoint( 20, 20 ) );
668
670 }
671 else if( evt->IsCancelInteractive() || evt->IsActivate() )
672 {
673 if( m_dragging && evt->IsCancelInteractive() )
674 evt->SetPassEvent( false );
675
676 restore_state = true; // Canceling the tool means that items have to be restored
677 break; // Finish
678 }
679 else if( evt->IsAction( &ACTIONS::undo ) )
680 {
681 restore_state = true; // Perform undo locally
682 break; // Finish
683 }
684 else if( evt->IsAction( &ACTIONS::doDelete ) || evt->IsAction( &ACTIONS::cut ) )
685 {
686 // Dispatch TOOL_ACTIONs
687 evt->SetPassEvent();
688 break; // finish -- there is no further processing for removed items
689 }
690 else if( evt->IsAction( &ACTIONS::duplicate ) )
691 {
692 evt->SetPassEvent();
693 break; // finish -- Duplicate tool will start a new Move with the dup'ed items
694 }
695 else if( evt->IsAction( &PCB_ACTIONS::rotateCw )
697 || evt->IsAction( &PCB_ACTIONS::flip )
699 || evt->IsAction( &PCB_ACTIONS::mirrorV ) )
700 {
701 updateBBox = true;
702 eatFirstMouseUp = false;
703 evt->SetPassEvent();
704 }
705 else if( evt->IsAction( &PCB_ACTIONS::moveExact ) )
706 {
707 // Reset positions so the Move Exactly is from the start.
708 for( EDA_ITEM* item : selection )
709 {
710 BOARD_ITEM* i = static_cast<BOARD_ITEM*>( item );
711 i->Move( -totalMovement );
712 }
713
714 break; // finish -- we moved exactly, so we are finished
715 }
716 else if( evt->IsMouseUp( BUT_LEFT ) || evt->IsClick( BUT_LEFT ) || isSkip )
717 {
718 // Eat mouse-up/-click events that leaked through from the lock dialog
719 if( eatFirstMouseUp && evt->Parameter<intptr_t>() != ACTIONS::CURSOR_CLICK )
720 {
721 eatFirstMouseUp = false;
722 continue;
723 }
724 else if( moveIndividually && m_dragging )
725 {
726 // Put skipped items back where they started
727 if( isSkip )
728 orig_items[itemIdx]->SetPosition( originalPos );
729
731
732 if( ++itemIdx < orig_items.size() )
733 {
734 BOARD_ITEM* nextItem = orig_items[itemIdx];
735
737
738 originalPos = nextItem->GetPosition();
739 m_selectionTool->AddItemToSel( nextItem );
740 selection.SetReferencePoint( originalPos );
741
742 sel_items.clear();
743 sel_items.push_back( nextItem );
744 updateStatusPopup( nextItem, itemIdx + 1, orig_items.size() );
745
746 // Pick up new item
747 m_commit->Modify( nextItem );
748 nextItem->SetPosition( controls->GetMousePosition( true ) );
749
750 continue;
751 }
752 }
753
754 break; // finish
755 }
756 else if( evt->IsDblClick( BUT_LEFT ) )
757 {
758 // The first click will move the new item, so put it back
759 if( moveIndividually )
760 orig_items[itemIdx]->SetPosition( originalPos );
761
762 break; // finish
763 }
764 else if( evt->IsAction( &PCB_ACTIONS::toggleHV45Mode ) )
765 {
766 hv45Mode = !hv45Mode;
767 displayConstraintsMessage( hv45Mode );
768 evt->SetPassEvent( false );
769 }
770 else if( ZONE_FILLER_TOOL::IsZoneFillAction( evt ) )
771 {
772 wxBell();
773 }
774 else
775 {
776 evt->SetPassEvent();
777 }
778
779 } while( ( evt = Wait() ) ); // Assignment (instead of equality test) is intentional
780
781 // Clear temporary COURTYARD_CONFLICT flag and ensure the conflict shadow is cleared
782 if( showCourtyardConflicts )
783 drc_on_move->ClearConflicts( m_toolMgr->GetView() );
784
785 controls->ForceCursorPosition( false );
786 controls->ShowCursor( false );
787 controls->SetAutoPan( false );
788
789 m_dragging = false;
790 editFrame->UndoRedoBlock( 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 (after the potential Revert()).
798
799 // TODO: there's an encapsulation leak here: this commit often has more than just the move
800 // in it; for instance it might have a paste, append board, etc. as well.
801 if( restore_state )
802 {
803 m_commit->Revert();
805
806 // Mainly for point editor, but there might be other clients that need to adjust to
807 // reverted state.
809
810 // Property panel needs to know about the reselect
812
813 if( hasRedrawn3D )
814 editFrame->Update3DView( false, true );
815 }
816 else
817 {
818 m_commit->Push( aCommitMessage );
819 m_toolMgr->RunAction( PCB_ACTIONS::selectItems, true, &orig_items );
820 }
821
822 m_toolMgr->GetTool<DRAWING_TOOL>()->UpdateStatusBar();
823 // Remove the dynamic ratsnest from the screen
825
826 editFrame->PopTool( aEvent );
827 editFrame->GetCanvas()->SetCurrentCursor( KICURSOR::ARROW );
828
829 return restore_state ? -1 : 0;
830}
831
BOX2< VECTOR2I > BOX2I
Definition: box2.h:847
@ CURSOR_RIGHT
Definition: actions.h:191
@ CURSOR_LEFT
Definition: actions.h:191
@ CURSOR_CLICK
Definition: actions.h:192
@ CURSOR_UP
Definition: actions.h:191
@ CURSOR_DOWN
Definition: actions.h:191
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:110
A base class for any item which can be embedded within the BOARD container class, and therefore insta...
Definition: board_item.h:71
virtual PCB_LAYER_ID GetLayer() const
Return the primary layer this item is on.
Definition: board_item.h:196
virtual void Move(const VECTOR2I &aMoveVector)
Move this object.
Definition: board_item.h:282
virtual void SetLayer(PCB_LAYER_ID aLayer)
Set the layer this item is on.
Definition: board_item.h:230
Information pertinent to a Pcbnew printed circuit board.
Definition: board.h:270
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:232
virtual void SetPosition(const VECTOR2I &aPos)
Definition: eda_item.h:233
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:326
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:2363
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:2532
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:214
static const TOOL_EVENT SelectedItemsMoved
Used to inform tools that the selection should temporarily be non-editable.
Definition: actions.h:217
EDA_ANGLE GetOrientation() const
Definition: footprint.h:193
void SetOrientation(const EDA_ANGLE &aNewAngle)
Definition: footprint.cpp:1728
void SetAttributes(int aAttributes)
Definition: footprint.h:253
int GetAttributes() const
Definition: footprint.h:252
bool IsFlipped() const
Definition: footprint.h:326
PADS & Pads()
Definition: footprint.h:172
void Flip(const VECTOR2I &aCentre, bool aFlipLeftRight) override
Flip this object, i.e.
Definition: footprint.cpp:1596
const wxString & GetReference() const
Definition: footprint.h:521
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:536
Definition: pad.h:59
DISPLAY_OPTIONS m_Display
bool m_ShowCourtyardCollisions
static TOOL_ACTION toggleHV45Mode
Definition: pcb_actions.h:467
static TOOL_ACTION mirrorH
Mirroring of selected items.
Definition: pcb_actions.h:129
static TOOL_ACTION hideLocalRatsnest
Definition: pcb_actions.h:509
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:510
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:216
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:201
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:189
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:81
bool IsDblClick(int aButtonMask=BUT_ANY) const
Definition: tool_event.cpp:195
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
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: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:106
@ 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:587
VECTOR2< int > VECTOR2I
Definition: vector2d.h:588