haiku/src/kits/shared/DragTrackingFilter.cpp

89 lines
2.3 KiB
C++

/*
* Copyright 2009, Alexandre Deckner, alex@zappotek.com
* Distributed under the terms of the MIT License.
*/
/*!
\class DragTrackingFilter
\brief A simple mouse drag detection filter
*
* A simple mouse filter that detects the start of a mouse drag over a
* threshold distance and sends a message with the 'what' field of your
* choice. Especially useful for drag and drop.
* Allows you to free your code of encumbering mouse tracking details.
*
* It can detect fast drags spanning outside of a small view by temporarily
* setting the B_POINTER_EVENTS flag on the view.
*/
#include <DragTrackingFilter.h>
#include <Message.h>
#include <Messenger.h>
#include <View.h>
static const int kSquaredDragThreshold = 9;
DragTrackingFilter::DragTrackingFilter(BView* targetView, uint32 messageWhat)
: BMessageFilter(B_ANY_DELIVERY, B_ANY_SOURCE),
fTargetView(targetView),
fMessageWhat(messageWhat),
fIsTracking(false),
fClickButtons(0)
{
}
filter_result
DragTrackingFilter::Filter(BMessage* message, BHandler** /*_target*/)
{
if (fTargetView == NULL)
return B_DISPATCH_MESSAGE;
switch (message->what) {
case B_MOUSE_DOWN:
message->FindPoint("where", &fClickPoint);
message->FindInt32("buttons", (int32*)&fClickButtons);
fIsTracking = true;
fTargetView->SetMouseEventMask(B_POINTER_EVENTS);
return B_DISPATCH_MESSAGE;
case B_MOUSE_UP:
fIsTracking = false;
return B_DISPATCH_MESSAGE;
case B_MOUSE_MOVED:
{
BPoint where;
message->FindPoint("be:view_where", &where);
// TODO: be more flexible about buttons and pass their state
// in the message
if (fIsTracking && (fClickButtons & B_PRIMARY_MOUSE_BUTTON)) {
BPoint delta(fClickPoint - where);
float squaredDelta = (delta.x * delta.x) + (delta.y * delta.y);
if (squaredDelta >= kSquaredDragThreshold) {
BMessage dragClickMessage(fMessageWhat);
dragClickMessage.AddPoint("be:view_where", fClickPoint);
// name it "be:view_where" since BView::DragMessage
// positions the dragging frame/bitmap by retrieving the
// current message and reading that field
BMessenger messenger(fTargetView);
messenger.SendMessage(&dragClickMessage);
fIsTracking = false;
}
}
return B_DISPATCH_MESSAGE;
}
default:
break;
}
return B_DISPATCH_MESSAGE;
}