#include "IconMenuItem.h"
#include <ControlLook.h>
#include <Debug.h>
#include <Menu.h>
#include <MenuField.h>
#include <MenuPrivate.h>
#include <NodeInfo.h>
#include "IconCache.h"
static void
DimmedIconBlitter(BView* view, BPoint where, BBitmap* bitmap, void*)
{
if (bitmap->ColorSpace() == B_RGBA32) {
rgb_color oldHighColor = view->HighColor();
view->SetHighColor(0, 0, 0, 128);
view->SetDrawingMode(B_OP_ALPHA);
view->SetBlendingMode(B_CONSTANT_ALPHA, B_ALPHA_OVERLAY);
view->DrawBitmap(bitmap, where);
view->SetHighColor(oldHighColor);
} else {
view->SetDrawingMode(B_OP_BLEND);
view->DrawBitmap(bitmap, where);
}
view->SetDrawingMode(B_OP_OVER);
}
ModelMenuItem::ModelMenuItem(const Model* model, const char* title,
BMessage* message, char shortcut, uint32 modifiers,
bool drawText, bool extraPad)
:
BMenuItem(title, message, shortcut, modifiers),
fModel(*model),
fHeightDelta(0),
fDrawText(drawText),
fExtraPad(extraPad)
{
ThrowOnInitCheckError(&fModel);
if (model->IsRoot())
SetLabel(model->Name());
SetTimeout(kSynchMenuInvokeTimeout);
}
ModelMenuItem::ModelMenuItem(const Model* model, BMenu* menu, bool drawText,
bool extraPad)
:
BMenuItem(menu),
fModel(*model),
fHeightDelta(0),
fDrawText(drawText),
fExtraPad(extraPad)
{
ThrowOnInitCheckError(&fModel);
SetTimeout(kSynchMenuInvokeTimeout);
}
ModelMenuItem::~ModelMenuItem()
{
}
status_t
ModelMenuItem::SetEntry(const BEntry* entry)
{
return fModel.SetTo(entry);
}
void
ModelMenuItem::DrawContent()
{
if (fDrawText) {
BPoint drawPoint(ContentLocation());
drawPoint.x += ListIconSize() + ListIconSize() / 4 + _ExtraLeftPadding();
if (fHeightDelta > 0)
drawPoint.y += ceilf(fHeightDelta / 2);
Menu()->MovePenTo(drawPoint);
_inherited::DrawContent();
}
DrawIcon();
}
void
ModelMenuItem::Highlight(bool hilited)
{
_inherited::Highlight(hilited);
DrawIcon();
}
void
ModelMenuItem::DrawIcon()
{
Menu()->PushState();
BPoint where(ContentLocation());
float deltaHeight = fHeightDelta < 0 ? -fHeightDelta : 0;
where.y += ceilf(deltaHeight / 2);
where.x += _ExtraLeftPadding();
Menu()->SetDrawingMode(B_OP_OVER);
Menu()->SetLowColor(B_TRANSPARENT_32_BIT);
if (IsEnabled()) {
IconCache::sIconCache->Draw(fModel.ResolveIfLink(), Menu(), where,
kNormalIcon, BSize(ListIconSize() - 1, ListIconSize() - 1));
} else {
IconCache::sIconCache->SyncDraw(fModel.ResolveIfLink(), Menu(), where,
kNormalIcon, BSize(ListIconSize() - 1, ListIconSize() - 1), DimmedIconBlitter);
}
Menu()->PopState();
}
float
ModelMenuItem::_ExtraLeftPadding()
{
if (!fExtraPad)
return 0;
float leftDelta;
_GetHorizontalItemMarginDelta(&leftDelta, NULL);
return leftDelta;
}
float
ModelMenuItem::_ExtraPadding()
{
if (!fExtraPad)
return 0;
float leftDelta, rightDelta;
_GetHorizontalItemMarginDelta(&leftDelta, &rightDelta);
return leftDelta + rightDelta;
}
void
ModelMenuItem::_GetHorizontalItemMarginDelta(float* _leftDelta, float* _rightDelta)
{
float menuLeft, menuRight, menuBarLeft, menuBarRight;
BMenu tempMenu("temp");
BPrivate::MenuPrivate menuPrivate(&tempMenu);
menuPrivate.GetItemMargins(&menuLeft, NULL, &menuRight, NULL);
BPrivate::MenuPrivate menuBarPrivate(Menu());
menuBarPrivate.GetItemMargins(&menuBarLeft, NULL, &menuBarRight, NULL);
if (_leftDelta != NULL)
*_leftDelta = menuLeft - menuBarLeft;
if (_rightDelta != NULL)
*_rightDelta = menuRight - menuBarRight;
}
void
ModelMenuItem::GetContentSize(float* width, float* height)
{
_inherited::GetContentSize(width, height);
const float iconSize = ListIconSize();
fHeightDelta = iconSize - *height;
if (*height < iconSize)
*height = iconSize;
*width += iconSize + iconSize / 4 + _ExtraPadding();
}
status_t
ModelMenuItem::Invoke(BMessage* message)
{
if (Menu() == NULL)
return B_ERROR;
if (!IsEnabled())
return B_ERROR;
if (message == NULL)
message = Message();
if (message == NULL)
return B_BAD_VALUE;
BMessage clone(*message);
clone.AddInt32("index", Menu()->IndexOf(this));
clone.AddInt64("when", system_time());
clone.AddPointer("source", this);
if ((modifiers() & B_OPTION_KEY) == 0) {
clone.RemoveData("nodeRefsToClose");
}
return BInvoker::Invoke(&clone);
}
SpecialModelMenuItem::SpecialModelMenuItem(const Model* model, BMenu* menu)
: ModelMenuItem(model, menu)
{
}
void
SpecialModelMenuItem::DrawContent()
{
Menu()->PushState();
BFont font;
Menu()->GetFont(&font);
font.SetFace(B_ITALIC_FACE);
Menu()->SetFont(&font);
_inherited::DrawContent();
Menu()->PopState();
}
IconMenuItem::IconMenuItem(const char* label, BMessage* message, BBitmap* icon,
icon_size which)
:
PositionPassingMenuItem(label, message),
fDeviceIcon(NULL),
fHeightDelta(0),
fWhich(which)
{
SetIcon(icon);
SetTimeout(kSynchMenuInvokeTimeout);
}
IconMenuItem::IconMenuItem(const char* label, BMessage* message,
const BNodeInfo* nodeInfo, icon_size which)
:
PositionPassingMenuItem(label, message),
fDeviceIcon(NULL),
fHeightDelta(0),
fWhich(which)
{
if (nodeInfo != NULL) {
fDeviceIcon = new BBitmap(BRect(BPoint(0, 0),
be_control_look->ComposeIconSize(which)), kDefaultIconDepth);
if (nodeInfo->GetTrackerIcon(fDeviceIcon, (icon_size)-1) != B_OK) {
delete fDeviceIcon;
fDeviceIcon = NULL;
}
}
SetTimeout(kSynchMenuInvokeTimeout);
}
IconMenuItem::IconMenuItem(const char* label, BMessage* message,
const char* iconType, icon_size which)
:
PositionPassingMenuItem(label, message),
fDeviceIcon(NULL),
fHeightDelta(0),
fWhich(which)
{
BMimeType mime(iconType);
fDeviceIcon = new BBitmap(BRect(BPoint(0, 0), be_control_look->ComposeIconSize(which)),
kDefaultIconDepth);
if (mime.GetIcon(fDeviceIcon, which) != B_OK) {
BMimeType super;
mime.GetSupertype(&super);
if (super.GetIcon(fDeviceIcon, which) != B_OK) {
delete fDeviceIcon;
fDeviceIcon = NULL;
}
}
SetTimeout(kSynchMenuInvokeTimeout);
}
IconMenuItem::IconMenuItem(BMenu* submenu, BMessage* message,
const char* iconType, icon_size which)
:
PositionPassingMenuItem(submenu, message),
fDeviceIcon(NULL),
fHeightDelta(0),
fWhich(which)
{
BMimeType mime(iconType);
fDeviceIcon = new BBitmap(BRect(BPoint(0, 0), be_control_look->ComposeIconSize(which)),
kDefaultIconDepth);
if (mime.GetIcon(fDeviceIcon, which) != B_OK) {
BMimeType super;
mime.GetSupertype(&super);
if (super.GetIcon(fDeviceIcon, which) != B_OK) {
delete fDeviceIcon;
fDeviceIcon = NULL;
}
}
SetTimeout(kSynchMenuInvokeTimeout);
}
IconMenuItem::IconMenuItem(BMessage* data)
:
PositionPassingMenuItem(data),
fDeviceIcon(NULL),
fHeightDelta(0),
fWhich(B_MINI_ICON)
{
if (data != NULL) {
fWhich = (icon_size)data->GetInt32("_which", B_MINI_ICON);
fDeviceIcon = new BBitmap(BRect(BPoint(0, 0), be_control_look->ComposeIconSize(fWhich)),
kDefaultIconDepth);
if (data->HasData("_deviceIconBits", B_RAW_TYPE)) {
ssize_t numBytes;
const void* bits;
if (data->FindData("_deviceIconBits", B_RAW_TYPE, &bits, &numBytes)
== B_OK) {
fDeviceIcon->SetBits(bits, numBytes, (int32)0,
kDefaultIconDepth);
}
}
}
SetTimeout(kSynchMenuInvokeTimeout);
}
BArchivable*
IconMenuItem::Instantiate(BMessage* data)
{
return new IconMenuItem(data);
return NULL;
}
status_t
IconMenuItem::Archive(BMessage* data, bool deep) const
{
status_t result = PositionPassingMenuItem::Archive(data, deep);
if (result == B_OK)
result = data->AddInt32("_which", (int32)fWhich);
if (result == B_OK && fDeviceIcon != NULL) {
result = data->AddData("_deviceIconBits", B_RAW_TYPE,
fDeviceIcon->Bits(), fDeviceIcon->BitsLength());
}
return result;
}
IconMenuItem::~IconMenuItem()
{
delete fDeviceIcon;
}
void
IconMenuItem::GetContentSize(float* width, float* height)
{
_inherited::GetContentSize(width, height);
int32 iconHeight = fWhich;
if (fDeviceIcon != NULL)
iconHeight = fDeviceIcon->Bounds().IntegerHeight() + 1;
fHeightDelta = iconHeight - *height;
if (*height < iconHeight)
*height = iconHeight;
if (fDeviceIcon != NULL)
*width += fDeviceIcon->Bounds().Width() + be_control_look->DefaultLabelSpacing();
}
void
IconMenuItem::DrawContent()
{
BPoint drawPoint(ContentLocation());
if (fDeviceIcon != NULL)
drawPoint.x += fDeviceIcon->Bounds().Width() + be_control_look->DefaultLabelSpacing();
if (fHeightDelta > 0)
drawPoint.y += ceilf(fHeightDelta / 2);
Menu()->MovePenTo(drawPoint);
_inherited::DrawContent();
Menu()->PushState();
BPoint where(ContentLocation());
float deltaHeight = fHeightDelta < 0 ? -fHeightDelta : 0;
where.y += ceilf(deltaHeight / 2);
if (fDeviceIcon != NULL) {
if (IsEnabled())
Menu()->SetDrawingMode(B_OP_ALPHA);
else {
Menu()->SetDrawingMode(B_OP_ALPHA);
Menu()->SetHighColor(0, 0, 0, 64);
Menu()->SetBlendingMode(B_CONSTANT_ALPHA, B_ALPHA_OVERLAY);
}
Menu()->DrawBitmapAsync(fDeviceIcon, where);
}
Menu()->PopState();
}
void
IconMenuItem::SetMarked(bool mark)
{
_inherited::SetMarked(mark);
if (!mark)
return;
BMenu* menu = Menu();
if (menu == NULL)
return;
BMenu* _menu = menu;
while ((_menu = _menu->Supermenu()) != NULL)
menu = _menu;
if (menu == NULL || menu->Parent() == NULL)
return;
if (dynamic_cast<BMenuField*>(menu->Parent()) == NULL)
return;
BMenuItem* topLevelItem = menu->ItemAt((int32)0);
if (topLevelItem == NULL)
return;
IconMenuItem* topLevelMenuItem = dynamic_cast<IconMenuItem*>(topLevelItem);
if (topLevelMenuItem == NULL)
return;
topLevelMenuItem->SetIcon(fDeviceIcon);
menu->Invalidate();
}
void
IconMenuItem::SetIcon(BBitmap* icon)
{
if (icon != NULL) {
if (fDeviceIcon != NULL)
delete fDeviceIcon;
fDeviceIcon = new BBitmap(BRect(BPoint(0, 0),
be_control_look->ComposeIconSize(fWhich)), icon->ColorSpace());
fDeviceIcon->ImportBits(icon);
} else {
delete fDeviceIcon;
fDeviceIcon = NULL;
}
}