dialog_copper_zones.cpp 14.8 KB
Newer Older
1 2 3 4 5 6 7 8 9
/////////////////////////////////////////////////////////////////////////////

// Name:        dialog_copper_zones.cpp
// Author:      jean-pierre Charras
// Created:     09/oct/2008
/// Licence:     GNU License
/////////////////////////////////////////////////////////////////////////////

#include "fctsys.h"
10
#include "appl_wxstruct.h"
11
#include "common.h"
12
#include "confirm.h"
13 14
#include "PolyLine.h"
#include "pcbnew.h"
charras's avatar
charras committed
15
#include "wxPcbStruct.h"
16 17 18 19 20 21 22 23 24 25 26 27 28
#include "trigo.h"
#include "autorout.h"
#include "zones.h"

#include "dialog_copper_zones.h"


/************************************************************************************************/
dialog_copper_zone::dialog_copper_zone( WinEDA_PcbFrame* parent, ZONE_SETTING* zone_setting ) :
    dialog_copper_zone_base( parent )
/************************************************************************************************/
{
    m_Parent = parent;
29
    m_Config = wxGetApp().m_EDA_Config;
30
    m_Zone_Setting = zone_setting;
charras's avatar
charras committed
31
    m_NetSorting   = 1;     // 0 = alphabetic sort, 1 = pad count sort, and filtering net names
32
    m_OnExitCode   = ZONE_ABORT;
33

34
    if( m_Config )
35
    {
36
        m_NetSorting = m_Config->Read( ZONE_NET_SORT_OPTION_KEY, 1l );
37 38 39
    }

    SetReturnCode( ZONE_ABORT ); // Will be changed on buttons click
40

charras's avatar
charras committed
41
    initDialog();
charras's avatar
charras committed
42

charras's avatar
charras committed
43
    GetSizer()->SetSizeHints( this );
charras's avatar
charras committed
44
    Center();
45 46 47 48
}


/*****************************************************************/
charras's avatar
charras committed
49
void dialog_copper_zone::initDialog( )
50 51 52 53
/*****************************************************************/

