#include "DraggableContainerIcon.h"
#include <algorithm>
#include <ControlLook.h>
#include <IconUtils.h>
#include <MenuItem.h>
#include <Region.h>
#include "ContainerWindow.h"
#include "IconCache.h"
#include "Model.h"
const float kDragSlop = 3.0f;
DraggableContainerIcon::DraggableContainerIcon(BSize iconSize)
:
BView("DraggableContainerIcon", B_WILL_DRAW),
fIconSize(iconSize),
fDragButton(0),
fDragStarted(false)
{
SetExplicitMinSize(BSize(iconSize.Width() + 5, iconSize.Height()));
SetExplicitMaxSize(BSize(iconSize.Width() + 5, B_SIZE_UNSET));
}
void
DraggableContainerIcon::MouseDown(BPoint where)
{
BContainerWindow* window = dynamic_cast<BContainerWindow*>(Window());
if (window == NULL)
return;
if (!window->ShouldHaveDraggableFolderIcon())
return;
if (window->CurrentMessage() == NULL)
return;
uint32 buttons = Window()->CurrentMessage()->GetInt32("buttons", 0);
if (IconCache::sIconCache->IconHitTest(where, window->TargetModel(), kNormalIcon, fIconSize)) {
fDragButton = buttons & (B_PRIMARY_MOUSE_BUTTON | B_SECONDARY_MOUSE_BUTTON);
fDragStarted = false;
fClickPoint = where;
} else {
fDragButton = 0;
}
if (!fDragButton)
Window()->Activate(true);
}
void
DraggableContainerIcon::MouseUp(BPoint)
{
if (!fDragStarted)
Window()->Activate(true);
fDragButton = 0;
fDragStarted = false;
}
void
DraggableContainerIcon::MouseMoved(BPoint where, uint32, const BMessage*)
{
if (fDragButton == 0 || fDragStarted
|| (abs((int32)(where.x - fClickPoint.x)) <= kDragSlop
&& abs((int32)(where.y - fClickPoint.y)) <= kDragSlop))
return;
BContainerWindow* window = static_cast<BContainerWindow*>(Window());
Model* model = window->TargetModel();
BFont font;
GetFont(&font);
font_height fontHeight;
font.GetHeight(&fontHeight);
float height = ceilf(fontHeight.ascent + fontHeight.descent
+ fontHeight.leading + 2 + Bounds().Height() + 8);
BRect rect(0, 0, std::max(Bounds().Width(),
font.StringWidth(model->Name()) + 4), height);
BBitmap* dragBitmap = new BBitmap(rect, B_RGBA32, true);
dragBitmap->Lock();
BView* view = new BView(dragBitmap->Bounds(), "", B_FOLLOW_NONE, 0);
dragBitmap->AddChild(view);
view->SetOrigin(B_ORIGIN);
BRect clipRect(view->Bounds());
BRegion newClip;
newClip.Set(clipRect);
view->ConstrainClippingRegion(&newClip);
view->SetHighColor(0, 0, 0, 0);
view->FillRect(view->Bounds());
view->SetDrawingMode(B_OP_ALPHA);
rgb_color textColor = ui_color(B_PANEL_TEXT_COLOR);
textColor.alpha = 128;
view->SetHighColor(textColor);
view->SetBlendingMode(B_CONSTANT_ALPHA, B_ALPHA_COMPOSITE);
float hIconOffset = (rect.Width() - Bounds().Width()) / 2;
IconCache::sIconCache->Draw(model, view, BPoint(hIconOffset, 0), kNormalIcon, fIconSize, true);
BString nameString = model->Name();
if (view->StringWidth(model->Name()) > rect.Width())
view->TruncateString(&nameString, B_TRUNCATE_MIDDLE, rect.Width() - 5);
float leftText = roundf((view->StringWidth(nameString.String()) - Bounds().Width()) / 2);
float x = hIconOffset - leftText + 2;
float y = Bounds().Height() + fontHeight.ascent + 2;
view->MovePenTo(BPoint(x, y));
view->DrawString(nameString.String());
view->Sync();
dragBitmap->Unlock();
BMessage message(B_SIMPLE_DATA);
message.AddRef("refs", model->EntryRef());
message.AddPoint("click_pt", fClickPoint);
BPoint tmpLoc;
uint32 button;
GetMouse(&tmpLoc, &button);
if (button)
message.AddInt32("buttons", (int32)button);
if ((button & B_PRIMARY_MOUSE_BUTTON) != 0) {
message.AddInt32("be:actions", (modifiers() & B_OPTION_KEY) != 0
? B_COPY_TARGET : B_MOVE_TARGET);
}
fDragStarted = true;
fDragButton = 0;
DragMessage(&message, dragBitmap, B_OP_ALPHA,
BPoint(fClickPoint.x + hIconOffset, fClickPoint.y), this);
}
void
DraggableContainerIcon::Draw(BRect updateRect)
{
BContainerWindow* window = dynamic_cast<BContainerWindow*>(Window());
ThrowOnAssert(window != NULL);
BRect rect(Bounds());
rgb_color base = ui_color(B_MENU_BACKGROUND_COLOR);
be_control_look->DrawBorder(this, rect, updateRect, base, B_PLAIN_BORDER,
0, BControlLook::B_BOTTOM_BORDER);
be_control_look->DrawMenuBarBackground(this, rect, updateRect, base, 0,
BControlLook::B_ALL_BORDERS & ~BControlLook::B_LEFT_BORDER);
SetDrawingMode(B_OP_ALPHA);
SetBlendingMode(B_PIXEL_ALPHA, B_ALPHA_OVERLAY);
float iconOffsetX = (Bounds().Width() - fIconSize.Width()) / 2;
float iconOffsetY = (Bounds().Height() - fIconSize.Height()) / 2;
IconCache::sIconCache->Draw(window->TargetModel(), this,
BPoint(iconOffsetX, iconOffsetY), kNormalIcon, fIconSize, true);
}