/3rd_party/wtl/Include/atlribbon.h

https://code.google.com/p/softart/ · C++ Header · 3446 lines · 2686 code · 533 blank · 227 comment · 430 complexity · c9eaf028c94020793111b9ac5f0efb9e MD5 · raw file

Large files are truncated click here to view the full file

  1. // Windows Template Library - WTL version 8.1
  2. // Copyright (C) Microsoft Corporation. All rights reserved.
  3. //
  4. // This file is a part of the Windows Template Library.
  5. // The use and distribution terms for this software are covered by the
  6. // Common Public License 1.0 (http://opensource.org/licenses/cpl1.0.php)
  7. // which can be found in the file CPL.TXT at the root of this distribution.
  8. // By using this software in any fashion, you are agreeing to be bound by
  9. // the terms of this license. You must not remove this notice, or
  10. // any other, from this software.
  11. #ifndef __ATLRIBBON_H__
  12. #define __ATLRIBBON_H__
  13. #pragma once
  14. #if (_MSC_VER < 1500)
  15. #error atlribbon.h requires Visual C++ 2008 compiler or higher
  16. #endif
  17. #ifndef _UNICODE
  18. #error atlribbon.h requires the Unicode character set
  19. #endif
  20. #if !defined(NTDDI_WIN7) || (NTDDI_VERSION < NTDDI_WIN7)
  21. #error atlribbon.h requires the Windows 7 SDK or higher
  22. #endif
  23. #ifdef _WIN32_WCE
  24. #error atlribbon.h is not supported on Windows CE
  25. #endif
  26. #ifndef __ATLAPP_H__
  27. #error atlribbon.h requires atlapp.h to be included first
  28. #endif
  29. #if (_ATL_VER < 0x0700)
  30. #include <shlwapi.h>
  31. #pragma comment(lib, "shlwapi.lib")
  32. #endif
  33. #include <atlmisc.h> // for RecentDocumentList classes
  34. #include <atlframe.h> // for Frame and UpdateUI classes
  35. #include <atlctrls.h> // required for atlctrlw.h
  36. #include <atlctrlw.h> // for CCommandBarCtrl
  37. #if !defined(_WTL_USE_CSTRING) && !defined(__ATLSTR_H__)
  38. #pragma warning(disable : 4530) // unwind semantics not enabled
  39. #include <string>
  40. #pragma warning(default : 4530)
  41. #endif
  42. #include <dwmapi.h>
  43. #pragma comment(lib, "dwmapi.lib")
  44. #include <UIRibbon.h>
  45. #include <UIRibbonPropertyHelpers.h>
  46. #pragma comment(lib, "propsys.lib")
  47. #include <Richedit.h> // for CHARFORMAT2
  48. ///////////////////////////////////////////////////////////////////////////////
  49. // Classes in this file:
  50. //
  51. // CRibbonUpdateUI : Automatic mapping of ribbon UI elements
  52. //
  53. // RibbonUI::Text
  54. // RibbonUI::CharFormat
  55. // RibbonUI::ICtrl
  56. // RibbonUI::CtrlImpl
  57. // RibbonUI::CommandCtrlImpl
  58. // RibbonUI::ItemProperty
  59. // RibbonUI::CollectionImplBase
  60. // RibbonUI::CollectionImpl
  61. // RibbonUI::TextCollectionImpl
  62. // RibbonUI::ItemCollectionImpl
  63. // RibbonUI::ComboCollectionImpl
  64. // RibbonUI::CommandCollectionImpl
  65. // RibbonUI::ToolbarCollectionImpl
  66. // RibbonUI::SimpleCollectionImpl
  67. // RibbonUI::CollectionCtrlImpl
  68. // RibbonUI::ToolbarGalleryCtrlImpl
  69. // RibbonUI::SimpleCollectionCtrlImpl
  70. // RibbonUI::RecentItemsCtrlImpl
  71. // RibbonUI::FontCtrlImpl
  72. // RibbonUI::ColorCtrlImpl
  73. // RibbonUI::SpinnerCtrlImpl
  74. //
  75. // RibbonUI::CRibbonImpl
  76. // CRibbonImpl::CRibbonComboCtrl
  77. // CRibbonImpl::CRibbonItemGalleryCtrl
  78. // CRibbonImpl::CRibbonCommandGalleryCtrl
  79. // CRibbonImpl::CRibbonToolbarGalleryCtrl
  80. // CRibbonImpl::CRibbonSimpleComboCtrl
  81. // CRibbonImpl::CRibbonSimpleGalleryCtrl
  82. // CRibbonImpl::CRibbonRecentItemsCtrl
  83. // CRibbonImpl::CRibbonColorCtrl
  84. // CRibbonImpl::CRibbonFontCtrl
  85. // CRibbonImpl::CRibbonSpinnerCtrl
  86. // CRibbonImpl::CRibbonFloatSpinnerCtrl
  87. // CRibbonImpl::CRibbonCommandCtrl
  88. //
  89. // CRibbonFrameWindowImplBase
  90. // CRibbonFrameWindowImpl
  91. // CRibbonMDIFrameWindowImpl
  92. // CRibbonPersist
  93. //
  94. // Global functions:
  95. // RibbonUI::SetPropertyVal()
  96. // RibbonUI::GetImage()
  97. // Constants
  98. #ifndef RIBBONUI_MAX_TEXT
  99. #define RIBBONUI_MAX_TEXT 128
  100. #endif
  101. #define TWIPS_PER_POINT 20 // For font size
  102. namespace WTL
  103. {
  104. ///////////////////////////////////////////////////////////////////////////////
  105. // CRibbonUpdateUI : Automatic mapping of ribbon UI elements
  106. template <class T>
  107. class CRibbonUpdateUI : public CAutoUpdateUI<T>
  108. {
  109. public:
  110. enum
  111. {
  112. UPDUI_RIBBON = 0x0080,
  113. UPDUI_PERSIST = 0x0020
  114. };
  115. bool IsRibbonElement(const _AtlUpdateUIMap& UIMap)
  116. {
  117. return (UIMap.m_wType & UPDUI_RIBBON) != 0;
  118. }
  119. bool IsRibbonID(UINT nID)
  120. {
  121. for(int i = 0; i < m_arrUIMap.GetSize(); i++)
  122. {
  123. if(m_arrUIMap[i].m_nID == nID)
  124. return IsRibbonElement(m_arrUIMap[i]);
  125. }
  126. return false;
  127. }
  128. // Element
  129. bool UIAddRibbonElement(UINT nID)
  130. {
  131. return UIAddElement<UPDUI_RIBBON>(nID);
  132. }
  133. bool UIRemoveRibbonElement(UINT nID)
  134. {
  135. return UIRemoveElement<UPDUI_RIBBON>(nID);
  136. }
  137. bool UIPersistElement(UINT nID, bool bPersist = true)
  138. {
  139. return bPersist ?
  140. UIAddElement<UPDUI_PERSIST>(nID) :
  141. UIRemoveElement<UPDUI_PERSIST>(nID);
  142. }
  143. // methods for Ribbon elements
  144. BOOL UISetText(int nID, LPCWSTR sText, BOOL bForceUpdate = FALSE)
  145. {
  146. T* pT = static_cast<T*>(this);
  147. BOOL bRes = CUpdateUIBase::UISetText(nID, sText, bForceUpdate);
  148. if (pT->IsRibbonUI() && IsRibbonID(nID))
  149. bRes = SUCCEEDED(pT->InvalidateProperty(nID, UI_PKEY_Label));
  150. return bRes;
  151. }
  152. BOOL UISetText(int nID, UINT uIdResource, BOOL bForceUpdate = FALSE)
  153. {
  154. CTempBuffer<WCHAR> sText(RIBBONUI_MAX_TEXT);
  155. return AtlLoadString(uIdResource, sText, RIBBONUI_MAX_TEXT) ?
  156. UISetText(nID, sText, bForceUpdate) :
  157. E_FAIL;
  158. }
  159. LPCTSTR UIGetText(int nID)
  160. {
  161. T* pT = static_cast<T*>(this);
  162. LPCTSTR sUI = CAutoUpdateUI::UIGetText(nID);
  163. // replace 'tab' by 'space' for RibbonUI elements
  164. if (sUI && pT->IsRibbonUI() && IsRibbonID(nID) && wcschr(sUI, L'\t'))
  165. {
  166. static WCHAR sText[RIBBONUI_MAX_TEXT] = { 0 };
  167. wcscpy_s(sText, sUI);
  168. *wcschr(sText, L'\t') = L' ';
  169. return sText;
  170. }
  171. else
  172. {
  173. return sUI;
  174. }
  175. }
  176. BOOL UIEnable(int nID, BOOL bEnable, BOOL bForceUpdate = FALSE)
  177. {
  178. T* pT = static_cast<T*>(this);
  179. BOOL bRes = CUpdateUIBase::UIEnable(nID, bEnable, bForceUpdate);
  180. if (pT->IsRibbonUI() && IsRibbonID(nID))
  181. bRes = SUCCEEDED(pT->SetProperty((WORD)nID, UI_PKEY_Enabled, bEnable));
  182. return bRes;
  183. }
  184. BOOL UISetCheck(int nID, INT nCheck, BOOL bForceUpdate = FALSE)
  185. {
  186. if ((nCheck == 0) || (nCheck == 1))
  187. return UISetCheck(nID, nCheck != 0, bForceUpdate);
  188. else
  189. return CUpdateUIBase::UISetCheck(nID, nCheck, bForceUpdate);
  190. }
  191. BOOL UISetCheck(int nID, bool bCheck, BOOL bForceUpdate = FALSE)
  192. {
  193. T* pT = static_cast<T*>(this);
  194. BOOL bRes = CUpdateUIBase::UISetCheck(nID, bCheck, bForceUpdate);
  195. if (bRes && pT->IsRibbonUI() && IsRibbonID(nID))
  196. bRes = SUCCEEDED(pT->SetProperty((WORD)nID, UI_PKEY_BooleanValue, bCheck));
  197. return bRes;
  198. }
  199. };
  200. ///////////////////////////////////////////////////////////////////////////////
  201. // RibbonUI namespace
  202. //
  203. namespace RibbonUI
  204. {
  205. // Minimal string allocation support for various PROPERTYKEY values
  206. #if defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__)
  207. typedef _CSTRING_NS::CString Text;
  208. #else
  209. class Text : public std::wstring
  210. {
  211. public:
  212. Text(std::wstring& s) : std::wstring(s)
  213. { }
  214. Text(LPCWSTR s) : std::wstring(s)
  215. { }
  216. Text()
  217. { }
  218. bool IsEmpty()
  219. {
  220. return empty();
  221. }
  222. operator LPCWSTR()
  223. {
  224. return c_str();
  225. }
  226. Text& operator =(LPCWSTR s)
  227. {
  228. return static_cast<Text&>(std::wstring::operator =(s));
  229. }
  230. };
  231. #endif
  232. // PROPERTYKEY enum and helpers
  233. enum k_KEY
  234. {
  235. // state
  236. k_Enabled = 1, k_BooleanValue = 200,
  237. // text properties
  238. k_LabelDescription = 2, k_Keytip = 3, k_Label = 4, k_TooltipDescription = 5, k_TooltipTitle = 6,
  239. // image properties
  240. k_LargeImage = 7, k_LargeHighContrastImage = 8, k_SmallImage = 9, k_SmallHighContrastImage = 10,
  241. // collection properties
  242. k_ItemsSource = 101, k_Categories = 102, k_SelectedItem = 104,
  243. // collection item properties
  244. k_CommandId = 100, k_CategoryId = 103, k_CommandType = 105, k_ItemImage = 106,
  245. // combo control property
  246. k_StringValue = 202,
  247. // spinner control properties
  248. k_DecimalValue = 201, k_MaxValue = 203, k_MinValue, k_Increment, k_DecimalPlaces, k_FormatString, k_RepresentativeString = 208,
  249. // font control properties
  250. k_FontProperties = 300, k_FontProperties_Family, k_FontProperties_Size, k_FontProperties_Bold, k_FontProperties_Italic = 304,
  251. k_FontProperties_Underline = 305, k_FontProperties_Strikethrough, k_FontProperties_VerticalPositioning, k_FontProperties_ForegroundColor = 308,
  252. k_FontProperties_BackgroundColor = 309, k_FontProperties_ForegroundColorType, k_FontProperties_BackgroundColorType, k_FontProperties_ChangedProperties = 312,
  253. k_FontProperties_DeltaSize = 313,
  254. // recent items properties
  255. k_RecentItems = 350, k_Pinned = 351,
  256. // color control properties
  257. k_Color = 400, k_ColorType = 401, k_ColorMode,
  258. k_ThemeColorsCategoryLabel = 403, k_StandardColorsCategoryLabel, k_RecentColorsCategoryLabel = 405, k_AutomaticColorLabel = 406,
  259. k_NoColorLabel = 407, k_MoreColorsLabel = 408,
  260. k_ThemeColors = 409, k_StandardColors = 410, k_ThemeColorsTooltips = 411, k_StandardColorsTooltips = 412,
  261. // Ribbon state
  262. k_Viewable = 1000, k_Minimized = 1001, k_QuickAccessToolbarDock = 1002, k_ContextAvailable = 1100,
  263. // Ribbon UI colors
  264. k_GlobalBackgroundColor = 2000, k_GlobalHighlightColor, k_GlobalTextColor = 2002
  265. };
  266. inline k_KEY k_(REFPROPERTYKEY key)
  267. {
  268. return (k_KEY)key.fmtid.Data1;
  269. }
  270. // PROPERTYKEY value assignment and specializations
  271. //
  272. template <typename V>
  273. HRESULT SetPropertyVal(REFPROPERTYKEY key, V val, PROPVARIANT* ppv)
  274. {
  275. switch (k_(key))
  276. {
  277. case k_Enabled:
  278. case k_BooleanValue:
  279. return InitPropVariantFromBoolean(val, ppv);
  280. default:
  281. return UIInitPropertyFromUInt32(key, val, ppv);
  282. }
  283. }
  284. inline HRESULT SetPropertyVal(REFPROPERTYKEY key, DOUBLE val, PROPVARIANT* ppv)
  285. {
  286. return SetPropertyVal(key, (LONG)val, ppv);
  287. }
  288. inline HRESULT SetPropertyVal(REFPROPERTYKEY key, IUIImage* val, PROPVARIANT* ppv)
  289. {
  290. HRESULT hr = UIInitPropertyFromImage(key, val, ppv);
  291. ATLVERIFY(val->Release() == 1);
  292. return hr;
  293. }
  294. inline HRESULT SetPropertyVal(REFPROPERTYKEY key, IUnknown* val, PROPVARIANT* ppv)
  295. {
  296. return UIInitPropertyFromInterface(key, val, ppv);
  297. }
  298. inline HRESULT SetPropertyVal(REFPROPERTYKEY key, IPropertyStore* val, PROPVARIANT* ppv)
  299. {
  300. return UIInitPropertyFromInterface(key, val, ppv);
  301. }
  302. inline HRESULT SetPropertyVal(REFPROPERTYKEY key, SAFEARRAY* val, PROPVARIANT* ppv)
  303. {
  304. return UIInitPropertyFromIUnknownArray(key, val, ppv);
  305. }
  306. inline HRESULT SetPropertyVal(REFPROPERTYKEY key, DECIMAL* val, PROPVARIANT* ppv)
  307. {
  308. return UIInitPropertyFromDecimal(key, *val, ppv);
  309. }
  310. inline HRESULT SetPropertyVal(REFPROPERTYKEY key, bool val, PROPVARIANT* ppv)
  311. {
  312. return UIInitPropertyFromBoolean(key, val, ppv);
  313. }
  314. inline HRESULT SetPropertyVal(REFPROPERTYKEY key, LPCWSTR val, PROPVARIANT* ppv)
  315. {
  316. return UIInitPropertyFromString(key, val, ppv);
  317. }
  318. // CharFormat helper struct for RibbonUI font control
  319. //
  320. struct CharFormat : CHARFORMAT2
  321. {
  322. // Default constructor
  323. CharFormat()
  324. {
  325. cbSize = sizeof CHARFORMAT2;
  326. Reset();
  327. }
  328. // Copy constructor
  329. CharFormat(const CharFormat& cf)
  330. {
  331. CopyMemory(this, &cf, sizeof CHARFORMAT2);
  332. }
  333. // Assign operator
  334. CharFormat& operator =(const CharFormat& cf)
  335. {
  336. CopyMemory(this, &cf, sizeof CHARFORMAT2);
  337. return (*this);
  338. }
  339. void Reset()
  340. {
  341. uValue = dwMask = dwEffects = 0;
  342. PropVariantInit(&propvar);
  343. }
  344. void operator <<(IPropertyStore* pStore)
  345. {
  346. if (pStore == NULL)
  347. {
  348. ATLASSERT(FALSE);
  349. return;
  350. }
  351. static void (CharFormat::*Getk_[])(IPropertyStore*) =
  352. {
  353. &CharFormat::Getk_Family,
  354. &CharFormat::Getk_FontProperties_Size,
  355. &CharFormat::Getk_MaskEffect<CFM_BOLD, CFE_BOLD, UI_PKEY_FontProperties_Bold>,
  356. &CharFormat::Getk_MaskEffect<CFM_ITALIC, CFE_ITALIC, UI_PKEY_FontProperties_Italic>,
  357. &CharFormat::Getk_MaskEffect<CFM_UNDERLINE, CFE_UNDERLINE, UI_PKEY_FontProperties_Underline>,
  358. &CharFormat::Getk_MaskEffect<CFM_STRIKEOUT, CFE_STRIKEOUT, UI_PKEY_FontProperties_Strikethrough>,
  359. &CharFormat::Getk_VerticalPositioning,
  360. &CharFormat::Getk_Color<CFM_COLOR, UI_PKEY_FontProperties_ForegroundColor>,
  361. &CharFormat::Getk_Color<CFM_BACKCOLOR, UI_PKEY_FontProperties_BackgroundColor>,
  362. &CharFormat::Getk_ColorType<CFM_COLOR, CFE_AUTOCOLOR, UI_SWATCHCOLORTYPE_AUTOMATIC, UI_PKEY_FontProperties_ForegroundColorType>,
  363. &CharFormat::Getk_ColorType<CFM_BACKCOLOR, CFE_AUTOBACKCOLOR, UI_SWATCHCOLORTYPE_NOCOLOR, UI_PKEY_FontProperties_BackgroundColorType>,
  364. };
  365. DWORD nProps = 0;
  366. Reset();
  367. ATLVERIFY(SUCCEEDED(pStore->GetCount(&nProps)));
  368. for (DWORD iProp = 0; iProp < nProps; iProp++)
  369. {
  370. PROPERTYKEY key;
  371. ATLVERIFY(SUCCEEDED(pStore->GetAt(iProp, &key)));
  372. ATLASSERT(k_(key) >= k_FontProperties_Family);
  373. if (k_(key) <= k_FontProperties_BackgroundColorType)
  374. (this->*Getk_[k_(key) - k_FontProperties_Family])(pStore);
  375. }
  376. }
  377. void operator >>(IPropertyStore* pStore)
  378. {
  379. if (pStore == NULL)
  380. {
  381. ATLASSERT(FALSE);
  382. return;
  383. }
  384. PutFace(pStore);
  385. PutSize(pStore);
  386. PutMaskEffect(CFM_BOLD, CFE_BOLD, UI_PKEY_FontProperties_Bold, pStore);
  387. PutMaskEffect(CFM_ITALIC, CFE_ITALIC, UI_PKEY_FontProperties_Italic, pStore);
  388. PutMaskEffect(CFM_UNDERLINE, CFE_UNDERLINE, UI_PKEY_FontProperties_Underline, pStore);
  389. PutMaskEffect(CFM_STRIKEOUT, CFE_STRIKEOUT, UI_PKEY_FontProperties_Strikethrough, pStore);
  390. PutVerticalPos(pStore);
  391. PutColor(pStore);
  392. PutBackColor(pStore);
  393. }
  394. private:
  395. PROPVARIANT propvar;
  396. UINT uValue;
  397. // Getk_ functions
  398. void Getk_Family(IPropertyStore* pStore)
  399. {
  400. if (SUCCEEDED(pStore->GetValue(UI_PKEY_FontProperties_Family, &propvar)))
  401. {
  402. PropVariantToString(propvar, szFaceName, LF_FACESIZE);
  403. if (*szFaceName)
  404. dwMask |= CFM_FACE;
  405. }
  406. }
  407. void Getk_FontProperties_Size(IPropertyStore* pStore)
  408. {
  409. if (SUCCEEDED(pStore->GetValue(UI_PKEY_FontProperties_Size, &propvar)))
  410. {
  411. DECIMAL decSize;
  412. UIPropertyToDecimal(UI_PKEY_FontProperties_Size, propvar, &decSize);
  413. DOUBLE dSize;
  414. VarR8FromDec(&decSize, &dSize);
  415. if (dSize > 0)
  416. {
  417. dwMask |= CFM_SIZE;
  418. yHeight = (LONG)(dSize * TWIPS_PER_POINT);
  419. }
  420. }
  421. }
  422. template <DWORD t_dwMask, DWORD t_dwEffects, REFPROPERTYKEY key>
  423. void Getk_MaskEffect(IPropertyStore* pStore)
  424. {
  425. if (SUCCEEDED(pStore->GetValue(key, &propvar)))
  426. {
  427. UIPropertyToUInt32(key, propvar, &uValue);
  428. if ((UI_FONTPROPERTIES)uValue != UI_FONTPROPERTIES_NOTAVAILABLE)
  429. {
  430. dwMask |= t_dwMask;
  431. dwEffects |= ((UI_FONTPROPERTIES) uValue == UI_FONTPROPERTIES_SET) ? t_dwEffects : 0;
  432. }
  433. }
  434. }
  435. void Getk_VerticalPositioning(IPropertyStore* pStore)
  436. {
  437. if (SUCCEEDED(pStore->GetValue(UI_PKEY_FontProperties_VerticalPositioning, &propvar)))
  438. {
  439. UIPropertyToUInt32(UI_PKEY_FontProperties_VerticalPositioning, propvar, &uValue);
  440. UI_FONTVERTICALPOSITION uVerticalPosition = (UI_FONTVERTICALPOSITION) uValue;
  441. if ((uVerticalPosition != UI_FONTVERTICALPOSITION_NOTAVAILABLE))
  442. {
  443. dwMask |= (CFM_SUPERSCRIPT | CFM_SUBSCRIPT);
  444. if (uVerticalPosition != UI_FONTVERTICALPOSITION_NOTSET)
  445. {
  446. dwEffects |= (uVerticalPosition == UI_FONTVERTICALPOSITION_SUPERSCRIPT) ? CFE_SUPERSCRIPT : CFE_SUBSCRIPT;
  447. }
  448. }
  449. }
  450. }
  451. template <DWORD t_dwMask, REFPROPERTYKEY key>
  452. void Getk_Color(IPropertyStore* pStore)
  453. {
  454. UINT32 color;
  455. if (SUCCEEDED(pStore->GetValue(key, &propvar)))
  456. {
  457. UIPropertyToUInt32(key, propvar, &color);
  458. dwMask |= t_dwMask;
  459. if (t_dwMask == CFM_COLOR)
  460. crTextColor = color;
  461. else
  462. crBackColor = color;
  463. }
  464. }
  465. template <DWORD t_dwMask, DWORD t_dwEffects, UI_SWATCHCOLORTYPE t_type, REFPROPERTYKEY key>
  466. void Getk_ColorType(IPropertyStore* pStore)
  467. {
  468. if (SUCCEEDED(pStore->GetValue(key, &propvar)))
  469. {
  470. UIPropertyToUInt32(key, propvar, &uValue);
  471. if (t_type == (UI_SWATCHCOLORTYPE)uValue)
  472. {
  473. dwMask |= t_dwMask;
  474. dwEffects |= t_dwEffects;
  475. }
  476. }
  477. }
  478. // Put functions
  479. void PutMaskEffect(WORD dwMaskVal, WORD dwEffectVal, REFPROPERTYKEY key, IPropertyStore* pStore)
  480. {
  481. PROPVARIANT propvar;
  482. UI_FONTPROPERTIES uProp = UI_FONTPROPERTIES_NOTAVAILABLE;
  483. if ((dwMask & dwMaskVal) != 0)
  484. uProp = dwEffects & dwEffectVal ? UI_FONTPROPERTIES_SET : UI_FONTPROPERTIES_NOTSET;
  485. SetPropertyVal(key, uProp, &propvar);
  486. pStore->SetValue(key, propvar);
  487. }
  488. void PutVerticalPos(IPropertyStore* pStore)
  489. {
  490. PROPVARIANT propvar;
  491. UI_FONTVERTICALPOSITION uProp = UI_FONTVERTICALPOSITION_NOTAVAILABLE;
  492. if ((dwMask & CFE_SUBSCRIPT) != 0)
  493. {
  494. if ((dwMask & CFM_SUBSCRIPT) && (dwEffects & CFE_SUBSCRIPT))
  495. uProp = UI_FONTVERTICALPOSITION_SUBSCRIPT;
  496. else
  497. uProp = UI_FONTVERTICALPOSITION_SUPERSCRIPT;
  498. }
  499. else if ((dwMask & CFM_OFFSET) != 0)
  500. {
  501. if (yOffset > 0)
  502. uProp = UI_FONTVERTICALPOSITION_SUPERSCRIPT;
  503. else if (yOffset < 0)
  504. uProp = UI_FONTVERTICALPOSITION_SUBSCRIPT;
  505. }
  506. SetPropertyVal(UI_PKEY_FontProperties_VerticalPositioning, uProp, &propvar);
  507. pStore->SetValue(UI_PKEY_FontProperties_VerticalPositioning, propvar);
  508. }
  509. void PutFace(IPropertyStore* pStore)
  510. {
  511. PROPVARIANT propvar;
  512. SetPropertyVal(UI_PKEY_FontProperties_Family,
  513. dwMask & CFM_FACE ? szFaceName : L"", &propvar);
  514. pStore->SetValue(UI_PKEY_FontProperties_Family, propvar);
  515. }
  516. void PutSize(IPropertyStore* pStore)
  517. {
  518. PROPVARIANT propvar;
  519. DECIMAL decVal;
  520. if ((dwMask & CFM_SIZE) != 0)
  521. VarDecFromR8((DOUBLE)yHeight / TWIPS_PER_POINT, &decVal);
  522. else
  523. VarDecFromI4(0, &decVal);
  524. SetPropertyVal(UI_PKEY_FontProperties_Size, &decVal, &propvar);
  525. pStore->SetValue(UI_PKEY_FontProperties_Size, propvar);
  526. }
  527. void PutColor(IPropertyStore* pStore)
  528. {
  529. if ((dwMask & CFM_COLOR) != 0)
  530. if ((dwEffects & CFE_AUTOCOLOR) == 0)
  531. {
  532. SetPropertyVal(UI_PKEY_FontProperties_ForegroundColorType, UI_SWATCHCOLORTYPE_RGB, &propvar);
  533. pStore->SetValue(UI_PKEY_FontProperties_ForegroundColorType, propvar);
  534. SetPropertyVal(UI_PKEY_FontProperties_ForegroundColor, crTextColor, &propvar);
  535. pStore->SetValue(UI_PKEY_FontProperties_ForegroundColor, propvar);
  536. }
  537. else
  538. {
  539. SetPropertyVal(UI_PKEY_FontProperties_ForegroundColorType, UI_SWATCHCOLORTYPE_AUTOMATIC, &propvar);
  540. pStore->SetValue(UI_PKEY_FontProperties_ForegroundColorType, propvar);
  541. }
  542. }
  543. void PutBackColor(IPropertyStore* pStore)
  544. {
  545. if (((dwMask & CFM_BACKCOLOR) != 0) && ((dwEffects & CFE_AUTOBACKCOLOR) == 0))
  546. {
  547. SetPropertyVal(UI_PKEY_FontProperties_BackgroundColorType, UI_SWATCHCOLORTYPE_RGB, &propvar);
  548. pStore->SetValue(UI_PKEY_FontProperties_BackgroundColorType, propvar);
  549. SetPropertyVal(UI_PKEY_FontProperties_BackgroundColor, crBackColor, &propvar);
  550. pStore->SetValue(UI_PKEY_FontProperties_BackgroundColor, propvar);
  551. }
  552. else
  553. {
  554. SetPropertyVal(UI_PKEY_FontProperties_BackgroundColorType, UI_SWATCHCOLORTYPE_NOCOLOR, &propvar);
  555. pStore->SetValue(UI_PKEY_FontProperties_BackgroundColorType, propvar);
  556. }
  557. }
  558. };
  559. // IUIImage helper
  560. //
  561. inline IUIImage* GetImage(HBITMAP hbm, UI_OWNERSHIP owner)
  562. {
  563. ATLASSERT(hbm);
  564. IUIImage* pIUII = NULL;
  565. ATL::CComPtr<IUIImageFromBitmap> pIFB;
  566. if SUCCEEDED(pIFB.CoCreateInstance(CLSID_UIRibbonImageFromBitmapFactory))
  567. ATLVERIFY(SUCCEEDED(pIFB->CreateImage(hbm, owner, &pIUII)));
  568. return pIUII;
  569. }
  570. ///////////////////////////////////////////////////////////////////////////////
  571. // Ribbon control classes
  572. // RibbonUI::ICtrl abstract interface of RibbonUI::CRibbonImpl and all RibbonUI control classes
  573. //
  574. struct ICtrl
  575. {
  576. virtual HRESULT DoExecute(UINT nCmdID, UI_EXECUTIONVERB verb,
  577. const PROPERTYKEY* key, const PROPVARIANT* ppropvarValue,
  578. IUISimplePropertySet* pCommandExecutionProperties) = 0;
  579. virtual HRESULT DoUpdateProperty(UINT nCmdID, REFPROPERTYKEY key,
  580. const PROPVARIANT* ppropvarCurrentValue, PROPVARIANT* ppropvarNewValue) = 0;
  581. };
  582. // RibbonUI::CtrlImpl base class for all ribbon controls
  583. //
  584. template <class T, UINT t_ID>
  585. class ATL_NO_VTABLE CtrlImpl : public ICtrl
  586. {
  587. protected:
  588. T* m_pWndRibbon;
  589. public:
  590. typedef T WndRibbon;
  591. CtrlImpl() : m_pWndRibbon(T::pWndRibbon)
  592. { }
  593. WndRibbon& GetWndRibbon()
  594. {
  595. return *m_pWndRibbon;
  596. }
  597. static WORD GetID()
  598. {
  599. return t_ID;
  600. }
  601. Text m_sTxt[5];
  602. // Operations
  603. HRESULT Invalidate()
  604. {
  605. return GetWndRibbon().InvalidateCtrl(GetID());
  606. }
  607. HRESULT Invalidate(REFPROPERTYKEY key, UI_INVALIDATIONS flags = UI_INVALIDATIONS_PROPERTY)
  608. {
  609. return GetWndRibbon().InvalidateProperty(GetID(), key, flags);
  610. }
  611. HRESULT SetText(REFPROPERTYKEY key, LPCWSTR sTxt, bool bUpdate = false)
  612. {
  613. ATLASSERT((k_(key) <= k_TooltipTitle) && (k_(key) >= k_LabelDescription));
  614. m_sTxt[k_(key) - k_LabelDescription] = sTxt;
  615. return bUpdate ?
  616. GetWndRibbon().InvalidateProperty(GetID(), key) :
  617. S_OK;
  618. }
  619. // Implementation
  620. template <typename V>
  621. HRESULT SetProperty(REFPROPERTYKEY key, V val)
  622. {
  623. return GetWndRibbon().SetProperty(GetID(), key, val);
  624. }
  625. HRESULT OnGetText(REFPROPERTYKEY key, PROPVARIANT* ppv)
  626. {
  627. ATLASSERT((k_(key) <= k_TooltipTitle) && (k_(key) >= k_LabelDescription));
  628. const INT iText = k_(key) - k_LabelDescription;
  629. if (m_sTxt[iText].IsEmpty())
  630. if (LPCWSTR sText = GetWndRibbon().OnRibbonQueryText(GetID(), key))
  631. m_sTxt[iText] = sText;
  632. return !m_sTxt[iText].IsEmpty() ?
  633. SetPropertyVal(key, (LPCWSTR)m_sTxt[iText], ppv) :
  634. S_OK;
  635. }
  636. virtual HRESULT DoExecute(UINT nCmdID, UI_EXECUTIONVERB verb,
  637. const PROPERTYKEY* key, const PROPVARIANT* ppropvarValue,
  638. IUISimplePropertySet* pCommandExecutionProperties)
  639. {
  640. ATLASSERT(nCmdID == t_ID);
  641. return GetWndRibbon().DoExecute(nCmdID, verb, key, ppropvarValue, pCommandExecutionProperties);
  642. }
  643. virtual HRESULT DoUpdateProperty(UINT nCmdID, REFPROPERTYKEY key,
  644. const PROPVARIANT* ppropvarCurrentValue, PROPVARIANT* ppropvarNewValue)
  645. {
  646. ATLASSERT(nCmdID == t_ID);
  647. const INT iMax = k_TooltipTitle - k_LabelDescription;
  648. const INT iVal = k_(key) - k_LabelDescription;
  649. return (iVal <= iMax) && (iVal >= 0) ?
  650. OnGetText(key, ppropvarNewValue) :
  651. GetWndRibbon().DoUpdateProperty(nCmdID, key, ppropvarCurrentValue, ppropvarNewValue);
  652. }
  653. };
  654. // CommandCtrlImpl base class for most ribbon controls
  655. //
  656. template <class T, UINT t_ID>
  657. class CommandCtrlImpl : public CtrlImpl<T, t_ID>
  658. {
  659. public:
  660. CBitmap m_hbm[4];
  661. HRESULT SetImage(REFPROPERTYKEY key, HBITMAP hbm, bool bUpdate = false)
  662. {
  663. ATLASSERT((k_(key) <= k_SmallHighContrastImage) && (k_(key) >= k_LargeImage));
  664. m_hbm[k_(key) - k_LargeImage].Attach(hbm);
  665. return bUpdate ?
  666. GetWndRibbon().InvalidateProperty(GetID(), key) :
  667. S_OK;
  668. }
  669. HRESULT OnGetImage(REFPROPERTYKEY key, PROPVARIANT* ppv)
  670. {
  671. ATLASSERT((k_(key) <= k_SmallHighContrastImage) && (k_(key) >= k_LargeImage));
  672. const INT iImage = k_(key) - k_LargeImage;
  673. if (m_hbm[iImage].IsNull())
  674. m_hbm[iImage] = GetWndRibbon().OnRibbonQueryImage(GetID(), key);
  675. return m_hbm[iImage].IsNull() ?
  676. E_NOTIMPL :
  677. SetPropertyVal(key, GetImage(m_hbm[iImage], UI_OWNERSHIP_COPY), ppv);
  678. }
  679. virtual HRESULT DoUpdateProperty(UINT nCmdID, REFPROPERTYKEY key,
  680. const PROPVARIANT* ppropvarCurrentValue, PROPVARIANT* ppropvarNewValue)
  681. {
  682. ATLASSERT (nCmdID == GetID());
  683. return (k_(key) <= k_SmallHighContrastImage) && (k_(key) >= k_LargeImage) ?
  684. OnGetImage(key, ppropvarNewValue) :
  685. CtrlImpl::DoUpdateProperty(nCmdID, key, ppropvarCurrentValue, ppropvarNewValue);
  686. }
  687. };
  688. ///////////////////////////////////////////////////////////////////////////////
  689. // Ribbon collection base classes
  690. // ItemProperty class: ribbon callback for each item in a collection
  691. //
  692. template <class TCollection>
  693. class ItemProperty : public IUISimplePropertySet
  694. {
  695. public:
  696. ItemProperty(UINT i, TCollection* pCollection) : m_Index(i), m_pCollection(pCollection)
  697. { }
  698. const UINT m_Index;
  699. TCollection* m_pCollection;
  700. // IUISimplePropertySet method.
  701. STDMETHODIMP GetValue(REFPROPERTYKEY key, PROPVARIANT *value)
  702. {
  703. return m_pCollection->OnGetItem(m_Index, key, value);
  704. }
  705. // IUnknown methods.
  706. STDMETHODIMP_(ULONG) AddRef()
  707. {
  708. return 1;
  709. }
  710. STDMETHODIMP_(ULONG) Release()
  711. {
  712. return 1;
  713. }
  714. STDMETHODIMP QueryInterface(REFIID iid, void** ppv)
  715. {
  716. if ((iid == __uuidof(IUnknown)) || (iid == __uuidof(IUISimplePropertySet)))
  717. {
  718. *ppv = this;
  719. return S_OK;
  720. }
  721. else
  722. {
  723. return E_NOINTERFACE;
  724. }
  725. }
  726. };
  727. // CollectionImplBase: base class for all RibbonUI collections
  728. //
  729. template <class TCollection, size_t t_size>
  730. class CollectionImplBase
  731. {
  732. typedef CollectionImplBase<TCollection, t_size> thisClass;
  733. public:
  734. CollectionImplBase()
  735. {
  736. for (int i = 0; i < t_size; i++)
  737. m_apItems[i] = new ItemProperty<TCollection>(i, static_cast<TCollection*>(this));
  738. }
  739. ~CollectionImplBase()
  740. {
  741. for (int i = 0; i < t_size; i++)
  742. delete m_apItems[i];
  743. }
  744. // Data members
  745. ItemProperty<TCollection>* m_apItems[t_size];
  746. };
  747. // CollectionImpl: handles categories and collecton resizing
  748. //
  749. template <class TCtrl, size_t t_items, size_t t_categories>
  750. class CollectionImpl : public CollectionImplBase<CollectionImpl<TCtrl, t_items, t_categories>, t_items + t_categories>
  751. {
  752. typedef CollectionImpl<TCtrl, t_items, t_categories> thisClass;
  753. public:
  754. typedef thisClass Collection;
  755. CollectionImpl() : m_size(t_items)
  756. {
  757. FillMemory(m_auItemCat, sizeof m_auItemCat, 0xff); // UI_COLLECTION_INVALIDINDEX
  758. }
  759. UINT32 m_auItemCat[t_items];
  760. Text m_asCatName[max(t_categories, 1)];
  761. size_t m_size;
  762. // Operations
  763. HRESULT SetItemCategory(UINT uItem, UINT uCat, bool bUpdate = false)
  764. {
  765. ATLASSERT((uItem < t_items) && (uCat < t_categories));
  766. m_auItemCat[uItem] = uCat;
  767. return bUpdate ? InvalidateItems() : S_OK;
  768. }
  769. HRESULT SetCategoryText(UINT uCat, LPCWSTR sText, bool bUpdate = false)
  770. {
  771. ATLASSERT(uCat < t_categories);
  772. m_asCatName[uCat] = sText;
  773. return bUpdate ? InvalidateCategories() : S_OK;
  774. }
  775. HRESULT Resize(size_t size, bool bUpdate = false)
  776. {
  777. ATLASSERT(size <= t_items);
  778. m_size = size;
  779. return bUpdate ? InvalidateItems() : S_OK;
  780. }
  781. // Implementation
  782. HRESULT OnGetItem(UINT uIndex, REFPROPERTYKEY key, PROPVARIANT *value)
  783. {
  784. ATLASSERT(uIndex < t_items + t_categories);
  785. TCtrl* pCtrl = static_cast<TCtrl*>(this);
  786. return uIndex < t_items ?
  787. pCtrl->DoGetItem(uIndex, key, value) :
  788. pCtrl->DoGetCategory(uIndex - t_items, key, value);
  789. }
  790. HRESULT DoGetItem(UINT uItem, REFPROPERTYKEY key, PROPVARIANT *value)
  791. {
  792. ATLASSERT(k_(key) == k_CategoryId);
  793. UINT32 uCat = UI_COLLECTION_INVALIDINDEX;
  794. if (t_categories != 0)
  795. {
  796. if (m_auItemCat[uItem] == UI_COLLECTION_INVALIDINDEX)
  797. {
  798. TCtrl::WndRibbon& ribbon = static_cast<TCtrl*>(this)->GetWndRibbon();
  799. m_auItemCat[uItem] = ribbon.OnRibbonQueryItemCategory(TCtrl::GetID(), uItem);
  800. }
  801. uCat = m_auItemCat[uItem];
  802. }
  803. return SetPropertyVal(key, uCat, value);
  804. }
  805. HRESULT DoGetCategory(UINT uCat, REFPROPERTYKEY key, PROPVARIANT *value)
  806. {
  807. HRESULT hr = S_OK;
  808. switch (k_(key))
  809. {
  810. case k_Label:
  811. if (m_asCatName[uCat].IsEmpty())
  812. {
  813. TCtrl::WndRibbon& ribbon = static_cast<TCtrl*>(this)->GetWndRibbon();
  814. m_asCatName[uCat] = ribbon.OnRibbonQueryCategoryText(TCtrl::GetID(), uCat);
  815. }
  816. hr = SetPropertyVal(key, (LPCWSTR)m_asCatName[uCat], value);
  817. break;
  818. case k_CategoryId:
  819. hr = SetPropertyVal(key, uCat, value);
  820. break;
  821. default:
  822. ATLASSERT(FALSE);
  823. break;
  824. }
  825. return hr;
  826. }
  827. HRESULT InvalidateItems()
  828. {
  829. return static_cast<TCtrl*>(this)->Invalidate(UI_PKEY_ItemsSource);
  830. }
  831. HRESULT InvalidateCategories()
  832. {
  833. return static_cast<TCtrl*>(this)->Invalidate(UI_PKEY_Categories);
  834. }
  835. HRESULT DoUpdateProperty(UINT nCmdID, REFPROPERTYKEY key,
  836. const PROPVARIANT* ppropvarCurrentValue, PROPVARIANT* /*ppropvarNewValue*/)
  837. {
  838. ATLASSERT(nCmdID == TCtrl::GetID());
  839. nCmdID; // avoid level 4 warning
  840. HRESULT hr = E_NOTIMPL;
  841. switch (k_(key))
  842. {
  843. case k_ItemsSource:
  844. {
  845. ATL::CComQIPtr<IUICollection> pIUICollection(ppropvarCurrentValue->punkVal);
  846. ATLASSERT(pIUICollection);
  847. hr = pIUICollection->Clear();
  848. for (UINT i = 0; i < m_size; i++)
  849. {
  850. if FAILED(hr = pIUICollection->Add(m_apItems[i]))
  851. break;
  852. }
  853. ATLASSERT(SUCCEEDED(hr));
  854. }
  855. break;
  856. case k_Categories:
  857. if (t_categories != 0)
  858. {
  859. ATL::CComQIPtr<IUICollection> pIUICategory(ppropvarCurrentValue->punkVal);
  860. ATLASSERT(pIUICategory.p);
  861. hr = pIUICategory->Clear();
  862. for (UINT i = t_items; i < t_items + t_categories; i++)
  863. {
  864. if FAILED(hr = pIUICategory->Add(m_apItems[i]))
  865. break;
  866. }
  867. ATLASSERT(SUCCEEDED(hr));
  868. }
  869. break;
  870. }
  871. return hr;
  872. }
  873. };
  874. // TextCollectionImpl: handles item labels and selection
  875. //
  876. template <class TCtrl, size_t t_items, size_t t_categories = 0>
  877. class TextCollectionImpl : public CollectionImpl<TCtrl, t_items, t_categories>
  878. {
  879. typedef TextCollectionImpl<TCtrl, t_items, t_categories> thisClass;
  880. public:
  881. typedef thisClass TextCollection;
  882. TextCollectionImpl() : m_uSelected(UI_COLLECTION_INVALIDINDEX)
  883. { }
  884. Text m_asText[t_items];
  885. UINT m_uSelected;
  886. // Operations
  887. HRESULT SetItemText(UINT uItem, LPCWSTR sText, bool bUpdate = false)
  888. {
  889. ATLASSERT(uItem < t_items);
  890. m_asText[uItem] = sText;
  891. return bUpdate ? InvalidateItems() : S_OK;
  892. }
  893. UINT GetSelected()
  894. {
  895. return m_uSelected;
  896. }
  897. HRESULT Select(UINT uItem, bool bUpdate = false)
  898. {
  899. ATLASSERT((uItem < t_items) || (uItem == UI_COLLECTION_INVALIDINDEX));
  900. m_uSelected = uItem;
  901. TCtrl::WndRibbon& ribbon = static_cast<TCtrl*>(this)->GetWndRibbon();
  902. return bUpdate ?
  903. ribbon.SetProperty(TCtrl::GetID(), UI_PKEY_SelectedItem, uItem) :
  904. S_OK;
  905. }
  906. // Implementation
  907. HRESULT DoGetItem(UINT uItem, REFPROPERTYKEY key, PROPVARIANT *value)
  908. {
  909. ATLASSERT(uItem < t_items);
  910. if (k_(key) == k_Label)
  911. {
  912. if (m_asText[uItem].IsEmpty())
  913. {
  914. TCtrl::WndRibbon& ribbon = static_cast<TCtrl*>(this)->GetWndRibbon();
  915. m_asText[uItem] = ribbon.OnRibbonQueryItemText(TCtrl::GetID(), uItem);
  916. }
  917. return SetPropertyVal(key, (LPCWSTR)m_asText[uItem], value);
  918. }
  919. else
  920. {
  921. return Collection::DoGetItem(uItem, key, value);
  922. }
  923. }
  924. HRESULT DoUpdateProperty(UINT nCmdID, REFPROPERTYKEY key,
  925. const PROPVARIANT* ppropvarCurrentValue, PROPVARIANT* ppropvarNewValue)
  926. {
  927. ATLASSERT(nCmdID == TCtrl::GetID());
  928. if (k_(key) == k_SelectedItem)
  929. {
  930. TCtrl::WndRibbon& ribbon = static_cast<TCtrl*>(this)->GetWndRibbon();
  931. UINT uSel = UI_COLLECTION_INVALIDINDEX;
  932. if ((m_uSelected == UI_COLLECTION_INVALIDINDEX) &&
  933. ribbon.OnRibbonQuerySelectedItem(TCtrl::GetID(), uSel))
  934. m_uSelected = uSel;
  935. return SetPropertyVal(key, m_uSelected, ppropvarNewValue);
  936. }
  937. else
  938. {
  939. return Collection::DoUpdateProperty(nCmdID, key, ppropvarCurrentValue, ppropvarNewValue);
  940. }
  941. }
  942. };
  943. // ItemCollectionImpl: handles item image
  944. //
  945. template <class TCtrl, size_t t_items, size_t t_categories = 0>
  946. class ItemCollectionImpl : public TextCollectionImpl<TCtrl, t_items, t_categories>
  947. {
  948. typedef ItemCollectionImpl<TCtrl, t_items, t_categories> thisClass;
  949. public:
  950. typedef thisClass ItemCollection;
  951. ItemCollectionImpl()
  952. {
  953. ZeroMemory(m_aBitmap, sizeof m_aBitmap);
  954. }
  955. CBitmap m_aBitmap[t_items];
  956. // Operations
  957. HRESULT SetItemImage(UINT uIndex, HBITMAP hbm, bool bUpdate = false)
  958. {
  959. ATLASSERT(uIndex < t_items);
  960. m_aBitmap[uIndex] = hbm;
  961. return bUpdate ? InvalidateItems() : S_OK;
  962. }
  963. // Implementation
  964. HRESULT DoGetItem(UINT uItem, REFPROPERTYKEY key, PROPVARIANT *value)
  965. {
  966. ATLASSERT(uItem < t_items);
  967. if (k_(key) == k_ItemImage)
  968. {
  969. if (m_aBitmap[uItem].IsNull())
  970. {
  971. TCtrl::WndRibbon& ribbon = static_cast<TCtrl*>(this)->GetWndRibbon();
  972. m_aBitmap[uItem] = ribbon.OnRibbonQueryItemImage(TCtrl::GetID(), uItem);
  973. }
  974. return m_aBitmap[uItem].IsNull() ?
  975. E_NOTIMPL :
  976. SetPropertyVal(key, GetImage(m_aBitmap[uItem], UI_OWNERSHIP_COPY), value);
  977. }
  978. else
  979. {
  980. return TextCollection::DoGetItem(uItem, key, value);
  981. }
  982. }
  983. };
  984. // ComboCollectionImpl: handles combo text
  985. //
  986. template <class TCtrl, size_t t_items, size_t t_categories = 0>
  987. class ComboCollectionImpl : public ItemCollectionImpl<TCtrl, t_items, t_categories>
  988. {
  989. typedef ComboCollectionImpl<TCtrl, t_items, t_categories> thisClass;
  990. public:
  991. typedef thisClass ComboCollection;
  992. // Operations
  993. HRESULT SetComboText(LPCWSTR sText)
  994. {
  995. TCtrl::WndRibbon& ribbon = static_cast<TCtrl*>(this)->GetWndRibbon();
  996. return ribbon.IsRibbonUI() ?
  997. ribbon.SetProperty(TCtrl::GetID(), UI_PKEY_StringValue, sText) :
  998. S_OK;
  999. }
  1000. LPCWSTR GetComboText()
  1001. {
  1002. static WCHAR sCombo[RIBBONUI_MAX_TEXT] = { 0 };
  1003. TCtrl::WndRibbon& ribbon = static_cast<TCtrl*>(this)->GetWndRibbon();
  1004. PROPVARIANT var;
  1005. if (ribbon.IsRibbonUI())
  1006. {
  1007. HRESULT hr = ribbon.GetIUIFrameworkPtr()->GetUICommandProperty(TCtrl::GetID(), UI_PKEY_StringValue, &var);
  1008. hr = PropVariantToString(var, sCombo, RIBBONUI_MAX_TEXT);
  1009. return sCombo;
  1010. }
  1011. return NULL;
  1012. }
  1013. };
  1014. // CommandCollectionImpl: handles RibbonUI command collection controls
  1015. //
  1016. template <class TCtrl, size_t t_items, size_t t_categories = 0>
  1017. class CommandCollectionImpl : public CollectionImpl<TCtrl, t_items, t_categories>
  1018. {
  1019. typedef CommandCollectionImpl<TCtrl, t_items, t_categories> thisClass;
  1020. public:
  1021. typedef thisClass CommandCollection;
  1022. CommandCollectionImpl()
  1023. {
  1024. ZeroMemory(m_auCmd, sizeof m_auCmd);
  1025. ZeroMemory(m_aCmdType, sizeof m_aCmdType);
  1026. }
  1027. UINT32 m_auCmd[t_items];
  1028. BYTE m_aCmdType[t_items];
  1029. // Operations
  1030. HRESULT SetItemCommand(UINT uItem, UINT32 uCommandID, bool bUpdate = false)
  1031. {
  1032. ATLASSERT(uItem < t_items);
  1033. if (uCommandID == m_auCmd[uItem])
  1034. return S_OK;
  1035. TCtrl::WndRibbon& ribbon = static_cast<TCtrl*>(this)->GetWndRibbon();
  1036. m_auCmd[uItem] = uCommandID;
  1037. if (uCommandID != 0)
  1038. ribbon.UIAddRibbonElement(uCommandID);
  1039. return bUpdate ? InvalidateItems() : S_OK;
  1040. }
  1041. HRESULT SetItemCommandType(UINT uItem, UI_COMMANDTYPE type, bool bUpdate = false)
  1042. {
  1043. ATLASSERT(uItem < t_items);
  1044. m_aCmdType[uItem] = (BYTE)type;
  1045. return bUpdate ? InvalidateItems() : S_OK;
  1046. }
  1047. // Implementation
  1048. HRESULT DoGetItem(UINT uItem, REFPROPERTYKEY key, PROPVARIANT *value)
  1049. {
  1050. ATLASSERT(uItem < t_items);
  1051. TCtrl::WndRibbon& ribbon = static_cast<TCtrl*>(this)->GetWndRibbon();
  1052. HRESULT hr = E_FAIL;
  1053. switch (k_(key))
  1054. {
  1055. case k_CommandId:
  1056. if (m_auCmd[uItem] == 0)
  1057. SetItemCommand(uItem, ribbon.OnRibbonQueryItemCommand(TCtrl::GetID(), uItem));
  1058. hr = SetPropertyVal(key, m_auCmd[uItem], value);
  1059. break;
  1060. case k_CommandType:
  1061. if (m_aCmdType[uItem] == UI_COMMANDTYPE_UNKNOWN)
  1062. SetItemCommandType(uItem, ribbon.OnRibbonQueryItemCommandType(TCtrl::GetID(), uItem));
  1063. hr = SetPropertyVal(key, UINT32(m_aCmdType[uItem]), value);
  1064. break;
  1065. case k_CategoryId:
  1066. default:
  1067. hr = Collection::DoGetItem(uItem, key, value);
  1068. break;
  1069. }
  1070. return hr;
  1071. }
  1072. HRESULT Select(UINT /*uItem*/, bool /*bUpdate*/ = false)
  1073. {
  1074. ATLASSERT(FALSE);
  1075. return S_OK;
  1076. }
  1077. };
  1078. // SimpleCollectionImpl: collection class for ribbon simple collection controls
  1079. //
  1080. template <class TCtrl, size_t t_size, UI_COMMANDTYPE t_CommandType = UI_COMMANDTYPE_ACTION>
  1081. class SimpleCollectionImpl : public CollectionImplBase<SimpleCollectionImpl<TCtrl, t_size>, t_size>
  1082. {
  1083. typedef SimpleCollectionImpl<TCtrl, t_size, t_CommandType> thisClass;
  1084. public:
  1085. typedef CollectionImplBase<thisClass, t_size> CollectionBase;
  1086. typedef thisClass SimpleCollection;
  1087. // Implementation
  1088. HRESULT OnGetItem(UINT uItem, REFPROPERTYKEY key, PROPVARIANT *value)
  1089. {
  1090. ATLASSERT(uItem < t_size);
  1091. TCtrl::WndRibbon& ribbon = static_cast<TCtrl*>(this)->GetWndRibbon();
  1092. HRESULT hr = E_NOTIMPL;
  1093. switch (k_(key))
  1094. {
  1095. case k_ItemImage:
  1096. if (HBITMAP hbm = ribbon.DefRibbonQueryItemImage(TCtrl::GetID(), uItem))
  1097. hr = SetPropertyVal(key, GetImage(hbm, UI_OWNERSHIP_TRANSFER), value);
  1098. break;
  1099. case k_Label:
  1100. if (LPCWSTR sText = ribbon.DefRibbonQueryItemText(TCtrl::GetID(), uItem))
  1101. hr = SetPropertyVal(key, (LPCWSTR)sText, value);
  1102. break;
  1103. case k_CommandType:
  1104. hr = SetPropertyVal(key, t_CommandType, value);
  1105. break;
  1106. case k_CommandId:
  1107. hr = SetPropertyVal(key, ribbon.DefRibbonQueryItemCommand(TCtrl::GetID(), uItem), value);
  1108. break;
  1109. case k_CategoryId:
  1110. hr = SetPropertyVal(key, UI_COLLECTION_INVALIDINDEX, value);
  1111. break;
  1112. default:
  1113. ATLASSERT(FALSE);
  1114. break;
  1115. }
  1116. return hr;
  1117. }
  1118. };
  1119. ///////////////////////////////////////////////////////////////////////////////
  1120. // Ribbon collection control classes
  1121. // CollectionCtrlImpl: specializable class for ribbon collection controls
  1122. //
  1123. template <class T, UINT t_ID, class TCollection>
  1124. class CollectionCtrlImpl : public CommandCtrlImpl<T, t_ID>, public TCollection
  1125. {
  1126. typedef CollectionCtrlImpl<T, t_ID, TCollection> thisClass;
  1127. public:
  1128. typedef CommandCtrlImpl<T, t_ID> CommandCtrl;
  1129. typedef TCollection Collection;
  1130. // Implementation
  1131. virtual HRESULT DoUpdateProperty(UINT nCmdID, REFPROPERTYKEY key,
  1132. const PROPVARIANT* ppropvarCurrentValue, PROPVARIANT* ppropvarNewValue)
  1133. {
  1134. ATLASSERT(nCmdID == GetID());
  1135. ATLASSERT(ppropvarNewValue);
  1136. HRESULT hr = Collection::DoUpdateProperty(nCmdID, key, ppropvarCurrentValue, ppropvarNewValue);
  1137. if FAILED(hr)
  1138. hr = CommandCtrl::DoUpdateProperty(nCmdID, key, ppropvarCurrentValue, ppropvarNewValue);
  1139. return hr;
  1140. }
  1141. virtual HRESULT DoExecute(UINT nCmdID, UI_EXECUTIONVERB verb,
  1142. const PROPERTYKEY* key, const PROPVARIANT* ppropvarValue,
  1143. IUISimplePropertySet* /*pCommandExecutionProperties*/)
  1144. {
  1145. ATLASSERT (nCmdID == GetID());
  1146. nCmdID; // avoid level4 warning
  1147. if (key == NULL) // gallery button pressed
  1148. {
  1149. GetWndRibbon().OnRibbonItemSelected(GetID(), UI_EXECUTIONVERB_EXECUTE, UI_COLLECTION_INVALIDINDEX);
  1150. return S_OK;
  1151. }
  1152. ATLASSERT(k_(*key) == k_SelectedItem);
  1153. ATLASSERT(ppropvarValue);
  1154. HRESULT hr = S_OK;
  1155. UINT32 uSel = 0xffff;
  1156. hr = UIPropertyToUInt32(*key, *ppropvarValue, &uSel);
  1157. if (SUCCEEDED(hr))
  1158. {
  1159. if (GetWndRibbon().OnRibbonItemSelected(GetID(), verb, uSel))
  1160. TCollection::Select(uSel);
  1161. }
  1162. return hr;
  1163. }
  1164. };
  1165. // ToolbarGalleryCtrlImpl: base class for ribbon toolbar gallery controls
  1166. //
  1167. template <class T, UINT t_ID, UINT t_idTB, size_t t_size>
  1168. class ToolbarGalleryCtrlImpl : public CollectionCtrlImpl<T, t_ID, CommandCollectionImpl<ToolbarGalleryCtrlImpl<T, t_ID, t_idTB, t_size>, t_size>>
  1169. {
  1170. public:
  1171. ToolbarGalleryCtrlImpl()
  1172. {
  1173. CResource tbres;
  1174. ATLVERIFY(tbres.Load(RT_TOOLBAR, t_idTB));
  1175. _AtlToolBarData* pData = (_AtlToolBarData*)tbres.Lock();
  1176. ATLASSERT(pData);
  1177. ATLASSERT(pData->wVersion == 1);
  1178. WORD* pItems = pData->items();
  1179. INT j = 0;
  1180. for (int i = 0; (i < pData->wItemCount) && (j < t_size); i++)
  1181. {
  1182. if (pItems[i] != 0)
  1183. {
  1184. m_aCmdType[j] = UI_COMMANDTYPE_ACTION;
  1185. m_auCmd[j++] = pItems[i];
  1186. }
  1187. }
  1188. if (j < t_size)
  1189. Resize(j);
  1190. }
  1191. HRESULT DoGetItem(UINT uItem, REFPROPERTYKEY key, PROPVARIANT *value)
  1192. {
  1193. ATLASSERT(uItem < m_size);
  1194. ATLASSERT(m_auCmd[uItem]);
  1195. HRESULT hr = E_FAIL;
  1196. switch (k_(key))
  1197. {
  1198. case k_CommandId:
  1199. hr = SetPropertyVal(key, m_auCmd[uItem], value);
  1200. break;
  1201. case k_CommandType:
  1202. hr = SetPropertyVal(key, UINT32(m_aCmdType[uItem]), value);
  1203. break;
  1204. case k_CategoryId:
  1205. hr = SetPropertyVal(key, UI_COLLECTION_INVALIDINDEX, value);
  1206. break;
  1207. default:
  1208. ATLASSERT(FALSE);
  1209. break;
  1210. }
  1211. return hr;
  1212. }
  1213. };
  1214. // SimpleCollectionCtrlImpl: base class for simple gallery and listbox controls
  1215. //
  1216. template <class T, UINT t_ID, size_t t_size, UI_COMMANDTYPE t_CommandType = UI_COMMANDTYPE_ACTION>
  1217. class SimpleCollectionCtrlImpl :
  1218. public CommandCtrlImpl<T, t_ID>,
  1219. public SimpleCollectionImpl<SimpleCollectionCtrlImpl<T, t_ID, t_size, t_CommandType>, t_size, t_CommandType>
  1220. {
  1221. typedef SimpleCollectionCtrlImpl<T, t_ID, t_size, t_CommandType> thisClass;
  1222. public:
  1223. typedef thisClass SimpleCollection;
  1224. SimpleCollectionCtrlImpl() : m_uSelected(0)
  1225. { }
  1226. UINT m_uSelected;
  1227. HRESULT Select(UINT uItem, bool bUpdate = false)
  1228. {
  1229. ATLASSERT((uItem < t_size) || (uItem == UI_COLLECTION_INVALIDINDEX));
  1230. m_uSelected = uItem;
  1231. return bUpdate ?
  1232. GetWndRibbon().SetProperty(GetID(), UI_PKEY_SelectedItem, uItem) :
  1233. S_OK;
  1234. }
  1235. // Implementation
  1236. virtual HRESULT DoUpdateProperty(UINT nCmdID, REFPROPERTYKEY key,
  1237. const PROPVARIANT* ppropvarCurrentValue, PROPVARIANT* ppropvarNewValue)
  1238. {
  1239. ATLASSERT(nCmdID == GetID());
  1240. ATLASSERT(ppropvarNewValue != NULL);
  1241. HRESULT hr = S_OK;
  1242. switch (k_(key))
  1243. {
  1244. case k_ItemsSource:
  1245. {
  1246. ATL::CComQIPtr<IUICollection> pIUICollection(ppropvarCurrentValue->punkVal);
  1247. ATLASSERT(pIUICollection.p);
  1248. hr = pIUICollection->Clear();
  1249. for (UINT i = 0; i < t_size; i++)
  1250. {
  1251. if FAILED(hr = pIUICollection->Add(m_apItems[i]))
  1252. break;
  1253. }
  1254. ATLASSERT(SUCCEEDED(hr));
  1255. }
  1256. break;
  1257. case k_SelectedItem:
  1258. hr = SetPropertyVal(UI_PKEY_SelectedItem, m_uSelected, ppropvarNewValue);
  1259. break;
  1260. default:
  1261. hr = CommandCtrlImpl::DoUpdateProperty(nCmdID, key, ppropvarCurrentValue, ppropvarNewValue);
  1262. break;
  1263. }
  1264. return hr;
  1265. }
  1266. virtual HRESULT DoExecute(UINT nCmdID, UI_EXECUTIONVERB verb,
  1267. const PROPERTYKEY* key, const PROPVARIANT* ppropvarValue,
  1268. IUISimplePropertySet* /*pCommandExecutionProperties*/)
  1269. {
  1270. ATLASSERT (nCmdID == GetID());
  1271. nCmdID; // avoid level 4 warning
  1272. HRESULT hr = S_OK;
  1273. if (key == NULL) // gallery button pressed
  1274. {
  1275. GetWndRibbon().OnRibbonItemSelected(GetID(), UI_EXECUTIONVERB_EXECUTE, UI_COLLECTION_INVALIDINDEX);
  1276. return hr;
  1277. }
  1278. ATLASSERT(k_(*key) == k_SelectedItem);
  1279. ATLASSERT(ppropvarValue);
  1280. if SUCCEEDED(hr = UIPropertyToUInt32(*key, *ppropvarValue, &m_uSelected))
  1281. GetWndRibbon().OnRibbonItemSelected(GetID(), verb, m_uSelected);
  1282. return hr;
  1283. }
  1284. };
  1285. // RecentItemsCtrlImpl
  1286. //
  1287. template <class T, UINT t_ID, class TDocList = CRecentDocumentList>
  1288. class RecentItemsCtrlImpl :
  1289. public CtrlImpl<T, t_ID>,
  1290. public CollectionImplBase<RecentItemsCtrlImpl<T, t_ID, TDocList>, TDocList::m_nMaxEntries_Max>,
  1291. public TDocList
  1292. {
  1293. typedef RecentItemsCtrlImpl<T, t_ID, TDocList> thisClass;
  1294. public:
  1295. typedef thisClass RecentItems;
  1296. // Implementation
  1297. HRESULT OnGetItem(UINT uItem, REFPROPERTYKEY key, PROPVARIANT *value)
  1298. {
  1299. ATLASSERT((INT)uItem < GetMaxEntries());
  1300. LPCWSTR sPath = m_arrDocs[uItem].szDocName;
  1301. HRESULT hr = E_NOTIMPL;
  1302. switch (k_(key))
  1303. {
  1304. case k_Label:
  1305. hr = SetPropertyVal(key, GetWndRibbon().OnRibbonQueryRecentItemName(sPath), value);
  1306. break;
  1307. case k_LabelDescription:
  1308. hr = SetPropertyVal(key, sPath, value);
  1309. break;
  1310. default:
  1311. ATLASSERT(FALSE);
  1312. break;
  1313. }
  1314. return hr;
  1315. }
  1316. virtual HRESULT DoUpdateProperty(UINT nCmdID, REFPROPERTYKEY key,
  1317. const PROPVARIANT* ppropvarCurrentValue, PROPVARIANT* ppropvarNewValue)
  1318. {
  1319. ATLASSERT(nCmdID == GetID());
  1320. ATLASSERT(ppropvarNewValue);
  1321. HRESULT hr = S_OK;
  1322. switch (k_(key))
  1323. {
  1324. case k_RecentItems:
  1325. if (SAFEARRAY* psa = SafeArrayCreateVector(VT_UNKNOWN, 0, m_arrDocs.GetSize()))
  1326. {
  1327. const int iLastIndex = m_arrDocs.GetSize() - 1;
  1328. for (LONG i = 0; i <= iLastIndex; i++)
  1329. SafeArrayPutElement(psa, &i, m_apItems[iLastIndex - i]); // reverse order
  1330. hr = SetPropertyVal(key, psa, ppropvarNewValue);
  1331. SafeArrayDestroy(psa);
  1332. }
  1333. break;
  1334. default:
  1335. hr = CtrlImpl::DoUpdateProperty(nCmdID, key, ppropvarCurrentValue, ppropvarNewValue);
  1336. break;
  1337. }
  1338. return hr;
  1339. }
  1340. virtual HRESULT DoExecute(UINT nCmdID, UI_EXECUTIONVERB verb,
  1341. const PROPERTYKEY* key, const PROPVARIANT* ppropvarValue,
  1342. IUISimplePropertySet* /*pCommandExecutionProperties*/)
  1343. {
  1344. ATLASSERT(nCmdID == GetID());
  1345. nCmdID; // avoid level 4 warning
  1346. ATLASSERT(verb == UI_EXECUTIONVERB_EXECUTE);
  1347. verb; // avoid level 4 warning
  1348. ATLASSERT((key) && (k_(*key) == k_SelectedItem));
  1349. ATLASSERT(ppropvarValue);
  1350. UINT32 uSel = 0xffff;
  1351. HRESULT hr = UIPropertyToUInt32(*key, *ppropvarValue, &uSel);
  1352. if SUCCEEDED(hr)
  1353. {
  1354. ATLASSERT(uSel < (UINT)GetMaxEntries());
  1355. GetWndRibbon().DefCommandExecute(ID_FILE_MRU_FIRST + uSel);
  1356. }
  1357. return hr;
  1358. }
  1359. };
  1360. ///////////////////////////////////////////////////////////////////////////////
  1361. // Ribbon stand-alone control classes
  1362. // FontCtrlImpl
  1363. //
  1364. template <class T, UINT t_ID>
  1365. class FontCtrlImpl : public CtrlImpl<T, t_ID>
  1366. {
  1367. public:
  1368. CharFormat m_cf;
  1369. // Implementation
  1370. virtual HRESULT DoExecute(UINT nCmdID, UI_EXECUTIONVERB verb,
  1371. const PROPERTYKEY* key, const PROPVARIANT* ppropvarValue,
  1372. IUISimplePropertySet* pCommandExecutionProperties)
  1373. {
  1374. ATLASSERT (nCmdID == GetID());
  1375. nCmdID; // avoid level 4 warning
  1376. ATLASSERT ((key) && (k_(*key) == k_FontProperties));
  1377. key; // avoid level 4 warning
  1378. HRESULT hr = E_INVALIDARG;
  1379. switch (verb)
  1380. {
  1381. case UI_EXECUTIONVERB_PREVIEW:
  1382. case UI_EXECUTIONVERB_EXECUTE:
  1383. ATLASSERT(pCommandExecutionProperties);
  1384. PROPVARIANT propvar;
  1385. if (SUCCEEDED(hr = pCommandExecutionProperties->GetValue(UI_PKEY_FontProperties_ChangedProperties, &propvar)))
  1386. m_cf << ATL::CComQIPtr<IPropertyStore>(propvar.punkVal);
  1387. break;
  1388. case UI_EXECUTIONVERB_CANCELPREVIEW:
  1389. ATLASSERT(ppropvarValue);
  1390. ATL::CComPtr<IPropertyStore> pStore;
  1391. if (SUCCEEDED(hr = UIPropertyToInterface(UI_PKEY_FontProperties, *ppropvarValue, &pStore)))
  1392. m_cf << pStore;
  1393. break;
  1394. }
  1395. if (SUCCEEDED(hr))
  1396. GetWndRibbon().OnRibbonFontCtrlExecute(GetID(), verb, &m_cf);
  1397. else
  1398. ATLASSERT(FALSE);
  1399. return hr;
  1400. }
  1401. virtual HRESULT DoUpdateProperty(UINT nCmdID, REFPROPERTYKEY key,
  1402. const PROPVARIANT* ppropvarCurrentValue, PROPVARIANT* ppropvarNewValue)
  1403. {
  1404. if ((k_(key) == k_FontProperties) && (GetWndRibbon().OnRibbonQueryFont(t_ID, m_cf)))
  1405. {
  1406. ATL::CComQIPtr<IPropertyStore> pStore(ppropvarCurrentValue->punkVal);
  1407. m_cf >> pStore;
  1408. return SetPropertyVal(key, pStore.p, ppropvarNewValue);
  1409. }
  1410. else
  1411. {
  1412. return CtrlImpl::DoUpdateProperty(nCmdID, key, ppropvarCurrentValue, ppropvarNewValue);
  1413. }
  1414. }
  1415. };
  1416. // ColorCtrlImpl
  1417. //
  1418. template <class T, UINT t_ID>
  1419. class ColorCtrlImpl : public CommandCtrlImpl<T, t_ID>
  1420. {
  1421. public:
  1422. ColorCtrlImpl() : m_colorType(UI_SWATCHCOLORTYPE_NOCOLOR), m_color(0x800080) /*MAGENTA*/
  1423. { }
  1424. COLORREF m_color;
  1425. UINT32 m_colorType; // value in UI_SWATCHCOLORTYPE
  1426. Text m_sLabels[6]; // k_MoreColorsLabel to k_ThemeColorsCategoryLabel
  1427. ATL::CSimpleArray<COLORREF> m_aColors[2];
  1428. ATL::CSimpleArray<LPCWSTR> m_aTooltips[2];
  1429. // Operations
  1430. HRESULT SetColor(COLORREF color, bool bUpdate = false)
  1431. {
  1432. if (m_colorType != UI_SWATCHCOLORTYPE_RGB)
  1433. SetColorType(UI_SWATCHCOLORTYPE_RGB, bUpdate);
  1434. m_color = color;
  1435. return bUpdate ? SetProperty(UI_PKEY_Color, color) : S_OK;
  1436. }
  1437. HRESULT SetColorType(UI_SWATCHCOLORTYPE type, bool bUpdate = false)
  1438. {
  1439. m_colorType = type;
  1440. return bUpdate ? SetProperty(UI_PKEY_ColorType, type) : S_OK;
  1441. }
  1442. HRESULT SetColorLabel(REFPROPERTYKEY key, LPCWSTR sLabel, bool bUpdate = false)
  1443. {
  1444. ATLASSERT((k_(key) >= k_ThemeColorsCategoryLabel) && (k_(key) <= k_MoreColorsLabel));
  1445. m_sLabels[k_(key) - k_ThemeColorsCategoryLabel] = sLabel;
  1446. return bUpdate ? SetProperty(key, sLabel) : S_OK;
  1447. }
  1448. HRESULT SetColorArray(REFPROPERTYKEY key, COLORREF* pColor, bool bUpdate = false)
  1449. {
  1450. ATLASSERT((k_(key) == k_ThemeColors) || (k_(key) == k_StandardColors));
  1451. const INT ic = k_(key) - k_ThemeColors;
  1452. m_aColors[ic].RemoveAll();
  1453. while (*pColor != 0x800080) /*MAGENTA*/
  1454. m_aColors[ic].Add(*pColor++);
  1455. if (bUpdate)
  1456. {
  1457. PROPVARIANT var;
  1458. if SUCCEEDED(InitPropVariantFromUInt32Vector(m_aColors[ic].GetData(), m_aColors[ic].GetSize(), &var))
  1459. return SetProperty(key, var);
  1460. else
  1461. return E_INVALIDARG;
  1462. }
  1463. else
  1464. {
  1465. return S_OK;
  1466. }
  1467. }
  1468. HRESULT SetColorTooltips(REFPROPERTYKEY key, LPCWSTR* ppsTT, bool bUpdate = false)
  1469. {
  1470. ATLASSERT((k_(key) == k_ThemeColorsTooltips) || (k_(key) == k_StandardColorsTooltips));
  1471. const INT ic = k_(key) - k_ThemeColorsTooltips;
  1472. m_aTooltips[ic].RemoveAll();
  1473. while (*ppsTT)
  1474. m_aTooltips[ic].Add(*ppsTT++);
  1475. if (bUpdate)
  1476. {
  1477. PROPVARIANT var;
  1478. if SUCCEEDED(InitPropVariantFromStringVector(m_aTooltips[ic].GetData(), m_aTooltips[ic].GetSize(), &var))
  1479. return SetProperty(key, var);
  1480. else
  1481. return E_INVALIDARG;
  1482. }
  1483. else
  1484. {
  1485. return S_OK;
  1486. }
  1487. }
  1488. // Implementation
  1489. virtual HRESULT DoExecute(UINT nCmdID, UI_EXECUTIONVERB verb,
  1490. const PROPERTYKEY* key, const PROPVARIANT* ppropvarValue,
  1491. IUISimplePropertySet* pCommandExecutionProperties)
  1492. {
  1493. ATLASSERT (nCmdID == GetID());
  1494. nCmdID; // avoid level 4 warning
  1495. ATLASSERT (key && (k_(*key) == k_ColorType));
  1496. key; // avoid level 4 warning
  1497. ATLASSERT (ppropvarValue);
  1498. HRESULT hr = PropVariantToUInt32(*ppropvarValue, &m_colorType);
  1499. ATLASSERT(SUCCEEDED(hr));
  1500. if (SUCCEEDED(hr