diff --git a/headers/os/interface/Dragger.h b/headers/os/interface/Dragger.h index 55aa70c672..b1300b87a0 100644 --- a/headers/os/interface/Dragger.h +++ b/headers/os/interface/Dragger.h @@ -1,5 +1,5 @@ /* - * Copyright 2006-2007, Haiku, Inc. All Rights Reserved. + * Copyright 2006-2009, Haiku, Inc. All Rights Reserved. * Distributed under the terms of the MIT License. */ #ifndef _DRAGGER_H @@ -115,7 +115,7 @@ class BDragger : public BView { bool fIsZombie; char fErrCount; bool fPopUpIsCustom; - BBitmap * fBitmap; + BBitmap* fBitmap; BPopUpMenu* fPopUp; uint32 _reserved[3]; }; diff --git a/headers/private/shared/DragTrackingFilter.h b/headers/private/shared/DragTrackingFilter.h new file mode 100644 index 0000000000..9d8eb0f0ce --- /dev/null +++ b/headers/private/shared/DragTrackingFilter.h @@ -0,0 +1,34 @@ +/* + * Copyright 2009, Alexandre Deckner, alex@zappotek.com + * Distributed under the terms of the MIT License. + */ +#ifndef DRAG_TRACKING_FILTER_H +#define DRAG_TRACKING_FILTER_H + +#include +#include + +class BView; +class BHandler; + +namespace BPrivate { + +class DragTrackingFilter : public BMessageFilter { +public: + DragTrackingFilter(BView* targetView, uint32 messageWhat); + + filter_result Filter(BMessage* message, BHandler** _target); + +private: + BView* fTargetView; + uint32 fMessageWhat; + bool fIsTracking; + BPoint fClickPoint; + uint32 fClickButtons; +}; + +} // namespace BPrivate + +using BPrivate::DragTrackingFilter; + +#endif // DRAG_TRACKING_FILTER_H diff --git a/src/kits/interface/Dragger.cpp b/src/kits/interface/Dragger.cpp index 3182e962da..d3b0bd7c3b 100644 --- a/src/kits/interface/Dragger.cpp +++ b/src/kits/interface/Dragger.cpp @@ -1,10 +1,11 @@ /* - * Copyright 2001-2008, Haiku. + * Copyright 2001-2009, Haiku. * Distributed under the terms of the MIT License. * * Authors: * Marc Flerackers (mflerackers@androme.be) * Rene Gollent (rene@gollent.com) + * Alexandre Deckner (alex@zappotek.com) */ //! BDragger represents a replicant "handle". @@ -25,6 +26,7 @@ #include #include +#include #include #include #include @@ -37,6 +39,7 @@ bool BDragger::sVisibleInitialized; BLocker BDragger::sLock("BDragger static"); BList BDragger::sList; +const uint32 kMsgDragStarted = 'Drgs'; const unsigned char kHandBitmap[] = { @@ -153,6 +156,8 @@ BDragger::AttachedToWindow() _DetermineRelationship(); _AddToList(); + + AddFilter(new DragTrackingFilter(this, kMsgDragStarted)); } @@ -211,73 +216,8 @@ BDragger::MouseDown(BPoint where) uint32 buttons; Window()->CurrentMessage()->FindInt32("buttons", (int32 *)&buttons); - if (buttons & B_SECONDARY_MOUSE_BUTTON) { - if (!fShelf) - return; - + if (fShelf != NULL && (buttons & B_SECONDARY_MOUSE_BUTTON)) _ShowPopUp(fTarget, where); - } else { - bigtime_t time = system_time(); - bigtime_t clickSpeed = 0; - - get_click_speed(&clickSpeed); - - bool drag = false; - - while (true) { - BPoint mousePoint; - GetMouse(&mousePoint, &buttons, false); - - if (!buttons || system_time() > time + clickSpeed) - break; - - float squaredDistance = - (mousePoint.x - where.x) * (mousePoint.x - where.x) - + (mousePoint.y - where.y) * (mousePoint.y - where.y); - - if (squaredDistance >= 16) { - drag = true; - break; - } - - snooze(40000); - } - - if (drag) { - BMessage archive(B_ARCHIVED_OBJECT); - - if (fRelation == TARGET_IS_PARENT) - fTarget->Archive(&archive); - else if (fRelation == TARGET_IS_CHILD) - Archive(&archive); - else { - if (fTarget->Archive(&archive)) { - BMessage archivedSelf(B_ARCHIVED_OBJECT); - - if (Archive(&archivedSelf)) - archive.AddMessage("__widget", &archivedSelf); - } - } - - archive.AddInt32("be:actions", B_TRASH_TARGET); - - BPoint offset; - drawing_mode mode; - BBitmap *bitmap = DragBitmap(&offset, &mode); - if (bitmap != NULL) - DragMessage(&archive, bitmap, mode, offset, this); - else { - DragMessage(&archive, - ConvertFromScreen(fTarget->ConvertToScreen(fTarget->Bounds())), - this); - } - } else { - if (!fShelf) - return; - - _ShowPopUp(fTarget, where); - } - } } @@ -328,6 +268,37 @@ BDragger::MessageReceived(BMessage *msg) } break; + case kMsgDragStarted: + if (fTarget != NULL) { + BMessage archive(B_ARCHIVED_OBJECT); + + if (fRelation == TARGET_IS_PARENT) + fTarget->Archive(&archive); + else if (fRelation == TARGET_IS_CHILD) + Archive(&archive); + else { + if (fTarget->Archive(&archive)) { + BMessage archivedSelf(B_ARCHIVED_OBJECT); + + if (Archive(&archivedSelf)) + archive.AddMessage("__widget", &archivedSelf); + } + } + + archive.AddInt32("be:actions", B_TRASH_TARGET); + BPoint offset; + drawing_mode mode; + BBitmap *bitmap = DragBitmap(&offset, &mode); + if (bitmap != NULL) + DragMessage(&archive, bitmap, mode, offset, this); + else { + DragMessage(&archive, + ConvertFromScreen(fTarget->ConvertToScreen(fTarget->Bounds())), + this); + } + } + break; + default: BView::MessageReceived(msg); break; diff --git a/src/kits/shared/DragTrackingFilter.cpp b/src/kits/shared/DragTrackingFilter.cpp new file mode 100644 index 0000000000..9c4b0dd8ed --- /dev/null +++ b/src/kits/shared/DragTrackingFilter.cpp @@ -0,0 +1,88 @@ +/* + * 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 usefull 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 + +#include +#include +#include + +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; +} diff --git a/src/kits/shared/Jamfile b/src/kits/shared/Jamfile index 5a010c3f9f..13adeb3666 100644 --- a/src/kits/shared/Jamfile +++ b/src/kits/shared/Jamfile @@ -17,6 +17,7 @@ StaticLibrary libshared.a : ColorQuantizer.cpp CommandPipe.cpp DateTime.cpp + DragTrackingFilter.cpp HashString.cpp RWLockManager.cpp ;