KiCad PCB EDA Suite
ee_selection_tool.cpp
Go to the documentation of this file.
1/*
2 * This program source code file is part of KiCad, a free EDA CAD application.
3 *
4 * Copyright (C) 2019 CERN
5 * Copyright (C) 2019-2022 KiCad Developers, see AUTHORS.txt for contributors.
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, you may find one here:
19 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
20 * or you may search the http://www.gnu.org website for the version 2 license,
21 * or you may write to the Free Software Foundation, Inc.,
22 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
23 */
24
25#include <core/typeinfo.h>
26#include <core/kicad_algo.h>
28#include <ee_actions.h>
29#include <ee_collectors.h>
30#include <ee_selection_tool.h>
31#include <eeschema_id.h>
32#include <symbol_edit_frame.h>
33#include <lib_item.h>
34#include <symbol_viewer_frame.h>
35#include <math/util.h>
36#include <geometry/shape_rect.h>
37#include <menus_helpers.h>
38#include <sch_painter.h>
40#include <sch_base_frame.h>
41#include <sch_symbol.h>
42#include <sch_field.h>
43#include <sch_edit_frame.h>
44#include <sch_item.h>
45#include <sch_line.h>
46#include <sch_bus_entry.h>
47#include <sch_junction.h>
48#include <sch_marker.h>
49#include <sch_sheet.h>
50#include <sch_sheet_pin.h>
51#include <lib_shape.h>
52#include <schematic.h>
53#include <tool/tool_event.h>
54#include <tool/tool_manager.h>
59#include <trigo.h>
60#include <view/view.h>
61#include <view/view_controls.h>
62#include <wx/log.h>
63
64
66{
67 if( aSel.GetSize() == 1 )
68 {
69 SCH_SYMBOL* symbol = dynamic_cast<SCH_SYMBOL*>( aSel.Front() );
70
71 if( symbol )
72 return !symbol->GetLibSymbolRef() || !symbol->GetLibSymbolRef()->IsPower();
73 }
74
75 return false;
76};
77
78
80{
81 return aSel.GetSize() == 1 && aSel.Front()->Type() == SCH_SYMBOL_T;
82};
83
84
86{
87 if( aSel.GetSize() == 1 )
88 {
89 SCH_SYMBOL* symbol = dynamic_cast<SCH_SYMBOL*>( aSel.Front() );
90
91 if( symbol )
92 return symbol->GetLibSymbolRef() && symbol->GetLibSymbolRef()->HasConversion();
93 }
94
95 return false;
96};
97
98
100{
101 if( aSel.GetSize() == 1 )
102 {
103 SCH_SYMBOL* symbol = dynamic_cast<SCH_SYMBOL*>( aSel.Front() );
104
105 if( symbol )
106 return symbol->GetLibSymbolRef() && symbol->GetLibSymbolRef()->GetUnitCount() >= 2;
107 }
108
109 return false;
110};
111
112
114{
115 if( aSel.CountType( SCH_MARKER_T ) != 1 )
116 return false;
117
118 return !static_cast<SCH_MARKER*>( aSel.Front() )->IsExcluded();
119};
120
121
122#define HITTEST_THRESHOLD_PIXELS 5
123
124
126 SELECTION_TOOL( "eeschema.InteractiveSelection" ),
127 m_frame( nullptr ),
128 m_nonModifiedCursor( KICURSOR::ARROW ),
129 m_isSymbolEditor( false ),
130 m_isSymbolViewer( false ),
131 m_unit( 0 ),
132 m_convert( 0 )
133{
135}
136
137
139{
141}
142
143
145
146
147static std::vector<KICAD_T> connectedTypes =
148{
150 SCH_PIN_T,
161};
162
163
165{
166 m_frame = getEditFrame<SCH_BASE_FRAME>();
167
168 SYMBOL_VIEWER_FRAME* symbolViewerFrame = dynamic_cast<SYMBOL_VIEWER_FRAME*>( m_frame );
169 SYMBOL_EDIT_FRAME* symbolEditorFrame = dynamic_cast<SYMBOL_EDIT_FRAME*>( m_frame );
170
171 if( symbolEditorFrame )
172 {
173 m_isSymbolEditor = true;
174 m_unit = symbolEditorFrame->GetUnit();
175 m_convert = symbolEditorFrame->GetConvert();
176 }
177 else
178 {
179 m_isSymbolViewer = symbolViewerFrame != nullptr;
180 }
181
182 auto wireSelection = E_C::Count( 1 ) && E_C::OnlyTypes( { SCH_ITEM_LOCATE_WIRE_T } );
183 auto busSelection = E_C::Count( 1 ) && E_C::OnlyTypes( { SCH_ITEM_LOCATE_BUS_T });
184 auto wireOrBusSelection = E_C::Count( 1 ) && E_C::OnlyTypes( { SCH_ITEM_LOCATE_WIRE_T, SCH_ITEM_LOCATE_BUS_T } );
185 auto connectedSelection = E_C::Count( 1 ) && E_C::OnlyTypes( connectedTypes );
186 auto sheetSelection = E_C::Count( 1 ) && E_C::OnlyTypes( { SCH_SHEET_T } );
187 auto crossProbingSelection = E_C::MoreThan( 0 ) && E_C::HasTypes( { SCH_SYMBOL_T, SCH_PIN_T, SCH_SHEET_T } );
188
189 auto schEditSheetPageNumberCondition =
190 [&] ( const SELECTION& aSel )
191 {
193 return false;
194
195 return E_C::LessThan( 2 )( aSel ) && E_C::OnlyTypes( { SCH_SHEET_T } )( aSel );
196 };
197
198 auto schEditCondition =
199 [this] ( const SELECTION& aSel )
200 {
202 };
203
204 auto belowRootSheetCondition =
205 [&]( const SELECTION& aSel )
206 {
207 SCH_EDIT_FRAME* editFrame = dynamic_cast<SCH_EDIT_FRAME*>( m_frame );
208
209 return editFrame
210 && editFrame->GetCurrentSheet().Last() != &editFrame->Schematic().Root();
211 };
212
213 auto haveHighlight =
214 [&]( const SELECTION& sel )
215 {
216 SCH_EDIT_FRAME* editFrame = dynamic_cast<SCH_EDIT_FRAME*>( m_frame );
217
218 return editFrame && editFrame->GetHighlightedConnection() != nullptr;
219 };
220
221 auto haveSymbol =
222 [&]( const SELECTION& sel )
223 {
224 return m_isSymbolEditor &&
225 static_cast<SYMBOL_EDIT_FRAME*>( m_frame )->GetCurSymbol();
226 };
227
228 auto symbolDisplayNameIsEditable =
229 [&]( const SELECTION& sel )
230 {
231 if ( !m_isSymbolEditor )
232 return false;
233
234 SYMBOL_EDIT_FRAME* symbEditorFrame = dynamic_cast<SYMBOL_EDIT_FRAME*>( m_frame );
235
236 return symbEditorFrame
237 && symbEditorFrame->GetCurSymbol()
238 && symbEditorFrame->GetCurSymbol()->IsMulti()
239 && symbEditorFrame->IsSymbolEditable()
240 && !symbEditorFrame->IsSymbolAlias();
241 };
242
243 auto& menu = m_menu.GetMenu();
244
245 menu.AddItem( EE_ACTIONS::clearHighlight, haveHighlight && EE_CONDITIONS::Idle, 1 );
246 menu.AddSeparator( haveHighlight && EE_CONDITIONS::Idle, 1 );
247
248 menu.AddItem( EE_ACTIONS::enterSheet, sheetSelection && EE_CONDITIONS::Idle, 2 );
249 menu.AddItem( EE_ACTIONS::selectOnPCB, crossProbingSelection && EE_CONDITIONS::Idle, 2 );
250 menu.AddItem( EE_ACTIONS::leaveSheet, belowRootSheetCondition, 2 );
251
252 menu.AddSeparator( 100 );
253 menu.AddItem( EE_ACTIONS::drawWire, schEditCondition && EE_CONDITIONS::Empty, 100 );
254 menu.AddItem( EE_ACTIONS::drawBus, schEditCondition && EE_CONDITIONS::Empty, 100 );
255
256 menu.AddSeparator( 100 );
258
259 menu.AddSeparator( 100 );
261
262 menu.AddSeparator( 200 );
263 menu.AddItem( EE_ACTIONS::selectConnection, connectedSelection && EE_CONDITIONS::Idle, 250 );
264 menu.AddItem( EE_ACTIONS::placeJunction, wireOrBusSelection && EE_CONDITIONS::Idle, 250 );
265 menu.AddItem( EE_ACTIONS::placeLabel, wireOrBusSelection && EE_CONDITIONS::Idle, 250 );
266 menu.AddItem( EE_ACTIONS::placeClassLabel, wireOrBusSelection && EE_CONDITIONS::Idle, 250 );
267 menu.AddItem( EE_ACTIONS::placeGlobalLabel, wireOrBusSelection && EE_CONDITIONS::Idle, 250 );
268 menu.AddItem( EE_ACTIONS::placeHierLabel, wireOrBusSelection && EE_CONDITIONS::Idle, 250 );
269 menu.AddItem( EE_ACTIONS::breakWire, wireSelection && EE_CONDITIONS::Idle, 250 );
270 menu.AddItem( EE_ACTIONS::breakBus, busSelection && EE_CONDITIONS::Idle, 250 );
271 menu.AddItem( EE_ACTIONS::importSingleSheetPin, sheetSelection && EE_CONDITIONS::Idle, 250 );
272 menu.AddItem( EE_ACTIONS::assignNetclass, connectedSelection && EE_CONDITIONS::Idle, 250 );
273 menu.AddItem( EE_ACTIONS::editPageNumber, schEditSheetPageNumberCondition, 250 );
274
275 menu.AddSeparator( 400 );
276 menu.AddItem( EE_ACTIONS::symbolProperties, haveSymbol && EE_CONDITIONS::Empty, 400 );
277 menu.AddItem( EE_ACTIONS::pinTable, haveSymbol && EE_CONDITIONS::Empty, 400 );
278 menu.AddItem( EE_ACTIONS::setUnitDisplayName,
279 haveSymbol && symbolDisplayNameIsEditable && EE_CONDITIONS::Empty, 400 );
280
281 menu.AddSeparator( 1000 );
283
284 m_disambiguateTimer.SetOwner( this );
285 Connect( wxEVT_TIMER, wxTimerEventHandler( EE_SELECTION_TOOL::onDisambiguationExpire ), nullptr, this );
286
287 return true;
288}
289
290
292{
293 m_frame = getEditFrame<SCH_BASE_FRAME>();
294
295 if( aReason == TOOL_BASE::MODEL_RELOAD )
296 {
297 // Remove pointers to the selected items from containers without changing their
298 // properties (as they are already deleted while a new sheet is loaded)
300 getView()->GetPainter()->GetSettings()->SetHighlight( false );
301
302 SYMBOL_EDIT_FRAME* symbolEditFrame = dynamic_cast<SYMBOL_EDIT_FRAME*>( m_frame );
303 SYMBOL_VIEWER_FRAME* symbolViewerFrame = dynamic_cast<SYMBOL_VIEWER_FRAME*>( m_frame );
304
305 if( symbolEditFrame )
306 {
307 m_isSymbolEditor = true;
308 m_unit = symbolEditFrame->GetUnit();
309 m_convert = symbolEditFrame->GetConvert();
310 }
311 else
312 {
313 m_isSymbolViewer = symbolViewerFrame != nullptr;
314 }
315 }
316 else
317 {
318 // Restore previous properties of selected items and remove them from containers
320 }
321
322 // Reinsert the VIEW_GROUP, in case it was removed from the VIEW
324 getView()->Add( &m_selection );
325}
326
327
329{
331
332 KIID lastRolloverItem = niluuid;
333
334 // Main loop: keep receiving events
335 while( TOOL_EVENT* evt = Wait() )
336 {
337 bool selCancelled = false;
338 bool displayWireCursor = false;
339 bool displayBusCursor = false;
340 bool displayLineCursor = false;
341 KIID rolloverItem = lastRolloverItem;
342
343 // on left click, a selection is made, depending on modifiers ALT, SHIFT, CTRL:
344 setModifiersState( evt->Modifier( MD_SHIFT ), evt->Modifier( MD_CTRL ),
345 evt->Modifier( MD_ALT ) );
346
347 bool modifier_enabled = m_subtractive || m_additive || m_exclusive_or;
348
349 MOUSE_DRAG_ACTION drag_action = m_frame->GetDragAction();
351
352 if( evt->IsMouseDown( BUT_LEFT ) )
353 {
354 // Avoid triggering when running under other tools
357 {
359 m_disambiguateTimer.StartOnce( 500 );
360 }
361 }
362 // Single click? Select single object
363 else if( evt->IsClick( BUT_LEFT ) )
364 {
365 // If the timer has stopped, then we have already run the disambiguate routine
366 // and we don't want to register an extra click here
367 if( !m_disambiguateTimer.IsRunning() )
368 {
369 evt->SetPassEvent();
370 continue;
371 }
372
373 m_disambiguateTimer.Stop();
374
375 if( SCH_EDIT_FRAME* schframe = dynamic_cast<SCH_EDIT_FRAME*>( m_frame ) )
376 schframe->FocusOnItem( nullptr );
377
378 // Collect items at the clicked location (doesn't select them yet)
379 EE_COLLECTOR collector;
380 CollectHits( collector, evt->Position() );
381 narrowSelection( collector, evt->Position(), false );
382
383 if( collector.GetCount() == 1 && !m_isSymbolEditor && !modifier_enabled )
384 {
385 OPT_TOOL_EVENT autostart = autostartEvent( evt, grid, collector[0] );
386
387 if( autostart )
388 {
390
391 params->layer = autostart->Parameter<DRAW_SEGMENT_EVENT_PARAMS*>()->layer;
392 params->quitOnDraw = true;
393 params->sourceSegment = dynamic_cast<SCH_LINE*>( collector[0] );
394
395 autostart->SetParameter( params );
396 m_toolMgr->ProcessEvent( *autostart );
397
398 selCancelled = true;
399 }
400 else if( collector[0]->IsHypertext() )
401 {
402 collector[ 0 ]->DoHypertextAction( m_frame );
403 selCancelled = true;
404 }
405 }
406
407 if( !selCancelled )
408 {
409 selectPoint( collector, evt->Position(), nullptr, nullptr, m_additive,
411 m_selection.SetIsHover( false );
412 }
413 }
414 else if( evt->IsClick( BUT_RIGHT ) )
415 {
416 m_disambiguateTimer.Stop();
417
418 // right click? if there is any object - show the context menu
419 if( m_selection.Empty() )
420 {
422 SelectPoint( evt->Position(), { SCH_LOCATE_ANY_T }, nullptr, &selCancelled );
423 m_selection.SetIsHover( true );
424 }
425 // If the cursor has moved off the bounding box of the selection by more than
426 // a grid square, check to see if there is another item available for selection
427 // under the cursor. If there is, the user likely meant to get the context menu
428 // for that item. If there is no new item, then keep the original selection and
429 // show the context menu for it.
430 else if( !m_selection.GetBoundingBox().Inflate( grid.GetGrid().x, grid.GetGrid().y )
431 .Contains( evt->Position() ) )
432 {
433 EE_SELECTION saved_selection = m_selection;
434
435 for( EDA_ITEM* item : saved_selection )
436 RemoveItemFromSel( item, true );
437
438 SelectPoint( evt->Position(), { SCH_LOCATE_ANY_T }, nullptr, &selCancelled );
439
440 if( m_selection.Empty() )
441 {
442 m_selection.SetIsHover( false );
443
444 for( EDA_ITEM* item : saved_selection )
445 AddItemToSel( item, true);
446 }
447 else
448 {
449 m_selection.SetIsHover( true );
450 }
451 }
452
453 if( !selCancelled )
455 }
456 else if( evt->IsDblClick( BUT_LEFT ) )
457 {
458 m_disambiguateTimer.Stop();
459
460 // double click? Display the properties window
461 if( SCH_EDIT_FRAME* schframe = dynamic_cast<SCH_EDIT_FRAME*>( m_frame ) )
462 schframe->FocusOnItem( nullptr );
463
464 if( m_selection.Empty() )
465 SelectPoint( evt->Position() );
466
467 EDA_ITEM* item = m_selection.Front();
468
469 if( item && item->Type() == SCH_SHEET_T )
471 else
473 }
474 else if( evt->IsDblClick( BUT_MIDDLE ) )
475 {
476 m_disambiguateTimer.Stop();
477
478 // Middle double click? Do zoom to fit or zoom to objects
479 if( evt->Modifier( MD_CTRL ) ) // Is CTRL key down?
481 else
483 }
484 else if( evt->IsDrag( BUT_LEFT ) )
485 {
486 m_disambiguateTimer.Stop();
487
488 // Is another tool already moving a new object? Don't allow a drag start
489 if( !m_selection.Empty() && m_selection[0]->HasFlag( IS_NEW | IS_MOVING ) )
490 {
491 evt->SetPassEvent();
492 continue;
493 }
494
495 // drag with LMB? Select multiple objects (or at least draw a selection box) or
496 // drag them
497 if( SCH_EDIT_FRAME* schframe = dynamic_cast<SCH_EDIT_FRAME*>( m_frame ) )
498 schframe->FocusOnItem( nullptr );
499
500 if( modifier_enabled || drag_action == MOUSE_DRAG_ACTION::SELECT )
501 {
503 }
504 else if( m_selection.Empty() && drag_action != MOUSE_DRAG_ACTION::DRAG_ANY )
505 {
507 }
508 else
509 {
510 if( m_isSymbolEditor )
511 {
512 if( static_cast<SYMBOL_EDIT_FRAME*>( m_frame )->IsSymbolAlias() )
513 {
515 }
516 else
517 {
521 LIB_PIN_T,
522 LIB_FIELD_T } );
523 }
524 }
525 else
526 {
528 }
529
530 // Check if dragging has started within any of selected items bounding box
531 if( selectionContains( evt->Position() ) )
532 {
533 // Yes -> run the move tool and wait till it finishes
534 if( m_isSymbolEditor )
535 m_toolMgr->InvokeTool( "eeschema.SymbolMoveTool" );
536 else
537 m_toolMgr->InvokeTool( "eeschema.InteractiveMove" );
538 }
539 else
540 {
541 // No -> drag a selection box
543 }
544 }
545 }
546 else if( evt->IsMouseDown( BUT_AUX1 ) )
547 {
549 }
550 else if( evt->IsMouseDown( BUT_AUX2 ) )
551 {
553 }
554 else if( evt->Category() == TC_COMMAND && evt->Action() == TA_CHOICE_MENU_CHOICE )
555 {
556 m_disambiguateTimer.Stop();
557
558 // context sub-menu selection? Handle unit selection or bus unfolding
559 if( *evt->GetCommandId() >= ID_POPUP_SCH_SELECT_UNIT_CMP
560 && *evt->GetCommandId() <= ID_POPUP_SCH_SELECT_UNIT_SYM_MAX )
561 {
562 SCH_SYMBOL* symbol = dynamic_cast<SCH_SYMBOL*>( m_selection.Front() );
563 int unit = *evt->GetCommandId() - ID_POPUP_SCH_SELECT_UNIT_CMP;
564
565 if( symbol )
566 static_cast<SCH_EDIT_FRAME*>( m_frame )->SelectUnit( symbol, unit );
567 }
568 else if( *evt->GetCommandId() >= ID_POPUP_SCH_UNFOLD_BUS
569 && *evt->GetCommandId() <= ID_POPUP_SCH_UNFOLD_BUS_END )
570 {
571 wxString* net = new wxString( *evt->Parameter<wxString*>() );
573 }
574 }
575 else if( evt->IsCancelInteractive() )
576 {
577 m_disambiguateTimer.Stop();
578
579 if( SCH_EDIT_FRAME* schframe = dynamic_cast<SCH_EDIT_FRAME*>( m_frame ) )
580 schframe->FocusOnItem( nullptr );
581
582 if( !GetSelection().Empty() )
583 {
585 }
586 else if( evt->FirstResponder() == this && evt->GetCommandId() == (int) WXK_ESCAPE )
587 {
589
591 editor->ClearHighlight( *evt );
592 }
593 }
594 else if( evt->Action() == TA_UNDO_REDO_PRE )
595 {
596 if( SCH_EDIT_FRAME* schframe = dynamic_cast<SCH_EDIT_FRAME*>( m_frame ) )
597 schframe->FocusOnItem( nullptr );
598
600 }
601 else if( evt->IsMotion() && !m_isSymbolEditor && evt->FirstResponder() == this )
602 {
603 // Update cursor and rollover item
604 rolloverItem = niluuid;
605 EE_COLLECTOR collector;
606
608
609 if( CollectHits( collector, evt->Position() ) )
610 {
611 narrowSelection( collector, evt->Position(), false );
612
613 if( collector.GetCount() == 1 && !modifier_enabled )
614 {
615 OPT_TOOL_EVENT autostartEvt = autostartEvent( evt, grid, collector[0] );
616
617 if( autostartEvt )
618 {
619 if( autostartEvt->Matches( EE_ACTIONS::drawBus.MakeEvent() ) )
620 displayBusCursor = true;
621 else if( autostartEvt->Matches( EE_ACTIONS::drawWire.MakeEvent() ) )
622 displayWireCursor = true;
623 else if( autostartEvt->Matches( EE_ACTIONS::drawLines.MakeEvent() ) )
624 displayLineCursor = true;
625 }
626 else if( collector[0]->IsHypertext() && !collector[0]->IsSelected() )
627 {
628 rolloverItem = collector[0]->m_Uuid;
629 }
630 }
631 }
632 }
633 else
634 {
635 evt->SetPassEvent();
636 }
637
638 if( rolloverItem != lastRolloverItem )
639 {
640 if( EDA_ITEM* item = m_frame->GetItem( lastRolloverItem ) )
641 {
642 item->ClearFlags( IS_ROLLOVER );
643 lastRolloverItem = niluuid;
644
645 if( item->Type() == SCH_FIELD_T )
646 m_frame->GetCanvas()->GetView()->Update( item->GetParent() );
647 else
648 m_frame->GetCanvas()->GetView()->Update( item );
649 }
650 }
651
652 if( EDA_ITEM* item = m_frame->GetItem( rolloverItem ) )
653 {
654 if( !( item->GetFlags() & IS_ROLLOVER ) )
655 {
656 item->SetFlags( IS_ROLLOVER );
657 lastRolloverItem = rolloverItem;
658
659 if( item->Type() == SCH_FIELD_T )
660 m_frame->GetCanvas()->GetView()->Update( item->GetParent() );
661 else
662 m_frame->GetCanvas()->GetView()->Update( item );
663 }
664 }
665
667 {
668 if( displayWireCursor )
669 {
671 }
672 else if( displayBusCursor )
673 {
675 }
676 else if( displayLineCursor )
677 {
679 }
680 else if( rolloverItem != niluuid )
681 {
683 }
684 else if( !m_selection.Empty()
685 && drag_action == MOUSE_DRAG_ACTION::DRAG_SELECTED
686 && evt->HasPosition()
687 && selectionContains( evt->Position() ) ) //move/drag option prediction
688 {
690 }
691 else
692 {
694 }
695 }
696 }
697
698 m_disambiguateTimer.Stop();
699
700 // Shutting down; clear the selection
702
703 return 0;
704}
705
706
708 SCH_ITEM* aItem )
709{
710 VECTOR2I pos = aGrid.BestSnapAnchor( aEvent->Position(), LAYER_CONNECTABLE );
711
714 && aItem->IsPointClickableAnchor( pos ) )
715 {
717
718 if( aItem->Type() == SCH_BUS_BUS_ENTRY_T )
719 {
721 }
722 else if( aItem->Type() == SCH_BUS_WIRE_ENTRY_T )
723 {
724 SCH_BUS_WIRE_ENTRY* busEntry = static_cast<SCH_BUS_WIRE_ENTRY*>( aItem );
725
726 if( !busEntry->m_connected_bus_item )
728 }
729 else if( aItem->Type() == SCH_LINE_T )
730 {
731 SCH_LINE* line = static_cast<SCH_LINE*>( aItem );
732
733 if( line->IsBus() )
734 newEvt = EE_ACTIONS::drawBus.MakeEvent();
735 else if( line->IsGraphicLine() )
736 newEvt = EE_ACTIONS::drawLines.MakeEvent();
737 }
738
739 newEvt->SetMousePosition( pos );
740 newEvt->SetHasPosition( true );
741 newEvt->SetForceImmediate( true );
742
743 getViewControls()->ForceCursorPosition( true, pos );
744
745 return newEvt;
746 }
747
748 return OPT_TOOL_EVENT();
749}
750
751
753{
754 wxMouseState keyboardState = wxGetMouseState();
755
756 setModifiersState( keyboardState.ShiftDown(), keyboardState.ControlDown(),
757 keyboardState.AltDown() );
758
759 m_skip_heuristics = true;
762 m_skip_heuristics = false;
763
764 return 0;
765}
766
767
768void EE_SELECTION_TOOL::OnIdle( wxIdleEvent& aEvent )
769{
771 {
772 wxMouseState keyboardState = wxGetMouseState();
773
774 setModifiersState( keyboardState.ShiftDown(), keyboardState.ControlDown(),
775 keyboardState.AltDown() );
776
777 if( m_additive )
779 else if( m_subtractive )
781 else if( m_exclusive_or )
783 else
785 }
786}
787
788
790{
791 return m_selection;
792}
793
794
795bool EE_SELECTION_TOOL::CollectHits( EE_COLLECTOR& aCollector, const VECTOR2I& aWhere,
796 const std::vector<KICAD_T>& aScanTypes )
797{
798 int pixelThreshold = KiROUND( getView()->ToWorld( HITTEST_THRESHOLD_PIXELS ) );
799 int gridThreshold = KiROUND( getView()->GetGAL()->GetGridSize().EuclideanNorm() / 2 );
800 aCollector.m_Threshold = std::max( pixelThreshold, gridThreshold );
802
803 if( m_isSymbolEditor )
804 {
805 LIB_SYMBOL* symbol = static_cast<SYMBOL_EDIT_FRAME*>( m_frame )->GetCurSymbol();
806
807 if( !symbol )
808 return false;
809
810 aCollector.Collect( symbol->GetDrawItems(), aScanTypes, aWhere, m_unit, m_convert );
811 }
812 else
813 {
814 aCollector.Collect( m_frame->GetScreen(), aScanTypes, aWhere, m_unit, m_convert );
815
817 {
818 int originalCount = aCollector.GetCount();
819
820 for( int ii = 0; ii < originalCount; ++ii )
821 {
822 if( aCollector[ii]->Type() == SCH_PIN_T )
823 {
824 SCH_PIN* pin = static_cast<SCH_PIN*>( aCollector[ii] );
825
826 if( !aCollector.HasItem( pin->GetParentSymbol() ) )
827 aCollector.Append( pin->GetParentSymbol() );
828 }
829 }
830 }
831 }
832
833 return aCollector.GetCount() > 0;
834}
835
836
838 bool aCheckLocked, bool aSelectedOnly )
839{
840 for( int i = collector.GetCount() - 1; i >= 0; --i )
841 {
842 if( !Selectable( collector[i], &aWhere ) )
843 {
844 collector.Remove( i );
845 continue;
846 }
847
848 if( aCheckLocked && collector[i]->IsLocked() )
849 {
850 collector.Remove( i );
851 continue;
852 }
853
854 if( aSelectedOnly && !collector[i]->IsSelected() )
855 {
856 collector.Remove( i );
857 continue;
858 }
859 }
860
861 // Apply some ugly heuristics to avoid disambiguation menus whenever possible
862 if( collector.GetCount() > 1 && !m_skip_heuristics )
863 GuessSelectionCandidates( collector, aWhere );
864}
865
866
867bool EE_SELECTION_TOOL::selectPoint( EE_COLLECTOR& aCollector, const VECTOR2I& aWhere,
868 EDA_ITEM** aItem, bool* aSelectionCancelledFlag, bool aAdd,
869 bool aSubtract, bool aExclusiveOr )
870{
872
873 // If still more than one item we're going to have to ask the user.
874 if( aCollector.GetCount() > 1 )
875 {
876 // Try to call selectionMenu via RunAction() to avoid event-loop contention
877 // But it we cannot handle the event, then we don't have an active tool loop, so
878 // handle it directly.
879 if( !m_toolMgr->RunAction( EE_ACTIONS::selectionMenu, true, &aCollector ) )
880 {
881 if( !doSelectionMenu( &aCollector ) )
882 aCollector.m_MenuCancelled = true;
883 }
884
885 if( aCollector.m_MenuCancelled )
886 {
887 if( aSelectionCancelledFlag )
888 *aSelectionCancelledFlag = true;
889
890 return false;
891 }
892 }
893
894 if( !aAdd && !aSubtract && !aExclusiveOr )
896
897 int addedCount = 0;
898 bool anySubtracted = false;
899
900 if( aCollector.GetCount() > 0 )
901 {
902 for( int i = 0; i < aCollector.GetCount(); ++i )
903 {
904 EDA_ITEM_FLAGS flags = 0;
905
906 // Handle line ends specially
907 if( aCollector[i]->Type() == SCH_LINE_T )
908 {
909 SCH_LINE* line = (SCH_LINE*) aCollector[i];
910
911 if( HitTestPoints( line->GetStartPoint(), aWhere, aCollector.m_Threshold ) )
912 flags = STARTPOINT;
913 else if( HitTestPoints( line->GetEndPoint(), aWhere, aCollector.m_Threshold ) )
914 flags = ENDPOINT;
915 else
916 flags = STARTPOINT | ENDPOINT;
917 }
918
919 if( aSubtract || ( aExclusiveOr && aCollector[i]->IsSelected() ) )
920 {
921 aCollector[i]->ClearFlags( flags );
922
923 if( !aCollector[i]->HasFlag( STARTPOINT ) && !aCollector[i]->HasFlag( ENDPOINT ) )
924 {
925 unselect( aCollector[i] );
926 anySubtracted = true;
927 }
928 }
929 else
930 {
931 aCollector[i]->SetFlags( flags );
932 select( aCollector[i] );
933 addedCount++;
934 }
935 }
936 }
937
938 if( addedCount == 1 )
939 {
941
942 if( aItem && aCollector.GetCount() == 1 )
943 *aItem = aCollector[0];
944
945 return true;
946 }
947 else if( addedCount > 1 )
948 {
950 return true;
951 }
952 else if( anySubtracted )
953 {
955 return true;
956 }
957
958 return false;
959}
960
961
963 const std::vector<KICAD_T>& aScanTypes,
964 EDA_ITEM** aItem, bool* aSelectionCancelledFlag,
965 bool aCheckLocked, bool aAdd, bool aSubtract,
966 bool aExclusiveOr )
967{
968 EE_COLLECTOR collector;
969
970 if( !CollectHits( collector, aWhere, aScanTypes ) )
971 return false;
972
973 narrowSelection( collector, aWhere, aCheckLocked, aSubtract );
974
975 return selectPoint( collector, aWhere, aItem, aSelectionCancelledFlag, aAdd, aSubtract,
976 aExclusiveOr );
977}
978
979
981{
982 m_multiple = true; // Multiple selection mode is active
983 KIGFX::VIEW* view = getView();
984
985 // hold all visible items
986 std::vector<KIGFX::VIEW::LAYER_ITEM_PAIR> selectedItems;
987 std::vector<KIGFX::VIEW::LAYER_ITEM_PAIR> sheetPins;
988
989 // Filter the view items based on the selection box
990 BOX2I selectionBox;
991
992 selectionBox.SetMaximum();
993 view->Query( selectionBox, selectedItems ); // Get the list of selected items
994
995 // Sheet pins aren't in the view; add them by hand
996 for( KIGFX::VIEW::LAYER_ITEM_PAIR& pair : selectedItems )
997 {
998 SCH_SHEET* sheet = dynamic_cast<SCH_SHEET*>( pair.first );
999
1000 if( sheet )
1001 {
1002 int layer = pair.second;
1003
1004 for( SCH_SHEET_PIN* pin : sheet->GetPins() )
1005 sheetPins.emplace_back( KIGFX::VIEW::LAYER_ITEM_PAIR( pin, layer ) );
1006 }
1007 }
1008
1009 selectedItems.insert( selectedItems.end(), sheetPins.begin(), sheetPins.end() );
1010
1011 for( const std::pair<KIGFX::VIEW_ITEM*, int>& item_pair : selectedItems )
1012 {
1013 if( EDA_ITEM* item = dynamic_cast<EDA_ITEM*>( item_pair.first ) )
1014 {
1015 if( Selectable( item ) )
1016 {
1017 if( item->Type() == SCH_LINE_T )
1018 item->SetFlags( STARTPOINT | ENDPOINT );
1019
1020 select( item );
1021 }
1022 }
1023 }
1024
1025 m_multiple = false;
1026
1027 return 0;
1028}
1029
1030
1032{
1033 // Prefer exact hits to sloppy ones
1034 std::set<EDA_ITEM*> exactHits;
1035
1036 for( int i = collector.GetCount() - 1; i >= 0; --i )
1037 {
1038 EDA_ITEM* item = collector[ i ];
1039 SCH_LINE* line = dynamic_cast<SCH_LINE*>( item );
1040 LIB_SHAPE* shape = dynamic_cast<LIB_SHAPE*>( item );
1041 SCH_SYMBOL* symbol = dynamic_cast<SCH_SYMBOL*>( item );
1042
1043 // Lines are hard to hit. Give them a bit more slop to still be considered "exact".
1044
1045 if( line || ( shape && shape->GetShape() == SHAPE_T::POLY ) )
1046 {
1047 int pixelThreshold = KiROUND( getView()->ToWorld( 1 ) );
1048
1049 if( item->HitTest( aPos, pixelThreshold ) )
1050 exactHits.insert( item );
1051 }
1052 else if( symbol && m_frame->eeconfig()->m_Selection.select_pin_selects_symbol )
1053 {
1054 if( symbol->GetBodyAndPinsBoundingBox().Contains( aPos ) )
1055 exactHits.insert( item );
1056 }
1057 else
1058 {
1059 if( item->HitTest( aPos, 0 ) )
1060 exactHits.insert( item );
1061 }
1062 }
1063
1064 if( exactHits.size() > 0 && exactHits.size() < (unsigned) collector.GetCount() )
1065 {
1066 for( int i = collector.GetCount() - 1; i >= 0; --i )
1067 {
1068 EDA_ITEM* item = collector[ i ];
1069
1070 if( !exactHits.count( item ) )
1071 collector.Transfer( item );
1072 }
1073 }
1074
1075 // Find the closest item. (Note that at this point all hits are either exact or non-exact.)
1076 VECTOR2I pos( aPos );
1077 SEG poss( m_isSymbolEditor ? mapCoords( pos ) : pos,
1078 m_isSymbolEditor ? mapCoords( pos ) : pos );
1079 EDA_ITEM* closest = nullptr;
1080 int closestDist = INT_MAX / 2;
1081
1082 for( EDA_ITEM* item : collector )
1083 {
1084 BOX2I bbox = item->GetBoundingBox();
1085 int dist = INT_MAX / 2;
1086
1087 if( exactHits.count( item ) )
1088 {
1089 if( item->Type() == SCH_PIN_T || item->Type() == SCH_JUNCTION_T )
1090 {
1091 closest = item;
1092 break;
1093 }
1094
1095 SCH_LINE* line = dynamic_cast<SCH_LINE*>( item );
1096 EDA_TEXT* text = dynamic_cast<EDA_TEXT*>( item );
1097 SCH_SYMBOL* symbol = dynamic_cast<SCH_SYMBOL*>( item );
1098
1099 if( line )
1100 {
1101 dist = DistanceLinePoint( line->GetStartPoint(), line->GetEndPoint(), pos );
1102 }
1103 else if( text )
1104 {
1105 text->GetEffectiveTextShape()->Collide( poss, closestDist, &dist );
1106 }
1107 else if( symbol )
1108 {
1109 try
1110 {
1111 bbox = symbol->GetBodyBoundingBox();
1112 }
1113 catch( const boost::bad_pointer& exc )
1114 {
1115 // This may be overkill and could be an assertion but we are more likely to
1116 // find any boost pointer container errors this way.
1117 wxLogError( wxT( "Boost bad pointer exception '%s' occurred." ), exc.what() );
1118 }
1119
1120 SHAPE_RECT rect( bbox.GetPosition(), bbox.GetWidth(), bbox.GetHeight() );
1121
1122 if( bbox.Contains( pos ) )
1123 dist = EuclideanNorm( bbox.GetCenter() - pos );
1124 else
1125 rect.Collide( poss, closestDist, &dist );
1126 }
1127 else
1128 {
1129 dist = EuclideanNorm( bbox.GetCenter() - pos );
1130 }
1131 }
1132 else
1133 {
1134 SHAPE_RECT rect( bbox.GetPosition(), bbox.GetWidth(), bbox.GetHeight() );
1135 rect.Collide( poss, collector.m_Threshold, &dist );
1136 }
1137
1138 if( dist == closestDist )
1139 {
1140 if( item->GetParent() == closest )
1141 closest = item;
1142 }
1143 else if( dist < closestDist )
1144 {
1145 closestDist = dist;
1146 closest = item;
1147 }
1148 }
1149
1150 // Construct a tight box (1/2 height and width) around the center of the closest item.
1151 // All items which exist at least partly outside this box have sufficient other areas
1152 // for selection and can be dropped.
1153 if( closest ) // Don't try and get a tight bbox if nothing is near the mouse pointer
1154 {
1155 BOX2I tightBox = closest->GetBoundingBox();
1156 tightBox.Inflate( -tightBox.GetWidth() / 4, -tightBox.GetHeight() / 4 );
1157
1158 for( int i = collector.GetCount() - 1; i >= 0; --i )
1159 {
1160 EDA_ITEM* item = collector[i];
1161
1162 if( item == closest )
1163 continue;
1164
1165 if( !item->HitTest( tightBox, true ) )
1166 collector.Transfer( item );
1167 }
1168 }
1169}
1170
1171
1172EE_SELECTION& EE_SELECTION_TOOL::RequestSelection( const std::vector<KICAD_T>& aScanTypes )
1173{
1174 if( m_selection.Empty() )
1175 {
1176 VECTOR2D cursorPos = getViewControls()->GetCursorPosition( true );
1177
1179 SelectPoint( cursorPos, aScanTypes );
1180 m_selection.SetIsHover( true );
1182 }
1183 else // Trim an existing selection by aFilterList
1184 {
1185 bool isMoving = false;
1186 bool anyUnselected = false;
1187
1188 for( int i = (int) m_selection.GetSize() - 1; i >= 0; --i )
1189 {
1190 EDA_ITEM* item = (EDA_ITEM*) m_selection.GetItem( i );
1191 isMoving |= static_cast<SCH_ITEM*>( item )->IsMoving();
1192
1193 if( !item->IsType( aScanTypes ) )
1194 {
1195 unselect( item );
1196 anyUnselected = true;
1197 }
1198 }
1199
1200 if( anyUnselected )
1202
1203 if( !isMoving )
1205 }
1206
1207 return m_selection;
1208}
1209
1210
1212{
1213 VECTOR2I refP( 0, 0 );
1214
1215 if( m_selection.Size() > 0 )
1216 {
1217 if( m_isSymbolEditor )
1218 refP = static_cast<LIB_ITEM*>( m_selection.GetTopLeftItem() )->GetPosition();
1219 else
1220 refP = static_cast<SCH_ITEM*>( m_selection.GetTopLeftItem() )->GetPosition();
1221 }
1222
1224}
1225
1226
1227// Some navigation actions are allowed in selectMultiple
1237 &ACTIONS::zoomFitObjects, nullptr };
1238
1239
1241{
1242 bool cancelled = false; // Was the tool canceled while it was running?
1243 m_multiple = true; // Multiple selection mode is active
1244 KIGFX::VIEW* view = getView();
1245
1247 view->Add( &area );
1248
1249 while( TOOL_EVENT* evt = Wait() )
1250 {
1251 int width = area.GetEnd().x - area.GetOrigin().x;
1252 int height = area.GetEnd().y - area.GetOrigin().y;
1253
1254 /* Selection mode depends on direction of drag-selection:
1255 * Left > Right : Select objects that are fully enclosed by selection
1256 * Right > Left : Select objects that are crossed by selection
1257 */
1258 bool isWindowSelection = width >= 0;
1259
1260 if( view->IsMirroredX() )
1261 isWindowSelection = !isWindowSelection;
1262
1265
1266 if( evt->IsCancelInteractive() || evt->IsActivate() )
1267 {
1268 cancelled = true;
1269 break;
1270 }
1271
1272 if( evt->IsDrag( BUT_LEFT ) )
1273 {
1276
1277 // Start drawing a selection box
1278 area.SetOrigin( evt->DragOrigin() );
1279 area.SetEnd( evt->Position() );
1282 area.SetExclusiveOr( false );
1283
1284 view->SetVisible( &area, true );
1285 view->Update( &area );
1286 getViewControls()->SetAutoPan( true );
1287 }
1288
1289 if( evt->IsMouseUp( BUT_LEFT ) )
1290 {
1291 getViewControls()->SetAutoPan( false );
1292
1293 // End drawing the selection box
1294 view->SetVisible( &area, false );
1295
1296 // Fetch items from the RTree that are in our area of interest
1297 std::vector<KIGFX::VIEW::LAYER_ITEM_PAIR> nearbyViewItems;
1298 view->Query( area.ViewBBox(), nearbyViewItems );
1299
1300 // Build lists of nearby items and their children
1301 std::unordered_set<EDA_ITEM*> nearbyItems;
1302 std::vector<EDA_ITEM*> nearbyChildren;
1303 std::vector<EDA_ITEM*> flaggedItems;
1304
1305 for( KIGFX::VIEW::LAYER_ITEM_PAIR& pair : nearbyViewItems )
1306 {
1307 if( EDA_ITEM* item = dynamic_cast<EDA_ITEM*>( pair.first ) )
1308 {
1309 if( nearbyItems.insert( item ).second )
1310 {
1311 item->ClearFlags( CANDIDATE );
1312
1313 if( SCH_ITEM* sch_item = dynamic_cast<SCH_ITEM*>( item ) )
1314 {
1315 sch_item->RunOnChildren(
1316 [&]( SCH_ITEM* aChild )
1317 {
1318 // Filter pins by unit
1319 if( SCH_PIN* pin = dyn_cast<SCH_PIN*>( aChild ) )
1320 {
1321 int unit = pin->GetLibPin()->GetUnit();
1322
1323 if( unit && unit != pin->GetParentSymbol()->GetUnit() )
1324 return;
1325 }
1326
1327 nearbyChildren.push_back( aChild );
1328 } );
1329 }
1330 }
1331 }
1332 }
1333
1334 BOX2I selectionRect( area.GetOrigin(), VECTOR2I( width, height ) );
1335 selectionRect.Normalize();
1336
1337 bool anyAdded = false;
1338 bool anySubtracted = false;
1339 auto selectItem = [&]( EDA_ITEM* aItem )
1340 {
1341 EDA_ITEM_FLAGS flags = 0;
1342
1343 // Handle line ends specially
1344 if( aItem->Type() == SCH_LINE_T )
1345 {
1346 SCH_LINE* line = (SCH_LINE*) aItem;
1347
1348 if( selectionRect.Contains( line->GetStartPoint() ) )
1349 flags |= STARTPOINT;
1350
1351 if( selectionRect.Contains( line->GetEndPoint() ) )
1352 flags |= ENDPOINT;
1353
1354
1355 // If no ends were selected, select whole line (both ends)
1356 // Also select both ends if the selection overlaps the midpoint
1357 if( ( !( flags & STARTPOINT ) && !( flags & ENDPOINT ) )
1358 || selectionRect.Contains( line->GetMidPoint() ) )
1359 {
1360 flags = STARTPOINT | ENDPOINT;
1361 }
1362 }
1363
1364 if( m_subtractive || ( m_exclusive_or && aItem->IsSelected() ) )
1365 {
1366 aItem->ClearFlags( flags );
1367
1368 if( !aItem->HasFlag( STARTPOINT ) && !aItem->HasFlag( ENDPOINT ) )
1369 {
1370 unselect( aItem );
1371 anySubtracted = true;
1372 }
1373 }
1374 else
1375 {
1376 aItem->SetFlags( flags );
1377 select( aItem );
1378 anyAdded = true;
1379 }
1380 };
1381
1382 for( EDA_ITEM* item : nearbyItems )
1383 {
1385 item->SetFlags( SHOW_ELEC_TYPE );
1386
1387 if( Selectable( item ) && item->HitTest( selectionRect, isWindowSelection ) )
1388 {
1389 item->SetFlags( CANDIDATE );
1390 flaggedItems.push_back( item );
1391 selectItem( item );
1392 }
1393
1394 item->ClearFlags( SHOW_ELEC_TYPE );
1395 }
1396
1397 for( EDA_ITEM* item : nearbyChildren )
1398 {
1400 item->SetFlags( SHOW_ELEC_TYPE );
1401
1402 if( Selectable( item )
1403 && !item->GetParent()->HasFlag( CANDIDATE )
1404 && item->HitTest( selectionRect, isWindowSelection ) )
1405 {
1406 selectItem( item );
1407 }
1408
1409 item->ClearFlags( SHOW_ELEC_TYPE );
1410 }
1411
1412 for( EDA_ITEM* item : flaggedItems )
1413 item->ClearFlags( CANDIDATE );
1414
1415 m_selection.SetIsHover( false );
1416
1417 // Inform other potentially interested tools
1418 if( anyAdded )
1420
1421 if( anySubtracted )
1423
1424 break; // Stop waiting for events
1425 }
1426
1427 // Allow some actions for navigation
1428 for( int i = 0; allowedActions[i]; ++i )
1429 {
1430 if( evt->IsAction( allowedActions[i] ) )
1431 {
1432 evt->SetPassEvent();
1433 break;
1434 }
1435 }
1436 }
1437
1438 getViewControls()->SetAutoPan( false );
1439
1440 // Stop drawing the selection box
1441 view->Remove( &area );
1442 m_multiple = false; // Multiple selection mode is inactive
1443
1444 if( !cancelled )
1446
1447 return cancelled;
1448}
1449
1450
1452{
1453 EE_COLLECTOR collector;
1454
1455 //TODO(snh): Reimplement after exposing KNN interface
1456 int pixelThreshold = KiROUND( getView()->ToWorld( HITTEST_THRESHOLD_PIXELS ) );
1457 int gridThreshold = KiROUND( getView()->GetGAL()->GetGridSize().EuclideanNorm() );
1458 int thresholdMax = std::max( pixelThreshold, gridThreshold );
1459
1460 for( int threshold : { 0, thresholdMax/4, thresholdMax/2, thresholdMax } )
1461 {
1462 collector.m_Threshold = threshold;
1463 collector.Collect( m_frame->GetScreen(), connectedTypes, aPosition );
1464
1465 if( collector.GetCount() > 0 )
1466 break;
1467 }
1468
1469 return collector.GetCount() ? collector[ 0 ] : nullptr;
1470}
1471
1472
1474{
1475 VECTOR2I cursorPos = getViewControls()->GetCursorPosition( false );
1476
1477 SelectPoint( cursorPos, connectedTypes );
1478
1479 return 0;
1480}
1481
1482
1484{
1486
1487 if( m_selection.Empty() )
1488 return 0;
1489
1490 SCH_LINE* line = (SCH_LINE*) m_selection.Front();
1491 unsigned done = false;
1492
1494 std::set<SCH_ITEM*> conns = m_frame->GetScreen()->MarkConnections( line, false );
1495
1496 for( SCH_ITEM* item : conns )
1497 {
1498 if( item->IsType( { SCH_ITEM_LOCATE_WIRE_T, SCH_ITEM_LOCATE_BUS_T } )
1499 && !item->IsSelected() )
1500 {
1501 done = true;
1502 }
1503
1504 select( item );
1505 }
1506
1507 if( !done )
1508 {
1509 conns = m_frame->GetScreen()->MarkConnections( line, true );
1510
1511 for( SCH_ITEM* item : conns )
1512 select( item );
1513 }
1514
1515 if( m_selection.GetSize() > 1 )
1517
1518 return 0;
1519}
1520
1521
1523{
1525
1526 return 0;
1527}
1528
1529
1531{
1532 if( aBBox.GetWidth() == 0 )
1533 return;
1534
1535 BOX2I bbox = aBBox;
1536 bbox.Normalize();
1537
1538 VECTOR2I bbSize = bbox.Inflate( bbox.GetWidth() * 0.2f ).GetSize();
1539 VECTOR2D screenSize = getView()->GetViewport().GetSize();
1540
1541 // This code tries to come up with a zoom factor that doesn't simply zoom in
1542 // to the cross probed symbol, but instead shows a reasonable amount of the
1543 // circuit around it to provide context. This reduces or eliminates the need
1544 // to manually change the zoom because it's too close.
1545
1546 // Using the default text height as a constant to compare against, use the
1547 // height of the bounding box of visible items for a footprint to figure out
1548 // if this is a big symbol (like a processor) or a small symbol (like a resistor).
1549 // This ratio is not useful by itself as a scaling factor. It must be "bent" to
1550 // provide good scaling at varying symbol sizes. Bigger symbols need less
1551 // scaling than small ones.
1552 double currTextHeight = schIUScale.MilsToIU( DEFAULT_TEXT_SIZE );
1553
1554 double compRatio = bbSize.y / currTextHeight; // Ratio of symbol to text height
1555 double compRatioBent = 1.0;
1556
1557 // LUT to scale zoom ratio to provide reasonable schematic context. Must work
1558 // with symbols of varying sizes (e.g. 0402 package and 200 pin BGA).
1559 // "first" is used as the input and "second" as the output
1560 //
1561 // "first" = compRatio (symbol height / default text height)
1562 // "second" = Amount to scale ratio by
1563 std::vector<std::pair<double, double>> lut{ { 1.25, 16 }, // 32
1564 { 2.5, 12 }, //24
1565 { 5, 8 }, // 16
1566 { 6, 6 }, //
1567 { 10, 4 }, //8
1568 { 20, 2 }, //4
1569 { 40, 1.5 }, // 2
1570 { 100, 1 } };
1571
1572 std::vector<std::pair<double, double>>::iterator it;
1573
1574 // Large symbol default is last LUT entry (1:1).
1575 compRatioBent = lut.back().second;
1576
1577 // Use LUT to do linear interpolation of "compRatio" within "first", then
1578 // use that result to linearly interpolate "second" which gives the scaling
1579 // factor needed.
1580 if( compRatio >= lut.front().first )
1581 {
1582 for( it = lut.begin(); it < lut.end() - 1; it++ )
1583 {
1584 if( it->first <= compRatio && next( it )->first >= compRatio )
1585 {
1586 double diffx = compRatio - it->first;
1587 double diffn = next( it )->first - it->first;
1588
1589 compRatioBent = it->second + ( next( it )->second - it->second ) * diffx / diffn;
1590 break; // We have our interpolated value
1591 }
1592 }
1593 }
1594 else
1595 {
1596 compRatioBent = lut.front().second; // Small symbol default is first entry
1597 }
1598
1599 // This is similar to the original KiCad code that scaled the zoom to make sure
1600 // symbols were visible on screen. It's simply a ratio of screen size to
1601 // symbol size, and its job is to zoom in to make the component fullscreen.
1602 // Earlier in the code the symbol BBox is given a 20% margin to add some
1603 // breathing room. We compare the height of this enlarged symbol bbox to the
1604 // default text height. If a symbol will end up with the sides clipped, we
1605 // adjust later to make sure it fits on screen.
1606 screenSize.x = std::max( 10.0, screenSize.x );
1607 screenSize.y = std::max( 10.0, screenSize.y );
1608 double ratio = std::max( -1.0, fabs( bbSize.y / screenSize.y ) );
1609
1610 // Original KiCad code for how much to scale the zoom
1611 double kicadRatio =
1612 std::max( fabs( bbSize.x / screenSize.x ), fabs( bbSize.y / screenSize.y ) );
1613
1614 // If the width of the part we're probing is bigger than what the screen width
1615 // will be after the zoom, then punt and use the KiCad zoom algorithm since it
1616 // guarantees the part's width will be encompassed within the screen.
1617 if( bbSize.x > screenSize.x * ratio * compRatioBent )
1618 {
1619 // Use standard KiCad zoom for parts too wide to fit on screen/
1620 ratio = kicadRatio;
1621 compRatioBent = 1.0; // Reset so we don't modify the "KiCad" ratio
1622 wxLogTrace( "CROSS_PROBE_SCALE",
1623 "Part TOO WIDE for screen. Using normal KiCad zoom ratio: %1.5f", ratio );
1624 }
1625
1626 // Now that "compRatioBent" holds our final scaling factor we apply it to the
1627 // original fullscreen zoom ratio to arrive at the final ratio itself.
1628 ratio *= compRatioBent;
1629
1630 bool alwaysZoom = false; // DEBUG - allows us to minimize zooming or not
1631
1632 // Try not to zoom on every cross-probe; it gets very noisy
1633 if( ( ratio < 0.5 || ratio > 1.0 ) || alwaysZoom )
1634 getView()->SetScale( getView()->GetScale() / ratio );
1635}
1636
1637
1638int EE_SELECTION_TOOL::SyncSelection( std::optional<SCH_SHEET_PATH> targetSheetPath,
1639 SCH_ITEM* focusItem, std::vector<SCH_ITEM*> items )
1640{
1641 SCH_EDIT_FRAME* editFrame = dynamic_cast<SCH_EDIT_FRAME*>( m_frame );
1642
1643 if( !editFrame || m_isSymbolEditor || m_isSymbolViewer )
1644 return 0;
1645
1646 if( targetSheetPath && targetSheetPath != editFrame->Schematic().CurrentSheet() )
1647 {
1648 editFrame->Schematic().SetCurrentSheet( *targetSheetPath );
1649 editFrame->DisplayCurrentSheet();
1650 }
1651
1652 ClearSelection( items.size() > 0 ? true /*quiet mode*/ : false );
1653
1654 // Perform individual selection of each item before processing the event.
1655 for( SCH_ITEM* item : items )
1656 select( item );
1657
1659
1660 if( bbox.GetWidth() != 0 && bbox.GetHeight() != 0 )
1661 {
1663 {
1665 ZoomFitCrossProbeBBox( bbox );
1666
1667 editFrame->FocusOnItem( focusItem );
1668
1669 if( !focusItem )
1670 editFrame->FocusOnLocation( bbox.Centre() );
1671 }
1672 }
1673
1674 if( m_selection.Size() > 0 )
1676
1677 return 0;
1678}
1679
1680
1682{
1684
1685 if( m_isSymbolEditor )
1686 {
1687 LIB_SYMBOL* start = static_cast<SYMBOL_EDIT_FRAME*>( m_frame )->GetCurSymbol();
1688
1689 for( LIB_ITEM& item : start->GetDrawItems() )
1690 {
1691 if( item.IsSelected() )
1692 select( &item );
1693 }
1694 }
1695 else
1696 {
1697 for( SCH_ITEM* item : m_frame->GetScreen()->Items() )
1698 {
1699 // If the field and symbol are selected, only use the symbol
1700 if( item->IsSelected() )
1701 {
1702 select( item );
1703 }
1704 else
1705 {
1706 item->RunOnChildren(
1707 [&]( SCH_ITEM* aChild )
1708 {
1709 if( aChild->IsSelected() )
1710 select( aChild );
1711 } );
1712 }
1713 }
1714 }
1715
1717
1718 // Inform other potentially interested tools
1720}
1721
1722
1723bool EE_SELECTION_TOOL::Selectable( const EDA_ITEM* aItem, const VECTOR2I* aPos,
1724 bool checkVisibilityOnly ) const
1725{
1726 // NOTE: in the future this is where Eeschema layer/itemtype visibility will be handled
1727
1728 SYMBOL_EDIT_FRAME* symEditFrame = dynamic_cast<SYMBOL_EDIT_FRAME*>( m_frame );
1729
1730 // Do not allow selection of anything except fields when the current symbol in the symbol
1731 // editor is a derived symbol.
1732 if( symEditFrame && symEditFrame->IsSymbolAlias() && aItem->Type() != LIB_FIELD_T )
1733 return false;
1734
1735 switch( aItem->Type() )
1736 {
1737 case SCH_PIN_T:
1738 {
1739 const SCH_PIN* pin = static_cast<const SCH_PIN*>( aItem );
1740
1741 if( !pin->IsVisible() && !m_frame->GetShowAllPins() )
1742 return false;
1743
1745 {
1746 // Pin anchors have to be allowed for auto-starting wires.
1747 if( aPos )
1748 {
1750
1751 if( pin->IsPointClickableAnchor( grid.BestSnapAnchor( *aPos, LAYER_CONNECTABLE ) ) )
1752 return true;
1753 }
1754
1755 return false;
1756 }
1757
1758 break;
1759 }
1760
1761 case LIB_SYMBOL_T: // In symbol_editor we do not want to select the symbol itself.
1762 return false;
1763
1764 case LIB_FIELD_T: // LIB_FIELD object can always be edited.
1765 break;
1766
1767 case LIB_SHAPE_T:
1768 case LIB_TEXT_T:
1769 case LIB_PIN_T:
1770 if( symEditFrame )
1771 {
1772 LIB_ITEM* lib_item = (LIB_ITEM*) aItem;
1773
1774 if( lib_item->GetUnit() && lib_item->GetUnit() != symEditFrame->GetUnit() )
1775 return false;
1776
1777 if( lib_item->GetConvert() && lib_item->GetConvert() != symEditFrame->GetConvert() )
1778 return false;
1779 }
1780
1781 break;
1782
1783 case SCH_MARKER_T: // Always selectable
1784 return true;
1785
1786 default: // Suppress warnings
1787 break;
1788 }
1789
1790 return true;
1791}
1792
1793
1795{
1796 if( m_selection.Empty() )
1797 return;
1798
1799 while( m_selection.GetSize() )
1801
1802 getView()->Update( &m_selection );
1803
1804 m_selection.SetIsHover( false );
1806
1807 // Inform other potentially interested tools
1808 if( !aQuietMode )
1809 {
1811 }
1812}
1813
1814
1816{
1817 highlight( aItem, SELECTED, &m_selection );
1818}
1819
1820
1822{
1823 unhighlight( aItem, SELECTED, &m_selection );
1824}
1825
1826
1827void EE_SELECTION_TOOL::highlight( EDA_ITEM* aItem, int aMode, SELECTION* aGroup )
1828{
1829 KICAD_T itemType = aItem->Type();
1830
1831 if( aMode == SELECTED )
1832 aItem->SetSelected();
1833 else if( aMode == BRIGHTENED )
1834 aItem->SetBrightened();
1835
1836 if( aGroup )
1837 aGroup->Add( aItem );
1838
1839 // Highlight pins and fields. (All the other symbol children are currently only
1840 // represented in the LIB_SYMBOL and will inherit the settings of the parent symbol.)
1841 if( SCH_ITEM* sch_item = dynamic_cast<SCH_ITEM*>( aItem ) )
1842 {
1843 sch_item->RunOnChildren(
1844 [&]( SCH_ITEM* aChild )
1845 {
1846 if( aMode == SELECTED )
1847 aChild->SetSelected();
1848 else if( aMode == BRIGHTENED )
1849 aChild->SetBrightened();
1850 } );
1851 }
1852
1853 if( itemType == SCH_PIN_T || itemType == SCH_FIELD_T || itemType == SCH_SHEET_PIN_T )
1854 getView()->Update( aItem->GetParent() );
1855 else
1856 getView()->Update( aItem );
1857}
1858
1859
1860void EE_SELECTION_TOOL::unhighlight( EDA_ITEM* aItem, int aMode, SELECTION* aGroup )
1861{
1862 KICAD_T itemType = aItem->Type();
1863
1864 if( aMode == SELECTED )
1865 {
1866 aItem->ClearSelected();
1867 // Lines need endpoints cleared here
1868 if( aItem->Type() == SCH_LINE_T )
1869 aItem->ClearFlags( STARTPOINT | ENDPOINT );
1870 }
1871 else if( aMode == BRIGHTENED )
1872 aItem->ClearBrightened();
1873
1874 if( aGroup )
1875 aGroup->Remove( aItem );
1876
1877 // Unhighlight pins and fields. (All the other symbol children are currently only
1878 // represented in the LIB_SYMBOL.)
1879 if( SCH_ITEM* sch_item = dynamic_cast<SCH_ITEM*>( aItem ) )
1880 {
1881 sch_item->RunOnChildren(
1882 [&]( SCH_ITEM* aChild )
1883 {
1884 if( aMode == SELECTED )
1885 aChild->ClearSelected();
1886 else if( aMode == BRIGHTENED )
1887 aChild->ClearBrightened();
1888 } );
1889 }
1890
1891 if( itemType == SCH_PIN_T || itemType == SCH_FIELD_T || itemType == SCH_SHEET_PIN_T )
1892 getView()->Update( aItem->GetParent() );
1893 else
1894 getView()->Update( aItem );
1895}
1896
1897
1899{
1900 const unsigned GRIP_MARGIN = 20;
1901 VECTOR2I margin = getView()->ToWorld( VECTOR2I( GRIP_MARGIN, GRIP_MARGIN ), false );
1902
1903 // Check if the point is located within any of the currently selected items bounding boxes
1904 for( EDA_ITEM* item : m_selection )
1905 {
1906 BOX2I itemBox = item->ViewBBox();
1907 itemBox.Inflate( margin.x, margin.y ); // Give some margin for gripping an item
1908
1909 if( itemBox.Contains( aPoint ) )
1910 return true;
1911 }
1912
1913 return false;
1914}
1915
1916
1918{
1920
1925
1931
1933
1935}
1936
1937
VECTOR2D mapCoords(const VECTOR2D &aSource)
Definition: PS_plotter.cpp:568
constexpr EDA_IU_SCALE schIUScale
Definition: base_units.h:111
static TOOL_ACTION cursorLeft
Definition: actions.h:118
static TOOL_ACTION zoomOutCenter
Definition: actions.h:96
static TOOL_ACTION zoomIn
Definition: actions.h:93
static TOOL_ACTION cursorLeftFast
Definition: actions.h:123
static TOOL_ACTION cursorDown
Definition: actions.h:117
static TOOL_ACTION zoomOut
Definition: actions.h:94
static TOOL_ACTION cursorRightFast
Definition: actions.h:124
static TOOL_ACTION zoomCenter
Definition: actions.h:97
static TOOL_ACTION panDown
Definition: actions.h:131
static TOOL_ACTION cursorDownFast
Definition: actions.h:122
static TOOL_ACTION cursorUpFast
Definition: actions.h:121
static TOOL_ACTION panLeft
Definition: actions.h:132
static TOOL_ACTION updateMenu
Definition: actions.h:170
static TOOL_ACTION zoomFitScreen
Definition: actions.h:98
static TOOL_ACTION panUp
Definition: actions.h:130
static TOOL_ACTION zoomFitObjects
Definition: actions.h:99
static TOOL_ACTION zoomInCenter
Definition: actions.h:95
static TOOL_ACTION panRight
Definition: actions.h:133
static TOOL_ACTION cursorUp
Cursor control with keyboard.
Definition: actions.h:116
static TOOL_ACTION cursorRight
Definition: actions.h:119
static TOOL_ACTION selectAll
Definition: actions.h:71
CROSS_PROBING_SETTINGS m_CrossProbing
Definition: app_settings.h:170
BOX2< Vec > & Normalize()
Ensure that the height and width are positive.
Definition: box2.h:119
const Vec & GetPosition() const
Definition: box2.h:184
void SetMaximum()
Definition: box2.h:63
const Vec GetCenter() const
Definition: box2.h:195
coord_type GetHeight() const
Definition: box2.h:188
coord_type GetWidth() const
Definition: box2.h:187
bool Contains(const Vec &aPoint) const
Definition: box2.h:141
BOX2< Vec > & Inflate(coord_type dx, coord_type dy)
Inflates the rectangle horizontally by dx and vertically by dy.
Definition: box2.h:506
Vec Centre() const
Definition: box2.h:70
const Vec & GetSize() const
Definition: box2.h:179
void Transfer(int aIndex)
Move the item at aIndex (first position is 0) to the backup list.
Definition: collector.h:151
bool m_MenuCancelled
Definition: collector.h:237
int GetCount() const
Return the number of objects in the list.
Definition: collector.h:81
bool HasItem(const EDA_ITEM *aItem) const
Tests if aItem has already been collected.
Definition: collector.h:195
void Remove(int aIndex)
Remove the item at aIndex (first position is 0).
Definition: collector.h:109
int m_Threshold
Definition: collector.h:234
void Append(EDA_ITEM *item)
Add an item to the end of the list.
Definition: collector.h:99
void AddItem(const TOOL_ACTION &aAction, const SELECTION_CONDITION &aCondition, int aOrder=ANY_ORDER)
Add a menu entry to run a TOOL_ACTION on selected items.
void AddStandardSubMenus(TOOL_MENU &aMenu)
Construct a "basic" menu for a tool, containing only items that apply to all tools (e....
void FocusOnLocation(const VECTOR2I &aPos)
Useful to focus on a particular location, in find functions.
virtual EDA_ITEM * GetItem(const KIID &aId) const
Fetch an item by KIID.
void SetCurrentCursor(KICURSOR aCursor)
Set the current cursor shape for this panel.
A base class for most all the KiCad significant classes used in schematics and boards.
Definition: eda_item.h:85
virtual const BOX2I GetBoundingBox() const
Return the orthogonal bounding box of this object for display purposes.
Definition: eda_item.cpp:74
void SetFlags(EDA_ITEM_FLAGS aMask)
Definition: eda_item.h:142
KICAD_T Type() const
Returns the type of object.
Definition: eda_item.h:97
void ClearSelected()
Definition: eda_item.h:121
void ClearFlags(EDA_ITEM_FLAGS aMask=EDA_ITEM_ALL_FLAGS)
Definition: eda_item.h:143
bool IsSelected() const
Definition: eda_item.h:107
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:183
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:222
EDA_ITEM * GetParent() const
Definition: eda_item.h:99
SHAPE_T GetShape() const
Definition: eda_shape.h:111
A mix-in class (via multiple inheritance) that handles texts such as labels, parts,...
Definition: eda_text.h:72
static TOOL_ACTION selectionActivate
Activation of the selection tool.
Definition: ee_actions.h:46
static TOOL_ACTION properties
Definition: ee_actions.h:131
static TOOL_ACTION addItemsToSel
Selects a list of items (specified as the event parameter)
Definition: ee_actions.h:63
static TOOL_ACTION clearHighlight
Definition: ee_actions.h:253
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:158
static TOOL_ACTION navigateForward
Definition: ee_actions.h:204
static TOOL_ACTION assignNetclass
Definition: ee_actions.h:164
static TOOL_ACTION clearSelection
Clears the current selection.
Definition: ee_actions.h:56
static TOOL_ACTION navigateBack
Definition: ee_actions.h:205
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:90
static TOOL_ACTION drawWire
Definition: ee_actions.h:83
static TOOL_ACTION removeItemsFromSel
Definition: ee_actions.h:64
static TOOL_ACTION drawBus
Definition: ee_actions.h:84
static TOOL_ACTION finishWire
Definition: ee_actions.h:106
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:146
static TOOL_ACTION drawLines
Definition: ee_actions.h:101
static TOOL_ACTION selectOnPCB
Definition: ee_actions.h:223
static TOOL_ACTION leaveSheet
Definition: ee_actions.h:202
static TOOL_ACTION placeGlobalLabel
Definition: ee_actions.h:91
static TOOL_ACTION removeItemFromSel
Definition: ee_actions.h:60
static TOOL_ACTION placeHierLabel
Definition: ee_actions.h:92
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:157
static TOOL_ACTION editPageNumber
Definition: ee_actions.h:166
static TOOL_ACTION enterSheet
Definition: ee_actions.h:201
static TOOL_ACTION setUnitDisplayName
Definition: ee_actions.h:197
static TOOL_ACTION importSingleSheetPin
Definition: ee_actions.h:94
static TOOL_ACTION unfoldBus
Definition: ee_actions.h:85
static TOOL_ACTION placeLabel
Definition: ee_actions.h:89
static TOOL_ACTION placeJunction
Definition: ee_actions.h:87
static TOOL_ACTION breakBus
Definition: ee_actions.h:147
static TOOL_ACTION finishBus
Definition: ee_actions.h:107
bool m_ShowPinElectricalTypes
static const std::vector< KICAD_T > MovableItems
Definition: ee_collectors.h:43
void Collect(SCH_SCREEN *aScreen, const std::vector< KICAD_T > &aScanTypes, const VECTOR2I &aPos, int aUnit=0, int aConvert=0)
Scan a EDA_ITEM using this class's Inspector method which does the collection.
static SELECTION_CONDITION SingleSymbol
static SELECTION_CONDITION SingleSymbolOrPower
static SELECTION_CONDITION SingleMultiUnitSymbol
static SELECTION_CONDITION SingleNonExcludedMarker
static SELECTION_CONDITION SingleDeMorganSymbol
VECTOR2I BestSnapAnchor(const VECTOR2I &aOrigin, int aLayer, SCH_ITEM *aDraggedItem)
Tool that displays edit points allowing to modify items by dragging the points.
bool HasPoint()
Indicate the cursor is over an edit point.
bool Selectable(const EDA_ITEM *aItem, const VECTOR2I *aPos=nullptr, bool checkVisibilityOnly=false) const
Check conditions for an item to be selected.
void GuessSelectionCandidates(EE_COLLECTOR &collector, const VECTOR2I &aPos)
Apply heuristics to try and determine a single object when multiple are found under the cursor.
bool selectMultiple()
Handle drawing a selection box that allows one to select many items at the same time.
bool selectionContains(const VECTOR2I &aPoint) const
Set up handlers for various events.
void unhighlight(EDA_ITEM *aItem, int aHighlightMode, SELECTION *aGroup=nullptr) override
Unhighlight the item visually.
EE_SELECTION m_selection
void unselect(EDA_ITEM *aItem) override
Take necessary action to mark an item as unselected.
int SelectConnection(const TOOL_EVENT &aEvent)
If a connected item is selected then expand the selection to the entire connection,...
bool CollectHits(EE_COLLECTOR &aCollector, const VECTOR2I &aWhere, const std::vector< KICAD_T > &aScanTypes={ SCH_LOCATE_ANY_T })
Collect one or more items at a given point.
void setTransitions() override
This method is meant to be overridden in order to specify handlers for events.
bool selectPoint(EE_COLLECTOR &aCollector, const VECTOR2I &aWhere, EDA_ITEM **aItem=nullptr, bool *aSelectionCancelledFlag=nullptr, bool aAdd=false, bool aSubtract=false, bool aExclusiveOr=false)
Perform a click-type selection at a point (usually the cursor position).
int SelectAll(const TOOL_EVENT &aEvent)
EE_SELECTION & RequestSelection(const std::vector< KICAD_T > &aScanTypes={ SCH_LOCATE_ANY_T })
Return either an existing selection (filtered), or the selection at the current cursor position if th...
void ZoomFitCrossProbeBBox(const BOX2I &aBBox)
bool SelectPoint(const VECTOR2I &aWhere, const std::vector< KICAD_T > &aScanTypes={ SCH_LOCATE_ANY_T }, EDA_ITEM **aItem=nullptr, bool *aSelectionCancelledFlag=nullptr, bool aCheckLocked=false, bool aAdd=false, bool aSubtract=false, bool aExclusiveOr=false)
Perform a click-type selection at a point (usually the cursor position).
int Main(const TOOL_EVENT &aEvent)
The main loop.
int disambiguateCursor(const TOOL_EVENT &aEvent)
Handle disambiguation actions including displaying the menu.
int SelectNode(const TOOL_EVENT &aEvent)
Selects the connected item at the current cursor position.
bool Init() override
Init() is called once upon a registration of the tool.
int ClearSelection(const TOOL_EVENT &aEvent)
Select all visible items in sheet.
OPT_TOOL_EVENT autostartEvent(TOOL_EVENT *aEvent, EE_GRID_HELPER &aGrid, SCH_ITEM *aItem)
int SyncSelection(std::optional< SCH_SHEET_PATH > targetSheetPath, SCH_ITEM *focusItem, std::vector< SCH_ITEM * > items)
void RebuildSelection()
Rebuild the selection from the EDA_ITEMs' selection flags.
void OnIdle(wxIdleEvent &aEvent)
Zoom the screen to fit the bounding box for cross probing/selection sync.
SCH_BASE_FRAME * m_frame
void narrowSelection(EE_COLLECTOR &collector, const VECTOR2I &aWhere, bool aCheckLocked, bool aSelectedOnly=false)
Apply rules to narrow the collection down to selectable objects, and then heuristics to try and narro...
void highlight(EDA_ITEM *aItem, int aHighlightMode, SELECTION *aGroup=nullptr) override
Highlight the item visually.
void Reset(RESET_REASON aReason) override
Bring the tool to a known, initial state.
void select(EDA_ITEM *aItem) override
Take necessary action to mark an item as selected.
EDA_ITEM * GetNode(VECTOR2I aPosition)
Finds a connected item at a point (usually the cursor position).
EE_SELECTION & GetSelection()
void updateReferencePoint()
Set the reference point to the anchor of the top-left item.
BOX2I GetBoundingBox() const override
EDA_ITEM * GetTopLeftItem(bool onlyModules=false) const override
static const TOOL_EVENT DisambiguatePoint
Definition: actions.h:220
static const TOOL_EVENT ClearedEvent
Selected item had a property changed (except movement)
Definition: actions.h:207
static const TOOL_EVENT SelectedEvent
Definition: actions.h:205
static const TOOL_EVENT PointSelectedEvent
Definition: actions.h:204
static const TOOL_EVENT UnselectedEvent
Definition: actions.h:206
virtual RENDER_SETTINGS * GetSettings()=0
Return a pointer to current settings that are going to be used when drawing items.
Represent a selection area (currently a rectangle) in a VIEW, drawn corner-to-corner between two poin...
void SetSubtractive(bool aSubtractive)
void SetAdditive(bool aAdditive)
void SetOrigin(const VECTOR2I &aOrigin)
const BOX2I ViewBBox() const override
Set the origin of the rectangle (the fixed corner)
void SetExclusiveOr(bool aExclusiveOr)
void SetEnd(const VECTOR2I &aEnd)
Set the current end of the rectangle (the corner that moves with the cursor.
void SetHighlight(bool aEnabled, int aNetcode=-1, bool aMulti=false)
Turns on/off highlighting.
virtual void ForceCursorPosition(bool aEnabled, const VECTOR2D &aPosition=VECTOR2D(0, 0))
Place the cursor immediately at a given point.
VECTOR2D GetCursorPosition() const
Return the current cursor position in world coordinates.
virtual void SetAutoPan(bool aEnabled)
Turn on/off auto panning (this feature is used when there is a tool active (eg.
Hold a (potentially large) number of VIEW_ITEMs and renders them on a graphics device provided by the...
Definition: view.h:69
BOX2D GetViewport() const
Return the current viewport visible area rectangle.
Definition: view.cpp:508
virtual void SetScale(double aScale, VECTOR2D aAnchor={ 0, 0 })
Set the scaling factor, zooming around a given anchor point.
Definition: view.cpp:548
virtual void Add(VIEW_ITEM *aItem, int aDrawPriority=-1)
Add a VIEW_ITEM to the view.
Definition: view.cpp:316
virtual void Remove(VIEW_ITEM *aItem)
Remove a VIEW_ITEM from the view.
Definition: view.cpp:346
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:422
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:1574
VECTOR2D ToWorld(const VECTOR2D &aCoord, bool aAbsolute=true) const
Converts a screen space point/vector to a point/vector in world space coordinates.
Definition: view.cpp:445
bool IsMirroredX() const
Return true if view is flipped across the X axis.
Definition: view.h:243
std::pair< VIEW_ITEM *, int > LAYER_ITEM_PAIR
Definition: view.h:73
PAINTER * GetPainter() const
Return the painter object used by the view for drawing #VIEW_ITEMS.
Definition: view.h:213
void SetVisible(VIEW_ITEM *aItem, bool aIsVisible=true)
Set the item visibility.
Definition: view.cpp:1512
Definition: kiid.h:47
The base class for drawable items used by schematic library symbols.
Definition: lib_item.h:61
int GetUnit() const
Definition: lib_item.h:273
int GetConvert() const
Definition: lib_item.h:276
Define a library symbol object.
Definition: lib_symbol.h:98
bool IsMulti() const
Definition: lib_symbol.h:556
LIB_ITEMS_CONTAINER & GetDrawItems()
Return a reference to the draw item list.
Definition: lib_symbol.h:507
SCH_SHEET_PATH & CurrentSheet() const override
Definition: schematic.h:119
void SetCurrentSheet(const SCH_SHEET_PATH &aPath) override
Definition: schematic.h:124
SCH_SHEET & Root() const
Definition: schematic.h:90
SCH_SCREEN * GetScreen() const override
Return a pointer to a BASE_SCREEN or one of its derivatives.
SCH_DRAW_PANEL * GetCanvas() const override
Return a pointer to GAL-based canvas of given EDA draw frame.
EESCHEMA_SETTINGS * eeconfig() const
KIGFX::SCH_RENDER_SETTINGS * GetRenderSettings()
virtual bool GetShowAllPins() const
Allow some frames to show/hide hidden pins.
Class for a wire to bus entry.
SCH_ITEM * m_connected_bus_item
Pointer to the bus item (usually a bus wire) connected to this bus-wire entry, if it is connected to ...
KIGFX::SCH_VIEW * GetView() const override
Return a pointer to the #VIEW instance used in the panel.
Handle actions specific to the schematic editor.
Schematic editor (Eeschema) main window.
const SCH_CONNECTION * GetHighlightedConnection() const
SCH_SHEET_PATH & GetCurrentSheet() const
SCHEMATIC & Schematic() const
void DisplayCurrentSheet()
Draw the current sheet on the display.
void FocusOnItem(SCH_ITEM *aItem)
Base class for any item which can be embedded within the SCHEMATIC container class,...
Definition: sch_item.h:147
virtual bool IsPointClickableAnchor(const VECTOR2I &aPos) const
Definition: sch_item.h:346
static bool IsDrawingWire(const SELECTION &aSelection)
static bool IsDrawingBus(const SELECTION &aSelection)
Segment description base class to describe items which have 2 end points (track, wire,...
Definition: sch_line.h:40
VECTOR2I GetMidPoint() const
Definition: sch_line.h:135
VECTOR2I GetEndPoint() const
Definition: sch_line.h:137
VECTOR2I GetStartPoint() const
Definition: sch_line.h:132
bool IsBus() const
Return true if the line is a bus.
Definition: sch_line.cpp:932
bool IsGraphicLine() const
Return if the line is a graphic (non electrical line)
Definition: sch_line.cpp:920
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:108
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:351
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:55
std::vector< SCH_SHEET_PIN * > & GetPins()
Definition: sch_sheet.h:172
Schematic symbol object.
Definition: sch_symbol.h:79
BOX2I GetBodyAndPinsBoundingBox() const
Return a bounding box for the symbol body and pins but not the fields.
std::unique_ptr< LIB_SYMBOL > & GetLibSymbolRef()
Definition: sch_symbol.h:189
BOX2I GetBodyBoundingBox() const
Return a bounding box for the symbol body but not the pins or fields.
Definition: seg.h:42
static SELECTION_CONDITION HasTypes(std::vector< KICAD_T > aTypes)
Create a functor that tests if among the selected items there is at least one of a given types.
static bool Empty(const SELECTION &aSelection)
Test if there are no items selected.
static SELECTION_CONDITION MoreThan(int aNumber)
Create a functor that tests if the number of selected items is greater than the value given as parame...
static bool Idle(const SELECTION &aSelection)
Test if there no items selected or being edited.
static SELECTION_CONDITION LessThan(int aNumber)
Create a functor that tests if the number of selected items is smaller than the value given as parame...
static SELECTION_CONDITION Count(int aNumber)
Create a functor that tests if the number of selected items is equal to the value given as parameter.
static SELECTION_CONDITION OnlyTypes(std::vector< KICAD_T > aTypes)
Create a functor that tests if the selected items are only of given types.
int RemoveItemFromSel(const TOOL_EVENT &aEvent)
bool doSelectionMenu(COLLECTOR *aCollector)
wxTimer m_disambiguateTimer
int AddItemsToSel(const TOOL_EVENT &aEvent)
int AddItemToSel(const TOOL_EVENT &aEvent)
int UpdateMenu(const TOOL_EVENT &aEvent)
Update a menu's state based on the current selection.
void setModifiersState(bool aShiftState, bool aCtrlState, bool aAltState)
Set the configuration of m_additive, m_subtractive, m_exclusive_or, m_skip_heuristics from the state ...
VECTOR2I m_originalCursor
int SelectionMenu(const TOOL_EVENT &aEvent)
Show a popup menu to trim the COLLECTOR passed as aEvent's parameter down to a single item.
int RemoveItemsFromSel(const TOOL_EVENT &aEvent)
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:32
virtual KIGFX::VIEW_ITEM * GetItem(unsigned int aIdx) const override
Definition: selection.cpp:65
void SetIsHover(bool aIsHover)
Definition: selection.h:76
virtual void Remove(EDA_ITEM *aItem)
Definition: selection.cpp:50
virtual unsigned int GetSize() const override
Return the number of stored items.
Definition: selection.h:97
EDA_ITEM * Front() const
Definition: selection.h:200
virtual void Clear() override
Remove all the stored items from the group.
Definition: selection.h:90
int Size() const
Returns the number of selected parts.
Definition: selection.h:113
void ClearReferencePoint()
Definition: selection.h:257
void SetReferencePoint(const VECTOR2I &aP)
Definition: selection.h:252
bool Empty() const
Checks if there is anything selected.
Definition: selection.h:107
bool Collide(const SHAPE *aShape, int aClearance, VECTOR2I *aMTV) const override
Check if the boundary of shape (this) lies closer to the shape aShape than aClearance,...
Definition: shape_rect.h:109
The symbol library editor main window.
bool IsSymbolAlias() const
Return true if aLibId is an alias for the editor screen symbol.
bool IsSymbolEditable() const
Test if a symbol is loaded and can be edited.
LIB_SYMBOL * GetCurSymbol() const
Return the current symbol being edited or NULL if none selected.
Symbol library viewer main window.
MOUSE_DRAG_ACTION GetDragAction() const
Indicates whether a drag should draw a selection rectangle or drag selected (or unselected) objects.
Definition: tools_holder.h:147
bool ToolStackIsEmpty()
Definition: tools_holder.h:128
Represent a single user action.
Definition: tool_action.h:68
TOOL_EVENT MakeEvent() const
Return the event associated with the action (i.e.
Definition: tool_action.cpp:72
KIGFX::VIEW_CONTROLS * getViewControls() const
Return the instance of VIEW_CONTROLS object used in the application.
Definition: tool_base.cpp:42
TOOL_MANAGER * m_toolMgr
Definition: tool_base.h:214
KIGFX::VIEW * getView() const
Returns the instance of #VIEW object used in the application.
Definition: tool_base.cpp:36
RESET_REASON
Determine the reason of reset for a tool.
Definition: tool_base.h:78
@ MODEL_RELOAD
Model changes (required full reload)
Definition: tool_base.h:80
Generic, UI-independent tool event.
Definition: tool_event.h:156
const VECTOR2D Position() const
Returns the point where dragging has started.
Definition: tool_event.h:266
void Go(int(T::*aStateFunc)(const TOOL_EVENT &), const TOOL_EVENT_LIST &aConditions=TOOL_EVENT(TC_ANY, TA_ANY))
Define which state (aStateFunc) to go when a certain event arrives (aConditions).
TOOL_MENU m_menu
The functions below are not yet implemented - their interface may change.
TOOL_EVENT * Wait(const TOOL_EVENT_LIST &aEventList=TOOL_EVENT(TC_ANY, TA_ANY))
Suspend execution of the tool until an event specified in aEventList arrives.
bool ProcessEvent(const TOOL_EVENT &aEvent)
Propagate an event to tools that requested events of matching type(s).
bool RunAction(const std::string &aActionName, bool aNow=false, T aParam=NULL)
Run the specified action.
Definition: tool_manager.h:142
bool InvokeTool(TOOL_ID aToolId)
Call a tool by sending a tool activation event to tool of given ID.
VECTOR2D GetMousePosition() const
CONDITIONAL_MENU & GetMenu()
Definition: tool_menu.cpp:44
void ShowContextMenu(SELECTION &aSelection)
Helper function to set and immediately show a CONDITIONAL_MENU in concert with the given SELECTION.
Definition: tool_menu.cpp:57
MOUSE_DRAG_ACTION
KICURSOR
Definition: cursors.h:34
#define DEFAULT_TEXT_SIZE
Ratio of the font height to the baseline of the text above the wire.
#define BRIGHTENED
item is drawn with a bright contour
#define IS_NEW
New item, just created.
#define SELECTED
Item was manually selected by the user.
#define ENDPOINT
ends. (Used to support dragging.)
std::uint32_t EDA_ITEM_FLAGS
#define CANDIDATE
flag indicating that the structure is connected
#define IS_ROLLOVER
Rollover active. Used for hyperlink highlighting.
#define IS_MOVING
Item being moved.
#define SHOW_ELEC_TYPE
Show pin electrical type. Shared with IS_ROLLOVER.
#define STARTPOINT
When a line is selected, these flags indicate which.
@ LAYER_CONNECTABLE
static std::vector< KICAD_T > connectedTypes
#define HITTEST_THRESHOLD_PIXELS
const TOOL_ACTION * allowedActions[]
@ ID_POPUP_SCH_UNFOLD_BUS_END
Definition: eeschema_id.h:91
@ ID_POPUP_SCH_SELECT_UNIT_CMP
Definition: eeschema_id.h:94
@ ID_POPUP_SCH_UNFOLD_BUS
Definition: eeschema_id.h:90
@ ID_POPUP_SCH_SELECT_UNIT_SYM_MAX
Definition: eeschema_id.h:98
KIID niluuid(0)
Macros and inline functions to create menus items in menubars or popup menus.
CITER next(CITER it)
Definition: ptree.cpp:126
std::function< bool(const SELECTION &)> SELECTION_CONDITION
< Functor type that checks a specific condition for selected items.
bool zoom_to_fit
Zoom to fit items (ignored if center_on_items is off)
Definition: app_settings.h:34
bool center_on_items
Automatically pan to cross-probed items.
Definition: app_settings.h:33
constexpr int MilsToIU(int mils) const
Definition: base_units.h:94
std::optional< TOOL_EVENT > OPT_TOOL_EVENT
Definition: tool_event.h:557
@ TA_CHOICE_MENU_CHOICE
Definition: tool_event.h:93
@ TA_UNDO_REDO_PRE
Definition: tool_event.h:101
@ TC_COMMAND
Definition: tool_event.h:52
@ MD_ALT
Definition: tool_event.h:140
@ MD_CTRL
Definition: tool_event.h:139
@ MD_SHIFT
Definition: tool_event.h:138
@ BUT_AUX1
Definition: tool_event.h:130
@ BUT_MIDDLE
Definition: tool_event.h:129
@ BUT_LEFT
Definition: tool_event.h:127
@ BUT_RIGHT
Definition: tool_event.h:128
@ BUT_AUX2
Definition: tool_event.h:131
double DistanceLinePoint(const VECTOR2I &linePointA, const VECTOR2I &linePointB, const VECTOR2I &referencePoint)
Compute the distance between a line and a reference point Reference: http://mathworld....
Definition: trigo.h:140
bool HitTestPoints(const VECTOR2I &pointA, const VECTOR2I &pointB, double threshold)
Test, if two points are near each other.
Definition: trigo.h:159
double EuclideanNorm(const VECTOR2I &vector)
Definition: trigo.h:129
KICAD_T
The set of class identification values stored in EDA_ITEM::m_structType.
Definition: typeinfo.h:78
@ SCH_LINE_T
Definition: typeinfo.h:145
@ LIB_SYMBOL_T
Definition: typeinfo.h:197
@ LIB_TEXT_T
Definition: typeinfo.h:200
@ SCH_SYMBOL_T
Definition: typeinfo.h:155
@ LIB_TEXTBOX_T
Definition: typeinfo.h:201
@ SCH_ITEM_LOCATE_WIRE_T
Definition: typeinfo.h:169
@ SCH_FIELD_T
Definition: typeinfo.h:154
@ SCH_DIRECTIVE_LABEL_T
Definition: typeinfo.h:153
@ SCH_LABEL_T
Definition: typeinfo.h:150
@ SCH_LOCATE_ANY_T
Definition: typeinfo.h:182
@ SCH_SHEET_T
Definition: typeinfo.h:157
@ SCH_ITEM_LOCATE_BUS_T
Definition: typeinfo.h:170
@ LIB_SHAPE_T
Definition: typeinfo.h:199
@ SCH_MARKER_T
Definition: typeinfo.h:140
@ SCH_HIER_LABEL_T
Definition: typeinfo.h:152
@ SCH_BUS_BUS_ENTRY_T
Definition: typeinfo.h:144
@ LIB_PIN_T
Definition: typeinfo.h:202
@ SCH_SHEET_PIN_T
Definition: typeinfo.h:156
@ LIB_FIELD_T
Definition: typeinfo.h:208
@ SCH_SYMBOL_LOCATE_POWER_T
Definition: typeinfo.h:179
@ SCH_BUS_WIRE_ENTRY_T
Definition: typeinfo.h:143
@ SCH_GLOBAL_LABEL_T
Definition: typeinfo.h:151
@ SCH_JUNCTION_T
Definition: typeinfo.h:141
@ SCH_PIN_T
Definition: typeinfo.h:158
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:80
VECTOR2< int > VECTOR2I
Definition: vector2d.h:618