KiCad PCB EDA Suite
Loading...
Searching...
No Matches
sch_tool_base.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
21#include <tools/sch_tool_base.h>
22#include "increment.h"
23#include <math/vector2d.h>
24#include <tool/tool_event.h>
26#include <tool/tool_manager.h>
27#include <tool/tool_menu.h>
28#include <tool/actions.h>
30#include <sch_edit_frame.h>
31#include <sch_base_frame.h>
32#include <sch_view.h>
33#include <symbol_edit_frame.h>
34#include <sch_shape.h>
35#include <pin_layout_cache.h>
36#include <sch_commit.h>
37#include <tool/picker_tool.h>
38#include <view/view_controls.h>
39
40#include <schematic.h>
41
42
43template <class T>
44SCH_TOOL_BASE<T>::SCH_TOOL_BASE( const std::string& aName ) :
45 TOOL_INTERACTIVE( aName ),
46 m_frame( nullptr ),
47 m_view( nullptr ),
48 m_selectionTool( nullptr ),
49 m_isSymbolEditor( false ),
50 m_pickerItem( nullptr )
51{}
53
54template <class T>
58
59template <class T>
61{
66 // A basic context menu. Many (but not all) tools will choose to override this.
67 auto& ctxMenu = m_menu->GetMenu();
68
69 // cancel current tool goes in main context menu at the top if present
71 ctxMenu.AddSeparator( 1 );
72
73 // Finally, add the standard zoom/grid items
74 m_frame->AddStandardSubMenus( *m_menu.get() );
75
76 return true;
77}
78
79
80template <class T>
82{
83 if( aReason == MODEL_RELOAD || aReason == SUPERMODEL_RELOAD )
84 {
85 // Init variables used by every drawing tool
87 m_isSymbolEditor = dynamic_cast<SYMBOL_EDIT_FRAME*>( m_frame ) != nullptr;
88 }
90 m_view = static_cast<KIGFX::SCH_VIEW*>( getView() );
91}
93
94template <class T>
96{
97 return m_isSymbolEditor;
98}
99
100
101template <class T>
103{
104 static const std::vector<KICAD_T> incrementable = { SCH_LABEL_T,
107 SCH_PIN_T,
108 SCH_TEXT_T };
109
110 ACTIONS::INCREMENT param = { 1, 0 };
111
112 if( aEvent.HasParameter() )
113 param = aEvent.Parameter<ACTIONS::INCREMENT>();
114
115 SCH_SELECTION& selection = m_selectionTool->RequestSelection( incrementable );
116
117 if( selection.Empty() )
118 return 0;
119
120 KICAD_T type = selection.Front()->Type();
121 bool allSameType = true;
122
123 for( EDA_ITEM* item : selection )
124 {
125 if( item->Type() != type )
126 {
127 allSameType = false;
128 break;
129 }
130 }
131
132 // Incrementing multiple types at once seems confusing though it would work.
133 if( !allSameType )
134 return 0;
135
136 const VECTOR2I mousePosition = getViewControls()->GetMousePosition();
137
139 // In schematics, it's probably less common to be operating
140 // on pin numbers which are usually IOSQXZ-skippy.
141 incrementer.SetSkipIOSQXZ( m_isSymbolEditor );
142
143 // If we're coming via another action like 'Move', use that commit
144 SCH_COMMIT localCommit( m_toolMgr );
145 SCH_COMMIT* commit = dynamic_cast<SCH_COMMIT*>( aEvent.Commit() );
146
147 if( !commit )
148 commit = &localCommit;
149
150 const auto modifyItem =
151 [&]( EDA_ITEM& aItem )
152 {
153 // A preview item is not on a screen yet, and its placement records the undo step
154 if( aItem.IsNew() )
155 {
156 m_toolMgr->PostAction( ACTIONS::refreshPreview );
157 return;
158 }
159
160 commit->Modify( &aItem, m_frame->GetScreen() );
161 };
162
163 for( EDA_ITEM* item : selection )
164 {
165 switch( item->Type() )
166 {
167 case SCH_PIN_T:
168 {
169 SCH_PIN& pin = static_cast<SCH_PIN&>( *item );
170 PIN_LAYOUT_CACHE& layout = pin.GetLayoutCache();
171
172 bool found = false;
173 OPT_BOX2I bbox = layout.GetPinNumberBBox();
174
175 if( bbox && bbox->Contains( mousePosition ) )
176 {
177 std::optional<wxString> nextNumber = incrementer.Increment( pin.GetNumber(), param.Delta,
178 param.Index );
179
180 if( nextNumber )
181 {
182 modifyItem( pin );
183 pin.SetNumber( *nextNumber );
184 }
185
186 found = true;
187 }
188
189 if( !found )
190 {
191 bbox = layout.GetPinNameBBox();
192
193 if( bbox && bbox->Contains( mousePosition ) )
194 {
195 std::optional<wxString> nextName = incrementer.Increment( pin.GetName(), param.Delta,
196 param.Index );
197
198 if( nextName )
199 {
200 modifyItem( pin );
201 pin.SetName( *nextName );
202 }
203
204 found = true;
205 }
206 }
207 break;
208 }
209
210 case SCH_LABEL_T:
212 case SCH_HIER_LABEL_T:
213 case SCH_TEXT_T:
214 {
215 SCH_TEXT& label = static_cast<SCH_TEXT&>( *item );
216
217 std::optional<wxString> newLabel = incrementer.Increment( label.GetText(), param.Delta,
218 param.Index );
219
220 if( newLabel )
221 {
222 modifyItem( label );
223 label.SetText( *newLabel );
224 }
225
226 break;
227 }
228
229 default:
230 // No increment for other items
231 break;
232 }
233 }
234
235 // A caller such as the move tool owns its commit and pushes it once the whole edit ends
236 if( !localCommit.Empty() )
237 localCommit.Push( _( "Increment" ) );
238
239 if( selection.IsHover() )
241
242 return 0;
243}
244
245
246template <class T>
248{
249 PICKER_TOOL* picker = m_toolMgr->GetTool<PICKER_TOOL>();
250
252 m_pickerItem = nullptr;
253
254 // Deactivate other tools; particularly important if another PICKER is currently running
255 Activate();
256
257 picker->SetCursor( KICURSOR::REMOVE );
258 picker->SetSnapping( false );
259 picker->ClearHandlers();
260
261 picker->SetClickHandler(
262 [this]( const VECTOR2D& aPosition ) -> bool
263 {
264 if( m_pickerItem )
265 {
266 SCH_SELECTION_TOOL* selectionTool = m_toolMgr->GetTool<SCH_SELECTION_TOOL>();
267 selectionTool->UnbrightenItem( m_pickerItem );
268 selectionTool->AddItemToSel( m_pickerItem, true /*quiet mode*/ );
269 m_toolMgr->RunAction( ACTIONS::doDelete );
270 m_pickerItem = nullptr;
271 }
272
273 return true;
274 } );
275
276 picker->SetMotionHandler(
277 [this]( const VECTOR2D& aPos )
278 {
279 SCH_SELECTION_TOOL* selectionTool = m_toolMgr->GetTool<SCH_SELECTION_TOOL>();
280 SCH_COLLECTOR collector;
281
282 selectionTool->CollectHits( collector, aPos, SCH_COLLECTOR::DeletableItems );
283
284 // Remove unselectable items
285 for( int i = collector.GetCount() - 1; i >= 0; --i )
286 {
287 if( !selectionTool->Selectable( collector[ i ] ) )
288 collector.Remove( i );
289 }
290
291 if( collector.GetCount() > 1 )
292 selectionTool->GuessSelectionCandidates( collector, aPos );
293
294 EDA_ITEM* item = collector.GetCount() == 1 ? collector[ 0 ] : nullptr;
295
296 if( m_pickerItem != item )
297 {
298 if( m_pickerItem )
299 selectionTool->UnbrightenItem( m_pickerItem );
300
301 m_pickerItem = item;
302
303 if( m_pickerItem )
304 selectionTool->BrightenItem( m_pickerItem );
305 }
306 } );
307
308 picker->SetFinalizeHandler(
309 [this]( const int& aFinalState )
310 {
311 if( m_pickerItem )
312 m_toolMgr->GetTool<SCH_SELECTION_TOOL>()->UnbrightenItem( m_pickerItem );
313
314 // Wake the selection tool after exiting to ensure the cursor gets updated
316 } );
317
318 m_toolMgr->RunAction( ACTIONS::pickerTool, &aEvent );
319
320 return 0;
321}
322
323
324template <class T>
326{
327 SCH_BASE_FRAME* baseFrame = m_frame;
328
329 if( m_isSymbolEditor )
330 return static_cast<SYMBOL_EDIT_FRAME*>( baseFrame )->GetCurSymbol();
331
332 return &static_cast<SCH_EDIT_FRAME*>( baseFrame )->Schematic();
333}
334
335
336template <class T>
337void SCH_TOOL_BASE<T>::updateItem( EDA_ITEM* aItem, bool aUpdateRTree ) const
338{
339 m_frame->UpdateItem( aItem, false, aUpdateRTree );
340}
341
342
343template <class T>
344void SCH_TOOL_BASE<T>::saveCopyInUndoList( EDA_ITEM* aItem, UNDO_REDO aType, bool aAppend, bool aDirtyConnectivity )
345{
346 if( !aItem->IsSCH_ITEM() )
347 return;
348
349 SCH_ITEM* item = static_cast<SCH_ITEM*>( aItem );
350 bool selected = item->IsSelected();
351
352 // IS_SELECTED flag should not be set on undo items which were added for
353 // a drag operation.
354 if( selected && item->HasFlag( SELECTED_BY_DRAG ) )
355 item->ClearSelected();
356
357 if( SYMBOL_EDIT_FRAME* symbolEditFrame = dynamic_cast<SYMBOL_EDIT_FRAME*>( m_frame ) )
358 {
359 symbolEditFrame->SaveCopyInUndoList( wxEmptyString, dynamic_cast<LIB_SYMBOL*>( item ) );
360 }
361 else if( SCH_EDIT_FRAME* schematicFrame = dynamic_cast<SCH_EDIT_FRAME*>( m_frame ) )
362 {
363 schematicFrame->SaveCopyInUndoList( schematicFrame->GetScreen(), item, UNDO_REDO::CHANGED, aAppend );
364
365 if( aDirtyConnectivity )
366 {
367 if( !item->IsConnectivityDirty()
368 && item->Connection()
369 && ( item->Connection()->Name() == schematicFrame->GetHighlightedConnection()
370 || item->Connection()->HasDriverChanged() ) )
371 {
372 schematicFrame->DirtyHighlightedConnection();
373 }
374
375 item->SetConnectivityDirty();
376 }
377 }
378
379 if( selected && aItem->HasFlag( SELECTED_BY_DRAG ) )
380 aItem->SetSelected();
381}
382
383
384template class SCH_TOOL_BASE<SCH_BASE_FRAME>;
385template class SCH_TOOL_BASE<SCH_EDIT_FRAME>;
std::optional< BOX2I > OPT_BOX2I
Definition box2.h:918
static TOOL_ACTION cancelInteractive
Definition actions.h:68
static TOOL_ACTION pickerTool
Definition actions.h:249
static TOOL_ACTION selectionActivate
Activation of the selection tool.
Definition actions.h:210
static TOOL_ACTION doDelete
Definition actions.h:81
static TOOL_ACTION selectionClear
Clear the current selection.
Definition actions.h:220
static TOOL_ACTION refreshPreview
Definition actions.h:155
bool Empty() const
Definition commit.h:145
COMMIT & Modify(EDA_ITEM *aItem, BASE_SCREEN *aScreen=nullptr, RECURSE_MODE aRecurse=RECURSE_MODE::NO_RECURSE)
Modify a given item in the model.
Definition commit.h:102
A base class for most all the KiCad significant classes used in schematics and boards.
Definition eda_item.h:98
void ClearSelected()
Definition eda_item.h:153
bool IsSelected() const
Definition eda_item.h:134
void SetSelected()
Definition eda_item.h:150
bool HasFlag(EDA_ITEM_FLAGS aFlag) const
Definition eda_item.h:168
virtual const wxString & GetText() const
Return the string associated with the text object.
Definition eda_text.h:118
virtual void SetText(const wxString &aText)
Definition eda_text.cpp:236
bool IsSCH_ITEM() const
Definition view_item.h:97
Define a library symbol object.
Definition lib_symbol.h:114
void SetMotionHandler(MOTION_HANDLER aHandler)
Set a handler for mouse motion.
Definition picker_tool.h:92
void SetClickHandler(CLICK_HANDLER aHandler)
Set a handler for mouse click event.
Definition picker_tool.h:81
void SetSnapping(bool aSnap)
Definition picker_tool.h:65
void SetCursor(KICURSOR aCursor)
Definition picker_tool.h:63
void SetFinalizeHandler(FINALIZE_HANDLER aHandler)
Set a handler for the finalize event.
A pin layout helper is a class that manages the layout of the parts of a pin on a schematic symbol:
OPT_BOX2I GetPinNumberBBox()
Get the bounding box of the pin number, if there is one.
OPT_BOX2I GetPinNameBBox()
Get the bounding box of the pin name, if there is one.
A shim class between EDA_DRAW_FRAME and several derived classes: SYMBOL_EDIT_FRAME,...
static const std::vector< KICAD_T > DeletableItems
Commit for the schematic and symbol editors.
Definition sch_commit.h:54
void Push(const wxString &aMessage=wxEmptyString, int aCommitFlags=0) override
Execute the changes.
bool HasDriverChanged() const
wxString Name(bool aIgnoreSheet=false) const
Schematic editor (Eeschema) main window.
Base class for any item which can be embedded within the SCHEMATIC container class,...
Definition sch_item.h:170
void SetConnectivityDirty(bool aDirty=true)
Set the dirty flag.
Definition sch_item.cpp:314
bool IsConnectivityDirty() const
Definition sch_item.h:630
SCH_CONNECTION * Connection(const SCH_SHEET_PATH *aSheet=nullptr) const
Retrieve the connection associated with this object in the given sheet.
Definition sch_item.cpp:580
bool CollectHits(SCH_COLLECTOR &aCollector, const VECTOR2I &aWhere, const std::vector< KICAD_T > &aScanTypes={ SCH_LOCATE_ANY_T })
Collect one or more items at a given point.
void GuessSelectionCandidates(SCH_COLLECTOR &collector, const VECTOR2I &aPos)
Apply heuristics to try and determine a single object when multiple are found under the cursor.
bool Selectable(const EDA_ITEM *aItem, const VECTOR2I *aPos=nullptr, bool checkVisibilityOnly=false) const
Check conditions for an item to be selected.
A foundation class for a tool operating on a schematic or symbol.
void updateItem(EDA_ITEM *aItem, bool aUpdateRTree) const
Similar to getView()->Update(), but also updates the SCH_SCREEN's RTree.
int Increment(const TOOL_EVENT &aEvent)
void saveCopyInUndoList(EDA_ITEM *aItem, UNDO_REDO aType, bool aAppend=false, bool aDirtyConnectivity=true)
Similar to m_frame->SaveCopyInUndoList(), but also handles connectivity.
int InteractiveDelete(const TOOL_EVENT &aEvent)
bool IsSymbolEditor() const
Returns true if the tool is running in the symbol editor.
KIGFX::SCH_VIEW * m_view
bool Init() override
Init() is called once upon a registration of the tool.
EDA_ITEM * getDrawParent() const
Return the parent container for new draw-items in the active editor.
EDA_ITEM * m_pickerItem
void Reset(RESET_REASON aReason) override
Bring the tool to a known, initial state.
~SCH_TOOL_BASE() override
SCH_TOOL_BASE(const std::string &aName)
Create a tool with given name.
SCH_SELECTION_TOOL * m_selectionTool
static bool ShowAlways(const SELECTION &aSelection)
The default condition function (always returns true).
void BrightenItem(EDA_ITEM *aItem)
int AddItemToSel(const TOOL_EVENT &aEvent)
void UnbrightenItem(EDA_ITEM *aItem)
Heuristically increment a string's n'th part from the right.
Definition increment.h:44
The symbol library editor main window.
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
Definition tool_base.cpp:34
RESET_REASON
Determine the reason of reset for a tool.
Definition tool_base.h:74
@ MODEL_RELOAD
Model changes (the sheet for a schematic)
Definition tool_base.h:76
@ SUPERMODEL_RELOAD
For schematics, the entire schematic changed, not just the sheet.
Definition tool_base.h:77
Generic, UI-independent tool event.
Definition tool_event.h:167
bool HasParameter() const
Definition tool_event.h:460
COMMIT * Commit() const
Definition tool_event.h:279
T Parameter() const
Return a parameter assigned to the event.
Definition tool_event.h:484
std::unique_ptr< TOOL_MENU > m_menu
TOOL_INTERACTIVE(TOOL_ID aId, const std::string &aName)
Create a tool with given id & name.
void Activate()
Run the tool.
@ REMOVE
Definition cursors.h:50
#define _(s)
#define SELECTED_BY_DRAG
Item was algorithmically selected as a dragged item.
@ FRAME_SCH_SYMBOL_EDITOR
Definition frame_type.h:31
Increment event parameters.
Definition actions.h:328
STRING_INCREMENTER incrementer
KIBIS_PIN * pin
KICAD_T
The set of class identification values stored in EDA_ITEM::m_structType.
Definition typeinfo.h:70
@ SCH_LABEL_T
Definition typeinfo.h:163
@ SCH_HIER_LABEL_T
Definition typeinfo.h:165
@ SCH_TEXT_T
Definition typeinfo.h:147
@ SCH_GLOBAL_LABEL_T
Definition typeinfo.h:164
@ SCH_PIN_T
Definition typeinfo.h:149
UNDO_REDO
Undo Redo considerations: Basically we have 3 cases New item Deleted item Modified item there is also...
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:708
VECTOR2< double > VECTOR2D
Definition vector2d.h:707