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 ? 28 : 60;
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  const int requested_scale = aWindow->GetIconScale();
106 
107  if( requested_scale > 0 )
108  return requested_scale;
109  else
110  return KiIconScale( aWindow );
111 }
112 
113 
114 wxBitmap KiScaledBitmap( BITMAP_DEF aBitmap, EDA_BASE_FRAME* aWindow )
115 {
116  // Bitmap conversions are cached because they can be slow.
117  static std::unordered_map<SCALED_BITMAP_ID, wxBitmap> bitmap_cache;
118  static std::mutex bitmap_cache_mutex;
119  const int scale = get_scale_factor( aWindow );
120 
121  SCALED_BITMAP_ID id = { aBitmap, scale };
122 
123  std::lock_guard<std::mutex> guard( bitmap_cache_mutex );
124  auto it = bitmap_cache.find( id );
125 
126  if( it != bitmap_cache.end() )
127  {
128  return it->second;
129  }
130  else
131  {
132  wxMemoryInputStream is( aBitmap->png, aBitmap->byteCount );
133  wxImage image( is, wxBITMAP_TYPE_PNG );
134 
135  // Bilinear seems to genuinely look better for these line-drawing icons
136  // than bicubic, despite claims in the wx documentation that bicubic is
137  // "highest quality". I don't recommend changing this. Bicubic looks
138  // blurry and makes me want an eye exam.
139  image.Rescale( scale * image.GetWidth() / 4, scale * image.GetHeight() / 4,
140  wxIMAGE_QUALITY_BILINEAR );
141  return bitmap_cache.emplace( id, wxBitmap( image ) ).first->second;
142  }
143 }
144 
145 
146 void KiScaledSeparator( wxAuiToolBar* aToolbar, EDA_BASE_FRAME* aWindow )
147 {
148  const int scale = get_scale_factor( aWindow );
149 
150  if( scale > 4 )
151  {
152  aToolbar->AddSpacer( 16 * ( scale - 4 ) / 4 );
153  }
154 
155  aToolbar->AddSeparator();
156 
157  if( scale > 4 )
158  {
159  aToolbar->AddSpacer( 16 * ( scale - 4 ) / 4 );
160  }
161 }
162 
163 
164 wxBitmap* KiBitmapNew( BITMAP_DEF aBitmap )
165 {
166  wxMemoryInputStream is( aBitmap->png, aBitmap->byteCount );
167  wxImage image( is, wxBITMAP_TYPE_PNG );
168  wxBitmap* bitmap = new wxBitmap( image );
169 
170  return bitmap;
171 }
172 
173 
174 wxMenuItem* AddMenuItem( wxMenu* aMenu, int aId, const wxString& aText,
175  const wxBitmap& aImage, wxItemKind aType = wxITEM_NORMAL )
176 {
177  wxMenuItem* item;
178 
179  item = new wxMenuItem( aMenu, aId, aText, wxEmptyString, aType );
180 
181  // Retrieve the global applicaton show icon option:
182  bool useImagesInMenus = Pgm().GetUseIconsInMenus();
183 
184  if( useImagesInMenus )
185  {
186  if( aType == wxITEM_CHECK || aType == wxITEM_RADIO )
187  {
188  #if defined( __WINDOWS__ )
189  item->SetBitmaps( KiBitmap( checked_ok_xpm ), aImage );
190  // A workaround to a strange bug on Windows, wx Widgets 3.0:
191  // size of bitmaps is not taken in account for wxITEM_{CHECK,RADIO} menu
192  // unless we call SetFont
193  item->SetFont( *wxNORMAL_FONT );
194  #endif
195  }
196  else if( aType != wxITEM_RADIO )
197  {
198  item->SetBitmap( aImage );
199  }
200  }
201 
202  aMenu->Append( item );
203 
204  return item;
205 }
206 
207 
208 wxMenuItem* AddMenuItem( wxMenu* aMenu, int aId, const wxString& aText,
209  const wxString& aHelpText, const wxBitmap& aImage,
210  wxItemKind aType = wxITEM_NORMAL )
211 {
212  wxMenuItem* item;
213 
214  item = new wxMenuItem( aMenu, aId, aText, aHelpText, aType );
215 
216  // Retrieve the global applicaton show icon option:
217  bool useImagesInMenus = Pgm().GetUseIconsInMenus();
218 
219  if( useImagesInMenus )
220  {
221  if( aType == wxITEM_CHECK || aType == wxITEM_RADIO )
222  {
223  #if defined( __WINDOWS__ )
224  item->SetBitmaps( KiBitmap( checked_ok_xpm ), aImage );
225  // A workaround to a strange bug on Windows, wx Widgets 3.0:
226  // size of bitmaps is not taken in account for wxITEM_{CHECK,RADIO} menu
227  // unless we call SetFont
228  item->SetFont( *wxNORMAL_FONT );
229  #endif
230  }
231  else if( aType != wxITEM_RADIO )
232  {
233  item->SetBitmap( aImage );
234  }
235  }
236 
237  aMenu->Append( item );
238 
239  return item;
240 }
241 
242 
243 wxMenuItem* AddMenuItem( wxMenu* aMenu, wxMenu* aSubMenu, int aId,
244  const wxString& aText, const wxBitmap& aImage )
245 {
246  wxMenuItem* item;
247 
248  item = new wxMenuItem( aMenu, aId, aText );
249  item->SetSubMenu( aSubMenu );
250 
251  // Retrieve the global applicaton show icon option:
252  bool useImagesInMenus = Pgm().GetUseIconsInMenus();
253 
254  if( useImagesInMenus )
255  item->SetBitmap( aImage );
256 
257  aMenu->Append( item );
258 
259  return item;
260 }
261 
262 
263 wxMenuItem* AddMenuItem( wxMenu* aMenu, wxMenu* aSubMenu, int aId,
264  const wxString& aText, const wxString& aHelpText,
265  const wxBitmap& aImage )
266 {
267  wxMenuItem* item;
268 
269  item = new wxMenuItem( aMenu, aId, aText, aHelpText );
270  item->SetSubMenu( aSubMenu );
271 
272  // Retrieve the global applicaton show icon option:
273  bool useImagesInMenus = Pgm().GetUseIconsInMenus();
274 
275  if( useImagesInMenus )
276  item->SetBitmap( aImage );
277 
278  aMenu->Append( item );
279 
280  return item;
281 }
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:174
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:65
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:114
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:164
SCALED_BITMAP_ID argument_type
Definition: bitmap.cpp:57
Base window classes and related definitions.
bool GetUseIconsInMenus()
Definition: pgm_base.h:328
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.
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:146
virtual int GetIconScale()
Function GetIconScale.
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