* it has been rewritten from using liblayout to use the new Haiku layout framework * TODO: it should come with default settings * TODO: the minimum window size is not yet set by the layout framework (?) git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@21373 a95241bf-73f2-0310-859d-f6bbb57e9c96
761 lines
21 KiB
C++
761 lines
21 KiB
C++
/*
|
|
* Copyright 2006, Haiku.
|
|
* Distributed under the terms of the MIT License.
|
|
*
|
|
* Authors:
|
|
* Stephan Aßmus <[email protected]>
|
|
*/
|
|
|
|
// NOTE: this file is a duplicate of the version in Icon-O-Matic/generic
|
|
// it should be placed into a common folder for generic useful stuff
|
|
|
|
#include "IconButton.h"
|
|
|
|
#include <new>
|
|
#include <stdio.h>
|
|
|
|
#include <Application.h>
|
|
#include <Bitmap.h>
|
|
#include <Control.h>
|
|
#include <Entry.h>
|
|
#include <Looper.h>
|
|
#include <Message.h>
|
|
#include <Mime.h>
|
|
#include <Path.h>
|
|
#include <Region.h>
|
|
#include <Roster.h>
|
|
#include <TranslationUtils.h>
|
|
#include <Window.h>
|
|
|
|
using std::nothrow;
|
|
|
|
// constructor
|
|
IconButton::IconButton(const char* name, uint32 id, const char* label,
|
|
BMessage* message, BHandler* target)
|
|
: BView(BRect(0.0, 0.0, 10.0, 10.0), name, B_FOLLOW_NONE, B_WILL_DRAW),
|
|
BInvoker(message, target),
|
|
fButtonState(STATE_ENABLED),
|
|
fID(id),
|
|
fNormalBitmap(NULL),
|
|
fDisabledBitmap(NULL),
|
|
fClickedBitmap(NULL),
|
|
fDisabledClickedBitmap(NULL),
|
|
fLabel(label),
|
|
fTargetCache(target)
|
|
{
|
|
SetLowColor(ui_color(B_PANEL_BACKGROUND_COLOR));
|
|
SetViewColor(B_TRANSPARENT_32_BIT);
|
|
}
|
|
|
|
// destructor
|
|
IconButton::~IconButton()
|
|
{
|
|
_DeleteBitmaps();
|
|
}
|
|
|
|
// MessageReceived
|
|
void
|
|
IconButton::MessageReceived(BMessage* message)
|
|
{
|
|
switch (message->what) {
|
|
default:
|
|
BView::MessageReceived(message);
|
|
break;
|
|
}
|
|
}
|
|
|
|
// AttachedToWindow
|
|
void
|
|
IconButton::AttachedToWindow()
|
|
{
|
|
SetTarget(fTargetCache);
|
|
if (!Target()) {
|
|
SetTarget(Window());
|
|
}
|
|
}
|
|
|
|
// Draw
|
|
void
|
|
IconButton::Draw(BRect area)
|
|
{
|
|
rgb_color background = LowColor();
|
|
if (BView* parent = Parent())
|
|
background = parent->ViewColor();
|
|
rgb_color lightShadow, shadow, darkShadow, light;
|
|
BRect r(Bounds());
|
|
BBitmap* bitmap = fNormalBitmap;
|
|
// adjust colors and bitmap according to flags
|
|
if (IsEnabled()) {
|
|
lightShadow = tint_color(background, B_DARKEN_1_TINT);
|
|
shadow = tint_color(background, B_DARKEN_2_TINT);
|
|
darkShadow = tint_color(background, B_DARKEN_4_TINT);
|
|
light = tint_color(background, B_LIGHTEN_MAX_TINT);
|
|
SetHighColor(0, 0, 0, 255);
|
|
} else {
|
|
lightShadow = tint_color(background, 1.11);
|
|
shadow = tint_color(background, B_DARKEN_1_TINT);
|
|
darkShadow = tint_color(background, B_DARKEN_2_TINT);
|
|
light = tint_color(background, B_LIGHTEN_2_TINT);
|
|
bitmap = fDisabledBitmap;
|
|
SetHighColor(tint_color(background, B_DISABLED_LABEL_TINT));
|
|
}
|
|
if (_HasFlags(STATE_PRESSED) || _HasFlags(STATE_FORCE_PRESSED)) {
|
|
if (IsEnabled()) {
|
|
// background = tint_color(background, B_DARKEN_2_TINT);
|
|
// background = tint_color(background, B_LIGHTEN_1_TINT);
|
|
background = tint_color(background, B_DARKEN_1_TINT);
|
|
bitmap = fClickedBitmap;
|
|
} else {
|
|
// background = tint_color(background, B_DARKEN_1_TINT);
|
|
// background = tint_color(background, (B_NO_TINT + B_LIGHTEN_1_TINT) / 2.0);
|
|
background = tint_color(background, (B_NO_TINT + B_DARKEN_1_TINT) / 2.0);
|
|
bitmap = fDisabledClickedBitmap;
|
|
}
|
|
// background
|
|
SetLowColor(background);
|
|
r.InsetBy(2.0, 2.0);
|
|
StrokeLine(r.LeftBottom(), r.LeftTop(), B_SOLID_LOW);
|
|
StrokeLine(r.LeftTop(), r.RightTop(), B_SOLID_LOW);
|
|
r.InsetBy(-2.0, -2.0);
|
|
}
|
|
// draw frame only if tracking
|
|
if (DrawBorder()) {
|
|
if (_HasFlags(STATE_PRESSED) || _HasFlags(STATE_FORCE_PRESSED))
|
|
DrawPressedBorder(r, background, shadow, darkShadow, lightShadow, light);
|
|
else
|
|
DrawNormalBorder(r, background, shadow, darkShadow, lightShadow, light);
|
|
r.InsetBy(2.0, 2.0);
|
|
} else
|
|
_DrawFrame(r, background, background, background, background);
|
|
float width = Bounds().Width();
|
|
float height = Bounds().Height();
|
|
// bitmap
|
|
BRegion originalClippingRegion;
|
|
if (bitmap && bitmap->IsValid()) {
|
|
float x = floorf((width - bitmap->Bounds().Width()) / 2.0 + 0.5);
|
|
float y = floorf((height - bitmap->Bounds().Height()) / 2.0 + 0.5);
|
|
BPoint point(x, y);
|
|
if (_HasFlags(STATE_PRESSED) || _HasFlags(STATE_FORCE_PRESSED))
|
|
point += BPoint(1.0, 1.0);
|
|
if (bitmap->ColorSpace() == B_RGBA32 || bitmap->ColorSpace() == B_RGBA32_BIG) {
|
|
FillRect(r, B_SOLID_LOW);
|
|
SetDrawingMode(B_OP_ALPHA);
|
|
SetBlendingMode(B_PIXEL_ALPHA, B_ALPHA_OVERLAY);
|
|
}
|
|
DrawBitmap(bitmap, point);
|
|
// constrain clipping region
|
|
BRegion region= originalClippingRegion;
|
|
GetClippingRegion(®ion);
|
|
region.Exclude(bitmap->Bounds().OffsetByCopy(point));
|
|
ConstrainClippingRegion(®ion);
|
|
}
|
|
// background
|
|
SetDrawingMode(B_OP_COPY);
|
|
FillRect(r, B_SOLID_LOW);
|
|
ConstrainClippingRegion(&originalClippingRegion);
|
|
// label
|
|
if (fLabel.CountChars() > 0) {
|
|
SetDrawingMode(B_OP_COPY);
|
|
font_height fh;
|
|
GetFontHeight(&fh);
|
|
float y = Bounds().bottom - 4.0;
|
|
y -= fh.descent;
|
|
float x = (width - StringWidth(fLabel.String())) / 2.0;
|
|
DrawString(fLabel.String(), BPoint(x, y));
|
|
}
|
|
}
|
|
|
|
// MouseDown
|
|
void
|
|
IconButton::MouseDown(BPoint where)
|
|
{
|
|
if (IsValid()) {
|
|
if (_HasFlags(STATE_ENABLED)/* && !_HasFlags(STATE_FORCE_PRESSED)*/) {
|
|
if (Bounds().Contains(where)) {
|
|
SetMouseEventMask(B_POINTER_EVENTS, B_LOCK_WINDOW_FOCUS);
|
|
_AddFlags(STATE_PRESSED | STATE_TRACKING);
|
|
} else {
|
|
_ClearFlags(STATE_PRESSED | STATE_TRACKING);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// MouseUp
|
|
void
|
|
IconButton::MouseUp(BPoint where)
|
|
{
|
|
if (IsValid()) {
|
|
// if (!_HasFlags(STATE_FORCE_PRESSED)) {
|
|
if (_HasFlags(STATE_ENABLED) && _HasFlags(STATE_PRESSED) && Bounds().Contains(where))
|
|
Invoke();
|
|
else if (Bounds().Contains(where))
|
|
_AddFlags(STATE_INSIDE);
|
|
_ClearFlags(STATE_PRESSED | STATE_TRACKING);
|
|
// }
|
|
}
|
|
}
|
|
|
|
// MouseMoved
|
|
void
|
|
IconButton::MouseMoved(BPoint where, uint32 transit, const BMessage* message)
|
|
{
|
|
if (IsValid()) {
|
|
uint32 buttons = 0;
|
|
Window()->CurrentMessage()->FindInt32("buttons", (int32*)&buttons);
|
|
// catch a mouse up event that we might have missed
|
|
if (!buttons && _HasFlags(STATE_PRESSED)) {
|
|
MouseUp(where);
|
|
return;
|
|
}
|
|
if (buttons && !_HasFlags(STATE_TRACKING))
|
|
return;
|
|
if ((transit == B_INSIDE_VIEW || transit == B_ENTERED_VIEW)
|
|
&& _HasFlags(STATE_ENABLED))
|
|
_AddFlags(STATE_INSIDE);
|
|
else
|
|
_ClearFlags(STATE_INSIDE);
|
|
if (_HasFlags(STATE_TRACKING)) {
|
|
if (Bounds().Contains(where))
|
|
_AddFlags(STATE_PRESSED);
|
|
else
|
|
_ClearFlags(STATE_PRESSED);
|
|
}
|
|
}
|
|
}
|
|
|
|
#define MIN_SPACE 15.0
|
|
|
|
// GetPreferredSize
|
|
void
|
|
IconButton::GetPreferredSize(float* width, float* height)
|
|
{
|
|
float minWidth = 0.0;
|
|
float minHeight = 0.0;
|
|
if (IsValid()) {
|
|
minWidth += fNormalBitmap->Bounds().IntegerWidth() + 1.0;
|
|
minHeight += fNormalBitmap->Bounds().IntegerHeight() + 1.0;
|
|
} else {
|
|
minWidth += MIN_SPACE;
|
|
minHeight += MIN_SPACE;
|
|
}
|
|
if (minWidth < MIN_SPACE)
|
|
minWidth = MIN_SPACE;
|
|
if (minHeight < MIN_SPACE)
|
|
minHeight = MIN_SPACE;
|
|
if (fLabel.CountChars() > 0) {
|
|
font_height fh;
|
|
GetFontHeight(&fh);
|
|
minHeight += ceilf(fh.ascent + fh.descent) + 4.0;
|
|
minWidth += StringWidth(fLabel.String()) + 4.0;
|
|
}
|
|
|
|
if (width)
|
|
*width = minWidth + 4.0;
|
|
if (height)
|
|
*height = minHeight + 4.0;
|
|
}
|
|
|
|
// Invoke
|
|
status_t
|
|
IconButton::Invoke(BMessage* message)
|
|
{
|
|
if (!message)
|
|
message = Message();
|
|
if (message) {
|
|
BMessage clone(*message);
|
|
clone.AddInt64("be:when", system_time());
|
|
clone.AddPointer("be:source", (BView*)this);
|
|
clone.AddInt32("be:value", Value());
|
|
clone.AddInt32("id", ID());
|
|
return BInvoker::Invoke(&clone);
|
|
}
|
|
return BInvoker::Invoke(message);
|
|
}
|
|
|
|
// SetPressed
|
|
void
|
|
IconButton::SetPressed(bool pressed)
|
|
{
|
|
if (pressed)
|
|
_AddFlags(STATE_FORCE_PRESSED);
|
|
else
|
|
_ClearFlags(STATE_FORCE_PRESSED);
|
|
}
|
|
|
|
// IsPressed
|
|
bool
|
|
IconButton::IsPressed() const
|
|
{
|
|
return _HasFlags(STATE_FORCE_PRESSED);
|
|
}
|
|
|
|
// SetIcon
|
|
status_t
|
|
IconButton::SetIcon(const char* pathToBitmap)
|
|
{
|
|
status_t status = B_BAD_VALUE;
|
|
if (pathToBitmap) {
|
|
BBitmap* fileBitmap = NULL;
|
|
// try to load bitmap from either relative or absolute path
|
|
BEntry entry(pathToBitmap, true);
|
|
if (!entry.Exists()) {
|
|
app_info info;
|
|
status = be_app->GetAppInfo(&info);
|
|
if (status == B_OK) {
|
|
BEntry app_entry(&info.ref, true);
|
|
BPath path;
|
|
app_entry.GetPath(&path);
|
|
status = path.InitCheck();
|
|
if (status == B_OK) {
|
|
status = path.GetParent(&path);
|
|
if (status == B_OK) {
|
|
status = path.Append(pathToBitmap, true);
|
|
if (status == B_OK)
|
|
fileBitmap = BTranslationUtils::GetBitmap(path.Path());
|
|
else
|
|
printf("IconButton::SetIcon() - path.Append() failed: %s\n", strerror(status));
|
|
} else
|
|
printf("IconButton::SetIcon() - path.GetParent() failed: %s\n", strerror(status));
|
|
} else
|
|
printf("IconButton::SetIcon() - path.InitCheck() failed: %s\n", strerror(status));
|
|
} else
|
|
printf("IconButton::SetIcon() - be_app->GetAppInfo() failed: %s\n", strerror(status));
|
|
} else
|
|
fileBitmap = BTranslationUtils::GetBitmap(pathToBitmap);
|
|
if (fileBitmap) {
|
|
status = _MakeBitmaps(fileBitmap);
|
|
delete fileBitmap;
|
|
} else
|
|
status = B_ERROR;
|
|
}
|
|
return status;
|
|
}
|
|
|
|
// SetIcon
|
|
status_t
|
|
IconButton::SetIcon(const BBitmap* bitmap)
|
|
{
|
|
if (bitmap && bitmap->ColorSpace() == B_CMAP8) {
|
|
status_t status = bitmap->InitCheck();
|
|
if (status >= B_OK) {
|
|
if (BBitmap* rgb32Bitmap = _ConvertToRGB32(bitmap)) {
|
|
status = _MakeBitmaps(rgb32Bitmap);
|
|
delete rgb32Bitmap;
|
|
} else
|
|
status = B_NO_MEMORY;
|
|
}
|
|
return status;
|
|
} else
|
|
return _MakeBitmaps(bitmap);
|
|
}
|
|
|
|
// SetIcon
|
|
status_t
|
|
IconButton::SetIcon(const BMimeType* fileType, bool small)
|
|
{
|
|
status_t status = fileType ? fileType->InitCheck() : B_BAD_VALUE;
|
|
if (status >= B_OK) {
|
|
BBitmap* mimeBitmap = new(nothrow) BBitmap(BRect(0.0, 0.0, 15.0, 15.0), B_CMAP8);
|
|
if (mimeBitmap && mimeBitmap->IsValid()) {
|
|
status = fileType->GetIcon(mimeBitmap, small ? B_MINI_ICON : B_LARGE_ICON);
|
|
if (status >= B_OK) {
|
|
if (BBitmap* bitmap = _ConvertToRGB32(mimeBitmap)) {
|
|
status = _MakeBitmaps(bitmap);
|
|
delete bitmap;
|
|
} else
|
|
printf("IconButton::SetIcon() - B_RGB32 bitmap is not valid\n");
|
|
} else
|
|
printf("IconButton::SetIcon() - fileType->GetIcon() failed: %s\n", strerror(status));
|
|
} else
|
|
printf("IconButton::SetIcon() - B_CMAP8 bitmap is not valid\n");
|
|
delete mimeBitmap;
|
|
} else
|
|
printf("IconButton::SetIcon() - fileType is not valid: %s\n", strerror(status));
|
|
return status;
|
|
}
|
|
|
|
// SetIcon
|
|
status_t
|
|
IconButton::SetIcon(const unsigned char* bitsFromQuickRes,
|
|
uint32 width, uint32 height, color_space format, bool convertToBW)
|
|
{
|
|
status_t status = B_BAD_VALUE;
|
|
if (bitsFromQuickRes && width > 0 && height > 0) {
|
|
BBitmap* quickResBitmap = new(nothrow) BBitmap(BRect(0.0, 0.0, width - 1.0, height - 1.0), format);
|
|
status = quickResBitmap ? quickResBitmap->InitCheck() : B_ERROR;
|
|
if (status >= B_OK) {
|
|
// It doesn't look right to copy BitsLength() bytes, but bitmaps
|
|
// exported from QuickRes still contain their padding, so it is alright.
|
|
memcpy(quickResBitmap->Bits(), bitsFromQuickRes, quickResBitmap->BitsLength());
|
|
if (format != B_RGB32 && format != B_RGBA32 && format != B_RGB32_BIG && format != B_RGBA32_BIG) {
|
|
// colorspace needs conversion
|
|
BBitmap* bitmap = new(nothrow) BBitmap(quickResBitmap->Bounds(), B_RGB32, true);
|
|
if (bitmap && bitmap->IsValid()) {
|
|
BView* helper = new BView(bitmap->Bounds(), "helper",
|
|
B_FOLLOW_NONE, B_WILL_DRAW);
|
|
if (bitmap->Lock()) {
|
|
bitmap->AddChild(helper);
|
|
helper->SetHighColor(ui_color(B_PANEL_BACKGROUND_COLOR));
|
|
helper->FillRect(helper->Bounds());
|
|
helper->SetDrawingMode(B_OP_OVER);
|
|
helper->DrawBitmap(quickResBitmap, BPoint(0.0, 0.0));
|
|
helper->Sync();
|
|
bitmap->Unlock();
|
|
}
|
|
status = _MakeBitmaps(bitmap);
|
|
} else
|
|
printf("IconButton::SetIcon() - B_RGB32 bitmap is not valid\n");
|
|
delete bitmap;
|
|
} else {
|
|
// native colorspace (32 bits)
|
|
if (convertToBW) {
|
|
// convert to gray scale icon
|
|
uint8* bits = (uint8*)quickResBitmap->Bits();
|
|
uint32 bpr = quickResBitmap->BytesPerRow();
|
|
for (uint32 y = 0; y < height; y++) {
|
|
uint8* handle = bits;
|
|
uint8 gray;
|
|
for (uint32 x = 0; x < width; x++) {
|
|
gray = uint8((116 * handle[0] + 600 * handle[1] + 308 * handle[2]) / 1024);
|
|
handle[0] = gray;
|
|
handle[1] = gray;
|
|
handle[2] = gray;
|
|
handle += 4;
|
|
}
|
|
bits += bpr;
|
|
}
|
|
}
|
|
status = _MakeBitmaps(quickResBitmap);
|
|
}
|
|
} else
|
|
printf("IconButton::SetIcon() - error allocating bitmap: %s\n", strerror(status));
|
|
delete quickResBitmap;
|
|
}
|
|
return status;
|
|
}
|
|
|
|
// ClearIcon
|
|
void
|
|
IconButton::ClearIcon()
|
|
{
|
|
_DeleteBitmaps();
|
|
_Update();
|
|
}
|
|
|
|
// Bitmap
|
|
BBitmap*
|
|
IconButton::Bitmap() const
|
|
{
|
|
BBitmap* bitmap = NULL;
|
|
if (fNormalBitmap && fNormalBitmap->IsValid()) {
|
|
bitmap = new(nothrow) BBitmap(fNormalBitmap);
|
|
if (bitmap->IsValid()) {
|
|
// TODO: remove this functionality when we use real transparent bitmaps
|
|
uint8* bits = (uint8*)bitmap->Bits();
|
|
uint32 bpr = bitmap->BytesPerRow();
|
|
uint32 width = bitmap->Bounds().IntegerWidth() + 1;
|
|
uint32 height = bitmap->Bounds().IntegerHeight() + 1;
|
|
color_space format = bitmap->ColorSpace();
|
|
if (format == B_CMAP8) {
|
|
// replace gray with magic transparent index
|
|
} else if (format == B_RGB32) {
|
|
for (uint32 y = 0; y < height; y++) {
|
|
uint8* bitsHandle = bits;
|
|
for (uint32 x = 0; x < width; x++) {
|
|
if (bitsHandle[0] == 216
|
|
&& bitsHandle[1] == 216
|
|
&& bitsHandle[2] == 216) {
|
|
bitsHandle[3] = 0; // make this pixel completely transparent
|
|
}
|
|
bitsHandle += 4;
|
|
}
|
|
bits += bpr;
|
|
}
|
|
}
|
|
} else {
|
|
delete bitmap;
|
|
bitmap = NULL;
|
|
}
|
|
}
|
|
return bitmap;
|
|
}
|
|
|
|
// DrawBorder
|
|
bool
|
|
IconButton::DrawBorder() const
|
|
{
|
|
return (IsEnabled() && (_HasFlags(STATE_INSIDE) || _HasFlags(STATE_TRACKING))
|
|
|| _HasFlags(STATE_FORCE_PRESSED));
|
|
}
|
|
|
|
// DrawNormalBorder
|
|
void
|
|
IconButton::DrawNormalBorder(BRect r, rgb_color background,
|
|
rgb_color shadow, rgb_color darkShadow,
|
|
rgb_color lightShadow, rgb_color light)
|
|
{
|
|
_DrawFrame(r, shadow, darkShadow, light, lightShadow);
|
|
}
|
|
|
|
// DrawPressedBorder
|
|
void
|
|
IconButton::DrawPressedBorder(BRect r, rgb_color background,
|
|
rgb_color shadow, rgb_color darkShadow,
|
|
rgb_color lightShadow, rgb_color light)
|
|
{
|
|
_DrawFrame(r, shadow, light, darkShadow, background);
|
|
}
|
|
|
|
// IsValid
|
|
bool
|
|
IconButton::IsValid() const
|
|
{
|
|
return (fNormalBitmap && fDisabledBitmap && fClickedBitmap && fDisabledClickedBitmap
|
|
&& fNormalBitmap->IsValid()
|
|
&& fDisabledBitmap->IsValid()
|
|
&& fClickedBitmap->IsValid()
|
|
&& fDisabledClickedBitmap->IsValid());
|
|
}
|
|
|
|
// Value
|
|
int32
|
|
IconButton::Value() const
|
|
{
|
|
return _HasFlags(STATE_PRESSED) ? B_CONTROL_ON : B_CONTROL_OFF;
|
|
}
|
|
|
|
// SetValue
|
|
void
|
|
IconButton::SetValue(int32 value)
|
|
{
|
|
if (value)
|
|
_AddFlags(STATE_PRESSED);
|
|
else
|
|
_ClearFlags(STATE_PRESSED);
|
|
}
|
|
|
|
// IsEnabled
|
|
bool
|
|
IconButton::IsEnabled() const
|
|
{
|
|
return _HasFlags(STATE_ENABLED) ? B_CONTROL_ON : B_CONTROL_OFF;
|
|
}
|
|
|
|
// SetEnabled
|
|
void
|
|
IconButton::SetEnabled(bool enabled)
|
|
{
|
|
if (enabled)
|
|
_AddFlags(STATE_ENABLED);
|
|
else
|
|
_ClearFlags(STATE_ENABLED | STATE_TRACKING | STATE_INSIDE);
|
|
}
|
|
|
|
// _ConvertToRGB32
|
|
BBitmap*
|
|
IconButton::_ConvertToRGB32(const BBitmap* bitmap) const
|
|
{
|
|
BBitmap* convertedBitmap = new(nothrow) BBitmap(bitmap->Bounds(), B_BITMAP_ACCEPTS_VIEWS, B_RGBA32);
|
|
if (convertedBitmap && convertedBitmap->IsValid()) {
|
|
memset(convertedBitmap->Bits(), 0, convertedBitmap->BitsLength());
|
|
BView* helper = new BView(bitmap->Bounds(), "helper",
|
|
B_FOLLOW_NONE, B_WILL_DRAW);
|
|
if (convertedBitmap->Lock()) {
|
|
convertedBitmap->AddChild(helper);
|
|
helper->SetDrawingMode(B_OP_OVER);
|
|
helper->DrawBitmap(bitmap, BPoint(0.0, 0.0));
|
|
helper->Sync();
|
|
convertedBitmap->Unlock();
|
|
}
|
|
} else {
|
|
delete convertedBitmap;
|
|
convertedBitmap = NULL;
|
|
}
|
|
return convertedBitmap;
|
|
}
|
|
|
|
// _MakeBitmaps
|
|
status_t
|
|
IconButton::_MakeBitmaps(const BBitmap* bitmap)
|
|
{
|
|
status_t status = bitmap ? bitmap->InitCheck() : B_BAD_VALUE;
|
|
if (status >= B_OK) {
|
|
// make our own versions of the bitmap
|
|
BRect b(bitmap->Bounds());
|
|
_DeleteBitmaps();
|
|
color_space format = bitmap->ColorSpace();
|
|
fNormalBitmap = new(nothrow) BBitmap(b, format);
|
|
fDisabledBitmap = new(nothrow) BBitmap(b, format);
|
|
fClickedBitmap = new(nothrow) BBitmap(b, format);
|
|
fDisabledClickedBitmap = new(nothrow) BBitmap(b, format);
|
|
if (IsValid()) {
|
|
// copy bitmaps from file bitmap
|
|
uint8* nBits = (uint8*)fNormalBitmap->Bits();
|
|
uint8* dBits = (uint8*)fDisabledBitmap->Bits();
|
|
uint8* cBits = (uint8*)fClickedBitmap->Bits();
|
|
uint8* dcBits = (uint8*)fDisabledClickedBitmap->Bits();
|
|
uint8* fBits = (uint8*)bitmap->Bits();
|
|
int32 nbpr = fNormalBitmap->BytesPerRow();
|
|
int32 fbpr = bitmap->BytesPerRow();
|
|
int32 pixels = b.IntegerWidth() + 1;
|
|
int32 lines = b.IntegerHeight() + 1;
|
|
// nontransparent version:
|
|
if (format == B_RGB32 || format == B_RGB32_BIG) {
|
|
// iterate over color components
|
|
for (int32 y = 0; y < lines; y++) {
|
|
for (int32 x = 0; x < pixels; x++) {
|
|
int32 nOffset = 4 * x;
|
|
int32 fOffset = 4 * x;
|
|
nBits[nOffset + 0] = fBits[fOffset + 0];
|
|
nBits[nOffset + 1] = fBits[fOffset + 1];
|
|
nBits[nOffset + 2] = fBits[fOffset + 2];
|
|
nBits[nOffset + 3] = 255;
|
|
// clicked bits are darker (lame method...)
|
|
cBits[nOffset + 0] = (uint8)((float)nBits[nOffset + 0] * 0.8);
|
|
cBits[nOffset + 1] = (uint8)((float)nBits[nOffset + 1] * 0.8);
|
|
cBits[nOffset + 2] = (uint8)((float)nBits[nOffset + 2] * 0.8);
|
|
cBits[nOffset + 3] = 255;
|
|
// disabled bits have less contrast (lame method...)
|
|
uint8 grey = 216;
|
|
float dist = (nBits[nOffset + 0] - grey) * 0.4;
|
|
dBits[nOffset + 0] = (uint8)(grey + dist);
|
|
dist = (nBits[nOffset + 1] - grey) * 0.4;
|
|
dBits[nOffset + 1] = (uint8)(grey + dist);
|
|
dist = (nBits[nOffset + 2] - grey) * 0.4;
|
|
dBits[nOffset + 2] = (uint8)(grey + dist);
|
|
dBits[nOffset + 3] = 255;
|
|
// disabled bits have less contrast (lame method...)
|
|
grey = 188;
|
|
dist = (nBits[nOffset + 0] - grey) * 0.4;
|
|
dcBits[nOffset + 0] = (uint8)(grey + dist);
|
|
dist = (nBits[nOffset + 1] - grey) * 0.4;
|
|
dcBits[nOffset + 1] = (uint8)(grey + dist);
|
|
dist = (nBits[nOffset + 2] - grey) * 0.4;
|
|
dcBits[nOffset + 2] = (uint8)(grey + dist);
|
|
dcBits[nOffset + 3] = 255;
|
|
}
|
|
nBits += nbpr;
|
|
dBits += nbpr;
|
|
cBits += nbpr;
|
|
dcBits += nbpr;
|
|
fBits += fbpr;
|
|
}
|
|
// transparent version:
|
|
} else if (format == B_RGBA32 || format == B_RGBA32_BIG) {
|
|
// iterate over color components
|
|
for (int32 y = 0; y < lines; y++) {
|
|
for (int32 x = 0; x < pixels; x++) {
|
|
int32 nOffset = 4 * x;
|
|
int32 fOffset = 4 * x;
|
|
nBits[nOffset + 0] = fBits[fOffset + 0];
|
|
nBits[nOffset + 1] = fBits[fOffset + 1];
|
|
nBits[nOffset + 2] = fBits[fOffset + 2];
|
|
nBits[nOffset + 3] = fBits[fOffset + 3];
|
|
// clicked bits are darker (lame method...)
|
|
cBits[nOffset + 0] = (uint8)(nBits[nOffset + 0] * 0.8);
|
|
cBits[nOffset + 1] = (uint8)(nBits[nOffset + 1] * 0.8);
|
|
cBits[nOffset + 2] = (uint8)(nBits[nOffset + 2] * 0.8);
|
|
cBits[nOffset + 3] = fBits[fOffset + 3];
|
|
// disabled bits have less opacity
|
|
dBits[nOffset + 0] = fBits[fOffset + 0];
|
|
dBits[nOffset + 1] = fBits[fOffset + 1];
|
|
dBits[nOffset + 2] = fBits[fOffset + 2];
|
|
dBits[nOffset + 3] = (uint8)(fBits[fOffset + 3] * 0.5);
|
|
// disabled bits have less contrast (lame method...)
|
|
dcBits[nOffset + 0] = (uint8)(nBits[nOffset + 0] * 0.8);
|
|
dcBits[nOffset + 1] = (uint8)(nBits[nOffset + 1] * 0.8);
|
|
dcBits[nOffset + 2] = (uint8)(nBits[nOffset + 2] * 0.8);
|
|
dcBits[nOffset + 3] = (uint8)(fBits[fOffset + 3] * 0.5);
|
|
}
|
|
nBits += nbpr;
|
|
dBits += nbpr;
|
|
cBits += nbpr;
|
|
dcBits += nbpr;
|
|
fBits += fbpr;
|
|
}
|
|
// unsupported format
|
|
} else {
|
|
printf("IconButton::_MakeBitmaps() - bitmap has unsupported colorspace\n");
|
|
status = B_MISMATCHED_VALUES;
|
|
_DeleteBitmaps();
|
|
}
|
|
} else {
|
|
printf("IconButton::_MakeBitmaps() - error allocating local bitmaps\n");
|
|
status = B_NO_MEMORY;
|
|
_DeleteBitmaps();
|
|
}
|
|
} else
|
|
printf("IconButton::_MakeBitmaps() - bitmap is not valid\n");
|
|
return status;
|
|
}
|
|
|
|
// _DeleteBitmaps
|
|
void
|
|
IconButton::_DeleteBitmaps()
|
|
{
|
|
delete fNormalBitmap;
|
|
fNormalBitmap = NULL;
|
|
delete fDisabledBitmap;
|
|
fDisabledBitmap = NULL;
|
|
delete fClickedBitmap;
|
|
fClickedBitmap = NULL;
|
|
delete fDisabledClickedBitmap;
|
|
fDisabledClickedBitmap = NULL;
|
|
}
|
|
|
|
// _Update
|
|
void
|
|
IconButton::_Update()
|
|
{
|
|
if (LockLooper()) {
|
|
Invalidate();
|
|
UnlockLooper();
|
|
}
|
|
}
|
|
|
|
// _AddFlags
|
|
void
|
|
IconButton::_AddFlags(uint32 flags)
|
|
{
|
|
if (!(fButtonState & flags)) {
|
|
fButtonState |= flags;
|
|
_Update();
|
|
}
|
|
}
|
|
|
|
// _ClearFlags
|
|
void
|
|
IconButton::_ClearFlags(uint32 flags)
|
|
{
|
|
if (fButtonState & flags) {
|
|
fButtonState &= ~flags;
|
|
_Update();
|
|
}
|
|
}
|
|
|
|
// _HasFlags
|
|
bool
|
|
IconButton::_HasFlags(uint32 flags) const
|
|
{
|
|
return (fButtonState & flags);
|
|
}
|
|
|
|
// _DrawFrame
|
|
void
|
|
IconButton::_DrawFrame(BRect r, rgb_color col1, rgb_color col2,
|
|
rgb_color col3, rgb_color col4)
|
|
{
|
|
BeginLineArray(8);
|
|
AddLine(BPoint(r.left, r.bottom), BPoint(r.left, r.top), col1);
|
|
AddLine(BPoint(r.left + 1.0, r.top), BPoint(r.right, r.top), col1);
|
|
AddLine(BPoint(r.right, r.top + 1.0), BPoint(r.right, r.bottom), col2);
|
|
AddLine(BPoint(r.right - 1.0, r.bottom), BPoint(r.left + 1.0, r.bottom), col2);
|
|
r.InsetBy(1.0, 1.0);
|
|
AddLine(BPoint(r.left, r.bottom), BPoint(r.left, r.top), col3);
|
|
AddLine(BPoint(r.left + 1.0, r.top), BPoint(r.right, r.top), col3);
|
|
AddLine(BPoint(r.right, r.top + 1.0), BPoint(r.right, r.bottom), col4);
|
|
AddLine(BPoint(r.right - 1.0, r.bottom), BPoint(r.left + 1.0, r.bottom), col4);
|
|
EndLineArray();
|
|
}
|