// Initialise all dialog options and values in wxTextCtrl
{
54
    BOARD* board = m_Parent->GetBoard();
55 56 57

    SetFocus();     // Required under wxGTK if we want to demiss the dialog with the ESC key

58
    wxString msg;
59 60 61 62

    if( g_Zone_45_Only )
        m_OrientEdgesOpt->SetSelection( 1 );

63
    m_FillModeCtrl->SetSelection( m_Zone_Setting->m_FillMode ? 1 : 0 );
64

65
    AddUnitSymbol( *m_ClearanceValueTitle, g_UnitMetric );
66
    msg = ReturnStringFromValue( g_UnitMetric,
67 68
                                 m_Zone_Setting->m_ZoneClearance,
                                 m_Parent->m_InternalUnits );
69 70
    m_ZoneClearanceCtrl->SetValue( msg );

71 72
    AddUnitSymbol( *m_MinThicknessValueTitle, g_UnitMetric );
    msg = ReturnStringFromValue( g_UnitMetric,
73 74
                                 m_Zone_Setting->m_ZoneMinThickness,
                                 m_Parent->m_InternalUnits );
75 76
    m_ZoneMinThicknessCtrl->SetValue( msg );

77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106
    switch( m_Zone_Setting->m_Zone_Pad_Options )
    {
    case PAD_NOT_IN_ZONE:           // Pads are not covered
        m_PadInZoneOpt->SetSelection( 2 );
        break;

    case THERMAL_PAD:               // Use thermal relief for pads
        m_PadInZoneOpt->SetSelection( 1 );
        break;

    case PAD_IN_ZONE:               // pads are covered by copper
        m_PadInZoneOpt->SetSelection( 0 );
        break;
    }


    if( m_Zone_Setting->m_Zone_Pad_Options != THERMAL_PAD )
    {
        m_AntipadSizeValue->Enable( false );
        m_CopperWidthValue->Enable( false );
    }
    else
    {
        m_AntipadSizeValue->Enable( true );
        m_CopperWidthValue->Enable( true );
    }

    AddUnitSymbol( *m_AntipadSizeText, g_UnitMetric );
    AddUnitSymbol( *m_CopperBridgeWidthText, g_UnitMetric );
    PutValueInLocalUnits( *m_AntipadSizeValue,
107 108
                          m_Zone_Setting->m_ThermalReliefGapValue,
                          PCB_INTERNAL_UNIT );
109
    PutValueInLocalUnits( *m_CopperWidthValue,
110 111
                          m_Zone_Setting->m_ThermalReliefCopperBridgeValue,
                          PCB_INTERNAL_UNIT );
112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127

    switch( m_Zone_Setting->m_Zone_HatchingStyle )
    {
    case CPolyLine::NO_HATCH:
        m_OutlineAppearanceCtrl->SetSelection( 0 );
        break;

    case CPolyLine::DIAGONAL_EDGE:
        m_OutlineAppearanceCtrl->SetSelection( 1 );
        break;

    case CPolyLine::DIAGONAL_FULL:
        m_OutlineAppearanceCtrl->SetSelection( 2 );
        break;
    }

128 129
    m_ArcApproximationOpt->SetSelection(
        m_Zone_Setting->m_ArcToSegmentsCount == ARC_APPROX_SEGMENTS_COUNT_HIGHT_DEF ? 1 : 0 );
130 131 132 133 134

    /* build copper layers list */
    int layer_cnt = board->GetCopperLayerCount();
    for( int ii = 0; ii < board->GetCopperLayerCount(); ii++ )
    {
dickelbeck's avatar
dickelbeck committed
135
        int layer_number = LAYER_N_BACK;
136 137 138 139

        if( layer_cnt <= 1 || ii < layer_cnt - 1 )
            layer_number = ii;
        else if( ii == layer_cnt - 1 )
dickelbeck's avatar
dickelbeck committed
140
            layer_number = LAYER_N_FRONT;
141 142 143 144 145 146 147 148 149 150 151 152

        m_LayerId[ii] = layer_number;

        msg = board->GetLayerName( layer_number ).Trim();
        m_LayerSelectionCtrl->InsertItems( 1, &msg, ii );

        if( m_Zone_Setting->m_CurrentZone_Layer == layer_number )
            m_LayerSelectionCtrl->SetSelection( ii );
    }

    m_NetSortingOption->SetSelection( m_NetSorting );

153
    wxString NetNameFilter = wxT( "N_0*" );
154
    if( m_Config )
155 156
    {
        NetNameFilter =
157
            m_Config->Read( ZONE_NET_FILTER_STRING_KEY );
158 159
    }

160
    // Build list of nets:
161 162
    m_NetNameFilter->SetValue( NetNameFilter );
    wxArrayString ListNetName;
163 164
    m_Parent->GetBoard()->ReturnSortedNetnamesList(
        ListNetName,
165
        m_NetSorting == 0 ? false : true );
166 167 168 169 170 171 172 173 174 175 176 177 178 179

    if( m_NetSorting != 0 )
    {
        wxString Filter = m_NetNameFilter->GetValue();
        for( unsigned ii = 0; ii < ListNetName.GetCount(); ii++ )
        {
            if( ListNetName[ii].Matches( Filter.GetData() ) )
            {
                ListNetName.RemoveAt( ii );
                ii--;
            }
        }
    }

180
    ListNetName.Insert( wxT( "<no net>" ), 0 );
181 182 183 184 185 186 187
    m_ListNetNameSelection->InsertItems( ListNetName, 0 );

    // Select net:
    int net_select = m_Zone_Setting->m_NetcodeSelection;

    if( net_select > 0 )
    {
188
        NETINFO_ITEM* equipot = m_Parent->GetBoard()->FindNet( net_select );
189 190 191 192
        if( equipot )  // Search net in list and select it
        {
            for( unsigned ii = 0; ii < ListNetName.GetCount(); ii++ )
            {
193
                if( ListNetName[ii] == equipot->GetNetname() )
194 195 196 197 198 199 200 201 202 203 204 205 206 207 208
                {
                    m_ListNetNameSelection->SetSelection( ii );
                    m_ListNetNameSelection->EnsureVisible( ii );
                    break;
                }
            }
        }
    }
}


/********************************************************************/
void dialog_copper_zone::OnButtonCancelClick( wxCommandEvent& event )
/********************************************************************/
{
209
    EndModal( m_OnExitCode );
210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252
}


/********************************************************************************************/
bool dialog_copper_zone::AcceptOptions( bool aPromptForErrors, bool aUseExportableSetupOnly )
/********************************************************************************************/

