xref: /haiku/src/kits/shared/DragTrackingFilter.cpp (revision 25a7b01d15612846f332751841da3579db313082)
1 /*
2  * Copyright 2009, Alexandre Deckner, alex@zappotek.com
3  * Distributed under the terms of the MIT License.
4  */
5 
6 /*!
7 	\class DragTrackingFilter
8 	\brief A simple mouse drag detection filter
9 	*
10 	* A simple mouse filter that detects the start of a mouse drag over a
11 	* threshold distance and sends a message with the 'what' field of your
12 	* choice. Especially useful for drag and drop.
13 	* Allows you to free your code of encumbering mouse tracking details.
14 	*
15 	* It can detect fast drags spanning outside of a small view by temporarily
16 	* setting the B_POINTER_EVENTS flag on the view.
17 */
18 
19 #include <DragTrackingFilter.h>
20 
21 #include <Message.h>
22 #include <Messenger.h>
23 #include <View.h>
24 
25 static const int kSquaredDragThreshold = 9;
26 
DragTrackingFilter(BView * targetView,uint32 messageWhat)27 DragTrackingFilter::DragTrackingFilter(BView* targetView, uint32 messageWhat)
28 	: BMessageFilter(B_ANY_DELIVERY, B_ANY_SOURCE),
29 	fTargetView(targetView),
30 	fMessageWhat(messageWhat),
31 	fIsTracking(false),
32 	fClickButtons(0)
33 {
34 }
35 
36 
37 filter_result
Filter(BMessage * message,BHandler **)38 DragTrackingFilter::Filter(BMessage* message, BHandler** /*_target*/)
39 {
40 	if (fTargetView == NULL)
41 		return B_DISPATCH_MESSAGE;
42 
43 	switch (message->what) {
44 		case B_MOUSE_DOWN:
45 			message->FindPoint("where", &fClickPoint);
46 			message->FindInt32("buttons", (int32*)&fClickButtons);
47 			fIsTracking = true;
48 
49 			fTargetView->SetMouseEventMask(B_POINTER_EVENTS);
50 
51 			return B_DISPATCH_MESSAGE;
52 
53 		case B_MOUSE_UP:
54 			fIsTracking = false;
55 			return B_DISPATCH_MESSAGE;
56 
57 		case B_MOUSE_MOVED:
58 		{
59 			BPoint where;
60 			message->FindPoint("be:view_where", &where);
61 
62 			// TODO: be more flexible about buttons and pass their state
63 			//		 in the message
64 			if (fIsTracking && (fClickButtons & B_PRIMARY_MOUSE_BUTTON)) {
65 
66 				BPoint delta(fClickPoint - where);
67 				float squaredDelta = (delta.x * delta.x) + (delta.y * delta.y);
68 
69 				if (squaredDelta >= kSquaredDragThreshold) {
70 					BMessage dragClickMessage(fMessageWhat);
71 					dragClickMessage.AddPoint("be:view_where", fClickPoint);
72 						// name it "be:view_where" since BView::DragMessage
73 						// positions the dragging frame/bitmap by retrieving the
74 						// current message and reading that field
75 					BMessenger messenger(fTargetView);
76 					messenger.SendMessage(&dragClickMessage);
77 
78 					fIsTracking = false;
79 				}
80 			}
81 			return B_DISPATCH_MESSAGE;
82 		}
83 		default:
84 			break;
85 	}
86 
87 	return B_DISPATCH_MESSAGE;
88 }
89