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