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.

632 lines
18 KiB

16 years ago
16 years ago
18 years ago
18 years ago
18 years ago
15 years ago
18 years ago
18 years ago
  1. /********************/
  2. /* basepcbframe.cpp */
  3. /********************/
  4. #ifdef __GNUG__
  5. #pragma implementation
  6. #endif
  7. #include "fctsys.h"
  8. #include "wxstruct.h"
  9. #include "common.h"
  10. #include "confirm.h"
  11. #include "appl_wxstruct.h"
  12. #include "dialog_helpers.h"
  13. #include "kicad_device_context.h"
  14. #include "pcbnew.h"
  15. #include "bitmaps.h"
  16. #include "pcbnew_id.h"
  17. #include "class_board_design_settings.h"
  18. #include "collectors.h"
  19. #include "class_drawpanel.h"
  20. /* Configuration entry names. */
  21. static const wxString UserGridSizeXEntry( wxT( "PcbUserGrid_X" ) );
  22. static const wxString UserGridSizeYEntry( wxT( "PcbUserGrid_Y" ) );
  23. static const wxString UserGridUnitsEntry( wxT( "PcbUserGrid_Unit" ) );
  24. static const wxString DisplayPadFillEntry( wxT( "DiPadFi" ) );
  25. static const wxString DisplayViaFillEntry( wxT( "DiViaFi" ) );
  26. static const wxString DisplayPadNumberEntry( wxT( "DiPadNu" ) );
  27. static const wxString DisplayModuleEdgeEntry( wxT( "DiModEd" ) );
  28. static const wxString DisplayModuleTextEntry( wxT( "DiModTx" ) );
  29. /****************************/
  30. /* class PCB_BASE_FRAME */
  31. /****************************/
  32. BEGIN_EVENT_TABLE( PCB_BASE_FRAME, EDA_DRAW_FRAME )
  33. EVT_MENU_RANGE( ID_POPUP_PCB_ITEM_SELECTION_START, ID_POPUP_PCB_ITEM_SELECTION_END,
  34. PCB_BASE_FRAME::ProcessItemSelection )
  35. EVT_TOOL( ID_TB_OPTIONS_SHOW_POLAR_COORD, PCB_BASE_FRAME::OnTogglePolarCoords )
  36. EVT_TOOL( ID_TB_OPTIONS_SHOW_PADS_SKETCH, PCB_BASE_FRAME::OnTogglePadDrawMode )
  37. EVT_UPDATE_UI( ID_TB_OPTIONS_SHOW_POLAR_COORD, PCB_BASE_FRAME::OnUpdateCoordType )
  38. EVT_UPDATE_UI( ID_TB_OPTIONS_SHOW_PADS_SKETCH, PCB_BASE_FRAME::OnUpdatePadDrawMode )
  39. EVT_UPDATE_UI( ID_ON_GRID_SELECT, PCB_BASE_FRAME::OnUpdateSelectGrid )
  40. EVT_UPDATE_UI( ID_ON_ZOOM_SELECT, PCB_BASE_FRAME::OnUpdateSelectZoom )
  41. EVT_UPDATE_UI_RANGE( ID_ZOOM_IN, ID_ZOOM_PAGE, PCB_BASE_FRAME::OnUpdateSelectZoom )
  42. END_EVENT_TABLE()
  43. PCB_BASE_FRAME::PCB_BASE_FRAME( wxWindow* father,
  44. int idtype,
  45. const wxString& title,
  46. const wxPoint& pos,
  47. const wxSize& size,
  48. long style) :
  49. EDA_DRAW_FRAME( father, idtype, title, pos, size, style )
  50. {
  51. m_InternalUnits = PCB_INTERNAL_UNIT; // Internal unit = 1/10000 inch
  52. m_Pcb = NULL;
  53. m_DisplayPadFill = true; // How to draw pads
  54. m_DisplayViaFill = true; // How to draw vias
  55. m_DisplayPadNum = true; // show pads number
  56. m_DisplayModEdge = FILLED; // How to display module drawings (line/ filled / sketch)
  57. m_DisplayModText = FILLED; // How to display module texts (line/ filled / sketch)
  58. m_DisplayPcbTrackFill = true; /* FALSE = sketch , true = filled */
  59. m_Draw3DFrame = NULL; // Display Window in 3D mode (OpenGL)
  60. m_ModuleEditFrame = NULL; // Frame for footprint edition
  61. m_UserGridSize = wxRealPoint( 100.0, 100.0 );
  62. m_UserGridUnit = INCHES;
  63. m_Collector = new GENERAL_COLLECTOR();
  64. }
  65. PCB_BASE_FRAME::~PCB_BASE_FRAME()
  66. {
  67. delete m_Collector;
  68. }
  69. void PCB_BASE_FRAME::SetBoard( BOARD* aBoard )
  70. {
  71. if( m_Pcb != g_ModuleEditor_Pcb )
  72. delete m_Pcb;
  73. m_Pcb = aBoard;
  74. }
  75. /**
  76. * Return the "best" zoom, i.e. the zoom which shows the entire board on screen
  77. */
  78. int PCB_BASE_FRAME::BestZoom( void )
  79. {
  80. int dx, dy, ii, jj;
  81. int bestzoom;
  82. wxSize size;
  83. if( m_Pcb == NULL )
  84. return 32 * GetScreen()->m_ZoomScalar;
  85. m_Pcb->ComputeBoundingBox();
  86. dx = m_Pcb->m_BoundaryBox.GetWidth();
  87. dy = m_Pcb->m_BoundaryBox.GetHeight();
  88. size = DrawPanel->GetClientSize();
  89. if( size.x )
  90. ii = wxRound( ( (double) dx + ((double) size.x / 2.0) ) / (double) size.x );
  91. else
  92. ii = 31;
  93. if ( size.y )
  94. jj = wxRound( ( (double) dy + ((double) size.y / 2.0) ) / (double) size.y );
  95. else
  96. jj = 31;
  97. bestzoom = MAX( ii, jj ) + 1;
  98. GetScreen()->SetScrollCenterPosition( m_Pcb->m_BoundaryBox.Centre() );
  99. return bestzoom * GetScreen()->m_ZoomScalar;
  100. }
  101. void PCB_BASE_FRAME::CursorGoto( const wxPoint& aPos )
  102. {
  103. // factored out of pcbnew/find.cpp
  104. PCB_SCREEN* screen = (PCB_SCREEN*)GetScreen();
  105. wxClientDC dc( DrawPanel );
  106. /* There may be need to reframe the drawing. */
  107. if( !DrawPanel->IsPointOnDisplay( aPos ) )
  108. {
  109. screen->SetCrossHairPosition( aPos );
  110. RedrawScreen( aPos, true );
  111. }
  112. else
  113. {
  114. // Put cursor on item position
  115. DrawPanel->CrossHairOff( &dc );
  116. screen->SetCrossHairPosition( aPos );
  117. DrawPanel->MoveCursorToCrossHair();
  118. DrawPanel->CrossHairOn( &dc );
  119. }
  120. }
  121. // Virtual function
  122. void PCB_BASE_FRAME::ReCreateMenuBar( void )
  123. {
  124. }
  125. /* Virtual functions: Do nothing for PCB_BASE_FRAME window */
  126. void PCB_BASE_FRAME::Show3D_Frame( wxCommandEvent& event )
  127. {
  128. }
  129. // Note: virtual, overridden in PCB_EDIT_FRAME;
  130. void PCB_BASE_FRAME::SwitchLayer( wxDC* DC, int layer )
  131. {
  132. int preslayer = ((PCB_SCREEN*)GetScreen())->m_Active_Layer;
  133. // Check if the specified layer matches the present layer
  134. if( layer == preslayer )
  135. return;
  136. // Copper layers cannot be selected unconditionally; how many
  137. // of those layers are currently enabled needs to be checked.
  138. if( IsValidCopperLayerIndex( layer ) )
  139. {
  140. // If only one copper layer is enabled, the only such layer
  141. // that can be selected to is the "Copper" layer (so the
  142. // selection of any other copper layer is disregarded).
  143. if( m_Pcb->GetCopperLayerCount() < 2 )
  144. {
  145. if( layer != LAYER_N_BACK )
  146. {
  147. return;
  148. }
  149. }
  150. // If more than one copper layer is enabled, the "Copper"
  151. // and "Component" layers can be selected, but the total
  152. // number of copper layers determines which internal
  153. // layers are also capable of being selected.
  154. else
  155. {
  156. if( ( layer != LAYER_N_BACK ) && ( layer != LAYER_N_FRONT )
  157. && ( layer >= m_Pcb->GetCopperLayerCount() - 1 ) )
  158. {
  159. return;
  160. }
  161. }
  162. }
  163. // Is yet more checking required? E.g. when the layer to be selected
  164. // is a non-copper layer, or when switching between a copper layer
  165. // and a non-copper layer, or vice-versa?
  166. // ...
  167. GetScreen()->m_Active_Layer = layer;
  168. if( DisplayOpt.ContrastModeDisplay )
  169. DrawPanel->Refresh();
  170. }
  171. void PCB_BASE_FRAME::OnTogglePolarCoords( wxCommandEvent& aEvent )
  172. {
  173. SetStatusText( wxEmptyString );
  174. DisplayOpt.DisplayPolarCood = !DisplayOpt.DisplayPolarCood;
  175. UpdateStatusBar();
  176. }
  177. void PCB_BASE_FRAME::OnTogglePadDrawMode( wxCommandEvent& aEvent )
  178. {
  179. m_DisplayPadFill = DisplayOpt.DisplayPadFill = !m_DisplayPadFill;
  180. DrawPanel->Refresh();
  181. }
  182. void PCB_BASE_FRAME::OnUpdateCoordType( wxUpdateUIEvent& aEvent )
  183. {
  184. aEvent.Check( DisplayOpt.DisplayPolarCood );
  185. m_OptionsToolBar->SetToolShortHelp( ID_TB_OPTIONS_SHOW_POLAR_COORD,
  186. DisplayOpt.DisplayPolarCood ?
  187. _( "Display rectangular coordinates" ) :
  188. _( "Display polar coordinates" ) );
  189. }
  190. void PCB_BASE_FRAME::OnUpdatePadDrawMode( wxUpdateUIEvent& aEvent )
  191. {
  192. aEvent.Check( !m_DisplayPadFill );
  193. m_OptionsToolBar->SetToolShortHelp( ID_TB_OPTIONS_SHOW_PADS_SKETCH,
  194. m_DisplayPadFill ?
  195. _( "Show pads in outline mode" ) :
  196. _( "Show pads in fill mode" ) );
  197. }
  198. void PCB_BASE_FRAME::OnUpdateSelectGrid( wxUpdateUIEvent& aEvent )
  199. {
  200. // No need to update the grid select box if it doesn't exist or the grid setting change
  201. // was made using the select box.
  202. if( m_SelGridBox == NULL || m_AuxiliaryToolBar == NULL )
  203. return;
  204. int select = wxNOT_FOUND;
  205. for( size_t i = 0; i < GetScreen()->GetGridCount(); i++ )
  206. {
  207. if( GetScreen()->GetGridId() == GetScreen()->GetGrid( i ).m_Id )
  208. {
  209. select = (int) i;
  210. break;
  211. }
  212. }
  213. if( select != m_SelGridBox->GetSelection() )
  214. m_SelGridBox->SetSelection( select );
  215. }
  216. void PCB_BASE_FRAME::OnUpdateSelectZoom( wxUpdateUIEvent& aEvent )
  217. {
  218. if( m_SelZoomBox == NULL || m_AuxiliaryToolBar == NULL )
  219. return;
  220. int current = 0;
  221. for( size_t i = 0; i < GetScreen()->m_ZoomList.GetCount(); i++ )
  222. {
  223. if( GetScreen()->GetZoom() == GetScreen()->m_ZoomList[i] )
  224. {
  225. current = i + 1;
  226. break;
  227. }
  228. }
  229. if( current != m_SelZoomBox->GetSelection() )
  230. m_SelZoomBox->SetSelection( current );
  231. }
  232. void PCB_BASE_FRAME::ProcessItemSelection( wxCommandEvent& aEvent )
  233. {
  234. int id = aEvent.GetId();
  235. // index into the collector list:
  236. int itemNdx = id - ID_POPUP_PCB_ITEM_SELECTION_START;
  237. if( id >= ID_POPUP_PCB_ITEM_SELECTION_START && id <= ID_POPUP_PCB_ITEM_SELECTION_END )
  238. {
  239. BOARD_ITEM* item = (*m_Collector)[itemNdx];
  240. DrawPanel->m_AbortRequest = false;
  241. #if 0 && defined (DEBUG)
  242. item->Show( 0, std::cout );
  243. #endif
  244. SetCurItem( item );
  245. }
  246. }
  247. void PCB_BASE_FRAME::SetCurItem( BOARD_ITEM* aItem, bool aDisplayInfo )
  248. {
  249. GetScreen()->SetCurItem( aItem );
  250. if( aItem )
  251. {
  252. if( aDisplayInfo )
  253. aItem->DisplayInfo( this );
  254. #if 0 && defined(DEBUG)
  255. aItem->Show( 0, std::cout );
  256. #endif
  257. }
  258. else
  259. {
  260. // we can use either of these two:
  261. //MsgPanel->EraseMsgBox();
  262. m_Pcb->DisplayInfo( this ); // show the BOARD stuff
  263. #if 0 && defined(DEBUG)
  264. std::cout << "SetCurItem(NULL)\n";
  265. #endif
  266. }
  267. }
  268. BOARD_ITEM* PCB_BASE_FRAME::GetCurItem()
  269. {
  270. return GetScreen()->GetCurItem();
  271. }
  272. GENERAL_COLLECTORS_GUIDE PCB_BASE_FRAME::GetCollectorsGuide()
  273. {
  274. GENERAL_COLLECTORS_GUIDE guide( m_Pcb->GetVisibleLayers(),
  275. ( (PCB_SCREEN*)GetScreen())->m_Active_Layer );
  276. // account for the globals
  277. guide.SetIgnoreMTextsMarkedNoShow( ! m_Pcb->IsElementVisible( MOD_TEXT_INVISIBLE ));
  278. guide.SetIgnoreMTextsOnCopper( ! m_Pcb->IsElementVisible( MOD_TEXT_BK_VISIBLE ));
  279. guide.SetIgnoreMTextsOnCmp( ! m_Pcb->IsElementVisible( MOD_TEXT_FR_VISIBLE ));
  280. guide.SetIgnoreModulesOnCu( ! m_Pcb->IsElementVisible( MOD_BK_VISIBLE ) );
  281. guide.SetIgnoreModulesOnCmp( ! m_Pcb->IsElementVisible( MOD_FR_VISIBLE ) );
  282. guide.SetIgnorePadsOnBack( ! m_Pcb->IsElementVisible( PAD_BK_VISIBLE ) );
  283. guide.SetIgnorePadsOnFront( ! m_Pcb->IsElementVisible( PAD_FR_VISIBLE ) );
  284. return guide;
  285. }
  286. void PCB_BASE_FRAME::SetToolID( int aId, int aCursor, const wxString& aToolMsg )
  287. {
  288. bool redraw = false;
  289. EDA_DRAW_FRAME::SetToolID( aId, aCursor, aToolMsg );
  290. if( aId < 0 )
  291. return;
  292. // handle color changes for transitions in and out of ID_TRACK_BUTT
  293. if( ( GetToolId() == ID_TRACK_BUTT && aId != ID_TRACK_BUTT )
  294. || ( GetToolId() != ID_TRACK_BUTT && aId== ID_TRACK_BUTT ) )
  295. {
  296. if( DisplayOpt.ContrastModeDisplay )
  297. redraw = true;
  298. }
  299. // must do this after the tool has been set, otherwise pad::Draw() does
  300. // not show proper color when DisplayOpt.ContrastModeDisplay is true.
  301. if( redraw && DrawPanel)
  302. DrawPanel->Refresh();
  303. }
  304. /*
  305. * Update the status bar information.
  306. */
  307. void PCB_BASE_FRAME::UpdateStatusBar()
  308. {
  309. EDA_DRAW_FRAME::UpdateStatusBar();
  310. if( DisplayOpt.DisplayPolarCood ) // display polar coordinates
  311. {
  312. PCB_SCREEN* screen = GetScreen();
  313. if( !screen )
  314. return;
  315. wxString Line;
  316. double theta, ro;
  317. int dx = screen->GetCrossHairPosition().x - screen->m_O_Curseur.x;
  318. int dy = screen->GetCrossHairPosition().y - screen->m_O_Curseur.y;
  319. if( dx==0 && dy==0 )
  320. theta = 0.0;
  321. else
  322. theta = atan2( (double) -dy, (double) dx );
  323. theta = theta * 180.0 / M_PI;
  324. ro = sqrt( ( (double) dx * dx ) + ( (double) dy * dy ) );
  325. wxString formatter;
  326. switch( g_UserUnit )
  327. {
  328. case INCHES:
  329. formatter = wxT( "Ro %.4f Th %.1f" );
  330. break;
  331. case MILLIMETRES:
  332. formatter = wxT( "Ro %.3f Th %.1f" );
  333. break;
  334. case UNSCALED_UNITS:
  335. formatter = wxT( "Ro %f Th %f" );
  336. break;
  337. }
  338. Line.Printf( formatter, To_User_Unit( g_UserUnit, ro, m_InternalUnits ), theta );
  339. // overwrite the absolute cartesian coordinates
  340. SetStatusText( Line, 2 );
  341. }
  342. }
  343. void PCB_BASE_FRAME::unitsChangeRefresh()
  344. {
  345. EDA_DRAW_FRAME::unitsChangeRefresh(); // Update the status bar.
  346. updateGridSelectBox();
  347. }
  348. /**
  349. * Load PCB base frame specific configuration settings.
  350. *
  351. * Don't forget to call this base method from any derived classes or the
  352. * settings will not get loaded.
  353. */
  354. void PCB_BASE_FRAME::LoadSettings()
  355. {
  356. wxASSERT( wxGetApp().m_EDA_Config != NULL );
  357. wxConfig* cfg = wxGetApp().m_EDA_Config;
  358. EDA_DRAW_FRAME::LoadSettings();
  359. // Ensure grid id is an existent grid id:
  360. if( (m_LastGridSizeId <= 0) ||
  361. (m_LastGridSizeId > (ID_POPUP_GRID_USER - ID_POPUP_GRID_LEVEL_1000)) )
  362. m_LastGridSizeId = ID_POPUP_GRID_LEVEL_500 - ID_POPUP_GRID_LEVEL_1000;
  363. cfg->Read( m_FrameName + UserGridSizeXEntry, &m_UserGridSize.x, 0.01 );
  364. cfg->Read( m_FrameName + UserGridSizeYEntry, &m_UserGridSize.y, 0.01 );
  365. long itmp;
  366. cfg->Read( m_FrameName + UserGridUnitsEntry, &itmp, ( long )INCHES );
  367. m_UserGridUnit = (UserUnitType) itmp;
  368. cfg->Read( m_FrameName + DisplayPadFillEntry, &m_DisplayPadFill, true );
  369. cfg->Read( m_FrameName + DisplayViaFillEntry, &m_DisplayViaFill, true );
  370. cfg->Read( m_FrameName + DisplayPadNumberEntry, &m_DisplayPadNum, true );
  371. cfg->Read( m_FrameName + DisplayModuleEdgeEntry, &m_DisplayModEdge, ( long )FILLED );
  372. if( m_DisplayModEdge < FILAIRE || m_DisplayModEdge > SKETCH )
  373. m_DisplayModEdge = FILLED;
  374. cfg->Read( m_FrameName + DisplayModuleTextEntry, &m_DisplayModText, ( long )FILLED );
  375. if( m_DisplayModText < FILAIRE || m_DisplayModText > SKETCH )
  376. m_DisplayModText = FILLED;
  377. // WxWidgets 2.9.1 seems call setlocale( LC_NUMERIC, "" )
  378. // when reading doubles in config,
  379. // but forget to back to current locale. So we call SetLocaleTo_Default
  380. SetLocaleTo_Default( );
  381. }
  382. /**
  383. * Save PCB base frame specific configuration settings.
  384. *
  385. * Don't forget to call this base method from any derived classes or the
  386. * settings will not get saved.
  387. */
  388. void PCB_BASE_FRAME::SaveSettings()
  389. {
  390. wxASSERT( wxGetApp().m_EDA_Config != NULL );
  391. wxConfig* cfg = wxGetApp().m_EDA_Config;
  392. EDA_DRAW_FRAME::SaveSettings();
  393. cfg->Write( m_FrameName + UserGridSizeXEntry, m_UserGridSize.x );
  394. cfg->Write( m_FrameName + UserGridSizeYEntry, m_UserGridSize.y );
  395. cfg->Write( m_FrameName + UserGridUnitsEntry, ( long )m_UserGridUnit );
  396. cfg->Write( m_FrameName + DisplayPadFillEntry, m_DisplayPadFill );
  397. cfg->Write( m_FrameName + DisplayViaFillEntry, m_DisplayViaFill );
  398. cfg->Write( m_FrameName + DisplayPadNumberEntry, m_DisplayPadNum );
  399. cfg->Write( m_FrameName + DisplayModuleEdgeEntry, ( long )m_DisplayModEdge );
  400. cfg->Write( m_FrameName + DisplayModuleTextEntry, ( long )m_DisplayModText );
  401. }
  402. /**
  403. * Function OnModify
  404. * Must be called after a schematic change
  405. * in order to set the "modify" flag of the current screen
  406. * and update the date in frame reference
  407. * do not forget to call this basic OnModify function to update info
  408. * in derived OnModify functions
  409. */
  410. void PCB_BASE_FRAME::OnModify( )
  411. {
  412. GetScreen()->SetModify( );
  413. wxString date = GenDate();
  414. GetScreen()->m_Date = date;
  415. }
  416. void PCB_BASE_FRAME::updateGridSelectBox()
  417. {
  418. UpdateStatusBar();
  419. DisplayUnitsMsg();
  420. if( m_SelGridBox == NULL )
  421. return;
  422. // Update grid values with the current units setting.
  423. m_SelGridBox->Clear();
  424. wxString msg;
  425. wxString format = _( "Grid");
  426. switch( g_UserUnit )
  427. {
  428. case INCHES:
  429. format += wxT( " %.1f" );
  430. break;
  431. case MILLIMETRES:
  432. format += wxT( " %.3f" );
  433. break;
  434. case UNSCALED_UNITS:
  435. format += wxT( " %f" );
  436. break;
  437. }
  438. for( size_t i = 0; i < GetScreen()->GetGridCount(); i++ )
  439. {
  440. GRID_TYPE& grid = GetScreen()->GetGrid( i );
  441. double value = To_User_Unit( g_UserUnit, grid.m_Size.x, m_InternalUnits );
  442. if( grid.m_Id != ID_POPUP_GRID_USER )
  443. {
  444. switch( g_UserUnit )
  445. {
  446. case INCHES:
  447. msg.Printf( format.GetData(), value * 1000 );
  448. break;
  449. case MILLIMETRES:
  450. case UNSCALED_UNITS:
  451. msg.Printf( format.GetData(), value );
  452. break;
  453. }
  454. }
  455. else
  456. msg = _( "User Grid" );
  457. m_SelGridBox->Append( msg, (void*) &grid.m_Id );
  458. if( ( m_LastGridSizeId + ID_POPUP_GRID_LEVEL_1000 ) == GetScreen()->GetGrid( i ).m_Id )
  459. m_SelGridBox->SetSelection( i );
  460. }
  461. }
  462. void PCB_BASE_FRAME::updateZoomSelectBox()
  463. {
  464. if( m_SelZoomBox == NULL )
  465. return;
  466. wxString msg;
  467. m_SelZoomBox->Clear();
  468. m_SelZoomBox->Append( _( "Auto" ) );
  469. m_SelZoomBox->SetSelection( 0 );
  470. for( int i = 0; i < (int)GetScreen()->m_ZoomList.GetCount(); i++ )
  471. {
  472. msg = _( "Zoom " );
  473. if ( ( GetScreen()->m_ZoomList[i] % GetScreen()->m_ZoomScalar ) == 0 )
  474. msg << GetScreen()->m_ZoomList[i] / GetScreen()->m_ZoomScalar;
  475. else
  476. {
  477. wxString value;
  478. value.Printf( wxT( "%.1f" ),
  479. (float)GetScreen()->m_ZoomList[i] / GetScreen()->m_ZoomScalar );
  480. msg += value;
  481. }
  482. m_SelZoomBox->Append( msg );
  483. if( GetScreen()->GetZoom() == GetScreen()->m_ZoomList[i] )
  484. m_SelZoomBox->SetSelection( i + 1 );
  485. }
  486. }