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, 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#pragma once
26
27#include "increment.h"
28#include <math/vector2d.h>
29#include <tool/tool_event.h>
31#include <tool/tool_manager.h>
32#include <tool/tool_menu.h>
33#include <tool/actions.h>
35#include <sch_edit_frame.h>
36#include <sch_view.h>
37#include <symbol_edit_frame.h>
38#include <sch_shape.h>
39#include <pin_layout_cache.h>
40#include <sch_commit.h>
41#include <tool/picker_tool.h>
42#include <view/view_controls.h>
43
44class SCH_SELECTION;
45
49
50
51template <class T>
53{
54public:
58 SCH_TOOL_BASE( const std::string& aName ) :
59 TOOL_INTERACTIVE ( aName ),
60 m_frame( nullptr ),
61 m_view( nullptr ),
62 m_selectionTool( nullptr ),
63 m_isSymbolEditor( false ),
64 m_pickerItem( nullptr )
65 {};
66
67 ~SCH_TOOL_BASE() override {};
68
70 bool Init() override
71 {
75
76 // A basic context menu. Many (but not all) tools will choose to override this.
77 auto& ctxMenu = m_menu->GetMenu();
78
79 // cancel current tool goes in main context menu at the top if present
81 ctxMenu.AddSeparator( 1 );
82
83 // Finally, add the standard zoom/grid items
84 m_frame->AddStandardSubMenus( *m_menu.get() );
85
86 return true;
87 }
88
90 void Reset( RESET_REASON aReason ) override
91 {
92 if( aReason == MODEL_RELOAD || aReason == SUPERMODEL_RELOAD )
93 {
94 // Init variables used by every drawing tool
96 m_isSymbolEditor = dynamic_cast<SYMBOL_EDIT_FRAME*>( m_frame ) != nullptr;
97 }
98
99 m_view = static_cast<KIGFX::SCH_VIEW*>( getView() );
100 }
101
105 bool IsSymbolEditor() const
106 {
107 return m_isSymbolEditor;
108 }
109
110 int Increment( const TOOL_EVENT& aEvent )
111 {
112 static const std::vector<KICAD_T> incrementable = { SCH_LABEL_T,
115 SCH_PIN_T,
116 SCH_TEXT_T };
117
118 const ACTIONS::INCREMENT param = { 1, 0 };
119
120 if( aEvent.HasParameter() )
122
123 SCH_SELECTION& selection = m_selectionTool->RequestSelection( incrementable );
124
125 if( selection.Empty() )
126 return 0;
127
128 KICAD_T type = selection.Front()->Type();
129 bool allSameType = true;
130
131 for( EDA_ITEM* item : selection )
132 {
133 if( item->Type() != type )
134 {
135 allSameType = false;
136 break;
137 }
138 }
139
140 // Incrementing multiple types at once seems confusing though it would work.
141 if( !allSameType )
142 return 0;
143
144 const VECTOR2I mousePosition = getViewControls()->GetMousePosition();
145
146 STRING_INCREMENTER incrementer;
147 // In schematics, it's probably less common to be operating
148 // on pin numbers which are usually IOSQXZ-skippy.
149 incrementer.SetSkipIOSQXZ( m_isSymbolEditor );
150
151 // If we're coming via another action like 'Move', use that commit
152 SCH_COMMIT localCommit( m_toolMgr );
153 SCH_COMMIT* commit = dynamic_cast<SCH_COMMIT*>( aEvent.Commit() );
154
155 if( !commit )
156 commit = &localCommit;
157
158 const auto modifyItem =
159 [&]( EDA_ITEM& aItem )
160 {
161 if( aItem.IsNew() )
162 m_toolMgr->PostAction( ACTIONS::refreshPreview );
163
164 commit->Modify( &aItem, m_frame->GetScreen() );
165 };
166
167 for( EDA_ITEM* item : selection )
168 {
169 switch( item->Type() )
170 {
171 case SCH_PIN_T:
172 {
173 SCH_PIN& pin = static_cast<SCH_PIN&>( *item );
174 PIN_LAYOUT_CACHE& layout = pin.GetLayoutCache();
175
176 bool found = false;
177 OPT_BOX2I bbox = layout.GetPinNumberBBox();
178
179 if( bbox && bbox->Contains( mousePosition ) )
180 {
181 std::optional<wxString> nextNumber = incrementer.Increment( pin.GetNumber(), param.Delta,
182 param.Index );
183
184 if( nextNumber )
185 {
186 modifyItem( pin );
187 pin.SetNumber( *nextNumber );
188 }
189
190 found = true;
191 }
192
193 if( !found )
194 {
195 bbox = layout.GetPinNameBBox();
196
197 if( bbox && bbox->Contains( mousePosition ) )
198 {
199 std::optional<wxString> nextName = incrementer.Increment( pin.GetName(), param.Delta,
200 param.Index );
201
202 if( nextName )
203 {
204 modifyItem( pin );
205 pin.SetName( *nextName );
206 }
207
208 found = true;
209 }
210 }
211 break;
212 }
213
214 case SCH_LABEL_T:
216 case SCH_HIER_LABEL_T:
217 case SCH_TEXT_T:
218 {
219 SCH_TEXT& label = static_cast<SCH_TEXT&>( *item );
220
221 std::optional<wxString> newLabel = incrementer.Increment( label.GetText(), param.Delta,
222 param.Index );
223
224 if( newLabel )
225 {
226 modifyItem( label );
227 label.SetText( *newLabel );
228 }
229
230 break;
231 }
232
233 default:
234 // No increment for other items
235 break;
236 }
237 }
238
239 commit->Push( _( "Increment" ) );
240
241 if( selection.IsHover() )
243
244 return 0;
245 }
246
247 int InteractiveDelete( const TOOL_EVENT& aEvent )
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
323protected:
327 void updateItem( EDA_ITEM* aItem, bool aUpdateRTree ) const
328 {
329 m_frame->UpdateItem( aItem, false, aUpdateRTree );
330 }
331
333 void saveCopyInUndoList( EDA_ITEM* aItem, UNDO_REDO aType, bool aAppend = false, bool aDirtyConnectivity = true )
334 {
335 if( !aItem->IsSCH_ITEM() )
336 return;
337
338 SCH_ITEM* item = static_cast<SCH_ITEM*>( aItem );
339 bool selected = item->IsSelected();
340
341 // IS_SELECTED flag should not be set on undo items which were added for
342 // a drag operation.
343 if( selected && item->HasFlag( SELECTED_BY_DRAG ) )
344 item->ClearSelected();
345
346 if( SYMBOL_EDIT_FRAME* symbolEditFrame = dynamic_cast<SYMBOL_EDIT_FRAME*>( m_frame ) )
347 {
348 symbolEditFrame->SaveCopyInUndoList( wxEmptyString, dynamic_cast<LIB_SYMBOL*>( item ) );
349 }
350 else if( SCH_EDIT_FRAME* schematicFrame = dynamic_cast<SCH_EDIT_FRAME*>( m_frame ) )
351 {
352 schematicFrame->SaveCopyInUndoList( schematicFrame->GetScreen(), item, UNDO_REDO::CHANGED, aAppend );
353
354 if( aDirtyConnectivity )
355 {
356 if( !item->IsConnectivityDirty()
357 && item->Connection()
358 && ( item->Connection()->Name() == schematicFrame->GetHighlightedConnection()
359 || item->Connection()->HasDriverChanged() ) )
360 {
361 schematicFrame->DirtyHighlightedConnection();
362 }
363
364 item->SetConnectivityDirty();
365 }
366 }
367
368 if( selected && aItem->HasFlag( SELECTED_BY_DRAG ) )
369 aItem->SetSelected();
370 }
371
372protected:
378};
std::optional< BOX2I > OPT_BOX2I
Definition box2.h:926
static TOOL_ACTION cancelInteractive
Definition actions.h:72
static TOOL_ACTION pickerTool
Definition actions.h:252
static TOOL_ACTION selectionActivate
Activation of the selection tool.
Definition actions.h:213
static TOOL_ACTION doDelete
Definition actions.h:85
static TOOL_ACTION selectionClear
Clear the current selection.
Definition actions.h:223
static TOOL_ACTION refreshPreview
Definition actions.h:158
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:106
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:137
bool IsSelected() const
Definition eda_item.h:127
void SetSelected()
Definition eda_item.h:134
bool HasFlag(EDA_ITEM_FLAGS aFlag) const
Definition eda_item.h:146
virtual const wxString & GetText() const
Return the string associated with the text object.
Definition eda_text.h:97
virtual void SetText(const wxString &aText)
Definition eda_text.cpp:271
virtual VECTOR2D GetMousePosition(bool aWorldCoordinates=true) const =0
Return the current mouse pointer position.
bool IsSCH_ITEM() const
Definition view_item.h:101
Define a library symbol object.
Definition lib_symbol.h:85
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:66
void SetCursor(KICURSOR aCursor)
Definition picker_tool.h:64
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:167
void SetConnectivityDirty(bool aDirty=true)
Definition sch_item.h:556
bool IsConnectivityDirty() const
Definition sch_item.h:554
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:323
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:48
void SetSkipIOSQXZ(bool aSkip)
If a alphabetic part is found, skip the letters I, O, S, Q, X, Z.
Definition increment.h:54
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:86
The symbol library editor main window.
T * getEditFrame() const
Return the application window object, casted to requested user type.
Definition tool_base.h:186
KIGFX::VIEW_CONTROLS * getViewControls() const
Return the instance of VIEW_CONTROLS object used in the application.
Definition tool_base.cpp:44
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:38
RESET_REASON
Determine the reason of reset for a tool.
Definition tool_base.h:78
@ MODEL_RELOAD
Model changes (the sheet for a schematic)
Definition tool_base.h:80
@ SUPERMODEL_RELOAD
For schematics, the entire schematic changed, not just the sheet.
Definition tool_base.h:81
Generic, UI-independent tool event.
Definition tool_event.h:171
bool HasParameter() const
Definition tool_event.h:464
COMMIT * Commit() const
Definition tool_event.h:283
T Parameter() const
Return a parameter assigned to the event.
Definition tool_event.h:473
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:52
#define _(s)
#define SELECTED_BY_DRAG
Item was algorithmically selected as a dragged item.
@ FRAME_SCH_SYMBOL_EDITOR
Definition frame_type.h:35
KICAD_T
The set of class identification values stored in EDA_ITEM::m_structType.
Definition typeinfo.h:78
@ SCH_LABEL_T
Definition typeinfo.h:169
@ SCH_HIER_LABEL_T
Definition typeinfo.h:171
@ SCH_TEXT_T
Definition typeinfo.h:153
@ SCH_GLOBAL_LABEL_T
Definition typeinfo.h:170
@ SCH_PIN_T
Definition typeinfo.h:155
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:695
VECTOR2< double > VECTOR2D
Definition vector2d.h:694