dialog_SVG_print.cpp 12.2 KB
Newer Older
1
/**
2
 * @file pcbnew/dialogs/dialog_SVG_print.cpp
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
 */

/*
 * This program source code file is part of KiCad, a free EDA CAD application.
 *
 * Copyright (C) 2012 Jean-Pierre Charras, jp.charras at wanadoo.fr
 * Copyright (C) 2012 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
 */

29

30 31 32 33 34 35
#include <fctsys.h>
#include <appl_wxstruct.h>
#include <common.h>
#include <class_drawpanel.h>
#include <wxBasePcbFrame.h>
#include <class_pcb_screen.h>
36
#include <base_units.h>
37
#include <convert_from_iu.h>
38
#include <wildcards_and_files_ext.h>
39 40 41 42 43 44

#include <pcbnew.h>
#include <pcbplot.h>
#include <printout_controler.h>
#include <class_board.h>
#include <dialog_SVG_print.h>
45

46
// Keys for configuration
47 48 49
#define PLOTSVGMODECOLOR_KEY        wxT( "PlotSVGModeColor" )
#define PLOTSVGPAGESIZEOPT_KEY      wxT( "PlotSVGPageOpt" )
#define PLOTSVGPLOT_BRD_EDGE_KEY    wxT( "PlotSVGBrdEdge" )
50

51
// reasonnable values for default pen width
52 53
#define WIDTH_MAX_VALUE (2 * IU_PER_MM)
#define WIDTH_MIN_VALUE (0.05 * IU_PER_MM)
54

55
// Local variables:
56 57
static long s_SelectedLayers = LAYER_BACK | LAYER_FRONT |
                               SILKSCREEN_LAYER_FRONT | SILKSCREEN_LAYER_BACK;
58

59
/*
60 61
 * DIALOG_SVG_PRINT functions
 */
62
DIALOG_SVG_PRINT::DIALOG_SVG_PRINT( EDA_DRAW_FRAME* parent ) :
63 64
    DIALOG_SVG_PRINT_base( parent )
{
65 66
    m_parent    = (PCB_BASE_FRAME*) parent;
    m_config    = wxGetApp().GetSettings();
67
    initDialog();
68 69
    GetSizer()->SetSizeHints( this );
    Centre();
70
}
71 72
bool DIALOG_SVG_PRINT::m_printMirror = false;
bool DIALOG_SVG_PRINT::m_oneFileOnly = false;
73 74


