xref: /haiku/src/kits/shared/IconButton.cpp (revision 323b65468e5836bb27a5e373b14027d902349437)
1 /*
2  * Copyright 2006-2011, Haiku.
3  * Distributed under the terms of the MIT License.
4  *
5  * Authors:
6  *		Stephan Aßmus <superstippi@gmx.de>
7  *		Axel Dörfler, axeld@pinc-software.de.
8  */
9 
10 
11 #include "IconButton.h"
12 
13 #include <new>
14 #include <stdio.h>
15 
16 #include <Application.h>
17 #include <Bitmap.h>
18 #include <Control.h>
19 #include <ControlLook.h>
20 #include <Entry.h>
21 #include <IconUtils.h>
22 #include <Looper.h>
23 #include <Message.h>
24 #include <Mime.h>
25 #include <Path.h>
26 #include <Region.h>
27 #include <Resources.h>
28 #include <Roster.h>
29 #include <TranslationUtils.h>
30 #include <Window.h>
31 
32 
33 namespace BPrivate {
34 
35 
36 enum {
37 	STATE_NONE			= 0x0000,
38 	STATE_PRESSED		= 0x0002,
39 	STATE_INSIDE		= 0x0008,
40 	STATE_FORCE_PRESSED	= 0x0010,
41 };
42 
43 
44 
45 BIconButton::BIconButton(const char* name, const char* label,
46 	BMessage* message, BHandler* target)
47 	:
48 	BControl(name, label, message, B_WILL_DRAW),
49 	fButtonState(0),
50 	fNormalBitmap(NULL),
51 	fDisabledBitmap(NULL),
52 	fClickedBitmap(NULL),
53 	fDisabledClickedBitmap(NULL),
54 	fTargetCache(target)
55 {
56 	SetTarget(target);
57 	SetLowColor(ui_color(B_PANEL_BACKGROUND_COLOR));
58 	SetViewColor(B_TRANSPARENT_32_BIT);
59 }
60 
61 
62 BIconButton::~BIconButton()
63 {
64 	_DeleteBitmaps();
65 }
66 
67 
68 void
69 BIconButton::MessageReceived(BMessage* message)
70 {
71 	switch (message->what) {
72 		default:
73 			BView::MessageReceived(message);
74 			break;
75 	}
76 }
77 
78 
79 void
80 BIconButton::AttachedToWindow()
81 {
82 	rgb_color background = B_TRANSPARENT_COLOR;
83 	if (BView* parent = Parent()) {
84 		background = parent->ViewColor();
85 		if (background == B_TRANSPARENT_COLOR)
86 			background = parent->LowColor();
87 	}
88 	if (background == B_TRANSPARENT_COLOR)
89 		background = ui_color(B_PANEL_BACKGROUND_COLOR);
90 	SetLowColor(background);
91 
92 	SetTarget(fTargetCache);
93 	if (!Target())
94 		SetTarget(Window());
95 }
96 
97 
98 void
99 BIconButton::Draw(BRect updateRect)
100 {
101 	rgb_color background = LowColor();
102 
103 	BRect r(Bounds());
104 
105 	uint32 flags = 0;
106 	BBitmap* bitmap = fNormalBitmap;
107 	if (!IsEnabled()) {
108 		flags |= BControlLook::B_DISABLED;
109 		bitmap = fDisabledBitmap;
110 	}
111 	if (_HasFlags(STATE_PRESSED) || _HasFlags(STATE_FORCE_PRESSED))
112 		flags |= BControlLook::B_ACTIVATED;
113 
114 	if (ShouldDrawBorder()) {
115 		DrawBorder(r, updateRect, background, flags);
116 		DrawBackground(r, updateRect, background, flags);
117 	} else {
118 		SetHighColor(background);
119 		FillRect(r);
120 	}
121 
122 	if (bitmap && bitmap->IsValid()) {
123 		if (bitmap->ColorSpace() == B_RGBA32
124 			|| bitmap->ColorSpace() == B_RGBA32_BIG) {
125 			SetDrawingMode(B_OP_ALPHA);
126 			SetBlendingMode(B_PIXEL_ALPHA, B_ALPHA_OVERLAY);
127 		}
128 		float x = r.left + floorf((r.Width()
129 			- bitmap->Bounds().Width()) / 2.0 + 0.5);
130 		float y = r.top + floorf((r.Height()
131 			- bitmap->Bounds().Height()) / 2.0 + 0.5);
132 		DrawBitmap(bitmap, BPoint(x, y));
133 	}
134 }
135 
136 
137 bool
138 BIconButton::ShouldDrawBorder() const
139 {
140 	return (IsEnabled() && (IsInside() || IsTracking()))
141 		|| _HasFlags(STATE_FORCE_PRESSED);
142 }
143 
144 
145 void
146 BIconButton::DrawBorder(BRect& frame, const BRect& updateRect,
147 	const rgb_color& backgroundColor, uint32 flags)
148 {
149 	be_control_look->DrawButtonFrame(this, frame, updateRect, backgroundColor,
150 		backgroundColor, flags);
151 }
152 
153 
154 void
155 BIconButton::DrawBackground(BRect& frame, const BRect& updateRect,
156 	const rgb_color& backgroundColor, uint32 flags)
157 {
158 	be_control_look->DrawButtonBackground(this, frame, updateRect,
159 		backgroundColor, flags);
160 }
161 
162 
163 void
164 BIconButton::MouseDown(BPoint where)
165 {
166 	if (!IsValid())
167 		return;
168 
169 	if (IsEnabled()) {
170 		if (Bounds().Contains(where)) {
171 			SetMouseEventMask(B_POINTER_EVENTS, B_LOCK_WINDOW_FOCUS);
172 			_SetFlags(STATE_PRESSED, true);
173 			_SetTracking(true);
174 		} else {
175 			_SetFlags(STATE_PRESSED, false);
176 			_SetTracking(false);
177 		}
178 	}
179 }
180 
181 
182 void
183 BIconButton::MouseUp(BPoint where)
184 {
185 	if (!IsValid())
186 		return;
187 
188 	if (IsEnabled() && _HasFlags(STATE_PRESSED)
189 		&& Bounds().Contains(where)) {
190 		Invoke();
191 	} else if (Bounds().Contains(where))
192 		SetInside(true);
193 
194 	_SetFlags(STATE_PRESSED, false);
195 	_SetTracking(false);
196 }
197 
198 
199 void
200 BIconButton::MouseMoved(BPoint where, uint32 transit, const BMessage* message)
201 {
202 	if (!IsValid())
203 		return;
204 
205 	uint32 buttons = 0;
206 	Window()->CurrentMessage()->FindInt32("buttons", (int32*)&buttons);
207 	// catch a mouse up event that we might have missed
208 	if (!buttons && _HasFlags(STATE_PRESSED)) {
209 		MouseUp(where);
210 		return;
211 	}
212 	if (buttons != 0 && !IsTracking())
213 		return;
214 
215 	SetInside((transit == B_INSIDE_VIEW || transit == B_ENTERED_VIEW)
216 		&& IsEnabled());
217 	if (IsTracking())
218 		_SetFlags(STATE_PRESSED, Bounds().Contains(where));
219 }
220 
221 
222 void
223 BIconButton::GetPreferredSize(float* width, float* height)
224 {
225 	float minWidth = 0.0f;
226 	float minHeight = 0.0f;
227 	if (IsValid()) {
228 		minWidth += fNormalBitmap->Bounds().IntegerWidth() + 1.0f;
229 		minHeight += fNormalBitmap->Bounds().IntegerHeight() + 1.0f;
230 	}
231 
232 	const float kMinSpace = 15.0f;
233 	if (minWidth < kMinSpace)
234 		minWidth = kMinSpace;
235 	if (minHeight < kMinSpace)
236 		minHeight = kMinSpace;
237 
238 	float hPadding = max_c(6.0f, ceilf(minHeight / 4.0f));
239 	float vPadding = max_c(6.0f, ceilf(minWidth / 4.0f));
240 
241 	if (Label() != NULL && Label()[0] != '\0') {
242 		font_height fh;
243 		GetFontHeight(&fh);
244 		minHeight += ceilf(fh.ascent + fh.descent) + vPadding;
245 		minWidth += StringWidth(Label()) + vPadding;
246 	}
247 
248 	if (width)
249 		*width = minWidth + hPadding;
250 	if (height)
251 		*height = minHeight + vPadding;
252 }
253 
254 
255 BSize
256 BIconButton::MinSize()
257 {
258 	BSize size;
259 	GetPreferredSize(&size.width, &size.height);
260 	return size;
261 }
262 
263 
264 BSize
265 BIconButton::MaxSize()
266 {
267 	return MinSize();
268 }
269 
270 
271 status_t
272 BIconButton::Invoke(BMessage* message)
273 {
274 	if (message == NULL)
275 		message = Message();
276 	if (message != NULL) {
277 		BMessage clone(*message);
278 		clone.AddInt64("be:when", system_time());
279 		clone.AddPointer("be:source", (BView*)this);
280 		clone.AddInt32("be:value", Value());
281 		return BInvoker::Invoke(&clone);
282 	}
283 	return BInvoker::Invoke(message);
284 }
285 
286 
287 void
288 BIconButton::SetPressed(bool pressed)
289 {
290 	_SetFlags(STATE_FORCE_PRESSED, pressed);
291 }
292 
293 
294 bool
295 BIconButton::IsPressed() const
296 {
297 	return _HasFlags(STATE_FORCE_PRESSED);
298 }
299 
300 
301 status_t
302 BIconButton::SetIcon(int32 resourceID)
303 {
304 	app_info info;
305 	status_t status = be_app->GetAppInfo(&info);
306 	if (status != B_OK)
307 		return status;
308 
309 	BResources resources(&info.ref);
310 	status = resources.InitCheck();
311 	if (status != B_OK)
312 		return status;
313 
314 	size_t size;
315 	const void* data = resources.LoadResource(B_VECTOR_ICON_TYPE, resourceID,
316 		&size);
317 	if (data != NULL) {
318 		BBitmap bitmap(BRect(0, 0, 31, 31), B_BITMAP_NO_SERVER_LINK, B_RGBA32);
319 		status = bitmap.InitCheck();
320 		if (status != B_OK)
321 			return status;
322 		status = BIconUtils::GetVectorIcon(reinterpret_cast<const uint8*>(data),
323 			size, &bitmap);
324 		if (status != B_OK)
325 			return status;
326 		return SetIcon(&bitmap);
327 	}
328 //	const void* data = resources.LoadResource(B_BITMAP_TYPE, resourceID, &size);
329 	return B_ERROR;
330 }
331 
332 
333 status_t
334 BIconButton::SetIcon(const char* pathToBitmap)
335 {
336 	if (pathToBitmap == NULL)
337 		return B_BAD_VALUE;
338 
339 	status_t status = B_BAD_VALUE;
340 	BBitmap* fileBitmap = NULL;
341 	// try to load bitmap from either relative or absolute path
342 	BEntry entry(pathToBitmap, true);
343 	if (!entry.Exists()) {
344 		app_info info;
345 		status = be_app->GetAppInfo(&info);
346 		if (status == B_OK) {
347 			BEntry app_entry(&info.ref, true);
348 			BPath path;
349 			app_entry.GetPath(&path);
350 			status = path.InitCheck();
351 			if (status == B_OK) {
352 				status = path.GetParent(&path);
353 				if (status == B_OK) {
354 					status = path.Append(pathToBitmap, true);
355 					if (status == B_OK)
356 						fileBitmap = BTranslationUtils::GetBitmap(path.Path());
357 					else {
358 						printf("BIconButton::SetIcon() - path.Append() failed: "
359 							"%s\n", strerror(status));
360 					}
361 				} else {
362 					printf("BIconButton::SetIcon() - path.GetParent() failed: "
363 						"%s\n", strerror(status));
364 				}
365 			} else {
366 				printf("BIconButton::SetIcon() - path.InitCheck() failed: "
367 					"%s\n", strerror(status));
368 			}
369 		} else {
370 			printf("BIconButton::SetIcon() - be_app->GetAppInfo() failed: "
371 				"%s\n", strerror(status));
372 		}
373 	} else
374 		fileBitmap = BTranslationUtils::GetBitmap(pathToBitmap);
375 	if (fileBitmap) {
376 		status = _MakeBitmaps(fileBitmap);
377 		delete fileBitmap;
378 	} else
379 		status = B_ERROR;
380 	return status;
381 }
382 
383 
384 status_t
385 BIconButton::SetIcon(const BBitmap* bitmap)
386 {
387 	if (bitmap && bitmap->ColorSpace() == B_CMAP8) {
388 		status_t status = bitmap->InitCheck();
389 		if (status >= B_OK) {
390 			if (BBitmap* rgb32Bitmap = _ConvertToRGB32(bitmap)) {
391 				status = _MakeBitmaps(rgb32Bitmap);
392 				delete rgb32Bitmap;
393 			} else
394 				status = B_NO_MEMORY;
395 		}
396 		return status;
397 	} else
398 		return _MakeBitmaps(bitmap);
399 }
400 
401 
402 status_t
403 BIconButton::SetIcon(const BMimeType* fileType, bool small)
404 {
405 	status_t status = fileType ? fileType->InitCheck() : B_BAD_VALUE;
406 	if (status >= B_OK) {
407 		BBitmap* mimeBitmap = new(std::nothrow) BBitmap(BRect(0.0, 0.0, 15.0,
408 			15.0), B_CMAP8);
409 		if (mimeBitmap && mimeBitmap->IsValid()) {
410 			status = fileType->GetIcon(mimeBitmap, small ? B_MINI_ICON
411 				: B_LARGE_ICON);
412 			if (status >= B_OK) {
413 				if (BBitmap* bitmap = _ConvertToRGB32(mimeBitmap)) {
414 					status = _MakeBitmaps(bitmap);
415 					delete bitmap;
416 				} else {
417 					printf("BIconButton::SetIcon() - B_RGB32 bitmap is not "
418 						"valid\n");
419 				}
420 			} else {
421 				printf("BIconButton::SetIcon() - fileType->GetIcon() failed: "
422 					"%s\n", strerror(status));
423 			}
424 		} else
425 			printf("BIconButton::SetIcon() - B_CMAP8 bitmap is not valid\n");
426 		delete mimeBitmap;
427 	} else {
428 		printf("BIconButton::SetIcon() - fileType is not valid: %s\n",
429 			strerror(status));
430 	}
431 	return status;
432 }
433 
434 
435 status_t
436 BIconButton::SetIcon(const unsigned char* bitsFromQuickRes,
437 	uint32 width, uint32 height, color_space format, bool convertToBW)
438 {
439 	status_t status = B_BAD_VALUE;
440 	if (bitsFromQuickRes && width > 0 && height > 0) {
441 		BBitmap* quickResBitmap = new(std::nothrow) BBitmap(BRect(0.0, 0.0,
442 			width - 1.0, height - 1.0), format);
443 		status = quickResBitmap ? quickResBitmap->InitCheck() : B_ERROR;
444 		if (status >= B_OK) {
445 			// It doesn't look right to copy BitsLength() bytes, but bitmaps
446 			// exported from QuickRes still contain their padding, so it is
447 			// alright.
448 			memcpy(quickResBitmap->Bits(), bitsFromQuickRes,
449 				quickResBitmap->BitsLength());
450 			if (format != B_RGB32 && format != B_RGBA32
451 				&& format != B_RGB32_BIG && format != B_RGBA32_BIG) {
452 				// colorspace needs conversion
453 				BBitmap* bitmap = new(std::nothrow) BBitmap(
454 					quickResBitmap->Bounds(), B_RGB32, true);
455 				if (bitmap && bitmap->IsValid()) {
456 					BView* helper = new BView(bitmap->Bounds(), "helper",
457 											  B_FOLLOW_NONE, B_WILL_DRAW);
458 					if (bitmap->Lock()) {
459 						bitmap->AddChild(helper);
460 						helper->SetHighColor(ui_color(B_PANEL_BACKGROUND_COLOR));
461 						helper->FillRect(helper->Bounds());
462 						helper->SetDrawingMode(B_OP_OVER);
463 						helper->DrawBitmap(quickResBitmap, BPoint(0.0, 0.0));
464 						helper->Sync();
465 						bitmap->Unlock();
466 					}
467 					status = _MakeBitmaps(bitmap);
468 				} else {
469 					printf("BIconButton::SetIcon() - B_RGB32 bitmap is not "
470 						"valid\n");
471 				}
472 				delete bitmap;
473 			} else {
474 				// native colorspace (32 bits)
475 				if (convertToBW) {
476 					// convert to gray scale icon
477 					uint8* bits = (uint8*)quickResBitmap->Bits();
478 					uint32 bpr = quickResBitmap->BytesPerRow();
479 					for (uint32 y = 0; y < height; y++) {
480 						uint8* handle = bits;
481 						uint8 gray;
482 						for (uint32 x = 0; x < width; x++) {
483 							gray = uint8((116 * handle[0] + 600 * handle[1]
484 								+ 308 * handle[2]) / 1024);
485 							handle[0] = gray;
486 							handle[1] = gray;
487 							handle[2] = gray;
488 							handle += 4;
489 						}
490 						bits += bpr;
491 					}
492 				}
493 				status = _MakeBitmaps(quickResBitmap);
494 			}
495 		} else {
496 			printf("BIconButton::SetIcon() - error allocating bitmap: "
497 				"%s\n", strerror(status));
498 		}
499 		delete quickResBitmap;
500 	}
501 	return status;
502 }
503 
504 
505 void
506 BIconButton::ClearIcon()
507 {
508 	_DeleteBitmaps();
509 	_Update();
510 }
511 
512 
513 void
514 BIconButton::TrimIcon(bool keepAspect)
515 {
516 	if (fNormalBitmap == NULL)
517 		return;
518 
519 	uint8* bits = (uint8*)fNormalBitmap->Bits();
520 	uint32 bpr = fNormalBitmap->BytesPerRow();
521 	uint32 width = fNormalBitmap->Bounds().IntegerWidth() + 1;
522 	uint32 height = fNormalBitmap->Bounds().IntegerHeight() + 1;
523 	BRect trimmed(LONG_MAX, LONG_MAX, LONG_MIN, LONG_MIN);
524 	for (uint32 y = 0; y < height; y++) {
525 		uint8* b = bits + 3;
526 		bool rowHasAlpha = false;
527 		for (uint32 x = 0; x < width; x++) {
528 			if (*b) {
529 				rowHasAlpha = true;
530 				if (x < trimmed.left)
531 					trimmed.left = x;
532 				if (x > trimmed.right)
533 					trimmed.right = x;
534 			}
535 			b += 4;
536 		}
537 		if (rowHasAlpha) {
538 			if (y < trimmed.top)
539 				trimmed.top = y;
540 			if (y > trimmed.bottom)
541 				trimmed.bottom = y;
542 		}
543 		bits += bpr;
544 	}
545 	if (!trimmed.IsValid())
546 		return;
547 	if (keepAspect) {
548 		float minInset = trimmed.left;
549 		minInset = min_c(minInset, trimmed.top);
550 		minInset = min_c(minInset, fNormalBitmap->Bounds().right
551 			- trimmed.right);
552 		minInset = min_c(minInset, fNormalBitmap->Bounds().bottom
553 			- trimmed.bottom);
554 		trimmed = fNormalBitmap->Bounds().InsetByCopy(minInset, minInset);
555 	}
556 	trimmed = trimmed & fNormalBitmap->Bounds();
557 	BBitmap trimmedBitmap(trimmed.OffsetToCopy(B_ORIGIN),
558 		B_BITMAP_NO_SERVER_LINK, B_RGBA32);
559 	bits = (uint8*)fNormalBitmap->Bits();
560 	bits += 4 * (int32)trimmed.left + bpr * (int32)trimmed.top;
561 	uint8* dst = (uint8*)trimmedBitmap.Bits();
562 	uint32 trimmedWidth = trimmedBitmap.Bounds().IntegerWidth() + 1;
563 	uint32 trimmedHeight = trimmedBitmap.Bounds().IntegerHeight() + 1;
564 	uint32 trimmedBPR = trimmedBitmap.BytesPerRow();
565 	for (uint32 y = 0; y < trimmedHeight; y++) {
566 		memcpy(dst, bits, trimmedWidth * 4);
567 		dst += trimmedBPR;
568 		bits += bpr;
569 	}
570 	SetIcon(&trimmedBitmap);
571 }
572 
573 
574 bool
575 BIconButton::IsValid() const
576 {
577 	return (fNormalBitmap && fDisabledBitmap && fClickedBitmap
578 		&& fDisabledClickedBitmap
579 		&& fNormalBitmap->IsValid()
580 		&& fDisabledBitmap->IsValid()
581 		&& fClickedBitmap->IsValid()
582 		&& fDisabledClickedBitmap->IsValid());
583 }
584 
585 
586 BBitmap*
587 BIconButton::Bitmap() const
588 {
589 	BBitmap* bitmap = NULL;
590 	if (fNormalBitmap && fNormalBitmap->IsValid()) {
591 		bitmap = new(std::nothrow) BBitmap(fNormalBitmap);
592 		if (bitmap != NULL && bitmap->IsValid()) {
593 			// TODO: remove this functionality when we use real transparent
594 			// bitmaps
595 			uint8* bits = (uint8*)bitmap->Bits();
596 			uint32 bpr = bitmap->BytesPerRow();
597 			uint32 width = bitmap->Bounds().IntegerWidth() + 1;
598 			uint32 height = bitmap->Bounds().IntegerHeight() + 1;
599 			color_space format = bitmap->ColorSpace();
600 			if (format == B_CMAP8) {
601 				// replace gray with magic transparent index
602 			} else if (format == B_RGB32) {
603 				for (uint32 y = 0; y < height; y++) {
604 					uint8* bitsHandle = bits;
605 					for (uint32 x = 0; x < width; x++) {
606 						if (bitsHandle[0] == 216
607 							&& bitsHandle[1] == 216
608 							&& bitsHandle[2] == 216) {
609 							// make this pixel completely transparent
610 							bitsHandle[3] = 0;
611 						}
612 						bitsHandle += 4;
613 					}
614 					bits += bpr;
615 				}
616 			}
617 		} else {
618 			delete bitmap;
619 			bitmap = NULL;
620 		}
621 	}
622 	return bitmap;
623 }
624 
625 
626 void
627 BIconButton::SetValue(int32 value)
628 {
629 	BControl::SetValue(value);
630 	_SetFlags(STATE_PRESSED, value != 0);
631 }
632 
633 
634 void
635 BIconButton::SetEnabled(bool enabled)
636 {
637 	BControl::SetEnabled(enabled);
638 	if (!enabled) {
639 		SetInside(false);
640 		_SetTracking(false);
641 	}
642 }
643 
644 
645 // #pragma mark - protected
646 
647 
648 bool
649 BIconButton::IsInside() const
650 {
651 	return _HasFlags(STATE_INSIDE);
652 }
653 
654 
655 void
656 BIconButton::SetInside(bool inside)
657 {
658 	_SetFlags(STATE_INSIDE, inside);
659 }
660 
661 
662 // #pragma mark - private
663 
664 
665 BBitmap*
666 BIconButton::_ConvertToRGB32(const BBitmap* bitmap) const
667 {
668 	BBitmap* convertedBitmap = new(std::nothrow) BBitmap(bitmap->Bounds(),
669 		B_BITMAP_ACCEPTS_VIEWS, B_RGBA32);
670 	if (convertedBitmap && convertedBitmap->IsValid()) {
671 		memset(convertedBitmap->Bits(), 0, convertedBitmap->BitsLength());
672 		BView* helper = new BView(bitmap->Bounds(), "helper",
673 								  B_FOLLOW_NONE, B_WILL_DRAW);
674 		if (convertedBitmap->Lock()) {
675 			convertedBitmap->AddChild(helper);
676 			helper->SetDrawingMode(B_OP_OVER);
677 			helper->DrawBitmap(bitmap, BPoint(0.0, 0.0));
678 			helper->Sync();
679 			convertedBitmap->Unlock();
680 		}
681 	} else {
682 		delete convertedBitmap;
683 		convertedBitmap = NULL;
684 	}
685 	return convertedBitmap;
686 }
687 
688 
689 status_t
690 BIconButton::_MakeBitmaps(const BBitmap* bitmap)
691 {
692 	status_t status = bitmap ? bitmap->InitCheck() : B_BAD_VALUE;
693 	if (status == B_OK) {
694 		// make our own versions of the bitmap
695 		BRect b(bitmap->Bounds());
696 		_DeleteBitmaps();
697 		color_space format = bitmap->ColorSpace();
698 		fNormalBitmap = new(std::nothrow) BBitmap(b, format);
699 		fDisabledBitmap = new(std::nothrow) BBitmap(b, format);
700 		fClickedBitmap = new(std::nothrow) BBitmap(b, format);
701 		fDisabledClickedBitmap = new(std::nothrow) BBitmap(b, format);
702 		if (IsValid()) {
703 			// copy bitmaps from file bitmap
704 			uint8* nBits = (uint8*)fNormalBitmap->Bits();
705 			uint8* dBits = (uint8*)fDisabledBitmap->Bits();
706 			uint8* cBits = (uint8*)fClickedBitmap->Bits();
707 			uint8* dcBits = (uint8*)fDisabledClickedBitmap->Bits();
708 			uint8* fBits = (uint8*)bitmap->Bits();
709 			int32 nbpr = fNormalBitmap->BytesPerRow();
710 			int32 fbpr = bitmap->BytesPerRow();
711 			int32 pixels = b.IntegerWidth() + 1;
712 			int32 lines = b.IntegerHeight() + 1;
713 			// nontransparent version:
714 			if (format == B_RGB32 || format == B_RGB32_BIG) {
715 				// iterate over color components
716 				for (int32 y = 0; y < lines; y++) {
717 					for (int32 x = 0; x < pixels; x++) {
718 						int32 nOffset = 4 * x;
719 						int32 fOffset = 4 * x;
720 						nBits[nOffset + 0] = fBits[fOffset + 0];
721 						nBits[nOffset + 1] = fBits[fOffset + 1];
722 						nBits[nOffset + 2] = fBits[fOffset + 2];
723 						nBits[nOffset + 3] = 255;
724 						// clicked bits are darker (lame method...)
725 						cBits[nOffset + 0] = (uint8)((float)nBits[nOffset + 0]
726 							* 0.8);
727 						cBits[nOffset + 1] = (uint8)((float)nBits[nOffset + 1]
728 							* 0.8);
729 						cBits[nOffset + 2] = (uint8)((float)nBits[nOffset + 2]
730 							* 0.8);
731 						cBits[nOffset + 3] = 255;
732 						// disabled bits have less contrast (lame method...)
733 						uint8 grey = 216;
734 						float dist = (nBits[nOffset + 0] - grey) * 0.4;
735 						dBits[nOffset + 0] = (uint8)(grey + dist);
736 						dist = (nBits[nOffset + 1] - grey) * 0.4;
737 						dBits[nOffset + 1] = (uint8)(grey + dist);
738 						dist = (nBits[nOffset + 2] - grey) * 0.4;
739 						dBits[nOffset + 2] = (uint8)(grey + dist);
740 						dBits[nOffset + 3] = 255;
741 						// disabled bits have less contrast (lame method...)
742 						grey = 188;
743 						dist = (nBits[nOffset + 0] - grey) * 0.4;
744 						dcBits[nOffset + 0] = (uint8)(grey + dist);
745 						dist = (nBits[nOffset + 1] - grey) * 0.4;
746 						dcBits[nOffset + 1] = (uint8)(grey + dist);
747 						dist = (nBits[nOffset + 2] - grey) * 0.4;
748 						dcBits[nOffset + 2] = (uint8)(grey + dist);
749 						dcBits[nOffset + 3] = 255;
750 					}
751 					nBits += nbpr;
752 					dBits += nbpr;
753 					cBits += nbpr;
754 					dcBits += nbpr;
755 					fBits += fbpr;
756 				}
757 			// transparent version:
758 			} else if (format == B_RGBA32 || format == B_RGBA32_BIG) {
759 				// iterate over color components
760 				for (int32 y = 0; y < lines; y++) {
761 					for (int32 x = 0; x < pixels; x++) {
762 						int32 nOffset = 4 * x;
763 						int32 fOffset = 4 * x;
764 						nBits[nOffset + 0] = fBits[fOffset + 0];
765 						nBits[nOffset + 1] = fBits[fOffset + 1];
766 						nBits[nOffset + 2] = fBits[fOffset + 2];
767 						nBits[nOffset + 3] = fBits[fOffset + 3];
768 						// clicked bits are darker (lame method...)
769 						cBits[nOffset + 0] = (uint8)(nBits[nOffset + 0] * 0.8);
770 						cBits[nOffset + 1] = (uint8)(nBits[nOffset + 1] * 0.8);
771 						cBits[nOffset + 2] = (uint8)(nBits[nOffset + 2] * 0.8);
772 						cBits[nOffset + 3] = fBits[fOffset + 3];
773 						// disabled bits have less opacity
774 
775 						uint8 grey = ((uint16)nBits[nOffset + 0] * 10
776 						    + nBits[nOffset + 1] * 60
777 							+ nBits[nOffset + 2] * 30) / 100;
778 						float dist = (nBits[nOffset + 0] - grey) * 0.3;
779 						dBits[nOffset + 0] = (uint8)(grey + dist);
780 						dist = (nBits[nOffset + 1] - grey) * 0.3;
781 						dBits[nOffset + 1] = (uint8)(grey + dist);
782 						dist = (nBits[nOffset + 2] - grey) * 0.3;
783 						dBits[nOffset + 2] = (uint8)(grey + dist);
784 						dBits[nOffset + 3] = (uint8)(fBits[fOffset + 3] * 0.3);
785 						// disabled bits have less contrast (lame method...)
786 						dcBits[nOffset + 0] = (uint8)(dBits[nOffset + 0] * 0.8);
787 						dcBits[nOffset + 1] = (uint8)(dBits[nOffset + 1] * 0.8);
788 						dcBits[nOffset + 2] = (uint8)(dBits[nOffset + 2] * 0.8);
789 						dcBits[nOffset + 3] = (uint8)(fBits[fOffset + 3] * 0.3);
790 					}
791 					nBits += nbpr;
792 					dBits += nbpr;
793 					cBits += nbpr;
794 					dcBits += nbpr;
795 					fBits += fbpr;
796 				}
797 			// unsupported format
798 			} else {
799 				printf("BIconButton::_MakeBitmaps() - bitmap has unsupported "
800 					"colorspace\n");
801 				status = B_MISMATCHED_VALUES;
802 				_DeleteBitmaps();
803 			}
804 		} else {
805 			printf("BIconButton::_MakeBitmaps() - error allocating local "
806 				"bitmaps\n");
807 			status = B_NO_MEMORY;
808 			_DeleteBitmaps();
809 		}
810 	} else
811 		printf("BIconButton::_MakeBitmaps() - bitmap is not valid\n");
812 	return status;
813 }
814 
815 
816 void
817 BIconButton::_DeleteBitmaps()
818 {
819 	delete fNormalBitmap;
820 	fNormalBitmap = NULL;
821 	delete fDisabledBitmap;
822 	fDisabledBitmap = NULL;
823 	delete fClickedBitmap;
824 	fClickedBitmap = NULL;
825 	delete fDisabledClickedBitmap;
826 	fDisabledClickedBitmap = NULL;
827 }
828 
829 
830 void
831 BIconButton::_Update()
832 {
833 	if (LockLooper()) {
834 		Invalidate();
835 		UnlockLooper();
836 	}
837 }
838 
839 
840 void
841 BIconButton::_SetFlags(uint32 flags, bool set)
842 {
843 	if (_HasFlags(flags) != set) {
844 		if (set)
845 			fButtonState |= flags;
846 		else
847 			fButtonState &= ~flags;
848 
849 		if ((flags & STATE_PRESSED) != 0)
850 			SetValueNoUpdate(set ? B_CONTROL_ON : B_CONTROL_OFF);
851 		_Update();
852 	}
853 }
854 
855 
856 bool
857 BIconButton::_HasFlags(uint32 flags) const
858 {
859 	return (fButtonState & flags) != 0;
860 }
861 
862 
863 //!	This one calls _Update() if needed; BControl::SetTracking() isn't virtual.
864 void
865 BIconButton::_SetTracking(bool tracking)
866 {
867 	if (IsTracking() == tracking)
868 		return;
869 
870 	SetTracking(tracking);
871 	_Update();
872 }
873 
874 
875 }	// namespace BPrivate
876