dialog_SVG_print.cpp 12.5 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
#include <macros.h>
40 41
#include <reporter.h>
#include <confirm.h>
42 43 44 45 46 47

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

49
// Keys for configuration
50 51 52
#define PLOTSVGMODECOLOR_KEY        wxT( "PlotSVGModeColor" )
#define PLOTSVGPAGESIZEOPT_KEY      wxT( "PlotSVGPageOpt" )
#define PLOTSVGPLOT_BRD_EDGE_KEY    wxT( "PlotSVGBrdEdge" )
53

54
// reasonable values for default pen width
55 56
#define WIDTH_MAX_VALUE (2 * IU_PER_MM)
#define WIDTH_MIN_VALUE (0.05 * IU_PER_MM)
57

58
// Local variables:
59 60
static long s_SelectedLayers = LAYER_BACK | LAYER_FRONT |
                               SILKSCREEN_LAYER_FRONT | SILKSCREEN_LAYER_BACK;
61

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


78
void DIALOG_SVG_PRINT::initDialog()
79
{
80 81 82
    m_board = m_parent->GetBoard();

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

92 93 94
    m_outputDirectory = m_parent->GetPlotSettings().GetOutputDirectory();
    m_outputDirectoryName->SetValue( m_outputDirectory );

95
    if( m_printBW )
96 97 98 99
        m_ModeColorOption->SetSelection( 1 );
    else
        m_ModeColorOption->SetSelection( 0 );

100 101 102 103
    m_printMirrorOpt->SetValue( m_printMirror );
    m_rbFileOpt->SetSelection( m_oneFileOnly ? 1 : 0 );


104
    AddUnitSymbol( *m_TextPenWidth, g_UserUnit );
105
    m_DialogDefaultPenSize->SetValue(
106
        ReturnStringFromValue( g_UserUnit, g_DrawDefaultLineThickness ) );
107

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

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

124
    for( LAYER_NUM layer_idx = FIRST_LAYER; layer_idx < NB_PCB_LAYERS; ++layer_idx )
125 126 127
    {
        layer = layersOrder[layer_idx];

128
        wxASSERT( layer < NB_PCB_LAYERS );
129

130
        if( m_boxSelectLayer[layer] == NULL )
131 132
            continue;

133
        LAYER_MSK mask = GetLayerMask( layer );
134

135
        if( mask & s_SelectedLayers )
136
            m_boxSelectLayer[layer]->SetValue( true );
137

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

150
    if( m_config )
151 152 153
    {
        wxString layerKey;

154
        for( LAYER_NUM layer = FIRST_LAYER; layer < NB_PCB_LAYERS; ++layer )
155 156
        {
            bool option;
157

158
            if( m_boxSelectLayer[layer] == NULL )
159
                continue;
160

161 162
            layerKey.Printf( OPTKEY_LAYERBASE, layer );

163 164
            if( m_config->Read( layerKey, &option ) )
                m_boxSelectLayer[layer]->SetValue( option );
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
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 ) )
198
            wxMessageBox( _( "Cannot make path relative (target volume different from board file volume)!" ),
199 200 201 202 203 204
                          _( "Plot Output Directory" ), wxOK | wxICON_ERROR );
    }

    m_outputDirectoryName->SetValue( dirName.GetFullPath() );
    m_outputDirectory = m_outputDirectoryName->GetValue();
}
205

206

207 208
void DIALOG_SVG_PRINT::SetPenWidth()
{
209
    int pensize = ReturnValueFromTextCtrl( *m_DialogDefaultPenSize );
210

211
    if( pensize > WIDTH_MAX_VALUE )
212
    {
213
        pensize = WIDTH_MAX_VALUE;
214 215
    }

216
    if( pensize < WIDTH_MIN_VALUE )
217
    {
218
        pensize = WIDTH_MIN_VALUE;
219 220
    }

221 222
    g_DrawDefaultLineThickness = pensize;
    m_DialogDefaultPenSize->SetValue( ReturnStringFromValue( g_UserUnit, pensize ) );
223 224
}

225

226
void DIALOG_SVG_PRINT::ExportSVGFile( bool aOnlyOneFile )
227
{
228 229 230 231 232 233
    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();
234
    WX_TEXT_CTRL_REPORTER reporter( m_messagesBox );
235

236 237 238 239 240 241
    if( !EnsureOutputDirectory( &outputDir, boardFilename, &reporter ) )
    {
        wxString msg;
        msg.Printf( _( "Could not write plot files to folder \"%s\"." ),
                    GetChars( outputDir.GetPath() ) );
        DisplayError( this, msg );
242
        return;
243
    }
244

245 246
    m_printMirror = m_printMirrorOpt->GetValue();
    m_printBW = m_ModeColorOption->GetSelection();
247 248
    SetPenWidth();

249
    // Build layers mask
250
    LAYER_MSK printMaskLayer = NO_LAYERS;
251

252
    for( LAYER_NUM layer = FIRST_LAYER; layer < NB_PCB_LAYERS; ++layer )
253
    {
254
        if( m_boxSelectLayer[layer] && m_boxSelectLayer[layer]->GetValue() )
255
            printMaskLayer |= GetLayerMask( layer );
256
    }
257

258
    wxString    msg;
259

260
    for( LAYER_NUM layer = FIRST_LAYER; layer < NB_PCB_LAYERS; ++layer )
261
    {
262
        LAYER_MSK currlayer_mask = GetLayerMask( layer );
263

264
        if( (printMaskLayer & currlayer_mask ) == 0 )
265 266
            continue;

267
        wxString suffix = m_board->GetStandardLayerName( layer );
268

269 270
        if( aOnlyOneFile )
        {
271 272
            m_printMaskLayer = printMaskLayer;
            suffix = wxT( "-brd" );
273
        }
274
        else
275
        {
276
            m_printMaskLayer = currlayer_mask;
277
            suffix = m_board->GetStandardLayerName( layer );
278 279
        }

280 281
        wxFileName fn(boardFilename);
        BuildPlotFileName( &fn, outputDir.GetPath(), suffix, SVGFileExtension );
282

283
        if( m_PrintBoardEdgesCtrl->IsChecked() )
284
            m_printMaskLayer |= EDGE_LAYER;
285 286 287 288 289

        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() ) );