75
void DIALOG_SVG_PRINT::initDialog()
76
{
77 78 79
    m_board = m_parent->GetBoard();

    if( m_config )
80
    {
81
        m_config->Read( PLOTSVGMODECOLOR_KEY, &m_printBW, false );
82
        long ltmp;
83
        m_config->Read( PLOTSVGPAGESIZEOPT_KEY, &ltmp, 0 );
84
        m_rbSvgPageSizeOpt->SetSelection( ltmp );
85
        m_config->Read( PLOTSVGPLOT_BRD_EDGE_KEY, &ltmp, 1 );
86
        m_PrintBoardEdgesCtrl->SetValue( ltmp );
87 88
    }

89 90 91
    m_outputDirectory = m_parent->GetPlotSettings().GetOutputDirectory();
    m_outputDirectoryName->SetValue( m_outputDirectory );

92
    if( m_printBW )
93 94 95 96
        m_ModeColorOption->SetSelection( 1 );
    else
        m_ModeColorOption->SetSelection( 0 );

97 98 99 100
    m_printMirrorOpt->SetValue( m_printMirror );
    m_rbFileOpt->SetSelection( m_oneFileOnly ? 1 : 0 );


101
    AddUnitSymbol( *m_TextPenWidth, g_UserUnit );
102
    m_DialogDefaultPenSize->SetValue(
103
        ReturnStringFromValue( g_UserUnit, g_DrawDefaultLineThickness ) );
104

105
    // Create layers list
106 107
    LAYER_NUM layer;
    for( layer = FIRST_LAYER; layer < NB_PCB_LAYERS; ++layer )
108
    {
109 110
        if( !m_board->IsLayerEnabled( layer ) )
            m_boxSelectLayer[layer] = NULL;
111
        else
112 113
            m_boxSelectLayer[layer] =
                new wxCheckBox( this, -1, m_board->GetLayerName( layer ) );
114
    }
115

116
    // Add wxCheckBoxes in layers lists dialog
117
    // List layers in same order than in setup layers dialog
118
    // (Front or Top to Back or Bottom)
119 120
    DECLARE_LAYERS_ORDER_LIST( layersOrder );

121
    for( LAYER_NUM layer_idx = FIRST_LAYER; layer_idx < NB_PCB_LAYERS; ++layer_idx )
122 123 124
    {
        layer = layersOrder[layer_idx];

125
        wxASSERT( layer < NB_PCB_LAYERS );
126

127
        if( m_boxSelectLayer[layer] == NULL )
128 129
            continue;

130
        LAYER_MSK mask = GetLayerMask( layer );
131

132
        if( mask & s_SelectedLayers )
133
            m_boxSelectLayer[layer]->SetValue( true );
134

135
        if( layer <= LAST_COPPER_LAYER )
136
            m_CopperLayersBoxSizer->Add(  m_boxSelectLayer[layer],
137 138 139
                                          0,
                                          wxGROW | wxALL,
                                          1 );
140
        else
141
            m_TechnicalBoxSizer->Add(  m_boxSelectLayer[layer],
142 143 144
                                       0,
                                       wxGROW | wxALL,
                                       1 );
145 146
    }

147
    if( m_config )
148 149 150
    {
        wxString layerKey;

151
        for( LAYER_NUM layer = FIRST_LAYER; layer < NB_PCB_LAYERS; ++layer )
152 153
        {
            bool option;
154

155
            if( m_boxSelectLayer[layer] == NULL )
156
                continue;
157

158 159
            layerKey.Printf( OPTKEY_LAYERBASE, layer );

160 161
            if( m_config->Read( layerKey, &option ) )
                m_boxSelectLayer[layer]->SetValue( option );
162 163 164 165
        }
    }
}

166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201
void DIALOG_SVG_PRINT::OnOutputDirectoryBrowseClicked( wxCommandEvent& event )
{
    // Build the absolute path of current output plot directory
    // to preselect it when opening the dialog.
    wxFileName  fn( m_outputDirectoryName->GetValue() );
    wxString    path;

    if( fn.IsRelative() )
        path = wxGetCwd() + fn.GetPathSeparator() + m_outputDirectoryName->GetValue();
    else
        path = m_outputDirectoryName->GetValue();

    wxDirDialog dirDialog( this, _( "Select Output Directory" ), path );

    if( dirDialog.ShowModal() == wxID_CANCEL )
        return;

    wxFileName      dirName = wxFileName::DirName( dirDialog.GetPath() );

    wxMessageDialog dialog( this, _( "Use a relative path? " ),
                            _( "Plot Output Directory" ),
                            wxYES_NO | wxICON_QUESTION | wxYES_DEFAULT );

    if( dialog.ShowModal() == wxID_YES )
    {
        wxString boardFilePath = ( (wxFileName) m_board->GetFileName() ).GetPath();

        if( !dirName.MakeRelativeTo( boardFilePath ) )
            wxMessageBox( _(
                              "Cannot make path relative (target volume different from board file volume)!" ),
                          _( "Plot Output Directory" ), wxOK | wxICON_ERROR );
    }

    m_outputDirectoryName->SetValue( dirName.GetFullPath() );
    m_outputDirectory = m_outputDirectoryName->GetValue();
}
202 203 204

