btrfs: Attempt to fix GCC2 build.
[haiku.git] / src / kits / interface / Icon.cpp
blob1cfbf7495da2af6ad93cd41b1c67c880e02a93de
1 /*
2 * Copyright 2006-2013, Haiku, Inc.
3 * Distributed under the terms of the MIT License.
5 * Authors:
6 * Stephan Aßmus, superstippi@gmx.de
7 * Ingo Weinhold, ingo_weinhold@gmx.de
8 */
11 #include <Icon.h>
13 #include <string.h>
15 #include <new>
17 #include <Bitmap.h>
19 #include <AutoDeleter.h>
22 namespace BPrivate {
25 BIcon::BIcon()
27 fEnabledBitmaps(8, true),
28 fDisabledBitmaps(8, true)
33 BIcon::~BIcon()
38 status_t
39 BIcon::SetTo(const BBitmap* bitmap, uint32 flags)
41 if (!bitmap->IsValid())
42 return B_BAD_VALUE;
44 DeleteBitmaps();
46 // check the color space
47 bool hasAlpha = false;
48 bool canUseForMakeBitmaps = false;
50 switch (bitmap->ColorSpace()) {
51 case B_RGBA32:
52 case B_RGBA32_BIG:
53 hasAlpha = true;
54 // fall through
55 case B_RGB32:
56 case B_RGB32_BIG:
57 canUseForMakeBitmaps = true;
58 break;
60 case B_UVLA32:
61 case B_LABA32:
62 case B_HSIA32:
63 case B_HSVA32:
64 case B_HLSA32:
65 case B_CMYA32:
66 case B_RGBA15:
67 case B_RGBA15_BIG:
68 case B_CMAP8:
69 hasAlpha = true;
70 break;
72 default:
73 break;
76 BBitmap* trimmedBitmap = NULL;
78 // trim the bitmap, if requested and the bitmap actually has alpha
79 status_t error;
80 if ((flags & (B_TRIM_ICON_BITMAP | B_TRIM_ICON_BITMAP_KEEP_ASPECT)) != 0
81 && hasAlpha) {
82 if (bitmap->ColorSpace() == B_RGBA32) {
83 error = _TrimBitmap(bitmap,
84 (flags & B_TRIM_ICON_BITMAP_KEEP_ASPECT) != 0, trimmedBitmap);
85 } else {
86 BBitmap* rgb32Bitmap = _ConvertToRGB32(bitmap, true);
87 if (rgb32Bitmap != NULL) {
88 error = _TrimBitmap(rgb32Bitmap,
89 (flags & B_TRIM_ICON_BITMAP_KEEP_ASPECT) != 0,
90 trimmedBitmap);
91 delete rgb32Bitmap;
92 } else
93 error = B_NO_MEMORY;
96 if (error != B_OK)
97 return error;
99 bitmap = trimmedBitmap;
100 canUseForMakeBitmaps = true;
103 // create the bitmaps
104 if (canUseForMakeBitmaps) {
105 error = _MakeBitmaps(bitmap, flags);
106 } else {
107 if (BBitmap* rgb32Bitmap = _ConvertToRGB32(bitmap, true)) {
108 error = _MakeBitmaps(rgb32Bitmap, flags);
109 delete rgb32Bitmap;
110 } else
111 error = B_NO_MEMORY;
114 delete trimmedBitmap;
116 return error;
120 bool
121 BIcon::SetBitmap(BBitmap* bitmap, uint32 which)
123 BitmapList& list = (which & B_DISABLED_ICON_BITMAP) == 0
124 ? fEnabledBitmaps : fDisabledBitmaps;
125 which &= ~uint32(B_DISABLED_ICON_BITMAP);
127 int32 count = list.CountItems();
128 if ((int32)which < count) {
129 list.ReplaceItem(which, bitmap);
130 return true;
133 while (list.CountItems() < (int32)which) {
134 if (!list.AddItem((BBitmap*)NULL))
135 return false;
138 return list.AddItem(bitmap);
142 BBitmap*
143 BIcon::Bitmap(uint32 which) const
145 const BitmapList& list = (which & B_DISABLED_ICON_BITMAP) == 0
146 ? fEnabledBitmaps : fDisabledBitmaps;
147 return list.ItemAt(which & ~uint32(B_DISABLED_ICON_BITMAP));
151 BBitmap*
152 BIcon::CreateBitmap(const BRect& bounds, color_space colorSpace, uint32 which)
154 BBitmap* bitmap = new(std::nothrow) BBitmap(bounds, colorSpace);
155 if (bitmap == NULL || !bitmap->IsValid() || !SetBitmap(bitmap, which)) {
156 delete bitmap;
157 return NULL;
160 return bitmap;
164 status_t
165 BIcon::SetExternalBitmap(const BBitmap* bitmap, uint32 which, uint32 flags)
167 BBitmap* ourBitmap = NULL;
168 if (bitmap != NULL) {
169 if (!bitmap->IsValid())
170 return B_BAD_VALUE;
172 if ((flags & B_KEEP_ICON_BITMAP) != 0) {
173 ourBitmap = const_cast<BBitmap*>(bitmap);
174 } else {
175 ourBitmap = _ConvertToRGB32(bitmap);
176 if (ourBitmap == NULL)
177 return B_NO_MEMORY;
181 if (!SetBitmap(ourBitmap, which)) {
182 if (ourBitmap != bitmap)
183 delete ourBitmap;
184 return B_NO_MEMORY;
187 return B_OK;
191 BBitmap*
192 BIcon::CopyBitmap(const BBitmap& bitmapToClone, uint32 which)
194 BBitmap* bitmap = new(std::nothrow) BBitmap(bitmapToClone);
195 if (bitmap == NULL || !bitmap->IsValid() || !SetBitmap(bitmap, which)) {
196 delete bitmap;
197 return NULL;
200 return bitmap;
204 void
205 BIcon::DeleteBitmaps()
207 fEnabledBitmaps.MakeEmpty(true);
208 fDisabledBitmaps.MakeEmpty(true);
212 /*static*/ status_t
213 BIcon::UpdateIcon(const BBitmap* bitmap, uint32 flags, BIcon*& _icon)
215 if (bitmap == NULL) {
216 delete _icon;
217 _icon = NULL;
218 return B_OK;
221 BIcon* icon = new(std::nothrow) BIcon;
222 if (icon == NULL)
223 return B_NO_MEMORY;
225 status_t error = icon->SetTo(bitmap, flags);
226 if (error != B_OK) {
227 delete icon;
228 return error;
231 _icon = icon;
232 return B_OK;
236 /*static*/ status_t
237 BIcon::SetIconBitmap(const BBitmap* bitmap, uint32 which, uint32 flags,
238 BIcon*& _icon)
240 bool newIcon = false;
241 if (_icon == NULL) {
242 if (bitmap == NULL)
243 return B_OK;
245 _icon = new(std::nothrow) BIcon;
246 if (_icon == NULL)
247 return B_NO_MEMORY;
248 newIcon = true;
251 status_t error = _icon->SetExternalBitmap(bitmap, which, flags);
252 if (error != B_OK) {
253 if (newIcon) {
254 delete _icon;
255 _icon = NULL;
257 return error;
260 return B_OK;
264 /*static*/ BBitmap*
265 BIcon::_ConvertToRGB32(const BBitmap* bitmap, bool noAppServerLink)
267 BBitmap* rgb32Bitmap = new(std::nothrow) BBitmap(bitmap->Bounds(),
268 noAppServerLink ? B_BITMAP_NO_SERVER_LINK : 0, B_RGBA32);
269 if (rgb32Bitmap == NULL)
270 return NULL;
272 if (!rgb32Bitmap->IsValid() || rgb32Bitmap->ImportBits(bitmap)!= B_OK) {
273 delete rgb32Bitmap;
274 return NULL;
277 return rgb32Bitmap;
281 /*static*/ status_t
282 BIcon::_TrimBitmap(const BBitmap* bitmap, bool keepAspect,
283 BBitmap*& _trimmedBitmap)
285 if (bitmap == NULL || !bitmap->IsValid()
286 || bitmap->ColorSpace() != B_RGBA32) {
287 return B_BAD_VALUE;
290 uint8* bits = (uint8*)bitmap->Bits();
291 uint32 bpr = bitmap->BytesPerRow();
292 uint32 width = bitmap->Bounds().IntegerWidth() + 1;
293 uint32 height = bitmap->Bounds().IntegerHeight() + 1;
294 BRect trimmed(INT32_MAX, INT32_MAX, INT32_MIN, INT32_MIN);
296 for (uint32 y = 0; y < height; y++) {
297 uint8* b = bits + 3;
298 bool rowHasAlpha = false;
299 for (uint32 x = 0; x < width; x++) {
300 if (*b) {
301 rowHasAlpha = true;
302 if (x < trimmed.left)
303 trimmed.left = x;
304 if (x > trimmed.right)
305 trimmed.right = x;
307 b += 4;
309 if (rowHasAlpha) {
310 if (y < trimmed.top)
311 trimmed.top = y;
312 if (y > trimmed.bottom)
313 trimmed.bottom = y;
315 bits += bpr;
318 if (!trimmed.IsValid())
319 return B_BAD_VALUE;
321 if (keepAspect) {
322 float minInset = trimmed.left;
323 minInset = min_c(minInset, trimmed.top);
324 minInset = min_c(minInset, bitmap->Bounds().right - trimmed.right);
325 minInset = min_c(minInset, bitmap->Bounds().bottom - trimmed.bottom);
326 trimmed = bitmap->Bounds().InsetByCopy(minInset, minInset);
328 trimmed = trimmed & bitmap->Bounds();
330 BBitmap* trimmedBitmap = new(std::nothrow) BBitmap(
331 trimmed.OffsetToCopy(B_ORIGIN), B_BITMAP_NO_SERVER_LINK, B_RGBA32);
332 if (trimmedBitmap == NULL)
333 return B_NO_MEMORY;
335 bits = (uint8*)bitmap->Bits();
336 bits += 4 * (int32)trimmed.left + bpr * (int32)trimmed.top;
337 uint8* dst = (uint8*)trimmedBitmap->Bits();
338 uint32 trimmedWidth = trimmedBitmap->Bounds().IntegerWidth() + 1;
339 uint32 trimmedHeight = trimmedBitmap->Bounds().IntegerHeight() + 1;
340 uint32 trimmedBPR = trimmedBitmap->BytesPerRow();
341 for (uint32 y = 0; y < trimmedHeight; y++) {
342 memcpy(dst, bits, trimmedWidth * 4);
343 dst += trimmedBPR;
344 bits += bpr;
347 _trimmedBitmap = trimmedBitmap;
348 return B_OK;
352 status_t
353 BIcon::_MakeBitmaps(const BBitmap* bitmap, uint32 flags)
355 // make our own versions of the bitmap
356 BRect b(bitmap->Bounds());
358 color_space format = bitmap->ColorSpace();
359 BBitmap* normalBitmap = CreateBitmap(b, format, B_INACTIVE_ICON_BITMAP);
360 if (normalBitmap == NULL)
361 return B_NO_MEMORY;
363 BBitmap* disabledBitmap = NULL;
364 if ((flags & B_CREATE_DISABLED_ICON_BITMAPS) != 0) {
365 disabledBitmap = CreateBitmap(b, format,
366 B_INACTIVE_ICON_BITMAP | B_DISABLED_ICON_BITMAP);
367 if (disabledBitmap == NULL)
368 return B_NO_MEMORY;
371 BBitmap* clickedBitmap = NULL;
372 if ((flags & (B_CREATE_ACTIVE_ICON_BITMAP
373 | B_CREATE_PARTIALLY_ACTIVE_ICON_BITMAP)) != 0) {
374 clickedBitmap = CreateBitmap(b, format, B_ACTIVE_ICON_BITMAP);
375 if (clickedBitmap == NULL)
376 return B_NO_MEMORY;
379 BBitmap* disabledClickedBitmap = NULL;
380 if (disabledBitmap != NULL && clickedBitmap != NULL) {
381 disabledClickedBitmap = CreateBitmap(b, format,
382 B_ACTIVE_ICON_BITMAP | B_DISABLED_ICON_BITMAP);
383 if (disabledClickedBitmap == NULL)
384 return B_NO_MEMORY;
387 // copy bitmaps from file bitmap
388 uint8* nBits = normalBitmap != NULL ? (uint8*)normalBitmap->Bits() : NULL;
389 uint8* dBits = disabledBitmap != NULL
390 ? (uint8*)disabledBitmap->Bits() : NULL;
391 uint8* cBits = clickedBitmap != NULL ? (uint8*)clickedBitmap->Bits() : NULL;
392 uint8* dcBits = disabledClickedBitmap != NULL
393 ? (uint8*)disabledClickedBitmap->Bits() : NULL;
394 uint8* fBits = (uint8*)bitmap->Bits();
395 int32 nbpr = normalBitmap->BytesPerRow();
396 int32 fbpr = bitmap->BytesPerRow();
397 int32 pixels = b.IntegerWidth() + 1;
398 int32 lines = b.IntegerHeight() + 1;
399 if (format == B_RGB32 || format == B_RGB32_BIG) {
400 // nontransparent version
402 // iterate over color components
403 for (int32 y = 0; y < lines; y++) {
404 for (int32 x = 0; x < pixels; x++) {
405 int32 nOffset = 4 * x;
406 int32 fOffset = 4 * x;
407 nBits[nOffset + 0] = fBits[fOffset + 0];
408 nBits[nOffset + 1] = fBits[fOffset + 1];
409 nBits[nOffset + 2] = fBits[fOffset + 2];
410 nBits[nOffset + 3] = 255;
412 // clicked bits are darker (lame method...)
413 if (cBits != NULL) {
414 cBits[nOffset + 0] = uint8((float)nBits[nOffset + 0] * 0.8);
415 cBits[nOffset + 1] = uint8((float)nBits[nOffset + 1] * 0.8);
416 cBits[nOffset + 2] = uint8((float)nBits[nOffset + 2] * 0.8);
417 cBits[nOffset + 3] = 255;
420 // disabled bits have less contrast (lame method...)
421 if (dBits != NULL) {
422 uint8 grey = 216;
423 float dist = (nBits[nOffset + 0] - grey) * 0.4;
424 dBits[nOffset + 0] = (uint8)(grey + dist);
425 dist = (nBits[nOffset + 1] - grey) * 0.4;
426 dBits[nOffset + 1] = (uint8)(grey + dist);
427 dist = (nBits[nOffset + 2] - grey) * 0.4;
428 dBits[nOffset + 2] = (uint8)(grey + dist);
429 dBits[nOffset + 3] = 255;
432 // disabled bits have less contrast (lame method...)
433 if (dcBits != NULL) {
434 uint8 grey = 188;
435 float dist = (nBits[nOffset + 0] - grey) * 0.4;
436 dcBits[nOffset + 0] = (uint8)(grey + dist);
437 dist = (nBits[nOffset + 1] - grey) * 0.4;
438 dcBits[nOffset + 1] = (uint8)(grey + dist);
439 dist = (nBits[nOffset + 2] - grey) * 0.4;
440 dcBits[nOffset + 2] = (uint8)(grey + dist);
441 dcBits[nOffset + 3] = 255;
444 fBits += fbpr;
445 nBits += nbpr;
446 if (cBits != NULL)
447 cBits += nbpr;
448 if (dBits != NULL)
449 dBits += nbpr;
450 if (dcBits != NULL)
451 dcBits += nbpr;
453 } else if (format == B_RGBA32 || format == B_RGBA32_BIG) {
454 // transparent version
456 // iterate over color components
457 for (int32 y = 0; y < lines; y++) {
458 for (int32 x = 0; x < pixels; x++) {
459 int32 nOffset = 4 * x;
460 int32 fOffset = 4 * x;
461 nBits[nOffset + 0] = fBits[fOffset + 0];
462 nBits[nOffset + 1] = fBits[fOffset + 1];
463 nBits[nOffset + 2] = fBits[fOffset + 2];
464 nBits[nOffset + 3] = fBits[fOffset + 3];
466 // clicked bits are darker (lame method...)
467 if (cBits != NULL) {
468 cBits[nOffset + 0] = (uint8)(nBits[nOffset + 0] * 0.8);
469 cBits[nOffset + 1] = (uint8)(nBits[nOffset + 1] * 0.8);
470 cBits[nOffset + 2] = (uint8)(nBits[nOffset + 2] * 0.8);
471 cBits[nOffset + 3] = fBits[fOffset + 3];
474 // disabled bits have less opacity
475 if (dBits != NULL) {
476 uint8 grey = ((uint16)nBits[nOffset + 0] * 10
477 + nBits[nOffset + 1] * 60
478 + nBits[nOffset + 2] * 30) / 100;
479 float dist = (nBits[nOffset + 0] - grey) * 0.3;
480 dBits[nOffset + 0] = (uint8)(grey + dist);
481 dist = (nBits[nOffset + 1] - grey) * 0.3;
482 dBits[nOffset + 1] = (uint8)(grey + dist);
483 dist = (nBits[nOffset + 2] - grey) * 0.3;
484 dBits[nOffset + 2] = (uint8)(grey + dist);
485 dBits[nOffset + 3] = (uint8)(fBits[fOffset + 3] * 0.3);
488 // disabled bits have less contrast (lame method...)
489 if (dcBits != NULL) {
490 dcBits[nOffset + 0] = (uint8)(dBits[nOffset + 0] * 0.8);
491 dcBits[nOffset + 1] = (uint8)(dBits[nOffset + 1] * 0.8);
492 dcBits[nOffset + 2] = (uint8)(dBits[nOffset + 2] * 0.8);
493 dcBits[nOffset + 3] = (uint8)(fBits[fOffset + 3] * 0.3);
496 fBits += fbpr;
497 nBits += nbpr;
498 if (cBits != NULL)
499 cBits += nbpr;
500 if (dBits != NULL)
501 dBits += nbpr;
502 if (dcBits != NULL)
503 dcBits += nbpr;
505 } else {
506 // unsupported format
507 return B_BAD_VALUE;
510 // make the partially-on bitmaps a copy of the on bitmaps
511 if ((flags & B_CREATE_PARTIALLY_ACTIVE_ICON_BITMAP) != 0) {
512 if (CopyBitmap(clickedBitmap, B_PARTIALLY_ACTIVATE_ICON_BITMAP) == NULL)
513 return B_NO_MEMORY;
514 if ((flags & B_CREATE_DISABLED_ICON_BITMAPS) != 0) {
515 if (CopyBitmap(disabledClickedBitmap,
516 B_PARTIALLY_ACTIVATE_ICON_BITMAP | B_DISABLED_ICON_BITMAP)
517 == NULL) {
518 return B_NO_MEMORY;
523 return B_OK;
527 } // namespace BPrivate