工具初始化与引脚创建流程
在 KiCad 的符号编辑器中,添加引脚不仅仅是绘制图形,更涉及内部状态的管理和对象的生命周期控制。核心逻辑位于 SYMBOL_EDITOR_PIN_TOOL 类中。
工具实例化
首先,工具基类被初始化,绑定到当前的编辑框架:
SYMBOL_EDITOR_PIN_TOOL::SYMBOL_EDITOR_PIN_TOOL() : EE_TOOL_BASE<SYMBOL_EDIT_FRAME>
这一步确立了操作上下文,确保后续对符号的操作能正确反映在编辑器界面中。
新建引脚的逻辑
当用户触发添加引脚动作时,系统会实例化一个新的 LIB_PIN 对象。这里的关键在于标志位(Flags)的设置,它决定了引脚在后续操作中的行为:
aSymbol->ClearTempFlags(); LIB_PIN* pin = new LIB_PIN( aSymbol ); pin->SetFlags( IS_NEW ); // Flag pins to consider if( m_frame->SynchronizePins() ) pin->SetFlags( IS_LINKED ); pin->MoveTo( aPosition ); pin->SetLength( GetLastPinLength() ); pin->SetOrientation( g_LastPinOrient ); pin->SetType( g_LastPinType ); pin->SetShape( g_LastPinShape ); pin->SetNameTextSize( GetLastPinNameSize() ); pin->SetNumberTextSize( GetLastPinNumSize() ); pin->SetConvert( g_LastPinCommonConvert ? 0 : m_frame->GetConvert() ); pin->SetUnit( g_LastPinCommonUnit ? 0 : m_frame->GetUnit() ); pin->SetVisible( g_LastPinVisible );
注意 IS_NEW 标志,它标记了这是一个新创建的引脚,便于后续区分修改操作。同时,如果启用了引脚同步功能(SynchronizePins()),还会设置 IS_LINKED,这意味着该引脚的状态变更可能会影响其他单元中的对应引脚。
修改与多单元同步
处理现有引脚的修改时,逻辑更为复杂,特别是当符号包含多个单元(Unit)时。系统需要维护一个撤销列表,并检查是否需要跨单元同步属性:
LIB_PIN original_pin( *aPin ); if( aPin->GetEditFlags() == 0 ) SaveCopyInUndoList( aPin->GetParent() ); aPin->SetModified(); if( !aPin->IsNew() && m_frame->SynchronizePins() && aPin->GetParent() ) { LIB_PINS pinList; aPin->GetParent()->GetPins( pinList ); // a pin can have a unit id = 0 (common to all units) to unit count // So we need a buffer size = GetUnitCount()+1 to store a value in a vector // when using the unit id of a pin as index std::vector<bool> got_unit( aPin->GetParent()->GetUnitCount() + 1 ); got_unit[static_cast<size_t>(aPin->GetUnit())] = true; for( LIB_PIN* other : pinList ) { if( other == aPin ) continue; /// Only change one pin per unit to allow stacking pins /// If you change all units on the position, then pins are not /// uniquely editable if( got_unit[static_cast<size_t>( other->GetUnit() )] ) continue; if( other->GetPosition() == original_pin.GetPosition() && other->GetOrientation() == original_pin.GetOrientation() && other->GetType() == original_pin.GetType() && other->IsVisible() == original_pin.IsVisible() && other->GetName() == original_pin.GetName() ) { if( aPin->GetConvert() == 0 ) { if( !aPin->GetUnit() || other->GetUnit() == aPin->GetUnit() ) aPin->GetParent()->RemoveDrawItem( other ); } else if( other->GetConvert() == aPin->GetConvert() ) { other->SetPosition( aPin->GetPosition() ); other->ChangeLength( aPin->GetLength() ); other->SetShape( aPin->GetShape() ); } if( aPin->GetUnit() == 0 ) { if( !aPin->GetConvert() || other->GetConvert() == aPin->GetConvert() ) aPin->GetParent()->RemoveDrawItem( other ); } other->SetOrientation( aPin->GetOrientation() ); other->SetType( aPin->GetType() ); other->SetVisible( aPin->IsVisible() ); other->SetName( aPin->GetName() ); other->SetNameTextSize( aPin->GetNameTextSize() ); other->SetNumberTextSize( aPin->GetNumberTextSize() ); other->SetModified(); got_unit[static_cast<size_t>( other->GetUnit() )] = true; } } }

