2 * Copyright 2006-2013, Haiku, Inc.
3 * Distributed under the terms of the MIT License.
6 * Stephan Aßmus, superstippi@gmx.de
7 * Ingo Weinhold, ingo_weinhold@gmx.de
19 #include <AutoDeleter.h>
27 fEnabledBitmaps(8, true),
28 fDisabledBitmaps(8, true)
39 BIcon::SetTo(const BBitmap
* bitmap
, uint32 flags
)
41 if (!bitmap
->IsValid())
46 // check the color space
47 bool hasAlpha
= false;
48 bool canUseForMakeBitmaps
= false;
50 switch (bitmap
->ColorSpace()) {
57 canUseForMakeBitmaps
= true;
76 BBitmap
* trimmedBitmap
= NULL
;
78 // trim the bitmap, if requested and the bitmap actually has alpha
80 if ((flags
& (B_TRIM_ICON_BITMAP
| B_TRIM_ICON_BITMAP_KEEP_ASPECT
)) != 0
82 if (bitmap
->ColorSpace() == B_RGBA32
) {
83 error
= _TrimBitmap(bitmap
,
84 (flags
& B_TRIM_ICON_BITMAP_KEEP_ASPECT
) != 0, trimmedBitmap
);
86 BBitmap
* rgb32Bitmap
= _ConvertToRGB32(bitmap
, true);
87 if (rgb32Bitmap
!= NULL
) {
88 error
= _TrimBitmap(rgb32Bitmap
,
89 (flags
& B_TRIM_ICON_BITMAP_KEEP_ASPECT
) != 0,
99 bitmap
= trimmedBitmap
;
100 canUseForMakeBitmaps
= true;
103 // create the bitmaps
104 if (canUseForMakeBitmaps
) {
105 error
= _MakeBitmaps(bitmap
, flags
);
107 if (BBitmap
* rgb32Bitmap
= _ConvertToRGB32(bitmap
, true)) {
108 error
= _MakeBitmaps(rgb32Bitmap
, flags
);
114 delete trimmedBitmap
;
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
);
133 while (list
.CountItems() < (int32
)which
) {
134 if (!list
.AddItem((BBitmap
*)NULL
))
138 return list
.AddItem(bitmap
);
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
));
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
)) {
165 BIcon::SetExternalBitmap(const BBitmap
* bitmap
, uint32 which
, uint32 flags
)
167 BBitmap
* ourBitmap
= NULL
;
168 if (bitmap
!= NULL
) {
169 if (!bitmap
->IsValid())
172 if ((flags
& B_KEEP_ICON_BITMAP
) != 0) {
173 ourBitmap
= const_cast<BBitmap
*>(bitmap
);
175 ourBitmap
= _ConvertToRGB32(bitmap
);
176 if (ourBitmap
== NULL
)
181 if (!SetBitmap(ourBitmap
, which
)) {
182 if (ourBitmap
!= bitmap
)
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
)) {
205 BIcon::DeleteBitmaps()
207 fEnabledBitmaps
.MakeEmpty(true);
208 fDisabledBitmaps
.MakeEmpty(true);
213 BIcon::UpdateIcon(const BBitmap
* bitmap
, uint32 flags
, BIcon
*& _icon
)
215 if (bitmap
== NULL
) {
221 BIcon
* icon
= new(std::nothrow
) BIcon
;
225 status_t error
= icon
->SetTo(bitmap
, flags
);
237 BIcon::SetIconBitmap(const BBitmap
* bitmap
, uint32 which
, uint32 flags
,
240 bool newIcon
= false;
245 _icon
= new(std::nothrow
) BIcon
;
251 status_t error
= _icon
->SetExternalBitmap(bitmap
, which
, flags
);
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
)
272 if (!rgb32Bitmap
->IsValid() || rgb32Bitmap
->ImportBits(bitmap
)!= B_OK
) {
282 BIcon::_TrimBitmap(const BBitmap
* bitmap
, bool keepAspect
,
283 BBitmap
*& _trimmedBitmap
)
285 if (bitmap
== NULL
|| !bitmap
->IsValid()
286 || bitmap
->ColorSpace() != B_RGBA32
) {
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
++) {
298 bool rowHasAlpha
= false;
299 for (uint32 x
= 0; x
< width
; x
++) {
302 if (x
< trimmed
.left
)
304 if (x
> trimmed
.right
)
312 if (y
> trimmed
.bottom
)
318 if (!trimmed
.IsValid())
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
)
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);
347 _trimmedBitmap
= trimmedBitmap
;
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
)
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
)
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
)
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
)
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...)
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...)
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
) {
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;
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...)
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
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);
506 // unsupported format
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
)
514 if ((flags
& B_CREATE_DISABLED_ICON_BITMAPS
) != 0) {
515 if (CopyBitmap(disabledClickedBitmap
,
516 B_PARTIALLY_ACTIVATE_ICON_BITMAP
| B_DISABLED_ICON_BITMAP
)
527 } // namespace BPrivate