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  WS_DRAW_ITEM_LINE* line = (WS_DRAW_ITEM_LINE*) aItem;
75  points->AddPoint( line->GetStart() );
76  points->AddPoint( line->GetEnd() );
77  break;
78  }
79  case WSG_RECT_T:
80  {
81  WS_DRAW_ITEM_RECT* rect = (WS_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->Modifier( MD_ALT ) ) );
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  WS_DATA_ITEM* dataItem = static_cast<WS_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  WS_DRAW_ITEM_LINE* line = (WS_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( WS_DRAW_ITEM_BASE* draw_item : dataItem->GetDrawItems() )
342  {
343  WS_DRAW_ITEM_LINE* draw_line = static_cast<WS_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  WS_DRAW_ITEM_RECT* rect = (WS_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 
370  for( WS_DRAW_ITEM_BASE* draw_item : dataItem->GetDrawItems() )
371  {
372  WS_DRAW_ITEM_RECT* draw_rect = (WS_DRAW_ITEM_RECT*) draw_item;
373 
374  draw_rect->SetStart( draw_rect->GetStart() + move_startpoint );
375  draw_rect->SetEnd( draw_rect->GetEnd() + move_endpoint );
376  getView()->Update( draw_item );
377  }
378 
379  break;
380  }
381 
382  default:
383  break;
384  }
385 
386  m_frame->SetMsgPanel( item );
387 
388  // The Properties frame will be updated. Avoid flicker during update:
389  m_frame->GetPropertiesFrame()->Freeze();
391  m_frame->GetPropertiesFrame()->Thaw();
392 }
393 
394 
396 {
397  if( !m_editPoints )
398  return;
399 
400  EDA_ITEM* item = m_editPoints->GetParent();
401 
402  if( !item )
403  return;
404 
405  switch( item->Type() )
406  {
407  case WSG_LINE_T:
408  {
409  WS_DRAW_ITEM_LINE* line = (WS_DRAW_ITEM_LINE*) item;
410 
411  m_editPoints->Point( LINE_START ).SetPosition( line->GetStart() );
412  m_editPoints->Point( LINE_END ).SetPosition( line->GetEnd() );
413  break;
414  }
415 
416  case WSG_RECT_T:
417  {
418  WS_DRAW_ITEM_RECT* rect = (WS_DRAW_ITEM_RECT*) item;
419  wxPoint topLeft = rect->GetPosition();
420  wxPoint botRight = rect->GetEnd();
421 
422  m_editPoints->Point( RECT_TOPLEFT ).SetPosition( (VECTOR2I) topLeft );
423  m_editPoints->Point( RECT_TOPRIGHT ).SetPosition( VECTOR2I( botRight.x, topLeft.y ) );
424  m_editPoints->Point( RECT_BOTLEFT ).SetPosition( VECTOR2I( topLeft.x, botRight.y ) );
425  m_editPoints->Point( RECT_BOTRIGHT ).SetPosition( (VECTOR2I) botRight );
426  break;
427  }
428 
429  default:
430  break;
431  }
432 
433  getView()->Update( m_editPoints.get() );
434 }
435 
436 
438 {
440 
441  if( aPoint )
442  {
444  controls->ForceCursorPosition( true, aPoint->GetPosition() );
445  controls->ShowCursor( true );
446  }
447  else
448  {
449  if( m_frame->ToolStackIsEmpty() )
450  controls->ShowCursor( false );
451 
452  controls->ForceCursorPosition( false );
453  }
454 
455  m_editedPoint = aPoint;
456 }
457 
458 
460 {
461  updatePoints();
462  return 0;
463 }
464 
465 
467 {
471 }
472 
473 
const wxPoint & GetStart() const
Definition: ws_draw_item.h:217
virtual void ShowCursor(bool aEnabled)
Function ShowCursor() Enables or disables display of cursor.
const wxPoint & GetEnd() const
Definition: ws_draw_item.h:219
PROPERTIES_FRAME * GetPropertiesFrame()
static const TOOL_EVENT SelectedEvent
Definition: actions.h:213
PL_EDITOR_FRAME * m_frame
void MoveEndPointToUi(wxPoint aPosition)
move the ending point of the item to a new position has meaning only for items defined by 2 points (s...
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:173
Work sheet structure type definitions.
Definition: ws_data_item.h:97
Model changes (required full reload)
Definition: tool_base.h:82
const wxPoint & GetEnd() const
Definition: ws_draw_item.h:137
void SetStart(wxPoint aPos)
Definition: ws_draw_item.h:136
This file is part of the common library.
VIEW_CONTROLS class definition.
static std::shared_ptr< EDIT_POINTS > Make(EDA_ITEM *aItem)
wxPoint GetPosition() const override
Definition: ws_draw_item.h:222
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:357
void SetStart(wxPoint aPos)
Definition: ws_draw_item.h:218
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()
void SetCurrentCursor(KICURSOR cursor)
Function SetCurrentCursor Set the current cursor shape for this panel.
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:218
bool IsNew() const
Definition: eda_item.h:187
const wxPoint GetStartPosUi(int ii=0) const
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:220
virtual VECTOR2I GetPosition() const
Function GetPosition()
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)
Updates which point is being edited.
void CopyPrmsFromItemToPanel(WS_DATA_ITEM *aItem)
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:135
TOOL_EVENT.
Definition: tool_event.h:171
void updateItem() const
Updates item's points with edit points.
bool ToolStackIsEmpty()
Definition: tools_holder.h:136
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: eda_item.h:250
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...
const std::vector< WS_DRAW_ITEM_BASE * > & GetDrawItems() const
Definition: ws_data_item.h:132
EDIT_POINT * m_editedPoint
Currently edited point, NULL if there is none.
int modifiedSelection(const TOOL_EVENT &aEvent)
void MoveStartPointToUi(wxPoint aPosition)
move the starting point of the item to a new position
const wxPoint GetEndPosUi(int ii=0) const
int Size() const
Returns the number of selected parts.
Definition: selection.h:126
EDA_ITEM is a base class for most all the KiCad significant classes used in schematics and boards.
Definition: eda_item.h:148
RESET_REASON
Determines the reason of reset for a tool
Definition: tool_base.h:79
Helper classes to handle basic graphic items used to draw/plot title blocks and frame references segm...
Definition: ws_draw_item.h:56
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:327
EDIT_POINT.
Definition: edit_points.h:45
KIGFX::VIEW_CONTROLS * getViewControls() const
Function getViewControls()
Definition: tool_base.cpp:42
VIEW.
Definition: view.h:63
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:201
virtual void Update(const VIEW_ITEM *aItem, int aUpdateFlags) const
For dynamic VIEWs, informs the associated VIEW that the graphical representation of this item has cha...
Definition: view.cpp:1513
KICAD_T Type() const
Function Type()
Definition: eda_item.h:181
void SetEnd(wxPoint aPos) override
Definition: ws_draw_item.h:138
virtual void SetPosition(const VECTOR2I &aPosition)
Function SetPosition()
Definition: edit_points.h:110