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 VECTOR2I sheetNewPos = sheet->GetPosition();
984 VECTOR2I sheetNewSize = sheet->GetSize();
985
986 gridHelper.SetSnap( aSnapToGrid );
987
988 int edited = getEditedPointIndex();
989
990 if( isModified( m_editPoints->Line( RECT_RIGHT ) ) )
991 edited = RECT_TOPRIGHT;
992 else if( isModified( m_editPoints->Line( RECT_BOT ) ) )
993 edited = RECT_BOTLEFT;
994
995 gridHelper.SetSnap( aSnapToGrid );
996
997 pinEditedCorner( sheet->GetMinWidth( edited == RECT_TOPRIGHT || edited == RECT_BOTRIGHT ),
998 sheet->GetMinHeight( edited == RECT_BOTLEFT || edited == RECT_BOTRIGHT ),
999 topLeft, topRight, botLeft, botRight, &gridHelper );
1000
1001 if( isModified( m_editPoints->Point( RECT_TOPLEFT ) )
1002 || isModified( m_editPoints->Point( RECT_TOPRIGHT ) )
1003 || isModified( m_editPoints->Point( RECT_BOTRIGHT ) )
1004 || isModified( m_editPoints->Point( RECT_BOTLEFT ) ) )
1005 {
1006 sheetNewPos = topLeft;
1007 sheetNewSize = VECTOR2I( botRight.x - topLeft.x, botRight.y - topLeft.y );
1008 }
1009 else if( isModified( m_editPoints->Line( RECT_TOP ) ) )
1010 {
1011 sheetNewPos = VECTOR2I( sheet->GetPosition().x, topLeft.y );
1012 sheetNewSize = VECTOR2I( sheet->GetSize().x, botRight.y - topLeft.y );
1013 }
1014 else if( isModified( m_editPoints->Line( RECT_LEFT ) ) )
1015 {
1016 sheetNewPos = VECTOR2I( topLeft.x, sheet->GetPosition().y );
1017 sheetNewSize = VECTOR2I( botRight.x - topLeft.x, sheet->GetSize().y );
1018 }
1019 else if( isModified( m_editPoints->Line( RECT_BOT ) ) )
1020 {
1021 sheetNewSize = VECTOR2I( sheet->GetSize().x, botRight.y - topLeft.y );
1022 }
1023 else if( isModified( m_editPoints->Line( RECT_RIGHT ) ) )
1024 {
1025 sheetNewSize = VECTOR2I( botRight.x - topLeft.x, sheet->GetSize().y );
1026 }
1027
1028 for( unsigned i = 0; i < m_editPoints->LinesSize(); ++i )
1029 {
1030 if( !isModified( m_editPoints->Line( i ) ) )
1031 {
1032 m_editPoints->Line( i ).SetConstraint(
1033 new EC_PERPLINE( m_editPoints->Line( i ) ) );
1034 }
1035 }
1036
1037 if( sheet->GetPosition() != sheetNewPos )
1038 {
1039 //Keep pins in the place they were before resizing
1040 for( SCH_SHEET_PIN* pin : sheet->GetPins() )
1041 {
1042 switch( pin->GetSide() )
1043 {
1044 case SHEET_SIDE::LEFT:
1045 case SHEET_SIDE::RIGHT:
1046 pin->Move( VECTOR2I( 0, sheet->GetPosition().y - sheetNewPos.y ) );
1047 break;
1048 case SHEET_SIDE::TOP:
1049 case SHEET_SIDE::BOTTOM:
1050 pin->Move( VECTOR2I( sheet->GetPosition().x - sheetNewPos.x, 0 ) );
1051 break;
1053 break;
1054 }
1055 }
1056
1057 sheet->SetPosition( sheetNewPos );
1058 }
1059
1060 if( sheet->GetSize() != sheetNewSize )
1061 {
1062 sheet->Resize( sheetNewSize );
1063 }
1064
1065 break;
1066 }
1067
1068 case SCH_LINE_T:
1069 {
1070 SCH_LINE* line = (SCH_LINE*) item;
1071
1072 line->SetStartPoint( m_editPoints->Point( LINE_START ).GetPosition() );
1073 line->SetEndPoint( m_editPoints->Point( LINE_END ).GetPosition() );
1074
1075 std::pair<EDA_ITEM*, int> connected = m_editPoints->Point( LINE_START ).GetConnected();
1076
1077 if( connected.first )
1078 {
1079 if( connected.second == STARTPOINT )
1080 static_cast<SCH_LINE*>( connected.first )->SetStartPoint( line->GetStartPoint() );
1081 else if( connected.second == ENDPOINT )
1082 static_cast<SCH_LINE*>( connected.first )->SetEndPoint( line->GetStartPoint() );
1083
1084 updateItem( connected.first, true );
1085 }
1086
1087 connected = m_editPoints->Point( LINE_END ).GetConnected();
1088
1089 if( connected.first )
1090 {
1091 if( connected.second == STARTPOINT )
1092 static_cast<SCH_LINE*>( connected.first )->SetStartPoint( line->GetEndPoint() );
1093 else if( connected.second == ENDPOINT )
1094 static_cast<SCH_LINE*>( connected.first )->SetEndPoint( line->GetEndPoint() );
1095
1096 updateItem( connected.first, true );
1097 }
1098
1099 break;
1100 }
1101
1102 default:
1103 break;
1104 }
1105
1106 updateItem( item, true );
1107 m_frame->SetMsgPanel( item );
1108}
1109
1110
1112{
1113 if( !m_editPoints )
1114 return;
1115
1116 EDA_ITEM* item = m_editPoints->GetParent();
1117
1118 if( !item )
1119 return;
1120
1121 switch( item->Type() )
1122 {
1123 case LIB_SHAPE_T:
1124 {
1125 LIB_SHAPE* shape = static_cast<LIB_SHAPE*>( item );
1126
1127 switch( shape->GetShape() )
1128 {
1129 case SHAPE_T::ARC:
1130 m_editPoints->Point( ARC_CENTER ).SetPosition( mapCoords( shape->GetPosition() ) );
1131 m_editPoints->Point( ARC_START ).SetPosition( mapCoords( shape->GetStart() ) );
1132 m_editPoints->Point( ARC_END ).SetPosition( mapCoords( shape->GetEnd() ) );
1133 break;
1134
1135 case SHAPE_T::CIRCLE:
1136 m_editPoints->Point( CIRC_CENTER ).SetPosition( mapCoords( shape->GetPosition() ) );
1137 m_editPoints->Point( CIRC_END ).SetPosition( mapCoords( shape->GetEnd() ) );
1138 break;
1139
1140 case SHAPE_T::POLY:
1141 {
1142 if( (int) m_editPoints->PointsSize() != shape->GetPointCount() )
1143 {
1144 getView()->Remove( m_editPoints.get() );
1145 m_editedPoint = nullptr;
1147 getView()->Add( m_editPoints.get() );
1148 }
1149 else
1150 {
1151 int ii = 0;
1152
1153 for( const VECTOR2I& pt : shape->GetPolyShape().Outline( 0 ).CPoints() )
1154 m_editPoints->Point( ii++ ).SetPosition( mapCoords( pt ) );
1155 }
1156
1157 break;
1158 }
1159
1160 case SHAPE_T::RECT:
1161 {
1162 // point editor works only with rectangles having width and height > 0
1163 // Some symbols can have rectangles with width or height < 0
1164 // So normalize the size:
1165 BOX2I dummy;
1166 dummy.SetOrigin( mapCoords( shape->GetPosition() ) );
1167 dummy.SetEnd( mapCoords( shape->GetEnd() ) );
1168 dummy.Normalize();
1169 VECTOR2I topLeft = dummy.GetPosition();
1170 VECTOR2I botRight = dummy.GetEnd();
1171
1172 m_editPoints->Point( RECT_TOPLEFT ).SetPosition( topLeft );
1173 m_editPoints->Point( RECT_TOPRIGHT ).SetPosition( VECTOR2I( botRight.x, topLeft.y ) );
1174 m_editPoints->Point( RECT_BOTLEFT ).SetPosition( VECTOR2I( topLeft.x, botRight.y ) );
1175 m_editPoints->Point( RECT_BOTRIGHT ).SetPosition( botRight );
1176 break;
1177 }
1178
1179 case SHAPE_T::BEZIER:
1180 // TODO
1181 break;
1182
1183 default:
1185 }
1186
1187 break;
1188 }
1189
1190 case LIB_TEXTBOX_T:
1191 {
1192 LIB_TEXTBOX* textbox = static_cast<LIB_TEXTBOX*>( item );
1193
1194 // point editor works only with rectangles having width and height > 0
1195 // Some symbols can have rectangles with width or height < 0
1196 // So normalize the size:
1197 BOX2I dummy;
1198 dummy.SetOrigin( mapCoords( textbox->GetPosition() ) );
1199 dummy.SetEnd( mapCoords( textbox->GetEnd() ) );
1200 dummy.Normalize();
1201 VECTOR2I topLeft = dummy.GetPosition();
1202 VECTOR2I botRight = dummy.GetEnd();
1203
1204 m_editPoints->Point( RECT_TOPLEFT ).SetPosition( topLeft );
1205 m_editPoints->Point( RECT_TOPRIGHT ).SetPosition( VECTOR2I( botRight.x, topLeft.y ) );
1206 m_editPoints->Point( RECT_BOTLEFT ).SetPosition( VECTOR2I( topLeft.x, botRight.y ) );
1207 m_editPoints->Point( RECT_BOTRIGHT ).SetPosition( botRight );
1208 break;
1209 }
1210
1211 case SCH_SHAPE_T:
1212 {
1213 SCH_SHAPE* shape = static_cast<SCH_SHAPE*>( item );
1214
1215 switch( shape->GetShape() )
1216 {
1217 case SHAPE_T::ARC:
1218 m_editPoints->Point( ARC_CENTER ).SetPosition( shape->GetPosition() );
1219 m_editPoints->Point( ARC_START ).SetPosition( shape->GetStart() );
1220 m_editPoints->Point( ARC_END ).SetPosition( shape->GetEnd() );
1221 break;
1222
1223 case SHAPE_T::CIRCLE:
1224 m_editPoints->Point( CIRC_CENTER ).SetPosition( shape->GetPosition() );
1225 m_editPoints->Point( CIRC_END ).SetPosition( shape->GetEnd() );
1226 break;
1227
1228 case SHAPE_T::POLY:
1229 {
1230 if( (int) m_editPoints->PointsSize() != shape->GetPointCount() )
1231 {
1232 getView()->Remove( m_editPoints.get() );
1233 m_editedPoint = nullptr;
1235 getView()->Add( m_editPoints.get() );
1236 }
1237 else
1238 {
1239 int ii = 0;
1240
1241 for( const VECTOR2I& pt : shape->GetPolyShape().Outline( 0 ).CPoints() )
1242 m_editPoints->Point( ii++ ).SetPosition( pt );
1243 }
1244
1245 break;
1246 }
1247
1248 case SHAPE_T::RECT:
1249 {
1250 // point editor works only with rectangles having width and height > 0
1251 // Some symbols can have rectangles with width or height < 0
1252 // So normalize the size:
1253 BOX2I dummy;
1254 dummy.SetOrigin( shape->GetPosition() );
1255 dummy.SetEnd( shape->GetEnd() );
1256 dummy.Normalize();
1257 VECTOR2I topLeft = dummy.GetPosition();
1258 VECTOR2I botRight = dummy.GetEnd();
1259
1260 m_editPoints->Point( RECT_TOPLEFT ).SetPosition( topLeft );
1261 m_editPoints->Point( RECT_TOPRIGHT ).SetPosition( VECTOR2I( botRight.x, topLeft.y ) );
1262 m_editPoints->Point( RECT_BOTLEFT ).SetPosition( VECTOR2I( topLeft.x, botRight.y ) );
1263 m_editPoints->Point( RECT_BOTRIGHT ).SetPosition( botRight );
1264 break;
1265 }
1266
1267 case SHAPE_T::BEZIER:
1268 // TODO
1269 break;
1270
1271 default:
1273 }
1274
1275 break;
1276 }
1277
1278 case SCH_TEXTBOX_T:
1279 {
1280 SCH_TEXTBOX* textBox = static_cast<SCH_TEXTBOX*>( item );
1281
1282 // point editor works only with rectangles having width and height > 0
1283 // Some symbols can have rectangles with width or height < 0
1284 // So normalize the size:
1285 BOX2I dummy;
1286 dummy.SetOrigin( textBox->GetPosition() );
1287 dummy.SetEnd( textBox->GetEnd() );
1288 dummy.Normalize();
1289 VECTOR2I topLeft = dummy.GetPosition();
1290 VECTOR2I botRight = dummy.GetEnd();
1291
1292 m_editPoints->Point( RECT_TOPLEFT ).SetPosition( topLeft );
1293 m_editPoints->Point( RECT_TOPRIGHT ).SetPosition( VECTOR2I( botRight.x, topLeft.y ) );
1294 m_editPoints->Point( RECT_BOTLEFT ).SetPosition( VECTOR2I( topLeft.x, botRight.y ) );
1295 m_editPoints->Point( RECT_BOTRIGHT ).SetPosition( botRight );
1296 break;
1297 }
1298
1299 case SCH_BITMAP_T:
1300 {
1301 SCH_BITMAP* bitmap = (SCH_BITMAP*) item;
1302 VECTOR2I topLeft = bitmap->GetPosition() - bitmap->GetSize() / 2;
1303 VECTOR2I botRight = bitmap->GetPosition() + bitmap->GetSize() / 2;
1304
1305 m_editPoints->Point( RECT_TOPLEFT ).SetPosition( topLeft );
1306 m_editPoints->Point( RECT_TOPRIGHT ).SetPosition( botRight.x, topLeft.y );
1307 m_editPoints->Point( RECT_BOTLEFT ).SetPosition( topLeft.x, botRight.y );
1308 m_editPoints->Point( RECT_BOTRIGHT ).SetPosition( botRight );
1309 break;
1310 }
1311
1312 case SCH_SHEET_T:
1313 {
1314 SCH_SHEET* sheet = (SCH_SHEET*) item;
1315 VECTOR2I topLeft = sheet->GetPosition();
1316 VECTOR2I botRight = sheet->GetPosition() + sheet->GetSize();
1317
1318 m_editPoints->Point( RECT_TOPLEFT ).SetPosition( topLeft );
1319 m_editPoints->Point( RECT_TOPRIGHT ).SetPosition( botRight.x, topLeft.y );
1320 m_editPoints->Point( RECT_BOTLEFT ).SetPosition( topLeft.x, botRight.y );
1321 m_editPoints->Point( RECT_BOTRIGHT ).SetPosition( botRight );
1322 break;
1323 }
1324
1325 case SCH_LINE_T:
1326 {
1327 SCH_LINE* line = (SCH_LINE*) item;
1328
1329 m_editPoints->Point( LINE_START ).SetPosition( line->GetStartPoint() );
1330 m_editPoints->Point( LINE_END ).SetPosition( line->GetEndPoint() );
1331 break;
1332 }
1333
1334 default:
1335 break;
1336 }
1337
1338 getView()->Update( m_editPoints.get() );
1339}
1340
1341
1343{
1345
1346 if( aPoint )
1347 {
1349 controls->ForceCursorPosition( true, aPoint->GetPosition() );
1350 controls->ShowCursor( true );
1351 }
1352 else
1353 {
1354 if( m_frame->ToolStackIsEmpty() )
1355 controls->ShowCursor( false );
1356
1357 controls->ForceCursorPosition( false );
1358 }
1359
1360 m_editedPoint = aPoint;
1361}
1362
1363
1365{
1366 if( !m_editPoints || !m_editedPoint || m_editPoints->GetParent()->Type() != LIB_SHAPE_T )
1367 return false;
1368
1369 LIB_SHAPE* shape = static_cast<LIB_SHAPE*>( m_editPoints->GetParent() );
1370
1371 if( shape->GetPolyShape().IsEmpty() )
1372 return false;
1373
1374 SHAPE_LINE_CHAIN& poly = shape->GetPolyShape().Outline( 0 );
1375
1376 if( poly.GetPointCount() < 3 )
1377 return false;
1378
1379 for( const VECTOR2I& pt : poly.CPoints() )
1380 {
1381 if( pt == mapCoords( m_editedPoint->GetPosition() ) )
1382 return true;
1383 }
1384
1385 return false;
1386}
1387
1388
1390{
1391 if( !m_editPoints || m_editPoints->GetParent()->Type() != LIB_SHAPE_T )
1392 return false;
1393
1394 LIB_SHAPE* shape = static_cast<LIB_SHAPE*>( m_editPoints->GetParent() );
1395
1396 if( shape->GetShape() != SHAPE_T::POLY )
1397 return false;
1398
1399 VECTOR2I cursorPos = getViewControls()->GetCursorPosition( false );
1400 double threshold = getView()->ToWorld( EDIT_POINT::POINT_SIZE );
1401
1402 return shape->HitTest( cursorPos, (int) threshold );
1403}
1404
1405
1407{
1408 if( !m_editPoints || m_editPoints->GetParent()->Type() != LIB_SHAPE_T )
1409 return 0;
1410
1411 LIB_SHAPE* shape = static_cast<LIB_SHAPE*>( m_editPoints->GetParent() );
1412 SHAPE_LINE_CHAIN& poly = shape->GetPolyShape().Outline( 0 );
1413
1415 VECTOR2I pos = mapCoords( cursor );
1416 int currentMinDistance = INT_MAX;
1417 int closestLineStart = 0;
1418
1419 for( unsigned i = 0; i < poly.GetPointCount() - 1; ++i )
1420 {
1421 int distance = (int) DistanceLinePoint( poly.CPoint( i ),
1422 poly.CPoint( i + 1 ), pos );
1423
1424 if( distance < currentMinDistance )
1425 {
1426 currentMinDistance = distance;
1427 closestLineStart = i;
1428 }
1429 }
1430
1432 poly.Insert( closestLineStart + 1, pos );
1433
1434 updateItem( shape, true );
1435 updatePoints();
1436
1437 m_frame->OnModify();
1438
1439 return 0;
1440}
1441
1442
1444{
1445 if( !m_editPoints || !m_editedPoint || m_editPoints->GetParent()->Type() != LIB_SHAPE_T )
1446 return 0;
1447
1448 LIB_SHAPE* shape = static_cast<LIB_SHAPE*>( m_editPoints->GetParent() );
1449 SHAPE_LINE_CHAIN& poly = shape->GetPolyShape().Outline( 0 );
1450
1451 if( poly.GetPointCount() < 3 )
1452 return 0;
1453
1455 poly.Remove( getEditedPointIndex() );
1456
1457 updateItem( shape, true );
1458 updatePoints();
1459
1460 m_frame->OnModify();
1461
1462 return 0;
1463}
1464
1465
1467{
1468 updatePoints();
1469 return 0;
1470}
1471
1472
1474{
1475 if( m_isSymbolEditor )
1476 {
1477 saveCopyInUndoList( m_editPoints->GetParent()->GetParent(), UNDO_REDO::LIBEDIT );
1478 }
1479 else
1480 {
1482
1483 if( m_editPoints->GetParent()->Type() == SCH_LINE_T )
1484 {
1485 std::pair<EDA_ITEM*, int> connected = m_editPoints->Point( LINE_START ).GetConnected();
1486
1487 if( connected.first )
1488 saveCopyInUndoList( (SCH_ITEM*) connected.first, UNDO_REDO::CHANGED, true );
1489
1490 connected = m_editPoints->Point( LINE_END ).GetConnected();
1491
1492 if( connected.first )
1493 saveCopyInUndoList( (SCH_ITEM*) connected.first, UNDO_REDO::CHANGED, true );
1494 }
1495 }
1496}
1497
1498
1500{
1501 if( m_isSymbolEditor )
1502 static_cast<SYMBOL_EDIT_FRAME*>( m_frame )->RollbackSymbolFromUndo();
1503 else
1504 static_cast<SCH_EDIT_FRAME*>( m_frame )->RollbackSchematicFromUndo();
1505}
1506
1507
1509{
1517}
1518
1519
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:173
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:181
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:1254
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:440
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:146
static TOOL_ACTION pointEditorAddCorner
Definition: ee_actions.h:145
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:191
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:209
static const TOOL_EVENT SelectedEvent
Definition: actions.h:207
static const TOOL_EVENT SelectedItemsModified
Selected items were moved, this can be very high frequency on the canvas, use with care.
Definition: actions.h:214
static const TOOL_EVENT PointSelectedEvent
Definition: actions.h:206
bool GetSnap() const
Definition: grid_helper.h:66
void SetSnap(bool aSnap)
Definition: grid_helper.h:65
VECTOR2I AlignGrid(const VECTOR2I &aPoint) const
Definition: grid_helper.cpp:91
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:349
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:1591
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:448
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:68
VECTOR2I GetPosition() const override
Definition: sch_bitmap.h:138
VECTOR2I GetSize() const
Definition: sch_bitmap.cpp:138
void SetImageScale(double aScale)
Definition: sch_bitmap.h:73
Schematic editor (Eeschema) main window.
Base class for any item which can be embedded within the SCHEMATIC container class,...
Definition: sch_item.h:147
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:57
void SetPosition(const VECTOR2I &aPosition) override
Definition: sch_sheet.cpp:907
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:488
VECTOR2I GetSize() const
Definition: sch_sheet.h:108
VECTOR2I GetPosition() const override
Definition: sch_sheet.h:368
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:522
void Resize(const VECTOR2I &aSize)
Resize this sheet to aSize and adjust all of the labels accordingly.
Definition: sch_sheet.cpp:915
std::vector< SCH_SHEET_PIN * > & GetPins()
Definition: sch_sheet.h:175
EDA_ITEM * Front() const
Definition: selection.h:208
int Size() const
Returns the number of selected parts.
Definition: selection.h:115
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:215
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)
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:590