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