#include "stdafx.h" #ifdef FEATURE_STARTPAGE #include "pidlbutton.h" #include namespace DirectUI { int PIDLButton::s_nImageSize = 0; // Construction / Destruction // PIDLButton::~PIDLButton() { ILFree(_pidl); } HRESULT PIDLButton::Create(LPITEMIDLIST pidl, UINT nActive, OUT Element** ppElement) { *ppElement = NULL; PIDLButton* pb = HNew (); if (!pb) return E_OUTOFMEMORY; HRESULT hr = pb->Initialize(pidl, nActive); if (FAILED(hr)) { pb->Destroy(); return hr; } *ppElement = pb; return S_OK; } HIMAGELIST GetSysImageList(UINT flags) { static HIMAGELIST s_imgList; static HIMAGELIST s_imgListSmall; if (!s_imgList) { Shell_GetImageLists(&s_imgList, &s_imgListSmall); } return (flags & SHGFI_SMALLICON) ? s_imgListSmall : s_imgList; } HRESULT PIDLButton::Initialize(LPITEMIDLIST pidl, UINT nActive) { _pidl = pidl; Layout* pbl = NULL; Element* peLabel = NULL; Element* peImage = NULL; Value* pvChildren; ElementList* pel; HRESULT hr = Button::Initialize(nActive); if (FAILED(hr)) goto CleanUp; // Create children hr = Element::Create(0, &peLabel); if (FAILED(hr)) goto CleanUp; hr = Element::Create(0, &peImage); if (FAILED(hr)) goto CleanUp; // Create layout hr = BorderLayout::Create(&pbl); if (FAILED(hr)) goto CleanUp; // Initialize SetLayout(pbl); // Setup children peImage->SetLayoutPos(BLP_Left); peImage->SetID(L"Image"); peLabel->SetLayoutPos(BLP_Client); peLabel->SetID(L"Label"); Add(peImage); Add(peLabel); pel = GetChildren(&pvChildren); // Initialize Shell's ImageList GetSysImageList(0); if (_pidl && pel && (pel->GetSize() >= 2)) { IShellFolder *psf; LPCITEMIDLIST pidlItem; if (SUCCEEDED(SHBindToFolderIDListParent(NULL, _pidl, IID_PPV_ARG(IShellFolder, &psf), &pidlItem))) { int iSysIndex = SHMapPIDLToSystemImageListIndex(psf, pidlItem, NULL); if (iSysIndex != -1) { HICON hi = ImageList_GetIcon(GetSysImageList(s_nImageSize), iSysIndex, 0); Value *pvalIcon = Value::CreateGraphic(hi); if (pvalIcon) { pel->GetItem(0)->SetValue(ContentProp, PI_Local, pvalIcon); pvalIcon->Release(); } else { DestroyIcon(hi); } } TCHAR szOut[MAX_PATH]; if (SUCCEEDED(DisplayNameOf(psf, pidlItem, SHGDN_NORMAL, szOut, ARRAYSIZE(szOut)))) { pel->GetItem(1)->SetContentString(szOut); } psf->Release(); } } pvChildren->Release(); return hr; CleanUp: if (pbl) pbl->Destroy(); if (peImage) peImage->Destroy(); if (peLabel) peLabel->Destroy(); return hr; } HRESULT PIDLButton::InvokePidl() { HRESULT hr = E_FAIL; IShellFolder *psf; LPCITEMIDLIST pidlShort; // Multi-level child pidl if (SUCCEEDED(SHBindToFolderIDListParent(NULL, _pidl, IID_PPV_ARG(IShellFolder, &psf), &pidlShort))) { hr = SHInvokeDefaultCommand(GetHWND(), psf, pidlShort); psf->Release(); } return hr; } HRESULT PIDLButton::OnContextMenu(POINT *ppt) { HRESULT hr = E_FAIL; IShellFolder *psf; LPCITEMIDLIST pidlShort; if (!GetHWND()) return hr; if (ppt->x == -1) // Keyboard context menu { Value *pv; const SIZE *psize = GetExtent(&pv); ppt->x = psize->cx/2; ppt->y = psize->cy/2; pv->Release(); } POINT pt; GetRoot()->MapElementPoint(this, ppt, &pt); ClientToScreen(GetHWND(), &pt); // Multi-level child pidl if (SUCCEEDED(SHBindToFolderIDListParent(NULL, _pidl, IID_PPV_ARG(IShellFolder, &psf), &pidlShort))) { IContextMenu *pcm; if (SUCCEEDED(hr = psf->GetUIObjectOf(GetHWND(), 1, &pidlShort, IID_IContextMenu, NULL, (void **)&pcm))) { HMENU hmenu = ::CreatePopupMenu(); if (hmenu) { UINT uFlags = CMF_NORMAL; if (GetKeyState(VK_SHIFT) < 0) { uFlags |= CMF_EXTENDEDVERBS; } #if 0 // REVIEW fabriced if (_dwFlags & HOSTF_CANRENAME) { uFlags |= CMF_CANRENAME; } #endif pcm->QueryContextMenu(hmenu, 0, IDM_QCM_MIN, IDM_QCM_MAX, uFlags); // Remove "Create shortcut" from context menu because it creates // the shortcut on the desktop, which the user can't see... ContextMenu_DeleteCommandByName(pcm, hmenu, IDM_QCM_MIN, TEXT("link")); // Remove "Cut" from context menu because we don't want objects // to be deleted. ContextMenu_DeleteCommandByName(pcm, hmenu, IDM_QCM_MIN, TEXT("cut")); // Change "Delete" to "Remove from this list". // If client doesn't support "delete" then nuke it outright. ContextMenu_DeleteCommandByName(pcm, hmenu, IDM_QCM_MIN, TEXT("delete")); #if 0 // REVIEW fabriced if (_dwFlags & HOSTF_CANDELETE) { if (LoadString(_Module.GetResourceInstance(), IDS_SFTHOST_REMOVEFROMLIST, szBuf, ARRAYSIZE(szBuf))) { ModifyMenu(hmenu, iposDelete, MF_BYPOSITION | MF_STRING, GetMenuItemID(hmenu, iposDelete), szBuf); } } else #endif _SHPrettyMenu(hmenu); ASSERT(_pcm2Pop == NULL); // Shouldn't be recursing pcm->QueryInterface(IID_PPV_ARG(IContextMenu2, &_pcm2Pop)); ASSERT(_pcm3Pop == NULL); // Shouldn't be recursing pcm->QueryInterface(IID_PPV_ARG(IContextMenu3, &_pcm3Pop)); GetHWNDHost()->WndProc(GetHWND(), PBM_SETMENUFORWARD, 0, (LPARAM)this); int idCmd = TrackPopupMenuEx(hmenu, TPM_RETURNCMD | TPM_RIGHTBUTTON | TPM_LEFTALIGN, pt.x, pt.y, GetHWND(), NULL); if (idCmd >= IDM_QCM_MIN && idCmd < IDM_QCM_MAX) { idCmd -= IDM_QCM_MIN; CMINVOKECOMMANDINFOEX ici = { sizeof(ici), // cbSize CMIC_MASK_ASYNCOK, // fMask GetHWND(), // hwnd (LPCSTR)IntToPtr(idCmd),// lpVerb NULL, // lpParameters NULL, // lpDirectory SW_SHOWDEFAULT, // nShow 0, // dwHotKey 0, // hIcon NULL, // lpTitle (LPCWSTR)IntToPtr(idCmd),// lpVerbW NULL, // lpParametersW NULL, // lpDirectoryW NULL, // lpTitleW { pt.x, pt.y }, // ptInvoke }; #if 0 // REVIEW fabriced if (_dwFlags & (HOSTF_CANDELETE | HOSTF_CANRENAME)) { ContextMenu_GetCommandStringVerb(pcm, idCmd, szBuf, ARRAYSIZE(szBuf)); } if ((_dwFlags & HOSTF_CANDELETE) && StrCmpI(szBuf, TEXT("delete")) == 0) { ContextMenuDeleteItem(pitem, pcm, &ici); SMNMCOMMANDINVOKED ci; ListView_GetItemRect(_hwndList, iItem, &ci.rcItem, LVIR_BOUNDS); MapWindowRect(_hwndList, NULL, &ci.rcItem); _SendNotify(_hwnd, SMN_COMMANDINVOKED, &ci); } else if ((_dwFlags & HOSTF_CANRENAME) && StrCmpI(szBuf, TEXT("rename")) == 0) { ListView_EditLabel(_hwndList, iItem); } else #endif { pcm->InvokeCommand(reinterpret_cast(&ici)); } } DestroyMenu(hmenu); GetHWNDHost()->WndProc(GetHWND(), PBM_SETMENUFORWARD, 0, (LPARAM)NULL); ATOMICRELEASE(_pcm2Pop); ATOMICRELEASE(_pcm3Pop); } pcm->Release(); } psf->Release(); } return hr; } LRESULT PIDLButton::OnMenuMessage(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { LRESULT lres; if (_pcm3Pop && SUCCEEDED(_pcm3Pop->HandleMenuMsg2(uMsg, wParam, lParam, &lres))) { return lres; } if (_pcm2Pop && SUCCEEDED(_pcm2Pop->HandleMenuMsg(uMsg, wParam, lParam))) { return 0; } return 0; } //////////////////////////////////////////////////////// // System events void PIDLButton::OnPropertyChanged(PropertyInfo* ppi, int iIndex, Value* pvOld, Value* pvNew) { // Do default processing Button::OnPropertyChanged(ppi, iIndex, pvOld, pvNew); } // Pointer is only guaranteed good for the lifetime of the call void PIDLButton::OnEvent(Event *pEvent) { if ((pEvent->peTarget == this) && (pEvent->uidType == Button::Click)) { // execute pidl InvokePidl(); pEvent->fHandled = true; return; } else if ((pEvent->peTarget == this) && (pEvent->uidType == Button::Context)) { ButtonContextEvent *peButton = reinterpret_cast(pEvent); OnContextMenu(&peButton->pt); return; } Button::OnEvent(pEvent); } void PIDLButton::OnInput(InputEvent* pie) { // Fabrice, I will be putting right button click support for context menu here -- I'll have it for you Monday Button::OnInput(pie); } //////////////////////////////////////////////////////// // Property definitions /** Property template (replace !!!), also update private PropertyInfo* parray and class header (element.h) // !!! property static int vv!!![] = { DUIV_INT, -1 }; StaticValue(svDefault!!!, DUIV_INT, 0); static PropertyInfo imp!!!Prop = { L"!!!", PF_Normal, 0, vv!!!, (Value*)&svDefault!!! }; PropertyInfo* Element::!!!Prop = &imp!!!Prop; **/ //////////////////////////////////////////////////////// // ClassInfo (must appear after property definitions) // Class properties // Define class info with type and base type, set static class pointer IClassInfo* PIDLButton::Class = NULL; HRESULT PIDLButton::Register() { return ClassInfo::Register(L"PIDLButton", NULL, 0); } } // namespace DirectUI #endif // FEATURE_STARTPAGE