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, you may find one here:
19 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
20 * or you may search the http://www.gnu.org website for the version 2 license,
21 * or you may write to the Free Software Foundation, Inc.,
22 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
23 */
24
25#include "sch_point_editor.h"
26
27#include <algorithm>
28#include <ee_grid_helper.h>
29#include <tool/tool_manager.h>
30#include <sch_commit.h>
31#include <view/view_controls.h>
33#include <geometry/seg.h>
37#include <tools/sch_actions.h>
39#include <sch_edit_frame.h>
40#include <sch_line.h>
41#include <sch_bitmap.h>
42#include <sch_sheet.h>
43#include <sch_textbox.h>
44#include <sch_table.h>
46
47
55
56
57// Few constants to avoid using bare numbers for point indices
62
63
68
69
74
75
80
81
86
91
92
94{
95public:
97 m_line( aLine ),
98 m_screen( aScreen )
99 {
100 }
101
102 void MakePoints( EDIT_POINTS& aPoints ) override
103 {
104 std::pair<EDA_ITEM*, int> connectedStart = { nullptr, STARTPOINT };
105 std::pair<EDA_ITEM*, int> connectedEnd = { nullptr, STARTPOINT };
106
107 for( SCH_ITEM* test : m_screen.Items().OfType( SCH_LINE_T ) )
108 {
109 if( test->GetLayer() != LAYER_NOTES )
110 continue;
111
112 if( test == &m_line )
113 continue;
114
115 SCH_LINE* testLine = static_cast<SCH_LINE*>( test );
116
117 if( testLine->GetStartPoint() == m_line.GetStartPoint() )
118 {
119 connectedStart = { testLine, STARTPOINT };
120 }
121 else if( testLine->GetEndPoint() == m_line.GetStartPoint() )
122 {
123 connectedStart = { testLine, ENDPOINT };
124 }
125 else if( testLine->GetStartPoint() == m_line.GetEndPoint() )
126 {
127 connectedEnd = { testLine, STARTPOINT };
128 }
129 else if( testLine->GetEndPoint() == m_line.GetEndPoint() )
130 {
131 connectedEnd = { testLine, ENDPOINT };
132 }
133 }
134
135 aPoints.AddPoint( m_line.GetStartPoint(), connectedStart );
136 aPoints.AddPoint( m_line.GetEndPoint(), connectedEnd );
137 }
138
139 void UpdatePoints( EDIT_POINTS& aPoints ) override
140 {
141 aPoints.Point( LINE_START ).SetPosition( m_line.GetStartPoint() );
142 aPoints.Point( LINE_END ).SetPosition( m_line.GetEndPoint() );
143 }
144
145 void UpdateItem( const EDIT_POINT& aEditedPoints, EDIT_POINTS& aPoints, COMMIT& aCommit,
146 std::vector<EDA_ITEM*>& aUpdatedItems ) override
147 {
148 m_line.SetStartPoint( aPoints.Point( LINE_START ).GetPosition() );
149 m_line.SetEndPoint( aPoints.Point( LINE_END ).GetPosition() );
150
151 std::pair<EDA_ITEM*, int> connected = aPoints.Point( LINE_START ).GetConnected();
152
153 if( connected.first )
154 {
155 aCommit.Modify( connected.first, &m_screen );
156 aUpdatedItems.push_back( connected.first );
157
158 if( connected.second == STARTPOINT )
159 static_cast<SCH_LINE*>( connected.first )->SetStartPoint( m_line.GetStartPoint() );
160 else if( connected.second == ENDPOINT )
161 static_cast<SCH_LINE*>( connected.first )->SetEndPoint( m_line.GetStartPoint() );
162 }
163
164 connected = aPoints.Point( LINE_END ).GetConnected();
165
166 if( connected.first )
167 {
168 aCommit.Modify( connected.first, &m_screen );
169 aUpdatedItems.push_back( connected.first );
170
171 if( connected.second == STARTPOINT )
172 static_cast<SCH_LINE*>( connected.first )->SetStartPoint( m_line.GetEndPoint() );
173 else if( connected.second == ENDPOINT )
174 static_cast<SCH_LINE*>( connected.first )->SetEndPoint( m_line.GetEndPoint() );
175 }
176 }
177
178private:
181};
182
184{
185public:
187 m_bitmap( aBitmap )
188 {}
189
190 void MakePoints( EDIT_POINTS& aPoints ) override
191 {
192 const REFERENCE_IMAGE& refImage = m_bitmap.GetReferenceImage();
193 const VECTOR2I topLeft = refImage.GetPosition() - refImage.GetSize() / 2;
194 const VECTOR2I botRight = refImage.GetPosition() + refImage.GetSize() / 2;
195
196 aPoints.AddPoint( topLeft );
197 aPoints.AddPoint( VECTOR2I( botRight.x, topLeft.y ) );
198 aPoints.AddPoint( VECTOR2I( topLeft.x, botRight.y ) );
199 aPoints.AddPoint( botRight );
200
201 aPoints.AddPoint( refImage.GetPosition() + refImage.GetTransformOriginOffset() );
202 }
203
204 void UpdatePoints( EDIT_POINTS& aPoints ) override
205 {
206 const REFERENCE_IMAGE& refImage = m_bitmap.GetReferenceImage();
207 const VECTOR2I topLeft = refImage.GetPosition() - refImage.GetSize() / 2;
208 const VECTOR2I botRight = refImage.GetPosition() + refImage.GetSize() / 2;
209
210 aPoints.Point( RECT_TOPLEFT ).SetPosition( topLeft );
211 aPoints.Point( RECT_TOPRIGHT ).SetPosition( botRight.x, topLeft.y );
212 aPoints.Point( RECT_BOTLEFT ).SetPosition( topLeft.x, botRight.y );
213 aPoints.Point( RECT_BOTRIGHT ).SetPosition( botRight );
214
215 aPoints.Point( REFIMG_ORIGIN )
216 .SetPosition( refImage.GetPosition() + refImage.GetTransformOriginOffset() );
217 }
218
219 void UpdateItem( const EDIT_POINT& aEditedPoint, EDIT_POINTS& aPoints, COMMIT& aCommit,
220 std::vector<EDA_ITEM*>& aUpdatedItems ) override
221 {
222 REFERENCE_IMAGE& refImg = m_bitmap.GetReferenceImage();
223 const VECTOR2I topLeft = aPoints.Point( RECT_TOPLEFT ).GetPosition();
224 const VECTOR2I topRight = aPoints.Point( RECT_TOPRIGHT ).GetPosition();
225 const VECTOR2I botLeft = aPoints.Point( RECT_BOTLEFT ).GetPosition();
226 const VECTOR2I botRight = aPoints.Point( RECT_BOTRIGHT ).GetPosition();
227 const VECTOR2I xfrmOrigin = aPoints.Point( REFIMG_ORIGIN ).GetPosition();
228
229 if( isModified( aEditedPoint, aPoints.Point( REFIMG_ORIGIN ) ) )
230 {
231 // Moving the transform origin
232 // As the other points didn't move, we can get the image extent from them
233 const VECTOR2I newOffset = xfrmOrigin - ( topLeft + botRight ) / 2;
234 refImg.SetTransformOriginOffset( newOffset );
235 }
236 else
237 {
238 const VECTOR2I oldOrigin = refImg.GetPosition() + refImg.GetTransformOriginOffset();
239 const VECTOR2I oldSize = refImg.GetSize();
240 const VECTOR2I pos = refImg.GetPosition();
241
242 OPT_VECTOR2I newCorner;
243 VECTOR2I oldCorner = pos;
244
245 if( isModified( aEditedPoint, aPoints.Point( RECT_TOPLEFT ) ) )
246 {
247 newCorner = topLeft;
248 oldCorner -= oldSize / 2;
249 }
250 else if( isModified( aEditedPoint, aPoints.Point( RECT_TOPRIGHT ) ) )
251 {
252 newCorner = topRight;
253 oldCorner -= VECTOR2I( -oldSize.x, oldSize.y ) / 2;
254 }
255 else if( isModified( aEditedPoint, aPoints.Point( RECT_BOTLEFT ) ) )
256 {
257 newCorner = botLeft;
258 oldCorner -= VECTOR2I( oldSize.x, -oldSize.y ) / 2;
259 }
260 else if( isModified( aEditedPoint, aPoints.Point( RECT_BOTRIGHT ) ) )
261 {
262 newCorner = botRight;
263 oldCorner += oldSize / 2;
264 }
265
266 if( newCorner )
267 {
268 // Turn in the respective vectors from the origin
269 *newCorner -= xfrmOrigin;
270 oldCorner -= oldOrigin;
271
272 // If we tried to cross the origin, clamp it to stop it
273 if( sign( newCorner->x ) != sign( oldCorner.x )
274 || sign( newCorner->y ) != sign( oldCorner.y ) )
275 {
276 *newCorner = VECTOR2I( 0, 0 );
277 }
278
279 const double newLength = newCorner->EuclideanNorm();
280 const double oldLength = oldCorner.EuclideanNorm();
281
282 double ratio = oldLength > 0 ? ( newLength / oldLength ) : 1.0;
283
284 // Clamp the scaling to a minimum of 50 mils
285 VECTOR2I newSize = oldSize * ratio;
286 double newWidth = std::max( newSize.x, EDA_UNIT_UTILS::Mils2IU( schIUScale, 50 ) );
287 double newHeight = std::max( newSize.y, EDA_UNIT_UTILS::Mils2IU( schIUScale, 50 ) );
288 ratio = std::min( newWidth / oldSize.x, newHeight / oldSize.y );
289
290 // Also handles the origin offset
291 refImg.SetImageScale( refImg.GetImageScale() * ratio );
292 }
293 }
294 aUpdatedItems.push_back( &m_bitmap );
295 }
296
297private:
299};
300
301
303{
304public:
307 m_cell( aCell ),
308 m_screen( aScreen )
309 {
310 }
311
312 void UpdateItem( const EDIT_POINT& aEditedPoint, EDIT_POINTS& aPoints, COMMIT& aCommit,
313 std::vector<EDA_ITEM*>& aUpdatedItems ) override
314 {
315 SCH_TABLE& table = static_cast<SCH_TABLE&>( *m_cell.GetParent() );
316 bool rotated = !m_cell.GetTextAngle().IsHorizontal();
317
318 aCommit.Modify( &table, &m_screen );
319 aUpdatedItems.push_back( &table );
320
321 if( rotated )
322 {
323 if( isModified( aEditedPoint, aPoints.Point( ROW_HEIGHT ) ) )
324 {
325 m_cell.SetEnd( VECTOR2I( m_cell.GetEndX(), aPoints.Point( ROW_HEIGHT ).GetY() ) );
326
327 int colWidth = std::abs( m_cell.GetRectangleHeight() );
328
329 for( int ii = 0; ii < m_cell.GetColSpan() - 1; ++ii )
330 colWidth -= table.GetColWidth( m_cell.GetColumn() + ii );
331
332 table.SetColWidth( m_cell.GetColumn() + m_cell.GetColSpan() - 1, colWidth );
333 }
334 else if( isModified( aEditedPoint, aPoints.Point( COL_WIDTH ) ) )
335 {
336 m_cell.SetEnd( VECTOR2I( aPoints.Point( COL_WIDTH ).GetX(), m_cell.GetEndY() ) );
337
338 int rowHeight = m_cell.GetRectangleWidth();
339
340 for( int ii = 0; ii < m_cell.GetRowSpan() - 1; ++ii )
341 rowHeight -= table.GetRowHeight( m_cell.GetRow() + ii );
342
343 table.SetRowHeight( m_cell.GetRow() + m_cell.GetRowSpan() - 1, rowHeight );
344 }
345 }
346 else
347 {
348 if( isModified( aEditedPoint, aPoints.Point( COL_WIDTH ) ) )
349 {
350 m_cell.SetEnd( VECTOR2I( aPoints.Point( COL_WIDTH ).GetX(), m_cell.GetEndY() ) );
351
352 int colWidth = m_cell.GetRectangleWidth();
353
354 for( int ii = 0; ii < m_cell.GetColSpan() - 1; ++ii )
355 colWidth -= table.GetColWidth( m_cell.GetColumn() + ii );
356
357 table.SetColWidth( m_cell.GetColumn() + m_cell.GetColSpan() - 1, colWidth );
358 }
359 else if( isModified( aEditedPoint, aPoints.Point( ROW_HEIGHT ) ) )
360 {
361 m_cell.SetEnd( VECTOR2I( m_cell.GetEndX(), aPoints.Point( ROW_HEIGHT ).GetY() ) );
362
363 int rowHeight = m_cell.GetRectangleHeight();
364
365 for( int ii = 0; ii < m_cell.GetRowSpan() - 1; ++ii )
366 rowHeight -= table.GetRowHeight( m_cell.GetRow() + ii );
367
368 table.SetRowHeight( m_cell.GetRow() + m_cell.GetRowSpan() - 1, rowHeight );
369 }
370 }
371
372 table.Normalize();
373 }
374
375private:
378};
379
380
382{
383public:
385 m_rect( aRect ),
386 m_frame( aFrame )
387 {
388 }
389
390 static void MakePoints( SCH_SHAPE& aRect, EDIT_POINTS& aPoints )
391 {
392 VECTOR2I topLeft = aRect.GetPosition();
393 VECTOR2I botRight = aRect.GetEnd();
394
395 aPoints.AddPoint( topLeft );
396 aPoints.AddPoint( VECTOR2I( botRight.x, topLeft.y ) );
397 aPoints.AddPoint( VECTOR2I( topLeft.x, botRight.y ) );
398 aPoints.AddPoint( botRight );
399 aPoints.AddPoint( aRect.GetCenter() );
400 aPoints.AddPoint( VECTOR2I( botRight.x - aRect.GetCornerRadius(), topLeft.y ) );
401 aPoints.Point( RECT_RADIUS ).SetDrawCircle();
402
403 aPoints.AddLine( aPoints.Point( RECT_TOPLEFT ), aPoints.Point( RECT_TOPRIGHT ) );
404 aPoints.Line( RECT_TOP ).SetConstraint( new EC_PERPLINE( aPoints.Line( RECT_TOP ) ) );
405 aPoints.AddLine( aPoints.Point( RECT_TOPRIGHT ), aPoints.Point( RECT_BOTRIGHT ) );
406 aPoints.Line( RECT_RIGHT ).SetConstraint( new EC_PERPLINE( aPoints.Line( RECT_RIGHT ) ) );
407 aPoints.AddLine( aPoints.Point( RECT_BOTRIGHT ), aPoints.Point( RECT_BOTLEFT ) );
408 aPoints.Line( RECT_BOT ).SetConstraint( new EC_PERPLINE( aPoints.Line( RECT_BOT ) ) );
409 aPoints.AddLine( aPoints.Point( RECT_BOTLEFT ), aPoints.Point( RECT_TOPLEFT ) );
410 aPoints.Line( RECT_LEFT ).SetConstraint( new EC_PERPLINE( aPoints.Line( RECT_LEFT ) ) );
411 }
412
413 static void UpdatePoints( SCH_SHAPE& aRect, EDIT_POINTS& aPoints )
414 {
415 VECTOR2I topLeft = aRect.GetPosition();
416 VECTOR2I botRight = aRect.GetEnd();
417
418 aPoints.Point( RECT_TOPLEFT ).SetPosition( topLeft );
419 aPoints.Point( RECT_RADIUS ).SetPosition( VECTOR2I( botRight.x - aRect.GetCornerRadius(), topLeft.y ) );
420 aPoints.Point( RECT_TOPRIGHT ).SetPosition( VECTOR2I( botRight.x, topLeft.y ) );
421 aPoints.Point( RECT_BOTLEFT ).SetPosition( VECTOR2I( topLeft.x, botRight.y ) );
422 aPoints.Point( RECT_BOTRIGHT ).SetPosition( botRight );
423 aPoints.Point( RECT_CENTER ).SetPosition( aRect.GetCenter() );
424 }
425
436 static void PinEditedCorner( const EDIT_POINT& aEditedPoint, const EDIT_POINTS& aPoints,
437 int minWidth, int minHeight, VECTOR2I& topLeft, VECTOR2I& topRight,
438 VECTOR2I& botLeft, VECTOR2I& botRight )
439 {
440 if( isModified( aEditedPoint, aPoints.Point( RECT_TOPLEFT ) ) )
441 {
442 // pin edited point within opposite corner
443 topLeft.x = std::min( topLeft.x, botRight.x - minWidth );
444 topLeft.y = std::min( topLeft.y, botRight.y - minHeight );
445
446 // push edited point edges to adjacent corners
447 topRight.y = topLeft.y;
448 botLeft.x = topLeft.x;
449 }
450 else if( isModified( aEditedPoint, aPoints.Point( RECT_TOPRIGHT ) ) )
451 {
452 // pin edited point within opposite corner
453 topRight.x = std::max( topRight.x, botLeft.x + minWidth );
454 topRight.y = std::min( topRight.y, botLeft.y - minHeight );
455
456 // push edited point edges to adjacent corners
457 topLeft.y = topRight.y;
458 botRight.x = topRight.x;
459 }
460 else if( isModified( aEditedPoint, aPoints.Point( RECT_BOTLEFT ) ) )
461 {
462 // pin edited point within opposite corner
463 botLeft.x = std::min( botLeft.x, topRight.x - minWidth );
464 botLeft.y = std::max( botLeft.y, topRight.y + minHeight );
465
466 // push edited point edges to adjacent corners
467 botRight.y = botLeft.y;
468 topLeft.x = botLeft.x;
469 }
470 else if( isModified( aEditedPoint, aPoints.Point( RECT_BOTRIGHT ) ) )
471 {
472 // pin edited point within opposite corner
473 botRight.x = std::max( botRight.x, topLeft.x + minWidth );
474 botRight.y = std::max( botRight.y, topLeft.y + minHeight );
475
476 // push edited point edges to adjacent corners
477 botLeft.y = botRight.y;
478 topRight.x = botRight.x;
479 }
480 else if( isModified( aEditedPoint, aPoints.Line( RECT_TOP ) ) )
481 {
482 topLeft.y = std::min( topLeft.y, botRight.y - minHeight );
483 }
484 else if( isModified( aEditedPoint, aPoints.Line( RECT_LEFT ) ) )
485 {
486 topLeft.x = std::min( topLeft.x, botRight.x - minWidth );
487 }
488 else if( isModified( aEditedPoint, aPoints.Line( RECT_BOT ) ) )
489 {
490 botRight.y = std::max( botRight.y, topLeft.y + minHeight );
491 }
492 else if( isModified( aEditedPoint, aPoints.Line( RECT_RIGHT ) ) )
493 {
494 botRight.x = std::max( botRight.x, topLeft.x + minWidth );
495 }
496 }
497
498 static void UpdateItem( SCH_SHAPE& aRect, const EDIT_POINT& aEditedPoint, EDIT_POINTS& aPoints )
499 {
500 VECTOR2I topLeft = aPoints.Point( RECT_TOPLEFT ).GetPosition();
501 VECTOR2I topRight = aPoints.Point( RECT_TOPRIGHT ).GetPosition();
502 VECTOR2I botLeft = aPoints.Point( RECT_BOTLEFT ).GetPosition();
503 VECTOR2I botRight = aPoints.Point( RECT_BOTRIGHT ).GetPosition();
504
505 PinEditedCorner( aEditedPoint, aPoints, schIUScale.MilsToIU( 1 ), schIUScale.MilsToIU( 1 ),
506 topLeft, topRight, botLeft, botRight );
507
508 if( isModified( aEditedPoint, aPoints.Point( RECT_TOPLEFT ) )
509 || isModified( aEditedPoint, aPoints.Point( RECT_TOPRIGHT ) )
510 || isModified( aEditedPoint, aPoints.Point( RECT_BOTRIGHT ) )
511 || isModified( aEditedPoint, aPoints.Point( RECT_BOTLEFT ) ) )
512 {
513 aRect.SetPosition( topLeft );
514 aRect.SetEnd( botRight );
515 }
516 else if( isModified( aEditedPoint, aPoints.Line( RECT_TOP ) ) )
517 {
518 aRect.SetStartY( topLeft.y );
519 }
520 else if( isModified( aEditedPoint, aPoints.Line( RECT_LEFT ) ) )
521 {
522 aRect.SetStartX( topLeft.x );
523 }
524 else if( isModified( aEditedPoint, aPoints.Line( RECT_BOT ) ) )
525 {
526 aRect.SetEndY( botRight.y );
527 }
528 else if( isModified( aEditedPoint, aPoints.Line( RECT_RIGHT ) ) )
529 {
530 aRect.SetEndX( botRight.x );
531 }
532
533 for( unsigned i = 0; i < aPoints.LinesSize(); ++i )
534 {
535 if( !isModified( aEditedPoint, aPoints.Line( i ) ) )
536 {
537 aPoints.Line( i ).SetConstraint( new EC_PERPLINE( aPoints.Line( i ) ) );
538 }
539 }
540 }
541
542 void MakePoints( EDIT_POINTS& aPoints ) override
543 {
544 m_rect.Normalize();
545 MakePoints( m_rect, aPoints );
546 }
547
548 void UpdatePoints( EDIT_POINTS& aPoints ) override
549 {
550 m_rect.Normalize();
551 UpdatePoints( m_rect, aPoints );
552 }
553
554 void UpdateItem( const EDIT_POINT& aEditedPoint, EDIT_POINTS& aPoints, COMMIT& aCommit,
555 std::vector<EDA_ITEM*>& aUpdatedItems ) override
556 {
557 VECTOR2I topLeft = aPoints.Point( RECT_TOPLEFT ).GetPosition();
558 VECTOR2I topRight = aPoints.Point( RECT_TOPRIGHT ).GetPosition();
559 VECTOR2I botLeft = aPoints.Point( RECT_BOTLEFT ).GetPosition();
560 VECTOR2I botRight = aPoints.Point( RECT_BOTRIGHT ).GetPosition();
561
562 PinEditedCorner( aEditedPoint, aPoints, schIUScale.MilsToIU( 1 ), schIUScale.MilsToIU( 1 ),
563 topLeft, topRight, botLeft, botRight );
564
565 const BOX2I oldBox = BOX2I::ByCorners( m_rect.GetStart(), m_rect.GetEnd() );
566 std::vector<SEG> oldSegs;
567 std::vector<VECTOR2I> moveVecs;
568
569 if( isModified( aEditedPoint, aPoints.Point( RECT_TOPLEFT ) )
570 || isModified( aEditedPoint, aPoints.Point( RECT_TOPRIGHT ) )
571 || isModified( aEditedPoint, aPoints.Point( RECT_BOTRIGHT ) )
572 || isModified( aEditedPoint, aPoints.Point( RECT_BOTLEFT ) ) )
573 {
574 // Corner drags don't update pins. Not only is it an escape hatch to avoid
575 // moving pins, it also avoids tricky problems when the pins "fall off"
576 // the ends of one of the two segments and get either left behind or
577 // "swept up" into the corner.
578 m_rect.SetPosition( topLeft );
579 m_rect.SetEnd( botRight );
580 }
581 else if( isModified( aEditedPoint, aPoints.Point( RECT_CENTER ) ) )
582 {
583 VECTOR2I moveVec = aPoints.Point( RECT_CENTER ).GetPosition() - oldBox.GetCenter();
584 m_rect.Move( moveVec );
585 }
586 else if( isModified( aEditedPoint, aPoints.Point( RECT_RADIUS ) ) )
587 {
588 int width = std::abs( botRight.x - topLeft.x );
589 int height = std::abs( botRight.y - topLeft.y );
590 int maxRadius = std::min( width, height ) / 2;
591 int x = aPoints.Point( RECT_RADIUS ).GetX();
592 x = std::clamp( x, botRight.x - maxRadius, botRight.x );
593 aPoints.Point( RECT_RADIUS ).SetPosition( VECTOR2I( x, topLeft.y ) );
594 m_rect.SetCornerRadius( botRight.x - x );
595 }
596 else if( isModified( aEditedPoint, aPoints.Line( RECT_TOP ) ) )
597 {
599 moveVecs.emplace_back( 0, topLeft.y - oldBox.GetTop() );
600 m_rect.SetStartY( topLeft.y );
601 }
602 else if( isModified( aEditedPoint, aPoints.Line( RECT_LEFT ) ) )
603 {
605 moveVecs.emplace_back( topLeft.x - oldBox.GetLeft(), 0 );
606 m_rect.SetStartX( topLeft.x );
607 }
608 else if( isModified( aEditedPoint, aPoints.Line( RECT_BOT ) ) )
609 {
611 moveVecs.emplace_back( 0, botRight.y - oldBox.GetBottom() );
612 m_rect.SetEndY( botRight.y );
613 }
614 else if( isModified( aEditedPoint, aPoints.Line( RECT_RIGHT ) ) )
615 {
617 moveVecs.emplace_back( botRight.x - oldBox.GetRight(), 0 );
618 m_rect.SetEndX( botRight.x );
619 }
620
621 dragPinsOnEdge( oldSegs, moveVecs, m_rect.GetUnit(), aCommit, aUpdatedItems );
622
623 for( unsigned i = 0; i < aPoints.LinesSize(); ++i )
624 {
625 if( !isModified( aEditedPoint, aPoints.Line( i ) ) )
626 {
627 aPoints.Line( i ).SetConstraint( new EC_PERPLINE( aPoints.Line( i ) ) );
628 }
629 }
630 }
631
632private:
633 void dragPinsOnEdge( const std::vector<SEG>& aOldEdges, const std::vector<VECTOR2I>& aMoveVecs,
634 int aEdgeUnit, COMMIT& aCommit, std::vector<EDA_ITEM*>& aUpdatedItems ) const
635 {
636 wxCHECK( aOldEdges.size() == aMoveVecs.size(), /* void */ );
637
638 // This only make sense in the symbol editor
639 if( !m_frame.IsType( FRAME_SCH_SYMBOL_EDITOR ) )
640 return;
641
643
644 // And only if the setting is enabled
645 if( !editor.GetSettings()->m_dragPinsAlongWithEdges )
646 return;
647
648 // Adjuting pins on a different unit to a unit-limited shape
649 // seems suspect.
650 wxCHECK( aEdgeUnit == 0 || aEdgeUnit == editor.GetUnit(), /* void */ );
651
652 /*
653 * Get a list of pins on a line segment
654 */
655 const auto getPinsOnSeg =
656 []( LIB_SYMBOL& aSymbol, int aUnit, const SEG& aSeg,
657 bool aIncludeEnds ) -> std::vector<SCH_PIN*>
658 {
659 std::vector<SCH_PIN*> pins;
660
661 for( SCH_PIN* pin : aSymbol.GetGraphicalPins( aUnit, 0 ) )
662 {
663 // Figure out if the pin "connects" to the line
664 const VECTOR2I pinRootPos = pin->GetPinRoot();
665
666 if( aSeg.Contains( pinRootPos ) )
667 {
668 if( aIncludeEnds || ( pinRootPos != aSeg.A && pinRootPos != aSeg.B ) )
669 {
670 pins.push_back( pin );
671 }
672 }
673 }
674
675 return pins;
676 };
677
678 LIB_SYMBOL* const symbol = editor.GetCurSymbol();
679
680 for( std::size_t i = 0; i < aOldEdges.size(); ++i )
681 {
682 if( aMoveVecs[i] == VECTOR2I( 0, 0 ) || !symbol )
683 continue;
684
685 const std::vector<SCH_PIN*> pins = getPinsOnSeg( *symbol, aEdgeUnit, aOldEdges[i], false );
686
687 for( SCH_PIN* pin : pins )
688 {
689 aCommit.Modify( pin, editor.GetScreen() );
690 aUpdatedItems.push_back( pin );
691
692 // Move the pin
693 pin->Move( aMoveVecs[i] );
694 }
695 }
696 }
697
698private:
701};
702
703
705{
706public:
708 m_textbox( aTextbox )
709 {}
710
711 void MakePoints( EDIT_POINTS& aPoints ) override
712 {
713 m_textbox.Normalize();
715 }
716
717 void UpdatePoints( EDIT_POINTS& aPoints ) override
718 {
719 // point editor works only with rectangles having width and height > 0
720 // Some symbols can have rectangles with width or height < 0
721 // So normalize the size:
722 m_textbox.Normalize();
724 }
725
726 void UpdateItem( const EDIT_POINT& aEditedPoint, EDIT_POINTS& aPoints, COMMIT& aCommit,
727 std::vector<EDA_ITEM*>& aUpdatedItems ) override
728 {
730 m_textbox.ClearRenderCache();
731 }
732
733private:
735};
736
737
739{
740public:
742 m_sheet( aSheet )
743 {}
744
745 void MakePoints( EDIT_POINTS& aPoints ) override
746 {
747 VECTOR2I topLeft = m_sheet.GetPosition();
748 VECTOR2I botRight = m_sheet.GetPosition() + m_sheet.GetSize();
749
750 aPoints.AddPoint( topLeft );
751 aPoints.AddPoint( VECTOR2I( botRight.x, topLeft.y ) );
752 aPoints.AddPoint( VECTOR2I( topLeft.x, botRight.y ) );
753 aPoints.AddPoint( botRight );
754
755 aPoints.AddLine( aPoints.Point( RECT_TOPLEFT ), aPoints.Point( RECT_TOPRIGHT ) );
756 aPoints.Line( RECT_TOP ).SetConstraint( new EC_PERPLINE( aPoints.Line( RECT_TOP ) ) );
757 aPoints.AddLine( aPoints.Point( RECT_TOPRIGHT ), aPoints.Point( RECT_BOTRIGHT ) );
758 aPoints.Line( RECT_RIGHT ).SetConstraint( new EC_PERPLINE( aPoints.Line( RECT_RIGHT ) ) );
759 aPoints.AddLine( aPoints.Point( RECT_BOTRIGHT ), aPoints.Point( RECT_BOTLEFT ) );
760 aPoints.Line( RECT_BOT ).SetConstraint( new EC_PERPLINE( aPoints.Line( RECT_BOT ) ) );
761 aPoints.AddLine( aPoints.Point( RECT_BOTLEFT ), aPoints.Point( RECT_TOPLEFT ) );
762 aPoints.Line( RECT_LEFT ).SetConstraint( new EC_PERPLINE( aPoints.Line( RECT_LEFT ) ) );
763 }
764
765 void UpdatePoints( EDIT_POINTS& aPoints ) override
766 {
767 VECTOR2I topLeft = m_sheet.GetPosition();
768 VECTOR2I botRight = m_sheet.GetPosition() + m_sheet.GetSize();
769
770 aPoints.Point( RECT_TOPLEFT ).SetPosition( topLeft );
771 aPoints.Point( RECT_TOPRIGHT ).SetPosition( botRight.x, topLeft.y );
772 aPoints.Point( RECT_BOTLEFT ).SetPosition( topLeft.x, botRight.y );
773 aPoints.Point( RECT_BOTRIGHT ).SetPosition( botRight );
774 }
775
776 void UpdateItem( const EDIT_POINT& aEditedPoint, EDIT_POINTS& aPoints, COMMIT& aCommit,
777 std::vector<EDA_ITEM*>& aUpdatedItems ) override
778 {
779 VECTOR2I topLeft = aPoints.Point( RECT_TOPLEFT ).GetPosition();
780 VECTOR2I topRight = aPoints.Point( RECT_TOPRIGHT ).GetPosition();
781 VECTOR2I botLeft = aPoints.Point( RECT_BOTLEFT ).GetPosition();
782 VECTOR2I botRight = aPoints.Point( RECT_BOTRIGHT ).GetPosition();
783 VECTOR2I sheetNewPos = m_sheet.GetPosition();
784 VECTOR2I sheetNewSize = m_sheet.GetSize();
785
786 bool editedTopRight = isModified( aEditedPoint, aPoints.Point( RECT_TOPRIGHT ) );
787 bool editedBotLeft = isModified( aEditedPoint, aPoints.Point( RECT_BOTLEFT ) );
788 bool editedBotRight = isModified( aEditedPoint, aPoints.Point( RECT_BOTRIGHT ) );
789
790 if( isModified( aEditedPoint, aPoints.Line( RECT_RIGHT ) ) )
791 editedTopRight = true;
792 else if( isModified( aEditedPoint, aPoints.Line( RECT_BOT ) ) )
793 editedBotLeft = true;
794
796 aEditedPoint, aPoints, m_sheet.GetMinWidth( editedTopRight || editedBotRight ),
797 m_sheet.GetMinHeight( editedBotLeft || editedBotRight ), topLeft, topRight, botLeft,
798 botRight );
799
800 if( isModified( aEditedPoint, aPoints.Point( RECT_TOPLEFT ) )
801 || isModified( aEditedPoint, aPoints.Point( RECT_TOPRIGHT ) )
802 || isModified( aEditedPoint, aPoints.Point( RECT_BOTRIGHT ) )
803 || isModified( aEditedPoint, aPoints.Point( RECT_BOTLEFT ) ) )
804 {
805 sheetNewPos = topLeft;
806 sheetNewSize = VECTOR2I( botRight.x - topLeft.x, botRight.y - topLeft.y );
807 }
808 else if( isModified( aEditedPoint, aPoints.Line( RECT_TOP ) ) )
809 {
810 sheetNewPos = VECTOR2I( m_sheet.GetPosition().x, topLeft.y );
811 sheetNewSize = VECTOR2I( m_sheet.GetSize().x, botRight.y - topLeft.y );
812 }
813 else if( isModified( aEditedPoint, aPoints.Line( RECT_LEFT ) ) )
814 {
815 sheetNewPos = VECTOR2I( topLeft.x, m_sheet.GetPosition().y );
816 sheetNewSize = VECTOR2I( botRight.x - topLeft.x, m_sheet.GetSize().y );
817 }
818 else if( isModified( aEditedPoint, aPoints.Line( RECT_BOT ) ) )
819 {
820 sheetNewSize = VECTOR2I( m_sheet.GetSize().x, botRight.y - topLeft.y );
821 }
822 else if( isModified( aEditedPoint, aPoints.Line( RECT_RIGHT ) ) )
823 {
824 sheetNewSize = VECTOR2I( botRight.x - topLeft.x, m_sheet.GetSize().y );
825 }
826
827 for( unsigned i = 0; i < aPoints.LinesSize(); ++i )
828 {
829 if( !isModified( aEditedPoint, aPoints.Line( i ) ) )
830 {
831 aPoints.Line( i ).SetConstraint( new EC_PERPLINE( aPoints.Line( i ) ) );
832 }
833 }
834
835 if( m_sheet.GetPosition() != sheetNewPos )
836 m_sheet.SetPositionIgnoringPins( sheetNewPos );
837
838 if( m_sheet.GetSize() != sheetNewSize )
839 m_sheet.Resize( sheetNewSize );
840 }
841
842private:
844};
845
846
848{
849 m_editBehavior = nullptr;
850 m_editPoints = std::make_shared<EDIT_POINTS>( aItem );
851
852 if( !aItem )
853 return;
854
855 // Generate list of edit points based on the item type
856 switch( aItem->Type() )
857 {
858 case SCH_SHAPE_T:
859 {
860 SCH_SHAPE* shape = static_cast<SCH_SHAPE*>( aItem );
861
862 switch( shape->GetShape() )
863 {
864 case SHAPE_T::ARC:
865 m_editBehavior = std::make_unique<EDA_ARC_POINT_EDIT_BEHAVIOR>(
866 *shape, m_arcEditMode, *getViewControls() );
867 break;
868 case SHAPE_T::CIRCLE:
869 m_editBehavior = std::make_unique<EDA_CIRCLE_POINT_EDIT_BEHAVIOR>( *shape );
870 break;
872 m_editBehavior = std::make_unique<RECTANGLE_POINT_EDIT_BEHAVIOR>( *shape, *m_frame );
873 break;
874 case SHAPE_T::POLY:
875 m_editBehavior = std::make_unique<EDA_POLYGON_POINT_EDIT_BEHAVIOR>( *shape );
876 break;
877 case SHAPE_T::BEZIER:
878 {
879 int maxError = schIUScale.mmToIU( ARC_LOW_DEF_MM );
880
881 if( SCHEMATIC* schematic = shape->Schematic() )
882 maxError = schematic->Settings().m_MaxError;
883
884 m_editBehavior = std::make_unique<EDA_BEZIER_POINT_EDIT_BEHAVIOR>( *shape, maxError );
885 break;
886 }
887 default:
889 }
890
891 break;
892 }
893 case SCH_RULE_AREA_T:
894 {
895 SCH_SHAPE* shape = static_cast<SCH_SHAPE*>( aItem );
896 // Implemented directly as a polygon
897 m_editBehavior = std::make_unique<EDA_POLYGON_POINT_EDIT_BEHAVIOR>( *shape );
898 break;
899 }
900 case SCH_TEXTBOX_T:
901 {
902 SCH_TEXTBOX* textbox = static_cast<SCH_TEXTBOX*>( aItem );
903 m_editBehavior = std::make_unique<TEXTBOX_POINT_EDIT_BEHAVIOR>( *textbox );
904 break;
905 }
906 case SCH_TABLECELL_T:
907 {
908 SCH_TABLECELL* cell = static_cast<SCH_TABLECELL*>( aItem );
909 m_editBehavior = std::make_unique<SCH_TABLECELL_POINT_EDIT_BEHAVIOR>( *cell, *m_frame->GetScreen() );
910 break;
911 }
912 case SCH_SHEET_T:
913 {
914 SCH_SHEET& sheet = static_cast<SCH_SHEET&>( *aItem );
915 m_editBehavior = std::make_unique<SHEET_POINT_EDIT_BEHAVIOR>( sheet );
916 break;
917 }
918 case SCH_BITMAP_T:
919 {
920 SCH_BITMAP& bitmap = static_cast<SCH_BITMAP&>( *aItem );
921 m_editBehavior = std::make_unique<BITMAP_POINT_EDIT_BEHAVIOR>( bitmap );
922 break;
923 }
924 case SCH_LINE_T:
925 {
926 SCH_LINE& line = static_cast<SCH_LINE&>( *aItem );
927 m_editBehavior = std::make_unique<LINE_POINT_EDIT_BEHAVIOR>( line, *m_frame->GetScreen() );
928 break;
929 }
930 default:
931 {
932 m_editPoints.reset();
933 break;
934 }
935 }
936
937 // If we got a behavior, generate the points
938 if( m_editBehavior )
939 {
940 wxCHECK( m_editPoints, /* void */ );
941 m_editBehavior->MakePoints( *m_editPoints );
942 }
943}
944
945
953
954
956{
957 SCH_TOOL_BASE::Reset( aReason );
958
959 m_editPoints.reset();
960 m_editedPoint = nullptr;
961}
962
963
965{
967
969
970 const auto addCornerCondition = [&]( const SELECTION& aSelection ) -> bool
971 {
972 return SCH_POINT_EDITOR::addCornerCondition( aSelection );
973 };
974
975 const auto removeCornerCondition = [&]( const SELECTION& aSelection ) -> bool
976 {
977 return SCH_POINT_EDITOR::removeCornerCondition( aSelection );
978 };
979
980 const auto arcIsEdited = [&]( const SELECTION& aSelection ) -> bool
981 {
982 const EDA_ITEM* item = aSelection.Front();
983 return ( item != nullptr ) && ( item->Type() == SCH_SHAPE_T )
984 && static_cast<const SCH_SHAPE*>( item )->GetShape() == SHAPE_T::ARC;
985 };
986
987 auto& menu = m_selectionTool->GetToolMenu().GetMenu();
988
989 // clang-format off
992 menu.AddItem( ACTIONS::cycleArcEditMode, S_C::Count( 1 ) && arcIsEdited );
993 // clang-format on
994
995 return true;
996}
997
998
1000{
1001 setEditedPoint( nullptr );
1002
1003 return 0;
1004}
1005
1006
1008{
1009 EDIT_POINT* point = m_editedPoint;
1010
1011 if( !m_editPoints )
1012 {
1013 point = nullptr;
1014 }
1015 else if( aEvent.IsMotion() )
1016 {
1017 point = m_editPoints->FindPoint( aEvent.Position(), getView() );
1018 }
1019 else if( aEvent.IsDrag( BUT_LEFT ) )
1020 {
1021 point = m_editPoints->FindPoint( aEvent.DragOrigin(), getView() );
1022 }
1023 else
1024 {
1025 point = m_editPoints->FindPoint( getViewControls()->GetCursorPosition( false ), getView() );
1026 }
1027
1028 if( m_editedPoint != point )
1029 setEditedPoint( point );
1030}
1031
1032
1034{
1035 if( !m_selectionTool )
1036 return 0;
1037
1038 if( m_inPointEditor )
1039 return 0;
1040
1042
1043 if( m_isSymbolEditor )
1044 {
1046
1047 if( !editor->IsSymbolEditable() || editor->IsSymbolAlias() )
1048 return 0;
1049 }
1050
1051 const SCH_SELECTION& selection = m_selectionTool->GetSelection();
1052
1053 if( selection.Size() != 1 || !selection.Front()->IsType( pointEditorTypes ) )
1054 return 0;
1055
1056 // Wait till drawing tool is done
1057 if( selection.Front()->IsNew() )
1058 return 0;
1059
1060 Activate();
1061
1064 VECTOR2I cursorPos;
1065 KIGFX::VIEW* view = getView();
1066 EDA_ITEM* item = selection.Front();
1067 SCH_COMMIT commit( m_toolMgr );
1068
1069 controls->ShowCursor( true );
1070
1071 makePointsAndBehavior( item );
1072 m_angleItem = std::make_unique<KIGFX::PREVIEW::ANGLE_ITEM>( m_editPoints.get() );
1073 view->Add( m_editPoints.get() );
1074 view->Add( m_angleItem.get() );
1075 setEditedPoint( nullptr );
1076 updateEditedPoint( aEvent );
1077 bool inDrag = false;
1078
1079 // Main loop: keep receiving events
1080 while( TOOL_EVENT* evt = Wait() )
1081 {
1082 if( grid )
1083 {
1084 grid->SetSnap( !evt->Modifier( MD_SHIFT ) );
1085 grid->SetUseGrid( getView()->GetGAL()->GetGridSnapping()
1086 && !evt->DisableGridSnapping() );
1087 }
1088 else
1089 {
1090 // This check is based on the assumption that the grid object must be valid.
1091 // If this assumption is wrong, please fix the code above.
1092 wxCHECK( false, 0 );
1093 }
1094
1095 if( !m_editPoints || evt->IsSelectionEvent() )
1096 break;
1097
1098 if ( !inDrag )
1099 updateEditedPoint( *evt );
1100
1101 if( evt->IsDrag( BUT_LEFT ) && m_editedPoint )
1102 {
1103 if( !inDrag )
1104 {
1105 commit.Modify( m_editPoints->GetParent(), m_frame->GetScreen() );
1106
1107 if( SCH_SHAPE* shape = dynamic_cast<SCH_SHAPE*>( item ) )
1108 {
1109 shape->SetFlags( IS_MOVING );
1110 shape->SetHatchingDirty();
1111 shape->UpdateHatching();
1112 }
1113
1114 inDrag = true;
1115 }
1116
1117 bool snap = !evt->DisableGridSnapping();
1118
1119 cursorPos = grid->Align( controls->GetMousePosition(),
1121 controls->ForceCursorPosition( true, cursorPos );
1122
1123 m_editedPoint->SetPosition( controls->GetCursorPosition( snap ) );
1124
1125 updateParentItem( snap, commit );
1126 updatePoints();
1127 }
1128 else if( inDrag && evt->IsMouseUp( BUT_LEFT ) )
1129 {
1130 if( !commit.Empty() )
1131 commit.Push( _( "Move Point" ) );
1132
1133 controls->SetAutoPan( false );
1134
1135 if( SCH_SHAPE* shape = dynamic_cast<SCH_SHAPE*>( item ) )
1136 {
1137 shape->ClearFlags( IS_MOVING );
1138 shape->SetHatchingDirty();
1139 shape->UpdateHatching();
1140 }
1141
1142 inDrag = false;
1143 }
1144 else if( evt->IsCancelInteractive() || evt->IsActivate() )
1145 {
1146 if( inDrag ) // Restore the last change
1147 {
1148 // Currently we are manually managing the lifetime of the grid
1149 // helpers because there is a bug in the tool stack that adds
1150 // the point editor again when commit.Revert() rebuilds the selection.
1151 // We remove this grid here so the its destructor is called before it
1152 // is added again.
1153 if( grid )
1154 {
1155 delete grid;
1156 grid = nullptr;
1157 }
1158
1159 commit.Revert();
1160 inDrag = false;
1161 break;
1162 }
1163 else if( evt->IsCancelInteractive() )
1164 {
1165 break;
1166 }
1167
1168 if( evt->IsActivate() )
1169 break;
1170 }
1171 else
1172 {
1173 evt->SetPassEvent();
1174 }
1175
1176 controls->SetAutoPan( inDrag );
1177 controls->CaptureCursor( inDrag );
1178 }
1179
1180 if( SCH_SHAPE* shape = dynamic_cast<SCH_SHAPE*>( item ) )
1181 {
1182 shape->ClearFlags( IS_MOVING );
1183 shape->SetHatchingDirty();
1184 shape->UpdateHatching();
1185 }
1186
1187 controls->SetAutoPan( false );
1188 controls->CaptureCursor( false );
1189 setEditedPoint( nullptr );
1190
1191 if( m_editPoints )
1192 {
1193 view->Remove( m_editPoints.get() );
1194 view->Remove( m_angleItem.get() );
1195
1196 m_editPoints.reset();
1197 m_angleItem.reset();
1198 m_frame->GetCanvas()->Refresh();
1199 }
1200
1201 delete grid;
1202
1203 return 0;
1204}
1205
1206
1207void SCH_POINT_EDITOR::updateParentItem( bool aSnapToGrid, SCH_COMMIT& aCommit ) const
1208{
1209 EDA_ITEM* item = m_editPoints->GetParent();
1210
1211 if( !item )
1212 return;
1213
1214 if( !m_editBehavior )
1215 return;
1216
1217 std::vector<EDA_ITEM*> updatedItems;
1218 m_editBehavior->UpdateItem( *m_editedPoint, *m_editPoints, aCommit, updatedItems );
1219
1220 for( EDA_ITEM* updatedItem : updatedItems )
1221 updateItem( updatedItem, true );
1222
1223 m_frame->SetMsgPanel( item );
1224}
1225
1226
1228{
1229 if( !m_editPoints || !m_editBehavior )
1230 return;
1231
1232 m_editBehavior->UpdatePoints( *m_editPoints );
1233 getView()->Update( m_editPoints.get() );
1234 getView()->Update( m_angleItem.get() );
1235}
1236
1237
1239{
1241
1242 if( aPoint )
1243 {
1244 m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::ARROW );
1245 controls->ForceCursorPosition( true, aPoint->GetPosition() );
1246 controls->ShowCursor( true );
1247 }
1248 else
1249 {
1250 if( m_frame->ToolStackIsEmpty() )
1251 controls->ShowCursor( false );
1252
1253 controls->ForceCursorPosition( false );
1254 }
1255
1256 m_editedPoint = aPoint;
1257}
1258
1259
1261{
1262 bool isRuleArea = false;
1263
1264 if( m_editPoints )
1265 isRuleArea = m_editPoints->GetParent()->Type() == SCH_RULE_AREA_T;
1266
1268 || !( m_editPoints->GetParent()->Type() == SCH_SHAPE_T || isRuleArea ) )
1269 {
1270 return false;
1271 }
1272
1273 SCH_SHAPE* shape = static_cast<SCH_SHAPE*>( m_editPoints->GetParent() );
1274
1275 if( shape->GetPolyShape().IsEmpty() )
1276 return false;
1277
1278 SHAPE_LINE_CHAIN& poly = shape->GetPolyShape().Outline( 0 );
1279
1280 if( m_editPoints->GetParent()->Type() == SCH_SHAPE_T && poly.GetPointCount() <= 2 )
1281 return false;
1282 if( m_editPoints->GetParent()->Type() == SCH_RULE_AREA_T && poly.GetPointCount() <= 3 )
1283 return false;
1284
1285 for( const VECTOR2I& pt : poly.CPoints() )
1286 {
1287 if( pt == m_editedPoint->GetPosition() )
1288 return true;
1289 }
1290
1291 return false;
1292}
1293
1294
1296{
1297 if( !m_editPoints
1298 || !( m_editPoints->GetParent()->Type() == SCH_SHAPE_T
1299 || m_editPoints->GetParent()->Type() == SCH_RULE_AREA_T ) )
1300 {
1301 return false;
1302 }
1303
1304 SCH_SHAPE* shape = static_cast<SCH_SHAPE*>( m_editPoints->GetParent() );
1305
1306 if( shape->GetShape() != SHAPE_T::POLY )
1307 return false;
1308
1309 VECTOR2I cursorPos = getViewControls()->GetCursorPosition( false );
1310 double threshold = getView()->ToWorld( EDIT_POINT::POINT_SIZE );
1311
1312 return shape->HitTest( cursorPos, (int) threshold );
1313}
1314
1315
1317{
1318 if( !m_editPoints
1319 || !( m_editPoints->GetParent()->Type() == SCH_SHAPE_T
1320 || m_editPoints->GetParent()->Type() == SCH_RULE_AREA_T ) )
1321 {
1322 return 0;
1323 }
1324
1325 SCH_SHAPE* shape = static_cast<SCH_SHAPE*>( m_editPoints->GetParent() );
1326 SHAPE_LINE_CHAIN& poly = shape->GetPolyShape().Outline( 0 );
1327 SCH_COMMIT commit( m_toolMgr );
1328
1329 commit.Modify( shape, m_frame->GetScreen() );
1330
1332 int currentMinDistance = INT_MAX;
1333 int closestLineStart = 0;
1334 unsigned numPoints = poly.GetPointCount();
1335
1336 if( !shape->IsClosed() )
1337 numPoints -= 1;
1338
1339 for( unsigned i = 0; i < numPoints; ++i )
1340 {
1341 SEG seg = poly.GetSegment( i );
1342 int distance = seg.Distance( cursor );
1343
1344 if( distance < currentMinDistance )
1345 {
1346 currentMinDistance = distance;
1347 closestLineStart = i;
1348 }
1349 }
1350
1351 poly.Insert( closestLineStart + 1, cursor );
1352
1353 updateItem( shape, true );
1354 updatePoints();
1355
1356 commit.Push( _( "Add Corner" ) );
1357 return 0;
1358}
1359
1360
1362{
1364 || !m_editPoints->GetParent()->IsType( { SCH_SHAPE_T, SCH_RULE_AREA_T } ) )
1365 {
1366 return 0;
1367 }
1368
1369 SCH_SHAPE* shape = static_cast<SCH_SHAPE*>( m_editPoints->GetParent() );
1370 SHAPE_LINE_CHAIN& poly = shape->GetPolyShape().Outline( 0 );
1371 SCH_COMMIT commit( m_toolMgr );
1372
1373 if( m_editPoints->GetParent()->Type() == SCH_SHAPE_T && poly.GetPointCount() <= 2 )
1374 return 0;
1375 if( m_editPoints->GetParent()->Type() == SCH_RULE_AREA_T && poly.GetPointCount() <= 3 )
1376 return 0;
1377
1378 commit.Modify( shape, m_frame->GetScreen() );
1379
1380 int idx = getEditedPointIndex();
1381 int last = (int) poly.GetPointCount() - 1;
1382
1383 if( idx == 0 && poly.GetPoint( 0 ) == poly.GetPoint( last ) )
1384 {
1385 poly.Remove( idx );
1386 poly.SetPoint( last-1, poly.GetPoint( 0 ) );
1387 }
1388 else
1389 {
1390 poly.Remove( idx );
1391 }
1392
1393 shape->SetHatchingDirty();
1394
1395 setEditedPoint( nullptr );
1396
1397 updateItem( shape, true );
1398 updatePoints();
1399
1400 commit.Push( _( "Remove Corner" ) );
1401 return 0;
1402}
1403
1404
1406{
1407 if( aEvent.Matches( ACTIONS::cycleArcEditMode.MakeEvent() ) )
1408 {
1409 m_arcEditMode = m_frame->eeconfig()->m_Drawing.arc_edit_mode;
1411 }
1412 else
1413 {
1415 }
1416
1417 m_frame->eeconfig()->m_Drawing.arc_edit_mode = m_arcEditMode;
1418
1419 return 0;
1420}
1421
1422
1424{
1425 updatePoints();
1426 return 0;
1427}
1428
1429
ARC_EDIT_MODE
Settings for arc editing.
@ KEEP_CENTER_ADJUST_ANGLE_RADIUS
When editing endpoints, the angle and radius are adjusted.
constexpr EDA_IU_SCALE schIUScale
Definition base_units.h:114
constexpr double ARC_LOW_DEF_MM
Definition base_units.h:118
BOX2< VECTOR2I > BOX2I
Definition box2.h:922
static TOOL_ACTION cycleArcEditMode
Definition actions.h:273
static TOOL_ACTION pointEditorArcKeepCenter
Definition actions.h:274
static TOOL_ACTION pointEditorArcKeepRadius
Definition actions.h:276
static TOOL_ACTION activatePointEditor
Definition actions.h:272
static TOOL_ACTION pointEditorArcKeepEndpoint
Definition actions.h:275
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.
BITMAP_POINT_EDIT_BEHAVIOR(SCH_BITMAP &aBitmap)
void UpdatePoints(EDIT_POINTS &aPoints) override
Update the list of the edit points for the item.
static constexpr BOX2< VECTOR2I > ByCorners(const VECTOR2I &aCorner1, const VECTOR2I &aCorner2)
Definition box2.h:70
constexpr const Vec GetCenter() const
Definition box2.h:230
constexpr coord_type GetLeft() const
Definition box2.h:228
constexpr coord_type GetRight() const
Definition box2.h:217
constexpr coord_type GetTop() const
Definition box2.h:229
constexpr coord_type GetBottom() const
Definition box2.h:222
Represent a set of changes (additions, deletions or modifications) of a data model (e....
Definition commit.h:72
bool Empty() const
Definition commit.h:137
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:106
EDIT_CONSTRAINT for a EDIT_LINE, that constrains the line to move perpendicular to the line itself.
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
virtual bool IsType(const std::vector< KICAD_T > &aScanTypes) const
Check whether the item is one of the listed types.
Definition eda_item.h:192
bool IsNew() const
Definition eda_item.h:124
void SetStartX(int x)
Definition eda_shape.h:191
void SetEndY(int aY)
Definition eda_shape.h:226
void SetStartY(int y)
Definition eda_shape.h:184
SHAPE_POLY_SET & GetPolyShape()
Definition eda_shape.h:337
SHAPE_T GetShape() const
Definition eda_shape.h:168
void SetEndX(int aX)
Definition eda_shape.h:233
const VECTOR2I & GetEnd() const
Return the ending point of the graphic.
Definition eda_shape.h:215
bool IsClosed() const
void SetEnd(const VECTOR2I &aEnd)
Definition eda_shape.h:219
wxString SHAPE_T_asString() const
void SetHatchingDirty()
Definition eda_shape.h:147
int GetCornerRadius() const
void SetConstraint(EDIT_CONSTRAINT< EDIT_LINE > *aConstraint)
Set a constraint for and 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:48
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:80
int GetY() const
Return Y coordinate of an EDIT_POINT.
Definition edit_points.h:96
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:72
int GetX() const
Return X coordinate of an EDIT_POINT.
Definition edit_points.h:88
void SetDrawCircle(bool aDrawCircle=true)
static const TOOL_EVENT ClearedEvent
Definition actions.h:348
static const TOOL_EVENT SelectedEvent
Definition actions.h:346
static const TOOL_EVENT SelectedItemsModified
Selected items were moved, this can be very high frequency on the canvas, use with care.
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:66
virtual void Add(VIEW_ITEM *aItem, int aDrawPriority=-1)
Add a VIEW_ITEM to the view.
Definition view.cpp:298
virtual void Remove(VIEW_ITEM *aItem)
Remove a VIEW_ITEM from the view.
Definition view.cpp:341
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:1685
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:467
Define a library symbol object.
Definition lib_symbol.h:85
std::vector< SCH_PIN * > GetGraphicalPins(int aUnit=0, int aBodyStyle=0) const
Graphical pins: Return schematic pin objects as drawn (unexpanded), filtered by unit/body.
void 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)
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
void UpdatePoints(EDIT_POINTS &aPoints) override
Update the list of the edit points for the item.
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:88
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:40
virtual void Push(const wxString &aMessage=wxT("A commit"), int aCommitFlags=0) override
Execute the changes.
virtual void Revert() override
Revert the commit by restoring the modified items state.
Base class for any item which can be embedded within the SCHEMATIC container class,...
Definition sch_item.h:167
SCHEMATIC * Schematic() const
Search the item hierarchy to find a SCHEMATIC.
Definition sch_item.cpp:217
Segment description base class to describe items which have 2 end points (track, wire,...
Definition sch_line.h:42
VECTOR2I GetEndPoint() const
Definition sch_line.h:144
VECTOR2I GetStartPoint() const
Definition sch_line.h:139
void updatePoints()
Update which point is being edited.
void Reset(RESET_REASON aReason) override
Bring the tool to a known, initial state.
void setEditedPoint(EDIT_POINT *aPoint)
Return true if aPoint is the currently modified point.
bool Init() override
Init() is called once upon a registration of the tool.
ARC_EDIT_MODE m_arcEditMode
Re-entrancy guards.
void updateParentItem(bool aSnapToGrid, SCH_COMMIT &aCommit) const
< Update item's points with edit points.
void updateEditedPoint(const TOOL_EVENT &aEvent)
Clear references to the points.
bool addCornerCondition(const SELECTION &aSelection)
std::unique_ptr< POINT_EDIT_BEHAVIOR > m_editBehavior
EDIT_POINT * m_editedPoint
int modifiedSelection(const TOOL_EVENT &aEvent)
int Main(const TOOL_EVENT &aEvent)
int getEditedPointIndex() const
std::shared_ptr< EDIT_POINTS > m_editPoints
int clearEditedPoints(const TOOL_EVENT &aEvent)
Set the current point being edited. NULL means none.
bool removeCornerCondition(const SELECTION &aSelection)
bool m_inPointEditor
Currently available edit points.
void setTransitions() override
This method is meant to be overridden in order to specify handlers for events.
void makePointsAndBehavior(EDA_ITEM *aItem)
Currently edited point, NULL if there is none.
std::unique_ptr< KIGFX::PREVIEW::ANGLE_ITEM > m_angleItem
Current item-specific edit behavior.
int changeArcEditMode(const TOOL_EVENT &aEvent)
int removeCorner(const TOOL_EVENT &aEvent)
int addCorner(const TOOL_EVENT &aEvent)
TOOL_ACTION handlers.
void SetPosition(const VECTOR2I &aPos) override
Definition sch_shape.h:86
VECTOR2I GetCenter() const
Definition sch_shape.h:88
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:85
Sheet symbol placed in a schematic, and is the entry point for a sub schematic.
Definition sch_sheet.h:47
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:42
int Distance(const SEG &aSeg) const
Compute minimum Euclidean distance to segment aSeg.
Definition seg.cpp:673
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:177
int Size() const
Returns the number of selected parts.
Definition selection.h:121
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.
void UpdatePoints(EDIT_POINTS &aPoints) override
Update the list of the edit points for the item.
SHEET_POINT_EDIT_BEHAVIOR(SCH_SHEET &aSheet)
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.
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.
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 UpdatePoints(EDIT_POINTS &aPoints) override
Update the list of the edit points for the item.
TEXTBOX_POINT_EDIT_BEHAVIOR(SCH_TEXTBOX &aTextbox)
SCH_BASE_FRAME * getEditFrame() const
Definition tool_base.h:186
KIGFX::VIEW_CONTROLS * getViewControls() const
Definition tool_base.cpp:44
KIGFX::VIEW * getView() const
Definition tool_base.cpp:38
Generic, UI-independent tool event.
Definition tool_event.h:171
bool DisableGridSnapping() const
Definition tool_event.h:371
bool Matches(const TOOL_EVENT &aEvent) const
Test whether two events match in terms of category & action or command.
Definition tool_event.h:392
const VECTOR2D Position() const
Return mouse cursor position in world coordinates.
Definition tool_event.h:293
bool IsDrag(int aButtonMask=BUT_ANY) const
Definition tool_event.h:315
const VECTOR2D DragOrigin() const
Return the point where dragging has started.
Definition tool_event.h:299
T Parameter() const
Return a parameter assigned to the event.
Definition tool_event.h:473
bool IsMotion() const
Definition tool_event.h:330
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))
T EuclideanNorm() const
Compute the Euclidean norm of the vector, which is defined as sqrt(x ** 2 + y ** 2).
Definition vector2d.h:283
@ ARROW
Definition cursors.h:46
#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.
@ RECTANGLE
Use RECTANGLE instead of RECT to avoid collision in a Windows header.
Definition eda_shape.h:46
@ FRAME_SCH_SYMBOL_EDITOR
Definition frame_type.h:35
@ GRID_GRAPHICS
Definition grid_helper.h:51
@ LAYER_NOTES
Definition layer_ids.h:466
#define UNIMPLEMENTED_FOR(type)
Definition macros.h:96
constexpr int Mils2IU(const EDA_IU_SCALE &aIuScale, int mils)
Definition eda_units.h:166
std::vector< SEG > GetSegsInDirection(const BOX2I &aBox, DIRECTION_45::Directions aDir)
Get the segments of a box that are in the given direction.
EDA_ANGLE abs(const EDA_ANGLE &aAngle)
Definition eda_angle.h:400
@ RECT_RIGHT
@ RECT_LEFT
@ RECT_BOT
@ RECT_TOP
@ 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
@ RECT_BOT
@ RECT_TOP
TABLECELL_POINTS
@ ROW_HEIGHT
@ COL_WIDTH
static const std::vector< KICAD_T > pointEditorTypes
@ LINE_START
@ LINE_END
REFIMAGE_POINTS
@ REFIMG_ORIGIN
@ ARC_START
@ ARC_END
@ ARC_CENTER
std::optional< VECTOR2I > OPT_VECTOR2I
Definition seg.h:39
Utility functions for working with shapes.
@ MD_SHIFT
Definition tool_event.h:143
@ BUT_LEFT
Definition tool_event.h:132
@ SCH_LINE_T
Definition typeinfo.h:165
@ SCH_TABLECELL_T
Definition typeinfo.h:168
@ SCH_SHEET_T
Definition typeinfo.h:177
@ SCH_SHAPE_T
Definition typeinfo.h:151
@ SCH_RULE_AREA_T
Definition typeinfo.h:172
@ SCH_ITEM_LOCATE_GRAPHIC_LINE_T
Definition typeinfo.h:190
@ SCH_BITMAP_T
Definition typeinfo.h:166
@ SCH_TEXTBOX_T
Definition typeinfo.h:154
constexpr int sign(T val)
Definition util.h:145
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:695