void DIALOG_MODULE_BOARD_EDITOR::Remove3DShape( wxCommandEvent& event )
{
    if( m_LastSelected3DShapeIndex >= 0 )
        TransfertDisplayTo3DValues( m_LastSelected3DShapeIndex );

    int ii = m_3D_ShapeNameListBox->GetSelection();
    if( ii < 0 )
        return;

    m_Shapes3D_list.erase( m_Shapes3D_list.begin() + ii );
    m_3D_ShapeNameListBox->Delete( ii );

    if( m_3D_ShapeNameListBox->GetCount() == 0 )
        Transfert3DValuesToDisplay( NULL );
    else
    {
        if( ii > 0 )
            m_LastSelected3DShapeIndex = ii - 1;
        else
            m_LastSelected3DShapeIndex = 0;

        m_3D_ShapeNameListBox->SetSelection( m_LastSelected3DShapeIndex );
        Transfert3DValuesToDisplay(
            m_Shapes3D_list[m_LastSelected3DShapeIndex] );
    }

    return;
}
void DIALOG_MODULE_BOARD_EDITOR::Edit3DShapeFileName()
{
    int idx = m_3D_ShapeNameListBox->GetSelection();

    if( idx < 0 )
        return;

    // ensure any updated parameters are not discarded
    TransfertDisplayTo3DValues( idx );

    // Edit filename
    wxString filename = m_3D_ShapeNameListBox->GetStringSelection();
    wxTextEntryDialog dlg( this, wxEmptyString, wxEmptyString, filename );

    bool hasAlias;
    S3D_FILENAME_RESOLVER* res = Prj().Get3DCacheManager()->GetResolver();

    if( dlg.ShowModal() != wxID_OK )
        return;

    filename = dlg.GetValue();

    if( filename.empty() )
        return;

    if( !res->ValidateFileName( filename, hasAlias ) )
    {
        wxString msg = _( "Invalid filename: " );
        msg.append( filename );
        wxMessageBox( msg, _T( "Edit 3D file name" ) );

        return;
    }

    m_3D_ShapeNameListBox->SetString( idx, filename );

    // if the user has specified an alias in the name then prepend ':'
    if( hasAlias )
        filename.insert( 0, wxT( ":" ) );

    #ifdef __WINDOWS__
    // In Kicad files, filenames and paths are stored using Unix notation
    filename.Replace( wxT( "\\" ), wxT( "/" ) );
    #endif

    S3D_MASTER* new3DShape = new S3D_MASTER( NULL );
    new3DShape->SetShape3DName( filename );
    new3DShape->m_MatPosition = m_Shapes3D_list[idx]->m_MatPosition;
    new3DShape->m_MatRotation = m_Shapes3D_list[idx]->m_MatRotation;
    new3DShape->m_MatScale = m_Shapes3D_list[idx]->m_MatScale;
    delete m_Shapes3D_list[idx];
    m_Shapes3D_list[idx] = new3DShape;

    Transfert3DValuesToDisplay( m_Shapes3D_list[idx] );

    return;
}
void DIALOG_MODULE_BOARD_EDITOR::On3DShapeNameSelected( wxCommandEvent& event )
{
    if( m_LastSelected3DShapeIndex >= 0 )
        TransfertDisplayTo3DValues( m_LastSelected3DShapeIndex );
    m_LastSelected3DShapeIndex = m_3D_ShapeNameListBox->GetSelection();

    if( m_LastSelected3DShapeIndex < 0 )    // happens under wxGTK when
                                            // deleting an item in
                                            // m_3D_ShapeNameListBox wxListBox
        return;

    if( m_LastSelected3DShapeIndex >= (int) m_Shapes3D_list.size() )
    {
        wxMessageBox( wxT( "On3DShapeNameSelected() error" ) );
        m_LastSelected3DShapeIndex = -1;
        return;
    }
    Transfert3DValuesToDisplay( m_Shapes3D_list[m_LastSelected3DShapeIndex] );
}
void DIALOG_MODULE_BOARD_EDITOR::Browse3DLib( wxCommandEvent& event )
{
    wxString fullfilename, shortfilename;
    wxString fullpath;

    fullpath = wxGetApp().ReturnLastVisitedLibraryPath( LIB3D_PATH );
#ifdef __WINDOWS__
    fullpath.Replace( wxT( "/" ), wxT( "\\" ) );
#endif

    wxString fileFilters;
    fileFilters = wxGetTranslation( Shapes3DFileWildcard );
    fileFilters += wxChar(  '|' );
    fileFilters += wxGetTranslation( IDF3DFileWildcard );

    fullfilename = EDA_FileSelector( _( "3D Shape:" ),
                                     fullpath,
                                     wxEmptyString,
                                     wxEmptyString,
                                     wxGetTranslation( fileFilters ),
                                     this,
                                     wxFD_OPEN,
                                     true
                                     );

    if( fullfilename.IsEmpty() )
        return;

    wxFileName fn = fullfilename;
    wxGetApp().SaveLastVisitedLibraryPath( fn.GetPath() );

    /* If the file path is already in the default search path
     * list, just add the name to the list.  Otherwise, add
     * the name with the full or relative path.
     * the relative path, when possible is preferable,
     * because it preserve use of default search path, when the path is a
     * sub path
     */

    wxString default_path;
    wxGetEnv( wxT( KISYS3DMOD ), &default_path );
    fn.MakeRelativeTo( default_path );

    // Here, we want a path relative only to the default_path
    if( fn.GetPathWithSep().StartsWith( wxT("..") ) )
        fn = fullfilename;  // keep the full file name

    shortfilename = fn.GetFullPath();

    if( fn.IsAbsolute() )
    {   // Absolute path, ask if the user wants a relative one
        int diag = wxMessageBox(
            _( "Use a relative path?" ),
            _( "Path type" ),
            wxYES_NO | wxICON_QUESTION, this );

        if( diag == wxYES )
        {   // Make it relative
            fn.MakeRelativeTo( wxT(".") );
            shortfilename = fn.GetFullPath();
        }
    }

    S3D_MASTER* new3DShape = new S3D_MASTER( NULL );
#ifdef __WINDOWS__
    // Store filename in Unix notation
    shortfilename.Replace( wxT( "\\" ), wxT( "/" ) );
#endif
    new3DShape->SetShape3DName( shortfilename );
    m_Shapes3D_list.push_back( new3DShape );
    m_3D_ShapeNameListBox->Append( shortfilename );

    if( m_LastSelected3DShapeIndex >= 0 )
        TransfertDisplayTo3DValues( m_LastSelected3DShapeIndex );

    m_LastSelected3DShapeIndex = m_3D_ShapeNameListBox->GetCount() - 1;
    m_3D_ShapeNameListBox->SetSelection( m_LastSelected3DShapeIndex );
    Transfert3DValuesToDisplay( m_Shapes3D_list[m_LastSelected3DShapeIndex] );
}
void DIALOG_MODULE_BOARD_EDITOR::InitModeditProperties()
{
    SetFocus();

    wxString default_path;
    wxGetEnv( wxT( KISYS3DMOD ), &default_path );
#ifdef __WINDOWS__
    default_path.Replace( wxT( "/" ), wxT( "\\" ) );
#endif
    m_textCtrl3DDefaultPath->SetValue( default_path );

    m_LastSelected3DShapeIndex = -1;

    // Init 3D shape list
    S3D_MASTER* draw3D = m_CurrentModule->Models();

    while( draw3D )
    {
        if( !draw3D->GetShape3DName().IsEmpty() )
        {
            S3D_MASTER* draw3DCopy = new S3D_MASTER( NULL );
            draw3DCopy->Copy( draw3D );
            m_Shapes3D_list.push_back( draw3DCopy );
            m_3D_ShapeNameListBox->Append( draw3DCopy->GetShape3DName() );
        }
        draw3D = (S3D_MASTER*) draw3D->Next();
    }

    m_ReferenceCopy = new TEXTE_MODULE( NULL );
    m_ValueCopy     = new TEXTE_MODULE( NULL );
    m_ReferenceCopy->Copy( &m_CurrentModule->Reference() );
    m_ValueCopy->Copy( &m_CurrentModule->Value() );
    m_ReferenceCtrl->SetValue( m_ReferenceCopy->GetText() );
    m_ValueCtrl->SetValue( m_ValueCopy->GetText() );

    // Shows the footprint's schematic path.
    m_textCtrlSheetPath->SetValue( m_CurrentModule->GetPath() );

    m_AttributsCtrl->SetItemToolTip( 0,
        _( "Use this attribute for most non SMD components\n"
            "Components with this option are not put in the footprint position list file" ) );
    m_AttributsCtrl->SetItemToolTip( 1,
         _( "Use this attribute for SMD components.\n"
            "Only components with this option are put in the footprint position list file" ) );
    m_AttributsCtrl->SetItemToolTip( 2,
        _( "Use this attribute for \"virtual\" components drawn on board\n"
           "(like a old ISA PC bus connector)" ) );

    // Controls on right side of the dialog
    switch( m_CurrentModule->GetAttributes() & 255 )
    {
    case 0:
        m_AttributsCtrl->SetSelection( 0 );
        break;

    case MOD_CMS:
        m_AttributsCtrl->SetSelection( 1 );
        break;

    case MOD_VIRTUAL:
        m_AttributsCtrl->SetSelection( 2 );
        break;

    default:
        m_AttributsCtrl->SetSelection( 0 );
        break;
    }

    m_AutoPlaceCtrl->SetSelection( (m_CurrentModule->IsLocked()) ? 1 : 0 );

    m_AutoPlaceCtrl->SetItemToolTip( 0,
                                    _( "Enable hotkey move commands and Auto Placement" ) );
    m_AutoPlaceCtrl->SetItemToolTip( 1,
                                    _( "Disable hotkey move commands and Auto Placement" ) );

    m_CostRot90Ctrl->SetValue( m_CurrentModule->GetPlacementCost90() );

    m_CostRot180Ctrl->SetValue( m_CurrentModule->GetPlacementCost180() );

    // Initialize 3D parameters
    m_3D_Scale = new VERTEX_VALUE_CTRL( m_Panel3D, m_bSizerShapeScale );
    m_3D_Offset = new VERTEX_VALUE_CTRL( m_Panel3D, m_bSizerShapeOffset );
    m_3D_Rotation = new VERTEX_VALUE_CTRL( m_Panel3D, m_bSizerShapeRotation );

    // if m_3D_ShapeNameListBox is not empty, preselect first 3D shape
    if( m_3D_ShapeNameListBox->GetCount() > 0 )
    {
        m_LastSelected3DShapeIndex = 0;
        m_3D_ShapeNameListBox->SetSelection( m_LastSelected3DShapeIndex );
        Transfert3DValuesToDisplay( m_Shapes3D_list[m_LastSelected3DShapeIndex] );
    }

    // We have modified the UI, so call Fit() for m_Panel3D
    // to be sure the m_Panel3D sizers are initiliazed before opening the dialog
    m_Panel3D->GetSizer()->Fit( m_Panel3D );
}
void DIALOG_MODULE_BOARD_EDITOR::Browse3DLib( wxCommandEvent& event )
{
    PROJECT&        prj = Prj();
    SEARCH_STACK&   search = Kiface().KifaceSearch();

    wxString    fullpath;
    wxString    kisys3dmod = wxGetenv( wxT( KISYS3DMOD ) );

    if( !kisys3dmod || !wxFileName::IsDirReadable( kisys3dmod ) )
    {
        fullpath = search.FindValidPath( LIB3D_PATH );
    }

    if( !fullpath )
        fullpath = prj.RPath(PROJECT::VIEWER_3D).LastVisitedPath( search, LIB3D_PATH );

#ifdef __WINDOWS__
    fullpath.Replace( wxT( "/" ), wxT( "\\" ) );
#endif

    wxString    fullfilename;
    wxString    shortfilename;

    wxString    fileFilters = wxGetTranslation( Shapes3DFileWildcard );

    fileFilters += wxChar( '|' );
    fileFilters += wxGetTranslation( IDF3DFileWildcard );

    fullfilename = EDA_FileSelector( _( "3D Shape:" ),
                                     fullpath,
                                     wxEmptyString,
                                     wxEmptyString,
                                     wxGetTranslation( fileFilters ),
                                     this,
                                     wxFD_OPEN,
                                     true
                                     );

    if( fullfilename.IsEmpty() )
        return;

    wxFileName fn = fullfilename;

    prj.RPath(PROJECT::VIEWER_3D).SaveLastVisitedPath( fn.GetPath() );

    /* If the file path is already in the library search paths
     * list, just add the library name to the list.  Otherwise, add
     * the library name with the full or relative path.
     * the relative path, when possible is preferable,
     * because it preserve use of default libraries paths, when the path is a
     * sub path of these default paths
     */
    shortfilename = search.FilenameWithRelativePathInSearchList( fullfilename );

    wxFileName aux = shortfilename;
    if( aux.IsAbsolute() )
    {   
        // Absolute path, ask if the user wants a relative one
        int diag = wxMessageBox(
            _( "Use a relative path?" ),
            _( "Path type" ),
            wxYES_NO | wxICON_QUESTION, this );

        if( diag == wxYES )
        {   
            // Make it relative
            aux.MakeRelativeTo( wxT(".") );
            shortfilename = aux.GetPathWithSep() + aux.GetFullName();
        }
    }

    S3D_MASTER* new3DShape = new S3D_MASTER( NULL );

#ifdef __WINDOWS__
    // Store filename in Unix notation
    shortfilename.Replace( wxT( "\\" ), wxT( "/" ) );
#endif

    new3DShape->SetShape3DName( shortfilename );
    m_Shapes3D_list.push_back( new3DShape );
    m_3D_ShapeNameListBox->Append( shortfilename );

    if( m_LastSelected3DShapeIndex >= 0 )
        TransfertDisplayTo3DValues( m_LastSelected3DShapeIndex );

    m_LastSelected3DShapeIndex = m_3D_ShapeNameListBox->GetCount() - 1;
    m_3D_ShapeNameListBox->SetSelection( m_LastSelected3DShapeIndex );
    Transfert3DValuesToDisplay( m_Shapes3D_list[m_LastSelected3DShapeIndex] );
}
void DIALOG_MODULE_BOARD_EDITOR::BrowseAndAdd3DShapeFile()
{
    PROJECT& prj = Prj();
    S3D_INFO model;

    wxString initialpath = prj.GetRString( PROJECT::VIEWER_3D_PATH );
    wxString sidx = prj.GetRString( PROJECT::VIEWER_3D_FILTER_INDEX );
    int filter = 0;

    if( !sidx.empty() )
    {
        long tmp;
        sidx.ToLong( &tmp );

        if( tmp > 0 && tmp <= 0x7FFFFFFF )
            filter = (int) tmp;
    }

    if( !S3D::Select3DModel( this, Prj().Get3DCacheManager(),
        initialpath, filter, &model ) || model.filename.empty() )
    {
        return;
    }

    prj.SetRString( PROJECT::VIEWER_3D_PATH, initialpath );
    sidx = wxString::Format( wxT( "%i" ), filter );
    prj.SetRString( PROJECT::VIEWER_3D_FILTER_INDEX, sidx );
    wxString origPath = model.filename;
    wxString alias;
    wxString shortPath;
    S3D_FILENAME_RESOLVER* res = Prj().Get3DCacheManager()->GetResolver();

    if( res && res->SplitAlias( origPath, alias, shortPath ) )
    {
        origPath = alias;
        origPath.append( wxT( ":" ) );
        origPath.append( shortPath );
    }

    m_3D_ShapeNameListBox->Append( origPath );

#ifdef __WINDOWS__
    // In Kicad files, filenames and paths are stored using Unix notation
    model.filename.Replace( wxT( "\\" ), wxT( "/" ) );
#endif

    S3D_MASTER* new3DShape = new S3D_MASTER( NULL );
    new3DShape->SetShape3DName( model.filename );
    new3DShape->m_MatScale.x = model.scale.x;
    new3DShape->m_MatScale.y = model.scale.y;
    new3DShape->m_MatScale.z = model.scale.z;
    new3DShape->m_MatRotation.x = model.rotation.x;
    new3DShape->m_MatRotation.y = model.rotation.y;
    new3DShape->m_MatRotation.z = model.rotation.z;
    new3DShape->m_MatPosition.x = model.offset.x;
    new3DShape->m_MatPosition.y = model.offset.y;
    new3DShape->m_MatPosition.z = model.offset.z;

    m_Shapes3D_list.push_back( new3DShape );
    m_LastSelected3DShapeIndex = m_3D_ShapeNameListBox->GetCount() - 1;
    m_3D_ShapeNameListBox->SetSelection( m_LastSelected3DShapeIndex );
    Transfert3DValuesToDisplay( m_Shapes3D_list[m_LastSelected3DShapeIndex] );

    return;
}
void DIALOG_MODULE_BOARD_EDITOR::InitModeditProperties()
{
    wxString default_path;
    wxGetEnv( KISYS3DMOD, &default_path );
#ifdef __WINDOWS__
    default_path.Replace( wxT( "/" ), wxT( "\\" ) );
#endif

    m_LastSelected3DShapeIndex = -1;

    // Init 3D shape list
    S3D_MASTER* draw3D = m_CurrentModule->Models();
    wxString origPath;
    wxString alias;
    wxString shortPath;
    S3D_FILENAME_RESOLVER* res = Prj().Get3DCacheManager()->GetResolver();

    while( draw3D )
    {
        if( !draw3D->GetShape3DName().IsEmpty() )
        {
            S3D_MASTER* draw3DCopy = new S3D_MASTER( NULL );
            draw3DCopy->Copy( draw3D );
            m_Shapes3D_list.push_back( draw3DCopy );
            origPath = draw3DCopy->GetShape3DName();

            if( res && res->SplitAlias( origPath, alias, shortPath ) )
            {
                origPath = alias;
                origPath.append( wxT( ":" ) );
                origPath.append( shortPath );
            }

            m_3D_ShapeNameListBox->Append( origPath );
        }

        draw3D = (S3D_MASTER*) draw3D->Next();
    }

    m_ReferenceCopy = new TEXTE_MODULE( NULL );
    m_ValueCopy     = new TEXTE_MODULE( NULL );
    m_ReferenceCopy->Copy( &m_CurrentModule->Reference() );
    m_ValueCopy->Copy( &m_CurrentModule->Value() );
    m_ReferenceCtrl->SetValue( m_ReferenceCopy->GetText() );
    m_ValueCtrl->SetValue( m_ValueCopy->GetText() );

    // Shows the footprint's schematic path.
    m_textCtrlSheetPath->SetValue( m_CurrentModule->GetPath() );

    m_AttributsCtrl->SetItemToolTip( 0,
        _( "Use this attribute for most non SMD components\n"
            "Components with this option are not put in the footprint position list file" ) );
    m_AttributsCtrl->SetItemToolTip( 1,
         _( "Use this attribute for SMD components.\n"
            "Only components with this option are put in the footprint position list file" ) );
    m_AttributsCtrl->SetItemToolTip( 2,
        _( "Use this attribute for \"virtual\" components drawn on board\n"
           "(like a old ISA PC bus connector)" ) );

    // Controls on right side of the dialog
    switch( m_CurrentModule->GetAttributes() & 255 )
    {
    case 0:
        m_AttributsCtrl->SetSelection( 0 );
        break;

    case MOD_CMS:
        m_AttributsCtrl->SetSelection( 1 );
        break;

    case MOD_VIRTUAL:
        m_AttributsCtrl->SetSelection( 2 );
        break;

    default:
        m_AttributsCtrl->SetSelection( 0 );
        break;
    }

    if( m_CurrentModule->IsLocked() )
        m_AutoPlaceCtrl->SetSelection( 2 );
    else if( m_CurrentModule->PadsLocked() )
        m_AutoPlaceCtrl->SetSelection( 1 );
    else
        m_AutoPlaceCtrl->SetSelection( 0 );

    m_AutoPlaceCtrl->SetItemToolTip( 0,
                                    _( "Component can be freely moved and auto placed. User can arbitrarily select and edit component's pads." ) );
    m_AutoPlaceCtrl->SetItemToolTip( 1,
                                    _( "Component can be freely moved and auto placed, but its pads cannot be selected or edited." ) );
    m_AutoPlaceCtrl->SetItemToolTip( 2,
                                    _( "Component is locked: it cannot be freely moved or auto placed." ) );

    m_CostRot90Ctrl->SetValue( m_CurrentModule->GetPlacementCost90() );

    m_CostRot180Ctrl->SetValue( m_CurrentModule->GetPlacementCost180() );

    // if m_3D_ShapeNameListBox is not empty, preselect first 3D shape
    if( m_3D_ShapeNameListBox->GetCount() > 0 )
    {
        m_LastSelected3DShapeIndex = 0;
        m_3D_ShapeNameListBox->SetSelection( m_LastSelected3DShapeIndex );
        Transfert3DValuesToDisplay( m_Shapes3D_list[m_LastSelected3DShapeIndex] );
    }
    else
    {
        S3D_INFO params;
        params.scale.x = 1.0;
        params.scale.y = 1.0;
        params.scale.z = 1.0;
        m_PreviewPane->SetModelData( &params );
    }

    // We have modified the UI, so call Fit() for m_Panel3D
    // to be sure the m_Panel3D sizers are initiliazed before opening the dialog
    m_Panel3D->GetSizer()->Fit( m_Panel3D );
}
void DIALOG_MODULE_MODULE_EDITOR::initModeditProperties()
{
    SetFocus();

    // Display the default path, given by environment variable KISYS3DMOD
    wxString default_path;
    wxGetEnv( wxT( KISYS3DMOD ), &default_path );
#ifdef __WINDOWS__
    default_path.Replace( wxT( "/" ), wxT( "\\" ) );
#endif
    m_textCtrl3DDefaultPath->SetValue( default_path );

    m_lastSelected3DShapeIndex = -1;

    // Init 3D shape list
    S3D_MASTER* draw3D = m_currentModule->Models();

    while( draw3D )
    {
        if( !draw3D->GetShape3DName().IsEmpty() )
        {
            S3D_MASTER* draw3DCopy = new S3D_MASTER(NULL);
            draw3DCopy->Copy( draw3D );
            m_shapes3D_list.push_back( draw3DCopy );
            m_3D_ShapeNameListBox->Append( draw3DCopy->GetShape3DName() );
        }
        draw3D = (S3D_MASTER*) draw3D->Next();
    }

    m_DocCtrl->SetValue( m_currentModule->GetDescription() );
    m_KeywordCtrl->SetValue( m_currentModule->GetKeywords() );
    m_referenceCopy = new TEXTE_MODULE( NULL );
    m_valueCopy = new TEXTE_MODULE( NULL );
    m_referenceCopy->Copy( &m_currentModule->Reference() );
    m_valueCopy->Copy( &m_currentModule->Value() );
    m_ReferenceCtrl->SetValue( m_referenceCopy->GetText() );
    m_ValueCtrl->SetValue( m_valueCopy->GetText() );
    m_ValueCtrl->SetValue( m_valueCopy->GetText() );
    m_FootprintNameCtrl->SetValue( m_currentModule->GetFPID().Format() );

    m_AttributsCtrl->SetItemToolTip( 0, _( "Use this attribute for most non SMD components" ) );
    m_AttributsCtrl->SetItemToolTip( 1,
                                    _( "Use this attribute for SMD components.\nOnly components with this option are put in the footprint position list file" ) );
    m_AttributsCtrl->SetItemToolTip( 2,
                                    _( "Use this attribute for \"virtual\" components drawn on board (like a old ISA PC bus connector)" ) );

    // Controls on right side of the dialog
    switch( m_currentModule->GetAttributes() & 255 )
    {
    case 0:
        m_AttributsCtrl->SetSelection( 0 );
        break;

    case MOD_CMS:
        m_AttributsCtrl->SetSelection( 1 );
        break;

    case MOD_VIRTUAL:
        m_AttributsCtrl->SetSelection( 2 );
        break;

    default:
        m_AttributsCtrl->SetSelection( 0 );
        break;
    }

    m_AutoPlaceCtrl->SetSelection( (m_currentModule->IsLocked()) ? 1 : 0 );
    m_AutoPlaceCtrl->SetItemToolTip( 0, _( "Enable hotkey move commands and Auto Placement" ) );
    m_AutoPlaceCtrl->SetItemToolTip( 1, _( "Disable hotkey move commands and Auto Placement" ) );

    m_CostRot90Ctrl->SetValue( m_currentModule->GetPlacementCost90() );
    m_CostRot180Ctrl->SetValue( m_currentModule->GetPlacementCost180() );

    // Initialize 3D parameters
    m_3D_Scale = new VERTEX_VALUE_CTRL( m_Panel3D, m_bSizerShapeScale );
    m_3D_Offset = new VERTEX_VALUE_CTRL( m_Panel3D, m_bSizerShapeOffset );
    m_3D_Rotation = new VERTEX_VALUE_CTRL( m_Panel3D, m_bSizerShapeRotation );

    // Initialize dialog relative to masks clearances
    m_NetClearanceUnits->SetLabel( GetAbbreviatedUnitsLabel( g_UserUnit ) );
    m_SolderMaskMarginUnits->SetLabel( GetAbbreviatedUnitsLabel( g_UserUnit ) );
    m_SolderPasteMarginUnits->SetLabel( GetAbbreviatedUnitsLabel( g_UserUnit ) );

    wxString  msg;
    PutValueInLocalUnits( *m_NetClearanceValueCtrl, m_currentModule->GetLocalClearance() );
    PutValueInLocalUnits( *m_SolderMaskMarginCtrl, m_currentModule->GetLocalSolderMaskMargin() );

    // These 2 parameters are usually < 0, so prepare entering a negative value, if current is 0
    PutValueInLocalUnits( *m_SolderPasteMarginCtrl, m_currentModule->GetLocalSolderPasteMargin() );

    if( m_currentModule->GetLocalSolderPasteMargin() == 0 )
        m_SolderPasteMarginCtrl->SetValue( wxT( "-" ) + m_SolderPasteMarginCtrl->GetValue() );

    if( m_currentModule->GetLocalSolderPasteMarginRatio() == 0.0 )
        msg.Printf( wxT( "-%f" ), m_currentModule->GetLocalSolderPasteMarginRatio() * 100.0 );
    else
        msg.Printf( wxT( "%f" ), m_currentModule->GetLocalSolderPasteMarginRatio() * 100.0 );

    m_SolderPasteMarginRatioCtrl->SetValue( msg );

    // Add solder paste margin ration in per cent
    // for the usual default value 0.0, display -0.0 (or -0,0 in some countries)
    msg.Printf( wxT( "%f" ), m_currentModule->GetLocalSolderPasteMarginRatio() * 100.0 );

    if( m_currentModule->GetLocalSolderPasteMarginRatio() == 0.0 &&
        msg[0] == '0')  // Sometimes Printf adds a sign if the value is very small (0.0)
        m_SolderPasteMarginRatioCtrl->SetValue( wxT( "-" ) + msg );
    else
        m_SolderPasteMarginRatioCtrl->SetValue( msg );

    // if m_3D_ShapeNameListBox is not empty, preselect first 3D shape
    if( m_3D_ShapeNameListBox->GetCount() > 0 )
    {
        m_lastSelected3DShapeIndex = 0;
        m_3D_ShapeNameListBox->SetSelection( m_lastSelected3DShapeIndex );
        Transfert3DValuesToDisplay( m_shapes3D_list[m_lastSelected3DShapeIndex] );
    }

    // We have modified the UI, so call Fit() for m_Panel3D
    // to be sure the m_Panel3D sizers are initialized before opening the dialog
    m_Panel3D->GetSizer()->Fit( m_Panel3D );
}