KiCad PCB EDA Suite
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-2022 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/stringimpl.h>
31#include <wx/translation.h>
32#include <algorithm>
33#include <cstdlib>
34#include <iterator>
35#include <memory>
36#include <utility>
37#include <vector>
38
39#include <eda_item.h>
40#include <bitmaps.h>
41#include <core/typeinfo.h>
42#include <layer_ids.h>
43#include <math/vector2d.h>
44#include <advanced_config.h>
45#include <tool/actions.h>
47#include <tool/selection.h>
49#include <tool/tool_event.h>
50#include <trigo.h>
51#include <undo_redo_container.h>
52#include <connection_graph.h>
53#include <eeschema_id.h>
54#include <sch_bus_entry.h>
55#include <sch_connection.h>
56#include <sch_edit_frame.h>
57#include <sch_item.h>
58#include <sch_line.h>
59#include <sch_screen.h>
60#include <sch_sheet.h>
61#include <sch_sheet_pin.h>
62#include <schematic.h>
63#include <ee_actions.h>
64#include <ee_grid_helper.h>
65#include <ee_selection.h>
66#include <ee_selection_tool.h>
67
69{
70public:
72 ACTION_MENU( true ),
73 m_showTitle( false )
74 {
76 SetTitle( _( "Unfold from Bus" ) );
77 }
78
80 {
81 m_showTitle = true;
82 }
83
84 bool PassHelpTextToHandler() override { return true; }
85
86protected:
87 ACTION_MENU* create() const override
88 {
89 return new BUS_UNFOLD_MENU();
90 }
91
92private:
93 void update() override
94 {
97 EE_SELECTION& selection = selTool->RequestSelection( { SCH_ITEM_LOCATE_BUS_T } );
98 SCH_LINE* bus = (SCH_LINE*) selection.Front();
99
100 Clear();
101
102 // TODO(JE) remove once real-time is enabled
103 if( !ADVANCED_CFG::GetCfg().m_RealTimeConnectivity || !CONNECTION_GRAPH::m_allowRealTime )
104 {
106
107 // Pick up the pointer again because it may have been changed by SchematicCleanUp
108 selection = selTool->RequestSelection( { SCH_ITEM_LOCATE_BUS_T } );
109 bus = (SCH_LINE*) selection.Front();
110 }
111
112 if( !bus )
113 {
114 Append( ID_POPUP_SCH_UNFOLD_BUS, _( "No bus selected" ), wxEmptyString );
115 Enable( ID_POPUP_SCH_UNFOLD_BUS, false );
116 return;
117 }
118
119 SCH_CONNECTION* connection = bus->Connection();
120
121 if( !connection || !connection->IsBus() || connection->Members().empty() )
122 {
123 Append( ID_POPUP_SCH_UNFOLD_BUS, _( "Bus has no members" ), wxEmptyString );
124 Enable( ID_POPUP_SCH_UNFOLD_BUS, false );
125 return;
126 }
127
128 int idx = 0;
129
130 if( m_showTitle )
131 {
132 Append( ID_POPUP_SCH_UNFOLD_BUS, _( "Unfold from Bus" ), wxEmptyString );
133 Enable( ID_POPUP_SCH_UNFOLD_BUS, false );
134 }
135
136 for( const std::shared_ptr<SCH_CONNECTION>& member : connection->Members() )
137 {
138 int id = ID_POPUP_SCH_UNFOLD_BUS + ( idx++ );
139 wxString name = member->FullLocalName();
140
141 if( member->Type() == CONNECTION_TYPE::BUS )
142 {
143 ACTION_MENU* submenu = new ACTION_MENU( true, m_tool );
144 AppendSubMenu( submenu, SCH_CONNECTION::PrintBusForUI( name ), name );
145
146 for( const std::shared_ptr<SCH_CONNECTION>& sub_member : member->Members() )
147 {
148 id = ID_POPUP_SCH_UNFOLD_BUS + ( idx++ );
149 name = sub_member->FullLocalName();
150 submenu->Append( id, SCH_CONNECTION::PrintBusForUI( name ), name );
151 }
152 }
153 else
154 {
155 Append( id, name, wxEmptyString );
156 }
157 }
158 }
159
161};
162
163
165 EE_TOOL_BASE<SCH_EDIT_FRAME>( "eeschema.InteractiveDrawingLineWireBus" ),
166 m_inDrawingTool( false )
167{
168 m_busUnfold = {};
169 m_wires.reserve( 16 );
170}
171
172
174{
175}
176
177
179{
181
182 std::shared_ptr<BUS_UNFOLD_MENU> busUnfoldMenu = std::make_shared<BUS_UNFOLD_MENU>();
183 busUnfoldMenu->SetTool( this );
184 m_menu.RegisterSubMenu( busUnfoldMenu );
185
186 std::shared_ptr<BUS_UNFOLD_MENU> selBusUnfoldMenu = std::make_shared<BUS_UNFOLD_MENU>();
187 selBusUnfoldMenu->SetTool( m_selectionTool );
188 m_selectionTool->GetToolMenu().RegisterSubMenu( selBusUnfoldMenu );
189
190 auto wireOrBusTool =
191 [this]( const SELECTION& aSel )
192 {
195 };
196
197 auto lineTool =
198 [this]( const SELECTION& aSel )
199 {
201 };
202
203 auto belowRootSheetCondition =
204 [&]( const SELECTION& aSel )
205 {
206 return m_frame->GetCurrentSheet().Last() != &m_frame->Schematic().Root();
207 };
208
209 auto busSelection = EE_CONDITIONS::MoreThan( 0 )
211
212 auto haveHighlight =
213 [&]( const SELECTION& sel )
214 {
215 SCH_EDIT_FRAME* editFrame = dynamic_cast<SCH_EDIT_FRAME*>( m_frame );
216
217 return editFrame && editFrame->GetHighlightedConnection() != nullptr;
218 };
219
220 auto& ctxMenu = m_menu.GetMenu();
221
222 // Build the tool menu
223 //
224 ctxMenu.AddItem( EE_ACTIONS::clearHighlight, haveHighlight && EE_CONDITIONS::Idle, 1 );
225 ctxMenu.AddSeparator( haveHighlight && EE_CONDITIONS::Idle, 1 );
226
227 ctxMenu.AddItem( EE_ACTIONS::leaveSheet, belowRootSheetCondition, 2 );
228
229 ctxMenu.AddSeparator( 10 );
230 ctxMenu.AddItem( EE_ACTIONS::drawWire, wireOrBusTool && EE_CONDITIONS::Idle, 10 );
231 ctxMenu.AddItem( EE_ACTIONS::drawBus, wireOrBusTool && EE_CONDITIONS::Idle, 10 );
232 ctxMenu.AddItem( EE_ACTIONS::drawLines, lineTool && EE_CONDITIONS::Idle, 10 );
233
236
237 ctxMenu.AddItem( EE_ACTIONS::finishWire, IsDrawingWire, 10 );
238 ctxMenu.AddItem( EE_ACTIONS::finishBus, IsDrawingBus, 10 );
239 ctxMenu.AddItem( EE_ACTIONS::finishLine, IsDrawingLine, 10 );
240
241 ctxMenu.AddMenu( busUnfoldMenu.get(), EE_CONDITIONS::Idle, 10 );
242
243 ctxMenu.AddSeparator( 100 );
244 ctxMenu.AddItem( EE_ACTIONS::placeJunction, wireOrBusTool && EE_CONDITIONS::Idle, 100 );
245 ctxMenu.AddItem( EE_ACTIONS::placeLabel, wireOrBusTool && EE_CONDITIONS::Idle, 100 );
246 ctxMenu.AddItem( EE_ACTIONS::placeClassLabel, wireOrBusTool && EE_CONDITIONS::Idle, 100 );
247 ctxMenu.AddItem( EE_ACTIONS::placeGlobalLabel, wireOrBusTool && EE_CONDITIONS::Idle, 100 );
248 ctxMenu.AddItem( EE_ACTIONS::placeHierLabel, wireOrBusTool && EE_CONDITIONS::Idle, 100 );
249 ctxMenu.AddItem( EE_ACTIONS::breakWire, wireOrBusTool && EE_CONDITIONS::Idle, 100 );
250 ctxMenu.AddItem( EE_ACTIONS::breakBus, wireOrBusTool && EE_CONDITIONS::Idle, 100 );
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 return IsDrawingLineWireOrBus( aSelection )
269 && aSelection.Front()->IsType( { SCH_ITEM_LOCATE_GRAPHIC_LINE_T } );
270}
271
272
274{
275 return IsDrawingLineWireOrBus( aSelection )
276 && aSelection.Front()->IsType( { SCH_ITEM_LOCATE_WIRE_T } );
277}
278
279
281{
282 return IsDrawingLineWireOrBus( aSelection )
283 && aSelection.Front()->IsType( { SCH_ITEM_LOCATE_BUS_T } );
284}
285
286
288{
289 // NOTE: for immediate hotkeys, it is NOT required that the line, wire or bus tool
290 // be selected
291 SCH_ITEM* item = (SCH_ITEM*) aSelection.Front();
292 return item && item->IsNew() && item->Type() == SCH_LINE_T;
293}
294
295
297{
298 if( m_inDrawingTool )
299 return 0;
300
302
304
305 m_frame->PushTool( aEvent );
307
308 if( aEvent.HasPosition() )
309 {
311 grid.SetSnap( !aEvent.Modifier( MD_SHIFT ) );
312 grid.SetUseGrid( getView()->GetGAL()->GetGridSnapping() && !aEvent.DisableGridSnapping() );
313
314 VECTOR2D cursorPos = grid.BestSnapAnchor( aEvent.Position(), LAYER_CONNECTABLE, nullptr );
315 startSegments( params->layer, cursorPos, params->sourceSegment );
316 }
317
318 return doDrawSegments( aEvent, params->layer, params->quitOnDraw );
319}
320
321
323{
324 if( m_inDrawingTool )
325 return 0;
326
328
329 wxString* netPtr = aEvent.Parameter<wxString*>();
330 wxString net;
331 SCH_LINE* segment = nullptr;
332
333 m_frame->PushTool( aEvent );
334 Activate();
335
336 if( netPtr )
337 {
338 net = *netPtr;
339 delete netPtr;
340 }
341 else
342 {
343 BUS_UNFOLD_MENU unfoldMenu;
344 unfoldMenu.SetTool( this );
345 unfoldMenu.SetShowTitle();
346
347 SetContextMenu( &unfoldMenu, CMENU_NOW );
348
349 while( TOOL_EVENT* evt = Wait() )
350 {
351 if( evt->Action() == TA_CHOICE_MENU_CHOICE )
352 {
353 std::optional<int> id = evt->GetCommandId();
354
355 if( id && ( *id > 0 ) )
356 net = *evt->Parameter<wxString*>();
357
358 break;
359 }
360 else if( evt->Action() == TA_CHOICE_MENU_CLOSED )
361 {
362 break;
363 }
364 else
365 {
366 evt->SetPassEvent();
367 }
368 }
369 }
370
371 // Break a wire for the given net out of the bus
372 if( !net.IsEmpty() )
373 segment = doUnfoldBus( net );
374
375 // If we have an unfolded wire to draw, then draw it
376 if( segment )
377 {
378 return doDrawSegments( aEvent, LAYER_WIRE, false );
379 }
380 else
381 {
382 m_frame->PopTool( aEvent );
383 return 0;
384 }
385}
386
387
388SCH_LINE* SCH_LINE_WIRE_BUS_TOOL::doUnfoldBus( const wxString& aNet, const VECTOR2I& aPos )
389{
390 SCHEMATIC_SETTINGS& cfg = getModel<SCHEMATIC>()->Settings();
391
392 VECTOR2I pos = aPos;
393
394 if( aPos == VECTOR2I( 0, 0 ) )
395 pos = static_cast<VECTOR2I>( getViewControls()->GetCursorPosition() );
396
398
402
408
410 m_busUnfold.origin = pos;
411 m_busUnfold.net_name = aNet;
412
414
416}
417
418
420{
421 SCH_SCREEN* screen = m_frame->GetScreen();
422
423 for( SCH_ITEM* item : screen->Items().Overlapping( SCH_SHEET_T, aPosition ) )
424 {
425 SCH_SHEET* sheet = static_cast<SCH_SHEET*>( item );
426
427 for( SCH_SHEET_PIN* pin : sheet->GetPins() )
428 {
429 if( pin->GetPosition() == aPosition )
430 return pin;
431 }
432 }
433
434 return nullptr;
435}
436
437
438void SCH_LINE_WIRE_BUS_TOOL::computeBreakPoint( const std::pair<SCH_LINE*, SCH_LINE*>& aSegments,
439 VECTOR2I& aPosition,
440 LINE_MODE mode,
441 bool posture )
442{
443 wxCHECK_RET( aSegments.first && aSegments.second,
444 wxT( "Cannot compute break point of NULL line segment." ) );
445
446 VECTOR2I midPoint;
447 SCH_LINE* segment = aSegments.first;
448 SCH_LINE* nextSegment = aSegments.second;
449
450 VECTOR2I delta = aPosition - segment->GetStartPoint();
451 int xDir = delta.x > 0 ? 1 : -1;
452 int yDir = delta.y > 0 ? 1 : -1;
453
454
455 bool preferHorizontal;
456 bool preferVertical;
457
458 if( ( mode == LINE_MODE_45 ) && posture )
459 {
460 preferHorizontal = ( nextSegment->GetEndPoint().x - nextSegment->GetStartPoint().x ) != 0;
461 preferVertical = ( nextSegment->GetEndPoint().y - nextSegment->GetStartPoint().y ) != 0;
462 }
463 else
464 {
465 preferHorizontal = ( segment->GetEndPoint().x - segment->GetStartPoint().x ) != 0;
466 preferVertical = ( segment->GetEndPoint().y - segment->GetStartPoint().y ) != 0;
467 }
468
469 // Check for times we need to force horizontal sheet pin connections
470 const SCH_SHEET_PIN* connectedPin = getSheetPin( segment->GetStartPoint() );
471 SHEET_SIDE force = connectedPin ? connectedPin->GetSide() : SHEET_SIDE::UNDEFINED;
472
473 if( force == SHEET_SIDE::LEFT || force == SHEET_SIDE::RIGHT )
474 {
475 if( aPosition.x == connectedPin->GetPosition().x ) // push outside sheet boundary
476 {
477 int direction = ( force == SHEET_SIDE::LEFT ) ? -1 : 1;
478 aPosition.x += KiROUND( getView()->GetGAL()->GetGridSize().x * direction );
479 }
480
481 preferHorizontal = true;
482 preferVertical = false;
483 }
484
485
486 auto breakVertical = [&]() mutable
487 {
488 switch( mode )
489 {
490 case LINE_MODE_45:
491 if( !posture )
492 {
493 midPoint.x = segment->GetStartPoint().x;
494 midPoint.y = aPosition.y - yDir * abs( delta.x );
495 }
496 else
497 {
498 midPoint.x = aPosition.x;
499 midPoint.y = segment->GetStartPoint().y + yDir * abs( delta.x );
500 }
501 break;
502 default:
503 midPoint.x = segment->GetStartPoint().x;
504 midPoint.y = aPosition.y;
505 }
506 };
507
508
509 auto breakHorizontal = [&]() mutable
510 {
511 switch( mode )
512 {
513 case LINE_MODE_45:
514 if( !posture )
515 {
516 midPoint.x = aPosition.x - xDir * abs( delta.y );
517 midPoint.y = segment->GetStartPoint().y;
518 }
519 else
520 {
521 midPoint.x = segment->GetStartPoint().x + xDir * abs( delta.y );
522 midPoint.y = aPosition.y;
523 }
524 break;
525 default:
526 midPoint.x = aPosition.x;
527 midPoint.y = segment->GetStartPoint().y;
528 }
529 };
530
531
532 // Maintain current line shape if we can, e.g. if we were originally moving
533 // vertically keep the first segment vertical
534 if( preferVertical )
535 breakVertical();
536 else if( preferHorizontal )
537 breakHorizontal();
538
539 // Check if our 45 degree angle is one of these shapes
540 // /
541 // /
542 // /
543 // /__________
544 VECTOR2I deltaMidpoint = midPoint - segment->GetStartPoint();
545
546 if( mode == LINE_MODE::LINE_MODE_45 && !posture
547 && ( ( alg::signbit( deltaMidpoint.x ) != alg::signbit( delta.x ) )
548 || ( alg::signbit( deltaMidpoint.y ) != alg::signbit( delta.y ) ) ) )
549 {
550 preferVertical = false;
551 preferHorizontal = false;
552 }
553 else if( mode == LINE_MODE::LINE_MODE_45 && posture
554 && ( ( abs( deltaMidpoint.x ) > abs( delta.x ) )
555 || ( abs( deltaMidpoint.y ) > abs( delta.y ) ) ) )
556 {
557 preferVertical = false;
558 preferHorizontal = false;
559 }
560
561 if( !preferHorizontal && !preferVertical )
562 {
563 if( std::abs( delta.x ) < std::abs( delta.y ) )
564 breakVertical();
565 else
566 breakHorizontal();
567 }
568
569 segment->SetEndPoint( midPoint );
570 nextSegment->SetStartPoint( midPoint );
571 nextSegment->SetEndPoint( aPosition );
572}
573
574
575int SCH_LINE_WIRE_BUS_TOOL::doDrawSegments( const TOOL_EVENT& aTool, int aType, bool aQuitOnDraw )
576{
577 SCH_SCREEN* screen = m_frame->GetScreen();
578 SCH_LINE* segment = nullptr;
581 int lastMode = m_frame->eeconfig()->m_Drawing.line_mode;
582 static bool posture = false;
583
584 auto setCursor =
585 [&]()
586 {
587 if( aType == LAYER_WIRE )
589 else if( aType == LAYER_BUS )
591 else if( aType == LAYER_NOTES )
593 else
595 };
596
597 auto cleanup =
598 [&] ()
599 {
601
602 for( SCH_LINE* wire : m_wires )
603 delete wire;
604
605 m_wires.clear();
606 segment = nullptr;
607
608 if( m_busUnfold.entry )
610
613
616
617 delete m_busUnfold.entry;
618 delete m_busUnfold.label;
619 m_busUnfold = {};
620
622 m_view->ShowPreview( false );
623 };
624
625 Activate();
626 // Must be done after Activate() so that it gets set into the correct context
627 controls->ShowCursor( true );
628 // Set initial cursor
629 setCursor();
630
631 // Add the new label to the selection so the rotate command operates on it
632 if( m_busUnfold.label )
634
635 // Continue the existing wires if we've started (usually by immediate action preference)
636 if( !m_wires.empty() )
637 segment = m_wires.back();
638
639 wxPoint contextMenuPos;
640
641 // Main loop: keep receiving events
642 while( TOOL_EVENT* evt = Wait() )
643 {
645 bool twoSegments = currentMode != LINE_MODE::LINE_MODE_FREE;
646
647 // The tool hotkey is interpreted as a click when drawing
648 bool isSyntheticClick = ( segment || m_busUnfold.in_progress ) && evt->IsActivate()
649 && evt->HasPosition() && evt->Matches( aTool );
650
651 setCursor();
652 grid.SetMask( GRID_HELPER::ALL );
653 grid.SetSnap( !evt->Modifier( MD_SHIFT ) );
654 grid.SetUseGrid( getView()->GetGAL()->GetGridSnapping() && !evt->DisableGridSnapping() );
655
656 if( segment )
657 {
658 if( segment->GetStartPoint().x == segment->GetEndPoint().x )
659 grid.ClearMaskFlag( GRID_HELPER::VERTICAL );
660
661 if( segment->GetStartPoint().y == segment->GetEndPoint().y )
662 grid.ClearMaskFlag( GRID_HELPER::HORIZONTAL );
663 }
664
665 VECTOR2D eventPosition = evt->HasPosition() ? evt->Position()
666 : controls->GetMousePosition();
667
668 VECTOR2I cursorPos = grid.BestSnapAnchor( eventPosition, LAYER_CONNECTABLE, segment );
669 controls->ForceCursorPosition( true, cursorPos );
670
671 // Need to handle change in H/V mode while drawing
672 if( currentMode != lastMode )
673 {
674 // Need to delete extra segment if we have one
675 if( segment && currentMode == LINE_MODE::LINE_MODE_FREE && m_wires.size() >= 2 )
676 {
677 m_wires.pop_back();
679 delete segment;
680
681 segment = m_wires.back();
682 segment->SetEndPoint( cursorPos );
683 }
684 // Add a segment so we can move orthogonally/45
685 else if( segment && lastMode == LINE_MODE::LINE_MODE_FREE )
686 {
687 segment->SetEndPoint( cursorPos );
688
689 // Create a new segment, and chain it after the current segment.
690 segment = static_cast<SCH_LINE*>( segment->Duplicate() );
691 segment->SetFlags( IS_NEW | IS_MOVING );
692 segment->SetStartPoint( cursorPos );
693 m_wires.push_back( segment );
694
695 m_selectionTool->AddItemToSel( segment, true /*quiet mode*/ );
696 }
697
698 lastMode = currentMode;
699 }
700
701 //------------------------------------------------------------------------
702 // Handle cancel:
703 //
704 if( evt->IsCancelInteractive() )
705 {
707
708 if( segment || m_busUnfold.in_progress )
709 {
710 cleanup();
711
712 if( aQuitOnDraw )
713 {
714 m_frame->PopTool( aTool );
715 break;
716 }
717 }
718 else
719 {
720 m_frame->PopTool( aTool );
721 break;
722 }
723 }
724 else if( evt->IsActivate() && !isSyntheticClick )
725 {
726 if( segment || m_busUnfold.in_progress )
727 {
728 m_frame->ShowInfoBarMsg( _( "Press <ESC> to cancel drawing." ) );
729 evt->SetPassEvent( false );
730 continue;
731 }
732
733 if( evt->IsMoveTool() )
734 {
735 // leave ourselves on the stack so we come back after the move
736 break;
737 }
738 else
739 {
740 m_frame->PopTool( aTool );
741 break;
742 }
743 }
744 //------------------------------------------------------------------------
745 // Handle finish:
746 //
747 else if( evt->IsAction( &EE_ACTIONS::finishLineWireOrBus )
748 || evt->IsAction( &EE_ACTIONS::finishWire )
749 || evt->IsAction( &EE_ACTIONS::finishBus )
750 || evt->IsAction( &EE_ACTIONS::finishLine ) )
751 {
752 if( segment || m_busUnfold.in_progress )
753 {
755 segment = nullptr;
756
757 if( aQuitOnDraw )
758 {
759 m_frame->PopTool( aTool );
760 break;
761 }
762 }
763 }
764 //------------------------------------------------------------------------
765 // Handle click:
766 //
767 else if( evt->IsClick( BUT_LEFT )
768 || ( segment && evt->IsDblClick( BUT_LEFT ) )
769 || isSyntheticClick )
770 {
771 // First click when unfolding places the label and wire-to-bus entry
773 {
774 wxASSERT( aType == LAYER_WIRE );
775
779 }
780
781 if( !segment )
782 {
783 segment = startSegments( aType, VECTOR2D( cursorPos ) );
784 }
785 // Create a new segment if we're out of previously-created ones
786 else if( !segment->IsNull()
787 || ( twoSegments && !m_wires[m_wires.size() - 2]->IsNull() ) )
788 {
789 // Terminate the command if the end point is on a pin, junction, label, or another
790 // wire or bus.
791 if( screen->IsTerminalPoint( cursorPos, segment->GetLayer() ) )
792 {
794 segment = nullptr;
795
796 if( aQuitOnDraw )
797 {
798 m_frame->PopTool( aTool );
799 break;
800 }
801 }
802 else
803 {
804 int placedSegments = 1;
805
806 // When placing lines with the forty-five degree end, the user is
807 // targetting the endpoint with the angled portion, so it's more
808 // intuitive to place both segments at the same time.
809 if( currentMode == LINE_MODE::LINE_MODE_45 )
810 placedSegments++;
811
812 segment->SetEndPoint( cursorPos );
813
814 for( int i = 0; i < placedSegments; i++ )
815 {
816 // Create a new segment, and chain it after the current segment.
817 segment = static_cast<SCH_LINE*>( segment->Duplicate() );
818 segment->SetFlags( IS_NEW | IS_MOVING );
819 segment->SetStartPoint( cursorPos );
820 m_wires.push_back( segment );
821
822 m_selectionTool->AddItemToSel( segment, true /*quiet mode*/ );
823 }
824 }
825 }
826
827 if( evt->IsDblClick( BUT_LEFT ) && segment )
828 {
829 if( twoSegments && m_wires.size() >= 2 )
830 computeBreakPoint( { m_wires[m_wires.size() - 2], segment }, cursorPos,
831 currentMode, posture );
832
834 segment = nullptr;
835
836 if( aQuitOnDraw )
837 {
838 m_frame->PopTool( aTool );
839 break;
840 }
841 }
842 }
843 //------------------------------------------------------------------------
844 // Handle motion:
845 //
846 else if( evt->IsMotion() || evt->IsAction( &ACTIONS::refreshPreview ) )
847 {
849
850 // Update the bus unfold posture based on the mouse movement
852 {
853 VECTOR2I cursor_delta = cursorPos - m_busUnfold.origin;
855
856 bool flipX = ( cursor_delta.x < 0 );
857 bool flipY = ( cursor_delta.y < 0 );
858
859 // Erase and redraw if necessary
860 if( flipX != m_busUnfold.flipX || flipY != m_busUnfold.flipY )
861 {
862 wxSize size = entry->GetSize();
863 int ySign = flipY ? -1 : 1;
864 int xSign = flipX ? -1 : 1;
865
866 size.x = std::abs( size.x ) * xSign;
867 size.y = std::abs( size.y ) * ySign;
868 entry->SetSize( size );
869
870 m_busUnfold.flipY = flipY;
871 m_busUnfold.flipX = flipX;
872
873 m_frame->UpdateItem( entry, false, true );
874 m_wires.front()->SetStartPoint( entry->GetEnd() );
875 }
876
877 // Update the label "ghost" position
878 m_busUnfold.label->SetPosition( cursorPos );
880
881 // Ensure segment is non-null at the start of bus unfold
882 if( !segment )
883 segment = m_wires.back();
884 }
885
886 if( segment )
887 {
888 // Coerce the line to vertical/horizontal/45 as necessary
889 if( twoSegments && m_wires.size() >= 2 )
890 {
891 computeBreakPoint( { m_wires[m_wires.size() - 2], segment }, cursorPos,
892 currentMode, posture );
893 }
894 else
895 {
896 segment->SetEndPoint( cursorPos );
897 }
898 }
899
900 for( SCH_LINE* wire : m_wires )
901 {
902 if( !wire->IsNull() )
903 m_view->AddToPreview( wire->Clone() );
904 }
905 }
906 else if( evt->IsAction( &EE_ACTIONS::undoLastSegment ) )
907 {
908 if( ( currentMode == LINE_MODE::LINE_MODE_FREE && m_wires.size() > 1 )
909 || ( LINE_MODE::LINE_MODE_90 && m_wires.size() > 2 ) )
910 {
912
913 m_wires.pop_back();
915 delete segment;
916
917 segment = m_wires.back();
918 segment->SetEndPoint( cursorPos );
919
920 // Find new bend point for current mode
921 if( twoSegments && m_wires.size() >= 2 )
922 {
923 computeBreakPoint( { m_wires[m_wires.size() - 2], segment }, cursorPos,
924 currentMode, posture );
925 }
926 else
927 {
928 segment->SetEndPoint( cursorPos );
929 }
930
931 for( SCH_LINE* wire : m_wires )
932 {
933 if( !wire->IsNull() )
934 m_view->AddToPreview( wire->Clone() );
935 }
936 }
937 else
938 {
939 wxBell();
940 }
941 }
942 else if( evt->IsAction( &EE_ACTIONS::switchSegmentPosture ) && m_wires.size() >= 2 )
943 {
944 posture = !posture;
945
946 // The 90 degree mode doesn't have a forced posture like
947 // the 45 degree mode and computeBreakPoint maintains existing 90s' postures.
948 // Instead, just swap the 90 angle here.
949 if( currentMode == LINE_MODE::LINE_MODE_90 )
950 {
952
953 SCH_LINE* line2 = m_wires[m_wires.size() - 1];
954 SCH_LINE* line1 = m_wires[m_wires.size() - 2];
955
956 VECTOR2I delta2 = line2->GetEndPoint() - line2->GetStartPoint();
957 VECTOR2I delta1 = line1->GetEndPoint() - line1->GetStartPoint();
958
959 line2->SetStartPoint(line2->GetEndPoint() - delta1);
960 line1->SetEndPoint(line1->GetStartPoint() + delta2);
961
962 for( SCH_LINE* wire : m_wires )
963 {
964 if( !wire->IsNull() )
965 m_view->AddToPreview( wire->Clone() );
966 }
967 }
968 else
969 {
970 computeBreakPoint( { m_wires[m_wires.size() - 2], segment }, cursorPos, currentMode,
971 posture );
972
974 }
975 }
976 //------------------------------------------------------------------------
977 // Handle context menu:
978 //
979 else if( evt->IsClick( BUT_RIGHT ) )
980 {
981 // Warp after context menu only if dragging...
982 if( !segment )
984
985 contextMenuPos = (wxPoint) cursorPos;
987 }
988 else if( evt->Category() == TC_COMMAND && evt->Action() == TA_CHOICE_MENU_CHOICE )
989 {
990 if( *evt->GetCommandId() >= ID_POPUP_SCH_UNFOLD_BUS
991 && *evt->GetCommandId() <= ID_POPUP_SCH_UNFOLD_BUS_END )
992 {
993 wxASSERT_MSG( !segment, "Bus unfold event received when already drawing!" );
994
995 aType = LAYER_WIRE;
996 wxString net = *evt->Parameter<wxString*>();
997 segment = doUnfoldBus( net, contextMenuPos );
998 }
999 }
1000 //------------------------------------------------------------------------
1001 // Handle TOOL_ACTION special cases
1002 //
1003 else if( evt->IsAction( &EE_ACTIONS::rotateCW ) || evt->IsAction( &EE_ACTIONS::rotateCCW ) )
1004 {
1006 {
1007 m_busUnfold.label->Rotate90( evt->IsAction( &EE_ACTIONS::rotateCW ) );
1009 }
1010 else
1011 {
1012 wxBell();
1013 }
1014 }
1015 else if( evt->IsAction( &ACTIONS::doDelete ) && ( segment || m_busUnfold.in_progress ) )
1016 {
1017 cleanup();
1018 }
1019 else
1020 {
1021 evt->SetPassEvent();
1022 }
1023
1024 // Enable autopanning and cursor capture only when there is a segment to be placed
1025 controls->SetAutoPan( segment != nullptr );
1026 controls->CaptureCursor( segment != nullptr );
1027 }
1028
1029 controls->SetAutoPan( false );
1030 controls->CaptureCursor( false );
1032 controls->ForceCursorPosition( false );
1033 return 0;
1034}
1035
1036
1038 SCH_LINE* aSegment )
1039{
1040 // If a segment isn't provided to copy properties from, we need to create one
1041 if( aSegment == nullptr )
1042 {
1043 switch( aType )
1044 {
1045 default: aSegment = new SCH_LINE( aPos, LAYER_NOTES ); break;
1046 case LAYER_WIRE: aSegment = new SCH_LINE( aPos, LAYER_WIRE ); break;
1047 case LAYER_BUS: aSegment = new SCH_LINE( aPos, LAYER_BUS ); break;
1048 }
1049
1050 // Give segments a parent so they find the default line/wire/bus widths
1051 aSegment->SetParent( &m_frame->Schematic() );
1052 }
1053 else
1054 {
1055 aSegment = static_cast<SCH_LINE*>( aSegment->Duplicate() );
1056 aSegment->SetStartPoint( aPos );
1057 }
1058
1059
1060 aSegment->SetFlags( IS_NEW | IS_MOVING );
1061 m_wires.push_back( aSegment );
1062
1063 m_selectionTool->AddItemToSel( aSegment, true /*quiet mode*/ );
1064
1065 // We need 2 segments to go from a given start pin to an end point when the
1066 // horizontal and vertical lines only switch is on.
1068 {
1069 aSegment = static_cast<SCH_LINE*>( aSegment->Duplicate() );
1070 aSegment->SetFlags( IS_NEW | IS_MOVING );
1071 m_wires.push_back( aSegment );
1072
1073 m_selectionTool->AddItemToSel( aSegment, true /*quiet mode*/ );
1074 }
1075
1076 return aSegment;
1077}
1078
1079
1094{
1095 for( auto it = m_wires.begin(); it != m_wires.end(); )
1096 {
1097 SCH_LINE* line = *it;
1098
1099 if( line->IsNull() )
1100 {
1101 delete line;
1102 it = m_wires.erase( it );
1103 continue;
1104 }
1105
1106 auto next_it = it;
1107 ++next_it;
1108
1109 if( next_it == m_wires.end() )
1110 break;
1111
1112 SCH_LINE* next_line = *next_it;
1113
1114 if( SCH_LINE* merged = line->MergeOverlap( m_frame->GetScreen(), next_line, false ) )
1115 {
1116 delete line;
1117 delete next_line;
1118 it = m_wires.erase( it );
1119 *it = merged;
1120 }
1121
1122 ++it;
1123 }
1124}
1125
1126
1128{
1129 // Clear selection when done so that a new wire can be started.
1130 // NOTE: this must be done before simplifyWireList is called or we might end up with
1131 // freed selected items.
1133
1134 SCH_SCREEN* screen = m_frame->GetScreen();
1135 PICKED_ITEMS_LIST itemList;
1136
1137 // Remove segments backtracking over others
1139
1140 // Collect the possible connection points for the new lines
1141 std::vector<VECTOR2I> connections = m_frame->GetSchematicConnections();
1142 std::vector<VECTOR2I> new_ends;
1143
1144 // Check each new segment for possible junctions and add/split if needed
1145 for( SCH_LINE* wire : m_wires )
1146 {
1147 if( wire->HasFlag( SKIP_STRUCT ) )
1148 continue;
1149
1150 std::vector<VECTOR2I> tmpends = wire->GetConnectionPoints();
1151
1152 new_ends.insert( new_ends.end(), tmpends.begin(), tmpends.end() );
1153
1154 for( const VECTOR2I& pt : connections )
1155 {
1156 if( IsPointOnSegment( wire->GetStartPoint(), wire->GetEndPoint(), pt ) )
1157 new_ends.push_back( pt );
1158 }
1159
1160 itemList.PushItem( ITEM_PICKER( screen, wire, UNDO_REDO::NEWITEM ) );
1161 }
1162
1164 {
1165 wxASSERT( m_busUnfold.entry && m_busUnfold.label );
1166
1169
1173 }
1174 else if( !m_wires.empty() )
1175 {
1177 }
1178
1179 for( size_t ii = 1; ii < m_wires.size(); ++ii )
1181
1182 // Get the last non-null wire (this is the last created segment).
1183 if( !m_wires.empty() )
1185
1186 // Add the new wires
1187 for( SCH_LINE* wire : m_wires )
1188 {
1189 wire->ClearFlags( IS_NEW | IS_MOVING );
1190 m_frame->AddToScreen( wire, screen );
1191 }
1192
1193 m_wires.clear();
1195 m_view->ShowPreview( false );
1196
1197 getViewControls()->CaptureCursor( false );
1198 getViewControls()->SetAutoPan( false );
1199
1200 m_frame->SaveCopyInUndoList( itemList, UNDO_REDO::NEWITEM, false );
1201
1202 // Correct and remove segments that need to be merged.
1204
1205 std::vector<SCH_ITEM*> symbols;
1206
1207 for( SCH_ITEM* symbol : m_frame->GetScreen()->Items().OfType( SCH_SYMBOL_T ) )
1208 symbols.push_back( symbol );
1209
1210 for( SCH_ITEM* symbol : symbols )
1211 {
1212 std::vector<VECTOR2I> pts = symbol->GetConnectionPoints();
1213
1214 if( pts.size() > 2 )
1215 continue;
1216
1217 for( auto pt = pts.begin(); pt != pts.end(); pt++ )
1218 {
1219 for( auto secondPt = pt + 1; secondPt != pts.end(); secondPt++ )
1220 m_frame->TrimWire( *pt, *secondPt );
1221 }
1222 }
1223
1224 for( const VECTOR2I& pt : new_ends )
1225 {
1227 m_frame->AddJunction( m_frame->GetScreen(), pt, true, false );
1228 }
1229
1231 m_busUnfold = {};
1232
1235
1236 m_frame->OnModify();
1237}
1238
1239
1241{
1242 EE_SELECTION* aSelection = aEvent.Parameter<EE_SELECTION*>();
1243 SCHEMATIC* sch = getModel<SCHEMATIC>();
1244 SCH_SCREEN* screen = sch->CurrentSheet().LastScreen();
1245
1246 std::set<SCH_LINE*> lines;
1247 BOX2I bb = aSelection->GetBoundingBox();
1248
1249 for( EDA_ITEM* item : screen->Items().Overlapping( SCH_LINE_T, bb ) )
1250 lines.insert( static_cast<SCH_LINE*>( item ) );
1251
1252 for( unsigned ii = 0; ii < aSelection->GetSize(); ii++ )
1253 {
1254 SCH_ITEM* item = dynamic_cast<SCH_ITEM*>( aSelection->GetItem( ii ) );
1255
1256 if( !item || !item->IsConnectable() || ( item->Type() == SCH_LINE_T ) )
1257 continue;
1258
1259 std::vector<VECTOR2I> pts = item->GetConnectionPoints();
1260
1263 for( SCH_LINE* line : lines )
1264 {
1265 std::vector<VECTOR2I> conn_pts;
1266
1267 for( VECTOR2I pt : pts )
1268 {
1269 if( IsPointOnSegment( line->GetStartPoint(), line->GetEndPoint(), pt ) )
1270 conn_pts.push_back( pt );
1271
1272 if( conn_pts.size() > 2 )
1273 break;
1274 }
1275
1276 if( conn_pts.size() == 2 )
1277 m_frame->TrimWire( conn_pts[0], conn_pts[1] );
1278 }
1279 }
1280
1281 return 0;
1282}
1283
1284
1286{
1287 EE_SELECTION* aSelection = aEvent.Parameter<EE_SELECTION*>();
1288
1289 std::vector<VECTOR2I> pts;
1290 std::vector<VECTOR2I> connections = m_frame->GetSchematicConnections();
1291
1292 std::set<SCH_LINE*> lines;
1293 BOX2I bb = aSelection->GetBoundingBox();
1294
1295 for( EDA_ITEM* item : m_frame->GetScreen()->Items().Overlapping( SCH_LINE_T, bb ) )
1296 lines.insert( static_cast<SCH_LINE*>( item ) );
1297
1298 for( unsigned ii = 0; ii < aSelection->GetSize(); ii++ )
1299 {
1300 SCH_ITEM* item = dynamic_cast<SCH_ITEM*>( aSelection->GetItem( ii ) );
1301
1302 if( !item || !item->IsConnectable() )
1303 continue;
1304
1305 std::vector<VECTOR2I> new_pts = item->GetConnectionPoints();
1306 pts.insert( pts.end(), new_pts.begin(), new_pts.end() );
1307
1308 // If the item is a line, we also add any connection points from the rest of the schematic
1309 // that terminate on the line after it is moved.
1310 if( item->Type() == SCH_LINE_T )
1311 {
1312 SCH_LINE* line = (SCH_LINE*) item;
1313
1314 for( const VECTOR2I& pt : connections )
1315 {
1316 if( IsPointOnSegment( line->GetStartPoint(), line->GetEndPoint(), pt ) )
1317 pts.push_back( pt );
1318 }
1319 }
1320 }
1321
1322 // We always have some overlapping connection points. Drop duplicates here
1323 std::sort( pts.begin(), pts.end(),
1324 []( const VECTOR2I& a, const VECTOR2I& b ) -> bool
1325 {
1326 return a.x < b.x || ( a.x == b.x && a.y < b.y );
1327 } );
1328
1329 pts.erase( unique( pts.begin(), pts.end() ), pts.end() );
1330
1331 for( const VECTOR2I& point : pts )
1332 {
1333 if( m_frame->GetScreen()->IsExplicitJunctionNeeded( point ) )
1334 m_frame->AddJunction( m_frame->GetScreen(), point, true, false );
1335 }
1336
1337 return 0;
1338}
1339
1340
1342{
1348
1350}
const char * name
Definition: DXF_plotter.cpp:56
@ add_line2bus
static TOOL_ACTION doDelete
Definition: actions.h:73
static TOOL_ACTION refreshPreview
Definition: actions.h:109
Defines the structure of a menu based on ACTIONs.
Definition: action_menu.h:49
ACTION_MENU(bool isContextMenu, TOOL_INTERACTIVE *aTool=nullptr)
< Default constructor
Definition: action_menu.cpp:47
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:87
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:73
TOOL_INTERACTIVE * m_tool
Associates tool actions with menu item IDs. Non-owning.
Definition: action_menu.h:266
static const ADVANCED_CFG & GetCfg()
Get the singleton instance's config, which is shared by all consumers.
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.
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 bool m_allowRealTime
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:142
KICAD_T Type() const
Returns the type of object.
Definition: eda_item.h:97
virtual bool IsType(const std::vector< KICAD_T > &aScanTypes) const
Check whether the item is one of the listed types.
Definition: eda_item.h:183
virtual void SetParent(EDA_ITEM *aParent)
Definition: eda_item.h:100
void ClearEditFlags()
Definition: eda_item.h:160
bool IsNew() const
Definition: eda_item.h:103
void SetTextSize(const VECTOR2I &aNewSize)
Definition: eda_text.cpp:347
static TOOL_ACTION finishLine
Definition: ee_actions.h:108
static TOOL_ACTION clearHighlight
Definition: ee_actions.h:253
static TOOL_ACTION selectConnection
If current selection is a wire or bus, expand to entire connection.
Definition: ee_actions.h:53
static TOOL_ACTION clearSelection
Clears the current selection.
Definition: ee_actions.h:56
static TOOL_ACTION placeClassLabel
Definition: ee_actions.h:90
static TOOL_ACTION drawWire
Definition: ee_actions.h:83
static TOOL_ACTION rotateCCW
Definition: ee_actions.h:127
static TOOL_ACTION drawBus
Definition: ee_actions.h:84
static TOOL_ACTION finishWire
Definition: ee_actions.h:106
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:146
static TOOL_ACTION drawLines
Definition: ee_actions.h:101
static TOOL_ACTION finishLineWireOrBus
Definition: ee_actions.h:105
static TOOL_ACTION rotateCW
Definition: ee_actions.h:126
static TOOL_ACTION leaveSheet
Definition: ee_actions.h:202
static TOOL_ACTION placeGlobalLabel
Definition: ee_actions.h:91
static TOOL_ACTION placeHierLabel
Definition: ee_actions.h:92
static TOOL_ACTION trimOverlappingWires
Definition: ee_actions.h:79
static TOOL_ACTION undoLastSegment
Definition: ee_actions.h:103
static TOOL_ACTION addNeededJunctions
Definition: ee_actions.h:78
static TOOL_ACTION unfoldBus
Definition: ee_actions.h:85
static TOOL_ACTION placeLabel
Definition: ee_actions.h:89
static TOOL_ACTION switchSegmentPosture
Definition: ee_actions.h:104
static TOOL_ACTION placeJunction
Definition: ee_actions.h:87
static TOOL_ACTION breakBus
Definition: ee_actions.h:147
static TOOL_ACTION finishBus
Definition: ee_actions.h:107
EE_TYPE Overlapping(const BOX2I &aRect) const
Definition: sch_rtree.h:243
EE_TYPE OfType(KICAD_T aType) const
Definition: sch_rtree.h:238
EE_SELECTION & RequestSelection(const std::vector< KICAD_T > &aScanTypes={ SCH_LOCATE_ANY_T })
Return either an existing selection (filtered), or the selection at the current cursor position if th...
EE_SELECTION & GetSelection()
BOX2I GetBoundingBox() const override
A foundation class for a tool operating on a schematic or symbol.
Definition: ee_tool_base.h:50
EE_SELECTION_TOOL * m_selectionTool
Definition: ee_tool_base.h:184
bool Init() override
Init() is called once upon a registration of the tool.
Definition: ee_tool_base.h:66
static const TOOL_EVENT SelectedItemsModified
Selected items were moved, this can be very high frequency on the canvas, use with care.
Definition: actions.h:213
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 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:1644
void AddToPreview(EDA_ITEM *aItem, bool aTakeOwnership=true)
Definition: view.cpp:1630
void ClearPreview()
Definition: view.cpp:1608
A holder to handle information on schematic or board items.
void PushItem(const ITEM_PICKER &aItem)
Push aItem to the top of the list.
These settings were stored in SCH_BASE_FRAME previously.
Holds all the data relating to one schematic.
Definition: schematic.h:61
SCH_SHEET & Root() const
Definition: schematic.h:91
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,...
void AddToScreen(EDA_ITEM *aItem, SCH_SCREEN *aScreen)
Add an item to the screen (and view) aScreen is the screen the item is located on,...
VECTOR2I GetEnd() const
wxSize GetSize() const
Definition: sch_bus_entry.h:71
void SetSize(const wxSize &aSize)
Definition: sch_bus_entry.h:72
Class for a wire to bus entry.
Each graphical item can have a SCH_CONNECTION describing its logical connection (to a bus or net).
bool IsBus() const
static wxString PrintBusForUI(const wxString &aString)
std::vector< std::shared_ptr< SCH_CONNECTION > > & Members()
Schematic editor (Eeschema) main window.
bool SchematicCleanUp(SCH_SCREEN *aScreen=nullptr)
Perform routine schematic cleaning including breaking wire and buses and deleting identical objects s...
const SCH_CONNECTION * GetHighlightedConnection() const
bool TrimWire(const VECTOR2I &aStart, const VECTOR2I &aEnd)
If any single wire passes through both points, remove the portion between the two points,...
void OnModify() override
Must be called after a schematic change in order to set the "modify" flag and update other data struc...
SCH_SCREEN * GetScreen() const override
Return a pointer to a BASE_SCREEN or one of its derivatives.
std::vector< VECTOR2I > GetSchematicConnections()
Collect a unique list of all possible connection points in the schematic.
void SaveCopyInUndoList(SCH_SCREEN *aScreen, SCH_ITEM *aItemToCopy, UNDO_REDO aTypeCommand, bool aAppend, bool aDirtyConnectivity=true)
Create a copy of the current schematic item, and put it in the undo list.
SCH_SHEET_PATH & GetCurrentSheet() const
SCHEMATIC & Schematic() const
void RecalculateConnections(SCH_CLEANUP_FLAGS aCleanupFlags)
Generate the connection data for the entire schematic hierarchy.
void UpdateItem(EDA_ITEM *aItem, bool isAddOrDelete=false, bool aUpdateRtree=false) override
Mark an item for refresh.
void AddCopyForRepeatItem(const SCH_ITEM *aItem)
SCH_JUNCTION * AddJunction(SCH_SCREEN *aScreen, const VECTOR2I &aPos, bool aAppendToUndo, bool aFinal=true)
void TestDanglingEnds()
Test all of the connectable objects in the schematic for unused connection points.
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:147
virtual bool IsConnectable() const
Definition: sch_item.h:349
SCH_LAYER_ID GetLayer() const
Return the layer this item is on.
Definition: sch_item.h:246
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:146
virtual std::vector< VECTOR2I > GetConnectionPoints() const
Add all the connection points for this item to aPoints.
Definition: sch_item.h:364
SCH_ITEM * Duplicate(bool doClone=false) const
Routine to create a new copy of given item.
Definition: sch_item.cpp:93
void Rotate90(bool aClockwise) override
Definition: sch_label.cpp:309
EDA_ITEM * Clone() const override
Create a duplicate of this item with linked list members set to NULL.
Definition: sch_label.h:250
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(const TOOL_EVENT &aEvent)
Handle the addition of junctions to a selection of objects.
int UnfoldBus(const TOOL_EVENT &aEvent)
static bool IsDrawingWire(const SELECTION &aSelection)
int doDrawSegments(const TOOL_EVENT &aTool, int aType, bool aQuitOnDraw)
static bool IsDrawingBus(const SELECTION &aSelection)
bool Init() override
Init() is called once upon a registration of the tool.
const SCH_SHEET_PIN * getSheetPin(const VECTOR2I &aPosition)
Search for a sheet pin at a location.
std::vector< SCH_LINE * > m_wires
static bool IsDrawingLineWireOrBus(const SELECTION &aSelection)
SCH_LINE * doUnfoldBus(const wxString &aNet, const VECTOR2I &aPos=VECTOR2I(0, 0))
int TrimOverLappingWires(const TOOL_EVENT &aEvent)
Logic to remove wires when overlapping correct items.
SCH_LINE * startSegments(int aType, const VECTOR2D &aPos, SCH_LINE *aSegment=nullptr)
void simplifyWireList()
Iterate over the wire list and removes the null segments and overlapping segments to create a simplif...
static bool IsDrawingLine(const SELECTION &aSelection)
Segment description base class to describe items which have 2 end points (track, wire,...
Definition: sch_line.h:40
void SetStartPoint(const VECTOR2I &aPosition)
Definition: sch_line.h:139
VECTOR2I GetEndPoint() const
Definition: sch_line.h:143
VECTOR2I GetStartPoint() const
Definition: sch_line.h:138
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:440
bool IsNull() const
Definition: sch_line.h:136
void SetEndPoint(const VECTOR2I &aPosition)
Definition: sch_line.h:144
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:782
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:443
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:55
std::vector< SCH_SHEET_PIN * > & GetPins()
Definition: sch_sheet.h:173
VECTOR2I GetPosition() const override
Definition: sch_text.h:203
void SetPosition(const VECTOR2I &aPosition) override
Definition: sch_text.h:204
virtual void SetTextSpinStyle(TEXT_SPIN_STYLE aSpinStyle)
Set a spin or rotation angle, along with specific horizontal and vertical justification styles with e...
Definition: sch_text.cpp:188
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:65
virtual unsigned int GetSize() const override
Return the number of stored items.
Definition: selection.h:97
EDA_ITEM * Front() const
Definition: selection.h:206
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:214
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:156
bool HasPosition() const
Definition: tool_event.h:243
bool DisableGridSnapping() const
Definition: tool_event.h:344
T Parameter() const
Return a non-standard parameter assigned to the event.
Definition: tool_event.h:442
const VECTOR2D Position() const
Returns the point where dragging has started.
Definition: tool_event.h:266
int Modifier(int aMask=MD_MODIFIER_MASK) const
Definition: tool_event.h:339
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.
void PostEvent(const TOOL_EVENT &aEvent)
Put an event to the event queue to be processed at the end of event processing cycle.
bool RunAction(const std::string &aActionName, bool aNow=false, T aParam=NULL)
Run the specified action.
Definition: tool_manager.h:142
TOOLS_HOLDER * GetToolHolder() const
Definition: tool_manager.h:296
void VetoContextMenuMouseWarp()
Disable mouse warping after the current context menu is closed.
Definition: tool_manager.h:424
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: infobar.cpp:175
#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.
@ LAYER_CONNECTABLE
@ ID_POPUP_SCH_UNFOLD_BUS_END
Definition: eeschema_id.h:91
@ ID_POPUP_SCH_UNFOLD_BUS
Definition: eeschema_id.h:90
LINE_MODE
@ LINE_MODE_90
@ LINE_MODE_45
@ LINE_MODE_FREE
@ LAYER_WIRE
Definition: layer_ids.h:344
@ LAYER_NOTES
Definition: layer_ids.h:358
@ LAYER_BUS
Definition: layer_ids.h:345
bool signbit(T v)
Integral version of std::signbit that works all compilers.
Definition: kicad_algo.h:197
EDA_ANGLE abs(const EDA_ANGLE &aAngle)
Definition: eda_angle.h:401
@ BUS
This item represents a bus vector.
@ NO_CLEANUP
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:148
@ TA_CHOICE_MENU_CHOICE
Definition: tool_event.h:93
@ TA_CHOICE_MENU_CLOSED
Definition: tool_event.h:96
@ TC_COMMAND
Definition: tool_event.h:52
@ MD_SHIFT
Definition: tool_event.h:138
@ BUT_LEFT
Definition: tool_event.h:127
@ BUT_RIGHT
Definition: tool_event.h:128
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:42
@ SCH_LINE_T
Definition: typeinfo.h:146
@ SCH_SYMBOL_T
Definition: typeinfo.h:156
@ SCH_ITEM_LOCATE_WIRE_T
Definition: typeinfo.h:170
@ SCH_SHEET_T
Definition: typeinfo.h:158
@ SCH_ITEM_LOCATE_BUS_T
Definition: typeinfo.h:171
@ SCH_ITEM_LOCATE_GRAPHIC_LINE_T
Definition: typeinfo.h:172
constexpr ret_type KiROUND(fp_type v)
Round a floating point number to an integer using "round halfway cases away from zero".
Definition: util.h:85
VECTOR2< double > VECTOR2D
Definition: vector2d.h:617
VECTOR2< int > VECTOR2I
Definition: vector2d.h:618