mirror of
https://github.com/Open-Shell/Open-Shell-Menu.git
synced 2026-04-14 04:38:26 +10:00
Some branding and licensing work (#22)
* Fix stdafx include * Fix basic handling of "Games" folder on Windows10 RS4 (#10) This does the following: - Sets the default state to hidden - Skips the Games folder when searching This does not: - Hide the dead menu entry. I do not currently know how to actively change the user preference setting to forcefully hide it. * Add basic Visual Studio gitignore * Add specific entries to gitignore * Do not set default menu to Win7 on RS4 (#10) * Rename "PC Settings" to "Settings" (#12) * Create distinction between modern and legacy settings in search results * Add more build artifacts to gitignore * Add default paths for toolset and build all languages * Fix several memsize, memtype and nullpointer issues * create trunk branch containing all changes * set fallback and next version to 4.3.2, set resource fallback value to allow loading in IDE * add generated en-US.dll to gitignore * Don't echo script contents, add disabled "git clean -dfx" to build fresh * Initial re-branding work (#21) * Create copy of __MakeFinal to build all languages (Use this file when releasing new versions) * Move the registry key IvoSoft->Passionate-Coder (#21) * Change company/mfg name IvoSoft->Passionate-Coder (#21) * Update some leftover copyright dates (#21) * Fix accidental copy-paste breaking MakeFinal scripts * Fix invalid company name for Wix and change registry keys to match the new string (#21) * Update more copyright and legal text (#21) * Update RTF files format (Wordpad generated those) (#21) * update license text in RTF files (#21) We lost the blue link text in the installer page. Will have to manually re-color all the links later.
This commit is contained in:
@@ -0,0 +1,936 @@
|
||||
// ## MenuContainer.h
|
||||
// Classic Shell (c) 2009-2017, Ivo Beltchev
|
||||
// Classic Start (c) 2017-2018, The Passionate-Coder Team
|
||||
// Confidential information of Ivo Beltchev. Not for disclosure or distribution without prior written consent from the author
|
||||
|
||||
// DragDrop.cpp - handles the drag and drop functionality of CMenuContainer
|
||||
|
||||
#include "stdafx.h"
|
||||
#include "MenuContainer.h"
|
||||
#include "ClassicStartMenuDLL.h"
|
||||
#include "SettingsUI.h"
|
||||
#include "FNVHash.h"
|
||||
#include "Settings.h"
|
||||
#include "ResourceHelper.h"
|
||||
#include "Translations.h"
|
||||
#include "FileHelper.h"
|
||||
#include <algorithm>
|
||||
|
||||
class CMetroDataObject: public IDataObject
|
||||
{
|
||||
public:
|
||||
CMetroDataObject( const wchar_t *path );
|
||||
~CMetroDataObject( void );
|
||||
|
||||
// from IUnknown
|
||||
virtual HRESULT STDMETHODCALLTYPE QueryInterface( REFIID riid, void **ppvObject );
|
||||
virtual ULONG STDMETHODCALLTYPE AddRef( void )
|
||||
{
|
||||
return ++m_RefCount;
|
||||
}
|
||||
virtual ULONG STDMETHODCALLTYPE Release( void )
|
||||
{
|
||||
if (m_RefCount==1)
|
||||
{
|
||||
delete this;
|
||||
return 0;
|
||||
}
|
||||
return --m_RefCount;
|
||||
}
|
||||
|
||||
// from IDataObject
|
||||
virtual HRESULT STDMETHODCALLTYPE GetData( FORMATETC *pformatetcIn, STGMEDIUM *pmedium );
|
||||
virtual HRESULT STDMETHODCALLTYPE SetData( FORMATETC *pformatetc, STGMEDIUM *pmedium, BOOL fRelease ) { return E_NOTIMPL; }
|
||||
virtual HRESULT STDMETHODCALLTYPE GetDataHere( FORMATETC *pformatetc, STGMEDIUM *pmedium ) { return E_NOTIMPL; }
|
||||
virtual HRESULT STDMETHODCALLTYPE QueryGetData( FORMATETC *pformatetc );
|
||||
virtual HRESULT STDMETHODCALLTYPE GetCanonicalFormatEtc( FORMATETC *pformatectIn, FORMATETC *pformatetcOut );
|
||||
virtual HRESULT STDMETHODCALLTYPE EnumFormatEtc( DWORD dwDirection, IEnumFORMATETC **ppenumFormatEtc );
|
||||
virtual HRESULT STDMETHODCALLTYPE DAdvise( FORMATETC *pformatetc, DWORD advf, IAdviseSink *pAdvSink, DWORD *pdwConnection ) { return OLE_E_ADVISENOTSUPPORTED; }
|
||||
virtual HRESULT STDMETHODCALLTYPE DUnadvise( DWORD dwConnection ) { return E_NOTIMPL; }
|
||||
virtual HRESULT STDMETHODCALLTYPE EnumDAdvise( IEnumSTATDATA **ppenumAdvise ) { return OLE_E_ADVISENOTSUPPORTED; }
|
||||
|
||||
private:
|
||||
int m_RefCount;
|
||||
std::map<CLIPFORMAT,HGLOBAL> m_Data;
|
||||
bool m_bContents;
|
||||
|
||||
void SetData( CLIPFORMAT format, HGLOBAL data );
|
||||
};
|
||||
|
||||
static CLIPFORMAT g_PreferredEffectFormat;
|
||||
|
||||
CMetroDataObject::CMetroDataObject( const wchar_t *path )
|
||||
{
|
||||
m_RefCount=0;
|
||||
m_bContents=false;
|
||||
SetData(CMenuContainer::s_MetroLinkFormat,NULL);
|
||||
|
||||
if (!path) return;
|
||||
HANDLE file=CreateFile(path,GENERIC_READ,FILE_SHARE_READ,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);
|
||||
if (file!=INVALID_HANDLE_VALUE)
|
||||
{
|
||||
DWORD size=GetFileSize(file,NULL);
|
||||
if (size>0)
|
||||
{
|
||||
HGLOBAL hContents=NULL, hDesc=NULL;
|
||||
hContents=GlobalAlloc(GMEM_MOVEABLE,size);
|
||||
if (hContents)
|
||||
hDesc=GlobalAlloc(GMEM_MOVEABLE|GMEM_ZEROINIT,sizeof(FILEGROUPDESCRIPTOR));
|
||||
if (hDesc)
|
||||
{
|
||||
FILEGROUPDESCRIPTOR *desc=(FILEGROUPDESCRIPTOR*)GlobalLock(hDesc);
|
||||
desc->cItems=1;
|
||||
desc->fgd->dwFlags=FD_ATTRIBUTES|FD_FILESIZE|FD_LINKUI|FD_UNICODE;
|
||||
desc->fgd->dwFileAttributes=FILE_ATTRIBUTE_NORMAL;
|
||||
desc->fgd->nFileSizeLow=size;
|
||||
Strcpy(desc->fgd->cFileName,_countof(desc->fgd->cFileName),PathFindFileName(path));
|
||||
GlobalUnlock(hDesc);
|
||||
SetData(CMenuContainer::s_DescriptorFormat,hDesc);
|
||||
hDesc=NULL;
|
||||
|
||||
DWORD q;
|
||||
if (!ReadFile(file,GlobalLock(hContents),size,&q,NULL))
|
||||
q=0;
|
||||
GlobalUnlock(hContents);
|
||||
if (q==size)
|
||||
{
|
||||
SetData(CMenuContainer::s_ContentsFormat,hContents);
|
||||
hContents=NULL;
|
||||
m_bContents=true;
|
||||
}
|
||||
}
|
||||
if (hContents) GlobalFree(hContents);
|
||||
if (hDesc) GlobalFree(hDesc);
|
||||
}
|
||||
CloseHandle(file);
|
||||
}
|
||||
}
|
||||
|
||||
CMetroDataObject::~CMetroDataObject( void )
|
||||
{
|
||||
for (std::map<CLIPFORMAT,HGLOBAL>::iterator it=m_Data.begin();it!=m_Data.end();++it)
|
||||
if (it->second)
|
||||
GlobalFree(it->second);
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE CMetroDataObject::QueryInterface( REFIID riid, void **ppvObject )
|
||||
{
|
||||
if (riid==IID_IDataObject || riid==IID_IUnknown)
|
||||
{
|
||||
AddRef();
|
||||
*ppvObject=this;
|
||||
return S_OK;
|
||||
}
|
||||
*ppvObject=NULL;
|
||||
return E_NOINTERFACE;
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE CMetroDataObject::GetData( FORMATETC *pformatetcIn, STGMEDIUM *pmedium )
|
||||
{
|
||||
if (!pformatetcIn || !pmedium)
|
||||
return E_INVALIDARG;
|
||||
|
||||
pmedium->hGlobal=NULL;
|
||||
pmedium->pUnkForRelease=NULL;
|
||||
|
||||
if (pformatetcIn->dwAspect!=DVASPECT_CONTENT) return DV_E_DVASPECT;
|
||||
if (!(pformatetcIn->tymed&TYMED_HGLOBAL)) return DV_E_TYMED;
|
||||
|
||||
std::map<CLIPFORMAT,HGLOBAL>::iterator it=m_Data.find(pformatetcIn->cfFormat);
|
||||
if (it==m_Data.end()) return DV_E_FORMATETC;
|
||||
|
||||
wchar_t name[100];
|
||||
GetClipboardFormatName(pformatetcIn->cfFormat,name,100);
|
||||
Trace(L"GetData: %s, %d",name,pformatetcIn->cfFormat);
|
||||
|
||||
pmedium->tymed=TYMED_HGLOBAL;
|
||||
SIZE_T size=GlobalSize(it->second);
|
||||
pmedium->hGlobal=GlobalAlloc(GMEM_MOVEABLE,size);
|
||||
if (!pmedium->hGlobal) return E_OUTOFMEMORY;
|
||||
|
||||
void *src=GlobalLock(it->second);
|
||||
void *dst=GlobalLock(pmedium->hGlobal);
|
||||
memcpy(dst,src,size);
|
||||
GlobalUnlock(pmedium->hGlobal);
|
||||
GlobalUnlock(it->second);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
void CMetroDataObject::SetData( CLIPFORMAT format, HGLOBAL data )
|
||||
{
|
||||
Assert(m_Data.find(format)==m_Data.end());
|
||||
m_Data[format]=data;
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE CMetroDataObject::QueryGetData( FORMATETC *pformatetc )
|
||||
{
|
||||
if (!pformatetc) return E_INVALIDARG;
|
||||
if (pformatetc->dwAspect!=DVASPECT_CONTENT) return DV_E_DVASPECT;
|
||||
if (!(pformatetc->tymed&TYMED_HGLOBAL)) return DV_E_TYMED;
|
||||
if (m_Data.find(pformatetc->cfFormat)==m_Data.end()) return DV_E_CLIPFORMAT;
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE CMetroDataObject::GetCanonicalFormatEtc( FORMATETC *pformatectIn, FORMATETC *pformatetcOut )
|
||||
{
|
||||
return pformatetcOut?DATA_S_SAMEFORMATETC:E_INVALIDARG;
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE CMetroDataObject::EnumFormatEtc( DWORD dwDirection, IEnumFORMATETC **ppenumFormatEtc )
|
||||
{
|
||||
if (!ppenumFormatEtc) return E_POINTER;
|
||||
*ppenumFormatEtc=NULL;
|
||||
if (dwDirection == DATADIR_GET)
|
||||
{
|
||||
FORMATETC formats[] =
|
||||
{
|
||||
{CMenuContainer::s_MetroLinkFormat,NULL,DVASPECT_CONTENT,-1,TYMED_HGLOBAL},
|
||||
{CMenuContainer::s_DescriptorFormat,NULL,DVASPECT_CONTENT,-1,TYMED_HGLOBAL},
|
||||
{CMenuContainer::s_ContentsFormat,NULL,DVASPECT_CONTENT,-1,TYMED_HGLOBAL},
|
||||
};
|
||||
HRESULT hr = SHCreateStdEnumFmtEtc(m_bContents?3:1,formats,ppenumFormatEtc);
|
||||
return hr;
|
||||
}
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
CComPtr<IDataObject> CMenuContainer::CreateMetroDataObject( const CItemManager::ItemInfo *pInfo )
|
||||
{
|
||||
CString path;
|
||||
if (!pInfo->PATH.IsEmpty())
|
||||
{
|
||||
CItemManager::RWLock lock(&g_ItemManager,false,CItemManager::RWLOCK_ITEMS);
|
||||
path=pInfo->GetPath();
|
||||
}
|
||||
IDataObject *pDataObjectIn=new CMetroDataObject(path);
|
||||
CComPtr<IDataObject> pDataObject;
|
||||
SHCreateDataObject(NULL,0,NULL,pDataObjectIn,IID_IDataObject,(void**)&pDataObject);
|
||||
if (pDataObject)
|
||||
{
|
||||
if (m_pDragSourceHelper)
|
||||
{
|
||||
g_ItemManager.UpdateItemInfo(pInfo,CItemManager::INFO_EXTRA_LARGE_ICON|CItemManager::INFO_REFRESH_NOW,false);
|
||||
int iconSize=CItemManager::EXTRA_LARGE_ICON_SIZE;
|
||||
SHDRAGIMAGE di={{iconSize,iconSize},{iconSize/2,iconSize},NULL,CLR_NONE};
|
||||
di.hbmpDragImage=(HBITMAP)CopyImage(pInfo->extraLargeIcon->bitmap,IMAGE_BITMAP,0,0,0);
|
||||
m_pDragSourceHelper->SetFlags(DSH_ALLOWDROPDESCRIPTIONTEXT);
|
||||
if (di.hbmpDragImage)
|
||||
m_pDragSourceHelper->InitializeFromBitmap(&di,pDataObject);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
pDataObjectIn->Release();
|
||||
}
|
||||
return pDataObject;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool CMenuContainer::DragOutApps( const CItemManager::ItemInfo *pInfo )
|
||||
{
|
||||
// drag the Apps tree item for reordering
|
||||
CComPtr<IDataObject> pDataObj=CreateMetroDataObject(pInfo);
|
||||
|
||||
// do drag drop
|
||||
s_pDragSource=NULL;
|
||||
s_bDragFromTree=false;
|
||||
m_DragIndex=-1;
|
||||
s_bPreventClosing=true;
|
||||
m_DragTime=GetMessageTime();
|
||||
SetTimer(TIMER_DRAG,100);
|
||||
s_bDragClosed=false;
|
||||
DWORD dwEffect=DROPEFFECT_MOVE;
|
||||
HRESULT res=SHDoDragDrop(NULL,pDataObj,NULL,dwEffect,&dwEffect);
|
||||
|
||||
s_pDragSource=NULL;
|
||||
s_bDragFromTree=false;
|
||||
if (!m_bDestroyed)
|
||||
KillTimer(TIMER_DRAG);
|
||||
HideTemp(false);
|
||||
s_bPreventClosing=false;
|
||||
|
||||
if (s_bDragClosed)
|
||||
{
|
||||
for (std::vector<CMenuContainer*>::iterator it=s_Menus.begin();it!=s_Menus.end();++it)
|
||||
if (!(*it)->m_bDestroyed)
|
||||
(*it)->PostMessage(WM_CLOSE);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CMenuContainer::DragOut( int index, bool bApp )
|
||||
{
|
||||
if (!(m_Options&CONTAINER_DRAG) || s_bNoDragDrop) return false;
|
||||
const MenuItem &item=m_Items[index];
|
||||
if (!item.pItem1 || (item.id!=MENU_NO && item.id!=MENU_RECENT)) return false;
|
||||
|
||||
bool bLeft=(GetKeyState(VK_LBUTTON)<0);
|
||||
bool bRight=(GetKeyState(VK_RBUTTON)<0);
|
||||
if (!bLeft && !bRight) return false;
|
||||
|
||||
CComPtr<IShellFolder> pFolder;
|
||||
PCUITEMID_CHILD child;
|
||||
|
||||
// get IDataObject for the current item
|
||||
CComPtr<IDataObject> pDataObj;
|
||||
bool bProtectedLink=false;
|
||||
if (bApp && GetWinVersion()<WIN_VER_WIN10)
|
||||
pDataObj=CreateMetroDataObject(item.pItemInfo);
|
||||
else
|
||||
{
|
||||
bool bMetroLink=false;
|
||||
if (FAILED(SHBindToParent(item.pItem1,IID_IShellFolder,(void**)&pFolder,&child)))
|
||||
return true;
|
||||
if (FAILED(pFolder->GetUIObjectOf(NULL,1,&child,IID_IDataObject,NULL,(void**)&pDataObj)))
|
||||
return true;
|
||||
|
||||
{
|
||||
CItemManager::RWLock lock(&g_ItemManager,false,CItemManager::RWLOCK_ITEMS);
|
||||
bProtectedLink=!m_bSubMenu || item.pItemInfo->IsProtectedLink();
|
||||
bMetroLink=item.pItemInfo->IsMetroLink();
|
||||
}
|
||||
if (m_pDragSourceHelper && bMetroLink)
|
||||
{
|
||||
g_ItemManager.UpdateItemInfo(item.pItemInfo,CItemManager::INFO_EXTRA_LARGE_ICON|CItemManager::INFO_REFRESH_NOW,false);
|
||||
int iconSize=CItemManager::EXTRA_LARGE_ICON_SIZE;
|
||||
SHDRAGIMAGE di={{iconSize,iconSize},{iconSize/2,iconSize},NULL,CLR_NONE};
|
||||
di.hbmpDragImage=(HBITMAP)CopyImage(item.pItemInfo->extraLargeIcon->bitmap,IMAGE_BITMAP,0,0,0);
|
||||
m_pDragSourceHelper->SetFlags(DSH_ALLOWDROPDESCRIPTIONTEXT);
|
||||
if (di.hbmpDragImage)
|
||||
m_pDragSourceHelper->InitializeFromBitmap(&di,pDataObj);
|
||||
}
|
||||
}
|
||||
if (bProtectedLink)
|
||||
{
|
||||
// protected links default to DROPEFFECT_LINK
|
||||
HGLOBAL hGlobal=GlobalAlloc(GMEM_MOVEABLE,4);
|
||||
if (hGlobal)
|
||||
{
|
||||
*(DWORD*)GlobalLock(hGlobal)=DROPEFFECT_LINK;
|
||||
GlobalUnlock(hGlobal);
|
||||
FORMATETC format={s_PreferredEffectFormat,NULL,DVASPECT_CONTENT,-1,TYMED_HGLOBAL};
|
||||
STGMEDIUM medium={TYMED_HGLOBAL};
|
||||
medium.hGlobal=hGlobal;
|
||||
if (FAILED(pDataObj->SetData(&format,&medium,TRUE)))
|
||||
GlobalFree(hGlobal);
|
||||
}
|
||||
}
|
||||
|
||||
// force synchronous operation
|
||||
{
|
||||
CComQIPtr<IDataObjectAsyncCapability> pAsync=pDataObj;
|
||||
if (pAsync)
|
||||
pAsync->SetAsyncMode(FALSE);
|
||||
}
|
||||
|
||||
// do drag drop
|
||||
s_pDragSource=this;
|
||||
s_bDragFromTree=(index==m_ProgramTreeIndex);
|
||||
m_DragIndex=index;
|
||||
s_bDragMovable=(item.id==MENU_NO && index<m_OriginalCount) || (item.jumpIndex>=0 && s_JumpList.groups[LOWORD(item.jumpIndex)].type==CJumpGroup::TYPE_PINNED);
|
||||
|
||||
s_bPreventClosing=true;
|
||||
m_DragTime=GetMessageTime();
|
||||
s_bDragClosed=false;
|
||||
SetTimer(TIMER_DRAG,100);
|
||||
DWORD dwEffect=DROPEFFECT_COPY|DROPEFFECT_MOVE|DROPEFFECT_LINK;
|
||||
HRESULT res=SHDoDragDrop(NULL,pDataObj,NULL,dwEffect,&dwEffect);
|
||||
|
||||
s_pDragSource=NULL;
|
||||
s_bDragFromTree=false;
|
||||
if (!m_bDestroyed)
|
||||
KillTimer(TIMER_DRAG);
|
||||
s_bDragMovable=false;
|
||||
HideTemp(false);
|
||||
s_bPreventClosing=false;
|
||||
|
||||
if (s_bDragClosed)
|
||||
{
|
||||
for (std::vector<CMenuContainer*>::iterator it=s_Menus.begin();it!=s_Menus.end();++it)
|
||||
if (!(*it)->m_bDestroyed)
|
||||
(*it)->PostMessage(WM_CLOSE);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (pFolder && res==DRAGDROP_S_DROP && !m_bDestroyed)
|
||||
{
|
||||
// check if the item still exists. refresh the menu if it doesn't
|
||||
SFGAOF flags=SFGAO_VALIDATE;
|
||||
if (FAILED(pFolder->GetAttributesOf(1,&child,&flags)))
|
||||
{
|
||||
SetActiveWindow();
|
||||
// close all submenus
|
||||
for (int i=(int)s_Menus.size()-1;s_Menus[i]!=this;i--)
|
||||
if (!s_Menus[i]->m_bDestroyed)
|
||||
s_Menus[i]->DestroyWindow();
|
||||
// update menu
|
||||
PostRefreshMessage();
|
||||
}
|
||||
}
|
||||
|
||||
// activate the top non-destroyed menu
|
||||
for (int i=(int)s_Menus.size()-1;i>=0;i--)
|
||||
if (!s_Menus[i]->m_bDestroyed)
|
||||
{
|
||||
SetForegroundWindow(s_Menus[i]->m_hWnd);
|
||||
s_Menus[i]->SetActiveWindow();
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void CMenuContainer::SetDropTip( IDataObject *pDataObj, bool bPin )
|
||||
{
|
||||
DROPDESCRIPTION desc={bPin?DROPIMAGE_LINK:DROPIMAGE_INVALID};
|
||||
Strcpy(desc.szMessage,_countof(desc.szMessage),bPin?FindTranslation(L"Menu.PinStart",L"Pin to Start menu"):L"");
|
||||
HGLOBAL hDesc=GlobalAlloc(GMEM_MOVEABLE,sizeof(desc));
|
||||
if (hDesc)
|
||||
{
|
||||
memcpy(GlobalLock(hDesc),&desc,sizeof(desc));
|
||||
GlobalUnlock(hDesc);
|
||||
FORMATETC fmte={CMenuContainer::s_DropDescriptionFormat,NULL,DVASPECT_CONTENT,-1,TYMED_HGLOBAL};
|
||||
STGMEDIUM medium={};
|
||||
medium.tymed=TYMED_HGLOBAL;
|
||||
medium.hGlobal=hDesc;
|
||||
|
||||
if (FAILED(pDataObj->SetData(&fmte,&medium,TRUE)))
|
||||
{
|
||||
GlobalFree(hDesc);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CMenuContainer::GetDragEffect( DWORD &grfKeyState, DWORD *pdwEffect )
|
||||
{
|
||||
grfKeyState&=MK_SHIFT|MK_CONTROL|MK_ALT;
|
||||
if (s_bNoDragDrop || !(m_Options&CONTAINER_DROP))
|
||||
{
|
||||
*pdwEffect=DROPEFFECT_NONE; // can't drop here
|
||||
return;
|
||||
}
|
||||
if (!m_pDropFolder[0] && !(s_pDragSource==this && s_bDragMovable && !s_bDragFromTree))
|
||||
{
|
||||
*pdwEffect=DROPEFFECT_NONE; // can't drop here
|
||||
return;
|
||||
}
|
||||
|
||||
// only accept known data formats
|
||||
FORMATETC format1={s_ShellFormat,NULL,DVASPECT_CONTENT,-1,TYMED_HGLOBAL};
|
||||
FORMATETC format2={s_ShellUrlFormat,NULL,DVASPECT_CONTENT,-1,TYMED_HGLOBAL};
|
||||
FORMATETC format3={s_MetroLinkFormat,NULL,DVASPECT_CONTENT,-1,TYMED_HGLOBAL};
|
||||
if (m_pDragObject->QueryGetData(&format1)!=S_OK && m_pDragObject->QueryGetData(&format2)!=S_OK && m_pDragObject->QueryGetData(&format3)!=S_OK)
|
||||
{
|
||||
*pdwEffect=DROPEFFECT_NONE;
|
||||
return;
|
||||
}
|
||||
|
||||
if (s_pDragSource)
|
||||
{
|
||||
if (s_pDragSource->m_Items[s_pDragSource->m_DragIndex].id==MENU_RECENT)
|
||||
*pdwEffect&=DROPEFFECT_LINK; // dragging a recent item (allow only link)
|
||||
else if (grfKeyState==0 && !s_bRightDrag && s_pDragSource==this && s_bDragMovable && !s_bDragFromTree)
|
||||
*pdwEffect&=DROPEFFECT_MOVE; // dragging within the same menu - use move by default
|
||||
else if (grfKeyState==0 && !s_bRightDrag)
|
||||
*pdwEffect&=(s_bDragMovable && m_bSubMenu && (s_pDragSource->m_Options&CONTAINER_PROGRAMS))?DROPEFFECT_MOVE:DROPEFFECT_LINK; // dragging normal item to a different menu - default to move or link
|
||||
}
|
||||
|
||||
if (m_pDragObject->QueryGetData(&format3)==S_OK)
|
||||
{
|
||||
if (m_Options&CONTAINER_APPS)
|
||||
*pdwEffect&=(s_pDragSource==this && !s_bDragFromTree)?DROPEFFECT_MOVE:DROPEFFECT_NONE; // dragging a metro link to Apps folder
|
||||
else
|
||||
*pdwEffect&=DROPEFFECT_LINK; // dragging a metro link to another folder
|
||||
}
|
||||
|
||||
// handle keys
|
||||
if (!s_bRightDrag)
|
||||
{
|
||||
if (grfKeyState==MK_SHIFT)
|
||||
*pdwEffect&=DROPEFFECT_MOVE;
|
||||
if (grfKeyState==MK_CONTROL)
|
||||
*pdwEffect&=DROPEFFECT_COPY;
|
||||
if (grfKeyState==(MK_CONTROL|MK_SHIFT) || grfKeyState==MK_ALT)
|
||||
*pdwEffect&=DROPEFFECT_LINK;
|
||||
}
|
||||
else if (!m_bSubMenu && grfKeyState==0 && (*pdwEffect&DROPEFFECT_LINK))
|
||||
{
|
||||
// when a file is dragged to the start menu he usually wants to make a shortcut
|
||||
// so when right-dragging, and linking is allowed, make it the default
|
||||
grfKeyState=MK_SHIFT|MK_CONTROL;
|
||||
}
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE CMenuContainer::DragEnter( IDataObject *pDataObj, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect )
|
||||
{
|
||||
s_bRightDrag=(grfKeyState&MK_RBUTTON)!=0;
|
||||
m_pDragObject=pDataObj;
|
||||
if (m_pDropTargetHelper)
|
||||
{
|
||||
POINT p={pt.x,pt.y};
|
||||
m_pDropTargetHelper->DragEnter(m_hWnd,m_pDragObject,&p,*pdwEffect);
|
||||
}
|
||||
if (!m_bSubMenu && !s_bShowTopEmpty)
|
||||
{
|
||||
// when dragging over the main menu, show an (Empty) item at the top so the user can drop items there
|
||||
for (size_t i=0;i<m_Items.size();i++)
|
||||
if (m_Items[i].id==MENU_EMPTY_TOP)
|
||||
{
|
||||
s_bShowTopEmpty=true;
|
||||
if (m_ScrollHeight>0 && m_FolderHash[0])
|
||||
s_MenuScrolls[m_FolderHash[0]]=m_ScrollOffset;
|
||||
else
|
||||
s_MenuScrolls.erase(m_FolderHash[0]);
|
||||
InitWindow();
|
||||
break;
|
||||
}
|
||||
}
|
||||
m_DragHoverTime=GetMessageTime()-10000;
|
||||
m_DragHoverItem=-1;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE CMenuContainer::DragOver( DWORD grfKeyState, POINTL pt, DWORD *pdwEffect )
|
||||
{
|
||||
POINT p0={pt.x,pt.y};
|
||||
if (m_pDropTargetHelper)
|
||||
m_pDropTargetHelper->DragOver(&p0,*pdwEffect);
|
||||
|
||||
POINT p=p0;
|
||||
ScreenToClient(&p);
|
||||
int index=HitTest(p,NULL,true);
|
||||
|
||||
int mark=-1;
|
||||
bool bAfter=false;
|
||||
|
||||
const CItemManager::ItemInfo *pInfo=NULL;
|
||||
RECT rcItem;
|
||||
if (index>=0)
|
||||
{
|
||||
GetItemRect(index,rcItem);
|
||||
if (!m_bSubMenu && index<m_OriginalCount && (!s_pDragSource || s_bDragFromTree || s_bDragMovable || m_Items[index].id!=MENU_RECENT))
|
||||
{
|
||||
int h=(rcItem.bottom-rcItem.top)/4;
|
||||
if (m_Items[index].id!=MENU_NO || (p.y>=rcItem.top+h && p.y<rcItem.bottom-h))
|
||||
pInfo=m_Items[index].pItemInfo;
|
||||
}
|
||||
}
|
||||
int dropTargetIndex=pInfo?index:-1;
|
||||
if (m_pDropTargetInfo!=pInfo)
|
||||
{
|
||||
if (m_pDropTarget)
|
||||
{
|
||||
m_pDropTarget->DragLeave();
|
||||
m_pDropTarget=NULL;
|
||||
}
|
||||
if (pInfo && pInfo->GetPidl())
|
||||
{
|
||||
m_pDropTargetInfo=pInfo;
|
||||
CComPtr<IShellItem> pItem;
|
||||
SHCreateItemFromIDList(pInfo->GetPidl(),IID_IShellItem,(void**)&pItem);
|
||||
if (pItem)
|
||||
{
|
||||
pItem->BindToHandler(NULL,BHID_SFUIObject,IID_IDropTarget,(void**)&m_pDropTarget);
|
||||
if (m_pDropTarget)
|
||||
{
|
||||
m_pDropTarget->DragEnter(m_pDragObject,grfKeyState,pt,pdwEffect);
|
||||
if (*pdwEffect==0)
|
||||
m_pDropTargetInfo=NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
m_pDropTargetInfo=NULL;
|
||||
}
|
||||
if (!m_pDropTargetInfo)
|
||||
{
|
||||
dropTargetIndex=-1;
|
||||
m_pDropTarget=NULL;
|
||||
}
|
||||
if (dropTargetIndex!=m_DropTargetIndex)
|
||||
{
|
||||
InvalidateItem(dropTargetIndex);
|
||||
InvalidateItem(m_DropTargetIndex);
|
||||
m_DropTargetIndex=dropTargetIndex;
|
||||
}
|
||||
if (m_pDropTarget)
|
||||
{
|
||||
SetDropTip(m_pDragObject,false);
|
||||
SetInsertMark(-1,false);
|
||||
return m_pDropTarget->DragOver(grfKeyState,pt,pdwEffect);
|
||||
}
|
||||
|
||||
s_bRightDrag=(grfKeyState&MK_RBUTTON)!=0;
|
||||
GetDragEffect(grfKeyState,pdwEffect);
|
||||
|
||||
if (index>=0 && index<m_OriginalCount && m_Items[index].id!=MENU_RECENT)
|
||||
{
|
||||
// set the new insert mark
|
||||
mark=index;
|
||||
int y=(rcItem.top+rcItem.bottom)/2;
|
||||
if (p.y<y)
|
||||
{
|
||||
// insert above
|
||||
if (m_Items[index].id!=MENU_NO && m_Items[index].id!=MENU_EMPTY && m_Items[index].id!=MENU_EMPTY_TOP && (index==0 || m_Items[index-1].id!=MENU_NO))
|
||||
mark=-1;
|
||||
}
|
||||
else
|
||||
{
|
||||
// insert below
|
||||
bAfter=true;
|
||||
if (m_Items[index].id!=MENU_NO && m_Items[index].id!=MENU_EMPTY && m_Items[index].id!=MENU_EMPTY_TOP && (index==m_Items.size()-1 || m_Items[index+1].id!=MENU_NO))
|
||||
mark=-1;
|
||||
}
|
||||
if (mark==-1 && m_Items[index].bFolder && (m_Items[index].bPrograms || m_Items[index].id==MENU_NO))
|
||||
{
|
||||
SetHotItem(index);
|
||||
}
|
||||
else
|
||||
{
|
||||
SetHotItem(-1);
|
||||
}
|
||||
if (!*pdwEffect || ((m_Options&CONTAINER_AUTOSORT) && s_pDragSource==this && !s_bDragFromTree && s_bDragMovable))
|
||||
mark=-1;
|
||||
}
|
||||
else if (s_pDragSource==this && !s_bDragFromTree && s_bDragMovable && m_Items[m_DragIndex].jumpIndex>=0 && index>=0 && m_Items[index].jumpIndex>=0)
|
||||
{
|
||||
int groupIndex=LOWORD(m_Items[m_DragIndex].jumpIndex);
|
||||
if (s_JumpList.groups[groupIndex].type==CJumpGroup::TYPE_PINNED && LOWORD(m_Items[index].jumpIndex)==groupIndex && (*pdwEffect&DROPEFFECT_MOVE))
|
||||
{
|
||||
// reorder jump list
|
||||
*pdwEffect=DROPEFFECT_MOVE;
|
||||
int y=(rcItem.top+rcItem.bottom)/2;
|
||||
bAfter=p.y>=y;
|
||||
SetHotItem(-1);
|
||||
}
|
||||
else
|
||||
index=-1;
|
||||
mark=index;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!m_bSubMenu && index<m_OriginalCount && PtInRect(&m_rContent,p) && (s_pDragSource!=this || s_bDragFromTree || !s_bDragMovable || m_Items[m_DragIndex].id==MENU_RECENT))
|
||||
{
|
||||
if (s_bWin7Style)
|
||||
{
|
||||
for (int i=0;i<m_ScrollCount;i++)
|
||||
{
|
||||
if (m_Items[i].id==MENU_NO || m_Items[i].id==MENU_EMPTY || m_Items[i].id==MENU_EMPTY_TOP)
|
||||
mark=i;
|
||||
}
|
||||
}
|
||||
else
|
||||
mark=m_ScrollCount-1;
|
||||
bAfter=true;
|
||||
}
|
||||
index=-1;
|
||||
}
|
||||
SetInsertMark(mark,bAfter);
|
||||
UpdateScroll(&p,false);
|
||||
|
||||
// check if the hover delay is done and it's time to open the item
|
||||
if (index>=0 && index==m_DragHoverItem)
|
||||
{
|
||||
int hoverTime=(int)s_HoverTime;
|
||||
if (m_Items[index].id==MENU_PROGRAMS && GetSettingInt(L"ProgramsStyle")==PROGRAMS_INLINE)
|
||||
hoverTime=(int)s_ProgramsHoverTime;
|
||||
if ((GetMessageTime()-m_DragHoverTime)>hoverTime && m_Submenu!=m_DragHoverItem)
|
||||
{
|
||||
// expand m_DragHoverItem
|
||||
if (index<m_OriginalCount && !m_Items[index].bHasJumpList && (!m_Items[index].bFolder || m_Items[index].pItem1))
|
||||
{
|
||||
ActivateData data;
|
||||
data.bNoModifiers=GetKeyState(VK_SHIFT)<0;
|
||||
ActivateItem(index,ACTIVATE_OPEN,NULL,&data);
|
||||
}
|
||||
if (!m_Items[index].bFolder)
|
||||
SetHotItem(-1);
|
||||
m_DragHoverTime=GetMessageTime();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
m_DragHoverItem=index;
|
||||
m_DragHoverTime=GetMessageTime();
|
||||
}
|
||||
|
||||
if (m_InsertMark<0)
|
||||
*pdwEffect=0;
|
||||
|
||||
int before=m_InsertMark;
|
||||
if (before>=0 && m_bInsertAfter && (before!=0 || (m_Items[0].id!=MENU_EMPTY && m_Items[0].id!=MENU_EMPTY_TOP)))
|
||||
before++;
|
||||
if (before>=0 && !m_bSubMenu && (*pdwEffect&DROPEFFECT_LINK) && (s_pDragSource!=this || s_bDragFromTree || !s_bDragMovable))
|
||||
{
|
||||
*pdwEffect=DROPEFFECT_LINK;
|
||||
SetDropTip(m_pDragObject,true);
|
||||
}
|
||||
else
|
||||
SetDropTip(m_pDragObject,false);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE CMenuContainer::DragLeave( void )
|
||||
{
|
||||
if (m_pDropTarget)
|
||||
{
|
||||
m_pDropTarget->DragLeave();
|
||||
m_pDropTarget=NULL;
|
||||
}
|
||||
InvalidateItem(m_DropTargetIndex);
|
||||
m_DropTargetIndex=-1;
|
||||
m_pDropTargetInfo=NULL;
|
||||
if (m_pDropTargetHelper)
|
||||
m_pDropTargetHelper->DragLeave();
|
||||
SetDropTip(m_pDragObject,false);
|
||||
SetInsertMark(-1,false);
|
||||
m_pDragObject=NULL;
|
||||
UpdateScroll(NULL,false);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE CMenuContainer::Drop( IDataObject *pDataObj, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect )
|
||||
{
|
||||
if (s_pDragSource)
|
||||
{
|
||||
if (!s_pDragSource->m_bDestroyed)
|
||||
s_pDragSource->KillTimer(TIMER_DRAG);
|
||||
}
|
||||
if (m_pDropTargetHelper)
|
||||
{
|
||||
POINT p={pt.x,pt.y};
|
||||
m_pDropTargetHelper->Drop(pDataObj,&p,*pdwEffect);
|
||||
}
|
||||
if (m_pDropTarget)
|
||||
{
|
||||
m_pDragObject=NULL;
|
||||
HRESULT res=m_pDropTarget->Drop(pDataObj,grfKeyState,pt,pdwEffect);
|
||||
m_pDropTarget=NULL;
|
||||
return res;
|
||||
}
|
||||
|
||||
GetDragEffect(grfKeyState,pdwEffect);
|
||||
m_pDragObject=NULL;
|
||||
|
||||
int before=m_InsertMark;
|
||||
if (before<0) return S_OK;
|
||||
if (before>=0 && m_bInsertAfter && (before!=0 || (m_Items[0].id!=MENU_EMPTY && m_Items[0].id!=MENU_EMPTY_TOP)))
|
||||
before++;
|
||||
|
||||
// clear the insert mark
|
||||
SetInsertMark(-1,false);
|
||||
|
||||
int folderIndex=0;
|
||||
if (before>=0)
|
||||
folderIndex=m_Items[min(before,(int)m_Items.size()-1)].priority>1?1:0;
|
||||
|
||||
if (s_pDragSource==this && !s_bDragFromTree && s_bDragMovable && (*pdwEffect&DROPEFFECT_MOVE) && m_DragIndex!=m_ProgramTreeIndex && m_Items[m_DragIndex].priority==(m_Items[min(before,(int)m_Items.size()-1)].priority&2))
|
||||
{
|
||||
if (before==m_DragIndex || before==m_DragIndex+1)
|
||||
return S_OK;
|
||||
// dropped in the same menu, just rearrange the items
|
||||
PlayMenuSound(SOUND_DROP);
|
||||
if (m_Items[m_DragIndex].jumpIndex>=0 && s_JumpList.groups[LOWORD(m_Items[m_DragIndex].jumpIndex)].type==CJumpGroup::TYPE_PINNED)
|
||||
{
|
||||
// reordering pinned item
|
||||
int groupIdx=LOWORD(m_Items[m_DragIndex].jumpIndex);
|
||||
int itemIdx=HIWORD(m_Items[m_DragIndex].jumpIndex);
|
||||
for (int i=0;i<=m_DragIndex;i++)
|
||||
{
|
||||
if (m_Items[i].jumpIndex>=0 && LOWORD(m_Items[i].jumpIndex)==groupIdx)
|
||||
{
|
||||
// found first pinned index
|
||||
PinJumpItem(s_JumpAppInfo,s_JumpList,groupIdx,itemIdx,true,before-i);
|
||||
PostRefreshMessage();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (!(m_Options&CONTAINER_AUTOSORT))
|
||||
{
|
||||
std::vector<SortMenuItem> items;
|
||||
int skip1=0, skip2=0;
|
||||
for (int i=0;i<m_OriginalCount;i++)
|
||||
{
|
||||
if (m_Items[i].id==MENU_NO)
|
||||
{
|
||||
SortMenuItem item(m_Items[i]);
|
||||
items.push_back(item);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (i<m_DragIndex) skip1++;
|
||||
if (i<before) skip2++;
|
||||
}
|
||||
}
|
||||
SortMenuItem drag=items[m_DragIndex-skip1];
|
||||
items.erase(items.begin()+(m_DragIndex-skip1));
|
||||
if (before-skip2>m_DragIndex-skip1)
|
||||
before--;
|
||||
items.insert(items.begin()+(before-skip2),drag);
|
||||
SaveItemOrder(items);
|
||||
if (m_bTwoColumns && s_MenuMode==MODE_JUMPLIST)
|
||||
SetMenuMode(MODE_NORMAL);
|
||||
PostRefreshMessage();
|
||||
}
|
||||
}
|
||||
else if (m_pDropFolder[folderIndex])
|
||||
{
|
||||
// simulate dropping the object into the original folder
|
||||
PlayMenuSound(SOUND_DROP);
|
||||
|
||||
if (before>=0 && !m_bSubMenu && (*pdwEffect&DROPEFFECT_LINK) && (s_pDragSource!=this || s_bDragFromTree || !s_bDragMovable))
|
||||
*pdwEffect=DROPEFFECT_LINK;
|
||||
|
||||
bool bDropped=false;
|
||||
if (!m_bSubMenu && (*pdwEffect&DROPEFFECT_LINK) && !s_bRightDrag)
|
||||
{
|
||||
// if dropping a single folder onto the main menu, create a fake folder
|
||||
CComPtr<IShellItemArray> pArray;
|
||||
if (SUCCEEDED(SHCreateShellItemArrayFromDataObject(pDataObj,IID_IShellItemArray,(void**)&pArray)))
|
||||
{
|
||||
DWORD count;
|
||||
CComPtr<IShellItem> pItem;
|
||||
if (SUCCEEDED(pArray->GetCount(&count)) && count==1 && SUCCEEDED(pArray->GetItemAt(0,&pItem)))
|
||||
{
|
||||
CComString pPath;
|
||||
if (pItem->GetDisplayName(SIGDN_FILESYSPATH,&pPath)==S_OK && PathIsDirectory(pPath))
|
||||
{
|
||||
wchar_t path[_MAX_PATH];
|
||||
if (SUCCEEDED(SHGetPathFromIDList(m_Path1[0],path)))
|
||||
{
|
||||
wchar_t fname[_MAX_FNAME];
|
||||
Strcpy(fname,_countof(fname),PathFindFileName(pPath));
|
||||
int len=Strlen(fname);
|
||||
while (len>0 && (fname[len-1]=='\\' || fname[len-1]==':'))
|
||||
len--;
|
||||
fname[len]=0;
|
||||
PathAppend(path,fname);
|
||||
wchar_t finalPath[_MAX_PATH];
|
||||
PathYetAnotherMakeUniqueName(finalPath,path,NULL,PathFindFileName(path));
|
||||
if (CreateFakeFolder(pPath,finalPath))
|
||||
{
|
||||
bDropped=true;
|
||||
wchar_t locName[_MAX_PATH];
|
||||
int locIndex;
|
||||
if (SHGetLocalizedName(pPath,locName,_countof(locName),&locIndex)==S_OK)
|
||||
{
|
||||
SHSetLocalizedName(finalPath,locName,locIndex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!bDropped)
|
||||
{
|
||||
// must use IShellFolder to get to the drop target because the BindToHandler doesn't support passing the parent window (easily)
|
||||
CComPtr<IShellFolder> pDesktop;
|
||||
SHGetDesktopFolder(&pDesktop);
|
||||
CComPtr<IShellFolder> pFolder;
|
||||
CComPtr<IDropTarget> pTarget;
|
||||
if (!pDesktop || FAILED(pDesktop->BindToObject(m_Path1[folderIndex],NULL,IID_IShellFolder,(void**)&pFolder)) || FAILED(pFolder->CreateViewObject(g_OwnerWindow,IID_IDropTarget,(void**)&pTarget)))
|
||||
return S_OK;
|
||||
|
||||
DWORD dwEffect=*pdwEffect;
|
||||
|
||||
if (s_bRightDrag)
|
||||
{
|
||||
if (FAILED(pTarget->DragEnter(pDataObj,MK_RBUTTON|grfKeyState,pt,&dwEffect)))
|
||||
return S_OK;
|
||||
dwEffect=*pdwEffect;
|
||||
pTarget->DragOver(MK_RBUTTON|grfKeyState,pt,&dwEffect);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (FAILED(pTarget->DragEnter(pDataObj,MK_LBUTTON|grfKeyState,pt,&dwEffect)))
|
||||
return S_OK;
|
||||
dwEffect=*pdwEffect;
|
||||
pTarget->DragOver(MK_LBUTTON|grfKeyState,pt,pdwEffect);
|
||||
}
|
||||
CComQIPtr<IDataObjectAsyncCapability> pAsync=pDataObj;
|
||||
if (pAsync)
|
||||
pAsync->SetAsyncMode(FALSE);
|
||||
for (std::vector<CMenuContainer*>::iterator it=s_Menus.begin();it!=s_Menus.end();++it)
|
||||
if (!(*it)->m_bDestroyed)
|
||||
(*it)->EnableWindow(FALSE); // disable all menus
|
||||
bool bAllPrograms=s_bAllPrograms;
|
||||
if (bAllPrograms) ::EnableWindow(g_TopWin7Menu,FALSE);
|
||||
bool bOld=s_bPreventClosing;
|
||||
s_bPreventClosing=true;
|
||||
AddRef();
|
||||
pTarget->Drop(pDataObj,grfKeyState,pt,pdwEffect);
|
||||
if (!bOld)
|
||||
HideTemp(false);
|
||||
s_bPreventClosing=bOld;
|
||||
for (std::vector<CMenuContainer*>::iterator it=s_Menus.begin();it!=s_Menus.end();++it)
|
||||
if (!(*it)->m_bDestroyed)
|
||||
(*it)->EnableWindow(TRUE); // enable all menus
|
||||
if (bAllPrograms) ::EnableWindow(g_TopWin7Menu,TRUE);
|
||||
}
|
||||
else
|
||||
{
|
||||
AddRef();
|
||||
}
|
||||
|
||||
if (!m_bDestroyed)
|
||||
{
|
||||
SetForegroundWindow(m_hWnd);
|
||||
SetActiveWindow();
|
||||
SetFocus();
|
||||
}
|
||||
|
||||
if (before>=0 && !(m_Options&CONTAINER_AUTOSORT))
|
||||
{
|
||||
std::vector<SortMenuItem> items;
|
||||
int skip=0;
|
||||
for (int i=0;i<m_OriginalCount;i++)
|
||||
{
|
||||
if (m_Items[i].id==MENU_NO)
|
||||
{
|
||||
SortMenuItem item(m_Items[i]);
|
||||
items.push_back(item);
|
||||
}
|
||||
else if (i<before)
|
||||
skip++;
|
||||
}
|
||||
SortMenuItem ins(L"",FNV_HASH0,false,false,folderIndex*2,0);
|
||||
items.insert(items.begin()+(before-skip),ins);
|
||||
SaveItemOrder(items);
|
||||
}
|
||||
if (m_bTwoColumns && s_MenuMode==MODE_JUMPLIST)
|
||||
SetMenuMode(MODE_NORMAL);
|
||||
PostRefreshMessage();
|
||||
Release();
|
||||
}
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
HRESULT STDMETHODCALLTYPE CDropTargetProxy::DragEnter( IDataObject *pDataObj, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect )
|
||||
{
|
||||
if (!m_pOwner) return E_FAIL;
|
||||
return m_pOwner->DragEnter(pDataObj,grfKeyState,pt,pdwEffect);
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE CDropTargetProxy::DragOver( DWORD grfKeyState, POINTL pt, DWORD *pdwEffect )
|
||||
{
|
||||
if (!m_pOwner) return E_FAIL;
|
||||
return m_pOwner->DragOver(grfKeyState,pt,pdwEffect);
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE CDropTargetProxy::DragLeave( void )
|
||||
{
|
||||
if (!m_pOwner) return E_FAIL;
|
||||
return m_pOwner->DragLeave();
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE CDropTargetProxy::Drop( IDataObject *pDataObj, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect )
|
||||
{
|
||||
if (!m_pOwner) return E_FAIL;
|
||||
return m_pOwner->Drop(pDataObj,grfKeyState,pt,pdwEffect);
|
||||
}
|
||||
Reference in New Issue
Block a user