diff options
Diffstat (limited to 'pcbnew/modules.cpp')
-rw-r--r-- | pcbnew/modules.cpp | 512 |
1 files changed, 512 insertions, 0 deletions
diff --git a/pcbnew/modules.cpp b/pcbnew/modules.cpp new file mode 100644 index 0000000..cb83e39 --- /dev/null +++ b/pcbnew/modules.cpp @@ -0,0 +1,512 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2012 Jean-Pierre Charras, jean-pierre.charras@ujf-grenoble.fr + * Copyright (C) 2012 SoftPLC Corporation, Dick Hollenbeck <dick@softplc.com> + * Copyright (C) 2012 Wayne Stambaugh <stambaughw@verizon.net> + * Copyright (C) 1992-2012 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 + */ + +/** + * @file modules.cpp + */ + +#include <fctsys.h> +#include <gr_basic.h> +#include <class_drawpanel.h> +#include <confirm.h> +#include <wxPcbStruct.h> +#include <trigo.h> +#include <macros.h> + +#include <class_board.h> +#include <class_module.h> + +#include <pcbnew.h> +#include <drag.h> + + +static void MoveFootprint( EDA_DRAW_PANEL* aPanel, wxDC* aDC, + const wxPoint& aPosition, bool aErase ); +static void Abort_MoveOrCopyModule( EDA_DRAW_PANEL* Panel, wxDC* DC ); + + +static MODULE* s_ModuleInitialCopy = NULL; /* Copy of module for + * abort/undo command + */ +static PICKED_ITEMS_LIST s_PickedList; /* a picked list to + * save initial module + * and dragged tracks + */ + +/* Get a module name from user and return a pointer to the corresponding module + */ +MODULE* PCB_BASE_FRAME::GetModuleByName() +{ + wxString moduleName; + MODULE* module = NULL; + + wxTextEntryDialog dlg( this, _( "Reference:" ), _( "Search for footprint" ), moduleName ); + + if( dlg.ShowModal() != wxID_OK ) + return NULL; //Aborted by user + + moduleName = dlg.GetValue(); + moduleName.Trim( true ); + moduleName.Trim( false ); + + if( !moduleName.IsEmpty() ) + { + module = GetBoard()->m_Modules; + + while( module ) + { + if( module->GetReference().CmpNoCase( moduleName ) == 0 ) + break; + + module = module->Next(); + } + } + + return module; +} + + +void PCB_EDIT_FRAME::StartMoveModule( MODULE* aModule, wxDC* aDC, + bool aDragConnectedTracks ) +{ + if( aModule == NULL ) + return; + + if( s_ModuleInitialCopy ) + delete s_ModuleInitialCopy; + + s_PickedList.ClearItemsList(); // Should be empty, but... + + // Creates a copy of the current module, for abort and undo commands + s_ModuleInitialCopy = (MODULE*)aModule->Clone(); + s_ModuleInitialCopy->SetParent( GetBoard() ); + s_ModuleInitialCopy->ClearFlags(); + + SetCurItem( aModule ); + GetBoard()->m_Status_Pcb &= ~RATSNEST_ITEM_LOCAL_OK; + aModule->SetFlags( IS_MOVED ); + + /* Show ratsnest. */ + if( GetBoard()->IsElementVisible( RATSNEST_VISIBLE ) ) + DrawGeneralRatsnest( aDC ); + + EraseDragList(); + + if( aDragConnectedTracks ) + { + DRAG_LIST drglist( GetBoard() ); + drglist.BuildDragListe( aModule ); + + ITEM_PICKER itemWrapper( NULL, UR_CHANGED ); + + for( unsigned ii = 0; ii < g_DragSegmentList.size(); ii++ ) + { + TRACK* segm = g_DragSegmentList[ii].m_Track; + itemWrapper.SetItem( segm ); + itemWrapper.SetLink( segm->Clone() ); + itemWrapper.GetLink()->SetState( IN_EDIT, false ); + s_PickedList.PushItem( itemWrapper ); + } + + UndrawAndMarkSegmentsToDrag( m_canvas, aDC ); + } + + GetBoard()->m_Status_Pcb |= DO_NOT_SHOW_GENERAL_RASTNEST; + m_canvas->SetMouseCapture( MoveFootprint, Abort_MoveOrCopyModule ); + m_canvas->SetAutoPanRequest( true ); + + // Erase the module. + if( aDC ) + { + aModule->SetFlags( DO_NOT_DRAW ); + m_canvas->RefreshDrawingRect( aModule->GetBoundingBox() ); + aModule->ClearFlags( DO_NOT_DRAW ); + } + + m_canvas->CallMouseCapture( aDC, wxDefaultPosition, false ); +} + + +/* Called on a move or copy module command abort + */ +void Abort_MoveOrCopyModule( EDA_DRAW_PANEL* Panel, wxDC* DC ) +{ + TRACK* pt_segm; + MODULE* module; + PCB_EDIT_FRAME* pcbframe = (PCB_EDIT_FRAME*) Panel->GetParent(); + + module = (MODULE*) pcbframe->GetScreen()->GetCurItem(); + pcbframe->GetBoard()->m_Status_Pcb &= ~RATSNEST_ITEM_LOCAL_OK; + Panel->SetMouseCapture( NULL, NULL ); + + if( module ) + { + // Erase the current footprint on screen + module->DrawOutlinesWhenMoving( Panel, DC, g_Offset_Module ); + + /* If a move command: return to old position + * If a copy command, delete the new footprint + */ + if( module->IsMoving() ) + { + /* Restore old position for dragged tracks */ + for( unsigned ii = 0; ii < g_DragSegmentList.size(); ii++ ) + { + pt_segm = g_DragSegmentList[ii].m_Track; + pt_segm->Draw( Panel, DC, GR_XOR ); + pt_segm->SetState( IN_EDIT, false ); + pt_segm->ClearFlags(); + g_DragSegmentList[ii].RestoreInitialValues(); + pt_segm->Draw( Panel, DC, GR_OR ); + } + + EraseDragList(); + module->ClearFlags( IS_MOVED ); + } + + if( module->IsNew() ) // Copy command: delete new footprint + { + module->DeleteStructure(); + module = NULL; + pcbframe->GetBoard()->m_Status_Pcb = 0; + pcbframe->GetBoard()->BuildListOfNets(); + } + } + + /* Redraw the module. */ + if( module && s_ModuleInitialCopy ) + { + if( s_ModuleInitialCopy->GetOrientation() != module->GetOrientation() ) + pcbframe->Rotate_Module( NULL, module, s_ModuleInitialCopy->GetOrientation(), false ); + + if( s_ModuleInitialCopy->GetLayer() != module->GetLayer() ) + pcbframe->Change_Side_Module( module, NULL ); + + module->Draw( Panel, DC, GR_OR ); + } + + pcbframe->SetCurItem( NULL ); + + delete s_ModuleInitialCopy; + s_ModuleInitialCopy = NULL; + s_PickedList.ClearListAndDeleteItems(); + + // Display ratsnest is allowed + pcbframe->GetBoard()->m_Status_Pcb &= ~DO_NOT_SHOW_GENERAL_RASTNEST; + + if( pcbframe->GetBoard()->IsElementVisible( RATSNEST_VISIBLE ) ) + pcbframe->DrawGeneralRatsnest( DC ); + +#ifdef __WXMAC__ + Panel->Refresh(); +#endif +} + + +/* Redraw the footprint when moving the mouse. + */ +void MoveFootprint( EDA_DRAW_PANEL* aPanel, wxDC* aDC, const wxPoint& aPosition, bool aErase ) +{ + MODULE* module = (MODULE*) aPanel->GetScreen()->GetCurItem(); + + if( module == NULL ) + return; + + /* Erase current footprint. */ + if( aErase ) + { + module->DrawOutlinesWhenMoving( aPanel, aDC, g_Offset_Module ); + } + + /* Redraw the module at the new position. */ + g_Offset_Module = module->GetPosition() - aPanel->GetParent()->GetCrossHairPosition(); + module->DrawOutlinesWhenMoving( aPanel, aDC, g_Offset_Module ); + + DrawSegmentWhileMovingFootprint( aPanel, aDC ); +} + + +bool PCB_EDIT_FRAME::Delete_Module( MODULE* aModule, wxDC* aDC ) +{ + wxString msg; + + if( aModule == NULL ) + return false; + + SetMsgPanel( aModule ); + + /* Remove module from list, and put it in undo command list */ + m_Pcb->m_Modules.Remove( aModule ); + aModule->SetState( IS_DELETED, true ); + SaveCopyInUndoList( aModule, UR_DELETED ); + + if( aDC && GetBoard()->IsElementVisible( RATSNEST_VISIBLE ) ) + Compile_Ratsnest( aDC, true ); + + // Redraw the full screen to ensure perfect display of board and ratsnest. + if( aDC ) + m_canvas->Refresh(); + + OnModify(); + + return true; +} + + +void PCB_EDIT_FRAME::Change_Side_Module( MODULE* Module, wxDC* DC ) +{ + if( Module == NULL ) + return; + + if( ( Module->GetLayer() != F_Cu ) && ( Module->GetLayer() != B_Cu ) ) + return; + + OnModify(); + + if( !Module->IsMoving() ) /* This is a simple flip, no other edition in progress */ + { + GetBoard()->m_Status_Pcb &= ~( LISTE_RATSNEST_ITEM_OK | CONNEXION_OK ); + + if( DC ) + { + Module->SetFlags( DO_NOT_DRAW ); + m_canvas->RefreshDrawingRect( Module->GetBoundingBox() ); + Module->ClearFlags( DO_NOT_DRAW ); + } + + /* Show ratsnest if necessary. */ + if( DC && GetBoard()->IsElementVisible( RATSNEST_VISIBLE ) ) + DrawGeneralRatsnest( DC ); + + g_Offset_Module.x = 0; + g_Offset_Module.y = 0; + } + else // Module is being moved. + { + /* Erase footprint and draw outline if it has been already drawn. */ + if( DC ) + { + Module->DrawOutlinesWhenMoving( m_canvas, DC, g_Offset_Module ); + DrawSegmentWhileMovingFootprint( m_canvas, DC ); + } + } + + /* Flip the module */ + Module->Flip( Module->GetPosition() ); + + SetMsgPanel( Module ); + + if( !Module->IsMoving() ) /* Inversion simple */ + { + if( DC ) + { + Module->Draw( m_canvas, DC, GR_OR ); + + if( GetBoard()->IsElementVisible( RATSNEST_VISIBLE ) ) + Compile_Ratsnest( DC, true ); + } + } + else + { + if( DC ) + { + Module->DrawOutlinesWhenMoving( m_canvas, DC, g_Offset_Module ); + DrawSegmentWhileMovingFootprint( m_canvas, DC ); + } + + GetBoard()->m_Status_Pcb &= ~RATSNEST_ITEM_LOCAL_OK; + } +} + + +void PCB_BASE_FRAME::PlaceModule( MODULE* aModule, wxDC* aDC, bool aDoNotRecreateRatsnest ) +{ + wxPoint newpos; + + if( aModule == 0 ) + return; + + OnModify(); + GetBoard()->m_Status_Pcb &= ~( LISTE_RATSNEST_ITEM_OK | CONNEXION_OK); + + if( aModule->IsNew() ) + { + SaveCopyInUndoList( aModule, UR_NEW ); + } + else if( aModule->IsMoving() ) + { + ITEM_PICKER picker( aModule, UR_CHANGED ); + picker.SetLink( s_ModuleInitialCopy ); + s_PickedList.PushItem( picker ); + s_ModuleInitialCopy = NULL; // the picker is now owner of s_ModuleInitialCopy. + } + + if( s_PickedList.GetCount() ) + { + SaveCopyInUndoList( s_PickedList, UR_UNSPECIFIED ); + + // Clear list, but DO NOT delete items, because they are owned by the saved undo + // list and they therefore in use + s_PickedList.ClearItemsList(); + } + + DISPLAY_OPTIONS* displ_opts = (DISPLAY_OPTIONS*)GetDisplayOptions(); + + if( displ_opts->m_Show_Module_Ratsnest && ( GetBoard()->m_Status_Pcb & LISTE_PAD_OK ) && aDC ) + TraceModuleRatsNest( aDC ); + + newpos = GetCrossHairPosition(); + aModule->SetPosition( newpos ); + aModule->ClearFlags(); + + delete s_ModuleInitialCopy; + s_ModuleInitialCopy = NULL; + + if( aDC ) + aModule->Draw( m_canvas, aDC, GR_OR ); + + // Redraw dragged track segments, if any + for( unsigned ii = 0; ii < g_DragSegmentList.size(); ii++ ) + { + TRACK * track = g_DragSegmentList[ii].m_Track; + track->SetState( IN_EDIT, false ); + track->ClearFlags(); + + if( aDC ) + track->Draw( m_canvas, aDC, GR_OR ); + } + + // Delete drag list + EraseDragList(); + + m_canvas->SetMouseCapture( NULL, NULL ); + + if( GetBoard()->IsElementVisible( RATSNEST_VISIBLE ) && !aDoNotRecreateRatsnest ) + Compile_Ratsnest( aDC, true ); + + if( aDC ) + m_canvas->Refresh(); + + SetMsgPanel( aModule ); +} + + +/* + * Rotate the footprint angle degrees in the direction < 0. + * If incremental == true, the rotation is made from the last orientation, + * If the module is placed in the absolute orientation angle. + * If DC == NULL, the component does not redraw. + * Otherwise, it erases and redraws turns + */ +void PCB_BASE_FRAME::Rotate_Module( wxDC* DC, MODULE* module, double angle, bool incremental ) +{ + if( module == NULL ) + return; + + OnModify(); + + if( !module->IsMoving() ) /* This is a simple rotation, no other + * edition in progress */ + { + if( DC ) // Erase footprint to screen + { + module->SetFlags( DO_NOT_DRAW ); + m_canvas->RefreshDrawingRect( module->GetBoundingBox() ); + module->ClearFlags( DO_NOT_DRAW ); + + if( GetBoard()->IsElementVisible( RATSNEST_VISIBLE ) ) + DrawGeneralRatsnest( DC ); + } + } + else + { + if( DC ) + { + module->DrawOutlinesWhenMoving( m_canvas, DC, g_Offset_Module ); + DrawSegmentWhileMovingFootprint( m_canvas, DC ); + } + } + + GetBoard()->m_Status_Pcb &= ~( LISTE_RATSNEST_ITEM_OK | CONNEXION_OK ); + + if( incremental ) + module->SetOrientation( module->GetOrientation() + angle ); + else + module->SetOrientation( angle ); + + SetMsgPanel( module ); + + if( DC ) + { + if( !module->IsMoving() ) + { + // not beiing moved: redraw the module and update ratsnest + module->Draw( m_canvas, DC, GR_OR ); + + if( GetBoard()->IsElementVisible( RATSNEST_VISIBLE ) ) + Compile_Ratsnest( DC, true ); + } + else + { + // Beiing moved: just redraw it + module->DrawOutlinesWhenMoving( m_canvas, DC, g_Offset_Module ); + DrawSegmentWhileMovingFootprint( m_canvas, DC ); + } + + if( module->GetFlags() == 0 ) // module not in edit: redraw full screen + m_canvas->Refresh(); + } +} + + +// Redraw in XOR mode the outlines of the module. +void MODULE::DrawOutlinesWhenMoving( EDA_DRAW_PANEL* panel, wxDC* DC, + const wxPoint& aMoveVector ) +{ + int pad_fill_tmp; + D_PAD* pt_pad; + + DrawEdgesOnly( panel, DC, aMoveVector, GR_XOR ); + DISPLAY_OPTIONS* displ_opts = (DISPLAY_OPTIONS*)panel->GetDisplayOptions(); + + // Show pads in sketch mode to speedu up drawings + pad_fill_tmp = displ_opts->m_DisplayPadFill; + displ_opts->m_DisplayPadFill = true; + + pt_pad = Pads(); + + for( ; pt_pad != NULL; pt_pad = pt_pad->Next() ) + pt_pad->Draw( panel, DC, GR_XOR, aMoveVector ); + + displ_opts->m_DisplayPadFill = pad_fill_tmp; + + if( displ_opts->m_Show_Module_Ratsnest ) + { + PCB_BASE_FRAME* frame = (PCB_BASE_FRAME*) panel->GetParent(); + frame->build_ratsnest_module( this ); + frame->TraceModuleRatsNest( DC ); + } +} |