KiCad PCB EDA Suite
Loading...
Searching...
No Matches
ee_selection_tool.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) 2019 CERN
5 * Copyright (C) 2019-2023 KiCad Developers, see AUTHORS.txt for contributors.
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, you may find one here:
19 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
20 * or you may search the http://www.gnu.org website for the version 2 license,
21 * or you may write to the Free Software Foundation, Inc.,
22 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
23 */
24
25#include <core/typeinfo.h>
26#include <core/kicad_algo.h>
28#include <ee_actions.h>
29#include <ee_collectors.h>
30#include <ee_selection_tool.h>
31#include <eeschema_id.h>
32#include <symbol_edit_frame.h>
33#include <lib_item.h>
34#include <symbol_viewer_frame.h>
35#include <math/util.h>
36#include <geometry/shape_rect.h>
37#include <menus_helpers.h>
38#include <sch_painter.h>
40#include <sch_base_frame.h>
41#include <sch_symbol.h>
42#include <sch_field.h>
43#include <sch_edit_frame.h>
44#include <sch_item.h>
45#include <sch_line.h>
46#include <sch_bus_entry.h>
47#include <sch_junction.h>
48#include <sch_marker.h>
49#include <sch_sheet.h>
50#include <sch_sheet_pin.h>
51#include <lib_shape.h>
52#include <schematic.h>
53#include <tool/tool_event.h>
54#include <tool/tool_manager.h>
59#include <trigo.h>
60#include <view/view.h>
61#include <view/view_controls.h>
62#include <wx/log.h>
63
64
66{
67 if( aSel.GetSize() == 1 )
68 {
69 SCH_SYMBOL* symbol = dynamic_cast<SCH_SYMBOL*>( aSel.Front() );
70
71 if( symbol )
72 return !symbol->GetLibSymbolRef() || !symbol->GetLibSymbolRef()->IsPower();
73 }
74
75 return false;
76};
77
78
80{
81 return aSel.GetSize() == 1 && aSel.Front()->Type() == SCH_SYMBOL_T;
82};
83
84
86{
87 if( aSel.GetSize() == 1 )
88 {
89 SCH_SYMBOL* symbol = dynamic_cast<SCH_SYMBOL*>( aSel.Front() );
90
91 if( symbol )
92 return symbol->GetLibSymbolRef() && symbol->GetLibSymbolRef()->HasConversion();
93 }
94
95 return false;
96};
97
98
100{
101 if( aSel.GetSize() == 1 )
102 {
103 SCH_SYMBOL* symbol = dynamic_cast<SCH_SYMBOL*>( aSel.Front() );
104
105 if( symbol )
106 return symbol->GetLibSymbolRef() && symbol->GetLibSymbolRef()->GetUnitCount() >= 2;
107 }
108
109 return false;
110};
111
112
114{
115 if( aSel.CountType( SCH_MARKER_T ) != 1 )
116 return false;
117
118 return !static_cast<SCH_MARKER*>( aSel.Front() )->IsExcluded();
119};
120
121
123{
124 return aSel.GetSize() > 1 && aSel.OnlyContains( { SCH_SYMBOL_T } );
125};
126
127
128#define HITTEST_THRESHOLD_PIXELS 5
129
130
132 SELECTION_TOOL( "eeschema.InteractiveSelection" ),
133 m_frame( nullptr ),
134 m_nonModifiedCursor( KICURSOR::ARROW ),
135 m_isSymbolEditor( false ),
136 m_isSymbolViewer( false ),
137 m_unit( 0 ),
138 m_convert( 0 )
139{
141}
142
143
145{
147}
148
149
151
152
153static std::vector<KICAD_T> connectedTypes =
154{
156 SCH_PIN_T,
167};
168
169
171{
172 m_frame = getEditFrame<SCH_BASE_FRAME>();
173
174 SYMBOL_VIEWER_FRAME* symbolViewerFrame = dynamic_cast<SYMBOL_VIEWER_FRAME*>( m_frame );
175 SYMBOL_EDIT_FRAME* symbolEditorFrame = dynamic_cast<SYMBOL_EDIT_FRAME*>( m_frame );
176
177 if( symbolEditorFrame )
178 {
179 m_isSymbolEditor = true;
180 m_unit = symbolEditorFrame->GetUnit();
181 m_convert = symbolEditorFrame->GetConvert();
182 }
183 else
184 {
185 m_isSymbolViewer = symbolViewerFrame != nullptr;
186 }
187
190 auto wireOrBusSelection = E_C::Count( 1 ) && E_C::OnlyTypes( { SCH_ITEM_LOCATE_WIRE_T, SCH_ITEM_LOCATE_BUS_T } );
191 auto connectedSelection = E_C::Count( 1 ) && E_C::OnlyTypes( connectedTypes );
192 auto sheetSelection = E_C::Count( 1 ) && E_C::OnlyTypes( { SCH_SHEET_T } );
193 auto crossProbingSelection = E_C::MoreThan( 0 ) && E_C::HasTypes( { SCH_SYMBOL_T, SCH_PIN_T, SCH_SHEET_T } );
194
195 auto schEditSheetPageNumberCondition =
196 [&] ( const SELECTION& aSel )
197 {
199 return false;
200
201 return E_C::LessThan( 2 )( aSel ) && E_C::OnlyTypes( { SCH_SHEET_T } )( aSel );
202 };
203
204 auto schEditCondition =
205 [this] ( const SELECTION& aSel )
206 {
208 };
209
210 auto belowRootSheetCondition =
211 [&]( const SELECTION& aSel )
212 {
213 SCH_EDIT_FRAME* editFrame = dynamic_cast<SCH_EDIT_FRAME*>( m_frame );
214
215 return editFrame
216 && editFrame->GetCurrentSheet().Last() != &editFrame->Schematic().Root();
217 };
218
219 auto haveHighlight =
220 [&]( const SELECTION& sel )
221 {
222 SCH_EDIT_FRAME* editFrame = dynamic_cast<SCH_EDIT_FRAME*>( m_frame );
223
224 return editFrame && !editFrame->GetHighlightedConnection().IsEmpty();
225 };
226
227 auto haveSymbol =
228 [&]( const SELECTION& sel )
229 {
230 return m_isSymbolEditor &&
231 static_cast<SYMBOL_EDIT_FRAME*>( m_frame )->GetCurSymbol();
232 };
233
234 auto symbolDisplayNameIsEditable =
235 [&]( const SELECTION& sel )
236 {
237 if ( !m_isSymbolEditor )
238 return false;
239
240 SYMBOL_EDIT_FRAME* symbEditorFrame = dynamic_cast<SYMBOL_EDIT_FRAME*>( m_frame );
241
242 return symbEditorFrame
243 && symbEditorFrame->GetCurSymbol()
244 && symbEditorFrame->GetCurSymbol()->IsMulti()
245 && symbEditorFrame->IsSymbolEditable()
246 && !symbEditorFrame->IsSymbolAlias();
247 };
248
249 auto& menu = m_menu.GetMenu();
250
251 menu.AddItem( EE_ACTIONS::clearHighlight, haveHighlight && EE_CONDITIONS::Idle, 1 );
252 menu.AddSeparator( haveHighlight && EE_CONDITIONS::Idle, 1 );
253
254 menu.AddItem( EE_ACTIONS::enterSheet, sheetSelection && EE_CONDITIONS::Idle, 2 );
255 menu.AddItem( EE_ACTIONS::selectOnPCB, crossProbingSelection && EE_CONDITIONS::Idle, 2 );
256 menu.AddItem( EE_ACTIONS::leaveSheet, belowRootSheetCondition, 2 );
257
258 menu.AddSeparator( 100 );
259 menu.AddItem( EE_ACTIONS::drawWire, schEditCondition && EE_CONDITIONS::Empty, 100 );
260 menu.AddItem( EE_ACTIONS::drawBus, schEditCondition && EE_CONDITIONS::Empty, 100 );
261
262 menu.AddSeparator( 100 );
264
265 menu.AddSeparator( 100 );
267
268 menu.AddSeparator( 200 );
269 menu.AddItem( EE_ACTIONS::selectConnection, connectedSelection && EE_CONDITIONS::Idle, 250 );
270 menu.AddItem( EE_ACTIONS::placeJunction, wireOrBusSelection && EE_CONDITIONS::Idle, 250 );
271 menu.AddItem( EE_ACTIONS::placeLabel, wireOrBusSelection && EE_CONDITIONS::Idle, 250 );
272 menu.AddItem( EE_ACTIONS::placeClassLabel, wireOrBusSelection && EE_CONDITIONS::Idle, 250 );
273 menu.AddItem( EE_ACTIONS::placeGlobalLabel, wireOrBusSelection && EE_CONDITIONS::Idle, 250 );
274 menu.AddItem( EE_ACTIONS::placeHierLabel, wireOrBusSelection && EE_CONDITIONS::Idle, 250 );
275 menu.AddItem( EE_ACTIONS::breakWire, linesSelection && EE_CONDITIONS::Idle, 250 );
276 menu.AddItem( EE_ACTIONS::slice, linesSelection && EE_CONDITIONS::Idle, 250 );
277 menu.AddItem( EE_ACTIONS::importSheetPin, sheetSelection && EE_CONDITIONS::Idle, 250 );
278 menu.AddItem( EE_ACTIONS::assignNetclass, connectedSelection && EE_CONDITIONS::Idle, 250 );
279 menu.AddItem( EE_ACTIONS::editPageNumber, schEditSheetPageNumberCondition, 250 );
280
281 menu.AddSeparator( 400 );
282 menu.AddItem( EE_ACTIONS::symbolProperties, haveSymbol && EE_CONDITIONS::Empty, 400 );
283 menu.AddItem( EE_ACTIONS::pinTable, haveSymbol && EE_CONDITIONS::Empty, 400 );
284 menu.AddItem( EE_ACTIONS::setUnitDisplayName,
285 haveSymbol && symbolDisplayNameIsEditable && EE_CONDITIONS::Empty, 400 );
286
287 menu.AddSeparator( 1000 );
289
290 m_disambiguateTimer.SetOwner( this );
291 Connect( wxEVT_TIMER, wxTimerEventHandler( EE_SELECTION_TOOL::onDisambiguationExpire ), nullptr, this );
292
293 return true;
294}
295
296
298{
299 m_frame = getEditFrame<SCH_BASE_FRAME>();
300
301 if( aReason != TOOL_BASE::REDRAW )
302 {
303 // Remove pointers to the selected items from containers without changing their
304 // properties (as they are already deleted while a new sheet is loaded)
306 }
307
308 if( aReason == TOOL_BASE::MODEL_RELOAD || aReason == TOOL_BASE::SUPERMODEL_RELOAD )
309 {
310 getView()->GetPainter()->GetSettings()->SetHighlight( false );
311
312 SYMBOL_EDIT_FRAME* symbolEditFrame = dynamic_cast<SYMBOL_EDIT_FRAME*>( m_frame );
313 SYMBOL_VIEWER_FRAME* symbolViewerFrame = dynamic_cast<SYMBOL_VIEWER_FRAME*>( m_frame );
314
315 if( symbolEditFrame )
316 {
317 m_isSymbolEditor = true;
318 m_unit = symbolEditFrame->GetUnit();
319 m_convert = symbolEditFrame->GetConvert();
320 }
321 else
322 {
323 m_isSymbolViewer = symbolViewerFrame != nullptr;
324 }
325 }
326
327 // Reinsert the VIEW_GROUP, in case it was removed from the VIEW
329 getView()->Add( &m_selection );
330}
331
332
334{
335 m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::ARROW );
336
337 KIID lastRolloverItem = niluuid;
339
340 // Main loop: keep receiving events
341 while( TOOL_EVENT* evt = Wait() )
342 {
343 bool selCancelled = false;
344 bool displayWireCursor = false;
345 bool displayBusCursor = false;
346 bool displayLineCursor = false;
347 KIID rolloverItem = lastRolloverItem;
348
349 // on left click, a selection is made, depending on modifiers ALT, SHIFT, CTRL:
350 setModifiersState( evt->Modifier( MD_SHIFT ), evt->Modifier( MD_CTRL ),
351 evt->Modifier( MD_ALT ) );
352
353 MOUSE_DRAG_ACTION drag_action = m_frame->GetDragAction();
354
355 if( evt->IsMouseDown( BUT_LEFT ) )
356 {
357 if( !m_frame->ToolStackIsEmpty() )
358 {
359 // Avoid triggering when running under other tools
360 }
363 {
364 // Distinguish point editor from selection modification by checking modifiers
365 if( hasModifier() )
366 {
368 m_disambiguateTimer.StartOnce( 500 );
369 }
370 }
371 else
372 {
374 m_disambiguateTimer.StartOnce( 500 );
375 }
376 }
377 // Single click? Select single object
378 else if( evt->IsClick( BUT_LEFT ) )
379 {
380 // If the timer has stopped, then we have already run the disambiguate routine
381 // and we don't want to register an extra click here
382 if( !m_disambiguateTimer.IsRunning() )
383 {
384 evt->SetPassEvent();
385 continue;
386 }
387
388 m_disambiguateTimer.Stop();
389
390 if( SCH_EDIT_FRAME* schframe = dynamic_cast<SCH_EDIT_FRAME*>( m_frame ) )
391 schframe->FocusOnItem( nullptr );
392
393 // Collect items at the clicked location (doesn't select them yet)
394 EE_COLLECTOR collector;
395 CollectHits( collector, evt->Position() );
396 narrowSelection( collector, evt->Position(), false );
397
398 if( collector.GetCount() == 1 && !m_isSymbolEditor && !hasModifier() )
399 {
400 OPT_TOOL_EVENT autostart = autostartEvent( evt, grid, collector[0] );
401
402 if( autostart )
403 {
405
406 params->layer = autostart->Parameter<DRAW_SEGMENT_EVENT_PARAMS*>()->layer;
407 params->quitOnDraw = true;
408 params->sourceSegment = dynamic_cast<SCH_LINE*>( collector[0] );
409
410 autostart->SetParameter( params );
411 m_toolMgr->ProcessEvent( *autostart );
412
413 selCancelled = true;
414 }
415 else if( collector[0]->IsHypertext() )
416 {
417 collector[ 0 ]->DoHypertextAction( m_frame );
418 selCancelled = true;
419 }
420 }
421
422 if( !selCancelled )
423 {
424 selectPoint( collector, evt->Position(), nullptr, nullptr, m_additive,
426 m_selection.SetIsHover( false );
427 }
428 }
429 else if( evt->IsClick( BUT_RIGHT ) )
430 {
431 m_disambiguateTimer.Stop();
432
433 // right click? if there is any object - show the context menu
434 if( m_selection.Empty() )
435 {
437 SelectPoint( evt->Position(), { SCH_LOCATE_ANY_T }, nullptr, &selCancelled );
438 m_selection.SetIsHover( true );
439 }
440 // If the cursor has moved off the bounding box of the selection by more than
441 // a grid square, check to see if there is another item available for selection
442 // under the cursor. If there is, the user likely meant to get the context menu
443 // for that item. If there is no new item, then keep the original selection and
444 // show the context menu for it.
445 else if( !m_selection.GetBoundingBox().Inflate( grid.GetGrid().x, grid.GetGrid().y )
446 .Contains( evt->Position() ) )
447 {
448 EE_COLLECTOR collector;
449
450 if( CollectHits( collector, evt->Position(), { SCH_LOCATE_ANY_T } ) )
451 {
453
454 SelectPoint( evt->Position(), { SCH_LOCATE_ANY_T }, nullptr, &selCancelled );
455 m_selection.SetIsHover( true );
456 }
457 }
458
459 if( !selCancelled )
461 }
462 else if( evt->IsDblClick( BUT_LEFT ) )
463 {
464 m_disambiguateTimer.Stop();
465
466 // double click? Display the properties window
467 if( SCH_EDIT_FRAME* schframe = dynamic_cast<SCH_EDIT_FRAME*>( m_frame ) )
468 schframe->FocusOnItem( nullptr );
469
470 if( m_selection.Empty() )
471 SelectPoint( evt->Position() );
472
473 EDA_ITEM* item = m_selection.Front();
474
475 if( item && item->Type() == SCH_SHEET_T )
477 else
479 }
480 else if( evt->IsDblClick( BUT_MIDDLE ) )
481 {
482 m_disambiguateTimer.Stop();
483
484 // Middle double click? Do zoom to fit or zoom to objects
485 if( evt->Modifier( MD_CTRL ) ) // Is CTRL key down?
487 else
489 }
490 else if( evt->IsDrag( BUT_LEFT ) )
491 {
492 m_disambiguateTimer.Stop();
493
494 // Is another tool already moving a new object? Don't allow a drag start
495 if( !m_selection.Empty() && m_selection[0]->HasFlag( IS_NEW | IS_MOVING ) )
496 {
497 evt->SetPassEvent();
498 continue;
499 }
500
501 // drag with LMB? Select multiple objects (or at least draw a selection box) or
502 // drag them
503 if( SCH_EDIT_FRAME* schframe = dynamic_cast<SCH_EDIT_FRAME*>( m_frame ) )
504 schframe->FocusOnItem( nullptr );
505
506 if( hasModifier() || drag_action == MOUSE_DRAG_ACTION::SELECT )
507 {
509 }
510 else if( m_selection.Empty() && drag_action != MOUSE_DRAG_ACTION::DRAG_ANY )
511 {
513 }
514 else
515 {
516 if( m_isSymbolEditor )
517 {
518 if( static_cast<SYMBOL_EDIT_FRAME*>( m_frame )->IsSymbolAlias() )
519 {
521 }
522 else
523 {
527 LIB_PIN_T,
528 LIB_FIELD_T } );
529 }
530 }
531 else
532 {
534 }
535
536 // Check if dragging has started within any of selected items bounding box
537 if( selectionContains( evt->DragOrigin() ) )
538 {
539 // Yes -> run the move tool and wait till it finishes
540 if( m_isSymbolEditor )
541 m_toolMgr->InvokeTool( "eeschema.SymbolMoveTool" );
542 else
543 m_toolMgr->InvokeTool( "eeschema.InteractiveMove" );
544 }
545 else
546 {
547 // No -> drag a selection box
549 }
550 }
551 }
552 else if( evt->IsMouseDown( BUT_AUX1 ) )
553 {
555 }
556 else if( evt->IsMouseDown( BUT_AUX2 ) )
557 {
559 }
560 else if( evt->Category() == TC_COMMAND && evt->Action() == TA_CHOICE_MENU_CHOICE )
561 {
562 m_disambiguateTimer.Stop();
563
564 // context sub-menu selection? Handle unit selection or bus unfolding
565 if( *evt->GetCommandId() >= ID_POPUP_SCH_SELECT_UNIT_CMP
566 && *evt->GetCommandId() <= ID_POPUP_SCH_SELECT_UNIT_SYM_MAX )
567 {
568 SCH_SYMBOL* symbol = dynamic_cast<SCH_SYMBOL*>( m_selection.Front() );
569 int unit = *evt->GetCommandId() - ID_POPUP_SCH_SELECT_UNIT_CMP;
570
571 if( symbol )
572 static_cast<SCH_EDIT_FRAME*>( m_frame )->SelectUnit( symbol, unit );
573 }
574 else if( *evt->GetCommandId() >= ID_POPUP_SCH_UNFOLD_BUS
575 && *evt->GetCommandId() <= ID_POPUP_SCH_UNFOLD_BUS_END )
576 {
577 wxString* net = new wxString( *evt->Parameter<wxString*>() );
579 }
580 }
581 else if( evt->IsCancelInteractive() )
582 {
583 m_disambiguateTimer.Stop();
584
585 // We didn't set these, but we have reports that they leak out of some other tools,
586 // so we clear them here.
587 getViewControls()->SetAutoPan( false );
588 getViewControls()->CaptureCursor( false );
589
590 if( SCH_EDIT_FRAME* schframe = dynamic_cast<SCH_EDIT_FRAME*>( m_frame ) )
591 schframe->FocusOnItem( nullptr );
592
593 if( !GetSelection().Empty() )
594 {
596 }
597 else if( evt->FirstResponder() == this && evt->GetCommandId() == (int) WXK_ESCAPE )
598 {
600
602 editor->ClearHighlight( *evt );
603 }
604 }
605 else if( evt->Action() == TA_UNDO_REDO_PRE )
606 {
607 if( SCH_EDIT_FRAME* schframe = dynamic_cast<SCH_EDIT_FRAME*>( m_frame ) )
608 schframe->FocusOnItem( nullptr );
609
611 }
612 else if( evt->IsMotion() && !m_isSymbolEditor && evt->FirstResponder() == this )
613 {
614 // Update cursor and rollover item
615 rolloverItem = niluuid;
616 EE_COLLECTOR collector;
617
619
620 if( CollectHits( collector, evt->Position() ) )
621 {
622 narrowSelection( collector, evt->Position(), false );
623
624 if( collector.GetCount() == 1 && !hasModifier() )
625 {
626 OPT_TOOL_EVENT autostartEvt = autostartEvent( evt, grid, collector[0] );
627
628 if( autostartEvt )
629 {
630 if( autostartEvt->Matches( EE_ACTIONS::drawBus.MakeEvent() ) )
631 displayBusCursor = true;
632 else if( autostartEvt->Matches( EE_ACTIONS::drawWire.MakeEvent() ) )
633 displayWireCursor = true;
634 else if( autostartEvt->Matches( EE_ACTIONS::drawLines.MakeEvent() ) )
635 displayLineCursor = true;
636 }
637 else if( collector[0]->IsHypertext() && !collector[0]->IsSelected() )
638 {
639 rolloverItem = collector[0]->m_Uuid;
640 }
641 }
642 }
643 }
644 else
645 {
646 evt->SetPassEvent();
647 }
648
649 if( rolloverItem != lastRolloverItem )
650 {
651 if( EDA_ITEM* item = m_frame->GetItem( lastRolloverItem ) )
652 {
653 item->ClearFlags( IS_ROLLOVER );
654 lastRolloverItem = niluuid;
655
656 if( item->Type() == SCH_FIELD_T )
657 m_frame->GetCanvas()->GetView()->Update( item->GetParent() );
658 else
659 m_frame->GetCanvas()->GetView()->Update( item );
660 }
661 }
662
663 if( EDA_ITEM* item = m_frame->GetItem( rolloverItem ) )
664 {
665 if( !( item->GetFlags() & IS_ROLLOVER ) )
666 {
667 item->SetFlags( IS_ROLLOVER );
668 lastRolloverItem = rolloverItem;
669
670 if( item->Type() == SCH_FIELD_T )
671 m_frame->GetCanvas()->GetView()->Update( item->GetParent() );
672 else
673 m_frame->GetCanvas()->GetView()->Update( item );
674 }
675 }
676
678 {
679 if( displayWireCursor )
680 {
681 m_nonModifiedCursor = KICURSOR::LINE_WIRE_ADD;
682 }
683 else if( displayBusCursor )
684 {
685 m_nonModifiedCursor = KICURSOR::LINE_BUS;
686 }
687 else if( displayLineCursor )
688 {
689 m_nonModifiedCursor = KICURSOR::LINE_GRAPHIC;
690 }
691 else if( rolloverItem != niluuid )
692 {
693 m_nonModifiedCursor = KICURSOR::HAND;
694 }
695 else if( !m_selection.Empty()
696 && drag_action == MOUSE_DRAG_ACTION::DRAG_SELECTED
697 && evt->HasPosition()
698 && selectionContains( evt->Position() ) ) //move/drag option prediction
699 {
700 m_nonModifiedCursor = KICURSOR::MOVING;
701 }
702 else
703 {
704 m_nonModifiedCursor = KICURSOR::ARROW;
705 }
706 }
707 }
708
709 m_disambiguateTimer.Stop();
710
711 // Shutting down; clear the selection
713
714 return 0;
715}
716
717
719 SCH_ITEM* aItem )
720{
721 VECTOR2I pos = aGrid.BestSnapAnchor( aEvent->Position(), LAYER_CONNECTABLE );
722
725 && aItem->IsPointClickableAnchor( pos ) )
726 {
728
729 if( aItem->Type() == SCH_BUS_BUS_ENTRY_T )
730 {
732 }
733 else if( aItem->Type() == SCH_BUS_WIRE_ENTRY_T )
734 {
735 SCH_BUS_WIRE_ENTRY* busEntry = static_cast<SCH_BUS_WIRE_ENTRY*>( aItem );
736
737 if( !busEntry->m_connected_bus_item )
739 }
740 else if( aItem->Type() == SCH_LINE_T )
741 {
742 SCH_LINE* line = static_cast<SCH_LINE*>( aItem );
743
744 if( line->IsBus() )
745 newEvt = EE_ACTIONS::drawBus.MakeEvent();
746 else if( line->IsGraphicLine() )
747 newEvt = EE_ACTIONS::drawLines.MakeEvent();
748 }
749 else if( aItem->Type() == SCH_LABEL_T || aItem->Type() == SCH_HIER_LABEL_T
750 || aItem->Type() == SCH_SHEET_PIN_T )
751 {
752 SCH_LABEL_BASE* label = static_cast<SCH_LABEL_BASE*>( aItem );
753 SCH_CONNECTION possibleConnection( label->Schematic()->ConnectionGraph() );
754 possibleConnection.ConfigureFromLabel( label->GetText() );
755
756 if( possibleConnection.IsBus() )
758 }
759
760 newEvt->SetMousePosition( pos );
761 newEvt->SetHasPosition( true );
762 newEvt->SetForceImmediate( true );
763
764 getViewControls()->ForceCursorPosition( true, pos );
765
766 return newEvt;
767 }
768
769 return OPT_TOOL_EVENT();
770}
771
772
774{
775 wxMouseState keyboardState = wxGetMouseState();
776
777 setModifiersState( keyboardState.ShiftDown(), keyboardState.ControlDown(),
778 keyboardState.AltDown() );
779
780 m_skip_heuristics = true;
783 m_skip_heuristics = false;
784
785 return 0;
786}
787
788
789void EE_SELECTION_TOOL::OnIdle( wxIdleEvent& aEvent )
790{
792 {
793 wxMouseState keyboardState = wxGetMouseState();
794
795 setModifiersState( keyboardState.ShiftDown(), keyboardState.ControlDown(),
796 keyboardState.AltDown() );
797
798 if( m_additive )
799 m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::ADD );
800 else if( m_subtractive )
801 m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::SUBTRACT );
802 else if( m_exclusive_or )
803 m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::XOR );
804 else
806 }
807}
808
809
811{
812 return m_selection;
813}
814
815
816bool EE_SELECTION_TOOL::CollectHits( EE_COLLECTOR& aCollector, const VECTOR2I& aWhere,
817 const std::vector<KICAD_T>& aScanTypes )
818{
819 int pixelThreshold = KiROUND( getView()->ToWorld( HITTEST_THRESHOLD_PIXELS ) );
820 int gridThreshold = KiROUND( getView()->GetGAL()->GetGridSize().EuclideanNorm() / 2 );
821 aCollector.m_Threshold = std::max( pixelThreshold, gridThreshold );
823
824 if( m_isSymbolEditor )
825 {
826 LIB_SYMBOL* symbol = static_cast<SYMBOL_EDIT_FRAME*>( m_frame )->GetCurSymbol();
827
828 if( !symbol )
829 return false;
830
831 aCollector.Collect( symbol->GetDrawItems(), aScanTypes, aWhere, m_unit, m_convert );
832 }
833 else
834 {
835 aCollector.Collect( m_frame->GetScreen(), aScanTypes, aWhere, m_unit, m_convert );
836
838 {
839 int originalCount = aCollector.GetCount();
840
841 for( int ii = 0; ii < originalCount; ++ii )
842 {
843 if( aCollector[ii]->Type() == SCH_PIN_T )
844 {
845 SCH_PIN* pin = static_cast<SCH_PIN*>( aCollector[ii] );
846
847 if( !aCollector.HasItem( pin->GetParentSymbol() ) )
848 aCollector.Append( pin->GetParentSymbol() );
849 }
850 }
851 }
852 }
853
854 return aCollector.GetCount() > 0;
855}
856
857
859 bool aCheckLocked, bool aSelectedOnly )
860{
861 for( int i = collector.GetCount() - 1; i >= 0; --i )
862 {
863 if( !Selectable( collector[i], &aWhere ) )
864 {
865 collector.Remove( i );
866 continue;
867 }
868
869 if( aCheckLocked && collector[i]->IsLocked() )
870 {
871 collector.Remove( i );
872 continue;
873 }
874
875 if( aSelectedOnly && !collector[i]->IsSelected() )
876 {
877 collector.Remove( i );
878 continue;
879 }
880 }
881
882 // Apply some ugly heuristics to avoid disambiguation menus whenever possible
883 if( collector.GetCount() > 1 && !m_skip_heuristics )
884 GuessSelectionCandidates( collector, aWhere );
885}
886
887
888bool EE_SELECTION_TOOL::selectPoint( EE_COLLECTOR& aCollector, const VECTOR2I& aWhere,
889 EDA_ITEM** aItem, bool* aSelectionCancelledFlag, bool aAdd,
890 bool aSubtract, bool aExclusiveOr )
891{
893
894 // If still more than one item we're going to have to ask the user.
895 if( aCollector.GetCount() > 1 )
896 {
897 // Try to call selectionMenu via RunAction() to avoid event-loop contention
898 // But it we cannot handle the event, then we don't have an active tool loop, so
899 // handle it directly.
900 if( !m_toolMgr->RunAction( EE_ACTIONS::selectionMenu, true, &aCollector ) )
901 {
902 if( !doSelectionMenu( &aCollector ) )
903 aCollector.m_MenuCancelled = true;
904 }
905
906 if( aCollector.m_MenuCancelled )
907 {
908 if( aSelectionCancelledFlag )
909 *aSelectionCancelledFlag = true;
910
911 return false;
912 }
913 }
914
915 if( !aAdd && !aSubtract && !aExclusiveOr )
917
918 int addedCount = 0;
919 bool anySubtracted = false;
920
921 if( aCollector.GetCount() > 0 )
922 {
923 for( int i = 0; i < aCollector.GetCount(); ++i )
924 {
925 EDA_ITEM_FLAGS flags = 0;
926 bool isLine = aCollector[i]->Type() == SCH_LINE_T;
927
928 // Handle line ends specially
929 if( isLine )
930 {
931 SCH_LINE* line = (SCH_LINE*) aCollector[i];
932
933 if( HitTestPoints( line->GetStartPoint(), aWhere, aCollector.m_Threshold ) )
934 flags = STARTPOINT;
935 else if( HitTestPoints( line->GetEndPoint(), aWhere, aCollector.m_Threshold ) )
936 flags = ENDPOINT;
937 else
938 flags = STARTPOINT | ENDPOINT;
939 }
940
941 if( aSubtract
942 || ( aExclusiveOr && aCollector[i]->IsSelected()
943 && ( !isLine || ( isLine && aCollector[i]->HasFlag( flags ) ) ) ) )
944 {
945 aCollector[i]->ClearFlags( flags );
946
947 // Need to update end shadows after ctrl-click unselecting one of two selected endpoints
948 if( isLine )
949 getView()->Update( aCollector[i] );
950
951 if( !aCollector[i]->HasFlag( STARTPOINT ) && !aCollector[i]->HasFlag( ENDPOINT ) )
952 {
953 unselect( aCollector[i] );
954 anySubtracted = true;
955 }
956 }
957 else
958 {
959 aCollector[i]->SetFlags( flags );
960 select( aCollector[i] );
961 addedCount++;
962 }
963 }
964 }
965
966 if( addedCount == 1 )
967 {
969
970 if( aItem && aCollector.GetCount() == 1 )
971 *aItem = aCollector[0];
972
973 return true;
974 }
975 else if( addedCount > 1 )
976 {
978 return true;
979 }
980 else if( anySubtracted )
981 {
983 return true;
984 }
985
986 return false;
987}
988
989
991 const std::vector<KICAD_T>& aScanTypes,
992 EDA_ITEM** aItem, bool* aSelectionCancelledFlag,
993 bool aCheckLocked, bool aAdd, bool aSubtract,
994 bool aExclusiveOr )
995{
996 EE_COLLECTOR collector;
997
998 if( !CollectHits( collector, aWhere, aScanTypes ) )
999 return false;
1000
1001 narrowSelection( collector, aWhere, aCheckLocked, aSubtract );
1002
1003 return selectPoint( collector, aWhere, aItem, aSelectionCancelledFlag, aAdd, aSubtract,
1004 aExclusiveOr );
1005}
1006
1007
1009{
1010 m_multiple = true; // Multiple selection mode is active
1011 KIGFX::VIEW* view = getView();
1012
1013 // hold all visible items
1014 std::vector<KIGFX::VIEW::LAYER_ITEM_PAIR> selectedItems;
1015 std::vector<KIGFX::VIEW::LAYER_ITEM_PAIR> sheetPins;
1016
1017 // Filter the view items based on the selection box
1018 BOX2I selectionBox;
1019
1020 selectionBox.SetMaximum();
1021 view->Query( selectionBox, selectedItems ); // Get the list of selected items
1022
1023 // Sheet pins aren't in the view; add them by hand
1024 for( KIGFX::VIEW::LAYER_ITEM_PAIR& pair : selectedItems )
1025 {
1026 SCH_SHEET* sheet = dynamic_cast<SCH_SHEET*>( pair.first );
1027
1028 if( sheet )
1029 {
1030 int layer = pair.second;
1031
1032 for( SCH_SHEET_PIN* pin : sheet->GetPins() )
1033 sheetPins.emplace_back( KIGFX::VIEW::LAYER_ITEM_PAIR( pin, layer ) );
1034 }
1035 }
1036
1037 selectedItems.insert( selectedItems.end(), sheetPins.begin(), sheetPins.end() );
1038
1039 for( const std::pair<KIGFX::VIEW_ITEM*, int>& item_pair : selectedItems )
1040 {
1041 if( EDA_ITEM* item = dynamic_cast<EDA_ITEM*>( item_pair.first ) )
1042 {
1043 if( Selectable( item ) )
1044 {
1045 if( item->Type() == SCH_LINE_T )
1046 item->SetFlags( STARTPOINT | ENDPOINT );
1047
1048 select( item );
1049 }
1050 }
1051 }
1052
1053 m_multiple = false;
1054
1056
1057 return 0;
1058}
1059
1060
1062{
1063 // Prefer exact hits to sloppy ones
1064 std::set<EDA_ITEM*> exactHits;
1065
1066 for( int i = collector.GetCount() - 1; i >= 0; --i )
1067 {
1068 EDA_ITEM* item = collector[ i ];
1069 SCH_LINE* line = dynamic_cast<SCH_LINE*>( item );
1070 LIB_SHAPE* shape = dynamic_cast<LIB_SHAPE*>( item );
1071 SCH_SYMBOL* symbol = dynamic_cast<SCH_SYMBOL*>( item );
1072
1073 // Lines are hard to hit. Give them a bit more slop to still be considered "exact".
1074
1075 if( line || ( shape && shape->GetShape() == SHAPE_T::POLY )
1076 || ( shape && shape->GetShape() == SHAPE_T::ARC ) )
1077 {
1078 int pixelThreshold = KiROUND( getView()->ToWorld( 6 ) );
1079
1080 if( item->HitTest( aPos, pixelThreshold ) )
1081 exactHits.insert( item );
1082 }
1083 else if( symbol && m_frame->eeconfig()->m_Selection.select_pin_selects_symbol )
1084 {
1085 if( symbol->GetBodyAndPinsBoundingBox().Contains( aPos ) )
1086 exactHits.insert( item );
1087 }
1088 else
1089 {
1090 if( item->HitTest( aPos, 0 ) )
1091 exactHits.insert( item );
1092 }
1093 }
1094
1095 if( exactHits.size() > 0 && exactHits.size() < (unsigned) collector.GetCount() )
1096 {
1097 for( int i = collector.GetCount() - 1; i >= 0; --i )
1098 {
1099 EDA_ITEM* item = collector[ i ];
1100
1101 if( !exactHits.count( item ) )
1102 collector.Transfer( item );
1103 }
1104 }
1105
1106 // Find the closest item. (Note that at this point all hits are either exact or non-exact.)
1107 VECTOR2I pos( aPos );
1108 SEG poss( m_isSymbolEditor ? mapCoords( pos ) : pos,
1109 m_isSymbolEditor ? mapCoords( pos ) : pos );
1110 EDA_ITEM* closest = nullptr;
1111 int closestDist = INT_MAX / 2;
1112
1113 for( EDA_ITEM* item : collector )
1114 {
1115 BOX2I bbox = item->GetBoundingBox();
1116 int dist = INT_MAX / 2;
1117
1118 if( exactHits.count( item ) )
1119 {
1120 if( item->Type() == SCH_PIN_T || item->Type() == SCH_JUNCTION_T )
1121 {
1122 closest = item;
1123 break;
1124 }
1125
1126 SCH_LINE* line = dynamic_cast<SCH_LINE*>( item );
1127 EDA_TEXT* text = dynamic_cast<EDA_TEXT*>( item );
1128 SCH_SYMBOL* symbol = dynamic_cast<SCH_SYMBOL*>( item );
1129
1130 if( line )
1131 {
1132 dist = DistanceLinePoint( line->GetStartPoint(), line->GetEndPoint(), pos );
1133 }
1134 else if( text )
1135 {
1136 if( SCH_FIELD* field = dynamic_cast<SCH_FIELD*>( text ) )
1137 {
1138 if( field->GetParent() && field->GetParent()->Type() == SCH_SYMBOL_T )
1139 {
1140 symbol = static_cast<SCH_SYMBOL*>( field->GetParent() );
1141
1142 VECTOR2I relPos = pos - symbol->GetPosition();
1143 relPos = symbol->GetTransform().InverseTransform().TransformCoordinate( relPos );
1144 pos = relPos + symbol->GetPosition();
1145
1146 poss = SEG( pos, pos );
1147 }
1148 }
1149
1150 text->GetEffectiveTextShape( false )->Collide( poss, closestDist, &dist );
1151 }
1152 else if( symbol )
1153 {
1154 try
1155 {
1156 bbox = symbol->GetBodyBoundingBox();
1157 }
1158 catch( const boost::bad_pointer& exc )
1159 {
1160 // This may be overkill and could be an assertion but we are more likely to
1161 // find any boost pointer container errors this way.
1162 wxLogError( wxT( "Boost bad pointer exception '%s' occurred." ), exc.what() );
1163 }
1164
1165 SHAPE_RECT rect( bbox.GetPosition(), bbox.GetWidth(), bbox.GetHeight() );
1166
1167 if( bbox.Contains( pos ) )
1168 dist = EuclideanNorm( bbox.GetCenter() - pos );
1169 else
1170 rect.Collide( poss, closestDist, &dist );
1171 }
1172 else
1173 {
1174 dist = EuclideanNorm( bbox.GetCenter() - pos );
1175 }
1176 }
1177 else
1178 {
1179 SHAPE_RECT rect( bbox.GetPosition(), bbox.GetWidth(), bbox.GetHeight() );
1180 rect.Collide( poss, collector.m_Threshold, &dist );
1181 }
1182
1183 if( dist == closestDist )
1184 {
1185 if( item->GetParent() == closest )
1186 closest = item;
1187 }
1188 else if( dist < closestDist )
1189 {
1190 closestDist = dist;
1191 closest = item;
1192 }
1193 }
1194
1195 // Construct a tight box (1/2 height and width) around the center of the closest item.
1196 // All items which exist at least partly outside this box have sufficient other areas
1197 // for selection and can be dropped.
1198 if( closest ) // Don't try and get a tight bbox if nothing is near the mouse pointer
1199 {
1200 BOX2I tightBox = closest->GetBoundingBox();
1201 tightBox.Inflate( -tightBox.GetWidth() / 4, -tightBox.GetHeight() / 4 );
1202
1203 for( int i = collector.GetCount() - 1; i >= 0; --i )
1204 {
1205 EDA_ITEM* item = collector[i];
1206
1207 if( item == closest )
1208 continue;
1209
1210 if( !item->HitTest( tightBox, true ) )
1211 collector.Transfer( item );
1212 }
1213 }
1214}
1215
1216
1217EE_SELECTION& EE_SELECTION_TOOL::RequestSelection( const std::vector<KICAD_T>& aScanTypes )
1218{
1219 if( m_selection.Empty() )
1220 {
1221 VECTOR2D cursorPos = getViewControls()->GetCursorPosition( true );
1222
1224 SelectPoint( cursorPos, aScanTypes );
1225 m_selection.SetIsHover( true );
1227 }
1228 else // Trim an existing selection by aFilterList
1229 {
1230 bool isMoving = false;
1231 bool anyUnselected = false;
1232
1233 for( int i = (int) m_selection.GetSize() - 1; i >= 0; --i )
1234 {
1235 EDA_ITEM* item = (EDA_ITEM*) m_selection.GetItem( i );
1236 isMoving |= static_cast<SCH_ITEM*>( item )->IsMoving();
1237
1238 if( !item->IsType( aScanTypes ) )
1239 {
1240 unselect( item );
1241 anyUnselected = true;
1242 }
1243 }
1244
1245 if( anyUnselected )
1247
1248 if( !isMoving )
1250 }
1251
1252 return m_selection;
1253}
1254
1255
1257{
1258 VECTOR2I refP( 0, 0 );
1259
1260 if( m_selection.Size() > 0 )
1261 {
1262 if( m_isSymbolEditor )
1263 refP = static_cast<LIB_ITEM*>( m_selection.GetTopLeftItem() )->GetPosition();
1264 else
1265 refP = static_cast<SCH_ITEM*>( m_selection.GetTopLeftItem() )->GetPosition();
1266 }
1267
1269}
1270
1271
1272// Some navigation actions are allowed in selectMultiple
1282 &ACTIONS::zoomFitObjects, nullptr };
1283
1284
1286{
1287 bool cancelled = false; // Was the tool canceled while it was running?
1288 m_multiple = true; // Multiple selection mode is active
1289 KIGFX::VIEW* view = getView();
1290
1292 view->Add( &area );
1293
1294 while( TOOL_EVENT* evt = Wait() )
1295 {
1296 int width = area.GetEnd().x - area.GetOrigin().x;
1297 int height = area.GetEnd().y - area.GetOrigin().y;
1298
1299 /* Selection mode depends on direction of drag-selection:
1300 * Left > Right : Select objects that are fully enclosed by selection
1301 * Right > Left : Select objects that are crossed by selection
1302 */
1303 bool isGreedy = width < 0;
1304
1305 if( view->IsMirroredX() )
1306 isGreedy = !isGreedy;
1307
1308 m_frame->GetCanvas()->SetCurrentCursor( isGreedy ? KICURSOR::SELECT_LASSO
1309 : KICURSOR::SELECT_WINDOW );
1310
1311 if( evt->IsCancelInteractive() || evt->IsActivate() )
1312 {
1313 cancelled = true;
1314 break;
1315 }
1316
1317 if( evt->IsDrag( BUT_LEFT ) )
1318 {
1321
1322 // Start drawing a selection box
1323 area.SetOrigin( evt->DragOrigin() );
1324 area.SetEnd( evt->Position() );
1327 area.SetExclusiveOr( false );
1328
1329 view->SetVisible( &area, true );
1330 view->Update( &area );
1331 getViewControls()->SetAutoPan( true );
1332 }
1333
1334 if( evt->IsMouseUp( BUT_LEFT ) )
1335 {
1336 getViewControls()->SetAutoPan( false );
1337
1338 // End drawing the selection box
1339 view->SetVisible( &area, false );
1340
1341 // Fetch items from the RTree that are in our area of interest
1342 std::vector<KIGFX::VIEW::LAYER_ITEM_PAIR> nearbyViewItems;
1343 view->Query( area.ViewBBox(), nearbyViewItems );
1344
1345 // Build lists of nearby items and their children
1346 std::unordered_set<EDA_ITEM*> nearbyItems;
1347 std::vector<EDA_ITEM*> nearbyChildren;
1348 std::vector<EDA_ITEM*> flaggedItems;
1349
1350 for( KIGFX::VIEW::LAYER_ITEM_PAIR& pair : nearbyViewItems )
1351 {
1352 if( EDA_ITEM* item = dynamic_cast<EDA_ITEM*>( pair.first ) )
1353 {
1354 if( nearbyItems.insert( item ).second )
1355 {
1356 item->ClearFlags( CANDIDATE );
1357
1358 if( SCH_ITEM* sch_item = dynamic_cast<SCH_ITEM*>( item ) )
1359 {
1360 sch_item->RunOnChildren(
1361 [&]( SCH_ITEM* aChild )
1362 {
1363 // Filter pins by unit
1364 if( SCH_PIN* pin = dyn_cast<SCH_PIN*>( aChild ) )
1365 {
1366 int unit = pin->GetLibPin()->GetUnit();
1367
1368 if( unit && unit != pin->GetParentSymbol()->GetUnit() )
1369 return;
1370 }
1371
1372 nearbyChildren.push_back( aChild );
1373 } );
1374 }
1375 }
1376 }
1377 }
1378
1379 BOX2I selectionRect( area.GetOrigin(), VECTOR2I( width, height ) );
1380 selectionRect.Normalize();
1381
1382 bool anyAdded = false;
1383 bool anySubtracted = false;
1384
1385 auto selectItem =
1386 [&]( EDA_ITEM* aItem, EDA_ITEM_FLAGS flags )
1387 {
1388 if( m_subtractive || ( m_exclusive_or && aItem->IsSelected() ) )
1389 {
1390 if ( m_exclusive_or )
1391 aItem->XorFlags( flags );
1392 else
1393 aItem->ClearFlags( flags );
1394
1395 if( !aItem->HasFlag( STARTPOINT ) && !aItem->HasFlag( ENDPOINT ) )
1396 {
1397 unselect( aItem );
1398 anySubtracted = true;
1399 }
1400
1401 // We changed one line endpoint on a selected line,
1402 // update the view at least.
1403 if( flags && !anySubtracted )
1404 {
1405 getView()->Update( aItem );
1406 }
1407 }
1408 else
1409 {
1410 aItem->SetFlags( flags );
1411 select( aItem );
1412 anyAdded = true;
1413 }
1414 };
1415
1416 for( EDA_ITEM* item : nearbyItems )
1417 {
1418 bool selected = false;
1419 EDA_ITEM_FLAGS flags = 0;
1420
1422 item->SetFlags( SHOW_ELEC_TYPE );
1423
1424 if( Selectable( item ) )
1425 {
1426 if( item->Type() == SCH_LINE_T )
1427 {
1428 SCH_LINE* line = static_cast<SCH_LINE*>( item );
1429
1430 if( ( isGreedy && line->HitTest( selectionRect, false ) )
1431 || ( selectionRect.Contains( line->GetEndPoint() )
1432 && selectionRect.Contains( line->GetStartPoint() ) ) )
1433 {
1434 selected = true;
1435 flags |= STARTPOINT | ENDPOINT;
1436 }
1437 else if( !isGreedy )
1438 {
1439 if( selectionRect.Contains( line->GetStartPoint() )
1440 && line->IsStartDangling() )
1441 {
1442 selected = true;
1443 flags |= STARTPOINT;
1444 }
1445
1446 if( selectionRect.Contains( line->GetEndPoint() )
1447 && line->IsEndDangling() )
1448 {
1449 selected = true;
1450 flags |= ENDPOINT;
1451 }
1452 }
1453 }
1454 else
1455 {
1456 selected = item->HitTest( selectionRect, !isGreedy );
1457 }
1458 }
1459
1460 if( selected )
1461 {
1462 item->SetFlags( CANDIDATE );
1463 flaggedItems.push_back( item );
1464 selectItem( item, flags );
1465 }
1466
1467 item->ClearFlags( SHOW_ELEC_TYPE );
1468 }
1469
1470 for( EDA_ITEM* item : nearbyChildren )
1471 {
1473 item->SetFlags( SHOW_ELEC_TYPE );
1474
1475 if( Selectable( item )
1476 && !item->GetParent()->HasFlag( CANDIDATE )
1477 && item->HitTest( selectionRect, !isGreedy ) )
1478 {
1479 selectItem( item, 0 );
1480 }
1481
1482 item->ClearFlags( SHOW_ELEC_TYPE );
1483 }
1484
1485 for( EDA_ITEM* item : flaggedItems )
1486 item->ClearFlags( CANDIDATE );
1487
1488 m_selection.SetIsHover( false );
1489
1490 // Inform other potentially interested tools
1491 if( anyAdded )
1493
1494 if( anySubtracted )
1496
1497 break; // Stop waiting for events
1498 }
1499
1500 // Allow some actions for navigation
1501 for( int i = 0; allowedActions[i]; ++i )
1502 {
1503 if( evt->IsAction( allowedActions[i] ) )
1504 {
1505 evt->SetPassEvent();
1506 break;
1507 }
1508 }
1509 }
1510
1511 getViewControls()->SetAutoPan( false );
1512
1513 // Stop drawing the selection box
1514 view->Remove( &area );
1515 m_multiple = false; // Multiple selection mode is inactive
1516
1517 if( !cancelled )
1519
1520 return cancelled;
1521}
1522
1523
1525{
1526 EE_COLLECTOR collector;
1527
1528 //TODO(snh): Reimplement after exposing KNN interface
1529 int pixelThreshold = KiROUND( getView()->ToWorld( HITTEST_THRESHOLD_PIXELS ) );
1530 int gridThreshold = KiROUND( getView()->GetGAL()->GetGridSize().EuclideanNorm() );
1531 int thresholdMax = std::max( pixelThreshold, gridThreshold );
1532
1533 for( int threshold : { 0, thresholdMax/4, thresholdMax/2, thresholdMax } )
1534 {
1535 collector.m_Threshold = threshold;
1536 collector.Collect( m_frame->GetScreen(), connectedTypes, aPosition );
1537
1538 if( collector.GetCount() > 0 )
1539 break;
1540 }
1541
1542 return collector.GetCount() ? collector[ 0 ] : nullptr;
1543}
1544
1545
1547{
1548 VECTOR2I cursorPos = getViewControls()->GetCursorPosition( false );
1549
1550 SelectPoint( cursorPos, connectedTypes );
1551
1552 return 0;
1553}
1554
1555
1557{
1559
1560 if( m_selection.Empty() )
1561 return 0;
1562
1563 SCH_LINE* line = (SCH_LINE*) m_selection.Front();
1564 unsigned done = false;
1565
1567 std::set<SCH_ITEM*> conns = m_frame->GetScreen()->MarkConnections( line, false );
1568
1569 for( SCH_ITEM* item : conns )
1570 {
1571 if( item->IsType( { SCH_ITEM_LOCATE_WIRE_T, SCH_ITEM_LOCATE_BUS_T } )
1572 && !item->IsSelected() )
1573 {
1574 done = true;
1575 }
1576
1577 select( item );
1578 }
1579
1580 if( !done )
1581 {
1582 conns = m_frame->GetScreen()->MarkConnections( line, true );
1583
1584 for( SCH_ITEM* item : conns )
1585 select( item );
1586 }
1587
1588 if( m_selection.GetSize() > 1 )
1590
1591 return 0;
1592}
1593
1594
1596{
1598
1599 return 0;
1600}
1601
1602
1604{
1605 if( aBBox.GetWidth() == 0 )
1606 return;
1607
1608 BOX2I bbox = aBBox;
1609 bbox.Normalize();
1610
1611 VECTOR2I bbSize = bbox.Inflate( bbox.GetWidth() * 0.2f ).GetSize();
1612 VECTOR2D screenSize = getView()->GetViewport().GetSize();
1613
1614 // This code tries to come up with a zoom factor that doesn't simply zoom in
1615 // to the cross probed symbol, but instead shows a reasonable amount of the
1616 // circuit around it to provide context. This reduces or eliminates the need
1617 // to manually change the zoom because it's too close.
1618
1619 // Using the default text height as a constant to compare against, use the
1620 // height of the bounding box of visible items for a footprint to figure out
1621 // if this is a big symbol (like a processor) or a small symbol (like a resistor).
1622 // This ratio is not useful by itself as a scaling factor. It must be "bent" to
1623 // provide good scaling at varying symbol sizes. Bigger symbols need less
1624 // scaling than small ones.
1625 double currTextHeight = schIUScale.MilsToIU( DEFAULT_TEXT_SIZE );
1626
1627 double compRatio = bbSize.y / currTextHeight; // Ratio of symbol to text height
1628 double compRatioBent = 1.0;
1629
1630 // LUT to scale zoom ratio to provide reasonable schematic context. Must work
1631 // with symbols of varying sizes (e.g. 0402 package and 200 pin BGA).
1632 // "first" is used as the input and "second" as the output
1633 //
1634 // "first" = compRatio (symbol height / default text height)
1635 // "second" = Amount to scale ratio by
1636 std::vector<std::pair<double, double>> lut{ { 1.25, 16 }, // 32
1637 { 2.5, 12 }, //24
1638 { 5, 8 }, // 16
1639 { 6, 6 }, //
1640 { 10, 4 }, //8
1641 { 20, 2 }, //4
1642 { 40, 1.5 }, // 2
1643 { 100, 1 } };
1644
1645 std::vector<std::pair<double, double>>::iterator it;
1646
1647 // Large symbol default is last LUT entry (1:1).
1648 compRatioBent = lut.back().second;
1649
1650 // Use LUT to do linear interpolation of "compRatio" within "first", then
1651 // use that result to linearly interpolate "second" which gives the scaling
1652 // factor needed.
1653 if( compRatio >= lut.front().first )
1654 {
1655 for( it = lut.begin(); it < lut.end() - 1; it++ )
1656 {
1657 if( it->first <= compRatio && next( it )->first >= compRatio )
1658 {
1659 double diffx = compRatio - it->first;
1660 double diffn = next( it )->first - it->first;
1661
1662 compRatioBent = it->second + ( next( it )->second - it->second ) * diffx / diffn;
1663 break; // We have our interpolated value
1664 }
1665 }
1666 }
1667 else
1668 {
1669 compRatioBent = lut.front().second; // Small symbol default is first entry
1670 }
1671
1672 // This is similar to the original KiCad code that scaled the zoom to make sure
1673 // symbols were visible on screen. It's simply a ratio of screen size to
1674 // symbol size, and its job is to zoom in to make the component fullscreen.
1675 // Earlier in the code the symbol BBox is given a 20% margin to add some
1676 // breathing room. We compare the height of this enlarged symbol bbox to the
1677 // default text height. If a symbol will end up with the sides clipped, we
1678 // adjust later to make sure it fits on screen.
1679 screenSize.x = std::max( 10.0, screenSize.x );
1680 screenSize.y = std::max( 10.0, screenSize.y );
1681 double ratio = std::max( -1.0, fabs( bbSize.y / screenSize.y ) );
1682
1683 // Original KiCad code for how much to scale the zoom
1684 double kicadRatio =
1685 std::max( fabs( bbSize.x / screenSize.x ), fabs( bbSize.y / screenSize.y ) );
1686
1687 // If the width of the part we're probing is bigger than what the screen width
1688 // will be after the zoom, then punt and use the KiCad zoom algorithm since it
1689 // guarantees the part's width will be encompassed within the screen.
1690 if( bbSize.x > screenSize.x * ratio * compRatioBent )
1691 {
1692 // Use standard KiCad zoom for parts too wide to fit on screen/
1693 ratio = kicadRatio;
1694 compRatioBent = 1.0; // Reset so we don't modify the "KiCad" ratio
1695 wxLogTrace( "CROSS_PROBE_SCALE",
1696 "Part TOO WIDE for screen. Using normal KiCad zoom ratio: %1.5f", ratio );
1697 }
1698
1699 // Now that "compRatioBent" holds our final scaling factor we apply it to the
1700 // original fullscreen zoom ratio to arrive at the final ratio itself.
1701 ratio *= compRatioBent;
1702
1703 bool alwaysZoom = false; // DEBUG - allows us to minimize zooming or not
1704
1705 // Try not to zoom on every cross-probe; it gets very noisy
1706 if( ( ratio < 0.5 || ratio > 1.0 ) || alwaysZoom )
1707 getView()->SetScale( getView()->GetScale() / ratio );
1708}
1709
1710
1711int EE_SELECTION_TOOL::SyncSelection( std::optional<SCH_SHEET_PATH> targetSheetPath,
1712 SCH_ITEM* focusItem, std::vector<SCH_ITEM*> items )
1713{
1714 SCH_EDIT_FRAME* editFrame = dynamic_cast<SCH_EDIT_FRAME*>( m_frame );
1715
1716 if( !editFrame || m_isSymbolEditor || m_isSymbolViewer )
1717 return 0;
1718
1719 if( targetSheetPath && targetSheetPath != editFrame->Schematic().CurrentSheet() )
1720 {
1721 editFrame->Schematic().SetCurrentSheet( *targetSheetPath );
1722 editFrame->DisplayCurrentSheet();
1723 }
1724
1725 ClearSelection( items.size() > 0 ? true /*quiet mode*/ : false );
1726
1727 // Perform individual selection of each item before processing the event.
1728 for( SCH_ITEM* item : items )
1729 select( item );
1730
1732
1733 if( bbox.GetWidth() != 0 && bbox.GetHeight() != 0 )
1734 {
1736 {
1738 ZoomFitCrossProbeBBox( bbox );
1739
1740 editFrame->FocusOnItem( focusItem );
1741
1742 if( !focusItem )
1743 editFrame->FocusOnLocation( bbox.Centre() );
1744 }
1745 }
1746
1747 if( m_selection.Size() > 0 )
1749
1750 return 0;
1751}
1752
1753
1755{
1757
1758 if( m_isSymbolEditor )
1759 {
1760 LIB_SYMBOL* start = static_cast<SYMBOL_EDIT_FRAME*>( m_frame )->GetCurSymbol();
1761
1762 for( LIB_ITEM& item : start->GetDrawItems() )
1763 {
1764 if( item.IsSelected() )
1765 select( &item );
1766 }
1767 }
1768 else
1769 {
1770 for( SCH_ITEM* item : m_frame->GetScreen()->Items() )
1771 {
1772 // If the field and symbol are selected, only use the symbol
1773 if( item->IsSelected() )
1774 {
1775 select( item );
1776 }
1777 else
1778 {
1779 item->RunOnChildren(
1780 [&]( SCH_ITEM* aChild )
1781 {
1782 if( aChild->IsSelected() )
1783 select( aChild );
1784 } );
1785 }
1786 }
1787 }
1788
1790
1791 // Inform other potentially interested tools
1793}
1794
1795
1796bool EE_SELECTION_TOOL::Selectable( const EDA_ITEM* aItem, const VECTOR2I* aPos,
1797 bool checkVisibilityOnly ) const
1798{
1799 // NOTE: in the future this is where Eeschema layer/itemtype visibility will be handled
1800
1801 SYMBOL_EDIT_FRAME* symEditFrame = dynamic_cast<SYMBOL_EDIT_FRAME*>( m_frame );
1802
1803 // Do not allow selection of anything except fields when the current symbol in the symbol
1804 // editor is a derived symbol.
1805 if( symEditFrame && symEditFrame->IsSymbolAlias() && aItem->Type() != LIB_FIELD_T )
1806 return false;
1807
1808 switch( aItem->Type() )
1809 {
1810 case SCH_PIN_T:
1811 {
1812 const SCH_PIN* pin = static_cast<const SCH_PIN*>( aItem );
1813
1814 if( !pin->IsVisible() && !m_frame->GetShowAllPins() )
1815 return false;
1816
1818 {
1819 // Pin anchors have to be allowed for auto-starting wires.
1820 if( aPos )
1821 {
1823
1824 if( pin->IsPointClickableAnchor( grid.BestSnapAnchor( *aPos, LAYER_CONNECTABLE ) ) )
1825 return true;
1826 }
1827
1828 return false;
1829 }
1830
1831 break;
1832 }
1833
1836 return false;
1837
1838 break;
1839
1840 case LIB_SYMBOL_T: // In symbol_editor we do not want to select the symbol itself.
1841 return false;
1842
1843 case LIB_FIELD_T: // LIB_FIELD object can always be edited.
1844 break;
1845
1846 case LIB_SHAPE_T:
1847 case LIB_TEXT_T:
1848 case LIB_PIN_T:
1849 if( symEditFrame )
1850 {
1851 LIB_ITEM* lib_item = (LIB_ITEM*) aItem;
1852
1853 if( lib_item->GetUnit() && lib_item->GetUnit() != symEditFrame->GetUnit() )
1854 return false;
1855
1856 if( lib_item->GetConvert() && lib_item->GetConvert() != symEditFrame->GetConvert() )
1857 return false;
1858 }
1859
1860 break;
1861
1862 case SCH_MARKER_T: // Always selectable
1863 return true;
1864
1865 default: // Suppress warnings
1866 break;
1867 }
1868
1869 return true;
1870}
1871
1872
1874{
1875 if( m_selection.Empty() )
1876 return;
1877
1878 while( m_selection.GetSize() )
1880
1881 getView()->Update( &m_selection );
1882
1883 m_selection.SetIsHover( false );
1885
1886 // Inform other potentially interested tools
1887 if( !aQuietMode )
1889}
1890
1891
1893{
1894 highlight( aItem, SELECTED, &m_selection );
1895}
1896
1897
1899{
1900 unhighlight( aItem, SELECTED, &m_selection );
1901}
1902
1903
1904void EE_SELECTION_TOOL::highlight( EDA_ITEM* aItem, int aMode, SELECTION* aGroup )
1905{
1906 KICAD_T itemType = aItem->Type();
1907
1908 if( aMode == SELECTED )
1909 aItem->SetSelected();
1910 else if( aMode == BRIGHTENED )
1911 aItem->SetBrightened();
1912
1913 if( aGroup )
1914 aGroup->Add( aItem );
1915
1916 // Highlight pins and fields. (All the other symbol children are currently only
1917 // represented in the LIB_SYMBOL and will inherit the settings of the parent symbol.)
1918 if( SCH_ITEM* sch_item = dynamic_cast<SCH_ITEM*>( aItem ) )
1919 {
1920 sch_item->RunOnChildren(
1921 [&]( SCH_ITEM* aChild )
1922 {
1923 if( aMode == SELECTED )
1924 {
1925 aChild->SetSelected();
1926 getView()->Hide( aChild, true );
1927 }
1928 else if( aMode == BRIGHTENED )
1929 {
1930 aChild->SetBrightened();
1931 }
1932 } );
1933 }
1934
1935 if( aGroup && aMode != BRIGHTENED )
1936 getView()->Hide( aItem, true );
1937
1938 if( itemType == SCH_PIN_T || itemType == SCH_FIELD_T || itemType == SCH_SHEET_PIN_T )
1939 getView()->Update( aItem->GetParent(), KIGFX::REPAINT );
1940 else
1941 getView()->Update( aItem, KIGFX::REPAINT );
1942}
1943
1944
1945void EE_SELECTION_TOOL::unhighlight( EDA_ITEM* aItem, int aMode, SELECTION* aGroup )
1946{
1947 KICAD_T itemType = aItem->Type();
1948
1949 if( aMode == SELECTED )
1950 {
1951 aItem->ClearSelected();
1952 // Lines need endpoints cleared here
1953 if( aItem->Type() == SCH_LINE_T )
1954 aItem->ClearFlags( STARTPOINT | ENDPOINT );
1955
1956 if( aMode != BRIGHTENED )
1957 getView()->Hide( aItem, false );
1958 }
1959 else if( aMode == BRIGHTENED )
1960 {
1961 aItem->ClearBrightened();
1962 }
1963
1964 if( aGroup )
1965 aGroup->Remove( aItem );
1966
1967 // Unhighlight pins and fields. (All the other symbol children are currently only
1968 // represented in the LIB_SYMBOL.)
1969 if( SCH_ITEM* sch_item = dynamic_cast<SCH_ITEM*>( aItem ) )
1970 {
1971 sch_item->RunOnChildren(
1972 [&]( SCH_ITEM* aChild )
1973 {
1974 if( aMode == SELECTED )
1975 {
1976 aChild->ClearSelected();
1977 getView()->Hide( aChild, false );
1978 }
1979 else if( aMode == BRIGHTENED )
1980 {
1981 aChild->ClearBrightened();
1982 }
1983 } );
1984 }
1985
1986 if( itemType == SCH_PIN_T || itemType == SCH_FIELD_T || itemType == SCH_SHEET_PIN_T )
1987 getView()->Update( aItem->GetParent(), KIGFX::REPAINT );
1988 else
1989 getView()->Update( aItem, KIGFX::REPAINT );
1990}
1991
1992
1994{
1995 const unsigned GRIP_MARGIN = 20;
1996 double margin = getView()->ToWorld( GRIP_MARGIN );
1997
1998 // Check if the point is located within any of the currently selected items bounding boxes
1999 for( EDA_ITEM* item : m_selection )
2000 {
2001 BOX2I itemBox = item->ViewBBox();
2002 itemBox.Inflate( margin ); // Give some margin for gripping an item
2003
2004 if( itemBox.Contains( aPoint ) )
2005 return true;
2006 }
2007
2008 return false;
2009}
2010
2011
2013{
2015
2020
2026
2028
2030}
2031
2032
VECTOR2D mapCoords(const VECTOR2D &aSource)
Definition: PS_plotter.cpp:568
constexpr EDA_IU_SCALE schIUScale
Definition: base_units.h:111
static TOOL_ACTION cursorLeft
Definition: actions.h:119
static TOOL_ACTION zoomOutCenter
Definition: actions.h:97
static TOOL_ACTION zoomIn
Definition: actions.h:94
static TOOL_ACTION cursorLeftFast
Definition: actions.h:124
static TOOL_ACTION cursorDown
Definition: actions.h:118
static TOOL_ACTION zoomOut
Definition: actions.h:95
static TOOL_ACTION cursorRightFast
Definition: actions.h:125
static TOOL_ACTION zoomCenter
Definition: actions.h:98
static TOOL_ACTION panDown
Definition: actions.h:132
static TOOL_ACTION cursorDownFast
Definition: actions.h:123
static TOOL_ACTION cursorUpFast
Definition: actions.h:122
static TOOL_ACTION panLeft
Definition: actions.h:133
static TOOL_ACTION updateMenu
Definition: actions.h:172
static TOOL_ACTION zoomFitScreen
Definition: actions.h:99
static TOOL_ACTION panUp
Definition: actions.h:131
static TOOL_ACTION zoomFitObjects
Definition: actions.h:100
static TOOL_ACTION zoomInCenter
Definition: actions.h:96
static TOOL_ACTION panRight
Definition: actions.h:134
static TOOL_ACTION cursorUp
Cursor control with keyboard.
Definition: actions.h:117
static TOOL_ACTION cursorRight
Definition: actions.h:120
static TOOL_ACTION selectAll
Definition: actions.h:71
CROSS_PROBING_SETTINGS m_CrossProbing
Definition: app_settings.h:173
BOX2< Vec > & Normalize()
Ensure that the height and width are positive.
Definition: box2.h:119
const Vec & GetPosition() const
Definition: box2.h:184
void SetMaximum()
Definition: box2.h:63
const Vec GetCenter() const
Definition: box2.h:195
coord_type GetHeight() const
Definition: box2.h:188
coord_type GetWidth() const
Definition: box2.h:187
bool Contains(const Vec &aPoint) const
Definition: box2.h:141
BOX2< Vec > & Inflate(coord_type dx, coord_type dy)
Inflates the rectangle horizontally by dx and vertically by dy.
Definition: box2.h:506
Vec Centre() const
Definition: box2.h:70
const Vec & GetSize() const
Definition: box2.h:179
void Transfer(int aIndex)
Move the item at aIndex (first position is 0) to the backup list.
Definition: collector.h:151
bool m_MenuCancelled
Definition: collector.h:237
int GetCount() const
Return the number of objects in the list.
Definition: collector.h:81
bool HasItem(const EDA_ITEM *aItem) const
Tests if aItem has already been collected.
Definition: collector.h:195
void Remove(int aIndex)
Remove the item at aIndex (first position is 0).
Definition: collector.h:109
int m_Threshold
Definition: collector.h:234
void Append(EDA_ITEM *item)
Add an item to the end of the list.
Definition: collector.h:99
void AddItem(const TOOL_ACTION &aAction, const SELECTION_CONDITION &aCondition, int aOrder=ANY_ORDER)
Add a menu entry to run a TOOL_ACTION on selected items.
void AddStandardSubMenus(TOOL_MENU &aMenu)
Construct a "basic" menu for a tool, containing only items that apply to all tools (e....
void FocusOnLocation(const VECTOR2I &aPos)
Useful to focus on a particular location, in find functions.
virtual EDA_ITEM * GetItem(const KIID &aId) const
Fetch an item by KIID.
void SetCurrentCursor(KICURSOR aCursor)
Set the current cursor shape for this panel.
A base class for most all the KiCad significant classes used in schematics and boards.
Definition: eda_item.h:85
virtual const BOX2I GetBoundingBox() const
Return the orthogonal bounding box of this object for display purposes.
Definition: eda_item.cpp:73
void SetFlags(EDA_ITEM_FLAGS aMask)
Definition: eda_item.h:123
KICAD_T Type() const
Returns the type of object.
Definition: eda_item.h:97
void ClearSelected()
Definition: eda_item.h:118
void ClearFlags(EDA_ITEM_FLAGS aMask=EDA_ITEM_ALL_FLAGS)
Definition: eda_item.h:125
bool IsSelected() const
Definition: eda_item.h:106
void SetSelected()
Definition: eda_item.h:115
virtual bool IsType(const std::vector< KICAD_T > &aScanTypes) const
Check whether the item is one of the listed types.
Definition: eda_item.h:165
void ClearBrightened()
Definition: eda_item.h:119
void SetBrightened()
Definition: eda_item.h:116
virtual bool HitTest(const VECTOR2I &aPosition, int aAccuracy=0) const
Test if aPosition is inside or on the boundary of this item.
Definition: eda_item.h:205
EDA_ITEM * GetParent() const
Definition: eda_item.h:99
bool HasFlag(EDA_ITEM_FLAGS aFlag) const
Definition: eda_item.h:127
void XorFlags(EDA_ITEM_FLAGS aMask)
Definition: eda_item.h:124
SHAPE_T GetShape() const
Definition: eda_shape.h:113
A mix-in class (via multiple inheritance) that handles texts such as labels, parts,...
Definition: eda_text.h:72
virtual const wxString & GetText() const
Return the string associated with the text object.
Definition: eda_text.h:87
static TOOL_ACTION selectionActivate
Activation of the selection tool.
Definition: ee_actions.h:46
static TOOL_ACTION properties
Definition: ee_actions.h:129
static TOOL_ACTION addItemsToSel
Selects a list of items (specified as the event parameter)
Definition: ee_actions.h:63
static TOOL_ACTION clearHighlight
Definition: ee_actions.h:284
static TOOL_ACTION selectConnection
If current selection is a wire or bus, expand to entire connection.
Definition: ee_actions.h:53
static TOOL_ACTION pinTable
Definition: ee_actions.h:156
static TOOL_ACTION navigateForward
Definition: ee_actions.h:218
static TOOL_ACTION slice
Definition: ee_actions.h:145
static TOOL_ACTION assignNetclass
Definition: ee_actions.h:162
static TOOL_ACTION clearSelection
Clears the current selection.
Definition: ee_actions.h:56
static TOOL_ACTION navigateBack
Definition: ee_actions.h:219
static TOOL_ACTION selectionMenu
Runs a selection menu to select from a list of items.
Definition: ee_actions.h:67
static TOOL_ACTION placeClassLabel
Definition: ee_actions.h:88
static TOOL_ACTION drawWire
Definition: ee_actions.h:81
static TOOL_ACTION removeItemsFromSel
Definition: ee_actions.h:64
static TOOL_ACTION drawBus
Definition: ee_actions.h:82
static TOOL_ACTION finishWire
Definition: ee_actions.h:103
static TOOL_ACTION selectNode
Select the junction, wire or bus segment under the cursor.
Definition: ee_actions.h:49
static TOOL_ACTION breakWire
Definition: ee_actions.h:144
static TOOL_ACTION drawLines
Definition: ee_actions.h:98
static TOOL_ACTION importSheetPin
Definition: ee_actions.h:92
static TOOL_ACTION selectOnPCB
Definition: ee_actions.h:240
static TOOL_ACTION leaveSheet
Definition: ee_actions.h:216
static TOOL_ACTION placeGlobalLabel
Definition: ee_actions.h:89
static TOOL_ACTION removeItemFromSel
Definition: ee_actions.h:60
static TOOL_ACTION placeHierLabel
Definition: ee_actions.h:90
static TOOL_ACTION addItemToSel
Selects an item (specified as the event parameter).
Definition: ee_actions.h:59
static TOOL_ACTION symbolProperties
Definition: ee_actions.h:155
static TOOL_ACTION editPageNumber
Definition: ee_actions.h:164
static TOOL_ACTION enterSheet
Definition: ee_actions.h:215
static TOOL_ACTION setUnitDisplayName
Definition: ee_actions.h:211
static TOOL_ACTION unfoldBus
Definition: ee_actions.h:83
static TOOL_ACTION placeLabel
Definition: ee_actions.h:87
static TOOL_ACTION placeJunction
Definition: ee_actions.h:85
static TOOL_ACTION finishBus
Definition: ee_actions.h:104
bool m_ShowPinElectricalTypes
static const std::vector< KICAD_T > MovableItems
Definition: ee_collectors.h:43
void Collect(SCH_SCREEN *aScreen, const std::vector< KICAD_T > &aScanTypes, const VECTOR2I &aPos, int aUnit=0, int aConvert=0)
Scan a EDA_ITEM using this class's Inspector method which does the collection.
static SELECTION_CONDITION SingleSymbol
static SELECTION_CONDITION SingleSymbolOrPower
static SELECTION_CONDITION SingleMultiUnitSymbol
static SELECTION_CONDITION SingleNonExcludedMarker
static SELECTION_CONDITION SingleDeMorganSymbol
static SELECTION_CONDITION MultipleSymbolsOrPower
VECTOR2I BestSnapAnchor(const VECTOR2I &aOrigin, int aLayer, SCH_ITEM *aDraggedItem)
Tool that displays edit points allowing to modify items by dragging the points.
bool HasPoint()
Indicate the cursor is over an edit point.
bool Selectable(const EDA_ITEM *aItem, const VECTOR2I *aPos=nullptr, bool checkVisibilityOnly=false) const
Check conditions for an item to be selected.
void GuessSelectionCandidates(EE_COLLECTOR &collector, const VECTOR2I &aPos)
Apply heuristics to try and determine a single object when multiple are found under the cursor.
bool selectMultiple()
Handle drawing a selection box that allows one to select many items at the same time.
bool selectionContains(const VECTOR2I &aPoint) const
Set up handlers for various events.
void unhighlight(EDA_ITEM *aItem, int aHighlightMode, SELECTION *aGroup=nullptr) override
Unhighlight the item visually.
EE_SELECTION m_selection
void unselect(EDA_ITEM *aItem) override
Take necessary action to mark an item as unselected.
int SelectConnection(const TOOL_EVENT &aEvent)
If a connected item is selected then expand the selection to the entire connection,...
bool CollectHits(EE_COLLECTOR &aCollector, const VECTOR2I &aWhere, const std::vector< KICAD_T > &aScanTypes={ SCH_LOCATE_ANY_T })
Collect one or more items at a given point.
void setTransitions() override
This method is meant to be overridden in order to specify handlers for events.
bool selectPoint(EE_COLLECTOR &aCollector, const VECTOR2I &aWhere, EDA_ITEM **aItem=nullptr, bool *aSelectionCancelledFlag=nullptr, bool aAdd=false, bool aSubtract=false, bool aExclusiveOr=false)
Perform a click-type selection at a point (usually the cursor position).
int SelectAll(const TOOL_EVENT &aEvent)
EE_SELECTION & RequestSelection(const std::vector< KICAD_T > &aScanTypes={ SCH_LOCATE_ANY_T })
Return either an existing selection (filtered), or the selection at the current cursor position if th...
void ZoomFitCrossProbeBBox(const BOX2I &aBBox)
bool SelectPoint(const VECTOR2I &aWhere, const std::vector< KICAD_T > &aScanTypes={ SCH_LOCATE_ANY_T }, EDA_ITEM **aItem=nullptr, bool *aSelectionCancelledFlag=nullptr, bool aCheckLocked=false, bool aAdd=false, bool aSubtract=false, bool aExclusiveOr=false)
Perform a click-type selection at a point (usually the cursor position).
int Main(const TOOL_EVENT &aEvent)
The main loop.
int disambiguateCursor(const TOOL_EVENT &aEvent)
Handle disambiguation actions including displaying the menu.
int SelectNode(const TOOL_EVENT &aEvent)
Selects the connected item at the current cursor position.
bool Init() override
Init() is called once upon a registration of the tool.
int ClearSelection(const TOOL_EVENT &aEvent)
Select all visible items in sheet.
OPT_TOOL_EVENT autostartEvent(TOOL_EVENT *aEvent, EE_GRID_HELPER &aGrid, SCH_ITEM *aItem)
int SyncSelection(std::optional< SCH_SHEET_PATH > targetSheetPath, SCH_ITEM *focusItem, std::vector< SCH_ITEM * > items)
void RebuildSelection()
Rebuild the selection from the EDA_ITEMs' selection flags.
void OnIdle(wxIdleEvent &aEvent)
Zoom the screen to fit the bounding box for cross probing/selection sync.
SCH_BASE_FRAME * m_frame
void narrowSelection(EE_COLLECTOR &collector, const VECTOR2I &aWhere, bool aCheckLocked, bool aSelectedOnly=false)
Apply rules to narrow the collection down to selectable objects, and then heuristics to try and narro...
void highlight(EDA_ITEM *aItem, int aHighlightMode, SELECTION *aGroup=nullptr) override
Highlight the item visually.
void Reset(RESET_REASON aReason) override
Bring the tool to a known, initial state.
void select(EDA_ITEM *aItem) override
Take necessary action to mark an item as selected.
EDA_ITEM * GetNode(VECTOR2I aPosition)
Finds a connected item at a point (usually the cursor position).
EE_SELECTION & GetSelection()
void updateReferencePoint()
Set the reference point to the anchor of the top-left item.
BOX2I GetBoundingBox() const override
EDA_ITEM * GetTopLeftItem(bool onlyModules=false) const override
static const TOOL_EVENT DisambiguatePoint
Definition: actions.h:224
static const TOOL_EVENT ClearedEvent
Definition: actions.h:209
static const TOOL_EVENT SelectedEvent
Definition: actions.h:207
static const TOOL_EVENT PointSelectedEvent
Definition: actions.h:206
static const TOOL_EVENT UnselectedEvent
Definition: actions.h:208
virtual RENDER_SETTINGS * GetSettings()=0
Return a pointer to current settings that are going to be used when drawing items.
Represent a selection area (currently a rectangle) in a VIEW, drawn corner-to-corner between two poin...
void SetSubtractive(bool aSubtractive)
void SetAdditive(bool aAdditive)
void SetOrigin(const VECTOR2I &aOrigin)
const BOX2I ViewBBox() const override
Set the origin of the rectangle (the fixed corner)
void SetExclusiveOr(bool aExclusiveOr)
void SetEnd(const VECTOR2I &aEnd)
Set the current end of the rectangle (the corner that moves with the cursor.
void SetHighlight(bool aEnabled, int aNetcode=-1, bool aMulti=false)
Turns on/off highlighting.
virtual void CaptureCursor(bool aEnabled)
Force the cursor to stay within the drawing panel area.
virtual void ForceCursorPosition(bool aEnabled, const VECTOR2D &aPosition=VECTOR2D(0, 0))
Place the cursor immediately at a given point.
VECTOR2D GetCursorPosition() const
Return the current cursor position in world coordinates.
virtual void SetAutoPan(bool aEnabled)
Turn on/off auto panning (this feature is used when there is a tool active (eg.
Hold a (potentially large) number of VIEW_ITEMs and renders them on a graphics device provided by the...
Definition: view.h:69
BOX2D GetViewport() const
Return the current viewport visible area rectangle.
Definition: view.cpp:508
virtual void SetScale(double aScale, VECTOR2D aAnchor={ 0, 0 })
Set the scaling factor, zooming around a given anchor point.
Definition: view.cpp:548
virtual void Add(VIEW_ITEM *aItem, int aDrawPriority=-1)
Add a VIEW_ITEM to the view.
Definition: view.cpp:314
virtual void Remove(VIEW_ITEM *aItem)
Remove a VIEW_ITEM from the view.
Definition: view.cpp:351
virtual int Query(const BOX2I &aRect, std::vector< LAYER_ITEM_PAIR > &aResult) const
Find all visible items that touch or are within the rectangle aRect.
Definition: view.cpp:422
virtual void Update(const VIEW_ITEM *aItem, int aUpdateFlags) const
For dynamic VIEWs, inform the associated VIEW that the graphical representation of this item has chan...
Definition: view.cpp:1608
VECTOR2D ToWorld(const VECTOR2D &aCoord, bool aAbsolute=true) const
Converts a screen space point/vector to a point/vector in world space coordinates.
Definition: view.cpp:445
void Hide(VIEW_ITEM *aItem, bool aHide=true)
Temporarily hide the item in the view (e.g.
Definition: view.cpp:1567
bool IsMirroredX() const
Return true if view is flipped across the X axis.
Definition: view.h:243
std::pair< VIEW_ITEM *, int > LAYER_ITEM_PAIR
Definition: view.h:73
PAINTER * GetPainter() const
Return the painter object used by the view for drawing #VIEW_ITEMS.
Definition: view.h:213
void SetVisible(VIEW_ITEM *aItem, bool aIsVisible=true)
Set the item visibility.
Definition: view.cpp:1546
Definition: kiid.h:48
The base class for drawable items used by schematic library symbols.
Definition: lib_item.h:61
int GetUnit() const
Definition: lib_item.h:293
int GetConvert() const
Definition: lib_item.h:296
Define a library symbol object.
Definition: lib_symbol.h:99
bool IsMulti() const
Definition: lib_symbol.h:564
LIB_ITEMS_CONTAINER & GetDrawItems()
Return a reference to the draw item list.
Definition: lib_symbol.h:515
SCH_SHEET_PATH & CurrentSheet() const override
Definition: schematic.h:133
CONNECTION_GRAPH * ConnectionGraph() const override
Definition: schematic.h:143
void SetCurrentSheet(const SCH_SHEET_PATH &aPath) override
Definition: schematic.h:138
SCH_SHEET & Root() const
Definition: schematic.h:102
SCH_SCREEN * GetScreen() const override
Return a pointer to a BASE_SCREEN or one of its derivatives.
SCH_DRAW_PANEL * GetCanvas() const override
Return a pointer to GAL-based canvas of given EDA draw frame.
EESCHEMA_SETTINGS * eeconfig() const
KIGFX::SCH_RENDER_SETTINGS * GetRenderSettings()
virtual bool GetShowAllPins() const
Allow some frames to show/hide hidden pins.
Class for a wire to bus entry.
SCH_ITEM * m_connected_bus_item
Pointer to the bus item (usually a bus wire) connected to this bus-wire entry, if it is connected to ...
Each graphical item can have a SCH_CONNECTION describing its logical connection (to a bus or net).
void ConfigureFromLabel(const wxString &aLabel)
Configures the connection given a label.
bool IsBus() const
KIGFX::SCH_VIEW * GetView() const override
Return a pointer to the #VIEW instance used in the panel.
Handle actions specific to the schematic editor.
Schematic editor (Eeschema) main window.
SCH_SHEET_PATH & GetCurrentSheet() const
SCHEMATIC & Schematic() const
void DisplayCurrentSheet()
Draw the current sheet on the display.
const wxString & GetHighlightedConnection() const
void FocusOnItem(SCH_ITEM *aItem)
Instances are attached to a symbol or sheet and provide a place for the symbol's value,...
Definition: sch_field.h:51
Base class for any item which can be embedded within the SCHEMATIC container class,...
Definition: sch_item.h:147
SCHEMATIC * Schematic() const
Searches the item hierarchy to find a SCHEMATIC.
Definition: sch_item.cpp:113
virtual bool IsPointClickableAnchor(const VECTOR2I &aPos) const
Definition: sch_item.h:358
static bool IsDrawingWire(const SELECTION &aSelection)
static bool IsDrawingBus(const SELECTION &aSelection)
Segment description base class to describe items which have 2 end points (track, wire,...
Definition: sch_line.h:40
bool HitTest(const VECTOR2I &aPosition, int aAccuracy=0) const override
Test if aPosition is inside or on the boundary of this item.
Definition: sch_line.cpp:807
bool IsStartDangling() const
Definition: sch_line.h:259
VECTOR2I GetEndPoint() const
Definition: sch_line.h:143
VECTOR2I GetStartPoint() const
Definition: sch_line.h:138
bool IsEndDangling() const
Definition: sch_line.h:260
bool IsBus() const
Return true if the line is a bus.
Definition: sch_line.cpp:974
bool IsGraphicLine() const
Return if the line is a graphic (non electrical line)
Definition: sch_line.cpp:962
void ClearDrawingState()
Clear the state flags of all the items in the screen.
EE_RTREE & Items()
Gets the full RTree, usually for iterating.
Definition: sch_screen.h:109
std::set< SCH_ITEM * > MarkConnections(SCH_LINE *aSegment, bool aSecondPass)
Return all wires and junctions connected to aSegment which are not connected any symbol pin.
Definition: sch_screen.cpp:399
SCH_SHEET * Last() const
Return a pointer to the last SCH_SHEET of the list.
Define a sheet pin (label) used in sheets to create hierarchical schematics.
Definition: sch_sheet_pin.h:66
Sheet symbol placed in a schematic, and is the entry point for a sub schematic.
Definition: sch_sheet.h:57
std::vector< SCH_SHEET_PIN * > & GetPins()
Definition: sch_sheet.h:183
Schematic symbol object.
Definition: sch_symbol.h:81
VECTOR2I GetPosition() const override
Definition: sch_symbol.h:726
TRANSFORM & GetTransform()
Definition: sch_symbol.h:286
BOX2I GetBodyAndPinsBoundingBox() const
Return a bounding box for the symbol body and pins but not the fields.
std::unique_ptr< LIB_SYMBOL > & GetLibSymbolRef()
Definition: sch_symbol.h:195
BOX2I GetBodyBoundingBox() const
Return a bounding box for the symbol body but not the pins or fields.
Definition: seg.h:42
static SELECTION_CONDITION HasTypes(std::vector< KICAD_T > aTypes)
Create a functor that tests if among the selected items there is at least one of a given types.
static bool Empty(const SELECTION &aSelection)
Test if there are no items selected.
static SELECTION_CONDITION MoreThan(int aNumber)
Create a functor that tests if the number of selected items is greater than the value given as parame...
static bool Idle(const SELECTION &aSelection)
Test if there no items selected or being edited.
static SELECTION_CONDITION LessThan(int aNumber)
Create a functor that tests if the number of selected items is smaller than the value given as parame...
static SELECTION_CONDITION Count(int aNumber)
Create a functor that tests if the number of selected items is equal to the value given as parameter.
static SELECTION_CONDITION OnlyTypes(std::vector< KICAD_T > aTypes)
Create a functor that tests if the selected items are only of given types.
int RemoveItemFromSel(const TOOL_EVENT &aEvent)
bool doSelectionMenu(COLLECTOR *aCollector)
wxTimer m_disambiguateTimer
int AddItemsToSel(const TOOL_EVENT &aEvent)
int AddItemToSel(const TOOL_EVENT &aEvent)
int UpdateMenu(const TOOL_EVENT &aEvent)
Update a menu's state based on the current selection.
void setModifiersState(bool aShiftState, bool aCtrlState, bool aAltState)
Set the configuration of m_additive, m_subtractive, m_exclusive_or, m_skip_heuristics from the state ...
VECTOR2I m_originalCursor
int SelectionMenu(const TOOL_EVENT &aEvent)
Show a popup menu to trim the COLLECTOR passed as aEvent's parameter down to a single item.
int RemoveItemsFromSel(const TOOL_EVENT &aEvent)
bool hasModifier()
True if a selection modifier is enabled, false otherwise.
void onDisambiguationExpire(wxTimerEvent &aEvent)
Start the process to show our disambiguation menu once the user has kept the mouse down for the minim...
virtual void Add(EDA_ITEM *aItem)
Definition: selection.cpp:42
virtual KIGFX::VIEW_ITEM * GetItem(unsigned int aIdx) const override
Definition: selection.cpp:75
void SetIsHover(bool aIsHover)
Definition: selection.h:78
virtual void Remove(EDA_ITEM *aItem)
Definition: selection.cpp:60
virtual unsigned int GetSize() const override
Return the number of stored items.
Definition: selection.h:99
EDA_ITEM * Front() const
Definition: selection.h:208
virtual void Clear() override
Remove all the stored items from the group.
Definition: selection.h:92
int Size() const
Returns the number of selected parts.
Definition: selection.h:115
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 Collide(const SHAPE *aShape, int aClearance, VECTOR2I *aMTV) const override
Check if the boundary of shape (this) lies closer to the shape aShape than aClearance,...
Definition: shape_rect.h:109
The symbol library editor main window.
bool IsSymbolAlias() const
Return true if aLibId is an alias for the editor screen symbol.
bool IsSymbolEditable() const
Test if a symbol is loaded and can be edited.
LIB_SYMBOL * GetCurSymbol() const
Return the current symbol being edited or NULL if none selected.
Symbol library viewer main window.
MOUSE_DRAG_ACTION GetDragAction() const
Indicates whether a drag should draw a selection rectangle or drag selected (or unselected) objects.
Definition: tools_holder.h:147
bool ToolStackIsEmpty()
Definition: tools_holder.h:128
Represent a single user action.
Definition: tool_action.h:68
TOOL_EVENT MakeEvent() const
Return the event associated with the action (i.e.
Definition: tool_action.cpp:72
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
RESET_REASON
Determine the reason of reset for a tool.
Definition: tool_base.h:78
@ REDRAW
Full drawing refresh.
Definition: tool_base.h:83
@ MODEL_RELOAD
Model changes (the sheet for a schematic)
Definition: tool_base.h:80
@ SUPERMODEL_RELOAD
For schematics, the entire schematic changed, not just the sheet.
Definition: tool_base.h:81
Generic, UI-independent tool event.
Definition: tool_event.h:156
void SetMousePosition(const VECTOR2D &aP)
Definition: tool_event.h:470
const VECTOR2D Position() const
Returns the point where dragging has started.
Definition: tool_event.h:266
void Go(int(T::*aStateFunc)(const TOOL_EVENT &), const TOOL_EVENT_LIST &aConditions=TOOL_EVENT(TC_ANY, TA_ANY))
Define which state (aStateFunc) to go when a certain event arrives (aConditions).
TOOL_MENU m_menu
The functions below are not yet implemented - their interface may change.
TOOL_EVENT * Wait(const TOOL_EVENT_LIST &aEventList=TOOL_EVENT(TC_ANY, TA_ANY))
Suspend execution of the tool until an event specified in aEventList arrives.
bool ProcessEvent(const TOOL_EVENT &aEvent)
Propagate an event to tools that requested events of matching type(s).
bool RunAction(const std::string &aActionName, bool aNow=false, T aParam=NULL)
Run the specified action.
Definition: tool_manager.h:142
bool InvokeTool(TOOL_ID aToolId)
Call a tool by sending a tool activation event to tool of given ID.
VECTOR2D GetMousePosition() const
CONDITIONAL_MENU & GetMenu()
Definition: tool_menu.cpp:44
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
TRANSFORM InverseTransform() const
Calculate the Inverse mirror/rotation transform.
Definition: transform.cpp:61
VECTOR2I TransformCoordinate(const VECTOR2I &aPoint) const
Calculate a new coordinate according to the mirror/rotation transform.
Definition: transform.cpp:46
MOUSE_DRAG_ACTION
KICURSOR
Definition: cursors.h:34
#define DEFAULT_TEXT_SIZE
Ratio of the font height to the baseline of the text above the wire.
#define BRIGHTENED
item is drawn with a bright contour
#define IS_NEW
New item, just created.
#define SELECTED
Item was manually selected by the user.
#define ENDPOINT
ends. (Used to support dragging.)
std::uint32_t EDA_ITEM_FLAGS
#define CANDIDATE
flag indicating that the structure is connected
#define IS_ROLLOVER
Rollover active. Used for hyperlink highlighting.
#define IS_MOVING
Item being moved.
#define SHOW_ELEC_TYPE
Show pin electrical type. Shared with IS_ROLLOVER.
#define STARTPOINT
When a line is selected, these flags indicate which.
@ LAYER_CONNECTABLE
static std::vector< KICAD_T > connectedTypes
#define HITTEST_THRESHOLD_PIXELS
const TOOL_ACTION * allowedActions[]
@ ID_POPUP_SCH_UNFOLD_BUS_END
Definition: eeschema_id.h:91
@ ID_POPUP_SCH_SELECT_UNIT_CMP
Definition: eeschema_id.h:94
@ ID_POPUP_SCH_UNFOLD_BUS
Definition: eeschema_id.h:90
@ ID_POPUP_SCH_SELECT_UNIT_SYM_MAX
Definition: eeschema_id.h:98
KIID niluuid(0)
Macros and inline functions to create menus items in menubars or popup menus.
@ REPAINT
Item needs to be redrawn.
Definition: view_item.h:52
CITER next(CITER it)
Definition: ptree.cpp:126
std::function< bool(const SELECTION &)> SELECTION_CONDITION
< Functor type that checks a specific condition for selected items.
bool zoom_to_fit
Zoom to fit items (ignored if center_on_items is off)
Definition: app_settings.h:34
bool center_on_items
Automatically pan to cross-probed items.
Definition: app_settings.h:33
constexpr int MilsToIU(int mils) const
Definition: base_units.h:94
std::optional< TOOL_EVENT > OPT_TOOL_EVENT
Definition: tool_event.h:557
@ TA_CHOICE_MENU_CHOICE
Definition: tool_event.h:93
@ TA_UNDO_REDO_PRE
Definition: tool_event.h:101
@ TC_COMMAND
Definition: tool_event.h:52
@ MD_ALT
Definition: tool_event.h:140
@ MD_CTRL
Definition: tool_event.h:139
@ MD_SHIFT
Definition: tool_event.h:138
@ BUT_AUX1
Definition: tool_event.h:130
@ BUT_MIDDLE
Definition: tool_event.h:129
@ BUT_LEFT
Definition: tool_event.h:127
@ BUT_RIGHT
Definition: tool_event.h:128
@ BUT_AUX2
Definition: tool_event.h:131
double DistanceLinePoint(const VECTOR2I &linePointA, const VECTOR2I &linePointB, const VECTOR2I &referencePoint)
Compute the distance between a line and a reference point Reference: http://mathworld....
Definition: trigo.h:140
bool HitTestPoints(const VECTOR2I &pointA, const VECTOR2I &pointB, double threshold)
Test, if two points are near each other.
Definition: trigo.h:159
double EuclideanNorm(const VECTOR2I &vector)
Definition: trigo.h:129
KICAD_T
The set of class identification values stored in EDA_ITEM::m_structType.
Definition: typeinfo.h:78
@ SCH_LINE_T
Definition: typeinfo.h:136
@ LIB_SYMBOL_T
Definition: typeinfo.h:188
@ LIB_TEXT_T
Definition: typeinfo.h:190
@ SCH_SYMBOL_T
Definition: typeinfo.h:146
@ LIB_TEXTBOX_T
Definition: typeinfo.h:191
@ SCH_ITEM_LOCATE_WIRE_T
Definition: typeinfo.h:160
@ SCH_FIELD_T
Definition: typeinfo.h:145
@ SCH_DIRECTIVE_LABEL_T
Definition: typeinfo.h:144
@ SCH_LABEL_T
Definition: typeinfo.h:141
@ SCH_LOCATE_ANY_T
Definition: typeinfo.h:173
@ SCH_SHEET_T
Definition: typeinfo.h:148
@ SCH_ITEM_LOCATE_BUS_T
Definition: typeinfo.h:161
@ LIB_SHAPE_T
Definition: typeinfo.h:189
@ SCH_MARKER_T
Definition: typeinfo.h:131
@ SCH_HIER_LABEL_T
Definition: typeinfo.h:143
@ SCH_BUS_BUS_ENTRY_T
Definition: typeinfo.h:135
@ LIB_PIN_T
Definition: typeinfo.h:192
@ SCH_ITEM_LOCATE_GRAPHIC_LINE_T
Definition: typeinfo.h:162
@ SCH_SHEET_PIN_T
Definition: typeinfo.h:147
@ LIB_FIELD_T
Definition: typeinfo.h:198
@ SCH_SYMBOL_LOCATE_POWER_T
Definition: typeinfo.h:170
@ SCH_BUS_WIRE_ENTRY_T
Definition: typeinfo.h:134
@ SCH_GLOBAL_LABEL_T
Definition: typeinfo.h:142
@ SCH_JUNCTION_T
Definition: typeinfo.h:132
@ SCH_PIN_T
Definition: typeinfo.h:149
constexpr ret_type KiROUND(fp_type v)
Round a floating point number to an integer using "round halfway cases away from zero".
Definition: util.h:85