/** Function dialog_copper_zone::AcceptOptions(
 * @return false if incorrect options, true if Ok.
 * @param aPromptForErrors = true to prompt user on incorrectparams
 * @param aUseExportableSetupOnly = true to use exportable parametres only (used to export this setup to other zones)
 */
{
    switch( m_PadInZoneOpt->GetSelection() )
    {
    case 2:
        m_Zone_Setting->m_Zone_Pad_Options = PAD_NOT_IN_ZONE;       // Pads are not covered
        break;

    case 1:
        m_Zone_Setting->m_Zone_Pad_Options = THERMAL_PAD;           // Use thermal relief for pads
        break;

    case 0:
        m_Zone_Setting->m_Zone_Pad_Options = PAD_IN_ZONE;           // pads are covered by copper
        break;
    }

    switch( m_OutlineAppearanceCtrl->GetSelection() )
    {
    case 0:
        m_Zone_Setting->m_Zone_HatchingStyle = CPolyLine::NO_HATCH;
        break;

    case 1:
        m_Zone_Setting->m_Zone_HatchingStyle = CPolyLine::DIAGONAL_EDGE;
        break;

    case 2:
        m_Zone_Setting->m_Zone_HatchingStyle = CPolyLine::DIAGONAL_FULL;
        break;
    }

253 254 255
    m_Zone_Setting->m_ArcToSegmentsCount = m_ArcApproximationOpt->GetSelection() == 1 ?
                                           ARC_APPROX_SEGMENTS_COUNT_HIGHT_DEF :
                                           ARC_APPROX_SEGMENTS_COUNT_LOW_DEF;
256

257
    if( m_Config )
258
    {
259
        m_Config->Write( ZONE_NET_OUTLINES_HATCH_OPTION_KEY,
260
                         (long) m_Zone_Setting->m_Zone_HatchingStyle );
261 262
        wxString Filter = m_NetNameFilter->GetValue();
        m_Config->Write( ZONE_NET_FILTER_STRING_KEY, Filter );
263 264
    }

265
    m_Zone_Setting->m_FillMode = (m_FillModeCtrl->GetSelection() == 0) ? 0 : 1;
266 267 268 269

    wxString txtvalue = m_ZoneClearanceCtrl->GetValue();
    m_Zone_Setting->m_ZoneClearance =
        ReturnValueFromString( g_UnitMetric, txtvalue, m_Parent->m_InternalUnits );
270

271 272 273
    // Test if this is a reasonnable value for this parameter
    // A too large value can hang pcbnew
    #define CLEARANCE_MAX_VALUE 5000    // in 1/10000 inch
274
    if( m_Zone_Setting->m_ZoneClearance > CLEARANCE_MAX_VALUE )
275 276 277 278 279
    {
        DisplayError( this, _( "Error : Zone clearance is set to an unreasonnable value" ) );
        return false;
    }

280 281 282
    txtvalue = m_ZoneMinThicknessCtrl->GetValue();
    m_Zone_Setting->m_ZoneMinThickness =
        ReturnValueFromString( g_UnitMetric, txtvalue, m_Parent->m_InternalUnits );
283
    if( m_Zone_Setting->m_ZoneMinThickness < 10 )
284 285
    {
        DisplayError( this,
286
                     _(
287
                         "Error :\nyou must choose a copper min thickness value bigger than 0.001 inch (or 0.0254 mm)" ) );
288 289
        return false;
    }
290

291 292 293 294 295 296
    if( m_OrientEdgesOpt->GetSelection() == 0 )
        g_Zone_45_Only = FALSE;
    else
        g_Zone_45_Only = TRUE;

    m_Zone_Setting->m_ThermalReliefGapValue = ReturnValueFromTextCtrl( *m_AntipadSizeValue,
297
                                                                       PCB_INTERNAL_UNIT );
298 299 300 301
    m_Zone_Setting->m_ThermalReliefCopperBridgeValue = ReturnValueFromTextCtrl(
        *m_CopperWidthValue,
        PCB_INTERNAL_UNIT );

302
    m_Config->Write( ZONE_THERMAL_RELIEF_GAP_STRING_KEY,
303
                     (long) m_Zone_Setting->m_ThermalReliefGapValue );
304
    m_Config->Write(
305
        ZONE_THERMAL_RELIEF_COPPER_WIDTH_STRING_KEY,
charras's avatar
charras committed
306 307 308 309
        (long) m_Zone_Setting->m_ThermalReliefCopperBridgeValue );

    if( m_Zone_Setting->m_ThermalReliefCopperBridgeValue <= m_Zone_Setting->m_ZoneMinThickness )
    {
310 311 312
        DisplayError( this,
                     _(
                         "Error :\nyou must choose a copper bridge value for thermal reliefs bigger than the min zone thickness" ) );
charras's avatar
charras committed
313 314
        return false;
    }
315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339

    // If we use only exportable to others zones parameters, exit here:
    if( aUseExportableSetupOnly )
        return true;

    /* Get the layer selection for this zone */
    int ii = m_LayerSelectionCtrl->GetSelection();
    if( ii < 0 && aPromptForErrors )
    {
        DisplayError( this, _( "Error : you must choose a layer" ) );
        return false;
    }


    m_Zone_Setting->m_CurrentZone_Layer = m_LayerId[ii];


    /* Get the net name selection for this zone */
    ii = m_ListNetNameSelection->GetSelection();
    if( ii < 0 && aPromptForErrors )
    {
        DisplayError( this, _( "Error : you must choose a net name" ) );
        return false;
    }

340
    if( ii == 0 )   // the not connected option was selected: this is not a good practice: warn:
341
    {
342 343
        if( !IsOK( this, _(
                      "You have chosen the \"not connected\" option. This will create insulated copper islands. Are you sure ?" ) )
344
            )
345 346
            return false;
    }
347

348 349 350
    wxString net_name = m_ListNetNameSelection->GetString( ii );

    g_Zone_Default_Setting.m_NetcodeSelection = 0;
351 352 353

    /* Search net_code for this net, if a net was selected */
    if( m_ListNetNameSelection->GetSelection() > 0 )
354
    {
355
        NETINFO_ITEM* net = m_Parent->GetBoard()->FindNet( net_name );
356 357
        if( net )
            g_Zone_Default_Setting.m_NetcodeSelection = net->GetNet();
358 359 360 361 362 363 364 365 366 367 368 369 370
    }

    return true;
}


