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 {
169  m_busUnfold = {};
170  m_wires.reserve( 16 );
171 }
172 
173 
175 {
176 }
177 
178 
180 {
182 
183  auto wireOrBusTool =
184  [this]( const SELECTION& aSel )
185  {
188  };
189 
190  auto lineTool =
191  [this]( const SELECTION& aSel )
192  {
194  };
195 
196  auto belowRootSheetCondition =
197  [&]( const SELECTION& aSel )
198  {
199  return m_frame->GetCurrentSheet().Last() != &m_frame->Schematic().Root();
200  };
201 
202  auto busSelection = EE_CONDITIONS::MoreThan( 0 )
204 
205  auto& ctxMenu = m_menu.GetMenu();
206 
207  // Build the tool menu
208  //
209  ctxMenu.AddItem( EE_ACTIONS::leaveSheet, belowRootSheetCondition, 2 );
210 
211  ctxMenu.AddSeparator( 10 );
212  ctxMenu.AddItem( EE_ACTIONS::drawWire, wireOrBusTool && EE_CONDITIONS::Idle, 10 );
213  ctxMenu.AddItem( EE_ACTIONS::drawBus, wireOrBusTool && EE_CONDITIONS::Idle, 10 );
214  ctxMenu.AddItem( EE_ACTIONS::drawLines, lineTool && EE_CONDITIONS::Idle, 10 );
215  ctxMenu.AddItem( EE_ACTIONS::finishWire, IsDrawingWire, 10 );
216  ctxMenu.AddItem( EE_ACTIONS::finishBus, IsDrawingBus, 10 );
217  ctxMenu.AddItem( EE_ACTIONS::finishLine, IsDrawingLine, 10 );
218 
219  std::shared_ptr<BUS_UNFOLD_MENU> busUnfoldMenu = std::make_shared<BUS_UNFOLD_MENU>();
220  busUnfoldMenu->SetTool( this );
221  m_menu.AddSubMenu( busUnfoldMenu );
222  ctxMenu.AddMenu( busUnfoldMenu.get(), EE_CONDITIONS::Idle, 10 );
223 
224  ctxMenu.AddSeparator( 100 );
225  ctxMenu.AddItem( EE_ACTIONS::placeJunction, wireOrBusTool && EE_CONDITIONS::Idle, 100 );
226  ctxMenu.AddItem( EE_ACTIONS::placeLabel, wireOrBusTool && EE_CONDITIONS::Idle, 100 );
227  ctxMenu.AddItem( EE_ACTIONS::placeGlobalLabel, wireOrBusTool && EE_CONDITIONS::Idle, 100 );
228  ctxMenu.AddItem( EE_ACTIONS::placeHierLabel, wireOrBusTool && EE_CONDITIONS::Idle, 100 );
229  ctxMenu.AddItem( EE_ACTIONS::breakWire, wireOrBusTool && EE_CONDITIONS::Idle, 100 );
230  ctxMenu.AddItem( EE_ACTIONS::breakBus, wireOrBusTool && EE_CONDITIONS::Idle, 100 );
231 
232  ctxMenu.AddSeparator( 200 );
233  ctxMenu.AddItem( EE_ACTIONS::selectNode, wireOrBusTool && EE_CONDITIONS::Idle, 200 );
234  ctxMenu.AddItem( EE_ACTIONS::selectConnection, wireOrBusTool && EE_CONDITIONS::Idle, 200 );
235 
236  // Add bus unfolding to the selection tool
237  //
239 
240  std::shared_ptr<BUS_UNFOLD_MENU> selBusUnfoldMenu = std::make_shared<BUS_UNFOLD_MENU>();
241  selBusUnfoldMenu->SetTool( m_selectionTool );
242  m_selectionTool->GetToolMenu().AddSubMenu( selBusUnfoldMenu );
243  selToolMenu.AddMenu( selBusUnfoldMenu.get(), busSelection && EE_CONDITIONS::Idle, 100 );
244 
245  return true;
246 }
247 
248 
250 {
251  static KICAD_T graphicLineType[] = { SCH_LINE_LOCATE_GRAPHIC_LINE_T, EOT };
252  return IsDrawingLineWireOrBus( aSelection ) && aSelection.Front()->IsType( graphicLineType );
253 }
254 
255 
257 {
258  static KICAD_T wireType[] = { SCH_LINE_LOCATE_WIRE_T, EOT };
259  return IsDrawingLineWireOrBus( aSelection ) && aSelection.Front()->IsType( wireType );
260 }
261 
262 
264 {
265  static KICAD_T busType[] = { SCH_LINE_LOCATE_BUS_T, EOT };
266  return IsDrawingLineWireOrBus( aSelection ) && aSelection.Front()->IsType( busType );
267 }
268 
269 
271 {
272  // NOTE: for immediate hotkeys, it is NOT required that the line, wire or bus tool
273  // be selected
274  SCH_ITEM* item = (SCH_ITEM*) aSelection.Front();
275  return item && item->IsNew() && item->Type() == SCH_LINE_T;
276 }
277 
278 
280 {
282 
283  std::string tool = aEvent.GetCommandStr().get();
284  m_frame->PushTool( tool );
286 
287  if( aEvent.HasPosition() )
288  {
290  grid.SetSnap( !aEvent.Modifier( MD_SHIFT ) );
291  grid.SetUseGrid( getView()->GetGAL()->GetGridSnapping() && !aEvent.DisableGridSnapping() );
292 
293  VECTOR2D cursorPos = grid.BestSnapAnchor( aEvent.Position(), LAYER_CONNECTABLE, nullptr );
294  startSegments( params->layer, cursorPos );
295  }
296 
297  return doDrawSegments( tool, params->layer, params->quitOnDraw );
298 }
299 
300 
302 {
303  wxString* netPtr = aEvent.Parameter<wxString*>();
304  wxString net;
305  SCH_LINE* segment = nullptr;
306 
307  std::string tool = aEvent.GetCommandStr().get();
308  m_frame->PushTool( tool );
309  Activate();
310 
311  if( netPtr )
312  {
313  net = *netPtr;
314  delete netPtr;
315  }
316  else
317  {
318  BUS_UNFOLD_MENU unfoldMenu;
319  unfoldMenu.SetTool( this );
320  unfoldMenu.SetShowTitle();
321 
322  SetContextMenu( &unfoldMenu, CMENU_NOW );
323 
324  while( TOOL_EVENT* evt = Wait() )
325  {
326  if( evt->Action() == TA_CHOICE_MENU_CHOICE )
327  {
328  OPT<int> id = evt->GetCommandId();
329 
330  if( id && ( *id > 0 ) )
331  net = *evt->Parameter<wxString*>();
332 
333  break;
334  }
335  else if( evt->Action() == TA_CHOICE_MENU_CLOSED )
336  {
337  break;
338  }
339  else
340  {
341  evt->SetPassEvent();
342  }
343  }
344  }
345 
346  // Break a wire for the given net out of the bus
347  if( !net.IsEmpty() )
348  segment = doUnfoldBus( net );
349 
350  // If we have an unfolded wire to draw, then draw it
351  if( segment )
352  return doDrawSegments( tool, LAYER_WIRE, false );
353  else
354  {
355  m_frame->PopTool( tool );
356  return 0;
357  }
358 }
359 
360 
361 SCH_LINE* SCH_LINE_WIRE_BUS_TOOL::doUnfoldBus( const wxString& aNet, const wxPoint& aPos )
362 {
363  SCHEMATIC_SETTINGS& cfg = getModel<SCHEMATIC>()->Settings();
364 
365  wxPoint pos = aPos;
366 
367  if( aPos == wxDefaultPosition )
368  pos = static_cast<wxPoint>( getViewControls()->GetCursorPosition() );
369 
371 
372  m_busUnfold.entry = new SCH_BUS_WIRE_ENTRY( pos );
375 
381 
382  m_busUnfold.in_progress = true;
383  m_busUnfold.origin = pos;
384  m_busUnfold.net_name = aNet;
385 
387 
389 }
390 
391 
392 const SCH_SHEET_PIN* SCH_LINE_WIRE_BUS_TOOL::getSheetPin( const wxPoint& aPosition )
393 {
394  SCH_SCREEN* screen = m_frame->GetScreen();
395 
396  for( SCH_ITEM* item : screen->Items().Overlapping( SCH_SHEET_T, aPosition ) )
397  {
398  SCH_SHEET* sheet = static_cast<SCH_SHEET*>( item );
399 
400  for( SCH_SHEET_PIN* pin : sheet->GetPins() )
401  {
402  if( pin->GetPosition() == aPosition )
403  return pin;
404  }
405  }
406 
407  return nullptr;
408 }
409 
410 
411 void SCH_LINE_WIRE_BUS_TOOL::computeBreakPoint( const std::pair<SCH_LINE*, SCH_LINE*>& aSegments,
412  wxPoint& aPosition )
413 {
414  wxCHECK_RET( aSegments.first && aSegments.second,
415  wxT( "Cannot compute break point of NULL line segment." ) );
416 
417  SCH_LINE* segment = aSegments.first;
418  SCH_LINE* next_segment = aSegments.second;
419 
420  wxPoint midPoint;
421  int iDx = segment->GetEndPoint().x - segment->GetStartPoint().x;
422  int iDy = segment->GetEndPoint().y - segment->GetStartPoint().y;
423 
424  const SCH_SHEET_PIN* connectedPin = getSheetPin( segment->GetStartPoint() );
425  SHEET_SIDE force = connectedPin ? connectedPin->GetEdge() : SHEET_SIDE::UNDEFINED;
426 
427  if( force == SHEET_SIDE::LEFT || force == SHEET_SIDE::RIGHT )
428  {
429  if( aPosition.x == connectedPin->GetPosition().x ) // push outside sheet boundary
430  {
431  int direction = ( force == SHEET_SIDE::LEFT ) ? -1 : 1;
432  aPosition.x += KiROUND( getView()->GetGAL()->GetGridSize().x * direction );
433  }
434 
435  midPoint.x = aPosition.x;
436  midPoint.y = segment->GetStartPoint().y; // force horizontal
437  }
438  else if( iDy != 0 ) // keep the first segment orientation (vertical)
439  {
440  midPoint.x = segment->GetStartPoint().x;
441  midPoint.y = aPosition.y;
442  }
443  else if( iDx != 0 ) // keep the first segment orientation (horizontal)
444  {
445  midPoint.x = aPosition.x;
446  midPoint.y = segment->GetStartPoint().y;
447  }
448  else
449  {
450  if( std::abs( aPosition.x - segment->GetStartPoint().x ) <
451  std::abs( aPosition.y - segment->GetStartPoint().y ) )
452  {
453  midPoint.x = segment->GetStartPoint().x;
454  midPoint.y = aPosition.y;
455  }
456  else
457  {
458  midPoint.x = aPosition.x;
459  midPoint.y = segment->GetStartPoint().y;
460  }
461  }
462 
463  segment->SetEndPoint( midPoint );
464  next_segment->SetStartPoint( midPoint );
465  next_segment->SetEndPoint( aPosition );
466 }
467 
468 
469 int SCH_LINE_WIRE_BUS_TOOL::doDrawSegments( const std::string& aTool, int aType, bool aQuitOnDraw )
470 {
471  SCH_SCREEN* screen = m_frame->GetScreen();
472  SCH_LINE* segment = nullptr;
475 
476  auto setCursor =
477  [&]()
478  {
479  if( aType == LAYER_WIRE )
481  else if( aType == LAYER_BUS )
483  else if( aType == LAYER_NOTES )
485  else
487  };
488 
489  auto cleanup =
490  [&] ()
491  {
493 
494  for( SCH_LINE* wire : m_wires )
495  delete wire;
496 
497  m_wires.clear();
498  segment = nullptr;
499 
500  if( m_busUnfold.entry )
502 
505 
508 
509  delete m_busUnfold.entry;
510  delete m_busUnfold.label;
511  m_busUnfold = {};
512 
513  m_view->ClearPreview();
514  m_view->ShowPreview( false );
515  };
516 
517  Activate();
518  // Must be done after Activate() so that it gets set into the correct context
519  controls->ShowCursor( true );
520  // Set initial cursor
521  setCursor();
522 
523  // Add the new label to the selection so the rotate command operates on it
524  if( m_busUnfold.label )
526 
527  // Continue the existing wires if we've started (usually by immediate action preference)
528  if( !m_wires.empty() )
529  segment = m_wires.back();
530 
531  wxPoint contextMenuPos;
532 
533  // Main loop: keep receiving events
534  while( TOOL_EVENT* evt = Wait() )
535  {
536  setCursor();
537  grid.SetMask( GRID_HELPER::ALL );
538  grid.SetSnap( !evt->Modifier( MD_SHIFT ) );
539  grid.SetUseGrid( getView()->GetGAL()->GetGridSnapping() && !evt->DisableGridSnapping() );
540 
541  if( segment )
542  {
543  if( segment->GetStartPoint().x == segment->GetEndPoint().x )
544  grid.ClearMaskFlag( GRID_HELPER::VERTICAL );
545 
546  if( segment->GetStartPoint().y == segment->GetEndPoint().y )
547  grid.ClearMaskFlag( GRID_HELPER::HORIZONTAL );
548  }
549 
550  wxPoint cursorPos = static_cast<wxPoint>( evt->HasPosition() ?
551  evt->Position() :
552  controls->GetMousePosition() );
553 
554  cursorPos = (wxPoint) grid.BestSnapAnchor( cursorPos, LAYER_CONNECTABLE, segment );
555  controls->ForceCursorPosition( true, cursorPos );
556 
557  bool forceHV = m_frame->eeconfig()->m_Drawing.hv_lines_only;
558 
559  //------------------------------------------------------------------------
560  // Handle cancel:
561  //
562  if( evt->IsCancelInteractive() )
563  {
564  if( segment || m_busUnfold.in_progress )
565  {
566  cleanup();
567  }
568  else
569  {
570  m_frame->PopTool( aTool );
571  break;
572  }
573  }
574  else if( evt->IsActivate() )
575  {
576  if( segment || m_busUnfold.in_progress )
577  {
578  m_frame->ShowInfoBarMsg( _( "Press <ESC> to cancel drawing." ) );
579  evt->SetPassEvent( false );
580  continue;
581  }
582 
583  if( evt->IsMoveTool() )
584  {
585  // leave ourselves on the stack so we come back after the move
586  break;
587  }
588  else
589  {
590  m_frame->PopTool( aTool );
591  break;
592  }
593  }
594  //------------------------------------------------------------------------
595  // Handle finish:
596  //
597  else if( evt->IsAction( &EE_ACTIONS::finishLineWireOrBus )
598  || evt->IsAction( &EE_ACTIONS::finishWire )
599  || evt->IsAction( &EE_ACTIONS::finishBus )
600  || evt->IsAction( &EE_ACTIONS::finishLine ) )
601  {
602  if( segment || m_busUnfold.in_progress )
603  {
604  finishSegments();
605  segment = nullptr;
606 
607  if( aQuitOnDraw )
608  {
609  m_frame->PopTool( aTool );
610  break;
611  }
612  }
613  }
614  //------------------------------------------------------------------------
615  // Handle click:
616  //
617  else if( evt->IsClick( BUT_LEFT ) || ( segment && evt->IsDblClick( BUT_LEFT ) ) )
618  {
619  // First click when unfolding places the label and wire-to-bus entry
621  {
622  wxASSERT( aType == LAYER_WIRE );
623 
624  m_frame->AddToScreen( m_busUnfold.label, screen );
626  m_busUnfold.label_placed = true;
627  }
628 
629  if( !segment )
630  {
631  segment = startSegments( aType, VECTOR2D( cursorPos ) );
632  }
633  // Create a new segment if we're out of previously-created ones
634  else if( !segment->IsNull() || ( forceHV && !m_wires[ m_wires.size() - 2 ]->IsNull() ) )
635  {
636  // Terminate the command if the end point is on a pin, junction, label, or another
637  // wire or bus.
638  if( screen->IsTerminalPoint( cursorPos, segment->GetLayer() ) )
639  {
640  finishSegments();
641  segment = nullptr;
642 
643  if( aQuitOnDraw )
644  {
645  m_frame->PopTool( aTool );
646  break;
647  }
648  }
649  else
650  {
651  segment->SetEndPoint( cursorPos );
652 
653  // Create a new segment, and chain it after the current segment.
654  segment = new SCH_LINE( *segment );
655  segment->SetFlags( IS_NEW | IS_MOVING );
656  segment->SetStartPoint( cursorPos );
657  m_wires.push_back( segment );
658 
659  m_selectionTool->AddItemToSel( segment, true /*quiet mode*/ );
660  }
661  }
662 
663  if( evt->IsDblClick( BUT_LEFT ) && segment )
664  {
665  if( forceHV && m_wires.size() >= 2 )
666  computeBreakPoint( { m_wires[ m_wires.size() - 2 ], segment }, cursorPos );
667 
668  finishSegments();
669  segment = nullptr;
670 
671  if( aQuitOnDraw )
672  {
673  m_frame->PopTool( aTool );
674  break;
675  }
676  }
677  }
678  //------------------------------------------------------------------------
679  // Handle motion:
680  //
681  else if( evt->IsMotion() || evt->IsAction( &ACTIONS::refreshPreview ) )
682  {
683  m_view->ClearPreview();
684 
685  // Update the bus unfold posture based on the mouse movement
687  {
688  wxPoint cursor_delta = cursorPos - m_busUnfold.origin;
690 
691  bool flipX = ( cursor_delta.x < 0 );
692  bool flipY = ( cursor_delta.y < 0 );
693 
694  // Erase and redraw if necessary
695  if( flipX != m_busUnfold.flipX || flipY != m_busUnfold.flipY )
696  {
697  wxSize size = entry->GetSize();
698  int ySign = flipY ? -1 : 1;
699  int xSign = flipX ? -1 : 1;
700 
701  size.x = std::abs( size.x ) * xSign;
702  size.y = std::abs( size.y ) * ySign;
703  entry->SetSize( size );
704 
705  m_busUnfold.flipY = flipY;
706  m_busUnfold.flipX = flipX;
707 
708  m_frame->UpdateItem( entry );
709  m_wires.front()->SetStartPoint( entry->GetEnd() );
710  }
711 
712  // Update the label "ghost" position
713  m_busUnfold.label->SetPosition( cursorPos );
715 
716  // Ensure segment is non-null at the start of bus unfold
717  if( !segment )
718  segment = m_wires.back();
719  }
720 
721  if( segment )
722  {
723  // Coerce the line to vertical or horizontal if necessary
724  if( forceHV && m_wires.size() >= 2 )
725  computeBreakPoint( { m_wires[ m_wires.size() - 2 ], segment }, cursorPos );
726  else
727  segment->SetEndPoint( cursorPos );
728  }
729 
730  for( SCH_LINE* wire : m_wires )
731  {
732  if( !wire->IsNull() )
733  m_view->AddToPreview( wire->Clone() );
734  }
735  }
736  //------------------------------------------------------------------------
737  // Handle context menu:
738  //
739  else if( evt->IsClick( BUT_RIGHT ) )
740  {
741  // Warp after context menu only if dragging...
742  if( !segment )
744 
745  contextMenuPos = cursorPos;
747  }
748  else if( evt->Category() == TC_COMMAND && evt->Action() == TA_CHOICE_MENU_CHOICE )
749  {
750  if( evt->GetCommandId().get() >= ID_POPUP_SCH_UNFOLD_BUS
751  && evt->GetCommandId().get() <= ID_POPUP_SCH_UNFOLD_BUS_END )
752  {
753  wxASSERT_MSG( !segment, "Bus unfold event received when already drawing!" );
754 
755  aType = LAYER_WIRE;
756  wxString net = *evt->Parameter<wxString*>();
757  segment = doUnfoldBus( net, contextMenuPos );
758  }
759  }
760  else if( evt->IsAction( &EE_ACTIONS::rotateCW ) || evt->IsAction( &EE_ACTIONS::rotateCCW ) )
761  {
763  {
764  m_busUnfold.label->Rotate90( evt->IsAction( &EE_ACTIONS::rotateCW ) );
766  }
767  else
768  {
769  wxBell();
770  }
771  }
772  else if( evt->IsAction( &ACTIONS::doDelete ) && ( segment || m_busUnfold.in_progress ) )
773  {
774  cleanup();
775  }
776  else
777  {
778  evt->SetPassEvent();
779  }
780 
781  // Enable autopanning and cursor capture only when there is a segment to be placed
782  controls->SetAutoPan( segment != nullptr );
783  controls->CaptureCursor( segment != nullptr );
784  }
785 
786  controls->SetAutoPan( false );
787  controls->CaptureCursor( false );
789  controls->ForceCursorPosition( false );
790  return 0;
791 }
792 
793 
795 {
796  SCH_LINE* segment = nullptr;
797 
798  switch ( aType )
799  {
800  default: segment = new SCH_LINE( aPos, LAYER_NOTES ); break;
801  case LAYER_WIRE: segment = new SCH_LINE( aPos, LAYER_WIRE ); break;
802  case LAYER_BUS: segment = new SCH_LINE( aPos, LAYER_BUS ); break;
803  }
804 
805  // Give segments a parent so they find the default line/wire/bus widths
806  segment->SetParent( &m_frame->Schematic() );
807  segment->SetFlags( IS_NEW | IS_MOVING );
808  m_wires.push_back( segment );
809 
810  m_selectionTool->AddItemToSel( segment, true /*quiet mode*/ );
811 
812  // We need 2 segments to go from a given start pin to an end point when the
813  // horizontal and vertical lines only switch is on.
815  {
816  segment = new SCH_LINE( *segment );
817  segment->SetFlags( IS_NEW | IS_MOVING );
818  m_wires.push_back( segment );
819 
820  m_selectionTool->AddItemToSel( segment, true /*quiet mode*/ );
821  }
822 
823  return segment;
824 }
825 
826 
841 {
842  for( auto it = m_wires.begin(); it != m_wires.end(); )
843  {
844  SCH_LINE* line = *it;
845 
846  if( line->IsNull() )
847  {
848  delete line;
849  it = m_wires.erase( it );
850  continue;
851  }
852 
853  auto next_it = it;
854  ++next_it;
855 
856  if( next_it == m_wires.end() )
857  break;
858 
859  SCH_LINE* next_line = *next_it;
860 
861  if( SCH_LINE* merged = line->MergeOverlap( m_frame->GetScreen(), next_line, false ) )
862  {
863  delete line;
864  delete next_line;
865  it = m_wires.erase( it );
866  *it = merged;
867  }
868 
869  ++it;
870  }
871 }
872 
873 
875 {
876  // Clear selection when done so that a new wire can be started.
877  // NOTE: this must be done before simplifyWireList is called or we might end up with
878  // freed selected items.
880 
881  SCH_SCREEN* screen = m_frame->GetScreen();
882  PICKED_ITEMS_LIST itemList;
883 
884  // Remove segments backtracking over others
886 
887  // Collect the possible connection points for the new lines
888  std::vector< wxPoint > connections = m_frame->GetSchematicConnections();
889  std::vector< wxPoint > new_ends;
890 
891  // Check each new segment for possible junctions and add/split if needed
892  for( SCH_LINE* wire : m_wires )
893  {
894  if( wire->HasFlag( SKIP_STRUCT ) )
895  continue;
896 
897  std::vector<wxPoint> tmpends = wire->GetConnectionPoints();
898 
899  new_ends.insert( new_ends.end(), tmpends.begin(), tmpends.end() );
900 
901  for( const wxPoint& pt : connections )
902  {
903  if( IsPointOnSegment( wire->GetStartPoint(), wire->GetEndPoint(), pt ) )
904  new_ends.push_back( pt );
905  }
906  itemList.PushItem( ITEM_PICKER( screen, wire, UNDO_REDO::NEWITEM ) );
907  }
908 
910  {
911  wxASSERT( m_busUnfold.entry && m_busUnfold.label );
912 
913  itemList.PushItem( ITEM_PICKER( screen, m_busUnfold.entry, UNDO_REDO::NEWITEM ) );
914  itemList.PushItem( ITEM_PICKER( screen, m_busUnfold.label, UNDO_REDO::NEWITEM ) );
916  }
917 
918  // Get the last non-null wire (this is the last created segment).
919  if( !m_wires.empty() )
921 
922  // Add the new wires
923  for( SCH_LINE* wire : m_wires )
924  {
925  wire->ClearFlags( IS_NEW | IS_MOVING );
926  m_frame->AddToScreen( wire, screen );
927  }
928 
929  m_wires.clear();
930  m_view->ClearPreview();
931  m_view->ShowPreview( false );
932 
933  getViewControls()->CaptureCursor( false );
934  getViewControls()->SetAutoPan( false );
935 
936  m_frame->SaveCopyInUndoList( itemList, UNDO_REDO::NEWITEM, false );
937 
938  // Correct and remove segments that need to be merged.
940 
941  std::vector<SCH_ITEM*> symbols;
942 
943  for( SCH_ITEM* symbol : m_frame->GetScreen()->Items().OfType( SCH_SYMBOL_T ) )
944  symbols.push_back( symbol );
945 
946  for( SCH_ITEM* symbol : symbols )
947  {
948  std::vector<wxPoint> pts = symbol->GetConnectionPoints();
949 
950  if( pts.size() > 2 )
951  continue;
952 
953  for( auto pt = pts.begin(); pt != pts.end(); pt++ )
954  {
955  for( auto secondPt = pt + 1; secondPt != pts.end(); secondPt++ )
956  m_frame->TrimWire( *pt, *secondPt );
957  }
958  }
959 
960  for( const wxPoint& pt : new_ends )
961  {
962  if( m_frame->GetScreen()->IsJunctionNeeded( pt, true ) )
963  m_frame->AddJunction( m_frame->GetScreen(), pt, true, false );
964  }
965 
967  m_busUnfold = {};
968 
971 
972  m_frame->OnModify();
973 }
974 
975 
977 {
978  EE_SELECTION* aSelection = aEvent.Parameter<EE_SELECTION*>();
979 
980  std::vector<wxPoint> pts;
981  std::vector<wxPoint> connections = m_frame->GetSchematicConnections();
982 
983  for( unsigned ii = 0; ii < aSelection->GetSize(); ii++ )
984  {
985  SCH_ITEM* item = dynamic_cast<SCH_ITEM*>( aSelection->GetItem( ii ) );
986 
987  if( !item || !item->IsConnectable() )
988  continue;
989 
990  std::vector<wxPoint> new_pts = item->GetConnectionPoints();
991  pts.insert( pts.end(), new_pts.begin(), new_pts.end() );
992 
993  // If the item is a line, we also add any connection points from the rest of the schematic
994  // that terminate on the line after it is moved.
995  if( item->Type() == SCH_LINE_T )
996  {
997  SCH_LINE* line = (SCH_LINE*) item;
998 
999  for( const wxPoint& pt : connections )
1000  {
1001  if( IsPointOnSegment( line->GetStartPoint(), line->GetEndPoint(), pt ) )
1002  pts.push_back( pt );
1003  }
1004  }
1005  else
1006  {
1007  // Clean up any wires that short non-wire connections in the list
1008  for( auto pt = new_pts.begin(); pt != new_pts.end(); pt++ )
1009  {
1010  for( auto secondPt = pt + 1; secondPt != new_pts.end(); secondPt++ )
1011  m_frame->TrimWire( *pt, *secondPt );
1012  }
1013  }
1014  }
1015 
1016  // We always have some overlapping connection points. Drop duplicates here
1017  std::sort( pts.begin(), pts.end(),
1018  []( const wxPoint& a, const wxPoint& b ) -> bool
1019  {
1020  return a.x < b.x || ( a.x == b.x && a.y < b.y );
1021  } );
1022 
1023  pts.erase( unique( pts.begin(), pts.end() ), pts.end() );
1024 
1025  for( const wxPoint& point : pts )
1026  {
1027  if( m_frame->GetScreen()->IsJunctionNeeded( point, true ) )
1028  m_frame->AddJunction( m_frame->GetScreen(), point, true, false );
1029  }
1030 
1031  return 0;
1032 }
1033 
1034 
1036 {
1041 
1043 }
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:216
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:453
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:358
void UpdateItem(EDA_ITEM *aItem, bool isAddOrDelete=false)
Mark an item for refresh.
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:373
static TOOL_ACTION breakBus
Definition: ee_actions.h:131
void RecalculateConnections(SCH_CLEANUP_FLAGS aCleanupFlags)
Generate the connection data for the entire schematic hierarchy.
wxPoint GetStartPoint() const
Definition: sch_line.h:90
void SetSize(const wxSize &aSize)
Definition: sch_bus_entry.h:64
#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...
void AddToPreview(EDA_ITEM *aItem, bool aTakeOwnership=true)
Definition: view.cpp:1562
bool IsTerminalPoint(const wxPoint &aPosition, int aLayer) const
Test if aPosition is a connection point on aLayer.
Definition: sch_screen.cpp:484
static bool Idle(const SELECTION &aSelection)
Test if there no items selected or being edited.
std::vector< SCH_LINE * > m_wires
Storage for the line segments while drawing.
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:84
TOOL_MANAGER * m_toolMgr
Definition: tool_base.h:214
static TOOL_ACTION placeJunction
Definition: ee_actions.h:80
static TOOL_ACTION selectConnection
If current selection is a wire or bus, expand to entire connection.
Definition: ee_actions.h:50
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:78
static TOOL_ACTION finishLineWireOrBus
Definition: ee_actions.h:90
void SetFlags(EDA_ITEM_FLAGS aMask)
Definition: eda_item.h:153
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.
SHEET_SIDE GetEdge() const
Schematic editor (Eeschema) main window.
void SetTextSize(const wxSize &aNewSize)
Definition: eda_text.h:237
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:204
virtual void SetParent(EDA_ITEM *aParent)
Definition: eda_item.h:116
static TOOL_ACTION breakWire
Definition: ee_actions.h:130
static TOOL_ACTION rotateCW
Definition: ee_actions.h:113
static TOOL_ACTION finishLine
Definition: ee_actions.h:93
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:119
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:1576
static TOOL_ACTION leaveSheet
Definition: ee_actions.h:181
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:131
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:114
EDA_ITEM * Clone() const override
Create a duplicate of this item with linked list members set to NULL.
Definition: sch_text.cpp:844
#define IS_MOVING
Item being moved.
wxPoint origin
Origin (on the bus) of the unfold.
VECTOR2< double > VECTOR2D
Definition: vector2d.h:622
void TestDanglingEnds()
Test all of the connectable objects in the schematic for unused connection points.
static TOOL_ACTION drawWire
Definition: ee_actions.h:76
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:1540
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)
EE_SELECTION_TOOL * m_selectionTool
Definition: ee_tool_base.h:177
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:183
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:53
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:72
wxString net_name
Net label for the unfolding operation.
wxPoint GetPosition() const override
Definition: sch_text.h:239
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:260
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:77
EE_TYPE Overlapping(const EDA_RECT &aRect) const
Definition: sch_rtree.h:221
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:301
virtual unsigned int GetSize() const override
Return the number of stored items.
Definition: selection.h:87
SCH_LAYER_ID GetLayer() const
Return the layer this item is on.
Definition: sch_item.h:268
std::vector< SCH_SHEET_PIN * > & GetPins()
Definition: sch_sheet.h:184
int Modifier(int aMask=MD_MODIFIER_MASK) const
Definition: tool_event.h:336
static bool m_allowRealTime
static TOOL_ACTION placeLabel
Definition: ee_actions.h:82
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
wxSize GetSize() const
Definition: sch_bus_entry.h:63
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:52
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
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:46
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
These settings were stored in SCH_BASE_FRAME previously.
bool IsJunctionNeeded(const wxPoint &aPosition, bool aNew=false) const
Test if a junction is required for the items at aPosition on the screen.
Definition: sch_screen.cpp:401
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.
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:88
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:319
bool IsBus() const
static TOOL_ACTION placeGlobalLabel
Definition: ee_actions.h:83
void ClearEditFlags()
Definition: eda_item.h:172
static TOOL_ACTION finishBus
Definition: ee_actions.h:92
void SetPosition(const wxPoint &aPosition) override
Definition: sch_text.h:240
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:193
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:91
const VECTOR2D Position() const
Returns the point where dragging has started.
Definition: tool_event.h:263
BUS_UNFOLDING_T m_busUnfold
Data related to bus unfolding tool.
static TOOL_ACTION refreshPreview
Definition: actions.h:106
This item represents a bus vector.
EDA_ITEM * Front() const
Definition: selection.h:144
bool in_progress
True if bus unfold operation is running.
KICAD_T Type() const
Returns the type of object.
Definition: eda_item.h:113
wxPoint GetEnd() const
wxPoint GetEndPoint() const
Definition: sch_line.h:93