diff --git a/eeschema/CMakeLists.txt b/eeschema/CMakeLists.txt index 9d9e071519..7a2c2e89aa 100644 --- a/eeschema/CMakeLists.txt +++ b/eeschema/CMakeLists.txt @@ -243,6 +243,7 @@ set( EESCHEMA_SRCS netlist_exporters/netlist_exporter_pspice.cpp tools/sch_actions.cpp + tools/sch_drawing_tool.cpp tools/sch_picker_tool.cpp tools/sch_selection_tool.cpp tools/selection.cpp diff --git a/eeschema/bus-wire-junction.cpp b/eeschema/bus-wire-junction.cpp index 4056b33c49..e6dcf58eb5 100644 --- a/eeschema/bus-wire-junction.cpp +++ b/eeschema/bus-wire-junction.cpp @@ -22,293 +22,17 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ -/** - * @file bus-wire-junction.cpp - * @brief Code for editing buses, wires, and junctions. - */ - #include -#include -#include #include - #include -#include #include #include #include #include #include -#include #include #include -#include #include -#include - - - -static void AbortCreateNewLine( EDA_DRAW_PANEL* aPanel, wxDC* aDC ); -static void ComputeBreakPoint( SCH_SCREEN* aScreen, SCH_LINE* aSegment, wxPoint& new_pos ); - -static DLIST< SCH_ITEM > s_wires; // when creating a new set of wires, - // stores here the new wires. - -/** - * 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& aWires ) -{ - EDA_ITEM* first = aWires.GetFirst(); - std::vector last_lines; - - for( EDA_ITEM* p = first; p; ) - { - SCH_LINE *line = static_cast( p ); - p = line->Next(); - - if( line->IsNull() ) - { - delete s_wires.Remove( line ); - continue; - } - - 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 ); - } - } -} - - -/** - * Mouse capture callback for drawing line segments. - */ -static void DrawSegment( EDA_DRAW_PANEL* aPanel, wxDC* aDC, const wxPoint& aPosition, bool aErase ) -{ - if( s_wires.GetCount() == 0 ) - return; - - SCH_EDIT_FRAME* frame = (SCH_EDIT_FRAME*) aPanel->GetParent(); - - wxPoint endpos = frame->GetCrossHairPosition(); - - auto view = static_cast( aPanel )->GetView(); - view->ClearPreview(); - - // Update the bus unfold posture based on the mouse movement - if( frame->m_busUnfold.in_progress && !frame->m_busUnfold.label_placed ) - { - auto cursor_delta = frame->GetCursorPosition( false ) - frame->m_busUnfold.origin; - auto entry = frame->m_busUnfold.entry; - - bool offset = ( cursor_delta.x < 0 ); - char shape = ( offset ? ( ( cursor_delta.y >= 0 ) ? '/' : '\\' ) - : ( ( cursor_delta.y >= 0 ) ? '\\' : '/' ) ); - - // Erase and redraw if necessary - if( shape != entry->GetBusEntryShape() || - offset != frame->m_busUnfold.offset ) - { - entry->SetBusEntryShape( shape ); - wxPoint entry_pos = frame->m_busUnfold.origin; - - if( offset ) - entry_pos -= entry->GetSize(); - - entry->SetPosition( entry_pos ); - frame->m_busUnfold.offset = offset; - - frame->RefreshItem( entry ); - - wxPoint wire_start = ( offset ? entry->GetPosition() : entry->m_End() ); - ( (SCH_LINE*) s_wires.begin() )->SetStartPoint( wire_start ); - } - - // Update the label "ghost" position - auto label = frame->m_busUnfold.label; - label->SetPosition( endpos ); - view->AddToPreview( label->Clone() ); - } - - if( frame->GetForceHVLines() ) /* Coerce the line to vertical or horizontal one: */ - ComputeBreakPoint( frame->GetScreen(), (SCH_LINE*) s_wires.GetLast()->Back(), endpos ); - else - ( (SCH_LINE*) s_wires.GetLast() )->SetEndPoint( endpos ); - - for( SCH_LINE* segment = (SCH_LINE*) s_wires.begin(); segment; segment = segment->Next() ) - { - if( !segment->IsNull() ) // Add to preview if segment length != 0 - view->AddToPreview( segment->Clone() ); - } -} - - -void SCH_EDIT_FRAME::BeginSegment( 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 ) || - ( segment->GetLayer() != type ) ) - { - 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. - { - // Place the label for bus unfolding if needed - if( IsBusUnfoldInProgress() && !m_busUnfold.label_placed ) - { - wxASSERT( type == LAYER_WIRE ); - - AddToScreen( m_busUnfold.label ); - m_busUnfold.label_placed = true; - - nextSegment = new SCH_LINE( cursorpos, LAYER_WIRE ); - - segment->ClearFlags( IS_NEW ); - segment->SetFlags( SELECTED ); - - nextSegment->SetStartPoint( cursorpos ); - nextSegment->SetFlags( IS_NEW ); - - s_wires.PushBack( nextSegment ); - GetScreen()->SetCurItem( nextSegment ); - - m_canvas->SetMouseCapture( DrawSegment, AbortCreateNewLine ); - SetRepeatItem( NULL ); - return; - } - - 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( nullptr, wxDefaultPosition, false ); - - // Terminate the command if the end point is on a pin, junction, or another wire or bus. - if( !IsBusUnfoldInProgress() && - GetScreen()->IsTerminalPoint( cursorpos, segment->GetLayer() ) ) - { - EndSegment(); - 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( nullptr, wxDefaultPosition, false ); - } -} void SCH_EDIT_FRAME::GetSchematicConnections( std::vector< wxPoint >& aConnections ) @@ -349,207 +73,6 @@ bool SCH_EDIT_FRAME::TestDanglingEnds() } -void SCH_EDIT_FRAME::EndSegment() -{ - SCH_SCREEN* screen = GetScreen(); - SCH_LINE* segment = (SCH_LINE*) screen->GetCurItem(); - PICKED_ITEMS_LIST itemList; - - if( segment == NULL || segment->Type() != SCH_LINE_T || !segment->IsNew() ) - return; - - // Remove segments backtracking over others - RemoveBacktracks( s_wires ); - - if( s_wires.GetCount() == 0 ) - return; - - // Collect the possible connection points for the new lines - std::vector< wxPoint > connections; - std::vector< wxPoint > new_ends; - GetSchematicConnections( connections ); - - // Check each new segment for possible junctions and add/split if needed - for( SCH_ITEM* wire = s_wires.GetFirst(); wire; wire=wire->Next() ) - { - SCH_LINE* test_line = (SCH_LINE*) wire; - if( wire->GetFlags() & SKIP_STRUCT ) - continue; - - wire->GetConnectionPoints( new_ends ); - - for( auto i : connections ) - { - if( IsPointOnSegment( test_line->GetStartPoint(), test_line->GetEndPoint(), i ) ) - { - new_ends.push_back( i ); - } - } - itemList.PushItem( ITEM_PICKER( wire, UR_NEW ) ); - } - - if( IsBusUnfoldInProgress() && m_busUnfold.label_placed ) - { - wxASSERT( m_busUnfold.entry && m_busUnfold.label ); - - itemList.PushItem( ITEM_PICKER( m_busUnfold.entry, UR_NEW ) ); - itemList.PushItem( ITEM_PICKER( m_busUnfold.label, UR_NEW ) ); - } - - // Get the last non-null wire (this is the last created segment). - SetRepeatItem( segment = (SCH_LINE*) s_wires.GetLast() ); - - // Add the new wires - AddToScreen( s_wires ); - - auto view = GetCanvas()->GetView(); - view->ClearPreview(); - view->ShowPreview( false ); - view->ClearHiddenFlags(); - - SaveCopyInUndoList(itemList, UR_NEW); - - // Correct and remove segments that need to be merged. - SchematicCleanUp( true ); - - for( auto item = GetScreen()->GetDrawItems(); item; item = item->Next() ) - { - if( item->Type() != SCH_COMPONENT_T ) - continue; - - std::vector< wxPoint > pts; - item->GetConnectionPoints( pts ); - - if( pts.size() > 2 ) - continue; - - for( auto i = pts.begin(); i != pts.end(); i++ ) - for( auto j = i + 1; j != pts.end(); j++ ) - TrimWire( *i, *j, true ); - } - - for( auto i : new_ends ) - { - if( screen->IsJunctionNeeded( i, true ) ) - AddJunction( i, true, false ); - } - - if( IsBusUnfoldInProgress() ) - { - FinishBusUnfold(); - } - - TestDanglingEnds(); - - screen->ClearDrawingState(); - screen->SetCurItem( NULL ); - m_canvas->EndMouseCapture( -1, -1, wxEmptyString, false ); - m_canvas->Refresh(); - OnModify(); -} - - -// A helper function to find any sheet pins at the specified position. -static const SCH_SHEET_PIN* getSheetPin( SCH_SCREEN* aScreen, const wxPoint& aPosition ) -{ - for( SCH_ITEM* item = aScreen->GetDrawItems(); item; item = item->Next() ) - { - if( item->Type() == SCH_SHEET_T ) - { - SCH_SHEET* sheet = (SCH_SHEET*) item; - - for( const SCH_SHEET_PIN& pin : sheet->GetPins() ) - { - if( pin.GetPosition() == aPosition ) - return &pin; - } - } - } - - return nullptr; -} - - -/** - * 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_SCREEN* aScreen, SCH_LINE* aSegment, wxPoint& aPosition ) -{ - wxCHECK_RET( aSegment != nullptr, wxT( "Cannot compute break point of NULL line segment." ) ); - - SCH_LINE* nextSegment = aSegment->Next(); - - wxPoint midPoint; - int iDx = aSegment->GetEndPoint().x - aSegment->GetStartPoint().x; - int iDy = aSegment->GetEndPoint().y - aSegment->GetStartPoint().y; - - const SCH_SHEET_PIN* connectedPin = getSheetPin( aScreen, aSegment->GetStartPoint() ); - auto force = connectedPin ? connectedPin->GetEdge() : SCH_SHEET_PIN::SHEET_UNDEFINED_SIDE; - - if( force == SCH_SHEET_PIN::SHEET_LEFT_SIDE || force == SCH_SHEET_PIN::SHEET_RIGHT_SIDE ) - { - if( aPosition.x == connectedPin->GetPosition().x ) // push outside sheet boundary - { - int direction = ( force == SCH_SHEET_PIN::SHEET_LEFT_SIDE ) ? -1 : 1; - aPosition.x += aScreen->GetGridSize().x * direction; - } - - midPoint.x = aPosition.x; - midPoint.y = aSegment->GetStartPoint().y; // force horizontal - } - else if( iDy != 0 ) // keep the first segment orientation (vertical) - { - midPoint.x = aSegment->GetStartPoint().x; - midPoint.y = aPosition.y; - } - else if( iDx != 0 ) // keep the first segment orientation (horizontal) - { - midPoint.x = aPosition.x; - midPoint.y = aSegment->GetStartPoint().y; - } - else - { - if( std::abs( aPosition.x - aSegment->GetStartPoint().x ) < - std::abs( aPosition.y - aSegment->GetStartPoint().y ) ) - { - midPoint.x = aSegment->GetStartPoint().x; - midPoint.y = aPosition.y; - } - else - { - midPoint.x = aPosition.x; - midPoint.y = aSegment->GetStartPoint().y; - } - } - - aSegment->SetEndPoint( midPoint ); - nextSegment->SetStartPoint( midPoint ); - nextSegment->SetEndPoint( aPosition ); -} - - -void SCH_EDIT_FRAME::DeleteCurrentSegment() -{ - SCH_SCREEN* screen = GetScreen(); - - SetRepeatItem( NULL ); - - if( ( screen->GetCurItem() == NULL ) || !screen->GetCurItem()->IsNew() ) - return; - - RemoveFromScreen( screen->GetCurItem() ); - m_canvas->SetMouseCaptureCallback( NULL ); - screen->SetCurItem( NULL ); -} - - bool SCH_EDIT_FRAME::TrimWire( const wxPoint& aStart, const wxPoint& aEnd, bool aAppend ) { SCH_LINE* line; @@ -950,39 +473,6 @@ SCH_NO_CONNECT* SCH_EDIT_FRAME::AddNoConnect( const wxPoint& aPosition ) } -/* Abort function for wire, bus or line creation - */ -static void AbortCreateNewLine( EDA_DRAW_PANEL* aPanel, wxDC* aDC ) -{ - SCH_SCREEN* screen = (SCH_SCREEN*) aPanel->GetScreen(); - - SCH_EDIT_FRAME* parent = ( SCH_EDIT_FRAME* ) aPanel->GetParent(); - - if( screen->GetCurItem() ) - { - s_wires.DeleteAll(); // Free the list, for a future usage - screen->SetCurItem( NULL ); - } - else - { - parent->SetRepeatItem( NULL ); - } - - if( parent->IsBusUnfoldInProgress() ) - { - parent->CancelBusUnfold(); - } - - auto view = static_cast(aPanel)->GetView(); - view->ClearPreview(); - view->ShowPreview( false ); - view->ClearHiddenFlags(); - - // Clear flags used in edit functions. - screen->ClearDrawingState(); -} - - void SCH_EDIT_FRAME::RepeatDrawItem() { SCH_ITEM* repeater = GetRepeatItem(); diff --git a/eeschema/eeschema_id.h b/eeschema/eeschema_id.h index b0bc4cbee9..e6ac2f0f13 100644 --- a/eeschema/eeschema_id.h +++ b/eeschema/eeschema_id.h @@ -144,7 +144,6 @@ enum id_eeschema_frm ID_POPUP_SCH_INIT_CMP, - ID_POPUP_SCH_SET_SHAPE_TEXT, ID_POPUP_SCH_END_SHEET, ID_POPUP_SCH_RESIZE_SHEET, ID_POPUP_SCH_CLEANUP_SHEET, diff --git a/eeschema/libedit/lib_edit_frame.cpp b/eeschema/libedit/lib_edit_frame.cpp index a84aed22d9..6859de3099 100644 --- a/eeschema/libedit/lib_edit_frame.cpp +++ b/eeschema/libedit/lib_edit_frame.cpp @@ -69,7 +69,7 @@ int LIB_EDIT_FRAME:: m_unit = 1; int LIB_EDIT_FRAME:: m_convert = 1; -LIB_ITEM* LIB_EDIT_FRAME::m_lastDrawItem = NULL; +LIB_ITEM* LIB_EDIT_FRAME:: m_lastDrawItem = NULL; bool LIB_EDIT_FRAME:: m_showDeMorgan = false; int LIB_EDIT_FRAME:: m_textSize = -1; @@ -1750,7 +1750,7 @@ void LIB_EDIT_FRAME::ShowChangedLanguage() void LIB_EDIT_FRAME::SetScreen( BASE_SCREEN* aScreen ) { - EDA_DRAW_FRAME::SetScreen( aScreen ); + SCH_BASE_FRAME::SetScreen( aScreen ); } diff --git a/eeschema/onleftclick.cpp b/eeschema/onleftclick.cpp index b8f04888e8..7b69ba78fc 100644 --- a/eeschema/onleftclick.cpp +++ b/eeschema/onleftclick.cpp @@ -27,16 +27,12 @@ #include #include #include -#include #include #include #include -#include -#include #include #include #include -#include #include #include @@ -45,6 +41,8 @@ void SCH_EDIT_FRAME::OnLeftClick( wxDC* aDC, const wxPoint& aPosition ) switch( GetToolId() ) { case ID_HIGHLIGHT_BUTT: + case ID_WIRE_BUTT: + case ID_BUS_BUTT: case ID_NOCONN_BUTT: case ID_JUNCTION_BUTT: case ID_WIRETOBUS_ENTRY_BUTT: @@ -55,6 +53,7 @@ void SCH_EDIT_FRAME::OnLeftClick( wxDC* aDC, const wxPoint& aPosition ) case ID_GLOBALLABEL_BUTT: case ID_HIERLABEL_BUTT: case ID_TEXT_COMMENT_BUTT: + case ID_LINE_COMMENT_BUTT: case ID_ADD_IMAGE_BUTT: return; // Moved to modern toolset default: @@ -82,9 +81,6 @@ void SCH_EDIT_FRAME::OnLeftClick( wxDC* aDC, const wxPoint& aPosition ) GetCanvas()->GetView()->ClearHiddenFlags(); return; - case SCH_LINE_T: // May already be drawing segment. - break; - default: wxFAIL_MSG( wxT( "SCH_EDIT_FRAME::OnLeftClick error. Item type <" ) + item->GetClass() + wxT( "> is already being edited." ) ); @@ -113,21 +109,6 @@ void SCH_EDIT_FRAME::OnLeftClick( wxDC* aDC, const wxPoint& aPosition ) DeleteItemAtCrossHair(); break; - case ID_WIRE_BUTT: - BeginSegment( LAYER_WIRE ); - m_canvas->SetAutoPanRequest( true ); - break; - - case ID_BUS_BUTT: - BeginSegment( LAYER_BUS ); - m_canvas->SetAutoPanRequest( true ); - break; - - case ID_LINE_COMMENT_BUTT: - BeginSegment( LAYER_NOTES ); - m_canvas->SetAutoPanRequest( true ); - break; - case ID_SHEET_SYMBOL_BUTT: if( item_flags == 0 ) { @@ -244,9 +225,7 @@ void SCH_EDIT_FRAME::OnLeftDClick( wxDC* aDC, const wxPoint& aPosition ) { case ID_NO_TOOL_SELECTED: if( ( item == NULL ) || ( item->GetFlags() == 0 ) ) - { item = LocateAndShowItem( aPosition, SCH_COLLECTOR::DoubleClickItems ); - } if( ( item == NULL ) || ( item->GetFlags() != 0 ) ) break; @@ -276,7 +255,6 @@ void SCH_EDIT_FRAME::OnLeftDClick( wxDC* aDC, const wxPoint& aPosition ) break; case SCH_BITMAP_T: - // The bitmap is cached in Opengl: clear the cache, because // the cache data is perhaps invalid if( EditImage( (SCH_BITMAP*) item ) ) @@ -298,13 +276,5 @@ void SCH_EDIT_FRAME::OnLeftDClick( wxDC* aDC, const wxPoint& aPosition ) } break; - - case ID_BUS_BUTT: - case ID_WIRE_BUTT: - case ID_LINE_COMMENT_BUTT: - if( item && item->IsNew() ) - EndSegment(); - - break; } } diff --git a/eeschema/onrightclick.cpp b/eeschema/onrightclick.cpp index 7bae98cddb..0134713ede 100644 --- a/eeschema/onrightclick.cpp +++ b/eeschema/onrightclick.cpp @@ -54,6 +54,7 @@ #include #include +#include static void AddMenusForBlock( wxMenu* PopMenu, SCH_EDIT_FRAME* frame ); static void AddMenusForWire( wxMenu* PopMenu, SCH_LINE* Wire, SCH_EDIT_FRAME* frame ); diff --git a/eeschema/sch_base_frame.cpp b/eeschema/sch_base_frame.cpp index 528914a277..a27a316fc2 100644 --- a/eeschema/sch_base_frame.cpp +++ b/eeschema/sch_base_frame.cpp @@ -64,10 +64,9 @@ LIB_ALIAS* SchGetLibAlias( const LIB_ID& aLibId, SYMBOL_LIB_TABLE* aLibTable, PA { if( aShowErrorMsg ) { - wxString msg; - - msg.Printf( _( "Could not load symbol \"%s\" from library \"%s\"." ), - aLibId.GetLibItemName().wx_str(), aLibId.GetLibNickname().wx_str() ); + wxString msg = wxString::Format( _( "Error loading symbol '%s' from library '%s'." ), + aLibId.GetLibItemName().wx_str(), + aLibId.GetLibNickname().wx_str() ); DisplayErrorMessage( aParent, msg, ioe.What() ); } } @@ -87,12 +86,10 @@ LIB_PART* SchGetLibPart( const LIB_ID& aLibId, SYMBOL_LIB_TABLE* aLibTable, PART // Static members: -SCH_BASE_FRAME::SCH_BASE_FRAME( KIWAY* aKiway, wxWindow* aParent, - FRAME_T aWindowType, const wxString& aTitle, - const wxPoint& aPosition, const wxSize& aSize, long aStyle, - const wxString& aFrameName ) : - EDA_DRAW_FRAME( aKiway, aParent, aWindowType, aTitle, aPosition, - aSize, aStyle, aFrameName ) +SCH_BASE_FRAME::SCH_BASE_FRAME( KIWAY* aKiway, wxWindow* aParent, FRAME_T aWindowType, + const wxString& aTitle, const wxPoint& aPosition, + const wxSize& aSize, long aStyle, const wxString& aFrameName ) : + EDA_DRAW_FRAME( aKiway, aParent, aWindowType, aTitle, aPosition, aSize, aStyle, aFrameName ) { createCanvas(); @@ -142,9 +139,7 @@ void SCH_BASE_FRAME::OnUpdateSwitchCanvas( wxUpdateUIEvent& aEvent ) { wxMenuItem* item = menuBar->FindItem( ii.menuId ); if( ii.galType == canvasType ) - { item->Check( true ); - } } } @@ -185,6 +180,18 @@ SCH_SCREEN* SCH_BASE_FRAME::GetScreen() const } +void SCH_BASE_FRAME::SetScreen( BASE_SCREEN* aScreen ) +{ + EDA_DRAW_FRAME::SetScreen( aScreen ); + + if( m_toolManager ) + { + m_toolManager->SetEnvironment( GetScreen(), GetCanvas()->GetView(), + GetCanvas()->GetViewControls(), this ); + } +} + + const wxString SCH_BASE_FRAME::GetZoomLevelIndicator() const { return EDA_DRAW_FRAME::GetZoomLevelIndicator(); @@ -351,7 +358,7 @@ bool SCH_BASE_FRAME::saveSymbolLibTables( bool aGlobal, bool aProject ) catch( const IO_ERROR& ioe ) { success = false; - msg.Printf( _( "Error saving global symbol library table:\n\n%s" ), ioe.What() ); + msg.Printf( _( "Error saving global symbol library table:\n%s" ), ioe.What() ); wxMessageBox( msg, _( "File Save Error" ), wxOK | wxICON_ERROR ); } } @@ -367,7 +374,7 @@ bool SCH_BASE_FRAME::saveSymbolLibTables( bool aGlobal, bool aProject ) catch( const IO_ERROR& ioe ) { success = false; - msg.Printf( _( "Error saving project-specific symbol library table:\n\n%s" ), ioe.What() ); + msg.Printf( _( "Error saving project-specific symbol library table:\n%s" ), ioe.What() ); wxMessageBox( msg, _( "File Save Error" ), wxOK | wxICON_ERROR ); } } @@ -388,9 +395,7 @@ void SCH_BASE_FRAME::Zoom_Automatique( bool aWarpPointer ) VECTOR2D screenSize = view->ToWorld( galCanvas->GetClientSize(), false ); if( bBox.GetWidth() == 0 || bBox.GetHeight() == 0 ) - { bBox = galCanvas->GetDefaultViewBBox(); - } VECTOR2D vsize = bBox.GetSize(); double scale = view->GetScale() / std::max( fabs( vsize.x / screenSize.x ), @@ -434,8 +439,7 @@ void SCH_BASE_FRAME::Window_Zoom( EDA_RECT& aRect ) VECTOR2D vsize = selectionBox.GetSize(); double scale; - double ratio = std::max( fabs( vsize.x / screenSize.x ), - fabs( vsize.y / screenSize.y ) ); + double ratio = std::max( fabs( vsize.x / screenSize.x ), fabs( vsize.y / screenSize.y ) ); scale = view->GetScale() / ratio; @@ -606,9 +610,11 @@ void SCH_BASE_FRAME::createCanvas() m_canvasType = LoadCanvasTypeSetting(); // Allows only a CAIRO or OPENGL canvas: - if( m_canvasType != EDA_DRAW_PANEL_GAL::GAL_TYPE_OPENGL && - m_canvasType != EDA_DRAW_PANEL_GAL::GAL_TYPE_CAIRO ) + if( m_canvasType != EDA_DRAW_PANEL_GAL::GAL_TYPE_OPENGL + && m_canvasType != EDA_DRAW_PANEL_GAL::GAL_TYPE_CAIRO ) + { m_canvasType = EDA_DRAW_PANEL_GAL::GAL_TYPE_OPENGL; + } m_canvas = new SCH_DRAW_PANEL( this, wxID_ANY, wxPoint( 0, 0 ), m_FrameSize, GetGalDisplayOptions(), m_canvasType ); @@ -661,26 +667,6 @@ void SCH_BASE_FRAME::AddToScreen( SCH_ITEM* aItem, SCH_SCREEN* aScreen ) } -void SCH_BASE_FRAME::AddToScreen( DLIST& aItems, SCH_SCREEN* aScreen ) -{ - auto screen = aScreen; - - if( aScreen == nullptr ) - screen = GetScreen(); - - if( screen == GetScreen() ) - { - for( SCH_ITEM* item = aItems.begin(); item; item = item->Next() ) - { - GetCanvas()->GetView()->Add( item ); - RefreshItem( item, true ); // handle any additional parent semantics - } - } - - screen->Append( aItems ); -} - - void SCH_BASE_FRAME::RemoveFromScreen( SCH_ITEM* aItem, SCH_SCREEN* aScreen ) { auto screen = aScreen; diff --git a/eeschema/sch_base_frame.h b/eeschema/sch_base_frame.h index c837f9e156..351802e1ee 100644 --- a/eeschema/sch_base_frame.h +++ b/eeschema/sch_base_frame.h @@ -106,6 +106,7 @@ public: SCH_DRAW_PANEL* GetCanvas() const override; SCH_SCREEN* GetScreen() const override; + void SetScreen( BASE_SCREEN* aScreen ) override; KIGFX::SCH_RENDER_SETTINGS* GetRenderSettings(); @@ -302,12 +303,6 @@ public: */ void AddToScreen( SCH_ITEM* aItem, SCH_SCREEN* aScreen = nullptr ); - /** - * Add a list of items to the screen (and view) - * aScreen is the screen the item is located on, if not the current screen - */ - void AddToScreen( DLIST& aItems, SCH_SCREEN* aScreen = nullptr ); - /** * Remove an item from the screen (and view) * aScreen is the screen the item is located on, if not the current screen diff --git a/eeschema/sch_draw_panel.cpp b/eeschema/sch_draw_panel.cpp index 735adbd428..923cdf2a36 100644 --- a/eeschema/sch_draw_panel.cpp +++ b/eeschema/sch_draw_panel.cpp @@ -43,22 +43,10 @@ using namespace std::placeholders; // Events used by EDA_DRAW_PANEL -// GAL TODO: some (most?) of these need to be implemented... BEGIN_EVENT_TABLE( SCH_DRAW_PANEL, wxScrolledCanvas ) -// EVT_LEAVE_WINDOW( EDA_DRAW_PANEL::OnMouseLeaving ) -// EVT_ENTER_WINDOW( EDA_DRAW_PANEL::OnMouseEntering ) -// EVT_MOUSEWHEEL( EDA_DRAW_PANEL::OnMouseWheel ) -#if wxCHECK_VERSION( 3, 1, 0 ) || defined( USE_OSX_MAGNIFY_EVENT ) -// EVT_MAGNIFY( EDA_DRAW_PANEL::OnMagnify ) -#endif -// EVT_MOUSE_EVENTS( EDA_DRAW_PANEL::OnMouseEvent ) EVT_CHAR( SCH_DRAW_PANEL::OnKeyEvent ) EVT_CHAR_HOOK( SCH_DRAW_PANEL::OnCharHook ) EVT_PAINT( SCH_DRAW_PANEL::onPaint ) -// EVT_ERASE_BACKGROUND( EDA_DRAW_PANEL::OnEraseBackground ) -// EVT_SCROLLWIN( EDA_DRAW_PANEL::OnScroll ) -// EVT_ACTIVATE( EDA_DRAW_PANEL::OnActivate ) -// EVT_MENU_RANGE( ID_PAN_UP, ID_PAN_RIGHT, EDA_DRAW_PANEL::OnPan ) END_EVENT_TABLE() SCH_DRAW_PANEL::SCH_DRAW_PANEL( wxWindow* aParentWindow, wxWindowID aWindowId, @@ -103,9 +91,7 @@ SCH_DRAW_PANEL::SCH_DRAW_PANEL( wxWindow* aParentWindow, wxWindowID aWindowId, }; for( auto e : events ) - { Connect( e, wxMouseEventHandler( SCH_DRAW_PANEL::OnMouseEvent ), NULL, this ); - } Connect( wxEVT_CHAR, wxKeyEventHandler( SCH_DRAW_PANEL::OnKeyEvent ), NULL, this ); Connect( wxEVT_CHAR_HOOK, wxKeyEventHandler( SCH_DRAW_PANEL::OnCharHook ), NULL, this ); @@ -165,12 +151,6 @@ void SCH_DRAW_PANEL::DisplaySheet( const SCH_SCREEN *aScreen ) } -void SCH_DRAW_PANEL::OnShow() -{ - //m_view->RecacheAllItems(); -} - - void SCH_DRAW_PANEL::setDefaultLayerOrder() { for( LAYER_NUM i = 0; (unsigned) i < sizeof( SCH_LAYER_ORDER ) / sizeof( LAYER_NUM ); ++i ) @@ -523,9 +503,7 @@ void SCH_DRAW_PANEL::OnMouseEvent( wxMouseEvent& event ) if( localbutt == (int) ( GR_M_LEFT_DOWN | GR_M_DCLICK ) ) { if( !screen->IsBlockActive() && IsMouseCaptured() ) - { m_endMouseCaptureCallback( this, nullptr ); - } } lastPanel = this; @@ -573,9 +551,7 @@ void SCH_DRAW_PANEL::EndMouseCapture( int id, int cursor, const wxString& title, bool aCallEndFunc ) { if( m_mouseCaptureCallback && m_endMouseCaptureCallback && aCallEndFunc ) - { m_endMouseCaptureCallback( this, nullptr ); - } m_mouseCaptureCallback = NULL; m_endMouseCaptureCallback = NULL; diff --git a/eeschema/sch_draw_panel.h b/eeschema/sch_draw_panel.h index 0e3c2ed180..ff72b82956 100644 --- a/eeschema/sch_draw_panel.h +++ b/eeschema/sch_draw_panel.h @@ -37,30 +37,14 @@ public: virtual wxWindow* GetWindow() override { return this; } - /** - * Function DisplayBoard FIXME - * adds all items from the current board to the VIEW, so they can be displayed by GAL. - * @param aBoard is the PCB to be loaded. - */ - void DisplayComponent( const LIB_PART *aComponent ); - void DisplaySheet( const SCH_SCREEN *aScreen ); - - /** - * Function UseColorScheme - * Applies layer color settings. - * @param aSettings are the new settings. - */ - void UseColorScheme( const COLORS_DESIGN_SETTINGS* aSettings ); - - ///> @copydoc EDA_DRAW_PANEL_GAL::OnShow() - void OnShow() override; + void DisplayComponent( const LIB_PART *aComponent ); + void DisplaySheet( const SCH_SCREEN *aScreen ); bool SwitchBackend( GAL_TYPE aGalType ) override; void OnMouseEvent( wxMouseEvent& event ); bool OnRightClick( wxMouseEvent& event ); void OnKeyEvent( wxKeyEvent& event ); void OnCharHook( wxKeyEvent& event ); - void OnTimer( wxTimerEvent& event ); void SetEnableMousewheelPan( bool aEnable ) override; void SetEnableZoomNoCenter( bool aEnable ) override; @@ -90,19 +74,14 @@ public: protected: - virtual void onPaint( wxPaintEvent& WXUNUSED( aEvent ) ) override; KIGFX::SCH_VIEW* view() const; - - ///> Reassigns layer order to the initial settings. - void setDefaultLayerOrder(); - - ///> Sets rendering targets & dependencies for layers. - void setDefaultLayerDeps(); - wxWindow* m_parent; + void setDefaultLayerOrder(); ///> Reassigns layer order to the initial settings. + void setDefaultLayerDeps(); ///> Sets rendering targets & dependencies for layers. + DECLARE_EVENT_TABLE() }; diff --git a/eeschema/sch_edit_frame.cpp b/eeschema/sch_edit_frame.cpp index dd73f4a812..4d14e96747 100644 --- a/eeschema/sch_edit_frame.cpp +++ b/eeschema/sch_edit_frame.cpp @@ -208,23 +208,6 @@ PART_LIBS* PROJECT::SchLibs() return libs; } -/* -NETLIST_OBJECT_LIST* PROJECT::Netlist() -{ - NETLIST_OBJECT_LIST* netlist = (NETLIST_OBJECT_LIST*) GetElem( PROJECT::ELEM_SCH_NETLIST ); - - wxASSERT( !libs || dynamic_cast( netlist ) ); - - if( !netlist ) - { - netlist = new NETLIST_OBJECT_LIST(); - - // Make PROJECT the new NETLIST_OBJECT_LIST owner. - SetElem( PROJECT::ELEM_SCH_NETLIST, netlist ); - } -} -*/ - //----------------------------------------------- @@ -394,7 +377,6 @@ SCH_EDIT_FRAME::SCH_EDIT_FRAME( KIWAY* aKiway, wxWindow* aParent ): m_findReplaceStatus = new wxString( wxEmptyString ); m_undoItem = NULL; m_hasAutoSave = true; - m_busUnfold = {}; m_FrameSize = ConvertDialogToPixels( wxSize( 500, 350 ) ); // default in case of no prefs SetForceHVLines( true ); @@ -1537,7 +1519,7 @@ void SCH_EDIT_FRAME::ShowChangedLanguage() void SCH_EDIT_FRAME::SetScreen( BASE_SCREEN* aScreen ) { - EDA_DRAW_FRAME::SetScreen( aScreen ); + SCH_BASE_FRAME::SetScreen( aScreen ); auto c = static_cast(m_canvas); c->DisplaySheet( static_cast( aScreen ) ); } diff --git a/eeschema/sch_edit_frame.h b/eeschema/sch_edit_frame.h index 160d790a45..22cbfa38c2 100644 --- a/eeschema/sch_edit_frame.h +++ b/eeschema/sch_edit_frame.h @@ -113,24 +113,6 @@ enum SCH_SEARCH_T { }; -/// Collection of data related to the bus unfolding tool -struct BUS_UNFOLDING_T { - bool in_progress; ///< True if bus unfold operation is running - - bool offset; ///< True if the bus entry should be offset from origin - - bool label_placed; ///< True if user has placed the net label - - wxPoint origin; ///< Origin (on the bus) of the unfold - - wxString net_name; ///< Net label for the unfolding operation - - SCH_BUS_WIRE_ENTRY* entry; - - SCH_LABEL* label; -}; - - /** * Schematic editor (Eeschema) main window. */ @@ -186,11 +168,6 @@ private: /// Use netcodes (net number) as net names when generating spice net lists. bool m_spiceAjustPassiveValues; -public: // TODO(JE) Make private - - /// Data related to bus unfolding tool - BUS_UNFOLDING_T m_busUnfold; - private: /* these are PROJECT specific, not schematic editor specific @@ -812,24 +789,6 @@ public: */ bool AskToSaveChanges(); - /** - * Checks if a bus unfolding operation is in progress, so that it can be - * properly canceled / commited along with the wire draw operation. - */ - bool IsBusUnfoldInProgress() { return m_busUnfold.in_progress; } - - /** - * Cancels a bus unfolding operation, cleaning up the bus entry and label - * that were created - */ - void CancelBusUnfold(); - - /** - * Completes a bus unfolding operation after the user finishes drawing the - * unfolded wire - */ - void FinishBusUnfold(); - SCH_NO_CONNECT* AddNoConnect( const wxPoint& aPosition ); SCH_JUNCTION* AddJunction( const wxPoint& aPosition, bool aAppendToUndo = false, bool aFinal = true ); @@ -840,6 +799,34 @@ public: SCH_TEXT* CreateNewText( int aType ); SCH_BITMAP* CreateNewImage(); + /** + * Performs routine schematic cleaning including breaking wire and buses and + * deleting identical objects superimposed on top of each other. + * + * @param aAppend The changes to the schematic should be appended to the previous undo + * @param aScreen is the screen to examine, or nullptr to examine the current screen + * @return True if any schematic clean up was performed. + */ + bool SchematicCleanUp( bool aAppend = false, SCH_SCREEN* aScreen = nullptr ); + + /** + * If any single wire passes through _both points_, remove the portion between the two points, + * potentially splitting the wire into two. + * + * @param aStart The starting point for trimmming + * @param aEnd The ending point for trimming + * @param aAppend Should the line changes be appended to a previous undo state + * @return True if any wires were changed by this operation + */ + bool TrimWire( const wxPoint& aStart, const wxPoint& aEnd, bool aAppend = true ); + + /** + * Collects a unique list of all possible connection points in the schematic. + * + * @param aConnections vector of connections + */ + void GetSchematicConnections( std::vector< wxPoint >& aConnections ); + private: /** @@ -971,34 +958,6 @@ private: // Bus Entry void SetBusEntryShape( wxDC* DC, SCH_BUS_ENTRY_BASE* BusEntry, char entry_shape ); - /** - * Collects a unique list of all possible connection points in the schematic. - * - * @param aConnections vector of connections - */ - void GetSchematicConnections( std::vector< wxPoint >& aConnections ); - - /** - * Performs routine schematic cleaning including breaking wire and buses and - * deleting identical objects superimposed on top of each other. - * - * @param aAppend The changes to the schematic should be appended to the previous undo - * @param aScreen is the screen to examine, or nullptr to examine the current screen - * @return True if any schematic clean up was performed. - */ - bool SchematicCleanUp( bool aAppend = false, SCH_SCREEN* aScreen = nullptr ); - - /** - * If any single wire passes through _both points_, remove the portion between the two points, - * potentially splitting the wire into two. - * - * @param aStart The starting point for trimmming - * @param aEnd The ending point for trimming - * @param aAppend Should the line changes be appended to a previous undo state - * @return True if any wires were changed by this operation - */ - bool TrimWire( const wxPoint& aStart, const wxPoint& aEnd, bool aAppend = true ); - /** * Checks all wires and adds any junctions that are missing * (Intended to be called only on file load) @@ -1040,15 +999,9 @@ private: */ void BeginSegment( int type ); - /** - * Terminate a bus, wire, or line creation. - */ - void EndSegment(); - /** * Erase the last segment at the current mouse position. */ - void DeleteCurrentSegment(); void DeleteConnection( bool DeleteFullConnection ); // Images: diff --git a/eeschema/schedit.cpp b/eeschema/schedit.cpp index 45574cdd42..c2b68cca09 100644 --- a/eeschema/schedit.cpp +++ b/eeschema/schedit.cpp @@ -26,12 +26,10 @@ #include #include #include -#include #include #include #include #include -#include #include #include #include @@ -71,7 +69,6 @@ case ID_POPUP_SCH_BEGIN_WIRE: case ID_POPUP_SCH_BEGIN_BUS: case ID_POPUP_END_LINE: - case ID_POPUP_SCH_SET_SHAPE_TEXT: case ID_POPUP_SCH_CLEANUP_SHEET: case ID_POPUP_SCH_END_SHEET: case ID_POPUP_SCH_RESIZE_SHEET: @@ -161,12 +158,10 @@ { SetNoToolSelected(); } - break; case ID_POPUP_END_LINE: - m_canvas->MoveCursorToCrossHair(); - EndSegment(); + m_toolManager->RunAction( SCH_ACTIONS::finishDrawing, true ); break; case ID_POPUP_SCH_BEGIN_WIRE: @@ -179,10 +174,6 @@ OnLeftClick( nullptr, GetCrossHairPosition() ); break; - case ID_POPUP_SCH_SET_SHAPE_TEXT: - // Not used - break; - case ID_POPUP_SCH_DELETE_NODE: case ID_POPUP_SCH_DELETE_CONNECTION: m_canvas->MoveCursorToCrossHair(); @@ -267,7 +258,6 @@ m_canvas->MoveCursorToCrossHair(); ConvertPart( (SCH_COMPONENT*) item ); } - break; case ID_POPUP_SCH_ENTER_SHEET: @@ -277,7 +267,6 @@ g_CurrentSheet->push_back( (SCH_SHEET*) item ); DisplayCurrentSheet(); } - break; case ID_POPUP_SCH_LEAVE_SHEET: @@ -286,7 +275,6 @@ g_CurrentSheet->pop_back(); DisplayCurrentSheet(); } - break; case ID_POPUP_PLACE_BLOCK: @@ -344,9 +332,8 @@ case ID_POPUP_SCH_ADD_LABEL: case ID_POPUP_SCH_ADD_GLABEL: - screen->SetCurItem( CreateNewText( id == ID_POPUP_SCH_ADD_LABEL ? LAYER_LOCLABEL - : LAYER_GLOBLABEL ) ); - item = screen->GetCurItem(); + item = CreateNewText( id == ID_POPUP_SCH_ADD_LABEL ? LAYER_LOCLABEL : LAYER_GLOBLABEL ); + screen->SetCurItem( item ); if( item ) AddItemToScreen( item ); @@ -371,76 +358,10 @@ void SCH_EDIT_FRAME::OnUnfoldBus( wxCommandEvent& event ) { - auto screen = GetScreen(); - auto item = static_cast< wxMenuItem* >( event.GetEventUserData() ); - auto net = item->GetItemLabelText(); + wxMenuItem* item = static_cast< wxMenuItem* >( event.GetEventUserData() ); + static wxString net = item->GetItemLabelText(); - auto pos = GetCrossHairPosition(); - - /** - * Unfolding a bus consists of the following user inputs: - * 1) User selects a bus to unfold (see AddMenusForBus()) - * We land in this event handler. - * - * 2) User clicks to set the net label location (handled by BeginSegment()) - * Before this first click, the posture of the bus entry follows the - * mouse cursor in X and Y (handled by DrawSegment()) - * - * 3) User is now in normal wiring mode and can exit in any normal way. - */ - - wxASSERT( !m_busUnfold.in_progress ); - - m_busUnfold.entry = new SCH_BUS_WIRE_ENTRY( pos, '\\' ); - - SetSchItemParent( m_busUnfold.entry, screen ); - AddToScreen( m_busUnfold.entry ); - - m_busUnfold.label = new SCH_LABEL( m_busUnfold.entry->m_End(), net ); - - m_busUnfold.label->SetTextSize( wxSize( GetDefaultTextSize(), - GetDefaultTextSize() ) ); - m_busUnfold.label->SetLabelSpinStyle( 0 ); - - SetSchItemParent( m_busUnfold.label, screen ); - - m_busUnfold.in_progress = true; - m_busUnfold.origin = pos; - m_busUnfold.net_name = net; - - SetToolID( ID_WIRE_BUTT, wxCURSOR_PENCIL, _( "Add wire" ) ); - - SetCrossHairPosition( m_busUnfold.entry->m_End() ); - BeginSegment( LAYER_WIRE ); - m_canvas->SetAutoPanRequest( true ); -} - - -void SCH_EDIT_FRAME::CancelBusUnfold() -{ - if( m_busUnfold.entry ) - { - RemoveFromScreen( m_busUnfold.entry ); - delete m_busUnfold.entry; - } - - if( m_busUnfold.label ) - { - if( m_busUnfold.label_placed ) - RemoveFromScreen( m_busUnfold.label ); - - delete m_busUnfold.label; - } - - FinishBusUnfold(); -} - - -void SCH_EDIT_FRAME::FinishBusUnfold() -{ - m_busUnfold = {}; - - SetToolID( ID_NO_TOOL_SELECTED, GetGalCanvas()->GetDefaultCursor(), wxEmptyString ); + GetToolManager()->RunAction( SCH_ACTIONS::unfoldBus, true, &net ); } @@ -610,6 +531,12 @@ void SCH_EDIT_FRAME::OnSelectTool( wxCommandEvent& aEvent ) case ID_SCH_PLACE_COMPONENT: case ID_MENU_PLACE_POWER_BUTT: case ID_PLACE_POWER_BUTT: + case ID_MENU_WIRE_BUTT: + case ID_WIRE_BUTT: + case ID_MENU_BUS_BUTT: + case ID_BUS_BUTT: + case ID_MENU_LINE_COMMENT_BUTT: + case ID_LINE_COMMENT_BUTT: // moved to modern toolset return; default: @@ -633,21 +560,6 @@ void SCH_EDIT_FRAME::OnSelectTool( wxCommandEvent& aEvent ) SetNoToolSelected(); break; - case ID_MENU_WIRE_BUTT: - case ID_WIRE_BUTT: - SetToolID( ID_WIRE_BUTT, wxCURSOR_PENCIL, _( "Add wire" ) ); - break; - - case ID_MENU_BUS_BUTT: - case ID_BUS_BUTT: - SetToolID( ID_BUS_BUTT, wxCURSOR_PENCIL, _( "Add bus" ) ); - break; - - case ID_MENU_LINE_COMMENT_BUTT: - case ID_LINE_COMMENT_BUTT: - SetToolID( ID_LINE_COMMENT_BUTT, wxCURSOR_PENCIL, _( "Add lines" ) ); - break; - case ID_MENU_SHEET_SYMBOL_BUTT: case ID_SHEET_SYMBOL_BUTT: SetToolID( ID_SHEET_SYMBOL_BUTT, wxCURSOR_PENCIL, _( "Add sheet" ) ); @@ -718,10 +630,8 @@ void SCH_EDIT_FRAME::DeleteConnection( bool aFullConnection ) bool SCH_EDIT_FRAME::DeleteItemAtCrossHair() { - SCH_ITEM* item; SCH_SCREEN* screen = GetScreen(); - - item = LocateItem( GetCrossHairPosition(), SCH_COLLECTOR::ParentItems ); + SCH_ITEM* item = LocateItem( GetCrossHairPosition(), SCH_COLLECTOR::ParentItems ); if( item ) { @@ -1194,8 +1104,7 @@ void SCH_EDIT_FRAME::OnEditItem( wxCommandEvent& aEvent ) break; default: // Unexpected item - wxFAIL_MSG( wxString::Format( wxT( "Cannot edit schematic item type %s." ), - GetChars( item->GetClass() ) ) ); + wxFAIL_MSG( wxString( "Cannot edit schematic item type " ) + item->GetClass() ); } RefreshItem( item ); @@ -1272,8 +1181,7 @@ void SCH_EDIT_FRAME::OnDragItem( wxCommandEvent& aEvent ) break; default: - wxFAIL_MSG( wxString::Format( wxT( "Cannot drag schematic item type %s." ), - GetChars( item->GetClass() ) ) ); + wxFAIL_MSG( wxString( "Cannot drag schematic item type " ) + item->GetClass() ); } } diff --git a/eeschema/tools/sch_actions.cpp b/eeschema/tools/sch_actions.cpp index e1ad753f01..22c47b44e3 100644 --- a/eeschema/tools/sch_actions.cpp +++ b/eeschema/tools/sch_actions.cpp @@ -27,6 +27,7 @@ #include #include #include +#include #include @@ -87,6 +88,14 @@ OPT SCH_ACTIONS::TranslateLegacyId( int aId ) case ID_PLACE_POWER_BUTT: return SCH_ACTIONS::placePower.MakeEvent(); + case ID_MENU_WIRE_BUTT: + case ID_WIRE_BUTT: + return SCH_ACTIONS::drawWire.MakeEvent(); + + case ID_MENU_BUS_BUTT: + case ID_BUS_BUTT: + return SCH_ACTIONS::drawBus.MakeEvent(); + case ID_MENU_NOCONN_BUTT: case ID_NOCONN_BUTT: return SCH_ACTIONS::placeNoConnect.MakeEvent(); @@ -119,9 +128,16 @@ OPT SCH_ACTIONS::TranslateLegacyId( int aId ) case ID_TEXT_COMMENT_BUTT: return SCH_ACTIONS::placeSchematicText.MakeEvent(); + case ID_MENU_LINE_COMMENT_BUTT: + case ID_LINE_COMMENT_BUTT: + return SCH_ACTIONS::drawLines.MakeEvent(); + case ID_MENU_ADD_IMAGE_BUTT: case ID_ADD_IMAGE_BUTT: return SCH_ACTIONS::placeImage.MakeEvent(); + + case ID_POPUP_END_LINE: + return SCH_ACTIONS::finishDrawing.MakeEvent(); } return OPT(); @@ -133,4 +149,5 @@ void SCH_ACTIONS::RegisterAllTools( TOOL_MANAGER* aToolManager ) aToolManager->RegisterTool( new COMMON_TOOLS ); aToolManager->RegisterTool( new SCH_EDITOR_CONTROL ); aToolManager->RegisterTool( new SCH_PICKER_TOOL ); + aToolManager->RegisterTool( new SCH_DRAWING_TOOL ); } diff --git a/eeschema/tools/sch_actions.h b/eeschema/tools/sch_actions.h index 2ac3d4394c..a97b4cfc0e 100644 --- a/eeschema/tools/sch_actions.h +++ b/eeschema/tools/sch_actions.h @@ -90,6 +90,9 @@ public: static TOOL_ACTION pickerTool; static TOOL_ACTION placeSymbol; static TOOL_ACTION placePower; + static TOOL_ACTION drawWire; + static TOOL_ACTION drawBus; + static TOOL_ACTION unfoldBus; static TOOL_ACTION placeNoConnect; static TOOL_ACTION placeJunction; static TOOL_ACTION placeBusWireEntry; @@ -98,7 +101,9 @@ public: static TOOL_ACTION placeGlobalLabel; static TOOL_ACTION placeHierarchicalLabel; static TOOL_ACTION placeSchematicText; + static TOOL_ACTION drawLines; static TOOL_ACTION placeImage; + static TOOL_ACTION finishDrawing; // Editing static TOOL_ACTION properties; diff --git a/eeschema/tools/sch_drawing_tool.cpp b/eeschema/tools/sch_drawing_tool.cpp new file mode 100644 index 0000000000..94c0ec9cfa --- /dev/null +++ b/eeschema/tools/sch_drawing_tool.cpp @@ -0,0 +1,1038 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2019 KiCad Developers, see AUTHORS.txt for contributors. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, you may find one here: + * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html + * or you may search the http://www.gnu.org website for the version 2 license, + * or you may write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include "sch_drawing_tool.h" +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +// Drawing tool actions +TOOL_ACTION SCH_ACTIONS::placeSymbol( "eeschema.InteractiveDrawing.placeSymbol", + AS_GLOBAL, TOOL_ACTION::LegacyHotKey( HK_ADD_NEW_COMPONENT ), + _( "Add Symbol" ), _( "Add a symbol" ), NULL, AF_ACTIVATE ); + +TOOL_ACTION SCH_ACTIONS::placePower( "eeschema.InteractiveDrawing.placePowerPort", + AS_GLOBAL, TOOL_ACTION::LegacyHotKey( HK_ADD_NEW_POWER ), + _( "Add Power" ), _( "Add a power port" ), NULL, AF_ACTIVATE ); + +TOOL_ACTION SCH_ACTIONS::drawWire( "eeschema.InteractiveDrawing.drawWire", + AS_GLOBAL, TOOL_ACTION::LegacyHotKey( HK_BEGIN_WIRE ), + _( "Add Wire" ), _( "Add a wire" ), NULL, AF_ACTIVATE ); + +TOOL_ACTION SCH_ACTIONS::drawBus( "eeschema.InteractiveDrawing.drawBus", + AS_GLOBAL, TOOL_ACTION::LegacyHotKey( HK_BEGIN_BUS ), + _( "Add Bus" ), _( "Add a bus" ), NULL, AF_ACTIVATE ); + +TOOL_ACTION SCH_ACTIONS::unfoldBus( "eeschema.InteractiveDrawing.unfoldBus", + AS_GLOBAL, 0, "", "", NULL, AF_ACTIVATE ); + +TOOL_ACTION SCH_ACTIONS::placeNoConnect( "eeschema.InteractiveDrawing.placeNoConnect", + AS_GLOBAL, TOOL_ACTION::LegacyHotKey( HK_ADD_NOCONN_FLAG ), + _( "Add No Connect Flag" ), _( "Add a no-connection flag" ), NULL, AF_ACTIVATE ); + +TOOL_ACTION SCH_ACTIONS::placeJunction( "eeschema.InteractiveDrawing.placeJunction", + AS_GLOBAL, TOOL_ACTION::LegacyHotKey( HK_ADD_JUNCTION ), + _( "Add Junction" ), _( "Add a junction" ), NULL, AF_ACTIVATE ); + +TOOL_ACTION SCH_ACTIONS::placeBusWireEntry( "eeschema.InteractiveDrawing.placeBusWireEntry", + AS_GLOBAL, TOOL_ACTION::LegacyHotKey( HK_ADD_WIRE_ENTRY ), + _( "Add Wire to Bus Entry" ), _( "Add a wire entry to a bus" ), NULL, AF_ACTIVATE ); + +TOOL_ACTION SCH_ACTIONS::placeBusBusEntry( "eeschema.InteractiveDrawing.placeBusBusEntry", + AS_GLOBAL, TOOL_ACTION::LegacyHotKey( HK_ADD_BUS_ENTRY ), + _( "Add Bus to Bus Entry" ), _( "Add a bus entry to a bus" ), NULL, AF_ACTIVATE ); + +TOOL_ACTION SCH_ACTIONS::placeLabel( "eeschema.InteractiveDrawing.placePLabel", + AS_GLOBAL, TOOL_ACTION::LegacyHotKey( HK_ADD_LABEL ), + _( "Add Label" ), _( "Add a net label" ), NULL, AF_ACTIVATE ); + +TOOL_ACTION SCH_ACTIONS::placeHierarchicalLabel( "eeschema.InteractiveDrawing.placeHierarchicalLabel", + AS_GLOBAL, TOOL_ACTION::LegacyHotKey( HK_ADD_HLABEL ), + _( "Add Hierarchical Label" ), _( "Add a hierarchical sheet label" ), NULL, AF_ACTIVATE ); + +TOOL_ACTION SCH_ACTIONS::placeGlobalLabel( "eeschema.InteractiveDrawing.placeGlobalLabel", + AS_GLOBAL, TOOL_ACTION::LegacyHotKey( HK_ADD_GLABEL ), + _( "Add Global Label" ), _( "Add a global label" ), NULL, AF_ACTIVATE ); + +TOOL_ACTION SCH_ACTIONS::placeSchematicText( "eeschema.InteractiveDrawing.placeSchematicText", + AS_GLOBAL, TOOL_ACTION::LegacyHotKey( HK_ADD_GRAPHIC_TEXT ), + _( "Add Text" ), _( "Add text" ), NULL, AF_ACTIVATE ); + +TOOL_ACTION SCH_ACTIONS::drawLines( "eeschema.InteractiveDrawing.drawLines", + AS_GLOBAL, TOOL_ACTION::LegacyHotKey( HK_ADD_GRAPHIC_POLYLINE ), + _( "Add Lines" ), _( "Add connected lines" ), NULL, AF_ACTIVATE ); + +TOOL_ACTION SCH_ACTIONS::placeImage( "eeschema.InteractiveDrawing.placeImage", + AS_GLOBAL, 0, + _( "Add Image" ), _( "Add bitmap image" ), NULL, AF_ACTIVATE ); + +TOOL_ACTION SCH_ACTIONS::finishDrawing( "eeschema.InteractiveDrawing.finishDrawing", + AS_GLOBAL, 0, "", "", NULL, AF_NONE ); + + +SCH_DRAWING_TOOL::SCH_DRAWING_TOOL() : + TOOL_INTERACTIVE( "eeschema.InteractiveDrawing" ), + m_view( nullptr ), + m_controls( nullptr ), + m_frame( nullptr ), + m_menu( *this ) +{ + m_busUnfold = {}; +}; + + +SCH_DRAWING_TOOL::~SCH_DRAWING_TOOL() +{ +} + + +bool SCH_DRAWING_TOOL::Init() +{ + auto activeToolFunctor = [ this ] ( const SELECTION& aSel ) { + return ( m_frame->GetToolId() != ID_NO_TOOL_SELECTED ); + }; + + auto& ctxMenu = m_menu.GetMenu(); + + // cancel current tool goes in main context menu at the top if present + ctxMenu.AddItem( ACTIONS::cancelInteractive, activeToolFunctor, 1 ); + ctxMenu.AddSeparator( activeToolFunctor, 1 ); + + return true; +} + + +void SCH_DRAWING_TOOL::Reset( RESET_REASON aReason ) +{ + // Init variables used by every drawing tool + m_view = static_cast( getView() ); + m_controls = getViewControls(); + m_frame = getEditFrame(); +} + + +// History lists for PlaceSymbol() +static SCH_BASE_FRAME::HISTORY_LIST s_SymbolHistoryList; +static SCH_BASE_FRAME::HISTORY_LIST s_PowerHistoryList; + + +int SCH_DRAWING_TOOL::PlaceSymbol( const TOOL_EVENT& aEvent ) +{ + SCH_COMPONENT* component = aEvent.Parameter(); + + m_frame->SetToolID( ID_SCH_PLACE_COMPONENT, wxCURSOR_PENCIL, _( "Add Symbol" ) ); + + return doPlaceComponent( component, nullptr, s_SymbolHistoryList ); +} + + +int SCH_DRAWING_TOOL::PlacePower( const TOOL_EVENT& aEvent ) +{ + SCH_COMPONENT* component = aEvent.Parameter(); + SCHLIB_FILTER filter; + + filter.FilterPowerParts( true ); + m_frame->SetToolID( ID_PLACE_POWER_BUTT, wxCURSOR_PENCIL, _( "Add Power" ) ); + + return doPlaceComponent( component, &filter, s_PowerHistoryList ); +} + + +int SCH_DRAWING_TOOL::doPlaceComponent( SCH_COMPONENT* aComponent, SCHLIB_FILTER* aFilter, + SCH_BASE_FRAME::HISTORY_LIST aHistoryList ) +{ + VECTOR2I cursorPos = m_controls->GetCursorPosition(); + + m_toolMgr->RunAction( SCH_ACTIONS::selectionClear, true ); + m_controls->ShowCursor( true ); + m_controls->SetSnapping( true ); + + Activate(); + + // Add all the drawable parts to preview + if( aComponent ) + { + aComponent->SetPosition( (wxPoint)cursorPos ); + m_view->ClearPreview(); + m_view->AddToPreview( aComponent->Clone() ); + } + + // Main loop: keep receiving events + while( OPT_TOOL_EVENT evt = Wait() ) + { + cursorPos = m_controls->GetCursorPosition( !evt->Modifier( MD_ALT ) ); + + if( evt->IsAction( &ACTIONS::cancelInteractive ) || evt->IsActivate() || evt->IsCancel() ) + { + if( aComponent ) + { + m_toolMgr->RunAction( SCH_ACTIONS::selectionClear, true ); + getModel()->SetCurItem( nullptr ); + m_view->ClearPreview(); + m_view->ClearHiddenFlags(); + delete aComponent; + aComponent = nullptr; + } + else + break; + + if( evt->IsActivate() ) // now finish unconditionally + break; + } + else if( evt->IsClick( BUT_LEFT ) ) + { + if( !aComponent ) + { + // Pick the module to be placed + m_frame->SetRepeatItem( NULL ); + m_frame->GetCanvas()->SetIgnoreMouseEvents( true ); + + auto sel = m_frame->SelectComponentFromLibTree( aFilter, aHistoryList, true, 1, 1, + m_frame->GetShowFootprintPreviews() ); + + // Restore cursor after dialog + m_frame->GetCanvas()->MoveCursorToCrossHair(); + + LIB_PART* part = nullptr; + + if( sel.LibId.IsValid() ) + part = m_frame->GetLibPart( sel.LibId ); + + if( !part ) + continue; + + aComponent = new SCH_COMPONENT( *part, sel.LibId, g_CurrentSheet, sel.Unit, + sel.Convert, (wxPoint)cursorPos, true ); + + // Be sure the link to the corresponding LIB_PART is OK: + aComponent->Resolve( *m_frame->Prj().SchSymbolLibTable() ); + + // Set any fields that have been modified + for( auto const& i : sel.Fields ) + { + auto field = aComponent->GetField( i.first ); + + if( field ) + field->SetText( i.second ); + } + + MSG_PANEL_ITEMS items; + aComponent->GetMsgPanelInfo( m_frame->GetUserUnits(), items ); + m_frame->SetMsgPanel( items ); + + if( m_frame->GetAutoplaceFields() ) + aComponent->AutoplaceFields( /* aScreen */ NULL, /* aManual */ false ); + + aComponent->SetFlags( IS_MOVED ); + m_frame->SetRepeatItem( aComponent ); + m_frame->GetScreen()->SetCurItem( aComponent ); + m_view->ClearPreview(); + m_view->AddToPreview( aComponent->Clone() ); + + m_controls->SetCursorPosition( cursorPos, false ); + } + else + { + m_view->ClearPreview(); + + m_frame->AddItemToScreen( aComponent ); + + aComponent = nullptr; + } + } + else if( evt->IsClick( BUT_RIGHT ) ) + { + // JEY TODO + // m_menu.ShowContextMenu( selTool->GetSelection() ); + } + else if( aComponent && ( evt->IsAction( &SCH_ACTIONS::refreshPreview ) || evt->IsMotion() ) ) + { + aComponent->SetPosition( (wxPoint)cursorPos ); + m_view->ClearPreview(); + m_view->AddToPreview( aComponent->Clone() ); + } + + // Enable autopanning and cursor capture only when there is a module to be placed + m_controls->SetAutoPan( !!aComponent ); + m_controls->CaptureCursor( !!aComponent ); + } + + m_frame->SetNoToolSelected(); + + return 0; +} + + +int SCH_DRAWING_TOOL::PlaceNoConnect( const TOOL_EVENT& aEvent ) +{ + m_frame->SetToolID( ID_NOCONN_BUTT, wxCURSOR_PENCIL, _( "Add no connect" ) ); + return doSingleClickPlace( SCH_NO_CONNECT_T ); +} + + +int SCH_DRAWING_TOOL::PlaceJunction( const TOOL_EVENT& aEvent ) +{ + m_frame->SetToolID( ID_JUNCTION_BUTT, wxCURSOR_PENCIL, _( "Add junction" ) ); + return doSingleClickPlace( SCH_JUNCTION_T ); +} + + +int SCH_DRAWING_TOOL::PlaceBusWireEntry( const TOOL_EVENT& aEvent ) +{ + m_frame->SetToolID( ID_WIRETOBUS_ENTRY_BUTT, wxCURSOR_PENCIL, _( "Add wire to bus entry" ) ); + return doSingleClickPlace( SCH_BUS_WIRE_ENTRY_T ); +} + + +int SCH_DRAWING_TOOL::PlaceBusBusEntry( const TOOL_EVENT& aEvent ) +{ + m_frame->SetToolID( ID_BUSTOBUS_ENTRY_BUTT, wxCURSOR_PENCIL, _( "Add bus to bus entry" ) ); + return doSingleClickPlace( SCH_BUS_BUS_ENTRY_T ); +} + + +int SCH_DRAWING_TOOL::doSingleClickPlace( KICAD_T aType ) +{ + m_toolMgr->RunAction( SCH_ACTIONS::selectionClear, true ); + m_controls->ShowCursor( true ); + m_controls->SetSnapping( true ); + + Activate(); + + // Main loop: keep receiving events + while( OPT_TOOL_EVENT evt = Wait() ) + { + wxPoint cursorPos = (wxPoint)m_controls->GetCursorPosition( !evt->Modifier( MD_ALT ) ); + + if( evt->IsAction( &ACTIONS::cancelInteractive ) || evt->IsActivate() || evt->IsCancel() ) + { + break; + } + else if( evt->IsClick( BUT_LEFT ) ) + { + SCH_ITEM* item = nullptr; + + if( !m_frame->GetScreen()->GetItem( cursorPos, 0, aType ) ) + { + switch( aType ) + { + case SCH_NO_CONNECT_T: item = m_frame->AddNoConnect( cursorPos ); break; + case SCH_JUNCTION_T: item = m_frame->AddJunction( cursorPos ); break; + case SCH_BUS_WIRE_ENTRY_T: item = m_frame->CreateBusWireEntry(); break; + case SCH_BUS_BUS_ENTRY_T: item = m_frame->CreateBusBusEntry(); break; + default: wxFAIL_MSG( "doSingleClickPlace(): unknown type" ); + } + } + + if( item ) + { + m_frame->SetRepeatItem( item ); + m_frame->GetScreen()->SetCurItem( item ); + } + } + else if( evt->IsClick( BUT_RIGHT ) ) + { + // JEY TODO + // m_menu.ShowContextMenu( selTool->GetSelection() ); + } + } + + m_frame->SetNoToolSelected(); + + return 0; +} + + +int SCH_DRAWING_TOOL::PlaceLabel( const TOOL_EVENT& aEvent ) +{ + m_frame->SetToolID( ID_LABEL_BUTT, wxCURSOR_PENCIL, _( "Add net label" ) ); + return doTwoClickPlace( SCH_LABEL_T ); +} + + +int SCH_DRAWING_TOOL::PlaceGlobalLabel( const TOOL_EVENT& aEvent ) +{ + m_frame->SetToolID( ID_GLOBALLABEL_BUTT, wxCURSOR_PENCIL, _( "Add global label" ) ); + return doTwoClickPlace( SCH_GLOBAL_LABEL_T ); +} + + +int SCH_DRAWING_TOOL::PlaceHierarchicalLabel( const TOOL_EVENT& aEvent ) +{ + m_frame->SetToolID( ID_HIERLABEL_BUTT, wxCURSOR_PENCIL, _( "Add hierarchical label" ) ); + return doTwoClickPlace( SCH_HIER_LABEL_T ); +} + + +int SCH_DRAWING_TOOL::PlaceSchematicText( const TOOL_EVENT& aEvent ) +{ + m_frame->SetToolID( ID_TEXT_COMMENT_BUTT, wxCURSOR_PENCIL, _( "Add text" ) ); + return doTwoClickPlace( SCH_TEXT_T ); +} + + +int SCH_DRAWING_TOOL::PlaceImage( const TOOL_EVENT& aEvent ) +{ + m_frame->SetToolID( ID_ADD_IMAGE_BUTT, wxCURSOR_PENCIL, _( "Add image" ) ); + return doTwoClickPlace( SCH_BITMAP_T ); +} + + +int SCH_DRAWING_TOOL::doTwoClickPlace( KICAD_T aType ) +{ + VECTOR2I cursorPos = m_controls->GetCursorPosition(); + SCH_ITEM* item = nullptr; + + m_toolMgr->RunAction( SCH_ACTIONS::selectionClear, true ); + m_controls->ShowCursor( true ); + m_controls->SetSnapping( true ); + + Activate(); + + // Main loop: keep receiving events + while( OPT_TOOL_EVENT evt = Wait() ) + { + cursorPos = m_controls->GetCursorPosition( !evt->Modifier( MD_ALT ) ); + + if( evt->IsAction( &ACTIONS::cancelInteractive ) || evt->IsActivate() || evt->IsCancel() ) + { + if( item ) + { + m_toolMgr->RunAction( SCH_ACTIONS::selectionClear, true ); + getModel()->SetCurItem( nullptr ); + m_view->ClearPreview(); + m_view->ClearHiddenFlags(); + delete item; + item = nullptr; + } + else + break; + + if( evt->IsActivate() ) // now finish unconditionally + break; + } + else if( evt->IsClick( BUT_LEFT ) ) + { + if( !item ) + { + m_frame->SetRepeatItem( NULL ); + m_frame->GetCanvas()->SetIgnoreMouseEvents( true ); + + switch( aType ) + { + case SCH_LABEL_T: item = m_frame->CreateNewText( LAYER_LOCLABEL ); break; + case SCH_HIER_LABEL_T: item = m_frame->CreateNewText( LAYER_HIERLABEL ); break; + case SCH_GLOBAL_LABEL_T: item = m_frame->CreateNewText( LAYER_GLOBLABEL ); break; + case SCH_TEXT_T: item = m_frame->CreateNewText( LAYER_NOTES ); break; + case SCH_BITMAP_T: item = m_frame->CreateNewImage(); break; + default: wxFAIL_MSG( "doTwoClickPlace(): unknown type" ); + } + + // Restore cursor after dialog + m_frame->GetCanvas()->MoveCursorToCrossHair(); + + if( item ) + { + MSG_PANEL_ITEMS items; + item->GetMsgPanelInfo( m_frame->GetUserUnits(), items ); + m_frame->SetMsgPanel( items ); + + item->SetFlags( IS_MOVED ); + m_view->ClearPreview(); + m_view->AddToPreview( item->Clone() ); + } + + m_controls->SetCursorPosition( cursorPos, false ); + } + else + { + m_view->ClearPreview(); + + m_frame->AddItemToScreen( item ); + + item = nullptr; + } + } + else if( evt->IsClick( BUT_RIGHT ) ) + { + // JEY TODO + // m_menu.ShowContextMenu( selTool->GetSelection() ); + } + else if( item && ( evt->IsAction( &SCH_ACTIONS::refreshPreview ) || evt->IsMotion() ) ) + { + item->SetPosition( (wxPoint)cursorPos ); + m_view->ClearPreview(); + m_view->AddToPreview( item->Clone() ); + } + + // Enable autopanning and cursor capture only when there is a module to be placed + m_controls->SetAutoPan( !!item ); + m_controls->CaptureCursor( !!item ); + } + + m_frame->SetNoToolSelected(); + + return 0; +} + + +int SCH_DRAWING_TOOL::DrawWire( const TOOL_EVENT& aEvent ) +{ + m_frame->SetToolID( ID_WIRE_BUTT, wxCURSOR_PENCIL, _( "Add wire" ) ); + return doDrawSegments( LAYER_WIRE ); +} + + +int SCH_DRAWING_TOOL::DrawBus( const TOOL_EVENT& aEvent ) +{ + m_frame->SetToolID( ID_BUS_BUTT, wxCURSOR_PENCIL, _( "Add bus" ) ); + return doDrawSegments( LAYER_BUS ); +} + + +int SCH_DRAWING_TOOL::UnfoldBus( const TOOL_EVENT& aEvent ) +{ + wxString net = *aEvent.Parameter(); + wxPoint pos = m_frame->GetCrossHairPosition(); + + /** + * Unfolding a bus consists of the following user inputs: + * 1) User selects a bus to unfold (see AddMenusForBus()) + * We land in this event handler. + * + * 2) User clicks to set the net label location (handled by BeginSegment()) + * Before this first click, the posture of the bus entry follows the + * mouse cursor in X and Y (handled by DrawSegment()) + * + * 3) User is now in normal wiring mode and can exit in any normal way. + */ + + wxASSERT( !m_busUnfold.in_progress ); + + m_busUnfold.entry = new SCH_BUS_WIRE_ENTRY( pos, '\\' ); + m_busUnfold.entry->SetParent( m_frame->GetScreen() ); + m_frame->AddToScreen( m_busUnfold.entry ); + + m_busUnfold.label = new SCH_LABEL( m_busUnfold.entry->m_End(), net ); + m_busUnfold.label->SetTextSize( wxSize( GetDefaultTextSize(), GetDefaultTextSize() ) ); + m_busUnfold.label->SetLabelSpinStyle( 0 ); + m_busUnfold.label->SetParent( m_frame->GetScreen() ); + + m_busUnfold.in_progress = true; + m_busUnfold.origin = pos; + m_busUnfold.net_name = net; + + m_frame->SetToolID( ID_WIRE_BUTT, wxCURSOR_PENCIL, _( "Add wire" ) ); + + m_frame->SetCrossHairPosition( m_busUnfold.entry->m_End() ); + return doDrawSegments( LAYER_WIRE ); +} + + +int SCH_DRAWING_TOOL::DrawLines( const TOOL_EVENT& aEvent) +{ + m_frame->SetToolID( ID_LINE_COMMENT_BUTT, wxCURSOR_PENCIL, _( "Add lines" ) ); + return doDrawSegments( LAYER_NOTES ); +} + + +// Storage for the line segments while drawing +static DLIST s_wires; + + +/** + * 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& aWires ) +{ + SCH_LINE* next = nullptr; + std::vector last_lines; + + for( SCH_LINE* line = aWires.GetFirst(); line; line = next ) + { + next = line->Next(); + + if( line->IsNull() ) + { + delete s_wires.Remove( line ); + continue; + } + + 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 ); + } + } +} + + +/** + * A helper function to find any sheet pins at the specified position. + */ +static const SCH_SHEET_PIN* getSheetPin( SCH_SCREEN* aScreen, const wxPoint& aPosition ) +{ + for( SCH_ITEM* item = aScreen->GetDrawItems(); item; item = item->Next() ) + { + if( item->Type() == SCH_SHEET_T ) + { + SCH_SHEET* sheet = (SCH_SHEET*) item; + + for( const SCH_SHEET_PIN& pin : sheet->GetPins() ) + { + if( pin.GetPosition() == aPosition ) + return &pin; + } + } + } + + return nullptr; +} + + +/** + * 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_SCREEN* aScreen, SCH_LINE* aSegment, wxPoint& aPosition ) +{ + wxCHECK_RET( aSegment != nullptr, wxT( "Cannot compute break point of NULL line segment." ) ); + + SCH_LINE* nextSegment = aSegment->Next(); + + wxPoint midPoint; + int iDx = aSegment->GetEndPoint().x - aSegment->GetStartPoint().x; + int iDy = aSegment->GetEndPoint().y - aSegment->GetStartPoint().y; + + const SCH_SHEET_PIN* connectedPin = getSheetPin( aScreen, aSegment->GetStartPoint() ); + auto force = connectedPin ? connectedPin->GetEdge() : SCH_SHEET_PIN::SHEET_UNDEFINED_SIDE; + + if( force == SCH_SHEET_PIN::SHEET_LEFT_SIDE || force == SCH_SHEET_PIN::SHEET_RIGHT_SIDE ) + { + if( aPosition.x == connectedPin->GetPosition().x ) // push outside sheet boundary + { + int direction = ( force == SCH_SHEET_PIN::SHEET_LEFT_SIDE ) ? -1 : 1; + aPosition.x += int( aScreen->GetGridSize().x * direction ); + } + + midPoint.x = aPosition.x; + midPoint.y = aSegment->GetStartPoint().y; // force horizontal + } + else if( iDy != 0 ) // keep the first segment orientation (vertical) + { + midPoint.x = aSegment->GetStartPoint().x; + midPoint.y = aPosition.y; + } + else if( iDx != 0 ) // keep the first segment orientation (horizontal) + { + midPoint.x = aPosition.x; + midPoint.y = aSegment->GetStartPoint().y; + } + else + { + if( std::abs( aPosition.x - aSegment->GetStartPoint().x ) < + std::abs( aPosition.y - aSegment->GetStartPoint().y ) ) + { + midPoint.x = aSegment->GetStartPoint().x; + midPoint.y = aPosition.y; + } + else + { + midPoint.x = aPosition.x; + midPoint.y = aSegment->GetStartPoint().y; + } + } + + aSegment->SetEndPoint( midPoint ); + nextSegment->SetStartPoint( midPoint ); + nextSegment->SetEndPoint( aPosition ); +} + + +int SCH_DRAWING_TOOL::doDrawSegments( int aType ) +{ + SCH_LINE* segment = nullptr; + bool forceHV = m_frame->GetForceHVLines(); + + m_toolMgr->RunAction( SCH_ACTIONS::selectionClear, true ); + m_controls->ShowCursor( true ); + m_controls->SetSnapping( true ); + + Activate(); + + // Main loop: keep receiving events + while( OPT_TOOL_EVENT evt = Wait() ) + { + wxPoint cursorPos = (wxPoint)m_controls->GetCursorPosition( !evt->Modifier( MD_ALT ) ); + + if( evt->IsAction( &ACTIONS::cancelInteractive ) || evt->IsActivate() || evt->IsCancel() ) + { + if( segment || m_busUnfold.in_progress ) + { + segment = nullptr; + getModel()->SetCurItem( nullptr ); + s_wires.DeleteAll(); + + if( m_busUnfold.entry ) + m_frame->RemoveFromScreen( m_busUnfold.entry ); + + if( m_busUnfold.label && m_busUnfold.label_placed ) + m_frame->RemoveFromScreen( m_busUnfold.label ); + + delete m_busUnfold.entry; + delete m_busUnfold.label; + m_busUnfold = {}; + + m_view->ClearPreview(); + m_view->ShowPreview( false ); + m_view->ClearHiddenFlags(); + + // Clear flags used in edit functions. + getModel()->ClearDrawingState(); + } + else + break; + + if( evt->IsActivate() ) // now finish unconditionally + break; + } + else if( evt->IsAction( &SCH_ACTIONS::finishDrawing ) ) + { + if( segment || m_busUnfold.in_progress ) + { + finishSegments(); + break; + } + } + else if( evt->IsClick( BUT_RIGHT ) ) + { + // JEY TODO + // m_menu.ShowContextMenu(); + } + else if( evt->IsClick( BUT_LEFT ) || ( segment && evt->IsDblClick( BUT_LEFT ) ) ) + { + // First click when unfolding places the label and wire-to-bus entry + if( m_busUnfold.in_progress && !m_busUnfold.label_placed ) + { + wxASSERT( aType == LAYER_WIRE ); + + m_frame->AddToScreen( m_busUnfold.label ); + m_busUnfold.label_placed = true; + + segment->ClearFlags( IS_NEW ); + segment->SetFlags( SELECTED ); + + segment = new SCH_LINE( *segment ); + segment->SetFlags( IS_NEW ); + segment->SetStartPoint( cursorPos ); + s_wires.PushBack( segment ); + m_frame->GetScreen()->SetCurItem( segment ); + } + else if( !segment ) + { + switch( aType ) + { + default: segment = new SCH_LINE( cursorPos, LAYER_NOTES ); break; + case LAYER_WIRE: segment = new SCH_LINE( cursorPos, LAYER_WIRE ); break; + case LAYER_BUS: segment = new SCH_LINE( cursorPos, LAYER_BUS ); break; + } + + segment->SetFlags( IS_NEW ); + s_wires.PushBack( segment ); + m_frame->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( forceHV ) + { + segment = new SCH_LINE( *segment ); + segment->SetFlags( IS_NEW ); + s_wires.PushBack( segment ); + m_frame->GetScreen()->SetCurItem( segment ); + } + } + // Create a new segment if we're out of previously-created ones + else if( !segment->IsNull() || ( forceHV && !segment->Back()->IsNull() ) ) + { + // Terminate the command if the end point is on a pin, junction, or another + // wire or bus. + if( !m_busUnfold.in_progress && + m_frame->GetScreen()->IsTerminalPoint( cursorPos, segment->GetLayer() ) ) + { + finishSegments(); + break; + } + + segment->SetEndPoint( cursorPos ); + segment->ClearFlags( IS_NEW ); + segment->SetFlags( SELECTED ); + + // Create a new segment, and chain it after the current new segment. + segment = new SCH_LINE( *segment ); + segment->SetFlags( IS_NEW ); + segment->SetStartPoint( cursorPos ); + s_wires.PushBack( segment ); + m_frame->GetScreen()->SetCurItem( segment ); + } + + if( evt->IsDblClick( BUT_LEFT ) ) + { + finishSegments(); + break; + } + } + else if( evt->IsMotion() ) + { + m_view->ClearPreview(); + + // Update the bus unfold posture based on the mouse movement + if( m_busUnfold.in_progress && !m_busUnfold.label_placed ) + { + wxPoint cursor_delta = cursorPos - m_busUnfold.origin; + SCH_BUS_WIRE_ENTRY* entry = m_busUnfold.entry; + + bool offset = ( cursor_delta.x < 0 ); + char shape = ( offset ? ( ( cursor_delta.y >= 0 ) ? '/' : '\\' ) + : ( ( cursor_delta.y >= 0 ) ? '\\' : '/' ) ); + + // Erase and redraw if necessary + if( shape != entry->GetBusEntryShape() || offset != m_busUnfold.offset ) + { + entry->SetBusEntryShape( shape ); + wxPoint entry_pos = m_busUnfold.origin; + + if( offset ) + entry_pos -= entry->GetSize(); + + entry->SetPosition( entry_pos ); + m_busUnfold.offset = offset; + + m_frame->RefreshItem( entry ); + + wxPoint wire_start = offset ? entry->GetPosition() : entry->m_End(); + s_wires.begin()->SetStartPoint( wire_start ); + } + + // Update the label "ghost" position + m_busUnfold.label->SetPosition( cursorPos ); + m_view->AddToPreview( m_busUnfold.label->Clone() ); + } + + if( segment ) + { + // Coerce the line to vertical or horizontal if necessary + if( forceHV ) + computeBreakPoint( m_frame->GetScreen(), segment->Back(), cursorPos ); + else + segment->SetEndPoint( cursorPos ); + } + + for( auto seg = s_wires.begin(); seg; seg = seg->Next() ) + { + if( !seg->IsNull() ) // Add to preview if segment length != 0 + m_view->AddToPreview( seg->Clone() ); + } + } + + // Enable autopanning and cursor capture only when there is a segment to be placed + m_controls->SetAutoPan( !!segment ); + m_controls->CaptureCursor( !!segment ); + } + + m_frame->SetNoToolSelected(); + + return 0; +} + + +void SCH_DRAWING_TOOL::finishSegments() +{ + PICKED_ITEMS_LIST itemList; + + // Remove segments backtracking over others + RemoveBacktracks( s_wires ); + + // Collect the possible connection points for the new lines + std::vector< wxPoint > connections; + std::vector< wxPoint > new_ends; + m_frame->GetSchematicConnections( connections ); + + // Check each new segment for possible junctions and add/split if needed + for( SCH_LINE* wire = s_wires.GetFirst(); wire; wire = wire->Next() ) + { + if( wire->GetFlags() & SKIP_STRUCT ) + continue; + + wire->GetConnectionPoints( new_ends ); + + for( auto i : connections ) + { + if( IsPointOnSegment( wire->GetStartPoint(), wire->GetEndPoint(), i ) ) + new_ends.push_back( i ); + } + itemList.PushItem( ITEM_PICKER( wire, UR_NEW ) ); + } + + if( m_busUnfold.in_progress && m_busUnfold.label_placed ) + { + wxASSERT( m_busUnfold.entry && m_busUnfold.label ); + + itemList.PushItem( ITEM_PICKER( m_busUnfold.entry, UR_NEW ) ); + itemList.PushItem( ITEM_PICKER( m_busUnfold.label, UR_NEW ) ); + } + + // Get the last non-null wire (this is the last created segment). + m_frame->SetRepeatItem( s_wires.GetLast() ); + + // Add the new wires + while( s_wires.GetFirst() ) + m_frame->AddToScreen( s_wires.PopFront() ); + + m_view->ClearPreview(); + m_view->ShowPreview( false ); + m_view->ClearHiddenFlags(); + + m_controls->CaptureCursor( false ); + m_controls->SetAutoPan( false ); + + m_frame->SaveCopyInUndoList( itemList, UR_NEW ); + + // Correct and remove segments that need to be merged. + m_frame->SchematicCleanUp( true ); + + for( auto item = m_frame->GetScreen()->GetDrawItems(); item; item = item->Next() ) + { + if( item->Type() != SCH_COMPONENT_T ) + continue; + + std::vector< wxPoint > pts; + item->GetConnectionPoints( pts ); + + if( pts.size() > 2 ) + continue; + + for( auto i = pts.begin(); i != pts.end(); i++ ) + { + for( auto j = i + 1; j != pts.end(); j++ ) + m_frame->TrimWire( *i, *j, true ); + } + } + + for( auto i : new_ends ) + { + if( m_frame->GetScreen()->IsJunctionNeeded( i, true ) ) + m_frame->AddJunction( i, true, false ); + } + + if( m_busUnfold.in_progress ) + m_busUnfold = {}; + + m_frame->TestDanglingEnds(); + + m_frame->GetScreen()->ClearDrawingState(); + m_frame->GetScreen()->SetCurItem( NULL ); + m_frame->OnModify(); +} + + +void SCH_DRAWING_TOOL::setTransitions() +{ + Go( &SCH_DRAWING_TOOL::PlaceSymbol, SCH_ACTIONS::placeSymbol.MakeEvent() ); + Go( &SCH_DRAWING_TOOL::PlacePower, SCH_ACTIONS::placePower.MakeEvent() ); + Go( &SCH_DRAWING_TOOL::DrawWire, SCH_ACTIONS::drawWire.MakeEvent() ); + Go( &SCH_DRAWING_TOOL::DrawBus, SCH_ACTIONS::drawBus.MakeEvent() ); + Go( &SCH_DRAWING_TOOL::UnfoldBus, SCH_ACTIONS::unfoldBus.MakeEvent() ); + Go( &SCH_DRAWING_TOOL::PlaceNoConnect, SCH_ACTIONS::placeNoConnect.MakeEvent() ); + Go( &SCH_DRAWING_TOOL::PlaceJunction, SCH_ACTIONS::placeJunction.MakeEvent() ); + Go( &SCH_DRAWING_TOOL::PlaceBusWireEntry, SCH_ACTIONS::placeBusWireEntry.MakeEvent() ); + Go( &SCH_DRAWING_TOOL::PlaceBusBusEntry, SCH_ACTIONS::placeBusBusEntry.MakeEvent() ); + Go( &SCH_DRAWING_TOOL::PlaceLabel, SCH_ACTIONS::placeLabel.MakeEvent() ); + Go( &SCH_DRAWING_TOOL::PlaceHierarchicalLabel,SCH_ACTIONS::placeHierarchicalLabel.MakeEvent() ); + Go( &SCH_DRAWING_TOOL::PlaceGlobalLabel, SCH_ACTIONS::placeGlobalLabel.MakeEvent() ); + Go( &SCH_DRAWING_TOOL::PlaceSchematicText, SCH_ACTIONS::placeSchematicText.MakeEvent() ); + Go( &SCH_DRAWING_TOOL::DrawLines, SCH_ACTIONS::drawLines.MakeEvent() ); + Go( &SCH_DRAWING_TOOL::PlaceImage, SCH_ACTIONS::placeImage.MakeEvent() ); +} diff --git a/eeschema/tools/sch_drawing_tool.h b/eeschema/tools/sch_drawing_tool.h new file mode 100644 index 0000000000..86484b0195 --- /dev/null +++ b/eeschema/tools/sch_drawing_tool.h @@ -0,0 +1,121 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2019 KiCad Developers, see AUTHORS.txt for contributors. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, you may find one here: + * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html + * or you may search the http://www.gnu.org website for the version 2 license, + * or you may write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef SCH_DRAWING_TOOL_H +#define SCH_DRAWING_TOOL_H + +#include +#include +#include +#include + + +class SCH_COMPONENT; +class SCH_BUS_WIRE_ENTRY; +class SCH_LABEL; +class SCHLIB_FILTER; +class SCH_EDIT_FRAME; + + +/// Collection of data related to the bus unfolding tool +struct BUS_UNFOLDING_T +{ + bool in_progress; ///< True if bus unfold operation is running + bool offset; ///< True if the bus entry should be offset from origin + bool label_placed; ///< True if user has placed the net label + + wxPoint origin; ///< Origin (on the bus) of the unfold + wxString net_name; ///< Net label for the unfolding operation + + SCH_BUS_WIRE_ENTRY* entry; + SCH_LABEL* label; +}; + + +/** + * Class SCH_DRAWING_TOOL + * + * Tool responsible for drawing graphical elements like lines, arcs, circles, etc. + */ + +class SCH_DRAWING_TOOL : public TOOL_INTERACTIVE +{ +public: + SCH_DRAWING_TOOL(); + ~SCH_DRAWING_TOOL(); + + /// @copydoc TOOL_INTERACTIVE::Init() + bool Init() override; + + /// @copydoc TOOL_INTERACTIVE::Reset() + void Reset( RESET_REASON aReason ) override; + + ///> Get the SCH_DRAWING_TOOL top-level context menu + inline TOOL_MENU& GetToolMenu() + { + return m_menu; + } + + int PlaceSymbol( const TOOL_EVENT& aEvent ); + int PlacePower( const TOOL_EVENT& aEvent ); + int DrawWire( const TOOL_EVENT& aEvent ); + int DrawBus( const TOOL_EVENT& aEvent ); + int UnfoldBus( const TOOL_EVENT& aEvent ); + int PlaceNoConnect( const TOOL_EVENT& aEvent ); + int PlaceJunction( const TOOL_EVENT& aEvent ); + int PlaceBusWireEntry( const TOOL_EVENT& aEvent ); + int PlaceBusBusEntry( const TOOL_EVENT& aEvent ); + int PlaceLabel( const TOOL_EVENT& aEvent ); + int PlaceGlobalLabel( const TOOL_EVENT& aEvent ); + int PlaceHierarchicalLabel( const TOOL_EVENT& aEvent ); + int PlaceSchematicText( const TOOL_EVENT& aEvent ); + int DrawLines( const TOOL_EVENT& aEvent ); + int PlaceImage( const TOOL_EVENT& aEvent ); + +private: + + int doPlaceComponent( SCH_COMPONENT* aComponent, SCHLIB_FILTER* aFilter, + SCH_BASE_FRAME::HISTORY_LIST aHistoryList ); + + int doSingleClickPlace( KICAD_T aType ); + + int doTwoClickPlace( KICAD_T aType ); + + int doDrawSegments( int aType ); + void finishSegments(); + + ///> Sets up handlers for various events. + void setTransitions() override; + + KIGFX::SCH_VIEW* m_view; + KIGFX::VIEW_CONTROLS* m_controls; + SCH_EDIT_FRAME* m_frame; + + /// Data related to bus unfolding tool. + BUS_UNFOLDING_T m_busUnfold; + + /// Menu model displayed by the tool. + TOOL_MENU m_menu; +}; + +#endif /* SCH_DRAWING_TOOL_H */ diff --git a/eeschema/tools/sch_editor_control.cpp b/eeschema/tools/sch_editor_control.cpp index 74f427573b..4fa57b2b33 100644 --- a/eeschema/tools/sch_editor_control.cpp +++ b/eeschema/tools/sch_editor_control.cpp @@ -26,10 +26,6 @@ #include #include #include -#include -#include -#include -#include #include #include #include @@ -41,7 +37,6 @@ #include #include #include -#include #include TOOL_ACTION SCH_ACTIONS::refreshPreview( "eeschema.EditorControl.refreshPreview", @@ -57,50 +52,6 @@ TOOL_ACTION SCH_ACTIONS::highlightNetCursor( "eeschema.EditorControl.highlightNe AS_GLOBAL, 0, _( "Highlight Net" ), _( "Highlight wires and pins of a net" ), NULL, AF_ACTIVATE ); -TOOL_ACTION SCH_ACTIONS::placeSymbol( "eeschema.EditorControl.placeSymbol", - AS_GLOBAL, TOOL_ACTION::LegacyHotKey( HK_ADD_NEW_COMPONENT ), - _( "Add Symbol" ), _( "Add a symbol" ), NULL, AF_ACTIVATE ); - -TOOL_ACTION SCH_ACTIONS::placePower( "eeschema.EditorControl.placePowerPort", - AS_GLOBAL, TOOL_ACTION::LegacyHotKey( HK_ADD_NEW_POWER ), - _( "Add Power" ), _( "Add a power port" ), NULL, AF_ACTIVATE ); - -TOOL_ACTION SCH_ACTIONS::placeNoConnect( "eeschema.EditorControl.placeNoConnect", - AS_GLOBAL, TOOL_ACTION::LegacyHotKey( HK_ADD_NOCONN_FLAG ), - _( "Add No Connect Flag" ), _( "Add a no-connection flag" ), NULL, AF_ACTIVATE ); - -TOOL_ACTION SCH_ACTIONS::placeJunction( "eeschema.EditorControl.placeJunction", - AS_GLOBAL, TOOL_ACTION::LegacyHotKey( HK_ADD_JUNCTION ), - _( "Add Junction" ), _( "Add a junction" ), NULL, AF_ACTIVATE ); - -TOOL_ACTION SCH_ACTIONS::placeBusWireEntry( "eeschema.EditorControl.placeBusWireEntry", - AS_GLOBAL, TOOL_ACTION::LegacyHotKey( HK_ADD_WIRE_ENTRY ), - _( "Add Wire to Bus Entry" ), _( "Add a wire entry to a bus" ), NULL, AF_ACTIVATE ); - -TOOL_ACTION SCH_ACTIONS::placeBusBusEntry( "eeschema.EditorControl.placeBusBusEntry", - AS_GLOBAL, TOOL_ACTION::LegacyHotKey( HK_ADD_BUS_ENTRY ), - _( "Add Bus to Bus Entry" ), _( "Add a bus entry to a bus" ), NULL, AF_ACTIVATE ); - -TOOL_ACTION SCH_ACTIONS::placeLabel( "eeschema.EditorControl.placePLabel", - AS_GLOBAL, TOOL_ACTION::LegacyHotKey( HK_ADD_LABEL ), - _( "Add Label" ), _( "Add a net label" ), NULL, AF_ACTIVATE ); - -TOOL_ACTION SCH_ACTIONS::placeHierarchicalLabel( "eeschema.EditorControl.placeHierarchicalLabel", - AS_GLOBAL, TOOL_ACTION::LegacyHotKey( HK_ADD_HLABEL ), - _( "Add Hierarchical Label" ), _( "Add a hierarchical sheet label" ), NULL, AF_ACTIVATE ); - -TOOL_ACTION SCH_ACTIONS::placeGlobalLabel( "eeschema.EditorControl.placeGlobalLabel", - AS_GLOBAL, TOOL_ACTION::LegacyHotKey( HK_ADD_GLABEL ), - _( "Add Global Label" ), _( "Add a global label" ), NULL, AF_ACTIVATE ); - -TOOL_ACTION SCH_ACTIONS::placeSchematicText( "eeschema.EditorControl.placeSchematicText", - AS_GLOBAL, TOOL_ACTION::LegacyHotKey( HK_ADD_GRAPHIC_TEXT ), - _( "Add Text" ), _( "Add text" ), NULL, AF_ACTIVATE ); - -TOOL_ACTION SCH_ACTIONS::placeImage( "eeschema.EditorControl.placeImage", - AS_GLOBAL, 0, - _( "Add Image" ), _( "Add bitmap image" ), NULL, AF_ACTIVATE ); - SCH_EDITOR_CONTROL::SCH_EDITOR_CONTROL() : TOOL_INTERACTIVE( "eeschema.EditorControl" ), @@ -304,377 +255,6 @@ int SCH_EDITOR_CONTROL::HighlightNetCursor( const TOOL_EVENT& aEvent ) } -// History lists for PlaceSymbol() -static SCH_BASE_FRAME::HISTORY_LIST s_SymbolHistoryList; -static SCH_BASE_FRAME::HISTORY_LIST s_PowerHistoryList; - - -int SCH_EDITOR_CONTROL::PlaceSymbol( const TOOL_EVENT& aEvent ) -{ - SCH_COMPONENT* component = aEvent.Parameter(); - - m_frame->SetToolID( ID_SCH_PLACE_COMPONENT, wxCURSOR_PENCIL, _( "Add Symbol" ) ); - - return doPlaceComponent( component, nullptr, s_SymbolHistoryList ); -} - - -int SCH_EDITOR_CONTROL::PlacePower( const TOOL_EVENT& aEvent ) -{ - SCH_COMPONENT* component = aEvent.Parameter(); - SCHLIB_FILTER filter; - - filter.FilterPowerParts( true ); - m_frame->SetToolID( ID_PLACE_POWER_BUTT, wxCURSOR_PENCIL, _( "Add Power" ) ); - - return doPlaceComponent( component, &filter, s_PowerHistoryList ); -} - - -int SCH_EDITOR_CONTROL::doPlaceComponent( SCH_COMPONENT* aComponent, SCHLIB_FILTER* aFilter, - SCH_BASE_FRAME::HISTORY_LIST aHistoryList ) -{ - KIGFX::VIEW_CONTROLS* controls = getViewControls(); - VECTOR2I cursorPos = controls->GetCursorPosition(); - KIGFX::SCH_VIEW* view = static_cast( getView() ); - - m_toolMgr->RunAction( SCH_ACTIONS::selectionClear, true ); - controls->ShowCursor( true ); - controls->SetSnapping( true ); - - Activate(); - - // Add all the drawable parts to preview - if( aComponent ) - { - aComponent->SetPosition( (wxPoint)cursorPos ); - view->ClearPreview(); - view->AddToPreview( aComponent->Clone() ); - } - - // Main loop: keep receiving events - while( OPT_TOOL_EVENT evt = Wait() ) - { - cursorPos = controls->GetCursorPosition( !evt->Modifier( MD_ALT ) ); - - if( evt->IsAction( &ACTIONS::cancelInteractive ) || evt->IsActivate() || evt->IsCancel() ) - { - if( aComponent ) - { - m_toolMgr->RunAction( SCH_ACTIONS::selectionClear, true ); - getModel()->SetCurItem( nullptr ); - view->ClearPreview(); - view->ClearHiddenFlags(); - delete aComponent; - aComponent = nullptr; - } - else - break; - - if( evt->IsActivate() ) // now finish unconditionally - break; - } - else if( evt->IsClick( BUT_LEFT ) ) - { - if( !aComponent ) - { - // Pick the module to be placed - m_frame->SetRepeatItem( NULL ); - m_frame->GetCanvas()->SetIgnoreMouseEvents( true ); - - auto sel = m_frame->SelectComponentFromLibTree( aFilter, aHistoryList, true, 1, 1, - m_frame->GetShowFootprintPreviews() ); - - // Restore cursor after dialog - m_frame->GetCanvas()->MoveCursorToCrossHair(); - - LIB_PART* part = nullptr; - - if( sel.LibId.IsValid() ) - part = m_frame->GetLibPart( sel.LibId ); - - if( !part ) - continue; - - aComponent = new SCH_COMPONENT( *part, sel.LibId, g_CurrentSheet, sel.Unit, - sel.Convert, (wxPoint)cursorPos, true ); - - // Be sure the link to the corresponding LIB_PART is OK: - aComponent->Resolve( *m_frame->Prj().SchSymbolLibTable() ); - - // Set any fields that have been modified - for( auto const& i : sel.Fields ) - { - auto field = aComponent->GetField( i.first ); - - if( field ) - field->SetText( i.second ); - } - - MSG_PANEL_ITEMS items; - aComponent->GetMsgPanelInfo( m_frame->GetUserUnits(), items ); - m_frame->SetMsgPanel( items ); - - if( m_frame->GetAutoplaceFields() ) - aComponent->AutoplaceFields( /* aScreen */ NULL, /* aManual */ false ); - - aComponent->SetFlags( IS_MOVED ); - m_frame->SetRepeatItem( aComponent ); - m_frame->GetScreen()->SetCurItem( aComponent ); - view->ClearPreview(); - view->AddToPreview( aComponent->Clone() ); - - controls->SetCursorPosition( cursorPos, false ); - } - else - { - view->ClearPreview(); - - m_frame->AddItemToScreen( aComponent ); - - aComponent = nullptr; - } - } - else if( evt->IsClick( BUT_RIGHT ) ) - { - // JEY TODO - // m_menu.ShowContextMenu( selTool->GetSelection() ); - } - else if( aComponent && ( evt->IsAction( &SCH_ACTIONS::refreshPreview ) || evt->IsMotion() ) ) - { - aComponent->SetPosition( (wxPoint)cursorPos ); - view->ClearPreview(); - view->AddToPreview( aComponent->Clone() ); - } - - // Enable autopanning and cursor capture only when there is a module to be placed - controls->SetAutoPan( !!aComponent ); - controls->CaptureCursor( !!aComponent ); - } - - m_frame->SetNoToolSelected(); - - return 0; -} - - -int SCH_EDITOR_CONTROL::PlaceNoConnect( const TOOL_EVENT& aEvent ) -{ - m_frame->SetToolID( ID_NOCONN_BUTT, wxCURSOR_PENCIL, _( "Add no connect" ) ); - return doSingleClickPlace( SCH_NO_CONNECT_T ); -} - - -int SCH_EDITOR_CONTROL::PlaceJunction( const TOOL_EVENT& aEvent ) -{ - m_frame->SetToolID( ID_JUNCTION_BUTT, wxCURSOR_PENCIL, _( "Add junction" ) ); - return doSingleClickPlace( SCH_JUNCTION_T ); -} - - -int SCH_EDITOR_CONTROL::PlaceBusWireEntry( const TOOL_EVENT& aEvent ) -{ - m_frame->SetToolID( ID_WIRETOBUS_ENTRY_BUTT, wxCURSOR_PENCIL, _( "Add wire to bus entry" ) ); - return doSingleClickPlace( SCH_BUS_WIRE_ENTRY_T ); -} - - -int SCH_EDITOR_CONTROL::PlaceBusBusEntry( const TOOL_EVENT& aEvent ) -{ - m_frame->SetToolID( ID_BUSTOBUS_ENTRY_BUTT, wxCURSOR_PENCIL, _( "Add bus to bus entry" ) ); - return doSingleClickPlace( SCH_BUS_BUS_ENTRY_T ); -} - - -int SCH_EDITOR_CONTROL::doSingleClickPlace( KICAD_T aType ) -{ - KIGFX::VIEW_CONTROLS* controls = getViewControls(); - - m_toolMgr->RunAction( SCH_ACTIONS::selectionClear, true ); - controls->ShowCursor( true ); - controls->SetSnapping( true ); - - Activate(); - - // Main loop: keep receiving events - while( OPT_TOOL_EVENT evt = Wait() ) - { - wxPoint cursorPos = (wxPoint)controls->GetCursorPosition( !evt->Modifier( MD_ALT ) ); - - if( evt->IsAction( &ACTIONS::cancelInteractive ) || evt->IsActivate() || evt->IsCancel() ) - { - break; - } - else if( evt->IsClick( BUT_LEFT ) ) - { - SCH_ITEM* item = nullptr; - - if( !m_frame->GetScreen()->GetItem( cursorPos, 0, aType ) ) - { - switch( aType ) - { - case SCH_NO_CONNECT_T: item = m_frame->AddNoConnect( cursorPos ); break; - case SCH_JUNCTION_T: item = m_frame->AddJunction( cursorPos ); break; - case SCH_BUS_WIRE_ENTRY_T: item = m_frame->CreateBusWireEntry(); break; - case SCH_BUS_BUS_ENTRY_T: item = m_frame->CreateBusBusEntry(); break; - default: wxFAIL_MSG( "doSingleClickPlace(): unknown type" ); - } - } - - if( item ) - { - m_frame->SetRepeatItem( item ); - m_frame->GetScreen()->SetCurItem( item ); - } - } - else if( evt->IsClick( BUT_RIGHT ) ) - { - // JEY TODO - // m_menu.ShowContextMenu( selTool->GetSelection() ); - } - } - - m_frame->SetNoToolSelected(); - - return 0; -} - - -int SCH_EDITOR_CONTROL::PlaceLabel( const TOOL_EVENT& aEvent ) -{ - m_frame->SetToolID( ID_LABEL_BUTT, wxCURSOR_PENCIL, _( "Add net label" ) ); - return doTwoClickPlace( SCH_LABEL_T ); -} - - -int SCH_EDITOR_CONTROL::PlaceGlobalLabel( const TOOL_EVENT& aEvent ) -{ - m_frame->SetToolID( ID_GLOBALLABEL_BUTT, wxCURSOR_PENCIL, _( "Add global label" ) ); - return doTwoClickPlace( SCH_GLOBAL_LABEL_T ); -} - - -int SCH_EDITOR_CONTROL::PlaceHierarchicalLabel( const TOOL_EVENT& aEvent ) -{ - m_frame->SetToolID( ID_HIERLABEL_BUTT, wxCURSOR_PENCIL, _( "Add hierarchical label" ) ); - return doTwoClickPlace( SCH_HIER_LABEL_T ); -} - - -int SCH_EDITOR_CONTROL::PlaceSchematicText( const TOOL_EVENT& aEvent ) -{ - m_frame->SetToolID( ID_TEXT_COMMENT_BUTT, wxCURSOR_PENCIL, _( "Add text" ) ); - return doTwoClickPlace( SCH_TEXT_T ); -} - - -int SCH_EDITOR_CONTROL::PlaceImage( const TOOL_EVENT& aEvent ) -{ - m_frame->SetToolID( ID_ADD_IMAGE_BUTT, wxCURSOR_PENCIL, _( "Add image" ) ); - return doTwoClickPlace( SCH_BITMAP_T ); -} - - -int SCH_EDITOR_CONTROL::doTwoClickPlace( KICAD_T aType ) -{ - KIGFX::VIEW_CONTROLS* controls = getViewControls(); - VECTOR2I cursorPos = controls->GetCursorPosition(); - KIGFX::SCH_VIEW* view = static_cast( getView() ); - SCH_ITEM* item = nullptr; - - m_toolMgr->RunAction( SCH_ACTIONS::selectionClear, true ); - controls->ShowCursor( true ); - controls->SetSnapping( true ); - - Activate(); - - // Main loop: keep receiving events - while( OPT_TOOL_EVENT evt = Wait() ) - { - cursorPos = controls->GetCursorPosition( !evt->Modifier( MD_ALT ) ); - - if( evt->IsAction( &ACTIONS::cancelInteractive ) || evt->IsActivate() || evt->IsCancel() ) - { - if( item ) - { - m_toolMgr->RunAction( SCH_ACTIONS::selectionClear, true ); - getModel()->SetCurItem( nullptr ); - view->ClearPreview(); - view->ClearHiddenFlags(); - delete item; - item = nullptr; - } - else - break; - - if( evt->IsActivate() ) // now finish unconditionally - break; - } - else if( evt->IsClick( BUT_LEFT ) ) - { - if( !item ) - { - m_frame->SetRepeatItem( NULL ); - m_frame->GetCanvas()->SetIgnoreMouseEvents( true ); - - switch( aType ) - { - case SCH_LABEL_T: item = m_frame->CreateNewText( LAYER_LOCLABEL ); break; - case SCH_HIER_LABEL_T: item = m_frame->CreateNewText( LAYER_HIERLABEL ); break; - case SCH_GLOBAL_LABEL_T: item = m_frame->CreateNewText( LAYER_GLOBLABEL ); break; - case SCH_TEXT_T: item = m_frame->CreateNewText( LAYER_NOTES ); break; - case SCH_BITMAP_T: item = m_frame->CreateNewImage(); break; - default: wxFAIL_MSG( "doTwoClickPlace(): unknown type" ); - } - - // Restore cursor after dialog - m_frame->GetCanvas()->MoveCursorToCrossHair(); - - if( item ) - { - MSG_PANEL_ITEMS items; - item->GetMsgPanelInfo( m_frame->GetUserUnits(), items ); - m_frame->SetMsgPanel( items ); - - item->SetFlags( IS_MOVED ); - view->ClearPreview(); - view->AddToPreview( item->Clone() ); - } - - controls->SetCursorPosition( cursorPos, false ); - } - else - { - view->ClearPreview(); - - m_frame->AddItemToScreen( item ); - - item = nullptr; - } - } - else if( evt->IsClick( BUT_RIGHT ) ) - { - // JEY TODO - // m_menu.ShowContextMenu( selTool->GetSelection() ); - } - else if( item && ( evt->IsAction( &SCH_ACTIONS::refreshPreview ) || evt->IsMotion() ) ) - { - item->SetPosition( (wxPoint)cursorPos ); - view->ClearPreview(); - view->AddToPreview( item->Clone() ); - } - - // Enable autopanning and cursor capture only when there is a module to be placed - controls->SetAutoPan( !!item ); - controls->CaptureCursor( !!item ); - } - - m_frame->SetNoToolSelected(); - - return 0; -} - - void SCH_EDITOR_CONTROL::setTransitions() { /* @@ -693,16 +273,4 @@ void SCH_EDITOR_CONTROL::setTransitions() Go( &SCH_EDITOR_CONTROL::HighlightNet, SCH_ACTIONS::highlightNet.MakeEvent() ); Go( &SCH_EDITOR_CONTROL::HighlightNetCursor, SCH_ACTIONS::highlightNetCursor.MakeEvent() ); Go( &SCH_EDITOR_CONTROL::HighlightNetSelection, SCH_ACTIONS::highlightNetSelection.MakeEvent() ); - - Go( &SCH_EDITOR_CONTROL::PlaceSymbol, SCH_ACTIONS::placeSymbol.MakeEvent() ); - Go( &SCH_EDITOR_CONTROL::PlacePower, SCH_ACTIONS::placePower.MakeEvent() ); - Go( &SCH_EDITOR_CONTROL::PlaceNoConnect, SCH_ACTIONS::placeNoConnect.MakeEvent() ); - Go( &SCH_EDITOR_CONTROL::PlaceJunction, SCH_ACTIONS::placeJunction.MakeEvent() ); - Go( &SCH_EDITOR_CONTROL::PlaceBusWireEntry, SCH_ACTIONS::placeBusWireEntry.MakeEvent() ); - Go( &SCH_EDITOR_CONTROL::PlaceBusBusEntry, SCH_ACTIONS::placeBusBusEntry.MakeEvent() ); - Go( &SCH_EDITOR_CONTROL::PlaceLabel, SCH_ACTIONS::placeLabel.MakeEvent() ); - Go( &SCH_EDITOR_CONTROL::PlaceHierarchicalLabel,SCH_ACTIONS::placeHierarchicalLabel.MakeEvent() ); - Go( &SCH_EDITOR_CONTROL::PlaceGlobalLabel, SCH_ACTIONS::placeGlobalLabel.MakeEvent() ); - Go( &SCH_EDITOR_CONTROL::PlaceSchematicText, SCH_ACTIONS::placeSchematicText.MakeEvent() ); - Go( &SCH_EDITOR_CONTROL::PlaceImage, SCH_ACTIONS::placeImage.MakeEvent() ); } diff --git a/eeschema/tools/sch_editor_control.h b/eeschema/tools/sch_editor_control.h index 5e2a327aa0..7800713fe7 100644 --- a/eeschema/tools/sch_editor_control.h +++ b/eeschema/tools/sch_editor_control.h @@ -31,8 +31,6 @@ #include class SCH_EDIT_FRAME; -class SCH_COMPONENT; -class SCHLIB_FILTER; /** * Class SCH_EDITOR_CONTROL @@ -70,27 +68,8 @@ public: ///> Launches a tool to highlight nets. int HighlightNetCursor( const TOOL_EVENT& aEvent ); - int PlaceSymbol( const TOOL_EVENT& aEvent ); - int PlacePower( const TOOL_EVENT& aEvent ); - int PlaceNoConnect( const TOOL_EVENT& aEvent ); - int PlaceJunction( const TOOL_EVENT& aEvent ); - int PlaceBusWireEntry( const TOOL_EVENT& aEvent ); - int PlaceBusBusEntry( const TOOL_EVENT& aEvent ); - int PlaceLabel( const TOOL_EVENT& aEvent ); - int PlaceGlobalLabel( const TOOL_EVENT& aEvent ); - int PlaceHierarchicalLabel( const TOOL_EVENT& aEvent ); - int PlaceSchematicText( const TOOL_EVENT& aEvent ); - int PlaceImage( const TOOL_EVENT& aEvent ); - private: - int doPlaceComponent( SCH_COMPONENT* aComponent, SCHLIB_FILTER* aFilter, - SCH_BASE_FRAME::HISTORY_LIST aHistoryList ); - - int doSingleClickPlace( KICAD_T aType ); - - int doTwoClickPlace( KICAD_T aType ); - ///> Sets up handlers for various events. void setTransitions() override; @@ -99,7 +78,6 @@ private: /// Menu model displayed by the tool. TOOL_MENU m_menu; - }; diff --git a/include/tool/tool_base.h b/include/tool/tool_base.h index 0302c15858..a8a5fcf6fe 100644 --- a/include/tool/tool_base.h +++ b/include/tool/tool_base.h @@ -199,6 +199,7 @@ protected: T* getModel() const { EDA_ITEM* m = getModelInt(); + wxASSERT( dynamic_cast( m ) ); return static_cast( m ); }