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.

277 lines
8.0 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-2018 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/mstream.h>
  27. #include <wx/menu.h>
  28. #include <wx/menuitem.h>
  29. #include <wx/aui/auibar.h>
  30. #include <cstdint>
  31. #include <mutex>
  32. #include <unordered_map>
  33. #include <common.h>
  34. #include <bitmaps.h>
  35. #include <pgm_base.h>
  36. #include <eda_base_frame.h>
  37. struct SCALED_BITMAP_ID {
  38. BITMAP_DEF bitmap;
  39. int scale;
  40. bool operator==( SCALED_BITMAP_ID const& other ) const noexcept
  41. {
  42. return bitmap == other.bitmap && scale == other.scale;
  43. }
  44. };
  45. namespace std {
  46. template<> struct hash<SCALED_BITMAP_ID>
  47. {
  48. typedef SCALED_BITMAP_ID argument_type;
  49. typedef std::size_t result_type;
  50. result_type operator()( argument_type const& id ) const noexcept
  51. {
  52. static const bool sz64 = sizeof( uintptr_t ) == 8;
  53. static const size_t mask = sz64 ? 0xF000000000000000uLL : 0xF0000000uL;
  54. static const size_t offset = sz64 ? 28 : 60;
  55. // The hash only needs to be fast and simple, not necessarily accurate - a collision
  56. // only makes things slower, not broken. BITMAP_DEF is a pointer, so the most
  57. // significant several bits are generally going to be the same for all. Just convert
  58. // it to an integer and stuff the scale factor into those bits.
  59. return
  60. ( (uintptr_t)( id.bitmap ) & ~mask ) |
  61. ( ( (uintptr_t)( id.scale ) & 0xF ) << offset );
  62. }
  63. };
  64. }
  65. wxBitmap KiBitmap( BITMAP_DEF aBitmap )
  66. {
  67. wxMemoryInputStream is( aBitmap->png, aBitmap->byteCount );
  68. wxImage image( is, wxBITMAP_TYPE_PNG );
  69. wxBitmap bitmap( image );
  70. return bitmap;
  71. }
  72. int KiIconScale( wxWindow* aWindow )
  73. {
  74. const int vert_size = aWindow->ConvertDialogToPixels( wxSize( 0, 8 ) ).y;
  75. // Autoscale won't exceed unity until the system has quite high resolution,
  76. // because we don't want the icons to look obviously scaled on a system
  77. // where it's easy to see it.
  78. if( vert_size > 34 ) return 8;
  79. else if( vert_size > 29 ) return 7;
  80. else if( vert_size > 24 ) return 6;
  81. else return 4;
  82. }
  83. static int get_scale_factor( EDA_BASE_FRAME* aWindow )
  84. {
  85. const int requested_scale = aWindow->GetIconScale();
  86. if( requested_scale > 0 )
  87. return requested_scale;
  88. else
  89. return KiIconScale( aWindow );
  90. }
  91. wxBitmap KiScaledBitmap( BITMAP_DEF aBitmap, EDA_BASE_FRAME* aWindow )
  92. {
  93. // Bitmap conversions are cached because they can be slow.
  94. static std::unordered_map<SCALED_BITMAP_ID, wxBitmap> bitmap_cache;
  95. static std::mutex bitmap_cache_mutex;
  96. const int scale = get_scale_factor( aWindow );
  97. SCALED_BITMAP_ID id = { aBitmap, scale };
  98. std::lock_guard<std::mutex> guard( bitmap_cache_mutex );
  99. auto it = bitmap_cache.find( id );
  100. if( it != bitmap_cache.end() )
  101. {
  102. return it->second;
  103. }
  104. else
  105. {
  106. wxMemoryInputStream is( aBitmap->png, aBitmap->byteCount );
  107. wxImage image( is, wxBITMAP_TYPE_PNG );
  108. // Bilinear seems to genuinely look better for these line-drawing icons
  109. // than bicubic, despite claims in the wx documentation that bicubic is
  110. // "highest quality". I don't recommend changing this. Bicubic looks
  111. // blurry and makes me want an eye exam.
  112. image.Rescale( scale * image.GetWidth() / 4, scale * image.GetHeight() / 4,
  113. wxIMAGE_QUALITY_BILINEAR );
  114. return bitmap_cache.emplace( id, wxBitmap( image ) ).first->second;
  115. }
  116. }
  117. void KiScaledSeparator( wxAuiToolBar* aToolbar, EDA_BASE_FRAME* aWindow )
  118. {
  119. const int scale = get_scale_factor( aWindow );
  120. if( scale > 4 )
  121. {
  122. aToolbar->AddSpacer( 16 * ( scale - 4 ) / 4 );
  123. }
  124. aToolbar->AddSeparator();
  125. if( scale > 4 )
  126. {
  127. aToolbar->AddSpacer( 16 * ( scale - 4 ) / 4 );
  128. }
  129. }
  130. wxBitmap* KiBitmapNew( BITMAP_DEF aBitmap )
  131. {
  132. wxMemoryInputStream is( aBitmap->png, aBitmap->byteCount );
  133. wxImage image( is, wxBITMAP_TYPE_PNG );
  134. wxBitmap* bitmap = new wxBitmap( image );
  135. return bitmap;
  136. }
  137. wxMenuItem* AddMenuItem( wxMenu* aMenu, int aId, const wxString& aText,
  138. const wxBitmap& aImage, wxItemKind aType = wxITEM_NORMAL )
  139. {
  140. wxMenuItem* item;
  141. item = new wxMenuItem( aMenu, aId, aText, wxEmptyString, aType );
  142. // Retrieve the global applicaton show icon option:
  143. bool useImagesInMenus = Pgm().GetUseIconsInMenus();
  144. if( useImagesInMenus )
  145. {
  146. if( aType == wxITEM_CHECK || aType == wxITEM_RADIO )
  147. {
  148. #if defined( __WINDOWS__ )
  149. item->SetBitmaps( KiBitmap( checked_ok_xpm ), aImage );
  150. // A workaround to a strange bug on Windows, wx Widgets 3.0:
  151. // size of bitmaps is not taken in account for wxITEM_{CHECK,RADIO} menu
  152. // unless we call SetFont
  153. item->SetFont( *wxNORMAL_FONT );
  154. #endif
  155. }
  156. else
  157. item->SetBitmap( aImage );
  158. }
  159. aMenu->Append( item );
  160. return item;
  161. }
  162. wxMenuItem* AddMenuItem( wxMenu* aMenu, int aId, const wxString& aText,
  163. const wxString& aHelpText, const wxBitmap& aImage,
  164. wxItemKind aType = wxITEM_NORMAL )
  165. {
  166. wxMenuItem* item;
  167. item = new wxMenuItem( aMenu, aId, aText, aHelpText, aType );
  168. // Retrieve the global applicaton show icon option:
  169. bool useImagesInMenus = Pgm().GetUseIconsInMenus();
  170. if( useImagesInMenus )
  171. {
  172. if( aType == wxITEM_CHECK || aType == wxITEM_RADIO )
  173. {
  174. #if defined( __WINDOWS__ )
  175. item->SetBitmaps( KiBitmap( checked_ok_xpm ), aImage );
  176. // A workaround to a strange bug on Windows, wx Widgets 3.0:
  177. // size of bitmaps is not taken in account for wxITEM_{CHECK,RADIO} menu
  178. // unless we call SetFont
  179. item->SetFont( *wxNORMAL_FONT );
  180. #endif
  181. }
  182. else
  183. item->SetBitmap( aImage );
  184. }
  185. aMenu->Append( item );
  186. return item;
  187. }
  188. wxMenuItem* AddMenuItem( wxMenu* aMenu, wxMenu* aSubMenu, int aId,
  189. const wxString& aText, const wxBitmap& aImage )
  190. {
  191. wxMenuItem* item;
  192. item = new wxMenuItem( aMenu, aId, aText );
  193. item->SetSubMenu( aSubMenu );
  194. // Retrieve the global applicaton show icon option:
  195. bool useImagesInMenus = Pgm().GetUseIconsInMenus();
  196. if( useImagesInMenus )
  197. item->SetBitmap( aImage );
  198. aMenu->Append( item );
  199. return item;
  200. }
  201. wxMenuItem* AddMenuItem( wxMenu* aMenu, wxMenu* aSubMenu, int aId,
  202. const wxString& aText, const wxString& aHelpText,
  203. const wxBitmap& aImage )
  204. {
  205. wxMenuItem* item;
  206. item = new wxMenuItem( aMenu, aId, aText, aHelpText );
  207. item->SetSubMenu( aSubMenu );
  208. // Retrieve the global applicaton show icon option:
  209. bool useImagesInMenus = Pgm().GetUseIconsInMenus();
  210. if( useImagesInMenus )
  211. item->SetBitmap( aImage );
  212. aMenu->Append( item );
  213. return item;
  214. }