KiCad PCB EDA Suite
sch_line_wire_bus_tool.cpp
Go to the documentation of this file.
1/*
2 * This program source code file is part of KiCad, a free EDA CAD application.
3 *
4 * Copyright (C) 2019 CERN
5 * Copyright (C) 2019-2022 KiCad Developers, see AUTHORS.txt for contributors.
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, you may find one here:
19 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
20 * or you may search the http://www.gnu.org website for the version 2 license,
21 * or you may write to the Free Software Foundation, Inc.,
22 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
23 */
24
26
27#include <wx/debug.h>
28#include <wx/gdicmn.h>
29#include <wx/string.h>
30#include <wx/stringimpl.h>
31#include <wx/translation.h>
32#include <algorithm>
33#include <cstdlib>
34#include <iterator>
35#include <memory>
36#include <utility>
37#include <vector>
38
39#include <eda_item.h>
40#include <bitmaps.h>
41#include <core/typeinfo.h>
42#include <layer_ids.h>
43#include <math/vector2d.h>
44#include <advanced_config.h>
45#include <tool/actions.h>
47#include <tool/selection.h>
49#include <tool/tool_event.h>
50#include <trigo.h>
51#include <undo_redo_container.h>
52#include <connection_graph.h>
53#include <eeschema_id.h>
54#include <sch_bus_entry.h>
55#include <sch_connection.h>
56#include <sch_edit_frame.h>
57#include <sch_item.h>
58#include <sch_line.h>
59#include <sch_screen.h>
60#include <sch_sheet.h>
61#include <sch_sheet_pin.h>
62#include <schematic.h>
63#include <ee_actions.h>
64#include <ee_grid_helper.h>
65#include <ee_selection.h>
66#include <ee_selection_tool.h>
67
69{
70public:
72 ACTION_MENU( true ),
73 m_showTitle( false )
74 {
76 SetTitle( _( "Unfold from Bus" ) );
77 }
78
80 {
81 m_showTitle = true;
82 }
83
84 bool PassHelpTextToHandler() override { return true; }
85
86protected:
87 ACTION_MENU* create() const override
88 {
89 return new BUS_UNFOLD_MENU();
90 }
91
92private:
93 void update() override
94 {
96 EE_SELECTION& selection = selTool->RequestSelection( { SCH_ITEM_LOCATE_BUS_T } );
97 SCH_LINE* bus = (SCH_LINE*) selection.Front();
98
99 Clear();
100
101 // Pick up the pointer again because it may have been changed by SchematicCleanUp
102 selection = selTool->RequestSelection( { SCH_ITEM_LOCATE_BUS_T } );
103 bus = (SCH_LINE*) selection.Front();
104
105 if( !bus )
106 {
107 Append( ID_POPUP_SCH_UNFOLD_BUS, _( "No bus selected" ), wxEmptyString );
108 Enable( ID_POPUP_SCH_UNFOLD_BUS, false );
109 return;
110 }
111
112 SCH_CONNECTION* connection = bus->Connection();
113
114 if( !connection || !connection->IsBus() || connection->Members().empty() )
115 {
116 Append( ID_POPUP_SCH_UNFOLD_BUS, _( "Bus has no members" ), wxEmptyString );
117 Enable( ID_POPUP_SCH_UNFOLD_BUS, false );
118 return;
119 }
120
121 int idx = 0;
122
123 if( m_showTitle )
124 {
125 Append( ID_POPUP_SCH_UNFOLD_BUS, _( "Unfold from Bus" ), wxEmptyString );
126 Enable( ID_POPUP_SCH_UNFOLD_BUS, false );
127 }
128
129 for( const std::shared_ptr<SCH_CONNECTION>& member : connection->Members() )
130 {
131 int id = ID_POPUP_SCH_UNFOLD_BUS + ( idx++ );
132 wxString name = member->FullLocalName();
133
134 if( member->Type() == CONNECTION_TYPE::BUS )
135 {
136 ACTION_MENU* submenu = new ACTION_MENU( true, m_tool );
137 AppendSubMenu( submenu, SCH_CONNECTION::PrintBusForUI( name ), name );
138
139 for( const std::shared_ptr<SCH_CONNECTION>& sub_member : member->Members() )
140 {
141 id = ID_POPUP_SCH_UNFOLD_BUS + ( idx++ );
142 name = sub_member->FullLocalName();
143 submenu->Append( id, SCH_CONNECTION::PrintBusForUI( name ), name );
144 }
145 }
146 else
147 {
148 Append( id, name, wxEmptyString );
149 }
150 }
151 }
152
154};
155
156
158 EE_TOOL_BASE<SCH_EDIT_FRAME>( "eeschema.InteractiveDrawingLineWireBus" ),
159 m_inDrawingTool( false )
160{
161 m_busUnfold = {};
162 m_wires.reserve( 16 );
163}
164
165
167{
168}
169
170
172{
174
175 std::shared_ptr<BUS_UNFOLD_MENU> busUnfoldMenu = std::make_shared<BUS_UNFOLD_MENU>();
176 busUnfoldMenu->SetTool( this );
177 m_menu.RegisterSubMenu( busUnfoldMenu );
178
179 std::shared_ptr<BUS_UNFOLD_MENU> selBusUnfoldMenu = std::make_shared<BUS_UNFOLD_MENU>();
180 selBusUnfoldMenu->SetTool( m_selectionTool );
181 m_selectionTool->GetToolMenu().RegisterSubMenu( selBusUnfoldMenu );
182
183 auto wireOrBusTool =
184 [this]( const SELECTION& aSel )
185 {
188 };
189
190 auto lineTool =
191 [this]( const SELECTION& aSel )
192 {
194 };
195
196 auto belowRootSheetCondition =
197 [&]( const SELECTION& aSel )
198 {
199 return m_frame->GetCurrentSheet().Last() != &m_frame->Schematic().Root();
200 };
201
202 auto busSelection = EE_CONDITIONS::MoreThan( 0 )
204
205 auto haveHighlight =
206 [&]( const SELECTION& sel )
207 {
208 SCH_EDIT_FRAME* editFrame = dynamic_cast<SCH_EDIT_FRAME*>( m_frame );
209
210 return editFrame && editFrame->GetHighlightedConnection() != nullptr;
211 };
212
213 auto& ctxMenu = m_menu.GetMenu();
214
215 // Build the tool menu
216 //
217 ctxMenu.AddItem( EE_ACTIONS::clearHighlight, haveHighlight && EE_CONDITIONS::Idle, 1 );
218 ctxMenu.AddSeparator( haveHighlight && EE_CONDITIONS::Idle, 1 );
219
220 ctxMenu.AddItem( EE_ACTIONS::leaveSheet, belowRootSheetCondition, 2 );
221
222 ctxMenu.AddSeparator( 10 );
223 ctxMenu.AddItem( EE_ACTIONS::drawWire, wireOrBusTool && EE_CONDITIONS::Idle, 10 );
224 ctxMenu.AddItem( EE_ACTIONS::drawBus, wireOrBusTool && EE_CONDITIONS::Idle, 10 );
225 ctxMenu.AddItem( EE_ACTIONS::drawLines, lineTool && EE_CONDITIONS::Idle, 10 );
226
229
230 ctxMenu.AddItem( EE_ACTIONS::finishWire, IsDrawingWire, 10 );
231 ctxMenu.AddItem( EE_ACTIONS::finishBus, IsDrawingBus, 10 );
232 ctxMenu.AddItem( EE_ACTIONS::finishLine, IsDrawingLine, 10 );
233
234 ctxMenu.AddMenu( busUnfoldMenu.get(), EE_CONDITIONS::Idle, 10 );
235
236 ctxMenu.AddSeparator( 100 );
237 ctxMenu.AddItem( EE_ACTIONS::placeJunction, wireOrBusTool && EE_CONDITIONS::Idle, 100 );
238 ctxMenu.AddItem( EE_ACTIONS::placeLabel, wireOrBusTool && EE_CONDITIONS::Idle, 100 );
239 ctxMenu.AddItem( EE_ACTIONS::placeClassLabel, wireOrBusTool && EE_CONDITIONS::Idle, 100 );
240 ctxMenu.AddItem( EE_ACTIONS::placeGlobalLabel, wireOrBusTool && EE_CONDITIONS::Idle, 100 );
241 ctxMenu.AddItem( EE_ACTIONS::placeHierLabel, wireOrBusTool && EE_CONDITIONS::Idle, 100 );
242 ctxMenu.AddItem( EE_ACTIONS::breakWire, wireOrBusTool && EE_CONDITIONS::Idle, 100 );
243 ctxMenu.AddItem( EE_ACTIONS::slice, ( wireOrBusTool || lineTool )
244 && EE_CONDITIONS::Idle, 100 );
245 ctxMenu.AddSeparator( 200 );
246 ctxMenu.AddItem( EE_ACTIONS::selectNode, wireOrBusTool && EE_CONDITIONS::Idle, 200 );
247 ctxMenu.AddItem( EE_ACTIONS::selectConnection, wireOrBusTool && EE_CONDITIONS::Idle, 200 );
248
249 // Add bus unfolding to the selection tool
250 //
252
253 selToolMenu.AddMenu( selBusUnfoldMenu.get(), busSelection && EE_CONDITIONS::Idle, 100 );
254
255 return true;
256}
257
258
260{
261 return IsDrawingLineWireOrBus( aSelection )
262 && aSelection.Front()->IsType( { SCH_ITEM_LOCATE_GRAPHIC_LINE_T } );
263}
264
265
267{
268 return IsDrawingLineWireOrBus( aSelection )
269 && aSelection.Front()->IsType( { SCH_ITEM_LOCATE_WIRE_T } );
270}
271
272
274{
275 return IsDrawingLineWireOrBus( aSelection )
276 && aSelection.Front()->IsType( { SCH_ITEM_LOCATE_BUS_T } );
277}
278
279
281{
282 // NOTE: for immediate hotkeys, it is NOT required that the line, wire or bus tool
283 // be selected
284 SCH_ITEM* item = (SCH_ITEM*) aSelection.Front();
285 return item && item->IsNew() && item->Type() == SCH_LINE_T;
286}
287
288
290{
291 if( m_inDrawingTool )
292 return 0;
293
295
297
298 m_frame->PushTool( aEvent );
300
301 if( aEvent.HasPosition() )
302 {
304 grid.SetSnap( !aEvent.Modifier( MD_SHIFT ) );
305 grid.SetUseGrid( getView()->GetGAL()->GetGridSnapping() && !aEvent.DisableGridSnapping() );
306
307 VECTOR2D cursorPos = grid.BestSnapAnchor( aEvent.Position(), LAYER_CONNECTABLE, nullptr );
308 startSegments( params->layer, cursorPos, params->sourceSegment );
309 }
310
311 return doDrawSegments( aEvent, params->layer, params->quitOnDraw );
312}
313
314
316{
317 if( m_inDrawingTool )
318 return 0;
319
321
322 wxString* netPtr = aEvent.Parameter<wxString*>();
323 wxString net;
324 SCH_LINE* segment = nullptr;
325
326 m_frame->PushTool( aEvent );
327 Activate();
328
329 if( netPtr )
330 {
331 net = *netPtr;
332 delete netPtr;
333 }
334 else
335 {
336 BUS_UNFOLD_MENU unfoldMenu;
337 unfoldMenu.SetTool( this );
338 unfoldMenu.SetShowTitle();
339
340 SetContextMenu( &unfoldMenu, CMENU_NOW );
341
342 while( TOOL_EVENT* evt = Wait() )
343 {
344 if( evt->Action() == TA_CHOICE_MENU_CHOICE )
345 {
346 std::optional<int> id = evt->GetCommandId();
347
348 if( id && ( *id > 0 ) )
349 net = *evt->Parameter<wxString*>();
350
351 break;
352 }
353 else if( evt->Action() == TA_CHOICE_MENU_CLOSED )
354 {
355 break;
356 }
357 else
358 {
359 evt->SetPassEvent();
360 }
361 }
362 }
363
364 // Break a wire for the given net out of the bus
365 if( !net.IsEmpty() )
366 segment = doUnfoldBus( net );
367
368 // If we have an unfolded wire to draw, then draw it
369 if( segment )
370 {
371 return doDrawSegments( aEvent, LAYER_WIRE, false );
372 }
373 else
374 {
375 m_frame->PopTool( aEvent );
376 return 0;
377 }
378}
379
380
381SCH_LINE* SCH_LINE_WIRE_BUS_TOOL::doUnfoldBus( const wxString& aNet, const VECTOR2I& aPos )
382{
383 SCHEMATIC_SETTINGS& cfg = getModel<SCHEMATIC>()->Settings();
384
385 VECTOR2I pos = aPos;
386
387 if( aPos == VECTOR2I( 0, 0 ) )
388 pos = static_cast<VECTOR2I>( getViewControls()->GetCursorPosition() );
389
391
395
401
403 m_busUnfold.origin = pos;
404 m_busUnfold.net_name = aNet;
405
407
409}
410
411
413{
414 SCH_SCREEN* screen = m_frame->GetScreen();
415
416 for( SCH_ITEM* item : screen->Items().Overlapping( SCH_SHEET_T, aPosition ) )
417 {
418 SCH_SHEET* sheet = static_cast<SCH_SHEET*>( item );
419
420 for( SCH_SHEET_PIN* pin : sheet->GetPins() )
421 {
422 if( pin->GetPosition() == aPosition )
423 return pin;
424 }
425 }
426
427 return nullptr;
428}
429
430
431void SCH_LINE_WIRE_BUS_TOOL::computeBreakPoint( const std::pair<SCH_LINE*, SCH_LINE*>& aSegments,
432 VECTOR2I& aPosition,
433 LINE_MODE mode,
434 bool posture )
435{
436 wxCHECK_RET( aSegments.first && aSegments.second,
437 wxT( "Cannot compute break point of NULL line segment." ) );
438
439 VECTOR2I midPoint;
440 SCH_LINE* segment = aSegments.first;
441 SCH_LINE* nextSegment = aSegments.second;
442
443 VECTOR2I delta = aPosition - segment->GetStartPoint();
444 int xDir = delta.x > 0 ? 1 : -1;
445 int yDir = delta.y > 0 ? 1 : -1;
446
447
448 bool preferHorizontal;
449 bool preferVertical;
450
451 if( ( mode == LINE_MODE_45 ) && posture )
452 {
453 preferHorizontal = ( nextSegment->GetEndPoint().x - nextSegment->GetStartPoint().x ) != 0;
454 preferVertical = ( nextSegment->GetEndPoint().y - nextSegment->GetStartPoint().y ) != 0;
455 }
456 else
457 {
458 preferHorizontal = ( segment->GetEndPoint().x - segment->GetStartPoint().x ) != 0;
459 preferVertical = ( segment->GetEndPoint().y - segment->GetStartPoint().y ) != 0;
460 }
461
462 // Check for times we need to force horizontal sheet pin connections
463 const SCH_SHEET_PIN* connectedPin = getSheetPin( segment->GetStartPoint() );
464 SHEET_SIDE force = connectedPin ? connectedPin->GetSide() : SHEET_SIDE::UNDEFINED;
465
466 if( force == SHEET_SIDE::LEFT || force == SHEET_SIDE::RIGHT )
467 {
468 if( aPosition.x == connectedPin->GetPosition().x ) // push outside sheet boundary
469 {
470 int direction = ( force == SHEET_SIDE::LEFT ) ? -1 : 1;
471 aPosition.x += KiROUND( getView()->GetGAL()->GetGridSize().x * direction );
472 }
473
474 preferHorizontal = true;
475 preferVertical = false;
476 }
477
478
479 auto breakVertical = [&]() mutable
480 {
481 switch( mode )
482 {
483 case LINE_MODE_45:
484 if( !posture )
485 {
486 midPoint.x = segment->GetStartPoint().x;
487 midPoint.y = aPosition.y - yDir * abs( delta.x );
488 }
489 else
490 {
491 midPoint.x = aPosition.x;
492 midPoint.y = segment->GetStartPoint().y + yDir * abs( delta.x );
493 }
494 break;
495 default:
496 midPoint.x = segment->GetStartPoint().x;
497 midPoint.y = aPosition.y;
498 }
499 };
500
501
502 auto breakHorizontal = [&]() mutable
503 {
504 switch( mode )
505 {
506 case LINE_MODE_45:
507 if( !posture )
508 {
509 midPoint.x = aPosition.x - xDir * abs( delta.y );
510 midPoint.y = segment->GetStartPoint().y;
511 }
512 else
513 {
514 midPoint.x = segment->GetStartPoint().x + xDir * abs( delta.y );
515 midPoint.y = aPosition.y;
516 }
517 break;
518 default:
519 midPoint.x = aPosition.x;
520 midPoint.y = segment->GetStartPoint().y;
521 }
522 };
523
524
525 // Maintain current line shape if we can, e.g. if we were originally moving
526 // vertically keep the first segment vertical
527 if( preferVertical )
528 breakVertical();
529 else if( preferHorizontal )
530 breakHorizontal();
531
532 // Check if our 45 degree angle is one of these shapes
533 // /
534 // /
535 // /
536 // /__________
537 VECTOR2I deltaMidpoint = midPoint - segment->GetStartPoint();
538
539 if( mode == LINE_MODE::LINE_MODE_45 && !posture
540 && ( ( alg::signbit( deltaMidpoint.x ) != alg::signbit( delta.x ) )
541 || ( alg::signbit( deltaMidpoint.y ) != alg::signbit( delta.y ) ) ) )
542 {
543 preferVertical = false;
544 preferHorizontal = false;
545 }
546 else if( mode == LINE_MODE::LINE_MODE_45 && posture
547 && ( ( abs( deltaMidpoint.x ) > abs( delta.x ) )
548 || ( abs( deltaMidpoint.y ) > abs( delta.y ) ) ) )
549 {
550 preferVertical = false;
551 preferHorizontal = false;
552 }
553
554 if( !preferHorizontal && !preferVertical )
555 {
556 if( std::abs( delta.x ) < std::abs( delta.y ) )
557 breakVertical();
558 else
559 breakHorizontal();
560 }
561
562 segment->SetEndPoint( midPoint );
563 nextSegment->SetStartPoint( midPoint );
564 nextSegment->SetEndPoint( aPosition );
565}
566
567
568int SCH_LINE_WIRE_BUS_TOOL::doDrawSegments( const TOOL_EVENT& aTool, int aType, bool aQuitOnDraw )
569{
570 SCH_SCREEN* screen = m_frame->GetScreen();
571 SCH_LINE* segment = nullptr;
574 int lastMode = m_frame->eeconfig()->m_Drawing.line_mode;
575 static bool posture = false;
576
577 auto setCursor =
578 [&]()
579 {
580 if( aType == LAYER_WIRE )
582 else if( aType == LAYER_BUS )
584 else if( aType == LAYER_NOTES )
586 else
588 };
589
590 auto cleanup =
591 [&] ()
592 {
594
595 for( SCH_LINE* wire : m_wires )
596 delete wire;
597
598 m_wires.clear();
599 segment = nullptr;
600
601 if( m_busUnfold.entry )
603
606
609
610 delete m_busUnfold.entry;
611 delete m_busUnfold.label;
612 m_busUnfold = {};
613
615 m_view->ShowPreview( false );
616 };
617
618 Activate();
619 // Must be done after Activate() so that it gets set into the correct context
620 controls->ShowCursor( true );
621 // Set initial cursor
622 setCursor();
623
624 // Add the new label to the selection so the rotate command operates on it
625 if( m_busUnfold.label )
627
628 // Continue the existing wires if we've started (usually by immediate action preference)
629 if( !m_wires.empty() )
630 segment = m_wires.back();
631
632 VECTOR2I contextMenuPos;
633
634 // Main loop: keep receiving events
635 while( TOOL_EVENT* evt = Wait() )
636 {
638 bool twoSegments = currentMode != LINE_MODE::LINE_MODE_FREE;
639
640 // The tool hotkey is interpreted as a click when drawing
641 bool isSyntheticClick = ( segment || m_busUnfold.in_progress ) && evt->IsActivate()
642 && evt->HasPosition() && evt->Matches( aTool );
643
644 setCursor();
645 grid.SetMask( GRID_HELPER::ALL );
646 grid.SetSnap( !evt->Modifier( MD_SHIFT ) );
647 grid.SetUseGrid( getView()->GetGAL()->GetGridSnapping() && !evt->DisableGridSnapping() );
648
649 if( segment )
650 {
651 if( segment->GetStartPoint().x == segment->GetEndPoint().x )
652 grid.ClearMaskFlag( GRID_HELPER::VERTICAL );
653
654 if( segment->GetStartPoint().y == segment->GetEndPoint().y )
655 grid.ClearMaskFlag( GRID_HELPER::HORIZONTAL );
656 }
657
658 VECTOR2D eventPosition = evt->HasPosition() ? evt->Position()
659 : controls->GetMousePosition();
660
661 VECTOR2I cursorPos = grid.BestSnapAnchor( eventPosition, LAYER_CONNECTABLE, segment );
662 controls->ForceCursorPosition( true, cursorPos );
663
664 // Need to handle change in H/V mode while drawing
665 if( currentMode != lastMode )
666 {
667 // Need to delete extra segment if we have one
668 if( segment && currentMode == LINE_MODE::LINE_MODE_FREE && m_wires.size() >= 2 )
669 {
670 m_wires.pop_back();
672 delete segment;
673
674 segment = m_wires.back();
675 segment->SetEndPoint( cursorPos );
676 }
677 // Add a segment so we can move orthogonally/45
678 else if( segment && lastMode == LINE_MODE::LINE_MODE_FREE )
679 {
680 segment->SetEndPoint( cursorPos );
681
682 // Create a new segment, and chain it after the current segment.
683 segment = static_cast<SCH_LINE*>( segment->Duplicate() );
684 segment->SetFlags( IS_NEW | IS_MOVING );
685 segment->SetStartPoint( cursorPos );
686 m_wires.push_back( segment );
687
688 m_selectionTool->AddItemToSel( segment, true /*quiet mode*/ );
689 }
690
691 lastMode = currentMode;
692 }
693
694 //------------------------------------------------------------------------
695 // Handle cancel:
696 //
697 if( evt->IsCancelInteractive() )
698 {
700
701 if( segment || m_busUnfold.in_progress )
702 {
703 cleanup();
704
705 if( aQuitOnDraw )
706 {
707 m_frame->PopTool( aTool );
708 break;
709 }
710 }
711 else
712 {
713 m_frame->PopTool( aTool );
714 break;
715 }
716 }
717 else if( evt->IsActivate() && !isSyntheticClick )
718 {
719 if( segment || m_busUnfold.in_progress )
720 {
721 m_frame->ShowInfoBarMsg( _( "Press <ESC> to cancel drawing." ) );
722 evt->SetPassEvent( false );
723 continue;
724 }
725
726 if( evt->IsMoveTool() )
727 {
728 // leave ourselves on the stack so we come back after the move
729 break;
730 }
731 else
732 {
733 m_frame->PopTool( aTool );
734 break;
735 }
736 }
737 //------------------------------------------------------------------------
738 // Handle finish:
739 //
740 else if( evt->IsAction( &EE_ACTIONS::finishLineWireOrBus )
741 || evt->IsAction( &EE_ACTIONS::finishWire )
742 || evt->IsAction( &EE_ACTIONS::finishBus )
743 || evt->IsAction( &EE_ACTIONS::finishLine ) )
744 {
745 if( segment || m_busUnfold.in_progress )
746 {
748 segment = nullptr;
749
750 if( aQuitOnDraw )
751 {
752 m_frame->PopTool( aTool );
753 break;
754 }
755 }
756 }
757 //------------------------------------------------------------------------
758 // Handle click:
759 //
760 else if( evt->IsClick( BUT_LEFT )
761 || ( segment && evt->IsDblClick( BUT_LEFT ) )
762 || isSyntheticClick )
763 {
764 // First click when unfolding places the label and wire-to-bus entry
766 {
767 wxASSERT( aType == LAYER_WIRE );
768
772 }
773
774 if( !segment )
775 {
776 segment = startSegments( aType, VECTOR2D( cursorPos ) );
777 }
778 // Create a new segment if we're out of previously-created ones
779 else if( !segment->IsNull()
780 || ( twoSegments && !m_wires[m_wires.size() - 2]->IsNull() ) )
781 {
782 // Terminate the command if the end point is on a pin, junction, label, or another
783 // wire or bus.
784 if( screen->IsTerminalPoint( cursorPos, segment->GetLayer() ) )
785 {
787 segment = nullptr;
788
789 if( aQuitOnDraw )
790 {
791 m_frame->PopTool( aTool );
792 break;
793 }
794 }
795 else
796 {
797 int placedSegments = 1;
798
799 // When placing lines with the forty-five degree end, the user is
800 // targetting the endpoint with the angled portion, so it's more
801 // intuitive to place both segments at the same time.
802 if( currentMode == LINE_MODE::LINE_MODE_45 )
803 placedSegments++;
804
805 segment->SetEndPoint( cursorPos );
806
807 for( int i = 0; i < placedSegments; i++ )
808 {
809 // Create a new segment, and chain it after the current segment.
810 segment = static_cast<SCH_LINE*>( segment->Duplicate() );
811 segment->SetFlags( IS_NEW | IS_MOVING );
812 segment->SetStartPoint( cursorPos );
813 m_wires.push_back( segment );
814
815 m_selectionTool->AddItemToSel( segment, true /*quiet mode*/ );
816 }
817 }
818 }
819
820 if( evt->IsDblClick( BUT_LEFT ) && segment )
821 {
822 if( twoSegments && m_wires.size() >= 2 )
823 computeBreakPoint( { m_wires[m_wires.size() - 2], segment }, cursorPos,
824 currentMode, posture );
825
827 segment = nullptr;
828
829 if( aQuitOnDraw )
830 {
831 m_frame->PopTool( aTool );
832 break;
833 }
834 }
835 }
836 //------------------------------------------------------------------------
837 // Handle motion:
838 //
839 else if( evt->IsMotion() || evt->IsAction( &ACTIONS::refreshPreview ) )
840 {
842
843 // Update the bus unfold posture based on the mouse movement
845 {
846 VECTOR2I cursor_delta = cursorPos - m_busUnfold.origin;
848
849 bool flipX = ( cursor_delta.x < 0 );
850 bool flipY = ( cursor_delta.y < 0 );
851
852 // Erase and redraw if necessary
853 if( flipX != m_busUnfold.flipX || flipY != m_busUnfold.flipY )
854 {
855 VECTOR2I size = entry->GetSize();
856 int ySign = flipY ? -1 : 1;
857 int xSign = flipX ? -1 : 1;
858
859 size.x = std::abs( size.x ) * xSign;
860 size.y = std::abs( size.y ) * ySign;
861 entry->SetSize( size );
862
863 m_busUnfold.flipY = flipY;
864 m_busUnfold.flipX = flipX;
865
866 m_frame->UpdateItem( entry, false, true );
867 m_wires.front()->SetStartPoint( entry->GetEnd() );
868 }
869
870 // Update the label "ghost" position
871 m_busUnfold.label->SetPosition( cursorPos );
873
874 // Ensure segment is non-null at the start of bus unfold
875 if( !segment )
876 segment = m_wires.back();
877 }
878
879 if( segment )
880 {
881 // Coerce the line to vertical/horizontal/45 as necessary
882 if( twoSegments && m_wires.size() >= 2 )
883 {
884 computeBreakPoint( { m_wires[m_wires.size() - 2], segment }, cursorPos,
885 currentMode, posture );
886 }
887 else
888 {
889 segment->SetEndPoint( cursorPos );
890 }
891 }
892
893 for( SCH_LINE* wire : m_wires )
894 {
895 if( !wire->IsNull() )
896 m_view->AddToPreview( wire->Clone() );
897 }
898 }
899 else if( evt->IsAction( &EE_ACTIONS::undoLastSegment ) )
900 {
901 if( ( currentMode == LINE_MODE::LINE_MODE_FREE && m_wires.size() > 1 )
902 || ( LINE_MODE::LINE_MODE_90 && m_wires.size() > 2 ) )
903 {
905
906 m_wires.pop_back();
908 delete segment;
909
910 segment = m_wires.back();
911 segment->SetEndPoint( cursorPos );
912
913 // Find new bend point for current mode
914 if( twoSegments && m_wires.size() >= 2 )
915 {
916 computeBreakPoint( { m_wires[m_wires.size() - 2], segment }, cursorPos,
917 currentMode, posture );
918 }
919 else
920 {
921 segment->SetEndPoint( cursorPos );
922 }
923
924 for( SCH_LINE* wire : m_wires )
925 {
926 if( !wire->IsNull() )
927 m_view->AddToPreview( wire->Clone() );
928 }
929 }
930 else
931 {
932 wxBell();
933 }
934 }
935 else if( evt->IsAction( &EE_ACTIONS::switchSegmentPosture ) && m_wires.size() >= 2 )
936 {
937 posture = !posture;
938
939 // The 90 degree mode doesn't have a forced posture like
940 // the 45 degree mode and computeBreakPoint maintains existing 90s' postures.
941 // Instead, just swap the 90 angle here.
942 if( currentMode == LINE_MODE::LINE_MODE_90 )
943 {
945
946 SCH_LINE* line2 = m_wires[m_wires.size() - 1];
947 SCH_LINE* line1 = m_wires[m_wires.size() - 2];
948
949 VECTOR2I delta2 = line2->GetEndPoint() - line2->GetStartPoint();
950 VECTOR2I delta1 = line1->GetEndPoint() - line1->GetStartPoint();
951
952 line2->SetStartPoint(line2->GetEndPoint() - delta1);
953 line1->SetEndPoint(line1->GetStartPoint() + delta2);
954
955 for( SCH_LINE* wire : m_wires )
956 {
957 if( !wire->IsNull() )
958 m_view->AddToPreview( wire->Clone() );
959 }
960 }
961 else
962 {
963 computeBreakPoint( { m_wires[m_wires.size() - 2], segment }, cursorPos, currentMode,
964 posture );
965
967 }
968 }
969 //------------------------------------------------------------------------
970 // Handle context menu:
971 //
972 else if( evt->IsClick( BUT_RIGHT ) )
973 {
974 // Warp after context menu only if dragging...
975 if( !segment )
977
978 contextMenuPos = cursorPos;
980 }
981 else if( evt->Category() == TC_COMMAND && evt->Action() == TA_CHOICE_MENU_CHOICE )
982 {
983 if( *evt->GetCommandId() >= ID_POPUP_SCH_UNFOLD_BUS
984 && *evt->GetCommandId() <= ID_POPUP_SCH_UNFOLD_BUS_END )
985 {
986 wxASSERT_MSG( !segment, "Bus unfold event received when already drawing!" );
987
988 aType = LAYER_WIRE;
989 wxString net = *evt->Parameter<wxString*>();
990 segment = doUnfoldBus( net, contextMenuPos );
991 }
992 }
993 //------------------------------------------------------------------------
994 // Handle TOOL_ACTION special cases
995 //
996 else if( evt->IsAction( &EE_ACTIONS::rotateCW ) || evt->IsAction( &EE_ACTIONS::rotateCCW ) )
997 {
999 {
1000 m_busUnfold.label->Rotate90( evt->IsAction( &EE_ACTIONS::rotateCW ) );
1002 }
1003 else
1004 {
1005 wxBell();
1006 }
1007 }
1008 else if( evt->IsAction( &ACTIONS::doDelete ) && ( segment || m_busUnfold.in_progress ) )
1009 {
1010 cleanup();
1011 }
1012 else
1013 {
1014 evt->SetPassEvent();
1015 }
1016
1017 // Enable autopanning and cursor capture only when there is a segment to be placed
1018 controls->SetAutoPan( segment != nullptr );
1019 controls->CaptureCursor( segment != nullptr );
1020 }
1021
1022 controls->SetAutoPan( false );
1023 controls->CaptureCursor( false );
1025 controls->ForceCursorPosition( false );
1026 return 0;
1027}
1028
1029
1031 SCH_LINE* aSegment )
1032{
1033 // If a segment isn't provided to copy properties from, we need to create one
1034 if( aSegment == nullptr )
1035 {
1036 switch( aType )
1037 {
1038 default: aSegment = new SCH_LINE( aPos, LAYER_NOTES ); break;
1039 case LAYER_WIRE: aSegment = new SCH_LINE( aPos, LAYER_WIRE ); break;
1040 case LAYER_BUS: aSegment = new SCH_LINE( aPos, LAYER_BUS ); break;
1041 }
1042
1043 // Give segments a parent so they find the default line/wire/bus widths
1044 aSegment->SetParent( &m_frame->Schematic() );
1045 }
1046 else
1047 {
1048 aSegment = static_cast<SCH_LINE*>( aSegment->Duplicate() );
1049 aSegment->SetStartPoint( aPos );
1050 }
1051
1052
1053 aSegment->SetFlags( IS_NEW | IS_MOVING );
1054 m_wires.push_back( aSegment );
1055
1056 m_selectionTool->AddItemToSel( aSegment, true /*quiet mode*/ );
1057
1058 // We need 2 segments to go from a given start pin to an end point when the
1059 // horizontal and vertical lines only switch is on.
1061 {
1062 aSegment = static_cast<SCH_LINE*>( aSegment->Duplicate() );
1063 aSegment->SetFlags( IS_NEW | IS_MOVING );
1064 m_wires.push_back( aSegment );
1065
1066 m_selectionTool->AddItemToSel( aSegment, true /*quiet mode*/ );
1067 }
1068
1069 return aSegment;
1070}
1071
1072
1087{
1088 for( auto it = m_wires.begin(); it != m_wires.end(); )
1089 {
1090 SCH_LINE* line = *it;
1091
1092 if( line->IsNull() )
1093 {
1094 delete line;
1095 it = m_wires.erase( it );
1096 continue;
1097 }
1098
1099 auto next_it = it;
1100 ++next_it;
1101
1102 if( next_it == m_wires.end() )
1103 break;
1104
1105 SCH_LINE* next_line = *next_it;
1106
1107 if( SCH_LINE* merged = line->MergeOverlap( m_frame->GetScreen(), next_line, false ) )
1108 {
1109 delete line;
1110 delete next_line;
1111 it = m_wires.erase( it );
1112 *it = merged;
1113 }
1114
1115 ++it;
1116 }
1117}
1118
1119
1121{
1122 // Clear selection when done so that a new wire can be started.
1123 // NOTE: this must be done before simplifyWireList is called or we might end up with
1124 // freed selected items.
1126
1127 SCH_SCREEN* screen = m_frame->GetScreen();
1128 PICKED_ITEMS_LIST itemList;
1129
1130 // Remove segments backtracking over others
1132
1133 // Collect the possible connection points for the new lines
1134 std::vector<VECTOR2I> connections = screen->GetConnections();
1135 std::vector<VECTOR2I> new_ends;
1136
1137 // Check each new segment for possible junctions and add/split if needed
1138 for( SCH_LINE* wire : m_wires )
1139 {
1140 if( wire->HasFlag( SKIP_STRUCT ) )
1141 continue;
1142
1143 std::vector<VECTOR2I> tmpends = wire->GetConnectionPoints();
1144
1145 new_ends.insert( new_ends.end(), tmpends.begin(), tmpends.end() );
1146
1147 for( const VECTOR2I& pt : connections )
1148 {
1149 if( IsPointOnSegment( wire->GetStartPoint(), wire->GetEndPoint(), pt ) )
1150 new_ends.push_back( pt );
1151 }
1152
1153 itemList.PushItem( ITEM_PICKER( screen, wire, UNDO_REDO::NEWITEM ) );
1154 }
1155
1157 {
1158 wxASSERT( m_busUnfold.entry && m_busUnfold.label );
1159
1162
1166 }
1167 else if( !m_wires.empty() )
1168 {
1170 }
1171
1172 for( size_t ii = 1; ii < m_wires.size(); ++ii )
1174
1175 // Get the last non-null wire (this is the last created segment).
1176 if( !m_wires.empty() )
1178
1179 // Add the new wires
1180 for( SCH_LINE* wire : m_wires )
1181 {
1182 wire->ClearFlags( IS_NEW | IS_MOVING );
1183 m_frame->AddToScreen( wire, screen );
1184 }
1185
1186 m_wires.clear();
1188 m_view->ShowPreview( false );
1189
1190 getViewControls()->CaptureCursor( false );
1191 getViewControls()->SetAutoPan( false );
1192
1193 m_frame->SaveCopyInUndoList( itemList, UNDO_REDO::NEWITEM, false );
1194
1195 // Correct and remove segments that need to be merged.
1197
1198 std::vector<SCH_ITEM*> symbols;
1199
1200 for( SCH_ITEM* symbol : m_frame->GetScreen()->Items().OfType( SCH_SYMBOL_T ) )
1201 symbols.push_back( symbol );
1202
1203 for( SCH_ITEM* symbol : symbols )
1204 {
1205 std::vector<VECTOR2I> pts = symbol->GetConnectionPoints();
1206
1207 if( pts.size() > 2 )
1208 continue;
1209
1210 for( auto pt = pts.begin(); pt != pts.end(); pt++ )
1211 {
1212 for( auto secondPt = pt + 1; secondPt != pts.end(); secondPt++ )
1213 m_frame->TrimWire( *pt, *secondPt );
1214 }
1215 }
1216
1217 for( const VECTOR2I& pt : new_ends )
1218 {
1220 m_frame->AddJunction( m_frame->GetScreen(), pt, true, false );
1221 }
1222
1224 m_busUnfold = {};
1225
1226 for( SCH_ITEM* item : m_frame->GetScreen()->Items() )
1227 item->ClearEditFlags();
1228
1231
1232 m_frame->OnModify();
1233}
1234
1235
1237{
1238 SCHEMATIC* sch = getModel<SCHEMATIC>();
1239 SCH_SCREEN* screen = sch->CurrentSheet().LastScreen();
1240
1241 std::set<SCH_LINE*> lines;
1242 BOX2I bb = aSelection->GetBoundingBox();
1243
1244 for( EDA_ITEM* item : screen->Items().Overlapping( SCH_LINE_T, bb ) )
1245 lines.insert( static_cast<SCH_LINE*>( item ) );
1246
1247 for( unsigned ii = 0; ii < aSelection->GetSize(); ii++ )
1248 {
1249 SCH_ITEM* item = dynamic_cast<SCH_ITEM*>( aSelection->GetItem( ii ) );
1250
1251 if( !item || !item->IsConnectable() || ( item->Type() == SCH_LINE_T ) )
1252 continue;
1253
1254 std::vector<VECTOR2I> pts = item->GetConnectionPoints();
1255
1258 for( SCH_LINE* line : lines )
1259 {
1260 std::vector<VECTOR2I> conn_pts;
1261
1262 for( VECTOR2I pt : pts )
1263 {
1264 if( IsPointOnSegment( line->GetStartPoint(), line->GetEndPoint(), pt ) )
1265 conn_pts.push_back( pt );
1266
1267 if( conn_pts.size() > 2 )
1268 break;
1269 }
1270
1271 if( conn_pts.size() == 2 )
1272 m_frame->TrimWire( conn_pts[0], conn_pts[1] );
1273 }
1274 }
1275
1276 return 0;
1277}
1278
1279
1281{
1282 SCH_SCREEN* screen = m_frame->GetScreen();
1283
1284 for( const VECTOR2I& point : screen->GetNeededJunctions( aSelection->Items() ) )
1285 m_frame->AddJunction( m_frame->GetScreen(), point, true, false );
1286
1287 return 0;
1288}
1289
1290
1292{
1296
1298}
const char * name
Definition: DXF_plotter.cpp:56
@ add_line2bus
static TOOL_ACTION doDelete
Definition: actions.h:73
static TOOL_ACTION refreshPreview
Definition: actions.h:110
Defines the structure of a menu based on ACTIONs.
Definition: action_menu.h:49
ACTION_MENU(bool isContextMenu, TOOL_INTERACTIVE *aTool=nullptr)
< Default constructor
Definition: action_menu.cpp:47
TOOL_MANAGER * getToolManager() const
void Clear()
Remove all the entries from the menu (as well as its title).
void SetTitle(const wxString &aTitle) override
Set title for the menu.
Definition: action_menu.cpp:87
void SetTool(TOOL_INTERACTIVE *aTool)
Set a tool that is the creator of the menu.
void SetIcon(BITMAPS aIcon)
Assign an icon for the entry.
Definition: action_menu.cpp:73
TOOL_INTERACTIVE * m_tool
Associates tool actions with menu item IDs. Non-owning.
Definition: action_menu.h:266
ACTION_MENU * create() const override
< Return an instance of this class. It has to be overridden in inheriting classes.
bool PassHelpTextToHandler() override
void update() override
Update menu state stub.
void AddItem(const TOOL_ACTION &aAction, const SELECTION_CONDITION &aCondition, int aOrder=ANY_ORDER)
Add a menu entry to run a TOOL_ACTION on selected items.
void AddMenu(ACTION_MENU *aMenu, const SELECTION_CONDITION &aCondition=SELECTION_CONDITIONS::ShowAlways, int aOrder=ANY_ORDER)
Add a submenu to the menu.
void ShowInfoBarMsg(const wxString &aMsg, bool aShowCloseButton=false)
Show the WX_INFOBAR displayed on the top of the canvas with a message and an info icon on the left of...
WX_INFOBAR * GetInfoBar()
void SetCurrentCursor(KICURSOR aCursor)
Set the current cursor shape for this panel.
A base class for most all the KiCad significant classes used in schematics and boards.
Definition: eda_item.h:85
void SetFlags(EDA_ITEM_FLAGS aMask)
Definition: eda_item.h:139
KICAD_T Type() const
Returns the type of object.
Definition: eda_item.h:97
virtual bool IsType(const std::vector< KICAD_T > &aScanTypes) const
Check whether the item is one of the listed types.
Definition: eda_item.h:181
virtual void SetParent(EDA_ITEM *aParent)
Definition: eda_item.h:100
void ClearEditFlags()
Definition: eda_item.h:158
bool IsNew() const
Definition: eda_item.h:103
void SetTextSize(const VECTOR2I &aNewSize)
Definition: eda_text.cpp:349
static TOOL_ACTION finishLine
Definition: ee_actions.h:105
static TOOL_ACTION clearHighlight
Definition: ee_actions.h:267
static TOOL_ACTION selectConnection
If current selection is a wire or bus, expand to entire connection.
Definition: ee_actions.h:53
static TOOL_ACTION slice
Definition: ee_actions.h:144
static TOOL_ACTION clearSelection
Clears the current selection.
Definition: ee_actions.h:56
static TOOL_ACTION placeClassLabel
Definition: ee_actions.h:88
static TOOL_ACTION drawWire
Definition: ee_actions.h:81
static TOOL_ACTION rotateCCW
Definition: ee_actions.h:124
static TOOL_ACTION drawBus
Definition: ee_actions.h:82
static TOOL_ACTION finishWire
Definition: ee_actions.h:103
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:143
static TOOL_ACTION drawLines
Definition: ee_actions.h:98
static TOOL_ACTION finishLineWireOrBus
Definition: ee_actions.h:102
static TOOL_ACTION rotateCW
Definition: ee_actions.h:123
static TOOL_ACTION leaveSheet
Definition: ee_actions.h:200
static TOOL_ACTION placeGlobalLabel
Definition: ee_actions.h:89
static TOOL_ACTION placeHierLabel
Definition: ee_actions.h:90
static TOOL_ACTION undoLastSegment
Definition: ee_actions.h:100
static TOOL_ACTION unfoldBus
Definition: ee_actions.h:83
static TOOL_ACTION placeLabel
Definition: ee_actions.h:87
static TOOL_ACTION switchSegmentPosture
Definition: ee_actions.h:101
static TOOL_ACTION placeJunction
Definition: ee_actions.h:85
static TOOL_ACTION finishBus
Definition: ee_actions.h:104
EE_TYPE Overlapping(const BOX2I &aRect) const
Definition: sch_rtree.h:243
EE_TYPE OfType(KICAD_T aType) const
Definition: sch_rtree.h:238
EE_SELECTION & RequestSelection(const std::vector< KICAD_T > &aScanTypes={ SCH_LOCATE_ANY_T })
Return either an existing selection (filtered), or the selection at the current cursor position if th...
EE_SELECTION & GetSelection()
BOX2I GetBoundingBox() const override
A foundation class for a tool operating on a schematic or symbol.
Definition: ee_tool_base.h:50
EE_SELECTION_TOOL * m_selectionTool
Definition: ee_tool_base.h:191
bool Init() override
Init() is called once upon a registration of the tool.
Definition: ee_tool_base.h:66
static const TOOL_EVENT SelectedItemsModified
Selected items were moved, this can be very high frequency on the canvas, use with care.
Definition: actions.h:214
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 ShowCursor(bool aEnabled)
Enable or disables display of cursor.
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 VECTOR2D GetMousePosition(bool aWorldCoordinates=true) const =0
Return the current mouse pointer position.
virtual void SetAutoPan(bool aEnabled)
Turn on/off auto panning (this feature is used when there is a tool active (eg.
void ShowPreview(bool aShow=true)
Definition: view.cpp:1649
void AddToPreview(EDA_ITEM *aItem, bool aTakeOwnership=true)
Definition: view.cpp:1635
void ClearPreview()
Definition: view.cpp:1613
A holder to handle information on schematic or board items.
void PushItem(const ITEM_PICKER &aItem)
Push aItem to the top of the list.
These settings were stored in SCH_BASE_FRAME previously.
Holds all the data relating to one schematic.
Definition: schematic.h:61
SCH_SHEET_PATH & CurrentSheet() const override
Definition: schematic.h:122
SCH_SHEET & Root() const
Definition: schematic.h:91
SCH_DRAW_PANEL * GetCanvas() const override
Return a pointer to GAL-based canvas of given EDA draw frame.
EESCHEMA_SETTINGS * eeconfig() const
void RemoveFromScreen(EDA_ITEM *aItem, SCH_SCREEN *aScreen)
Remove an item from the screen (and view) aScreen is the screen the item is located on,...
void AddToScreen(EDA_ITEM *aItem, SCH_SCREEN *aScreen)
Add an item to the screen (and view) aScreen is the screen the item is located on,...
VECTOR2I GetSize() const
Definition: sch_bus_entry.h:71
void SetSize(const VECTOR2I &aSize)
Definition: sch_bus_entry.h:72
VECTOR2I GetEnd() const
Class for a wire to bus entry.
Each graphical item can have a SCH_CONNECTION describing its logical connection (to a bus or net).
bool IsBus() const
static wxString PrintBusForUI(const wxString &aString)
std::vector< std::shared_ptr< SCH_CONNECTION > > & Members()
Schematic editor (Eeschema) main window.
bool SchematicCleanUp(SCH_SCREEN *aScreen=nullptr)
Perform routine schematic cleaning including breaking wire and buses and deleting identical objects s...
const SCH_CONNECTION * GetHighlightedConnection() const
bool TrimWire(const VECTOR2I &aStart, const VECTOR2I &aEnd)
If any single wire passes through both points, remove the portion between the two points,...
void OnModify() override
Must be called after a schematic change in order to set the "modify" flag and update other data struc...
SCH_SCREEN * GetScreen() const override
Return a pointer to a BASE_SCREEN or one of its derivatives.
void SaveCopyInUndoList(SCH_SCREEN *aScreen, SCH_ITEM *aItemToCopy, UNDO_REDO aTypeCommand, bool aAppend, bool aDirtyConnectivity=true)
Create a copy of the current schematic item, and put it in the undo list.
SCH_SHEET_PATH & GetCurrentSheet() const
SCHEMATIC & Schematic() const
void UpdateItem(EDA_ITEM *aItem, bool isAddOrDelete=false, bool aUpdateRtree=false) override
Mark an item for refresh.
void AddCopyForRepeatItem(const SCH_ITEM *aItem)
SCH_JUNCTION * AddJunction(SCH_SCREEN *aScreen, const VECTOR2I &aPos, bool aAppendToUndo, bool aFinal=true)
void TestDanglingEnds()
Test all of the connectable objects in the schematic for unused connection points.
void SaveCopyForRepeatItem(const SCH_ITEM *aItem)
Clone aItem and owns that clone in this container.
Base class for any item which can be embedded within the SCHEMATIC container class,...
Definition: sch_item.h:147
virtual bool IsConnectable() const
Definition: sch_item.h:349
SCH_LAYER_ID GetLayer() const
Return the layer this item is on.
Definition: sch_item.h:246
SCH_CONNECTION * Connection(const SCH_SHEET_PATH *aSheet=nullptr) const
Retrieve the connection associated with this object in the given sheet.
Definition: sch_item.cpp:146
virtual std::vector< VECTOR2I > GetConnectionPoints() const
Add all the connection points for this item to aPoints.
Definition: sch_item.h:364
SCH_ITEM * Duplicate(bool doClone=false) const
Routine to create a new copy of given item.
Definition: sch_item.cpp:93
void Rotate90(bool aClockwise) override
Definition: sch_label.cpp:309
EDA_ITEM * Clone() const override
Create a duplicate of this item with linked list members set to NULL.
Definition: sch_label.h:260
void computeBreakPoint(const std::pair< SCH_LINE *, SCH_LINE * > &aSegments, VECTOR2I &aPosition, LINE_MODE mode, bool posture)
Compute the middle coordinate for 2 segments from the start point to aPosition with the segments kept...
int DrawSegments(const TOOL_EVENT &aEvent)
void setTransitions() override
This method is meant to be overridden in order to specify handlers for events.
int AddJunctionsIfNeeded(EE_SELECTION *aSelection)
Handle the addition of junctions to a selection of objects.
int UnfoldBus(const TOOL_EVENT &aEvent)
static bool IsDrawingWire(const SELECTION &aSelection)
int doDrawSegments(const TOOL_EVENT &aTool, int aType, bool aQuitOnDraw)
static bool IsDrawingBus(const SELECTION &aSelection)
bool Init() override
Init() is called once upon a registration of the tool.
const SCH_SHEET_PIN * getSheetPin(const VECTOR2I &aPosition)
Search for a sheet pin at a location.
std::vector< SCH_LINE * > m_wires
int TrimOverLappingWires(EE_SELECTION *aSelection)
Logic to remove wires when overlapping correct items.
static bool IsDrawingLineWireOrBus(const SELECTION &aSelection)
SCH_LINE * doUnfoldBus(const wxString &aNet, const VECTOR2I &aPos=VECTOR2I(0, 0))
SCH_LINE * startSegments(int aType, const VECTOR2D &aPos, SCH_LINE *aSegment=nullptr)
void simplifyWireList()
Iterate over the wire list and removes the null segments and overlapping segments to create a simplif...
static bool IsDrawingLine(const SELECTION &aSelection)
Segment description base class to describe items which have 2 end points (track, wire,...
Definition: sch_line.h:40
void SetStartPoint(const VECTOR2I &aPosition)
Definition: sch_line.h:139
VECTOR2I GetEndPoint() const
Definition: sch_line.h:143
VECTOR2I GetStartPoint() const
Definition: sch_line.h:138
SCH_LINE * MergeOverlap(SCH_SCREEN *aScreen, SCH_LINE *aLine, bool aCheckJunctions)
Check line against aLine to see if it overlaps and merge if it does.
Definition: sch_line.cpp:471
bool IsNull() const
Definition: sch_line.h:136
void SetEndPoint(const VECTOR2I &aPosition)
Definition: sch_line.h:144
EE_RTREE & Items()
Gets the full RTree, usually for iterating.
Definition: sch_screen.h:109
bool IsTerminalPoint(const VECTOR2I &aPosition, int aLayer) const
Test if aPosition is a connection point on aLayer.
Definition: sch_screen.cpp:817
bool IsExplicitJunctionNeeded(const VECTOR2I &aPosition) const
Indicates that a junction dot is necessary at the given location, and does not yet exist.
Definition: sch_screen.cpp:478
std::vector< VECTOR2I > GetNeededJunctions(const std::deque< EDA_ITEM * > &aItems) const
Return the unique set of points belonging to aItems where a junction is needed.
std::vector< VECTOR2I > GetConnections() const
Collect a unique list of all possible connection points in the schematic.
SCH_SCREEN * LastScreen()
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:57
std::vector< SCH_SHEET_PIN * > & GetPins()
Definition: sch_sheet.h:175
VECTOR2I GetPosition() const override
Definition: sch_text.h:203
void SetPosition(const VECTOR2I &aPosition) override
Definition: sch_text.h:204
virtual void SetTextSpinStyle(TEXT_SPIN_STYLE aSpinStyle)
Set a spin or rotation angle, along with specific horizontal and vertical justification styles with e...
Definition: sch_text.cpp:188
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 bool ShowAlways(const SELECTION &aSelection)
The default condition function (always returns true).
static SELECTION_CONDITION OnlyTypes(std::vector< KICAD_T > aTypes)
Create a functor that tests if the selected items are only of given types.
int RemoveItemFromSel(const TOOL_EVENT &aEvent)
int AddItemToSel(const TOOL_EVENT &aEvent)
virtual KIGFX::VIEW_ITEM * GetItem(unsigned int aIdx) const override
Definition: selection.cpp:75
virtual unsigned int GetSize() const override
Return the number of stored items.
Definition: selection.h:99
EDA_ITEM * Front() const
Definition: selection.h:208
std::deque< EDA_ITEM * > & Items()
Definition: selection.h:213
virtual void PopTool(const TOOL_EVENT &aEvent)
Pops a tool from the stack.
virtual void PushTool(const TOOL_EVENT &aEvent)
NB: the definition of "tool" is different at the user level.
bool IsCurrentTool(const TOOL_ACTION &aAction) const
KIGFX::VIEW_CONTROLS * getViewControls() const
Return the instance of VIEW_CONTROLS object used in the application.
Definition: tool_base.cpp:42
TOOL_MANAGER * m_toolMgr
Definition: tool_base.h:215
KIGFX::VIEW * getView() const
Returns the instance of #VIEW object used in the application.
Definition: tool_base.cpp:36
Generic, UI-independent tool event.
Definition: tool_event.h:156
bool HasPosition() const
Definition: tool_event.h:243
bool DisableGridSnapping() const
Definition: tool_event.h:344
T Parameter() const
Return a non-standard parameter assigned to the event.
Definition: tool_event.h:442
const VECTOR2D Position() const
Returns the point where dragging has started.
Definition: tool_event.h:266
int Modifier(int aMask=MD_MODIFIER_MASK) const
Definition: tool_event.h:339
void SetContextMenu(ACTION_MENU *aMenu, CONTEXT_MENU_TRIGGER aTrigger=CMENU_BUTTON)
Assign a context menu and tells when it should be activated.
void Go(int(T::*aStateFunc)(const TOOL_EVENT &), const TOOL_EVENT_LIST &aConditions=TOOL_EVENT(TC_ANY, TA_ANY))
Define which state (aStateFunc) to go when a certain event arrives (aConditions).
TOOL_MENU & GetToolMenu()
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.
void Activate()
Run the tool.
void PostEvent(const TOOL_EVENT &aEvent)
Put an event to the event queue to be processed at the end of event processing cycle.
bool RunAction(const std::string &aActionName, bool aNow=false, T aParam=NULL)
Run the specified action.
Definition: tool_manager.h:142
void VetoContextMenuMouseWarp()
Disable mouse warping after the current context menu is closed.
Definition: tool_manager.h:424
CONDITIONAL_MENU & GetMenu()
Definition: tool_menu.cpp:44
void RegisterSubMenu(std::shared_ptr< ACTION_MENU > aSubMenu)
Store a submenu of this menu model.
Definition: tool_menu.cpp:50
void ShowContextMenu(SELECTION &aSelection)
Helper function to set and immediately show a CONDITIONAL_MENU in concert with the given SELECTION.
Definition: tool_menu.cpp:57
void Dismiss() override
Dismisses the infobar and updates the containing layout and AUI manager (if one is provided).
Definition: wx_infobar.cpp:175
#define _(s)
#define IS_NEW
New item, just created.
#define SKIP_STRUCT
flag indicating that the structure should be ignored
#define IS_MOVING
Item being moved.
@ LAYER_CONNECTABLE
@ ID_POPUP_SCH_UNFOLD_BUS_END
Definition: eeschema_id.h:91
@ ID_POPUP_SCH_UNFOLD_BUS
Definition: eeschema_id.h:90
LINE_MODE
@ LINE_MODE_90
@ LINE_MODE_45
@ LINE_MODE_FREE
@ LAYER_WIRE
Definition: layer_ids.h:344
@ LAYER_NOTES
Definition: layer_ids.h:358
@ LAYER_BUS
Definition: layer_ids.h:345
bool signbit(T v)
Integral version of std::signbit that works all compilers.
Definition: kicad_algo.h:197
EDA_ANGLE abs(const EDA_ANGLE &aAngle)
Definition: eda_angle.h:418
@ BUS
This item represents a bus vector.
SHEET_SIDE
Define the edge of the sheet that the sheet pin is positioned.
Definition: sch_sheet_pin.h:46
bool label_placed
True if user has placed the net label.
wxString net_name
Net label for the unfolding operation.
bool flipY
True if the bus entry should be flipped in the y-axis.
SCH_BUS_WIRE_ENTRY * entry
bool flipX
True if the bus entry should be flipped in the x-axis.
VECTOR2I origin
Origin (on the bus) of the unfold.
bool in_progress
True if bus unfold operation is running.
constexpr int delta
@ CMENU_NOW
Definition: tool_event.h:148
@ TA_CHOICE_MENU_CHOICE
Definition: tool_event.h:93
@ TA_CHOICE_MENU_CLOSED
Definition: tool_event.h:96
@ TC_COMMAND
Definition: tool_event.h:52
@ MD_SHIFT
Definition: tool_event.h:138
@ BUT_LEFT
Definition: tool_event.h:127
@ BUT_RIGHT
Definition: tool_event.h:128
bool IsPointOnSegment(const VECTOR2I &aSegStart, const VECTOR2I &aSegEnd, const VECTOR2I &aTestPoint)
Test if aTestPoint is on line defined by aSegStart and aSegEnd.
Definition: trigo.cpp:42
@ SCH_LINE_T
Definition: typeinfo.h:146
@ SCH_SYMBOL_T
Definition: typeinfo.h:156
@ SCH_ITEM_LOCATE_WIRE_T
Definition: typeinfo.h:170
@ SCH_SHEET_T
Definition: typeinfo.h:158
@ SCH_ITEM_LOCATE_BUS_T
Definition: typeinfo.h:171
@ SCH_ITEM_LOCATE_GRAPHIC_LINE_T
Definition: typeinfo.h:172
constexpr ret_type KiROUND(fp_type v)
Round a floating point number to an integer using "round halfway cases away from zero".
Definition: util.h:85
VECTOR2< double > VECTOR2D
Definition: vector2d.h:589
VECTOR2< int > VECTOR2I
Definition: vector2d.h:590