www.pudn.com > PropBrowser_demo.zip > PropertyBrowserPage.cpp
// PropertyBrowserPage.cpp: implementation of the CPropertyBrowserPage class. // ////////////////////////////////////////////////////////////////////// #include "stdafx.h" #include#include "PropertyBrowserPage.h" #include "PBDib.h" #ifdef _DEBUG #undef THIS_FILE static char THIS_FILE[]=__FILE__; #define new DEBUG_NEW #endif /* Property Browser Page v1.0 Template class that provides automatic property page for ATL-based ActiveX Controls Copyrights, (c) 1999 Vladimir Scherbakov (rise@alt.ru) */ ////////////////////////////////////////////////////////////////////// // Construction/Destruction ////////////////////////////////////////////////////////////////////// BOOL CPBProperty::SetNewText(BSTR bstrNewText) { _ASSERT(m_vt != VT_NULL); CComVariant v_text,v_value; if(bstrNewText && m_bstrText.m_str) if(wcscmp(bstrNewText,m_bstrText.m_str) == 0) return TRUE; if(bstrNewText) for(ULONG i = 0;i < m_castr.cElems;i++) if(wcscmp(m_castr.pElems[i],bstrNewText) == 0) { m_value = m_pvPredefinedValues[i]; m_bstrText = bstrNewText; m_bDirty = TRUE; return TRUE; } v_text = bstrNewText; if(VariantChangeType(&v_value,&v_text,0,m_vt) != S_OK) return FALSE; if(!m_bstrText.m_str && ::SysStringLen(bstrNewText) == 0) return TRUE; m_bstrText = bstrNewText; m_bDirty = TRUE; m_value = v_value; for(ULONG i = 0;i < m_castr.cElems;i++) { CComVariant v(m_pvPredefinedValues[i]); if(v == m_value) { m_bstrText = m_castr.pElems[i]; return TRUE; } } return TRUE; } BOOL CPBProperty::SetNewValue(VARIANT * pVar) { CComVariant v_text;ULONG i=0; HRESULT hr; m_value = *pVar; m_vt = pVar->vt; switch(m_DisplayType) { case PBT_STR: for(i = 0;i < m_castr.cElems;i++) { CComVariant v(m_pvPredefinedValues[i]); if(v == m_value) { m_bstrText = m_castr.pElems[i]; return TRUE; } } if(VariantChangeType(&v_text,pVar,0,VT_BSTR) != S_OK) { ATLTRACE(_T("[CPBProperty::SetNewValue] - failed to convert to text\n")); } else m_bstrText = V_BSTR(&v_text); break; case PBT_FONT: { CComDispatchDriver dd; if(pVar->vt == VT_DISPATCH) dd = pVar->pdispVal; else if(pVar->vt == (VT_DISPATCH | VT_BYREF)) dd = *(pVar->ppdispVal); else { // no ideas where is this font _ASSERT(FALSE); return FALSE; } if(!dd) { m_bstrText = L"(None)"; return TRUE; } CComVariant v; hr = dd.GetProperty(DISPID_FONT_NAME,&v); if(SUCCEEDED(hr)) { m_bstrText = V_BSTR(&v); } else { _ASSERT(FALSE); return FALSE; } } break; case PBT_COLOR: { _ASSERT(V_VT(pVar) == VT_UI4 || V_VT(pVar) == VT_I4 ); TCHAR szText[32]; _stprintf(szText,_T("&H%08X&"),pVar->lVal); m_bstrText = szText; } break; case PBT_ENUM: { for(i = 0;i < m_castr.cElems;i++) { CComVariant v(m_pvPredefinedValues[i]); if(v == m_value) { m_bstrText = m_castr.pElems[i]; return TRUE; } } //TODO: } break; case PBT_PICTURE: { CComDispatchDriver dd; if(pVar->vt == VT_DISPATCH) dd = pVar->pdispVal; else if(pVar->vt == (VT_DISPATCH | VT_BYREF)) dd = *(pVar->ppdispVal); else { _ASSERT(FALSE); return FALSE; } if(!dd) { m_bstrText = L"(None)"; return TRUE; } CComVariant v; hr = dd.GetProperty(DISPID_PICT_TYPE,&v); if(SUCCEEDED(hr)) { switch(v.iVal) { case PICTYPE_BITMAP: m_bstrText = L"(Bitmap)"; break; case PICTYPE_ICON: m_bstrText = L"(Icon)"; break; case PICTYPE_METAFILE: case PICTYPE_ENHMETAFILE: m_bstrText = L"(Metafile)"; break; default: m_bstrText = L"(None)"; break; } } else { _ASSERT(FALSE); return FALSE; } } break; case PBT_BOOL: if(m_value.boolVal) m_bstrText = m_castr.pElems[1]; else m_bstrText = m_castr.pElems[0]; break; default: // unknow type found _ASSERT(FALSE); break; } return TRUE; } ////////////////////// CPropBrowseWnd ///////////////////////////// int CPropBrowseWnd::m_nDeltaX = 2; void CPropBrowseWnd::AddProperty(CPBProperty * pProp) { _ASSERT(::IsWindow(m_hWnd)); _ASSERT(pProp); _ASSERT(pProp->m_bstrName.m_str); int nWidth = GetItemWidth(pProp); if(nWidth > m_nColWidth) m_nColWidth = nWidth; int nIdx = (int)SendMessage(LB_ADDSTRING,0,(LPARAM)pProp); SendMessage(LB_SETITEMDATA,nIdx,(LPARAM)pProp); } LRESULT CPropBrowseWnd::DrawItem(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) { USES_CONVERSION; DRAWITEMSTRUCT* di = (DRAWITEMSTRUCT*)lParam; HDC hDC = di->hDC; RECT rcItem; ::CopyRect(&rcItem,&di->rcItem); rcItem.right = rcItem.left + m_nColWidth; switch(di->itemAction) { case ODA_SELECT: case ODA_DRAWENTIRE: { SIZE sizeText; CPBProperty * pProp = (CPBProperty*)di->itemData; _ASSERT(pProp); LPTSTR szText = OLE2T(pProp->m_bstrName.m_str); ::SetBkColor(hDC,di->itemState & ODS_SELECTED ? m_clrHighlite:m_clrBack); ::SetTextColor(hDC,di->itemState & ODS_SELECTED ? m_clrHighliteText:m_clrText); ::GetTextExtentPoint32(hDC,szText,pProp->m_bstrName.Length(),&sizeText); ::ExtTextOut(hDC, rcItem.left + m_nDeltaX, rcItem.top + (rcItem.bottom - rcItem.top -sizeText.cy)/2 +1, ETO_OPAQUE | ETO_CLIPPED, &rcItem, szText, pProp->m_bstrName.Length(), NULL); // Draw property text ::CopyRect(&rcItem,&di->rcItem); rcItem.left += m_nColWidth; if(NeedArrow(pProp)) rcItem.right -= rcItem.bottom - rcItem.top; if(pProp->m_bstrText.m_str) szText = OLE2T(pProp->m_bstrText.m_str); else szText = _T(""); ::SetBkColor(hDC,m_clrBack); ::SetTextColor(hDC,m_clrText); if(pProp->m_DisplayType == CPBProperty::PBPropTypes::PBT_COLOR) { // special case for color RECT rcClr; OLE_COLOR oc = pProp->m_value.lVal; COLORREF clr; OleTranslateColor(oc,NULL,&clr); ::CopyRect(&rcClr,&rcItem); rcClr.left += m_nDeltaX; rcItem.left += rcClr.bottom - rcClr.top + m_nDeltaX*2; rcClr.bottom --; rcClr.right = rcClr.left + rcClr.bottom - rcClr.top; ::InflateRect(&rcClr,-1,-1); HPEN hOldPen = (HPEN)::SelectObject(hDC,::GetStockObject(BLACK_PEN)); HBRUSH hBr = ::CreateSolidBrush(clr); HBRUSH hOldBrush = (HBRUSH)::SelectObject(hDC,hBr); ::Rectangle(hDC,rcClr.left,rcClr.top,rcClr.right,rcClr.bottom); ::SelectObject(hDC,hOldBrush); ::DeleteObject(hBr); ::SelectObject(hDC,hOldPen); } ::GetTextExtentPoint32(hDC,szText,pProp->m_bstrText.Length(),&sizeText); if(pProp->m_bDirty) ::SetTextColor(hDC,m_clrDirtyText); ::ExtTextOut(hDC, rcItem.left + m_nDeltaX, rcItem.top + (rcItem.bottom - rcItem.top -sizeText.cy)/2 +1, ETO_OPAQUE | ETO_CLIPPED, &rcItem, szText, pProp->m_bstrText.Length(), NULL); HPEN oldPen = (HPEN)::SelectObject(hDC,m_hGridPen); ::MoveToEx(hDC,di->rcItem.left + m_nColWidth,di->rcItem.top,NULL); ::LineTo(hDC,di->rcItem.left + m_nColWidth,di->rcItem.bottom); CopyRect(&rcItem,&di->rcItem); ::MoveToEx(hDC,rcItem.left,rcItem.bottom-1,NULL); ::LineTo(hDC,rcItem.right,rcItem.bottom-1); ::SelectObject(hDC,oldPen); DrawItemArrow(hDC,&di->rcItem,pProp,di->itemState & ODS_SELECTED); } break; } return 0; } LRESULT CPropBrowseWnd::OnKillFocusEdit(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) { bHandled = FALSE; if(GetFocus() == m_wndLBox.m_hWnd) return 0; m_wndEdit.ShowWindow(SW_HIDE); m_wndLBox.ShowWindow(SW_HIDE); if(m_pEditProp) { //still not handled property change, do it now CComBSTR bstrText; m_wndEdit.GetWindowText(bstrText.m_str); if(m_pEditProp->SetNewText(bstrText) == FALSE) // it is unsafe to display Message Box inside this message handler PostMessage(WM_PB_WARNING); else if(m_pEditProp->m_bDirty) ::PostMessage(GetParent(),WM_PB_PROPCHANGE,0,0); m_pEditProp = NULL; } return 0; } LRESULT CPropBrowseWnd::OnDisplayWarning(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) { MessageBox(_T("Invalid property value!"),_T("Error"),MB_OK | MB_ICONSTOP); return 0; } // custom message handler used to display in-place edit window LRESULT CPropBrowseWnd::OnStartEdit(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) { USES_CONVERSION; _ASSERT(m_pEditProp); if(m_pEditProp->m_bstrText.m_str) m_wndEdit.SetWindowText(OLE2CT(m_pEditProp->m_bstrText.m_str)); else m_wndEdit.SetWindowText(_T("")); if(m_pEditProp->m_castr.cElems > 0) m_rcEdit.right -= m_rcEdit.bottom - m_rcEdit.top; m_bEditReadOnly = m_pEditProp->m_DisplayType == CPBProperty::PBPropTypes::PBT_STR ? FALSE : TRUE; m_wndEdit.SetWindowPos(HWND_TOP,&m_rcEdit,SWP_SHOWWINDOW); m_wndEdit.SetFocus(); return 0; } LRESULT CPropBrowseWnd::OnKeyDownEdit(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) { bHandled = FALSE; int nVirtKey = (int)wParam; if(!m_pEditProp) return 0; if(nVirtKey == VK_DOWN || nVirtKey == VK_UP) { if(m_wndLBox.IsWindowVisible()) { int nIdx = (int)m_wndLBox.m_wndList.SendMessage(LB_GETCURSEL); int nCnt = (int)m_pEditProp->m_castr.cElems; if(nIdx != LB_ERR) { USES_CONVERSION; if(nVirtKey == VK_DOWN) if(nIdx < nCnt - 1) nIdx++; else nIdx = 0; else if(nIdx) nIdx--; else nIdx = nCnt - 1; m_wndLBox.m_wndList.SendMessage(LB_SETCURSEL,nIdx); m_wndEdit.SetWindowText(OLE2T(m_pEditProp->m_castr.pElems[nIdx])); m_wndEdit.PostMessage(EM_SETSEL,0,(LPARAM)(INT)-1); } } } return 0; } LRESULT CPropBrowseWnd::OnSysKeyDownEdit(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) { bHandled = FALSE; int nVirtKey = (int)wParam; if(!m_pEditProp) return 0; if(nVirtKey == VK_DOWN && m_pEditProp->m_castr.cElems > 0) { RECT r; m_wndEdit.GetWindowRect(&r); m_wndLBox.Display(&r,m_pEditProp,m_wndEdit.m_hWnd); bHandled = TRUE; } return 0; } LRESULT CPropBrowseWnd::OnLDoubleClickEdit(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) { bHandled = FALSE; if(m_pEditProp == NULL) { _ASSERT(FALSE); return 0; } TCHAR szText[128]; m_wndEdit.GetWindowText(szText,127); USES_CONVERSION; LPOLESTR szNextText = m_pEditProp->GetNextPredefinedString(szText); if(szNextText) { m_wndEdit.SetWindowText(OLE2T(szNextText)); bHandled = TRUE; } return 0; } LRESULT CPropBrowseWnd::OnLButtonDoubleClick(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) { POINT pt; pt.x = (int)LOWORD(lParam);pt.y = (int) HIWORD(lParam); bHandled = FALSE; DWORD dw = SendMessage(LB_ITEMFROMPOINT,0,lParam); if(HIWORD(dw) != 0) // no item hit? return 0; int nIdx = LOWORD(dw); if(SendMessage(LB_GETSEL,nIdx,0) <= 0) return 0;// item is not selected RECT rcItem; SendMessage(LB_GETITEMRECT,nIdx,(LPARAM)&rcItem); if(::PtInRect(&rcItem,pt)) { CPBProperty * pProp =(CPBProperty *) SendMessage(LB_GETITEMDATA,nIdx,0); if(!pProp) { _ASSERT(pProp); return 0; } switch(pProp->m_DisplayType) { case CPBProperty::PBPropTypes::PBT_FONT: case CPBProperty::PBPropTypes::PBT_PICTURE: PostMessage(WM_PB_SHOWPOPUP,(WPARAM)pProp,0); break; default: USES_CONVERSION; LPOLESTR szNextText = pProp->GetNextPredefinedString(OLE2T(pProp->m_bstrText)); if(szNextText) { CComBSTR bstr(szNextText); pProp->SetNewText(bstr); if(pProp->m_bDirty) { ::PostMessage(GetParent(),WM_PB_PROPCHANGE,0,0); InvalidateRect(&rcItem); } } } } return 0; } LRESULT CPropBrowseWnd::OnLButtonDown(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) { USES_CONVERSION; POINT pt; pt.x = (int)LOWORD(lParam);pt.y = (int) HIWORD(lParam); // get item hit bHandled = FALSE; DWORD dw = SendMessage(LB_ITEMFROMPOINT,0,lParam); if(HIWORD(dw) != 0) // no item hit? return 0; int nIdx = LOWORD(dw); if(SendMessage(LB_GETSEL,nIdx,0) <= 0) return 0;// item is not selected CPBProperty * pProp =(CPBProperty *) SendMessage(LB_GETITEMDATA,nIdx,0); if(!pProp) { _ASSERT(pProp); return 0; } RECT rcItem,rc; SendMessage(LB_GETITEMRECT,nIdx,(LPARAM)&rcItem); ::CopyRect(&rc,&rcItem); rc.left = rc.right - (rc.bottom - rc.top); // check for popup window activation if(NeedArrow(pProp)) { if(::PtInRect(&rc,pt)) { ::CopyRect(&m_rcEdit,&rcItem); m_rcEdit.left += m_nColWidth; bHandled = TRUE; PostMessage(WM_PB_SHOWPOPUP,(WPARAM)pProp,MAKELPARAM(rc.right,rc.bottom)); return 0; } } // for text properties if(pt.x > m_nColWidth) { rc.left = rcItem.left + m_nColWidth; rc.bottom --; m_pEditProp = pProp; ::CopyRect(&m_rcEdit,&rc); switch(pProp->m_DisplayType ) { case CPBProperty::PBPropTypes::PBT_BOOL: case CPBProperty::PBPropTypes::PBT_ENUM: case CPBProperty::PBPropTypes::PBT_STR: bHandled = TRUE; PostMessage(WM_PB_STARTEDIT,0,0); default: break; } // can't activate edit control and set the focus inside this message handler // so post a custom message to do it } return 0; } LRESULT CPropBrowseWnd::OnCreate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) { bHandled = FALSE; RECT rcEdit; ::SetRectEmpty(&rcEdit); rcEdit.right = rcEdit.bottom = 10; if(m_wndEdit.Create(m_hWnd,rcEdit,_T(""),WS_CHILD | ES_AUTOHSCROLL ,0,_ID_EDIT) == NULL) { _ASSERT(FALSE); return 0; } if(m_wndLBox.Create(NULL,rcEdit,_T(""),WS_BORDER | WS_POPUP,WS_EX_TOOLWINDOW) == NULL) { _ASSERT(FALSE); return 0; } return 0; } BOOL CPropBrowseWnd::Create(HWND hWndParent, LPRECT prcPos,UINT nID) { DWORD dwStyle = WS_CHILD | WS_TABSTOP | WS_VSCROLL | WS_VISIBLE | LBS_OWNERDRAWFIXED | LBS_NOINTEGRALHEIGHT | LBS_HASSTRINGS; if(CWindowImpl ::Create(hWndParent,*prcPos,_T(""),dwStyle, WS_EX_CLIENTEDGE ,nID) == NULL) return FALSE; HFONT hFont = (HFONT)::SendMessage(hWndParent,WM_GETFONT,0,0); SetFont(hFont); m_wndEdit.SetFont(hFont); m_wndLBox.m_wndList.SetFont(hFont); if(!m_wndColor.CreateWnd(this)) { _ASSERT(FALSE); return 0; } m_wndColor.SetFont(hFont); return TRUE; } int CPropBrowseWnd::GetItemWidth(CPBProperty * pProp) { USES_CONVERSION; if(!IsWindow(m_hWnd)) return 0; SIZE sizeText; HDC hdc = GetWindowDC(); HFONT hOldFont = (HFONT)SelectObject(hdc,GetFont()); GetTextExtentPoint32(hdc,OLE2T(pProp->m_bstrName),pProp->m_bstrName.Length(), &sizeText); sizeText.cx += m_nDeltaX * 2; SelectObject(hdc,hOldFont); ReleaseDC(hdc); return sizeText.cx; } BOOL CPropBrowseWnd::NeedArrow(CPBProperty * pProp) { _ASSERT(pProp); if(pProp->m_castr.cElems > 0) return TRUE; if(pProp->m_DisplayType == CPBProperty::PBPropTypes::PBT_STR) return FALSE; return TRUE; } void CPropBrowseWnd::DrawItemArrow(HDC hDC,LPRECT prcItem, CPBProperty * pProp,BOOL bSelected) { RECT rcBtn; ::CopyRect(&rcBtn,prcItem); rcBtn.left = rcBtn.right - (rcBtn.bottom - rcBtn.top); if(bSelected) switch(pProp->m_DisplayType) { case CPBProperty::PBPropTypes::PBT_STR: if(pProp->m_castr.cElems <= 0) break; case CPBProperty::PBPropTypes::PBT_COLOR: case CPBProperty::PBPropTypes::PBT_ENUM: case CPBProperty::PBPropTypes::PBT_BOOL: ::DrawFrameControl(hDC,&rcBtn,DFC_SCROLL,DFCS_SCROLLCOMBOBOX); break; case CPBProperty::PBPropTypes::PBT_PICTURE: case CPBProperty::PBPropTypes::PBT_FONT: { ::DrawFrameControl(hDC,&rcBtn,DFC_BUTTON,DFCS_BUTTONPUSH); COLORREF clrText = ::SetTextColor(hDC,m_clrText); int nBackMode = ::SetBkMode(hDC,TRANSPARENT); ::DrawText(hDC,_T("..."),3,&rcBtn,DT_CENTER | DT_SINGLELINE | DT_VCENTER); ::SetTextColor(hDC,clrText); ::SetBkMode(hDC,nBackMode); } break; default: break; } else { rcBtn.bottom -= 1; COLORREF clrBack = ::SetBkColor(hDC,m_clrBack); ::ExtTextOut(hDC,0,0,ETO_OPAQUE | ETO_CLIPPED,&rcBtn,_T(""),0,NULL); ::SetBkColor(hDC,clrBack); } } LRESULT CPropBrowseWnd::OnShowPopup(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) { CPBProperty *pProp = (CPBProperty*)wParam; _ASSERT(pProp); HRESULT hr = S_FALSE; switch(pProp->m_DisplayType) { case CPBProperty::PBPropTypes::PBT_FONT: hr = SelectFont(pProp); break; case CPBProperty::PBPropTypes::PBT_COLOR: { ClientToScreen(&m_rcEdit); hr = m_wndColor.PickColor(pProp,&m_rcEdit); } break; case CPBProperty::PBPropTypes::PBT_PICTURE: hr = SelectPicture(pProp); break; case CPBProperty::PBPropTypes::PBT_ENUM: case CPBProperty::PBPropTypes::PBT_BOOL: case CPBProperty::PBPropTypes::PBT_STR: { RECT r; m_pEditProp = pProp; CopyRect(&r,&m_rcEdit); if(m_pEditProp->m_castr.cElems > 0) m_rcEdit.right -= m_rcEdit.bottom - m_rcEdit.top; BOOL bDummy=TRUE; OnStartEdit(0,0,0,bDummy); ClientToScreen(&r); m_wndLBox.Display(&r,m_pEditProp,m_wndEdit.m_hWnd); } break; } if(hr==S_OK) ::PostMessage(GetParent(),WM_PB_PROPCHANGE,0,0); RedrawWindow(); return 0; } HRESULT CPropBrowseWnd::AddIconFile(CPBProperty * pProp, LPCTSTR lpszFile) { HICON hIcon = (HICON)::ExtractIcon(NULL,lpszFile,0); if(hIcon == NULL || hIcon == (HICON) 1) { MessageBox(_T("Error reading icon file!")); return E_FAIL; } PICTDESC pd; ZeroMemory(&pd,sizeof(pd)); // pd.cbSizeOfStruct = sizeof(PICTDESC); pd.picType = PICTYPE_ICON; pd.icon.hicon = hIcon; CComPtr spPictDisp; HRESULT hr = OleCreatePictureIndirect(&pd,IID_IPictureDisp, TRUE,(void**) &spPictDisp); if(FAILED(hr)) { MessageBox(_T("Error creating picture object!")); return hr; } CComVariant v(spPictDisp); if(pProp->SetNewValue(&v)) pProp->m_bDirty = TRUE; return S_OK; } HRESULT CPropBrowseWnd::AddBitmapFile(CPBProperty * pProp, LPCTSTR lpszFile) { PBDib dib; TCHAR szErrorText[] = _T("Error reading picture file!"); BOOL bOpen = dib.ReadDIBFile(lpszFile); if(!bOpen) { MessageBox(szErrorText); return E_FAIL; } HPALETTE hpal = dib.ClonePalette(); HBITMAP bmp; bmp = dib.CreateBitmap(); if(!bmp) { MessageBox(szErrorText); return E_FAIL; } PICTDESC pd; ZeroMemory(&pd,sizeof(pd)); // pd.cbSizeOfStruct = sizeof(PICTDESC); pd.picType = PICTYPE_BITMAP; pd.bmp.hbitmap = bmp; pd.bmp.hpal = hpal; CComPtr spPictDisp; HRESULT hr = OleCreatePictureIndirect(&pd,IID_IPictureDisp, TRUE,(void**) &spPictDisp); if(FAILED(hr)) { ::DeleteObject(bmp); if(hpal) ::GlobalFree(hpal); MessageBox(szErrorText); return hr; } CComVariant v(spPictDisp); if(pProp->SetNewValue(&v)) pProp->m_bDirty = TRUE; return S_OK; } HRESULT CPropBrowseWnd::AddMetaFile(CPBProperty * pProp, LPCTSTR szFileName) { HENHMETAFILE hemf = GetEnhMetaFile(szFileName); if(!hemf) return E_FAIL; PICTDESC pd; ZeroMemory(&pd,sizeof(pd)); // pd.cbSizeOfStruct = sizeof(PICTDESC); pd.picType = PICTYPE_ENHMETAFILE; pd.emf.hemf = hemf; CComPtr spPictDisp; HRESULT hr = OleCreatePictureIndirect(&pd,IID_IPictureDisp, TRUE,(void**) &spPictDisp); if(FAILED(hr)) { MessageBox(_T("Error creating picture object!")); DeleteEnhMetaFile(hemf); return hr; } CComVariant v(spPictDisp); if(pProp->SetNewValue(&v)) pProp->m_bDirty = TRUE; return S_OK; } HRESULT CPropBrowseWnd::SelectPicture(CPBProperty * pProp) { _ASSERT(pProp->m_DisplayType == CPBProperty::PBPropTypes::PBT_PICTURE); OPENFILENAME ofn; TCHAR szFile[512]=_T(""); ZeroMemory(&ofn,sizeof(ofn)); ofn.lStructSize = sizeof(ofn); ofn.hwndOwner = m_hWnd; ofn.hInstance = _Module.m_hInst; ofn.lpstrFilter = _T("Image Files\0*.BMP;*.ICO;*.EMF\0Bitmap Files\0*.BMP\0Icon Files\0*.ICO\0Windows Metafiles\0*.EMF\0\0"); ofn.lpstrCustomFilter = NULL; ofn.lpstrFile = szFile; ofn.nMaxFile = 511; ofn.Flags = OFN_EXPLORER | OFN_FILEMUSTEXIST; BOOL bRes = GetOpenFileName(&ofn); if(!bRes) return S_FALSE; if(_tcsicmp(szFile + ofn.nFileExtension,_T("ICO")) == 0) return AddIconFile(pProp,szFile); else if(_tcsicmp(szFile + ofn.nFileExtension,_T("BMP")) == 0) return AddBitmapFile(pProp,szFile); else if(_tcsicmp(szFile + ofn.nFileExtension,_T("EMF")) == 0) return AddMetaFile(pProp,szFile); return S_FALSE; } HRESULT CPropBrowseWnd::SelectFont(CPBProperty * pProp) { _ASSERT(pProp->m_DisplayType == CPBProperty::PBPropTypes::PBT_FONT); LOGFONT lf; HRESULT hr = S_OK; CComPtr pDisp; if(pProp->m_value.vt == VT_DISPATCH) pDisp = pProp->m_value.pdispVal; else if(pProp->m_value.vt == (VT_DISPATCH | VT_BYREF)) pDisp = *(pProp->m_value.ppdispVal); if(!pDisp) ::ZeroMemory(&lf,sizeof(lf)); else { CComQIPtr pFont(pDisp); HFONT hFont = NULL; if(pFont) { hr = pFont->get_hFont(&hFont); if(SUCCEEDED(hr)) ::GetObject(hFont,sizeof(lf),&lf); } } CHOOSEFONT cf; ::ZeroMemory(&cf,sizeof(cf)); cf.lStructSize = sizeof(cf); cf.hwndOwner = GetParent(); cf.lpLogFont = &lf; cf.Flags = CF_INITTOLOGFONTSTRUCT | CF_SCREENFONTS | CF_EFFECTS; if(!ChooseFont(&cf)) return S_FALSE; USES_CONVERSION; FONTDESC fd; ::ZeroMemory(&fd,sizeof(fd)); // fd.cbSizeOfStruct = sizeof(fd); //<- UnComment this line if you have new header files fd.lpstrName = T2OLE(lf.lfFaceName); fd.cySize.Lo = cf.iPointSize*1000; // fd.sWeight = (short)lf.lfWeight; fd.sCharset = lf.lfCharSet; fd.fItalic = lf.lfItalic; fd.fUnderline = lf.lfUnderline; fd.fStrikethrough = lf.lfStrikeOut; CComPtr pFontDisp; hr = OleCreateFontIndirect(&fd,IID_IFontDisp,(void**)&pFontDisp); if(FAILED(hr)) return hr; CComVariant v(pFontDisp); if(pProp->SetNewValue(&v)) pProp->m_bDirty = TRUE; return S_OK; } HRESULT CPropBrowseWnd::TranslateAccelerator(MSG * lpmsg) { if(m_wndEdit.IsWindowVisible() && lpmsg->message == WM_KEYDOWN) { if(LOWORD(lpmsg->wParam) == VK_ESCAPE) { m_pEditProp = NULL; // to prevent apply property during KillFocus m_wndEdit.ShowWindow(SW_HIDE); return S_OK; } else if(LOWORD(lpmsg->wParam) == VK_RETURN) { m_wndEdit.ShowWindow(SW_HIDE); return S_OK; } if(m_bEditReadOnly) switch(LOWORD(lpmsg->wParam)) { case VK_UP: case VK_DOWN: break; default: return S_OK; } } return S_FALSE; } ///////// Color Picker's Window Implementation ///////////////////// PBSystemColorEntry CPBColorPicker::m_SysColors[]= { {0x80000000,_T("Scroll Bars")}, {0x80000001,_T("Desktop")}, {0x80000002,_T("Active Title Bar")}, {0x80000003,_T("Inactive Title Bar")}, {0x80000004,_T("Menu Bar")}, {0x80000005,_T("Window Background")}, {0x80000006,_T("Window Frame")}, {0x80000007,_T("Menu Text")}, {0x80000008,_T("Window Text")}, {0x80000009,_T("Active Title Bar Text")}, {0x8000000A,_T("Active Border")}, {0x8000000B,_T("Inactive Border")}, {0x8000000C,_T("Application Workspace")}, {0x8000000D,_T("Highlight")}, {0x8000000E,_T("Highlight Text")}, {0x8000000F,_T("Button Face")}, {0x80000010,_T("Button Shadow")}, {0x80000011,_T("Disabled Text")}, {0x80000012,_T("Button Text")}, {0x80000013,_T("Inactive Title Bar Text")}, {0x80000014,_T("Button Highlight")}, {0x80000015,_T("Button Dark Shadow")}, {0x80000016,_T("Button Light Shadow")}, {0x80000017,_T("ToolTip Text")}, {0x80000018,_T("ToolTip")}, {0x00000000,NULL} }; OLE_COLOR CPBColorPicker::m_clrPalette[]= { 0x00FFFFFF,0x00C0C0ff,0x00C0E0ff,0x00C0FFFF,0x00C0FFC0,0x00FFFFC0,0x00FFC0C0,0x00FFC0FF, 0x00E0E0E0,0x008080FF,0x0080C0FF,0x0080FFFF,0x0080FF80,0x00FFFF80,0x00FF8080,0x00FF80FF, 0x00C0C0C0,0x000000FF,0x000080FF,0x0000FFFF,0x0000FF00,0x00FFFF00,0x00FF0000,0x00FF00FF, 0x00808080,0x000000C0,0x000040C0,0x0000C0C0,0x0000C000,0x00C0C000,0x00C00000,0x00C000C0, 0x00404040,0x00000080,0x00004080,0x00008080,0x00008000,0x00808000,0x00800000,0x00800080, 0x00000000,0x00000040,0x00404080,0x00004040,0x00004000,0x00404000,0x00400000,0x00400040, 0x00FFFFFF,0x00FFFFFF,0x00FFFFFF,0x00FFFFFF,0x00FFFFFF,0x00FFFFFF,0x00FFFFFF,0x00FFFFFF, 0x00FFFFFF,0x00FFFFFF,0x00FFFFFF,0x00FFFFFF,0x00FFFFFF,0x00FFFFFF,0x00FFFFFF,0x00FFFFFF }; BOOL CPBColorPicker::CreateWnd(CPropBrowseWnd * pParent) { _ASSERT(pParent); m_pParent = pParent; RECT r; SetRectEmpty(&r); r.right = r.bottom = 10;// 'll be updated soon if(Create(NULL,r,_T(""),WS_POPUP,WS_EX_TOOLWINDOW |WS_EX_DLGMODALFRAME) == NULL) { _ASSERT(FALSE);//creation failed return FALSE; } SetFont(pParent->GetFont()); m_wndTab.SetFont(pParent->GetFont()); m_wndList.SetFont(pParent->GetFont()); TC_ITEM tci; ::ZeroMemory(&tci,sizeof(tci)); tci.mask = TCIF_TEXT; tci.pszText = _T("Palette"); m_wndTab.SendMessage(TCM_INSERTITEM,0,(LPARAM)&tci); tci.pszText = _T("System"); m_wndTab.SendMessage(TCM_INSERTITEM,1,(LPARAM)&tci); for(int i=0;m_SysColors[i].c;i++) { int nIdx = m_wndList.SendMessage(LB_ADDSTRING,0,(LPARAM)_T("")); m_wndList.SendMessage(LB_SETITEMDATA,nIdx,i); } CalcSizes(); return TRUE; } LRESULT CPBColorPicker::OnDrawItem(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) { UINT nCtrl = (UINT)wParam; DRAWITEMSTRUCT *di = (DRAWITEMSTRUCT *)lParam; if(nCtrl == 2) DrawPalette(di); else if(nCtrl == 3) DrawListItem(di); return 0; } LRESULT CPBColorPicker::OnCreate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) { bHandled = FALSE; RECT rc; GetClientRect(&rc); if(m_wndTab.Create(m_hWnd,rc,_T(""), WS_CHILD | WS_VISIBLE | TCS_SINGLELINE | TCS_FOCUSNEVER,0,1) == NULL) { _ASSERT(FALSE); } if(m_wndPalette.Create(m_hWnd,rc,_T(""),WS_CHILD | BS_NOTIFY | WS_VISIBLE | BS_OWNERDRAW,0,2)==NULL) { _ASSERT(FALSE); } if(m_wndList.Create(m_hWnd,rc,_T(""),WS_CHILD | WS_VSCROLL | LBS_NOTIFY | LBS_OWNERDRAWFIXED | LBS_NOINTEGRALHEIGHT,0,3) == NULL) { _ASSERT(FALSE); } return 0; } void CPBColorPicker::CalcSizes() { int nSizeX = 0; HDC hdc = GetDC(); HFONT hFont = (HFONT)::SelectObject(hdc,m_wndList.GetFont()); for(int i=0;m_SysColors[i].szText;i++) { SIZE sizeText; ::GetTextExtentPoint32(hdc,m_SysColors[i].szText,lstrlen(m_SysColors[i].szText), &sizeText); if(nSizeX < sizeText.cx + sizeText.cy) nSizeX = sizeText.cx + sizeText.cy; } ::SelectObject(hdc,hFont); ::ReleaseDC(m_hWnd,hdc); nSizeX += GetSystemMetrics(SM_CXVSCROLL);// add scrollbar nSizeX += GetSystemMetrics(SM_CXBORDER)*2; m_nCellSize = MulDiv(nSizeX,100,800); RECT r; r.left = r.top = 0; r.bottom = r.right = m_nCellSize*8; m_wndTab.SendMessage(TCM_ADJUSTRECT,(WPARAM)TRUE,(LPARAM)&r); if(r.left < 0) { r.right -= r.left; r.left = 0; } if(r.top < 0) { r.bottom -= r.top; r.top = 0; } r.bottom += ::GetSystemMetrics(SM_CYEDGE)*2+2; r.right += ::GetSystemMetrics(SM_CXEDGE)*2+2; SetWindowPos(m_hWnd,&r,SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOZORDER); GetClientRect(&r); m_wndTab.MoveWindow(&r,FALSE); m_wndTab.SendMessage(TCM_ADJUSTRECT,(WPARAM)FALSE,(LPARAM)&r); ::CopyRect(&m_rcDisplay,&r); m_wndList.MoveWindow(&r,FALSE); m_wndPalette.MoveWindow(&r,FALSE); } HRESULT CPBColorPicker::PickColor(CPBProperty * pProp,RECT* r) { RECT rcWnd; m_pProp = pProp; GetWindowRect(&rcWnd); int x,y,h,w; h = rcWnd.bottom - rcWnd.top; w = rcWnd.right - rcWnd.left; x = r->right - w; if(x < 0) x = 0; if(r->bottom + h >= ::GetSystemMetrics(SM_CYSCREEN)) y = r->top - h; //drop Up else y = r->bottom; m_clr = (DWORD)m_pProp->m_value.lVal; SetStartColor(m_clr); BOOL bPicked = FALSE; SetWindowPos(HWND_TOP,x,y,w,h,SWP_SHOWWINDOW); SetFocus(); m_nChooseColor = -1; for(;;) { MSG msg; ::GetMessage(&msg, NULL, 0, 0); HWND hCaptureWnd = ::GetCapture(); if (hCaptureWnd && (hCaptureWnd != m_hWnd && ::GetParent(hCaptureWnd) != m_hWnd)) break; switch (msg.message) { case WM_ENDPICK: bPicked = msg.wParam; goto ExitLoop; case WM_RBUTTONDOWN: goto ExitLoop; break; case WM_KEYDOWN: if (msg.wParam == VK_ESCAPE) goto ExitLoop; default: TranslateMessage(&msg); DispatchMessage(&msg); break; } } ExitLoop: ShowWindow(SW_HIDE); if(m_nChooseColor > 47) { CHOOSECOLOR cc; ::ZeroMemory(&cc,sizeof(cc)); cc.lStructSize = sizeof(cc); cc.hwndOwner = GetParent(); cc.hInstance = NULL; cc.rgbResult = m_clrPalette[m_nChooseColor]; cc.lpCustColors = &m_clrPalette[48]; cc.Flags = CC_ANYCOLOR | CC_FULLOPEN | CC_RGBINIT; if(ChooseColor(&cc)) { bPicked = TRUE; m_clr = cc.rgbResult; } } if(bPicked) { VARIANT v; v.vt = VT_UI4; v.lVal = m_clr; if(pProp->SetNewValue(&v) == FALSE) { _ASSERT(FALSE); return E_FAIL; } pProp->m_bDirty = TRUE; } return bPicked ? S_OK : S_FALSE; } void CPBColorPicker::DrawPalette(LPDRAWITEMSTRUCT di) { HDC hdc = ::CreateCompatibleDC(di->hDC); _ASSERT(hdc); HBITMAP hbmp = ::CreateCompatibleBitmap(di->hDC, di->rcItem.right - di->rcItem.left, di->rcItem.bottom - di->rcItem.top); _ASSERT(hbmp); HBITMAP hbmp_old = (HBITMAP)::SelectObject(hdc,hbmp); HBRUSH hbr = (HBRUSH)::SelectObject(hdc,::GetStockObject(GRAY_BRUSH)); ::Rectangle (hdc, 0,0, di->rcItem.right - di->rcItem.left, di->rcItem.bottom - di->rcItem.top ); ::SelectObject(hdc,hbr); HPEN hOldPen = (HPEN)::SelectObject(hdc,::GetStockObject(BLACK_PEN)); for(int i=0;i < sizeof(m_clrPalette) / sizeof(m_clrPalette[0]);i++) { RECT r;COLORREF clr; r.left = m_nCellSize*(i%8); r.top = m_nCellSize*(i/8); r.right = r.left + m_nCellSize; r.bottom = r.top + m_nCellSize; clr = m_clrPalette[i];// in this case OLE_COLOR just 0x00RRGGBB == RGB() HBRUSH hBr; hBr = ::CreateSolidBrush(clr); r.right --; r.bottom --; if(m_nTrackIndex == i) { ::SelectObject(hdc,::GetStockObject(WHITE_PEN)); ::Rectangle(hdc,r.left,r.top,r.right,r.bottom); ::SelectObject(hdc,::GetStockObject(BLACK_PEN)); } HBRUSH hOldBr= (HBRUSH)::SelectObject(hdc,hBr); ::InflateRect(&r,-1,-1); ::Rectangle(hdc,r.left,r.top,r.right,r.bottom); ::SelectObject(hdc,hOldBr); ::DeleteObject(hBr); } ::BitBlt(di->hDC, di->rcItem.left, di->rcItem.top, di->rcItem.right - di->rcItem.left, di->rcItem.bottom - di->rcItem.top, hdc, 0,0,SRCCOPY); ::SelectObject(hdc,hOldPen); ::DeleteObject(::SelectObject(hdc,hbmp_old)); ::DeleteDC(hdc); } void CPBColorPicker::DrawListItem(LPDRAWITEMSTRUCT di) { HDC hdc = di->hDC; RECT &rcItem = di->rcItem; RECT r; int i = (int)(di->itemData); ::CopyRect(&r,&rcItem); r.right = r.left + r.bottom - r.top; ::InflateRect(&r,-1,-1); COLORREF clr; OleTranslateColor(m_SysColors[i].c,NULL,&clr); COLORREF clrBack = ::GetBkColor(hdc); COLORREF clrText = ::GetTextColor(hdc); HPEN hPen= (HPEN)::SelectObject(hdc,GetStockObject(BLACK_PEN)); HBRUSH hBr = ::CreateSolidBrush(clr); HBRUSH hOldBrush = (HBRUSH)::SelectObject(hdc,hBr); ::Rectangle(hdc,r.left,r.top,r.right,r.bottom); ::SelectObject(hdc,hOldBrush); ::DeleteObject(hBr); ::CopyRect(&r,&rcItem); r.left += r.bottom - r.top; if(di->itemState & ODS_SELECTED) { ::SetBkColor(hdc,::GetSysColor(COLOR_HIGHLIGHT)); ::SetTextColor(hdc,::GetSysColor(COLOR_HIGHLIGHTTEXT)); } else { ::SetBkColor(hdc,::GetSysColor(COLOR_WINDOW)); ::SetTextColor(hdc,::GetSysColor(COLOR_WINDOWTEXT)); } ::ExtTextOut(hdc,r.left,r.top, ETO_OPAQUE | ETO_CLIPPED, &r, m_SysColors[i].szText, _tcslen(m_SysColors[i].szText), NULL); ::SetBkColor(hdc,clrBack); ::SetTextColor(hdc,clrText); ::SelectObject(hdc,hPen); } LRESULT CPBColorPicker::OnLButtonDownPalette(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) { POINT pt; m_wndPalette.SetCapture(); pt.x = (int)LOWORD(lParam);pt.y = (int) HIWORD(lParam); m_bTrackPaletteColor = FALSE; int nHit = HitTestPalette(pt); m_nTrackIndex = nHit; if(nHit < 0) return 0; m_bTrackPaletteColor = TRUE; m_clr = m_clrPalette[nHit]; m_wndPalette.Invalidate(); return 0; } LRESULT CPBColorPicker::OnMouseMovePalette(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) { POINT pt; pt.x = (int)LOWORD(lParam);pt.y = (int) HIWORD(lParam); if(!m_bTrackPaletteColor) return 0; int nHit = HitTestPalette(pt); if(nHit >= 0 && m_nTrackIndex != nHit) { m_clr = m_clrPalette[nHit]; m_nTrackIndex = nHit; m_wndPalette.Invalidate(); } m_nTrackIndex = nHit; return 0; } LRESULT CPBColorPicker::OnLButtonUpPalette(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) { POINT pt; if(::GetCapture() == m_wndPalette.m_hWnd) ::ReleaseCapture(); pt.x = (int)LOWORD(lParam);pt.y = (int) HIWORD(lParam); int nHit = HitTestPalette(pt); if(m_bTrackPaletteColor && nHit >= 0) { m_clr = m_clrPalette[nHit]; PostMessage(WM_ENDPICK,1); } m_bTrackPaletteColor = FALSE; return 0; } int CPBColorPicker::HitTestPalette(POINT p) { RECT r; m_wndPalette.GetClientRect(&r); int x = r.left,y = r.top; for(int i=0;i < sizeof(m_clrPalette) / sizeof(m_clrPalette[0]);i++) { r.left = x + m_nCellSize*(i%8); r.top = y + m_nCellSize*(i/8); r.right = r.left + m_nCellSize -1; r.bottom = r.top + m_nCellSize -1; if(::PtInRect(&r,p)) return i; } return -1; } // rect is relative to palette window int CPBColorPicker::GetPaletteItemRect(int nIdx, RECT * r) { if(nIdx < 0 || nIdx >= sizeof(m_clrPalette) / sizeof(m_clrPalette[0])) { _ASSERT(FALSE); return -1; } m_wndPalette.GetClientRect(r); r->left += m_nCellSize*(nIdx%8); r->top += m_nCellSize*(nIdx/8); r->right = r->left + m_nCellSize -1; r->bottom = r->top + m_nCellSize -1; return nIdx; } void CPBColorPicker::SetStartColor(OLE_COLOR c) { m_wndTab.SendMessage(TCM_SETCURSEL,0); m_wndList.ShowWindow(SW_HIDE); m_wndPalette.ShowWindow(SW_SHOW); for(int i=0;m_SysColors[i].c;i++) if(c == m_SysColors[i].c) { m_wndList.SendMessage(LB_SETCURSEL,i); m_wndTab.SendMessage(TCM_SETCURSEL,1); m_wndList.ShowWindow(SW_SHOW); m_wndPalette.ShowWindow(SW_HIDE); m_nTrackIndex = -1; return; } m_wndList.SendMessage(LB_SETCURSEL,-1); for(i = 0;i < sizeof(m_clrPalette) / sizeof(m_clrPalette[0]);i++) if(c == m_clrPalette[i]) { m_nTrackIndex = i; return; } for(i = 48;i < sizeof(m_clrPalette) / sizeof(m_clrPalette[0]);i++) if(m_clrPalette[i] == 0x00FFFFFF) { m_clrPalette[i] = c; m_nTrackIndex = i; return; } int nLastChanceIdx = sizeof(m_clrPalette) / sizeof(m_clrPalette[0])-1; m_clrPalette[nLastChanceIdx] = c; m_nTrackIndex = nLastChanceIdx; } LRESULT CPBDropListBox::OnCreate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) { bHandled = FALSE; RECT rc; GetClientRect(&rc); if(m_wndList.Create(m_hWnd,rc,_T(""),WS_CHILD | WS_VISIBLE | WS_VSCROLL | LBS_NOTIFY | LBS_NOINTEGRALHEIGHT,0,1) == NULL) { _ASSERT(FALSE); } return 0; } int CPBDropListBox::LoadStrings(CPBProperty * pProp) { USES_CONVERSION; _ASSERT(IsWindow(m_wndList.m_hWnd)); _ASSERT(pProp); m_wndList.SendMessage(LB_RESETCONTENT); for(ULONG i=0;i < pProp->m_castr.cElems;i++) m_wndList.SendMessage(LB_ADDSTRING,0,(LPARAM)OLE2T(pProp->m_castr.pElems[i])); return pProp->m_castr.cElems; } void CPBDropListBox::Display(RECT * r,CPBProperty *pProp,HWND hwndEdit) { int x,y,h,w; m_hwndBuddyEdit = hwndEdit; m_pProp = pProp; h = r->bottom - r->top; w = r->right - r->left; x = r->right - w; LoadStrings(pProp); TCHAR szText[128]; ::GetWindowText(hwndEdit,szText,127); int nHit = (int)m_wndList.SendMessage(LB_FINDSTRING,-1,(LPARAM)szText); if(nHit != LB_ERR) m_wndList.SendMessage(LB_SETCURSEL,nHit,0); h = (int)m_wndList.SendMessage(LB_GETITEMHEIGHT)*min(8,pProp->m_castr.cElems); h += GetSystemMetrics(SM_CYBORDER)*2; if(h == 0) return; if(x < 0) x = 0; if(r->bottom + h >= ::GetSystemMetrics(SM_CYSCREEN)) y = r->top - h; //drop Up else y = r->bottom; SetWindowPos(HWND_TOP,x,y,w,h,SWP_NOACTIVATE | SWP_SHOWWINDOW); RECT rcClient; GetClientRect(&rcClient); m_wndList.MoveWindow(&rcClient); } LPOLESTR CPBProperty::GetNextPredefinedString(LPCTSTR szText) { LPOLESTR szNext = NULL; USES_CONVERSION; for(ULONG i=0;i < m_castr.cElems;i++) if(wcscmp(m_castr.pElems[i],T2COLE(szText)) == 0) if(i < m_castr.cElems - 1) return m_castr.pElems[i+1]; else return m_castr.pElems[0]; return NULL; }