Commit 980ffac1 authored by jean-pierre charras's avatar jean-pierre charras
Browse files

Pcbnew: add append board function, only available when Pcbnew is run in...

Pcbnew: add append board function, only available when Pcbnew is run in standalone mode (outside a project), to allow a basic panelization.
(this function is not compatible with a project, because it breaks the coherency with the schematic)
parent 70a61b80
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -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
+221 −0
Original line number Diff line number Diff line
/*
 * 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 <fctsys.h>
#include <confirm.h>
#include <wxPcbStruct.h>
#include <pcbnew.h>
#include <io_mgr.h>
#include <class_module.h>
#include <class_zone.h>
#include <class_board.h>
#include <pcb_draw_panel_gal.h>

// 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<PCB_DRAW_PANEL_GAL*>( 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;
}
+12 −20
Original line number Diff line number Diff line
@@ -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<DIM( loaders );  ++i )
    unsigned pluginsCount = aKicadFilesOnly ? 2 : DIM( loaders );

    for( unsigned i=0; i < pluginsCount; ++i )
    {
        if( 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<wxString>& 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 );

+7 −2
Original line number Diff line number Diff line
@@ -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 );
+9 −1
Original line number Diff line number Diff line
@@ -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 );
    }