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_base_frame.h>
33#include <sch_view.h>
34#include <symbol_edit_frame.h>
35#include <sch_shape.h>
36#include <pin_layout_cache.h>
37#include <sch_commit.h>
38#include <tool/picker_tool.h>
39#include <view/view_controls.h>
40
41class SCH_SELECTION;
42
46
47
48template <class T>
50{
51public:
55 SCH_TOOL_BASE( const std::string& aName ) :
56 TOOL_INTERACTIVE ( aName ),
57 m_frame( nullptr ),
58 m_view( nullptr ),
59 m_selectionTool( nullptr ),
60 m_isSymbolEditor( false ),
61 m_pickerItem( nullptr )
62 {};
63
64 ~SCH_TOOL_BASE() override {};
65
67 bool Init() override
68 {
72
73 // A basic context menu. Many (but not all) tools will choose to override this.
74 auto& ctxMenu = m_menu->GetMenu();
75
76 // cancel current tool goes in main context menu at the top if present
78 ctxMenu.AddSeparator( 1 );
79
80 // Finally, add the standard zoom/grid items
81 m_frame->AddStandardSubMenus( *m_menu.get() );
82
83 return true;
84 }
85
87 void Reset( RESET_REASON aReason ) override
88 {
89 if( aReason == MODEL_RELOAD || aReason == SUPERMODEL_RELOAD )
90 {
91 // Init variables used by every drawing tool
93 m_isSymbolEditor = dynamic_cast<SYMBOL_EDIT_FRAME*>( m_frame ) != nullptr;
94 }
95
96 m_view = static_cast<KIGFX::SCH_VIEW*>( getView() );
97 }
98
102 bool IsSymbolEditor() const
103 {
104 return m_isSymbolEditor;
105 }
106
107 int Increment( const TOOL_EVENT& aEvent )
108 {
109 static const std::vector<KICAD_T> incrementable = { SCH_LABEL_T,
112 SCH_PIN_T,
113 SCH_TEXT_T };
114
115 ACTIONS::INCREMENT param = { 1, 0 };
116
117 if( aEvent.HasParameter() )
118 param = aEvent.Parameter<ACTIONS::INCREMENT>();
119
120 SCH_SELECTION& selection = m_selectionTool->RequestSelection( incrementable );
121
122 if( selection.Empty() )
123 return 0;
124
125 KICAD_T type = selection.Front()->Type();
126 bool allSameType = true;
127
128 for( EDA_ITEM* item : selection )
129 {
130 if( item->Type() != type )
131 {
132 allSameType = false;
133 break;
134 }
135 }
136
137 // Incrementing multiple types at once seems confusing though it would work.
138 if( !allSameType )
139 return 0;
140
141 const VECTOR2I mousePosition = getViewControls()->GetMousePosition();
142
143 STRING_INCREMENTER incrementer;
144 // In schematics, it's probably less common to be operating
145 // on pin numbers which are usually IOSQXZ-skippy.
146 incrementer.SetSkipIOSQXZ( m_isSymbolEditor );
147
148 // If we're coming via another action like 'Move', use that commit
149 SCH_COMMIT localCommit( m_toolMgr );
150 SCH_COMMIT* commit = dynamic_cast<SCH_COMMIT*>( aEvent.Commit() );
151
152 if( !commit )
153 commit = &localCommit;
154
155 const auto modifyItem =
156 [&]( EDA_ITEM& aItem )
157 {
158 if( aItem.IsNew() )
159 m_toolMgr->PostAction( ACTIONS::refreshPreview );
160
161 commit->Modify( &aItem, m_frame->GetScreen() );
162 };
163
164 for( EDA_ITEM* item : selection )
165 {
166 switch( item->Type() )
167 {
168 case SCH_PIN_T:
169 {
170 SCH_PIN& pin = static_cast<SCH_PIN&>( *item );
171 PIN_LAYOUT_CACHE& layout = pin.GetLayoutCache();
172
173 bool found = false;
174 OPT_BOX2I bbox = layout.GetPinNumberBBox();
175
176 if( bbox && bbox->Contains( mousePosition ) )
177 {
178 std::optional<wxString> nextNumber = incrementer.Increment( pin.GetNumber(), param.Delta,
179 param.Index );
180
181 if( nextNumber )
182 {
183 modifyItem( pin );
184 pin.SetNumber( *nextNumber );
185 }
186
187 found = true;
188 }
189
190 if( !found )
191 {
192 bbox = layout.GetPinNameBBox();
193
194 if( bbox && bbox->Contains( mousePosition ) )
195 {
196 std::optional<wxString> nextName = incrementer.Increment( pin.GetName(), param.Delta,
197 param.Index );
198
199 if( nextName )
200 {
201 modifyItem( pin );
202 pin.SetName( *nextName );
203 }
204
205 found = true;
206 }
207 }
208 break;
209 }
210
211 case SCH_LABEL_T:
213 case SCH_HIER_LABEL_T:
214 case SCH_TEXT_T:
215 {
216 SCH_TEXT& label = static_cast<SCH_TEXT&>( *item );
217
218 std::optional<wxString> newLabel = incrementer.Increment( label.GetText(), param.Delta,
219 param.Index );
220
221 if( newLabel )
222 {
223 modifyItem( label );
224 label.SetText( *newLabel );
225 }
226
227 break;
228 }
229
230 default:
231 // No increment for other items
232 break;
233 }
234 }
235
236 commit->Push( _( "Increment" ) );
237
238 if( selection.IsHover() )
240
241 return 0;
242 }
243
244 int InteractiveDelete( const TOOL_EVENT& aEvent )
245 {
246 PICKER_TOOL* picker = m_toolMgr->GetTool<PICKER_TOOL>();
247
249 m_pickerItem = nullptr;
250
251 // Deactivate other tools; particularly important if another PICKER is currently running
252 Activate();
253
254 picker->SetCursor( KICURSOR::REMOVE );
255 picker->SetSnapping( false );
256 picker->ClearHandlers();
257
258 picker->SetClickHandler(
259 [this]( const VECTOR2D& aPosition ) -> bool
260 {
261 if( m_pickerItem )
262 {
263 SCH_SELECTION_TOOL* selectionTool = m_toolMgr->GetTool<SCH_SELECTION_TOOL>();
264 selectionTool->UnbrightenItem( m_pickerItem );
265 selectionTool->AddItemToSel( m_pickerItem, true /*quiet mode*/ );
266 m_toolMgr->RunAction( ACTIONS::doDelete );
267 m_pickerItem = nullptr;
268 }
269
270 return true;
271 } );
272
273 picker->SetMotionHandler(
274 [this]( const VECTOR2D& aPos )
275 {
276 SCH_SELECTION_TOOL* selectionTool = m_toolMgr->GetTool<SCH_SELECTION_TOOL>();
277 SCH_COLLECTOR collector;
278
279 selectionTool->CollectHits( collector, aPos, SCH_COLLECTOR::DeletableItems );
280
281 // Remove unselectable items
282 for( int i = collector.GetCount() - 1; i >= 0; --i )
283 {
284 if( !selectionTool->Selectable( collector[ i ] ) )
285 collector.Remove( i );
286 }
287
288 if( collector.GetCount() > 1 )
289 selectionTool->GuessSelectionCandidates( collector, aPos );
290
291 EDA_ITEM* item = collector.GetCount() == 1 ? collector[ 0 ] : nullptr;
292
293 if( m_pickerItem != item )
294 {
295 if( m_pickerItem )
296 selectionTool->UnbrightenItem( m_pickerItem );
297
298 m_pickerItem = item;
299
300 if( m_pickerItem )
301 selectionTool->BrightenItem( m_pickerItem );
302 }
303 } );
304
305 picker->SetFinalizeHandler(
306 [this]( const int& aFinalState )
307 {
308 if( m_pickerItem )
309 m_toolMgr->GetTool<SCH_SELECTION_TOOL>()->UnbrightenItem( m_pickerItem );
310
311 // Wake the selection tool after exiting to ensure the cursor gets updated
313 } );
314
315 m_toolMgr->RunAction( ACTIONS::pickerTool, &aEvent );
316
317 return 0;
318 }
319
320protected:
321 template <class F = SCH_BASE_FRAME>
322 F* frame() const
323 {
324 return getEditFrame<F>();
325 }
326
334 {
335 if( m_isSymbolEditor )
336 return static_cast<SYMBOL_EDIT_FRAME*>( m_frame )->GetCurSymbol();
337
338 return &static_cast<SCH_EDIT_FRAME*>( m_frame )->Schematic();
339 }
340
344 void updateItem( EDA_ITEM* aItem, bool aUpdateRTree ) const
345 {
346 m_frame->UpdateItem( aItem, false, aUpdateRTree );
347 }
348
350 void saveCopyInUndoList( EDA_ITEM* aItem, UNDO_REDO aType, bool aAppend = false, bool aDirtyConnectivity = true )
351 {
352 if( !aItem->IsSCH_ITEM() )
353 return;
354
355 SCH_ITEM* item = static_cast<SCH_ITEM*>( aItem );
356 bool selected = item->IsSelected();
357
358 // IS_SELECTED flag should not be set on undo items which were added for
359 // a drag operation.
360 if( selected && item->HasFlag( SELECTED_BY_DRAG ) )
361 item->ClearSelected();
362
363 if( SYMBOL_EDIT_FRAME* symbolEditFrame = dynamic_cast<SYMBOL_EDIT_FRAME*>( m_frame ) )
364 {
365 symbolEditFrame->SaveCopyInUndoList( wxEmptyString, dynamic_cast<LIB_SYMBOL*>( item ) );
366 }
367 else if( SCH_EDIT_FRAME* schematicFrame = dynamic_cast<SCH_EDIT_FRAME*>( m_frame ) )
368 {
369 schematicFrame->SaveCopyInUndoList( schematicFrame->GetScreen(), item, UNDO_REDO::CHANGED, aAppend );
370
371 if( aDirtyConnectivity )
372 {
373 if( !item->IsConnectivityDirty()
374 && item->Connection()
375 && ( item->Connection()->Name() == schematicFrame->GetHighlightedConnection()
376 || item->Connection()->HasDriverChanged() ) )
377 {
378 schematicFrame->DirtyHighlightedConnection();
379 }
380
381 item->SetConnectivityDirty();
382 }
383 }
384
385 if( selected && aItem->HasFlag( SELECTED_BY_DRAG ) )
386 aItem->SetSelected();
387 }
388
389protected:
395};
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:114
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 * 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.
F * frame() const
~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
#define F(x, y, z)
Definition md5_hash.cpp:15
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