KiCad PCB EDA Suite
bitmap.cpp
Go to the documentation of this file.
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 
25 
26 #include <wx/image.h>
27 #include <wx/bitmap.h>
28 #include <wx/mstream.h>
29 #include <wx/menu.h>
30 #include <wx/menuitem.h>
31 #include <wx/aui/auibar.h>
32 
33 #include <cstdint>
34 #include <mutex>
35 #include <unordered_map>
36 
37 #include <common.h>
38 #include <bitmaps.h>
39 #include <pgm_base.h>
40 #include <eda_base_frame.h>
41 
42 
45  int scale;
46 
47  bool operator==( SCALED_BITMAP_ID const& other ) const noexcept
48  {
49  return bitmap == other.bitmap && scale == other.scale;
50  }
51 };
52 
53 
54 namespace std {
55  template<> struct hash<SCALED_BITMAP_ID>
56  {
58  typedef std::size_t result_type;
59 
60  result_type operator()( argument_type const& id ) const noexcept
61  {
62  static const bool sz64 = sizeof( uintptr_t ) == 8;
63  static const size_t mask = sz64 ? 0xF000000000000000uLL : 0xF0000000uL;
64  static const size_t offset = sz64 ? 60 : 28;
65 
66  // The hash only needs to be fast and simple, not necessarily accurate - a collision
67  // only makes things slower, not broken. BITMAP_DEF is a pointer, so the most
68  // significant several bits are generally going to be the same for all. Just convert
69  // it to an integer and stuff the scale factor into those bits.
70  return
71  ( (uintptr_t)( id.bitmap ) & ~mask ) |
72  ( ( (uintptr_t)( id.scale ) & 0xF ) << offset );
73  }
74  };
75 }
76 
77 
78 wxBitmap KiBitmap( BITMAP_DEF aBitmap )
79 {
80  wxMemoryInputStream is( aBitmap->png, aBitmap->byteCount );
81  wxImage image( is, wxBITMAP_TYPE_PNG );
82  wxBitmap bitmap( image );
83 
84  return bitmap;
85 }
86 
87 
88 int KiIconScale( wxWindow* aWindow )
89 {
90  const int vert_size = aWindow->ConvertDialogToPixels( wxSize( 0, 8 ) ).y;
91 
92  // Autoscale won't exceed unity until the system has quite high resolution,
93  // because we don't want the icons to look obviously scaled on a system
94  // where it's easy to see it.
95 
96  if( vert_size > 34 ) return 8;
97  else if( vert_size > 29 ) return 7;
98  else if( vert_size > 24 ) return 6;
99  else return 4;
100 }
101 
102 
103 static int get_scale_factor( EDA_BASE_FRAME* aWindow )
104 {
105  int requested_scale;
106  Pgm().CommonSettings()->Read( ICON_SCALE_KEY, &requested_scale, 0 );
107 
108  if( requested_scale > 0 )
109  return requested_scale;
110  else
111  return KiIconScale( aWindow );
112 }
113 
114 
115 wxBitmap KiScaledBitmap( BITMAP_DEF aBitmap, EDA_BASE_FRAME* aWindow )
116 {
117  // Bitmap conversions are cached because they can be slow.
118  static std::unordered_map<SCALED_BITMAP_ID, wxBitmap> bitmap_cache;
119  static std::mutex bitmap_cache_mutex;
120  const int scale = get_scale_factor( aWindow );
121 
122  SCALED_BITMAP_ID id = { aBitmap, scale };
123 
124  std::lock_guard<std::mutex> guard( bitmap_cache_mutex );
125  auto it = bitmap_cache.find( id );
126 
127  if( it != bitmap_cache.end() )
128  {
129  return it->second;
130  }
131  else
132  {
133  wxMemoryInputStream is( aBitmap->png, aBitmap->byteCount );
134  wxImage image( is, wxBITMAP_TYPE_PNG );
135 
136  // Bilinear seems to genuinely look better for these line-drawing icons
137  // than bicubic, despite claims in the wx documentation that bicubic is
138  // "highest quality". I don't recommend changing this. Bicubic looks
139  // blurry and makes me want an eye exam.
140  image.Rescale( scale * image.GetWidth() / 4, scale * image.GetHeight() / 4,
141  wxIMAGE_QUALITY_BILINEAR );
142  return bitmap_cache.emplace( id, wxBitmap( image ) ).first->second;
143  }
144 }
145 
146 
147 void KiScaledSeparator( wxAuiToolBar* aToolbar, EDA_BASE_FRAME* aWindow )
148 {
149  const int scale = get_scale_factor( aWindow );
150 
151  if( scale > 4 )
152  {
153  aToolbar->AddSpacer( 16 * ( scale - 4 ) / 4 );
154  }
155 
156  aToolbar->AddSeparator();
157 
158  if( scale > 4 )
159  {
160  aToolbar->AddSpacer( 16 * ( scale - 4 ) / 4 );
161  }
162 }
163 
164 
165 wxBitmap* KiBitmapNew( BITMAP_DEF aBitmap )
166 {
167  wxMemoryInputStream is( aBitmap->png, aBitmap->byteCount );
168  wxImage image( is, wxBITMAP_TYPE_PNG );
169  wxBitmap* bitmap = new wxBitmap( image );
170 
171  return bitmap;
172 }
173 
174 
175 wxMenuItem* AddMenuItem( wxMenu* aMenu, int aId, const wxString& aText,
176  const wxBitmap& aImage, wxItemKind aType = wxITEM_NORMAL )
177 {
178  wxMenuItem* item;
179 
180  item = new wxMenuItem( aMenu, aId, aText, wxEmptyString, aType );
181 
182  // Retrieve the global applicaton show icon option:
183  bool useImagesInMenus;
184  Pgm().CommonSettings()->Read( USE_ICONS_IN_MENUS_KEY, &useImagesInMenus );
185 
186  if( useImagesInMenus )
187  {
188  if( aType == wxITEM_CHECK || aType == wxITEM_RADIO )
189  {
190  #if defined( __WINDOWS__ )
191  item->SetBitmaps( KiBitmap( checked_ok_xpm ), aImage );
192  // A workaround to a strange bug on Windows, wx Widgets 3.0:
193  // size of bitmaps is not taken in account for wxITEM_{CHECK,RADIO} menu
194  // unless we call SetFont
195  item->SetFont( *wxNORMAL_FONT );
196  #endif
197  }
198  else if( aType != wxITEM_RADIO )
199  {
200  item->SetBitmap( aImage );
201  }
202  }
203 
204  aMenu->Append( item );
205 
206  return item;
207 }
208 
209 
210 wxMenuItem* AddMenuItem( wxMenu* aMenu, int aId, const wxString& aText,
211  const wxString& aHelpText, const wxBitmap& aImage,
212  wxItemKind aType = wxITEM_NORMAL )
213 {
214  wxMenuItem* item;
215 
216  item = new wxMenuItem( aMenu, aId, aText, aHelpText, aType );
217 
218  // Retrieve the global applicaton show icon option:
219  bool useImagesInMenus;
220  Pgm().CommonSettings()->Read( USE_ICONS_IN_MENUS_KEY, &useImagesInMenus );
221 
222  if( useImagesInMenus )
223  {
224  if( aType == wxITEM_CHECK || aType == wxITEM_RADIO )
225  {
226  #if defined( __WINDOWS__ )
227  item->SetBitmaps( KiBitmap( checked_ok_xpm ), aImage );
228  // A workaround to a strange bug on Windows, wx Widgets 3.0:
229  // size of bitmaps is not taken in account for wxITEM_{CHECK,RADIO} menu
230  // unless we call SetFont
231  item->SetFont( *wxNORMAL_FONT );
232  #endif
233  }
234  else if( aType != wxITEM_RADIO )
235  {
236  item->SetBitmap( aImage );
237  }
238  }
239 
240  aMenu->Append( item );
241 
242  return item;
243 }
244 
245 
246 wxMenuItem* AddMenuItem( wxMenu* aMenu, wxMenu* aSubMenu, int aId,
247  const wxString& aText, const wxBitmap& aImage )
248 {
249  wxMenuItem* item;
250 
251  item = new wxMenuItem( aMenu, aId, aText );
252  item->SetSubMenu( aSubMenu );
253 
254  // Retrieve the global applicaton show icon option:
255  bool useImagesInMenus;
256  Pgm().CommonSettings()->Read( USE_ICONS_IN_MENUS_KEY, &useImagesInMenus );
257 
258  if( useImagesInMenus )
259  item->SetBitmap( aImage );
260 
261  aMenu->Append( item );
262 
263  return item;
264 }
265 
266 
267 wxMenuItem* AddMenuItem( wxMenu* aMenu, wxMenu* aSubMenu, int aId,
268  const wxString& aText, const wxString& aHelpText,
269  const wxBitmap& aImage )
270 {
271  wxMenuItem* item;
272 
273  item = new wxMenuItem( aMenu, aId, aText, aHelpText );
274  item->SetSubMenu( aSubMenu );
275 
276  // Retrieve the global applicaton show icon option:
277  bool useImagesInMenus;
278  Pgm().CommonSettings()->Read( USE_ICONS_IN_MENUS_KEY, &useImagesInMenus );
279 
280  if( useImagesInMenus )
281  item->SetBitmap( aImage );
282 
283  aMenu->Append( item );
284 
285  return item;
286 }
PNG memory record (file in memory).
Definition: bitmap_types.h:41
wxMenuItem * AddMenuItem(wxMenu *aMenu, int aId, const wxString &aText, const wxBitmap &aImage, wxItemKind aType=wxITEM_NORMAL)
Function AddMenuItem is an inline helper function to create and insert a menu item with an icon into ...
Definition: bitmap.cpp:175
int KiIconScale(wxWindow *aWindow)
Function KiIconScale Returns the automatic scale factor that would be used for a given window by KiSc...
Definition: bitmap.cpp:88
Template specialization to enable wxStrings for certain containers (e.g. unordered_map) ...
Definition: bitmap.cpp:54
PGM_BASE & Pgm()
The global Program "get" accessor.
Definition: kicad.cpp:66
wxBitmap KiScaledBitmap(BITMAP_DEF aBitmap, EDA_BASE_FRAME *aWindow)
Function KiScaledBitmap Constructs a wxBitmap from a memory record, scaling it if device DPI demands ...
Definition: bitmap.cpp:115
const unsigned char * png
Definition: bitmap_types.h:43
wxBitmap KiBitmap(BITMAP_DEF aBitmap)
Function KiBitmap constructs a wxBitmap from a memory record, held in a BITMAP_DEF.
Definition: bitmap.cpp:78
result_type operator()(argument_type const &id) const noexcept
Definition: bitmap.cpp:60
wxBitmap * KiBitmapNew(BITMAP_DEF aBitmap)
Function KiBitmapNew allocates a wxBitmap on heap from a memory record, held in a BITMAP_DEF...
Definition: bitmap.cpp:165
SCALED_BITMAP_ID argument_type
Definition: bitmap.cpp:57
Base window classes and related definitions.
#define ICON_SCALE_KEY
Definition: pgm_base.h:44
BITMAP_DEF bitmap
Definition: bitmap.cpp:44
see class PGM_BASE
Class EDA_BASE_FRAME is the base frame for deriving all KiCad main window classes.
VTBL_ENTRY wxConfigBase * CommonSettings() const
Definition: pgm_base.h:162
#define USE_ICONS_IN_MENUS_KEY
Definition: pgm_base.h:43
The common library.
void KiScaledSeparator(wxAuiToolBar *aToolbar, EDA_BASE_FRAME *aWindow)
Function KiScaledSeparator Adds a separator to the given toolbar scaled the same way as KiScaledBitma...
Definition: bitmap.cpp:147
bool operator==(SCALED_BITMAP_ID const &other) const noexcept
Definition: bitmap.cpp:47
static int get_scale_factor(EDA_BASE_FRAME *aWindow)
Definition: bitmap.cpp:103