SCH_LINE* SCH_SCREEN::GetWireOrBus( const wxPoint& aPosition ) { for( SCH_ITEM* item = m_drawList.begin(); item; item = item->Next() ) { if( (item->Type() == SCH_LINE_T) && item->HitTest( aPosition ) && (item->GetLayer() == LAYER_BUS || item->GetLayer() == LAYER_WIRE) ) { return (SCH_LINE*) item; } } return NULL; }
bool SCH_COLLECTOR::IsNode( bool aIncludePins ) const { 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 ) continue; if( type == SCH_LINE_T ) { if( item->GetLayer() != LAYER_WIRE ) return false; continue; } if( type == LIB_PIN_T ) { if( !aIncludePins ) return false; continue; } // Any other item types indicate that this collection is not a node. return false; } return true; }
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; }
SCH_LINE* SCH_SCREEN::GetLine( const wxPoint& aPosition, int aAccuracy, int aLayer, SCH_LINE_TEST_T aSearchType ) { for( SCH_ITEM* item = m_drawList.begin(); item; item = item->Next() ) { if( item->Type() != SCH_LINE_T ) continue; if( item->GetLayer() != aLayer ) continue; if( !item->HitTest( aPosition, aAccuracy ) ) continue; switch( aSearchType ) { case ENTIRE_LENGTH_T: return (SCH_LINE*) item; case EXCLUDE_END_POINTS_T: if( !( (SCH_LINE*) item )->IsEndPoint( aPosition ) ) return (SCH_LINE*) item; break; case END_POINTS_ONLY_T: if( ( (SCH_LINE*) item )->IsEndPoint( aPosition ) ) return (SCH_LINE*) item; } } return NULL; }
int SCH_SCREEN::GetNode( const wxPoint& aPosition, EDA_ITEMS& aList ) { for( SCH_ITEM* item = m_drawList.begin(); item; item = item->Next() ) { if( item->Type() == SCH_LINE_T && item->HitTest( aPosition ) && (item->GetLayer() == LAYER_BUS || item->GetLayer() == LAYER_WIRE) ) { aList.push_back( item ); } else if( item->Type() == SCH_JUNCTION_T && item->HitTest( aPosition ) ) { aList.push_back( item ); } } return (int) aList.size(); }
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)); }
void SCH_EDIT_FRAME::OnDragItem( wxCommandEvent& aEvent ) { SCH_SCREEN* screen = GetScreen(); SCH_ITEM* item = screen->GetCurItem(); INSTALL_UNBUFFERED_DC( dc, m_canvas ); if( item == NULL ) { // If we didn't get here by a hot key, then something has gone wrong. if( aEvent.GetInt() == 0 ) return; EDA_HOTKEY_CLIENT_DATA* data = (EDA_HOTKEY_CLIENT_DATA*) aEvent.GetClientObject(); wxCHECK_RET( data != NULL, wxT( "Invalid hot key client object." ) ); item = LocateAndShowItem( data->GetPosition(), SCH_COLLECTOR::DraggableItems, aEvent.GetInt() ); // Exit if no item found at the current location or the item is already being edited. if( (item == NULL) || (item->GetFlags() != 0) ) return; } switch( item->Type() ) { case SCH_BUS_BUS_ENTRY_T: case SCH_BUS_WIRE_ENTRY_T: case SCH_LINE_T: case SCH_JUNCTION_T: if( item->GetLayer() == LAYER_BUS ) break; // Fall thru if item is not on bus layer. case SCH_COMPONENT_T: case SCH_LABEL_T: case SCH_GLOBAL_LABEL_T: case SCH_HIERARCHICAL_LABEL_T: case SCH_SHEET_T: m_canvas->MoveCursorToCrossHair(); // The easiest way to handle a drag component or sheet command // is to simulate a block drag command if( screen->m_BlockLocate.GetState() == STATE_NO_BLOCK ) { if( !HandleBlockBegin( &dc, BLOCK_DRAG, GetCrossHairPosition() ) ) break; // Give a non null size to the search block: screen->m_BlockLocate.Inflate( 1 ); HandleBlockEnd( &dc ); } break; default: wxFAIL_MSG( wxString::Format( wxT( "Cannot drag schematic item type %s." ), GetChars( item->GetClass() ) ) ); } }
bool SCH_EDIT_FRAME::OnRightClick( const wxPoint& aPosition, wxMenu* PopMenu ) { SCH_ITEM* item = GetScreen()->GetCurItem(); bool blockActive = GetScreen()->IsBlockActive(); wxString msg; // Do not start a block command on context menu. m_canvas->SetCanStartBlock( -1 ); if( blockActive ) { AddMenusForBlock( PopMenu, this ); PopMenu->AppendSeparator(); // If we have a block containing only one main element // we append its edition submenu if( item != NULL ) { switch( item->Type() ) { case SCH_COMPONENT_T: AddMenusForEditComponent( PopMenu, (SCH_COMPONENT *) item, Prj().SchLibs() ); PopMenu->AppendSeparator(); break; case SCH_TEXT_T: msg = AddHotkeyName( _( "Edit Text" ), g_Schematic_Hokeys_Descr, HK_EDIT ); AddMenuItem( PopMenu, ID_SCH_EDIT_ITEM, msg, KiBitmap( edit_text_xpm ) ); PopMenu->AppendSeparator(); break; case SCH_LABEL_T: msg = AddHotkeyName( _( "Edit Label" ), g_Schematic_Hokeys_Descr, HK_EDIT ); AddMenuItem( PopMenu, ID_SCH_EDIT_ITEM, msg, KiBitmap( edit_text_xpm ) ); PopMenu->AppendSeparator(); break; case SCH_GLOBAL_LABEL_T: msg = AddHotkeyName( _( "Edit Global Label" ), g_Schematic_Hokeys_Descr, HK_EDIT ); AddMenuItem( PopMenu, ID_SCH_EDIT_ITEM, msg, KiBitmap( edit_text_xpm ) ); PopMenu->AppendSeparator(); break; case SCH_HIERARCHICAL_LABEL_T: msg = AddHotkeyName( _( "Edit Hierarchical Label" ), g_Schematic_Hokeys_Descr, HK_EDIT ); AddMenuItem( PopMenu, ID_SCH_EDIT_ITEM, msg, KiBitmap( edit_text_xpm ) ); PopMenu->AppendSeparator(); break; case SCH_BITMAP_T: msg = AddHotkeyName( _( "Edit Image" ), g_Schematic_Hokeys_Descr, HK_EDIT ); AddMenuItem( PopMenu, ID_SCH_EDIT_ITEM, msg, KiBitmap( image_xpm ) ); PopMenu->AppendSeparator(); break; default: break; } } return true; } // Try to locate items at cursor position. if( (item == NULL) || (item->GetFlags() == 0) ) { item = LocateAndShowItem( aPosition, SCH_COLLECTOR::AllItemsButPins ); // If the clarify item selection context menu is aborted, don't show the context menu. if( item == NULL && m_canvas->GetAbortRequest() ) { m_canvas->SetAbortRequest( false ); return false; } } // If a command is in progress: add "cancel" and "end tool" menu // If if( GetToolId() != ID_NO_TOOL_SELECTED ) { if( item && item->GetFlags() ) { AddMenuItem( PopMenu, ID_CANCEL_CURRENT_COMMAND, _( "Cancel" ), KiBitmap( cancel_xpm ) ); } else { AddMenuItem( PopMenu, ID_CANCEL_CURRENT_COMMAND, _( "End Tool" ), KiBitmap( cursor_xpm ) ); } PopMenu->AppendSeparator(); switch( GetToolId() ) { case ID_WIRE_BUTT: AddMenusForWire( PopMenu, NULL, this ); if( item == NULL ) PopMenu->AppendSeparator(); break; case ID_BUS_BUTT: AddMenusForBus( PopMenu, NULL, this ); if( item == NULL ) PopMenu->AppendSeparator(); break; default: break; } } else { if( item && item->GetFlags() ) { AddMenuItem( PopMenu, ID_CANCEL_CURRENT_COMMAND, _( "Cancel" ), KiBitmap( cancel_xpm ) ); PopMenu->AppendSeparator(); } } if( item == NULL ) { if( m_CurrentSheet->Last() != g_RootSheet ) { msg = AddHotkeyName( _( "Leave Sheet" ), g_Schematic_Hokeys_Descr, HK_LEAVE_SHEET ); AddMenuItem( PopMenu, ID_POPUP_SCH_LEAVE_SHEET, msg, KiBitmap( leave_sheet_xpm ) ); PopMenu->AppendSeparator(); } return true; } bool is_new = item->IsNew(); switch( item->Type() ) { case SCH_NO_CONNECT_T: AddMenuItem( PopMenu, ID_POPUP_SCH_DELETE, _( "Delete No Connect" ), KiBitmap( delete_xpm ) ); break; case SCH_JUNCTION_T: addJunctionMenuEntries( PopMenu, (SCH_JUNCTION*) item ); break; case SCH_BUS_BUS_ENTRY_T: case SCH_BUS_WIRE_ENTRY_T: AddMenusForBusEntry( PopMenu, static_cast<SCH_BUS_ENTRY_BASE*>( item ) ); break; case SCH_MARKER_T: AddMenusForMarkers( PopMenu, (SCH_MARKER*) item, this ); break; case SCH_TEXT_T: AddMenusForText( PopMenu, (SCH_TEXT*) item ); break; case SCH_LABEL_T: AddMenusForLabel( PopMenu, (SCH_LABEL*) item ); break; case SCH_GLOBAL_LABEL_T: AddMenusForGLabel( PopMenu, (SCH_GLOBALLABEL*) item ); break; case SCH_HIERARCHICAL_LABEL_T: AddMenusForHLabel( PopMenu, (SCH_HIERLABEL*) item ); break; case SCH_FIELD_T: AddMenusForComponentField( PopMenu, (SCH_FIELD*) item ); break; case SCH_COMPONENT_T: AddMenusForComponent( PopMenu, (SCH_COMPONENT*) item, Prj().SchLibs() ); break; case SCH_BITMAP_T: AddMenusForBitmap( PopMenu, (SCH_BITMAP*) item ); break; case SCH_LINE_T: switch( item->GetLayer() ) { case LAYER_WIRE: AddMenusForWire( PopMenu, (SCH_LINE*) item, this ); break; case LAYER_BUS: AddMenusForBus( PopMenu, (SCH_LINE*) item, this ); break; default: if( is_new ) AddMenuItem( PopMenu, ID_POPUP_END_LINE, _( "End Drawing" ), KiBitmap( checked_ok_xpm ) ); AddMenuItem( PopMenu, ID_POPUP_SCH_DELETE, _( "Delete Drawing" ), KiBitmap( delete_xpm ) ); break; } break; case SCH_SHEET_T: AddMenusForHierchicalSheet( PopMenu, (SCH_SHEET*) item ); break; case SCH_SHEET_PIN_T: AddMenusForSheetPin( PopMenu, (SCH_SHEET_PIN*) item ); break; default: wxFAIL_MSG( wxString::Format( wxT( "Cannot create context menu for unknown type %d" ), item->Type() ) ); break; } PopMenu->AppendSeparator(); return true; }
bool SCH_SCREEN::IsJunctionNeeded( const wxPoint& aPosition, bool aNew ) { bool has_nonparallel[2] = { false }; int end_count[2] = { 0 }; int pin_count = 0; std::vector<SCH_LINE*> lines[2]; for( SCH_ITEM* item = m_drawList.begin(); item; item = item->Next() ) { if( item->GetFlags() & STRUCT_DELETED ) continue; if( aNew && ( item->Type() == SCH_JUNCTION_T ) && ( item->HitTest( aPosition ) ) ) return false; if( ( item->Type() == SCH_LINE_T ) && ( item->HitTest( aPosition, 0 ) ) ) { if( item->GetLayer() == LAYER_WIRE ) lines[0].push_back( (SCH_LINE*) item ); else if( item->GetLayer() == LAYER_BUS ) lines[1].push_back( (SCH_LINE*) item ); } if( ( item->Type() == SCH_COMPONENT_T ) && ( item->IsConnected( aPosition ) ) ) pin_count++; } for( int i = 0; i < 2; i++ ) { bool removed_overlapping = false; end_count[i] = lines[i].size(); for( auto line = lines[i].begin(); line < lines[i].end(); line++ ) { // Consider ending on a line to be equivalent to two endpoints because // we will want to split the line if anything else connects if( !(*line)->IsEndPoint( aPosition ) ) end_count[i]++; for( auto second_line = lines[i].end() - 1; second_line > line; second_line-- ) { if( !(*line)->IsParallel( *second_line ) ) has_nonparallel[i] = true; else if( !removed_overlapping && (*line)->IsSameQuadrant( *second_line, aPosition ) ) { /** * Overlapping lines that point in the same direction should not be counted * as extra end_points. We remove the overlapping lines, being careful to only * remove them once. */ removed_overlapping = true; end_count[i]--; } } } } // // If there are three or more endpoints if( pin_count + end_count[0] > 2 ) return true; // If there is at least one segment that ends on a non-parallel line or // junction of two other lines if( has_nonparallel[0] && end_count[0] > 2 ) return true; // Check for bus - bus junction requirements if( has_nonparallel[1] && end_count[1] > 2 ) return true; return false; }