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 <eeschema_id.h>
34#include <symbol_edit_frame.h>
35#include <symbol_viewer_frame.h>
36#include <math/util.h>
37#include <geometry/shape_rect.h>
38#include <sch_painter.h>
40#include <sch_commit.h>
41#include <sch_edit_frame.h>
42#include <sch_line.h>
43#include <sch_bus_entry.h>
44#include <sch_group.h>
45#include <sch_marker.h>
46#include <sch_no_connect.h>
47#include <sch_sheet_pin.h>
48#include <sch_table.h>
49#include <tool/tool_event.h>
50#include <tool/tool_manager.h>
55#include <trigo.h>
56#include <view/view.h>
57#include <view/view_controls.h>
58#include <wx/log.h>
59
61
62
64{
65 if( aSel.GetSize() == 1 )
66 {
67 SCH_SYMBOL* symbol = dynamic_cast<SCH_SYMBOL*>( aSel.Front() );
68
69 if( symbol )
70 return !symbol->GetLibSymbolRef() || !symbol->GetLibSymbolRef()->IsPower();
71 }
72
73 return false;
74};
75
76
78{
79 return aSel.GetSize() == 1 && aSel.Front()->Type() == SCH_SYMBOL_T;
80};
81
82
84{
85 if( aSel.GetSize() == 1 )
86 {
87 SCH_SYMBOL* symbol = dynamic_cast<SCH_SYMBOL*>( aSel.Front() );
88
89 if( symbol )
90 return symbol->GetLibSymbolRef() && symbol->GetLibSymbolRef()->HasAlternateBodyStyle();
91 }
92
93 return false;
94};
95
96
98{
99 if( aSel.GetSize() == 1 )
100 {
101 SCH_SYMBOL* symbol = dynamic_cast<SCH_SYMBOL*>( aSel.Front() );
102
103 if( symbol )
104 return symbol->GetLibSymbolRef() && symbol->GetLibSymbolRef()->GetUnitCount() >= 2;
105 }
106
107 return false;
108};
109
110
112{
113 if( aSel.GetSize() == 1 )
114 {
115 SCH_PIN* pin = dynamic_cast<SCH_PIN*>( aSel.Front() );
116
117 if( pin && pin->GetLibPin() )
118 return !pin->GetLibPin()->GetAlternates().empty();
119 }
120
121 return false;
122};
123
124
126{
127 if( aSel.CountType( SCH_MARKER_T ) != 1 )
128 return false;
129
130 return !static_cast<SCH_MARKER*>( aSel.Front() )->IsExcluded();
131};
132
133
135{
136 return aSel.GetSize() > 1 && aSel.OnlyContains( { SCH_SYMBOL_T } );
137};
138
139
141{
142 return aSel.GetSize() >= 1 && aSel.OnlyContains( { SCH_PIN_T } );
143};
144
145
147{
148 return aSel.GetSize() >= 1 && aSel.OnlyContains( { SCH_PIN_T, SCH_SHEET_PIN_T } );
149};
150
151
152#define HITTEST_THRESHOLD_PIXELS 5
153
154
156 SELECTION_TOOL( "common.InteractiveSelection" ),
157 m_frame( nullptr ),
158 m_nonModifiedCursor( KICURSOR::ARROW ),
159 m_isSymbolEditor( false ),
160 m_isSymbolViewer( false ),
161 m_unit( 0 ),
162 m_bodyStyle( 0 ),
163 m_enteredGroup( nullptr ),
164 m_previous_first_cell( nullptr )
165{
168}
169
170
172{
175}
176
177
178static std::vector<KICAD_T> connectedTypes =
179{
181 SCH_PIN_T,
192};
193
194static std::vector<KICAD_T> connectedLineTypes =
195{
198};
199
200static std::vector<KICAD_T> crossProbingTypes =
201{
203 SCH_PIN_T,
205};
206
207static std::vector<KICAD_T> lineTypes = { SCH_LINE_T };
208static std::vector<KICAD_T> sheetTypes = { SCH_SHEET_T };
209static std::vector<KICAD_T> tableCellTypes = { SCH_TABLECELL_T };
210
212{
213 m_frame = getEditFrame<SCH_BASE_FRAME>();
214
215 SYMBOL_VIEWER_FRAME* symbolViewerFrame = dynamic_cast<SYMBOL_VIEWER_FRAME*>( m_frame );
216 SYMBOL_EDIT_FRAME* symbolEditorFrame = dynamic_cast<SYMBOL_EDIT_FRAME*>( m_frame );
217
218 if( symbolEditorFrame )
219 {
220 m_isSymbolEditor = true;
221 m_unit = symbolEditorFrame->GetUnit();
222 m_bodyStyle = symbolEditorFrame->GetBodyStyle();
223 }
224 else
225 {
226 m_isSymbolViewer = symbolViewerFrame != nullptr;
227 }
228
229 // clang-format off
230 auto linesSelection = SCH_CONDITIONS::MoreThan( 0 ) && SCH_CONDITIONS::OnlyTypes( lineTypes );
231 auto wireOrBusSelection = SCH_CONDITIONS::Count( 1 ) && SCH_CONDITIONS::OnlyTypes( connectedLineTypes );
232 auto connectedSelection = SCH_CONDITIONS::Count( 1 ) && SCH_CONDITIONS::OnlyTypes( connectedTypes );
233 auto sheetSelection = SCH_CONDITIONS::Count( 1 ) && SCH_CONDITIONS::OnlyTypes( sheetTypes );
234 auto crossProbingSelection = SCH_CONDITIONS::MoreThan( 0 ) && SCH_CONDITIONS::HasTypes( crossProbingTypes );
235 auto tableCellSelection = SCH_CONDITIONS::MoreThan( 0 ) && SCH_CONDITIONS::OnlyTypes( tableCellTypes );
236 // clang-format on
237
238 auto schEditSheetPageNumberCondition =
239 [&] ( const SELECTION& aSel )
240 {
242 return false;
243
244 return SCH_CONDITIONS::LessThan( 2 )( aSel )
246 };
247
248 auto schEditCondition =
249 [this] ( const SELECTION& aSel )
250 {
252 };
253
254 auto belowRootSheetCondition =
255 [&]( const SELECTION& aSel )
256 {
257 SCH_EDIT_FRAME* editFrame = dynamic_cast<SCH_EDIT_FRAME*>( m_frame );
258
259 return editFrame
260 && editFrame->GetCurrentSheet().Last() != &editFrame->Schematic().Root();
261 };
262
263 auto haveHighlight =
264 [&]( const SELECTION& sel )
265 {
266 SCH_EDIT_FRAME* editFrame = dynamic_cast<SCH_EDIT_FRAME*>( m_frame );
267
268 return editFrame && !editFrame->GetHighlightedConnection().IsEmpty();
269 };
270
271 auto haveSymbol =
272 [&]( const SELECTION& sel )
273 {
274 return m_isSymbolEditor &&
275 static_cast<SYMBOL_EDIT_FRAME*>( m_frame )->GetCurSymbol();
276 };
277
278 auto groupEnterCondition =
280
281 auto inGroupCondition =
282 [this] ( const SELECTION& )
283 {
284 return m_enteredGroup != nullptr;
285 };
286
287 auto symbolDisplayNameIsEditable =
288 [&]( const SELECTION& sel )
289 {
290 if ( !m_isSymbolEditor )
291 return false;
292
293 SYMBOL_EDIT_FRAME* symbEditorFrame = dynamic_cast<SYMBOL_EDIT_FRAME*>( m_frame );
294
295 return symbEditorFrame
296 && symbEditorFrame->GetCurSymbol()
297 && symbEditorFrame->GetCurSymbol()->IsMulti()
298 && symbEditorFrame->IsSymbolEditable()
299 && !symbEditorFrame->IsSymbolAlias();
300 };
301
302 auto& menu = m_menu->GetMenu();
303
304 // clang-format off
305 menu.AddItem( ACTIONS::groupEnter, groupEnterCondition, 1 );
306 menu.AddItem( ACTIONS::groupLeave, inGroupCondition, 1 );
307 menu.AddItem( SCH_ACTIONS::placeLinkedDesignBlock, groupEnterCondition, 1 );
308 menu.AddItem( SCH_ACTIONS::saveToLinkedDesignBlock, groupEnterCondition, 1 );
309 menu.AddItem( SCH_ACTIONS::clearHighlight, haveHighlight && SCH_CONDITIONS::Idle, 1 );
310 menu.AddSeparator( haveHighlight && SCH_CONDITIONS::Idle, 1 );
311
312 menu.AddItem( ACTIONS::selectColumns, tableCellSelection && SCH_CONDITIONS::Idle, 2 );
313 menu.AddItem( ACTIONS::selectRows, tableCellSelection && SCH_CONDITIONS::Idle, 2 );
314 menu.AddItem( ACTIONS::selectTable, tableCellSelection && SCH_CONDITIONS::Idle, 2 );
315
316 menu.AddSeparator( 100 );
317 menu.AddItem( SCH_ACTIONS::drawWire, schEditCondition && SCH_CONDITIONS::Empty, 100 );
318 menu.AddItem( SCH_ACTIONS::drawBus, schEditCondition && SCH_CONDITIONS::Empty, 100 );
319
320 menu.AddSeparator( 100 );
322
323 menu.AddItem( SCH_ACTIONS::enterSheet, sheetSelection && SCH_CONDITIONS::Idle, 150 );
324 menu.AddItem( SCH_ACTIONS::selectOnPCB, crossProbingSelection && schEditCondition && SCH_CONDITIONS::Idle, 150 );
325 menu.AddItem( SCH_ACTIONS::leaveSheet, belowRootSheetCondition, 150 );
326
327 menu.AddSeparator( 200 );
328 menu.AddItem( SCH_ACTIONS::placeJunction, wireOrBusSelection && SCH_CONDITIONS::Idle, 250 );
329 menu.AddItem( SCH_ACTIONS::placeLabel, wireOrBusSelection && SCH_CONDITIONS::Idle, 250 );
330 menu.AddItem( SCH_ACTIONS::placeClassLabel, wireOrBusSelection && SCH_CONDITIONS::Idle, 250 );
331 menu.AddItem( SCH_ACTIONS::placeGlobalLabel, wireOrBusSelection && SCH_CONDITIONS::Idle, 250 );
332 menu.AddItem( SCH_ACTIONS::placeHierLabel, wireOrBusSelection && SCH_CONDITIONS::Idle, 250 );
333 menu.AddItem( SCH_ACTIONS::breakWire, linesSelection && SCH_CONDITIONS::Idle, 250 );
334 menu.AddItem( SCH_ACTIONS::slice, linesSelection && SCH_CONDITIONS::Idle, 250 );
335 menu.AddItem( SCH_ACTIONS::placeSheetPin, sheetSelection && SCH_CONDITIONS::Idle, 250 );
336 menu.AddItem( SCH_ACTIONS::autoplaceAllSheetPins, sheetSelection && SCH_CONDITIONS::Idle, 250 );
337 menu.AddItem( SCH_ACTIONS::syncSheetPins, sheetSelection && SCH_CONDITIONS::Idle, 250 );
338 menu.AddItem( SCH_ACTIONS::assignNetclass, connectedSelection && SCH_CONDITIONS::Idle, 250 );
339 menu.AddItem( SCH_ACTIONS::editPageNumber, schEditSheetPageNumberCondition, 250 );
340
341 menu.AddSeparator( 400 );
342 menu.AddItem( SCH_ACTIONS::symbolProperties, haveSymbol && SCH_CONDITIONS::Empty, 400 );
343 menu.AddItem( SCH_ACTIONS::pinTable, haveSymbol && SCH_CONDITIONS::Empty, 400 );
344 menu.AddItem( SCH_ACTIONS::setUnitDisplayName, haveSymbol && symbolDisplayNameIsEditable && SCH_CONDITIONS::Empty, 400 );
345
346 menu.AddSeparator( 1000 );
348 // clang-format on
349
350 m_disambiguateTimer.SetOwner( this );
351 Connect( m_disambiguateTimer.GetId(), wxEVT_TIMER,
352 wxTimerEventHandler( SCH_SELECTION_TOOL::onDisambiguationExpire ), nullptr, this );
353
354 return true;
355}
356
357
359{
360 m_frame = getEditFrame<SCH_BASE_FRAME>();
361
362 if( aReason != TOOL_BASE::REDRAW )
363 {
364 if( m_enteredGroup )
365 ExitGroup();
366
367 // Remove pointers to the selected items from containers without changing their
368 // properties (as they are already deleted while a new sheet is loaded)
370 }
371
372 if( aReason == RESET_REASON::SHUTDOWN )
373 return;
374
375 if( aReason == TOOL_BASE::MODEL_RELOAD || aReason == TOOL_BASE::SUPERMODEL_RELOAD )
376 {
377 getView()->GetPainter()->GetSettings()->SetHighlight( false );
378
379 SYMBOL_EDIT_FRAME* symbolEditFrame = dynamic_cast<SYMBOL_EDIT_FRAME*>( m_frame );
380 SYMBOL_VIEWER_FRAME* symbolViewerFrame = dynamic_cast<SYMBOL_VIEWER_FRAME*>( m_frame );
381
382 if( symbolEditFrame )
383 {
384 m_isSymbolEditor = true;
385 m_unit = symbolEditFrame->GetUnit();
386 m_bodyStyle = symbolEditFrame->GetBodyStyle();
387 }
388 else
389 {
390 m_isSymbolViewer = symbolViewerFrame != nullptr;
391 }
392 }
393
394 // Reinsert the VIEW_GROUP, in case it was removed from the VIEW
396 getView()->Add( &m_selection );
397
400}
401
403{
404 m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::ARROW );
405
406 KIID lastRolloverItem = niluuid;
408
409 auto pinOrientation =
410 []( EDA_ITEM* aItem )
411 {
412 SCH_PIN* pin = dynamic_cast<SCH_PIN*>( aItem );
413
414 if( pin )
415 {
416 const SCH_SYMBOL* parent = dynamic_cast<const SCH_SYMBOL*>( pin->GetParentSymbol() );
417
418 if( !parent )
419 return pin->GetOrientation();
420 else
421 {
422 SCH_PIN dummy( *pin );
424 return dummy.GetOrientation();
425 }
426 }
427
428 SCH_SHEET_PIN* sheetPin = dynamic_cast<SCH_SHEET_PIN*>( aItem );
429
430 if( sheetPin )
431 {
432 switch( sheetPin->GetSide() )
433 {
434 default:
435 case SHEET_SIDE::LEFT: return PIN_ORIENTATION::PIN_RIGHT;
436 case SHEET_SIDE::RIGHT: return PIN_ORIENTATION::PIN_LEFT;
437 case SHEET_SIDE::TOP: return PIN_ORIENTATION::PIN_DOWN;
438 case SHEET_SIDE::BOTTOM: return PIN_ORIENTATION::PIN_UP;
439 }
440 }
441
442 return PIN_ORIENTATION::PIN_LEFT;
443 };
444
445 // Main loop: keep receiving events
446 while( TOOL_EVENT* evt = Wait() )
447 {
448 bool selCancelled = false;
449 bool displayWireCursor = false;
450 bool displayBusCursor = false;
451 bool displayLineCursor = false;
452 KIID rolloverItem = lastRolloverItem;
453
454 // on left click, a selection is made, depending on modifiers ALT, SHIFT, CTRL:
455 setModifiersState( evt->Modifier( MD_SHIFT ), evt->Modifier( MD_CTRL ),
456 evt->Modifier( MD_ALT ) );
457
458 MOUSE_DRAG_ACTION drag_action = m_frame->GetDragAction();
459
460 if( evt->IsMouseDown( BUT_LEFT ) )
461 {
462 if( !m_frame->ToolStackIsEmpty() )
463 {
464 // Avoid triggering when running under other tools
465 }
468 {
469 // Distinguish point editor from selection modification by checking modifiers
470 if( hasModifier() )
471 {
473 m_disambiguateTimer.StartOnce( ADVANCED_CFG::GetCfg().m_DisambiguationMenuDelay );
474 }
475 }
476 else
477 {
479 m_disambiguateTimer.StartOnce( ADVANCED_CFG::GetCfg().m_DisambiguationMenuDelay );
480 }
481 }
482 // Single click? Select single object
483 else if( evt->IsClick( BUT_LEFT ) )
484 {
485 // If the timer has stopped, then we have already run the disambiguate routine
486 // and we don't want to register an extra click here
487 if( !m_disambiguateTimer.IsRunning() )
488 {
489 evt->SetPassEvent();
490 continue;
491 }
492
493 m_disambiguateTimer.Stop();
494
495 if( SCH_EDIT_FRAME* schframe = dynamic_cast<SCH_EDIT_FRAME*>( m_frame ) )
496 schframe->ClearFocus();
497
498 // Collect items at the clicked location (doesn't select them yet)
499 SCH_COLLECTOR collector;
500 CollectHits( collector, evt->Position() );
501 narrowSelection( collector, evt->Position(), false );
502
503 if( m_selection.GetSize() != 0 && dynamic_cast<SCH_TABLECELL*>( m_selection.GetItem( 0 ) ) && m_additive
504 && collector.GetCount() == 1 && dynamic_cast<SCH_TABLECELL*>( collector[0] ) )
505 {
506 SCH_TABLECELL* firstCell = static_cast<SCH_TABLECELL*>( m_selection.GetItem( 0 ) );
507 SCH_TABLECELL* clickedCell = static_cast<SCH_TABLECELL*>( collector[0] );
508 bool allCellsFromSameTable = true;
509
510 if( m_previous_first_cell == nullptr || m_selection.GetSize() == 1)
511 {
512 m_previous_first_cell = firstCell;
513 }
514
516 {
517 if( !static_cast<SCH_TABLECELL*>( selection )
518 || selection->GetParent() != clickedCell->GetParent() )
519 {
520 allCellsFromSameTable = false;
521 }
522 }
523
524 if( m_previous_first_cell && clickedCell && allCellsFromSameTable )
525 {
526 for( auto selection : m_selection )
527 {
528 selection->ClearSelected();
529 }
531 SCH_TABLE* parentTable = dynamic_cast<SCH_TABLE*>( m_previous_first_cell->GetParent() );
532
534 VECTOR2D end = clickedCell->GetCenter();
535
536 if( parentTable )
537 {
538 InitializeSelectionState( parentTable );
539
540 VECTOR2D topLeft( std::min( start.x, end.x ), std::min( start.y, end.y ) );
541 VECTOR2D bottomRight( std::max( start.x, end.x ), std::max( start.y, end.y ) );
542
543 SelectCellsBetween( topLeft, bottomRight - topLeft, parentTable );
544 }
545 }
546 }
547 else if( collector.GetCount() == 1 && !m_isSymbolEditor && !hasModifier() )
548 {
549 OPT_TOOL_EVENT autostart = autostartEvent( evt, grid, collector[0] );
550
551 if( autostart )
552 {
554
555 params->layer = autostart->Parameter<const DRAW_SEGMENT_EVENT_PARAMS*>()->layer;
556 params->quitOnDraw = true;
557 params->sourceSegment = dynamic_cast<SCH_LINE*>( collector[0] );
558
559 autostart->SetParameter<const DRAW_SEGMENT_EVENT_PARAMS*>( params );
560 m_toolMgr->ProcessEvent( *autostart );
561
562 selCancelled = true;
563 }
564 else if( collector[0]->IsHypertext() )
565 {
566 collector[ 0 ]->DoHypertextAction( m_frame );
567 selCancelled = true;
568 }
569 else if( collector[0]->IsBrightened() )
570 {
571 if( SCH_EDIT_FRAME* schframe = dynamic_cast<SCH_EDIT_FRAME*>( m_frame ) )
572 {
573 NET_NAVIGATOR_ITEM_DATA itemData( schframe->GetCurrentSheet(),
574 collector[0] );
575
576 schframe->SelectNetNavigatorItem( &itemData );
577 }
578 }
579 }
580
581 if( !selCancelled )
582 {
583 selectPoint( collector, evt->Position(), nullptr, nullptr, m_additive,
585 m_selection.SetIsHover( false );
586 }
587 }
588 else if( evt->IsClick( BUT_RIGHT ) )
589 {
590 m_disambiguateTimer.Stop();
591
592 // right click? if there is any object - show the context menu
593 if( m_selection.Empty() )
594 {
596 SelectPoint( evt->Position(), { SCH_LOCATE_ANY_T }, nullptr, &selCancelled );
597 m_selection.SetIsHover( true );
598 }
599 // If the cursor has moved off the bounding box of the selection by more than
600 // a grid square, check to see if there is another item available for selection
601 // under the cursor. If there is, the user likely meant to get the context menu
602 // for that item. If there is no new item, then keep the original selection and
603 // show the context menu for it.
604 else if( !m_selection.GetBoundingBox().Inflate( grid.GetGrid().x, grid.GetGrid().y )
605 .Contains( evt->Position() ) )
606 {
607 SCH_COLLECTOR collector;
608
609 if( CollectHits( collector, evt->Position(), { SCH_LOCATE_ANY_T } ) )
610 {
612
613 SelectPoint( evt->Position(), { SCH_LOCATE_ANY_T }, nullptr, &selCancelled );
614 m_selection.SetIsHover( true );
615 }
616 }
617
618 if( !selCancelled )
619 m_menu->ShowContextMenu( m_selection );
620 }
621 else if( evt->IsDblClick( BUT_LEFT ) )
622 {
623 m_disambiguateTimer.Stop();
624
625 // double click? Display the properties window
626 if( SCH_EDIT_FRAME* schframe = dynamic_cast<SCH_EDIT_FRAME*>( m_frame ) )
627 schframe->ClearFocus();
628
629 if( m_selection.Empty() )
630 SelectPoint( evt->Position() );
631
632 EDA_ITEM* item = m_selection.Front();
633
634 if( item && item->Type() == SCH_SHEET_T )
636 else if( m_selection.GetSize() == 1 && m_selection[0]->Type() == SCH_GROUP_T )
637 EnterGroup();
638 else
640 }
641 else if( evt->IsDblClick( BUT_MIDDLE ) )
642 {
643 m_disambiguateTimer.Stop();
644
645 // Middle double click? Do zoom to fit or zoom to objects
646 if( evt->Modifier( MD_CTRL ) ) // Is CTRL key down?
648 else
650 }
651 else if( evt->IsDrag( BUT_LEFT ) )
652 {
653 m_disambiguateTimer.Stop();
654
655 // Is another tool already moving a new object? Don't allow a drag start
656 if( !m_selection.Empty() && m_selection[0]->HasFlag( IS_NEW | IS_MOVING ) )
657 {
658 evt->SetPassEvent();
659 continue;
660 }
661
662 // drag with LMB? Select multiple objects (or at least draw a selection box) or
663 // drag them
664 if( SCH_EDIT_FRAME* schframe = dynamic_cast<SCH_EDIT_FRAME*>( m_frame ) )
665 schframe->ClearFocus();
666
667 SCH_COLLECTOR collector;
668
669 if( m_selection.GetSize() == 1 && dynamic_cast<SCH_TABLE*>( m_selection.GetItem( 0 ) ) )
670 {
672 }
673 // Allow drag selecting table cells, except when they're inside a group that we haven't entered
674 else if( CollectHits( collector, evt->DragOrigin(), { SCH_TABLECELL_T } )
675 && ( collector[0]->GetParent()->GetParentGroup() == nullptr
676 || collector[0]->GetParent()->GetParentGroup() == m_enteredGroup ) )
677 {
678 selectTableCells( static_cast<SCH_TABLE*>( collector[0]->GetParent() ) );
679 }
680 else if( hasModifier() || drag_action == MOUSE_DRAG_ACTION::SELECT )
681 {
683 }
684 else if( m_selection.Empty() && drag_action != MOUSE_DRAG_ACTION::DRAG_ANY )
685 {
687 }
688 else
689 {
690 if( m_isSymbolEditor )
691 {
692 if( static_cast<SYMBOL_EDIT_FRAME*>( m_frame )->IsSymbolAlias() )
693 {
695 }
696 else
697 {
701 SCH_PIN_T,
702 SCH_FIELD_T } );
703 }
704 }
705 else
706 {
708 }
709
710 // Check if dragging has started within any of selected items bounding box
711 if( evt->HasPosition() && selectionContains( evt->DragOrigin() ) )
712 {
713 // drag_is_move option exists only in schematic editor, not in symbol editor
714 // (m_frame->eeconfig() returns nullptr in Symbol Editor)
717 else
719 }
720 else
721 {
722 // No -> drag a selection box
724 }
725 }
726 }
727 else if( evt->IsMouseDown( BUT_AUX1 ) )
728 {
730 }
731 else if( evt->IsMouseDown( BUT_AUX2 ) )
732 {
734 }
735 else if( evt->Action() == TA_MOUSE_WHEEL )
736 {
737 int field = -1;
738
739 if( evt->Modifier() == ( MD_SHIFT | MD_ALT ) )
740 field = 0;
741 else if( evt->Modifier() == ( MD_CTRL | MD_ALT ) )
742 field = 1;
743 // any more?
744
745 if( field >= 0 )
746 {
747 const int delta = evt->Parameter<int>();
748 ACTIONS::INCREMENT incParams{
749 delta > 0 ? 1 : -1,
750 field,
751 };
752
754 }
755 }
756 else if( evt->Category() == TC_COMMAND && evt->Action() == TA_CHOICE_MENU_CHOICE )
757 {
758 m_disambiguateTimer.Stop();
759
760 // context sub-menu selection? Handle unit selection or bus unfolding
761 if( *evt->GetCommandId() >= ID_POPUP_SCH_SELECT_UNIT
762 && *evt->GetCommandId() <= ID_POPUP_SCH_SELECT_UNIT_END )
763 {
764 SCH_SYMBOL* symbol = dynamic_cast<SCH_SYMBOL*>( m_selection.Front() );
765 int unit = *evt->GetCommandId() - ID_POPUP_SCH_SELECT_UNIT;
766
767 if( symbol )
768 static_cast<SCH_EDIT_FRAME*>( m_frame )->SelectUnit( symbol, unit );
769 }
770 else if( *evt->GetCommandId() >= ID_POPUP_SCH_SELECT_BASE
771 && *evt->GetCommandId() <= ID_POPUP_SCH_SELECT_ALT )
772 {
773 SCH_SYMBOL* symbol = dynamic_cast<SCH_SYMBOL*>( m_selection.Front() );
774 int bodyStyle = ( *evt->GetCommandId() - ID_POPUP_SCH_SELECT_BASE ) + 1;
775
776 if( symbol && symbol->GetBodyStyle() != bodyStyle )
777 static_cast<SCH_EDIT_FRAME*>( m_frame )->FlipBodyStyle( symbol );
778 }
779 else if( *evt->GetCommandId() >= ID_POPUP_SCH_ALT_PIN_FUNCTION
780 && *evt->GetCommandId() <= ID_POPUP_SCH_ALT_PIN_FUNCTION_END )
781 {
782 SCH_PIN* pin = dynamic_cast<SCH_PIN*>( m_selection.Front() );
783 wxString alt = *evt->Parameter<wxString*>();
784
785 if( pin )
786 static_cast<SCH_EDIT_FRAME*>( m_frame )->SetAltPinFunction( pin, alt );
787 }
788 else if( *evt->GetCommandId() >= ID_POPUP_SCH_PIN_TRICKS_START
789 && *evt->GetCommandId() <= ID_POPUP_SCH_PIN_TRICKS_END
791 {
792 SCH_EDIT_FRAME* sch_frame = static_cast<SCH_EDIT_FRAME*>( m_frame );
793
794 // Keep track of new items so we make them the new selection at the end
795 EDA_ITEMS newItems;
796 SCH_COMMIT commit( sch_frame );
797
798 if( *evt->GetCommandId() == ID_POPUP_SCH_PIN_TRICKS_NO_CONNECT )
799 {
800 for( EDA_ITEM* item : m_selection )
801 {
802 if( item->Type() != SCH_PIN_T && item->Type() != SCH_SHEET_PIN_T )
803 continue;
804
805 SCH_NO_CONNECT* nc = new SCH_NO_CONNECT( item->GetPosition() );
806 commit.Add( nc, sch_frame->GetScreen() );
807 newItems.push_back( nc );
808 }
809
810 if( !commit.Empty() )
811 {
812 commit.Push( wxS( "No Connect Pins" ) );
814 }
815 }
816 else if( *evt->GetCommandId() == ID_POPUP_SCH_PIN_TRICKS_WIRE )
817 {
818 VECTOR2I wireGrid = grid.GetGridSize( GRID_HELPER_GRIDS::GRID_WIRES );
819
820 for( EDA_ITEM* item : m_selection )
821 {
822 if( item->Type() != SCH_PIN_T && item->Type() != SCH_SHEET_PIN_T )
823 continue;
824
825 SCH_LINE* wire = new SCH_LINE( item->GetPosition(), LAYER_WIRE );
826
827 // Add some length to the wire as nothing in our code base handles
828 // 0 length wires very well, least of all the ortho drag algorithm
829 VECTOR2I stub;
830
831 switch( pinOrientation( item ) )
832 {
833 default:
834 case PIN_ORIENTATION::PIN_RIGHT:
835 stub = VECTOR2I( -1 * wireGrid.x, 0 );
836 break;
837 case PIN_ORIENTATION::PIN_LEFT:
838 stub = VECTOR2I( 1 * wireGrid.x, 0 );
839 break;
840 case PIN_ORIENTATION::PIN_UP:
841 stub = VECTOR2I( 0, 1 * wireGrid.y );
842 break;
843 case PIN_ORIENTATION::PIN_DOWN:
844 stub = VECTOR2I( 0, -1 * wireGrid.y );
845 break;
846 }
847
848 wire->SetEndPoint( item->GetPosition() + stub );
849
850 m_frame->AddToScreen( wire, sch_frame->GetScreen() );
851 commit.Added( wire, sch_frame->GetScreen() );
852 newItems.push_back( wire );
853 }
854
855 if( !commit.Empty() )
856 {
858 AddItemsToSel( &newItems );
859
860 // Select only the ends so we can immediately start dragging them
861 for( EDA_ITEM* item : newItems )
862 static_cast<SCH_LINE*>( item )->SetFlags( ENDPOINT );
863
865
866 // Put the mouse on the nearest point of the first wire
867 SCH_LINE* first = static_cast<SCH_LINE*>( newItems[0] );
868 vc->SetCrossHairCursorPosition( first->GetEndPoint(), false );
869 vc->WarpMouseCursor( vc->GetCursorPosition(), true );
870
871 // Start the drag tool, canceling will remove the wires
872 if( m_toolMgr->RunSynchronousAction( SCH_ACTIONS::drag, &commit, false ) )
873 commit.Push( wxS( "Wire Pins" ) );
874 else
875 commit.Revert();
876 }
877 }
878 else
879 {
880 // For every pin in the selection, add a label according to menu item
881 // selected by the user
882 for( EDA_ITEM* item : m_selection )
883 {
884 SCH_PIN* pin = dynamic_cast<SCH_PIN*>( item );
885 SCH_SHEET_PIN* sheetPin = dynamic_cast<SCH_SHEET_PIN*>( item );
886 SCH_LABEL_BASE* label = nullptr;
887 SCH_SHEET_PATH& sheetPath = sch_frame->GetCurrentSheet();
888
889 wxString labelText;
890
891 if( pin )
892 {
893 labelText = pin->GetShownName();
894
895 if( labelText.IsEmpty() )
896 {
897 labelText.Printf( "%s_%s",
898 pin->GetParentSymbol()->GetRef( &sheetPath ),
899 pin->GetNumber() );
900 }
901 }
902 else if( sheetPin )
903 {
904 labelText = sheetPin->GetShownText( &sheetPath, false );
905 }
906 else
907 {
908 continue;
909 }
910
911 switch( *evt->GetCommandId() )
912 {
914 label = new SCH_LABEL( item->GetPosition(), labelText );
915 break;
917 label = new SCH_HIERLABEL( item->GetPosition(), labelText );
918 break;
920 label = new SCH_GLOBALLABEL( item->GetPosition(), labelText );
921 break;
922 default:
923 continue;
924 }
925
926 switch( pinOrientation( item ) )
927 {
928 default:
929 case PIN_ORIENTATION::PIN_RIGHT:
931 break;
932 case PIN_ORIENTATION::PIN_LEFT:
934 break;
935 case PIN_ORIENTATION::PIN_UP:
937 break;
938 case PIN_ORIENTATION::PIN_DOWN:
940 break;
941 }
942
943 ELECTRICAL_PINTYPE pinType = ELECTRICAL_PINTYPE::PT_UNSPECIFIED;
944
945 if( pin )
946 {
947 pinType = pin->GetType();
948 }
949 else if( sheetPin )
950 {
951 switch( sheetPin->GetLabelShape() )
952 {
953 case LABEL_INPUT: pinType = ELECTRICAL_PINTYPE::PT_INPUT; break;
954 case LABEL_OUTPUT: pinType = ELECTRICAL_PINTYPE::PT_OUTPUT; break;
955 case LABEL_BIDI: pinType = ELECTRICAL_PINTYPE::PT_BIDI; break;
956 case LABEL_TRISTATE: pinType = ELECTRICAL_PINTYPE::PT_TRISTATE; break;
957 case LABEL_PASSIVE: pinType = ELECTRICAL_PINTYPE::PT_PASSIVE; break;
958 }
959 }
960
961 switch( pinType )
962 {
963 case ELECTRICAL_PINTYPE::PT_BIDI:
964 label->SetShape( LABEL_FLAG_SHAPE::L_BIDI );
965 break;
966 case ELECTRICAL_PINTYPE::PT_INPUT:
967 label->SetShape( LABEL_FLAG_SHAPE::L_INPUT );
968 break;
969 case ELECTRICAL_PINTYPE::PT_OUTPUT:
970 label->SetShape( LABEL_FLAG_SHAPE::L_OUTPUT );
971 break;
972 case ELECTRICAL_PINTYPE::PT_TRISTATE:
973 label->SetShape( LABEL_FLAG_SHAPE::L_TRISTATE );
974 break;
975 case ELECTRICAL_PINTYPE::PT_UNSPECIFIED:
976 label->SetShape( LABEL_FLAG_SHAPE::L_UNSPECIFIED );
977 break;
978 default:
979 label->SetShape( LABEL_FLAG_SHAPE::L_INPUT );
980 }
981
982 commit.Add( label, sch_frame->GetScreen() );
983 newItems.push_back( label );
984 }
985
986 if( !commit.Empty() )
987 {
988 commit.Push( wxS( "Label Pins" ) );
989
990 // Many users will want to drag these items to wire off of the pins, so
991 // pre-select them.
993 AddItemsToSel( &newItems );
994 }
995 }
996 }
997 else if( *evt->GetCommandId() >= ID_POPUP_SCH_UNFOLD_BUS
998 && *evt->GetCommandId() <= ID_POPUP_SCH_UNFOLD_BUS_END )
999 {
1000 wxString* net = new wxString( *evt->Parameter<wxString*>() );
1001 m_toolMgr->RunAction<wxString*>( SCH_ACTIONS::unfoldBus, net );
1002 }
1003 }
1004 else if( evt->IsCancelInteractive() )
1005 {
1006 m_disambiguateTimer.Stop();
1007
1008 // We didn't set these, but we have reports that they leak out of some other tools,
1009 // so we clear them here.
1010 getViewControls()->SetAutoPan( false );
1011 getViewControls()->CaptureCursor( false );
1012
1013 if( SCH_EDIT_FRAME* schframe = dynamic_cast<SCH_EDIT_FRAME*>( m_frame ) )
1014 schframe->ClearFocus();
1015
1016 if( !GetSelection().Empty() )
1017 {
1019 }
1020 else if( evt->FirstResponder() == this && evt->GetCommandId() == (int) WXK_ESCAPE )
1021 {
1022 if( m_enteredGroup )
1023 {
1024 ExitGroup();
1025 }
1026 else
1027 {
1029
1031 editor->ClearHighlight( *evt );
1032 }
1033 }
1034 }
1035 else if( evt->Action() == TA_UNDO_REDO_PRE )
1036 {
1037 if( SCH_EDIT_FRAME* schframe = dynamic_cast<SCH_EDIT_FRAME*>( m_frame ) )
1038 schframe->ClearFocus();
1039 }
1040 else if( evt->IsMotion() && !m_isSymbolEditor && evt->FirstResponder() == this )
1041 {
1042 // Update cursor and rollover item
1043 rolloverItem = niluuid;
1044 SCH_COLLECTOR collector;
1045
1047
1048 if( CollectHits( collector, evt->Position() ) )
1049 {
1050 narrowSelection( collector, evt->Position(), false );
1051
1052 if( collector.GetCount() == 1 && !hasModifier() )
1053 {
1054 OPT_TOOL_EVENT autostartEvt = autostartEvent( evt, grid, collector[0] );
1055
1056 if( autostartEvt )
1057 {
1058 if( autostartEvt->Matches( SCH_ACTIONS::drawBus.MakeEvent() ) )
1059 displayBusCursor = true;
1060 else if( autostartEvt->Matches( SCH_ACTIONS::drawWire.MakeEvent() ) )
1061 displayWireCursor = true;
1062 else if( autostartEvt->Matches( SCH_ACTIONS::drawLines.MakeEvent() ) )
1063 displayLineCursor = true;
1064 }
1065 else if( collector[0]->IsHypertext() && !collector[0]->IsSelected() )
1066 {
1067 rolloverItem = collector[0]->m_Uuid;
1068 }
1069 }
1070 }
1071 }
1072 else
1073 {
1074 evt->SetPassEvent();
1075 }
1076
1077 if( lastRolloverItem != niluuid && lastRolloverItem != rolloverItem )
1078 {
1079 EDA_ITEM* item = m_frame->ResolveItem( lastRolloverItem );
1080
1081 if( item->IsRollover() )
1082 {
1083 item->SetIsRollover( false );
1084
1085 if( item->Type() == SCH_FIELD_T || item->Type() == SCH_TABLECELL_T )
1086 m_frame->GetCanvas()->GetView()->Update( item->GetParent() );
1087 else
1088 m_frame->GetCanvas()->GetView()->Update( item );
1089 }
1090 }
1091
1092 if( rolloverItem != niluuid )
1093 {
1094 EDA_ITEM* item = m_frame->ResolveItem( rolloverItem );
1095
1096 if( !item->IsRollover() )
1097 {
1098 item->SetIsRollover( true );
1099
1100 if( item->Type() == SCH_FIELD_T || item->Type() == SCH_TABLECELL_T )
1101 m_frame->GetCanvas()->GetView()->Update( item->GetParent() );
1102 else
1103 m_frame->GetCanvas()->GetView()->Update( item );
1104 }
1105 }
1106
1107 lastRolloverItem = rolloverItem;
1108
1109 if( m_frame->ToolStackIsEmpty() )
1110 {
1111 if( displayWireCursor )
1112 {
1113 m_nonModifiedCursor = KICURSOR::LINE_WIRE;
1114 }
1115 else if( displayBusCursor )
1116 {
1117 m_nonModifiedCursor = KICURSOR::LINE_BUS;
1118 }
1119 else if( displayLineCursor )
1120 {
1121 m_nonModifiedCursor = KICURSOR::LINE_GRAPHIC;
1122 }
1123 else if( rolloverItem != niluuid )
1124 {
1125 m_nonModifiedCursor = KICURSOR::HAND;
1126 }
1127 else if( !m_selection.Empty()
1128 && drag_action == MOUSE_DRAG_ACTION::DRAG_SELECTED
1129 && evt->HasPosition()
1130 && selectionContains( evt->Position() ) //move/drag option prediction
1131 )
1132 {
1133 m_nonModifiedCursor = KICURSOR::MOVING;
1134 }
1135 else
1136 {
1137 m_nonModifiedCursor = KICURSOR::ARROW;
1138 }
1139 }
1140 }
1141
1142 m_disambiguateTimer.Stop();
1143
1144 // Shutting down; clear the selection
1146
1147 return 0;
1148}
1149
1150
1152{
1153 wxCHECK_RET( m_selection.GetSize() == 1 && m_selection[0]->Type() == SCH_GROUP_T,
1154 wxT( "EnterGroup called when selection is not a single group" ) );
1155 SCH_GROUP* aGroup = static_cast<SCH_GROUP*>( m_selection[0] );
1156
1157 if( m_enteredGroup != nullptr )
1158 ExitGroup();
1159
1161 m_enteredGroup = aGroup;
1164 [&]( SCH_ITEM* aChild )
1165 {
1166 if( aChild->Type() == SCH_LINE_T )
1167 aChild->SetFlags( STARTPOINT | ENDPOINT );
1168
1169 select( aChild );
1170 },
1171 RECURSE_MODE::NO_RECURSE );
1172
1174
1175 getView()->Hide( m_enteredGroup, true );
1178}
1179
1180
1181void SCH_SELECTION_TOOL::ExitGroup( bool aSelectGroup )
1182{
1183 // Only continue if there is a group entered
1184 if( m_enteredGroup == nullptr )
1185 return;
1186
1188 getView()->Hide( m_enteredGroup, false );
1190
1191 if( aSelectGroup )
1192 {
1195 }
1196
1198 m_enteredGroup = nullptr;
1200}
1201
1202
1204 SCH_ITEM* aItem )
1205{
1206 VECTOR2I pos = aGrid.BestSnapAnchor( aEvent->Position(), aGrid.GetItemGrid( aItem ) );
1207
1210 && aItem->IsPointClickableAnchor( pos ) )
1211 {
1213
1214 if( aItem->Type() == SCH_BUS_BUS_ENTRY_T )
1215 {
1217 }
1218 else if( aItem->Type() == SCH_BUS_WIRE_ENTRY_T )
1219 {
1220 SCH_BUS_WIRE_ENTRY* busEntry = static_cast<SCH_BUS_WIRE_ENTRY*>( aItem );
1221
1222 if( !busEntry->m_connected_bus_item )
1224 }
1225 else if( aItem->Type() == SCH_LINE_T )
1226 {
1227 SCH_LINE* line = static_cast<SCH_LINE*>( aItem );
1228
1229 if( line->IsBus() )
1230 newEvt = SCH_ACTIONS::drawBus.MakeEvent();
1231 else if( line->IsGraphicLine() )
1232 newEvt = SCH_ACTIONS::drawLines.MakeEvent();
1233 }
1234 else if( aItem->Type() == SCH_LABEL_T || aItem->Type() == SCH_HIER_LABEL_T
1235 || aItem->Type() == SCH_SHEET_PIN_T || aItem->Type() == SCH_GLOBAL_LABEL_T )
1236 {
1237 SCH_LABEL_BASE* label = static_cast<SCH_LABEL_BASE*>( aItem );
1238 SCH_CONNECTION possibleConnection( label->Schematic()->ConnectionGraph() );
1239 possibleConnection.ConfigureFromLabel( label->GetShownText( false ) );
1240
1241 if( possibleConnection.IsBus() )
1243 }
1244 else if( aItem->Type() == SCH_SYMBOL_T )
1245 {
1246 const SCH_SYMBOL* symbol = static_cast<const SCH_SYMBOL*>( aItem );
1247 const SCH_PIN* pin = symbol->GetPin( pos );
1248
1249 if( !pin || !pin->IsPointClickableAnchor( pos ) )
1250 return OPT_TOOL_EVENT();
1251
1252 if( !pin->IsVisible()
1255 {
1256 return OPT_TOOL_EVENT();
1257 }
1258 }
1259
1260 newEvt->SetMousePosition( pos );
1261 newEvt->SetHasPosition( true );
1262 newEvt->SetForceImmediate( true );
1263
1264 getViewControls()->ForceCursorPosition( true, pos );
1265
1266 return newEvt;
1267 }
1268
1269 return OPT_TOOL_EVENT();
1270}
1271
1272
1274{
1275 wxMouseState keyboardState = wxGetMouseState();
1276
1277 setModifiersState( keyboardState.ShiftDown(), keyboardState.ControlDown(),
1278 keyboardState.AltDown() );
1279
1280 m_skip_heuristics = true;
1283 m_skip_heuristics = false;
1284
1285 return 0;
1286}
1287
1288
1289void SCH_SELECTION_TOOL::OnIdle( wxIdleEvent& aEvent )
1290{
1292 {
1293 wxMouseState keyboardState = wxGetMouseState();
1294
1295 setModifiersState( keyboardState.ShiftDown(), keyboardState.ControlDown(),
1296 keyboardState.AltDown() );
1297
1298 if( m_additive )
1299 m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::ADD );
1300 else if( m_subtractive )
1301 m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::SUBTRACT );
1302 else if( m_exclusive_or )
1303 m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::XOR );
1304 else
1306 }
1307}
1308
1309
1311{
1312 return m_selection;
1313}
1314
1315
1317 const std::vector<KICAD_T>& aScanTypes )
1318{
1319 int pixelThreshold = KiROUND( getView()->ToWorld( HITTEST_THRESHOLD_PIXELS ) );
1320 int gridThreshold = KiROUND( getView()->GetGAL()->GetGridSize().EuclideanNorm() / 2.0 );
1321 aCollector.m_Threshold = std::max( pixelThreshold, gridThreshold );
1323
1324 if( m_isSymbolEditor )
1325 {
1326 LIB_SYMBOL* symbol = static_cast<SYMBOL_EDIT_FRAME*>( m_frame )->GetCurSymbol();
1327
1328 if( !symbol )
1329 return false;
1330
1331 aCollector.Collect( symbol->GetDrawItems(), aScanTypes, aWhere, m_unit, m_bodyStyle );
1332 }
1333 else
1334 {
1335 aCollector.Collect( m_frame->GetScreen(), aScanTypes, aWhere, m_unit, m_bodyStyle );
1336
1337 // If pins are disabled in the filter, they will be removed later. Let's add the parent
1338 // so that people can use pins to select symbols in this case.
1339 if( !m_filter.pins )
1340 {
1341 int originalCount = aCollector.GetCount();
1342
1343 for( int ii = 0; ii < originalCount; ++ii )
1344 {
1345 if( aCollector[ii]->Type() == SCH_PIN_T )
1346 {
1347 SCH_PIN* pin = static_cast<SCH_PIN*>( aCollector[ii] );
1348
1349 if( !aCollector.HasItem( pin->GetParentSymbol() ) )
1350 aCollector.Append( pin->GetParentSymbol() );
1351 }
1352 }
1353 }
1354 }
1355
1356 return aCollector.GetCount() > 0;
1357}
1358
1359
1361 bool aCheckLocked, bool aSelectedOnly )
1362{
1363 SYMBOL_EDIT_FRAME* symbolEditorFrame = dynamic_cast<SYMBOL_EDIT_FRAME*>( m_frame );
1364
1365 for( int i = collector.GetCount() - 1; i >= 0; --i )
1366 {
1367 if( symbolEditorFrame )
1368 {
1369 // Do not select invisible items if they are not displayed
1370 EDA_ITEM* item = collector[i];
1371
1372 if( item->Type() == SCH_FIELD_T )
1373 {
1374 if( !static_cast<SCH_FIELD*>( item )->IsVisible()
1375 && !symbolEditorFrame->GetShowInvisibleFields() )
1376 {
1377 collector.Remove( i );
1378 continue;
1379 }
1380 }
1381 else if( item->Type() == SCH_PIN_T )
1382 {
1383 if( !static_cast<SCH_PIN*>( item )->IsVisible()
1384 && !symbolEditorFrame->GetShowInvisiblePins() )
1385 {
1386 collector.Remove( i );
1387 continue;
1388 }
1389 }
1390 }
1391
1392 if( !Selectable( collector[i], &aWhere ) )
1393 {
1394 collector.Remove( i );
1395 continue;
1396 }
1397
1398 if( aCheckLocked && collector[i]->IsLocked() )
1399 {
1400 collector.Remove( i );
1401 continue;
1402 }
1403
1404 if( !itemPassesFilter( collector[i] ) )
1405 {
1406 collector.Remove( i );
1407 continue;
1408 }
1409
1410 if( aSelectedOnly && !collector[i]->IsSelected() )
1411 {
1412 collector.Remove( i );
1413 continue;
1414 }
1415 }
1416
1417 filterCollectorForHierarchy( collector, false );
1418
1419 // Apply some ugly heuristics to avoid disambiguation menus whenever possible
1420 if( collector.GetCount() > 1 && !m_skip_heuristics )
1421 GuessSelectionCandidates( collector, aWhere );
1422}
1423
1424
1426 EDA_ITEM** aItem, bool* aSelectionCancelledFlag, bool aAdd,
1427 bool aSubtract, bool aExclusiveOr )
1428{
1430
1431 // If still more than one item we're going to have to ask the user.
1432 if( aCollector.GetCount() > 1 )
1433 {
1434 // Try to call selectionMenu via RunAction() to avoid event-loop contention
1435 // But it we cannot handle the event, then we don't have an active tool loop, so
1436 // handle it directly.
1437 if( !m_toolMgr->RunAction<COLLECTOR*>( ACTIONS::selectionMenu, &aCollector ) )
1438 {
1439 if( !doSelectionMenu( &aCollector ) )
1440 aCollector.m_MenuCancelled = true;
1441 }
1442
1443 if( aCollector.m_MenuCancelled )
1444 {
1445 if( aSelectionCancelledFlag )
1446 *aSelectionCancelledFlag = true;
1447
1448 return false;
1449 }
1450 }
1451
1452 if( !aAdd && !aSubtract && !aExclusiveOr )
1454
1455 // It is possible for slop in the selection model to cause us to be outside the group,
1456 // but also selecting an item within the group, so only exit if the selection doesn't
1457 // have an item belonging to the group
1459 {
1460 bool foundEnteredGroup = false;
1461 for( EDA_ITEM* item : aCollector )
1462 {
1463 if( item->GetParentGroup() == m_enteredGroup )
1464 {
1465 foundEnteredGroup = true;
1466 break;
1467 }
1468 }
1469
1470 if( !foundEnteredGroup )
1471 ExitGroup();
1472 }
1473
1474 filterCollectorForHierarchy( aCollector, true );
1475
1476 int addedCount = 0;
1477 bool anySubtracted = false;
1478
1479 if( aCollector.GetCount() > 0 )
1480 {
1481 for( int i = 0; i < aCollector.GetCount(); ++i )
1482 {
1483 EDA_ITEM_FLAGS flags = 0;
1484 bool isLine = aCollector[i]->Type() == SCH_LINE_T;
1485
1486 // Handle line ends specially
1487 if( isLine )
1488 {
1489 SCH_LINE* line = (SCH_LINE*) aCollector[i];
1490
1491 if( line->GetStartPoint().Distance( aWhere ) <= aCollector.m_Threshold )
1492 flags = STARTPOINT;
1493 else if( line->GetEndPoint().Distance( aWhere ) <= aCollector.m_Threshold )
1494 flags = ENDPOINT;
1495 else
1496 flags = STARTPOINT | ENDPOINT;
1497 }
1498
1499 if( aSubtract
1500 || ( aExclusiveOr && aCollector[i]->IsSelected()
1501 && ( !isLine || ( isLine && aCollector[i]->HasFlag( flags ) ) ) ) )
1502 {
1503 aCollector[i]->ClearFlags( flags );
1504
1505 // Need to update end shadows after ctrl-click unselecting one of two selected
1506 // endpoints.
1507 if( isLine )
1508 getView()->Update( aCollector[i] );
1509
1510 if( !aCollector[i]->HasFlag( STARTPOINT ) && !aCollector[i]->HasFlag( ENDPOINT ) )
1511 {
1512 unselect( aCollector[i] );
1513 anySubtracted = true;
1514 }
1515 }
1516 else
1517 {
1518 aCollector[i]->SetFlags( flags );
1519 select( aCollector[i] );
1520 addedCount++;
1521 }
1522 }
1523 }
1524
1525 if( addedCount == 1 )
1526 {
1528
1529 if( aItem && aCollector.GetCount() == 1 )
1530 *aItem = aCollector[0];
1531
1532 return true;
1533 }
1534 else if( addedCount > 1 )
1535 {
1537 return true;
1538 }
1539 else if( anySubtracted )
1540 {
1542 return true;
1543 }
1544
1546 return false;
1547}
1548
1549
1551 const std::vector<KICAD_T>& aScanTypes,
1552 EDA_ITEM** aItem, bool* aSelectionCancelledFlag,
1553 bool aCheckLocked, bool aAdd, bool aSubtract,
1554 bool aExclusiveOr )
1555{
1556 SCH_COLLECTOR collector;
1557
1558 if( !CollectHits( collector, aWhere, aScanTypes ) )
1559 return false;
1560
1561 narrowSelection( collector, aWhere, aCheckLocked, aSubtract );
1562
1563 return selectPoint( collector, aWhere, aItem, aSelectionCancelledFlag, aAdd, aSubtract,
1564 aExclusiveOr );
1565}
1566
1567
1569{
1570 SCH_COLLECTOR collection;
1571 m_multiple = true; // Multiple selection mode is active
1572 KIGFX::VIEW* view = getView();
1573
1574 std::vector<EDA_ITEM*> sheetPins;
1575
1576 // Filter the view items based on the selection box
1577 BOX2I selectionBox;
1578
1579 selectionBox.SetMaximum();
1580 view->Query( selectionBox,
1581 [&]( KIGFX::VIEW_ITEM* viewItem ) -> bool
1582 {
1583 SCH_ITEM* item = static_cast<SCH_ITEM*>( viewItem );
1584
1585 if( !item )
1586 return true;
1587
1588 collection.Append( item );
1589 return true;
1590 } );
1591
1592 filterCollectorForHierarchy( collection, true );
1593
1594 // Sheet pins aren't in the view; add them by hand
1595 for( EDA_ITEM* item : collection )
1596 {
1597 SCH_SHEET* sheet = dynamic_cast<SCH_SHEET*>( item );
1598
1599 if( sheet )
1600 {
1601 for( SCH_SHEET_PIN* pin : sheet->GetPins() )
1602 sheetPins.emplace_back( pin );
1603 }
1604 }
1605
1606 for( EDA_ITEM* pin : sheetPins )
1607 collection.Append( pin );
1608
1609 for( EDA_ITEM* item : collection )
1610 {
1611 if( Selectable( item ) && itemPassesFilter( item ) )
1612 {
1613 if( item->Type() == SCH_LINE_T )
1614 item->SetFlags( STARTPOINT | ENDPOINT );
1615
1616 select( item );
1617 }
1618 }
1619
1620 m_multiple = false;
1621
1624 return 0;
1625}
1626
1628{
1629 m_multiple = true; // Multiple selection mode is active
1630 KIGFX::VIEW* view = getView();
1631
1632 // hold all visible items
1633 std::vector<KIGFX::VIEW::LAYER_ITEM_PAIR> selectedItems;
1634
1635 // Filter the view items based on the selection box
1636 BOX2I selectionBox;
1637
1638 selectionBox.SetMaximum();
1639 view->Query( selectionBox, selectedItems ); // Get the list of selected items
1640
1641 for( KIGFX::VIEW::LAYER_ITEM_PAIR& pair : selectedItems )
1642 {
1643 SCH_SHEET* sheet = dynamic_cast<SCH_SHEET*>( pair.first );
1644
1645 if( sheet )
1646 {
1647 for( SCH_SHEET_PIN* pin : sheet->GetPins() )
1648 {
1649 EDA_ITEM* item = dynamic_cast<EDA_ITEM*>( pin );
1650
1651 if( item && Selectable( item ) )
1652 unselect( item );
1653 }
1654 }
1655
1656 if( EDA_ITEM* item = dynamic_cast<EDA_ITEM*>( pair.first ) )
1657 {
1658 if( Selectable( item ) )
1659 unselect( item );
1660 }
1661 }
1662
1663 m_multiple = false;
1664
1667 return 0;
1668}
1669
1670
1672{
1673 // Prefer exact hits to sloppy ones
1674 std::set<EDA_ITEM*> exactHits;
1675
1676 for( int i = collector.GetCount() - 1; i >= 0; --i )
1677 {
1678 EDA_ITEM* item = collector[ i ];
1679 SCH_LINE* line = dynamic_cast<SCH_LINE*>( item );
1680 SCH_SHAPE* shape = dynamic_cast<SCH_SHAPE*>( item );
1681 SCH_TABLE* table = dynamic_cast<SCH_TABLE*>( item );
1682
1683 // Lines are hard to hit. Give them a bit more slop to still be considered "exact".
1684 if( line || ( shape && shape->GetShape() == SHAPE_T::POLY )
1685 || ( shape && shape->GetShape() == SHAPE_T::ARC ) )
1686 {
1687 int pixelThreshold = KiROUND( getView()->ToWorld( 6 ) );
1688
1689 if( item->HitTest( aPos, pixelThreshold ) )
1690 exactHits.insert( item );
1691 }
1692 else if( table )
1693 {
1694 // Consider table cells exact, but not the table itself
1695 }
1696 else
1697 {
1698
1700 item->SetFlags( SHOW_ELEC_TYPE );
1701
1702 if( item->HitTest( aPos, 0 ) )
1703 exactHits.insert( item );
1704
1705 item->ClearFlags( SHOW_ELEC_TYPE );
1706 }
1707 }
1708
1709 if( exactHits.size() > 0 && exactHits.size() < (unsigned) collector.GetCount() )
1710 {
1711 for( int i = collector.GetCount() - 1; i >= 0; --i )
1712 {
1713 EDA_ITEM* item = collector[ i ];
1714
1715 if( !exactHits.contains( item ) )
1716 collector.Transfer( item );
1717 }
1718 }
1719
1720 // Find the closest item. (Note that at this point all hits are either exact or non-exact.)
1721 SEG poss( aPos, aPos );
1722 EDA_ITEM* closest = nullptr;
1723 int closestDist = INT_MAX / 4;
1724
1725 for( EDA_ITEM* item : collector )
1726 {
1727 BOX2I bbox = item->GetBoundingBox();
1728 int dist = INT_MAX / 4;
1729
1730 // A dominating item is one that would unfairly win distance tests
1731 // and mask out other items. For example, a filled rectangle "wins"
1732 // with a zero distance over anything inside it.
1733 bool dominating = false;
1734
1735 if( exactHits.contains( item ) )
1736 {
1737 if( item->Type() == SCH_PIN_T || item->Type() == SCH_JUNCTION_T )
1738 {
1739 closest = item;
1740 break;
1741 }
1742
1743 SCH_LINE* line = dynamic_cast<SCH_LINE*>( item );
1744 SCH_FIELD* field = dynamic_cast<SCH_FIELD*>( item );
1745 EDA_TEXT* text = dynamic_cast<EDA_TEXT*>( item );
1746 EDA_SHAPE* shape = dynamic_cast<EDA_SHAPE*>( item );
1747 SCH_SYMBOL* symbol = dynamic_cast<SCH_SYMBOL*>( item );
1748
1749 if( line )
1750 {
1751 dist = line->GetSeg().Distance( aPos );
1752 }
1753 else if( field )
1754 {
1755 BOX2I box = field->GetBoundingBox();
1756 EDA_ANGLE orient = field->GetTextAngle();
1757
1758 if( field->GetParent() && field->GetParent()->Type() == SCH_SYMBOL_T )
1759 {
1760 if( static_cast<SCH_SYMBOL*>( field->GetParent() )->GetTransform().y1 )
1761 {
1762 if( orient.IsHorizontal() )
1763 orient = ANGLE_VERTICAL;
1764 else
1765 orient = ANGLE_HORIZONTAL;
1766 }
1767 }
1768
1769 field->GetEffectiveTextShape( false, box, orient )
1770 ->Collide( poss, INT_MAX / 4, &dist );
1771 }
1772 else if( text )
1773 {
1774 text->GetEffectiveTextShape( false )->Collide( poss, INT_MAX / 4, &dist );
1775 }
1776 else if( shape )
1777 {
1778 std::vector<SHAPE*> shapes = shape->MakeEffectiveShapes();
1779
1780 for( SHAPE* s : shapes )
1781 {
1782 int shapeDist = dist;
1783 s->Collide( poss, INT_MAX / 4, &shapeDist );
1784
1785 if( shapeDist < dist )
1786 dist = shapeDist;
1787
1788 delete s;
1789 }
1790
1791 // Filled shapes win hit tests anywhere inside them
1792 dominating = shape->IsFilledForHitTesting();
1793 }
1794 else if( symbol )
1795 {
1796 bbox = symbol->GetBodyBoundingBox();
1797
1798 SHAPE_RECT rect( bbox.GetPosition(), bbox.GetWidth(), bbox.GetHeight() );
1799
1800 if( bbox.Contains( aPos ) )
1801 dist = bbox.GetCenter().Distance( aPos );
1802 else
1803 rect.Collide( poss, closestDist, &dist );
1804 }
1805 else
1806 {
1807 dist = bbox.GetCenter().Distance( aPos );
1808 }
1809 }
1810 else
1811 {
1812 SHAPE_RECT rect( bbox.GetPosition(), bbox.GetWidth(), bbox.GetHeight() );
1813 rect.Collide( poss, collector.m_Threshold, &dist );
1814 }
1815
1816 // Don't promote dominating items to be the closest item
1817 // (they'll always win) - they'll still be available for selection, but they
1818 // won't boot out worthy competitors.
1819 if ( !dominating )
1820 {
1821 if( dist == closestDist )
1822 {
1823 if( item->GetParent() == closest )
1824 closest = item;
1825 }
1826 else if( dist < closestDist )
1827 {
1828 closestDist = dist;
1829 closest = item;
1830 }
1831 }
1832 }
1833
1834 // Construct a tight box (1/2 height and width) around the center of the closest item.
1835 // All items which exist at least partly outside this box have sufficient other areas
1836 // for selection and can be dropped.
1837 if( closest ) // Don't try and get a tight bbox if nothing is near the mouse pointer
1838 {
1839 BOX2I tightBox = closest->GetBoundingBox();
1840 tightBox.Inflate( -tightBox.GetWidth() / 4, -tightBox.GetHeight() / 4 );
1841
1842 for( int i = collector.GetCount() - 1; i >= 0; --i )
1843 {
1844 EDA_ITEM* item = collector[i];
1845
1846 if( item == closest )
1847 continue;
1848
1849 if( !item->HitTest( tightBox, true ) )
1850 collector.Transfer( item );
1851 }
1852 }
1853}
1854
1855
1856SCH_SELECTION& SCH_SELECTION_TOOL::RequestSelection( const std::vector<KICAD_T>& aScanTypes,
1857 bool aPromoteCellSelections,
1858 bool aPromoteGroups )
1859{
1860 bool anyUnselected = false;
1861 bool anySelected = false;
1862
1863 if( m_selection.Empty() )
1864 {
1865 VECTOR2D cursorPos = getViewControls()->GetCursorPosition( true );
1866
1868 SelectPoint( cursorPos, aScanTypes );
1869 m_selection.SetIsHover( true );
1871 }
1872 else // Trim an existing selection by aFilterList
1873 {
1874 bool isMoving = false;
1875
1876 for( int i = (int) m_selection.GetSize() - 1; i >= 0; --i )
1877 {
1878 EDA_ITEM* item = (EDA_ITEM*) m_selection.GetItem( i );
1879 isMoving |= static_cast<SCH_ITEM*>( item )->IsMoving();
1880
1881 if( !item->IsType( aScanTypes ) )
1882 {
1883 unselect( item );
1884 anyUnselected = true;
1885 }
1886 }
1887
1888 if( !isMoving )
1890 }
1891
1892 if( aPromoteGroups )
1893 {
1894 for( int i = (int) m_selection.GetSize() - 1; i >= 0; --i )
1895 {
1896 EDA_ITEM* item = (EDA_ITEM*) m_selection.GetItem( i );
1897
1898 std::set<EDA_ITEM*> selectedChildren;
1899
1900 if( item->Type() == SCH_GROUP_T )
1901 {
1902 static_cast<SCH_ITEM*>(item)->RunOnChildren( [&]( SCH_ITEM* aChild )
1903 {
1904 if( aChild->IsType( aScanTypes ) )
1905 selectedChildren.insert( aChild );
1906 },
1907 RECURSE_MODE::RECURSE );
1908 unselect( item );
1909 anyUnselected = true;
1910 }
1911
1912 for( EDA_ITEM* child : selectedChildren )
1913 {
1914 if( !child->IsSelected() )
1915 {
1916 if( child->Type() == SCH_LINE_T )
1917 static_cast<SCH_LINE*>( child )->SetFlags( STARTPOINT | ENDPOINT );
1918
1919 select( child );
1920 anySelected = true;
1921 }
1922 }
1923 }
1924 }
1925
1926 if( aPromoteCellSelections )
1927 {
1928 std::set<EDA_ITEM*> parents;
1929
1930 for( int i = (int) m_selection.GetSize() - 1; i >= 0; --i )
1931 {
1932 EDA_ITEM* item = (EDA_ITEM*) m_selection.GetItem( i );
1933
1934 if( item->Type() == SCH_TABLECELL_T )
1935 {
1936 parents.insert( item->GetParent() );
1937 unselect( item );
1938 anyUnselected = true;
1939 }
1940 }
1941
1942 for( EDA_ITEM* parent : parents )
1943 {
1944 if( !parent->IsSelected() )
1945 {
1946 select( parent );
1947 anySelected = true;
1948 }
1949 }
1950 }
1951
1952 if( anyUnselected )
1954
1955 if( anySelected )
1957
1958 return m_selection;
1959}
1960
1961
1962void SCH_SELECTION_TOOL::filterCollectedItems( SCH_COLLECTOR& aCollector, bool aMultiSelect )
1963{
1964 if( aCollector.GetCount() == 0 )
1965 return;
1966
1967 std::set<EDA_ITEM*> rejected;
1968
1969 for( EDA_ITEM* item : aCollector )
1970 {
1971 if( !itemPassesFilter( item ) )
1972 rejected.insert( item );
1973 }
1974
1975 for( EDA_ITEM* item : rejected )
1976 aCollector.Remove( item );
1977}
1978
1979
1981{
1982 if( !aItem )
1983 return false;
1984
1985 // Locking is not yet exposed uniformly in the schematic
1986#if 0
1987 if( SCH_ITEM* schItem = dynamic_cast<SCH_ITEM*>( aItem ) )
1988 {
1989 if( schItem->IsLocked() && !m_filter.lockedItems )
1990 return false;
1991 }
1992#endif
1993
1994 switch( aItem->Type() )
1995 {
1996 case SCH_SYMBOL_T:
1997 case SCH_SHEET_T:
1998 if( !m_filter.symbols )
1999 return false;
2000
2001 break;
2002
2003 case SCH_PIN_T:
2004 case SCH_SHEET_PIN_T:
2005 if( !m_filter.pins )
2006 return false;
2007
2008 break;
2009
2010 case SCH_JUNCTION_T:
2011 if( !m_filter.wires )
2012 return false;
2013
2014 break;
2015
2016 case SCH_LINE_T:
2017 {
2018 switch( static_cast<SCH_LINE*>( aItem )->GetLayer() )
2019 {
2020 case LAYER_WIRE:
2021 case LAYER_BUS:
2022 if( !m_filter.wires )
2023 return false;
2024
2025 break;
2026
2027 default:
2028 if( !m_filter.graphics )
2029 return false;
2030 }
2031
2032 break;
2033 }
2034
2035 case SCH_SHAPE_T:
2036 if( !m_filter.graphics )
2037 return false;
2038
2039 break;
2040
2041 case SCH_TEXT_T:
2042 case SCH_TEXTBOX_T:
2043 case SCH_TABLE_T:
2044 case SCH_TABLECELL_T:
2045 case SCH_FIELD_T:
2046 if( !m_filter.text )
2047 return false;
2048
2049 break;
2050
2051 case SCH_LABEL_T:
2052 case SCH_GLOBAL_LABEL_T:
2053 case SCH_HIER_LABEL_T:
2054 if( !m_filter.labels )
2055 return false;
2056
2057 break;
2058
2059 case SCH_BITMAP_T:
2060 if( !m_filter.images )
2061 return false;
2062
2063 break;
2064
2065 case SCH_RULE_AREA_T:
2066 if( !m_filter.ruleAreas )
2067 return false;
2068
2069 break;
2070
2071 default:
2072 if( !m_filter.otherItems )
2073 return false;
2074
2075 break;
2076 }
2077
2078 return true;
2079}
2080
2081
2083{
2084 VECTOR2I refP( 0, 0 );
2085
2086 if( m_selection.Size() > 0 )
2087 refP = static_cast<SCH_ITEM*>( m_selection.GetTopLeftItem() )->GetPosition();
2088
2090}
2091
2092
2093// Some navigation actions are allowed in selectMultiple
2103 &ACTIONS::zoomFitObjects, nullptr };
2104
2105
2107{
2108 // Block selection not allowed in symbol viewer frame: no actual code to handle
2109 // a selection, so return to avoid to draw a selection rectangle, and to avoid crashes.
2110 if( m_frame->IsType( FRAME_T::FRAME_SCH_VIEWER ) )
2111 return false;
2112
2113 bool cancelled = false; // Was the tool canceled while it was running?
2114 m_multiple = true; // Multiple selection mode is active
2115 KIGFX::VIEW* view = getView();
2116
2118 view->Add( &area );
2119
2120 while( TOOL_EVENT* evt = Wait() )
2121 {
2122 /* Selection mode depends on direction of drag-selection:
2123 * Left > Right : Select objects that are fully enclosed by selection
2124 * Right > Left : Select objects that are crossed by selection
2125 */
2126 bool isGreedy = area.GetEnd().x < area.GetOrigin().x;
2127
2128 if( view->IsMirroredX() )
2129 isGreedy = !isGreedy;
2130
2131 m_frame->GetCanvas()->SetCurrentCursor( isGreedy ? KICURSOR::SELECT_LASSO
2132 : KICURSOR::SELECT_WINDOW );
2133
2134 if( evt->IsCancelInteractive() || evt->IsActivate() )
2135 {
2136 cancelled = true;
2137 break;
2138 }
2139
2140 if( evt->IsDrag( BUT_LEFT ) )
2141 {
2144
2145 // Start drawing a selection box
2146 area.SetOrigin( evt->DragOrigin() );
2147 area.SetEnd( evt->Position() );
2150 area.SetExclusiveOr( false );
2151 area.SetMode( isGreedy ? SELECTION_MODE::TOUCHING_RECTANGLE
2152 : SELECTION_MODE::INSIDE_RECTANGLE );
2153
2154 view->SetVisible( &area, true );
2155 view->Update( &area );
2156 getViewControls()->SetAutoPan( true );
2157 }
2158
2159 if( evt->IsMouseUp( BUT_LEFT ) )
2160 {
2161 getViewControls()->SetAutoPan( false );
2162
2163 // End drawing the selection box
2164 view->SetVisible( &area, false );
2165
2166 // Fetch items from the RTree that are in our area of interest
2167 std::vector<KIGFX::VIEW::LAYER_ITEM_PAIR> candidates;
2168 BOX2I selectionRect = area.ViewBBox();
2169 view->Query( selectionRect, candidates );
2170
2171 // Ensure candidates only have unique items
2172 std::set<SCH_ITEM*> uniqueCandidates;
2173
2174 for( const auto& [viewItem, layer] : candidates )
2175 {
2176 if( viewItem->IsSCH_ITEM() )
2177 uniqueCandidates.insert( static_cast<SCH_ITEM*>( viewItem ) );
2178 }
2179
2180 for( KIGFX::VIEW_ITEM* item : uniqueCandidates )
2181 {
2182 // If the item is a sheet or symbol, ensure we add its pins because they are not
2183 // in the RTree and we need to check them against the selection box.
2184 if( SCH_SHEET* sheet = dynamic_cast<SCH_SHEET*>( item ) )
2185 {
2186 for( SCH_SHEET_PIN* pin : sheet->GetPins() )
2187 {
2188 // If the pin is within the selection box, add it as a candidate
2189 if( selectionRect.Intersects( pin->GetBoundingBox() ) )
2190 uniqueCandidates.insert( pin );
2191 }
2192 }
2193 else if( SCH_SYMBOL* symbol = dynamic_cast<SCH_SYMBOL*>( item ) )
2194 {
2195 for( SCH_PIN* pin : symbol->GetPins() )
2196 {
2197 // If the pin is within the selection box, add it as a candidate
2198 if( selectionRect.Intersects( pin->GetBoundingBox() ) )
2199 uniqueCandidates.insert( pin );
2200 }
2201 }
2202 }
2203
2204 // Build lists of nearby items and their children
2205 SCH_COLLECTOR collector;
2206 SCH_COLLECTOR pinsCollector;
2207 std::set<EDA_ITEM*> group_items;
2208
2209 for( EDA_ITEM* item : m_frame->GetScreen()->Items().OfType( SCH_GROUP_T ) )
2210 {
2211 SCH_GROUP* group = static_cast<SCH_GROUP*>( item );
2212
2213 // The currently entered group does not get limited
2214 if( m_enteredGroup == group )
2215 continue;
2216
2217 std::unordered_set<EDA_ITEM*>& newset = group->GetItems();
2218
2219 // If we are not greedy and have selected the whole group, add just one item
2220 // to allow it to be promoted to the group later
2221 if( !isGreedy && selectionRect.Contains( group->GetBoundingBox() ) && newset.size() )
2222 {
2223 for( EDA_ITEM* group_item : newset )
2224 {
2225 if( !group_item->IsSCH_ITEM() )
2226 continue;
2227
2228 if( Selectable( static_cast<SCH_ITEM*>( group_item ) ) )
2229 collector.Append( *newset.begin() );
2230 }
2231 }
2232
2233 for( EDA_ITEM* group_item : newset )
2234 group_items.emplace( group_item );
2235 }
2236
2237 for( SCH_ITEM* item : uniqueCandidates )
2238 {
2239 // If the item is a line, add it even if it doesn't pass the hit test using the greedy
2240 // flag as we handle partially selecting line ends later
2241 if( item && Selectable( item )
2242 && ( item->HitTest( selectionRect, !isGreedy ) || item->Type() == SCH_LINE_T )
2243 && ( isGreedy || !group_items.count( item ) ) )
2244 {
2245 if( item->Type() == SCH_PIN_T && !m_isSymbolEditor )
2246 pinsCollector.Append( item );
2247 else
2248 collector.Append( item );
2249 }
2250 }
2251
2252 // Apply the stateful filter
2253 filterCollectedItems( collector, true );
2254
2255 filterCollectorForHierarchy( collector, true );
2256
2257 // If we selected nothing but pins, allow them to be selected
2258 if( collector.GetCount() == 0 )
2259 {
2260 collector = pinsCollector;
2261 filterCollectedItems( collector, true );
2262 filterCollectorForHierarchy( collector, true );
2263 }
2264
2265 // Sort the filtered selection by rows and columns to have a nice default
2266 // for tools that can use it.
2267 std::sort( collector.begin(), collector.end(),
2268 []( EDA_ITEM* a, EDA_ITEM* b )
2269 {
2270 VECTOR2I aPos = a->GetPosition();
2271 VECTOR2I bPos = b->GetPosition();
2272
2273 if( aPos.y == bPos.y )
2274 return aPos.x < bPos.x;
2275
2276 return aPos.y < bPos.y;
2277 } );
2278
2279 bool anyAdded = false;
2280 bool anySubtracted = false;
2281
2282 auto selectItem =
2283 [&]( EDA_ITEM* aItem, EDA_ITEM_FLAGS flags )
2284 {
2285 if( m_subtractive || ( m_exclusive_or && aItem->IsSelected() ) )
2286 {
2287 if ( m_exclusive_or )
2288 aItem->XorFlags( flags );
2289 else
2290 aItem->ClearFlags( flags );
2291
2292 if( !aItem->HasFlag( STARTPOINT ) && !aItem->HasFlag( ENDPOINT ) )
2293 {
2294 unselect( aItem );
2295 anySubtracted = true;
2296 }
2297
2298 // We changed one line endpoint on a selected line,
2299 // update the view at least.
2300 if( flags && !anySubtracted )
2301 getView()->Update( aItem );
2302 }
2303 else
2304 {
2305 aItem->SetFlags( flags );
2306 select( aItem );
2307 anyAdded = true;
2308 }
2309 };
2310
2311 std::vector<EDA_ITEM*> flaggedItems;
2312
2313 for( EDA_ITEM* item : collector )
2314 {
2315 EDA_ITEM_FLAGS flags = 0;
2316
2317 item->SetFlags( SELECTION_CANDIDATE );
2318 flaggedItems.push_back( item );
2319
2321 item->SetFlags( SHOW_ELEC_TYPE );
2322
2323 if( item->Type() == SCH_LINE_T )
2324 {
2325 SCH_LINE* line = static_cast<SCH_LINE*>( item );
2326
2327 if( ( isGreedy && line->HitTest( selectionRect, false ) )
2328 || ( selectionRect.Contains( line->GetEndPoint() )
2329 && selectionRect.Contains( line->GetStartPoint() ) ) )
2330 {
2331 flags |= STARTPOINT | ENDPOINT;
2332 }
2333 else if( !isGreedy )
2334 {
2335 if( selectionRect.Contains( line->GetStartPoint() ) && line->IsStartDangling() )
2336 flags |= STARTPOINT;
2337
2338 if( selectionRect.Contains( line->GetEndPoint() ) && line->IsEndDangling() )
2339 flags |= ENDPOINT;
2340 }
2341
2342 // Only select a line if it at least one point is selected
2343 if( flags & ( STARTPOINT | ENDPOINT ) )
2344 selectItem( item, flags );
2345 }
2346 else
2347 selectItem( item, flags );
2348
2349 item->ClearFlags( SHOW_ELEC_TYPE );
2350 }
2351
2352 for( EDA_ITEM* item : pinsCollector )
2353 {
2355 item->SetFlags( SHOW_ELEC_TYPE );
2356
2357 if( Selectable( item ) && itemPassesFilter( item ) && !item->GetParent()->HasFlag( SELECTION_CANDIDATE )
2358 && item->HitTest( selectionRect, !isGreedy ) )
2359 {
2360 selectItem( item, 0 );
2361 }
2362
2363 item->ClearFlags( SHOW_ELEC_TYPE );
2364 }
2365
2366 for( EDA_ITEM* item : flaggedItems )
2367 item->ClearFlags( SELECTION_CANDIDATE );
2368
2369 m_selection.SetIsHover( false );
2370
2371 // Inform other potentially interested tools
2372 if( anyAdded )
2374
2375 if( anySubtracted )
2377
2378 break; // Stop waiting for events
2379 }
2380
2381 // Allow some actions for navigation
2382 for( int i = 0; allowedActions[i]; ++i )
2383 {
2384 if( evt->IsAction( allowedActions[i] ) )
2385 {
2386 evt->SetPassEvent();
2387 break;
2388 }
2389 }
2390 }
2391
2392 getViewControls()->SetAutoPan( false );
2393
2394 // Stop drawing the selection box
2395 view->Remove( &area );
2396 m_multiple = false; // Multiple selection mode is inactive
2397
2398 if( !cancelled )
2400
2401 return cancelled;
2402}
2403
2404
2406 bool aMultiselect ) const
2407{
2408 std::unordered_set<EDA_ITEM*> toAdd;
2409
2410 // Set SELECTION_CANDIDATE on all parents which are included in the GENERAL_COLLECTOR. This
2411 // algorithm is O(3n), whereas checking for the parent inclusion could potentially be O(n^2).
2412 for( int j = 0; j < aCollector.GetCount(); j++ )
2413 {
2414 if( aCollector[j]->GetParent() )
2415 aCollector[j]->GetParent()->ClearFlags( SELECTION_CANDIDATE );
2416
2417 if( aCollector[j]->GetParentSymbol() )
2418 aCollector[j]->GetParentSymbol()->ClearFlags( SELECTION_CANDIDATE );
2419 }
2420
2421 if( aMultiselect )
2422 {
2423 for( int j = 0; j < aCollector.GetCount(); j++ )
2424 aCollector[j]->SetFlags( SELECTION_CANDIDATE );
2425 }
2426
2427 for( int j = 0; j < aCollector.GetCount(); )
2428 {
2429 SCH_ITEM* item = aCollector[j];
2430 SYMBOL* sym = item->GetParentSymbol();
2431 SCH_ITEM* start = item;
2432
2433 if( !m_isSymbolEditor && sym )
2434 start = sym;
2435
2436 // If a group is entered, disallow selections of objects outside the group.
2438 {
2439 aCollector.Remove( item );
2440 continue;
2441 }
2442
2443 // If any element is a member of a group, replace those elements with the top containing
2444 // group.
2446 {
2447 if( top->AsEdaItem() != item )
2448 {
2449 toAdd.insert( top->AsEdaItem() );
2450 top->AsEdaItem()->SetFlags( SELECTION_CANDIDATE );
2451
2452 aCollector.Remove( item );
2453 continue;
2454 }
2455 }
2456
2457 // Symbols are a bit easier as they can't be nested.
2458 if( sym && ( sym->GetFlags() & SELECTION_CANDIDATE ) )
2459 {
2460 // Remove children of selected items
2461 aCollector.Remove( item );
2462 continue;
2463 }
2464
2465 ++j;
2466 }
2467
2468 for( EDA_ITEM* item : toAdd )
2469 {
2470 if( !aCollector.HasItem( item ) )
2471 aCollector.Append( item );
2472 }
2473}
2474
2475
2477{
2478 getView()->Update( &m_selection );
2480
2481 return 0;
2482}
2483
2484
2486{
2487 for( SCH_TABLECELL* cell : aTable->GetCells() )
2488 {
2489 if( cell->IsSelected() )
2490 cell->SetFlags( SELECTION_CANDIDATE );
2491 else
2492 cell->ClearFlags( SELECTION_CANDIDATE );
2493 }
2494}
2495
2497{
2498 BOX2I selectionRect( start, end );
2499 selectionRect.Normalize();
2500
2501 auto wasSelected = []( EDA_ITEM* aItem )
2502 {
2503 return ( aItem->GetFlags() & SELECTION_CANDIDATE ) > 0;
2504 };
2505
2506 for( SCH_TABLECELL* cell : aTable->GetCells() )
2507 {
2508 bool doSelect = false;
2509
2510 if( cell->HitTest( selectionRect, false ) )
2511 {
2512 if( m_subtractive )
2513 doSelect = false;
2514 else if( m_exclusive_or )
2515 doSelect = !wasSelected( cell );
2516 else
2517 doSelect = true;
2518 }
2519 else if( wasSelected( cell ) )
2520 {
2521 doSelect = m_additive || m_subtractive || m_exclusive_or;
2522 }
2523
2524 if( doSelect && !cell->IsSelected() )
2525 select( cell );
2526 else if( !doSelect && cell->IsSelected() )
2527 unselect( cell );
2528 }
2529}
2530
2532{
2533 bool cancelled = false;
2534 m_multiple = true;
2535
2536 InitializeSelectionState( aTable );
2537
2538 while( TOOL_EVENT* evt = Wait() )
2539 {
2540 if( evt->IsCancelInteractive() || evt->IsActivate() )
2541 {
2542 cancelled = true;
2543 break;
2544 }
2545 else if( evt->IsDrag( BUT_LEFT ) )
2546 {
2547 getViewControls()->SetAutoPan( true );
2548 SelectCellsBetween( evt->DragOrigin(), evt->Position() - evt->DragOrigin(), aTable );
2549 }
2550 else if( evt->IsMouseUp( BUT_LEFT ) )
2551 {
2552 m_selection.SetIsHover( false );
2553
2554 bool anyAdded = false;
2555 bool anySubtracted = false;
2556
2557 for( SCH_TABLECELL* cell : aTable->GetCells() )
2558 {
2559 if( cell->IsSelected() && ( cell->GetFlags() & SELECTION_CANDIDATE ) <= 0 )
2560 anyAdded = true;
2561 else if( ( cell->GetFlags() & SELECTION_CANDIDATE ) > 0 && !cell->IsSelected() )
2562 anySubtracted = true;
2563 }
2564
2565 if( anyAdded )
2567 if( anySubtracted )
2569
2570 break;
2571 }
2572 else
2573 {
2574 for( int i = 0; allowedActions[i]; ++i )
2575 {
2576 if( evt->IsAction( allowedActions[i] ) )
2577 {
2578 evt->SetPassEvent();
2579 break;
2580 }
2581 }
2582 }
2583 }
2584
2585 getViewControls()->SetAutoPan( false );
2586
2587 m_multiple = false;
2588
2589 if( !cancelled )
2591
2592 return cancelled;
2593}
2594
2595
2597{
2598 SCH_COLLECTOR collector;
2599
2600 //TODO(snh): Reimplement after exposing KNN interface
2601 int pixelThreshold = KiROUND( getView()->ToWorld( HITTEST_THRESHOLD_PIXELS ) );
2602 int gridThreshold = KiROUND( getView()->GetGAL()->GetGridSize().EuclideanNorm() );
2603 int thresholdMax = std::max( pixelThreshold, gridThreshold );
2604
2605 for( int threshold : { 0, thresholdMax/4, thresholdMax/2, thresholdMax } )
2606 {
2607 collector.m_Threshold = threshold;
2608 collector.Collect( m_frame->GetScreen(), connectedTypes, aPosition );
2609
2610 if( collector.GetCount() > 0 )
2611 break;
2612 }
2613
2614 return collector.GetCount() ? collector[ 0 ] : nullptr;
2615}
2616
2617
2619{
2620 VECTOR2I cursorPos = getViewControls()->GetCursorPosition( false );
2621
2622 SelectPoint( cursorPos, connectedTypes );
2623 return 0;
2624}
2625
2626
2628{
2631
2632 if( m_selection.Empty() )
2633 return 0;
2634
2636
2637 for( EDA_ITEM* selItem : m_selection.GetItems() )
2638 {
2639 if( selItem->Type() != SCH_LINE_T )
2640 continue;
2641
2642 SCH_LINE* line = static_cast<SCH_LINE*>( selItem );
2643
2644 std::set<SCH_ITEM*> conns = m_frame->GetScreen()->MarkConnections( line, line->IsConnectable() );
2645
2646 for( SCH_ITEM* item : conns )
2647 select( item );
2648 }
2649
2650 if( m_selection.GetSize() > 1 )
2652
2653 return 0;
2654}
2655
2656
2658{
2659 std::set<std::pair<SCH_TABLE*, int>> columns;
2660 bool added = false;
2661
2662 for( EDA_ITEM* item : m_selection )
2663 {
2664 if( SCH_TABLECELL* cell = dynamic_cast<SCH_TABLECELL*>( item ) )
2665 {
2666 SCH_TABLE* table = static_cast<SCH_TABLE*>( cell->GetParent() );
2667 columns.insert( std::make_pair( table, cell->GetColumn() ) );
2668 }
2669 }
2670
2671 for( auto& [ table, col ] : columns )
2672 {
2673 for( int row = 0; row < table->GetRowCount(); ++row )
2674 {
2675 SCH_TABLECELL* cell = table->GetCell( row, col );
2676
2677 if( !cell->IsSelected() )
2678 {
2679 select( table->GetCell( row, col ) );
2680 added = true;
2681 }
2682 }
2683 }
2684
2685 if( added )
2687
2688 return 0;
2689}
2690
2691
2693{
2694 std::set<std::pair<SCH_TABLE*, int>> rows;
2695 bool added = false;
2696
2697 for( EDA_ITEM* item : m_selection )
2698 {
2699 if( SCH_TABLECELL* cell = dynamic_cast<SCH_TABLECELL*>( item ) )
2700 {
2701 SCH_TABLE* table = static_cast<SCH_TABLE*>( cell->GetParent() );
2702 rows.insert( std::make_pair( table, cell->GetRow() ) );
2703 }
2704 }
2705
2706 for( auto& [ table, row ] : rows )
2707 {
2708 for( int col = 0; col < table->GetColCount(); ++col )
2709 {
2710 SCH_TABLECELL* cell = table->GetCell( row, col );
2711
2712 if( !cell->IsSelected() )
2713 {
2714 select( table->GetCell( row, col ) );
2715 added = true;
2716 }
2717 }
2718 }
2719
2720 if( added )
2722
2723 return 0;
2724}
2725
2726
2728{
2729 std::set<SCH_TABLE*> tables;
2730 bool added = false;
2731
2732 for( EDA_ITEM* item : m_selection )
2733 {
2734 if( SCH_TABLECELL* cell = dynamic_cast<SCH_TABLECELL*>( item ) )
2735 tables.insert( static_cast<SCH_TABLE*>( cell->GetParent() ) );
2736 }
2737
2739
2740 for( SCH_TABLE* table : tables )
2741 {
2742 if( !table->IsSelected() )
2743 {
2744 select( table );
2745 added = true;
2746 }
2747 }
2748
2749 if( added )
2751
2752 return 0;
2753}
2754
2755
2757{
2759 return 0;
2760}
2761
2762
2764{
2765 if( aBBox.GetWidth() == 0 )
2766 return;
2767
2768 BOX2I bbox = aBBox;
2769 bbox.Normalize();
2770
2771 VECTOR2I bbSize = bbox.Inflate( KiROUND( bbox.GetWidth() * 0.2f ) ).GetSize();
2772 VECTOR2D screenSize = getView()->GetViewport().GetSize();
2773
2774 // This code tries to come up with a zoom factor that doesn't simply zoom in to the cross
2775 // probed symbol, but instead shows a reasonable amount of the circuit around it to provide
2776 // context. This reduces the need to manually change the zoom because it's too close.
2777
2778 // Using the default text height as a constant to compare against, use the height of the
2779 // bounding box of visible items for a footprint to figure out if this is a big symbol (like
2780 // a processor) or a small symbol (like a resistor). This ratio is not useful by itself as a
2781 // scaling factor. It must be "bent" to provide good scaling at varying symbol sizes. Bigger
2782 // symbols need less scaling than small ones.
2783 double currTextHeight = schIUScale.MilsToIU( DEFAULT_TEXT_SIZE );
2784
2785 double compRatio = bbSize.y / currTextHeight; // Ratio of symbol to text height
2786 double compRatioBent = 1.0;
2787
2788 // LUT to scale zoom ratio to provide reasonable schematic context. Must work with symbols
2789 // of varying sizes (e.g. 0402 package and 200 pin BGA).
2790 // Each entry represents a compRatio (symbol height / default text height) and an amount to
2791 // scale by.
2792 std::vector<std::pair<double, double>> lut{ { 1.25, 16 },
2793 { 2.5, 12 },
2794 { 5, 8 },
2795 { 6, 6 },
2796 { 10, 4 },
2797 { 20, 2 },
2798 { 40, 1.5 },
2799 { 100, 1 } };
2800
2801 std::vector<std::pair<double, double>>::iterator it;
2802
2803 // Large symbol default is last LUT entry (1:1).
2804 compRatioBent = lut.back().second;
2805
2806 // Use LUT to do linear interpolation of "compRatio" within "first", then use that result to
2807 // linearly interpolate "second" which gives the scaling factor needed.
2808 if( compRatio >= lut.front().first )
2809 {
2810 for( it = lut.begin(); it < lut.end() - 1; ++it )
2811 {
2812 if( it->first <= compRatio && next( it )->first >= compRatio )
2813 {
2814 double diffx = compRatio - it->first;
2815 double diffn = next( it )->first - it->first;
2816
2817 compRatioBent = it->second + ( next( it )->second - it->second ) * diffx / diffn;
2818 break; // We have our interpolated value
2819 }
2820 }
2821 }
2822 else
2823 {
2824 compRatioBent = lut.front().second; // Small symbol default is first entry
2825 }
2826
2827 // This is similar to the original KiCad code that scaled the zoom to make sure symbols were
2828 // visible on screen. It's simply a ratio of screen size to symbol size, and its job is to
2829 // zoom in to make the component fullscreen. Earlier in the code the symbol BBox is given a
2830 // 20% margin to add some breathing room. We compare the height of this enlarged symbol bbox
2831 // to the default text height. If a symbol will end up with the sides clipped, we adjust
2832 // later to make sure it fits on screen.
2833 screenSize.x = std::max( 10.0, screenSize.x );
2834 screenSize.y = std::max( 10.0, screenSize.y );
2835 double ratio = std::max( -1.0, fabs( bbSize.y / screenSize.y ) );
2836
2837 // Original KiCad code for how much to scale the zoom
2838 double kicadRatio = std::max( fabs( bbSize.x / screenSize.x ),
2839 fabs( bbSize.y / screenSize.y ) );
2840
2841 // If the width of the part we're probing is bigger than what the screen width will be after
2842 // the zoom, then punt and use the KiCad zoom algorithm since it guarantees the part's width
2843 // will be encompassed within the screen.
2844 if( bbSize.x > screenSize.x * ratio * compRatioBent )
2845 {
2846 // Use standard KiCad zoom for parts too wide to fit on screen/
2847 ratio = kicadRatio;
2848 compRatioBent = 1.0; // Reset so we don't modify the "KiCad" ratio
2849 wxLogTrace( "CROSS_PROBE_SCALE",
2850 "Part TOO WIDE for screen. Using normal KiCad zoom ratio: %1.5f", ratio );
2851 }
2852
2853 // Now that "compRatioBent" holds our final scaling factor we apply it to the original
2854 // fullscreen zoom ratio to arrive at the final ratio itself.
2855 ratio *= compRatioBent;
2856
2857 bool alwaysZoom = false; // DEBUG - allows us to minimize zooming or not
2858
2859 // Try not to zoom on every cross-probe; it gets very noisy
2860 if( ( ratio < 0.5 || ratio > 1.0 ) || alwaysZoom )
2861 getView()->SetScale( getView()->GetScale() / ratio );
2862}
2863
2864
2865void SCH_SELECTION_TOOL::SyncSelection( const std::optional<SCH_SHEET_PATH>& targetSheetPath,
2866 SCH_ITEM* focusItem, const std::vector<SCH_ITEM*>& items )
2867{
2868 SCH_EDIT_FRAME* editFrame = dynamic_cast<SCH_EDIT_FRAME*>( m_frame );
2869
2870 if( !editFrame )
2871 return;
2872
2873 if( targetSheetPath && targetSheetPath != editFrame->Schematic().CurrentSheet() )
2874 {
2875 SCH_SHEET_PATH path = targetSheetPath.value();
2877 }
2878
2879 ClearSelection( items.size() > 0 ? true /*quiet mode*/ : false );
2880
2881 // Perform individual selection of each item before processing the event.
2882 for( SCH_ITEM* item : items )
2883 {
2884 SCH_ITEM* parent = dynamic_cast<SCH_ITEM*>( item->GetParent() );
2885
2886 // Make sure we only select items on the current screen
2887 if( m_frame->GetScreen()->CheckIfOnDrawList( item )
2888 || ( parent && m_frame->GetScreen()->CheckIfOnDrawList( parent ) ) )
2889 {
2890 select( item );
2891 }
2892 }
2893
2895
2896 if( bbox.GetWidth() != 0 && bbox.GetHeight() != 0 )
2897 {
2899 {
2901 ZoomFitCrossProbeBBox( bbox );
2902
2903 editFrame->FocusOnItem( focusItem );
2904
2905 if( !focusItem )
2906 editFrame->FocusOnLocation( bbox.Centre() );
2907 }
2908 }
2909
2910 if( m_selection.Size() > 0 )
2912}
2913
2914
2916{
2918
2919 bool enteredGroupFound = false;
2920
2921 if( m_isSymbolEditor )
2922 {
2923 LIB_SYMBOL* start = static_cast<SYMBOL_EDIT_FRAME*>( m_frame )->GetCurSymbol();
2924
2925 for( SCH_ITEM& item : start->GetDrawItems() )
2926 {
2927 if( item.IsSelected() )
2928 select( &item );
2929
2930 if( item.Type() == SCH_GROUP_T )
2931 {
2932 if( &item == m_enteredGroup )
2933 {
2934 item.SetFlags( ENTERED );
2935 enteredGroupFound = true;
2936 }
2937 else
2938 {
2939 item.ClearFlags( ENTERED );
2940 }
2941 }
2942 }
2943 }
2944 else
2945 {
2946 for( SCH_ITEM* item : m_frame->GetScreen()->Items() )
2947 {
2948 // If the field and symbol are selected, only use the symbol
2949 if( item->IsSelected() )
2950 {
2951 select( item );
2952 }
2953 else
2954 {
2955 item->RunOnChildren(
2956 [&]( SCH_ITEM* aChild )
2957 {
2958 if( aChild->IsSelected() )
2959 select( aChild );
2960 },
2961 RECURSE_MODE::NO_RECURSE );
2962 }
2963
2964 if( item->Type() == SCH_GROUP_T )
2965 {
2966 if( item == m_enteredGroup )
2967 {
2968 item->SetFlags( ENTERED );
2969 enteredGroupFound = true;
2970 }
2971 else
2972 {
2973 item->ClearFlags( ENTERED );
2974 }
2975 }
2976 }
2977 }
2978
2980
2981 if( !enteredGroupFound )
2982 {
2984 m_enteredGroup = nullptr;
2985 }
2986
2987 // Inform other potentially interested tools
2989}
2990
2991
2992bool SCH_SELECTION_TOOL::Selectable( const EDA_ITEM* aItem, const VECTOR2I* aPos,
2993 bool checkVisibilityOnly ) const
2994{
2995 // NOTE: in the future this is where Eeschema layer/itemtype visibility will be handled
2996
2997 SYMBOL_EDIT_FRAME* symEditFrame = dynamic_cast<SYMBOL_EDIT_FRAME*>( m_frame );
2998
2999 // Do not allow selection of anything except fields when the current symbol in the symbol
3000 // editor is a derived symbol.
3001 if( symEditFrame && symEditFrame->IsSymbolAlias() && aItem->Type() != SCH_FIELD_T )
3002 return false;
3003
3004 switch( aItem->Type() )
3005 {
3006 case SCH_PIN_T:
3007 {
3008 const SCH_PIN* pin = static_cast<const SCH_PIN*>( aItem );
3009
3010 if( symEditFrame )
3011 {
3012 if( pin->GetUnit() && pin->GetUnit() != symEditFrame->GetUnit() )
3013 return false;
3014
3015 if( pin->GetBodyStyle() && pin->GetBodyStyle() != symEditFrame->GetBodyStyle() )
3016 return false;
3017 }
3018
3019 if( !pin->IsVisible() && !m_frame->GetShowAllPins() )
3020 return false;
3021
3022 if( !m_filter.pins )
3023 {
3024 // Pin anchors have to be allowed for auto-starting wires.
3025 if( aPos )
3026 {
3028 GRID_HELPER_GRIDS pinGrid = grid.GetItemGrid( pin );
3029
3030 if( pin->IsPointClickableAnchor( grid.BestSnapAnchor( *aPos, pinGrid ) ) )
3031 return true;
3032 }
3033
3034 return false;
3035 }
3036
3037 break;
3038 }
3039
3042 return false;
3043
3044 break;
3045
3046 case LIB_SYMBOL_T: // In symbol_editor we do not want to select the symbol itself.
3047 return false;
3048
3049 case SCH_FIELD_T: // SCH_FIELD objects are not unit/body-style-specific.
3050 {
3051 const SCH_FIELD* field = static_cast<const SCH_FIELD*>( aItem );
3052
3053 if( !field->IsVisible() && !( symEditFrame && symEditFrame->GetShowInvisibleFields() ) )
3054 return false;
3055
3056 break;
3057 }
3058
3059 case SCH_SHAPE_T:
3060 case SCH_TEXT_T:
3061 case SCH_TEXTBOX_T:
3062 if( symEditFrame )
3063 {
3064 const SCH_ITEM* sch_item = static_cast<const SCH_ITEM*>( aItem );
3065
3066 if( sch_item->GetUnit() && sch_item->GetUnit() != symEditFrame->GetUnit() )
3067 return false;
3068
3069 if( sch_item->GetBodyStyle() && sch_item->GetBodyStyle() != symEditFrame->GetBodyStyle() )
3070 return false;
3071 }
3072
3073 break;
3074
3075 case SCH_MARKER_T: // Always selectable
3076 return true;
3077
3078 case SCH_TABLECELL_T:
3079 {
3080 const SCH_TABLECELL* cell = static_cast<const SCH_TABLECELL*>( aItem );
3081
3082 if( cell->GetColSpan() == 0 || cell->GetRowSpan() == 0 )
3083 return false;
3084
3085 break;
3086 }
3087
3088 case NOT_USED: // Things like CONSTRUCTION_GEOM that aren't part of the model
3089 return false;
3090
3091 default: // Suppress warnings
3092 break;
3093 }
3094
3095 return true;
3096}
3097
3098
3100{
3101 if( m_selection.Empty() )
3102 return;
3103
3104 while( m_selection.GetSize() )
3106
3107 getView()->Update( &m_selection );
3108
3109 m_selection.SetIsHover( false );
3111
3112 // Inform other potentially interested tools
3113 if( !aQuietMode )
3115}
3116
3117
3119{
3120 // Don't group when we select new items, the schematic editor selects all new items for moving.
3121 // The PCB editor doesn't need this logic because it doesn't select new items for moving.
3122 if( m_enteredGroup && !aItem->IsNew()
3123 && !SCH_GROUP::WithinScope( static_cast<SCH_ITEM*>( aItem ), m_enteredGroup, m_isSymbolEditor ) )
3124 {
3125 ExitGroup();
3126 }
3127
3128 highlight( aItem, SELECTED, &m_selection );
3129}
3130
3131
3133{
3134 unhighlight( aItem, SELECTED, &m_selection );
3135}
3136
3137
3138void SCH_SELECTION_TOOL::highlight( EDA_ITEM* aItem, int aMode, SELECTION* aGroup )
3139{
3140 if( aMode == SELECTED )
3141 aItem->SetSelected();
3142 else if( aMode == BRIGHTENED )
3143 aItem->SetBrightened();
3144
3145 if( aGroup )
3146 aGroup->Add( aItem );
3147
3148 // Highlight pins and fields. (All the other symbol children are currently only
3149 // represented in the LIB_SYMBOL and will inherit the settings of the parent symbol.)
3150 if( SCH_ITEM* sch_item = dynamic_cast<SCH_ITEM*>( aItem ) )
3151 {
3152 // We don't want to select group children if the group itself is selected,
3153 // we can only select them when the group is entered
3154 if( sch_item->Type() != SCH_GROUP_T )
3155 {
3156 sch_item->RunOnChildren(
3157 [&]( SCH_ITEM* aChild )
3158 {
3159 if( aMode == SELECTED )
3160 {
3161 aChild->SetSelected();
3162 getView()->Hide( aChild, true );
3163 }
3164 else if( aMode == BRIGHTENED )
3165 {
3166 aChild->SetBrightened();
3167 }
3168 },
3169 RECURSE_MODE::NO_RECURSE );
3170 }
3171 }
3172
3173 if( aGroup && aMode != BRIGHTENED )
3174 getView()->Hide( aItem, true );
3175
3176 if( aItem->GetParent() && aItem->GetParent()->Type() != SCHEMATIC_T )
3177 getView()->Update( aItem->GetParent(), KIGFX::REPAINT );
3178
3179 getView()->Update( aItem, KIGFX::REPAINT );
3180}
3181
3182
3183void SCH_SELECTION_TOOL::unhighlight( EDA_ITEM* aItem, int aMode, SELECTION* aGroup )
3184{
3185 if( aMode == SELECTED )
3186 {
3187 aItem->ClearSelected();
3188 // Lines need endpoints cleared here
3189 if( aItem->Type() == SCH_LINE_T )
3190 aItem->ClearFlags( STARTPOINT | ENDPOINT );
3191
3192 if( aMode != BRIGHTENED )
3193 getView()->Hide( aItem, false );
3194 }
3195 else if( aMode == BRIGHTENED )
3196 {
3197 aItem->ClearBrightened();
3198 }
3199
3200 if( aGroup )
3201 aGroup->Remove( aItem );
3202
3203 // Unhighlight pins and fields. (All the other symbol children are currently only
3204 // represented in the LIB_SYMBOL.)
3205 if( SCH_ITEM* sch_item = dynamic_cast<SCH_ITEM*>( aItem ) )
3206 {
3207 sch_item->RunOnChildren(
3208 [&]( SCH_ITEM* aChild )
3209 {
3210 if( aMode == SELECTED )
3211 {
3212 aChild->ClearSelected();
3213 getView()->Hide( aChild, false );
3214 }
3215 else if( aMode == BRIGHTENED )
3216 {
3217 aChild->ClearBrightened();
3218 }
3219
3220 if( aGroup )
3221 aGroup->Remove( aChild );
3222 },
3223 RECURSE_MODE::NO_RECURSE );
3224 }
3225
3226 if( aItem->GetParent() && aItem->GetParent()->Type() != SCHEMATIC_T )
3227 getView()->Update( aItem->GetParent(), KIGFX::REPAINT );
3228
3229 getView()->Update( aItem, KIGFX::REPAINT );
3230}
3231
3232
3234{
3235 const unsigned GRIP_MARGIN = 20;
3236 int margin = KiROUND( getView()->ToWorld( GRIP_MARGIN ) );
3237
3238 // Check if the point is located within any of the currently selected items bounding boxes
3239 for( EDA_ITEM* item : m_selection )
3240 {
3241 BOX2I itemBox = item->ViewBBox();
3242 itemBox.Inflate( margin ); // Give some margin for gripping an item
3243
3244 if( itemBox.Contains( aPoint ) )
3245 return true;
3246 }
3247
3248 return false;
3249}
3250
3251
3253{
3254 SCH_EDIT_FRAME* editFrame = dynamic_cast<SCH_EDIT_FRAME*>( m_frame );
3255
3256 if( !editFrame || !editFrame->GetNetNavigator() || m_selection.Size() == 0 )
3257 return 0;
3258
3259 if( !m_selection.Front()->IsBrightened() )
3260 return 0;
3261
3262 const SCH_ITEM* item = editFrame->SelectNextPrevNetNavigatorItem( true );
3263
3264 if( item )
3265 {
3267 select( const_cast<SCH_ITEM*>( item ) );
3269 }
3270
3271 return 0;
3272}
3273
3274
3276{
3277 SCH_EDIT_FRAME* editFrame = dynamic_cast<SCH_EDIT_FRAME*>( m_frame );
3278
3279 if( !editFrame || !editFrame->GetNetNavigator() || m_selection.Size() == 0 )
3280 return 0;
3281
3282 if( !m_selection.Front()->IsBrightened() )
3283 return 0;
3284
3285 const SCH_ITEM* item = editFrame->SelectNextPrevNetNavigatorItem( false );
3286
3287 if( item )
3288 {
3290 select( const_cast<SCH_ITEM*>( item ) );
3292 }
3293
3294 return 0;
3295}
3296
3297
3299{
3301
3308
3310
3316
3319
3322
3325
3327}
constexpr EDA_IU_SCALE schIUScale
Definition: base_units.h:114
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:224
static TOOL_ACTION cursorLeft
Definition: actions.h:169
static TOOL_ACTION zoomOutCenter
Definition: actions.h:135
static TOOL_ACTION unselectItem
Definition: actions.h:225
static TOOL_ACTION zoomIn
Definition: actions.h:132
static TOOL_ACTION cursorLeftFast
Definition: actions.h:174
static TOOL_ACTION groupEnter
Definition: actions.h:240
static TOOL_ACTION selectColumns
Definition: actions.h:102
static TOOL_ACTION cursorDown
Definition: actions.h:168
static TOOL_ACTION zoomOut
Definition: actions.h:133
static TOOL_ACTION cursorRightFast
Definition: actions.h:175
static TOOL_ACTION zoomCenter
Definition: actions.h:140
static TOOL_ACTION panDown
Definition: actions.h:182
static TOOL_ACTION selectionActivate
Activation of the selection tool.
Definition: actions.h:211
static TOOL_ACTION cursorDownFast
Definition: actions.h:173
static TOOL_ACTION selectionMenu
Run a selection menu to select from a list of items.
Definition: actions.h:233
static TOOL_ACTION selectRows
Definition: actions.h:101
static TOOL_ACTION cursorUpFast
Definition: actions.h:172
static TOOL_ACTION panLeft
Definition: actions.h:183
static TOOL_ACTION updateMenu
Definition: actions.h:267
static TOOL_ACTION zoomFitScreen
Definition: actions.h:141
static TOOL_ACTION increment
Definition: actions.h:94
static TOOL_ACTION selectionClear
Clear the current selection.
Definition: actions.h:221
static TOOL_ACTION panUp
Definition: actions.h:181
static TOOL_ACTION zoomFitObjects
Definition: actions.h:142
static TOOL_ACTION zoomInCenter
Definition: actions.h:134
static TOOL_ACTION panRight
Definition: actions.h:184
static TOOL_ACTION selectTable
Definition: actions.h:103
static TOOL_ACTION cursorUp
Cursor control with keyboard.
Definition: actions.h:167
static TOOL_ACTION groupLeave
Definition: actions.h:241
static TOOL_ACTION finishInteractive
Definition: actions.h:73
static TOOL_ACTION cursorRight
Definition: actions.h:170
static TOOL_ACTION selectAll
Definition: actions.h:82
static TOOL_ACTION unselectItems
Definition: actions.h:230
static TOOL_ACTION selectItems
Select a list of items (specified as the event parameter)
Definition: actions.h:229
static const ADVANCED_CFG & GetCfg()
Get the singleton instance's config, which is shared by all consumers.
CROSS_PROBING_SETTINGS m_CrossProbing
Definition: app_settings.h:213
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:85
bool Empty() const
Definition: commit.h:152
COMMIT & Add(EDA_ITEM *aItem, BASE_SCREEN *aScreen=nullptr)
Add a new item to the model.
Definition: commit.h:79
bool IsHorizontal() const
Definition: eda_angle.h:142
bool IsType(FRAME_T aType) const
void AddStandardSubMenus(TOOL_MENU &aMenu)
Construct a "basic" menu for a tool, containing only items that apply to all tools (e....
virtual EDA_ITEM * ResolveItem(const KIID &aId, bool aAllowNullptrReturn=false) const
Fetch an item by KIID.
void FocusOnLocation(const VECTOR2I &aPos)
Useful to focus on a particular location, in find functions.
void ForceRefresh()
Force a redraw.
void SetCurrentCursor(KICURSOR aCursor)
Set the current cursor shape for this panel.
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:98
virtual const BOX2I GetBoundingBox() const
Return the orthogonal bounding box of this object for display purposes.
Definition: eda_item.cpp:110
void SetFlags(EDA_ITEM_FLAGS aMask)
Definition: eda_item.h:142
KICAD_T Type() const
Returns the type of object.
Definition: eda_item.h:110
void ClearSelected()
Definition: eda_item.h:137
void ClearFlags(EDA_ITEM_FLAGS aMask=EDA_ITEM_ALL_FLAGS)
Definition: eda_item.h:144
void SetIsRollover(bool aIsRollover)
Definition: eda_item.h:132
bool IsSelected() const
Definition: eda_item.h:127
void SetSelected()
Definition: eda_item.h:134
virtual bool IsType(const std::vector< KICAD_T > &aScanTypes) const
Check whether the item is one of the listed types.
Definition: eda_item.h:192
void ClearBrightened()
Definition: eda_item.h:138
void SetBrightened()
Definition: eda_item.h:135
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:233
EDA_ITEM * GetParent() const
Definition: eda_item.h:112
bool IsRollover() const
Definition: eda_item.h:131
bool HasFlag(EDA_ITEM_FLAGS aFlag) const
Definition: eda_item.h:146
bool IsBrightened() const
Definition: eda_item.h:129
void XorFlags(EDA_ITEM_FLAGS aMask)
Definition: eda_item.h:143
EDA_ITEM_FLAGS GetFlags() const
Definition: eda_item.h:145
bool IsNew() const
Definition: eda_item.h:124
virtual std::vector< SHAPE * > MakeEffectiveShapes(bool aEdgeOnly=false) const
Make a set of SHAPE objects representing the EDA_SHAPE.
Definition: eda_shape.h:379
SHAPE_T GetShape() const
Definition: eda_shape.h:168
virtual bool IsFilledForHitTesting() const
Definition: eda_shape.h:131
A mix-in class (via multiple inheritance) that handles texts such as labels, parts,...
Definition: eda_text.h:79
const EDA_ANGLE & GetTextAngle() const
Definition: eda_text.h:144
virtual bool IsVisible() const
Definition: eda_text.h:184
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.
Definition: eda_text.cpp:1108
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 OfType(KICAD_T aType) const
Definition: sch_rtree.h:241
static const TOOL_EVENT DisambiguatePoint
Used for hotkey feedback.
Definition: actions.h:359
static const TOOL_EVENT ClearedEvent
Definition: actions.h:344
static const TOOL_EVENT SelectedEvent
Definition: actions.h:342
static const TOOL_EVENT SelectedItemsModified
Selected items were moved, this can be very high frequency on the canvas, use with care.
Definition: actions.h:349
static const TOOL_EVENT PointSelectedEvent
Definition: actions.h:341
static const TOOL_EVENT SelectedItemsMoved
Used to inform tools that the selection should temporarily be non-editable.
Definition: actions.h:352
static const TOOL_EVENT UnselectedEvent
Definition: actions.h:343
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)
void SetAdditive(bool aAdditive)
void SetOrigin(const VECTOR2I &aOrigin)
const BOX2I ViewBBox() const override
Set the origin of the rectangle (the fixed corner)
void SetExclusiveOr(bool aExclusiveOr)
void SetEnd(const VECTOR2I &aEnd)
Set the current end of the rectangle (the corner that moves with the cursor.
void SetHighlight(bool aEnabled, int aNetcode=-1, bool aMulti=false)
Turns on/off highlighting.
void Update(const KIGFX::VIEW_ITEM *aItem, int aUpdateFlags) const override
For dynamic VIEWs, inform the associated VIEW that the graphical representation of this item has chan...
Definition: sch_view.cpp:60
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 SetAutoPan(bool aEnabled)
Turn on/off auto panning (this feature is used when there is a tool active (eg.
virtual void Clear()
Remove all the stored items from the group.
Definition: view_group.cpp:77
virtual void Add(VIEW_ITEM *aItem)
Add an item to the group.
Definition: view_group.cpp:65
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:66
BOX2D GetViewport() const
Return the current viewport visible area rectangle.
Definition: view.cpp:530
virtual void SetScale(double aScale, VECTOR2D aAnchor={ 0, 0 })
Set the scaling factor, zooming around a given anchor point.
Definition: view.cpp:570
virtual void Add(VIEW_ITEM *aItem, int aDrawPriority=-1)
Add a VIEW_ITEM to the view.
Definition: view.cpp:298
virtual void Remove(VIEW_ITEM *aItem)
Remove a VIEW_ITEM from the view.
Definition: view.cpp:341
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:420
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:1685
bool IsMirroredX() const
Return true if view is flipped across the X axis.
Definition: view.h:250
std::pair< VIEW_ITEM *, int > LAYER_ITEM_PAIR
Definition: view.h:70
void Hide(VIEW_ITEM *aItem, bool aHide=true, bool aHideOverlay=false)
Temporarily hide the item in the view (e.g.
Definition: view.cpp:1633
PAINTER * GetPainter() const
Return the painter object used by the view for drawing #VIEW_ITEMS.
Definition: view.h:220
void SetVisible(VIEW_ITEM *aItem, bool aIsVisible=true)
Set the item visibility.
Definition: view.cpp:1612
Definition: kiid.h:49
Define a library symbol object.
Definition: lib_symbol.h:85
bool IsMulti() const override
Definition: lib_symbol.h:589
LIB_ITEMS_CONTAINER & GetDrawItems()
Return a reference to the draw item list.
Definition: lib_symbol.h:519
Tree view item data for the net navigator.
CONNECTION_GRAPH * ConnectionGraph() const
Definition: schematic.h:183
SCH_SHEET & Root() const
Definition: schematic.h:140
SCH_SHEET_PATH & CurrentSheet() const
Definition: schematic.h:171
static TOOL_ACTION placeClassLabel
Definition: sch_actions.h:79
static TOOL_ACTION placeSheetPin
Definition: sch_actions.h:85
static TOOL_ACTION saveToLinkedDesignBlock
Definition: sch_actions.h:71
static TOOL_ACTION clearHighlight
Definition: sch_actions.h:297
static TOOL_ACTION placeGlobalLabel
Definition: sch_actions.h:80
static TOOL_ACTION pinTable
Definition: sch_actions.h:152
static TOOL_ACTION navigateBack
Definition: sch_actions.h:222
static TOOL_ACTION properties
Definition: sch_actions.h:125
static TOOL_ACTION leaveSheet
Definition: sch_actions.h:219
static TOOL_ACTION breakWire
Definition: sch_actions.h:140
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
Definition: sch_actions.h:168
static TOOL_ACTION drawWire
Definition: sch_actions.h:72
static TOOL_ACTION drag
Definition: sch_actions.h:118
static TOOL_ACTION placeJunction
Definition: sch_actions.h:76
static TOOL_ACTION previousNetItem
Definition: sch_actions.h:169
static TOOL_ACTION navigateForward
Definition: sch_actions.h:221
static TOOL_ACTION setUnitDisplayName
Definition: sch_actions.h:214
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
Definition: sch_actions.h:151
static TOOL_ACTION slice
Definition: sch_actions.h:141
static TOOL_ACTION changeSheet
Definition: sch_actions.h:217
static TOOL_ACTION assignNetclass
Definition: sch_actions.h:158
static TOOL_ACTION enterSheet
Definition: sch_actions.h:218
static TOOL_ACTION editPageNumber
Definition: sch_actions.h:160
static TOOL_ACTION selectOnPCB
Definition: sch_actions.h:247
static TOOL_ACTION move
Definition: sch_actions.h:117
static TOOL_ACTION syncSheetPins
Definition: sch_actions.h:89
SCH_RENDER_SETTINGS * GetRenderSettings()
SCH_SCREEN * GetScreen() const override
Return a pointer to a BASE_SCREEN or one of its derivatives.
SCH_DRAW_PANEL * GetCanvas() const override
Return a pointer to GAL-based canvas of given EDA draw frame.
EESCHEMA_SETTINGS * eeconfig() const
virtual bool GetShowAllPins() const
Allow some frames to show/hide hidden pins.
void AddToScreen(EDA_ITEM *aItem, SCH_SCREEN *aScreen=nullptr) override
Add an item to the screen (and view) aScreen is the screen the item is located on,...
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 aConvert=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.
Definition: sch_commit.cpp:489
virtual void Revert() override
Revert the commit by restoring the modified items state.
Definition: sch_commit.cpp:567
static SELECTION_CONDITION SingleMultiFunctionPin
static SELECTION_CONDITION SingleSymbol
static SELECTION_CONDITION MultipleSymbolsOrPower
static SELECTION_CONDITION AllPinsOrSheetPins
static SELECTION_CONDITION SingleDeMorganSymbol
static SELECTION_CONDITION SingleSymbolOrPower
static SELECTION_CONDITION SingleNonExcludedMarker
static SELECTION_CONDITION SingleMultiUnitSymbol
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
KIGFX::SCH_VIEW * GetView() const override
Return a pointer to the #VIEW instance used in the panel.
Handle actions specific to the schematic editor.
Schematic editor (Eeschema) main window.
SCH_SCREEN * GetScreen() const override
Return a pointer to a BASE_SCREEN or one of its derivatives.
SCH_SHEET_PATH & GetCurrentSheet() const
SCHEMATIC & Schematic() const
wxTreeCtrl * GetNetNavigator()
void FlipBodyStyle(SCH_SYMBOL *aSymbol)
Definition: picksymbol.cpp:188
const SCH_ITEM * SelectNextPrevNetNavigatorItem(bool aNext)
const wxString & GetHighlightedConnection() const
void FocusOnItem(EDA_ITEM *aItem) override
Focus on a particular canvas item.
const BOX2I GetBoundingBox() const override
Return the orthogonal bounding box of this object for display purposes.
Definition: sch_field.cpp:489
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)
Definition: sch_group.cpp:103
void RunOnChildren(const std::function< void(SCH_ITEM *)> &aFunction, RECURSE_MODE aMode) override
Definition: sch_group.cpp:346
static EDA_GROUP * TopLevelGroup(SCH_ITEM *aItem, EDA_GROUP *aScope, bool isSymbolEditor)
Definition: sch_group.cpp:97
const BOX2I GetBoundingBox() const override
Return the orthogonal bounding box of this object for display purposes.
Definition: sch_group.cpp:198
Base class for any item which can be embedded within the SCHEMATIC container class,...
Definition: sch_item.h:168
const SYMBOL * GetParentSymbol() const
Definition: sch_item.cpp:252
SCHEMATIC * Schematic() const
Search the item hierarchy to find a SCHEMATIC.
Definition: sch_item.cpp:246
int GetBodyStyle() const
Definition: sch_item.h:248
virtual bool IsPointClickableAnchor(const VECTOR2I &aPos) const
Definition: sch_item.h:504
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
Definition: sch_label.cpp:891
void SetShape(LABEL_FLAG_SHAPE aShape)
Definition: sch_label.h:177
LABEL_SHAPE GetLabelShape() const
Definition: sch_label.h:180
virtual void SetSpinStyle(SPIN_STYLE aSpinStyle)
Definition: sch_label.cpp:316
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:785
bool IsStartDangling() const
Definition: sch_line.h:294
VECTOR2I GetEndPoint() const
Definition: sch_line.h:144
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:150
bool IsEndDangling() const
Definition: sch_line.h:295
bool IsBus() const
Return true if the line is a bus.
Definition: sch_line.cpp:955
bool IsConnectable() const override
Definition: sch_line.cpp:633
bool IsGraphicLine() const
Return if the line is a graphic (non electrical line)
Definition: sch_line.cpp:943
void SetEndPoint(const VECTOR2I &aPosition)
Definition: sch_line.h:145
bool IsVisible() const
Definition: sch_pin.cpp:343
Tool that displays edit points allowing to modify items by dragging the points.
bool HasPoint()
Indicate the cursor is over an edit point.
void ClearDrawingState()
Clear the state flags of all the items in the screen.
Definition: sch_screen.cpp:998
EE_RTREE & Items()
Get the full RTree, usually for iterating.
Definition: sch_screen.h:117
std::set< SCH_ITEM * > MarkConnections(SCH_LINE *aSegment, bool aSecondPass)
Return all wires and junctions connected to aSegment which are not connected any symbol pin or all gr...
Definition: sch_screen.cpp:415
bool CheckIfOnDrawList(const SCH_ITEM *aItem) const
Definition: sch_screen.cpp:393
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)
SCH_SELECTION m_selection
int SelectAll(const TOOL_EVENT &aEvent)
Unselect all visible items in sheet.
KIGFX::VIEW_GROUP m_enteredGroupOverlay
EDA_ITEM * GetNode(const VECTOR2I &aPosition)
Finds a connected item at a point (usually the cursor position).
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 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 narrowSelection(SCH_COLLECTOR &collector, const VECTOR2I &aWhere, bool aCheckLocked, bool aSelectedOnly=false)
Apply rules to narrow the collection down to selectable objects, and then heuristics to try and narro...
void 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()
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.
bool Selectable(const EDA_ITEM *aItem, const VECTOR2I *aPos=nullptr, bool checkVisibilityOnly=false) const
Check conditions for an item to be selected.
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.
int SelectColumns(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
bool itemPassesFilter(EDA_ITEM *aItem)
Return true if the given item passes the stateful selection filter.
EDA_ITEM * GetTopLeftItem(bool onlyModules=false) const override
BOX2I GetBoundingBox() const override
VECTOR2I GetCenter() const
Definition: sch_shape.h:87
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.
Definition: sch_sheet_pin.h:66
SHEET_SIDE GetSide() const
Sheet symbol placed in a schematic, and is the entry point for a sub schematic.
Definition: sch_sheet.h:47
std::vector< SCH_SHEET_PIN * > & GetPins()
Definition: sch_sheet.h:187
Schematic symbol object.
Definition: sch_symbol.h:75
std::vector< SCH_PIN * > GetPins(const SCH_SHEET_PATH *aSheet) const
Retrieve a list of the SCH_PINs for the given sheet path.
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:183
BOX2I GetBodyBoundingBox() const override
Return a bounding box for the symbol body but not the pins or fields.
int GetColSpan() const
Definition: sch_tablecell.h:64
int GetRowSpan() const
Definition: sch_tablecell.h:67
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:675
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.
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
virtual KIGFX::VIEW_ITEM * GetItem(unsigned int aIdx) const override
Definition: selection.cpp:75
const std::deque< EDA_ITEM * > GetItems() const
Definition: selection.h:126
void SetIsHover(bool aIsHover)
Definition: selection.h:84
virtual void Remove(EDA_ITEM *aItem)
Definition: selection.cpp:60
virtual unsigned int GetSize() const override
Return the number of stored items.
Definition: selection.h:105
EDA_ITEM * Front() const
Definition: selection.h:177
virtual void Clear() override
Remove all the stored items from the group.
Definition: selection.h:98
int Size() const
Returns the number of selected parts.
Definition: selection.h:121
void ClearReferencePoint()
Definition: selection.cpp:184
void SetReferencePoint(const VECTOR2I &aP)
Definition: selection.cpp:178
bool Empty() const
Checks if there is anything selected.
Definition: selection.h:115
bool 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:142
An abstract shape on 2D plane.
Definition: shape.h:126
The symbol library editor main window.
bool IsSymbolAlias() const
Return true if aLibId is an alias for the editor screen symbol.
int GetBodyStyle() const
bool IsSymbolEditable() const
Test if a symbol is loaded and can be edited.
LIB_SYMBOL * GetCurSymbol() const
Return the current symbol being edited or NULL if none selected.
Symbol library viewer main window.
A base class for LIB_SYMBOL and SCH_SYMBOL.
Definition: symbol.h:63
MOUSE_DRAG_ACTION GetDragAction() const
Indicates whether a drag should draw a selection rectangle or drag selected (or unselected) objects.
Definition: tools_holder.h:144
bool ToolStackIsEmpty()
Definition: tools_holder.h:125
TOOL_MANAGER * GetToolManager() const
Return the MVC controller.
Definition: tools_holder.h:55
Represent a single user action.
Definition: tool_action.h:304
TOOL_EVENT MakeEvent() const
Return the event associated with the action (i.e.
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:168
const VECTOR2D Position() const
Return mouse cursor position in world coordinates.
Definition: tool_event.h:290
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.
bool ProcessEvent(const TOOL_EVENT &aEvent)
Propagate an event to tools that requested events of matching type(s).
bool RunAction(const std::string &aActionName, T aParam)
Run the specified action immediately, pausing the current action to run the new one.
Definition: tool_manager.h:150
VECTOR2D GetMousePosition() const
bool PostAction(const std::string &aActionName, T aParam)
Run the specified action after the current action (coroutine) ends.
Definition: tool_manager.h:235
bool RunSynchronousAction(const TOOL_ACTION &aAction, COMMIT *aCommit, T aParam)
Run the specified action immediately, pausing the current action to run the new one.
Definition: tool_manager.h:197
double Distance(const VECTOR2< extended_type > &aVector) const
Compute the distance between two vectors.
Definition: vector2d.h:561
MOUSE_DRAG_ACTION
KICURSOR
Definition: cursors.h:44
#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
std::vector< EDA_ITEM * > EDA_ITEMS
Define list of drawing items for screens.
Definition: eda_item.h:566
#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:91
@ ID_POPUP_SCH_PIN_TRICKS_HIER_LABEL
Definition: eeschema_id.h:95
@ ID_POPUP_SCH_PIN_TRICKS_WIRE
Definition: eeschema_id.h:93
@ ID_POPUP_SCH_ALT_PIN_FUNCTION
Definition: eeschema_id.h:99
@ ID_POPUP_SCH_UNFOLD_BUS_END
Definition: eeschema_id.h:79
@ ID_POPUP_SCH_SELECT_UNIT
Definition: eeschema_id.h:82
@ ID_POPUP_SCH_SELECT_BASE
Definition: eeschema_id.h:88
@ ID_POPUP_SCH_SELECT_ALT
Definition: eeschema_id.h:89
@ ID_POPUP_SCH_PIN_TRICKS_NET_LABEL
Definition: eeschema_id.h:94
@ ID_POPUP_SCH_PIN_TRICKS_NO_CONNECT
Definition: eeschema_id.h:92
@ ID_POPUP_SCH_UNFOLD_BUS
Definition: eeschema_id.h:78
@ ID_POPUP_SCH_SELECT_UNIT_END
Definition: eeschema_id.h:86
@ ID_POPUP_SCH_ALT_PIN_FUNCTION_END
Definition: eeschema_id.h:100
@ ID_POPUP_SCH_PIN_TRICKS_GLOBAL_LABEL
Definition: eeschema_id.h:96
@ ID_POPUP_SCH_PIN_TRICKS_END
Definition: eeschema_id.h:97
GRID_HELPER_GRIDS
Definition: grid_helper.h:43
KIID niluuid(0)
@ LAYER_WIRE
Definition: layer_ids.h:442
@ LAYER_BUS
Definition: layer_ids.h:443
@ 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
CITER next(CITER it)
Definition: ptree.cpp:124
#define HITTEST_THRESHOLD_PIXELS
Class to handle a set of SCH_ITEMs.
@ LABEL_BIDI
Definition: sch_label.h:120
@ LABEL_INPUT
Definition: sch_label.h:118
@ LABEL_OUTPUT
Definition: sch_label.h:119
@ LABEL_PASSIVE
Definition: sch_label.h:122
@ LABEL_TRISTATE
Definition: sch_label.h:121
static std::vector< KICAD_T > connectedTypes
static std::vector< KICAD_T > tableCellTypes
static std::vector< KICAD_T > lineTypes
static std::vector< KICAD_T > sheetTypes
const TOOL_ACTION * allowedActions[]
static std::vector< KICAD_T > connectedLineTypes
static std::vector< KICAD_T > crossProbingTypes
std::function< bool(const SELECTION &)> SELECTION_CONDITION
Functor type that checks a specific condition for selected items.
std::vector< FAB_LAYER_COLOR > dummy
bool zoom_to_fit
Zoom to fit items (ignored if center_on_items is off).
Definition: app_settings.h:35
bool center_on_items
Automatically pan to cross-probed items.
Definition: app_settings.h:34
constexpr int MilsToIU(int mils) const
Definition: base_units.h:97
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.
VECTOR2I end
int delta
std::optional< TOOL_EVENT > OPT_TOOL_EVENT
Definition: tool_event.h:633
@ 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
@ TC_COMMAND
Definition: tool_event.h:57
@ MD_ALT
Definition: tool_event.h:145
@ MD_CTRL
Definition: tool_event.h:144
@ MD_SHIFT
Definition: tool_event.h:143
@ 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_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:79
@ 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:695