diff --git a/eeschema/tools/sch_move_tool.cpp b/eeschema/tools/sch_move_tool.cpp index 989b292f3a..01479058de 100644 --- a/eeschema/tools/sch_move_tool.cpp +++ b/eeschema/tools/sch_move_tool.cpp @@ -46,6 +46,9 @@ #include #include #include +#include +#include +#include #include "sch_move_tool.h" @@ -500,6 +503,7 @@ bool SCH_MOVE_TOOL::doMoveSelection( const TOOL_EVENT& aEvent, SCH_COMMIT* aComm TOOL_EVENT* evt = © VECTOR2I prevPos; GRID_HELPER_GRIDS snapLayer = GRID_CURRENT; + SCH_SHEET* hoverSheet = nullptr; m_cursor = controls->GetCursorPosition(); @@ -771,7 +775,65 @@ bool SCH_MOVE_TOOL::doMoveSelection( const TOOL_EVENT& aEvent, SCH_COMMIT* aComm m_cursor = grid.BestSnapAnchor( controls->GetCursorPosition( false ), snapLayer, selection ); + // Determine potential target sheet. + SCH_SHEET* sheet = dynamic_cast( m_frame->GetScreen()->GetItem( m_cursor, 0, + SCH_SHEET_T ) ); + if( sheet && sheet->IsSelected() ) + sheet = nullptr; // Never target a selected sheet + if( !sheet ) + { + // Build current selection bounding box in its (already moved) position. + BOX2I selBBox; + for( EDA_ITEM* it : selection ) + { + if( SCH_ITEM* schIt = dynamic_cast( it ) ) + selBBox.Merge( schIt->GetBoundingBox() ); + } + + if( selBBox.GetWidth() > 0 && selBBox.GetHeight() > 0 ) + { + VECTOR2I selCenter( selBBox.GetX() + selBBox.GetWidth() / 2, + selBBox.GetY() + selBBox.GetHeight() / 2 ); + + // Find first non-selected sheet whose body fully contains the selection + // or at least contains its center point. + for( SCH_ITEM* it : m_frame->GetScreen()->Items().OfType( SCH_SHEET_T ) ) + { + SCH_SHEET* candidate = static_cast( it ); + if( candidate->IsSelected() || candidate->IsRootSheet() ) + continue; + + BOX2I body = candidate->GetBodyBoundingBox(); + + if( body.Contains( selBBox ) || body.Contains( selCenter ) ) + { + sheet = candidate; + break; + } + } + } + } + + if( sheet != hoverSheet ) + { + if( hoverSheet ) + { + hoverSheet->ClearFlags( BRIGHTENED ); + m_frame->UpdateItem( hoverSheet, false ); + } + + hoverSheet = sheet; + + if( hoverSheet ) + { + hoverSheet->SetFlags( BRIGHTENED ); + m_frame->UpdateItem( hoverSheet, false ); + } + } + + m_frame->GetCanvas()->SetCurrentCursor( hoverSheet ? KICURSOR::PLACE + : KICURSOR::MOVING ); VECTOR2I delta( m_cursor - prevPos ); m_anchorPos = m_cursor; @@ -1032,6 +1094,22 @@ bool SCH_MOVE_TOOL::doMoveSelection( const TOOL_EVENT& aEvent, SCH_COMMIT* aComm } while( ( evt = Wait() ) ); //Should be assignment not equality test + SCH_SHEET* targetSheet = hoverSheet; + + if( hoverSheet ) + { + hoverSheet->ClearFlags( BRIGHTENED ); + m_frame->UpdateItem( hoverSheet, false ); + } + + if( targetSheet ) + { + moveSelectionToSheet( selection, targetSheet, aCommit ); + m_toolMgr->RunAction( ACTIONS::selectionClear ); + m_newDragLines.clear(); + m_changedDragLines.clear(); + } + // Create a selection of original selection, drag selected/changed items, and new // bend lines for later before we clear them in the aCommit. We'll need these // to check for new junctions needed, etc. @@ -1135,6 +1213,60 @@ bool SCH_MOVE_TOOL::doMoveSelection( const TOOL_EVENT& aEvent, SCH_COMMIT* aComm } +void SCH_MOVE_TOOL::moveSelectionToSheet( SCH_SELECTION& aSelection, SCH_SHEET* aTargetSheet, + SCH_COMMIT* aCommit ) +{ + SCH_SCREEN* destScreen = aTargetSheet->GetScreen(); + SCH_SCREEN* srcScreen = m_frame->GetScreen(); + + BOX2I bbox; + + for( EDA_ITEM* item : aSelection ) + bbox.Merge( static_cast( item )->GetBoundingBox() ); + + VECTOR2I offset = VECTOR2I( 0, 0 ) - bbox.GetPosition(); + int step = schIUScale.MilsToIU( 50 ); + bool overlap = false; + + do + { + BOX2I moved = bbox; + moved.Move( offset ); + overlap = false; + + for( SCH_ITEM* existing : destScreen->Items() ) + { + if( moved.Intersects( existing->GetBoundingBox() ) ) + { + overlap = true; + break; + } + } + + if( overlap ) + offset += VECTOR2I( step, step ); + } while( overlap ); + + for( EDA_ITEM* item : aSelection ) + { + SCH_ITEM* schItem = static_cast( item ); + + // Remove from current screen and view manually + m_frame->RemoveFromScreen( schItem, srcScreen ); + + // Move the item + schItem->Move( offset ); + + // Add to destination screen manually (won't add to view since it's not current) + destScreen->Append( schItem ); + + // Record in commit with CHT_DONE flag to bypass automatic screen/view operations + aCommit->Stage( schItem, CHT_REMOVE | CHT_DONE, srcScreen ); + aCommit->Stage( schItem, CHT_ADD | CHT_DONE, destScreen ); + } +} + + void SCH_MOVE_TOOL::trimDanglingLines( SCH_COMMIT* aCommit ) { // Need a local cleanup first to ensure we remove unneeded junctions @@ -1163,8 +1295,7 @@ void SCH_MOVE_TOOL::trimDanglingLines( SCH_COMMIT* aCommit ) { line->SetFlags( STRUCT_DELETED ); aCommit->Removed( line, m_frame->GetScreen() ); - - updateItem( line, false ); + updateItem( line, false ); // Update any cached visuals before commit processes m_frame->RemoveFromScreen( line, m_frame->GetScreen() ); } } diff --git a/eeschema/tools/sch_move_tool.h b/eeschema/tools/sch_move_tool.h index 14097b2f84..73dea13cfd 100644 --- a/eeschema/tools/sch_move_tool.h +++ b/eeschema/tools/sch_move_tool.h @@ -35,6 +35,9 @@ class SCH_LINE; class SCH_LABEL_BASE; class SCH_SHEET_PIN; class SCH_JUNCTION; +class SCH_SELECTION; +class SCH_SHEET; +class SCH_COMMIT; struct SPECIAL_CASE_LABEL_INFO @@ -81,6 +84,8 @@ private: void orthoLineDrag( SCH_COMMIT* aCommit, SCH_LINE* line, const VECTOR2I& splitDelta, int& xBendCount, int& yBendCount, const EE_GRID_HELPER& grid ); + void moveSelectionToSheet( SCH_SELECTION& aSelection, SCH_SHEET* aTarget, SCH_COMMIT* aCommit ); + ///< Clears the new drag lines and removes them from the screen void clearNewDragLines();