diff --git a/pcbnew/CMakeLists.txt b/pcbnew/CMakeLists.txt index ab7f49f4de..0d633d0fe4 100644 --- a/pcbnew/CMakeLists.txt +++ b/pcbnew/CMakeLists.txt @@ -166,6 +166,7 @@ set( PCBNEW_CLASS_SRCS modview_frame.cpp pcbframe.cpp pcb_base_edit_frame.cpp + append_board_to_current.cpp attribut.cpp board_items_to_polygon_shape_transform.cpp board_undo_redo.cpp diff --git a/pcbnew/append_board_to_current.cpp b/pcbnew/append_board_to_current.cpp new file mode 100644 index 0000000000..e6de984939 --- /dev/null +++ b/pcbnew/append_board_to_current.cpp @@ -0,0 +1,221 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2004-2014 Jean-Pierre Charras, jp.charras at wanadoo.fr + * Copyright (C) 2014 KiCad Developers, see change_log.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 append_board_to_current.cpp + * @brief append a board to the currently edited board. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// Defined in files.cpp: +extern IO_MGR::PCB_FILE_T plugin_type( const wxString& aFileName, int aCtl ); + + +bool PCB_EDIT_FRAME::AppendBoardFile( const wxString& aFullFileName, int aCtl ) +{ + IO_MGR::PCB_FILE_T pluginType = plugin_type( aFullFileName, aCtl ); + PLUGIN::RELEASER pi( IO_MGR::PluginFind( pluginType ) ); + + // keep trace of existing items, in order to know what are the new items + // (for undo command for instance) + + // Tracks are inserted, not append, so mark existing tracks to know what are + // the new tracks + for( TRACK* track = GetBoard()->m_Track; track; track = track->Next() ) + track->SetFlags( FLAG0 ); + + // Other items are append to the item list, so keep trace to the + // last existing item is enough + MODULE* module = GetBoard()->m_Modules.GetLast(); + BOARD_ITEM* drawing = GetBoard()->m_Drawings.GetLast(); + int zonescount = GetBoard()->GetAreaCount(); + + // Keep also the count of copper layers, because we can happen boards + // with different copper layers counts, + // and the enabled layers + int initialCopperLayerCount = GetBoard()->GetCopperLayerCount(); + LSET initialEnabledLayers = GetBoard()->GetEnabledLayers(); + + try + { + PROPERTIES props; + char xbuf[30]; + char ybuf[30]; + + // EAGLE_PLUGIN can use this info to center the BOARD, but it does not yet. + sprintf( xbuf, "%d", GetPageSizeIU().x ); + sprintf( ybuf, "%d", GetPageSizeIU().y ); + + props["page_width"] = xbuf; + props["page_height"] = ybuf; + + GetDesignSettings().m_NetClasses.Clear(); + pi->Load( aFullFileName, GetBoard(), &props ); + } + catch( const IO_ERROR& ioe ) + { + for( TRACK* track = GetBoard()->m_Track; track; track = track->Next() ) + track->ClearFlags( FLAG0 ); + + wxString msg = wxString::Format( _( + "Error loading board.\n%s" ), + GetChars( ioe.errorText ) + ); + DisplayError( this, msg ); + + return false; + } + + // Now prepare a block move command to place the new items, and + // prepare the undo command. + BLOCK_SELECTOR& blockmove = GetScreen()->m_BlockLocate; + HandleBlockBegin( NULL, BLOCK_PRESELECT_MOVE, wxPoint( 0, 0) ); + PICKED_ITEMS_LIST& blockitemsList = blockmove.GetItems(); + PICKED_ITEMS_LIST undoListPicker; + ITEM_PICKER picker( NULL, UR_NEW ); + + EDA_RECT bbox; // the new items bounding box, for block move + bool bboxInit = true; // true until the bounding box is initialized + + for( TRACK* track = GetBoard()->m_Track; track; track = track->Next() ) + { + if( track->GetFlags() & FLAG0 ) + { + track->ClearFlags( FLAG0 ); + continue; + } + + track->SetFlags( IS_MOVED ); + picker.SetItem( track ); + undoListPicker.PushItem( picker ); + blockitemsList.PushItem( picker ); + + if( bboxInit ) + bbox = track->GetBoundingBox(); + else + + bboxInit = false; + bbox.Merge(track->GetBoundingBox() ); + } + + if( module ) + module = module->Next(); + else + module = GetBoard()->m_Modules; + + for( ; module; module = module->Next() ) + { + module->SetFlags( IS_MOVED ); + picker.SetItem( module ); + undoListPicker.PushItem( picker ); + blockitemsList.PushItem( picker ); + + if( bboxInit ) + bbox = module->GetBoundingBox(); + else + bbox.Merge(module->GetBoundingBox() ); + + bboxInit = false; + } + + if( drawing ) + drawing = drawing->Next(); + else + drawing = GetBoard()->m_Drawings; + + for( ; drawing; drawing = drawing->Next() ) + { + drawing->SetFlags( IS_MOVED ); + picker.SetItem( drawing ); + undoListPicker.PushItem( picker ); + blockitemsList.PushItem( picker ); + + if( bboxInit ) + bbox = drawing->GetBoundingBox(); + else + bbox.Merge(drawing->GetBoundingBox() ); + + bboxInit = false; + } + + for( ZONE_CONTAINER* zone = GetBoard()->GetArea( zonescount ); zone; + zone = GetBoard()->GetArea( zonescount ) ) + { + zone->SetFlags( IS_MOVED ); + picker.SetItem( zone ); + undoListPicker.PushItem( picker ); + blockitemsList.PushItem( picker ); + zonescount++; + + if( bboxInit ) + bbox = zone->GetBoundingBox(); + else + bbox.Merge(zone->GetBoundingBox() ); + + bboxInit = false; + } + + SaveCopyInUndoList( undoListPicker, UR_NEW ); + + // we should not ask PLUGINs to do these items: + int copperLayerCount = GetBoard()->GetCopperLayerCount(); + + if( copperLayerCount > initialCopperLayerCount ) + GetBoard()->SetCopperLayerCount( copperLayerCount ); + + // Enable all used layers, and make them visible: + LSET enabledLayers = GetBoard()->GetEnabledLayers(); + enabledLayers |= initialEnabledLayers; + GetBoard()->SetEnabledLayers( enabledLayers ); + GetBoard()->SetVisibleLayers( enabledLayers ); + ReCreateLayerBox(); + ReFillLayerWidget(); + + if( IsGalCanvasActive() ) + static_cast( GetGalCanvas() )->SyncLayersVisibility( GetBoard() ); + + GetBoard()->BuildListOfNets(); + GetBoard()->SynchronizeNetsAndNetClasses(); + + SetStatusText( wxEmptyString ); + BestZoom(); + + // Finish block move command: + wxPoint cpos = GetNearestGridPosition( bbox.Centre() ); + blockmove.SetOrigin( bbox.GetOrigin() ); + blockmove.SetSize( bbox.GetSize() ); + blockmove.SetLastCursorPosition( cpos ); + HandleBlockEnd( NULL ); + + return true; +} diff --git a/pcbnew/files.cpp b/pcbnew/files.cpp index cb3660e751..d373b54d05 100644 --- a/pcbnew/files.cpp +++ b/pcbnew/files.cpp @@ -69,10 +69,11 @@ static const wxChar autosavePrefix[] = wxT( "_autosave-" ); * @param aCtl is where to put the OpenProjectFiles() control bits. * * @param aFileName on entry is a probable choice, on return is the chosen filename. + * @param aKicadFilesOnly true to list kiacad pcb files plugins only, false to list all plugins. * * @return bool - true if chosen, else false if user aborted. */ -bool AskLoadBoardFileName( wxWindow* aParent, int* aCtl, wxString* aFileName ) +bool AskLoadBoardFileName( wxWindow* aParent, int* aCtl, wxString* aFileName, bool aKicadFilesOnly = false ) { // This is a subset of all PLUGINs which are trusted to be able to // load a BOARD. User may occasionally use the wrong plugin to load a @@ -93,7 +94,9 @@ bool AskLoadBoardFileName( wxWindow* aParent, int* aCtl, wxString* aFileName ) wxFileName fileName( *aFileName ); wxString fileFilters; - for( unsigned i=0; i 0 ) fileFilters += wxChar( '|' ); @@ -291,10 +294,12 @@ void PCB_EDIT_FRAME::Files_io( wxCommandEvent& event ) int open_ctl; wxString fileName; - if( !AskLoadBoardFileName( this, &open_ctl, &fileName ) ) + if( !AskLoadBoardFileName( this, &open_ctl, &fileName, true ) ) break; AppendBoardFile( fileName, open_ctl ); + + m_canvas->Refresh(); } break; @@ -343,7 +348,7 @@ void PCB_EDIT_FRAME::Files_io( wxCommandEvent& event ) // The KIWAY_PLAYER::OpenProjectFiles() API knows nothing about plugins, so // determine how to load the BOARD here, with minor assistance from KICTL_EAGLE_BRD // bit flag. -static IO_MGR::PCB_FILE_T plugin_type( const wxString& aFileName, int aCtl ) +IO_MGR::PCB_FILE_T plugin_type( const wxString& aFileName, int aCtl ) { IO_MGR::PCB_FILE_T pluginType; @@ -369,19 +374,6 @@ static IO_MGR::PCB_FILE_T plugin_type( const wxString& aFileName, int aCtl ) } -bool PCB_EDIT_FRAME::AppendBoardFile( const wxString& aFullFileName, int aCtl ) -{ - return false; - - // I'll never use it, and it was mucking up OpenProjectFiles() with - // complicated cruft. If you must, put it here separate from that important - // function. - - // Actually I think this serves too many masters. Just do panelization in - // a good gerber file manager. -} - - bool PCB_EDIT_FRAME::OpenProjectFiles( const std::vector& aFileSet, int aCtl ) { // This is for python: @@ -713,7 +705,7 @@ bool PCB_EDIT_FRAME::SavePcbFile( const wxString& aFileName, bool aCreateBackupF ); DisplayError( this, msg ); - lowerTxt = _( "Failed to create " ) + pcbFileName.GetFullPath(); + lowerTxt.Printf( _( "Failed to create '%s'" ), GetChars( pcbFileName.GetFullPath() ) ); AppendMsgPanel( upperTxt, lowerTxt, CYAN ); @@ -739,9 +731,9 @@ bool PCB_EDIT_FRAME::SavePcbFile( const wxString& aFileName, bool aCreateBackupF wxRemoveFile( autoSaveFileName.GetFullPath() ); if( !!backupFileName ) - upperTxt = _( "Backup file: " ) + backupFileName; + upperTxt.Printf( _( "Backup file: '%s'" ), GetChars( backupFileName ) ); - lowerTxt = _( "Wrote board file: " ) + pcbFileName.GetFullPath(); + lowerTxt.Printf( _( "Wrote board file: '%s'" ), GetChars( pcbFileName.GetFullPath() ) ); AppendMsgPanel( upperTxt, lowerTxt, CYAN ); diff --git a/pcbnew/menubar_pcbframe.cpp b/pcbnew/menubar_pcbframe.cpp index e791bc8a77..9f1e6777b1 100644 --- a/pcbnew/menubar_pcbframe.cpp +++ b/pcbnew/menubar_pcbframe.cpp @@ -43,6 +43,7 @@ void PCB_EDIT_FRAME::ReCreateMenuBar() { wxString text; wxMenuBar* menuBar = GetMenuBar(); + wxMenuItem * menutitem; wxFileHistory& fhist = Kiface().GetFileHistory(); @@ -95,10 +96,14 @@ void PCB_EDIT_FRAME::ReCreateMenuBar() KiBitmap( open_project_xpm ) ); } - AddMenuItem( filesMenu, ID_APPEND_FILE, + menutitem = AddMenuItem( filesMenu, ID_APPEND_FILE, _( "&Append Board" ), - _( "Append another Pcbnew board to the current loaded board" ), + _( "Append another Pcbnew board to the current loaded board. Available only when Pcbnew runs in stand alone mode" ), KiBitmap( import_xpm ) ); + if( ! Kiface().IsSingle() ) // disable when under a project mgr + menutitem->Enable( false ); + + filesMenu->AppendSeparator(); text = AddHotkeyName( _( "&Save" ), g_Board_Editor_Hokeys_Descr, HK_SAVE_BOARD ); diff --git a/pcbnew/tracepcb.cpp b/pcbnew/tracepcb.cpp index e4992ba937..ae15213d9f 100644 --- a/pcbnew/tracepcb.cpp +++ b/pcbnew/tracepcb.cpp @@ -67,7 +67,7 @@ void FOOTPRINT_EDIT_FRAME::RedrawActiveWindow( wxDC* DC, bool EraseBg ) GRSetDrawMode( DC, GR_COPY ); m_canvas->DrawBackGround( DC ); - DrawWorkSheet( DC, screen, 0, IU_PER_MILS, wxEmptyString ); + DrawWorkSheet( DC, screen, 0, IU_PER_MILS, wxEmptyString ); // Redraw the footprints for( MODULE* module = GetBoard()->m_Modules; module; module = module->Next() ) @@ -153,11 +153,19 @@ void BOARD::Draw( EDA_DRAW_PANEL* aPanel, wxDC* DC, GR_DRAWMODE aDrawMode, const */ for( TRACK* track = m_Track; track; track = track->Next() ) { + if( track->IsMoving() ) + continue; + track->Draw( aPanel, DC, aDrawMode ); } + // SEGZONE is outdated, only her for compatibility with + // very old designs for( SEGZONE* zone = m_Zone; zone; zone = zone->Next() ) { + if( zone->IsMoving() ) + continue; + zone->Draw( aPanel, DC, aDrawMode ); }