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 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>
26 using namespace std::placeholders;
27 
28 #include <tool/tool_manager.h>
29 #include <tool/actions.h>
30 #include <view/view_controls.h>
32 #include <geometry/seg.h>
33 #include <confirm.h>
34 
35 #include <bitmaps.h>
36 #include <status_popup.h>
40 
41 #include "pl_editor_frame.h"
42 #include "pl_editor_id.h"
43 #include "pl_point_editor.h"
44 #include "properties_frame.h"
45 #include "tools/pl_actions.h"
47 
48 // Few constants to avoid using bare numbers for point indices
50 {
52 };
53 
55 {
57 };
58 
60 {
61 public:
62  static std::shared_ptr<EDIT_POINTS> Make( EDA_ITEM* aItem )
63  {
64  std::shared_ptr<EDIT_POINTS> points = std::make_shared<EDIT_POINTS>( aItem );
65 
66  if( !aItem )
67  return points;
68 
69  // Generate list of edit points based on the item type
70  switch( aItem->Type() )
71  {
72  case WSG_LINE_T:
73  {
74  DS_DRAW_ITEM_LINE* line = static_cast<DS_DRAW_ITEM_LINE*>( aItem );
75  points->AddPoint( line->GetStart() );
76  points->AddPoint( line->GetEnd() );
77  break;
78  }
79  case WSG_RECT_T:
80  {
81  DS_DRAW_ITEM_RECT* rect = static_cast<DS_DRAW_ITEM_RECT*>( aItem );
82  wxPoint topLeft = rect->GetStart();
83  wxPoint botRight = rect->GetEnd();
84 
85  points->AddPoint( (VECTOR2I) topLeft );
86  points->AddPoint( VECTOR2I( botRight.x, topLeft.y ) );
87  points->AddPoint( VECTOR2I( topLeft.x, botRight.y ) );
88  points->AddPoint( (VECTOR2I) botRight );
89  break;
90  }
91  default:
92  points.reset();
93  break;
94  }
95 
96  return points;
97  }
98 
99 private:
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  {
139  point = m_editPoints->FindPoint( aEvent.Position(), getView() );
140  }
141  else if( aEvent.IsDrag( BUT_LEFT ) )
142  {
143  point = m_editPoints->FindPoint( aEvent.DragOrigin(), getView() );
144  }
145  else
146  {
147  point = m_editPoints->FindPoint( getViewControls()->GetCursorPosition(), getView() );
148  }
149 
150  if( m_editedPoint != point )
151  setEditedPoint( point );
152 }
153 
154 
155 int PL_POINT_EDITOR::Main( const TOOL_EVENT& aEvent )
156 {
157  static KICAD_T pointTypes[] = { WSG_LINE_T, WSG_RECT_T, EOT };
158 
159  if( !m_selectionTool )
160  return 0;
161 
162  const PL_SELECTION& selection = m_selectionTool->GetSelection();
163 
164  if( selection.Size() != 1 || !selection.Front()->IsType( pointTypes ) )
165  return 0;
166 
167  // Wait till drawing tool is done
168  if( selection.Front()->IsNew() )
169  return 0;
170 
171  Activate();
172 
174  KIGFX::VIEW* view = getView();
175  EDA_ITEM* item = (EDA_ITEM*) selection.Front();
176 
177  controls->ShowCursor( true );
178 
180 
181  if( !m_editPoints )
182  return 0;
183 
184  view->Add( m_editPoints.get() );
185  setEditedPoint( nullptr );
186  updateEditedPoint( aEvent );
187  bool inDrag = false;
188  bool modified = false;
189 
190  // Main loop: keep receiving events
191  while( TOOL_EVENT* evt = Wait() )
192  {
193  if( !m_editPoints || evt->IsSelectionEvent() )
194  break;
195 
196  if ( !inDrag )
197  updateEditedPoint( *evt );
198 
199  if( evt->IsDrag( BUT_LEFT ) && m_editedPoint )
200  {
201  if( !inDrag )
202  {
204  controls->ForceCursorPosition( false );
205  inDrag = true;
206  modified = true;
207  }
208 
209  m_editedPoint->SetPosition( controls->GetCursorPosition( !evt->DisableGridSnapping() ) );
210 
211  updateItem();
212  updatePoints();
213  }
214 
215  else if( inDrag && evt->IsMouseUp( BUT_LEFT ) )
216  {
217  controls->SetAutoPan( false );
218  inDrag = false;
219  }
220 
221  else if( evt->IsCancelInteractive() || evt->IsActivate() )
222  {
223  if( inDrag ) // Restore the last change
224  {
226  inDrag = false;
227  modified = false;
228  }
229  else if( evt->IsCancelInteractive() )
230  break;
231 
232  if( evt->IsActivate() && !evt->IsMoveTool() )
233  break;
234  }
235 
236  else
237  evt->SetPassEvent();
238 
239  controls->SetAutoPan( inDrag );
240  controls->CaptureCursor( inDrag );
241  }
242 
243  controls->SetAutoPan( false );
244  controls->CaptureCursor( false );
245 
246  if( m_editPoints )
247  {
248  view->Remove( m_editPoints.get() );
249 
250  if( modified )
251  m_frame->OnModify();
252 
253  m_editPoints.reset();
254  m_frame->GetCanvas()->Refresh();
255  }
256 
257  return 0;
258 }
259 
260 
261 void pinEditedCorner( int editedPointIndex, int minWidth, int minHeight, VECTOR2I& topLeft,
262  VECTOR2I& topRight, VECTOR2I& botLeft, VECTOR2I& botRight )
263 {
264  switch( editedPointIndex )
265  {
266  case RECT_TOPLEFT:
267  // pin edited point within opposite corner
268  topLeft.x = std::min( topLeft.x, botRight.x - minWidth );
269  topLeft.y = std::min( topLeft.y, botRight.y - minHeight );
270 
271  // push edited point edges to adjacent corners
272  topRight.y = topLeft.y;
273  botLeft.x = topLeft.x;
274 
275  break;
276 
277  case RECT_TOPRIGHT:
278  // pin edited point within opposite corner
279  topRight.x = std::max( topRight.x, botLeft.x + minWidth );
280  topRight.y = std::min( topRight.y, botLeft.y - minHeight );
281 
282  // push edited point edges to adjacent corners
283  topLeft.y = topRight.y;
284  botRight.x = topRight.x;
285 
286  break;
287 
288  case RECT_BOTLEFT:
289  // pin edited point within opposite corner
290  botLeft.x = std::min( botLeft.x, topRight.x - minWidth );
291  botLeft.y = std::max( botLeft.y, topRight.y + minHeight );
292 
293  // push edited point edges to adjacent corners
294  botRight.y = botLeft.y;
295  topLeft.x = botLeft.x;
296 
297  break;
298 
299  case RECT_BOTRIGHT:
300  // pin edited point within opposite corner
301  botRight.x = std::max( botRight.x, topLeft.x + minWidth );
302  botRight.y = std::max( botRight.y, topLeft.y + minHeight );
303 
304  // push edited point edges to adjacent corners
305  botLeft.y = botRight.y;
306  topRight.x = botRight.x;
307 
308  break;
309  }
310 }
311 
312 
314 {
315  EDA_ITEM* item = m_editPoints->GetParent();
316 
317  if( !item )
318  return;
319 
320  DS_DATA_ITEM* dataItem = static_cast<DS_DRAW_ITEM_BASE*>( item )->GetPeer();
321 
322  // the current item is perhaps not the main item if we have a set of
323  // repeated items.
324  // So we change the coordinate references in dataItem using move vectors
325  // of the start and end points that are the same for each repeated item
326 
327  switch( item->Type() )
328  {
329  case WSG_LINE_T:
330  {
331  DS_DRAW_ITEM_LINE* line = static_cast<DS_DRAW_ITEM_LINE*>( item );
332 
333  wxPoint move_startpoint = (wxPoint) m_editPoints->Point( LINE_START ).GetPosition()
334  - line->GetStart();
335  wxPoint move_endpoint = (wxPoint) m_editPoints->Point( LINE_END ).GetPosition()
336  - line->GetEnd();
337 
338  dataItem->MoveStartPointToUi( dataItem->GetStartPosUi() + move_startpoint );
339  dataItem->MoveEndPointToUi( dataItem->GetEndPosUi() + move_endpoint );
340 
341  for( DS_DRAW_ITEM_BASE* draw_item : dataItem->GetDrawItems() )
342  {
343  DS_DRAW_ITEM_LINE* draw_line = static_cast<DS_DRAW_ITEM_LINE*>( draw_item );
344 
345  draw_line->SetStart( draw_line->GetStart() + move_startpoint );
346  draw_line->SetEnd( draw_line->GetEnd() + move_endpoint );
347  getView()->Update( draw_item );
348  }
349 
350  break;
351  }
352 
353  case WSG_RECT_T:
354  {
355  DS_DRAW_ITEM_RECT* rect = static_cast<DS_DRAW_ITEM_RECT*>( item );
356  VECTOR2I topLeft = m_editPoints->Point( RECT_TOPLEFT ).GetPosition();
357  VECTOR2I topRight = m_editPoints->Point( RECT_TOPRIGHT ).GetPosition();
358  VECTOR2I botLeft = m_editPoints->Point( RECT_BOTLEFT ).GetPosition();
359  VECTOR2I botRight = m_editPoints->Point( RECT_BOTRIGHT ).GetPosition();
360 
361  pinEditedCorner( getEditedPointIndex(), Mils2iu( 1 ), Mils2iu( 1 ),
362  topLeft, topRight, botLeft, botRight );
363 
364  wxPoint move_startpoint = (wxPoint) topLeft - rect->GetStart();
365  wxPoint move_endpoint = (wxPoint) botRight - rect->GetEnd();
366 
367  dataItem->MoveStartPointToUi( dataItem->GetStartPosUi() + move_startpoint );
368  dataItem->MoveEndPointToUi( dataItem->GetEndPosUi() + move_endpoint );
369  for( DS_DRAW_ITEM_BASE* draw_item : dataItem->GetDrawItems() )
370  {
371  DS_DRAW_ITEM_RECT* draw_rect = static_cast<DS_DRAW_ITEM_RECT*>( draw_item );
372 
373  draw_rect->SetStart( draw_rect->GetStart() + move_startpoint );
374  draw_rect->SetEnd( draw_rect->GetEnd() + move_endpoint );
375  getView()->Update( draw_item );
376  }
377 
378  break;
379  }
380 
381  default:
382  break;
383  }
384 
385  m_frame->SetMsgPanel( item );
386 
387  // The Properties frame will be updated. Avoid flicker during update:
388  m_frame->GetPropertiesFrame()->Freeze();
390  m_frame->GetPropertiesFrame()->Thaw();
391 }
392 
393 
395 {
396  if( !m_editPoints )
397  return;
398 
399  EDA_ITEM* item = m_editPoints->GetParent();
400 
401  if( !item )
402  return;
403 
404  switch( item->Type() )
405  {
406  case WSG_LINE_T:
407  {
408  DS_DRAW_ITEM_LINE* line = static_cast<DS_DRAW_ITEM_LINE*>( item );
409 
410  m_editPoints->Point( LINE_START ).SetPosition( line->GetStart() );
411  m_editPoints->Point( LINE_END ).SetPosition( line->GetEnd() );
412  break;
413  }
414 
415  case WSG_RECT_T:
416  {
417  DS_DRAW_ITEM_RECT* rect = static_cast<DS_DRAW_ITEM_RECT*>( item );
418  wxPoint topLeft = rect->GetPosition();
419  wxPoint botRight = rect->GetEnd();
420 
421  m_editPoints->Point( RECT_TOPLEFT ).SetPosition( (VECTOR2I) topLeft );
422  m_editPoints->Point( RECT_TOPRIGHT ).SetPosition( VECTOR2I( botRight.x, topLeft.y ) );
423  m_editPoints->Point( RECT_BOTLEFT ).SetPosition( VECTOR2I( topLeft.x, botRight.y ) );
424  m_editPoints->Point( RECT_BOTRIGHT ).SetPosition( (VECTOR2I) botRight );
425  break;
426  }
427 
428  default:
429  break;
430  }
431 
432  getView()->Update( m_editPoints.get() );
433 }
434 
435 
437 {
439 
440  if( aPoint )
441  {
443  controls->ForceCursorPosition( true, aPoint->GetPosition() );
444  controls->ShowCursor( true );
445  }
446  else
447  {
448  if( m_frame->ToolStackIsEmpty() )
449  controls->ShowCursor( false );
450 
451  controls->ForceCursorPosition( false );
452  }
453 
454  m_editedPoint = aPoint;
455 }
456 
457 
459 {
460  updatePoints();
461  return 0;
462 }
463 
464 
466 {
470 }
471 
472 
virtual void ShowCursor(bool aEnabled)
Enable or disables display of cursor.
void SetStart(const wxPoint &aPos)
Definition: ds_draw_item.h:220
void SetStart(const wxPoint &aPos)
Definition: ds_draw_item.h:134
PROPERTIES_FRAME * GetPropertiesFrame()
static const TOOL_EVENT SelectedEvent
Definition: actions.h:199
PL_EDITOR_FRAME * m_frame
void SetCurrentCursor(KICURSOR aCursor)
Set the current cursor shape for this panel.
PL_DRAW_PANEL_GAL * GetCanvas() const override
Return a pointer to GAL-based canvas of given EDA draw frame.
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.
static TOOL_ACTION activatePointEditor
Definition: actions.h:168
Model changes (required full reload)
Definition: tool_base.h:80
const wxPoint GetEndPosUi(int ii=0) const
This file is part of the common library.
void SetEnd(const wxPoint &aPos) override
Definition: ds_draw_item.h:222
static std::shared_ptr< EDIT_POINTS > Make(EDA_ITEM *aItem)
void MoveEndPointToUi(const wxPoint &aPosition)
Move the ending point of the item to a new position.
TOOL_MANAGER * m_toolMgr
Definition: tool_base.h:214
void updatePoints()
Update which point is being edited.
bool Init() override
Init() is called once upon a registration of the tool.
virtual void Remove(VIEW_ITEM *aItem)
Remove a VIEW_ITEM from the view.
Definition: view.cpp:351
bool IsMotion() const
Definition: tool_event.h:295
PL_SELECTION_TOOL * m_selectionTool
Currently edited point, NULL if there is none.
std::shared_ptr< EDIT_POINTS > m_editPoints
void setEditedPoint(EDIT_POINT *aPoint)
Return true if aPoint is the currently modified point.
void pinEditedCorner(int editedPointIndex, int minWidth, int minHeight, VECTOR2I &topLeft, VECTOR2I &topRight, VECTOR2I &botLeft, VECTOR2I &botRight)
VECTOR2< int > VECTOR2I
Definition: vector2d.h:623
const wxPoint & GetStart() const
Definition: ds_draw_item.h:133
wxPoint GetPosition() const override
Definition: ds_draw_item.h:224
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).
const wxPoint & GetStart() const
Definition: ds_draw_item.h:219
PL_SELECTION & GetSelection()
Return the set of currently selected items.
search types array terminator (End Of Types)
Definition: typeinfo.h:81
KICAD_T
The set of class identification values stored in EDA_ITEM::m_structType.
Definition: typeinfo.h:77
static const TOOL_EVENT SelectedItemsModified
Selected items were moved, this can be very high frequency on the canvas, use with care.
Definition: actions.h:204
bool IsNew() const
Definition: eda_item.h:119
void OnModify()
Must be called after a change in order to set the "modify" flag.
Base class to handle basic graphic items.
Definition: ds_draw_item.h:58
int getEditedPointIndex() const
bool IsDrag(int aButtonMask=BUT_ANY) const
Definition: tool_event.h:285
virtual VECTOR2I GetPosition() const
Return coordinates of an EDIT_POINT.
Definition: edit_points.h:70
int Main(const TOOL_EVENT &aEvent)
void SetMsgPanel(const std::vector< MSG_PANEL_ITEM > &aList)
Clear the message panel and populates it with the contents of aList.
void updateEditedPoint(const TOOL_EVENT &aEvent)
Set the current point being edited. NULL means none.
virtual void CaptureCursor(bool aEnabled)
Force the cursor to stay within the drawing panel area.
void Reset(RESET_REASON aReason) override
Bring the tool to a known, initial state.
Generic, UI-independent tool event.
Definition: tool_event.h:152
void updateItem() const
< Update item's points with edit points.
bool ToolStackIsEmpty()
Definition: tools_holder.h:116
An interface for classes handling user events controlling the view behavior such as zooming,...
const VECTOR2D DragOrigin() const
Returns information about mouse buttons state.
Definition: tool_event.h:269
const std::vector< DS_DRAW_ITEM_BASE * > & GetDrawItems() const
Definition: ds_data_item.h:110
virtual void ForceCursorPosition(bool aEnabled, const VECTOR2D &aPosition=VECTOR2D(0, 0))
Place the cursor immediately at a given point.
virtual bool IsType(const KICAD_T aScanTypes[]) const
Check whether the item is one of the listed types.
Definition: eda_item.h:183
LINE_POINTS
KIGFX::VIEW * getView() const
Returns the instance of #VIEW object used in the application.
Definition: tool_base.cpp:36
virtual void SetAutoPan(bool aEnabled)
Turn on/off auto panning (this feature is used when there is a tool active (eg.
EDIT_POINT * m_editedPoint
Currently available edit points.
int modifiedSelection(const TOOL_EVENT &aEvent)
Non filled rectangle with thick segment.
Definition: ds_draw_item.h:205
void MoveStartPointToUi(const wxPoint &aPosition)
Move the starting point of the item to a new position.
Drawing sheet structure type definitions.
Definition: ds_data_item.h:95
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...
int Size() const
Returns the number of selected parts.
Definition: selection.h:103
A base class for most all the KiCad significant classes used in schematics and boards.
Definition: eda_item.h:100
RESET_REASON
Determine the reason of reset for a tool.
Definition: tool_base.h:77
void SaveCopyInUndoList()
Save a copy of the description (in a S expr string) for Undo/redo commands.
void Activate()
Run the tool.
const wxPoint & GetEnd() const
Definition: ds_draw_item.h:221
void CopyPrmsFromItemToPanel(DS_DATA_ITEM *aItem)
virtual void Add(VIEW_ITEM *aItem, int aDrawPriority=-1)
Add a VIEW_ITEM to the view.
Definition: view.cpp:321
Represent a single point that can be used for modifying items.
Definition: edit_points.h:47
KIGFX::VIEW_CONTROLS * getViewControls() const
Return the instance of VIEW_CONTROLS object used in the application.
Definition: tool_base.cpp:42
Hold a (potentially large) number of VIEW_ITEMs and renders them on a graphics device provided by the...
Definition: view.h:67
void setTransitions() override
This method is meant to be overridden in order to specify handlers for events.
void RollbackFromUndo()
Apply the last command in Undo List without stacking a Redo.
RECTANGLE_POINTS
static std::shared_ptr< EDIT_POINTS > Make(EDA_ITEM *aItem, SCH_BASE_FRAME *frame)
const VECTOR2D Position() const
Returns the point where dragging has started.
Definition: tool_event.h:263
const wxPoint & GetEnd() const
Definition: ds_draw_item.h:135
VECTOR2D GetCursorPosition() const
Return the current cursor position in world coordinates.
EDA_ITEM * Front() const
Definition: selection.h:144
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:1503
KICAD_T Type() const
Returns the type of object.
Definition: eda_item.h:113
const wxPoint GetStartPosUi(int ii=0) const
void SetEnd(const wxPoint &aPos) override
Definition: ds_draw_item.h:136
virtual void SetPosition(const VECTOR2I &aPosition)
Set new coordinates for an EDIT_POINT.
Definition: edit_points.h:106