KiCad PCB EDA Suite
pl_drawing_tools.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 <class_draw_panel_gal.h>
26 #include <confirm.h>
27 #include <view/view_group.h>
28 #include <view/view_controls.h>
29 #include <view/view.h>
30 #include <tool/tool_manager.h>
31 #include <bitmaps.h>
34 
36 #include "pl_editor_frame.h"
37 #include "pl_editor_id.h"
38 #include "pl_point_editor.h"
39 #include "tools/pl_actions.h"
41 #include "tools/pl_drawing_tools.h"
42 
44  TOOL_INTERACTIVE( "plEditor.InteractiveDrawing" ),
45  m_frame( nullptr ),
46  m_selectionTool( nullptr )
47 {
48 }
49 
50 
52 {
53  m_frame = getEditFrame<PL_EDITOR_FRAME>();
55 
56  auto& ctxMenu = m_menu.GetMenu();
57 
58  // cancel current tool goes in main context menu at the top if present
60  ctxMenu.AddSeparator( 1 );
61 
62  // Finally, add the standard zoom/grid items
64 
65  return true;
66 }
67 
68 
70 {
71  if( aReason == MODEL_RELOAD )
72  m_frame = getEditFrame<PL_EDITOR_FRAME>();
73 }
74 
75 
77 {
79  VECTOR2I cursorPos;
80  DS_DRAW_ITEM_BASE* item = nullptr;
81  bool isText = aEvent.IsAction( &PL_ACTIONS::placeText );
82 
84 
85  std::string tool = aEvent.GetCommandStr().get();
86  m_frame->PushTool( tool );
87 
88  auto setCursor =
89  [&]()
90  {
91  if( item )
93  else
95  };
96 
97 
98  Activate();
99  // Must be done after Activate() so that it gets set into the correct context
100  getViewControls()->ShowCursor( true );
101  // Set initial cursor
102  setCursor();
103 
104  // Prime the pump
105  if( aEvent.HasPosition() || ( !aEvent.IsReactivate() && isText ) )
107 
108  // Main loop: keep receiving events
109  while( TOOL_EVENT* evt = Wait() )
110  {
111  setCursor();
112 
113  cursorPos = getViewControls()->GetCursorPosition( !evt->DisableGridSnapping() );
114 
115  auto cleanup =
116  [&] ()
117  {
119  item = nullptr;
120 
121  // There's nothing to roll-back, but we still need to pop the undo stack
122  // This also deletes the item being placed.
124  };
125 
126  if( evt->IsCancelInteractive() )
127  {
128  if( item )
129  cleanup();
130  else
131  {
132  m_frame->PopTool( tool );
133  break;
134  }
135  }
136  else if( evt->IsActivate() )
137  {
138  if( item )
139  cleanup();
140 
141  if( evt->IsMoveTool() )
142  {
143  // leave ourselves on the stack so we come back after the move
144  break;
145  }
146  else
147  {
148  m_frame->PopTool( tool );
149  break;
150  }
151  }
152  else if( evt->IsClick( BUT_LEFT ) )
153  {
154  // First click creates...
155  if( !item )
156  {
157  DS_DATA_ITEM* dataItem = m_frame->AddDrawingSheetItem( type );
158 
159  if( dataItem ) // dataItem = nullptr can happens if the command was cancelled
160  {
162 
164 
165  item = dataItem->GetDrawItems()[0];
166  item->SetFlags( IS_NEW | IS_MOVING );
167 
168  // Select the item but don't inform other tools (to prevent the Properties
169  // panel from updating the item before it has been placed)
170  m_selectionTool->AddItemToSel( item, true );
171 
172  // update the cursor so it looks correct before another event
173  setCursor();
174  }
175  }
176  // ... and second click places:
177  else
178  {
179  item->GetPeer()->MoveStartPointToUi( (wxPoint) cursorPos );
180  item->SetPosition( item->GetPeer()->GetStartPosUi( 0 ) );
181  item->ClearEditFlags();
182  getView()->Update( item );
183 
184  // Now we re-select and inform other tools, so that the Properties panel
185  // is updated.
187  m_selectionTool->AddItemToSel( item, false );
188 
189  item = nullptr;
190 
191  m_frame->OnModify();
192  }
193  }
194  else if( evt->IsClick( BUT_RIGHT ) )
195  {
196  // Warp after context menu only if dragging...
197  if( !item )
199 
201  }
202  else if( item && ( evt->IsAction( &ACTIONS::refreshPreview ) || evt->IsMotion() ) )
203  {
204  item->GetPeer()->MoveStartPointToUi( (wxPoint) cursorPos );
205  item->SetPosition( item->GetPeer()->GetStartPosUi( 0 ) );
206  getView()->Update( item );
207  }
208  else
209  {
210  evt->SetPassEvent();
211  }
212 
213  // Enable autopanning and cursor capture only when there is an item to be placed
214  getViewControls()->SetAutoPan( item != nullptr );
215  getViewControls()->CaptureCursor( item != nullptr );
216  }
217 
218  getViewControls()->SetAutoPan( false );
219  getViewControls()->CaptureCursor( false );
221  return 0;
222 }
223 
224 
226 {
228  DS_DRAW_ITEM_BASE* item = nullptr;
229 
230  // We might be running as the same shape in another co-routine. Make sure that one
231  // gets whacked.
233 
235 
236  std::string tool = aEvent.GetCommandStr().get();
237  m_frame->PushTool( tool );
238 
239  auto setCursor =
240  [&]()
241  {
243  };
244 
245  Activate();
246  // Must be done after Activate() so that it gets set into the correct context
247  getViewControls()->ShowCursor( true );
248  // Set initial cursor
249  setCursor();
250 
251  // Prime the pump
252  if( aEvent.HasPosition() )
254 
255  // Main loop: keep receiving events
256  while( TOOL_EVENT* evt = Wait() )
257  {
258  setCursor();
259 
260  VECTOR2I cursorPos = getViewControls()->GetCursorPosition( !evt->DisableGridSnapping() );
261 
262  if( evt->IsCancelInteractive() || evt->IsActivate() )
263  {
265 
266  if( item )
267  {
268  item = nullptr;
269 
270  // Pop the undo stack and delete the item being placed
272  }
273  else if( evt->IsCancelInteractive() )
274  {
275  break;
276  }
277 
278  if( evt->IsActivate() && !evt->IsPointEditor() && !evt->IsMoveTool() )
279  break;
280  }
281  else if( evt->IsClick( BUT_LEFT ) )
282  {
283  if( !item ) // start drawing
284  {
287 
288  DS_DATA_ITEM* dataItem = m_frame->AddDrawingSheetItem( type );
289  dataItem->MoveToUi( (wxPoint) cursorPos );
290 
291  item = dataItem->GetDrawItems()[0];
292  item->SetFlags( IS_NEW );
293 
294  // Select the item but don't inform other tools (to prevent the Properties
295  // panel from updating the item before it has been placed)
296  m_selectionTool->AddItemToSel( item, true );
297  }
298  else // finish drawing
299  {
300  // Now we re-select and inform other tools, so that the Properties panel
301  // is updated.
303  m_selectionTool->AddItemToSel( item, false );
304 
305  item->ClearEditFlags();
306  item = nullptr;
307 
308  // Activate point editor immediately to allow resizing of the item just created
310 
311  m_frame->OnModify();
312  }
313  }
314  else if( evt->IsAction( &ACTIONS::refreshPreview ) || evt->IsMotion() )
315  {
316  if( item )
317  {
318  item->GetPeer()->MoveEndPointToUi( (wxPoint) cursorPos );
319  item->SetEnd( item->GetPeer()->GetEndPosUi( 0 ) );
320  getView()->Update( item );
321  }
322  }
323  else if( evt->IsClick( BUT_RIGHT ) )
324  {
325  // Warp after context menu only if dragging...
326  if( !item )
328 
330  }
331  else
332  {
333  evt->SetPassEvent();
334  }
335 
336  // Enable autopanning and cursor capture only when there is a shape being drawn
337  getViewControls()->SetAutoPan( item != nullptr );
338  getViewControls()->CaptureCursor( item != nullptr );
339  }
340 
341  getViewControls()->SetAutoPan( false );
342  getViewControls()->CaptureCursor( false );
344  m_frame->PopTool( tool );
345  return 0;
346 }
347 
348 
350 {
355 }
virtual void ShowCursor(bool aEnabled)
Enable or disables display of cursor.
static bool ShowAlways(const SELECTION &aSelection)
The default condition function (always returns true).
void AddStandardSubMenus(TOOL_MENU &aMenu)
Construct a "basic" menu for a tool, containing only items that apply to all tools (e....
TOOL_MENU m_menu
The functions below are not yet implemented - their interface may change.
void SetCurrentCursor(KICURSOR aCursor)
Set the current cursor shape for this panel.
void setTransitions() override
< Set up handlers for various events.
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
#define IS_NEW
New item, just created.
This file is part of the common library.
virtual void SetPosition(const wxPoint &aPos)
Definition: eda_item.h:253
static TOOL_ACTION drawLine
Definition: pl_actions.h:61
static TOOL_ACTION placeImage
Definition: pl_actions.h:59
CONDITIONAL_MENU & GetMenu()
Definition: tool_menu.cpp:46
TOOL_MANAGER * m_toolMgr
Definition: tool_base.h:214
static TOOL_ACTION cancelInteractive
Definition: actions.h:62
virtual void PushTool(const std::string &actionName)
NB: the definition of "tool" is different at the user level.
void SetFlags(EDA_ITEM_FLAGS aMask)
Definition: eda_item.h:153
bool RunAction(const std::string &aActionName, bool aNow=false, T aParam=NULL)
Run the specified action.
Definition: tool_manager.h:143
static TOOL_ACTION placeText
Definition: pl_actions.h:58
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).
int AddItemToSel(const TOOL_EVENT &aEvent)
void DeactivateTool()
Deactivate the currently active tool.
PL_SELECTION & GetSelection()
Return the set of currently selected items.
bool IsAction(const TOOL_ACTION *aAction) const
Test if the event contains an action issued upon activation of the given TOOL_ACTION.
Definition: tool_event.cpp:88
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 PlaceItem(const TOOL_EVENT &aEvent)
#define IS_MOVING
Item being moved.
int DrawShape(const TOOL_EVENT &aEvent)
virtual void PopTool(const std::string &actionName)
virtual void CaptureCursor(bool aEnabled)
Force the cursor to stay within the drawing panel area.
T Parameter() const
Return a non-standard parameter assigned to the event.
Definition: tool_event.h:432
bool Init() override
Init() is called once upon a registration of the tool.
Generic, UI-independent tool event.
Definition: tool_event.h:152
const std::vector< DS_DRAW_ITEM_BASE * > & GetDrawItems() const
Definition: ds_data_item.h:110
static TOOL_ACTION drawRectangle
Definition: pl_actions.h:60
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.
PL_SELECTION_TOOL * m_selectionTool
static TOOL_ACTION clearSelection
Clear the current selection.
Definition: pl_actions.h:43
OPT< std::string > GetCommandStr() const
Definition: tool_event.h:460
void MoveStartPointToUi(const wxPoint &aPosition)
Move the starting point of the item to a new position.
DS_DATA_ITEM * GetPeer() const
Definition: ds_draw_item.h:63
Drawing sheet structure type definitions.
Definition: ds_data_item.h:95
void VetoContextMenuMouseWarp()
Disable mouse warping after the current context menu is closed.
Definition: tool_manager.h:422
RESET_REASON
Determine the reason of reset for a tool.
Definition: tool_base.h:77
bool IsReactivate() const
Definition: tool_event.h:252
void SaveCopyInUndoList()
Save a copy of the description (in a S expr string) for Undo/redo commands.
void Activate()
Run the tool.
void Reset(RESET_REASON aReason) override
Bring the tool to a known, initial state.
bool HasPosition() const
Definition: tool_event.h:240
KIGFX::VIEW_CONTROLS * getViewControls() const
Return the instance of VIEW_CONTROLS object used in the application.
Definition: tool_base.cpp:42
void MoveToUi(const wxPoint &aPosition)
Move item to a new position.
PL_EDITOR_FRAME * m_frame
void ClearEditFlags()
Definition: eda_item.h:172
void RollbackFromUndo()
Apply the last command in Undo List without stacking a Redo.
DS_DATA_ITEM * AddDrawingSheetItem(int aType)
Add a new item to the drawing sheet item list.
void ShowContextMenu(SELECTION &aSelection)
Helper function to set and immediately show a CONDITIONAL_MENU in concert with the given SELECTION.
Definition: tool_menu.cpp:59
static TOOL_ACTION refreshPreview
Definition: actions.h:106
VECTOR2D GetCursorPosition() const
Return the current cursor position in world coordinates.
static TOOL_ACTION cursorClick
Definition: actions.h:123
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:1512
const wxPoint GetStartPosUi(int ii=0) const