KiCad PCB EDA Suite
Loading...
Searching...
No Matches
sch_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 The 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 <advanced_config.h>
26#include <core/typeinfo.h>
27#include <core/kicad_algo.h>
30#include <sch_actions.h>
31#include <sch_collectors.h>
32#include <sch_selection_tool.h>
33#include <sch_base_frame.h>
34#include <eeschema_id.h>
35#include <symbol_edit_frame.h>
36#include <symbol_viewer_frame.h>
37#include <math/util.h>
38#include <deque>
39#include <unordered_set>
41#include <geometry/shape_rect.h>
43#include <sch_painter.h>
45#include <sch_commit.h>
46#include <sch_edit_frame.h>
47#include <connection_graph.h>
48#include <sch_line.h>
49#include <sch_bus_entry.h>
50#include <sch_pin.h>
51#include <sch_group.h>
52#include <sch_marker.h>
53#include <sch_no_connect.h>
54#include <sch_sheet_pin.h>
55#include <sch_table.h>
56#include <tool/tool_event.h>
57#include <tool/tool_manager.h>
59#include <tools/sch_move_tool.h>
64#include <trigo.h>
65#include <view/view.h>
66#include <view/view_controls.h>
67#include <wx/log.h>
68
70
71
73{
74 if( aSel.GetSize() == 1 )
75 {
76 SCH_SYMBOL* symbol = dynamic_cast<SCH_SYMBOL*>( aSel.Front() );
77
78 if( symbol )
79 return !symbol->GetLibSymbolRef() || !symbol->GetLibSymbolRef()->IsPower();
80 }
81
82 return false;
83};
84
85
87{
88 return aSel.GetSize() == 1 && aSel.Front()->Type() == SCH_SYMBOL_T;
89};
90
91
93{
94 if( aSel.GetSize() == 1 )
95 {
96 SCH_SYMBOL* symbol = dynamic_cast<SCH_SYMBOL*>( aSel.Front() );
97
98 if( symbol )
99 return symbol->GetLibSymbolRef() && symbol->GetLibSymbolRef()->IsMultiBodyStyle();
100 }
101
102 return false;
103};
104
105
107{
108 if( aSel.GetSize() == 1 )
109 {
110 SCH_SYMBOL* symbol = dynamic_cast<SCH_SYMBOL*>( aSel.Front() );
111
112 if( symbol )
113 return symbol->GetLibSymbolRef() && symbol->GetLibSymbolRef()->GetUnitCount() >= 2;
114 }
115
116 return false;
117};
118
119
121{
122 if( aSel.GetSize() == 1 )
123 {
124 SCH_PIN* pin = dynamic_cast<SCH_PIN*>( aSel.Front() );
125
126 if( pin && pin->GetLibPin() )
127 return !pin->GetLibPin()->GetAlternates().empty();
128 }
129
130 return false;
131};
132
133
135{
136 if( aSel.CountType( SCH_MARKER_T ) != 1 )
137 return false;
138
139 return !static_cast<SCH_MARKER*>( aSel.Front() )->IsExcluded();
140};
141
142
144{
145 return aSel.GetSize() > 1 && aSel.OnlyContains( { SCH_SYMBOL_T } );
146};
147
148
150{
151 return aSel.GetSize() >= 1 && aSel.OnlyContains( { SCH_PIN_T } );
152};
153
154
156{
157 return aSel.GetSize() >= 1 && aSel.OnlyContains( { SCH_PIN_T, SCH_SHEET_PIN_T } );
158};
159
160
162{
163 for( EDA_ITEM* item : aSel.Items() )
164 {
165 if( SCH_ITEM* schItem = dynamic_cast<SCH_ITEM*>( item ) )
166 {
167 if( schItem->IsLocked() )
168 return true;
169 }
170 }
171
172 return false;
173};
174
175
177{
178 for( EDA_ITEM* item : aSel.Items() )
179 {
180 if( SCH_ITEM* schItem = dynamic_cast<SCH_ITEM*>( item ) )
181 {
182 if( !schItem->IsLocked() )
183 return true;
184 }
185 }
186
187 return false;
188};
189
190
191static void passEvent( TOOL_EVENT* const aEvent, const TOOL_ACTION* const aAllowedActions[] )
192{
193 for( int i = 0; aAllowedActions[i]; ++i )
194 {
195 if( aEvent->IsAction( aAllowedActions[i] ) )
196 {
197 aEvent->SetPassEvent();
198 break;
199 }
200 }
201}
202
203
204#define HITTEST_THRESHOLD_PIXELS 5
205
206
208 SELECTION_TOOL( "common.InteractiveSelection" ),
209 m_frame( nullptr ),
211 m_isSymbolEditor( false ),
212 m_isSymbolViewer( false ),
213 m_unit( 0 ),
214 m_bodyStyle( 0 ),
215 m_enteredGroup( nullptr ),
217 m_previous_first_cell( nullptr )
218{
219 m_filter.SetDefaults();
220 m_selection.Clear();
221}
222
223
229
230
246
247static std::vector<KICAD_T> connectedLineTypes =
248{
251};
252
272
273static std::vector<KICAD_T> crossProbingTypes =
274{
276 SCH_PIN_T,
278};
279
280static std::vector<KICAD_T> lineTypes = { SCH_LINE_T };
281static std::vector<KICAD_T> sheetTypes = { SCH_SHEET_T };
282static std::vector<KICAD_T> tableCellTypes = { SCH_TABLECELL_T };
283
285{
287
288 SYMBOL_VIEWER_FRAME* symbolViewerFrame = dynamic_cast<SYMBOL_VIEWER_FRAME*>( m_frame );
289 SYMBOL_EDIT_FRAME* symbolEditorFrame = dynamic_cast<SYMBOL_EDIT_FRAME*>( m_frame );
290
291 if( symbolEditorFrame )
292 {
293 m_isSymbolEditor = true;
294 m_unit = symbolEditorFrame->GetUnit();
295 m_bodyStyle = symbolEditorFrame->GetBodyStyle();
296 }
297 else
298 {
299 m_isSymbolViewer = symbolViewerFrame != nullptr;
300 }
301
302 // clang-format off
303 auto linesSelection = SCH_CONDITIONS::MoreThan( 0 ) && SCH_CONDITIONS::OnlyTypes( lineTypes );
304 auto wireOrBusSelection = SCH_CONDITIONS::Count( 1 ) && SCH_CONDITIONS::OnlyTypes( connectedLineTypes );
305 auto connectedSelection = SCH_CONDITIONS::MoreThan( 0 ) && SCH_CONDITIONS::OnlyTypes( connectedTypes );
306 auto expandableSelection =
308 auto sheetSelection = SCH_CONDITIONS::Count( 1 ) && SCH_CONDITIONS::OnlyTypes( sheetTypes );
309 auto crossProbingSelection = SCH_CONDITIONS::MoreThan( 0 ) && SCH_CONDITIONS::HasTypes( crossProbingTypes );
310 auto tableCellSelection = SCH_CONDITIONS::MoreThan( 0 ) && SCH_CONDITIONS::OnlyTypes( tableCellTypes );
311 auto multiplePinsSelection = SCH_CONDITIONS::MoreThan( 1 ) && SCH_CONDITIONS::OnlyTypes( { SCH_PIN_T } );
312 // clang-format on
313
314 auto schEditSheetPageNumberCondition =
315 [this] ( const SELECTION& aSel )
316 {
318 return false;
319
320 return SCH_CONDITIONS::LessThan( 2 )( aSel )
322 };
323
324 auto schEditCondition =
325 [this] ( const SELECTION& aSel )
326 {
328 };
329
330 auto belowRootSheetCondition =
331 [this]( const SELECTION& aSel )
332 {
333 SCH_EDIT_FRAME* editFrame = dynamic_cast<SCH_EDIT_FRAME*>( m_frame );
334
335 return editFrame
336 && editFrame->GetCurrentSheet().Last() != &editFrame->Schematic().Root();
337 };
338
339 auto haveHighlight =
340 [this]( const SELECTION& sel )
341 {
342 SCH_EDIT_FRAME* editFrame = dynamic_cast<SCH_EDIT_FRAME*>( m_frame );
343
344 return editFrame && !editFrame->GetHighlightedConnection().IsEmpty();
345 };
346
347 auto haveSymbol =
348 [this]( const SELECTION& sel )
349 {
350 return m_isSymbolEditor &&
351 static_cast<SYMBOL_EDIT_FRAME*>( m_frame )->GetCurSymbol();
352 };
353
354 auto groupEnterCondition =
356
357 auto inGroupCondition =
358 [this] ( const SELECTION& )
359 {
360 return m_enteredGroup != nullptr;
361 };
362
363 auto multipleUnitsSelection = []( const SELECTION& aSel )
364 {
365 return !GetSameSymbolMultiUnitSelection( aSel ).empty();
366 };
367
368 auto allowPinSwaps =
369 [this]( const SELECTION& )
370 {
371 return m_frame->eeconfig() &&
372 m_frame->eeconfig()->m_Input.allow_unconstrained_pin_swaps;
373 };
374
375
376 auto& menu = m_menu->GetMenu();
377
378 // clang-format off
379 menu.AddItem( ACTIONS::groupEnter, groupEnterCondition, 1 );
380 menu.AddItem( ACTIONS::groupLeave, inGroupCondition, 1 );
381 menu.AddItem( SCH_ACTIONS::placeLinkedDesignBlock, groupEnterCondition, 1 );
382 menu.AddItem( SCH_ACTIONS::saveToLinkedDesignBlock, groupEnterCondition, 1 );
383 menu.AddItem( SCH_ACTIONS::clearHighlight, haveHighlight && SCH_CONDITIONS::Idle, 1 );
384 menu.AddSeparator( haveHighlight && SCH_CONDITIONS::Idle, 1 );
385
386 menu.AddItem( SCH_ACTIONS::selectConnection, expandableSelection && SCH_CONDITIONS::Idle, 2 );
387 menu.AddItem( ACTIONS::selectColumns, tableCellSelection && SCH_CONDITIONS::Idle, 2 );
388 menu.AddItem( ACTIONS::selectRows, tableCellSelection && SCH_CONDITIONS::Idle, 2 );
389 menu.AddItem( ACTIONS::selectTable, tableCellSelection && SCH_CONDITIONS::Idle, 2 );
390
391 menu.AddSeparator( 100 );
392 menu.AddItem( SCH_ACTIONS::drawWire, schEditCondition && SCH_CONDITIONS::Empty, 100 );
393 menu.AddItem( SCH_ACTIONS::drawBus, schEditCondition && SCH_CONDITIONS::Empty, 100 );
394
395 menu.AddSeparator( 100 );
397
398 menu.AddItem( SCH_ACTIONS::enterSheet, sheetSelection && SCH_CONDITIONS::Idle, 150 );
399 menu.AddItem( SCH_ACTIONS::selectOnPCB, crossProbingSelection && schEditCondition && SCH_CONDITIONS::Idle, 150 );
400 menu.AddItem( SCH_ACTIONS::leaveSheet, belowRootSheetCondition, 150 );
401
402 menu.AddSeparator( 200 );
403 menu.AddItem( SCH_ACTIONS::placeJunction, wireOrBusSelection && SCH_CONDITIONS::Idle, 250 );
404 menu.AddItem( SCH_ACTIONS::placeLabel, wireOrBusSelection && SCH_CONDITIONS::Idle, 250 );
405 menu.AddItem( SCH_ACTIONS::placeClassLabel, wireOrBusSelection && SCH_CONDITIONS::Idle, 250 );
406 menu.AddItem( SCH_ACTIONS::placeGlobalLabel, wireOrBusSelection && SCH_CONDITIONS::Idle, 250 );
407 menu.AddItem( SCH_ACTIONS::placeHierLabel, wireOrBusSelection && SCH_CONDITIONS::Idle, 250 );
408 menu.AddItem( SCH_ACTIONS::breakWire, linesSelection && SCH_CONDITIONS::Idle, 250 );
409 menu.AddItem( SCH_ACTIONS::slice, linesSelection && SCH_CONDITIONS::Idle, 250 );
410 menu.AddItem( SCH_ACTIONS::placeSheetPin, sheetSelection && SCH_CONDITIONS::Idle, 250 );
411 menu.AddItem( SCH_ACTIONS::autoplaceAllSheetPins, sheetSelection && SCH_CONDITIONS::Idle, 250 );
412 menu.AddItem( SCH_ACTIONS::syncSheetPins, sheetSelection && SCH_CONDITIONS::Idle, 250 );
413 menu.AddItem( SCH_ACTIONS::swapPinLabels, multiplePinsSelection && schEditCondition && SCH_CONDITIONS::Idle, 250 );
414 menu.AddItem( SCH_ACTIONS::swapUnitLabels, multipleUnitsSelection && schEditCondition && SCH_CONDITIONS::Idle, 250 );
415 menu.AddItem( SCH_ACTIONS::swapPins, multiplePinsSelection && schEditCondition && SCH_CONDITIONS::Idle && allowPinSwaps, 250 );
416 menu.AddItem( SCH_ACTIONS::assignNetclass, connectedSelection && SCH_CONDITIONS::Idle, 250 );
417 menu.AddItem( SCH_ACTIONS::findNetInInspector, connectedSelection && SCH_CONDITIONS::Idle, 250 );
418 menu.AddItem( SCH_ACTIONS::editPageNumber, schEditSheetPageNumberCondition, 250 );
419
420 menu.AddSeparator( 400 );
421 menu.AddItem( SCH_ACTIONS::symbolProperties, haveSymbol && SCH_CONDITIONS::Empty, 400 );
422 menu.AddItem( SCH_ACTIONS::pinTable, haveSymbol && SCH_CONDITIONS::Empty, 400 );
423
424 menu.AddSeparator( 1000 );
425 m_frame->AddStandardSubMenus( *m_menu.get() );
426 // clang-format on
427
428 m_disambiguateTimer.SetOwner( this );
429 Connect( m_disambiguateTimer.GetId(), wxEVT_TIMER,
430 wxTimerEventHandler( SCH_SELECTION_TOOL::onDisambiguationExpire ), nullptr, this );
431
432 return true;
433}
434
435
437{
439
440 if( aReason != TOOL_BASE::REDRAW )
441 {
442 if( m_enteredGroup )
443 ExitGroup();
444
445 // Remove pointers to the selected items from containers without changing their
446 // properties (as they are already deleted while a new sheet is loaded)
447 m_selection.Clear();
448 }
449
450 if( aReason == RESET_REASON::SHUTDOWN )
451 return;
452
453 if( aReason == TOOL_BASE::MODEL_RELOAD || aReason == TOOL_BASE::SUPERMODEL_RELOAD )
454 {
455 getView()->GetPainter()->GetSettings()->SetHighlight( false );
456
457 SYMBOL_EDIT_FRAME* symbolEditFrame = dynamic_cast<SYMBOL_EDIT_FRAME*>( m_frame );
458 SYMBOL_VIEWER_FRAME* symbolViewerFrame = dynamic_cast<SYMBOL_VIEWER_FRAME*>( m_frame );
459
460 if( symbolEditFrame )
461 {
462 m_isSymbolEditor = true;
463 m_unit = symbolEditFrame->GetUnit();
464 m_bodyStyle = symbolEditFrame->GetBodyStyle();
465 }
466 else
467 {
468 m_isSymbolViewer = symbolViewerFrame != nullptr;
469 }
470 }
471
472 // Reinsert the VIEW_GROUP, in case it was removed from the VIEW
474 getView()->Add( &m_selection );
475
478}
479
481{
482 m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::ARROW );
483
484 KIID lastRolloverItemId = niluuid;
486
487 auto pinOrientation =
488 []( EDA_ITEM* aItem )
489 {
490 SCH_PIN* pin = dynamic_cast<SCH_PIN*>( aItem );
491
492 if( pin )
493 {
494 const SCH_SYMBOL* parent = dynamic_cast<const SCH_SYMBOL*>( pin->GetParentSymbol() );
495
496 if( !parent )
497 return pin->GetOrientation();
498 else
499 {
500 SCH_PIN dummy( *pin );
502 return dummy.GetOrientation();
503 }
504 }
505
506 SCH_SHEET_PIN* sheetPin = dynamic_cast<SCH_SHEET_PIN*>( aItem );
507
508 if( sheetPin )
509 {
510 switch( sheetPin->GetSide() )
511 {
512 default:
517 }
518 }
519
521 };
522
523 // Main loop: keep receiving events
524 while( TOOL_EVENT* evt = Wait() )
525 {
526 bool selCancelled = false;
527 bool displayWireCursor = false;
528 bool displayBusCursor = false;
529 bool displayLineCursor = false;
530 KIID rolloverItemId = lastRolloverItemId;
531
532 // on left click, a selection is made, depending on modifiers ALT, SHIFT, CTRL:
533 setModifiersState( evt->Modifier( MD_SHIFT ), evt->Modifier( MD_CTRL ),
534 evt->Modifier( MD_ALT ) );
535
536 MOUSE_DRAG_ACTION drag_action = m_frame->GetDragAction();
537
538 if( evt->IsMouseDown( BUT_LEFT ) )
539 {
540 if( !m_frame->ToolStackIsEmpty() )
541 {
542 // Avoid triggering when running under other tools
543 }
544 else if( m_toolMgr->GetTool<SCH_POINT_EDITOR>()
545 && m_toolMgr->GetTool<SCH_POINT_EDITOR>()->HasPoint() )
546 {
547 // Distinguish point editor from selection modification by checking modifiers
548 if( hasModifier() )
549 {
550 m_originalCursor = m_toolMgr->GetMousePosition();
551 m_disambiguateTimer.StartOnce( ADVANCED_CFG::GetCfg().m_DisambiguationMenuDelay );
552 }
553 }
554 else
555 {
556 m_originalCursor = m_toolMgr->GetMousePosition();
557 m_disambiguateTimer.StartOnce( ADVANCED_CFG::GetCfg().m_DisambiguationMenuDelay );
558 }
559 }
560 // Single click? Select single object
561 else if( evt->IsClick( BUT_LEFT ) )
562 {
563 // If the timer has stopped, then we have already run the disambiguate routine
564 // and we don't want to register an extra click here
565 if( !m_disambiguateTimer.IsRunning() )
566 {
567 evt->SetPassEvent();
568 continue;
569 }
570
571 m_disambiguateTimer.Stop();
572
573 if( SCH_EDIT_FRAME* schframe = dynamic_cast<SCH_EDIT_FRAME*>( m_frame ) )
574 schframe->ClearFocus();
575
576 // Collect items at the clicked location (doesn't select them yet)
577 SCH_COLLECTOR collector;
579
580 CollectHits( collector, evt->Position() );
581 size_t preFilterCount = collector.GetCount();
582 rejected.SetAll( false );
583 narrowSelection( collector, evt->Position(), false, false, &rejected );
584
585 if( m_selection.GetSize() != 0 && dynamic_cast<SCH_TABLECELL*>( m_selection.GetItem( 0 ) ) && m_additive
586 && collector.GetCount() == 1 && dynamic_cast<SCH_TABLECELL*>( collector[0] ) )
587 {
588 SCH_TABLECELL* firstCell = static_cast<SCH_TABLECELL*>( m_selection.GetItem( 0 ) );
589 SCH_TABLECELL* clickedCell = static_cast<SCH_TABLECELL*>( collector[0] );
590 bool allCellsFromSameTable = true;
591
592 if( m_previous_first_cell == nullptr || m_selection.GetSize() == 1)
593 {
594 m_previous_first_cell = firstCell;
595 }
596
598 {
599 if( !static_cast<SCH_TABLECELL*>( selection )
600 || selection->GetParent() != clickedCell->GetParent() )
601 {
602 allCellsFromSameTable = false;
603 }
604 }
605
606 if( m_previous_first_cell && clickedCell && allCellsFromSameTable )
607 {
609 selection->ClearSelected();
610
611 m_selection.Clear();
612 SCH_TABLE* parentTable = dynamic_cast<SCH_TABLE*>( m_previous_first_cell->GetParent() );
613
614 VECTOR2D start = m_previous_first_cell->GetCenter();
615 VECTOR2D end = clickedCell->GetCenter();
616
617 if( parentTable )
618 {
619 InitializeSelectionState( parentTable );
620
621 VECTOR2D topLeft( std::min( start.x, end.x ), std::min( start.y, end.y ) );
622 VECTOR2D bottomRight( std::max( start.x, end.x ), std::max( start.y, end.y ) );
623
624 SelectCellsBetween( topLeft, bottomRight - topLeft, parentTable );
625 }
626 }
627 }
628 else if( collector.GetCount() == 1 && !m_isSymbolEditor && !hasModifier() )
629 {
630 OPT_TOOL_EVENT autostart = autostartEvent( evt, grid, collector[0] );
631
632 if( autostart )
633 {
635
636 params->layer = autostart->Parameter<const DRAW_SEGMENT_EVENT_PARAMS*>()->layer;
637 params->quitOnDraw = true;
638 params->sourceSegment = dynamic_cast<SCH_LINE*>( collector[0] );
639
640 autostart->SetParameter<const DRAW_SEGMENT_EVENT_PARAMS*>( params );
641 m_toolMgr->ProcessEvent( *autostart );
642
643 selCancelled = true;
644 }
645 else if( collector[0]->HasHoveredHypertext() )
646 {
647 collector[ 0 ]->DoHypertextAction( m_frame, evt->Position() );
648 selCancelled = true;
649 }
650 else if( collector[0]->IsBrightened() )
651 {
652 if( SCH_EDIT_FRAME* schframe = dynamic_cast<SCH_EDIT_FRAME*>( m_frame ) )
653 {
654 NET_NAVIGATOR_ITEM_DATA itemData( schframe->GetCurrentSheet(), collector[0] );
655
656 schframe->SelectNetNavigatorItem( &itemData );
657 }
658 }
659 }
660
661 if( !selCancelled )
662 {
663 if( collector.GetCount() == 0 && preFilterCount > 0 )
664 {
665 if( SCH_BASE_FRAME* frame = dynamic_cast<SCH_BASE_FRAME*>( m_frame ) )
666 frame->HighlightSelectionFilter( rejected );
667 }
668
669 selectPoint( collector, evt->Position(), nullptr, nullptr, m_additive, m_subtractive, m_exclusive_or );
670 m_selection.SetIsHover( false );
671 }
672 }
673 else if( evt->IsClick( BUT_RIGHT ) )
674 {
675 m_disambiguateTimer.Stop();
676
677 // right click? if there is any object - show the context menu
678 if( m_selection.Empty() )
679 {
681 SelectPoint( evt->Position(), { SCH_LOCATE_ANY_T }, nullptr, &selCancelled );
682 m_selection.SetIsHover( true );
683 }
684 // If the cursor has moved off the bounding box of the selection by more than
685 // a grid square, check to see if there is another item available for selection
686 // under the cursor. If there is, the user likely meant to get the context menu
687 // for that item. If there is no new item, then keep the original selection and
688 // show the context menu for it.
689 else if( !m_selection.GetBoundingBox().Inflate( grid.GetGrid().x, grid.GetGrid().y )
690 .Contains( evt->Position() ) )
691 {
692 SCH_COLLECTOR collector;
693
694 if( CollectHits( collector, evt->Position(), { SCH_LOCATE_ANY_T } ) )
695 {
697
698 SelectPoint( evt->Position(), { SCH_LOCATE_ANY_T }, nullptr, &selCancelled );
699 m_selection.SetIsHover( true );
700 }
701 }
702
703 if( !selCancelled )
704 m_menu->ShowContextMenu( m_selection );
705 }
706 else if( evt->IsDblClick( BUT_LEFT ) )
707 {
708 m_disambiguateTimer.Stop();
709
710 // double click? Display the properties window
711 if( SCH_EDIT_FRAME* schframe = dynamic_cast<SCH_EDIT_FRAME*>( m_frame ) )
712 schframe->ClearFocus();
713
714 if( m_selection.Empty() )
715 SelectPoint( evt->Position() );
716
717 EDA_ITEM* item = m_selection.Front();
718
719 if( item && item->Type() == SCH_SHEET_T )
720 m_toolMgr->PostAction( SCH_ACTIONS::enterSheet );
721 else if( m_selection.GetSize() == 1 && m_selection[0]->Type() == SCH_GROUP_T )
722 EnterGroup();
723 else
724 m_toolMgr->PostAction( SCH_ACTIONS::properties );
725 }
726 else if( evt->IsDblClick( BUT_MIDDLE ) )
727 {
728 m_disambiguateTimer.Stop();
729
730 // Middle double click? Do zoom to fit or zoom to objects
731 if( evt->Modifier( MD_CTRL ) ) // Is CTRL key down?
733 else
734 m_toolMgr->RunAction( ACTIONS::zoomFitScreen );
735 }
736 else if( evt->IsDrag( BUT_LEFT ) )
737 {
738 m_disambiguateTimer.Stop();
739
740 // Is another tool already moving a new object? Don't allow a drag start
741 if( !m_selection.Empty() && m_selection[0]->HasFlag( IS_NEW | IS_MOVING ) )
742 {
743 evt->SetPassEvent();
744 continue;
745 }
746
747 // drag with LMB? Select multiple objects (or at least draw a selection box) or
748 // drag them
749 if( SCH_EDIT_FRAME* schframe = dynamic_cast<SCH_EDIT_FRAME*>( m_frame ) )
750 schframe->ClearFocus();
751
752 SCH_COLLECTOR collector;
753
754 if( m_selection.GetSize() == 1 && dynamic_cast<SCH_TABLE*>( m_selection.GetItem( 0 ) )
755 && evt->HasPosition() && selectionContains( evt->DragOrigin() ) )
756 {
757 m_toolMgr->RunAction( SCH_ACTIONS::move );
758 }
759 // Allow drag selecting table cells, except when they're inside a group that we haven't entered
760 else if( CollectHits( collector, evt->DragOrigin(), { SCH_TABLECELL_T } )
761 && ( collector[0]->GetParent()->GetParentGroup() == nullptr
762 || collector[0]->GetParent()->GetParentGroup() == m_enteredGroup ) )
763 {
764 selectTableCells( static_cast<SCH_TABLE*>( collector[0]->GetParent() ) );
765 }
766 else if( hasModifier() || drag_action == MOUSE_DRAG_ACTION::SELECT )
767 {
770 selectLasso();
771 else
773 }
774 else if( m_selection.Empty() && drag_action != MOUSE_DRAG_ACTION::DRAG_ANY )
775 {
778 selectLasso();
779 else
781 }
782 else
783 {
784 if( m_isSymbolEditor )
785 {
786 if( static_cast<SYMBOL_EDIT_FRAME*>( m_frame )->IsSymbolAlias() )
787 {
789 }
790 else
791 {
795 SCH_PIN_T,
796 SCH_FIELD_T } );
797 }
798 }
799 else
800 {
802 }
803
804 // Check if dragging has started within any of selected items bounding box
805 if( evt->HasPosition() && selectionContains( evt->DragOrigin() ) )
806 {
807 // drag_is_move option exists only in schematic editor, not in symbol editor
808 // (m_frame->eeconfig() returns nullptr in Symbol Editor)
809 if( m_isSymbolEditor || m_frame->eeconfig()->m_Input.drag_is_move )
810 m_toolMgr->RunAction( SCH_ACTIONS::move );
811 else
812 m_toolMgr->RunAction( SCH_ACTIONS::drag );
813 }
814 else
815 {
816 // No -> drag a selection box
819 selectLasso();
820 else
822 }
823 }
824 }
825 else if( evt->IsMouseDown( BUT_AUX1 ) )
826 {
828 }
829 else if( evt->IsMouseDown( BUT_AUX2 ) )
830 {
832 }
833 else if( evt->Action() == TA_MOUSE_WHEEL )
834 {
835 int field = -1;
836
837 if( evt->Modifier() == ( MD_SHIFT | MD_ALT ) )
838 field = 0;
839 else if( evt->Modifier() == ( MD_CTRL | MD_ALT ) )
840 field = 1;
841 // any more?
842
843 if( field >= 0 )
844 {
845 const int delta = evt->Parameter<int>();
846 ACTIONS::INCREMENT incParams{ delta > 0 ? 1 : -1, field };
847
848 m_toolMgr->RunAction( ACTIONS::increment, incParams );
849 }
850 }
851 else if( evt->Category() == TC_COMMAND && evt->Action() == TA_CHOICE_MENU_CHOICE )
852 {
853 m_disambiguateTimer.Stop();
854
855 // context sub-menu selection? Handle unit selection or bus unfolding
856 if( *evt->GetCommandId() >= ID_POPUP_SCH_SELECT_UNIT
857 && *evt->GetCommandId() <= ID_POPUP_SCH_SELECT_UNIT_END )
858 {
859 SCH_SYMBOL* symbol = dynamic_cast<SCH_SYMBOL*>( m_selection.Front() );
860 int unit = *evt->GetCommandId() - ID_POPUP_SCH_SELECT_UNIT;
861
862 if( symbol )
863 static_cast<SCH_EDIT_FRAME*>( m_frame )->SelectUnit( symbol, unit );
864 }
865 else if( *evt->GetCommandId() >= ID_POPUP_SCH_PLACE_UNIT
866 && *evt->GetCommandId() <= ID_POPUP_SCH_PLACE_UNIT_END )
867 {
868 SCH_SYMBOL* symbol = dynamic_cast<SCH_SYMBOL*>( m_selection.Front() );
869 int unit = *evt->GetCommandId() - ID_POPUP_SCH_PLACE_UNIT;
870
871 if( symbol )
874 }
875 else if( *evt->GetCommandId() >= ID_POPUP_SCH_SELECT_BODY_STYLE
876 && *evt->GetCommandId() <= ID_POPUP_SCH_SELECT_BODY_STYLE_END )
877 {
878 SCH_SYMBOL* symbol = dynamic_cast<SCH_SYMBOL*>( m_selection.Front() );
879 int bodyStyle = ( *evt->GetCommandId() - ID_POPUP_SCH_SELECT_BODY_STYLE ) + 1;
880
881 if( symbol && symbol->GetBodyStyle() != bodyStyle )
882 static_cast<SCH_EDIT_FRAME*>( m_frame )->SelectBodyStyle( symbol, bodyStyle );
883 }
884 else if( *evt->GetCommandId() >= ID_POPUP_SCH_ALT_PIN_FUNCTION
885 && *evt->GetCommandId() <= ID_POPUP_SCH_ALT_PIN_FUNCTION_END )
886 {
887 SCH_PIN* pin = dynamic_cast<SCH_PIN*>( m_selection.Front() );
888 wxString alt = *evt->Parameter<wxString*>();
889
890 if( pin )
891 static_cast<SCH_EDIT_FRAME*>( m_frame )->SetAltPinFunction( pin, alt );
892 }
893 else if( *evt->GetCommandId() >= ID_POPUP_SCH_PIN_TRICKS_START
894 && *evt->GetCommandId() <= ID_POPUP_SCH_PIN_TRICKS_END
896 {
897 SCH_EDIT_FRAME* sch_frame = static_cast<SCH_EDIT_FRAME*>( m_frame );
898
899 // Keep track of new items so we make them the new selection at the end
900 EDA_ITEMS newItems;
901 SCH_COMMIT commit( sch_frame );
902
903 if( *evt->GetCommandId() == ID_POPUP_SCH_PIN_TRICKS_NO_CONNECT )
904 {
905 for( EDA_ITEM* item : m_selection )
906 {
907 if( item->Type() != SCH_PIN_T && item->Type() != SCH_SHEET_PIN_T )
908 continue;
909
910 SCH_NO_CONNECT* nc = new SCH_NO_CONNECT( item->GetPosition() );
911 commit.Add( nc, sch_frame->GetScreen() );
912 newItems.push_back( nc );
913 }
914
915 if( !commit.Empty() )
916 {
917 commit.Push( wxS( "No Connect Pins" ) );
919 }
920 }
921 else if( *evt->GetCommandId() == ID_POPUP_SCH_PIN_TRICKS_WIRE )
922 {
923 VECTOR2I wireGrid = grid.GetGridSize( GRID_HELPER_GRIDS::GRID_WIRES );
924
925 for( EDA_ITEM* item : m_selection )
926 {
927 if( item->Type() != SCH_PIN_T && item->Type() != SCH_SHEET_PIN_T )
928 continue;
929
930 SCH_LINE* wire = new SCH_LINE( item->GetPosition(), LAYER_WIRE );
931
932 // Add some length to the wire as nothing in our code base handles
933 // 0 length wires very well, least of all the ortho drag algorithm
934 VECTOR2I stub;
935
936 switch( pinOrientation( item ) )
937 {
938 default:
940 stub = VECTOR2I( -1 * wireGrid.x, 0 );
941 break;
943 stub = VECTOR2I( 1 * wireGrid.x, 0 );
944 break;
946 stub = VECTOR2I( 0, 1 * wireGrid.y );
947 break;
949 stub = VECTOR2I( 0, -1 * wireGrid.y );
950 break;
951 }
952
953 wire->SetEndPoint( item->GetPosition() + stub );
954
955 m_frame->AddToScreen( wire, sch_frame->GetScreen() );
956 commit.Added( wire, sch_frame->GetScreen() );
957 newItems.push_back( wire );
958 }
959
960 if( !commit.Empty() )
961 {
963 AddItemsToSel( &newItems );
964
965 // Select only the ends so we can immediately start dragging them
966 for( EDA_ITEM* item : newItems )
967 static_cast<SCH_LINE*>( item )->SetFlags( ENDPOINT );
968
970
971 // Put the mouse on the nearest point of the first wire
972 SCH_LINE* first = static_cast<SCH_LINE*>( newItems[0] );
973 vc->SetCrossHairCursorPosition( first->GetEndPoint(), false );
974 vc->WarpMouseCursor( vc->GetCursorPosition(), true );
975
976 // Start the drag tool, canceling will remove the wires
977 if( m_toolMgr->RunSynchronousAction( SCH_ACTIONS::drag, &commit ) )
978 commit.Push( wxS( "Wire Pins" ) );
979 else
980 commit.Revert();
981 }
982 }
983 else
984 {
985 // For every pin in the selection, add a label according to menu item
986 // selected by the user
987 for( EDA_ITEM* item : m_selection )
988 {
989 SCH_PIN* pin = dynamic_cast<SCH_PIN*>( item );
990 SCH_SHEET_PIN* sheetPin = dynamic_cast<SCH_SHEET_PIN*>( item );
991 SCH_LABEL_BASE* label = nullptr;
992 SCH_SHEET_PATH& sheetPath = sch_frame->GetCurrentSheet();
993
994 wxString labelText;
995
996 if( pin )
997 {
998 labelText = pin->GetShownName();
999
1000 if( labelText.IsEmpty() )
1001 {
1002 labelText.Printf( "%s_%s",
1003 pin->GetParentSymbol()->GetRef( &sheetPath ),
1004 pin->GetNumber() );
1005 }
1006 }
1007 else if( sheetPin )
1008 {
1009 labelText = sheetPin->GetShownText( &sheetPath, false );
1010 }
1011 else
1012 {
1013 continue;
1014 }
1015
1016 switch( *evt->GetCommandId() )
1017 {
1019 label = new SCH_LABEL( item->GetPosition(), labelText );
1020 break;
1022 label = new SCH_HIERLABEL( item->GetPosition(), labelText );
1023 break;
1025 label = new SCH_GLOBALLABEL( item->GetPosition(), labelText );
1026 break;
1027 default:
1028 continue;
1029 }
1030
1031 switch( pinOrientation( item ) )
1032 {
1033 default:
1036 break;
1039 break;
1042 break;
1045 break;
1046 }
1047
1049
1050 if( pin )
1051 {
1052 pinType = pin->GetType();
1053 }
1054 else if( sheetPin )
1055 {
1056 switch( sheetPin->GetLabelShape() )
1057 {
1058 case LABEL_INPUT: pinType = ELECTRICAL_PINTYPE::PT_INPUT; break;
1059 case LABEL_OUTPUT: pinType = ELECTRICAL_PINTYPE::PT_OUTPUT; break;
1060 case LABEL_BIDI: pinType = ELECTRICAL_PINTYPE::PT_BIDI; break;
1061 case LABEL_TRISTATE: pinType = ELECTRICAL_PINTYPE::PT_TRISTATE; break;
1062 case LABEL_PASSIVE: pinType = ELECTRICAL_PINTYPE::PT_PASSIVE; break;
1063 }
1064 }
1065
1066 switch( pinType )
1067 {
1070 break;
1073 break;
1076 break;
1079 break;
1082 break;
1083 default:
1085 }
1086
1087 commit.Add( label, sch_frame->GetScreen() );
1088 newItems.push_back( label );
1089 }
1090
1091 if( !commit.Empty() )
1092 {
1093 commit.Push( wxS( "Label Pins" ) );
1094
1095 // Many users will want to drag these items to wire off of the pins, so
1096 // pre-select them.
1098 AddItemsToSel( &newItems );
1099 }
1100 }
1101 }
1102 else if( *evt->GetCommandId() >= ID_POPUP_SCH_UNFOLD_BUS
1103 && *evt->GetCommandId() <= ID_POPUP_SCH_UNFOLD_BUS_END )
1104 {
1105 wxString* net = new wxString( *evt->Parameter<wxString*>() );
1106 m_toolMgr->RunAction<wxString*>( SCH_ACTIONS::unfoldBus, net );
1107 }
1108 }
1109 else if( evt->IsCancelInteractive() )
1110 {
1111 m_disambiguateTimer.Stop();
1112
1113 // We didn't set these, but we have reports that they leak out of some other tools,
1114 // so we clear them here.
1115 getViewControls()->SetAutoPan( false );
1116 getViewControls()->CaptureCursor( false );
1117
1118 if( SCH_EDIT_FRAME* schframe = dynamic_cast<SCH_EDIT_FRAME*>( m_frame ) )
1119 schframe->ClearFocus();
1120
1121 if( !GetSelection().Empty() )
1122 {
1124 }
1125 else if( evt->FirstResponder() == this && evt->GetCommandId() == (int) WXK_ESCAPE )
1126 {
1127 if( m_enteredGroup )
1128 {
1129 ExitGroup();
1130 }
1131 else
1132 {
1134
1135 if( editor && m_frame->eeconfig()->m_Input.esc_clears_net_highlight )
1136 editor->ClearHighlight( *evt );
1137 }
1138 }
1139 }
1140 else if( evt->Action() == TA_UNDO_REDO_PRE )
1141 {
1142 if( SCH_EDIT_FRAME* schframe = dynamic_cast<SCH_EDIT_FRAME*>( m_frame ) )
1143 schframe->ClearFocus();
1144 }
1145 else if( evt->IsMotion() && !m_isSymbolEditor && evt->FirstResponder() == this )
1146 {
1147 // Update cursor and rollover item
1148 rolloverItemId = niluuid;
1149 SCH_COLLECTOR collector;
1150
1152
1153 if( CollectHits( collector, evt->Position() ) )
1154 {
1155 narrowSelection( collector, evt->Position(), false, false, nullptr );
1156
1157 if( collector.GetCount() == 1 && !hasModifier() )
1158 {
1159 OPT_TOOL_EVENT autostartEvt = autostartEvent( evt, grid, collector[0] );
1160
1161 if( autostartEvt )
1162 {
1163 if( autostartEvt->Matches( SCH_ACTIONS::drawBus.MakeEvent() ) )
1164 displayBusCursor = true;
1165 else if( autostartEvt->Matches( SCH_ACTIONS::drawWire.MakeEvent() ) )
1166 displayWireCursor = true;
1167 else if( autostartEvt->Matches( SCH_ACTIONS::drawLines.MakeEvent() ) )
1168 displayLineCursor = true;
1169 }
1170 else if( collector[0]->HasHypertext() && !collector[0]->IsSelected() )
1171 {
1172 rolloverItemId = collector[0]->m_Uuid;
1173 }
1174 }
1175 }
1176 }
1177 else
1178 {
1179 evt->SetPassEvent();
1180 }
1181
1182 if( lastRolloverItemId != niluuid && lastRolloverItemId != rolloverItemId )
1183 {
1184 EDA_ITEM* item = m_frame->ResolveItem( lastRolloverItemId );
1185
1186 item->SetIsRollover( false, { 0, 0 } );
1187
1188 if( item->Type() == SCH_FIELD_T || item->Type() == SCH_TABLECELL_T )
1189 m_frame->GetCanvas()->GetView()->Update( item->GetParent() );
1190 else
1191 m_frame->GetCanvas()->GetView()->Update( item );
1192 }
1193
1194 SCH_ITEM* rolloverItem = nullptr;
1195
1196 if( rolloverItemId != niluuid )
1197 {
1198 rolloverItem = static_cast<SCH_ITEM*>( m_frame->ResolveItem( rolloverItemId ) );
1199
1200 rolloverItem->SetIsRollover( true, getViewControls()->GetMousePosition() );
1201
1202 if( rolloverItem->Type() == SCH_FIELD_T || rolloverItem->Type() == SCH_TABLECELL_T )
1203 m_frame->GetCanvas()->GetView()->Update( rolloverItem->GetParent() );
1204 else
1205 m_frame->GetCanvas()->GetView()->Update( rolloverItem );
1206 }
1207
1208 lastRolloverItemId = rolloverItemId;
1209
1210 if( m_frame->ToolStackIsEmpty() )
1211 {
1212 if( displayWireCursor )
1213 {
1215 }
1216 else if( displayBusCursor )
1217 {
1219 }
1220 else if( displayLineCursor )
1221 {
1223 }
1224 else if( rolloverItem && rolloverItem->HasHoveredHypertext() )
1225 {
1227 }
1228 else if( !m_selection.Empty()
1229 && drag_action == MOUSE_DRAG_ACTION::DRAG_SELECTED
1230 && evt->HasPosition()
1231 && selectionContains( evt->Position() ) //move/drag option prediction
1232 )
1233 {
1235 }
1236 else
1237 {
1239 }
1240 }
1241 }
1242
1243 m_disambiguateTimer.Stop();
1244
1245 // Shutting down; clear the selection
1246 m_selection.Clear();
1247
1248 return 0;
1249}
1250
1251
1253{
1254 wxCHECK_RET( m_selection.GetSize() == 1 && m_selection[0]->Type() == SCH_GROUP_T,
1255 wxT( "EnterGroup called when selection is not a single group" ) );
1256 SCH_GROUP* aGroup = static_cast<SCH_GROUP*>( m_selection[0] );
1257
1258 if( m_enteredGroup != nullptr )
1259 ExitGroup();
1260
1262 m_enteredGroup = aGroup;
1263 m_enteredGroup->SetFlags( ENTERED );
1264 m_enteredGroup->RunOnChildren(
1265 [&]( SCH_ITEM* aChild )
1266 {
1267 if( aChild->Type() == SCH_LINE_T )
1268 aChild->SetFlags( STARTPOINT | ENDPOINT );
1269
1270 select( aChild );
1271 },
1273
1274 m_toolMgr->ProcessEvent( EVENTS::SelectedEvent );
1275
1276 getView()->Hide( m_enteredGroup, true );
1279}
1280
1281
1282void SCH_SELECTION_TOOL::ExitGroup( bool aSelectGroup )
1283{
1284 // Only continue if there is a group entered
1285 if( m_enteredGroup == nullptr )
1286 return;
1287
1288 m_enteredGroup->ClearFlags( ENTERED );
1289 getView()->Hide( m_enteredGroup, false );
1291
1292 if( aSelectGroup )
1293 {
1295 m_toolMgr->ProcessEvent( EVENTS::SelectedEvent );
1296 }
1297
1298 m_enteredGroupOverlay.Clear();
1299 m_enteredGroup = nullptr;
1301}
1302
1303
1305 SCH_ITEM* aItem )
1306{
1307 VECTOR2I pos = aGrid.BestSnapAnchor( aEvent->Position(), aGrid.GetItemGrid( aItem ) );
1308
1309 if( m_frame->eeconfig()->m_Drawing.auto_start_wires
1310 && !m_toolMgr->GetTool<SCH_POINT_EDITOR>()->HasPoint()
1311 && aItem->IsPointClickableAnchor( pos ) )
1312 {
1313 OPT_TOOL_EVENT newEvt = SCH_ACTIONS::drawWire.MakeEvent();
1314
1315 if( aItem->Type() == SCH_BUS_BUS_ENTRY_T )
1316 {
1317 newEvt = SCH_ACTIONS::drawBus.MakeEvent();
1318 }
1319 else if( aItem->Type() == SCH_BUS_WIRE_ENTRY_T )
1320 {
1321 SCH_BUS_WIRE_ENTRY* busEntry = static_cast<SCH_BUS_WIRE_ENTRY*>( aItem );
1322
1323 if( !busEntry->m_connected_bus_item )
1324 newEvt = SCH_ACTIONS::drawBus.MakeEvent();
1325 }
1326 else if( aItem->Type() == SCH_LINE_T )
1327 {
1328 SCH_LINE* line = static_cast<SCH_LINE*>( aItem );
1329
1330 if( line->IsBus() )
1331 newEvt = SCH_ACTIONS::drawBus.MakeEvent();
1332 else if( line->IsGraphicLine() )
1333 newEvt = SCH_ACTIONS::drawLines.MakeEvent();
1334 }
1335 else if( aItem->Type() == SCH_LABEL_T || aItem->Type() == SCH_HIER_LABEL_T
1336 || aItem->Type() == SCH_SHEET_PIN_T || aItem->Type() == SCH_GLOBAL_LABEL_T )
1337 {
1338 SCH_LABEL_BASE* label = static_cast<SCH_LABEL_BASE*>( aItem );
1339 SCH_CONNECTION possibleConnection( label->Schematic()->ConnectionGraph() );
1340 possibleConnection.ConfigureFromLabel( label->GetShownText( false ) );
1341
1342 if( possibleConnection.IsBus() )
1343 newEvt = SCH_ACTIONS::drawBus.MakeEvent();
1344 }
1345 else if( aItem->Type() == SCH_SYMBOL_T )
1346 {
1347 const SCH_SYMBOL* symbol = static_cast<const SCH_SYMBOL*>( aItem );
1348 const SCH_PIN* pin = symbol->GetPin( pos );
1349
1350 if( !pin || !pin->IsPointClickableAnchor( pos ) )
1351 return OPT_TOOL_EVENT();
1352
1353 if( !pin->IsVisible()
1354 && !( m_frame->eeconfig()->m_Appearance.show_hidden_pins
1355 || m_frame->GetRenderSettings()->m_ShowHiddenPins ) )
1356 {
1357 return OPT_TOOL_EVENT();
1358 }
1359 }
1360
1361 newEvt->SetMousePosition( pos );
1362 newEvt->SetHasPosition( true );
1363 newEvt->SetForceImmediate( true );
1364
1365 getViewControls()->ForceCursorPosition( true, pos );
1366
1367 return newEvt;
1368 }
1369
1370 return OPT_TOOL_EVENT();
1371}
1372
1373
1375{
1376 wxMouseState keyboardState = wxGetMouseState();
1377
1378 setModifiersState( keyboardState.ShiftDown(), keyboardState.ControlDown(),
1379 keyboardState.AltDown() );
1380
1381 m_skip_heuristics = true;
1384 m_skip_heuristics = false;
1385
1386 return 0;
1387}
1388
1389
1390void SCH_SELECTION_TOOL::OnIdle( wxIdleEvent& aEvent )
1391{
1392 if( m_frame->ToolStackIsEmpty() && !m_multiple )
1393 {
1394 wxMouseState keyboardState = wxGetMouseState();
1395
1396 setModifiersState( keyboardState.ShiftDown(), keyboardState.ControlDown(),
1397 keyboardState.AltDown() );
1398
1399 if( m_additive )
1400 m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::ADD );
1401 else if( m_subtractive )
1402 m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::SUBTRACT );
1403 else if( m_exclusive_or )
1404 m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::XOR );
1405 else
1406 m_frame->GetCanvas()->SetCurrentCursor( m_nonModifiedCursor );
1407 }
1408}
1409
1410
1415
1416
1418 const std::vector<KICAD_T>& aScanTypes )
1419{
1420 int pixelThreshold = KiROUND( getView()->ToWorld( HITTEST_THRESHOLD_PIXELS ) );
1421 int gridThreshold = KiROUND( getView()->GetGAL()->GetGridSize().EuclideanNorm() / 2.0 );
1422 aCollector.m_Threshold = std::max( pixelThreshold, gridThreshold );
1423 aCollector.m_ShowPinElectricalTypes = m_frame->GetRenderSettings()->m_ShowPinsElectricalType;
1424
1425 if( m_isSymbolEditor )
1426 {
1427 LIB_SYMBOL* symbol = static_cast<SYMBOL_EDIT_FRAME*>( m_frame )->GetCurSymbol();
1428
1429 if( !symbol )
1430 return false;
1431
1432 aCollector.Collect( symbol->GetDrawItems(), aScanTypes, aWhere, m_unit, m_bodyStyle );
1433 }
1434 else
1435 {
1436 aCollector.Collect( m_frame->GetScreen(), aScanTypes, aWhere, m_unit, m_bodyStyle );
1437
1438 // If pins are disabled in the filter, they will be removed later. Let's add the parent
1439 // so that people can use pins to select symbols in this case.
1440 if( !m_filter.pins )
1441 {
1442 int originalCount = aCollector.GetCount();
1443
1444 for( int ii = 0; ii < originalCount; ++ii )
1445 {
1446 if( aCollector[ii]->Type() == SCH_PIN_T )
1447 {
1448 SCH_PIN* pin = static_cast<SCH_PIN*>( aCollector[ii] );
1449
1450 if( !aCollector.HasItem( pin->GetParentSymbol() ) )
1451 aCollector.Append( pin->GetParentSymbol() );
1452 }
1453 }
1454 }
1455 }
1456
1457 return aCollector.GetCount() > 0;
1458}
1459
1460
1462 bool aCheckLocked, bool aSelectedOnly,
1463 SCH_SELECTION_FILTER_OPTIONS* aRejected )
1464{
1465 SYMBOL_EDIT_FRAME* symbolEditorFrame = dynamic_cast<SYMBOL_EDIT_FRAME*>( m_frame );
1466
1467 for( int i = collector.GetCount() - 1; i >= 0; --i )
1468 {
1469 if( symbolEditorFrame )
1470 {
1471 // Do not select invisible items if they are not displayed
1472 EDA_ITEM* item = collector[i];
1473
1474 if( item->Type() == SCH_FIELD_T )
1475 {
1476 if( !static_cast<SCH_FIELD*>( item )->IsVisible()
1477 && !symbolEditorFrame->GetShowInvisibleFields() )
1478 {
1479 collector.Remove( i );
1480 continue;
1481 }
1482 }
1483 else if( item->Type() == SCH_PIN_T )
1484 {
1485 if( !static_cast<SCH_PIN*>( item )->IsVisible()
1486 && !symbolEditorFrame->GetShowInvisiblePins() )
1487 {
1488 collector.Remove( i );
1489 continue;
1490 }
1491 }
1492 }
1493
1494 if( !Selectable( collector[i], &aWhere ) )
1495 {
1496 collector.Remove( i );
1497 continue;
1498 }
1499
1500 if( aCheckLocked && collector[i]->IsLocked() )
1501 {
1502 if( aRejected )
1503 aRejected->lockedItems = true;
1504 collector.Remove( i );
1505 continue;
1506 }
1507
1508 if( !itemPassesFilter( collector[i], aRejected ) )
1509 {
1510 collector.Remove( i );
1511 continue;
1512 }
1513
1514 if( aSelectedOnly && !collector[i]->IsSelected() )
1515 {
1516 collector.Remove( i );
1517 continue;
1518 }
1519 }
1520
1521 filterCollectorForHierarchy( collector, false );
1522
1523 // Apply some ugly heuristics to avoid disambiguation menus whenever possible
1524 if( collector.GetCount() > 1 && !m_skip_heuristics )
1525 GuessSelectionCandidates( collector, aWhere );
1526}
1527
1528
1530 EDA_ITEM** aItem, bool* aSelectionCancelledFlag, bool aAdd,
1531 bool aSubtract, bool aExclusiveOr )
1532{
1533 m_selection.ClearReferencePoint();
1534
1535 // If still more than one item we're going to have to ask the user.
1536 if( aCollector.GetCount() > 1 )
1537 {
1538 // Try to call selectionMenu via RunAction() to avoid event-loop contention
1539 // But it we cannot handle the event, then we don't have an active tool loop, so
1540 // handle it directly.
1541 if( !m_toolMgr->RunAction<COLLECTOR*>( ACTIONS::selectionMenu, &aCollector ) )
1542 {
1543 if( !doSelectionMenu( &aCollector ) )
1544 aCollector.m_MenuCancelled = true;
1545 }
1546
1547 if( aCollector.m_MenuCancelled )
1548 {
1549 if( aSelectionCancelledFlag )
1550 *aSelectionCancelledFlag = true;
1551
1552 return false;
1553 }
1554 }
1555
1556 if( !aAdd && !aSubtract && !aExclusiveOr )
1558
1559 // It is possible for slop in the selection model to cause us to be outside the group,
1560 // but also selecting an item within the group, so only exit if the selection doesn't
1561 // have an item belonging to the group
1562 if( m_enteredGroup && !m_enteredGroup->GetBoundingBox().Contains( aWhere ) )
1563 {
1564 bool foundEnteredGroup = false;
1565 for( EDA_ITEM* item : aCollector )
1566 {
1567 if( item->GetParentGroup() == m_enteredGroup )
1568 {
1569 foundEnteredGroup = true;
1570 break;
1571 }
1572 }
1573
1574 if( !foundEnteredGroup )
1575 ExitGroup();
1576 }
1577
1578 filterCollectorForHierarchy( aCollector, true );
1579
1580 int addedCount = 0;
1581 bool anySubtracted = false;
1582
1583 if( aCollector.GetCount() > 0 )
1584 {
1585 for( int i = 0; i < aCollector.GetCount(); ++i )
1586 {
1587 EDA_ITEM_FLAGS flags = 0;
1588 bool isLine = aCollector[i]->Type() == SCH_LINE_T;
1589
1590 // Handle line ends specially
1591 if( isLine )
1592 {
1593 SCH_LINE* line = (SCH_LINE*) aCollector[i];
1594
1595 if( line->GetStartPoint().Distance( aWhere ) <= aCollector.m_Threshold )
1596 flags = STARTPOINT;
1597 else if( line->GetEndPoint().Distance( aWhere ) <= aCollector.m_Threshold )
1598 flags = ENDPOINT;
1599 else
1600 flags = STARTPOINT | ENDPOINT;
1601 }
1602
1603 if( aSubtract
1604 || ( aExclusiveOr && aCollector[i]->IsSelected()
1605 && ( !isLine || ( isLine && aCollector[i]->HasFlag( flags ) ) ) ) )
1606 {
1607 aCollector[i]->ClearFlags( flags );
1608
1609 // Need to update end shadows after ctrl-click unselecting one of two selected
1610 // endpoints.
1611 if( isLine )
1612 getView()->Update( aCollector[i] );
1613
1614 if( !aCollector[i]->HasFlag( STARTPOINT ) && !aCollector[i]->HasFlag( ENDPOINT ) )
1615 {
1616 unselect( aCollector[i] );
1617 anySubtracted = true;
1618 }
1619 }
1620 else
1621 {
1622 aCollector[i]->SetFlags( flags );
1623 select( aCollector[i] );
1624 addedCount++;
1625 }
1626 }
1627 }
1628
1629 if( addedCount == 1 )
1630 {
1631 m_toolMgr->ProcessEvent( EVENTS::PointSelectedEvent );
1632
1633 if( aItem && aCollector.GetCount() == 1 )
1634 *aItem = aCollector[0];
1635
1636 return true;
1637 }
1638 else if( addedCount > 1 )
1639 {
1640 m_toolMgr->ProcessEvent( EVENTS::SelectedEvent );
1641 return true;
1642 }
1643 else if( anySubtracted )
1644 {
1645 m_toolMgr->ProcessEvent( EVENTS::UnselectedEvent );
1646 return true;
1647 }
1648
1649 m_frame->GetCanvas()->ForceRefresh();
1650 return false;
1651}
1652
1653
1655 const std::vector<KICAD_T>& aScanTypes,
1656 EDA_ITEM** aItem, bool* aSelectionCancelledFlag,
1657 bool aCheckLocked, bool aAdd, bool aSubtract,
1658 bool aExclusiveOr )
1659{
1660 SCH_COLLECTOR collector;
1661
1662 if( !CollectHits( collector, aWhere, aScanTypes ) )
1663 return false;
1664
1665 size_t preFilterCount = collector.GetCount();
1667 rejected.SetAll( false );
1668 narrowSelection( collector, aWhere, aCheckLocked, aSubtract, &rejected );
1669
1670 if( collector.GetCount() == 0 && preFilterCount > 0 )
1671 {
1672 if( SCH_BASE_FRAME* frame = dynamic_cast<SCH_BASE_FRAME*>( m_frame ) )
1673 frame->HighlightSelectionFilter( rejected );
1674
1675 if( !aAdd && !aSubtract && !aExclusiveOr && m_selection.GetSize() > 0 )
1676 {
1677 ClearSelection( true /*quiet mode*/ );
1678 m_toolMgr->ProcessEvent( EVENTS::UnselectedEvent );
1679 }
1680
1681 return false;
1682 }
1683
1684 return selectPoint( collector, aWhere, aItem, aSelectionCancelledFlag, aAdd, aSubtract,
1685 aExclusiveOr );
1686}
1687
1688
1690{
1691 SCH_COLLECTOR collection;
1692 m_multiple = true; // Multiple selection mode is active
1693 KIGFX::VIEW* view = getView();
1694
1695 std::vector<EDA_ITEM*> sheetPins;
1696
1697 // Filter the view items based on the selection box
1698 BOX2I selectionBox;
1699
1700 selectionBox.SetMaximum();
1701 view->Query( selectionBox,
1702 [&]( KIGFX::VIEW_ITEM* viewItem ) -> bool
1703 {
1704 SCH_ITEM* item = static_cast<SCH_ITEM*>( viewItem );
1705
1706 if( !item )
1707 return true;
1708
1709 collection.Append( item );
1710 return true;
1711 } );
1712
1713 filterCollectorForHierarchy( collection, true );
1714
1715 // Sheet pins aren't in the view; add them by hand
1716 for( EDA_ITEM* item : collection )
1717 {
1718 SCH_SHEET* sheet = dynamic_cast<SCH_SHEET*>( item );
1719
1720 if( sheet )
1721 {
1722 for( SCH_SHEET_PIN* pin : sheet->GetPins() )
1723 sheetPins.emplace_back( pin );
1724 }
1725 }
1726
1727 for( EDA_ITEM* pin : sheetPins )
1728 collection.Append( pin );
1729
1730 for( EDA_ITEM* item : collection )
1731 {
1732 if( Selectable( item ) && itemPassesFilter( item, nullptr ) )
1733 {
1734 if( item->Type() == SCH_LINE_T )
1735 item->SetFlags( STARTPOINT | ENDPOINT );
1736
1737 select( item );
1738 }
1739 }
1740
1741 m_multiple = false;
1742
1743 m_toolMgr->ProcessEvent( EVENTS::SelectedEvent );
1744 m_frame->GetCanvas()->ForceRefresh();
1745 return 0;
1746}
1747
1749{
1750 m_multiple = true; // Multiple selection mode is active
1751 KIGFX::VIEW* view = getView();
1752
1753 // hold all visible items
1754 std::vector<KIGFX::VIEW::LAYER_ITEM_PAIR> selectedItems;
1755
1756 // Filter the view items based on the selection box
1757 BOX2I selectionBox;
1758
1759 selectionBox.SetMaximum();
1760 view->Query( selectionBox, selectedItems ); // Get the list of selected items
1761
1762 for( KIGFX::VIEW::LAYER_ITEM_PAIR& pair : selectedItems )
1763 {
1764 SCH_SHEET* sheet = dynamic_cast<SCH_SHEET*>( pair.first );
1765
1766 if( sheet )
1767 {
1768 for( SCH_SHEET_PIN* pin : sheet->GetPins() )
1769 {
1770 EDA_ITEM* item = dynamic_cast<EDA_ITEM*>( pin );
1771
1772 if( item && Selectable( item ) )
1773 unselect( item );
1774 }
1775 }
1776
1777 if( EDA_ITEM* item = dynamic_cast<EDA_ITEM*>( pair.first ) )
1778 {
1779 if( Selectable( item ) )
1780 unselect( item );
1781 }
1782 }
1783
1784 m_multiple = false;
1785
1786 m_toolMgr->ProcessEvent( EVENTS::UnselectedEvent );
1787 m_frame->GetCanvas()->ForceRefresh();
1788 return 0;
1789}
1790
1791
1793{
1794 // Prefer exact hits to sloppy ones
1795 std::set<EDA_ITEM*> exactHits;
1796
1797 for( int i = collector.GetCount() - 1; i >= 0; --i )
1798 {
1799 EDA_ITEM* item = collector[ i ];
1800 SCH_LINE* line = dynamic_cast<SCH_LINE*>( item );
1801 SCH_SHAPE* shape = dynamic_cast<SCH_SHAPE*>( item );
1802 SCH_TABLE* table = dynamic_cast<SCH_TABLE*>( item );
1803
1804 // Lines are hard to hit. Give them a bit more slop to still be considered "exact".
1805 if( line || ( shape && shape->GetShape() == SHAPE_T::POLY )
1806 || ( shape && shape->GetShape() == SHAPE_T::ARC ) )
1807 {
1808 int pixelThreshold = KiROUND( getView()->ToWorld( 6 ) );
1809
1810 if( item->HitTest( aPos, pixelThreshold ) )
1811 exactHits.insert( item );
1812 }
1813 else if( table )
1814 {
1815 // Consider table cells exact, but not the table itself
1816 }
1817 else
1818 {
1819
1820 if( m_frame->GetRenderSettings()->m_ShowPinsElectricalType )
1821 item->SetFlags( SHOW_ELEC_TYPE );
1822
1823 if( item->HitTest( aPos, 0 ) )
1824 exactHits.insert( item );
1825
1826 item->ClearFlags( SHOW_ELEC_TYPE );
1827 }
1828 }
1829
1830 if( exactHits.size() > 0 && exactHits.size() < (unsigned) collector.GetCount() )
1831 {
1832 for( int i = collector.GetCount() - 1; i >= 0; --i )
1833 {
1834 EDA_ITEM* item = collector[ i ];
1835
1836 if( !exactHits.contains( item ) )
1837 collector.Transfer( item );
1838 }
1839 }
1840
1841 // Find the closest item. (Note that at this point all hits are either exact or non-exact.)
1842 SEG poss( aPos, aPos );
1843 EDA_ITEM* closest = nullptr;
1844 int closestDist = INT_MAX / 4;
1845
1846 for( EDA_ITEM* item : collector )
1847 {
1848 BOX2I bbox = item->GetBoundingBox();
1849 int dist = INT_MAX / 4;
1850
1851 // A dominating item is one that would unfairly win distance tests
1852 // and mask out other items. For example, a filled rectangle "wins"
1853 // with a zero distance over anything inside it.
1854 bool dominating = false;
1855
1856 if( exactHits.contains( item ) )
1857 {
1858 if( item->Type() == SCH_PIN_T || item->Type() == SCH_JUNCTION_T )
1859 {
1860 closest = item;
1861 break;
1862 }
1863
1864 SCH_LINE* line = dynamic_cast<SCH_LINE*>( item );
1865 SCH_FIELD* field = dynamic_cast<SCH_FIELD*>( item );
1866 EDA_TEXT* text = dynamic_cast<EDA_TEXT*>( item );
1867 EDA_SHAPE* shape = dynamic_cast<EDA_SHAPE*>( item );
1868 SCH_SYMBOL* symbol = dynamic_cast<SCH_SYMBOL*>( item );
1869
1870 if( line )
1871 {
1872 dist = line->GetSeg().Distance( aPos );
1873 }
1874 else if( field )
1875 {
1876 BOX2I box = field->GetBoundingBox();
1877 EDA_ANGLE orient = field->GetTextAngle();
1878
1879 if( field->GetParent() && field->GetParent()->Type() == SCH_SYMBOL_T )
1880 {
1881 if( static_cast<SCH_SYMBOL*>( field->GetParent() )->GetTransform().y1 )
1882 {
1883 if( orient.IsHorizontal() )
1884 orient = ANGLE_VERTICAL;
1885 else
1886 orient = ANGLE_HORIZONTAL;
1887 }
1888 }
1889
1890 field->GetEffectiveTextShape( false, box, orient )->Collide( poss, INT_MAX / 4, &dist );
1891 }
1892 else if( text )
1893 {
1894 text->GetEffectiveTextShape( false )->Collide( poss, INT_MAX / 4, &dist );
1895 }
1896 else if( shape )
1897 {
1898 auto shapes = std::make_shared<SHAPE_COMPOUND>( shape->MakeEffectiveShapesForHitTesting() );
1899
1900 shapes->Collide( poss, INT_MAX / 4, &dist );
1901
1902 // Filled shapes win hit tests anywhere inside them
1903 dominating = shape->IsFilledForHitTesting();
1904 }
1905 else if( symbol )
1906 {
1907 bbox = symbol->GetBodyBoundingBox();
1908
1909 SHAPE_RECT rect( bbox.GetPosition(), bbox.GetWidth(), bbox.GetHeight() );
1910
1911 if( bbox.Contains( aPos ) )
1912 dist = bbox.GetCenter().Distance( aPos );
1913 else
1914 rect.Collide( poss, closestDist, &dist );
1915 }
1916 else
1917 {
1918 dist = bbox.GetCenter().Distance( aPos );
1919 }
1920 }
1921 else
1922 {
1923 SHAPE_RECT rect( bbox.GetPosition(), bbox.GetWidth(), bbox.GetHeight() );
1924 rect.Collide( poss, collector.m_Threshold, &dist );
1925 }
1926
1927 // Don't promote dominating items to be the closest item
1928 // (they'll always win) - they'll still be available for selection, but they
1929 // won't boot out worthy competitors.
1930 if ( !dominating )
1931 {
1932 if( dist == closestDist )
1933 {
1934 if( item->GetParent() == closest )
1935 closest = item;
1936 }
1937 else if( dist < closestDist )
1938 {
1939 closestDist = dist;
1940 closest = item;
1941 }
1942 }
1943 }
1944
1945 // Construct a tight box (1/2 height and width) around the center of the closest item.
1946 // All items which exist at least partly outside this box have sufficient other areas
1947 // for selection and can be dropped.
1948 if( closest ) // Don't try and get a tight bbox if nothing is near the mouse pointer
1949 {
1950 BOX2I tightBox = closest->GetBoundingBox();
1951 tightBox.Inflate( -tightBox.GetWidth() / 4, -tightBox.GetHeight() / 4 );
1952
1953 for( int i = collector.GetCount() - 1; i >= 0; --i )
1954 {
1955 EDA_ITEM* item = collector[i];
1956
1957 if( item == closest )
1958 continue;
1959
1960 if( !item->HitTest( tightBox, true ) )
1961 collector.Transfer( item );
1962 }
1963 }
1964}
1965
1966
1967SCH_SELECTION& SCH_SELECTION_TOOL::RequestSelection( const std::vector<KICAD_T>& aScanTypes,
1968 bool aPromoteCellSelections,
1969 bool aPromoteGroups )
1970{
1971 bool anyUnselected = false;
1972 bool anySelected = false;
1973
1974 if( m_selection.Empty() )
1975 {
1976 VECTOR2D cursorPos = getViewControls()->GetCursorPosition( true );
1977
1979 SelectPoint( cursorPos, aScanTypes );
1980 m_selection.SetIsHover( true );
1981 m_selection.ClearReferencePoint();
1982 }
1983 else // Trim an existing selection by aFilterList
1984 {
1985 bool isMoving = false;
1986
1987 for( int i = (int) m_selection.GetSize() - 1; i >= 0; --i )
1988 {
1989 EDA_ITEM* item = (EDA_ITEM*) m_selection.GetItem( i );
1990 isMoving |= static_cast<SCH_ITEM*>( item )->IsMoving();
1991
1992 if( !item->IsType( aScanTypes ) )
1993 {
1994 unselect( item );
1995 anyUnselected = true;
1996 }
1997 }
1998
1999 if( !isMoving )
2001 }
2002
2003 if( aPromoteGroups )
2004 {
2005 for( int i = (int) m_selection.GetSize() - 1; i >= 0; --i )
2006 {
2007 EDA_ITEM* item = (EDA_ITEM*) m_selection.GetItem( i );
2008
2009 std::set<EDA_ITEM*> selectedChildren;
2010
2011 if( item->Type() == SCH_GROUP_T )
2012 {
2013 static_cast<SCH_ITEM*>(item)->RunOnChildren( [&]( SCH_ITEM* aChild )
2014 {
2015 if( aChild->IsType( aScanTypes ) )
2016 selectedChildren.insert( aChild );
2017 },
2019 unselect( item );
2020 anyUnselected = true;
2021 }
2022
2023 for( EDA_ITEM* child : selectedChildren )
2024 {
2025 if( !child->IsSelected() )
2026 {
2027 if( child->Type() == SCH_LINE_T )
2028 static_cast<SCH_LINE*>( child )->SetFlags( STARTPOINT | ENDPOINT );
2029
2030 select( child );
2031 anySelected = true;
2032 }
2033 }
2034 }
2035 }
2036
2037 if( aPromoteCellSelections )
2038 {
2039 std::set<EDA_ITEM*> parents;
2040
2041 for( int i = (int) m_selection.GetSize() - 1; i >= 0; --i )
2042 {
2043 EDA_ITEM* item = (EDA_ITEM*) m_selection.GetItem( i );
2044
2045 if( item->Type() == SCH_TABLECELL_T )
2046 {
2047 parents.insert( item->GetParent() );
2048 unselect( item );
2049 anyUnselected = true;
2050 }
2051 }
2052
2053 for( EDA_ITEM* parent : parents )
2054 {
2055 if( !parent->IsSelected() )
2056 {
2057 select( parent );
2058 anySelected = true;
2059 }
2060 }
2061 }
2062
2063 if( anyUnselected )
2064 m_toolMgr->ProcessEvent( EVENTS::UnselectedEvent );
2065
2066 if( anySelected )
2067 m_toolMgr->ProcessEvent( EVENTS::SelectedEvent );
2068
2069 return m_selection;
2070}
2071
2072
2073void SCH_SELECTION_TOOL::filterCollectedItems( SCH_COLLECTOR& aCollector, bool aMultiSelect )
2074{
2075 if( aCollector.GetCount() == 0 )
2076 return;
2077
2078 std::set<EDA_ITEM*> rejected;
2079
2080 for( EDA_ITEM* item : aCollector )
2081 {
2082 if( !itemPassesFilter( item, nullptr ) )
2083 rejected.insert( item );
2084 }
2085
2086 for( EDA_ITEM* item : rejected )
2087 aCollector.Remove( item );
2088}
2089
2090
2092{
2093 if( !aItem )
2094 return false;
2095
2096 if( SCH_ITEM* schItem = dynamic_cast<SCH_ITEM*>( aItem ) )
2097 {
2098 if( schItem->IsLocked() && !m_filter.lockedItems )
2099 {
2100 if( aRejected )
2101 aRejected->lockedItems = true;
2102
2103 return false;
2104 }
2105 }
2106
2107 switch( aItem->Type() )
2108 {
2109 case SCH_SYMBOL_T:
2110 case SCH_SHEET_T:
2111 if( !m_filter.symbols )
2112 {
2113 if( aRejected )
2114 aRejected->symbols = true;
2115 return false;
2116 }
2117
2118 break;
2119
2120 case SCH_PIN_T:
2121 case SCH_SHEET_PIN_T:
2122 if( !m_filter.pins )
2123 {
2124 if( aRejected )
2125 aRejected->pins = true;
2126 return false;
2127 }
2128
2129 break;
2130
2131 case SCH_JUNCTION_T:
2132 if( !m_filter.wires )
2133 {
2134 if( aRejected )
2135 aRejected->wires = true;
2136 return false;
2137 }
2138
2139 break;
2140
2141 case SCH_LINE_T:
2142 {
2143 switch( static_cast<SCH_LINE*>( aItem )->GetLayer() )
2144 {
2145 case LAYER_WIRE:
2146 case LAYER_BUS:
2147 if( !m_filter.wires )
2148 {
2149 if( aRejected )
2150 aRejected->wires = true;
2151 return false;
2152 }
2153
2154 break;
2155
2156 default:
2157 if( !m_filter.graphics )
2158 {
2159 if( aRejected )
2160 aRejected->graphics = true;
2161 return false;
2162 }
2163 }
2164
2165 break;
2166 }
2167
2168 case SCH_SHAPE_T:
2169 if( !m_filter.graphics )
2170 {
2171 if( aRejected )
2172 aRejected->graphics = true;
2173 return false;
2174 }
2175
2176 break;
2177
2178 case SCH_TEXT_T:
2179 case SCH_TEXTBOX_T:
2180 case SCH_TABLE_T:
2181 case SCH_TABLECELL_T:
2182 case SCH_FIELD_T:
2183 if( !m_filter.text )
2184 {
2185 if( aRejected )
2186 aRejected->text = true;
2187 return false;
2188 }
2189
2190 break;
2191
2192 case SCH_LABEL_T:
2193 case SCH_GLOBAL_LABEL_T:
2194 case SCH_HIER_LABEL_T:
2195 if( !m_filter.labels )
2196 {
2197 if( aRejected )
2198 aRejected->labels = true;
2199 return false;
2200 }
2201
2202 break;
2203
2204 case SCH_BITMAP_T:
2205 if( !m_filter.images )
2206 {
2207 if( aRejected )
2208 aRejected->images = true;
2209 return false;
2210 }
2211
2212 break;
2213
2214 case SCH_RULE_AREA_T:
2215 if( !m_filter.ruleAreas )
2216 {
2217 if( aRejected )
2218 aRejected->ruleAreas = true;
2219 return false;
2220 }
2221
2222 break;
2223
2224 default:
2225 if( !m_filter.otherItems )
2226 {
2227 if( aRejected )
2228 aRejected->otherItems = true;
2229 return false;
2230 }
2231
2232 break;
2233 }
2234
2235 return true;
2236}
2237
2238
2240{
2241 VECTOR2I refP( 0, 0 );
2242
2243 if( m_selection.Size() > 0 )
2244 refP = static_cast<SCH_ITEM*>( m_selection.GetTopLeftItem() )->GetPosition();
2245
2246 m_selection.SetReferencePoint( refP );
2247}
2248
2249
2251{
2253 m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::SELECT_LASSO );
2254 m_toolMgr->PostAction( ACTIONS::selectionTool );
2255 return 0;
2256}
2257
2258
2260{
2262 m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::ARROW );
2263 m_toolMgr->PostAction( ACTIONS::selectionTool );
2264 return 0;
2265}
2266
2267
2268// Some navigation actions are allowed in selectMultiple
2279
2280
2282{
2283 // Block selection not allowed in symbol viewer frame: no actual code to handle
2284 // a selection, so return to avoid to draw a selection rectangle, and to avoid crashes.
2285 if( m_frame->IsType( FRAME_T::FRAME_SCH_VIEWER ) )
2286 return false;
2287
2288 bool cancelled = false; // Was the tool canceled while it was running?
2289 m_multiple = true; // Multiple selection mode is active
2290 KIGFX::VIEW* view = getView();
2291
2293 view->Add( &area );
2294
2295 while( TOOL_EVENT* evt = Wait() )
2296 {
2297 /* Selection mode depends on direction of drag-selection:
2298 * Left > Right : Select objects that are fully enclosed by selection
2299 * Right > Left : Select objects that are crossed by selection
2300 */
2301 bool isGreedy = area.GetEnd().x < area.GetOrigin().x;
2302
2303 if( view->IsMirroredX() )
2304 isGreedy = !isGreedy;
2305
2306 m_frame->GetCanvas()->SetCurrentCursor( isGreedy ? KICURSOR::SELECT_LASSO
2308
2309 if( evt->IsCancelInteractive() || evt->IsActivate() )
2310 {
2311 cancelled = true;
2312 break;
2313 }
2314
2315 if( evt->IsDrag( BUT_LEFT ) )
2316 {
2319
2320 // Start drawing a selection box
2321 area.SetOrigin( evt->DragOrigin() );
2322 area.SetEnd( evt->Position() );
2325 area.SetExclusiveOr( false );
2328
2329 view->SetVisible( &area, true );
2330 view->Update( &area );
2331 getViewControls()->SetAutoPan( true );
2332 }
2333
2334 if( evt->IsMouseUp( BUT_LEFT ) )
2335 {
2336 getViewControls()->SetAutoPan( false );
2337 view->SetVisible( &area, false );
2338 SelectMultiple( area, m_drag_subtractive, false );
2339 evt->SetPassEvent( false );
2340 break;
2341 }
2342
2343 passEvent( evt, allowedActions );
2344 }
2345
2346 getViewControls()->SetAutoPan( false );
2347
2348 // Stop drawing the selection box
2349 view->Remove( &area );
2350 m_multiple = false; // Multiple selection mode is inactive
2351
2352 if( !cancelled )
2353 m_selection.ClearReferencePoint();
2354
2355 return cancelled;
2356}
2357
2358
2360{
2361 bool cancelled = false;
2362 m_multiple = true;
2364 getView()->Add( &area );
2365 getView()->SetVisible( &area, true );
2366 getViewControls()->SetAutoPan( true );
2367
2368 SHAPE_LINE_CHAIN points;
2369 points.SetClosed( true );
2370
2372 m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::SELECT_LASSO );
2373
2374 while( TOOL_EVENT* evt = Wait() )
2375 {
2376 double shapeArea = area.GetPoly().Area( false );
2377 bool isClockwise = shapeArea > 0 ? true : false;
2378
2379 if( getView()->IsMirroredX() && shapeArea != 0 )
2380 isClockwise = !isClockwise;
2381
2382 if( isClockwise )
2383 {
2384 selectionMode = SELECTION_MODE::INSIDE_LASSO;
2385 m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::SELECT_WINDOW );
2386 }
2387 else
2388 {
2389 selectionMode = SELECTION_MODE::TOUCHING_LASSO;
2390 m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::SELECT_LASSO );
2391 }
2392
2393 if( evt->IsCancelInteractive() || evt->IsActivate() )
2394 {
2395 cancelled = true;
2396 break;
2397 }
2398 else if( evt->IsDrag( BUT_LEFT )
2399 || evt->IsClick( BUT_LEFT )
2400 || evt->IsAction( &ACTIONS::cursorClick ) )
2401 {
2402 points.Append( evt->Position() );
2403 }
2404 else if( evt->IsDblClick( BUT_LEFT )
2405 || evt->IsAction( &ACTIONS::cursorDblClick )
2406 || evt->IsAction( &ACTIONS::finishInteractive ) )
2407 {
2408 area.GetPoly().GenerateBBoxCache();
2409 SelectMultiple( area, m_drag_subtractive, false );
2410 break;
2411 }
2412 else if( evt->IsAction( &ACTIONS::doDelete )
2413 || evt->IsAction( &ACTIONS::undo ) )
2414 {
2415 if( points.GetPointCount() > 0 )
2416 {
2418 points.Remove( points.GetPointCount() - 1 );
2419 }
2420 }
2421 else
2422 {
2423 passEvent( evt, allowedActions );
2424 }
2425
2426 if( points.PointCount() > 0 )
2427 {
2429 {
2430 if( m_selection.GetSize() > 0 )
2431 {
2432 ClearSelection( true );
2433 m_toolMgr->ProcessEvent( EVENTS::UnselectedEvent );
2434 }
2435 }
2436 }
2437
2438 area.SetPoly( points );
2439 area.GetPoly().Append( m_toolMgr->GetMousePosition() );
2442 area.SetExclusiveOr( false );
2443 area.SetMode( selectionMode );
2444 getView()->Update( &area );
2445 }
2446
2447 getViewControls()->SetAutoPan( false );
2448 getView()->SetVisible( &area, false );
2449 getView()->Remove( &area );
2450 m_multiple = false;
2451
2452 if( !cancelled )
2453 m_selection.ClearReferencePoint();
2454
2455 return cancelled;
2456}
2457
2458
2460 bool aExclusiveOr )
2461{
2462 KIGFX::VIEW* view = getView();
2463
2464 SELECTION_MODE selectionMode = aArea.GetMode();
2465 bool containedMode = ( selectionMode == SELECTION_MODE::INSIDE_RECTANGLE
2466 || selectionMode == SELECTION_MODE::INSIDE_LASSO );
2467 bool boxMode = ( selectionMode == SELECTION_MODE::INSIDE_RECTANGLE
2468 || selectionMode == SELECTION_MODE::TOUCHING_RECTANGLE );
2469
2470 std::vector<KIGFX::VIEW::LAYER_ITEM_PAIR> candidates;
2471 BOX2I selectionRect = aArea.ViewBBox();
2472 view->Query( selectionRect, candidates );
2473
2474 std::set<SCH_ITEM*> uniqueCandidates;
2475
2476 for( const auto& [viewItem, layer] : candidates )
2477 {
2478 if( viewItem->IsSCH_ITEM() )
2479 uniqueCandidates.insert( static_cast<SCH_ITEM*>( viewItem ) );
2480 }
2481
2482 for( KIGFX::VIEW_ITEM* item : uniqueCandidates )
2483 {
2484 if( SCH_SHEET* sheet = dynamic_cast<SCH_SHEET*>( item ) )
2485 {
2486 for( SCH_SHEET_PIN* pin : sheet->GetPins() )
2487 {
2488 if( boxMode ? selectionRect.Intersects( pin->GetBoundingBox() )
2489 : KIGEOM::BoxHitTest( aArea.GetPoly(), pin->GetBoundingBox(), true ) )
2490 uniqueCandidates.insert( pin );
2491 }
2492 }
2493 else if( SCH_SYMBOL* symbol = dynamic_cast<SCH_SYMBOL*>( item ) )
2494 {
2495 for( SCH_PIN* pin : symbol->GetPins() )
2496 {
2497 if( boxMode ? selectionRect.Intersects( pin->GetBoundingBox() )
2498 : KIGEOM::BoxHitTest( aArea.GetPoly(), pin->GetBoundingBox(), true ) )
2499 uniqueCandidates.insert( pin );
2500 }
2501
2502 for( SCH_FIELD& field : symbol->GetFields() )
2503 {
2504 if( field.IsVisible()
2505 && ( boxMode ? selectionRect.Intersects( field.GetBoundingBox() )
2506 : KIGEOM::BoxHitTest( aArea.GetPoly(), field.GetBoundingBox(), true ) ) )
2507 {
2508 uniqueCandidates.insert( &field );
2509 }
2510 }
2511 }
2512 }
2513
2514 SCH_COLLECTOR collector;
2515 SCH_COLLECTOR pinsCollector;
2516 std::set<EDA_ITEM*> group_items;
2517
2518 for( EDA_ITEM* item : m_frame->GetScreen()->Items().OfType( SCH_GROUP_T ) )
2519 {
2520 SCH_GROUP* group = static_cast<SCH_GROUP*>( item );
2521
2522 if( m_enteredGroup == group )
2523 continue;
2524
2525 std::unordered_set<EDA_ITEM*>& newset = group->GetItems();
2526
2527 auto boxContained =
2528 [&]( const BOX2I& aBox )
2529 {
2530 return boxMode ? selectionRect.Contains( aBox )
2531 : KIGEOM::BoxHitTest( aArea.GetPoly(), aBox, true );
2532 };
2533
2534 if( containedMode && boxContained( group->GetBoundingBox() ) && newset.size() )
2535 {
2536 for( EDA_ITEM* group_item : newset )
2537 {
2538 if( !group_item->IsSCH_ITEM() )
2539 continue;
2540
2541 if( Selectable( static_cast<SCH_ITEM*>( group_item ) ) )
2542 collector.Append( group_item );
2543 }
2544 }
2545
2546 for( EDA_ITEM* group_item : newset )
2547 group_items.emplace( group_item );
2548 }
2549
2550 auto hitTest =
2551 [&]( SCH_ITEM* aItem )
2552 {
2553 return boxMode ? aItem->HitTest( selectionRect, containedMode )
2554 : aItem->HitTest( aArea.GetPoly(), containedMode );
2555 };
2556
2557 for( SCH_ITEM* item : uniqueCandidates )
2558 {
2559 if( Selectable( item ) && ( hitTest( item ) || item->Type() == SCH_LINE_T )
2560 && ( !containedMode || !group_items.count( item ) ) )
2561 {
2562 if( item->Type() == SCH_PIN_T && !m_isSymbolEditor )
2563 pinsCollector.Append( item );
2564 else
2565 collector.Append( item );
2566 }
2567 }
2568
2569 filterCollectedItems( collector, true );
2570 filterCollectorForHierarchy( collector, true );
2571
2572 if( collector.GetCount() == 0 )
2573 {
2574 collector = pinsCollector;
2575 filterCollectedItems( collector, true );
2576 filterCollectorForHierarchy( collector, true );
2577 }
2578
2579 std::sort( collector.begin(), collector.end(),
2580 []( EDA_ITEM* a, EDA_ITEM* b )
2581 {
2582 VECTOR2I aPos = a->GetPosition();
2583 VECTOR2I bPos = b->GetPosition();
2584
2585 if( aPos.y == bPos.y )
2586 return aPos.x < bPos.x;
2587
2588 return aPos.y < bPos.y;
2589 } );
2590
2591 bool anyAdded = false;
2592 bool anySubtracted = false;
2593
2594 auto selectItem =
2595 [&]( EDA_ITEM* aItem, EDA_ITEM_FLAGS flags )
2596 {
2597 if( aSubtractive || ( aExclusiveOr && aItem->IsSelected() ) )
2598 {
2599 if( aExclusiveOr )
2600 aItem->XorFlags( flags );
2601 else
2602 aItem->ClearFlags( flags );
2603
2604 if( !aItem->HasFlag( STARTPOINT ) && !aItem->HasFlag( ENDPOINT ) )
2605 {
2606 unselect( aItem );
2607 anySubtracted = true;
2608 }
2609
2610 if( flags && !anySubtracted )
2611 getView()->Update( aItem );
2612 }
2613 else
2614 {
2615 aItem->SetFlags( flags );
2616 select( aItem );
2617 anyAdded = true;
2618 }
2619 };
2620
2621 std::vector<EDA_ITEM*> flaggedItems;
2622
2623 auto shapeContains =
2624 [&]( const VECTOR2I& aPoint )
2625 {
2626 return boxMode ? selectionRect.Contains( aPoint )
2627 : aArea.GetPoly().PointInside( aPoint );
2628 };
2629
2630 for( EDA_ITEM* item : collector )
2631 {
2632 EDA_ITEM_FLAGS flags = 0;
2633
2634 item->SetFlags( SELECTION_CANDIDATE );
2635 flaggedItems.push_back( item );
2636
2637 if( m_frame->GetRenderSettings()->m_ShowPinsElectricalType )
2638 item->SetFlags( SHOW_ELEC_TYPE );
2639
2640 if( item->Type() == SCH_LINE_T )
2641 {
2642 SCH_LINE* line = static_cast<SCH_LINE*>( item );
2643 bool hits = false;
2644
2645 if( boxMode )
2646 hits = line->HitTest( selectionRect, false );
2647 else
2648 hits = line->HitTest( aArea.GetPoly(), false );
2649
2650 if( ( !containedMode && hits )
2651 || ( shapeContains( line->GetEndPoint() ) && shapeContains( line->GetStartPoint() ) ) )
2652 {
2653 flags |= STARTPOINT | ENDPOINT;
2654 }
2655 else if( containedMode )
2656 {
2657 if( shapeContains( line->GetStartPoint() ) && line->IsStartDangling() )
2658 flags |= STARTPOINT;
2659
2660 if( shapeContains( line->GetEndPoint() ) && line->IsEndDangling() )
2661 flags |= ENDPOINT;
2662 }
2663
2664 if( flags & ( STARTPOINT | ENDPOINT ) )
2665 selectItem( item, flags );
2666 }
2667 else
2668 selectItem( item, flags );
2669
2670 item->ClearFlags( SHOW_ELEC_TYPE );
2671 }
2672
2673 for( EDA_ITEM* item : pinsCollector )
2674 {
2675 if( m_frame->GetRenderSettings()->m_ShowPinsElectricalType )
2676 item->SetFlags( SHOW_ELEC_TYPE );
2677
2678 // If the pin lives inside a group that is already being selected, don't also select the pin.
2679 if( EDA_GROUP* group =
2681 {
2682 if( collector.HasItem( group->AsEdaItem() ) )
2683 {
2684 item->ClearFlags( SHOW_ELEC_TYPE );
2685 continue;
2686 }
2687 }
2688
2689 if( Selectable( item ) && itemPassesFilter( item, nullptr )
2690 && !item->GetParent()->HasFlag( SELECTION_CANDIDATE ) && hitTest( static_cast<SCH_ITEM*>( item ) ) )
2691 {
2692 selectItem( item, 0 );
2693 }
2694
2695 item->ClearFlags( SHOW_ELEC_TYPE );
2696 }
2697
2698 for( EDA_ITEM* item : flaggedItems )
2699 item->ClearFlags( SELECTION_CANDIDATE );
2700
2701 m_selection.SetIsHover( false );
2702
2703 if( anyAdded )
2704 m_toolMgr->ProcessEvent( EVENTS::SelectedEvent );
2705 else if( anySubtracted )
2706 m_toolMgr->ProcessEvent( EVENTS::UnselectedEvent );
2707}
2708
2709
2711 bool aMultiselect ) const
2712{
2713 std::unordered_set<EDA_ITEM*> toAdd;
2714
2715 // Set SELECTION_CANDIDATE on all parents which are included in the GENERAL_COLLECTOR. This
2716 // algorithm is O(3n), whereas checking for the parent inclusion could potentially be O(n^2).
2717 for( int j = 0; j < aCollector.GetCount(); j++ )
2718 {
2719 if( aCollector[j]->GetParent() )
2720 aCollector[j]->GetParent()->ClearFlags( SELECTION_CANDIDATE );
2721
2722 if( aCollector[j]->GetParentSymbol() )
2723 aCollector[j]->GetParentSymbol()->ClearFlags( SELECTION_CANDIDATE );
2724 }
2725
2726 if( aMultiselect )
2727 {
2728 for( int j = 0; j < aCollector.GetCount(); j++ )
2729 aCollector[j]->SetFlags( SELECTION_CANDIDATE );
2730 }
2731
2732 for( int j = 0; j < aCollector.GetCount(); )
2733 {
2734 SCH_ITEM* item = aCollector[j];
2735 SYMBOL* sym = item->GetParentSymbol();
2736 SCH_ITEM* start = item;
2737
2738 if( !m_isSymbolEditor && sym )
2739 start = sym;
2740
2741 // If a group is entered, disallow selections of objects outside the group.
2743 {
2744 aCollector.Remove( item );
2745 continue;
2746 }
2747
2748 // If any element is a member of a group, replace those elements with the top containing
2749 // group.
2751 {
2752 if( top->AsEdaItem() != item )
2753 {
2754 toAdd.insert( top->AsEdaItem() );
2755 top->AsEdaItem()->SetFlags( SELECTION_CANDIDATE );
2756
2757 aCollector.Remove( item );
2758 continue;
2759 }
2760 }
2761
2762 // Symbols are a bit easier as they can't be nested.
2763 if( sym && ( sym->GetFlags() & SELECTION_CANDIDATE ) )
2764 {
2765 // Remove children of selected items
2766 aCollector.Remove( item );
2767 continue;
2768 }
2769
2770 ++j;
2771 }
2772
2773 for( EDA_ITEM* item : toAdd )
2774 {
2775 if( !aCollector.HasItem( item ) )
2776 aCollector.Append( item );
2777 }
2778}
2779
2780
2782{
2783 if( m_frame && m_frame->GetOverrideLocks() )
2784 return;
2785
2786 std::vector<EDA_ITEM*> toRemove;
2787
2788 for( EDA_ITEM* item : m_selection )
2789 {
2790 if( SCH_ITEM* schItem = dynamic_cast<SCH_ITEM*>( item ) )
2791 {
2792 bool lockedDescendant = false;
2793
2794 schItem->RunOnChildren(
2795 [&]( SCH_ITEM* child )
2796 {
2797 if( child->IsLocked() )
2798 lockedDescendant = true;
2799 },
2801
2802 if( schItem->IsLocked() || lockedDescendant )
2803 toRemove.push_back( item );
2804 }
2805 }
2806
2807 for( EDA_ITEM* item : toRemove )
2808 RemoveItemFromSel( item, true /* quiet mode */ );
2809}
2810
2811
2813{
2814 getView()->Update( &m_selection );
2816
2817 return 0;
2818}
2819
2820
2822{
2823 for( SCH_TABLECELL* cell : aTable->GetCells() )
2824 {
2825 if( cell->IsSelected() )
2826 cell->SetFlags( SELECTION_CANDIDATE );
2827 else
2828 cell->ClearFlags( SELECTION_CANDIDATE );
2829 }
2830}
2831
2833{
2834 BOX2I selectionRect( start, end );
2835 selectionRect.Normalize();
2836
2837 auto wasSelected = []( EDA_ITEM* aItem )
2838 {
2839 return ( aItem->GetFlags() & SELECTION_CANDIDATE ) > 0;
2840 };
2841
2842 for( SCH_TABLECELL* cell : aTable->GetCells() )
2843 {
2844 bool doSelect = false;
2845
2846 if( cell->HitTest( selectionRect, false ) )
2847 {
2848 if( m_subtractive )
2849 doSelect = false;
2850 else if( m_exclusive_or )
2851 doSelect = !wasSelected( cell );
2852 else
2853 doSelect = true;
2854 }
2855 else if( wasSelected( cell ) )
2856 {
2857 doSelect = m_additive || m_subtractive || m_exclusive_or;
2858 }
2859
2860 if( doSelect && !cell->IsSelected() )
2861 select( cell );
2862 else if( !doSelect && cell->IsSelected() )
2863 unselect( cell );
2864 }
2865}
2866
2868{
2869 bool cancelled = false;
2870 m_multiple = true;
2871
2872 InitializeSelectionState( aTable );
2873
2874 while( TOOL_EVENT* evt = Wait() )
2875 {
2876 if( evt->IsCancelInteractive() || evt->IsActivate() )
2877 {
2878 cancelled = true;
2879 break;
2880 }
2881 else if( evt->IsDrag( BUT_LEFT ) )
2882 {
2883 getViewControls()->SetAutoPan( true );
2884 SelectCellsBetween( evt->DragOrigin(), evt->Position() - evt->DragOrigin(), aTable );
2885 }
2886 else if( evt->IsMouseUp( BUT_LEFT ) )
2887 {
2888 m_selection.SetIsHover( false );
2889
2890 bool anyAdded = false;
2891 bool anySubtracted = false;
2892
2893 for( SCH_TABLECELL* cell : aTable->GetCells() )
2894 {
2895 if( cell->IsSelected() && ( cell->GetFlags() & SELECTION_CANDIDATE ) <= 0 )
2896 anyAdded = true;
2897 else if( ( cell->GetFlags() & SELECTION_CANDIDATE ) > 0 && !cell->IsSelected() )
2898 anySubtracted = true;
2899 }
2900
2901 if( anyAdded )
2902 m_toolMgr->ProcessEvent( EVENTS::SelectedEvent );
2903 if( anySubtracted )
2904 m_toolMgr->ProcessEvent( EVENTS::UnselectedEvent );
2905
2906 break;
2907 }
2908 else
2909 {
2910 for( int i = 0; allowedActions[i]; ++i )
2911 {
2912 if( evt->IsAction( allowedActions[i] ) )
2913 {
2914 evt->SetPassEvent();
2915 break;
2916 }
2917 }
2918 }
2919 }
2920
2921 getViewControls()->SetAutoPan( false );
2922
2923 m_multiple = false;
2924
2925 if( !cancelled )
2926 m_selection.ClearReferencePoint();
2927
2928 return cancelled;
2929}
2930
2931
2933{
2934 SCH_COLLECTOR collector;
2935
2936 //TODO(snh): Reimplement after exposing KNN interface
2937 int pixelThreshold = KiROUND( getView()->ToWorld( HITTEST_THRESHOLD_PIXELS ) );
2938 int gridThreshold = KiROUND( getView()->GetGAL()->GetGridSize().EuclideanNorm() );
2939 int thresholdMax = std::max( pixelThreshold, gridThreshold );
2940
2941 for( int threshold : { 0, thresholdMax/4, thresholdMax/2, thresholdMax } )
2942 {
2943 collector.m_Threshold = threshold;
2944 collector.Collect( m_frame->GetScreen(), connectedTypes, aPosition );
2945
2946 if( collector.GetCount() > 0 )
2947 break;
2948 }
2949
2950 return collector.GetCount() ? collector[ 0 ] : nullptr;
2951}
2952
2953
2955{
2956 VECTOR2I cursorPos = getViewControls()->GetCursorPosition( false );
2957
2958 SelectPoint( cursorPos, connectedTypes );
2959 return 0;
2960}
2961
2962
2963std::set<SCH_ITEM*>
2965 STOP_CONDITION aStopCondition )
2966{
2967 SCH_EDIT_FRAME* editFrame = dynamic_cast<SCH_EDIT_FRAME*>( m_frame );
2968
2969 if( m_isSymbolEditor || m_isSymbolViewer || !editFrame )
2970 return {};
2971
2972 CONNECTION_GRAPH* graph = editFrame->Schematic().ConnectionGraph();
2973
2974 if( !graph )
2975 return {};
2976
2977 SCH_SCREEN* screen = m_frame->GetScreen();
2978 SCH_SHEET_PATH& currentSheet = editFrame->GetCurrentSheet();
2979 std::vector<SCH_ITEM*> startItems;
2980 std::set<SCH_ITEM*> added;
2981
2982 for( auto item : aItems )
2983 {
2984 if( !item->IsSCH_ITEM() )
2985 continue;
2986
2987 SCH_ITEM* schItem = static_cast<SCH_ITEM*>( item );
2988
2989 if( schItem->Type() == SCH_SYMBOL_T )
2990 {
2991 for( SCH_PIN* pin : static_cast<SCH_SYMBOL*>( schItem )->GetPins( &currentSheet ) )
2992 {
2993 if( pin )
2994 startItems.push_back( pin );
2995 }
2996 }
2997 else if( schItem->IsConnectable() )
2998 {
2999 startItems.push_back( schItem );
3000 }
3001 }
3002
3003 if( startItems.empty() )
3004 return {};
3005
3006 // Pre-compute which start items belong to symbols already in the original selection so that
3007 // pin-stop traversal can step away from those symbols without immediately bouncing back.
3008 std::unordered_set<SCH_SYMBOL*> startSymbols;
3009
3010 for( SCH_ITEM* item : startItems )
3011 {
3012 if( SCH_PIN* pin = dynamic_cast<SCH_PIN*>( item ) )
3013 {
3014 if( SCH_SYMBOL* parent = dynamic_cast<SCH_SYMBOL*>( pin->GetParent() ) )
3015 startSymbols.insert( parent );
3016 }
3017 }
3018
3019 // Cache every pin position on the sheet so endpoint tests are O(log n) lookups instead of
3020 // an R-tree query plus a full pin iteration per call.
3021 std::set<VECTOR2I> pinPositions;
3022
3023 for( SCH_ITEM* it : screen->Items().OfType( SCH_SYMBOL_T ) )
3024 {
3025 for( SCH_PIN* pin : static_cast<SCH_SYMBOL*>( it )->GetPins( &currentSheet ) )
3026 {
3027 if( pin )
3028 pinPositions.insert( pin->GetPosition() );
3029 }
3030 }
3031
3032 auto isStopPoint = [&]( const VECTOR2I& aPoint ) -> bool
3033 {
3034 if( aStopCondition == STOP_CONDITION::STOP_NEVER )
3035 return false;
3036
3037 if( pinPositions.count( aPoint ) )
3038 return true;
3039
3040 if( aStopCondition == STOP_CONDITION::STOP_AT_PIN )
3041 return false;
3042
3043 if( screen->IsJunction( aPoint ) || screen->IsExplicitJunction( aPoint ) )
3044 return true;
3045
3046 for( SCH_ITEM* it : screen->Items().Overlapping( aPoint ) )
3047 {
3048 switch( it->Type() )
3049 {
3050 case SCH_LABEL_T:
3051 case SCH_GLOBAL_LABEL_T:
3052 case SCH_HIER_LABEL_T:
3054 case SCH_SHEET_PIN_T:
3055 case SCH_NO_CONNECT_T:
3056 if( it->IsConnected( aPoint ) )
3057 return true;
3058
3059 break;
3060
3061 default:
3062 break;
3063 }
3064 }
3065
3066 return false;
3067 };
3068
3069 // STOP_AT_JUNCTION refuses to pull a symbol into the selection unless the user already had
3070 // a symbol selected; later passes accept every reachable symbol.
3071 auto shouldPullInSymbol = [&]()
3072 {
3073 return aStopCondition != STOP_CONDITION::STOP_AT_JUNCTION || !startSymbols.empty();
3074 };
3075
3076 std::deque<SCH_ITEM*> queue;
3077 std::unordered_set<SCH_ITEM*> visited;
3078
3079 auto enqueue = [&]( SCH_ITEM* aItem )
3080 {
3081 if( !aItem )
3082 return;
3083
3084 if( visited.insert( aItem ).second )
3085 queue.push_back( aItem );
3086 };
3087
3088 for( SCH_ITEM* item : startItems )
3089 enqueue( item );
3090
3091 while( !queue.empty() )
3092 {
3093 SCH_ITEM* item = queue.front();
3094 queue.pop_front();
3095
3096 if( SCH_PIN* pin = dynamic_cast<SCH_PIN*>( item ) )
3097 {
3098 SCH_SYMBOL* symbol = dynamic_cast<SCH_SYMBOL*>( pin->GetParent() );
3099
3100 if( shouldPullInSymbol() && symbol && Selectable( symbol )
3101 && itemPassesFilter( symbol, nullptr ) && !symbol->IsSelected() )
3102 {
3103 added.insert( symbol );
3104 }
3105 }
3106
3107 SCH_LINE* line = dynamic_cast<SCH_LINE*>( item );
3108 std::vector<VECTOR2I> openPoints;
3109
3110 if( line && aStopCondition != STOP_CONDITION::STOP_NEVER )
3111 {
3112 for( const VECTOR2I& pt : { line->GetStartPoint(), line->GetEndPoint() } )
3113 {
3114 if( !isStopPoint( pt ) )
3115 openPoints.push_back( pt );
3116 }
3117 }
3118
3119 const SCH_ITEM_VEC& neighbors = item->ConnectedItems( currentSheet );
3120
3121 for( SCH_ITEM* neighbor : neighbors )
3122 {
3123 if( !neighbor )
3124 continue;
3125
3126 if( neighbor->Type() == SCH_SYMBOL_T )
3127 {
3128 SCH_SYMBOL* symbol = static_cast<SCH_SYMBOL*>( neighbor );
3129
3130 if( shouldPullInSymbol() && Selectable( symbol ) && itemPassesFilter( symbol, nullptr )
3131 && !symbol->IsSelected() )
3132 {
3133 added.insert( symbol );
3134 }
3135
3136 continue;
3137 }
3138
3139 // Wires gate traversal on open endpoints; items without distinct endpoints always flow.
3140 if( line && aStopCondition != STOP_CONDITION::STOP_NEVER )
3141 {
3142 bool sharesOpenPoint = false;
3143
3144 for( const VECTOR2I& pt : openPoints )
3145 {
3146 if( neighbor->IsConnected( pt ) )
3147 {
3148 sharesOpenPoint = true;
3149 break;
3150 }
3151 }
3152
3153 if( !sharesOpenPoint )
3154 continue;
3155 }
3156
3157 enqueue( neighbor );
3158 }
3159
3160 if( !Selectable( item ) || !itemPassesFilter( item, nullptr ) )
3161 continue;
3162
3163 added.insert( item );
3164 }
3165
3166 return added;
3167}
3168
3169
3171{
3172 std::set<SCH_ITEM*> added;
3173
3174 for( auto item : aItems )
3175 {
3176 if( !item->IsSCH_ITEM() )
3177 continue;
3178
3179 SCH_ITEM* schItem = static_cast<SCH_ITEM*>( item );
3180
3181 std::set<SCH_ITEM*> conns = m_frame->GetScreen()->MarkConnections( schItem, schItem->IsConnectable() );
3182
3183 // Make sure we don't add things the user has disabled in the selection filter
3184 for( SCH_ITEM* connItem : conns )
3185 {
3186 if( !Selectable( connItem ) || !itemPassesFilter( connItem, nullptr ) )
3187 continue;
3188
3189 added.insert( connItem );
3190 }
3191 }
3192
3193 return added;
3194}
3195
3196
3198{
3200
3201 if( m_selection.Empty() )
3202 return 0;
3203
3204 SCH_SELECTION connectableSelection;
3205 SCH_SELECTION graphicalSelection;
3206
3207 // We need to filter the selection into connectable items (wires, pins, symbols)
3208 // and non-connectable items (shapes, unconnectable lines) for processing
3209 // with the graph or by the graphical are-endpoints-touching method.
3210 for( EDA_ITEM* selItem : originalSelection.GetItems() )
3211 {
3212 if( !selItem->IsSCH_ITEM() )
3213 continue;
3214
3215 SCH_ITEM* item = static_cast<SCH_ITEM*>( selItem );
3216
3217 if( item->Type() == SCH_LINE_T && !item->IsConnectable() )
3218 graphicalSelection.Add( item );
3219 else if( item->Type() == SCH_SHAPE_T )
3220 graphicalSelection.Add( item );
3221 else
3222 connectableSelection.Add( item );
3223 }
3224
3225 // Repeated Ctrl+4 must advance to the next stop condition if the current stage did not pull
3226 // in any items beyond what was already selected, matching PCBNew's "Select/Expand Connection".
3227 std::unordered_set<const SCH_ITEM*> originalConnectableSet;
3228
3229 for( EDA_ITEM* selItem : connectableSelection.GetItems() )
3230 originalConnectableSet.insert( static_cast<const SCH_ITEM*>( selItem ) );
3231
3232 ClearSelection( true );
3233
3234 std::set<SCH_ITEM*> graphAdded;
3235 std::set<SCH_ITEM*> graphicalAdded;
3236
3237 if( !connectableSelection.Empty() )
3238 {
3242 {
3243 graphAdded = expandConnectionWithGraph( connectableSelection, stop );
3244
3245 bool grew = std::any_of( graphAdded.begin(), graphAdded.end(),
3246 [&]( const SCH_ITEM* c )
3247 {
3248 return !originalConnectableSet.count( c );
3249 } );
3250
3251 if( grew )
3252 break;
3253 }
3254 }
3255
3256 if( !graphicalSelection.Empty() )
3257 graphicalAdded = expandConnectionGraphically( graphicalSelection );
3258
3259 // For whatever reason, the connection graph isn't working (e.g. in symbol editor )
3260 // so fall back to graphical expansion for those items if nothing was added.
3261 if( graphAdded.empty() && !connectableSelection.Empty() )
3262 {
3263 SCH_SELECTION combinedSelection = connectableSelection;
3264
3265 for( EDA_ITEM* selItem : graphicalSelection.GetItems() )
3266 combinedSelection.Add( selItem );
3267
3268 graphicalSelection = combinedSelection;
3269 }
3270
3271 graphicalAdded = expandConnectionGraphically( graphicalSelection );
3272
3273 auto smartAddToSel = [&]( EDA_ITEM* aItem )
3274 {
3275 AddItemToSel( aItem, true );
3276
3277 if( aItem->Type() == SCH_LINE_T )
3278 aItem->SetFlags( STARTPOINT | ENDPOINT );
3279 };
3280
3281 // Add everything to the selection, including the original selection
3282 for( auto item : graphAdded )
3283 smartAddToSel( item );
3284
3285 for( auto item : graphicalAdded )
3286 smartAddToSel( item );
3287
3288 for( auto item : originalSelection )
3289 smartAddToSel( item );
3290
3291 m_selection.SetIsHover( originalSelection.IsHover() );
3292
3293 if( originalSelection.HasReferencePoint() )
3294 m_selection.SetReferencePoint( originalSelection.GetReferencePoint() );
3295 else
3296 m_selection.ClearReferencePoint();
3297
3298 getView()->Update( &m_selection );
3299
3300 m_toolMgr->ProcessEvent( EVENTS::SelectedEvent );
3301
3302 return 0;
3303}
3304
3305
3307{
3308 std::set<std::pair<SCH_TABLE*, int>> columns;
3309 bool added = false;
3310
3311 for( EDA_ITEM* item : m_selection )
3312 {
3313 if( SCH_TABLECELL* cell = dynamic_cast<SCH_TABLECELL*>( item ) )
3314 {
3315 SCH_TABLE* table = static_cast<SCH_TABLE*>( cell->GetParent() );
3316 columns.insert( std::make_pair( table, cell->GetColumn() ) );
3317 }
3318 }
3319
3320 for( auto& [ table, col ] : columns )
3321 {
3322 for( int row = 0; row < table->GetRowCount(); ++row )
3323 {
3324 SCH_TABLECELL* cell = table->GetCell( row, col );
3325
3326 if( !cell->IsSelected() )
3327 {
3328 select( table->GetCell( row, col ) );
3329 added = true;
3330 }
3331 }
3332 }
3333
3334 if( added )
3335 m_toolMgr->ProcessEvent( EVENTS::SelectedEvent );
3336
3337 return 0;
3338}
3339
3340
3342{
3343 std::set<std::pair<SCH_TABLE*, int>> rows;
3344 bool added = false;
3345
3346 for( EDA_ITEM* item : m_selection )
3347 {
3348 if( SCH_TABLECELL* cell = dynamic_cast<SCH_TABLECELL*>( item ) )
3349 {
3350 SCH_TABLE* table = static_cast<SCH_TABLE*>( cell->GetParent() );
3351 rows.insert( std::make_pair( table, cell->GetRow() ) );
3352 }
3353 }
3354
3355 for( auto& [ table, row ] : rows )
3356 {
3357 for( int col = 0; col < table->GetColCount(); ++col )
3358 {
3359 SCH_TABLECELL* cell = table->GetCell( row, col );
3360
3361 if( !cell->IsSelected() )
3362 {
3363 select( table->GetCell( row, col ) );
3364 added = true;
3365 }
3366 }
3367 }
3368
3369 if( added )
3370 m_toolMgr->ProcessEvent( EVENTS::SelectedEvent );
3371
3372 return 0;
3373}
3374
3375
3377{
3378 std::set<SCH_TABLE*> tables;
3379 bool added = false;
3380
3381 for( EDA_ITEM* item : m_selection )
3382 {
3383 if( SCH_TABLECELL* cell = dynamic_cast<SCH_TABLECELL*>( item ) )
3384 tables.insert( static_cast<SCH_TABLE*>( cell->GetParent() ) );
3385 }
3386
3388
3389 for( SCH_TABLE* table : tables )
3390 {
3391 if( !table->IsSelected() )
3392 {
3393 select( table );
3394 added = true;
3395 }
3396 }
3397
3398 if( added )
3399 m_toolMgr->ProcessEvent( EVENTS::SelectedEvent );
3400
3401 return 0;
3402}
3403
3404
3406{
3408 return 0;
3409}
3410
3411
3413{
3414 if( aBBox.GetWidth() == 0 )
3415 return;
3416
3417 BOX2I bbox = aBBox;
3418 bbox.Normalize();
3419
3420 VECTOR2I bbSize = bbox.Inflate( KiROUND( bbox.GetWidth() * 0.2f ) ).GetSize();
3421 VECTOR2D screenSize = getView()->GetViewport().GetSize();
3422
3423 // This code tries to come up with a zoom factor that doesn't simply zoom in to the cross
3424 // probed symbol, but instead shows a reasonable amount of the circuit around it to provide
3425 // context. This reduces the need to manually change the zoom because it's too close.
3426
3427 // Using the default text height as a constant to compare against, use the height of the
3428 // bounding box of visible items for a footprint to figure out if this is a big symbol (like
3429 // a processor) or a small symbol (like a resistor). This ratio is not useful by itself as a
3430 // scaling factor. It must be "bent" to provide good scaling at varying symbol sizes. Bigger
3431 // symbols need less scaling than small ones.
3432 double currTextHeight = schIUScale.MilsToIU( DEFAULT_TEXT_SIZE );
3433
3434 double compRatio = bbSize.y / currTextHeight; // Ratio of symbol to text height
3435 double compRatioBent = 1.0;
3436
3437 // LUT to scale zoom ratio to provide reasonable schematic context. Must work with symbols
3438 // of varying sizes (e.g. 0402 package and 200 pin BGA).
3439 // Each entry represents a compRatio (symbol height / default text height) and an amount to
3440 // scale by.
3441 std::vector<std::pair<double, double>> lut{ { 1.25, 16 },
3442 { 2.5, 12 },
3443 { 5, 8 },
3444 { 6, 6 },
3445 { 10, 4 },
3446 { 20, 2 },
3447 { 40, 1.5 },
3448 { 100, 1 } };
3449
3450 std::vector<std::pair<double, double>>::iterator it;
3451
3452 // Large symbol default is last LUT entry (1:1).
3453 compRatioBent = lut.back().second;
3454
3455 // Use LUT to do linear interpolation of "compRatio" within "first", then use that result to
3456 // linearly interpolate "second" which gives the scaling factor needed.
3457 if( compRatio >= lut.front().first )
3458 {
3459 for( it = lut.begin(); it < lut.end() - 1; ++it )
3460 {
3461 if( it->first <= compRatio && next( it )->first >= compRatio )
3462 {
3463 double diffx = compRatio - it->first;
3464 double diffn = next( it )->first - it->first;
3465
3466 compRatioBent = it->second + ( next( it )->second - it->second ) * diffx / diffn;
3467 break; // We have our interpolated value
3468 }
3469 }
3470 }
3471 else
3472 {
3473 compRatioBent = lut.front().second; // Small symbol default is first entry
3474 }
3475
3476 // This is similar to the original KiCad code that scaled the zoom to make sure symbols were
3477 // visible on screen. It's simply a ratio of screen size to symbol size, and its job is to
3478 // zoom in to make the component fullscreen. Earlier in the code the symbol BBox is given a
3479 // 20% margin to add some breathing room. We compare the height of this enlarged symbol bbox
3480 // to the default text height. If a symbol will end up with the sides clipped, we adjust
3481 // later to make sure it fits on screen.
3482 screenSize.x = std::max( 10.0, screenSize.x );
3483 screenSize.y = std::max( 10.0, screenSize.y );
3484 double ratio = std::max( -1.0, fabs( bbSize.y / screenSize.y ) );
3485
3486 // Original KiCad code for how much to scale the zoom
3487 double kicadRatio = std::max( fabs( bbSize.x / screenSize.x ),
3488 fabs( bbSize.y / screenSize.y ) );
3489
3490 // If the width of the part we're probing is bigger than what the screen width will be after
3491 // the zoom, then punt and use the KiCad zoom algorithm since it guarantees the part's width
3492 // will be encompassed within the screen.
3493 if( bbSize.x > screenSize.x * ratio * compRatioBent )
3494 {
3495 // Use standard KiCad zoom for parts too wide to fit on screen/
3496 ratio = kicadRatio;
3497 compRatioBent = 1.0; // Reset so we don't modify the "KiCad" ratio
3498 wxLogTrace( "CROSS_PROBE_SCALE",
3499 "Part TOO WIDE for screen. Using normal KiCad zoom ratio: %1.5f", ratio );
3500 }
3501
3502 // Now that "compRatioBent" holds our final scaling factor we apply it to the original
3503 // fullscreen zoom ratio to arrive at the final ratio itself.
3504 ratio *= compRatioBent;
3505
3506 bool alwaysZoom = false; // DEBUG - allows us to minimize zooming or not
3507
3508 // Try not to zoom on every cross-probe; it gets very noisy
3509 if( ( ratio < 0.5 || ratio > 1.0 ) || alwaysZoom )
3510 getView()->SetScale( getView()->GetScale() / ratio );
3511}
3512
3513
3514void SCH_SELECTION_TOOL::SyncSelection( const std::optional<SCH_SHEET_PATH>& targetSheetPath,
3515 SCH_ITEM* focusItem, const std::vector<SCH_ITEM*>& items )
3516{
3517 SCH_EDIT_FRAME* editFrame = dynamic_cast<SCH_EDIT_FRAME*>( m_frame );
3518
3519 if( !editFrame )
3520 return;
3521
3522 double targetZoom = 0.0;
3523 VECTOR2D targetCenter;
3524 bool targetZoomValid = false;
3525 bool changedSheet = false;
3526
3527 if( targetSheetPath )
3528 {
3529 SCH_SHEET_PATH path = targetSheetPath.value();
3530
3531 if( SCH_SCREEN* screen = path.LastScreen() )
3532 {
3533 targetZoom = screen->m_LastZoomLevel;
3534 targetCenter = screen->m_ScrollCenter;
3535 targetZoomValid = screen->IsZoomInitialized();
3536 }
3537
3538 if( path != editFrame->Schematic().CurrentSheet() )
3539 {
3540 m_frame->GetToolManager()->RunAction<SCH_SHEET_PATH*>( SCH_ACTIONS::changeSheet, &path );
3541 changedSheet = true;
3542 }
3543 }
3544
3545 if( changedSheet && targetZoomValid && !m_frame->eeconfig()->m_CrossProbing.zoom_to_fit )
3546 {
3547 getView()->SetScale( targetZoom );
3548 getView()->SetCenter( targetCenter );
3549 }
3550
3551 ClearSelection( items.size() > 0 ? true /*quiet mode*/ : false );
3552
3553 // Perform individual selection of each item before processing the event.
3554 for( SCH_ITEM* item : items )
3555 {
3556 SCH_ITEM* parent = dynamic_cast<SCH_ITEM*>( item->GetParent() );
3557
3558 // Make sure we only select items on the current screen
3559 if( m_frame->GetScreen()->CheckIfOnDrawList( item )
3560 || ( parent && m_frame->GetScreen()->CheckIfOnDrawList( parent ) ) )
3561 {
3562 select( item );
3563 }
3564 }
3565
3566 BOX2I bbox = m_selection.GetBoundingBox();
3567
3568 if( bbox.GetWidth() != 0 && bbox.GetHeight() != 0 )
3569 {
3570 if( m_frame->eeconfig()->m_CrossProbing.center_on_items )
3571 {
3572 if( m_frame->eeconfig()->m_CrossProbing.zoom_to_fit )
3573 ZoomFitCrossProbeBBox( bbox );
3574
3575 editFrame->FocusOnItem( focusItem );
3576
3577 if( !focusItem )
3578 editFrame->FocusOnLocation( bbox.Centre() );
3579 }
3580 }
3581
3582 if( m_selection.Size() > 0 )
3583 m_toolMgr->ProcessEvent( EVENTS::SelectedEvent );
3584}
3585
3586
3588{
3589 m_selection.Clear();
3590
3591 bool enteredGroupFound = false;
3592
3593 if( m_isSymbolEditor )
3594 {
3595 LIB_SYMBOL* start = static_cast<SYMBOL_EDIT_FRAME*>( m_frame )->GetCurSymbol();
3596
3597 for( SCH_ITEM& item : start->GetDrawItems() )
3598 {
3599 if( item.IsSelected() )
3600 select( &item );
3601
3602 if( item.Type() == SCH_GROUP_T )
3603 {
3604 if( &item == m_enteredGroup )
3605 {
3606 item.SetFlags( ENTERED );
3607 enteredGroupFound = true;
3608 }
3609 else
3610 {
3611 item.ClearFlags( ENTERED );
3612 }
3613 }
3614 }
3615 }
3616 else
3617 {
3618 for( SCH_ITEM* item : m_frame->GetScreen()->Items() )
3619 {
3620 // If the field and symbol are selected, only use the symbol
3621 if( item->IsSelected() )
3622 {
3623 select( item );
3624 }
3625 else
3626 {
3627 item->RunOnChildren(
3628 [&]( SCH_ITEM* aChild )
3629 {
3630 if( aChild->IsSelected() )
3631 select( aChild );
3632 },
3634 }
3635
3636 if( item->Type() == SCH_GROUP_T )
3637 {
3638 if( item == m_enteredGroup )
3639 {
3640 item->SetFlags( ENTERED );
3641 enteredGroupFound = true;
3642 }
3643 else
3644 {
3645 item->ClearFlags( ENTERED );
3646 }
3647 }
3648 }
3649 }
3650
3652
3653 if( !enteredGroupFound )
3654 {
3655 m_enteredGroupOverlay.Clear();
3656 m_enteredGroup = nullptr;
3657 }
3658
3659 // Inform other potentially interested tools
3660 m_toolMgr->ProcessEvent( EVENTS::SelectedEvent );
3661}
3662
3663
3664bool SCH_SELECTION_TOOL::Selectable( const EDA_ITEM* aItem, const VECTOR2I* aPos,
3665 bool checkVisibilityOnly ) const
3666{
3667 // NOTE: in the future this is where Eeschema layer/itemtype visibility will be handled
3668
3669 SYMBOL_EDIT_FRAME* symEditFrame = dynamic_cast<SYMBOL_EDIT_FRAME*>( m_frame );
3670
3671 // Do not allow selection of anything except fields when the current symbol in the symbol
3672 // editor is a derived symbol.
3673 if( symEditFrame && symEditFrame->IsSymbolAlias() && aItem->Type() != SCH_FIELD_T )
3674 return false;
3675
3676 switch( aItem->Type() )
3677 {
3678 case SCH_PIN_T:
3679 {
3680 const SCH_PIN* pin = static_cast<const SCH_PIN*>( aItem );
3681
3682 if( symEditFrame )
3683 {
3684 if( pin->GetUnit() && pin->GetUnit() != symEditFrame->GetUnit() )
3685 return false;
3686
3687 if( pin->GetBodyStyle() && pin->GetBodyStyle() != symEditFrame->GetBodyStyle() )
3688 return false;
3689 }
3690
3691 if( !pin->IsVisible() && !m_frame->GetShowAllPins() )
3692 return false;
3693
3694 if( !m_filter.pins )
3695 {
3696 // Pin anchors have to be allowed for auto-starting wires.
3697 if( aPos )
3698 {
3700 GRID_HELPER_GRIDS pinGrid = grid.GetItemGrid( pin );
3701
3702 if( pin->IsPointClickableAnchor( grid.BestSnapAnchor( *aPos, pinGrid ) ) )
3703 return true;
3704 }
3705
3706 return false;
3707 }
3708
3709 break;
3710 }
3711
3713 if( !m_frame->eeconfig()->m_Appearance.show_directive_labels )
3714 return false;
3715
3716 break;
3717
3718 case LIB_SYMBOL_T: // In symbol_editor we do not want to select the symbol itself.
3719 return false;
3720
3721 case SCH_FIELD_T: // SCH_FIELD objects are not unit/body-style-specific.
3722 {
3723 const SCH_FIELD* field = static_cast<const SCH_FIELD*>( aItem );
3724
3725 if( !field->IsVisible() && !( symEditFrame && symEditFrame->GetShowInvisibleFields() ) )
3726 return false;
3727
3728 break;
3729 }
3730
3731 case SCH_SHAPE_T:
3732 case SCH_TEXT_T:
3733 case SCH_TEXTBOX_T:
3734 if( symEditFrame )
3735 {
3736 const SCH_ITEM* sch_item = static_cast<const SCH_ITEM*>( aItem );
3737
3738 if( sch_item->GetUnit() && sch_item->GetUnit() != symEditFrame->GetUnit() )
3739 return false;
3740
3741 if( sch_item->GetBodyStyle() && sch_item->GetBodyStyle() != symEditFrame->GetBodyStyle() )
3742 return false;
3743 }
3744
3745 break;
3746
3747 case SCH_MARKER_T: // Always selectable
3748 return true;
3749
3750 case SCH_TABLECELL_T:
3751 {
3752 const SCH_TABLECELL* cell = static_cast<const SCH_TABLECELL*>( aItem );
3753
3754 if( cell->GetColSpan() == 0 || cell->GetRowSpan() == 0 )
3755 return false;
3756
3757 break;
3758 }
3759
3760 case NOT_USED: // Things like CONSTRUCTION_GEOM that aren't part of the model
3761 return false;
3762
3763 default: // Suppress warnings
3764 break;
3765 }
3766
3767 return true;
3768}
3769
3770
3772{
3773 if( m_selection.Empty() )
3774 return;
3775
3776 while( m_selection.GetSize() )
3778
3779 getView()->Update( &m_selection );
3780
3781 m_selection.SetIsHover( false );
3782 m_selection.ClearReferencePoint();
3783
3784 // Inform other potentially interested tools
3785 if( !aQuietMode )
3786 m_toolMgr->ProcessEvent( EVENTS::ClearedEvent );
3787}
3788
3789
3791{
3792 // Don't group when we select new items, the schematic editor selects all new items for moving.
3793 // The PCB editor doesn't need this logic because it doesn't select new items for moving.
3794 if( m_enteredGroup && !aItem->IsNew()
3795 && !SCH_GROUP::WithinScope( static_cast<SCH_ITEM*>( aItem ), m_enteredGroup, m_isSymbolEditor ) )
3796 {
3797 ExitGroup();
3798 }
3799
3800 highlight( aItem, SELECTED, &m_selection );
3801}
3802
3803
3805{
3806 unhighlight( aItem, SELECTED, &m_selection );
3807}
3808
3809
3810void SCH_SELECTION_TOOL::highlight( EDA_ITEM* aItem, int aMode, SELECTION* aGroup )
3811{
3812 if( aMode == SELECTED )
3813 aItem->SetSelected();
3814 else if( aMode == BRIGHTENED )
3815 aItem->SetBrightened();
3816
3817 if( aGroup )
3818 aGroup->Add( aItem );
3819
3820 // Highlight pins and fields. (All the other symbol children are currently only
3821 // represented in the LIB_SYMBOL and will inherit the settings of the parent symbol.)
3822 if( SCH_ITEM* sch_item = dynamic_cast<SCH_ITEM*>( aItem ) )
3823 {
3824 // We don't want to select group children if the group itself is selected,
3825 // we can only select them when the group is entered
3826 if( sch_item->Type() != SCH_GROUP_T )
3827 {
3828 sch_item->RunOnChildren(
3829 [&]( SCH_ITEM* aChild )
3830 {
3831 if( aMode == SELECTED )
3832 {
3833 aChild->SetSelected();
3834 getView()->Hide( aChild, true );
3835 }
3836 else if( aMode == BRIGHTENED )
3837 {
3838 aChild->SetBrightened();
3839 }
3840 },
3842 }
3843 }
3844
3845 if( aGroup && aMode != BRIGHTENED )
3846 getView()->Hide( aItem, true );
3847
3848 if( aItem->GetParent() && aItem->GetParent()->Type() != SCHEMATIC_T )
3849 getView()->Update( aItem->GetParent(), KIGFX::REPAINT );
3850
3851 getView()->Update( aItem, KIGFX::REPAINT );
3852}
3853
3854
3855void SCH_SELECTION_TOOL::unhighlight( EDA_ITEM* aItem, int aMode, SELECTION* aGroup )
3856{
3857 if( aMode == SELECTED )
3858 {
3859 aItem->ClearSelected();
3860 // Lines need endpoints cleared here
3861 if( aItem->Type() == SCH_LINE_T )
3862 aItem->ClearFlags( STARTPOINT | ENDPOINT );
3863
3864 if( aMode != BRIGHTENED )
3865 getView()->Hide( aItem, false );
3866 }
3867 else if( aMode == BRIGHTENED )
3868 {
3869 aItem->ClearBrightened();
3870 }
3871
3872 if( aGroup )
3873 aGroup->Remove( aItem );
3874
3875 // Unhighlight pins and fields. (All the other symbol children are currently only
3876 // represented in the LIB_SYMBOL.)
3877 if( SCH_ITEM* sch_item = dynamic_cast<SCH_ITEM*>( aItem ) )
3878 {
3879 sch_item->RunOnChildren(
3880 [&]( SCH_ITEM* aChild )
3881 {
3882 if( aMode == SELECTED )
3883 {
3884 aChild->ClearSelected();
3885 getView()->Hide( aChild, false );
3886 }
3887 else if( aMode == BRIGHTENED )
3888 {
3889 aChild->ClearBrightened();
3890 }
3891
3892 if( aGroup )
3893 aGroup->Remove( aChild );
3894 },
3896 }
3897
3898 if( aItem->GetParent() && aItem->GetParent()->Type() != SCHEMATIC_T )
3899 getView()->Update( aItem->GetParent(), KIGFX::REPAINT );
3900
3901 getView()->Update( aItem, KIGFX::REPAINT );
3902}
3903
3904
3906{
3907 const unsigned GRIP_MARGIN = 20;
3908 int margin = KiROUND( getView()->ToWorld( GRIP_MARGIN ) );
3909
3910 // Check if the point is located within any of the currently selected items bounding boxes
3911 for( EDA_ITEM* item : m_selection )
3912 {
3913 BOX2I itemBox = item->ViewBBox();
3914 itemBox.Inflate( margin ); // Give some margin for gripping an item
3915
3916 if( itemBox.Contains( aPoint ) )
3917 return true;
3918 }
3919
3920 return false;
3921}
3922
3923
3925{
3926 SCH_EDIT_FRAME* editFrame = dynamic_cast<SCH_EDIT_FRAME*>( m_frame );
3927
3928 if( !editFrame || !editFrame->GetNetNavigator() || m_selection.Size() == 0 )
3929 return 0;
3930
3931 if( !m_selection.Front()->IsBrightened() )
3932 return 0;
3933
3934 const SCH_ITEM* item = editFrame->SelectNextPrevNetNavigatorItem( true );
3935
3936 if( item )
3937 {
3939 select( const_cast<SCH_ITEM*>( item ) );
3940 m_toolMgr->ProcessEvent( EVENTS::SelectedEvent );
3941 }
3942
3943 return 0;
3944}
3945
3946
3948{
3949 SCH_EDIT_FRAME* editFrame = dynamic_cast<SCH_EDIT_FRAME*>( m_frame );
3950
3951 if( !editFrame || !editFrame->GetNetNavigator() || m_selection.Size() == 0 )
3952 return 0;
3953
3954 if( !m_selection.Front()->IsBrightened() )
3955 return 0;
3956
3957 const SCH_ITEM* item = editFrame->SelectNextPrevNetNavigatorItem( false );
3958
3959 if( item )
3960 {
3962 select( const_cast<SCH_ITEM*>( item ) );
3963 m_toolMgr->ProcessEvent( EVENTS::SelectedEvent );
3964 }
3965
3966 return 0;
3967}
3968
3969
3971{
3973
3980
3982
3985
3991
3994
3997
4000
4002}
constexpr EDA_IU_SCALE schIUScale
Definition base_units.h:127
BOX2< VECTOR2I > BOX2I
Definition box2.h:922
constexpr BOX2I KiROUND(const BOX2D &aBoxD)
Definition box2.h:990
static TOOL_ACTION unselectAll
Definition actions.h:83
static TOOL_ACTION selectItem
Select an item (specified as the event parameter).
Definition actions.h:227
static TOOL_ACTION cursorLeft
Definition actions.h:172
static TOOL_ACTION zoomOutCenter
Definition actions.h:136
static TOOL_ACTION unselectItem
Definition actions.h:228
static TOOL_ACTION zoomIn
Definition actions.h:133
static TOOL_ACTION cursorLeftFast
Definition actions.h:177
static TOOL_ACTION selectSetLasso
Definition actions.h:221
static TOOL_ACTION selectSetRect
Set lasso selection mode.
Definition actions.h:220
static TOOL_ACTION groupEnter
Definition actions.h:243
static TOOL_ACTION selectColumns
Definition actions.h:102
static TOOL_ACTION cursorDown
Definition actions.h:171
static TOOL_ACTION zoomOut
Definition actions.h:134
static TOOL_ACTION cursorRightFast
Definition actions.h:178
static TOOL_ACTION zoomCenter
Definition actions.h:141
static TOOL_ACTION panDown
Definition actions.h:185
static TOOL_ACTION cursorDblClick
Definition actions.h:181
static TOOL_ACTION undo
Definition actions.h:75
static TOOL_ACTION selectionActivate
Activation of the selection tool.
Definition actions.h:214
static TOOL_ACTION cursorDownFast
Definition actions.h:176
static TOOL_ACTION selectionMenu
Run a selection menu to select from a list of items.
Definition actions.h:236
static TOOL_ACTION selectRows
Definition actions.h:101
static TOOL_ACTION cursorUpFast
Definition actions.h:175
static TOOL_ACTION panLeft
Definition actions.h:186
static TOOL_ACTION updateMenu
Definition actions.h:270
static TOOL_ACTION doDelete
Definition actions.h:85
static TOOL_ACTION selectionTool
Definition actions.h:251
static TOOL_ACTION cursorClick
Definition actions.h:180
static TOOL_ACTION zoomFitScreen
Definition actions.h:142
static TOOL_ACTION increment
Definition actions.h:94
static TOOL_ACTION selectionClear
Clear the current selection.
Definition actions.h:224
static TOOL_ACTION panUp
Definition actions.h:184
static TOOL_ACTION zoomFitObjects
Definition actions.h:143
static TOOL_ACTION zoomInCenter
Definition actions.h:135
static TOOL_ACTION panRight
Definition actions.h:187
static TOOL_ACTION selectTable
Definition actions.h:103
static TOOL_ACTION cursorUp
Cursor control with keyboard.
Definition actions.h:170
static TOOL_ACTION groupLeave
Definition actions.h:244
static TOOL_ACTION finishInteractive
Definition actions.h:73
static TOOL_ACTION cursorRight
Definition actions.h:173
static TOOL_ACTION selectAll
Definition actions.h:82
static TOOL_ACTION unselectItems
Definition actions.h:233
static TOOL_ACTION selectItems
Select a list of items (specified as the event parameter)
Definition actions.h:232
static const ADVANCED_CFG & GetCfg()
Get the singleton instance's config, which is shared by all consumers.
constexpr const Vec & GetPosition() const
Definition box2.h:211
constexpr void SetMaximum()
Definition box2.h:80
constexpr BOX2< Vec > & Inflate(coord_type dx, coord_type dy)
Inflates the rectangle horizontally by dx and vertically by dy.
Definition box2.h:558
constexpr BOX2< Vec > & Normalize()
Ensure that the height and width are positive.
Definition box2.h:146
constexpr size_type GetWidth() const
Definition box2.h:214
constexpr Vec Centre() const
Definition box2.h:97
constexpr const Vec GetCenter() const
Definition box2.h:230
constexpr size_type GetHeight() const
Definition box2.h:215
constexpr bool Contains(const Vec &aPoint) const
Definition box2.h:168
constexpr const SizeVec & GetSize() const
Definition box2.h:206
constexpr bool Intersects(const BOX2< Vec > &aRect) const
Definition box2.h:311
An abstract class that will find and hold all the objects according to an inspection done by the Insp...
Definition collector.h:49
void Transfer(int aIndex)
Move the item at aIndex (first position is 0) to the backup list.
Definition collector.h:153
bool m_MenuCancelled
Definition collector.h:239
ITER begin()
Definition collector.h:75
int GetCount() const
Return the number of objects in the list.
Definition collector.h:83
bool HasItem(const EDA_ITEM *aItem) const
Tests if aItem has already been collected.
Definition collector.h:197
void Remove(int aIndex)
Remove the item at aIndex (first position is 0).
Definition collector.h:111
int m_Threshold
Definition collector.h:236
ITER end()
Definition collector.h:76
void Append(EDA_ITEM *item)
Add an item to the end of the list.
Definition collector.h:101
COMMIT & Added(EDA_ITEM *aItem, BASE_SCREEN *aScreen=nullptr)
Notify observers that aItem has been added.
Definition commit.h:84
bool Empty() const
Definition commit.h:137
COMMIT & Add(EDA_ITEM *aItem, BASE_SCREEN *aScreen=nullptr)
Add a new item to the model.
Definition commit.h:78
Calculate the connectivity of a schematic and generates netlists.
bool IsHorizontal() const
Definition eda_angle.h:142
void FocusOnLocation(const VECTOR2I &aPos, bool aAllowScroll=true)
Useful to focus on a particular location, in find functions.
A set of EDA_ITEMs (i.e., without duplicates).
Definition eda_group.h:46
A base class for most all the KiCad significant classes used in schematics and boards.
Definition eda_item.h:100
virtual VECTOR2I GetPosition() const
Definition eda_item.h:279
void SetIsRollover(bool aIsRollover, const VECTOR2I &aMousePos)
Definition eda_item.h:135
virtual const BOX2I GetBoundingBox() const
Return the orthogonal bounding box of this object for display purposes.
Definition eda_item.cpp:120
void SetFlags(EDA_ITEM_FLAGS aMask)
Definition eda_item.h:149
KICAD_T Type() const
Returns the type of object.
Definition eda_item.h:112
void ClearSelected()
Definition eda_item.h:144
void ClearFlags(EDA_ITEM_FLAGS aMask=EDA_ITEM_ALL_FLAGS)
Definition eda_item.h:151
bool IsSelected() const
Definition eda_item.h:129
void SetSelected()
Definition eda_item.h:141
virtual bool IsType(const std::vector< KICAD_T > &aScanTypes) const
Check whether the item is one of the listed types.
Definition eda_item.h:199
void ClearBrightened()
Definition eda_item.h:145
void SetBrightened()
Definition eda_item.h:142
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:240
EDA_ITEM * GetParent() const
Definition eda_item.h:114
bool HasFlag(EDA_ITEM_FLAGS aFlag) const
Definition eda_item.h:153
void XorFlags(EDA_ITEM_FLAGS aMask)
Definition eda_item.h:150
EDA_ITEM_FLAGS GetFlags() const
Definition eda_item.h:152
bool IsNew() const
Definition eda_item.h:126
SHAPE_T GetShape() const
Definition eda_shape.h:185
virtual bool IsFilledForHitTesting() const
Definition eda_shape.h:147
virtual std::vector< SHAPE * > MakeEffectiveShapesForHitTesting() const
Definition eda_shape.h:399
A mix-in class (via multiple inheritance) that handles texts such as labels, parts,...
Definition eda_text.h:93
const EDA_ANGLE & GetTextAngle() const
Definition eda_text.h:172
virtual bool IsVisible() const
Definition eda_text.h:212
std::shared_ptr< SHAPE_COMPOUND > GetEffectiveTextShape(bool aTriangulate=true, const BOX2I &aBBox=BOX2I(), const EDA_ANGLE &aAngle=ANGLE_0) const
build a list of segments (SHAPE_SEGMENT) to describe a text shape.
GRID_HELPER_GRIDS GetItemGrid(const EDA_ITEM *aItem) const override
Get the coarsest grid that applies to an item.
VECTOR2I BestSnapAnchor(const VECTOR2I &aOrigin, GRID_HELPER_GRIDS aGrid, SCH_ITEM *aSkip)
EE_TYPE Overlapping(const BOX2I &aRect) const
Definition sch_rtree.h:230
EE_TYPE OfType(KICAD_T aType) const
Definition sch_rtree.h:225
static const TOOL_EVENT DisambiguatePoint
Used for hotkey feedback.
Definition actions.h:362
static const TOOL_EVENT ClearedEvent
Definition actions.h:347
static const TOOL_EVENT SelectedEvent
Definition actions.h:345
static const TOOL_EVENT SelectedItemsModified
Selected items were moved, this can be very high frequency on the canvas, use with care.
Definition actions.h:352
static const TOOL_EVENT PointSelectedEvent
Definition actions.h:344
static const TOOL_EVENT SelectedItemsMoved
Used to inform tools that the selection should temporarily be non-editable.
Definition actions.h:355
static const TOOL_EVENT UnselectedEvent
Definition actions.h:346
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 SetMode(SELECTION_MODE aMode)
void SetSubtractive(bool aSubtractive)
SELECTION_MODE GetMode() const
void SetAdditive(bool aAdditive)
void SetPoly(SHAPE_LINE_CHAIN &aPoly)
void SetOrigin(const VECTOR2I &aOrigin)
const BOX2I ViewBBox() const override
Set the origin of the rectangle (the fixed corner)
SHAPE_LINE_CHAIN & GetPoly()
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.
An interface for classes handling user events controlling the view behavior such as zooming,...
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.
virtual void WarpMouseCursor(const VECTOR2D &aPosition, bool aWorldCoordinates=false, bool aWarpView=false)=0
If enabled (.
virtual void SetCrossHairCursorPosition(const VECTOR2D &aPosition, bool aWarpView=true)=0
Move the graphic crosshair cursor to the requested position expressed in world coordinates.
VECTOR2D GetCursorPosition() const
Return the current cursor position in world coordinates.
virtual void SetCursorPosition(const VECTOR2D &aPosition, bool aWarpView=true, bool aTriggeredByArrows=false, long aArrowCommand=0)=0
Move cursor to the requested position expressed in world coordinates.
virtual void SetAutoPan(bool aEnabled)
Turn on/off auto panning (this feature is used when there is a tool active (eg.
An abstract base class for deriving all objects that can be added to a VIEW.
Definition view_item.h:86
Hold a (potentially large) number of VIEW_ITEMs and renders them on a graphics device provided by the...
Definition view.h:67
BOX2D GetViewport() const
Return the current viewport visible area rectangle.
Definition view.cpp:598
virtual void SetScale(double aScale, VECTOR2D aAnchor={ 0, 0 })
Set the scaling factor, zooming around a given anchor point.
Definition view.cpp:638
virtual void Add(VIEW_ITEM *aItem, int aDrawPriority=-1)
Add a VIEW_ITEM to the view.
Definition view.cpp:301
virtual void Remove(VIEW_ITEM *aItem)
Remove a VIEW_ITEM from the view.
Definition view.cpp:405
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:488
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:1809
bool IsMirroredX() const
Return true if view is flipped across the X axis.
Definition view.h:259
std::pair< VIEW_ITEM *, int > LAYER_ITEM_PAIR
Definition view.h:71
void Hide(VIEW_ITEM *aItem, bool aHide=true, bool aHideOverlay=false)
Temporarily hide the item in the view (e.g.
Definition view.cpp:1757
PAINTER * GetPainter() const
Return the painter object used by the view for drawing #VIEW_ITEMS.
Definition view.h:229
void SetCenter(const VECTOR2D &aCenter)
Set the center point of the VIEW (i.e.
Definition view.cpp:664
void SetVisible(VIEW_ITEM *aItem, bool aIsVisible=true)
Set the item visibility.
Definition view.cpp:1736
Definition kiid.h:48
Define a library symbol object.
Definition lib_symbol.h:83
bool IsPower() const override
bool IsMultiBodyStyle() const override
Definition lib_symbol.h:774
LIB_ITEMS_CONTAINER & GetDrawItems()
Return a reference to the draw item list.
Definition lib_symbol.h:712
int GetUnitCount() const override
bool IsExcluded() const
Definition marker_base.h:93
Tree view item data for the net navigator.
CONNECTION_GRAPH * ConnectionGraph() const
Definition schematic.h:200
SCH_SHEET & Root() const
Definition schematic.h:133
SCH_SHEET_PATH & CurrentSheet() const
Definition schematic.h:188
static TOOL_ACTION placeClassLabel
Definition sch_actions.h:79
static TOOL_ACTION placeSheetPin
Definition sch_actions.h:85
static TOOL_ACTION placeNextSymbolUnit
Definition sch_actions.h:67
static TOOL_ACTION swapPins
static TOOL_ACTION saveToLinkedDesignBlock
Definition sch_actions.h:71
static TOOL_ACTION clearHighlight
static TOOL_ACTION placeGlobalLabel
Definition sch_actions.h:80
static TOOL_ACTION pinTable
static TOOL_ACTION navigateBack
static TOOL_ACTION properties
static TOOL_ACTION leaveSheet
static TOOL_ACTION breakWire
static TOOL_ACTION findNetInInspector
static TOOL_ACTION autoplaceAllSheetPins
Definition sch_actions.h:86
static TOOL_ACTION drawLines
Definition sch_actions.h:99
static TOOL_ACTION placeHierLabel
Definition sch_actions.h:81
static TOOL_ACTION selectConnection
If current selection is a wire or bus, expand to entire connection.
Definition sch_actions.h:51
static TOOL_ACTION placeLabel
Definition sch_actions.h:78
static TOOL_ACTION nextNetItem
static TOOL_ACTION drawWire
Definition sch_actions.h:72
static TOOL_ACTION drag
static TOOL_ACTION placeJunction
Definition sch_actions.h:76
static TOOL_ACTION previousNetItem
static TOOL_ACTION swapUnitLabels
static TOOL_ACTION navigateForward
static TOOL_ACTION placeLinkedDesignBlock
Definition sch_actions.h:70
static TOOL_ACTION selectNode
Select the junction, wire or bus segment under the cursor.
Definition sch_actions.h:47
static TOOL_ACTION unfoldBus
Definition sch_actions.h:74
static TOOL_ACTION drawBus
Definition sch_actions.h:73
static TOOL_ACTION symbolProperties
static TOOL_ACTION slice
static TOOL_ACTION changeSheet
static TOOL_ACTION assignNetclass
static TOOL_ACTION swapPinLabels
static TOOL_ACTION enterSheet
static TOOL_ACTION editPageNumber
static TOOL_ACTION selectOnPCB
static TOOL_ACTION move
static TOOL_ACTION syncSheetPins
Definition sch_actions.h:89
A shim class between EDA_DRAW_FRAME and several derived classes: SYMBOL_EDIT_FRAME,...
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 ...
void Collect(SCH_SCREEN *aScreen, const std::vector< KICAD_T > &aScanTypes, const VECTOR2I &aPos, int aUnit=0, int aBodyStyle=0)
Scan a EDA_ITEM using this class's Inspector method which does the collection.
bool m_ShowPinElectricalTypes
static const std::vector< KICAD_T > MovableItems
virtual void Push(const wxString &aMessage=wxT("A commit"), int aCommitFlags=0) override
Execute the changes.
virtual void Revert() override
Revert the commit by restoring the modified items state.
static SELECTION_CONDITION SingleMultiFunctionPin
static SELECTION_CONDITION SingleSymbol
static SELECTION_CONDITION MultipleSymbolsOrPower
static SELECTION_CONDITION HasLockedItems
static SELECTION_CONDITION AllPinsOrSheetPins
static SELECTION_CONDITION SingleSymbolOrPower
static SELECTION_CONDITION HasUnlockedItems
static SELECTION_CONDITION SingleNonExcludedMarker
static SELECTION_CONDITION SingleMultiUnitSymbol
static SELECTION_CONDITION SingleMultiBodyStyleSymbol
static SELECTION_CONDITION AllPins
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
Handle actions specific to the schematic editor.
Schematic editor (Eeschema) main window.
void FocusOnItem(EDA_ITEM *aItem, bool aAllowScroll=true) override
Focus on a particular canvas item.
SCH_SCREEN * GetScreen() const override
Return a pointer to a BASE_SCREEN or one of its derivatives.
SCH_SHEET_PATH & GetCurrentSheet() const
SCHEMATIC & Schematic() const
const SCH_ITEM * SelectNextPrevNetNavigatorItem(bool aNext)
const wxString & GetHighlightedConnection() const
wxGenericTreeCtrl * GetNetNavigator()
const BOX2I GetBoundingBox() const override
Return the orthogonal bounding box of this object for display purposes.
A set of SCH_ITEMs (i.e., without duplicates).
Definition sch_group.h:52
static bool WithinScope(SCH_ITEM *aItem, SCH_GROUP *aScope, bool isSymbolEditor)
static EDA_GROUP * TopLevelGroup(SCH_ITEM *aItem, EDA_GROUP *aScope, bool isSymbolEditor)
Base class for any item which can be embedded within the SCHEMATIC container class,...
Definition sch_item.h:168
virtual bool IsConnectable() const
Definition sch_item.h:530
virtual bool HasHoveredHypertext() const
Indicates that a hypertext link is currently active.
Definition sch_item.h:337
const SCH_ITEM_VEC & ConnectedItems(const SCH_SHEET_PATH &aPath)
Retrieve the set of items connected to this item on the given sheet.
Definition sch_item.cpp:562
const SYMBOL * GetParentSymbol() const
Definition sch_item.cpp:278
SCHEMATIC * Schematic() const
Search the item hierarchy to find a SCHEMATIC.
Definition sch_item.cpp:272
int GetBodyStyle() const
Definition sch_item.h:248
virtual bool IsPointClickableAnchor(const VECTOR2I &aPos) const
Definition sch_item.h:536
bool IsLocked() const override
Definition sch_item.cpp:152
int GetUnit() const
Definition sch_item.h:239
bool IsType(const std::vector< KICAD_T > &aScanTypes) const override
Check whether the item is one of the listed types.
Definition sch_item.h:183
wxString GetShownText(const SCH_SHEET_PATH *aPath, bool aAllowExtraText, int aDepth=0) const override
void SetShape(LABEL_FLAG_SHAPE aShape)
Definition sch_label.h:183
LABEL_SHAPE GetLabelShape() const
Definition sch_label.h:179
virtual void SetSpinStyle(SPIN_STYLE aSpinStyle)
static bool IsDrawingLineWireOrBus(const SELECTION &aSelection)
Segment description base class to describe items which have 2 end points (track, wire,...
Definition sch_line.h:42
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:857
bool IsStartDangling() const
Definition sch_line.h:303
VECTOR2I GetEndPoint() const
Definition sch_line.h:148
VECTOR2I GetStartPoint() const
Definition sch_line.h:139
SEG GetSeg() const
Get the geometric aspect of the wire as a SEG.
Definition sch_line.h:158
bool IsEndDangling() const
Definition sch_line.h:304
bool IsBus() const
Return true if the line is a bus.
bool IsGraphicLine() const
Return if the line is a graphic (non electrical line)
void SetEndPoint(const VECTOR2I &aPosition)
Definition sch_line.h:149
Tool that displays edit points allowing to modify items by dragging the points.
bool HasPoint()
Indicate the cursor is over an edit point.
bool IsExplicitJunction(const VECTOR2I &aPosition) const
Indicate that a junction dot is necessary at the given location.
EE_RTREE & Items()
Get the full RTree, usually for iterating.
Definition sch_screen.h:119
bool IsJunction(const VECTOR2I &aPosition) const
Test if a junction is required for the items at aPosition on the screen.
SELECTION & selection() override
Return a reference to the selection.
int SelectPrevious(const TOOL_EVENT &aEvent)
void highlight(EDA_ITEM *aItem, int aMode, SELECTION *aGroup=nullptr) override
Highlight the item visually.
void SyncSelection(const std::optional< SCH_SHEET_PATH > &targetSheetPath, SCH_ITEM *focusItem, const std::vector< SCH_ITEM * > &items)
int SelectAll(const TOOL_EVENT &aEvent)
Unselect all visible items in sheet.
void narrowSelection(SCH_COLLECTOR &collector, const VECTOR2I &aWhere, bool aCheckLocked, bool aSelectedOnly=false, SCH_SELECTION_FILTER_OPTIONS *aRejected=nullptr)
Apply rules to narrow the collection down to selectable objects, and then heuristics to try and narro...
void FilterSelectionForLockedItems()
Remove locked items from the current selection.
std::set< SCH_ITEM * > expandConnectionGraphically(const SCH_SELECTION &aItems)
KIGFX::VIEW_GROUP m_enteredGroupOverlay
EDA_ITEM * GetNode(const VECTOR2I &aPosition)
Finds a connected item at a point (usually the cursor position).
bool itemPassesFilter(EDA_ITEM *aItem, SCH_SELECTION_FILTER_OPTIONS *aRejected=nullptr)
Return true if the given item passes the stateful selection filter.
SCH_BASE_FRAME * m_frame
void EnterGroup() override
Enter the group at the head of the current selection.
void unhighlight(EDA_ITEM *aItem, int aMode, SELECTION *aGroup=nullptr) override
Unhighlight the item visually.
bool selectTableCells(SCH_TABLE *aTable)
Handle a table cell drag selection within a table.
int SetSelectRect(const TOOL_EVENT &aEvent)
int Main(const TOOL_EVENT &aEvent)
The main loop.
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 ClearSelection(const TOOL_EVENT &aEvent)
Select all visible items in sheet.
bool CollectHits(SCH_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 GuessSelectionCandidates(SCH_COLLECTOR &collector, const VECTOR2I &aPos)
Apply heuristics to try and determine a single object when multiple are found under the cursor.
void Reset(RESET_REASON aReason) override
Bring the tool to a known, initial state.
void RebuildSelection()
Rebuild the selection from the EDA_ITEMs' selection flags.
SCH_TABLECELL * m_previous_first_cell
SCH_SELECTION & GetSelection()
std::set< SCH_ITEM * > expandConnectionWithGraph(const SCH_SELECTION &aItems, STOP_CONDITION aStopCondition)
SCH_SELECTION & RequestSelection(const std::vector< KICAD_T > &aScanTypes={ SCH_LOCATE_ANY_T }, bool aPromoteCellSelections=false, bool aPromoteGroups=false)
Return either an existing selection (filtered), or the selection at the current cursor position if th...
int SelectNext(const TOOL_EVENT &aEvent)
Select previous net item.
int UnselectAll(const TOOL_EVENT &aEvent)
Select next net item.
bool Init() override
Init() is called once upon a registration of the tool.
bool selectPoint(SCH_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).
OPT_TOOL_EVENT autostartEvent(TOOL_EVENT *aEvent, EE_GRID_HELPER &aGrid, SCH_ITEM *aItem)
void filterCollectorForHierarchy(SCH_COLLECTOR &aCollector, bool aMultiselect) const
In general we don't want to select both a parent and any of it's children.
bool selectMultiple()
Handle drawing a selection box that allows one to select many items at the same time.
SELECTION_MODE m_selectionMode
bool Selectable(const EDA_ITEM *aItem, const VECTOR2I *aPos=nullptr, bool checkVisibilityOnly=false) const
Check conditions for an item to be selected.
@ STOP_AT_PIN
Walk through junctions and labels but stop at pins.
@ STOP_NEVER
Walk the entire connected sub-net.
@ STOP_AT_JUNCTION
Stop at the first junction, label, or pin reached.
void updateReferencePoint()
Set the reference point to the anchor of the top-left item.
int SelectNode(const TOOL_EVENT &aEvent)
Selects the connected item at the current cursor position.
void InitializeSelectionState(SCH_TABLE *aTable)
Initialize the selection state of table cells.
void ExitGroup(bool aSelectGroup=false) override
Leave the currently-entered group.
int SelectRows(const TOOL_EVENT &aEvent)
void SelectCellsBetween(const VECTOR2D &start, const VECTOR2D &end, SCH_TABLE *aTable)
Select table cells within a rectangular area between two points.
void unselect(EDA_ITEM *aItem) override
Take necessary action to mark an item as unselected.
void select(EDA_ITEM *aItem) override
Take necessary action to mark an item as selected.
void SelectMultiple(KIGFX::PREVIEW::SELECTION_AREA &aArea, bool aSubtractive=false, bool aExclusiveOr=false)
int SelectColumns(const TOOL_EVENT &aEvent)
int SetSelectPoly(const TOOL_EVENT &aEvent)
int SelectTable(const TOOL_EVENT &aEvent)
Clear current selection event handler.
int disambiguateCursor(const TOOL_EVENT &aEvent)
Handle disambiguation actions including displaying the menu.
SCH_SELECTION_FILTER_OPTIONS m_filter
int SelectConnection(const TOOL_EVENT &aEvent)
If a connected item is selected then expand the selection to the entire connection,...
void ZoomFitCrossProbeBBox(const BOX2I &aBBox)
void OnIdle(wxIdleEvent &aEvent)
Zoom the screen to fit the bounding box for cross probing/selection sync.
void setTransitions() override
This method is meant to be overridden in order to specify handlers for events.
int updateSelection(const TOOL_EVENT &aEvent)
Event handler to update the selection VIEW_ITEM.
void filterCollectedItems(SCH_COLLECTOR &aCollector, bool aMultiSelect)
Set up handlers for various events.
bool selectionContains(const VECTOR2I &aPoint) const
VECTOR2I GetCenter() const
Definition sch_shape.h:91
Handle access to a stack of flattened SCH_SHEET objects by way of a path for creating a flattened sch...
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.
SHEET_SIDE GetSide() const
Sheet symbol placed in a schematic, and is the entry point for a sub schematic.
Definition sch_sheet.h:48
std::vector< SCH_SHEET_PIN * > & GetPins()
Definition sch_sheet.h:231
Schematic symbol object.
Definition sch_symbol.h:76
std::vector< const SCH_PIN * > GetPins(const SCH_SHEET_PATH *aSheet) const
Retrieve a list of the SCH_PINs for the given sheet path.
void GetFields(std::vector< SCH_FIELD * > &aVector, bool aVisibleOnly) const override
Populate a std::vector with SCH_FIELDs, sorted in ordinal order.
SCH_PIN * GetPin(const wxString &number) const
Find a symbol pin by number.
int GetOrientation() const override
Get the display symbol orientation.
std::unique_ptr< LIB_SYMBOL > & GetLibSymbolRef()
Definition sch_symbol.h:184
BOX2I GetBodyBoundingBox() const override
Return a bounding box for the symbol body but not the pins or fields.
int GetColSpan() const
int GetRowSpan() const
std::vector< SCH_TABLECELL * > GetCells() const
Definition sch_table.h:157
Definition seg.h:42
int Distance(const SEG &aSeg) const
Compute minimum Euclidean distance to segment aSeg.
Definition seg.cpp:702
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 SELECTION_CONDITION HasType(KICAD_T aType)
Create a functor that tests if among the selected items there is at least one of a given type.
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.
bool m_multiple
Multiple selection mode is active.
int RemoveItemFromSel(const TOOL_EVENT &aEvent)
bool doSelectionMenu(COLLECTOR *aCollector)
wxTimer m_disambiguateTimer
Timer to show the disambiguate menu.
bool m_drag_additive
Add multiple items to selection.
bool m_exclusive_or
Items' selection state should be toggled.
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
Location of original cursor when starting click.
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 m_subtractive
Items should be removed from selection.
SELECTION_TOOL(const std::string &aName)
bool m_skip_heuristics
Show disambiguation menu for all items under the cursor rather than trying to narrow them down first ...
bool m_drag_subtractive
Remove multiple from selection.
bool m_additive
Items should be added to sel (instead of replacing).
bool hasModifier()
True if a selection modifier is enabled, false otherwise.
bool m_canceledMenu
Sets to true if the disambiguation menu was canceled.
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
const std::deque< EDA_ITEM * > GetItems() const
Definition selection.h:126
VECTOR2I GetReferencePoint() const
virtual void Remove(EDA_ITEM *aItem)
Definition selection.cpp:60
bool IsHover() const
Definition selection.h:89
bool Empty() const
Checks if there is anything selected.
Definition selection.h:115
bool HasReferencePoint() const
Definition selection.h:216
Represent a polyline containing arcs as well as line segments: A chain of connected line and/or arc s...
void GenerateBBoxCache() const
void SetClosed(bool aClosed)
Mark the line chain as closed (i.e.
int PointCount() const
Return the number of points (vertices) in this line chain.
double Area(bool aAbsolute=true) const
Return the area of this chain.
virtual size_t GetPointCount() const override
void Append(int aX, int aY, bool aAllowDuplication=false)
Append a new point at the end of the line chain.
const VECTOR2I & CLastPoint() const
Return the last point in the line chain.
void Remove(int aStartIndex, int aEndIndex)
Remove the range of points [start_index, end_index] from the line chain.
bool PointInside(const VECTOR2I &aPt, int aAccuracy=0, bool aUseBBoxCache=false) const override
Check if point aP lies inside a closed shape.
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:151
The symbol library editor main window.
bool IsSymbolAlias() const
Return true if aLibId is an alias for the editor screen symbol.
Symbol library viewer main window.
A base class for LIB_SYMBOL and SCH_SYMBOL.
Definition symbol.h:63
const TRANSFORM & GetTransform() const
Definition symbol.h:247
Represent a single user action.
T * getEditFrame() const
Return the application window object, casted to requested user type.
Definition tool_base.h:186
KIGFX::VIEW_CONTROLS * getViewControls() const
Return the instance of VIEW_CONTROLS object used in the application.
Definition tool_base.cpp:44
TOOL_MANAGER * m_toolMgr
Definition tool_base.h:220
KIGFX::VIEW * getView() const
Returns the instance of #VIEW object used in the application.
Definition tool_base.cpp:38
RESET_REASON
Determine the reason of reset for a tool.
Definition tool_base.h:78
@ REDRAW
Full drawing refresh.
Definition tool_base.h:83
@ SHUTDOWN
Tool is being shut down.
Definition tool_base.h:84
@ 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:171
const VECTOR2D Position() const
Return mouse cursor position in world coordinates.
Definition tool_event.h:293
bool IsAction(const TOOL_ACTION *aAction) const
Test if the event contains an action issued upon activation of the given TOOL_ACTION.
void SetPassEvent(bool aPass=true)
Definition tool_event.h:256
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).
std::unique_ptr< 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.
double Distance(const VECTOR2< extended_type > &aVector) const
Compute the distance between two vectors.
Definition vector2d.h:553
KICURSOR
Definition cursors.h:44
@ LINE_BUS
Definition cursors.h:90
@ LINE_WIRE
Definition cursors.h:94
@ SUBTRACT
Definition cursors.h:72
@ SELECT_WINDOW
Definition cursors.h:86
@ SELECT_LASSO
Definition cursors.h:88
@ MOVING
Definition cursors.h:48
@ ARROW
Definition cursors.h:46
@ LINE_GRAPHIC
Definition cursors.h:92
#define DEFAULT_TEXT_SIZE
Ratio of the font height to the baseline of the text above the wire.
static constexpr EDA_ANGLE ANGLE_VERTICAL
Definition eda_angle.h:408
static constexpr EDA_ANGLE ANGLE_HORIZONTAL
Definition eda_angle.h:407
@ RECURSE
Definition eda_item.h:53
@ NO_RECURSE
Definition eda_item.h:54
#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 SELECTION_CANDIDATE
indicates an item is a candidate for selection
#define ENTERED
indicates a group has been entered
#define ENDPOINT
ends. (Used to support dragging.)
std::uint32_t EDA_ITEM_FLAGS
#define IS_MOVING
Item being moved.
#define SHOW_ELEC_TYPE
Show pin electrical type.
#define STARTPOINT
When a line is selected, these flags indicate which.
@ ID_POPUP_SCH_PIN_TRICKS_START
Definition eeschema_id.h:99
@ ID_POPUP_SCH_PIN_TRICKS_HIER_LABEL
@ ID_POPUP_SCH_PIN_TRICKS_WIRE
@ ID_POPUP_SCH_PLACE_UNIT_END
Definition eeschema_id.h:93
@ ID_POPUP_SCH_ALT_PIN_FUNCTION
@ ID_POPUP_SCH_UNFOLD_BUS_END
Definition eeschema_id.h:82
@ ID_POPUP_SCH_SELECT_UNIT
Definition eeschema_id.h:85
@ ID_POPUP_SCH_SELECT_BODY_STYLE
Definition eeschema_id.h:95
@ ID_POPUP_SCH_PIN_TRICKS_NET_LABEL
@ ID_POPUP_SCH_SELECT_BODY_STYLE_END
Definition eeschema_id.h:97
@ ID_POPUP_SCH_PIN_TRICKS_NO_CONNECT
@ ID_POPUP_SCH_UNFOLD_BUS
Definition eeschema_id.h:81
@ ID_POPUP_SCH_SELECT_UNIT_END
Definition eeschema_id.h:89
@ ID_POPUP_SCH_ALT_PIN_FUNCTION_END
@ ID_POPUP_SCH_PLACE_UNIT
Definition eeschema_id.h:91
@ ID_POPUP_SCH_PIN_TRICKS_GLOBAL_LABEL
@ ID_POPUP_SCH_PIN_TRICKS_END
@ FRAME_SCH_VIEWER
Definition frame_type.h:36
a few functions useful in geometry calculations.
GRID_HELPER_GRIDS
Definition grid_helper.h:44
@ GRID_WIRES
Definition grid_helper.h:49
KIID niluuid(0)
@ LAYER_WIRE
Definition layer_ids.h:454
@ LAYER_BUS
Definition layer_ids.h:455
MOUSE_DRAG_ACTION
bool BoxHitTest(const VECTOR2I &aHitPoint, const BOX2I &aHittee, int aAccuracy)
Perform a point-to-box hit test.
@ REPAINT
Item needs to be redrawn.
Definition view_item.h:58
ELECTRICAL_PINTYPE
The symbol library pin object electrical types used in ERC tests.
Definition pin_type.h:36
@ PT_INPUT
usual pin input: must be connected
Definition pin_type.h:37
@ PT_OUTPUT
usual output
Definition pin_type.h:38
@ PT_TRISTATE
tri state bus pin
Definition pin_type.h:40
@ PT_BIDI
input or output (like port for a microprocessor)
Definition pin_type.h:39
@ PT_UNSPECIFIED
unknown electrical properties: creates always a warning when connected
Definition pin_type.h:45
@ PT_PASSIVE
pin for passive symbols: must be connected, and can be connected to any pin.
Definition pin_type.h:43
@ PIN_UP
The pin extends upwards from the connection point: Probably on the bottom side of the symbol.
Definition pin_type.h:127
@ PIN_RIGHT
The pin extends rightwards from the connection point.
Definition pin_type.h:111
@ PIN_LEFT
The pin extends leftwards from the connection point: Probably on the right side of the symbol.
Definition pin_type.h:118
@ PIN_DOWN
The pin extends downwards from the connection: Probably on the top side of the symbol.
Definition pin_type.h:135
CITER next(CITER it)
Definition ptree.cpp:124
#define HITTEST_THRESHOLD_PIXELS
Class to handle a set of SCH_ITEMs.
std::vector< SCH_ITEM * > SCH_ITEM_VEC
Definition sch_item.h:157
std::vector< EDA_ITEM * > EDA_ITEMS
@ L_BIDI
Definition sch_label.h:104
@ L_TRISTATE
Definition sch_label.h:105
@ L_UNSPECIFIED
Definition sch_label.h:106
@ L_OUTPUT
Definition sch_label.h:103
@ L_INPUT
Definition sch_label.h:102
@ LABEL_BIDI
Definition sch_label.h:122
@ LABEL_INPUT
Definition sch_label.h:120
@ LABEL_OUTPUT
Definition sch_label.h:121
@ LABEL_PASSIVE
Definition sch_label.h:124
@ LABEL_TRISTATE
Definition sch_label.h:123
static std::vector< KICAD_T > connectedTypes
static std::vector< KICAD_T > tableCellTypes
static std::vector< KICAD_T > expandConnectionGraphTypes
static std::vector< KICAD_T > lineTypes
static std::vector< KICAD_T > sheetTypes
const TOOL_ACTION * allowedActions[]
static void passEvent(TOOL_EVENT *const aEvent, const TOOL_ACTION *const aAllowedActions[])
static std::vector< KICAD_T > connectedLineTypes
static std::vector< KICAD_T > crossProbingTypes
std::vector< SCH_SYMBOL * > GetSameSymbolMultiUnitSelection(const SELECTION &aSel)
Validates and gathers a selection containing multiple symbol units that all belong to the same refere...
std::function< bool(const SELECTION &)> SELECTION_CONDITION
Functor type that checks a specific condition for selected items.
SELECTION_MODE
std::vector< FAB_LAYER_COLOR > dummy
bool symbols
Allow selecting symbols and sheet symbols.
bool labels
Net and bus labels.
bool pins
Symbol and sheet pins.
bool graphics
Graphic lines, shapes, polygons.
bool lockedItems
Allow selecting locked items.
bool images
Bitmap/vector images.
bool otherItems
Anything not fitting one of the above categories.
bool wires
Net and bus wires and junctions.
void RotateAndMirrorPin(SCH_PIN &aPin, int aOrientMirror)
Rotate and/or mirror a SCH_PIN according to aOrientMirror.
std::string path
KIBIS top(path, &reporter)
KIBIS_PIN * pin
std::vector< std::vector< std::string > > table
VECTOR2I end
int delta
@ TA_CHOICE_MENU_CHOICE
Context menu choice.
Definition tool_event.h:98
@ TA_UNDO_REDO_PRE
This event is sent before undo/redo command is performed.
Definition tool_event.h:106
@ TA_MOUSE_WHEEL
Definition tool_event.h:73
std::optional< TOOL_EVENT > OPT_TOOL_EVENT
Definition tool_event.h:641
@ MD_ALT
Definition tool_event.h:145
@ MD_CTRL
Definition tool_event.h:144
@ MD_SHIFT
Definition tool_event.h:143
@ TC_COMMAND
Definition tool_event.h:57
@ BUT_AUX1
Definition tool_event.h:135
@ BUT_MIDDLE
Definition tool_event.h:134
@ BUT_LEFT
Definition tool_event.h:132
@ BUT_RIGHT
Definition tool_event.h:133
@ BUT_AUX2
Definition tool_event.h:136
@ SCH_GROUP_T
Definition typeinfo.h:174
@ SCH_TABLE_T
Definition typeinfo.h:166
@ SCH_LINE_T
Definition typeinfo.h:164
@ LIB_SYMBOL_T
Definition typeinfo.h:149
@ SCH_NO_CONNECT_T
Definition typeinfo.h:161
@ SCH_SYMBOL_T
Definition typeinfo.h:173
@ SCH_TABLECELL_T
Definition typeinfo.h:167
@ SCH_ITEM_LOCATE_WIRE_T
Definition typeinfo.h:187
@ SCH_FIELD_T
Definition typeinfo.h:151
@ SCH_DIRECTIVE_LABEL_T
Definition typeinfo.h:172
@ SCH_LABEL_T
Definition typeinfo.h:168
@ SCH_LOCATE_ANY_T
Definition typeinfo.h:200
@ SCH_SHEET_T
Definition typeinfo.h:176
@ SCH_ITEM_LOCATE_BUS_T
Definition typeinfo.h:188
@ SCH_MARKER_T
Definition typeinfo.h:159
@ SCH_SHAPE_T
Definition typeinfo.h:150
@ SCH_RULE_AREA_T
Definition typeinfo.h:171
@ SCH_HIER_LABEL_T
Definition typeinfo.h:170
@ NOT_USED
the 3d code uses this value
Definition typeinfo.h:76
@ SCH_BUS_BUS_ENTRY_T
Definition typeinfo.h:163
@ SCH_ITEM_LOCATE_GRAPHIC_LINE_T
Definition typeinfo.h:189
@ SCHEMATIC_T
Definition typeinfo.h:205
@ SCH_SHEET_PIN_T
Definition typeinfo.h:175
@ SCH_TEXT_T
Definition typeinfo.h:152
@ SCH_SYMBOL_LOCATE_POWER_T
Definition typeinfo.h:197
@ SCH_BUS_WIRE_ENTRY_T
Definition typeinfo.h:162
@ SCH_BITMAP_T
Definition typeinfo.h:165
@ SCH_TEXTBOX_T
Definition typeinfo.h:153
@ SCH_GLOBAL_LABEL_T
Definition typeinfo.h:169
@ SCH_JUNCTION_T
Definition typeinfo.h:160
@ SCH_PIN_T
Definition typeinfo.h:154
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:687
VECTOR2< double > VECTOR2D
Definition vector2d.h:686