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-2021 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 
25 #include <sch_line_wire_bus_tool.h>
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>
46 #include <tool/conditional_menu.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 <sch_text.h>
63 #include <schematic.h>
64 #include <ee_actions.h>
65 #include <ee_grid_helper.h>
66 #include <ee_selection.h>
67 #include <ee_selection_tool.h>
68 
70 {
71 public:
73  ACTION_MENU( true ),
74  m_showTitle( false )
75  {
77  SetTitle( _( "Unfold from Bus" ) );
78  }
79 
80  void SetShowTitle()
81  {
82  m_showTitle = true;
83  }
84 
85  bool PassHelpTextToHandler() override { return true; }
86 
87 protected:
88  ACTION_MENU* create() const override
89  {
90  return new BUS_UNFOLD_MENU();
91  }
92 
93 private:
94  void update() override
95  {
98  KICAD_T busType[] = { SCH_LINE_LOCATE_BUS_T, EOT };
99  EE_SELECTION& selection = selTool->RequestSelection( busType );
100  SCH_LINE* bus = (SCH_LINE*) selection.Front();
101 
102  Clear();
103 
104  // TODO(JE) remove once real-time is enabled
105  if( !ADVANCED_CFG::GetCfg().m_RealTimeConnectivity || !CONNECTION_GRAPH::m_allowRealTime )
106  {
108 
109  // Pick up the pointer again because it may have been changed by SchematicCleanUp
110  selection = selTool->RequestSelection( busType );
111  bus = (SCH_LINE*) selection.Front();
112  }
113 
114  if( !bus )
115  {
116  Append( ID_POPUP_SCH_UNFOLD_BUS, _( "No bus selected" ), wxEmptyString );
117  Enable( ID_POPUP_SCH_UNFOLD_BUS, false );
118  return;
119  }
120 
121  SCH_CONNECTION* connection = bus->Connection();
122 
123  if( !connection || !connection->IsBus() || connection->Members().empty() )
124  {
125  Append( ID_POPUP_SCH_UNFOLD_BUS, _( "Bus has no members" ), wxEmptyString );
126  Enable( ID_POPUP_SCH_UNFOLD_BUS, false );
127  return;
128  }
129 
130  int idx = 0;
131 
132  if( m_showTitle )
133  {
134  Append( ID_POPUP_SCH_UNFOLD_BUS, _( "Unfold from Bus" ), wxEmptyString );
135  Enable( ID_POPUP_SCH_UNFOLD_BUS, false );
136  }
137 
138  for( const std::shared_ptr<SCH_CONNECTION>& member : connection->Members() )
139  {
140  int id = ID_POPUP_SCH_UNFOLD_BUS + ( idx++ );
141  wxString name = member->FullLocalName();
142 
143  if( member->Type() == CONNECTION_TYPE::BUS )
144  {
145  ACTION_MENU* submenu = new ACTION_MENU( true, m_tool );
146  AppendSubMenu( submenu, SCH_CONNECTION::PrintBusForUI( name ), name );
147 
148  for( const std::shared_ptr<SCH_CONNECTION>& sub_member : member->Members() )
149  {
150  id = ID_POPUP_SCH_UNFOLD_BUS + ( idx++ );
151  name = sub_member->FullLocalName();
152  submenu->Append( id, SCH_CONNECTION::PrintBusForUI( name ), name );
153  }
154  }
155  else
156  {
157  Append( id, name, wxEmptyString );
158  }
159  }
160  }
161 
163 };
164 
165 
167  EE_TOOL_BASE<SCH_EDIT_FRAME>( "eeschema.InteractiveDrawingLineWireBus" ),
168  m_inDrawingTool( false )
169 {
170  m_busUnfold = {};
171  m_wires.reserve( 16 );
172 }
173 
174 
176 {
177 }
178 
179 
181 {
183 
184  auto wireOrBusTool =
185  [this]( const SELECTION& aSel )
186  {
189  };
190 
191  auto lineTool =
192  [this]( const SELECTION& aSel )
193  {
195  };
196 
197  auto belowRootSheetCondition =
198  [&]( const SELECTION& aSel )
199  {
200  return m_frame->GetCurrentSheet().Last() != &m_frame->Schematic().Root();
201  };
202 
203  auto busSelection = EE_CONDITIONS::MoreThan( 0 )
205 
206  auto& ctxMenu = m_menu.GetMenu();
207 
208  // Build the tool menu
209  //
210  ctxMenu.AddItem( EE_ACTIONS::leaveSheet, belowRootSheetCondition, 2 );
211 
212  ctxMenu.AddSeparator( 10 );
213  ctxMenu.AddItem( EE_ACTIONS::drawWire, wireOrBusTool && EE_CONDITIONS::Idle, 10 );
214  ctxMenu.AddItem( EE_ACTIONS::drawBus, wireOrBusTool && EE_CONDITIONS::Idle, 10 );
215  ctxMenu.AddItem( EE_ACTIONS::drawLines, lineTool && EE_CONDITIONS::Idle, 10 );
216  ctxMenu.AddItem( EE_ACTIONS::finishWire, IsDrawingWire, 10 );
217  ctxMenu.AddItem( EE_ACTIONS::finishBus, IsDrawingBus, 10 );
218  ctxMenu.AddItem( EE_ACTIONS::finishLine, IsDrawingLine, 10 );
219 
220  std::shared_ptr<BUS_UNFOLD_MENU> busUnfoldMenu = std::make_shared<BUS_UNFOLD_MENU>();
221  busUnfoldMenu->SetTool( this );
222  m_menu.AddSubMenu( busUnfoldMenu );
223  ctxMenu.AddMenu( busUnfoldMenu.get(), EE_CONDITIONS::Idle, 10 );
224 
225  ctxMenu.AddSeparator( 100 );
226  ctxMenu.AddItem( EE_ACTIONS::placeJunction, wireOrBusTool && EE_CONDITIONS::Idle, 100 );
227  ctxMenu.AddItem( EE_ACTIONS::placeLabel, wireOrBusTool && EE_CONDITIONS::Idle, 100 );
228  ctxMenu.AddItem( EE_ACTIONS::placeGlobalLabel, wireOrBusTool && EE_CONDITIONS::Idle, 100 );
229  ctxMenu.AddItem( EE_ACTIONS::placeHierLabel, wireOrBusTool && EE_CONDITIONS::Idle, 100 );
230  ctxMenu.AddItem( EE_ACTIONS::breakWire, wireOrBusTool && EE_CONDITIONS::Idle, 100 );
231  ctxMenu.AddItem( EE_ACTIONS::breakBus, wireOrBusTool && EE_CONDITIONS::Idle, 100 );
232 
233  ctxMenu.AddSeparator( 200 );
234  ctxMenu.AddItem( EE_ACTIONS::selectNode, wireOrBusTool && EE_CONDITIONS::Idle, 200 );
235  ctxMenu.AddItem( EE_ACTIONS::selectConnection, wireOrBusTool && EE_CONDITIONS::Idle, 200 );
236 
237  // Add bus unfolding to the selection tool
238  //
240 
241  std::shared_ptr<BUS_UNFOLD_MENU> selBusUnfoldMenu = std::make_shared<BUS_UNFOLD_MENU>();
242  selBusUnfoldMenu->SetTool( m_selectionTool );
243  m_selectionTool->GetToolMenu().AddSubMenu( selBusUnfoldMenu );
244  selToolMenu.AddMenu( selBusUnfoldMenu.get(), busSelection && EE_CONDITIONS::Idle, 100 );
245 
246  return true;
247 }
248 
249 
251 {
252  static KICAD_T graphicLineType[] = { SCH_LINE_LOCATE_GRAPHIC_LINE_T, EOT };
253  return IsDrawingLineWireOrBus( aSelection ) && aSelection.Front()->IsType( graphicLineType );
254 }
255 
256 
258 {
259  static KICAD_T wireType[] = { SCH_LINE_LOCATE_WIRE_T, EOT };
260  return IsDrawingLineWireOrBus( aSelection ) && aSelection.Front()->IsType( wireType );
261 }
262 
263 
265 {
266  static KICAD_T busType[] = { SCH_LINE_LOCATE_BUS_T, EOT };
267  return IsDrawingLineWireOrBus( aSelection ) && aSelection.Front()->IsType( busType );
268 }
269 
270 
272 {
273  // NOTE: for immediate hotkeys, it is NOT required that the line, wire or bus tool
274  // be selected
275  SCH_ITEM* item = (SCH_ITEM*) aSelection.Front();
276  return item && item->IsNew() && item->Type() == SCH_LINE_T;
277 }
278 
279 
281 {
282  if( m_inDrawingTool )
283  return 0;
284 
286 
288 
289  std::string tool = aEvent.GetCommandStr().get();
290  m_frame->PushTool( tool );
292 
293  if( aEvent.HasPosition() )
294  {
296  grid.SetSnap( !aEvent.Modifier( MD_SHIFT ) );
297  grid.SetUseGrid( getView()->GetGAL()->GetGridSnapping() && !aEvent.DisableGridSnapping() );
298 
299  VECTOR2D cursorPos = grid.BestSnapAnchor( aEvent.Position(), LAYER_CONNECTABLE, nullptr );
300  startSegments( params->layer, cursorPos );
301  }
302 
303  return doDrawSegments( tool, params->layer, params->quitOnDraw );
304 }
305 
306 
308 {
309  if( m_inDrawingTool )
310  return 0;
311 
313 
314  wxString* netPtr = aEvent.Parameter<wxString*>();
315  wxString net;
316  SCH_LINE* segment = nullptr;
317 
318  std::string tool = aEvent.GetCommandStr().get();
319  m_frame->PushTool( tool );
320  Activate();
321 
322  if( netPtr )
323  {
324  net = *netPtr;
325  delete netPtr;
326  }
327  else
328  {
329  BUS_UNFOLD_MENU unfoldMenu;
330  unfoldMenu.SetTool( this );
331  unfoldMenu.SetShowTitle();
332 
333  SetContextMenu( &unfoldMenu, CMENU_NOW );
334 
335  while( TOOL_EVENT* evt = Wait() )
336  {
337  if( evt->Action() == TA_CHOICE_MENU_CHOICE )
338  {
339  OPT<int> id = evt->GetCommandId();
340 
341  if( id && ( *id > 0 ) )
342  net = *evt->Parameter<wxString*>();
343 
344  break;
345  }
346  else if( evt->Action() == TA_CHOICE_MENU_CLOSED )
347  {
348  break;
349  }
350  else
351  {
352  evt->SetPassEvent();
353  }
354  }
355  }
356 
357  // Break a wire for the given net out of the bus
358  if( !net.IsEmpty() )
359  segment = doUnfoldBus( net );
360 
361  // If we have an unfolded wire to draw, then draw it
362  if( segment )
363  return doDrawSegments( tool, LAYER_WIRE, false );
364  else
365  {
366  m_frame->PopTool( tool );
367  return 0;
368  }
369 }
370 
371 
372 SCH_LINE* SCH_LINE_WIRE_BUS_TOOL::doUnfoldBus( const wxString& aNet, const wxPoint& aPos )
373 {
374  SCHEMATIC_SETTINGS& cfg = getModel<SCHEMATIC>()->Settings();
375 
376  wxPoint pos = aPos;
377 
378  if( aPos == wxDefaultPosition )
379  pos = static_cast<wxPoint>( getViewControls()->GetCursorPosition() );
380 
382 
383  m_busUnfold.entry = new SCH_BUS_WIRE_ENTRY( pos );
386 
392 
393  m_busUnfold.in_progress = true;
394  m_busUnfold.origin = pos;
395  m_busUnfold.net_name = aNet;
396 
398 
400 }
401 
402 
403 const SCH_SHEET_PIN* SCH_LINE_WIRE_BUS_TOOL::getSheetPin( const wxPoint& aPosition )
404 {
405  SCH_SCREEN* screen = m_frame->GetScreen();
406 
407  for( SCH_ITEM* item : screen->Items().Overlapping( SCH_SHEET_T, aPosition ) )
408  {
409  SCH_SHEET* sheet = static_cast<SCH_SHEET*>( item );
410 
411  for( SCH_SHEET_PIN* pin : sheet->GetPins() )
412  {
413  if( pin->GetPosition() == aPosition )
414  return pin;
415  }
416  }
417 
418  return nullptr;
419 }
420 
421 
422 void SCH_LINE_WIRE_BUS_TOOL::computeBreakPoint( const std::pair<SCH_LINE*, SCH_LINE*>& aSegments,
423  wxPoint& aPosition )
424 {
425  wxCHECK_RET( aSegments.first && aSegments.second,
426  wxT( "Cannot compute break point of NULL line segment." ) );
427 
428  SCH_LINE* segment = aSegments.first;
429  SCH_LINE* next_segment = aSegments.second;
430 
431  wxPoint midPoint;
432  int iDx = segment->GetEndPoint().x - segment->GetStartPoint().x;
433  int iDy = segment->GetEndPoint().y - segment->GetStartPoint().y;
434 
435  const SCH_SHEET_PIN* connectedPin = getSheetPin( segment->GetStartPoint() );
436  SHEET_SIDE force = connectedPin ? connectedPin->GetSide() : SHEET_SIDE::UNDEFINED;
437 
438  if( force == SHEET_SIDE::LEFT || force == SHEET_SIDE::RIGHT )
439  {
440  if( aPosition.x == connectedPin->GetPosition().x ) // push outside sheet boundary
441  {
442  int direction = ( force == SHEET_SIDE::LEFT ) ? -1 : 1;
443  aPosition.x += KiROUND( getView()->GetGAL()->GetGridSize().x * direction );
444  }
445 
446  midPoint.x = aPosition.x;
447  midPoint.y = segment->GetStartPoint().y; // force horizontal
448  }
449  else if( iDy != 0 ) // keep the first segment orientation (vertical)
450  {
451  midPoint.x = segment->GetStartPoint().x;
452  midPoint.y = aPosition.y;
453  }
454  else if( iDx != 0 ) // keep the first segment orientation (horizontal)
455  {
456  midPoint.x = aPosition.x;
457  midPoint.y = segment->GetStartPoint().y;
458  }
459  else
460  {
461  if( std::abs( aPosition.x - segment->GetStartPoint().x ) <
462  std::abs( aPosition.y - segment->GetStartPoint().y ) )
463  {
464  midPoint.x = segment->GetStartPoint().x;
465  midPoint.y = aPosition.y;
466  }
467  else
468  {
469  midPoint.x = aPosition.x;
470  midPoint.y = segment->GetStartPoint().y;
471  }
472  }
473 
474  segment->SetEndPoint( midPoint );
475  next_segment->SetStartPoint( midPoint );
476  next_segment->SetEndPoint( aPosition );
477 }
478 
479 
480 int SCH_LINE_WIRE_BUS_TOOL::doDrawSegments( const std::string& aTool, int aType, bool aQuitOnDraw )
481 {
482  SCH_SCREEN* screen = m_frame->GetScreen();
483  SCH_LINE* segment = nullptr;
486  bool forceHV = m_frame->eeconfig()->m_Drawing.hv_lines_only;
487 
488  auto setCursor =
489  [&]()
490  {
491  if( aType == LAYER_WIRE )
493  else if( aType == LAYER_BUS )
495  else if( aType == LAYER_NOTES )
497  else
499  };
500 
501  auto cleanup =
502  [&] ()
503  {
505 
506  for( SCH_LINE* wire : m_wires )
507  delete wire;
508 
509  m_wires.clear();
510  segment = nullptr;
511 
512  if( m_busUnfold.entry )
514 
517 
520 
521  delete m_busUnfold.entry;
522  delete m_busUnfold.label;
523  m_busUnfold = {};
524 
525  m_view->ClearPreview();
526  m_view->ShowPreview( false );
527  };
528 
529  Activate();
530  // Must be done after Activate() so that it gets set into the correct context
531  controls->ShowCursor( true );
532  // Set initial cursor
533  setCursor();
534 
535  // Add the new label to the selection so the rotate command operates on it
536  if( m_busUnfold.label )
538 
539  // Continue the existing wires if we've started (usually by immediate action preference)
540  if( !m_wires.empty() )
541  segment = m_wires.back();
542 
543  wxPoint contextMenuPos;
544 
545  // Main loop: keep receiving events
546  while( TOOL_EVENT* evt = Wait() )
547  {
548  setCursor();
549  grid.SetMask( GRID_HELPER::ALL );
550  grid.SetSnap( !evt->Modifier( MD_SHIFT ) );
551  grid.SetUseGrid( getView()->GetGAL()->GetGridSnapping() && !evt->DisableGridSnapping() );
552 
553  if( segment )
554  {
555  if( segment->GetStartPoint().x == segment->GetEndPoint().x )
556  grid.ClearMaskFlag( GRID_HELPER::VERTICAL );
557 
558  if( segment->GetStartPoint().y == segment->GetEndPoint().y )
559  grid.ClearMaskFlag( GRID_HELPER::HORIZONTAL );
560  }
561 
562  wxPoint cursorPos = static_cast<wxPoint>( evt->HasPosition() ?
563  evt->Position() :
564  controls->GetMousePosition() );
565 
566  cursorPos = (wxPoint) grid.BestSnapAnchor( cursorPos, LAYER_CONNECTABLE, segment );
567  controls->ForceCursorPosition( true, cursorPos );
568 
569  // Need to handle change in H/V mode while drawing
570  if( forceHV != m_frame->eeconfig()->m_Drawing.hv_lines_only )
571  {
572  forceHV = m_frame->eeconfig()->m_Drawing.hv_lines_only;
573 
574  // Need to delete extra segment if we have one
575  if( !forceHV && m_wires.size() >= 2 && segment != nullptr )
576  {
577  m_wires.pop_back();
579  delete segment;
580 
581  segment = m_wires.back();
582  segment->SetEndPoint( cursorPos );
583  }
584  // Add a segment so we can move orthogonally
585  else if( forceHV && segment )
586  {
587  segment->SetEndPoint( cursorPos );
588 
589  // Create a new segment, and chain it after the current segment.
590  segment = static_cast<SCH_LINE*>( segment->Duplicate() );
591  segment->SetFlags( IS_NEW | IS_MOVING );
592  segment->SetStartPoint( cursorPos );
593  m_wires.push_back( segment );
594 
595  m_selectionTool->AddItemToSel( segment, true /*quiet mode*/ );
596  }
597  }
598 
599 
600  //------------------------------------------------------------------------
601  // Handle cancel:
602  //
603  if( evt->IsCancelInteractive() )
604  {
605  m_frame->GetInfoBar()->Dismiss();
606 
607  if( segment || m_busUnfold.in_progress )
608  {
609  cleanup();
610  }
611  else
612  {
613  m_frame->PopTool( aTool );
614  break;
615  }
616  }
617  else if( evt->IsActivate() )
618  {
619  if( segment || m_busUnfold.in_progress )
620  {
621  m_frame->ShowInfoBarMsg( _( "Press <ESC> to cancel drawing." ) );
622  evt->SetPassEvent( false );
623  continue;
624  }
625 
626  if( evt->IsMoveTool() )
627  {
628  // leave ourselves on the stack so we come back after the move
629  break;
630  }
631  else
632  {
633  m_frame->PopTool( aTool );
634  break;
635  }
636  }
637  //------------------------------------------------------------------------
638  // Handle finish:
639  //
640  else if( evt->IsAction( &EE_ACTIONS::finishLineWireOrBus )
641  || evt->IsAction( &EE_ACTIONS::finishWire )
642  || evt->IsAction( &EE_ACTIONS::finishBus )
643  || evt->IsAction( &EE_ACTIONS::finishLine ) )
644  {
645  if( segment || m_busUnfold.in_progress )
646  {
647  finishSegments();
648  segment = nullptr;
649 
650  if( aQuitOnDraw )
651  {
652  m_frame->PopTool( aTool );
653  break;
654  }
655  }
656  }
657  //------------------------------------------------------------------------
658  // Handle click:
659  //
660  else if( evt->IsClick( BUT_LEFT ) || ( segment && evt->IsDblClick( BUT_LEFT ) ) )
661  {
662  // First click when unfolding places the label and wire-to-bus entry
664  {
665  wxASSERT( aType == LAYER_WIRE );
666 
667  m_frame->AddToScreen( m_busUnfold.label, screen );
669  m_busUnfold.label_placed = true;
670  }
671 
672  if( !segment )
673  {
674  segment = startSegments( aType, VECTOR2D( cursorPos ) );
675  }
676  // Create a new segment if we're out of previously-created ones
677  else if( !segment->IsNull() || ( forceHV && !m_wires[ m_wires.size() - 2 ]->IsNull() ) )
678  {
679  // Terminate the command if the end point is on a pin, junction, label, or another
680  // wire or bus.
681  if( screen->IsTerminalPoint( cursorPos, segment->GetLayer() ) )
682  {
683  finishSegments();
684  segment = nullptr;
685 
686  if( aQuitOnDraw )
687  {
688  m_frame->PopTool( aTool );
689  break;
690  }
691  }
692  else
693  {
694  segment->SetEndPoint( cursorPos );
695 
696  // Create a new segment, and chain it after the current segment.
697  segment = static_cast<SCH_LINE*>( segment->Duplicate() );
698  segment->SetFlags( IS_NEW | IS_MOVING );
699  segment->SetStartPoint( cursorPos );
700  m_wires.push_back( segment );
701 
702  m_selectionTool->AddItemToSel( segment, true /*quiet mode*/ );
703  }
704  }
705 
706  if( evt->IsDblClick( BUT_LEFT ) && segment )
707  {
708  if( forceHV && m_wires.size() >= 2 )
709  computeBreakPoint( { m_wires[ m_wires.size() - 2 ], segment }, cursorPos );
710 
711  finishSegments();
712  segment = nullptr;
713 
714  if( aQuitOnDraw )
715  {
716  m_frame->PopTool( aTool );
717  break;
718  }
719  }
720  }
721  //------------------------------------------------------------------------
722  // Handle motion:
723  //
724  else if( evt->IsMotion() || evt->IsAction( &ACTIONS::refreshPreview ) )
725  {
726  m_view->ClearPreview();
727 
728  // Update the bus unfold posture based on the mouse movement
730  {
731  wxPoint cursor_delta = cursorPos - m_busUnfold.origin;
733 
734  bool flipX = ( cursor_delta.x < 0 );
735  bool flipY = ( cursor_delta.y < 0 );
736 
737  // Erase and redraw if necessary
738  if( flipX != m_busUnfold.flipX || flipY != m_busUnfold.flipY )
739  {
740  wxSize size = entry->GetSize();
741  int ySign = flipY ? -1 : 1;
742  int xSign = flipX ? -1 : 1;
743 
744  size.x = std::abs( size.x ) * xSign;
745  size.y = std::abs( size.y ) * ySign;
746  entry->SetSize( size );
747 
748  m_busUnfold.flipY = flipY;
749  m_busUnfold.flipX = flipX;
750 
751  m_frame->UpdateItem( entry, false, true );
752  m_wires.front()->SetStartPoint( entry->GetEnd() );
753  }
754 
755  // Update the label "ghost" position
756  m_busUnfold.label->SetPosition( cursorPos );
758 
759  // Ensure segment is non-null at the start of bus unfold
760  if( !segment )
761  segment = m_wires.back();
762  }
763 
764  if( segment )
765  {
766  // Coerce the line to vertical or horizontal if necessary
767  if( forceHV && m_wires.size() >= 2 )
768  computeBreakPoint( { m_wires[ m_wires.size() - 2 ], segment }, cursorPos );
769  else
770  segment->SetEndPoint( cursorPos );
771  }
772 
773  for( SCH_LINE* wire : m_wires )
774  {
775  if( !wire->IsNull() )
776  m_view->AddToPreview( wire->Clone() );
777  }
778  }
779  //------------------------------------------------------------------------
780  // Handle context menu:
781  //
782  else if( evt->IsClick( BUT_RIGHT ) )
783  {
784  // Warp after context menu only if dragging...
785  if( !segment )
787 
788  contextMenuPos = cursorPos;
790  }
791  else if( evt->Category() == TC_COMMAND && evt->Action() == TA_CHOICE_MENU_CHOICE )
792  {
793  if( evt->GetCommandId().get() >= ID_POPUP_SCH_UNFOLD_BUS
794  && evt->GetCommandId().get() <= ID_POPUP_SCH_UNFOLD_BUS_END )
795  {
796  wxASSERT_MSG( !segment, wxT( "Bus unfold event received when already drawing!" ) );
797 
798  aType = LAYER_WIRE;
799  wxString net = *evt->Parameter<wxString*>();
800  segment = doUnfoldBus( net, contextMenuPos );
801  }
802  }
803  //------------------------------------------------------------------------
804  // Handle TOOL_ACTION special cases
805  //
806  else if( evt->IsAction( &EE_ACTIONS::rotateCW ) || evt->IsAction( &EE_ACTIONS::rotateCCW ) )
807  {
809  {
810  m_busUnfold.label->Rotate90( evt->IsAction( &EE_ACTIONS::rotateCW ) );
812  }
813  else
814  {
815  wxBell();
816  }
817  }
818  else if( evt->IsAction( &ACTIONS::doDelete ) && ( segment || m_busUnfold.in_progress ) )
819  {
820  cleanup();
821  }
822  else
823  {
824  evt->SetPassEvent();
825  }
826 
827  // Enable autopanning and cursor capture only when there is a segment to be placed
828  controls->SetAutoPan( segment != nullptr );
829  controls->CaptureCursor( segment != nullptr );
830  }
831 
832  controls->SetAutoPan( false );
833  controls->CaptureCursor( false );
835  controls->ForceCursorPosition( false );
836  return 0;
837 }
838 
839 
841 {
842  SCH_LINE* segment = nullptr;
843 
844  switch ( aType )
845  {
846  default: segment = new SCH_LINE( aPos, LAYER_NOTES ); break;
847  case LAYER_WIRE: segment = new SCH_LINE( aPos, LAYER_WIRE ); break;
848  case LAYER_BUS: segment = new SCH_LINE( aPos, LAYER_BUS ); break;
849  }
850 
851  // Give segments a parent so they find the default line/wire/bus widths
852  segment->SetParent( &m_frame->Schematic() );
853  segment->SetFlags( IS_NEW | IS_MOVING );
854  m_wires.push_back( segment );
855 
856  m_selectionTool->AddItemToSel( segment, true /*quiet mode*/ );
857 
858  // We need 2 segments to go from a given start pin to an end point when the
859  // horizontal and vertical lines only switch is on.
861  {
862  segment = static_cast<SCH_LINE*>( segment->Duplicate() );
863  segment->SetFlags( IS_NEW | IS_MOVING );
864  m_wires.push_back( segment );
865 
866  m_selectionTool->AddItemToSel( segment, true /*quiet mode*/ );
867  }
868 
869  return segment;
870 }
871 
872 
887 {
888  for( auto it = m_wires.begin(); it != m_wires.end(); )
889  {
890  SCH_LINE* line = *it;
891 
892  if( line->IsNull() )
893  {
894  delete line;
895  it = m_wires.erase( it );
896  continue;
897  }
898 
899  auto next_it = it;
900  ++next_it;
901 
902  if( next_it == m_wires.end() )
903  break;
904 
905  SCH_LINE* next_line = *next_it;
906 
907  if( SCH_LINE* merged = line->MergeOverlap( m_frame->GetScreen(), next_line, false ) )
908  {
909  delete line;
910  delete next_line;
911  it = m_wires.erase( it );
912  *it = merged;
913  }
914 
915  ++it;
916  }
917 }
918 
919 
921 {
922  // Clear selection when done so that a new wire can be started.
923  // NOTE: this must be done before simplifyWireList is called or we might end up with
924  // freed selected items.
926 
927  SCH_SCREEN* screen = m_frame->GetScreen();
928  PICKED_ITEMS_LIST itemList;
929 
930  // Remove segments backtracking over others
932 
933  // Collect the possible connection points for the new lines
934  std::vector< wxPoint > connections = m_frame->GetSchematicConnections();
935  std::vector< wxPoint > new_ends;
936 
937  // Check each new segment for possible junctions and add/split if needed
938  for( SCH_LINE* wire : m_wires )
939  {
940  if( wire->HasFlag( SKIP_STRUCT ) )
941  continue;
942 
943  std::vector<wxPoint> tmpends = wire->GetConnectionPoints();
944 
945  new_ends.insert( new_ends.end(), tmpends.begin(), tmpends.end() );
946 
947  for( const wxPoint& pt : connections )
948  {
949  if( IsPointOnSegment( wire->GetStartPoint(), wire->GetEndPoint(), pt ) )
950  new_ends.push_back( pt );
951  }
952  itemList.PushItem( ITEM_PICKER( screen, wire, UNDO_REDO::NEWITEM ) );
953  }
954 
956  {
957  wxASSERT( m_busUnfold.entry && m_busUnfold.label );
958 
959  itemList.PushItem( ITEM_PICKER( screen, m_busUnfold.entry, UNDO_REDO::NEWITEM ) );
960  itemList.PushItem( ITEM_PICKER( screen, m_busUnfold.label, UNDO_REDO::NEWITEM ) );
962  }
963 
964  // Get the last non-null wire (this is the last created segment).
965  if( !m_wires.empty() )
967 
968  // Add the new wires
969  for( SCH_LINE* wire : m_wires )
970  {
971  wire->ClearFlags( IS_NEW | IS_MOVING );
972  m_frame->AddToScreen( wire, screen );
973  }
974 
975  m_wires.clear();
976  m_view->ClearPreview();
977  m_view->ShowPreview( false );
978 
979  getViewControls()->CaptureCursor( false );
980  getViewControls()->SetAutoPan( false );
981 
982  m_frame->SaveCopyInUndoList( itemList, UNDO_REDO::NEWITEM, false );
983 
984  // Correct and remove segments that need to be merged.
986 
987  std::vector<SCH_ITEM*> symbols;
988 
989  for( SCH_ITEM* symbol : m_frame->GetScreen()->Items().OfType( SCH_SYMBOL_T ) )
990  symbols.push_back( symbol );
991 
992  for( SCH_ITEM* symbol : symbols )
993  {
994  std::vector<wxPoint> pts = symbol->GetConnectionPoints();
995 
996  if( pts.size() > 2 )
997  continue;
998 
999  for( auto pt = pts.begin(); pt != pts.end(); pt++ )
1000  {
1001  for( auto secondPt = pt + 1; secondPt != pts.end(); secondPt++ )
1002  m_frame->TrimWire( *pt, *secondPt );
1003  }
1004  }
1005 
1006  for( const wxPoint& pt : new_ends )
1007  {
1009  m_frame->AddJunction( m_frame->GetScreen(), pt, true, false );
1010  }
1011 
1012  if( m_busUnfold.in_progress )
1013  m_busUnfold = {};
1014 
1017 
1018  m_frame->OnModify();
1019 }
1020 
1021 
1023 {
1024  EE_SELECTION* aSelection = aEvent.Parameter<EE_SELECTION*>();
1025  SCHEMATIC* sch = getModel<SCHEMATIC>();
1026  SCH_SCREEN* screen = sch->CurrentSheet().LastScreen();
1027 
1028  std::set<SCH_LINE*> lines;
1029  EDA_RECT bb = aSelection->GetBoundingBox();
1030 
1031  for( EDA_ITEM* item : screen->Items().Overlapping( SCH_LINE_T, bb ) )
1032  lines.insert( static_cast<SCH_LINE*>( item ) );
1033 
1034  for( unsigned ii = 0; ii < aSelection->GetSize(); ii++ )
1035  {
1036  SCH_ITEM* item = dynamic_cast<SCH_ITEM*>( aSelection->GetItem( ii ) );
1037  std::vector<wxPoint> pts = item->GetConnectionPoints();
1038 
1039  if( !item || !item->IsConnectable() || ( item->Type() == SCH_LINE_T ) )
1040  continue;
1041 
1044  for( SCH_LINE* line : lines )
1045  {
1046  std::vector<wxPoint> conn_pts;
1047 
1048  for( wxPoint pt : pts )
1049  {
1050  if( IsPointOnSegment( line->GetStartPoint(), line->GetEndPoint(), pt ) )
1051  conn_pts.push_back( pt );
1052 
1053  if( conn_pts.size() > 2 )
1054  break;
1055  }
1056 
1057  if( conn_pts.size() == 2 )
1058  m_frame->TrimWire( conn_pts[0], conn_pts[1] );
1059  }
1060  }
1061 
1062  return 0;
1063 }
1064 
1065 
1067 {
1068  EE_SELECTION* aSelection = aEvent.Parameter<EE_SELECTION*>();
1069 
1070  std::vector<wxPoint> pts;
1071  std::vector<wxPoint> connections = m_frame->GetSchematicConnections();
1072 
1073  std::set<SCH_LINE*> lines;
1074  EDA_RECT bb = aSelection->GetBoundingBox();
1075 
1076  for( EDA_ITEM* item : m_frame->GetScreen()->Items().Overlapping( SCH_LINE_T, bb ) )
1077  lines.insert( static_cast<SCH_LINE*>( item ) );
1078 
1079  for( unsigned ii = 0; ii < aSelection->GetSize(); ii++ )
1080  {
1081  SCH_ITEM* item = dynamic_cast<SCH_ITEM*>( aSelection->GetItem( ii ) );
1082 
1083  if( !item || !item->IsConnectable() )
1084  continue;
1085 
1086  std::vector<wxPoint> new_pts = item->GetConnectionPoints();
1087  pts.insert( pts.end(), new_pts.begin(), new_pts.end() );
1088 
1089  // If the item is a line, we also add any connection points from the rest of the schematic
1090  // that terminate on the line after it is moved.
1091  if( item->Type() == SCH_LINE_T )
1092  {
1093  SCH_LINE* line = (SCH_LINE*) item;
1094 
1095  for( const wxPoint& pt : connections )
1096  {
1097  if( IsPointOnSegment( line->GetStartPoint(), line->GetEndPoint(), pt ) )
1098  pts.push_back( pt );
1099  }
1100  }
1101  }
1102 
1103  // We always have some overlapping connection points. Drop duplicates here
1104  std::sort( pts.begin(), pts.end(),
1105  []( const wxPoint& a, const wxPoint& b ) -> bool
1106  {
1107  return a.x < b.x || ( a.x == b.x && a.y < b.y );
1108  } );
1109 
1110  pts.erase( unique( pts.begin(), pts.end() ), pts.end() );
1111 
1112  for( const wxPoint& point : pts )
1113  {
1114  if( m_frame->GetScreen()->IsExplicitJunctionNeeded( point ) )
1115  m_frame->AddJunction( m_frame->GetScreen(), point, true, false );
1116  }
1117 
1118  return 0;
1119 }
1120 
1121 
1123 {
1129 
1131 }
static wxString PrintBusForUI(const wxString &aString)
virtual void ShowCursor(bool aEnabled)
Enable or disables display of cursor.
void AddMenu(ACTION_MENU *aMenu, const SELECTION_CONDITION &aCondition=SELECTION_CONDITIONS::ShowAlways, int aOrder=ANY_ORDER)
Add a submenu to the menu.
EE_TYPE OfType(KICAD_T aType) const
Definition: sch_rtree.h:230
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:511
bool SchematicCleanUp(SCH_SCREEN *aScreen=nullptr)
Perform routine schematic cleaning including breaking wire and buses and deleting identical objects s...
bool IsCurrentTool(const TOOL_ACTION &aAction) const
TOOL_MENU m_menu
The functions below are not yet implemented - their interface may change.
virtual bool IsConnectable() const
Definition: sch_item.h:349
static bool IsDrawingWire(const SELECTION &aSelection)
void simplifyWireList()
Iterate over the wire list and removes the null segments and overlapping segments to create a simplif...
void SetCurrentCursor(KICURSOR aCursor)
Set the current cursor shape for this panel.
bool flipY
True if the bus entry should be flipped in the y-axis.
bool PassHelpTextToHandler() override
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.
virtual VECTOR2D GetMousePosition(bool aWorldCoordinates=true) const =0
Return the current mouse pointer position.
virtual std::vector< wxPoint > GetConnectionPoints() const
Add all the connection points for this item to aPoints.
Definition: sch_item.h:364
static TOOL_ACTION breakBus
Definition: ee_actions.h:135
void RecalculateConnections(SCH_CLEANUP_FLAGS aCleanupFlags)
Generate the connection data for the entire schematic hierarchy.
wxPoint GetStartPoint() const
Definition: sch_line.h:90
Holds all the data relating to one schematic.
Definition: schematic.h:59
void SetSize(const wxSize &aSize)
Definition: sch_bus_entry.h:76
#define IS_NEW
New item, just created.
SCH_SHEET * Last() const
Return a pointer to the last SCH_SHEET of the list.
Defines the structure of a menu based on ACTIONs.
Definition: action_menu.h:48
static TOOL_ACTION doDelete
Definition: actions.h:72
void SetIcon(BITMAPS aIcon)
Assign an icon for the entry.
Definition: action_menu.cpp:73
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...
EDA_RECT GetBoundingBox() const override
void AddToPreview(EDA_ITEM *aItem, bool aTakeOwnership=true)
Definition: view.cpp:1614
bool IsTerminalPoint(const wxPoint &aPosition, int aLayer) const
Test if aPosition is a connection point on aLayer.
Definition: sch_screen.cpp:545
static bool Idle(const SELECTION &aSelection)
Test if there no items selected or being edited.
std::vector< SCH_LINE * > m_wires
int AddJunctionsIfNeeded(const TOOL_EVENT &aEvent)
Handle the addition of junctions to a selection of objects.
CONDITIONAL_MENU & GetMenu()
Definition: tool_menu.cpp:46
static TOOL_ACTION placeHierLabel
Definition: ee_actions.h:88
TOOL_MANAGER * m_toolMgr
Definition: tool_base.h:214
static TOOL_ACTION placeJunction
Definition: ee_actions.h:84
static TOOL_ACTION selectConnection
If current selection is a wire or bus, expand to entire connection.
Definition: ee_actions.h:53
virtual void PushTool(const std::string &actionName)
NB: the definition of "tool" is different at the user level.
SCH_LINE * startSegments(int aType, const VECTOR2D &aPos)
static TOOL_ACTION unfoldBus
Definition: ee_actions.h:82
static TOOL_ACTION finishLineWireOrBus
Definition: ee_actions.h:94
void SetFlags(EDA_ITEM_FLAGS aMask)
Definition: eda_item.h:152
TOOL_MENU & GetToolMenu()
bool IsPointOnSegment(const wxPoint &aSegStart, const wxPoint &aSegEnd, const wxPoint &aTestPoint)
Test if aTestPoint is on line defined by aSegStart and aSegEnd.
Definition: trigo.cpp:42
bool RunAction(const std::string &aActionName, bool aNow=false, T aParam=NULL)
Run the specified action.
Definition: tool_manager.h:143
static bool IsDrawingLine(const SELECTION &aSelection)
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 PushItem(const ITEM_PICKER &aItem)
Push aItem to the top of the list.
Schematic editor (Eeschema) main window.
void SetTextSize(const wxSize &aNewSize)
Definition: eda_text.h:258
void SetContextMenu(ACTION_MENU *aMenu, CONTEXT_MENU_TRIGGER aTrigger=CMENU_BUTTON)
Assign a context menu and tells when it should be activated.
void update() override
Update menu state stub.
void setTransitions() override
This method is meant to be overridden in order to specify handlers for events.
int UnfoldBus(const TOOL_EVENT &aEvent)
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).
search types array terminator (End Of Types)
Definition: typeinfo.h:81
KICAD_T
The set of class identification values stored in EDA_ITEM::m_structType.
Definition: typeinfo.h:77
static const TOOL_EVENT SelectedItemsModified
Selected items were moved, this can be very high frequency on the canvas, use with care.
Definition: actions.h:205
virtual void SetParent(EDA_ITEM *aParent)
Definition: eda_item.h:115
static TOOL_ACTION breakWire
Definition: ee_actions.h:134
static TOOL_ACTION rotateCW
Definition: ee_actions.h:117
static TOOL_ACTION finishLine
Definition: ee_actions.h:97
void SetEndPoint(const wxPoint &aPosition)
Definition: sch_line.h:94
void SetTool(TOOL_INTERACTIVE *aTool)
Set a tool that is the creator of the menu.
bool IsNew() const
Definition: eda_item.h:118
const SCH_SHEET_PIN * getSheetPin(const wxPoint &aPosition)
Search for a sheet pin at a location.
SCH_JUNCTION * AddJunction(SCH_SCREEN *aScreen, const wxPoint &aPos, bool aAppendToUndo, bool aFinal=true)
bool Init() override
Init() is called once upon a registration of the tool.
void ShowPreview(bool aShow=true)
Definition: view.cpp:1628
static TOOL_ACTION leaveSheet
Definition: ee_actions.h:186
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:138
bool Init() override
Init() is called once upon a registration of the tool.
Definition: ee_tool_base.h:66
EE_SELECTION & GetSelection()
Return the set of currently selected items.
EESCHEMA_SETTINGS * eeconfig() const
EE_SELECTION & RequestSelection(const KICAD_T *aFilterList=EE_COLLECTOR::AllItems)
Return either an existing selection (filtered), or the selection at the current cursor if the existin...
SCH_SCREEN * GetScreen() const override
Return a pointer to a BASE_SCREEN or one of its derivatives.
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...
static TOOL_ACTION rotateCCW
Definition: ee_actions.h:118
static TOOL_ACTION trimOverlappingWires
Definition: ee_actions.h:76
EDA_ITEM * Clone() const override
Create a duplicate of this item with linked list members set to NULL.
Definition: sch_text.cpp:845
void Dismiss() override
Dismisses the infobar and updates the containing layout and AUI manager (if one is provided).
Definition: infobar.cpp:175
#define IS_MOVING
Item being moved.
wxPoint origin
Origin (on the bus) of the unfold.
SCH_ITEM * Duplicate(bool doClone=false) const
Routine to create a new copy of given item.
Definition: sch_item.cpp:85
VECTOR2< double > VECTOR2D
Definition: vector2d.h:621
void TestDanglingEnds()
Test all of the connectable objects in the schematic for unused connection points.
static TOOL_ACTION drawWire
Definition: ee_actions.h:80
SHEET_SIDE GetSide() const
virtual void PopTool(const std::string &actionName)
virtual void CaptureCursor(bool aEnabled)
Force the cursor to stay within the drawing panel area.
bool IsNull() const
Definition: sch_line.h:88
T Parameter() const
Return a non-standard parameter assigned to the event.
Definition: tool_event.h:432
void SetStartPoint(const wxPoint &aPosition)
Definition: sch_line.h:91
SCH_DRAW_PANEL * GetCanvas() const override
Return a pointer to GAL-based canvas of given EDA draw frame.
Generic, UI-independent tool event.
Definition: tool_event.h:152
void SaveCopyForRepeatItem(const SCH_ITEM *aItem)
Clone aItem and owns that clone in this container.
void ClearPreview()
Definition: view.cpp:1592
SCHEMATIC & Schematic() const
std::vector< wxPoint > GetSchematicConnections()
Collect a unique list of all possible connection points in the schematic.
An interface for classes handling user events controlling the view behavior such as zooming,...
#define _(s)
void UpdateItem(EDA_ITEM *aItem, bool isAddOrDelete=false, bool aUpdateRtree=false)
Mark an item for refresh.
EE_SELECTION_TOOL * m_selectionTool
Definition: ee_tool_base.h:179
virtual void ForceCursorPosition(bool aEnabled, const VECTOR2D &aPosition=VECTOR2D(0, 0))
Place the cursor immediately at a given point.
virtual bool IsType(const KICAD_T aScanTypes[]) const
Check whether the item is one of the listed types.
Definition: eda_item.h:182
Define a sheet pin (label) used in sheets to create hierarchical schematics.
Definition: sch_sheet_pin.h:65
bool DisableGridSnapping() const
Definition: tool_event.h:341
static TOOL_ACTION clearSelection
Clears the current selection.
Definition: ee_actions.h:56
virtual void SetCrossHairCursorPosition(const VECTOR2D &aPosition, bool aWarpView=true)=0
Move the graphic crosshair cursor to the requested position expressed in world coordinates.
A holder to handle information on schematic or board items.
static TOOL_ACTION addNeededJunctions
Definition: ee_actions.h:75
wxString net_name
Net label for the unfolding operation.
wxPoint GetPosition() const override
Definition: sch_text.h:241
int doDrawSegments(const std::string &aTool, int aType, bool aQuitOnDraw)
void computeBreakPoint(const std::pair< SCH_LINE *, SCH_LINE * > &aSegments, wxPoint &aPosition)
Compute the middle coordinate for 2 segments from the start point to aPosition with the segments kept...
TOOL_INTERACTIVE * m_tool
Associates tool actions with menu item IDs. Non-owning.
Definition: action_menu.h:266
KIGFX::VIEW * getView() const
Returns the instance of #VIEW object used in the application.
Definition: tool_base.cpp:36
virtual void SetAutoPan(bool aEnabled)
Turn on/off auto panning (this feature is used when there is a tool active (eg.
SCH_BUS_WIRE_ENTRY * entry
static bool IsDrawingBus(const SELECTION &aSelection)
static TOOL_ACTION drawBus
Definition: ee_actions.h:81
EE_TYPE Overlapping(const EDA_RECT &aRect) const
Definition: sch_rtree.h:235
Sheet symbol placed in a schematic, and is the entry point for a sub schematic.
Definition: sch_sheet.h:54
virtual void Rotate90(bool aClockwise)
Definition: sch_text.cpp:312
virtual unsigned int GetSize() const override
Return the number of stored items.
Definition: selection.h:88
SCH_LAYER_ID GetLayer() const
Return the layer this item is on.
Definition: sch_item.h:259
std::vector< SCH_SHEET_PIN * > & GetPins()
Definition: sch_sheet.h:183
int Modifier(int aMask=MD_MODIFIER_MASK) const
Definition: tool_event.h:336
static bool m_allowRealTime
bool IsExplicitJunctionNeeded(const wxPoint &aPosition) const
Indicates that a junction dot is necessary at the given location, and does not yet exist.
Definition: sch_screen.cpp:423
static TOOL_ACTION placeLabel
Definition: ee_actions.h:86
int RemoveItemFromSel(const TOOL_EVENT &aEvent)
OPT< std::string > GetCommandStr() const
Definition: tool_event.h:460
static bool IsDrawingLineWireOrBus(const SELECTION &aSelection)
TOOLS_HOLDER * GetToolHolder() const
Definition: tool_manager.h:294
int TrimOverLappingWires(const TOOL_EVENT &aEvent)
Logic to remove wires when overlapping correct items.
wxSize GetSize() const
Definition: sch_bus_entry.h:75
SCH_SHEET & Root() const
Definition: schematic.h:92
void SetTitle(const wxString &aTitle) override
Set title for the menu.
Definition: action_menu.cpp:87
#define SKIP_STRUCT
flag indicating that the structure should be ignored
int AddItemToSel(const TOOL_EVENT &aEvent)
const char * name
Definition: DXF_plotter.cpp:56
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,...
Segment description base class to describe items which have 2 end points (track, wire,...
Definition: sch_line.h:37
virtual KIGFX::VIEW_ITEM * GetItem(unsigned int aIdx) const override
Definition: selection.cpp:53
ACTION_MENU(bool isContextMenu, TOOL_INTERACTIVE *aTool=nullptr)
< Default constructor
Definition: action_menu.cpp:47
Each graphical item can have a SCH_CONNECTION describing its logical connection (to a bus or net).
void SaveCopyInUndoList(SCH_SCREEN *aScreen, SCH_ITEM *aItemToCopy, UNDO_REDO aTypeCommand, bool aAppend)
Create a copy of the current schematic item, and put it in the undo list.
ACTION_MENU * create() const override
< Return an instance of this class. It has to be overridden in inheriting classes.
TOOL_MANAGER * getToolManager() const
void AddSubMenu(std::shared_ptr< ACTION_MENU > aSubMenu)
Store a submenu of this menu model.
Definition: tool_menu.cpp:52
EE_RTREE & Items()
Gets the full RTree, usually for iterating.
Definition: sch_screen.h:110
static SELECTION_CONDITION OnlyType(KICAD_T aType)
Create a functor that tests if the selected items are only of given type.
void VetoContextMenuMouseWarp()
Disable mouse warping after the current context menu is closed.
Definition: tool_manager.h:422
Handle the component boundary box.
Definition: eda_rect.h:42
void Clear()
Remove all the entries from the menu (as well as its title).
static TOOL_ACTION selectNode
Select the junction, wire or bus segment under the cursor.
Definition: ee_actions.h:49
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:73
A base class for most all the KiCad significant classes used in schematics and boards.
Definition: eda_item.h:99
These settings were stored in SCH_BASE_FRAME previously.
boost::optional< T > OPT
Definition: optional.h:7
std::vector< std::shared_ptr< SCH_CONNECTION > > & Members()
Class for a wire to bus entry.
void Activate()
Run the tool.
WX_INFOBAR * GetInfoBar()
SCH_SHEET_PATH & GetCurrentSheet() const
bool TrimWire(const wxPoint &aStart, const wxPoint &aEnd)
If any single wire passes through both points, remove the portion between the two points,...
static const ADVANCED_CFG & GetCfg()
Get the singleton instance's config, which is shared by all consumers.
A foundation class for a tool operating on a schematic or symbol.
Definition: ee_tool_base.h:49
bool HasPosition() const
Definition: tool_event.h:240
SHEET_SIDE
Define the edge of the sheet that the sheet pin is positioned.
Definition: sch_sheet_pin.h:45
static TOOL_ACTION drawLines
Definition: ee_actions.h:92
void OnModify() override
Must be called after a schematic change in order to set the "modify" flag of the current screen and u...
bool label_placed
True if user has placed the net label.
KIGFX::VIEW_CONTROLS * getViewControls() const
Return the instance of VIEW_CONTROLS object used in the application.
Definition: tool_base.cpp:42
virtual void SetLabelSpinStyle(LABEL_SPIN_STYLE aSpinStyle)
Set a spin or rotation angle, along with specific horizontal and vertical justification styles with e...
Definition: sch_text.cpp:330
bool IsBus() const
static TOOL_ACTION placeGlobalLabel
Definition: ee_actions.h:87
void ClearEditFlags()
Definition: eda_item.h:171
static TOOL_ACTION finishBus
Definition: ee_actions.h:96
void SetPosition(const wxPoint &aPosition) override
Definition: sch_text.h:242
void PostEvent(const TOOL_EVENT &aEvent)
Put an event to the event queue to be processed at the end of event processing cycle.
bool flipX
True if the bus entry should be flipped in the x-axis.
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.
Base class for any item which can be embedded within the SCHEMATIC container class,...
Definition: sch_item.h:182
void ShowContextMenu(SELECTION &aSelection)
Helper function to set and immediately show a CONDITIONAL_MENU in concert with the given SELECTION.
Definition: tool_menu.cpp:59
int DrawSegments(const TOOL_EVENT &aEvent)
SCH_LINE * doUnfoldBus(const wxString &aNet, const wxPoint &aPos=wxDefaultPosition)
static TOOL_ACTION finishWire
Definition: ee_actions.h:95
const VECTOR2D Position() const
Returns the point where dragging has started.
Definition: tool_event.h:263
static TOOL_ACTION refreshPreview
Definition: actions.h:106
This item represents a bus vector.
EDA_ITEM * Front() const
Definition: selection.h:145
bool in_progress
True if bus unfold operation is running.
KICAD_T Type() const
Returns the type of object.
Definition: eda_item.h:112
wxPoint GetEnd() const
wxPoint GetEndPoint() const
Definition: sch_line.h:93