142 lines
3.7 KiB
C++
142 lines
3.7 KiB
C++
/*
|
|
* Copyright 2011, Alexandre Deckner, alex@zappotek.com
|
|
* Distributed under the terms of the MIT License.
|
|
*/
|
|
|
|
/*!
|
|
\class LongAndDragTrackingFilter
|
|
\brief A simple long mouse down and drag detection filter
|
|
*
|
|
* A simple mouse filter that detects long clicks and pointer drags.
|
|
* A long click message is sent when the mouse button is kept down
|
|
* for a duration longer than a given threshold while the pointer stays
|
|
* within the limits of a given threshold radius.
|
|
* A drag message is triggered if the mouse goes further than the
|
|
* threshold radius before the duration threshold elapsed.
|
|
*
|
|
* The messages contain the pointer position and the buttons state at
|
|
* the moment of the click. The drag message is ready to use with the
|
|
* be/haiku drag and drop API cf. comment in code.
|
|
*
|
|
* Current limitation: A long mouse down or a drag can be detected for
|
|
* any mouse button, but any released button cancels the tracking.
|
|
*
|
|
*/
|
|
|
|
|
|
#include <LongAndDragTrackingFilter.h>
|
|
|
|
#include <Message.h>
|
|
#include <Messenger.h>
|
|
#include <MessageRunner.h>
|
|
#include <View.h>
|
|
|
|
#include <new>
|
|
|
|
|
|
LongAndDragTrackingFilter::LongAndDragTrackingFilter(uint32 longMessageWhat,
|
|
uint32 dragMessageWhat, float radiusThreshold,
|
|
bigtime_t durationThreshold)
|
|
:
|
|
BMessageFilter(B_ANY_DELIVERY, B_ANY_SOURCE),
|
|
fLongMessageWhat(longMessageWhat),
|
|
fDragMessageWhat(dragMessageWhat),
|
|
fMessageRunner(NULL),
|
|
fClickButtons(0),
|
|
fSquaredRadiusThreshold(radiusThreshold * radiusThreshold),
|
|
fDurationThreshold(durationThreshold)
|
|
{
|
|
if (durationThreshold == 0) {
|
|
get_click_speed(&fDurationThreshold);
|
|
// use system's doubleClickSpeed as default threshold
|
|
}
|
|
}
|
|
|
|
|
|
LongAndDragTrackingFilter::~LongAndDragTrackingFilter()
|
|
{
|
|
delete fMessageRunner;
|
|
}
|
|
|
|
|
|
void
|
|
LongAndDragTrackingFilter::_StopTracking()
|
|
{
|
|
delete fMessageRunner;
|
|
fMessageRunner = NULL;
|
|
}
|
|
|
|
|
|
filter_result
|
|
LongAndDragTrackingFilter::Filter(BMessage* message, BHandler** target)
|
|
{
|
|
if (*target == NULL)
|
|
return B_DISPATCH_MESSAGE;
|
|
|
|
switch (message->what) {
|
|
case B_MOUSE_DOWN: {
|
|
int32 clicks = 0;
|
|
|
|
message->FindInt32("buttons", (int32*)&fClickButtons);
|
|
message->FindInt32("clicks", (int32*)&clicks);
|
|
|
|
if (fClickButtons != 0 && clicks == 1) {
|
|
|
|
BView* targetView = dynamic_cast<BView*>(*target);
|
|
if (targetView != NULL)
|
|
targetView->SetMouseEventMask(B_POINTER_EVENTS);
|
|
|
|
message->FindPoint("where", &fClickPoint);
|
|
BMessage message(fLongMessageWhat);
|
|
message.AddPoint("where", fClickPoint);
|
|
message.AddInt32("buttons", fClickButtons);
|
|
|
|
delete fMessageRunner;
|
|
fMessageRunner = new (std::nothrow) BMessageRunner(
|
|
BMessenger(*target), &message, fDurationThreshold, 1);
|
|
}
|
|
return B_DISPATCH_MESSAGE;
|
|
}
|
|
|
|
case B_MOUSE_UP:
|
|
_StopTracking();
|
|
message->AddInt32("last_buttons", (int32)fClickButtons);
|
|
message->FindInt32("buttons", (int32*)&fClickButtons);
|
|
return B_DISPATCH_MESSAGE;
|
|
|
|
case B_MOUSE_MOVED:
|
|
{
|
|
if (fMessageRunner != NULL) {
|
|
BPoint where;
|
|
message->FindPoint("be:view_where", &where);
|
|
|
|
BPoint delta(fClickPoint - where);
|
|
float squaredDelta = (delta.x * delta.x) + (delta.y * delta.y);
|
|
|
|
if (squaredDelta >= fSquaredRadiusThreshold) {
|
|
BMessage dragMessage(fDragMessageWhat);
|
|
dragMessage.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
|
|
dragMessage.AddInt32("buttons", (int32)fClickButtons);
|
|
BMessenger messenger(*target);
|
|
messenger.SendMessage(&dragMessage);
|
|
|
|
_StopTracking();
|
|
}
|
|
}
|
|
return B_DISPATCH_MESSAGE;
|
|
}
|
|
|
|
default:
|
|
if (message->what == fLongMessageWhat) {
|
|
_StopTracking();
|
|
return B_DISPATCH_MESSAGE;
|
|
}
|
|
break;
|
|
}
|
|
|
|
return B_DISPATCH_MESSAGE;
|
|
}
|