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.

612 lines
22 KiB

  1. /*
  2. * This program source code file is part of KiCad, a free EDA CAD application.
  3. *
  4. * Copyright (C) 1992-2018 Jean-Pierre Charras jp.charras at wanadoo.fr
  5. * Copyright (C) 1992-2010 Lorenzo Marcantonio
  6. * Copyright (C) 2011 Wayne Stambaugh <stambaughw@gmail.com>
  7. * Copyright (C) 1992-2023 KiCad Developers, see AUTHORS.txt for contributors.
  8. *
  9. * This program is free software; you can redistribute it and/or
  10. * modify it under the terms of the GNU General Public License
  11. * as published by the Free Software Foundation; either version 2
  12. * of the License, or (at your option) any later version.
  13. *
  14. * This program is distributed in the hope that it will be useful,
  15. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  17. * GNU General Public License for more details.
  18. *
  19. * You should have received a copy of the GNU General Public License
  20. * along with this program; if not, you may find one here:
  21. * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
  22. * or you may search the http://www.gnu.org website for the version 2 license,
  23. * or you may write to the Free Software Foundation, Inc.,
  24. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
  25. */
  26. #include <bitmaps.h>
  27. #include <common.h> // For ExpandEnvVarSubstitutions
  28. #include "widgets/wx_html_report_panel.h"
  29. #include <widgets/std_bitmap_button.h>
  30. #include <dialog_plot_schematic.h>
  31. #include <eeschema_settings.h>
  32. #include <kiface_base.h>
  33. #include <locale_io.h>
  34. #include <plotters/plotter_hpgl.h>
  35. #include <plotters/plotter_dxf.h>
  36. #include <plotters/plotters_pslike.h>
  37. #include <reporter.h>
  38. #include <trace_helpers.h>
  39. #include <settings/settings_manager.h>
  40. #include <drawing_sheet/ds_painter.h>
  41. #include <wx_filename.h>
  42. #include <pgm_base.h>
  43. #include <sch_edit_frame.h>
  44. #include <sch_painter.h>
  45. #include <schematic.h>
  46. #include <sch_screen.h>
  47. #include <wx/dirdlg.h>
  48. #include <wx/msgdlg.h>
  49. #include <kiplatform/environment.h>
  50. #include <wx/log.h>
  51. #include <jobs/job_export_sch_plot.h>
  52. // static members (static to remember last state):
  53. int DIALOG_PLOT_SCHEMATIC::m_pageSizeSelect = PAGE_SIZE_AUTO;
  54. HPGL_PAGE_SIZE DIALOG_PLOT_SCHEMATIC::m_HPGLPaperSizeSelect = HPGL_PAGE_SIZE::DEFAULT;
  55. DIALOG_PLOT_SCHEMATIC::DIALOG_PLOT_SCHEMATIC( SCH_EDIT_FRAME* aEditFrame ) :
  56. DIALOG_PLOT_SCHEMATIC( aEditFrame, aEditFrame )
  57. {
  58. }
  59. DIALOG_PLOT_SCHEMATIC::DIALOG_PLOT_SCHEMATIC( SCH_EDIT_FRAME* aEditFrame, wxWindow* aParent,
  60. JOB_EXPORT_SCH_PLOT* aJob )
  61. : DIALOG_PLOT_SCHEMATIC_BASE( aEditFrame ),
  62. m_editFrame( aEditFrame ),
  63. m_plotFormat( PLOT_FORMAT::UNDEFINED ),
  64. m_HPGLPenSize( 1.0 ),
  65. m_defaultLineWidth( aEditFrame, m_lineWidthLabel, m_lineWidthCtrl, m_lineWidthUnits ),
  66. m_penWidth( aEditFrame, m_penWidthLabel, m_penWidthCtrl, m_penWidthUnits ), m_job( aJob )
  67. {
  68. m_configChanged = false;
  69. if( !m_job )
  70. {
  71. m_browseButton->SetBitmap( KiBitmapBundle( BITMAPS::small_folder ) );
  72. m_MessagesBox->SetFileName( Prj().GetProjectPath() + wxT( "report.txt" ) );
  73. SetupStandardButtons( { { wxID_OK, _( "Plot All Pages" ) },
  74. { wxID_APPLY, _( "Plot Current Page" ) },
  75. { wxID_CANCEL, _( "Close" ) } } );
  76. }
  77. else
  78. {
  79. m_browseButton->Hide();
  80. m_MessagesBox->Hide();
  81. m_sdbSizer1Apply->Hide();
  82. m_openFileAfterPlot->Hide();
  83. SetupStandardButtons( { { wxID_OK, _( "Save" ) },
  84. { wxID_CANCEL, _( "Close" ) } } );
  85. }
  86. initDlg();
  87. // Now all widgets have the size fixed, call FinishDialogSettings
  88. finishDialogSettings();
  89. }
  90. void DIALOG_PLOT_SCHEMATIC::initDlg()
  91. {
  92. auto cfg = dynamic_cast<EESCHEMA_SETTINGS*>( Kiface().KifaceSettings() );
  93. wxASSERT( cfg );
  94. if( !m_job )
  95. {
  96. if( cfg )
  97. {
  98. for( COLOR_SETTINGS* settings : Pgm().GetSettingsManager().GetColorSettingsList() )
  99. {
  100. int idx =
  101. m_colorTheme->Append( settings->GetName(), static_cast<void*>( settings ) );
  102. if( settings->GetFilename() == cfg->m_PlotPanel.color_theme )
  103. m_colorTheme->SetSelection( idx );
  104. }
  105. m_colorTheme->Enable( cfg->m_PlotPanel.color );
  106. m_plotBackgroundColor->Enable( cfg->m_PlotPanel.color );
  107. m_plotBackgroundColor->SetValue( cfg->m_PlotPanel.background_color );
  108. // Set color or B&W plot option
  109. setModeColor( cfg->m_PlotPanel.color );
  110. // Set plot or not frame reference option
  111. setPlotDrawingSheet( cfg->m_PlotPanel.frame_reference );
  112. setOpenFileAfterPlot( cfg->m_PlotPanel.open_file_after_plot );
  113. m_plotPDFPropertyPopups->SetValue( cfg->m_PlotPanel.pdf_property_popups );
  114. m_plotPDFHierarchicalLinks->SetValue( cfg->m_PlotPanel.pdf_hierarchical_links );
  115. m_plotPDFMetadata->SetValue( cfg->m_PlotPanel.pdf_metadata );
  116. // HPGL plot origin and unit system configuration
  117. m_plotOriginOpt->SetSelection( cfg->m_PlotPanel.hpgl_origin );
  118. m_HPGLPaperSizeSelect = static_cast<HPGL_PAGE_SIZE>( cfg->m_PlotPanel.hpgl_paper_size );
  119. // HPGL Pen Size is stored in mm in config
  120. m_HPGLPenSize = cfg->m_PlotPanel.hpgl_pen_size * schIUScale.IU_PER_MM;
  121. // Switch to the last save plot format
  122. PLOT_FORMAT fmt = static_cast<PLOT_FORMAT>( cfg->m_PlotPanel.format );
  123. switch( fmt )
  124. {
  125. default:
  126. case PLOT_FORMAT::POST: m_plotFormatOpt->SetSelection( 0 ); break;
  127. case PLOT_FORMAT::PDF: m_plotFormatOpt->SetSelection( 1 ); break;
  128. case PLOT_FORMAT::SVG: m_plotFormatOpt->SetSelection( 2 ); break;
  129. case PLOT_FORMAT::DXF: m_plotFormatOpt->SetSelection( 3 ); break;
  130. case PLOT_FORMAT::HPGL: m_plotFormatOpt->SetSelection( 4 ); break;
  131. }
  132. if( fmt == PLOT_FORMAT::DXF || fmt == PLOT_FORMAT::HPGL )
  133. m_plotBackgroundColor->Disable();
  134. // Set the default line width (pen width which should be used for
  135. // items that do not have a pen size defined (like frame ref)
  136. // the default line width is stored in mils in config
  137. m_defaultLineWidth.SetValue( schIUScale.MilsToIU( cfg->m_Drawing.default_line_thickness ) );
  138. }
  139. // Initialize HPGL specific widgets
  140. m_penWidth.SetValue( m_HPGLPenSize );
  141. // Plot directory
  142. SCHEMATIC_SETTINGS& settings = m_editFrame->Schematic().Settings();
  143. wxString path = settings.m_PlotDirectoryName;
  144. #ifdef __WINDOWS__
  145. path.Replace( '/', '\\' );
  146. #endif
  147. m_outputDirectoryName->SetValue( path );
  148. }
  149. else if( m_job )
  150. {
  151. for( COLOR_SETTINGS* settings : Pgm().GetSettingsManager().GetColorSettingsList() )
  152. {
  153. int idx = m_colorTheme->Append( settings->GetName(), static_cast<void*>( settings ) );
  154. if( settings->GetName() == m_job->m_theme )
  155. m_colorTheme->SetSelection( idx );
  156. }
  157. if( m_colorTheme->GetSelection() == wxNOT_FOUND )
  158. m_colorTheme->SetSelection( 0 );
  159. m_plotBackgroundColor->SetValue( m_job->m_useBackgroundColor );
  160. m_penWidth.SetValue( m_job->m_HPGLPenSize );
  161. m_HPGLPaperSizeSelect = static_cast<HPGL_PAGE_SIZE>( m_job->m_HPGLPaperSizeSelect );
  162. m_plotPDFPropertyPopups->SetValue( m_job->m_PDFPropertyPopups );
  163. m_plotPDFHierarchicalLinks->SetValue( m_job->m_PDFHierarchicalLinks );
  164. m_plotPDFMetadata->SetValue( m_job->m_PDFMetadata );
  165. m_colorTheme->Enable( m_job->m_plotFormat != SCH_PLOT_FORMAT::HPGL );
  166. m_ModeColorOption->Enable( m_job->m_plotFormat != SCH_PLOT_FORMAT::HPGL );
  167. m_plotOriginOpt->SetSelection( static_cast<int>( m_job->m_HPGLPlotOrigin ) );
  168. m_pageSizeSelect = static_cast<int>( m_job->m_pageSizeSelect );
  169. m_plotDrawingSheet->SetValue( m_job->m_plotDrawingSheet );
  170. setModeColor( !m_job->m_blackAndWhite );
  171. // Set the plot format
  172. switch( m_job->m_plotFormat )
  173. {
  174. default:
  175. case SCH_PLOT_FORMAT::POST: m_plotFormatOpt->SetSelection( 0 ); break;
  176. case SCH_PLOT_FORMAT::PDF: m_plotFormatOpt->SetSelection( 1 ); break;
  177. case SCH_PLOT_FORMAT::SVG: m_plotFormatOpt->SetSelection( 2 ); break;
  178. case SCH_PLOT_FORMAT::DXF: m_plotFormatOpt->SetSelection( 3 ); break;
  179. case SCH_PLOT_FORMAT::HPGL: m_plotFormatOpt->SetSelection( 4 ); break;
  180. }
  181. // And then hide it
  182. m_plotFormatOpt->Hide();
  183. m_outputDirectoryName->SetValue( m_job->GetOutputPath() );
  184. }
  185. }
  186. /**
  187. * @todo Copy of DIALOG_PLOT::OnOutputDirectoryBrowseClicked in dialog_plot.cpp, maybe merge to
  188. * a common method.
  189. */
  190. void DIALOG_PLOT_SCHEMATIC::OnOutputDirectoryBrowseClicked( wxCommandEvent& event )
  191. {
  192. // Build the absolute path of current output directory to preselect it in the file browser.
  193. wxString path = ExpandEnvVarSubstitutions( m_outputDirectoryName->GetValue(), &Prj() );
  194. // When editing a schematic that is not part of a project in the stand alone mode, the
  195. // project path is not defined so point to the users document path to save the plot files.
  196. if( Prj().IsNullProject() )
  197. {
  198. path = KIPLATFORM::ENV::GetDocumentsPath();
  199. }
  200. else
  201. {
  202. // Build the absolute path of current output directory to preselect it in the file browser.
  203. path = ExpandEnvVarSubstitutions( m_outputDirectoryName->GetValue(), &Prj() );
  204. path = Prj().AbsolutePath( path );
  205. }
  206. wxDirDialog dirDialog( this, _( "Select Output Directory" ), path );
  207. if( dirDialog.ShowModal() == wxID_CANCEL )
  208. return;
  209. wxFileName dirName = wxFileName::DirName( dirDialog.GetPath() );
  210. wxFileName fn( Prj().AbsolutePath( m_editFrame->Schematic().Root().GetFileName() ) );
  211. wxString defaultPath = fn.GetPathWithSep();
  212. wxString msg;
  213. wxFileName relPathTest; // Used to test if we can make the path relative
  214. relPathTest.Assign( dirDialog.GetPath() );
  215. // Test if making the path relative is possible before asking the user if they want to do it
  216. if( relPathTest.MakeRelativeTo( defaultPath ) )
  217. {
  218. msg.Printf( _( "Do you want to use a path relative to\n'%s'?" ), defaultPath );
  219. wxMessageDialog dialog( this, msg, _( "Plot Output Directory" ),
  220. wxYES_NO | wxICON_QUESTION | wxYES_DEFAULT );
  221. if( dialog.ShowModal() == wxID_YES )
  222. dirName.MakeRelativeTo( defaultPath );
  223. }
  224. m_outputDirectoryName->SetValue( dirName.GetFullPath() );
  225. }
  226. PLOT_FORMAT DIALOG_PLOT_SCHEMATIC::GetPlotFileFormat()
  227. {
  228. switch( m_plotFormatOpt->GetSelection() )
  229. {
  230. default:
  231. case 0: return PLOT_FORMAT::POST;
  232. case 1: return PLOT_FORMAT::PDF;
  233. case 2: return PLOT_FORMAT::SVG;
  234. case 3: return PLOT_FORMAT::DXF;
  235. case 4: return PLOT_FORMAT::HPGL;
  236. }
  237. }
  238. void DIALOG_PLOT_SCHEMATIC::OnPageSizeSelected( wxCommandEvent& event )
  239. {
  240. if( GetPlotFileFormat() == PLOT_FORMAT::HPGL )
  241. m_HPGLPaperSizeSelect = static_cast<HPGL_PAGE_SIZE>( m_paperSizeOption->GetSelection() );
  242. else
  243. m_pageSizeSelect = m_paperSizeOption->GetSelection();
  244. }
  245. void DIALOG_PLOT_SCHEMATIC::OnUpdateUI( wxUpdateUIEvent& event )
  246. {
  247. PLOT_FORMAT fmt = GetPlotFileFormat();
  248. if( fmt != m_plotFormat )
  249. {
  250. m_plotFormat = fmt;
  251. wxArrayString paperSizes;
  252. paperSizes.push_back( _( "Schematic size" ) );
  253. int selection;
  254. if( fmt == PLOT_FORMAT::HPGL )
  255. {
  256. paperSizes.push_back( _( "A5" ) );
  257. paperSizes.push_back( _( "A4" ) );
  258. paperSizes.push_back( _( "A3" ) );
  259. paperSizes.push_back( _( "A2" ) );
  260. paperSizes.push_back( _( "A1" ) );
  261. paperSizes.push_back( _( "A0" ) );
  262. paperSizes.push_back( _( "A" ) );
  263. paperSizes.push_back( _( "B" ) );
  264. paperSizes.push_back( _( "C" ) );
  265. paperSizes.push_back( _( "D" ) );
  266. paperSizes.push_back( _( "E" ) );
  267. selection = static_cast<int>( m_HPGLPaperSizeSelect );
  268. }
  269. else
  270. {
  271. paperSizes.push_back( _( "A4" ) );
  272. paperSizes.push_back( _( "A" ) );
  273. selection = m_pageSizeSelect;
  274. }
  275. m_openFileAfterPlot->Enable( fmt == PLOT_FORMAT::PDF );
  276. m_plotPDFPropertyPopups->Enable( fmt == PLOT_FORMAT::PDF );
  277. m_plotPDFHierarchicalLinks->Enable( fmt == PLOT_FORMAT::PDF );
  278. m_plotPDFMetadata->Enable( fmt == PLOT_FORMAT::PDF );
  279. m_paperSizeOption->Set( paperSizes );
  280. m_paperSizeOption->SetSelection( selection );
  281. m_defaultLineWidth.Enable(
  282. fmt == PLOT_FORMAT::POST || fmt == PLOT_FORMAT::PDF || fmt == PLOT_FORMAT::SVG );
  283. m_plotOriginTitle->Enable( fmt == PLOT_FORMAT::HPGL );
  284. m_plotOriginOpt->Enable( fmt == PLOT_FORMAT::HPGL );
  285. m_penWidth.Enable( fmt == PLOT_FORMAT::HPGL );
  286. m_plotBackgroundColor->Enable(
  287. fmt == PLOT_FORMAT::POST || fmt == PLOT_FORMAT::PDF || fmt == PLOT_FORMAT::SVG );
  288. m_colorTheme->Enable( fmt != PLOT_FORMAT::HPGL );
  289. m_ModeColorOption->Enable( fmt != PLOT_FORMAT::HPGL );
  290. }
  291. }
  292. void DIALOG_PLOT_SCHEMATIC::getPlotOptions( RENDER_SETTINGS* aSettings )
  293. {
  294. m_HPGLPenSize = m_penWidth.GetValue();
  295. EESCHEMA_SETTINGS* cfg = dynamic_cast<EESCHEMA_SETTINGS*>( Kiface().KifaceSettings() );
  296. wxASSERT( cfg );
  297. COLOR_SETTINGS* colors = getColorSettings();
  298. if( cfg )
  299. {
  300. cfg->m_PlotPanel.background_color = m_plotBackgroundColor->GetValue();
  301. cfg->m_PlotPanel.color = getModeColor();
  302. cfg->m_PlotPanel.color_theme = colors->GetFilename();
  303. cfg->m_PlotPanel.frame_reference = getPlotDrawingSheet();
  304. cfg->m_PlotPanel.format = static_cast<int>( GetPlotFileFormat() );
  305. cfg->m_PlotPanel.hpgl_origin = m_plotOriginOpt->GetSelection();
  306. cfg->m_PlotPanel.hpgl_paper_size = static_cast<int>( m_HPGLPaperSizeSelect );
  307. cfg->m_PlotPanel.pdf_property_popups = m_plotPDFPropertyPopups->GetValue();
  308. cfg->m_PlotPanel.pdf_hierarchical_links = m_plotPDFHierarchicalLinks->GetValue();
  309. cfg->m_PlotPanel.pdf_metadata = m_plotPDFMetadata->GetValue();
  310. cfg->m_PlotPanel.open_file_after_plot = getOpenFileAfterPlot();
  311. // HPGL Pen Size is stored in mm in config
  312. cfg->m_PlotPanel.hpgl_pen_size = m_HPGLPenSize / schIUScale.IU_PER_MM;
  313. aSettings->SetDefaultFont( cfg->m_Appearance.default_font );
  314. }
  315. aSettings->LoadColors( colors );
  316. aSettings->SetMinPenWidth( (int) m_defaultLineWidth.GetValue() );
  317. if( m_plotBackgroundColor->GetValue() )
  318. aSettings->SetBackgroundColor( colors->GetColor( LAYER_SCHEMATIC_BACKGROUND ) );
  319. else
  320. aSettings->SetBackgroundColor( COLOR4D::UNSPECIFIED );
  321. // Plot directory
  322. wxString path = m_outputDirectoryName->GetValue();
  323. path.Replace( '\\', '/' );
  324. SCHEMATIC_SETTINGS& settings = m_editFrame->Schematic().Settings();
  325. if( settings.m_PlotDirectoryName != path )
  326. m_configChanged = true;
  327. settings.m_PlotDirectoryName = path;
  328. }
  329. COLOR_SETTINGS* DIALOG_PLOT_SCHEMATIC::getColorSettings()
  330. {
  331. int selection = m_colorTheme->GetSelection();
  332. if( selection < 0 )
  333. {
  334. return m_editFrame->GetSettingsManager()->GetColorSettings(
  335. COLOR_SETTINGS::COLOR_BUILTIN_DEFAULT );
  336. }
  337. return static_cast<COLOR_SETTINGS*>( m_colorTheme->GetClientData( selection ) );
  338. }
  339. void DIALOG_PLOT_SCHEMATIC::OnPlotCurrent( wxCommandEvent& event )
  340. {
  341. plotSchematic( false );
  342. }
  343. void DIALOG_PLOT_SCHEMATIC::OnPlotAll( wxCommandEvent& event )
  344. {
  345. if (!m_job)
  346. {
  347. plotSchematic( true );
  348. }
  349. else
  350. {
  351. m_job->m_blackAndWhite = !getModeColor();
  352. m_job->m_useBackgroundColor = m_plotBackgroundColor->GetValue();
  353. m_job->m_HPGLPenSize = m_penWidth.GetValue();
  354. // m_job->m_HPGLPaperSizeSelect = m_HPGLPaperSizeSelect;
  355. m_job->m_pageSizeSelect = static_cast<JOB_PAGE_SIZE>( m_pageSizeSelect );
  356. m_job->m_PDFPropertyPopups = m_plotPDFPropertyPopups->GetValue();
  357. m_job->m_PDFHierarchicalLinks = m_plotPDFHierarchicalLinks->GetValue();
  358. m_job->m_PDFMetadata = m_plotPDFMetadata->GetValue();
  359. m_job->m_plotDrawingSheet = m_plotDrawingSheet->GetValue();
  360. m_job->m_plotAll = true;
  361. m_job->m_filename = m_outputDirectoryName->GetValue();
  362. m_job->m_HPGLPlotOrigin =
  363. static_cast<JOB_HPGL_PLOT_ORIGIN_AND_UNITS>( m_plotOriginOpt->GetSelection() );
  364. COLOR_SETTINGS* colors = getColorSettings();
  365. m_job->m_theme = colors->GetName();
  366. Close();
  367. }
  368. }
  369. void DIALOG_PLOT_SCHEMATIC::plotSchematic( bool aPlotAll )
  370. {
  371. wxBusyCursor dummy;
  372. SCH_RENDER_SETTINGS renderSettings( *m_editFrame->GetRenderSettings() );
  373. renderSettings.m_ShowHiddenPins = false;
  374. renderSettings.m_ShowHiddenFields = false;
  375. getPlotOptions( &renderSettings );
  376. std::unique_ptr<SCH_PLOTTER> schPlotter = std::make_unique<SCH_PLOTTER>( m_editFrame );
  377. COLOR_SETTINGS* colors = getColorSettings();
  378. SCH_PLOT_OPTS plotOpts;
  379. plotOpts.m_plotDrawingSheet = getPlotDrawingSheet();
  380. plotOpts.m_plotAll = aPlotAll;
  381. plotOpts.m_blackAndWhite = !getModeColor();
  382. plotOpts.m_useBackgroundColor = m_plotBackgroundColor->GetValue();
  383. plotOpts.m_theme = colors->GetFilename();
  384. plotOpts.m_PDFPropertyPopups = m_plotPDFPropertyPopups->GetValue();
  385. plotOpts.m_PDFHierarchicalLinks = m_plotPDFHierarchicalLinks->GetValue();
  386. plotOpts.m_PDFMetadata = m_plotPDFMetadata->GetValue();
  387. plotOpts.m_HPGLPaperSizeSelect = static_cast<HPGL_PAGE_SIZE>( m_HPGLPaperSizeSelect );
  388. plotOpts.m_HPGLPlotOrigin =
  389. static_cast<HPGL_PLOT_ORIGIN_AND_UNITS>( m_plotOriginOpt->GetSelection() );
  390. plotOpts.m_HPGLPenSize = m_HPGLPenSize;
  391. plotOpts.m_outputDirectory = getOutputPath();
  392. plotOpts.m_pageSizeSelect = m_pageSizeSelect;
  393. schPlotter->Plot( GetPlotFileFormat(), plotOpts, &renderSettings, &m_MessagesBox->Reporter() );
  394. if( GetPlotFileFormat() == PLOT_FORMAT::PDF && getOpenFileAfterPlot() )
  395. wxLaunchDefaultApplication( schPlotter->GetLastOutputFilePath() );
  396. }
  397. void DIALOG_PLOT_SCHEMATIC::setHpglPenWidth()
  398. {
  399. m_HPGLPenSize = m_penWidth.GetValue();
  400. if( m_HPGLPenSize > schIUScale.mmToIU( 2 ) )
  401. m_HPGLPenSize = schIUScale.mmToIU( 2 );
  402. if( m_HPGLPenSize < schIUScale.mmToIU( 0.01 ) )
  403. m_HPGLPenSize = schIUScale.mmToIU( 0.01 );
  404. }
  405. wxString DIALOG_PLOT_SCHEMATIC::getOutputPath()
  406. {
  407. wxString msg;
  408. wxString extMsg;
  409. wxFileName fn;
  410. extMsg.Printf( _( "Falling back to user path '%s'." ), KIPLATFORM::ENV::GetDocumentsPath() );
  411. // Build the absolute path of current output directory to preselect it in the file browser.
  412. std::function<bool( wxString* )> textResolver =
  413. [&]( wxString* token ) -> bool
  414. {
  415. SCHEMATIC& schematic = m_editFrame->Schematic();
  416. return schematic.ResolveTextVar( &schematic.CurrentSheet(), token, 0 );
  417. };
  418. wxString path = m_outputDirectoryName->GetValue();
  419. path = ExpandTextVars( path, &textResolver );
  420. path = ExpandEnvVarSubstitutions( path, &Prj() );
  421. fn.SetPath( path );
  422. // If the contents of the path edit control results in an absolute path, return it as is.
  423. if( fn.IsAbsolute() )
  424. return path;
  425. // When editing a schematic that is not part of a project in the stand alone mode, the
  426. // project path is not defined.
  427. if( Prj().IsNullProject() )
  428. {
  429. SCH_SCREEN* screen = m_editFrame->Schematic().RootScreen();
  430. if( screen && !screen->GetFileName().IsEmpty() )
  431. {
  432. fn = screen->GetFileName();
  433. msg.Printf( _( "Cannot normalize path '%s%s'." ), fn.GetPathWithSep(), path );
  434. fn.SetPath( fn.GetPathWithSep() + path );
  435. // Normalize always returns true for a non-empty file name so clear the file name
  436. // and extension so that only the path is normalized.
  437. fn.SetName( wxEmptyString );
  438. fn.SetExt( wxEmptyString );
  439. if( fn.Normalize( FN_NORMALIZE_FLAGS | wxPATH_NORM_ENV_VARS ) )
  440. {
  441. path = fn.GetPath();
  442. }
  443. else
  444. {
  445. wxMessageDialog dlg( this, msg, _( "Warning" ), wxOK | wxCENTER | wxRESIZE_BORDER
  446. | wxICON_EXCLAMATION | wxSTAY_ON_TOP );
  447. dlg.SetExtendedMessage( extMsg );
  448. dlg.ShowModal();
  449. path = KIPLATFORM::ENV::GetDocumentsPath();
  450. }
  451. }
  452. else
  453. {
  454. msg = _( "No project or path defined for the current schematic." );
  455. wxMessageDialog dlg( this, msg, _( "Warning" ), wxOK | wxCENTER | wxRESIZE_BORDER
  456. | wxICON_EXCLAMATION | wxSTAY_ON_TOP );
  457. dlg.SetExtendedMessage( extMsg );
  458. dlg.ShowModal();
  459. // Always fall back to user's document path if no other absolute path can be normalized.
  460. path = KIPLATFORM::ENV::GetDocumentsPath();
  461. }
  462. }
  463. else
  464. {
  465. msg.Printf( _( "Cannot normalize path '%s%s'." ), Prj().GetProjectPath(), path );
  466. // Build the absolute path of current output directory and the project path.
  467. fn.SetPath( Prj().GetProjectPath() + path );
  468. if( fn.Normalize( FN_NORMALIZE_FLAGS | wxPATH_NORM_ENV_VARS ) )
  469. {
  470. path = fn.GetPath();
  471. }
  472. else
  473. {
  474. wxMessageDialog dlg( this, msg, _( "Warning" ),
  475. wxOK | wxCENTER | wxRESIZE_BORDER | wxICON_EXCLAMATION |
  476. wxSTAY_ON_TOP );
  477. dlg.SetExtendedMessage( extMsg );
  478. dlg.ShowModal();
  479. path = KIPLATFORM::ENV::GetDocumentsPath();
  480. }
  481. }
  482. return path;
  483. }