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