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