1 ///////////////////////////////////////////////////////////////////////////////
2 // Name:        src/common/arttango.cpp
3 // Purpose:     art provider using embedded PNG versions of Tango icons
4 // Author:      Vadim Zeitlin
5 // Created:     2010-12-27
6 // Copyright:   (c) 2010 Vadim Zeitlin <vadim@wxwidgets.org>
7 // Licence:     wxWindows licence
8 ///////////////////////////////////////////////////////////////////////////////
9 
10 // ============================================================================
11 // declarations
12 // ============================================================================
13 
14 // ----------------------------------------------------------------------------
15 // headers
16 // ----------------------------------------------------------------------------
17 
18 // for compilers that support precompilation, includes "wx.h".
19 #include "wx/wxprec.h"
20 
21 #ifdef __BORLANDC__
22     #pragma hdrstop
23 #endif
24 
25 #if wxUSE_ARTPROVIDER_TANGO
26 
27 #ifndef WX_PRECOMP
28     #include "wx/image.h"
29     #include "wx/log.h"
30 #endif // WX_PRECOMP
31 
32 #include "wx/artprov.h"
33 
34 #include "wx/mstream.h"
35 
36 // ----------------------------------------------------------------------------
37 // image data
38 // ----------------------------------------------------------------------------
39 
40 // All files in art/tango in alphabetical order:
41 #include "../../art/tango/application_x_executable.h"
42 #include "../../art/tango/dialog_error.h"
43 #include "../../art/tango/dialog_information.h"
44 #include "../../art/tango/dialog_warning.h"
45 #include "../../art/tango/document_new.h"
46 #include "../../art/tango/document_open.h"
47 #include "../../art/tango/document_print.h"
48 #include "../../art/tango/document_save.h"
49 #include "../../art/tango/document_save_as.h"
50 #include "../../art/tango/drive_harddisk.h"
51 #include "../../art/tango/drive_optical.h"
52 #include "../../art/tango/drive_removable_media.h"
53 #include "../../art/tango/edit_copy.h"
54 #include "../../art/tango/edit_cut.h"
55 #include "../../art/tango/edit_delete.h"
56 #include "../../art/tango/edit_find.h"
57 #include "../../art/tango/edit_find_replace.h"
58 #include "../../art/tango/edit_paste.h"
59 #include "../../art/tango/edit_redo.h"
60 #include "../../art/tango/edit_undo.h"
61 #include "../../art/tango/folder.h"
62 #include "../../art/tango/folder_new.h"
63 #include "../../art/tango/folder_open.h"
64 #include "../../art/tango/go_down.h"
65 #include "../../art/tango/go_first.h"
66 #include "../../art/tango/go_home.h"
67 #include "../../art/tango/go_last.h"
68 #include "../../art/tango/go_next.h"
69 #include "../../art/tango/go_previous.h"
70 #include "../../art/tango/go_up.h"
71 #include "../../art/tango/image_missing.h"
72 #include "../../art/tango/text_x_generic.h"
73 #include "../../art/tango/list_add.h"
74 #include "../../art/tango/list_remove.h"
75 
76 // ----------------------------------------------------------------------------
77 // art provider class
78 // ----------------------------------------------------------------------------
79 
80 namespace
81 {
82 
83 class wxTangoArtProvider : public wxArtProvider
84 {
85 public:
wxTangoArtProvider()86     wxTangoArtProvider()
87     {
88         m_imageHandledAdded = false;
89     }
90 
91 protected:
92     virtual wxBitmap CreateBitmap(const wxArtID& id,
93                                   const wxArtClient& client,
94                                   const wxSize& size);
95 
96 private:
97     bool m_imageHandledAdded;
98 
99     wxDECLARE_NO_COPY_CLASS(wxTangoArtProvider);
100 };
101 
102 } // anonymous namespace
103 
104 // ============================================================================
105 // implementation
106 // ============================================================================
107 
108 wxBitmap
CreateBitmap(const wxArtID & id,const wxArtClient & client,const wxSize & sizeHint)109 wxTangoArtProvider::CreateBitmap(const wxArtID& id,
110                                  const wxArtClient& client,
111                                  const wxSize& sizeHint)
112 {
113     // Array indexed by the id names with pointers to image data in 16 and 32
114     // pixel sizes as values. The order of the elements in this array is the
115     // same as the definition order in wx/artprov.h. While it's not very
116     // logical, this should make it simpler to add new icons later. Notice that
117     // most elements without Tango equivalents are simply omitted.
118 
119     // To avoid repetition use BITMAP_DATA to only specify the image name once
120     // (this is especially important if we decide to add more image sizes
121     // later).
122     #define BITMAP_ARRAY_NAME(name, size) \
123         name ## _ ## size ## x ## size ## _png
124     #define BITMAP_DATA_FOR_SIZE(name, size) \
125         BITMAP_ARRAY_NAME(name, size), sizeof(BITMAP_ARRAY_NAME(name, size))
126     #define BITMAP_DATA(name) \
127         BITMAP_DATA_FOR_SIZE(name, 16), BITMAP_DATA_FOR_SIZE(name, 24)
128 
129     static const struct BitmapEntry
130     {
131         const char *id;
132         const unsigned char *data16;
133         size_t len16;
134         const unsigned char *data24;
135         size_t len24;
136     } s_allBitmaps[] =
137     {
138         // Tango does have bookmark-new but no matching bookmark-delete and
139         // using mismatching icons would be ugly so we don't provide this one
140         // neither, we should add both of them if Tango ever adds the other one.
141         //{ wxART_ADD_BOOKMARK,       BITMAP_DATA(bookmark_new)},
142         //{ wxART_DEL_BOOKMARK,       BITMAP_DATA() },
143 
144         { wxART_GO_BACK,            BITMAP_DATA(go_previous)                },
145         { wxART_GO_FORWARD,         BITMAP_DATA(go_next)                    },
146         { wxART_GO_UP,              BITMAP_DATA(go_up)                      },
147         { wxART_GO_DOWN,            BITMAP_DATA(go_down)                    },
148         // wxART_GO_TO_PARENT doesn't seem to exist in Tango
149         { wxART_GO_HOME,            BITMAP_DATA(go_home)                    },
150         { wxART_GOTO_FIRST,         BITMAP_DATA(go_first)                   },
151         { wxART_GOTO_LAST,          BITMAP_DATA(go_last)                    },
152 
153         { wxART_FILE_OPEN,          BITMAP_DATA(document_open)              },
154         { wxART_FILE_SAVE,          BITMAP_DATA(document_save)              },
155         { wxART_FILE_SAVE_AS,       BITMAP_DATA(document_save_as)           },
156         { wxART_PRINT,              BITMAP_DATA(document_print)             },
157 
158         // Should we use help-browser for wxART_HELP?
159 
160         { wxART_NEW_DIR,            BITMAP_DATA(folder_new)                 },
161         { wxART_HARDDISK,           BITMAP_DATA(drive_harddisk)             },
162         // drive-removable-media seems to be better than media-floppy
163         { wxART_FLOPPY,             BITMAP_DATA(drive_removable_media)      },
164         { wxART_CDROM,              BITMAP_DATA(drive_optical)              },
165         { wxART_REMOVABLE,          BITMAP_DATA(drive_removable_media)      },
166 
167         { wxART_FOLDER,             BITMAP_DATA(folder)                     },
168         { wxART_FOLDER_OPEN,        BITMAP_DATA(folder_open)                },
169         // wxART_GO_DIR_UP doesn't seem to exist in Tango
170 
171         { wxART_EXECUTABLE_FILE,    BITMAP_DATA(application_x_executable)   },
172         { wxART_NORMAL_FILE,        BITMAP_DATA(text_x_generic)             },
173 
174         // There is no dialog-question in Tango so use the information icon
175         // too, this is better for consistency and we do have a precedent for
176         // doing this as Windows Vista/7 does the same thing natively.
177         { wxART_ERROR,              BITMAP_DATA(dialog_error)               },
178         { wxART_QUESTION,           BITMAP_DATA(dialog_information)         },
179         { wxART_WARNING,            BITMAP_DATA(dialog_warning)             },
180         { wxART_INFORMATION,        BITMAP_DATA(dialog_information)         },
181 
182         { wxART_MISSING_IMAGE,      BITMAP_DATA(image_missing)              },
183 
184         { wxART_COPY,               BITMAP_DATA(edit_copy)                  },
185         { wxART_CUT,                BITMAP_DATA(edit_cut)                   },
186         { wxART_PASTE,              BITMAP_DATA(edit_paste)                 },
187         { wxART_DELETE,             BITMAP_DATA(edit_delete)                },
188         { wxART_NEW,                BITMAP_DATA(document_new)               },
189         { wxART_UNDO,               BITMAP_DATA(edit_undo)                  },
190         { wxART_REDO,               BITMAP_DATA(edit_redo)                  },
191 
192         { wxART_PLUS,               BITMAP_DATA(list_add)                   },
193         { wxART_MINUS,              BITMAP_DATA(list_remove)                },
194 
195         // Surprisingly Tango doesn't seem to have neither wxART_CLOSE nor
196         // wxART_QUIT. We could use system-log-out for the latter but it
197         // doesn't seem quite right.
198 
199         { wxART_FIND,               BITMAP_DATA(edit_find)                  },
200         { wxART_FIND_AND_REPLACE,   BITMAP_DATA(edit_find_replace)          },
201     };
202 
203     #undef BITMAP_ARRAY_NAME
204     #undef BITMAP_DATA_FOR_SIZE
205     #undef BITMAP_DATA
206 
207     for ( unsigned n = 0; n < WXSIZEOF(s_allBitmaps); n++ )
208     {
209         const BitmapEntry& entry = s_allBitmaps[n];
210         if ( entry.id != id )
211             continue;
212 
213         // This is one of the bitmaps that we have, determine in which size we
214         // should return it.
215 
216         wxSize size;
217         bool sizeIsAHint;
218         if ( sizeHint == wxDefaultSize )
219         {
220             // Use the normal platform-specific icon size.
221             size = GetNativeSizeHint(client);
222 
223             if ( size == wxDefaultSize )
224             {
225                 // If we failed to get it, determine the best size more or less
226                 // arbitrarily. This definitely won't look good but then it
227                 // shouldn't normally happen, all platforms should implement
228                 // GetNativeSizeHint() properly.
229                 if ( client == wxART_MENU || client == wxART_BUTTON )
230                     size = wxSize(16, 16);
231                 else
232                     size = wxSize(24, 24);
233             }
234 
235             // We should return the icon of exactly this size so it's more than
236             // just a hint.
237             sizeIsAHint = false;
238         }
239         else // We have a size hint
240         {
241             // Use it for determining the version of the icon to return.
242             size = sizeHint;
243 
244             // But we don't need to return the image of exactly the same size
245             // as the hint, after all it's just that, a hint.
246             sizeIsAHint = true;
247         }
248 
249         enum
250         {
251             TangoSize_16,
252             TangoSize_24
253         } tangoSize;
254 
255         // We prefer to downscale the image rather than upscale it if possible
256         // so use the smaller one if we can, otherwise the large one.
257         if ( size.x <= 16 && size.y <= 16 )
258             tangoSize = TangoSize_16;
259         else
260             tangoSize = TangoSize_24;
261 
262         const unsigned char *data;
263         size_t len;
264         switch ( tangoSize )
265         {
266             default:
267                 wxFAIL_MSG( "Unsupported Tango bitmap size" );
268                 // fall through
269 
270             case TangoSize_16:
271                 data = entry.data16;
272                 len = entry.len16;
273                 break;
274 
275             case TangoSize_24:
276                 data = entry.data24;
277                 len = entry.len24;
278                 break;
279         }
280 
281         wxMemoryInputStream is(data, len);
282 
283         // Before reading the image data from the stream for the first time,
284         // add the handler for PNG images: we do it here and not in, say,
285         // InitTangoProvider() to do it as lately as possible and so to avoid
286         // the asserts about adding an already added handler if the user code
287         // adds the handler itself.
288         if ( !m_imageHandledAdded )
289         {
290             // Of course, if the user code did add it already, we have nothing
291             // to do.
292             if ( !wxImage::FindHandler(wxBITMAP_TYPE_PNG) )
293                 wxImage::AddHandler(new wxPNGHandler);
294 
295             // In any case, no need to do it again.
296             m_imageHandledAdded = true;
297         }
298 
299         wxImage image(is, wxBITMAP_TYPE_PNG);
300         if ( !image.IsOk() )
301         {
302             // This should normally never happen as all the embedded images are
303             // well-formed.
304             wxLogDebug("Failed to load embedded PNG image for \"%s\"", id);
305             return wxNullBitmap;
306         }
307 
308         if ( !sizeIsAHint )
309         {
310             // Notice that this won't do anything if the size is already right.
311             image.Rescale(size.x, size.y, wxIMAGE_QUALITY_HIGH);
312         }
313 
314         return image;
315     }
316 
317     // Not one of the bitmaps that we support.
318     return wxNullBitmap;
319 }
320 
321 /* static */
InitTangoProvider()322 void wxArtProvider::InitTangoProvider()
323 {
324     wxArtProvider::PushBack(new wxTangoArtProvider);
325 }
326 
327 #endif // wxUSE_ARTPROVIDER_TANGO
328