KiCad PCB EDA Suite
Loading...
Searching...
No Matches
sch_line_wire_bus_tool.cpp
Go to the documentation of this file.
1/*
2 * This program source code file is part of KiCad, a free EDA CAD application.
3 *
4 * Copyright (C) 2019 CERN
5 * Copyright (C) 2019-2023 KiCad Developers, see AUTHORS.txt for contributors.
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, you may find one here:
19 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
20 * or you may search the http://www.gnu.org website for the version 2 license,
21 * or you may write to the Free Software Foundation, Inc.,
22 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
23 */
24
26
27#include <wx/debug.h>
28#include <wx/gdicmn.h>
29#include <wx/string.h>
30#include <wx/translation.h>
31#include <algorithm>
32#include <cstdlib>
33#include <iterator>
34#include <memory>
35#include <utility>
36#include <vector>
37
38#include <layer_ids.h>
39#include <math/vector2d.h>
40#include <advanced_config.h>
42#include <view/view_controls.h>
43#include <tool/actions.h>
45#include <tool/selection.h>
47#include <tool/tool_event.h>
48#include <trigo.h>
49#include <eeschema_id.h>
50#include <sch_bus_entry.h>
51#include <sch_connection.h>
52#include <sch_edit_frame.h>
53#include <sch_line.h>
54#include <sch_screen.h>
55#include <sch_sheet.h>
56#include <sch_sheet_pin.h>
57#include <schematic.h>
58#include <sch_commit.h>
59#include <ee_actions.h>
60#include <ee_grid_helper.h>
61#include <ee_selection.h>
62#include <ee_selection_tool.h>
63
65{
66public:
68 ACTION_MENU( true ),
69 m_showTitle( false )
70 {
71 SetIcon( BITMAPS::add_line2bus );
72 SetTitle( _( "Unfold from Bus" ) );
73 }
74
76 {
77 m_showTitle = true;
78 }
79
80 bool PassHelpTextToHandler() override { return true; }
81
82protected:
83 ACTION_MENU* create() const override
84 {
85 return new BUS_UNFOLD_MENU();
86 }
87
88private:
89 void update() override
90 {
92 EE_SELECTION& selection = selTool->RequestSelection( { SCH_ITEM_LOCATE_BUS_T } );
93 SCH_LINE* bus = (SCH_LINE*) selection.Front();
94
95 Clear();
96
97 // Pick up the pointer again because it may have been changed by SchematicCleanUp
98 selection = selTool->RequestSelection( { SCH_ITEM_LOCATE_BUS_T } );
99 bus = (SCH_LINE*) selection.Front();
100
101 if( !bus )
102 {
103 Append( ID_POPUP_SCH_UNFOLD_BUS, _( "No bus selected" ), wxEmptyString );
104 Enable( ID_POPUP_SCH_UNFOLD_BUS, false );
105 return;
106 }
107
108 SCH_CONNECTION* connection = bus->Connection();
109
110 if( !connection || !connection->IsBus() || connection->Members().empty() )
111 {
112 Append( ID_POPUP_SCH_UNFOLD_BUS, _( "Bus has no members" ), wxEmptyString );
113 Enable( ID_POPUP_SCH_UNFOLD_BUS, false );
114 return;
115 }
116
117 int idx = 0;
118
119 if( m_showTitle )
120 {
121 Append( ID_POPUP_SCH_UNFOLD_BUS, _( "Unfold from Bus" ), wxEmptyString );
122 Enable( ID_POPUP_SCH_UNFOLD_BUS, false );
123 }
124
125 for( const std::shared_ptr<SCH_CONNECTION>& member : connection->Members() )
126 {
127 int id = ID_POPUP_SCH_UNFOLD_BUS + ( idx++ );
128 wxString name = member->FullLocalName();
129
130 if( member->Type() == CONNECTION_TYPE::BUS )
131 {
132 ACTION_MENU* submenu = new ACTION_MENU( true, m_tool );
133 AppendSubMenu( submenu, SCH_CONNECTION::PrintBusForUI( name ), name );
134
135 for( const std::shared_ptr<SCH_CONNECTION>& sub_member : member->Members() )
136 {
137 id = ID_POPUP_SCH_UNFOLD_BUS + ( idx++ );
138 name = sub_member->FullLocalName();
139 submenu->Append( id, SCH_CONNECTION::PrintBusForUI( name ), name );
140 }
141 }
142 else
143 {
144 Append( id, name, wxEmptyString );
145 }
146 }
147 }
148
150};
151
152
157{
159};
160
161
164};
165
166
168 EE_TOOL_BASE<SCH_EDIT_FRAME>( "eeschema.InteractiveDrawingLineWireBus" ),
169 m_inDrawingTool( false )
170{
171 m_busUnfold = {};
172 m_wires.reserve( 16 );
173}
174
175
177{
178}
179
180
182{
184
185 std::shared_ptr<BUS_UNFOLD_MENU> busUnfoldMenu = std::make_shared<BUS_UNFOLD_MENU>();
186 busUnfoldMenu->SetTool( this );
187 m_menu.RegisterSubMenu( busUnfoldMenu );
188
189 std::shared_ptr<BUS_UNFOLD_MENU> selBusUnfoldMenu = std::make_shared<BUS_UNFOLD_MENU>();
190 selBusUnfoldMenu->SetTool( m_selectionTool );
191 m_selectionTool->GetToolMenu().RegisterSubMenu( selBusUnfoldMenu );
192
193 auto wireOrBusTool =
194 [this]( const SELECTION& aSel )
195 {
198 };
199
200 auto lineTool =
201 [this]( const SELECTION& aSel )
202 {
204 };
205
206 auto belowRootSheetCondition =
207 [&]( const SELECTION& aSel )
208 {
209 return m_frame->GetCurrentSheet().Last() != &m_frame->Schematic().Root();
210 };
211
212 auto busSelection = EE_CONDITIONS::MoreThan( 0 )
214
215 auto haveHighlight =
216 [&]( const SELECTION& sel )
217 {
218 SCH_EDIT_FRAME* editFrame = dynamic_cast<SCH_EDIT_FRAME*>( m_frame );
219
220 return editFrame && !editFrame->GetHighlightedConnection().IsEmpty();
221 };
222
223 auto& ctxMenu = m_menu.GetMenu();
224
225 // Build the tool menu
226 //
227 ctxMenu.AddItem( EE_ACTIONS::clearHighlight, haveHighlight && EE_CONDITIONS::Idle, 1 );
228 ctxMenu.AddSeparator( haveHighlight && EE_CONDITIONS::Idle, 1 );
229
230 ctxMenu.AddSeparator( 10 );
231 ctxMenu.AddItem( EE_ACTIONS::drawWire, wireOrBusTool && EE_CONDITIONS::Idle, 10 );
232 ctxMenu.AddItem( EE_ACTIONS::drawBus, wireOrBusTool && EE_CONDITIONS::Idle, 10 );
233 ctxMenu.AddItem( EE_ACTIONS::drawLines, lineTool && EE_CONDITIONS::Idle, 10 );
234
238
239 ctxMenu.AddMenu( busUnfoldMenu.get(), EE_CONDITIONS::Idle, 10 );
240
241 ctxMenu.AddSeparator( 100 );
242 ctxMenu.AddItem( EE_ACTIONS::placeJunction, wireOrBusTool && EE_CONDITIONS::Idle, 100 );
243 ctxMenu.AddItem( EE_ACTIONS::placeLabel, wireOrBusTool && EE_CONDITIONS::Idle, 100 );
244 ctxMenu.AddItem( EE_ACTIONS::placeClassLabel, wireOrBusTool && EE_CONDITIONS::Idle, 100 );
245 ctxMenu.AddItem( EE_ACTIONS::placeGlobalLabel, wireOrBusTool && EE_CONDITIONS::Idle, 100 );
246 ctxMenu.AddItem( EE_ACTIONS::placeHierLabel, wireOrBusTool && EE_CONDITIONS::Idle, 100 );
247 ctxMenu.AddItem( EE_ACTIONS::breakWire, wireOrBusTool && EE_CONDITIONS::Idle, 100 );
248 ctxMenu.AddItem( EE_ACTIONS::slice, ( wireOrBusTool || lineTool )
249 && EE_CONDITIONS::Idle, 100 );
250 ctxMenu.AddItem( EE_ACTIONS::leaveSheet, belowRootSheetCondition, 150 );
251
252 ctxMenu.AddSeparator( 200 );
253 ctxMenu.AddItem( EE_ACTIONS::selectNode, wireOrBusTool && EE_CONDITIONS::Idle, 200 );
254 ctxMenu.AddItem( EE_ACTIONS::selectConnection, wireOrBusTool && EE_CONDITIONS::Idle, 200 );
255
256 // Add bus unfolding to the selection tool
257 //
259
260 selToolMenu.AddMenu( selBusUnfoldMenu.get(), busSelection && EE_CONDITIONS::Idle, 100 );
261
262 return true;
263}
264
265
267{
268 // NOTE: for immediate hotkeys, it is NOT required that the line, wire or bus tool
269 // be selected
270 SCH_ITEM* item = (SCH_ITEM*) aSelection.Front();
271 return item && item->IsNew() && item->Type() == SCH_LINE_T;
272}
273
274
276{
277 if( m_inDrawingTool )
278 return 0;
279
281
282 const DRAW_SEGMENT_EVENT_PARAMS* params = aEvent.Parameter<const DRAW_SEGMENT_EVENT_PARAMS*>();
283
284 m_frame->PushTool( aEvent );
286
287 if( aEvent.HasPosition() )
288 {
290 GRID_HELPER_GRIDS gridType = ( params->layer == LAYER_NOTES ) ? GRID_GRAPHICS : GRID_WIRES;
291
292 grid.SetSnap( !aEvent.Modifier( MD_SHIFT ) );
293 grid.SetUseGrid( getView()->GetGAL()->GetGridSnapping() && !aEvent.DisableGridSnapping() );
294
295 VECTOR2D cursorPos = grid.BestSnapAnchor( aEvent.Position(), gridType, nullptr );
296 startSegments( params->layer, cursorPos, params->sourceSegment );
297 }
298
299 return doDrawSegments( aEvent, params->layer, params->quitOnDraw );
300}
301
302
304{
305 if( m_inDrawingTool )
306 return 0;
307
309
310 wxString* netPtr = aEvent.Parameter<wxString*>();
311 wxString net;
312 SCH_LINE* segment = nullptr;
313
314 m_frame->PushTool( aEvent );
315 Activate();
316
317 if( netPtr )
318 {
319 net = *netPtr;
320 delete netPtr;
321 }
322 else
323 {
324 BUS_UNFOLD_MENU unfoldMenu;
325 unfoldMenu.SetTool( this );
326 unfoldMenu.SetShowTitle();
327
328 SetContextMenu( &unfoldMenu, CMENU_NOW );
329
330 while( TOOL_EVENT* evt = Wait() )
331 {
332 if( evt->Action() == TA_CHOICE_MENU_CHOICE )
333 {
334 std::optional<int> id = evt->GetCommandId();
335
336 if( id && ( *id > 0 ) )
337 net = *evt->Parameter<wxString*>();
338
339 break;
340 }
341 else if( evt->Action() == TA_CHOICE_MENU_CLOSED )
342 {
343 break;
344 }
345 else
346 {
347 evt->SetPassEvent();
348 }
349 }
350 }
351
352 // Break a wire for the given net out of the bus
353 if( !net.IsEmpty() )
354 segment = doUnfoldBus( net );
355
356 // If we have an unfolded wire to draw, then draw it
357 if( segment )
358 {
359 return doDrawSegments( aEvent, LAYER_WIRE, false );
360 }
361 else
362 {
363 m_frame->PopTool( aEvent );
364 return 0;
365 }
366}
367
368
369SCH_LINE* SCH_LINE_WIRE_BUS_TOOL::doUnfoldBus( const wxString& aNet, const VECTOR2I& aPos )
370{
371 SCHEMATIC_SETTINGS& cfg = getModel<SCHEMATIC>()->Settings();
372 SCH_SCREEN* screen = m_frame->GetScreen();
373
374 VECTOR2I pos = aPos;
375
376 if( aPos == VECTOR2I( 0, 0 ) )
377 pos = static_cast<VECTOR2I>( getViewControls()->GetCursorPosition() );
378
380
382 m_busUnfold.entry->SetParent( screen );
384
390
392 m_busUnfold.origin = pos;
393 m_busUnfold.net_name = aNet;
394
396
397 std::vector<DANGLING_END_ITEM> endPointsByType;
398
399 for( SCH_ITEM* item : screen->Items().Overlapping( m_busUnfold.entry->GetBoundingBox() ) )
400 item->GetEndPoints( endPointsByType );
401
402 std::vector<DANGLING_END_ITEM> endPointsByPos = endPointsByType;
403 DANGLING_END_ITEM_HELPER::sort_dangling_end_items( endPointsByType, endPointsByPos );
404 m_busUnfold.entry->UpdateDanglingState( endPointsByType, endPointsByPos );
407
409}
410
411
413{
414 SCH_SCREEN* screen = m_frame->GetScreen();
415
416 for( SCH_ITEM* item : screen->Items().Overlapping( SCH_SHEET_T, aPosition ) )
417 {
418 SCH_SHEET* sheet = static_cast<SCH_SHEET*>( item );
419
420 for( SCH_SHEET_PIN* pin : sheet->GetPins() )
421 {
422 if( pin->GetPosition() == aPosition )
423 return pin;
424 }
425 }
426
427 return nullptr;
428}
429
430
431void SCH_LINE_WIRE_BUS_TOOL::computeBreakPoint( const std::pair<SCH_LINE*, SCH_LINE*>& aSegments,
432 VECTOR2I& aPosition,
433 LINE_MODE mode,
434 bool posture )
435{
436 wxCHECK_RET( aSegments.first && aSegments.second,
437 wxT( "Cannot compute break point of NULL line segment." ) );
438
439 VECTOR2I midPoint;
440 SCH_LINE* segment = aSegments.first;
441 SCH_LINE* nextSegment = aSegments.second;
442
443 VECTOR2I delta = aPosition - segment->GetStartPoint();
444 int xDir = delta.x > 0 ? 1 : -1;
445 int yDir = delta.y > 0 ? 1 : -1;
446
447
448 bool preferHorizontal;
449 bool preferVertical;
450
451 if( ( mode == LINE_MODE_45 ) && posture )
452 {
453 preferHorizontal = ( nextSegment->GetEndPoint().x - nextSegment->GetStartPoint().x ) != 0;
454 preferVertical = ( nextSegment->GetEndPoint().y - nextSegment->GetStartPoint().y ) != 0;
455 }
456 else
457 {
458 preferHorizontal = ( segment->GetEndPoint().x - segment->GetStartPoint().x ) != 0;
459 preferVertical = ( segment->GetEndPoint().y - segment->GetStartPoint().y ) != 0;
460 }
461
462 // Check for times we need to force horizontal sheet pin connections
463 const SCH_SHEET_PIN* connectedPin = getSheetPin( segment->GetStartPoint() );
464 SHEET_SIDE force = connectedPin ? connectedPin->GetSide() : SHEET_SIDE::UNDEFINED;
465
466 if( force == SHEET_SIDE::LEFT || force == SHEET_SIDE::RIGHT )
467 {
468 if( aPosition.x == connectedPin->GetPosition().x ) // push outside sheet boundary
469 {
470 int direction = ( force == SHEET_SIDE::LEFT ) ? -1 : 1;
471 aPosition.x += KiROUND( getView()->GetGAL()->GetGridSize().x * direction );
472 }
473
474 preferHorizontal = true;
475 preferVertical = false;
476 }
477
478
479 auto breakVertical = [&]() mutable
480 {
481 switch( mode )
482 {
483 case LINE_MODE_45:
484 if( !posture )
485 {
486 midPoint.x = segment->GetStartPoint().x;
487 midPoint.y = aPosition.y - yDir * abs( delta.x );
488 }
489 else
490 {
491 midPoint.x = aPosition.x;
492 midPoint.y = segment->GetStartPoint().y + yDir * abs( delta.x );
493 }
494 break;
495 default:
496 midPoint.x = segment->GetStartPoint().x;
497 midPoint.y = aPosition.y;
498 }
499 };
500
501
502 auto breakHorizontal = [&]() mutable
503 {
504 switch( mode )
505 {
506 case LINE_MODE_45:
507 if( !posture )
508 {
509 midPoint.x = aPosition.x - xDir * abs( delta.y );
510 midPoint.y = segment->GetStartPoint().y;
511 }
512 else
513 {
514 midPoint.x = segment->GetStartPoint().x + xDir * abs( delta.y );
515 midPoint.y = aPosition.y;
516 }
517 break;
518 default:
519 midPoint.x = aPosition.x;
520 midPoint.y = segment->GetStartPoint().y;
521 }
522 };
523
524
525 // Maintain current line shape if we can, e.g. if we were originally moving
526 // vertically keep the first segment vertical
527 if( preferVertical )
528 breakVertical();
529 else if( preferHorizontal )
530 breakHorizontal();
531
532 // Check if our 45 degree angle is one of these shapes
533 // /
534 // /
535 // /
536 // /__________
537 VECTOR2I deltaMidpoint = midPoint - segment->GetStartPoint();
538
539 if( mode == LINE_MODE::LINE_MODE_45 && !posture
540 && ( ( alg::signbit( deltaMidpoint.x ) != alg::signbit( delta.x ) )
541 || ( alg::signbit( deltaMidpoint.y ) != alg::signbit( delta.y ) ) ) )
542 {
543 preferVertical = false;
544 preferHorizontal = false;
545 }
546 else if( mode == LINE_MODE::LINE_MODE_45 && posture
547 && ( ( abs( deltaMidpoint.x ) > abs( delta.x ) )
548 || ( abs( deltaMidpoint.y ) > abs( delta.y ) ) ) )
549 {
550 preferVertical = false;
551 preferHorizontal = false;
552 }
553
554 if( !preferHorizontal && !preferVertical )
555 {
556 if( std::abs( delta.x ) < std::abs( delta.y ) )
557 breakVertical();
558 else
559 breakHorizontal();
560 }
561
562 segment->SetEndPoint( midPoint );
563 nextSegment->SetStartPoint( midPoint );
564 nextSegment->SetEndPoint( aPosition );
565}
566
567
568int SCH_LINE_WIRE_BUS_TOOL::doDrawSegments( const TOOL_EVENT& aTool, int aType, bool aQuitOnDraw )
569{
570 SCH_SCREEN* screen = m_frame->GetScreen();
571 SCH_LINE* segment = nullptr;
573 GRID_HELPER_GRIDS gridType = ( aType == LAYER_NOTES ) ? GRID_GRAPHICS : GRID_WIRES;
575 int lastMode = m_frame->eeconfig()->m_Drawing.line_mode;
576 static bool posture = false;
577
578 auto setCursor =
579 [&]()
580 {
581 if( aType == LAYER_WIRE )
582 m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::LINE_WIRE );
583 else if( aType == LAYER_BUS )
584 m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::LINE_BUS );
585 else if( aType == LAYER_NOTES )
586 m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::LINE_GRAPHIC );
587 else
588 m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::LINE_WIRE );
589 };
590
591 auto cleanup =
592 [&] ()
593 {
595
596 for( SCH_LINE* wire : m_wires )
597 delete wire;
598
599 m_wires.clear();
600 segment = nullptr;
601
602 if( m_busUnfold.entry )
604
607
610
611 delete m_busUnfold.entry;
612 delete m_busUnfold.label;
613 m_busUnfold = {};
614
616 m_view->ShowPreview( false );
617 };
618
619 Activate();
620 // Must be done after Activate() so that it gets set into the correct context
621 controls->ShowCursor( true );
622 // Set initial cursor
623 setCursor();
624
625 // Add the new label to the selection so the rotate command operates on it
626 if( m_busUnfold.label )
628
629 // Continue the existing wires if we've started (usually by immediate action preference)
630 if( !m_wires.empty() )
631 segment = m_wires.back();
632
633 VECTOR2I contextMenuPos;
634
635 // Main loop: keep receiving events
636 while( TOOL_EVENT* evt = Wait() )
637 {
639 bool twoSegments = currentMode != LINE_MODE::LINE_MODE_FREE;
640
641 // The tool hotkey is interpreted as a click when drawing
642 bool isSyntheticClick = ( segment || m_busUnfold.in_progress ) && evt->IsActivate()
643 && evt->HasPosition() && evt->Matches( aTool );
644
645 setCursor();
646 grid.SetMask( GRID_HELPER::ALL );
647 grid.SetSnap( !evt->Modifier( MD_SHIFT ) );
648 grid.SetUseGrid( getView()->GetGAL()->GetGridSnapping() && !evt->DisableGridSnapping() );
649
650 if( segment )
651 {
652 if( segment->GetStartPoint().x == segment->GetEndPoint().x )
653 grid.ClearMaskFlag( GRID_HELPER::VERTICAL );
654
655 if( segment->GetStartPoint().y == segment->GetEndPoint().y )
656 grid.ClearMaskFlag( GRID_HELPER::HORIZONTAL );
657 }
658
659 VECTOR2D eventPosition = evt->HasPosition() ? evt->Position()
660 : controls->GetMousePosition();
661
662 VECTOR2I cursorPos = grid.BestSnapAnchor( eventPosition, gridType, segment );
663 controls->ForceCursorPosition( true, cursorPos );
664
665 // Need to handle change in H/V mode while drawing
666 if( currentMode != lastMode )
667 {
668 // Need to delete extra segment if we have one
669 if( segment && currentMode == LINE_MODE::LINE_MODE_FREE && m_wires.size() >= 2 )
670 {
671 m_wires.pop_back();
673 delete segment;
674
675 segment = m_wires.back();
676 segment->SetEndPoint( cursorPos );
677 }
678 // Add a segment so we can move orthogonally/45
679 else if( segment && lastMode == LINE_MODE::LINE_MODE_FREE )
680 {
681 segment->SetEndPoint( cursorPos );
682
683 // Create a new segment, and chain it after the current segment.
684 segment = static_cast<SCH_LINE*>( segment->Duplicate() );
685 segment->SetFlags( IS_NEW | IS_MOVING );
686 segment->SetStartPoint( cursorPos );
687 m_wires.push_back( segment );
688
689 m_selectionTool->AddItemToSel( segment, true /*quiet mode*/ );
690 }
691
692 lastMode = currentMode;
693 }
694
695 //------------------------------------------------------------------------
696 // Handle cancel:
697 //
698 if( evt->IsCancelInteractive() )
699 {
701
702 if( segment || m_busUnfold.in_progress )
703 {
704 cleanup();
705
706 if( aQuitOnDraw )
707 {
708 m_frame->PopTool( aTool );
709 break;
710 }
711 }
712 else
713 {
714 m_frame->PopTool( aTool );
715 break;
716 }
717 }
718 else if( evt->IsActivate() && !isSyntheticClick )
719 {
720 if( segment || m_busUnfold.in_progress )
721 {
722 m_frame->ShowInfoBarMsg( _( "Press <ESC> to cancel drawing." ) );
723 evt->SetPassEvent( false );
724 continue;
725 }
726
727 if( evt->IsMoveTool() )
728 {
729 // leave ourselves on the stack so we come back after the move
730 break;
731 }
732 else
733 {
734 m_frame->PopTool( aTool );
735 break;
736 }
737 }
738 //------------------------------------------------------------------------
739 // Handle finish:
740 //
741 else if( evt->IsAction( &ACTIONS::finishInteractive ) )
742 {
743 if( segment || m_busUnfold.in_progress )
744 {
746 segment = nullptr;
747
748 if( aQuitOnDraw )
749 {
750 m_frame->PopTool( aTool );
751 break;
752 }
753 }
754 }
755 //------------------------------------------------------------------------
756 // Handle click:
757 //
758 else if( evt->IsClick( BUT_LEFT )
759 || ( segment && evt->IsDblClick( BUT_LEFT ) )
760 || isSyntheticClick )
761 {
762 // First click when unfolding places the label and wire-to-bus entry
764 {
765 wxASSERT( aType == LAYER_WIRE );
766
770 }
771
772 if( !segment )
773 {
774 segment = startSegments( aType, VECTOR2D( cursorPos ) );
775 }
776 // Create a new segment if we're out of previously-created ones
777 else if( !segment->IsNull()
778 || ( twoSegments && !m_wires[m_wires.size() - 2]->IsNull() ) )
779 {
780 // Terminate the command if the end point is on a pin, junction, label, or another
781 // wire or bus.
782 if( screen->IsTerminalPoint( cursorPos, segment->GetLayer() ) )
783 {
785 segment = nullptr;
786
787 if( aQuitOnDraw )
788 {
789 m_frame->PopTool( aTool );
790 break;
791 }
792 }
793 else
794 {
795 int placedSegments = 1;
796
797 // When placing lines with the forty-five degree end, the user is
798 // targetting the endpoint with the angled portion, so it's more
799 // intuitive to place both segments at the same time.
800 if( currentMode == LINE_MODE::LINE_MODE_45 )
801 placedSegments++;
802
803 segment->SetEndPoint( cursorPos );
804
805 for( int i = 0; i < placedSegments; i++ )
806 {
807 // Create a new segment, and chain it after the current segment.
808 segment = static_cast<SCH_LINE*>( segment->Duplicate() );
809 segment->SetFlags( IS_NEW | IS_MOVING );
810 segment->SetStartPoint( cursorPos );
811 m_wires.push_back( segment );
812
813 m_selectionTool->AddItemToSel( segment, true /*quiet mode*/ );
814 }
815 }
816 }
817
818 if( evt->IsDblClick( BUT_LEFT ) && segment )
819 {
820 if( twoSegments && m_wires.size() >= 2 )
821 {
822 computeBreakPoint( { m_wires[m_wires.size() - 2], segment }, cursorPos,
823 currentMode, posture );
824 }
825
827 segment = nullptr;
828
829 if( aQuitOnDraw )
830 {
831 m_frame->PopTool( aTool );
832 break;
833 }
834 }
835 }
836 //------------------------------------------------------------------------
837 // Handle motion:
838 //
839 else if( evt->IsMotion() || evt->IsAction( &ACTIONS::refreshPreview ) )
840 {
842
843 // Update the bus unfold posture based on the mouse movement
845 {
846 VECTOR2I cursor_delta = cursorPos - m_busUnfold.origin;
848
849 bool flipX = ( cursor_delta.x < 0 );
850 bool flipY = ( cursor_delta.y < 0 );
851
852 // Erase and redraw if necessary
853 if( flipX != m_busUnfold.flipX || flipY != m_busUnfold.flipY )
854 {
855 VECTOR2I size = entry->GetSize();
856 int ySign = flipY ? -1 : 1;
857 int xSign = flipX ? -1 : 1;
858
859 size.x = std::abs( size.x ) * xSign;
860 size.y = std::abs( size.y ) * ySign;
861 entry->SetSize( size );
862
863 m_busUnfold.flipY = flipY;
864 m_busUnfold.flipX = flipX;
865
866 m_frame->UpdateItem( entry, false, true );
867 m_wires.front()->SetStartPoint( entry->GetEnd() );
868 }
869
870 // Update the label "ghost" position
871 m_busUnfold.label->SetPosition( cursorPos );
873
874 // Ensure segment is non-null at the start of bus unfold
875 if( !segment )
876 segment = m_wires.back();
877 }
878
879 if( segment )
880 {
881 // Coerce the line to vertical/horizontal/45 as necessary
882 if( twoSegments && m_wires.size() >= 2 )
883 {
884 computeBreakPoint( { m_wires[m_wires.size() - 2], segment }, cursorPos,
885 currentMode, posture );
886 }
887 else
888 {
889 segment->SetEndPoint( cursorPos );
890 }
891 }
892
893 for( SCH_LINE* wire : m_wires )
894 {
895 if( !wire->IsNull() )
896 m_view->AddToPreview( wire->Clone() );
897 }
898 }
899 else if( evt->IsAction( &EE_ACTIONS::undoLastSegment )
900 || evt->IsAction( &ACTIONS::doDelete )
901 || evt->IsAction( &ACTIONS::undo ) )
902 {
903 if( ( currentMode == LINE_MODE::LINE_MODE_FREE && m_wires.size() > 1 )
904 || ( LINE_MODE::LINE_MODE_90 && m_wires.size() > 2 ) )
905 {
907
908 m_wires.pop_back();
910 delete segment;
911
912 segment = m_wires.back();
913 cursorPos = segment->GetEndPoint();
914 getViewControls()->WarpMouseCursor( cursorPos, true );
915
916 // Find new bend point for current mode
917 if( twoSegments && m_wires.size() >= 2 )
918 {
919 computeBreakPoint( { m_wires[m_wires.size() - 2], segment }, cursorPos,
920 currentMode, posture );
921 }
922 else
923 {
924 segment->SetEndPoint( cursorPos );
925 }
926
927 for( SCH_LINE* wire : m_wires )
928 {
929 if( !wire->IsNull() )
930 m_view->AddToPreview( wire->Clone() );
931 }
932 }
933 else if( evt->IsAction( &ACTIONS::undo ) )
934 {
935 // Dispatch as normal undo event
936 evt->SetPassEvent();
937 }
938 else
939 {
940 wxBell();
941 }
942 }
943 else if( evt->IsAction( &EE_ACTIONS::switchSegmentPosture ) && m_wires.size() >= 2 )
944 {
945 posture = !posture;
946
947 // The 90 degree mode doesn't have a forced posture like
948 // the 45 degree mode and computeBreakPoint maintains existing 90s' postures.
949 // Instead, just swap the 90 angle here.
950 if( currentMode == LINE_MODE::LINE_MODE_90 )
951 {
953
954 SCH_LINE* line2 = m_wires[m_wires.size() - 1];
955 SCH_LINE* line1 = m_wires[m_wires.size() - 2];
956
957 VECTOR2I delta2 = line2->GetEndPoint() - line2->GetStartPoint();
958 VECTOR2I delta1 = line1->GetEndPoint() - line1->GetStartPoint();
959
960 line2->SetStartPoint(line2->GetEndPoint() - delta1);
961 line1->SetEndPoint(line1->GetStartPoint() + delta2);
962
963 for( SCH_LINE* wire : m_wires )
964 {
965 if( !wire->IsNull() )
966 m_view->AddToPreview( wire->Clone() );
967 }
968 }
969 else
970 {
971 computeBreakPoint( { m_wires[m_wires.size() - 2], segment }, cursorPos, currentMode,
972 posture );
973
975 }
976 }
977 //------------------------------------------------------------------------
978 // Handle context menu:
979 //
980 else if( evt->IsClick( BUT_RIGHT ) )
981 {
982 // Warp after context menu only if dragging...
983 if( !segment )
985
986 contextMenuPos = cursorPos;
988 }
989 else if( evt->Category() == TC_COMMAND && evt->Action() == TA_CHOICE_MENU_CHOICE )
990 {
991 if( *evt->GetCommandId() >= ID_POPUP_SCH_UNFOLD_BUS
992 && *evt->GetCommandId() <= ID_POPUP_SCH_UNFOLD_BUS_END )
993 {
994 wxASSERT_MSG( !segment, "Bus unfold event received when already drawing!" );
995
996 aType = LAYER_WIRE;
997 wxString net = *evt->Parameter<wxString*>();
998 segment = doUnfoldBus( net, contextMenuPos );
999 }
1000 }
1001 //------------------------------------------------------------------------
1002 // Handle TOOL_ACTION special cases
1003 //
1004 else if( evt->IsAction( &EE_ACTIONS::rotateCW ) || evt->IsAction( &EE_ACTIONS::rotateCCW ) )
1005 {
1007 {
1008 m_busUnfold.label->Rotate90( evt->IsAction( &EE_ACTIONS::rotateCW ) );
1010
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: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:610
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:88
virtual void ClearEditFlags()
Definition: eda_item.h:140
void SetFlags(EDA_ITEM_FLAGS aMask)
Definition: eda_item.h:126
KICAD_T Type() const
Returns the type of object.
Definition: eda_item.h:100
virtual void SetParent(EDA_ITEM *aParent)
Definition: eda_item.h:103
bool IsNew() const
Definition: eda_item.h:106
void SetTextSize(VECTOR2I aNewSize, bool aEnforceMinTextSize=true)
Definition: eda_text.cpp:372
static TOOL_ACTION clearHighlight
Definition: ee_actions.h:294
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 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:103
static TOOL_ACTION rotateCW
Definition: ee_actions.h:124
static TOOL_ACTION leaveSheet
Definition: ee_actions.h:220
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(bool aOnlyVisible=false) 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:1689
GAL * GetGAL() const
Return the #GAL this view is using to draw graphical primitives.
Definition: view.h:197
void ClearPreview()
Definition: view.cpp:1653
void AddToPreview(VIEW_ITEM *aItem, bool aTakeOwnership=true)
Definition: view.cpp:1675
These are loaded from Eeschema settings but then overwritten by the project settings.
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:406
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:174
virtual bool IsConnectable() const
Definition: sch_item.h:457
SCH_LAYER_ID GetLayer() const
Return the layer this item is on.
Definition: sch_item.h:289
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:216
virtual std::vector< VECTOR2I > GetConnectionPoints() const
Add all the connection points for this item to aPoints.
Definition: sch_item.h:472
SCH_ITEM * Duplicate(bool doClone=false) const
Routine to create a new copy of given item.
Definition: sch_item.cpp:126
void SetIsDangling(bool aIsDangling)
Definition: sch_label.h:320
SPIN_STYLE GetSpinStyle() const
Definition: sch_label.cpp:373
void SetPosition(const VECTOR2I &aPosition) override
Definition: sch_label.cpp:412
void Rotate90(bool aClockwise) override
Definition: sch_label.cpp:443
virtual void SetSpinStyle(SPIN_STYLE aSpinStyle)
Definition: sch_label.cpp:338
EDA_ITEM * Clone() const override
Create a duplicate of this item with linked list members set to NULL.
Definition: sch_label.h:406
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:136
VECTOR2I GetEndPoint() const
Definition: sch_line.h:140
VECTOR2I GetStartPoint() const
Definition: sch_line.h:135
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:461
bool IsNull() const
Definition: sch_line.h:133
void SetEndPoint(const VECTOR2I &aPosition)
Definition: sch_line.h:141
SCH_LINE * GetLine(const VECTOR2I &aPosition, int aAccuracy=0, int aLayer=LAYER_NOTES, SCH_LINE_TEST_T aSearchType=ENTIRE_LENGTH_T) const
Return a line item located at aPosition.
EE_RTREE & Items()
Gets the full RTree, usually for iterating.
Definition: sch_screen.h:108
bool IsTerminalPoint(const VECTOR2I &aPosition, int aLayer) const
Test if aPosition is a connection point on aLayer.
Definition: sch_screen.cpp:816
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:497
std::vector< VECTOR2I > GetNeededJunctions(const std::deque< EDA_ITEM * > &aItems) const
Return the unique set of points belonging to aItems where a junction is needed.
std::vector< VECTOR2I > GetConnections() const
Collect a unique list of all possible connection points in the schematic.
SCH_SCREEN * LastScreen()
SCH_SHEET * Last() const
Return a pointer to the last SCH_SHEET of the list.
Define a sheet pin (label) used in sheets to create hierarchical schematics.
Definition: sch_sheet_pin.h:66
SHEET_SIDE GetSide() const
Sheet symbol placed in a schematic, and is the entry point for a sub schematic.
Definition: sch_sheet.h:57
std::vector< SCH_SHEET_PIN * > & GetPins()
Definition: sch_sheet.h:181
VECTOR2I GetPosition() const override
Definition: sch_text.h:141
static SELECTION_CONDITION MoreThan(int aNumber)
Create a functor that tests if the number of selected items is greater than the value given as parame...
static bool Idle(const SELECTION &aSelection)
Test if there no items selected or being edited.
static bool ShowAlways(const SELECTION &aSelection)
The default condition function (always returns true).
static SELECTION_CONDITION OnlyTypes(std::vector< KICAD_T > aTypes)
Create a functor that tests if the selected items are only of given types.
int RemoveItemFromSel(const TOOL_EVENT &aEvent)
int AddItemToSel(const TOOL_EVENT &aEvent)
virtual KIGFX::VIEW_ITEM * GetItem(unsigned int aIdx) const override
Definition: selection.cpp:75
virtual unsigned int GetSize() const override
Return the number of stored items.
Definition: selection.h:100
EDA_ITEM * Front() const
Definition: selection.h:172
std::deque< EDA_ITEM * > & Items()
Definition: selection.h:177
virtual void PopTool(const TOOL_EVENT &aEvent)
Pops a tool from the stack.
virtual void PushTool(const TOOL_EVENT &aEvent)
NB: the definition of "tool" is different at the user level.
bool IsCurrentTool(const TOOL_ACTION &aAction) const
KIGFX::VIEW_CONTROLS * getViewControls() const
Return the instance of VIEW_CONTROLS object used in the application.
Definition: tool_base.cpp:42
TOOL_MANAGER * m_toolMgr
Definition: tool_base.h:217
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:150
bool PostAction(const std::string &aActionName, T aParam)
Run the specified action after the current action (coroutine) ends.
Definition: tool_manager.h:235
void VetoContextMenuMouseWarp()
Disable mouse warping after the current context menu is closed.
Definition: tool_manager.h:530
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:356
@ LAYER_NOTES
Definition: layer_ids.h:371
@ LAYER_BUS
Definition: layer_ids.h:357
bool signbit(T v)
Integral version of std::signbit that works all compilers.
Definition: kicad_algo.h:198
EDA_ANGLE abs(const EDA_ANGLE &aAngle)
Definition: eda_angle.h:424
static BUS_UNFOLD_PERSISTENT_SETTINGS busUnfoldPersistentSettings
SHEET_SIDE
Define the edge of the sheet that the sheet pin is positioned.
Definition: sch_sheet_pin.h:46
bool label_placed
True if user has placed the net label.
wxString net_name
Net label for the unfolding operation.
bool flipY
True if the bus entry should be flipped in the y-axis.
SCH_BUS_WIRE_ENTRY * entry
bool flipX
True if the bus entry should be flipped in the x-axis.
VECTOR2I origin
Origin (on the bus) of the unfold.
bool in_progress
True if bus unfold operation is running.
Settings for bus unfolding that are persistent across invocations of the tool.
constexpr int delta
@ CMENU_NOW
Definition: tool_event.h:152
@ TA_CHOICE_MENU_CHOICE
Definition: tool_event.h:97
@ TA_CHOICE_MENU_CLOSED
Definition: tool_event.h:100
@ TC_COMMAND
Definition: tool_event.h:56
@ MD_SHIFT
Definition: tool_event.h:142
@ BUT_LEFT
Definition: tool_event.h:131
@ BUT_RIGHT
Definition: tool_event.h:132
bool IsPointOnSegment(const VECTOR2I &aSegStart, const VECTOR2I &aSegEnd, const VECTOR2I &aTestPoint)
Test if aTestPoint is on line defined by aSegStart and aSegEnd.
Definition: trigo.cpp:88
@ SCH_LINE_T
Definition: typeinfo.h:163
@ SCH_SYMBOL_T
Definition: typeinfo.h:172
@ SCH_SHEET_T
Definition: typeinfo.h:174
@ SCH_ITEM_LOCATE_BUS_T
Definition: typeinfo.h:186
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:118
VECTOR2< double > VECTOR2D
Definition: vector2d.h:601
VECTOR2< int > VECTOR2I
Definition: vector2d.h:602