mirror of
https://gitlab.com/kicad/code/kicad.git
synced 2025-09-15 10:43:15 +02:00
* Added exporting of netclass vias to specctra_export. * DIALOG_DESIGN_RULES now remembers it last selected TAB and screen position and window size, and its grid columns are automatically expanded to fit the column titles. Remembering screen position and size allows someone with multiple monitors, to have a given window always come up on the monitor last chosen for it.
1053 lines
34 KiB
C++
1053 lines
34 KiB
C++
/////////////////////////////////////////////////////////////////////////////
|
|
// Name: dialog_design_rules.cpp
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
/*
|
|
* This program source code file is part of KICAD, a free EDA CAD application.
|
|
*
|
|
* Copyright (C) 2004-2009 Jean-Pierre Charras, jean-pierre.charras@gpisa-lab.inpg.fr
|
|
* Copyright (C) 2009 Dick Hollenbeck, dick@softplc.com
|
|
* Copyright (C) 2009 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
|
|
*/
|
|
|
|
|
|
/* functions relatives to the design rules editor
|
|
*/
|
|
#include "fctsys.h"
|
|
#include "common.h"
|
|
#include "class_drawpanel.h"
|
|
|
|
#include "confirm.h"
|
|
#include "pcbnew.h"
|
|
#include "wxPcbStruct.h"
|
|
#include "class_board_design_settings.h"
|
|
|
|
#include "pcbnew_id.h"
|
|
#include "dialog_design_rules.h"
|
|
#include "wx/generic/gridctrl.h"
|
|
|
|
|
|
// Field Positions on rules grid
|
|
enum {
|
|
GRID_CLEARANCE,
|
|
GRID_TRACKSIZE,
|
|
GRID_VIASIZE,
|
|
GRID_VIADRILL,
|
|
GRID_uVIASIZE,
|
|
GRID_uVIADRILL,
|
|
};
|
|
|
|
const wxString DIALOG_DESIGN_RULES::wildCard = _("* (Any)");
|
|
|
|
// dialog should remember it previously selected tab
|
|
int DIALOG_DESIGN_RULES::s_LastTabSelection = -1;
|
|
|
|
// dialog should remember its previous screen position and size
|
|
wxPoint DIALOG_DESIGN_RULES::s_LastPos( -1, -1 );
|
|
wxSize DIALOG_DESIGN_RULES::s_LastSize;
|
|
|
|
|
|
|
|
|
|
/**
|
|
* Function EnsureGridColumnWidths
|
|
* resizes all the columns in a wxGrid based only on the requirements of the
|
|
* column titles and not on the grid cell requirements, assuming that the grid
|
|
* cell width requirements are narrower than the column title requirements.
|
|
*/
|
|
// @todo: maybe move this to common.cpp if it works.
|
|
void EnsureGridColumnWidths( wxGrid* aGrid )
|
|
{
|
|
wxScreenDC sDC;
|
|
|
|
sDC.SetFont( aGrid->GetLabelFont() );
|
|
|
|
int colCount = aGrid->GetNumberCols();
|
|
for( int col=0; col<colCount; ++col )
|
|
{
|
|
// add two spaces to the text and size it.
|
|
wxString colText = aGrid->GetColLabelValue( col ) + ' ' + ' ';
|
|
|
|
wxSize needed = sDC.GetTextExtent( colText );
|
|
|
|
// set the width of this column
|
|
aGrid->SetColSize( col, needed.x );
|
|
}
|
|
}
|
|
|
|
|
|
/***********************************************************************************/
|
|
DIALOG_DESIGN_RULES::DIALOG_DESIGN_RULES( WinEDA_PcbFrame* parent ) :
|
|
DIALOG_DESIGN_RULES_BASE( parent )
|
|
/***********************************************************************************/
|
|
{
|
|
m_Parent = parent;
|
|
SetAutoLayout( true );
|
|
|
|
EnsureGridColumnWidths( m_grid ); // override any column widths set by wxformbuilder.
|
|
|
|
wxListItem column0;
|
|
wxListItem column1;
|
|
|
|
column0.Clear();
|
|
column1.Clear();
|
|
|
|
column0.SetImage( -1 );
|
|
column1.SetImage( -1 );
|
|
|
|
column0.SetText( _( "Net" ) );
|
|
column1.SetText( _( "Class" ) );
|
|
|
|
m_leftListCtrl->InsertColumn( 0, column0 );
|
|
m_leftListCtrl->InsertColumn( 1, column1 );
|
|
m_leftListCtrl->SetColumnWidth( 0, wxLIST_AUTOSIZE );
|
|
m_leftListCtrl->SetColumnWidth( 1, wxLIST_AUTOSIZE );
|
|
|
|
m_rightListCtrl->InsertColumn( 0, column0 );
|
|
m_rightListCtrl->InsertColumn( 1, column1 );
|
|
m_rightListCtrl->SetColumnWidth( 0, wxLIST_AUTOSIZE );
|
|
m_rightListCtrl->SetColumnWidth( 1, wxLIST_AUTOSIZE );
|
|
|
|
// if user has been into the dialog before, go back to same tab
|
|
if( s_LastTabSelection != -1 )
|
|
{
|
|
m_DRnotebook->SetSelection( s_LastTabSelection );
|
|
}
|
|
|
|
InitDialogRules();
|
|
Layout();
|
|
GetSizer()->Fit( this );
|
|
GetSizer()->SetSizeHints( this );
|
|
|
|
if( s_LastPos.x != -1 )
|
|
{
|
|
SetSize( s_LastSize );
|
|
SetPosition( s_LastPos );
|
|
}
|
|
else
|
|
Center();
|
|
}
|
|
|
|
|
|
/* Display on m_MessagesList the current global settings:
|
|
* minimal values for tracks, vias, clearance ...
|
|
*/
|
|
void DIALOG_DESIGN_RULES::PrintCurrentSettings( )
|
|
{
|
|
wxString msg, value;
|
|
int internal_units = m_Parent->m_InternalUnits;
|
|
|
|
m_MessagesList->AppendToPage(_("<b>Current general settings:</b><br>") );
|
|
|
|
// Display min values:
|
|
value = ReturnStringFromValue( g_UnitMetric, g_DesignSettings.m_TrackMinWidth, internal_units, true );
|
|
msg.Printf(_("Minimum value for tracks width: <b>%s</b><br>\n"), GetChars( value ) );
|
|
m_MessagesList->AppendToPage(msg);
|
|
|
|
value = ReturnStringFromValue( g_UnitMetric, g_DesignSettings.m_ViasMinSize, internal_units, true );
|
|
msg.Printf(_("Minimum value for vias diameter: <b>%s</b><br>\n"), GetChars( value ) );
|
|
m_MessagesList->AppendToPage(msg);
|
|
|
|
value = ReturnStringFromValue( g_UnitMetric, g_DesignSettings.m_MicroViasMinSize, internal_units, true );
|
|
msg.Printf(_("Minimum value for microvias diameter: <b>%s</b><br>\n"), GetChars( value ) );
|
|
m_MessagesList->AppendToPage(msg);
|
|
|
|
}
|
|
|
|
|
|
/******************************************/
|
|
void DIALOG_DESIGN_RULES::InitDialogRules()
|
|
/******************************************/
|
|
{
|
|
SetFocus();
|
|
SetReturnCode( 0 );
|
|
|
|
// Initialize the layers grid:
|
|
m_Pcb = m_Parent->GetBoard();
|
|
|
|
// Initialize the Rules List
|
|
InitRulesList();
|
|
|
|
// copy all NETs into m_AllNets by adding them as NETCUPs.
|
|
|
|
// @todo go fix m_Pcb->SynchronizeNetsAndNetClasses() so that the netcode==0 is not present in the BOARD::m_NetClasses
|
|
|
|
|
|
NETCLASS* netclass;
|
|
|
|
NETCLASSES& netclasses = m_Pcb->m_NetClasses;
|
|
|
|
netclass = netclasses.GetDefault();
|
|
|
|
// Initialize list of nets for Default Net Class
|
|
for( NETCLASS::const_iterator name = netclass->begin(); name != netclass->end(); ++name )
|
|
{
|
|
m_AllNets.push_back( NETCUP( *name, netclass->GetName() ) );
|
|
}
|
|
|
|
// Initialize list of nets for others (custom) Net Classes
|
|
for( NETCLASSES::const_iterator nc = netclasses.begin(); nc != netclasses.end(); ++nc )
|
|
{
|
|
netclass = nc->second;
|
|
|
|
for( NETCLASS::const_iterator name = netclass->begin(); name != netclass->end(); ++name )
|
|
{
|
|
m_AllNets.push_back( NETCUP( *name, netclass->GetName() ) );
|
|
}
|
|
}
|
|
|
|
InitializeRulesSelectionBoxes();
|
|
InitGlobalRules();
|
|
|
|
PrintCurrentSettings( );
|
|
}
|
|
|
|
/*******************************************/
|
|
void DIALOG_DESIGN_RULES::InitGlobalRules()
|
|
/*******************************************/
|
|
{
|
|
AddUnitSymbol( *m_ViaMinTitle );
|
|
AddUnitSymbol( *m_ViaMinDrillTitle );
|
|
AddUnitSymbol( *m_MicroViaMinSizeTitle );
|
|
AddUnitSymbol( *m_MicroViaMinDrillTitle );
|
|
AddUnitSymbol( *m_TrackMinWidthTitle );
|
|
|
|
int Internal_Unit = m_Parent->m_InternalUnits;
|
|
PutValueInLocalUnits( *m_SetViasMinSizeCtrl, g_DesignSettings.m_ViasMinSize, Internal_Unit );
|
|
PutValueInLocalUnits( *m_SetViasMinDrillCtrl, g_DesignSettings.m_ViasMinDrill, Internal_Unit );
|
|
|
|
if( g_DesignSettings.m_CurrentViaType != VIA_THROUGH )
|
|
m_OptViaType->SetSelection( 1 );
|
|
|
|
m_AllowMicroViaCtrl->SetSelection( g_DesignSettings.m_MicroViasAllowed ? 1 : 0);
|
|
PutValueInLocalUnits( *m_SetMicroViasMinSizeCtrl, g_DesignSettings.m_MicroViasMinSize, Internal_Unit );
|
|
PutValueInLocalUnits( *m_SetMicroViasMinDrillCtrl, g_DesignSettings.m_MicroViasMinDrill, Internal_Unit );
|
|
|
|
PutValueInLocalUnits( *m_SetTrackMinWidthCtrl, g_DesignSettings.m_TrackMinWidth, Internal_Unit );
|
|
|
|
// Initialize Vias and Tracks sizes lists.
|
|
// note we display only extra values, never the current netclass value.
|
|
// (the first value in histories list)
|
|
m_TracksWidthList = m_Parent->GetBoard()->m_TrackWidthList;
|
|
m_TracksWidthList.erase( m_TracksWidthList.begin() ); // remove the netclass value
|
|
m_ViasDimensionsList = m_Parent->GetBoard()->m_ViasDimensionsList;
|
|
m_ViasDimensionsList.erase( m_ViasDimensionsList.begin() ); // remove the netclass value
|
|
InitDimensionsLists();
|
|
|
|
}
|
|
|
|
/***************************************************/
|
|
void DIALOG_DESIGN_RULES::InitDimensionsLists()
|
|
/***************************************************/
|
|
|
|
/* Populates the lists of sizes (Tracks width list and Vias diameters & drill list)
|
|
*/
|
|
{
|
|
wxString msg;
|
|
int Internal_Unit = m_Parent->m_InternalUnits;
|
|
|
|
for( unsigned ii = 0; ii < m_TracksWidthList.size(); ii++ )
|
|
{
|
|
msg = ReturnStringFromValue( g_UnitMetric, m_TracksWidthList[ii], Internal_Unit, false );
|
|
m_gridTrackWidthList->SetCellValue( ii, 0, msg );
|
|
}
|
|
|
|
for( unsigned ii = 0; ii < m_ViasDimensionsList.size(); ii++ )
|
|
{
|
|
msg = ReturnStringFromValue( g_UnitMetric, m_ViasDimensionsList[ii].m_Diameter,
|
|
Internal_Unit, false );
|
|
m_gridViaSizeList->SetCellValue( ii, 0, msg );
|
|
if( m_ViasDimensionsList[ii].m_Drill > 0 )
|
|
{
|
|
msg = ReturnStringFromValue( g_UnitMetric, m_ViasDimensionsList[ii].m_Drill,
|
|
Internal_Unit, false );
|
|
m_gridViaSizeList->SetCellValue( ii, 1, msg );
|
|
}
|
|
}
|
|
|
|
// recompute the column widths here, after setting texts
|
|
m_gridViaSizeList->SetColumnWidth( 0, wxLIST_AUTOSIZE );
|
|
m_gridTrackWidthList->SetColumnWidth( 0, wxLIST_AUTOSIZE );
|
|
}
|
|
|
|
// Sort comparison function (helper for makePointers() )
|
|
static bool sortByClassThenName( NETCUP* a, NETCUP* b )
|
|
{
|
|
// return a < b
|
|
|
|
if( a->clazz < b->clazz )
|
|
return true;
|
|
|
|
if( a->net < b->net )
|
|
return true;
|
|
|
|
return false;
|
|
}
|
|
|
|
void DIALOG_DESIGN_RULES::makePointers( PNETCUPS* aList, const wxString& aNetClassName )
|
|
{
|
|
aList->clear();
|
|
|
|
if( wildCard == aNetClassName )
|
|
{
|
|
for( NETCUPS::iterator n = m_AllNets.begin(); n != m_AllNets.end(); ++n )
|
|
{
|
|
aList->push_back( &*n );
|
|
}
|
|
|
|
sort( aList->begin(), aList->end(), sortByClassThenName );
|
|
|
|
// could use a different sort order for wildCard case.
|
|
}
|
|
else
|
|
{
|
|
for( NETCUPS::iterator n = m_AllNets.begin(); n != m_AllNets.end(); ++n )
|
|
{
|
|
if( n->clazz == aNetClassName )
|
|
aList->push_back( &*n );
|
|
}
|
|
|
|
sort( aList->begin(), aList->end(), sortByClassThenName );
|
|
}
|
|
}
|
|
|
|
|
|
void DIALOG_DESIGN_RULES::setRowItem( wxListCtrl* aListCtrl, int aRow, NETCUP* aNetAndClass )
|
|
{
|
|
wxASSERT( aRow >= 0 );
|
|
|
|
// insert blanks if aRow is larger than existing count
|
|
while( aRow >= aListCtrl->GetItemCount() )
|
|
{
|
|
long ndx = aListCtrl->InsertItem( aListCtrl->GetItemCount(), wxEmptyString );
|
|
|
|
wxASSERT( ndx >= 0 );
|
|
|
|
aListCtrl->SetItem( ndx, 1, wxEmptyString );
|
|
}
|
|
|
|
aListCtrl->SetItem( aRow, 0, aNetAndClass->net );
|
|
aListCtrl->SetItem( aRow, 1, aNetAndClass->clazz );
|
|
|
|
// recompute the column widths here, after setting texts
|
|
aListCtrl->SetColumnWidth( 0, wxLIST_AUTOSIZE );
|
|
aListCtrl->SetColumnWidth( 1, wxLIST_AUTOSIZE );
|
|
}
|
|
|
|
|
|
/**
|
|
* Function FillListBoxWithNetNames
|
|
* populates aListCtrl with net names and class names from m_AllNets in a two column display.
|
|
*/
|
|
void DIALOG_DESIGN_RULES::FillListBoxWithNetNames( wxListCtrl* aListCtrl, const wxString& aNetClass )
|
|
{
|
|
aListCtrl->DeleteAllItems();
|
|
|
|
PNETCUPS ptrList;
|
|
|
|
// get a subset of m_AllNets in pointer form, sorted as desired.
|
|
makePointers( &ptrList, aNetClass );
|
|
|
|
#if 0 && defined(DEBUG)
|
|
int r = 0;
|
|
for( PNETCUPS::iterator i = ptrList.begin(); i!=ptrList.end(); ++i, ++r )
|
|
{
|
|
printf("[%d]: %s %s\n", r, CONV_TO_UTF8( (*i)->net ), CONV_TO_UTF8( (*i)->clazz ) );
|
|
}
|
|
#endif
|
|
|
|
// to speed up inserting we hide the control temporarily
|
|
aListCtrl->Hide();
|
|
|
|
int row = 0;
|
|
for( PNETCUPS::iterator i = ptrList.begin(); i!=ptrList.end(); ++i, ++row )
|
|
{
|
|
setRowItem( aListCtrl, row, *i );
|
|
}
|
|
|
|
aListCtrl->Show();
|
|
}
|
|
|
|
|
|
/* Initialize the combo boxes by the list of existing net classes
|
|
*/
|
|
void DIALOG_DESIGN_RULES::InitializeRulesSelectionBoxes()
|
|
{
|
|
m_rightClassChoice->Clear();
|
|
m_leftClassChoice->Clear();
|
|
|
|
m_rightClassChoice->Append( wildCard );
|
|
m_leftClassChoice->Append( wildCard );
|
|
|
|
for( int ii = 0; ii < m_grid->GetNumberRows(); ii++ )
|
|
{
|
|
m_rightClassChoice->Append( m_grid->GetRowLabelValue( ii ) );
|
|
m_leftClassChoice->Append( m_grid->GetRowLabelValue( ii ) );
|
|
}
|
|
|
|
m_rightClassChoice->Select( 0 );
|
|
m_leftClassChoice->Select( 0 );
|
|
|
|
m_buttonRightToLeft->Enable( false );
|
|
m_buttonLeftToRight->Enable( false );;
|
|
|
|
FillListBoxWithNetNames( m_leftListCtrl, m_leftClassChoice->GetStringSelection() );
|
|
FillListBoxWithNetNames( m_rightListCtrl, m_rightClassChoice->GetStringSelection() );
|
|
}
|
|
|
|
|
|
/* Initialize the rules list from board
|
|
*/
|
|
|
|
static void class2gridRow( wxGrid* grid, int row, NETCLASS* nc, int units )
|
|
{
|
|
wxString msg;
|
|
|
|
// label is netclass name
|
|
grid->SetRowLabelValue( row, nc->GetName() );
|
|
|
|
msg = ReturnStringFromValue( g_UnitMetric, nc->GetClearance(), units );
|
|
grid->SetCellValue( row, GRID_CLEARANCE, msg );
|
|
|
|
msg = ReturnStringFromValue( g_UnitMetric, nc->GetTrackWidth(), units );
|
|
grid->SetCellValue( row, GRID_TRACKSIZE, msg );
|
|
|
|
msg = ReturnStringFromValue( g_UnitMetric, nc->GetViaDiameter(), units );
|
|
grid->SetCellValue( row, GRID_VIASIZE, msg );
|
|
|
|
msg = ReturnStringFromValue( g_UnitMetric, nc->GetViaDrill(), units );
|
|
grid->SetCellValue( row, GRID_VIADRILL, msg );
|
|
|
|
msg = ReturnStringFromValue( g_UnitMetric, nc->GetuViaDiameter(), units );
|
|
grid->SetCellValue( row, GRID_uVIASIZE, msg );
|
|
|
|
msg = ReturnStringFromValue( g_UnitMetric, nc->GetuViaDrill(), units );
|
|
grid->SetCellValue( row, GRID_uVIADRILL, msg );
|
|
}
|
|
|
|
/** Function InitRulesList()
|
|
* Fill the grid showing current rules with values
|
|
*/
|
|
void DIALOG_DESIGN_RULES::InitRulesList()
|
|
{
|
|
NETCLASSES& netclasses = m_Pcb->m_NetClasses;
|
|
|
|
// the +1 is for the Default NETCLASS.
|
|
if( netclasses.GetCount()+1 > (unsigned) m_grid->GetNumberRows() )
|
|
{
|
|
m_grid->AppendRows( netclasses.GetCount()+1 - m_grid->GetNumberRows() );
|
|
}
|
|
|
|
// enter the Default NETCLASS.
|
|
class2gridRow( m_grid, 0, netclasses.GetDefault(), m_Parent->m_InternalUnits );
|
|
|
|
// enter others netclasses
|
|
int row = 1;
|
|
for( NETCLASSES::iterator i=netclasses.begin(); i!=netclasses.end(); ++i, ++row )
|
|
{
|
|
NETCLASS* netclass = i->second;
|
|
|
|
class2gridRow( m_grid, row, netclass, m_Parent->m_InternalUnits );
|
|
}
|
|
}
|
|
|
|
|
|
static void gridRow2class( wxGrid* grid, int row, NETCLASS* nc, int units )
|
|
{
|
|
#define MYCELL(col) \
|
|
ReturnValueFromString( g_UnitMetric, grid->GetCellValue( row, col ), units )
|
|
|
|
nc->SetClearance( MYCELL( GRID_CLEARANCE ) );
|
|
nc->SetTrackWidth( MYCELL( GRID_TRACKSIZE ) );
|
|
nc->SetViaDiameter( MYCELL( GRID_VIASIZE ) );
|
|
nc->SetViaDrill( MYCELL( GRID_VIADRILL ) );
|
|
nc->SetuViaDiameter( MYCELL( GRID_uVIASIZE ) );
|
|
nc->SetuViaDrill( MYCELL( GRID_uVIADRILL ) );
|
|
}
|
|
|
|
|
|
/* Copy the rules list from grid to board
|
|
*/
|
|
void DIALOG_DESIGN_RULES::CopyRulesListToBoard()
|
|
{
|
|
NETCLASSES& netclasses = m_Pcb->m_NetClasses;
|
|
|
|
// Remove all netclasses from board. We'll copy new list after
|
|
netclasses.Clear();
|
|
|
|
// Copy the default NetClass:
|
|
gridRow2class( m_grid, 0, netclasses.GetDefault(), m_Parent->m_InternalUnits );
|
|
|
|
// Copy other NetClasses :
|
|
for( int row = 1; row < m_grid->GetNumberRows(); ++row )
|
|
{
|
|
NETCLASS* nc = new NETCLASS( m_Pcb, m_grid->GetRowLabelValue( row ) );
|
|
|
|
if( !m_Pcb->m_NetClasses.Add( nc ) )
|
|
{
|
|
// this netclass cannot be added because an other netclass with the same name exists
|
|
// Should not occur because OnAddNetclassClick() tests for existing NetClass names
|
|
wxString msg;
|
|
msg.Printf( wxT("CopyRulesListToBoard(): The NetClass \"%s\" already exists. Skip"),
|
|
GetChars( m_grid->GetRowLabelValue( row ) ) );
|
|
wxMessageBox( msg );
|
|
delete nc;
|
|
continue;
|
|
}
|
|
|
|
gridRow2class( m_grid, row, nc, m_Parent->m_InternalUnits );
|
|
}
|
|
|
|
// Now read all nets and push them in the corresponding netclass net buffer
|
|
for( NETCUPS::const_iterator netcup = m_AllNets.begin(); netcup != m_AllNets.end(); ++netcup )
|
|
{
|
|
NETCLASS* nc = netclasses.Find( netcup->clazz );
|
|
wxASSERT( nc );
|
|
nc->Add( netcup->net );
|
|
}
|
|
|
|
m_Pcb->SynchronizeNetsAndNetClasses();
|
|
}
|
|
|
|
/*************************************************/
|
|
void DIALOG_DESIGN_RULES::CopyGlobalRulesToBoard()
|
|
/*************************************************/
|
|
{
|
|
g_DesignSettings.m_CurrentViaType = VIA_THROUGH;
|
|
if( m_OptViaType->GetSelection() > 0 )
|
|
g_DesignSettings.m_CurrentViaType = VIA_BLIND_BURIED;
|
|
|
|
// Update vias minimum values for DRC
|
|
g_DesignSettings.m_ViasMinSize =
|
|
ReturnValueFromTextCtrl( *m_SetViasMinSizeCtrl, m_Parent->m_InternalUnits );
|
|
g_DesignSettings.m_ViasMinDrill =
|
|
ReturnValueFromTextCtrl( *m_SetViasMinDrillCtrl, m_Parent->m_InternalUnits );
|
|
|
|
g_DesignSettings.m_MicroViasAllowed = m_AllowMicroViaCtrl->GetSelection() == 1;
|
|
|
|
// Update microvias minimum values for DRC
|
|
g_DesignSettings.m_MicroViasMinSize =
|
|
ReturnValueFromTextCtrl( *m_SetMicroViasMinSizeCtrl, m_Parent->m_InternalUnits );
|
|
g_DesignSettings.m_MicroViasMinDrill =
|
|
ReturnValueFromTextCtrl( *m_SetMicroViasMinDrillCtrl, m_Parent->m_InternalUnits );
|
|
|
|
// Update tracks minimum values for DRC
|
|
g_DesignSettings.m_TrackMinWidth =
|
|
ReturnValueFromTextCtrl( *m_SetTrackMinWidthCtrl, m_Parent->m_InternalUnits );
|
|
}
|
|
|
|
/*******************************************************************/
|
|
void DIALOG_DESIGN_RULES::CopyDimensionsListsToBoard( )
|
|
/*******************************************************************/
|
|
{
|
|
wxString msg;
|
|
|
|
// Reinitialize m_TrackWidthList
|
|
m_TracksWidthList.clear();
|
|
for( int row = 0; row < m_gridTrackWidthList->GetNumberRows(); ++row )
|
|
{
|
|
msg = m_gridTrackWidthList->GetCellValue( row, 0 );
|
|
if( msg.IsEmpty() )
|
|
continue;
|
|
int value = ReturnValueFromString( g_UnitMetric, msg, m_Parent->m_InternalUnits );
|
|
m_TracksWidthList.push_back( value);
|
|
}
|
|
// Sort new list by by increasing value
|
|
sort( m_TracksWidthList.begin(), m_TracksWidthList.end() );
|
|
|
|
// Reinitialize m_TrackWidthList
|
|
m_ViasDimensionsList.clear();
|
|
for( int row = 0; row < m_gridViaSizeList->GetNumberRows(); ++row )
|
|
{
|
|
msg = m_gridViaSizeList->GetCellValue( row, 0 );
|
|
if( msg.IsEmpty() )
|
|
continue;
|
|
int value = ReturnValueFromString( g_UnitMetric, msg, m_Parent->m_InternalUnits );
|
|
VIA_DIMENSION via_dim;
|
|
via_dim.m_Diameter = value;
|
|
msg = m_gridViaSizeList->GetCellValue( row, 1 );
|
|
if( ! msg.IsEmpty() )
|
|
{
|
|
value = ReturnValueFromString( g_UnitMetric, msg, m_Parent->m_InternalUnits );
|
|
via_dim.m_Drill = value;
|
|
}
|
|
m_ViasDimensionsList.push_back( via_dim);
|
|
}
|
|
// Sort new list by by increasing value
|
|
sort( m_ViasDimensionsList.begin(), m_ViasDimensionsList.end() );
|
|
|
|
std::vector <int>* tlist = &m_Parent->GetBoard()->m_TrackWidthList;
|
|
tlist->erase( tlist->begin() + 1, tlist->end() ); // Remove old "custom" sizes
|
|
tlist->insert( tlist->end(), m_TracksWidthList.begin(), m_TracksWidthList.end() ); //Add new "custom" sizes
|
|
|
|
// Reinitialize m_ViaSizeList
|
|
std::vector <VIA_DIMENSION>* vialist = &m_Parent->GetBoard()->m_ViasDimensionsList;
|
|
vialist->erase( vialist->begin() + 1, vialist->end() );
|
|
vialist->insert( vialist->end(), m_ViasDimensionsList.begin(), m_ViasDimensionsList.end() );
|
|
|
|
m_Parent->m_TrackAndViasSizesList_Changed = true;
|
|
}
|
|
|
|
|
|
/*****************************************************************/
|
|
void DIALOG_DESIGN_RULES::OnCancelButtonClick( wxCommandEvent& event )
|
|
/*****************************************************************/
|
|
{
|
|
s_LastTabSelection = m_DRnotebook->GetSelection();
|
|
|
|
// Save the dialog's position before finishing
|
|
s_LastPos = GetPosition();
|
|
s_LastSize = GetSize();
|
|
|
|
EndModal( wxID_CANCEL );
|
|
}
|
|
|
|
|
|
/**************************************************************************/
|
|
void DIALOG_DESIGN_RULES::OnOkButtonClick( wxCommandEvent& event )
|
|
/**************************************************************************/
|
|
{
|
|
s_LastTabSelection = m_DRnotebook->GetSelection();
|
|
|
|
if( !TestDataValidity() )
|
|
{
|
|
DisplayError( this, _( "Errors detected, Abort" ) );
|
|
return;
|
|
}
|
|
|
|
CopyRulesListToBoard();
|
|
CopyGlobalRulesToBoard();
|
|
CopyDimensionsListsToBoard( );
|
|
|
|
// Save the dialog's position before finishing
|
|
s_LastPos = GetPosition();
|
|
s_LastSize = GetSize();
|
|
|
|
EndModal( wxID_OK );
|
|
|
|
m_Parent->AuxiliaryToolBar_Update_UI();
|
|
}
|
|
|
|
|
|
/**************************************************************************/
|
|
void DIALOG_DESIGN_RULES::OnAddNetclassClick( wxCommandEvent& event )
|
|
/**************************************************************************/
|
|
{
|
|
wxString class_name;
|
|
|
|
if( Get_Message( _( "New Net Class Name:" ),
|
|
wxEmptyString,
|
|
class_name,
|
|
this ) )
|
|
return;
|
|
|
|
// The name must dot exists:
|
|
for( int ii = 0; ii < m_grid->GetNumberRows(); ii++ )
|
|
{
|
|
wxString value;
|
|
value = m_grid->GetRowLabelValue( ii );
|
|
if( class_name.CmpNoCase( value ) == 0 ) // Already exists!
|
|
{
|
|
DisplayError( this, _( "This NetClass is already existing, cannot add it; Aborted" ) );
|
|
return;
|
|
}
|
|
}
|
|
|
|
m_grid->AppendRows();
|
|
m_grid->SetRowLabelValue(
|
|
m_grid->GetNumberRows() - 1,
|
|
class_name );
|
|
|
|
// Copy values of the default class:
|
|
int irow = m_grid->GetNumberRows() - 1;
|
|
for( int icol = 0; icol < m_grid->GetNumberCols(); icol++ )
|
|
{
|
|
wxString value;
|
|
value = m_grid->GetCellValue( 0, icol );
|
|
m_grid->SetCellValue( irow, icol, value );
|
|
}
|
|
|
|
InitializeRulesSelectionBoxes();
|
|
}
|
|
|
|
// Sort function for wxArrayInt. Items (ints) are sorted by decreasing value
|
|
// used in DIALOG_DESIGN_RULES::OnRemoveNetclassClick
|
|
int sort_int(int *first, int *second)
|
|
{
|
|
return * second - *first;
|
|
}
|
|
/**************************************************************************/
|
|
void DIALOG_DESIGN_RULES::OnRemoveNetclassClick( wxCommandEvent& event )
|
|
/**************************************************************************/
|
|
{
|
|
wxArrayInt select = m_grid->GetSelectedRows();
|
|
// Sort selection by decreasing index order:
|
|
select.Sort(sort_int);
|
|
bool reinit = false;
|
|
// rows labels are not removed when deleting rows: they are not deleted.
|
|
// So we must store them, remove correponding labels and reinit them
|
|
wxArrayString labels;
|
|
for( int ii = 0; ii < m_grid->GetNumberRows(); ii++ )
|
|
labels.Add(m_grid->GetRowLabelValue(ii));
|
|
// Delete rows from last to first (this is the order wxArrayInt select after sorting) )
|
|
// This order is Ok when removing rows
|
|
for( unsigned ii = 0; ii < select.GetCount(); ii++ )
|
|
{
|
|
int grid_row = select[ii];
|
|
if( grid_row != 0 ) // Do not remove the default class
|
|
{
|
|
wxString classname = m_grid->GetRowLabelValue( grid_row );
|
|
m_grid->DeleteRows( grid_row );
|
|
labels.RemoveAt(grid_row); // Remove corresponding row label
|
|
reinit = true;
|
|
|
|
// reset the net class to default for members of the removed class
|
|
swapNetClass( classname, NETCLASS::Default );
|
|
}
|
|
else
|
|
wxMessageBox(_("The defaut Netclass cannot be removed") );
|
|
}
|
|
if( reinit )
|
|
{
|
|
// Reinit labels :
|
|
for( unsigned ii = 1; ii < labels.GetCount(); ii++ )
|
|
m_grid->SetRowLabelValue(ii, labels[ii]);
|
|
|
|
InitializeRulesSelectionBoxes();
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Called on "Move Up" button click
|
|
* the selected(s) rules are moved up
|
|
* The default netclass is always the first rule
|
|
*/
|
|
void DIALOG_DESIGN_RULES::OnMoveUpSelectedNetClass( wxCommandEvent& event )
|
|
{
|
|
// Cannot move up rules if we have 1 or 2 rules only
|
|
if( m_grid->GetNumberRows() < 3 )
|
|
return;
|
|
wxArrayInt select = m_grid->GetSelectedRows();
|
|
|
|
bool reinit = false;
|
|
for( unsigned irow = 0; irow < select.GetCount(); irow++ )
|
|
{
|
|
int ii = select[irow];
|
|
if( ii < 2 ) // The default netclass *must* be the first netclass
|
|
continue; // so we cannot move up line 0 and 1
|
|
// Swap the rule and the previous rule
|
|
wxString curr_value, previous_value;
|
|
for( int icol = 0; icol < m_grid->GetNumberCols(); icol++ )
|
|
{
|
|
reinit = true;
|
|
curr_value = m_grid->GetCellValue( ii, icol );
|
|
previous_value = m_grid->GetCellValue( ii-1, icol );
|
|
m_grid->SetCellValue( ii, icol, previous_value );
|
|
m_grid->SetCellValue( ii-1, icol, curr_value );
|
|
}
|
|
curr_value = m_grid->GetRowLabelValue( ii );
|
|
previous_value = m_grid->GetRowLabelValue( ii-1 );
|
|
m_grid->SetRowLabelValue(ii, previous_value );
|
|
m_grid->SetRowLabelValue(ii-1, curr_value );
|
|
}
|
|
|
|
if( reinit )
|
|
InitializeRulesSelectionBoxes();
|
|
}
|
|
|
|
|
|
/*
|
|
* Called on the left Choice Box selection
|
|
*/
|
|
void DIALOG_DESIGN_RULES::OnLeftCBSelection( wxCommandEvent& event )
|
|
{
|
|
FillListBoxWithNetNames( m_leftListCtrl, m_leftClassChoice->GetStringSelection() );
|
|
if( m_leftClassChoice->GetStringSelection() == m_rightClassChoice->GetStringSelection() )
|
|
{
|
|
m_buttonRightToLeft->Enable( false );
|
|
m_buttonLeftToRight->Enable( false );
|
|
}
|
|
else
|
|
{
|
|
m_buttonRightToLeft->Enable( true );
|
|
m_buttonLeftToRight->Enable( true );
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
* Called on the Right Choice Box selection
|
|
*/
|
|
void DIALOG_DESIGN_RULES::OnRightCBSelection( wxCommandEvent& event )
|
|
{
|
|
FillListBoxWithNetNames( m_rightListCtrl, m_rightClassChoice->GetStringSelection() );
|
|
if( m_leftClassChoice->GetStringSelection() == m_rightClassChoice->GetStringSelection() )
|
|
{
|
|
m_buttonRightToLeft->Enable( false );
|
|
m_buttonLeftToRight->Enable( false );;
|
|
}
|
|
else
|
|
{
|
|
m_buttonRightToLeft->Enable( true );
|
|
m_buttonLeftToRight->Enable( true );
|
|
}
|
|
}
|
|
|
|
|
|
void DIALOG_DESIGN_RULES::moveSelectedItems( wxListCtrl* src, const wxString& newClassName )
|
|
{
|
|
wxListItem item;
|
|
wxString netName;
|
|
item.m_mask |= wxLIST_MASK_TEXT ; // Validate the member m_text of the wxListItem item
|
|
|
|
for( int row = 0; row < src->GetItemCount(); ++row )
|
|
{
|
|
if( !src->GetItemState( row, wxLIST_STATE_SELECTED ) )
|
|
continue;
|
|
|
|
item.SetColumn( 0 );
|
|
item.SetId( row );
|
|
|
|
src->GetItem( item );
|
|
netName = item.GetText();
|
|
|
|
setNetClass( netName, newClassName == wildCard ? NETCLASS::Default : newClassName );
|
|
}
|
|
}
|
|
|
|
|
|
void DIALOG_DESIGN_RULES::OnRightToLeftCopyButton( wxCommandEvent& event )
|
|
{
|
|
wxString newClassName = m_leftClassChoice->GetStringSelection();
|
|
|
|
moveSelectedItems( m_rightListCtrl, newClassName );
|
|
|
|
FillListBoxWithNetNames( m_leftListCtrl, m_leftClassChoice->GetStringSelection() );
|
|
FillListBoxWithNetNames( m_rightListCtrl, m_rightClassChoice->GetStringSelection() );
|
|
}
|
|
|
|
void DIALOG_DESIGN_RULES::OnLeftToRightCopyButton( wxCommandEvent& event )
|
|
{
|
|
wxString newClassName = m_rightClassChoice->GetStringSelection();
|
|
|
|
moveSelectedItems( m_leftListCtrl, newClassName );
|
|
|
|
FillListBoxWithNetNames( m_leftListCtrl, m_leftClassChoice->GetStringSelection() );
|
|
FillListBoxWithNetNames( m_rightListCtrl, m_rightClassChoice->GetStringSelection() );
|
|
}
|
|
|
|
|
|
/* Called on clicking the left "select all" button:
|
|
* select alls items of the left netname list lisxt box
|
|
*/
|
|
void DIALOG_DESIGN_RULES::OnLeftSelectAllButton( wxCommandEvent& event )
|
|
{
|
|
for( int ii = 0; ii < m_leftListCtrl->GetItemCount(); ii++ )
|
|
m_leftListCtrl->SetItemState( ii, wxLIST_STATE_SELECTED, wxLIST_STATE_SELECTED );
|
|
}
|
|
|
|
|
|
/* Called on clicking the right "select all" button:
|
|
* select alls items of the right netname list lisxt box
|
|
*/
|
|
void DIALOG_DESIGN_RULES::OnRightSelectAllButton( wxCommandEvent& event )
|
|
{
|
|
for( int ii = 0; ii < m_rightListCtrl->GetItemCount(); ii++ )
|
|
m_rightListCtrl->SetItemState( ii, wxLIST_STATE_SELECTED, wxLIST_STATE_SELECTED );
|
|
}
|
|
|
|
|
|
void DIALOG_DESIGN_RULES::setNetClass( const wxString& aNetName, const wxString& aClassName )
|
|
{
|
|
for( NETCUPS::iterator i = m_AllNets.begin(); i != m_AllNets.end(); ++i )
|
|
{
|
|
if( i->net == aNetName )
|
|
{
|
|
i->clazz = aClassName;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/* TestDataValidity
|
|
* Performs a control of data validity
|
|
* set the background of a bad cell in RED and display an info message
|
|
* @return true if Ok, false if error
|
|
*/
|
|
bool DIALOG_DESIGN_RULES::TestDataValidity()
|
|
{
|
|
bool result = true;
|
|
|
|
m_MessagesList->SetPage(wxEmptyString); // Clear message list
|
|
|
|
wxString msg;
|
|
|
|
int minViaDia = ReturnValueFromTextCtrl( *m_SetViasMinSizeCtrl, m_Parent->m_InternalUnits );
|
|
int minViaDrill = ReturnValueFromTextCtrl( *m_SetViasMinDrillCtrl, m_Parent->m_InternalUnits );
|
|
int minUViaDia = ReturnValueFromTextCtrl( *m_SetMicroViasMinSizeCtrl, m_Parent->m_InternalUnits );
|
|
int minUViaDrill = ReturnValueFromTextCtrl( *m_SetMicroViasMinDrillCtrl, m_Parent->m_InternalUnits );
|
|
int minTrackWidth = ReturnValueFromTextCtrl( *m_SetTrackMinWidthCtrl, m_Parent->m_InternalUnits );
|
|
|
|
|
|
for( int row = 0; row < m_grid->GetNumberRows(); row++ )
|
|
{
|
|
int tracksize = ReturnValueFromString( g_UnitMetric,
|
|
m_grid->GetCellValue( row, GRID_TRACKSIZE ),
|
|
m_Parent->m_InternalUnits );
|
|
if( tracksize < minTrackWidth )
|
|
{
|
|
result = false;
|
|
msg.Printf( _( "%s: <b>Track Size</b> < <b>Min Track Size</b><br>" ),
|
|
GetChars( m_grid->GetRowLabelValue(row)) );
|
|
|
|
m_MessagesList->AppendToPage( msg );
|
|
}
|
|
|
|
// Test vias
|
|
int viadia = ReturnValueFromString( g_UnitMetric,
|
|
m_grid->GetCellValue( row, GRID_VIASIZE ),
|
|
m_Parent->m_InternalUnits );
|
|
|
|
if( viadia < minViaDia )
|
|
{
|
|
result = false;
|
|
msg.Printf( _( "%s: <b>Via Diameter</b> < <b>Minimun Via Diameter</b><br>" ),
|
|
GetChars( m_grid->GetRowLabelValue(row)) );
|
|
|
|
m_MessagesList->AppendToPage( msg );
|
|
}
|
|
|
|
int viadrill = ReturnValueFromString( g_UnitMetric,
|
|
m_grid->GetCellValue( row, GRID_VIADRILL ),
|
|
m_Parent->m_InternalUnits );
|
|
if( viadrill >= viadia )
|
|
{
|
|
result = false;
|
|
msg.Printf( _( "%s: <b>Via Drill</b> ≥ <b>Via Dia</b><br>" ),
|
|
GetChars( m_grid->GetRowLabelValue(row)) );
|
|
|
|
m_MessagesList->AppendToPage( msg );
|
|
}
|
|
|
|
if( viadrill < minViaDrill )
|
|
{
|
|
result = false;
|
|
msg.Printf( _( "%s: <b>Via Drill</b> < <b>Min Via Drill</b><br>" ),
|
|
GetChars( m_grid->GetRowLabelValue(row)) );
|
|
|
|
m_MessagesList->AppendToPage( msg );
|
|
}
|
|
|
|
// Test Micro vias
|
|
int muviadia = ReturnValueFromString( g_UnitMetric,
|
|
m_grid->GetCellValue( row, GRID_uVIASIZE ),
|
|
m_Parent->m_InternalUnits );
|
|
|
|
if( muviadia < minUViaDia )
|
|
{
|
|
result = false;
|
|
msg.Printf( _( "%s: <b>MicroVia Diameter</b> < <b>MicroVia Min Diameter</b><br>" ),
|
|
GetChars( m_grid->GetRowLabelValue(row)) );
|
|
|
|
m_MessagesList->AppendToPage( msg );
|
|
}
|
|
|
|
int muviadrill = ReturnValueFromString( g_UnitMetric,
|
|
m_grid->GetCellValue( row, GRID_uVIADRILL ),
|
|
m_Parent->m_InternalUnits );
|
|
if( muviadrill >= muviadia )
|
|
{
|
|
result = false;
|
|
msg.Printf( _( "%s: <b>MicroVia Drill</b> ≥ <b>MicroVia Dia</b><br>" ),
|
|
GetChars( m_grid->GetRowLabelValue(row)) );
|
|
|
|
m_MessagesList->AppendToPage( msg );
|
|
}
|
|
|
|
if( muviadrill < minUViaDrill )
|
|
{
|
|
result = false;
|
|
msg.Printf( _( "%s: <b>MicroVia Drill</b> < <b>MicroVia Min Drill</b><br>" ),
|
|
GetChars( m_grid->GetRowLabelValue(row)) );
|
|
|
|
m_MessagesList->AppendToPage( msg );
|
|
}
|
|
}
|
|
|
|
// Test list of values for specific vias and tracks
|
|
for( int row = 1; row < m_gridTrackWidthList->GetNumberRows(); ++row )
|
|
{
|
|
wxString tvalue = m_gridTrackWidthList->GetCellValue(row, 0);
|
|
if( tvalue.IsEmpty() )
|
|
continue;
|
|
|
|
int tracksize = ReturnValueFromString( g_UnitMetric,
|
|
tvalue,
|
|
m_Parent->m_InternalUnits );
|
|
if( tracksize < minTrackWidth )
|
|
{
|
|
result = false;
|
|
msg.Printf( _( "<b>Extra Track %d Size</b> %s < <b>Min Track Size</b><br>" ),
|
|
row+1, GetChars( tvalue ) );
|
|
|
|
m_MessagesList->AppendToPage( msg );
|
|
}
|
|
if( tracksize > 10000 )
|
|
{
|
|
result = false;
|
|
msg.Printf( _( "<b>Extra Track %d Size</b> %s > <b>1 inch!</b><br>" ),
|
|
row+1, GetChars( tvalue ) );
|
|
|
|
m_MessagesList->AppendToPage( msg );
|
|
}
|
|
}
|
|
|
|
for( int row = 1; row < m_gridViaSizeList->GetNumberRows(); ++row )
|
|
{
|
|
wxString tvalue = m_gridViaSizeList->GetCellValue(row, 0);
|
|
if( tvalue.IsEmpty() )
|
|
continue;
|
|
|
|
int viadia = ReturnValueFromString( g_UnitMetric,
|
|
tvalue,
|
|
m_Parent->m_InternalUnits );
|
|
if( viadia < minViaDia )
|
|
{
|
|
result = false;
|
|
msg.Printf( _( "<b>Extra Via %d Size</b> %s < <b>Min Via Size</b><br>" ),
|
|
row+1, GetChars( tvalue ) );
|
|
|
|
m_MessagesList->AppendToPage( msg );
|
|
}
|
|
if( viadia > 10000 )
|
|
{
|
|
result = false;
|
|
msg.Printf( _( "<b>Extra Via %d Size</b>%s > <b>1 inch!</b><br>" ),
|
|
row+1, GetChars( tvalue ) );
|
|
|
|
m_MessagesList->AppendToPage( msg );
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|