1 /*
2 * Copyright 2006, Haiku.
3 * Distributed under the terms of the MIT License.
4 *
5 * Authors:
6 * Stephan Aßmus <superstippi@gmx.de>
7 */
8
9 #include "IconButton.h"
10
11 #include <new>
12 #include <stdio.h>
13
14 #include <Application.h>
15 #include <Bitmap.h>
16 #include <Control.h>
17 #include <Entry.h>
18 #include <Looper.h>
19 #include <Message.h>
20 #include <Mime.h>
21 #include <Path.h>
22 #include <Region.h>
23 #include <Roster.h>
24 #include <TranslationUtils.h>
25 #include <Window.h>
26
27 using std::nothrow;
28
29 // constructor
IconButton(const char * name,uint32 id,const char * label,BMessage * message,BHandler * target)30 IconButton::IconButton(const char* name, uint32 id, const char* label,
31 BMessage* message, BHandler* target)
32 : BView(BRect(0.0, 0.0, 10.0, 10.0), name, B_FOLLOW_NONE, B_WILL_DRAW),
33 BInvoker(message, target),
34 fButtonState(STATE_ENABLED),
35 fID(id),
36 fNormalBitmap(NULL),
37 fDisabledBitmap(NULL),
38 fClickedBitmap(NULL),
39 fDisabledClickedBitmap(NULL),
40 fLabel(label),
41 fTargetCache(target)
42 {
43 SetLowColor(ui_color(B_PANEL_BACKGROUND_COLOR));
44 SetViewColor(B_TRANSPARENT_32_BIT);
45 }
46
47 // destructor
~IconButton()48 IconButton::~IconButton()
49 {
50 _DeleteBitmaps();
51 }
52
53 // MessageReceived
54 void
MessageReceived(BMessage * message)55 IconButton::MessageReceived(BMessage* message)
56 {
57 switch (message->what) {
58 default:
59 BView::MessageReceived(message);
60 break;
61 }
62 }
63
64 // AttachedToWindow
65 void
AttachedToWindow()66 IconButton::AttachedToWindow()
67 {
68 SetTarget(fTargetCache);
69 if (!Target()) {
70 SetTarget(Window());
71 }
72 }
73
74 // Draw
75 void
Draw(BRect area)76 IconButton::Draw(BRect area)
77 {
78 rgb_color background = LowColor();
79 if (MView* parent = dynamic_cast<MView*>(Parent()))
80 background = parent->getcolor();
81 rgb_color lightShadow, shadow, darkShadow, light;
82 BRect r(Bounds());
83 BBitmap* bitmap = fNormalBitmap;
84 // adjust colors and bitmap according to flags
85 if (IsEnabled()) {
86 lightShadow = tint_color(background, B_DARKEN_1_TINT);
87 shadow = tint_color(background, B_DARKEN_2_TINT);
88 darkShadow = tint_color(background, B_DARKEN_4_TINT);
89 light = tint_color(background, B_LIGHTEN_MAX_TINT);
90 SetHighColor(0, 0, 0, 255);
91 } else {
92 lightShadow = tint_color(background, 1.11);
93 shadow = tint_color(background, B_DARKEN_1_TINT);
94 darkShadow = tint_color(background, B_DARKEN_2_TINT);
95 light = tint_color(background, B_LIGHTEN_2_TINT);
96 bitmap = fDisabledBitmap;
97 SetHighColor(tint_color(background, B_DISABLED_LABEL_TINT));
98 }
99 if (_HasFlags(STATE_PRESSED) || _HasFlags(STATE_FORCE_PRESSED)) {
100 if (IsEnabled()) {
101 // background = tint_color(background, B_DARKEN_2_TINT);
102 // background = tint_color(background, B_LIGHTEN_1_TINT);
103 background = tint_color(background, B_DARKEN_1_TINT);
104 bitmap = fClickedBitmap;
105 } else {
106 // background = tint_color(background, B_DARKEN_1_TINT);
107 // background = tint_color(background, (B_NO_TINT + B_LIGHTEN_1_TINT) / 2.0);
108 background = tint_color(background, (B_NO_TINT + B_DARKEN_1_TINT) / 2.0);
109 bitmap = fDisabledClickedBitmap;
110 }
111 // background
112 SetLowColor(background);
113 r.InsetBy(2.0, 2.0);
114 StrokeLine(r.LeftBottom(), r.LeftTop(), B_SOLID_LOW);
115 StrokeLine(r.LeftTop(), r.RightTop(), B_SOLID_LOW);
116 r.InsetBy(-2.0, -2.0);
117 }
118 // draw frame only if tracking
119 if (DrawBorder()) {
120 if (_HasFlags(STATE_PRESSED) || _HasFlags(STATE_FORCE_PRESSED))
121 DrawPressedBorder(r, background, shadow, darkShadow, lightShadow, light);
122 else
123 DrawNormalBorder(r, background, shadow, darkShadow, lightShadow, light);
124 r.InsetBy(2.0, 2.0);
125 } else
126 _DrawFrame(r, background, background, background, background);
127 float width = Bounds().Width();
128 float height = Bounds().Height();
129 // bitmap
130 BRegion originalClippingRegion;
131 if (bitmap && bitmap->IsValid()) {
132 float x = floorf((width - bitmap->Bounds().Width()) / 2.0 + 0.5);
133 float y = floorf((height - bitmap->Bounds().Height()) / 2.0 + 0.5);
134 BPoint point(x, y);
135 if (_HasFlags(STATE_PRESSED) || _HasFlags(STATE_FORCE_PRESSED))
136 point += BPoint(1.0, 1.0);
137 if (bitmap->ColorSpace() == B_RGBA32 || bitmap->ColorSpace() == B_RGBA32_BIG) {
138 FillRect(r, B_SOLID_LOW);
139 SetDrawingMode(B_OP_ALPHA);
140 SetBlendingMode(B_PIXEL_ALPHA, B_ALPHA_OVERLAY);
141 }
142 DrawBitmap(bitmap, point);
143 // constrain clipping region
144 BRegion region= originalClippingRegion;
145 GetClippingRegion(®ion);
146 region.Exclude(bitmap->Bounds().OffsetByCopy(point));
147 ConstrainClippingRegion(®ion);
148 }
149 // background
150 SetDrawingMode(B_OP_COPY);
151 FillRect(r, B_SOLID_LOW);
152 ConstrainClippingRegion(&originalClippingRegion);
153 // label
154 if (fLabel.CountChars() > 0) {
155 SetDrawingMode(B_OP_COPY);
156 font_height fh;
157 GetFontHeight(&fh);
158 float y = Bounds().bottom - 4.0;
159 y -= fh.descent;
160 float x = (width - StringWidth(fLabel.String())) / 2.0;
161 DrawString(fLabel.String(), BPoint(x, y));
162 }
163 }
164
165 // MouseDown
166 void
MouseDown(BPoint where)167 IconButton::MouseDown(BPoint where)
168 {
169 if (IsValid()) {
170 if (_HasFlags(STATE_ENABLED)/* && !_HasFlags(STATE_FORCE_PRESSED)*/) {
171 if (Bounds().Contains(where)) {
172 SetMouseEventMask(B_POINTER_EVENTS, B_LOCK_WINDOW_FOCUS);
173 _AddFlags(STATE_PRESSED | STATE_TRACKING);
174 } else {
175 _ClearFlags(STATE_PRESSED | STATE_TRACKING);
176 }
177 }
178 }
179 }
180
181 // MouseUp
182 void
MouseUp(BPoint where)183 IconButton::MouseUp(BPoint where)
184 {
185 if (IsValid()) {
186 // if (!_HasFlags(STATE_FORCE_PRESSED)) {
187 if (_HasFlags(STATE_ENABLED) && _HasFlags(STATE_PRESSED) && Bounds().Contains(where))
188 Invoke();
189 else if (Bounds().Contains(where))
190 _AddFlags(STATE_INSIDE);
191 _ClearFlags(STATE_PRESSED | STATE_TRACKING);
192 // }
193 }
194 }
195
196 // MouseMoved
197 void
MouseMoved(BPoint where,uint32 transit,const BMessage * message)198 IconButton::MouseMoved(BPoint where, uint32 transit, const BMessage* message)
199 {
200 if (IsValid()) {
201 uint32 buttons = 0;
202 Window()->CurrentMessage()->FindInt32("buttons", (int32*)&buttons);
203 // catch a mouse up event that we might have missed
204 if (!buttons && _HasFlags(STATE_PRESSED)) {
205 MouseUp(where);
206 return;
207 }
208 if (buttons && !_HasFlags(STATE_TRACKING))
209 return;
210 if ((transit == B_INSIDE_VIEW || transit == B_ENTERED_VIEW)
211 && _HasFlags(STATE_ENABLED))
212 _AddFlags(STATE_INSIDE);
213 else
214 _ClearFlags(STATE_INSIDE);
215 if (_HasFlags(STATE_TRACKING)) {
216 if (Bounds().Contains(where))
217 _AddFlags(STATE_PRESSED);
218 else
219 _ClearFlags(STATE_PRESSED);
220 }
221 }
222 }
223
224 // GetPreferredSize
225 void
GetPreferredSize(float * width,float * height)226 IconButton::GetPreferredSize(float* width, float* height)
227 {
228 layoutprefs();
229
230 if (width)
231 *width = mpm.mini.x;
232 if (height)
233 *height = mpm.mini.y;
234 }
235
236 // Invoke
237 status_t
Invoke(BMessage * message)238 IconButton::Invoke(BMessage* message)
239 {
240 if (!message)
241 message = Message();
242 if (message) {
243 BMessage clone(*message);
244 clone.AddInt64("be:when", system_time());
245 clone.AddPointer("be:source", (BView*)this);
246 clone.AddInt32("be:value", Value());
247 clone.AddInt32("id", ID());
248 return BInvoker::Invoke(&clone);
249 }
250 return BInvoker::Invoke(message);
251 }
252
253 #define MIN_SPACE 15.0
254
255 // layoutprefs
256 minimax
layoutprefs()257 IconButton::layoutprefs()
258 {
259 float minWidth = 0.0;
260 float minHeight = 0.0;
261 if (IsValid()) {
262 minWidth += fNormalBitmap->Bounds().IntegerWidth() + 1.0;
263 minHeight += fNormalBitmap->Bounds().IntegerHeight() + 1.0;
264 } else {
265 minWidth += MIN_SPACE;
266 minHeight += MIN_SPACE;
267 }
268 if (minWidth < MIN_SPACE)
269 minWidth = MIN_SPACE;
270 if (minHeight < MIN_SPACE)
271 minHeight = MIN_SPACE;
272 if (fLabel.CountChars() > 0) {
273 font_height fh;
274 GetFontHeight(&fh);
275 minHeight += ceilf(fh.ascent + fh.descent) + 4.0;
276 minWidth += StringWidth(fLabel.String()) + 4.0;
277 }
278 mpm.mini.x = minWidth + 4.0;
279 // mpm.maxi.x = 10000.0 + 4.0;
280 mpm.maxi.x = minWidth + 4.0;
281 mpm.mini.y = minHeight + 4.0;
282 // mpm.maxi.y = 10000.0 + 4.0;
283 mpm.maxi.y = minHeight + 4.0;
284 mpm.weight = 0.0;
285 return mpm;
286 }
287
288 // layout
289 BRect
layout(BRect rect)290 IconButton::layout(BRect rect)
291 {
292 MoveTo(rect.LeftTop());
293 ResizeTo(rect.Width(), rect.Height());
294 return Frame();
295 }
296
297 // SetPressed
298 void
SetPressed(bool pressed)299 IconButton::SetPressed(bool pressed)
300 {
301 if (pressed)
302 _AddFlags(STATE_FORCE_PRESSED);
303 else
304 _ClearFlags(STATE_FORCE_PRESSED);
305 }
306
307 // IsPressed
308 bool
IsPressed() const309 IconButton::IsPressed() const
310 {
311 return _HasFlags(STATE_FORCE_PRESSED);
312 }
313
314 // SetIcon
315 status_t
SetIcon(const char * pathToBitmap)316 IconButton::SetIcon(const char* pathToBitmap)
317 {
318 status_t status = B_BAD_VALUE;
319 if (pathToBitmap) {
320 BBitmap* fileBitmap = NULL;
321 // try to load bitmap from either relative or absolute path
322 BEntry entry(pathToBitmap, true);
323 if (!entry.Exists()) {
324 app_info info;
325 status = be_app->GetAppInfo(&info);
326 if (status == B_OK) {
327 BEntry app_entry(&info.ref, true);
328 BPath path;
329 app_entry.GetPath(&path);
330 status = path.InitCheck();
331 if (status == B_OK) {
332 status = path.GetParent(&path);
333 if (status == B_OK) {
334 status = path.Append(pathToBitmap, true);
335 if (status == B_OK)
336 fileBitmap = BTranslationUtils::GetBitmap(path.Path());
337 else
338 printf("IconButton::SetIcon() - path.Append() failed: %s\n", strerror(status));
339 } else
340 printf("IconButton::SetIcon() - path.GetParent() failed: %s\n", strerror(status));
341 } else
342 printf("IconButton::SetIcon() - path.InitCheck() failed: %s\n", strerror(status));
343 } else
344 printf("IconButton::SetIcon() - be_app->GetAppInfo() failed: %s\n", strerror(status));
345 } else
346 fileBitmap = BTranslationUtils::GetBitmap(pathToBitmap);
347 if (fileBitmap) {
348 status = _MakeBitmaps(fileBitmap);
349 delete fileBitmap;
350 } else
351 status = B_ERROR;
352 }
353 return status;
354 }
355
356 // SetIcon
357 status_t
SetIcon(const BBitmap * bitmap)358 IconButton::SetIcon(const BBitmap* bitmap)
359 {
360 if (bitmap && bitmap->ColorSpace() == B_CMAP8) {
361 status_t status = bitmap->InitCheck();
362 if (status >= B_OK) {
363 if (BBitmap* rgb32Bitmap = _ConvertToRGB32(bitmap)) {
364 status = _MakeBitmaps(rgb32Bitmap);
365 delete rgb32Bitmap;
366 } else
367 status = B_NO_MEMORY;
368 }
369 return status;
370 } else
371 return _MakeBitmaps(bitmap);
372 }
373
374 // SetIcon
375 status_t
SetIcon(const BMimeType * fileType,bool small)376 IconButton::SetIcon(const BMimeType* fileType, bool small)
377 {
378 status_t status = fileType ? fileType->InitCheck() : B_BAD_VALUE;
379 if (status >= B_OK) {
380 BBitmap* mimeBitmap = new(nothrow) BBitmap(BRect(0.0, 0.0, 15.0, 15.0), B_CMAP8);
381 if (mimeBitmap && mimeBitmap->IsValid()) {
382 status = fileType->GetIcon(mimeBitmap, small ? B_MINI_ICON : B_LARGE_ICON);
383 if (status >= B_OK) {
384 if (BBitmap* bitmap = _ConvertToRGB32(mimeBitmap)) {
385 status = _MakeBitmaps(bitmap);
386 delete bitmap;
387 } else
388 printf("IconButton::SetIcon() - B_RGB32 bitmap is not valid\n");
389 } else
390 printf("IconButton::SetIcon() - fileType->GetIcon() failed: %s\n", strerror(status));
391 } else
392 printf("IconButton::SetIcon() - B_CMAP8 bitmap is not valid\n");
393 delete mimeBitmap;
394 } else
395 printf("IconButton::SetIcon() - fileType is not valid: %s\n", strerror(status));
396 return status;
397 }
398
399 // SetIcon
400 status_t
SetIcon(const unsigned char * bitsFromQuickRes,uint32 width,uint32 height,color_space format,bool convertToBW)401 IconButton::SetIcon(const unsigned char* bitsFromQuickRes,
402 uint32 width, uint32 height, color_space format, bool convertToBW)
403 {
404 status_t status = B_BAD_VALUE;
405 if (bitsFromQuickRes && width > 0 && height > 0) {
406 BBitmap* quickResBitmap = new(nothrow) BBitmap(BRect(0.0, 0.0, width - 1.0, height - 1.0), format);
407 status = quickResBitmap ? quickResBitmap->InitCheck() : B_ERROR;
408 if (status >= B_OK) {
409 // It doesn't look right to copy BitsLength() bytes, but bitmaps
410 // exported from QuickRes still contain their padding, so it is alright.
411 memcpy(quickResBitmap->Bits(), bitsFromQuickRes, quickResBitmap->BitsLength());
412 if (format != B_RGB32 && format != B_RGBA32 && format != B_RGB32_BIG && format != B_RGBA32_BIG) {
413 // colorspace needs conversion
414 BBitmap* bitmap = new(nothrow) BBitmap(quickResBitmap->Bounds(), B_RGB32, true);
415 if (bitmap && bitmap->IsValid()) {
416 BView* helper = new BView(bitmap->Bounds(), "helper",
417 B_FOLLOW_NONE, B_WILL_DRAW);
418 if (bitmap->Lock()) {
419 bitmap->AddChild(helper);
420 helper->SetHighColor(ui_color(B_PANEL_BACKGROUND_COLOR));
421 helper->FillRect(helper->Bounds());
422 helper->SetDrawingMode(B_OP_OVER);
423 helper->DrawBitmap(quickResBitmap, BPoint(0.0, 0.0));
424 helper->Sync();
425 bitmap->Unlock();
426 }
427 status = _MakeBitmaps(bitmap);
428 } else
429 printf("IconButton::SetIcon() - B_RGB32 bitmap is not valid\n");
430 delete bitmap;
431 } else {
432 // native colorspace (32 bits)
433 if (convertToBW) {
434 // convert to gray scale icon
435 uint8* bits = (uint8*)quickResBitmap->Bits();
436 uint32 bpr = quickResBitmap->BytesPerRow();
437 for (uint32 y = 0; y < height; y++) {
438 uint8* handle = bits;
439 uint8 gray;
440 for (uint32 x = 0; x < width; x++) {
441 gray = uint8((116 * handle[0] + 600 * handle[1] + 308 * handle[2]) / 1024);
442 handle[0] = gray;
443 handle[1] = gray;
444 handle[2] = gray;
445 handle += 4;
446 }
447 bits += bpr;
448 }
449 }
450 status = _MakeBitmaps(quickResBitmap);
451 }
452 } else
453 printf("IconButton::SetIcon() - error allocating bitmap: %s\n", strerror(status));
454 delete quickResBitmap;
455 }
456 return status;
457 }
458
459 // ClearIcon
460 void
ClearIcon()461 IconButton::ClearIcon()
462 {
463 _DeleteBitmaps();
464 _Update();
465 }
466
467 // Bitmap
468 BBitmap*
Bitmap() const469 IconButton::Bitmap() const
470 {
471 BBitmap* bitmap = NULL;
472 if (fNormalBitmap && fNormalBitmap->IsValid()) {
473 bitmap = new(nothrow) BBitmap(fNormalBitmap);
474 if (bitmap->IsValid()) {
475 // TODO: remove this functionality when we use real transparent bitmaps
476 uint8* bits = (uint8*)bitmap->Bits();
477 uint32 bpr = bitmap->BytesPerRow();
478 uint32 width = bitmap->Bounds().IntegerWidth() + 1;
479 uint32 height = bitmap->Bounds().IntegerHeight() + 1;
480 color_space format = bitmap->ColorSpace();
481 if (format == B_CMAP8) {
482 // replace gray with magic transparent index
483 } else if (format == B_RGB32) {
484 for (uint32 y = 0; y < height; y++) {
485 uint8* bitsHandle = bits;
486 for (uint32 x = 0; x < width; x++) {
487 if (bitsHandle[0] == 216
488 && bitsHandle[1] == 216
489 && bitsHandle[2] == 216) {
490 bitsHandle[3] = 0; // make this pixel completely transparent
491 }
492 bitsHandle += 4;
493 }
494 bits += bpr;
495 }
496 }
497 } else {
498 delete bitmap;
499 bitmap = NULL;
500 }
501 }
502 return bitmap;
503 }
504
505 // DrawBorder
506 bool
DrawBorder() const507 IconButton::DrawBorder() const
508 {
509 return (IsEnabled() && (_HasFlags(STATE_INSIDE) || _HasFlags(STATE_TRACKING))
510 || _HasFlags(STATE_FORCE_PRESSED));
511 }
512
513 // DrawNormalBorder
514 void
DrawNormalBorder(BRect r,rgb_color background,rgb_color shadow,rgb_color darkShadow,rgb_color lightShadow,rgb_color light)515 IconButton::DrawNormalBorder(BRect r, rgb_color background,
516 rgb_color shadow, rgb_color darkShadow,
517 rgb_color lightShadow, rgb_color light)
518 {
519 _DrawFrame(r, shadow, darkShadow, light, lightShadow);
520 }
521
522 // DrawPressedBorder
523 void
DrawPressedBorder(BRect r,rgb_color background,rgb_color shadow,rgb_color darkShadow,rgb_color lightShadow,rgb_color light)524 IconButton::DrawPressedBorder(BRect r, rgb_color background,
525 rgb_color shadow, rgb_color darkShadow,
526 rgb_color lightShadow, rgb_color light)
527 {
528 _DrawFrame(r, shadow, light, darkShadow, background);
529 }
530
531 // IsValid
532 bool
IsValid() const533 IconButton::IsValid() const
534 {
535 return (fNormalBitmap && fDisabledBitmap && fClickedBitmap && fDisabledClickedBitmap
536 && fNormalBitmap->IsValid()
537 && fDisabledBitmap->IsValid()
538 && fClickedBitmap->IsValid()
539 && fDisabledClickedBitmap->IsValid());
540 }
541
542 // Value
543 int32
Value() const544 IconButton::Value() const
545 {
546 return _HasFlags(STATE_PRESSED) ? B_CONTROL_ON : B_CONTROL_OFF;
547 }
548
549 // SetValue
550 void
SetValue(int32 value)551 IconButton::SetValue(int32 value)
552 {
553 if (value)
554 _AddFlags(STATE_PRESSED);
555 else
556 _ClearFlags(STATE_PRESSED);
557 }
558
559 // IsEnabled
560 bool
IsEnabled() const561 IconButton::IsEnabled() const
562 {
563 return _HasFlags(STATE_ENABLED) ? B_CONTROL_ON : B_CONTROL_OFF;
564 }
565
566 // SetEnabled
567 void
SetEnabled(bool enabled)568 IconButton::SetEnabled(bool enabled)
569 {
570 if (enabled)
571 _AddFlags(STATE_ENABLED);
572 else
573 _ClearFlags(STATE_ENABLED | STATE_TRACKING | STATE_INSIDE);
574 }
575
576 // _ConvertToRGB32
577 BBitmap*
_ConvertToRGB32(const BBitmap * bitmap) const578 IconButton::_ConvertToRGB32(const BBitmap* bitmap) const
579 {
580 BBitmap* convertedBitmap = new(nothrow) BBitmap(bitmap->Bounds(), B_BITMAP_ACCEPTS_VIEWS, B_RGBA32);
581 if (convertedBitmap && convertedBitmap->IsValid()) {
582 memset(convertedBitmap->Bits(), 0, convertedBitmap->BitsLength());
583 BView* helper = new BView(bitmap->Bounds(), "helper",
584 B_FOLLOW_NONE, B_WILL_DRAW);
585 if (convertedBitmap->Lock()) {
586 convertedBitmap->AddChild(helper);
587 helper->SetDrawingMode(B_OP_OVER);
588 helper->DrawBitmap(bitmap, BPoint(0.0, 0.0));
589 helper->Sync();
590 convertedBitmap->Unlock();
591 }
592 } else {
593 delete convertedBitmap;
594 convertedBitmap = NULL;
595 }
596 return convertedBitmap;
597 }
598
599 // _MakeBitmaps
600 status_t
_MakeBitmaps(const BBitmap * bitmap)601 IconButton::_MakeBitmaps(const BBitmap* bitmap)
602 {
603 status_t status = bitmap ? bitmap->InitCheck() : B_BAD_VALUE;
604 if (status >= B_OK) {
605 // make our own versions of the bitmap
606 BRect b(bitmap->Bounds());
607 _DeleteBitmaps();
608 color_space format = bitmap->ColorSpace();
609 fNormalBitmap = new(nothrow) BBitmap(b, format);
610 fDisabledBitmap = new(nothrow) BBitmap(b, format);
611 fClickedBitmap = new(nothrow) BBitmap(b, format);
612 fDisabledClickedBitmap = new(nothrow) BBitmap(b, format);
613 if (IsValid()) {
614 // copy bitmaps from file bitmap
615 uint8* nBits = (uint8*)fNormalBitmap->Bits();
616 uint8* dBits = (uint8*)fDisabledBitmap->Bits();
617 uint8* cBits = (uint8*)fClickedBitmap->Bits();
618 uint8* dcBits = (uint8*)fDisabledClickedBitmap->Bits();
619 uint8* fBits = (uint8*)bitmap->Bits();
620 int32 nbpr = fNormalBitmap->BytesPerRow();
621 int32 fbpr = bitmap->BytesPerRow();
622 int32 pixels = b.IntegerWidth() + 1;
623 int32 lines = b.IntegerHeight() + 1;
624 // nontransparent version:
625 if (format == B_RGB32 || format == B_RGB32_BIG) {
626 // iterate over color components
627 for (int32 y = 0; y < lines; y++) {
628 for (int32 x = 0; x < pixels; x++) {
629 int32 nOffset = 4 * x;
630 int32 fOffset = 4 * x;
631 nBits[nOffset + 0] = fBits[fOffset + 0];
632 nBits[nOffset + 1] = fBits[fOffset + 1];
633 nBits[nOffset + 2] = fBits[fOffset + 2];
634 nBits[nOffset + 3] = 255;
635 // clicked bits are darker (lame method...)
636 cBits[nOffset + 0] = (uint8)((float)nBits[nOffset + 0] * 0.8);
637 cBits[nOffset + 1] = (uint8)((float)nBits[nOffset + 1] * 0.8);
638 cBits[nOffset + 2] = (uint8)((float)nBits[nOffset + 2] * 0.8);
639 cBits[nOffset + 3] = 255;
640 // disabled bits have less contrast (lame method...)
641 uint8 grey = 216;
642 float dist = (nBits[nOffset + 0] - grey) * 0.4;
643 dBits[nOffset + 0] = (uint8)(grey + dist);
644 dist = (nBits[nOffset + 1] - grey) * 0.4;
645 dBits[nOffset + 1] = (uint8)(grey + dist);
646 dist = (nBits[nOffset + 2] - grey) * 0.4;
647 dBits[nOffset + 2] = (uint8)(grey + dist);
648 dBits[nOffset + 3] = 255;
649 // disabled bits have less contrast (lame method...)
650 grey = 188;
651 dist = (nBits[nOffset + 0] - grey) * 0.4;
652 dcBits[nOffset + 0] = (uint8)(grey + dist);
653 dist = (nBits[nOffset + 1] - grey) * 0.4;
654 dcBits[nOffset + 1] = (uint8)(grey + dist);
655 dist = (nBits[nOffset + 2] - grey) * 0.4;
656 dcBits[nOffset + 2] = (uint8)(grey + dist);
657 dcBits[nOffset + 3] = 255;
658 }
659 nBits += nbpr;
660 dBits += nbpr;
661 cBits += nbpr;
662 dcBits += nbpr;
663 fBits += fbpr;
664 }
665 // transparent version:
666 } else if (format == B_RGBA32 || format == B_RGBA32_BIG) {
667 // iterate over color components
668 for (int32 y = 0; y < lines; y++) {
669 for (int32 x = 0; x < pixels; x++) {
670 int32 nOffset = 4 * x;
671 int32 fOffset = 4 * x;
672 nBits[nOffset + 0] = fBits[fOffset + 0];
673 nBits[nOffset + 1] = fBits[fOffset + 1];
674 nBits[nOffset + 2] = fBits[fOffset + 2];
675 nBits[nOffset + 3] = fBits[fOffset + 3];
676 // clicked bits are darker (lame method...)
677 cBits[nOffset + 0] = (uint8)(nBits[nOffset + 0] * 0.8);
678 cBits[nOffset + 1] = (uint8)(nBits[nOffset + 1] * 0.8);
679 cBits[nOffset + 2] = (uint8)(nBits[nOffset + 2] * 0.8);
680 cBits[nOffset + 3] = fBits[fOffset + 3];
681 // disabled bits have less opacity
682 dBits[nOffset + 0] = fBits[fOffset + 0];
683 dBits[nOffset + 1] = fBits[fOffset + 1];
684 dBits[nOffset + 2] = fBits[fOffset + 2];
685 dBits[nOffset + 3] = (uint8)(fBits[fOffset + 3] * 0.5);
686 // disabled bits have less contrast (lame method...)
687 dcBits[nOffset + 0] = (uint8)(nBits[nOffset + 0] * 0.8);
688 dcBits[nOffset + 1] = (uint8)(nBits[nOffset + 1] * 0.8);
689 dcBits[nOffset + 2] = (uint8)(nBits[nOffset + 2] * 0.8);
690 dcBits[nOffset + 3] = (uint8)(fBits[fOffset + 3] * 0.5);
691 }
692 nBits += nbpr;
693 dBits += nbpr;
694 cBits += nbpr;
695 dcBits += nbpr;
696 fBits += fbpr;
697 }
698 // unsupported format
699 } else {
700 printf("IconButton::_MakeBitmaps() - bitmap has unsupported colorspace\n");
701 status = B_MISMATCHED_VALUES;
702 _DeleteBitmaps();
703 }
704 } else {
705 printf("IconButton::_MakeBitmaps() - error allocating local bitmaps\n");
706 status = B_NO_MEMORY;
707 _DeleteBitmaps();
708 }
709 } else
710 printf("IconButton::_MakeBitmaps() - bitmap is not valid\n");
711 return status;
712 }
713
714 // _DeleteBitmaps
715 void
_DeleteBitmaps()716 IconButton::_DeleteBitmaps()
717 {
718 delete fNormalBitmap;
719 fNormalBitmap = NULL;
720 delete fDisabledBitmap;
721 fDisabledBitmap = NULL;
722 delete fClickedBitmap;
723 fClickedBitmap = NULL;
724 delete fDisabledClickedBitmap;
725 fDisabledClickedBitmap = NULL;
726 }
727
728 // _Update
729 void
_Update()730 IconButton::_Update()
731 {
732 if (LockLooper()) {
733 Invalidate();
734 UnlockLooper();
735 }
736 }
737
738 // _AddFlags
739 void
_AddFlags(uint32 flags)740 IconButton::_AddFlags(uint32 flags)
741 {
742 if (!(fButtonState & flags)) {
743 fButtonState |= flags;
744 _Update();
745 }
746 }
747
748 // _ClearFlags
749 void
_ClearFlags(uint32 flags)750 IconButton::_ClearFlags(uint32 flags)
751 {
752 if (fButtonState & flags) {
753 fButtonState &= ~flags;
754 _Update();
755 }
756 }
757
758 // _HasFlags
759 bool
_HasFlags(uint32 flags) const760 IconButton::_HasFlags(uint32 flags) const
761 {
762 return (fButtonState & flags);
763 }
764
765 // _DrawFrame
766 void
_DrawFrame(BRect r,rgb_color col1,rgb_color col2,rgb_color col3,rgb_color col4)767 IconButton::_DrawFrame(BRect r, rgb_color col1, rgb_color col2,
768 rgb_color col3, rgb_color col4)
769 {
770 BeginLineArray(8);
771 AddLine(BPoint(r.left, r.bottom), BPoint(r.left, r.top), col1);
772 AddLine(BPoint(r.left + 1.0, r.top), BPoint(r.right, r.top), col1);
773 AddLine(BPoint(r.right, r.top + 1.0), BPoint(r.right, r.bottom), col2);
774 AddLine(BPoint(r.right - 1.0, r.bottom), BPoint(r.left + 1.0, r.bottom), col2);
775 r.InsetBy(1.0, 1.0);
776 AddLine(BPoint(r.left, r.bottom), BPoint(r.left, r.top), col3);
777 AddLine(BPoint(r.left + 1.0, r.top), BPoint(r.right, r.top), col3);
778 AddLine(BPoint(r.right, r.top + 1.0), BPoint(r.right, r.bottom), col4);
779 AddLine(BPoint(r.right - 1.0, r.bottom), BPoint(r.left + 1.0, r.bottom), col4);
780 EndLineArray();
781 }
782