KiCad PCB EDA Suite
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 (C) 2019-2021 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 <functional>
26using namespace std::placeholders;
27
28#include <tool/tool_manager.h>
29#include <tool/actions.h>
30#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
44{
46};
47
49{
51};
52
54{
55public:
56 static std::shared_ptr<EDIT_POINTS> Make( EDA_ITEM* aItem )
57 {
58 std::shared_ptr<EDIT_POINTS> points = std::make_shared<EDIT_POINTS>( aItem );
59
60 if( !aItem )
61 return points;
62
63 // Generate list of edit points based on the item type
64 switch( aItem->Type() )
65 {
66 case WSG_LINE_T:
67 {
68 DS_DRAW_ITEM_LINE* line = static_cast<DS_DRAW_ITEM_LINE*>( aItem );
69 points->AddPoint( line->GetStart() );
70 points->AddPoint( line->GetEnd() );
71 break;
72 }
73 case WSG_RECT_T:
74 {
75 DS_DRAW_ITEM_RECT* rect = static_cast<DS_DRAW_ITEM_RECT*>( aItem );
76 VECTOR2I topLeft = rect->GetStart();
77 VECTOR2I botRight = rect->GetEnd();
78
79 if( topLeft.y > botRight.y )
80 std::swap( topLeft.y, botRight.y );
81
82 if( topLeft.x > botRight.x )
83 std::swap( topLeft.x, botRight.x );
84
85 points->AddPoint( topLeft );
86 points->AddPoint( VECTOR2I( botRight.x, topLeft.y ) );
87 points->AddPoint( VECTOR2I( topLeft.x, botRight.y ) );
88 points->AddPoint( botRight );
89 break;
90 }
91 default:
92 points.reset();
93 break;
94 }
95
96 return points;
97 }
98
99private:
101};
102
103
105 TOOL_INTERACTIVE( "plEditor.PointEditor" ),
106 m_frame( nullptr ),
107 m_selectionTool( nullptr ),
108 m_editedPoint( nullptr )
109{
110}
111
112
114{
115 if( aReason == MODEL_RELOAD )
116 {
117 // Init variables used by every drawing tool
118 m_frame = getEditFrame<PL_EDITOR_FRAME>();
119 }
120
121 m_editPoints.reset();
122}
123
124
126{
127 m_frame = getEditFrame<PL_EDITOR_FRAME>();
129 return true;
130}
131
132
134{
135 EDIT_POINT* point = m_editedPoint;
136
137 if( aEvent.IsMotion() )
138 point = m_editPoints->FindPoint( aEvent.Position(), getView() );
139 else if( aEvent.IsDrag( BUT_LEFT ) )
140 point = m_editPoints->FindPoint( aEvent.DragOrigin(), getView() );
141 else
142 point = m_editPoints->FindPoint( getViewControls()->GetCursorPosition(), getView() );
143
144 if( m_editedPoint != point )
145 setEditedPoint( point );
146}
147
148
150{
152 const PL_SELECTION& selection = m_selectionTool->GetSelection();
153
154 if( selection.Size() != 1 || !selection.Front()->IsType( { WSG_LINE_T, WSG_RECT_T } ) )
155 return 0;
156
157 EDA_ITEM* item = (EDA_ITEM*) selection.Front();
158
159 // Wait till drawing tool is done
160 if( item->IsNew() )
161 return 0;
162
163 Activate();
164 // Must be done after Activate() so that it gets set into the correct context
165 controls->ShowCursor( true );
166
168
169 if( !m_editPoints )
170 return 0;
171
172 getView()->Add( m_editPoints.get() );
173 setEditedPoint( nullptr );
174 updateEditedPoint( aEvent );
175 bool inDrag = false;
176 bool modified = false;
177
178 // Main loop: keep receiving events
179 while( TOOL_EVENT* evt = Wait() )
180 {
181 if( !m_editPoints || evt->IsSelectionEvent() )
182 break;
183
184 if ( !inDrag )
185 updateEditedPoint( *evt );
186
187 if( evt->IsDrag( BUT_LEFT ) && m_editedPoint )
188 {
189 if( !inDrag )
190 {
192 controls->ForceCursorPosition( false );
193 inDrag = true;
194 modified = true;
195 }
196
197 m_editedPoint->SetPosition( controls->GetCursorPosition( !evt->DisableGridSnapping() ) );
198
199 updateItem();
200 updatePoints();
201 }
202
203 else if( inDrag && evt->IsMouseUp( BUT_LEFT ) )
204 {
205 controls->SetAutoPan( false );
206 inDrag = false;
207 }
208
209 else if( evt->IsCancelInteractive() || evt->IsActivate() )
210 {
211 if( inDrag ) // Restore the last change
212 {
214 inDrag = false;
215 modified = false;
216 }
217 else if( evt->IsCancelInteractive() )
218 break;
219
220 if( evt->IsActivate() && !evt->IsMoveTool() )
221 break;
222 }
223
224 else
225 evt->SetPassEvent();
226
227 controls->SetAutoPan( inDrag );
228 controls->CaptureCursor( inDrag );
229 }
230
231 controls->SetAutoPan( false );
232 controls->CaptureCursor( false );
233
234 if( m_editPoints )
235 {
236 getView()->Remove( m_editPoints.get() );
237
238 if( modified )
239 m_frame->OnModify();
240
241 m_editPoints.reset();
243 }
244
245 return 0;
246}
247
248
249void pinEditedCorner( int editedPointIndex, int minWidth, int minHeight, VECTOR2I& topLeft,
250 VECTOR2I& topRight, VECTOR2I& botLeft, VECTOR2I& botRight )
251{
252 switch( editedPointIndex )
253 {
254 case RECT_TOPLEFT:
255 // pin edited point within opposite corner
256 topLeft.x = std::min( topLeft.x, botRight.x - minWidth );
257 topLeft.y = std::min( topLeft.y, botRight.y - minHeight );
258
259 // push edited point edges to adjacent corners
260 topRight.y = topLeft.y;
261 botLeft.x = topLeft.x;
262
263 break;
264
265 case RECT_TOPRIGHT:
266 // pin edited point within opposite corner
267 topRight.x = std::max( topRight.x, botLeft.x + minWidth );
268 topRight.y = std::min( topRight.y, botLeft.y - minHeight );
269
270 // push edited point edges to adjacent corners
271 topLeft.y = topRight.y;
272 botRight.x = topRight.x;
273
274 break;
275
276 case RECT_BOTLEFT:
277 // pin edited point within opposite corner
278 botLeft.x = std::min( botLeft.x, topRight.x - minWidth );
279 botLeft.y = std::max( botLeft.y, topRight.y + minHeight );
280
281 // push edited point edges to adjacent corners
282 botRight.y = botLeft.y;
283 topLeft.x = botLeft.x;
284
285 break;
286
287 case RECT_BOTRIGHT:
288 // pin edited point within opposite corner
289 botRight.x = std::max( botRight.x, topLeft.x + minWidth );
290 botRight.y = std::max( botRight.y, topLeft.y + minHeight );
291
292 // push edited point edges to adjacent corners
293 botLeft.y = botRight.y;
294 topRight.x = botRight.x;
295
296 break;
297 }
298}
299
300
302{
303 EDA_ITEM* item = m_editPoints->GetParent();
304
305 if( !item )
306 return;
307
308 DS_DATA_ITEM* dataItem = static_cast<DS_DRAW_ITEM_BASE*>( item )->GetPeer();
309
310 // The current item is perhaps not the main item if we have a set of repeated items.
311 // So we change the coordinate references in dataItem using move vectors of the start and
312 // end points that are the same for each repeated item.
313
314 switch( item->Type() )
315 {
316 case WSG_LINE_T:
317 {
318 DS_DRAW_ITEM_LINE* line = static_cast<DS_DRAW_ITEM_LINE*>( item );
319
320 VECTOR2I move_startpoint = m_editPoints->Point( LINE_START ).GetPosition() - line->GetStart();
321 VECTOR2I move_endpoint = m_editPoints->Point( LINE_END ).GetPosition() - line->GetEnd();
322
323 dataItem->MoveStartPointToUi( dataItem->GetStartPosUi() + move_startpoint );
324 dataItem->MoveEndPointToUi( dataItem->GetEndPosUi() + move_endpoint );
325
326 for( DS_DRAW_ITEM_BASE* draw_item : dataItem->GetDrawItems() )
327 {
328 DS_DRAW_ITEM_LINE* draw_line = static_cast<DS_DRAW_ITEM_LINE*>( draw_item );
329
330 draw_line->SetStart( draw_line->GetStart() + move_startpoint );
331 draw_line->SetEnd( draw_line->GetEnd() + move_endpoint );
332 getView()->Update( draw_item );
333 }
334
335 break;
336 }
337
338 case WSG_RECT_T:
339 {
340 DS_DRAW_ITEM_RECT* rect = static_cast<DS_DRAW_ITEM_RECT*>( item );
341 VECTOR2I topLeft = m_editPoints->Point( RECT_TOPLEFT ).GetPosition();
342 VECTOR2I topRight = m_editPoints->Point( RECT_TOPRIGHT ).GetPosition();
343 VECTOR2I botLeft = m_editPoints->Point( RECT_BOTLEFT ).GetPosition();
344 VECTOR2I botRight = m_editPoints->Point( RECT_BOTRIGHT ).GetPosition();
345
348 topLeft, topRight, botLeft, botRight );
349
350 VECTOR2I start_delta, end_delta;
351
352 if( rect->GetStart().y > rect->GetEnd().y )
353 {
354 start_delta.y = botRight.y - rect->GetStart().y;
355 end_delta.y = topLeft.y - rect->GetEnd().y;
356 }
357 else
358 {
359 start_delta.y = topLeft.y - rect->GetStart().y;
360 end_delta.y = botRight.y - rect->GetEnd().y;
361 }
362
363 if( rect->GetStart().x > rect->GetEnd().x )
364 {
365 start_delta.x = botRight.x - rect->GetStart().x;
366 end_delta.x = topLeft.x - rect->GetEnd().x;
367 }
368 else
369 {
370 start_delta.x = topLeft.x - rect->GetStart().x;
371 end_delta.x = botRight.x - rect->GetEnd().x;
372 }
373
374 dataItem->MoveStartPointToUi( dataItem->GetStartPosUi() + start_delta );
375 dataItem->MoveEndPointToUi( dataItem->GetEndPosUi() + end_delta );
376
377 for( DS_DRAW_ITEM_BASE* draw_item : dataItem->GetDrawItems() )
378 {
379 DS_DRAW_ITEM_RECT* draw_rect = static_cast<DS_DRAW_ITEM_RECT*>( draw_item );
380
381 draw_rect->SetStart( draw_rect->GetStart() + start_delta );
382 draw_rect->SetEnd( draw_rect->GetEnd() + end_delta );
383 getView()->Update( draw_item );
384 }
385
386 break;
387 }
388
389 default:
390 break;
391 }
392
393 m_frame->SetMsgPanel( item );
394
395 // The Properties frame will be updated. Avoid flicker during update:
396 m_frame->GetPropertiesFrame()->Freeze();
398 m_frame->GetPropertiesFrame()->Thaw();
399}
400
401
403{
404 if( !m_editPoints )
405 return;
406
407 EDA_ITEM* item = m_editPoints->GetParent();
408
409 if( !item )
410 return;
411
412 switch( item->Type() )
413 {
414 case WSG_LINE_T:
415 {
416 DS_DRAW_ITEM_LINE* line = static_cast<DS_DRAW_ITEM_LINE*>( item );
417
418 m_editPoints->Point( LINE_START ).SetPosition( line->GetStart() );
419 m_editPoints->Point( LINE_END ).SetPosition( line->GetEnd() );
420 break;
421 }
422
423 case WSG_RECT_T:
424 {
425 DS_DRAW_ITEM_RECT* rect = static_cast<DS_DRAW_ITEM_RECT*>( item );
426 VECTOR2I topLeft = rect->GetPosition();
427 VECTOR2I botRight = rect->GetEnd();
428
429 if( topLeft.y > botRight.y )
430 std::swap( topLeft.y, botRight.y );
431
432 if( topLeft.x > botRight.x )
433 std::swap( topLeft.x, botRight.x );
434
435 m_editPoints->Point( RECT_TOPLEFT ).SetPosition( (VECTOR2I) topLeft );
436 m_editPoints->Point( RECT_TOPRIGHT ).SetPosition( VECTOR2I( botRight.x, topLeft.y ) );
437 m_editPoints->Point( RECT_BOTLEFT ).SetPosition( VECTOR2I( topLeft.x, botRight.y ) );
438 m_editPoints->Point( RECT_BOTRIGHT ).SetPosition( (VECTOR2I) botRight );
439 break;
440 }
441
442 default:
443 break;
444 }
445
446 getView()->Update( m_editPoints.get() );
447}
448
449
451{
453
454 if( aPoint )
455 {
457 controls->ForceCursorPosition( true, aPoint->GetPosition() );
458 controls->ShowCursor( true );
459 }
460 else
461 {
463 controls->ShowCursor( false );
464
465 controls->ForceCursorPosition( false );
466 }
467
468 m_editedPoint = aPoint;
469}
470
471
473{
474 updatePoints();
475 return 0;
476}
477
478
480{
484}
485
486
constexpr EDA_IU_SCALE drawSheetIUScale
Definition: base_units.h:110
static TOOL_ACTION activatePointEditor
Definition: actions.h:172
Drawing sheet structure type definitions.
Definition: ds_data_item.h:96
const VECTOR2I GetStartPosUi(int ii=0) const
void MoveEndPointToUi(const VECTOR2I &aPosition)
Move the ending point of the item to a new position.
void MoveStartPointToUi(const VECTOR2I &aPosition)
Move the starting point of the item to a new position.
const VECTOR2I GetEndPosUi(int ii=0) const
const std::vector< DS_DRAW_ITEM_BASE * > & GetDrawItems() const
Definition: ds_data_item.h:110
Base class to handle basic graphic items.
Definition: ds_draw_item.h:59
void SetEnd(const VECTOR2I &aPos) override
Definition: ds_draw_item.h:136
void SetStart(const VECTOR2I &aPos)
Definition: ds_draw_item.h:134
const VECTOR2I & GetStart() const
Definition: ds_draw_item.h:133
const VECTOR2I & GetEnd() const
Definition: ds_draw_item.h:135
Non filled rectangle with thick segment.
Definition: ds_draw_item.h:208
const VECTOR2I & GetEnd() const
Definition: ds_draw_item.h:223
const VECTOR2I & GetStart() const
Definition: ds_draw_item.h:221
VECTOR2I GetPosition() const override
Definition: ds_draw_item.h:226
void SetEnd(const VECTOR2I &aPos) override
Definition: ds_draw_item.h:224
void SetStart(const VECTOR2I &aPos)
Definition: ds_draw_item.h:222
void SetMsgPanel(const std::vector< MSG_PANEL_ITEM > &aList)
Clear the message panel and populates it with the contents of aList.
void SetCurrentCursor(KICURSOR aCursor)
Set the current cursor shape for this panel.
virtual void Refresh(bool aEraseBackground=true, const wxRect *aRect=nullptr) override
Update the board display after modifying it by a python script (note: it is automatically called by a...
A base class for most all the KiCad significant classes used in schematics and boards.
Definition: eda_item.h:85
KICAD_T Type() const
Returns the type of object.
Definition: eda_item.h:97
virtual bool IsType(const std::vector< KICAD_T > &aScanTypes) const
Check whether the item is one of the listed types.
Definition: eda_item.h:183
bool IsNew() const
Definition: eda_item.h:103
static std::shared_ptr< EDIT_POINTS > Make(EDA_ITEM *aItem, SCH_BASE_FRAME *frame)
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:48
virtual void SetPosition(const VECTOR2I &aPosition)
Set new coordinates for an EDIT_POINT.
Definition: edit_points.h:107
virtual VECTOR2I GetPosition() const
Return coordinates of an EDIT_POINT.
Definition: edit_points.h:71
static const TOOL_EVENT SelectedEvent
Definition: actions.h:206
static const TOOL_EVENT SelectedItemsModified
Selected items were moved, this can be very high frequency on the canvas, use with care.
Definition: actions.h:211
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.
virtual void Add(VIEW_ITEM *aItem, int aDrawPriority=-1)
Add a VIEW_ITEM to the view.
Definition: view.cpp:316
virtual void Remove(VIEW_ITEM *aItem)
Remove a VIEW_ITEM from the view.
Definition: view.cpp:346
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:1574
void OnModify() override
Must be called after a change in order to set the "modify" flag.
void RollbackFromUndo()
Apply the last command in Undo List without stacking a Redo.
void SaveCopyInUndoList()
Save a copy of the description (in a S expr string) for Undo/redo commands.
PROPERTIES_FRAME * GetPropertiesFrame()
PL_DRAW_PANEL_GAL * GetCanvas() const override
Return a pointer to GAL-based canvas of given EDA draw frame.
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.
void setEditedPoint(EDIT_POINT *aPoint)
Return true if aPoint is the currently modified point.
std::shared_ptr< EDIT_POINTS > m_editPoints
PL_SELECTION & GetSelection()
Return the set of currently selected items.
void CopyPrmsFromItemToPanel(DS_DATA_ITEM *aItem)
EDA_ITEM * Front() const
Definition: selection.h:206
int Size() const
Returns the number of selected parts.
Definition: selection.h:113
bool ToolStackIsEmpty()
Definition: tools_holder.h:128
KIGFX::VIEW_CONTROLS * getViewControls() const
Return the instance of VIEW_CONTROLS object used in the application.
Definition: tool_base.cpp:42
TOOL_MANAGER * m_toolMgr
Definition: tool_base.h:214
KIGFX::VIEW * getView() const
Returns the instance of #VIEW object used in the application.
Definition: tool_base.cpp:36
RESET_REASON
Determine the reason of reset for a tool.
Definition: tool_base.h:78
@ MODEL_RELOAD
Model changes (required full reload)
Definition: tool_base.h:80
Generic, UI-independent tool event.
Definition: tool_event.h:156
const VECTOR2D Position() const
Returns the point where dragging has started.
Definition: tool_event.h:266
bool IsDrag(int aButtonMask=BUT_ANY) const
Definition: tool_event.h:288
const VECTOR2D DragOrigin() const
Returns information about mouse buttons state.
Definition: tool_event.h:272
bool IsMotion() const
Definition: tool_event.h:303
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_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.
RECTANGLE_POINTS
LINE_POINTS
@ RECT_BOTLEFT
@ RECT_TOPLEFT
@ RECT_TOPRIGHT
@ RECT_BOTRIGHT
@ LINE_START
@ LINE_END
void pinEditedCorner(int editedPointIndex, int minWidth, int minHeight, VECTOR2I &topLeft, VECTOR2I &topRight, VECTOR2I &botLeft, VECTOR2I &botRight)
constexpr int MilsToIU(int mils) const
Definition: base_units.h:94
@ BUT_LEFT
Definition: tool_event.h:127
@ WSG_LINE_T
Definition: typeinfo.h:221
@ WSG_RECT_T
Definition: typeinfo.h:222
VECTOR2< int > VECTOR2I
Definition: vector2d.h:618