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.

888 lines
26 KiB

15 years ago
19 years ago
19 years ago
19 years ago
19 years ago
19 years ago
19 years ago
19 years ago
19 years ago
19 years ago
19 years ago
19 years ago
19 years ago
19 years ago
19 years ago
19 years ago
19 years ago
19 years ago
19 years ago
19 years ago
19 years ago
19 years ago
19 years ago
19 years ago
19 years ago
19 years ago
19 years ago
19 years ago
19 years ago
19 years ago
19 years ago
19 years ago
19 years ago
19 years ago
19 years ago
19 years ago
19 years ago
19 years ago
19 years ago
19 years ago
19 years ago
19 years ago
19 years ago
19 years ago
19 years ago
19 years ago
19 years ago
19 years ago
19 years ago
19 years ago
19 years ago
19 years ago
19 years ago
  1. /*
  2. * This program source code file is part of KiCad, a free EDA CAD application.
  3. *
  4. * Copyright (C) 2004 Jean-Pierre Charras, jaen-pierre.charras@gipsa-lab.inpg.com
  5. * Copyright (C) 2008-2011 Wayne Stambaugh <stambaughw@verizon.net>
  6. * Copyright (C) 2004-2011 KiCad Developers, see change_log.txt for contributors.
  7. *
  8. * This program is free software; you can redistribute it and/or
  9. * modify it under the terms of the GNU General Public License
  10. * as published by the Free Software Foundation; either version 2
  11. * of the License, or (at your option) any later version.
  12. *
  13. * This program is distributed in the hope that it will be useful,
  14. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. * GNU General Public License for more details.
  17. *
  18. * You should have received a copy of the GNU General Public License
  19. * along with this program; if not, you may find one here:
  20. * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
  21. * or you may search the http://www.gnu.org website for the version 2 license,
  22. * or you may write to the Free Software Foundation, Inc.,
  23. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
  24. */
  25. /**
  26. * @file drawframe.cpp
  27. */
  28. #include "fctsys.h"
  29. #include "appl_wxstruct.h"
  30. #include "gr_basic.h"
  31. #include "common.h"
  32. #include "bitmaps.h"
  33. #include "macros.h"
  34. #include "id.h"
  35. #include "class_drawpanel.h"
  36. #include "class_base_screen.h"
  37. #include "wxstruct.h"
  38. #include "confirm.h"
  39. #include "kicad_device_context.h"
  40. #include "dialog_helpers.h"
  41. #include <wx/fontdlg.h>
  42. /**
  43. * Definition for enabling and disabling scroll bar setting trace output. See the
  44. * wxWidgets documentation on useing the WXTRACE environment variable.
  45. */
  46. static const wxString traceScrollSettings( wxT( "KicadScrollSettings" ) );
  47. // Configuration entry names.
  48. static const wxString CursorShapeEntryKeyword( wxT( "CursorShape" ) );
  49. static const wxString ShowGridEntryKeyword( wxT( "ShowGrid" ) );
  50. static const wxString GridColorEntryKeyword( wxT( "GridColor" ) );
  51. static const wxString LastGridSizeId( wxT( "_LastGridSize" ) );
  52. BEGIN_EVENT_TABLE( EDA_DRAW_FRAME, EDA_BASE_FRAME )
  53. EVT_MOUSEWHEEL( EDA_DRAW_FRAME::OnMouseEvent )
  54. EVT_MENU_OPEN( EDA_DRAW_FRAME::OnMenuOpen )
  55. EVT_ACTIVATE( EDA_DRAW_FRAME::OnActivate )
  56. EVT_MENU_RANGE( ID_ZOOM_IN, ID_ZOOM_REDRAW, EDA_DRAW_FRAME::OnZoom )
  57. EVT_MENU_RANGE( ID_POPUP_ZOOM_START_RANGE, ID_POPUP_ZOOM_END_RANGE,
  58. EDA_DRAW_FRAME::OnZoom )
  59. EVT_MENU_RANGE( ID_POPUP_GRID_LEVEL_1000, ID_POPUP_GRID_USER,
  60. EDA_DRAW_FRAME::OnSelectGrid )
  61. EVT_TOOL( ID_TB_OPTIONS_SHOW_GRID, EDA_DRAW_FRAME::OnToggleGridState )
  62. EVT_TOOL_RANGE( ID_TB_OPTIONS_SELECT_UNIT_MM, ID_TB_OPTIONS_SELECT_UNIT_INCH,
  63. EDA_DRAW_FRAME::OnSelectUnits )
  64. EVT_TOOL( ID_TB_OPTIONS_SELECT_CURSOR, EDA_DRAW_FRAME::OnToggleCrossHairStyle )
  65. EVT_UPDATE_UI( wxID_UNDO, EDA_DRAW_FRAME::OnUpdateUndo )
  66. EVT_UPDATE_UI( wxID_REDO, EDA_DRAW_FRAME::OnUpdateRedo )
  67. EVT_UPDATE_UI( ID_TB_OPTIONS_SHOW_GRID, EDA_DRAW_FRAME::OnUpdateGrid )
  68. EVT_UPDATE_UI( ID_TB_OPTIONS_SELECT_CURSOR, EDA_DRAW_FRAME::OnUpdateCrossHairStyle )
  69. EVT_UPDATE_UI_RANGE( ID_TB_OPTIONS_SELECT_UNIT_MM, ID_TB_OPTIONS_SELECT_UNIT_INCH,
  70. EDA_DRAW_FRAME::OnUpdateUnits )
  71. END_EVENT_TABLE()
  72. EDA_DRAW_FRAME::EDA_DRAW_FRAME( wxWindow* father, int idtype, const wxString& title,
  73. const wxPoint& pos, const wxSize& size, long style ) :
  74. EDA_BASE_FRAME( father, idtype, title, pos, size, style )
  75. {
  76. wxSize minsize;
  77. m_drawToolBar = NULL;
  78. m_optionsToolBar = NULL;
  79. m_gridSelectBox = NULL;
  80. m_zoomSelectBox = NULL;
  81. m_HotkeysZoomAndGridList = NULL;
  82. m_canvas = NULL;
  83. m_messagePanel = NULL;
  84. m_currentScreen = NULL;
  85. m_toolId = ID_NO_TOOL_SELECTED;
  86. m_lastDrawToolId = ID_NO_TOOL_SELECTED;
  87. m_showAxis = false; // true to draw axis.
  88. m_showBorderAndTitleBlock = false; // true to display reference sheet.
  89. m_showGridAxis = false; // true to draw the grid axis
  90. m_cursorShape = 0;
  91. m_LastGridSizeId = 0;
  92. m_DrawGrid = true; // hide/Show grid. default = show
  93. m_GridColor = DARKGRAY; // Grid color
  94. m_snapToGrid = true;
  95. // Internal units per inch: = 1000 for schema, = 10000 for PCB
  96. m_internalUnits = EESCHEMA_INTERNAL_UNIT;
  97. minsize.x = 470;
  98. minsize.y = 350 + m_MsgFrameHeight;
  99. SetSizeHints( minsize.x, minsize.y, -1, -1, -1, -1 );
  100. // Make sure window has a sane minimum size.
  101. if( ( size.x < minsize.x ) || ( size.y < minsize.y ) )
  102. SetSize( 0, 0, minsize.x, minsize.y );
  103. // Pane sizes for status bar.
  104. // @todo these should be sized based on typical text content, like
  105. // "dx -10.123 -10.123 dy -10.123 -10.123" using the system font which is
  106. // in play on a particular platform, and should not be constants.
  107. // Please do not reduce these constant values, and please use dynamic
  108. // system font specific sizing in the future.
  109. #define ZOOM_DISPLAY_SIZE 60
  110. #define COORD_DISPLAY_SIZE 165
  111. #define DELTA_DISPLAY_SIZE 190
  112. #define UNITS_DISPLAY_SIZE 65
  113. #define FUNCTION_DISPLAY_SIZE 110
  114. static const int dims[6] = { -1, ZOOM_DISPLAY_SIZE,
  115. COORD_DISPLAY_SIZE, DELTA_DISPLAY_SIZE,
  116. UNITS_DISPLAY_SIZE, FUNCTION_DISPLAY_SIZE };
  117. CreateStatusBar( 6 );
  118. SetStatusWidths( 6, dims );
  119. // Create child subwindows.
  120. GetClientSize( &m_FrameSize.x, &m_FrameSize.y );
  121. m_FramePos.x = m_FramePos.y = 0;
  122. m_FrameSize.y -= m_MsgFrameHeight;
  123. m_canvas = new EDA_DRAW_PANEL( this, -1, wxPoint( 0, 0 ), m_FrameSize );
  124. m_messagePanel = new EDA_MSG_PANEL( this, -1, wxPoint( 0, m_FrameSize.y ),
  125. wxSize( m_FrameSize.x, m_MsgFrameHeight ) );
  126. m_messagePanel->SetBackgroundColour( wxColour( ColorRefs[LIGHTGRAY].m_Red,
  127. ColorRefs[LIGHTGRAY].m_Green,
  128. ColorRefs[LIGHTGRAY].m_Blue ) );
  129. }
  130. EDA_DRAW_FRAME::~EDA_DRAW_FRAME()
  131. {
  132. SAFE_DELETE( m_currentScreen );
  133. m_auimgr.UnInit();
  134. }
  135. void EDA_DRAW_FRAME::unitsChangeRefresh()
  136. {
  137. UpdateStatusBar();
  138. EDA_ITEM* item = GetScreen()->GetCurItem();
  139. if( item )
  140. item->DisplayInfo( this );
  141. }
  142. void EDA_DRAW_FRAME::EraseMsgBox()
  143. {
  144. if( m_messagePanel )
  145. m_messagePanel->EraseMsgBox();
  146. }
  147. void EDA_DRAW_FRAME::OnActivate( wxActivateEvent& event )
  148. {
  149. m_FrameIsActive = event.GetActive();
  150. if( m_canvas )
  151. m_canvas->m_CanStartBlock = -1;
  152. event.Skip(); // required under wxMAC
  153. }
  154. void EDA_DRAW_FRAME::OnMenuOpen( wxMenuEvent& event )
  155. {
  156. if( m_canvas )
  157. m_canvas->m_CanStartBlock = -1;
  158. event.Skip();
  159. }
  160. void EDA_DRAW_FRAME::OnToggleGridState( wxCommandEvent& aEvent )
  161. {
  162. SetGridVisibility( !IsGridVisible() );
  163. m_canvas->Refresh();
  164. }
  165. void EDA_DRAW_FRAME::OnSelectUnits( wxCommandEvent& aEvent )
  166. {
  167. if( aEvent.GetId() == ID_TB_OPTIONS_SELECT_UNIT_MM && g_UserUnit != MILLIMETRES )
  168. {
  169. g_UserUnit = MILLIMETRES;
  170. unitsChangeRefresh();
  171. }
  172. else if( aEvent.GetId() == ID_TB_OPTIONS_SELECT_UNIT_INCH && g_UserUnit != INCHES )
  173. {
  174. g_UserUnit = INCHES;
  175. unitsChangeRefresh();
  176. }
  177. }
  178. void EDA_DRAW_FRAME::OnToggleCrossHairStyle( wxCommandEvent& aEvent )
  179. {
  180. INSTALL_UNBUFFERED_DC( dc, m_canvas );
  181. m_canvas->CrossHairOff( &dc );
  182. m_cursorShape = !m_cursorShape;
  183. m_canvas->CrossHairOn( &dc );
  184. }
  185. void EDA_DRAW_FRAME::OnUpdateUndo( wxUpdateUIEvent& aEvent )
  186. {
  187. if( GetScreen() )
  188. aEvent.Enable( GetScreen()->GetUndoCommandCount() > 0 );
  189. }
  190. void EDA_DRAW_FRAME::OnUpdateRedo( wxUpdateUIEvent& aEvent )
  191. {
  192. if( GetScreen() )
  193. aEvent.Enable( GetScreen()->GetRedoCommandCount() > 0 );
  194. }
  195. void EDA_DRAW_FRAME::OnUpdateUnits( wxUpdateUIEvent& aEvent )
  196. {
  197. bool enable;
  198. enable = ( ((aEvent.GetId() == ID_TB_OPTIONS_SELECT_UNIT_MM) && (g_UserUnit == MILLIMETRES))
  199. || ((aEvent.GetId() == ID_TB_OPTIONS_SELECT_UNIT_INCH) && (g_UserUnit == INCHES)) );
  200. aEvent.Check( enable );
  201. DisplayUnitsMsg();
  202. }
  203. void EDA_DRAW_FRAME::OnUpdateGrid( wxUpdateUIEvent& aEvent )
  204. {
  205. wxString tool_tip = IsGridVisible() ? _( "Hide grid" ) : _( "Show grid" );
  206. aEvent.Check( IsGridVisible() );
  207. m_optionsToolBar->SetToolShortHelp( ID_TB_OPTIONS_SHOW_GRID, tool_tip );
  208. }
  209. void EDA_DRAW_FRAME::OnUpdateCrossHairStyle( wxUpdateUIEvent& aEvent )
  210. {
  211. aEvent.Check( m_cursorShape );
  212. }
  213. void EDA_DRAW_FRAME::ReCreateAuxiliaryToolbar()
  214. {
  215. }
  216. void EDA_DRAW_FRAME::ReCreateMenuBar()
  217. {
  218. }
  219. void EDA_DRAW_FRAME::OnHotKey( wxDC* aDC, int aHotKey, const wxPoint& aPosition, EDA_ITEM* aItem )
  220. {
  221. }
  222. void EDA_DRAW_FRAME::ToolOnRightClick( wxCommandEvent& event )
  223. {
  224. }
  225. void EDA_DRAW_FRAME::PrintPage( wxDC* aDC,int aPrintMask, bool aPrintMirrorMode, void* aData )
  226. {
  227. wxMessageBox( wxT("EDA_DRAW_FRAME::PrintPage() error") );
  228. }
  229. void EDA_DRAW_FRAME::OnSelectGrid( wxCommandEvent& event )
  230. {
  231. int* clientData;
  232. int id = ID_POPUP_GRID_LEVEL_100;
  233. if( event.GetEventType() == wxEVT_COMMAND_COMBOBOX_SELECTED )
  234. {
  235. if( m_gridSelectBox == NULL )
  236. return;
  237. /*
  238. * Don't use wxCommandEvent::GetClientData() here. It always
  239. * returns NULL in GTK. This solution is not as elegant but
  240. * it works.
  241. */
  242. int index = m_gridSelectBox->GetSelection();
  243. wxASSERT( index != wxNOT_FOUND );
  244. clientData = (int*) m_gridSelectBox->wxItemContainer::GetClientData( index );
  245. if( clientData != NULL )
  246. id = *clientData;
  247. }
  248. else
  249. {
  250. id = event.GetId();
  251. /* Update the grid select combobox if the grid size was changed
  252. * by menu event.
  253. */
  254. if( m_gridSelectBox != NULL )
  255. {
  256. for( size_t i = 0; i < m_gridSelectBox->GetCount(); i++ )
  257. {
  258. clientData = (int*) m_gridSelectBox->wxItemContainer::GetClientData( i );
  259. if( clientData && id == *clientData )
  260. {
  261. m_gridSelectBox->SetSelection( i );
  262. break;
  263. }
  264. }
  265. }
  266. }
  267. BASE_SCREEN* screen = GetScreen();
  268. if( screen->GetGridId() == id )
  269. return;
  270. /*
  271. * This allows for saving non-sequential command ID offsets used that
  272. * may be used in the grid size combobox. Do not use the selection
  273. * index returned by GetSelection().
  274. */
  275. m_LastGridSizeId = id - ID_POPUP_GRID_LEVEL_1000;
  276. screen->SetGrid( id );
  277. screen->SetCrossHairPosition( screen->RefPos( true ) );
  278. Refresh();
  279. }
  280. void EDA_DRAW_FRAME::OnSelectZoom( wxCommandEvent& event )
  281. {
  282. if( m_zoomSelectBox == NULL )
  283. return; // Should not happen!
  284. int id = m_zoomSelectBox->GetCurrentSelection();
  285. if( id < 0 || !( id < (int)m_zoomSelectBox->GetCount() ) )
  286. return;
  287. if( id == 0 ) // Auto zoom (Fit in Page)
  288. {
  289. Zoom_Automatique( true );
  290. }
  291. else
  292. {
  293. id--;
  294. int selectedZoom = GetScreen()->m_ZoomList[id];
  295. if( GetScreen()->GetZoom() == selectedZoom )
  296. return;
  297. GetScreen()->SetZoom( selectedZoom );
  298. RedrawScreen( GetScreen()->GetScrollCenterPosition(), false );
  299. }
  300. }
  301. double EDA_DRAW_FRAME::GetZoom( void )
  302. {
  303. return GetScreen()->GetZoom();
  304. }
  305. void EDA_DRAW_FRAME::OnMouseEvent( wxMouseEvent& event )
  306. {
  307. event.Skip();
  308. }
  309. void EDA_DRAW_FRAME::OnLeftDClick( wxDC* DC, const wxPoint& MousePos )
  310. {
  311. }
  312. void EDA_DRAW_FRAME::DisplayToolMsg( const wxString& msg )
  313. {
  314. SetStatusText( msg, 5 );
  315. }
  316. void EDA_DRAW_FRAME::DisplayUnitsMsg()
  317. {
  318. wxString msg;
  319. switch( g_UserUnit )
  320. {
  321. case INCHES:
  322. msg = _( "Inches" );
  323. break;
  324. case MILLIMETRES:
  325. msg += _( "mm" );
  326. break;
  327. default:
  328. msg += _( "Units" );
  329. break;
  330. }
  331. SetStatusText( msg, 4 );
  332. }
  333. void EDA_DRAW_FRAME::OnSize( wxSizeEvent& SizeEv )
  334. {
  335. m_FrameSize = GetClientSize( );
  336. SizeEv.Skip();
  337. }
  338. void EDA_DRAW_FRAME::SetToolID( int aId, int aCursor, const wxString& aToolMsg )
  339. {
  340. // Keep default cursor in toolbars
  341. SetCursor( wxNullCursor );
  342. // Change m_canvas cursor if requested.
  343. if( m_canvas && aCursor >= 0 )
  344. m_canvas->SetCurrentCursor( aCursor );
  345. DisplayToolMsg( aToolMsg );
  346. if( aId < 0 )
  347. return;
  348. wxCHECK2_MSG( aId >= ID_NO_TOOL_SELECTED, aId = ID_NO_TOOL_SELECTED,
  349. wxString::Format( wxT( "Current tool ID cannot be set to %d." ), aId ) );
  350. m_toolId = aId;
  351. }
  352. void EDA_DRAW_FRAME::OnGrid( int grid_type )
  353. {
  354. }
  355. wxPoint EDA_DRAW_FRAME::GetGridPosition( const wxPoint& aPosition )
  356. {
  357. wxPoint pos = aPosition;
  358. if( m_currentScreen != NULL && m_snapToGrid )
  359. pos = m_currentScreen->GetNearestGridPosition( aPosition );
  360. return pos;
  361. }
  362. int EDA_DRAW_FRAME::ReturnBlockCommand( int key )
  363. {
  364. return 0;
  365. }
  366. void EDA_DRAW_FRAME::InitBlockPasteInfos()
  367. {
  368. GetScreen()->m_BlockLocate.ClearItemsList();
  369. m_canvas->m_mouseCaptureCallback = NULL;
  370. }
  371. void EDA_DRAW_FRAME::HandleBlockPlace( wxDC* DC )
  372. {
  373. }
  374. bool EDA_DRAW_FRAME::HandleBlockEnd( wxDC* DC )
  375. {
  376. return false;
  377. }
  378. void EDA_DRAW_FRAME::AdjustScrollBars( const wxPoint& aCenterPosition )
  379. {
  380. int unitsX, unitsY, posX, posY;
  381. wxSize clientSize, logicalClientSize, virtualSize;
  382. BASE_SCREEN* screen = GetScreen();
  383. bool noRefresh = true;
  384. if( screen == NULL || m_canvas == NULL )
  385. return;
  386. double scalar = screen->GetScalingFactor();
  387. wxLogTrace( traceScrollSettings, wxT( "Center Position = ( %d, %d ), scalar = %0.5f." ),
  388. aCenterPosition.x, aCenterPosition.y, scalar );
  389. // Calculate the portion of the drawing that can be displayed in the
  390. // client area at the current zoom level.
  391. clientSize = m_canvas->GetClientSize();
  392. // The logical size of the client window.
  393. logicalClientSize.x = wxRound( (double) clientSize.x / scalar );
  394. logicalClientSize.y = wxRound( (double) clientSize.y / scalar );
  395. // A corner of the drawing in internal units.
  396. wxSize corner = GetPageSizeIU();
  397. // The drawing rectangle logical units
  398. wxRect drawingRect( wxPoint( 0, 0 ), corner );
  399. wxLogTrace( traceScrollSettings, wxT( "Logical drawing rect = ( %d, %d, %d, %d )." ),
  400. drawingRect.x, drawingRect.y, drawingRect.width, drawingRect.height );
  401. wxLogTrace( traceScrollSettings, wxT( " left %d, right %d, top %d, bottome %d" ),
  402. drawingRect.GetLeft(), drawingRect.GetRight(),
  403. drawingRect.GetTop(), drawingRect.GetBottom() );
  404. // The size of the client rectangle in logical units.
  405. int x = wxRound( (double) aCenterPosition.x - ( (double) logicalClientSize.x / 2.0 ) );
  406. int y = wxRound( (double) aCenterPosition.y - ( (double) logicalClientSize.y / 2.0 ) );
  407. // If drawn around the center, adjust the client rectangle accordingly.
  408. if( screen->m_Center )
  409. {
  410. x += wxRound( (double) drawingRect.width / 2.0 );
  411. y += wxRound( (double) drawingRect.height / 2.0 );
  412. }
  413. wxRect logicalClientRect( wxPoint( x, y ), logicalClientSize );
  414. wxLogTrace( traceScrollSettings, wxT( "Logical client rect = ( %d, %d, %d, %d )." ),
  415. logicalClientRect.x, logicalClientRect.y,
  416. logicalClientRect.width, logicalClientRect.height );
  417. wxLogTrace( traceScrollSettings, wxT( " left %d, right %d, top %d, bottome %d" ),
  418. logicalClientRect.GetLeft(), logicalClientRect.GetRight(),
  419. logicalClientRect.GetTop(), logicalClientRect.GetBottom() );
  420. if( drawingRect == logicalClientRect )
  421. {
  422. virtualSize = drawingRect.GetSize();
  423. }
  424. else if( drawingRect.Contains( logicalClientRect ) )
  425. {
  426. virtualSize = drawingRect.GetSize();
  427. }
  428. else
  429. {
  430. int drawingCenterX = drawingRect.x + ( drawingRect.width / 2 );
  431. int clientCenterX = logicalClientRect.x + ( logicalClientRect.width / 2 );
  432. int drawingCenterY = drawingRect.y + ( drawingRect.height / 2 );
  433. int clientCenterY = logicalClientRect.y + ( logicalClientRect.height / 2 );
  434. if( logicalClientRect.width > drawingRect.width )
  435. {
  436. if( drawingCenterX > clientCenterX )
  437. virtualSize.x = ( drawingCenterX - logicalClientRect.GetLeft() ) * 2;
  438. else if( drawingCenterX < clientCenterX )
  439. virtualSize.x = ( logicalClientRect.GetRight() - drawingCenterX ) * 2;
  440. else
  441. virtualSize.x = logicalClientRect.width;
  442. }
  443. else if( logicalClientRect.width < drawingRect.width )
  444. {
  445. if( drawingCenterX > clientCenterX )
  446. virtualSize.x = drawingRect.width +
  447. ( (drawingRect.GetLeft() - logicalClientRect.GetLeft() ) * 2 );
  448. else if( drawingCenterX < clientCenterX )
  449. virtualSize.x = drawingRect.width +
  450. ( (logicalClientRect.GetRight() - drawingRect.GetRight() ) * 2 );
  451. else
  452. virtualSize.x = drawingRect.width;
  453. }
  454. else
  455. {
  456. virtualSize.x = drawingRect.width;
  457. }
  458. if( logicalClientRect.height > drawingRect.height )
  459. {
  460. if( drawingCenterY > clientCenterY )
  461. virtualSize.y = ( drawingCenterY - logicalClientRect.GetTop() ) * 2;
  462. else if( drawingCenterY < clientCenterY )
  463. virtualSize.y = ( logicalClientRect.GetBottom() - drawingCenterY ) * 2;
  464. else
  465. virtualSize.y = logicalClientRect.height;
  466. }
  467. else if( logicalClientRect.height < drawingRect.height )
  468. {
  469. if( drawingCenterY > clientCenterY )
  470. virtualSize.y = drawingRect.height +
  471. ( ( drawingRect.GetTop() - logicalClientRect.GetTop() ) * 2 );
  472. else if( drawingCenterY < clientCenterY )
  473. virtualSize.y = drawingRect.height +
  474. ( ( logicalClientRect.GetBottom() - drawingRect.GetBottom() ) * 2 );
  475. else
  476. virtualSize.y = drawingRect.height;
  477. }
  478. else
  479. {
  480. virtualSize.y = drawingRect.height;
  481. }
  482. }
  483. if( screen->m_Center )
  484. {
  485. screen->m_DrawOrg.x = -( wxRound( (double) virtualSize.x / 2.0 ) );
  486. screen->m_DrawOrg.y = -( wxRound( (double) virtualSize.y / 2.0 ) );
  487. }
  488. else
  489. {
  490. screen->m_DrawOrg.x = -( wxRound( (double) (virtualSize.x - drawingRect.width) / 2.0 ) );
  491. screen->m_DrawOrg.y = -( wxRound( (double) (virtualSize.y - drawingRect.height) / 2.0 ) );
  492. }
  493. /* Always set scrollbar pixels per unit to 1 unless you want the zoom
  494. * around cursor to jump around. This reported problem occurs when the
  495. * zoom point is not on a pixel per unit increment. If you set the
  496. * pixels per unit to 10, you have potential for the zoom point to
  497. * jump around +/-5 pixels from the nearest grid point.
  498. */
  499. screen->m_ScrollPixelsPerUnitX = screen->m_ScrollPixelsPerUnitY = 1;
  500. // Calculate the number of scroll bar units for the given zoom level in device units.
  501. unitsX = wxRound( (double) virtualSize.x * scalar );
  502. unitsY = wxRound( (double) virtualSize.y * scalar );
  503. // Calculate the scroll bar position in logical units to place the center position at
  504. // the center of client rectangle.
  505. screen->SetScrollCenterPosition( aCenterPosition );
  506. posX = aCenterPosition.x - wxRound( (double) logicalClientRect.width / 2.0 ) -
  507. screen->m_DrawOrg.x;
  508. posY = aCenterPosition.y - wxRound( (double) logicalClientRect.height / 2.0 ) -
  509. screen->m_DrawOrg.y;
  510. // Convert scroll bar position to device units.
  511. posX = wxRound( (double) posX * scalar );
  512. posY = wxRound( (double) posY * scalar );
  513. if( posX < 0 )
  514. {
  515. wxLogTrace( traceScrollSettings, wxT( "Required scroll bar X position %d" ), posX );
  516. posX = 0;
  517. }
  518. if( posX > unitsX )
  519. {
  520. wxLogTrace( traceScrollSettings, wxT( "Required scroll bar X position %d" ), posX );
  521. posX = unitsX;
  522. }
  523. if( posY < 0 )
  524. {
  525. wxLogTrace( traceScrollSettings, wxT( "Required scroll bar Y position %d" ), posY );
  526. posY = 0;
  527. }
  528. if( posY > unitsY )
  529. {
  530. wxLogTrace( traceScrollSettings, wxT( "Required scroll bar Y position %d" ), posY );
  531. posY = unitsY;
  532. }
  533. screen->m_ScrollbarPos = wxPoint( posX, posY );
  534. screen->m_ScrollbarNumber = wxSize( unitsX, unitsY );
  535. wxLogTrace( traceScrollSettings,
  536. wxT( "Drawing = (%d, %d), Client = (%d, %d), Offset = (%d, %d), \
  537. SetScrollbars(%d, %d, %d, %d, %d, %d)" ),
  538. virtualSize.x, virtualSize.y, logicalClientSize.x, logicalClientSize.y,
  539. screen->m_DrawOrg.x, screen->m_DrawOrg.y,
  540. screen->m_ScrollPixelsPerUnitX, screen->m_ScrollPixelsPerUnitY,
  541. screen->m_ScrollbarNumber.x, screen->m_ScrollbarNumber.y,
  542. screen->m_ScrollbarPos.x, screen->m_ScrollbarPos.y );
  543. m_canvas->SetScrollbars( screen->m_ScrollPixelsPerUnitX,
  544. screen->m_ScrollPixelsPerUnitY,
  545. screen->m_ScrollbarNumber.x,
  546. screen->m_ScrollbarNumber.y,
  547. screen->m_ScrollbarPos.x,
  548. screen->m_ScrollbarPos.y, noRefresh );
  549. }
  550. void EDA_DRAW_FRAME::SetLanguage( wxCommandEvent& event )
  551. {
  552. EDA_BASE_FRAME::SetLanguage( event );
  553. }
  554. /**
  555. * Round to the nearest precision.
  556. *
  557. * Try to approximate a coordinate using a given precision to prevent
  558. * rounding errors when converting from inches to mm.
  559. *
  560. * ie round the unit value to 0 if unit is 1 or 2, or 8 or 9
  561. */
  562. double RoundTo0( double x, double precision )
  563. {
  564. assert( precision != 0 );
  565. long long ix = wxRound( x * precision );
  566. if ( x < 0.0 )
  567. NEGATE( ix );
  568. int remainder = ix % 10; // remainder is in precision mm
  569. if ( remainder <= 2 )
  570. ix -= remainder; // truncate to the near number
  571. else if (remainder >= 8 )
  572. ix += 10 - remainder; // round to near number
  573. if ( x < 0 )
  574. NEGATE( ix );
  575. return (double) ix / precision;
  576. }
  577. void EDA_DRAW_FRAME::UpdateStatusBar()
  578. {
  579. wxString Line;
  580. int dx, dy;
  581. BASE_SCREEN* screen = GetScreen();
  582. if( !screen )
  583. return;
  584. // Display Zoom level: zoom = zoom_coeff/ZoomScalar
  585. Line.Printf( wxT( "Z %g" ), screen->GetZoom() );
  586. SetStatusText( Line, 1 );
  587. // Display absolute coordinates:
  588. double dXpos = To_User_Unit( g_UserUnit, screen->GetCrossHairPosition().x, m_internalUnits );
  589. double dYpos = To_User_Unit( g_UserUnit, screen->GetCrossHairPosition().y, m_internalUnits );
  590. /*
  591. * Converting from inches to mm can give some coordinates due to
  592. * float point precision rounding errors, like 1.999 or 2.001 so
  593. * round to the nearest drawing precision required by the application.
  594. */
  595. if ( g_UserUnit == MILLIMETRES )
  596. {
  597. dXpos = RoundTo0( dXpos, (double)( m_internalUnits / 10 ) );
  598. dYpos = RoundTo0( dYpos, (double)( m_internalUnits / 10 ) );
  599. }
  600. // The following sadly is an if Eeschema/if Pcbnew
  601. wxString absformatter;
  602. wxString locformatter;
  603. switch( g_UserUnit )
  604. {
  605. case INCHES:
  606. if( m_internalUnits == EESCHEMA_INTERNAL_UNIT )
  607. {
  608. absformatter = wxT( "X %.3f Y %.3f" );
  609. locformatter = wxT( "dx %.3f dy %.3f" );
  610. }
  611. else
  612. {
  613. absformatter = wxT( "X %.4f Y %.4f" );
  614. locformatter = wxT( "dx %.4f dy %.4f" );
  615. }
  616. break;
  617. case MILLIMETRES:
  618. if( m_internalUnits == EESCHEMA_INTERNAL_UNIT )
  619. {
  620. absformatter = wxT( "X %.2f Y %.2f" );
  621. locformatter = wxT( "dx %.2f dy %.2f" );
  622. }
  623. else
  624. {
  625. absformatter = wxT( "X %.3f Y %.3f" );
  626. locformatter = wxT( "dx %.3f dy %.3f" );
  627. }
  628. break;
  629. case UNSCALED_UNITS:
  630. absformatter = wxT( "X %f Y %f" );
  631. locformatter = wxT( "dx %f dy %f" );
  632. break;
  633. }
  634. Line.Printf( absformatter, dXpos, dYpos );
  635. SetStatusText( Line, 2 );
  636. // Display relative coordinates:
  637. dx = screen->GetCrossHairPosition().x - screen->m_O_Curseur.x;
  638. dy = screen->GetCrossHairPosition().y - screen->m_O_Curseur.y;
  639. dXpos = To_User_Unit( g_UserUnit, dx, m_internalUnits );
  640. dYpos = To_User_Unit( g_UserUnit, dy, m_internalUnits );
  641. if( g_UserUnit == MILLIMETRES )
  642. {
  643. dXpos = RoundTo0( dXpos, (double) ( m_internalUnits / 10 ) );
  644. dYpos = RoundTo0( dYpos, (double) ( m_internalUnits / 10 ) );
  645. }
  646. // We already decided the formatter above
  647. Line.Printf( locformatter, dXpos, dYpos );
  648. SetStatusText( Line, 3 );
  649. }
  650. void EDA_DRAW_FRAME::LoadSettings()
  651. {
  652. wxASSERT( wxGetApp().GetSettings() != NULL );
  653. wxConfig* cfg = wxGetApp().GetSettings();
  654. EDA_BASE_FRAME::LoadSettings();
  655. cfg->Read( m_FrameName + CursorShapeEntryKeyword, &m_cursorShape, ( long )0 );
  656. bool btmp;
  657. if ( cfg->Read( m_FrameName + ShowGridEntryKeyword, &btmp ) )
  658. SetGridVisibility( btmp );
  659. int itmp;
  660. if( cfg->Read( m_FrameName + GridColorEntryKeyword, &itmp ) )
  661. SetGridColor( itmp );
  662. cfg->Read( m_FrameName + LastGridSizeId, &m_LastGridSizeId, 0L );
  663. }
  664. void EDA_DRAW_FRAME::SaveSettings()
  665. {
  666. wxASSERT( wxGetApp().GetSettings() != NULL );
  667. wxConfig* cfg = wxGetApp().GetSettings();
  668. EDA_BASE_FRAME::SaveSettings();
  669. cfg->Write( m_FrameName + CursorShapeEntryKeyword, m_cursorShape );
  670. cfg->Write( m_FrameName + ShowGridEntryKeyword, IsGridVisible() );
  671. cfg->Write( m_FrameName + GridColorEntryKeyword, GetGridColor() );
  672. cfg->Write( m_FrameName + LastGridSizeId, ( long ) m_LastGridSizeId );
  673. }
  674. void EDA_DRAW_FRAME::AppendMsgPanel( const wxString& textUpper,
  675. const wxString& textLower,
  676. int color, int pad )
  677. {
  678. if( m_messagePanel == NULL )
  679. return;
  680. m_messagePanel->AppendMessage( textUpper, textLower, color, pad );
  681. }
  682. void EDA_DRAW_FRAME::ClearMsgPanel( void )
  683. {
  684. if( m_messagePanel == NULL )
  685. return;
  686. m_messagePanel->EraseMsgBox();
  687. }
  688. wxString EDA_DRAW_FRAME::CoordinateToString( int aValue, bool aConvertToMils )
  689. {
  690. return ::CoordinateToString( aValue, m_internalUnits, aConvertToMils );
  691. }