/***************************************************************************/
void dialog_copper_zone::OnNetSortingOptionSelected( wxCommandEvent& event )
/***************************************************************************/
{
    wxArrayString ListNetName;

    m_NetSorting = m_NetSortingOption->GetSelection();
371
    m_Parent->GetBoard()->ReturnSortedNetnamesList(
372
        ListNetName, m_NetSorting == 0 ? false : true );
373 374 375 376 377 378 379 380 381 382 383 384 385 386
    if( m_NetSorting != 0 )
    {
        wxString Filter = m_NetNameFilter->GetValue();
        for( unsigned ii = 0; ii < ListNetName.GetCount(); ii++ )
        {
            if( ListNetName[ii].Matches( Filter.GetData() ) )
            {
                ListNetName.RemoveAt( ii );
                ii--;
            }
        }
    }
    m_ListNetNameSelection->Clear();
    m_ListNetNameSelection->InsertItems( ListNetName, 0 );
387
    if( m_Config )
388
    {
389 390 391
        m_Config->Write( ZONE_NET_SORT_OPTION_KEY, (long) m_NetSorting );
        wxString Filter = m_NetNameFilter->GetValue();
        m_Config->Write( ZONE_NET_FILTER_STRING_KEY, Filter );
392 393
    }

394
    // Select and display current zone net name in listbox:
395 396 397
    int net_select = m_Zone_Setting->m_NetcodeSelection;
    if( net_select > 0 )
    {
398
        NETINFO_ITEM* equipot = m_Parent->GetBoard()->FindNet( net_select );
399 400 401 402
        if( equipot )  // Search net in list and select it
        {
            for( unsigned ii = 0; ii < ListNetName.GetCount(); ii++ )
            {
403
                if( ListNetName[ii] == equipot->GetNetname() )
404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430
                {
                    m_ListNetNameSelection->SetSelection( ii );
                    m_ListNetNameSelection->EnsureVisible( ii );
                    break;
                }
            }
        }
    }
}


/*****************************************************************/
void dialog_copper_zone::OnButtonOkClick( wxCommandEvent& event )
/*****************************************************************/
{
    if( AcceptOptions( true ) )
        EndModal( ZONE_OK );
}


/******************************************************************************/
void dialog_copper_zone::ExportSetupToOtherCopperZones( wxCommandEvent& event )
/******************************************************************************/
{
    if( !AcceptOptions( true, true ) )
        return;

431
    // Export settings ( but layer and netcode ) to others zones:
432
    BOARD* pcb = m_Parent->GetBoard();
433 434 435
    for( int ii = 0; ii < pcb->GetAreaCount(); ii++ )
    {
        ZONE_CONTAINER* zone = pcb->GetArea( ii );
436
        m_Zone_Setting->ExportSetting( *zone, false );  // false = partiel export
437
        m_Parent->OnModify();
438
    }
439

440
    m_OnExitCode = ZONE_EXPORT_VALUES;     // values are exported to others zones
441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460
}


/******************************************************************/
void dialog_copper_zone::OnPadsInZoneClick( wxCommandEvent& event )
/******************************************************************/
{
    switch( m_PadInZoneOpt->GetSelection() )
    {
    default:
        m_AntipadSizeValue->Enable( false );
        m_CopperWidthValue->Enable( false );
        break;

    case 1:
        m_AntipadSizeValue->Enable( true );
        m_CopperWidthValue->Enable( true );
        break;
    }
}