KiCad PCB EDA Suite
sch_drawing_tools.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-2020 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_drawing_tools.h"
26 #include "ee_selection_tool.h"
27 #include "ee_point_editor.h"
28 #include <ee_actions.h>
29 #include <sch_edit_frame.h>
30 #include <project.h>
31 #include <id.h>
32 #include <eeschema_id.h>
33 #include <confirm.h>
34 #include <view/view_controls.h>
35 #include <view/view.h>
36 #include <sch_component.h>
37 #include <sch_no_connect.h>
38 #include <sch_line.h>
39 #include <sch_junction.h>
40 #include <sch_bus_entry.h>
41 #include <sch_text.h>
42 #include <sch_sheet.h>
43 #include <sch_bitmap.h>
44 #include <schematic.h>
45 #include <class_library.h>
46 #include <eeschema_settings.h>
48 
50  EE_TOOL_BASE<SCH_EDIT_FRAME>( "eeschema.InteractiveDrawing" ),
51  m_lastGlobalLabelShape( PINSHEETLABEL_SHAPE::PS_INPUT ),
52  m_lastTextOrientation( LABEL_SPIN_STYLE::LEFT ),
53  m_lastTextBold( false ),
54  m_lastTextItalic( false )
55 {
56 }
57 
58 
60 {
62 
63  auto belowRootSheetCondition =
64  [&]( const SELECTION& aSel )
65  {
66  return m_frame->GetCurrentSheet().Last() != &m_frame->Schematic().Root();
67  };
68 
69  auto& ctxMenu = m_menu.GetMenu();
70  ctxMenu.AddItem( EE_ACTIONS::leaveSheet, belowRootSheetCondition, 2 );
71 
72  return true;
73 }
74 
75 
77 {
78  SCH_COMPONENT* component = aEvent.Parameter<SCH_COMPONENT*>();
79  SCHLIB_FILTER filter;
80  std::vector<COMPONENT_SELECTION>* historyList = nullptr;
81 
82  if( aEvent.IsAction( &EE_ACTIONS::placeSymbol ) )
83  historyList = &m_symbolHistoryList;
84  else if (aEvent.IsAction( &EE_ACTIONS::placePower ) )
85  {
86  historyList = &m_powerHistoryList;
87  filter.FilterPowerParts( true );
88  }
89  else
90  wxFAIL_MSG( "PlaceCompontent(): unexpected request" );
91 
92  getViewControls()->ShowCursor( true );
93 
94  // If a component was passed in get it ready for placement.
95  if( component )
96  {
97  component->SetFlags( IS_NEW | IS_MOVED );
98 
100  m_selectionTool->AddItemToSel( component );
101  }
102 
103  std::string tool = aEvent.GetCommandStr().get();
104  m_frame->PushTool( tool );
105  Activate();
106 
107  // Prime the pump
108  if( component )
109  {
110  getViewControls()->WarpCursor( getViewControls()->GetMousePosition( false ) );
112  }
113  else if( aEvent.HasPosition() )
115 
116  // Main loop: keep receiving events
117  while( TOOL_EVENT* evt = Wait() )
118  {
119  m_frame->GetCanvas()->SetCurrentCursor( component ? wxCURSOR_ARROW : wxCURSOR_PENCIL );
120  VECTOR2I cursorPos = getViewControls()->GetCursorPosition( !evt->Modifier( MD_ALT ) );
121 
122  auto cleanup = [&] () {
124  m_view->ClearPreview();
125  delete component;
126  component = nullptr;
127  };
128 
129  if( evt->IsCancelInteractive() )
130  {
131  if( component )
132  cleanup();
133  else
134  {
135  m_frame->PopTool( tool );
136  break;
137  }
138  }
139  else if( evt->IsActivate() )
140  {
141  if( component )
142  cleanup();
143 
144  if( evt->IsMoveTool() )
145  {
146  // leave ourselves on the stack so we come back after the move
147  break;
148  }
149  else
150  {
151  m_frame->PopTool( tool );
152  break;
153  }
154  }
155  else if( evt->IsClick( BUT_LEFT ) )
156  {
157  if( !component )
158  {
160 
161  // Pick the module to be placed
162  bool footprintPreviews = m_frame->eeconfig()->m_Appearance.footprint_preview;
163  COMPONENT_SELECTION sel = m_frame->SelectCompFromLibTree( &filter, *historyList,
164  true, 1, 1,
165  footprintPreviews );
166 
167  // Restore cursor after dialog
168  getViewControls()->WarpCursor( getViewControls()->GetCursorPosition(), true );
169 
170  LIB_PART* part = sel.LibId.IsValid() ? m_frame->GetLibPart( sel.LibId ) : nullptr;
171 
172  if( !part )
173  continue;
174 
175  component = new SCH_COMPONENT(
176  *part, &m_frame->GetCurrentSheet(), sel, (wxPoint) cursorPos );
177  component->SetParent( m_frame->GetCurrentSheet().LastScreen() );
178  component->SetFlags( IS_NEW | IS_MOVED );
179 
181  component->AutoplaceFields( /* aScreen */ NULL, /* aManual */ false );
182 
183  m_frame->SaveCopyForRepeatItem( component );
184 
185  m_view->ClearPreview();
186  m_view->AddToPreview( component->Clone() );
187  m_selectionTool->AddItemToSel( component );
188  }
189  else
190  {
191  SCH_COMPONENT* next_comp = nullptr;
192 
193  m_view->ClearPreview();
194  m_frame->AddItemToScreenAndUndoList( m_frame->GetScreen(), component, false );
195 
196  EE_SELECTION new_sel;
197  new_sel.Add( component );
198 
200  m_frame->OnModify();
201 
204  {
205  int new_unit = component->GetUnit();
206 
208  && component->GetUnit() < component->GetUnitCount() )
209  new_unit++;
210  else
211  new_unit = 1;
212 
213  // We are either stepping to the next unit or next component
214  if( m_frame->eeconfig()->m_SymChooserPanel.keep_symbol || new_unit > 1 )
215  {
216  // Deselect the last placed symbol: obviously we do not want to
217  // apply some changes (like rotation, mirror...) to previously placed
218  // symbols.
220 
221  next_comp = static_cast<SCH_COMPONENT*>( component->Duplicate() );
222  next_comp->SetFlags( IS_NEW | IS_MOVED );
223  next_comp->SetUnit( new_unit );
224  next_comp->SetUnitSelection( &m_frame->GetCurrentSheet(), new_unit );
225 
227  component->AutoplaceFields( /* aScreen */ NULL, /* aManual */ false );
228 
229  m_frame->SaveCopyForRepeatItem( next_comp );
230  m_view->AddToPreview( next_comp->Clone() );
231  m_selectionTool->AddItemToSel( next_comp );
232  }
233  }
234 
235  component = next_comp;
236  }
237  }
238  else if( evt->IsClick( BUT_RIGHT ) )
239  {
240  // Warp after context menu only if dragging...
241  if( !component )
243 
245  }
246  else if( evt->Category() == TC_COMMAND && evt->Action() == TA_CHOICE_MENU_CHOICE )
247  {
248  if( evt->GetCommandId().get() >= ID_POPUP_SCH_SELECT_UNIT_CMP
249  && evt->GetCommandId().get() <= ID_POPUP_SCH_SELECT_UNIT_CMP_MAX )
250  {
251  int unit = evt->GetCommandId().get() - ID_POPUP_SCH_SELECT_UNIT_CMP;
252 
253  if( component )
254  {
255  m_frame->SelectUnit( component, unit );
257  }
258  }
259  }
260  else if( component && ( evt->IsAction( &ACTIONS::refreshPreview ) || evt->IsMotion() ) )
261  {
262  component->SetPosition( (wxPoint)cursorPos );
263  m_view->ClearPreview();
264  m_view->AddToPreview( component->Clone() );
265  }
266  else
267  evt->SetPassEvent();
268 
269  // Enable autopanning and cursor capture only when there is a module to be placed
270  getViewControls()->SetAutoPan( component != nullptr );
271  getViewControls()->CaptureCursor( component != nullptr );
272  }
273 
274  return 0;
275 }
276 
277 
279 {
280  SCH_BITMAP* image = aEvent.Parameter<SCH_BITMAP*>();
281  bool immediateMode = image;
282  VECTOR2I cursorPos = getViewControls()->GetCursorPosition();
283 
285  getViewControls()->ShowCursor( true );
286 
287  // Add all the drawable parts to preview
288  if( image )
289  {
290  image->SetPosition( (wxPoint)cursorPos );
291  m_view->ClearPreview();
292  m_view->AddToPreview( image->Clone() );
293  }
294 
295  std::string tool = aEvent.GetCommandStr().get();
296  m_frame->PushTool( tool );
297  Activate();
298 
299  // Prime the pump
300  if( image )
302  else if( aEvent.HasPosition() )
304 
305  // Main loop: keep receiving events
306  while( TOOL_EVENT* evt = Wait() )
307  {
308  m_frame->GetCanvas()->SetCurrentCursor( image ? wxCURSOR_ARROW : wxCURSOR_PENCIL );
309  cursorPos = getViewControls()->GetCursorPosition( !evt->Modifier( MD_ALT ) );
310 
311  auto cleanup = [&] () {
313  m_view->ClearPreview();
314  delete image;
315  image = nullptr;
316  };
317 
318  if( evt->IsCancelInteractive() )
319  {
320  if( image )
321  cleanup();
322  else
323  {
324  m_frame->PopTool( tool );
325  break;
326  }
327 
328  if( immediateMode )
329  {
330  m_frame->PopTool( tool );
331  break;
332  }
333  }
334  else if( evt->IsActivate() )
335  {
336  if( image )
337  cleanup();
338 
339  if( evt->IsMoveTool() )
340  {
341  // leave ourselves on the stack so we come back after the move
342  break;
343  }
344  else
345  {
346  m_frame->PopTool( tool );
347  break;
348  }
349  }
350  else if( evt->IsClick( BUT_LEFT ) )
351  {
352  if( !image )
353  {
355  wxFileDialog dlg( m_frame, _( "Choose Image" ), wxEmptyString, wxEmptyString,
356  _( "Image Files " ) + wxImage::GetImageExtWildcard(), wxFD_OPEN );
357 
358  if( dlg.ShowModal() != wxID_OK )
359  continue;
360 
361  // Restore cursor after dialog
362  getViewControls()->WarpCursor( getViewControls()->GetCursorPosition(), true );
363 
364  wxString fullFilename = dlg.GetPath();
365 
366  if( wxFileExists( fullFilename ) )
367  image = new SCH_BITMAP( (wxPoint)cursorPos );
368 
369  if( !image || !image->ReadImageFile( fullFilename ) )
370  {
371  wxMessageBox( _( "Couldn't load image from \"%s\"" ), fullFilename );
372  delete image;
373  image = nullptr;
374  continue;
375  }
376 
377  image->SetFlags( IS_NEW | IS_MOVED );
378 
379  m_frame->SaveCopyForRepeatItem( image );
380 
381  m_view->ClearPreview();
382  m_view->AddToPreview( image->Clone() );
383  m_view->RecacheAllItems(); // Bitmaps are cached in Opengl
384 
385  m_selectionTool->AddItemToSel( image );
386 
387  getViewControls()->SetCursorPosition( cursorPos, false );
388  }
389  else
390  {
392  image = nullptr;
394 
395  m_view->ClearPreview();
396 
397  if( immediateMode )
398  {
399  m_frame->PopTool( tool );
400  break;
401  }
402  }
403  }
404  else if( evt->IsClick( BUT_RIGHT ) )
405  {
406  // Warp after context menu only if dragging...
407  if( !image )
409 
411  }
412  else if( image && ( evt->IsAction( &ACTIONS::refreshPreview ) || evt->IsMotion() ) )
413  {
414  image->SetPosition( (wxPoint)cursorPos );
415  m_view->ClearPreview();
416  m_view->AddToPreview( image->Clone() );
417  m_view->RecacheAllItems(); // Bitmaps are cached in Opengl
418  }
419  else
420  evt->SetPassEvent();
421 
422  // Enable autopanning and cursor capture only when there is a module to be placed
423  getViewControls()->SetAutoPan( image != nullptr );
424  getViewControls()->CaptureCursor( image != nullptr );
425  }
426 
427  return 0;
428 }
429 
430 
432 {
433  wxPoint cursorPos;
434  KICAD_T type = aEvent.Parameter<KICAD_T>();
435 
436  if( type == SCH_JUNCTION_T && aEvent.HasPosition() )
437  {
438  EE_SELECTION& selection = m_selectionTool->GetSelection();
439  SCH_LINE* wire = dynamic_cast<SCH_LINE*>( selection.Front() );
440 
441  if( wire )
442  {
443  SEG seg( wire->GetStartPoint(), wire->GetEndPoint() );
444  VECTOR2I nearest = seg.NearestPoint( getViewControls()->GetCursorPosition() );
445  getViewControls()->SetCrossHairCursorPosition( nearest, false );
446  getViewControls()->WarpCursor( getViewControls()->GetCursorPosition(), true );
447  }
448  }
449 
451  getViewControls()->ShowCursor( true );
452 
453  SCH_ITEM* previewItem;
454  switch( type )
455  {
456  case SCH_NO_CONNECT_T:
457  previewItem = new SCH_NO_CONNECT( cursorPos );
458  break;
459  case SCH_JUNCTION_T:
460  previewItem = new SCH_JUNCTION( cursorPos );
461  break;
463  previewItem = new SCH_BUS_WIRE_ENTRY( cursorPos );
464  break;
465  default:
466  wxASSERT_MSG( false, "Unknown item type in SCH_DRAWING_TOOLS::SingleClickPlace" );
467  return 0;
468  }
469 
470  previewItem->SetParent( m_frame->GetScreen() );
471 
472  m_view->ClearPreview();
473  m_view->AddToPreview( previewItem->Clone() );
474 
475  std::string tool = aEvent.GetCommandStr().get();
476  m_frame->PushTool( tool );
477  Activate();
478 
479  // Prime the pump
480  if( aEvent.HasPosition() )
482 
483  // Main loop: keep receiving events
484  while( TOOL_EVENT* evt = Wait() )
485  {
486  m_frame->GetCanvas()->SetCurrentCursor( wxCURSOR_ARROW );
487  cursorPos = (wxPoint) getViewControls()->GetCursorPosition( !evt->Modifier( MD_ALT ) );
488 
489  if( evt->IsCancelInteractive() )
490  {
491  m_frame->PopTool( tool );
492  break;
493  }
494  else if( evt->IsActivate() )
495  {
496  if( evt->IsMoveTool() )
497  {
498  // leave ourselves on the stack so we come back after the move
499  break;
500  }
501  else
502  {
503  m_frame->PopTool( tool );
504  break;
505  }
506  }
507  else if( evt->IsClick( BUT_LEFT ) )
508  {
509  if( !m_frame->GetScreen()->GetItem( cursorPos, 0, type ) )
510  {
511  if( type == SCH_JUNCTION_T )
512  m_frame->AddJunction( m_frame->GetScreen(), cursorPos, false );
513  else
514  {
515  SCH_ITEM* newItem = static_cast<SCH_ITEM*>( previewItem->Clone() );
516  newItem->SetPosition( cursorPos );
517  newItem->SetFlags( IS_NEW );
518 
519  m_frame->AddItemToScreenAndUndoList( m_frame->GetScreen(), newItem, false );
520  m_frame->SaveCopyForRepeatItem( newItem );
521 
523  m_frame->OnModify();
524  }
525  }
526  }
527  else if( evt->IsClick( BUT_RIGHT ) )
528  {
530  }
531  else if( evt->IsAction( &ACTIONS::refreshPreview ) || evt->IsMotion() )
532  {
533  previewItem->SetPosition( (wxPoint)cursorPos );
534  m_view->ClearPreview();
535  m_view->AddToPreview( previewItem->Clone() );
536  }
537  else if( evt->Category() == TC_COMMAND )
538  {
539  if( ( type == SCH_BUS_WIRE_ENTRY_T )
540  && ( evt->IsAction( &EE_ACTIONS::rotateCW )
541  || evt->IsAction( &EE_ACTIONS::rotateCCW )
542  || evt->IsAction( &EE_ACTIONS::mirrorX )
543  || evt->IsAction( &EE_ACTIONS::mirrorY ) ) )
544  {
545  SCH_BUS_ENTRY_BASE* busItem = static_cast<SCH_BUS_ENTRY_BASE*>( previewItem );
546 
547  // The bus entries only rotate in one direction
548  if( evt->IsAction( &EE_ACTIONS::rotateCW )
549  || evt->IsAction( &EE_ACTIONS::rotateCCW ) )
550  busItem->Rotate( busItem->GetPosition() );
551  else if( evt->IsAction( &EE_ACTIONS::mirrorX ) )
552  busItem->MirrorX( busItem->GetPosition().x );
553  else if( evt->IsAction( &EE_ACTIONS::mirrorY ) )
554  busItem->MirrorY( busItem->GetPosition().y );
555 
556  m_view->ClearPreview();
557  m_view->AddToPreview( previewItem->Clone() );
558  }
559  }
560  else
561  evt->SetPassEvent();
562  }
563 
564  delete previewItem;
565  m_view->ClearPreview();
566 
567  return 0;
568 }
569 
570 
571 // History lists for placing labels and text
572 
574 {
575  if( m_queuedTexts.empty() )
576  return nullptr;
577 
578  auto next_text = std::move( m_queuedTexts.front() );
579  m_queuedTexts.pop_front();
580 
581  return next_text.release();
582 }
583 
584 
585 SCH_TEXT* SCH_DRAWING_TOOLS::createNewText( const VECTOR2I& aPosition, int aType )
586 {
587  SCHEMATIC* schematic = getModel<SCHEMATIC>();
588  SCHEMATIC_SETTINGS& settings = schematic->Settings();
589  SCH_TEXT* textItem = nullptr;
590 
591  m_queuedTexts.clear();
592 
593  switch( aType )
594  {
595  case LAYER_NOTES:
596  textItem = new SCH_TEXT( (wxPoint) aPosition );
597  break;
598 
599  case LAYER_LOCLABEL:
600  textItem = new SCH_LABEL( (wxPoint) aPosition );
601  break;
602 
603  case LAYER_HIERLABEL:
604  textItem = new SCH_HIERLABEL( (wxPoint) aPosition );
605  textItem->SetShape( m_lastGlobalLabelShape );
606  break;
607 
608  case LAYER_GLOBLABEL:
609  textItem = new SCH_GLOBALLABEL( (wxPoint) aPosition );
610  textItem->SetShape( m_lastGlobalLabelShape );
611  break;
612 
613  default:
614  wxFAIL_MSG( "SCH_EDIT_FRAME::CreateNewText() unknown layer type" );
615  return nullptr;
616  }
617 
618  textItem->SetParent( schematic );
619  textItem->SetBold( m_lastTextBold );
620  textItem->SetItalic( m_lastTextItalic );
622  textItem->SetTextSize( wxSize( settings.m_DefaultTextSize, settings.m_DefaultTextSize ) );
623  textItem->SetFlags( IS_NEW | IS_MOVED );
624 
625  DIALOG_LABEL_EDITOR dlg( m_frame, textItem );
626 
627  if( dlg.ShowModal() != wxID_OK || textItem->GetText().IsEmpty() )
628  {
629  delete textItem;
630  return nullptr;
631  }
632 
633  if( aType != LAYER_NOTES )
634  {
635  UTF8 text( textItem->GetText() );
636  int brace_count = 0;
637  int bracket_count = 0;
638  bool last_space = false;
639  UTF8 token;
640 
641  for( auto chIt = text.ubegin(); chIt != text.uend(); chIt++ )
642  {
643  switch( *chIt )
644  {
645  case '{':
646  brace_count++;
647  last_space = false;
648  break;
649 
650  case '[':
651  bracket_count++;
652  last_space = false;
653  break;
654 
655  case '}':
656  brace_count = std::max( 0, brace_count - 1 );
657  last_space = false;
658  break;
659 
660  case ']':
661  bracket_count = std::max( 0, bracket_count - 1 );
662  last_space = false;
663  break;
664 
665  case ' ':
666  case '\n':
667  case '\r':
668  case '\t':
669  if( !token.empty() && bracket_count == 0 && brace_count == 0 )
670  {
671  std::unique_ptr<SCH_TEXT> nextitem( static_cast<SCH_TEXT*>( textItem->Clone() ) );
672  nextitem->SetText( token.wx_str() );
673  m_queuedTexts.push_back( std::move( nextitem ) );
674  token.clear();
675  continue;
676  }
677 
678  // Skip leading whitespace
679  if( token.empty() || last_space )
680  continue;
681 
682  last_space = true;
683  break;
684 
685  default:
686  last_space = false;
687  break;
688  }
689 
690  token += *chIt;
691  }
692 
693  if( !token.empty() )
694  {
695  std::unique_ptr<SCH_TEXT> nextitem( static_cast<SCH_TEXT*>( textItem->Clone() ) );
696  nextitem->SetText( token.wx_str() );
697  m_queuedTexts.push_back( std::move( nextitem ) );
698  }
699 
700  delete textItem;
701  textItem = getNextNewText();
702 
703  if( !textItem )
704  return nullptr;
705  }
706 
707  m_lastTextBold = textItem->IsBold();
708  m_lastTextItalic = textItem->IsItalic();
710 
711  if( textItem->Type() == SCH_GLOBAL_LABEL_T || textItem->Type() == SCH_HIER_LABEL_T )
712  m_lastGlobalLabelShape = textItem->GetShape();
713 
714  return textItem;
715 }
716 
717 
719 {
720  EDA_ITEM* item = nullptr;
721  bool importMode = aEvent.IsAction( &EE_ACTIONS::importSheetPin );
722  KICAD_T type = aEvent.Parameter<KICAD_T>();
723 
725  getViewControls()->ShowCursor( true );
726 
727  std::string tool = aEvent.GetCommandStr().get();
728  m_frame->PushTool( tool );
729  Activate();
730 
731  // Prime the pump
732  if( aEvent.HasPosition() )
734 
735  // Main loop: keep receiving events
736  while( TOOL_EVENT* evt = Wait() )
737  {
738  m_frame->GetCanvas()->SetCurrentCursor( item ? wxCURSOR_ARROW : wxCURSOR_PENCIL );
739  VECTOR2I cursorPos = getViewControls()->GetCursorPosition( !evt->Modifier( MD_ALT ) );
740 
741  auto cleanup = [&] () {
743  m_view->ClearPreview();
744  delete item;
745  item = nullptr;
746  };
747 
748  if( evt->IsCancelInteractive() )
749  {
750  if( item )
751  cleanup();
752  else
753  {
754  m_frame->PopTool( tool );
755  break;
756  }
757  }
758  else if( evt->IsActivate() )
759  {
760  if( item )
761  cleanup();
762 
763  if( evt->IsPointEditor() )
764  {
765  // don't exit (the point editor runs in the background)
766  }
767  else if( evt->IsMoveTool() )
768  {
769  // leave ourselves on the stack so we come back after the move
770  break;
771  }
772  else
773  {
774  m_frame->PopTool( tool );
775  break;
776  }
777  }
778  else if( evt->IsClick( BUT_LEFT ) )
779  {
780  // First click creates...
781  if( !item )
782  {
784 
785  switch( type )
786  {
787  case SCH_LABEL_T:
788  item = createNewText( cursorPos, LAYER_LOCLABEL );
789  break;
790  case SCH_HIER_LABEL_T:
791  item = createNewText( cursorPos, LAYER_HIERLABEL );
792  break;
793  case SCH_GLOBAL_LABEL_T:
794  item = createNewText( cursorPos, LAYER_GLOBLABEL );
795  break;
796  case SCH_TEXT_T:
797  item = createNewText( cursorPos, LAYER_NOTES );
798  break;
799  case SCH_SHEET_PIN_T:
800  {
801  SCH_HIERLABEL* label = nullptr;
802  SCH_SHEET* sheet = nullptr;
803 
804  if( m_selectionTool->SelectPoint( cursorPos, EE_COLLECTOR::SheetsOnly, &item ) )
805  sheet = dynamic_cast<SCH_SHEET*>( item );
806 
807  item = nullptr;
808 
809  if( !sheet )
810  {
811  m_statusPopup.reset( new STATUS_TEXT_POPUP( m_frame ) );
812  m_statusPopup->SetText( _( "Click over a sheet." ) );
813  m_statusPopup->Move( wxGetMousePosition() + wxPoint( 20, 20 ) );
814  m_statusPopup->PopupFor( 2000 );
815  break;
816  }
817 
818  if( importMode )
819  {
820  label = m_frame->ImportHierLabel( sheet );
821 
822  if( !label )
823  {
824  m_statusPopup.reset( new STATUS_TEXT_POPUP( m_frame ) );
825  m_statusPopup->SetText( _( "No new hierarchical labels found." ) );
826  m_statusPopup->Move( wxGetMousePosition() + wxPoint( 20, 20 ) );
827  m_statusPopup->PopupFor( 2000 );
828  break;
829  }
830  }
831 
832  item = m_frame->CreateSheetPin( sheet, label );
833  break;
834  }
835  default:
836  break;
837  }
838 
839  // Restore cursor after dialog
840  getViewControls()->WarpCursor( getViewControls()->GetCursorPosition(), true );
841 
842  if( item )
843  {
844  item->SetFlags( IS_NEW | IS_MOVED );
845  m_view->ClearPreview();
846  m_view->AddToPreview( item->Clone() );
847  m_selectionTool->AddItemToSel( item );
848  }
849 
850  getViewControls()->SetCursorPosition( cursorPos, false );
851  }
852 
853  // ... and second click places:
854  else
855  {
856  item->ClearFlags( IS_MOVED );
858  item = getNextNewText();
859 
860  if( item )
861  {
863  item->SetFlags( IS_NEW | IS_MOVED );
864  m_view->ClearPreview();
865  m_view->AddToPreview( item->Clone() );
866  m_selectionTool->AddItemToSel( item );
867  }
868  else
869  {
870  m_view->ClearPreview();
871  }
872  }
873  }
874  else if( evt->IsClick( BUT_RIGHT ) )
875  {
876  // Warp after context menu only if dragging...
877  if( !item )
879 
881  }
882  else if( item && evt->IsSelectionEvent() )
883  {
884  // This happens if our text was replaced out from under us by ConvertTextType()
885  EE_SELECTION& selection = m_selectionTool->GetSelection();
886 
887  if( selection.GetSize() == 1 )
888  {
889  item = (SCH_ITEM*) selection.Front();
890  m_view->ClearPreview();
891  m_view->AddToPreview( item->Clone() );
892  }
893  else
894  item = nullptr;
895  }
896  else if( item && ( evt->IsAction( &ACTIONS::refreshPreview ) || evt->IsMotion() ) )
897  {
898  static_cast<SCH_ITEM*>( item )->SetPosition( (wxPoint) cursorPos );
899  m_view->ClearPreview();
900  m_view->AddToPreview( item->Clone() );
901  }
902  else
903  evt->SetPassEvent();
904 
905  // Enable autopanning and cursor capture only when there is a module to be placed
906  getViewControls()->SetAutoPan( item != nullptr );
907  getViewControls()->CaptureCursor( item != nullptr );
908  }
909 
910  return 0;
911 }
912 
913 
915 {
917  SCH_SHEET* sheet = nullptr;
918 
920  getViewControls()->ShowCursor( true );
921 
922  std::string tool = aEvent.GetCommandStr().get();
923  m_frame->PushTool( tool );
924  Activate();
925 
926  // Prime the pump
927  if( aEvent.HasPosition() )
929 
930  // Main loop: keep receiving events
931  while( TOOL_EVENT* evt = Wait() )
932  {
933  if( !pointEditor->HasPoint() )
934  m_frame->GetCanvas()->SetCurrentCursor( wxCURSOR_PENCIL );
935 
936  VECTOR2I cursorPos = getViewControls()->GetCursorPosition( !evt->Modifier( MD_ALT ) );
937 
938  auto cleanup = [&] () {
940  m_view->ClearPreview();
941  delete sheet;
942  sheet = nullptr;
943  };
944 
945  if( evt->IsCancelInteractive() )
946  {
947  if( sheet )
948  cleanup();
949  else
950  {
951  m_frame->PopTool( tool );
952  break;
953  }
954  }
955  else if( evt->IsActivate() )
956  {
957  if( sheet )
958  cleanup();
959 
960  if( evt->IsPointEditor() )
961  {
962  // don't exit (the point editor runs in the background)
963  }
964  else if( evt->IsMoveTool() )
965  {
966  // leave ourselves on the stack so we come back after the move
967  break;
968  }
969  else
970  {
971  m_frame->PopTool( tool );
972  break;
973  }
974  }
975 
976  else if( evt->IsClick( BUT_LEFT ) && !sheet )
977  {
979 
981 
982  sheet = new SCH_SHEET( m_frame->GetCurrentSheet().Last(),
983  static_cast<wxPoint>( cursorPos ) );
984  sheet->SetFlags( IS_NEW | IS_RESIZED );
985  sheet->SetScreen( NULL );
986  sheet->SetBorderWidth( cfg->m_Drawing.default_line_thickness );
987  sheet->SetBorderColor( cfg->m_Drawing.default_sheet_border_color );
988  sheet->SetBackgroundColor( cfg->m_Drawing.default_sheet_background_color );
989  sheet->GetFields()[ SHEETNAME ].SetText( "Untitled Sheet" );
990  sheet->GetFields()[ SHEETFILENAME ].SetText( "untitled.kicad_sch" );
991  sizeSheet( sheet, cursorPos );
992 
993  m_view->ClearPreview();
994  m_view->AddToPreview( sheet->Clone() );
995  }
996 
997  else if( sheet && ( evt->IsClick( BUT_LEFT )
998  || evt->IsAction( &EE_ACTIONS::finishSheet ) ) )
999  {
1000  m_view->ClearPreview();
1001  getViewControls()->SetAutoPan( false );
1002  getViewControls()->CaptureCursor( false );
1003 
1004  if( m_frame->EditSheetProperties( static_cast<SCH_SHEET*>( sheet ),
1005  &m_frame->GetCurrentSheet(), nullptr ) )
1006  {
1007  sheet->AutoplaceFields( /* aScreen */ NULL, /* aManual */ false );
1008 
1009  m_frame->AddItemToScreenAndUndoList( m_frame->GetScreen(), sheet, false );
1011  m_selectionTool->AddItemToSel( sheet );
1012  }
1013  else
1014  {
1015  delete sheet;
1016  }
1017 
1018  sheet = nullptr;
1019  }
1020 
1021  else if( sheet && ( evt->IsAction( &ACTIONS::refreshPreview ) || evt->IsMotion() ) )
1022  {
1023  sizeSheet( sheet, cursorPos );
1024  m_view->ClearPreview();
1025  m_view->AddToPreview( sheet->Clone() );
1026  }
1027 
1028  else if( evt->IsClick( BUT_RIGHT ) )
1029  {
1030  // Warp after context menu only if dragging...
1031  if( !sheet )
1033 
1035  }
1036  else
1037  evt->SetPassEvent();
1038 
1039  // Enable autopanning and cursor capture only when there is a sheet to be placed
1040  getViewControls()->SetAutoPan( sheet != nullptr );
1041  getViewControls()->CaptureCursor( sheet != nullptr );
1042  }
1043 
1044  return 0;
1045 }
1046 
1047 
1049 {
1050  wxPoint pos = aSheet->GetPosition();
1051  wxPoint size = (wxPoint) aPos - pos;
1052 
1053  size.x = std::max( size.x, MIN_SHEET_WIDTH );
1054  size.y = std::max( size.y, MIN_SHEET_HEIGHT );
1055 
1056  wxPoint grid = m_frame->GetNearestGridPosition( pos + size );
1057  aSheet->Resize( wxSize( grid.x - pos.x, grid.y - pos.y ) );
1058 }
1059 
1060 
1062 {
1075 }
virtual void ShowCursor(bool aEnabled)
Function ShowCursor() Enables or disables display of cursor.
UTF8 is an 8 bit string that is assuredly encoded in UTF8, and supplies special conversion support to...
Definition: utf8.h:73
bool IsBold() const
Definition: eda_text.h:183
bool SchematicCleanUp(SCH_SCREEN *aScreen=nullptr)
Performs routine schematic cleaning including breaking wire and buses and deleting identical objects ...
void SetShape(PINSHEETLABEL_SHAPE aShape)
Definition: sch_text.h:241
PINSHEETLABEL_SHAPE m_lastGlobalLabelShape
int TwoClickPlace(const TOOL_EVENT &aEvent)
TOOL_MENU m_menu
functions below are not yet implemented - their interface may change
static TOOL_ACTION finishSheet
Definition: ee_actions.h:98
bool Init() override
Function Init() Init() is called once upon a registration of the tool.
int PlaceComponent(const TOOL_EVENT &aEvent)
TOOL_EVENT * Wait(const TOOL_EVENT_LIST &aEventList=TOOL_EVENT(TC_ANY, TA_ANY))
Function Wait()
std::vector< COMPONENT_SELECTION > m_symbolHistoryList
static TOOL_ACTION activatePointEditor
Definition: actions.h:166
wxPoint GetStartPoint() const
Definition: sch_line.h:94
Holds all the data relating to one schematic A schematic may consist of one or more sheets (and one r...
Definition: schematic.h:42
SCH_SHEET * Last() const
Function Last returns a pointer to the last sheet of the list One can see the others sheet as the "pa...
This file is part of the common library.
virtual void SetPosition(const wxPoint &aPos)
Definition: base_struct.h:338
void SetCurrentCursor(wxStockCursor aStockCursorID)
Function SetCurrentCursor Set the current cursor shape for this panel.
void AddToPreview(EDA_ITEM *aItem, bool aTakeOwnership=true)
Definition: view.cpp:1572
VIEW_CONTROLS class definition.
bool HasPoint()
Indicates the cursor is over an edit point.
STATUS_TEXT_POPUP.
Definition: status_popup.h:79
CONDITIONAL_MENU & GetMenu()
Function GetMenu.
Definition: tool_menu.cpp:46
static TOOL_ACTION mirrorY
Definition: ee_actions.h:120
SCHEMATIC_SETTINGS & Settings() const
Definition: schematic.cpp:124
static TOOL_ACTION placeHierLabel
Definition: ee_actions.h:87
void SetItalic(bool isItalic)
Definition: eda_text.h:179
TOOL_MANAGER * m_toolMgr
Definition: tool_base.h:219
static TOOL_ACTION placeJunction
Definition: ee_actions.h:83
void RecacheAllItems()
Function RecacheAllItems() Rebuilds GAL display lists.
Definition: view.cpp:1395
virtual void PushTool(const std::string &actionName)
NB: the definition of "tool" is different at the user level.
int GetUnitCount() const
Return the number of units per package of the symbol.
void Rotate(wxPoint aPosition) override
Rotate the item around aPosition 90 degrees in the clockwise direction.
bool RunAction(const std::string &aActionName, bool aNow=false, T aParam=NULL)
Function RunAction() Runs the specified action.
Definition: tool_manager.h:140
void SetPosition(const wxPoint &aPosition) override
virtual void SetCursorPosition(const VECTOR2D &aPosition, bool aWarpView=true, bool aTriggeredByArrows=false, long aArrowCommand=0)=0
Moves cursor to the requested position expressed in world coordinates.
Schematic editor (Eeschema) main window.
LIB_PART * GetLibPart(const LIB_ID &aLibId, bool aUseCacheLib=false, bool aShowErrorMsg=false)
Load symbol from symbol library table.
static TOOL_ACTION placeBusWireEntry
Definition: ee_actions.h:84
void SetTextSize(const wxSize &aNewSize)
Definition: eda_text.h:238
std::vector< COMPONENT_SELECTION > m_powerHistoryList
static const KICAD_T SheetsOnly[]
Definition: ee_collectors.h:48
wxPoint GetNearestGridPosition(const wxPoint &aPosition) const
Return the nearest aGridSize location to aPosition.
bool IsValid() const
Definition: lib_id.h:171
int PlaceImage(const TOOL_EVENT &aEvent)
PANEL_SYM_CHOOSER m_SymChooserPanel
void Go(int(T::*aStateFunc)(const TOOL_EVENT &), const TOOL_EVENT_LIST &aConditions=TOOL_EVENT(TC_ANY, TA_ANY))
Function Go()
KICAD_T
Enum KICAD_T is the set of class identification values, stored in EDA_ITEM::m_StructType.
Definition: typeinfo.h:78
#define MIN_SHEET_WIDTH
Definition: sch_sheet.h:42
virtual void SetParent(EDA_ITEM *aParent)
Definition: base_struct.h:196
virtual EDA_ITEM * Clone() const
Function Clone creates a duplicate of this item with linked list members set to NULL.
static TOOL_ACTION rotateCW
Definition: ee_actions.h:117
virtual void Add(EDA_ITEM *aItem)
Definition: selection.h:76
bool IsAction(const TOOL_ACTION *aAction) const
Function IsAction() Tests if the event contains an action issued upon activation of the given TOOL_AC...
Definition: tool_event.cpp:67
SCH_JUNCTION * AddJunction(SCH_SCREEN *aScreen, const wxPoint &aPos, bool aAppendToUndo, bool aFinal=true)
static TOOL_ACTION leaveSheet
Definition: ee_actions.h:185
Base class for a bus or wire entry.
Definition: sch_bus_entry.h:43
bool Init() override
Function Init() Init() is called once upon a registration of the tool.
Definition: ee_tool_base.h:69
bool IsItalic() const
Definition: eda_text.h:180
EE_SELECTION & GetSelection()
Function GetSelection()
#define IS_NEW
New item, just created.
Definition: base_struct.h:117
EESCHEMA_SETTINGS * eeconfig() const
SCH_SCREEN * GetScreen() const override
Return a pointer to a BASE_SCREEN or one of its derivatives.
static TOOL_ACTION drawSheet
Definition: ee_actions.h:88
virtual void WarpCursor(const VECTOR2D &aPosition, bool aWorldCoordinates=false, bool aWarpView=false)=0
Function WarpCursor() If enabled (.
static TOOL_ACTION rotateCCW
Definition: ee_actions.h:118
int GetUnit() const
AUTOPLACE_FIELDS m_AutoplaceFields
static TOOL_ACTION placePower
Definition: ee_actions.h:78
EDA_ITEM * Clone() const override
Function Clone creates a duplicate of this item with linked list members set to NULL.
Definition: sch_text.cpp:143
void SetFlags(STATUS_FLAGS aMask)
Definition: base_struct.h:232
SCH_ITEM * Duplicate(bool doClone=false) const
Routine to create a new copy of given item.
Definition: sch_item.cpp:81
#define NULL
virtual void PopTool(const std::string &actionName)
virtual void CaptureCursor(bool aEnabled)
Function CaptureCursor() Forces the cursor to stay within the drawing panel area.
int SingleClickPlace(const TOOL_EVENT &aEvent)
T Parameter() const
Function Parameter() Returns a non-standard parameter assigned to the event.
Definition: tool_event.h:435
static TOOL_ACTION placeSchematicText
Definition: ee_actions.h:91
SCH_DRAW_PANEL * GetCanvas() const override
Return a pointer to GAL-based canvas of given EDA draw frame.
EDA_ITEM * Clone() const override
Function Clone creates a duplicate of this item with linked list members set to NULL.
TOOL_EVENT.
Definition: tool_event.h:171
static TOOL_ACTION placeImage
Definition: ee_actions.h:93
void ClearPreview()
Definition: view.cpp:1553
SCHEMATIC & Schematic() const
void UpdateHierarchyNavigator(bool aForceUpdate=false)
Run the Hierarchy Navigator dialog.
Define a library symbol object.
void SaveCopyForRepeatItem(SCH_ITEM *aItem)
Clone aItem and owns that clone in this container.
static TOOL_ACTION mirrorX
Definition: ee_actions.h:119
EE_SELECTION_TOOL * m_selectionTool
Definition: ee_tool_base.h:160
LABEL_SPIN_STYLE GetLabelSpinStyle() const
Definition: sch_text.h:234
static TOOL_ACTION importSheetPin
Definition: ee_actions.h:90
void SetUnit(int aUnit)
Change the unit number to aUnit.
static TOOL_ACTION clearSelection
Clears the current selection.
Definition: ee_actions.h:56
static TOOL_ACTION placeSymbol
Definition: ee_actions.h:77
virtual void SetCrossHairCursorPosition(const VECTOR2D &aPosition, bool aWarpView=true)=0
Moves the graphic crosshair cursor to the requested position expressed in world coordinates.
static TOOL_ACTION addNeededJunctions
Definition: ee_actions.h:75
COMPONENT_SELECTION SelectCompFromLibTree(const SCHLIB_FILTER *aFilter, std::vector< COMPONENT_SELECTION > &aHistoryList, bool aUseLibBrowser, int aUnit, int aConvert, bool aShowFootprints, const LIB_ID *aHighlight=nullptr, bool aAllowFields=true)
Function SelectComponentFromLib Calls the library viewer to select component to import into schematic...
Definition: getpart.cpp:89
wxPoint GetPosition() const override
Definition: sch_sheet.h:567
Object to handle a bitmap image that can be inserted in a schematic.
Definition: sch_bitmap.h:42
virtual void SetAutoPan(bool aEnabled)
Function SetAutoPan Turns on/off auto panning (this feature is used when there is a tool active (eg.
void SelectUnit(SCH_COMPONENT *aComponent, int aUnit)
Definition: getpart.cpp:196
Sheet symbol placed in a schematic, and is the entry point for a sub schematic.
Definition: sch_sheet.h:216
virtual unsigned int GetSize() const override
Function GetSize() Returns the number of stored items.
Definition: selection.h:100
Definition: seg.h:39
static TOOL_ACTION placeLabel
Definition: ee_actions.h:85
OPT< std::string > GetCommandStr() const
Definition: tool_event.h:463
void SetUnitSelection(const SCH_SHEET_PATH *aSheet, int aUnitSelection)
PINSHEETLABEL_SHAPE
Definition: sch_text.h:152
SCH_SHEET & Root() const
Definition: schematic.h:94
SCH_TEXT * getNextNewText()
Gets the next queued text item.
void AddItemToScreenAndUndoList(SCH_SCREEN *aScreen, SCH_ITEM *aItem, bool aUndoAppend)
Add an item to the schematic and adds the changes to the undo/redo container.
SCH_HIERLABEL * ImportHierLabel(SCH_SHEET *aSheet)
Import a hierarchical label with no attached sheet pin.
Definition: sheet.cpp:519
int AddItemToSel(const TOOL_EVENT &aEvent)
SCH_SCREEN * LastScreen()
Function LastScreen.
Segment description base class to describe items which have 2 end points (track, wire,...
Definition: sch_line.h:37
bool SelectPoint(const VECTOR2I &aWhere, const KICAD_T *aFilterList=EE_COLLECTOR::AllItems, EDA_ITEM **aItem=nullptr, bool *aSelectionCancelledFlag=nullptr, bool aCheckLocked=false, bool aAdd=false, bool aSubtract=false, bool aExclusiveOr=false)
Function SelectPoint() Selects one or all items pointed by the parameter aWhere.
int ClearSelection(const TOOL_EVENT &aEvent)
Clear current selection event handler.
#define _(s)
Definition: 3d_actions.cpp:33
EE_POINT_EDITOR.
void MirrorX(int aXaxis_position) override
Mirror item relative to the X axis about aXaxis_position.
wxString wx_str() const
Definition: utf8.cpp:51
void VetoContextMenuMouseWarp()
Disables mouse warping after the current context menu is closed.
Definition: tool_manager.h:413
SCH_TEXT * createNewText(const VECTOR2I &aPosition, int aType)
static TOOL_ACTION placeNoConnect
Definition: ee_actions.h:82
void AutoplaceFields(SCH_SCREEN *aScreen, bool aManual) override
Automatically orient all the fields in the component.
Schematic symbol object.
Definition: sch_component.h:80
EDA_ITEM * Clone() const override
Function Clone creates a duplicate of this item with linked list members set to NULL.
Definition: sch_bitmap.cpp:89
EDA_ITEM is a base class for most all the KiCad significant classes, used in schematics and boards.
Definition: base_struct.h:159
std::deque< std::unique_ptr< SCH_TEXT > > m_queuedTexts
#define MIN_SHEET_HEIGHT
Definition: sch_sheet.h:43
#define IS_RESIZED
Item being resized.
Definition: base_struct.h:118
These settings were stored in SCH_BASE_FRAME previously.
Class for a wire to bus entry.
void ClearFlags(STATUS_FLAGS aMask=EDA_ITEM_ALL_FLAGS)
Definition: base_struct.h:233
bool EditSheetProperties(SCH_SHEET *aSheet, SCH_SHEET_PATH *aHierarchy, bool *aClearAnnotationNewItems)
Edit an existing sheet or add a new sheet to the schematic.
Definition: sheet.cpp:464
void Activate()
Function Activate() Runs the tool.
SCH_SHEET_PATH & GetCurrentSheet() const
bool ReadImageFile(const wxString &aFullFilename)
Reads and stores an image file.
Definition: sch_bitmap.cpp:83
EE_TOOL_BASE.
Definition: ee_tool_base.h:50
LABEL_SPIN_STYLE m_lastTextOrientation
SCH_ITEM * GetItem(const wxPoint &aPosition, int aAccuracy=0, KICAD_T aType=SCH_LOCATE_ANY_T)
Check aPosition within a distance of aAccuracy for items of type aFilter.
Definition: sch_screen.cpp:312
bool HasPosition() const
Returns if it this event has a valid position (true for mouse events and context-menu or hotkey-based...
Definition: tool_event.h:260
void OnModify() override
Must be called after a schematic change in order to set the "modify" flag of the current screen and u...
Definition for part library class.
KIGFX::VIEW_CONTROLS * getViewControls() const
Function getViewControls()
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:229
void clear()
Definition: utf8.h:113
static TOOL_ACTION placeGlobalLabel
Definition: ee_actions.h:86
void SetBold(bool aBold)
Definition: eda_text.h:182
void AddItem(const TOOL_ACTION &aAction, const SELECTION_CONDITION &aCondition, int aOrder=ANY_ORDER)
Adds a menu entry to run a TOOL_ACTION on selected items.
void MirrorY(int aYaxis_position) override
Mirror item relative to the Y axis about aYaxis_position.
Base class for any item which can be embedded within the SCHEMATIC container class,...
Definition: sch_item.h:194
void ShowContextMenu(SELECTION &aSelection)
Function ShowContextMenu.
Definition: tool_menu.cpp:59
SCH_SHEET_PIN * CreateSheetPin(SCH_SHEET *aSheet, SCH_HIERLABEL *aLabel)
Create a new SCH_SHEET_PIN object and add it to aSheet at the current cursor position.
Definition: sheet.cpp:483
void SetPosition(const wxPoint &aPosition) override
Definition: sch_bitmap.h:141
virtual const wxString & GetText() const
Return the string associated with the text object.
Definition: eda_text.h:127
void setTransitions() override
Sets up handlers for various events.
static TOOL_ACTION refreshPreview
Definition: actions.h:104
VECTOR2D GetCursorPosition() const
Returns the current cursor position in world coordinates.
EDA_ITEM * Front() const
Definition: selection.h:184
int DrawSheet(const TOOL_EVENT &aEvent)
static TOOL_ACTION cursorClick
Definition: actions.h:121
PINSHEETLABEL_SHAPE GetShape() const
Definition: sch_text.h:239
KICAD_T Type() const
Function Type()
Definition: base_struct.h:193
bool empty() const
Definition: utf8.h:108
void Resize(const wxSize &aSize)
Resize this sheet to aSize and adjust all of the labels accordingly.
Definition: sch_sheet.cpp:796
void sizeSheet(SCH_SHEET *aSheet, VECTOR2I aPos)
wxPoint GetPosition() const override
#define IS_MOVED
Item being moved.
Definition: base_struct.h:116
wxPoint GetEndPoint() const
Definition: sch_line.h:97
std::unique_ptr< STATUS_TEXT_POPUP > m_statusPopup