kicad/pcbnew/dialogs/dialog_plot.cpp

826 lines
28 KiB
C++

/**
* @file dialog_plot.cpp
*/
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* 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
*/
#include <kiface_i.h>
#include <plot_common.h>
#include <confirm.h>
#include <wxPcbStruct.h>
#include <pcbplot.h>
#include <base_units.h>
#include <macros.h>
#include <reporter.h>
#include <class_board.h>
#include <wx/ffile.h>
#include <dialog_plot.h>
DIALOG_PLOT::DIALOG_PLOT( PCB_EDIT_FRAME* aParent ) :
DIALOG_PLOT_BASE( aParent ), m_parent( aParent ),
m_board( aParent->GetBoard() ),
m_plotOpts( aParent->GetPlotSettings() )
{
m_config = Kiface().KifaceSettings();
m_brdSettings = m_board->GetDesignSettings();
Init_Dialog();
GetSizer()->Fit( this );
GetSizer()->SetSizeHints( this );
}
void DIALOG_PLOT::Init_Dialog()
{
wxString msg;
wxFileName fileName;
m_config->Read( OPTKEY_PLOT_X_FINESCALE_ADJ, &m_XScaleAdjust );
m_config->Read( OPTKEY_PLOT_Y_FINESCALE_ADJ, &m_YScaleAdjust );
// m_PSWidthAdjust is stored in mm in user config
double dtmp;
m_config->Read( CONFIG_PS_FINEWIDTH_ADJ, &dtmp, 0 );
m_PSWidthAdjust = KiROUND( dtmp * IU_PER_MM );
// The reasonable width correction value must be in a range of
// [-(MinTrackWidth-1), +(MinClearanceValue-1)] decimils.
m_widthAdjustMinValue = -(m_board->GetDesignSettings().m_TrackMinWidth - 1);
m_widthAdjustMaxValue = m_board->GetSmallestClearanceValue() - 1;
switch( m_plotOpts.GetFormat() )
{
default:
case PLOT_FORMAT_GERBER:
m_plotFormatOpt->SetSelection( 0 );
break;
case PLOT_FORMAT_POST:
m_plotFormatOpt->SetSelection( 1 );
break;
case PLOT_FORMAT_SVG:
m_plotFormatOpt->SetSelection( 2 );
break;
case PLOT_FORMAT_DXF:
m_plotFormatOpt->SetSelection( 3 );
break;
case PLOT_FORMAT_HPGL:
m_plotFormatOpt->SetSelection( 4 );
break;
case PLOT_FORMAT_PDF:
m_plotFormatOpt->SetSelection( 5 );
break;
}
msg = StringFromValue( g_UserUnit, m_brdSettings.m_SolderMaskMargin, true );
m_SolderMaskMarginCurrValue->SetLabel( msg );
msg = StringFromValue( g_UserUnit, m_brdSettings.m_SolderMaskMinWidth, true );
m_SolderMaskMinWidthCurrValue->SetLabel( msg );
// Set units and value for HPGL pen size (this param in in mils).
AddUnitSymbol( *m_textPenSize, g_UserUnit );
msg = StringFromValue( g_UserUnit,
m_plotOpts.GetHPGLPenDiameter() * IU_PER_MILS );
m_HPGLPenSizeOpt->AppendText( msg );
// Set units and value for HPGL pen overlay (this param in in mils).
AddUnitSymbol( *m_textPenOvr, g_UserUnit );
msg = StringFromValue( g_UserUnit,
m_plotOpts.GetHPGLPenOverlay() * IU_PER_MILS );
m_HPGLPenOverlayOpt->AppendText( msg );
AddUnitSymbol( *m_textDefaultPenSize, g_UserUnit );
msg = StringFromValue( g_UserUnit, m_plotOpts.GetLineWidth() );
m_linesWidth->AppendText( msg );
// Set units for PS global width correction.
AddUnitSymbol( *m_textPSFineAdjustWidth, g_UserUnit );
m_useAuxOriginCheckBox->SetValue( m_plotOpts.GetUseAuxOrigin() );
// Test for a reasonable scale value. Set to 1 if problem
if( m_XScaleAdjust < PLOT_MIN_SCALE || m_YScaleAdjust < PLOT_MIN_SCALE
|| m_XScaleAdjust > PLOT_MAX_SCALE || m_YScaleAdjust > PLOT_MAX_SCALE )
m_XScaleAdjust = m_YScaleAdjust = 1.0;
msg.Printf( wxT( "%f" ), m_XScaleAdjust );
m_fineAdjustXscaleOpt->AppendText( msg );
msg.Printf( wxT( "%f" ), m_YScaleAdjust );
m_fineAdjustYscaleOpt->AppendText( msg );
// Test for a reasonable PS width correction value. Set to 0 if problem.
if( m_PSWidthAdjust < m_widthAdjustMinValue || m_PSWidthAdjust > m_widthAdjustMaxValue )
m_PSWidthAdjust = 0.;
msg.Printf( wxT( "%f" ), To_User_Unit( g_UserUnit, m_PSWidthAdjust ) );
m_PSFineAdjustWidthOpt->AppendText( msg );
m_plotPSNegativeOpt->SetValue( m_plotOpts.GetNegative() );
m_forcePSA4OutputOpt->SetValue( m_plotOpts.GetA4Output() );
// List layers in same order than in setup layers dialog
// (Front or Top to Back or Bottom)
DECLARE_LAYERS_ORDER_LIST( layersOrder );
int layerIndex, checkIndex;
LAYER_NUM layer;
for( layerIndex = 0; layerIndex < NB_LAYERS; layerIndex++ )
{
layer = layersOrder[layerIndex];
wxASSERT( layer < NB_LAYERS );
if( !m_board->IsLayerEnabled( layer ) )
continue;
m_layerList.push_back( layer );
checkIndex = m_layerCheckListBox->Append( m_board->GetLayerName( layer ) );
if( m_plotOpts.GetLayerSelection() & GetLayerMask( layer ) )
m_layerCheckListBox->Check( checkIndex );
}
// Option for using proper Gerber extensions
m_useGerberExtensions->SetValue( m_plotOpts.GetUseGerberExtensions() );
// Option for excluding contents of "Edges Pcb" layer
m_excludeEdgeLayerOpt->SetValue( m_plotOpts.GetExcludeEdgeLayer() );
m_subtractMaskFromSilk->SetValue( m_plotOpts.GetSubtractMaskFromSilk() );
// Option to plot page references:
m_plotSheetRef->SetValue( m_plotOpts.GetPlotFrameRef() );
// Option to allow pads on silkscreen layers
m_plotPads_on_Silkscreen->SetValue( m_plotOpts.GetPlotPadsOnSilkLayer() );
// Options to plot texts on footprints
m_plotModuleValueOpt->SetValue( m_plotOpts.GetPlotValue() );
m_plotModuleRefOpt->SetValue( m_plotOpts.GetPlotReference() );
m_plotTextOther->SetValue( m_plotOpts.GetPlotOtherText() );
m_plotInvisibleText->SetValue( m_plotOpts.GetPlotInvisibleText() );
// Options to plot pads and vias holes
m_drillShapeOpt->SetSelection( m_plotOpts.GetDrillMarksType() );
// Scale option
m_scaleOpt->SetSelection( m_plotOpts.GetScaleSelection() );
// Plot mode
m_plotModeOpt->SetSelection( m_plotOpts.GetMode() );
// Plot mirror option
m_plotMirrorOpt->SetValue( m_plotOpts.GetMirror() );
// Put vias on mask layer
m_plotNoViaOnMaskOpt->SetValue( m_plotOpts.GetPlotViaOnMaskLayer() );
// Output directory
m_outputDirectoryName->SetValue( m_plotOpts.GetOutputDirectory() );
// Update options values:
wxCommandEvent cmd_event;
SetPlotFormat( cmd_event );
OnSetScaleOpt( cmd_event );
}
void DIALOG_PLOT::OnQuit( wxCommandEvent& event )
{
Close( true ); // true is to force the frame to close
}
void DIALOG_PLOT::OnClose( wxCloseEvent& event )
{
applyPlotSettings();
EndModal( 0 );
}
// A helper function to show a popup menu, when the dialog is right clicked.
void DIALOG_PLOT::OnRightClick( wxMouseEvent& event )
{
PopupMenu( m_popMenu );
}
// Select or deselect groups of layers in the layers list:
#include <layers_id_colors_and_visibility.h>
void DIALOG_PLOT::OnPopUpLayers( wxCommandEvent& event )
{
unsigned int i;
switch( event.GetId() )
{
case ID_LAYER_FAB: // Select layers usually needed to build a board
for( i = 0; i < m_layerList.size(); i++ )
{
LAYER_MSK layermask = GetLayerMask( m_layerList[ i ] );
if( layermask & ( ALL_CU_LAYERS | ALL_TECH_LAYERS ) )
m_layerCheckListBox->Check( i, true );
else
m_layerCheckListBox->Check( i, false );
}
break;
case ID_SELECT_COPPER_LAYERS:
for( i = 0; i < m_layerList.size(); i++ )
{
if( m_layerList[i] <= LAST_COPPER_LAYER )
m_layerCheckListBox->Check( i, true );
}
break;
case ID_DESELECT_COPPER_LAYERS:
for( i = 0; i < m_layerList.size(); i++ )
{
if( m_layerList[i] <= LAST_COPPER_LAYER )
m_layerCheckListBox->Check( i, false );
}
break;
case ID_SELECT_ALL_LAYERS:
for( i = 0; i < m_layerList.size(); i++ )
m_layerCheckListBox->Check( i, true );
break;
case ID_DESELECT_ALL_LAYERS:
for( i = 0; i < m_layerList.size(); i++ )
m_layerCheckListBox->Check( i, false );
break;
default:
break;
}
}
void DIALOG_PLOT::CreateDrillFile( wxCommandEvent& event )
{
m_parent->InstallDrillFrame( event );
}
void DIALOG_PLOT::OnSetScaleOpt( wxCommandEvent& event )
{
/* Disable sheet reference for scale != 1:1 */
bool scale1 = ( m_scaleOpt->GetSelection() == 1 );
m_plotSheetRef->Enable( scale1 );
if( !scale1 )
m_plotSheetRef->SetValue( false );
}
void DIALOG_PLOT::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_parent->GetBoard()->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() );
}
PlotFormat DIALOG_PLOT::GetPlotFormat()
{
// plot format id's are ordered like displayed in m_plotFormatOpt
static const PlotFormat plotFmt[] =
{
PLOT_FORMAT_GERBER,
PLOT_FORMAT_POST,
PLOT_FORMAT_SVG,
PLOT_FORMAT_DXF,
PLOT_FORMAT_HPGL,
PLOT_FORMAT_PDF
};
return plotFmt[ m_plotFormatOpt->GetSelection() ];
}
// Enable or disable widgets according to the plot format selected
// and clear also some optional values
void DIALOG_PLOT::SetPlotFormat( wxCommandEvent& event )
{
switch( GetPlotFormat() )
{
case PLOT_FORMAT_PDF:
case PLOT_FORMAT_SVG:
m_drillShapeOpt->Enable( true );
m_plotModeOpt->Enable( false );
m_plotModeOpt->SetSelection( 1 );
m_plotMirrorOpt->Enable( true );
m_useAuxOriginCheckBox->Enable( false );
m_useAuxOriginCheckBox->SetValue( false );
m_linesWidth->Enable( true );
m_HPGLPenSizeOpt->Enable( false );
m_HPGLPenOverlayOpt->Enable( false );
m_excludeEdgeLayerOpt->Enable( true );
m_subtractMaskFromSilk->Enable( false );
m_subtractMaskFromSilk->SetValue( false );
m_useGerberExtensions->Enable( false );
m_useGerberExtensions->SetValue( false );
m_scaleOpt->Enable( false );
m_scaleOpt->SetSelection( 1 );
m_fineAdjustXscaleOpt->Enable( false );
m_fineAdjustYscaleOpt->Enable( false );
m_PSFineAdjustWidthOpt->Enable( false );
m_plotPSNegativeOpt->Enable( true );
m_forcePSA4OutputOpt->Enable( false );
m_forcePSA4OutputOpt->SetValue( false );
m_PlotOptionsSizer->Hide( m_GerberOptionsSizer );
m_PlotOptionsSizer->Hide( m_HPGLOptionsSizer );
m_PlotOptionsSizer->Hide( m_PSOptionsSizer );
break;
case PLOT_FORMAT_POST:
m_drillShapeOpt->Enable( true );
m_plotModeOpt->Enable( true );
m_plotMirrorOpt->Enable( true );
m_useAuxOriginCheckBox->Enable( false );
m_useAuxOriginCheckBox->SetValue( false );
m_linesWidth->Enable( true );
m_HPGLPenSizeOpt->Enable( false );
m_HPGLPenOverlayOpt->Enable( false );
m_excludeEdgeLayerOpt->Enable( true );
m_subtractMaskFromSilk->Enable( false );
m_subtractMaskFromSilk->SetValue( false );
m_useGerberExtensions->Enable( false );
m_useGerberExtensions->SetValue( false );
m_scaleOpt->Enable( true );
m_fineAdjustXscaleOpt->Enable( true );
m_fineAdjustYscaleOpt->Enable( true );
m_PSFineAdjustWidthOpt->Enable( true );
m_plotPSNegativeOpt->Enable( true );
m_forcePSA4OutputOpt->Enable( true );
m_PlotOptionsSizer->Hide( m_GerberOptionsSizer );
m_PlotOptionsSizer->Hide( m_HPGLOptionsSizer );
m_PlotOptionsSizer->Show( m_PSOptionsSizer );
break;
case PLOT_FORMAT_GERBER:
m_drillShapeOpt->Enable( false );
m_drillShapeOpt->SetSelection( 0 );
m_plotModeOpt->Enable( false );
m_plotModeOpt->SetSelection( 1 );
m_plotMirrorOpt->Enable( false );
m_plotMirrorOpt->SetValue( false );
m_useAuxOriginCheckBox->Enable( true );
m_linesWidth->Enable( true );
m_HPGLPenSizeOpt->Enable( false );
m_HPGLPenOverlayOpt->Enable( false );
m_excludeEdgeLayerOpt->Enable( true );
m_subtractMaskFromSilk->Enable( true );
m_useGerberExtensions->Enable( true );
m_scaleOpt->Enable( false );
m_scaleOpt->SetSelection( 1 );
m_fineAdjustXscaleOpt->Enable( false );
m_fineAdjustYscaleOpt->Enable( false );
m_PSFineAdjustWidthOpt->Enable( false );
m_plotPSNegativeOpt->Enable( false );
m_plotPSNegativeOpt->SetValue( false );
m_forcePSA4OutputOpt->Enable( false );
m_forcePSA4OutputOpt->SetValue( false );
m_PlotOptionsSizer->Show( m_GerberOptionsSizer );
m_PlotOptionsSizer->Hide( m_HPGLOptionsSizer );
m_PlotOptionsSizer->Hide( m_PSOptionsSizer );
break;
case PLOT_FORMAT_HPGL:
m_drillShapeOpt->Enable( true );
m_plotModeOpt->Enable( true );
m_plotMirrorOpt->Enable( true );
m_useAuxOriginCheckBox->Enable( false );
m_useAuxOriginCheckBox->SetValue( false );
m_linesWidth->Enable( false );
m_HPGLPenSizeOpt->Enable( true );
m_HPGLPenOverlayOpt->Enable( true );
m_excludeEdgeLayerOpt->Enable( true );
m_subtractMaskFromSilk->Enable( false );
m_subtractMaskFromSilk->SetValue( false );
m_useGerberExtensions->Enable( false );
m_useGerberExtensions->SetValue( false );
m_scaleOpt->Enable( true );
m_fineAdjustXscaleOpt->Enable( false );
m_fineAdjustYscaleOpt->Enable( false );
m_PSFineAdjustWidthOpt->Enable( false );
m_plotPSNegativeOpt->SetValue( false );
m_plotPSNegativeOpt->Enable( false );
m_forcePSA4OutputOpt->Enable( true );
m_PlotOptionsSizer->Hide( m_GerberOptionsSizer );
m_PlotOptionsSizer->Show( m_HPGLOptionsSizer );
m_PlotOptionsSizer->Hide( m_PSOptionsSizer );
break;
case PLOT_FORMAT_DXF:
m_drillShapeOpt->Enable( true );
m_plotModeOpt->Enable( true );
m_plotMirrorOpt->Enable( false );
m_plotMirrorOpt->SetValue( false );
m_useAuxOriginCheckBox->Enable( true );
m_linesWidth->Enable( false );
m_HPGLPenSizeOpt->Enable( false );
m_HPGLPenOverlayOpt->Enable( false );
m_excludeEdgeLayerOpt->Enable( true );
m_subtractMaskFromSilk->Enable( false );
m_subtractMaskFromSilk->SetValue( false );
m_useGerberExtensions->Enable( false );
m_useGerberExtensions->SetValue( false );
m_scaleOpt->Enable( false );
m_scaleOpt->SetSelection( 1 );
m_fineAdjustXscaleOpt->Enable( false );
m_fineAdjustYscaleOpt->Enable( false );
m_PSFineAdjustWidthOpt->Enable( false );
m_plotPSNegativeOpt->Enable( false );
m_plotPSNegativeOpt->SetValue( false );
m_forcePSA4OutputOpt->Enable( false );
m_forcePSA4OutputOpt->SetValue( false );
m_PlotOptionsSizer->Show( m_GerberOptionsSizer );
m_PlotOptionsSizer->Hide( m_HPGLOptionsSizer );
m_PlotOptionsSizer->Hide( m_PSOptionsSizer );
break;
default:
wxASSERT( false );
}
/* Update the interlock between scale and frame reference
* (scaling would mess up the frame border...) */
OnSetScaleOpt( event );
Layout();
m_MainSizer->SetSizeHints( this );
}
// A helper function to "clip" aValue between aMin and aMax
// and write result in * aResult
// return false if clipped, true if aValue is just copied into * aResult
static bool setDouble( double* aResult, double aValue, double aMin, double aMax )
{
if( aValue < aMin )
{
*aResult = aMin;
return false;
}
else if( aValue > aMax )
{
*aResult = aMax;
return false;
}
*aResult = aValue;
return true;
}
static bool setInt( int* aResult, int aValue, int aMin, int aMax )
{
if( aValue < aMin )
{
*aResult = aMin;
return false;
}
else if( aValue > aMax )
{
*aResult = aMax;
return false;
}
*aResult = aValue;
return true;
}
void DIALOG_PLOT::applyPlotSettings()
{
PCB_PLOT_PARAMS tempOptions;
tempOptions.SetExcludeEdgeLayer( m_excludeEdgeLayerOpt->GetValue() );
tempOptions.SetSubtractMaskFromSilk( m_subtractMaskFromSilk->GetValue() );
tempOptions.SetPlotFrameRef( m_plotSheetRef->GetValue() );
tempOptions.SetPlotPadsOnSilkLayer( m_plotPads_on_Silkscreen->GetValue() );
tempOptions.SetUseAuxOrigin( m_useAuxOriginCheckBox->GetValue() );
tempOptions.SetPlotValue( m_plotModuleValueOpt->GetValue() );
tempOptions.SetPlotReference( m_plotModuleRefOpt->GetValue() );
tempOptions.SetPlotOtherText( m_plotTextOther->GetValue() );
tempOptions.SetPlotInvisibleText( m_plotInvisibleText->GetValue() );
tempOptions.SetScaleSelection( m_scaleOpt->GetSelection() );
tempOptions.SetDrillMarksType( static_cast<PCB_PLOT_PARAMS::DrillMarksType>
( m_drillShapeOpt->GetSelection() ) );
tempOptions.SetMirror( m_plotMirrorOpt->GetValue() );
tempOptions.SetMode( static_cast<EDA_DRAW_MODE_T>( m_plotModeOpt->GetSelection() ) );
tempOptions.SetPlotViaOnMaskLayer( m_plotNoViaOnMaskOpt->GetValue() );
// Update settings from text fields. Rewrite values back to the fields,
// since the values may have been constrained by the setters.
// read HPLG pen size (this param is stored in mils)
wxString msg = m_HPGLPenSizeOpt->GetValue();
int tmp = ValueFromString( g_UserUnit, msg ) / IU_PER_MILS;
if( !tempOptions.SetHPGLPenDiameter( tmp ) )
{
msg = StringFromValue( g_UserUnit, tempOptions.GetHPGLPenDiameter() * IU_PER_MILS );
m_HPGLPenSizeOpt->SetValue( msg );
msg.Printf( _( "HPGL pen size constrained!\n" ) );
m_messagesBox->AppendText( msg );
}
// Read HPGL pen overlay (this param is stored in mils)
msg = m_HPGLPenOverlayOpt->GetValue();
tmp = ValueFromString( g_UserUnit, msg ) / IU_PER_MILS;
if( !tempOptions.SetHPGLPenOverlay( tmp ) )
{
msg = StringFromValue( g_UserUnit,
tempOptions.GetHPGLPenOverlay() * IU_PER_MILS );
m_HPGLPenOverlayOpt->SetValue( msg );
msg.Printf( _( "HPGL pen overlay constrained!\n" ) );
m_messagesBox->AppendText( msg );
}
// Default linewidth
msg = m_linesWidth->GetValue();
tmp = ValueFromString( g_UserUnit, msg );
if( !tempOptions.SetLineWidth( tmp ) )
{
msg = StringFromValue( g_UserUnit, tempOptions.GetLineWidth() );
m_linesWidth->SetValue( msg );
msg.Printf( _( "Default line width constrained!\n" ) );
m_messagesBox->AppendText( msg );
}
// X scale
double tmpDouble;
msg = m_fineAdjustXscaleOpt->GetValue();
msg.ToDouble( &tmpDouble );
if( !setDouble( &m_XScaleAdjust, tmpDouble, PLOT_MIN_SCALE, PLOT_MAX_SCALE ) )
{
msg.Printf( wxT( "%f" ), m_XScaleAdjust );
m_fineAdjustXscaleOpt->SetValue( msg );
msg.Printf( _( "X scale constrained!\n" ) );
m_messagesBox->AppendText( msg );
}
ConfigBaseWriteDouble( m_config, OPTKEY_PLOT_X_FINESCALE_ADJ, m_XScaleAdjust );
// Y scale
msg = m_fineAdjustYscaleOpt->GetValue();
msg.ToDouble( &tmpDouble );
if( !setDouble( &m_YScaleAdjust, tmpDouble, PLOT_MIN_SCALE, PLOT_MAX_SCALE ) )
{
msg.Printf( wxT( "%f" ), m_YScaleAdjust );
m_fineAdjustYscaleOpt->SetValue( msg );
msg.Printf( _( "Y scale constrained!\n" ) );
m_messagesBox->AppendText( msg );
}
ConfigBaseWriteDouble( m_config, OPTKEY_PLOT_Y_FINESCALE_ADJ, m_YScaleAdjust );
// PS Width correction
msg = m_PSFineAdjustWidthOpt->GetValue();
int itmp = ValueFromString( g_UserUnit, msg );
if( !setInt( &m_PSWidthAdjust, itmp, m_widthAdjustMinValue, m_widthAdjustMaxValue ) )
{
msg = StringFromValue( g_UserUnit, m_PSWidthAdjust );
m_PSFineAdjustWidthOpt->SetValue( msg );
msg.Printf( _( "Width correction constrained!\n"
"The reasonable width correction value must be in a range of\n"
" [%+f; %+f] (%s) for current design rules!\n" ),
To_User_Unit( g_UserUnit, m_widthAdjustMinValue ),
To_User_Unit( g_UserUnit, m_widthAdjustMaxValue ),
( g_UserUnit == INCHES ) ? wxT( "\"" ) : wxT( "mm" ) );
m_messagesBox->AppendText( msg );
}
// Store m_PSWidthAdjust in mm in user config
ConfigBaseWriteDouble( m_config, CONFIG_PS_FINEWIDTH_ADJ,
(double)m_PSWidthAdjust / IU_PER_MM );
tempOptions.SetUseGerberExtensions( m_useGerberExtensions->GetValue() );
tempOptions.SetFormat( GetPlotFormat() );
long selectedLayers = 0;
unsigned int i;
for( i = 0; i < m_layerList.size(); i++ )
{
if( m_layerCheckListBox->IsChecked( i ) )
selectedLayers |= GetLayerMask( m_layerList[i] );
}
tempOptions.SetLayerSelection( selectedLayers );
tempOptions.SetNegative( m_plotPSNegativeOpt->GetValue() );
tempOptions.SetA4Output( m_forcePSA4OutputOpt->GetValue() );
// Set output directory and replace backslashes with forward ones
wxString dirStr;
dirStr = m_outputDirectoryName->GetValue();
dirStr.Replace( wxT( "\\" ), wxT( "/" ) );
tempOptions.SetOutputDirectory( dirStr );
if( m_plotOpts != tempOptions )
{
m_parent->SetPlotSettings( tempOptions );
m_plotOpts = tempOptions;
m_parent->OnModify();
}
}
void DIALOG_PLOT::Plot( wxCommandEvent& event )
{
applyPlotSettings();
// Create output directory if it does not exist (also transform it in
// absolute form). Bail if it fails
wxFileName outputDir = wxFileName::DirName( m_plotOpts.GetOutputDirectory() );
wxString boardFilename = m_parent->GetBoard()->GetFileName();
WX_TEXT_CTRL_REPORTER reporter( m_messagesBox );
if( !EnsureOutputDirectory( &outputDir, boardFilename, &reporter ) )
{
wxString msg;
msg.Printf( _( "Could not write plot files to folder \"%s\"." ),
GetChars( outputDir.GetPath() ) );
DisplayError( this, msg );
return;
}
m_plotOpts.SetAutoScale( false );
m_plotOpts.SetScale( 1 );
switch( m_plotOpts.GetScaleSelection() )
{
default:
break;
case 0: // Autoscale option
m_plotOpts.SetAutoScale( true );
break;
case 2: // 3:2 option
m_plotOpts.SetScale( 1.5 );
break;
case 3: // 2:1 option
m_plotOpts.SetScale( 2 );
break;
case 4: // 3:1 option
m_plotOpts.SetScale( 3 );
break;
}
/* If the scale factor edit controls are disabled or the scale value
* is 0, don't adjust the base scale factor. This fixes a bug when
* the default scale adjust is initialized to 0 and saved in program
* settings resulting in a divide by zero fault.
*/
if( m_fineAdjustXscaleOpt->IsEnabled() && m_XScaleAdjust != 0.0 )
m_plotOpts.SetFineScaleAdjustX( m_XScaleAdjust );
if( m_fineAdjustYscaleOpt->IsEnabled() && m_YScaleAdjust != 0.0 )
m_plotOpts.SetFineScaleAdjustY( m_YScaleAdjust );
if( m_PSFineAdjustWidthOpt->IsEnabled() )
m_plotOpts.SetWidthAdjust( m_PSWidthAdjust );
wxString file_ext( GetDefaultPlotExtension( m_plotOpts.GetFormat() ) );
// Test for a reasonable scale value
// XXX could this actually happen? isn't it constrained in the apply
// function?
if( m_plotOpts.GetScale() < PLOT_MIN_SCALE )
DisplayInfoMessage( this,
_( "Warning: Scale option set to a very small value" ) );
if( m_plotOpts.GetScale() > PLOT_MAX_SCALE )
DisplayInfoMessage( this,
_( "Warning: Scale option set to a very large value" ) );
// Save the current plot options in the board
m_parent->SetPlotSettings( m_plotOpts );
for( LAYER_NUM layer = FIRST_LAYER; layer < NB_PCB_LAYERS; ++layer )
{
if( m_plotOpts.GetLayerSelection() & GetLayerMask( layer ) )
{
// Pick the basename from the board file
wxFileName fn( boardFilename );
// Use Gerber Extensions based on layer number
// (See http://en.wikipedia.org/wiki/Gerber_File)
if( ( m_plotOpts.GetFormat() == PLOT_FORMAT_GERBER )
&& m_useGerberExtensions->GetValue() )
file_ext = GetGerberExtension( layer );
// Create file name (from the English layer name for non copper layers).
BuildPlotFileName( &fn, outputDir.GetPath(),
m_board->GetStandardLayerName( layer ),
file_ext );
LOCALE_IO toggle;
BOARD *board = m_parent->GetBoard();
PLOTTER *plotter = StartPlotBoard( board, &m_plotOpts,
fn.GetFullPath(),
wxEmptyString );
// Print diags in messages box:
wxString msg;
if( plotter )
{
PlotOneBoardLayer( board, plotter, layer, m_plotOpts );
plotter->EndPlot();
delete plotter;
msg.Printf( _( "Plot file <%s> created" ), GetChars( fn.GetFullPath() ) );
}
else
msg.Printf( _( "Unable to create <%s>" ), GetChars( fn.GetFullPath() ) );
msg << wxT( "\n" );
m_messagesBox->AppendText( msg );
}
}
// If no layer selected, we have nothing plotted.
// Prompt user if it happens because he could think there is a bug in Pcbnew.
if( !m_plotOpts.GetLayerSelection() )
DisplayError( this, _( "No layer selected" ) );
}