int EDIT_TOOL::Remove( const TOOL_EVENT& aEvent ) { const SELECTION& selection = m_selectionTool->GetSelection(); if( !hoverSelection( selection ) ) return 0; // Get a copy of the selected items set PICKED_ITEMS_LIST selectedItems = selection.items; PCB_BASE_FRAME* editFrame = getEditFrame<PCB_BASE_FRAME>(); // As we are about to remove items, they have to be removed from the selection first m_toolMgr->RunAction( COMMON_ACTIONS::selectionClear, true ); // Save them for( unsigned int i = 0; i < selectedItems.GetCount(); ++i ) selectedItems.SetPickedItemStatus( UR_DELETED, i ); editFrame->OnModify(); editFrame->SaveCopyInUndoList( selectedItems, UR_DELETED ); // And now remove for( unsigned int i = 0; i < selectedItems.GetCount(); ++i ) remove( static_cast<BOARD_ITEM*>( selectedItems.GetPickedItem( i ) ) ); getModel<BOARD>()->GetRatsnest()->Recalculate(); return 0; }
void POINT_EDITOR::removeCorner( EDIT_POINT* aPoint ) { EDA_ITEM* item = m_editPoints->GetParent(); if( item->Type() == PCB_ZONE_AREA_T ) { const SELECTION& selection = m_selectionTool->GetSelection(); PCB_BASE_FRAME* frame = getEditFrame<PCB_BASE_FRAME>(); ZONE_CONTAINER* zone = static_cast<ZONE_CONTAINER*>( item ); CPolyLine* outline = zone->Outline(); for( int i = 0; i < outline->GetCornersCount(); ++i ) { if( VECTOR2I( outline->GetPos( i ) ) == aPoint->GetPosition() ) { frame->OnModify(); frame->SaveCopyInUndoList( selection.items, UR_CHANGED ); outline->DeleteCorner( i ); setEditedPoint( NULL ); break; } } } }
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; }
int EDIT_TOOL::Flip( TOOL_EVENT& aEvent ) { const SELECTION& selection = m_selectionTool->GetSelection(); PCB_BASE_FRAME* editFrame = getEditFrame<PCB_BASE_FRAME>(); // Shall the selection be cleared at the end? bool unselect = selection.Empty(); if( !makeSelection( selection ) || m_selectionTool->CheckLock() ) { setTransitions(); return 0; } wxPoint flipPoint = getModificationPoint( selection ); if( !m_dragging ) // If it is being dragged, then it is already saved with UR_CHANGED flag { editFrame->OnModify(); editFrame->SaveCopyInUndoList( selection.items, UR_FLIPPED, flipPoint ); } for( unsigned int i = 0; i < selection.items.GetCount(); ++i ) { BOARD_ITEM* item = selection.Item<BOARD_ITEM>( i ); item->Flip( flipPoint ); if( !m_dragging ) item->ViewUpdate( KIGFX::VIEW_ITEM::LAYERS ); } updateRatsnest( m_dragging ); // Update dragging offset (distance between cursor and the first dragged item) m_offset = static_cast<BOARD_ITEM*>( selection.items.GetPickedItem( 0 ) )->GetPosition() - flipPoint; 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 ); setTransitions(); return 0; }
void DIALOG_COPPER_ZONE::ExportSetupToOtherCopperZones( wxCommandEvent& event ) { if( !AcceptOptions( true, true ) ) return; // Export settings ( but layer and netcode ) to others copper zones BOARD* pcb = m_Parent->GetBoard(); for( int ii = 0; ii < pcb->GetAreaCount(); ii++ ) { ZONE_CONTAINER* zone = pcb->GetArea( ii ); // Cannot export settings from a copper zone // to a zone keepout: if( zone->GetIsKeepout() ) continue; m_settings.ExportSetting( *zone, false ); // false = partial export m_Parent->OnModify(); } m_OnExitCode = ZONE_EXPORT_VALUES; // values are exported to others zones }
/* Update the parameters for the component being edited. */ void DIALOG_GLOBAL_PADS_EDITION::PadPropertiesAccept( wxCommandEvent& event ) { int returncode = 0; switch( event.GetId() ) { case ID_CHANGE_ID_MODULES: returncode = 1; // Fall through case ID_CHANGE_CURRENT_MODULE: m_Pad_Shape_Filter = m_Pad_Shape_Filter_CB->GetValue(); m_Pad_Layer_Filter = m_Pad_Layer_Filter_CB->GetValue(); m_Pad_Orient_Filter = m_Pad_Orient_Filter_CB->GetValue(); EndModal( returncode ); break; } m_parent->OnModify(); }
int EDIT_TOOL::CreateArray( const TOOL_EVENT& aEvent ) { // first, check if we have a selection, or try to get one SELECTION_TOOL* selTool = m_toolMgr->GetTool<SELECTION_TOOL>(); const SELECTION& selection = selTool->GetSelection(); // pick up items under the cursor if needed if( !hoverSelection( selection ) ) return 0; // we have a selection to work on now, so start the tool process PCB_BASE_FRAME* editFrame = getEditFrame<PCB_BASE_FRAME>(); editFrame->OnModify(); GAL_ARRAY_CREATOR array_creator( *editFrame, m_editModules, getModel<BOARD>()->GetRatsnest(), selection ); array_creator.Invoke(); return 0; }
int EDIT_TOOL::CreateArray( const TOOL_EVENT& aEvent ) { // first, check if we have a selection, or try to get one SELECTION_TOOL* selTool = m_toolMgr->GetTool<SELECTION_TOOL>(); const SELECTION& selection = selTool->GetSelection(); // Be sure that there is at least one item that we can modify if( !hoverSelection( selection ) ) return 0; bool originalItemsModified = false; // we have a selection to work on now, so start the tool process PCB_BASE_FRAME* editFrame = getEditFrame<PCB_BASE_FRAME>(); editFrame->OnModify(); if( m_editModules ) { // Module editors do their undo point upfront for the whole module editFrame->SaveCopyInUndoList( editFrame->GetBoard()->m_Modules, UR_MODEDIT ); } else { // We may also change the original item editFrame->SaveCopyInUndoList( selection.items, UR_CHANGED ); } DIALOG_CREATE_ARRAY::ARRAY_OPTIONS* array_opts = NULL; VECTOR2I rp = selection.GetCenter(); const wxPoint rotPoint( rp.x, rp.y ); DIALOG_CREATE_ARRAY dialog( editFrame, rotPoint, &array_opts ); int ret = dialog.ShowModal(); if( ret == wxID_OK && array_opts != NULL ) { PICKED_ITEMS_LIST newItemList; for( int i = 0; i < selection.Size(); ++i ) { BOARD_ITEM* item = selection.Item<BOARD_ITEM>( i ); if( !item ) continue; wxString cachedString; if( item->Type() == PCB_MODULE_T ) { cachedString = static_cast<MODULE*>( item )->GetReferencePrefix(); } else if( EDA_TEXT* text = dynamic_cast<EDA_TEXT*>( item ) ) { // Copy the text (not just take a reference cachedString = text->GetText(); } // iterate across the array, laying out the item at the // correct position const unsigned nPoints = array_opts->GetArraySize(); for( unsigned ptN = 0; ptN < nPoints; ++ptN ) { BOARD_ITEM* newItem = NULL; if( ptN == 0 ) newItem = item; else { // if renumbering, no need to increment const bool increment = !array_opts->ShouldRenumberItems(); // Some items cannot be duplicated // i.e. the ref and value fields of a footprint or zones // therefore newItem can be null if( m_editModules ) newItem = editFrame->GetBoard()->m_Modules->DuplicateAndAddItem( item, increment ); else { #if 0 // @TODO: see if we allow zone duplication here // Duplicate zones is especially tricky (overlaping zones must be merged) // so zones are not duplicated if( item->Type() == PCB_ZONE_AREA_T ) newItem = NULL; else #endif newItem = editFrame->GetBoard()->DuplicateAndAddItem( item, increment ); } if( newItem ) { array_opts->TransformItem( ptN, newItem, rotPoint ); m_toolMgr->RunAction( COMMON_ACTIONS::unselectItem, true, newItem ); newItemList.PushItem( newItem ); if( newItem->Type() == PCB_MODULE_T) { static_cast<MODULE*>( newItem )->RunOnChildren( boost::bind( &KIGFX::VIEW::Add, getView(), _1 ) ); } editFrame->GetGalCanvas()->GetView()->Add( newItem ); getModel<BOARD>()->GetRatsnest()->Update( newItem ); } } // set the number if needed: if( newItem && array_opts->ShouldRenumberItems() ) { switch( newItem->Type() ) { case PCB_PAD_T: { const wxString padName = array_opts->GetItemNumber( ptN ); static_cast<D_PAD*>( newItem )->SetPadName( padName ); originalItemsModified = true; break; } case PCB_MODULE_T: { const wxString moduleName = array_opts->GetItemNumber( ptN ); MODULE* module = static_cast<MODULE*>( newItem ); module->SetReference( cachedString + moduleName ); originalItemsModified = true; break; } case PCB_MODULE_TEXT_T: case PCB_TEXT_T: { EDA_TEXT* text = dynamic_cast<EDA_TEXT*>( newItem ); if( text ) text->SetText( array_opts->InterpolateNumberIntoString( ptN, cachedString ) ); originalItemsModified = true; break; } default: // no renumbering of other items break; } } } } if( !m_editModules ) { if( originalItemsModified ) { // Update the appearance of the original items selection.group->ItemsViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY ); } // Add all items as a single undo point for PCB editors // TODO: Can this be merged into the previous undo point (where // we saved the original items) editFrame->SaveCopyInUndoList( newItemList, UR_NEW ); } } getModel<BOARD>()->GetRatsnest()->Recalculate(); return 0; }
int EDIT_TOOL::Duplicate( const TOOL_EVENT& aEvent ) { bool increment = aEvent.IsAction( &COMMON_ACTIONS::duplicateIncrement ); // first, check if we have a selection, or try to get one SELECTION_TOOL* selTool = m_toolMgr->GetTool<SELECTION_TOOL>(); const SELECTION& selection = selTool->GetSelection(); // Be sure that there is at least one item that we can modify if( !hoverSelection( selection ) ) return 0; // we have a selection to work on now, so start the tool process PCB_BASE_FRAME* editFrame = getEditFrame<PCB_BASE_FRAME>(); editFrame->OnModify(); // prevent other tools making undo points while the duplicate is going on // so that if you cancel, you don't get a duplicate object hiding over // the original incUndoInhibit(); if( m_editModules ) editFrame->SaveCopyInUndoList( editFrame->GetBoard()->m_Modules, UR_MODEDIT ); std::vector<BOARD_ITEM*> old_items; for( int i = 0; i < selection.Size(); ++i ) { BOARD_ITEM* item = selection.Item<BOARD_ITEM>( i ); if( item ) old_items.push_back( item ); } for( unsigned i = 0; i < old_items.size(); ++i ) { BOARD_ITEM* item = old_items[i]; // Unselect the item, so we won't pick it up again // Do this first, so a single-item duplicate will correctly call // SetCurItem and show the item properties m_toolMgr->RunAction( COMMON_ACTIONS::unselectItem, true, item ); BOARD_ITEM* new_item = NULL; if( m_editModules ) new_item = editFrame->GetBoard()->m_Modules->DuplicateAndAddItem( item, increment ); else { #if 0 // @TODO: see if we allow zone duplication here // Duplicate zones is especially tricky (overlaping zones must be merged) // so zones are not duplicated if( item->Type() != PCB_ZONE_AREA_T ) #endif new_item = editFrame->GetBoard()->DuplicateAndAddItem( item, increment ); } if( new_item ) { if( new_item->Type() == PCB_MODULE_T ) { static_cast<MODULE*>( new_item )->RunOnChildren( boost::bind( &KIGFX::VIEW::Add, getView(), _1 ) ); } editFrame->GetGalCanvas()->GetView()->Add( new_item ); // Select the new item, so we can pick it up m_toolMgr->RunAction( COMMON_ACTIONS::selectItem, true, new_item ); } } // record the new items as added if( !m_editModules ) editFrame->SaveCopyInUndoList( selection.items, UR_NEW ); editFrame->DisplayToolMsg( wxString::Format( _( "Duplicated %d item(s)" ), (int) old_items.size() ) ); // pick up the selected item(s) and start moving // this works well for "dropping" copies around TOOL_EVENT evt = COMMON_ACTIONS::editActivate.MakeEvent(); Main( evt ); // and re-enable undos decUndoInhibit(); return 0; }
void DIALOG_PAD_PROPERTIES::PadPropertiesAccept( wxCommandEvent& event ) { if( !padValuesOK() ) return; bool rastnestIsChanged = false; int isign = m_isFlipped ? -1 : 1; transferDataToPad( m_padMaster ); // m_padMaster is a pattern: ensure there is no net for this pad: m_padMaster->SetNetCode( NETINFO_LIST::UNCONNECTED ); if( m_currentPad ) // Set current Pad parameters { wxSize size; MODULE* module = m_currentPad->GetParent(); m_parent->SaveCopyInUndoList( module, UR_CHANGED ); module->SetLastEditTime(); // redraw the area where the pad was, without pad (delete pad on screen) m_currentPad->SetFlags( DO_NOT_DRAW ); m_parent->GetCanvas()->RefreshDrawingRect( m_currentPad->GetBoundingBox() ); m_currentPad->ClearFlags( DO_NOT_DRAW ); // Update values m_currentPad->SetShape( m_padMaster->GetShape() ); m_currentPad->SetAttribute( m_padMaster->GetAttribute() ); if( m_currentPad->GetPosition() != m_padMaster->GetPosition() ) { m_currentPad->SetPosition( m_padMaster->GetPosition() ); rastnestIsChanged = true; } // compute the pos 0 value, i.e. pad position for module with orientation = 0 // i.e. relative to module origin (module position) wxPoint pt = m_currentPad->GetPosition() - module->GetPosition(); RotatePoint( &pt, -module->GetOrientation() ); m_currentPad->SetPos0( pt ); m_currentPad->SetOrientation( m_padMaster->GetOrientation() * isign + module->GetOrientation() ); m_currentPad->SetSize( m_padMaster->GetSize() ); size = m_padMaster->GetDelta(); size.y *= isign; m_currentPad->SetDelta( size ); m_currentPad->SetDrillSize( m_padMaster->GetDrillSize() ); m_currentPad->SetDrillShape( m_padMaster->GetDrillShape() ); wxPoint offset = m_padMaster->GetOffset(); offset.y *= isign; m_currentPad->SetOffset( offset ); m_currentPad->SetPadToDieLength( m_padMaster->GetPadToDieLength() ); if( m_currentPad->GetLayerSet() != m_padMaster->GetLayerSet() ) { rastnestIsChanged = true; m_currentPad->SetLayerSet( m_padMaster->GetLayerSet() ); } if( m_isFlipped ) m_currentPad->SetLayerSet( FlipLayerMask( m_currentPad->GetLayerSet() ) ); m_currentPad->SetPadName( m_padMaster->GetPadName() ); wxString padNetname; // For PAD_HOLE_NOT_PLATED, ensure there is no net name selected if( m_padMaster->GetAttribute() != PAD_HOLE_NOT_PLATED ) padNetname = m_PadNetNameCtrl->GetValue(); if( m_currentPad->GetNetname() != padNetname ) { const NETINFO_ITEM* netinfo = m_board->FindNet( padNetname ); if( !padNetname.IsEmpty() && netinfo == NULL ) { DisplayError( NULL, _( "Unknown netname, netname not changed" ) ); } else { rastnestIsChanged = true; m_currentPad->SetNetCode( netinfo->GetNet() ); } } m_currentPad->SetLocalClearance( m_padMaster->GetLocalClearance() ); m_currentPad->SetLocalSolderMaskMargin( m_padMaster->GetLocalSolderMaskMargin() ); m_currentPad->SetLocalSolderPasteMargin( m_padMaster->GetLocalSolderPasteMargin() ); m_currentPad->SetLocalSolderPasteMarginRatio( m_padMaster->GetLocalSolderPasteMarginRatio() ); m_currentPad->SetZoneConnection( m_padMaster->GetZoneConnection() ); m_currentPad->SetThermalWidth( m_padMaster->GetThermalWidth() ); m_currentPad->SetThermalGap( m_padMaster->GetThermalGap() ); module->CalculateBoundingBox(); m_parent->SetMsgPanel( m_currentPad ); // redraw the area where the pad was m_parent->GetCanvas()->RefreshDrawingRect( m_currentPad->GetBoundingBox() ); m_parent->OnModify(); } EndModal( wxID_OK ); if( rastnestIsChanged ) // The net ratsnest must be recalculated m_board->m_Status_Pcb = 0; }
void POINT_EDITOR::addCorner( const VECTOR2I& aBreakPoint ) { EDA_ITEM* item = m_editPoints->GetParent(); const SELECTION& selection = m_selectionTool->GetSelection(); if( item->Type() == PCB_ZONE_AREA_T ) { getEditFrame<PCB_BASE_FRAME>()->OnModify(); getEditFrame<PCB_BASE_FRAME>()->SaveCopyInUndoList( selection.items, UR_CHANGED ); ZONE_CONTAINER* zone = static_cast<ZONE_CONTAINER*>( item ); CPolyLine* outline = zone->Outline(); // Handle the last segment, so other segments can be easily handled in a loop unsigned int nearestIdx = outline->GetCornersCount() - 1, nextNearestIdx = 0; SEG side( VECTOR2I( outline->GetPos( nearestIdx ) ), VECTOR2I( outline->GetPos( nextNearestIdx ) ) ); unsigned int nearestDist = side.Distance( aBreakPoint ); for( int i = 0; i < outline->GetCornersCount() - 1; ++i ) { side = SEG( VECTOR2I( outline->GetPos( i ) ), VECTOR2I( outline->GetPos( i + 1 ) ) ); unsigned int distance = side.Distance( aBreakPoint ); if( distance < nearestDist ) { nearestDist = distance; nearestIdx = i; nextNearestIdx = i + 1; } } // Find the point on the closest segment VECTOR2I sideOrigin( outline->GetPos( nearestIdx ) ); VECTOR2I sideEnd( outline->GetPos( nextNearestIdx ) ); SEG nearestSide( sideOrigin, sideEnd ); VECTOR2I nearestPoint = nearestSide.NearestPoint( aBreakPoint ); // Do not add points that have the same coordinates as ones that already belong to polygon // instead, add a point in the middle of the side if( nearestPoint == sideOrigin || nearestPoint == sideEnd ) nearestPoint = ( sideOrigin + sideEnd ) / 2; outline->InsertCorner( nearestIdx, nearestPoint.x, nearestPoint.y ); } else if( item->Type() == PCB_LINE_T || item->Type() == PCB_MODULE_EDGE_T ) { bool moduleEdge = item->Type() == PCB_MODULE_EDGE_T; PCB_BASE_FRAME* frame = getEditFrame<PCB_BASE_FRAME>(); frame->OnModify(); if( moduleEdge ) frame->SaveCopyInUndoList( getModel<BOARD>()->m_Modules, UR_MODEDIT ); else frame->SaveCopyInUndoList( selection.items, UR_CHANGED ); DRAWSEGMENT* segment = static_cast<DRAWSEGMENT*>( item ); if( segment->GetShape() == S_SEGMENT ) { SEG seg( segment->GetStart(), segment->GetEnd() ); VECTOR2I nearestPoint = seg.NearestPoint( aBreakPoint ); // Move the end of the line to the break point.. segment->SetEnd( wxPoint( nearestPoint.x, nearestPoint.y ) ); // and add another one starting from the break point DRAWSEGMENT* newSegment; if( moduleEdge ) { EDGE_MODULE* edge = static_cast<EDGE_MODULE*>( segment ); assert( segment->GetParent()->Type() == PCB_MODULE_T ); newSegment = new EDGE_MODULE( *edge ); edge->SetLocalCoord(); } else { newSegment = new DRAWSEGMENT( *segment ); } newSegment->ClearSelected(); newSegment->SetStart( wxPoint( nearestPoint.x, nearestPoint.y ) ); newSegment->SetEnd( wxPoint( seg.B.x, seg.B.y ) ); if( moduleEdge ) { static_cast<EDGE_MODULE*>( newSegment )->SetLocalCoord(); getModel<BOARD>()->m_Modules->Add( newSegment ); } else { getModel<BOARD>()->Add( newSegment ); } getView()->Add( newSegment ); } } }
void DialogEditModuleText::OnOkClick( wxCommandEvent& event ) { wxString msg; if ( m_module) m_parent->SaveCopyInUndoList( m_module, UR_CHANGED ); #ifndef USE_WX_OVERLAY if( m_dc ) //Erase old text on screen { m_currentText->Draw( m_parent->GetCanvas(), m_dc, GR_XOR, (m_currentText->IsMoving()) ? MoveVector : wxPoint( 0, 0 ) ); } #endif m_currentText->SetText( m_Name->GetValue() ); m_currentText->SetItalic( m_Style->GetSelection() == 1 ); wxPoint tmp; msg = m_TxtPosCtrlX->GetValue(); tmp.x = ValueFromString( g_UserUnit, msg ); msg = m_TxtPosCtrlY->GetValue(); tmp.y = ValueFromString( g_UserUnit, msg ); m_currentText->SetPos0( tmp ); wxSize textSize( wxSize( ValueFromString( g_UserUnit, m_TxtSizeCtrlX->GetValue() ), ValueFromString( g_UserUnit, m_TxtSizeCtrlY->GetValue() ) ) ); // Test for a reasonnable size: if( textSize.x < TEXTS_MIN_SIZE ) textSize.x = TEXTS_MIN_SIZE; if( textSize.y < TEXTS_MIN_SIZE ) textSize.y = TEXTS_MIN_SIZE; m_currentText->SetSize( textSize ), msg = m_TxtWidthCtlr->GetValue(); int width = ValueFromString( g_UserUnit, msg ); // Test for a reasonnable width: if( width <= 1 ) width = 1; int maxthickness = Clamp_Text_PenSize(width, m_currentText->GetSize() ); if( width > maxthickness ) { DisplayError( NULL, _( "The text thickness is too large for the text size. It will be clamped" ) ); width = maxthickness; } m_currentText->SetThickness( width ); m_currentText->SetVisible( m_Show->GetSelection() == 0 ); int text_orient = (m_Orient->GetSelection() == 0) ? 0 : 900; m_currentText->SetOrientation( text_orient ); m_currentText->SetDrawCoord(); #ifndef USE_WX_OVERLAY if( m_dc ) // Display new text { m_currentText->Draw( m_parent->GetCanvas(), m_dc, GR_XOR, (m_currentText->IsMoving()) ? MoveVector : wxPoint( 0, 0 ) ); } #else m_parent->Refresh(); #endif m_parent->OnModify(); if( m_module ) m_module->SetLastEditTime(); EndModal(1); }
void BOARD_COMMIT::Push( const wxString& aMessage, bool aCreateUndoEntry, bool aSetDirtyBit ) { // Objects potentially interested in changes: PICKED_ITEMS_LIST undoList; KIGFX::VIEW* view = m_toolMgr->GetView(); BOARD* board = (BOARD*) m_toolMgr->GetModel(); PCB_BASE_FRAME* frame = (PCB_BASE_FRAME*) m_toolMgr->GetEditFrame(); auto connectivity = board->GetConnectivity(); std::set<EDA_ITEM*> savedModules; std::vector<BOARD_ITEM*> itemsToDeselect; if( Empty() ) return; for( COMMIT_LINE& ent : m_changes ) { int changeType = ent.m_type & CHT_TYPE; int changeFlags = ent.m_type & CHT_FLAGS; BOARD_ITEM* boardItem = static_cast<BOARD_ITEM*>( ent.m_item ); // Module items need to be saved in the undo buffer before modification if( m_editModules ) { // Be sure that we are storing a module if( ent.m_item->Type() != PCB_MODULE_T ) ent.m_item = ent.m_item->GetParent(); // We have not saved the module yet, so let's create an entry if( savedModules.count( ent.m_item ) == 0 ) { if( !ent.m_copy ) { wxASSERT( changeType != CHT_MODIFY ); // too late to make a copy.. ent.m_copy = ent.m_item->Clone(); } wxASSERT( ent.m_item->Type() == PCB_MODULE_T ); wxASSERT( ent.m_copy->Type() == PCB_MODULE_T ); if( aCreateUndoEntry ) { ITEM_PICKER itemWrapper( ent.m_item, UR_CHANGED ); itemWrapper.SetLink( ent.m_copy ); undoList.PushItem( itemWrapper ); frame->SaveCopyInUndoList( undoList, UR_CHANGED ); } savedModules.insert( ent.m_item ); static_cast<MODULE*>( ent.m_item )->SetLastEditTime(); } } switch( changeType ) { case CHT_ADD: { if( !m_editModules ) { if( aCreateUndoEntry ) { undoList.PushItem( ITEM_PICKER( boardItem, UR_NEW ) ); } if( !( changeFlags & CHT_DONE ) ) board->Add( boardItem ); // handles connectivity } else { // modules inside modules are not supported yet wxASSERT( boardItem->Type() != PCB_MODULE_T ); boardItem->SetParent( board->m_Modules.GetFirst() ); if( !( changeFlags & CHT_DONE ) ) board->m_Modules->Add( boardItem ); } view->Add( boardItem ); break; } case CHT_REMOVE: { if( !m_editModules && aCreateUndoEntry ) undoList.PushItem( ITEM_PICKER( boardItem, UR_DELETED ) ); switch( boardItem->Type() ) { // Module items case PCB_PAD_T: case PCB_MODULE_EDGE_T: case PCB_MODULE_TEXT_T: // This level can only handle module items when editing modules if( !m_editModules ) break; if( boardItem->Type() == PCB_MODULE_TEXT_T ) { TEXTE_MODULE* text = static_cast<TEXTE_MODULE*>( boardItem ); // don't allow deletion of Reference or Value if( text->GetType() != TEXTE_MODULE::TEXT_is_DIVERS ) break; } view->Remove( boardItem ); if( !( changeFlags & CHT_DONE ) ) { MODULE* module = static_cast<MODULE*>( boardItem->GetParent() ); wxASSERT( module && module->Type() == PCB_MODULE_T ); module->Delete( boardItem ); } board->m_Status_Pcb = 0; // it is done in the legacy view (ratsnest perhaps?) break; // Board items case PCB_LINE_T: // a segment not on copper layers case PCB_TEXT_T: // a text on a layer case PCB_TRACE_T: // a track segment (segment on a copper layer) case PCB_VIA_T: // a via (like track segment on a copper layer) case PCB_DIMENSION_T: // a dimension (graphic item) case PCB_TARGET_T: // a target (graphic item) case PCB_MARKER_T: // a marker used to show something case PCB_ZONE_AREA_T: itemsToDeselect.push_back( boardItem ); view->Remove( boardItem ); if( !( changeFlags & CHT_DONE ) ) board->Remove( boardItem ); break; case PCB_MODULE_T: { itemsToDeselect.push_back( boardItem ); // There are no modules inside a module yet wxASSERT( !m_editModules ); MODULE* module = static_cast<MODULE*>( boardItem ); view->Remove( module ); module->ClearFlags(); if( !( changeFlags & CHT_DONE ) ) board->Remove( module ); // handles connectivity // Clear flags to indicate, that the ratsnest, list of nets & pads are not valid anymore board->m_Status_Pcb = 0; } break; default: // other types do not need to (or should not) be handled wxASSERT( false ); break; } break; } case CHT_MODIFY: { if( !m_editModules && aCreateUndoEntry ) { ITEM_PICKER itemWrapper( boardItem, UR_CHANGED ); wxASSERT( ent.m_copy ); itemWrapper.SetLink( ent.m_copy ); undoList.PushItem( itemWrapper ); } if( ent.m_copy ) connectivity->MarkItemNetAsDirty( static_cast<BOARD_ITEM*>( ent.m_copy ) ); connectivity->Update( boardItem ); view->Update( boardItem ); // if no undo entry is needed, the copy would create a memory leak if( !aCreateUndoEntry ) delete ent.m_copy; break; } default: wxASSERT( false ); break; } } // Removing an item should trigger the unselect action // but only after all items are removed otherwise we can get // flickering depending on the system if( itemsToDeselect.size() > 0 ) m_toolMgr->RunAction( PCB_ACTIONS::unselectItems, true, &itemsToDeselect ); if( !m_editModules && aCreateUndoEntry ) frame->SaveCopyInUndoList( undoList, UR_UNSPECIFIED ); if( TOOL_MANAGER* toolMgr = frame->GetToolManager() ) toolMgr->PostEvent( { TC_MESSAGE, TA_MODEL_CHANGE, AS_GLOBAL } ); if ( !m_editModules ) { auto panel = static_cast<PCB_DRAW_PANEL_GAL*>( frame->GetGalCanvas() ); connectivity->RecalculateRatsnest(); connectivity->ClearDynamicRatsnest(); panel->RedrawRatsnest(); } if( aSetDirtyBit ) frame->OnModify(); frame->UpdateMsgPanel(); clear(); }
void BOARD_COMMIT::Push( const wxString& aMessage ) { // Objects potentially interested in changes: PICKED_ITEMS_LIST undoList; KIGFX::VIEW* view = m_toolMgr->GetView(); BOARD* board = (BOARD*) m_toolMgr->GetModel(); PCB_BASE_FRAME* frame = (PCB_BASE_FRAME*) m_toolMgr->GetEditFrame(); RN_DATA* ratsnest = board->GetRatsnest(); std::set<EDA_ITEM*> savedModules; if( Empty() ) return; for( COMMIT_LINE& ent : m_changes ) { int changeType = ent.m_type & CHT_TYPE; int changeFlags = ent.m_type & CHT_FLAGS; BOARD_ITEM* boardItem = static_cast<BOARD_ITEM*>( ent.m_item ); // Module items need to be saved in the undo buffer before modification if( m_editModules ) { // Be sure that we are storing a module if( ent.m_item->Type() != PCB_MODULE_T ) ent.m_item = ent.m_item->GetParent(); // We have not saved the module yet, so let's create an entry if( savedModules.count( ent.m_item ) == 0 ) { if( !ent.m_copy ) { assert( changeType != CHT_MODIFY ); // too late to make a copy.. ent.m_copy = ent.m_item->Clone(); } assert( ent.m_item->Type() == PCB_MODULE_T ); assert( ent.m_copy->Type() == PCB_MODULE_T ); ITEM_PICKER itemWrapper( ent.m_item, UR_CHANGED ); itemWrapper.SetLink( ent.m_copy ); undoList.PushItem( itemWrapper ); frame->SaveCopyInUndoList( undoList, UR_CHANGED ); savedModules.insert( ent.m_item ); static_cast<MODULE*>( ent.m_item )->SetLastEditTime(); } } switch( changeType ) { case CHT_ADD: { if( !m_editModules ) { undoList.PushItem( ITEM_PICKER( boardItem, UR_NEW ) ); if( !( changeFlags & CHT_DONE ) ) board->Add( boardItem ); //ratsnest->Add( boardItem ); // TODO currently done by BOARD::Add() if( boardItem->Type() == PCB_MODULE_T ) { MODULE* mod = static_cast<MODULE*>( boardItem ); mod->RunOnChildren( boost::bind( &KIGFX::VIEW::Add, view, _1 ) ); } } else { // modules inside modules are not supported yet assert( boardItem->Type() != PCB_MODULE_T ); if( !( changeFlags & CHT_DONE ) ) board->m_Modules->Add( boardItem ); } view->Add( boardItem ); break; } case CHT_REMOVE: { if( !m_editModules ) { undoList.PushItem( ITEM_PICKER( boardItem, UR_DELETED ) ); } switch( boardItem->Type() ) { // Module items case PCB_PAD_T: case PCB_MODULE_EDGE_T: case PCB_MODULE_TEXT_T: { // Do not allow footprint text removal when not editing a module if( !m_editModules ) break; bool remove = true; if( boardItem->Type() == PCB_MODULE_TEXT_T ) { TEXTE_MODULE* text = static_cast<TEXTE_MODULE*>( boardItem ); switch( text->GetType() ) { case TEXTE_MODULE::TEXT_is_REFERENCE: //DisplayError( frame, _( "Cannot delete component reference." ) ); remove = false; break; case TEXTE_MODULE::TEXT_is_VALUE: //DisplayError( frame, _( "Cannot delete component value." ) ); remove = false; break; case TEXTE_MODULE::TEXT_is_DIVERS: // suppress warnings break; default: assert( false ); break; } } if( remove ) { view->Remove( boardItem ); if( !( changeFlags & CHT_DONE ) ) { MODULE* module = static_cast<MODULE*>( boardItem->GetParent() ); assert( module && module->Type() == PCB_MODULE_T ); module->Delete( boardItem ); } board->m_Status_Pcb = 0; // it is done in the legacy view (ratsnest perhaps?) } break; } // Board items case PCB_LINE_T: // a segment not on copper layers case PCB_TEXT_T: // a text on a layer case PCB_TRACE_T: // a track segment (segment on a copper layer) case PCB_VIA_T: // a via (like track segment on a copper layer) case PCB_DIMENSION_T: // a dimension (graphic item) case PCB_TARGET_T: // a target (graphic item) case PCB_MARKER_T: // a marker used to show something case PCB_ZONE_T: // SEG_ZONE items are now deprecated case PCB_ZONE_AREA_T: view->Remove( boardItem ); if( !( changeFlags & CHT_DONE ) ) board->Remove( boardItem ); //ratsnest->Remove( boardItem ); // currently done by BOARD::Remove() break; case PCB_MODULE_T: { // There are no modules inside a module yet assert( !m_editModules ); MODULE* module = static_cast<MODULE*>( boardItem ); module->ClearFlags(); module->RunOnChildren( boost::bind( &KIGFX::VIEW::Remove, view, _1 ) ); view->Remove( module ); if( !( changeFlags & CHT_DONE ) ) board->Remove( module ); // Clear flags to indicate, that the ratsnest, list of nets & pads are not valid anymore board->m_Status_Pcb = 0; } break; default: // other types do not need to (or should not) be handled assert( false ); break; } break; } case CHT_MODIFY: { if( !m_editModules ) { ITEM_PICKER itemWrapper( boardItem, UR_CHANGED ); assert( ent.m_copy ); itemWrapper.SetLink( ent.m_copy ); undoList.PushItem( itemWrapper ); } boardItem->ViewUpdate( KIGFX::VIEW_ITEM::ALL ); ratsnest->Update( boardItem ); break; } default: assert( false ); break; } } if( !m_editModules ) frame->SaveCopyInUndoList( undoList, UR_UNSPECIFIED ); frame->OnModify(); ratsnest->Recalculate(); clear(); }