KiCad PCB EDA Suite
Loading...
Searching...
No Matches
sch_tool_base.h
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#pragma once
22
23#include "increment.h"
24#include <math/vector2d.h>
25#include <tool/tool_event.h>
27#include <tool/tool_manager.h>
28#include <tool/tool_menu.h>
29#include <tool/actions.h>
31#include <sch_edit_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
40class SCH_SELECTION;
41
45
46
47template <class T>
49{
50public:
54 SCH_TOOL_BASE( const std::string& aName ) :
55 TOOL_INTERACTIVE ( aName ),
56 m_frame( nullptr ),
57 m_view( nullptr ),
58 m_selectionTool( nullptr ),
59 m_isSymbolEditor( false ),
60 m_pickerItem( nullptr )
61 {};
62
63 ~SCH_TOOL_BASE() override {};
64
66 bool Init() override
67 {
71
72 // A basic context menu. Many (but not all) tools will choose to override this.
73 auto& ctxMenu = m_menu->GetMenu();
74
75 // cancel current tool goes in main context menu at the top if present
77 ctxMenu.AddSeparator( 1 );
78
79 // Finally, add the standard zoom/grid items
80 m_frame->AddStandardSubMenus( *m_menu.get() );
81
82 return true;
83 }
84
86 void Reset( RESET_REASON aReason ) override
87 {
88 if( aReason == MODEL_RELOAD || aReason == SUPERMODEL_RELOAD )
89 {
90 // Init variables used by every drawing tool
92 m_isSymbolEditor = dynamic_cast<SYMBOL_EDIT_FRAME*>( m_frame ) != nullptr;
93 }
94
95 m_view = static_cast<KIGFX::SCH_VIEW*>( getView() );
96 }
97
101 bool IsSymbolEditor() const
102 {
103 return m_isSymbolEditor;
104 }
105
106 int Increment( const TOOL_EVENT& aEvent )
107 {
108 static const std::vector<KICAD_T> incrementable = { SCH_LABEL_T,
111 SCH_PIN_T,
112 SCH_TEXT_T };
113
114 ACTIONS::INCREMENT param = { 1, 0 };
115
116 if( aEvent.HasParameter() )
117 param = aEvent.Parameter<ACTIONS::INCREMENT>();
118
119 SCH_SELECTION& selection = m_selectionTool->RequestSelection( incrementable );
120
121 if( selection.Empty() )
122 return 0;
123
124 KICAD_T type = selection.Front()->Type();
125 bool allSameType = true;
126
127 for( EDA_ITEM* item : selection )
128 {
129 if( item->Type() != type )
130 {
131 allSameType = false;
132 break;
133 }
134 }
135
136 // Incrementing multiple types at once seems confusing though it would work.
137 if( !allSameType )
138 return 0;
139
140 const VECTOR2I mousePosition = getViewControls()->GetMousePosition();
141
142 STRING_INCREMENTER incrementer;
143 // In schematics, it's probably less common to be operating
144 // on pin numbers which are usually IOSQXZ-skippy.
145 incrementer.SetSkipIOSQXZ( m_isSymbolEditor );
146
147 // If we're coming via another action like 'Move', use that commit
148 SCH_COMMIT localCommit( m_toolMgr );
149 SCH_COMMIT* commit = dynamic_cast<SCH_COMMIT*>( aEvent.Commit() );
150
151 if( !commit )
152 commit = &localCommit;
153
154 const auto modifyItem =
155 [&]( EDA_ITEM& aItem )
156 {
157 if( aItem.IsNew() )
158 m_toolMgr->PostAction( ACTIONS::refreshPreview );
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 commit->Push( _( "Increment" ) );
236
237 if( selection.IsHover() )
239
240 return 0;
241 }
242
243 int InteractiveDelete( const TOOL_EVENT& aEvent )
244 {
245 PICKER_TOOL* picker = m_toolMgr->GetTool<PICKER_TOOL>();
246
248 m_pickerItem = nullptr;
249
250 // Deactivate other tools; particularly important if another PICKER is currently running
251 Activate();
252
253 picker->SetCursor( KICURSOR::REMOVE );
254 picker->SetSnapping( false );
255 picker->ClearHandlers();
256
257 picker->SetClickHandler(
258 [this]( const VECTOR2D& aPosition ) -> bool
259 {
260 if( m_pickerItem )
261 {
262 SCH_SELECTION_TOOL* selectionTool = m_toolMgr->GetTool<SCH_SELECTION_TOOL>();
263 selectionTool->UnbrightenItem( m_pickerItem );
264 selectionTool->AddItemToSel( m_pickerItem, true /*quiet mode*/ );
265 m_toolMgr->RunAction( ACTIONS::doDelete );
266 m_pickerItem = nullptr;
267 }
268
269 return true;
270 } );
271
272 picker->SetMotionHandler(
273 [this]( const VECTOR2D& aPos )
274 {
275 SCH_SELECTION_TOOL* selectionTool = m_toolMgr->GetTool<SCH_SELECTION_TOOL>();
276 SCH_COLLECTOR collector;
277
278 selectionTool->CollectHits( collector, aPos, SCH_COLLECTOR::DeletableItems );
279
280 // Remove unselectable items
281 for( int i = collector.GetCount() - 1; i >= 0; --i )
282 {
283 if( !selectionTool->Selectable( collector[ i ] ) )
284 collector.Remove( i );
285 }
286
287 if( collector.GetCount() > 1 )
288 selectionTool->GuessSelectionCandidates( collector, aPos );
289
290 EDA_ITEM* item = collector.GetCount() == 1 ? collector[ 0 ] : nullptr;
291
292 if( m_pickerItem != item )
293 {
294 if( m_pickerItem )
295 selectionTool->UnbrightenItem( m_pickerItem );
296
297 m_pickerItem = item;
298
299 if( m_pickerItem )
300 selectionTool->BrightenItem( m_pickerItem );
301 }
302 } );
303
304 picker->SetFinalizeHandler(
305 [this]( const int& aFinalState )
306 {
307 if( m_pickerItem )
308 m_toolMgr->GetTool<SCH_SELECTION_TOOL>()->UnbrightenItem( m_pickerItem );
309
310 // Wake the selection tool after exiting to ensure the cursor gets updated
312 } );
313
314 m_toolMgr->RunAction( ACTIONS::pickerTool, &aEvent );
315
316 return 0;
317 }
318
319protected:
323 void updateItem( EDA_ITEM* aItem, bool aUpdateRTree ) const
324 {
325 m_frame->UpdateItem( aItem, false, aUpdateRTree );
326 }
327
329 void saveCopyInUndoList( EDA_ITEM* aItem, UNDO_REDO aType, bool aAppend = false, bool aDirtyConnectivity = true )
330 {
331 if( !aItem->IsSCH_ITEM() )
332 return;
333
334 SCH_ITEM* item = static_cast<SCH_ITEM*>( aItem );
335 bool selected = item->IsSelected();
336
337 // IS_SELECTED flag should not be set on undo items which were added for
338 // a drag operation.
339 if( selected && item->HasFlag( SELECTED_BY_DRAG ) )
340 item->ClearSelected();
341
342 if( SYMBOL_EDIT_FRAME* symbolEditFrame = dynamic_cast<SYMBOL_EDIT_FRAME*>( m_frame ) )
343 {
344 symbolEditFrame->SaveCopyInUndoList( wxEmptyString, dynamic_cast<LIB_SYMBOL*>( item ) );
345 }
346 else if( SCH_EDIT_FRAME* schematicFrame = dynamic_cast<SCH_EDIT_FRAME*>( m_frame ) )
347 {
348 schematicFrame->SaveCopyInUndoList( schematicFrame->GetScreen(), item, UNDO_REDO::CHANGED, aAppend );
349
350 if( aDirtyConnectivity )
351 {
352 if( !item->IsConnectivityDirty()
353 && item->Connection()
354 && ( item->Connection()->Name() == schematicFrame->GetHighlightedConnection()
355 || item->Connection()->HasDriverChanged() ) )
356 {
357 schematicFrame->DirtyHighlightedConnection();
358 }
359
360 item->SetConnectivityDirty();
361 }
362 }
363
364 if( selected && aItem->HasFlag( SELECTED_BY_DRAG ) )
365 aItem->SetSelected();
366 }
367
368protected:
374};
std::optional< BOX2I > OPT_BOX2I
Definition box2.h:922
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
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:96
void ClearSelected()
Definition eda_item.h:147
bool IsSelected() const
Definition eda_item.h:132
void SetSelected()
Definition eda_item.h:144
bool HasFlag(EDA_ITEM_FLAGS aFlag) const
Definition eda_item.h:156
virtual const wxString & GetText() const
Return the string associated with the text object.
Definition eda_text.h:110
virtual void SetText(const wxString &aText)
Definition eda_text.cpp:265
virtual VECTOR2D GetMousePosition(bool aWorldCoordinates=true) const =0
Return the current mouse pointer position.
bool IsSCH_ITEM() const
Definition view_item.h:97
Define a library symbol object.
Definition lib_symbol.h:79
void SetMotionHandler(MOTION_HANDLER aHandler)
Set a handler for mouse motion.
Definition picker_tool.h:88
void SetClickHandler(CLICK_HANDLER aHandler)
Set a handler for mouse click event.
Definition picker_tool.h:77
void SetSnapping(bool aSnap)
Definition picker_tool.h:62
void SetCursor(KICURSOR aCursor)
Definition picker_tool.h:60
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.
static const std::vector< KICAD_T > DeletableItems
virtual void Push(const wxString &aMessage=wxT("A commit"), 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:162
void SetConnectivityDirty(bool aDirty=true)
Definition sch_item.h:587
bool IsConnectivityDirty() const
Definition sch_item.h:585
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:487
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.
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)
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 * 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
void SetSkipIOSQXZ(bool aSkip)
If a alphabetic part is found, skip the letters I, O, S, Q, X, Z.
Definition increment.h:50
std::optional< wxString > Increment(const wxString &aStr, int aDelta, size_t aRightIndex) const
Increment the n-th part from the right of the given string.
Definition increment.cpp:82
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
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
@ 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:469
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.
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
KIBIS_PIN * pin
KICAD_T
The set of class identification values stored in EDA_ITEM::m_structType.
Definition typeinfo.h:71
@ SCH_LABEL_T
Definition typeinfo.h:164
@ SCH_HIER_LABEL_T
Definition typeinfo.h:166
@ SCH_TEXT_T
Definition typeinfo.h:148
@ SCH_GLOBAL_LABEL_T
Definition typeinfo.h:165
@ SCH_PIN_T
Definition typeinfo.h:150
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:683
VECTOR2< double > VECTOR2D
Definition vector2d.h:682