708 lines
19 KiB
C++
708 lines
19 KiB
C++
// Copyright (c) 2012-2022 Wojciech Figat. All rights reserved.
|
|
|
|
#if PLATFORM_WINDOWS
|
|
|
|
#include "WindowsWindow.h"
|
|
|
|
#if USE_EDITOR
|
|
|
|
#include "Engine/Core/Log.h"
|
|
#include "Engine/Core/Collections/Array.h"
|
|
#include "Engine/Engine/Engine.h"
|
|
#include "Engine/Platform/IGuiData.h"
|
|
#include "Engine/Input/Input.h"
|
|
#include "Engine/Input/Mouse.h"
|
|
#include "Engine/Threading/ThreadPoolTask.h"
|
|
#include "Engine/Threading/ThreadPool.h"
|
|
#include "Engine/Scripting/Scripting.h"
|
|
#include "Engine/Scripting/ManagedCLR/MDomain.h"
|
|
#include "../Win32/IncludeWindowsHeaders.h"
|
|
#include <oleidl.h>
|
|
#include <shellapi.h>
|
|
|
|
HGLOBAL duplicateGlobalMem(HGLOBAL hMem)
|
|
{
|
|
auto len = GlobalSize(hMem);
|
|
auto source = GlobalLock(hMem);
|
|
auto dest = GlobalAlloc(GMEM_FIXED, len);
|
|
Platform::MemoryCopy(dest, source, len);
|
|
GlobalUnlock(hMem);
|
|
return dest;
|
|
}
|
|
|
|
DWORD dropEffect2OleEnum(DragDropEffect effect)
|
|
{
|
|
DWORD result;
|
|
switch (effect)
|
|
{
|
|
case DragDropEffect::None:
|
|
result = DROPEFFECT_NONE;
|
|
break;
|
|
case DragDropEffect::Copy:
|
|
result = DROPEFFECT_COPY;
|
|
break;
|
|
case DragDropEffect::Move:
|
|
result = DROPEFFECT_MOVE;
|
|
break;
|
|
case DragDropEffect::Link:
|
|
result = DROPEFFECT_LINK;
|
|
break;
|
|
default:
|
|
result = DROPEFFECT_NONE;
|
|
break;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
DragDropEffect dropEffectFromOleEnum(DWORD effect)
|
|
{
|
|
DragDropEffect result;
|
|
switch (effect)
|
|
{
|
|
case DROPEFFECT_NONE:
|
|
result = DragDropEffect::None;
|
|
break;
|
|
case DROPEFFECT_COPY:
|
|
result = DragDropEffect::Copy;
|
|
break;
|
|
case DROPEFFECT_MOVE:
|
|
result = DragDropEffect::Move;
|
|
break;
|
|
case DROPEFFECT_LINK:
|
|
result = DragDropEffect::Link;
|
|
break;
|
|
default:
|
|
result = DragDropEffect::None;
|
|
break;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
HANDLE StringToHandle(const StringView& str)
|
|
{
|
|
// Allocate and lock a global memory buffer.
|
|
// Make it fixed data so we don't have to use GlobalLock
|
|
const int32 length = str.Length();
|
|
char* ptr = static_cast<char*>(GlobalAlloc(GMEM_FIXED, length + 1));
|
|
|
|
// Copy the string into the buffer as ANSI text
|
|
StringUtils::ConvertUTF162ANSI(str.Get(), ptr, length);
|
|
ptr[length] = '\0';
|
|
|
|
return ptr;
|
|
}
|
|
|
|
void DeepCopyFormatEtc(FORMATETC* dest, FORMATETC* source)
|
|
{
|
|
// Copy the source FORMATETC into dest
|
|
*dest = *source;
|
|
|
|
if (source->ptd)
|
|
{
|
|
// Allocate memory for the DVTARGETDEVICE if necessary
|
|
dest->ptd = static_cast<DVTARGETDEVICE*>(CoTaskMemAlloc(sizeof(DVTARGETDEVICE)));
|
|
|
|
// Copy the contents of the source DVTARGETDEVICE into dest->ptd
|
|
*(dest->ptd) = *(source->ptd);
|
|
}
|
|
}
|
|
|
|
HRESULT CreateEnumFormatEtc(UINT nNumFormats, FORMATETC* pFormatEtc, IEnumFORMATETC** ppEnumFormatEtc);
|
|
|
|
/// <summary>
|
|
/// GUI data for Windows platform
|
|
/// </summary>
|
|
class WindowsGuiData : public IGuiData
|
|
{
|
|
private:
|
|
|
|
Type _type;
|
|
Array<String> _data;
|
|
|
|
public:
|
|
|
|
/// <summary>
|
|
/// Init
|
|
/// </summary>
|
|
WindowsGuiData()
|
|
: _type(Type::Unknown)
|
|
, _data(1)
|
|
{
|
|
}
|
|
|
|
public:
|
|
|
|
/// <summary>
|
|
/// Init from Ole IDataObject
|
|
/// </summary>
|
|
/// <param name="pDataObj">Object</param>
|
|
void Init(IDataObject* pDataObj)
|
|
{
|
|
// Temporary data
|
|
FORMATETC fmtetc;
|
|
STGMEDIUM stgmed;
|
|
|
|
// Clear
|
|
_type = Type::Unknown;
|
|
_data.Clear();
|
|
|
|
// Check type
|
|
fmtetc = { CF_TEXT, nullptr, DVASPECT_CONTENT, -1, TYMED_HGLOBAL };
|
|
if (pDataObj->GetData(&fmtetc, &stgmed) == S_OK)
|
|
{
|
|
// Text
|
|
_type = Type::Text;
|
|
|
|
// Get data
|
|
char* text = static_cast<char*>(GlobalLock(stgmed.hGlobal));
|
|
_data.Add(String(text));
|
|
GlobalUnlock(stgmed.hGlobal);
|
|
ReleaseStgMedium(&stgmed);
|
|
}
|
|
else
|
|
{
|
|
fmtetc = { CF_UNICODETEXT, nullptr, DVASPECT_CONTENT, -1, TYMED_HGLOBAL };
|
|
if (pDataObj->GetData(&fmtetc, &stgmed) == S_OK)
|
|
{
|
|
// Unicode Text
|
|
_type = Type::Text;
|
|
|
|
// Get data
|
|
Char* text = static_cast<Char*>(GlobalLock(stgmed.hGlobal));
|
|
_data.Add(String(text));
|
|
GlobalUnlock(stgmed.hGlobal);
|
|
ReleaseStgMedium(&stgmed);
|
|
}
|
|
else
|
|
{
|
|
fmtetc = { CF_HDROP, nullptr, DVASPECT_CONTENT, -1, TYMED_HGLOBAL };
|
|
if (pDataObj->GetData(&fmtetc, &stgmed) == S_OK)
|
|
{
|
|
// Files
|
|
_type = Type::Files;
|
|
|
|
// Get data
|
|
Char item[MAX_PATH];
|
|
HDROP hdrop = static_cast<HDROP>(GlobalLock(stgmed.hGlobal));
|
|
UINT filesCount = DragQueryFileW(hdrop, 0xFFFFFFFF, nullptr, 0);
|
|
for (UINT i = 0; i < filesCount; i++)
|
|
{
|
|
if (DragQueryFileW(hdrop, i, item, MAX_PATH) != 0)
|
|
{
|
|
_data.Add(String(item));
|
|
}
|
|
}
|
|
GlobalUnlock(stgmed.hGlobal);
|
|
ReleaseStgMedium(&stgmed);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
public:
|
|
|
|
// [IGuiData]
|
|
Type GetType() const override
|
|
{
|
|
return _type;
|
|
}
|
|
|
|
String GetAsText() const override
|
|
{
|
|
String result;
|
|
if (_type == Type::Text)
|
|
{
|
|
result = _data[0];
|
|
}
|
|
return result;
|
|
}
|
|
|
|
void GetAsFiles(Array<String>* files) const override
|
|
{
|
|
if (_type == Type::Files)
|
|
{
|
|
files->Add(_data);
|
|
}
|
|
}
|
|
};
|
|
|
|
/// <summary>
|
|
/// Tool class for Windows Ole support
|
|
/// </summary>
|
|
class WindowsEnumFormatEtc : public IEnumFORMATETC
|
|
{
|
|
private:
|
|
|
|
ULONG _refCount;
|
|
ULONG _index;
|
|
ULONG _formatsCount;
|
|
FORMATETC* _formatEtc;
|
|
|
|
public:
|
|
|
|
WindowsEnumFormatEtc(FORMATETC* pFormatEtc, int32 nNumFormats)
|
|
: _refCount(1)
|
|
, _index(0)
|
|
, _formatsCount(nNumFormats)
|
|
, _formatEtc(nullptr)
|
|
{
|
|
// Allocate memory
|
|
_formatEtc = new FORMATETC[nNumFormats];
|
|
|
|
// Copy the FORMATETC structures
|
|
for (int32 i = 0; i < nNumFormats; i++)
|
|
{
|
|
DeepCopyFormatEtc(&_formatEtc[i], &pFormatEtc[i]);
|
|
}
|
|
}
|
|
|
|
~WindowsEnumFormatEtc()
|
|
{
|
|
if (_formatEtc)
|
|
{
|
|
for (uint32 i = 0; i < _formatsCount; i++)
|
|
{
|
|
if (_formatEtc[i].ptd)
|
|
{
|
|
CoTaskMemFree(_formatEtc[i].ptd);
|
|
}
|
|
}
|
|
|
|
delete[] _formatEtc;
|
|
}
|
|
}
|
|
|
|
public:
|
|
|
|
HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, _COM_Outptr_ void __RPC_FAR *__RPC_FAR * ppvObject) override
|
|
{
|
|
// Check to see what interface has been requested
|
|
if (riid == IID_IEnumFORMATETC || riid == IID_IUnknown)
|
|
{
|
|
AddRef();
|
|
*ppvObject = this;
|
|
return S_OK;
|
|
}
|
|
|
|
// No interface
|
|
*ppvObject = nullptr;
|
|
return E_NOINTERFACE;
|
|
}
|
|
|
|
ULONG STDMETHODCALLTYPE AddRef() override
|
|
{
|
|
_InterlockedIncrement(&_refCount);
|
|
return _refCount;
|
|
}
|
|
|
|
ULONG STDMETHODCALLTYPE Release() override
|
|
{
|
|
ULONG ulRefCount = _InterlockedDecrement(&_refCount);
|
|
if (_refCount == 0)
|
|
{
|
|
delete this;
|
|
}
|
|
return ulRefCount;
|
|
}
|
|
|
|
// [IEnumFormatEtc]
|
|
HRESULT STDMETHODCALLTYPE Next(ULONG celt, FORMATETC* pFormatEtc, ULONG* pceltFetched) override
|
|
{
|
|
ULONG copied = 0;
|
|
|
|
// validate arguments
|
|
if (celt == 0 || pFormatEtc == nullptr)
|
|
return E_INVALIDARG;
|
|
|
|
// copy FORMATETC structures into caller's buffer
|
|
while (_index < _formatsCount && copied < celt)
|
|
{
|
|
DeepCopyFormatEtc(&pFormatEtc[copied], &_formatEtc[_index]);
|
|
copied++;
|
|
_index++;
|
|
}
|
|
|
|
// store result
|
|
if (pceltFetched != nullptr)
|
|
*pceltFetched = copied;
|
|
|
|
// did we copy all that was requested?
|
|
return (copied == celt) ? S_OK : S_FALSE;
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE Skip(ULONG celt) override
|
|
{
|
|
_index += celt;
|
|
return (_index <= _formatsCount) ? S_OK : S_FALSE;
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE Reset() override
|
|
{
|
|
_index = 0;
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE Clone(IEnumFORMATETC** ppEnumFormatEtc) override
|
|
{
|
|
HRESULT result;
|
|
|
|
// Make a duplicate enumerator
|
|
result = CreateEnumFormatEtc(_formatsCount, _formatEtc, ppEnumFormatEtc);
|
|
|
|
if (result == S_OK)
|
|
{
|
|
// Manually set the index state
|
|
static_cast<WindowsEnumFormatEtc*>(*ppEnumFormatEtc)->_index = _index;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
};
|
|
|
|
HRESULT CreateEnumFormatEtc(UINT nNumFormats, FORMATETC* pFormatEtc, IEnumFORMATETC** ppEnumFormatEtc)
|
|
{
|
|
if (nNumFormats == 0 || pFormatEtc == nullptr || ppEnumFormatEtc == nullptr)
|
|
return E_INVALIDARG;
|
|
|
|
*ppEnumFormatEtc = new WindowsEnumFormatEtc(pFormatEtc, nNumFormats);
|
|
|
|
return (*ppEnumFormatEtc) ? S_OK : E_OUTOFMEMORY;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Drag drop source and data container for Ole
|
|
/// </summary>
|
|
class WindowsDragSource : public IDataObject, public IDropSource
|
|
{
|
|
private:
|
|
|
|
ULONG _refCount;
|
|
int32 _formatsCount;
|
|
FORMATETC* _formatEtc;
|
|
STGMEDIUM* _stgMedium;
|
|
|
|
public:
|
|
|
|
WindowsDragSource(FORMATETC* fmtetc, STGMEDIUM* stgmed, int32 count)
|
|
: _refCount(1)
|
|
, _formatsCount(count)
|
|
, _formatEtc(nullptr)
|
|
, _stgMedium(nullptr)
|
|
{
|
|
// Allocate memory
|
|
_formatEtc = new FORMATETC[count];
|
|
_stgMedium = new STGMEDIUM[count];
|
|
|
|
// Copy descriptors
|
|
for (int32 i = 0; i < count; i++)
|
|
{
|
|
_formatEtc[i] = fmtetc[i];
|
|
_stgMedium[i] = stgmed[i];
|
|
}
|
|
}
|
|
|
|
virtual ~WindowsDragSource()
|
|
{
|
|
if (_formatEtc)
|
|
delete[] _formatEtc;
|
|
if (_stgMedium)
|
|
delete[] _stgMedium;
|
|
}
|
|
|
|
public:
|
|
|
|
// [IUnknown]
|
|
HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, _COM_Outptr_ void __RPC_FAR *__RPC_FAR * ppvObject) override
|
|
{
|
|
// Check to see what interface has been requested
|
|
if (riid == IID_IDataObject || riid == IID_IUnknown || riid == IID_IDropSource)
|
|
{
|
|
AddRef();
|
|
*ppvObject = this;
|
|
return S_OK;
|
|
}
|
|
|
|
// No interface
|
|
*ppvObject = nullptr;
|
|
return E_NOINTERFACE;
|
|
}
|
|
|
|
ULONG STDMETHODCALLTYPE AddRef() override
|
|
{
|
|
_InterlockedIncrement(&_refCount);
|
|
return _refCount;
|
|
}
|
|
|
|
ULONG STDMETHODCALLTYPE Release() override
|
|
{
|
|
ULONG ulRefCount = _InterlockedDecrement(&_refCount);
|
|
if (_refCount == 0)
|
|
{
|
|
delete this;
|
|
}
|
|
return ulRefCount;
|
|
}
|
|
|
|
// [IDropSource]
|
|
HRESULT STDMETHODCALLTYPE QueryContinueDrag(_In_ BOOL fEscapePressed, _In_ DWORD grfKeyState) override
|
|
{
|
|
// If the Escape key has been pressed since the last call, cancel the drop
|
|
if (fEscapePressed == TRUE || grfKeyState & MK_RBUTTON)
|
|
return DRAGDROP_S_CANCEL;
|
|
|
|
// If the LeftMouse button has been released, then do the drop!
|
|
if ((grfKeyState & MK_LBUTTON) == 0)
|
|
return DRAGDROP_S_DROP;
|
|
|
|
// Continue with the drag-drop
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE GiveFeedback(_In_ DWORD dwEffect) override
|
|
{
|
|
// TODO: allow to use custom mouse cursor during drop and drag operation
|
|
return DRAGDROP_S_USEDEFAULTCURSORS;
|
|
}
|
|
|
|
// [IDataObject]
|
|
HRESULT STDMETHODCALLTYPE GetData(_In_ FORMATETC* pformatetcIn, _Out_ STGMEDIUM* pmedium) override
|
|
{
|
|
if (pformatetcIn == nullptr || pmedium == nullptr)
|
|
return E_INVALIDARG;
|
|
|
|
// Try to match the specified FORMATETC with one of our supported formats
|
|
int32 index = lookupFormatEtc(pformatetcIn);
|
|
if (index == INVALID_INDEX)
|
|
return DV_E_FORMATETC;
|
|
|
|
// Found a match - transfer data into supplied storage medium
|
|
pmedium->tymed = _formatEtc[index].tymed;
|
|
pmedium->pUnkForRelease = nullptr;
|
|
|
|
// Copy the data into the caller's storage medium
|
|
switch (_formatEtc[index].tymed)
|
|
{
|
|
case TYMED_HGLOBAL:
|
|
pmedium->hGlobal = duplicateGlobalMem(_stgMedium[index].hGlobal);
|
|
break;
|
|
|
|
default:
|
|
return DV_E_FORMATETC;
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE GetDataHere(_In_ FORMATETC* pformatetc, _Inout_ STGMEDIUM* pmedium) override
|
|
{
|
|
return DATA_E_FORMATETC;
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE QueryGetData(__RPC__in_opt FORMATETC* pformatetc) override
|
|
{
|
|
return lookupFormatEtc(pformatetc) == INVALID_INDEX ? DV_E_FORMATETC : S_OK;
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE GetCanonicalFormatEtc(__RPC__in_opt FORMATETC* pformatectIn, __RPC__out FORMATETC* pformatetcOut) override
|
|
{
|
|
// Apparently we have to set this field to NULL even though we don't do anything else
|
|
pformatetcOut->ptd = nullptr;
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE SetData(_In_ FORMATETC* pformatetc, _In_ STGMEDIUM* pmedium, BOOL fRelease) override
|
|
{
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE EnumFormatEtc(DWORD dwDirection, __RPC__deref_out_opt IEnumFORMATETC** ppenumFormatEtc) override
|
|
{
|
|
// Only the get direction is supported for OLE
|
|
if (dwDirection == DATADIR_GET)
|
|
{
|
|
// TODO: use SHCreateStdEnumFmtEtc API call
|
|
return CreateEnumFormatEtc(_formatsCount, _formatEtc, ppenumFormatEtc);
|
|
}
|
|
|
|
// The direction specified is not supported for drag+drop
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE DAdvise(__RPC__in FORMATETC* pformatetc, DWORD advf, __RPC__in_opt IAdviseSink* pAdvSink, __RPC__out DWORD* pdwConnection) override
|
|
{
|
|
return OLE_E_ADVISENOTSUPPORTED;
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE DUnadvise(DWORD dwConnection) override
|
|
{
|
|
return OLE_E_ADVISENOTSUPPORTED;
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE EnumDAdvise(__RPC__deref_out_opt IEnumSTATDATA** ppenumAdvise) override
|
|
{
|
|
return OLE_E_ADVISENOTSUPPORTED;
|
|
}
|
|
|
|
private:
|
|
|
|
int32 lookupFormatEtc(FORMATETC* pFormatEtc) const
|
|
{
|
|
// Check each of our formats in turn to see if one matches
|
|
for (int32 i = 0; i < _formatsCount; i++)
|
|
{
|
|
if ((_formatEtc[i].tymed & pFormatEtc->tymed) &&
|
|
_formatEtc[i].cfFormat == pFormatEtc->cfFormat &&
|
|
_formatEtc[i].dwAspect == pFormatEtc->dwAspect)
|
|
{
|
|
// Return index of stored format
|
|
return i;
|
|
}
|
|
}
|
|
|
|
// Format not found
|
|
return INVALID_INDEX;
|
|
}
|
|
};
|
|
|
|
WindowsGuiData GuiDragDropData;
|
|
|
|
/// <summary>
|
|
/// Async DoDragDrop helper (used for rendering frames during main thread stall).
|
|
/// </summary>
|
|
class DoDragDropJob : public ThreadPoolTask
|
|
{
|
|
public:
|
|
|
|
int64 ExitFlag = 0;
|
|
|
|
public:
|
|
|
|
// [ThreadPoolTask]
|
|
bool Run() override
|
|
{
|
|
const uint64 beginFrame = Engine::FrameCount;
|
|
|
|
Scripting::GetScriptsDomain()->Dispatch();
|
|
|
|
while (Platform::AtomicRead(&ExitFlag) == 0)
|
|
{
|
|
// Render single frame
|
|
Engine::OnDraw();
|
|
|
|
// Wait for a while
|
|
Platform::Sleep(20);
|
|
}
|
|
|
|
const uint64 endFrame = Engine::FrameCount;
|
|
LOG(Info, "Rendered {0} frames during DoDragDrop stall.", endFrame - beginFrame);
|
|
|
|
return false;
|
|
}
|
|
};
|
|
|
|
DragDropEffect WindowsWindow::DoDragDrop(const StringView& data)
|
|
{
|
|
// Create background worker that will keep updating GUI (perform rendering)
|
|
const auto task = New<DoDragDropJob>();
|
|
Task::StartNew(task);
|
|
while (task->GetState() == TaskState::Queued)
|
|
{
|
|
Platform::Sleep(1);
|
|
}
|
|
|
|
// Create descriptors
|
|
FORMATETC fmtetc = { CF_TEXT, nullptr, DVASPECT_CONTENT, -1, TYMED_HGLOBAL };
|
|
STGMEDIUM stgmed = { TYMED_HGLOBAL, { nullptr }, nullptr };
|
|
|
|
// Create a HGLOBAL inside the storage medium
|
|
stgmed.hGlobal = StringToHandle(data);
|
|
|
|
// Create drop source
|
|
auto dropSource = new WindowsDragSource(&fmtetc, &stgmed, 1);
|
|
|
|
// Do the drag drop operation
|
|
DWORD dwEffect;
|
|
HRESULT result = ::DoDragDrop(dropSource, dropSource, DROPEFFECT_COPY | DROPEFFECT_MOVE | DROPEFFECT_LINK | DROPEFFECT_SCROLL, &dwEffect);
|
|
|
|
// Wait for job end
|
|
Platform::AtomicStore(&task->ExitFlag, 1);
|
|
task->Wait();
|
|
|
|
// Release allocated data
|
|
dropSource->Release();
|
|
ReleaseStgMedium(&stgmed);
|
|
|
|
// Fix hanging mouse state (Windows doesn't send WM_LBUTTONUP when we end the drag and drop)
|
|
if (Input::GetMouseButton(MouseButton::Left))
|
|
Input::Mouse->OnMouseUp(Input::Mouse->GetPosition(), MouseButton::Left, this);
|
|
|
|
return SUCCEEDED(result) ? dropEffectFromOleEnum(dwEffect) : DragDropEffect::None;
|
|
}
|
|
|
|
HRESULT WindowsWindow::DragEnter(Windows::IDataObject* pDataObj, Windows::DWORD grfKeyState, Windows::POINTL pt, Windows::DWORD* pdwEffect)
|
|
{
|
|
// Call GUI
|
|
POINT p = { pt.x, pt.y };
|
|
::ScreenToClient(_handle, &p);
|
|
GuiDragDropData.Init((IDataObject*)pDataObj);
|
|
DragDropEffect effect = DragDropEffect::None;
|
|
OnDragEnter(&GuiDragDropData, Vector2(static_cast<float>(p.x), static_cast<float>(p.y)), effect);
|
|
|
|
// Focus
|
|
Focus();
|
|
|
|
// Translate effect into Ole Api type
|
|
*pdwEffect = dropEffect2OleEnum(effect);
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT WindowsWindow::DragOver(Windows::DWORD grfKeyState, Windows::POINTL pt, Windows::DWORD* pdwEffect)
|
|
{
|
|
// Call GUI
|
|
POINT p = { pt.x, pt.y };
|
|
::ScreenToClient(_handle, &p);
|
|
DragDropEffect effect = DragDropEffect::None;
|
|
OnDragOver(&GuiDragDropData, Vector2(static_cast<float>(p.x), static_cast<float>(p.y)), effect);
|
|
|
|
// Translate effect into Ole Api type
|
|
*pdwEffect = dropEffect2OleEnum(effect);
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT WindowsWindow::DragLeave()
|
|
{
|
|
// Call GUI
|
|
OnDragLeave();
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT WindowsWindow::Drop(Windows::IDataObject* pDataObj, Windows::DWORD grfKeyState, Windows::POINTL pt, Windows::DWORD* pdwEffect)
|
|
{
|
|
// Call GUI
|
|
POINT p = { pt.x, pt.y };
|
|
::ScreenToClient(_handle, &p);
|
|
GuiDragDropData.Init((IDataObject*)pDataObj);
|
|
DragDropEffect effect = DragDropEffect::None;
|
|
OnDragDrop(&GuiDragDropData, Vector2(static_cast<float>(p.x), static_cast<float>(p.y)), effect);
|
|
|
|
// Translate effect into Ole Api type
|
|
*pdwEffect = dropEffect2OleEnum(effect);
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
#else
|
|
|
|
DragDropEffect WindowsWindow::DoDragDrop(const StringView& data)
|
|
{
|
|
// Not supported
|
|
return DragDropEffect::None;
|
|
}
|
|
|
|
#endif
|
|
|
|
#endif
|