290
        m_messagesBox->AppendText( msg );
291

292
        if( aOnlyOneFile )
293 294 295 296 297
            break;
    }
}


298
// Actual SVG file export  function.
299
bool DIALOG_SVG_PRINT::CreateSVGFile( const wxString& aFullFileName )
300
{
301
    PCB_PLOT_PARAMS m_plotOpts;
302

303
    m_plotOpts.SetPlotFrameRef( PrintPageRef() );
304 305

    // Adding drill marks, for copper layers
306
    if( (m_printMaskLayer & ALL_CU_LAYERS) )
307 308 309
        m_plotOpts.SetDrillMarksType( PCB_PLOT_PARAMS::FULL_DRILL_SHAPE );
    else
        m_plotOpts.SetDrillMarksType( PCB_PLOT_PARAMS::NO_DRILL_SHAPE );
310 311 312

    m_plotOpts.SetSkipPlotNPTH_Pads( false );

313 314
    m_plotOpts.SetMirror( m_printMirror );
    m_plotOpts.SetFormat( PLOT_FORMAT_SVG );
315
    EDA_COLOR_T color = UNSPECIFIED_COLOR;      // Used layer color to plot ref and value
316 317
    m_plotOpts.SetReferenceColor( color );
    m_plotOpts.SetValueColor( color );
318

319 320
    PAGE_INFO pageInfo = m_board->GetPageSettings();
    wxPoint axisorigin = m_board->GetOriginAxisPosition();
321

322 323
    if( PageIsBoardBoundarySize() )
    {
324 325
        EDA_RECT bbox = m_board->ComputeBoundingBox();
        PAGE_INFO currpageInfo = m_board->GetPageSettings();
326 327
        currpageInfo.SetWidthMils(  bbox.GetWidth() / IU_PER_MILS );
        currpageInfo.SetHeightMils( bbox.GetHeight() / IU_PER_MILS );
328
        m_board->SetPageSettings( currpageInfo );
329 330
        m_plotOpts.SetUseAuxOrigin( true );
        wxPoint origin = bbox.GetOrigin();
331
        m_board->SetOriginAxisPosition( origin );
332
    }
333

334
    LOCALE_IO    toggle;
335
    SVG_PLOTTER* plotter = (SVG_PLOTTER*) StartPlotBoard( m_board,
336 337
                                                          &m_plotOpts, aFullFileName,
                                                          wxEmptyString );
338

339 340 341
    if( plotter )
    {
        plotter->SetColorMode( m_ModeColorOption->GetSelection() == 0 );
342 343
        PlotStandardLayer( m_board, plotter, m_printMaskLayer, m_plotOpts );
        plotter->EndPlot();
344
    }
345

346
    delete plotter;
347 348
    m_board->SetOriginAxisPosition( axisorigin );
    m_board->SetPageSettings( pageInfo );
349

350
    return true;
351 352
}

353
void DIALOG_SVG_PRINT::OnButtonPlot( wxCommandEvent& event )
354
{
355 356
    m_oneFileOnly = m_rbFileOpt->GetSelection() == 1;
    ExportSVGFile( m_oneFileOnly );
357 358 359 360 361 362 363 364 365 366 367
}


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


void DIALOG_SVG_PRINT::OnCloseWindow( wxCloseEvent& event )
{
368
    SetPenWidth();
369 370 371
    m_printBW = m_ModeColorOption->GetSelection();
    m_oneFileOnly = m_rbFileOpt->GetSelection() == 1;

372
    if( m_config )
373
    {
374 375 376
        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() );
377

378
        wxString layerKey;
379

380
        for( LAYER_NUM layer = FIRST_LAYER; layer < NB_PCB_LAYERS; ++layer )
381
        {
382
            if( m_boxSelectLayer[layer] == NULL )
383
                continue;
384

385
            layerKey.Printf( OPTKEY_LAYERBASE, layer );
386
            m_config->Write( layerKey, m_boxSelectLayer[layer]->IsChecked() );
387 388
        }
    }
389

390 391 392 393 394 395 396 397 398 399 400 401 402
    // 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();
    }

403 404
    EndModal( 0 );
}