#include <Bitmap.h>
#include <ControlLook.h>
#include <Node.h>
#include <TranslationKit.h>
#include <View.h>
#include <Window.h>
#include <fs_attr.h>
#include "BackgroundImage.h"
#include "Background.h"
#include "Commands.h"
#include "PoseView.h"
namespace BPrivate {
const char* kBackgroundImageInfo = B_BACKGROUND_INFO;
const char* kBackgroundImageInfoOffset = B_BACKGROUND_ORIGIN;
const char* kBackgroundImageInfoTextOutline = B_BACKGROUND_TEXT_OUTLINE;
const char* kBackgroundImageInfoMode = B_BACKGROUND_MODE;
const char* kBackgroundImageInfoWorkspaces = B_BACKGROUND_WORKSPACES;
const char* kBackgroundImageInfoPath = B_BACKGROUND_IMAGE;
}
BackgroundImage*
BackgroundImage::GetBackgroundImage(const BNode* node, bool isDesktop)
{
attr_info info;
if (node->GetAttrInfo(kBackgroundImageInfo, &info) != B_OK)
return NULL;
BMessage container;
char* buffer = new char[info.size];
status_t error = node->ReadAttr(kBackgroundImageInfo, info.type, 0,
buffer, (size_t)info.size);
if (error == info.size)
error = container.Unflatten(buffer);
delete[] buffer;
if (error != B_OK)
return NULL;
BackgroundImage* backgroundImage = NULL;
for (int32 index = 0; ; index++) {
const char* path;
uint32 workspaces = B_ALL_WORKSPACES;
Mode mode = kTiled;
bool textWidgetLabelOutline = false;
BPoint offset;
BBitmap* bitmap = NULL;
if (container.FindString(kBackgroundImageInfoPath, index, &path)
== B_OK) {
bitmap = BTranslationUtils::GetBitmap(path);
if (!bitmap)
PRINT(("failed to load background bitmap from path\n"));
} else
break;
if (isDesktop)
be_control_look->SetBackgroundInfo(container);
container.FindInt32(kBackgroundImageInfoWorkspaces, index,
(int32*)&workspaces);
container.FindInt32(kBackgroundImageInfoMode, index, (int32*)&mode);
container.FindBool(kBackgroundImageInfoTextOutline, index,
&textWidgetLabelOutline);
container.FindPoint(kBackgroundImageInfoOffset, index, &offset);
BackgroundImage::BackgroundImageInfo* imageInfo = new
BackgroundImage::BackgroundImageInfo(workspaces, bitmap, mode,
offset, textWidgetLabelOutline);
if (backgroundImage == NULL)
backgroundImage = new BackgroundImage(node, isDesktop);
backgroundImage->Add(imageInfo);
}
return backgroundImage;
}
BackgroundImage::BackgroundImageInfo::BackgroundImageInfo(uint32 workspaces,
BBitmap* bitmap, Mode mode, BPoint offset, bool textWidgetOutline)
:
fWorkspace(workspaces),
fBitmap(bitmap),
fMode(mode),
fOffset(offset),
fTextWidgetOutline(textWidgetOutline)
{
}
BackgroundImage::BackgroundImageInfo::~BackgroundImageInfo()
{
delete fBitmap;
}
BackgroundImage::BackgroundImage(const BNode* node, bool desktop)
:
fIsDesktop(desktop),
fDefinedByNode(*node),
fView(NULL),
fShowingBitmap(NULL),
fBitmapForWorkspaceList(1)
{
}
BackgroundImage::~BackgroundImage()
{
}
void
BackgroundImage::Add(BackgroundImageInfo* info)
{
fBitmapForWorkspaceList.AddItem(info);
}
void
BackgroundImage::Show(BView* view, int32 workspace)
{
fView = view;
BackgroundImageInfo* info = ImageInfoForWorkspace(workspace);
if (info) {
BPoseView* poseView = dynamic_cast<BPoseView*>(fView);
if (poseView != NULL)
poseView->SetWidgetTextOutline(info->fTextWidgetOutline);
Show(info, fView);
}
}
void
BackgroundImage::Show(BackgroundImageInfo* info, BView* view)
{
BPoseView* poseView = dynamic_cast<BPoseView*>(view);
if (poseView != NULL)
poseView->SetWidgetTextOutline(info->fTextWidgetOutline);
if (info->fBitmap == NULL) {
view->ClearViewBitmap();
view->Invalidate();
fShowingBitmap = info;
return;
}
BRect viewBounds(view->Bounds());
BRect bitmapBounds(info->fBitmap->Bounds());
BRect destinationBitmapBounds(bitmapBounds);
uint32 options = 0;
uint32 followFlags = B_FOLLOW_TOP | B_FOLLOW_LEFT;
switch (info->fMode) {
case kCentered:
if (fIsDesktop) {
destinationBitmapBounds.OffsetBy(
(viewBounds.Width() - bitmapBounds.Width()) / 2,
(viewBounds.Height() - bitmapBounds.Height()) / 2);
break;
}
case kScaledToFit:
if (fIsDesktop) {
if (BRectRatio(destinationBitmapBounds)
>= BRectRatio(viewBounds)) {
float overlap = BRectHorizontalOverlap(viewBounds,
destinationBitmapBounds);
destinationBitmapBounds.Set(-overlap, 0,
viewBounds.Width() + overlap, viewBounds.Height());
} else {
float overlap = BRectVerticalOverlap(viewBounds,
destinationBitmapBounds);
destinationBitmapBounds.Set(0, -overlap,
viewBounds.Width(), viewBounds.Height() + overlap);
}
followFlags = B_FOLLOW_ALL;
options |= B_FILTER_BITMAP_BILINEAR;
break;
}
case kAtOffset:
if (!fIsDesktop && poseView != NULL)
destinationBitmapBounds.OffsetTo(poseView->Extent().LeftTop() + info->fOffset);
else
destinationBitmapBounds.OffsetTo(info->fOffset);
break;
case kTiled:
if (fIsDesktop) {
destinationBitmapBounds.OffsetBy(
(viewBounds.Width() - bitmapBounds.Width()) / 2,
(viewBounds.Height() - bitmapBounds.Height()) / 2);
} else if (poseView != NULL) {
destinationBitmapBounds.OffsetTo(poseView->Extent().LeftTop());
}
options |= B_TILE_BITMAP;
break;
}
view->SetViewBitmap(info->fBitmap, bitmapBounds, destinationBitmapBounds,
followFlags, options);
view->Invalidate();
fShowingBitmap = info;
}
float
BackgroundImage::BRectRatio(BRect rect)
{
return rect.Width() / rect.Height();
}
float
BackgroundImage::BRectHorizontalOverlap(BRect hostRect, BRect resizedRect)
{
return ((hostRect.Height() / resizedRect.Height() * resizedRect.Width())
- hostRect.Width()) / 2;
}
float
BackgroundImage::BRectVerticalOverlap(BRect hostRect, BRect resizedRect)
{
return ((hostRect.Width() / resizedRect.Width() * resizedRect.Height())
- hostRect.Height()) / 2;
}
void
BackgroundImage::Remove()
{
if (fShowingBitmap != NULL) {
fView->ClearViewBitmap();
fView->Invalidate();
BPoseView* poseView = dynamic_cast<BPoseView*>(fView);
if (poseView != NULL)
poseView->SetWidgetTextOutline(true);
}
fShowingBitmap = NULL;
}
BackgroundImage::BackgroundImageInfo*
BackgroundImage::ImageInfoForWorkspace(int32 workspace) const
{
uint32 workspaceMask = 1;
for ( ; workspace; workspace--)
workspaceMask *= 2;
int32 count = fBitmapForWorkspaceList.CountItems();
BackgroundImageInfo* result = NULL;
for (int32 index = 0; index < count; index++) {
BackgroundImageInfo* info = fBitmapForWorkspaceList.ItemAt(index);
if (info->fWorkspace == workspaceMask)
return info;
if (info->fWorkspace & workspaceMask)
result = info;
}
return result;
}
void
BackgroundImage::WorkspaceActivated(BView* view, int32 workspace, bool state)
{
if (!fIsDesktop) {
return;
}
if (!state) {
return;
}
BackgroundImageInfo* info = ImageInfoForWorkspace(workspace);
if (info != fShowingBitmap) {
if (info != NULL)
Show(info, view);
else {
BPoseView* poseView = dynamic_cast<BPoseView*>(view);
if (poseView != NULL)
poseView->SetWidgetTextOutline(true);
view->ClearViewBitmap();
view->Invalidate();
}
fShowingBitmap = info;
}
}
void
BackgroundImage::ScreenChanged(BRect, color_space)
{
if (!fIsDesktop || fShowingBitmap == NULL || fShowingBitmap->fBitmap == NULL)
return;
if (fShowingBitmap->fMode == kCentered) {
BRect viewBounds(fView->Bounds());
BRect bitmapBounds(fShowingBitmap->fBitmap->Bounds());
BRect destinationBitmapBounds(bitmapBounds);
destinationBitmapBounds.OffsetBy(
(viewBounds.Width() - bitmapBounds.Width()) / 2,
(viewBounds.Height() - bitmapBounds.Height()) / 2);
fView->SetViewBitmap(fShowingBitmap->fBitmap, bitmapBounds,
destinationBitmapBounds, B_FOLLOW_NONE, 0);
fView->Invalidate();
}
}
BackgroundImage*
BackgroundImage::Refresh(BackgroundImage* oldBackgroundImage,
const BNode* fromNode, bool desktop, BPoseView* poseView)
{
if (oldBackgroundImage != NULL) {
oldBackgroundImage->Remove();
delete oldBackgroundImage;
}
BackgroundImage* backgroundImage = GetBackgroundImage(fromNode, desktop);
if (backgroundImage != NULL && poseView != NULL && poseView->ViewMode() != kListMode)
backgroundImage->Show(poseView, current_workspace());
return backgroundImage;
}