KiCad PCB EDA Suite
ee_point_editor.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 <functional>
26 using namespace std::placeholders;
27 
28 #include "ee_point_editor.h"
29 #include <ee_grid_helper.h>
30 #include <tool/tool_manager.h>
31 #include <view/view_controls.h>
32 #include <geometry/seg.h>
33 #include <tools/ee_actions.h>
35 #include <bitmaps.h>
36 #include <sch_edit_frame.h>
37 #include <sch_line.h>
38 #include <sch_bitmap.h>
39 #include <sch_sheet.h>
40 #include <sch_sheet_pin.h>
41 #include <symbol_edit_frame.h>
42 #include <lib_shape.h>
43 
44 
45 // Few constants to avoid using bare numbers for point indices
47 {
49 };
50 
52 {
54 };
55 
57 {
59 };
60 
62 {
64 };
65 
67 {
68 public:
69  static std::shared_ptr<EDIT_POINTS> Make( EDA_ITEM* aItem, SCH_BASE_FRAME* frame )
70  {
71  std::shared_ptr<EDIT_POINTS> points = std::make_shared<EDIT_POINTS>( aItem );
72 
73  if( !aItem )
74  return points;
75 
76  // Generate list of edit points based on the item type
77  switch( aItem->Type() )
78  {
79  case LIB_SHAPE_T:
80  {
81  LIB_SHAPE* shape = static_cast<LIB_SHAPE*>( aItem );
82 
83  switch( shape->GetShape() )
84  {
85  case SHAPE_T::ARC:
86  points->AddPoint( mapCoords( shape->GetPosition() ) );
87  points->AddPoint( mapCoords( shape->GetStart() ) );
88  points->AddPoint( mapCoords( shape->GetEnd() ) );
89  break;
90 
91  case SHAPE_T::CIRCLE:
92  points->AddPoint( mapCoords( shape->GetPosition() ) );
93  points->AddPoint( mapCoords( shape->GetEnd() ) );
94  break;
95 
96  case SHAPE_T::RECT:
97  {
98  // point editor works only with rectangles having width and height > 0
99  // Some symbols can have rectangles with width or height < 0
100  // So normalize the size:
101  BOX2I dummy;
102  dummy.SetOrigin( mapCoords( shape->GetPosition() ) );
103  dummy.SetEnd( mapCoords( shape->GetEnd() ) );
104  dummy.Normalize();
105  VECTOR2I topLeft = dummy.GetPosition();
106  VECTOR2I botRight = dummy.GetEnd();
107 
108  points->AddPoint( topLeft );
109  points->AddPoint( VECTOR2I( botRight.x, topLeft.y ) );
110  points->AddPoint( VECTOR2I( topLeft.x, botRight.y ) );
111  points->AddPoint( botRight );
112  }
113  break;
114 
115  case SHAPE_T::POLY:
116  for( const VECTOR2I& pt : shape->GetPolyShape().Outline( 0 ).CPoints() )
117  points->AddPoint( mapCoords( pt ) );
118 
119  break;
120 
121  case SHAPE_T::BEZIER:
122  // TODO
123  break;
124 
125  default:
126  wxFAIL_MSG( wxT( "EDIT_POINTS_FACTORY::Make not implemented for " )
127  + shape->SHAPE_T_asString() );
128  }
129  }
130  break;
131 
132  case SCH_SHEET_T:
133  {
134  SCH_SHEET* sheet = (SCH_SHEET*) aItem;
135  wxPoint topLeft = sheet->GetPosition();
136  wxPoint botRight = sheet->GetPosition() + sheet->GetSize();
137 
138  points->AddPoint( (wxPoint) topLeft );
139  points->AddPoint( wxPoint( botRight.x, topLeft.y ) );
140  points->AddPoint( wxPoint( topLeft.x, botRight.y ) );
141  points->AddPoint( (wxPoint) botRight );
142  }
143  break;
144 
145  case SCH_BITMAP_T:
146  {
147  SCH_BITMAP* bitmap = (SCH_BITMAP*) aItem;
148  wxPoint topLeft = bitmap->GetPosition() - bitmap->GetSize() / 2;
149  wxPoint botRight = bitmap->GetPosition() + bitmap->GetSize() / 2;
150 
151  points->AddPoint( (wxPoint) topLeft );
152  points->AddPoint( wxPoint( botRight.x, topLeft.y ) );
153  points->AddPoint( wxPoint( topLeft.x, botRight.y ) );
154  points->AddPoint( (wxPoint) botRight );
155  }
156  break;
157 
158  case SCH_LINE_T:
159  {
160  SCH_LINE* line = (SCH_LINE*) aItem;
161  std::pair<EDA_ITEM*, int> connectedStart = { nullptr, STARTPOINT };
162  std::pair<EDA_ITEM*, int> connectedEnd = { nullptr, STARTPOINT };
163 
164  for( SCH_ITEM* test : frame->GetScreen()->Items().OfType( SCH_LINE_T ) )
165  {
166  if( test->GetLayer() != LAYER_NOTES )
167  continue;
168 
169  if( test == aItem )
170  continue;
171 
172  SCH_LINE* testLine = static_cast<SCH_LINE*>( test );
173 
174  if( testLine->GetStartPoint() == line->GetStartPoint() )
175  {
176  connectedStart = { testLine, STARTPOINT };
177  }
178  else if( testLine->GetEndPoint() == line->GetStartPoint() )
179  {
180  connectedStart = { testLine, ENDPOINT };
181  }
182  else if( testLine->GetStartPoint() == line->GetEndPoint() )
183  {
184  connectedEnd = { testLine, STARTPOINT };
185  }
186  else if( testLine->GetEndPoint() == line->GetEndPoint() )
187  {
188  connectedEnd = { testLine, ENDPOINT };
189  }
190  }
191 
192  points->AddPoint( line->GetStartPoint(), connectedStart );
193  points->AddPoint( line->GetEndPoint(), connectedEnd );
194  }
195  break;
196 
197  default:
198  points.reset();
199  break;
200  }
201 
202  return points;
203  }
204 
205 private:
207 };
208 
209 
211  EE_TOOL_BASE<SCH_BASE_FRAME>( "eeschema.PointEditor" ),
212  m_editedPoint( nullptr )
213 {
214 }
215 
216 
218 {
219  EE_TOOL_BASE::Reset( aReason );
220 
221  m_editPoints.reset();
222  m_editedPoint = nullptr;
223 }
224 
225 
227 {
229 
230  auto& menu = m_selectionTool->GetToolMenu().GetMenu();
232  std::bind( &EE_POINT_EDITOR::addCornerCondition, this, _1 ) );
234  std::bind( &EE_POINT_EDITOR::removeCornerCondition, this, _1 ) );
235 
236  return true;
237 }
238 
239 
241 {
242  setEditedPoint( nullptr );
243 
244  return 0;
245 }
246 
247 
249 {
250  EDIT_POINT* point = m_editedPoint;
251 
252  if( !m_editPoints )
253  {
254  point = nullptr;
255  }
256  else if( aEvent.IsMotion() )
257  {
258  point = m_editPoints->FindPoint( aEvent.Position(), getView() );
259  }
260  else if( aEvent.IsDrag( BUT_LEFT ) )
261  {
262  point = m_editPoints->FindPoint( aEvent.DragOrigin(), getView() );
263  }
264  else
265  {
266  point = m_editPoints->FindPoint( getViewControls()->GetCursorPosition(), getView() );
267  }
268 
269  if( m_editedPoint != point )
270  setEditedPoint( point );
271 }
272 
273 
274 int EE_POINT_EDITOR::Main( const TOOL_EVENT& aEvent )
275 {
276  static KICAD_T supportedTypes[] = {
277  LIB_SHAPE_T,
278  SCH_SHEET_T,
280  SCH_BITMAP_T,
281  EOT
282  };
283 
284  if( !m_selectionTool )
285  return 0;
286 
287  if( m_isSymbolEditor )
288  {
289  SYMBOL_EDIT_FRAME* editor = getEditFrame<SYMBOL_EDIT_FRAME>();
290 
291  if( !editor->IsSymbolEditable() || editor->IsSymbolAlias() )
292  return 0;
293  }
294 
295  const EE_SELECTION& selection = m_selectionTool->GetSelection();
296 
297  if( selection.Size() != 1 || !selection.Front()->IsType( supportedTypes ) )
298  return 0;
299 
300  // Wait till drawing tool is done
301  if( selection.Front()->IsNew() )
302  return 0;
303 
304  Activate();
305 
307  KIGFX::VIEW* view = getView();
308  EDA_ITEM* item = (EDA_ITEM*) selection.Front();
309 
310  controls->ShowCursor( true );
311 
313  view->Add( m_editPoints.get() );
314  setEditedPoint( nullptr );
315  updateEditedPoint( aEvent );
316  bool inDrag = false;
317  bool modified = false;
318 
319  // Main loop: keep receiving events
320  while( TOOL_EVENT* evt = Wait() )
321  {
322  if( !m_editPoints || evt->IsSelectionEvent() )
323  break;
324 
325  if ( !inDrag )
326  updateEditedPoint( *evt );
327 
328  if( evt->IsDrag( BUT_LEFT ) && m_editedPoint )
329  {
330  if( !inDrag )
331  {
332  saveItemsToUndo();
333  controls->ForceCursorPosition( false );
334  inDrag = true;
335  modified = true;
336  }
337 
338  bool snap = !evt->DisableGridSnapping();
339  EDA_SHAPE* shape = dynamic_cast<EDA_SHAPE*>( item );
340 
341  if( shape && shape->GetShape() == SHAPE_T::ARC && getEditedPointIndex() == ARC_CENTER )
342  snap = false;
343 
344  m_editedPoint->SetPosition( controls->GetCursorPosition( snap ) );
345 
347  updatePoints();
348  }
349  else if( inDrag && evt->IsMouseUp( BUT_LEFT ) )
350  {
351  if( modified )
352  {
353  m_frame->OnModify();
354  modified = false;
355  }
356 
357  controls->SetAutoPan( false );
358  inDrag = false;
359  }
360  else if( evt->IsCancelInteractive() || evt->IsActivate() )
361  {
362  if( inDrag ) // Restore the last change
363  {
365  inDrag = false;
366  modified = false;
367  break;
368  }
369  else if( evt->IsCancelInteractive() )
370  {
371  break;
372  }
373 
374  if( evt->IsActivate() )
375  break;
376  }
377  else
378  {
379  evt->SetPassEvent();
380  }
381 
382  controls->SetAutoPan( inDrag );
383  controls->CaptureCursor( inDrag );
384  }
385 
386  controls->SetAutoPan( false );
387  controls->CaptureCursor( false );
388  setEditedPoint( nullptr );
389 
390  if( m_editPoints )
391  {
392  view->Remove( m_editPoints.get() );
393 
394  if( modified )
395  m_frame->OnModify();
396 
397  m_editPoints.reset();
398  m_frame->GetCanvas()->Refresh();
399  }
400 
401  return 0;
402 }
403 
415 static void pinEditedCorner( int aEditedPointIndex, int minWidth, int minHeight,
416  VECTOR2I& topLeft, VECTOR2I& topRight, VECTOR2I& botLeft,
417  VECTOR2I& botRight, EE_GRID_HELPER* aGrid )
418 {
419  switch( aEditedPointIndex )
420  {
421  case RECT_TOPLEFT:
422  // pin edited point within opposite corner
423  topLeft.x = std::min( topLeft.x, botRight.x - minWidth );
424  topLeft.y = std::min( topLeft.y, botRight.y - minHeight );
425 
426  topLeft = aGrid->AlignGrid( topLeft );
427 
428  // push edited point edges to adjacent corners
429  topRight.y = topLeft.y;
430  botLeft.x = topLeft.x;
431 
432  break;
433 
434  case RECT_TOPRIGHT:
435  // pin edited point within opposite corner
436  topRight.x = std::max( topRight.x, botLeft.x + minWidth );
437  topRight.y = std::min( topRight.y, botLeft.y - minHeight );
438 
439  topRight = aGrid->AlignGrid( topRight );
440 
441  // push edited point edges to adjacent corners
442  topLeft.y = topRight.y;
443  botRight.x = topRight.x;
444 
445  break;
446 
447  case RECT_BOTLEFT:
448  // pin edited point within opposite corner
449  botLeft.x = std::min( botLeft.x, topRight.x - minWidth );
450  botLeft.y = std::max( botLeft.y, topRight.y + minHeight );
451 
452  botLeft = aGrid->AlignGrid( botLeft );
453 
454  // push edited point edges to adjacent corners
455  botRight.y = botLeft.y;
456  topLeft.x = botLeft.x;
457 
458  break;
459 
460  case RECT_BOTRIGHT:
461  // pin edited point within opposite corner
462  botRight.x = std::max( botRight.x, topLeft.x + minWidth );
463  botRight.y = std::max( botRight.y, topLeft.y + minHeight );
464 
465  botRight = aGrid->AlignGrid( botRight );
466 
467  // push edited point edges to adjacent corners
468  botLeft.y = botRight.y;
469  topRight.x = botRight.x;
470 
471  break;
472  }
473 }
474 
475 
477 {
478  EDA_ITEM* item = m_editPoints->GetParent();
479 
480  if( !item )
481  return;
482 
483  switch( item->Type() )
484  {
485  case LIB_SHAPE_T:
486  {
487  LIB_SHAPE* shape = static_cast<LIB_SHAPE*>( item );
488 
489  switch( shape->GetShape() )
490  {
491  case SHAPE_T::ARC:
493  {
494  shape->SetEditState( 4 );
495  shape->CalcEdit( mapCoords( m_editPoints->Point( ARC_CENTER ).GetPosition() ) );
496  }
497  else if( getEditedPointIndex() == ARC_START )
498  {
499  shape->SetEditState( 2 );
500  shape->CalcEdit( mapCoords( m_editPoints->Point( ARC_START ).GetPosition() ) );
501  }
502  else if( getEditedPointIndex() == ARC_END )
503  {
504  shape->SetEditState( 3 );
505  shape->CalcEdit( mapCoords( m_editPoints->Point( ARC_END ).GetPosition() ) );
506  }
507  break;
508 
509  case SHAPE_T::CIRCLE:
510  shape->SetPosition( mapCoords( m_editPoints->Point( CIRC_CENTER ).GetPosition() ) );
511  shape->SetEnd( mapCoords( m_editPoints->Point( CIRC_END ).GetPosition() ) );
512  break;
513 
514  case SHAPE_T::POLY:
515  shape->GetPolyShape().RemoveAllContours();
516  shape->GetPolyShape().NewOutline();
517 
518  for( unsigned i = 0; i < m_editPoints->PointsSize(); ++i )
519  {
520  wxPoint pt = mapCoords( m_editPoints->Point( i ).GetPosition() );
521  shape->GetPolyShape().Append( pt.x, pt.y, -1, -1, true );
522  }
523 
524  break;
525 
526  case SHAPE_T::RECT:
527  {
528  EE_GRID_HELPER gridHelper( m_toolMgr );
529  VECTOR2I topLeft = m_editPoints->Point( RECT_TOPLEFT ).GetPosition();
530  VECTOR2I topRight = m_editPoints->Point( RECT_TOPRIGHT ).GetPosition();
531  VECTOR2I botLeft = m_editPoints->Point( RECT_BOTLEFT ).GetPosition();
532  VECTOR2I botRight = m_editPoints->Point( RECT_BOTRIGHT ).GetPosition();
533 
534  pinEditedCorner( getEditedPointIndex(), Mils2iu( 1 ), Mils2iu( 1 ),
535  topLeft, topRight, botLeft, botRight, &gridHelper );
536 
537  shape->SetPosition( mapCoords( topLeft ) );
538  shape->SetEnd( mapCoords( botRight ) );
539  }
540  break;
541 
542  case SHAPE_T::BEZIER:
543  // TODO
544  break;
545 
546  default:
547  wxFAIL_MSG( wxT( "EE_POINT_EDITOR::updateParentItem not implemented for " )
548  + shape->SHAPE_T_asString() );
549  }
550  }
551  break;
552 
553  case SCH_BITMAP_T:
554  {
555  EE_GRID_HELPER gridHelper( m_toolMgr );
556  SCH_BITMAP* bitmap = (SCH_BITMAP*) item;
557  VECTOR2I topLeft = m_editPoints->Point( RECT_TOPLEFT ).GetPosition();
558  VECTOR2I topRight = m_editPoints->Point( RECT_TOPRIGHT ).GetPosition();
559  VECTOR2I botLeft = m_editPoints->Point( RECT_BOTLEFT ).GetPosition();
560  VECTOR2I botRight = m_editPoints->Point( RECT_BOTRIGHT ).GetPosition();
561 
562  pinEditedCorner( getEditedPointIndex(), Mils2iu( 50 ), Mils2iu( 50 ),
563  topLeft, topRight, botLeft, botRight, &gridHelper );
564 
565  double oldWidth = bitmap->GetSize().x;
566  double newWidth = topRight.x - topLeft.x;
567  double widthRatio = newWidth / oldWidth;
568 
569  double oldHeight = bitmap->GetSize().y;
570  double newHeight = botLeft.y - topLeft.y;
571  double heightRatio = newHeight / oldHeight;
572 
573  bitmap->SetImageScale( bitmap->GetImageScale() * std::min( widthRatio, heightRatio ) );
574  }
575  break;
576 
577  case SCH_SHEET_T:
578  {
579  SCH_SHEET* sheet = (SCH_SHEET*) item;
580  EE_GRID_HELPER gridHelper( m_toolMgr );
581  VECTOR2I topLeft = m_editPoints->Point( RECT_TOPLEFT ).GetPosition();
582  VECTOR2I topRight = m_editPoints->Point( RECT_TOPRIGHT ).GetPosition();
583  VECTOR2I botLeft = m_editPoints->Point( RECT_BOTLEFT ).GetPosition();
584  VECTOR2I botRight = m_editPoints->Point( RECT_BOTRIGHT ).GetPosition();
585  int edited = getEditedPointIndex();
586 
588  sheet->GetMinWidth( edited == RECT_TOPRIGHT || edited == RECT_BOTRIGHT ),
589  sheet->GetMinHeight( edited == RECT_BOTLEFT || edited == RECT_BOTRIGHT ),
590  topLeft, topRight, botLeft, botRight, &gridHelper );
591 
592  // Pin positions are relative to origin. Attempt to leave them where they
593  // are if the origin moves.
594  wxPoint originDelta = sheet->GetPosition() - (wxPoint) topLeft;
595 
596  sheet->SetPosition( (wxPoint) topLeft );
597  sheet->SetSize( wxSize( botRight.x - topLeft.x, botRight.y - topLeft.y ) );
598 
599  // Update the fields if we're in autoplace mode
601  sheet->AutoplaceFields( /* aScreen */ nullptr, /* aManual */ false );
602 
603  // Keep sheet pins attached to edges:
604  for( SCH_SHEET_PIN* pin : sheet->GetPins() )
605  {
606  wxPoint pos = pin->GetPosition();
607 
608  pos += originDelta;
609 
610  switch( pin->GetSide() )
611  {
612  case SHEET_SIDE::LEFT: pos.x = topLeft.x; break;
613  case SHEET_SIDE::RIGHT: pos.x = topRight.x; break;
614  case SHEET_SIDE::TOP: pos.y = topLeft.y; break;
615  case SHEET_SIDE::BOTTOM: pos.y = botLeft.y; break;
616  case SHEET_SIDE::UNDEFINED: break;
617  }
618 
619  pin->SetPosition( pos );
620  }
621  }
622  break;
623 
624  case SCH_LINE_T:
625  {
626  SCH_LINE* line = (SCH_LINE*) item;
627 
628  line->SetStartPoint( (wxPoint) m_editPoints->Point( LINE_START ).GetPosition() );
629  line->SetEndPoint( (wxPoint) m_editPoints->Point( LINE_END ).GetPosition() );
630 
631  std::pair<EDA_ITEM*, int> connected = m_editPoints->Point( LINE_START ).GetConnected();
632 
633  if( connected.first )
634  {
635  if( connected.second == STARTPOINT )
636  static_cast<SCH_LINE*>( connected.first )->SetStartPoint( line->GetPosition() );
637  else if( connected.second == ENDPOINT )
638  static_cast<SCH_LINE*>( connected.first )->SetEndPoint( line->GetPosition() );
639 
640  updateItem( connected.first, true );
641  }
642 
643  connected = m_editPoints->Point( LINE_END ).GetConnected();
644 
645  if( connected.first )
646  {
647  if( connected.second == STARTPOINT )
648  static_cast<SCH_LINE*>( connected.first )->SetStartPoint( line->GetEndPoint() );
649  else if( connected.second == ENDPOINT )
650  static_cast<SCH_LINE*>( connected.first )->SetEndPoint( line->GetEndPoint() );
651 
652  updateItem( connected.first, true );
653  }
654  }
655  break;
656 
657  default:
658  break;
659  }
660 
661  updateItem( item, true );
662  m_frame->SetMsgPanel( item );
663 }
664 
665 
667 {
668  if( !m_editPoints )
669  return;
670 
671  EDA_ITEM* item = m_editPoints->GetParent();
672 
673  if( !item )
674  return;
675 
676  switch( item->Type() )
677  {
678  case LIB_SHAPE_T:
679  {
680  LIB_SHAPE* shape = static_cast<LIB_SHAPE*>( item );
681 
682  switch( shape->GetShape() )
683  {
684  case SHAPE_T::ARC:
685  m_editPoints->Point( ARC_CENTER ).SetPosition( mapCoords( shape->GetPosition() ) );
686  m_editPoints->Point( ARC_START ).SetPosition( mapCoords( shape->GetStart() ) );
687  m_editPoints->Point( ARC_END ).SetPosition( mapCoords( shape->GetEnd() ) );
688  break;
689 
690  case SHAPE_T::CIRCLE:
691  m_editPoints->Point( CIRC_CENTER ).SetPosition( mapCoords( shape->GetPosition() ) );
692  m_editPoints->Point( CIRC_END ).SetPosition( mapCoords( shape->GetEnd() ) );
693  break;
694 
695  case SHAPE_T::POLY:
696  {
697  if( (int) m_editPoints->PointsSize() != shape->GetPointCount() )
698  {
699  getView()->Remove( m_editPoints.get() );
700  m_editedPoint = nullptr;
702  getView()->Add( m_editPoints.get() );
703  }
704  else
705  {
706  int ii = 0;
707 
708  for( const VECTOR2I& pt : shape->GetPolyShape().Outline( 0 ).CPoints() )
709  m_editPoints->Point( ii++ ).SetPosition( mapCoords( pt ) );
710  }
711 
712  break;
713  }
714 
715  case SHAPE_T::RECT:
716  {
717  // point editor works only with rectangles having width and height > 0
718  // Some symbols can have rectangles with width or height < 0
719  // So normalize the size:
720  BOX2I dummy;
721  dummy.SetOrigin( mapCoords( shape->GetPosition() ) );
722  dummy.SetEnd( mapCoords( shape->GetEnd() ) );
723  dummy.Normalize();
724  VECTOR2I topLeft = dummy.GetPosition();
725  VECTOR2I botRight = dummy.GetEnd();
726 
727  m_editPoints->Point( RECT_TOPLEFT ).SetPosition( topLeft );
728  m_editPoints->Point( RECT_TOPRIGHT ).SetPosition( VECTOR2I( botRight.x, topLeft.y ) );
729  m_editPoints->Point( RECT_BOTLEFT ).SetPosition( VECTOR2I( topLeft.x, botRight.y ) );
730  m_editPoints->Point( RECT_BOTRIGHT ).SetPosition( botRight );
731  }
732  break;
733 
734  case SHAPE_T::BEZIER:
735  // TODO
736  break;
737 
738  default:
739  wxFAIL_MSG( wxT( "EE_POINT_EDITOR::updatePoints not implemented for " )
740  + shape->SHAPE_T_asString() );
741  }
742  }
743  break;
744 
745  case SCH_BITMAP_T:
746  {
747  SCH_BITMAP* bitmap = (SCH_BITMAP*) item;
748  wxPoint topLeft = bitmap->GetPosition() - bitmap->GetSize() / 2;
749  wxPoint botRight = bitmap->GetPosition() + bitmap->GetSize() / 2;
750 
751  m_editPoints->Point( RECT_TOPLEFT ).SetPosition( topLeft );
752  m_editPoints->Point( RECT_TOPRIGHT ).SetPosition( botRight.x, topLeft.y );
753  m_editPoints->Point( RECT_BOTLEFT ).SetPosition( topLeft.x, botRight.y );
754  m_editPoints->Point( RECT_BOTRIGHT ).SetPosition( botRight );
755  }
756  break;
757 
758  case SCH_SHEET_T:
759  {
760  SCH_SHEET* sheet = (SCH_SHEET*) item;
761  wxPoint topLeft = sheet->GetPosition();
762  wxPoint botRight = sheet->GetPosition() + sheet->GetSize();
763 
764  m_editPoints->Point( RECT_TOPLEFT ).SetPosition( topLeft );
765  m_editPoints->Point( RECT_TOPRIGHT ).SetPosition( botRight.x, topLeft.y );
766  m_editPoints->Point( RECT_BOTLEFT ).SetPosition( topLeft.x, botRight.y );
767  m_editPoints->Point( RECT_BOTRIGHT ).SetPosition( botRight );
768  }
769  break;
770 
771  case SCH_LINE_T:
772  {
773  SCH_LINE* line = (SCH_LINE*) item;
774 
775  m_editPoints->Point( LINE_START ).SetPosition( line->GetStartPoint() );
776  m_editPoints->Point( LINE_END ).SetPosition( line->GetEndPoint() );
777  }
778  break;
779 
780  default:
781  break;
782  }
783 
784  getView()->Update( m_editPoints.get() );
785 }
786 
787 
789 {
791 
792  if( aPoint )
793  {
795  controls->ForceCursorPosition( true, aPoint->GetPosition() );
796  controls->ShowCursor( true );
797  }
798  else
799  {
800  if( m_frame->ToolStackIsEmpty() )
801  controls->ShowCursor( false );
802 
803  controls->ForceCursorPosition( false );
804  }
805 
806  m_editedPoint = aPoint;
807 }
808 
809 
811 {
812  if( !m_editPoints || !m_editedPoint || m_editPoints->GetParent()->Type() != LIB_SHAPE_T )
813  return false;
814 
815  LIB_SHAPE* shape = static_cast<LIB_SHAPE*>( m_editPoints->GetParent() );
816 
817  if( shape->GetPolyShape().IsEmpty() )
818  return false;
819 
820  SHAPE_LINE_CHAIN& poly = shape->GetPolyShape().Outline( 0 );
821 
822  if( poly.GetPointCount() < 3 )
823  return false;
824 
825  for( const VECTOR2I& pt : poly.CPoints() )
826  {
827  if( pt == mapCoords( m_editedPoint->GetPosition() ) )
828  return true;
829  }
830 
831  return false;
832 }
833 
834 
836 {
837  if( !m_editPoints || m_editPoints->GetParent()->Type() != LIB_SHAPE_T )
838  return false;
839 
840  LIB_SHAPE* shape = static_cast<LIB_SHAPE*>( m_editPoints->GetParent() );
841 
842  if( shape->GetShape() != SHAPE_T::POLY )
843  return false;
844 
845  VECTOR2I cursorPos = getViewControls()->GetCursorPosition();
846  double threshold = getView()->ToWorld( EDIT_POINT::POINT_SIZE );
847 
848  return shape->HitTest( (wxPoint) cursorPos, (int) threshold );
849 }
850 
851 
853 {
854  if( !m_editPoints || m_editPoints->GetParent()->Type() != LIB_SHAPE_T )
855  return 0;
856 
857  LIB_SHAPE* shape = static_cast<LIB_SHAPE*>( m_editPoints->GetParent() );
858  SHAPE_LINE_CHAIN& poly = shape->GetPolyShape().Outline( 0 );
859 
861  wxPoint pos = mapCoords( cursor );
862  int currentMinDistance = INT_MAX;
863  int closestLineStart = 0;
864 
865  for( unsigned i = 0; i < poly.GetPointCount() - 1; ++i )
866  {
867  int distance = (int) DistanceLinePoint( (wxPoint) poly.CPoint( i ),
868  (wxPoint) poly.CPoint( i + 1 ), pos );
869 
870  if( distance < currentMinDistance )
871  {
872  currentMinDistance = distance;
873  closestLineStart = i;
874  }
875  }
876 
877  saveItemsToUndo();
878  poly.Insert( closestLineStart + 1, pos );
879 
880  updateItem( shape, true );
881  updatePoints();
882 
883  m_frame->OnModify();
884 
885  return 0;
886 }
887 
888 
890 {
891  if( !m_editPoints || !m_editedPoint || m_editPoints->GetParent()->Type() != LIB_SHAPE_T )
892  return 0;
893 
894  LIB_SHAPE* shape = static_cast<LIB_SHAPE*>( m_editPoints->GetParent() );
895  SHAPE_LINE_CHAIN& poly = shape->GetPolyShape().Outline( 0 );
896 
897  if( poly.GetPointCount() < 3 )
898  return 0;
899 
900  saveItemsToUndo();
901  poly.Remove( getEditedPointIndex() );
902 
903  updateItem( shape, true );
904  updatePoints();
905 
906  m_frame->OnModify();
907 
908  return 0;
909 }
910 
911 
913 {
914  updatePoints();
915  return 0;
916 }
917 
918 
920 {
921  if( m_isSymbolEditor )
922  {
923  saveCopyInUndoList( m_editPoints->GetParent()->GetParent(), UNDO_REDO::LIBEDIT );
924  }
925  else
926  {
928 
929  if( m_editPoints->GetParent()->Type() == SCH_LINE_T )
930  {
931  std::pair<EDA_ITEM*, int> connected = m_editPoints->Point( LINE_START ).GetConnected();
932 
933  if( connected.first )
934  saveCopyInUndoList( (SCH_ITEM*) connected.first, UNDO_REDO::CHANGED, true );
935 
936  connected = m_editPoints->Point( LINE_END ).GetConnected();
937 
938  if( connected.first )
939  saveCopyInUndoList( (SCH_ITEM*) connected.first, UNDO_REDO::CHANGED, true );
940  }
941  }
942 }
943 
944 
946 {
947  if( m_isSymbolEditor )
948  static_cast<SYMBOL_EDIT_FRAME*>( m_frame )->RollbackSymbolFromUndo();
949  else
950  static_cast<SCH_EDIT_FRAME*>( m_frame )->RollbackSchematicFromUndo();
951 }
952 
953 
955 {
962 }
963 
964 
int Main(const TOOL_EVENT &aEvent)
virtual void ShowCursor(bool aEnabled)
Enable or disables display of cursor.
EE_TYPE OfType(KICAD_T aType) const
Definition: sch_rtree.h:230
void Reset(RESET_REASON aReason) override
Bring the tool to a known, initial state.
Definition: ee_tool_base.h:86
static const TOOL_EVENT SelectedEvent
Definition: actions.h:200
#define STARTPOINT
When a line is selected, these flags indicate which.
void SetCurrentCursor(KICURSOR aCursor)
Set the current cursor shape for this panel.
virtual size_t GetPointCount() const 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.
static TOOL_ACTION activatePointEditor
Definition: actions.h:168
void SetEnd(const wxPoint &aEnd)
Definition: eda_shape.h:135
wxPoint GetStartPoint() const
Definition: sch_line.h:90
int clearEditedPoints(const TOOL_EVENT &aEvent)
Set the current point being edited. NULL means none.
VECTOR2D ToWorld(const VECTOR2D &aCoord, bool aAbsolute=true) const
Converts a screen space point/vector to a point/vector in world space coordinates.
Definition: view.cpp:449
const wxPoint & GetStart() const
Return the starting point of the graphic.
Definition: eda_shape.h:106
int GetMinWidth(bool aFromLeft) const
Return the minimum width of the sheet based on the widths of the sheet pin text.
Definition: sch_sheet.cpp:461
static TOOL_ACTION pointEditorAddCorner
Definition: ee_actions.h:136
CONDITIONAL_MENU & GetMenu()
Definition: tool_menu.cpp:46
void updateEditedPoint(const TOOL_EVENT &aEvent)
Clear references to the points.
TOOL_MANAGER * m_toolMgr
Definition: tool_base.h:214
bool IsEmpty() const
SCH_SCREEN * GetScreen() const override
Return a pointer to a BASE_SCREEN or one of its derivatives.
virtual void Remove(VIEW_ITEM *aItem)
Remove a VIEW_ITEM from the view.
Definition: view.cpp:350
TOOL_MENU & GetToolMenu()
bool IsMotion() const
Definition: tool_event.h:300
void SetEditState(int aState)
Definition: lib_shape.h:79
EDIT_POINT * m_editedPoint
< Currently edited point, NULL if there is none.
void updatePoints()
Update which point is being edited.
int GetMinHeight(bool aFromTop) const
Return the minimum height that the sheet can be resized based on the sheet pin positions.
Definition: sch_sheet.cpp:495
#define ENDPOINT
ends. (Used to support dragging.)
virtual wxPoint GetPosition() const
Definition: eda_item.h:251
wxPoint GetPosition() const override
Definition: sch_bitmap.h:136
VECTOR2< int > VECTOR2I
Definition: vector2d.h:622
int modifiedSelection(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
FIELDS_AUTOPLACED GetFieldsAutoplaced() const
Return whether the fields have been automatically placed.
Definition: sch_item.h:424
void SetEndPoint(const wxPoint &aPosition)
Definition: sch_line.h:94
bool IsNew() const
Definition: eda_item.h:118
bool Init() override
Init() is called once upon a registration of the tool.
Definition: ee_tool_base.h:66
bool addCornerCondition(const SELECTION &aSelection)
EE_SELECTION & GetSelection()
Return the set of currently selected items.
static LIB_SYMBOL * dummy()
Used to draw a dummy shape when a LIB_SYMBOL is not found in library.
Definition: sch_symbol.cpp:72
void SetPosition(const wxPoint &aPosition) override
Definition: lib_shape.h:88
int GetPointCount() const
Definition: eda_shape.cpp:1222
bool IsDrag(int aButtonMask=BUT_ANY) const
Definition: tool_event.h:285
const wxPoint & GetEnd() const
Return the ending point of the graphic.
Definition: eda_shape.h:131
wxSize GetSize() const
Definition: sch_bitmap.cpp:125
bool Init() override
Init() is called once upon a registration of the tool.
virtual VECTOR2I GetPosition() const
Return coordinates of an EDIT_POINT.
Definition: edit_points.h:70
static TOOL_ACTION pointEditorRemoveCorner
Definition: ee_actions.h:137
const std::vector< VECTOR2I > & CPoints() const
void SetMsgPanel(const std::vector< MSG_PANEL_ITEM > &aList)
Clear the message panel and populates it with the contents of aList.
void saveCopyInUndoList(EDA_ITEM *aItem, UNDO_REDO aType, bool aAppend=false)
Definition: ee_tool_base.h:134
virtual void OnModify()
Must be called after a model change in order to set the "modify" flag and do other frame-specific pro...
virtual void CaptureCursor(bool aEnabled)
Force the cursor to stay within the drawing panel area.
SHAPE_LINE_CHAIN & Outline(int aIndex)
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.
void SetImageScale(double aScale)
Definition: sch_bitmap.h:71
Generic, UI-independent tool event.
Definition: tool_event.h:152
int removeCorner(const TOOL_EVENT &aEvent)
bool ToolStackIsEmpty()
Definition: tools_holder.h:116
An interface for classes handling user events controlling the view behavior such as zooming,...
EE_SELECTION_TOOL * m_selectionTool
Definition: ee_tool_base.h:179
const VECTOR2D DragOrigin() const
Returns information about mouse buttons state.
Definition: tool_event.h:269
static const TOOL_EVENT ClearedEvent
Selected item had a property changed (except movement)
Definition: actions.h:202
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
void updateParentItem() const
< Update item's points with edit points.
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
void CalcEdit(const wxPoint &aPosition) override
Calculate the attributes of an item at aPosition when it is being edited.
Definition: lib_shape.h:76
bool HitTest(const wxPoint &aPosition, int aAccuracy=0) const override
Test if aPosition is inside or on the boundary of this item.
Definition: lib_shape.cpp:45
static float distance(const SFVEC2UI &a, const SFVEC2UI &b)
int addCorner(const TOOL_EVENT &aEvent)
TOOL_ACTION handlers.
wxString SHAPE_T_asString() const
Definition: eda_shape.cpp:71
static VECTOR2D mapCoords(const wxPoint &aCoord)
wxPoint GetPosition() const override
Definition: sch_sheet.h:379
LINE_POINTS
int NewOutline()
Creates a new hole in a given outline.
Object to handle a bitmap image that can be inserted in a schematic.
Definition: sch_bitmap.h:40
KIGFX::VIEW * getView() const
Returns the instance of #VIEW object used in the application.
Definition: tool_base.cpp:36
SHAPE_POLY_SET & GetPolyShape()
Definition: eda_shape.h:227
virtual void SetAutoPan(bool aEnabled)
Turn on/off auto panning (this feature is used when there is a tool active (eg.
bool removeCornerCondition(const SELECTION &aSelection)
void updateItem(EDA_ITEM *aItem, bool aUpdateRTree) const
Similar to getView()->Update(), but handles items that are redrawn by their parents and updating the ...
Definition: ee_tool_base.h:103
Sheet symbol placed in a schematic, and is the entry point for a sub schematic.
Definition: sch_sheet.h:54
void SetSize(const wxSize &aSize)
Definition: sch_sheet.h:105
std::vector< SCH_SHEET_PIN * > & GetPins()
Definition: sch_sheet.h:183
void Reset(RESET_REASON aReason) override
Bring the tool to a known, initial state.
ARC_POINTS
std::shared_ptr< EDIT_POINTS > m_editPoints
Segment description base class to describe items which have 2 end points (track, wire,...
Definition: sch_line.h:37
int getEditedPointIndex() const
Represent a polyline containing arcs as well as line segments: A chain of connected line and/or arc s...
wxSize GetSize() const
Definition: sch_sheet.h:104
wxPoint GetPosition() const override
Definition: sch_line.h:231
CIRCLE_POINTS
void SetPosition(const wxPoint &aPosition) override
Definition: sch_sheet.cpp:879
double GetImageScale() const
Definition: sch_bitmap.h:66
EE_RTREE & Items()
Gets the full RTree, usually for iterating.
Definition: sch_screen.h:110
virtual void Refresh(bool aEraseBackground=true, const wxRect *aRect=nullptr) override
Update the board display after modifying it by a python script (note: it is automatically called by a...
int Size() const
Returns the number of selected parts.
Definition: selection.h:104
void setEditedPoint(EDIT_POINT *aPoint)
Return true if aPoint is the currently modified point.
A base class for most all the KiCad significant classes used in schematics and boards.
Definition: eda_item.h:99
RESET_REASON
Determine the reason of reset for a tool.
Definition: tool_base.h:77
static const int POINT_SIZE
Border size when not hovering.
Definition: edit_points.h:186
void Activate()
Run the tool.
A foundation class for a tool operating on a schematic or symbol.
Definition: ee_tool_base.h:49
virtual void Add(VIEW_ITEM *aItem, int aDrawPriority=-1)
Add a VIEW_ITEM to the view.
Definition: view.cpp:320
Represent a single point that can be used for modifying items.
Definition: edit_points.h:47
SHAPE_T GetShape() const
Definition: eda_shape.h:101
void AutoplaceFields(SCH_SCREEN *aScreen, bool aManual) override
Definition: sch_sheet.cpp:579
KIGFX::VIEW_CONTROLS * getViewControls() const
Return the instance of VIEW_CONTROLS object used in the application.
Definition: tool_base.cpp:42
Hold a (potentially large) number of VIEW_ITEMs and renders them on a graphics device provided by the...
Definition: view.h:68
wxPoint GetPosition() const override
Definition: lib_shape.h:87
static void pinEditedCorner(int aEditedPointIndex, int minWidth, int minHeight, VECTOR2I &topLeft, VECTOR2I &topRight, VECTOR2I &botLeft, VECTOR2I &botRight, EE_GRID_HELPER *aGrid)
Update the coordinates of 4 corners of a rectangle, according to constraints and the moved corner.
void setTransitions() override
This method is meant to be overridden in order to specify handlers for events.
RECTANGLE_POINTS
A shim class between EDA_DRAW_FRAME and several derived classes: SYMBOL_EDIT_FRAME,...
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
static std::shared_ptr< EDIT_POINTS > Make(EDA_ITEM *aItem, SCH_BASE_FRAME *frame)
const VECTOR2D Position() const
Returns the point where dragging has started.
Definition: tool_event.h:263
double DistanceLinePoint(const wxPoint &linePointA, const wxPoint &linePointB, const wxPoint &referencePoint)
Compute the distance between a line and a reference point Reference: http://mathworld....
Definition: trigo.h:163
VECTOR2D GetCursorPosition() const
Return the current cursor position in world coordinates.
EDA_ITEM * Front() const
Definition: selection.h:145
virtual void Update(const VIEW_ITEM *aItem, int aUpdateFlags) const
For dynamic VIEWs, inform the associated VIEW that the graphical representation of this item has chan...
Definition: view.cpp:1570
KICAD_T Type() const
Returns the type of object.
Definition: eda_item.h:112
int Append(int x, int y, int aOutline=-1, int aHole=-1, bool aAllowDuplication=false)
Add a new vertex to the contour indexed by aOutline and aHole (defaults to the outline of the last po...
The symbol library editor main window.
virtual void SetPosition(const VECTOR2I &aPosition)
Set new coordinates for an EDIT_POINT.
Definition: edit_points.h:106
VECTOR2I AlignGrid(const VECTOR2I &aPoint) const
Definition: grid_helper.cpp:83
wxPoint GetEndPoint() const
Definition: sch_line.h:93