KiCad PCB EDA Suite
Loading...
Searching...
No Matches
ee_selection_tool.cpp
Go to the documentation of this file.
1/*
2 * This program source code file is part of KiCad, a free EDA CAD application.
3 *
4 * Copyright (C) 2019 CERN
5 * Copyright (C) 2019-2024 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 <ee_actions.h>
31#include <ee_collectors.h>
32#include <ee_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_base_frame.h>
41#include <sch_commit.h>
42#include <sch_symbol.h>
43#include <sch_field.h>
44#include <sch_edit_frame.h>
45#include <sch_item.h>
46#include <sch_line.h>
47#include <sch_bus_entry.h>
48#include <sch_marker.h>
49#include <sch_no_connect.h>
50#include <sch_sheet.h>
51#include <sch_sheet_pin.h>
52#include <sch_table.h>
53#include <sch_tablecell.h>
54#include <schematic.h>
55#include <tool/tool_event.h>
56#include <tool/tool_manager.h>
61#include <trigo.h>
62#include <view/view.h>
63#include <view/view_controls.h>
64#include <wx/log.h>
65
66
68{
69 if( aSel.GetSize() == 1 )
70 {
71 SCH_SYMBOL* symbol = dynamic_cast<SCH_SYMBOL*>( aSel.Front() );
72
73 if( symbol )
74 return !symbol->GetLibSymbolRef() || !symbol->GetLibSymbolRef()->IsPower();
75 }
76
77 return false;
78};
79
80
82{
83 return aSel.GetSize() == 1 && aSel.Front()->Type() == SCH_SYMBOL_T;
84};
85
86
88{
89 if( aSel.GetSize() == 1 )
90 {
91 SCH_SYMBOL* symbol = dynamic_cast<SCH_SYMBOL*>( aSel.Front() );
92
93 if( symbol )
94 return symbol->GetLibSymbolRef() && symbol->GetLibSymbolRef()->HasAlternateBodyStyle();
95 }
96
97 return false;
98};
99
100
102{
103 if( aSel.GetSize() == 1 )
104 {
105 SCH_SYMBOL* symbol = dynamic_cast<SCH_SYMBOL*>( aSel.Front() );
106
107 if( symbol )
108 return symbol->GetLibSymbolRef() && symbol->GetLibSymbolRef()->GetUnitCount() >= 2;
109 }
110
111 return false;
112};
113
114
116{
117 if( aSel.GetSize() == 1 )
118 {
119 SCH_PIN* pin = dynamic_cast<SCH_PIN*>( aSel.Front() );
120
121 if( pin && pin->GetLibPin() )
122 return !pin->GetLibPin()->GetAlternates().empty();
123 }
124
125 return false;
126};
127
128
130{
131 if( aSel.CountType( SCH_MARKER_T ) != 1 )
132 return false;
133
134 return !static_cast<SCH_MARKER*>( aSel.Front() )->IsExcluded();
135};
136
137
139{
140 return aSel.GetSize() > 1 && aSel.OnlyContains( { SCH_SYMBOL_T } );
141};
142
143
145{
146 return aSel.GetSize() >= 1 && aSel.OnlyContains( { SCH_PIN_T } );
147};
148
149
150#define HITTEST_THRESHOLD_PIXELS 5
151
152
154 SELECTION_TOOL( "eeschema.InteractiveSelection" ),
155 m_frame( nullptr ),
156 m_nonModifiedCursor( KICURSOR::ARROW ),
157 m_isSymbolEditor( false ),
158 m_isSymbolViewer( false ),
159 m_unit( 0 ),
160 m_bodyStyle( 0 )
161{
164}
165
166
168{
170}
171
172
174
175
176static std::vector<KICAD_T> connectedTypes =
177{
179 SCH_PIN_T,
190};
191
192
194{
195 m_frame = getEditFrame<SCH_BASE_FRAME>();
196
197 SYMBOL_VIEWER_FRAME* symbolViewerFrame = dynamic_cast<SYMBOL_VIEWER_FRAME*>( m_frame );
198 SYMBOL_EDIT_FRAME* symbolEditorFrame = dynamic_cast<SYMBOL_EDIT_FRAME*>( m_frame );
199
200 if( symbolEditorFrame )
201 {
202 m_isSymbolEditor = true;
203 m_unit = symbolEditorFrame->GetUnit();
204 m_bodyStyle = symbolEditorFrame->GetBodyStyle();
205 }
206 else
207 {
208 m_isSymbolViewer = symbolViewerFrame != nullptr;
209 }
210
211 auto linesSelection = E_C::MoreThan( 0 ) &&
214 auto wireOrBusSelection = E_C::Count( 1 ) &&
217 auto connectedSelection = E_C::Count( 1 ) && E_C::OnlyTypes( connectedTypes );
218 auto sheetSelection = E_C::Count( 1 ) && E_C::OnlyTypes( { SCH_SHEET_T } );
219 auto crossProbingSelection = E_C::MoreThan( 0 ) && E_C::HasTypes( { SCH_SYMBOL_T, SCH_PIN_T, SCH_SHEET_T } );
220 auto tableCellSelection = E_C::MoreThan( 0 ) && E_C::OnlyTypes( { SCH_TABLECELL_T } );
221
222 auto schEditSheetPageNumberCondition =
223 [&] ( const SELECTION& aSel )
224 {
226 return false;
227
228 return E_C::LessThan( 2 )( aSel ) && E_C::OnlyTypes( { SCH_SHEET_T } )( aSel );
229 };
230
231 auto schEditCondition =
232 [this] ( const SELECTION& aSel )
233 {
235 };
236
237 auto belowRootSheetCondition =
238 [&]( const SELECTION& aSel )
239 {
240 SCH_EDIT_FRAME* editFrame = dynamic_cast<SCH_EDIT_FRAME*>( m_frame );
241
242 return editFrame
243 && editFrame->GetCurrentSheet().Last() != &editFrame->Schematic().Root();
244 };
245
246 auto haveHighlight =
247 [&]( const SELECTION& sel )
248 {
249 SCH_EDIT_FRAME* editFrame = dynamic_cast<SCH_EDIT_FRAME*>( m_frame );
250
251 return editFrame && !editFrame->GetHighlightedConnection().IsEmpty();
252 };
253
254 auto haveSymbol =
255 [&]( const SELECTION& sel )
256 {
257 return m_isSymbolEditor &&
258 static_cast<SYMBOL_EDIT_FRAME*>( m_frame )->GetCurSymbol();
259 };
260
261 auto symbolDisplayNameIsEditable =
262 [&]( const SELECTION& sel )
263 {
264 if ( !m_isSymbolEditor )
265 return false;
266
267 SYMBOL_EDIT_FRAME* symbEditorFrame = dynamic_cast<SYMBOL_EDIT_FRAME*>( m_frame );
268
269 return symbEditorFrame
270 && symbEditorFrame->GetCurSymbol()
271 && symbEditorFrame->GetCurSymbol()->IsMulti()
272 && symbEditorFrame->IsSymbolEditable()
273 && !symbEditorFrame->IsSymbolAlias();
274 };
275
276 auto& menu = m_menu.GetMenu();
277
278 menu.AddItem( EE_ACTIONS::clearHighlight, haveHighlight && EE_CONDITIONS::Idle, 1 );
279 menu.AddSeparator( haveHighlight && EE_CONDITIONS::Idle, 1 );
280
281 menu.AddItem( ACTIONS::selectColumns, tableCellSelection && EE_CONDITIONS::Idle, 2 );
282 menu.AddItem( ACTIONS::selectRows, tableCellSelection && EE_CONDITIONS::Idle, 2 );
283 menu.AddItem( ACTIONS::selectTable, tableCellSelection && EE_CONDITIONS::Idle, 2 );
284
285 menu.AddSeparator( 100 );
286 menu.AddItem( EE_ACTIONS::drawWire, schEditCondition && EE_CONDITIONS::Empty, 100 );
287 menu.AddItem( EE_ACTIONS::drawBus, schEditCondition && EE_CONDITIONS::Empty, 100 );
288
289 menu.AddSeparator( 100 );
290 menu.AddItem( ACTIONS::finishInteractive,
292
293 menu.AddItem( EE_ACTIONS::enterSheet, sheetSelection && EE_CONDITIONS::Idle, 150 );
294 menu.AddItem( EE_ACTIONS::selectOnPCB,
295 crossProbingSelection && EE_CONDITIONS::Idle, 150 );
296 menu.AddItem( EE_ACTIONS::leaveSheet, belowRootSheetCondition, 150 );
297
298 menu.AddSeparator( 200 );
299 menu.AddItem( EE_ACTIONS::placeJunction, wireOrBusSelection && EE_CONDITIONS::Idle, 250 );
300 menu.AddItem( EE_ACTIONS::placeLabel, wireOrBusSelection && EE_CONDITIONS::Idle, 250 );
301 menu.AddItem( EE_ACTIONS::placeClassLabel, wireOrBusSelection && EE_CONDITIONS::Idle, 250 );
302 menu.AddItem( EE_ACTIONS::placeGlobalLabel, wireOrBusSelection && EE_CONDITIONS::Idle, 250 );
303 menu.AddItem( EE_ACTIONS::placeHierLabel, wireOrBusSelection && EE_CONDITIONS::Idle, 250 );
304 menu.AddItem( EE_ACTIONS::breakWire, linesSelection && EE_CONDITIONS::Idle, 250 );
305 menu.AddItem( EE_ACTIONS::slice, linesSelection && EE_CONDITIONS::Idle, 250 );
306 menu.AddItem( EE_ACTIONS::placeSheetPin, sheetSelection && EE_CONDITIONS::Idle, 250 );
307 menu.AddItem( EE_ACTIONS::syncSheetPins, sheetSelection && EE_CONDITIONS::Idle, 250 );
308 menu.AddItem( EE_ACTIONS::assignNetclass, connectedSelection && EE_CONDITIONS::Idle, 250 );
309 menu.AddItem( EE_ACTIONS::editPageNumber, schEditSheetPageNumberCondition, 250 );
310
311 menu.AddSeparator( 400 );
312 menu.AddItem( EE_ACTIONS::symbolProperties, haveSymbol && EE_CONDITIONS::Empty, 400 );
313 menu.AddItem( EE_ACTIONS::pinTable, haveSymbol && EE_CONDITIONS::Empty, 400 );
314 menu.AddItem( EE_ACTIONS::setUnitDisplayName,
315 haveSymbol && symbolDisplayNameIsEditable && EE_CONDITIONS::Empty, 400 );
316
317 menu.AddSeparator( 1000 );
319
320 m_disambiguateTimer.SetOwner( this );
321 Connect( wxEVT_TIMER, wxTimerEventHandler( EE_SELECTION_TOOL::onDisambiguationExpire ),
322 nullptr, this );
323
324 return true;
325}
326
327
329{
330 m_frame = getEditFrame<SCH_BASE_FRAME>();
331
332 if( aReason != TOOL_BASE::REDRAW )
333 {
334 // Remove pointers to the selected items from containers without changing their
335 // properties (as they are already deleted while a new sheet is loaded)
337 }
338
339 if( aReason == TOOL_BASE::MODEL_RELOAD || aReason == TOOL_BASE::SUPERMODEL_RELOAD )
340 {
341 getView()->GetPainter()->GetSettings()->SetHighlight( false );
342
343 SYMBOL_EDIT_FRAME* symbolEditFrame = dynamic_cast<SYMBOL_EDIT_FRAME*>( m_frame );
344 SYMBOL_VIEWER_FRAME* symbolViewerFrame = dynamic_cast<SYMBOL_VIEWER_FRAME*>( m_frame );
345
346 if( symbolEditFrame )
347 {
348 m_isSymbolEditor = true;
349 m_unit = symbolEditFrame->GetUnit();
350 m_bodyStyle = symbolEditFrame->GetBodyStyle();
351 }
352 else
353 {
354 m_isSymbolViewer = symbolViewerFrame != nullptr;
355 }
356 }
357
358 // Reinsert the VIEW_GROUP, in case it was removed from the VIEW
360 getView()->Add( &m_selection );
361}
362
363
365{
366 m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::ARROW );
367
368 KIID lastRolloverItem = niluuid;
370
371 // Main loop: keep receiving events
372 while( TOOL_EVENT* evt = Wait() )
373 {
374 bool selCancelled = false;
375 bool displayWireCursor = false;
376 bool displayBusCursor = false;
377 bool displayLineCursor = false;
378 KIID rolloverItem = lastRolloverItem;
379
380 // on left click, a selection is made, depending on modifiers ALT, SHIFT, CTRL:
381 setModifiersState( evt->Modifier( MD_SHIFT ), evt->Modifier( MD_CTRL ),
382 evt->Modifier( MD_ALT ) );
383
384 MOUSE_DRAG_ACTION drag_action = m_frame->GetDragAction();
385
386 if( evt->IsMouseDown( BUT_LEFT ) )
387 {
388 if( !m_frame->ToolStackIsEmpty() )
389 {
390 // Avoid triggering when running under other tools
391 }
394 {
395 // Distinguish point editor from selection modification by checking modifiers
396 if( hasModifier() )
397 {
399 m_disambiguateTimer.StartOnce( ADVANCED_CFG::GetCfg().m_DisambiguationMenuDelay );
400 }
401 }
402 else
403 {
405 m_disambiguateTimer.StartOnce( ADVANCED_CFG::GetCfg().m_DisambiguationMenuDelay );
406 }
407 }
408 // Single click? Select single object
409 else if( evt->IsClick( BUT_LEFT ) )
410 {
411 // If the timer has stopped, then we have already run the disambiguate routine
412 // and we don't want to register an extra click here
413 if( !m_disambiguateTimer.IsRunning() )
414 {
415 evt->SetPassEvent();
416 continue;
417 }
418
419 m_disambiguateTimer.Stop();
420
421 if( SCH_EDIT_FRAME* schframe = dynamic_cast<SCH_EDIT_FRAME*>( m_frame ) )
422 schframe->FocusOnItem( nullptr );
423
424 // Collect items at the clicked location (doesn't select them yet)
425 EE_COLLECTOR collector;
426 CollectHits( collector, evt->Position() );
427 narrowSelection( collector, evt->Position(), false );
428
429 if( collector.GetCount() == 1 && !m_isSymbolEditor && !hasModifier() )
430 {
431 OPT_TOOL_EVENT autostart = autostartEvent( evt, grid, collector[0] );
432
433 if( autostart )
434 {
436
437 params->layer = autostart->Parameter<const DRAW_SEGMENT_EVENT_PARAMS*>()->layer;
438 params->quitOnDraw = true;
439 params->sourceSegment = dynamic_cast<SCH_LINE*>( collector[0] );
440
441 autostart->SetParameter<const DRAW_SEGMENT_EVENT_PARAMS*>( params );
442 m_toolMgr->ProcessEvent( *autostart );
443
444 selCancelled = true;
445 }
446 else if( collector[0]->IsHypertext() )
447 {
448 collector[ 0 ]->DoHypertextAction( m_frame );
449 selCancelled = true;
450 }
451 else if( collector[0]->IsBrightened() )
452 {
453 if( SCH_EDIT_FRAME* schframe = dynamic_cast<SCH_EDIT_FRAME*>( m_frame ) )
454 {
455 NET_NAVIGATOR_ITEM_DATA itemData( schframe->GetCurrentSheet(),
456 collector[0] );
457
458 schframe->SelectNetNavigatorItem( &itemData );
459 }
460 }
461 }
462
463 if( !selCancelled )
464 {
465 selectPoint( collector, evt->Position(), nullptr, nullptr, m_additive,
467 m_selection.SetIsHover( false );
468 }
469 }
470 else if( evt->IsClick( BUT_RIGHT ) )
471 {
472 m_disambiguateTimer.Stop();
473
474 // right click? if there is any object - show the context menu
475 if( m_selection.Empty() )
476 {
478 SelectPoint( evt->Position(), { SCH_LOCATE_ANY_T }, nullptr, &selCancelled );
479 m_selection.SetIsHover( true );
480 }
481 // If the cursor has moved off the bounding box of the selection by more than
482 // a grid square, check to see if there is another item available for selection
483 // under the cursor. If there is, the user likely meant to get the context menu
484 // for that item. If there is no new item, then keep the original selection and
485 // show the context menu for it.
486 else if( !m_selection.GetBoundingBox().Inflate( grid.GetGrid().x, grid.GetGrid().y )
487 .Contains( evt->Position() ) )
488 {
489 EE_COLLECTOR collector;
490
491 if( CollectHits( collector, evt->Position(), { SCH_LOCATE_ANY_T } ) )
492 {
494
495 SelectPoint( evt->Position(), { SCH_LOCATE_ANY_T }, nullptr, &selCancelled );
496 m_selection.SetIsHover( true );
497 }
498 }
499
500 if( !selCancelled )
502 }
503 else if( evt->IsDblClick( BUT_LEFT ) )
504 {
505 m_disambiguateTimer.Stop();
506
507 // double click? Display the properties window
508 if( SCH_EDIT_FRAME* schframe = dynamic_cast<SCH_EDIT_FRAME*>( m_frame ) )
509 schframe->FocusOnItem( nullptr );
510
511 if( m_selection.Empty() )
512 SelectPoint( evt->Position() );
513
514 EDA_ITEM* item = m_selection.Front();
515
516 if( item && item->Type() == SCH_SHEET_T )
518 else
520 }
521 else if( evt->IsDblClick( BUT_MIDDLE ) )
522 {
523 m_disambiguateTimer.Stop();
524
525 // Middle double click? Do zoom to fit or zoom to objects
526 if( evt->Modifier( MD_CTRL ) ) // Is CTRL key down?
528 else
530 }
531 else if( evt->IsDrag( BUT_LEFT ) )
532 {
533 m_disambiguateTimer.Stop();
534
535 // Is another tool already moving a new object? Don't allow a drag start
536 if( !m_selection.Empty() && m_selection[0]->HasFlag( IS_NEW | IS_MOVING ) )
537 {
538 evt->SetPassEvent();
539 continue;
540 }
541
542 // drag with LMB? Select multiple objects (or at least draw a selection box) or
543 // drag them
544 if( SCH_EDIT_FRAME* schframe = dynamic_cast<SCH_EDIT_FRAME*>( m_frame ) )
545 schframe->FocusOnItem( nullptr );
546
547 EE_COLLECTOR collector;
548
549 if( CollectHits( collector, evt->DragOrigin(), { SCH_TABLECELL_T } ) )
550 {
551 selectTableCells( static_cast<SCH_TABLE*>( collector[0]->GetParent() ) );
552 }
553 else if( hasModifier() || drag_action == MOUSE_DRAG_ACTION::SELECT )
554 {
556 }
557 else if( m_selection.Empty() && drag_action != MOUSE_DRAG_ACTION::DRAG_ANY )
558 {
560 }
561 else
562 {
563 if( m_isSymbolEditor )
564 {
565 if( static_cast<SYMBOL_EDIT_FRAME*>( m_frame )->IsSymbolAlias() )
566 {
568 }
569 else
570 {
574 SCH_PIN_T,
575 SCH_FIELD_T } );
576 }
577 }
578 else
579 {
581 }
582
583 // Check if dragging has started within any of selected items bounding box
584 if( selectionContains( evt->DragOrigin() ) )
585 {
586 // drag_is_move option exists only in schematic editor, not in symbol editor
587 // (m_frame->eeconfig() returns nullptr in Symbol Editor)
590 else
592 }
593 else
594 {
595 // No -> drag a selection box
597 }
598 }
599 }
600 else if( evt->IsMouseDown( BUT_AUX1 ) )
601 {
603 }
604 else if( evt->IsMouseDown( BUT_AUX2 ) )
605 {
607 }
608 else if( evt->Category() == TC_COMMAND && evt->Action() == TA_CHOICE_MENU_CHOICE )
609 {
610 m_disambiguateTimer.Stop();
611
612 // context sub-menu selection? Handle unit selection or bus unfolding
613 if( *evt->GetCommandId() >= ID_POPUP_SCH_SELECT_UNIT
614 && *evt->GetCommandId() <= ID_POPUP_SCH_SELECT_UNIT_END )
615 {
616 SCH_SYMBOL* symbol = dynamic_cast<SCH_SYMBOL*>( m_selection.Front() );
617 int unit = *evt->GetCommandId() - ID_POPUP_SCH_SELECT_UNIT;
618
619 if( symbol )
620 static_cast<SCH_EDIT_FRAME*>( m_frame )->SelectUnit( symbol, unit );
621 }
622 else if( *evt->GetCommandId() >= ID_POPUP_SCH_ALT_PIN_FUNCTION
623 && *evt->GetCommandId() <= ID_POPUP_SCH_ALT_PIN_FUNCTION_END )
624 {
625 SCH_PIN* pin = dynamic_cast<SCH_PIN*>( m_selection.Front() );
626 wxString alt = *evt->Parameter<wxString*>();
627
628 if( pin )
629 static_cast<SCH_EDIT_FRAME*>( m_frame )->SetAltPinFunction( pin, alt );
630 }
631 else if( *evt->GetCommandId() >= ID_POPUP_SCH_PIN_TRICKS_START
632 && *evt->GetCommandId() <= ID_POPUP_SCH_PIN_TRICKS_END )
633 {
635 return 0;
636
637 // Keep track of new items so we make them the new selection at the end
638 EDA_ITEMS newItems;
639 SCH_COMMIT commit( static_cast<SCH_EDIT_FRAME*>( m_frame ) );
640
641 if( *evt->GetCommandId() == ID_POPUP_SCH_PIN_TRICKS_NO_CONNECT )
642 {
643 for( EDA_ITEM* item : m_selection )
644 {
645 SCH_PIN* pin = static_cast<SCH_PIN*>( item );
646 SCH_NO_CONNECT* nc = new SCH_NO_CONNECT( pin->GetPosition() );
647 commit.Add( nc, m_frame->GetScreen() );
648 newItems.push_back( nc );
649 }
650
651 commit.Push( wxS( "No Connect Pins" ) );
653 }
654 else if( *evt->GetCommandId() == ID_POPUP_SCH_PIN_TRICKS_WIRE )
655 {
656 VECTOR2I wireGrid = grid.GetGridSize( GRID_HELPER_GRIDS::GRID_WIRES );
657
658 for( EDA_ITEM* item : m_selection )
659 {
660 SCH_PIN* pin = static_cast<SCH_PIN*>( item );
661 SCH_LINE* wire = new SCH_LINE( pin->GetPosition(), LAYER_WIRE );
662
663 // Add some length to the wire as nothing in our code base handles
664 // 0 length wires very well, least of all the ortho drag algorithm
665 VECTOR2I stub;
666
667 switch( pin->GetOrientation() )
668 {
669 default:
670 case PIN_ORIENTATION::PIN_RIGHT:
671 stub = VECTOR2I( -1 * wireGrid.x, 0 );
672 break;
673 case PIN_ORIENTATION::PIN_LEFT:
674 stub = VECTOR2I( 1 * wireGrid.x, 0 );
675 break;
676 case PIN_ORIENTATION::PIN_UP:
677 stub = VECTOR2I( 0, 1 * wireGrid.y );
678 break;
679 case PIN_ORIENTATION::PIN_DOWN:
680 stub = VECTOR2I( 0, -1 * wireGrid.y );
681 break;
682 }
683
684 wire->SetEndPoint( pin->GetPosition() + stub );
685
687 commit.Added( wire, m_frame->GetScreen() );
688 newItems.push_back( wire );
689 }
690
692 AddItemsToSel( &newItems );
693
694 // Select only the ends so we can immediately start dragging them
695 for( EDA_ITEM* item : newItems )
696 static_cast<SCH_LINE*>( item )->SetFlags( ENDPOINT );
697
698 // Put the mouse on the nearest point of the first wire
699 SCH_LINE* first = static_cast<SCH_LINE*>( newItems[0] );
701 getViewControls()->WarpMouseCursor( getViewControls()->GetCursorPosition(),
702 true );
703
704 // Start the drag tool, canceling will remove the wires
705 if( m_toolMgr->RunSynchronousAction( EE_ACTIONS::drag, &commit, false ) )
706 commit.Push( wxS( "Wire Pins" ) );
707 else
708 commit.Revert();
709 }
710 else
711 {
712 // For every pin in the selection, add a label according to menu item
713 // selected by the user
714 for( EDA_ITEM* item : m_selection )
715 {
716 SCH_PIN* pin = static_cast<SCH_PIN*>( item );
717 SCH_LABEL_BASE* label = nullptr;
718
719 switch( *evt->GetCommandId() )
720 {
722 label = new SCH_LABEL( pin->GetPosition(), pin->GetShownName() );
723 break;
725 label = new SCH_HIERLABEL( pin->GetPosition(), pin->GetShownName() );
726 break;
728 label = new SCH_GLOBALLABEL( pin->GetPosition(), pin->GetShownName() );
729 break;
730 default: continue;
731 }
732
733 switch( pin->GetOrientation() )
734 {
735 default:
736 case PIN_ORIENTATION::PIN_RIGHT:
738 break;
739 case PIN_ORIENTATION::PIN_LEFT:
741 break;
742 case PIN_ORIENTATION::PIN_UP:
744 break;
745 case PIN_ORIENTATION::PIN_DOWN:
747 break;
748 }
749
750 switch( pin->GetType() )
751 {
752 case ELECTRICAL_PINTYPE::PT_BIDI:
753 label->SetShape( LABEL_FLAG_SHAPE::L_BIDI );
754 break;
755 case ELECTRICAL_PINTYPE::PT_INPUT:
756 label->SetShape( LABEL_FLAG_SHAPE::L_INPUT );
757 break;
758 case ELECTRICAL_PINTYPE::PT_OUTPUT:
759 label->SetShape( LABEL_FLAG_SHAPE::L_OUTPUT );
760 break;
761 case ELECTRICAL_PINTYPE::PT_TRISTATE:
762 label->SetShape( LABEL_FLAG_SHAPE::L_TRISTATE );
763 break;
764 case ELECTRICAL_PINTYPE::PT_UNSPECIFIED:
765 label->SetShape( LABEL_FLAG_SHAPE::L_UNSPECIFIED );
766 break;
767 default:
768 label->SetShape( LABEL_FLAG_SHAPE::L_INPUT );
769 }
770
771 commit.Add( label, m_frame->GetScreen() );
772 newItems.push_back( label );
773 }
774
775 commit.Push( wxS( "Label Pins" ) );
776
777 // Many users will want to drag these items to wire off of the pins, so
778 // pre-select them.
780 AddItemsToSel( &newItems );
781 }
782 }
783 else if( *evt->GetCommandId() >= ID_POPUP_SCH_UNFOLD_BUS
784 && *evt->GetCommandId() <= ID_POPUP_SCH_UNFOLD_BUS_END )
785 {
786 wxString* net = new wxString( *evt->Parameter<wxString*>() );
787 m_toolMgr->RunAction<wxString*>( EE_ACTIONS::unfoldBus, net );
788 }
789 }
790 else if( evt->IsCancelInteractive() )
791 {
792 m_disambiguateTimer.Stop();
793
794 // We didn't set these, but we have reports that they leak out of some other tools,
795 // so we clear them here.
796 getViewControls()->SetAutoPan( false );
797 getViewControls()->CaptureCursor( false );
798
799 if( SCH_EDIT_FRAME* schframe = dynamic_cast<SCH_EDIT_FRAME*>( m_frame ) )
800 schframe->FocusOnItem( nullptr );
801
802 if( !GetSelection().Empty() )
803 {
805 }
806 else if( evt->FirstResponder() == this && evt->GetCommandId() == (int) WXK_ESCAPE )
807 {
809
811 editor->ClearHighlight( *evt );
812 }
813 }
814 else if( evt->Action() == TA_UNDO_REDO_PRE )
815 {
816 if( SCH_EDIT_FRAME* schframe = dynamic_cast<SCH_EDIT_FRAME*>( m_frame ) )
817 schframe->FocusOnItem( nullptr );
818 }
819 else if( evt->IsMotion() && !m_isSymbolEditor && evt->FirstResponder() == this )
820 {
821 // Update cursor and rollover item
822 rolloverItem = niluuid;
823 EE_COLLECTOR collector;
824
826
827 if( CollectHits( collector, evt->Position() ) )
828 {
829 narrowSelection( collector, evt->Position(), false );
830
831 if( collector.GetCount() == 1 && !hasModifier() )
832 {
833 OPT_TOOL_EVENT autostartEvt = autostartEvent( evt, grid, collector[0] );
834
835 if( autostartEvt )
836 {
837 if( autostartEvt->Matches( EE_ACTIONS::drawBus.MakeEvent() ) )
838 displayBusCursor = true;
839 else if( autostartEvt->Matches( EE_ACTIONS::drawWire.MakeEvent() ) )
840 displayWireCursor = true;
841 else if( autostartEvt->Matches( EE_ACTIONS::drawLines.MakeEvent() ) )
842 displayLineCursor = true;
843 }
844 else if( collector[0]->IsHypertext() && !collector[0]->IsSelected() )
845 {
846 rolloverItem = collector[0]->m_Uuid;
847 }
848 }
849 }
850 }
851 else
852 {
853 evt->SetPassEvent();
854 }
855
856 if( rolloverItem != lastRolloverItem )
857 {
858 if( EDA_ITEM* item = m_frame->GetItem( lastRolloverItem ) )
859 {
860 item->ClearFlags( IS_ROLLOVER );
861 lastRolloverItem = niluuid;
862
863 if( item->Type() == SCH_FIELD_T )
864 m_frame->GetCanvas()->GetView()->Update( item->GetParent() );
865 else
866 m_frame->GetCanvas()->GetView()->Update( item );
867 }
868 }
869
870 if( rolloverItem != niluuid )
871 {
872 EDA_ITEM* item = m_frame->GetItem( rolloverItem );
873
874 if( item && !( item->GetFlags() & IS_ROLLOVER ) )
875 {
876 item->SetFlags( IS_ROLLOVER );
877 lastRolloverItem = rolloverItem;
878
879 if( item->Type() == SCH_FIELD_T )
880 m_frame->GetCanvas()->GetView()->Update( item->GetParent() );
881 else
882 m_frame->GetCanvas()->GetView()->Update( item );
883 }
884 }
885
887 {
888 if( displayWireCursor )
889 {
890 m_nonModifiedCursor = KICURSOR::LINE_WIRE_ADD;
891 }
892 else if( displayBusCursor )
893 {
894 m_nonModifiedCursor = KICURSOR::LINE_BUS;
895 }
896 else if( displayLineCursor )
897 {
898 m_nonModifiedCursor = KICURSOR::LINE_GRAPHIC;
899 }
900 else if( rolloverItem != niluuid )
901 {
902 m_nonModifiedCursor = KICURSOR::HAND;
903 }
904 else if( !m_selection.Empty()
905 && drag_action == MOUSE_DRAG_ACTION::DRAG_SELECTED
906 && evt->HasPosition()
907 && selectionContains( evt->Position() ) ) //move/drag option prediction
908 {
909 m_nonModifiedCursor = KICURSOR::MOVING;
910 }
911 else
912 {
913 m_nonModifiedCursor = KICURSOR::ARROW;
914 }
915 }
916 }
917
918 m_disambiguateTimer.Stop();
919
920 // Shutting down; clear the selection
921 m_selection.Clear();
922
923 return 0;
924}
925
926
928 SCH_ITEM* aItem )
929{
930 VECTOR2I pos = aGrid.BestSnapAnchor( aEvent->Position(), aGrid.GetItemGrid( aItem ) );
931
934 && aItem->IsPointClickableAnchor( pos ) )
935 {
937
938 if( aItem->Type() == SCH_BUS_BUS_ENTRY_T )
939 {
941 }
942 else if( aItem->Type() == SCH_BUS_WIRE_ENTRY_T )
943 {
944 SCH_BUS_WIRE_ENTRY* busEntry = static_cast<SCH_BUS_WIRE_ENTRY*>( aItem );
945
946 if( !busEntry->m_connected_bus_item )
948 }
949 else if( aItem->Type() == SCH_LINE_T )
950 {
951 SCH_LINE* line = static_cast<SCH_LINE*>( aItem );
952
953 if( line->IsBus() )
954 newEvt = EE_ACTIONS::drawBus.MakeEvent();
955 else if( line->IsGraphicLine() )
956 newEvt = EE_ACTIONS::drawLines.MakeEvent();
957 }
958 else if( aItem->Type() == SCH_LABEL_T || aItem->Type() == SCH_HIER_LABEL_T
959 || aItem->Type() == SCH_SHEET_PIN_T )
960 {
961 SCH_LABEL_BASE* label = static_cast<SCH_LABEL_BASE*>( aItem );
962 SCH_CONNECTION possibleConnection( label->Schematic()->ConnectionGraph() );
963 possibleConnection.ConfigureFromLabel( label->GetText() );
964
965 if( possibleConnection.IsBus() )
967 }
968 else if( aItem->Type() == SCH_SYMBOL_T )
969 {
970 const SCH_SYMBOL* symbol = static_cast<const SCH_SYMBOL*>( aItem );
971
972 wxCHECK( symbol, OPT_TOOL_EVENT() );
973
974 const SCH_PIN* pin = symbol->GetPin( pos );
975
976 wxCHECK( pin, OPT_TOOL_EVENT() );
977
978 if( !pin->IsVisible() && !m_frame->eeconfig()->m_Appearance.show_hidden_pins )
979 return OPT_TOOL_EVENT();
980 }
981
982 newEvt->SetMousePosition( pos );
983 newEvt->SetHasPosition( true );
984 newEvt->SetForceImmediate( true );
985
986 getViewControls()->ForceCursorPosition( true, pos );
987
988 return newEvt;
989 }
990
991 return OPT_TOOL_EVENT();
992}
993
994
996{
997 wxMouseState keyboardState = wxGetMouseState();
998
999 setModifiersState( keyboardState.ShiftDown(), keyboardState.ControlDown(),
1000 keyboardState.AltDown() );
1001
1002 m_skip_heuristics = true;
1005 m_skip_heuristics = false;
1006
1007 return 0;
1008}
1009
1010
1011void EE_SELECTION_TOOL::OnIdle( wxIdleEvent& aEvent )
1012{
1014 {
1015 wxMouseState keyboardState = wxGetMouseState();
1016
1017 setModifiersState( keyboardState.ShiftDown(), keyboardState.ControlDown(),
1018 keyboardState.AltDown() );
1019
1020 if( m_additive )
1021 m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::ADD );
1022 else if( m_subtractive )
1023 m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::SUBTRACT );
1024 else if( m_exclusive_or )
1025 m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::XOR );
1026 else
1028 }
1029}
1030
1031
1033{
1034 return m_selection;
1035}
1036
1037
1039 const std::vector<KICAD_T>& aScanTypes )
1040{
1041 int pixelThreshold = KiROUND( getView()->ToWorld( HITTEST_THRESHOLD_PIXELS ) );
1042 int gridThreshold = KiROUND( getView()->GetGAL()->GetGridSize().EuclideanNorm() / 2 );
1043 aCollector.m_Threshold = std::max( pixelThreshold, gridThreshold );
1045
1046 if( m_isSymbolEditor )
1047 {
1048 LIB_SYMBOL* symbol = static_cast<SYMBOL_EDIT_FRAME*>( m_frame )->GetCurSymbol();
1049
1050 if( !symbol )
1051 return false;
1052
1053 aCollector.Collect( symbol->GetDrawItems(), aScanTypes, aWhere, m_unit, m_bodyStyle );
1054 }
1055 else
1056 {
1057 aCollector.Collect( m_frame->GetScreen(), aScanTypes, aWhere, m_unit, m_bodyStyle );
1058
1059 // If pins are disabled in the filter, they will be removed later. Let's add the parent
1060 // so that people can use pins to select symbols in this case.
1061 if( !m_filter.pins )
1062 {
1063 int originalCount = aCollector.GetCount();
1064
1065 for( int ii = 0; ii < originalCount; ++ii )
1066 {
1067 if( aCollector[ii]->Type() == SCH_PIN_T )
1068 {
1069 SCH_PIN* pin = static_cast<SCH_PIN*>( aCollector[ii] );
1070
1071 if( !aCollector.HasItem( pin->GetParentSymbol() ) )
1072 aCollector.Append( pin->GetParentSymbol() );
1073 }
1074 }
1075 }
1076 }
1077
1078 return aCollector.GetCount() > 0;
1079}
1080
1081
1083 bool aCheckLocked, bool aSelectedOnly )
1084{
1085 SYMBOL_EDIT_FRAME* symbolEditorFrame = dynamic_cast<SYMBOL_EDIT_FRAME*>( m_frame );
1086
1087 for( int i = collector.GetCount() - 1; i >= 0; --i )
1088 {
1089 if( symbolEditorFrame )
1090 {
1091 // Do not select invisible items if they are not displayed
1092 EDA_ITEM* item = collector[i];
1093
1094 if( item->Type() == SCH_FIELD_T )
1095 {
1096 if( !static_cast<SCH_FIELD*>( item )->IsVisible()
1097 && !symbolEditorFrame->GetShowInvisibleFields() )
1098 {
1099 collector.Remove( i );
1100 continue;
1101 }
1102 }
1103 else if( item->Type() == SCH_PIN_T )
1104 {
1105 if( !static_cast<SCH_PIN*>( item )->IsVisible()
1106 && !symbolEditorFrame->GetShowInvisiblePins() )
1107 {
1108 collector.Remove( i );
1109 continue;
1110 }
1111 }
1112 }
1113
1114 if( !Selectable( collector[i], &aWhere ) )
1115 {
1116 collector.Remove( i );
1117 continue;
1118 }
1119
1120 if( aCheckLocked && collector[i]->IsLocked() )
1121 {
1122 collector.Remove( i );
1123 continue;
1124 }
1125
1126 if( !itemPassesFilter( collector[i] ) )
1127 {
1128 collector.Remove( i );
1129 continue;
1130 }
1131
1132 if( aSelectedOnly && !collector[i]->IsSelected() )
1133 {
1134 collector.Remove( i );
1135 continue;
1136 }
1137 }
1138
1139 // Apply some ugly heuristics to avoid disambiguation menus whenever possible
1140 if( collector.GetCount() > 1 && !m_skip_heuristics )
1141 GuessSelectionCandidates( collector, aWhere );
1142}
1143
1144
1146 EDA_ITEM** aItem, bool* aSelectionCancelledFlag, bool aAdd,
1147 bool aSubtract, bool aExclusiveOr )
1148{
1150
1151 // If still more than one item we're going to have to ask the user.
1152 if( aCollector.GetCount() > 1 )
1153 {
1154 // Try to call selectionMenu via RunAction() to avoid event-loop contention
1155 // But it we cannot handle the event, then we don't have an active tool loop, so
1156 // handle it directly.
1157 if( !m_toolMgr->RunAction<COLLECTOR*>( EE_ACTIONS::selectionMenu, &aCollector ) )
1158 {
1159 if( !doSelectionMenu( &aCollector ) )
1160 aCollector.m_MenuCancelled = true;
1161 }
1162
1163 if( aCollector.m_MenuCancelled )
1164 {
1165 if( aSelectionCancelledFlag )
1166 *aSelectionCancelledFlag = true;
1167
1168 return false;
1169 }
1170 }
1171
1172 if( !aAdd && !aSubtract && !aExclusiveOr )
1174
1175 int addedCount = 0;
1176 bool anySubtracted = false;
1177
1178 if( aCollector.GetCount() > 0 )
1179 {
1180 for( int i = 0; i < aCollector.GetCount(); ++i )
1181 {
1182 EDA_ITEM_FLAGS flags = 0;
1183 bool isLine = aCollector[i]->Type() == SCH_LINE_T;
1184
1185 // Handle line ends specially
1186 if( isLine )
1187 {
1188 SCH_LINE* line = (SCH_LINE*) aCollector[i];
1189
1190 if( HitTestPoints( line->GetStartPoint(), aWhere, aCollector.m_Threshold ) )
1191 flags = STARTPOINT;
1192 else if( HitTestPoints( line->GetEndPoint(), aWhere, aCollector.m_Threshold ) )
1193 flags = ENDPOINT;
1194 else
1195 flags = STARTPOINT | ENDPOINT;
1196 }
1197
1198 if( aSubtract
1199 || ( aExclusiveOr && aCollector[i]->IsSelected()
1200 && ( !isLine || ( isLine && aCollector[i]->HasFlag( flags ) ) ) ) )
1201 {
1202 aCollector[i]->ClearFlags( flags );
1203
1204 // Need to update end shadows after ctrl-click unselecting one of two selected
1205 // endpoints.
1206 if( isLine )
1207 getView()->Update( aCollector[i] );
1208
1209 if( !aCollector[i]->HasFlag( STARTPOINT ) && !aCollector[i]->HasFlag( ENDPOINT ) )
1210 {
1211 unselect( aCollector[i] );
1212 anySubtracted = true;
1213 }
1214 }
1215 else
1216 {
1217 aCollector[i]->SetFlags( flags );
1218 select( aCollector[i] );
1219 addedCount++;
1220 }
1221 }
1222 }
1223
1224 if( addedCount == 1 )
1225 {
1227
1228 if( aItem && aCollector.GetCount() == 1 )
1229 *aItem = aCollector[0];
1230
1231 return true;
1232 }
1233 else if( addedCount > 1 )
1234 {
1236 return true;
1237 }
1238 else if( anySubtracted )
1239 {
1241 return true;
1242 }
1243
1244 return false;
1245}
1246
1247
1249 const std::vector<KICAD_T>& aScanTypes,
1250 EDA_ITEM** aItem, bool* aSelectionCancelledFlag,
1251 bool aCheckLocked, bool aAdd, bool aSubtract,
1252 bool aExclusiveOr )
1253{
1254 EE_COLLECTOR collector;
1255
1256 if( !CollectHits( collector, aWhere, aScanTypes ) )
1257 return false;
1258
1259 narrowSelection( collector, aWhere, aCheckLocked, aSubtract );
1260
1261 return selectPoint( collector, aWhere, aItem, aSelectionCancelledFlag, aAdd, aSubtract,
1262 aExclusiveOr );
1263}
1264
1265
1267{
1268 m_multiple = true; // Multiple selection mode is active
1269 KIGFX::VIEW* view = getView();
1270
1271 // hold all visible items
1272 std::vector<KIGFX::VIEW::LAYER_ITEM_PAIR> selectedItems;
1273 std::vector<KIGFX::VIEW::LAYER_ITEM_PAIR> sheetPins;
1274
1275 // Filter the view items based on the selection box
1276 BOX2I selectionBox;
1277
1278 selectionBox.SetMaximum();
1279 view->Query( selectionBox, selectedItems ); // Get the list of selected items
1280
1281 // Sheet pins aren't in the view; add them by hand
1282 for( KIGFX::VIEW::LAYER_ITEM_PAIR& pair : selectedItems )
1283 {
1284 SCH_SHEET* sheet = dynamic_cast<SCH_SHEET*>( pair.first );
1285
1286 if( sheet )
1287 {
1288 int layer = pair.second;
1289
1290 for( SCH_SHEET_PIN* pin : sheet->GetPins() )
1291 sheetPins.emplace_back( KIGFX::VIEW::LAYER_ITEM_PAIR( pin, layer ) );
1292 }
1293 }
1294
1295 selectedItems.insert( selectedItems.end(), sheetPins.begin(), sheetPins.end() );
1296
1297 for( const std::pair<KIGFX::VIEW_ITEM*, int>& item_pair : selectedItems )
1298 {
1299 if( EDA_ITEM* item = dynamic_cast<EDA_ITEM*>( item_pair.first ) )
1300 {
1301 if( Selectable( item ) && itemPassesFilter( item ) )
1302 {
1303 if( item->Type() == SCH_LINE_T )
1304 item->SetFlags( STARTPOINT | ENDPOINT );
1305
1306 select( item );
1307 }
1308 }
1309 }
1310
1311 m_multiple = false;
1312
1314
1315 return 0;
1316}
1317
1319{
1320 m_multiple = true; // Multiple selection mode is active
1321 KIGFX::VIEW* view = getView();
1322
1323 // hold all visible items
1324 std::vector<KIGFX::VIEW::LAYER_ITEM_PAIR> selectedItems;
1325
1326 // Filter the view items based on the selection box
1327 BOX2I selectionBox;
1328
1329 selectionBox.SetMaximum();
1330 view->Query( selectionBox, selectedItems ); // Get the list of selected items
1331
1332 for( KIGFX::VIEW::LAYER_ITEM_PAIR& pair : selectedItems )
1333 {
1334 SCH_SHEET* sheet = dynamic_cast<SCH_SHEET*>( pair.first );
1335
1336 if( sheet )
1337 {
1338 for( SCH_SHEET_PIN* pin : sheet->GetPins() )
1339 {
1340 EDA_ITEM* item = dynamic_cast<EDA_ITEM*>( pin );
1341
1342 if( item && Selectable( item ) )
1343 unselect( item );
1344 }
1345 }
1346
1347 if( EDA_ITEM* item = dynamic_cast<EDA_ITEM*>( pair.first ) )
1348 {
1349 if( Selectable( item ) )
1350 unselect( item );
1351 }
1352 }
1353
1354 m_multiple = false;
1355
1357
1358 return 0;
1359}
1360
1361
1363{
1364 // Prefer exact hits to sloppy ones
1365 std::set<EDA_ITEM*> exactHits;
1366
1367 for( int i = collector.GetCount() - 1; i >= 0; --i )
1368 {
1369 EDA_ITEM* item = collector[ i ];
1370 SCH_LINE* line = dynamic_cast<SCH_LINE*>( item );
1371 SCH_SHAPE* shape = dynamic_cast<SCH_SHAPE*>( item );
1372 SCH_TABLE* table = dynamic_cast<SCH_TABLE*>( item );
1373
1374 // Lines are hard to hit. Give them a bit more slop to still be considered "exact".
1375 if( line || ( shape && shape->GetShape() == SHAPE_T::POLY )
1376 || ( shape && shape->GetShape() == SHAPE_T::ARC ) )
1377 {
1378 int pixelThreshold = KiROUND( getView()->ToWorld( 6 ) );
1379
1380 if( item->HitTest( aPos, pixelThreshold ) )
1381 exactHits.insert( item );
1382 }
1383 else if( table )
1384 {
1385 // Consider table cells exact, but not the table itself
1386 }
1387 else
1388 {
1389 if( item->HitTest( aPos, 0 ) )
1390 exactHits.insert( item );
1391 }
1392 }
1393
1394 if( exactHits.size() > 0 && exactHits.size() < (unsigned) collector.GetCount() )
1395 {
1396 for( int i = collector.GetCount() - 1; i >= 0; --i )
1397 {
1398 EDA_ITEM* item = collector[ i ];
1399
1400 if( !exactHits.contains( item ) )
1401 collector.Transfer( item );
1402 }
1403 }
1404
1405 // Find the closest item. (Note that at this point all hits are either exact or non-exact.)
1406 SEG poss( mapCoords( aPos, m_isSymbolEditor ), mapCoords( aPos, m_isSymbolEditor ) );
1407 EDA_ITEM* closest = nullptr;
1408 int closestDist = INT_MAX / 4;
1409
1410 for( EDA_ITEM* item : collector )
1411 {
1412 BOX2I bbox = item->GetBoundingBox();
1413 int dist = INT_MAX / 4;
1414
1415 if( exactHits.contains( item ) )
1416 {
1417 if( item->Type() == SCH_PIN_T || item->Type() == SCH_JUNCTION_T )
1418 {
1419 closest = item;
1420 break;
1421 }
1422
1423 SCH_LINE* line = dynamic_cast<SCH_LINE*>( item );
1424 SCH_FIELD* field = dynamic_cast<SCH_FIELD*>( item );
1425 EDA_TEXT* text = dynamic_cast<EDA_TEXT*>( item );
1426 EDA_SHAPE* shape = dynamic_cast<EDA_SHAPE*>( item );
1427 SCH_SYMBOL* symbol = dynamic_cast<SCH_SYMBOL*>( item );
1428
1429 if( line )
1430 {
1431 dist = KiROUND( DistanceLinePoint( line->GetStartPoint(),
1432 line->GetEndPoint(), aPos ) );
1433 }
1434 else if( field )
1435 {
1436 BOX2I box = field->GetBoundingBox();
1437 EDA_ANGLE orient = field->GetTextAngle();
1438
1439 if( field->GetParent() && field->GetParent()->Type() == SCH_SYMBOL_T )
1440 {
1441 if( static_cast<SCH_SYMBOL*>( field->GetParent() )->GetTransform().y1 )
1442 {
1443 if( orient.IsHorizontal() )
1444 orient = ANGLE_VERTICAL;
1445 else
1446 orient = ANGLE_HORIZONTAL;
1447 }
1448 }
1449
1450 field->GetEffectiveTextShape( false, box, orient )
1451 ->Collide( poss, INT_MAX / 4, &dist );
1452 }
1453 else if( text )
1454 {
1455 text->GetEffectiveTextShape( false )->Collide( poss, INT_MAX / 4, &dist );
1456 }
1457 else if( shape )
1458 {
1459 std::vector<SHAPE*> shapes = shape->MakeEffectiveShapes();
1460
1461 for( SHAPE* s : shapes )
1462 {
1463 int shapeDist = dist;
1464 s->Collide( poss, INT_MAX / 4, &shapeDist );
1465
1466 if( shapeDist < dist )
1467 dist = shapeDist;
1468
1469 delete s;
1470 }
1471 }
1472 else if( symbol )
1473 {
1474 bbox = symbol->GetBodyBoundingBox();
1475
1476 SHAPE_RECT rect( bbox.GetPosition(), bbox.GetWidth(), bbox.GetHeight() );
1477
1478 if( bbox.Contains( aPos ) )
1479 dist = KiROUND( EuclideanNorm( bbox.GetCenter() - aPos ) );
1480 else
1481 rect.Collide( poss, closestDist, &dist );
1482 }
1483 else
1484 {
1485 dist = KiROUND( EuclideanNorm( bbox.GetCenter() - aPos ) );
1486 }
1487 }
1488 else
1489 {
1490 SHAPE_RECT rect( bbox.GetPosition(), bbox.GetWidth(), bbox.GetHeight() );
1491 rect.Collide( poss, collector.m_Threshold, &dist );
1492 }
1493
1494 if( dist == closestDist )
1495 {
1496 if( item->GetParent() == closest )
1497 closest = item;
1498 }
1499 else if( dist < closestDist )
1500 {
1501 closestDist = dist;
1502 closest = item;
1503 }
1504 }
1505
1506 // Construct a tight box (1/2 height and width) around the center of the closest item.
1507 // All items which exist at least partly outside this box have sufficient other areas
1508 // for selection and can be dropped.
1509 if( closest ) // Don't try and get a tight bbox if nothing is near the mouse pointer
1510 {
1511 BOX2I tightBox = closest->GetBoundingBox();
1512 tightBox.Inflate( -tightBox.GetWidth() / 4, -tightBox.GetHeight() / 4 );
1513
1514 for( int i = collector.GetCount() - 1; i >= 0; --i )
1515 {
1516 EDA_ITEM* item = collector[i];
1517
1518 if( item == closest )
1519 continue;
1520
1521 if( !item->HitTest( tightBox, true ) )
1522 collector.Transfer( item );
1523 }
1524 }
1525}
1526
1527
1528EE_SELECTION& EE_SELECTION_TOOL::RequestSelection( const std::vector<KICAD_T>& aScanTypes,
1529 bool aPromoteCellSelections )
1530{
1531 bool anyUnselected = false;
1532 bool anySelected = false;
1533
1534 if( m_selection.Empty() )
1535 {
1536 VECTOR2D cursorPos = getViewControls()->GetCursorPosition( true );
1537
1539 SelectPoint( cursorPos, aScanTypes );
1540 m_selection.SetIsHover( true );
1542 }
1543 else // Trim an existing selection by aFilterList
1544 {
1545 bool isMoving = false;
1546
1547 for( int i = (int) m_selection.GetSize() - 1; i >= 0; --i )
1548 {
1549 EDA_ITEM* item = (EDA_ITEM*) m_selection.GetItem( i );
1550 isMoving |= static_cast<SCH_ITEM*>( item )->IsMoving();
1551
1552 if( !item->IsType( aScanTypes ) )
1553 {
1554 unselect( item );
1555 anyUnselected = true;
1556 }
1557 }
1558
1559 if( !isMoving )
1561 }
1562
1563 if( aPromoteCellSelections )
1564 {
1565 std::set<EDA_ITEM*> parents;
1566
1567 for( int i = (int) m_selection.GetSize() - 1; i >= 0; --i )
1568 {
1569 EDA_ITEM* item = (EDA_ITEM*) m_selection.GetItem( i );
1570
1571 if( item->Type() == SCH_TABLECELL_T )
1572 {
1573 parents.insert( item->GetParent() );
1574 unselect( item );
1575 anyUnselected = true;
1576 }
1577 }
1578
1579 for( EDA_ITEM* parent : parents )
1580 {
1581 if( !parent->IsSelected() )
1582 {
1583 select( parent );
1584 anySelected = true;
1585 }
1586 }
1587 }
1588
1589 if( anyUnselected )
1591
1592 if( anySelected )
1594
1595 return m_selection;
1596}
1597
1598
1600{
1601 if( !aItem )
1602 return false;
1603
1604 // Locking is not yet exposed uniformly in the schematic
1605#if 0
1606 if( SCH_ITEM* schItem = dynamic_cast<SCH_ITEM*>( aItem ) )
1607 {
1608 if( schItem->IsLocked() && !m_filter.lockedItems )
1609 return false;
1610 }
1611#endif
1612
1613 switch( aItem->Type() )
1614 {
1615 case SCH_SYMBOL_T:
1616 case SCH_SHEET_T:
1617 if( !m_filter.symbols )
1618 return false;
1619
1620 break;
1621
1622 case SCH_PIN_T:
1623 case SCH_SHEET_PIN_T:
1624 if( !m_filter.pins )
1625 return false;
1626
1627 break;
1628
1629 case SCH_LINE_T:
1630 {
1631 switch( static_cast<SCH_LINE*>( aItem )->GetLayer() )
1632 {
1633 case LAYER_WIRE:
1634 case LAYER_BUS:
1635 if( !m_filter.wires )
1636 return false;
1637
1638 break;
1639
1640 default:
1641 if( !m_filter.graphics )
1642 return false;
1643 }
1644
1645 break;
1646 }
1647
1648 case SCH_SHAPE_T:
1649 if( !m_filter.graphics )
1650 return false;
1651
1652 break;
1653
1654 case SCH_TEXT_T:
1655 case SCH_TEXTBOX_T:
1656 case SCH_TABLE_T:
1657 case SCH_TABLECELL_T:
1658 case SCH_FIELD_T:
1659 if( !m_filter.text )
1660 return false;
1661
1662 break;
1663
1664 case SCH_LABEL_T:
1665 case SCH_GLOBAL_LABEL_T:
1666 case SCH_HIER_LABEL_T:
1667 if( !m_filter.labels )
1668 return false;
1669
1670 break;
1671
1672 case SCH_BITMAP_T:
1673 if( !m_filter.images )
1674 return false;
1675
1676 break;
1677
1678 default:
1679 if( !m_filter.otherItems )
1680 return false;
1681
1682 break;
1683 }
1684
1685 return true;
1686}
1687
1688
1690{
1691 VECTOR2I refP( 0, 0 );
1692
1693 if( m_selection.Size() > 0 )
1694 refP = static_cast<SCH_ITEM*>( m_selection.GetTopLeftItem() )->GetPosition();
1695
1697}
1698
1699
1700// Some navigation actions are allowed in selectMultiple
1710 &ACTIONS::zoomFitObjects, nullptr };
1711
1712
1714{
1715 bool cancelled = false; // Was the tool canceled while it was running?
1716 m_multiple = true; // Multiple selection mode is active
1717 KIGFX::VIEW* view = getView();
1718
1720 view->Add( &area );
1721
1722 while( TOOL_EVENT* evt = Wait() )
1723 {
1724 int width = area.GetEnd().x - area.GetOrigin().x;
1725 int height = area.GetEnd().y - area.GetOrigin().y;
1726
1727 /* Selection mode depends on direction of drag-selection:
1728 * Left > Right : Select objects that are fully enclosed by selection
1729 * Right > Left : Select objects that are crossed by selection
1730 */
1731 bool isGreedy = width < 0;
1732
1733 if( view->IsMirroredX() )
1734 isGreedy = !isGreedy;
1735
1736 m_frame->GetCanvas()->SetCurrentCursor( isGreedy ? KICURSOR::SELECT_LASSO
1737 : KICURSOR::SELECT_WINDOW );
1738
1739 if( evt->IsCancelInteractive() || evt->IsActivate() )
1740 {
1741 cancelled = true;
1742 break;
1743 }
1744
1745 if( evt->IsDrag( BUT_LEFT ) )
1746 {
1749
1750 // Start drawing a selection box
1751 area.SetOrigin( evt->DragOrigin() );
1752 area.SetEnd( evt->Position() );
1755 area.SetExclusiveOr( false );
1756
1757 view->SetVisible( &area, true );
1758 view->Update( &area );
1759 getViewControls()->SetAutoPan( true );
1760 }
1761
1762 if( evt->IsMouseUp( BUT_LEFT ) )
1763 {
1764 getViewControls()->SetAutoPan( false );
1765
1766 // End drawing the selection box
1767 view->SetVisible( &area, false );
1768
1769 // Fetch items from the RTree that are in our area of interest
1770 std::vector<KIGFX::VIEW::LAYER_ITEM_PAIR> nearbyViewItems;
1771 view->Query( area.ViewBBox(), nearbyViewItems );
1772
1773 // Build lists of nearby items and their children
1774 std::unordered_set<EDA_ITEM*> nearbyItems;
1775 std::vector<EDA_ITEM*> nearbyChildren;
1776 std::vector<EDA_ITEM*> flaggedItems;
1777
1778 for( KIGFX::VIEW::LAYER_ITEM_PAIR& pair : nearbyViewItems )
1779 {
1780 if( EDA_ITEM* item = dynamic_cast<EDA_ITEM*>( pair.first ) )
1781 {
1782 if( nearbyItems.insert( item ).second )
1783 {
1784 item->ClearFlags( CANDIDATE );
1785
1786 if( SCH_ITEM* sch_item = dynamic_cast<SCH_ITEM*>( item ) )
1787 {
1788 sch_item->RunOnChildren(
1789 [&]( SCH_ITEM* aChild )
1790 {
1791 // Filter pins by unit
1792 if( SCH_PIN* pin = dynamic_cast<SCH_PIN*>( aChild ) )
1793 {
1794 int unit = pin->GetLibPin()->GetUnit();
1795
1796 if( unit && unit != pin->GetParentSymbol()->GetUnit() )
1797 return;
1798 }
1799
1800 nearbyChildren.push_back( aChild );
1801 } );
1802 }
1803 }
1804 }
1805 }
1806
1807 BOX2I selectionRect( area.GetOrigin(), VECTOR2I( width, height ) );
1808 selectionRect.Normalize();
1809
1810 bool anyAdded = false;
1811 bool anySubtracted = false;
1812
1813 auto selectItem =
1814 [&]( EDA_ITEM* aItem, EDA_ITEM_FLAGS flags )
1815 {
1816 if( m_subtractive || ( m_exclusive_or && aItem->IsSelected() ) )
1817 {
1818 if ( m_exclusive_or )
1819 aItem->XorFlags( flags );
1820 else
1821 aItem->ClearFlags( flags );
1822
1823 if( !aItem->HasFlag( STARTPOINT ) && !aItem->HasFlag( ENDPOINT ) )
1824 {
1825 unselect( aItem );
1826 anySubtracted = true;
1827 }
1828
1829 // We changed one line endpoint on a selected line,
1830 // update the view at least.
1831 if( flags && !anySubtracted )
1832 getView()->Update( aItem );
1833 }
1834 else
1835 {
1836 aItem->SetFlags( flags );
1837 select( aItem );
1838 anyAdded = true;
1839 }
1840 };
1841
1842 for( EDA_ITEM* item : nearbyItems )
1843 {
1844 bool selected = false;
1845 EDA_ITEM_FLAGS flags = 0;
1846
1848 item->SetFlags( SHOW_ELEC_TYPE );
1849
1850 if( Selectable( item ) && itemPassesFilter( item ) )
1851 {
1852 if( item->Type() == SCH_LINE_T )
1853 {
1854 SCH_LINE* line = static_cast<SCH_LINE*>( item );
1855
1856 if( ( isGreedy && line->HitTest( selectionRect, false ) )
1857 || ( selectionRect.Contains( line->GetEndPoint() )
1858 && selectionRect.Contains( line->GetStartPoint() ) ) )
1859 {
1860 selected = true;
1861 flags |= STARTPOINT | ENDPOINT;
1862 }
1863 else if( !isGreedy )
1864 {
1865 if( selectionRect.Contains( line->GetStartPoint() )
1866 && line->IsStartDangling() )
1867 {
1868 selected = true;
1869 flags |= STARTPOINT;
1870 }
1871
1872 if( selectionRect.Contains( line->GetEndPoint() )
1873 && line->IsEndDangling() )
1874 {
1875 selected = true;
1876 flags |= ENDPOINT;
1877 }
1878 }
1879 }
1880 else
1881 {
1882 selected = item->HitTest( selectionRect, !isGreedy );
1883 }
1884 }
1885
1886 if( selected )
1887 {
1888 item->SetFlags( CANDIDATE );
1889 flaggedItems.push_back( item );
1890 selectItem( item, flags );
1891 }
1892
1893 item->ClearFlags( SHOW_ELEC_TYPE );
1894 }
1895
1896 for( EDA_ITEM* item : nearbyChildren )
1897 {
1899 item->SetFlags( SHOW_ELEC_TYPE );
1900
1901 if( Selectable( item )
1902 && itemPassesFilter( item )
1903 && !item->GetParent()->HasFlag( CANDIDATE )
1904 && item->HitTest( selectionRect, !isGreedy ) )
1905 {
1906 selectItem( item, 0 );
1907 }
1908
1909 item->ClearFlags( SHOW_ELEC_TYPE );
1910 }
1911
1912 for( EDA_ITEM* item : flaggedItems )
1913 item->ClearFlags( CANDIDATE );
1914
1915 m_selection.SetIsHover( false );
1916
1917 // Inform other potentially interested tools
1918 if( anyAdded )
1920
1921 if( anySubtracted )
1923
1924 break; // Stop waiting for events
1925 }
1926
1927 // Allow some actions for navigation
1928 for( int i = 0; allowedActions[i]; ++i )
1929 {
1930 if( evt->IsAction( allowedActions[i] ) )
1931 {
1932 evt->SetPassEvent();
1933 break;
1934 }
1935 }
1936 }
1937
1938 getViewControls()->SetAutoPan( false );
1939
1940 // Stop drawing the selection box
1941 view->Remove( &area );
1942 m_multiple = false; // Multiple selection mode is inactive
1943
1944 if( !cancelled )
1946
1947 return cancelled;
1948}
1949
1950
1952{
1953 bool cancelled = false; // Was the tool canceled while it was running?
1954 m_multiple = true; // Multiple selection mode is active
1955
1956 for( SCH_TABLECELL* cell : aTable->GetCells() )
1957 {
1958 if( cell->IsSelected() )
1959 cell->SetFlags( CANDIDATE );
1960 else
1961 cell->ClearFlags( CANDIDATE );
1962 }
1963
1964 auto wasSelected =
1965 []( EDA_ITEM* aItem )
1966 {
1967 return ( aItem->GetFlags() & CANDIDATE ) > 0;
1968 };
1969
1970 while( TOOL_EVENT* evt = Wait() )
1971 {
1972 if( evt->IsCancelInteractive() || evt->IsActivate() )
1973 {
1974 cancelled = true;
1975 break;
1976 }
1977 else if( evt->IsDrag( BUT_LEFT ) )
1978 {
1979 getViewControls()->SetAutoPan( true );
1980
1981 BOX2I selectionRect( evt->DragOrigin(), evt->Position() - evt->DragOrigin() );
1982 selectionRect.Normalize();
1983
1984 for( SCH_TABLECELL* cell : aTable->GetCells() )
1985 {
1986 bool doSelect = false;
1987
1988 if( cell->HitTest( selectionRect, false ) )
1989 {
1990 if( m_subtractive )
1991 doSelect = false;
1992 else if( m_exclusive_or )
1993 doSelect = !wasSelected( cell );
1994 else
1995 doSelect = true;
1996 }
1997 else if( wasSelected( cell ) )
1998 {
1999 doSelect = m_additive || m_subtractive || m_exclusive_or;
2000 }
2001
2002 if( doSelect && !cell->IsSelected() )
2003 select( cell );
2004 else if( !doSelect && cell->IsSelected() )
2005 unselect( cell );
2006 }
2007 }
2008 else if( evt->IsMouseUp( BUT_LEFT ) )
2009 {
2010 m_selection.SetIsHover( false );
2011
2012 bool anyAdded = false;
2013 bool anySubtracted = false;
2014
2015 for( SCH_TABLECELL* cell : aTable->GetCells() )
2016 {
2017 if( cell->IsSelected() && !wasSelected( cell ) )
2018 anyAdded = true;
2019 else if( wasSelected( cell ) && !cell->IsSelected() )
2020 anySubtracted = true;
2021 }
2022
2023 // Inform other potentially interested tools
2024 if( anyAdded )
2026
2027 if( anySubtracted )
2029
2030 break; // Stop waiting for events
2031 }
2032 else
2033 {
2034 // Allow some actions for navigation
2035 for( int i = 0; allowedActions[i]; ++i )
2036 {
2037 if( evt->IsAction( allowedActions[i] ) )
2038 {
2039 evt->SetPassEvent();
2040 break;
2041 }
2042 }
2043 }
2044 }
2045
2046 getViewControls()->SetAutoPan( false );
2047
2048 m_multiple = false; // Multiple selection mode is inactive
2049
2050 if( !cancelled )
2052
2053 return cancelled;
2054}
2055
2056
2058{
2059 EE_COLLECTOR collector;
2060
2061 //TODO(snh): Reimplement after exposing KNN interface
2062 int pixelThreshold = KiROUND( getView()->ToWorld( HITTEST_THRESHOLD_PIXELS ) );
2063 int gridThreshold = KiROUND( getView()->GetGAL()->GetGridSize().EuclideanNorm() );
2064 int thresholdMax = std::max( pixelThreshold, gridThreshold );
2065
2066 for( int threshold : { 0, thresholdMax/4, thresholdMax/2, thresholdMax } )
2067 {
2068 collector.m_Threshold = threshold;
2069 collector.Collect( m_frame->GetScreen(), connectedTypes, aPosition );
2070
2071 if( collector.GetCount() > 0 )
2072 break;
2073 }
2074
2075 return collector.GetCount() ? collector[ 0 ] : nullptr;
2076}
2077
2078
2080{
2081 VECTOR2I cursorPos = getViewControls()->GetCursorPosition( false );
2082
2083 SelectPoint( cursorPos, connectedTypes );
2084 return 0;
2085}
2086
2087
2089{
2092
2093 if( m_selection.Empty() )
2094 return 0;
2095
2096 unsigned done = false;
2097
2099
2100 for( EDA_ITEM* selItem : m_selection.GetItems() )
2101 {
2102 if( selItem->Type() != SCH_LINE_T )
2103 continue;
2104
2105 SCH_LINE* line = static_cast<SCH_LINE*>( selItem );
2106
2107 std::set<SCH_ITEM*> conns = m_frame->GetScreen()->MarkConnections( line, false );
2108 for( SCH_ITEM* item : conns )
2109 {
2110 if( item->IsType( { SCH_ITEM_LOCATE_WIRE_T, SCH_ITEM_LOCATE_BUS_T,
2111 SCH_ITEM_LOCATE_GRAPHIC_LINE_T } )
2112 && !item->IsSelected() )
2113 {
2114 done = true;
2115 }
2116
2117 select( item );
2118 }
2119
2120 if( !done )
2121 {
2122 conns = m_frame->GetScreen()->MarkConnections( line, true );
2123
2124 for( SCH_ITEM* item : conns )
2125 select( item );
2126 }
2127 }
2128
2129 if( m_selection.GetSize() > 1 )
2131
2132 return 0;
2133}
2134
2135
2137{
2138 std::set<std::pair<SCH_TABLE*, int>> columns;
2139 bool added = false;
2140
2141 for( EDA_ITEM* item : m_selection )
2142 {
2143 if( SCH_TABLECELL* cell = dynamic_cast<SCH_TABLECELL*>( item ) )
2144 {
2145 SCH_TABLE* table = static_cast<SCH_TABLE*>( cell->GetParent() );
2146 columns.insert( std::make_pair( table, cell->GetColumn() ) );
2147 }
2148 }
2149
2150 for( auto& [ table, col ] : columns )
2151 {
2152 for( int row = 0; row < table->GetRowCount(); ++row )
2153 {
2154 SCH_TABLECELL* cell = table->GetCell( row, col );
2155
2156 if( !cell->IsSelected() )
2157 {
2158 select( table->GetCell( row, col ) );
2159 added = true;
2160 }
2161 }
2162 }
2163
2164 if( added )
2166
2167 return 0;
2168}
2169
2170
2172{
2173 std::set<std::pair<SCH_TABLE*, int>> rows;
2174 bool added = false;
2175
2176 for( EDA_ITEM* item : m_selection )
2177 {
2178 if( SCH_TABLECELL* cell = dynamic_cast<SCH_TABLECELL*>( item ) )
2179 {
2180 SCH_TABLE* table = static_cast<SCH_TABLE*>( cell->GetParent() );
2181 rows.insert( std::make_pair( table, cell->GetRow() ) );
2182 }
2183 }
2184
2185 for( auto& [ table, row ] : rows )
2186 {
2187 for( int col = 0; col < table->GetColCount(); ++col )
2188 {
2189 SCH_TABLECELL* cell = table->GetCell( row, col );
2190
2191 if( !cell->IsSelected() )
2192 {
2193 select( table->GetCell( row, col ) );
2194 added = true;
2195 }
2196 }
2197 }
2198
2199 if( added )
2201
2202 return 0;
2203}
2204
2205
2207{
2208 std::set<SCH_TABLE*> tables;
2209 bool added = false;
2210
2211 for( EDA_ITEM* item : m_selection )
2212 {
2213 if( SCH_TABLECELL* cell = dynamic_cast<SCH_TABLECELL*>( item ) )
2214 tables.insert( static_cast<SCH_TABLE*>( cell->GetParent() ) );
2215 }
2216
2218
2219 for( SCH_TABLE* table : tables )
2220 {
2221 if( !table->IsSelected() )
2222 {
2223 select( table );
2224 added = true;
2225 }
2226 }
2227
2228 if( added )
2230
2231 return 0;
2232}
2233
2234
2236{
2238 return 0;
2239}
2240
2241
2243{
2244 if( aBBox.GetWidth() == 0 )
2245 return;
2246
2247 BOX2I bbox = aBBox;
2248 bbox.Normalize();
2249
2250 VECTOR2I bbSize = bbox.Inflate( KiROUND( bbox.GetWidth() * 0.2f ) ).GetSize();
2251 VECTOR2D screenSize = getView()->GetViewport().GetSize();
2252
2253 // This code tries to come up with a zoom factor that doesn't simply zoom in to the cross
2254 // probed symbol, but instead shows a reasonable amount of the circuit around it to provide
2255 // context. This reduces the need to manually change the zoom because it's too close.
2256
2257 // Using the default text height as a constant to compare against, use the height of the
2258 // bounding box of visible items for a footprint to figure out if this is a big symbol (like
2259 // a processor) or a small symbol (like a resistor). This ratio is not useful by itself as a
2260 // scaling factor. It must be "bent" to provide good scaling at varying symbol sizes. Bigger
2261 // symbols need less scaling than small ones.
2262 double currTextHeight = schIUScale.MilsToIU( DEFAULT_TEXT_SIZE );
2263
2264 double compRatio = bbSize.y / currTextHeight; // Ratio of symbol to text height
2265 double compRatioBent = 1.0;
2266
2267 // LUT to scale zoom ratio to provide reasonable schematic context. Must work with symbols
2268 // of varying sizes (e.g. 0402 package and 200 pin BGA).
2269 // Each entry represents a compRatio (symbol height / default text height) and an amount to
2270 // scale by.
2271 std::vector<std::pair<double, double>> lut{ { 1.25, 16 },
2272 { 2.5, 12 },
2273 { 5, 8 },
2274 { 6, 6 },
2275 { 10, 4 },
2276 { 20, 2 },
2277 { 40, 1.5 },
2278 { 100, 1 } };
2279
2280 std::vector<std::pair<double, double>>::iterator it;
2281
2282 // Large symbol default is last LUT entry (1:1).
2283 compRatioBent = lut.back().second;
2284
2285 // Use LUT to do linear interpolation of "compRatio" within "first", then use that result to
2286 // linearly interpolate "second" which gives the scaling factor needed.
2287 if( compRatio >= lut.front().first )
2288 {
2289 for( it = lut.begin(); it < lut.end() - 1; ++it )
2290 {
2291 if( it->first <= compRatio && next( it )->first >= compRatio )
2292 {
2293 double diffx = compRatio - it->first;
2294 double diffn = next( it )->first - it->first;
2295
2296 compRatioBent = it->second + ( next( it )->second - it->second ) * diffx / diffn;
2297 break; // We have our interpolated value
2298 }
2299 }
2300 }
2301 else
2302 {
2303 compRatioBent = lut.front().second; // Small symbol default is first entry
2304 }
2305
2306 // This is similar to the original KiCad code that scaled the zoom to make sure symbols were
2307 // visible on screen. It's simply a ratio of screen size to symbol size, and its job is to
2308 // zoom in to make the component fullscreen. Earlier in the code the symbol BBox is given a
2309 // 20% margin to add some breathing room. We compare the height of this enlarged symbol bbox
2310 // to the default text height. If a symbol will end up with the sides clipped, we adjust
2311 // later to make sure it fits on screen.
2312 screenSize.x = std::max( 10.0, screenSize.x );
2313 screenSize.y = std::max( 10.0, screenSize.y );
2314 double ratio = std::max( -1.0, fabs( bbSize.y / screenSize.y ) );
2315
2316 // Original KiCad code for how much to scale the zoom
2317 double kicadRatio = std::max( fabs( bbSize.x / screenSize.x ),
2318 fabs( bbSize.y / screenSize.y ) );
2319
2320 // If the width of the part we're probing is bigger than what the screen width will be after
2321 // the zoom, then punt and use the KiCad zoom algorithm since it guarantees the part's width
2322 // will be encompassed within the screen.
2323 if( bbSize.x > screenSize.x * ratio * compRatioBent )
2324 {
2325 // Use standard KiCad zoom for parts too wide to fit on screen/
2326 ratio = kicadRatio;
2327 compRatioBent = 1.0; // Reset so we don't modify the "KiCad" ratio
2328 wxLogTrace( "CROSS_PROBE_SCALE",
2329 "Part TOO WIDE for screen. Using normal KiCad zoom ratio: %1.5f", ratio );
2330 }
2331
2332 // Now that "compRatioBent" holds our final scaling factor we apply it to the original
2333 // fullscreen zoom ratio to arrive at the final ratio itself.
2334 ratio *= compRatioBent;
2335
2336 bool alwaysZoom = false; // DEBUG - allows us to minimize zooming or not
2337
2338 // Try not to zoom on every cross-probe; it gets very noisy
2339 if( ( ratio < 0.5 || ratio > 1.0 ) || alwaysZoom )
2340 getView()->SetScale( getView()->GetScale() / ratio );
2341}
2342
2343
2344void EE_SELECTION_TOOL::SyncSelection( const std::optional<SCH_SHEET_PATH>& targetSheetPath,
2345 SCH_ITEM* focusItem, const std::vector<SCH_ITEM*>& items )
2346{
2347 SCH_EDIT_FRAME* editFrame = dynamic_cast<SCH_EDIT_FRAME*>( m_frame );
2348
2349 if( !editFrame )
2350 return;
2351
2352 if( targetSheetPath && targetSheetPath != editFrame->Schematic().CurrentSheet() )
2353 {
2354 editFrame->Schematic().SetCurrentSheet( *targetSheetPath );
2355 editFrame->DisplayCurrentSheet();
2356 }
2357
2358 ClearSelection( items.size() > 0 ? true /*quiet mode*/ : false );
2359
2360 // Perform individual selection of each item before processing the event.
2361 for( SCH_ITEM* item : items )
2362 {
2363 SCH_ITEM* parent = dynamic_cast<SCH_ITEM*>( item->GetParent() );
2364
2365 // Make sure we only select items on the current screen
2366 if( m_frame->GetScreen()->CheckIfOnDrawList( item )
2367 || ( parent && m_frame->GetScreen()->CheckIfOnDrawList( parent ) ) )
2368 {
2369 select( item );
2370 }
2371 }
2372
2374
2375 if( bbox.GetWidth() != 0 && bbox.GetHeight() != 0 )
2376 {
2378 {
2380 ZoomFitCrossProbeBBox( bbox );
2381
2382 editFrame->FocusOnItem( focusItem );
2383
2384 if( !focusItem )
2385 editFrame->FocusOnLocation( bbox.Centre() );
2386 }
2387 }
2388
2389 if( m_selection.Size() > 0 )
2391}
2392
2393
2395{
2397
2398 if( m_isSymbolEditor )
2399 {
2400 LIB_SYMBOL* start = static_cast<SYMBOL_EDIT_FRAME*>( m_frame )->GetCurSymbol();
2401
2402 for( SCH_ITEM& item : start->GetDrawItems() )
2403 {
2404 if( item.IsSelected() )
2405 select( &item );
2406 }
2407 }
2408 else
2409 {
2410 for( SCH_ITEM* item : m_frame->GetScreen()->Items() )
2411 {
2412 // If the field and symbol are selected, only use the symbol
2413 if( item->IsSelected() )
2414 {
2415 select( item );
2416 }
2417 else
2418 {
2419 item->RunOnChildren(
2420 [&]( SCH_ITEM* aChild )
2421 {
2422 if( aChild->IsSelected() )
2423 select( aChild );
2424 } );
2425 }
2426 }
2427 }
2428
2430
2431 // Inform other potentially interested tools
2433}
2434
2435
2436bool EE_SELECTION_TOOL::Selectable( const EDA_ITEM* aItem, const VECTOR2I* aPos,
2437 bool checkVisibilityOnly ) const
2438{
2439 // NOTE: in the future this is where Eeschema layer/itemtype visibility will be handled
2440
2441 SYMBOL_EDIT_FRAME* symEditFrame = dynamic_cast<SYMBOL_EDIT_FRAME*>( m_frame );
2442
2443 // Do not allow selection of anything except fields when the current symbol in the symbol
2444 // editor is a derived symbol.
2445 if( symEditFrame && symEditFrame->IsSymbolAlias() && aItem->Type() != SCH_FIELD_T )
2446 return false;
2447
2448 switch( aItem->Type() )
2449 {
2450 case SCH_PIN_T:
2451 {
2452 const SCH_PIN* pin = static_cast<const SCH_PIN*>( aItem );
2453
2454 if( symEditFrame )
2455 {
2456 if( pin->GetUnit() && pin->GetUnit() != symEditFrame->GetUnit() )
2457 return false;
2458
2459 if( pin->GetBodyStyle() && pin->GetBodyStyle() != symEditFrame->GetBodyStyle() )
2460 return false;
2461 }
2462
2463 if( !pin->IsVisible() && !m_frame->GetShowAllPins() )
2464 return false;
2465
2466 if( !m_filter.pins )
2467 {
2468 // Pin anchors have to be allowed for auto-starting wires.
2469 if( aPos )
2470 {
2472 GRID_HELPER_GRIDS pinGrid = grid.GetItemGrid( pin );
2473
2474 if( pin->IsPointClickableAnchor( grid.BestSnapAnchor( *aPos, pinGrid ) ) )
2475 return true;
2476 }
2477
2478 return false;
2479 }
2480
2481 break;
2482 }
2483
2486 return false;
2487
2488 break;
2489
2490 case LIB_SYMBOL_T: // In symbol_editor we do not want to select the symbol itself.
2491 return false;
2492
2493 case SCH_FIELD_T: // SCH_FIELD objects are not unit/body-style-specific.
2494 {
2495 const SCH_FIELD* field = static_cast<const SCH_FIELD*>( aItem );
2496
2497 if( !field->IsVisible() && !( symEditFrame && symEditFrame->GetShowInvisibleFields() ) )
2498 return false;
2499
2500 break;
2501 }
2502
2503 case SCH_SHAPE_T:
2504 case SCH_TEXT_T:
2505 case SCH_TEXTBOX_T:
2506 if( symEditFrame )
2507 {
2508 const SCH_ITEM* sch_item = static_cast<const SCH_ITEM*>( aItem );
2509
2510 if( sch_item->GetUnit() && sch_item->GetUnit() != symEditFrame->GetUnit() )
2511 return false;
2512
2513 if( sch_item->GetBodyStyle() && sch_item->GetBodyStyle() != symEditFrame->GetBodyStyle() )
2514 return false;
2515 }
2516
2517 break;
2518
2519 case SCH_MARKER_T: // Always selectable
2520 return true;
2521
2522 case SCH_TABLECELL_T:
2523 {
2524 const SCH_TABLECELL* cell = static_cast<const SCH_TABLECELL*>( aItem );
2525
2526 if( cell->GetColSpan() == 0 || cell->GetRowSpan() == 0 )
2527 return false;
2528
2529 break;
2530 }
2531
2532 default: // Suppress warnings
2533 break;
2534 }
2535
2536 return true;
2537}
2538
2539
2541{
2542 if( m_selection.Empty() )
2543 return;
2544
2545 while( m_selection.GetSize() )
2547
2548 getView()->Update( &m_selection );
2549
2550 m_selection.SetIsHover( false );
2552
2553 // Inform other potentially interested tools
2554 if( !aQuietMode )
2556}
2557
2558
2560{
2561 highlight( aItem, SELECTED, &m_selection );
2562}
2563
2564
2566{
2567 unhighlight( aItem, SELECTED, &m_selection );
2568}
2569
2570
2571void EE_SELECTION_TOOL::highlight( EDA_ITEM* aItem, int aMode, SELECTION* aGroup )
2572{
2573 if( aMode == SELECTED )
2574 aItem->SetSelected();
2575 else if( aMode == BRIGHTENED )
2576 aItem->SetBrightened();
2577
2578 if( aGroup )
2579 aGroup->Add( aItem );
2580
2581 // Highlight pins and fields. (All the other symbol children are currently only
2582 // represented in the LIB_SYMBOL and will inherit the settings of the parent symbol.)
2583 if( SCH_ITEM* sch_item = dynamic_cast<SCH_ITEM*>( aItem ) )
2584 {
2585 sch_item->RunOnChildren(
2586 [&]( SCH_ITEM* aChild )
2587 {
2588 if( aMode == SELECTED )
2589 {
2590 aChild->SetSelected();
2591 getView()->Hide( aChild, true );
2592 }
2593 else if( aMode == BRIGHTENED )
2594 {
2595 aChild->SetBrightened();
2596 }
2597 } );
2598 }
2599
2600 if( aGroup && aMode != BRIGHTENED )
2601 getView()->Hide( aItem, true );
2602
2603 if( aItem->GetParent() && aItem->GetParent()->Type() != SCHEMATIC_T )
2604 getView()->Update( aItem->GetParent(), KIGFX::REPAINT );
2605
2606 getView()->Update( aItem, KIGFX::REPAINT );
2607}
2608
2609
2610void EE_SELECTION_TOOL::unhighlight( EDA_ITEM* aItem, int aMode, SELECTION* aGroup )
2611{
2612 if( aMode == SELECTED )
2613 {
2614 aItem->ClearSelected();
2615 // Lines need endpoints cleared here
2616 if( aItem->Type() == SCH_LINE_T )
2617 aItem->ClearFlags( STARTPOINT | ENDPOINT );
2618
2619 if( aMode != BRIGHTENED )
2620 getView()->Hide( aItem, false );
2621 }
2622 else if( aMode == BRIGHTENED )
2623 {
2624 aItem->ClearBrightened();
2625 }
2626
2627 if( aGroup )
2628 aGroup->Remove( aItem );
2629
2630 // Unhighlight pins and fields. (All the other symbol children are currently only
2631 // represented in the LIB_SYMBOL.)
2632 if( SCH_ITEM* sch_item = dynamic_cast<SCH_ITEM*>( aItem ) )
2633 {
2634 sch_item->RunOnChildren(
2635 [&]( SCH_ITEM* aChild )
2636 {
2637 if( aMode == SELECTED )
2638 {
2639 aChild->ClearSelected();
2640 getView()->Hide( aChild, false );
2641 }
2642 else if( aMode == BRIGHTENED )
2643 {
2644 aChild->ClearBrightened();
2645 }
2646
2647 if( aGroup )
2648 aGroup->Remove( aChild );
2649 } );
2650 }
2651
2652 if( aItem->GetParent() && aItem->GetParent()->Type() != SCHEMATIC_T )
2653 getView()->Update( aItem->GetParent(), KIGFX::REPAINT );
2654
2655 getView()->Update( aItem, KIGFX::REPAINT );
2656}
2657
2658
2660{
2661 const unsigned GRIP_MARGIN = 20;
2662 int margin = KiROUND( getView()->ToWorld( GRIP_MARGIN ) );
2663
2664 // Check if the point is located within any of the currently selected items bounding boxes
2665 for( EDA_ITEM* item : m_selection )
2666 {
2667 BOX2I itemBox = item->ViewBBox();
2668 itemBox.Inflate( margin ); // Give some margin for gripping an item
2669
2670 if( itemBox.Contains( aPoint ) )
2671 return true;
2672 }
2673
2674 return false;
2675}
2676
2677
2679{
2681
2688
2690
2696
2699
2701}
2702
2703
VECTOR2D mapCoords(const VECTOR2D &aSource)
Definition: PS_plotter.cpp:531
constexpr EDA_IU_SCALE schIUScale
Definition: base_units.h:110
static TOOL_ACTION unselectAll
Definition: actions.h:73
static TOOL_ACTION cursorLeft
Definition: actions.h:146
static TOOL_ACTION zoomOutCenter
Definition: actions.h:118
static TOOL_ACTION zoomIn
Definition: actions.h:115
static TOOL_ACTION cursorLeftFast
Definition: actions.h:151
static TOOL_ACTION selectColumns
Definition: actions.h:85
static TOOL_ACTION cursorDown
Definition: actions.h:145
static TOOL_ACTION zoomOut
Definition: actions.h:116
static TOOL_ACTION cursorRightFast
Definition: actions.h:152
static TOOL_ACTION zoomCenter
Definition: actions.h:123
static TOOL_ACTION panDown
Definition: actions.h:159
static TOOL_ACTION cursorDownFast
Definition: actions.h:150
static TOOL_ACTION selectRows
Definition: actions.h:84
static TOOL_ACTION cursorUpFast
Definition: actions.h:149
static TOOL_ACTION panLeft
Definition: actions.h:160
static TOOL_ACTION updateMenu
Definition: actions.h:204
static TOOL_ACTION zoomFitScreen
Definition: actions.h:124
static TOOL_ACTION panUp
Definition: actions.h:158
static TOOL_ACTION zoomFitObjects
Definition: actions.h:125
static TOOL_ACTION zoomInCenter
Definition: actions.h:117
static TOOL_ACTION panRight
Definition: actions.h:161
static TOOL_ACTION selectTable
Definition: actions.h:86
static TOOL_ACTION cursorUp
Cursor control with keyboard.
Definition: actions.h:144
static TOOL_ACTION finishInteractive
Definition: actions.h:64
static TOOL_ACTION cursorRight
Definition: actions.h:147
static TOOL_ACTION selectAll
Definition: actions.h:72
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:156
BOX2< Vec > & Normalize()
Ensure that the height and width are positive.
Definition: box2.h:136
const Vec & GetPosition() const
Definition: box2.h:201
void SetMaximum()
Definition: box2.h:70
const SizeVec & GetSize() const
Definition: box2.h:196
size_type GetHeight() const
Definition: box2.h:205
const Vec GetCenter() const
Definition: box2.h:220
size_type GetWidth() const
Definition: box2.h:204
bool Contains(const Vec &aPoint) const
Definition: box2.h:158
BOX2< Vec > & Inflate(coord_type dx, coord_type dy)
Inflates the rectangle horizontally by dx and vertically by dy.
Definition: box2.h:541
Vec Centre() const
Definition: box2.h:87
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:151
bool m_MenuCancelled
Definition: collector.h:237
int GetCount() const
Return the number of objects in the list.
Definition: collector.h:81
bool HasItem(const EDA_ITEM *aItem) const
Tests if aItem has already been collected.
Definition: collector.h:195
void Remove(int aIndex)
Remove the item at aIndex (first position is 0).
Definition: collector.h:109
int m_Threshold
Definition: collector.h:234
void Append(EDA_ITEM *item)
Add an item to the end of the list.
Definition: collector.h:99
COMMIT & Added(EDA_ITEM *aItem, BASE_SCREEN *aScreen=nullptr)
Remove a new item from the model.
Definition: commit.h:86
COMMIT & Add(EDA_ITEM *aItem, BASE_SCREEN *aScreen=nullptr)
Notify observers that aItem has been added.
Definition: commit.h:80
void AddItem(const TOOL_ACTION &aAction, const SELECTION_CONDITION &aCondition, int aOrder=ANY_ORDER)
Add a menu entry to run a TOOL_ACTION on selected items.
bool IsHorizontal() const
Definition: eda_angle.h:180
void AddStandardSubMenus(TOOL_MENU &aMenu)
Construct a "basic" menu for a tool, containing only items that apply to all tools (e....
void FocusOnLocation(const VECTOR2I &aPos)
Useful to focus on a particular location, in find functions.
virtual EDA_ITEM * GetItem(const KIID &aId) const
Fetch an item by KIID.
void SetCurrentCursor(KICURSOR aCursor)
Set the current cursor shape for this panel.
A base class for most all the KiCad significant classes used in schematics and boards.
Definition: eda_item.h:88
virtual const BOX2I GetBoundingBox() const
Return the orthogonal bounding box of this object for display purposes.
Definition: eda_item.cpp:74
void SetFlags(EDA_ITEM_FLAGS aMask)
Definition: eda_item.h:126
KICAD_T Type() const
Returns the type of object.
Definition: eda_item.h:100
void ClearSelected()
Definition: eda_item.h:121
void ClearFlags(EDA_ITEM_FLAGS aMask=EDA_ITEM_ALL_FLAGS)
Definition: eda_item.h:128
bool IsSelected() const
Definition: eda_item.h:109
void SetSelected()
Definition: eda_item.h:118
virtual bool IsType(const std::vector< KICAD_T > &aScanTypes) const
Check whether the item is one of the listed types.
Definition: eda_item.h:175
void ClearBrightened()
Definition: eda_item.h:122
void SetBrightened()
Definition: eda_item.h:119
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:215
EDA_ITEM * GetParent() const
Definition: eda_item.h:102
bool HasFlag(EDA_ITEM_FLAGS aFlag) const
Definition: eda_item.h:130
void XorFlags(EDA_ITEM_FLAGS aMask)
Definition: eda_item.h:127
EDA_ITEM_FLAGS GetFlags() const
Definition: eda_item.h:129
virtual std::vector< SHAPE * > MakeEffectiveShapes(bool aEdgeOnly=false) const
Make a set of SHAPE objects representing the EDA_SHAPE.
Definition: eda_shape.h:304
SHAPE_T GetShape() const
Definition: eda_shape.h:120
A mix-in class (via multiple inheritance) that handles texts such as labels, parts,...
Definition: eda_text.h:83
const EDA_ANGLE & GetTextAngle() const
Definition: eda_text.h:134
virtual const wxString & GetText() const
Return the string associated with the text object.
Definition: eda_text.h:98
virtual bool IsVisible() const
Definition: eda_text.h:151
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:985
static TOOL_ACTION selectionActivate
Activation of the selection tool.
Definition: ee_actions.h:46
static TOOL_ACTION properties
Definition: ee_actions.h:129
static TOOL_ACTION addItemsToSel
Selects a list of items (specified as the event parameter)
Definition: ee_actions.h:63
static TOOL_ACTION move
Definition: ee_actions.h:121
static TOOL_ACTION clearHighlight
Definition: ee_actions.h:293
static TOOL_ACTION selectConnection
If current selection is a wire or bus, expand to entire connection.
Definition: ee_actions.h:53
static TOOL_ACTION pinTable
Definition: ee_actions.h:156
static TOOL_ACTION navigateForward
Definition: ee_actions.h:222
static TOOL_ACTION slice
Definition: ee_actions.h:145
static TOOL_ACTION assignNetclass
Definition: ee_actions.h:162
static TOOL_ACTION clearSelection
Clears the current selection.
Definition: ee_actions.h:56
static TOOL_ACTION drag
Definition: ee_actions.h:122
static TOOL_ACTION navigateBack
Definition: ee_actions.h:223
static TOOL_ACTION selectionMenu
Runs a selection menu to select from a list of items.
Definition: ee_actions.h:67
static TOOL_ACTION placeClassLabel
Definition: ee_actions.h:88
static TOOL_ACTION drawWire
Definition: ee_actions.h:81
static TOOL_ACTION removeItemsFromSel
Definition: ee_actions.h:64
static TOOL_ACTION drawBus
Definition: ee_actions.h:82
static TOOL_ACTION selectNode
Select the junction, wire or bus segment under the cursor.
Definition: ee_actions.h:49
static TOOL_ACTION breakWire
Definition: ee_actions.h:144
static TOOL_ACTION placeSheetPin
Definition: ee_actions.h:92
static TOOL_ACTION drawLines
Definition: ee_actions.h:103
static TOOL_ACTION syncSheetPins
Definition: ee_actions.h:94
static TOOL_ACTION selectOnPCB
Definition: ee_actions.h:246
static TOOL_ACTION leaveSheet
Definition: ee_actions.h:220
static TOOL_ACTION placeGlobalLabel
Definition: ee_actions.h:89
static TOOL_ACTION removeItemFromSel
Definition: ee_actions.h:60
static TOOL_ACTION placeHierLabel
Definition: ee_actions.h:90
static TOOL_ACTION addItemToSel
Selects an item (specified as the event parameter).
Definition: ee_actions.h:59
static TOOL_ACTION symbolProperties
Definition: ee_actions.h:155
static TOOL_ACTION editPageNumber
Definition: ee_actions.h:164
static TOOL_ACTION enterSheet
Definition: ee_actions.h:219
static TOOL_ACTION setUnitDisplayName
Definition: ee_actions.h:214
static TOOL_ACTION unfoldBus
Definition: ee_actions.h:83
static TOOL_ACTION placeLabel
Definition: ee_actions.h:87
static TOOL_ACTION placeJunction
Definition: ee_actions.h:85
bool m_ShowPinElectricalTypes
static const std::vector< KICAD_T > MovableItems
Definition: ee_collectors.h:43
void Collect(SCH_SCREEN *aScreen, const std::vector< KICAD_T > &aScanTypes, const VECTOR2I &aPos, int aUnit=0, int aConvert=0)
Scan a EDA_ITEM using this class's Inspector method which does the collection.
static SELECTION_CONDITION SingleSymbol
static SELECTION_CONDITION SingleMultiFunctionPin
static SELECTION_CONDITION SingleSymbolOrPower
static SELECTION_CONDITION SingleMultiUnitSymbol
static SELECTION_CONDITION SingleNonExcludedMarker
static SELECTION_CONDITION SingleDeMorganSymbol
static SELECTION_CONDITION AllPins
static SELECTION_CONDITION MultipleSymbolsOrPower
GRID_HELPER_GRIDS GetItemGrid(const EDA_ITEM *aItem) const override
Gets the coarsest grid that applies to an item.
VECTOR2I BestSnapAnchor(const VECTOR2I &aOrigin, GRID_HELPER_GRIDS aGrid, SCH_ITEM *aSkip)
Tool that displays edit points allowing to modify items by dragging the points.
bool HasPoint()
Indicate the cursor is over an edit point.
bool Selectable(const EDA_ITEM *aItem, const VECTOR2I *aPos=nullptr, bool checkVisibilityOnly=false) const
Check conditions for an item to be selected.
void GuessSelectionCandidates(EE_COLLECTOR &collector, const VECTOR2I &aPos)
Apply heuristics to try and determine a single object when multiple are found under the cursor.
bool selectMultiple()
Handle drawing a selection box that allows one to select many items at the same time.
bool selectionContains(const VECTOR2I &aPoint) const
SCH_SELECTION_FILTER_OPTIONS m_filter
EE_SELECTION m_selection
void unselect(EDA_ITEM *aItem) override
Take necessary action to mark an item as unselected.
void unhighlight(EDA_ITEM *aItem, int aMode, SELECTION *aGroup=nullptr) override
Unhighlight the item visually.
int SelectColumns(const TOOL_EVENT &aEvent)
void SyncSelection(const std::optional< SCH_SHEET_PATH > &targetSheetPath, SCH_ITEM *focusItem, const std::vector< SCH_ITEM * > &items)
int SelectConnection(const TOOL_EVENT &aEvent)
If a connected item is selected then expand the selection to the entire connection,...
bool CollectHits(EE_COLLECTOR &aCollector, const VECTOR2I &aWhere, const std::vector< KICAD_T > &aScanTypes={ SCH_LOCATE_ANY_T })
Collect one or more items at a given point.
void setTransitions() override
This method is meant to be overridden in order to specify handlers for events.
bool selectPoint(EE_COLLECTOR &aCollector, const VECTOR2I &aWhere, EDA_ITEM **aItem=nullptr, bool *aSelectionCancelledFlag=nullptr, bool aAdd=false, bool aSubtract=false, bool aExclusiveOr=false)
Perform a click-type selection at a point (usually the cursor position).
int SelectAll(const TOOL_EVENT &aEvent)
Unselect all visible items in sheet.
EE_SELECTION & RequestSelection(const std::vector< KICAD_T > &aScanTypes={ SCH_LOCATE_ANY_T }, bool aPromoteCellSelections=false)
Return either an existing selection (filtered), or the selection at the current cursor position if th...
bool selectTableCells(SCH_TABLE *aTable)
Handle a table cell drag selection within a table.
EDA_ITEM * GetNode(const VECTOR2I &aPosition)
Finds a connected item at a point (usually the cursor position).
void ZoomFitCrossProbeBBox(const BOX2I &aBBox)
bool SelectPoint(const VECTOR2I &aWhere, const std::vector< KICAD_T > &aScanTypes={ SCH_LOCATE_ANY_T }, EDA_ITEM **aItem=nullptr, bool *aSelectionCancelledFlag=nullptr, bool aCheckLocked=false, bool aAdd=false, bool aSubtract=false, bool aExclusiveOr=false)
Perform a click-type selection at a point (usually the cursor position).
int Main(const TOOL_EVENT &aEvent)
The main loop.
int UnselectAll(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.
void highlight(EDA_ITEM *aItem, int aMode, SELECTION *aGroup=nullptr) override
Highlight the item visually.
int SelectNode(const TOOL_EVENT &aEvent)
Selects the connected item at the current cursor position.
bool Init() override
Init() is called once upon a registration of the tool.
int ClearSelection(const TOOL_EVENT &aEvent)
Select all visible items in sheet.
OPT_TOOL_EVENT autostartEvent(TOOL_EVENT *aEvent, EE_GRID_HELPER &aGrid, SCH_ITEM *aItem)
bool itemPassesFilter(EDA_ITEM *aItem)
Return true if the given item passes the stateful selection filter.
void RebuildSelection()
Rebuild the selection from the EDA_ITEMs' selection flags.
void OnIdle(wxIdleEvent &aEvent)
Zoom the screen to fit the bounding box for cross probing/selection sync.
SCH_BASE_FRAME * m_frame
void narrowSelection(EE_COLLECTOR &collector, const VECTOR2I &aWhere, bool aCheckLocked, bool aSelectedOnly=false)
Apply rules to narrow the collection down to selectable objects, and then heuristics to try and narro...
void Reset(RESET_REASON aReason) override
Bring the tool to a known, initial state.
void select(EDA_ITEM *aItem) override
Take necessary action to mark an item as selected.
int SelectRows(const TOOL_EVENT &aEvent)
EE_SELECTION & GetSelection()
void updateReferencePoint()
Set the reference point to the anchor of the top-left item.
BOX2I GetBoundingBox() const override
EDA_ITEM * GetTopLeftItem(bool onlyModules=false) const override
static const TOOL_EVENT DisambiguatePoint
Used for hotkey feedback.
Definition: actions.h:277
static const TOOL_EVENT ClearedEvent
Definition: actions.h:262
static const TOOL_EVENT SelectedEvent
Definition: actions.h:260
static const TOOL_EVENT PointSelectedEvent
Definition: actions.h:259
static const TOOL_EVENT UnselectedEvent
Definition: actions.h:261
virtual RENDER_SETTINGS * GetSettings()=0
Return a pointer to current settings that are going to be used when drawing items.
Represent a selection area (currently a rectangle) in a VIEW, drawn corner-to-corner between two poin...
void SetSubtractive(bool aSubtractive)
void SetAdditive(bool aAdditive)
void SetOrigin(const VECTOR2I &aOrigin)
const BOX2I ViewBBox() const override
Set the origin of the rectangle (the fixed corner)
void SetExclusiveOr(bool aExclusiveOr)
void SetEnd(const VECTOR2I &aEnd)
Set the current end of the rectangle (the corner that moves with the cursor.
void SetHighlight(bool aEnabled, int aNetcode=-1, bool aMulti=false)
Turns on/off highlighting.
virtual void CaptureCursor(bool aEnabled)
Force the cursor to stay within the drawing panel area.
virtual void ForceCursorPosition(bool aEnabled, const VECTOR2D &aPosition=VECTOR2D(0, 0))
Place the cursor immediately at a given point.
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.
Hold a (potentially large) number of VIEW_ITEMs and renders them on a graphics device provided by the...
Definition: view.h:68
BOX2D GetViewport() const
Return the current viewport visible area rectangle.
Definition: view.cpp:512
virtual void SetScale(double aScale, VECTOR2D aAnchor={ 0, 0 })
Set the scaling factor, zooming around a given anchor point.
Definition: view.cpp:552
virtual void Add(VIEW_ITEM *aItem, int aDrawPriority=-1)
Add a VIEW_ITEM to the view.
Definition: view.cpp:315
virtual void Remove(VIEW_ITEM *aItem)
Remove a VIEW_ITEM from the view.
Definition: view.cpp:354
virtual int Query(const BOX2I &aRect, std::vector< LAYER_ITEM_PAIR > &aResult) const
Find all visible items that touch or are within the rectangle aRect.
Definition: view.cpp:426
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:1631
bool IsMirroredX() const
Return true if view is flipped across the X axis.
Definition: view.h:245
std::pair< VIEW_ITEM *, int > LAYER_ITEM_PAIR
Definition: view.h:72
void Hide(VIEW_ITEM *aItem, bool aHide=true, bool aHideOverlay=false)
Temporarily hide the item in the view (e.g.
Definition: view.cpp:1579
PAINTER * GetPainter() const
Return the painter object used by the view for drawing #VIEW_ITEMS.
Definition: view.h:215
void SetVisible(VIEW_ITEM *aItem, bool aIsVisible=true)
Set the item visibility.
Definition: view.cpp:1558
Definition: kiid.h:49
Define a library symbol object.
Definition: lib_symbol.h:77
bool IsMulti() const override
Definition: lib_symbol.h:541
LIB_ITEMS_CONTAINER & GetDrawItems()
Return a reference to the draw item list.
Definition: lib_symbol.h:486
Tree view item data for the net navigator.
SCH_SHEET_PATH & CurrentSheet() const override
Definition: schematic.h:136
CONNECTION_GRAPH * ConnectionGraph() const override
Definition: schematic.h:146
void SetCurrentSheet(const SCH_SHEET_PATH &aPath) override
Definition: schematic.h:141
SCH_SHEET & Root() const
Definition: schematic.h:105
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 ...
virtual void Push(const wxString &aMessage=wxT("A commit"), int aCommitFlags=0) override
Revert the commit by restoring the modified items state.
Definition: sch_commit.cpp:405
virtual void Revert() override
Definition: sch_commit.cpp:483
Each graphical item can have a SCH_CONNECTION describing its logical connection (to a bus or net).
void ConfigureFromLabel(const wxString &aLabel)
Configures the connection given a label.
bool IsBus() const
KIGFX::SCH_VIEW * GetView() const override
Return a pointer to the #VIEW instance used in the panel.
Handle actions specific to the schematic editor.
Schematic editor (Eeschema) main window.
SCH_SHEET_PATH & GetCurrentSheet() const
SCHEMATIC & Schematic() const
void DisplayCurrentSheet()
Draw the current sheet on the display.
const wxString & GetHighlightedConnection() const
void FocusOnItem(SCH_ITEM *aItem)
Instances are attached to a symbol or sheet and provide a place for the symbol's value,...
Definition: sch_field.h:51
const BOX2I GetBoundingBox() const override
Return the orthogonal bounding box of this object for display purposes.
Definition: sch_field.cpp:586
Base class for any item which can be embedded within the SCHEMATIC container class,...
Definition: sch_item.h:174
SCHEMATIC * Schematic() const
Searches the item hierarchy to find a SCHEMATIC.
Definition: sch_item.cpp:139
int GetBodyStyle() const
Definition: sch_item.h:240
virtual bool IsPointClickableAnchor(const VECTOR2I &aPos) const
Definition: sch_item.h:463
int GetUnit() const
Definition: sch_item.h:237
void SetShape(LABEL_FLAG_SHAPE aShape)
Definition: sch_label.h:173
virtual void SetSpinStyle(SPIN_STYLE aSpinStyle)
Definition: sch_label.cpp:338
static bool IsDrawingLineWireOrBus(const SELECTION &aSelection)
Segment description base class to describe items which have 2 end points (track, wire,...
Definition: sch_line.h:40
bool HitTest(const VECTOR2I &aPosition, int aAccuracy=0) const override
Test if aPosition is inside or on the boundary of this item.
Definition: sch_line.cpp:844
bool IsStartDangling() const
Definition: sch_line.h:254
VECTOR2I GetEndPoint() const
Definition: sch_line.h:140
VECTOR2I GetStartPoint() const
Definition: sch_line.h:135
bool IsEndDangling() const
Definition: sch_line.h:255
bool IsBus() const
Return true if the line is a bus.
Definition: sch_line.cpp:1017
bool IsGraphicLine() const
Return if the line is a graphic (non electrical line)
Definition: sch_line.cpp:1005
void SetEndPoint(const VECTOR2I &aPosition)
Definition: sch_line.h:141
bool IsVisible() const
Definition: sch_pin.cpp:338
void ClearDrawingState()
Clear the state flags of all the items in the screen.
EE_RTREE & Items()
Gets the full RTree, usually for iterating.
Definition: sch_screen.h:109
std::set< SCH_ITEM * > MarkConnections(SCH_LINE *aSegment, bool aSecondPass)
Return all wires and junctions connected to aSegment which are not connected any symbol pin.
Definition: sch_screen.cpp:405
bool CheckIfOnDrawList(const SCH_ITEM *aItem) const
Definition: sch_screen.cpp:383
SCH_SHEET * Last() const
Return a pointer to the last SCH_SHEET of the list.
Define a sheet pin (label) used in sheets to create hierarchical schematics.
Definition: sch_sheet_pin.h:66
Sheet symbol placed in a schematic, and is the entry point for a sub schematic.
Definition: sch_sheet.h:57
std::vector< SCH_SHEET_PIN * > & GetPins()
Definition: sch_sheet.h:181
Schematic symbol object.
Definition: sch_symbol.h:108
TRANSFORM & GetTransform()
Definition: sch_symbol.h:285
SCH_PIN * GetPin(const wxString &number) const
Find a symbol pin by number.
std::unique_ptr< LIB_SYMBOL > & GetLibSymbolRef()
Definition: sch_symbol.h:216
BOX2I GetBodyBoundingBox() const
Return a bounding box for the symbol body but not the pins or fields.
int GetColSpan() const
Definition: sch_tablecell.h:61
int GetRowSpan() const
Definition: sch_tablecell.h:64
std::vector< SCH_TABLECELL * > GetCells() const
Definition: sch_table.h:141
Definition: seg.h:42
static SELECTION_CONDITION HasTypes(std::vector< KICAD_T > aTypes)
Create a functor that tests if among the selected items there is at least one of a given types.
static bool Empty(const SELECTION &aSelection)
Test if there are no items selected.
static SELECTION_CONDITION MoreThan(int aNumber)
Create a functor that tests if the number of selected items is greater than the value given as parame...
static bool Idle(const SELECTION &aSelection)
Test if there no items selected or being edited.
static SELECTION_CONDITION LessThan(int aNumber)
Create a functor that tests if the number of selected items is smaller than the value given as parame...
static SELECTION_CONDITION Count(int aNumber)
Create a functor that tests if the number of selected items is equal to the value given as parameter.
static SELECTION_CONDITION OnlyTypes(std::vector< KICAD_T > aTypes)
Create a functor that tests if the selected items are only of given types.
int RemoveItemFromSel(const TOOL_EVENT &aEvent)
bool doSelectionMenu(COLLECTOR *aCollector)
wxTimer m_disambiguateTimer
int AddItemsToSel(const TOOL_EVENT &aEvent)
int AddItemToSel(const TOOL_EVENT &aEvent)
int UpdateMenu(const TOOL_EVENT &aEvent)
Update a menu's state based on the current selection.
void setModifiersState(bool aShiftState, bool aCtrlState, bool aAltState)
Set the configuration of m_additive, m_subtractive, m_exclusive_or, m_skip_heuristics from the state ...
VECTOR2I m_originalCursor
int SelectionMenu(const TOOL_EVENT &aEvent)
Show a popup menu to trim the COLLECTOR passed as aEvent's parameter down to a single item.
int RemoveItemsFromSel(const TOOL_EVENT &aEvent)
bool hasModifier()
True if a selection modifier is enabled, false otherwise.
void onDisambiguationExpire(wxTimerEvent &aEvent)
Start the process to show our disambiguation menu once the user has kept the mouse down for the minim...
virtual void Add(EDA_ITEM *aItem)
Definition: selection.cpp:42
virtual KIGFX::VIEW_ITEM * GetItem(unsigned int aIdx) const override
Definition: selection.cpp:75
const std::deque< EDA_ITEM * > GetItems() const
Definition: selection.h:120
void SetIsHover(bool aIsHover)
Definition: selection.h:78
virtual void Remove(EDA_ITEM *aItem)
Definition: selection.cpp:60
virtual unsigned int GetSize() const override
Return the number of stored items.
Definition: selection.h:99
EDA_ITEM * Front() const
Definition: selection.h:208
virtual void Clear() override
Remove all the stored items from the group.
Definition: selection.h:92
int Size() const
Returns the number of selected parts.
Definition: selection.h:115
void ClearReferencePoint()
Definition: selection.cpp:185
bool OnlyContains(std::vector< KICAD_T > aList) const
Checks if all items in the selection have a type in aList.
Definition: selection.cpp:212
void SetReferencePoint(const VECTOR2I &aP)
Definition: selection.cpp:179
bool Empty() const
Checks if there is anything selected.
Definition: selection.h:109
bool Collide(const SHAPE *aShape, int aClearance, VECTOR2I *aMTV) const override
Check if the boundary of shape (this) lies closer to the shape aShape than aClearance,...
Definition: shape_rect.h:109
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.
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
Represent a single user action.
Definition: tool_action.h:269
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:42
TOOL_MANAGER * m_toolMgr
Definition: tool_base.h:216
KIGFX::VIEW * getView() const
Returns the instance of #VIEW object used in the application.
Definition: tool_base.cpp:36
RESET_REASON
Determine the reason of reset for a tool.
Definition: tool_base.h:78
@ REDRAW
Full drawing refresh.
Definition: tool_base.h:83
@ MODEL_RELOAD
Model changes (the sheet for a schematic)
Definition: tool_base.h:80
@ SUPERMODEL_RELOAD
For schematics, the entire schematic changed, not just the sheet.
Definition: tool_base.h:81
Generic, UI-independent tool event.
Definition: tool_event.h:167
const VECTOR2D Position() const
Returns the point where dragging has started.
Definition: tool_event.h:285
void Go(int(T::*aStateFunc)(const TOOL_EVENT &), const TOOL_EVENT_LIST &aConditions=TOOL_EVENT(TC_ANY, TA_ANY))
Define which state (aStateFunc) to go when a certain event arrives (aConditions).
TOOL_MENU m_menu
The functions below are not yet implemented - their interface may change.
TOOL_EVENT * Wait(const TOOL_EVENT_LIST &aEventList=TOOL_EVENT(TC_ANY, TA_ANY))
Suspend execution of the tool until an event specified in aEventList arrives.
bool ProcessEvent(const TOOL_EVENT &aEvent)
Propagate an event to tools that requested events of matching type(s).
bool RunAction(const std::string &aActionName, T aParam)
Run the specified action immediately, pausing the current action to run the new one.
Definition: tool_manager.h:145
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:230
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:192
CONDITIONAL_MENU & GetMenu()
Definition: tool_menu.cpp:44
void ShowContextMenu(SELECTION &aSelection)
Helper function to set and immediately show a CONDITIONAL_MENU in concert with the given SELECTION.
Definition: tool_menu.cpp:57
int y1
Definition: transform.h:49
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:432
static constexpr EDA_ANGLE ANGLE_HORIZONTAL
Definition: eda_angle.h:431
std::vector< EDA_ITEM * > EDA_ITEMS
Define list of drawing items for screens.
Definition: eda_item.h:532
#define BRIGHTENED
item is drawn with a bright contour
#define IS_NEW
New item, just created.
#define SELECTED
Item was manually selected by the user.
#define ENDPOINT
ends. (Used to support dragging.)
std::uint32_t EDA_ITEM_FLAGS
#define CANDIDATE
flag indicating that the structure is connected
#define IS_ROLLOVER
Rollover active. Used for hyperlink highlighting.
#define IS_MOVING
Item being moved.
#define SHOW_ELEC_TYPE
Show pin electrical type. Shared with IS_ROLLOVER.
#define STARTPOINT
When a line is selected, these flags indicate which.
static std::vector< KICAD_T > connectedTypes
#define HITTEST_THRESHOLD_PIXELS
const TOOL_ACTION * allowedActions[]
@ ID_POPUP_SCH_PIN_TRICKS_START
Definition: eeschema_id.h:88
@ ID_POPUP_SCH_PIN_TRICKS_HIER_LABEL
Definition: eeschema_id.h:92
@ ID_POPUP_SCH_PIN_TRICKS_WIRE
Definition: eeschema_id.h:90
@ ID_POPUP_SCH_ALT_PIN_FUNCTION
Definition: eeschema_id.h:96
@ ID_POPUP_SCH_UNFOLD_BUS_END
Definition: eeschema_id.h:79
@ ID_POPUP_SCH_SELECT_UNIT
Definition: eeschema_id.h:82
@ ID_POPUP_SCH_PIN_TRICKS_NET_LABEL
Definition: eeschema_id.h:91
@ ID_POPUP_SCH_PIN_TRICKS_NO_CONNECT
Definition: eeschema_id.h:89
@ 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:97
@ ID_POPUP_SCH_PIN_TRICKS_GLOBAL_LABEL
Definition: eeschema_id.h:93
@ ID_POPUP_SCH_PIN_TRICKS_END
Definition: eeschema_id.h:94
GRID_HELPER_GRIDS
Definition: grid_helper.h:37
KIID niluuid(0)
@ LAYER_WIRE
Definition: layer_ids.h:356
@ LAYER_BUS
Definition: layer_ids.h:357
@ REPAINT
Item needs to be redrawn.
Definition: view_item.h:57
CITER next(CITER it)
Definition: ptree.cpp:126
std::function< bool(const SELECTION &)> SELECTION_CONDITION
< Functor type that checks a specific condition for selected items.
bool zoom_to_fit
Zoom to fit items (ignored if center_on_items is off)
Definition: app_settings.h: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:93
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.
std::optional< TOOL_EVENT > OPT_TOOL_EVENT
Definition: tool_event.h:629
@ TA_CHOICE_MENU_CHOICE
Definition: tool_event.h:97
@ TA_UNDO_REDO_PRE
Definition: tool_event.h:105
@ TC_COMMAND
Definition: tool_event.h:56
@ MD_ALT
Definition: tool_event.h:144
@ MD_CTRL
Definition: tool_event.h:143
@ MD_SHIFT
Definition: tool_event.h:142
@ BUT_AUX1
Definition: tool_event.h:134
@ BUT_MIDDLE
Definition: tool_event.h:133
@ BUT_LEFT
Definition: tool_event.h:131
@ BUT_RIGHT
Definition: tool_event.h:132
@ BUT_AUX2
Definition: tool_event.h:135
double DistanceLinePoint(const VECTOR2I &linePointA, const VECTOR2I &linePointB, const VECTOR2I &referencePoint)
Compute the distance between a line and a reference point.
Definition: trigo.h:143
bool HitTestPoints(const VECTOR2I &pointA, const VECTOR2I &pointB, double threshold)
Test if two points are near each other.
Definition: trigo.h:165
double EuclideanNorm(const VECTOR2I &vector)
Definition: trigo.h:128
@ 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:185
@ 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:198
@ SCH_SHEET_T
Definition: typeinfo.h:174
@ SCH_ITEM_LOCATE_BUS_T
Definition: typeinfo.h:186
@ SCH_MARKER_T
Definition: typeinfo.h:158
@ SCH_SHAPE_T
Definition: typeinfo.h:149
@ SCH_HIER_LABEL_T
Definition: typeinfo.h:169
@ SCH_BUS_BUS_ENTRY_T
Definition: typeinfo.h:162
@ SCH_ITEM_LOCATE_GRAPHIC_LINE_T
Definition: typeinfo.h:187
@ SCHEMATIC_T
Definition: typeinfo.h:203
@ SCH_SHEET_PIN_T
Definition: typeinfo.h:173
@ SCH_TEXT_T
Definition: typeinfo.h:151
@ SCH_SYMBOL_LOCATE_POWER_T
Definition: typeinfo.h:195
@ 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
constexpr ret_type KiROUND(fp_type v)
Round a floating point number to an integer using "round halfway cases away from zero".
Definition: util.h:118
VECTOR2< int > VECTOR2I
Definition: vector2d.h:588