int ALIGN_DISTRIBUTE_TOOL::AlignCenterY( const TOOL_EVENT& aEvent ) { ALIGNMENT_RECTS itemsToAlign; ALIGNMENT_RECTS locked_items; if( !GetSelections( itemsToAlign, locked_items, []( const ALIGNMENT_RECT left, const ALIGNMENT_RECT right) { return ( left.second.GetCenter().y < right.second.GetCenter().y ); } ) ) return 0; BOARD_COMMIT commit( m_frame ); commit.StageItems( m_selectionTool->GetSelection(), CHT_MODIFY ); auto targetY = selectTarget( itemsToAlign, locked_items, []( const ALIGNMENT_RECT& aVal ) { return aVal.second.GetCenter().y; } ); // Move the selected items for( auto& i : itemsToAlign ) { int difference = targetY - i.second.GetCenter().y; BOARD_ITEM* item = i.first; // Don't move a pad by itself unless editing the footprint if( item->Type() == PCB_PAD_T && m_frame->IsType( FRAME_PCB ) ) item = item->GetParent(); item->Move( wxPoint( 0, difference ) ); } commit.Push( _( "Align to center" ) ); return 0; }
int PLACEMENT_TOOL::AlignTop( const TOOL_EVENT& aEvent ) { const SELECTION& selection = m_selectionTool->GetSelection(); if( selection.Size() <= 1 ) return 0; BOARD_COMMIT commit( getEditFrame<PCB_BASE_FRAME>() ); commit.Stage( selection.items, UR_CHANGED ); // Compute the highest point of selection - it will be the edge of alignment int top = selection.Item<BOARD_ITEM>( 0 )->GetBoundingBox().GetY(); for( int i = 1; i < selection.Size(); ++i ) { int currentTop = selection.Item<BOARD_ITEM>( i )->GetBoundingBox().GetY(); if( top > currentTop ) // Y decreases when going up top = currentTop; } // Move the selected items for( int i = 0; i < selection.Size(); ++i ) { BOARD_ITEM* item = selection.Item<BOARD_ITEM>( i ); int difference = top - item->GetBoundingBox().GetY(); item->Move( wxPoint( 0, difference ) ); } commit.Push( _( "Align to top" ) ); return 0; }
int PLACEMENT_TOOL::AlignRight( const TOOL_EVENT& aEvent ) { const SELECTION& selection = m_selectionTool->GetSelection(); if( selection.Size() <= 1 ) return 0; BOARD_COMMIT commit( getEditFrame<PCB_BASE_FRAME>() ); commit.Stage( selection.items, UR_CHANGED ); // Compute the rightmost point of selection - it will be the edge of alignment int right = selection.Item<BOARD_ITEM>( 0 )->GetBoundingBox().GetRight(); for( int i = 1; i < selection.Size(); ++i ) { int currentRight = selection.Item<BOARD_ITEM>( i )->GetBoundingBox().GetRight(); if( right < currentRight ) // X increases when going right right = currentRight; } // Move the selected items for( int i = 0; i < selection.Size(); ++i ) { BOARD_ITEM* item = selection.Item<BOARD_ITEM>( i ); int difference = right - item->GetBoundingBox().GetRight(); item->Move( wxPoint( difference, 0 ) ); } commit.Push( _( "Align to right" ) ); return 0; }
int EDIT_TOOL::MoveExact( const TOOL_EVENT& aEvent ) { const SELECTION& selection = m_selectionTool->GetSelection(); // Shall the selection be cleared at the end? bool unselect = selection.Empty(); if( !hoverSelection( selection ) ) return 0; wxPoint translation; double rotation = 0; PCB_BASE_FRAME* editFrame = getEditFrame<PCB_BASE_FRAME>(); DIALOG_MOVE_EXACT dialog( editFrame, translation, rotation ); int ret = dialog.ShowModal(); if( ret == wxID_OK ) { if( !isUndoInhibited() ) { editFrame->OnModify(); // Record an action of move and rotate editFrame->SaveCopyInUndoList( selection.items, UR_CHANGED ); } VECTOR2I rp = selection.GetCenter(); wxPoint rotPoint( rp.x, rp.y ); for( unsigned int i = 0; i < selection.items.GetCount(); ++i ) { BOARD_ITEM* item = selection.Item<BOARD_ITEM>( i ); item->Move( translation ); item->Rotate( rotPoint, rotation ); if( !m_dragging ) item->ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY ); } updateRatsnest( m_dragging ); if( m_dragging ) selection.group->ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY ); else getModel<BOARD>()->GetRatsnest()->Recalculate(); if( unselect ) m_toolMgr->RunAction( COMMON_ACTIONS::selectionClear, true ); m_toolMgr->RunAction( COMMON_ACTIONS::pointEditorUpdate, true ); } return 0; }
void PCB_EDIT_FRAME::Block_Move() { OnModify(); wxPoint MoveVector = GetScreen()->m_BlockLocate.GetMoveVector(); PICKED_ITEMS_LIST* itemsList = &GetScreen()->m_BlockLocate.GetItems(); itemsList->m_Status = UR_MOVED; for( unsigned ii = 0; ii < itemsList->GetCount(); ii++ ) { BOARD_ITEM* item = (BOARD_ITEM*) itemsList->GetPickedItem( ii ); itemsList->SetPickedItemStatus( UR_MOVED, ii ); item->Move( MoveVector ); GetBoard()->GetConnectivity()->Update( item ); item->ClearFlags( IS_MOVED ); switch( item->Type() ) { case PCB_MODULE_T: m_Pcb->m_Status_Pcb = 0; item->ClearFlags(); break; // Move track segments case PCB_TRACE_T: // a track segment (segment on a copper layer) case PCB_VIA_T: // a via (like a track segment on a copper layer) m_Pcb->m_Status_Pcb = 0; break; case PCB_ZONE_AREA_T: case PCB_LINE_T: case PCB_TEXT_T: case PCB_TARGET_T: case PCB_DIMENSION_T: break; // This item is not put in undo list case PCB_ZONE_T: // SEG_ZONE items are now deprecated itemsList->RemovePicker( ii ); ii--; break; default: wxMessageBox( wxT( "PCB_EDIT_FRAME::Block_Move( ) error: unexpected type" ) ); break; } } SaveCopyInUndoList( *itemsList, UR_MOVED, MoveVector ); Compile_Ratsnest( NULL, true ); m_canvas->Refresh( true ); }
void FOOTPRINT_EDIT_FRAME::moveExact() { MOVE_PARAMETERS params; params.allowOverride = false; params.editingFootprint = true; DIALOG_MOVE_EXACT dialog( this, params ); int ret = dialog.ShowModal(); if( ret == wxID_OK ) { SaveCopyInUndoList( GetBoard()->m_Modules, UR_CHANGED ); BOARD_ITEM* item = GetScreen()->GetCurItem(); wxPoint anchorPoint = item->GetPosition(); wxPoint origin; switch( params.origin ) { case RELATIVE_TO_USER_ORIGIN: origin = GetScreen()->m_O_Curseur; break; case RELATIVE_TO_GRID_ORIGIN: origin = GetGridOrigin(); break; case RELATIVE_TO_DRILL_PLACE_ORIGIN: origin = GetAuxOrigin(); break; case RELATIVE_TO_SHEET_ORIGIN: origin = wxPoint( 0, 0 ); break; case RELATIVE_TO_CURRENT_POSITION: // relative movement means that only the translation values should be used: // -> set origin and anchor to zero origin = wxPoint( 0, 0 ); anchorPoint = wxPoint( 0, 0 ); break; } wxPoint finalMoveVector = params.translation + origin - anchorPoint; item->Move( finalMoveVector ); item->Rotate( item->GetPosition(), params.rotation ); m_canvas->Refresh(); } m_canvas->MoveCursorToCrossHair(); }
int EDIT_TOOL::MoveExact( const TOOL_EVENT& aEvent ) { const SELECTION& selection = m_selectionTool->GetSelection(); // Shall the selection be cleared at the end? bool unselect = selection.Empty(); if( !hoverSelection() || m_selectionTool->CheckLock() == SELECTION_LOCKED ) return 0; wxPoint translation; double rotation = 0; PCB_BASE_FRAME* editFrame = getEditFrame<PCB_BASE_FRAME>(); DIALOG_MOVE_EXACT dialog( editFrame, translation, rotation ); int ret = dialog.ShowModal(); if( ret == wxID_OK ) { VECTOR2I rp = selection.GetCenter(); wxPoint rotPoint( rp.x, rp.y ); for( unsigned int i = 0; i < selection.items.GetCount(); ++i ) { BOARD_ITEM* item = selection.Item<BOARD_ITEM>( i ); m_commit->Modify( item ); item->Move( translation ); item->Rotate( rotPoint, rotation ); if( !m_dragging ) item->ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY ); } m_commit->Push( _( "Move exact" ) ); if( unselect ) m_toolMgr->RunAction( COMMON_ACTIONS::selectionClear, true ); m_toolMgr->RunAction( COMMON_ACTIONS::editModifiedSelection, true ); } return 0; }
void PCB_EDIT_FRAME::Block_Duplicate( bool aIncrement ) { wxPoint MoveVector = GetScreen()->m_BlockLocate.GetMoveVector(); OnModify(); PICKED_ITEMS_LIST* itemsList = &GetScreen()->m_BlockLocate.GetItems(); PICKED_ITEMS_LIST newList; newList.m_Status = UR_NEW; ITEM_PICKER picker( NULL, UR_NEW ); BOARD_ITEM* newitem; for( unsigned ii = 0; ii < itemsList->GetCount(); ii++ ) { BOARD_ITEM* item = (BOARD_ITEM*) itemsList->GetPickedItem( ii ); newitem = (BOARD_ITEM*)item->Clone(); if( aIncrement ) newitem->IncrementItemReference(); if( item->Type() == PCB_MODULE_T ) m_Pcb->m_Status_Pcb = 0; m_Pcb->Add( newitem ); if( newitem ) { newitem->Move( MoveVector ); picker.SetItem ( newitem ); newList.PushItem( picker ); } } if( newList.GetCount() ) SaveCopyInUndoList( newList, UR_NEW ); Compile_Ratsnest( NULL, true ); m_canvas->Refresh( true ); }
void FOOTPRINT_EDIT_FRAME::moveExact() { wxPoint translation; double rotation = 0; DIALOG_MOVE_EXACT dialog( this, translation, rotation ); int ret = dialog.ShowModal(); if( ret == wxID_OK ) { SaveCopyInUndoList( GetBoard()->m_Modules, UR_MODEDIT ); BOARD_ITEM* item = GetScreen()->GetCurItem(); item->Move( translation ); item->Rotate( item->GetPosition(), rotation ); m_canvas->Refresh(); } m_canvas->MoveCursorToCrossHair(); }
void ALIGN_DISTRIBUTE_TOOL::doDistributeCentersVertically( ALIGNMENT_RECTS& itemsToDistribute ) const { std::sort( itemsToDistribute.begin(), itemsToDistribute.end(), [] ( const ALIGNMENT_RECT left, const ALIGNMENT_RECT right) { return ( left.second.GetCenter().y < right.second.GetCenter().y ); } ); const auto totalGap = ( itemsToDistribute.end()-1 )->second.GetCenter().y - itemsToDistribute.begin()->second.GetCenter().y; const auto itemGap = totalGap / ( itemsToDistribute.size() - 1 ); auto targetY = itemsToDistribute.begin()->second.GetCenter().y; for( auto& i : itemsToDistribute ) { BOARD_ITEM* item = i.first; // Don't move a pad by itself unless editing the footprint if( item->Type() == PCB_PAD_T && m_frame->IsType( FRAME_PCB ) ) item = item->GetParent(); int difference = targetY - i.second.GetCenter().y; item->Move( wxPoint( 0, difference ) ); targetY += ( itemGap ); } }
void ALIGN_DISTRIBUTE_TOOL::doDistributeGapsHorizontally( ALIGNMENT_RECTS& itemsToDistribute, const BOARD_ITEM* lastItem, int totalGap ) const { const auto itemGap = totalGap / ( itemsToDistribute.size() - 1 ); auto targetX = itemsToDistribute.begin()->second.GetX(); for( auto& i : itemsToDistribute ) { BOARD_ITEM* item = i.first; // cover the corner case where the last item is wider than the previous item and gap if( lastItem == item ) continue; // Don't move a pad by itself unless editing the footprint if( item->Type() == PCB_PAD_T && m_frame->IsType( FRAME_PCB ) ) item = item->GetParent(); int difference = targetX - i.second.GetX(); item->Move( wxPoint( difference, 0 ) ); targetX += ( i.second.GetWidth() + itemGap ); } }
void PCB_BASE_EDIT_FRAME::PutDataInPreviousState( PICKED_ITEMS_LIST* aList, bool aRedoCommand, bool aRebuildRatsnet ) { BOARD_ITEM* item; bool not_found = false; bool reBuild_ratsnest = false; bool deep_reBuild_ratsnest = false; // true later if pointers must be rebuilt auto view = GetGalCanvas()->GetView(); auto connectivity = GetBoard()->GetConnectivity(); // Undo in the reverse order of list creation: (this can allow stacked changes // like the same item can be changes and deleted in the same complex command bool build_item_list = true; // if true the list of existing items must be rebuilt // Restore changes in reverse order for( int ii = aList->GetCount() - 1; ii >= 0 ; ii-- ) { item = (BOARD_ITEM*) aList->GetPickedItem( ii ); wxASSERT( item ); /* Test for existence of item on board. * It could be deleted, and no more on board: * - if a call to SaveCopyInUndoList was forgotten in Pcbnew * - in zones outlines, when a change in one zone merges this zone with an other * This test avoids a Pcbnew crash * Obviously, this test is not made for deleted items */ UNDO_REDO_T status = aList->GetPickedItemStatus( ii ); if( status != UR_DELETED && status != UR_DRILLORIGIN // origin markers never on board && status != UR_GRIDORIGIN ) // origin markers never on board { if( build_item_list ) // Build list of existing items, for integrity test TestForExistingItem( GetBoard(), NULL ); build_item_list = false; if( !TestForExistingItem( GetBoard(), item ) ) { // Checking if it ever happens wxASSERT_MSG( false, "Item in the undo buffer does not exist" ); // Remove this non existent item aList->RemovePicker( ii ); ii++; // the current item was removed, ii points now the next item // decrement it because it will be incremented later not_found = true; continue; } } item->ClearFlags(); // see if we must rebuild ratsnets and pointers lists switch( item->Type() ) { case PCB_MODULE_T: deep_reBuild_ratsnest = true; // Pointers on pads can be invalid // Fall through case PCB_ZONE_AREA_T: case PCB_TRACE_T: case PCB_VIA_T: reBuild_ratsnest = true; break; case PCB_NETINFO_T: reBuild_ratsnest = true; deep_reBuild_ratsnest = true; break; default: break; } // It is possible that we are going to replace the selected item, so clear it SetCurItem( NULL ); switch( aList->GetPickedItemStatus( ii ) ) { case UR_CHANGED: /* Exchange old and new data for each item */ { BOARD_ITEM* image = (BOARD_ITEM*) aList->GetPickedItemLink( ii ); // Remove all pads/drawings/texts, as they become invalid // for the VIEW after SwapData() called for modules view->Remove( item ); connectivity->Remove( item ); SwapItemData( item, image ); // Update all pads/drawings/texts, as they become invalid // for the VIEW after SwapData() called for modules if( item->Type() == PCB_MODULE_T ) { MODULE* newModule = static_cast<MODULE*>( item ); newModule->RunOnChildren( std::bind( &BOARD_ITEM::ClearFlags, _1, EDA_ITEM_ALL_FLAGS )); } view->Add( item ); connectivity->Add( item ); item->ClearFlags(); } break; case UR_NEW: /* new items are deleted */ aList->SetPickedItemStatus( UR_DELETED, ii ); GetModel()->Remove( item ); view->Remove( item ); break; case UR_DELETED: /* deleted items are put in List, as new items */ aList->SetPickedItemStatus( UR_NEW, ii ); GetModel()->Add( item ); view->Add( item ); build_item_list = true; break; case UR_MOVED: item->Move( aRedoCommand ? aList->m_TransformPoint : -aList->m_TransformPoint ); view->Update( item, KIGFX::GEOMETRY ); connectivity->Update( item ); break; case UR_ROTATED: item->Rotate( aList->m_TransformPoint, aRedoCommand ? m_rotationAngle : -m_rotationAngle ); view->Update( item, KIGFX::GEOMETRY ); connectivity->Update( item ); break; case UR_ROTATED_CLOCKWISE: item->Rotate( aList->m_TransformPoint, aRedoCommand ? -m_rotationAngle : m_rotationAngle ); view->Update( item, KIGFX::GEOMETRY ); connectivity->Update( item ); break; case UR_FLIPPED: item->Flip( aList->m_TransformPoint ); view->Update( item, KIGFX::LAYERS ); connectivity->Update( item ); break; case UR_DRILLORIGIN: case UR_GRIDORIGIN: { BOARD_ITEM* image = (BOARD_ITEM*) aList->GetPickedItemLink( ii ); VECTOR2D origin = image->GetPosition(); image->SetPosition( item->GetPosition() ); if( aList->GetPickedItemStatus( ii ) == UR_DRILLORIGIN ) PCB_EDITOR_CONTROL::DoSetDrillOrigin( view, this, item, origin ); else PCBNEW_CONTROL::DoSetGridOrigin( view, this, item, origin ); } break; default: { wxLogDebug( wxT( "PutDataInPreviousState() error (unknown code %X)" ), aList->GetPickedItemStatus( ii ) ); } break; } } if( not_found ) wxMessageBox( _( "Incomplete undo/redo operation: some items not found" ) ); // Rebuild pointers and connectivity that can be changed. // connectivity can be rebuilt only in the board editor frame if( IsType( FRAME_PCB ) && ( reBuild_ratsnest || deep_reBuild_ratsnest ) ) { Compile_Ratsnest( NULL, false ); } GetBoard()->SanitizeNetcodes(); }
void PCB_EDIT_FRAME::PutDataInPreviousState( PICKED_ITEMS_LIST* aList, bool aRedoCommand, bool aRebuildRatsnet ) { BOARD_ITEM* item; bool not_found = false; bool reBuild_ratsnest = false; KIGFX::VIEW* view = GetGalCanvas()->GetView(); RN_DATA* ratsnest = GetBoard()->GetRatsnest(); // Undo in the reverse order of list creation: (this can allow stacked changes // like the same item can be changes and deleted in the same complex command bool build_item_list = true; // if true the list of existing items must be rebuilt for( int ii = aList->GetCount() - 1; ii >= 0 ; ii-- ) { item = (BOARD_ITEM*) aList->GetPickedItem( ii ); wxASSERT( item ); /* Test for existence of item on board. * It could be deleted, and no more on board: * - if a call to SaveCopyInUndoList was forgotten in Pcbnew * - in zones outlines, when a change in one zone merges this zone with an other * This test avoids a Pcbnew crash * Obviously, this test is not made for deleted items */ UNDO_REDO_T status = aList->GetPickedItemStatus( ii ); if( status != UR_DELETED ) { if( build_item_list ) // Build list of existing items, for integrity test TestForExistingItem( GetBoard(), NULL ); build_item_list = false; if( !TestForExistingItem( GetBoard(), item ) ) { // Remove this non existent item aList->RemovePicker( ii ); ii++; // the current item was removed, ii points now the next item // decrement it because it will be incremented later not_found = true; continue; } } item->ClearFlags(); // see if we must rebuild ratsnets and pointers lists switch( item->Type() ) { case PCB_MODULE_T: case PCB_ZONE_AREA_T: case PCB_TRACE_T: case PCB_VIA_T: reBuild_ratsnest = true; break; default: break; } switch( aList->GetPickedItemStatus( ii ) ) { case UR_CHANGED: /* Exchange old and new data for each item */ { BOARD_ITEM* image = (BOARD_ITEM*) aList->GetPickedItemLink( ii ); // Remove all pads/drawings/texts, as they become invalid // for the VIEW after SwapData() called for modules if( item->Type() == PCB_MODULE_T ) { MODULE* oldModule = static_cast<MODULE*>( item ); oldModule->RunOnChildren( boost::bind( &KIGFX::VIEW::Remove, view, _1 ) ); } ratsnest->Remove( item ); item->SwapData( image ); // Update all pads/drawings/texts, as they become invalid // for the VIEW after SwapData() called for modules if( item->Type() == PCB_MODULE_T ) { MODULE* newModule = static_cast<MODULE*>( item ); newModule->RunOnChildren( boost::bind( &KIGFX::VIEW::Add, view, _1 ) ); } ratsnest->Add( item ); item->ClearFlags( SELECTED ); item->ViewUpdate( KIGFX::VIEW_ITEM::LAYERS ); } break; case UR_NEW: /* new items are deleted */ aList->SetPickedItemStatus( UR_DELETED, ii ); GetBoard()->Remove( item ); if( item->Type() == PCB_MODULE_T ) { MODULE* module = static_cast<MODULE*>( item ); module->RunOnChildren( boost::bind( &KIGFX::VIEW::Remove, view, _1 ) ); } view->Remove( item ); item->ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY ); break; case UR_DELETED: /* deleted items are put in List, as new items */ aList->SetPickedItemStatus( UR_NEW, ii ); GetBoard()->Add( item ); if( item->Type() == PCB_MODULE_T ) { MODULE* module = static_cast<MODULE*>( item ); module->RunOnChildren( boost::bind( &KIGFX::VIEW::Add, view, _1) ); } view->Add( item ); item->ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY ); build_item_list = true; break; case UR_MOVED: item->Move( aRedoCommand ? aList->m_TransformPoint : -aList->m_TransformPoint ); item->ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY ); ratsnest->Update( item ); break; case UR_ROTATED: item->Rotate( aList->m_TransformPoint, aRedoCommand ? m_rotationAngle : -m_rotationAngle ); item->ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY ); ratsnest->Update( item ); break; case UR_ROTATED_CLOCKWISE: item->Rotate( aList->m_TransformPoint, aRedoCommand ? -m_rotationAngle : m_rotationAngle ); item->ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY ); ratsnest->Update( item ); break; case UR_FLIPPED: item->Flip( aList->m_TransformPoint ); item->ViewUpdate( KIGFX::VIEW_ITEM::LAYERS ); ratsnest->Update( item ); break; default: { wxString msg; msg.Printf( wxT( "PutDataInPreviousState() error (unknown code %X)" ), aList->GetPickedItemStatus( ii ) ); wxMessageBox( msg ); } break; } } if( not_found ) wxMessageBox( wxT( "Incomplete undo/redo operation: some items not found" ) ); // Rebuild pointers and ratsnest that can be changed. if( reBuild_ratsnest && aRebuildRatsnet ) { if( IsGalCanvasActive() ) ratsnest->Recalculate(); else Compile_Ratsnest( NULL, true ); } }
int DRAWING_TOOL::PlaceDXF( const TOOL_EVENT& aEvent ) { DIALOG_DXF_IMPORT dlg( m_frame ); int dlgResult = dlg.ShowModal(); const std::list<BOARD_ITEM*>& list = dlg.GetImportedItems(); if( dlgResult != wxID_OK || m_board->m_Modules == NULL || list.empty() ) return 0; VECTOR2I cursorPos = m_controls->GetCursorPosition(); VECTOR2I delta = cursorPos - (*list.begin())->GetPosition(); // Add a VIEW_GROUP that serves as a preview for the new item KIGFX::VIEW_GROUP preview( m_view ); // Build the undo list & add items to the current view std::list<BOARD_ITEM*>::const_iterator it, itEnd; for( it = list.begin(), itEnd = list.end(); it != itEnd; ++it ) { BOARD_ITEM* item = *it; BOARD_ITEM* converted = NULL; // Modules use different types for the same things, // so we need to convert imported items to appropriate classes. switch( item->Type() ) { case PCB_LINE_T: { if( m_editModules ) { converted = new EDGE_MODULE( m_board->m_Modules ); *static_cast<DRAWSEGMENT*>( converted ) = *static_cast<DRAWSEGMENT*>( item ); converted->Move( wxPoint( delta.x, delta.y ) ); preview.Add( converted ); delete item; } else { preview.Add( item ); } break; } case PCB_TEXT_T: { if( m_editModules ) { converted = new TEXTE_MODULE( m_board->m_Modules ); *static_cast<TEXTE_PCB*>( converted ) = *static_cast<TEXTE_PCB*>( item ); converted->Move( wxPoint( delta.x, delta.y ) ); preview.Add( converted ); delete item; } else { preview.Add( item ); } break; } default: assert( false ); // there is a type that is currently not handled here break; } } BOARD_ITEM* firstItem = static_cast<BOARD_ITEM*>( *preview.Begin() ); m_view->Add( &preview ); m_toolMgr->RunAction( COMMON_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(); if( evt->IsMotion() ) { delta = cursorPos - firstItem->GetPosition(); for( KIGFX::VIEW_GROUP::iter it = preview.Begin(), end = preview.End(); it != end; ++it ) static_cast<BOARD_ITEM*>( *it )->Move( wxPoint( delta.x, delta.y ) ); preview.ViewUpdate(); } else if( evt->Category() == TC_COMMAND ) { if( evt->IsAction( &COMMON_ACTIONS::rotate ) ) { for( KIGFX::VIEW_GROUP::iter it = preview.Begin(), end = preview.End(); it != end; ++it ) static_cast<BOARD_ITEM*>( *it )->Rotate( wxPoint( cursorPos.x, cursorPos.y ), m_frame->GetRotationAngle() ); preview.ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY ); } else if( evt->IsAction( &COMMON_ACTIONS::flip ) ) { for( KIGFX::VIEW_GROUP::iter it = preview.Begin(), end = preview.End(); it != end; ++it ) static_cast<BOARD_ITEM*>( *it )->Flip( wxPoint( cursorPos.x, cursorPos.y ) ); preview.ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY ); } else if( evt->IsCancel() || evt->IsActivate() ) { preview.FreeItems(); break; } } else if( evt->IsClick( BUT_LEFT ) ) { // Place the drawing if( m_editModules ) { m_frame->SaveCopyInUndoList( m_board->m_Modules, UR_MODEDIT ); m_board->m_Modules->SetLastEditTime(); for( KIGFX::VIEW_GROUP::iter it = preview.Begin(), end = preview.End(); it != end; ++it ) { BOARD_ITEM* item = static_cast<BOARD_ITEM*>( *it ); m_board->m_Modules->Add( item ); switch( item->Type() ) { case PCB_MODULE_TEXT_T: static_cast<TEXTE_MODULE*>( item )->SetLocalCoord(); break; case PCB_MODULE_EDGE_T: static_cast<EDGE_MODULE*>( item )->SetLocalCoord(); break; default: assert( false ); break; } m_view->Add( item ); } } else { PICKED_ITEMS_LIST picklist; for( KIGFX::VIEW_GROUP::iter it = preview.Begin(), end = preview.End(); it != end; ++it ) { BOARD_ITEM* item = static_cast<BOARD_ITEM*>( *it ); m_board->Add( item ); ITEM_PICKER itemWrapper( item, UR_NEW ); picklist.PushItem( itemWrapper ); m_view->Add( item ); } m_frame->SaveCopyInUndoList( picklist, UR_NEW ); } m_frame->OnModify(); break; } } preview.Clear(); m_controls->ShowCursor( false ); m_controls->SetSnapping( false ); m_controls->SetAutoPan( false ); m_controls->CaptureCursor( false ); m_view->Remove( &preview ); return 0; }
/** * Function PutDataInPreviousState * Used in undo or redo command. * Put data pointed by List in the previous state, i.e. the state memorised by List * @param aList = a PICKED_ITEMS_LIST pointer to the list of items to undo/redo * @param aRedoCommand = a bool: true for redo, false for undo * @param aRebuildRatsnet = a bool: true to rebuid ratsnet (normal use, and default), false * to just retrieve las state (used in abort commands that do not need to rebuild ratsnest) */ void PCB_EDIT_FRAME::PutDataInPreviousState( PICKED_ITEMS_LIST* aList, bool aRedoCommand, bool aRebuildRatsnet ) { BOARD_ITEM* item; bool not_found = false; bool reBuild_ratsnest = false; // Undo in the reverse order of list creation: (this can allow stacked changes // like the same item can be changes and deleted in the same complex command bool build_item_list = true; // if true the list of esiting items must be rebuilt for( int ii = aList->GetCount()-1; ii >= 0 ; ii-- ) { item = (BOARD_ITEM*) aList->GetPickedItem( ii ); wxASSERT( item ); /* Test for existence of item on board. * It could be deleted, and no more on board: * - if a call to SaveCopyInUndoList was forgotten in Pcbnew * - in zones outlines, when a change in one zone merges this zone with an other * This test avoids a Pcbnew crash * Obviouly, this test is not made for deleted items */ UNDO_REDO_T status = aList->GetPickedItemStatus( ii ); if( status != UR_DELETED ) { if( build_item_list ) // Build list of existing items, for integrity test TestForExistingItem( GetBoard(), NULL ); build_item_list = false; if( !TestForExistingItem( GetBoard(), item ) ) { // Remove this non existant item aList->RemovePicker( ii ); ii++; // the current item was removed, ii points now the next item // decrement it because it will be incremented later not_found = true; continue; } } item->ClearFlags(); // see if we must rebuild ratsnets and pointers lists switch( item->Type() ) { case PCB_MODULE_T: case PCB_ZONE_AREA_T: case PCB_TRACE_T: case PCB_VIA_T: reBuild_ratsnest = true; break; default: break; } switch( aList->GetPickedItemStatus( ii ) ) { case UR_CHANGED: /* Exchange old and new data for each item */ { BOARD_ITEM* image = (BOARD_ITEM*) aList->GetPickedItemLink( ii ); SwapData( item, image ); } break; case UR_NEW: /* new items are deleted */ aList->SetPickedItemStatus( UR_DELETED, ii ); GetBoard()->Remove( item ); break; case UR_DELETED: /* deleted items are put in List, as new items */ aList->SetPickedItemStatus( UR_NEW, ii ); GetBoard()->Add( item ); build_item_list = true; break; case UR_MOVED: item->Move( aRedoCommand ? aList->m_TransformPoint : -aList->m_TransformPoint ); break; case UR_ROTATED: item->Rotate( aList->m_TransformPoint, aRedoCommand ? 900 : -900 ); break; case UR_ROTATED_CLOCKWISE: item->Rotate( aList->m_TransformPoint, aRedoCommand ? -900 : 900 ); break; case UR_FLIPPED: item->Flip( aList->m_TransformPoint ); break; default: { wxString msg; msg.Printf( wxT( "PutDataInPreviousState() error (unknown code %X)" ), aList->GetPickedItemStatus( ii ) ); wxMessageBox( msg ); } break; } } if( not_found ) wxMessageBox( wxT( "Incomplete undo/redo operation: some items not found" ) ); // Rebuild pointers and rastnest that can be changed. if( reBuild_ratsnest && aRebuildRatsnet ) Compile_Ratsnest( NULL, true ); }