KiCad PCB EDA Suite
Loading...
Searching...
No Matches
sch_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 The 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, see <https://www.gnu.org/licenses/>.
19 */
20
21#include "sch_point_editor.h"
22
23#include <algorithm>
24#include <ee_grid_helper.h>
25#include <tool/tool_manager.h>
26#include <sch_commit.h>
27#include <view/view_controls.h>
29#include <geometry/seg.h>
33#include <tools/sch_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_table.h>
41#include <sch_sheet_pin.h>
43#include <sch_no_connect.h>
44
45
53
54
55static std::optional<SNAP_CANDIDATE> authoredSnapRelation( const EDIT_RELATION& aRelation )
56{
57 const SNAP_STABLE_ID id{ SNAP_ID_KIND::INTRINSIC_ANCHOR, {}, static_cast<int>( aRelation.Kind() ), 0 };
58 const EDIT_POINT* reference = aRelation.Reference();
59
60 switch( aRelation.Kind() )
61 {
63 if( !reference )
64 return std::nullopt;
65
68
70 if( !reference )
71 return std::nullopt;
72
75
77 if( !reference )
78 return std::nullopt;
79
82 aRelation.Direction(), 0.0 );
83
85 {
86 const EDIT_POINT* secondary = aRelation.SecondaryReference();
87
88 if( !reference || !secondary )
89 return std::nullopt;
90
91 SNAP_CANDIDATE candidate;
92 candidate.id = id;
96 candidate.origin = reference->GetPosition();
97 candidate.consumedDof = 1;
98 candidate.manifold =
99 CIRCLE( reference->GetPosition(), reference->GetPosition().Distance( secondary->GetPosition() ) );
100 return candidate;
101 }
102
106 0.0 );
107
108 default: return std::nullopt;
109 }
110}
111
112
113// Few constants to avoid using bare numbers for point indices
120
121
131
132
140
141
146
147
152
157
158
160{
161public:
163 m_line( aLine ),
164 m_screen( aScreen )
165 {
166 }
167
168 void MakePoints( EDIT_POINTS& aPoints ) override
169 {
170 std::pair<EDA_ITEM*, int> connectedStart = { nullptr, STARTPOINT };
171 std::pair<EDA_ITEM*, int> connectedEnd = { nullptr, STARTPOINT };
172
173 for( SCH_ITEM* test : m_screen.Items().OfType( SCH_LINE_T ) )
174 {
175 if( test->GetLayer() != LAYER_NOTES )
176 continue;
177
178 if( test == &m_line )
179 continue;
180
181 SCH_LINE* testLine = static_cast<SCH_LINE*>( test );
182
183 if( testLine->GetStartPoint() == m_line.GetStartPoint() )
184 {
185 connectedStart = { testLine, STARTPOINT };
186 }
187 else if( testLine->GetEndPoint() == m_line.GetStartPoint() )
188 {
189 connectedStart = { testLine, ENDPOINT };
190 }
191 else if( testLine->GetStartPoint() == m_line.GetEndPoint() )
192 {
193 connectedEnd = { testLine, STARTPOINT };
194 }
195 else if( testLine->GetEndPoint() == m_line.GetEndPoint() )
196 {
197 connectedEnd = { testLine, ENDPOINT };
198 }
199 }
200
201 aPoints.AddPoint( m_line.GetStartPoint(), connectedStart );
202 aPoints.AddPoint( m_line.GetEndPoint(), connectedEnd );
203 }
204
205 bool UpdatePoints( EDIT_POINTS& aPoints ) override
206 {
207 aPoints.Point( LINE_START ).SetPosition( m_line.GetStartPoint() );
208 aPoints.Point( LINE_END ).SetPosition( m_line.GetEndPoint() );
209 return true;
210 }
211
212 void UpdateItem( const EDIT_POINT& aEditedPoints, EDIT_POINTS& aPoints, COMMIT& aCommit,
213 std::vector<EDA_ITEM*>& aUpdatedItems ) override
214 {
215 m_line.SetStartPoint( aPoints.Point( LINE_START ).GetPosition() );
216 m_line.SetEndPoint( aPoints.Point( LINE_END ).GetPosition() );
217
218 std::pair<EDA_ITEM*, int> connected = aPoints.Point( LINE_START ).GetConnected();
219
220 if( connected.first )
221 {
222 aCommit.Modify( connected.first, &m_screen );
223 aUpdatedItems.push_back( connected.first );
224
225 if( connected.second == STARTPOINT )
226 static_cast<SCH_LINE*>( connected.first )->SetStartPoint( m_line.GetStartPoint() );
227 else if( connected.second == ENDPOINT )
228 static_cast<SCH_LINE*>( connected.first )->SetEndPoint( m_line.GetStartPoint() );
229 }
230
231 connected = aPoints.Point( LINE_END ).GetConnected();
232
233 if( connected.first )
234 {
235 aCommit.Modify( connected.first, &m_screen );
236 aUpdatedItems.push_back( connected.first );
237
238 if( connected.second == STARTPOINT )
239 static_cast<SCH_LINE*>( connected.first )->SetStartPoint( m_line.GetEndPoint() );
240 else if( connected.second == ENDPOINT )
241 static_cast<SCH_LINE*>( connected.first )->SetEndPoint( m_line.GetEndPoint() );
242 }
243 }
244
245private:
248};
249
251{
252public:
254 m_bitmap( aBitmap )
255 {
256 }
257
258 void MakePoints( EDIT_POINTS& aPoints ) override
259 {
260 const REFERENCE_IMAGE& refImage = m_bitmap.GetReferenceImage();
261 const VECTOR2I topLeft = refImage.GetPosition() - refImage.GetSize() / 2;
262 const VECTOR2I botRight = refImage.GetPosition() + refImage.GetSize() / 2;
263
264 aPoints.AddPoint( topLeft );
265 aPoints.AddPoint( VECTOR2I( botRight.x, topLeft.y ) );
266 aPoints.AddPoint( VECTOR2I( topLeft.x, botRight.y ) );
267 aPoints.AddPoint( botRight );
268
269 aPoints.AddPoint( refImage.GetPosition() + refImage.GetTransformOriginOffset() );
270 }
271
272 bool UpdatePoints( EDIT_POINTS& aPoints ) override
273 {
274 const REFERENCE_IMAGE& refImage = m_bitmap.GetReferenceImage();
275 const VECTOR2I topLeft = refImage.GetPosition() - refImage.GetSize() / 2;
276 const VECTOR2I botRight = refImage.GetPosition() + refImage.GetSize() / 2;
277
278 aPoints.Point( RECT_TOPLEFT ).SetPosition( topLeft );
279 aPoints.Point( RECT_TOPRIGHT ).SetPosition( botRight.x, topLeft.y );
280 aPoints.Point( RECT_BOTLEFT ).SetPosition( topLeft.x, botRight.y );
281 aPoints.Point( RECT_BOTRIGHT ).SetPosition( botRight );
282
283 aPoints.Point( REFIMG_ORIGIN ).SetPosition( refImage.GetPosition() + refImage.GetTransformOriginOffset() );
284 return true;
285 }
286
287 void UpdateItem( const EDIT_POINT& aEditedPoint, EDIT_POINTS& aPoints, COMMIT& aCommit,
288 std::vector<EDA_ITEM*>& aUpdatedItems ) override
289 {
290 REFERENCE_IMAGE& refImg = m_bitmap.GetReferenceImage();
291 const VECTOR2I topLeft = aPoints.Point( RECT_TOPLEFT ).GetPosition();
292 const VECTOR2I topRight = aPoints.Point( RECT_TOPRIGHT ).GetPosition();
293 const VECTOR2I botLeft = aPoints.Point( RECT_BOTLEFT ).GetPosition();
294 const VECTOR2I botRight = aPoints.Point( RECT_BOTRIGHT ).GetPosition();
295 const VECTOR2I xfrmOrigin = aPoints.Point( REFIMG_ORIGIN ).GetPosition();
296
297 if( isModified( aEditedPoint, aPoints.Point( REFIMG_ORIGIN ) ) )
298 {
299 // Moving the transform origin
300 // As the other points didn't move, we can get the image extent from them
301 const VECTOR2I newOffset = xfrmOrigin - ( topLeft + botRight ) / 2;
302 refImg.SetTransformOriginOffset( newOffset );
303 }
304 else
305 {
306 const VECTOR2I oldOrigin = refImg.GetPosition() + refImg.GetTransformOriginOffset();
307 const VECTOR2I oldSize = refImg.GetSize();
308 const VECTOR2I pos = refImg.GetPosition();
309
310 OPT_VECTOR2I newCorner;
311 VECTOR2I oldCorner = pos;
312
313 if( isModified( aEditedPoint, aPoints.Point( RECT_TOPLEFT ) ) )
314 {
315 newCorner = topLeft;
316 oldCorner -= oldSize / 2;
317 }
318 else if( isModified( aEditedPoint, aPoints.Point( RECT_TOPRIGHT ) ) )
319 {
320 newCorner = topRight;
321 oldCorner -= VECTOR2I( -oldSize.x, oldSize.y ) / 2;
322 }
323 else if( isModified( aEditedPoint, aPoints.Point( RECT_BOTLEFT ) ) )
324 {
325 newCorner = botLeft;
326 oldCorner -= VECTOR2I( oldSize.x, -oldSize.y ) / 2;
327 }
328 else if( isModified( aEditedPoint, aPoints.Point( RECT_BOTRIGHT ) ) )
329 {
330 newCorner = botRight;
331 oldCorner += oldSize / 2;
332 }
333
334 if( newCorner )
335 {
336 // Turn in the respective vectors from the origin
337 *newCorner -= xfrmOrigin;
338 oldCorner -= oldOrigin;
339
340 // If we tried to cross the origin, clamp it to stop it
341 if( sign( newCorner->x ) != sign( oldCorner.x )
342 || sign( newCorner->y ) != sign( oldCorner.y ) )
343 {
344 *newCorner = VECTOR2I( 0, 0 );
345 }
346
347 const double newLength = newCorner->EuclideanNorm();
348 const double oldLength = oldCorner.EuclideanNorm();
349
350 double ratio = oldLength > 0 ? ( newLength / oldLength ) : 1.0;
351
352 // Clamp the scaling to a minimum of 50 mils
353 VECTOR2I newSize = oldSize * ratio;
354 double newWidth = std::max( newSize.x, EDA_UNIT_UTILS::Mils2IU( schIUScale, 50 ) );
355 double newHeight = std::max( newSize.y, EDA_UNIT_UTILS::Mils2IU( schIUScale, 50 ) );
356 ratio = std::min( newWidth / oldSize.x, newHeight / oldSize.y );
357
358 // Also handles the origin offset
359 refImg.SetImageScale( refImg.GetImageScale() * ratio );
360 }
361 }
362 aUpdatedItems.push_back( &m_bitmap );
363 }
364
365private:
367};
368
369
371{
372public:
375 m_cell( aCell ),
376 m_screen( aScreen )
377 {
378 }
379
380 void UpdateItem( const EDIT_POINT& aEditedPoint, EDIT_POINTS& aPoints, COMMIT& aCommit,
381 std::vector<EDA_ITEM*>& aUpdatedItems ) override
382 {
383 SCH_TABLE& table = static_cast<SCH_TABLE&>( *m_cell.GetParent() );
384 bool rotated = !m_cell.GetTextAngle().IsHorizontal();
385
386 aCommit.Modify( &table, &m_screen );
387 aUpdatedItems.push_back( &table );
388
389 if( rotated )
390 {
391 if( isModified( aEditedPoint, aPoints.Point( ROW_HEIGHT ) ) )
392 {
393 m_cell.SetEnd( VECTOR2I( m_cell.GetEndX(), aPoints.Point( ROW_HEIGHT ).GetY() ) );
394
395 int colWidth = std::abs( m_cell.GetRectangleHeight() );
396
397 for( int ii = 0; ii < m_cell.GetColSpan() - 1; ++ii )
398 colWidth -= table.GetColWidth( m_cell.GetColumn() + ii );
399
400 table.SetColWidth( m_cell.GetColumn() + m_cell.GetColSpan() - 1, colWidth );
401 }
402 else if( isModified( aEditedPoint, aPoints.Point( COL_WIDTH ) ) )
403 {
404 m_cell.SetEnd( VECTOR2I( aPoints.Point( COL_WIDTH ).GetX(), m_cell.GetEndY() ) );
405
406 int rowHeight = m_cell.GetRectangleWidth();
407
408 for( int ii = 0; ii < m_cell.GetRowSpan() - 1; ++ii )
409 rowHeight -= table.GetRowHeight( m_cell.GetRow() + ii );
410
411 table.SetRowHeight( m_cell.GetRow() + m_cell.GetRowSpan() - 1, rowHeight );
412 }
413 }
414 else
415 {
416 if( isModified( aEditedPoint, aPoints.Point( COL_WIDTH ) ) )
417 {
418 m_cell.SetEnd( VECTOR2I( aPoints.Point( COL_WIDTH ).GetX(), m_cell.GetEndY() ) );
419
420 int colWidth = m_cell.GetRectangleWidth();
421
422 for( int ii = 0; ii < m_cell.GetColSpan() - 1; ++ii )
423 colWidth -= table.GetColWidth( m_cell.GetColumn() + ii );
424
425 table.SetColWidth( m_cell.GetColumn() + m_cell.GetColSpan() - 1, colWidth );
426 }
427 else if( isModified( aEditedPoint, aPoints.Point( ROW_HEIGHT ) ) )
428 {
429 m_cell.SetEnd( VECTOR2I( m_cell.GetEndX(), aPoints.Point( ROW_HEIGHT ).GetY() ) );
430
431 int rowHeight = m_cell.GetRectangleHeight();
432
433 for( int ii = 0; ii < m_cell.GetRowSpan() - 1; ++ii )
434 rowHeight -= table.GetRowHeight( m_cell.GetRow() + ii );
435
436 table.SetRowHeight( m_cell.GetRow() + m_cell.GetRowSpan() - 1, rowHeight );
437 }
438 }
439
440 table.Normalize();
441 }
442
443private:
446};
447
448
450{
451public:
453 m_rect( aRect ),
454 m_frame( aFrame )
455 {
456 }
457
458 static void MakePoints( SCH_SHAPE& aRect, EDIT_POINTS& aPoints )
459 {
460 VECTOR2I topLeft = aRect.GetPosition();
461 VECTOR2I botRight = aRect.GetEnd();
462
463 aPoints.AddPoint( topLeft );
464 aPoints.AddPoint( VECTOR2I( botRight.x, topLeft.y ) );
465 aPoints.AddPoint( VECTOR2I( topLeft.x, botRight.y ) );
466 aPoints.AddPoint( botRight );
467 aPoints.AddPoint( aRect.GetCenter() );
468 aPoints.AddPoint( VECTOR2I( botRight.x - aRect.GetCornerRadius(), topLeft.y ) );
469 aPoints.Point( RECT_RADIUS ).SetDrawCircle();
470
471 aPoints.AddLine( aPoints.Point( RECT_TOPLEFT ), aPoints.Point( RECT_TOPRIGHT ) );
473 aPoints.AddLine( aPoints.Point( RECT_TOPRIGHT ), aPoints.Point( RECT_BOTRIGHT ) );
475 aPoints.AddLine( aPoints.Point( RECT_BOTRIGHT ), aPoints.Point( RECT_BOTLEFT ) );
477 aPoints.AddLine( aPoints.Point( RECT_BOTLEFT ), aPoints.Point( RECT_TOPLEFT ) );
479 }
480
481 static void UpdatePoints( SCH_SHAPE& aRect, EDIT_POINTS& aPoints )
482 {
483 VECTOR2I topLeft = aRect.GetPosition();
484 VECTOR2I botRight = aRect.GetEnd();
485
486 aPoints.Point( RECT_TOPLEFT ).SetPosition( topLeft );
487 aPoints.Point( RECT_RADIUS ).SetPosition( VECTOR2I( botRight.x - aRect.GetCornerRadius(), topLeft.y ) );
488 aPoints.Point( RECT_TOPRIGHT ).SetPosition( VECTOR2I( botRight.x, topLeft.y ) );
489 aPoints.Point( RECT_BOTLEFT ).SetPosition( VECTOR2I( topLeft.x, botRight.y ) );
490 aPoints.Point( RECT_BOTRIGHT ).SetPosition( botRight );
491 aPoints.Point( RECT_CENTER ).SetPosition( aRect.GetCenter() );
492 }
493
504 static void PinEditedCorner( const EDIT_POINT& aEditedPoint, const EDIT_POINTS& aPoints,
505 int minWidth, int minHeight, VECTOR2I& topLeft, VECTOR2I& topRight,
506 VECTOR2I& botLeft, VECTOR2I& botRight )
507 {
508 if( isModified( aEditedPoint, aPoints.Point( RECT_TOPLEFT ) ) )
509 {
510 // pin edited point within opposite corner
511 topLeft.x = std::min( topLeft.x, botRight.x - minWidth );
512 topLeft.y = std::min( topLeft.y, botRight.y - minHeight );
513
514 // push edited point edges to adjacent corners
515 topRight.y = topLeft.y;
516 botLeft.x = topLeft.x;
517 }
518 else if( isModified( aEditedPoint, aPoints.Point( RECT_TOPRIGHT ) ) )
519 {
520 // pin edited point within opposite corner
521 topRight.x = std::max( topRight.x, botLeft.x + minWidth );
522 topRight.y = std::min( topRight.y, botLeft.y - minHeight );
523
524 // push edited point edges to adjacent corners
525 topLeft.y = topRight.y;
526 botRight.x = topRight.x;
527 }
528 else if( isModified( aEditedPoint, aPoints.Point( RECT_BOTLEFT ) ) )
529 {
530 // pin edited point within opposite corner
531 botLeft.x = std::min( botLeft.x, topRight.x - minWidth );
532 botLeft.y = std::max( botLeft.y, topRight.y + minHeight );
533
534 // push edited point edges to adjacent corners
535 botRight.y = botLeft.y;
536 topLeft.x = botLeft.x;
537 }
538 else if( isModified( aEditedPoint, aPoints.Point( RECT_BOTRIGHT ) ) )
539 {
540 // pin edited point within opposite corner
541 botRight.x = std::max( botRight.x, topLeft.x + minWidth );
542 botRight.y = std::max( botRight.y, topLeft.y + minHeight );
543
544 // push edited point edges to adjacent corners
545 botLeft.y = botRight.y;
546 topRight.x = botRight.x;
547 }
548 else if( isModified( aEditedPoint, aPoints.Line( RECT_TOP ) ) )
549 {
550 topLeft.y = std::min( topLeft.y, botRight.y - minHeight );
551 }
552 else if( isModified( aEditedPoint, aPoints.Line( RECT_LEFT ) ) )
553 {
554 topLeft.x = std::min( topLeft.x, botRight.x - minWidth );
555 }
556 else if( isModified( aEditedPoint, aPoints.Line( RECT_BOT ) ) )
557 {
558 botRight.y = std::max( botRight.y, topLeft.y + minHeight );
559 }
560 else if( isModified( aEditedPoint, aPoints.Line( RECT_RIGHT ) ) )
561 {
562 botRight.x = std::max( botRight.x, topLeft.x + minWidth );
563 }
564 }
565
566 static void UpdateItem( SCH_SHAPE& aRect, const EDIT_POINT& aEditedPoint,
567 EDIT_POINTS& aPoints, const VECTOR2I& aMinSize = { 0, 0 } )
568 {
569 VECTOR2I topLeft = aPoints.Point( RECT_TOPLEFT ).GetPosition();
570 VECTOR2I topRight = aPoints.Point( RECT_TOPRIGHT ).GetPosition();
571 VECTOR2I botLeft = aPoints.Point( RECT_BOTLEFT ).GetPosition();
572 VECTOR2I botRight = aPoints.Point( RECT_BOTRIGHT ).GetPosition();
573
574 int minWidth = std::max( schIUScale.MilsToIU( 1 ), aMinSize.x );
575 int minHeight = std::max( schIUScale.MilsToIU( 1 ), aMinSize.y );
576
577 PinEditedCorner( aEditedPoint, aPoints, minWidth, minHeight,
578 topLeft, topRight, botLeft, botRight );
579
580 if( isModified( aEditedPoint, aPoints.Point( RECT_TOPLEFT ) )
581 || isModified( aEditedPoint, aPoints.Point( RECT_TOPRIGHT ) )
582 || isModified( aEditedPoint, aPoints.Point( RECT_BOTRIGHT ) )
583 || isModified( aEditedPoint, aPoints.Point( RECT_BOTLEFT ) ) )
584 {
585 aRect.SetPosition( topLeft );
586 aRect.SetEnd( botRight );
587 }
588 else if( isModified( aEditedPoint, aPoints.Line( RECT_TOP ) ) )
589 {
590 aRect.SetStartY( topLeft.y );
591 }
592 else if( isModified( aEditedPoint, aPoints.Line( RECT_LEFT ) ) )
593 {
594 aRect.SetStartX( topLeft.x );
595 }
596 else if( isModified( aEditedPoint, aPoints.Line( RECT_BOT ) ) )
597 {
598 aRect.SetEndY( botRight.y );
599 }
600 else if( isModified( aEditedPoint, aPoints.Line( RECT_RIGHT ) ) )
601 {
602 aRect.SetEndX( botRight.x );
603 }
604
605 for( unsigned i = 0; i < aPoints.LinesSize(); ++i )
606 {
607 if( !isModified( aEditedPoint, aPoints.Line( i ) ) )
608 {
609 aPoints.Line( i ).SetRelation( EDIT_RELATION::PerpendicularTranslation( aPoints.Line( i ) ) );
610 }
611 }
612 }
613
614 void MakePoints( EDIT_POINTS& aPoints ) override
615 {
616 m_rect.Normalize();
617 MakePoints( m_rect, aPoints );
618 }
619
620 bool UpdatePoints( EDIT_POINTS& aPoints ) override
621 {
622 m_rect.Normalize();
623 UpdatePoints( m_rect, aPoints );
624 return true;
625 }
626
627 void UpdateItem( const EDIT_POINT& aEditedPoint, EDIT_POINTS& aPoints, COMMIT& aCommit,
628 std::vector<EDA_ITEM*>& aUpdatedItems ) override
629 {
630 VECTOR2I topLeft = aPoints.Point( RECT_TOPLEFT ).GetPosition();
631 VECTOR2I topRight = aPoints.Point( RECT_TOPRIGHT ).GetPosition();
632 VECTOR2I botLeft = aPoints.Point( RECT_BOTLEFT ).GetPosition();
633 VECTOR2I botRight = aPoints.Point( RECT_BOTRIGHT ).GetPosition();
634
635 PinEditedCorner( aEditedPoint, aPoints, schIUScale.MilsToIU( 1 ), schIUScale.MilsToIU( 1 ),
636 topLeft, topRight, botLeft, botRight );
637
638 const BOX2I oldBox = BOX2I::ByCorners( m_rect.GetStart(), m_rect.GetEnd() );
639 std::vector<SEG> oldSegs;
640 std::vector<VECTOR2I> moveVecs;
641
642 if( isModified( aEditedPoint, aPoints.Point( RECT_TOPLEFT ) )
643 || isModified( aEditedPoint, aPoints.Point( RECT_TOPRIGHT ) )
644 || isModified( aEditedPoint, aPoints.Point( RECT_BOTRIGHT ) )
645 || isModified( aEditedPoint, aPoints.Point( RECT_BOTLEFT ) ) )
646 {
647 // Corner drags don't update pins. Not only is it an escape hatch to avoid
648 // moving pins, it also avoids tricky problems when the pins "fall off"
649 // the ends of one of the two segments and get either left behind or
650 // "swept up" into the corner.
651 m_rect.SetPosition( topLeft );
652 m_rect.SetEnd( botRight );
653 }
654 else if( isModified( aEditedPoint, aPoints.Point( RECT_CENTER ) ) )
655 {
656 VECTOR2I moveVec = aPoints.Point( RECT_CENTER ).GetPosition() - oldBox.GetCenter();
657 m_rect.Move( moveVec );
658 }
659 else if( isModified( aEditedPoint, aPoints.Point( RECT_RADIUS ) ) )
660 {
661 int width = std::abs( botRight.x - topLeft.x );
662 int height = std::abs( botRight.y - topLeft.y );
663 int maxRadius = std::min( width, height ) / 2;
664 int x = aPoints.Point( RECT_RADIUS ).GetX();
665 x = std::clamp( x, botRight.x - maxRadius, botRight.x );
666 aPoints.Point( RECT_RADIUS ).SetPosition( VECTOR2I( x, topLeft.y ) );
667 m_rect.SetCornerRadius( botRight.x - x );
668 }
669 else if( isModified( aEditedPoint, aPoints.Line( RECT_TOP ) ) )
670 {
672 moveVecs.emplace_back( 0, topLeft.y - oldBox.GetTop() );
673 m_rect.SetStartY( topLeft.y );
674 }
675 else if( isModified( aEditedPoint, aPoints.Line( RECT_LEFT ) ) )
676 {
678 moveVecs.emplace_back( topLeft.x - oldBox.GetLeft(), 0 );
679 m_rect.SetStartX( topLeft.x );
680 }
681 else if( isModified( aEditedPoint, aPoints.Line( RECT_BOT ) ) )
682 {
684 moveVecs.emplace_back( 0, botRight.y - oldBox.GetBottom() );
685 m_rect.SetEndY( botRight.y );
686 }
687 else if( isModified( aEditedPoint, aPoints.Line( RECT_RIGHT ) ) )
688 {
690 moveVecs.emplace_back( botRight.x - oldBox.GetRight(), 0 );
691 m_rect.SetEndX( botRight.x );
692 }
693
694 dragPinsOnEdge( oldSegs, moveVecs, m_rect.GetUnit(), aCommit, aUpdatedItems );
695
696 for( unsigned i = 0; i < aPoints.LinesSize(); ++i )
697 {
698 if( !isModified( aEditedPoint, aPoints.Line( i ) ) )
699 {
700 aPoints.Line( i ).SetRelation( EDIT_RELATION::PerpendicularTranslation( aPoints.Line( i ) ) );
701 }
702 }
703 }
704
705private:
706 void dragPinsOnEdge( const std::vector<SEG>& aOldEdges, const std::vector<VECTOR2I>& aMoveVecs, int aEdgeUnit,
707 COMMIT& aCommit, std::vector<EDA_ITEM*>& aUpdatedItems ) const
708 {
709 wxCHECK( aOldEdges.size() == aMoveVecs.size(), /* void */ );
710
711 // This only make sense in the symbol editor
712 if( !m_frame.IsType( FRAME_SCH_SYMBOL_EDITOR ) )
713 return;
714
716
717 // And only if the setting is enabled
718 if( !editor.GetSettings()->m_dragPinsAlongWithEdges )
719 return;
720
721 // Adjuting pins on a different unit to a unit-limited shape
722 // seems suspect.
723 wxCHECK( aEdgeUnit == 0 || aEdgeUnit == editor.GetUnit(), /* void */ );
724
725 /*
726 * Get a list of pins on a line segment
727 */
728 const auto getPinsOnSeg =
729 []( LIB_SYMBOL& aSymbol, int aUnit, const SEG& aSeg,
730 bool aIncludeEnds ) -> std::vector<SCH_PIN*>
731 {
732 std::vector<SCH_PIN*> pins;
733
734 for( SCH_PIN* pin : aSymbol.GetGraphicalPins( aUnit, 0 ) )
735 {
736 // Figure out if the pin "connects" to the line
737 const VECTOR2I pinRootPos = pin->GetPinRoot();
738
739 if( aSeg.Contains( pinRootPos ) )
740 {
741 if( aIncludeEnds || ( pinRootPos != aSeg.A && pinRootPos != aSeg.B ) )
742 {
743 pins.push_back( pin );
744 }
745 }
746 }
747
748 return pins;
749 };
750
751 LIB_SYMBOL* const symbol = editor.GetCurSymbol();
752
753 for( std::size_t i = 0; i < aOldEdges.size(); ++i )
754 {
755 if( aMoveVecs[i] == VECTOR2I( 0, 0 ) || !symbol )
756 continue;
757
758 const std::vector<SCH_PIN*> pins = getPinsOnSeg( *symbol, aEdgeUnit, aOldEdges[i], false );
759
760 for( SCH_PIN* pin : pins )
761 {
762 aCommit.Modify( pin, editor.GetScreen() );
763 aUpdatedItems.push_back( pin );
764
765 // Move the pin
766 pin->Move( aMoveVecs[i] );
767 }
768 }
769 }
770
771private:
774};
775
776
778{
779public:
781 m_textbox( aTextbox )
782 {
783 }
784
785 void MakePoints( EDIT_POINTS& aPoints ) override
786 {
787 m_textbox.Normalize();
789 }
790
791 bool UpdatePoints( EDIT_POINTS& aPoints ) override
792 {
793 // point editor works only with rectangles having width and height > 0
794 // Some symbols can have rectangles with width or height < 0
795 // So normalize the size:
796 m_textbox.Normalize();
798 return true;
799 }
800
801 void UpdateItem( const EDIT_POINT& aEditedPoint, EDIT_POINTS& aPoints, COMMIT& aCommit,
802 std::vector<EDA_ITEM*>& aUpdatedItems ) override
803 {
804 m_textbox.ClearBoundingBoxCache();
805 VECTOR2I minSize = m_textbox.GetMinSize();
806
808 m_textbox.ClearRenderCache();
809 }
810
811private:
813};
814
815
817{
818public:
820 m_sheet( aSheet ),
821 m_screen( aScreen )
822 {
823 m_noConnects = m_sheet.GetNoConnects();
824
825 // Find all wires connected to sheet pins and store their connections
826 for( SCH_SHEET_PIN* pin : m_sheet.GetPins() )
827 {
828 VECTOR2I pinPos = pin->GetPosition();
829
830 for( SCH_ITEM* item : m_screen.Items().Overlapping( SCH_LINE_T, pinPos ) )
831 {
832 SCH_LINE* line = static_cast<SCH_LINE*>( item );
833
834 if( !line->IsWire() && !line->IsBus() )
835 continue;
836
837 if( line->GetStartPoint() == pinPos )
838 m_connectedWires.push_back( { pin, line, STARTPOINT } );
839 else if( line->GetEndPoint() == pinPos )
840 m_connectedWires.push_back( { pin, line, ENDPOINT } );
841 }
842 }
843 }
844
845 void MakePoints( EDIT_POINTS& aPoints ) override
846 {
847 VECTOR2I topLeft = m_sheet.GetPosition();
848 VECTOR2I botRight = m_sheet.GetPosition() + m_sheet.GetSize();
849
850 aPoints.AddPoint( topLeft );
851 aPoints.AddPoint( VECTOR2I( botRight.x, topLeft.y ) );
852 aPoints.AddPoint( VECTOR2I( topLeft.x, botRight.y ) );
853 aPoints.AddPoint( botRight );
854
855 aPoints.AddLine( aPoints.Point( RECT_TOPLEFT ), aPoints.Point( RECT_TOPRIGHT ) );
857 aPoints.AddLine( aPoints.Point( RECT_TOPRIGHT ), aPoints.Point( RECT_BOTRIGHT ) );
859 aPoints.AddLine( aPoints.Point( RECT_BOTRIGHT ), aPoints.Point( RECT_BOTLEFT ) );
861 aPoints.AddLine( aPoints.Point( RECT_BOTLEFT ), aPoints.Point( RECT_TOPLEFT ) );
863 }
864
865 bool UpdatePoints( EDIT_POINTS& aPoints ) override
866 {
867 VECTOR2I topLeft = m_sheet.GetPosition();
868 VECTOR2I botRight = m_sheet.GetPosition() + m_sheet.GetSize();
869
870 aPoints.Point( RECT_TOPLEFT ).SetPosition( topLeft );
871 aPoints.Point( RECT_TOPRIGHT ).SetPosition( botRight.x, topLeft.y );
872 aPoints.Point( RECT_BOTLEFT ).SetPosition( topLeft.x, botRight.y );
873 aPoints.Point( RECT_BOTRIGHT ).SetPosition( botRight );
874 return true;
875 }
876
877 void UpdateItem( const EDIT_POINT& aEditedPoint, EDIT_POINTS& aPoints, COMMIT& aCommit,
878 std::vector<EDA_ITEM*>& aUpdatedItems ) override
879 {
880 VECTOR2I topLeft = aPoints.Point( RECT_TOPLEFT ).GetPosition();
881 VECTOR2I topRight = aPoints.Point( RECT_TOPRIGHT ).GetPosition();
882 VECTOR2I botLeft = aPoints.Point( RECT_BOTLEFT ).GetPosition();
883 VECTOR2I botRight = aPoints.Point( RECT_BOTRIGHT ).GetPosition();
884 VECTOR2I sheetNewPos = m_sheet.GetPosition();
885 VECTOR2I sheetNewSize = m_sheet.GetSize();
886
887 bool editedTopRight = isModified( aEditedPoint, aPoints.Point( RECT_TOPRIGHT ) );
888 bool editedBotLeft = isModified( aEditedPoint, aPoints.Point( RECT_BOTLEFT ) );
889 bool editedBotRight = isModified( aEditedPoint, aPoints.Point( RECT_BOTRIGHT ) );
890
891 if( isModified( aEditedPoint, aPoints.Line( RECT_RIGHT ) ) )
892 editedTopRight = true;
893 else if( isModified( aEditedPoint, aPoints.Line( RECT_BOT ) ) )
894 editedBotLeft = true;
895
897 aEditedPoint, aPoints, m_sheet.GetMinWidth( editedTopRight || editedBotRight ),
898 m_sheet.GetMinHeight( editedBotLeft || editedBotRight ), topLeft, topRight, botLeft,
899 botRight );
900
901 if( isModified( aEditedPoint, aPoints.Point( RECT_TOPLEFT ) )
902 || isModified( aEditedPoint, aPoints.Point( RECT_TOPRIGHT ) )
903 || isModified( aEditedPoint, aPoints.Point( RECT_BOTRIGHT ) )
904 || isModified( aEditedPoint, aPoints.Point( RECT_BOTLEFT ) ) )
905 {
906 sheetNewPos = topLeft;
907 sheetNewSize = VECTOR2I( botRight.x - topLeft.x, botRight.y - topLeft.y );
908 }
909 else if( isModified( aEditedPoint, aPoints.Line( RECT_TOP ) ) )
910 {
911 sheetNewPos = VECTOR2I( m_sheet.GetPosition().x, topLeft.y );
912 sheetNewSize = VECTOR2I( m_sheet.GetSize().x, botRight.y - topLeft.y );
913 }
914 else if( isModified( aEditedPoint, aPoints.Line( RECT_LEFT ) ) )
915 {
916 sheetNewPos = VECTOR2I( topLeft.x, m_sheet.GetPosition().y );
917 sheetNewSize = VECTOR2I( botRight.x - topLeft.x, m_sheet.GetSize().y );
918 }
919 else if( isModified( aEditedPoint, aPoints.Line( RECT_BOT ) ) )
920 {
921 sheetNewSize = VECTOR2I( m_sheet.GetSize().x, botRight.y - topLeft.y );
922 }
923 else if( isModified( aEditedPoint, aPoints.Line( RECT_RIGHT ) ) )
924 {
925 sheetNewSize = VECTOR2I( botRight.x - topLeft.x, m_sheet.GetSize().y );
926 }
927
928 for( unsigned i = 0; i < aPoints.LinesSize(); ++i )
929 {
930 if( !isModified( aEditedPoint, aPoints.Line( i ) ) )
931 {
932 aPoints.Line( i ).SetRelation( EDIT_RELATION::PerpendicularTranslation( aPoints.Line( i ) ) );
933 }
934 }
935
936 if( m_sheet.GetPosition() != sheetNewPos )
937 m_sheet.SetPositionIgnoringPins( sheetNewPos );
938
939 if( m_sheet.GetSize() != sheetNewSize )
940 m_sheet.Resize( sheetNewSize );
941
942 // Update no-connects to follow their sheet pins
943 for( auto& [sheetPin, noConnect] : m_noConnects )
944 {
945 if( noConnect->GetPosition() != sheetPin->GetTextPos() )
946 {
947 aCommit.Modify( noConnect, &m_screen );
948 noConnect->SetPosition( sheetPin->GetTextPos() );
949 aUpdatedItems.push_back( noConnect );
950 }
951 }
952
953 // Update connected wires to follow their sheet pins
954 for( auto& [pin, line, endpoint] : m_connectedWires )
955 {
956 VECTOR2I newPinPos = pin->GetPosition();
957 bool needsUpdate = false;
958
959 if( endpoint == STARTPOINT && line->GetStartPoint() != newPinPos )
960 needsUpdate = true;
961 else if( endpoint == ENDPOINT && line->GetEndPoint() != newPinPos )
962 needsUpdate = true;
963
964 if( needsUpdate )
965 {
966 aCommit.Modify( line, &m_screen );
967
968 if( endpoint == STARTPOINT )
969 line->SetStartPoint( newPinPos );
970 else
971 line->SetEndPoint( newPinPos );
972
973 aUpdatedItems.push_back( line );
974 }
975 }
976 }
977
978private:
981 std::map<SCH_SHEET_PIN*, SCH_NO_CONNECT*> m_noConnects;
982 std::vector<std::tuple<SCH_SHEET_PIN*, SCH_LINE*, int>> m_connectedWires;
983};
984
985
987{
988 m_editBehavior = nullptr;
989 m_editPoints = std::make_shared<EDIT_POINTS>( aItem );
990
991 if( !aItem )
992 return;
993
994 // Generate list of edit points based on the item type
995 switch( aItem->Type() )
996 {
997 case SCH_SHAPE_T:
998 {
999 SCH_SHAPE* shape = static_cast<SCH_SHAPE*>( aItem );
1000
1001 switch( shape->GetShape() )
1002 {
1003 case SHAPE_T::ARC:
1004 // EDA_ARC_POINT_EDIT_BEHAVIOR holds a reference to m_arcEditMode, so the
1005 // persisted value must be synced from settings before the behavior is built.
1006 if( m_isSymbolEditor )
1007 {
1008 if( SYMBOL_EDITOR_SETTINGS* cfg = m_frame->libeditconfig() )
1009 m_arcEditMode = cfg->m_ArcEditMode;
1010 }
1011 else if( EESCHEMA_SETTINGS* cfg = m_frame->eeconfig() )
1012 {
1013 m_arcEditMode = cfg->m_Drawing.arc_edit_mode;
1014 }
1015
1016 m_editBehavior = std::make_unique<EDA_ARC_POINT_EDIT_BEHAVIOR>( *shape, m_arcEditMode, *getViewControls(),
1017 schIUScale );
1018 break;
1019 case SHAPE_T::CIRCLE: m_editBehavior = std::make_unique<EDA_CIRCLE_POINT_EDIT_BEHAVIOR>( *shape ); break;
1020 case SHAPE_T::RECTANGLE:
1021 m_editBehavior = std::make_unique<RECTANGLE_POINT_EDIT_BEHAVIOR>( *shape, *m_frame );
1022 break;
1023 case SHAPE_T::POLY: m_editBehavior = std::make_unique<EDA_POLYGON_POINT_EDIT_BEHAVIOR>( *shape ); break;
1024 case SHAPE_T::BEZIER:
1025 {
1026 int maxError = schIUScale.mmToIU( ARC_LOW_DEF_MM );
1027
1028 if( SCHEMATIC* schematic = shape->Schematic() )
1029 maxError = schematic->Settings().m_MaxError;
1030
1031 m_editBehavior = std::make_unique<EDA_BEZIER_POINT_EDIT_BEHAVIOR>( *shape, maxError );
1032 break;
1033 }
1034 case SHAPE_T::ELLIPSE:
1035 case SHAPE_T::ELLIPSE_ARC: m_editBehavior = std::make_unique<EDA_ELLIPSE_POINT_EDIT_BEHAVIOR>( *shape ); break;
1036 default:
1038 }
1039
1040 break;
1041 }
1042 case SCH_RULE_AREA_T:
1043 {
1044 SCH_SHAPE* shape = static_cast<SCH_SHAPE*>( aItem );
1045 // Implemented directly as a polygon
1046 m_editBehavior = std::make_unique<EDA_POLYGON_POINT_EDIT_BEHAVIOR>( *shape );
1047 break;
1048 }
1049 case SCH_TEXTBOX_T:
1050 {
1051 SCH_TEXTBOX* textbox = static_cast<SCH_TEXTBOX*>( aItem );
1052 m_editBehavior = std::make_unique<TEXTBOX_POINT_EDIT_BEHAVIOR>( *textbox );
1053 break;
1054 }
1055 case SCH_TABLECELL_T:
1056 {
1057 SCH_TABLECELL* cell = static_cast<SCH_TABLECELL*>( aItem );
1058 m_editBehavior = std::make_unique<SCH_TABLECELL_POINT_EDIT_BEHAVIOR>( *cell, *m_frame->GetScreen() );
1059 break;
1060 }
1061 case SCH_SHEET_T:
1062 {
1063 SCH_SHEET& sheet = static_cast<SCH_SHEET&>( *aItem );
1064 m_editBehavior = std::make_unique<SHEET_POINT_EDIT_BEHAVIOR>( sheet, *m_frame->GetScreen() );
1065 break;
1066 }
1067 case SCH_BITMAP_T:
1068 {
1069 SCH_BITMAP& bitmap = static_cast<SCH_BITMAP&>( *aItem );
1070 m_editBehavior = std::make_unique<BITMAP_POINT_EDIT_BEHAVIOR>( bitmap );
1071 break;
1072 }
1073 case SCH_LINE_T:
1074 {
1075 SCH_LINE& line = static_cast<SCH_LINE&>( *aItem );
1076 m_editBehavior = std::make_unique<LINE_POINT_EDIT_BEHAVIOR>( line, *m_frame->GetScreen() );
1077 break;
1078 }
1079 default:
1080 {
1081 m_editPoints.reset();
1082 break;
1083 }
1084 }
1085
1086 // If we got a behavior, generate the points
1087 if( m_editBehavior )
1088 {
1089 wxCHECK( m_editPoints, /* void */ );
1090 m_editBehavior->MakePoints( *m_editPoints );
1091 }
1092}
1093
1094
1096 SCH_TOOL_BASE<SCH_BASE_FRAME>( "eeschema.PointEditor" ),
1097 m_editedPoint( nullptr ),
1098 m_inDrag( false ),
1100 m_inPointEditor( false )
1101{
1102}
1103
1104
1106{
1107 SCH_TOOL_BASE::Reset( aReason );
1108
1109 if( KIGFX::VIEW* view = getView() )
1110 {
1111 if( m_angleItem )
1112 view->Remove( m_angleItem.get() );
1113
1114 if( m_editPoints )
1115 view->Remove( m_editPoints.get() );
1116 }
1117
1118 m_angleItem.reset();
1119 m_editPoints.reset();
1120 m_editedPoint = nullptr;
1121
1122 // A reset can tear down the Main() loop mid-drag, so clear the drag flag here too.
1123 m_inDrag = false;
1124}
1125
1126
1128{
1129 using S_C = SELECTION_CONDITIONS;
1130
1132
1133 const auto addCornerCondition = [&]( const SELECTION& aSelection ) -> bool
1134 {
1135 return SCH_POINT_EDITOR::addCornerCondition( aSelection );
1136 };
1137
1138 const auto removeCornerCondition = [&]( const SELECTION& aSelection ) -> bool
1139 {
1140 return SCH_POINT_EDITOR::removeCornerCondition( aSelection );
1141 };
1142
1143 const auto arcIsEdited = [&]( const SELECTION& aSelection ) -> bool
1144 {
1145 const EDA_ITEM* item = aSelection.Front();
1146 return ( item != nullptr ) && ( item->Type() == SCH_SHAPE_T )
1147 && static_cast<const SCH_SHAPE*>( item )->GetShape() == SHAPE_T::ARC;
1148 };
1149
1150 auto& menu = m_selectionTool->GetToolMenu().GetMenu();
1151
1152 // clang-format off
1155 menu.AddItem( ACTIONS::cycleArcEditMode, S_C::Count( 1 ) && arcIsEdited );
1156 // clang-format on
1157
1158 return true;
1159}
1160
1161
1163{
1164 setEditedPoint( nullptr );
1165
1166 return 0;
1167}
1168
1169
1171{
1172 EDIT_POINT* point = m_editedPoint;
1173
1174 if( !m_editPoints )
1175 {
1176 point = nullptr;
1177 }
1178 else if( aEvent.IsMotion() )
1179 {
1180 point = m_editPoints->FindPoint( aEvent.Position(), getView() );
1181 }
1182 else if( aEvent.IsDrag( BUT_LEFT ) )
1183 {
1184 point = m_editPoints->FindPoint( aEvent.DragOrigin(), getView() );
1185 }
1186 else
1187 {
1188 point = m_editPoints->FindPoint( getViewControls()->GetCursorPosition( false ), getView() );
1189 }
1190
1191 if( m_editedPoint != point )
1192 setEditedPoint( point );
1193}
1194
1195
1197{
1198 if( !m_selectionTool )
1199 return 0;
1200
1201 if( m_inPointEditor )
1202 return 0;
1203
1205
1206 if( m_isSymbolEditor )
1207 {
1209
1210 if( !editor->IsSymbolEditable() || editor->IsSymbolAlias() )
1211 return 0;
1212 }
1213
1214 const SCH_SELECTION& selection = m_selectionTool->GetSelection();
1215
1216 if( selection.Size() != 1 || !selection.Front()->IsType( pointEditorTypes ) )
1217 return 0;
1218
1219 // Wait till drawing tool is done
1220 if( selection.Front()->IsNew() )
1221 return 0;
1222
1223 Activate();
1224
1227 grid->SetPointEditProfile( true );
1228 VECTOR2I cursorPos;
1229 KIGFX::VIEW* view = getView();
1230 EDA_ITEM* item = selection.Front();
1231 SCH_COMMIT commit( m_toolMgr );
1232
1233 controls->ShowCursor( true );
1234
1235 makePointsAndBehavior( item );
1236 m_angleItem = std::make_unique<KIGFX::PREVIEW::ANGLE_ITEM>( m_editPoints );
1237 view->Add( m_editPoints.get() );
1238 view->Add( m_angleItem.get() );
1239 setEditedPoint( nullptr );
1240 updateEditedPoint( aEvent );
1241 bool inDrag = false;
1242
1243 // Main loop: keep receiving events
1244 while( TOOL_EVENT* evt = Wait() )
1245 {
1246 if( grid )
1247 {
1248 grid->SetSnap( !evt->Modifier( MD_SHIFT ) );
1249 grid->SetUseGrid( getView()->GetGAL()->GetGridSnapping()
1250 && !evt->DisableGridSnapping() );
1251 }
1252 else
1253 {
1254 // This check is based on the assumption that the grid object must be valid.
1255 // If this assumption is wrong, please fix the code above.
1256 wxCHECK( false, 0 );
1257 }
1258
1259 if( !m_editPoints || evt->IsSelectionEvent() )
1260 break;
1261
1262 if( !inDrag )
1263 updateEditedPoint( *evt );
1264
1265 if( evt->IsDrag( BUT_LEFT ) && m_editedPoint )
1266 {
1267 if( !inDrag )
1268 {
1269 // Ctrl overrides grid snapping during the drag, but it is also the selection
1270 // disambiguation modifier. Cancel the pending disambiguation menu so it does
1271 // not pop up mid-drag.
1272 m_selectionTool->CancelDisambiguation();
1273
1274 commit.Modify( m_editPoints->GetParent(), m_frame->GetScreen() );
1275
1276 if( SCH_SHAPE* shape = dynamic_cast<SCH_SHAPE*>( item ) )
1277 {
1278 shape->SetFlags( IS_MOVING );
1279 shape->SetHatchingDirty();
1280 shape->UpdateHatching();
1281 }
1282
1283 inDrag = true;
1284 }
1285
1286 bool snap = !evt->DisableGridSnapping();
1287 VECTOR2I rawPosition = controls->GetMousePosition();
1288 EDIT_RELATION* relation = m_editedPoint->GetRelation();
1289 bool angleRelation = relation
1290 && ( relation->Kind() == EDIT_RELATION_KIND::ANGLE_STEP_45
1291 || relation->Kind() == EDIT_RELATION_KIND::ANGLE_STEP_90 );
1292
1293 if( angleRelation && relation->Reference() )
1294 {
1295 grid->SetAngleRestriction( relation->Reference()->GetPosition(),
1296 relation->Kind() == EDIT_RELATION_KIND::ANGLE_STEP_45 ? 45.0 : 90.0 );
1297 }
1298 else
1299 {
1300 grid->SetAngleRestriction( std::nullopt, 0.0 );
1301 }
1302
1303 std::vector<VECTOR2I> stationarySelfPoints;
1304 std::vector<SEG> stationarySelfSegments;
1305
1306 if( SCH_SHAPE* shape = dynamic_cast<SCH_SHAPE*>( item ) )
1307 {
1308 int editedIndex = getEditedPointIndex();
1309
1310 if( shape->GetShape() == SHAPE_T::POLY )
1311 {
1312 const EDIT_LINE* editedLine = dynamic_cast<const EDIT_LINE*>( m_editedPoint );
1313
1314 for( unsigned i = 0; i < m_editPoints->PointsSize(); ++i )
1315 {
1316 const EDIT_POINT& point = m_editPoints->Point( i );
1317
1318 if( &point != m_editedPoint
1319 && ( !editedLine
1320 || ( &point != &editedLine->GetOrigin() && &point != &editedLine->GetEnd() ) ) )
1321 {
1322 stationarySelfPoints.push_back( point.GetPosition() );
1323 }
1324 }
1325
1326 for( unsigned i = 0; i < m_editPoints->LinesSize(); ++i )
1327 {
1328 const EDIT_LINE& line = m_editPoints->Line( i );
1329
1330 if( &line != editedLine && &line.GetOrigin() != m_editedPoint && &line.GetEnd() != m_editedPoint
1331 && ( !editedLine
1332 || ( &line.GetOrigin() != &editedLine->GetOrigin()
1333 && &line.GetOrigin() != &editedLine->GetEnd()
1334 && &line.GetEnd() != &editedLine->GetOrigin()
1335 && &line.GetEnd() != &editedLine->GetEnd() ) ) )
1336 {
1337 stationarySelfSegments.emplace_back( line.GetOrigin().GetPosition(),
1338 line.GetEnd().GetPosition() );
1339 }
1340 }
1341 }
1342 else if( shape->GetShape() == SHAPE_T::RECTANGLE && editedIndex >= RECT_TOPLEFT
1343 && editedIndex <= RECT_BOTRIGHT )
1344 {
1345 stationarySelfPoints.push_back( m_editPoints->Point( RECT_BOTRIGHT - editedIndex ).GetPosition() );
1346 }
1347 else if( shape->GetShape() == SHAPE_T::RECTANGLE )
1348 {
1349 for( unsigned i = 0; i < m_editPoints->LinesSize() && i < 4; ++i )
1350 {
1351 if( m_editedPoint != &m_editPoints->Line( i ) )
1352 continue;
1353
1354 const EDIT_LINE& opposite = m_editPoints->Line( ( i + 2 ) % 4 );
1355 stationarySelfPoints.push_back( opposite.GetOrigin().GetPosition() );
1356 stationarySelfPoints.push_back( opposite.GetEnd().GetPosition() );
1357 stationarySelfSegments.emplace_back( opposite.GetOrigin().GetPosition(),
1358 opposite.GetEnd().GetPosition() );
1359 break;
1360 }
1361 }
1362 else if( shape->GetShape() == SHAPE_T::ARC )
1363 {
1364 constexpr int arcStart = 0;
1365 constexpr int arcMid = 1;
1366 constexpr int arcEnd = 2;
1367 constexpr int arcCenter = 3;
1368
1370 {
1371 if( editedIndex != arcStart )
1372 stationarySelfPoints.push_back( m_editPoints->Point( arcStart ).GetPosition() );
1373
1374 if( editedIndex != arcEnd )
1375 stationarySelfPoints.push_back( m_editPoints->Point( arcEnd ).GetPosition() );
1376 }
1377 else if( editedIndex == arcStart || editedIndex == arcMid || editedIndex == arcEnd )
1378 {
1379 stationarySelfPoints.push_back( m_editPoints->Point( arcCenter ).GetPosition() );
1380 }
1381 }
1382 }
1383
1384 grid->SetStationarySelfGeometry( std::move( stationarySelfPoints ), std::move( stationarySelfSegments ) );
1385 grid->SetFeasibilityCallback( {} );
1386
1387 if( relation && !angleRelation )
1388 {
1389 if( std::optional<SNAP_CANDIDATE> authored = authoredSnapRelation( *relation ) )
1390 {
1391 grid->SetFeasibilityCallback(
1392 [authored = std::move( *authored )]( const SNAP_SOURCE_CONTEXT& aContext,
1393 const std::vector<SNAP_CANDIDATE>& aCandidates )
1394 {
1396 resolver.AddCandidate( authored );
1397
1398 for( const SNAP_CANDIDATE& candidate : aCandidates )
1399 resolver.AddCandidate( candidate );
1400
1401 SNAP_RESULT result = resolver.Resolve( aContext );
1402
1403 if( !result.Accepted( authored.id ) )
1404 {
1406 return result;
1407 }
1408
1409 for( const SNAP_CANDIDATE& candidate : aCandidates )
1410 {
1411 if( !result.Accepted( candidate.id ) )
1412 {
1414 break;
1415 }
1416 }
1417
1418 return result;
1419 } );
1420 }
1421 }
1422
1423 m_editedPoint->SetPosition(
1424 grid->ResolveSnap( rawPosition, GRID_HELPER_GRIDS::GRID_GRAPHICS, static_cast<SCH_ITEM*>( item ) )
1425 .position );
1426
1427 cursorPos = m_editedPoint->GetPosition();
1428 controls->ForceCursorPosition( true, cursorPos );
1429
1430 updateParentItem( snap, commit );
1431 updatePoints();
1432 }
1433 else if( inDrag && evt->IsMouseUp( BUT_LEFT ) )
1434 {
1435 if( !commit.Empty() )
1436 commit.Push( _( "Move Point" ) );
1437
1438 controls->SetAutoPan( false );
1439
1440 if( SCH_SHAPE* shape = dynamic_cast<SCH_SHAPE*>( item ) )
1441 {
1442 shape->ClearFlags( IS_MOVING );
1443 shape->SetHatchingDirty();
1444 shape->UpdateHatching();
1445 }
1446
1447 inDrag = false;
1448 }
1449 else if( evt->IsCancelInteractive() || evt->IsActivate() )
1450 {
1451 if( inDrag ) // Restore the last change
1452 {
1453 // Currently we are manually managing the lifetime of the grid
1454 // helpers because there is a bug in the tool stack that adds
1455 // the point editor again when commit.Revert() rebuilds the selection.
1456 // We remove this grid here so the its destructor is called before it
1457 // is added again.
1458 if( grid )
1459 {
1460 delete grid;
1461 grid = nullptr;
1462 }
1463
1464 commit.Revert();
1465 inDrag = false;
1466 break;
1467 }
1468 else if( evt->IsCancelInteractive() )
1469 {
1470 break;
1471 }
1472
1473 if( evt->IsActivate() )
1474 break;
1475 }
1476 else
1477 {
1478 evt->SetPassEvent();
1479 }
1480
1481 // Mirror the drag state so IsDragging() lets the frame defer the autosave snapshot,
1482 // which would otherwise serialize the whole schematic over a live point edit.
1483 m_inDrag = inDrag;
1484
1485 controls->SetAutoPan( inDrag );
1486 controls->CaptureCursor( inDrag );
1487 }
1488
1489 m_inDrag = false;
1490
1491 if( SCH_SHAPE* shape = dynamic_cast<SCH_SHAPE*>( item ) )
1492 {
1493 shape->ClearFlags( IS_MOVING );
1494 shape->SetHatchingDirty();
1495 shape->UpdateHatching();
1496 }
1497
1498 controls->SetAutoPan( false );
1499 controls->CaptureCursor( false );
1500 setEditedPoint( nullptr );
1501
1502 if( m_editPoints )
1503 {
1504 view->Remove( m_editPoints.get() );
1505 view->Remove( m_angleItem.get() );
1506
1507 m_editPoints.reset();
1508 m_angleItem.reset();
1509 m_frame->GetCanvas()->Refresh();
1510 }
1511
1512 delete grid;
1513
1514 return 0;
1515}
1516
1517
1518void SCH_POINT_EDITOR::updateParentItem( bool aSnapToGrid, SCH_COMMIT& aCommit ) const
1519{
1520 EDA_ITEM* item = m_editPoints->GetParent();
1521
1522 if( !item )
1523 return;
1524
1525 if( !m_editBehavior )
1526 return;
1527
1528 std::vector<EDA_ITEM*> updatedItems;
1529 m_editBehavior->UpdateItem( *m_editedPoint, *m_editPoints, aCommit, updatedItems );
1530
1531 for( EDA_ITEM* updatedItem : updatedItems )
1532 updateItem( updatedItem, true );
1533
1534 m_frame->SetMsgPanel( item );
1535}
1536
1537
1539{
1540 if( !m_editPoints || !m_editBehavior )
1541 return;
1542
1543 // Careful; the unit and/or body style may have changed out from under us, meaning the item is no
1544 // longer present on the canvas.
1545 if( m_isSymbolEditor )
1546 {
1548 SCH_ITEM* item = dynamic_cast<SCH_ITEM*>( m_editPoints->GetParent() );
1549
1550 if( ( item && item->GetUnit() != 0 && item->GetUnit() != editor->GetUnit() )
1551 || ( item && item->GetBodyStyle() != 0 && item->GetBodyStyle() != editor->GetBodyStyle() ) )
1552 {
1553 getView()->Remove( m_editPoints.get() );
1554 getView()->Remove( m_angleItem.get() );
1555 m_editPoints.reset();
1556 m_angleItem.reset();
1557 return;
1558 }
1559 }
1560
1561 m_editBehavior->UpdatePoints( *m_editPoints );
1562 getView()->Update( m_editPoints.get() );
1563 getView()->Update( m_angleItem.get() );
1564}
1565
1566
1568{
1570
1571 if( aPoint )
1572 {
1573 m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::ARROW );
1574 controls->ForceCursorPosition( true, aPoint->GetPosition() );
1575 controls->ShowCursor( true );
1576 }
1577 else
1578 {
1579 if( m_frame->ToolStackIsEmpty() )
1580 controls->ShowCursor( false );
1581
1582 controls->ForceCursorPosition( false );
1583 }
1584
1585 m_editedPoint = aPoint;
1586}
1587
1588
1590{
1591 if( !m_editPoints || !m_editedPoint || !m_editPoints->GetParent()->IsType( { SCH_SHAPE_T, SCH_RULE_AREA_T } ) )
1592 return false;
1593
1594 SCH_SHAPE* shape = static_cast<SCH_SHAPE*>( m_editPoints->GetParent() );
1595
1596 if( shape->GetPolyShape().IsEmpty() )
1597 return false;
1598
1599 SHAPE_LINE_CHAIN& poly = shape->GetPolyShape().Outline( 0 );
1600
1601 if( m_editPoints->GetParent()->Type() == SCH_SHAPE_T && poly.GetPointCount() <= 2 )
1602 return false;
1603 if( m_editPoints->GetParent()->Type() == SCH_RULE_AREA_T && poly.GetPointCount() <= 3 )
1604 return false;
1605
1606 for( const VECTOR2I& pt : poly.CPoints() )
1607 {
1608 if( pt == m_editedPoint->GetPosition() )
1609 return true;
1610 }
1611
1612 return false;
1613}
1614
1615
1617{
1618 if( !m_editPoints || !m_editPoints->GetParent()->IsType( { SCH_SHAPE_T, SCH_RULE_AREA_T } ) )
1619 return false;
1620
1621 SCH_SHAPE* shape = static_cast<SCH_SHAPE*>( m_editPoints->GetParent() );
1622
1623 if( shape->GetShape() != SHAPE_T::POLY )
1624 return false;
1625
1626 VECTOR2I cursorPos = getViewControls()->GetCursorPosition( false );
1627 double threshold = getView()->ToWorld( EDIT_POINT::POINT_SIZE );
1628
1629 return shape->HitTest( cursorPos, (int) threshold );
1630}
1631
1632
1634{
1635 if( !m_editPoints || !m_editPoints->GetParent()->IsType( { SCH_SHAPE_T, SCH_RULE_AREA_T } ) )
1636 return 0;
1637
1638 SCH_SHAPE* shape = static_cast<SCH_SHAPE*>( m_editPoints->GetParent() );
1639 SHAPE_LINE_CHAIN& poly = shape->GetPolyShape().Outline( 0 );
1640 SCH_COMMIT commit( m_toolMgr );
1641
1642 commit.Modify( shape, m_frame->GetScreen() );
1643
1645 int currentMinDistance = INT_MAX;
1646 int closestLineStart = 0;
1647 unsigned numPoints = poly.GetPointCount();
1648
1649 if( !shape->IsClosed() )
1650 numPoints -= 1;
1651
1652 for( unsigned i = 0; i < numPoints; ++i )
1653 {
1654 SEG seg = poly.GetSegment( i );
1655 int distance = seg.Distance( cursor );
1656
1657 if( distance < currentMinDistance )
1658 {
1659 currentMinDistance = distance;
1660 closestLineStart = i;
1661 }
1662 }
1663
1664 poly.Insert( closestLineStart + 1, cursor );
1665
1666 updateItem( shape, true );
1667 updatePoints();
1668
1669 commit.Push( _( "Add Corner" ) );
1670 return 0;
1671}
1672
1673
1675{
1676 if( !m_editPoints || !m_editedPoint || !m_editPoints->GetParent()->IsType( { SCH_SHAPE_T, SCH_RULE_AREA_T } ) )
1677 return 0;
1678
1679 SCH_SHAPE* shape = static_cast<SCH_SHAPE*>( m_editPoints->GetParent() );
1680 SHAPE_LINE_CHAIN& poly = shape->GetPolyShape().Outline( 0 );
1681 SCH_COMMIT commit( m_toolMgr );
1682
1683 if( m_editPoints->GetParent()->Type() == SCH_SHAPE_T && poly.GetPointCount() <= 2 )
1684 return 0;
1685 if( m_editPoints->GetParent()->Type() == SCH_RULE_AREA_T && poly.GetPointCount() <= 3 )
1686 return 0;
1687
1688 commit.Modify( shape, m_frame->GetScreen() );
1689
1690 int idx = getEditedPointIndex();
1691 int last = (int) poly.GetPointCount() - 1;
1692
1693 if( idx == 0 && poly.GetPoint( 0 ) == poly.GetPoint( last ) )
1694 {
1695 poly.Remove( idx );
1696 poly.SetPoint( last - 1, poly.GetPoint( 0 ) );
1697 }
1698 else
1699 {
1700 poly.Remove( idx );
1701 }
1702
1703 shape->SetHatchingDirty();
1704
1705 setEditedPoint( nullptr );
1706
1707 updateItem( shape, true );
1708 updatePoints();
1709
1710 commit.Push( _( "Remove Corner" ) );
1711 return 0;
1712}
1713
1714
1716{
1717 // The Symbol Editor uses SYMBOL_EDITOR_SETTINGS, not EESCHEMA_SETTINGS, so eeconfig()
1718 // returns nullptr there. Dispatch on frame type to read/write the right settings store.
1719 EESCHEMA_SETTINGS* schCfg = m_isSymbolEditor ? nullptr : m_frame->eeconfig();
1720 SYMBOL_EDITOR_SETTINGS* symCfg = m_isSymbolEditor ? m_frame->libeditconfig() : nullptr;
1721
1722 if( aEvent.Matches( ACTIONS::cycleArcEditMode.MakeEvent() ) )
1723 {
1724 if( schCfg )
1726 else if( symCfg )
1727 m_arcEditMode = symCfg->m_ArcEditMode;
1728
1730 }
1731 else
1732 {
1734 }
1735
1736 if( schCfg )
1738 else if( symCfg )
1739 symCfg->m_ArcEditMode = m_arcEditMode;
1740
1741 return 0;
1742}
1743
1744
1746{
1747 updatePoints();
1748 return 0;
1749}
1750
1751
ARC_EDIT_MODE
Settings for arc editing.
@ KEEP_ENDPOINTS_OR_START_DIRECTION
Whe editing endpoints, the other end remains in place.
@ KEEP_CENTER_ADJUST_ANGLE_RADIUS
When editing endpoints, the angle and radius are adjusted.
constexpr EDA_IU_SCALE schIUScale
Definition base_units.h:123
constexpr double ARC_LOW_DEF_MM
Definition base_units.h:127
BOX2< VECTOR2I > BOX2I
Definition box2.h:918
static TOOL_ACTION cycleArcEditMode
Definition actions.h:270
static TOOL_ACTION pointEditorArcKeepCenter
Definition actions.h:271
static TOOL_ACTION pointEditorArcKeepRadius
Definition actions.h:273
static TOOL_ACTION activatePointEditor
Definition actions.h:267
static TOOL_ACTION pointEditorArcKeepEndpoint
Definition actions.h:272
void MakePoints(EDIT_POINTS &aPoints) override
Construct the initial set of edit points for the item and append to the given list.
void UpdateItem(const EDIT_POINT &aEditedPoint, EDIT_POINTS &aPoints, COMMIT &aCommit, std::vector< EDA_ITEM * > &aUpdatedItems) override
Update the item with the new positions of the edit points.
bool UpdatePoints(EDIT_POINTS &aPoints) override
Update the list of the edit points for the item.
BITMAP_POINT_EDIT_BEHAVIOR(SCH_BITMAP &aBitmap)
static constexpr BOX2< VECTOR2I > ByCorners(const VECTOR2I &aCorner1, const VECTOR2I &aCorner2)
Definition box2.h:66
constexpr const Vec GetCenter() const
Definition box2.h:226
constexpr coord_type GetLeft() const
Definition box2.h:224
constexpr coord_type GetRight() const
Definition box2.h:213
constexpr coord_type GetTop() const
Definition box2.h:225
constexpr coord_type GetBottom() const
Definition box2.h:218
Represent a set of changes (additions, deletions or modifications) of a data model (e....
Definition commit.h:68
bool Empty() const
Definition commit.h:134
COMMIT & Modify(EDA_ITEM *aItem, BASE_SCREEN *aScreen=nullptr, RECURSE_MODE aRecurse=RECURSE_MODE::NO_RECURSE)
Modify a given item in the model.
Definition commit.h:102
The base class for create windows for drawing purpose.
A base class for most all the KiCad significant classes used in schematics and boards.
Definition eda_item.h:96
KICAD_T Type() const
Returns the type of object.
Definition eda_item.h:108
virtual bool IsType(const std::vector< KICAD_T > &aScanTypes) const
Check whether the item is one of the listed types.
Definition eda_item.h:202
bool IsNew() const
Definition eda_item.h:129
virtual void SetEnd(const VECTOR2I &aEnd)
Definition eda_shape.h:244
void SetStartX(int x)
Definition eda_shape.h:208
void SetEndY(int aY)
Definition eda_shape.h:251
void SetStartY(int y)
Definition eda_shape.h:201
SHAPE_POLY_SET & GetPolyShape()
SHAPE_T GetShape() const
Definition eda_shape.h:185
void SetEndX(int aX)
Definition eda_shape.h:258
const VECTOR2I & GetEnd() const
Return the ending point of the graphic.
Definition eda_shape.h:240
bool IsClosed() const
wxString SHAPE_T_asString() const
void SetHatchingDirty()
Definition eda_shape.h:163
int GetCornerRadius() const
Represent a line connecting two EDIT_POINTs.
void SetRelation(std::unique_ptr< EDIT_RELATION > aRelation)
Set a relation for an EDIT_LINE.
EDIT_POINT & GetEnd()
Return the end EDIT_POINT.
EDIT_POINT & GetOrigin()
Return the origin EDIT_POINT.
EDIT_POINTS is a VIEW_ITEM that manages EDIT_POINTs and EDIT_LINEs and draws them.
void AddPoint(const EDIT_POINT &aPoint)
Add an EDIT_POINT.
EDIT_LINE & Line(unsigned int aIndex)
unsigned int LinesSize() const
Return number of stored EDIT_LINEs.
EDIT_POINT & Point(unsigned int aIndex)
void AddLine(const EDIT_LINE &aLine)
Adds an EDIT_LINE.
Represent a single point that can be used for modifying items.
Definition edit_points.h:44
virtual std::pair< EDA_ITEM *, int > GetConnected() const
Return a connected item record comprising an EDA_ITEM* and a STARTPOINT/ENDPOINT flag.
Definition edit_points.h:76
int GetY() const
Return Y coordinate of an EDIT_POINT.
Definition edit_points.h:92
static const int POINT_SIZE
Single point size in pixels.
virtual void SetPosition(const VECTOR2I &aPosition)
Set new coordinates for an EDIT_POINT.
virtual VECTOR2I GetPosition() const
Return coordinates of an EDIT_POINT.
Definition edit_points.h:68
int GetX() const
Return X coordinate of an EDIT_POINT.
Definition edit_points.h:84
void SetDrawCircle(bool aDrawCircle=true)
const VECTOR2I & Origin() const
static std::unique_ptr< EDIT_RELATION > PerpendicularTranslation(const EDIT_LINE &aLine)
const EDIT_POINT * Reference() const
const VECTOR2I & Direction() const
const EDIT_POINT * SecondaryReference() const
EDIT_RELATION_KIND Kind() const
static const TOOL_EVENT ClearedEvent
Definition actions.h:345
static const TOOL_EVENT SelectedEvent
Definition actions.h:343
static const TOOL_EVENT SelectedItemsModified
Selected items were moved, this can be very high frequency on the canvas, use with care.
Definition actions.h:350
static const TOOL_EVENT PointSelectedEvent
Definition actions.h:342
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 VECTOR2D GetMousePosition(bool aWorldCoordinates=true) const =0
Return the current mouse pointer position.
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:63
virtual void Add(VIEW_ITEM *aItem, int aDrawPriority=-1)
Add a VIEW_ITEM to the view.
Definition view.cpp:300
virtual void Remove(VIEW_ITEM *aItem)
Remove a VIEW_ITEM from the view.
Definition view.cpp:404
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:1835
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:534
Define a library symbol object.
Definition lib_symbol.h:114
std::vector< const SCH_PIN * > GetGraphicalPins(int aUnit=0, int aBodyStyle=0) const
Graphical pins: Return schematic pin objects as drawn (unexpanded), filtered by unit/body.
bool UpdatePoints(EDIT_POINTS &aPoints) override
Update the list of the edit points for the item.
void UpdateItem(const EDIT_POINT &aEditedPoints, EDIT_POINTS &aPoints, COMMIT &aCommit, std::vector< EDA_ITEM * > &aUpdatedItems) override
Update the item with the new positions of the edit points.
void MakePoints(EDIT_POINTS &aPoints) override
Construct the initial set of edit points for the item and append to the given list.
LINE_POINT_EDIT_BEHAVIOR(SCH_LINE &aLine, SCH_SCREEN &aScreen)
A helper class interface to manage the edit points for a single item.
static bool isModified(const EDIT_POINT &aEditedPoint, const EDIT_POINT &aPoint)
Checks if two points are the same instance - which means the point is being edited.
static void UpdateItem(SCH_SHAPE &aRect, const EDIT_POINT &aEditedPoint, EDIT_POINTS &aPoints, const VECTOR2I &aMinSize={ 0, 0 })
bool UpdatePoints(EDIT_POINTS &aPoints) override
Update the list of the edit points for the item.
static void UpdatePoints(SCH_SHAPE &aRect, EDIT_POINTS &aPoints)
static void PinEditedCorner(const EDIT_POINT &aEditedPoint, const EDIT_POINTS &aPoints, int minWidth, int minHeight, VECTOR2I &topLeft, VECTOR2I &topRight, VECTOR2I &botLeft, VECTOR2I &botRight)
Update the coordinates of 4 corners of a rectangle, according to constraints and the moved corner.
static void MakePoints(SCH_SHAPE &aRect, EDIT_POINTS &aPoints)
void UpdateItem(const EDIT_POINT &aEditedPoint, EDIT_POINTS &aPoints, COMMIT &aCommit, std::vector< EDA_ITEM * > &aUpdatedItems) override
Update the item with the new positions of the edit points.
void MakePoints(EDIT_POINTS &aPoints) override
Construct the initial set of edit points for the item and append to the given list.
RECTANGLE_POINT_EDIT_BEHAVIOR(SCH_SHAPE &aRect, EDA_DRAW_FRAME &aFrame)
void dragPinsOnEdge(const std::vector< SEG > &aOldEdges, const std::vector< VECTOR2I > &aMoveVecs, int aEdgeUnit, COMMIT &aCommit, std::vector< EDA_ITEM * > &aUpdatedItems) const
A REFERENCE_IMAGE is a wrapper around a BITMAP_IMAGE that is displayed in an editor as a reference fo...
void SetTransformOriginOffset(const VECTOR2I &aCenter)
VECTOR2I GetTransformOriginOffset() const
Get the center of scaling, etc, relative to the image center (GetPosition()).
VECTOR2I GetPosition() const
VECTOR2I GetSize() const
double GetImageScale() const
void SetImageScale(double aScale)
Set the image "zoom" value.
Holds all the data relating to one schematic.
Definition schematic.h:90
static TOOL_ACTION pointEditorAddCorner
static TOOL_ACTION pointEditorRemoveCorner
A shim class between EDA_DRAW_FRAME and several derived classes: SYMBOL_EDIT_FRAME,...
Object to handle a bitmap image that can be inserted in a schematic.
Definition sch_bitmap.h:36
virtual void Push(const wxString &aMessage=wxT("A commit"), int aCommitFlags=0) override
Execute the changes.
virtual void Revert() override
Revert the commit by restoring the modified items state.
Base class for any item which can be embedded within the SCHEMATIC container class,...
Definition sch_item.h:162
SCHEMATIC * Schematic() const
Search the item hierarchy to find a SCHEMATIC.
Definition sch_item.cpp:268
int GetBodyStyle() const
Definition sch_item.h:242
int GetUnit() const
Definition sch_item.h:233
Segment description base class to describe items which have 2 end points (track, wire,...
Definition sch_line.h:38
VECTOR2I GetEndPoint() const
Definition sch_line.h:144
VECTOR2I GetStartPoint() const
Definition sch_line.h:135
void updatePoints()
Update which point is being edited.
void Reset(RESET_REASON aReason) override
Bring the tool to a known, initial state.
void setEditedPoint(EDIT_POINT *aPoint)
Return true if aPoint is the currently modified point.
bool Init() override
Init() is called once upon a registration of the tool.
ARC_EDIT_MODE m_arcEditMode
Re-entrancy guards.
void updateParentItem(bool aSnapToGrid, SCH_COMMIT &aCommit) const
< Update item's points with edit points.
void updateEditedPoint(const TOOL_EVENT &aEvent)
Clear references to the points.
bool addCornerCondition(const SELECTION &aSelection)
std::unique_ptr< POINT_EDIT_BEHAVIOR > m_editBehavior
EDIT_POINT * m_editedPoint
True while a point drag is in progress (between grab and release).
int modifiedSelection(const TOOL_EVENT &aEvent)
int Main(const TOOL_EVENT &aEvent)
int getEditedPointIndex() const
std::shared_ptr< EDIT_POINTS > m_editPoints
int clearEditedPoints(const TOOL_EVENT &aEvent)
Set the current point being edited. NULL means none.
bool removeCornerCondition(const SELECTION &aSelection)
bool m_inPointEditor
Currently available edit points.
void setTransitions() override
This method is meant to be overridden in order to specify handlers for events.
void makePointsAndBehavior(EDA_ITEM *aItem)
Currently edited point, NULL if there is none.
std::unique_ptr< KIGFX::PREVIEW::ANGLE_ITEM > m_angleItem
Current item-specific edit behavior.
int changeArcEditMode(const TOOL_EVENT &aEvent)
int removeCorner(const TOOL_EVENT &aEvent)
int addCorner(const TOOL_EVENT &aEvent)
TOOL_ACTION handlers.
void SetPosition(const VECTOR2I &aPos) override
Definition sch_shape.h:85
VECTOR2I GetCenter() const
Definition sch_shape.h:92
bool HitTest(const VECTOR2I &aPosition, int aAccuracy=0) const override
Test if aPosition is inside or on the boundary of this item.
VECTOR2I GetPosition() const override
Definition sch_shape.h:84
Define a sheet pin (label) used in sheets to create hierarchical schematics.
Sheet symbol placed in a schematic, and is the entry point for a sub schematic.
Definition sch_sheet.h:44
SCH_TABLECELL_POINT_EDIT_BEHAVIOR(SCH_TABLECELL &aCell, SCH_SCREEN &aScreen)
void UpdateItem(const EDIT_POINT &aEditedPoint, EDIT_POINTS &aPoints, COMMIT &aCommit, std::vector< EDA_ITEM * > &aUpdatedItems) override
Update the item with the new positions of the edit points.
void updateItem(EDA_ITEM *aItem, bool aUpdateRTree) const
bool Init() override
Init() is called once upon a registration of the tool.
void Reset(RESET_REASON aReason) override
Bring the tool to a known, initial state.
SCH_TOOL_BASE(const std::string &aName)
SCH_SELECTION_TOOL * m_selectionTool
Definition seg.h:38
int Distance(const SEG &aSeg) const
Compute minimum Euclidean distance to segment aSeg.
Definition seg.cpp:698
Class that groups generic conditions for selected items.
static SELECTION_CONDITION Count(int aNumber)
Create a functor that tests if the number of selected items is equal to the value given as parameter.
EDA_ITEM * Front() const
Definition selection.h:176
int Size() const
Returns the number of selected parts.
Definition selection.h:120
Represent a polyline containing arcs as well as line segments: A chain of connected line and/or arc s...
virtual const VECTOR2I GetPoint(int aIndex) const override
void SetPoint(int aIndex, const VECTOR2I &aPos)
Move a point to a specific location.
virtual size_t GetPointCount() const override
virtual const SEG GetSegment(int aIndex) const override
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
Return true if the set is empty (no polygons at all)
SHAPE_LINE_CHAIN & Outline(int aIndex)
Return the reference to aIndex-th outline in the set.
SHEET_POINT_EDIT_BEHAVIOR(SCH_SHEET &aSheet, SCH_SCREEN &aScreen)
void UpdateItem(const EDIT_POINT &aEditedPoint, EDIT_POINTS &aPoints, COMMIT &aCommit, std::vector< EDA_ITEM * > &aUpdatedItems) override
Update the item with the new positions of the edit points.
std::vector< std::tuple< SCH_SHEET_PIN *, SCH_LINE *, int > > m_connectedWires
std::map< SCH_SHEET_PIN *, SCH_NO_CONNECT * > m_noConnects
bool UpdatePoints(EDIT_POINTS &aPoints) override
Update the list of the edit points for the item.
void MakePoints(EDIT_POINTS &aPoints) override
Construct the initial set of edit points for the item and append to the given list.
The symbol library editor main window.
void MakePoints(EDIT_POINTS &aPoints) override
Construct the initial set of edit points for the item and append to the given list.
bool UpdatePoints(EDIT_POINTS &aPoints) override
Update the list of the edit points for the item.
void UpdateItem(const EDIT_POINT &aEditedPoint, EDIT_POINTS &aPoints, COMMIT &aCommit, std::vector< EDA_ITEM * > &aUpdatedItems) override
Update the item with the new positions of the edit points.
TEXTBOX_POINT_EDIT_BEHAVIOR(SCH_TEXTBOX &aTextbox)
SCH_BASE_FRAME * getEditFrame() const
Definition tool_base.h:182
KIGFX::VIEW_CONTROLS * getViewControls() const
Definition tool_base.cpp:40
KIGFX::VIEW * getView() const
Definition tool_base.cpp:34
Generic, UI-independent tool event.
Definition tool_event.h:167
bool DisableGridSnapping() const
Definition tool_event.h:367
bool Matches(const TOOL_EVENT &aEvent) const
Test whether two events match in terms of category & action or command.
Definition tool_event.h:388
const VECTOR2D Position() const
Return mouse cursor position in world coordinates.
Definition tool_event.h:289
bool IsDrag(int aButtonMask=BUT_ANY) const
Definition tool_event.h:311
const VECTOR2D DragOrigin() const
Return the point where dragging has started.
Definition tool_event.h:295
T Parameter() const
Return a parameter assigned to the event.
Definition tool_event.h:469
bool IsMotion() const
Definition tool_event.h:326
void Go(int(SCH_BASE_FRAME::*aStateFunc)(const TOOL_EVENT &), const TOOL_EVENT_LIST &aConditions=TOOL_EVENT(TC_ANY, TA_ANY))
TOOL_EVENT * Wait(const TOOL_EVENT_LIST &aEventList=TOOL_EVENT(TC_ANY, TA_ANY))
double Distance(const VECTOR2< extended_type > &aVector) const
Compute the distance between two vectors.
Definition vector2d.h:549
T EuclideanNorm() const
Compute the Euclidean norm of the vector, which is defined as sqrt(x ** 2 + y ** 2).
Definition vector2d.h:279
@ ARROW
Definition cursors.h:42
const int minSize
Push and Shove router track width and via size dialog.
#define _(s)
#define ENDPOINT
ends. (Used to support dragging.)
#define IS_MOVING
Item being moved.
#define STARTPOINT
When a line is selected, these flags indicate which.
@ ELLIPSE
Definition eda_shape.h:52
@ RECTANGLE
Use RECTANGLE instead of RECT to avoid collision in a Windows header.
Definition eda_shape.h:47
@ ELLIPSE_ARC
Definition eda_shape.h:53
static FILENAME_RESOLVER * resolver
@ FRAME_SCH_SYMBOL_EDITOR
Definition frame_type.h:31
@ GRID_GRAPHICS
Definition grid_helper.h:63
@ LAYER_NOTES
Definition layer_ids.h:473
#define UNIMPLEMENTED_FOR(type)
Definition macros.h:92
constexpr int Mils2IU(const EDA_IU_SCALE &aIuScale, int mils)
Definition eda_units.h:171
std::vector< SEG > GetSegsInDirection(const BOX2I &aBox, DIRECTION_45::Directions aDir)
Get the segments of a box that are in the given direction.
EDA_ANGLE abs(const EDA_ANGLE &aAngle)
Definition eda_angle.h:400
@ RECT_RIGHT
@ RECT_LEFT
@ RECT_CENTER
@ RECT_RADIUS
ARC_EDIT_MODE IncrementArcEditMode(ARC_EDIT_MODE aMode)
static float distance(const SFVEC2UI &a, const SFVEC2UI &b)
SCH_CONDITIONS S_C
RECTANGLE_POINTS
@ RECT_BOTLEFT
@ RECT_TOPLEFT
@ RECT_TOPRIGHT
@ RECT_CENTER
@ RECT_BOTRIGHT
@ RECT_RADIUS
RECTANGLE_LINES
@ RECT_RIGHT
@ RECT_LEFT
TABLECELL_POINTS
@ ROW_HEIGHT
@ COL_WIDTH
static const std::vector< KICAD_T > pointEditorTypes
static std::optional< SNAP_CANDIDATE > authoredSnapRelation(const EDIT_RELATION &aRelation)
@ LINE_START
REFIMAGE_POINTS
@ REFIMG_ORIGIN
@ ARC_START
@ ARC_CENTER
std::optional< VECTOR2I > OPT_VECTOR2I
Definition seg.h:35
Utility functions for working with shapes.
SNAP_PRIORITY_TIER priority
std::optional< INTERSECTABLE_GEOM > manifold
SNAP_STABLE_ID id
static SNAP_CANDIDATE Line(SNAP_STABLE_ID aId, SNAP_PRIORITY_TIER aPriority, SNAP_CANDIDATE_SUBTYPE aSubtype, const VECTOR2I &aOrigin, const VECTOR2D &aDirection, double aResidual)
static SNAP_CANDIDATE AxisY(SNAP_STABLE_ID aId, SNAP_PRIORITY_TIER aPriority, SNAP_CANDIDATE_SUBTYPE aSubtype, int aCoordinate, double aResidual)
static SNAP_CANDIDATE AxisX(SNAP_STABLE_ID aId, SNAP_PRIORITY_TIER aPriority, SNAP_CANDIDATE_SUBTYPE aSubtype, int aCoordinate, double aResidual)
SNAP_RELATION relation
SNAP_CANDIDATE_SUBTYPE subtype
KIBIS_PIN * pin
wxString result
Test unit parsing edge cases and error handling.
@ MD_SHIFT
Definition tool_event.h:139
@ BUT_LEFT
Definition tool_event.h:128
@ SCH_LINE_T
Definition typeinfo.h:160
@ SCH_TABLECELL_T
Definition typeinfo.h:163
@ SCH_SHEET_T
Definition typeinfo.h:172
@ SCH_SHAPE_T
Definition typeinfo.h:146
@ SCH_RULE_AREA_T
Definition typeinfo.h:167
@ SCH_ITEM_LOCATE_GRAPHIC_LINE_T
Definition typeinfo.h:185
@ SCH_BITMAP_T
Definition typeinfo.h:161
@ SCH_TEXTBOX_T
Definition typeinfo.h:149
constexpr int sign(T val)
Definition util.h:141
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:683