KiCad PCB EDA Suite
Loading...
Searching...
No Matches
symbol_editor_move_tool.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, 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#include <tool/tool_manager.h>
27#include <sch_actions.h>
28#include <ee_grid_helper.h>
29#include <eda_item.h>
31#include <sch_shape.h>
32#include <sch_group.h>
33#include <sch_commit.h>
34#include <wx/debug.h>
35#include <view/view_controls.h>
38
39
41 SCH_TOOL_BASE( "eeschema.SymbolMoveTool" ),
42 m_moveInProgress( false )
43{
44}
45
46
48{
50
51 //
52 // Add move actions to the selection tool menu
53 //
54 CONDITIONAL_MENU& selToolMenu = m_selectionTool->GetToolMenu().GetMenu();
55
56 auto canMove =
57 [&]( const SELECTION& sel )
58 {
60 wxCHECK( editor, false );
61
62 if( !editor->IsSymbolEditable() )
63 return false;
64
65 if( editor->IsSymbolAlias() )
66 {
67 for( EDA_ITEM* item : sel )
68 {
69 if( item->Type() != SCH_FIELD_T )
70 return false;
71 }
72 }
73
74 return true;
75 };
76
77 selToolMenu.AddItem( SCH_ACTIONS::move, canMove && SCH_CONDITIONS::IdleSelection, 150 );
79
80 return true;
81}
82
83
85{
86 SCH_TOOL_BASE::Reset( aReason );
87
88 if( aReason == MODEL_RELOAD )
89 m_moveInProgress = false;
90}
91
92
94{
95 if( SCH_COMMIT* commit = dynamic_cast<SCH_COMMIT*>( aEvent.Commit() ) )
96 {
97 wxCHECK( aEvent.SynchronousState(), 0 );
98 aEvent.SynchronousState()->store( STS_RUNNING );
99
100 if( doMoveSelection( aEvent, commit ) )
101 aEvent.SynchronousState()->store( STS_FINISHED );
102 else
103 aEvent.SynchronousState()->store( STS_CANCELLED );
104 }
105 else
106 {
107 SCH_COMMIT localCommit( m_toolMgr );
108
109 if( doMoveSelection( aEvent, &localCommit ) )
110 localCommit.Push( _( "Move" ) );
111 else
112 localCommit.Revert();
113 }
114
115 return 0;
116}
117
118
120{
123
124 m_anchorPos = { 0, 0 };
125
126 // Be sure that there is at least one item that we can move. If there's no selection try
127 // looking for the stuff under mouse cursor (i.e. Kicad old-style hover selection).
128 SCH_SELECTION& selection = m_frame->IsSymbolAlias() ? m_selectionTool->RequestSelection( { SCH_FIELD_T } )
129 : m_selectionTool->RequestSelection();
130 bool unselect = selection.IsHover();
131
132 if( !m_frame->IsSymbolEditable() || selection.Empty() )
133 return false;
134
135 if( m_moveInProgress )
136 {
137 // The tool hotkey is interpreted as a click when already moving
138 m_toolMgr->RunAction( ACTIONS::cursorClick );
139 return true;
140 }
141
142 m_frame->PushTool( aEvent );
143
144 Activate();
145 // Must be done after Activate() so that it gets set into the correct context
146 controls->ShowCursor( true );
147 controls->SetAutoPan( true );
148
149 bool restore_state = false;
150 TOOL_EVENT copy = aEvent;
151 TOOL_EVENT* evt = &copy;
152 VECTOR2I prevPos;
153 VECTOR2I moveOffset;
154
155 // Axis locking for arrow key movement
156 enum class AXIS_LOCK { NONE, HORIZONTAL, VERTICAL };
157 AXIS_LOCK axisLock = AXIS_LOCK::NONE;
158 long lastArrowKeyAction = 0;
159
160 aCommit->Modify( m_frame->GetCurSymbol(), m_frame->GetScreen() );
161
162 m_cursor = controls->GetCursorPosition( !aEvent.DisableGridSnapping() );
163
164 // Main loop: keep receiving events
165 do
166 {
167 m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::MOVING );
168 grid.SetSnap( !evt->Modifier( MD_SHIFT ) );
169 grid.SetUseGrid( getView()->GetGAL()->GetGridSnapping() && !evt->DisableGridSnapping() );
170
171 if( evt->IsAction( &SCH_ACTIONS::move )
172 || evt->IsMotion()
173 || evt->IsDrag( BUT_LEFT )
175 {
176 GRID_HELPER_GRIDS snapLayer = grid.GetSelectionGrid( selection );
177
178 if( !m_moveInProgress ) // Prepare to start moving/dragging
179 {
180 SCH_ITEM* lib_item = static_cast<SCH_ITEM*>( selection.Front() );
181
182 // Pick up any synchronized pins
183 //
184 // Careful when pasting. The pasted pin will be at the same location as it
185 // was copied from, leading us to believe it's a synchronized pin. It's not.
186 if( m_frame->SynchronizePins() && !( lib_item->GetEditFlags() & IS_PASTED ) )
187 {
188 std::set<SCH_PIN*> sync_pins;
189
190 for( EDA_ITEM* sel_item : selection )
191 {
192 lib_item = static_cast<SCH_ITEM*>( sel_item );
193
194 if( lib_item->Type() == SCH_PIN_T )
195 {
196 SCH_PIN* cur_pin = static_cast<SCH_PIN*>( lib_item );
197 LIB_SYMBOL* symbol = m_frame->GetCurSymbol();
198 std::vector<bool> got_unit( symbol->GetUnitCount() + 1 );
199
200 got_unit[cur_pin->GetUnit()] = true;
201
202 for( SCH_PIN* pin : symbol->GetPins() )
203 {
204 if( !got_unit[pin->GetUnit()]
205 && pin->GetPosition() == cur_pin->GetPosition()
206 && pin->GetOrientation() == cur_pin->GetOrientation()
207 && pin->GetBodyStyle() == cur_pin->GetBodyStyle()
208 && pin->GetType() == cur_pin->GetType()
209 && pin->GetName() == cur_pin->GetName() )
210 {
211 if( sync_pins.insert( pin ).second )
212 got_unit[pin->GetUnit()] = true;
213 }
214 }
215 }
216 }
217
218 for( SCH_PIN* pin : sync_pins )
219 m_selectionTool->AddItemToSel( pin, true /*quiet mode*/ );
220 }
221
222 // Apply any initial offset in case we're coming from a previous command.
223 //
224 for( EDA_ITEM* item : selection )
225 moveItem( item, moveOffset );
226
227 // Set up the starting position and move/drag offset
228 //
229 m_cursor = controls->GetCursorPosition( !evt->DisableGridSnapping() );
230
231 if( lib_item->IsNew() )
232 {
233 m_anchorPos = selection.GetReferencePoint();
235
236 // Drag items to the current cursor position
237 for( EDA_ITEM* item : selection )
238 {
239 SCH_ITEM* schItem = static_cast<SCH_ITEM*>( item );
240
241 moveItem( schItem, delta );
242 updateItem( schItem, false );
243
244 // While SCH_COMMIT::Push() will add any new items to the entered group,
245 // we need to do it earlier so that the previews while moving are correct.
246 if( SCH_GROUP* enteredGroup = m_selectionTool->GetEnteredGroup() )
247 {
248 if( schItem->IsGroupableType() && !item->GetParentGroup() )
249 {
250 aCommit->Modify( enteredGroup, m_frame->GetScreen(), RECURSE_MODE::NO_RECURSE );
251 enteredGroup->AddItem( schItem );
252 }
253 }
254 }
255
257 }
258 else if( m_frame->GetMoveWarpsCursor() )
259 {
260 // User wants to warp the mouse
261 m_cursor = grid.BestDragOrigin( m_cursor, snapLayer, selection );
262 selection.SetReferencePoint( m_cursor );
264 }
265 else
266 {
267 m_cursor = controls->GetCursorPosition( !evt->DisableGridSnapping() );
269 }
270
271 controls->SetCursorPosition( m_cursor, false );
272
273 prevPos = m_cursor;
274 controls->SetAutoPan( true );
275 m_moveInProgress = true;
276 }
277
278 //------------------------------------------------------------------------
279 // Follow the mouse
280 //
281 // We need to bypass refreshPreview action here because it is triggered by the move,
282 // so we were getting double-key events that toggled the axis locking if you
283 // pressed them in a certain order.
285 {
286 VECTOR2I keyboardPos( controls->GetSettings().m_lastKeyboardCursorPosition );
287 long action = controls->GetSettings().m_lastKeyboardCursorCommand;
288
289 grid.SetSnap( false );
290 m_cursor = grid.Align( keyboardPos, snapLayer );
291
292 // Update axis lock based on arrow key press
293 if( action == ACTIONS::CURSOR_LEFT || action == ACTIONS::CURSOR_RIGHT )
294 {
295 if( axisLock == AXIS_LOCK::HORIZONTAL )
296 {
297 // Check if opposite horizontal key pressed to unlock
298 if( ( lastArrowKeyAction == ACTIONS::CURSOR_LEFT && action == ACTIONS::CURSOR_RIGHT ) ||
299 ( lastArrowKeyAction == ACTIONS::CURSOR_RIGHT && action == ACTIONS::CURSOR_LEFT ) )
300 {
301 axisLock = AXIS_LOCK::NONE;
302 }
303 // Same direction axis, keep locked
304 }
305 else
306 {
307 axisLock = AXIS_LOCK::HORIZONTAL;
308 }
309 }
310 else if( action == ACTIONS::CURSOR_UP || action == ACTIONS::CURSOR_DOWN )
311 {
312 if( axisLock == AXIS_LOCK::VERTICAL )
313 {
314 // Check if opposite vertical key pressed to unlock
315 if( ( lastArrowKeyAction == ACTIONS::CURSOR_UP && action == ACTIONS::CURSOR_DOWN ) ||
316 ( lastArrowKeyAction == ACTIONS::CURSOR_DOWN && action == ACTIONS::CURSOR_UP ) )
317 {
318 axisLock = AXIS_LOCK::NONE;
319 }
320 // Same direction axis, keep locked
321 }
322 else
323 {
324 axisLock = AXIS_LOCK::VERTICAL;
325 }
326 }
327
328 lastArrowKeyAction = action;
329 }
330 else
331 {
332 m_cursor = grid.BestSnapAnchor( controls->GetCursorPosition( false ), snapLayer,
333 selection );
334 }
335
336 if( axisLock == AXIS_LOCK::HORIZONTAL )
337 m_cursor.y = prevPos.y;
338 else if( axisLock == AXIS_LOCK::VERTICAL )
339 m_cursor.x = prevPos.x;
340
341 VECTOR2I delta( m_cursor - prevPos );
343
344 moveOffset += delta;
345 prevPos = m_cursor;
346
347 for( EDA_ITEM* item : selection )
348 {
349 moveItem( item, delta );
350 updateItem( item, false );
351 }
352
354 }
355 //------------------------------------------------------------------------
356 // Handle cancel
357 //
358 else if( evt->IsCancelInteractive() || evt->IsActivate() )
359 {
360 if( m_moveInProgress )
361 {
362 evt->SetPassEvent( false );
363 restore_state = true;
364 }
365
366 break;
367 }
368 //------------------------------------------------------------------------
369 // Handle TOOL_ACTION special cases
370 //
371 else if( evt->Action() == TA_UNDO_REDO_PRE )
372 {
373 unselect = true;
374 break;
375 }
376 else if( evt->IsAction( &ACTIONS::doDelete ) )
377 {
378 // Exit on a remove operation; there is no further processing for removed items.
379 break;
380 }
381 else if( evt->IsAction( &ACTIONS::duplicate ) )
382 {
383 wxBell();
384 }
385 //------------------------------------------------------------------------
386 // Handle context menu
387 //
388 else if( evt->IsClick( BUT_RIGHT ) )
389 {
390 m_menu->ShowContextMenu( m_selectionTool->GetSelection() );
391 }
392 //------------------------------------------------------------------------
393 // Handle drop
394 //
395 else if( evt->IsMouseUp( BUT_LEFT )
396 || evt->IsClick( BUT_LEFT )
397 || evt->IsDblClick( BUT_LEFT ) )
398 {
399 if( selection.GetSize() == 1 && selection.Front()->Type() == SCH_PIN_T )
400 {
402
403 try
404 {
405 SCH_PIN* curr_pin = static_cast<SCH_PIN*>( selection.Front() );
406
407 if( pinTool->PlacePin( aCommit, curr_pin ) )
408 {
409 // PlacePin() clears the current selection, which we don't want. Not only
410 // is it a poor user experience, but it also prevents us from doing the
411 // proper cleanup at the end of this routine (ie: clearing the edit flags).
412 m_selectionTool->AddItemToSel( curr_pin, true /*quiet mode*/ );
413 }
414 else
415 {
416 restore_state = true;
417 }
418 }
419 catch( const boost::bad_pointer& e )
420 {
421 restore_state = true;
422 wxFAIL_MSG( wxString::Format( wxT( "Boost pointer exception occurred: %s" ),
423 e.what() ) );
424 }
425 }
426
427 break; // Finish
428 }
429 else
430 {
431 evt->SetPassEvent();
432 }
433
434 } while( ( evt = Wait() ) ); // Assignment intentional; not equality test
435
436 controls->ForceCursorPosition( false );
437 controls->ShowCursor( false );
438 controls->SetAutoPan( false );
439
440 m_anchorPos = { 0, 0 };
441
442 for( EDA_ITEM* item : selection )
443 item->ClearEditFlags();
444
445 if( unselect )
447
448 m_moveInProgress = false;
449 m_frame->PopTool( aEvent );
450
451 return !restore_state;
452}
453
454
456{
458 SCH_SELECTION& selection = m_selectionTool->RequestSelection();
459 SCH_COMMIT commit( m_toolMgr );
460
461 for( EDA_ITEM* item : selection )
462 {
463 VECTOR2I newPos = grid.AlignGrid( item->GetPosition(), grid.GetItemGrid( item ) );
464 VECTOR2I delta = newPos - item->GetPosition();
465
466 if( delta != VECTOR2I( 0, 0 ) )
467 {
468 commit.Modify( item, m_frame->GetScreen(), RECURSE_MODE::RECURSE );
469 static_cast<SCH_ITEM*>( item )->Move( delta );
470 updateItem( item, true );
471 };
472
473 if( SCH_PIN* pin = dynamic_cast<SCH_PIN*>( item ) )
474 {
475 int length = pin->GetLength();
476 int pinGrid;
477
478 if( pin->GetOrientation() == PIN_ORIENTATION::PIN_LEFT
479 || pin->GetOrientation() == PIN_ORIENTATION::PIN_RIGHT )
480 {
481 pinGrid = KiROUND( grid.GetGridSize( grid.GetItemGrid( item ) ).x );
482 }
483 else
484 {
485 pinGrid = KiROUND( grid.GetGridSize( grid.GetItemGrid( item ) ).y );
486 }
487
488 int newLength = KiROUND( (double) length / pinGrid ) * pinGrid;
489
490 if( newLength > 0 )
491 pin->SetLength( newLength );
492 }
493 }
494
496
497 commit.Push( _( "Align Items to Grid" ) );
498 return 0;
499}
500
501
503{
504 static_cast<SCH_ITEM*>( aItem )->Move( aDelta );
505 aItem->SetFlags( IS_MOVING );
506}
507
508
constexpr BOX2I KiROUND(const BOX2D &aBoxD)
Definition box2.h:990
@ CURSOR_RIGHT
Definition actions.h:311
@ CURSOR_LEFT
Definition actions.h:309
@ CURSOR_UP
Definition actions.h:305
@ CURSOR_DOWN
Definition actions.h:307
static TOOL_ACTION duplicate
Definition actions.h:84
static TOOL_ACTION doDelete
Definition actions.h:85
static TOOL_ACTION cursorClick
Definition actions.h:180
static TOOL_ACTION selectionClear
Clear the current selection.
Definition actions.h:224
static TOOL_ACTION refreshPreview
Definition actions.h:159
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
void AddItem(const TOOL_ACTION &aAction, const SELECTION_CONDITION &aCondition, int aOrder=ANY_ORDER)
Add a menu entry to run a TOOL_ACTION on selected items.
A base class for most all the KiCad significant classes used in schematics and boards.
Definition eda_item.h:100
EDA_ITEM_FLAGS GetEditFlags() const
Definition eda_item.h:162
void SetFlags(EDA_ITEM_FLAGS aMask)
Definition eda_item.h:156
KICAD_T Type() const
Returns the type of object.
Definition eda_item.h:112
bool IsNew() const
Definition eda_item.h:133
static const TOOL_EVENT SelectedItemsMoved
Used to inform tools that the selection should temporarily be non-editable.
Definition actions.h:355
An interface for classes handling user events controlling the view behavior such as zooming,...
virtual void ForceCursorPosition(bool aEnabled, const VECTOR2D &aPosition=VECTOR2D(0, 0))
Place the cursor immediately at a given point.
virtual void ShowCursor(bool aEnabled)
Enable or disables display of cursor.
VECTOR2D GetCursorPosition() const
Return the current cursor position in world coordinates.
virtual void SetCursorPosition(const VECTOR2D &aPosition, bool aWarpView=true, bool aTriggeredByArrows=false, long aArrowCommand=0)=0
Move cursor to the requested position expressed in world coordinates.
virtual void SetAutoPan(bool aEnabled)
Turn on/off auto panning (this feature is used when there is a tool active (eg.
const VC_SETTINGS & GetSettings() const
Return the current VIEW_CONTROLS settings.
Define a library symbol object.
Definition lib_symbol.h:83
std::vector< SCH_PIN * > GetPins() const override
int GetUnitCount() const override
static TOOL_ACTION alignToGrid
static TOOL_ACTION move
virtual void Push(const wxString &aMessage=wxT("A commit"), int aCommitFlags=0) override
Execute the changes.
virtual void Revert() override
Revert the commit by restoring the modified items state.
A set of SCH_ITEMs (i.e., without duplicates).
Definition sch_group.h:52
Base class for any item which can be embedded within the SCHEMATIC container class,...
Definition sch_item.h:166
int GetBodyStyle() const
Definition sch_item.h:246
int GetUnit() const
Definition sch_item.h:237
bool IsGroupableType() const
Definition sch_item.cpp:117
const wxString & GetName() const
Definition sch_pin.cpp:485
PIN_ORIENTATION GetOrientation() const
Definition sch_pin.cpp:344
VECTOR2I GetPosition() const override
Definition sch_pin.cpp:336
ELECTRICAL_PINTYPE GetType() const
Definition sch_pin.cpp:393
void updateItem(EDA_ITEM *aItem, bool aUpdateRTree) const
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.
SCH_TOOL_BASE(const std::string &aName)
SCH_SELECTION_TOOL * m_selectionTool
static bool IdleSelection(const SELECTION &aSelection)
Test if all selected items are not being edited.
bool IsHover() const
Definition selection.h:89
virtual unsigned int GetSize() const override
Return the number of stored items.
Definition selection.h:105
EDA_ITEM * Front() const
Definition selection.h:177
bool Empty() const
Checks if there is anything selected.
Definition selection.h:115
bool doMoveSelection(const TOOL_EVENT &aEvent, SCH_COMMIT *aCommit)
void Reset(RESET_REASON aReason) override
Bring the tool to a known, initial state.
void setTransitions() override
This method is meant to be overridden in order to specify handlers for events.
void moveItem(EDA_ITEM *aItem, const VECTOR2I &aDelta)
Set up handlers for various events.
bool Init() override
Init() is called once upon a registration of the tool.
int Main(const TOOL_EVENT &aEvent)
Run an interactive move of the selected items, or the item under the cursor.
int AlignElements(const TOOL_EVENT &aEvent)
Align selected elements to the grid.
bool m_moveInProgress
Last cursor position (needed for getModificationPoint() to avoid changes of edit reference point).
bool PlacePin(SCH_COMMIT *aCommit, SCH_PIN *aPin)
The symbol library editor main window.
KIGFX::VIEW_CONTROLS * getViewControls() const
Definition tool_base.cpp:44
KIGFX::VIEW * getView() const
Definition tool_base.cpp:38
Generic, UI-independent tool event.
Definition tool_event.h:171
bool DisableGridSnapping() const
Definition tool_event.h:371
bool IsCancelInteractive() const
Indicate the event should restart/end an ongoing interactive tool's event loop (eg esc key,...
TOOL_ACTIONS Action() const
Returns more specific information about the type of an event.
Definition tool_event.h:250
bool IsActivate() const
Definition tool_event.h:345
COMMIT * Commit() const
Definition tool_event.h:283
bool IsClick(int aButtonMask=BUT_ANY) const
bool IsDrag(int aButtonMask=BUT_ANY) const
Definition tool_event.h:315
int Modifier(int aMask=MD_MODIFIER_MASK) const
Return information about key modifiers state (Ctrl, Alt, etc.).
Definition tool_event.h:366
bool IsAction(const TOOL_ACTION *aAction) const
Test if the event contains an action issued upon activation of the given TOOL_ACTION.
bool IsDblClick(int aButtonMask=BUT_ANY) const
std::atomic< SYNCRONOUS_TOOL_STATE > * SynchronousState() const
Definition tool_event.h:280
void SetPassEvent(bool aPass=true)
Definition tool_event.h:256
bool IsMouseUp(int aButtonMask=BUT_ANY) const
Definition tool_event.h:325
bool IsMotion() const
Definition tool_event.h:330
void Go(int(SYMBOL_EDIT_FRAME::*aStateFunc)(const TOOL_EVENT &), const TOOL_EVENT_LIST &aConditions=TOOL_EVENT(TC_ANY, TA_ANY))
std::unique_ptr< TOOL_MENU > m_menu
TOOL_EVENT * Wait(const TOOL_EVENT_LIST &aEventList=TOOL_EVENT(TC_ANY, TA_ANY))
@ MOVING
Definition cursors.h:48
#define _(s)
@ RECURSE
Definition eda_item.h:53
@ NO_RECURSE
Definition eda_item.h:54
#define IS_PASTED
Modifier on IS_NEW which indicates it came from clipboard.
#define IS_MOVING
Item being moved.
@ NONE
Definition eda_shape.h:76
GRID_HELPER_GRIDS
Definition grid_helper.h:44
@ PIN_RIGHT
The pin extends rightwards from the connection point.
Definition pin_type.h:111
@ PIN_LEFT
The pin extends leftwards from the connection point: Probably on the right side of the symbol.
Definition pin_type.h:118
Class to handle a set of SCH_ITEMs.
VECTOR2D m_lastKeyboardCursorPosition
Position of the above event.
bool m_lastKeyboardCursorPositionValid
Is last cursor motion event coming from keyboard arrow cursor motion action.
long m_lastKeyboardCursorCommand
ACTIONS::CURSOR_UP, ACTIONS::CURSOR_DOWN, etc.
KIBIS_PIN * pin
int delta
@ TA_UNDO_REDO_PRE
This event is sent before undo/redo command is performed.
Definition tool_event.h:106
@ STS_CANCELLED
Definition tool_event.h:164
@ STS_FINISHED
Definition tool_event.h:163
@ STS_RUNNING
Definition tool_event.h:162
@ MD_SHIFT
Definition tool_event.h:143
@ BUT_LEFT
Definition tool_event.h:132
@ BUT_RIGHT
Definition tool_event.h:133
@ SCH_FIELD_T
Definition typeinfo.h:151
@ SCH_PIN_T
Definition typeinfo.h:154
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:687