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.

562 lines
15 KiB

  1. /*
  2. * This program source code file is part of KICAD, a free EDA CAD application.
  3. *
  4. * Copyright (C) 1992-2010 jean-pierre.charras
  5. * Copyright The KiCad Developers, see AUTHORS.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 <bitmap2component.h>
  25. #include <bitmap2cmp_frame.h>
  26. #include <bitmap2cmp_panel.h>
  27. #include <bitmap2cmp_settings.h>
  28. #include <bitmap_io.h>
  29. #include <bitmaps.h>
  30. #include <common.h>
  31. #include <id.h>
  32. #include <widgets/wx_menubar.h>
  33. #include <wildcards_and_files_ext.h>
  34. #include <file_history.h>
  35. #include <tool/tool_manager.h>
  36. #include <tool/tool_dispatcher.h>
  37. #include <tool/common_control.h>
  38. #include <tool/action_manager.h>
  39. #include <bitmap2cmp_control.h>
  40. #include <tool/actions.h>
  41. #include <wx/filedlg.h>
  42. #include <wx/msgdlg.h>
  43. #define DEFAULT_DPI 300 // the image DPI used in formats that do not define a DPI
  44. IMAGE_SIZE::IMAGE_SIZE()
  45. {
  46. m_outputSize = 0.0;
  47. m_originalDPI = DEFAULT_DPI;
  48. m_originalSizePixels = 0;
  49. m_unit = EDA_UNITS::MILLIMETRES;
  50. }
  51. void IMAGE_SIZE::SetOutputSizeFromInitialImageSize()
  52. {
  53. // Safety-check to guarantee no divide-by-zero
  54. m_originalDPI = std::max( 1, m_originalDPI );
  55. // Set the m_outputSize value from the m_originalSizePixels and the selected unit
  56. if( m_unit == EDA_UNITS::MILLIMETRES )
  57. m_outputSize = (double)GetOriginalSizePixels() / m_originalDPI * 25.4;
  58. else if( m_unit == EDA_UNITS::INCHES )
  59. m_outputSize = (double)GetOriginalSizePixels() / m_originalDPI;
  60. else
  61. m_outputSize = m_originalDPI;
  62. }
  63. int IMAGE_SIZE::GetOutputDPI()
  64. {
  65. int outputDPI;
  66. if( m_unit == EDA_UNITS::MILLIMETRES )
  67. outputDPI = GetOriginalSizePixels() / ( m_outputSize / 25.4 );
  68. else if( m_unit == EDA_UNITS::INCHES )
  69. outputDPI = GetOriginalSizePixels() / m_outputSize;
  70. else
  71. outputDPI = KiROUND( m_outputSize );
  72. // Zero is not a DPI, and may cause divide-by-zero errors...
  73. outputDPI = std::max( 1, outputDPI );
  74. return outputDPI;
  75. }
  76. void IMAGE_SIZE::SetUnit( EDA_UNITS aUnit )
  77. {
  78. // Set the unit used for m_outputSize, and convert the old m_outputSize value
  79. // to the value in new unit
  80. if( aUnit == m_unit )
  81. return;
  82. // Convert m_outputSize to mm:
  83. double size_mm;
  84. if( m_unit == EDA_UNITS::MILLIMETRES )
  85. {
  86. size_mm = m_outputSize;
  87. }
  88. else if( m_unit == EDA_UNITS::INCHES )
  89. {
  90. size_mm = m_outputSize * 25.4;
  91. }
  92. else
  93. {
  94. // m_outputSize is the DPI, not an image size
  95. // the image size is m_originalSizePixels / m_outputSize (in inches)
  96. if( m_outputSize )
  97. size_mm = m_originalSizePixels / m_outputSize * 25.4;
  98. else
  99. size_mm = 0;
  100. }
  101. // Convert m_outputSize to new value:
  102. if( aUnit == EDA_UNITS::MILLIMETRES )
  103. {
  104. m_outputSize = size_mm;
  105. }
  106. else if( aUnit == EDA_UNITS::INCHES )
  107. {
  108. m_outputSize = size_mm / 25.4;
  109. }
  110. else
  111. {
  112. if( size_mm )
  113. m_outputSize = m_originalSizePixels / size_mm * 25.4;
  114. else
  115. m_outputSize = 0;
  116. }
  117. m_unit = aUnit;
  118. }
  119. BEGIN_EVENT_TABLE( BITMAP2CMP_FRAME, KIWAY_PLAYER )
  120. EVT_MENU( wxID_CLOSE, BITMAP2CMP_FRAME::OnExit )
  121. EVT_MENU( wxID_EXIT, BITMAP2CMP_FRAME::OnExit )
  122. EVT_MENU_RANGE( ID_FILE1, ID_FILEMAX, BITMAP2CMP_FRAME::OnFileHistory )
  123. EVT_MENU( ID_FILE_LIST_CLEAR, BITMAP2CMP_FRAME::OnClearFileHistory )
  124. END_EVENT_TABLE()
  125. BITMAP2CMP_FRAME::BITMAP2CMP_FRAME( KIWAY* aKiway, wxWindow* aParent ) :
  126. KIWAY_PLAYER( aKiway, aParent, FRAME_BM2CMP, _( "Image Converter" ), wxDefaultPosition,
  127. wxDefaultSize, wxDEFAULT_FRAME_STYLE, wxT( "bitmap2cmp" ), unityScale ),
  128. m_panel( nullptr ),
  129. m_statusBar( nullptr )
  130. {
  131. m_aboutTitle = _HKI( "KiCad Image Converter" );
  132. // Give an icon
  133. wxIcon icon;
  134. wxIconBundle icon_bundle;
  135. icon.CopyFromBitmap( KiBitmap( BITMAPS::icon_bitmap2component, 48 ) );
  136. icon_bundle.AddIcon( icon );
  137. icon.CopyFromBitmap( KiBitmap( BITMAPS::icon_bitmap2component, 128 ) );
  138. icon_bundle.AddIcon( icon );
  139. icon.CopyFromBitmap( KiBitmap( BITMAPS::icon_bitmap2component, 256 ) );
  140. icon_bundle.AddIcon( icon );
  141. icon.CopyFromBitmap( KiBitmap( BITMAPS::icon_bitmap2component_32 ) );
  142. icon_bundle.AddIcon( icon );
  143. icon.CopyFromBitmap( KiBitmap( BITMAPS::icon_bitmap2component_16 ) );
  144. icon_bundle.AddIcon( icon );
  145. SetIcons( icon_bundle );
  146. wxBoxSizer* mainSizer = new wxBoxSizer( wxVERTICAL );
  147. SetSizer( mainSizer );
  148. m_panel = new BITMAP2CMP_PANEL( this );
  149. mainSizer->Add( m_panel, 1, wxEXPAND, 5 );
  150. m_statusBar = this->CreateStatusBar( 1, wxSTB_SIZEGRIP, wxID_ANY );
  151. LoadSettings( config() );
  152. m_toolManager = new TOOL_MANAGER;
  153. m_toolManager->SetEnvironment( nullptr, nullptr, nullptr, config(), this );
  154. m_toolDispatcher = new TOOL_DISPATCHER( m_toolManager );
  155. // Register tools
  156. m_toolManager->RegisterTool( new COMMON_CONTROL );
  157. m_toolManager->RegisterTool( new BITMAP2CMP_CONTROL );
  158. m_toolManager->InitTools();
  159. ReCreateMenuBar();
  160. setupUIConditions();
  161. GetSizer()->SetSizeHints( this );
  162. SetSize( m_framePos.x, m_framePos.y, m_frameSize.x, m_frameSize.y );
  163. if ( m_framePos == wxDefaultPosition )
  164. Centre();
  165. }
  166. BITMAP2CMP_FRAME::~BITMAP2CMP_FRAME()
  167. {
  168. SaveSettings( config() );
  169. /*
  170. * This needed for OSX: avoids further OnDraw processing after this
  171. * destructor and before the native window is destroyed
  172. */
  173. Freeze();
  174. }
  175. void BITMAP2CMP_FRAME::OnExit( wxCommandEvent& aEvent )
  176. {
  177. // Just generate a wxCloseEvent
  178. Close( false );
  179. }
  180. wxWindow* BITMAP2CMP_FRAME::GetToolCanvas() const
  181. {
  182. return m_panel->GetCurrentPage();
  183. }
  184. void BITMAP2CMP_FRAME::OnFileHistory( wxCommandEvent& event )
  185. {
  186. wxString fn = GetFileFromHistory( event.GetId(), _( "Image files" ) );
  187. if( !fn.IsEmpty() )
  188. {
  189. OpenProjectFiles( std::vector<wxString>( 1, fn ) );
  190. Refresh();
  191. }
  192. }
  193. void BITMAP2CMP_FRAME::OnClearFileHistory( wxCommandEvent& aEvent )
  194. {
  195. ClearFileHistory();
  196. }
  197. void BITMAP2CMP_FRAME::doReCreateMenuBar()
  198. {
  199. COMMON_CONTROL* tool = m_toolManager->GetTool<COMMON_CONTROL>();
  200. EDA_BASE_FRAME* base_frame = dynamic_cast<EDA_BASE_FRAME*>( this );
  201. // base_frame == nullptr should not happen, but it makes Coverity happy
  202. wxCHECK( base_frame, /* void */ );
  203. // wxWidgets handles the OSX Application menu behind the scenes, but that means
  204. // we always have to start from scratch with a new wxMenuBar.
  205. wxMenuBar* oldMenuBar = base_frame->GetMenuBar();
  206. WX_MENUBAR* menuBar = new WX_MENUBAR();
  207. //-- File menu -----------------------------------------------------------
  208. //
  209. ACTION_MENU* fileMenu = new ACTION_MENU( false, tool );
  210. fileMenu->Add( ACTIONS::open );
  211. static ACTION_MENU* openRecentMenu;
  212. FILE_HISTORY& fileHistory = GetFileHistory();
  213. // Create the menu if it does not exist. Adding a file to/from the history
  214. // will automatically refresh the menu.
  215. if( !openRecentMenu )
  216. {
  217. openRecentMenu = new ACTION_MENU( false, tool );
  218. openRecentMenu->SetIcon( BITMAPS::recent );
  219. fileHistory.UseMenu( openRecentMenu );
  220. fileHistory.AddFilesToMenu();
  221. }
  222. // Ensure the title is up to date after changing language
  223. openRecentMenu->SetTitle( _( "Open Recent" ) );
  224. fileHistory.UpdateClearText( openRecentMenu, _( "Clear Recent Files" ) );
  225. wxMenuItem* item = fileMenu->Add( openRecentMenu->Clone() );
  226. // Add the file menu condition here since it needs the item ID for the submenu
  227. ACTION_CONDITIONS cond;
  228. cond.Enable( FILE_HISTORY::FileHistoryNotEmpty( fileHistory ) );
  229. RegisterUIUpdateHandler( item->GetId(), cond );
  230. fileMenu->AppendSeparator();
  231. fileMenu->AddQuit( _( "Image Converter" ) );
  232. //-- Preferences menu -----------------------------------------------
  233. //
  234. ACTION_MENU* prefsMenu = new ACTION_MENU( false, tool );
  235. prefsMenu->Add( ACTIONS::openPreferences );
  236. prefsMenu->AppendSeparator();
  237. AddMenuLanguageList( prefsMenu, tool );
  238. //-- Menubar -------------------------------------------------------------
  239. //
  240. menuBar->Append( fileMenu, _( "&File" ) );
  241. menuBar->Append( prefsMenu, _( "&Preferences" ) );
  242. base_frame->AddStandardHelpMenu( menuBar );
  243. base_frame->SetMenuBar( menuBar );
  244. delete oldMenuBar;
  245. }
  246. void BITMAP2CMP_FRAME::ShowChangedLanguage()
  247. {
  248. EDA_BASE_FRAME::ShowChangedLanguage();
  249. UpdateTitle();
  250. SaveSettings( config() );
  251. IMAGE_SIZE imageSizeX = m_panel->GetOutputSizeX();
  252. IMAGE_SIZE imageSizeY = m_panel->GetOutputSizeY();
  253. Freeze();
  254. wxSizer* mainSizer = m_panel->GetContainingSizer();
  255. mainSizer->Detach( m_panel );
  256. m_panel->Destroy();
  257. m_panel = new BITMAP2CMP_PANEL( this );
  258. mainSizer->Add( m_panel, 1, wxEXPAND, 5 );
  259. Layout();
  260. if( !m_srcFileName.IsEmpty() )
  261. OpenProjectFiles( std::vector<wxString>( 1, m_srcFileName ) );
  262. LoadSettings( config() );
  263. m_panel->SetOutputSize( imageSizeX, imageSizeY );
  264. Thaw();
  265. Refresh();
  266. }
  267. void BITMAP2CMP_FRAME::UpdateTitle()
  268. {
  269. wxString title;
  270. if( !m_srcFileName.IsEmpty() )
  271. {
  272. wxFileName filename( m_srcFileName );
  273. title = filename.GetFullName() + wxT( " \u2014 " );
  274. }
  275. title += _( "Image Converter" );
  276. SetTitle( title );
  277. }
  278. void BITMAP2CMP_FRAME::LoadSettings( APP_SETTINGS_BASE* aCfg )
  279. {
  280. EDA_BASE_FRAME::LoadSettings( aCfg );
  281. if( BITMAP2CMP_SETTINGS* cfg = dynamic_cast<BITMAP2CMP_SETTINGS*>( aCfg ) )
  282. {
  283. m_srcFileName = cfg->m_BitmapFileName;
  284. m_outFileName = cfg->m_ConvertedFileName;
  285. m_panel->LoadSettings( cfg );
  286. }
  287. }
  288. void BITMAP2CMP_FRAME::SaveSettings( APP_SETTINGS_BASE* aCfg )
  289. {
  290. EDA_BASE_FRAME::SaveSettings( aCfg );
  291. if( BITMAP2CMP_SETTINGS* cfg = dynamic_cast<BITMAP2CMP_SETTINGS*>( aCfg ) )
  292. {
  293. cfg->m_BitmapFileName = m_srcFileName;
  294. cfg->m_ConvertedFileName = m_outFileName;
  295. m_panel->SaveSettings( cfg );
  296. }
  297. }
  298. void BITMAP2CMP_FRAME::OnLoadFile()
  299. {
  300. wxFileName fn( m_srcFileName );
  301. wxString path = fn.GetPath();
  302. if( path.IsEmpty() || !wxDirExists( path ) )
  303. path = m_mruPath;
  304. wxFileDialog fileDlg( this, _( "Choose Image" ), path, wxEmptyString,
  305. _( "Image Files" ) + wxS( " " )+ wxImage::GetImageExtWildcard(),
  306. wxFD_OPEN | wxFD_FILE_MUST_EXIST );
  307. if( fileDlg.ShowModal() != wxID_OK )
  308. return;
  309. wxString fullFilename = fileDlg.GetPath();
  310. if( !OpenProjectFiles( std::vector<wxString>( 1, fullFilename ) ) )
  311. return;
  312. fn = fullFilename;
  313. m_mruPath = fn.GetPath();
  314. SetStatusText( fullFilename );
  315. UpdateTitle();
  316. Refresh();
  317. }
  318. bool BITMAP2CMP_FRAME::OpenProjectFiles( const std::vector<wxString>& aFileSet, int aCtl )
  319. {
  320. m_srcFileName = aFileSet[0];
  321. if( m_panel->OpenProjectFiles( aFileSet, aCtl ) )
  322. {
  323. UpdateFileHistory( m_srcFileName );
  324. return true;
  325. }
  326. return false;
  327. }
  328. void BITMAP2CMP_FRAME::ExportDrawingSheetFormat()
  329. {
  330. wxFileName fn( m_outFileName );
  331. wxString path = fn.GetPath();
  332. if( path.IsEmpty() || !wxDirExists(path) )
  333. path = ::wxGetCwd();
  334. wxFileDialog fileDlg( this, _( "Create Drawing Sheet File" ), path, wxEmptyString,
  335. FILEEXT::DrawingSheetFileWildcard(), wxFD_SAVE | wxFD_OVERWRITE_PROMPT );
  336. if( fileDlg.ShowModal() != wxID_OK )
  337. return;
  338. fn = fileDlg.GetPath();
  339. fn.SetExt( FILEEXT::DrawingSheetFileExtension );
  340. m_outFileName = fn.GetFullPath();
  341. FILE* outfile = wxFopen( m_outFileName, wxT( "w" ) );
  342. if( !outfile )
  343. {
  344. wxMessageBox( wxString::Format( _( "File '%s' could not be created." ), m_outFileName ) );
  345. return;
  346. }
  347. std::string buffer;
  348. m_panel->ExportToBuffer( buffer, DRAWING_SHEET_FMT );
  349. fputs( buffer.c_str(), outfile );
  350. fclose( outfile );
  351. }
  352. void BITMAP2CMP_FRAME::ExportPostScriptFormat()
  353. {
  354. wxFileName fn( m_outFileName );
  355. wxString path = fn.GetPath();
  356. if( path.IsEmpty() || !wxDirExists( path ) )
  357. path = ::wxGetCwd();
  358. wxFileDialog fileDlg( this, _( "Create PostScript File" ), path, wxEmptyString,
  359. FILEEXT::PSFileWildcard(), wxFD_SAVE | wxFD_OVERWRITE_PROMPT );
  360. if( fileDlg.ShowModal() != wxID_OK )
  361. return;
  362. fn = fileDlg.GetPath();
  363. fn.SetExt( wxT( "ps" ) );
  364. m_outFileName = fn.GetFullPath();
  365. FILE* outfile = wxFopen( m_outFileName, wxT( "w" ) );
  366. if( !outfile )
  367. {
  368. wxMessageBox( wxString::Format( _( "File '%s' could not be created." ), m_outFileName ) );
  369. return;
  370. }
  371. std::string buffer;
  372. m_panel->ExportToBuffer( buffer, POSTSCRIPT_FMT );
  373. fputs( buffer.c_str(), outfile );
  374. fclose( outfile );
  375. }
  376. void BITMAP2CMP_FRAME::ExportEeschemaFormat()
  377. {
  378. wxFileName fn( m_outFileName );
  379. wxString path = fn.GetPath();
  380. if( path.IsEmpty() || !wxDirExists( path ) )
  381. path = ::wxGetCwd();
  382. wxFileDialog fileDlg( this, _( "Create Symbol Library" ), path, wxEmptyString,
  383. FILEEXT::KiCadSymbolLibFileWildcard(),
  384. wxFD_SAVE | wxFD_OVERWRITE_PROMPT );
  385. if( fileDlg.ShowModal() != wxID_OK )
  386. return;
  387. fn = EnsureFileExtension( fileDlg.GetPath(), FILEEXT::KiCadSymbolLibFileExtension );
  388. m_outFileName = fn.GetFullPath();
  389. FILE* outfile = wxFopen( m_outFileName, wxT( "w" ) );
  390. if( !outfile )
  391. {
  392. wxMessageBox( wxString::Format( _( "File '%s' could not be created." ), m_outFileName ) );
  393. return;
  394. }
  395. std::string buffer;
  396. m_panel->ExportToBuffer( buffer, SYMBOL_FMT );
  397. fputs( buffer.c_str(), outfile );
  398. fclose( outfile );
  399. }
  400. void BITMAP2CMP_FRAME::ExportPcbnewFormat()
  401. {
  402. wxFileName fn( m_outFileName );
  403. wxString path = fn.GetPath();
  404. if( path.IsEmpty() || !wxDirExists( path ) )
  405. path = m_mruPath;
  406. wxFileDialog fileDlg( this, _( "Create Footprint Library" ), path, wxEmptyString,
  407. FILEEXT::KiCadFootprintLibFileWildcard(),
  408. wxFD_SAVE | wxFD_OVERWRITE_PROMPT );
  409. if( fileDlg.ShowModal() != wxID_OK )
  410. return;
  411. fn = EnsureFileExtension( fileDlg.GetPath(), FILEEXT::KiCadFootprintFileExtension );
  412. m_outFileName = fn.GetFullPath();
  413. FILE* outfile = wxFopen( m_outFileName, wxT( "w" ) );
  414. if( !outfile )
  415. {
  416. wxMessageBox( wxString::Format( _( "File '%s' could not be created." ), m_outFileName ) );
  417. return;
  418. }
  419. std::string buffer;
  420. m_panel->ExportToBuffer( buffer, FOOTPRINT_FMT );
  421. fputs( buffer.c_str(), outfile );
  422. fclose( outfile );
  423. m_mruPath = fn.GetPath();
  424. }