1 | //************************************ bs::framework - Copyright 2018 Marko Pintera **************************************// |
---|---|
2 | //*********** Licensed under the MIT license. See LICENSE.md for full terms. This notice is not to be removed. ***********// |
3 | #include "GUI/BsDragAndDropManager.h" |
4 | #include "Platform/BsPlatform.h" |
5 | #include "BsCoreApplication.h" |
6 | #include "Utility/BsTime.h" |
7 | |
8 | using namespace std::placeholders; |
9 | |
10 | namespace bs |
11 | { |
12 | DragAndDropManager::DragAndDropManager() |
13 | { |
14 | mMouseCaptureChangedConn = Platform::onMouseCaptureChanged.connect(std::bind(&DragAndDropManager::mouseCaptureChanged, this)); |
15 | Input::instance().onPointerReleased.connect(std::bind(&DragAndDropManager::cursorReleased, this, _1)); |
16 | } |
17 | |
18 | DragAndDropManager::~DragAndDropManager() |
19 | { |
20 | mMouseCaptureChangedConn.disconnect(); |
21 | } |
22 | |
23 | void DragAndDropManager::addDropCallback(std::function<void(bool)> dropCallback) |
24 | { |
25 | mDropCallbacks.push_back(dropCallback); |
26 | } |
27 | |
28 | void DragAndDropManager::startDrag(UINT32 typeId, void* data, std::function<void(bool)> dropCallback, bool needsValidDropTarget) |
29 | { |
30 | if (mIsDragInProgress) |
31 | endDrag(false); |
32 | |
33 | mDragTypeId = typeId; |
34 | mData = data; |
35 | mNeedsValidDropTarget = needsValidDropTarget; |
36 | addDropCallback(dropCallback); |
37 | mIsDragInProgress = true; |
38 | |
39 | mCaptureActive.store(false); |
40 | mCaptureChanged.store(false); |
41 | |
42 | Platform::captureMouse(*gCoreApplication().getPrimaryWindow()); |
43 | } |
44 | |
45 | void DragAndDropManager::_update() |
46 | { |
47 | if(!mIsDragInProgress) |
48 | return; |
49 | |
50 | // This generally happens when window loses focus and capture is lost (for example alt+tab) |
51 | int captureActive = mCaptureActive.load(); |
52 | if (!captureActive && mCaptureChanged.load() && |
53 | (gTime().getFrameIdx() > mCaptureChangeFrame.load())) // Wait one frame to ensure input (like mouse up) gets a chance to be processed |
54 | { |
55 | endDrag(false); |
56 | mCaptureChanged.store(false); |
57 | } |
58 | } |
59 | |
60 | void DragAndDropManager::endDrag(bool processed) |
61 | { |
62 | for(auto& callback : mDropCallbacks) |
63 | callback(processed); |
64 | |
65 | mDragTypeId = 0; |
66 | mData = nullptr; |
67 | mDropCallbacks.clear(); |
68 | mIsDragInProgress = false; |
69 | } |
70 | |
71 | void DragAndDropManager::mouseCaptureChanged() |
72 | { |
73 | mCaptureActive.fetch_xor(1); // mCaptureActive = !mCaptureActive; |
74 | mCaptureChanged.store(true); |
75 | mCaptureChangeFrame.store(gTime().getFrameIdx()); |
76 | } |
77 | |
78 | void DragAndDropManager::cursorReleased(const PointerEvent& event) |
79 | { |
80 | if(!mIsDragInProgress) |
81 | return; |
82 | |
83 | if(!onDragEnded.empty()) |
84 | { |
85 | DragCallbackInfo info; |
86 | onDragEnded(event, info); |
87 | |
88 | endDrag(info.processed); |
89 | } |
90 | else |
91 | endDrag(false); |
92 | |
93 | Platform::releaseMouseCapture(); |
94 | } |
95 | } |