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-2022 KiCad Developers, see AUTHORS.txt for contributors.
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, you may find one here:
19 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
20 * or you may search the http://www.gnu.org website for the version 2 license,
21 * or you may write to the Free Software Foundation, Inc.,
22 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
23 */
24
25#include <functional>
26using 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 <sch_edit_frame.h>
36#include <sch_line.h>
37#include <sch_bitmap.h>
38#include <sch_sheet.h>
39#include <sch_textbox.h>
40#include <sch_shape.h>
41#include <sch_sheet_pin.h>
42#include <symbol_edit_frame.h>
43#include <lib_shape.h>
44#include <lib_textbox.h>
45
46
47// Few constants to avoid using bare numbers for point indices
49{
51};
52
54{
56};
57
59{
61};
62
64{
66};
67
68
70{
72};
73
75{
76public:
77 static std::shared_ptr<EDIT_POINTS> Make( EDA_ITEM* aItem, SCH_BASE_FRAME* frame )
78 {
79 std::shared_ptr<EDIT_POINTS> points = std::make_shared<EDIT_POINTS>( aItem );
80
81 if( !aItem )
82 return points;
83
84 // Generate list of edit points based on the item type
85 switch( aItem->Type() )
86 {
87 case LIB_SHAPE_T:
88 {
89 LIB_SHAPE* shape = static_cast<LIB_SHAPE*>( aItem );
90
91 switch( shape->GetShape() )
92 {
93 case SHAPE_T::ARC:
94 points->AddPoint( mapCoords( shape->GetPosition() ) );
95 points->AddPoint( mapCoords( shape->GetStart() ) );
96 points->AddPoint( mapCoords( shape->GetEnd() ) );
97 break;
98
99 case SHAPE_T::CIRCLE:
100 points->AddPoint( mapCoords( shape->GetPosition() ) );
101 points->AddPoint( mapCoords( shape->GetEnd() ) );
102 break;
103
104 case SHAPE_T::RECT:
105 {
106 shape->Normalize();
107
108 VECTOR2I topLeft = mapCoords( shape->GetPosition() );
109 VECTOR2I botRight = mapCoords( shape->GetEnd() );
110
111 points->AddPoint( topLeft );
112 points->AddPoint( VECTOR2I( botRight.x, topLeft.y ) );
113 points->AddPoint( VECTOR2I( topLeft.x, botRight.y ) );
114 points->AddPoint( botRight );
115
116 points->AddLine( points->Point( RECT_TOPLEFT ), points->Point( RECT_TOPRIGHT ) );
117 points->Line( RECT_TOP ).SetConstraint( new EC_PERPLINE( points->Line( RECT_TOP ) ) );
118 points->AddLine( points->Point( RECT_TOPRIGHT ), points->Point( RECT_BOTRIGHT ) );
119 points->Line( RECT_RIGHT ).SetConstraint( new EC_PERPLINE( points->Line( RECT_RIGHT ) ) );
120 points->AddLine( points->Point( RECT_BOTRIGHT ), points->Point( RECT_BOTLEFT ) );
121 points->Line( RECT_BOT ).SetConstraint( new EC_PERPLINE( points->Line( RECT_BOT ) ) );
122 points->AddLine( points->Point( RECT_BOTLEFT ), points->Point( RECT_TOPLEFT ) );
123 points->Line( RECT_LEFT ).SetConstraint( new EC_PERPLINE( points->Line( RECT_LEFT ) ) );
124
125 break;
126 }
127
128 case SHAPE_T::POLY:
129 for( const VECTOR2I& pt : shape->GetPolyShape().Outline( 0 ).CPoints() )
130 points->AddPoint( mapCoords( pt ) );
131
132 break;
133
134 case SHAPE_T::BEZIER:
135 // TODO
136 break;
137
138 default:
140 }
141
142 break;
143 }
144
145 case LIB_TEXTBOX_T:
146 {
147 LIB_TEXTBOX* textBox = static_cast<LIB_TEXTBOX*>( aItem );
148
149 textBox->Normalize();
150
151 VECTOR2I topLeft = mapCoords( textBox->GetPosition() );
152 VECTOR2I botRight = mapCoords( textBox->GetEnd() );
153
154 points->AddPoint( topLeft );
155 points->AddPoint( VECTOR2I( botRight.x, topLeft.y ) );
156 points->AddPoint( VECTOR2I( topLeft.x, botRight.y ) );
157 points->AddPoint( botRight );
158
159 points->AddLine( points->Point( RECT_TOPLEFT ), points->Point( RECT_TOPRIGHT ) );
160 points->Line( RECT_TOP ).SetConstraint( new EC_PERPLINE( points->Line( RECT_TOP ) ) );
161 points->AddLine( points->Point( RECT_TOPRIGHT ), points->Point( RECT_BOTRIGHT ) );
162 points->Line( RECT_RIGHT ).SetConstraint( new EC_PERPLINE( points->Line( RECT_RIGHT ) ) );
163 points->AddLine( points->Point( RECT_BOTRIGHT ), points->Point( RECT_BOTLEFT ) );
164 points->Line( RECT_BOT ).SetConstraint( new EC_PERPLINE( points->Line( RECT_BOT ) ) );
165 points->AddLine( points->Point( RECT_BOTLEFT ), points->Point( RECT_TOPLEFT ) );
166 points->Line( RECT_LEFT ).SetConstraint( new EC_PERPLINE( points->Line( RECT_LEFT ) ) );
167
168 break;
169 }
170
171 case SCH_SHAPE_T:
172 {
173 SCH_SHAPE* shape = static_cast<SCH_SHAPE*>( aItem );
174
175 switch( shape->GetShape() )
176 {
177 case SHAPE_T::ARC:
178 points->AddPoint( shape->GetPosition() );
179 points->AddPoint( shape->GetStart() );
180 points->AddPoint( shape->GetEnd() );
181 break;
182
183 case SHAPE_T::CIRCLE:
184 points->AddPoint( shape->GetPosition() );
185 points->AddPoint( shape->GetEnd() );
186 break;
187
188 case SHAPE_T::RECT:
189 {
190 shape->Normalize();
191
192 VECTOR2I topLeft = shape->GetPosition();
193 VECTOR2I botRight = shape->GetEnd();
194
195 points->AddPoint( topLeft );
196 points->AddPoint( VECTOR2I( botRight.x, topLeft.y ) );
197 points->AddPoint( VECTOR2I( topLeft.x, botRight.y ) );
198 points->AddPoint( botRight );
199
200 points->AddLine( points->Point( RECT_TOPLEFT ), points->Point( RECT_TOPRIGHT ) );
201 points->Line( RECT_TOP ).SetConstraint( new EC_PERPLINE( points->Line( RECT_TOP ) ) );
202 points->AddLine( points->Point( RECT_TOPRIGHT ), points->Point( RECT_BOTRIGHT ) );
203 points->Line( RECT_RIGHT ).SetConstraint( new EC_PERPLINE( points->Line( RECT_RIGHT ) ) );
204 points->AddLine( points->Point( RECT_BOTRIGHT ), points->Point( RECT_BOTLEFT ) );
205 points->Line( RECT_BOT ).SetConstraint( new EC_PERPLINE( points->Line( RECT_BOT ) ) );
206 points->AddLine( points->Point( RECT_BOTLEFT ), points->Point( RECT_TOPLEFT ) );
207 points->Line( RECT_LEFT ).SetConstraint( new EC_PERPLINE( points->Line( RECT_LEFT ) ) );
208
209 break;
210 }
211
212 case SHAPE_T::POLY:
213 for( const VECTOR2I& pt : shape->GetPolyShape().Outline( 0 ).CPoints() )
214 points->AddPoint( pt );
215
216 break;
217
218 case SHAPE_T::BEZIER:
219 // TODO
220 break;
221
222 default:
224 }
225
226 break;
227 }
228
229 case SCH_TEXTBOX_T:
230 {
231 SCH_TEXTBOX* textBox = static_cast<SCH_TEXTBOX*>( aItem );
232
233 textBox->Normalize();
234
235 VECTOR2I topLeft = textBox->GetPosition();
236 VECTOR2I botRight = textBox->GetEnd();
237
238 points->AddPoint( topLeft );
239 points->AddPoint( VECTOR2I( botRight.x, topLeft.y ) );
240 points->AddPoint( VECTOR2I( topLeft.x, botRight.y ) );
241 points->AddPoint( botRight );
242
243 points->AddLine( points->Point( RECT_TOPLEFT ), points->Point( RECT_TOPRIGHT ) );
244 points->Line( RECT_TOP ).SetConstraint( new EC_PERPLINE( points->Line( RECT_TOP ) ) );
245 points->AddLine( points->Point( RECT_TOPRIGHT ), points->Point( RECT_BOTRIGHT ) );
246 points->Line( RECT_RIGHT ).SetConstraint( new EC_PERPLINE( points->Line( RECT_RIGHT ) ) );
247 points->AddLine( points->Point( RECT_BOTRIGHT ), points->Point( RECT_BOTLEFT ) );
248 points->Line( RECT_BOT ).SetConstraint( new EC_PERPLINE( points->Line( RECT_BOT ) ) );
249 points->AddLine( points->Point( RECT_BOTLEFT ), points->Point( RECT_TOPLEFT ) );
250 points->Line( RECT_LEFT ).SetConstraint( new EC_PERPLINE( points->Line( RECT_LEFT ) ) );
251
252 break;
253 }
254
255 case SCH_SHEET_T:
256 {
257 SCH_SHEET* sheet = (SCH_SHEET*) aItem;
258 VECTOR2I topLeft = sheet->GetPosition();
259 VECTOR2I botRight = sheet->GetPosition() + sheet->GetSize();
260
261 points->AddPoint( topLeft );
262 points->AddPoint( VECTOR2I( botRight.x, topLeft.y ) );
263 points->AddPoint( VECTOR2I( topLeft.x, botRight.y ) );
264 points->AddPoint( botRight );
265
266 points->AddLine( points->Point( RECT_TOPLEFT ), points->Point( RECT_TOPRIGHT ) );
267 points->Line( RECT_TOP ).SetConstraint( new EC_PERPLINE( points->Line( RECT_TOP ) ) );
268 points->AddLine( points->Point( RECT_TOPRIGHT ), points->Point( RECT_BOTRIGHT ) );
269 points->Line( RECT_RIGHT ).SetConstraint( new EC_PERPLINE( points->Line( RECT_RIGHT ) ) );
270 points->AddLine( points->Point( RECT_BOTRIGHT ), points->Point( RECT_BOTLEFT ) );
271 points->Line( RECT_BOT ).SetConstraint( new EC_PERPLINE( points->Line( RECT_BOT ) ) );
272 points->AddLine( points->Point( RECT_BOTLEFT ), points->Point( RECT_TOPLEFT ) );
273 points->Line( RECT_LEFT ).SetConstraint( new EC_PERPLINE( points->Line( RECT_LEFT ) ) );
274
275 break;
276 }
277
278 case SCH_BITMAP_T:
279 {
280 SCH_BITMAP* bitmap = (SCH_BITMAP*) aItem;
281 VECTOR2I topLeft = bitmap->GetPosition() - bitmap->GetSize() / 2;
282 VECTOR2I botRight = bitmap->GetPosition() + bitmap->GetSize() / 2;
283
284 points->AddPoint( topLeft );
285 points->AddPoint( VECTOR2I( botRight.x, topLeft.y ) );
286 points->AddPoint( VECTOR2I( topLeft.x, botRight.y ) );
287 points->AddPoint( botRight );
288 break;
289 }
290
291 case SCH_LINE_T:
292 {
293 SCH_LINE* line = (SCH_LINE*) aItem;
294 std::pair<EDA_ITEM*, int> connectedStart = { nullptr, STARTPOINT };
295 std::pair<EDA_ITEM*, int> connectedEnd = { nullptr, STARTPOINT };
296
297 for( SCH_ITEM* test : frame->GetScreen()->Items().OfType( SCH_LINE_T ) )
298 {
299 if( test->GetLayer() != LAYER_NOTES )
300 continue;
301
302 if( test == aItem )
303 continue;
304
305 SCH_LINE* testLine = static_cast<SCH_LINE*>( test );
306
307 if( testLine->GetStartPoint() == line->GetStartPoint() )
308 {
309 connectedStart = { testLine, STARTPOINT };
310 }
311 else if( testLine->GetEndPoint() == line->GetStartPoint() )
312 {
313 connectedStart = { testLine, ENDPOINT };
314 }
315 else if( testLine->GetStartPoint() == line->GetEndPoint() )
316 {
317 connectedEnd = { testLine, STARTPOINT };
318 }
319 else if( testLine->GetEndPoint() == line->GetEndPoint() )
320 {
321 connectedEnd = { testLine, ENDPOINT };
322 }
323 }
324
325 points->AddPoint( line->GetStartPoint(), connectedStart );
326 points->AddPoint( line->GetEndPoint(), connectedEnd );
327 break;
328 }
329
330 default:
331 points.reset();
332 break;
333 }
334
335 return points;
336 }
337
338private:
340};
341
342
344 EE_TOOL_BASE<SCH_BASE_FRAME>( "eeschema.PointEditor" ),
345 m_editedPoint( nullptr )
346{
347}
348
349
351{
352 EE_TOOL_BASE::Reset( aReason );
353
354 m_editPoints.reset();
355 m_editedPoint = nullptr;
356}
357
358
360{
362
363 auto& menu = m_selectionTool->GetToolMenu().GetMenu();
365 std::bind( &EE_POINT_EDITOR::addCornerCondition, this, _1 ) );
367 std::bind( &EE_POINT_EDITOR::removeCornerCondition, this, _1 ) );
368
369 return true;
370}
371
372
374{
375 setEditedPoint( nullptr );
376
377 return 0;
378}
379
380
382{
383 EDIT_POINT* point = m_editedPoint;
384
385 if( !m_editPoints )
386 {
387 point = nullptr;
388 }
389 else if( aEvent.IsMotion() )
390 {
391 point = m_editPoints->FindPoint( aEvent.Position(), getView() );
392 }
393 else if( aEvent.IsDrag( BUT_LEFT ) )
394 {
395 point = m_editPoints->FindPoint( aEvent.DragOrigin(), getView() );
396 }
397 else
398 {
399 point = m_editPoints->FindPoint( getViewControls()->GetCursorPosition( false ), getView() );
400 }
401
402 if( m_editedPoint != point )
403 setEditedPoint( point );
404}
405
406
408{
409 if( !m_selectionTool )
410 return 0;
411
412 if( m_isSymbolEditor )
413 {
414 SYMBOL_EDIT_FRAME* editor = getEditFrame<SYMBOL_EDIT_FRAME>();
415
416 if( !editor->IsSymbolEditable() || editor->IsSymbolAlias() )
417 return 0;
418 }
419
420 const EE_SELECTION& selection = m_selectionTool->GetSelection();
421
422 if( selection.Size() != 1 || !selection.Front()->IsType( { LIB_SHAPE_T, SCH_SHAPE_T,
423 LIB_TEXTBOX_T, SCH_TEXTBOX_T,
424 SCH_SHEET_T,
425 SCH_ITEM_LOCATE_GRAPHIC_LINE_T,
426 SCH_BITMAP_T } ) )
427 {
428 return 0;
429 }
430
431 // Wait till drawing tool is done
432 if( selection.Front()->IsNew() )
433 return 0;
434
435 Activate();
436
438 KIGFX::VIEW* view = getView();
439 EDA_ITEM* item = (EDA_ITEM*) selection.Front();
440
441 controls->ShowCursor( true );
442
444 view->Add( m_editPoints.get() );
445 setEditedPoint( nullptr );
446 updateEditedPoint( aEvent );
447 bool inDrag = false;
448 bool modified = false;
449
450 // Main loop: keep receiving events
451 while( TOOL_EVENT* evt = Wait() )
452 {
453 if( !m_editPoints || evt->IsSelectionEvent() )
454 break;
455
456 if ( !inDrag )
457 updateEditedPoint( *evt );
458
459 if( evt->IsDrag( BUT_LEFT ) && m_editedPoint )
460 {
461 if( !inDrag )
462 {
464 controls->ForceCursorPosition( false );
465 inDrag = true;
466 modified = true;
467 }
468
469 bool snap = !evt->DisableGridSnapping();
470 EDA_SHAPE* shape = dynamic_cast<EDA_SHAPE*>( item );
471
472 if( shape && shape->GetShape() == SHAPE_T::ARC && getEditedPointIndex() == ARC_CENTER )
473 snap = false;
474
475 m_editedPoint->SetPosition( controls->GetCursorPosition( snap ) );
476
477 updateParentItem( snap );
478 updatePoints();
479 }
480 else if( inDrag && evt->IsMouseUp( BUT_LEFT ) )
481 {
482 if( modified )
483 {
484 m_frame->OnModify();
485 modified = false;
486 }
487
488 controls->SetAutoPan( false );
489 inDrag = false;
490 }
491 else if( evt->IsCancelInteractive() || evt->IsActivate() )
492 {
493 if( inDrag ) // Restore the last change
494 {
496 inDrag = false;
497 modified = false;
498 break;
499 }
500 else if( evt->IsCancelInteractive() )
501 {
502 break;
503 }
504
505 if( evt->IsActivate() )
506 break;
507 }
508 else
509 {
510 evt->SetPassEvent();
511 }
512
513 controls->SetAutoPan( inDrag );
514 controls->CaptureCursor( inDrag );
515 }
516
517 controls->SetAutoPan( false );
518 controls->CaptureCursor( false );
519 setEditedPoint( nullptr );
520
521 if( m_editPoints )
522 {
523 view->Remove( m_editPoints.get() );
524
525 if( modified )
526 m_frame->OnModify();
527
528 m_editPoints.reset();
530 }
531
532 return 0;
533}
534
545void EE_POINT_EDITOR::pinEditedCorner( int minWidth, int minHeight, VECTOR2I& topLeft,
546 VECTOR2I& topRight, VECTOR2I& botLeft, VECTOR2I& botRight,
547 EE_GRID_HELPER* aGrid ) const
548{
549 if( isModified( m_editPoints->Point( RECT_TOPLEFT ) ) )
550 {
551 // pin edited point within opposite corner
552 topLeft.x = std::min( topLeft.x, botRight.x - minWidth );
553 topLeft.y = std::min( topLeft.y, botRight.y - minHeight );
554
555 if( aGrid->GetSnap() )
556 topLeft = aGrid->AlignGrid( topLeft );
557
558 // push edited point edges to adjacent corners
559 topRight.y = topLeft.y;
560 botLeft.x = topLeft.x;
561 }
562 else if( isModified( m_editPoints->Point( RECT_TOPRIGHT ) ) )
563 {
564 // pin edited point within opposite corner
565 topRight.x = std::max( topRight.x, botLeft.x + minWidth );
566 topRight.y = std::min( topRight.y, botLeft.y - minHeight );
567
568 if( aGrid->GetSnap() )
569 topRight = aGrid->AlignGrid( topRight );
570
571 // push edited point edges to adjacent corners
572 topLeft.y = topRight.y;
573 botRight.x = topRight.x;
574 }
575 else if( isModified( m_editPoints->Point( RECT_BOTLEFT ) ) )
576 {
577 // pin edited point within opposite corner
578 botLeft.x = std::min( botLeft.x, topRight.x - minWidth );
579 botLeft.y = std::max( botLeft.y, topRight.y + minHeight );
580
581 if( aGrid->GetSnap() )
582 botLeft = aGrid->AlignGrid( botLeft );
583
584 // push edited point edges to adjacent corners
585 botRight.y = botLeft.y;
586 topLeft.x = botLeft.x;
587 }
588 else if( isModified( m_editPoints->Point( RECT_BOTRIGHT ) ) )
589 {
590 // pin edited point within opposite corner
591 botRight.x = std::max( botRight.x, topLeft.x + minWidth );
592 botRight.y = std::max( botRight.y, topLeft.y + minHeight );
593
594 if( aGrid->GetSnap() )
595 botRight = aGrid->AlignGrid( botRight );
596
597 // push edited point edges to adjacent corners
598 botLeft.y = botRight.y;
599 topRight.x = botRight.x;
600 }
601 else if( isModified( m_editPoints->Line( RECT_TOP ) ) )
602 {
603 topLeft.y = std::min( topLeft.y, botRight.y - minHeight );
604
605 if( aGrid->GetSnap() )
606 topLeft = aGrid->AlignGrid( topLeft );
607 }
608 else if( isModified( m_editPoints->Line( RECT_LEFT ) ) )
609 {
610 topLeft.x = std::min( topLeft.x, botRight.x - minWidth );
611
612 if( aGrid->GetSnap() )
613 topLeft = aGrid->AlignGrid( topLeft );
614 }
615 else if( isModified( m_editPoints->Line( RECT_BOT ) ) )
616 {
617 botRight.y = std::max( botRight.y, topLeft.y + minHeight );
618
619 if( aGrid->GetSnap() )
620 botRight = aGrid->AlignGrid( botRight );
621 }
622 else if( isModified( m_editPoints->Line( RECT_RIGHT ) ) )
623 {
624 botRight.x = std::max( botRight.x, topLeft.x + minWidth );
625
626 if( aGrid->GetSnap() )
627 botRight = aGrid->AlignGrid( botRight );
628 }
629}
630
631
632void EE_POINT_EDITOR::updateParentItem( bool aSnapToGrid ) const
633{
634 EDA_ITEM* item = m_editPoints->GetParent();
635
636 if( !item )
637 return;
638
639 switch( item->Type() )
640 {
641 case LIB_SHAPE_T:
642 {
643 LIB_SHAPE* shape = static_cast<LIB_SHAPE*>( item );
644
645 switch( shape->GetShape() )
646 {
647 case SHAPE_T::ARC:
649 {
650 shape->SetEditState( 4 );
651 shape->CalcEdit( mapCoords( m_editPoints->Point( ARC_CENTER ).GetPosition() ) );
652 }
653 else if( getEditedPointIndex() == ARC_START )
654 {
655 shape->SetEditState( 2 );
656 shape->CalcEdit( mapCoords( m_editPoints->Point( ARC_START ).GetPosition() ) );
657 }
658 else if( getEditedPointIndex() == ARC_END )
659 {
660 shape->SetEditState( 3 );
661 shape->CalcEdit( mapCoords( m_editPoints->Point( ARC_END ).GetPosition() ) );
662 }
663 break;
664
665 case SHAPE_T::CIRCLE:
666 shape->SetPosition( mapCoords( m_editPoints->Point( CIRC_CENTER ).GetPosition() ) );
667 shape->SetEnd( mapCoords( m_editPoints->Point( CIRC_END ).GetPosition() ) );
668 break;
669
670 case SHAPE_T::POLY:
672 shape->GetPolyShape().NewOutline();
673
674 for( unsigned i = 0; i < m_editPoints->PointsSize(); ++i )
675 {
676 VECTOR2I pt = mapCoords( m_editPoints->Point( i ).GetPosition() );
677 shape->GetPolyShape().Append( pt.x, pt.y, -1, -1, true );
678 }
679
680 break;
681
682 case SHAPE_T::RECT:
683 {
684 EE_GRID_HELPER gridHelper( m_toolMgr );
685 VECTOR2I topLeft = m_editPoints->Point( RECT_TOPLEFT ).GetPosition();
686 VECTOR2I topRight = m_editPoints->Point( RECT_TOPRIGHT ).GetPosition();
687 VECTOR2I botLeft = m_editPoints->Point( RECT_BOTLEFT ).GetPosition();
688 VECTOR2I botRight = m_editPoints->Point( RECT_BOTRIGHT ).GetPosition();
689
690 gridHelper.SetSnap( aSnapToGrid );
691
692 pinEditedCorner( schIUScale.MilsToIU( 1 ), schIUScale.MilsToIU( 1 ), topLeft, topRight,
693 botLeft, botRight, &gridHelper );
694
695 if( isModified( m_editPoints->Point( RECT_TOPLEFT ) )
698 || isModified( m_editPoints->Point( RECT_BOTLEFT ) ) )
699 {
700 shape->SetPosition( mapCoords( topLeft ) );
701 shape->SetEnd( mapCoords( botRight ) );
702 }
703 else if( isModified( m_editPoints->Line( RECT_TOP ) ) )
704 {
705 shape->SetStartY( mapCoords( topLeft ).y );
706 }
707 else if( isModified( m_editPoints->Line( RECT_LEFT ) ) )
708 {
709 shape->SetStartX( mapCoords( topLeft ).x );
710 }
711 else if( isModified( m_editPoints->Line( RECT_BOT ) ) )
712 {
713 shape->SetEndY( mapCoords( botRight ).y );
714 }
715 else if( isModified( m_editPoints->Line( RECT_RIGHT ) ) )
716 {
717 shape->SetEndX( mapCoords( botRight ).x );
718 }
719
720 for( unsigned i = 0; i < m_editPoints->LinesSize(); ++i )
721 {
722 if( !isModified( m_editPoints->Line( i ) ) )
723 {
724 m_editPoints->Line( i ).SetConstraint(
725 new EC_PERPLINE( m_editPoints->Line( i ) ) );
726 }
727 }
728
729 break;
730 }
731
732 case SHAPE_T::BEZIER:
733 // TODO
734 break;
735
736 default:
738 }
739
740 break;
741 }
742
743 case LIB_TEXTBOX_T:
744 {
745 LIB_TEXTBOX* textbox = static_cast<LIB_TEXTBOX*>( item );
746 EE_GRID_HELPER gridHelper( m_toolMgr );
747 VECTOR2I topLeft = m_editPoints->Point( RECT_TOPLEFT ).GetPosition();
748 VECTOR2I topRight = m_editPoints->Point( RECT_TOPRIGHT ).GetPosition();
749 VECTOR2I botLeft = m_editPoints->Point( RECT_BOTLEFT ).GetPosition();
750 VECTOR2I botRight = m_editPoints->Point( RECT_BOTRIGHT ).GetPosition();
751
752 gridHelper.SetSnap( aSnapToGrid );
753
754 pinEditedCorner( schIUScale.MilsToIU( 1 ), schIUScale.MilsToIU( 1 ), topLeft, topRight,
755 botLeft, botRight, &gridHelper );
756
757 if( isModified( m_editPoints->Point( RECT_TOPLEFT ) )
760 || isModified( m_editPoints->Point( RECT_BOTLEFT ) ) )
761 {
762 textbox->SetPosition( mapCoords( topLeft ) );
763 textbox->SetEnd( mapCoords( botRight ) );
764 }
765 else if( isModified( m_editPoints->Line( RECT_TOP ) ) )
766 {
767 textbox->SetStartY( mapCoords( topLeft ).y );
768 }
769 else if( isModified( m_editPoints->Line( RECT_LEFT ) ) )
770 {
771 textbox->SetStartX( mapCoords( topLeft ).x );
772 }
773 else if( isModified( m_editPoints->Line( RECT_BOT ) ) )
774 {
775 textbox->SetEndY( mapCoords( botRight ).y );
776 }
777 else if( isModified( m_editPoints->Line( RECT_RIGHT ) ) )
778 {
779 textbox->SetEndX( mapCoords( botRight ).x );
780 }
781
782 for( unsigned i = 0; i < m_editPoints->LinesSize(); ++i )
783 {
784 if( !isModified( m_editPoints->Line( i ) ) )
785 {
786 m_editPoints->Line( i ).SetConstraint(
787 new EC_PERPLINE( m_editPoints->Line( i ) ) );
788 }
789 }
790
791 textbox->ClearRenderCache();
792 break;
793 }
794
795 case SCH_SHAPE_T:
796 {
797 SCH_SHAPE* shape = static_cast<SCH_SHAPE*>( item );
798
799 switch( shape->GetShape() )
800 {
801 case SHAPE_T::ARC:
803 {
804 shape->SetEditState( 4 );
805 shape->CalcEdit( m_editPoints->Point( ARC_CENTER ).GetPosition() );
806 }
807 else if( getEditedPointIndex() == ARC_START )
808 {
809 shape->SetEditState( 2 );
810 shape->CalcEdit( m_editPoints->Point( ARC_START ).GetPosition() );
811 }
812 else if( getEditedPointIndex() == ARC_END )
813 {
814 shape->SetEditState( 3 );
815 shape->CalcEdit( m_editPoints->Point( ARC_END ).GetPosition() );
816 }
817 break;
818
819 case SHAPE_T::CIRCLE:
820 shape->SetPosition( m_editPoints->Point( CIRC_CENTER ).GetPosition() );
821 shape->SetEnd( m_editPoints->Point( CIRC_END ).GetPosition() );
822 break;
823
824 case SHAPE_T::POLY:
826 shape->GetPolyShape().NewOutline();
827
828 for( unsigned i = 0; i < m_editPoints->PointsSize(); ++i )
829 {
830 VECTOR2I pt = m_editPoints->Point( i ).GetPosition();
831 shape->GetPolyShape().Append( pt.x, pt.y, -1, -1, true );
832 }
833
834 break;
835
836 case SHAPE_T::RECT:
837 {
838 EE_GRID_HELPER gridHelper( m_toolMgr );
839 VECTOR2I topLeft = m_editPoints->Point( RECT_TOPLEFT ).GetPosition();
840 VECTOR2I topRight = m_editPoints->Point( RECT_TOPRIGHT ).GetPosition();
841 VECTOR2I botLeft = m_editPoints->Point( RECT_BOTLEFT ).GetPosition();
842 VECTOR2I botRight = m_editPoints->Point( RECT_BOTRIGHT ).GetPosition();
843
844 gridHelper.SetSnap( aSnapToGrid );
845
846 pinEditedCorner( schIUScale.MilsToIU( 1 ), schIUScale.MilsToIU( 1 ), topLeft, topRight,
847 botLeft, botRight, &gridHelper );
848
849 if( isModified( m_editPoints->Point( RECT_TOPLEFT ) )
852 || isModified( m_editPoints->Point( RECT_BOTLEFT ) ) )
853 {
854 shape->SetPosition( topLeft );
855 shape->SetEnd( botRight );
856 }
857 else if( isModified( m_editPoints->Line( RECT_TOP ) ) )
858 {
859 shape->SetStartY( topLeft.y );
860 }
861 else if( isModified( m_editPoints->Line( RECT_LEFT ) ) )
862 {
863 shape->SetStartX( topLeft.x );
864 }
865 else if( isModified( m_editPoints->Line( RECT_BOT ) ) )
866 {
867 shape->SetEndY( botRight.y );
868 }
869 else if( isModified( m_editPoints->Line( RECT_RIGHT ) ) )
870 {
871 shape->SetEndX( botRight.x );
872 }
873
874 for( unsigned i = 0; i < m_editPoints->LinesSize(); ++i )
875 {
876 if( !isModified( m_editPoints->Line( i ) ) )
877 {
878 m_editPoints->Line( i ).SetConstraint(
879 new EC_PERPLINE( m_editPoints->Line( i ) ) );
880 }
881 }
882
883 break;
884 }
885
886 case SHAPE_T::BEZIER:
887 // TODO
888 break;
889
890 default:
892 }
893
894 break;
895 }
896
897 case SCH_TEXTBOX_T:
898 {
899 SCH_TEXTBOX* textBox = static_cast<SCH_TEXTBOX*>( item );
900 EE_GRID_HELPER gridHelper( m_toolMgr );
901 VECTOR2I topLeft = m_editPoints->Point( RECT_TOPLEFT ).GetPosition();
902 VECTOR2I topRight = m_editPoints->Point( RECT_TOPRIGHT ).GetPosition();
903 VECTOR2I botLeft = m_editPoints->Point( RECT_BOTLEFT ).GetPosition();
904 VECTOR2I botRight = m_editPoints->Point( RECT_BOTRIGHT ).GetPosition();
905
906 gridHelper.SetSnap( aSnapToGrid );
907
908 pinEditedCorner( schIUScale.MilsToIU( 1 ), schIUScale.MilsToIU( 1 ), topLeft, topRight,
909 botLeft, botRight, &gridHelper );
910
911 if( isModified( m_editPoints->Point( RECT_TOPLEFT ) )
914 || isModified( m_editPoints->Point( RECT_BOTLEFT ) ) )
915 {
916 textBox->SetPosition( topLeft );
917 textBox->SetEnd( botRight );
918 }
919 else if( isModified( m_editPoints->Line( RECT_TOP ) ) )
920 {
921 textBox->SetStartY( topLeft.y );
922 }
923 else if( isModified( m_editPoints->Line( RECT_LEFT ) ) )
924 {
925 textBox->SetStartX( topLeft.x );
926 }
927 else if( isModified( m_editPoints->Line( RECT_BOT ) ) )
928 {
929 textBox->SetEndY( botRight.y );
930 }
931 else if( isModified( m_editPoints->Line( RECT_RIGHT ) ) )
932 {
933 textBox->SetEndX( botRight.x );
934 }
935
936 for( unsigned i = 0; i < m_editPoints->LinesSize(); ++i )
937 {
938 if( !isModified( m_editPoints->Line( i ) ) )
939 {
940 m_editPoints->Line( i ).SetConstraint(
941 new EC_PERPLINE( m_editPoints->Line( i ) ) );
942 }
943 }
944
945 textBox->ClearRenderCache();
946 break;
947 }
948
949 case SCH_BITMAP_T:
950 {
951 EE_GRID_HELPER gridHelper( m_toolMgr );
952 SCH_BITMAP* bitmap = (SCH_BITMAP*) item;
953 VECTOR2I topLeft = m_editPoints->Point( RECT_TOPLEFT ).GetPosition();
954 VECTOR2I topRight = m_editPoints->Point( RECT_TOPRIGHT ).GetPosition();
955 VECTOR2I botLeft = m_editPoints->Point( RECT_BOTLEFT ).GetPosition();
956 VECTOR2I botRight = m_editPoints->Point( RECT_BOTRIGHT ).GetPosition();
957
958 gridHelper.SetSnap( aSnapToGrid );
959
960 pinEditedCorner( schIUScale.MilsToIU( 50 ), schIUScale.MilsToIU( 50 ), topLeft, topRight,
961 botLeft, botRight, &gridHelper );
962
963 double oldWidth = bitmap->GetSize().x;
964 double newWidth = topRight.x - topLeft.x;
965 double widthRatio = newWidth / oldWidth;
966
967 double oldHeight = bitmap->GetSize().y;
968 double newHeight = botLeft.y - topLeft.y;
969 double heightRatio = newHeight / oldHeight;
970
971 bitmap->SetImageScale( bitmap->GetImageScale() * std::min( widthRatio, heightRatio ) );
972 break;
973 }
974
975 case SCH_SHEET_T:
976 {
977 SCH_SHEET* sheet = (SCH_SHEET*) item;
978 EE_GRID_HELPER gridHelper( m_toolMgr );
979 VECTOR2I topLeft = m_editPoints->Point( RECT_TOPLEFT ).GetPosition();
980 VECTOR2I topRight = m_editPoints->Point( RECT_TOPRIGHT ).GetPosition();
981 VECTOR2I botLeft = m_editPoints->Point( RECT_BOTLEFT ).GetPosition();
982 VECTOR2I botRight = m_editPoints->Point( RECT_BOTRIGHT ).GetPosition();
983 int edited = getEditedPointIndex();
984
985 if( isModified( m_editPoints->Line( RECT_RIGHT ) ) )
986 edited = RECT_TOPRIGHT;
987 else if( isModified( m_editPoints->Line( RECT_BOT ) ) )
988 edited = RECT_BOTLEFT;
989
990 gridHelper.SetSnap( aSnapToGrid );
991
992 pinEditedCorner( sheet->GetMinWidth( edited == RECT_TOPRIGHT || edited == RECT_BOTRIGHT ),
993 sheet->GetMinHeight( edited == RECT_BOTLEFT || edited == RECT_BOTRIGHT ),
994 topLeft, topRight, botLeft, botRight, &gridHelper );
995
996 // Pin positions are relative to origin. Attempt to leave them where they
997 // are if the origin moves.
998 VECTOR2I originDelta = sheet->GetPosition() - topLeft;
999
1000 if( isModified( m_editPoints->Point( RECT_TOPLEFT ) )
1001 || isModified( m_editPoints->Point( RECT_TOPRIGHT ) )
1002 || isModified( m_editPoints->Point( RECT_BOTRIGHT ) )
1003 || isModified( m_editPoints->Point( RECT_BOTLEFT ) ) )
1004 {
1005 sheet->SetPosition( topLeft );
1006 sheet->SetSize( wxSize( botRight.x - topLeft.x, botRight.y - topLeft.y ) );
1007 }
1008 else if( isModified( m_editPoints->Line( RECT_TOP ) ) )
1009 {
1010 sheet->SetPosition( VECTOR2I( sheet->GetPosition().x, topLeft.y ) );
1011 sheet->SetSize( wxSize( sheet->GetSize().x, botRight.y - topLeft.y ) );
1012 }
1013 else if( isModified( m_editPoints->Line( RECT_LEFT ) ) )
1014 {
1015 sheet->SetPosition( VECTOR2I( topLeft.x, sheet->GetPosition().y ) );
1016 sheet->SetSize( wxSize( botRight.x - topLeft.x, sheet->GetSize().y ) );
1017 }
1018 else if( isModified( m_editPoints->Line( RECT_BOT ) ) )
1019 {
1020 sheet->SetSize( wxSize( sheet->GetSize().x, botRight.y - topLeft.y ) );
1021 }
1022 else if( isModified( m_editPoints->Line( RECT_RIGHT ) ) )
1023 {
1024 sheet->SetSize( wxSize( botRight.x - topLeft.x, sheet->GetSize().y ) );
1025 }
1026
1027 for( unsigned i = 0; i < m_editPoints->LinesSize(); ++i )
1028 {
1029 if( !isModified( m_editPoints->Line( i ) ) )
1030 {
1031 m_editPoints->Line( i ).SetConstraint(
1032 new EC_PERPLINE( m_editPoints->Line( i ) ) );
1033 }
1034 }
1035
1036 // Update the fields if we're in autoplace mode
1038 sheet->AutoplaceFields( /* aScreen */ nullptr, /* aManual */ false );
1039
1040 // Keep sheet pins attached to edges:
1041 for( SCH_SHEET_PIN* pin : sheet->GetPins() )
1042 {
1043 VECTOR2I pos = pin->GetPosition();
1044
1045 pos += originDelta;
1046
1047 switch( pin->GetSide() )
1048 {
1049 case SHEET_SIDE::LEFT: pos.x = topLeft.x; break;
1050 case SHEET_SIDE::RIGHT: pos.x = topRight.x; break;
1051 case SHEET_SIDE::TOP: pos.y = topLeft.y; break;
1052 case SHEET_SIDE::BOTTOM: pos.y = botLeft.y; break;
1053 case SHEET_SIDE::UNDEFINED: break;
1054 }
1055
1056 pin->SetPosition( pos );
1057 }
1058
1059 break;
1060 }
1061
1062 case SCH_LINE_T:
1063 {
1064 SCH_LINE* line = (SCH_LINE*) item;
1065
1066 line->SetStartPoint( m_editPoints->Point( LINE_START ).GetPosition() );
1067 line->SetEndPoint( m_editPoints->Point( LINE_END ).GetPosition() );
1068
1069 std::pair<EDA_ITEM*, int> connected = m_editPoints->Point( LINE_START ).GetConnected();
1070
1071 if( connected.first )
1072 {
1073 if( connected.second == STARTPOINT )
1074 static_cast<SCH_LINE*>( connected.first )->SetStartPoint( line->GetStartPoint() );
1075 else if( connected.second == ENDPOINT )
1076 static_cast<SCH_LINE*>( connected.first )->SetEndPoint( line->GetStartPoint() );
1077
1078 updateItem( connected.first, true );
1079 }
1080
1081 connected = m_editPoints->Point( LINE_END ).GetConnected();
1082
1083 if( connected.first )
1084 {
1085 if( connected.second == STARTPOINT )
1086 static_cast<SCH_LINE*>( connected.first )->SetStartPoint( line->GetEndPoint() );
1087 else if( connected.second == ENDPOINT )
1088 static_cast<SCH_LINE*>( connected.first )->SetEndPoint( line->GetEndPoint() );
1089
1090 updateItem( connected.first, true );
1091 }
1092
1093 break;
1094 }
1095
1096 default:
1097 break;
1098 }
1099
1100 updateItem( item, true );
1101 m_frame->SetMsgPanel( item );
1102}
1103
1104
1106{
1107 if( !m_editPoints )
1108 return;
1109
1110 EDA_ITEM* item = m_editPoints->GetParent();
1111
1112 if( !item )
1113 return;
1114
1115 switch( item->Type() )
1116 {
1117 case LIB_SHAPE_T:
1118 {
1119 LIB_SHAPE* shape = static_cast<LIB_SHAPE*>( item );
1120
1121 switch( shape->GetShape() )
1122 {
1123 case SHAPE_T::ARC:
1124 m_editPoints->Point( ARC_CENTER ).SetPosition( mapCoords( shape->GetPosition() ) );
1125 m_editPoints->Point( ARC_START ).SetPosition( mapCoords( shape->GetStart() ) );
1126 m_editPoints->Point( ARC_END ).SetPosition( mapCoords( shape->GetEnd() ) );
1127 break;
1128
1129 case SHAPE_T::CIRCLE:
1130 m_editPoints->Point( CIRC_CENTER ).SetPosition( mapCoords( shape->GetPosition() ) );
1131 m_editPoints->Point( CIRC_END ).SetPosition( mapCoords( shape->GetEnd() ) );
1132 break;
1133
1134 case SHAPE_T::POLY:
1135 {
1136 if( (int) m_editPoints->PointsSize() != shape->GetPointCount() )
1137 {
1138 getView()->Remove( m_editPoints.get() );
1139 m_editedPoint = nullptr;
1141 getView()->Add( m_editPoints.get() );
1142 }
1143 else
1144 {
1145 int ii = 0;
1146
1147 for( const VECTOR2I& pt : shape->GetPolyShape().Outline( 0 ).CPoints() )
1148 m_editPoints->Point( ii++ ).SetPosition( mapCoords( pt ) );
1149 }
1150
1151 break;
1152 }
1153
1154 case SHAPE_T::RECT:
1155 {
1156 // point editor works only with rectangles having width and height > 0
1157 // Some symbols can have rectangles with width or height < 0
1158 // So normalize the size:
1159 BOX2I dummy;
1160 dummy.SetOrigin( mapCoords( shape->GetPosition() ) );
1161 dummy.SetEnd( mapCoords( shape->GetEnd() ) );
1162 dummy.Normalize();
1163 VECTOR2I topLeft = dummy.GetPosition();
1164 VECTOR2I botRight = dummy.GetEnd();
1165
1166 m_editPoints->Point( RECT_TOPLEFT ).SetPosition( topLeft );
1167 m_editPoints->Point( RECT_TOPRIGHT ).SetPosition( VECTOR2I( botRight.x, topLeft.y ) );
1168 m_editPoints->Point( RECT_BOTLEFT ).SetPosition( VECTOR2I( topLeft.x, botRight.y ) );
1169 m_editPoints->Point( RECT_BOTRIGHT ).SetPosition( botRight );
1170 break;
1171 }
1172
1173 case SHAPE_T::BEZIER:
1174 // TODO
1175 break;
1176
1177 default:
1179 }
1180
1181 break;
1182 }
1183
1184 case LIB_TEXTBOX_T:
1185 {
1186 LIB_TEXTBOX* textbox = static_cast<LIB_TEXTBOX*>( item );
1187
1188 // point editor works only with rectangles having width and height > 0
1189 // Some symbols can have rectangles with width or height < 0
1190 // So normalize the size:
1191 BOX2I dummy;
1192 dummy.SetOrigin( mapCoords( textbox->GetPosition() ) );
1193 dummy.SetEnd( mapCoords( textbox->GetEnd() ) );
1194 dummy.Normalize();
1195 VECTOR2I topLeft = dummy.GetPosition();
1196 VECTOR2I botRight = dummy.GetEnd();
1197
1198 m_editPoints->Point( RECT_TOPLEFT ).SetPosition( topLeft );
1199 m_editPoints->Point( RECT_TOPRIGHT ).SetPosition( VECTOR2I( botRight.x, topLeft.y ) );
1200 m_editPoints->Point( RECT_BOTLEFT ).SetPosition( VECTOR2I( topLeft.x, botRight.y ) );
1201 m_editPoints->Point( RECT_BOTRIGHT ).SetPosition( botRight );
1202 break;
1203 }
1204
1205 case SCH_SHAPE_T:
1206 {
1207 SCH_SHAPE* shape = static_cast<SCH_SHAPE*>( item );
1208
1209 switch( shape->GetShape() )
1210 {
1211 case SHAPE_T::ARC:
1212 m_editPoints->Point( ARC_CENTER ).SetPosition( shape->GetPosition() );
1213 m_editPoints->Point( ARC_START ).SetPosition( shape->GetStart() );
1214 m_editPoints->Point( ARC_END ).SetPosition( shape->GetEnd() );
1215 break;
1216
1217 case SHAPE_T::CIRCLE:
1218 m_editPoints->Point( CIRC_CENTER ).SetPosition( shape->GetPosition() );
1219 m_editPoints->Point( CIRC_END ).SetPosition( shape->GetEnd() );
1220 break;
1221
1222 case SHAPE_T::POLY:
1223 {
1224 if( (int) m_editPoints->PointsSize() != shape->GetPointCount() )
1225 {
1226 getView()->Remove( m_editPoints.get() );
1227 m_editedPoint = nullptr;
1229 getView()->Add( m_editPoints.get() );
1230 }
1231 else
1232 {
1233 int ii = 0;
1234
1235 for( const VECTOR2I& pt : shape->GetPolyShape().Outline( 0 ).CPoints() )
1236 m_editPoints->Point( ii++ ).SetPosition( pt );
1237 }
1238
1239 break;
1240 }
1241
1242 case SHAPE_T::RECT:
1243 {
1244 // point editor works only with rectangles having width and height > 0
1245 // Some symbols can have rectangles with width or height < 0
1246 // So normalize the size:
1247 BOX2I dummy;
1248 dummy.SetOrigin( shape->GetPosition() );
1249 dummy.SetEnd( shape->GetEnd() );
1250 dummy.Normalize();
1251 VECTOR2I topLeft = dummy.GetPosition();
1252 VECTOR2I botRight = dummy.GetEnd();
1253
1254 m_editPoints->Point( RECT_TOPLEFT ).SetPosition( topLeft );
1255 m_editPoints->Point( RECT_TOPRIGHT ).SetPosition( VECTOR2I( botRight.x, topLeft.y ) );
1256 m_editPoints->Point( RECT_BOTLEFT ).SetPosition( VECTOR2I( topLeft.x, botRight.y ) );
1257 m_editPoints->Point( RECT_BOTRIGHT ).SetPosition( botRight );
1258 break;
1259 }
1260
1261 case SHAPE_T::BEZIER:
1262 // TODO
1263 break;
1264
1265 default:
1267 }
1268
1269 break;
1270 }
1271
1272 case SCH_TEXTBOX_T:
1273 {
1274 SCH_TEXTBOX* textBox = static_cast<SCH_TEXTBOX*>( item );
1275
1276 // point editor works only with rectangles having width and height > 0
1277 // Some symbols can have rectangles with width or height < 0
1278 // So normalize the size:
1279 BOX2I dummy;
1280 dummy.SetOrigin( textBox->GetPosition() );
1281 dummy.SetEnd( textBox->GetEnd() );
1282 dummy.Normalize();
1283 VECTOR2I topLeft = dummy.GetPosition();
1284 VECTOR2I botRight = dummy.GetEnd();
1285
1286 m_editPoints->Point( RECT_TOPLEFT ).SetPosition( topLeft );
1287 m_editPoints->Point( RECT_TOPRIGHT ).SetPosition( VECTOR2I( botRight.x, topLeft.y ) );
1288 m_editPoints->Point( RECT_BOTLEFT ).SetPosition( VECTOR2I( topLeft.x, botRight.y ) );
1289 m_editPoints->Point( RECT_BOTRIGHT ).SetPosition( botRight );
1290 break;
1291 }
1292
1293 case SCH_BITMAP_T:
1294 {
1295 SCH_BITMAP* bitmap = (SCH_BITMAP*) item;
1296 VECTOR2I topLeft = bitmap->GetPosition() - bitmap->GetSize() / 2;
1297 VECTOR2I botRight = bitmap->GetPosition() + bitmap->GetSize() / 2;
1298
1299 m_editPoints->Point( RECT_TOPLEFT ).SetPosition( topLeft );
1300 m_editPoints->Point( RECT_TOPRIGHT ).SetPosition( botRight.x, topLeft.y );
1301 m_editPoints->Point( RECT_BOTLEFT ).SetPosition( topLeft.x, botRight.y );
1302 m_editPoints->Point( RECT_BOTRIGHT ).SetPosition( botRight );
1303 break;
1304 }
1305
1306 case SCH_SHEET_T:
1307 {
1308 SCH_SHEET* sheet = (SCH_SHEET*) item;
1309 VECTOR2I topLeft = sheet->GetPosition();
1310 VECTOR2I botRight = sheet->GetPosition() + sheet->GetSize();
1311
1312 m_editPoints->Point( RECT_TOPLEFT ).SetPosition( topLeft );
1313 m_editPoints->Point( RECT_TOPRIGHT ).SetPosition( botRight.x, topLeft.y );
1314 m_editPoints->Point( RECT_BOTLEFT ).SetPosition( topLeft.x, botRight.y );
1315 m_editPoints->Point( RECT_BOTRIGHT ).SetPosition( botRight );
1316 break;
1317 }
1318
1319 case SCH_LINE_T:
1320 {
1321 SCH_LINE* line = (SCH_LINE*) item;
1322
1323 m_editPoints->Point( LINE_START ).SetPosition( line->GetStartPoint() );
1324 m_editPoints->Point( LINE_END ).SetPosition( line->GetEndPoint() );
1325 break;
1326 }
1327
1328 default:
1329 break;
1330 }
1331
1332 getView()->Update( m_editPoints.get() );
1333}
1334
1335
1337{
1339
1340 if( aPoint )
1341 {
1343 controls->ForceCursorPosition( true, aPoint->GetPosition() );
1344 controls->ShowCursor( true );
1345 }
1346 else
1347 {
1348 if( m_frame->ToolStackIsEmpty() )
1349 controls->ShowCursor( false );
1350
1351 controls->ForceCursorPosition( false );
1352 }
1353
1354 m_editedPoint = aPoint;
1355}
1356
1357
1359{
1360 if( !m_editPoints || !m_editedPoint || m_editPoints->GetParent()->Type() != LIB_SHAPE_T )
1361 return false;
1362
1363 LIB_SHAPE* shape = static_cast<LIB_SHAPE*>( m_editPoints->GetParent() );
1364
1365 if( shape->GetPolyShape().IsEmpty() )
1366 return false;
1367
1368 SHAPE_LINE_CHAIN& poly = shape->GetPolyShape().Outline( 0 );
1369
1370 if( poly.GetPointCount() < 3 )
1371 return false;
1372
1373 for( const VECTOR2I& pt : poly.CPoints() )
1374 {
1375 if( pt == mapCoords( m_editedPoint->GetPosition() ) )
1376 return true;
1377 }
1378
1379 return false;
1380}
1381
1382
1384{
1385 if( !m_editPoints || m_editPoints->GetParent()->Type() != LIB_SHAPE_T )
1386 return false;
1387
1388 LIB_SHAPE* shape = static_cast<LIB_SHAPE*>( m_editPoints->GetParent() );
1389
1390 if( shape->GetShape() != SHAPE_T::POLY )
1391 return false;
1392
1393 VECTOR2I cursorPos = getViewControls()->GetCursorPosition( false );
1394 double threshold = getView()->ToWorld( EDIT_POINT::POINT_SIZE );
1395
1396 return shape->HitTest( cursorPos, (int) threshold );
1397}
1398
1399
1401{
1402 if( !m_editPoints || m_editPoints->GetParent()->Type() != LIB_SHAPE_T )
1403 return 0;
1404
1405 LIB_SHAPE* shape = static_cast<LIB_SHAPE*>( m_editPoints->GetParent() );
1406 SHAPE_LINE_CHAIN& poly = shape->GetPolyShape().Outline( 0 );
1407
1409 VECTOR2I pos = mapCoords( cursor );
1410 int currentMinDistance = INT_MAX;
1411 int closestLineStart = 0;
1412
1413 for( unsigned i = 0; i < poly.GetPointCount() - 1; ++i )
1414 {
1415 int distance = (int) DistanceLinePoint( poly.CPoint( i ),
1416 poly.CPoint( i + 1 ), pos );
1417
1418 if( distance < currentMinDistance )
1419 {
1420 currentMinDistance = distance;
1421 closestLineStart = i;
1422 }
1423 }
1424
1426 poly.Insert( closestLineStart + 1, pos );
1427
1428 updateItem( shape, true );
1429 updatePoints();
1430
1431 m_frame->OnModify();
1432
1433 return 0;
1434}
1435
1436
1438{
1439 if( !m_editPoints || !m_editedPoint || m_editPoints->GetParent()->Type() != LIB_SHAPE_T )
1440 return 0;
1441
1442 LIB_SHAPE* shape = static_cast<LIB_SHAPE*>( m_editPoints->GetParent() );
1443 SHAPE_LINE_CHAIN& poly = shape->GetPolyShape().Outline( 0 );
1444
1445 if( poly.GetPointCount() < 3 )
1446 return 0;
1447
1449 poly.Remove( getEditedPointIndex() );
1450
1451 updateItem( shape, true );
1452 updatePoints();
1453
1454 m_frame->OnModify();
1455
1456 return 0;
1457}
1458
1459
1461{
1462 updatePoints();
1463 return 0;
1464}
1465
1466
1468{
1469 if( m_isSymbolEditor )
1470 {
1471 saveCopyInUndoList( m_editPoints->GetParent()->GetParent(), UNDO_REDO::LIBEDIT );
1472 }
1473 else
1474 {
1476
1477 if( m_editPoints->GetParent()->Type() == SCH_LINE_T )
1478 {
1479 std::pair<EDA_ITEM*, int> connected = m_editPoints->Point( LINE_START ).GetConnected();
1480
1481 if( connected.first )
1482 saveCopyInUndoList( (SCH_ITEM*) connected.first, UNDO_REDO::CHANGED, true );
1483
1484 connected = m_editPoints->Point( LINE_END ).GetConnected();
1485
1486 if( connected.first )
1487 saveCopyInUndoList( (SCH_ITEM*) connected.first, UNDO_REDO::CHANGED, true );
1488 }
1489 }
1490}
1491
1492
1494{
1495 if( m_isSymbolEditor )
1496 static_cast<SYMBOL_EDIT_FRAME*>( m_frame )->RollbackSymbolFromUndo();
1497 else
1498 static_cast<SCH_EDIT_FRAME*>( m_frame )->RollbackSchematicFromUndo();
1499}
1500
1501
1503{
1511}
1512
1513
VECTOR2D mapCoords(const VECTOR2D &aSource)
Definition: PS_plotter.cpp:568
constexpr EDA_IU_SCALE schIUScale
Definition: base_units.h:111
static TOOL_ACTION activatePointEditor
Definition: actions.h:172
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.
EDIT_CONSTRAINT for a EDIT_LINE, that constrains the line to move perpendicular to the line itself.
virtual void OnModify()
Must be called after a model change in order to set the "modify" flag and do other frame-specific pro...
void SetMsgPanel(const std::vector< MSG_PANEL_ITEM > &aList)
Clear the message panel and populates it with the contents of aList.
void SetCurrentCursor(KICURSOR aCursor)
Set the current cursor shape for this panel.
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...
A base class for most all the KiCad significant classes used in schematics and boards.
Definition: eda_item.h:85
KICAD_T Type() const
Returns the type of object.
Definition: eda_item.h:97
virtual bool IsType(const std::vector< KICAD_T > &aScanTypes) const
Check whether the item is one of the listed types.
Definition: eda_item.h:183
bool IsNew() const
Definition: eda_item.h:103
void SetStartX(int x)
Definition: eda_shape.h:136
void SetEndY(int y)
Definition: eda_shape.h:155
void SetStartY(int y)
Definition: eda_shape.h:130
SHAPE_POLY_SET & GetPolyShape()
Definition: eda_shape.h:247
SHAPE_T GetShape() const
Definition: eda_shape.h:113
void SetEndX(int x)
Definition: eda_shape.h:161
int GetPointCount() const
Definition: eda_shape.cpp:1242
const VECTOR2I & GetEnd() const
Return the ending point of the graphic.
Definition: eda_shape.h:145
const VECTOR2I & GetStart() const
Return the starting point of the graphic.
Definition: eda_shape.h:120
void SetEnd(const VECTOR2I &aEnd)
Definition: eda_shape.h:149
wxString SHAPE_T_asString() const
Definition: eda_shape.cpp:75
virtual void ClearRenderCache()
Definition: eda_text.cpp:438
static std::shared_ptr< EDIT_POINTS > Make(EDA_ITEM *aItem, SCH_BASE_FRAME *frame)
Represent a single point that can be used for modifying items.
Definition: edit_points.h:48
static const int POINT_SIZE
Border size when not hovering.
Definition: edit_points.h:190
virtual void SetPosition(const VECTOR2I &aPosition)
Set new coordinates for an EDIT_POINT.
Definition: edit_points.h:107
virtual VECTOR2I GetPosition() const
Return coordinates of an EDIT_POINT.
Definition: edit_points.h:71
static TOOL_ACTION pointEditorRemoveCorner
Definition: ee_actions.h:149
static TOOL_ACTION pointEditorAddCorner
Definition: ee_actions.h:148
void updatePoints()
Update which point is being edited.
int Main(const TOOL_EVENT &aEvent)
void updateEditedPoint(const TOOL_EVENT &aEvent)
Clear references to the points.
void setEditedPoint(EDIT_POINT *aPoint)
Return true if aPoint is the currently modified point.
int modifiedSelection(const TOOL_EVENT &aEvent)
bool Init() override
Init() is called once upon a registration of the tool.
EDIT_POINT * m_editedPoint
< Currently edited point, NULL if there is none.
bool addCornerCondition(const SELECTION &aSelection)
void setTransitions() override
This method is meant to be overridden in order to specify handlers for events.
void pinEditedCorner(int minWidth, int minHeight, VECTOR2I &topLeft, VECTOR2I &topRight, VECTOR2I &botLeft, VECTOR2I &botRight, EE_GRID_HELPER *aGrid) const
Update the coordinates of 4 corners of a rectangle, according to constraints and the moved corner.
bool isModified(const EDIT_POINT &aPoint) const
int addCorner(const TOOL_EVENT &aEvent)
TOOL_ACTION handlers.
std::shared_ptr< EDIT_POINTS > m_editPoints
bool removeCornerCondition(const SELECTION &aSelection)
int removeCorner(const TOOL_EVENT &aEvent)
void Reset(RESET_REASON aReason) override
Bring the tool to a known, initial state.
int getEditedPointIndex() const
int clearEditedPoints(const TOOL_EVENT &aEvent)
Set the current point being edited. NULL means none.
void updateParentItem(bool aSnapToGrid) const
< Update item's points with edit points.
EE_TYPE OfType(KICAD_T aType) const
Definition: sch_rtree.h:238
EE_SELECTION & GetSelection()
A foundation class for a tool operating on a schematic or symbol.
Definition: ee_tool_base.h:50
void Reset(RESET_REASON aReason) override
Bring the tool to a known, initial state.
Definition: ee_tool_base.h:86
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
void saveCopyInUndoList(EDA_ITEM *aItem, UNDO_REDO aType, bool aAppend=false, bool aDirtyConnectivity=true)
Definition: ee_tool_base.h:134
EE_SELECTION_TOOL * m_selectionTool
Definition: ee_tool_base.h:184
bool Init() override
Init() is called once upon a registration of the tool.
Definition: ee_tool_base.h:66
static const TOOL_EVENT ClearedEvent
Definition: actions.h:208
static const TOOL_EVENT SelectedEvent
Definition: actions.h:206
static const TOOL_EVENT SelectedItemsModified
Selected items were moved, this can be very high frequency on the canvas, use with care.
Definition: actions.h:213
static const TOOL_EVENT PointSelectedEvent
Definition: actions.h:205
bool GetSnap() const
Definition: grid_helper.h:65
void SetSnap(bool aSnap)
Definition: grid_helper.h:64
VECTOR2I AlignGrid(const VECTOR2I &aPoint) const
Definition: grid_helper.cpp:83
An interface for classes handling user events controlling the view behavior such as zooming,...
virtual void CaptureCursor(bool aEnabled)
Force the cursor to stay within the drawing panel area.
virtual void ForceCursorPosition(bool aEnabled, const VECTOR2D &aPosition=VECTOR2D(0, 0))
Place the cursor immediately at a given point.
virtual void ShowCursor(bool aEnabled)
Enable or disables display of cursor.
VECTOR2D GetCursorPosition() const
Return the current cursor position in world coordinates.
virtual void SetAutoPan(bool aEnabled)
Turn on/off auto panning (this feature is used when there is a tool active (eg.
Hold a (potentially large) number of VIEW_ITEMs and renders them on a graphics device provided by the...
Definition: view.h:69
virtual void Add(VIEW_ITEM *aItem, int aDrawPriority=-1)
Add a VIEW_ITEM to the view.
Definition: view.cpp:316
virtual void Remove(VIEW_ITEM *aItem)
Remove a VIEW_ITEM from the view.
Definition: view.cpp:346
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:1586
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:445
bool HitTest(const VECTOR2I &aPosition, int aAccuracy=0) const override
Test if aPosition is inside or on the boundary of this item.
Definition: lib_shape.cpp:46
void SetEditState(int aState)
Definition: lib_shape.h:77
void SetPosition(const VECTOR2I &aPosition) override
Definition: lib_shape.h:86
void CalcEdit(const VECTOR2I &aPosition) override
Calculate the attributes of an item at aPosition when it is being edited.
Definition: lib_shape.h:74
void Normalize()
Definition: lib_shape.cpp:93
VECTOR2I GetPosition() const override
Definition: lib_shape.h:85
A shim class between EDA_DRAW_FRAME and several derived classes: SYMBOL_EDIT_FRAME,...
SCH_SCREEN * GetScreen() const override
Return a pointer to a BASE_SCREEN or one of its derivatives.
SCH_DRAW_PANEL * GetCanvas() const override
Return a pointer to GAL-based canvas of given EDA draw frame.
Object to handle a bitmap image that can be inserted in a schematic.
Definition: sch_bitmap.h:41
double GetImageScale() const
Definition: sch_bitmap.h:66
VECTOR2I GetPosition() const override
Definition: sch_bitmap.h:136
VECTOR2I GetSize() const
Definition: sch_bitmap.cpp:125
void SetImageScale(double aScale)
Definition: sch_bitmap.h:71
Schematic editor (Eeschema) main window.
Base class for any item which can be embedded within the SCHEMATIC container class,...
Definition: sch_item.h:147
FIELDS_AUTOPLACED GetFieldsAutoplaced() const
Return whether the fields have been automatically placed.
Definition: sch_item.h:424
Segment description base class to describe items which have 2 end points (track, wire,...
Definition: sch_line.h:40
void SetStartPoint(const VECTOR2I &aPosition)
Definition: sch_line.h:139
VECTOR2I GetEndPoint() const
Definition: sch_line.h:143
VECTOR2I GetStartPoint() const
Definition: sch_line.h:138
void SetEndPoint(const VECTOR2I &aPosition)
Definition: sch_line.h:144
EE_RTREE & Items()
Gets the full RTree, usually for iterating.
Definition: sch_screen.h:109
void SetPosition(const VECTOR2I &aPos) override
Definition: sch_shape.h:78
void CalcEdit(const VECTOR2I &aPosition)
Definition: sch_shape.h:84
void SetEditState(int aState)
Definition: sch_shape.h:86
void Normalize()
Definition: sch_shape.cpp:73
VECTOR2I GetPosition() const override
Definition: sch_shape.h:77
Define a sheet pin (label) used in sheets to create hierarchical schematics.
Definition: sch_sheet_pin.h:66
Sheet symbol placed in a schematic, and is the entry point for a sub schematic.
Definition: sch_sheet.h:55
void SetSize(const wxSize &aSize)
Definition: sch_sheet.h:107
void SetPosition(const VECTOR2I &aPosition) override
Definition: sch_sheet.cpp:891
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:472
VECTOR2I GetPosition() const override
Definition: sch_sheet.h:366
wxSize GetSize() const
Definition: sch_sheet.h:106
void AutoplaceFields(SCH_SCREEN *aScreen, bool aManual) override
Definition: sch_sheet.cpp:590
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:506
std::vector< SCH_SHEET_PIN * > & GetPins()
Definition: sch_sheet.h:173
EDA_ITEM * Front() const
Definition: selection.h:206
int Size() const
Returns the number of selected parts.
Definition: selection.h:113
Represent a polyline containing arcs as well as line segments: A chain of connected line and/or arc s...
virtual size_t GetPointCount() const override
const VECTOR2I & CPoint(int aIndex) const
Return a reference to a given point in the line chain.
void Remove(int aStartIndex, int aEndIndex)
Remove the range of points [start_index, end_index] from the line chain.
void Insert(size_t aVertex, const VECTOR2I &aP)
const std::vector< VECTOR2I > & CPoints() const
bool IsEmpty() const
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...
SHAPE_LINE_CHAIN & Outline(int aIndex)
int NewOutline()
Creates a new hole in a given outline.
The symbol library editor main window.
bool ToolStackIsEmpty()
Definition: tools_holder.h:128
KIGFX::VIEW_CONTROLS * getViewControls() const
Return the instance of VIEW_CONTROLS object used in the application.
Definition: tool_base.cpp:42
TOOL_MANAGER * m_toolMgr
Definition: tool_base.h:214
KIGFX::VIEW * getView() const
Returns the instance of #VIEW object used in the application.
Definition: tool_base.cpp:36
RESET_REASON
Determine the reason of reset for a tool.
Definition: tool_base.h:78
Generic, UI-independent tool event.
Definition: tool_event.h:156
bool DisableGridSnapping() const
Definition: tool_event.h:344
const VECTOR2D Position() const
Returns the point where dragging has started.
Definition: tool_event.h:266
bool IsDrag(int aButtonMask=BUT_ANY) const
Definition: tool_event.h:288
const VECTOR2D DragOrigin() const
Returns information about mouse buttons state.
Definition: tool_event.h:272
bool IsMotion() const
Definition: tool_event.h:303
void Go(int(T::*aStateFunc)(const TOOL_EVENT &), const TOOL_EVENT_LIST &aConditions=TOOL_EVENT(TC_ANY, TA_ANY))
Define which state (aStateFunc) to go when a certain event arrives (aConditions).
TOOL_MENU & GetToolMenu()
TOOL_EVENT * Wait(const TOOL_EVENT_LIST &aEventList=TOOL_EVENT(TC_ANY, TA_ANY))
Suspend execution of the tool until an event specified in aEventList arrives.
void Activate()
Run the tool.
CONDITIONAL_MENU & GetMenu()
Definition: tool_menu.cpp:44
#define ENDPOINT
ends. (Used to support dragging.)
#define STARTPOINT
When a line is selected, these flags indicate which.
RECTANGLE_POINTS
@ RECT_BOTLEFT
@ RECT_TOPLEFT
@ RECT_TOPRIGHT
@ RECT_BOTRIGHT
RECTANGLE_LINES
@ RECT_RIGHT
@ RECT_LEFT
@ RECT_BOT
@ RECT_TOP
LINE_POINTS
@ LINE_START
@ LINE_END
ARC_POINTS
@ ARC_START
@ ARC_END
@ ARC_CENTER
CIRCLE_POINTS
@ CIRC_END
@ CIRC_CENTER
@ LAYER_NOTES
Definition: layer_ids.h:358
#define UNIMPLEMENTED_FOR(type)
Definition: macros.h:120
static float distance(const SFVEC2UI &a, const SFVEC2UI &b)
@ FIELDS_AUTOPLACED_AUTO
Definition: sch_item.h:57
std::vector< FAB_LAYER_COLOR > dummy
constexpr int MilsToIU(int mils) const
Definition: base_units.h:94
@ BUT_LEFT
Definition: tool_event.h:127
double DistanceLinePoint(const VECTOR2I &linePointA, const VECTOR2I &linePointB, const VECTOR2I &referencePoint)
Compute the distance between a line and a reference point Reference: http://mathworld....
Definition: trigo.h:140
@ SCH_LINE_T
Definition: typeinfo.h:146
@ LIB_TEXTBOX_T
Definition: typeinfo.h:201
@ SCH_SHEET_T
Definition: typeinfo.h:158
@ LIB_SHAPE_T
Definition: typeinfo.h:199
@ SCH_SHAPE_T
Definition: typeinfo.h:147
@ SCH_BITMAP_T
Definition: typeinfo.h:148
@ SCH_TEXTBOX_T
Definition: typeinfo.h:149
VECTOR2< int > VECTOR2I
Definition: vector2d.h:618