void SCH_EDIT_FRAME::CheckListConnections( PICKED_ITEMS_LIST& aItemsList, bool aAppend ) { std::vector< wxPoint > pts; std::vector< wxPoint > connections; GetSchematicConnections( connections ); for( unsigned ii = 0; ii < aItemsList.GetCount(); ii++ ) { SCH_ITEM* item = (SCH_ITEM*) aItemsList.GetPickedItem( ii ); std::vector< wxPoint > new_pts; if( !item->IsConnectable() ) continue; item->GetConnectionPoints( new_pts ); pts.insert( pts.end(), new_pts.begin(), new_pts.end() ); // If the item is a line, we also add any connection points from the rest of the schematic // that terminate on the line after it is moved. if( item->Type() == SCH_LINE_T ) { SCH_LINE* line = (SCH_LINE*) item; for( auto i : connections ) if( IsPointOnSegment( line->GetStartPoint(), line->GetEndPoint(), i ) ) pts.push_back( i ); } else { // Clean up any wires that short non-wire connections in the list for( auto point = new_pts.begin(); point != new_pts.end(); point++ ) { for( auto second_point = point + 1; second_point != new_pts.end(); second_point++ ) { aAppend |= TrimWire( *point, *second_point, aAppend ); } } } } // We always have some overlapping connection points. Drop duplicates here std::sort( pts.begin(), pts.end(), []( const wxPoint& a, const wxPoint& b ) -> bool { return a.x < b.x || (a.x == b.x && a.y < b.y); } ); pts.erase( unique( pts.begin(), pts.end() ), pts.end() ); for( auto point : pts ) { if( GetScreen()->IsJunctionNeeded( point, true ) ) { AddJunction( point, aAppend ); aAppend = true; } } }
void AddMenusForWire( wxMenu* PopMenu, SCH_LINE* Wire, SCH_EDIT_FRAME* frame ) { SCH_SCREEN* screen = frame->GetScreen(); wxPoint pos = frame->GetCrossHairPosition(); wxString msg; if( Wire == NULL ) { msg = AddHotkeyName( _( "Begin Wire" ), g_Schematic_Hokeys_Descr, HK_BEGIN_WIRE ); AddMenuItem( PopMenu, ID_POPUP_SCH_BEGIN_WIRE, msg, KiBitmap( add_line_xpm ) ); return; } bool is_new = Wire->IsNew(); if( is_new ) { msg = AddHotkeyName( _( "Wire End" ), g_Schematic_Hokeys_Descr, HK_END_CURR_LINEWIREBUS ); AddMenuItem( PopMenu, ID_POPUP_END_LINE, msg, KiBitmap( checked_ok_xpm ) ); return; } msg = AddHotkeyName( _( "Drag Wire" ), g_Schematic_Hokeys_Descr, HK_DRAG ); AddMenuItem( PopMenu, ID_SCH_DRAG_ITEM, msg, KiBitmap( move_track_xpm ) ); PopMenu->AppendSeparator(); msg = AddHotkeyName( _( "Delete Wire" ), g_Schematic_Hokeys_Descr, HK_DELETE ); AddMenuItem( PopMenu, ID_POPUP_SCH_DELETE, msg, KiBitmap( delete_xpm ) ); AddMenuItem( PopMenu, ID_POPUP_SCH_DELETE_NODE, _( "Delete Node" ), KiBitmap( delete_node_xpm ) ); AddMenuItem( PopMenu, ID_POPUP_SCH_DELETE_CONNECTION, _( "Delete Connection" ), KiBitmap( delete_connection_xpm ) ); SCH_LINE* line = screen->GetWireOrBus( frame->GetCrossHairPosition() ); if( line && !line->IsEndPoint( frame->GetCrossHairPosition() ) ) AddMenuItem( PopMenu, ID_POPUP_SCH_BREAK_WIRE, _( "Break Wire" ), KiBitmap( break_line_xpm ) ); PopMenu->AppendSeparator(); msg = AddHotkeyName( _( "Add Junction" ), g_Schematic_Hokeys_Descr, HK_ADD_JUNCTION ); AddMenuItem( PopMenu, ID_POPUP_SCH_ADD_JUNCTION, msg, KiBitmap( add_junction_xpm ) ); msg = AddHotkeyName( _( "Add Label" ), g_Schematic_Hokeys_Descr, HK_ADD_LABEL ); AddMenuItem( PopMenu, ID_POPUP_SCH_ADD_LABEL, msg, KiBitmap( add_line_label_xpm ) ); // Add global label command only if the cursor is over one end of the wire. if( Wire->IsEndPoint( pos ) ) AddMenuItem( PopMenu, ID_POPUP_SCH_ADD_GLABEL, _( "Add Global Label" ), KiBitmap( add_glabel_xpm ) ); }
bool SCH_SCREEN::SchematicCleanUp() { bool modified = false; for( SCH_ITEM* item = m_drawList.begin() ; item; item = item->Next() ) { if( ( item->Type() != SCH_LINE_T ) && ( item->Type() != SCH_JUNCTION_T ) ) continue; bool restart; for( SCH_ITEM* testItem = item->Next(); testItem; testItem = restart ? m_drawList.begin() : testItem->Next() ) { restart = false; if( ( item->Type() == SCH_LINE_T ) && ( testItem->Type() == SCH_LINE_T ) ) { SCH_LINE* line = (SCH_LINE*) item; if( line->MergeOverlap( (SCH_LINE*) testItem ) ) { // Keep the current flags, because the deleted segment can be flagged. item->SetFlags( testItem->GetFlags() ); DeleteItem( testItem ); restart = true; modified = true; } } else if ( ( ( item->Type() == SCH_JUNCTION_T ) && ( testItem->Type() == SCH_JUNCTION_T ) ) && ( testItem != item ) ) { if ( testItem->HitTest( item->GetPosition() ) ) { // Keep the current flags, because the deleted segment can be flagged. item->SetFlags( testItem->GetFlags() ); DeleteItem( testItem ); restart = true; modified = true; } } } } TestDanglingEnds(); return modified; }
bool SCH_SCREEN::BreakSegment( const wxPoint& aPoint ) { SCH_LINE* segment; SCH_LINE* newSegment; bool brokenSegments = false; for( SCH_ITEM* item = m_drawList.begin(); item; item = item->Next() ) { if( (item->Type() != SCH_LINE_T) || (item->GetLayer() == LAYER_NOTES) ) continue; segment = (SCH_LINE*) item; if( !segment->HitTest( aPoint, 0 ) || segment->IsEndPoint( aPoint ) ) continue; // Break the segment at aPoint and create a new segment. newSegment = new SCH_LINE( *segment ); newSegment->SetStartPoint( aPoint ); segment->SetEndPoint( aPoint ); m_drawList.Insert( newSegment, segment->Next() ); item = newSegment; brokenSegments = true; } return brokenSegments; }
/** * Function ComputeBreakPoint * computes the middle coordinate for 2 segments from the start point to \a aPosition * with the segments kept in the horizontal or vertical axis only. * * @param aSegment A pointer to a #SCH_LINE object containing the first line break point * to compute. * @param aPosition A reference to a wxPoint object containing the coordinates of the * position used to calculate the line break point. */ static void ComputeBreakPoint( SCH_LINE* aSegment, const wxPoint& aPosition ) { wxCHECK_RET( aSegment != NULL, wxT( "Cannot compute break point of NULL line segment." ) ); SCH_LINE* nextSegment = aSegment->Next(); wxPoint midPoint = aPosition; wxCHECK_RET( nextSegment != NULL, wxT( "Cannot compute break point of NULL second line segment." ) ); #if 0 if( ABS( midPoint.x - aSegment->GetStartPoint().x ) < ABS( midPoint.y - aSegment->GetStartPoint().y ) ) midPoint.x = aSegment->GetStartPoint().x; else midPoint.y = aSegment->GetStartPoint().y; #else int iDx = aSegment->GetEndPoint().x - aSegment->GetStartPoint().x; int iDy = aSegment->GetEndPoint().y - aSegment->GetStartPoint().y; if( iDy != 0 ) // keep the first segment orientation (currently horizontal) { midPoint.x = aSegment->GetStartPoint().x; } else if( iDx != 0 ) // keep the first segment orientation (currently vertical) { midPoint.y = aSegment->GetStartPoint().y; } else { if( std::abs( midPoint.x - aSegment->GetStartPoint().x ) < std::abs( midPoint.y - aSegment->GetStartPoint().y ) ) midPoint.x = aSegment->GetStartPoint().x; else midPoint.y = aSegment->GetStartPoint().y; } #endif aSegment->SetEndPoint( midPoint ); nextSegment->SetStartPoint( midPoint ); nextSegment->SetEndPoint( aPosition ); }
void SCH_SCREEN::addConnectedItemsToBlock( const wxPoint& position ) { SCH_ITEM* item; ITEM_PICKER picker; bool addinlist = true; for( item = m_drawList.begin(); item; item = item->Next() ) { picker.SetItem( item ); if( !item->IsConnectable() || !item->IsConnected( position ) || (item->GetFlags() & SKIP_STRUCT) ) continue; if( item->IsSelected() && item->Type() != SCH_LINE_T ) continue; // A line having 2 ends, it can be tested twice: one time per end if( item->Type() == SCH_LINE_T ) { if( ! item->IsSelected() ) // First time this line is tested item->SetFlags( SELECTED | STARTPOINT | ENDPOINT ); else // second time (or more) this line is tested addinlist = false; SCH_LINE* line = (SCH_LINE*) item; if( line->GetStartPoint() == position ) item->ClearFlags( STARTPOINT ); else if( line->GetEndPoint() == position ) item->ClearFlags( ENDPOINT ); } else item->SetFlags( SELECTED ); if( addinlist ) { picker.SetFlags( item->GetFlags() ); m_BlockLocate.GetItems().PushItem( picker ); } } }
void SCH_SCREEN::MarkConnections( SCH_LINE* aSegment ) { wxCHECK_RET( (aSegment) && (aSegment->Type() == SCH_LINE_T), wxT( "Invalid object pointer." ) ); for( SCH_ITEM* item = m_drawList.begin(); item; item = item->Next() ) { if( item->GetFlags() & CANDIDATE ) continue; if( item->Type() == SCH_JUNCTION_T ) { SCH_JUNCTION* junction = (SCH_JUNCTION*) item; if( aSegment->IsEndPoint( junction->GetPosition() ) ) item->SetFlags( CANDIDATE ); continue; } if( item->Type() != SCH_LINE_T ) continue; SCH_LINE* segment = (SCH_LINE*) item; if( aSegment->IsEndPoint( segment->GetStartPoint() ) && !GetPin( segment->GetStartPoint(), NULL, true ) ) { item->SetFlags( CANDIDATE ); MarkConnections( segment ); } if( aSegment->IsEndPoint( segment->GetEndPoint() ) && !GetPin( segment->GetEndPoint(), NULL, true ) ) { item->SetFlags( CANDIDATE ); MarkConnections( segment ); } } }
/** * In a contiguous list of wires, remove wires that backtrack over the previous * wire. Example: * * Wire is added: * ----------------------------------------> * * A second wire backtracks over it: * -------------------<====================> * * RemoveBacktracks is called: * -------------------> */ static void RemoveBacktracks( DLIST<SCH_ITEM>& aWires ) { SCH_LINE* last_line = NULL; EDA_ITEM* first = aWires.GetFirst(); for( EDA_ITEM* p = first; p; ) { SCH_LINE *line = dynamic_cast<SCH_LINE*>( p ); if( !line ) { wxFAIL_MSG( "RemoveBacktracks() requires SCH_LINE items" ); break; } p = line->Next(); if( last_line ) { wxASSERT_MSG( last_line->GetEndPoint() == line->GetStartPoint(), "RemoveBacktracks() requires contiguous lines" ); if( IsPointOnSegment( last_line->GetStartPoint(), line->GetStartPoint(), line->GetEndPoint() ) ) { last_line->SetEndPoint( line->GetEndPoint() ); delete s_wires.Remove( line ); } else last_line = line; } else last_line = line; } }
bool SCH_COLLECTOR::IsDraggableJunction() const { int wireEndCount = 0; int wireMidPoint = 0; int junctionCount = 0; for( size_t i = 0; i < m_List.size(); i++ ) { SCH_ITEM* item = (SCH_ITEM*) m_List[ i ]; KICAD_T type = item->Type(); if( type == SCH_JUNCTION_T ) { junctionCount++; continue; } if( type == SCH_LINE_T ) { if( item->GetLayer() != LAYER_WIRE ) return false; SCH_LINE* line = (SCH_LINE*) item; if( line->IsEndPoint( m_RefPos ) ) wireEndCount++; else wireMidPoint++; continue; } // Any other item types indicate that this collection is not a draggable junction. return false; } return (wireEndCount >= 3) || ((wireEndCount >= 1) && (wireMidPoint == 1)) || ((wireMidPoint >= 2) && (junctionCount == 1)); }
/** * Mouse capture callback for drawing line segments. */ static void DrawSegment( EDA_DRAW_PANEL* aPanel, wxDC* aDC, const wxPoint& aPosition, bool aErase ) { SCH_LINE* segment; if( s_wires.GetCount() == 0 ) return; segment = (SCH_LINE*) s_wires.begin(); EDA_COLOR_T color = GetLayerColor( segment->GetLayer() ); ColorChangeHighlightFlag( &color, !(color & HIGHLIGHT_FLAG) ); if( aErase ) { while( segment ) { if( !segment->IsNull() ) // Redraw if segment length != 0 segment->Draw( aPanel, aDC, wxPoint( 0, 0 ), g_XorMode, color ); segment = segment->Next(); } } SCH_EDIT_FRAME* frame = (SCH_EDIT_FRAME*) aPanel->GetParent(); wxPoint endpos = frame->GetCrossHairPosition(); if( frame->GetForceHVLines() ) /* Coerce the line to vertical or horizontal one: */ ComputeBreakPoint( (SCH_LINE*) s_wires.GetLast()->Back(), endpos ); else ( (SCH_LINE*) s_wires.GetLast() )->SetEndPoint( endpos ); segment = (SCH_LINE*) s_wires.begin(); while( segment ) { if( !segment->IsNull() ) // Redraw if segment length != 0 segment->Draw( aPanel, aDC, wxPoint( 0, 0 ), g_XorMode, color ); segment = segment->Next(); } }
/** * In a contiguous list of wires, remove wires that backtrack over the previous * wire. Example: * * Wire is added: * ----------------------------------------> * * A second wire backtracks over it: * -------------------<====================> * * RemoveBacktracks is called: * -------------------> */ static void RemoveBacktracks( DLIST<SCH_ITEM>& aWires ) { EDA_ITEM* first = aWires.GetFirst(); std::vector<SCH_LINE*> last_lines; for( EDA_ITEM* p = first; p; ) { SCH_LINE *line = static_cast<SCH_LINE*>( p ); p = line->Next(); if( !last_lines.empty() ) { SCH_LINE* last_line = last_lines[last_lines.size() - 1]; bool contiguous = ( last_line->GetEndPoint() == line->GetStartPoint() ); bool backtracks = IsPointOnSegment( last_line->GetStartPoint(), last_line->GetEndPoint(), line->GetEndPoint() ); bool total_backtrack = ( last_line->GetStartPoint() == line->GetEndPoint() ); if( contiguous && backtracks ) { if( total_backtrack ) { delete s_wires.Remove( last_line ); delete s_wires.Remove( line ); last_lines.pop_back(); } else { last_line->SetEndPoint( line->GetEndPoint() ); delete s_wires.Remove( line ); } } else { last_lines.push_back( line ); } } else { last_lines.push_back( line ); } } }
/* * Hot keys. Some commands are relative to the item under the mouse cursor * Commands are case insensitive */ bool SCH_EDIT_FRAME::OnHotKey( wxDC* aDC, int aHotKey, const wxPoint& aPosition, EDA_ITEM* aItem ) { if( aHotKey == 0 ) return false; wxCommandEvent cmd( wxEVT_COMMAND_MENU_SELECTED ); SCH_SCREEN* screen = GetScreen(); // itemInEdit == false means no item currently edited. We can ask for editing a new item bool itemInEdit = screen->GetCurItem() && screen->GetCurItem()->GetFlags(); // blocInProgress == false means no block in progress. // Because a drag command uses a drag block, false means also no drag in progress // If false, we can ask for editing a new item bool blocInProgress = screen->m_BlockLocate.GetState() != STATE_NO_BLOCK; // notBusy == true means no item currently edited and no other command in progress // We can change active tool and ask for editing a new item bool notBusy = (!itemInEdit) && (!blocInProgress); /* Convert lower to upper case (the usual toupper function has problem * with non ascii codes like function keys */ if( (aHotKey >= 'a') && (aHotKey <= 'z') ) aHotKey += 'A' - 'a'; // Search command from key : EDA_HOTKEY* hotKey = GetDescriptorFromHotkey( aHotKey, common_Hotkey_List ); if( hotKey == NULL ) hotKey = GetDescriptorFromHotkey( aHotKey, schematic_Hotkey_List ); if( hotKey == NULL ) return false; switch( hotKey->m_Idcommand ) { default: case HK_NOT_FOUND: return false; case HK_HELP: // Display Current hotkey list DisplayHotkeyList( this, g_Schematic_Hokeys_Descr ); break; case HK_RESET_LOCAL_COORD: // Reset the relative coord GetScreen()->m_O_Curseur = GetCrossHairPosition(); break; case ID_HOTKEY_HIGHLIGHT: if( notBusy ) HighlightConnectionAtPosition( GetCrossHairPosition() ); break; case HK_LEFT_CLICK: case HK_LEFT_DCLICK: // Simulate a double left click: generate 2 events if( screen->m_BlockLocate.GetState() == STATE_BLOCK_MOVE ) { GetCanvas()->SetAutoPanRequest( false ); HandleBlockPlace( aDC ); } else if( screen->m_BlockLocate.GetState() == STATE_NO_BLOCK ) { OnLeftClick( aDC, aPosition ); if( hotKey->m_Idcommand == HK_LEFT_DCLICK ) OnLeftDClick( aDC, aPosition ); } break; case HK_ZOOM_IN: case HK_ZOOM_OUT: case HK_ZOOM_REDRAW: case HK_ZOOM_CENTER: case HK_ZOOM_AUTO: case HK_ZOOM_SELECTION: case HK_MOVEBLOCK_TO_DRAGBLOCK: // Switch to drag mode, when block moving case HK_SAVE_BLOCK: // Copy block to paste buffer. cmd.SetId( hotKey->m_IdMenuEvent ); GetEventHandler()->ProcessEvent( cmd ); break; case HK_DELETE: if( notBusy ) DeleteItemAtCrossHair( aDC ); break; case HK_REPEAT_LAST: if( notBusy ) RepeatDrawItem( aDC ); break; case HK_END_CURR_LINEWIREBUS: // this key terminates a new line/bus/wire in progress if( aItem && aItem->IsNew() && aItem->Type() == SCH_LINE_T ) { cmd.SetId( hotKey->m_IdMenuEvent ); GetEventHandler()->ProcessEvent( cmd ); } break; case HK_UNDO: // Hot keys that map to command IDs that cannot be called case HK_REDO: // while busy performing another command. case HK_FIND_ITEM: case HK_FIND_REPLACE: case HK_DELETE_NODE: case HK_LEAVE_SHEET: if( notBusy ) { cmd.SetId( hotKey->m_IdMenuEvent ); GetEventHandler()->ProcessEvent( cmd ); } break; case HK_FIND_NEXT_ITEM: case HK_FIND_NEXT_DRC_MARKER: if( notBusy ) { wxFindDialogEvent event( hotKey->m_IdMenuEvent, GetId() ); event.SetEventObject( this ); event.SetFlags( m_findReplaceData->GetFlags() ); event.SetFindString( m_findReplaceData->GetFindString() ); GetEventHandler()->ProcessEvent( event ); } break; case HK_ADD_NEW_COMPONENT: // Add component case HK_ADD_NEW_POWER: // Add power component case HK_ADD_LABEL: case HK_ADD_HLABEL: case HK_ADD_GLABEL: case HK_ADD_JUNCTION: case HK_ADD_WIRE_ENTRY: case HK_ADD_BUS_ENTRY: case HK_ADD_HIER_SHEET: case HK_ADD_GRAPHIC_TEXT: case HK_ADD_GRAPHIC_POLYLINE: case HK_ADD_NOCONN_FLAG: // Add a no connected flag case HK_BEGIN_BUS: case HK_BEGIN_WIRE: if( notBusy ) { EDA_HOTKEY_CLIENT_DATA data( aPosition ); cmd.SetInt( aHotKey ); cmd.SetClientObject( &data ); cmd.SetId( hotKey->m_IdMenuEvent ); GetEventHandler()->ProcessEvent( cmd ); } else if( aItem && aItem->IsNew() ) { // If the item is a bus or a wire, a begin command is not possible. if( (GetToolId() == ID_BUS_BUTT) && (aItem->Type() == SCH_LINE_T) ) { SCH_LINE* segment = (SCH_LINE*) aItem; if( segment->GetLayer() != LAYER_BUS ) break; // Bus in progress: OnLeftClick( aDC, aPosition ); } else if( (GetToolId() == ID_WIRE_BUTT ) && (aItem->Type() == SCH_LINE_T) ) { SCH_LINE* segment = (SCH_LINE*) aItem; if( segment->GetLayer() != LAYER_WIRE ) break; // Wire in progress: OnLeftClick( aDC, aPosition ); } } break; case HK_COPY_COMPONENT_OR_LABEL: // Duplicate component or text/label if( itemInEdit ) break; if( aItem == NULL ) { aItem = LocateAndShowItem( aPosition, SCH_COLLECTOR::CopyableItems ); if( aItem == NULL ) break; } cmd.SetId( hotKey->m_IdMenuEvent ); wxPostEvent( this, cmd ); break; case HK_DRAG: // Start drag case HK_MOVE_COMPONENT_OR_ITEM: // Start move schematic item. if( ! notBusy ) break; // Fall through case HK_EDIT: // Edit schematic item. Do not allow sheet edition when mowing // Because a sheet edition can be complex. if( itemInEdit && screen->GetCurItem()->Type() == SCH_SHEET_T ) break; // Fall through case HK_EDIT_COMPONENT_VALUE: // Edit component value field. case HK_EDIT_COMPONENT_REFERENCE: // Edit component value reference. case HK_EDIT_COMPONENT_FOOTPRINT: // Edit component footprint field. case HK_MIRROR_Y: // Mirror Y case HK_MIRROR_X: // Mirror X case HK_ORIENT_NORMAL_COMPONENT: // Orient 0, no mirror (Component) case HK_ROTATE: // Rotate schematic item. case HK_EDIT_COMPONENT_WITH_LIBEDIT: // Call Libedit and load the current component case HK_AUTOPLACE_FIELDS: // Autoplace all fields around component { // force a new item search on hot keys at current position, // if there is no currently edited item, // to avoid using a previously selected item if( ! itemInEdit ) screen->SetCurItem( NULL ); EDA_HOTKEY_CLIENT_DATA data( aPosition ); cmd.SetInt( hotKey->m_Idcommand ); cmd.SetClientObject( &data ); cmd.SetId( hotKey->m_IdMenuEvent ); GetEventHandler()->ProcessEvent( cmd ); } break; } // Hot key handled. return true; }
void SCH_EDIT_FRAME::EndSegment( wxDC* DC ) { SCH_SCREEN* screen = GetScreen(); SCH_LINE* segment = (SCH_LINE*) screen->GetCurItem(); if( segment == NULL || segment->Type() != SCH_LINE_T || !segment->IsNew() ) return; // Delete zero length segments and clear item flags. SCH_ITEM* item = s_wires.begin(); while( item ) { item->ClearFlags(); wxCHECK_RET( item->Type() == SCH_LINE_T, wxT( "Unexpected object type in wire list." ) ); segment = (SCH_LINE*) item; item = item->Next(); if( segment->IsNull() ) delete s_wires.Remove( segment ); } if( s_wires.GetCount() == 0 ) return; // Get the last non-null wire (this is the last created segment). SetRepeatItem( segment = (SCH_LINE*) s_wires.GetLast() ); screen->SetCurItem( NULL ); m_canvas->EndMouseCapture( -1, -1, wxEmptyString, false ); // store the terminal point of this last segment: a junction could be needed // (the last wire could be merged/deleted/modified, and lost) wxPoint endpoint = segment->GetEndPoint(); // store the starting point of this first segment: a junction could be needed SCH_LINE* firstsegment = (SCH_LINE*) s_wires.GetFirst(); wxPoint startPoint = firstsegment->GetStartPoint(); // Save the old wires for the undo command DLIST< SCH_ITEM > oldWires; // stores here the old wires GetScreen()->ExtractWires( oldWires, true ); // Save them in oldWires list // Put the snap shot of the previous wire, buses, and junctions in the undo/redo list. PICKED_ITEMS_LIST oldItems; oldItems.m_Status = UR_WIRE_IMAGE; while( oldWires.GetCount() != 0 ) { ITEM_PICKER picker = ITEM_PICKER( oldWires.PopFront(), UR_WIRE_IMAGE ); oldItems.PushItem( picker ); } SaveCopyInUndoList( oldItems, UR_WIRE_IMAGE ); // Remove segments backtracking over others RemoveBacktracks( s_wires ); // Add the new wires screen->Append( s_wires ); // Correct and remove segments that need to be merged. screen->SchematicCleanUp(); // A junction could be needed to connect the end point of the last created segment. if( screen->IsJunctionNeeded( endpoint ) ) screen->Append( AddJunction( DC, endpoint ) ); // A junction could be needed to connect the start point of the set of new created wires if( screen->IsJunctionNeeded( startPoint ) ) screen->Append( AddJunction( DC, startPoint ) ); m_canvas->Refresh(); OnModify(); }
void SCH_EDIT_FRAME::BeginSegment( wxDC* DC, int type ) { SCH_LINE* segment; SCH_LINE* nextSegment; wxPoint cursorpos = GetCrossHairPosition(); // We should know if a segment is currently in progress segment = (SCH_LINE*) GetScreen()->GetCurItem(); if( segment ) // a current item exists, but not necessary a currently edited item { if( !segment->GetFlags() || ( segment->Type() != SCH_LINE_T ) ) { if( segment->GetFlags() ) { wxLogDebug( wxT( "BeginSegment: item->GetFlags()== %X" ), segment->GetFlags() ); } // no wire, bus or graphic line in progress segment = NULL; } } if( !segment ) // first point : Create the first wire or bus segment { switch( type ) { default: segment = new SCH_LINE( cursorpos, LAYER_NOTES ); break; case LAYER_WIRE: segment = new SCH_LINE( cursorpos, LAYER_WIRE ); /* A junction will be created later, when we'll know the * segment end position, and if the junction is really needed */ break; case LAYER_BUS: segment = new SCH_LINE( cursorpos, LAYER_BUS ); break; } segment->SetFlags( IS_NEW ); s_wires.PushBack( segment ); GetScreen()->SetCurItem( segment ); // We need 2 segments to go from a given start pin to an end point when the horizontal // and vertical lines only switch is on. if( GetForceHVLines() ) { nextSegment = new SCH_LINE( *segment ); nextSegment->SetFlags( IS_NEW ); s_wires.PushBack( nextSegment ); GetScreen()->SetCurItem( nextSegment ); } m_canvas->SetMouseCapture( DrawSegment, AbortCreateNewLine ); SetRepeatItem( NULL ); } else // A segment is in progress: terminates the current segment and add a new segment. { SCH_LINE* prevSegment = segment->Back(); // Be aware prevSegment can be null when the horizontal and vertical lines only switch is off // when we create the first segment. if( !GetForceHVLines() ) { // If only one segment is needed and it has a zero length, do not create a new one. if( segment->IsNull() ) return; } else { wxCHECK_RET( prevSegment != NULL, wxT( "Failed to create second line segment." ) ); // If two segments are required and they both have zero length, do not // create a new one. if( prevSegment && prevSegment->IsNull() && segment->IsNull() ) return; } m_canvas->CallMouseCapture( DC, wxDefaultPosition, false ); // Terminate the command if the end point is on a pin, junction, or another wire or bus. if( GetScreen()->IsTerminalPoint( cursorpos, segment->GetLayer() ) ) { EndSegment( DC ); return; } // Create a new segment, and chain it after the current new segment. nextSegment = new SCH_LINE( *segment ); nextSegment->SetStartPoint( cursorpos ); s_wires.PushBack( nextSegment ); segment->SetEndPoint( cursorpos ); segment->ClearFlags( IS_NEW ); segment->SetFlags( SELECTED ); nextSegment->SetFlags( IS_NEW ); GetScreen()->SetCurItem( nextSegment ); m_canvas->CallMouseCapture( DC, wxDefaultPosition, false ); } }
bool SCH_SCREEN::SchematicCleanUp( EDA_DRAW_PANEL* aCanvas, wxDC* aDC ) { SCH_ITEM* item, * testItem; bool modified = false; item = m_drawList.begin(); for( ; item; item = item->Next() ) { if( ( item->Type() != SCH_LINE_T ) && ( item->Type() != SCH_JUNCTION_T ) ) continue; testItem = item->Next(); while( testItem ) { if( ( item->Type() == SCH_LINE_T ) && ( testItem->Type() == SCH_LINE_T ) ) { SCH_LINE* line = (SCH_LINE*) item; if( line->MergeOverlap( (SCH_LINE*) testItem ) ) { // Keep the current flags, because the deleted segment can be flagged. item->SetFlags( testItem->GetFlags() ); DeleteItem( testItem ); testItem = m_drawList.begin(); modified = true; } else { testItem = testItem->Next(); } } else if ( ( ( item->Type() == SCH_JUNCTION_T ) && ( testItem->Type() == SCH_JUNCTION_T ) ) && ( testItem != item ) ) { if ( testItem->HitTest( item->GetPosition() ) ) { // Keep the current flags, because the deleted segment can be flagged. item->SetFlags( testItem->GetFlags() ); DeleteItem( testItem ); testItem = m_drawList.begin(); modified = true; } else { testItem = testItem->Next(); } } else { testItem = testItem->Next(); } } } TestDanglingEnds( aCanvas, aDC ); if( aCanvas && modified ) aCanvas->Refresh(); return modified; }
void SCH_SCREEN::addConnectedItemsToBlock( const SCH_ITEM* aItem, const wxPoint& position ) { SCH_ITEM* item; ITEM_PICKER picker; for( item = m_drawList.begin(); item; item = item->Next() ) { if( !item->IsConnectable() || ( item->GetFlags() & SKIP_STRUCT ) || !item->CanConnect( aItem ) || item == aItem ) continue; // A line having 2 ends, it can be tested twice: one time per end if( item->Type() == SCH_LINE_T ) { SCH_LINE* line = (SCH_LINE*) item; if( !item->HitTest( position ) ) continue; // First time through. Flags set to denote an end that is not moving if( !item->IsSelected() ) item->SetFlags( CANDIDATE | STARTPOINT | ENDPOINT ); if( line->GetStartPoint() == position ) item->ClearFlags( STARTPOINT ); else if( line->GetEndPoint() == position ) item->ClearFlags( ENDPOINT ); else // This picks up items such as labels that can connect to the middle of a line item->ClearFlags( STARTPOINT | ENDPOINT ); } // We want to move a mid-connected label or bus entry when the full line is being moved else if( !item->IsSelected() && aItem->Type() == SCH_LINE_T && !( aItem->GetFlags() & ( ENDPOINT | STARTPOINT ) ) ) { std::vector< wxPoint > connections; item->GetConnectionPoints( connections ); for( auto conn : connections ) { if( aItem->HitTest( conn ) ) { item->SetFlags( CANDIDATE ); break; } } } if( item->IsSelected() ) continue; if( ( item->GetFlags() & CANDIDATE ) || item->IsConnected( position ) ) // Deal with all non-line items { item->ClearFlags( CANDIDATE ); item->SetFlags( SELECTED ); picker.SetItem( item ); picker.SetFlags( item->GetFlags() ); m_BlockLocate.GetItems().PushItem( picker ); } } }
int SCH_SCREEN::GetConnection( const wxPoint& aPosition, PICKED_ITEMS_LIST& aList, bool aFullConnection ) { SCH_ITEM* item; EDA_ITEM* tmp; EDA_ITEMS list; // Clear flags member for all items. ClearDrawingState(); BreakSegmentsOnJunctions(); if( GetNode( aPosition, list ) == 0 ) return 0; for( size_t i = 0; i < list.size(); i++ ) { item = (SCH_ITEM*) list[ i ]; item->SetFlags( SELECTEDNODE | STRUCT_DELETED ); /* Put this structure in the picked list: */ ITEM_PICKER picker( item, UR_DELETED ); aList.PushItem( picker ); } // Mark all wires, junctions, .. connected to the item(s) found. if( aFullConnection ) { SCH_LINE* segment; for( item = m_drawList.begin(); item; item = item->Next() ) { if( !(item->GetFlags() & SELECTEDNODE) ) continue; if( item->Type() != SCH_LINE_T ) continue; MarkConnections( (SCH_LINE*) item ); } // Search all attached wires (i.e wire with one new dangling end ) for( item = m_drawList.begin(); item; item = item->Next() ) { bool noconnect = false; if( item->GetFlags() & STRUCT_DELETED ) continue; // Already seen if( !(item->GetFlags() & CANDIDATE) ) continue; // not a candidate if( item->Type() != SCH_LINE_T ) continue; item->SetFlags( SKIP_STRUCT ); segment = (SCH_LINE*) item; /* If the wire start point is connected to a wire that was already found * and now is not connected, add the wire to the list. */ for( tmp = m_drawList.begin(); tmp; tmp = tmp->Next() ) { // Ensure tmp is a previously deleted segment: if( ( tmp->GetFlags() & STRUCT_DELETED ) == 0 ) continue; if( tmp->Type() != SCH_LINE_T ) continue; SCH_LINE* testSegment = (SCH_LINE*) tmp; // Test for segment connected to the previously deleted segment: if( testSegment->IsEndPoint( segment->GetStartPoint() ) ) break; } // when tmp != NULL, segment is a new candidate: // put it in deleted list if // the start point is not connected to an other item (like pin) if( tmp && !CountConnectedItems( segment->GetStartPoint(), true ) ) noconnect = true; /* If the wire end point is connected to a wire that has already been found * and now is not connected, add the wire to the list. */ for( tmp = m_drawList.begin(); tmp; tmp = tmp->Next() ) { // Ensure tmp is a previously deleted segment: if( ( tmp->GetFlags() & STRUCT_DELETED ) == 0 ) continue; if( tmp->Type() != SCH_LINE_T ) continue; SCH_LINE* testSegment = (SCH_LINE*) tmp; // Test for segment connected to the previously deleted segment: if( testSegment->IsEndPoint( segment->GetEndPoint() ) ) break; } // when tmp != NULL, segment is a new candidate: // put it in deleted list if // the end point is not connected to an other item (like pin) if( tmp && !CountConnectedItems( segment->GetEndPoint(), true ) ) noconnect = true; item->ClearFlags( SKIP_STRUCT ); if( noconnect ) { item->SetFlags( STRUCT_DELETED ); ITEM_PICKER picker( item, UR_DELETED ); aList.PushItem( picker ); item = m_drawList.begin(); } } // Get redundant junctions (junctions which connect < 3 end wires // and no pin) for( item = m_drawList.begin(); item; item = item->Next() ) { if( item->GetFlags() & STRUCT_DELETED ) continue; if( !(item->GetFlags() & CANDIDATE) ) continue; if( item->Type() != SCH_JUNCTION_T ) continue; SCH_JUNCTION* junction = (SCH_JUNCTION*) item; if( CountConnectedItems( junction->GetPosition(), false ) <= 2 ) { item->SetFlags( STRUCT_DELETED ); ITEM_PICKER picker( item, UR_DELETED ); aList.PushItem( picker ); } } for( item = m_drawList.begin(); item; item = item->Next() ) { if( item->GetFlags() & STRUCT_DELETED ) continue; if( item->Type() != SCH_LABEL_T ) continue; tmp = GetWireOrBus( ( (SCH_TEXT*) item )->GetPosition() ); if( tmp && tmp->GetFlags() & STRUCT_DELETED ) { item->SetFlags( STRUCT_DELETED ); ITEM_PICKER picker( item, UR_DELETED ); aList.PushItem( picker ); } } } ClearDrawingState(); return aList.GetCount(); }