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 The KiCad Developers, see AUTHORS.txt for contributors.
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, you may find one here:
19 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
20 * or you may search the http://www.gnu.org website for the version 2 license,
21 * or you may write to the Free Software Foundation, Inc.,
22 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
23 */
24
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_group.h>
57#include <sch_sheet_pin.h>
58#include <schematic.h>
59#include <sch_commit.h>
60#include <sch_actions.h>
61#include <ee_grid_helper.h>
62#include <sch_selection.h>
63#include <sch_selection_tool.h>
64
65
66using BUS_GETTER = std::function<SCH_LINE*()>;
67
69{
70public:
76 ACTION_MENU( true ),
77 m_showTitle( false ),
78 m_busGetter( aBusGetter )
79 {
80 SetIcon( BITMAPS::add_line2bus );
81 SetTitle( _( "Unfold from Bus" ) );
82 }
83
85 {
86 m_showTitle = true;
87 }
88
89 bool PassHelpTextToHandler() override { return true; }
90
91protected:
92 ACTION_MENU* create() const override
93 {
94 return new BUS_UNFOLD_MENU( m_busGetter );
95 }
96
97private:
98 void update() override
99 {
100 SCH_LINE* bus = m_busGetter();
101 Clear();
102 // Pick up the pointer again because it may have been changed by SchematicCleanUp
103 bus = m_busGetter();
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
155};
156
157
162{
164};
165
166
169};
170
171
173 SCH_TOOL_BASE<SCH_EDIT_FRAME>( "eeschema.InteractiveDrawingLineWireBus" ),
174 m_inDrawingTool( false )
175{
176 m_busUnfold = {};
177 m_wires.reserve( 16 );
178}
179
180
182{
183}
184
185
187{
189
190 const auto busGetter = [this]()
191 {
192 return getBusForUnfolding();
193 };
194
195 std::shared_ptr<BUS_UNFOLD_MENU>
196 busUnfoldMenu = std::make_shared<BUS_UNFOLD_MENU>( busGetter );
197 busUnfoldMenu->SetTool( this );
198 m_menu->RegisterSubMenu( busUnfoldMenu );
199
200 std::shared_ptr<BUS_UNFOLD_MENU> selBusUnfoldMenu = std::make_shared<BUS_UNFOLD_MENU>( busGetter );
201 selBusUnfoldMenu->SetTool( m_selectionTool );
202 m_selectionTool->GetToolMenu().RegisterSubMenu( selBusUnfoldMenu );
203
204 auto wireOrBusTool =
205 [this]( const SELECTION& aSel )
206 {
209 };
210
211 auto lineTool =
212 [this]( const SELECTION& aSel )
213 {
215 };
216
217 auto belowRootSheetCondition =
218 [&]( const SELECTION& aSel )
219 {
220 return m_frame->GetCurrentSheet().Last() != &m_frame->Schematic().Root();
221 };
222
223 auto busSelection = SCH_CONDITIONS::MoreThan( 0 )
225
226 auto haveHighlight =
227 [&]( const SELECTION& sel )
228 {
229 SCH_EDIT_FRAME* editFrame = dynamic_cast<SCH_EDIT_FRAME*>( m_frame );
230
231 return editFrame && !editFrame->GetHighlightedConnection().IsEmpty();
232 };
233
234 auto& ctxMenu = m_menu->GetMenu();
235
236 // Build the tool menu
237 //
238 ctxMenu.AddItem( SCH_ACTIONS::clearHighlight, haveHighlight && SCH_CONDITIONS::Idle, 1 );
239 ctxMenu.AddSeparator( haveHighlight && SCH_CONDITIONS::Idle, 1 );
240
241 ctxMenu.AddSeparator( 10 );
242 ctxMenu.AddItem( SCH_ACTIONS::drawWire, wireOrBusTool && SCH_CONDITIONS::Idle, 10 );
243 ctxMenu.AddItem( SCH_ACTIONS::drawBus, wireOrBusTool && SCH_CONDITIONS::Idle, 10 );
244 ctxMenu.AddItem( SCH_ACTIONS::drawLines, lineTool && SCH_CONDITIONS::Idle, 10 );
245
249
250 ctxMenu.AddMenu( busUnfoldMenu.get(), SCH_CONDITIONS::Idle, 10 );
251
252 ctxMenu.AddSeparator( 100 );
253 ctxMenu.AddItem( SCH_ACTIONS::placeJunction, wireOrBusTool && SCH_CONDITIONS::Idle, 100 );
254 ctxMenu.AddItem( SCH_ACTIONS::placeLabel, wireOrBusTool && SCH_CONDITIONS::Idle, 100 );
255 ctxMenu.AddItem( SCH_ACTIONS::placeClassLabel, wireOrBusTool && SCH_CONDITIONS::Idle, 100 );
256 ctxMenu.AddItem( SCH_ACTIONS::placeGlobalLabel, wireOrBusTool && SCH_CONDITIONS::Idle, 100 );
257 ctxMenu.AddItem( SCH_ACTIONS::placeHierLabel, wireOrBusTool && SCH_CONDITIONS::Idle, 100 );
258 ctxMenu.AddItem( SCH_ACTIONS::breakWire, wireOrBusTool && SCH_CONDITIONS::Idle, 100 );
259 ctxMenu.AddItem( SCH_ACTIONS::slice, ( wireOrBusTool || lineTool )
260 && SCH_CONDITIONS::Idle, 100 );
261 ctxMenu.AddItem( SCH_ACTIONS::leaveSheet, belowRootSheetCondition, 150 );
262
263 ctxMenu.AddSeparator( 200 );
264 ctxMenu.AddItem( SCH_ACTIONS::selectNode, wireOrBusTool && SCH_CONDITIONS::Idle, 200 );
265 ctxMenu.AddItem( SCH_ACTIONS::selectConnection, wireOrBusTool && SCH_CONDITIONS::Idle, 200 );
266
267 // Add bus unfolding to the selection tool
268 //
270
271 selToolMenu.AddMenu( selBusUnfoldMenu.get(), busSelection && SCH_CONDITIONS::Idle, 100 );
272
273 return true;
274}
275
276
278{
279 // NOTE: for immediate hotkeys, it is NOT required that the line, wire or bus tool
280 // be selected
281 SCH_ITEM* item = (SCH_ITEM*) aSelection.Front();
282 return item && item->IsNew() && item->Type() == SCH_LINE_T;
283}
284
285
287{
288 if( m_inDrawingTool )
289 return 0;
290
292
293 const DRAW_SEGMENT_EVENT_PARAMS* params = aEvent.Parameter<const DRAW_SEGMENT_EVENT_PARAMS*>();
294 SCH_COMMIT commit( m_toolMgr );
295
296 m_frame->PushTool( aEvent );
298
299 if( aEvent.HasPosition() )
300 {
302 GRID_HELPER_GRIDS gridType = ( params->layer == LAYER_NOTES ) ? GRID_GRAPHICS : GRID_WIRES;
303
304 grid.SetSnap( !aEvent.Modifier( MD_SHIFT ) );
305 grid.SetUseGrid( getView()->GetGAL()->GetGridSnapping() && !aEvent.DisableGridSnapping() );
306
307 VECTOR2D cursorPos = grid.BestSnapAnchor( aEvent.Position(), gridType, nullptr );
308 startSegments( commit, params->layer, cursorPos, params->sourceSegment );
309 }
310
311 return doDrawSegments( aEvent, commit, params->layer, params->quitOnDraw );
312}
313
314
316{
317 if( m_inDrawingTool )
318 return 0;
319
321
322 SCH_COMMIT commit( m_toolMgr );
323 wxString* netPtr = aEvent.Parameter<wxString*>();
324 wxString net;
325 SCH_LINE* segment = nullptr;
326
327 m_frame->PushTool( aEvent );
328 Activate();
329
330 if( netPtr )
331 {
332 net = *netPtr;
333 delete netPtr;
334 }
335 else
336 {
337 const auto busGetter = [this]()
338 {
339 return getBusForUnfolding();
340 };
341 BUS_UNFOLD_MENU unfoldMenu( busGetter );
342 unfoldMenu.SetTool( this );
343 unfoldMenu.SetShowTitle();
344
345 SetContextMenu( &unfoldMenu, CMENU_NOW );
346
347 while( TOOL_EVENT* evt = Wait() )
348 {
349 if( evt->Action() == TA_CHOICE_MENU_CHOICE )
350 {
351 std::optional<int> id = evt->GetCommandId();
352
353 if( id && ( *id > 0 ) )
354 net = *evt->Parameter<wxString*>();
355
356 break;
357 }
358 else if( evt->Action() == TA_CHOICE_MENU_CLOSED )
359 {
360 break;
361 }
362 else
363 {
364 evt->SetPassEvent();
365 }
366 }
367 }
368
369 // Break a wire for the given net out of the bus
370 if( !net.IsEmpty() )
371 segment = doUnfoldBus( commit, net );
372
373 // If we have an unfolded wire to draw, then draw it
374 if( segment )
375 {
376 return doDrawSegments( aEvent, commit, LAYER_WIRE, false );
377 }
378 else
379 {
380 m_frame->PopTool( aEvent );
381 return 0;
382 }
383}
384
385
387{
389 return static_cast<SCH_LINE*>( selection.Front() );
390}
391
392
394 const std::optional<VECTOR2I>& aPos )
395{
396 SCHEMATIC_SETTINGS& cfg = getModel<SCHEMATIC>()->Settings();
397 SCH_SCREEN* screen = m_frame->GetScreen();
398 // use the same function as the menu selector, so we choose the same bus segment
399 SCH_LINE* const bus = getBusForUnfolding();
400
401 if ( bus == nullptr )
402 {
403 wxASSERT_MSG( false, wxString::Format( "Couldn't find the originating bus line (but had a net: %s )",
404 aNet ) );
405 return nullptr;
406 }
407
408 VECTOR2I pos = aPos.value_or( static_cast<VECTOR2I>( getViewControls()->GetCursorPosition() ) );
409
410 // It is possible for the position to be near the bus, but not exactly on it, but
411 // we need the bus entry to be on the bus exactly to connect.
412 // If the bus segment is H or V, this will be on the selection grid, if it's not,
413 // it might not be, but it won't be a broken connection (and the user asked for it!)
414 pos = bus->GetSeg().NearestPoint( pos );
415
417
419 m_busUnfold.entry->SetParent( screen );
421
427
429 m_busUnfold.origin = pos;
430 m_busUnfold.net_name = aNet;
431
433
434 std::vector<DANGLING_END_ITEM> endPointsByType;
435
436 for( SCH_ITEM* item : screen->Items().Overlapping( m_busUnfold.entry->GetBoundingBox() ) )
437 item->GetEndPoints( endPointsByType );
438
439 std::vector<DANGLING_END_ITEM> endPointsByPos = endPointsByType;
440 DANGLING_END_ITEM_HELPER::sort_dangling_end_items( endPointsByType, endPointsByPos );
441 m_busUnfold.entry->UpdateDanglingState( endPointsByType, endPointsByPos );
444
445 return startSegments( aCommit, LAYER_WIRE, m_busUnfold.entry->GetEnd() );
446}
447
448
450{
451 SCH_SCREEN* screen = m_frame->GetScreen();
452
453 for( SCH_ITEM* item : screen->Items().Overlapping( SCH_SHEET_T, aPosition ) )
454 {
455 SCH_SHEET* sheet = static_cast<SCH_SHEET*>( item );
456
457 for( SCH_SHEET_PIN* pin : sheet->GetPins() )
458 {
459 if( pin->GetPosition() == aPosition )
460 return pin;
461 }
462 }
463
464 return nullptr;
465}
466
467
468void SCH_LINE_WIRE_BUS_TOOL::computeBreakPoint( const std::pair<SCH_LINE*, SCH_LINE*>& aSegments,
469 VECTOR2I& aPosition,
470 LINE_MODE mode,
471 bool posture )
472{
473 wxCHECK_RET( aSegments.first && aSegments.second,
474 wxT( "Cannot compute break point of NULL line segment." ) );
475
476 VECTOR2I midPoint;
477 SCH_LINE* segment = aSegments.first;
478 SCH_LINE* nextSegment = aSegments.second;
479
480 VECTOR2I delta = aPosition - segment->GetStartPoint();
481 int xDir = delta.x > 0 ? 1 : -1;
482 int yDir = delta.y > 0 ? 1 : -1;
483
484
485 bool preferHorizontal;
486 bool preferVertical;
487
488 if( ( mode == LINE_MODE_45 ) && posture )
489 {
490 preferHorizontal = ( nextSegment->GetEndPoint().x - nextSegment->GetStartPoint().x ) != 0;
491 preferVertical = ( nextSegment->GetEndPoint().y - nextSegment->GetStartPoint().y ) != 0;
492 }
493 else
494 {
495 preferHorizontal = ( segment->GetEndPoint().x - segment->GetStartPoint().x ) != 0;
496 preferVertical = ( segment->GetEndPoint().y - segment->GetStartPoint().y ) != 0;
497 }
498
499 // Check for times we need to force horizontal sheet pin connections
500 const SCH_SHEET_PIN* connectedPin = getSheetPin( segment->GetStartPoint() );
501 SHEET_SIDE force = connectedPin ? connectedPin->GetSide() : SHEET_SIDE::UNDEFINED;
502
503 if( force == SHEET_SIDE::LEFT || force == SHEET_SIDE::RIGHT )
504 {
505 if( aPosition.x == connectedPin->GetPosition().x ) // push outside sheet boundary
506 {
507 int direction = ( force == SHEET_SIDE::LEFT ) ? -1 : 1;
508 aPosition.x += KiROUND( getView()->GetGAL()->GetGridSize().x * direction );
509 }
510
511 preferHorizontal = true;
512 preferVertical = false;
513 }
514
515
516 auto breakVertical = [&]() mutable
517 {
518 switch( mode )
519 {
520 case LINE_MODE_45:
521 if( !posture )
522 {
523 midPoint.x = segment->GetStartPoint().x;
524 midPoint.y = aPosition.y - yDir * abs( delta.x );
525 }
526 else
527 {
528 midPoint.x = aPosition.x;
529 midPoint.y = segment->GetStartPoint().y + yDir * abs( delta.x );
530 }
531 break;
532 default:
533 midPoint.x = segment->GetStartPoint().x;
534 midPoint.y = aPosition.y;
535 }
536 };
537
538
539 auto breakHorizontal = [&]() mutable
540 {
541 switch( mode )
542 {
543 case LINE_MODE_45:
544 if( !posture )
545 {
546 midPoint.x = aPosition.x - xDir * abs( delta.y );
547 midPoint.y = segment->GetStartPoint().y;
548 }
549 else
550 {
551 midPoint.x = segment->GetStartPoint().x + xDir * abs( delta.y );
552 midPoint.y = aPosition.y;
553 }
554 break;
555 default:
556 midPoint.x = aPosition.x;
557 midPoint.y = segment->GetStartPoint().y;
558 }
559 };
560
561
562 // Maintain current line shape if we can, e.g. if we were originally moving
563 // vertically keep the first segment vertical
564 if( preferVertical )
565 breakVertical();
566 else if( preferHorizontal )
567 breakHorizontal();
568
569 // Check if our 45 degree angle is one of these shapes
570 // /
571 // /
572 // /
573 // /__________
574 VECTOR2I deltaMidpoint = midPoint - segment->GetStartPoint();
575
576 if( mode == LINE_MODE::LINE_MODE_45 && !posture
577 && ( ( alg::signbit( deltaMidpoint.x ) != alg::signbit( delta.x ) )
578 || ( alg::signbit( deltaMidpoint.y ) != alg::signbit( delta.y ) ) ) )
579 {
580 preferVertical = false;
581 preferHorizontal = false;
582 }
583 else if( mode == LINE_MODE::LINE_MODE_45 && posture
584 && ( ( abs( deltaMidpoint.x ) > abs( delta.x ) )
585 || ( abs( deltaMidpoint.y ) > abs( delta.y ) ) ) )
586 {
587 preferVertical = false;
588 preferHorizontal = false;
589 }
590
591 if( !preferHorizontal && !preferVertical )
592 {
593 if( std::abs( delta.x ) < std::abs( delta.y ) )
594 breakVertical();
595 else
596 breakHorizontal();
597 }
598
599 segment->SetEndPoint( midPoint );
600 nextSegment->SetStartPoint( midPoint );
601 nextSegment->SetEndPoint( aPosition );
602}
603
604
606 int aType, bool aQuitOnDraw )
607{
608 SCH_SCREEN* screen = m_frame->GetScreen();
609 SCH_LINE* segment = nullptr;
611 GRID_HELPER_GRIDS gridType = ( aType == LAYER_NOTES ) ? GRID_GRAPHICS : GRID_WIRES;
613 int lastMode = m_frame->eeconfig()->m_Drawing.line_mode;
614 static bool posture = false;
615
616 auto setCursor =
617 [&]()
618 {
619 if( aType == LAYER_WIRE )
620 m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::LINE_WIRE );
621 else if( aType == LAYER_BUS )
622 m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::LINE_BUS );
623 else if( aType == LAYER_NOTES )
624 m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::LINE_GRAPHIC );
625 else
626 m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::LINE_WIRE );
627 };
628
629 auto cleanup =
630 [&] ()
631 {
633
634 for( SCH_LINE* wire : m_wires )
635 delete wire;
636
637 m_wires.clear();
638 segment = nullptr;
639
640 if( m_busUnfold.entry )
642
645
648
649 delete m_busUnfold.entry;
650 delete m_busUnfold.label;
651 m_busUnfold = {};
652
654 m_view->ShowPreview( false );
655 };
656
657 Activate();
658 // Must be done after Activate() so that it gets set into the correct context
659 controls->ShowCursor( true );
660 // Set initial cursor
661 setCursor();
662
663 // Add the new label to the selection so the rotate command operates on it
664 if( m_busUnfold.label )
666
667 // Continue the existing wires if we've started (usually by immediate action preference)
668 if( !m_wires.empty() )
669 segment = m_wires.back();
670
671 VECTOR2I contextMenuPos;
672
673 // Main loop: keep receiving events
674 while( TOOL_EVENT* evt = Wait() )
675 {
677 bool twoSegments = currentMode != LINE_MODE::LINE_MODE_FREE;
678
679 // The tool hotkey is interpreted as a click when drawing
680 bool isSyntheticClick = ( segment || m_busUnfold.in_progress ) && evt->IsActivate()
681 && evt->HasPosition() && evt->Matches( aTool );
682
683 setCursor();
684 grid.SetMask( GRID_HELPER::ALL );
685 grid.SetSnap( !evt->Modifier( MD_SHIFT ) );
686 grid.SetUseGrid( getView()->GetGAL()->GetGridSnapping() && !evt->DisableGridSnapping() );
687
688 if( segment )
689 {
690 if( segment->GetStartPoint().x == segment->GetEndPoint().x )
691 grid.ClearMaskFlag( GRID_HELPER::VERTICAL );
692
693 if( segment->GetStartPoint().y == segment->GetEndPoint().y )
694 grid.ClearMaskFlag( GRID_HELPER::HORIZONTAL );
695 }
696
697 VECTOR2D eventPosition = evt->HasPosition() ? evt->Position()
698 : controls->GetMousePosition();
699
700 VECTOR2I cursorPos = grid.BestSnapAnchor( eventPosition, gridType, segment );
701 controls->ForceCursorPosition( true, cursorPos );
702
703 // Need to handle change in H/V mode while drawing
704 if( currentMode != lastMode )
705 {
706 // Need to delete extra segment if we have one
707 if( segment && currentMode == LINE_MODE::LINE_MODE_FREE && m_wires.size() >= 2 )
708 {
709 m_wires.pop_back();
711 delete segment;
712
713 segment = m_wires.back();
714 segment->SetEndPoint( cursorPos );
715 }
716 // Add a segment so we can move orthogonally/45
717 else if( segment && lastMode == LINE_MODE::LINE_MODE_FREE )
718 {
719 segment->SetEndPoint( cursorPos );
720
721 // Create a new segment, and chain it after the current segment.
722 segment = static_cast<SCH_LINE*>( segment->Duplicate( true, &aCommit ) );
723 segment->SetFlags( IS_NEW | IS_MOVING );
724 segment->SetStartPoint( cursorPos );
725 m_wires.push_back( segment );
726
727 m_selectionTool->AddItemToSel( segment, true /*quiet mode*/ );
728 }
729
730 lastMode = currentMode;
731 }
732
733 //------------------------------------------------------------------------
734 // Handle cancel:
735 //
736 if( evt->IsCancelInteractive() )
737 {
739
740 if( segment || m_busUnfold.in_progress )
741 {
742 cleanup();
743
744 if( aQuitOnDraw )
745 {
746 m_frame->PopTool( aTool );
747 break;
748 }
749 }
750 else
751 {
752 m_frame->PopTool( aTool );
753 break;
754 }
755 }
756 else if( evt->IsActivate() && !isSyntheticClick )
757 {
758 if( segment || m_busUnfold.in_progress )
759 {
760 m_frame->ShowInfoBarMsg( _( "Press <ESC> to cancel drawing." ) );
761 evt->SetPassEvent( false );
762 continue;
763 }
764
765 if( evt->IsMoveTool() )
766 {
767 // leave ourselves on the stack so we come back after the move
768 break;
769 }
770 else
771 {
772 m_frame->PopTool( aTool );
773 break;
774 }
775 }
776 //------------------------------------------------------------------------
777 // Handle finish:
778 //
779 else if( evt->IsAction( &ACTIONS::finishInteractive ) )
780 {
781 if( segment || m_busUnfold.in_progress )
782 {
783 finishSegments( aCommit );
784 segment = nullptr;
785
786 aCommit.Push( _( "Draw Wires" ) );
787
788 if( aQuitOnDraw )
789 {
790 m_frame->PopTool( aTool );
791 break;
792 }
793 }
794 }
795 //------------------------------------------------------------------------
796 // Handle click:
797 //
798 else if( evt->IsClick( BUT_LEFT )
799 || ( segment && evt->IsDblClick( BUT_LEFT ) )
800 || isSyntheticClick )
801 {
802 // First click when unfolding places the label and wire-to-bus entry
804 {
805 wxASSERT( aType == LAYER_WIRE );
806
810 }
811
812 if( !segment )
813 {
814 segment = startSegments( aCommit, aType, VECTOR2D( cursorPos ) );
815 }
816 // Create a new segment if we're out of previously-created ones
817 else if( !segment->IsNull()
818 || ( twoSegments && !m_wires[m_wires.size() - 2]->IsNull() ) )
819 {
820 // Terminate the command if the end point is on a pin, junction, label, or another
821 // wire or bus.
822 if( screen->IsTerminalPoint( cursorPos, segment->GetLayer() ) )
823 {
824 finishSegments( aCommit );
825 segment = nullptr;
826
827 aCommit.Push( _( "Draw Wires" ) );
828
829 if( aQuitOnDraw )
830 {
831 m_frame->PopTool( aTool );
832 break;
833 }
834 }
835 else
836 {
837 int placedSegments = 1;
838
839 // When placing lines with the forty-five degree end, the user is
840 // targetting the endpoint with the angled portion, so it's more
841 // intuitive to place both segments at the same time.
842 if( currentMode == LINE_MODE::LINE_MODE_45 )
843 placedSegments++;
844
845 segment->SetEndPoint( cursorPos );
846
847 for( int i = 0; i < placedSegments; i++ )
848 {
849 // Create a new segment, and chain it after the current segment.
850 segment = static_cast<SCH_LINE*>( segment->Duplicate( true, &aCommit ) );
851 segment->SetFlags( IS_NEW | IS_MOVING );
852 segment->SetStartPoint( cursorPos );
853 m_wires.push_back( segment );
854
855 m_selectionTool->AddItemToSel( segment, true /*quiet mode*/ );
856 }
857 }
858 }
859
860 if( evt->IsDblClick( BUT_LEFT ) && segment )
861 {
862 if( twoSegments && m_wires.size() >= 2 )
863 {
864 computeBreakPoint( { m_wires[m_wires.size() - 2], segment }, cursorPos,
865 currentMode, posture );
866 }
867
868 finishSegments( aCommit );
869 segment = nullptr;
870
871 aCommit.Push( _( "Draw Wires" ) );
872
873 if( aQuitOnDraw )
874 {
875 m_frame->PopTool( aTool );
876 break;
877 }
878 }
879 }
880 //------------------------------------------------------------------------
881 // Handle motion:
882 //
883 else if( evt->IsMotion() || evt->IsAction( &ACTIONS::refreshPreview ) )
884 {
886
887 // Update the bus unfold posture based on the mouse movement
889 {
890 VECTOR2I cursor_delta = cursorPos - m_busUnfold.origin;
892
893 bool flipX = ( cursor_delta.x < 0 );
894 bool flipY = ( cursor_delta.y < 0 );
895
896 // Erase and redraw if necessary
897 if( flipX != m_busUnfold.flipX || flipY != m_busUnfold.flipY )
898 {
899 VECTOR2I size = entry->GetSize();
900 int ySign = flipY ? -1 : 1;
901 int xSign = flipX ? -1 : 1;
902
903 size.x = std::abs( size.x ) * xSign;
904 size.y = std::abs( size.y ) * ySign;
905 entry->SetSize( size );
906
907 m_busUnfold.flipY = flipY;
908 m_busUnfold.flipX = flipX;
909
910 m_frame->UpdateItem( entry, false, true );
911 m_wires.front()->SetStartPoint( entry->GetEnd() );
912 }
913
914 // Update the label "ghost" position
915 m_busUnfold.label->SetPosition( cursorPos );
917
918 // Ensure segment is non-null at the start of bus unfold
919 if( !segment )
920 segment = m_wires.back();
921 }
922
923 if( segment )
924 {
925 // Coerce the line to vertical/horizontal/45 as necessary
926 if( twoSegments && m_wires.size() >= 2 )
927 {
928 computeBreakPoint( { m_wires[m_wires.size() - 2], segment }, cursorPos,
929 currentMode, posture );
930 }
931 else
932 {
933 segment->SetEndPoint( cursorPos );
934 }
935 }
936
937 for( SCH_LINE* wire : m_wires )
938 {
939 if( !wire->IsNull() )
940 m_view->AddToPreview( wire->Clone() );
941 }
942 }
943 else if( evt->IsAction( &SCH_ACTIONS::undoLastSegment )
944 || evt->IsAction( &ACTIONS::doDelete )
945 || evt->IsAction( &ACTIONS::undo ) )
946 {
947 if( ( currentMode == LINE_MODE::LINE_MODE_FREE && m_wires.size() > 1 )
948 || ( LINE_MODE::LINE_MODE_90 && m_wires.size() > 2 ) )
949 {
951
952 m_wires.pop_back();
954 delete segment;
955
956 segment = m_wires.back();
957 cursorPos = segment->GetEndPoint();
958 getViewControls()->WarpMouseCursor( cursorPos, true );
959
960 // Find new bend point for current mode
961 if( twoSegments && m_wires.size() >= 2 )
962 {
963 computeBreakPoint( { m_wires[m_wires.size() - 2], segment }, cursorPos,
964 currentMode, posture );
965 }
966 else
967 {
968 segment->SetEndPoint( cursorPos );
969 }
970
971 for( SCH_LINE* wire : m_wires )
972 {
973 if( !wire->IsNull() )
974 m_view->AddToPreview( wire->Clone() );
975 }
976 }
977 else if( evt->IsAction( &ACTIONS::undo ) )
978 {
979 // Dispatch as normal undo event
980 evt->SetPassEvent();
981 }
982 else
983 {
984 wxBell();
985 }
986 }
987 else if( evt->IsAction( &SCH_ACTIONS::switchSegmentPosture ) && m_wires.size() >= 2 )
988 {
989 posture = !posture;
990
991 // The 90 degree mode doesn't have a forced posture like
992 // the 45 degree mode and computeBreakPoint maintains existing 90s' postures.
993 // Instead, just swap the 90 angle here.
994 if( currentMode == LINE_MODE::LINE_MODE_90 )
995 {
997
998 SCH_LINE* line2 = m_wires[m_wires.size() - 1];
999 SCH_LINE* line1 = m_wires[m_wires.size() - 2];
1000
1001 VECTOR2I delta2 = line2->GetEndPoint() - line2->GetStartPoint();
1002 VECTOR2I delta1 = line1->GetEndPoint() - line1->GetStartPoint();
1003
1004 line2->SetStartPoint(line2->GetEndPoint() - delta1);
1005 line1->SetEndPoint(line1->GetStartPoint() + delta2);
1006
1007 for( SCH_LINE* wire : m_wires )
1008 {
1009 if( !wire->IsNull() )
1010 m_view->AddToPreview( wire->Clone() );
1011 }
1012 }
1013 else
1014 {
1015 computeBreakPoint( { m_wires[m_wires.size() - 2], segment }, cursorPos, currentMode,
1016 posture );
1017
1019 }
1020 }
1021 //------------------------------------------------------------------------
1022 // Handle context menu:
1023 //
1024 else if( evt->IsClick( BUT_RIGHT ) )
1025 {
1026 // Warp after context menu only if dragging...
1027 if( !segment )
1029
1030 contextMenuPos = cursorPos;
1031 m_menu->ShowContextMenu( m_selectionTool->GetSelection() );
1032 }
1033 else if( evt->Category() == TC_COMMAND && evt->Action() == TA_CHOICE_MENU_CHOICE )
1034 {
1035 if( *evt->GetCommandId() >= ID_POPUP_SCH_UNFOLD_BUS
1036 && *evt->GetCommandId() <= ID_POPUP_SCH_UNFOLD_BUS_END )
1037 {
1038 wxASSERT_MSG( !segment, "Bus unfold event received when already drawing!" );
1039
1040 aType = LAYER_WIRE;
1041 wxString net = *evt->Parameter<wxString*>();
1042 segment = doUnfoldBus( aCommit, net, contextMenuPos );
1043 }
1044 }
1045 //------------------------------------------------------------------------
1046 // Handle TOOL_ACTION special cases
1047 //
1048 else if( evt->IsAction( &SCH_ACTIONS::rotateCW ) || evt->IsAction( &SCH_ACTIONS::rotateCCW ) )
1049 {
1051 {
1052 m_busUnfold.label->Rotate90( evt->IsAction( &SCH_ACTIONS::rotateCW ) );
1054
1056 }
1057 else
1058 {
1059 wxBell();
1060 }
1061 }
1062 else if( evt->IsAction( &ACTIONS::redo ) )
1063 {
1064 wxBell();
1065 }
1066 else
1067 {
1068 evt->SetPassEvent();
1069 }
1070
1071 // Enable autopanning and cursor capture only when there is a segment to be placed
1072 controls->SetAutoPan( segment != nullptr );
1073 controls->CaptureCursor( segment != nullptr );
1074 }
1075
1076 controls->SetAutoPan( false );
1077 controls->CaptureCursor( false );
1078 m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::ARROW );
1079 controls->ForceCursorPosition( false );
1080 return 0;
1081}
1082
1083
1085 SCH_LINE* aSegment )
1086{
1087 if( !aSegment )
1088 aSegment = m_frame->GetScreen()->GetLine( aPos, 0, aType );
1089
1090 if( !aSegment )
1091 {
1092 switch( aType )
1093 {
1094 default: aSegment = new SCH_LINE( aPos, LAYER_NOTES ); break;
1095 case LAYER_WIRE: aSegment = new SCH_LINE( aPos, LAYER_WIRE ); break;
1096 case LAYER_BUS: aSegment = new SCH_LINE( aPos, LAYER_BUS ); break;
1097 }
1098
1099 // Give segments a parent so they find the default line/wire/bus widths
1100 aSegment->SetParent( &m_frame->Schematic() );
1101 }
1102 else
1103 {
1104 aSegment = static_cast<SCH_LINE*>( aSegment->Duplicate( true, &aCommit ) );
1105 aSegment->SetStartPoint( aPos );
1106 }
1107
1108
1109 aSegment->SetFlags( IS_NEW | IS_MOVING );
1110 m_wires.push_back( aSegment );
1111
1112 m_selectionTool->AddItemToSel( aSegment, true /*quiet mode*/ );
1113
1114 // We need 2 segments to go from a given start pin to an end point when the
1115 // horizontal and vertical lines only switch is on.
1117 {
1118 aSegment = static_cast<SCH_LINE*>( aSegment->Duplicate( true, &aCommit ) );
1119 aSegment->SetFlags( IS_NEW | IS_MOVING );
1120 m_wires.push_back( aSegment );
1121
1122 m_selectionTool->AddItemToSel( aSegment, true /*quiet mode*/ );
1123 }
1124
1125 return aSegment;
1126}
1127
1128
1143{
1144 for( auto it = m_wires.begin(); it != m_wires.end(); )
1145 {
1146 SCH_LINE* line = *it;
1147
1148 if( line->IsNull() )
1149 {
1150 delete line;
1151 it = m_wires.erase( it );
1152 continue;
1153 }
1154
1155 auto next_it = it;
1156 ++next_it;
1157
1158 if( next_it == m_wires.end() )
1159 break;
1160
1161 SCH_LINE* next_line = *next_it;
1162
1163 if( SCH_LINE* merged = line->MergeOverlap( m_frame->GetScreen(), next_line, false ) )
1164 {
1165 delete line;
1166 delete next_line;
1167 it = m_wires.erase( it );
1168 *it = merged;
1169 }
1170
1171 ++it;
1172 }
1173}
1174
1175
1177{
1178 // Clear selection when done so that a new wire can be started.
1179 // NOTE: this must be done before simplifyWireList is called or we might end up with
1180 // freed selected items.
1182
1183 SCH_SCREEN* screen = m_frame->GetScreen();
1184
1185 // Remove segments backtracking over others
1187
1188 // Collect the possible connection points for the new lines
1189 std::vector<VECTOR2I> connections = screen->GetConnections();
1190 std::vector<VECTOR2I> new_ends;
1191
1192 // Check each new segment for possible junctions and add/split if needed
1193 for( SCH_LINE* wire : m_wires )
1194 {
1195 if( wire->HasFlag( SKIP_STRUCT ) )
1196 continue;
1197
1198 std::vector<VECTOR2I> tmpends = wire->GetConnectionPoints();
1199
1200 new_ends.insert( new_ends.end(), tmpends.begin(), tmpends.end() );
1201
1202 for( const VECTOR2I& pt : connections )
1203 {
1204 if( IsPointOnSegment( wire->GetStartPoint(), wire->GetEndPoint(), pt ) )
1205 new_ends.push_back( pt );
1206 }
1207
1208 aCommit.Added( wire, screen );
1209 }
1210
1212 {
1213 wxASSERT( m_busUnfold.entry && m_busUnfold.label );
1214
1215 aCommit.Added( m_busUnfold.entry, screen );
1217
1218 aCommit.Added( m_busUnfold.label, screen );
1221 }
1222 else if( !m_wires.empty() )
1223 {
1225 }
1226
1227 for( size_t ii = 1; ii < m_wires.size(); ++ii )
1229
1230 // Get the last non-null wire (this is the last created segment).
1231 if( !m_wires.empty() )
1233
1234 // Add the new wires
1235 for( SCH_LINE* wire : m_wires )
1236 {
1237 wire->ClearFlags( IS_NEW | IS_MOVING );
1238 m_frame->AddToScreen( wire, screen );
1239 }
1240
1241 m_wires.clear();
1243 m_view->ShowPreview( false );
1244
1245 getViewControls()->CaptureCursor( false );
1246 getViewControls()->SetAutoPan( false );
1247
1248 // Correct and remove segments that need to be merged.
1249 m_frame->Schematic().CleanUp( &aCommit );
1250
1251 std::vector<SCH_ITEM*> symbols;
1252
1253 for( SCH_ITEM* symbol : m_frame->GetScreen()->Items().OfType( SCH_SYMBOL_T ) )
1254 symbols.push_back( symbol );
1255
1256 for( SCH_ITEM* symbol : symbols )
1257 {
1258 std::vector<VECTOR2I> pts = symbol->GetConnectionPoints();
1259
1260 if( pts.size() > 2 )
1261 continue;
1262
1263 for( auto pt = pts.begin(); pt != pts.end(); pt++ )
1264 {
1265 for( auto secondPt = pt + 1; secondPt != pts.end(); secondPt++ )
1266 m_frame->TrimWire( &aCommit, *pt, *secondPt );
1267 }
1268 }
1269
1270 for( const VECTOR2I& pt : new_ends )
1271 {
1273 m_frame->AddJunction( &aCommit, m_frame->GetScreen(), pt );
1274 }
1275
1277 m_busUnfold = {};
1278
1279 for( SCH_ITEM* item : m_frame->GetScreen()->Items() )
1280 item->ClearEditFlags();
1281}
1282
1283
1285{
1286 SCHEMATIC* sch = getModel<SCHEMATIC>();
1287 SCH_SCREEN* screen = sch->CurrentSheet().LastScreen();
1288
1289 std::set<SCH_LINE*> lines;
1290 BOX2I bb = aSelection->GetBoundingBox();
1291
1292 for( EDA_ITEM* item : screen->Items().Overlapping( SCH_LINE_T, bb ) )
1293 lines.insert( static_cast<SCH_LINE*>( item ) );
1294
1295 for( unsigned ii = 0; ii < aSelection->GetSize(); ii++ )
1296 {
1297 SCH_ITEM* item = dynamic_cast<SCH_ITEM*>( aSelection->GetItem( ii ) );
1298
1299 if( !item || !item->IsConnectable() || ( item->Type() == SCH_LINE_T ) )
1300 continue;
1301
1302 std::vector<VECTOR2I> pts = item->GetConnectionPoints();
1303
1306 for( SCH_LINE* line : lines )
1307 {
1308 std::vector<VECTOR2I> conn_pts;
1309
1310 for( const VECTOR2I& pt : pts )
1311 {
1312 if( IsPointOnSegment( line->GetStartPoint(), line->GetEndPoint(), pt ) )
1313 conn_pts.push_back( pt );
1314
1315 if( conn_pts.size() > 2 )
1316 break;
1317 }
1318
1319 if( conn_pts.size() == 2 )
1320 m_frame->TrimWire( aCommit, conn_pts[0], conn_pts[1] );
1321 }
1322 }
1323
1324 return 0;
1325}
1326
1327
1329{
1330 SCH_SCREEN* screen = m_frame->GetScreen();
1331 std::deque<EDA_ITEM*> allItems;
1332
1333 for( EDA_ITEM* item : aSelection->Items() )
1334 {
1335 allItems.push_back( item );
1336
1337 if( item->Type() == SCH_GROUP_T )
1338 {
1339 static_cast<SCH_GROUP*>( item )->RunOnChildren(
1340 [&]( SCH_ITEM* child )
1341 {
1342 allItems.push_back( child );
1343 }, RECURSE_MODE::RECURSE );
1344 }
1345 }
1346
1347 for( const VECTOR2I& point : screen->GetNeededJunctions( allItems ) )
1348 m_frame->AddJunction( aCommit, m_frame->GetScreen(), point );
1349
1350 return 0;
1351}
1352
1353
1355{
1359
1361}
const char * name
Definition: DXF_plotter.cpp:62
constexpr BOX2I KiROUND(const BOX2D &aBoxD)
Definition: box2.h:990
static TOOL_ACTION undo
Definition: actions.h:75
static TOOL_ACTION doDelete
Definition: actions.h:85
static TOOL_ACTION redo
Definition: actions.h:76
static TOOL_ACTION selectionClear
Clear the current selection.
Definition: actions.h:221
static TOOL_ACTION refreshPreview
Definition: actions.h:156
static TOOL_ACTION finishInteractive
Definition: actions.h:73
Define 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
Creator of the menu.
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)
Notify observers that aItem has been added.
Definition: commit.h:85
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:816
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:98
virtual void ClearEditFlags()
Definition: eda_item.h:156
void SetFlags(EDA_ITEM_FLAGS aMask)
Definition: eda_item.h:142
KICAD_T Type() const
Returns the type of object.
Definition: eda_item.h:110
virtual void SetParent(EDA_ITEM *aParent)
Definition: eda_item.h:113
bool IsNew() const
Definition: eda_item.h:124
void SetTextSize(VECTOR2I aNewSize, bool aEnforceMinTextSize=true)
Definition: eda_text.cpp:533
EE_TYPE Overlapping(const BOX2I &aRect) const
Definition: sch_rtree.h:246
EE_TYPE OfType(KICAD_T aType) const
Definition: sch_rtree.h:241
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:1743
GAL * GetGAL() const
Return the #GAL this view is using to draw graphical primitives.
Definition: view.h:202
void ClearPreview()
Definition: view.cpp:1707
void AddToPreview(VIEW_ITEM *aItem, bool aTakeOwnership=true)
Definition: view.cpp:1729
These are loaded from Eeschema settings but then overwritten by the project settings.
Holds all the data relating to one schematic.
Definition: schematic.h:88
void CleanUp(SCH_COMMIT *aCommit, SCH_SCREEN *aScreen=nullptr)
Perform routine schematic cleaning including breaking wire and buses and deleting identical objects s...
Definition: schematic.cpp:1117
SCH_SHEET & Root() const
Definition: schematic.h:140
SCH_SHEET_PATH & CurrentSheet() const
Definition: schematic.h:171
static TOOL_ACTION rotateCCW
Definition: sch_actions.h:121
static TOOL_ACTION placeClassLabel
Definition: sch_actions.h:79
static TOOL_ACTION clearHighlight
Definition: sch_actions.h:297
static TOOL_ACTION placeGlobalLabel
Definition: sch_actions.h:80
static TOOL_ACTION leaveSheet
Definition: sch_actions.h:219
static TOOL_ACTION breakWire
Definition: sch_actions.h:140
static TOOL_ACTION drawLines
Definition: sch_actions.h:99
static TOOL_ACTION placeHierLabel
Definition: sch_actions.h:81
static TOOL_ACTION selectConnection
If current selection is a wire or bus, expand to entire connection.
Definition: sch_actions.h:51
static TOOL_ACTION placeLabel
Definition: sch_actions.h:78
static TOOL_ACTION drawWire
Definition: sch_actions.h:72
static TOOL_ACTION rotateCW
Definition: sch_actions.h:120
static TOOL_ACTION placeJunction
Definition: sch_actions.h:76
static TOOL_ACTION selectNode
Select the junction, wire or bus segment under the cursor.
Definition: sch_actions.h:47
static TOOL_ACTION unfoldBus
Definition: sch_actions.h:74
static TOOL_ACTION drawBus
Definition: sch_actions.h:73
static TOOL_ACTION slice
Definition: sch_actions.h:141
static TOOL_ACTION undoLastSegment
Definition: sch_actions.h:101
static TOOL_ACTION switchSegmentPosture
Definition: sch_actions.h:102
void RemoveFromScreen(EDA_ITEM *aItem, SCH_SCREEN *aScreen) override
Remove an item from 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 AddToScreen(EDA_ITEM *aItem, SCH_SCREEN *aScreen=nullptr) override
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: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
Execute the changes.
Definition: sch_commit.cpp:489
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.
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.
A set of SCH_ITEMs (i.e., without duplicates).
Definition: sch_group.h:52
Base class for any item which can be embedded within the SCHEMATIC container class,...
Definition: sch_item.h:168
SCH_ITEM * Duplicate(bool addToParentGroup, SCH_COMMIT *aCommit=nullptr, bool doClone=false) const
Routine to create a new copy of given item.
Definition: sch_item.cpp:137
virtual bool IsConnectable() const
Definition: sch_item.h:498
SCH_LAYER_ID GetLayer() const
Return the layer this item is on.
Definition: sch_item.h:313
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:352
virtual std::vector< VECTOR2I > GetConnectionPoints() const
Add all the connection points for this item to aPoints.
Definition: sch_item.h:513
void SetIsDangling(bool aIsDangling)
Definition: sch_label.h:330
SPIN_STYLE GetSpinStyle() const
Definition: sch_label.cpp:351
void SetPosition(const VECTOR2I &aPosition) override
Definition: sch_label.cpp:390
void Rotate90(bool aClockwise) override
Definition: sch_label.cpp:421
virtual void SetSpinStyle(SPIN_STYLE aSpinStyle)
Definition: sch_label.cpp:316
EDA_ITEM * Clone() const override
Create a duplicate of this item with linked list members set to NULL.
Definition: sch_label.h:413
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, SCH_SELECTION *aSelection)
Handle the addition of junctions to a selection of objects.
int UnfoldBus(const TOOL_EVENT &aEvent)
SCH_LINE * startSegments(SCH_COMMIT &aCommit, int aType, const VECTOR2D &aPos, SCH_LINE *aSegment=nullptr)
bool Init() override
Init() is called once upon a registration of the tool.
int TrimOverLappingWires(SCH_COMMIT *aCommit, SCH_SELECTION *aSelection)
Logic to remove wires when overlapping correct items.
const SCH_SHEET_PIN * getSheetPin(const VECTOR2I &aPosition)
Search for a sheet pin at a location.
SCH_LINE * doUnfoldBus(SCH_COMMIT &aCommit, 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
static bool IsDrawingLineWireOrBus(const SELECTION &aSelection)
void simplifyWireList()
Iterate over the wire list and removes the null segments and overlapping segments to create a simplif...
int doDrawSegments(const TOOL_EVENT &aTool, SCH_COMMIT &aCommit, int aType, bool aQuitOnDraw)
void finishSegments(SCH_COMMIT &aCommit)
Segment description base class to describe items which have 2 end points (track, wire,...
Definition: sch_line.h:42
void SetStartPoint(const VECTOR2I &aPosition)
Definition: sch_line.h:140
VECTOR2I GetEndPoint() const
Definition: sch_line.h:144
VECTOR2I GetStartPoint() const
Definition: sch_line.h:139
SEG GetSeg() const
Get the geometric aspect of the wire as a SEG.
Definition: sch_line.h:150
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:425
bool IsNull() const
Definition: sch_line.h:137
void SetEndPoint(const VECTOR2I &aPosition)
Definition: sch_line.h:145
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()
Get the full RTree, usually for iterating.
Definition: sch_screen.h:117
bool IsTerminalPoint(const VECTOR2I &aPosition, int aLayer) const
Test if aPosition is a connection point on aLayer.
Definition: sch_screen.cpp:599
bool IsExplicitJunctionNeeded(const VECTOR2I &aPosition) const
Indicate that a junction dot is necessary at the given location, and does not yet exist.
Definition: sch_screen.cpp:491
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_SELECTION & GetSelection()
SCH_SELECTION & RequestSelection(const std::vector< KICAD_T > &aScanTypes={ SCH_LOCATE_ANY_T }, bool aPromoteCellSelections=false, bool aPromoteGroups=false)
Return either an existing selection (filtered), or the selection at the current cursor position if th...
BOX2I GetBoundingBox() const override
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:47
std::vector< SCH_SHEET_PIN * > & GetPins()
Definition: sch_sheet.h:187
VECTOR2I GetPosition() const override
Definition: sch_text.h:141
A foundation class for a tool operating on a schematic or symbol.
Definition: sch_tool_base.h:49
bool Init() override
Init() is called once upon a registration of the tool.
Definition: sch_tool_base.h:65
SCH_SELECTION_TOOL * m_selectionTool
const VECTOR2I NearestPoint(const VECTOR2I &aP) const
Compute a point on the segment (this) that is closest to point aP.
Definition: seg.cpp:606
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:105
EDA_ITEM * Front() const
Definition: selection.h:177
std::deque< EDA_ITEM * > & Items()
Definition: selection.h:182
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:44
TOOL_MANAGER * m_toolMgr
Definition: tool_base.h:220
KIGFX::VIEW * getView() const
Returns the instance of #VIEW object used in the application.
Definition: tool_base.cpp:38
Generic, UI-independent tool event.
Definition: tool_event.h:168
bool HasPosition() const
Returns if it this event has a valid position (true for mouse events and context-menu or hotkey-based...
Definition: tool_event.h:257
bool DisableGridSnapping() const
Definition: tool_event.h:368
const VECTOR2D Position() const
Return mouse cursor position in world coordinates.
Definition: tool_event.h:290
int Modifier(int aMask=MD_MODIFIER_MASK) const
Return information about key modifiers state (Ctrl, Alt, etc.).
Definition: tool_event.h:363
T Parameter() const
Return a parameter assigned to the event.
Definition: tool_event.h:465
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:515
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:192
#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:43
@ GRID_GRAPHICS
Definition: grid_helper.h:51
@ GRID_WIRES
Definition: grid_helper.h:48
@ LAYER_WIRE
Definition: layer_ids.h:442
@ LAYER_NOTES
Definition: layer_ids.h:457
@ LAYER_BUS
Definition: layer_ids.h:443
bool signbit(T v)
Integral version of std::signbit that works all compilers.
Definition: kicad_algo.h:176
EDA_ANGLE abs(const EDA_ANGLE &aAngle)
Definition: eda_angle.h:400
Class to handle a set of SCH_ITEMs.
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.
int delta
@ CMENU_NOW
Right now (after TOOL_INTERACTIVE::SetContextMenu).
Definition: tool_event.h:153
@ TA_CHOICE_MENU_CHOICE
Context menu choice.
Definition: tool_event.h:98
@ TA_CHOICE_MENU_CLOSED
Context menu is closed, no matter whether anything has been chosen or not.
Definition: tool_event.h:101
@ TC_COMMAND
Definition: tool_event.h:57
@ MD_SHIFT
Definition: tool_event.h:143
@ BUT_LEFT
Definition: tool_event.h:132
@ BUT_RIGHT
Definition: tool_event.h:133
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_GROUP_T
Definition: typeinfo.h:174
@ SCH_LINE_T
Definition: typeinfo.h:164
@ SCH_SYMBOL_T
Definition: typeinfo.h:173
@ SCH_SHEET_T
Definition: typeinfo.h:176
@ SCH_ITEM_LOCATE_BUS_T
Definition: typeinfo.h:188
VECTOR2< int32_t > VECTOR2I
Definition: vector2d.h:695
VECTOR2< double > VECTOR2D
Definition: vector2d.h:694