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.

203 lines
5.8 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 <pgm_base.h>
  40. #include <paths.h>
  41. #include <kiplatform/ui.h>
  42. #include <math/util.h>
  43. #include <settings/common_settings.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. wxBitmapBundle KiBitmapBundle( BITMAPS aBitmap )
  89. {
  90. return GetBitmapStore()->GetBitmapBundle( aBitmap );
  91. }
  92. wxBitmapBundle KiDisabledBitmapBundle( BITMAPS aBitmap )
  93. {
  94. return GetBitmapStore()->GetDisabledBitmapBundle( aBitmap );
  95. }
  96. int KiIconScale( wxWindow* aWindow )
  97. {
  98. // For historical reasons, "4" here means unity (no scaling)
  99. #if defined( __WXMSW__)
  100. // Basically don't try and scale within kicad and let wx do its thing
  101. // with wx introducing bitmap bundles, it will auto scale automatically with dpi
  102. // the issue is, none of the scaling factors have any tie to system scaling
  103. // this means wx is actually going to scale again causing even more distorted icons
  104. return 4;
  105. #else
  106. const int vert_size = aWindow->ConvertDialogToPixels( wxSize( 0, 8 ) ).y;
  107. // Autoscale won't exceed unity until the system has quite high resolution,
  108. // because we don't want the icons to look obviously scaled on a system
  109. // where it's easy to see it.
  110. if( vert_size > 34 ) return 8;
  111. else if( vert_size > 29 ) return 7;
  112. else if( vert_size > 24 ) return 6;
  113. else return 4;
  114. #endif
  115. }
  116. wxBitmap KiScaledBitmap( BITMAPS aBitmap, wxWindow* aWindow, int aHeight, bool aQuantized )
  117. {
  118. // Bitmap conversions are cached because they can be slow.
  119. int scale = KiIconScale( aWindow );
  120. if( aQuantized )
  121. scale = KiROUND( (double) scale / 4.0 ) * 4;
  122. SCALED_BITMAP_ID id = { static_cast<BITMAPS>( aBitmap ), scale };
  123. std::lock_guard<std::mutex> guard( s_BitmapCacheMutex );
  124. auto it = s_ScaledBitmapCache.find( id );
  125. if( it != s_ScaledBitmapCache.end() )
  126. {
  127. return it->second;
  128. }
  129. else
  130. {
  131. wxBitmap bitmap = GetBitmapStore()->GetBitmapScaled( aBitmap, scale, aHeight );
  132. return s_ScaledBitmapCache.emplace( id, bitmap ).first->second;
  133. }
  134. }
  135. void ClearScaledBitmapCache()
  136. {
  137. std::lock_guard<std::mutex> guard( s_BitmapCacheMutex );
  138. s_ScaledBitmapCache.clear();
  139. }
  140. wxBitmap KiScaledBitmap( const wxBitmap& aBitmap, wxWindow* aWindow )
  141. {
  142. const int scale = KiIconScale( aWindow );
  143. if( scale == 4 )
  144. {
  145. return wxBitmap( aBitmap );
  146. }
  147. else
  148. {
  149. wxImage image = aBitmap.ConvertToImage();
  150. image.Rescale( scale * image.GetWidth() / 4, scale * image.GetHeight() / 4,
  151. wxIMAGE_QUALITY_BILINEAR );
  152. return wxBitmap( image );
  153. }
  154. }
  155. wxBitmap* KiBitmapNew( BITMAPS aBitmap )
  156. {
  157. wxBitmap* bitmap = new wxBitmap( GetBitmapStore()->GetBitmap( aBitmap ) );
  158. return bitmap;
  159. }