You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

635 lines
20 KiB

9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
  1. /*
  2. * This program source code file is part of KiCad, a free EDA CAD application.
  3. *
  4. * Copyright (C) 2015 CERN
  5. * @author Maciej Suminski <maciej.suminski@cern.ch>
  6. *
  7. * This program is free software; you can redistribute it and/or
  8. * modify it under the terms of the GNU General Public License
  9. * as published by the Free Software Foundation; either version 2
  10. * of the License, or (at your option) any later version.
  11. *
  12. * This program is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. * GNU General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU General Public License
  18. * along with this program; if not, you may find one here:
  19. * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
  20. * or you may search the http://www.gnu.org website for the version 2 license,
  21. * or you may write to the Free Software Foundation, Inc.,
  22. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
  23. */
  24. #include <dialogs/dialog_track_via_properties.h>
  25. #include <class_pcb_layer_box_selector.h>
  26. #include <tools/selection_tool.h>
  27. #include <class_track.h>
  28. #include <pcb_edit_frame.h>
  29. #include <confirm.h>
  30. #include <widgets/text_ctrl_eval.h>
  31. #include <widgets/widget_net_selector.h>
  32. #include <board_commit.h>
  33. DIALOG_TRACK_VIA_PROPERTIES::DIALOG_TRACK_VIA_PROPERTIES( PCB_BASE_FRAME* aParent, const SELECTION& aItems ) :
  34. DIALOG_TRACK_VIA_PROPERTIES_BASE( aParent ), m_items( aItems ),
  35. m_trackStartX( aParent, m_TrackStartXCtrl, m_TrackStartXUnit ),
  36. m_trackStartY( aParent, m_TrackStartYCtrl, m_TrackStartYUnit ),
  37. m_trackEndX( aParent, m_TrackEndXCtrl, m_TrackEndXUnit ),
  38. m_trackEndY( aParent, m_TrackEndYCtrl, m_TrackEndYUnit ),
  39. m_trackWidth( aParent, m_TrackWidthCtrl, m_TrackWidthUnit ),
  40. m_viaX( aParent, m_ViaXCtrl, m_ViaXUnit ), m_viaY( aParent, m_ViaYCtrl, m_ViaYUnit ),
  41. m_viaDiameter( aParent, m_ViaDiameterCtrl, m_ViaDiameterUnit ),
  42. m_viaDrill( aParent, m_ViaDrillCtrl, m_ViaDrillUnit ),
  43. m_tracks( false ), m_vias( false )
  44. {
  45. wxASSERT( !m_items.Empty() );
  46. // This is a way to trick gcc into considering these variables as initialized
  47. OPT<int> trackStartX( []()->OPT<int> { return NULLOPT; }() );
  48. OPT<int> trackStartY( []()->OPT<int> { return NULLOPT; }() );
  49. OPT<int> trackEndX( []()->OPT<int> { return NULLOPT; }() );
  50. OPT<int> trackEndY( []()->OPT<int> { return NULLOPT; }() );
  51. OPT<int> trackWidth( []()->OPT<int> { return NULLOPT; }() );
  52. OPT<PCB_LAYER_ID> trackLayer( []()->OPT<PCB_LAYER_ID> { return NULLOPT; }() );
  53. OPT<int> viaX( []()->OPT<int> { return NULLOPT; }() );
  54. OPT<int> viaY( []()->OPT<int> { return NULLOPT; }() );
  55. OPT<int> viaDiameter( []()->OPT<int> { return NULLOPT; }() );
  56. OPT<int> viaDrill( []()->OPT<int> { return NULLOPT; }() );
  57. VIATYPE_T viaType = VIA_NOT_DEFINED;
  58. PCB_LAYER_ID viaStartLayer = UNDEFINED_LAYER;
  59. PCB_LAYER_ID viaEndLayer = UNDEFINED_LAYER;
  60. m_haveUniqueNet = true;
  61. int prevNet = -1;
  62. m_NetComboBox->SetBoard( aParent->GetBoard() );
  63. m_NetComboBox->Enable( true );
  64. bool hasLocked = false;
  65. bool hasUnlocked = false;
  66. for( auto& item : m_items )
  67. {
  68. int net = static_cast<BOARD_CONNECTED_ITEM*>(item)->GetNetCode();
  69. if( prevNet >= 0 && net != prevNet )
  70. {
  71. printf("prev %d net %d\n", net, prevNet );
  72. m_haveUniqueNet = false;
  73. break;
  74. }
  75. prevNet = net;
  76. }
  77. if ( m_haveUniqueNet )
  78. {
  79. m_NetComboBox->SetSelectedNet( prevNet );
  80. }
  81. else
  82. {
  83. m_NetComboBox->SetMultiple( true );
  84. }
  85. // Look for values that are common for every item that is selected
  86. for( auto& item : m_items )
  87. {
  88. switch( item->Type() )
  89. {
  90. case PCB_TRACE_T:
  91. {
  92. const TRACK* t = static_cast<const TRACK*>( item );
  93. if( !m_tracks ) // first track in the list
  94. {
  95. trackStartX = t->GetStart().x;
  96. trackStartY = t->GetStart().y;
  97. trackEndX = t->GetEnd().x;
  98. trackEndY = t->GetEnd().y;
  99. trackWidth = t->GetWidth();
  100. trackLayer = t->GetLayer();
  101. m_tracks = true;
  102. }
  103. else // check if values are the same for every selected track
  104. {
  105. if( trackStartX && ( *trackStartX != t->GetStart().x ) )
  106. trackStartX = NULLOPT;
  107. if( trackStartY && ( *trackStartY != t->GetStart().y ) )
  108. trackStartY = NULLOPT;
  109. if( trackEndX && ( *trackEndX != t->GetEnd().x ) )
  110. trackEndX = NULLOPT;
  111. if( trackEndY && ( *trackEndY != t->GetEnd().y ) )
  112. trackEndY = NULLOPT;
  113. if( trackWidth && ( *trackWidth != t->GetWidth() ) )
  114. trackWidth = NULLOPT;
  115. if( trackLayer && ( *trackLayer != t->GetLayer() ) )
  116. trackLayer = NULLOPT;
  117. }
  118. if( t->IsLocked() )
  119. hasLocked = true;
  120. else
  121. hasUnlocked = true;
  122. break;
  123. }
  124. case PCB_VIA_T:
  125. {
  126. const VIA* v = static_cast<const VIA*>( item );
  127. if( !m_vias ) // first via in the list
  128. {
  129. viaX = v->GetPosition().x;
  130. viaY = v->GetPosition().y;
  131. viaDiameter = v->GetWidth();
  132. viaDrill = v->GetDrillValue();
  133. m_vias = true;
  134. viaType = v->GetViaType();
  135. viaStartLayer = v->TopLayer();
  136. viaEndLayer = v->BottomLayer();
  137. }
  138. else // check if values are the same for every selected via
  139. {
  140. if( viaX && ( *viaX != v->GetPosition().x ) )
  141. viaX = NULLOPT;
  142. if( viaY && ( *viaY != v->GetPosition().y ) )
  143. viaY = NULLOPT;
  144. if( viaDiameter && ( *viaDiameter != v->GetWidth() ) )
  145. viaDiameter = NULLOPT;
  146. if( viaDrill && ( *viaDrill != v->GetDrillValue() ) )
  147. viaDrill = NULLOPT;
  148. if( viaType != v->GetViaType() )
  149. viaType = VIA_NOT_DEFINED;
  150. if( viaStartLayer != v->TopLayer() )
  151. viaStartLayer = UNDEFINED_LAYER;
  152. if( viaEndLayer != v->BottomLayer() )
  153. viaEndLayer = UNDEFINED_LAYER;
  154. }
  155. if( v->IsLocked() )
  156. hasLocked = true;
  157. else
  158. hasUnlocked = true;
  159. break;
  160. }
  161. default:
  162. {
  163. wxASSERT( false );
  164. break;
  165. }
  166. }
  167. }
  168. wxASSERT( m_tracks || m_vias );
  169. if( m_vias )
  170. {
  171. setCommonVal( viaX, m_ViaXCtrl, m_viaX );
  172. setCommonVal( viaY, m_ViaYCtrl, m_viaY );
  173. setCommonVal( viaDiameter, m_ViaDiameterCtrl, m_viaDiameter );
  174. setCommonVal( viaDrill, m_ViaDrillCtrl, m_viaDrill );
  175. m_DesignRuleViasUnit->SetLabel( GetAbbreviatedUnitsLabel( g_UserUnit ) );
  176. int viaSelection = wxNOT_FOUND;
  177. for( unsigned ii = 0; ii < aParent->GetDesignSettings().m_ViasDimensionsList.size(); ii++ )
  178. {
  179. VIA_DIMENSION* viaDimension = &aParent->GetDesignSettings().m_ViasDimensionsList[ii];
  180. wxString msg = StringFromValue( g_UserUnit, viaDimension->m_Diameter, false )
  181. + " / " + StringFromValue( g_UserUnit, viaDimension->m_Drill, false );
  182. m_DesignRuleViasCtrl->Append( msg, viaDimension );
  183. if( viaSelection == wxNOT_FOUND && viaDiameter == viaDimension->m_Diameter
  184. && viaDrill == viaDimension->m_Drill )
  185. {
  186. viaSelection = ii;
  187. }
  188. }
  189. m_DesignRuleViasCtrl->SetSelection( viaSelection );
  190. m_DesignRuleViasCtrl->Connect( wxEVT_CHOICE, wxCommandEventHandler( DIALOG_TRACK_VIA_PROPERTIES::onViaSelect ), NULL, this );
  191. m_ViaDiameterCtrl->Connect( wxEVT_TEXT, wxCommandEventHandler( DIALOG_TRACK_VIA_PROPERTIES::onViaEdit ), NULL, this );
  192. m_ViaDrillCtrl->Connect( wxEVT_TEXT, wxCommandEventHandler( DIALOG_TRACK_VIA_PROPERTIES::onViaEdit ), NULL, this );
  193. m_ViaTypeChoice->Connect( wxEVT_CHOICE, wxCommandEventHandler( DIALOG_TRACK_VIA_PROPERTIES::onViaEdit ), NULL, this );
  194. m_ViaDiameterCtrl->SetFocus();
  195. m_ViaTypeChoice->Enable();
  196. if( viaType == VIA_THROUGH )
  197. m_ViaTypeChoice->SetSelection( 0 );
  198. else if( viaType == VIA_MICROVIA )
  199. m_ViaTypeChoice->SetSelection( 1 );
  200. else if ( viaType == VIA_BLIND_BURIED )
  201. m_ViaTypeChoice->SetSelection( 2 );
  202. else if( viaType == VIA_NOT_DEFINED )
  203. m_ViaTypeChoice->SetSelection( 3 );
  204. m_ViaStartLayer->SetLayersHotkeys( false );
  205. m_ViaStartLayer->SetLayerSet( LSET::AllNonCuMask() );
  206. m_ViaStartLayer->SetBoardFrame( aParent );
  207. m_ViaStartLayer->Resync();
  208. m_ViaEndLayer->SetLayersHotkeys( false );
  209. m_ViaEndLayer->SetLayerSet( LSET::AllNonCuMask() );
  210. m_ViaEndLayer->SetBoardFrame( aParent );
  211. m_ViaEndLayer->Resync();
  212. m_ViaStartLayer->SetLayerSelection( viaStartLayer );
  213. m_ViaEndLayer->SetLayerSelection( viaEndLayer );
  214. m_ViaStartLayer->Enable( false );
  215. m_ViaEndLayer->Enable( false );
  216. if( viaType != VIA_THROUGH ) // check if selected type isnt through.
  217. {
  218. m_ViaStartLayer->Enable();
  219. m_ViaEndLayer->Enable();
  220. }
  221. }
  222. else
  223. {
  224. m_MainSizer->Hide( m_sbViaSizer, true );
  225. }
  226. if( m_tracks )
  227. {
  228. setCommonVal( trackStartX, m_TrackStartXCtrl, m_trackStartX );
  229. setCommonVal( trackStartY, m_TrackStartYCtrl, m_trackStartY );
  230. setCommonVal( trackEndX, m_TrackEndXCtrl, m_trackEndX );
  231. setCommonVal( trackEndY, m_TrackEndYCtrl, m_trackEndY );
  232. setCommonVal( trackWidth, m_TrackWidthCtrl, m_trackWidth );
  233. for( unsigned ii = 0; ii < aParent->GetDesignSettings().m_TrackWidthList.size(); ii++ )
  234. {
  235. int width = aParent->GetDesignSettings().m_TrackWidthList[ii];
  236. wxString msg = StringFromValue( g_UserUnit, width, false );
  237. m_TrackWidthCtrl->Append( msg );
  238. }
  239. m_TrackLayerCtrl->SetLayersHotkeys( false );
  240. m_TrackLayerCtrl->SetLayerSet( LSET::AllNonCuMask() );
  241. m_TrackLayerCtrl->SetBoardFrame( aParent );
  242. m_TrackLayerCtrl->Resync();
  243. if( trackLayer )
  244. m_TrackLayerCtrl->SetLayerSelection( *trackLayer );
  245. m_TrackWidthCtrl->SetFocus();
  246. }
  247. else
  248. {
  249. m_MainSizer->Hide( m_sbTrackSizer, true );
  250. }
  251. if( hasLocked && hasUnlocked )
  252. {
  253. m_lockedCbox->Set3StateValue( wxCHK_UNDETERMINED );
  254. }
  255. else if( hasLocked )
  256. {
  257. m_lockedCbox->Set3StateValue( wxCHK_CHECKED );
  258. }
  259. else
  260. {
  261. m_lockedCbox->Set3StateValue( wxCHK_UNCHECKED );
  262. }
  263. m_StdButtonsOK->SetDefault();
  264. // Pressing ENTER when any of the text input fields is active applies changes
  265. Connect( wxEVT_TEXT_ENTER, wxCommandEventHandler( DIALOG_TRACK_VIA_PROPERTIES::onOkClick ),
  266. NULL, this );
  267. }
  268. bool DIALOG_TRACK_VIA_PROPERTIES::Apply( COMMIT& aCommit )
  269. {
  270. if( !check() )
  271. return false;
  272. bool changeLock = m_lockedCbox->Get3StateValue() != wxCHK_UNDETERMINED;
  273. bool setLock = m_lockedCbox->Get3StateValue() == wxCHK_CHECKED;
  274. for( auto item : m_items )
  275. {
  276. aCommit.Modify( item );
  277. switch( item->Type() )
  278. {
  279. case PCB_TRACE_T:
  280. {
  281. wxASSERT( m_tracks );
  282. TRACK* t = static_cast<TRACK*>( item );
  283. if( m_trackStartX.Valid() || m_trackStartY.Valid() )
  284. {
  285. wxPoint start = t->GetStart();
  286. if( m_trackStartX.Valid() )
  287. start.x = m_trackStartX.GetValue();
  288. if( m_trackStartY.Valid() )
  289. start.y = m_trackStartY.GetValue();
  290. t->SetStart( start );
  291. }
  292. if( m_trackEndX.Valid() || m_trackEndY.Valid() )
  293. {
  294. wxPoint end = t->GetEnd();
  295. if( m_trackEndX.Valid() )
  296. end.x = m_trackEndX.GetValue();
  297. if( m_trackEndY.Valid() )
  298. end.y = m_trackEndY.GetValue();
  299. t->SetEnd( end );
  300. }
  301. if( m_trackNetclass->IsChecked() )
  302. {
  303. t->SetWidth( t->GetNetClass()->GetTrackWidth() );
  304. }
  305. else if( m_trackWidth.Valid() )
  306. {
  307. t->SetWidth( m_trackWidth.GetValue() );
  308. }
  309. LAYER_NUM layer = m_TrackLayerCtrl->GetLayerSelection();
  310. if( layer != UNDEFINED_LAYER )
  311. t->SetLayer( (PCB_LAYER_ID) layer );
  312. if( changeLock )
  313. t->SetLocked( setLock );
  314. if ( m_NetComboBox->IsUniqueNetSelected() )
  315. {
  316. printf("snc %d\n", m_NetComboBox->GetSelectedNet());
  317. t->SetNetCode( m_NetComboBox->GetSelectedNet() );
  318. }
  319. break;
  320. }
  321. case PCB_VIA_T:
  322. {
  323. wxASSERT( m_vias );
  324. VIA* v = static_cast<VIA*>( item );
  325. if( m_viaX.Valid() || m_viaY.Valid() )
  326. {
  327. wxPoint pos = v->GetPosition();
  328. if( m_viaX.Valid() )
  329. pos.x = m_viaX.GetValue();
  330. if( m_viaY.Valid() )
  331. pos.y = m_viaY.GetValue();
  332. v->SetPosition( pos );
  333. }
  334. if( m_ViaTypeChoice->GetSelection() != 3)
  335. {
  336. switch( m_ViaTypeChoice->GetSelection() )
  337. {
  338. case 0:
  339. v->SetViaType( VIA_THROUGH );
  340. v->SanitizeLayers();
  341. break;
  342. case 1:
  343. v->SetViaType( VIA_MICROVIA );
  344. break;
  345. case 2:
  346. v->SetViaType( VIA_BLIND_BURIED );
  347. break;
  348. default:
  349. break;
  350. }
  351. }
  352. auto startLayer = static_cast<PCB_LAYER_ID>( m_ViaStartLayer->GetLayerSelection() );
  353. auto endLayer = static_cast<PCB_LAYER_ID>( m_ViaEndLayer->GetLayerSelection() );
  354. if (startLayer != UNDEFINED_LAYER )
  355. v->SetTopLayer( startLayer );
  356. if (endLayer != UNDEFINED_LAYER )
  357. v->SetBottomLayer( endLayer );
  358. v->SanitizeLayers();
  359. if( m_viaNetclass->IsChecked() )
  360. {
  361. switch( v->GetViaType() )
  362. {
  363. default:
  364. wxFAIL_MSG("Unhandled via type");
  365. // fall through
  366. case VIA_THROUGH:
  367. case VIA_BLIND_BURIED:
  368. v->SetWidth( v->GetNetClass()->GetViaDiameter() );
  369. v->SetDrill( v->GetNetClass()->GetViaDrill() );
  370. break;
  371. case VIA_MICROVIA:
  372. v->SetWidth( v->GetNetClass()->GetuViaDiameter() );
  373. v->SetDrill( v->GetNetClass()->GetuViaDrill() );
  374. break;
  375. }
  376. }
  377. else
  378. {
  379. if( m_viaDiameter.Valid() )
  380. v->SetWidth( m_viaDiameter.GetValue() );
  381. if( m_viaDrill.Valid() )
  382. v->SetDrill( m_viaDrill.GetValue() );
  383. }
  384. if ( m_NetComboBox->IsUniqueNetSelected() )
  385. {
  386. printf("snc %d\n", m_NetComboBox->GetSelectedNet());
  387. v->SetNetCode( m_NetComboBox->GetSelectedNet() );
  388. }
  389. if( changeLock )
  390. v->SetLocked( setLock );
  391. break;
  392. }
  393. default:
  394. wxASSERT( false );
  395. break;
  396. }
  397. }
  398. return true;
  399. }
  400. void DIALOG_TRACK_VIA_PROPERTIES::onClose( wxCloseEvent& aEvent )
  401. {
  402. EndModal( 0 );
  403. }
  404. void DIALOG_TRACK_VIA_PROPERTIES::onTrackNetclassCheck( wxCommandEvent& aEvent )
  405. {
  406. bool enableNC = aEvent.IsChecked();
  407. m_TrackWidthLabel->Enable( !enableNC );
  408. m_TrackWidthCtrl->Enable( !enableNC );
  409. m_TrackWidthUnit->Enable( !enableNC );
  410. }
  411. void DIALOG_TRACK_VIA_PROPERTIES::onViaNetclassCheck( wxCommandEvent& aEvent )
  412. {
  413. bool enableNC = aEvent.IsChecked();
  414. m_DesignRuleVias->Enable( !enableNC );
  415. m_DesignRuleViasCtrl->Enable( !enableNC );
  416. m_DesignRuleViasUnit->Enable( !enableNC );
  417. m_ViaDiameterLabel->Enable( !enableNC );
  418. m_ViaDiameterCtrl->Enable( !enableNC );
  419. m_ViaDiameterUnit->Enable( !enableNC );
  420. m_ViaDrillLabel->Enable( !enableNC );
  421. m_ViaDrillCtrl->Enable( !enableNC );
  422. m_ViaDrillUnit->Enable( !enableNC );
  423. }
  424. void DIALOG_TRACK_VIA_PROPERTIES::onCancelClick( wxCommandEvent& aEvent )
  425. {
  426. EndModal( 0 );
  427. }
  428. void DIALOG_TRACK_VIA_PROPERTIES::onOkClick( wxCommandEvent& aEvent )
  429. {
  430. if( check() )
  431. EndModal( 1 );
  432. }
  433. void DIALOG_TRACK_VIA_PROPERTIES::onViaSelect( wxCommandEvent& aEvent )
  434. {
  435. VIA_DIMENSION* viaDimension = static_cast<VIA_DIMENSION*> ( aEvent.GetClientData() );
  436. wxString msg = StringFromValue( g_UserUnit, viaDimension->m_Diameter, false );
  437. m_ViaDiameterCtrl->ChangeValue( msg );
  438. msg = StringFromValue( g_UserUnit, viaDimension->m_Drill, false );
  439. m_ViaDrillCtrl->ChangeValue( msg );
  440. }
  441. void DIALOG_TRACK_VIA_PROPERTIES::onViaEdit( wxCommandEvent& aEvent )
  442. {
  443. m_DesignRuleViasCtrl->SetSelection( wxNOT_FOUND );
  444. if( m_vias )
  445. {
  446. if( m_ViaTypeChoice->GetSelection() != 0 ) // check if selected type isnt through.
  447. {
  448. m_ViaStartLayer->Enable();
  449. m_ViaEndLayer->Enable();
  450. }
  451. else
  452. {
  453. m_ViaStartLayer->SetLayerSelection( F_Cu );
  454. m_ViaEndLayer->SetLayerSelection( B_Cu );
  455. m_ViaStartLayer->Enable( false );
  456. m_ViaEndLayer->Enable( false );
  457. }
  458. }
  459. }
  460. bool DIALOG_TRACK_VIA_PROPERTIES::check() const
  461. {
  462. bool trackNetclass = m_trackNetclass->IsChecked();
  463. bool viaNetclass = m_trackNetclass->IsChecked();
  464. if( m_tracks && !trackNetclass && m_trackWidth.Valid() && m_trackWidth.GetValue() <= 0 )
  465. {
  466. DisplayError( GetParent(), _( "Invalid track width" ) );
  467. m_TrackWidthCtrl->SetFocus();
  468. return false;
  469. }
  470. if( m_vias && !viaNetclass )
  471. {
  472. if( m_viaDiameter.Valid() && m_viaDiameter.GetValue() <= 0 )
  473. {
  474. DisplayError( GetParent(), _( "Invalid via diameter" ) );
  475. m_ViaDiameterCtrl->SetFocus();
  476. return false;
  477. }
  478. if( m_viaDrill.Valid() && m_viaDrill.GetValue() <= 0 )
  479. {
  480. DisplayError( GetParent(), _( "Invalid via drill size" ) );
  481. m_ViaDrillCtrl->SetFocus();
  482. return false;
  483. }
  484. if( m_viaDiameter.Valid() && m_viaDrill.Valid() && m_viaDiameter.GetValue() <= m_viaDrill.GetValue() )
  485. {
  486. DisplayError( GetParent(), _( "Via drill size has to be smaller than via diameter" ) );
  487. m_ViaDrillCtrl->SetFocus();
  488. return false;
  489. }
  490. }
  491. if( m_vias)
  492. {
  493. if( m_ViaStartLayer->GetLayerSelection() == m_ViaEndLayer->GetLayerSelection() )
  494. {
  495. DisplayError( GetParent(), _( "Via start layer and end layer cannot be the same" ) );
  496. return false;
  497. }
  498. }
  499. return true;
  500. }