KiCad PCB EDA Suite
Loading...
Searching...
No Matches
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 The 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, see <https://www.gnu.org/licenses/>.
19 */
20
22#include <confirm.h>
23#include <view/view_controls.h>
24#include <tool/tool_manager.h>
25#include <bitmaps.h>
29
30#include "pl_editor_frame.h"
31#include "tools/pl_actions.h"
34#include "pgm_base.h"
35
37 TOOL_INTERACTIVE( "plEditor.InteractiveDrawing" ),
38 m_frame( nullptr ),
39 m_selectionTool( nullptr )
40{
41}
42
43
47
48
50{
53
54 auto& ctxMenu = m_menu->GetMenu();
55
56 // cancel current tool goes in main context menu at the top if present
58 ctxMenu.AddSeparator( 1 );
59
60 // Finally, add the standard zoom/grid items
61 m_frame->AddStandardSubMenus( *m_menu.get() );
62
63 return true;
64}
65
66
68{
69 if( aReason != REDRAW )
70 m_pendingItem.reset();
71
72 if( aReason == MODEL_RELOAD )
74}
75
76
78{
80 VECTOR2I cursorPos;
81 bool isText = aEvent.IsAction( &PL_ACTIONS::placeText );
82 DS_DATA_ITEM* item = nullptr;
83
85
86 TOOL_EVENT originalEvent = aEvent; // This can change out from under us when the event loop runs
87 SCOPED_TOOL_PUSHER raii( m_frame, originalEvent );
88
89 auto setCursor =
90 [&]()
91 {
92 if( item )
93 m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::PLACE );
94 else if( isText )
95 {
96 m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::TEXT );
97 }
98 else if( aEvent.IsAction( &PL_ACTIONS::placeImage ) )
99 {
100 m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::ARROW );
101 }
102 else
103 {
104 m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::PENCIL );
105 }
106 };
107
108 auto cleanup =
109 [&]()
110 {
111 getView()->Remove( item->GetDrawItems()[0] );
112 item = nullptr;
113 m_pendingItem.reset();
114 };
115
116 auto createPending =
117 [&]() -> bool
118 {
119 m_pendingItem.reset( m_frame->CreateDrawingSheetItem( type ) );
120 item = m_pendingItem.get();
121
122 if( !item )
123 return false;
124
125 item->MoveToIU( getViewControls()->GetCursorPosition() );
126
127 DS_DRAW_ITEM_BASE* drawItem = item->GetDrawItems()[0];
128 drawItem->SetFlags( IS_NEW | IS_MOVING );
129 getView()->Update( drawItem );
130
131 setCursor();
132 return true;
133 };
134
135 Activate();
136 // Must be done after Activate() so that it gets set into the correct context
137 getViewControls()->ShowCursor( true );
138 // Set initial cursor
139 setCursor();
140
141 if( isText )
142 createPending();
143
144 if( aEvent.HasPosition() )
145 m_toolMgr->PrimeTool( aEvent.Position() );
146
147 // Main loop: keep receiving events
148 while( TOOL_EVENT* evt = Wait() )
149 {
150 setCursor();
151 cursorPos = getViewControls()->GetCursorPosition( !evt->DisableGridSnapping() );
152
153 if( evt->IsCancelInteractive() || ( !isText && item && evt->IsAction( &ACTIONS::undo ) ) )
154 {
155 bool wasPending = item != nullptr;
156
157 if( wasPending )
158 cleanup();
159
160 if( isText || !wasPending )
161 break;
162 }
163 else if( evt->IsActivate() )
164 {
165 if( item )
166 cleanup();
167
168 if( evt->IsMoveTool() )
169 {
170 // Make sure we come back after the move tool runs
171 m_frame->PushTool( originalEvent );
172 }
173
174 break;
175 }
176 else if( evt->IsClick( BUT_LEFT ) )
177 {
178 bool placeItem = item != nullptr;
179
180 if( !item )
181 {
183
184 if( createPending() )
185 {
186 // Text is a single-click-place. All others are first-click-creates,
187 // second-click-places.
188 placeItem = isText;
189 }
190 }
191
192 if( item && placeItem )
193 {
194 m_frame->SaveCopyInUndoList();
196
197 item->MoveStartPointToIU( cursorPos );
198
199 DS_DRAW_ITEM_BASE* drawItem = item->GetDrawItems()[0];
200 drawItem->SetPosition( item->GetStartPosIU( 0 ) );
201 drawItem->ClearEditFlags();
202
203 // A full canvas rebuild drops the pending item from the view, so a plain
204 // view update is not enough to bring it back
205 getView()->Remove( drawItem );
206 getView()->Add( drawItem );
207
208 // Now we select and inform other tools, so that the Properties panel
209 // is updated.
211 m_selectionTool->AddItemToSel( drawItem, false );
212
213 item = nullptr;
214
215 m_frame->OnModify();
216
217 if( isText )
218 createPending();
219 }
220 }
221 else if( evt->IsClick( BUT_RIGHT ) )
222 {
223 // Warp after context menu only if dragging...
224 if( !item )
225 m_toolMgr->VetoContextMenuMouseWarp();
226
227 m_menu->ShowContextMenu( m_selectionTool->GetSelection() );
228 }
229 else if( item && ( evt->IsAction( &ACTIONS::refreshPreview ) || evt->IsMotion() ) )
230 {
231 item->MoveStartPointToIU( cursorPos );
232
233 DS_DRAW_ITEM_BASE* drawItem = item->GetDrawItems()[0];
234 drawItem->SetPosition( item->GetStartPosIU( 0 ) );
235
236 getView()->Remove( drawItem );
237 getView()->Add( drawItem );
238 }
239 else
240 {
241 evt->SetPassEvent();
242 }
243
244 // Enable autopanning and cursor capture only for two click placements
245 getViewControls()->SetAutoPan( !isText && item != nullptr );
246 getViewControls()->CaptureCursor( !isText && item != nullptr );
247 }
248
249 getViewControls()->SetAutoPan( false );
250 getViewControls()->CaptureCursor( false );
251 m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::ARROW );
252 return 0;
253}
254
255
257{
259 DS_DRAW_ITEM_BASE* item = nullptr;
260
261 // We might be running as the same shape in another co-routine. Make sure that one
262 // gets whacked.
263 m_toolMgr->DeactivateTool();
264
266
267 TOOL_EVENT originalEvent = aEvent; // This can change out from under us when the event loop runs
268 SCOPED_TOOL_PUSHER raii( m_frame, originalEvent );
269
270 auto setCursor =
271 [&]()
272 {
273 m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::PENCIL );
274 };
275
276 Activate();
277 // Must be done after Activate() so that it gets set into the correct context
278 getViewControls()->ShowCursor( true );
279 // Set initial cursor
280 setCursor();
281
282 if( aEvent.HasPosition() )
283 m_toolMgr->PrimeTool( aEvent.Position() );
284
285 // Main loop: keep receiving events
286 while( TOOL_EVENT* evt = Wait() )
287 {
288 setCursor();
289
290 VECTOR2I cursorPos = getViewControls()->GetCursorPosition( !evt->DisableGridSnapping() );
291
292 if( evt->IsCancelInteractive() || ( item && evt->IsAction( &ACTIONS::undo ) ) )
293 {
295
296 if( item )
297 {
298 item = nullptr;
299
300 // Pop the undo stack and delete the item being placed
301 m_frame->RollbackFromUndo();
302 }
303 else
304 {
305 break;
306 }
307 }
308 else if( evt->IsActivate() )
309 {
310 if( item )
311 {
312 item = nullptr;
313
314 // Pop the undo stack and delete the item being placed
315 m_frame->RollbackFromUndo();
316 continue;
317 }
318
319 if( evt->IsPointEditor() || evt->IsMoveTool() )
320 {
321 // Make sure we come back after the move tool is done
322 m_frame->PushTool( originalEvent );
323 break;
324 }
325 }
326 else if( evt->IsClick( BUT_LEFT ) )
327 {
328 if( !item ) // start drawing
329 {
330 m_frame->SaveCopyInUndoList();
332
333 DS_DATA_ITEM* dataItem = m_frame->CreateDrawingSheetItem( type );
335 dataItem->MoveToIU( cursorPos );
336
337 item = dataItem->GetDrawItems()[0];
338 item->SetFlags( IS_NEW );
339
340 // Select the item but don't inform other tools (to prevent the Properties
341 // panel from updating the item before it has been placed)
342 m_selectionTool->AddItemToSel( item, true );
343 }
344 else // finish drawing
345 {
346 // Now we re-select and inform other tools, so that the Properties panel
347 // is updated.
349 m_selectionTool->AddItemToSel( item, false );
350
351 item->ClearEditFlags();
352 item = nullptr;
353
354 // Activate point editor immediately to allow resizing of the item just created
356
357 m_frame->OnModify();
358 }
359 }
360 else if( evt->IsAction( &ACTIONS::refreshPreview ) || evt->IsMotion() )
361 {
362 if( item )
363 {
364 item->GetPeer()->MoveEndPointToIU( cursorPos );
365 item->SetEnd( item->GetPeer()->GetEndPosIU( 0 ) );
366 getView()->Update( item );
367 }
368 }
369 else if( evt->IsClick( BUT_RIGHT ) )
370 {
371 // Warp after context menu only if dragging...
372 if( !item )
373 m_toolMgr->VetoContextMenuMouseWarp();
374
375 m_menu->ShowContextMenu( m_selectionTool->GetSelection() );
376 }
377 else
378 {
379 evt->SetPassEvent();
380 }
381
382 // Enable autopanning and cursor capture only when there is a shape being drawn
383 getViewControls()->SetAutoPan( item != nullptr );
384 getViewControls()->CaptureCursor( item != nullptr );
385 }
386
387 getViewControls()->SetAutoPan( false );
388 getViewControls()->CaptureCursor( false );
389 m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::ARROW );
390 return 0;
391}
392
393
static TOOL_ACTION cancelInteractive
Definition actions.h:68
static TOOL_ACTION undo
Definition actions.h:71
static TOOL_ACTION activatePointEditor
Definition actions.h:267
static TOOL_ACTION selectionClear
Clear the current selection.
Definition actions.h:220
static TOOL_ACTION refreshPreview
Definition actions.h:155
Drawing sheet structure type definitions.
void MoveStartPointToIU(const VECTOR2I &aPosition)
Move the starting point of the item to a new position.
void MoveToIU(const VECTOR2I &aPosition)
Move item to a new position.
const VECTOR2I GetStartPosIU(int ii=0) const
const std::vector< DS_DRAW_ITEM_BASE * > & GetDrawItems() const
static DS_DATA_MODEL & GetTheInstance()
Return the instance of DS_DATA_MODEL used in the application.
void Append(DS_DATA_ITEM *aItem)
Base class to handle basic graphic items.
virtual void ClearEditFlags()
Definition eda_item.h:178
virtual void SetPosition(const VECTOR2I &aPos)
Definition eda_item.h:349
void SetFlags(EDA_ITEM_FLAGS aMask)
Definition eda_item.h:158
virtual void CaptureCursor(bool aEnabled)
Force the cursor to stay within the drawing panel area.
virtual void ShowCursor(bool aEnabled)
Enable or disables display of cursor.
VECTOR2D GetCursorPosition() const
Return the current cursor position in world coordinates.
virtual void SetAutoPan(bool aEnabled)
Turn on/off auto panning (this feature is used when there is a tool active (eg.
virtual void Add(VIEW_ITEM *aItem, int aDrawPriority=-1)
Add a VIEW_ITEM to the view.
Definition view.cpp:301
virtual void Remove(VIEW_ITEM *aItem)
Remove a VIEW_ITEM from the view.
Definition view.cpp:416
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:1852
static TOOL_ACTION placeImage
Definition pl_actions.h:37
static TOOL_ACTION drawRectangle
Definition pl_actions.h:38
static TOOL_ACTION placeText
Definition pl_actions.h:36
static TOOL_ACTION drawLine
Definition pl_actions.h:39
PL_SELECTION_TOOL * m_selectionTool
int PlaceItem(const TOOL_EVENT &aEvent)
int DrawShape(const TOOL_EVENT &aEvent)
PL_EDITOR_FRAME * m_frame
void setTransitions() override
< Set up handlers for various events.
std::unique_ptr< DS_DATA_ITEM > m_pendingItem
bool Init() override
Init() is called once upon a registration of the tool.
void Reset(RESET_REASON aReason) override
Bring the tool to a known, initial state.
static bool ShowAlways(const SELECTION &aSelection)
The default condition function (always returns true).
T * getEditFrame() const
Return the application window object, casted to requested user type.
Definition tool_base.h:182
KIGFX::VIEW_CONTROLS * getViewControls() const
Return the instance of VIEW_CONTROLS object used in the application.
Definition tool_base.cpp:40
TOOL_MANAGER * m_toolMgr
Definition tool_base.h:220
KIGFX::VIEW * getView() const
Returns the instance of #VIEW object used in the application.
Definition tool_base.cpp:34
RESET_REASON
Determine the reason of reset for a tool.
Definition tool_base.h:74
@ REDRAW
Full drawing refresh.
Definition tool_base.h:79
@ MODEL_RELOAD
Model changes (the sheet for a schematic)
Definition tool_base.h:76
Generic, UI-independent tool event.
Definition tool_event.h:167
bool HasPosition() const
Returns if it this event has a valid position (true for mouse events and context-menu or hotkey-based...
Definition tool_event.h:256
const VECTOR2D Position() const
Return mouse cursor position in world coordinates.
Definition tool_event.h:289
bool IsAction(const TOOL_ACTION *aAction) const
Test if the event contains an action issued upon activation of the given TOOL_ACTION.
T Parameter() const
Return a parameter assigned to the event.
Definition tool_event.h:469
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).
std::unique_ptr< TOOL_MENU > m_menu
The functions below are not yet implemented - their interface may change.
TOOL_INTERACTIVE(TOOL_ID aId, const std::string &aName)
Create a tool with given id & name.
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.
void Activate()
Run the tool.
This file is part of the common library.
@ PLACE
Definition cursors.h:94
@ ARROW
Definition cursors.h:42
@ PENCIL
Definition cursors.h:48
#define IS_NEW
New item, just created.
#define IS_MOVING
Item being moved.
see class PGM_BASE
@ BUT_LEFT
Definition tool_event.h:128
@ BUT_RIGHT
Definition tool_event.h:129
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:683