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 <tool/actions.h>
44#include <tool/selection.h>
46#include <tool/tool_event.h>
47#include <trigo.h>
48#include <eeschema_id.h>
49#include <sch_bus_entry.h>
50#include <sch_connection.h>
51#include <sch_edit_frame.h>
52#include <sch_line.h>
53#include <sch_screen.h>
54#include <sch_sheet.h>
55#include <sch_sheet_pin.h>
56#include <schematic.h>
57#include <sch_commit.h>
58#include <ee_actions.h>
59#include <ee_grid_helper.h>
60#include <ee_selection.h>
61#include <ee_selection_tool.h>
62
64{
65public:
67 ACTION_MENU( true ),
68 m_showTitle( false )
69 {
70 SetIcon( BITMAPS::add_line2bus );
71 SetTitle( _( "Unfold from Bus" ) );
72 }
73
75 {
76 m_showTitle = true;
77 }
78
79 bool PassHelpTextToHandler() override { return true; }
80
81protected:
82 ACTION_MENU* create() const override
83 {
84 return new BUS_UNFOLD_MENU();
85 }
86
87private:
88 void update() override
89 {
91 EE_SELECTION& selection = selTool->RequestSelection( { SCH_ITEM_LOCATE_BUS_T } );
92 SCH_LINE* bus = (SCH_LINE*) selection.Front();
93
94 Clear();
95
96 // Pick up the pointer again because it may have been changed by SchematicCleanUp
97 selection = selTool->RequestSelection( { SCH_ITEM_LOCATE_BUS_T } );
98 bus = (SCH_LINE*) selection.Front();
99
100 if( !bus )
101 {
102 Append( ID_POPUP_SCH_UNFOLD_BUS, _( "No bus selected" ), wxEmptyString );
103 Enable( ID_POPUP_SCH_UNFOLD_BUS, false );
104 return;
105 }
106
107 SCH_CONNECTION* connection = bus->Connection();
108
109 if( !connection || !connection->IsBus() || connection->Members().empty() )
110 {
111 Append( ID_POPUP_SCH_UNFOLD_BUS, _( "Bus has no members" ), wxEmptyString );
112 Enable( ID_POPUP_SCH_UNFOLD_BUS, false );
113 return;
114 }
115
116 int idx = 0;
117
118 if( m_showTitle )
119 {
120 Append( ID_POPUP_SCH_UNFOLD_BUS, _( "Unfold from Bus" ), wxEmptyString );
121 Enable( ID_POPUP_SCH_UNFOLD_BUS, false );
122 }
123
124 for( const std::shared_ptr<SCH_CONNECTION>& member : connection->Members() )
125 {
126 int id = ID_POPUP_SCH_UNFOLD_BUS + ( idx++ );
127 wxString name = member->FullLocalName();
128
129 if( member->Type() == CONNECTION_TYPE::BUS )
130 {
131 ACTION_MENU* submenu = new ACTION_MENU( true, m_tool );
132 AppendSubMenu( submenu, SCH_CONNECTION::PrintBusForUI( name ), name );
133
134 for( const std::shared_ptr<SCH_CONNECTION>& sub_member : member->Members() )
135 {
136 id = ID_POPUP_SCH_UNFOLD_BUS + ( idx++ );
137 name = sub_member->FullLocalName();
138 submenu->Append( id, SCH_CONNECTION::PrintBusForUI( name ), name );
139 }
140 }
141 else
142 {
143 Append( id, name, wxEmptyString );
144 }
145 }
146 }
147
149};
150
151
153 EE_TOOL_BASE<SCH_EDIT_FRAME>( "eeschema.InteractiveDrawingLineWireBus" ),
154 m_inDrawingTool( false )
155{
156 m_busUnfold = {};
157 m_wires.reserve( 16 );
158}
159
160
162{
163}
164
165
167{
169
170 std::shared_ptr<BUS_UNFOLD_MENU> busUnfoldMenu = std::make_shared<BUS_UNFOLD_MENU>();
171 busUnfoldMenu->SetTool( this );
172 m_menu.RegisterSubMenu( busUnfoldMenu );
173
174 std::shared_ptr<BUS_UNFOLD_MENU> selBusUnfoldMenu = std::make_shared<BUS_UNFOLD_MENU>();
175 selBusUnfoldMenu->SetTool( m_selectionTool );
176 m_selectionTool->GetToolMenu().RegisterSubMenu( selBusUnfoldMenu );
177
178 auto wireOrBusTool =
179 [this]( const SELECTION& aSel )
180 {
183 };
184
185 auto lineTool =
186 [this]( const SELECTION& aSel )
187 {
189 };
190
191 auto belowRootSheetCondition =
192 [&]( const SELECTION& aSel )
193 {
194 return m_frame->GetCurrentSheet().Last() != &m_frame->Schematic().Root();
195 };
196
197 auto busSelection = EE_CONDITIONS::MoreThan( 0 )
199
200 auto haveHighlight =
201 [&]( const SELECTION& sel )
202 {
203 SCH_EDIT_FRAME* editFrame = dynamic_cast<SCH_EDIT_FRAME*>( m_frame );
204
205 return editFrame && !editFrame->GetHighlightedConnection().IsEmpty();
206 };
207
208 auto& ctxMenu = m_menu.GetMenu();
209
210 // Build the tool menu
211 //
212 ctxMenu.AddItem( EE_ACTIONS::clearHighlight, haveHighlight && EE_CONDITIONS::Idle, 1 );
213 ctxMenu.AddSeparator( haveHighlight && EE_CONDITIONS::Idle, 1 );
214
215 ctxMenu.AddItem( EE_ACTIONS::leaveSheet, belowRootSheetCondition, 2 );
216
217 ctxMenu.AddSeparator( 10 );
218 ctxMenu.AddItem( EE_ACTIONS::drawWire, wireOrBusTool && EE_CONDITIONS::Idle, 10 );
219 ctxMenu.AddItem( EE_ACTIONS::drawBus, wireOrBusTool && EE_CONDITIONS::Idle, 10 );
220 ctxMenu.AddItem( EE_ACTIONS::drawLines, lineTool && EE_CONDITIONS::Idle, 10 );
221
224
225 ctxMenu.AddItem( EE_ACTIONS::finishWire, IsDrawingWire, 10 );
226 ctxMenu.AddItem( EE_ACTIONS::finishBus, IsDrawingBus, 10 );
227 ctxMenu.AddItem( EE_ACTIONS::finishLine, IsDrawingLine, 10 );
228
229 ctxMenu.AddMenu( busUnfoldMenu.get(), EE_CONDITIONS::Idle, 10 );
230
231 ctxMenu.AddSeparator( 100 );
232 ctxMenu.AddItem( EE_ACTIONS::placeJunction, wireOrBusTool && EE_CONDITIONS::Idle, 100 );
233 ctxMenu.AddItem( EE_ACTIONS::placeLabel, wireOrBusTool && EE_CONDITIONS::Idle, 100 );
234 ctxMenu.AddItem( EE_ACTIONS::placeClassLabel, wireOrBusTool && EE_CONDITIONS::Idle, 100 );
235 ctxMenu.AddItem( EE_ACTIONS::placeGlobalLabel, wireOrBusTool && EE_CONDITIONS::Idle, 100 );
236 ctxMenu.AddItem( EE_ACTIONS::placeHierLabel, wireOrBusTool && EE_CONDITIONS::Idle, 100 );
237 ctxMenu.AddItem( EE_ACTIONS::breakWire, wireOrBusTool && EE_CONDITIONS::Idle, 100 );
238 ctxMenu.AddItem( EE_ACTIONS::slice, ( wireOrBusTool || lineTool )
239 && EE_CONDITIONS::Idle, 100 );
240 ctxMenu.AddSeparator( 200 );
241 ctxMenu.AddItem( EE_ACTIONS::selectNode, wireOrBusTool && EE_CONDITIONS::Idle, 200 );
242 ctxMenu.AddItem( EE_ACTIONS::selectConnection, wireOrBusTool && EE_CONDITIONS::Idle, 200 );
243
244 // Add bus unfolding to the selection tool
245 //
247
248 selToolMenu.AddMenu( selBusUnfoldMenu.get(), busSelection && EE_CONDITIONS::Idle, 100 );
249
250 return true;
251}
252
253
255{
256 return IsDrawingLineWireOrBus( aSelection )
257 && aSelection.Front()->IsType( { SCH_ITEM_LOCATE_GRAPHIC_LINE_T } );
258}
259
260
262{
263 return IsDrawingLineWireOrBus( aSelection )
264 && aSelection.Front()->IsType( { SCH_ITEM_LOCATE_WIRE_T } );
265}
266
267
269{
270 return IsDrawingLineWireOrBus( aSelection )
271 && aSelection.Front()->IsType( { SCH_ITEM_LOCATE_BUS_T } );
272}
273
274
276{
277 // NOTE: for immediate hotkeys, it is NOT required that the line, wire or bus tool
278 // be selected
279 SCH_ITEM* item = (SCH_ITEM*) aSelection.Front();
280 return item && item->IsNew() && item->Type() == SCH_LINE_T;
281}
282
283
285{
286 if( m_inDrawingTool )
287 return 0;
288
290
291 const DRAW_SEGMENT_EVENT_PARAMS* params = aEvent.Parameter<const DRAW_SEGMENT_EVENT_PARAMS*>();
292
293 m_frame->PushTool( aEvent );
295
296 if( aEvent.HasPosition() )
297 {
299 grid.SetSnap( !aEvent.Modifier( MD_SHIFT ) );
300 grid.SetUseGrid( getView()->GetGAL()->GetGridSnapping() && !aEvent.DisableGridSnapping() );
301
302 VECTOR2D cursorPos = grid.BestSnapAnchor( aEvent.Position(), GRID_WIRES, nullptr );
303 startSegments( params->layer, cursorPos, params->sourceSegment );
304 }
305
306 return doDrawSegments( aEvent, params->layer, params->quitOnDraw );
307}
308
309
311{
312 if( m_inDrawingTool )
313 return 0;
314
316
317 wxString* netPtr = aEvent.Parameter<wxString*>();
318 wxString net;
319 SCH_LINE* segment = nullptr;
320
321 m_frame->PushTool( aEvent );
322 Activate();
323
324 if( netPtr )
325 {
326 net = *netPtr;
327 delete netPtr;
328 }
329 else
330 {
331 BUS_UNFOLD_MENU unfoldMenu;
332 unfoldMenu.SetTool( this );
333 unfoldMenu.SetShowTitle();
334
335 SetContextMenu( &unfoldMenu, CMENU_NOW );
336
337 while( TOOL_EVENT* evt = Wait() )
338 {
339 if( evt->Action() == TA_CHOICE_MENU_CHOICE )
340 {
341 std::optional<int> id = evt->GetCommandId();
342
343 if( id && ( *id > 0 ) )
344 net = *evt->Parameter<wxString*>();
345
346 break;
347 }
348 else if( evt->Action() == TA_CHOICE_MENU_CLOSED )
349 {
350 break;
351 }
352 else
353 {
354 evt->SetPassEvent();
355 }
356 }
357 }
358
359 // Break a wire for the given net out of the bus
360 if( !net.IsEmpty() )
361 segment = doUnfoldBus( net );
362
363 // If we have an unfolded wire to draw, then draw it
364 if( segment )
365 {
366 return doDrawSegments( aEvent, LAYER_WIRE, false );
367 }
368 else
369 {
370 m_frame->PopTool( aEvent );
371 return 0;
372 }
373}
374
375
376SCH_LINE* SCH_LINE_WIRE_BUS_TOOL::doUnfoldBus( const wxString& aNet, const VECTOR2I& aPos )
377{
378 SCHEMATIC_SETTINGS& cfg = getModel<SCHEMATIC>()->Settings();
379 SCH_SCREEN* screen = m_frame->GetScreen();
380
381 VECTOR2I pos = aPos;
382
383 if( aPos == VECTOR2I( 0, 0 ) )
384 pos = static_cast<VECTOR2I>( getViewControls()->GetCursorPosition() );
385
387
389 m_busUnfold.entry->SetParent( screen );
391
397
399 m_busUnfold.origin = pos;
400 m_busUnfold.net_name = aNet;
401
403
404 std::vector<DANGLING_END_ITEM> endPoints;
405
406 for( SCH_ITEM* item : screen->Items().Overlapping( m_busUnfold.entry->GetBoundingBox() ) )
407 item->GetEndPoints( endPoints );
408
412
414}
415
416
418{
419 SCH_SCREEN* screen = m_frame->GetScreen();
420
421 for( SCH_ITEM* item : screen->Items().Overlapping( SCH_SHEET_T, aPosition ) )
422 {
423 SCH_SHEET* sheet = static_cast<SCH_SHEET*>( item );
424
425 for( SCH_SHEET_PIN* pin : sheet->GetPins() )
426 {
427 if( pin->GetPosition() == aPosition )
428 return pin;
429 }
430 }
431
432 return nullptr;
433}
434
435
436void SCH_LINE_WIRE_BUS_TOOL::computeBreakPoint( const std::pair<SCH_LINE*, SCH_LINE*>& aSegments,
437 VECTOR2I& aPosition,
438 LINE_MODE mode,
439 bool posture )
440{
441 wxCHECK_RET( aSegments.first && aSegments.second,
442 wxT( "Cannot compute break point of NULL line segment." ) );
443
444 VECTOR2I midPoint;
445 SCH_LINE* segment = aSegments.first;
446 SCH_LINE* nextSegment = aSegments.second;
447
448 VECTOR2I delta = aPosition - segment->GetStartPoint();
449 int xDir = delta.x > 0 ? 1 : -1;
450 int yDir = delta.y > 0 ? 1 : -1;
451
452
453 bool preferHorizontal;
454 bool preferVertical;
455
456 if( ( mode == LINE_MODE_45 ) && posture )
457 {
458 preferHorizontal = ( nextSegment->GetEndPoint().x - nextSegment->GetStartPoint().x ) != 0;
459 preferVertical = ( nextSegment->GetEndPoint().y - nextSegment->GetStartPoint().y ) != 0;
460 }
461 else
462 {
463 preferHorizontal = ( segment->GetEndPoint().x - segment->GetStartPoint().x ) != 0;
464 preferVertical = ( segment->GetEndPoint().y - segment->GetStartPoint().y ) != 0;
465 }
466
467 // Check for times we need to force horizontal sheet pin connections
468 const SCH_SHEET_PIN* connectedPin = getSheetPin( segment->GetStartPoint() );
469 SHEET_SIDE force = connectedPin ? connectedPin->GetSide() : SHEET_SIDE::UNDEFINED;
470
471 if( force == SHEET_SIDE::LEFT || force == SHEET_SIDE::RIGHT )
472 {
473 if( aPosition.x == connectedPin->GetPosition().x ) // push outside sheet boundary
474 {
475 int direction = ( force == SHEET_SIDE::LEFT ) ? -1 : 1;
476 aPosition.x += KiROUND( getView()->GetGAL()->GetGridSize().x * direction );
477 }
478
479 preferHorizontal = true;
480 preferVertical = false;
481 }
482
483
484 auto breakVertical = [&]() mutable
485 {
486 switch( mode )
487 {
488 case LINE_MODE_45:
489 if( !posture )
490 {
491 midPoint.x = segment->GetStartPoint().x;
492 midPoint.y = aPosition.y - yDir * abs( delta.x );
493 }
494 else
495 {
496 midPoint.x = aPosition.x;
497 midPoint.y = segment->GetStartPoint().y + yDir * abs( delta.x );
498 }
499 break;
500 default:
501 midPoint.x = segment->GetStartPoint().x;
502 midPoint.y = aPosition.y;
503 }
504 };
505
506
507 auto breakHorizontal = [&]() mutable
508 {
509 switch( mode )
510 {
511 case LINE_MODE_45:
512 if( !posture )
513 {
514 midPoint.x = aPosition.x - xDir * abs( delta.y );
515 midPoint.y = segment->GetStartPoint().y;
516 }
517 else
518 {
519 midPoint.x = segment->GetStartPoint().x + xDir * abs( delta.y );
520 midPoint.y = aPosition.y;
521 }
522 break;
523 default:
524 midPoint.x = aPosition.x;
525 midPoint.y = segment->GetStartPoint().y;
526 }
527 };
528
529
530 // Maintain current line shape if we can, e.g. if we were originally moving
531 // vertically keep the first segment vertical
532 if( preferVertical )
533 breakVertical();
534 else if( preferHorizontal )
535 breakHorizontal();
536
537 // Check if our 45 degree angle is one of these shapes
538 // /
539 // /
540 // /
541 // /__________
542 VECTOR2I deltaMidpoint = midPoint - segment->GetStartPoint();
543
544 if( mode == LINE_MODE::LINE_MODE_45 && !posture
545 && ( ( alg::signbit( deltaMidpoint.x ) != alg::signbit( delta.x ) )
546 || ( alg::signbit( deltaMidpoint.y ) != alg::signbit( delta.y ) ) ) )
547 {
548 preferVertical = false;
549 preferHorizontal = false;
550 }
551 else if( mode == LINE_MODE::LINE_MODE_45 && posture
552 && ( ( abs( deltaMidpoint.x ) > abs( delta.x ) )
553 || ( abs( deltaMidpoint.y ) > abs( delta.y ) ) ) )
554 {
555 preferVertical = false;
556 preferHorizontal = false;
557 }
558
559 if( !preferHorizontal && !preferVertical )
560 {
561 if( std::abs( delta.x ) < std::abs( delta.y ) )
562 breakVertical();
563 else
564 breakHorizontal();
565 }
566
567 segment->SetEndPoint( midPoint );
568 nextSegment->SetStartPoint( midPoint );
569 nextSegment->SetEndPoint( aPosition );
570}
571
572
573int SCH_LINE_WIRE_BUS_TOOL::doDrawSegments( const TOOL_EVENT& aTool, int aType, bool aQuitOnDraw )
574{
575 SCH_SCREEN* screen = m_frame->GetScreen();
576 SCH_LINE* segment = nullptr;
579 int lastMode = m_frame->eeconfig()->m_Drawing.line_mode;
580 static bool posture = false;
581
582 auto setCursor =
583 [&]()
584 {
585 if( aType == LAYER_WIRE )
586 m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::LINE_WIRE );
587 else if( aType == LAYER_BUS )
588 m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::LINE_BUS );
589 else if( aType == LAYER_NOTES )
590 m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::LINE_GRAPHIC );
591 else
592 m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::LINE_WIRE );
593 };
594
595 auto cleanup =
596 [&] ()
597 {
599
600 for( SCH_LINE* wire : m_wires )
601 delete wire;
602
603 m_wires.clear();
604 segment = nullptr;
605
606 if( m_busUnfold.entry )
608
611
614
615 delete m_busUnfold.entry;
616 delete m_busUnfold.label;
617 m_busUnfold = {};
618
620 m_view->ShowPreview( false );
621 };
622
623 Activate();
624 // Must be done after Activate() so that it gets set into the correct context
625 controls->ShowCursor( true );
626 // Set initial cursor
627 setCursor();
628
629 // Add the new label to the selection so the rotate command operates on it
630 if( m_busUnfold.label )
632
633 // Continue the existing wires if we've started (usually by immediate action preference)
634 if( !m_wires.empty() )
635 segment = m_wires.back();
636
637 VECTOR2I contextMenuPos;
638
639 // Main loop: keep receiving events
640 while( TOOL_EVENT* evt = Wait() )
641 {
643 bool twoSegments = currentMode != LINE_MODE::LINE_MODE_FREE;
644
645 // The tool hotkey is interpreted as a click when drawing
646 bool isSyntheticClick = ( segment || m_busUnfold.in_progress ) && evt->IsActivate()
647 && evt->HasPosition() && evt->Matches( aTool );
648
649 setCursor();
650 grid.SetMask( GRID_HELPER::ALL );
651 grid.SetSnap( !evt->Modifier( MD_SHIFT ) );
652 grid.SetUseGrid( getView()->GetGAL()->GetGridSnapping() && !evt->DisableGridSnapping() );
653
654 if( segment )
655 {
656 if( segment->GetStartPoint().x == segment->GetEndPoint().x )
657 grid.ClearMaskFlag( GRID_HELPER::VERTICAL );
658
659 if( segment->GetStartPoint().y == segment->GetEndPoint().y )
660 grid.ClearMaskFlag( GRID_HELPER::HORIZONTAL );
661 }
662
663 VECTOR2D eventPosition = evt->HasPosition() ? evt->Position()
664 : controls->GetMousePosition();
665
666 VECTOR2I cursorPos = grid.BestSnapAnchor( eventPosition, GRID_WIRES, segment );
667 controls->ForceCursorPosition( true, cursorPos );
668
669 // Need to handle change in H/V mode while drawing
670 if( currentMode != lastMode )
671 {
672 // Need to delete extra segment if we have one
673 if( segment && currentMode == LINE_MODE::LINE_MODE_FREE && m_wires.size() >= 2 )
674 {
675 m_wires.pop_back();
677 delete segment;
678
679 segment = m_wires.back();
680 segment->SetEndPoint( cursorPos );
681 }
682 // Add a segment so we can move orthogonally/45
683 else if( segment && lastMode == LINE_MODE::LINE_MODE_FREE )
684 {
685 segment->SetEndPoint( cursorPos );
686
687 // Create a new segment, and chain it after the current segment.
688 segment = static_cast<SCH_LINE*>( segment->Duplicate() );
689 segment->SetFlags( IS_NEW | IS_MOVING );
690 segment->SetStartPoint( cursorPos );
691 m_wires.push_back( segment );
692
693 m_selectionTool->AddItemToSel( segment, true /*quiet mode*/ );
694 }
695
696 lastMode = currentMode;
697 }
698
699 //------------------------------------------------------------------------
700 // Handle cancel:
701 //
702 if( evt->IsCancelInteractive() )
703 {
705
706 if( segment || m_busUnfold.in_progress )
707 {
708 cleanup();
709
710 if( aQuitOnDraw )
711 {
712 m_frame->PopTool( aTool );
713 break;
714 }
715 }
716 else
717 {
718 m_frame->PopTool( aTool );
719 break;
720 }
721 }
722 else if( evt->IsActivate() && !isSyntheticClick )
723 {
724 if( segment || m_busUnfold.in_progress )
725 {
726 m_frame->ShowInfoBarMsg( _( "Press <ESC> to cancel drawing." ) );
727 evt->SetPassEvent( false );
728 continue;
729 }
730
731 if( evt->IsMoveTool() )
732 {
733 // leave ourselves on the stack so we come back after the move
734 break;
735 }
736 else
737 {
738 m_frame->PopTool( aTool );
739 break;
740 }
741 }
742 //------------------------------------------------------------------------
743 // Handle finish:
744 //
745 else if( evt->IsAction( &EE_ACTIONS::finishLineWireOrBus )
746 || evt->IsAction( &EE_ACTIONS::finishWire )
747 || evt->IsAction( &EE_ACTIONS::finishBus )
748 || evt->IsAction( &EE_ACTIONS::finishLine ) )
749 {
750 if( segment || m_busUnfold.in_progress )
751 {
753 segment = nullptr;
754
755 if( aQuitOnDraw )
756 {
757 m_frame->PopTool( aTool );
758 break;
759 }
760 }
761 }
762 //------------------------------------------------------------------------
763 // Handle click:
764 //
765 else if( evt->IsClick( BUT_LEFT )
766 || ( segment && evt->IsDblClick( BUT_LEFT ) )
767 || isSyntheticClick )
768 {
769 // First click when unfolding places the label and wire-to-bus entry
771 {
772 wxASSERT( aType == LAYER_WIRE );
773
777 }
778
779 if( !segment )
780 {
781 segment = startSegments( aType, VECTOR2D( cursorPos ) );
782 }
783 // Create a new segment if we're out of previously-created ones
784 else if( !segment->IsNull()
785 || ( twoSegments && !m_wires[m_wires.size() - 2]->IsNull() ) )
786 {
787 // Terminate the command if the end point is on a pin, junction, label, or another
788 // wire or bus.
789 if( screen->IsTerminalPoint( cursorPos, segment->GetLayer() ) )
790 {
792 segment = nullptr;
793
794 if( aQuitOnDraw )
795 {
796 m_frame->PopTool( aTool );
797 break;
798 }
799 }
800 else
801 {
802 int placedSegments = 1;
803
804 // When placing lines with the forty-five degree end, the user is
805 // targetting the endpoint with the angled portion, so it's more
806 // intuitive to place both segments at the same time.
807 if( currentMode == LINE_MODE::LINE_MODE_45 )
808 placedSegments++;
809
810 segment->SetEndPoint( cursorPos );
811
812 for( int i = 0; i < placedSegments; i++ )
813 {
814 // Create a new segment, and chain it after the current segment.
815 segment = static_cast<SCH_LINE*>( segment->Duplicate() );
816 segment->SetFlags( IS_NEW | IS_MOVING );
817 segment->SetStartPoint( cursorPos );
818 m_wires.push_back( segment );
819
820 m_selectionTool->AddItemToSel( segment, true /*quiet mode*/ );
821 }
822 }
823 }
824
825 if( evt->IsDblClick( BUT_LEFT ) && segment )
826 {
827 if( twoSegments && m_wires.size() >= 2 )
828 {
829 computeBreakPoint( { m_wires[m_wires.size() - 2], segment }, cursorPos,
830 currentMode, posture );
831 }
832
834 segment = nullptr;
835
836 if( aQuitOnDraw )
837 {
838 m_frame->PopTool( aTool );
839 break;
840 }
841 }
842 }
843 //------------------------------------------------------------------------
844 // Handle motion:
845 //
846 else if( evt->IsMotion() || evt->IsAction( &ACTIONS::refreshPreview ) )
847 {
849
850 // Update the bus unfold posture based on the mouse movement
852 {
853 VECTOR2I cursor_delta = cursorPos - m_busUnfold.origin;
855
856 bool flipX = ( cursor_delta.x < 0 );
857 bool flipY = ( cursor_delta.y < 0 );
858
859 // Erase and redraw if necessary
860 if( flipX != m_busUnfold.flipX || flipY != m_busUnfold.flipY )
861 {
862 VECTOR2I size = entry->GetSize();
863 int ySign = flipY ? -1 : 1;
864 int xSign = flipX ? -1 : 1;
865
866 size.x = std::abs( size.x ) * xSign;
867 size.y = std::abs( size.y ) * ySign;
868 entry->SetSize( size );
869
870 m_busUnfold.flipY = flipY;
871 m_busUnfold.flipX = flipX;
872
873 m_frame->UpdateItem( entry, false, true );
874 m_wires.front()->SetStartPoint( entry->GetEnd() );
875 }
876
877 // Update the label "ghost" position
878 m_busUnfold.label->SetPosition( cursorPos );
880
881 // Ensure segment is non-null at the start of bus unfold
882 if( !segment )
883 segment = m_wires.back();
884 }
885
886 if( segment )
887 {
888 // Coerce the line to vertical/horizontal/45 as necessary
889 if( twoSegments && m_wires.size() >= 2 )
890 {
891 computeBreakPoint( { m_wires[m_wires.size() - 2], segment }, cursorPos,
892 currentMode, posture );
893 }
894 else
895 {
896 segment->SetEndPoint( cursorPos );
897 }
898 }
899
900 for( SCH_LINE* wire : m_wires )
901 {
902 if( !wire->IsNull() )
903 m_view->AddToPreview( wire->Clone() );
904 }
905 }
906 else if( evt->IsAction( &EE_ACTIONS::undoLastSegment )
907 || evt->IsAction( &ACTIONS::doDelete )
908 || evt->IsAction( &ACTIONS::undo ) )
909 {
910 if( ( currentMode == LINE_MODE::LINE_MODE_FREE && m_wires.size() > 1 )
911 || ( LINE_MODE::LINE_MODE_90 && m_wires.size() > 2 ) )
912 {
914
915 m_wires.pop_back();
917 delete segment;
918
919 segment = m_wires.back();
920 cursorPos = segment->GetEndPoint();
921 getViewControls()->WarpMouseCursor( cursorPos, true );
922
923 // Find new bend point for current mode
924 if( twoSegments && m_wires.size() >= 2 )
925 {
926 computeBreakPoint( { m_wires[m_wires.size() - 2], segment }, cursorPos,
927 currentMode, posture );
928 }
929 else
930 {
931 segment->SetEndPoint( cursorPos );
932 }
933
934 for( SCH_LINE* wire : m_wires )
935 {
936 if( !wire->IsNull() )
937 m_view->AddToPreview( wire->Clone() );
938 }
939 }
940 else
941 {
942 wxBell();
943 }
944 }
945 else if( evt->IsAction( &EE_ACTIONS::switchSegmentPosture ) && m_wires.size() >= 2 )
946 {
947 posture = !posture;
948
949 // The 90 degree mode doesn't have a forced posture like
950 // the 45 degree mode and computeBreakPoint maintains existing 90s' postures.
951 // Instead, just swap the 90 angle here.
952 if( currentMode == LINE_MODE::LINE_MODE_90 )
953 {
955
956 SCH_LINE* line2 = m_wires[m_wires.size() - 1];
957 SCH_LINE* line1 = m_wires[m_wires.size() - 2];
958
959 VECTOR2I delta2 = line2->GetEndPoint() - line2->GetStartPoint();
960 VECTOR2I delta1 = line1->GetEndPoint() - line1->GetStartPoint();
961
962 line2->SetStartPoint(line2->GetEndPoint() - delta1);
963 line1->SetEndPoint(line1->GetStartPoint() + delta2);
964
965 for( SCH_LINE* wire : m_wires )
966 {
967 if( !wire->IsNull() )
968 m_view->AddToPreview( wire->Clone() );
969 }
970 }
971 else
972 {
973 computeBreakPoint( { m_wires[m_wires.size() - 2], segment }, cursorPos, currentMode,
974 posture );
975
977 }
978 }
979 //------------------------------------------------------------------------
980 // Handle context menu:
981 //
982 else if( evt->IsClick( BUT_RIGHT ) )
983 {
984 // Warp after context menu only if dragging...
985 if( !segment )
987
988 contextMenuPos = cursorPos;
990 }
991 else if( evt->Category() == TC_COMMAND && evt->Action() == TA_CHOICE_MENU_CHOICE )
992 {
993 if( *evt->GetCommandId() >= ID_POPUP_SCH_UNFOLD_BUS
994 && *evt->GetCommandId() <= ID_POPUP_SCH_UNFOLD_BUS_END )
995 {
996 wxASSERT_MSG( !segment, "Bus unfold event received when already drawing!" );
997
998 aType = LAYER_WIRE;
999 wxString net = *evt->Parameter<wxString*>();
1000 segment = doUnfoldBus( net, contextMenuPos );
1001 }
1002 }
1003 //------------------------------------------------------------------------
1004 // Handle TOOL_ACTION special cases
1005 //
1006 else if( evt->IsAction( &EE_ACTIONS::rotateCW ) || evt->IsAction( &EE_ACTIONS::rotateCCW ) )
1007 {
1009 {
1010 m_busUnfold.label->Rotate90( evt->IsAction( &EE_ACTIONS::rotateCW ) );
1012 }
1013 else
1014 {
1015 wxBell();
1016 }
1017 }
1018 else if( evt->IsAction( &ACTIONS::redo ) )
1019 {
1020 wxBell();
1021 }
1022 else
1023 {
1024 evt->SetPassEvent();
1025 }
1026
1027 // Enable autopanning and cursor capture only when there is a segment to be placed
1028 controls->SetAutoPan( segment != nullptr );
1029 controls->CaptureCursor( segment != nullptr );
1030 }
1031
1032 controls->SetAutoPan( false );
1033 controls->CaptureCursor( false );
1034 m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::ARROW );
1035 controls->ForceCursorPosition( false );
1036 return 0;
1037}
1038
1039
1041 SCH_LINE* aSegment )
1042{
1043 if( !aSegment )
1044 aSegment = m_frame->GetScreen()->GetLine( aPos, 0, aType );
1045
1046 if( !aSegment )
1047 {
1048 switch( aType )
1049 {
1050 default: aSegment = new SCH_LINE( aPos, LAYER_NOTES ); break;
1051 case LAYER_WIRE: aSegment = new SCH_LINE( aPos, LAYER_WIRE ); break;
1052 case LAYER_BUS: aSegment = new SCH_LINE( aPos, LAYER_BUS ); break;
1053 }
1054
1055 // Give segments a parent so they find the default line/wire/bus widths
1056 aSegment->SetParent( &m_frame->Schematic() );
1057 }
1058 else
1059 {
1060 aSegment = static_cast<SCH_LINE*>( aSegment->Duplicate() );
1061 aSegment->SetStartPoint( aPos );
1062 }
1063
1064
1065 aSegment->SetFlags( IS_NEW | IS_MOVING );
1066 m_wires.push_back( aSegment );
1067
1068 m_selectionTool->AddItemToSel( aSegment, true /*quiet mode*/ );
1069
1070 // We need 2 segments to go from a given start pin to an end point when the
1071 // horizontal and vertical lines only switch is on.
1073 {
1074 aSegment = static_cast<SCH_LINE*>( aSegment->Duplicate() );
1075 aSegment->SetFlags( IS_NEW | IS_MOVING );
1076 m_wires.push_back( aSegment );
1077
1078 m_selectionTool->AddItemToSel( aSegment, true /*quiet mode*/ );
1079 }
1080
1081 return aSegment;
1082}
1083
1084
1099{
1100 for( auto it = m_wires.begin(); it != m_wires.end(); )
1101 {
1102 SCH_LINE* line = *it;
1103
1104 if( line->IsNull() )
1105 {
1106 delete line;
1107 it = m_wires.erase( it );
1108 continue;
1109 }
1110
1111 auto next_it = it;
1112 ++next_it;
1113
1114 if( next_it == m_wires.end() )
1115 break;
1116
1117 SCH_LINE* next_line = *next_it;
1118
1119 if( SCH_LINE* merged = line->MergeOverlap( m_frame->GetScreen(), next_line, false ) )
1120 {
1121 delete line;
1122 delete next_line;
1123 it = m_wires.erase( it );
1124 *it = merged;
1125 }
1126
1127 ++it;
1128 }
1129}
1130
1131
1133{
1134 // Clear selection when done so that a new wire can be started.
1135 // NOTE: this must be done before simplifyWireList is called or we might end up with
1136 // freed selected items.
1138
1139 SCH_SCREEN* screen = m_frame->GetScreen();
1140 SCH_COMMIT commit( m_toolMgr );
1141
1142 // Remove segments backtracking over others
1144
1145 // Collect the possible connection points for the new lines
1146 std::vector<VECTOR2I> connections = screen->GetConnections();
1147 std::vector<VECTOR2I> new_ends;
1148
1149 // Check each new segment for possible junctions and add/split if needed
1150 for( SCH_LINE* wire : m_wires )
1151 {
1152 if( wire->HasFlag( SKIP_STRUCT ) )
1153 continue;
1154
1155 std::vector<VECTOR2I> tmpends = wire->GetConnectionPoints();
1156
1157 new_ends.insert( new_ends.end(), tmpends.begin(), tmpends.end() );
1158
1159 for( const VECTOR2I& pt : connections )
1160 {
1161 if( IsPointOnSegment( wire->GetStartPoint(), wire->GetEndPoint(), pt ) )
1162 new_ends.push_back( pt );
1163 }
1164
1165 commit.Added( wire, screen );
1166 }
1167
1169 {
1170 wxASSERT( m_busUnfold.entry && m_busUnfold.label );
1171
1172 commit.Added( m_busUnfold.entry, screen );
1174
1175 commit.Added( m_busUnfold.label, screen );
1178 }
1179 else if( !m_wires.empty() )
1180 {
1182 }
1183
1184 for( size_t ii = 1; ii < m_wires.size(); ++ii )
1186
1187 // Get the last non-null wire (this is the last created segment).
1188 if( !m_wires.empty() )
1190
1191 // Add the new wires
1192 for( SCH_LINE* wire : m_wires )
1193 {
1194 wire->ClearFlags( IS_NEW | IS_MOVING );
1195 m_frame->AddToScreen( wire, screen );
1196 }
1197
1198 m_wires.clear();
1200 m_view->ShowPreview( false );
1201
1202 getViewControls()->CaptureCursor( false );
1203 getViewControls()->SetAutoPan( false );
1204
1205 // Correct and remove segments that need to be merged.
1206 m_frame->SchematicCleanUp( &commit );
1207
1208 std::vector<SCH_ITEM*> symbols;
1209
1210 for( SCH_ITEM* symbol : m_frame->GetScreen()->Items().OfType( SCH_SYMBOL_T ) )
1211 symbols.push_back( symbol );
1212
1213 for( SCH_ITEM* symbol : symbols )
1214 {
1215 std::vector<VECTOR2I> pts = symbol->GetConnectionPoints();
1216
1217 if( pts.size() > 2 )
1218 continue;
1219
1220 for( auto pt = pts.begin(); pt != pts.end(); pt++ )
1221 {
1222 for( auto secondPt = pt + 1; secondPt != pts.end(); secondPt++ )
1223 m_frame->TrimWire( &commit, *pt, *secondPt );
1224 }
1225 }
1226
1227 for( const VECTOR2I& pt : new_ends )
1228 {
1230 m_frame->AddJunction( &commit, m_frame->GetScreen(), pt );
1231 }
1232
1234 m_busUnfold = {};
1235
1236 for( SCH_ITEM* item : m_frame->GetScreen()->Items() )
1237 item->ClearEditFlags();
1238
1239 commit.Push( _( "Draw Wires" ) );
1240}
1241
1242
1244{
1245 SCHEMATIC* sch = getModel<SCHEMATIC>();
1246 SCH_SCREEN* screen = sch->CurrentSheet().LastScreen();
1247
1248 std::set<SCH_LINE*> lines;
1249 BOX2I bb = aSelection->GetBoundingBox();
1250
1251 for( EDA_ITEM* item : screen->Items().Overlapping( SCH_LINE_T, bb ) )
1252 lines.insert( static_cast<SCH_LINE*>( item ) );
1253
1254 for( unsigned ii = 0; ii < aSelection->GetSize(); ii++ )
1255 {
1256 SCH_ITEM* item = dynamic_cast<SCH_ITEM*>( aSelection->GetItem( ii ) );
1257
1258 if( !item || !item->IsConnectable() || ( item->Type() == SCH_LINE_T ) )
1259 continue;
1260
1261 std::vector<VECTOR2I> pts = item->GetConnectionPoints();
1262
1265 for( SCH_LINE* line : lines )
1266 {
1267 std::vector<VECTOR2I> conn_pts;
1268
1269 for( const VECTOR2I& pt : pts )
1270 {
1271 if( IsPointOnSegment( line->GetStartPoint(), line->GetEndPoint(), pt ) )
1272 conn_pts.push_back( pt );
1273
1274 if( conn_pts.size() > 2 )
1275 break;
1276 }
1277
1278 if( conn_pts.size() == 2 )
1279 m_frame->TrimWire( aCommit, conn_pts[0], conn_pts[1] );
1280 }
1281 }
1282
1283 return 0;
1284}
1285
1286
1288{
1289 SCH_SCREEN* screen = m_frame->GetScreen();
1290
1291 for( const VECTOR2I& point : screen->GetNeededJunctions( aSelection->Items() ) )
1292 m_frame->AddJunction( aCommit, m_frame->GetScreen(), point );
1293
1294 return 0;
1295}
1296
1297
1299{
1303
1305}
const char * name
Definition: DXF_plotter.cpp:57
static TOOL_ACTION undo
Definition: actions.h:65
static TOOL_ACTION doDelete
Definition: actions.h:74
static TOOL_ACTION redo
Definition: actions.h:66
static TOOL_ACTION refreshPreview
Definition: actions.h:113
Defines the structure of a menu based on ACTIONs.
Definition: action_menu.h:49
TOOL_MANAGER * getToolManager() const
void Clear()
Remove all the entries from the menu (as well as its title).
void SetTitle(const wxString &aTitle) override
Set title for the menu.
Definition: action_menu.cpp:91
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:77
TOOL_INTERACTIVE * m_tool
Associates tool actions with menu item IDs. Non-owning.
Definition: action_menu.h:275
ACTION_MENU * create() const override
< Return an instance of this class. It has to be overridden in inheriting classes.
bool PassHelpTextToHandler() override
void update() override
Update menu state stub.
COMMIT & Added(EDA_ITEM *aItem, BASE_SCREEN *aScreen=nullptr)
Remove a new item from the model.
Definition: commit.h:84
void AddItem(const TOOL_ACTION &aAction, const SELECTION_CONDITION &aCondition, int aOrder=ANY_ORDER)
Add a menu entry to run a TOOL_ACTION on selected items.
void AddMenu(ACTION_MENU *aMenu, const SELECTION_CONDITION &aCondition=SELECTION_CONDITIONS::ShowAlways, int aOrder=ANY_ORDER)
Add a submenu to the menu.
void ShowInfoBarMsg(const wxString &aMsg, bool aShowCloseButton=false)
Show the WX_INFOBAR displayed on the top of the canvas with a message and an info icon on the left of...
WX_INFOBAR * GetInfoBar()
void SetCurrentCursor(KICURSOR aCursor)
Set the current cursor shape for this panel.
A base class for most all the KiCad significant classes used in schematics and boards.
Definition: eda_item.h:85
void SetFlags(EDA_ITEM_FLAGS aMask)
Definition: eda_item.h:123
KICAD_T Type() const
Returns the type of object.
Definition: eda_item.h:97
virtual bool IsType(const std::vector< KICAD_T > &aScanTypes) const
Check whether the item is one of the listed types.
Definition: eda_item.h:172
virtual void SetParent(EDA_ITEM *aParent)
Definition: eda_item.h:100
void ClearEditFlags()
Definition: eda_item.h:137
bool IsNew() const
Definition: eda_item.h:103
void SetTextSize(VECTOR2I aNewSize)
Definition: eda_text.cpp:358
static TOOL_ACTION finishLine
Definition: ee_actions.h:106
static TOOL_ACTION clearHighlight
Definition: ee_actions.h:285
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:145
static TOOL_ACTION clearSelection
Clears the current selection.
Definition: ee_actions.h:56
static TOOL_ACTION placeClassLabel
Definition: ee_actions.h:88
static TOOL_ACTION drawWire
Definition: ee_actions.h:81
static TOOL_ACTION rotateCCW
Definition: ee_actions.h:125
static TOOL_ACTION drawBus
Definition: ee_actions.h:82
static TOOL_ACTION finishWire
Definition: ee_actions.h:104
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:144
static TOOL_ACTION drawLines
Definition: ee_actions.h:98
static TOOL_ACTION finishLineWireOrBus
Definition: ee_actions.h:103
static TOOL_ACTION rotateCW
Definition: ee_actions.h:124
static TOOL_ACTION leaveSheet
Definition: ee_actions.h:217
static TOOL_ACTION placeGlobalLabel
Definition: ee_actions.h:89
static TOOL_ACTION placeHierLabel
Definition: ee_actions.h:90
static TOOL_ACTION undoLastSegment
Definition: ee_actions.h:101
static TOOL_ACTION unfoldBus
Definition: ee_actions.h:83
static TOOL_ACTION placeLabel
Definition: ee_actions.h:87
static TOOL_ACTION switchSegmentPosture
Definition: ee_actions.h:102
static TOOL_ACTION placeJunction
Definition: ee_actions.h:85
static TOOL_ACTION finishBus
Definition: ee_actions.h:105
EE_TYPE Overlapping(const BOX2I &aRect) const
Definition: sch_rtree.h:243
EE_TYPE OfType(KICAD_T aType) const
Definition: sch_rtree.h:238
EE_SELECTION & RequestSelection(const std::vector< KICAD_T > &aScanTypes={ SCH_LOCATE_ANY_T })
Return either an existing selection (filtered), or the selection at the current cursor position if th...
EE_SELECTION & GetSelection()
BOX2I GetBoundingBox() const override
A foundation class for a tool operating on a schematic or symbol.
Definition: ee_tool_base.h:48
EE_SELECTION_TOOL * m_selectionTool
Definition: ee_tool_base.h:197
bool Init() override
Init() is called once upon a registration of the tool.
Definition: ee_tool_base.h:64
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.
VECTOR2D GetCursorPosition() const
Return the current cursor position in world coordinates.
virtual VECTOR2D GetMousePosition(bool aWorldCoordinates=true) const =0
Return the current mouse pointer position.
virtual void SetAutoPan(bool aEnabled)
Turn on/off auto panning (this feature is used when there is a tool active (eg.
void ShowPreview(bool aShow=true)
Definition: view.cpp:1676
void ClearPreview()
Definition: view.cpp:1640
void AddToPreview(VIEW_ITEM *aItem, bool aTakeOwnership=true)
Definition: view.cpp:1662
These settings were stored in SCH_BASE_FRAME previously.
Holds all the data relating to one schematic.
Definition: schematic.h:75
SCH_SHEET_PATH & CurrentSheet() const override
Definition: schematic.h:136
SCH_SHEET & Root() const
Definition: schematic.h:105
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 > &aItemList, 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:353
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:151
virtual bool IsConnectable() const
Definition: sch_item.h:372
SCH_LAYER_ID GetLayer() const
Return the layer this item is on.
Definition: sch_item.h:258
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:147
virtual std::vector< VECTOR2I > GetConnectionPoints() const
Add all the connection points for this item to aPoints.
Definition: sch_item.h:387
SCH_ITEM * Duplicate(bool doClone=false) const
Routine to create a new copy of given item.
Definition: sch_item.cpp:94
void SetIsDangling(bool aIsDangling)
Definition: sch_label.h:313
void SetPosition(const VECTOR2I &aPosition) override
Definition: sch_label.cpp:410
void Rotate90(bool aClockwise) override
Definition: sch_label.cpp:441
virtual void SetSpinStyle(SPIN_STYLE aSpinStyle)
Definition: sch_label.cpp:337
EDA_ITEM * Clone() const override
Create a duplicate of this item with linked list members set to NULL.
Definition: sch_label.h:395
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)
static bool IsDrawingWire(const SELECTION &aSelection)
int doDrawSegments(const TOOL_EVENT &aTool, int aType, bool aQuitOnDraw)
static bool IsDrawingBus(const SELECTION &aSelection)
bool Init() override
Init() is called once upon a registration of the tool.
const SCH_SHEET_PIN * getSheetPin(const VECTOR2I &aPosition)
Search for a sheet pin at a location.
std::vector< SCH_LINE * > m_wires
int TrimOverLappingWires(SCH_COMMIT *aCommit, EE_SELECTION *aSelection)
Logic to remove wires when overlapping correct items.
static bool IsDrawingLineWireOrBus(const SELECTION &aSelection)
SCH_LINE * doUnfoldBus(const wxString &aNet, const VECTOR2I &aPos=VECTOR2I(0, 0))
SCH_LINE * startSegments(int aType, const VECTOR2D &aPos, SCH_LINE *aSegment=nullptr)
void simplifyWireList()
Iterate over the wire list and removes the null segments and overlapping segments to create a simplif...
static bool IsDrawingLine(const SELECTION &aSelection)
Segment description base class to describe items which have 2 end points (track, wire,...
Definition: sch_line.h:40
void SetStartPoint(const VECTOR2I &aPosition)
Definition: sch_line.h:141
VECTOR2I GetEndPoint() const
Definition: sch_line.h:145
VECTOR2I GetStartPoint() const
Definition: sch_line.h:140
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:470
bool IsNull() const
Definition: sch_line.h:138
void SetEndPoint(const VECTOR2I &aPosition)
Definition: sch_line.h:146
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:109
bool IsTerminalPoint(const VECTOR2I &aPosition, int aLayer) const
Test if aPosition is a connection point on aLayer.
Definition: sch_screen.cpp:815
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:134
static SELECTION_CONDITION MoreThan(int aNumber)
Create a functor that tests if the number of selected items is greater than the value given as parame...
static bool Idle(const SELECTION &aSelection)
Test if there no items selected or being edited.
static bool ShowAlways(const SELECTION &aSelection)
The default condition function (always returns true).
static SELECTION_CONDITION OnlyTypes(std::vector< KICAD_T > aTypes)
Create a functor that tests if the selected items are only of given types.
int RemoveItemFromSel(const TOOL_EVENT &aEvent)
int AddItemToSel(const TOOL_EVENT &aEvent)
virtual KIGFX::VIEW_ITEM * GetItem(unsigned int aIdx) const override
Definition: selection.cpp:75
virtual unsigned int GetSize() const override
Return the number of stored items.
Definition: selection.h:99
EDA_ITEM * Front() const
Definition: selection.h:208
std::deque< EDA_ITEM * > & Items()
Definition: selection.h:213
virtual void PopTool(const TOOL_EVENT &aEvent)
Pops a tool from the stack.
virtual void PushTool(const TOOL_EVENT &aEvent)
NB: the definition of "tool" is different at the user level.
bool IsCurrentTool(const TOOL_ACTION &aAction) const
KIGFX::VIEW_CONTROLS * getViewControls() const
Return the instance of VIEW_CONTROLS object used in the application.
Definition: tool_base.cpp:42
TOOL_MANAGER * m_toolMgr
Definition: tool_base.h:216
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()
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:145
bool PostAction(const std::string &aActionName, T aParam)
Run the specified action after the current action (coroutine) ends.
Definition: tool_manager.h:230
void VetoContextMenuMouseWarp()
Disable mouse warping after the current context menu is closed.
Definition: tool_manager.h:517
CONDITIONAL_MENU & GetMenu()
Definition: tool_menu.cpp:44
void RegisterSubMenu(std::shared_ptr< ACTION_MENU > aSubMenu)
Store a submenu of this menu model.
Definition: tool_menu.cpp:50
void ShowContextMenu(SELECTION &aSelection)
Helper function to set and immediately show a CONDITIONAL_MENU in concert with the given SELECTION.
Definition: tool_menu.cpp:57
void Dismiss() override
Dismisses the infobar and updates the containing layout and AUI manager (if one is provided).
Definition: wx_infobar.cpp:187
#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_WIRES
Definition: grid_helper.h:42
@ LAYER_WIRE
Definition: layer_ids.h:349
@ LAYER_NOTES
Definition: layer_ids.h:363
@ LAYER_BUS
Definition: layer_ids.h:350
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:426
SHEET_SIDE
Define the edge of the sheet that the sheet pin is positioned.
Definition: sch_sheet_pin.h:46
bool label_placed
True if user has placed the net label.
wxString net_name
Net label for the unfolding operation.
bool flipY
True if the bus entry should be flipped in the y-axis.
SCH_BUS_WIRE_ENTRY * entry
bool flipX
True if the bus entry should be flipped in the x-axis.
VECTOR2I origin
Origin (on the bus) of the unfold.
bool in_progress
True if bus unfold operation is running.
constexpr int delta
@ CMENU_NOW
Definition: tool_event.h: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:88
@ SCH_LINE_T
Definition: typeinfo.h:146
@ SCH_SYMBOL_T
Definition: typeinfo.h:156
@ SCH_ITEM_LOCATE_WIRE_T
Definition: typeinfo.h:170
@ SCH_SHEET_T
Definition: typeinfo.h:158
@ SCH_ITEM_LOCATE_BUS_T
Definition: typeinfo.h:171
@ SCH_ITEM_LOCATE_GRAPHIC_LINE_T
Definition: typeinfo.h:172
constexpr ret_type KiROUND(fp_type v)
Round a floating point number to an integer using "round halfway cases away from zero".
Definition: util.h:85
VECTOR2< double > VECTOR2D
Definition: vector2d.h:587
VECTOR2< int > VECTOR2I
Definition: vector2d.h:588