KiCad PCB EDA Suite
Loading...
Searching...
No Matches
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-2023 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/translation.h>
31#include <algorithm>
32#include <cstdlib>
33#include <iterator>
34#include <memory>
35#include <utility>
36#include <vector>
37
38#include <layer_ids.h>
39#include <math/vector2d.h>
40#include <advanced_config.h>
42#include <view/view_controls.h>
43#include <tool/actions.h>
45#include <tool/selection.h>
47#include <tool/tool_event.h>
48#include <trigo.h>
49#include <eeschema_id.h>
50#include <sch_bus_entry.h>
51#include <sch_connection.h>
52#include <sch_edit_frame.h>
53#include <sch_line.h>
54#include <sch_screen.h>
55#include <sch_sheet.h>
56#include <sch_sheet_pin.h>
57#include <schematic.h>
58#include <sch_commit.h>
59#include <ee_actions.h>
60#include <ee_grid_helper.h>
61#include <ee_selection.h>
62#include <ee_selection_tool.h>
63
64
65using BUS_GETTER = std::function<SCH_LINE*()>;
66
68{
69public:
75 ACTION_MENU( true ),
76 m_showTitle( false ),
77 m_busGetter( aBusGetter )
78 {
79 SetIcon( BITMAPS::add_line2bus );
80 SetTitle( _( "Unfold from Bus" ) );
81 }
82
84 {
85 m_showTitle = true;
86 }
87
88 bool PassHelpTextToHandler() override { return true; }
89
90protected:
91 ACTION_MENU* create() const override
92 {
93 return new BUS_UNFOLD_MENU( m_busGetter );
94 }
95
96private:
97 void update() override
98 {
99 SCH_LINE* bus = m_busGetter();
100 Clear();
101 // Pick up the pointer again because it may have been changed by SchematicCleanUp
102 bus = m_busGetter();
103
104 if( !bus )
105 {
106 Append( ID_POPUP_SCH_UNFOLD_BUS, _( "No bus selected" ), wxEmptyString );
107 Enable( ID_POPUP_SCH_UNFOLD_BUS, false );
108 return;
109 }
110
111 SCH_CONNECTION* connection = bus->Connection();
112
113 if( !connection || !connection->IsBus() || connection->Members().empty() )
114 {
115 Append( ID_POPUP_SCH_UNFOLD_BUS, _( "Bus has no members" ), wxEmptyString );
116 Enable( ID_POPUP_SCH_UNFOLD_BUS, false );
117 return;
118 }
119
120 int idx = 0;
121
122 if( m_showTitle )
123 {
124 Append( ID_POPUP_SCH_UNFOLD_BUS, _( "Unfold from Bus" ), wxEmptyString );
125 Enable( ID_POPUP_SCH_UNFOLD_BUS, false );
126 }
127
128 for( const std::shared_ptr<SCH_CONNECTION>& member : connection->Members() )
129 {
130 int id = ID_POPUP_SCH_UNFOLD_BUS + ( idx++ );
131 wxString name = member->FullLocalName();
132
133 if( member->Type() == CONNECTION_TYPE::BUS )
134 {
135 ACTION_MENU* submenu = new ACTION_MENU( true, m_tool );
136 AppendSubMenu( submenu, SCH_CONNECTION::PrintBusForUI( name ), name );
137
138 for( const std::shared_ptr<SCH_CONNECTION>& sub_member : member->Members() )
139 {
140 id = ID_POPUP_SCH_UNFOLD_BUS + ( idx++ );
141 name = sub_member->FullLocalName();
142 submenu->Append( id, SCH_CONNECTION::PrintBusForUI( name ), name );
143 }
144 }
145 else
146 {
147 Append( id, name, wxEmptyString );
148 }
149 }
150 }
151
154};
155
156
161{
163};
164
165
168};
169
170
172 EE_TOOL_BASE<SCH_EDIT_FRAME>( "eeschema.InteractiveDrawingLineWireBus" ),
173 m_inDrawingTool( false )
174{
175 m_busUnfold = {};
176 m_wires.reserve( 16 );
177}
178
179
181{
182}
183
184
186{
188
189 const auto busGetter = [this]()
190 {
191 return getBusForUnfolding();
192 };
193
194 std::shared_ptr<BUS_UNFOLD_MENU>
195 busUnfoldMenu = std::make_shared<BUS_UNFOLD_MENU>( busGetter );
196 busUnfoldMenu->SetTool( this );
197 m_menu->RegisterSubMenu( busUnfoldMenu );
198
199 std::shared_ptr<BUS_UNFOLD_MENU> selBusUnfoldMenu = std::make_shared<BUS_UNFOLD_MENU>( busGetter );
200 selBusUnfoldMenu->SetTool( m_selectionTool );
201 m_selectionTool->GetToolMenu().RegisterSubMenu( selBusUnfoldMenu );
202
203 auto wireOrBusTool =
204 [this]( const SELECTION& aSel )
205 {
208 };
209
210 auto lineTool =
211 [this]( const SELECTION& aSel )
212 {
214 };
215
216 auto belowRootSheetCondition =
217 [&]( const SELECTION& aSel )
218 {
219 return m_frame->GetCurrentSheet().Last() != &m_frame->Schematic().Root();
220 };
221
222 auto busSelection = EE_CONDITIONS::MoreThan( 0 )
224
225 auto haveHighlight =
226 [&]( const SELECTION& sel )
227 {
228 SCH_EDIT_FRAME* editFrame = dynamic_cast<SCH_EDIT_FRAME*>( m_frame );
229
230 return editFrame && !editFrame->GetHighlightedConnection().IsEmpty();
231 };
232
233 auto& ctxMenu = m_menu->GetMenu();
234
235 // Build the tool menu
236 //
237 ctxMenu.AddItem( EE_ACTIONS::clearHighlight, haveHighlight && EE_CONDITIONS::Idle, 1 );
238 ctxMenu.AddSeparator( haveHighlight && EE_CONDITIONS::Idle, 1 );
239
240 ctxMenu.AddSeparator( 10 );
241 ctxMenu.AddItem( EE_ACTIONS::drawWire, wireOrBusTool && EE_CONDITIONS::Idle, 10 );
242 ctxMenu.AddItem( EE_ACTIONS::drawBus, wireOrBusTool && EE_CONDITIONS::Idle, 10 );
243 ctxMenu.AddItem( EE_ACTIONS::drawLines, lineTool && EE_CONDITIONS::Idle, 10 );
244
248
249 ctxMenu.AddMenu( busUnfoldMenu.get(), EE_CONDITIONS::Idle, 10 );
250
251 ctxMenu.AddSeparator( 100 );
252 ctxMenu.AddItem( EE_ACTIONS::placeJunction, wireOrBusTool && EE_CONDITIONS::Idle, 100 );
253 ctxMenu.AddItem( EE_ACTIONS::placeLabel, wireOrBusTool && EE_CONDITIONS::Idle, 100 );
254 ctxMenu.AddItem( EE_ACTIONS::placeClassLabel, wireOrBusTool && EE_CONDITIONS::Idle, 100 );
255 ctxMenu.AddItem( EE_ACTIONS::placeGlobalLabel, wireOrBusTool && EE_CONDITIONS::Idle, 100 );
256 ctxMenu.AddItem( EE_ACTIONS::placeHierLabel, wireOrBusTool && EE_CONDITIONS::Idle, 100 );
257 ctxMenu.AddItem( EE_ACTIONS::breakWire, wireOrBusTool && EE_CONDITIONS::Idle, 100 );
258 ctxMenu.AddItem( EE_ACTIONS::slice, ( wireOrBusTool || lineTool )
259 && EE_CONDITIONS::Idle, 100 );
260 ctxMenu.AddItem( EE_ACTIONS::leaveSheet, belowRootSheetCondition, 150 );
261
262 ctxMenu.AddSeparator( 200 );
263 ctxMenu.AddItem( EE_ACTIONS::selectNode, wireOrBusTool && EE_CONDITIONS::Idle, 200 );
264 ctxMenu.AddItem( EE_ACTIONS::selectConnection, wireOrBusTool && EE_CONDITIONS::Idle, 200 );
265
266 // Add bus unfolding to the selection tool
267 //
269
270 selToolMenu.AddMenu( selBusUnfoldMenu.get(), busSelection && EE_CONDITIONS::Idle, 100 );
271
272 return true;
273}
274
275
277{
278 // NOTE: for immediate hotkeys, it is NOT required that the line, wire or bus tool
279 // be selected
280 SCH_ITEM* item = (SCH_ITEM*) aSelection.Front();
281 return item && item->IsNew() && item->Type() == SCH_LINE_T;
282}
283
284
286{
287 if( m_inDrawingTool )
288 return 0;
289
291
292 const DRAW_SEGMENT_EVENT_PARAMS* params = aEvent.Parameter<const DRAW_SEGMENT_EVENT_PARAMS*>();
293
294 m_frame->PushTool( aEvent );
296
297 if( aEvent.HasPosition() )
298 {
300 GRID_HELPER_GRIDS gridType = ( params->layer == LAYER_NOTES ) ? GRID_GRAPHICS : GRID_WIRES;
301
302 grid.SetSnap( !aEvent.Modifier( MD_SHIFT ) );
303 grid.SetUseGrid( getView()->GetGAL()->GetGridSnapping() && !aEvent.DisableGridSnapping() );
304
305 VECTOR2D cursorPos = grid.BestSnapAnchor( aEvent.Position(), gridType, nullptr );
306 startSegments( params->layer, cursorPos, params->sourceSegment );
307 }
308
309 return doDrawSegments( aEvent, params->layer, params->quitOnDraw );
310}
311
312
314{
315 if( m_inDrawingTool )
316 return 0;
317
319
320 wxString* netPtr = aEvent.Parameter<wxString*>();
321 wxString net;
322 SCH_LINE* segment = nullptr;
323
324 m_frame->PushTool( aEvent );
325 Activate();
326
327 if( netPtr )
328 {
329 net = *netPtr;
330 delete netPtr;
331 }
332 else
333 {
334 const auto busGetter = [this]()
335 {
336 return getBusForUnfolding();
337 };
338 BUS_UNFOLD_MENU unfoldMenu( busGetter );
339 unfoldMenu.SetTool( this );
340 unfoldMenu.SetShowTitle();
341
342 SetContextMenu( &unfoldMenu, CMENU_NOW );
343
344 while( TOOL_EVENT* evt = Wait() )
345 {
346 if( evt->Action() == TA_CHOICE_MENU_CHOICE )
347 {
348 std::optional<int> id = evt->GetCommandId();
349
350 if( id && ( *id > 0 ) )
351 net = *evt->Parameter<wxString*>();
352
353 break;
354 }
355 else if( evt->Action() == TA_CHOICE_MENU_CLOSED )
356 {
357 break;
358 }
359 else
360 {
361 evt->SetPassEvent();
362 }
363 }
364 }
365
366 // Break a wire for the given net out of the bus
367 if( !net.IsEmpty() )
368 segment = doUnfoldBus( net );
369
370 // If we have an unfolded wire to draw, then draw it
371 if( segment )
372 {
373 return doDrawSegments( aEvent, LAYER_WIRE, false );
374 }
375 else
376 {
377 m_frame->PopTool( aEvent );
378 return 0;
379 }
380}
381
382
384{
386 return static_cast<SCH_LINE*>( selection.Front() );
387}
388
389
391 const std::optional<VECTOR2I>& aPos )
392{
393 SCHEMATIC_SETTINGS& cfg = getModel<SCHEMATIC>()->Settings();
394 SCH_SCREEN* screen = m_frame->GetScreen();
395 // use the same function as the menu selector, so we choose the same bus segment
396 SCH_LINE* const bus = getBusForUnfolding();
397
398 if ( bus == nullptr )
399 {
400 wxASSERT_MSG( false,
401 wxString::Format( "Couldn't find the originating bus line (but had a net: %s )",
402 aNet ) );
403 return nullptr;
404 }
405
406 VECTOR2I pos = aPos.value_or( static_cast<VECTOR2I>( getViewControls()->GetCursorPosition() ) );
407
408 // It is possible for the position to be near the bus, but not exactly on it, but
409 // we need the bus entry to be on the bus exactly to connect.
410 // If the bus segment is H or V, this will be on the selection grid, if it's not,
411 // it might not be, but it won't be a broken connection (and the user asked for it!)
412 pos = bus->GetSeg().NearestPoint( pos );
413
415
417 m_busUnfold.entry->SetParent( screen );
419
425
427 m_busUnfold.origin = pos;
428 m_busUnfold.net_name = aNet;
429
431
432 std::vector<DANGLING_END_ITEM> endPointsByType;
433
434 for( SCH_ITEM* item : screen->Items().Overlapping( m_busUnfold.entry->GetBoundingBox() ) )
435 item->GetEndPoints( endPointsByType );
436
437 std::vector<DANGLING_END_ITEM> endPointsByPos = endPointsByType;
438 DANGLING_END_ITEM_HELPER::sort_dangling_end_items( endPointsByType, endPointsByPos );
439 m_busUnfold.entry->UpdateDanglingState( endPointsByType, endPointsByPos );
442
444}
445
446
448{
449 SCH_SCREEN* screen = m_frame->GetScreen();
450
451 for( SCH_ITEM* item : screen->Items().Overlapping( SCH_SHEET_T, aPosition ) )
452 {
453 SCH_SHEET* sheet = static_cast<SCH_SHEET*>( item );
454
455 for( SCH_SHEET_PIN* pin : sheet->GetPins() )
456 {
457 if( pin->GetPosition() == aPosition )
458 return pin;
459 }
460 }
461
462 return nullptr;
463}
464
465
466void SCH_LINE_WIRE_BUS_TOOL::computeBreakPoint( const std::pair<SCH_LINE*, SCH_LINE*>& aSegments,
467 VECTOR2I& aPosition,
468 LINE_MODE mode,
469 bool posture )
470{
471 wxCHECK_RET( aSegments.first && aSegments.second,
472 wxT( "Cannot compute break point of NULL line segment." ) );
473
474 VECTOR2I midPoint;
475 SCH_LINE* segment = aSegments.first;
476 SCH_LINE* nextSegment = aSegments.second;
477
478 VECTOR2I delta = aPosition - segment->GetStartPoint();
479 int xDir = delta.x > 0 ? 1 : -1;
480 int yDir = delta.y > 0 ? 1 : -1;
481
482
483 bool preferHorizontal;
484 bool preferVertical;
485
486 if( ( mode == LINE_MODE_45 ) && posture )
487 {
488 preferHorizontal = ( nextSegment->GetEndPoint().x - nextSegment->GetStartPoint().x ) != 0;
489 preferVertical = ( nextSegment->GetEndPoint().y - nextSegment->GetStartPoint().y ) != 0;
490 }
491 else
492 {
493 preferHorizontal = ( segment->GetEndPoint().x - segment->GetStartPoint().x ) != 0;
494 preferVertical = ( segment->GetEndPoint().y - segment->GetStartPoint().y ) != 0;
495 }
496
497 // Check for times we need to force horizontal sheet pin connections
498 const SCH_SHEET_PIN* connectedPin = getSheetPin( segment->GetStartPoint() );
499 SHEET_SIDE force = connectedPin ? connectedPin->GetSide() : SHEET_SIDE::UNDEFINED;
500
501 if( force == SHEET_SIDE::LEFT || force == SHEET_SIDE::RIGHT )
502 {
503 if( aPosition.x == connectedPin->GetPosition().x ) // push outside sheet boundary
504 {
505 int direction = ( force == SHEET_SIDE::LEFT ) ? -1 : 1;
506 aPosition.x += KiROUND( getView()->GetGAL()->GetGridSize().x * direction );
507 }
508
509 preferHorizontal = true;
510 preferVertical = false;
511 }
512
513
514 auto breakVertical = [&]() mutable
515 {
516 switch( mode )
517 {
518 case LINE_MODE_45:
519 if( !posture )
520 {
521 midPoint.x = segment->GetStartPoint().x;
522 midPoint.y = aPosition.y - yDir * abs( delta.x );
523 }
524 else
525 {
526 midPoint.x = aPosition.x;
527 midPoint.y = segment->GetStartPoint().y + yDir * abs( delta.x );
528 }
529 break;
530 default:
531 midPoint.x = segment->GetStartPoint().x;
532 midPoint.y = aPosition.y;
533 }
534 };
535
536
537 auto breakHorizontal = [&]() mutable
538 {
539 switch( mode )
540 {
541 case LINE_MODE_45:
542 if( !posture )
543 {
544 midPoint.x = aPosition.x - xDir * abs( delta.y );
545 midPoint.y = segment->GetStartPoint().y;
546 }
547 else
548 {
549 midPoint.x = segment->GetStartPoint().x + xDir * abs( delta.y );
550 midPoint.y = aPosition.y;
551 }
552 break;
553 default:
554 midPoint.x = aPosition.x;
555 midPoint.y = segment->GetStartPoint().y;
556 }
557 };
558
559
560 // Maintain current line shape if we can, e.g. if we were originally moving
561 // vertically keep the first segment vertical
562 if( preferVertical )
563 breakVertical();
564 else if( preferHorizontal )
565 breakHorizontal();
566
567 // Check if our 45 degree angle is one of these shapes
568 // /
569 // /
570 // /
571 // /__________
572 VECTOR2I deltaMidpoint = midPoint - segment->GetStartPoint();
573
574 if( mode == LINE_MODE::LINE_MODE_45 && !posture
575 && ( ( alg::signbit( deltaMidpoint.x ) != alg::signbit( delta.x ) )
576 || ( alg::signbit( deltaMidpoint.y ) != alg::signbit( delta.y ) ) ) )
577 {
578 preferVertical = false;
579 preferHorizontal = false;
580 }
581 else if( mode == LINE_MODE::LINE_MODE_45 && posture
582 && ( ( abs( deltaMidpoint.x ) > abs( delta.x ) )
583 || ( abs( deltaMidpoint.y ) > abs( delta.y ) ) ) )
584 {
585 preferVertical = false;
586 preferHorizontal = false;
587 }
588
589 if( !preferHorizontal && !preferVertical )
590 {
591 if( std::abs( delta.x ) < std::abs( delta.y ) )
592 breakVertical();
593 else
594 breakHorizontal();
595 }
596
597 segment->SetEndPoint( midPoint );
598 nextSegment->SetStartPoint( midPoint );
599 nextSegment->SetEndPoint( aPosition );
600}
601
602
603int SCH_LINE_WIRE_BUS_TOOL::doDrawSegments( const TOOL_EVENT& aTool, int aType, bool aQuitOnDraw )
604{
605 SCH_SCREEN* screen = m_frame->GetScreen();
606 SCH_LINE* segment = nullptr;
608 GRID_HELPER_GRIDS gridType = ( aType == LAYER_NOTES ) ? GRID_GRAPHICS : GRID_WIRES;
610 int lastMode = m_frame->eeconfig()->m_Drawing.line_mode;
611 static bool posture = false;
612
613 auto setCursor =
614 [&]()
615 {
616 if( aType == LAYER_WIRE )
617 m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::LINE_WIRE );
618 else if( aType == LAYER_BUS )
619 m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::LINE_BUS );
620 else if( aType == LAYER_NOTES )
621 m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::LINE_GRAPHIC );
622 else
623 m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::LINE_WIRE );
624 };
625
626 auto cleanup =
627 [&] ()
628 {
630
631 for( SCH_LINE* wire : m_wires )
632 delete wire;
633
634 m_wires.clear();
635 segment = nullptr;
636
637 if( m_busUnfold.entry )
639
642
645
646 delete m_busUnfold.entry;
647 delete m_busUnfold.label;
648 m_busUnfold = {};
649
651 m_view->ShowPreview( false );
652 };
653
654 Activate();
655 // Must be done after Activate() so that it gets set into the correct context
656 controls->ShowCursor( true );
657 // Set initial cursor
658 setCursor();
659
660 // Add the new label to the selection so the rotate command operates on it
661 if( m_busUnfold.label )
663
664 // Continue the existing wires if we've started (usually by immediate action preference)
665 if( !m_wires.empty() )
666 segment = m_wires.back();
667
668 VECTOR2I contextMenuPos;
669
670 // Main loop: keep receiving events
671 while( TOOL_EVENT* evt = Wait() )
672 {
674 bool twoSegments = currentMode != LINE_MODE::LINE_MODE_FREE;
675
676 // The tool hotkey is interpreted as a click when drawing
677 bool isSyntheticClick = ( segment || m_busUnfold.in_progress ) && evt->IsActivate()
678 && evt->HasPosition() && evt->Matches( aTool );
679
680 setCursor();
681 grid.SetMask( GRID_HELPER::ALL );
682 grid.SetSnap( !evt->Modifier( MD_SHIFT ) );
683 grid.SetUseGrid( getView()->GetGAL()->GetGridSnapping() && !evt->DisableGridSnapping() );
684
685 if( segment )
686 {
687 if( segment->GetStartPoint().x == segment->GetEndPoint().x )
688 grid.ClearMaskFlag( GRID_HELPER::VERTICAL );
689
690 if( segment->GetStartPoint().y == segment->GetEndPoint().y )
691 grid.ClearMaskFlag( GRID_HELPER::HORIZONTAL );
692 }
693
694 VECTOR2D eventPosition = evt->HasPosition() ? evt->Position()
695 : controls->GetMousePosition();
696
697 VECTOR2I cursorPos = grid.BestSnapAnchor( eventPosition, gridType, segment );
698 controls->ForceCursorPosition( true, cursorPos );
699
700 // Need to handle change in H/V mode while drawing
701 if( currentMode != lastMode )
702 {
703 // Need to delete extra segment if we have one
704 if( segment && currentMode == LINE_MODE::LINE_MODE_FREE && m_wires.size() >= 2 )
705 {
706 m_wires.pop_back();
708 delete segment;
709
710 segment = m_wires.back();
711 segment->SetEndPoint( cursorPos );
712 }
713 // Add a segment so we can move orthogonally/45
714 else if( segment && lastMode == LINE_MODE::LINE_MODE_FREE )
715 {
716 segment->SetEndPoint( cursorPos );
717
718 // Create a new segment, and chain it after the current segment.
719 segment = static_cast<SCH_LINE*>( segment->Duplicate() );
720 segment->SetFlags( IS_NEW | IS_MOVING );
721 segment->SetStartPoint( cursorPos );
722 m_wires.push_back( segment );
723
724 m_selectionTool->AddItemToSel( segment, true /*quiet mode*/ );
725 }
726
727 lastMode = currentMode;
728 }
729
730 //------------------------------------------------------------------------
731 // Handle cancel:
732 //
733 if( evt->IsCancelInteractive() )
734 {
736
737 if( segment || m_busUnfold.in_progress )
738 {
739 cleanup();
740
741 if( aQuitOnDraw )
742 {
743 m_frame->PopTool( aTool );
744 break;
745 }
746 }
747 else
748 {
749 m_frame->PopTool( aTool );
750 break;
751 }
752 }
753 else if( evt->IsActivate() && !isSyntheticClick )
754 {
755 if( segment || m_busUnfold.in_progress )
756 {
757 m_frame->ShowInfoBarMsg( _( "Press <ESC> to cancel drawing." ) );
758 evt->SetPassEvent( false );
759 continue;
760 }
761
762 if( evt->IsMoveTool() )
763 {
764 // leave ourselves on the stack so we come back after the move
765 break;
766 }
767 else
768 {
769 m_frame->PopTool( aTool );
770 break;
771 }
772 }
773 //------------------------------------------------------------------------
774 // Handle finish:
775 //
776 else if( evt->IsAction( &ACTIONS::finishInteractive ) )
777 {
778 if( segment || m_busUnfold.in_progress )
779 {
781 segment = nullptr;
782
783 if( aQuitOnDraw )
784 {
785 m_frame->PopTool( aTool );
786 break;
787 }
788 }
789 }
790 //------------------------------------------------------------------------
791 // Handle click:
792 //
793 else if( evt->IsClick( BUT_LEFT )
794 || ( segment && evt->IsDblClick( BUT_LEFT ) )
795 || isSyntheticClick )
796 {
797 // First click when unfolding places the label and wire-to-bus entry
799 {
800 wxASSERT( aType == LAYER_WIRE );
801
805 }
806
807 if( !segment )
808 {
809 segment = startSegments( aType, VECTOR2D( cursorPos ) );
810 }
811 // Create a new segment if we're out of previously-created ones
812 else if( !segment->IsNull()
813 || ( twoSegments && !m_wires[m_wires.size() - 2]->IsNull() ) )
814 {
815 // Terminate the command if the end point is on a pin, junction, label, or another
816 // wire or bus.
817 if( screen->IsTerminalPoint( cursorPos, segment->GetLayer() ) )
818 {
820 segment = nullptr;
821
822 if( aQuitOnDraw )
823 {
824 m_frame->PopTool( aTool );
825 break;
826 }
827 }
828 else
829 {
830 int placedSegments = 1;
831
832 // When placing lines with the forty-five degree end, the user is
833 // targetting the endpoint with the angled portion, so it's more
834 // intuitive to place both segments at the same time.
835 if( currentMode == LINE_MODE::LINE_MODE_45 )
836 placedSegments++;
837
838 segment->SetEndPoint( cursorPos );
839
840 for( int i = 0; i < placedSegments; i++ )
841 {
842 // Create a new segment, and chain it after the current segment.
843 segment = static_cast<SCH_LINE*>( segment->Duplicate() );
844 segment->SetFlags( IS_NEW | IS_MOVING );
845 segment->SetStartPoint( cursorPos );
846 m_wires.push_back( segment );
847
848 m_selectionTool->AddItemToSel( segment, true /*quiet mode*/ );
849 }
850 }
851 }
852
853 if( evt->IsDblClick( BUT_LEFT ) && segment )
854 {
855 if( twoSegments && m_wires.size() >= 2 )
856 {
857 computeBreakPoint( { m_wires[m_wires.size() - 2], segment }, cursorPos,
858 currentMode, posture );
859 }
860
862 segment = nullptr;
863
864 if( aQuitOnDraw )
865 {
866 m_frame->PopTool( aTool );
867 break;
868 }
869 }
870 }
871 //------------------------------------------------------------------------
872 // Handle motion:
873 //
874 else if( evt->IsMotion() || evt->IsAction( &ACTIONS::refreshPreview ) )
875 {
877
878 // Update the bus unfold posture based on the mouse movement
880 {
881 VECTOR2I cursor_delta = cursorPos - m_busUnfold.origin;
883
884 bool flipX = ( cursor_delta.x < 0 );
885 bool flipY = ( cursor_delta.y < 0 );
886
887 // Erase and redraw if necessary
888 if( flipX != m_busUnfold.flipX || flipY != m_busUnfold.flipY )
889 {
890 VECTOR2I size = entry->GetSize();
891 int ySign = flipY ? -1 : 1;
892 int xSign = flipX ? -1 : 1;
893
894 size.x = std::abs( size.x ) * xSign;
895 size.y = std::abs( size.y ) * ySign;
896 entry->SetSize( size );
897
898 m_busUnfold.flipY = flipY;
899 m_busUnfold.flipX = flipX;
900
901 m_frame->UpdateItem( entry, false, true );
902 m_wires.front()->SetStartPoint( entry->GetEnd() );
903 }
904
905 // Update the label "ghost" position
906 m_busUnfold.label->SetPosition( cursorPos );
908
909 // Ensure segment is non-null at the start of bus unfold
910 if( !segment )
911 segment = m_wires.back();
912 }
913
914 if( segment )
915 {
916 // Coerce the line to vertical/horizontal/45 as necessary
917 if( twoSegments && m_wires.size() >= 2 )
918 {
919 computeBreakPoint( { m_wires[m_wires.size() - 2], segment }, cursorPos,
920 currentMode, posture );
921 }
922 else
923 {
924 segment->SetEndPoint( cursorPos );
925 }
926 }
927
928 for( SCH_LINE* wire : m_wires )
929 {
930 if( !wire->IsNull() )
931 m_view->AddToPreview( wire->Clone() );
932 }
933 }
934 else if( evt->IsAction( &EE_ACTIONS::undoLastSegment )
935 || evt->IsAction( &ACTIONS::doDelete )
936 || evt->IsAction( &ACTIONS::undo ) )
937 {
938 if( ( currentMode == LINE_MODE::LINE_MODE_FREE && m_wires.size() > 1 )
939 || ( LINE_MODE::LINE_MODE_90 && m_wires.size() > 2 ) )
940 {
942
943 m_wires.pop_back();
945 delete segment;
946
947 segment = m_wires.back();
948 cursorPos = segment->GetEndPoint();
949 getViewControls()->WarpMouseCursor( cursorPos, true );
950
951 // Find new bend point for current mode
952 if( twoSegments && m_wires.size() >= 2 )
953 {
954 computeBreakPoint( { m_wires[m_wires.size() - 2], segment }, cursorPos,
955 currentMode, posture );
956 }
957 else
958 {
959 segment->SetEndPoint( cursorPos );
960 }
961
962 for( SCH_LINE* wire : m_wires )
963 {
964 if( !wire->IsNull() )
965 m_view->AddToPreview( wire->Clone() );
966 }
967 }
968 else if( evt->IsAction( &ACTIONS::undo ) )
969 {
970 // Dispatch as normal undo event
971 evt->SetPassEvent();
972 }
973 else
974 {
975 wxBell();
976 }
977 }
978 else if( evt->IsAction( &EE_ACTIONS::switchSegmentPosture ) && m_wires.size() >= 2 )
979 {
980 posture = !posture;
981
982 // The 90 degree mode doesn't have a forced posture like
983 // the 45 degree mode and computeBreakPoint maintains existing 90s' postures.
984 // Instead, just swap the 90 angle here.
985 if( currentMode == LINE_MODE::LINE_MODE_90 )
986 {
988
989 SCH_LINE* line2 = m_wires[m_wires.size() - 1];
990 SCH_LINE* line1 = m_wires[m_wires.size() - 2];
991
992 VECTOR2I delta2 = line2->GetEndPoint() - line2->GetStartPoint();
993 VECTOR2I delta1 = line1->GetEndPoint() - line1->GetStartPoint();
994
995 line2->SetStartPoint(line2->GetEndPoint() - delta1);
996 line1->SetEndPoint(line1->GetStartPoint() + delta2);
997
998 for( SCH_LINE* wire : m_wires )
999 {
1000 if( !wire->IsNull() )
1001 m_view->AddToPreview( wire->Clone() );
1002 }
1003 }
1004 else
1005 {
1006 computeBreakPoint( { m_wires[m_wires.size() - 2], segment }, cursorPos, currentMode,
1007 posture );
1008
1010 }
1011 }
1012 //------------------------------------------------------------------------
1013 // Handle context menu:
1014 //
1015 else if( evt->IsClick( BUT_RIGHT ) )
1016 {
1017 // Warp after context menu only if dragging...
1018 if( !segment )
1020
1021 contextMenuPos = cursorPos;
1022 m_menu->ShowContextMenu( m_selectionTool->GetSelection() );
1023 }
1024 else if( evt->Category() == TC_COMMAND && evt->Action() == TA_CHOICE_MENU_CHOICE )
1025 {
1026 if( *evt->GetCommandId() >= ID_POPUP_SCH_UNFOLD_BUS
1027 && *evt->GetCommandId() <= ID_POPUP_SCH_UNFOLD_BUS_END )
1028 {
1029 wxASSERT_MSG( !segment, "Bus unfold event received when already drawing!" );
1030
1031 aType = LAYER_WIRE;
1032 wxString net = *evt->Parameter<wxString*>();
1033 segment = doUnfoldBus( net, contextMenuPos );
1034 }
1035 }
1036 //------------------------------------------------------------------------
1037 // Handle TOOL_ACTION special cases
1038 //
1039 else if( evt->IsAction( &EE_ACTIONS::rotateCW ) || evt->IsAction( &EE_ACTIONS::rotateCCW ) )
1040 {
1042 {
1043 m_busUnfold.label->Rotate90( evt->IsAction( &EE_ACTIONS::rotateCW ) );
1045
1047 }
1048 else
1049 {
1050 wxBell();
1051 }
1052 }
1053 else if( evt->IsAction( &ACTIONS::redo ) )
1054 {
1055 wxBell();
1056 }
1057 else
1058 {
1059 evt->SetPassEvent();
1060 }
1061
1062 // Enable autopanning and cursor capture only when there is a segment to be placed
1063 controls->SetAutoPan( segment != nullptr );
1064 controls->CaptureCursor( segment != nullptr );
1065 }
1066
1067 controls->SetAutoPan( false );
1068 controls->CaptureCursor( false );
1069 m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::ARROW );
1070 controls->ForceCursorPosition( false );
1071 return 0;
1072}
1073
1074
1076 SCH_LINE* aSegment )
1077{
1078 if( !aSegment )
1079 aSegment = m_frame->GetScreen()->GetLine( aPos, 0, aType );
1080
1081 if( !aSegment )
1082 {
1083 switch( aType )
1084 {
1085 default: aSegment = new SCH_LINE( aPos, LAYER_NOTES ); break;
1086 case LAYER_WIRE: aSegment = new SCH_LINE( aPos, LAYER_WIRE ); break;
1087 case LAYER_BUS: aSegment = new SCH_LINE( aPos, LAYER_BUS ); break;
1088 }
1089
1090 // Give segments a parent so they find the default line/wire/bus widths
1091 aSegment->SetParent( &m_frame->Schematic() );
1092 }
1093 else
1094 {
1095 aSegment = static_cast<SCH_LINE*>( aSegment->Duplicate() );
1096 aSegment->SetStartPoint( aPos );
1097 }
1098
1099
1100 aSegment->SetFlags( IS_NEW | IS_MOVING );
1101 m_wires.push_back( aSegment );
1102
1103 m_selectionTool->AddItemToSel( aSegment, true /*quiet mode*/ );
1104
1105 // We need 2 segments to go from a given start pin to an end point when the
1106 // horizontal and vertical lines only switch is on.
1108 {
1109 aSegment = static_cast<SCH_LINE*>( aSegment->Duplicate() );
1110 aSegment->SetFlags( IS_NEW | IS_MOVING );
1111 m_wires.push_back( aSegment );
1112
1113 m_selectionTool->AddItemToSel( aSegment, true /*quiet mode*/ );
1114 }
1115
1116 return aSegment;
1117}
1118
1119
1134{
1135 for( auto it = m_wires.begin(); it != m_wires.end(); )
1136 {
1137 SCH_LINE* line = *it;
1138
1139 if( line->IsNull() )
1140 {
1141 delete line;
1142 it = m_wires.erase( it );
1143 continue;
1144 }
1145
1146 auto next_it = it;
1147 ++next_it;
1148
1149 if( next_it == m_wires.end() )
1150 break;
1151
1152 SCH_LINE* next_line = *next_it;
1153
1154 if( SCH_LINE* merged = line->MergeOverlap( m_frame->GetScreen(), next_line, false ) )
1155 {
1156 delete line;
1157 delete next_line;
1158 it = m_wires.erase( it );
1159 *it = merged;
1160 }
1161
1162 ++it;
1163 }
1164}
1165
1166
1168{
1169 // Clear selection when done so that a new wire can be started.
1170 // NOTE: this must be done before simplifyWireList is called or we might end up with
1171 // freed selected items.
1173
1174 SCH_SCREEN* screen = m_frame->GetScreen();
1175 SCH_COMMIT commit( m_toolMgr );
1176
1177 // Remove segments backtracking over others
1179
1180 // Collect the possible connection points for the new lines
1181 std::vector<VECTOR2I> connections = screen->GetConnections();
1182 std::vector<VECTOR2I> new_ends;
1183
1184 // Check each new segment for possible junctions and add/split if needed
1185 for( SCH_LINE* wire : m_wires )
1186 {
1187 if( wire->HasFlag( SKIP_STRUCT ) )
1188 continue;
1189
1190 std::vector<VECTOR2I> tmpends = wire->GetConnectionPoints();
1191
1192 new_ends.insert( new_ends.end(), tmpends.begin(), tmpends.end() );
1193
1194 for( const VECTOR2I& pt : connections )
1195 {
1196 if( IsPointOnSegment( wire->GetStartPoint(), wire->GetEndPoint(), pt ) )
1197 new_ends.push_back( pt );
1198 }
1199
1200 commit.Added( wire, screen );
1201 }
1202
1204 {
1205 wxASSERT( m_busUnfold.entry && m_busUnfold.label );
1206
1207 commit.Added( m_busUnfold.entry, screen );
1209
1210 commit.Added( m_busUnfold.label, screen );
1213 }
1214 else if( !m_wires.empty() )
1215 {
1217 }
1218
1219 for( size_t ii = 1; ii < m_wires.size(); ++ii )
1221
1222 // Get the last non-null wire (this is the last created segment).
1223 if( !m_wires.empty() )
1225
1226 // Add the new wires
1227 for( SCH_LINE* wire : m_wires )
1228 {
1229 wire->ClearFlags( IS_NEW | IS_MOVING );
1230 m_frame->AddToScreen( wire, screen );
1231 }
1232
1233 m_wires.clear();
1235 m_view->ShowPreview( false );
1236
1237 getViewControls()->CaptureCursor( false );
1238 getViewControls()->SetAutoPan( false );
1239
1240 // Correct and remove segments that need to be merged.
1241 m_frame->SchematicCleanUp( &commit );
1242
1243 std::vector<SCH_ITEM*> symbols;
1244
1245 for( SCH_ITEM* symbol : m_frame->GetScreen()->Items().OfType( SCH_SYMBOL_T ) )
1246 symbols.push_back( symbol );
1247
1248 for( SCH_ITEM* symbol : symbols )
1249 {
1250 std::vector<VECTOR2I> pts = symbol->GetConnectionPoints();
1251
1252 if( pts.size() > 2 )
1253 continue;
1254
1255 for( auto pt = pts.begin(); pt != pts.end(); pt++ )
1256 {
1257 for( auto secondPt = pt + 1; secondPt != pts.end(); secondPt++ )
1258 m_frame->TrimWire( &commit, *pt, *secondPt );
1259 }
1260 }
1261
1262 for( const VECTOR2I& pt : new_ends )
1263 {
1265 m_frame->AddJunction( &commit, m_frame->GetScreen(), pt );
1266 }
1267
1269 m_busUnfold = {};
1270
1271 for( SCH_ITEM* item : m_frame->GetScreen()->Items() )
1272 item->ClearEditFlags();
1273
1274 commit.Push( _( "Draw Wires" ) );
1275}
1276
1277
1279{
1280 SCHEMATIC* sch = getModel<SCHEMATIC>();
1281 SCH_SCREEN* screen = sch->CurrentSheet().LastScreen();
1282
1283 std::set<SCH_LINE*> lines;
1284 BOX2I bb = aSelection->GetBoundingBox();
1285
1286 for( EDA_ITEM* item : screen->Items().Overlapping( SCH_LINE_T, bb ) )
1287 lines.insert( static_cast<SCH_LINE*>( item ) );
1288
1289 for( unsigned ii = 0; ii < aSelection->GetSize(); ii++ )
1290 {
1291 SCH_ITEM* item = dynamic_cast<SCH_ITEM*>( aSelection->GetItem( ii ) );
1292
1293 if( !item || !item->IsConnectable() || ( item->Type() == SCH_LINE_T ) )
1294 continue;
1295
1296 std::vector<VECTOR2I> pts = item->GetConnectionPoints();
1297
1300 for( SCH_LINE* line : lines )
1301 {
1302 std::vector<VECTOR2I> conn_pts;
1303
1304 for( const VECTOR2I& pt : pts )
1305 {
1306 if( IsPointOnSegment( line->GetStartPoint(), line->GetEndPoint(), pt ) )
1307 conn_pts.push_back( pt );
1308
1309 if( conn_pts.size() > 2 )
1310 break;
1311 }
1312
1313 if( conn_pts.size() == 2 )
1314 m_frame->TrimWire( aCommit, conn_pts[0], conn_pts[1] );
1315 }
1316 }
1317
1318 return 0;
1319}
1320
1321
1323{
1324 SCH_SCREEN* screen = m_frame->GetScreen();
1325
1326 for( const VECTOR2I& point : screen->GetNeededJunctions( aSelection->Items() ) )
1327 m_frame->AddJunction( aCommit, m_frame->GetScreen(), point );
1328
1329 return 0;
1330}
1331
1332
1334{
1338
1340}
const char * name
Definition: DXF_plotter.cpp:57
constexpr BOX2I KiROUND(const BOX2D &aBoxD)
Definition: box2.h:990
static TOOL_ACTION undo
Definition: actions.h:68
static TOOL_ACTION doDelete
Definition: actions.h:78
static TOOL_ACTION redo
Definition: actions.h:69
static TOOL_ACTION refreshPreview
Definition: actions.h:149
static TOOL_ACTION finishInteractive
Definition: actions.h:66
Defines the structure of a menu based on ACTIONs.
Definition: action_menu.h:49
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:92
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:78
TOOL_INTERACTIVE * m_tool
Associates tool actions with menu item IDs. Non-owning.
Definition: action_menu.h:278
ACTION_MENU * create() const override
< Return an instance of this class. It has to be overridden in inheriting classes.
bool PassHelpTextToHandler() override
BUS_UNFOLD_MENU(BUS_GETTER aBusGetter)
void update() override
Update menu state stub.
COMMIT & Added(EDA_ITEM *aItem, BASE_SCREEN *aScreen=nullptr)
Remove a new item from the model.
Definition: commit.h:86
void AddMenu(ACTION_MENU *aMenu, const SELECTION_CONDITION &aCondition=SELECTION_CONDITIONS::ShowAlways, int aOrder=ANY_ORDER)
Add a submenu to the menu.
static void sort_dangling_end_items(std::vector< DANGLING_END_ITEM > &aItemListByType, std::vector< DANGLING_END_ITEM > &aItemListByPos)
Both contain the same information.
Definition: sch_item.cpp:615
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:89
virtual void ClearEditFlags()
Definition: eda_item.h:141
void SetFlags(EDA_ITEM_FLAGS aMask)
Definition: eda_item.h:127
KICAD_T Type() const
Returns the type of object.
Definition: eda_item.h:101
virtual void SetParent(EDA_ITEM *aParent)
Definition: eda_item.h:104
bool IsNew() const
Definition: eda_item.h:107
void SetTextSize(VECTOR2I aNewSize, bool aEnforceMinTextSize=true)
Definition: eda_text.cpp:419
static TOOL_ACTION clearHighlight
Definition: ee_actions.h:309
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:151
static TOOL_ACTION clearSelection
Clears the current selection.
Definition: ee_actions.h:56
static TOOL_ACTION placeClassLabel
Definition: ee_actions.h:90
static TOOL_ACTION drawWire
Definition: ee_actions.h:83
static TOOL_ACTION rotateCCW
Definition: ee_actions.h:131
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 drawLines
Definition: ee_actions.h:109
static TOOL_ACTION rotateCW
Definition: ee_actions.h:130
static TOOL_ACTION leaveSheet
Definition: ee_actions.h:233
static TOOL_ACTION placeGlobalLabel
Definition: ee_actions.h:91
static TOOL_ACTION placeHierLabel
Definition: ee_actions.h:92
static TOOL_ACTION undoLastSegment
Definition: ee_actions.h:111
static TOOL_ACTION unfoldBus
Definition: ee_actions.h:85
static TOOL_ACTION placeLabel
Definition: ee_actions.h:89
static TOOL_ACTION switchSegmentPosture
Definition: ee_actions.h:112
static TOOL_ACTION placeJunction
Definition: ee_actions.h:87
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 }, bool aPromoteCellSelections=false)
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:48
EE_SELECTION_TOOL * m_selectionTool
Definition: ee_tool_base.h:200
bool Init() override
Init() is called once upon a registration of the tool.
Definition: ee_tool_base.h:64
bool GetGridSnapping() const
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 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.
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:1745
GAL * GetGAL() const
Return the #GAL this view is using to draw graphical primitives.
Definition: view.h:203
void ClearPreview()
Definition: view.cpp:1709
void AddToPreview(VIEW_ITEM *aItem, bool aTakeOwnership=true)
Definition: view.cpp:1731
These are loaded from Eeschema settings but then overwritten by the project settings.
Holds all the data relating to one schematic.
Definition: schematic.h:77
SCH_SHEET_PATH & CurrentSheet() const override
Definition: schematic.h:152
SCH_SHEET & Root() const
Definition: schematic.h:121
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_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,...
VECTOR2I GetSize() const
Definition: sch_bus_entry.h:73
void SetSize(const VECTOR2I &aSize)
Definition: sch_bus_entry.h:74
void SetEndDangling(bool aDanglingState)
Definition: sch_bus_entry.h:46
VECTOR2I GetEnd() const
const BOX2I GetBoundingBox() const override
Return the orthogonal bounding box of this object for display purposes.
Class for a wire to bus entry.
bool UpdateDanglingState(std::vector< DANGLING_END_ITEM > &aItemListByType, std::vector< DANGLING_END_ITEM > &aItemListByPos, const SCH_SHEET_PATH *aPath=nullptr) override
Test the schematic item to aItemList to check if it's dangling state has changed.
virtual void Push(const wxString &aMessage=wxT("A commit"), int aCommitFlags=0) override
Revert the commit by restoring the modified items state.
Definition: sch_commit.cpp:432
Each graphical item can have a SCH_CONNECTION describing its logical connection (to a bus or net).
bool IsBus() const
const std::vector< std::shared_ptr< SCH_CONNECTION > > & Members() const
static wxString PrintBusForUI(const wxString &aString)
Schematic editor (Eeschema) main window.
SCH_SCREEN * GetScreen() const override
Return a pointer to a BASE_SCREEN or one of its derivatives.
void SchematicCleanUp(SCH_COMMIT *aCommit, SCH_SCREEN *aScreen=nullptr)
Perform routine schematic cleaning including breaking wire and buses and deleting identical objects s...
SCH_SHEET_PATH & GetCurrentSheet() const
SCHEMATIC & Schematic() const
const wxString & GetHighlightedConnection() const
void UpdateItem(EDA_ITEM *aItem, bool isAddOrDelete=false, bool aUpdateRtree=false) override
Mark an item for refresh.
bool TrimWire(SCH_COMMIT *aCommit, const VECTOR2I &aStart, const VECTOR2I &aEnd)
If any single wire passes through both points, remove the portion between the two points,...
void AddCopyForRepeatItem(const SCH_ITEM *aItem)
SCH_JUNCTION * AddJunction(SCH_COMMIT *aCommit, SCH_SCREEN *aScreen, const VECTOR2I &aPos)
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:166
virtual bool IsConnectable() const
Definition: sch_item.h:449
SCH_LAYER_ID GetLayer() const
Return the layer this item is on.
Definition: sch_item.h:281
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:221
virtual std::vector< VECTOR2I > GetConnectionPoints() const
Add all the connection points for this item to aPoints.
Definition: sch_item.h:464
SCH_ITEM * Duplicate(bool doClone=false) const
Routine to create a new copy of given item.
Definition: sch_item.cpp:131
void SetIsDangling(bool aIsDangling)
Definition: sch_label.h:325
SPIN_STYLE GetSpinStyle() const
Definition: sch_label.cpp:332
void SetPosition(const VECTOR2I &aPosition) override
Definition: sch_label.cpp:371
void Rotate90(bool aClockwise) override
Definition: sch_label.cpp:402
virtual void SetSpinStyle(SPIN_STYLE aSpinStyle)
Definition: sch_label.cpp:297
EDA_ITEM * Clone() const override
Create a duplicate of this item with linked list members set to NULL.
Definition: sch_label.h:411
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(SCH_COMMIT *aCommit, EE_SELECTION *aSelection)
Handle the addition of junctions to a selection of objects.
int UnfoldBus(const TOOL_EVENT &aEvent)
int doDrawSegments(const TOOL_EVENT &aTool, int aType, bool aQuitOnDraw)
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.
SCH_LINE * doUnfoldBus(const wxString &aNet, const std::optional< VECTOR2I > &aPos=std::nullopt)
Unfold the given bus from the given position.
SCH_LINE * getBusForUnfolding()
Choose a bus to unfold based on the current tool selection.
std::vector< SCH_LINE * > m_wires
int TrimOverLappingWires(SCH_COMMIT *aCommit, EE_SELECTION *aSelection)
Logic to remove wires when overlapping correct items.
static bool IsDrawingLineWireOrBus(const SELECTION &aSelection)
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...
Segment description base class to describe items which have 2 end points (track, wire,...
Definition: sch_line.h:41
void SetStartPoint(const VECTOR2I &aPosition)
Definition: sch_line.h:137
VECTOR2I GetEndPoint() const
Definition: sch_line.h:141
VECTOR2I GetStartPoint() const
Definition: sch_line.h:136
SEG GetSeg() const
Get the geometric aspect of the wire as a SEG.
Definition: sch_line.h:147
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:462
bool IsNull() const
Definition: sch_line.h:134
void SetEndPoint(const VECTOR2I &aPosition)
Definition: sch_line.h:142
SCH_LINE * GetLine(const VECTOR2I &aPosition, int aAccuracy=0, int aLayer=LAYER_NOTES, SCH_LINE_TEST_T aSearchType=ENTIRE_LENGTH_T) const
Return a line item located at aPosition.
EE_RTREE & Items()
Gets the full RTree, usually for iterating.
Definition: sch_screen.h:108
bool IsTerminalPoint(const VECTOR2I &aPosition, int aLayer) const
Test if aPosition is a connection point on aLayer.
Definition: sch_screen.cpp:601
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:496
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:181
VECTOR2I GetPosition() const override
Definition: sch_text.h:141
const VECTOR2I NearestPoint(const VECTOR2I &aP) const
Compute a point on the segment (this) that is closest to point aP.
Definition: seg.cpp:327
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:100
EDA_ITEM * Front() const
Definition: selection.h:172
std::deque< EDA_ITEM * > & Items()
Definition: selection.h:177
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:218
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:167
bool HasPosition() const
Definition: tool_event.h:256
bool DisableGridSnapping() const
Definition: tool_event.h:363
const VECTOR2D Position() const
Returns the point where dragging has started.
Definition: tool_event.h:285
int Modifier(int aMask=MD_MODIFIER_MASK) const
Definition: tool_event.h:358
T Parameter() const
Return a parameter assigned to the event.
Definition: tool_event.h:460
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()
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.
void Activate()
Run the tool.
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
bool PostAction(const std::string &aActionName, T aParam)
Run the specified action after the current action (coroutine) ends.
Definition: tool_manager.h:235
void VetoContextMenuMouseWarp()
Disable mouse warping after the current context menu is closed.
Definition: tool_manager.h:511
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 Dismiss() override
Dismisses the infobar and updates the containing layout and AUI manager (if one is provided).
Definition: wx_infobar.cpp:190
#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.
@ ID_POPUP_SCH_UNFOLD_BUS_END
Definition: eeschema_id.h:79
@ ID_POPUP_SCH_UNFOLD_BUS
Definition: eeschema_id.h:78
LINE_MODE
@ LINE_MODE_45
GRID_HELPER_GRIDS
Definition: grid_helper.h:42
@ GRID_GRAPHICS
Definition: grid_helper.h:50
@ GRID_WIRES
Definition: grid_helper.h:47
@ LAYER_WIRE
Definition: layer_ids.h:356
@ LAYER_NOTES
Definition: layer_ids.h:371
@ LAYER_BUS
Definition: layer_ids.h:357
bool signbit(T v)
Integral version of std::signbit that works all compilers.
Definition: kicad_algo.h:198
EDA_ANGLE abs(const EDA_ANGLE &aAngle)
Definition: eda_angle.h:390
std::function< SCH_LINE *()> BUS_GETTER
static BUS_UNFOLD_PERSISTENT_SETTINGS busUnfoldPersistentSettings
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.
Settings for bus unfolding that are persistent across invocations of the tool.
constexpr int delta
@ CMENU_NOW
Definition: tool_event.h:152
@ TA_CHOICE_MENU_CHOICE
Definition: tool_event.h:97
@ TA_CHOICE_MENU_CLOSED
Definition: tool_event.h:100
@ TC_COMMAND
Definition: tool_event.h:56
@ MD_SHIFT
Definition: tool_event.h:142
@ BUT_LEFT
Definition: tool_event.h:131
@ BUT_RIGHT
Definition: tool_event.h:132
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:89
@ SCH_LINE_T
Definition: typeinfo.h:163
@ SCH_SYMBOL_T
Definition: typeinfo.h:172
@ SCH_SHEET_T
Definition: typeinfo.h:174
@ SCH_ITEM_LOCATE_BUS_T
Definition: typeinfo.h:186
VECTOR2< int32_t > VECTOR2I
Definition: vector2d.h:691
VECTOR2< double > VECTOR2D
Definition: vector2d.h:690