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.

306 lines
8.5 KiB

  1. /*
  2. * This program source code file is part of KiCad, a free EDA CAD application.
  3. *
  4. * Copyright (C) 2011 SoftPLC Corporation, Dick Hollenbeck <dick@softplc.com>
  5. * Copyright (C) 2017-2021 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 <wx/image.h>
  25. #include <wx/bitmap.h>
  26. #include <wx/gdicmn.h>
  27. #include <wx/mstream.h>
  28. #include <wx/menu.h>
  29. #include <wx/menuitem.h>
  30. #include <wx/aui/auibar.h>
  31. #include <wx/dcclient.h>
  32. #include <wx/dcmemory.h>
  33. #include <cstdint>
  34. #include <mutex>
  35. #include <unordered_map>
  36. #include <asset_archive.h>
  37. #include <bitmaps.h>
  38. #include <bitmap_store.h>
  39. #include <bitmaps/bitmap_opaque.h> // for pcb_calculator compatibility shim
  40. #include <pgm_base.h>
  41. #include <eda_base_frame.h>
  42. #include <eda_draw_frame.h>
  43. #include <paths.h>
  44. static std::unique_ptr<BITMAP_STORE> s_BitmapStore;
  45. struct SCALED_BITMAP_ID {
  46. BITMAPS bitmap;
  47. int scale;
  48. bool operator==( SCALED_BITMAP_ID const& other ) const noexcept
  49. {
  50. return bitmap == other.bitmap && scale == other.scale;
  51. }
  52. };
  53. namespace std {
  54. template<> struct hash<SCALED_BITMAP_ID>
  55. {
  56. typedef SCALED_BITMAP_ID argument_type;
  57. typedef std::size_t result_type;
  58. result_type operator()( argument_type const& id ) const noexcept
  59. {
  60. static const bool sz64 = sizeof( uintptr_t ) == 8;
  61. static const size_t mask = sz64 ? 0xF000000000000000uLL : 0xF0000000uL;
  62. static const size_t offset = sz64 ? 60 : 28;
  63. // The hash only needs to be fast and simple, not necessarily accurate - a collision
  64. // only makes things slower, not broken. BITMAPS is a pointer, so the most
  65. // significant several bits are generally going to be the same for all. Just convert
  66. // it to an integer and stuff the scale factor into those bits.
  67. return
  68. ( (uintptr_t)( id.bitmap ) & ~mask ) |
  69. ( ( (uintptr_t)( id.scale ) & 0xF ) << offset );
  70. }
  71. };
  72. }
  73. static std::unordered_map<SCALED_BITMAP_ID, wxBitmap> s_ScaledBitmapCache;
  74. static std::mutex s_BitmapCacheMutex;
  75. BITMAP_STORE* GetBitmapStore()
  76. {
  77. if( !s_BitmapStore )
  78. {
  79. wxFileName path( PATHS::GetStockDataPath() + wxT( "/resources" ), wxT( "images.zip" ) );
  80. s_BitmapStore = std::make_unique<BITMAP_STORE>();
  81. }
  82. return s_BitmapStore.get();
  83. }
  84. wxBitmap KiBitmap( BITMAPS aBitmap, int aHeightTag )
  85. {
  86. return GetBitmapStore()->GetBitmap( aBitmap, aHeightTag );
  87. }
  88. // TODO: Remove this once pcb_calculator images are moved into the main bitmap system
  89. wxBitmap KiBitmap( const BITMAP_OPAQUE* aBitmap )
  90. {
  91. wxMemoryInputStream is( aBitmap->png, aBitmap->byteCount );
  92. wxImage image( is, wxBITMAP_TYPE_PNG );
  93. wxBitmap bitmap( image );
  94. return bitmap;
  95. }
  96. int KiIconScale( wxWindow* aWindow )
  97. {
  98. const int vert_size = aWindow->ConvertDialogToPixels( wxSize( 0, 8 ) ).y;
  99. // Autoscale won't exceed unity until the system has quite high resolution,
  100. // because we don't want the icons to look obviously scaled on a system
  101. // where it's easy to see it.
  102. if( vert_size > 34 ) return 8;
  103. else if( vert_size > 29 ) return 7;
  104. else if( vert_size > 24 ) return 6;
  105. else return 4;
  106. }
  107. static int get_scale_factor( wxWindow* aWindow )
  108. {
  109. int requested_scale = Pgm().GetCommonSettings()->m_Appearance.icon_scale;
  110. if( requested_scale > 0 )
  111. return requested_scale;
  112. else
  113. return KiIconScale( aWindow );
  114. }
  115. wxBitmap KiScaledBitmap( BITMAPS aBitmap, wxWindow* aWindow, int aHeight, bool aQuantized )
  116. {
  117. // Bitmap conversions are cached because they can be slow.
  118. int scale = get_scale_factor( aWindow );
  119. if( aQuantized )
  120. scale = KiROUND( (double) scale / 4.0 ) * 4;
  121. SCALED_BITMAP_ID id = { static_cast<BITMAPS>( aBitmap ), scale };
  122. std::lock_guard<std::mutex> guard( s_BitmapCacheMutex );
  123. auto it = s_ScaledBitmapCache.find( id );
  124. if( it != s_ScaledBitmapCache.end() )
  125. {
  126. return it->second;
  127. }
  128. else
  129. {
  130. wxBitmap bitmap = GetBitmapStore()->GetBitmapScaled( aBitmap, scale, aHeight );
  131. return s_ScaledBitmapCache.emplace( id, bitmap ).first->second;
  132. }
  133. }
  134. void ClearScaledBitmapCache()
  135. {
  136. std::lock_guard<std::mutex> guard( s_BitmapCacheMutex );
  137. s_ScaledBitmapCache.clear();
  138. }
  139. wxBitmap KiScaledBitmap( const wxBitmap& aBitmap, wxWindow* aWindow )
  140. {
  141. const int scale = get_scale_factor( aWindow );
  142. if( scale == 4 )
  143. {
  144. return wxBitmap( aBitmap );
  145. }
  146. else
  147. {
  148. wxImage image = aBitmap.ConvertToImage();
  149. image.Rescale( scale * image.GetWidth() / 4, scale * image.GetHeight() / 4,
  150. wxIMAGE_QUALITY_BILINEAR );
  151. return wxBitmap( image );
  152. }
  153. }
  154. wxBitmap* KiBitmapNew( BITMAPS aBitmap )
  155. {
  156. wxBitmap* bitmap = new wxBitmap( GetBitmapStore()->GetBitmap( aBitmap ) );
  157. return bitmap;
  158. }
  159. bool SaveCanvasImageToFile( EDA_DRAW_FRAME* aFrame, const wxString& aFileName,
  160. BITMAP_TYPE aBitmapType )
  161. {
  162. wxCHECK( aFrame != nullptr, false );
  163. bool retv = true;
  164. // Make a screen copy of the canvas:
  165. wxSize image_size = aFrame->GetCanvas()->GetClientSize();
  166. wxClientDC dc( aFrame->GetCanvas() );
  167. wxBitmap bitmap( image_size.x, image_size.y );
  168. wxMemoryDC memdc;
  169. memdc.SelectObject( bitmap );
  170. memdc.Blit( 0, 0, image_size.x, image_size.y, &dc, 0, 0 );
  171. memdc.SelectObject( wxNullBitmap );
  172. wxImage image = bitmap.ConvertToImage();
  173. wxBitmapType type = wxBITMAP_TYPE_PNG;
  174. switch( aBitmapType )
  175. {
  176. case BITMAP_TYPE::PNG: type = wxBITMAP_TYPE_PNG; break;
  177. case BITMAP_TYPE::BMP: type = wxBITMAP_TYPE_BMP; break;
  178. case BITMAP_TYPE::JPG: type = wxBITMAP_TYPE_JPEG; break;
  179. }
  180. if( !image.SaveFile( aFileName, type ) )
  181. retv = false;
  182. image.Destroy();
  183. return retv;
  184. }
  185. void AddBitmapToMenuItem( wxMenuItem* aMenu, const wxBitmap& aImage )
  186. {
  187. // Retrieve the global application show icon option:
  188. bool useImagesInMenus = Pgm().GetCommonSettings()->m_Appearance.use_icons_in_menus;
  189. wxItemKind menu_type = aMenu->GetKind();
  190. if( useImagesInMenus && menu_type != wxITEM_CHECK && menu_type != wxITEM_RADIO )
  191. {
  192. aMenu->SetBitmap( aImage );
  193. }
  194. }
  195. wxMenuItem* AddMenuItem( wxMenu* aMenu, int aId, const wxString& aText,
  196. const wxBitmap& aImage, wxItemKind aType = wxITEM_NORMAL )
  197. {
  198. wxMenuItem* item = new wxMenuItem( aMenu, aId, aText, wxEmptyString, aType );
  199. AddBitmapToMenuItem( item, aImage );
  200. aMenu->Append( item );
  201. return item;
  202. }
  203. wxMenuItem* AddMenuItem( wxMenu* aMenu, int aId, const wxString& aText,
  204. const wxString& aHelpText, const wxBitmap& aImage,
  205. wxItemKind aType = wxITEM_NORMAL )
  206. {
  207. wxMenuItem* item = new wxMenuItem( aMenu, aId, aText, aHelpText, aType );
  208. AddBitmapToMenuItem( item, aImage );
  209. aMenu->Append( item );
  210. return item;
  211. }
  212. wxMenuItem* AddMenuItem( wxMenu* aMenu, wxMenu* aSubMenu, int aId,
  213. const wxString& aText, const wxBitmap& aImage )
  214. {
  215. wxMenuItem* item = new wxMenuItem( aMenu, aId, aText );
  216. item->SetSubMenu( aSubMenu );
  217. AddBitmapToMenuItem( item, aImage );
  218. aMenu->Append( item );
  219. return item;
  220. }
  221. wxMenuItem* AddMenuItem( wxMenu* aMenu, wxMenu* aSubMenu, int aId,
  222. const wxString& aText, const wxString& aHelpText,
  223. const wxBitmap& aImage )
  224. {
  225. wxMenuItem* item = new wxMenuItem( aMenu, aId, aText, aHelpText );
  226. item->SetSubMenu( aSubMenu );
  227. AddBitmapToMenuItem( item, aImage );
  228. aMenu->Append( item );
  229. return item;
  230. }