KiCad PCB EDA Suite
Loading...
Searching...
No Matches
pl_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 <functional>
22using namespace std::placeholders;
23
24#include <wx/log.h>
25#include <fmt/format.h>
26
27#include <tool/tool_manager.h>
28#include <tool/actions.h>
29#include <view/view_controls.h>
32#include <confirm.h>
33#include <bitmaps.h>
34#include <status_popup.h>
37#include "pl_editor_frame.h"
38#include "pl_point_editor.h"
39#include "properties_frame.h"
41
42// Few constants to avoid using bare numbers for point indices
47
48
53
54
56{
57public:
58 static std::shared_ptr<EDIT_POINTS> Make( EDA_ITEM* aItem )
59 {
60 std::shared_ptr<EDIT_POINTS> points = std::make_shared<EDIT_POINTS>( aItem );
61
62 if( !aItem )
63 return points;
64
65 // Generate list of edit points based on the item type
66 switch( aItem->Type() )
67 {
68 case WSG_LINE_T:
69 {
70 DS_DRAW_ITEM_LINE* line = static_cast<DS_DRAW_ITEM_LINE*>( aItem );
71 points->AddPoint( line->GetStart() );
72 points->AddPoint( line->GetEnd() );
73 break;
74 }
75
76 case WSG_RECT_T:
77 {
78 DS_DRAW_ITEM_RECT* rect = static_cast<DS_DRAW_ITEM_RECT*>( aItem );
79 VECTOR2I topLeft = rect->GetStart();
80 VECTOR2I botRight = rect->GetEnd();
81
82 if( topLeft.y > botRight.y )
83 std::swap( topLeft.y, botRight.y );
84
85 if( topLeft.x > botRight.x )
86 std::swap( topLeft.x, botRight.x );
87
88 points->AddPoint( topLeft );
89 points->AddPoint( VECTOR2I( botRight.x, topLeft.y ) );
90 points->AddPoint( VECTOR2I( topLeft.x, botRight.y ) );
91 points->AddPoint( botRight );
92 break;
93 }
94
95 default:
96 points.reset();
97 break;
98 }
99
100 return points;
101 }
102
103private:
105};
106
107
109 TOOL_INTERACTIVE( "plEditor.PointEditor" ),
110 m_frame( nullptr ),
111 m_selectionTool( nullptr ),
112 m_editedPoint( nullptr )
113{
114}
115
116
118{
119 if( aReason == MODEL_RELOAD )
120 {
121 // Init variables used by every drawing tool
123 }
124
125 if( KIGFX::VIEW* view = getView() )
126 {
127 if( m_angleItem )
128 view->Remove( m_angleItem.get() );
129
130 if( m_editPoints )
131 view->Remove( m_editPoints.get() );
132 }
133
134 m_angleItem.reset();
135 m_editPoints.reset();
136}
137
138
140{
143 return true;
144}
145
146
148{
149 EDIT_POINT* point = m_editedPoint;
150
151 if( aEvent.IsMotion() )
152 point = m_editPoints->FindPoint( aEvent.Position(), getView() );
153 else if( aEvent.IsDrag( BUT_LEFT ) )
154 point = m_editPoints->FindPoint( aEvent.DragOrigin(), getView() );
155 else
156 point = m_editPoints->FindPoint( getViewControls()->GetCursorPosition(), getView() );
157
158 if( m_editedPoint != point )
159 setEditedPoint( point );
160}
161
162
164{
166 const PL_SELECTION& selection = m_selectionTool->GetSelection();
167
168 if( selection.Size() != 1 || !selection.Front()->IsType( { WSG_LINE_T, WSG_RECT_T } ) )
169 return 0;
170
171 EDA_ITEM* item = (EDA_ITEM*) selection.Front();
172
173 // Wait till drawing tool is done
174 if( item->IsNew() )
175 return 0;
176
177 Activate();
178 // Must be done after Activate() so that it gets set into the correct context
179 controls->ShowCursor( true );
180
182
183 if( !m_editPoints )
184 return 0;
185
186 m_angleItem = std::make_unique<KIGFX::PREVIEW::ANGLE_ITEM>( m_editPoints );
187
188 getView()->Add( m_editPoints.get() );
189 getView()->Add( m_angleItem.get() );
190 setEditedPoint( nullptr );
191 updateEditedPoint( aEvent );
192 bool inDrag = false;
193 bool modified = false;
194
195 // Main loop: keep receiving events
196 while( TOOL_EVENT* evt = Wait() )
197 {
198 if( !m_editPoints || evt->IsSelectionEvent() )
199 break;
200
201 if ( !inDrag )
202 updateEditedPoint( *evt );
203
204 if( evt->IsDrag( BUT_LEFT ) && m_editedPoint )
205 {
206 if( !inDrag )
207 {
208 try
209 {
210 m_frame->SaveCopyInUndoList();
211 }
212 catch( const fmt::format_error& exc )
213 {
214 wxLogWarning( wxS( "Exception \"%s\" serializing string ocurred." ),
215 exc.what() );
216 return 1;
217 }
218
219 controls->ForceCursorPosition( false );
220 inDrag = true;
221 modified = true;
222 }
223
224 m_editedPoint->SetPosition( controls->GetCursorPosition( !evt->DisableGridSnapping() ) );
225
226 updateItem();
227 updatePoints();
228 }
229
230 else if( inDrag && evt->IsMouseUp( BUT_LEFT ) )
231 {
232 controls->SetAutoPan( false );
233 inDrag = false;
234 }
235
236 else if( evt->IsCancelInteractive() || evt->IsActivate() )
237 {
238 if( inDrag ) // Restore the last change
239 {
240 m_frame->RollbackFromUndo();
241 inDrag = false;
242 modified = false;
243 }
244 else if( evt->IsCancelInteractive() )
245 {
246 break;
247 }
248
249 if( evt->IsActivate() && !evt->IsMoveTool() )
250 break;
251 }
252 else
253 {
254 evt->SetPassEvent();
255 }
256
257 controls->SetAutoPan( inDrag );
258 controls->CaptureCursor( inDrag );
259 }
260
261 controls->SetAutoPan( false );
262 controls->CaptureCursor( false );
263
264 if( m_editPoints )
265 {
266 getView()->Remove( m_editPoints.get() );
267 getView()->Remove( m_angleItem.get() );
268
269 if( modified )
270 m_frame->OnModify();
271
272 m_editPoints.reset();
273 m_angleItem.reset();
274 m_frame->GetCanvas()->Refresh();
275 }
276
277 return 0;
278}
279
280
281void pinEditedCorner( int editedPointIndex, int minWidth, int minHeight, VECTOR2I& topLeft,
282 VECTOR2I& topRight, VECTOR2I& botLeft, VECTOR2I& botRight )
283{
284 switch( editedPointIndex )
285 {
286 case RECT_TOPLEFT:
287 // pin edited point within opposite corner
288 topLeft.x = std::min( topLeft.x, botRight.x - minWidth );
289 topLeft.y = std::min( topLeft.y, botRight.y - minHeight );
290
291 // push edited point edges to adjacent corners
292 topRight.y = topLeft.y;
293 botLeft.x = topLeft.x;
294
295 break;
296
297 case RECT_TOPRIGHT:
298 // pin edited point within opposite corner
299 topRight.x = std::max( topRight.x, botLeft.x + minWidth );
300 topRight.y = std::min( topRight.y, botLeft.y - minHeight );
301
302 // push edited point edges to adjacent corners
303 topLeft.y = topRight.y;
304 botRight.x = topRight.x;
305
306 break;
307
308 case RECT_BOTLEFT:
309 // pin edited point within opposite corner
310 botLeft.x = std::min( botLeft.x, topRight.x - minWidth );
311 botLeft.y = std::max( botLeft.y, topRight.y + minHeight );
312
313 // push edited point edges to adjacent corners
314 botRight.y = botLeft.y;
315 topLeft.x = botLeft.x;
316
317 break;
318
319 case RECT_BOTRIGHT:
320 // pin edited point within opposite corner
321 botRight.x = std::max( botRight.x, topLeft.x + minWidth );
322 botRight.y = std::max( botRight.y, topLeft.y + minHeight );
323
324 // push edited point edges to adjacent corners
325 botLeft.y = botRight.y;
326 topRight.x = botRight.x;
327
328 break;
329 }
330}
331
332
334{
335 EDA_ITEM* item = m_editPoints->GetParent();
336
337 if( !item )
338 return;
339
340 DS_DATA_ITEM* dataItem = static_cast<DS_DRAW_ITEM_BASE*>( item )->GetPeer();
341
342 // The current item is perhaps not the main item if we have a set of repeated items.
343 // So we change the coordinate references in dataItem using move vectors of the start and
344 // end points that are the same for each repeated item.
345
346 switch( item->Type() )
347 {
348 case WSG_LINE_T:
349 {
350 DS_DRAW_ITEM_LINE* line = static_cast<DS_DRAW_ITEM_LINE*>( item );
351
352 VECTOR2I move_startpoint = m_editPoints->Point( LINE_START ).GetPosition() - line->GetStart();
353 VECTOR2I move_endpoint = m_editPoints->Point( LINE_END ).GetPosition() - line->GetEnd();
354
355 dataItem->MoveStartPointToIU( dataItem->GetStartPosIU() + move_startpoint );
356 dataItem->MoveEndPointToIU( dataItem->GetEndPosIU() + move_endpoint );
357
358 for( DS_DRAW_ITEM_BASE* draw_item : dataItem->GetDrawItems() )
359 {
360 DS_DRAW_ITEM_LINE* draw_line = static_cast<DS_DRAW_ITEM_LINE*>( draw_item );
361
362 draw_line->SetStart( draw_line->GetStart() + move_startpoint );
363 draw_line->SetEnd( draw_line->GetEnd() + move_endpoint );
364 getView()->Update( draw_item );
365 }
366
367 break;
368 }
369
370 case WSG_RECT_T:
371 {
372 DS_DRAW_ITEM_RECT* rect = static_cast<DS_DRAW_ITEM_RECT*>( item );
373 VECTOR2I topLeft = m_editPoints->Point( RECT_TOPLEFT ).GetPosition();
374 VECTOR2I topRight = m_editPoints->Point( RECT_TOPRIGHT ).GetPosition();
375 VECTOR2I botLeft = m_editPoints->Point( RECT_BOTLEFT ).GetPosition();
376 VECTOR2I botRight = m_editPoints->Point( RECT_BOTRIGHT ).GetPosition();
377
379 drawSheetIUScale.MilsToIU( 1 ),
380 topLeft, topRight, botLeft, botRight );
381
382 VECTOR2I start_delta, end_delta;
383
384 if( rect->GetStart().y > rect->GetEnd().y )
385 {
386 start_delta.y = botRight.y - rect->GetStart().y;
387 end_delta.y = topLeft.y - rect->GetEnd().y;
388 }
389 else
390 {
391 start_delta.y = topLeft.y - rect->GetStart().y;
392 end_delta.y = botRight.y - rect->GetEnd().y;
393 }
394
395 if( rect->GetStart().x > rect->GetEnd().x )
396 {
397 start_delta.x = botRight.x - rect->GetStart().x;
398 end_delta.x = topLeft.x - rect->GetEnd().x;
399 }
400 else
401 {
402 start_delta.x = topLeft.x - rect->GetStart().x;
403 end_delta.x = botRight.x - rect->GetEnd().x;
404 }
405
406 dataItem->MoveStartPointToIU( dataItem->GetStartPosIU() + start_delta );
407 dataItem->MoveEndPointToIU( dataItem->GetEndPosIU() + end_delta );
408
409 for( DS_DRAW_ITEM_BASE* draw_item : dataItem->GetDrawItems() )
410 {
411 DS_DRAW_ITEM_RECT* draw_rect = static_cast<DS_DRAW_ITEM_RECT*>( draw_item );
412
413 draw_rect->SetStart( draw_rect->GetStart() + start_delta );
414 draw_rect->SetEnd( draw_rect->GetEnd() + end_delta );
415 getView()->Update( draw_item );
416 }
417
418 break;
419 }
420
421 default:
422 break;
423 }
424
425 m_frame->SetMsgPanel( item );
426
427 // The Properties frame will be updated. Avoid flicker during update:
428 m_frame->GetPropertiesFrame()->Freeze();
429 m_frame->GetPropertiesFrame()->CopyPrmsFromItemToPanel( dataItem );
430 m_frame->GetPropertiesFrame()->Thaw();
431}
432
433
435{
436 if( !m_editPoints )
437 return;
438
439 EDA_ITEM* item = m_editPoints->GetParent();
440
441 if( !item )
442 return;
443
444 switch( item->Type() )
445 {
446 case WSG_LINE_T:
447 {
448 DS_DRAW_ITEM_LINE* line = static_cast<DS_DRAW_ITEM_LINE*>( item );
449
450 m_editPoints->Point( LINE_START ).SetPosition( line->GetStart() );
451 m_editPoints->Point( LINE_END ).SetPosition( line->GetEnd() );
452 break;
453 }
454
455 case WSG_RECT_T:
456 {
457 DS_DRAW_ITEM_RECT* rect = static_cast<DS_DRAW_ITEM_RECT*>( item );
458 VECTOR2I topLeft = rect->GetPosition();
459 VECTOR2I botRight = rect->GetEnd();
460
461 if( topLeft.y > botRight.y )
462 std::swap( topLeft.y, botRight.y );
463
464 if( topLeft.x > botRight.x )
465 std::swap( topLeft.x, botRight.x );
466
467 m_editPoints->Point( RECT_TOPLEFT ).SetPosition( (VECTOR2I) topLeft );
468 m_editPoints->Point( RECT_TOPRIGHT ).SetPosition( VECTOR2I( botRight.x, topLeft.y ) );
469 m_editPoints->Point( RECT_BOTLEFT ).SetPosition( VECTOR2I( topLeft.x, botRight.y ) );
470 m_editPoints->Point( RECT_BOTRIGHT ).SetPosition( (VECTOR2I) botRight );
471 break;
472 }
473
474 default:
475 break;
476 }
477
478 getView()->Update( m_editPoints.get() );
479 getView()->Update( m_angleItem.get() );
480}
481
482
484{
486
487 if( aPoint )
488 {
489 m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::ARROW );
490 controls->ForceCursorPosition( true, aPoint->GetPosition() );
491 controls->ShowCursor( true );
492 }
493 else
494 {
495 if( m_frame->ToolStackIsEmpty() )
496 controls->ShowCursor( false );
497
498 controls->ForceCursorPosition( false );
499 }
500
501 m_editedPoint = aPoint;
502}
503
504
506{
507 updatePoints();
508 return 0;
509}
510
511
518
519
constexpr EDA_IU_SCALE drawSheetIUScale
Definition base_units.h:122
static TOOL_ACTION activatePointEditor
Definition actions.h:267
Drawing sheet structure type definitions.
void MoveStartPointToIU(const VECTOR2I &aPosition)
Move the starting point of the item to a new position.
void MoveEndPointToIU(const VECTOR2I &aPosition)
Move the ending point of the item to a new position.
const VECTOR2I GetStartPosIU(int ii=0) const
const VECTOR2I GetEndPosIU(int ii=0) const
const std::vector< DS_DRAW_ITEM_BASE * > & GetDrawItems() const
Base class to handle basic graphic items.
void SetEnd(const VECTOR2I &aPos) override
void SetStart(const VECTOR2I &aPos)
const VECTOR2I & GetStart() const
const VECTOR2I & GetEnd() const
Non filled rectangle with thick segment.
const VECTOR2I & GetEnd() const
const VECTOR2I & GetStart() const
VECTOR2I GetPosition() const override
void SetEnd(const VECTOR2I &aPos) override
void SetStart(const VECTOR2I &aPos)
A base class for most all the KiCad significant classes used in schematics and boards.
Definition eda_item.h:96
KICAD_T Type() const
Returns the type of object.
Definition eda_item.h:108
virtual bool IsType(const std::vector< KICAD_T > &aScanTypes) const
Check whether the item is one of the listed types.
Definition eda_item.h:202
bool IsNew() const
Definition eda_item.h:129
static std::shared_ptr< EDIT_POINTS > Make(EDA_ITEM *aItem)
Represent a single point that can be used for modifying items.
Definition edit_points.h:44
virtual VECTOR2I GetPosition() const
Return coordinates of an EDIT_POINT.
Definition edit_points.h:68
static const TOOL_EVENT SelectedEvent
Definition actions.h:341
static const TOOL_EVENT SelectedItemsModified
Selected items were moved, this can be very high frequency on the canvas, use with care.
Definition actions.h:348
An interface for classes handling user events controlling the view behavior such as zooming,...
virtual void CaptureCursor(bool aEnabled)
Force the cursor to stay within the drawing panel area.
virtual void ForceCursorPosition(bool aEnabled, const VECTOR2D &aPosition=VECTOR2D(0, 0))
Place the cursor immediately at a given point.
virtual void ShowCursor(bool aEnabled)
Enable or disables display of cursor.
VECTOR2D GetCursorPosition() const
Return the current cursor position in world coordinates.
virtual void SetAutoPan(bool aEnabled)
Turn on/off auto panning (this feature is used when there is a tool active (eg.
Hold a (potentially large) number of VIEW_ITEMs and renders them on a graphics device provided by the...
Definition view.h:63
virtual void Add(VIEW_ITEM *aItem, int aDrawPriority=-1)
Add a VIEW_ITEM to the view.
Definition view.cpp:300
virtual void Remove(VIEW_ITEM *aItem)
Remove a VIEW_ITEM from the view.
Definition view.cpp:404
virtual void Update(const VIEW_ITEM *aItem, int aUpdateFlags) const
For dynamic VIEWs, inform the associated VIEW that the graphical representation of this item has chan...
Definition view.cpp:1835
void setTransitions() override
This method is meant to be overridden in order to specify handlers for events.
PL_EDITOR_FRAME * m_frame
PL_SELECTION_TOOL * m_selectionTool
Currently edited point, NULL if there is none.
int modifiedSelection(const TOOL_EVENT &aEvent)
int getEditedPointIndex() const
void updateItem() const
< Update item's points with edit points.
void Reset(RESET_REASON aReason) override
Bring the tool to a known, initial state.
void updateEditedPoint(const TOOL_EVENT &aEvent)
Set the current point being edited. NULL means none.
EDIT_POINT * m_editedPoint
Currently available edit points.
bool Init() override
Init() is called once upon a registration of the tool.
int Main(const TOOL_EVENT &aEvent)
void updatePoints()
Update which point is being edited.
std::unique_ptr< KIGFX::PREVIEW::ANGLE_ITEM > m_angleItem
void setEditedPoint(EDIT_POINT *aPoint)
Return true if aPoint is the currently modified point.
std::shared_ptr< EDIT_POINTS > m_editPoints
EDA_ITEM * Front() const
Definition selection.h:173
int Size() const
Returns the number of selected parts.
Definition selection.h:117
T * getEditFrame() const
Return the application window object, casted to requested user type.
Definition tool_base.h:182
KIGFX::VIEW_CONTROLS * getViewControls() const
Return the instance of VIEW_CONTROLS object used in the application.
Definition tool_base.cpp:40
TOOL_MANAGER * m_toolMgr
Definition tool_base.h:220
KIGFX::VIEW * getView() const
Returns the instance of #VIEW object used in the application.
Definition tool_base.cpp:34
RESET_REASON
Determine the reason of reset for a tool.
Definition tool_base.h:74
@ MODEL_RELOAD
Model changes (the sheet for a schematic)
Definition tool_base.h:76
Generic, UI-independent tool event.
Definition tool_event.h:167
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
bool IsMotion() const
Definition tool_event.h:326
void Go(int(T::*aStateFunc)(const TOOL_EVENT &), const TOOL_EVENT_LIST &aConditions=TOOL_EVENT(TC_ANY, TA_ANY))
Define which state (aStateFunc) to go when a certain event arrives (aConditions).
TOOL_INTERACTIVE(TOOL_ID aId, const std::string &aName)
Create a tool with given id & name.
TOOL_EVENT * Wait(const TOOL_EVENT_LIST &aEventList=TOOL_EVENT(TC_ANY, TA_ANY))
Suspend execution of the tool until an event specified in aEventList arrives.
void Activate()
Run the tool.
This file is part of the common library.
@ ARROW
Definition cursors.h:42
void pinEditedCorner(int editedPointIndex, int minWidth, int minHeight, VECTOR2I &topLeft, VECTOR2I &topRight, VECTOR2I &botLeft, VECTOR2I &botRight)
RECTANGLE_POINTS
@ RECT_BOTLEFT
@ RECT_TOPLEFT
@ RECT_TOPRIGHT
@ RECT_BOTRIGHT
@ LINE_START
@ LINE_END
@ BUT_LEFT
Definition tool_event.h:128
@ WSG_LINE_T
Definition typeinfo.h:213
@ WSG_RECT_T
Definition typeinfo.h:214
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:683