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.AddSeparator( 10 );
216 ctxMenu.AddItem( EE_ACTIONS::drawWire, wireOrBusTool && EE_CONDITIONS::Idle, 10 );
217 ctxMenu.AddItem( EE_ACTIONS::drawBus, wireOrBusTool && EE_CONDITIONS::Idle, 10 );
218 ctxMenu.AddItem( EE_ACTIONS::drawLines, lineTool && EE_CONDITIONS::Idle, 10 );
219
223
224 ctxMenu.AddMenu( busUnfoldMenu.get(), EE_CONDITIONS::Idle, 10 );
225
226 ctxMenu.AddSeparator( 100 );
227 ctxMenu.AddItem( EE_ACTIONS::placeJunction, wireOrBusTool && EE_CONDITIONS::Idle, 100 );
228 ctxMenu.AddItem( EE_ACTIONS::placeLabel, wireOrBusTool && EE_CONDITIONS::Idle, 100 );
229 ctxMenu.AddItem( EE_ACTIONS::placeClassLabel, wireOrBusTool && EE_CONDITIONS::Idle, 100 );
230 ctxMenu.AddItem( EE_ACTIONS::placeGlobalLabel, wireOrBusTool && EE_CONDITIONS::Idle, 100 );
231 ctxMenu.AddItem( EE_ACTIONS::placeHierLabel, wireOrBusTool && EE_CONDITIONS::Idle, 100 );
232 ctxMenu.AddItem( EE_ACTIONS::breakWire, wireOrBusTool && EE_CONDITIONS::Idle, 100 );
233 ctxMenu.AddItem( EE_ACTIONS::slice, ( wireOrBusTool || lineTool )
234 && EE_CONDITIONS::Idle, 100 );
235 ctxMenu.AddItem( EE_ACTIONS::leaveSheet, belowRootSheetCondition, 150 );
236
237 ctxMenu.AddSeparator( 200 );
238 ctxMenu.AddItem( EE_ACTIONS::selectNode, wireOrBusTool && EE_CONDITIONS::Idle, 200 );
239 ctxMenu.AddItem( EE_ACTIONS::selectConnection, wireOrBusTool && EE_CONDITIONS::Idle, 200 );
240
241 // Add bus unfolding to the selection tool
242 //
244
245 selToolMenu.AddMenu( selBusUnfoldMenu.get(), busSelection && EE_CONDITIONS::Idle, 100 );
246
247 return true;
248}
249
250
252{
253 // NOTE: for immediate hotkeys, it is NOT required that the line, wire or bus tool
254 // be selected
255 SCH_ITEM* item = (SCH_ITEM*) aSelection.Front();
256 return item && item->IsNew() && item->Type() == SCH_LINE_T;
257}
258
259
261{
262 if( m_inDrawingTool )
263 return 0;
264
266
267 const DRAW_SEGMENT_EVENT_PARAMS* params = aEvent.Parameter<const DRAW_SEGMENT_EVENT_PARAMS*>();
268
269 m_frame->PushTool( aEvent );
271
272 if( aEvent.HasPosition() )
273 {
275 GRID_HELPER_GRIDS gridType = ( params->layer == LAYER_NOTES ) ? GRID_GRAPHICS : GRID_WIRES;
276
277 grid.SetSnap( !aEvent.Modifier( MD_SHIFT ) );
278 grid.SetUseGrid( getView()->GetGAL()->GetGridSnapping() && !aEvent.DisableGridSnapping() );
279
280 VECTOR2D cursorPos = grid.BestSnapAnchor( aEvent.Position(), gridType, nullptr );
281 startSegments( params->layer, cursorPos, params->sourceSegment );
282 }
283
284 return doDrawSegments( aEvent, params->layer, params->quitOnDraw );
285}
286
287
289{
290 if( m_inDrawingTool )
291 return 0;
292
294
295 wxString* netPtr = aEvent.Parameter<wxString*>();
296 wxString net;
297 SCH_LINE* segment = nullptr;
298
299 m_frame->PushTool( aEvent );
300 Activate();
301
302 if( netPtr )
303 {
304 net = *netPtr;
305 delete netPtr;
306 }
307 else
308 {
309 BUS_UNFOLD_MENU unfoldMenu;
310 unfoldMenu.SetTool( this );
311 unfoldMenu.SetShowTitle();
312
313 SetContextMenu( &unfoldMenu, CMENU_NOW );
314
315 while( TOOL_EVENT* evt = Wait() )
316 {
317 if( evt->Action() == TA_CHOICE_MENU_CHOICE )
318 {
319 std::optional<int> id = evt->GetCommandId();
320
321 if( id && ( *id > 0 ) )
322 net = *evt->Parameter<wxString*>();
323
324 break;
325 }
326 else if( evt->Action() == TA_CHOICE_MENU_CLOSED )
327 {
328 break;
329 }
330 else
331 {
332 evt->SetPassEvent();
333 }
334 }
335 }
336
337 // Break a wire for the given net out of the bus
338 if( !net.IsEmpty() )
339 segment = doUnfoldBus( net );
340
341 // If we have an unfolded wire to draw, then draw it
342 if( segment )
343 {
344 return doDrawSegments( aEvent, LAYER_WIRE, false );
345 }
346 else
347 {
348 m_frame->PopTool( aEvent );
349 return 0;
350 }
351}
352
353
354SCH_LINE* SCH_LINE_WIRE_BUS_TOOL::doUnfoldBus( const wxString& aNet, const VECTOR2I& aPos )
355{
356 SCHEMATIC_SETTINGS& cfg = getModel<SCHEMATIC>()->Settings();
357 SCH_SCREEN* screen = m_frame->GetScreen();
358
359 VECTOR2I pos = aPos;
360
361 if( aPos == VECTOR2I( 0, 0 ) )
362 pos = static_cast<VECTOR2I>( getViewControls()->GetCursorPosition() );
363
365
367 m_busUnfold.entry->SetParent( screen );
369
375
377 m_busUnfold.origin = pos;
378 m_busUnfold.net_name = aNet;
379
381
382 std::vector<DANGLING_END_ITEM> endPointsByType;
383
384 for( SCH_ITEM* item : screen->Items().Overlapping( m_busUnfold.entry->GetBoundingBox() ) )
385 item->GetEndPoints( endPointsByType );
386
387 std::vector<DANGLING_END_ITEM> endPointsByPos = endPointsByType;
388 DANGLING_END_ITEM_HELPER::sort_dangling_end_items( endPointsByType, endPointsByPos );
389 m_busUnfold.entry->UpdateDanglingState( endPointsByType, endPointsByPos );
392
394}
395
396
398{
399 SCH_SCREEN* screen = m_frame->GetScreen();
400
401 for( SCH_ITEM* item : screen->Items().Overlapping( SCH_SHEET_T, aPosition ) )
402 {
403 SCH_SHEET* sheet = static_cast<SCH_SHEET*>( item );
404
405 for( SCH_SHEET_PIN* pin : sheet->GetPins() )
406 {
407 if( pin->GetPosition() == aPosition )
408 return pin;
409 }
410 }
411
412 return nullptr;
413}
414
415
416void SCH_LINE_WIRE_BUS_TOOL::computeBreakPoint( const std::pair<SCH_LINE*, SCH_LINE*>& aSegments,
417 VECTOR2I& aPosition,
418 LINE_MODE mode,
419 bool posture )
420{
421 wxCHECK_RET( aSegments.first && aSegments.second,
422 wxT( "Cannot compute break point of NULL line segment." ) );
423
424 VECTOR2I midPoint;
425 SCH_LINE* segment = aSegments.first;
426 SCH_LINE* nextSegment = aSegments.second;
427
428 VECTOR2I delta = aPosition - segment->GetStartPoint();
429 int xDir = delta.x > 0 ? 1 : -1;
430 int yDir = delta.y > 0 ? 1 : -1;
431
432
433 bool preferHorizontal;
434 bool preferVertical;
435
436 if( ( mode == LINE_MODE_45 ) && posture )
437 {
438 preferHorizontal = ( nextSegment->GetEndPoint().x - nextSegment->GetStartPoint().x ) != 0;
439 preferVertical = ( nextSegment->GetEndPoint().y - nextSegment->GetStartPoint().y ) != 0;
440 }
441 else
442 {
443 preferHorizontal = ( segment->GetEndPoint().x - segment->GetStartPoint().x ) != 0;
444 preferVertical = ( segment->GetEndPoint().y - segment->GetStartPoint().y ) != 0;
445 }
446
447 // Check for times we need to force horizontal sheet pin connections
448 const SCH_SHEET_PIN* connectedPin = getSheetPin( segment->GetStartPoint() );
449 SHEET_SIDE force = connectedPin ? connectedPin->GetSide() : SHEET_SIDE::UNDEFINED;
450
451 if( force == SHEET_SIDE::LEFT || force == SHEET_SIDE::RIGHT )
452 {
453 if( aPosition.x == connectedPin->GetPosition().x ) // push outside sheet boundary
454 {
455 int direction = ( force == SHEET_SIDE::LEFT ) ? -1 : 1;
456 aPosition.x += KiROUND( getView()->GetGAL()->GetGridSize().x * direction );
457 }
458
459 preferHorizontal = true;
460 preferVertical = false;
461 }
462
463
464 auto breakVertical = [&]() mutable
465 {
466 switch( mode )
467 {
468 case LINE_MODE_45:
469 if( !posture )
470 {
471 midPoint.x = segment->GetStartPoint().x;
472 midPoint.y = aPosition.y - yDir * abs( delta.x );
473 }
474 else
475 {
476 midPoint.x = aPosition.x;
477 midPoint.y = segment->GetStartPoint().y + yDir * abs( delta.x );
478 }
479 break;
480 default:
481 midPoint.x = segment->GetStartPoint().x;
482 midPoint.y = aPosition.y;
483 }
484 };
485
486
487 auto breakHorizontal = [&]() mutable
488 {
489 switch( mode )
490 {
491 case LINE_MODE_45:
492 if( !posture )
493 {
494 midPoint.x = aPosition.x - xDir * abs( delta.y );
495 midPoint.y = segment->GetStartPoint().y;
496 }
497 else
498 {
499 midPoint.x = segment->GetStartPoint().x + xDir * abs( delta.y );
500 midPoint.y = aPosition.y;
501 }
502 break;
503 default:
504 midPoint.x = aPosition.x;
505 midPoint.y = segment->GetStartPoint().y;
506 }
507 };
508
509
510 // Maintain current line shape if we can, e.g. if we were originally moving
511 // vertically keep the first segment vertical
512 if( preferVertical )
513 breakVertical();
514 else if( preferHorizontal )
515 breakHorizontal();
516
517 // Check if our 45 degree angle is one of these shapes
518 // /
519 // /
520 // /
521 // /__________
522 VECTOR2I deltaMidpoint = midPoint - segment->GetStartPoint();
523
524 if( mode == LINE_MODE::LINE_MODE_45 && !posture
525 && ( ( alg::signbit( deltaMidpoint.x ) != alg::signbit( delta.x ) )
526 || ( alg::signbit( deltaMidpoint.y ) != alg::signbit( delta.y ) ) ) )
527 {
528 preferVertical = false;
529 preferHorizontal = false;
530 }
531 else if( mode == LINE_MODE::LINE_MODE_45 && posture
532 && ( ( abs( deltaMidpoint.x ) > abs( delta.x ) )
533 || ( abs( deltaMidpoint.y ) > abs( delta.y ) ) ) )
534 {
535 preferVertical = false;
536 preferHorizontal = false;
537 }
538
539 if( !preferHorizontal && !preferVertical )
540 {
541 if( std::abs( delta.x ) < std::abs( delta.y ) )
542 breakVertical();
543 else
544 breakHorizontal();
545 }
546
547 segment->SetEndPoint( midPoint );
548 nextSegment->SetStartPoint( midPoint );
549 nextSegment->SetEndPoint( aPosition );
550}
551
552
553int SCH_LINE_WIRE_BUS_TOOL::doDrawSegments( const TOOL_EVENT& aTool, int aType, bool aQuitOnDraw )
554{
555 SCH_SCREEN* screen = m_frame->GetScreen();
556 SCH_LINE* segment = nullptr;
558 GRID_HELPER_GRIDS gridType = ( aType == LAYER_NOTES ) ? GRID_GRAPHICS : GRID_WIRES;
560 int lastMode = m_frame->eeconfig()->m_Drawing.line_mode;
561 static bool posture = false;
562
563 auto setCursor =
564 [&]()
565 {
566 if( aType == LAYER_WIRE )
567 m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::LINE_WIRE );
568 else if( aType == LAYER_BUS )
569 m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::LINE_BUS );
570 else if( aType == LAYER_NOTES )
571 m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::LINE_GRAPHIC );
572 else
573 m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::LINE_WIRE );
574 };
575
576 auto cleanup =
577 [&] ()
578 {
580
581 for( SCH_LINE* wire : m_wires )
582 delete wire;
583
584 m_wires.clear();
585 segment = nullptr;
586
587 if( m_busUnfold.entry )
589
592
595
596 delete m_busUnfold.entry;
597 delete m_busUnfold.label;
598 m_busUnfold = {};
599
601 m_view->ShowPreview( false );
602 };
603
604 Activate();
605 // Must be done after Activate() so that it gets set into the correct context
606 controls->ShowCursor( true );
607 // Set initial cursor
608 setCursor();
609
610 // Add the new label to the selection so the rotate command operates on it
611 if( m_busUnfold.label )
613
614 // Continue the existing wires if we've started (usually by immediate action preference)
615 if( !m_wires.empty() )
616 segment = m_wires.back();
617
618 VECTOR2I contextMenuPos;
619
620 // Main loop: keep receiving events
621 while( TOOL_EVENT* evt = Wait() )
622 {
624 bool twoSegments = currentMode != LINE_MODE::LINE_MODE_FREE;
625
626 // The tool hotkey is interpreted as a click when drawing
627 bool isSyntheticClick = ( segment || m_busUnfold.in_progress ) && evt->IsActivate()
628 && evt->HasPosition() && evt->Matches( aTool );
629
630 setCursor();
631 grid.SetMask( GRID_HELPER::ALL );
632 grid.SetSnap( !evt->Modifier( MD_SHIFT ) );
633 grid.SetUseGrid( getView()->GetGAL()->GetGridSnapping() && !evt->DisableGridSnapping() );
634
635 if( segment )
636 {
637 if( segment->GetStartPoint().x == segment->GetEndPoint().x )
638 grid.ClearMaskFlag( GRID_HELPER::VERTICAL );
639
640 if( segment->GetStartPoint().y == segment->GetEndPoint().y )
641 grid.ClearMaskFlag( GRID_HELPER::HORIZONTAL );
642 }
643
644 VECTOR2D eventPosition = evt->HasPosition() ? evt->Position()
645 : controls->GetMousePosition();
646
647 VECTOR2I cursorPos = grid.BestSnapAnchor( eventPosition, gridType, segment );
648 controls->ForceCursorPosition( true, cursorPos );
649
650 // Need to handle change in H/V mode while drawing
651 if( currentMode != lastMode )
652 {
653 // Need to delete extra segment if we have one
654 if( segment && currentMode == LINE_MODE::LINE_MODE_FREE && m_wires.size() >= 2 )
655 {
656 m_wires.pop_back();
658 delete segment;
659
660 segment = m_wires.back();
661 segment->SetEndPoint( cursorPos );
662 }
663 // Add a segment so we can move orthogonally/45
664 else if( segment && lastMode == LINE_MODE::LINE_MODE_FREE )
665 {
666 segment->SetEndPoint( cursorPos );
667
668 // Create a new segment, and chain it after the current segment.
669 segment = static_cast<SCH_LINE*>( segment->Duplicate() );
670 segment->SetFlags( IS_NEW | IS_MOVING );
671 segment->SetStartPoint( cursorPos );
672 m_wires.push_back( segment );
673
674 m_selectionTool->AddItemToSel( segment, true /*quiet mode*/ );
675 }
676
677 lastMode = currentMode;
678 }
679
680 //------------------------------------------------------------------------
681 // Handle cancel:
682 //
683 if( evt->IsCancelInteractive() )
684 {
686
687 if( segment || m_busUnfold.in_progress )
688 {
689 cleanup();
690
691 if( aQuitOnDraw )
692 {
693 m_frame->PopTool( aTool );
694 break;
695 }
696 }
697 else
698 {
699 m_frame->PopTool( aTool );
700 break;
701 }
702 }
703 else if( evt->IsActivate() && !isSyntheticClick )
704 {
705 if( segment || m_busUnfold.in_progress )
706 {
707 m_frame->ShowInfoBarMsg( _( "Press <ESC> to cancel drawing." ) );
708 evt->SetPassEvent( false );
709 continue;
710 }
711
712 if( evt->IsMoveTool() )
713 {
714 // leave ourselves on the stack so we come back after the move
715 break;
716 }
717 else
718 {
719 m_frame->PopTool( aTool );
720 break;
721 }
722 }
723 //------------------------------------------------------------------------
724 // Handle finish:
725 //
726 else if( evt->IsAction( &ACTIONS::finishInteractive ) )
727 {
728 if( segment || m_busUnfold.in_progress )
729 {
731 segment = nullptr;
732
733 if( aQuitOnDraw )
734 {
735 m_frame->PopTool( aTool );
736 break;
737 }
738 }
739 }
740 //------------------------------------------------------------------------
741 // Handle click:
742 //
743 else if( evt->IsClick( BUT_LEFT )
744 || ( segment && evt->IsDblClick( BUT_LEFT ) )
745 || isSyntheticClick )
746 {
747 // First click when unfolding places the label and wire-to-bus entry
749 {
750 wxASSERT( aType == LAYER_WIRE );
751
755 }
756
757 if( !segment )
758 {
759 segment = startSegments( aType, VECTOR2D( cursorPos ) );
760 }
761 // Create a new segment if we're out of previously-created ones
762 else if( !segment->IsNull()
763 || ( twoSegments && !m_wires[m_wires.size() - 2]->IsNull() ) )
764 {
765 // Terminate the command if the end point is on a pin, junction, label, or another
766 // wire or bus.
767 if( screen->IsTerminalPoint( cursorPos, segment->GetLayer() ) )
768 {
770 segment = nullptr;
771
772 if( aQuitOnDraw )
773 {
774 m_frame->PopTool( aTool );
775 break;
776 }
777 }
778 else
779 {
780 int placedSegments = 1;
781
782 // When placing lines with the forty-five degree end, the user is
783 // targetting the endpoint with the angled portion, so it's more
784 // intuitive to place both segments at the same time.
785 if( currentMode == LINE_MODE::LINE_MODE_45 )
786 placedSegments++;
787
788 segment->SetEndPoint( cursorPos );
789
790 for( int i = 0; i < placedSegments; i++ )
791 {
792 // Create a new segment, and chain it after the current segment.
793 segment = static_cast<SCH_LINE*>( segment->Duplicate() );
794 segment->SetFlags( IS_NEW | IS_MOVING );
795 segment->SetStartPoint( cursorPos );
796 m_wires.push_back( segment );
797
798 m_selectionTool->AddItemToSel( segment, true /*quiet mode*/ );
799 }
800 }
801 }
802
803 if( evt->IsDblClick( BUT_LEFT ) && segment )
804 {
805 if( twoSegments && m_wires.size() >= 2 )
806 {
807 computeBreakPoint( { m_wires[m_wires.size() - 2], segment }, cursorPos,
808 currentMode, posture );
809 }
810
812 segment = nullptr;
813
814 if( aQuitOnDraw )
815 {
816 m_frame->PopTool( aTool );
817 break;
818 }
819 }
820 }
821 //------------------------------------------------------------------------
822 // Handle motion:
823 //
824 else if( evt->IsMotion() || evt->IsAction( &ACTIONS::refreshPreview ) )
825 {
827
828 // Update the bus unfold posture based on the mouse movement
830 {
831 VECTOR2I cursor_delta = cursorPos - m_busUnfold.origin;
833
834 bool flipX = ( cursor_delta.x < 0 );
835 bool flipY = ( cursor_delta.y < 0 );
836
837 // Erase and redraw if necessary
838 if( flipX != m_busUnfold.flipX || flipY != m_busUnfold.flipY )
839 {
840 VECTOR2I size = entry->GetSize();
841 int ySign = flipY ? -1 : 1;
842 int xSign = flipX ? -1 : 1;
843
844 size.x = std::abs( size.x ) * xSign;
845 size.y = std::abs( size.y ) * ySign;
846 entry->SetSize( size );
847
848 m_busUnfold.flipY = flipY;
849 m_busUnfold.flipX = flipX;
850
851 m_frame->UpdateItem( entry, false, true );
852 m_wires.front()->SetStartPoint( entry->GetEnd() );
853 }
854
855 // Update the label "ghost" position
856 m_busUnfold.label->SetPosition( cursorPos );
858
859 // Ensure segment is non-null at the start of bus unfold
860 if( !segment )
861 segment = m_wires.back();
862 }
863
864 if( segment )
865 {
866 // Coerce the line to vertical/horizontal/45 as necessary
867 if( twoSegments && m_wires.size() >= 2 )
868 {
869 computeBreakPoint( { m_wires[m_wires.size() - 2], segment }, cursorPos,
870 currentMode, posture );
871 }
872 else
873 {
874 segment->SetEndPoint( cursorPos );
875 }
876 }
877
878 for( SCH_LINE* wire : m_wires )
879 {
880 if( !wire->IsNull() )
881 m_view->AddToPreview( wire->Clone() );
882 }
883 }
884 else if( evt->IsAction( &EE_ACTIONS::undoLastSegment )
885 || evt->IsAction( &ACTIONS::doDelete )
886 || evt->IsAction( &ACTIONS::undo ) )
887 {
888 if( ( currentMode == LINE_MODE::LINE_MODE_FREE && m_wires.size() > 1 )
889 || ( LINE_MODE::LINE_MODE_90 && m_wires.size() > 2 ) )
890 {
892
893 m_wires.pop_back();
895 delete segment;
896
897 segment = m_wires.back();
898 cursorPos = segment->GetEndPoint();
899 getViewControls()->WarpMouseCursor( cursorPos, true );
900
901 // Find new bend point for current mode
902 if( twoSegments && m_wires.size() >= 2 )
903 {
904 computeBreakPoint( { m_wires[m_wires.size() - 2], segment }, cursorPos,
905 currentMode, posture );
906 }
907 else
908 {
909 segment->SetEndPoint( cursorPos );
910 }
911
912 for( SCH_LINE* wire : m_wires )
913 {
914 if( !wire->IsNull() )
915 m_view->AddToPreview( wire->Clone() );
916 }
917 }
918 else if( evt->IsAction( &ACTIONS::undo ) )
919 {
920 // Dispatch as normal undo event
921 evt->SetPassEvent();
922 }
923 else
924 {
925 wxBell();
926 }
927 }
928 else if( evt->IsAction( &EE_ACTIONS::switchSegmentPosture ) && m_wires.size() >= 2 )
929 {
930 posture = !posture;
931
932 // The 90 degree mode doesn't have a forced posture like
933 // the 45 degree mode and computeBreakPoint maintains existing 90s' postures.
934 // Instead, just swap the 90 angle here.
935 if( currentMode == LINE_MODE::LINE_MODE_90 )
936 {
938
939 SCH_LINE* line2 = m_wires[m_wires.size() - 1];
940 SCH_LINE* line1 = m_wires[m_wires.size() - 2];
941
942 VECTOR2I delta2 = line2->GetEndPoint() - line2->GetStartPoint();
943 VECTOR2I delta1 = line1->GetEndPoint() - line1->GetStartPoint();
944
945 line2->SetStartPoint(line2->GetEndPoint() - delta1);
946 line1->SetEndPoint(line1->GetStartPoint() + delta2);
947
948 for( SCH_LINE* wire : m_wires )
949 {
950 if( !wire->IsNull() )
951 m_view->AddToPreview( wire->Clone() );
952 }
953 }
954 else
955 {
956 computeBreakPoint( { m_wires[m_wires.size() - 2], segment }, cursorPos, currentMode,
957 posture );
958
960 }
961 }
962 //------------------------------------------------------------------------
963 // Handle context menu:
964 //
965 else if( evt->IsClick( BUT_RIGHT ) )
966 {
967 // Warp after context menu only if dragging...
968 if( !segment )
970
971 contextMenuPos = cursorPos;
973 }
974 else if( evt->Category() == TC_COMMAND && evt->Action() == TA_CHOICE_MENU_CHOICE )
975 {
976 if( *evt->GetCommandId() >= ID_POPUP_SCH_UNFOLD_BUS
977 && *evt->GetCommandId() <= ID_POPUP_SCH_UNFOLD_BUS_END )
978 {
979 wxASSERT_MSG( !segment, "Bus unfold event received when already drawing!" );
980
981 aType = LAYER_WIRE;
982 wxString net = *evt->Parameter<wxString*>();
983 segment = doUnfoldBus( net, contextMenuPos );
984 }
985 }
986 //------------------------------------------------------------------------
987 // Handle TOOL_ACTION special cases
988 //
989 else if( evt->IsAction( &EE_ACTIONS::rotateCW ) || evt->IsAction( &EE_ACTIONS::rotateCCW ) )
990 {
992 {
993 m_busUnfold.label->Rotate90( evt->IsAction( &EE_ACTIONS::rotateCW ) );
995 }
996 else
997 {
998 wxBell();
999 }
1000 }
1001 else if( evt->IsAction( &ACTIONS::redo ) )
1002 {
1003 wxBell();
1004 }
1005 else
1006 {
1007 evt->SetPassEvent();
1008 }
1009
1010 // Enable autopanning and cursor capture only when there is a segment to be placed
1011 controls->SetAutoPan( segment != nullptr );
1012 controls->CaptureCursor( segment != nullptr );
1013 }
1014
1015 controls->SetAutoPan( false );
1016 controls->CaptureCursor( false );
1017 m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::ARROW );
1018 controls->ForceCursorPosition( false );
1019 return 0;
1020}
1021
1022
1024 SCH_LINE* aSegment )
1025{
1026 if( !aSegment )
1027 aSegment = m_frame->GetScreen()->GetLine( aPos, 0, aType );
1028
1029 if( !aSegment )
1030 {
1031 switch( aType )
1032 {
1033 default: aSegment = new SCH_LINE( aPos, LAYER_NOTES ); break;
1034 case LAYER_WIRE: aSegment = new SCH_LINE( aPos, LAYER_WIRE ); break;
1035 case LAYER_BUS: aSegment = new SCH_LINE( aPos, LAYER_BUS ); break;
1036 }
1037
1038 // Give segments a parent so they find the default line/wire/bus widths
1039 aSegment->SetParent( &m_frame->Schematic() );
1040 }
1041 else
1042 {
1043 aSegment = static_cast<SCH_LINE*>( aSegment->Duplicate() );
1044 aSegment->SetStartPoint( aPos );
1045 }
1046
1047
1048 aSegment->SetFlags( IS_NEW | IS_MOVING );
1049 m_wires.push_back( aSegment );
1050
1051 m_selectionTool->AddItemToSel( aSegment, true /*quiet mode*/ );
1052
1053 // We need 2 segments to go from a given start pin to an end point when the
1054 // horizontal and vertical lines only switch is on.
1056 {
1057 aSegment = static_cast<SCH_LINE*>( aSegment->Duplicate() );
1058 aSegment->SetFlags( IS_NEW | IS_MOVING );
1059 m_wires.push_back( aSegment );
1060
1061 m_selectionTool->AddItemToSel( aSegment, true /*quiet mode*/ );
1062 }
1063
1064 return aSegment;
1065}
1066
1067
1082{
1083 for( auto it = m_wires.begin(); it != m_wires.end(); )
1084 {
1085 SCH_LINE* line = *it;
1086
1087 if( line->IsNull() )
1088 {
1089 delete line;
1090 it = m_wires.erase( it );
1091 continue;
1092 }
1093
1094 auto next_it = it;
1095 ++next_it;
1096
1097 if( next_it == m_wires.end() )
1098 break;
1099
1100 SCH_LINE* next_line = *next_it;
1101
1102 if( SCH_LINE* merged = line->MergeOverlap( m_frame->GetScreen(), next_line, false ) )
1103 {
1104 delete line;
1105 delete next_line;
1106 it = m_wires.erase( it );
1107 *it = merged;
1108 }
1109
1110 ++it;
1111 }
1112}
1113
1114
1116{
1117 // Clear selection when done so that a new wire can be started.
1118 // NOTE: this must be done before simplifyWireList is called or we might end up with
1119 // freed selected items.
1121
1122 SCH_SCREEN* screen = m_frame->GetScreen();
1123 SCH_COMMIT commit( m_toolMgr );
1124
1125 // Remove segments backtracking over others
1127
1128 // Collect the possible connection points for the new lines
1129 std::vector<VECTOR2I> connections = screen->GetConnections();
1130 std::vector<VECTOR2I> new_ends;
1131
1132 // Check each new segment for possible junctions and add/split if needed
1133 for( SCH_LINE* wire : m_wires )
1134 {
1135 if( wire->HasFlag( SKIP_STRUCT ) )
1136 continue;
1137
1138 std::vector<VECTOR2I> tmpends = wire->GetConnectionPoints();
1139
1140 new_ends.insert( new_ends.end(), tmpends.begin(), tmpends.end() );
1141
1142 for( const VECTOR2I& pt : connections )
1143 {
1144 if( IsPointOnSegment( wire->GetStartPoint(), wire->GetEndPoint(), pt ) )
1145 new_ends.push_back( pt );
1146 }
1147
1148 commit.Added( wire, screen );
1149 }
1150
1152 {
1153 wxASSERT( m_busUnfold.entry && m_busUnfold.label );
1154
1155 commit.Added( m_busUnfold.entry, screen );
1157
1158 commit.Added( m_busUnfold.label, screen );
1161 }
1162 else if( !m_wires.empty() )
1163 {
1165 }
1166
1167 for( size_t ii = 1; ii < m_wires.size(); ++ii )
1169
1170 // Get the last non-null wire (this is the last created segment).
1171 if( !m_wires.empty() )
1173
1174 // Add the new wires
1175 for( SCH_LINE* wire : m_wires )
1176 {
1177 wire->ClearFlags( IS_NEW | IS_MOVING );
1178 m_frame->AddToScreen( wire, screen );
1179 }
1180
1181 m_wires.clear();
1183 m_view->ShowPreview( false );
1184
1185 getViewControls()->CaptureCursor( false );
1186 getViewControls()->SetAutoPan( false );
1187
1188 // Correct and remove segments that need to be merged.
1189 m_frame->SchematicCleanUp( &commit );
1190
1191 std::vector<SCH_ITEM*> symbols;
1192
1193 for( SCH_ITEM* symbol : m_frame->GetScreen()->Items().OfType( SCH_SYMBOL_T ) )
1194 symbols.push_back( symbol );
1195
1196 for( SCH_ITEM* symbol : symbols )
1197 {
1198 std::vector<VECTOR2I> pts = symbol->GetConnectionPoints();
1199
1200 if( pts.size() > 2 )
1201 continue;
1202
1203 for( auto pt = pts.begin(); pt != pts.end(); pt++ )
1204 {
1205 for( auto secondPt = pt + 1; secondPt != pts.end(); secondPt++ )
1206 m_frame->TrimWire( &commit, *pt, *secondPt );
1207 }
1208 }
1209
1210 for( const VECTOR2I& pt : new_ends )
1211 {
1213 m_frame->AddJunction( &commit, m_frame->GetScreen(), pt );
1214 }
1215
1217 m_busUnfold = {};
1218
1219 for( SCH_ITEM* item : m_frame->GetScreen()->Items() )
1220 item->ClearEditFlags();
1221
1222 commit.Push( _( "Draw Wires" ) );
1223}
1224
1225
1227{
1228 SCHEMATIC* sch = getModel<SCHEMATIC>();
1229 SCH_SCREEN* screen = sch->CurrentSheet().LastScreen();
1230
1231 std::set<SCH_LINE*> lines;
1232 BOX2I bb = aSelection->GetBoundingBox();
1233
1234 for( EDA_ITEM* item : screen->Items().Overlapping( SCH_LINE_T, bb ) )
1235 lines.insert( static_cast<SCH_LINE*>( item ) );
1236
1237 for( unsigned ii = 0; ii < aSelection->GetSize(); ii++ )
1238 {
1239 SCH_ITEM* item = dynamic_cast<SCH_ITEM*>( aSelection->GetItem( ii ) );
1240
1241 if( !item || !item->IsConnectable() || ( item->Type() == SCH_LINE_T ) )
1242 continue;
1243
1244 std::vector<VECTOR2I> pts = item->GetConnectionPoints();
1245
1248 for( SCH_LINE* line : lines )
1249 {
1250 std::vector<VECTOR2I> conn_pts;
1251
1252 for( const VECTOR2I& pt : pts )
1253 {
1254 if( IsPointOnSegment( line->GetStartPoint(), line->GetEndPoint(), pt ) )
1255 conn_pts.push_back( pt );
1256
1257 if( conn_pts.size() > 2 )
1258 break;
1259 }
1260
1261 if( conn_pts.size() == 2 )
1262 m_frame->TrimWire( aCommit, conn_pts[0], conn_pts[1] );
1263 }
1264 }
1265
1266 return 0;
1267}
1268
1269
1271{
1272 SCH_SCREEN* screen = m_frame->GetScreen();
1273
1274 for( const VECTOR2I& point : screen->GetNeededJunctions( aSelection->Items() ) )
1275 m_frame->AddJunction( aCommit, m_frame->GetScreen(), point );
1276
1277 return 0;
1278}
1279
1280
1282{
1286
1288}
const char * name
Definition: DXF_plotter.cpp:57
static TOOL_ACTION undo
Definition: actions.h:66
static TOOL_ACTION doDelete
Definition: actions.h:75
static TOOL_ACTION redo
Definition: actions.h:67
static TOOL_ACTION refreshPreview
Definition: actions.h:137
static TOOL_ACTION finishInteractive
Definition: actions.h:64
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:92
void SetTool(TOOL_INTERACTIVE *aTool)
Set a tool that is the creator of the menu.
void SetIcon(BITMAPS aIcon)
Assign an icon for the entry.
Definition: action_menu.cpp:78
TOOL_INTERACTIVE * m_tool
Associates tool actions with menu item IDs. Non-owning.
Definition: action_menu.h:278
ACTION_MENU * create() const override
< Return an instance of this class. It has to be overridden in inheriting classes.
bool PassHelpTextToHandler() override
void update() override
Update menu state stub.
COMMIT & Added(EDA_ITEM *aItem, BASE_SCREEN *aScreen=nullptr)
Remove a new item from the model.
Definition: commit.h:86
void 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.
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:433
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 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, bool aEnforceMinTextSize=true)
Definition: eda_text.cpp:374
static TOOL_ACTION clearHighlight
Definition: ee_actions.h:288
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:142
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:122
static TOOL_ACTION drawBus
Definition: ee_actions.h:82
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:141
static TOOL_ACTION drawLines
Definition: ee_actions.h:103
static TOOL_ACTION rotateCW
Definition: ee_actions.h:121
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:105
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:106
static TOOL_ACTION placeJunction
Definition: ee_actions.h:85
EE_TYPE Overlapping(const BOX2I &aRect) const
Definition: sch_rtree.h:243
EE_TYPE OfType(KICAD_T aType) const
Definition: sch_rtree.h:238
EE_SELECTION & RequestSelection(const std::vector< KICAD_T > &aScanTypes={ SCH_LOCATE_ANY_T }, bool aPromoteCellSelections=false)
Return either an existing selection (filtered), or the selection at the current cursor position if th...
EE_SELECTION & GetSelection()
BOX2I GetBoundingBox() const override
A foundation class for a tool operating on a schematic or symbol.
Definition: ee_tool_base.h:48
EE_SELECTION_TOOL * m_selectionTool
Definition: ee_tool_base.h:200
bool Init() override
Init() is called once upon a registration of the tool.
Definition: ee_tool_base.h:64
bool GetGridSnapping() const
An interface for classes handling user events controlling the view behavior such as zooming,...
virtual void CaptureCursor(bool aEnabled)
Force the cursor to stay within the drawing panel area.
virtual void ForceCursorPosition(bool aEnabled, const VECTOR2D &aPosition=VECTOR2D(0, 0))
Place the cursor immediately at a given point.
virtual void ShowCursor(bool aEnabled)
Enable or disables display of cursor.
virtual void WarpMouseCursor(const VECTOR2D &aPosition, bool aWorldCoordinates=false, bool aWarpView=false)=0
If enabled (.
virtual void SetCrossHairCursorPosition(const VECTOR2D &aPosition, bool aWarpView=true)=0
Move the graphic crosshair cursor to the requested position expressed in world coordinates.
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:1694
GAL * GetGAL() const
Return the #GAL this view is using to draw graphical primitives.
Definition: view.h:197
void ClearPreview()
Definition: view.cpp:1658
void AddToPreview(VIEW_ITEM *aItem, bool aTakeOwnership=true)
Definition: view.cpp:1680
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 > &aItemListByType, std::vector< DANGLING_END_ITEM > &aItemListByPos, const SCH_SHEET_PATH *aPath=nullptr) override
Test the schematic item to aItemList to check if it's dangling state has changed.
virtual void Push(const wxString &aMessage=wxT("A commit"), int aCommitFlags=0) override
Revert the commit by restoring the modified items state.
Definition: sch_commit.cpp:393
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:165
virtual bool IsConnectable() const
Definition: sch_item.h:389
SCH_LAYER_ID GetLayer() const
Return the layer this item is on.
Definition: sch_item.h:272
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:404
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:317
void SetPosition(const VECTOR2I &aPosition) override
Definition: sch_label.cpp:411
void Rotate90(bool aClockwise) override
Definition: sch_label.cpp:442
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:399
void computeBreakPoint(const std::pair< SCH_LINE *, SCH_LINE * > &aSegments, VECTOR2I &aPosition, LINE_MODE mode, bool posture)
Compute the middle coordinate for 2 segments from the start point to aPosition with the segments kept...
int DrawSegments(const TOOL_EVENT &aEvent)
void setTransitions() override
This method is meant to be overridden in order to specify handlers for events.
int AddJunctionsIfNeeded(SCH_COMMIT *aCommit, EE_SELECTION *aSelection)
Handle the addition of junctions to a selection of objects.
int UnfoldBus(const TOOL_EVENT &aEvent)
int doDrawSegments(const TOOL_EVENT &aTool, int aType, bool aQuitOnDraw)
bool Init() override
Init() is called once upon a registration of the tool.
const SCH_SHEET_PIN * getSheetPin(const VECTOR2I &aPosition)
Search for a sheet pin at a location.
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...
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:471
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_HELPER_GRIDS
Definition: grid_helper.h:37
@ GRID_GRAPHICS
Definition: grid_helper.h:45
@ GRID_WIRES
Definition: grid_helper.h:42
@ LAYER_WIRE
Definition: layer_ids.h:355
@ LAYER_NOTES
Definition: layer_ids.h:369
@ LAYER_BUS
Definition: layer_ids.h:356
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:424
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:148
@ SCH_SYMBOL_T
Definition: typeinfo.h:160
@ SCH_SHEET_T
Definition: typeinfo.h:162
@ SCH_ITEM_LOCATE_BUS_T
Definition: typeinfo.h:175
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