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