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