28#include <wx/translation.h>
111 std::vector<MEMBER>
result;
123 if( !connection || !connection->IsBus() )
131 const auto leafName = [&](
const BUS_SCHEMA::NODE& aNode )
133 const auto& leaves = members.
schema->leaves;
134 return aNode.leaf && *aNode.leaf < leaves.size() ? leaves[*aNode.leaf].name : wxString();
138 const bool namedGroup = members.
tree->kind == BUS_SCHEMA::NODE::KIND::GROUP
139 && !members.
tree->prefix.IsEmpty();
140 const wxString prefix = namedGroup ? members.
tree->prefix + wxS(
"." ) : wxString();
142 for(
const BUS_SCHEMA::NODE& node : members.
tree->members )
145 entry.
bus = node.kind != BUS_SCHEMA::NODE::KIND::NET;
146 entry.
name = entry.
bus ? prefix + node.text : leafName( node );
148 for(
const BUS_SCHEMA::NODE& sub : node.members )
150 if( wxString
name = leafName( sub ); !
name.IsEmpty() )
160 if( !connection || !connection->
IsBus() )
163 for(
const std::shared_ptr<SCH_CONNECTION>& member : connection->
Members() )
166 entry.
name = member->FullLocalName();
169 for(
const std::shared_ptr<SCH_CONNECTION>& sub : member->Members() )
170 entry.
members.push_back( sub->FullLocalName() );
192 if( members.empty() )
207 std::unordered_map<wxString, ACTION_MENU*> diff_busses{};
209 for(
const MEMBER& member : members )
212 wxString
name = member.name;
218 if( (
name.ends_with(
'+' ) ||
name.ends_with(
'-' ) ||
name.ends_with(
'P' ) ||
name.ends_with(
'N' ) )
219 && !member.members.empty() )
221 wxString submenu_name =
name.substr( 0,
name.length() - 1 );
222 auto bus_submenu = diff_busses.find( submenu_name );
224 if( bus_submenu == diff_busses.end() )
227 diff_busses.emplace( submenu_name, submenu );
232 submenu = bus_submenu->second;
242 for(
const wxString& subMemberName : member.members )
245 name = subMemberName;
247 if( (
name.ends_with(
'+' ) ||
name.ends_with(
'-' ) ||
name.ends_with(
'P' )
248 ||
name.ends_with(
'N' ) ) )
250 wxString submenu_name =
name.substr( 0,
name.length() - 1 );
251 auto bus_submenu = diff_busses.find( submenu_name );
254 if( bus_submenu == diff_busses.end() )
257 diff_busses.emplace( submenu_name, diff_submenu );
263 diff_submenu = bus_submenu->second;
317 const auto busGetter =
323 std::shared_ptr<BUS_UNFOLD_MENU>
324 busUnfoldMenu = std::make_shared<BUS_UNFOLD_MENU>( busGetter );
325 busUnfoldMenu->SetTool(
this );
326 m_menu->RegisterSubMenu( busUnfoldMenu );
328 std::shared_ptr<BUS_UNFOLD_MENU> selBusUnfoldMenu = std::make_shared<BUS_UNFOLD_MENU>( busGetter );
345 auto belowRootSheetCondition =
348 return m_frame->GetCurrentSheet().Last() != &
m_frame->Schematic().Root();
362 auto& ctxMenu =
m_menu->GetMenu();
369 ctxMenu.AddSeparator( 10 );
380 ctxMenu.AddSeparator( 100 );
391 ctxMenu.AddSeparator( 200 );
453 wxString* netPtr = aEvent.
Parameter<wxString*>();
468 const auto busGetter =
484 std::optional<int>
id = evt->GetCommandId();
486 if(
id && ( *
id > 0 ) )
487 net = *evt->Parameter<wxString*>();
522 const std::optional<VECTOR2I>& aPos )
529 if ( bus ==
nullptr )
531 wxASSERT_MSG(
false, wxString::Format(
"Couldn't find the originating bus line (but had a net: %s )",
562 std::vector<DANGLING_END_ITEM> endPointsByType;
565 item->GetEndPoints( endPointsByType );
567 std::vector<DANGLING_END_ITEM> endPointsByPos = endPointsByType;
569 m_busUnfold.entry->UpdateDanglingState( endPointsByType, endPointsByPos );
587 if(
pin->GetPosition() == aPosition )
601 wxCHECK_RET( aSegments.first && aSegments.second,
602 wxT(
"Cannot compute break point of NULL line segment." ) );
605 SCH_LINE* segment = aSegments.first;
606 SCH_LINE* nextSegment = aSegments.second;
609 int xDir =
delta.x > 0 ? 1 : -1;
610 int yDir =
delta.y > 0 ? 1 : -1;
613 bool preferHorizontal;
636 aPosition.
x +=
KiROUND(
getView()->GetGAL()->GetGridSize().x * direction );
639 preferHorizontal =
true;
640 preferVertical =
false;
644 auto breakVertical = [&]()
mutable
652 midPoint.
y = aPosition.
y - yDir * abs(
delta.x );
656 midPoint.
x = aPosition.
x;
662 midPoint.
y = aPosition.
y;
667 auto breakHorizontal = [&]()
mutable
674 midPoint.
x = aPosition.
x - xDir * abs(
delta.y );
680 midPoint.
y = aPosition.
y;
684 midPoint.
x = aPosition.
x;
694 else if( preferHorizontal )
708 preferVertical =
false;
709 preferHorizontal =
false;
712 && ( ( abs( deltaMidpoint.
x ) > abs(
delta.x ) )
713 || ( abs( deltaMidpoint.
y ) > abs(
delta.y ) ) ) )
715 preferVertical =
false;
716 preferHorizontal =
false;
719 if( !preferHorizontal && !preferVertical )
734 int aType,
bool aQuitOnDraw )
741 int lastMode =
m_frame->eeconfig()->m_Drawing.line_mode;
742 static bool posture =
false;
782 m_view->ShowPreview(
false );
808 bool isSyntheticClick = ( segment ||
m_busUnfold.in_progress ) && evt->IsActivate()
809 && evt->HasPosition() && evt->Matches( aTool );
814 grid.SetUseGrid(
getView()->GetGAL()->GetGridSnapping() && !evt->DisableGridSnapping() );
825 VECTOR2D eventPosition = evt->HasPosition() ? evt->Position()
828 VECTOR2I cursorPos =
grid.ResolveSnap( eventPosition, gridType, segment ).position;
832 if( currentMode != lastMode )
858 lastMode = currentMode;
864 if( evt->IsCancelInteractive() )
866 m_frame->GetInfoBar()->Dismiss();
880 else if( evt->IsActivate() && !isSyntheticClick )
884 m_frame->ShowInfoBarMsg(
_(
"Press <ESC> to cancel drawing." ) );
885 evt->SetPassEvent(
false );
889 if( evt->IsMoveTool() )
907 aCommit.
Push(
_(
"Draw Wires" ) );
918 || ( segment && evt->IsDblClick(
BUT_LEFT ) )
920 || isSyntheticClick )
937 else if( !segment->
IsNull()
947 aCommit.
Push(
_(
"Draw Wires" ) );
954 int placedSegments = 1;
964 for(
int i = 0; i < placedSegments; i++ )
977 if( segment && ( evt->IsDblClick(
BUT_LEFT )
980 if( twoSegments &&
m_wires.size() >= 2 )
986 aCommit.
Push(
_(
"Draw Wires" ) );
1005 bool flipX = ( cursor_delta.
x < 0 );
1006 bool flipY = ( cursor_delta.
y < 0 );
1012 int ySign = flipY ? -1 : 1;
1013 int xSign = flipX ? -1 : 1;
1022 m_frame->UpdateItem( entry,
false,
true );
1038 if( twoSegments &&
m_wires.size() >= 2 )
1046 if( !wire->IsNull() )
1047 m_view->AddToPreview( wire->Clone() );
1050 std::vector<SCH_ITEM*> previewItems;
1054 if( !wire->IsNull() )
1055 previewItems.push_back( wire );
1062 m_view->AddToPreview( jct,
true );
1082 if( twoSegments &&
m_wires.size() >= 2 )
1089 if( !wire->IsNull() )
1090 m_view->AddToPreview( wire->Clone() );
1096 evt->SetPassEvent();
1125 if( !wire->IsNull() )
1126 m_view->AddToPreview( wire->Clone() );
1145 contextMenuPos = cursorPos;
1153 wxASSERT_MSG( !segment,
"Bus unfold event received when already drawing!" );
1156 wxString net = *evt->Parameter<wxString*>();
1157 segment =
doUnfoldBus( aCommit, net, contextMenuPos );
1183 evt->SetPassEvent();
1203 aSegment =
m_frame->GetScreen()->GetLine( aPos, 0, aType );
1225 m_wires.push_back( aSegment );
1231 if(
m_frame->eeconfig()->m_Drawing.line_mode )
1235 m_wires.push_back( aSegment );
1273 if( next_it ==
m_wires.end() )
1305 std::vector<VECTOR2I> new_ends;
1313 std::vector<VECTOR2I> tmpends = wire->GetConnectionPoints();
1315 new_ends.insert( new_ends.end(), tmpends.begin(), tmpends.end() );
1317 for(
const VECTOR2I& pt : connections )
1320 new_ends.push_back( pt );
1323 aCommit.
Added( wire, screen );
1345 for(
size_t ii = 1; ii <
m_wires.size(); ++ii )
1352 m_frame->AddToScreen( wire, screen );
1357 m_view->ShowPreview(
false );
1363 m_frame->Schematic().CleanUp( &aCommit );
1365 std::vector<SCH_ITEM*> symbols;
1368 symbols.push_back( symbol );
1372 std::vector<VECTOR2I> pts = symbol->GetConnectionPoints();
1374 if( pts.size() > 2 )
1377 for(
auto pt = pts.begin(); pt != pts.end(); pt++ )
1379 for(
auto secondPt = pt + 1; secondPt != pts.end(); secondPt++ )
1380 m_frame->TrimWire( &aCommit, *pt, *secondPt );
1384 for(
const VECTOR2I& pt : new_ends )
1386 if(
m_frame->GetScreen()->IsExplicitJunctionNeeded( pt ) )
1394 item->ClearEditFlags();
1403 std::set<SCH_LINE*> lines;
1407 lines.insert(
static_cast<SCH_LINE*
>( item ) );
1409 for(
unsigned ii = 0; ii < aSelection->
GetSize(); ii++ )
1422 std::vector<VECTOR2I> conn_pts;
1427 conn_pts.push_back( pt );
1429 if( conn_pts.size() > 2 )
1433 if( conn_pts.size() == 2 )
1434 m_frame->TrimWire( aCommit, conn_pts[0], conn_pts[1] );
1445 std::deque<EDA_ITEM*> allItems;
1449 allItems.push_back( item );
1453 static_cast<SCH_GROUP*
>( item )->RunOnChildren(
1456 allItems.push_back( child );
1463 wxLogTrace(
"KICAD_SCH_MOVE",
"AddJunctionsIfNeeded: adding junction at %s", point.Format().c_str() );
1475 aCommit->
Modify( aSegment, aScreen );
1481 m_frame->AddToScreen( newSegment, aScreen );
1483 aCommit->
Added( newSegment, aScreen );
1485 *aNewSegment = newSegment;
1491 bool brokenSegments =
false;
1496 BreakSegment( aCommit, wire, aPos, &new_line, aScreen );
1497 brokenSegments =
true;
1500 return brokenSegments;
1506 bool brokenSegments =
false;
1508 std::set<VECTOR2I> point_set;
1511 point_set.insert( item->GetPosition() );
1517 point_set.insert( entry->
GetEnd() );
1520 for(
const VECTOR2I& pt : point_set )
1523 brokenSegments =
true;
1526 return brokenSegments;
1535 if( aScreen->
GetBus( aPos ) )
1538 m_frame->AddToScreen( junction, aScreen );
1539 aCommit->
Added( junction, aScreen );
constexpr BOX2I KiROUND(const BOX2D &aBoxD)
static TOOL_ACTION cursorDblClick
static TOOL_ACTION doDelete
static TOOL_ACTION cursorClick
static TOOL_ACTION selectionClear
Clear the current selection.
static TOOL_ACTION refreshPreview
static TOOL_ACTION finishInteractive
static const ADVANCED_CFG & GetCfg()
Get the singleton instance's config, which is shared by all consumers.
COMMIT & Added(EDA_ITEM *aItem, BASE_SCREEN *aScreen=nullptr)
Notify observers that aItem has been added.
COMMIT & Modify(EDA_ITEM *aItem, BASE_SCREEN *aScreen=nullptr, RECURSE_MODE aRecurse=RECURSE_MODE::NO_RECURSE)
Modify a given item in the model.
static void sort_dangling_end_items(std::vector< DANGLING_END_ITEM > &aItemListByType, std::vector< DANGLING_END_ITEM > &aItemListByPos)
A base class for most all the KiCad significant classes used in schematics and boards.
void SetFlags(EDA_ITEM_FLAGS aMask)
KICAD_T Type() const
Returns the type of object.
virtual void SetParent(EDA_ITEM *aParent)
EE_TYPE Overlapping(const BOX2I &aRect) const
EE_TYPE OfType(KICAD_T aType) const
An interface for classes handling user events controlling the view behavior such as zooming,...
virtual void CaptureCursor(bool aEnabled)
Force the cursor to stay within the drawing panel area.
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.
virtual void WarpMouseCursor(const VECTOR2D &aPosition, bool aWorldCoordinates=false, bool aWarpView=false)=0
If enabled (.
virtual void SetCrossHairCursorPosition(const VECTOR2D &aPosition, bool aWarpView=true)=0
Move the graphic crosshair cursor to the requested position expressed in world coordinates.
virtual VECTOR2D GetMousePosition(bool aWorldCoordinates=true) const =0
Return the current mouse pointer position.
virtual void SetAutoPan(bool aEnabled)
Turn on/off auto panning (this feature is used when there is a tool active (eg.
These are loaded from Eeschema settings but then overwritten by the project settings.
Holds all the data relating to one schematic.
SCH_CONNECTIVITY::FACADE & Connectivity() const
SCH_SHEET_PATH & CurrentSheet() const
static TOOL_ACTION rotateCCW
static TOOL_ACTION placeClassLabel
static TOOL_ACTION clearHighlight
static TOOL_ACTION placeGlobalLabel
static TOOL_ACTION leaveSheet
static TOOL_ACTION breakWire
static TOOL_ACTION drawLines
static TOOL_ACTION placeHierLabel
static TOOL_ACTION selectConnection
If current selection is a wire or bus, expand to entire connection.
static TOOL_ACTION placeLabel
static TOOL_ACTION drawWire
static TOOL_ACTION rotateCW
static TOOL_ACTION placeJunction
static TOOL_ACTION selectNode
Select the junction, wire or bus segment under the cursor.
static TOOL_ACTION unfoldBus
static TOOL_ACTION drawBus
static TOOL_ACTION undoLastSegment
static TOOL_ACTION switchSegmentPosture
void SetSize(const VECTOR2I &aSize)
VECTOR2I GetPosition() const override
Class for a wire to bus entry.
Commit for the schematic and symbol editors.
void Push(const wxString &aMessage=wxEmptyString, int aCommitFlags=0) override
Execute the changes.
Each graphical item can have a SCH_CONNECTION describing its logical connection (to a bus or net).
const std::vector< std::shared_ptr< SCH_CONNECTION > > & Members() const
static wxString PrintBusForUI(const wxString &aString)
std::optional< ITEM_VIEW > Connection(const KIID &aItem, const KIID_PATH &aPath) const
Schematic editor (Eeschema) main window.
const wxString & GetHighlightedConnection() const
A set of SCH_ITEMs (i.e., without duplicates).
Base class for any item which can be embedded within the SCHEMATIC container class,...
SCH_ITEM * Duplicate(bool addToParentGroup, SCH_COMMIT *aCommit=nullptr, bool aDoClone=false) const
Routine to create a new copy of given item.
virtual bool IsConnectable() const
SCHEMATIC * Schematic() const
Search the item hierarchy to find a SCHEMATIC.
void SetLayer(SCH_LAYER_ID aLayer)
SCH_LAYER_ID GetLayer() const
Return the layer this item is on.
SCH_CONNECTION * Connection(const SCH_SHEET_PATH *aSheet=nullptr) const
Retrieve the connection associated with this object in the given sheet.
virtual std::vector< VECTOR2I > GetConnectionPoints() const
Add all the connection points for this item to aPoints.
Segment description base class to describe items which have 2 end points (track, wire,...
void SetStartPoint(const VECTOR2I &aPosition)
VECTOR2I GetEndPoint() const
VECTOR2I GetStartPoint() const
SEG GetSeg() const
Get the geometric aspect of the wire as a SEG.
SCH_LINE * MergeOverlap(SCH_SCREEN *aScreen, SCH_LINE *aLine, bool aCheckJunctions)
Check line against aLine to see if it overlaps and merge if it does.
SCH_LINE * BreakAt(SCH_COMMIT *aCommit, const VECTOR2I &aPoint)
Break this segment into two at the specified point.
void SetEndPoint(const VECTOR2I &aPosition)
std::vector< SCH_LINE * > GetBusesAndWires(const VECTOR2I &aPosition, bool aIgnoreEndpoints=false) const
Return buses and wires passing through aPosition.
EE_RTREE & Items()
Get the full RTree, usually for iterating.
bool IsTerminalPoint(const VECTOR2I &aPosition, int aLayer) const
Test if aPosition is a connection point on aLayer.
SCH_LINE * GetBus(const VECTOR2I &aPosition, int aAccuracy=0, SCH_LINE_TEST_T aSearchType=ENTIRE_LENGTH_T) const
std::vector< VECTOR2I > GetNeededJunctions(const std::deque< EDA_ITEM * > &aItems) const
Return the unique set of points belonging to aItems where a junction is needed.
std::vector< VECTOR2I > GetConnections() const
Collect a unique list of all possible connection points in the schematic.
BOX2I GetBoundingBox() const override
SCH_SCREEN * LastScreen()
const KIID_PATH & PathRef() const
Borrow the cached path until this sheet path is modified or destroyed.
Define a sheet pin (label) used in sheets to create hierarchical schematics.
SHEET_SIDE GetSide() const
Sheet symbol placed in a schematic, and is the entry point for a sub schematic.
std::vector< SCH_SHEET_PIN * > & GetPins()
VECTOR2I GetPosition() const override
const VECTOR2I NearestPoint(const VECTOR2I &aP) const
Compute a point on the segment (this) that is closest to point aP.
static SELECTION_CONDITION MoreThan(int aNumber)
Create a functor that tests if the number of selected items is greater than the value given as parame...
static bool Idle(const SELECTION &aSelection)
Test if there no items selected or being edited.
static bool ShowAlways(const SELECTION &aSelection)
The default condition function (always returns true).
static SELECTION_CONDITION OnlyTypes(std::vector< KICAD_T > aTypes)
Create a functor that tests if the selected items are only of given types.
virtual KIGFX::VIEW_ITEM * GetItem(unsigned int aIdx) const override
virtual unsigned int GetSize() const override
Return the number of stored items.
std::deque< EDA_ITEM * > & Items()
Spin style for labels of all kinds on schematics.
#define IS_CHANGED
Item was edited, and modified.
#define IS_NEW
New item, just created.
#define IS_BROKEN
Is a segment just broken by BreakSegment.
#define SKIP_STRUCT
flag indicating that the structure should be ignored
#define IS_MOVING
Item being moved.
@ ID_POPUP_SCH_UNFOLD_BUS_END
@ ID_POPUP_SCH_UNFOLD_BUS
std::vector< SCH_JUNCTION * > PreviewJunctions(const SCH_SCREEN *aScreen, const std::vector< class SCH_ITEM * > &aItems)
Determine the points where explicit junctions would be required if the given temporary items were com...
bool signbit(T v)
Integral version of std::signbit that works all compilers.
EDA_ANGLE abs(const EDA_ANGLE &aAngle)
@ BUS
This item represents a bus vector.
Class to handle a set of SCH_ITEMs.
SHEET_SIDE
Define the edge of the sheet that the sheet pin is positioned.
Settings for bus unfolding that are persistent across invocations of the tool.
SPIN_STYLE label_spin_style
Query-time snapshot; reacquire after Update.
std::shared_ptr< const BUS_SCHEMA > schema
std::shared_ptr< const BUS_SCHEMA::NODE > tree
The parsed form of one bus text.
wxString result
Test unit parsing edge cases and error handling.
bool IsPointOnSegment(const VECTOR2I &aSegStart, const VECTOR2I &aSegEnd, const VECTOR2I &aTestPoint)
Test if aTestPoint is on line defined by aSegStart and aSegEnd.
VECTOR2< int32_t > VECTOR2I
VECTOR2< double > VECTOR2D