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