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_frame( nullptr ),
105  m_selectionTool( nullptr ),
106  m_editedPoint( nullptr )
107 {
108 }
109 
110 
112 {
113  if( aReason == MODEL_RELOAD )
114  {
115  // Init variables used by every drawing tool
116  m_frame = getEditFrame<PL_EDITOR_FRAME>();
117  }
118 
119  m_editPoints.reset();
120 }
121 
122 
124 {
125  m_frame = getEditFrame<PL_EDITOR_FRAME>();
127  return true;
128 }
129 
130 
132 {
133  EDIT_POINT* point = m_editedPoint;
134 
135  if( aEvent.IsMotion() )
136  {
137  point = m_editPoints->FindPoint( aEvent.Position(), getView() );
138  }
139  else if( aEvent.IsDrag( BUT_LEFT ) )
140  {
141  point = m_editPoints->FindPoint( aEvent.DragOrigin(), getView() );
142  }
143  else
144  {
145  point = m_editPoints->FindPoint( getViewControls()->GetCursorPosition(), getView() );
146  }
147 
148  if( m_editedPoint != point )
149  setEditedPoint( point );
150 }
151 
152 
153 int PL_POINT_EDITOR::Main( const TOOL_EVENT& aEvent )
154 {
155  static KICAD_T pointTypes[] = { WSG_LINE_T, WSG_RECT_T, EOT };
156 
157  if( !m_selectionTool )
158  return 0;
159 
160  const PL_SELECTION& selection = m_selectionTool->GetSelection();
161 
162  if( selection.Size() != 1 || !selection.Front()->IsType( pointTypes ) )
163  return 0;
164 
165  // Wait till drawing tool is done
166  if( selection.Front()->IsNew() )
167  return 0;
168 
169  Activate();
170 
172  KIGFX::VIEW* view = getView();
173  EDA_ITEM* item = (EDA_ITEM*) selection.Front();
174 
175  controls->ShowCursor( true );
176 
178 
179  if( !m_editPoints )
180  return 0;
181 
182  view->Add( m_editPoints.get() );
183  setEditedPoint( nullptr );
184  updateEditedPoint( aEvent );
185  bool inDrag = false;
186  bool modified = false;
187 
188  // Main loop: keep receiving events
189  while( TOOL_EVENT* evt = Wait() )
190  {
191  if( !m_editPoints || evt->IsSelectionEvent() )
192  break;
193 
194  if ( !inDrag )
195  updateEditedPoint( *evt );
196 
197  if( evt->IsDrag( BUT_LEFT ) && m_editedPoint )
198  {
199  if( !inDrag )
200  {
202  controls->ForceCursorPosition( false );
203  inDrag = true;
204  modified = true;
205  }
206 
207  m_editedPoint->SetPosition( controls->GetCursorPosition( !evt->Modifier( MD_ALT ) ) );
208 
209  updateItem();
210  updatePoints();
211  }
212 
213  else if( inDrag && evt->IsMouseUp( BUT_LEFT ) )
214  {
215  controls->SetAutoPan( false );
216  inDrag = false;
217  }
218 
219  else if( evt->IsCancelInteractive() || evt->IsActivate() )
220  {
221  if( inDrag ) // Restore the last change
222  {
224  inDrag = false;
225  modified = false;
226  }
227  else if( evt->IsCancelInteractive() )
228  break;
229 
230  if( evt->IsActivate() && !evt->IsMoveTool() )
231  break;
232  }
233 
234  else
235  evt->SetPassEvent();
236 
237  controls->SetAutoPan( inDrag );
238  controls->CaptureCursor( inDrag );
239  }
240 
241  controls->SetAutoPan( false );
242  controls->CaptureCursor( false );
243 
244  if( m_editPoints )
245  {
246  view->Remove( m_editPoints.get() );
247 
248  if( modified )
249  m_frame->OnModify();
250 
251  m_editPoints.reset();
252  m_frame->GetCanvas()->Refresh();
253  }
254 
255  return 0;
256 }
257 
258 
259 void pinEditedCorner( int editedPointIndex, int minWidth, int minHeight, VECTOR2I& topLeft,
260  VECTOR2I& topRight, VECTOR2I& botLeft, VECTOR2I& botRight )
261 {
262  switch( editedPointIndex )
263  {
264  case RECT_TOPLEFT:
265  // pin edited point within opposite corner
266  topLeft.x = std::min( topLeft.x, botRight.x - minWidth );
267  topLeft.y = std::min( topLeft.y, botRight.y - minHeight );
268 
269  // push edited point edges to adjacent corners
270  topRight.y = topLeft.y;
271  botLeft.x = topLeft.x;
272 
273  break;
274 
275  case RECT_TOPRIGHT:
276  // pin edited point within opposite corner
277  topRight.x = std::max( topRight.x, botLeft.x + minWidth );
278  topRight.y = std::min( topRight.y, botLeft.y - minHeight );
279 
280  // push edited point edges to adjacent corners
281  topLeft.y = topRight.y;
282  botRight.x = topRight.x;
283 
284  break;
285 
286  case RECT_BOTLEFT:
287  // pin edited point within opposite corner
288  botLeft.x = std::min( botLeft.x, topRight.x - minWidth );
289  botLeft.y = std::max( botLeft.y, topRight.y + minHeight );
290 
291  // push edited point edges to adjacent corners
292  botRight.y = botLeft.y;
293  topLeft.x = botLeft.x;
294 
295  break;
296 
297  case RECT_BOTRIGHT:
298  // pin edited point within opposite corner
299  botRight.x = std::max( botRight.x, topLeft.x + minWidth );
300  botRight.y = std::max( botRight.y, topLeft.y + minHeight );
301 
302  // push edited point edges to adjacent corners
303  botLeft.y = botRight.y;
304  topRight.x = botRight.x;
305 
306  break;
307  }
308 }
309 
310 
312 {
313  EDA_ITEM* item = m_editPoints->GetParent();
314 
315  if( !item )
316  return;
317 
318  switch( item->Type() )
319  {
320  case WSG_LINE_T:
321  {
322  WS_DRAW_ITEM_LINE* line = (WS_DRAW_ITEM_LINE*) item;
323 
324  line->SetStart( (wxPoint) m_editPoints->Point( LINE_START ).GetPosition() );
325  line->SetEnd( (wxPoint) m_editPoints->Point( LINE_END ).GetPosition() );
326  break;
327  }
328 
329  case WSG_RECT_T:
330  {
331  WS_DRAW_ITEM_RECT* rect = (WS_DRAW_ITEM_RECT*) item;
332  VECTOR2I topLeft = m_editPoints->Point( RECT_TOPLEFT ).GetPosition();
333  VECTOR2I topRight = m_editPoints->Point( RECT_TOPRIGHT ).GetPosition();
334  VECTOR2I botLeft = m_editPoints->Point( RECT_BOTLEFT ).GetPosition();
335  VECTOR2I botRight = m_editPoints->Point( RECT_BOTRIGHT ).GetPosition();
336 
337  pinEditedCorner( getEditedPointIndex(), Mils2iu( 1 ), Mils2iu( 1 ),
338  topLeft, topRight, botLeft, botRight );
339 
340  rect->SetStart( (wxPoint) topLeft );
341  rect->SetEnd( (wxPoint) botRight );
342  break;
343  }
344 
345  default:
346  break;
347  }
348 
349  getView()->Update( item );
350  m_frame->SetMsgPanel( item );
351 }
352 
353 
355 {
356  if( !m_editPoints )
357  return;
358 
359  EDA_ITEM* item = m_editPoints->GetParent();
360 
361  if( !item )
362  return;
363 
364  switch( item->Type() )
365  {
366  case WSG_LINE_T:
367  {
368  WS_DRAW_ITEM_LINE* line = (WS_DRAW_ITEM_LINE*) item;
369 
370  m_editPoints->Point( LINE_START ).SetPosition( line->GetStart() );
371  m_editPoints->Point( LINE_END ).SetPosition( line->GetEnd() );
372  break;
373  }
374 
375  case WSG_RECT_T:
376  {
377  WS_DRAW_ITEM_RECT* rect = (WS_DRAW_ITEM_RECT*) item;
378  wxPoint topLeft = rect->GetPosition();
379  wxPoint botRight = rect->GetEnd();
380 
381  m_editPoints->Point( RECT_TOPLEFT ).SetPosition( (VECTOR2I) topLeft );
382  m_editPoints->Point( RECT_TOPRIGHT ).SetPosition( VECTOR2I( botRight.x, topLeft.y ) );
383  m_editPoints->Point( RECT_BOTLEFT ).SetPosition( VECTOR2I( topLeft.x, botRight.y ) );
384  m_editPoints->Point( RECT_BOTRIGHT ).SetPosition( (VECTOR2I) botRight );
385  break;
386  }
387 
388  default:
389  break;
390  }
391 
392  getView()->Update( m_editPoints.get() );
393 }
394 
395 
397 {
399 
400  if( aPoint )
401  {
402  m_frame->GetCanvas()->SetCurrentCursor( wxCURSOR_ARROW );
403  controls->ForceCursorPosition( true, aPoint->GetPosition() );
404  controls->ShowCursor( true );
405  }
406  else
407  {
408  if( m_frame->ToolStackIsEmpty() )
409  controls->ShowCursor( false );
410 
411  controls->ForceCursorPosition( false );
412  }
413 
414  m_editedPoint = aPoint;
415 }
416 
417 
419 {
420  updatePoints();
421  return 0;
422 }
423 
424 
426 {
430 }
431 
432 
const wxPoint & GetStart() const
Definition: ws_draw_item.h:211
virtual void ShowCursor(bool aEnabled)
Function ShowCursor() Enables or disables display of cursor.
const wxPoint & GetEnd() const
Definition: ws_draw_item.h:213
static const TOOL_EVENT SelectedEvent
Definition: actions.h:203
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:164
Model changes (required full reload)
Definition: tool_base.h:82
const wxPoint & GetEnd() const
Definition: ws_draw_item.h:133
void SetStart(wxPoint aPos)
Definition: ws_draw_item.h:132
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)
wxPoint GetPosition() const override
Definition: ws_draw_item.h:216
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:212
bool IsMotion() const
Definition: tool_event.h:306
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:594
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:207
bool IsNew() const
Definition: base_struct.h:199
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:214
virtual VECTOR2I GetPosition() const
Function GetPosition()
Definition: edit_points.h:69
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:131
TOOL_EVENT.
Definition: tool_event.h:171
void updateItem() const
Updates item's points with edit points.
bool ToolStackIsEmpty()
Definition: tools_holder.h:84
VIEW_CONTROLS is an interface for classes handling user events controlling the view behaviour (such a...
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 bool IsType(const KICAD_T aScanTypes[]) const
Function IsType Checks whether the item is one of the listed types.
Definition: base_struct.h:262
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)
int Size() const
Returns the number of selected parts.
Definition: selection.h:127
EDA_ITEM is a base class for most all the KiCad significant classes, used in schematics and boards.
Definition: base_struct.h:159
RESET_REASON
Determines the reason of reset for a tool
Definition: tool_base.h:79
void SaveCopyInUndoList()
Save a copy of the description (in a S expr string) for Undo/redo commands.
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
EDIT_POINT.
Definition: edit_points.h:46
KIGFX::VIEW_CONTROLS * getViewControls() const
Function getViewControls()
Definition: tool_base.cpp:42
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
static std::shared_ptr< EDIT_POINTS > Make(EDA_ITEM *aItem, SCH_BASE_FRAME *frame)
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:184
KICAD_T Type() const
Function Type()
Definition: base_struct.h:193
void SetEnd(wxPoint aPos) override
Definition: ws_draw_item.h:134
virtual void SetPosition(const VECTOR2I &aPosition)
Function SetPosition()
Definition: edit_points.h:106