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
152
153
155{
156public:
158 m_line( aLine ),
159 m_screen( aScreen )
160 {
161 }
162
163 void MakePoints( EDIT_POINTS& aPoints ) override
164 {
165 std::pair<EDA_ITEM*, int> connectedStart = { nullptr, STARTPOINT };
166 std::pair<EDA_ITEM*, int> connectedEnd = { nullptr, STARTPOINT };
167
168 for( SCH_ITEM* test : m_screen.Items().OfType( SCH_LINE_T ) )
169 {
170 if( test->GetLayer() != LAYER_NOTES )
171 continue;
172
173 if( test == &m_line )
174 continue;
175
176 SCH_LINE* testLine = static_cast<SCH_LINE*>( test );
177
178 if( testLine->GetStartPoint() == m_line.GetStartPoint() )
179 {
180 connectedStart = { testLine, STARTPOINT };
181 }
182 else if( testLine->GetEndPoint() == m_line.GetStartPoint() )
183 {
184 connectedStart = { testLine, ENDPOINT };
185 }
186 else if( testLine->GetStartPoint() == m_line.GetEndPoint() )
187 {
188 connectedEnd = { testLine, STARTPOINT };
189 }
190 else if( testLine->GetEndPoint() == m_line.GetEndPoint() )
191 {
192 connectedEnd = { testLine, ENDPOINT };
193 }
194 }
195
196 aPoints.AddPoint( m_line.GetStartPoint(), connectedStart );
197 aPoints.AddPoint( m_line.GetEndPoint(), connectedEnd );
198 }
199
200 bool UpdatePoints( EDIT_POINTS& aPoints ) override
201 {
202 aPoints.Point( LINE_START ).SetPosition( m_line.GetStartPoint() );
203 aPoints.Point( LINE_END ).SetPosition( m_line.GetEndPoint() );
204 return true;
205 }
206
207 void UpdateItem( const EDIT_POINT& aEditedPoints, EDIT_POINTS& aPoints, COMMIT& aCommit,
208 std::vector<EDA_ITEM*>& aUpdatedItems ) override
209 {
210 m_line.SetStartPoint( aPoints.Point( LINE_START ).GetPosition() );
211 m_line.SetEndPoint( aPoints.Point( LINE_END ).GetPosition() );
212
213 std::pair<EDA_ITEM*, int> connected = aPoints.Point( LINE_START ).GetConnected();
214
215 if( connected.first )
216 {
217 aCommit.Modify( connected.first, &m_screen );
218 aUpdatedItems.push_back( connected.first );
219
220 if( connected.second == STARTPOINT )
221 static_cast<SCH_LINE*>( connected.first )->SetStartPoint( m_line.GetStartPoint() );
222 else if( connected.second == ENDPOINT )
223 static_cast<SCH_LINE*>( connected.first )->SetEndPoint( m_line.GetStartPoint() );
224 }
225
226 connected = aPoints.Point( LINE_END ).GetConnected();
227
228 if( connected.first )
229 {
230 aCommit.Modify( connected.first, &m_screen );
231 aUpdatedItems.push_back( connected.first );
232
233 if( connected.second == STARTPOINT )
234 static_cast<SCH_LINE*>( connected.first )->SetStartPoint( m_line.GetEndPoint() );
235 else if( connected.second == ENDPOINT )
236 static_cast<SCH_LINE*>( connected.first )->SetEndPoint( m_line.GetEndPoint() );
237 }
238 }
239
240private:
243};
244
245
247{
248public:
251 m_cell( aCell ),
252 m_screen( aScreen )
253 {
254 }
255
256 void UpdateItem( const EDIT_POINT& aEditedPoint, EDIT_POINTS& aPoints, COMMIT& aCommit,
257 std::vector<EDA_ITEM*>& aUpdatedItems ) override
258 {
259 SCH_TABLE& table = static_cast<SCH_TABLE&>( *m_cell.GetParent() );
260 bool rotated = !m_cell.GetTextAngle().IsHorizontal();
261
262 aCommit.Modify( &table, &m_screen );
263 aUpdatedItems.push_back( &table );
264
265 if( rotated )
266 {
267 if( isModified( aEditedPoint, aPoints.Point( ROW_HEIGHT ) ) )
268 {
269 m_cell.SetEnd( VECTOR2I( m_cell.GetEndX(), aPoints.Point( ROW_HEIGHT ).GetY() ) );
270
271 int colWidth = std::abs( m_cell.GetRectangleHeight() );
272
273 for( int ii = 0; ii < m_cell.GetColSpan() - 1; ++ii )
274 colWidth -= table.GetColWidth( m_cell.GetColumn() + ii );
275
276 table.SetColWidth( m_cell.GetColumn() + m_cell.GetColSpan() - 1, colWidth );
277 }
278 else if( isModified( aEditedPoint, aPoints.Point( COL_WIDTH ) ) )
279 {
280 m_cell.SetEnd( VECTOR2I( aPoints.Point( COL_WIDTH ).GetX(), m_cell.GetEndY() ) );
281
282 int rowHeight = m_cell.GetRectangleWidth();
283
284 for( int ii = 0; ii < m_cell.GetRowSpan() - 1; ++ii )
285 rowHeight -= table.GetRowHeight( m_cell.GetRow() + ii );
286
287 table.SetRowHeight( m_cell.GetRow() + m_cell.GetRowSpan() - 1, rowHeight );
288 }
289 }
290 else
291 {
292 if( isModified( aEditedPoint, aPoints.Point( COL_WIDTH ) ) )
293 {
294 m_cell.SetEnd( VECTOR2I( aPoints.Point( COL_WIDTH ).GetX(), m_cell.GetEndY() ) );
295
296 int colWidth = m_cell.GetRectangleWidth();
297
298 for( int ii = 0; ii < m_cell.GetColSpan() - 1; ++ii )
299 colWidth -= table.GetColWidth( m_cell.GetColumn() + ii );
300
301 table.SetColWidth( m_cell.GetColumn() + m_cell.GetColSpan() - 1, colWidth );
302 }
303 else if( isModified( aEditedPoint, aPoints.Point( ROW_HEIGHT ) ) )
304 {
305 m_cell.SetEnd( VECTOR2I( m_cell.GetEndX(), aPoints.Point( ROW_HEIGHT ).GetY() ) );
306
307 int rowHeight = m_cell.GetRectangleHeight();
308
309 for( int ii = 0; ii < m_cell.GetRowSpan() - 1; ++ii )
310 rowHeight -= table.GetRowHeight( m_cell.GetRow() + ii );
311
312 table.SetRowHeight( m_cell.GetRow() + m_cell.GetRowSpan() - 1, rowHeight );
313 }
314 }
315
316 table.Normalize();
317 }
318
319private:
322};
323
324
326{
327public:
329 m_rect( aRect ),
330 m_frame( aFrame )
331 {
332 }
333
334 static void MakePoints( SCH_SHAPE& aRect, EDIT_POINTS& aPoints )
335 {
336 VECTOR2I topLeft = aRect.GetPosition();
337 VECTOR2I botRight = aRect.GetEnd();
338
339 aPoints.AddPoint( topLeft );
340 aPoints.AddPoint( VECTOR2I( botRight.x, topLeft.y ) );
341 aPoints.AddPoint( VECTOR2I( topLeft.x, botRight.y ) );
342 aPoints.AddPoint( botRight );
343 aPoints.AddPoint( aRect.GetCenter() );
344 aPoints.AddPoint( VECTOR2I( botRight.x - aRect.GetCornerRadius(), topLeft.y ) );
345 aPoints.Point( RECT_RADIUS ).SetDrawCircle();
346
347 aPoints.AddLine( aPoints.Point( RECT_TOPLEFT ), aPoints.Point( RECT_TOPRIGHT ) );
349 aPoints.AddLine( aPoints.Point( RECT_TOPRIGHT ), aPoints.Point( RECT_BOTRIGHT ) );
351 aPoints.AddLine( aPoints.Point( RECT_BOTRIGHT ), aPoints.Point( RECT_BOTLEFT ) );
353 aPoints.AddLine( aPoints.Point( RECT_BOTLEFT ), aPoints.Point( RECT_TOPLEFT ) );
355 }
356
357 static void UpdatePoints( SCH_SHAPE& aRect, EDIT_POINTS& aPoints )
358 {
359 VECTOR2I topLeft = aRect.GetPosition();
360 VECTOR2I botRight = aRect.GetEnd();
361
362 aPoints.Point( RECT_TOPLEFT ).SetPosition( topLeft );
363 aPoints.Point( RECT_RADIUS ).SetPosition( VECTOR2I( botRight.x - aRect.GetCornerRadius(), topLeft.y ) );
364 aPoints.Point( RECT_TOPRIGHT ).SetPosition( VECTOR2I( botRight.x, topLeft.y ) );
365 aPoints.Point( RECT_BOTLEFT ).SetPosition( VECTOR2I( topLeft.x, botRight.y ) );
366 aPoints.Point( RECT_BOTRIGHT ).SetPosition( botRight );
367 aPoints.Point( RECT_CENTER ).SetPosition( aRect.GetCenter() );
368 }
369
383 static void PinEditedCorner( const EDIT_POINT& aEditedPoint, const EDIT_POINTS& aPoints,
384 int minWidth, int minHeight, VECTOR2I& topLeft, VECTOR2I& topRight,
385 VECTOR2I& botLeft, VECTOR2I& botRight )
386 {
387 if( isModified( aEditedPoint, aPoints.Point( RECT_TOPLEFT ) ) )
388 {
389 // pin edited point within opposite corner
390 topLeft.x = std::min( topLeft.x, botRight.x - minWidth );
391 topLeft.y = std::min( topLeft.y, botRight.y - minHeight );
392
393 // push edited point edges to adjacent corners
394 topRight.y = topLeft.y;
395 botLeft.x = topLeft.x;
396 }
397 else if( isModified( aEditedPoint, aPoints.Point( RECT_TOPRIGHT ) ) )
398 {
399 // pin edited point within opposite corner
400 topRight.x = std::max( topRight.x, botLeft.x + minWidth );
401 topRight.y = std::min( topRight.y, botLeft.y - minHeight );
402
403 // push edited point edges to adjacent corners
404 topLeft.y = topRight.y;
405 botRight.x = topRight.x;
406 }
407 else if( isModified( aEditedPoint, aPoints.Point( RECT_BOTLEFT ) ) )
408 {
409 // pin edited point within opposite corner
410 botLeft.x = std::min( botLeft.x, topRight.x - minWidth );
411 botLeft.y = std::max( botLeft.y, topRight.y + minHeight );
412
413 // push edited point edges to adjacent corners
414 botRight.y = botLeft.y;
415 topLeft.x = botLeft.x;
416 }
417 else if( isModified( aEditedPoint, aPoints.Point( RECT_BOTRIGHT ) ) )
418 {
419 // pin edited point within opposite corner
420 botRight.x = std::max( botRight.x, topLeft.x + minWidth );
421 botRight.y = std::max( botRight.y, topLeft.y + minHeight );
422
423 // push edited point edges to adjacent corners
424 botLeft.y = botRight.y;
425 topRight.x = botRight.x;
426 }
427 else if( isModified( aEditedPoint, aPoints.Line( RECT_TOP ) ) )
428 {
429 topLeft.y = std::min( topLeft.y, botRight.y - minHeight );
430 }
431 else if( isModified( aEditedPoint, aPoints.Line( RECT_LEFT ) ) )
432 {
433 topLeft.x = std::min( topLeft.x, botRight.x - minWidth );
434 }
435 else if( isModified( aEditedPoint, aPoints.Line( RECT_BOT ) ) )
436 {
437 botRight.y = std::max( botRight.y, topLeft.y + minHeight );
438 }
439 else if( isModified( aEditedPoint, aPoints.Line( RECT_RIGHT ) ) )
440 {
441 botRight.x = std::max( botRight.x, topLeft.x + minWidth );
442 }
443 }
444
445 static void UpdateItem( SCH_SHAPE& aRect, const EDIT_POINT& aEditedPoint,
446 EDIT_POINTS& aPoints, const VECTOR2I& aMinSize = { 0, 0 } )
447 {
448 VECTOR2I topLeft = aPoints.Point( RECT_TOPLEFT ).GetPosition();
449 VECTOR2I topRight = aPoints.Point( RECT_TOPRIGHT ).GetPosition();
450 VECTOR2I botLeft = aPoints.Point( RECT_BOTLEFT ).GetPosition();
451 VECTOR2I botRight = aPoints.Point( RECT_BOTRIGHT ).GetPosition();
452
453 int minWidth = std::max( schIUScale.MilsToIU( 1 ), aMinSize.x );
454 int minHeight = std::max( schIUScale.MilsToIU( 1 ), aMinSize.y );
455
456 PinEditedCorner( aEditedPoint, aPoints, minWidth, minHeight,
457 topLeft, topRight, botLeft, botRight );
458
459 if( isModified( aEditedPoint, aPoints.Point( RECT_TOPLEFT ) )
460 || isModified( aEditedPoint, aPoints.Point( RECT_TOPRIGHT ) )
461 || isModified( aEditedPoint, aPoints.Point( RECT_BOTRIGHT ) )
462 || isModified( aEditedPoint, aPoints.Point( RECT_BOTLEFT ) ) )
463 {
464 aRect.SetPosition( topLeft );
465 aRect.SetEnd( botRight );
466 }
467 else if( isModified( aEditedPoint, aPoints.Line( RECT_TOP ) ) )
468 {
469 aRect.SetStartY( topLeft.y );
470 }
471 else if( isModified( aEditedPoint, aPoints.Line( RECT_LEFT ) ) )
472 {
473 aRect.SetStartX( topLeft.x );
474 }
475 else if( isModified( aEditedPoint, aPoints.Line( RECT_BOT ) ) )
476 {
477 aRect.SetEndY( botRight.y );
478 }
479 else if( isModified( aEditedPoint, aPoints.Line( RECT_RIGHT ) ) )
480 {
481 aRect.SetEndX( botRight.x );
482 }
483
484 for( unsigned i = 0; i < aPoints.LinesSize(); ++i )
485 {
486 if( !isModified( aEditedPoint, aPoints.Line( i ) ) )
487 {
488 aPoints.Line( i ).SetRelation( EDIT_RELATION::PerpendicularTranslation( aPoints.Line( i ) ) );
489 }
490 }
491 }
492
493 void MakePoints( EDIT_POINTS& aPoints ) override
494 {
495 m_rect.Normalize();
496 MakePoints( m_rect, aPoints );
497 }
498
499 bool UpdatePoints( EDIT_POINTS& aPoints ) override
500 {
501 m_rect.Normalize();
502 UpdatePoints( m_rect, aPoints );
503 return true;
504 }
505
506 void UpdateItem( const EDIT_POINT& aEditedPoint, EDIT_POINTS& aPoints, COMMIT& aCommit,
507 std::vector<EDA_ITEM*>& aUpdatedItems ) override
508 {
509 VECTOR2I topLeft = aPoints.Point( RECT_TOPLEFT ).GetPosition();
510 VECTOR2I topRight = aPoints.Point( RECT_TOPRIGHT ).GetPosition();
511 VECTOR2I botLeft = aPoints.Point( RECT_BOTLEFT ).GetPosition();
512 VECTOR2I botRight = aPoints.Point( RECT_BOTRIGHT ).GetPosition();
513
514 PinEditedCorner( aEditedPoint, aPoints, schIUScale.MilsToIU( 1 ), schIUScale.MilsToIU( 1 ),
515 topLeft, topRight, botLeft, botRight );
516
517 const BOX2I oldBox = BOX2I::ByCorners( m_rect.GetStart(), m_rect.GetEnd() );
518 std::vector<SEG> oldSegs;
519 std::vector<VECTOR2I> moveVecs;
520
521 if( isModified( aEditedPoint, aPoints.Point( RECT_TOPLEFT ) )
522 || isModified( aEditedPoint, aPoints.Point( RECT_TOPRIGHT ) )
523 || isModified( aEditedPoint, aPoints.Point( RECT_BOTRIGHT ) )
524 || isModified( aEditedPoint, aPoints.Point( RECT_BOTLEFT ) ) )
525 {
526 // Corner drags don't update pins. Not only is it an escape hatch to avoid
527 // moving pins, it also avoids tricky problems when the pins "fall off"
528 // the ends of one of the two segments and get either left behind or
529 // "swept up" into the corner.
530 m_rect.SetPosition( topLeft );
531 m_rect.SetEnd( botRight );
532 }
533 else if( isModified( aEditedPoint, aPoints.Point( RECT_CENTER ) ) )
534 {
535 VECTOR2I moveVec = aPoints.Point( RECT_CENTER ).GetPosition() - oldBox.GetCenter();
536 m_rect.Move( moveVec );
537 }
538 else if( isModified( aEditedPoint, aPoints.Point( RECT_RADIUS ) ) )
539 {
540 int width = std::abs( botRight.x - topLeft.x );
541 int height = std::abs( botRight.y - topLeft.y );
542 int maxRadius = std::min( width, height ) / 2;
543 int x = aPoints.Point( RECT_RADIUS ).GetX();
544 x = std::clamp( x, botRight.x - maxRadius, botRight.x );
545 aPoints.Point( RECT_RADIUS ).SetPosition( VECTOR2I( x, topLeft.y ) );
546 m_rect.SetCornerRadius( botRight.x - x );
547 }
548 else if( isModified( aEditedPoint, aPoints.Line( RECT_TOP ) ) )
549 {
551 moveVecs.emplace_back( 0, topLeft.y - oldBox.GetTop() );
552 m_rect.SetStartY( topLeft.y );
553 }
554 else if( isModified( aEditedPoint, aPoints.Line( RECT_LEFT ) ) )
555 {
557 moveVecs.emplace_back( topLeft.x - oldBox.GetLeft(), 0 );
558 m_rect.SetStartX( topLeft.x );
559 }
560 else if( isModified( aEditedPoint, aPoints.Line( RECT_BOT ) ) )
561 {
563 moveVecs.emplace_back( 0, botRight.y - oldBox.GetBottom() );
564 m_rect.SetEndY( botRight.y );
565 }
566 else if( isModified( aEditedPoint, aPoints.Line( RECT_RIGHT ) ) )
567 {
569 moveVecs.emplace_back( botRight.x - oldBox.GetRight(), 0 );
570 m_rect.SetEndX( botRight.x );
571 }
572
573 dragPinsOnEdge( oldSegs, moveVecs, m_rect.GetUnit(), aCommit, aUpdatedItems );
574
575 for( unsigned i = 0; i < aPoints.LinesSize(); ++i )
576 {
577 if( !isModified( aEditedPoint, aPoints.Line( i ) ) )
578 {
579 aPoints.Line( i ).SetRelation( EDIT_RELATION::PerpendicularTranslation( aPoints.Line( i ) ) );
580 }
581 }
582 }
583
584private:
585 void dragPinsOnEdge( const std::vector<SEG>& aOldEdges, const std::vector<VECTOR2I>& aMoveVecs, int aEdgeUnit,
586 COMMIT& aCommit, std::vector<EDA_ITEM*>& aUpdatedItems ) const
587 {
588 wxCHECK( aOldEdges.size() == aMoveVecs.size(), /* void */ );
589
590 // This only make sense in the symbol editor
591 if( !m_frame.IsType( FRAME_SCH_SYMBOL_EDITOR ) )
592 return;
593
595
596 // And only if the setting is enabled
597 if( !editor.GetSettings()->m_dragPinsAlongWithEdges )
598 return;
599
600 // Adjuting pins on a different unit to a unit-limited shape
601 // seems suspect.
602 wxCHECK( aEdgeUnit == 0 || aEdgeUnit == editor.GetUnit(), /* void */ );
603
604 /*
605 * Get a list of pins on a line segment
606 */
607 const auto getPinsOnSeg =
608 []( LIB_SYMBOL& aSymbol, int aUnit, const SEG& aSeg,
609 bool aIncludeEnds ) -> std::vector<SCH_PIN*>
610 {
611 std::vector<SCH_PIN*> pins;
612
613 for( SCH_PIN* pin : aSymbol.GetGraphicalPins( aUnit, 0 ) )
614 {
615 // Figure out if the pin "connects" to the line
616 const VECTOR2I pinRootPos = pin->GetPinRoot();
617
618 if( aSeg.Contains( pinRootPos ) )
619 {
620 if( aIncludeEnds || ( pinRootPos != aSeg.A && pinRootPos != aSeg.B ) )
621 {
622 pins.push_back( pin );
623 }
624 }
625 }
626
627 return pins;
628 };
629
630 LIB_SYMBOL* const symbol = editor.GetCurSymbol();
631
632 for( std::size_t i = 0; i < aOldEdges.size(); ++i )
633 {
634 if( aMoveVecs[i] == VECTOR2I( 0, 0 ) || !symbol )
635 continue;
636
637 const std::vector<SCH_PIN*> pins = getPinsOnSeg( *symbol, aEdgeUnit, aOldEdges[i], false );
638
639 for( SCH_PIN* pin : pins )
640 {
641 aCommit.Modify( pin, editor.GetScreen() );
642 aUpdatedItems.push_back( pin );
643
644 // Move the pin
645 pin->Move( aMoveVecs[i] );
646 }
647 }
648 }
649
650private:
653};
654
655
657{
658public:
660 m_textbox( aTextbox )
661 {
662 }
663
664 void MakePoints( EDIT_POINTS& aPoints ) override
665 {
666 m_textbox.Normalize();
668 }
669
670 bool UpdatePoints( EDIT_POINTS& aPoints ) override
671 {
672 // point editor works only with rectangles having width and height > 0
673 // Some symbols can have rectangles with width or height < 0
674 // So normalize the size:
675 m_textbox.Normalize();
677 return true;
678 }
679
680 void UpdateItem( const EDIT_POINT& aEditedPoint, EDIT_POINTS& aPoints, COMMIT& aCommit,
681 std::vector<EDA_ITEM*>& aUpdatedItems ) override
682 {
683 m_textbox.ClearBoundingBoxCache();
684 VECTOR2I minSize = m_textbox.GetMinSize();
685
687 m_textbox.ClearRenderCache();
688 }
689
690private:
692};
693
694
696{
697public:
699 m_sheet( aSheet ),
700 m_screen( aScreen )
701 {
702 m_noConnects = m_sheet.GetNoConnects();
703
704 // Find all wires connected to sheet pins and store their connections
705 for( SCH_SHEET_PIN* pin : m_sheet.GetPins() )
706 {
707 VECTOR2I pinPos = pin->GetPosition();
708
709 for( SCH_ITEM* item : m_screen.Items().Overlapping( SCH_LINE_T, pinPos ) )
710 {
711 SCH_LINE* line = static_cast<SCH_LINE*>( item );
712
713 if( !line->IsWire() && !line->IsBus() )
714 continue;
715
716 if( line->GetStartPoint() == pinPos )
717 m_connectedWires.push_back( { pin, line, STARTPOINT } );
718 else if( line->GetEndPoint() == pinPos )
719 m_connectedWires.push_back( { pin, line, ENDPOINT } );
720 }
721 }
722 }
723
724 void MakePoints( EDIT_POINTS& aPoints ) override
725 {
726 VECTOR2I topLeft = m_sheet.GetPosition();
727 VECTOR2I botRight = m_sheet.GetPosition() + m_sheet.GetSize();
728
729 aPoints.AddPoint( topLeft );
730 aPoints.AddPoint( VECTOR2I( botRight.x, topLeft.y ) );
731 aPoints.AddPoint( VECTOR2I( topLeft.x, botRight.y ) );
732 aPoints.AddPoint( botRight );
733
734 aPoints.AddLine( aPoints.Point( RECT_TOPLEFT ), aPoints.Point( RECT_TOPRIGHT ) );
736 aPoints.AddLine( aPoints.Point( RECT_TOPRIGHT ), aPoints.Point( RECT_BOTRIGHT ) );
738 aPoints.AddLine( aPoints.Point( RECT_BOTRIGHT ), aPoints.Point( RECT_BOTLEFT ) );
740 aPoints.AddLine( aPoints.Point( RECT_BOTLEFT ), aPoints.Point( RECT_TOPLEFT ) );
742 }
743
744 bool UpdatePoints( EDIT_POINTS& aPoints ) override
745 {
746 VECTOR2I topLeft = m_sheet.GetPosition();
747 VECTOR2I botRight = m_sheet.GetPosition() + m_sheet.GetSize();
748
749 aPoints.Point( RECT_TOPLEFT ).SetPosition( topLeft );
750 aPoints.Point( RECT_TOPRIGHT ).SetPosition( botRight.x, topLeft.y );
751 aPoints.Point( RECT_BOTLEFT ).SetPosition( topLeft.x, botRight.y );
752 aPoints.Point( RECT_BOTRIGHT ).SetPosition( botRight );
753 return true;
754 }
755
756 void UpdateItem( const EDIT_POINT& aEditedPoint, EDIT_POINTS& aPoints, COMMIT& aCommit,
757 std::vector<EDA_ITEM*>& aUpdatedItems ) override
758 {
759 VECTOR2I topLeft = aPoints.Point( RECT_TOPLEFT ).GetPosition();
760 VECTOR2I topRight = aPoints.Point( RECT_TOPRIGHT ).GetPosition();
761 VECTOR2I botLeft = aPoints.Point( RECT_BOTLEFT ).GetPosition();
762 VECTOR2I botRight = aPoints.Point( RECT_BOTRIGHT ).GetPosition();
763 VECTOR2I sheetNewPos = m_sheet.GetPosition();
764 VECTOR2I sheetNewSize = m_sheet.GetSize();
765
766 bool editedTopRight = isModified( aEditedPoint, aPoints.Point( RECT_TOPRIGHT ) );
767 bool editedBotLeft = isModified( aEditedPoint, aPoints.Point( RECT_BOTLEFT ) );
768 bool editedBotRight = isModified( aEditedPoint, aPoints.Point( RECT_BOTRIGHT ) );
769
770 if( isModified( aEditedPoint, aPoints.Line( RECT_RIGHT ) ) )
771 editedTopRight = true;
772 else if( isModified( aEditedPoint, aPoints.Line( RECT_BOT ) ) )
773 editedBotLeft = true;
774
776 aEditedPoint, aPoints, m_sheet.GetMinWidth( editedTopRight || editedBotRight ),
777 m_sheet.GetMinHeight( editedBotLeft || editedBotRight ), topLeft, topRight, botLeft,
778 botRight );
779
780 if( isModified( aEditedPoint, aPoints.Point( RECT_TOPLEFT ) )
781 || isModified( aEditedPoint, aPoints.Point( RECT_TOPRIGHT ) )
782 || isModified( aEditedPoint, aPoints.Point( RECT_BOTRIGHT ) )
783 || isModified( aEditedPoint, aPoints.Point( RECT_BOTLEFT ) ) )
784 {
785 sheetNewPos = topLeft;
786 sheetNewSize = VECTOR2I( botRight.x - topLeft.x, botRight.y - topLeft.y );
787 }
788 else if( isModified( aEditedPoint, aPoints.Line( RECT_TOP ) ) )
789 {
790 sheetNewPos = VECTOR2I( m_sheet.GetPosition().x, topLeft.y );
791 sheetNewSize = VECTOR2I( m_sheet.GetSize().x, botRight.y - topLeft.y );
792 }
793 else if( isModified( aEditedPoint, aPoints.Line( RECT_LEFT ) ) )
794 {
795 sheetNewPos = VECTOR2I( topLeft.x, m_sheet.GetPosition().y );
796 sheetNewSize = VECTOR2I( botRight.x - topLeft.x, m_sheet.GetSize().y );
797 }
798 else if( isModified( aEditedPoint, aPoints.Line( RECT_BOT ) ) )
799 {
800 sheetNewSize = VECTOR2I( m_sheet.GetSize().x, botRight.y - topLeft.y );
801 }
802 else if( isModified( aEditedPoint, aPoints.Line( RECT_RIGHT ) ) )
803 {
804 sheetNewSize = VECTOR2I( botRight.x - topLeft.x, m_sheet.GetSize().y );
805 }
806
807 for( unsigned i = 0; i < aPoints.LinesSize(); ++i )
808 {
809 if( !isModified( aEditedPoint, aPoints.Line( i ) ) )
810 {
811 aPoints.Line( i ).SetRelation( EDIT_RELATION::PerpendicularTranslation( aPoints.Line( i ) ) );
812 }
813 }
814
815 if( m_sheet.GetPosition() != sheetNewPos )
816 m_sheet.SetPositionIgnoringPins( sheetNewPos );
817
818 if( m_sheet.GetSize() != sheetNewSize )
819 m_sheet.Resize( sheetNewSize );
820
821 // Update no-connects to follow their sheet pins
822 for( auto& [sheetPin, noConnect] : m_noConnects )
823 {
824 if( noConnect->GetPosition() != sheetPin->GetTextPos() )
825 {
826 aCommit.Modify( noConnect, &m_screen );
827 noConnect->SetPosition( sheetPin->GetTextPos() );
828 aUpdatedItems.push_back( noConnect );
829 }
830 }
831
832 // Update connected wires to follow their sheet pins
833 for( auto& [pin, line, endpoint] : m_connectedWires )
834 {
835 VECTOR2I newPinPos = pin->GetPosition();
836 bool needsUpdate = false;
837
838 if( endpoint == STARTPOINT && line->GetStartPoint() != newPinPos )
839 needsUpdate = true;
840 else if( endpoint == ENDPOINT && line->GetEndPoint() != newPinPos )
841 needsUpdate = true;
842
843 if( needsUpdate )
844 {
845 aCommit.Modify( line, &m_screen );
846
847 if( endpoint == STARTPOINT )
848 line->SetStartPoint( newPinPos );
849 else
850 line->SetEndPoint( newPinPos );
851
852 aUpdatedItems.push_back( line );
853 }
854 }
855 }
856
857private:
860 std::map<SCH_SHEET_PIN*, SCH_NO_CONNECT*> m_noConnects;
861 std::vector<std::tuple<SCH_SHEET_PIN*, SCH_LINE*, int>> m_connectedWires;
862};
863
864
866{
867 m_editBehavior = nullptr;
868 m_editPoints = std::make_shared<EDIT_POINTS>( aItem );
869
870 if( !aItem )
871 return;
872
873 // Generate list of edit points based on the item type
874 switch( aItem->Type() )
875 {
876 case SCH_SHAPE_T:
877 {
878 SCH_SHAPE* shape = static_cast<SCH_SHAPE*>( aItem );
879
880 switch( shape->GetShape() )
881 {
882 case SHAPE_T::ARC:
883 // EDA_ARC_POINT_EDIT_BEHAVIOR holds a reference to m_arcEditMode, so the
884 // persisted value must be synced from settings before the behavior is built.
885 if( m_isSymbolEditor )
886 {
887 if( SYMBOL_EDITOR_SETTINGS* cfg = m_frame->libeditconfig() )
888 m_arcEditMode = cfg->m_ArcEditMode;
889 }
890 else if( EESCHEMA_SETTINGS* cfg = m_frame->eeconfig() )
891 {
892 m_arcEditMode = cfg->m_Drawing.arc_edit_mode;
893 }
894
895 m_editBehavior = std::make_unique<EDA_ARC_POINT_EDIT_BEHAVIOR>( *shape, m_arcEditMode, *getViewControls(),
896 schIUScale );
897 break;
898 case SHAPE_T::CIRCLE: m_editBehavior = std::make_unique<EDA_CIRCLE_POINT_EDIT_BEHAVIOR>( *shape ); break;
900 m_editBehavior = std::make_unique<RECTANGLE_POINT_EDIT_BEHAVIOR>( *shape, *m_frame );
901 break;
902 case SHAPE_T::POLY: m_editBehavior = std::make_unique<EDA_POLYGON_POINT_EDIT_BEHAVIOR>( *shape ); break;
903 case SHAPE_T::BEZIER:
904 {
905 int maxError = schIUScale.mmToIU( ARC_LOW_DEF_MM );
906
907 if( SCHEMATIC* schematic = shape->Schematic() )
908 maxError = schematic->Settings().m_MaxError;
909
910 m_editBehavior = std::make_unique<EDA_BEZIER_POINT_EDIT_BEHAVIOR>( *shape, maxError );
911 break;
912 }
913 case SHAPE_T::ELLIPSE:
914 case SHAPE_T::ELLIPSE_ARC: m_editBehavior = std::make_unique<EDA_ELLIPSE_POINT_EDIT_BEHAVIOR>( *shape ); break;
915 default:
917 }
918
919 break;
920 }
921 case SCH_RULE_AREA_T:
922 {
923 SCH_SHAPE* shape = static_cast<SCH_SHAPE*>( aItem );
924 // Implemented directly as a polygon
925 m_editBehavior = std::make_unique<EDA_POLYGON_POINT_EDIT_BEHAVIOR>( *shape );
926 break;
927 }
928 case SCH_TEXTBOX_T:
929 {
930 SCH_TEXTBOX* textbox = static_cast<SCH_TEXTBOX*>( aItem );
931 m_editBehavior = std::make_unique<TEXTBOX_POINT_EDIT_BEHAVIOR>( *textbox );
932 break;
933 }
934 case SCH_TABLECELL_T:
935 {
936 SCH_TABLECELL* cell = static_cast<SCH_TABLECELL*>( aItem );
937 m_editBehavior = std::make_unique<SCH_TABLECELL_POINT_EDIT_BEHAVIOR>( *cell, *m_frame->GetScreen() );
938 break;
939 }
940 case SCH_SHEET_T:
941 {
942 SCH_SHEET& sheet = static_cast<SCH_SHEET&>( *aItem );
943 m_editBehavior = std::make_unique<SHEET_POINT_EDIT_BEHAVIOR>( sheet, *m_frame->GetScreen() );
944 break;
945 }
946 case SCH_BITMAP_T:
947 {
948 SCH_BITMAP& bitmap = static_cast<SCH_BITMAP&>( *aItem );
949 m_editBehavior = std::make_unique<REFERENCE_IMAGE_POINT_EDIT_BEHAVIOR>( bitmap.GetReferenceImage(),
950 schIUScale.MilsToIU( 50 ) );
951 break;
952 }
953 case SCH_LINE_T:
954 {
955 SCH_LINE& line = static_cast<SCH_LINE&>( *aItem );
956 m_editBehavior = std::make_unique<LINE_POINT_EDIT_BEHAVIOR>( line, *m_frame->GetScreen() );
957 break;
958 }
959 default:
960 {
961 m_editPoints.reset();
962 break;
963 }
964 }
965
966 // If we got a behavior, generate the points
967 if( m_editBehavior )
968 {
969 wxCHECK( m_editPoints, /* void */ );
970 m_editBehavior->MakePoints( *m_editPoints );
971 }
972}
973
974
976 SCH_TOOL_BASE<SCH_BASE_FRAME>( "eeschema.PointEditor" ),
977 m_editedPoint( nullptr ),
978 m_inDrag( false ),
980 m_inPointEditor( false )
981{
982}
983
984
986{
987 SCH_TOOL_BASE::Reset( aReason );
988
989 // ResetTools() skips DeactivateTool() for a REDRAW, so Main() exits without unwinding its
990 // drag; a REDRAW is also the only reason that leaves the item alive to clear the flag through
991 if( aReason == REDRAW && m_editPoints )
992 {
993 SCH_SHAPE* shape = dynamic_cast<SCH_SHAPE*>( m_editPoints->GetParent() );
994
995 if( shape && shape->HasFlag( IS_MOVING ) )
996 {
997 shape->ClearFlags( IS_MOVING );
998 shape->SetHatchingDirty();
999 shape->UpdateHatching();
1000 }
1001 }
1002
1003 if( KIGFX::VIEW* view = getView() )
1004 {
1005 if( m_angleItem )
1006 view->Remove( m_angleItem.get() );
1007
1008 if( m_editPoints )
1009 view->Remove( m_editPoints.get() );
1010 }
1011
1012 m_angleItem.reset();
1013 m_editPoints.reset();
1014 m_editedPoint = nullptr;
1015
1016 // A reset can tear down the Main() loop mid-drag, so clear the drag flag here too.
1017 m_inDrag = false;
1018}
1019
1020
1022{
1023 using S_C = SELECTION_CONDITIONS;
1024
1026
1027 const auto addCornerCondition = [&]( const SELECTION& aSelection ) -> bool
1028 {
1029 return SCH_POINT_EDITOR::addCornerCondition( aSelection );
1030 };
1031
1032 const auto removeCornerCondition = [&]( const SELECTION& aSelection ) -> bool
1033 {
1034 return SCH_POINT_EDITOR::removeCornerCondition( aSelection );
1035 };
1036
1037 const auto arcIsEdited = [&]( const SELECTION& aSelection ) -> bool
1038 {
1039 const EDA_ITEM* item = aSelection.Front();
1040 return ( item != nullptr ) && ( item->Type() == SCH_SHAPE_T )
1041 && static_cast<const SCH_SHAPE*>( item )->GetShape() == SHAPE_T::ARC;
1042 };
1043
1044 auto& menu = m_selectionTool->GetToolMenu().GetMenu();
1045
1046 // clang-format off
1049 menu.AddItem( ACTIONS::cycleArcEditMode, S_C::Count( 1 ) && arcIsEdited );
1050 // clang-format on
1051
1052 return true;
1053}
1054
1055
1057{
1058 setEditedPoint( nullptr );
1059
1060 return 0;
1061}
1062
1063
1065{
1066 EDIT_POINT* point = m_editedPoint;
1067
1068 if( !m_editPoints )
1069 {
1070 point = nullptr;
1071 }
1072 else if( aEvent.IsMotion() )
1073 {
1074 point = m_editPoints->FindPoint( aEvent.Position(), getView() );
1075 }
1076 else if( aEvent.IsDrag( BUT_LEFT ) )
1077 {
1078 point = m_editPoints->FindPoint( aEvent.DragOrigin(), getView() );
1079 }
1080 else
1081 {
1082 point = m_editPoints->FindPoint( getViewControls()->GetCursorPosition( false ), getView() );
1083 }
1084
1085 if( m_editedPoint != point )
1086 setEditedPoint( point );
1087}
1088
1089
1091{
1092 if( !m_selectionTool )
1093 return 0;
1094
1095 if( m_inPointEditor )
1096 return 0;
1097
1099
1100 if( m_isSymbolEditor )
1101 {
1103
1104 if( !editor->IsSymbolGraphicallyEditable() )
1105 return 0;
1106 }
1107
1108 const SCH_SELECTION& selection = m_selectionTool->GetSelection();
1109
1110 if( selection.Size() != 1 || !selection.Front()->IsType( pointEditorTypes ) )
1111 return 0;
1112
1113 // Wait till drawing tool is done
1114 if( selection.Front()->IsNew() )
1115 return 0;
1116
1117 Activate();
1118
1121 grid->SetPointEditProfile( true );
1122 VECTOR2I cursorPos;
1123 KIGFX::VIEW* view = getView();
1124 EDA_ITEM* item = selection.Front();
1125 SCH_COMMIT commit( m_toolMgr );
1126
1127 controls->ShowCursor( true );
1128
1129 makePointsAndBehavior( item );
1130 m_angleItem = std::make_unique<KIGFX::PREVIEW::ANGLE_ITEM>( m_editPoints );
1131 view->Add( m_editPoints.get() );
1132 view->Add( m_angleItem.get() );
1133 setEditedPoint( nullptr );
1134 updateEditedPoint( aEvent );
1135 bool inDrag = false;
1136
1137 // Main loop: keep receiving events
1138 while( TOOL_EVENT* evt = Wait() )
1139 {
1140 if( grid )
1141 {
1142 grid->SetSnap( !evt->Modifier( MD_SHIFT ) );
1143 grid->SetUseGrid( getView()->GetGAL()->GetGridSnapping()
1144 && !evt->DisableGridSnapping() );
1145 }
1146 else
1147 {
1148 // This check is based on the assumption that the grid object must be valid.
1149 // If this assumption is wrong, please fix the code above.
1150 wxCHECK( false, 0 );
1151 }
1152
1153 if( !m_editPoints || evt->IsSelectionEvent() )
1154 break;
1155
1156 if( !inDrag )
1157 updateEditedPoint( *evt );
1158
1159 if( evt->IsDrag( BUT_LEFT ) && m_editedPoint )
1160 {
1161 if( !inDrag )
1162 {
1163 // Ctrl overrides grid snapping during the drag, but it is also the selection
1164 // disambiguation modifier. Cancel the pending disambiguation menu so it does
1165 // not pop up mid-drag.
1166 m_selectionTool->CancelDisambiguation();
1167
1168 commit.Modify( m_editPoints->GetParent(), m_frame->GetScreen() );
1169
1170 if( SCH_SHAPE* shape = dynamic_cast<SCH_SHAPE*>( item ) )
1171 {
1172 shape->SetFlags( IS_MOVING );
1173 shape->SetHatchingDirty();
1174 shape->UpdateHatching();
1175 }
1176
1177 inDrag = true;
1178 }
1179
1180 bool snap = !evt->DisableGridSnapping();
1181 VECTOR2I rawPosition = controls->GetMousePosition();
1182 EDIT_RELATION* relation = m_editedPoint->GetRelation();
1183 bool angleRelation = relation
1184 && ( relation->Kind() == EDIT_RELATION_KIND::ANGLE_STEP_45
1185 || relation->Kind() == EDIT_RELATION_KIND::ANGLE_STEP_90 );
1186
1187 if( angleRelation && relation->Reference() )
1188 {
1189 grid->SetAngleRestriction( relation->Reference()->GetPosition(),
1190 relation->Kind() == EDIT_RELATION_KIND::ANGLE_STEP_45 ? 45.0 : 90.0 );
1191 }
1192 else
1193 {
1194 grid->SetAngleRestriction( std::nullopt, 0.0 );
1195 }
1196
1197 std::vector<VECTOR2I> stationarySelfPoints;
1198 std::vector<SEG> stationarySelfSegments;
1199
1200 if( SCH_SHAPE* shape = dynamic_cast<SCH_SHAPE*>( item ) )
1201 {
1202 int editedIndex = getEditedPointIndex();
1203
1204 if( shape->GetShape() == SHAPE_T::POLY )
1205 {
1206 const EDIT_LINE* editedLine = dynamic_cast<const EDIT_LINE*>( m_editedPoint );
1207
1208 for( unsigned i = 0; i < m_editPoints->PointsSize(); ++i )
1209 {
1210 const EDIT_POINT& point = m_editPoints->Point( i );
1211
1212 if( &point != m_editedPoint
1213 && ( !editedLine
1214 || ( &point != &editedLine->GetOrigin() && &point != &editedLine->GetEnd() ) ) )
1215 {
1216 stationarySelfPoints.push_back( point.GetPosition() );
1217 }
1218 }
1219
1220 for( unsigned i = 0; i < m_editPoints->LinesSize(); ++i )
1221 {
1222 const EDIT_LINE& line = m_editPoints->Line( i );
1223
1224 if( &line != editedLine && &line.GetOrigin() != m_editedPoint && &line.GetEnd() != m_editedPoint
1225 && ( !editedLine
1226 || ( &line.GetOrigin() != &editedLine->GetOrigin()
1227 && &line.GetOrigin() != &editedLine->GetEnd()
1228 && &line.GetEnd() != &editedLine->GetOrigin()
1229 && &line.GetEnd() != &editedLine->GetEnd() ) ) )
1230 {
1231 stationarySelfSegments.emplace_back( line.GetOrigin().GetPosition(),
1232 line.GetEnd().GetPosition() );
1233 }
1234 }
1235 }
1236 else if( shape->GetShape() == SHAPE_T::RECTANGLE && editedIndex >= RECT_TOPLEFT
1237 && editedIndex <= RECT_BOTRIGHT )
1238 {
1239 stationarySelfPoints.push_back( m_editPoints->Point( RECT_BOTRIGHT - editedIndex ).GetPosition() );
1240 }
1241 else if( shape->GetShape() == SHAPE_T::RECTANGLE )
1242 {
1243 for( unsigned i = 0; i < m_editPoints->LinesSize() && i < 4; ++i )
1244 {
1245 if( m_editedPoint != &m_editPoints->Line( i ) )
1246 continue;
1247
1248 const EDIT_LINE& opposite = m_editPoints->Line( ( i + 2 ) % 4 );
1249 stationarySelfPoints.push_back( opposite.GetOrigin().GetPosition() );
1250 stationarySelfPoints.push_back( opposite.GetEnd().GetPosition() );
1251 stationarySelfSegments.emplace_back( opposite.GetOrigin().GetPosition(),
1252 opposite.GetEnd().GetPosition() );
1253 break;
1254 }
1255 }
1256 else if( shape->GetShape() == SHAPE_T::ARC )
1257 {
1258 constexpr int arcStart = 0;
1259 constexpr int arcMid = 1;
1260 constexpr int arcEnd = 2;
1261 constexpr int arcCenter = 3;
1262
1264 {
1265 if( editedIndex != arcStart )
1266 stationarySelfPoints.push_back( m_editPoints->Point( arcStart ).GetPosition() );
1267
1268 if( editedIndex != arcEnd )
1269 stationarySelfPoints.push_back( m_editPoints->Point( arcEnd ).GetPosition() );
1270 }
1271 else if( editedIndex == arcStart || editedIndex == arcMid || editedIndex == arcEnd )
1272 {
1273 stationarySelfPoints.push_back( m_editPoints->Point( arcCenter ).GetPosition() );
1274 }
1275 }
1276 }
1277
1278 grid->SetStationarySelfGeometry( std::move( stationarySelfPoints ), std::move( stationarySelfSegments ) );
1279 grid->SetFeasibilityCallback( {} );
1280
1281 if( relation && !angleRelation )
1282 {
1283 if( std::optional<SNAP_CANDIDATE> authored = authoredSnapRelation( *relation ) )
1284 {
1285 grid->SetFeasibilityCallback(
1286 [authored = std::move( *authored )]( const SNAP_SOURCE_CONTEXT& aContext,
1287 const std::vector<SNAP_CANDIDATE>& aCandidates )
1288 {
1289 SNAP_RESOLVER resolver;
1290 resolver.AddCandidate( authored );
1291
1292 for( const SNAP_CANDIDATE& candidate : aCandidates )
1293 resolver.AddCandidate( candidate );
1294
1295 SNAP_RESULT result = resolver.Resolve( aContext );
1296
1297 if( !result.Accepted( authored.id ) )
1298 {
1300 return result;
1301 }
1302
1303 for( const SNAP_CANDIDATE& candidate : aCandidates )
1304 {
1305 if( !result.Accepted( candidate.id ) )
1306 {
1308 break;
1309 }
1310 }
1311
1312 return result;
1313 } );
1314 }
1315 }
1316
1317 m_editedPoint->SetPosition(
1318 grid->ResolveSnap( rawPosition, GRID_HELPER_GRIDS::GRID_GRAPHICS, static_cast<SCH_ITEM*>( item ) )
1319 .position );
1320
1321 cursorPos = m_editedPoint->GetPosition();
1322 controls->ForceCursorPosition( true, cursorPos );
1323
1324 updateParentItem( snap, commit );
1325 updatePoints();
1326 }
1327 else if( inDrag && evt->IsMouseUp( BUT_LEFT ) )
1328 {
1329 if( !commit.Empty() )
1330 commit.Push( _( "Move Point" ) );
1331
1332 controls->SetAutoPan( false );
1333
1334 if( SCH_SHAPE* shape = dynamic_cast<SCH_SHAPE*>( item ) )
1335 {
1336 shape->ClearFlags( IS_MOVING );
1337 shape->SetHatchingDirty();
1338 shape->UpdateHatching();
1339 }
1340
1341 inDrag = false;
1342 }
1343 else if( evt->IsCancelInteractive() || evt->IsActivate() )
1344 {
1345 if( inDrag ) // Restore the last change
1346 {
1347 // Currently we are manually managing the lifetime of the grid
1348 // helpers because there is a bug in the tool stack that adds
1349 // the point editor again when commit.Revert() rebuilds the selection.
1350 // We remove this grid here so the its destructor is called before it
1351 // is added again.
1352 if( grid )
1353 {
1354 delete grid;
1355 grid = nullptr;
1356 }
1357
1358 // Revert() keeps edit flags and, in the library editor, replaces the symbol and
1359 // frees item, so drop the flag first and rehatch the reverted geometry after
1360 if( SCH_SHAPE* shape = dynamic_cast<SCH_SHAPE*>( item ) )
1361 shape->ClearFlags( IS_MOVING );
1362
1363 commit.Revert();
1364
1365 if( m_editPoints )
1366 {
1367 if( SCH_SHAPE* shape = dynamic_cast<SCH_SHAPE*>( m_editPoints->GetParent() ) )
1368 {
1369 shape->SetHatchingDirty();
1370 shape->UpdateHatching();
1371 }
1372 }
1373
1374 inDrag = false;
1375 break;
1376 }
1377 else if( evt->IsCancelInteractive() )
1378 {
1379 break;
1380 }
1381
1382 if( evt->IsActivate() )
1383 break;
1384 }
1385 else
1386 {
1387 evt->SetPassEvent();
1388 }
1389
1390 // Mirror the drag state so IsDragging() lets the frame defer the autosave snapshot,
1391 // which would otherwise serialize the whole schematic over a live point edit.
1392 m_inDrag = inDrag;
1393
1394 controls->SetAutoPan( inDrag );
1395 controls->CaptureCursor( inDrag );
1396 }
1397
1398 m_inDrag = false;
1399
1400 // IS_MOVING is only still set if the loop broke mid-drag, and a null m_editPoints means
1401 // Reset() ran while we were suspended and has already dealt with a parent we cannot reach
1402 if( inDrag && m_editPoints )
1403 {
1404 if( SCH_SHAPE* shape = dynamic_cast<SCH_SHAPE*>( m_editPoints->GetParent() ) )
1405 {
1406 shape->ClearFlags( IS_MOVING );
1407 shape->SetHatchingDirty();
1408 shape->UpdateHatching();
1409 }
1410 }
1411
1412 controls->SetAutoPan( false );
1413 controls->CaptureCursor( false );
1414 setEditedPoint( nullptr );
1415
1416 if( m_editPoints )
1417 {
1418 view->Remove( m_editPoints.get() );
1419 view->Remove( m_angleItem.get() );
1420
1421 m_editPoints.reset();
1422 m_angleItem.reset();
1423 m_frame->GetCanvas()->Refresh();
1424 }
1425
1426 delete grid;
1427
1428 return 0;
1429}
1430
1431
1432void SCH_POINT_EDITOR::updateParentItem( bool aSnapToGrid, SCH_COMMIT& aCommit ) const
1433{
1434 EDA_ITEM* item = m_editPoints->GetParent();
1435
1436 if( !item )
1437 return;
1438
1439 if( !m_editBehavior )
1440 return;
1441
1442 // The edited item is always updated, so behaviors only report the other items they touch.
1443 std::vector<EDA_ITEM*> updatedItems = { item };
1444
1445 m_editBehavior->UpdateItem( *m_editedPoint, *m_editPoints, aCommit, updatedItems );
1446
1447 for( EDA_ITEM* updatedItem : updatedItems )
1448 updateItem( updatedItem, true );
1449
1450 m_frame->SetMsgPanel( item );
1451}
1452
1453
1455{
1456 if( !m_editPoints || !m_editBehavior )
1457 return;
1458
1459 // Careful; the unit and/or body style may have changed out from under us, meaning the item is no
1460 // longer present on the canvas.
1461 if( m_isSymbolEditor )
1462 {
1464 SCH_ITEM* item = dynamic_cast<SCH_ITEM*>( m_editPoints->GetParent() );
1465
1466 if( ( item && item->GetUnit() != ALL_UNITS && item->GetUnit() != editor->GetUnit() )
1467 || ( item && item->GetBodyStyle() != ALL_BODY_STYLES && item->GetBodyStyle() != editor->GetBodyStyle() ) )
1468 {
1469 getView()->Remove( m_editPoints.get() );
1470 getView()->Remove( m_angleItem.get() );
1471 m_editPoints.reset();
1472 m_angleItem.reset();
1473 return;
1474 }
1475 }
1476
1477 m_editBehavior->UpdatePoints( *m_editPoints );
1478 getView()->Update( m_editPoints.get() );
1479 getView()->Update( m_angleItem.get() );
1480}
1481
1482
1484{
1486
1487 if( aPoint )
1488 {
1489 m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::ARROW );
1490 controls->ForceCursorPosition( true, aPoint->GetPosition() );
1491 controls->ShowCursor( true );
1492 }
1493 else
1494 {
1495 if( m_frame->ToolStackIsEmpty() )
1496 controls->ShowCursor( false );
1497
1498 controls->ForceCursorPosition( false );
1499 }
1500
1501 m_editedPoint = aPoint;
1502}
1503
1504
1506{
1507 if( !m_editPoints || !m_editedPoint || !m_editPoints->GetParent()->IsType( { SCH_SHAPE_T, SCH_RULE_AREA_T } ) )
1508 return false;
1509
1510 SCH_SHAPE* shape = static_cast<SCH_SHAPE*>( m_editPoints->GetParent() );
1511
1512 if( shape->GetPolyShape().IsEmpty() )
1513 return false;
1514
1515 SHAPE_LINE_CHAIN& poly = shape->GetPolyShape().Outline( 0 );
1516
1517 if( m_editPoints->GetParent()->Type() == SCH_SHAPE_T && poly.GetPointCount() <= 2 )
1518 return false;
1519 if( m_editPoints->GetParent()->Type() == SCH_RULE_AREA_T && poly.GetPointCount() <= 3 )
1520 return false;
1521
1522 for( const VECTOR2I& pt : poly.CPoints() )
1523 {
1524 if( pt == m_editedPoint->GetPosition() )
1525 return true;
1526 }
1527
1528 return false;
1529}
1530
1531
1533{
1534 if( !m_editPoints || !m_editPoints->GetParent()->IsType( { SCH_SHAPE_T, SCH_RULE_AREA_T } ) )
1535 return false;
1536
1537 SCH_SHAPE* shape = static_cast<SCH_SHAPE*>( m_editPoints->GetParent() );
1538
1539 if( shape->GetShape() != SHAPE_T::POLY )
1540 return false;
1541
1542 VECTOR2I cursorPos = getViewControls()->GetCursorPosition( false );
1543 double threshold = getView()->ToWorld( EDIT_POINT::POINT_SIZE );
1544
1545 return shape->HitTest( cursorPos, (int) threshold );
1546}
1547
1548
1550{
1551 if( !m_editPoints || !m_editPoints->GetParent()->IsType( { SCH_SHAPE_T, SCH_RULE_AREA_T } ) )
1552 return 0;
1553
1554 SCH_SHAPE* shape = static_cast<SCH_SHAPE*>( m_editPoints->GetParent() );
1555
1556 if( shape->GetPolyShape().IsEmpty() )
1557 return 0;
1558
1559 SHAPE_LINE_CHAIN& poly = shape->GetPolyShape().Outline( 0 );
1560 SCH_COMMIT commit( m_toolMgr );
1561
1562 commit.Modify( shape, m_frame->GetScreen() );
1563
1565 int currentMinDistance = INT_MAX;
1566 int closestLineStart = 0;
1567 unsigned numPoints = poly.GetPointCount();
1568
1569 if( !shape->IsClosed() )
1570 numPoints -= 1;
1571
1572 for( unsigned i = 0; i < numPoints; ++i )
1573 {
1574 SEG seg = poly.GetSegment( i );
1575 int distance = seg.Distance( cursor );
1576
1577 if( distance < currentMinDistance )
1578 {
1579 currentMinDistance = distance;
1580 closestLineStart = i;
1581 }
1582 }
1583
1584 poly.Insert( closestLineStart + 1, cursor );
1585
1586 updateItem( shape, true );
1587 updatePoints();
1588
1589 commit.Push( _( "Add Corner" ) );
1590 return 0;
1591}
1592
1593
1595{
1596 if( !m_editPoints || !m_editedPoint || !m_editPoints->GetParent()->IsType( { SCH_SHAPE_T, SCH_RULE_AREA_T } ) )
1597 return 0;
1598
1599 SCH_SHAPE* shape = static_cast<SCH_SHAPE*>( m_editPoints->GetParent() );
1600
1601 if( shape->GetPolyShape().IsEmpty() )
1602 return 0;
1603
1604 SHAPE_LINE_CHAIN& poly = shape->GetPolyShape().Outline( 0 );
1605 SCH_COMMIT commit( m_toolMgr );
1606
1607 if( m_editPoints->GetParent()->Type() == SCH_SHAPE_T && poly.GetPointCount() <= 2 )
1608 return 0;
1609 if( m_editPoints->GetParent()->Type() == SCH_RULE_AREA_T && poly.GetPointCount() <= 3 )
1610 return 0;
1611
1612 commit.Modify( shape, m_frame->GetScreen() );
1613
1614 int idx = getEditedPointIndex();
1615 int last = (int) poly.GetPointCount() - 1;
1616
1617 if( idx == 0 && poly.GetPoint( 0 ) == poly.GetPoint( last ) )
1618 {
1619 poly.Remove( idx );
1620 poly.SetPoint( last - 1, poly.GetPoint( 0 ) );
1621 }
1622 else
1623 {
1624 poly.Remove( idx );
1625 }
1626
1627 shape->SetHatchingDirty();
1628
1629 setEditedPoint( nullptr );
1630
1631 updateItem( shape, true );
1632 updatePoints();
1633
1634 commit.Push( _( "Remove Corner" ) );
1635 return 0;
1636}
1637
1638
1640{
1641 // The Symbol Editor uses SYMBOL_EDITOR_SETTINGS, not EESCHEMA_SETTINGS, so eeconfig()
1642 // returns nullptr there. Dispatch on frame type to read/write the right settings store.
1643 EESCHEMA_SETTINGS* schCfg = m_isSymbolEditor ? nullptr : m_frame->eeconfig();
1644 SYMBOL_EDITOR_SETTINGS* symCfg = m_isSymbolEditor ? m_frame->libeditconfig() : nullptr;
1645
1646 if( aEvent.Matches( ACTIONS::cycleArcEditMode.MakeEvent() ) )
1647 {
1648 if( schCfg )
1650 else if( symCfg )
1651 m_arcEditMode = symCfg->m_ArcEditMode;
1652
1654 }
1655 else
1656 {
1658 }
1659
1660 if( schCfg )
1662 else if( symCfg )
1663 symCfg->m_ArcEditMode = m_arcEditMode;
1664
1665 return 0;
1666}
1667
1668
1670{
1671 updatePoints();
1672 return 0;
1673}
1674
1675
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:272
static TOOL_ACTION pointEditorArcKeepCenter
Definition actions.h:273
static TOOL_ACTION pointEditorArcKeepRadius
Definition actions.h:275
static TOOL_ACTION activatePointEditor
Definition actions.h:268
static TOOL_ACTION pointEditorArcKeepEndpoint
Definition actions.h:274
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:337
void SetStartX(int x)
Definition eda_shape.h:301
void SetEndY(int aY)
Definition eda_shape.h:344
void SetStartY(int y)
Definition eda_shape.h:294
SHAPE_POLY_SET & GetPolyShape()
SHAPE_T GetShape() const
Definition eda_shape.h:177
void SetEndX(int aX)
Definition eda_shape.h:351
const VECTOR2I & GetEnd() const
Return the ending point of the graphic.
Definition eda_shape.h:333
bool IsClosed() const
wxString SHAPE_T_asString() const
void SetHatchingDirty()
Definition eda_shape.h:155
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:348
static const TOOL_EVENT SelectedEvent
Definition actions.h:346
static const TOOL_EVENT SelectedItemsModified
Selected item had a property changed (except movement)
Definition actions.h:353
static const TOOL_EVENT PointSelectedEvent
Definition actions.h:345
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:68
virtual void Add(VIEW_ITEM *aItem, int aDrawPriority=-1)
Add a VIEW_ITEM to the view.
Definition view.cpp:365
virtual void Remove(VIEW_ITEM *aItem)
Remove a VIEW_ITEM from the view.
Definition view.cpp:488
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:2631
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:791
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
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
REFERENCE_IMAGE & GetReferenceImage()
Definition sch_bitmap.h:50
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:89
void UpdateHatching() const override
VECTOR2I GetCenter() const
Definition sch_shape.h:96
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:88
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
@ ARROW
Definition cursors.h:43
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:495
#define UNIMPLEMENTED_FOR(type)
Definition macros.h:92
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
@ ARC_START
@ ARC_CENTER
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
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:708