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