KiCad PCB EDA Suite
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-2022 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() != nullptr;
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::MODEL_RELOAD )
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 getView()->GetPainter()->GetSettings()->SetHighlight( false );
307
308 SYMBOL_EDIT_FRAME* symbolEditFrame = dynamic_cast<SYMBOL_EDIT_FRAME*>( m_frame );
309 SYMBOL_VIEWER_FRAME* symbolViewerFrame = dynamic_cast<SYMBOL_VIEWER_FRAME*>( m_frame );
310
311 if( symbolEditFrame )
312 {
313 m_isSymbolEditor = true;
314 m_unit = symbolEditFrame->GetUnit();
315 m_convert = symbolEditFrame->GetConvert();
316 }
317 else
318 {
319 m_isSymbolViewer = symbolViewerFrame != nullptr;
320 }
321 }
322 else
323 {
324 // Restore previous properties of selected items and remove them from containers
326 }
327
328 // Reinsert the VIEW_GROUP, in case it was removed from the VIEW
330 getView()->Add( &m_selection );
331}
332
333
335{
337
338 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();
355
356 if( evt->IsMouseDown( BUT_LEFT ) )
357 {
358 // Avoid triggering when running under other tools
359 // Distinguish point editor from selection modification by checking modifiers
362 {
364 m_disambiguateTimer.StartOnce( 500 );
365 }
366 }
367 // Single click? Select single object
368 else if( evt->IsClick( BUT_LEFT ) )
369 {
370 // If the timer has stopped, then we have already run the disambiguate routine
371 // and we don't want to register an extra click here
372 if( !m_disambiguateTimer.IsRunning() )
373 {
374 evt->SetPassEvent();
375 continue;
376 }
377
378 m_disambiguateTimer.Stop();
379
380 if( SCH_EDIT_FRAME* schframe = dynamic_cast<SCH_EDIT_FRAME*>( m_frame ) )
381 schframe->FocusOnItem( nullptr );
382
383 // Collect items at the clicked location (doesn't select them yet)
384 EE_COLLECTOR collector;
385 CollectHits( collector, evt->Position() );
386 narrowSelection( collector, evt->Position(), false );
387
388 if( collector.GetCount() == 1 && !m_isSymbolEditor && !hasModifier() )
389 {
390 OPT_TOOL_EVENT autostart = autostartEvent( evt, grid, collector[0] );
391
392 if( autostart )
393 {
395
396 params->layer = autostart->Parameter<DRAW_SEGMENT_EVENT_PARAMS*>()->layer;
397 params->quitOnDraw = true;
398 params->sourceSegment = dynamic_cast<SCH_LINE*>( collector[0] );
399
400 autostart->SetParameter( params );
401 m_toolMgr->ProcessEvent( *autostart );
402
403 selCancelled = true;
404 }
405 else if( collector[0]->IsHypertext() )
406 {
407 collector[ 0 ]->DoHypertextAction( m_frame );
408 selCancelled = true;
409 }
410 }
411
412 if( !selCancelled )
413 {
414 selectPoint( collector, evt->Position(), nullptr, nullptr, m_additive,
416 m_selection.SetIsHover( false );
417 }
418 }
419 else if( evt->IsClick( BUT_RIGHT ) )
420 {
421 m_disambiguateTimer.Stop();
422
423 // right click? if there is any object - show the context menu
424 if( m_selection.Empty() )
425 {
427 SelectPoint( evt->Position(), { SCH_LOCATE_ANY_T }, nullptr, &selCancelled );
428 m_selection.SetIsHover( true );
429 }
430 // If the cursor has moved off the bounding box of the selection by more than
431 // a grid square, check to see if there is another item available for selection
432 // under the cursor. If there is, the user likely meant to get the context menu
433 // for that item. If there is no new item, then keep the original selection and
434 // show the context menu for it.
435 else if( !m_selection.GetBoundingBox().Inflate( grid.GetGrid().x, grid.GetGrid().y )
436 .Contains( evt->Position() ) )
437 {
438 EE_COLLECTOR collector;
439
440 if( CollectHits( collector, evt->Position(), { SCH_LOCATE_ANY_T } ) )
441 {
443
444 SelectPoint( evt->Position(), { SCH_LOCATE_ANY_T }, nullptr, &selCancelled );
445 m_selection.SetIsHover( true );
446 }
447 }
448
449 if( !selCancelled )
451 }
452 else if( evt->IsDblClick( BUT_LEFT ) )
453 {
454 m_disambiguateTimer.Stop();
455
456 // double click? Display the properties window
457 if( SCH_EDIT_FRAME* schframe = dynamic_cast<SCH_EDIT_FRAME*>( m_frame ) )
458 schframe->FocusOnItem( nullptr );
459
460 if( m_selection.Empty() )
461 SelectPoint( evt->Position() );
462
463 EDA_ITEM* item = m_selection.Front();
464
465 if( item && item->Type() == SCH_SHEET_T )
467 else
469 }
470 else if( evt->IsDblClick( BUT_MIDDLE ) )
471 {
472 m_disambiguateTimer.Stop();
473
474 // Middle double click? Do zoom to fit or zoom to objects
475 if( evt->Modifier( MD_CTRL ) ) // Is CTRL key down?
477 else
479 }
480 else if( evt->IsDrag( BUT_LEFT ) )
481 {
482 m_disambiguateTimer.Stop();
483
484 // Is another tool already moving a new object? Don't allow a drag start
485 if( !m_selection.Empty() && m_selection[0]->HasFlag( IS_NEW | IS_MOVING ) )
486 {
487 evt->SetPassEvent();
488 continue;
489 }
490
491 // drag with LMB? Select multiple objects (or at least draw a selection box) or
492 // drag them
493 if( SCH_EDIT_FRAME* schframe = dynamic_cast<SCH_EDIT_FRAME*>( m_frame ) )
494 schframe->FocusOnItem( nullptr );
495
496 if( hasModifier() || drag_action == MOUSE_DRAG_ACTION::SELECT )
497 {
499 }
500 else if( m_selection.Empty() && drag_action != MOUSE_DRAG_ACTION::DRAG_ANY )
501 {
503 }
504 else
505 {
506 if( m_isSymbolEditor )
507 {
508 if( static_cast<SYMBOL_EDIT_FRAME*>( m_frame )->IsSymbolAlias() )
509 {
511 }
512 else
513 {
517 LIB_PIN_T,
518 LIB_FIELD_T } );
519 }
520 }
521 else
522 {
524 }
525
526 // Check if dragging has started within any of selected items bounding box
527 if( selectionContains( evt->DragOrigin() ) )
528 {
529 // Yes -> run the move tool and wait till it finishes
530 if( m_isSymbolEditor )
531 m_toolMgr->InvokeTool( "eeschema.SymbolMoveTool" );
532 else
533 m_toolMgr->InvokeTool( "eeschema.InteractiveMove" );
534 }
535 else
536 {
537 // No -> drag a selection box
539 }
540 }
541 }
542 else if( evt->IsMouseDown( BUT_AUX1 ) )
543 {
545 }
546 else if( evt->IsMouseDown( BUT_AUX2 ) )
547 {
549 }
550 else if( evt->Category() == TC_COMMAND && evt->Action() == TA_CHOICE_MENU_CHOICE )
551 {
552 m_disambiguateTimer.Stop();
553
554 // context sub-menu selection? Handle unit selection or bus unfolding
555 if( *evt->GetCommandId() >= ID_POPUP_SCH_SELECT_UNIT_CMP
556 && *evt->GetCommandId() <= ID_POPUP_SCH_SELECT_UNIT_SYM_MAX )
557 {
558 SCH_SYMBOL* symbol = dynamic_cast<SCH_SYMBOL*>( m_selection.Front() );
559 int unit = *evt->GetCommandId() - ID_POPUP_SCH_SELECT_UNIT_CMP;
560
561 if( symbol )
562 static_cast<SCH_EDIT_FRAME*>( m_frame )->SelectUnit( symbol, unit );
563 }
564 else if( *evt->GetCommandId() >= ID_POPUP_SCH_UNFOLD_BUS
565 && *evt->GetCommandId() <= ID_POPUP_SCH_UNFOLD_BUS_END )
566 {
567 wxString* net = new wxString( *evt->Parameter<wxString*>() );
569 }
570 }
571 else if( evt->IsCancelInteractive() )
572 {
573 m_disambiguateTimer.Stop();
574
575 if( SCH_EDIT_FRAME* schframe = dynamic_cast<SCH_EDIT_FRAME*>( m_frame ) )
576 schframe->FocusOnItem( nullptr );
577
578 if( !GetSelection().Empty() )
579 {
581 }
582 else if( evt->FirstResponder() == this && evt->GetCommandId() == (int) WXK_ESCAPE )
583 {
585
587 editor->ClearHighlight( *evt );
588 }
589 }
590 else if( evt->Action() == TA_UNDO_REDO_PRE )
591 {
592 if( SCH_EDIT_FRAME* schframe = dynamic_cast<SCH_EDIT_FRAME*>( m_frame ) )
593 schframe->FocusOnItem( nullptr );
594
596 }
597 else if( evt->IsMotion() && !m_isSymbolEditor && evt->FirstResponder() == this )
598 {
599 // Update cursor and rollover item
600 rolloverItem = niluuid;
601 EE_COLLECTOR collector;
602
604
605 if( CollectHits( collector, evt->Position() ) )
606 {
607 narrowSelection( collector, evt->Position(), false );
608
609 if( collector.GetCount() == 1 && !hasModifier() )
610 {
611 OPT_TOOL_EVENT autostartEvt = autostartEvent( evt, grid, collector[0] );
612
613 if( autostartEvt )
614 {
615 if( autostartEvt->Matches( EE_ACTIONS::drawBus.MakeEvent() ) )
616 displayBusCursor = true;
617 else if( autostartEvt->Matches( EE_ACTIONS::drawWire.MakeEvent() ) )
618 displayWireCursor = true;
619 else if( autostartEvt->Matches( EE_ACTIONS::drawLines.MakeEvent() ) )
620 displayLineCursor = true;
621 }
622 else if( collector[0]->IsHypertext() && !collector[0]->IsSelected() )
623 {
624 rolloverItem = collector[0]->m_Uuid;
625 }
626 }
627 }
628 }
629 else
630 {
631 evt->SetPassEvent();
632 }
633
634 if( rolloverItem != lastRolloverItem )
635 {
636 if( EDA_ITEM* item = m_frame->GetItem( lastRolloverItem ) )
637 {
638 item->ClearFlags( IS_ROLLOVER );
639 lastRolloverItem = niluuid;
640
641 if( item->Type() == SCH_FIELD_T )
642 m_frame->GetCanvas()->GetView()->Update( item->GetParent() );
643 else
644 m_frame->GetCanvas()->GetView()->Update( item );
645 }
646 }
647
648 if( EDA_ITEM* item = m_frame->GetItem( rolloverItem ) )
649 {
650 if( !( item->GetFlags() & IS_ROLLOVER ) )
651 {
652 item->SetFlags( IS_ROLLOVER );
653 lastRolloverItem = rolloverItem;
654
655 if( item->Type() == SCH_FIELD_T )
656 m_frame->GetCanvas()->GetView()->Update( item->GetParent() );
657 else
658 m_frame->GetCanvas()->GetView()->Update( item );
659 }
660 }
661
663 {
664 if( displayWireCursor )
665 {
667 }
668 else if( displayBusCursor )
669 {
671 }
672 else if( displayLineCursor )
673 {
675 }
676 else if( rolloverItem != niluuid )
677 {
679 }
680 else if( !m_selection.Empty()
681 && drag_action == MOUSE_DRAG_ACTION::DRAG_SELECTED
682 && evt->HasPosition()
683 && selectionContains( evt->Position() ) ) //move/drag option prediction
684 {
686 }
687 else
688 {
690 }
691 }
692 }
693
694 m_disambiguateTimer.Stop();
695
696 // Shutting down; clear the selection
698
699 return 0;
700}
701
702
704 SCH_ITEM* aItem )
705{
706 VECTOR2I pos = aGrid.BestSnapAnchor( aEvent->Position(), LAYER_CONNECTABLE );
707
710 && aItem->IsPointClickableAnchor( pos ) )
711 {
713
714 if( aItem->Type() == SCH_BUS_BUS_ENTRY_T )
715 {
717 }
718 else if( aItem->Type() == SCH_BUS_WIRE_ENTRY_T )
719 {
720 SCH_BUS_WIRE_ENTRY* busEntry = static_cast<SCH_BUS_WIRE_ENTRY*>( aItem );
721
722 if( !busEntry->m_connected_bus_item )
724 }
725 else if( aItem->Type() == SCH_LINE_T )
726 {
727 SCH_LINE* line = static_cast<SCH_LINE*>( aItem );
728
729 if( line->IsBus() )
730 newEvt = EE_ACTIONS::drawBus.MakeEvent();
731 else if( line->IsGraphicLine() )
732 newEvt = EE_ACTIONS::drawLines.MakeEvent();
733 }
734 else if( aItem->Type() == SCH_LABEL_T || aItem->Type() == SCH_HIER_LABEL_T
735 || aItem->Type() == SCH_SHEET_PIN_T )
736 {
737 SCH_LABEL_BASE* label = static_cast<SCH_LABEL_BASE*>( aItem );
738 SCH_CONNECTION possibleConnection( label->Schematic()->ConnectionGraph() );
739 possibleConnection.ConfigureFromLabel( label->GetText() );
740
741 if( possibleConnection.IsBus() )
743 }
744
745 newEvt->SetMousePosition( pos );
746 newEvt->SetHasPosition( true );
747 newEvt->SetForceImmediate( true );
748
749 getViewControls()->ForceCursorPosition( true, pos );
750
751 return newEvt;
752 }
753
754 return OPT_TOOL_EVENT();
755}
756
757
759{
760 wxMouseState keyboardState = wxGetMouseState();
761
762 setModifiersState( keyboardState.ShiftDown(), keyboardState.ControlDown(),
763 keyboardState.AltDown() );
764
765 m_skip_heuristics = true;
768 m_skip_heuristics = false;
769
770 return 0;
771}
772
773
774void EE_SELECTION_TOOL::OnIdle( wxIdleEvent& aEvent )
775{
777 {
778 wxMouseState keyboardState = wxGetMouseState();
779
780 setModifiersState( keyboardState.ShiftDown(), keyboardState.ControlDown(),
781 keyboardState.AltDown() );
782
783 if( m_additive )
785 else if( m_subtractive )
787 else if( m_exclusive_or )
789 else
791 }
792}
793
794
796{
797 return m_selection;
798}
799
800
801bool EE_SELECTION_TOOL::CollectHits( EE_COLLECTOR& aCollector, const VECTOR2I& aWhere,
802 const std::vector<KICAD_T>& aScanTypes )
803{
804 int pixelThreshold = KiROUND( getView()->ToWorld( HITTEST_THRESHOLD_PIXELS ) );
805 int gridThreshold = KiROUND( getView()->GetGAL()->GetGridSize().EuclideanNorm() / 2 );
806 aCollector.m_Threshold = std::max( pixelThreshold, gridThreshold );
808
809 if( m_isSymbolEditor )
810 {
811 LIB_SYMBOL* symbol = static_cast<SYMBOL_EDIT_FRAME*>( m_frame )->GetCurSymbol();
812
813 if( !symbol )
814 return false;
815
816 aCollector.Collect( symbol->GetDrawItems(), aScanTypes, aWhere, m_unit, m_convert );
817 }
818 else
819 {
820 aCollector.Collect( m_frame->GetScreen(), aScanTypes, aWhere, m_unit, m_convert );
821
823 {
824 int originalCount = aCollector.GetCount();
825
826 for( int ii = 0; ii < originalCount; ++ii )
827 {
828 if( aCollector[ii]->Type() == SCH_PIN_T )
829 {
830 SCH_PIN* pin = static_cast<SCH_PIN*>( aCollector[ii] );
831
832 if( !aCollector.HasItem( pin->GetParentSymbol() ) )
833 aCollector.Append( pin->GetParentSymbol() );
834 }
835 }
836 }
837 }
838
839 return aCollector.GetCount() > 0;
840}
841
842
844 bool aCheckLocked, bool aSelectedOnly )
845{
846 for( int i = collector.GetCount() - 1; i >= 0; --i )
847 {
848 if( !Selectable( collector[i], &aWhere ) )
849 {
850 collector.Remove( i );
851 continue;
852 }
853
854 if( aCheckLocked && collector[i]->IsLocked() )
855 {
856 collector.Remove( i );
857 continue;
858 }
859
860 if( aSelectedOnly && !collector[i]->IsSelected() )
861 {
862 collector.Remove( i );
863 continue;
864 }
865 }
866
867 // Apply some ugly heuristics to avoid disambiguation menus whenever possible
868 if( collector.GetCount() > 1 && !m_skip_heuristics )
869 GuessSelectionCandidates( collector, aWhere );
870}
871
872
873bool EE_SELECTION_TOOL::selectPoint( EE_COLLECTOR& aCollector, const VECTOR2I& aWhere,
874 EDA_ITEM** aItem, bool* aSelectionCancelledFlag, bool aAdd,
875 bool aSubtract, bool aExclusiveOr )
876{
878
879 // If still more than one item we're going to have to ask the user.
880 if( aCollector.GetCount() > 1 )
881 {
882 // Try to call selectionMenu via RunAction() to avoid event-loop contention
883 // But it we cannot handle the event, then we don't have an active tool loop, so
884 // handle it directly.
885 if( !m_toolMgr->RunAction( EE_ACTIONS::selectionMenu, true, &aCollector ) )
886 {
887 if( !doSelectionMenu( &aCollector ) )
888 aCollector.m_MenuCancelled = true;
889 }
890
891 if( aCollector.m_MenuCancelled )
892 {
893 if( aSelectionCancelledFlag )
894 *aSelectionCancelledFlag = true;
895
896 return false;
897 }
898 }
899
900 if( !aAdd && !aSubtract && !aExclusiveOr )
902
903 int addedCount = 0;
904 bool anySubtracted = false;
905
906 if( aCollector.GetCount() > 0 )
907 {
908 for( int i = 0; i < aCollector.GetCount(); ++i )
909 {
910 EDA_ITEM_FLAGS flags = 0;
911 bool isLine = aCollector[i]->Type() == SCH_LINE_T;
912
913 // Handle line ends specially
914 if( isLine )
915 {
916 SCH_LINE* line = (SCH_LINE*) aCollector[i];
917
918 if( HitTestPoints( line->GetStartPoint(), aWhere, aCollector.m_Threshold ) )
919 flags = STARTPOINT;
920 else if( HitTestPoints( line->GetEndPoint(), aWhere, aCollector.m_Threshold ) )
921 flags = ENDPOINT;
922 else
923 flags = STARTPOINT | ENDPOINT;
924 }
925
926 if( aSubtract
927 || ( aExclusiveOr && aCollector[i]->IsSelected()
928 && ( !isLine || ( isLine && aCollector[i]->HasFlag( flags ) ) ) ) )
929 {
930 aCollector[i]->ClearFlags( flags );
931
932 // Need to update end shadows after ctrl-click unselecting one of two selected endpoints
933 if( isLine )
934 getView()->Update( aCollector[i] );
935
936 if( !aCollector[i]->HasFlag( STARTPOINT ) && !aCollector[i]->HasFlag( ENDPOINT ) )
937 {
938 unselect( aCollector[i] );
939 anySubtracted = true;
940 }
941 }
942 else
943 {
944 aCollector[i]->SetFlags( flags );
945 select( aCollector[i] );
946 addedCount++;
947 }
948 }
949 }
950
951 if( addedCount == 1 )
952 {
954
955 if( aItem && aCollector.GetCount() == 1 )
956 *aItem = aCollector[0];
957
958 return true;
959 }
960 else if( addedCount > 1 )
961 {
963 return true;
964 }
965 else if( anySubtracted )
966 {
968 return true;
969 }
970
971 return false;
972}
973
974
976 const std::vector<KICAD_T>& aScanTypes,
977 EDA_ITEM** aItem, bool* aSelectionCancelledFlag,
978 bool aCheckLocked, bool aAdd, bool aSubtract,
979 bool aExclusiveOr )
980{
981 EE_COLLECTOR collector;
982
983 if( !CollectHits( collector, aWhere, aScanTypes ) )
984 return false;
985
986 narrowSelection( collector, aWhere, aCheckLocked, aSubtract );
987
988 return selectPoint( collector, aWhere, aItem, aSelectionCancelledFlag, aAdd, aSubtract,
989 aExclusiveOr );
990}
991
992
994{
995 m_multiple = true; // Multiple selection mode is active
996 KIGFX::VIEW* view = getView();
997
998 // hold all visible items
999 std::vector<KIGFX::VIEW::LAYER_ITEM_PAIR> selectedItems;
1000 std::vector<KIGFX::VIEW::LAYER_ITEM_PAIR> sheetPins;
1001
1002 // Filter the view items based on the selection box
1003 BOX2I selectionBox;
1004
1005 selectionBox.SetMaximum();
1006 view->Query( selectionBox, selectedItems ); // Get the list of selected items
1007
1008 // Sheet pins aren't in the view; add them by hand
1009 for( KIGFX::VIEW::LAYER_ITEM_PAIR& pair : selectedItems )
1010 {
1011 SCH_SHEET* sheet = dynamic_cast<SCH_SHEET*>( pair.first );
1012
1013 if( sheet )
1014 {
1015 int layer = pair.second;
1016
1017 for( SCH_SHEET_PIN* pin : sheet->GetPins() )
1018 sheetPins.emplace_back( KIGFX::VIEW::LAYER_ITEM_PAIR( pin, layer ) );
1019 }
1020 }
1021
1022 selectedItems.insert( selectedItems.end(), sheetPins.begin(), sheetPins.end() );
1023
1024 for( const std::pair<KIGFX::VIEW_ITEM*, int>& item_pair : selectedItems )
1025 {
1026 if( EDA_ITEM* item = dynamic_cast<EDA_ITEM*>( item_pair.first ) )
1027 {
1028 if( Selectable( item ) )
1029 {
1030 if( item->Type() == SCH_LINE_T )
1031 item->SetFlags( STARTPOINT | ENDPOINT );
1032
1033 select( item );
1034 }
1035 }
1036 }
1037
1038 m_multiple = false;
1039
1041
1042 return 0;
1043}
1044
1045
1047{
1048 // Prefer exact hits to sloppy ones
1049 std::set<EDA_ITEM*> exactHits;
1050
1051 for( int i = collector.GetCount() - 1; i >= 0; --i )
1052 {
1053 EDA_ITEM* item = collector[ i ];
1054 SCH_LINE* line = dynamic_cast<SCH_LINE*>( item );
1055 LIB_SHAPE* shape = dynamic_cast<LIB_SHAPE*>( item );
1056 SCH_SYMBOL* symbol = dynamic_cast<SCH_SYMBOL*>( item );
1057
1058 // Lines are hard to hit. Give them a bit more slop to still be considered "exact".
1059
1060 if( line || ( shape && shape->GetShape() == SHAPE_T::POLY )
1061 || ( shape && shape->GetShape() == SHAPE_T::ARC ) )
1062 {
1063 int pixelThreshold = KiROUND( getView()->ToWorld( 6 ) );
1064
1065 if( item->HitTest( aPos, pixelThreshold ) )
1066 exactHits.insert( item );
1067 }
1068 else if( symbol && m_frame->eeconfig()->m_Selection.select_pin_selects_symbol )
1069 {
1070 if( symbol->GetBodyAndPinsBoundingBox().Contains( aPos ) )
1071 exactHits.insert( item );
1072 }
1073 else
1074 {
1075 if( item->HitTest( aPos, 0 ) )
1076 exactHits.insert( item );
1077 }
1078 }
1079
1080 if( exactHits.size() > 0 && exactHits.size() < (unsigned) collector.GetCount() )
1081 {
1082 for( int i = collector.GetCount() - 1; i >= 0; --i )
1083 {
1084 EDA_ITEM* item = collector[ i ];
1085
1086 if( !exactHits.count( item ) )
1087 collector.Transfer( item );
1088 }
1089 }
1090
1091 // Find the closest item. (Note that at this point all hits are either exact or non-exact.)
1092 VECTOR2I pos( aPos );
1093 SEG poss( m_isSymbolEditor ? mapCoords( pos ) : pos,
1094 m_isSymbolEditor ? mapCoords( pos ) : pos );
1095 EDA_ITEM* closest = nullptr;
1096 int closestDist = INT_MAX / 2;
1097
1098 for( EDA_ITEM* item : collector )
1099 {
1100 BOX2I bbox = item->GetBoundingBox();
1101 int dist = INT_MAX / 2;
1102
1103 if( exactHits.count( item ) )
1104 {
1105 if( item->Type() == SCH_PIN_T || item->Type() == SCH_JUNCTION_T )
1106 {
1107 closest = item;
1108 break;
1109 }
1110
1111 SCH_LINE* line = dynamic_cast<SCH_LINE*>( item );
1112 EDA_TEXT* text = dynamic_cast<EDA_TEXT*>( item );
1113 SCH_SYMBOL* symbol = dynamic_cast<SCH_SYMBOL*>( item );
1114
1115 if( line )
1116 {
1117 dist = DistanceLinePoint( line->GetStartPoint(), line->GetEndPoint(), pos );
1118 }
1119 else if( text )
1120 {
1121 if( SCH_FIELD* field = dynamic_cast<SCH_FIELD*>( text ) )
1122 {
1123 if( field->GetParent() && field->GetParent()->Type() == SCH_SYMBOL_T )
1124 {
1125 symbol = static_cast<SCH_SYMBOL*>( field->GetParent() );
1126
1127 VECTOR2I relPos = pos - symbol->GetPosition();
1128 relPos = symbol->GetTransform().InverseTransform().TransformCoordinate( relPos );
1129 pos = relPos + symbol->GetPosition();
1130
1131 poss = SEG( pos, pos );
1132 }
1133 }
1134
1135 text->GetEffectiveTextShape()->Collide( poss, closestDist, &dist );
1136 }
1137 else if( symbol )
1138 {
1139 try
1140 {
1141 bbox = symbol->GetBodyBoundingBox();
1142 }
1143 catch( const boost::bad_pointer& exc )
1144 {
1145 // This may be overkill and could be an assertion but we are more likely to
1146 // find any boost pointer container errors this way.
1147 wxLogError( wxT( "Boost bad pointer exception '%s' occurred." ), exc.what() );
1148 }
1149
1150 SHAPE_RECT rect( bbox.GetPosition(), bbox.GetWidth(), bbox.GetHeight() );
1151
1152 if( bbox.Contains( pos ) )
1153 dist = EuclideanNorm( bbox.GetCenter() - pos );
1154 else
1155 rect.Collide( poss, closestDist, &dist );
1156 }
1157 else
1158 {
1159 dist = EuclideanNorm( bbox.GetCenter() - pos );
1160 }
1161 }
1162 else
1163 {
1164 SHAPE_RECT rect( bbox.GetPosition(), bbox.GetWidth(), bbox.GetHeight() );
1165 rect.Collide( poss, collector.m_Threshold, &dist );
1166 }
1167
1168 if( dist == closestDist )
1169 {
1170 if( item->GetParent() == closest )
1171 closest = item;
1172 }
1173 else if( dist < closestDist )
1174 {
1175 closestDist = dist;
1176 closest = item;
1177 }
1178 }
1179
1180 // Construct a tight box (1/2 height and width) around the center of the closest item.
1181 // All items which exist at least partly outside this box have sufficient other areas
1182 // for selection and can be dropped.
1183 if( closest ) // Don't try and get a tight bbox if nothing is near the mouse pointer
1184 {
1185 BOX2I tightBox = closest->GetBoundingBox();
1186 tightBox.Inflate( -tightBox.GetWidth() / 4, -tightBox.GetHeight() / 4 );
1187
1188 for( int i = collector.GetCount() - 1; i >= 0; --i )
1189 {
1190 EDA_ITEM* item = collector[i];
1191
1192 if( item == closest )
1193 continue;
1194
1195 if( !item->HitTest( tightBox, true ) )
1196 collector.Transfer( item );
1197 }
1198 }
1199}
1200
1201
1202EE_SELECTION& EE_SELECTION_TOOL::RequestSelection( const std::vector<KICAD_T>& aScanTypes )
1203{
1204 if( m_selection.Empty() )
1205 {
1206 VECTOR2D cursorPos = getViewControls()->GetCursorPosition( true );
1207
1209 SelectPoint( cursorPos, aScanTypes );
1210 m_selection.SetIsHover( true );
1212 }
1213 else // Trim an existing selection by aFilterList
1214 {
1215 bool isMoving = false;
1216 bool anyUnselected = false;
1217
1218 for( int i = (int) m_selection.GetSize() - 1; i >= 0; --i )
1219 {
1220 EDA_ITEM* item = (EDA_ITEM*) m_selection.GetItem( i );
1221 isMoving |= static_cast<SCH_ITEM*>( item )->IsMoving();
1222
1223 if( !item->IsType( aScanTypes ) )
1224 {
1225 unselect( item );
1226 anyUnselected = true;
1227 }
1228 }
1229
1230 if( anyUnselected )
1232
1233 if( !isMoving )
1235 }
1236
1237 return m_selection;
1238}
1239
1240
1242{
1243 VECTOR2I refP( 0, 0 );
1244
1245 if( m_selection.Size() > 0 )
1246 {
1247 if( m_isSymbolEditor )
1248 refP = static_cast<LIB_ITEM*>( m_selection.GetTopLeftItem() )->GetPosition();
1249 else
1250 refP = static_cast<SCH_ITEM*>( m_selection.GetTopLeftItem() )->GetPosition();
1251 }
1252
1254}
1255
1256
1257// Some navigation actions are allowed in selectMultiple
1267 &ACTIONS::zoomFitObjects, nullptr };
1268
1269
1271{
1272 bool cancelled = false; // Was the tool canceled while it was running?
1273 m_multiple = true; // Multiple selection mode is active
1274 KIGFX::VIEW* view = getView();
1275
1277 view->Add( &area );
1278
1279 while( TOOL_EVENT* evt = Wait() )
1280 {
1281 int width = area.GetEnd().x - area.GetOrigin().x;
1282 int height = area.GetEnd().y - area.GetOrigin().y;
1283
1284 /* Selection mode depends on direction of drag-selection:
1285 * Left > Right : Select objects that are fully enclosed by selection
1286 * Right > Left : Select objects that are crossed by selection
1287 */
1288 bool isGreedy = width < 0;
1289
1290 if( view->IsMirroredX() )
1291 isGreedy = !isGreedy;
1292
1295
1296 if( evt->IsCancelInteractive() || evt->IsActivate() )
1297 {
1298 cancelled = true;
1299 break;
1300 }
1301
1302 if( evt->IsDrag( BUT_LEFT ) )
1303 {
1306
1307 // Start drawing a selection box
1308 area.SetOrigin( evt->DragOrigin() );
1309 area.SetEnd( evt->Position() );
1312 area.SetExclusiveOr( false );
1313
1314 view->SetVisible( &area, true );
1315 view->Update( &area );
1316 getViewControls()->SetAutoPan( true );
1317 }
1318
1319 if( evt->IsMouseUp( BUT_LEFT ) )
1320 {
1321 getViewControls()->SetAutoPan( false );
1322
1323 // End drawing the selection box
1324 view->SetVisible( &area, false );
1325
1326 // Fetch items from the RTree that are in our area of interest
1327 std::vector<KIGFX::VIEW::LAYER_ITEM_PAIR> nearbyViewItems;
1328 view->Query( area.ViewBBox(), nearbyViewItems );
1329
1330 // Build lists of nearby items and their children
1331 std::unordered_set<EDA_ITEM*> nearbyItems;
1332 std::vector<EDA_ITEM*> nearbyChildren;
1333 std::vector<EDA_ITEM*> flaggedItems;
1334
1335 for( KIGFX::VIEW::LAYER_ITEM_PAIR& pair : nearbyViewItems )
1336 {
1337 if( EDA_ITEM* item = dynamic_cast<EDA_ITEM*>( pair.first ) )
1338 {
1339 if( nearbyItems.insert( item ).second )
1340 {
1341 item->ClearFlags( CANDIDATE );
1342
1343 if( SCH_ITEM* sch_item = dynamic_cast<SCH_ITEM*>( item ) )
1344 {
1345 sch_item->RunOnChildren(
1346 [&]( SCH_ITEM* aChild )
1347 {
1348 // Filter pins by unit
1349 if( SCH_PIN* pin = dyn_cast<SCH_PIN*>( aChild ) )
1350 {
1351 int unit = pin->GetLibPin()->GetUnit();
1352
1353 if( unit && unit != pin->GetParentSymbol()->GetUnit() )
1354 return;
1355 }
1356
1357 nearbyChildren.push_back( aChild );
1358 } );
1359 }
1360 }
1361 }
1362 }
1363
1364 BOX2I selectionRect( area.GetOrigin(), VECTOR2I( width, height ) );
1365 selectionRect.Normalize();
1366
1367 bool anyAdded = false;
1368 bool anySubtracted = false;
1369
1370 auto selectItem =
1371 [&]( EDA_ITEM* aItem, EDA_ITEM_FLAGS flags )
1372 {
1373 if( m_subtractive || ( m_exclusive_or && aItem->IsSelected() ) )
1374 {
1375 if ( m_exclusive_or )
1376 aItem->XorFlags( flags );
1377 else
1378 aItem->ClearFlags( flags );
1379
1380 if( !aItem->HasFlag( STARTPOINT ) && !aItem->HasFlag( ENDPOINT ) )
1381 {
1382 unselect( aItem );
1383 anySubtracted = true;
1384 }
1385
1386 // We changed one line endpoint on a selected line,
1387 // update the view at least.
1388 if( flags && !anySubtracted )
1389 {
1390 getView()->Update( aItem );
1391 }
1392 }
1393 else
1394 {
1395 aItem->SetFlags( flags );
1396 select( aItem );
1397 anyAdded = true;
1398 }
1399 };
1400
1401 for( EDA_ITEM* item : nearbyItems )
1402 {
1403 bool selected = false;
1404 EDA_ITEM_FLAGS flags = 0;
1405
1407 item->SetFlags( SHOW_ELEC_TYPE );
1408
1409 if( Selectable( item ) )
1410 {
1411 if( item->Type() == SCH_LINE_T )
1412 {
1413 SCH_LINE* line = static_cast<SCH_LINE*>( item );
1414
1415 if( ( isGreedy && line->HitTest( selectionRect, false ) )
1416 || ( selectionRect.Contains( line->GetEndPoint() )
1417 && selectionRect.Contains( line->GetStartPoint() ) ) )
1418 {
1419 selected = true;
1420 flags |= STARTPOINT | ENDPOINT;
1421 }
1422 else if( !isGreedy )
1423 {
1424 if( selectionRect.Contains( line->GetStartPoint() )
1425 && line->IsStartDangling() )
1426 {
1427 selected = true;
1428 flags |= STARTPOINT;
1429 }
1430
1431 if( selectionRect.Contains( line->GetEndPoint() )
1432 && line->IsEndDangling() )
1433 {
1434 selected = true;
1435 flags |= ENDPOINT;
1436 }
1437 }
1438 }
1439 else
1440 {
1441 selected = item->HitTest( selectionRect, !isGreedy );
1442 }
1443 }
1444
1445 if( selected )
1446 {
1447 item->SetFlags( CANDIDATE );
1448 flaggedItems.push_back( item );
1449 selectItem( item, flags );
1450 }
1451
1452 item->ClearFlags( SHOW_ELEC_TYPE );
1453 }
1454
1455 for( EDA_ITEM* item : nearbyChildren )
1456 {
1458 item->SetFlags( SHOW_ELEC_TYPE );
1459
1460 if( Selectable( item )
1461 && !item->GetParent()->HasFlag( CANDIDATE )
1462 && item->HitTest( selectionRect, !isGreedy ) )
1463 {
1464 selectItem( item, 0 );
1465 }
1466
1467 item->ClearFlags( SHOW_ELEC_TYPE );
1468 }
1469
1470 for( EDA_ITEM* item : flaggedItems )
1471 item->ClearFlags( CANDIDATE );
1472
1473 m_selection.SetIsHover( false );
1474
1475 // Inform other potentially interested tools
1476 if( anyAdded )
1478
1479 if( anySubtracted )
1481
1482 break; // Stop waiting for events
1483 }
1484
1485 // Allow some actions for navigation
1486 for( int i = 0; allowedActions[i]; ++i )
1487 {
1488 if( evt->IsAction( allowedActions[i] ) )
1489 {
1490 evt->SetPassEvent();
1491 break;
1492 }
1493 }
1494 }
1495
1496 getViewControls()->SetAutoPan( false );
1497
1498 // Stop drawing the selection box
1499 view->Remove( &area );
1500 m_multiple = false; // Multiple selection mode is inactive
1501
1502 if( !cancelled )
1504
1505 return cancelled;
1506}
1507
1508
1510{
1511 EE_COLLECTOR collector;
1512
1513 //TODO(snh): Reimplement after exposing KNN interface
1514 int pixelThreshold = KiROUND( getView()->ToWorld( HITTEST_THRESHOLD_PIXELS ) );
1515 int gridThreshold = KiROUND( getView()->GetGAL()->GetGridSize().EuclideanNorm() );
1516 int thresholdMax = std::max( pixelThreshold, gridThreshold );
1517
1518 for( int threshold : { 0, thresholdMax/4, thresholdMax/2, thresholdMax } )
1519 {
1520 collector.m_Threshold = threshold;
1521 collector.Collect( m_frame->GetScreen(), connectedTypes, aPosition );
1522
1523 if( collector.GetCount() > 0 )
1524 break;
1525 }
1526
1527 return collector.GetCount() ? collector[ 0 ] : nullptr;
1528}
1529
1530
1532{
1533 VECTOR2I cursorPos = getViewControls()->GetCursorPosition( false );
1534
1535 SelectPoint( cursorPos, connectedTypes );
1536
1537 return 0;
1538}
1539
1540
1542{
1544
1545 if( m_selection.Empty() )
1546 return 0;
1547
1548 SCH_LINE* line = (SCH_LINE*) m_selection.Front();
1549 unsigned done = false;
1550
1552 std::set<SCH_ITEM*> conns = m_frame->GetScreen()->MarkConnections( line, false );
1553
1554 for( SCH_ITEM* item : conns )
1555 {
1556 if( item->IsType( { SCH_ITEM_LOCATE_WIRE_T, SCH_ITEM_LOCATE_BUS_T } )
1557 && !item->IsSelected() )
1558 {
1559 done = true;
1560 }
1561
1562 select( item );
1563 }
1564
1565 if( !done )
1566 {
1567 conns = m_frame->GetScreen()->MarkConnections( line, true );
1568
1569 for( SCH_ITEM* item : conns )
1570 select( item );
1571 }
1572
1573 if( m_selection.GetSize() > 1 )
1575
1576 return 0;
1577}
1578
1579
1581{
1583
1584 return 0;
1585}
1586
1587
1589{
1590 if( aBBox.GetWidth() == 0 )
1591 return;
1592
1593 BOX2I bbox = aBBox;
1594 bbox.Normalize();
1595
1596 VECTOR2I bbSize = bbox.Inflate( bbox.GetWidth() * 0.2f ).GetSize();
1597 VECTOR2D screenSize = getView()->GetViewport().GetSize();
1598
1599 // This code tries to come up with a zoom factor that doesn't simply zoom in
1600 // to the cross probed symbol, but instead shows a reasonable amount of the
1601 // circuit around it to provide context. This reduces or eliminates the need
1602 // to manually change the zoom because it's too close.
1603
1604 // Using the default text height as a constant to compare against, use the
1605 // height of the bounding box of visible items for a footprint to figure out
1606 // if this is a big symbol (like a processor) or a small symbol (like a resistor).
1607 // This ratio is not useful by itself as a scaling factor. It must be "bent" to
1608 // provide good scaling at varying symbol sizes. Bigger symbols need less
1609 // scaling than small ones.
1610 double currTextHeight = schIUScale.MilsToIU( DEFAULT_TEXT_SIZE );
1611
1612 double compRatio = bbSize.y / currTextHeight; // Ratio of symbol to text height
1613 double compRatioBent = 1.0;
1614
1615 // LUT to scale zoom ratio to provide reasonable schematic context. Must work
1616 // with symbols of varying sizes (e.g. 0402 package and 200 pin BGA).
1617 // "first" is used as the input and "second" as the output
1618 //
1619 // "first" = compRatio (symbol height / default text height)
1620 // "second" = Amount to scale ratio by
1621 std::vector<std::pair<double, double>> lut{ { 1.25, 16 }, // 32
1622 { 2.5, 12 }, //24
1623 { 5, 8 }, // 16
1624 { 6, 6 }, //
1625 { 10, 4 }, //8
1626 { 20, 2 }, //4
1627 { 40, 1.5 }, // 2
1628 { 100, 1 } };
1629
1630 std::vector<std::pair<double, double>>::iterator it;
1631
1632 // Large symbol default is last LUT entry (1:1).
1633 compRatioBent = lut.back().second;
1634
1635 // Use LUT to do linear interpolation of "compRatio" within "first", then
1636 // use that result to linearly interpolate "second" which gives the scaling
1637 // factor needed.
1638 if( compRatio >= lut.front().first )
1639 {
1640 for( it = lut.begin(); it < lut.end() - 1; it++ )
1641 {
1642 if( it->first <= compRatio && next( it )->first >= compRatio )
1643 {
1644 double diffx = compRatio - it->first;
1645 double diffn = next( it )->first - it->first;
1646
1647 compRatioBent = it->second + ( next( it )->second - it->second ) * diffx / diffn;
1648 break; // We have our interpolated value
1649 }
1650 }
1651 }
1652 else
1653 {
1654 compRatioBent = lut.front().second; // Small symbol default is first entry
1655 }
1656
1657 // This is similar to the original KiCad code that scaled the zoom to make sure
1658 // symbols were visible on screen. It's simply a ratio of screen size to
1659 // symbol size, and its job is to zoom in to make the component fullscreen.
1660 // Earlier in the code the symbol BBox is given a 20% margin to add some
1661 // breathing room. We compare the height of this enlarged symbol bbox to the
1662 // default text height. If a symbol will end up with the sides clipped, we
1663 // adjust later to make sure it fits on screen.
1664 screenSize.x = std::max( 10.0, screenSize.x );
1665 screenSize.y = std::max( 10.0, screenSize.y );
1666 double ratio = std::max( -1.0, fabs( bbSize.y / screenSize.y ) );
1667
1668 // Original KiCad code for how much to scale the zoom
1669 double kicadRatio =
1670 std::max( fabs( bbSize.x / screenSize.x ), fabs( bbSize.y / screenSize.y ) );
1671
1672 // If the width of the part we're probing is bigger than what the screen width
1673 // will be after the zoom, then punt and use the KiCad zoom algorithm since it
1674 // guarantees the part's width will be encompassed within the screen.
1675 if( bbSize.x > screenSize.x * ratio * compRatioBent )
1676 {
1677 // Use standard KiCad zoom for parts too wide to fit on screen/
1678 ratio = kicadRatio;
1679 compRatioBent = 1.0; // Reset so we don't modify the "KiCad" ratio
1680 wxLogTrace( "CROSS_PROBE_SCALE",
1681 "Part TOO WIDE for screen. Using normal KiCad zoom ratio: %1.5f", ratio );
1682 }
1683
1684 // Now that "compRatioBent" holds our final scaling factor we apply it to the
1685 // original fullscreen zoom ratio to arrive at the final ratio itself.
1686 ratio *= compRatioBent;
1687
1688 bool alwaysZoom = false; // DEBUG - allows us to minimize zooming or not
1689
1690 // Try not to zoom on every cross-probe; it gets very noisy
1691 if( ( ratio < 0.5 || ratio > 1.0 ) || alwaysZoom )
1692 getView()->SetScale( getView()->GetScale() / ratio );
1693}
1694
1695
1696int EE_SELECTION_TOOL::SyncSelection( std::optional<SCH_SHEET_PATH> targetSheetPath,
1697 SCH_ITEM* focusItem, std::vector<SCH_ITEM*> items )
1698{
1699 SCH_EDIT_FRAME* editFrame = dynamic_cast<SCH_EDIT_FRAME*>( m_frame );
1700
1701 if( !editFrame || m_isSymbolEditor || m_isSymbolViewer )
1702 return 0;
1703
1704 if( targetSheetPath && targetSheetPath != editFrame->Schematic().CurrentSheet() )
1705 {
1706 editFrame->Schematic().SetCurrentSheet( *targetSheetPath );
1707 editFrame->DisplayCurrentSheet();
1708 }
1709
1710 ClearSelection( items.size() > 0 ? true /*quiet mode*/ : false );
1711
1712 // Perform individual selection of each item before processing the event.
1713 for( SCH_ITEM* item : items )
1714 select( item );
1715
1717
1718 if( bbox.GetWidth() != 0 && bbox.GetHeight() != 0 )
1719 {
1721 {
1723 ZoomFitCrossProbeBBox( bbox );
1724
1725 editFrame->FocusOnItem( focusItem );
1726
1727 if( !focusItem )
1728 editFrame->FocusOnLocation( bbox.Centre() );
1729 }
1730 }
1731
1732 if( m_selection.Size() > 0 )
1734
1735 return 0;
1736}
1737
1738
1740{
1742
1743 if( m_isSymbolEditor )
1744 {
1745 LIB_SYMBOL* start = static_cast<SYMBOL_EDIT_FRAME*>( m_frame )->GetCurSymbol();
1746
1747 for( LIB_ITEM& item : start->GetDrawItems() )
1748 {
1749 if( item.IsSelected() )
1750 select( &item );
1751 }
1752 }
1753 else
1754 {
1755 for( SCH_ITEM* item : m_frame->GetScreen()->Items() )
1756 {
1757 // If the field and symbol are selected, only use the symbol
1758 if( item->IsSelected() )
1759 {
1760 select( item );
1761 }
1762 else
1763 {
1764 item->RunOnChildren(
1765 [&]( SCH_ITEM* aChild )
1766 {
1767 if( aChild->IsSelected() )
1768 select( aChild );
1769 } );
1770 }
1771 }
1772 }
1773
1775
1776 // Inform other potentially interested tools
1778}
1779
1780
1781bool EE_SELECTION_TOOL::Selectable( const EDA_ITEM* aItem, const VECTOR2I* aPos,
1782 bool checkVisibilityOnly ) const
1783{
1784 // NOTE: in the future this is where Eeschema layer/itemtype visibility will be handled
1785
1786 SYMBOL_EDIT_FRAME* symEditFrame = dynamic_cast<SYMBOL_EDIT_FRAME*>( m_frame );
1787
1788 // Do not allow selection of anything except fields when the current symbol in the symbol
1789 // editor is a derived symbol.
1790 if( symEditFrame && symEditFrame->IsSymbolAlias() && aItem->Type() != LIB_FIELD_T )
1791 return false;
1792
1793 switch( aItem->Type() )
1794 {
1795 case SCH_PIN_T:
1796 {
1797 const SCH_PIN* pin = static_cast<const SCH_PIN*>( aItem );
1798
1799 if( !pin->IsVisible() && !m_frame->GetShowAllPins() )
1800 return false;
1801
1803 {
1804 // Pin anchors have to be allowed for auto-starting wires.
1805 if( aPos )
1806 {
1808
1809 if( pin->IsPointClickableAnchor( grid.BestSnapAnchor( *aPos, LAYER_CONNECTABLE ) ) )
1810 return true;
1811 }
1812
1813 return false;
1814 }
1815
1816 break;
1817 }
1818
1819 case LIB_SYMBOL_T: // In symbol_editor we do not want to select the symbol itself.
1820 return false;
1821
1822 case LIB_FIELD_T: // LIB_FIELD object can always be edited.
1823 break;
1824
1825 case LIB_SHAPE_T:
1826 case LIB_TEXT_T:
1827 case LIB_PIN_T:
1828 if( symEditFrame )
1829 {
1830 LIB_ITEM* lib_item = (LIB_ITEM*) aItem;
1831
1832 if( lib_item->GetUnit() && lib_item->GetUnit() != symEditFrame->GetUnit() )
1833 return false;
1834
1835 if( lib_item->GetConvert() && lib_item->GetConvert() != symEditFrame->GetConvert() )
1836 return false;
1837 }
1838
1839 break;
1840
1841 case SCH_MARKER_T: // Always selectable
1842 return true;
1843
1844 default: // Suppress warnings
1845 break;
1846 }
1847
1848 return true;
1849}
1850
1851
1853{
1854 if( m_selection.Empty() )
1855 return;
1856
1857 while( m_selection.GetSize() )
1859
1860 getView()->Update( &m_selection );
1861
1862 m_selection.SetIsHover( false );
1864
1865 // Inform other potentially interested tools
1866 if( !aQuietMode )
1868}
1869
1870
1872{
1873 highlight( aItem, SELECTED, &m_selection );
1874}
1875
1876
1878{
1879 unhighlight( aItem, SELECTED, &m_selection );
1880}
1881
1882
1883void EE_SELECTION_TOOL::highlight( EDA_ITEM* aItem, int aMode, SELECTION* aGroup )
1884{
1885 KICAD_T itemType = aItem->Type();
1886
1887 if( aMode == SELECTED )
1888 aItem->SetSelected();
1889 else if( aMode == BRIGHTENED )
1890 aItem->SetBrightened();
1891
1892 if( aGroup )
1893 aGroup->Add( aItem );
1894
1895 // Highlight pins and fields. (All the other symbol children are currently only
1896 // represented in the LIB_SYMBOL and will inherit the settings of the parent symbol.)
1897 if( SCH_ITEM* sch_item = dynamic_cast<SCH_ITEM*>( aItem ) )
1898 {
1899 sch_item->RunOnChildren(
1900 [&]( SCH_ITEM* aChild )
1901 {
1902 if( aMode == SELECTED )
1903 aChild->SetSelected();
1904 else if( aMode == BRIGHTENED )
1905 aChild->SetBrightened();
1906 } );
1907 }
1908
1909 if( itemType == SCH_PIN_T || itemType == SCH_FIELD_T || itemType == SCH_SHEET_PIN_T )
1910 getView()->Update( aItem->GetParent() );
1911 else
1912 getView()->Update( aItem );
1913}
1914
1915
1916void EE_SELECTION_TOOL::unhighlight( EDA_ITEM* aItem, int aMode, SELECTION* aGroup )
1917{
1918 KICAD_T itemType = aItem->Type();
1919
1920 if( aMode == SELECTED )
1921 {
1922 aItem->ClearSelected();
1923 // Lines need endpoints cleared here
1924 if( aItem->Type() == SCH_LINE_T )
1925 aItem->ClearFlags( STARTPOINT | ENDPOINT );
1926 }
1927 else if( aMode == BRIGHTENED )
1928 aItem->ClearBrightened();
1929
1930 if( aGroup )
1931 aGroup->Remove( aItem );
1932
1933 // Unhighlight pins and fields. (All the other symbol children are currently only
1934 // represented in the LIB_SYMBOL.)
1935 if( SCH_ITEM* sch_item = dynamic_cast<SCH_ITEM*>( aItem ) )
1936 {
1937 sch_item->RunOnChildren(
1938 [&]( SCH_ITEM* aChild )
1939 {
1940 if( aMode == SELECTED )
1941 aChild->ClearSelected();
1942 else if( aMode == BRIGHTENED )
1943 aChild->ClearBrightened();
1944 } );
1945 }
1946
1947 if( itemType == SCH_PIN_T || itemType == SCH_FIELD_T || itemType == SCH_SHEET_PIN_T )
1948 getView()->Update( aItem->GetParent() );
1949 else
1950 getView()->Update( aItem );
1951}
1952
1953
1955{
1956 const unsigned GRIP_MARGIN = 20;
1957 double margin = getView()->ToWorld( GRIP_MARGIN );
1958
1959 // Check if the point is located within any of the currently selected items bounding boxes
1960 for( EDA_ITEM* item : m_selection )
1961 {
1962 BOX2I itemBox = item->ViewBBox();
1963 itemBox.Inflate( margin ); // Give some margin for gripping an item
1964
1965 if( itemBox.Contains( aPoint ) )
1966 return true;
1967 }
1968
1969 return false;
1970}
1971
1972
1974{
1976
1981
1987
1989
1991}
1992
1993
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:118
static TOOL_ACTION zoomOutCenter
Definition: actions.h:96
static TOOL_ACTION zoomIn
Definition: actions.h:93
static TOOL_ACTION cursorLeftFast
Definition: actions.h:123
static TOOL_ACTION cursorDown
Definition: actions.h:117
static TOOL_ACTION zoomOut
Definition: actions.h:94
static TOOL_ACTION cursorRightFast
Definition: actions.h:124
static TOOL_ACTION zoomCenter
Definition: actions.h:97
static TOOL_ACTION panDown
Definition: actions.h:131
static TOOL_ACTION cursorDownFast
Definition: actions.h:122
static TOOL_ACTION cursorUpFast
Definition: actions.h:121
static TOOL_ACTION panLeft
Definition: actions.h:132
static TOOL_ACTION updateMenu
Definition: actions.h:171
static TOOL_ACTION zoomFitScreen
Definition: actions.h:98
static TOOL_ACTION panUp
Definition: actions.h:130
static TOOL_ACTION zoomFitObjects
Definition: actions.h:99
static TOOL_ACTION zoomInCenter
Definition: actions.h:95
static TOOL_ACTION panRight
Definition: actions.h:133
static TOOL_ACTION cursorUp
Cursor control with keyboard.
Definition: actions.h:116
static TOOL_ACTION cursorRight
Definition: actions.h:119
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:74
void SetFlags(EDA_ITEM_FLAGS aMask)
Definition: eda_item.h:139
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:141
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:181
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:222
EDA_ITEM * GetParent() const
Definition: eda_item.h:99
bool HasFlag(EDA_ITEM_FLAGS aFlag) const
Definition: eda_item.h:143
void XorFlags(EDA_ITEM_FLAGS aMask)
Definition: eda_item.h:140
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:128
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:250
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:155
static TOOL_ACTION navigateForward
Definition: ee_actions.h:201
static TOOL_ACTION slice
Definition: ee_actions.h:144
static TOOL_ACTION assignNetclass
Definition: ee_actions.h:161
static TOOL_ACTION clearSelection
Clears the current selection.
Definition: ee_actions.h:56
static TOOL_ACTION navigateBack
Definition: ee_actions.h:202
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:143
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:220
static TOOL_ACTION leaveSheet
Definition: ee_actions.h:199
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:154
static TOOL_ACTION editPageNumber
Definition: ee_actions.h:163
static TOOL_ACTION enterSheet
Definition: ee_actions.h:198
static TOOL_ACTION setUnitDisplayName
Definition: ee_actions.h:194
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:223
static const TOOL_EVENT ClearedEvent
Definition: actions.h:208
static const TOOL_EVENT SelectedEvent
Definition: actions.h:206
static const TOOL_EVENT PointSelectedEvent
Definition: actions.h:205
static const TOOL_EVENT UnselectedEvent
Definition: actions.h:207
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 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:511
virtual void SetScale(double aScale, VECTOR2D aAnchor={ 0, 0 })
Set the scaling factor, zooming around a given anchor point.
Definition: view.cpp:551
virtual void Add(VIEW_ITEM *aItem, int aDrawPriority=-1)
Add a VIEW_ITEM to the view.
Definition: view.cpp:316
virtual void Remove(VIEW_ITEM *aItem)
Remove a VIEW_ITEM from the view.
Definition: view.cpp:349
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:425
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:1591
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:448
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:1529
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:273
int GetConvert() const
Definition: lib_item.h:276
Define a library symbol object.
Definition: lib_symbol.h:99
bool IsMulti() const
Definition: lib_symbol.h:557
LIB_ITEMS_CONTAINER & GetDrawItems()
Return a reference to the draw item list.
Definition: lib_symbol.h:508
SCH_SHEET_PATH & CurrentSheet() const override
Definition: schematic.h:122
CONNECTION_GRAPH * ConnectionGraph() const override
Definition: schematic.h:132
void SetCurrentSheet(const SCH_SHEET_PATH &aPath) override
Definition: schematic.h:127
SCH_SHEET & Root() const
Definition: schematic.h:91
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.
const SCH_CONNECTION * GetHighlightedConnection() const
SCH_SHEET_PATH & GetCurrentSheet() const
SCHEMATIC & Schematic() const
void DisplayCurrentSheet()
Draw the current sheet on the display.
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:112
virtual bool IsPointClickableAnchor(const VECTOR2I &aPos) const
Definition: sch_item.h:355
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:776
bool IsStartDangling() const
Definition: sch_line.h:257
VECTOR2I GetEndPoint() const
Definition: sch_line.h:143
VECTOR2I GetStartPoint() const
Definition: sch_line.h:138
bool IsEndDangling() const
Definition: sch_line.h:258
bool IsBus() const
Return true if the line is a bus.
Definition: sch_line.cpp:943
bool IsGraphicLine() const
Return if the line is a graphic (non electrical line)
Definition: sch_line.cpp:931
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:392
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:175
Schematic symbol object.
Definition: sch_symbol.h:81
VECTOR2I GetPosition() const override
Definition: sch_symbol.h:712
TRANSFORM & GetTransform()
Definition: sch_symbol.h:283
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:192
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:215
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
@ MODEL_RELOAD
Model changes (required full reload)
Definition: tool_base.h:80
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:60
VECTOR2I TransformCoordinate(const VECTOR2I &aPoint) const
Calculate a new coordinate according to the mirror/rotation transform.
Definition: transform.cpp:45
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.
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:146
@ LIB_SYMBOL_T
Definition: typeinfo.h:198
@ LIB_TEXT_T
Definition: typeinfo.h:200
@ SCH_SYMBOL_T
Definition: typeinfo.h:156
@ LIB_TEXTBOX_T
Definition: typeinfo.h:201
@ SCH_ITEM_LOCATE_WIRE_T
Definition: typeinfo.h:170
@ SCH_FIELD_T
Definition: typeinfo.h:155
@ SCH_DIRECTIVE_LABEL_T
Definition: typeinfo.h:154
@ SCH_LABEL_T
Definition: typeinfo.h:151
@ SCH_LOCATE_ANY_T
Definition: typeinfo.h:183
@ SCH_SHEET_T
Definition: typeinfo.h:158
@ SCH_ITEM_LOCATE_BUS_T
Definition: typeinfo.h:171
@ LIB_SHAPE_T
Definition: typeinfo.h:199
@ SCH_MARKER_T
Definition: typeinfo.h:141
@ SCH_HIER_LABEL_T
Definition: typeinfo.h:153
@ SCH_BUS_BUS_ENTRY_T
Definition: typeinfo.h:145
@ LIB_PIN_T
Definition: typeinfo.h:202
@ SCH_ITEM_LOCATE_GRAPHIC_LINE_T
Definition: typeinfo.h:172
@ SCH_SHEET_PIN_T
Definition: typeinfo.h:157
@ LIB_FIELD_T
Definition: typeinfo.h:208
@ SCH_SYMBOL_LOCATE_POWER_T
Definition: typeinfo.h:180
@ SCH_BUS_WIRE_ENTRY_T
Definition: typeinfo.h:144
@ SCH_GLOBAL_LABEL_T
Definition: typeinfo.h:152
@ SCH_JUNCTION_T
Definition: typeinfo.h:142
@ SCH_PIN_T
Definition: typeinfo.h:159
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