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