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 "pl_point_editor.h"
29 #include <tool/tool_manager.h>
30 #include <tool/actions.h>
31 #include <tools/pl_actions.h>
33 #include <view/view_controls.h>
35 #include <geometry/seg.h>
36 #include <confirm.h>
37 
38 #include <bitmaps.h>
39 #include <status_popup.h>
40 #include <pl_editor_frame.h>
41 #include <ws_draw_item.h>
43 #include <pl_editor_id.h>
44 
45 
46 // Few constants to avoid using bare numbers for point indices
48 {
50 };
51 
53 {
55 };
56 
58 {
59 public:
60  static std::shared_ptr<EDIT_POINTS> Make( EDA_ITEM* aItem )
61  {
62  std::shared_ptr<EDIT_POINTS> points = std::make_shared<EDIT_POINTS>( aItem );
63 
64  if( !aItem )
65  return points;
66 
67  // Generate list of edit points based on the item type
68  switch( aItem->Type() )
69  {
70  case WSG_LINE_T:
71  {
72  WS_DRAW_ITEM_LINE* line = (WS_DRAW_ITEM_LINE*) aItem;
73  points->AddPoint( line->GetStart() );
74  points->AddPoint( line->GetEnd() );
75  break;
76  }
77  case WSG_RECT_T:
78  {
79  WS_DRAW_ITEM_RECT* rect = (WS_DRAW_ITEM_RECT*) aItem;
80  wxPoint topLeft = rect->GetStart();
81  wxPoint botRight = rect->GetEnd();
82 
83  points->AddPoint( (VECTOR2I) topLeft );
84  points->AddPoint( VECTOR2I( botRight.x, topLeft.y ) );
85  points->AddPoint( VECTOR2I( topLeft.x, botRight.y ) );
86  points->AddPoint( (VECTOR2I) botRight );
87  break;
88  }
89  default:
90  points.reset();
91  break;
92  }
93 
94  return points;
95  }
96 
97 private:
99 };
100 
101 
103  TOOL_INTERACTIVE( "plEditor.PointEditor" ),
104  m_editedPoint( nullptr )
105 {
106 }
107 
108 
110 {
111  if( aReason == MODEL_RELOAD )
112  {
113  // Init variables used by every drawing tool
114  m_frame = getEditFrame<PL_EDITOR_FRAME>();
115  }
116 
117  m_editPoints.reset();
118 }
119 
120 
122 {
123  m_frame = getEditFrame<PL_EDITOR_FRAME>();
125  return true;
126 }
127 
128 
130 {
131  EDIT_POINT* point = m_editedPoint;
132 
133  if( aEvent.IsMotion() )
134  {
135  point = m_editPoints->FindPoint( aEvent.Position(), getView() );
136  }
137  else if( aEvent.IsDrag( BUT_LEFT ) )
138  {
139  point = m_editPoints->FindPoint( aEvent.DragOrigin(), getView() );
140  }
141  else
142  {
143  point = m_editPoints->FindPoint( getViewControls()->GetCursorPosition(), getView() );
144  }
145 
146  if( m_editedPoint != point )
147  setEditedPoint( point );
148 }
149 
150 
151 int PL_POINT_EDITOR::Main( const TOOL_EVENT& aEvent )
152 {
153  static KICAD_T pointTypes[] = { WSG_LINE_T, WSG_RECT_T, EOT };
154 
155  if( !m_selectionTool )
156  return 0;
157 
158  const PL_SELECTION& selection = m_selectionTool->GetSelection();
159 
160  if( selection.Size() != 1 || !selection.Front()->IsType( pointTypes ) )
161  return 0;
162 
163  // Wait till drawing tool is done
164  if( selection.Front()->IsNew() )
165  return 0;
166 
167  Activate();
168 
170  KIGFX::VIEW* view = getView();
171  EDA_ITEM* item = (EDA_ITEM*) selection.Front();
172 
173  controls->ShowCursor( true );
174 
176 
177  if( !m_editPoints )
178  return 0;
179 
180  view->Add( m_editPoints.get() );
181  setEditedPoint( nullptr );
182  updateEditedPoint( aEvent );
183  bool inDrag = false;
184  bool modified = false;
185 
186  // Main loop: keep receiving events
187  while( TOOL_EVENT* evt = Wait() )
188  {
189  if( !m_editPoints || evt->IsSelectionEvent() )
190  break;
191 
192  if ( !inDrag )
193  updateEditedPoint( *evt );
194 
195  if( evt->IsDrag( BUT_LEFT ) && m_editedPoint )
196  {
197  if( !inDrag )
198  {
200  controls->ForceCursorPosition( false );
201  inDrag = true;
202  modified = true;
203  }
204 
205  m_editedPoint->SetPosition( controls->GetCursorPosition( !evt->Modifier( MD_ALT ) ) );
206 
207  updateItem();
208  updatePoints();
209  }
210 
211  else if( inDrag && evt->IsMouseUp( BUT_LEFT ) )
212  {
213  controls->SetAutoPan( false );
214  inDrag = false;
215  }
216 
217  else if( evt->IsCancelInteractive() || evt->IsActivate() )
218  {
219  if( inDrag ) // Restore the last change
220  {
222  inDrag = false;
223  modified = false;
224  }
225  else if( evt->IsCancelInteractive() )
226  break;
227 
228  if( evt->IsActivate() && !evt->IsMoveTool() )
229  break;
230  }
231 
232  else
233  evt->SetPassEvent();
234 
235  controls->SetAutoPan( inDrag );
236  controls->CaptureCursor( inDrag );
237  }
238 
239  controls->SetAutoPan( false );
240  controls->CaptureCursor( false );
241 
242  if( m_editPoints )
243  {
244  view->Remove( m_editPoints.get() );
245 
246  if( modified )
247  m_frame->OnModify();
248 
249  m_editPoints.reset();
250  m_frame->GetCanvas()->Refresh();
251  }
252 
253  return 0;
254 }
255 
256 
257 void pinEditedCorner( int editedPointIndex, int minWidth, int minHeight, VECTOR2I& topLeft,
258  VECTOR2I& topRight, VECTOR2I& botLeft, VECTOR2I& botRight )
259 {
260  switch( editedPointIndex )
261  {
262  case RECT_TOPLEFT:
263  // pin edited point within opposite corner
264  topLeft.x = std::min( topLeft.x, botRight.x - minWidth );
265  topLeft.y = std::min( topLeft.y, botRight.y - minHeight );
266 
267  // push edited point edges to adjacent corners
268  topRight.y = topLeft.y;
269  botLeft.x = topLeft.x;
270 
271  break;
272 
273  case RECT_TOPRIGHT:
274  // pin edited point within opposite corner
275  topRight.x = std::max( topRight.x, botLeft.x + minWidth );
276  topRight.y = std::min( topRight.y, botLeft.y - minHeight );
277 
278  // push edited point edges to adjacent corners
279  topLeft.y = topRight.y;
280  botRight.x = topRight.x;
281 
282  break;
283 
284  case RECT_BOTLEFT:
285  // pin edited point within opposite corner
286  botLeft.x = std::min( botLeft.x, topRight.x - minWidth );
287  botLeft.y = std::max( botLeft.y, topRight.y + minHeight );
288 
289  // push edited point edges to adjacent corners
290  botRight.y = botLeft.y;
291  topLeft.x = botLeft.x;
292 
293  break;
294 
295  case RECT_BOTRIGHT:
296  // pin edited point within opposite corner
297  botRight.x = std::max( botRight.x, topLeft.x + minWidth );
298  botRight.y = std::max( botRight.y, topLeft.y + minHeight );
299 
300  // push edited point edges to adjacent corners
301  botLeft.y = botRight.y;
302  topRight.x = botRight.x;
303 
304  break;
305  }
306 }
307 
308 
310 {
311  EDA_ITEM* item = m_editPoints->GetParent();
312 
313  if( !item )
314  return;
315 
316  switch( item->Type() )
317  {
318  case WSG_LINE_T:
319  {
320  WS_DRAW_ITEM_LINE* line = (WS_DRAW_ITEM_LINE*) item;
321 
322  line->SetStart( (wxPoint) m_editPoints->Point( LINE_START ).GetPosition() );
323  line->SetEnd( (wxPoint) m_editPoints->Point( LINE_END ).GetPosition() );
324  break;
325  }
326 
327  case WSG_RECT_T:
328  {
329  WS_DRAW_ITEM_RECT* rect = (WS_DRAW_ITEM_RECT*) item;
330  VECTOR2I topLeft = m_editPoints->Point( RECT_TOPLEFT ).GetPosition();
331  VECTOR2I topRight = m_editPoints->Point( RECT_TOPRIGHT ).GetPosition();
332  VECTOR2I botLeft = m_editPoints->Point( RECT_BOTLEFT ).GetPosition();
333  VECTOR2I botRight = m_editPoints->Point( RECT_BOTRIGHT ).GetPosition();
334 
335  pinEditedCorner( getEditedPointIndex(), Mils2iu( 1 ), Mils2iu( 1 ),
336  topLeft, topRight, botLeft, botRight );
337 
338  rect->SetStart( (wxPoint) topLeft );
339  rect->SetEnd( (wxPoint) botRight );
340  break;
341  }
342 
343  default:
344  break;
345  }
346 
347  getView()->Update( item );
348  m_frame->SetMsgPanel( item );
349 }
350 
351 
353 {
354  if( !m_editPoints )
355  return;
356 
357  EDA_ITEM* item = m_editPoints->GetParent();
358 
359  if( !item )
360  return;
361 
362  switch( item->Type() )
363  {
364  case WSG_LINE_T:
365  {
366  WS_DRAW_ITEM_LINE* line = (WS_DRAW_ITEM_LINE*) item;
367 
368  m_editPoints->Point( LINE_START ).SetPosition( line->GetStart() );
369  m_editPoints->Point( LINE_END ).SetPosition( line->GetEnd() );
370  break;
371  }
372 
373  case WSG_RECT_T:
374  {
375  WS_DRAW_ITEM_RECT* rect = (WS_DRAW_ITEM_RECT*) item;
376  wxPoint topLeft = rect->GetPosition();
377  wxPoint botRight = rect->GetEnd();
378 
379  m_editPoints->Point( RECT_TOPLEFT ).SetPosition( (VECTOR2I) topLeft );
380  m_editPoints->Point( RECT_TOPRIGHT ).SetPosition( VECTOR2I( botRight.x, topLeft.y ) );
381  m_editPoints->Point( RECT_BOTLEFT ).SetPosition( VECTOR2I( topLeft.x, botRight.y ) );
382  m_editPoints->Point( RECT_BOTRIGHT ).SetPosition( (VECTOR2I) botRight );
383  break;
384  }
385 
386  default:
387  break;
388  }
389 
390  getView()->Update( m_editPoints.get() );
391 }
392 
393 
395 {
397 
398  if( aPoint )
399  {
400  m_frame->GetCanvas()->SetCurrentCursor( wxCURSOR_ARROW );
401  controls->ForceCursorPosition( true, aPoint->GetPosition() );
402  controls->ShowCursor( true );
403  }
404  else
405  {
406  if( m_frame->ToolStackIsEmpty() )
407  controls->ShowCursor( false );
408 
409  controls->ForceCursorPosition( false );
410  }
411 
412  m_editedPoint = aPoint;
413 }
414 
415 
417 {
418  updatePoints();
419  return 0;
420 }
421 
422 
424 {
428 }
429 
430 
const wxPoint & GetStart() const
Definition: ws_draw_item.h:206
virtual void ShowCursor(bool aEnabled)
Function ShowCursor() Enables or disables display of cursor.
void SaveCopyInUndoList(bool aSavePageSettingsAndTitleBlock=false)
Save a copy of the description (in a S expr string) for Undo/redo commands.
const wxPoint & GetEnd() const
Definition: ws_draw_item.h:208
static const TOOL_EVENT SelectedEvent
Definition: actions.h:197
PL_EDITOR_FRAME * m_frame
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))
Function Wait()
static TOOL_ACTION activatePointEditor
Definition: actions.h:159
Model changes (required full reload)
Definition: tool_base.h:82
const wxPoint & GetEnd() const
Definition: ws_draw_item.h:124
void SetStart(wxPoint aPos)
Definition: ws_draw_item.h:123
This file is part of the common library.
void SetCurrentCursor(wxStockCursor aStockCursorID)
Function SetCurrentCursor Set the current cursor shape for this panel.
VIEW_CONTROLS class definition.
static std::shared_ptr< EDIT_POINTS > Make(EDA_ITEM *aItem)
TOOL_MANAGER * m_toolMgr
Definition: tool_base.h:219
void updatePoints()
Updates edit points with item's points.
bool Init() override
Function Init() Init() is called once upon a registration of the tool.
virtual void Remove(VIEW_ITEM *aItem)
Function Remove() Removes a VIEW_ITEM from the view.
Definition: view.cpp:376
void SetStart(wxPoint aPos)
Definition: ws_draw_item.h:207
bool IsMotion() const
Definition: tool_event.h:306
virtual bool IsType(const KICAD_T aScanTypes[])
Function IsType Checks whether the item is one of the listed types.
Definition: base_struct.h:294
PL_SELECTION_TOOL * m_selectionTool
std::shared_ptr< EDIT_POINTS > m_editPoints
Currently available edit points.
void setEditedPoint(EDIT_POINT *aPoint)
Sets the current point being edited. NULL means none.
void pinEditedCorner(int editedPointIndex, int minWidth, int minHeight, VECTOR2I &topLeft, VECTOR2I &topRight, VECTOR2I &botLeft, VECTOR2I &botRight)
VECTOR2< int > VECTOR2I
Definition: vector2d.h:587
void Go(int(T::*aStateFunc)(const TOOL_EVENT &), const TOOL_EVENT_LIST &aConditions=TOOL_EVENT(TC_ANY, TA_ANY))
Function Go()
PL_SELECTION & GetSelection()
Function GetSelection()
search types array terminator (End Of Types)
Definition: typeinfo.h:82
KICAD_T
Enum KICAD_T is the set of class identification values, stored in EDA_ITEM::m_StructType.
Definition: typeinfo.h:78
static const TOOL_EVENT SelectedItemsModified
Definition: actions.h:201
bool IsNew() const
Definition: base_struct.h:228
void OnModify()
Must be called after a change in order to set the "modify" flag.
int getEditedPointIndex() const
bool IsDrag(int aButtonMask=BUT_ANY) const
Definition: tool_event.h:296
void SetEnd(wxPoint aPos) override
Definition: ws_draw_item.h:209
virtual VECTOR2I GetPosition() const
Function GetPosition()
Definition: edit_points.h:68
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)
Updates which point is being edited.
virtual void CaptureCursor(bool aEnabled)
Function CaptureCursor() Forces the cursor to stay within the drawing panel area.
void Reset(RESET_REASON aReason) override
Function Reset() Brings the tool to a known, initial state.
const wxPoint & GetStart() const
Definition: ws_draw_item.h:122
Class TOOL_EVENT.
Definition: tool_event.h:171
void updateItem() const
Updates item's points with edit points.
Class VIEW_CONTROLS is an interface for classes handling user events controlling the view behaviour (...
const VECTOR2D DragOrigin() const
Returns the point where dragging has started.
Definition: tool_event.h:280
virtual void ForceCursorPosition(bool aEnabled, const VECTOR2D &aPosition=VECTOR2D(0, 0))
Function ForceCursorPosition() Places the cursor immediately at a given point.
virtual void Update(VIEW_ITEM *aItem, int aUpdateFlags)
For dynamic VIEWs, informs the associated VIEW that the graphical representation of this item has cha...
Definition: view.cpp:1540
LINE_POINTS
KIGFX::VIEW * getView() const
Function getView()
Definition: tool_base.cpp:36
virtual void SetAutoPan(bool aEnabled)
Function SetAutoPan Turns on/off auto panning (this feature is used when there is a tool active (eg.
virtual void Refresh(bool aEraseBackground=true, const wxRect *aRect=NULL) override
Update the board display after modifying it by a python script (note: it is automatically called by a...
EDIT_POINT * m_editedPoint
Currently edited point, NULL if there is none.
int modifiedSelection(const TOOL_EVENT &aEvent)
bool ToolStackIsEmpty()
#define max(a, b)
Definition: auxiliary.h:86
int Size() const
Returns the number of selected parts.
Definition: selection.h:125
Class EDA_ITEM is a base class for most all the KiCad significant classes, used in schematics and boa...
Definition: base_struct.h:163
RESET_REASON
Determines the reason of reset for a tool
Definition: tool_base.h:79
const wxPoint GetPosition() const override
Definition: ws_draw_item.h:211
void Activate()
Function Activate() Runs the tool.
virtual void Add(VIEW_ITEM *aItem, int aDrawPriority=-1)
Function Add() Adds a VIEW_ITEM to the view.
Definition: view.cpp:346
Class EDIT_POINT.
Definition: edit_points.h:46
KIGFX::VIEW_CONTROLS * getViewControls() const
Function getViewControls()
Definition: tool_base.cpp:42
Class VIEW.
Definition: view.h:61
void setTransitions() override
Sets up handlers for various events.
void RollbackFromUndo()
Apply the last command in Undo List without stacking a Redo.
RECTANGLE_POINTS
const VECTOR2D Position() const
Returns mouse cursor position in world coordinates.
Definition: tool_event.h:274
VECTOR2D GetCursorPosition() const
Returns the current cursor position in world coordinates.
EDA_ITEM * Front() const
Definition: selection.h:182
KICAD_T Type() const
Function Type()
Definition: base_struct.h:210
#define min(a, b)
Definition: auxiliary.h:85
void SetEnd(wxPoint aPos) override
Definition: ws_draw_item.h:125
static std::shared_ptr< EDIT_POINTS > Make(EDA_ITEM *aItem, KIGFX::GAL *aGal)
virtual void SetPosition(const VECTOR2I &aPosition)
Function SetPosition()
Definition: edit_points.h:105