kicad/pcbnew/dialogs/dialog_design_rules.cpp

1106 lines
35 KiB
C++
Raw Normal View History

/**
* @file dialog_design_rules.cpp
*/
2009-09-11 06:18:55 +00:00
/*
* This program source code file is part of KiCad, a free EDA CAD application.
2009-09-11 06:18:55 +00:00
*
* Copyright (C) 2004-2009 Jean-Pierre Charras, jp.charras at wanadoo.fr
2009-09-11 06:18:55 +00:00
* Copyright (C) 2009 Dick Hollenbeck, dick@softplc.com
* Copyright (C) 2009-2018 KiCad Developers, see change_log.txt for contributors.
2009-09-11 06:18:55 +00:00
*
* 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 relative to the design rules editor
*/
#include <fctsys.h>
#include <class_drawpanel.h>
#include <base_units.h>
#include <confirm.h>
#include <pcbnew.h>
2018-01-29 20:58:58 +00:00
#include <pcb_edit_frame.h>
2018-02-02 20:57:12 +00:00
#include <board_design_settings.h>
#include <bitmaps.h>
#include <pcbnew_id.h>
#include <class_track.h>
#include <macros.h>
#include <html_messagebox.h>
#include <dialog_text_entry.h>
#include <dialog_design_rules.h>
#include <wx/generic/gridctrl.h>
#include <dialog_design_rules_aux_helper_class.h>
2009-09-10 15:22:26 +00:00
#include <tool/tool_event.h>
#include <tool/tool_manager.h>
// Column labels for net lists
#define NET_TITLE _( "Net" )
#define CLASS_TITLE _( "Class" )
2009-09-10 15:22:26 +00:00
// Field Positions on rules grid
enum {
GRID_NAME = 0,
2009-09-10 15:22:26 +00:00
GRID_CLEARANCE,
GRID_TRACKSIZE,
GRID_VIASIZE,
GRID_VIADRILL,
GRID_uVIASIZE,
GRID_uVIADRILL,
GRID_DIFF_PAIR_WIDTH,
GRID_DIFF_PAIR_GAP
2009-09-10 15:22:26 +00:00
};
const wxString DIALOG_DESIGN_RULES::wildCard = _( "* (Any)" );
2009-09-10 15:22:26 +00:00
2009-11-02 22:08:22 +00:00
// dialog should remember its previously selected tab
int DIALOG_DESIGN_RULES::s_LastTabSelection = -1;
// methods for the helper class NETS_LIST_CTRL
wxString NETS_LIST_CTRL::OnGetItemText( long item, long column ) const
{
if( column == 0 )
{
if( item < (long) m_Netnames.GetCount() )
return m_Netnames[item];
else
return wxEmptyString;
}
else if( item < (long) m_Classnames.GetCount() )
return m_Classnames[item];
return wxEmptyString;
}
void NETS_LIST_CTRL::SetRowItems( unsigned aRow,
const wxString& aNetname,
const wxString& aNetclassName )
{
// insert blanks if aRow is larger than existing row count
unsigned cnt = m_Netnames.GetCount();
if( cnt <= aRow )
m_Netnames.Add( wxEmptyString, aRow - cnt + 1 );
cnt = m_Classnames.GetCount();
if( cnt <= aRow )
m_Classnames.Add( wxEmptyString, aRow - cnt + 1 );
if( (int)aRow <= GetItemCount() )
SetItemCount( aRow + 1 );
m_Netnames[aRow] = aNetname;
m_Classnames[aRow] = aNetclassName;
}
DIALOG_DESIGN_RULES::DIALOG_DESIGN_RULES( PCB_EDIT_FRAME* parent ) :
DIALOG_DESIGN_RULES_BASE( parent ),
m_trackMinWidth( parent, m_TrackMinWidthTitle, m_SetTrackMinWidthCtrl, m_TrackMinWidthUnits, true, 0 ),
m_viaMinDiameter( parent, m_ViaMinTitle, m_SetViasMinSizeCtrl, m_ViaMinUnits, true, 0 ),
m_viaMinDrill( parent, m_ViaMinDrillTitle, m_SetViasMinDrillCtrl, m_ViaMinDrillUnits, true, 0 ),
m_microViaMinDiameter( parent, m_MicroViaMinSizeTitle, m_SetMicroViasMinSizeCtrl, m_MicroViaMinSizeUnits, true, 0 ),
m_microViaMinDrill( parent, m_MicroViaMinDrillTitle, m_SetMicroViasMinDrillCtrl, m_MicroViaMinDrillUnits, true, 0 )
{
m_Parent = parent;
m_gridErrorGrid = nullptr;
// Loading the grid messes up the column widths set in wxFormBuilder
m_originalColWidths = new int[ m_grid->GetNumberCols() ];
for( int i = 0; i < m_grid->GetNumberCols(); ++i )
m_originalColWidths[ i ] = m_grid->GetColSize( i );
wxListItem column0;
wxListItem column1;
2009-09-10 15:22:26 +00:00
column0.Clear();
column1.Clear();
column0.SetMask( wxLIST_MASK_TEXT );
column1.SetMask( wxLIST_MASK_TEXT );
2009-09-10 15:22:26 +00:00
column0.SetText( NET_TITLE );
column1.SetText( CLASS_TITLE );
2009-09-10 15:22:26 +00:00
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 );
}
2009-09-10 15:22:26 +00:00
m_addButton->SetBitmap( KiBitmap( small_plus_xpm ) );
m_removeButton->SetBitmap( KiBitmap( trash_xpm ) );
m_moveUpButton->SetBitmap( KiBitmap( small_up_xpm ) );
m_moveDownButton->SetBitmap( KiBitmap( small_down_xpm ) );
m_sdbSizer1OK->SetDefault();
// Allow tabbing out of grid controls.
m_grid->SetTabBehaviour( wxGrid::Tab_Leave );
m_gridViaSizeList->SetTabBehaviour( wxGrid::Tab_Leave );
m_gridTrackWidthList->SetTabBehaviour( wxGrid::Tab_Leave );
// wxFormBuilder doesn't include this event...
m_grid->Connect( wxEVT_GRID_CELL_CHANGING, wxGridEventHandler( DIALOG_DESIGN_RULES::OnNetclassGridCellChanging ), NULL, this );
m_panelNetClassesEditor->Layout();
m_panelGolbalDesignRules->Layout();
Fit();
// Now all widgets have the size fixed, call FinishDialogSettings
FinishDialogSettings();
}
DIALOG_DESIGN_RULES::~DIALOG_DESIGN_RULES()
{
delete [] m_originalColWidths;
m_grid->Disconnect( wxEVT_GRID_CELL_CHANGING, wxGridEventHandler( DIALOG_DESIGN_RULES::OnNetclassGridCellChanging ), NULL, this );
}
bool DIALOG_DESIGN_RULES::TransferDataToWindow()
{
if( !wxDialog::TransferDataToWindow() )
return false;
m_Pcb = m_Parent->GetBoard();
m_BrdSettings = &m_Pcb->GetDesignSettings();
2009-09-10 15:22:26 +00:00
// Initialize the Rules List
transferNetclassesToWindow();
// Reassure that all nets have net classes assigned
m_Pcb->BuildListOfNets();
2009-09-10 15:22:26 +00:00
// 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
NETCLASSES& netclasses = m_BrdSettings->m_NetClasses;
NETCLASSPTR netclass = netclasses.GetDefault();
2009-09-10 15:22:26 +00:00
// Initialize list of nets for Default Net Class
for( NETCLASS::iterator name = netclass->begin(); name != netclass->end(); ++name )
{
2009-09-10 15:22:26 +00:00
m_AllNets.push_back( NETCUP( *name, netclass->GetName() ) );
}
// Initialize list of nets for others (custom) Net Classes
2009-09-10 15:22:26 +00:00
for( NETCLASSES::const_iterator nc = netclasses.begin(); nc != netclasses.end(); ++nc )
{
2009-09-10 15:22:26 +00:00
netclass = nc->second;
for( NETCLASS::const_iterator name = netclass->begin(); name != netclass->end(); ++name )
{
2009-09-10 15:22:26 +00:00
m_AllNets.push_back( NETCUP( *name, netclass->GetName() ) );
}
}
rebuildNetclassDropdowns();
transferGlobalRulesToWindow();
return true;
2009-09-10 15:22:26 +00:00
}
void DIALOG_DESIGN_RULES::transferGlobalRulesToWindow()
{
m_trackMinWidth.SetValue( m_BrdSettings->m_TrackMinWidth );
m_viaMinDiameter.SetValue(m_BrdSettings->m_ViasMinSize );
m_viaMinDrill.SetValue( m_BrdSettings->m_ViasMinDrill );
m_OptAllowBlindBuriedVias->SetValue( m_BrdSettings->m_BlindBuriedViaAllowed );
m_OptAllowMicroVias->SetValue( m_BrdSettings->m_MicroViasAllowed );
CheckAllowMicroVias();
m_microViaMinDiameter.SetValue( m_BrdSettings->m_MicroViasMinSize );
m_microViaMinDrill.SetValue( m_BrdSettings->m_MicroViasMinDrill );
// Initialize Vias and Tracks sizes lists.
// note we display only extra values, never the current netclass value.
// (the first value in history list)
m_TracksWidthList = m_BrdSettings->m_TrackWidthList;
m_TracksWidthList.erase( m_TracksWidthList.begin() ); // remove the netclass value
m_ViasDimensionsList = m_BrdSettings->m_ViasDimensionsList;
m_ViasDimensionsList.erase( m_ViasDimensionsList.begin() ); // remove the netclass value
InitDimensionsLists();
}
void DIALOG_DESIGN_RULES::InitDimensionsLists()
{
wxString msg;
// Fill cells with actual values:
m_gridViaSizeList->SetCellValue( 0, 0, wxEmptyString );
m_gridViaSizeList->SetCellValue( 0, 1, wxEmptyString );
m_gridTrackWidthList->SetCellValue( 0, 0, wxEmptyString );
for( unsigned ii = 0; ii < m_TracksWidthList.size(); ii++ )
{
msg = StringFromValue( GetUserUnits(), m_TracksWidthList[ii], true, true );
m_gridTrackWidthList->SetCellValue( ii, 0, msg );
}
for( unsigned ii = 0; ii < m_ViasDimensionsList.size(); ii++ )
{
msg = StringFromValue( GetUserUnits(), m_ViasDimensionsList[ii].m_Diameter, true, true );
m_gridViaSizeList->SetCellValue( ii, 0, msg );
if( m_ViasDimensionsList[ii].m_Drill > 0 )
{
msg = StringFromValue( GetUserUnits(), m_ViasDimensionsList[ii].m_Drill, true, true );
m_gridViaSizeList->SetCellValue( ii, 1, msg );
}
}
}
// Sort comparison function (helper for makePointers() )
2009-09-10 15:22:26 +00:00
static bool sortByClassThenName( NETCUP* a, NETCUP* b )
{
// return a < b
if( a->clazz < b->clazz )
return true;
// inside the same class, sort by net name:
if( a->clazz == b->clazz )
{
if( a->net < b->net )
return true;
}
2009-09-10 15:22:26 +00:00
return false;
}
2009-09-10 15:22:26 +00:00
void DIALOG_DESIGN_RULES::makePointers( PNETCUPS* aList, const wxString& aNetClassName )
{
aList->clear();
if( wildCard == aNetClassName )
{
2009-09-10 15:22:26 +00:00
for( NETCUPS::iterator n = m_AllNets.begin(); n != m_AllNets.end(); ++n )
{
aList->push_back( &*n );
}
2009-09-10 15:22:26 +00:00
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 )
{
2009-09-10 15:22:26 +00:00
if( n->clazz == aNetClassName )
aList->push_back( &*n );
}
2009-09-10 15:22:26 +00:00
sort( aList->begin(), aList->end(), sortByClassThenName );
}
2009-09-10 15:22:26 +00:00
}
2009-09-10 15:22:26 +00:00
void DIALOG_DESIGN_RULES::FillListBoxWithNetNames( NETS_LIST_CTRL* aListCtrl,
const wxString& aNetClass )
{
aListCtrl->ClearList();
PNETCUPS ptrList;
2009-09-10 15:22:26 +00:00
// get a subset of m_AllNets in pointer form, sorted as desired.
2009-09-10 15:22:26 +00:00
makePointers( &ptrList, aNetClass );
// Add netclass info to m_Netnames and m_Classnames wxArrayString buffers
// aListCtrl uses wxLC_VIRTUAL option, so this is fast
wxClientDC sDC( aListCtrl );
2009-09-10 15:22:26 +00:00
int row = 0;
// recompute the column widths here, after setting texts
int net_colsize = sDC.GetTextExtent( NET_TITLE ).x;
int class_colsize = sDC.GetTextExtent( CLASS_TITLE ).x;
2009-09-10 15:22:26 +00:00
for( PNETCUPS::iterator i = ptrList.begin(); i!=ptrList.end(); ++i, ++row )
{
wxSize net_needed = sDC.GetTextExtent( (*i)->net );
wxSize class_needed = sDC.GetTextExtent( (*i)->clazz );
net_colsize = std::max( net_colsize, net_needed.x );
class_colsize = std::max( class_colsize, class_needed.x );
aListCtrl->SetRowItems( row, (*i)->net, (*i)->clazz );
2009-09-10 15:22:26 +00:00
}
int margin = sDC.GetTextExtent( wxT( "XX" ) ).x;
aListCtrl->SetColumnWidth( 0, net_colsize + margin );
aListCtrl->SetColumnWidth( 1, class_colsize + margin );
aListCtrl->Refresh();
}
/* Populates drop-downs with the list of net classes
*/
void DIALOG_DESIGN_RULES::rebuildNetclassDropdowns()
{
wxString rightSelected = m_rightClassChoice->GetStringSelection();
wxString leftSelected = m_leftClassChoice->GetStringSelection();
2009-09-10 15:22:26 +00:00
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->GetCellValue( ii, GRID_NAME ) );
m_leftClassChoice->Append( m_grid->GetCellValue( ii, GRID_NAME ) );
}
// Reselect previous choice if still available; otherwise the wildcard
m_rightClassChoice->Select( std::max( 0, m_rightClassChoice->FindString( rightSelected ) ) );
m_leftClassChoice->Select( std::max( 0, m_leftClassChoice->FindString( leftSelected ) ) );
2009-09-10 15:22:26 +00:00
FillListBoxWithNetNames( m_leftListCtrl, m_leftClassChoice->GetStringSelection() );
FillListBoxWithNetNames( m_rightListCtrl, m_rightClassChoice->GetStringSelection() );
}
2009-09-10 15:22:26 +00:00
/* Initialize the rules list from board
*/
2009-09-10 15:22:26 +00:00
static void class2gridRow( EDA_UNITS_T aUnits, wxGrid* grid, int row, const NETCLASSPTR& nc )
{
2009-09-10 15:22:26 +00:00
wxString msg;
grid->SetCellValue( row, GRID_NAME, nc->GetName() );
2009-09-10 15:22:26 +00:00
msg = StringFromValue( aUnits, nc->GetClearance(), true, true );
grid->SetCellValue( row, GRID_CLEARANCE, msg );
msg = StringFromValue( aUnits, nc->GetTrackWidth(), true, true );
grid->SetCellValue( row, GRID_TRACKSIZE, msg );
msg = StringFromValue( aUnits, nc->GetViaDiameter(), true, true );
grid->SetCellValue( row, GRID_VIASIZE, msg );
msg = StringFromValue( aUnits, nc->GetViaDrill(), true, true );
grid->SetCellValue( row, GRID_VIADRILL, msg );
msg = StringFromValue( aUnits, nc->GetuViaDiameter(), true, true );
grid->SetCellValue( row, GRID_uVIASIZE, msg );
msg = StringFromValue( aUnits, nc->GetuViaDrill(), true, true );
grid->SetCellValue( row, GRID_uVIADRILL, msg );
msg = StringFromValue( aUnits, nc->GetDiffPairGap(), true, true );
grid->SetCellValue( row, GRID_DIFF_PAIR_GAP, msg );
msg = StringFromValue( aUnits, nc->GetDiffPairWidth(),true, true );
grid->SetCellValue( row, GRID_DIFF_PAIR_WIDTH, msg );
2009-09-10 15:22:26 +00:00
}
void DIALOG_DESIGN_RULES::transferNetclassesToWindow()
{
NETCLASSES& netclasses = m_BrdSettings->m_NetClasses;
2009-08-17 02:59:38 +00:00
2009-09-10 15:22:26 +00:00
// the +1 is for the Default NETCLASS.
if( netclasses.GetCount() + 1 > (unsigned) m_grid->GetNumberRows() )
m_grid->AppendRows( netclasses.GetCount() + 1 - m_grid->GetNumberRows() );
2009-09-10 15:22:26 +00:00
// enter the Default NETCLASS.
class2gridRow( GetUserUnits(), m_grid, 0, netclasses.GetDefault() );
2009-09-10 15:22:26 +00:00
// make the Default NETCLASS name read-only
wxGridCellAttr* cellAttr = m_grid->GetOrCreateCellAttr( 0, GRID_NAME );
cellAttr->SetReadOnly();
cellAttr->DecRef();
// enter other netclasses
int row = 1;
for( NETCLASSES::iterator i = netclasses.begin(); i != netclasses.end(); ++i, ++row )
class2gridRow( GetUserUnits(), m_grid, row, i->second );
}
static void gridRow2class( EDA_UNITS_T aUnits, wxGrid* grid, int row, const NETCLASSPTR& nc )
2009-09-10 15:22:26 +00:00
{
nc->SetName( grid->GetCellValue( row, GRID_NAME ) );
#define MYCELL( col ) \
ValueFromString( aUnits, grid->GetCellValue( row, col ) )
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 ) );
nc->SetDiffPairGap( MYCELL( GRID_DIFF_PAIR_GAP ) );
nc->SetDiffPairWidth( MYCELL( GRID_DIFF_PAIR_WIDTH ) );
2009-09-10 15:22:26 +00:00
}
void DIALOG_DESIGN_RULES::CopyNetclassesToBoard()
{
// Commit any pending in-place edits and close the editor
m_grid->DisableCellEditControl();
NETCLASSES& netclasses = m_BrdSettings->m_NetClasses;
2009-08-17 02:59:38 +00:00
// Remove all netclasses from board. We'll copy new list after
2009-08-17 02:59:38 +00:00
netclasses.Clear();
// Copy the default NetClass:
gridRow2class( GetUserUnits(), m_grid, 0, netclasses.GetDefault() );
2009-09-10 15:22:26 +00:00
// Copy other NetClasses :
2009-09-10 15:22:26 +00:00
for( int row = 1; row < m_grid->GetNumberRows(); ++row )
{
NETCLASSPTR nc = std::make_shared<NETCLASS>( m_grid->GetCellValue( row, GRID_NAME ) );
if( m_BrdSettings->m_NetClasses.Add( nc ) )
gridRow2class( GetUserUnits(), m_grid, row, nc );
2009-09-10 15:22:26 +00:00
}
// 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 )
2009-09-10 15:22:26 +00:00
{
NETCLASSPTR nc = netclasses.Find( netcup->clazz );
2009-09-10 15:22:26 +00:00
wxASSERT( nc );
nc->Add( netcup->net );
}
2009-08-17 02:59:38 +00:00
m_Pcb->SynchronizeNetsAndNetClasses();
}
void DIALOG_DESIGN_RULES::CopyGlobalRulesToBoard()
{
// Update tracks minimum values for DRC
m_BrdSettings->m_TrackMinWidth = m_trackMinWidth.GetValue();
// Update vias minimum values for DRC
m_BrdSettings->m_ViasMinSize = m_viaMinDiameter.GetValue();
m_BrdSettings->m_ViasMinDrill = m_viaMinDrill.GetValue();
m_BrdSettings->m_BlindBuriedViaAllowed = m_OptAllowBlindBuriedVias->GetValue();
m_BrdSettings->m_MicroViasAllowed = m_OptAllowMicroVias->GetValue();
// Update microvias minimum values for DRC
m_BrdSettings->m_MicroViasMinSize = m_microViaMinDiameter.GetValue();
m_BrdSettings->m_MicroViasMinDrill = m_microViaMinDrill.GetValue();
}
void DIALOG_DESIGN_RULES::CopyDimensionsListsToBoard()
{
wxString msg;
// Commit any pending in-place edits and close editors from grid controls
m_gridTrackWidthList->DisableCellEditControl();
m_gridViaSizeList->DisableCellEditControl();
// 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 = ValueFromString( GetUserUnits(), msg );
m_TracksWidthList.push_back( value );
}
// Sort new list by by increasing value
sort( m_TracksWidthList.begin(), m_TracksWidthList.end() );
// Reinitialize m_ViasDimensionsList
m_ViasDimensionsList.clear();
for( int row = 0; row < m_gridViaSizeList->GetNumberRows(); ++row )
{
msg = m_gridViaSizeList->GetCellValue( row, 0 );
if( msg.IsEmpty() )
continue;
int value = ValueFromString( GetUserUnits(), msg );
VIA_DIMENSION via_dim;
via_dim.m_Diameter = value;
msg = m_gridViaSizeList->GetCellValue( row, 1 );
if( !msg.IsEmpty() )
{
* KIWAY Milestone A): Make major modules into DLL/DSOs. ! The initial testing of this commit should be done using a Debug build so that all the wxASSERT()s are enabled. Also, be sure and keep enabled the USE_KIWAY_DLLs option. The tree won't likely build without it. Turning it off is senseless anyways. If you want stable code, go back to a prior version, the one tagged with "stable". * Relocate all functionality out of the wxApp derivative into more finely targeted purposes: a) DLL/DSO specific b) PROJECT specific c) EXE or process specific d) configuration file specific data e) configuration file manipulations functions. All of this functionality was blended into an extremely large wxApp derivative and that was incompatible with the desire to support multiple concurrently loaded DLL/DSO's ("KIFACE")s and multiple concurrently open projects. An amazing amount of organization come from simply sorting each bit of functionality into the proper box. * Switch to wxConfigBase from wxConfig everywhere except instantiation. * Add classes KIWAY, KIFACE, KIFACE_I, SEARCH_STACK, PGM_BASE, PGM_KICAD, PGM_SINGLE_TOP, * Remove "Return" prefix on many function names. * Remove obvious comments from CMakeLists.txt files, and from else() and endif()s. * Fix building boost for use in a DSO on linux. * Remove some of the assumptions in the CMakeLists.txt files that windows had to be the host platform when building windows binaries. * Reduce the number of wxStrings being constructed at program load time via static construction. * Pass wxConfigBase* to all SaveSettings() and LoadSettings() functions so that these functions are useful even when the wxConfigBase comes from another source, as is the case in the KICAD_MANAGER_FRAME. * Move the setting of the KIPRJMOD environment variable into class PROJECT, so that it can be moved into a project variable soon, and out of FP_LIB_TABLE. * Add the KIWAY_PLAYER which is associated with a particular PROJECT, and all its child wxFrames and wxDialogs now have a Kiway() member function which returns a KIWAY& that that window tree branch is in support of. This is like wxWindows DNA in that child windows get this member with proper value at time of construction. * Anticipate some of the needs for milestones B) and C) and make code adjustments now in an effort to reduce work in those milestones. * No testing has been done for python scripting, since milestone C) has that being largely reworked and re-thought-out.
2014-03-20 00:42:08 +00:00
value = ValueFromString( g_UserUnit, msg );
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_BrdSettings->m_TrackWidthList;
// Remove old "custom" sizes
tlist->erase( tlist->begin() + 1, tlist->end() );
// Add new "custom" sizes
tlist->insert( tlist->end(), m_TracksWidthList.begin(), m_TracksWidthList.end() );
// Reinitialize m_ViaSizeList
std::vector<VIA_DIMENSION>* vialist = &m_BrdSettings->m_ViasDimensionsList;
vialist->erase( vialist->begin() + 1, vialist->end() );
vialist->insert( vialist->end(), m_ViasDimensionsList.begin(), m_ViasDimensionsList.end() );
}
void DIALOG_DESIGN_RULES::OnNotebookPageChanged( wxNotebookEvent& event )
{
s_LastTabSelection = event.GetSelection();
// Skip() allows OSX to properly refresh controls.
event.Skip();
}
bool DIALOG_DESIGN_RULES::TransferDataFromWindow()
{
if( !wxDialog::TransferDataFromWindow() )
return false;
if( !validateData() )
return false;
CopyNetclassesToBoard();
CopyGlobalRulesToBoard();
CopyDimensionsListsToBoard();
m_BrdSettings->SetCurrentNetClass( NETCLASS::Default );
//this event causes the routing tool to reload its design rules information
TOOL_MANAGER* toolManager = m_Parent->GetToolManager();
TOOL_EVENT event( TC_COMMAND, TA_MODEL_CHANGE, AS_ACTIVE );
toolManager->ProcessEvent( event );
return true;
}
bool DIALOG_DESIGN_RULES::validateNetclassName( int aRow, wxString aName, bool focusFirst )
{
aName.Trim( true );
aName.Trim( false );
if( aName.IsEmpty() )
{
setGridError( m_grid, _( "Netclass name cannot be empty." ), aRow, GRID_NAME );
return false;
}
2009-09-10 15:22:26 +00:00
for( int ii = 0; ii < m_grid->GetNumberRows(); ii++ )
{
if( ii != aRow && m_grid->GetRowLabelValue( ii ).CmpNoCase( aName ) == 0 )
{
if( focusFirst )
setGridError( m_grid, _( "Netclass name already in use." ), aRow, GRID_NAME );
else
setGridError( m_grid, _( "Netclass name already in use." ), ii, GRID_NAME );
return false;
}
}
return true;
}
void DIALOG_DESIGN_RULES::OnNetclassGridCellChanging( wxGridEvent& event )
{
if( event.GetCol() == GRID_NAME )
{
if( validateNetclassName( event.GetRow(), event.GetString() ) )
m_netclassesDirty = true;
else
event.Veto();
}
}
void DIALOG_DESIGN_RULES::OnAddNetclassClick( wxCommandEvent& event )
{
2009-09-10 15:22:26 +00:00
m_grid->AppendRows();
// Copy values of the default class:
2009-09-10 15:22:26 +00:00
int irow = m_grid->GetNumberRows() - 1;
for( int icol = 1; icol < m_grid->GetNumberCols(); icol++ )
{
wxString value;
value = m_grid->GetCellValue( 0, icol );
2009-09-10 15:22:26 +00:00
m_grid->SetCellValue( irow, icol, value );
}
rebuildNetclassDropdowns();
}
void DIALOG_DESIGN_RULES::OnRemoveNetclassClick( wxCommandEvent& event )
{
int curRow = m_grid->GetGridCursorRow();
if( curRow == 0 )
{
DisplayErrorMessage( this, _( "The default net class is required." ) );
return;
}
// reset the net class to default for members of the removed class
wxString classname = m_grid->GetCellValue( curRow, GRID_NAME );
swapNetClass( classname, NETCLASS::Default );
m_grid->DeleteRows( curRow, 1 );
rebuildNetclassDropdowns();
}
void DIALOG_DESIGN_RULES::AdjustNetclassGridColumns( int aWidth )
{
int fixedColsWidth = 0;
for( int i = 1; i < m_grid->GetNumberCols(); i++ )
{
m_grid->SetColSize( i, m_originalColWidths[ i ] );
fixedColsWidth += m_originalColWidths[ i ];
}
m_grid->SetColSize( 0, aWidth - fixedColsWidth - 4 );
}
void DIALOG_DESIGN_RULES::OnSizeNetclassGrid( wxSizeEvent& event )
{
AdjustNetclassGridColumns( event.GetSize().GetX() );
event.Skip();
}
void DIALOG_DESIGN_RULES::setGridError( wxGrid* aGrid, const wxString& aMsg, int aRow, int aCol )
{
m_gridErrorGrid = aGrid;
m_gridErrorMsg = aMsg;
m_gridErrorRow = aRow;
m_gridErrorCol = aCol;
if( m_gridErrorGrid->GetParent() != m_DRnotebook->GetCurrentPage() )
m_DRnotebook->AdvanceSelection();
}
void DIALOG_DESIGN_RULES::OnUpdateUI( wxUpdateUIEvent& event )
{
if( m_netclassesDirty )
{
rebuildNetclassDropdowns();
m_netclassesDirty = false;
}
// Handle a grid error. This is delayed to OnUpdateUI so that we can change focus
// even when the original validation was triggered from a killFocus event, and so
// that the corresponding notebook page can be shown in the background when triggered
// from an OK.
if( m_gridErrorGrid )
{
// We will re-enter this routine when the error dialog is displayed, so make
// sure we don't keep putting up more dialogs.
wxGrid* grid = m_gridErrorGrid;
m_gridErrorGrid = nullptr;
DisplayErrorMessage( this, m_gridErrorMsg );
grid->GoToCell( m_gridErrorRow, m_gridErrorCol );
grid->SetFocus();
}
}
void DIALOG_DESIGN_RULES::CheckAllowMicroVias()
{
bool enabled = m_OptAllowMicroVias->GetValue();
m_microViaMinDiameter.Enable( enabled );
m_microViaMinDrill.Enable( enabled );
}
/**
* Function OnAllowMicroVias
* is called whenever the AllowMicroVias checkbox is toggled
*/
void DIALOG_DESIGN_RULES::OnAllowMicroVias( wxCommandEvent& event )
{
CheckAllowMicroVias();
}
void DIALOG_DESIGN_RULES::OnMoveUpSelectedNetClass( wxCommandEvent& event )
{
// Commit any pending in-place edits and close the editor
m_grid->DisableCellEditControl();
int curRow = m_grid->GetGridCursorRow();
if( curRow < 2 )
{
wxBell();
return;
}
// Swap the rule and the previous rule
for( int icol = 0; icol < m_grid->GetNumberCols(); icol++ )
{
wxString curr_value = m_grid->GetCellValue( curRow, icol );
wxString previous_value = m_grid->GetCellValue( curRow - 1, icol );
m_grid->SetCellValue( curRow, icol, previous_value );
m_grid->SetCellValue( curRow - 1, icol, curr_value );
}
m_grid->SetGridCursor( curRow - 1, m_grid->GetGridCursorCol() );
m_grid->MakeCellVisible( m_grid->GetGridCursorRow(), m_grid->GetGridCursorCol() );
m_netclassesDirty = true;
}
void DIALOG_DESIGN_RULES::OnMoveDownSelectedNetClass( wxCommandEvent& event )
{
// Commit any pending in-place edits and close the editor
m_grid->DisableCellEditControl();
int curRow = m_grid->GetGridCursorRow();
if( curRow == 0 || curRow == m_grid->GetNumberRows() - 1 )
{
wxBell();
return;
}
// Swap the rule and the next rule
for( int icol = 0; icol < m_grid->GetNumberCols(); icol++ )
{
wxString curr_value = m_grid->GetCellValue( curRow, icol );
wxString next_value = m_grid->GetCellValue( curRow + 1, icol );
m_grid->SetCellValue( curRow, icol, next_value );
m_grid->SetCellValue( curRow + 1, icol, curr_value );
}
m_grid->SetGridCursor( curRow + 1, m_grid->GetGridCursorCol() );
m_grid->MakeCellVisible( m_grid->GetGridCursorRow(), m_grid->GetGridCursorCol() );
m_netclassesDirty = true;
}
void DIALOG_DESIGN_RULES::OnLeftCBSelection( wxCommandEvent& event )
{
2009-09-10 15:22:26 +00:00
FillListBoxWithNetNames( m_leftListCtrl, m_leftClassChoice->GetStringSelection() );
2009-09-10 15:22:26 +00:00
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::OnRightCBSelection( wxCommandEvent& event )
{
2009-09-10 15:22:26 +00:00
FillListBoxWithNetNames( m_rightListCtrl, m_rightClassChoice->GetStringSelection() );
2009-09-10 15:22:26 +00:00
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( NETS_LIST_CTRL* src, const wxString& newClassName )
{
wxListItem item;
wxString netName;
item.m_mask |= wxLIST_MASK_TEXT; // Validate the member m_text of the wxListItem item
2009-09-10 15:22:26 +00:00
2009-09-10 17:28:38 +00:00
for( int row = 0; row < src->GetItemCount(); ++row )
{
2009-09-10 17:28:38 +00:00
if( !src->GetItemState( row, wxLIST_STATE_SELECTED ) )
continue;
2009-09-10 17:28:38 +00:00
item.SetColumn( 0 );
item.SetId( row );
src->GetItem( item );
netName = item.GetText();
2009-09-10 15:22:26 +00:00
setNetClass( netName, newClassName == wildCard ? NETCLASS::Default : newClassName );
}
2009-09-10 17:28:38 +00:00
}
void DIALOG_DESIGN_RULES::OnRightToLeftCopyButton( wxCommandEvent& event )
{
wxString newClassName = m_leftClassChoice->GetStringSelection();
moveSelectedItems( m_rightListCtrl, newClassName );
2009-09-10 15:22:26 +00:00
FillListBoxWithNetNames( m_leftListCtrl, m_leftClassChoice->GetStringSelection() );
FillListBoxWithNetNames( m_rightListCtrl, m_rightClassChoice->GetStringSelection() );
}
void DIALOG_DESIGN_RULES::OnLeftToRightCopyButton( wxCommandEvent& event )
{
2009-09-10 17:28:38 +00:00
wxString newClassName = m_rightClassChoice->GetStringSelection();
moveSelectedItems( m_leftListCtrl, newClassName );
2009-09-10 15:22:26 +00:00
FillListBoxWithNetNames( m_leftListCtrl, m_leftClassChoice->GetStringSelection() );
FillListBoxWithNetNames( m_rightListCtrl, m_rightClassChoice->GetStringSelection() );
}
void DIALOG_DESIGN_RULES::OnLeftSelectAllButton( wxCommandEvent& event )
{
2009-09-10 15:22:26 +00:00
for( int ii = 0; ii < m_leftListCtrl->GetItemCount(); ii++ )
m_leftListCtrl->SetItemState( ii, wxLIST_STATE_SELECTED, wxLIST_STATE_SELECTED );
}
void DIALOG_DESIGN_RULES::OnRightSelectAllButton( wxCommandEvent& event )
{
2009-09-10 15:22:26 +00:00
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;
}
}
}
bool DIALOG_DESIGN_RULES::validateData()
{
wxString msg;
* KIWAY Milestone A): Make major modules into DLL/DSOs. ! The initial testing of this commit should be done using a Debug build so that all the wxASSERT()s are enabled. Also, be sure and keep enabled the USE_KIWAY_DLLs option. The tree won't likely build without it. Turning it off is senseless anyways. If you want stable code, go back to a prior version, the one tagged with "stable". * Relocate all functionality out of the wxApp derivative into more finely targeted purposes: a) DLL/DSO specific b) PROJECT specific c) EXE or process specific d) configuration file specific data e) configuration file manipulations functions. All of this functionality was blended into an extremely large wxApp derivative and that was incompatible with the desire to support multiple concurrently loaded DLL/DSO's ("KIFACE")s and multiple concurrently open projects. An amazing amount of organization come from simply sorting each bit of functionality into the proper box. * Switch to wxConfigBase from wxConfig everywhere except instantiation. * Add classes KIWAY, KIFACE, KIFACE_I, SEARCH_STACK, PGM_BASE, PGM_KICAD, PGM_SINGLE_TOP, * Remove "Return" prefix on many function names. * Remove obvious comments from CMakeLists.txt files, and from else() and endif()s. * Fix building boost for use in a DSO on linux. * Remove some of the assumptions in the CMakeLists.txt files that windows had to be the host platform when building windows binaries. * Reduce the number of wxStrings being constructed at program load time via static construction. * Pass wxConfigBase* to all SaveSettings() and LoadSettings() functions so that these functions are useful even when the wxConfigBase comes from another source, as is the case in the KICAD_MANAGER_FRAME. * Move the setting of the KIPRJMOD environment variable into class PROJECT, so that it can be moved into a project variable soon, and out of FP_LIB_TABLE. * Add the KIWAY_PLAYER which is associated with a particular PROJECT, and all its child wxFrames and wxDialogs now have a Kiway() member function which returns a KIWAY& that that window tree branch is in support of. This is like wxWindows DNA in that child windows get this member with proper value at time of construction. * Anticipate some of the needs for milestones B) and C) and make code adjustments now in an effort to reduce work in those milestones. * No testing has been done for python scripting, since milestone C) has that being largely reworked and re-thought-out.
2014-03-20 00:42:08 +00:00
int minViaDia = ValueFromTextCtrl( *m_SetViasMinSizeCtrl );
int minViaDrill = ValueFromTextCtrl( *m_SetViasMinDrillCtrl );
int minUViaDia = ValueFromTextCtrl( *m_SetMicroViasMinSizeCtrl );
int minUViaDrill = ValueFromTextCtrl( *m_SetMicroViasMinDrillCtrl );
int minTrackWidth = ValueFromTextCtrl( *m_SetTrackMinWidthCtrl );
// Test net class parameters.
2009-09-10 15:22:26 +00:00
for( int row = 0; row < m_grid->GetNumberRows(); row++ )
{
wxString netclassName = m_grid->GetCellValue( row, GRID_NAME );
netclassName.Trim( true );
netclassName.Trim( false );
if( !validateNetclassName( row, netclassName, false ) )
return false;
if( ValueFromString( GetUserUnits(), m_grid->GetCellValue( row, GRID_TRACKSIZE ) )
< minTrackWidth )
{
msg.Printf( _( "Track width less than minimum track width (%s)." ),
StringFromValue( GetUserUnits(), minTrackWidth, true, true ) );
setGridError( m_grid, msg, row, GRID_TRACKSIZE );
return false;
}
if( ValueFromString( GetUserUnits(), m_grid->GetCellValue( row, GRID_DIFF_PAIR_WIDTH ) )
< minTrackWidth )
{
msg.Printf( _( "Differential pair width less than minimum track width (%s)." ),
StringFromValue( GetUserUnits(), minTrackWidth, true, true ) );
setGridError( m_grid, msg, row, GRID_DIFF_PAIR_WIDTH );
return false;
}
// Test vias
if( ValueFromString( GetUserUnits(), m_grid->GetCellValue( row, GRID_VIASIZE ) )
< minViaDia )
{
msg.Printf( _( "Via diameter less than minimum via diameter (%s)." ),
StringFromValue( GetUserUnits(), minViaDia, true, true ) );
setGridError( m_grid, msg, row, GRID_VIASIZE );
return false;
}
if( ValueFromString( GetUserUnits(), m_grid->GetCellValue( row, GRID_VIADRILL ) )
>= ValueFromString( GetUserUnits(), m_grid->GetCellValue( row, GRID_VIASIZE ) ) )
{
msg = _( "Via drill larger than via diameter." );
setGridError( m_grid, msg, row, GRID_VIADRILL );
return false;
}
if( ValueFromString( GetUserUnits(), m_grid->GetCellValue( row, GRID_VIADRILL ) )
< minViaDrill )
{
msg.Printf( _( "Via drill less than minimum via drill (%s)." ),
StringFromValue( GetUserUnits(), minViaDrill, true, true ) );
setGridError( m_grid, msg, row, GRID_VIADRILL );
return false;
}
// Test Micro vias
if( ValueFromString( GetUserUnits(), m_grid->GetCellValue( row, GRID_uVIASIZE ) )
< minUViaDia )
{
msg.Printf( _( "Microvia diameter less than minimum microvia diameter (%s)." ),
StringFromValue( GetUserUnits(), minUViaDia, true, true ) );
setGridError( m_grid, msg, row, GRID_uVIASIZE );
return false;
}
if( ValueFromString( GetUserUnits(), m_grid->GetCellValue( row, GRID_uVIADRILL ) )
>= ValueFromString( GetUserUnits(), m_grid->GetCellValue( row, GRID_uVIASIZE ) ) )
{
msg = _( "Microvia drill larger than microvia diameter." );
setGridError( m_grid, msg, row, GRID_uVIADRILL );
return false;
}
if( ValueFromString( GetUserUnits(), m_grid->GetCellValue( row, GRID_uVIADRILL ) )
< minUViaDrill )
{
msg.Printf( _( "Microvia drill less than minimum microvia drill (%s)." ),
StringFromValue( GetUserUnits(), minUViaDrill, true, true ) );
setGridError( m_grid, msg, row, GRID_uVIADRILL );
return false;
}
}
// Test custom tracks
for( int row = 0; row < m_gridTrackWidthList->GetNumberRows(); ++row )
{
wxString tvalue = m_gridTrackWidthList->GetCellValue( row, 0 );
if( tvalue.IsEmpty() )
continue;
if( ValueFromString( GetUserUnits(), tvalue ) < minTrackWidth )
{
msg.Printf( _( "Track width less than minimum track width (%s)." ),
StringFromValue( GetUserUnits(), minTrackWidth, true, true ) );
setGridError( m_gridTrackWidthList, msg, row, 0 );
return false;
}
}
// Test custom vias
for( int row = 0; row < m_gridViaSizeList->GetNumberRows(); ++row )
{
wxString viaDia = m_gridViaSizeList->GetCellValue( row, 0 );
if( viaDia.IsEmpty() )
continue;
if( ValueFromString( GetUserUnits(), viaDia ) < minViaDia )
{
msg.Printf( _( "Via diameter less than minimum via diameter (%s)." ),
StringFromValue( GetUserUnits(), minViaDia, true, true ) );
setGridError( m_gridViaSizeList, msg, row, 0 );
return false;
}
wxString viaDrill = m_gridViaSizeList->GetCellValue( row, 1 );
if( viaDrill.IsEmpty() )
{
msg = _( "No via drill defined." );
setGridError( m_gridViaSizeList, msg, row, 1 );
return false;
}
if( ValueFromString( GetUserUnits(), viaDrill ) < minViaDrill )
{
msg.Printf( _( "Via drill less than minimum via drill (%s)." ),
StringFromValue( GetUserUnits(), minViaDrill, true, true ) );
setGridError( m_gridViaSizeList, msg, row, 1 );
return false;
}
if( ValueFromString( GetUserUnits(), viaDrill )
>= ValueFromString( GetUserUnits(), viaDia ) )
{
msg = _( "Via drill larger than via diameter." );
setGridError( m_gridViaSizeList, msg, row, 1 );
return false;
}
}
return true;
}