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