1 // Windows Template Library - WTL version 9.10
2 // Copyright (C) Microsoft Corporation, WTL Team. 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 // Microsoft Public License (http://opensource.org/licenses/MS-PL)
7 // which can be found in the file MS-PL.txt at the root folder.
8 
9 #ifndef __ATLRIBBON_H__
10 #define __ATLRIBBON_H__
11 
12 #pragma once
13 
14 #if (_MSC_VER < 1500)
15 	#error atlribbon.h requires Visual C++ 2008 compiler or higher
16 #endif
17 
18 #ifndef _UNICODE
19 	#error atlribbon.h requires the Unicode character set
20 #endif
21 
22 #if !defined(NTDDI_WIN7) || (NTDDI_VERSION < NTDDI_WIN7)
23 	#error atlribbon.h requires the Windows 7 SDK or higher
24 #endif
25 
26 #ifdef _WIN32_WCE
27 	#error atlribbon.h is not supported on Windows CE
28 #endif
29 
30 #ifndef __ATLAPP_H__
31 	#error atlribbon.h requires atlapp.h to be included first
32 #endif
33 
34 #if (_ATL_VER < 0x0700)
35   #include <shlwapi.h>
36   #pragma comment(lib, "shlwapi.lib")
37 #endif
38 
39 #include <atlmisc.h>    // for RecentDocumentList classes
40 #include <atlframe.h>   // for Frame and UpdateUI classes
41 #include <atlctrls.h>   // required for atlctrlw.h
42 #include <atlctrlw.h>   // for CCommandBarCtrl
43 
44 #if !defined(_WTL_USE_CSTRING) && !defined(__ATLSTR_H__)
45   #pragma warning(push)
46   #pragma warning(disable: 4530)   // unwind semantics not enabled
47   #include <string>
48   #pragma warning(pop)
49 #endif
50 
51 #include <dwmapi.h>
52 #pragma comment(lib, "dwmapi.lib")
53 
54 #include <UIRibbon.h>
55 #include <UIRibbonPropertyHelpers.h>
56 #pragma comment(lib, "propsys.lib")
57 
58 #include <Richedit.h>   // for CHARFORMAT2
59 
60 
61 ///////////////////////////////////////////////////////////////////////////////
62 // Classes in this file:
63 //
64 // CRibbonUpdateUI : Automatic mapping of ribbon UI elements
65 //
66 // RibbonUI::Text
67 // RibbonUI::CharFormat
68 // RibbonUI::ICtrl
69 // RibbonUI::CtrlImpl
70 // RibbonUI::CommandCtrlImpl
71 // RibbonUI::ItemProperty
72 // RibbonUI::CollectionImplBase
73 // RibbonUI::CollectionImpl
74 // RibbonUI::TextCollectionImpl
75 // RibbonUI::ItemCollectionImpl
76 // RibbonUI::ComboCollectionImpl
77 // RibbonUI::CommandCollectionImpl
78 // RibbonUI::ToolbarCollectionImpl
79 // RibbonUI::SimpleCollectionImpl
80 // RibbonUI::CollectionCtrlImpl
81 // RibbonUI::ToolbarGalleryCtrlImpl
82 // RibbonUI::SimpleCollectionCtrlImpl
83 // RibbonUI::RecentItemsCtrlImpl
84 // RibbonUI::FontCtrlImpl
85 // RibbonUI::ColorCtrlImpl
86 // RibbonUI::SpinnerCtrlImpl
87 //
88 // RibbonUI::CRibbonImpl
89 //	 CRibbonImpl::CRibbonComboCtrl
90 //	 CRibbonImpl::CRibbonItemGalleryCtrl
91 //	 CRibbonImpl::CRibbonCommandGalleryCtrl
92 //	 CRibbonImpl::CRibbonToolbarGalleryCtrl
93 //	 CRibbonImpl::CRibbonSimpleComboCtrl
94 //	 CRibbonImpl::CRibbonSimpleGalleryCtrl
95 //	 CRibbonImpl::CRibbonRecentItemsCtrl
96 //	 CRibbonImpl::CRibbonColorCtrl
97 //	 CRibbonImpl::CRibbonFontCtrl
98 //	 CRibbonImpl::CRibbonSpinnerCtrl
99 //	 CRibbonImpl::CRibbonFloatSpinnerCtrl
100 //	 CRibbonImpl::CRibbonCommandCtrl
101 //
102 // CRibbonFrameWindowImplBase
103 // CRibbonFrameWindowImpl
104 // CRibbonMDIFrameWindowImpl
105 // CRibbonPersist
106 //
107 // Global functions:
108 //   RibbonUI::SetPropertyVal()
109 //   RibbonUI::GetImage()
110 
111 
112 // Constants
113 
114 #ifndef RIBBONUI_MAX_TEXT
115   #define RIBBONUI_MAX_TEXT 128
116 #endif
117 
118 #define TWIPS_PER_POINT 20   // For font size
119 
120 
121 namespace WTL
122 {
123 
124 ///////////////////////////////////////////////////////////////////////////////
125 // CRibbonUpdateUI : Automatic mapping of ribbon UI elements
126 
127 template <class T>
128 class CRibbonUpdateUI : public CAutoUpdateUI<T>
129 {
130 public:
131 	enum
132 	{
133 		UPDUI_RIBBON = 0x0080,
134 		UPDUI_PERSIST = 0x0020
135 	};
136 
IsRibbonElement(const _AtlUpdateUIMap & UIMap)137 	bool IsRibbonElement(const _AtlUpdateUIMap& UIMap)
138 	{
139 		return (UIMap.m_wType & UPDUI_RIBBON) != 0;
140 	}
141 
IsRibbonID(UINT nID)142 	bool IsRibbonID(UINT nID)
143 	{
144 		for(int i = 0; i < m_arrUIMap.GetSize(); i++)
145 		{
146 			if(m_arrUIMap[i].m_nID == nID)
147 				return IsRibbonElement(m_arrUIMap[i]);
148 		}
149 
150 		return false;
151 	}
152 
153 // Element
UIAddRibbonElement(UINT nID)154 	bool UIAddRibbonElement(UINT nID)
155 	{
156 		return UIAddElement<UPDUI_RIBBON>(nID);
157 	}
158 
UIRemoveRibbonElement(UINT nID)159 	bool UIRemoveRibbonElement(UINT nID)
160 	{
161 		return UIRemoveElement<UPDUI_RIBBON>(nID);
162 	}
163 
164 	bool UIPersistElement(UINT nID, bool bPersist = true)
165 	{
166 		return bPersist ?
167 			UIAddElement<UPDUI_PERSIST>(nID) :
168 			UIRemoveElement<UPDUI_PERSIST>(nID);
169 	}
170 
171 // methods for Ribbon elements
172 	BOOL UISetText(int nID, LPCWSTR sText, BOOL bForceUpdate = FALSE)
173 	{
174 		T* pT = static_cast<T*>(this);
175 		BOOL bRes = CUpdateUIBase::UISetText(nID, sText, bForceUpdate);
176 		if (pT->IsRibbonUI() && IsRibbonID(nID))
177 			bRes = SUCCEEDED(pT->InvalidateProperty(nID, UI_PKEY_Label));
178 		return bRes;
179 	}
180 
181 	BOOL UISetText(int nID, UINT uIdResource, BOOL bForceUpdate = FALSE)
182 	{
183 		CTempBuffer<WCHAR> sText(RIBBONUI_MAX_TEXT);
184 		int nRet = AtlLoadString(uIdResource, sText, RIBBONUI_MAX_TEXT);
185 		if(nRet > 0)
186 			UISetText(nID, sText, bForceUpdate);
187 		return (nRet > 0) ? TRUE : FALSE;
188 	}
189 
UIGetText(int nID)190 	LPCTSTR UIGetText(int nID)
191 	{
192 		T* pT = static_cast<T*>(this);
193 		LPCTSTR sUI = CAutoUpdateUI::UIGetText(nID);
194 
195 		// replace 'tab' by 'space' for RibbonUI elements
196 		if (sUI && pT->IsRibbonUI() && IsRibbonID(nID) && wcschr(sUI, L'\t'))
197 		{
198 			static WCHAR sText[RIBBONUI_MAX_TEXT] = { 0 };
199 			wcscpy_s(sText, sUI);
200 			WCHAR* pch = wcschr(sText, L'\t');
201 			if (pch != NULL)
202 				*pch = L' ';
203 			return sText;
204 		}
205 		else
206 		{
207 			return sUI;
208 		}
209 	}
210 
211 	BOOL UIEnable(int nID, BOOL bEnable, BOOL bForceUpdate = FALSE)
212 	{
213 		T* pT = static_cast<T*>(this);
214 		BOOL bRes = CUpdateUIBase::UIEnable(nID, bEnable, bForceUpdate);
215 		if (pT->IsRibbonUI() && IsRibbonID(nID))
216 			bRes = SUCCEEDED(pT->SetProperty((WORD)nID, UI_PKEY_Enabled, bEnable));
217 		return bRes;
218 	}
219 
220 	BOOL UISetCheck(int nID, INT nCheck, BOOL bForceUpdate = FALSE)
221 	{
222 		if ((nCheck == 0) || (nCheck == 1))
223 			return UISetCheck(nID, nCheck != 0, bForceUpdate);
224 		else
225 			return CUpdateUIBase::UISetCheck(nID, nCheck, bForceUpdate);
226 	}
227 
228 	BOOL UISetCheck(int nID, bool bCheck, BOOL bForceUpdate = FALSE)
229 	{
230 		T* pT = static_cast<T*>(this);
231 		BOOL bRes = CUpdateUIBase::UISetCheck(nID, bCheck, bForceUpdate);
232 		if (bRes && pT->IsRibbonUI() && IsRibbonID(nID))
233 			bRes = SUCCEEDED(pT->SetProperty((WORD)nID, UI_PKEY_BooleanValue, bCheck));
234 		return bRes;
235 	}
236 };
237 
238 
239 ///////////////////////////////////////////////////////////////////////////////
240 // RibbonUI namespace
241 //
242 
243 namespace RibbonUI
244 {
245 
246 // Minimal string allocation support for various PROPERTYKEY values
247 #if defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__)
248   typedef _CSTRING_NS::CString Text;
249 #else
250   class Text : public std::wstring
251   {
252   public:
253 	Text(std::wstring& s) : std::wstring(s)
254 	{ }
255 	Text(LPCWSTR s) : std::wstring(s)
256 	{ }
257 	Text()
258 	{ }
259 	bool IsEmpty()
260 	{
261 		return empty();
262 	}
263 	operator LPCWSTR()
264 	{
265 		return c_str();
266 	}
267 	Text& operator =(LPCWSTR s)
268 	{
269 		return static_cast<Text&>(std::wstring::operator =(s));
270 	}
271   };
272 #endif
273 
274 // PROPERTYKEY enum and helpers
275 enum k_KEY
276 {
277 	// state
278 	k_Enabled = 1, k_BooleanValue = 200,
279 	// text properties
280 	k_LabelDescription = 2, k_Keytip = 3, k_Label = 4, k_TooltipDescription = 5, k_TooltipTitle = 6,
281 	// image properties
282 	k_LargeImage = 7, k_LargeHighContrastImage = 8, k_SmallImage = 9, k_SmallHighContrastImage = 10,
283 	// collection properties
284 	k_ItemsSource = 101, k_Categories = 102, k_SelectedItem = 104,
285 	// collection item properties
286 	k_CommandId = 100, k_CategoryId = 103, k_CommandType = 105, k_ItemImage = 106,
287 	// combo control property
288 	k_StringValue = 202,
289 	// spinner control properties
290 	k_DecimalValue = 201, k_MaxValue = 203, k_MinValue, k_Increment, k_DecimalPlaces, k_FormatString, k_RepresentativeString = 208,
291 	// font control properties
292 	k_FontProperties = 300, k_FontProperties_Family, k_FontProperties_Size, k_FontProperties_Bold, k_FontProperties_Italic = 304,
293 	k_FontProperties_Underline = 305, k_FontProperties_Strikethrough, k_FontProperties_VerticalPositioning, k_FontProperties_ForegroundColor = 308,
294 	k_FontProperties_BackgroundColor = 309, k_FontProperties_ForegroundColorType, k_FontProperties_BackgroundColorType, k_FontProperties_ChangedProperties = 312,
295 	k_FontProperties_DeltaSize = 313,
296 	// recent items properties
297 	k_RecentItems = 350, k_Pinned = 351,
298 	// color control properties
299 	k_Color = 400, k_ColorType = 401, k_ColorMode,
300 	k_ThemeColorsCategoryLabel = 403, k_StandardColorsCategoryLabel, k_RecentColorsCategoryLabel = 405, k_AutomaticColorLabel = 406,
301 	k_NoColorLabel = 407, k_MoreColorsLabel = 408,
302 	k_ThemeColors = 409, k_StandardColors = 410, k_ThemeColorsTooltips = 411, k_StandardColorsTooltips = 412,
303 	// Ribbon state
304 	k_Viewable = 1000, k_Minimized = 1001, k_QuickAccessToolbarDock = 1002, k_ContextAvailable = 1100,
305 	// Ribbon UI colors
306 	k_GlobalBackgroundColor = 2000, k_GlobalHighlightColor, k_GlobalTextColor = 2002
307 };
308 
k_(REFPROPERTYKEY key)309 inline k_KEY k_(REFPROPERTYKEY key)
310 {
311 	return (k_KEY)key.fmtid.Data1;
312 }
313 
314 // PROPERTYKEY value assignment and specializations
315 //
316 template <typename V>
SetPropertyVal(REFPROPERTYKEY key,V val,PROPVARIANT * ppv)317 HRESULT SetPropertyVal(REFPROPERTYKEY key, V val, PROPVARIANT* ppv)
318 {
319 	switch (k_(key))
320 	{
321 	case k_Enabled:
322 	case k_BooleanValue:
323 		return InitPropVariantFromBoolean(val, ppv);
324 	default:
325 		return UIInitPropertyFromUInt32(key, val, ppv);
326 	}
327 }
328 
SetPropertyVal(REFPROPERTYKEY key,DOUBLE val,PROPVARIANT * ppv)329 inline HRESULT SetPropertyVal(REFPROPERTYKEY key, DOUBLE val, PROPVARIANT* ppv)
330 {
331 	return SetPropertyVal(key, (LONG)val, ppv);
332 }
333 
SetPropertyVal(REFPROPERTYKEY key,IUIImage * val,PROPVARIANT * ppv)334 inline HRESULT SetPropertyVal(REFPROPERTYKEY key, IUIImage* val, PROPVARIANT* ppv)
335 {
336 	HRESULT hr = UIInitPropertyFromImage(key, val, ppv);
337 	ATLVERIFY(val->Release() == 1);
338 	return hr;
339 }
340 
SetPropertyVal(REFPROPERTYKEY key,IUnknown * val,PROPVARIANT * ppv)341 inline HRESULT SetPropertyVal(REFPROPERTYKEY key, IUnknown* val, PROPVARIANT* ppv)
342 {
343 	return UIInitPropertyFromInterface(key, val, ppv);
344 }
345 
SetPropertyVal(REFPROPERTYKEY key,IPropertyStore * val,PROPVARIANT * ppv)346 inline HRESULT SetPropertyVal(REFPROPERTYKEY key, IPropertyStore* val, PROPVARIANT* ppv)
347 {
348 	return UIInitPropertyFromInterface(key, val, ppv);
349 }
350 
SetPropertyVal(REFPROPERTYKEY key,SAFEARRAY * val,PROPVARIANT * ppv)351 inline HRESULT SetPropertyVal(REFPROPERTYKEY key, SAFEARRAY* val, PROPVARIANT* ppv)
352 {
353 	return UIInitPropertyFromIUnknownArray(key, val, ppv);
354 }
355 
SetPropertyVal(REFPROPERTYKEY key,DECIMAL * val,PROPVARIANT * ppv)356 inline HRESULT SetPropertyVal(REFPROPERTYKEY key, DECIMAL* val, PROPVARIANT* ppv)
357 {
358 	return UIInitPropertyFromDecimal(key, *val, ppv);
359 }
360 
SetPropertyVal(REFPROPERTYKEY key,bool val,PROPVARIANT * ppv)361 inline HRESULT SetPropertyVal(REFPROPERTYKEY key, bool val, PROPVARIANT* ppv)
362 {
363 	return UIInitPropertyFromBoolean(key, val, ppv);
364 }
365 
SetPropertyVal(REFPROPERTYKEY key,LPCWSTR val,PROPVARIANT * ppv)366 inline HRESULT SetPropertyVal(REFPROPERTYKEY key, LPCWSTR val, PROPVARIANT* ppv)
367 {
368 	return UIInitPropertyFromString(key, val, ppv);
369 }
370 
371 // CharFormat helper struct for RibbonUI font control
372 //
373 struct CharFormat : CHARFORMAT2
374 {
375 	// Default constructor
CharFormatCharFormat376 	CharFormat()
377 	{
378 		cbSize = sizeof(CHARFORMAT2);
379 		Reset();
380 	}
381 
382 	// Copy constructor
CharFormatCharFormat383 	CharFormat(const CharFormat& cf)
384 	{
385 		::CopyMemory(this, &cf, sizeof(CHARFORMAT2));
386 	}
387 
388 	// Assign operator
389 	CharFormat& operator =(const CharFormat& cf)
390 	{
391 		::CopyMemory(this, &cf, sizeof(CHARFORMAT2));
392 		return (*this);
393 	}
394 
ResetCharFormat395 	void Reset()
396 	{
397 		uValue = dwMask = dwEffects = 0;
398 		PropVariantInit(&propvar);
399 	}
400 
401 	void operator <<(IPropertyStore* pStore)
402 	{
403 		if (pStore == NULL)
404 		{
405 			ATLASSERT(FALSE);
406 			return;
407 		}
408 
409 		static void (CharFormat::*Getk_[])(IPropertyStore*) =
410 		{
411 			&CharFormat::Getk_Family,
412 			&CharFormat::Getk_FontProperties_Size,
413 			&CharFormat::Getk_MaskEffect<CFM_BOLD, CFE_BOLD, UI_PKEY_FontProperties_Bold>,
414 			&CharFormat::Getk_MaskEffect<CFM_ITALIC, CFE_ITALIC, UI_PKEY_FontProperties_Italic>,
415 			&CharFormat::Getk_MaskEffect<CFM_UNDERLINE, CFE_UNDERLINE, UI_PKEY_FontProperties_Underline>,
416 			&CharFormat::Getk_MaskEffect<CFM_STRIKEOUT, CFE_STRIKEOUT, UI_PKEY_FontProperties_Strikethrough>,
417 			&CharFormat::Getk_VerticalPositioning,
418 			&CharFormat::Getk_Color<CFM_COLOR, UI_PKEY_FontProperties_ForegroundColor>,
419 			&CharFormat::Getk_Color<CFM_BACKCOLOR, UI_PKEY_FontProperties_BackgroundColor>,
420 			&CharFormat::Getk_ColorType<CFM_COLOR, CFE_AUTOCOLOR, UI_SWATCHCOLORTYPE_AUTOMATIC, UI_PKEY_FontProperties_ForegroundColorType>,
421 			&CharFormat::Getk_ColorType<CFM_BACKCOLOR, CFE_AUTOBACKCOLOR, UI_SWATCHCOLORTYPE_NOCOLOR, UI_PKEY_FontProperties_BackgroundColorType>,
422 		};
423 
424 		DWORD nProps = 0;
425 		Reset();
426 
427 		ATLVERIFY(SUCCEEDED(pStore->GetCount(&nProps)));
428 		for (DWORD iProp = 0; iProp < nProps; iProp++)
429 		{
430 			PROPERTYKEY key;
431 			ATLVERIFY(SUCCEEDED(pStore->GetAt(iProp, &key)));
432 			ATLASSERT(k_(key) >= k_FontProperties_Family);
433 
434 			if (k_(key) <= k_FontProperties_BackgroundColorType)
435 				(this->*Getk_[k_(key) - k_FontProperties_Family])(pStore);
436 		}
437 	}
438 
439 	void operator >>(IPropertyStore* pStore)
440 	{
441 		if (pStore == NULL)
442 		{
443 			ATLASSERT(FALSE);
444 			return;
445 		}
446 
447 		PutFace(pStore);
448 		PutSize(pStore);
449 		PutMaskEffect(CFM_BOLD, CFE_BOLD, UI_PKEY_FontProperties_Bold, pStore);
450 		PutMaskEffect(CFM_ITALIC, CFE_ITALIC, UI_PKEY_FontProperties_Italic, pStore);
451 		PutMaskEffect(CFM_UNDERLINE, CFE_UNDERLINE, UI_PKEY_FontProperties_Underline, pStore);
452 		PutMaskEffect(CFM_STRIKEOUT, CFE_STRIKEOUT, UI_PKEY_FontProperties_Strikethrough, pStore);
453 		PutVerticalPos(pStore);
454 		PutColor(pStore);
455 		PutBackColor(pStore);
456 	}
457 
458 private:
459 	PROPVARIANT propvar;
460 	UINT uValue;
461 
462 	// Getk_ functions
Getk_FamilyCharFormat463 	void Getk_Family(IPropertyStore* pStore)
464 	{
465 		if (SUCCEEDED(pStore->GetValue(UI_PKEY_FontProperties_Family, &propvar)))
466 		{
467 			PropVariantToString(propvar, szFaceName, LF_FACESIZE);
468 			if (*szFaceName)
469 				dwMask |= CFM_FACE;
470 		}
471 	}
472 
Getk_FontProperties_SizeCharFormat473 	void Getk_FontProperties_Size(IPropertyStore* pStore)
474 	{
475 		if (SUCCEEDED(pStore->GetValue(UI_PKEY_FontProperties_Size, &propvar)))
476 		{
477 			DECIMAL decSize = { 0 };
478 			UIPropertyToDecimal(UI_PKEY_FontProperties_Size, propvar, &decSize);
479 			DOUBLE dSize = 0;
480 			VarR8FromDec(&decSize, &dSize);
481 			if (dSize > 0)
482 			{
483 				dwMask |= CFM_SIZE;
484 				yHeight = (LONG)(dSize * TWIPS_PER_POINT);
485 			}
486 		}
487 	}
488 
489 	template <DWORD t_dwMask, DWORD t_dwEffects, REFPROPERTYKEY key>
Getk_MaskEffectCharFormat490 	void Getk_MaskEffect(IPropertyStore* pStore)
491 	{
492 		if (SUCCEEDED(pStore->GetValue(key, &propvar)))
493 		{
494 			UIPropertyToUInt32(key, propvar, &uValue);
495 			if ((UI_FONTPROPERTIES)uValue != UI_FONTPROPERTIES_NOTAVAILABLE)
496 			{
497 				dwMask |= t_dwMask;
498 				dwEffects |= ((UI_FONTPROPERTIES) uValue == UI_FONTPROPERTIES_SET) ? t_dwEffects : 0;
499 			}
500 		}
501 	}
502 
Getk_VerticalPositioningCharFormat503 	void Getk_VerticalPositioning(IPropertyStore* pStore)
504 	{
505 		if (SUCCEEDED(pStore->GetValue(UI_PKEY_FontProperties_VerticalPositioning, &propvar)))
506 		{
507 			UIPropertyToUInt32(UI_PKEY_FontProperties_VerticalPositioning, propvar, &uValue);
508 			UI_FONTVERTICALPOSITION uVerticalPosition = (UI_FONTVERTICALPOSITION) uValue;
509 			if ((uVerticalPosition != UI_FONTVERTICALPOSITION_NOTAVAILABLE))
510 			{
511 				dwMask |= (CFM_SUPERSCRIPT | CFM_SUBSCRIPT);
512 				if (uVerticalPosition != UI_FONTVERTICALPOSITION_NOTSET)
513 				{
514 					dwEffects |= (uVerticalPosition == UI_FONTVERTICALPOSITION_SUPERSCRIPT) ? CFE_SUPERSCRIPT : CFE_SUBSCRIPT;
515 				}
516 			}
517 		}
518 	}
519 
520 	template <DWORD t_dwMask, REFPROPERTYKEY key>
Getk_ColorCharFormat521 	void Getk_Color(IPropertyStore* pStore)
522 	{
523 		UINT32 color = 0;
524 		if (SUCCEEDED(pStore->GetValue(key, &propvar)))
525 		{
526 			UIPropertyToUInt32(key, propvar, &color);
527 			dwMask |= t_dwMask;
528 
529 			if (t_dwMask == CFM_COLOR)
530 				crTextColor = color;
531 			else
532 				crBackColor = color;
533 		}
534 	}
535 
536 	template <DWORD t_dwMask, DWORD t_dwEffects, UI_SWATCHCOLORTYPE t_type, REFPROPERTYKEY key>
Getk_ColorTypeCharFormat537 	void Getk_ColorType(IPropertyStore* pStore)
538 	{
539 		if (SUCCEEDED(pStore->GetValue(key, &propvar)))
540 		{
541 			UIPropertyToUInt32(key, propvar, &uValue);
542 			if (t_type == (UI_SWATCHCOLORTYPE)uValue)
543 			{
544 				dwMask |= t_dwMask;
545 				dwEffects |= t_dwEffects;
546 			}
547 		}
548 	}
549 
550 	// Put functions
PutMaskEffectCharFormat551 	void PutMaskEffect(WORD dwMaskVal, WORD dwEffectVal, REFPROPERTYKEY key, IPropertyStore* pStore)
552 	{
553 		PROPVARIANT var;
554 		UI_FONTPROPERTIES uProp = UI_FONTPROPERTIES_NOTAVAILABLE;
555 		if ((dwMask & dwMaskVal) != 0)
556 			uProp = dwEffects & dwEffectVal ? UI_FONTPROPERTIES_SET : UI_FONTPROPERTIES_NOTSET;
557 		SetPropertyVal(key, uProp, &var);
558 		pStore->SetValue(key, var);
559 	}
560 
PutVerticalPosCharFormat561 	void PutVerticalPos(IPropertyStore* pStore)
562 	{
563 		PROPVARIANT var;
564 		UI_FONTVERTICALPOSITION uProp = UI_FONTVERTICALPOSITION_NOTAVAILABLE;
565 
566 		if ((dwMask & CFE_SUBSCRIPT) != 0)
567 		{
568 			if ((dwMask & CFM_SUBSCRIPT) && (dwEffects & CFE_SUBSCRIPT))
569 				uProp = UI_FONTVERTICALPOSITION_SUBSCRIPT;
570 			else
571 				uProp = UI_FONTVERTICALPOSITION_SUPERSCRIPT;
572 		}
573 		else if ((dwMask & CFM_OFFSET) != 0)
574 		{
575 			if (yOffset > 0)
576 				uProp = UI_FONTVERTICALPOSITION_SUPERSCRIPT;
577 			else if (yOffset < 0)
578 				uProp = UI_FONTVERTICALPOSITION_SUBSCRIPT;
579 		}
580 
581 		SetPropertyVal(UI_PKEY_FontProperties_VerticalPositioning, uProp, &var);
582 		pStore->SetValue(UI_PKEY_FontProperties_VerticalPositioning, var);
583 	}
584 
PutFaceCharFormat585 	void PutFace(IPropertyStore* pStore)
586 	{
587 		PROPVARIANT var;
588 		SetPropertyVal(UI_PKEY_FontProperties_Family,
589 			dwMask & CFM_FACE ? szFaceName : L"", &var);
590 		pStore->SetValue(UI_PKEY_FontProperties_Family, var);
591 	}
592 
PutSizeCharFormat593 	void PutSize(IPropertyStore* pStore)
594 	{
595 		PROPVARIANT var;
596 		DECIMAL decVal;
597 
598 		if ((dwMask & CFM_SIZE) != 0)
599 			VarDecFromR8((DOUBLE)yHeight / TWIPS_PER_POINT, &decVal);
600 		else
601 			VarDecFromI4(0, &decVal);
602 
603 		SetPropertyVal(UI_PKEY_FontProperties_Size, &decVal, &var);
604 		pStore->SetValue(UI_PKEY_FontProperties_Size, var);
605 	}
606 
PutColorCharFormat607 	void PutColor(IPropertyStore* pStore)
608 	{
609 		if ((dwMask & CFM_COLOR) != 0)
610 		{
611 			if ((dwEffects & CFE_AUTOCOLOR) == 0)
612 			{
613 				SetPropertyVal(UI_PKEY_FontProperties_ForegroundColorType, UI_SWATCHCOLORTYPE_RGB, &propvar);
614 				pStore->SetValue(UI_PKEY_FontProperties_ForegroundColorType, propvar);
615 
616 				SetPropertyVal(UI_PKEY_FontProperties_ForegroundColor, crTextColor, &propvar);
617 				pStore->SetValue(UI_PKEY_FontProperties_ForegroundColor, propvar);
618 			}
619 			else
620 			{
621 				SetPropertyVal(UI_PKEY_FontProperties_ForegroundColorType, UI_SWATCHCOLORTYPE_AUTOMATIC, &propvar);
622 				pStore->SetValue(UI_PKEY_FontProperties_ForegroundColorType, propvar);
623 			}
624 		}
625 	}
626 
PutBackColorCharFormat627 	void PutBackColor(IPropertyStore* pStore)
628 	{
629 		if (((dwMask & CFM_BACKCOLOR) != 0) && ((dwEffects & CFE_AUTOBACKCOLOR) == 0))
630 		{
631 			SetPropertyVal(UI_PKEY_FontProperties_BackgroundColorType, UI_SWATCHCOLORTYPE_RGB, &propvar);
632 			pStore->SetValue(UI_PKEY_FontProperties_BackgroundColorType, propvar);
633 
634 			SetPropertyVal(UI_PKEY_FontProperties_BackgroundColor, crBackColor, &propvar);
635 			pStore->SetValue(UI_PKEY_FontProperties_BackgroundColor, propvar);
636 		}
637 		else
638 		{
639 			SetPropertyVal(UI_PKEY_FontProperties_BackgroundColorType, UI_SWATCHCOLORTYPE_NOCOLOR, &propvar);
640 			pStore->SetValue(UI_PKEY_FontProperties_BackgroundColorType, propvar);
641 		}
642 	}
643 };
644 
645 // IUIImage helper
646 //
GetImage(HBITMAP hbm,UI_OWNERSHIP owner)647 inline IUIImage* GetImage(HBITMAP hbm, UI_OWNERSHIP owner)
648 {
649 	ATLASSERT(hbm);
650 	IUIImage* pIUII = NULL;
651 	ATL::CComPtr<IUIImageFromBitmap> pIFB;
652 
653 	if SUCCEEDED(pIFB.CoCreateInstance(CLSID_UIRibbonImageFromBitmapFactory))
654 		ATLVERIFY(SUCCEEDED(pIFB->CreateImage(hbm, owner, &pIUII)));
655 
656 	return pIUII;
657 }
658 
659 
660 ///////////////////////////////////////////////////////////////////////////////
661 // Ribbon control classes
662 
663 // RibbonUI::ICtrl abstract interface of RibbonUI::CRibbonImpl and all RibbonUI control classes
664 //
665 struct ICtrl
666 {
667 	virtual HRESULT DoExecute(UINT nCmdID, UI_EXECUTIONVERB verb,
668 	                          const PROPERTYKEY* key, const PROPVARIANT* ppropvarValue,
669 	                          IUISimplePropertySet* pCommandExecutionProperties) = 0;
670 
671 	virtual HRESULT DoUpdateProperty(UINT nCmdID, REFPROPERTYKEY key,
672 	                                 const PROPVARIANT* ppropvarCurrentValue, PROPVARIANT* ppropvarNewValue) = 0;
673 };
674 
675 // RibbonUI::CtrlImpl base class for all ribbon controls
676 //
677 template <class T, UINT t_ID>
678 class ATL_NO_VTABLE CtrlImpl : public ICtrl
679 {
680 protected:
681 	T* m_pWndRibbon;
682 
683 public:
684 	typedef T WndRibbon;
685 
CtrlImpl()686 	CtrlImpl() : m_pWndRibbon(T::pWndRibbon)
687 	{ }
688 
GetWndRibbon()689 	WndRibbon& GetWndRibbon()
690 	{
691 		return *m_pWndRibbon;
692 	}
693 
GetID()694 	static WORD GetID()
695 	{
696 		return t_ID;
697 	}
698 
699 	Text m_sTxt[5];
700 
701 	// Operations
Invalidate()702 	HRESULT Invalidate()
703 	{
704 		return GetWndRibbon().InvalidateCtrl(GetID());
705 	}
706 
707 	HRESULT Invalidate(REFPROPERTYKEY key, UI_INVALIDATIONS flags = UI_INVALIDATIONS_PROPERTY)
708 	{
709 		return GetWndRibbon().InvalidateProperty(GetID(), key, flags);
710 	}
711 
712 	HRESULT SetText(REFPROPERTYKEY key, LPCWSTR sTxt, bool bUpdate = false)
713 	{
714 		ATLASSERT((k_(key) <= k_TooltipTitle) && (k_(key) >= k_LabelDescription));
715 
716 		m_sTxt[k_(key) - k_LabelDescription] = sTxt;
717 
718 		return bUpdate ?
719 			GetWndRibbon().InvalidateProperty(GetID(), key) :
720 			S_OK;
721 	}
722 
723 	// Implementation
724 	template <typename V>
SetProperty(REFPROPERTYKEY key,V val)725 	HRESULT SetProperty(REFPROPERTYKEY key, V val)
726 	{
727 		return GetWndRibbon().SetProperty(GetID(), key, val);
728 	}
729 
OnGetText(REFPROPERTYKEY key,PROPVARIANT * ppv)730 	HRESULT OnGetText(REFPROPERTYKEY key, PROPVARIANT* ppv)
731 	{
732 		ATLASSERT((k_(key) <= k_TooltipTitle) && (k_(key) >= k_LabelDescription));
733 
734 		const INT iText = k_(key) - k_LabelDescription;
735 		if (m_sTxt[iText].IsEmpty())
736 			if (LPCWSTR sText = GetWndRibbon().OnRibbonQueryText(GetID(), key))
737 				m_sTxt[iText] = sText;
738 
739 		return !m_sTxt[iText].IsEmpty() ?
740 			SetPropertyVal(key, (LPCWSTR)m_sTxt[iText], ppv) :
741 			S_OK;
742 	}
743 
DoExecute(UINT nCmdID,UI_EXECUTIONVERB verb,const PROPERTYKEY * key,const PROPVARIANT * ppropvarValue,IUISimplePropertySet * pCommandExecutionProperties)744 	virtual HRESULT DoExecute(UINT nCmdID, UI_EXECUTIONVERB verb,
745 	                          const PROPERTYKEY* key, const PROPVARIANT* ppropvarValue,
746 	                          IUISimplePropertySet* pCommandExecutionProperties)
747 	{
748 		ATLASSERT(nCmdID == t_ID);
749 		return GetWndRibbon().DoExecute(nCmdID, verb, key, ppropvarValue, pCommandExecutionProperties);
750 	}
751 
DoUpdateProperty(UINT nCmdID,REFPROPERTYKEY key,const PROPVARIANT * ppropvarCurrentValue,PROPVARIANT * ppropvarNewValue)752 	virtual HRESULT DoUpdateProperty(UINT nCmdID, REFPROPERTYKEY key,
753 	                                 const PROPVARIANT* ppropvarCurrentValue, PROPVARIANT* ppropvarNewValue)
754 	{
755 		ATLASSERT(nCmdID == t_ID);
756 
757 		const INT iMax = k_TooltipTitle - k_LabelDescription;
758 		const INT iVal = k_(key) - k_LabelDescription;
759 
760 		return (iVal <= iMax) && (iVal >= 0) ?
761 			OnGetText(key, ppropvarNewValue) :
762 			GetWndRibbon().DoUpdateProperty(nCmdID, key, ppropvarCurrentValue, ppropvarNewValue);
763 	}
764 };
765 
766 // CommandCtrlImpl base class for most ribbon controls
767 //
768 template <class T, UINT t_ID>
769 class CommandCtrlImpl : public CtrlImpl<T, t_ID>
770 {
771 public:
772 	CBitmap m_hbm[4];
773 
774 	HRESULT SetImage(REFPROPERTYKEY key, HBITMAP hbm, bool bUpdate = false)
775 	{
776 		ATLASSERT((k_(key) <= k_SmallHighContrastImage) && (k_(key) >= k_LargeImage));
777 
778 		m_hbm[k_(key) - k_LargeImage].Attach(hbm);
779 
780 		return bUpdate ?
781 			GetWndRibbon().InvalidateProperty(GetID(), key) :
782 			S_OK;
783 	}
784 
OnGetImage(REFPROPERTYKEY key,PROPVARIANT * ppv)785 	HRESULT OnGetImage(REFPROPERTYKEY key, PROPVARIANT* ppv)
786 	{
787 		ATLASSERT((k_(key) <= k_SmallHighContrastImage) && (k_(key) >= k_LargeImage));
788 
789 		const INT iImage = k_(key) - k_LargeImage;
790 
791 		if (m_hbm[iImage].IsNull())
792 			m_hbm[iImage] = GetWndRibbon().OnRibbonQueryImage(GetID(), key);
793 
794 		return m_hbm[iImage].IsNull() ?
795 			E_NOTIMPL :
796 			SetPropertyVal(key, GetImage(m_hbm[iImage], UI_OWNERSHIP_COPY), ppv);
797 	}
798 
DoUpdateProperty(UINT nCmdID,REFPROPERTYKEY key,const PROPVARIANT * ppropvarCurrentValue,PROPVARIANT * ppropvarNewValue)799 	virtual HRESULT DoUpdateProperty(UINT nCmdID, REFPROPERTYKEY key,
800 	                                 const PROPVARIANT* ppropvarCurrentValue, PROPVARIANT* ppropvarNewValue)
801 	{
802 		ATLASSERT (nCmdID == GetID());
803 
804 		return (k_(key) <= k_SmallHighContrastImage) && (k_(key) >= k_LargeImage) ?
805 			OnGetImage(key, ppropvarNewValue) :
806 			CtrlImpl::DoUpdateProperty(nCmdID, key, ppropvarCurrentValue, ppropvarNewValue);
807 	}
808 };
809 
810 
811 ///////////////////////////////////////////////////////////////////////////////
812 // Ribbon collection base classes
813 
814 // ItemProperty class: ribbon callback for each item in a collection
815 //
816 
817 #pragma warning(push)
818 #pragma warning(disable: 4512)   // assignment operator could not be generated
819 
820 template <class TCollection>
821 class ItemProperty : public IUISimplePropertySet
822 {
823 public:
ItemProperty(UINT i,TCollection * pCollection)824 	ItemProperty(UINT i, TCollection* pCollection) : m_Index(i), m_pCollection(pCollection)
825 	{ }
826 
827 	const UINT m_Index;
828 	TCollection* m_pCollection;
829 
830 	// IUISimplePropertySet method.
GetValue(REFPROPERTYKEY key,PROPVARIANT * value)831 	STDMETHODIMP GetValue(REFPROPERTYKEY key, PROPVARIANT *value)
832 	{
833 		return m_pCollection->OnGetItem(m_Index, key, value);
834 	}
835 
836 	// IUnknown methods.
AddRef()837 	STDMETHODIMP_(ULONG) AddRef()
838 	{
839 		return 1;
840 	}
841 
Release()842 	STDMETHODIMP_(ULONG) Release()
843 	{
844 		return 1;
845 	}
846 
QueryInterface(REFIID iid,void ** ppv)847 	STDMETHODIMP QueryInterface(REFIID iid, void** ppv)
848 	{
849 		if ((iid == __uuidof(IUnknown)) || (iid == __uuidof(IUISimplePropertySet)))
850 		{
851 			*ppv = this;
852 			return S_OK;
853 		}
854 		else
855 		{
856 			return E_NOINTERFACE;
857 		}
858 	}
859 };
860 
861 #pragma warning(pop)
862 
863 
864 // CollectionImplBase: base class for all RibbonUI collections
865 //
866 template <class TCollection, size_t t_size>
867 class CollectionImplBase
868 {
869 	typedef CollectionImplBase<TCollection, t_size> thisClass;
870 
871 public:
CollectionImplBase()872 	CollectionImplBase()
873 	{
874 		for (int i = 0; i < t_size; i++)
875 			m_apItems[i] = new ItemProperty<TCollection>(i, static_cast<TCollection*>(this));
876 	}
877 
~CollectionImplBase()878 	~CollectionImplBase()
879 	{
880 		for (int i = 0; i < t_size; i++)
881 			delete m_apItems[i];
882 	}
883 
884 // Data members
885 	ItemProperty<TCollection>* m_apItems[t_size];
886 };
887 
888 // CollectionImpl: handles categories and collecton resizing
889 //
890 template <class TCtrl, size_t t_items, size_t t_categories>
891 class CollectionImpl : public CollectionImplBase<CollectionImpl<TCtrl, t_items, t_categories>, t_items + t_categories>
892 {
893 	typedef CollectionImpl<TCtrl, t_items, t_categories> thisClass;
894 public:
895 	typedef thisClass Collection;
896 
CollectionImpl()897 	CollectionImpl() : m_size(t_items)
898 	{
899 		::FillMemory(m_auItemCat, sizeof(m_auItemCat), 0xff); // UI_COLLECTION_INVALIDINDEX
900 	}
901 
902 	UINT32 m_auItemCat[t_items];
903 	Text m_asCatName[__max(t_categories, 1)];
904 	size_t m_size;
905 
906 // Operations
907 	HRESULT SetItemCategory(UINT uItem, UINT uCat, bool bUpdate = false)
908 	{
909 		ATLASSERT((uItem < t_items) && (uCat < t_categories));
910 
911 		m_auItemCat[uItem] = uCat;
912 
913 		return bUpdate ? InvalidateItems() : S_OK;
914 	}
915 
916 	HRESULT SetCategoryText(UINT uCat, LPCWSTR sText, bool bUpdate = false)
917 	{
918 		ATLASSERT(uCat < t_categories);
919 
920 		m_asCatName[uCat] = sText;
921 
922 		return bUpdate ? InvalidateCategories() : S_OK;
923 	}
924 
925 	HRESULT Resize(size_t size, bool bUpdate = false)
926 	{
927 		ATLASSERT(size <= t_items);
928 
929 		m_size = size;
930 
931 		return bUpdate ? InvalidateItems() : S_OK;
932 	}
933 
934 // Implementation
OnGetItem(UINT uIndex,REFPROPERTYKEY key,PROPVARIANT * value)935 	HRESULT OnGetItem(UINT uIndex, REFPROPERTYKEY key, PROPVARIANT *value)
936 	{
937 		ATLASSERT(uIndex < t_items + t_categories);
938 		TCtrl* pCtrl = static_cast<TCtrl*>(this);
939 
940 		return uIndex < t_items ?
941 			pCtrl->DoGetItem(uIndex, key, value) :
942 			pCtrl->DoGetCategory(uIndex - t_items, key, value);
943 	}
944 
DoGetItem(UINT uItem,REFPROPERTYKEY key,PROPVARIANT * value)945 	HRESULT DoGetItem(UINT uItem, REFPROPERTYKEY key, PROPVARIANT *value)
946 	{
947 		ATLASSERT(k_(key) == k_CategoryId);
948 		UINT32 uCat = UI_COLLECTION_INVALIDINDEX;
949 
950 		if (t_categories != 0)
951 		{
952 			if (m_auItemCat[uItem] == UI_COLLECTION_INVALIDINDEX)
953 			{
954 				TCtrl::WndRibbon& ribbon = static_cast<TCtrl*>(this)->GetWndRibbon();
955 				m_auItemCat[uItem] = ribbon.OnRibbonQueryItemCategory(TCtrl::GetID(), uItem);
956 			}
957 			uCat = m_auItemCat[uItem];
958 		}
959 
960 		return SetPropertyVal(key, uCat, value);
961 	}
962 
DoGetCategory(UINT uCat,REFPROPERTYKEY key,PROPVARIANT * value)963 	HRESULT DoGetCategory(UINT uCat, REFPROPERTYKEY key, PROPVARIANT *value)
964 	{
965 		HRESULT hr = S_OK;
966 
967 		switch (k_(key))
968 		{
969 		case k_Label:
970 			if (m_asCatName[uCat].IsEmpty())
971 			{
972 				TCtrl::WndRibbon& ribbon = static_cast<TCtrl*>(this)->GetWndRibbon();
973 				m_asCatName[uCat] = ribbon.OnRibbonQueryCategoryText(TCtrl::GetID(), uCat);
974 			}
975 			hr = SetPropertyVal(key, (LPCWSTR)m_asCatName[uCat], value);
976 			break;
977 		case k_CategoryId:
978 			hr = SetPropertyVal(key, uCat, value);
979 			break;
980 		default:
981 			ATLASSERT(FALSE);
982 			break;
983 		}
984 
985 		return hr;
986 	}
987 
InvalidateItems()988 	HRESULT InvalidateItems()
989 	{
990 		return static_cast<TCtrl*>(this)->Invalidate(UI_PKEY_ItemsSource);
991 	}
992 
InvalidateCategories()993 	HRESULT InvalidateCategories()
994 	{
995 		return static_cast<TCtrl*>(this)->Invalidate(UI_PKEY_Categories);
996 	}
997 
DoUpdateProperty(UINT nCmdID,REFPROPERTYKEY key,const PROPVARIANT * ppropvarCurrentValue,PROPVARIANT *)998 	HRESULT DoUpdateProperty(UINT nCmdID, REFPROPERTYKEY key,
999 	                         const PROPVARIANT* ppropvarCurrentValue, PROPVARIANT* /*ppropvarNewValue*/)
1000 	{
1001 		ATLASSERT(nCmdID == TCtrl::GetID());
1002 		nCmdID;   // avoid level 4 warning
1003 
1004 		HRESULT hr = E_NOTIMPL;
1005 		switch (k_(key))
1006 		{
1007 		case k_ItemsSource:
1008 			{
1009 				ATL::CComQIPtr<IUICollection> pIUICollection(ppropvarCurrentValue->punkVal);
1010 				ATLASSERT(pIUICollection);
1011 				hr = pIUICollection->Clear();
1012 				for (UINT i = 0; i < m_size; i++)
1013 				{
1014 					if FAILED(hr = pIUICollection->Add(m_apItems[i]))
1015 						break;
1016 				}
1017 				ATLASSERT(SUCCEEDED(hr));
1018 			}
1019 			break;
1020 		case k_Categories:
1021 			if (t_categories != 0)
1022 			{
1023 				ATL::CComQIPtr<IUICollection> pIUICategory(ppropvarCurrentValue->punkVal);
1024 				ATLASSERT(pIUICategory.p);
1025 				hr = pIUICategory->Clear();
1026 				for (UINT i = t_items; i < (t_items + t_categories); i++)
1027 				{
1028 					if FAILED(hr = pIUICategory->Add(m_apItems[i]))
1029 						break;
1030 				}
1031 				ATLASSERT(SUCCEEDED(hr));
1032 			}
1033 			break;
1034 		}
1035 
1036 		return hr;
1037 	}
1038 };
1039 
1040 // TextCollectionImpl: handles item labels and selection
1041 //
1042 template <class TCtrl, size_t t_items, size_t t_categories = 0>
1043 class TextCollectionImpl : public CollectionImpl<TCtrl, t_items, t_categories>
1044 {
1045 	typedef TextCollectionImpl<TCtrl, t_items, t_categories> thisClass;
1046 public:
1047 	typedef thisClass TextCollection;
1048 
TextCollectionImpl()1049 	TextCollectionImpl() : m_uSelected(UI_COLLECTION_INVALIDINDEX)
1050 	{ }
1051 
1052 	Text m_asText[t_items];
1053 	UINT m_uSelected;
1054 
1055 	// Operations
1056 	HRESULT SetItemText(UINT uItem, LPCWSTR sText, bool bUpdate = false)
1057 	{
1058 		ATLASSERT(uItem < t_items);
1059 
1060 		m_asText[uItem] = sText;
1061 
1062 		return bUpdate ? InvalidateItems() : S_OK;
1063 	}
1064 
GetSelected()1065 	UINT GetSelected()
1066 	{
1067 		return m_uSelected;
1068 	}
1069 
1070 	HRESULT Select(UINT uItem, bool bUpdate = false)
1071 	{
1072 		ATLASSERT((uItem < t_items) || (uItem == UI_COLLECTION_INVALIDINDEX));
1073 
1074 		m_uSelected = uItem;
1075 
1076 		TCtrl::WndRibbon& ribbon = static_cast<TCtrl*>(this)->GetWndRibbon();
1077 		return bUpdate ?
1078 			ribbon.SetProperty(TCtrl::GetID(), UI_PKEY_SelectedItem, uItem) :
1079 			S_OK;
1080 	}
1081 
1082 // Implementation
DoGetItem(UINT uItem,REFPROPERTYKEY key,PROPVARIANT * value)1083  	HRESULT DoGetItem(UINT uItem, REFPROPERTYKEY key, PROPVARIANT *value)
1084 	{
1085 		ATLASSERT(uItem < t_items);
1086 
1087 		if (k_(key) == k_Label)
1088 		{
1089 			if (m_asText[uItem].IsEmpty())
1090 			{
1091 				TCtrl::WndRibbon& ribbon = static_cast<TCtrl*>(this)->GetWndRibbon();
1092 				m_asText[uItem] = ribbon.OnRibbonQueryItemText(TCtrl::GetID(), uItem);
1093 			}
1094 			return SetPropertyVal(key, (LPCWSTR)m_asText[uItem], value);
1095 		}
1096 		else
1097 		{
1098 			return Collection::DoGetItem(uItem, key, value);
1099 		}
1100 	}
1101 
DoUpdateProperty(UINT nCmdID,REFPROPERTYKEY key,const PROPVARIANT * ppropvarCurrentValue,PROPVARIANT * ppropvarNewValue)1102 	HRESULT DoUpdateProperty(UINT nCmdID, REFPROPERTYKEY key,
1103 	                         const PROPVARIANT* ppropvarCurrentValue, PROPVARIANT* ppropvarNewValue)
1104 	{
1105 		ATLASSERT(nCmdID == TCtrl::GetID());
1106 
1107 		if (k_(key) == k_SelectedItem)
1108 		{
1109 			TCtrl::WndRibbon& ribbon = static_cast<TCtrl*>(this)->GetWndRibbon();
1110 			UINT uSel = UI_COLLECTION_INVALIDINDEX;
1111 			if ((m_uSelected == UI_COLLECTION_INVALIDINDEX) &&
1112 			    ribbon.OnRibbonQuerySelectedItem(TCtrl::GetID(), uSel))
1113 				m_uSelected = uSel;
1114 
1115 			return SetPropertyVal(key, m_uSelected, ppropvarNewValue);
1116 		}
1117 		else
1118 		{
1119 			return Collection::DoUpdateProperty(nCmdID, key, ppropvarCurrentValue, ppropvarNewValue);
1120 		}
1121 	}
1122 };
1123 
1124 // ItemCollectionImpl: handles item image
1125 //
1126 template <class TCtrl, size_t t_items, size_t t_categories = 0>
1127 class ItemCollectionImpl : public TextCollectionImpl<TCtrl, t_items, t_categories>
1128 {
1129 	typedef ItemCollectionImpl<TCtrl, t_items, t_categories> thisClass;
1130 public:
1131 	typedef thisClass ItemCollection;
1132 
ItemCollectionImpl()1133 	ItemCollectionImpl()
1134 	{
1135 		::ZeroMemory(m_aBitmap, sizeof(m_aBitmap));
1136 	}
1137 
1138 	CBitmap m_aBitmap[t_items];
1139 
1140 	// Operations
1141 	HRESULT SetItemImage(UINT uIndex, HBITMAP hbm, bool bUpdate = false)
1142 	{
1143 		ATLASSERT(uIndex < t_items);
1144 
1145 		m_aBitmap[uIndex] = hbm;
1146 
1147 		return bUpdate ? InvalidateItems() : S_OK;
1148 	}
1149 
1150 // Implementation
DoGetItem(UINT uItem,REFPROPERTYKEY key,PROPVARIANT * value)1151 	HRESULT DoGetItem(UINT uItem, REFPROPERTYKEY key, PROPVARIANT *value)
1152 	{
1153 		ATLASSERT(uItem < t_items);
1154 
1155 		if (k_(key) == k_ItemImage)
1156 		{
1157 			if (m_aBitmap[uItem].IsNull())
1158 			{
1159 				TCtrl::WndRibbon& ribbon = static_cast<TCtrl*>(this)->GetWndRibbon();
1160 				m_aBitmap[uItem] = ribbon.OnRibbonQueryItemImage(TCtrl::GetID(), uItem);
1161 			}
1162 			return m_aBitmap[uItem].IsNull() ?
1163 				E_NOTIMPL :
1164 				SetPropertyVal(key, GetImage(m_aBitmap[uItem], UI_OWNERSHIP_COPY), value);
1165 		}
1166 		else
1167 		{
1168 			return TextCollection::DoGetItem(uItem, key, value);
1169 		}
1170 	}
1171 };
1172 
1173 // ComboCollectionImpl: handles combo text
1174 //
1175 template <class TCtrl, size_t t_items, size_t t_categories = 0>
1176 class ComboCollectionImpl : public ItemCollectionImpl<TCtrl, t_items, t_categories>
1177 {
1178 	typedef ComboCollectionImpl<TCtrl, t_items, t_categories> thisClass;
1179 public:
1180 	typedef thisClass ComboCollection;
1181 
1182 	// Operations
SetComboText(LPCWSTR sText)1183 	HRESULT SetComboText(LPCWSTR sText)
1184 	{
1185 		TCtrl::WndRibbon& ribbon = static_cast<TCtrl*>(this)->GetWndRibbon();
1186 		return ribbon.IsRibbonUI() ?
1187 			ribbon.SetProperty(TCtrl::GetID(), UI_PKEY_StringValue, sText) :
1188 			S_OK;
1189 	}
1190 
GetComboText()1191 	LPCWSTR GetComboText()
1192 	{
1193 		static WCHAR sCombo[RIBBONUI_MAX_TEXT] = { 0 };
1194 		TCtrl::WndRibbon& ribbon = static_cast<TCtrl*>(this)->GetWndRibbon();
1195 		PROPVARIANT var;
1196 		if (ribbon.IsRibbonUI())
1197 		{
1198 			HRESULT hr = ribbon.GetIUIFrameworkPtr()->GetUICommandProperty(TCtrl::GetID(), UI_PKEY_StringValue, &var);
1199 			hr = PropVariantToString(var, sCombo, RIBBONUI_MAX_TEXT);
1200 			return sCombo;
1201 		}
1202 		return NULL;
1203 	}
1204 };
1205 
1206 // CommandCollectionImpl: handles RibbonUI command collection controls
1207 //
1208 template <class TCtrl, size_t t_items, size_t t_categories = 0>
1209 class CommandCollectionImpl : public CollectionImpl<TCtrl, t_items, t_categories>
1210 {
1211 	typedef CommandCollectionImpl<TCtrl, t_items, t_categories> thisClass;
1212 public:
1213 	typedef thisClass CommandCollection;
1214 
CommandCollectionImpl()1215 	CommandCollectionImpl()
1216 	{
1217 		::ZeroMemory(m_auCmd, sizeof(m_auCmd));
1218 		::ZeroMemory(m_aCmdType, sizeof(m_aCmdType));
1219 	}
1220 
1221 	UINT32 m_auCmd[t_items];
1222 	BYTE m_aCmdType[t_items];
1223 
1224 	// Operations
1225 	HRESULT SetItemCommand(UINT uItem, UINT32 uCommandID, bool bUpdate = false)
1226 	{
1227 		ATLASSERT(uItem < t_items);
1228 
1229 		if (uCommandID == m_auCmd[uItem])
1230 			return S_OK;
1231 
1232 		TCtrl::WndRibbon& ribbon = static_cast<TCtrl*>(this)->GetWndRibbon();
1233 
1234 		m_auCmd[uItem] = uCommandID;
1235 		if (uCommandID != 0)
1236 			ribbon.UIAddRibbonElement(uCommandID);
1237 
1238 		return bUpdate ? InvalidateItems() : S_OK;
1239 	}
1240 
1241 	HRESULT SetItemCommandType(UINT uItem, UI_COMMANDTYPE type, bool bUpdate = false)
1242 	{
1243 		ATLASSERT(uItem < t_items);
1244 
1245 		m_aCmdType[uItem] = (BYTE)type;
1246 
1247 		return bUpdate ? InvalidateItems() : S_OK;
1248 	}
1249 
1250 // Implementation
DoGetItem(UINT uItem,REFPROPERTYKEY key,PROPVARIANT * value)1251  	HRESULT DoGetItem(UINT uItem, REFPROPERTYKEY key, PROPVARIANT *value)
1252 	{
1253 		ATLASSERT(uItem < t_items);
1254 		TCtrl::WndRibbon& ribbon = static_cast<TCtrl*>(this)->GetWndRibbon();
1255 
1256 		HRESULT hr = E_FAIL;
1257 		switch (k_(key))
1258 		{
1259 		case k_CommandId:
1260 			if (m_auCmd[uItem] == 0)
1261 				SetItemCommand(uItem, ribbon.OnRibbonQueryItemCommand(TCtrl::GetID(), uItem));
1262 			hr = SetPropertyVal(key, m_auCmd[uItem], value);
1263 			break;
1264 		case k_CommandType:
1265 			if (m_aCmdType[uItem] == UI_COMMANDTYPE_UNKNOWN)
1266 				SetItemCommandType(uItem, ribbon.OnRibbonQueryItemCommandType(TCtrl::GetID(), uItem));
1267 			hr = SetPropertyVal(key, UINT32(m_aCmdType[uItem]), value);
1268 			break;
1269 		case k_CategoryId:
1270 		default:
1271 			hr = Collection::DoGetItem(uItem, key, value);
1272 			break;
1273 		}
1274 
1275 		return hr;
1276 	}
1277 
1278 	HRESULT Select(UINT /*uItem*/, bool /*bUpdate*/ = false)
1279 	{
1280 		ATLASSERT(FALSE);
1281 		return S_OK;
1282 	}
1283 };
1284 
1285 // SimpleCollectionImpl: collection class for ribbon simple collection controls
1286 //
1287 template <class TCtrl, size_t t_size, UI_COMMANDTYPE t_CommandType = UI_COMMANDTYPE_ACTION>
1288 class SimpleCollectionImpl : public CollectionImplBase<SimpleCollectionImpl<TCtrl, t_size>, t_size>
1289 {
1290 	typedef SimpleCollectionImpl<TCtrl, t_size, t_CommandType> thisClass;
1291 public:
1292 	typedef CollectionImplBase<thisClass, t_size> CollectionBase;
1293 	typedef thisClass SimpleCollection;
1294 
1295 // Implementation
OnGetItem(UINT uItem,REFPROPERTYKEY key,PROPVARIANT * value)1296 	HRESULT OnGetItem(UINT uItem, REFPROPERTYKEY key, PROPVARIANT *value)
1297 	{
1298 		ATLASSERT(uItem < t_size);
1299 		TCtrl::WndRibbon& ribbon = static_cast<TCtrl*>(this)->GetWndRibbon();
1300 
1301 		HRESULT hr = E_NOTIMPL;
1302 		switch (k_(key))
1303 		{
1304 		case k_ItemImage:
1305 			if (HBITMAP hbm = ribbon.DefRibbonQueryItemImage(TCtrl::GetID(), uItem))
1306 				hr = SetPropertyVal(key, GetImage(hbm, UI_OWNERSHIP_TRANSFER), value);
1307 			break;
1308 		case k_Label:
1309 			if (LPCWSTR sText = ribbon.DefRibbonQueryItemText(TCtrl::GetID(), uItem))
1310 				hr = SetPropertyVal(key, (LPCWSTR)sText, value);
1311 			break;
1312 		case k_CommandType:
1313 			hr = SetPropertyVal(key, t_CommandType, value);
1314 			break;
1315 		case k_CommandId:
1316 			hr = SetPropertyVal(key, ribbon.DefRibbonQueryItemCommand(TCtrl::GetID(), uItem), value);
1317 			break;
1318 		case k_CategoryId:
1319 			hr = SetPropertyVal(key, UI_COLLECTION_INVALIDINDEX, value);
1320 			break;
1321 		default:
1322 			ATLASSERT(FALSE);
1323 			break;
1324 		}
1325 
1326 		return hr;
1327 	}
1328 };
1329 
1330 
1331 ///////////////////////////////////////////////////////////////////////////////
1332 // Ribbon collection control classes
1333 
1334 // CollectionCtrlImpl: specializable class for ribbon collection controls
1335 //
1336 template <class T, UINT t_ID, class TCollection>
1337 class CollectionCtrlImpl : public CommandCtrlImpl<T, t_ID>, public TCollection
1338 {
1339 	typedef CollectionCtrlImpl<T, t_ID, TCollection> thisClass;
1340 public:
1341 	typedef CommandCtrlImpl<T, t_ID> CommandCtrl;
1342 	typedef TCollection Collection;
1343 
1344 	// Implementation
DoUpdateProperty(UINT nCmdID,REFPROPERTYKEY key,const PROPVARIANT * ppropvarCurrentValue,PROPVARIANT * ppropvarNewValue)1345 	virtual HRESULT DoUpdateProperty(UINT nCmdID, REFPROPERTYKEY key,
1346 	                                 const PROPVARIANT* ppropvarCurrentValue, PROPVARIANT* ppropvarNewValue)
1347 	{
1348 		ATLASSERT(nCmdID == GetID());
1349 		ATLASSERT(ppropvarNewValue);
1350 
1351 		HRESULT hr = Collection::DoUpdateProperty(nCmdID, key, ppropvarCurrentValue, ppropvarNewValue);
1352 		if FAILED(hr)
1353 			hr = CommandCtrl::DoUpdateProperty(nCmdID, key, ppropvarCurrentValue, ppropvarNewValue);
1354 
1355 		return hr;
1356 	}
1357 
DoExecute(UINT nCmdID,UI_EXECUTIONVERB verb,const PROPERTYKEY * key,const PROPVARIANT * ppropvarValue,IUISimplePropertySet *)1358 	virtual HRESULT DoExecute(UINT nCmdID, UI_EXECUTIONVERB verb,
1359 	                          const PROPERTYKEY* key, const PROPVARIANT* ppropvarValue,
1360 	                          IUISimplePropertySet* /*pCommandExecutionProperties*/)
1361 	{
1362 		ATLASSERT (nCmdID == GetID());
1363 		nCmdID; // avoid level4 warning
1364 
1365 		if (key == NULL) // gallery button pressed
1366 		{
1367 			GetWndRibbon().OnRibbonItemSelected(GetID(), UI_EXECUTIONVERB_EXECUTE, UI_COLLECTION_INVALIDINDEX);
1368 			return S_OK;
1369 		}
1370 
1371 		ATLASSERT(k_(*key) == k_SelectedItem);
1372 		ATLASSERT(ppropvarValue);
1373 
1374 		HRESULT hr = S_OK;
1375 		UINT32 uSel = 0xffff;
1376 		hr = UIPropertyToUInt32(*key, *ppropvarValue, &uSel);
1377 
1378 		if (SUCCEEDED(hr))
1379 		{
1380 			if (GetWndRibbon().OnRibbonItemSelected(GetID(), verb, uSel))
1381 				TCollection::Select(uSel);
1382 		}
1383 
1384 		return hr;
1385 	}
1386 };
1387 
1388 // ToolbarGalleryCtrlImpl: base class for ribbon toolbar gallery controls
1389 //
1390 template <class T, UINT t_ID, UINT t_idTB, size_t t_size>
1391 class ToolbarGalleryCtrlImpl : public CollectionCtrlImpl<T, t_ID, CommandCollectionImpl<ToolbarGalleryCtrlImpl<T, t_ID, t_idTB, t_size>, t_size>>
1392 {
1393 public:
ToolbarGalleryCtrlImpl()1394 	ToolbarGalleryCtrlImpl()
1395 	{
1396 		CResource tbres;
1397 		ATLVERIFY(tbres.Load(RT_TOOLBAR, t_idTB));
1398 		_AtlToolBarData* pData = (_AtlToolBarData*)tbres.Lock();
1399 		ATLASSERT(pData);
1400 		ATLASSERT(pData->wVersion == 1);
1401 
1402 		WORD* pItems = pData->items();
1403 		INT j = 0;
1404 		for (int i = 0; (i < pData->wItemCount) && (j < t_size); i++)
1405 		{
1406 			if (pItems[i] != 0)
1407 			{
1408 				m_aCmdType[j] = UI_COMMANDTYPE_ACTION;
1409 				m_auCmd[j++] = pItems[i];
1410 			}
1411 		}
1412 
1413 		if (j < t_size)
1414 			Resize(j);
1415 	}
1416 
DoGetItem(UINT uItem,REFPROPERTYKEY key,PROPVARIANT * value)1417  	HRESULT DoGetItem(UINT uItem, REFPROPERTYKEY key, PROPVARIANT *value)
1418 	{
1419 		ATLASSERT(uItem < m_size);
1420 		ATLASSERT(m_auCmd[uItem]);
1421 
1422 		HRESULT hr = E_FAIL;
1423 		switch (k_(key))
1424 		{
1425 		case k_CommandId:
1426 			hr = SetPropertyVal(key, m_auCmd[uItem], value);
1427 			break;
1428 		case k_CommandType:
1429 			hr = SetPropertyVal(key, UINT32(m_aCmdType[uItem]), value);
1430 			break;
1431 		case k_CategoryId:
1432 			hr = SetPropertyVal(key, UI_COLLECTION_INVALIDINDEX, value);
1433 			break;
1434 		default:
1435 			ATLASSERT(FALSE);
1436 			break;
1437 		}
1438 
1439 		return hr;
1440 	}
1441 };
1442 
1443 
1444 // SimpleCollectionCtrlImpl: base class for simple gallery and listbox controls
1445 //
1446 template <class T, UINT t_ID, size_t t_size, UI_COMMANDTYPE t_CommandType = UI_COMMANDTYPE_ACTION>
1447 class SimpleCollectionCtrlImpl :
1448 		public CommandCtrlImpl<T, t_ID>,
1449 		public SimpleCollectionImpl<SimpleCollectionCtrlImpl<T, t_ID, t_size, t_CommandType>, t_size, t_CommandType>
1450 {
1451 	typedef SimpleCollectionCtrlImpl<T, t_ID, t_size, t_CommandType> thisClass;
1452 public:
1453 	typedef thisClass SimpleCollection;
1454 
SimpleCollectionCtrlImpl()1455 	SimpleCollectionCtrlImpl() : m_uSelected(0)
1456 	{ }
1457 
1458 	UINT m_uSelected;
1459 
1460 	HRESULT Select(UINT uItem, bool bUpdate = false)
1461 	{
1462 		ATLASSERT((uItem < t_size) || (uItem == UI_COLLECTION_INVALIDINDEX));
1463 
1464 		m_uSelected = uItem;
1465 
1466 		return bUpdate ?
1467 			GetWndRibbon().SetProperty(GetID(), UI_PKEY_SelectedItem, uItem) :
1468 			S_OK;
1469 	}
1470 
1471 	// Implementation
DoUpdateProperty(UINT nCmdID,REFPROPERTYKEY key,const PROPVARIANT * ppropvarCurrentValue,PROPVARIANT * ppropvarNewValue)1472 	virtual HRESULT DoUpdateProperty(UINT nCmdID, REFPROPERTYKEY key,
1473 	                                 const PROPVARIANT* ppropvarCurrentValue, PROPVARIANT* ppropvarNewValue)
1474 	{
1475 		ATLASSERT(nCmdID == GetID());
1476 		ATLASSERT(ppropvarNewValue != NULL);
1477 
1478 		HRESULT hr = S_OK;
1479 		switch (k_(key))
1480 		{
1481 		case k_ItemsSource:
1482 			{
1483 				ATL::CComQIPtr<IUICollection> pIUICollection(ppropvarCurrentValue->punkVal);
1484 				ATLASSERT(pIUICollection.p);
1485 				hr = pIUICollection->Clear();
1486 				for (UINT i = 0; i < t_size; i++)
1487 				{
1488 					if FAILED(hr = pIUICollection->Add(m_apItems[i]))
1489 						break;
1490 				}
1491 				ATLASSERT(SUCCEEDED(hr));
1492 			}
1493 			break;
1494 		case k_SelectedItem:
1495 			hr = SetPropertyVal(UI_PKEY_SelectedItem, m_uSelected, ppropvarNewValue);
1496 			break;
1497 		default:
1498 			hr = CommandCtrlImpl::DoUpdateProperty(nCmdID, key, ppropvarCurrentValue, ppropvarNewValue);
1499 			break;
1500 		}
1501 
1502 		return hr;
1503 	}
1504 
DoExecute(UINT nCmdID,UI_EXECUTIONVERB verb,const PROPERTYKEY * key,const PROPVARIANT * ppropvarValue,IUISimplePropertySet *)1505 	virtual HRESULT DoExecute(UINT nCmdID, UI_EXECUTIONVERB verb,
1506 	                          const PROPERTYKEY* key, const PROPVARIANT* ppropvarValue,
1507 	                          IUISimplePropertySet* /*pCommandExecutionProperties*/)
1508 	{
1509 		ATLASSERT (nCmdID == GetID());
1510 		nCmdID;   // avoid level 4 warning
1511 
1512 		HRESULT hr = S_OK;
1513 		if (key == NULL) // gallery button pressed
1514 		{
1515 			GetWndRibbon().OnRibbonItemSelected(GetID(), UI_EXECUTIONVERB_EXECUTE, UI_COLLECTION_INVALIDINDEX);
1516 			return hr;
1517 		}
1518 		ATLASSERT(k_(*key) == k_SelectedItem);
1519 		ATLASSERT(ppropvarValue);
1520 
1521 		if SUCCEEDED(hr = UIPropertyToUInt32(*key, *ppropvarValue, &m_uSelected))
1522 			GetWndRibbon().OnRibbonItemSelected(GetID(), verb, m_uSelected);
1523 
1524 		return hr;
1525 	}
1526 };
1527 
1528 // RecentItemsCtrlImpl
1529 //
1530 template <class T, UINT t_ID, class TDocList = CRecentDocumentList>
1531 class RecentItemsCtrlImpl :
1532 		public CtrlImpl<T, t_ID>,
1533 		public CollectionImplBase<RecentItemsCtrlImpl<T, t_ID, TDocList>, TDocList::m_nMaxEntries_Max>,
1534 		public TDocList
1535 {
1536 	typedef RecentItemsCtrlImpl<T, t_ID, TDocList> thisClass;
1537 public:
1538 	typedef thisClass RecentItems;
1539 
1540 	// Implementation
OnGetItem(UINT uItem,REFPROPERTYKEY key,PROPVARIANT * value)1541 	HRESULT OnGetItem(UINT uItem, REFPROPERTYKEY key, PROPVARIANT *value)
1542 	{
1543 		ATLASSERT((INT)uItem < GetMaxEntries());
1544 
1545 		LPCWSTR sPath = m_arrDocs[uItem].szDocName;
1546 		HRESULT hr = E_NOTIMPL;
1547 		switch (k_(key))
1548 		{
1549 		case k_Label:
1550 			hr = SetPropertyVal(key, GetWndRibbon().OnRibbonQueryRecentItemName(sPath), value);
1551 			break;
1552 		case k_LabelDescription:
1553 			hr = SetPropertyVal(key, sPath, value);
1554 			break;
1555 		default:
1556 			ATLASSERT(FALSE);
1557 			break;
1558 		}
1559 
1560 		return hr;
1561 	}
1562 
DoUpdateProperty(UINT nCmdID,REFPROPERTYKEY key,const PROPVARIANT * ppropvarCurrentValue,PROPVARIANT * ppropvarNewValue)1563 	virtual HRESULT DoUpdateProperty(UINT nCmdID, REFPROPERTYKEY key,
1564 	                                 const PROPVARIANT* ppropvarCurrentValue, PROPVARIANT* ppropvarNewValue)
1565 	{
1566 		ATLASSERT(nCmdID == GetID());
1567 		ATLASSERT(ppropvarNewValue);
1568 
1569 		HRESULT hr = S_OK;
1570 		switch (k_(key))
1571 		{
1572 		case k_RecentItems:
1573 			if (SAFEARRAY* psa = SafeArrayCreateVector(VT_UNKNOWN, 0, m_arrDocs.GetSize()))
1574 			{
1575 				const int iLastIndex = m_arrDocs.GetSize() - 1;
1576 				for (LONG i = 0; i <= iLastIndex; i++)
1577 					SafeArrayPutElement(psa, &i, m_apItems[iLastIndex - i]); // reverse order
1578 
1579 				hr = SetPropertyVal(key, psa, ppropvarNewValue);
1580 				SafeArrayDestroy(psa);
1581 			}
1582 			break;
1583 		default:
1584 			hr = CtrlImpl::DoUpdateProperty(nCmdID, key, ppropvarCurrentValue, ppropvarNewValue);
1585 			break;
1586 		}
1587 
1588 		return hr;
1589 	}
1590 
DoExecute(UINT nCmdID,UI_EXECUTIONVERB verb,const PROPERTYKEY * key,const PROPVARIANT * ppropvarValue,IUISimplePropertySet *)1591 	virtual HRESULT DoExecute(UINT nCmdID, UI_EXECUTIONVERB verb,
1592 	                          const PROPERTYKEY* key, const PROPVARIANT* ppropvarValue,
1593 	                          IUISimplePropertySet* /*pCommandExecutionProperties*/)
1594 	{
1595 		ATLASSERT(nCmdID == GetID());
1596 		nCmdID;   // avoid level 4 warning
1597 		ATLASSERT(verb == UI_EXECUTIONVERB_EXECUTE);
1598 		verb;   // avoid level 4 warning
1599 		ATLASSERT((key) && (k_(*key) == k_SelectedItem));
1600 		ATLASSERT(ppropvarValue);
1601 
1602 		UINT32 uSel = 0xffff;
1603 		HRESULT hr = UIPropertyToUInt32(*key, *ppropvarValue, &uSel);
1604 		if SUCCEEDED(hr)
1605 		{
1606 			ATLASSERT(uSel < (UINT)GetMaxEntries());
1607 			GetWndRibbon().DefCommandExecute(ID_FILE_MRU_FIRST + uSel);
1608 		}
1609 
1610 		return hr;
1611 	}
1612 };
1613 
1614 
1615 ///////////////////////////////////////////////////////////////////////////////
1616 // Ribbon stand-alone control classes
1617 
1618 // FontCtrlImpl
1619 //
1620 template <class T, UINT t_ID>
1621 class FontCtrlImpl : public CtrlImpl<T, t_ID>
1622 {
1623 public:
1624 
1625 	CharFormat m_cf;
1626 
1627 // Implementation
DoExecute(UINT nCmdID,UI_EXECUTIONVERB verb,const PROPERTYKEY * key,const PROPVARIANT * ppropvarValue,IUISimplePropertySet * pCommandExecutionProperties)1628 	virtual HRESULT DoExecute(UINT nCmdID, UI_EXECUTIONVERB verb,
1629 	                          const PROPERTYKEY* key, const PROPVARIANT* ppropvarValue,
1630 	                          IUISimplePropertySet* pCommandExecutionProperties)
1631 	{
1632 		ATLASSERT (nCmdID == GetID());
1633 		nCmdID;   // avoid level 4 warning
1634 		ATLASSERT ((key) && (k_(*key) == k_FontProperties));
1635 		key;   // avoid level 4 warning
1636 
1637 		HRESULT hr = E_INVALIDARG;
1638 		switch (verb)
1639 		{
1640 			case UI_EXECUTIONVERB_PREVIEW:
1641 			case UI_EXECUTIONVERB_EXECUTE:
1642 				ATLASSERT(pCommandExecutionProperties);
1643 				PROPVARIANT propvar;
1644 
1645 				if (SUCCEEDED(hr = pCommandExecutionProperties->GetValue(UI_PKEY_FontProperties_ChangedProperties, &propvar)))
1646 					m_cf << ATL::CComQIPtr<IPropertyStore>(propvar.punkVal);
1647 				break;
1648 
1649 			case UI_EXECUTIONVERB_CANCELPREVIEW:
1650 				ATLASSERT(ppropvarValue);
1651 				ATL::CComPtr<IPropertyStore> pStore;
1652 
1653 				if (SUCCEEDED(hr = UIPropertyToInterface(UI_PKEY_FontProperties, *ppropvarValue, &pStore)))
1654 					m_cf << pStore;
1655 				break;
1656 		}
1657 
1658 		if (SUCCEEDED(hr))
1659 			GetWndRibbon().OnRibbonFontCtrlExecute(GetID(), verb, &m_cf);
1660 		else
1661 			ATLASSERT(FALSE);
1662 
1663 		return hr;
1664 	}
1665 
DoUpdateProperty(UINT nCmdID,REFPROPERTYKEY key,const PROPVARIANT * ppropvarCurrentValue,PROPVARIANT * ppropvarNewValue)1666 	virtual HRESULT DoUpdateProperty(UINT nCmdID, REFPROPERTYKEY key,
1667 	                                 const PROPVARIANT* ppropvarCurrentValue, PROPVARIANT* ppropvarNewValue)
1668 	{
1669 		if ((k_(key) == k_FontProperties) && (GetWndRibbon().OnRibbonQueryFont(t_ID, m_cf)))
1670 		{
1671 			ATL::CComQIPtr<IPropertyStore> pStore(ppropvarCurrentValue->punkVal);
1672 			m_cf >> pStore;
1673 			return SetPropertyVal(key, pStore.p, ppropvarNewValue);
1674 		}
1675 		else
1676 		{
1677 			return CtrlImpl::DoUpdateProperty(nCmdID, key, ppropvarCurrentValue, ppropvarNewValue);
1678 		}
1679 	}
1680 };
1681 
1682 // ColorCtrlImpl
1683 //
1684 template <class T, UINT t_ID>
1685 class ColorCtrlImpl : public CommandCtrlImpl<T, t_ID>
1686 {
1687 public:
ColorCtrlImpl()1688 	ColorCtrlImpl() : m_colorType(UI_SWATCHCOLORTYPE_NOCOLOR), m_color(0x800080) /*MAGENTA*/
1689 	{ }
1690 
1691 	COLORREF m_color;
1692 	UINT32 m_colorType; // value in UI_SWATCHCOLORTYPE
1693 	Text m_sLabels[6]; // k_MoreColorsLabel to k_ThemeColorsCategoryLabel
1694 	ATL::CSimpleArray<COLORREF> m_aColors[2];
1695 	ATL::CSimpleArray<LPCWSTR> m_aTooltips[2];
1696 
1697 	// Operations
1698 	HRESULT SetColor(COLORREF color, bool bUpdate = false)
1699 	{
1700 		if (m_colorType != UI_SWATCHCOLORTYPE_RGB)
1701 			SetColorType(UI_SWATCHCOLORTYPE_RGB, bUpdate);
1702 		m_color = color;
1703 		return bUpdate ? SetProperty(UI_PKEY_Color, color) : S_OK;
1704 	}
1705 
1706 	HRESULT SetColorType(UI_SWATCHCOLORTYPE type, bool bUpdate = false)
1707 	{
1708 		m_colorType = type;
1709 		return bUpdate ? SetProperty(UI_PKEY_ColorType, type) : S_OK;
1710 	}
1711 
1712 	HRESULT SetColorLabel(REFPROPERTYKEY key, LPCWSTR sLabel, bool bUpdate = false)
1713 	{
1714 		ATLASSERT((k_(key) >= k_ThemeColorsCategoryLabel) && (k_(key) <= k_MoreColorsLabel));
1715 		m_sLabels[k_(key) - k_ThemeColorsCategoryLabel] = sLabel;
1716 		return bUpdate ? SetProperty(key, sLabel) : S_OK;
1717 	}
1718 
1719 	HRESULT SetColorArray(REFPROPERTYKEY key, COLORREF* pColor, bool bUpdate = false)
1720 	{
1721 		ATLASSERT((k_(key) == k_ThemeColors) || (k_(key) == k_StandardColors));
1722 
1723 		const INT ic = k_(key) - k_ThemeColors;
1724 		m_aColors[ic].RemoveAll();
1725 		while (*pColor != 0x800080) /*MAGENTA*/
1726 			m_aColors[ic].Add(*pColor++);
1727 
1728 		if (bUpdate)
1729 		{
1730 			PROPVARIANT var;
1731 			if SUCCEEDED(InitPropVariantFromUInt32Vector(m_aColors[ic].GetData(), m_aColors[ic].GetSize(), &var))
1732 				return SetProperty(key, var);
1733 			else
1734 				return E_INVALIDARG;
1735 		}
1736 		else
1737 		{
1738 			return S_OK;
1739 		}
1740 	}
1741 
1742 	HRESULT SetColorTooltips(REFPROPERTYKEY key, LPCWSTR* ppsTT, bool bUpdate = false)
1743 	{
1744 		ATLASSERT((k_(key) == k_ThemeColorsTooltips) || (k_(key) == k_StandardColorsTooltips));
1745 
1746 		const INT ic = k_(key) - k_ThemeColorsTooltips;
1747 		m_aTooltips[ic].RemoveAll();
1748 		while (*ppsTT)
1749 			m_aTooltips[ic].Add(*ppsTT++);
1750 
1751 		if (bUpdate)
1752 		{
1753 			PROPVARIANT var;
1754 			if SUCCEEDED(InitPropVariantFromStringVector(m_aTooltips[ic].GetData(), m_aTooltips[ic].GetSize(), &var))
1755 				return SetProperty(key, var);
1756 			else
1757 				return E_INVALIDARG;
1758 		}
1759 		else
1760 		{
1761 			return S_OK;
1762 		}
1763 	}
1764 
1765 	// Implementation
DoExecute(UINT nCmdID,UI_EXECUTIONVERB verb,const PROPERTYKEY * key,const PROPVARIANT * ppropvarValue,IUISimplePropertySet * pCommandExecutionProperties)1766 	virtual HRESULT DoExecute(UINT nCmdID, UI_EXECUTIONVERB verb,
1767 	                          const PROPERTYKEY* key, const PROPVARIANT* ppropvarValue,
1768 	                          IUISimplePropertySet* pCommandExecutionProperties)
1769 	{
1770 		ATLASSERT (nCmdID == GetID());
1771 		nCmdID;   // avoid level 4 warning
1772 		ATLASSERT (key && (k_(*key) == k_ColorType));
1773 		key;   // avoid level 4 warning
1774 		ATLASSERT (ppropvarValue);
1775 
1776 		HRESULT hr = PropVariantToUInt32(*ppropvarValue, &m_colorType);
1777 		ATLASSERT(SUCCEEDED(hr));
1778 
1779 		if (SUCCEEDED(hr) && (m_colorType == UI_SWATCHCOLORTYPE_RGB))
1780 		{
1781 			ATLASSERT(pCommandExecutionProperties);
1782 			PROPVARIANT var;
1783 			if SUCCEEDED(hr = pCommandExecutionProperties->GetValue(UI_PKEY_Color, &var))
1784 				hr = PropVariantToUInt32(var, &m_color);
1785 		}
1786 
1787 		if SUCCEEDED(hr)
1788 			GetWndRibbon().OnRibbonColorCtrlExecute(GetID(), verb, (UI_SWATCHCOLORTYPE)m_colorType/*uType*/, m_color);
1789 		else
1790 			ATLASSERT(FALSE); // something was wrong
1791 
1792 		return hr;
1793 	}
1794 
DoUpdateProperty(UINT nCmdID,REFPROPERTYKEY key,const PROPVARIANT * ppropvarCurrentValue,PROPVARIANT * ppropvarNewValue)1795 	virtual HRESULT DoUpdateProperty(UINT nCmdID, REFPROPERTYKEY key,
1796 	                                 const PROPVARIANT* ppropvarCurrentValue, PROPVARIANT* ppropvarNewValue)
1797 	{
1798 		ATLASSERT (nCmdID == GetID());
1799 
1800 		HRESULT hr = E_NOTIMPL;
1801 
1802 		switch (k_(key))
1803 		{
1804 		case k_ColorType:
1805 			hr = SetPropertyVal(key, m_colorType, ppropvarNewValue);
1806 			break;
1807 		case k_Color:
1808 			if (m_color == 0x800080) /*MAGENTA*/
1809 				m_color = GetWndRibbon().OnRibbonQueryColor(GetID());
1810 			hr = SetPropertyVal(key, m_color, ppropvarNewValue);
1811 			break;
1812 		case k_ColorMode:
1813 			break;
1814 		case k_ThemeColorsCategoryLabel:
1815 		case k_StandardColorsCategoryLabel:
1816 		case k_RecentColorsCategoryLabel:
1817 		case k_AutomaticColorLabel:
1818 		case k_NoColorLabel:
1819 		case k_MoreColorsLabel:
1820 			{
1821 				const UINT iLabel = k_(key) - k_ThemeColorsCategoryLabel;
1822 				if (m_sLabels[iLabel].IsEmpty())
1823 					if (LPCWSTR psLabel = GetWndRibbon().OnRibbonQueryColorLabel(GetID(), key))
1824 						m_sLabels[iLabel] = psLabel;
1825 				if (!m_sLabels[iLabel].IsEmpty())
1826 					hr = SetPropertyVal(key, (LPCWSTR)m_sLabels[iLabel], ppropvarNewValue);
1827 			}
1828 			break;
1829 		case k_ThemeColors:
1830 		case k_StandardColors:
1831 			{
1832 				const INT ic = k_(key) - k_ThemeColors;
1833 				if (!m_aColors[ic].GetSize())
1834 					if (COLORREF* pColor = GetWndRibbon().OnRibbonQueryColorArray(GetID(), key))
1835 						SetColorArray(key, pColor);
1836 				if (INT iMax = m_aColors[ic].GetSize())
1837 					hr = InitPropVariantFromUInt32Vector(m_aColors[ic].GetData(), iMax, ppropvarNewValue);
1838 			}
1839 			break;
1840 		case k_ThemeColorsTooltips:
1841 		case k_StandardColorsTooltips:
1842 			{
1843 				const INT ic = k_(key) - k_ThemeColorsTooltips;
1844 				if (m_aTooltips[ic].GetSize() == 0)
1845 					if (LPCWSTR* ppsTT = GetWndRibbon().OnRibbonQueryColorTooltips(GetID(), key))
1846 						SetColorTooltips(key, ppsTT);
1847 				if (INT iMax = m_aTooltips[ic].GetSize())
1848 					hr = InitPropVariantFromStringVector(m_aTooltips[ic].GetData(), iMax, ppropvarNewValue);
1849 			}
1850 			break;
1851 		default:
1852 			hr = CommandCtrlImpl::DoUpdateProperty(nCmdID, key, ppropvarCurrentValue, ppropvarNewValue);
1853 			break;
1854 		}
1855 
1856 		return hr;
1857 	}
1858 };
1859 
1860 // SpinnerCtrlImpl
1861 //
1862 template <class T, UINT t_ID, typename V = LONG>
1863 class SpinnerCtrlImpl : public CtrlImpl<T, t_ID>
1864 {
1865 public:
SpinnerCtrlImpl()1866 	SpinnerCtrlImpl()
1867 	{
1868 		m_Values[0] = m_Values[2] = m_Values[4] = 0;
1869 		m_Values[1] = 100;
1870 		m_Values[3] = 1;
1871 	}
1872 
1873 	V m_Values[5];
1874 		// k_DecimalValue = 201, k_MaxValue = 203, k_MinValue, k_Increment, k_DecimalPlaces
1875 
1876 	Text m_FormatString;
1877 	Text m_RepresentativeString;
1878 
1879 	// Operations
1880 	HRESULT SetDecimalPlaces(V vPlaces, bool bUpdate = false)
1881 	{
1882 		return SetValue(UI_PKEY_DecimalPlaces, vPlaces, bUpdate);
1883 	}
1884 
1885 	HRESULT SetMin(V vMin, bool bUpdate = false)
1886 	{
1887 		return SetValue(UI_PKEY_MinValue, vMin, bUpdate);
1888 	}
1889 
1890 	HRESULT SetMax(V vMax, bool bUpdate = false)
1891 	{
1892 		return SetValue(UI_PKEY_MaxValue, vMax, bUpdate);
1893 	}
1894 
1895 	HRESULT SetVal(V vVal, bool bUpdate = false)
1896 	{
1897 		return SetValue(UI_PKEY_DecimalValue, vVal, bUpdate);
1898 	}
1899 
1900 	HRESULT SetIncrement(V vIncrement, bool bUpdate = false)
1901 	{
1902 		return SetValue(UI_PKEY_Increment, vIncrement, bUpdate);
1903 	}
1904 
1905 	HRESULT SetFormatString(LPCWSTR sFormat, bool bUpdate = false)
1906 	{
1907 		return SetText(UI_PKEY_FormatString, sFormat, bUpdate);
1908 	}
1909 
1910 	HRESULT SetRepresentativeString(LPCWSTR sRepresentative, bool bUpdate = false)
1911 	{
1912 		return SetText(UI_PKEY_RepresentativeString, sRepresentative, bUpdate);
1913 	}
1914 
1915 	// Implementation
1916 	HRESULT SetText(REFPROPERTYKEY key, LPCWSTR sText, bool bUpdate = false)
1917 	{
1918 		switch (k_(key))
1919 		{
1920 		case k_FormatString:
1921 			m_FormatString = sText;
1922 			break;
1923 		case k_RepresentativeString:
1924 			m_RepresentativeString = sText;
1925 			break;
1926 		default:
1927 			return CtrlImpl::SetText(key, sText, bUpdate);
1928 		}
1929 
1930 		return bUpdate ?
1931 			GetWndRibbon().InvalidateProperty(GetID(), key) :
1932 			S_OK;
1933 	}
1934 
1935 	HRESULT SetValue(REFPROPERTYKEY key, V val, bool bUpdate = false)
1936 	{
1937 		ATLASSERT((k_(key) <= k_DecimalPlaces) && (k_(key) >= k_DecimalValue));
1938 
1939 		const INT iVal = k_(key) == k_DecimalValue ? 0 : k_(key) - k_StringValue;
1940 		m_Values[iVal] = val;
1941 
1942 		if (bUpdate)
1943 		{
1944 			if(k_(key) == k_DecimalValue)
1945 			{
1946 				DECIMAL decVal;
1947 				InitDecimal(val, &decVal);
1948 				return SetProperty(key, &decVal);
1949 			}
1950 			else
1951 			{
1952 				return GetWndRibbon().InvalidateProperty(GetID(), key);
1953 			}
1954 		}
1955 		else
1956 		{
1957 			return S_OK;
1958 		}
1959 	}
1960 
QueryValue(REFPROPERTYKEY key,LONG * plVal)1961 	HRESULT QueryValue(REFPROPERTYKEY key, LONG* plVal)
1962 	{
1963 		return GetWndRibbon().OnRibbonQuerySpinnerValue(GetID(), key, plVal) ? S_OK : S_FALSE;
1964 	}
1965 
QueryValue(REFPROPERTYKEY key,DOUBLE * pdVal)1966 	HRESULT QueryValue(REFPROPERTYKEY key, DOUBLE* pdVal)
1967 	{
1968 		return GetWndRibbon().OnRibbonQueryFloatSpinnerValue(GetID(), key, pdVal) ? S_OK : S_FALSE;
1969 	}
1970 
OnGetValue(REFPROPERTYKEY key,PROPVARIANT * ppv)1971 	HRESULT OnGetValue(REFPROPERTYKEY key, PROPVARIANT* ppv)
1972 	{
1973 		ATLASSERT((k_(key) <= k_DecimalPlaces) && (k_(key) >= k_DecimalValue));
1974 
1975 		const INT iVal = k_(key) == k_DecimalValue ? 0 : k_(key) - k_StringValue;
1976 
1977 		QueryValue(key, m_Values + iVal);
1978 
1979 		if (k_(key) == k_DecimalPlaces)
1980 		{
1981 			return SetPropertyVal(key, m_Values[iVal], ppv);
1982 		}
1983 		else
1984 		{
1985 			DECIMAL decVal;
1986 			InitDecimal(m_Values[iVal], &decVal);
1987 			return SetPropertyVal(key, &decVal, ppv);
1988 		}
1989 	}
1990 
OnGetText(REFPROPERTYKEY key,Text & sVal,PROPVARIANT * ppv)1991 	HRESULT OnGetText(REFPROPERTYKEY key, Text& sVal, PROPVARIANT* ppv)
1992 	{
1993 		if (LPCWSTR sNew = GetWndRibbon().OnRibbonQueryText(GetID(), key))
1994 			sVal = sNew;
1995 		return SetPropertyVal(key, (LPCWSTR)sVal, ppv);
1996 	}
1997 
DoExecute(UINT nCmdID,UI_EXECUTIONVERB verb,const PROPERTYKEY * key,const PROPVARIANT * ppropvarValue,IUISimplePropertySet *)1998 	virtual HRESULT DoExecute(UINT nCmdID, UI_EXECUTIONVERB verb,
1999 	                          const PROPERTYKEY* key, const PROPVARIANT* ppropvarValue,
2000 	                          IUISimplePropertySet* /*pCommandExecutionProperties*/)
2001 	{
2002 		ATLASSERT (nCmdID == GetID());
2003 		nCmdID;   // avoid level 4 warning
2004 		ATLASSERT (key && (k_(*key) == k_DecimalValue));
2005 		key;   // avoid level 4 warning
2006 		ATLASSERT (verb == UI_EXECUTIONVERB_EXECUTE);
2007 		verb;   // avoid level 4 warning
2008 
2009 		DECIMAL decVal;
2010 
2011 		HRESULT hr = UIPropertyToDecimal(UI_PKEY_DecimalValue, *ppropvarValue, &decVal);
2012 		hr = InitVal(m_Values[0], &decVal);
2013 
2014 		GetWndRibbon().OnRibbonSpinnerCtrlExecute(GetID(), &m_Values[0]);
2015 
2016 		return hr;
2017 	}
2018 
DoUpdateProperty(UINT nCmdID,REFPROPERTYKEY key,const PROPVARIANT * ppropvarCurrentValue,PROPVARIANT * ppropvarNewValue)2019 	virtual HRESULT DoUpdateProperty(UINT nCmdID, REFPROPERTYKEY key,
2020 	                                 const PROPVARIANT* ppropvarCurrentValue, PROPVARIANT* ppropvarNewValue)
2021 	{
2022 		ATLASSERT (nCmdID == GetID());
2023 
2024 		HRESULT hr = E_NOTIMPL;
2025 		switch (k_(key))
2026 		{
2027 		case k_DecimalPlaces:
2028 		case k_DecimalValue:
2029 		case k_Increment:
2030 		case k_MaxValue:
2031 		case k_MinValue:
2032 			hr = OnGetValue(key, ppropvarNewValue);
2033 			break;
2034 		case k_FormatString:
2035 			if (m_FormatString.IsEmpty())
2036 				return OnGetText(key, m_FormatString, ppropvarNewValue);
2037 			break;
2038 		case k_RepresentativeString:
2039 			if (m_RepresentativeString.IsEmpty())
2040 				return OnGetText(key, m_RepresentativeString, ppropvarNewValue);
2041 			break;
2042 		default:
2043 			hr = CtrlImpl::DoUpdateProperty(nCmdID, key, ppropvarCurrentValue, ppropvarNewValue);
2044 			break;
2045 		}
2046 
2047 		return hr;
2048 	}
2049 
2050 	// decimal conversion helpers
InitDecimal(LONG & val,DECIMAL * pDecimal)2051 	static HRESULT InitDecimal(LONG& val, DECIMAL* pDecimal)
2052 	{
2053 		return ::VarDecFromI4(val, pDecimal);
2054 	}
2055 
InitDecimal(DOUBLE & val,DECIMAL * pDecimal)2056 	static HRESULT InitDecimal(DOUBLE& val, DECIMAL* pDecimal)
2057 	{
2058 		return ::VarDecFromR8(val, pDecimal);
2059 	}
2060 
InitVal(LONG & val,const DECIMAL * pDecimal)2061 	static HRESULT InitVal(LONG& val, const DECIMAL* pDecimal)
2062 	{
2063 		return ::VarI4FromDec(pDecimal, &val);
2064 	}
2065 
InitVal(DOUBLE & val,const DECIMAL * pDecimal)2066 	static HRESULT InitVal(DOUBLE& val, const DECIMAL* pDecimal)
2067 	{
2068 		return ::VarR8FromDec(pDecimal, &val);
2069 	}
2070 };
2071 
2072 // CRibbonImpl Ribbon implementation class
2073 //
2074 template <class T>
2075 class CRibbonImpl :
2076 		public CRibbonUpdateUI<T>,
2077 		public ICtrl,
2078 		public IUIApplication,
2079 		public IUICommandHandler
2080 {
2081 	typedef CRibbonImpl<T> thisClass;
2082 public:
2083 	typedef thisClass Ribbon;
2084 	typedef T WndRibbon;
2085 
CRibbonImpl()2086 	CRibbonImpl() : m_bRibbonUI(false), m_hgRibbonSettings(NULL)
2087 	{
2088 #ifdef _DEBUG
2089 		m_cRef = 1;
2090 #endif
2091 		pWndRibbon = static_cast<T*>(this);
2092 		HRESULT hr = ::CoInitialize(NULL);
2093 		if(SUCCEEDED(hr))
2094 			if (RunTimeHelper::IsRibbonUIAvailable())
2095 				hr = m_pIUIFramework.CoCreateInstance(CLSID_UIRibbonFramework);
2096 			else
2097 				ATLTRACE2(atlTraceUI, 0, _T("Ribbon UI not available\n"));
2098 
2099 		if FAILED(hr)
2100 			ATLTRACE2(atlTraceUI, 0, _T("Ribbon construction failed\n"));
2101 
2102 		ATLASSERT(SUCCEEDED(hr));
2103 	}
2104 
~CRibbonImpl()2105 	~CRibbonImpl()
2106 	{
2107 		::GlobalFree(m_hgRibbonSettings);
2108 		m_pIUIFramework.Release();
2109 		::CoUninitialize();
2110 	}
2111 
GetRibbonCtrl(UINT)2112 	ICtrl& GetRibbonCtrl(UINT)
2113 	{
2114 		return static_cast<ICtrl&>(*this);
2115 	}
2116 
2117 	ATL::CComPtr<IUIFramework> m_pIUIFramework;
2118 	HGLOBAL m_hgRibbonSettings;
2119 	bool m_bRibbonUI;
2120 
IsRibbonUI()2121 	bool IsRibbonUI()
2122 	{
2123 		return m_bRibbonUI;
2124 	}
2125 
GetIUIFrameworkPtr()2126 	IUIFramework* GetIUIFrameworkPtr()
2127 	{
2128 		return m_pIUIFramework;
2129 	}
2130 
2131 	template <typename I>
GetRibbonViewPtr(UINT32 uID)2132 	I* GetRibbonViewPtr(UINT32 uID)
2133 	{
2134 		ATLASSERT(m_pIUIFramework);
2135 		ATL::CComPtr<I> pI;
2136 		return m_pIUIFramework->GetView(uID, __uuidof(I), (void**) &pI) == S_OK ?
2137 			pI :
2138 			NULL;
2139 	}
2140 
GetRibbonPtr()2141 	IUIRibbon* GetRibbonPtr()
2142 	{
2143 		return GetRibbonViewPtr<IUIRibbon>(0);
2144 	}
2145 
GetMenuPtr(UINT32 uID)2146 	IUIContextualUI* GetMenuPtr(UINT32 uID)
2147 	{
2148 		ATLASSERT(uID);
2149 		return GetRibbonViewPtr<IUIContextualUI>(uID);
2150 	}
2151 
GetRibbonHeight()2152 	UINT GetRibbonHeight()
2153 	{
2154 		ATLASSERT(IsRibbonUI());
2155 
2156 		UINT32 cy = 0;
2157 		if (ATL::CComPtr<IUIRibbon> pIUIRibbon = GetRibbonPtr())
2158 			pIUIRibbon->GetHeight(&cy);
2159 		return cy;
2160 	}
2161 
2162 	HRESULT CreateRibbon(LPCWSTR sResName = L"APPLICATION_RIBBON")
2163 	{
2164 		T* pT = static_cast<T*>(this);
2165 		ATLASSERT(GetIUIFrameworkPtr() && !IsRibbonUI());
2166 		ATLASSERT(pT->IsWindow());
2167 
2168 		HRESULT hr = m_pIUIFramework->Initialize(pT->m_hWnd, this);
2169 
2170 		if (hr == S_OK)
2171 			hr = m_pIUIFramework->LoadUI(ModuleHelper::GetResourceInstance(), sResName);
2172 
2173 		return hr;
2174 	}
2175 
DestroyRibbon()2176 	HRESULT DestroyRibbon()
2177 	{
2178 		T* pT = static_cast<T*>(this);
2179 		ATLASSERT(GetIUIFrameworkPtr() && IsRibbonUI());
2180 		ATLASSERT(pT->IsWindow());
2181 
2182 		HRESULT hRes = m_pIUIFramework->Destroy();
2183 		if (!RunTimeHelper::IsWin7())
2184 			pT->SetWindowRgn(NULL, TRUE); // Vista Basic bug workaround
2185 		return hRes;
2186 	}
2187 
2188 // Ribbon persistency
2189 	HRESULT operator >>(IStream* pIStream)
2190 	{
2191 		ATLASSERT(GetIUIFrameworkPtr());
2192 		ATLASSERT(pIStream);
2193 
2194 		HRESULT hr = E_FAIL;
2195 		if (ATL::CComPtr<IUIRibbon> pIUIRibbon = GetRibbonPtr())
2196 		{
2197 			const LARGE_INTEGER li0 = { 0 };
2198 			pIStream->Seek(li0, STREAM_SEEK_SET, NULL);
2199 			hr = pIUIRibbon->SaveSettingsToStream(pIStream);
2200 			pIStream->Commit(STGC_DEFAULT);
2201 		}
2202 
2203 		return hr;
2204 	}
2205 
2206 	HRESULT operator <<(IStream* pIStream)
2207 	{
2208 		ATLASSERT(GetIUIFrameworkPtr());
2209 		ATLASSERT(pIStream);
2210 
2211 		HRESULT hr = E_FAIL;
2212 		if (ATL::CComPtr<IUIRibbon> pIUIRibbon = GetRibbonPtr())
2213 		{
2214 			const LARGE_INTEGER li0 = { 0 };
2215 			pIStream->Seek(li0, STREAM_SEEK_SET, NULL);
2216 			hr = pIUIRibbon->LoadSettingsFromStream(pIStream);
2217 		}
2218 
2219 		return hr;
2220 	}
2221 
ResetRibbonSettings()2222 	void ResetRibbonSettings()
2223 	{
2224 		if (m_hgRibbonSettings != NULL)
2225 		{
2226 			::GlobalFree(m_hgRibbonSettings);
2227 			m_hgRibbonSettings = NULL;
2228 		}
2229 	}
2230 
SaveRibbonSettings()2231 	HRESULT SaveRibbonSettings()
2232 	{
2233 		ATLASSERT(GetIUIFrameworkPtr());
2234 		ATLASSERT(static_cast<T*>(this)->IsWindow());
2235 
2236 		HRESULT hr = E_FAIL;
2237 		ATL::CComPtr<IStream> pIStream;
2238 
2239 		if SUCCEEDED(hr = ::CreateStreamOnHGlobal(m_hgRibbonSettings, FALSE, &pIStream))
2240 			hr = *this >> pIStream;
2241 
2242 		if (SUCCEEDED(hr) && (m_hgRibbonSettings == NULL))
2243 			hr = ::GetHGlobalFromStream(pIStream, &m_hgRibbonSettings);
2244 
2245 		if FAILED(hr)
2246 			ResetRibbonSettings();
2247 
2248 		return hr;
2249 	}
2250 
RestoreRibbonSettings()2251 	HRESULT RestoreRibbonSettings()
2252 	{
2253 		ATLASSERT(GetIUIFrameworkPtr());
2254 		ATLASSERT(m_hgRibbonSettings);
2255 		ATLASSERT(static_cast<T*>(this)->IsWindow());
2256 
2257 		HRESULT hr = E_FAIL;
2258 		ATL::CComPtr<IStream> pIStream;
2259 
2260 		if SUCCEEDED(hr = ::CreateStreamOnHGlobal(m_hgRibbonSettings, FALSE, &pIStream))
2261 			hr = *this << pIStream;
2262 
2263 		if FAILED(hr)
2264 			ResetRibbonSettings();
2265 
2266 		return hr;
2267 	}
2268 
2269 // QAT dock states
GetQATDock()2270 	UI_CONTROLDOCK GetQATDock()
2271 	{
2272 		ATLASSERT(GetIUIFrameworkPtr());
2273 		ATLASSERT(IsRibbonUI());
2274 
2275 		UINT32 uDock = 0;
2276 		PROPVARIANT propvar;
2277 		ATL::CComQIPtr<IPropertyStore>pIPS(GetRibbonPtr());
2278 
2279 		if ((pIPS != NULL) && SUCCEEDED(pIPS->GetValue(UI_PKEY_QuickAccessToolbarDock, &propvar)) &&
2280 			SUCCEEDED(UIPropertyToUInt32(UI_PKEY_QuickAccessToolbarDock, propvar, &uDock)))
2281 				return (UI_CONTROLDOCK)uDock;
2282 
2283 		ATLASSERT(FALSE); // something was wrong
2284 		return (UI_CONTROLDOCK)0;
2285 	}
2286 
SetQATDock(UI_CONTROLDOCK dockState)2287 	bool SetQATDock(UI_CONTROLDOCK dockState)
2288 	{
2289 		ATLASSERT(GetIUIFrameworkPtr());
2290 		ATLASSERT(IsRibbonUI());
2291 
2292 		PROPVARIANT propvar;
2293 		ATLVERIFY(SUCCEEDED(SetPropertyVal(UI_PKEY_QuickAccessToolbarDock, dockState, &propvar)));
2294 
2295 		ATL::CComQIPtr<IPropertyStore>pIPS(GetRibbonPtr());
2296 		if ((pIPS != NULL) && SUCCEEDED(pIPS->SetValue(UI_PKEY_QuickAccessToolbarDock, propvar)))
2297 		{
2298 			pIPS->Commit();
2299 			return true;
2300 		}
2301 
2302 		ATLASSERT(FALSE); // something was wrong
2303 		return false;
2304 	}
2305 
2306 // Ribbon display states
GetRibbonDisplayState(REFPROPERTYKEY key)2307 	bool GetRibbonDisplayState(REFPROPERTYKEY key)
2308 	{
2309 		ATLASSERT(GetIUIFrameworkPtr());
2310 		ATLASSERT(IsRibbonUI());
2311 		ATLASSERT((k_(key) == k_Viewable) || (k_(key) == k_Minimized));
2312 
2313 		PROPVARIANT propvar;
2314 		ATL::CComQIPtr<IPropertyStore>pIPS(GetRibbonPtr());
2315 
2316 		if ((pIPS != NULL) && SUCCEEDED(pIPS->GetValue(key, &propvar)))
2317 		{
2318 			BOOL bState = FALSE;
2319 			if SUCCEEDED(UIPropertyToBoolean(key, propvar, &bState))
2320 				return (bState != FALSE);
2321 		}
2322 
2323 		ATLASSERT(FALSE); // something was wrong
2324 		return false;
2325 	}
2326 
2327 	bool SetRibbonDisplayState(REFPROPERTYKEY key, bool bState = true)
2328 	{
2329 		ATLASSERT(GetIUIFrameworkPtr());
2330 		ATLASSERT(IsRibbonUI());
2331 		ATLASSERT((k_(key) == k_Viewable) || (k_(key) == k_Minimized));
2332 
2333 		PROPVARIANT propvar;
2334 		ATLVERIFY(SUCCEEDED(SetPropertyVal(key, bState, &propvar)));
2335 
2336 		ATL::CComQIPtr<IPropertyStore>pIPS(GetRibbonPtr());
2337 
2338 		if ((pIPS != NULL) && SUCCEEDED(pIPS->SetValue(key, propvar)))
2339 		{
2340 			pIPS->Commit();
2341 			return true;
2342 		}
2343 
2344 		ATLASSERT(FALSE); // something was wrong
2345 		return false;
2346 	}
2347 
IsRibbonMinimized()2348 	bool IsRibbonMinimized()
2349 	{
2350 		return GetRibbonDisplayState(UI_PKEY_Minimized);
2351 	}
2352 
2353 	bool MinimizeRibbon(bool bMinimize = true)
2354 	{
2355 		return SetRibbonDisplayState(UI_PKEY_Minimized, bMinimize);
2356 	}
2357 
IsRibbonHidden()2358 	bool IsRibbonHidden()
2359 	{
2360 		return !GetRibbonDisplayState(UI_PKEY_Viewable);
2361 	}
2362 
2363 	bool HideRibbon(bool bHide = true)
2364 	{
2365 		return SetRibbonDisplayState(UI_PKEY_Viewable, !bHide);
2366 	}
2367 
2368 // Ribbon colors
GetRibbonColor(REFPROPERTYKEY key)2369 	UI_HSBCOLOR GetRibbonColor(REFPROPERTYKEY key)
2370 	{
2371 		ATLASSERT(GetIUIFrameworkPtr());
2372 		ATLASSERT(IsRibbonUI());
2373 		ATLASSERT((k_(key) >= k_GlobalBackgroundColor) && (k_(key) <= k_GlobalTextColor));
2374 
2375 		PROPVARIANT propvar;
2376 		ATL::CComQIPtr<IPropertyStore>pIPS(GetIUIFrameworkPtr());
2377 
2378 		if ((pIPS != NULL) && SUCCEEDED(pIPS->GetValue(key, &propvar)))
2379 		{
2380 			UINT32 color = 0;
2381 			if SUCCEEDED(UIPropertyToUInt32(key, propvar, &color))
2382 				return color;
2383 		}
2384 
2385 		ATLASSERT(FALSE); // something was wrong
2386 		return 0;
2387 	}
2388 
SetRibbonColor(REFPROPERTYKEY key,UI_HSBCOLOR color)2389 	bool SetRibbonColor(REFPROPERTYKEY key, UI_HSBCOLOR color)
2390 	{
2391 		ATLASSERT(GetIUIFrameworkPtr());
2392 		ATLASSERT(IsRibbonUI());
2393 		ATLASSERT((k_(key) >= k_GlobalBackgroundColor) && (k_(key) <= k_GlobalTextColor));
2394 
2395 		PROPVARIANT propvar;
2396 		ATLVERIFY(SUCCEEDED(SetPropertyVal(key, color, &propvar)));
2397 
2398 		ATL::CComQIPtr<IPropertyStore>pIPS(GetIUIFrameworkPtr());
2399 
2400 		if ((pIPS != NULL) && SUCCEEDED(pIPS->SetValue(key, propvar)))
2401 		{
2402 			pIPS->Commit();
2403 			return true;
2404 		}
2405 
2406 		ATLASSERT(FALSE); // something was wrong
2407 		return false;
2408 	}
2409 
2410 // Ribbon modes
SetRibbonModes(INT32 iModes)2411 	HRESULT SetRibbonModes(INT32 iModes)
2412 	{
2413 		ATLASSERT(IsRibbonUI());
2414 		return GetIUIFrameworkPtr()->SetModes(iModes);
2415 	}
2416 
2417 // Ribbon contextual tab
GetRibbonContextAvail(UINT32 uID)2418 	UI_CONTEXTAVAILABILITY GetRibbonContextAvail(UINT32 uID)
2419 	{
2420 		ATLASSERT(GetIUIFrameworkPtr());
2421 
2422 		PROPVARIANT propvar;
2423 		if (IsRibbonUI() &&
2424 		    SUCCEEDED(GetIUIFrameworkPtr()->GetUICommandProperty(uID, UI_PKEY_ContextAvailable, &propvar)))
2425 		{
2426 			UINT uav;
2427 			if (SUCCEEDED(PropVariantToUInt32(propvar, &uav)))
2428 			{
2429 				CUpdateUIBase::UIEnable(uID, uav != UI_CONTEXTAVAILABILITY_NOTAVAILABLE);
2430 				CUpdateUIBase::UISetCheck(uID, uav == UI_CONTEXTAVAILABILITY_ACTIVE);
2431 				return (UI_CONTEXTAVAILABILITY)uav;
2432 			}
2433 		}
2434 
2435 		return UI_CONTEXTAVAILABILITY_NOTAVAILABLE;
2436 	}
2437 
SetRibbonContextAvail(UINT32 uID,UI_CONTEXTAVAILABILITY cav)2438 	HRESULT SetRibbonContextAvail(UINT32 uID, UI_CONTEXTAVAILABILITY cav)
2439 	{
2440 		CUpdateUIBase::UIEnable(uID, cav != UI_CONTEXTAVAILABILITY_NOTAVAILABLE);
2441 		CUpdateUIBase::UISetCheck(uID, cav == UI_CONTEXTAVAILABILITY_ACTIVE);
2442 
2443 		return SetProperty((WORD)uID, UI_PKEY_ContextAvailable, UINT32(cav));
2444 	}
2445 
2446 // Ribbon context menu
HasRibbonMenu(UINT32 uID)2447 	bool HasRibbonMenu(UINT32 uID)
2448 	{
2449 		ATL::CComPtr<IUIContextualUI> pI = GetMenuPtr(uID);
2450 		return pI != NULL;
2451 	}
2452 
TrackRibbonMenu(UINT32 uID,INT32 x,INT32 y)2453 	HRESULT TrackRibbonMenu(UINT32 uID, INT32 x, INT32 y)
2454 	{
2455 		ATLASSERT(HasRibbonMenu(uID));
2456 
2457 		return IsRibbonUI() ?
2458 			ATL::CComPtr<IUIContextualUI>(GetMenuPtr(uID))->ShowAtLocation(x, y) :
2459 			E_FAIL;
2460 	}
2461 
TrackRibbonMenu(UINT32 uID,LPARAM lParam)2462 	HRESULT TrackRibbonMenu(UINT32 uID, LPARAM lParam)
2463 	{
2464 		return TrackRibbonMenu(uID, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));
2465 	}
2466 
2467 // Overrideables
OnRibbonQueryImage(UINT nCmdID,REFPROPERTYKEY)2468 	HBITMAP OnRibbonQueryImage(UINT nCmdID, REFPROPERTYKEY /*key*/)
2469 	{
2470 		return DefRibbonQueryImage(nCmdID);
2471 	}
2472 
OnRibbonQueryText(UINT nCmdID,REFPROPERTYKEY key)2473 	LPCWSTR OnRibbonQueryText(UINT nCmdID, REFPROPERTYKEY key)
2474 	{
2475 		return DefRibbonQueryText(nCmdID, key);
2476 	}
2477 
OnRibbonQueryState(UINT nCmdID,REFPROPERTYKEY key)2478 	bool OnRibbonQueryState(UINT nCmdID, REFPROPERTYKEY key)
2479 	{
2480 		return DefRibbonQueryState(nCmdID, key);
2481 	}
2482 
OnRibbonQueryTabAvail(UINT nCmdID)2483 	UI_CONTEXTAVAILABILITY OnRibbonQueryTabAvail(UINT nCmdID)
2484 	{
2485 		DWORD dwState = UIGetState(nCmdID);
2486 		return ((dwState & UPDUI_DISABLED) == UPDUI_DISABLED) ?
2487 			UI_CONTEXTAVAILABILITY_NOTAVAILABLE :
2488 			(((dwState & UPDUI_CHECKED) == UPDUI_CHECKED) ?
2489 				UI_CONTEXTAVAILABILITY_ACTIVE :
2490 				UI_CONTEXTAVAILABILITY_AVAILABLE);
2491 	}
2492 
OnRibbonQueryComboText(UINT32)2493 	LPCWSTR OnRibbonQueryComboText(UINT32 /*uCtrlID*/)
2494 	{
2495 		return NULL;
2496 	}
2497 
OnRibbonQueryCategoryText(UINT32,UINT32)2498 	LPCWSTR OnRibbonQueryCategoryText(UINT32 /*uCtrlID*/, UINT32 /*uCat*/)
2499 	{
2500 		return L"Category";
2501 	}
2502 
OnRibbonQueryItemCategory(UINT32,UINT32)2503 	UINT32 OnRibbonQueryItemCategory(UINT32 /*uCtrlID*/, UINT32 /*uItem*/)
2504 	{
2505 		return 0;
2506 	}
2507 
OnRibbonQueryItemText(UINT32 uCtrlID,UINT32 uItem)2508 	LPCWSTR OnRibbonQueryItemText(UINT32 uCtrlID, UINT32 uItem)
2509 	{
2510 		return DefRibbonQueryItemText(uCtrlID, uItem);
2511 	}
2512 
OnRibbonQuerySelectedItem(UINT32,UINT32 &)2513 	bool OnRibbonQuerySelectedItem(UINT32 /*uCtrlID*/, UINT32& /*uSel*/)
2514 	{
2515 		return false;
2516 	}
2517 
OnRibbonQueryItemImage(UINT32 uCtrlID,UINT32 uItem)2518 	HBITMAP OnRibbonQueryItemImage(UINT32 uCtrlID, UINT32 uItem)
2519 	{
2520 		return DefRibbonQueryItemImage(uCtrlID, uItem);
2521 	}
2522 
OnRibbonQueryItemCommand(UINT32 uCtrlID,UINT32 uItem)2523 	UINT32 OnRibbonQueryItemCommand(UINT32 uCtrlID, UINT32 uItem)
2524 	{
2525 		return DefRibbonQueryItemCommand(uCtrlID, uItem);
2526 	}
2527 
OnRibbonQueryItemCommandType(UINT32,UINT32)2528 	UI_COMMANDTYPE OnRibbonQueryItemCommandType(UINT32 /*uCtrlID*/, UINT32 /*uItem*/)
2529 	{
2530 		return UI_COMMANDTYPE_ACTION;
2531 	}
2532 
OnRibbonQueryRecentItemName(LPCWSTR sPath)2533 	LPCWSTR OnRibbonQueryRecentItemName(LPCWSTR sPath)
2534 	{
2535 		return ::PathFindFileName(sPath);
2536 	}
2537 
OnRibbonQueryFont(UINT,CHARFORMAT2 &)2538 	bool OnRibbonQueryFont(UINT /*nId*/, CHARFORMAT2& /*cf*/)
2539 	{
2540 		return false;
2541 	}
2542 
OnRibbonQuerySpinnerValue(UINT,REFPROPERTYKEY,LONG *)2543 	bool OnRibbonQuerySpinnerValue(UINT /*nCmdID*/, REFPROPERTYKEY /*key*/, LONG* /*pVal*/)
2544 	{
2545 		return false;
2546 	}
2547 
OnRibbonQueryFloatSpinnerValue(UINT,REFPROPERTYKEY,DOUBLE *)2548 	bool OnRibbonQueryFloatSpinnerValue(UINT /*nCmdID*/, REFPROPERTYKEY /*key*/, DOUBLE* /*pVal*/)
2549 	{
2550 		return false;
2551 	}
2552 
OnRibbonQueryColor(UINT)2553 	COLORREF OnRibbonQueryColor(UINT /*nCmdID*/)
2554 	{
2555 		return 0x800080; /*MAGENTA*/
2556 	}
2557 
OnRibbonQueryColorLabel(UINT,REFPROPERTYKEY)2558 	LPCWSTR OnRibbonQueryColorLabel(UINT /*nCmdID*/, REFPROPERTYKEY /*key*/)
2559 	{
2560 		return NULL;
2561 	}
2562 
OnRibbonQueryColorArray(UINT,REFPROPERTYKEY)2563 	COLORREF* OnRibbonQueryColorArray(UINT /*nCmdID*/, REFPROPERTYKEY /*key*/)
2564 	{
2565 		return NULL;
2566 	}
2567 
OnRibbonQueryColorTooltips(UINT,REFPROPERTYKEY)2568 	LPCWSTR* OnRibbonQueryColorTooltips(UINT /*nCmdID*/, REFPROPERTYKEY /*key*/)
2569 	{
2570 		return NULL;
2571 	}
2572 
OnRibbonItemSelected(UINT32 uCtrlID,UI_EXECUTIONVERB verb,UINT32 uItem)2573 	bool OnRibbonItemSelected(UINT32 uCtrlID, UI_EXECUTIONVERB verb, UINT32 uItem)
2574 	{
2575 		DefCommandExecute(MAKELONG(uCtrlID, verb), uItem);
2576 		return true;
2577 	}
2578 
OnRibbonColorCtrlExecute(UINT32 uCtrlID,UI_EXECUTIONVERB verb,UI_SWATCHCOLORTYPE uType,COLORREF color)2579 	void OnRibbonColorCtrlExecute(UINT32 uCtrlID, UI_EXECUTIONVERB verb, UI_SWATCHCOLORTYPE uType, COLORREF color)
2580 	{
2581 		DefRibbonColorCtrlExecute(uCtrlID, verb, uType, color);
2582 	}
2583 
OnRibbonFontCtrlExecute(UINT32 uCtrlID,UI_EXECUTIONVERB verb,CHARFORMAT2 * pcf)2584 	void OnRibbonFontCtrlExecute(UINT32 uCtrlID, UI_EXECUTIONVERB verb, CHARFORMAT2* pcf)
2585 	{
2586 		DefCommandExecute(MAKELONG(uCtrlID, verb), (LPARAM)pcf);
2587 	}
2588 
OnRibbonSpinnerCtrlExecute(UINT32 uCtrlID,LONG * pVal)2589 	void OnRibbonSpinnerCtrlExecute(UINT32 uCtrlID, LONG* pVal)
2590 	{
2591 		DefCommandExecute(uCtrlID, *pVal);
2592 	}
2593 
OnRibbonSpinnerCtrlExecute(UINT32 uCtrlID,DOUBLE * pVal)2594 	void OnRibbonSpinnerCtrlExecute(UINT32 uCtrlID, DOUBLE* pVal)
2595 	{
2596 		DefCommandExecute(uCtrlID, (LPARAM)pVal);
2597 	}
2598 
OnRibbonCommandExecute(UINT32 uCmdID)2599 	void OnRibbonCommandExecute(UINT32 uCmdID)
2600 	{
2601 		DefCommandExecute(uCmdID);
2602 	}
2603 
2604 // Default implementations
DefRibbonQueryImage(UINT nCmdID)2605 	HBITMAP DefRibbonQueryImage(UINT nCmdID)
2606 	{
2607 		return AtlLoadBitmapImage(nCmdID, LR_CREATEDIBSECTION);
2608 	}
2609 
DefRibbonQueryState(UINT nCmdID,REFPROPERTYKEY key)2610 	bool DefRibbonQueryState(UINT nCmdID, REFPROPERTYKEY key)
2611 	{
2612 		DWORD dwState = UIGetState(nCmdID);
2613 		bool bRet = false;
2614 		switch (k_(key))
2615 		{
2616 		case k_BooleanValue:
2617 			bRet = (dwState & UPDUI_CHECKED) == UPDUI_CHECKED;
2618 			break;
2619 		case k_Enabled:
2620 			bRet = (dwState & UPDUI_DISABLED) != UPDUI_DISABLED;
2621 			break;
2622 		default:
2623 			ATLASSERT(FALSE);
2624 			break;
2625 		}
2626 
2627 		return bRet;
2628 	}
2629 
DefRibbonQueryText(UINT nCmdID,REFPROPERTYKEY key)2630 	LPCTSTR DefRibbonQueryText(UINT nCmdID, REFPROPERTYKEY key)
2631 	{
2632 		static WCHAR sText[RIBBONUI_MAX_TEXT] = { 0 };
2633 
2634 		if (k_(key) == k_Label)
2635 			 return UIGetText(nCmdID);
2636 
2637 		if (AtlLoadString(nCmdID, sText, RIBBONUI_MAX_TEXT))
2638 		{
2639 			PWCHAR pTitle = wcschr(sText, L'\n');
2640 			switch (k_(key))
2641 			{
2642 			case k_Keytip:
2643 				if (PWCHAR pAmp = wcschr(sText, L'&'))
2644 					pTitle = pAmp;
2645 				if (pTitle != NULL)
2646 					*(pTitle + 2) = NULL; // fall through
2647 			case k_TooltipTitle:
2648 				return pTitle ? ++pTitle : NULL;
2649 			case k_TooltipDescription:
2650 			case k_LabelDescription:
2651 				if (pTitle != NULL)
2652 					*pTitle = NULL;
2653 				return sText;
2654 			}
2655 		}
2656 
2657 		return NULL;
2658 	}
2659 
DefRibbonQueryItemText(UINT32 uCtrlID,UINT32 uItem)2660 	LPCWSTR DefRibbonQueryItemText(UINT32 uCtrlID, UINT32 uItem)
2661 	{
2662 		return DefRibbonQueryText(uCtrlID + 1 + uItem, UI_PKEY_LabelDescription);
2663 	}
2664 
DefRibbonQueryItemImage(UINT32 uCtrlID,UINT32 uItem)2665 	HBITMAP DefRibbonQueryItemImage(UINT32 uCtrlID, UINT32 uItem)
2666 	{
2667 		return DefRibbonQueryImage(uCtrlID + 1 + uItem);
2668 	}
2669 
DefRibbonQueryItemCommand(UINT32 uCtrlID,UINT32 uItem)2670 	UINT32 DefRibbonQueryItemCommand(UINT32 uCtrlID, UINT32 uItem)
2671 	{
2672 		return uCtrlID + 1 + uItem;
2673 	}
2674 
DefRibbonColorCtrlExecute(UINT32 uCtrlID,UI_EXECUTIONVERB verb,UI_SWATCHCOLORTYPE uType,COLORREF color)2675 	void DefRibbonColorCtrlExecute(UINT32 uCtrlID, UI_EXECUTIONVERB verb, UI_SWATCHCOLORTYPE uType, COLORREF color)
2676 	{
2677 		switch(uType)
2678 		{
2679 		case UI_SWATCHCOLORTYPE_RGB:
2680 			break;
2681 		case UI_SWATCHCOLORTYPE_AUTOMATIC:
2682 			color = ::GetSysColor(COLOR_WINDOWTEXT);
2683 			break;
2684 		case UI_SWATCHCOLORTYPE_NOCOLOR:
2685 			color = ::GetSysColor(COLOR_WINDOW);
2686 			break;
2687 		default:
2688 			ATLASSERT(FALSE);
2689 			break;
2690 		}
2691 
2692 		DefCommandExecute(MAKELONG(uCtrlID, verb), color);
2693 	}
2694 
2695 	void DefCommandExecute(UINT32 uCmd, LPARAM lParam = 0)
2696 	{
2697 		static_cast<T*>(this)->PostMessage(WM_COMMAND, uCmd, lParam);
2698 	}
2699 
2700 // Elements setting helpers
InvalidateCtrl(UINT32 nID)2701 	HRESULT InvalidateCtrl(UINT32 nID)
2702 	{
2703 		return IsRibbonUI() ?
2704 			GetIUIFrameworkPtr()->InvalidateUICommand(nID, UI_INVALIDATIONS_ALLPROPERTIES, NULL) :
2705 			E_FAIL;
2706 	}
2707 
2708 	HRESULT InvalidateProperty(UINT32 nID, REFPROPERTYKEY key, UI_INVALIDATIONS flags = UI_INVALIDATIONS_PROPERTY)
2709 	{
2710 		return IsRibbonUI() ?
2711 			GetIUIFrameworkPtr()->InvalidateUICommand(nID, flags, &key) :
2712 			E_FAIL;
2713 	}
2714 
2715 	template <typename V>
SetProperty(WORD wID,REFPROPERTYKEY key,V val)2716 	HRESULT SetProperty(WORD wID, REFPROPERTYKEY key, V val)
2717 	{
2718 		if (IsRibbonUI())
2719 		{
2720 			PROPVARIANT var;
2721 			if (SUCCEEDED(RibbonUI::SetPropertyVal(key, val, &var)))
2722 			{
2723 				return SetProperty(wID, key, var);
2724 			}
2725 			return E_INVALIDARG;
2726 		}
2727 		else
2728 		{
2729 			return E_FAIL;
2730 		}
2731 	}
2732 
2733 	template <>
SetProperty(WORD nID,REFPROPERTYKEY key,PROPVARIANT var)2734 	HRESULT SetProperty(WORD nID, REFPROPERTYKEY key, PROPVARIANT var)
2735 	{
2736 		return IsRibbonUI() ?
2737 			GetIUIFrameworkPtr()->SetUICommandProperty(nID, key, var) :
2738 			E_FAIL;
2739 	}
2740 
2741 // Interfaces
2742 	// IUIApplication
OnViewChanged(UINT32,UI_VIEWTYPE,IUnknown *,UI_VIEWVERB verb,INT32)2743 	STDMETHODIMP OnViewChanged(UINT32, UI_VIEWTYPE, IUnknown*, UI_VIEWVERB verb, INT32)
2744 	{
2745 		switch (verb)
2746 		{
2747 		case UI_VIEWVERB_CREATE:
2748 			m_bRibbonUI = true;
2749 			if (m_hgRibbonSettings != NULL)
2750 				RestoreRibbonSettings();
2751 			break;
2752 		case UI_VIEWVERB_SIZE:
2753 			static_cast<T*>(this)->UpdateLayout(FALSE);
2754 			break;
2755 		case UI_VIEWVERB_DESTROY:
2756 			SaveRibbonSettings();
2757 			m_bRibbonUI = false;
2758 			break;
2759 		}
2760 
2761 		return S_OK;
2762 	}
2763 
OnCreateUICommand(UINT32 nCmdID,UI_COMMANDTYPE typeID,IUICommandHandler ** ppCommandHandler)2764 	STDMETHODIMP OnCreateUICommand(UINT32 nCmdID, UI_COMMANDTYPE typeID, IUICommandHandler** ppCommandHandler)
2765 	{
2766 		UIAddRibbonElement(nCmdID);
2767 		if (typeID == UI_COMMANDTYPE_CONTEXT)
2768 			CUpdateUIBase::UIEnable(nCmdID, false);
2769 		*ppCommandHandler = this;
2770 		return S_OK;
2771 	}
2772 
OnDestroyUICommand(UINT32 nCmdID,UI_COMMANDTYPE,IUICommandHandler *)2773 	STDMETHODIMP OnDestroyUICommand(UINT32 nCmdID, UI_COMMANDTYPE, IUICommandHandler*)
2774 	{
2775 		UIRemoveRibbonElement(nCmdID);
2776 		return S_OK;
2777 	}
2778 
2779 	// IUICommandHandler
Execute(UINT nCmdID,UI_EXECUTIONVERB verb,const PROPERTYKEY * key,const PROPVARIANT * ppropvarValue,IUISimplePropertySet * pCommandExecutionProperties)2780 	STDMETHODIMP Execute(UINT nCmdID,
2781 		UI_EXECUTIONVERB verb,
2782 		const PROPERTYKEY* key,
2783 		const PROPVARIANT* ppropvarValue,
2784 		IUISimplePropertySet* pCommandExecutionProperties)
2785 	{
2786 		T* pT =static_cast<T*>(this);
2787 		return pT->GetRibbonCtrl(nCmdID).DoExecute(nCmdID, verb, key, ppropvarValue, pCommandExecutionProperties);
2788 	}
2789 
UpdateProperty(UINT nCmdID,REFPROPERTYKEY key,const PROPVARIANT * ppropvarCurrentValue,PROPVARIANT * ppropvarNewValue)2790 	STDMETHODIMP UpdateProperty(UINT nCmdID, REFPROPERTYKEY key,
2791 	                            const PROPVARIANT* ppropvarCurrentValue, PROPVARIANT* ppropvarNewValue)
2792 	{
2793 		T* pT =static_cast<T*>(this);
2794 		return pT->GetRibbonCtrl(nCmdID).DoUpdateProperty(nCmdID, key, ppropvarCurrentValue, ppropvarNewValue);
2795 	}
2796 
2797 #ifdef _DEBUG
2798 	// IUnknown methods (heavyweight)
AddRef()2799 	STDMETHODIMP_(ULONG) AddRef()
2800 	{
2801 		return InterlockedIncrement(&m_cRef);
2802 	}
2803 
Release()2804 	STDMETHODIMP_(ULONG) Release()
2805 	{
2806 		LONG cRef = InterlockedDecrement(&m_cRef);
2807 		if (cRef == 0) // NoOp for breakpoint
2808 		{
2809 			cRef = 0;
2810 		}
2811 
2812 		return cRef;
2813 	}
2814 
QueryInterface(REFIID iid,void ** ppv)2815 	STDMETHODIMP QueryInterface(REFIID iid, void** ppv)
2816 	{
2817 		if (ppv == NULL)
2818 		{
2819 			return E_POINTER;
2820 		}
2821 		else if ((iid == __uuidof(IUnknown)) ||
2822 		         (iid == __uuidof(IUICommandHandler)) ||
2823 		         (iid == __uuidof(IUIApplication)))
2824 		{
2825 			*ppv = this;
2826 			AddRef();
2827 			return S_OK;
2828 		}
2829 		else
2830 		{
2831 			return E_NOINTERFACE;
2832 		}
2833 	}
2834 
2835 	LONG m_cRef;
2836 #else
2837 	// IUnknown methods (lightweight)
QueryInterface(REFIID iid,void ** ppv)2838 	STDMETHODIMP QueryInterface(REFIID iid, void** ppv)
2839 	{
2840 		if ((iid == __uuidof(IUnknown)) ||
2841 		    (iid == __uuidof(IUICommandHandler)) ||
2842 		    (iid == __uuidof(IUIApplication)))
2843 		{
2844 			*ppv = this;
2845 			return S_OK;
2846 		}
2847 		return E_NOINTERFACE;
2848 	}
AddRef()2849 	ULONG STDMETHODCALLTYPE AddRef()
2850 	{
2851 		return 1;
2852 	}
Release()2853 	ULONG STDMETHODCALLTYPE Release()
2854 	{
2855 		return 1;
2856 	}
2857 #endif
2858 
2859 // CRibbonImpl ICtrl implementation
DoExecute(UINT nCmdID,UI_EXECUTIONVERB verb,const PROPERTYKEY * key,const PROPVARIANT * ppropvarValue,IUISimplePropertySet *)2860 	virtual HRESULT DoExecute(UINT nCmdID, UI_EXECUTIONVERB verb,
2861 	                          const PROPERTYKEY* key, const PROPVARIANT* ppropvarValue,
2862 	                          IUISimplePropertySet* /*pCommandExecutionProperties*/)
2863 	{
2864 		if (key != NULL)
2865 		{
2866 			if(k_(*key) != k_BooleanValue)
2867 			{
2868 				ATLTRACE2(atlTraceUI, 0, _T("Control ID %d is not handled\n"), nCmdID);
2869 				return E_NOTIMPL;
2870 			}
2871 			BOOL bChecked = FALSE;
2872 			ATLVERIFY(SUCCEEDED(PropVariantToBoolean(*ppropvarValue, &bChecked)));
2873 			CUpdateUIBase::UISetCheck(nCmdID, bChecked);
2874 		}
2875 
2876 		ATLASSERT(verb == UI_EXECUTIONVERB_EXECUTE);
2877 		verb;   // avoid level 4 warning
2878 
2879 		static_cast<T*>(this)->OnRibbonCommandExecute(nCmdID);
2880 
2881 		return S_OK;
2882 	}
2883 
DoUpdateProperty(UINT nCmdID,REFPROPERTYKEY key,const PROPVARIANT *,PROPVARIANT * ppropvarNewValue)2884 	virtual HRESULT DoUpdateProperty(UINT nCmdID, REFPROPERTYKEY key,
2885 		const PROPVARIANT* /*ppropvarCurrentValue*/, PROPVARIANT* ppropvarNewValue)
2886 	{
2887 		T* pT = static_cast<T*>(this);
2888 		HRESULT hr = E_NOTIMPL;
2889 		switch (k_(key))
2890 		{
2891 		case k_LargeImage:
2892 		case k_LargeHighContrastImage:
2893 		case k_SmallImage:
2894 		case k_SmallHighContrastImage:
2895 			if (HBITMAP hbm = pT->OnRibbonQueryImage(nCmdID, key))
2896 				hr = SetPropertyVal(key, GetImage(hbm, UI_OWNERSHIP_TRANSFER), ppropvarNewValue);
2897 			break;
2898 		case k_Label:
2899 		case k_Keytip:
2900 		case k_TooltipTitle:
2901 		case k_TooltipDescription:
2902 		case k_LabelDescription:
2903 			if (LPCWSTR sText = pT->OnRibbonQueryText(nCmdID, key))
2904 				hr = SetPropertyVal(key, sText, ppropvarNewValue);
2905 			break;
2906 		case k_BooleanValue:
2907 		case k_Enabled:
2908 			hr = SetPropertyVal(key, pT->OnRibbonQueryState(nCmdID, key), ppropvarNewValue);
2909 			break;
2910 		case k_ContextAvailable:
2911 			hr = SetPropertyVal(key, pT->OnRibbonQueryTabAvail(nCmdID), ppropvarNewValue);
2912 			break;
2913 		}
2914 
2915 		return hr;
2916 	}
2917 
2918 // CRibbonImpl::CRibbonXXXCtrl specialized classes
2919 	 //CRibbonComboCtrl
2920 	template <UINT t_ID, size_t t_items, size_t t_categories = 0>
2921 	class CRibbonComboCtrl : public CollectionCtrlImpl<T, t_ID, ComboCollectionImpl<CRibbonComboCtrl<t_ID, t_items, t_categories>, t_items, t_categories>>
2922 	{
2923 	public:
CRibbonComboCtrl()2924 		CRibbonComboCtrl()
2925 		{ }
2926 	};
2927 
2928 	// CRibbonItemGalleryCtrl
2929 	template <UINT t_ID, size_t t_items, size_t t_categories = 0>
2930 	class CRibbonItemGalleryCtrl : public CollectionCtrlImpl<T, t_ID, ItemCollectionImpl<CRibbonItemGalleryCtrl<t_ID, t_items, t_categories>, t_items, t_categories>>
2931 	{
2932 	public:
CRibbonItemGalleryCtrl()2933 		CRibbonItemGalleryCtrl()
2934 		{ }
2935 	};
2936 
2937 	// CRibbonCommandGalleryCtrl
2938 	template <UINT t_ID, size_t t_items, size_t t_categories = 0>
2939 	class CRibbonCommandGalleryCtrl : public CollectionCtrlImpl<T, t_ID, CommandCollectionImpl<CRibbonCommandGalleryCtrl<t_ID, t_items, t_categories>, t_items, t_categories>>
2940 	{
2941 	public:
CRibbonCommandGalleryCtrl()2942 		CRibbonCommandGalleryCtrl()
2943 		{ }
2944 	};
2945 
2946 	// CRibbonToolbarGalleryCtrl
2947 	template <UINT t_ID, UINT t_idTB, size_t t_size>
2948 	class CRibbonToolbarGalleryCtrl : public ToolbarGalleryCtrlImpl<T, t_ID, t_idTB, t_size>
2949 	{ };
2950 
2951 	// CRibbonSimpleComboCtrl
2952 	template <UINT t_ID, size_t t_size>
2953 	class CRibbonSimpleComboCtrl : public SimpleCollectionCtrlImpl<T, t_ID, t_size>
2954 	{ };
2955 
2956 	// CRibbonSimpleGalleryCtrl
2957 	template <UINT t_ID, size_t t_size, UI_COMMANDTYPE t_CommandType = UI_COMMANDTYPE_ACTION>
2958 	class CRibbonSimpleGalleryCtrl : public SimpleCollectionCtrlImpl<T, t_ID, t_size, t_CommandType>
2959 	{ };
2960 
2961 	//CRibbonRecentItemsCtrl
2962 	template <UINT t_ID, class TDocList = CRecentDocumentList>
2963 	class CRibbonRecentItemsCtrl : public RecentItemsCtrlImpl<T, t_ID, TDocList>
2964 	{
2965 	public:
CRibbonRecentItemsCtrl()2966 		CRibbonRecentItemsCtrl()
2967 		{ }
2968 	};
2969 
2970 	// CRibbonColorCtrl
2971 	template <UINT t_ID>
2972 	class CRibbonColorCtrl : public ColorCtrlImpl<T, t_ID>
2973 	{
2974 	public:
CRibbonColorCtrl()2975 		CRibbonColorCtrl()
2976 		{ }
2977 	};
2978 
2979 	 //CRibbonFontCtrl
2980 	template <UINT t_ID>
2981 	class CRibbonFontCtrl : public FontCtrlImpl<T, t_ID>
2982 	{
2983 	public:
CRibbonFontCtrl()2984 		CRibbonFontCtrl()
2985 		{ }
2986 	};
2987 
2988 	// CRibbonSpinnerCtrl
2989 	template <UINT t_ID>
2990 	class CRibbonSpinnerCtrl : public SpinnerCtrlImpl<T, t_ID, LONG>
2991 	{
2992 	public:
CRibbonSpinnerCtrl()2993 		CRibbonSpinnerCtrl()
2994 		{ }
2995 	};
2996 
2997 	// CRibbonFloatSpinnerCtrl
2998 	template <UINT t_ID>
2999 	class CRibbonFloatSpinnerCtrl : public SpinnerCtrlImpl<T, t_ID, DOUBLE>
3000 	{
3001 	public:
CRibbonFloatSpinnerCtrl()3002 		CRibbonFloatSpinnerCtrl()
3003 		{
3004 			m_Values[4] = 1; // 1 decimal
3005 		}
3006 	};
3007 
3008 	// CRibbonCommandCtrl
3009 	template <UINT t_ID>
3010 	class CRibbonCommandCtrl : public CommandCtrlImpl<T, t_ID>
3011 	{
3012 	public:
CRibbonCommandCtrl()3013 		CRibbonCommandCtrl()
3014 		{ }
3015 	};
3016 
3017 // Control classes access to T instance (re-initialized in constructor)
3018 	static T* pWndRibbon;
3019 };
3020 
3021 template <class T>
3022 __declspec(selectany) T* CRibbonImpl<T>::pWndRibbon;
3023 
3024 // Control map element
3025 #pragma warning(push)
3026 #pragma warning(disable: 4510 610 4512)   // missing default constructor, can't be instatiated, assignment operator could not be generated
3027 typedef struct
3028 {
3029 	UINT uID;
3030 	ICtrl& ctrl;
3031 } _ribbonCtrl;
3032 #pragma warning(pop)
3033 
3034 }; // namespace RibbonUI
3035 
3036 
3037 ///////////////////////////////////////////////////////////////////////////////
3038 // RibbonUI Control map
3039 
3040 // Control map macros
3041 #define BEGIN_RIBBON_CONTROL_MAP(theClass) \
3042 	WTL::RibbonUI::ICtrl& GetRibbonCtrl(UINT id) \
3043 	{ \
3044 		WTL::RibbonUI::_ribbonCtrl _ctrls[] = \
3045 		{
3046 
3047 #define RIBBON_CONTROL(member) {member.GetID(), static_cast<WTL::RibbonUI::ICtrl&>(member)},
3048 
3049 #define END_RIBBON_CONTROL_MAP() \
3050 		{0, *this} \
3051 	}; \
3052 	int i = 0; \
3053 	for(; i < _countof(_ctrls) - 1; i++) \
3054 		if (_ctrls[i].uID == id) \
3055 			break; \
3056 	return _ctrls[i].ctrl; \
3057 }
3058 
3059 // Control message map macros
3060 #define RIBBON_GALLERY_CONTROL_HANDLER(id, func) \
3061 	if(uMsg == WM_COMMAND && id == LOWORD(wParam)) \
3062 	{ \
3063 		bHandled = TRUE; \
3064 		lResult = func((UI_EXECUTIONVERB)HIWORD(wParam), LOWORD(wParam), (UINT)lParam, bHandled); \
3065 		if(bHandled) \
3066 			return TRUE; \
3067 	}
3068 
3069 #define RIBBON_COMBO_CONTROL_HANDLER(id, func) \
3070 	RIBBON_GALLERY_CONTROL_HANDLER(id, func)
3071 
3072 #define RIBBON_FONT_CONTROL_HANDLER(id, func) \
3073 	if(uMsg == WM_COMMAND && id == LOWORD(wParam)) \
3074 	{ \
3075 		bHandled = TRUE; \
3076 		lResult = func((UI_EXECUTIONVERB)HIWORD(wParam), LOWORD(wParam), (CHARFORMAT2*)lParam, bHandled); \
3077 		if(bHandled) \
3078 			return TRUE; \
3079 	}
3080 
3081 #define RIBBON_COLOR_CONTROL_HANDLER(id, func) \
3082 	if(uMsg == WM_COMMAND && id == LOWORD(wParam)) \
3083 	{ \
3084 		bHandled = TRUE; \
3085 		lResult = func((UI_EXECUTIONVERB)HIWORD(wParam), LOWORD(wParam), (COLORREF)lParam, bHandled); \
3086 		if(bHandled) \
3087 			return TRUE; \
3088 	}
3089 
3090 #define RIBBON_SPINNER_CONTROL_HANDLER(id, func) \
3091 	if(uMsg == WM_COMMAND && id == wParam) \
3092 	{ \
3093 		bHandled = TRUE; \
3094 		lResult = func((WORD)wParam, (LONG)lParam, bHandled); \
3095 		if(bHandled) \
3096 			return TRUE; \
3097 	}
3098 
3099 #define RIBBON_FLOATSPINNER_CONTROL_HANDLER(id, func) \
3100 	if(uMsg == WM_COMMAND && id == wParam) \
3101 	{ \
3102 		bHandled = TRUE; \
3103 		lResult = func((WORD)wParam, (DOUBLE*)lParam, bHandled); \
3104 		if(bHandled) \
3105 			return TRUE; \
3106 	}
3107 
3108 // Handler prototypes
3109 /*
3110 	LRESULT OnRibbonGalleryCtrl(UI_EXECUTIONVERB verb, WORD wID, UINT uSel, BOOL& bHandled);
3111 	LRESULT OnRibbonComboCtrl(UI_EXECUTIONVERB verb, WORD wID, UINT uSel, BOOL& bHandled);
3112 	LRESULT OnRibbonFontCtrl(UI_EXECUTIONVERB verb, WORD wID, CHARFORMAT2* pcf, BOOL& bHandled);
3113 	LRESULT OnRibbonColorCtrl(UI_EXECUTIONVERB verb, WORD wID, COLORREF color, BOOL& bHandled);
3114 	LRESULT OnRibbonSpinnerCtrl(WORD wID, LONG lVal, BOOL& bHandled);
3115 	LRESULT OnRibbonFloatSpinnerCtrl(WORD wID, DOUBLE* pdVal, BOOL& bHandled);
3116 */
3117 
3118 
3119 ///////////////////////////////////////////////////////////////////////////////
3120 // Ribbon frame classes
3121 
3122 // CRibbonFrameWindowImplBase
3123 //
3124 template <class T, class TFrameImpl>
3125 class ATL_NO_VTABLE CRibbonFrameWindowImplBase : public TFrameImpl, public RibbonUI::CRibbonImpl<T>
3126 {
3127 	typedef TFrameImpl baseFrame;
3128 	bool m_bUseCommandBarBitmaps;
3129 	bool m_bWin7Fix;
3130 
3131 public:
3132 // Construction
3133 	CRibbonFrameWindowImplBase(bool bUseCommandBarBitmaps = true) :
m_bUseCommandBarBitmaps(bUseCommandBarBitmaps)3134 			m_bUseCommandBarBitmaps(bUseCommandBarBitmaps), m_bWin7Fix(false)
3135 	{
3136 		__if_not_exists(T::m_CmdBar)
3137 		{
3138 			m_bUseCommandBarBitmaps = false;
3139 		}
3140 	}
3141 
3142 // Win7 Aero fix helpers
ResetFrame()3143 	void ResetFrame()
3144 	{
3145 		const MARGINS margins = { 0 };
3146 		::DwmExtendFrameIntoClientArea(m_hWnd, &margins);
3147 	}
3148 
CalcWin7Fix()3149 	INT CalcWin7Fix()
3150 	{
3151 		ResetFrame();
3152 		RECT rc = { 0 };
3153 		::AdjustWindowRectEx(&rc, T::GetWndStyle(0), GetMenu() != NULL, T::GetWndExStyle(0));
3154 		return -rc.top;
3155 	}
3156 
NeedWin7Fix()3157 	bool NeedWin7Fix()
3158 	{
3159 		BOOL bComp = FALSE;
3160 		return m_bWin7Fix && RunTimeHelper::IsWin7() && SUCCEEDED(DwmIsCompositionEnabled(&bComp)) && bComp;
3161 	}
3162 
3163 // Operations
UseCommandBarBitmaps(bool bUse)3164 	bool UseCommandBarBitmaps(bool bUse)
3165 	{
3166 		__if_exists(T::m_CmdBar)
3167 		{
3168 			return m_bUseCommandBarBitmaps = bUse;
3169 		}
3170 		__if_not_exists(T::m_CmdBar)
3171 		{
3172 			bUse;   // avoid level 4 warning
3173 			return false;
3174 		}
3175 	}
3176 
3177 	bool ShowRibbonUI(bool bShow, INT32 imodes = UI_MAKEAPPMODE(0), LPCWSTR sResName = L"APPLICATION_RIBBON")
3178 	{
3179 		if (!RunTimeHelper::IsRibbonUIAvailable())
3180 			return false;
3181 
3182 		ATLASSERT(GetIUIFrameworkPtr());
3183 
3184 		if (IsRibbonUI() == bShow)
3185 			return bShow;
3186 
3187 		bool bVisible = (IsWindowVisible() != FALSE);
3188 		if(bVisible && !bShow)
3189 			SetRedraw(FALSE);
3190 
3191 		if (bShow && ::IsWindow(m_hWndToolBar))
3192 		{
3193 			::ShowWindow(m_hWndToolBar, SW_HIDE);
3194 			UpdateLayout();
3195 		}
3196 
3197 		m_bWin7Fix = !bShow;
3198 
3199 		HRESULT hr = bShow ? CreateRibbon(sResName) : DestroyRibbon();
3200 
3201 		m_bWin7Fix = SUCCEEDED(hr) && !bShow;
3202 
3203 		if (SUCCEEDED(hr))
3204 		{
3205 			if(::IsWindow(m_hWndToolBar) && !bShow)
3206 			{
3207 				::ShowWindow(m_hWndToolBar, SW_SHOWNA);
3208 				UpdateLayout();
3209 			}
3210 			else if (bShow)
3211 			{
3212 				PostMessage(WM_SIZE);
3213 				SetRibbonModes(imodes);
3214 			}
3215 		}
3216 
3217 		if(bVisible && !bShow)
3218 		{
3219 			SetRedraw(TRUE);
3220 			RedrawWindow(NULL, NULL, RDW_FRAME | RDW_ERASE | RDW_INVALIDATE | RDW_UPDATENOW | RDW_ALLCHILDREN);
3221 		}
3222 
3223 		return SUCCEEDED(hr) ? bShow : !bShow;
3224 	}
3225 
3226 // Overrideables
OnRibbonQueryImage(UINT nCmdID,REFPROPERTYKEY key)3227 	HBITMAP OnRibbonQueryImage(UINT nCmdID, REFPROPERTYKEY key)
3228 	{
3229 		if ((key == UI_PKEY_SmallImage) && m_bUseCommandBarBitmaps)
3230 		{
3231 			if (HBITMAP hbm = GetCommandBarBitmap(nCmdID))
3232 				return (HBITMAP)::CopyImage(hbm, IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION);
3233 		}
3234 
3235 		return DefRibbonQueryImage(nCmdID);
3236 	}
3237 
3238 	BEGIN_MSG_MAP(CRibbonFrameWindowImplBase)
3239 		if (!IsRibbonUI() && NeedWin7Fix())
3240 		{
3241 			MESSAGE_HANDLER(WM_SIZING, OnSizing)
3242 			MESSAGE_HANDLER(WM_SIZE, OnSize)
3243 			MESSAGE_HANDLER(WM_ACTIVATE, OnActivate)
3244 			MESSAGE_HANDLER(WM_NCCALCSIZE, OnNCCalcSize)
3245 		}
3246 		CHAIN_MSG_MAP(CRibbonUpdateUI<T>)
CHAIN_MSG_MAP(baseFrame)3247 		CHAIN_MSG_MAP(baseFrame)
3248 	END_MSG_MAP()
3249 
3250 // Message handlers for Win7 Aero
3251 	LRESULT OnSizing(UINT /*uMsg*/, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/)
3252 	{
3253 		switch (wParam)
3254 		{
3255 		case WMSZ_TOP:
3256 		case WMSZ_TOPLEFT:
3257 		case WMSZ_TOPRIGHT:
3258 			SetWindowPos(NULL, (LPRECT)lParam, SWP_NOMOVE | SWP_NOZORDER | SWP_FRAMECHANGED);
3259 			break;
3260 		default:
3261 			DefWindowProc();
3262 			break;
3263 		}
3264 
3265 		return 1; // handled
3266 	}
3267 
OnSize(UINT,WPARAM wParam,LPARAM,BOOL & bHandled)3268 	LRESULT OnSize(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled)
3269 	{
3270 		if (wParam != SIZE_MINIMIZED)
3271 			SetWindowPos(NULL, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED);
3272 
3273 		bHandled = FALSE;
3274 		return 1;
3275 	}
3276 
OnActivate(UINT,WPARAM wParam,LPARAM,BOOL & bHandled)3277 	LRESULT OnActivate(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled)
3278 	{
3279 		if(wParam != WA_INACTIVE)
3280 			SetWindowPos(NULL, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED);
3281 
3282 		bHandled = FALSE;
3283 		return 1;
3284 	}
3285 
OnNCCalcSize(UINT,WPARAM wParam,LPARAM lParam,BOOL &)3286 	LRESULT OnNCCalcSize(UINT /*uMsg*/, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/)
3287 	{
3288 		ATLASSERT(!IsRibbonUI() && NeedWin7Fix());
3289 
3290 		LRESULT lRet = DefWindowProc();
3291 
3292 		if(wParam)
3293 		{
3294 			LPNCCALCSIZE_PARAMS pParams = (LPNCCALCSIZE_PARAMS)lParam;
3295 			pParams->rgrc[0].top = pParams->rgrc[1].top + CalcWin7Fix();
3296 		}
3297 
3298 		return lRet;
3299 	}
3300 
3301 // Overrides
3302 	void UpdateLayout(BOOL bResizeBars = TRUE)
3303 	{
3304 		RECT rect = { 0 };
3305 		GetClientRect(&rect);
3306 
3307 		if (IsRibbonUI() && !IsRibbonHidden())
3308 		{
3309 			rect.top += GetRibbonHeight();
3310 		}
3311 		else if (!IsRibbonUI() && NeedWin7Fix())
3312 		{
3313 			ResetFrame();
3314 		}
3315 
3316 		// position bars and offset their dimensions
3317 		UpdateBarsPosition(rect, bResizeBars);
3318 
3319 		// resize client window
3320 		if(m_hWndClient != NULL)
3321 			::SetWindowPos(m_hWndClient, NULL, rect.left, rect.top,
3322 				rect.right - rect.left, rect.bottom - rect.top,
3323 				SWP_NOZORDER | SWP_NOACTIVATE);
3324 	}
3325 
3326 	// Implementation
GetCommandBarBitmap(UINT nCmdID)3327 	HBITMAP GetCommandBarBitmap(UINT nCmdID)
3328 	{
3329 		__if_exists (T::m_CmdBar)
3330 		{
3331 			ATLASSERT(RunTimeHelper::IsVista());
3332 			T* pT =static_cast<T*>(this);
3333 			int nIndex = pT->m_CmdBar.m_arrCommand.Find((WORD&)nCmdID);
3334 			return (nIndex == -1) ? NULL : pT->m_CmdBar.m_arrVistaBitmap[nIndex];
3335 		}
3336 		__if_not_exists (T::m_CmdBar)
3337 		{
3338 			nCmdID;   // avoid level 4 warning
3339 			return NULL;
3340 		}
3341 	}
3342 };
3343 
3344 // CRibbonFrameWindowImpl
3345 //
3346 template <class T, class TBase = ATL::CWindow, class TWinTraits = ATL::CFrameWinTraits>
3347 class ATL_NO_VTABLE CRibbonFrameWindowImpl : public CRibbonFrameWindowImplBase<T, CFrameWindowImpl<T, TBase, TWinTraits>>
3348 { };
3349 
3350 // CRibbonMDIFrameWindowImpl
3351 //
3352 template <class T, class TBase = CMDIWindow, class TWinTraits = ATL::CFrameWinTraits>
3353 class ATL_NO_VTABLE CRibbonMDIFrameWindowImpl : public CRibbonFrameWindowImplBase<T, CMDIFrameWindowImpl<T, TBase, TWinTraits>>
3354 { };
3355 
3356 
3357 ///////////////////////////////////////////////////////////////////////////////
3358 // CRibbonPersist helper for RibbonUI persistency
3359 
3360 class CRibbonPersist
3361 {
3362 public:
CRibbonPersist(LPCWSTR sAppKey)3363 	CRibbonPersist(LPCWSTR sAppKey)
3364 	{
3365 		ATLASSERT(sAppKey && *sAppKey);
3366 		m_Key.Create(HKEY_CURRENT_USER, sAppKey);
3367 		ATLASSERT(m_Key.m_hKey);
3368 	}
3369 
3370 	CRegKeyEx m_Key;
3371 
3372 	LONG Save(bool bRibbonUI, HGLOBAL hgSettings = NULL)
3373 	{
3374 		CRegKeyEx key;
3375 		const DWORD dwUI = bRibbonUI;
3376 
3377 		LONG lRet = key.Create(m_Key, L"Ribbon");
3378 		if(lRet != ERROR_SUCCESS)
3379 			return lRet;
3380 
3381 		lRet = key.SetDWORDValue(L"UI", dwUI);
3382 		if(lRet != ERROR_SUCCESS)
3383 			return lRet;
3384 
3385 		if (hgSettings != NULL)
3386 		{
3387 			LPBYTE pVal = (LPBYTE)::GlobalLock(hgSettings);
3388 			if (pVal != NULL)
3389 			{
3390 				lRet = key.SetBinaryValue(L"Settings", pVal, (ULONG)::GlobalSize(hgSettings));
3391 				::GlobalUnlock(hgSettings);
3392 			}
3393 			else
3394 			{
3395 				lRet = GetLastError();
3396 			}
3397 		}
3398 
3399 		return lRet;
3400 	}
3401 
Restore(bool & bRibbonUI,HGLOBAL & hgSettings)3402 	LONG Restore(bool& bRibbonUI, HGLOBAL& hgSettings)
3403 	{
3404 		ATLASSERT(hgSettings == NULL);
3405 
3406 		CRegKeyEx key;
3407 
3408 		LONG lRet = key.Open(m_Key, L"Ribbon");
3409 		if(lRet != ERROR_SUCCESS)
3410 			return lRet;
3411 
3412 		DWORD dwUI = 0xffff;
3413 		lRet = key.QueryDWORDValue(L"UI", dwUI);
3414 		if(lRet == ERROR_SUCCESS)
3415 			bRibbonUI = dwUI == 1;
3416 		else
3417 			return lRet;
3418 
3419 		ULONG ulSize = 0;
3420 		lRet = key.QueryBinaryValue(L"Settings", NULL, &ulSize);
3421 		if (lRet == ERROR_SUCCESS)
3422 		{
3423 			ATLASSERT(ulSize != 0);
3424 
3425 			hgSettings = ::GlobalAlloc(GHND, ulSize);
3426 			if (hgSettings != NULL)
3427 			{
3428 				LPBYTE pData = (LPBYTE)::GlobalLock(hgSettings);
3429 				if (pData != NULL)
3430 				{
3431 					lRet = key.QueryBinaryValue(L"Settings", pData, &ulSize);
3432 				}
3433 				else
3434 				{
3435 					lRet = GetLastError();
3436 					::GlobalFree(hgSettings);
3437 					hgSettings = NULL;
3438 				}
3439 			}
3440 			else
3441 			{
3442 				lRet = GetLastError();
3443 			}
3444 		}
3445 		return lRet;
3446 	}
3447 
Delete()3448 	LONG Delete()
3449 	{
3450 		return m_Key.DeleteSubKey(L"Ribbon");
3451 	}
3452 };
3453 
3454 } // namespace WTL
3455 
3456 #endif // __ATLRIBBON_H__
3457