void PCB_EDIT_FRAME::duplicateZone( wxDC* aDC, ZONE_CONTAINER* aZone ) { ZONE_CONTAINER* newZone = new ZONE_CONTAINER( GetBoard() ); newZone->Copy( aZone ); newZone->UnFill(); ZONE_SETTINGS zoneSettings; zoneSettings << *aZone; bool success; if( aZone->GetIsKeepout() ) success = InvokeKeepoutAreaEditor( this, &zoneSettings ); else if( aZone->IsOnCopperLayer() ) success = InvokeCopperZonesEditor( this, &zoneSettings ); else success = InvokeNonCopperZonesEditor( this, aZone, &zoneSettings ); if( success ) { zoneSettings.ExportSetting( *newZone ); newZone->m_Poly->Hatch(); s_AuxiliaryList.ClearListAndDeleteItems(); s_PickedList.ClearListAndDeleteItems(); SaveCopyOfZones( s_PickedList, GetBoard(), newZone->GetNet(), newZone->GetLayer() ); GetBoard()->Add( newZone ); ITEM_PICKER picker( newZone, UR_NEW ); s_PickedList.PushItem( picker ); GetScreen()->SetCurItem( NULL ); // This outline may be deleted when merging outlines // Combine zones if possible GetBoard()->OnAreaPolygonModified( &s_AuxiliaryList, newZone ); // Redraw zones GetBoard()->RedrawAreasOutlines( m_canvas, aDC, GR_OR, newZone->GetLayer() ); GetBoard()->RedrawFilledAreas( m_canvas, aDC, GR_OR, newZone->GetLayer() ); if( GetBoard()->GetAreaIndex( newZone ) >= 0 && GetBoard()->Test_Drc_Areas_Outlines_To_Areas_Outlines( newZone, true ) ) { DisplayError( this, _( "Duplicate Zone: The outline of the duplicated zone fails DRC check!" ) ); } UpdateCopyOfZonesList( s_PickedList, s_AuxiliaryList, GetBoard() ); SaveCopyInUndoList( s_PickedList, UR_UNSPECIFIED ); s_PickedList.ClearItemsList(); OnModify(); } else delete newZone; }
int PCB_EDITOR_CONTROL::ZoneDuplicate( const TOOL_EVENT& aEvent ) { auto selTool = m_toolMgr->GetTool<SELECTION_TOOL>(); const auto& selection = selTool->GetSelection(); // because this pops up the zone editor, it would be confusing // to handle multiple zones, so just handle single selections // containing exactly one zone if( selection.Size() != 1 ) return 0; auto oldZone = dyn_cast<ZONE_CONTAINER*>( selection[0] ); if( !oldZone ) return 0; auto newZone = std::make_unique<ZONE_CONTAINER>( *oldZone ); newZone->ClearSelected(); newZone->UnFill(); ZONE_SETTINGS zoneSettings; zoneSettings << *oldZone; bool success = false; if( oldZone->GetIsKeepout() ) success = InvokeKeepoutAreaEditor( m_frame, &zoneSettings ); else if( oldZone->IsOnCopperLayer() ) success = InvokeCopperZonesEditor( m_frame, &zoneSettings ); else success = InvokeNonCopperZonesEditor( m_frame, oldZone, &zoneSettings ); // If the new zone is on the same layer as the the initial zone, // do nothing if( success && ( oldZone->GetLayer() == zoneSettings.m_CurrentZone_Layer ) ) { DisplayError( m_frame, _( "The duplicated zone cannot be on the same layer as the original zone." ) ); success = false; } // duplicate the zone if( success ) { BOARD_COMMIT commit( m_frame ); zoneSettings.ExportSetting( *newZone ); commit.Add( newZone.release() ); commit.Push( _( "Duplicate zone" ) ); } 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 }
void PCB_EDIT_FRAME::Edit_Zone_Params( wxDC* DC, ZONE_CONTAINER* aZone ) { ZONE_EDIT_T edited; ZONE_SETTINGS zoneInfo = GetZoneSettings(); m_canvas->SetIgnoreMouseEvents( true ); // Save initial zones configuration, for undo/redo, before adding new zone // note the net name and the layer can be changed, so we must save all zones s_AuxiliaryList.ClearListAndDeleteItems(); s_PickedList.ClearListAndDeleteItems(); SaveCopyOfZones(s_PickedList, GetBoard(), -1, -1 ); if( aZone->GetIsKeepout() ) { // edit a keepout area on a copper layer zoneInfo << *aZone; edited = InvokeKeepoutAreaEditor( this, &zoneInfo ); } else if( aZone->GetLayer() < FIRST_NO_COPPER_LAYER ) { // edit a zone on a copper layer zoneInfo << *aZone; edited = InvokeCopperZonesEditor( this, &zoneInfo ); } else { edited = InvokeNonCopperZonesEditor( this, aZone, &zoneInfo ); } m_canvas->MoveCursorToCrossHair(); m_canvas->SetIgnoreMouseEvents( false ); if( edited == ZONE_ABORT ) { s_AuxiliaryList.ClearListAndDeleteItems(); s_PickedList.ClearListAndDeleteItems(); return; } SetZoneSettings( zoneInfo ); if( edited == ZONE_EXPORT_VALUES ) { UpdateCopyOfZonesList( s_PickedList, s_AuxiliaryList, GetBoard() ); SaveCopyInUndoList(s_PickedList, UR_UNSPECIFIED); s_PickedList.ClearItemsList(); // s_ItemsListPicker is no more owner of picked items return; } // Undraw old zone outlines for( int ii = 0; ii < GetBoard()->GetAreaCount(); ii++ ) { ZONE_CONTAINER* edge_zone = GetBoard()->GetArea( ii ); edge_zone->Draw( m_canvas, DC, GR_XOR ); } zoneInfo.ExportSetting( *aZone ); NETINFO_ITEM* net = GetBoard()->FindNet( zoneInfo.m_NetcodeSelection ); if( net ) // net == NULL should not occur aZone->SetNetName( net->GetNetname() ); // Combine zones if possible GetBoard()->OnAreaPolygonModified( &s_AuxiliaryList, aZone ); // Redraw the real new zone outlines GetBoard()->RedrawAreasOutlines( m_canvas, DC, GR_OR, -1 ); UpdateCopyOfZonesList( s_PickedList, s_AuxiliaryList, GetBoard() ); SaveCopyInUndoList(s_PickedList, UR_UNSPECIFIED); s_PickedList.ClearItemsList(); // s_ItemsListPicker is no longer owner of picked items OnModify(); }
int PCB_EDIT_FRAME::Begin_Zone( wxDC* DC ) { ZONE_SETTINGS zoneInfo = GetZoneSettings(); // verify if s_CurrentZone exists (could be deleted since last selection) : int ii; for( ii = 0; ii < GetBoard()->GetAreaCount(); ii++ ) { if( s_CurrentZone == GetBoard()->GetArea( ii ) ) break; } if( ii >= GetBoard()->GetAreaCount() ) // Not found: could be deleted since last selection { s_AddCutoutToCurrentZone = false; s_CurrentZone = NULL; } // If no zone contour in progress, a new zone is being created: if( !GetBoard()->m_CurrentZoneContour ) { if( GetToolId() == ID_PCB_KEEPOUT_AREA_BUTT && getActiveLayer() >= FIRST_NON_COPPER_LAYER ) { DisplayError( this, _( "Error: a keepout area is allowed only on copper layers" ) ); return 0; } else GetBoard()->m_CurrentZoneContour = new ZONE_CONTAINER( GetBoard() ); } ZONE_CONTAINER* zone = GetBoard()->m_CurrentZoneContour; if( zone->GetNumCorners() == 0 ) // Start a new contour: init zone params (net, layer ...) { if( !s_CurrentZone ) // A new outline is created, from scratch { ZONE_EDIT_T edited; // Init zone params to reasonable values zone->SetLayer( getActiveLayer() ); // Prompt user for parameters: m_canvas->SetIgnoreMouseEvents( true ); if( zone->IsOnCopperLayer() ) { // Put a zone on a copper layer if( GetBoard()->GetHighLightNetCode() > 0 ) { zoneInfo.m_NetcodeSelection = GetBoard()->GetHighLightNetCode(); zone->SetNet( zoneInfo.m_NetcodeSelection ); zone->SetNetNameFromNetCode( ); } double tmp = ZONE_THERMAL_RELIEF_GAP_MIL; wxGetApp().GetSettings()->Read( ZONE_THERMAL_RELIEF_GAP_STRING_KEY, &tmp ); zoneInfo.m_ThermalReliefGap = KiROUND( tmp * IU_PER_MILS); tmp = ZONE_THERMAL_RELIEF_COPPER_WIDTH_MIL; wxGetApp().GetSettings()->Read( ZONE_THERMAL_RELIEF_COPPER_WIDTH_STRING_KEY, &tmp ); zoneInfo.m_ThermalReliefCopperBridge = KiROUND( tmp * IU_PER_MILS ); tmp = ZONE_CLEARANCE_MIL; wxGetApp().GetSettings()->Read( ZONE_CLEARANCE_WIDTH_STRING_KEY, &tmp ); zoneInfo.m_ZoneClearance = KiROUND( tmp * IU_PER_MILS ); tmp = ZONE_THICKNESS_MIL; wxGetApp().GetSettings()->Read( ZONE_MIN_THICKNESS_WIDTH_STRING_KEY, &tmp ); zoneInfo.m_ZoneMinThickness = KiROUND( tmp * IU_PER_MILS ); zoneInfo.m_CurrentZone_Layer = zone->GetLayer(); if( GetToolId() == ID_PCB_KEEPOUT_AREA_BUTT ) { zoneInfo.SetIsKeepout( true ); edited = InvokeKeepoutAreaEditor( this, &zoneInfo ); } else { zoneInfo.SetIsKeepout( false ); edited = InvokeCopperZonesEditor( this, &zoneInfo ); } } else // Put a zone on a non copper layer (technical layer) { zoneInfo.SetIsKeepout( false ); zoneInfo.m_NetcodeSelection = 0; // No net for non copper zones edited = InvokeNonCopperZonesEditor( this, zone, &zoneInfo ); } m_canvas->MoveCursorToCrossHair(); m_canvas->SetIgnoreMouseEvents( false ); if( edited == ZONE_ABORT ) return 0; // Switch active layer to the selected zone layer setActiveLayer( zoneInfo.m_CurrentZone_Layer ); SetZoneSettings( zoneInfo ); } else { // Start a new contour: init zone params (net and layer) from an existing // zone (add cutout or similar zone) zoneInfo.m_CurrentZone_Layer = s_CurrentZone->GetLayer(); setActiveLayer( s_CurrentZone->GetLayer() ); zoneInfo << *s_CurrentZone; SetZoneSettings( zoneInfo ); } // Show the Net for zones on copper layers if( zoneInfo.m_CurrentZone_Layer < FIRST_NO_COPPER_LAYER && ! zoneInfo.GetIsKeepout() ) { if( s_CurrentZone ) { zoneInfo.m_NetcodeSelection = s_CurrentZone->GetNet(); GetBoard()->SetZoneSettings( zoneInfo ); } if( GetBoard()->IsHighLightNetON() ) { HighLight( DC ); // Remove old highlight selection } GetBoard()->SetHighLightNet( zoneInfo.m_NetcodeSelection ); HighLight( DC ); } if( !s_AddCutoutToCurrentZone ) s_CurrentZone = NULL; // the zone is used only once ("add similar zone" command) } // if first segment if( zone->GetNumCorners() == 0 ) { zone->SetFlags( IS_NEW ); zone->SetTimeStamp( GetNewTimeStamp() ); zoneInfo.ExportSetting( *zone ); zone->m_Poly->Start( zoneInfo.m_CurrentZone_Layer, GetScreen()->GetCrossHairPosition().x, GetScreen()->GetCrossHairPosition().y, zone->GetHatchStyle() ); zone->AppendCorner( GetScreen()->GetCrossHairPosition() ); if( Drc_On && (m_drc->Drc( zone, 0 ) == BAD_DRC) && zone->IsOnCopperLayer() ) { zone->ClearFlags(); zone->RemoveAllContours(); // use the form of SetCurItem() which does not write to the msg panel, // SCREEN::SetCurItem(), so the DRC error remains on screen. // PCB_EDIT_FRAME::SetCurItem() calls DisplayInfo(). GetScreen()->SetCurItem( NULL ); DisplayError( this, _( "DRC error: this start point is inside or too close an other area" ) ); return 0; } SetCurItem( zone ); m_canvas->SetMouseCapture( Show_New_Edge_While_Move_Mouse, Abort_Zone_Create_Outline ); } else // edge in progress: { ii = zone->GetNumCorners() - 1; // edge in progress : the current corner coordinate was set // by Show_New_Edge_While_Move_Mouse if( zone->GetCornerPosition( ii - 1 ) != zone->GetCornerPosition( ii ) ) { if( !Drc_On || !zone->IsOnCopperLayer() || ( m_drc->Drc( zone, ii - 1 ) == OK_DRC ) ) { // Ok, we can add a new corner if( m_canvas->IsMouseCaptured() ) m_canvas->CallMouseCapture( DC, wxPoint(0,0), false ); zone->AppendCorner( GetScreen()->GetCrossHairPosition() ); SetCurItem( zone ); // calls DisplayInfo(). if( m_canvas->IsMouseCaptured() ) m_canvas->CallMouseCapture( DC, wxPoint(0,0), false ); } } } return zone->GetNumCorners(); }
int DRAWING_TOOL::drawZone( bool aKeepout ) { ZONE_CONTAINER* zone = NULL; DRAWSEGMENT line45; DRAWSEGMENT* helperLine = NULL; // we will need more than one helper line // if one day it is possible to draw zones in the footprint editor, // then hereby I'm letting you know that this tool does not handle UR_MODEDIT undo yet assert( !m_editModules ); // Add a VIEW_GROUP that serves as a preview for the new item KIGFX::VIEW_GROUP preview( m_view ); m_view->Add( &preview ); m_toolMgr->RunAction( COMMON_ACTIONS::selectionClear, true ); m_controls->ShowCursor( true ); m_controls->SetSnapping( true ); Activate(); VECTOR2I origin; int numPoints = 0; bool direction45 = false; // 45 degrees only mode // Main loop: keep receiving events while( OPT_TOOL_EVENT evt = Wait() ) { bool updatePreview = false; // should preview be updated VECTOR2I cursorPos = m_controls->GetCursorPosition(); // Enable 45 degrees lines only mode by holding control if( direction45 != ( evt->Modifier( MD_CTRL ) && numPoints > 0 ) ) { direction45 = evt->Modifier( MD_CTRL ); if( direction45 ) { preview.Add( &line45 ); make45DegLine( helperLine, &line45 ); } else { preview.Remove( &line45 ); helperLine->SetEnd( wxPoint( cursorPos.x, cursorPos.y ) ); } updatePreview = true; } if( evt->IsCancel() || evt->IsActivate() ) { if( numPoints > 0 ) // cancel the current zone { delete zone; zone = NULL; m_controls->SetAutoPan( false ); m_controls->CaptureCursor( false ); if( direction45 ) { preview.Remove( &line45 ); direction45 = false; } preview.FreeItems(); updatePreview = true; numPoints = 0; } else // there is no zone currently drawn - just stop the tool break; if( evt->IsActivate() ) // now finish unconditionally break; } else if( evt->IsClick( BUT_LEFT ) || evt->IsDblClick( BUT_LEFT ) ) { // Check if it is double click / closing line (so we have to finish the zone) if( evt->IsDblClick( BUT_LEFT ) || ( numPoints > 0 && cursorPos == origin ) ) { if( numPoints > 2 ) // valid zone consists of more than 2 points { assert( zone->GetNumCorners() > 2 ); // Finish the zone if( direction45 ) zone->AppendCorner( cursorPos == origin ? line45.GetStart() : line45.GetEnd() ); zone->Outline()->CloseLastContour(); zone->Outline()->RemoveNullSegments(); m_board->Add( zone ); m_view->Add( zone ); if( !aKeepout ) static_cast<PCB_EDIT_FRAME*>( m_frame )->Fill_Zone( zone ); zone->ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY ); m_board->GetRatsnest()->Update( zone ); m_frame->OnModify(); m_frame->SaveCopyInUndoList( zone, UR_NEW ); zone = NULL; } else { delete zone; zone = NULL; } numPoints = 0; m_controls->SetAutoPan( false ); m_controls->CaptureCursor( false ); if( direction45 ) { preview.Remove( &line45 ); direction45 = false; } preview.FreeItems(); updatePreview = true; } else { if( numPoints == 0 ) // it's the first click { // Get the current default settings for zones ZONE_SETTINGS zoneInfo = m_frame->GetZoneSettings(); zoneInfo.m_CurrentZone_Layer = m_frame->GetScreen()->m_Active_Layer; m_controls->SetAutoPan( true ); m_controls->CaptureCursor( true ); // Show options dialog ZONE_EDIT_T dialogResult; if( aKeepout ) dialogResult = InvokeKeepoutAreaEditor( m_frame, &zoneInfo ); else { if( IsCopperLayer( zoneInfo.m_CurrentZone_Layer ) ) dialogResult = InvokeCopperZonesEditor( m_frame, &zoneInfo ); else dialogResult = InvokeNonCopperZonesEditor( m_frame, NULL, &zoneInfo ); } if( dialogResult == ZONE_ABORT ) { m_controls->SetAutoPan( false ); m_controls->CaptureCursor( false ); continue; } // Apply the selected settings zone = new ZONE_CONTAINER( m_board ); zoneInfo.ExportSetting( *zone ); m_frame->GetGalCanvas()->SetTopLayer( zoneInfo.m_CurrentZone_Layer ); // Add the first point zone->Outline()->Start( zoneInfo.m_CurrentZone_Layer, cursorPos.x, cursorPos.y, zone->GetHatchStyle() ); origin = cursorPos; // Helper line represents the currently drawn line of the zone polygon helperLine = new DRAWSEGMENT; helperLine->SetShape( S_SEGMENT ); helperLine->SetWidth( 1 ); helperLine->SetLayer( zoneInfo.m_CurrentZone_Layer ); helperLine->SetStart( wxPoint( cursorPos.x, cursorPos.y ) ); helperLine->SetEnd( wxPoint( cursorPos.x, cursorPos.y ) ); line45 = *helperLine; preview.Add( helperLine ); } else { zone->AppendCorner( helperLine->GetEnd() ); helperLine = new DRAWSEGMENT( *helperLine ); helperLine->SetStart( helperLine->GetEnd() ); preview.Add( helperLine ); } ++numPoints; updatePreview = true; } } else if( evt->IsMotion() && numPoints > 0 ) { // 45 degree lines if( direction45 ) make45DegLine( helperLine, &line45 ); else helperLine->SetEnd( wxPoint( cursorPos.x, cursorPos.y ) ); // Show a preview of the item updatePreview = true; } if( updatePreview ) preview.ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY ); } m_controls->ShowCursor( false ); m_controls->SetSnapping( false ); m_controls->SetAutoPan( false ); m_controls->CaptureCursor( false ); m_view->Remove( &preview ); m_frame->SetToolID( ID_NO_TOOL_SELECTED, wxCURSOR_DEFAULT, wxEmptyString ); return 0; }