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.

537 lines
15 KiB

Modular-Kicad milestone B), major portions: *) Rework the set language support, simplify it by using KIWAY. Now any major frame with a "change language" menu can change the language for all KIWAY_PLAYERs in the whole KIWAY. Multiple KIWAYs are not supported yet. *) Simplify "modal wxFrame" support, and add that support exclusively to KIWAY_PLAYER where it is inherited by all derivatives. The function KIWAY_PLAYER::ShowModal() is in the vtable and so is cross module capable. *) Remove the requirements and assumptions that the wxFrame hierarchy always had PCB_EDIT_FRAME and SCH_EDIT_FRAME as immediate parents of their viewers and editors. This is no longer the case, nor required. *) Use KIWAY::Player() everywhere to make KIWAY_PLAYERs, this registers the KIWAY_PLAYER within the KIWAY and makes it very easy to find an open frame quickly. It also gives control to the KIWAY as to frame hierarchical relationships. *) Change single_top to use the KIWAY for loading a KIFACE and instantiating the single KIWAY_PLAYER, see bullet immediately above. *) Add KIWAY::OnKiwayEnd() and call it from PGM_BASE at program termination, this gives the KIFACEs a chance to save their final configuration dope to disk. *) Add dedicated FRAME_T's for the modal frames, so m_Ident can be tested and these modal frames are distinctly different than their non-modal equivalents. KIWAY_PLAYER::IsModal() is !not! a valid test during the wxFrame's constructor, so this is another important reason for having a dedicated FRAME_T for each modal wxFrame. On balance, more lines were deleted than were added to achieve all this.
12 years ago
  1. /*
  2. * This program source code file is part of KiCad, a free EDA CAD application.
  3. *
  4. * Copyright (C) 2012 SoftPLC Corporation, Dick Hollenbeck <dick@softplc.com>
  5. * Copyright (C) 2015-2020 KiCad Developers, see change_log.txt for contributors.
  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 <base_units.h>
  25. #include <kiway.h>
  26. #include <pgm_base.h>
  27. #include <eeschema_settings.h>
  28. #include <sch_draw_panel.h>
  29. #include <sch_view.h>
  30. #include <sch_painter.h>
  31. #include <settings/settings_manager.h>
  32. #include <gal/graphics_abstraction_layer.h>
  33. #include <confirm.h>
  34. #include <preview_items/selection_area.h>
  35. #include <class_library.h>
  36. #include <sch_base_frame.h>
  37. #include <symbol_lib_table.h>
  38. #include <tool/action_toolbar.h>
  39. #include <tool/tool_manager.h>
  40. #include <tool/tool_dispatcher.h>
  41. #include <tools/ee_actions.h>
  42. #include <tools/ee_selection_tool.h>
  43. #include <default_values.h> // For some default values
  44. LIB_PART* SchGetLibPart( const LIB_ID& aLibId, SYMBOL_LIB_TABLE* aLibTable, PART_LIB* aCacheLib,
  45. wxWindow* aParent, bool aShowErrorMsg )
  46. {
  47. wxCHECK_MSG( aLibTable, nullptr, "Invalid symbol library table." );
  48. LIB_PART* symbol = nullptr;
  49. try
  50. {
  51. symbol = aLibTable->LoadSymbol( aLibId );
  52. if( !symbol && aCacheLib )
  53. {
  54. wxCHECK_MSG( aCacheLib->IsCache(), nullptr, "Invalid cache library." );
  55. wxString cacheName = aLibId.GetLibNickname().wx_str();
  56. cacheName += "_" + aLibId.GetLibItemName();
  57. symbol = aCacheLib->FindPart( cacheName );
  58. }
  59. }
  60. catch( const IO_ERROR& ioe )
  61. {
  62. if( aShowErrorMsg )
  63. {
  64. wxString msg = wxString::Format( _( "Error loading symbol '%s' from library '%s'." ),
  65. aLibId.GetLibItemName().wx_str(),
  66. aLibId.GetLibNickname().wx_str() );
  67. DisplayErrorMessage( aParent, msg, ioe.What() );
  68. }
  69. }
  70. return symbol;
  71. }
  72. SCH_BASE_FRAME::SCH_BASE_FRAME( KIWAY* aKiway, wxWindow* aParent, FRAME_T aWindowType,
  73. const wxString& aTitle, const wxPoint& aPosition,
  74. const wxSize& aSize, long aStyle, const wxString& aFrameName ) :
  75. EDA_DRAW_FRAME( aKiway, aParent, aWindowType, aTitle, aPosition, aSize, aStyle, aFrameName ),
  76. m_defaultLineWidth( DEFAULT_LINE_THICKNESS * IU_PER_MILS ),
  77. m_defaultWireThickness( DEFAULT_WIRE_THICKNESS * IU_PER_MILS ),
  78. m_defaultBusThickness( DEFAULT_BUS_THICKNESS * IU_PER_MILS ),
  79. m_defaultTextSize( DEFAULT_TEXT_SIZE * IU_PER_MILS ),
  80. m_textOffsetRatio( 0.08 ),
  81. m_pinSymbolSize( DEFAULT_TEXT_SIZE * IU_PER_MILS / 2 ),
  82. m_showPinElectricalTypeName( false )
  83. {
  84. createCanvas();
  85. // Adjusted to display zoom level ~ 1 when the screen shows a 1:1 image
  86. // Obviously depends on the monitor, but this is an acceptable value
  87. m_zoomLevelCoeff = 11.0 * IU_PER_MILS;
  88. }
  89. SCH_BASE_FRAME::~SCH_BASE_FRAME()
  90. {
  91. }
  92. SCH_SCREEN* SCH_BASE_FRAME::GetScreen() const
  93. {
  94. return (SCH_SCREEN*) EDA_DRAW_FRAME::GetScreen();
  95. }
  96. void SCH_BASE_FRAME::SetScreen( BASE_SCREEN* aScreen )
  97. {
  98. EDA_DRAW_FRAME::SetScreen( aScreen );
  99. if( m_toolManager )
  100. {
  101. m_toolManager->SetEnvironment( aScreen, GetCanvas()->GetView(),
  102. GetCanvas()->GetViewControls(), this );
  103. }
  104. }
  105. const wxString SCH_BASE_FRAME::GetZoomLevelIndicator() const
  106. {
  107. return EDA_DRAW_FRAME::GetZoomLevelIndicator();
  108. }
  109. void SCH_BASE_FRAME::SetDefaultLineWidth( int aWidth )
  110. {
  111. m_defaultLineWidth = aWidth;
  112. GetRenderSettings()->SetDefaultPenWidth( aWidth );
  113. }
  114. void SCH_BASE_FRAME::SetDefaultWireThickness( int aThickness )
  115. {
  116. m_defaultWireThickness = aThickness;
  117. GetRenderSettings()->m_DefaultWireThickness = aThickness;
  118. }
  119. void SCH_BASE_FRAME::SetDefaultBusThickness( int aThickness )
  120. {
  121. m_defaultBusThickness = aThickness;
  122. GetRenderSettings()->m_DefaultBusThickness = aThickness;
  123. }
  124. void SCH_BASE_FRAME::SetPinSymbolSize( int aSize )
  125. {
  126. m_pinSymbolSize = aSize;
  127. GetRenderSettings()->m_PinSymbolSize = aSize;
  128. }
  129. void SCH_BASE_FRAME::SetPageSettings( const PAGE_INFO& aPageSettings )
  130. {
  131. GetScreen()->SetPageSettings( aPageSettings );
  132. }
  133. const PAGE_INFO& SCH_BASE_FRAME::GetPageSettings () const
  134. {
  135. return GetScreen()->GetPageSettings();
  136. }
  137. const wxSize SCH_BASE_FRAME::GetPageSizeIU() const
  138. {
  139. // GetSizeIU is compile time dependent:
  140. return GetScreen()->GetPageSettings().GetSizeIU();
  141. }
  142. const wxPoint& SCH_BASE_FRAME::GetAuxOrigin() const
  143. {
  144. wxASSERT( GetScreen() );
  145. return GetScreen()->GetAuxOrigin();
  146. }
  147. void SCH_BASE_FRAME::SetAuxOrigin( const wxPoint& aPosition )
  148. {
  149. wxASSERT( GetScreen() );
  150. GetScreen()->SetAuxOrigin( aPosition );
  151. }
  152. const TITLE_BLOCK& SCH_BASE_FRAME::GetTitleBlock() const
  153. {
  154. wxASSERT( GetScreen() );
  155. return GetScreen()->GetTitleBlock();
  156. }
  157. void SCH_BASE_FRAME::SetTitleBlock( const TITLE_BLOCK& aTitleBlock )
  158. {
  159. wxASSERT( GetScreen() );
  160. GetScreen()->SetTitleBlock( aTitleBlock );
  161. }
  162. void SCH_BASE_FRAME::UpdateStatusBar()
  163. {
  164. wxString line;
  165. BASE_SCREEN* screen = GetScreen();
  166. if( !screen )
  167. return;
  168. EDA_DRAW_FRAME::UpdateStatusBar();
  169. // Display absolute coordinates:
  170. VECTOR2D cursorPos = GetCanvas()->GetViewControls()->GetCursorPosition();
  171. double dXpos = To_User_Unit( GetUserUnits(), cursorPos.x );
  172. double dYpos = To_User_Unit( GetUserUnits(), cursorPos.y );
  173. wxString absformatter;
  174. wxString locformatter;
  175. switch( GetUserUnits() )
  176. {
  177. case EDA_UNITS::INCHES:
  178. absformatter = "X %.3f Y %.3f";
  179. locformatter = "dx %.3f dy %.3f dist %.3f";
  180. break;
  181. case EDA_UNITS::MILLIMETRES:
  182. absformatter = "X %.4f Y %.4f";
  183. locformatter = "dx %.4f dy %.4f dist %.4f";
  184. break;
  185. case EDA_UNITS::UNSCALED:
  186. absformatter = "X %f Y %f";
  187. locformatter = "dx %f dy %f dist %f";
  188. break;
  189. default:
  190. wxASSERT( false );
  191. break;
  192. }
  193. line.Printf( absformatter, dXpos, dYpos );
  194. SetStatusText( line, 2 );
  195. // Display relative coordinates:
  196. double dx = cursorPos.x - screen->m_LocalOrigin.x;
  197. double dy = cursorPos.y - screen->m_LocalOrigin.y;
  198. dXpos = To_User_Unit( GetUserUnits(), dx );
  199. dYpos = To_User_Unit( GetUserUnits(), dy );
  200. // We already decided the formatter above
  201. line.Printf( locformatter, dXpos, dYpos, hypot( dXpos, dYpos ) );
  202. SetStatusText( line, 3 );
  203. // refresh grid display
  204. DisplayGridMsg();
  205. // refresh units display
  206. DisplayUnitsMsg();
  207. }
  208. LIB_PART* SCH_BASE_FRAME::GetLibPart( const LIB_ID& aLibId, bool aUseCacheLib, bool aShowErrorMsg )
  209. {
  210. PART_LIB* cache = ( aUseCacheLib ) ? Prj().SchLibs()->GetCacheLibrary() : NULL;
  211. return SchGetLibPart( aLibId, Prj().SchSymbolLibTable(), cache, this, aShowErrorMsg );
  212. }
  213. bool SCH_BASE_FRAME::saveSymbolLibTables( bool aGlobal, bool aProject )
  214. {
  215. wxString msg;
  216. bool success = true;
  217. if( aGlobal )
  218. {
  219. try
  220. {
  221. SYMBOL_LIB_TABLE::GetGlobalLibTable().Save( SYMBOL_LIB_TABLE::GetGlobalTableFileName() );
  222. }
  223. catch( const IO_ERROR& ioe )
  224. {
  225. success = false;
  226. msg.Printf( _( "Error saving global symbol library table:\n%s" ), ioe.What() );
  227. wxMessageBox( msg, _( "File Save Error" ), wxOK | wxICON_ERROR );
  228. }
  229. }
  230. if( aProject && !Prj().GetProjectName().IsEmpty() )
  231. {
  232. wxFileName fn( Prj().GetProjectPath(), SYMBOL_LIB_TABLE::GetSymbolLibTableFileName() );
  233. try
  234. {
  235. Prj().SchSymbolLibTable()->Save( fn.GetFullPath() );
  236. }
  237. catch( const IO_ERROR& ioe )
  238. {
  239. success = false;
  240. msg.Printf( _( "Error saving project-specific symbol library table:\n%s" ), ioe.What() );
  241. wxMessageBox( msg, _( "File Save Error" ), wxOK | wxICON_ERROR );
  242. }
  243. }
  244. return success;
  245. }
  246. void SCH_BASE_FRAME::RedrawScreen( const wxPoint& aCenterPoint, bool aWarpPointer )
  247. {
  248. KIGFX::GAL* gal = GetCanvas()->GetGAL();
  249. double selectedZoom = GetScreen()->GetZoom();
  250. double zoomFactor = gal->GetWorldScale() / gal->GetZoomFactor();
  251. double scale = 1.0 / ( zoomFactor * selectedZoom );
  252. if( aCenterPoint != wxPoint( 0, 0 ) )
  253. GetCanvas()->GetView()->SetScale( scale, aCenterPoint );
  254. else
  255. GetCanvas()->GetView()->SetScale( scale );
  256. GetCanvas()->GetView()->SetCenter( aCenterPoint );
  257. if( aWarpPointer )
  258. GetCanvas()->GetViewControls()->CenterOnCursor();
  259. GetCanvas()->Refresh();
  260. }
  261. void SCH_BASE_FRAME::CenterScreen( const wxPoint& aCenterPoint, bool aWarpPointer )
  262. {
  263. GetCanvas()->GetView()->SetCenter( aCenterPoint );
  264. if( aWarpPointer )
  265. GetCanvas()->GetViewControls()->WarpCursor( aCenterPoint, true );
  266. GetCanvas()->Refresh();
  267. }
  268. void SCH_BASE_FRAME::FocusOnItem( SCH_ITEM* aItem )
  269. {
  270. static KIID lastBrightenedItemID( niluuid );
  271. SCH_SHEET_LIST sheetList( g_RootSheet );
  272. SCH_SHEET_PATH dummy;
  273. SCH_ITEM* lastItem = sheetList.GetItem( lastBrightenedItemID, &dummy );
  274. if( lastItem && lastItem != aItem )
  275. {
  276. lastItem->ClearBrightened();
  277. RefreshItem( lastItem );
  278. lastBrightenedItemID = niluuid;
  279. }
  280. if( aItem )
  281. {
  282. aItem->SetBrightened();
  283. RefreshItem( aItem );
  284. lastBrightenedItemID = aItem->m_Uuid;
  285. // JEY TODO: test this with pins and fields (and with rotated symbols) ....
  286. FocusOnLocation( aItem->GetFocusPosition() );
  287. }
  288. }
  289. void SCH_BASE_FRAME::HardRedraw()
  290. {
  291. GetCanvas()->GetView()->UpdateAllItems( KIGFX::ALL );
  292. GetCanvas()->ForceRefresh();
  293. }
  294. SCH_DRAW_PANEL* SCH_BASE_FRAME::GetCanvas() const
  295. {
  296. return static_cast<SCH_DRAW_PANEL*>( EDA_DRAW_FRAME::GetCanvas() );
  297. }
  298. KIGFX::SCH_RENDER_SETTINGS* SCH_BASE_FRAME::GetRenderSettings()
  299. {
  300. KIGFX::PAINTER* painter = GetCanvas()->GetView()->GetPainter();
  301. return static_cast<KIGFX::SCH_RENDER_SETTINGS*>( painter->GetSettings() );
  302. }
  303. void SCH_BASE_FRAME::createCanvas()
  304. {
  305. m_canvasType = LoadCanvasTypeSetting();
  306. // Allows only a CAIRO or OPENGL canvas:
  307. if( m_canvasType != EDA_DRAW_PANEL_GAL::GAL_TYPE_OPENGL
  308. && m_canvasType != EDA_DRAW_PANEL_GAL::GAL_TYPE_CAIRO )
  309. {
  310. m_canvasType = EDA_DRAW_PANEL_GAL::GAL_TYPE_OPENGL;
  311. }
  312. SetCanvas( new SCH_DRAW_PANEL( this, wxID_ANY, wxPoint( 0, 0 ), m_FrameSize,
  313. GetGalDisplayOptions(), m_canvasType ));
  314. ActivateGalCanvas();
  315. }
  316. void SCH_BASE_FRAME::RefreshItem( EDA_ITEM* aItem, bool isAddOrDelete )
  317. {
  318. EDA_ITEM* parent = aItem->GetParent();
  319. if( aItem->Type() == SCH_SHEET_PIN_T )
  320. {
  321. // Sheet pins aren't in the view. Refresh their parent.
  322. if( parent )
  323. GetCanvas()->GetView()->Update( parent );
  324. }
  325. else
  326. {
  327. if( !isAddOrDelete )
  328. GetCanvas()->GetView()->Update( aItem );
  329. // Component children are drawn from their parents. Mark them for re-paint.
  330. if( parent && parent->Type() == SCH_COMPONENT_T )
  331. GetCanvas()->GetView()->Update( parent, KIGFX::REPAINT );
  332. else if( parent && parent->Type() == SCH_SHEET_T )
  333. GetCanvas()->GetView()->Update( parent, KIGFX::REPAINT );
  334. }
  335. GetCanvas()->Refresh();
  336. }
  337. void SCH_BASE_FRAME::RefreshSelection()
  338. {
  339. if( m_toolManager )
  340. {
  341. EE_SELECTION_TOOL* selectionTool = m_toolManager->GetTool<EE_SELECTION_TOOL>();
  342. SELECTION& selection = selectionTool->GetSelection();
  343. KIGFX::SCH_VIEW* view = GetCanvas()->GetView();
  344. for( EDA_ITEM* item : selection )
  345. {
  346. EDA_ITEM* parent = item->GetParent();
  347. if( item->Type() == SCH_SHEET_PIN_T )
  348. {
  349. // Sheet pins aren't in the view. Refresh their parent.
  350. if( parent )
  351. GetCanvas()->GetView()->Update( parent );
  352. }
  353. else
  354. {
  355. view->Update( item, KIGFX::REPAINT );
  356. // Component children are drawn from their parents. Mark them for re-paint.
  357. if( parent && parent->Type() == SCH_COMPONENT_T )
  358. GetCanvas()->GetView()->Update( parent, KIGFX::REPAINT );
  359. }
  360. }
  361. }
  362. }
  363. void SCH_BASE_FRAME::AddToScreen( EDA_ITEM* aItem, SCH_SCREEN* aScreen )
  364. {
  365. auto screen = aScreen;
  366. if( aScreen == nullptr )
  367. screen = GetScreen();
  368. screen->Append( (SCH_ITEM*) aItem );
  369. if( screen == GetScreen() )
  370. {
  371. GetCanvas()->GetView()->Add( aItem );
  372. RefreshItem( aItem, true ); // handle any additional parent semantics
  373. }
  374. }
  375. void SCH_BASE_FRAME::RemoveFromScreen( EDA_ITEM* aItem, SCH_SCREEN* aScreen )
  376. {
  377. auto screen = aScreen;
  378. if( aScreen == nullptr )
  379. screen = GetScreen();
  380. if( screen == GetScreen() )
  381. GetCanvas()->GetView()->Remove( aItem );
  382. screen->Remove( (SCH_ITEM*) aItem );
  383. if( screen == GetScreen() )
  384. RefreshItem( aItem, true ); // handle any additional parent semantics
  385. }
  386. void SCH_BASE_FRAME::SyncView()
  387. {
  388. auto gs = GetScreen()->GetGridSize();
  389. GetCanvas()->GetGAL()->SetGridSize( VECTOR2D( gs.x, gs.y ));
  390. GetCanvas()->GetView()->UpdateAllItems( KIGFX::ALL );
  391. }
  392. COLOR4D SCH_BASE_FRAME::GetLayerColor( SCH_LAYER_ID aLayer )
  393. {
  394. return GetColorSettings()->GetColor( aLayer );
  395. }
  396. void SCH_BASE_FRAME::CommonSettingsChanged( bool aEnvVarsChanged )
  397. {
  398. EDA_DRAW_FRAME::CommonSettingsChanged( aEnvVarsChanged );
  399. EESCHEMA_SETTINGS* cfg = Pgm().GetSettingsManager().GetAppSettings<EESCHEMA_SETTINGS>();
  400. m_colorSettings = Pgm().GetSettingsManager().GetColorSettings( cfg->m_ColorTheme );
  401. }
  402. COLOR_SETTINGS* SCH_BASE_FRAME::GetColorSettings()
  403. {
  404. if( !m_colorSettings )
  405. {
  406. EESCHEMA_SETTINGS* cfg = Pgm().GetSettingsManager().GetAppSettings<EESCHEMA_SETTINGS>();
  407. m_colorSettings = Pgm().GetSettingsManager().GetColorSettings( cfg->m_ColorTheme );
  408. }
  409. return m_colorSettings;
  410. }