void DIALOG_SVG_PRINT::SetPenWidth()
{
205
    int pensize = ReturnValueFromTextCtrl( *m_DialogDefaultPenSize );
206

207
    if( pensize > WIDTH_MAX_VALUE )
208
    {
209
        pensize = WIDTH_MAX_VALUE;
210 211
    }

212
    if( pensize < WIDTH_MIN_VALUE )
213
    {
214
        pensize = WIDTH_MIN_VALUE;
215 216
    }

217 218
    g_DrawDefaultLineThickness = pensize;
    m_DialogDefaultPenSize->SetValue( ReturnStringFromValue( g_UserUnit, pensize ) );
219 220
}

221
void DIALOG_SVG_PRINT::ExportSVGFile( bool aOnlyOneFile )
222
{
223 224 225 226 227 228 229 230 231
    m_outputDirectory = m_outputDirectoryName->GetValue();

    // Create output directory if it does not exist (also transform it in
    // absolute form). Bail if it fails
    wxFileName outputDir = wxFileName::DirName( m_outputDirectory );
    wxString boardFilename = m_board->GetFileName();

    if( !EnsureOutputDirectory( &outputDir, boardFilename, m_messagesBox ) )
        return;
232

233 234
    m_printMirror = m_printMirrorOpt->GetValue();
    m_printBW = m_ModeColorOption->GetSelection();
235 236
    SetPenWidth();

237
    // Build layers mask
238
    LAYER_MSK printMaskLayer = NO_LAYERS;
239

240
    for( LAYER_NUM layer = FIRST_LAYER; layer < NB_PCB_LAYERS; ++layer )
241
    {
242
        if( m_boxSelectLayer[layer] && m_boxSelectLayer[layer]->GetValue() )
243
            printMaskLayer |= GetLayerMask( layer );
244
    }
245

246
    wxString    msg;
247
    for( LAYER_NUM layer = FIRST_LAYER; layer < NB_PCB_LAYERS; ++layer )
248
    {
249
        LAYER_MSK currlayer_mask = GetLayerMask( layer );
250
        if( (printMaskLayer & currlayer_mask ) == 0 )
251 252
            continue;

253
        wxString suffix = m_board->GetStandardLayerName( layer );
254

255 256
        if( aOnlyOneFile )
        {
257 258 259
            m_printMaskLayer = printMaskLayer;
            suffix = wxT( "-brd" );
         }
260
        else
261
        {
262
            m_printMaskLayer = currlayer_mask;
263
            suffix = m_board->GetStandardLayerName( layer );
264 265
        }

266 267
        wxFileName fn(boardFilename);
        BuildPlotFileName( &fn, outputDir.GetPath(), suffix, SVGFileExtension );
268

269
        if( m_PrintBoardEdgesCtrl->IsChecked() )
270
            m_printMaskLayer |= EDGE_LAYER;
271 272 273 274 275

        if( CreateSVGFile( fn.GetFullPath() ) )
            msg.Printf( _( "Plot: %s OK\n" ), GetChars( fn.GetFullPath() ) );
        else    // Error
            msg.Printf( _( "** Unable to create %s **\n" ), GetChars( fn.GetFullPath() ) );
276
        m_messagesBox->AppendText( msg );
277

278
        if( aOnlyOneFile )
279 280 281 282 283
            break;
    }
}


