PageRenderTime 143ms CodeModel.GetById 85ms app.highlight 49ms RepoModel.GetById 0ms app.codeStats 1ms

/3rd_party/wtl/Include/atlribbon.h

https://code.google.com/p/softart/
C++ Header | 3446 lines | 2686 code | 533 blank | 227 comment | 429 complexity | c9eaf028c94020793111b9ac5f0efb9e MD5 | raw file
Possible License(s): LGPL-2.1, BSD-3-Clause, JSON, MPL-2.0-no-copyleft-exception, GPL-2.0, GPL-3.0, LGPL-3.0, BSD-2-Clause

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

Large files files are truncated, but you can click here to view the full file