284
// Actual SVG file export  function.
285
bool DIALOG_SVG_PRINT::CreateSVGFile( const wxString& aFullFileName )
286
{
287
    PCB_PLOT_PARAMS m_plotOpts;
288

289
    m_plotOpts.SetPlotFrameRef( PrintPageRef() );
290 291

    // Adding drill marks, for copper layers
292
    if( (m_printMaskLayer & ALL_CU_LAYERS) )
293 294 295
        m_plotOpts.SetDrillMarksType( PCB_PLOT_PARAMS::FULL_DRILL_SHAPE );
    else
        m_plotOpts.SetDrillMarksType( PCB_PLOT_PARAMS::NO_DRILL_SHAPE );
296 297 298

    m_plotOpts.SetSkipPlotNPTH_Pads( false );

299 300
    m_plotOpts.SetMirror( m_printMirror );
    m_plotOpts.SetFormat( PLOT_FORMAT_SVG );
301
    EDA_COLOR_T color = UNSPECIFIED_COLOR;      // Used layer color to plot ref and value
302 303
    m_plotOpts.SetReferenceColor( color );
    m_plotOpts.SetValueColor( color );
304

305 306
    PAGE_INFO pageInfo = m_board->GetPageSettings();
    wxPoint axisorigin = m_board->GetOriginAxisPosition();
307

308 309
    if( PageIsBoardBoundarySize() )
    {
310 311
        EDA_RECT bbox = m_board->ComputeBoundingBox();
        PAGE_INFO currpageInfo = m_board->GetPageSettings();
312 313
        currpageInfo.SetWidthMils(  bbox.GetWidth() / IU_PER_MILS );
        currpageInfo.SetHeightMils( bbox.GetHeight() / IU_PER_MILS );
314
        m_board->SetPageSettings( currpageInfo );
315 316
        m_plotOpts.SetUseAuxOrigin( true );
        wxPoint origin = bbox.GetOrigin();
317
        m_board->SetOriginAxisPosition( origin );
318
    }
319

320
    LOCALE_IO    toggle;
321
    SVG_PLOTTER* plotter = (SVG_PLOTTER*) StartPlotBoard( m_board,
322 323
                                              &m_plotOpts, aFullFileName,
                                              wxEmptyString );
324

325 326 327
    if( plotter )
    {
        plotter->SetColorMode( m_ModeColorOption->GetSelection() == 0 );
328 329
        PlotStandardLayer( m_board, plotter, m_printMaskLayer, m_plotOpts );
        plotter->EndPlot();
330
    }
331

332
    delete plotter;
333 334
    m_board->SetOriginAxisPosition( axisorigin );
    m_board->SetPageSettings( pageInfo );
335

336
    return true;
337 338
}

339
void DIALOG_SVG_PRINT::OnButtonPlot( wxCommandEvent& event )
340
{
341 342
    m_oneFileOnly = m_rbFileOpt->GetSelection() == 1;
    ExportSVGFile( m_oneFileOnly );
343 344 345 346 347 348 349 350 351 352 353
}


void DIALOG_SVG_PRINT::OnButtonCancelClick( wxCommandEvent& event )
{
    Close();
}


void DIALOG_SVG_PRINT::OnCloseWindow( wxCloseEvent& event )
{
354
    SetPenWidth();
355 356 357
    m_printBW = m_ModeColorOption->GetSelection();
    m_oneFileOnly = m_rbFileOpt->GetSelection() == 1;

358
    if( m_config )
359
    {
360 361 362
        m_config->Write( PLOTSVGMODECOLOR_KEY, m_printBW );
        m_config->Write( PLOTSVGPAGESIZEOPT_KEY, m_rbSvgPageSizeOpt->GetSelection() );
        m_config->Write( PLOTSVGPLOT_BRD_EDGE_KEY, m_PrintBoardEdgesCtrl->GetValue() );
363

364
        wxString layerKey;
365

366
        for( LAYER_NUM layer = FIRST_LAYER; layer < NB_PCB_LAYERS; ++layer )
367
        {
368
            if( m_boxSelectLayer[layer] == NULL )
369
                continue;
370

371
            layerKey.Printf( OPTKEY_LAYERBASE, layer );
372
            m_config->Write( layerKey, m_boxSelectLayer[layer]->IsChecked() );
373 374
        }
    }
375

376 377 378 379 380 381 382 383 384 385 386 387 388 389
    // Set output directory and replace backslashes with forward ones
    wxString dirStr;
    dirStr = m_outputDirectoryName->GetValue();
    dirStr.Replace( wxT( "\\" ), wxT( "/" ) );

    if( dirStr != m_parent->GetPlotSettings().GetOutputDirectory() )
    {
        PCB_PLOT_PARAMS tempOptions( m_parent->GetPlotSettings() );
        tempOptions.SetOutputDirectory( dirStr );
        m_parent->SetPlotSettings( tempOptions );
        m_parent->OnModify();
    }


390 391
    EndModal( 0 );
}