// Windows Template Library - WTL version 8.1 // Copyright (C) Microsoft Corporation. All rights reserved. // // This file is a part of the Windows Template Library. // The use and distribution terms for this software are covered by the // Common Public License 1.0 (http://opensource.org/licenses/cpl1.0.php) // which can be found in the file CPL.TXT at the root of this distribution. // By using this software in any fashion, you are agreeing to be bound by // the terms of this license. You must not remove this notice, or // any other, from this software. #ifndef __ATLRIBBON_H__ #define __ATLRIBBON_H__ #pragma once #if (_MSC_VER < 1500) #error atlribbon.h requires Visual C++ 2008 compiler or higher #endif #ifndef _UNICODE #error atlribbon.h requires the Unicode character set #endif #if !defined(NTDDI_WIN7) || (NTDDI_VERSION < NTDDI_WIN7) #error atlribbon.h requires the Windows 7 SDK or higher #endif #ifdef _WIN32_WCE #error atlribbon.h is not supported on Windows CE #endif #ifndef __ATLAPP_H__ #error atlribbon.h requires atlapp.h to be included first #endif #if (_ATL_VER < 0x0700) #include #pragma comment(lib, "shlwapi.lib") #endif #include // for RecentDocumentList classes #include // for Frame and UpdateUI classes #include // required for atlctrlw.h #include // for CCommandBarCtrl #if !defined(_WTL_USE_CSTRING) && !defined(__ATLSTR_H__) #pragma warning(disable : 4530) // unwind semantics not enabled #include #pragma warning(default : 4530) #endif #include #pragma comment(lib, "dwmapi.lib") #include #include #pragma comment(lib, "propsys.lib") #include // for CHARFORMAT2 /////////////////////////////////////////////////////////////////////////////// // Classes in this file: // // CRibbonUpdateUI : Automatic mapping of ribbon UI elements // // RibbonUI::Text // RibbonUI::CharFormat // RibbonUI::ICtrl // RibbonUI::CtrlImpl // RibbonUI::CommandCtrlImpl // RibbonUI::ItemProperty // RibbonUI::CollectionImplBase // RibbonUI::CollectionImpl // RibbonUI::TextCollectionImpl // RibbonUI::ItemCollectionImpl // RibbonUI::ComboCollectionImpl // RibbonUI::CommandCollectionImpl // RibbonUI::ToolbarCollectionImpl // RibbonUI::SimpleCollectionImpl // RibbonUI::CollectionCtrlImpl // RibbonUI::ToolbarGalleryCtrlImpl // RibbonUI::SimpleCollectionCtrlImpl // RibbonUI::RecentItemsCtrlImpl // RibbonUI::FontCtrlImpl // RibbonUI::ColorCtrlImpl // RibbonUI::SpinnerCtrlImpl // // RibbonUI::CRibbonImpl // CRibbonImpl::CRibbonComboCtrl // CRibbonImpl::CRibbonItemGalleryCtrl // CRibbonImpl::CRibbonCommandGalleryCtrl // CRibbonImpl::CRibbonToolbarGalleryCtrl // CRibbonImpl::CRibbonSimpleComboCtrl // CRibbonImpl::CRibbonSimpleGalleryCtrl // CRibbonImpl::CRibbonRecentItemsCtrl // CRibbonImpl::CRibbonColorCtrl // CRibbonImpl::CRibbonFontCtrl // CRibbonImpl::CRibbonSpinnerCtrl // CRibbonImpl::CRibbonFloatSpinnerCtrl // CRibbonImpl::CRibbonCommandCtrl // // CRibbonFrameWindowImplBase // CRibbonFrameWindowImpl // CRibbonMDIFrameWindowImpl // CRibbonPersist // // Global functions: // RibbonUI::SetPropertyVal() // RibbonUI::GetImage() // Constants #ifndef RIBBONUI_MAX_TEXT #define RIBBONUI_MAX_TEXT 128 #endif #define TWIPS_PER_POINT 20 // For font size namespace WTL { /////////////////////////////////////////////////////////////////////////////// // CRibbonUpdateUI : Automatic mapping of ribbon UI elements template class CRibbonUpdateUI : public CAutoUpdateUI { public: enum { UPDUI_RIBBON = 0x0080, UPDUI_PERSIST = 0x0020 }; bool IsRibbonElement(const _AtlUpdateUIMap& UIMap) { return (UIMap.m_wType & UPDUI_RIBBON) != 0; } bool IsRibbonID(UINT nID) { for(int i = 0; i < m_arrUIMap.GetSize(); i++) { if(m_arrUIMap[i].m_nID == nID) return IsRibbonElement(m_arrUIMap[i]); } return false; } // Element bool UIAddRibbonElement(UINT nID) { return UIAddElement(nID); } bool UIRemoveRibbonElement(UINT nID) { return UIRemoveElement(nID); } bool UIPersistElement(UINT nID, bool bPersist = true) { return bPersist ? UIAddElement(nID) : UIRemoveElement(nID); } // methods for Ribbon elements BOOL UISetText(int nID, LPCWSTR sText, BOOL bForceUpdate = FALSE) { T* pT = static_cast(this); BOOL bRes = CUpdateUIBase::UISetText(nID, sText, bForceUpdate); if (pT->IsRibbonUI() && IsRibbonID(nID)) bRes = SUCCEEDED(pT->InvalidateProperty(nID, UI_PKEY_Label)); return bRes; } BOOL UISetText(int nID, UINT uIdResource, BOOL bForceUpdate = FALSE) { CTempBuffer sText(RIBBONUI_MAX_TEXT); return AtlLoadString(uIdResource, sText, RIBBONUI_MAX_TEXT) ? UISetText(nID, sText, bForceUpdate) : E_FAIL; } LPCTSTR UIGetText(int nID) { T* pT = static_cast(this); LPCTSTR sUI = CAutoUpdateUI::UIGetText(nID); // replace 'tab' by 'space' for RibbonUI elements if (sUI && pT->IsRibbonUI() && IsRibbonID(nID) && wcschr(sUI, L'\t')) { static WCHAR sText[RIBBONUI_MAX_TEXT] = { 0 }; wcscpy_s(sText, sUI); *wcschr(sText, L'\t') = L' '; return sText; } else { return sUI; } } BOOL UIEnable(int nID, BOOL bEnable, BOOL bForceUpdate = FALSE) { T* pT = static_cast(this); BOOL bRes = CUpdateUIBase::UIEnable(nID, bEnable, bForceUpdate); if (pT->IsRibbonUI() && IsRibbonID(nID)) bRes = SUCCEEDED(pT->SetProperty((WORD)nID, UI_PKEY_Enabled, bEnable)); return bRes; } BOOL UISetCheck(int nID, INT nCheck, BOOL bForceUpdate = FALSE) { if ((nCheck == 0) || (nCheck == 1)) return UISetCheck(nID, nCheck != 0, bForceUpdate); else return CUpdateUIBase::UISetCheck(nID, nCheck, bForceUpdate); } BOOL UISetCheck(int nID, bool bCheck, BOOL bForceUpdate = FALSE) { T* pT = static_cast(this); BOOL bRes = CUpdateUIBase::UISetCheck(nID, bCheck, bForceUpdate); if (bRes && pT->IsRibbonUI() && IsRibbonID(nID)) bRes = SUCCEEDED(pT->SetProperty((WORD)nID, UI_PKEY_BooleanValue, bCheck)); return bRes; } }; /////////////////////////////////////////////////////////////////////////////// // RibbonUI namespace // namespace RibbonUI { // Minimal string allocation support for various PROPERTYKEY values #if defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__) typedef _CSTRING_NS::CString Text; #else class Text : public std::wstring { public: Text(std::wstring& s) : std::wstring(s) { } Text(LPCWSTR s) : std::wstring(s) { } Text() { } bool IsEmpty() { return empty(); } operator LPCWSTR() { return c_str(); } Text& operator =(LPCWSTR s) { return static_cast(std::wstring::operator =(s)); } }; #endif // PROPERTYKEY enum and helpers enum k_KEY { // state k_Enabled = 1, k_BooleanValue = 200, // text properties k_LabelDescription = 2, k_Keytip = 3, k_Label = 4, k_TooltipDescription = 5, k_TooltipTitle = 6, // image properties k_LargeImage = 7, k_LargeHighContrastImage = 8, k_SmallImage = 9, k_SmallHighContrastImage = 10, // collection properties k_ItemsSource = 101, k_Categories = 102, k_SelectedItem = 104, // collection item properties k_CommandId = 100, k_CategoryId = 103, k_CommandType = 105, k_ItemImage = 106, // combo control property k_StringValue = 202, // spinner control properties k_DecimalValue = 201, k_MaxValue = 203, k_MinValue, k_Increment, k_DecimalPlaces, k_FormatString, k_RepresentativeString = 208, // font control properties k_FontProperties = 300, k_FontProperties_Family, k_FontProperties_Size, k_FontProperties_Bold, k_FontProperties_Italic = 304, k_FontProperties_Underline = 305, k_FontProperties_Strikethrough, k_FontProperties_VerticalPositioning, k_FontProperties_ForegroundColor = 308, k_FontProperties_BackgroundColor = 309, k_FontProperties_ForegroundColorType, k_FontProperties_BackgroundColorType, k_FontProperties_ChangedProperties = 312, k_FontProperties_DeltaSize = 313, // recent items properties k_RecentItems = 350, k_Pinned = 351, // color control properties k_Color = 400, k_ColorType = 401, k_ColorMode, k_ThemeColorsCategoryLabel = 403, k_StandardColorsCategoryLabel, k_RecentColorsCategoryLabel = 405, k_AutomaticColorLabel = 406, k_NoColorLabel = 407, k_MoreColorsLabel = 408, k_ThemeColors = 409, k_StandardColors = 410, k_ThemeColorsTooltips = 411, k_StandardColorsTooltips = 412, // Ribbon state k_Viewable = 1000, k_Minimized = 1001, k_QuickAccessToolbarDock = 1002, k_ContextAvailable = 1100, // Ribbon UI colors k_GlobalBackgroundColor = 2000, k_GlobalHighlightColor, k_GlobalTextColor = 2002 }; inline k_KEY k_(REFPROPERTYKEY key) { return (k_KEY)key.fmtid.Data1; } // PROPERTYKEY value assignment and specializations // template HRESULT SetPropertyVal(REFPROPERTYKEY key, V val, PROPVARIANT* ppv) { switch (k_(key)) { case k_Enabled: case k_BooleanValue: return InitPropVariantFromBoolean(val, ppv); default: return UIInitPropertyFromUInt32(key, val, ppv); } } inline HRESULT SetPropertyVal(REFPROPERTYKEY key, DOUBLE val, PROPVARIANT* ppv) { return SetPropertyVal(key, (LONG)val, ppv); } inline HRESULT SetPropertyVal(REFPROPERTYKEY key, IUIImage* val, PROPVARIANT* ppv) { HRESULT hr = UIInitPropertyFromImage(key, val, ppv); ATLVERIFY(val->Release() == 1); return hr; } inline HRESULT SetPropertyVal(REFPROPERTYKEY key, IUnknown* val, PROPVARIANT* ppv) { return UIInitPropertyFromInterface(key, val, ppv); } inline HRESULT SetPropertyVal(REFPROPERTYKEY key, IPropertyStore* val, PROPVARIANT* ppv) { return UIInitPropertyFromInterface(key, val, ppv); } inline HRESULT SetPropertyVal(REFPROPERTYKEY key, SAFEARRAY* val, PROPVARIANT* ppv) { return UIInitPropertyFromIUnknownArray(key, val, ppv); } inline HRESULT SetPropertyVal(REFPROPERTYKEY key, DECIMAL* val, PROPVARIANT* ppv) { return UIInitPropertyFromDecimal(key, *val, ppv); } inline HRESULT SetPropertyVal(REFPROPERTYKEY key, bool val, PROPVARIANT* ppv) { return UIInitPropertyFromBoolean(key, val, ppv); } inline HRESULT SetPropertyVal(REFPROPERTYKEY key, LPCWSTR val, PROPVARIANT* ppv) { return UIInitPropertyFromString(key, val, ppv); } // CharFormat helper struct for RibbonUI font control // struct CharFormat : CHARFORMAT2 { // Default constructor CharFormat() { cbSize = sizeof CHARFORMAT2; Reset(); } // Copy constructor CharFormat(const CharFormat& cf) { CopyMemory(this, &cf, sizeof CHARFORMAT2); } // Assign operator CharFormat& operator =(const CharFormat& cf) { CopyMemory(this, &cf, sizeof CHARFORMAT2); return (*this); } void Reset() { uValue = dwMask = dwEffects = 0; PropVariantInit(&propvar); } void operator <<(IPropertyStore* pStore) { if (pStore == NULL) { ATLASSERT(FALSE); return; } static void (CharFormat::*Getk_[])(IPropertyStore*) = { &CharFormat::Getk_Family, &CharFormat::Getk_FontProperties_Size, &CharFormat::Getk_MaskEffect, &CharFormat::Getk_MaskEffect, &CharFormat::Getk_MaskEffect, &CharFormat::Getk_MaskEffect, &CharFormat::Getk_VerticalPositioning, &CharFormat::Getk_Color, &CharFormat::Getk_Color, &CharFormat::Getk_ColorType, &CharFormat::Getk_ColorType, }; DWORD nProps = 0; Reset(); ATLVERIFY(SUCCEEDED(pStore->GetCount(&nProps))); for (DWORD iProp = 0; iProp < nProps; iProp++) { PROPERTYKEY key; ATLVERIFY(SUCCEEDED(pStore->GetAt(iProp, &key))); ATLASSERT(k_(key) >= k_FontProperties_Family); if (k_(key) <= k_FontProperties_BackgroundColorType) (this->*Getk_[k_(key) - k_FontProperties_Family])(pStore); } } void operator >>(IPropertyStore* pStore) { if (pStore == NULL) { ATLASSERT(FALSE); return; } PutFace(pStore); PutSize(pStore); PutMaskEffect(CFM_BOLD, CFE_BOLD, UI_PKEY_FontProperties_Bold, pStore); PutMaskEffect(CFM_ITALIC, CFE_ITALIC, UI_PKEY_FontProperties_Italic, pStore); PutMaskEffect(CFM_UNDERLINE, CFE_UNDERLINE, UI_PKEY_FontProperties_Underline, pStore); PutMaskEffect(CFM_STRIKEOUT, CFE_STRIKEOUT, UI_PKEY_FontProperties_Strikethrough, pStore); PutVerticalPos(pStore); PutColor(pStore); PutBackColor(pStore); } private: PROPVARIANT propvar; UINT uValue; // Getk_ functions void Getk_Family(IPropertyStore* pStore) { if (SUCCEEDED(pStore->GetValue(UI_PKEY_FontProperties_Family, &propvar))) { PropVariantToString(propvar, szFaceName, LF_FACESIZE); if (*szFaceName) dwMask |= CFM_FACE; } } void Getk_FontProperties_Size(IPropertyStore* pStore) { if (SUCCEEDED(pStore->GetValue(UI_PKEY_FontProperties_Size, &propvar))) { DECIMAL decSize; UIPropertyToDecimal(UI_PKEY_FontProperties_Size, propvar, &decSize); DOUBLE dSize; VarR8FromDec(&decSize, &dSize); if (dSize > 0) { dwMask |= CFM_SIZE; yHeight = (LONG)(dSize * TWIPS_PER_POINT); } } } template void Getk_MaskEffect(IPropertyStore* pStore) { if (SUCCEEDED(pStore->GetValue(key, &propvar))) { UIPropertyToUInt32(key, propvar, &uValue); if ((UI_FONTPROPERTIES)uValue != UI_FONTPROPERTIES_NOTAVAILABLE) { dwMask |= t_dwMask; dwEffects |= ((UI_FONTPROPERTIES) uValue == UI_FONTPROPERTIES_SET) ? t_dwEffects : 0; } } } void Getk_VerticalPositioning(IPropertyStore* pStore) { if (SUCCEEDED(pStore->GetValue(UI_PKEY_FontProperties_VerticalPositioning, &propvar))) { UIPropertyToUInt32(UI_PKEY_FontProperties_VerticalPositioning, propvar, &uValue); UI_FONTVERTICALPOSITION uVerticalPosition = (UI_FONTVERTICALPOSITION) uValue; if ((uVerticalPosition != UI_FONTVERTICALPOSITION_NOTAVAILABLE)) { dwMask |= (CFM_SUPERSCRIPT | CFM_SUBSCRIPT); if (uVerticalPosition != UI_FONTVERTICALPOSITION_NOTSET) { dwEffects |= (uVerticalPosition == UI_FONTVERTICALPOSITION_SUPERSCRIPT) ? CFE_SUPERSCRIPT : CFE_SUBSCRIPT; } } } } template void Getk_Color(IPropertyStore* pStore) { UINT32 color; if (SUCCEEDED(pStore->GetValue(key, &propvar))) { UIPropertyToUInt32(key, propvar, &color); dwMask |= t_dwMask; if (t_dwMask == CFM_COLOR) crTextColor = color; else crBackColor = color; } } template void Getk_ColorType(IPropertyStore* pStore) { if (SUCCEEDED(pStore->GetValue(key, &propvar))) { UIPropertyToUInt32(key, propvar, &uValue); if (t_type == (UI_SWATCHCOLORTYPE)uValue) { dwMask |= t_dwMask; dwEffects |= t_dwEffects; } } } // Put functions void PutMaskEffect(WORD dwMaskVal, WORD dwEffectVal, REFPROPERTYKEY key, IPropertyStore* pStore) { PROPVARIANT propvar; UI_FONTPROPERTIES uProp = UI_FONTPROPERTIES_NOTAVAILABLE; if ((dwMask & dwMaskVal) != 0) uProp = dwEffects & dwEffectVal ? UI_FONTPROPERTIES_SET : UI_FONTPROPERTIES_NOTSET; SetPropertyVal(key, uProp, &propvar); pStore->SetValue(key, propvar); } void PutVerticalPos(IPropertyStore* pStore) { PROPVARIANT propvar; UI_FONTVERTICALPOSITION uProp = UI_FONTVERTICALPOSITION_NOTAVAILABLE; if ((dwMask & CFE_SUBSCRIPT) != 0) { if ((dwMask & CFM_SUBSCRIPT) && (dwEffects & CFE_SUBSCRIPT)) uProp = UI_FONTVERTICALPOSITION_SUBSCRIPT; else uProp = UI_FONTVERTICALPOSITION_SUPERSCRIPT; } else if ((dwMask & CFM_OFFSET) != 0) { if (yOffset > 0) uProp = UI_FONTVERTICALPOSITION_SUPERSCRIPT; else if (yOffset < 0) uProp = UI_FONTVERTICALPOSITION_SUBSCRIPT; } SetPropertyVal(UI_PKEY_FontProperties_VerticalPositioning, uProp, &propvar); pStore->SetValue(UI_PKEY_FontProperties_VerticalPositioning, propvar); } void PutFace(IPropertyStore* pStore) { PROPVARIANT propvar; SetPropertyVal(UI_PKEY_FontProperties_Family, dwMask & CFM_FACE ? szFaceName : L"", &propvar); pStore->SetValue(UI_PKEY_FontProperties_Family, propvar); } void PutSize(IPropertyStore* pStore) { PROPVARIANT propvar; DECIMAL decVal; if ((dwMask & CFM_SIZE) != 0) VarDecFromR8((DOUBLE)yHeight / TWIPS_PER_POINT, &decVal); else VarDecFromI4(0, &decVal); SetPropertyVal(UI_PKEY_FontProperties_Size, &decVal, &propvar); pStore->SetValue(UI_PKEY_FontProperties_Size, propvar); } void PutColor(IPropertyStore* pStore) { if ((dwMask & CFM_COLOR) != 0) if ((dwEffects & CFE_AUTOCOLOR) == 0) { SetPropertyVal(UI_PKEY_FontProperties_ForegroundColorType, UI_SWATCHCOLORTYPE_RGB, &propvar); pStore->SetValue(UI_PKEY_FontProperties_ForegroundColorType, propvar); SetPropertyVal(UI_PKEY_FontProperties_ForegroundColor, crTextColor, &propvar); pStore->SetValue(UI_PKEY_FontProperties_ForegroundColor, propvar); } else { SetPropertyVal(UI_PKEY_FontProperties_ForegroundColorType, UI_SWATCHCOLORTYPE_AUTOMATIC, &propvar); pStore->SetValue(UI_PKEY_FontProperties_ForegroundColorType, propvar); } } void PutBackColor(IPropertyStore* pStore) { if (((dwMask & CFM_BACKCOLOR) != 0) && ((dwEffects & CFE_AUTOBACKCOLOR) == 0)) { SetPropertyVal(UI_PKEY_FontProperties_BackgroundColorType, UI_SWATCHCOLORTYPE_RGB, &propvar); pStore->SetValue(UI_PKEY_FontProperties_BackgroundColorType, propvar); SetPropertyVal(UI_PKEY_FontProperties_BackgroundColor, crBackColor, &propvar); pStore->SetValue(UI_PKEY_FontProperties_BackgroundColor, propvar); } else { SetPropertyVal(UI_PKEY_FontProperties_BackgroundColorType, UI_SWATCHCOLORTYPE_NOCOLOR, &propvar); pStore->SetValue(UI_PKEY_FontProperties_BackgroundColorType, propvar); } } }; // IUIImage helper // inline IUIImage* GetImage(HBITMAP hbm, UI_OWNERSHIP owner) { ATLASSERT(hbm); IUIImage* pIUII = NULL; ATL::CComPtr pIFB; if SUCCEEDED(pIFB.CoCreateInstance(CLSID_UIRibbonImageFromBitmapFactory)) ATLVERIFY(SUCCEEDED(pIFB->CreateImage(hbm, owner, &pIUII))); return pIUII; } /////////////////////////////////////////////////////////////////////////////// // Ribbon control classes // RibbonUI::ICtrl abstract interface of RibbonUI::CRibbonImpl and all RibbonUI control classes // struct ICtrl { virtual HRESULT DoExecute(UINT nCmdID, UI_EXECUTIONVERB verb, const PROPERTYKEY* key, const PROPVARIANT* ppropvarValue, IUISimplePropertySet* pCommandExecutionProperties) = 0; virtual HRESULT DoUpdateProperty(UINT nCmdID, REFPROPERTYKEY key, const PROPVARIANT* ppropvarCurrentValue, PROPVARIANT* ppropvarNewValue) = 0; }; // RibbonUI::CtrlImpl base class for all ribbon controls // template class ATL_NO_VTABLE CtrlImpl : public ICtrl { protected: T* m_pWndRibbon; public: typedef T WndRibbon; CtrlImpl() : m_pWndRibbon(T::pWndRibbon) { } WndRibbon& GetWndRibbon() { return *m_pWndRibbon; } static WORD GetID() { return t_ID; } Text m_sTxt[5]; // Operations HRESULT Invalidate() { return GetWndRibbon().InvalidateCtrl(GetID()); } HRESULT Invalidate(REFPROPERTYKEY key, UI_INVALIDATIONS flags = UI_INVALIDATIONS_PROPERTY) { return GetWndRibbon().InvalidateProperty(GetID(), key, flags); } HRESULT SetText(REFPROPERTYKEY key, LPCWSTR sTxt, bool bUpdate = false) { ATLASSERT((k_(key) <= k_TooltipTitle) && (k_(key) >= k_LabelDescription)); m_sTxt[k_(key) - k_LabelDescription] = sTxt; return bUpdate ? GetWndRibbon().InvalidateProperty(GetID(), key) : S_OK; } // Implementation template HRESULT SetProperty(REFPROPERTYKEY key, V val) { return GetWndRibbon().SetProperty(GetID(), key, val); } HRESULT OnGetText(REFPROPERTYKEY key, PROPVARIANT* ppv) { ATLASSERT((k_(key) <= k_TooltipTitle) && (k_(key) >= k_LabelDescription)); const INT iText = k_(key) - k_LabelDescription; if (m_sTxt[iText].IsEmpty()) if (LPCWSTR sText = GetWndRibbon().OnRibbonQueryText(GetID(), key)) m_sTxt[iText] = sText; return !m_sTxt[iText].IsEmpty() ? SetPropertyVal(key, (LPCWSTR)m_sTxt[iText], ppv) : S_OK; } virtual HRESULT DoExecute(UINT nCmdID, UI_EXECUTIONVERB verb, const PROPERTYKEY* key, const PROPVARIANT* ppropvarValue, IUISimplePropertySet* pCommandExecutionProperties) { ATLASSERT(nCmdID == t_ID); return GetWndRibbon().DoExecute(nCmdID, verb, key, ppropvarValue, pCommandExecutionProperties); } virtual HRESULT DoUpdateProperty(UINT nCmdID, REFPROPERTYKEY key, const PROPVARIANT* ppropvarCurrentValue, PROPVARIANT* ppropvarNewValue) { ATLASSERT(nCmdID == t_ID); const INT iMax = k_TooltipTitle - k_LabelDescription; const INT iVal = k_(key) - k_LabelDescription; return (iVal <= iMax) && (iVal >= 0) ? OnGetText(key, ppropvarNewValue) : GetWndRibbon().DoUpdateProperty(nCmdID, key, ppropvarCurrentValue, ppropvarNewValue); } }; // CommandCtrlImpl base class for most ribbon controls // template class CommandCtrlImpl : public CtrlImpl { public: CBitmap m_hbm[4]; HRESULT SetImage(REFPROPERTYKEY key, HBITMAP hbm, bool bUpdate = false) { ATLASSERT((k_(key) <= k_SmallHighContrastImage) && (k_(key) >= k_LargeImage)); m_hbm[k_(key) - k_LargeImage].Attach(hbm); return bUpdate ? GetWndRibbon().InvalidateProperty(GetID(), key) : S_OK; } HRESULT OnGetImage(REFPROPERTYKEY key, PROPVARIANT* ppv) { ATLASSERT((k_(key) <= k_SmallHighContrastImage) && (k_(key) >= k_LargeImage)); const INT iImage = k_(key) - k_LargeImage; if (m_hbm[iImage].IsNull()) m_hbm[iImage] = GetWndRibbon().OnRibbonQueryImage(GetID(), key); return m_hbm[iImage].IsNull() ? E_NOTIMPL : SetPropertyVal(key, GetImage(m_hbm[iImage], UI_OWNERSHIP_COPY), ppv); } virtual HRESULT DoUpdateProperty(UINT nCmdID, REFPROPERTYKEY key, const PROPVARIANT* ppropvarCurrentValue, PROPVARIANT* ppropvarNewValue) { ATLASSERT (nCmdID == GetID()); return (k_(key) <= k_SmallHighContrastImage) && (k_(key) >= k_LargeImage) ? OnGetImage(key, ppropvarNewValue) : CtrlImpl::DoUpdateProperty(nCmdID, key, ppropvarCurrentValue, ppropvarNewValue); } }; /////////////////////////////////////////////////////////////////////////////// // Ribbon collection base classes // ItemProperty class: ribbon callback for each item in a collection // template class ItemProperty : public IUISimplePropertySet { public: ItemProperty(UINT i, TCollection* pCollection) : m_Index(i), m_pCollection(pCollection) { } const UINT m_Index; TCollection* m_pCollection; // IUISimplePropertySet method. STDMETHODIMP GetValue(REFPROPERTYKEY key, PROPVARIANT *value) { return m_pCollection->OnGetItem(m_Index, key, value); } // IUnknown methods. STDMETHODIMP_(ULONG) AddRef() { return 1; } STDMETHODIMP_(ULONG) Release() { return 1; } STDMETHODIMP QueryInterface(REFIID iid, void** ppv) { if ((iid == __uuidof(IUnknown)) || (iid == __uuidof(IUISimplePropertySet))) { *ppv = this; return S_OK; } else { return E_NOINTERFACE; } } }; // CollectionImplBase: base class for all RibbonUI collections // template class CollectionImplBase { typedef CollectionImplBase thisClass; public: CollectionImplBase() { for (int i = 0; i < t_size; i++) m_apItems[i] = new ItemProperty(i, static_cast(this)); } ~CollectionImplBase() { for (int i = 0; i < t_size; i++) delete m_apItems[i]; } // Data members ItemProperty* m_apItems[t_size]; }; // CollectionImpl: handles categories and collecton resizing // template class CollectionImpl : public CollectionImplBase, t_items + t_categories> { typedef CollectionImpl thisClass; public: typedef thisClass Collection; CollectionImpl() : m_size(t_items) { FillMemory(m_auItemCat, sizeof m_auItemCat, 0xff); // UI_COLLECTION_INVALIDINDEX } UINT32 m_auItemCat[t_items]; Text m_asCatName[max(t_categories, 1)]; size_t m_size; // Operations HRESULT SetItemCategory(UINT uItem, UINT uCat, bool bUpdate = false) { ATLASSERT((uItem < t_items) && (uCat < t_categories)); m_auItemCat[uItem] = uCat; return bUpdate ? InvalidateItems() : S_OK; } HRESULT SetCategoryText(UINT uCat, LPCWSTR sText, bool bUpdate = false) { ATLASSERT(uCat < t_categories); m_asCatName[uCat] = sText; return bUpdate ? InvalidateCategories() : S_OK; } HRESULT Resize(size_t size, bool bUpdate = false) { ATLASSERT(size <= t_items); m_size = size; return bUpdate ? InvalidateItems() : S_OK; } // Implementation HRESULT OnGetItem(UINT uIndex, REFPROPERTYKEY key, PROPVARIANT *value) { ATLASSERT(uIndex < t_items + t_categories); TCtrl* pCtrl = static_cast(this); return uIndex < t_items ? pCtrl->DoGetItem(uIndex, key, value) : pCtrl->DoGetCategory(uIndex - t_items, key, value); } HRESULT DoGetItem(UINT uItem, REFPROPERTYKEY key, PROPVARIANT *value) { ATLASSERT(k_(key) == k_CategoryId); UINT32 uCat = UI_COLLECTION_INVALIDINDEX; if (t_categories != 0) { if (m_auItemCat[uItem] == UI_COLLECTION_INVALIDINDEX) { TCtrl::WndRibbon& ribbon = static_cast(this)->GetWndRibbon(); m_auItemCat[uItem] = ribbon.OnRibbonQueryItemCategory(TCtrl::GetID(), uItem); } uCat = m_auItemCat[uItem]; } return SetPropertyVal(key, uCat, value); } HRESULT DoGetCategory(UINT uCat, REFPROPERTYKEY key, PROPVARIANT *value) { HRESULT hr = S_OK; switch (k_(key)) { case k_Label: if (m_asCatName[uCat].IsEmpty()) { TCtrl::WndRibbon& ribbon = static_cast(this)->GetWndRibbon(); m_asCatName[uCat] = ribbon.OnRibbonQueryCategoryText(TCtrl::GetID(), uCat); } hr = SetPropertyVal(key, (LPCWSTR)m_asCatName[uCat], value); break; case k_CategoryId: hr = SetPropertyVal(key, uCat, value); break; default: ATLASSERT(FALSE); break; } return hr; } HRESULT InvalidateItems() { return static_cast(this)->Invalidate(UI_PKEY_ItemsSource); } HRESULT InvalidateCategories() { return static_cast(this)->Invalidate(UI_PKEY_Categories); } HRESULT DoUpdateProperty(UINT nCmdID, REFPROPERTYKEY key, const PROPVARIANT* ppropvarCurrentValue, PROPVARIANT* /*ppropvarNewValue*/) { ATLASSERT(nCmdID == TCtrl::GetID()); nCmdID; // avoid level 4 warning HRESULT hr = E_NOTIMPL; switch (k_(key)) { case k_ItemsSource: { ATL::CComQIPtr pIUICollection(ppropvarCurrentValue->punkVal); ATLASSERT(pIUICollection); hr = pIUICollection->Clear(); for (UINT i = 0; i < m_size; i++) { if FAILED(hr = pIUICollection->Add(m_apItems[i])) break; } ATLASSERT(SUCCEEDED(hr)); } break; case k_Categories: if (t_categories != 0) { ATL::CComQIPtr pIUICategory(ppropvarCurrentValue->punkVal); ATLASSERT(pIUICategory.p); hr = pIUICategory->Clear(); for (UINT i = t_items; i < t_items + t_categories; i++) { if FAILED(hr = pIUICategory->Add(m_apItems[i])) break; } ATLASSERT(SUCCEEDED(hr)); } break; } return hr; } }; // TextCollectionImpl: handles item labels and selection // template class TextCollectionImpl : public CollectionImpl { typedef TextCollectionImpl thisClass; public: typedef thisClass TextCollection; TextCollectionImpl() : m_uSelected(UI_COLLECTION_INVALIDINDEX) { } Text m_asText[t_items]; UINT m_uSelected; // Operations HRESULT SetItemText(UINT uItem, LPCWSTR sText, bool bUpdate = false) { ATLASSERT(uItem < t_items); m_asText[uItem] = sText; return bUpdate ? InvalidateItems() : S_OK; } UINT GetSelected() { return m_uSelected; } HRESULT Select(UINT uItem, bool bUpdate = false) { ATLASSERT((uItem < t_items) || (uItem == UI_COLLECTION_INVALIDINDEX)); m_uSelected = uItem; TCtrl::WndRibbon& ribbon = static_cast(this)->GetWndRibbon(); return bUpdate ? ribbon.SetProperty(TCtrl::GetID(), UI_PKEY_SelectedItem, uItem) : S_OK; } // Implementation HRESULT DoGetItem(UINT uItem, REFPROPERTYKEY key, PROPVARIANT *value) { ATLASSERT(uItem < t_items); if (k_(key) == k_Label) { if (m_asText[uItem].IsEmpty()) { TCtrl::WndRibbon& ribbon = static_cast(this)->GetWndRibbon(); m_asText[uItem] = ribbon.OnRibbonQueryItemText(TCtrl::GetID(), uItem); } return SetPropertyVal(key, (LPCWSTR)m_asText[uItem], value); } else { return Collection::DoGetItem(uItem, key, value); } } HRESULT DoUpdateProperty(UINT nCmdID, REFPROPERTYKEY key, const PROPVARIANT* ppropvarCurrentValue, PROPVARIANT* ppropvarNewValue) { ATLASSERT(nCmdID == TCtrl::GetID()); if (k_(key) == k_SelectedItem) { TCtrl::WndRibbon& ribbon = static_cast(this)->GetWndRibbon(); UINT uSel = UI_COLLECTION_INVALIDINDEX; if ((m_uSelected == UI_COLLECTION_INVALIDINDEX) && ribbon.OnRibbonQuerySelectedItem(TCtrl::GetID(), uSel)) m_uSelected = uSel; return SetPropertyVal(key, m_uSelected, ppropvarNewValue); } else { return Collection::DoUpdateProperty(nCmdID, key, ppropvarCurrentValue, ppropvarNewValue); } } }; // ItemCollectionImpl: handles item image // template class ItemCollectionImpl : public TextCollectionImpl { typedef ItemCollectionImpl thisClass; public: typedef thisClass ItemCollection; ItemCollectionImpl() { ZeroMemory(m_aBitmap, sizeof m_aBitmap); } CBitmap m_aBitmap[t_items]; // Operations HRESULT SetItemImage(UINT uIndex, HBITMAP hbm, bool bUpdate = false) { ATLASSERT(uIndex < t_items); m_aBitmap[uIndex] = hbm; return bUpdate ? InvalidateItems() : S_OK; } // Implementation HRESULT DoGetItem(UINT uItem, REFPROPERTYKEY key, PROPVARIANT *value) { ATLASSERT(uItem < t_items); if (k_(key) == k_ItemImage) { if (m_aBitmap[uItem].IsNull()) { TCtrl::WndRibbon& ribbon = static_cast(this)->GetWndRibbon(); m_aBitmap[uItem] = ribbon.OnRibbonQueryItemImage(TCtrl::GetID(), uItem); } return m_aBitmap[uItem].IsNull() ? E_NOTIMPL : SetPropertyVal(key, GetImage(m_aBitmap[uItem], UI_OWNERSHIP_COPY), value); } else { return TextCollection::DoGetItem(uItem, key, value); } } }; // ComboCollectionImpl: handles combo text // template class ComboCollectionImpl : public ItemCollectionImpl { typedef ComboCollectionImpl thisClass; public: typedef thisClass ComboCollection; // Operations HRESULT SetComboText(LPCWSTR sText) { TCtrl::WndRibbon& ribbon = static_cast(this)->GetWndRibbon(); return ribbon.IsRibbonUI() ? ribbon.SetProperty(TCtrl::GetID(), UI_PKEY_StringValue, sText) : S_OK; } LPCWSTR GetComboText() { static WCHAR sCombo[RIBBONUI_MAX_TEXT] = { 0 }; TCtrl::WndRibbon& ribbon = static_cast(this)->GetWndRibbon(); PROPVARIANT var; if (ribbon.IsRibbonUI()) { HRESULT hr = ribbon.GetIUIFrameworkPtr()->GetUICommandProperty(TCtrl::GetID(), UI_PKEY_StringValue, &var); hr = PropVariantToString(var, sCombo, RIBBONUI_MAX_TEXT); return sCombo; } return NULL; } }; // CommandCollectionImpl: handles RibbonUI command collection controls // template class CommandCollectionImpl : public CollectionImpl { typedef CommandCollectionImpl thisClass; public: typedef thisClass CommandCollection; CommandCollectionImpl() { ZeroMemory(m_auCmd, sizeof m_auCmd); ZeroMemory(m_aCmdType, sizeof m_aCmdType); } UINT32 m_auCmd[t_items]; BYTE m_aCmdType[t_items]; // Operations HRESULT SetItemCommand(UINT uItem, UINT32 uCommandID, bool bUpdate = false) { ATLASSERT(uItem < t_items); if (uCommandID == m_auCmd[uItem]) return S_OK; TCtrl::WndRibbon& ribbon = static_cast(this)->GetWndRibbon(); m_auCmd[uItem] = uCommandID; if (uCommandID != 0) ribbon.UIAddRibbonElement(uCommandID); return bUpdate ? InvalidateItems() : S_OK; } HRESULT SetItemCommandType(UINT uItem, UI_COMMANDTYPE type, bool bUpdate = false) { ATLASSERT(uItem < t_items); m_aCmdType[uItem] = (BYTE)type; return bUpdate ? InvalidateItems() : S_OK; } // Implementation HRESULT DoGetItem(UINT uItem, REFPROPERTYKEY key, PROPVARIANT *value) { ATLASSERT(uItem < t_items); TCtrl::WndRibbon& ribbon = static_cast(this)->GetWndRibbon(); HRESULT hr = E_FAIL; switch (k_(key)) { case k_CommandId: if (m_auCmd[uItem] == 0) SetItemCommand(uItem, ribbon.OnRibbonQueryItemCommand(TCtrl::GetID(), uItem)); hr = SetPropertyVal(key, m_auCmd[uItem], value); break; case k_CommandType: if (m_aCmdType[uItem] == UI_COMMANDTYPE_UNKNOWN) SetItemCommandType(uItem, ribbon.OnRibbonQueryItemCommandType(TCtrl::GetID(), uItem)); hr = SetPropertyVal(key, UINT32(m_aCmdType[uItem]), value); break; case k_CategoryId: default: hr = Collection::DoGetItem(uItem, key, value); break; } return hr; } HRESULT Select(UINT /*uItem*/, bool /*bUpdate*/ = false) { ATLASSERT(FALSE); return S_OK; } }; // SimpleCollectionImpl: collection class for ribbon simple collection controls // template class SimpleCollectionImpl : public CollectionImplBase, t_size> { typedef SimpleCollectionImpl thisClass; public: typedef CollectionImplBase CollectionBase; typedef thisClass SimpleCollection; // Implementation HRESULT OnGetItem(UINT uItem, REFPROPERTYKEY key, PROPVARIANT *value) { ATLASSERT(uItem < t_size); TCtrl::WndRibbon& ribbon = static_cast(this)->GetWndRibbon(); HRESULT hr = E_NOTIMPL; switch (k_(key)) { case k_ItemImage: if (HBITMAP hbm = ribbon.DefRibbonQueryItemImage(TCtrl::GetID(), uItem)) hr = SetPropertyVal(key, GetImage(hbm, UI_OWNERSHIP_TRANSFER), value); break; case k_Label: if (LPCWSTR sText = ribbon.DefRibbonQueryItemText(TCtrl::GetID(), uItem)) hr = SetPropertyVal(key, (LPCWSTR)sText, value); break; case k_CommandType: hr = SetPropertyVal(key, t_CommandType, value); break; case k_CommandId: hr = SetPropertyVal(key, ribbon.DefRibbonQueryItemCommand(TCtrl::GetID(), uItem), value); break; case k_CategoryId: hr = SetPropertyVal(key, UI_COLLECTION_INVALIDINDEX, value); break; default: ATLASSERT(FALSE); break; } return hr; } }; /////////////////////////////////////////////////////////////////////////////// // Ribbon collection control classes // CollectionCtrlImpl: specializable class for ribbon collection controls // template class CollectionCtrlImpl : public CommandCtrlImpl, public TCollection { typedef CollectionCtrlImpl thisClass; public: typedef CommandCtrlImpl CommandCtrl; typedef TCollection Collection; // Implementation virtual HRESULT DoUpdateProperty(UINT nCmdID, REFPROPERTYKEY key, const PROPVARIANT* ppropvarCurrentValue, PROPVARIANT* ppropvarNewValue) { ATLASSERT(nCmdID == GetID()); ATLASSERT(ppropvarNewValue); HRESULT hr = Collection::DoUpdateProperty(nCmdID, key, ppropvarCurrentValue, ppropvarNewValue); if FAILED(hr) hr = CommandCtrl::DoUpdateProperty(nCmdID, key, ppropvarCurrentValue, ppropvarNewValue); return hr; } virtual HRESULT DoExecute(UINT nCmdID, UI_EXECUTIONVERB verb, const PROPERTYKEY* key, const PROPVARIANT* ppropvarValue, IUISimplePropertySet* /*pCommandExecutionProperties*/) { ATLASSERT (nCmdID == GetID()); nCmdID; // avoid level4 warning if (key == NULL) // gallery button pressed { GetWndRibbon().OnRibbonItemSelected(GetID(), UI_EXECUTIONVERB_EXECUTE, UI_COLLECTION_INVALIDINDEX); return S_OK; } ATLASSERT(k_(*key) == k_SelectedItem); ATLASSERT(ppropvarValue); HRESULT hr = S_OK; UINT32 uSel = 0xffff; hr = UIPropertyToUInt32(*key, *ppropvarValue, &uSel); if (SUCCEEDED(hr)) { if (GetWndRibbon().OnRibbonItemSelected(GetID(), verb, uSel)) TCollection::Select(uSel); } return hr; } }; // ToolbarGalleryCtrlImpl: base class for ribbon toolbar gallery controls // template class ToolbarGalleryCtrlImpl : public CollectionCtrlImpl, t_size>> { public: ToolbarGalleryCtrlImpl() { CResource tbres; ATLVERIFY(tbres.Load(RT_TOOLBAR, t_idTB)); _AtlToolBarData* pData = (_AtlToolBarData*)tbres.Lock(); ATLASSERT(pData); ATLASSERT(pData->wVersion == 1); WORD* pItems = pData->items(); INT j = 0; for (int i = 0; (i < pData->wItemCount) && (j < t_size); i++) { if (pItems[i] != 0) { m_aCmdType[j] = UI_COMMANDTYPE_ACTION; m_auCmd[j++] = pItems[i]; } } if (j < t_size) Resize(j); } HRESULT DoGetItem(UINT uItem, REFPROPERTYKEY key, PROPVARIANT *value) { ATLASSERT(uItem < m_size); ATLASSERT(m_auCmd[uItem]); HRESULT hr = E_FAIL; switch (k_(key)) { case k_CommandId: hr = SetPropertyVal(key, m_auCmd[uItem], value); break; case k_CommandType: hr = SetPropertyVal(key, UINT32(m_aCmdType[uItem]), value); break; case k_CategoryId: hr = SetPropertyVal(key, UI_COLLECTION_INVALIDINDEX, value); break; default: ATLASSERT(FALSE); break; } return hr; } }; // SimpleCollectionCtrlImpl: base class for simple gallery and listbox controls // template class SimpleCollectionCtrlImpl : public CommandCtrlImpl, public SimpleCollectionImpl, t_size, t_CommandType> { typedef SimpleCollectionCtrlImpl thisClass; public: typedef thisClass SimpleCollection; SimpleCollectionCtrlImpl() : m_uSelected(0) { } UINT m_uSelected; HRESULT Select(UINT uItem, bool bUpdate = false) { ATLASSERT((uItem < t_size) || (uItem == UI_COLLECTION_INVALIDINDEX)); m_uSelected = uItem; return bUpdate ? GetWndRibbon().SetProperty(GetID(), UI_PKEY_SelectedItem, uItem) : S_OK; } // Implementation virtual HRESULT DoUpdateProperty(UINT nCmdID, REFPROPERTYKEY key, const PROPVARIANT* ppropvarCurrentValue, PROPVARIANT* ppropvarNewValue) { ATLASSERT(nCmdID == GetID()); ATLASSERT(ppropvarNewValue != NULL); HRESULT hr = S_OK; switch (k_(key)) { case k_ItemsSource: { ATL::CComQIPtr pIUICollection(ppropvarCurrentValue->punkVal); ATLASSERT(pIUICollection.p); hr = pIUICollection->Clear(); for (UINT i = 0; i < t_size; i++) { if FAILED(hr = pIUICollection->Add(m_apItems[i])) break; } ATLASSERT(SUCCEEDED(hr)); } break; case k_SelectedItem: hr = SetPropertyVal(UI_PKEY_SelectedItem, m_uSelected, ppropvarNewValue); break; default: hr = CommandCtrlImpl::DoUpdateProperty(nCmdID, key, ppropvarCurrentValue, ppropvarNewValue); break; } return hr; } virtual HRESULT DoExecute(UINT nCmdID, UI_EXECUTIONVERB verb, const PROPERTYKEY* key, const PROPVARIANT* ppropvarValue, IUISimplePropertySet* /*pCommandExecutionProperties*/) { ATLASSERT (nCmdID == GetID()); nCmdID; // avoid level 4 warning HRESULT hr = S_OK; if (key == NULL) // gallery button pressed { GetWndRibbon().OnRibbonItemSelected(GetID(), UI_EXECUTIONVERB_EXECUTE, UI_COLLECTION_INVALIDINDEX); return hr; } ATLASSERT(k_(*key) == k_SelectedItem); ATLASSERT(ppropvarValue); if SUCCEEDED(hr = UIPropertyToUInt32(*key, *ppropvarValue, &m_uSelected)) GetWndRibbon().OnRibbonItemSelected(GetID(), verb, m_uSelected); return hr; } }; // RecentItemsCtrlImpl // template class RecentItemsCtrlImpl : public CtrlImpl, public CollectionImplBase, TDocList::m_nMaxEntries_Max>, public TDocList { typedef RecentItemsCtrlImpl thisClass; public: typedef thisClass RecentItems; // Implementation HRESULT OnGetItem(UINT uItem, REFPROPERTYKEY key, PROPVARIANT *value) { ATLASSERT((INT)uItem < GetMaxEntries()); LPCWSTR sPath = m_arrDocs[uItem].szDocName; HRESULT hr = E_NOTIMPL; switch (k_(key)) { case k_Label: hr = SetPropertyVal(key, GetWndRibbon().OnRibbonQueryRecentItemName(sPath), value); break; case k_LabelDescription: hr = SetPropertyVal(key, sPath, value); break; default: ATLASSERT(FALSE); break; } return hr; } virtual HRESULT DoUpdateProperty(UINT nCmdID, REFPROPERTYKEY key, const PROPVARIANT* ppropvarCurrentValue, PROPVARIANT* ppropvarNewValue) { ATLASSERT(nCmdID == GetID()); ATLASSERT(ppropvarNewValue); HRESULT hr = S_OK; switch (k_(key)) { case k_RecentItems: if (SAFEARRAY* psa = SafeArrayCreateVector(VT_UNKNOWN, 0, m_arrDocs.GetSize())) { const int iLastIndex = m_arrDocs.GetSize() - 1; for (LONG i = 0; i <= iLastIndex; i++) SafeArrayPutElement(psa, &i, m_apItems[iLastIndex - i]); // reverse order hr = SetPropertyVal(key, psa, ppropvarNewValue); SafeArrayDestroy(psa); } break; default: hr = CtrlImpl::DoUpdateProperty(nCmdID, key, ppropvarCurrentValue, ppropvarNewValue); break; } return hr; } virtual HRESULT DoExecute(UINT nCmdID, UI_EXECUTIONVERB verb, const PROPERTYKEY* key, const PROPVARIANT* ppropvarValue, IUISimplePropertySet* /*pCommandExecutionProperties*/) { ATLASSERT(nCmdID == GetID()); nCmdID; // avoid level 4 warning ATLASSERT(verb == UI_EXECUTIONVERB_EXECUTE); verb; // avoid level 4 warning ATLASSERT((key) && (k_(*key) == k_SelectedItem)); ATLASSERT(ppropvarValue); UINT32 uSel = 0xffff; HRESULT hr = UIPropertyToUInt32(*key, *ppropvarValue, &uSel); if SUCCEEDED(hr) { ATLASSERT(uSel < (UINT)GetMaxEntries()); GetWndRibbon().DefCommandExecute(ID_FILE_MRU_FIRST + uSel); } return hr; } }; /////////////////////////////////////////////////////////////////////////////// // Ribbon stand-alone control classes // FontCtrlImpl // template class FontCtrlImpl : public CtrlImpl { public: CharFormat m_cf; // Implementation virtual HRESULT DoExecute(UINT nCmdID, UI_EXECUTIONVERB verb, const PROPERTYKEY* key, const PROPVARIANT* ppropvarValue, IUISimplePropertySet* pCommandExecutionProperties) { ATLASSERT (nCmdID == GetID()); nCmdID; // avoid level 4 warning ATLASSERT ((key) && (k_(*key) == k_FontProperties)); key; // avoid level 4 warning HRESULT hr = E_INVALIDARG; switch (verb) { case UI_EXECUTIONVERB_PREVIEW: case UI_EXECUTIONVERB_EXECUTE: ATLASSERT(pCommandExecutionProperties); PROPVARIANT propvar; if (SUCCEEDED(hr = pCommandExecutionProperties->GetValue(UI_PKEY_FontProperties_ChangedProperties, &propvar))) m_cf << ATL::CComQIPtr(propvar.punkVal); break; case UI_EXECUTIONVERB_CANCELPREVIEW: ATLASSERT(ppropvarValue); ATL::CComPtr pStore; if (SUCCEEDED(hr = UIPropertyToInterface(UI_PKEY_FontProperties, *ppropvarValue, &pStore))) m_cf << pStore; break; } if (SUCCEEDED(hr)) GetWndRibbon().OnRibbonFontCtrlExecute(GetID(), verb, &m_cf); else ATLASSERT(FALSE); return hr; } virtual HRESULT DoUpdateProperty(UINT nCmdID, REFPROPERTYKEY key, const PROPVARIANT* ppropvarCurrentValue, PROPVARIANT* ppropvarNewValue) { if ((k_(key) == k_FontProperties) && (GetWndRibbon().OnRibbonQueryFont(t_ID, m_cf))) { ATL::CComQIPtr pStore(ppropvarCurrentValue->punkVal); m_cf >> pStore; return SetPropertyVal(key, pStore.p, ppropvarNewValue); } else { return CtrlImpl::DoUpdateProperty(nCmdID, key, ppropvarCurrentValue, ppropvarNewValue); } } }; // ColorCtrlImpl // template class ColorCtrlImpl : public CommandCtrlImpl { public: ColorCtrlImpl() : m_colorType(UI_SWATCHCOLORTYPE_NOCOLOR), m_color(0x800080) /*MAGENTA*/ { } COLORREF m_color; UINT32 m_colorType; // value in UI_SWATCHCOLORTYPE Text m_sLabels[6]; // k_MoreColorsLabel to k_ThemeColorsCategoryLabel ATL::CSimpleArray m_aColors[2]; ATL::CSimpleArray m_aTooltips[2]; // Operations HRESULT SetColor(COLORREF color, bool bUpdate = false) { if (m_colorType != UI_SWATCHCOLORTYPE_RGB) SetColorType(UI_SWATCHCOLORTYPE_RGB, bUpdate); m_color = color; return bUpdate ? SetProperty(UI_PKEY_Color, color) : S_OK; } HRESULT SetColorType(UI_SWATCHCOLORTYPE type, bool bUpdate = false) { m_colorType = type; return bUpdate ? SetProperty(UI_PKEY_ColorType, type) : S_OK; } HRESULT SetColorLabel(REFPROPERTYKEY key, LPCWSTR sLabel, bool bUpdate = false) { ATLASSERT((k_(key) >= k_ThemeColorsCategoryLabel) && (k_(key) <= k_MoreColorsLabel)); m_sLabels[k_(key) - k_ThemeColorsCategoryLabel] = sLabel; return bUpdate ? SetProperty(key, sLabel) : S_OK; } HRESULT SetColorArray(REFPROPERTYKEY key, COLORREF* pColor, bool bUpdate = false) { ATLASSERT((k_(key) == k_ThemeColors) || (k_(key) == k_StandardColors)); const INT ic = k_(key) - k_ThemeColors; m_aColors[ic].RemoveAll(); while (*pColor != 0x800080) /*MAGENTA*/ m_aColors[ic].Add(*pColor++); if (bUpdate) { PROPVARIANT var; if SUCCEEDED(InitPropVariantFromUInt32Vector(m_aColors[ic].GetData(), m_aColors[ic].GetSize(), &var)) return SetProperty(key, var); else return E_INVALIDARG; } else { return S_OK; } } HRESULT SetColorTooltips(REFPROPERTYKEY key, LPCWSTR* ppsTT, bool bUpdate = false) { ATLASSERT((k_(key) == k_ThemeColorsTooltips) || (k_(key) == k_StandardColorsTooltips)); const INT ic = k_(key) - k_ThemeColorsTooltips; m_aTooltips[ic].RemoveAll(); while (*ppsTT) m_aTooltips[ic].Add(*ppsTT++); if (bUpdate) { PROPVARIANT var; if SUCCEEDED(InitPropVariantFromStringVector(m_aTooltips[ic].GetData(), m_aTooltips[ic].GetSize(), &var)) return SetProperty(key, var); else return E_INVALIDARG; } else { return S_OK; } } // Implementation virtual HRESULT DoExecute(UINT nCmdID, UI_EXECUTIONVERB verb, const PROPERTYKEY* key, const PROPVARIANT* ppropvarValue, IUISimplePropertySet* pCommandExecutionProperties) { ATLASSERT (nCmdID == GetID()); nCmdID; // avoid level 4 warning ATLASSERT (key && (k_(*key) == k_ColorType)); key; // avoid level 4 warning ATLASSERT (ppropvarValue); HRESULT hr = PropVariantToUInt32(*ppropvarValue, &m_colorType); ATLASSERT(SUCCEEDED(hr)); if (SUCCEEDED(hr) && (m_colorType == UI_SWATCHCOLORTYPE_RGB)) { ATLASSERT(pCommandExecutionProperties); PROPVARIANT var; if SUCCEEDED(hr = pCommandExecutionProperties->GetValue(UI_PKEY_Color, &var)) hr = PropVariantToUInt32(var, &m_color); } if SUCCEEDED(hr) GetWndRibbon().OnRibbonColorCtrlExecute(GetID(), verb, (UI_SWATCHCOLORTYPE)m_colorType/*uType*/, m_color); else ATLASSERT(FALSE); // something was wrong return hr; } virtual HRESULT DoUpdateProperty(UINT nCmdID, REFPROPERTYKEY key, const PROPVARIANT* ppropvarCurrentValue, PROPVARIANT* ppropvarNewValue) { ATLASSERT (nCmdID == GetID()); HRESULT hr = E_NOTIMPL; switch (k_(key)) { case k_ColorType: hr = SetPropertyVal(key, m_colorType, ppropvarNewValue); break; case k_Color: if (m_color == 0x800080) /*MAGENTA*/ m_color = GetWndRibbon().OnRibbonQueryColor(GetID()); hr = SetPropertyVal(key, m_color, ppropvarNewValue); break; case k_ColorMode: break; case k_ThemeColorsCategoryLabel: case k_StandardColorsCategoryLabel: case k_RecentColorsCategoryLabel: case k_AutomaticColorLabel: case k_NoColorLabel: case k_MoreColorsLabel: { const UINT iLabel = k_(key) - k_ThemeColorsCategoryLabel; if (m_sLabels[iLabel].IsEmpty()) if (LPCWSTR psLabel = GetWndRibbon().OnRibbonQueryColorLabel(GetID(), key)) m_sLabels[iLabel] = psLabel; if (!m_sLabels[iLabel].IsEmpty()) hr = SetPropertyVal(key, (LPCWSTR)m_sLabels[iLabel], ppropvarNewValue); } break; case k_ThemeColors: case k_StandardColors: { const INT ic = k_(key) - k_ThemeColors; if (!m_aColors[ic].GetSize()) if (COLORREF* pColor = GetWndRibbon().OnRibbonQueryColorArray(GetID(), key)) SetColorArray(key, pColor); if (INT iMax = m_aColors[ic].GetSize()) hr = InitPropVariantFromUInt32Vector(m_aColors[ic].GetData(), iMax, ppropvarNewValue); } break; case k_ThemeColorsTooltips: case k_StandardColorsTooltips: { const INT ic = k_(key) - k_ThemeColorsTooltips; if (m_aTooltips[ic].GetSize() == 0) if (LPCWSTR* ppsTT = GetWndRibbon().OnRibbonQueryColorTooltips(GetID(), key)) SetColorTooltips(key, ppsTT); if (INT iMax = m_aTooltips[ic].GetSize()) hr = InitPropVariantFromStringVector(m_aTooltips[ic].GetData(), iMax, ppropvarNewValue); } break; default: hr = CommandCtrlImpl::DoUpdateProperty(nCmdID, key, ppropvarCurrentValue, ppropvarNewValue); break; } return hr; } }; // SpinnerCtrlImpl // template class SpinnerCtrlImpl : public CtrlImpl { public: SpinnerCtrlImpl() { m_Values[0] = m_Values[2] = m_Values[4] = 0; m_Values[1] = 100; m_Values[3] = 1; } V m_Values[5]; // k_DecimalValue = 201, k_MaxValue = 203, k_MinValue, k_Increment, k_DecimalPlaces Text m_FormatString; Text m_RepresentativeString; // Operations HRESULT SetDecimalPlaces(V vPlaces, bool bUpdate = false) { return SetValue(UI_PKEY_DecimalPlaces, vPlaces, bUpdate); } HRESULT SetMin(V vMin, bool bUpdate = false) { return SetValue(UI_PKEY_MinValue, vMin, bUpdate); } HRESULT SetMax(V vMax, bool bUpdate = false) { return SetValue(UI_PKEY_MaxValue, vMax, bUpdate); } HRESULT SetVal(V vVal, bool bUpdate = false) { return SetValue(UI_PKEY_DecimalValue, vVal, bUpdate); } HRESULT SetIncrement(V vIncrement, bool bUpdate = false) { return SetValue(UI_PKEY_Increment, vIncrement, bUpdate); } HRESULT SetFormatString(LPCWSTR sFormat, bool bUpdate = false) { return SetText(UI_PKEY_FormatString, sFormat, bUpdate); } HRESULT SetRepresentativeString(LPCWSTR sRepresentative, bool bUpdate = false) { return SetText(UI_PKEY_RepresentativeString, sRepresentative, bUpdate); } // Implementation HRESULT SetText(REFPROPERTYKEY key, LPCWSTR sText, bool bUpdate = false) { switch (k_(key)) { case k_FormatString: m_FormatString = sText; break; case k_RepresentativeString: m_RepresentativeString = sText; break; default: return CtrlImpl::SetText(key, sText, bUpdate); } return bUpdate ? GetWndRibbon().InvalidateProperty(GetID(), key) : S_OK; } HRESULT SetValue(REFPROPERTYKEY key, V val, bool bUpdate = false) { ATLASSERT((k_(key) <= k_DecimalPlaces) && (k_(key) >= k_DecimalValue)); const INT iVal = k_(key) == k_DecimalValue ? 0 : k_(key) - k_StringValue; m_Values[iVal] = val; if (bUpdate) { if(k_(key) == k_DecimalValue) { DECIMAL decVal; InitDecimal(val, &decVal); return SetProperty(key, &decVal); } else { return GetWndRibbon().InvalidateProperty(GetID(), key); } } else { return S_OK; } } HRESULT QueryValue(REFPROPERTYKEY key, LONG* plVal) { return GetWndRibbon().OnRibbonQuerySpinnerValue(GetID(), key, plVal); } HRESULT QueryValue(REFPROPERTYKEY key, DOUBLE* pdVal) { return GetWndRibbon().OnRibbonQueryFloatSpinnerValue(GetID(), key, pdVal); } HRESULT OnGetValue(REFPROPERTYKEY key, PROPVARIANT* ppv) { ATLASSERT((k_(key) <= k_DecimalPlaces) && (k_(key) >= k_DecimalValue)); const INT iVal = k_(key) == k_DecimalValue ? 0 : k_(key) - k_StringValue; QueryValue(key, m_Values + iVal); if (k_(key) == k_DecimalPlaces) { return SetPropertyVal(key, m_Values[iVal], ppv); } else { DECIMAL decVal; InitDecimal(m_Values[iVal], &decVal); return SetPropertyVal(key, &decVal, ppv); } } HRESULT OnGetText(REFPROPERTYKEY key, Text& sVal, PROPVARIANT* ppv) { if (LPCWSTR sNew = GetWndRibbon().OnRibbonQueryText(GetID(), key)) sVal = sNew; return SetPropertyVal(key, (LPCWSTR)sVal, ppv); } virtual HRESULT DoExecute(UINT nCmdID, UI_EXECUTIONVERB verb, const PROPERTYKEY* key, const PROPVARIANT* ppropvarValue, IUISimplePropertySet* /*pCommandExecutionProperties*/) { ATLASSERT (nCmdID == GetID()); nCmdID; // avoid level 4 warning ATLASSERT (key && (k_(*key) == k_DecimalValue)); key; // avoid level 4 warning ATLASSERT (verb == UI_EXECUTIONVERB_EXECUTE); verb; // avoid level 4 warning DECIMAL decVal; HRESULT hr = UIPropertyToDecimal(UI_PKEY_DecimalValue, *ppropvarValue, &decVal); hr = InitVal(m_Values[0], &decVal); GetWndRibbon().OnRibbonSpinnerCtrlExecute(GetID(), &m_Values[0]); return hr; } virtual HRESULT DoUpdateProperty(UINT nCmdID, REFPROPERTYKEY key, const PROPVARIANT* ppropvarCurrentValue, PROPVARIANT* ppropvarNewValue) { ATLASSERT (nCmdID == GetID()); HRESULT hr = E_NOTIMPL; switch (k_(key)) { case k_DecimalPlaces: case k_DecimalValue: case k_Increment: case k_MaxValue: case k_MinValue: hr = OnGetValue(key, ppropvarNewValue); break; case k_FormatString: if (m_FormatString.IsEmpty()) return OnGetText(key, m_FormatString, ppropvarNewValue); break; case k_RepresentativeString: if (m_RepresentativeString.IsEmpty()) return OnGetText(key, m_RepresentativeString, ppropvarNewValue); break; default: hr = CtrlImpl::DoUpdateProperty(nCmdID, key, ppropvarCurrentValue, ppropvarNewValue); break; } return hr; } // decimal conversion helpers static HRESULT InitDecimal(LONG& val, DECIMAL* pDecimal) { return ::VarDecFromI4(val, pDecimal); } static HRESULT InitDecimal(DOUBLE& val, DECIMAL* pDecimal) { return ::VarDecFromR8(val, pDecimal); } static HRESULT InitVal(LONG& val, const DECIMAL* pDecimal) { return ::VarI4FromDec(pDecimal, &val); } static HRESULT InitVal(DOUBLE& val, const DECIMAL* pDecimal) { return ::VarR8FromDec(pDecimal, &val); } }; // CRibbonImpl Ribbon implementation class // template class CRibbonImpl : public CRibbonUpdateUI, public ICtrl, public IUIApplication, public IUICommandHandler { typedef CRibbonImpl thisClass; public: typedef thisClass Ribbon; typedef T WndRibbon; CRibbonImpl() : m_bRibbonUI(false), m_hgRibbonSettings(NULL) { #ifdef _DEBUG m_cRef = 1; #endif pWndRibbon = static_cast(this); HRESULT hr = ::CoInitialize(NULL); if(SUCCEEDED(hr)) if (RunTimeHelper::IsRibbonUIAvailable()) hr = m_pIUIFramework.CoCreateInstance(CLSID_UIRibbonFramework); else ATLTRACE(L"Ribbon UI not available\n"); if FAILED(hr) ATLTRACE(L"Ribbon construction failed\n"); ATLASSERT(SUCCEEDED(hr)); } ~CRibbonImpl() { ::GlobalFree(m_hgRibbonSettings); m_pIUIFramework.Release(); ::CoUninitialize(); } ICtrl& GetRibbonCtrl(UINT) { return static_cast(*this); } ATL::CComPtr m_pIUIFramework; HGLOBAL m_hgRibbonSettings; bool m_bRibbonUI; bool IsRibbonUI() { return m_bRibbonUI; } IUIFramework* GetIUIFrameworkPtr() { return m_pIUIFramework; } template I* GetRibbonViewPtr(UINT32 uID) { ATLASSERT(m_pIUIFramework); ATL::CComPtr pI; return m_pIUIFramework->GetView(uID, __uuidof(I), (void**) &pI) == S_OK ? pI : NULL; } IUIRibbon* GetRibbonPtr() { return GetRibbonViewPtr(0); } IUIContextualUI* GetMenuPtr(UINT32 uID) { ATLASSERT(uID); return GetRibbonViewPtr(uID); } UINT GetRibbonHeight() { ATLASSERT(IsRibbonUI()); UINT32 cy = 0; if (ATL::CComPtr pIUIRibbon = GetRibbonPtr()) pIUIRibbon->GetHeight(&cy); return cy; } HRESULT CreateRibbon(LPCWSTR sResName = L"APPLICATION_RIBBON") { T* pT = static_cast(this); ATLASSERT(GetIUIFrameworkPtr() && !IsRibbonUI()); ATLASSERT(pT->IsWindow()); HRESULT hr = m_pIUIFramework->Initialize(pT->m_hWnd, this); if (hr == S_OK) hr = m_pIUIFramework->LoadUI(ModuleHelper::GetResourceInstance(), sResName); return hr; } HRESULT DestroyRibbon() { T* pT = static_cast(this); ATLASSERT(GetIUIFrameworkPtr() && IsRibbonUI()); ATLASSERT(pT->IsWindow()); HRESULT hRes = m_pIUIFramework->Destroy(); if (!RunTimeHelper::IsWin7()) pT->SetWindowRgn(NULL, TRUE); // Vista Basic bug workaround return hRes; } // Ribbon persistency HRESULT operator >>(IStream* pIStream) { ATLASSERT(GetIUIFrameworkPtr()); ATLASSERT(pIStream); HRESULT hr = E_FAIL; if (ATL::CComPtr pIUIRibbon = GetRibbonPtr()) { const LARGE_INTEGER li0 = { 0 }; pIStream->Seek(li0, STREAM_SEEK_SET, NULL); hr = pIUIRibbon->SaveSettingsToStream(pIStream); pIStream->Commit(STGC_DEFAULT); } return hr; } HRESULT operator <<(IStream* pIStream) { ATLASSERT(GetIUIFrameworkPtr()); ATLASSERT(pIStream); HRESULT hr = E_FAIL; if (ATL::CComPtr pIUIRibbon = GetRibbonPtr()) { const LARGE_INTEGER li0 = { 0 }; pIStream->Seek(li0, STREAM_SEEK_SET, NULL); hr = pIUIRibbon->LoadSettingsFromStream(pIStream); } return hr; } void ResetRibbonSettings() { if (m_hgRibbonSettings != NULL) { ::GlobalFree(m_hgRibbonSettings); m_hgRibbonSettings = NULL; } } HRESULT SaveRibbonSettings() { ATLASSERT(GetIUIFrameworkPtr()); ATLASSERT(static_cast(this)->IsWindow()); HRESULT hr = E_FAIL; ATL::CComPtr pIStream; if SUCCEEDED(hr = ::CreateStreamOnHGlobal(m_hgRibbonSettings, FALSE, &pIStream)) hr = *this >> pIStream; if (SUCCEEDED(hr) && (m_hgRibbonSettings == NULL)) hr = ::GetHGlobalFromStream(pIStream, &m_hgRibbonSettings); if FAILED(hr) ResetRibbonSettings(); return hr; } HRESULT RestoreRibbonSettings() { ATLASSERT(GetIUIFrameworkPtr()); ATLASSERT(m_hgRibbonSettings); ATLASSERT(static_cast(this)->IsWindow()); HRESULT hr = E_FAIL; ATL::CComPtr pIStream; if SUCCEEDED(hr = ::CreateStreamOnHGlobal(m_hgRibbonSettings, FALSE, &pIStream)) hr = *this << pIStream; if FAILED(hr) ResetRibbonSettings(); return hr; } // QAT dock states UI_CONTROLDOCK GetQATDock() { ATLASSERT(GetIUIFrameworkPtr()); ATLASSERT(IsRibbonUI()); UINT32 uDock = 0; PROPVARIANT propvar; ATL::CComQIPtrpIPS(GetRibbonPtr()); if ((pIPS != NULL) && SUCCEEDED(pIPS->GetValue(UI_PKEY_QuickAccessToolbarDock, &propvar)) && SUCCEEDED(UIPropertyToUInt32(UI_PKEY_QuickAccessToolbarDock, propvar, &uDock))) return (UI_CONTROLDOCK)uDock; ATLASSERT(FALSE); // something was wrong return (UI_CONTROLDOCK)0; } bool SetQATDock(UI_CONTROLDOCK dockState) { ATLASSERT(GetIUIFrameworkPtr()); ATLASSERT(IsRibbonUI()); PROPVARIANT propvar; ATLVERIFY(SUCCEEDED(SetPropertyVal(UI_PKEY_QuickAccessToolbarDock, dockState, &propvar))); ATL::CComQIPtrpIPS(GetRibbonPtr()); if ((pIPS != NULL) && SUCCEEDED(pIPS->SetValue(UI_PKEY_QuickAccessToolbarDock, propvar))) { pIPS->Commit(); return true; } ATLASSERT(FALSE); // something was wrong return false; } // Ribbon display states bool GetRibbonDisplayState(REFPROPERTYKEY key) { ATLASSERT(GetIUIFrameworkPtr()); ATLASSERT(IsRibbonUI()); ATLASSERT((k_(key) == k_Viewable) || (k_(key) == k_Minimized)); PROPVARIANT propvar; ATL::CComQIPtrpIPS(GetRibbonPtr()); if ((pIPS != NULL) && SUCCEEDED(pIPS->GetValue(key, &propvar))) { BOOL bState = FALSE; if SUCCEEDED(UIPropertyToBoolean(key, propvar, &bState)) return (bState != FALSE); } ATLASSERT(FALSE); // something was wrong return false; } bool SetRibbonDisplayState(REFPROPERTYKEY key, bool bState = true) { ATLASSERT(GetIUIFrameworkPtr()); ATLASSERT(IsRibbonUI()); ATLASSERT((k_(key) == k_Viewable) || (k_(key) == k_Minimized)); PROPVARIANT propvar; ATLVERIFY(SUCCEEDED(SetPropertyVal(key, bState, &propvar))); ATL::CComQIPtrpIPS(GetRibbonPtr()); if ((pIPS != NULL) && SUCCEEDED(pIPS->SetValue(key, propvar))) { pIPS->Commit(); return true; } ATLASSERT(FALSE); // something was wrong return false; } bool IsRibbonMinimized() { return GetRibbonDisplayState(UI_PKEY_Minimized); } bool MinimizeRibbon(bool bMinimize = true) { return SetRibbonDisplayState(UI_PKEY_Minimized, bMinimize); } bool IsRibbonHidden() { return !GetRibbonDisplayState(UI_PKEY_Viewable); } bool HideRibbon(bool bHide = true) { return SetRibbonDisplayState(UI_PKEY_Viewable, !bHide); } // Ribbon colors UI_HSBCOLOR GetRibbonColor(REFPROPERTYKEY key) { ATLASSERT(GetIUIFrameworkPtr()); ATLASSERT(IsRibbonUI()); ATLASSERT((k_(key) >= k_GlobalBackgroundColor) && (k_(key) <= k_GlobalTextColor)); PROPVARIANT propvar; ATL::CComQIPtrpIPS(GetIUIFrameworkPtr()); if ((pIPS != NULL) && SUCCEEDED(pIPS->GetValue(key, &propvar))) { UINT32 color = 0; if SUCCEEDED(UIPropertyToUInt32(key, propvar, &color)) return color; } ATLASSERT(FALSE); // something was wrong return 0; } bool SetRibbonColor(REFPROPERTYKEY key, UI_HSBCOLOR color) { ATLASSERT(GetIUIFrameworkPtr()); ATLASSERT(IsRibbonUI()); ATLASSERT((k_(key) >= k_GlobalBackgroundColor) && (k_(key) <= k_GlobalTextColor)); PROPVARIANT propvar; ATLVERIFY(SUCCEEDED(SetPropertyVal(key, color, &propvar))); ATL::CComQIPtrpIPS(GetIUIFrameworkPtr()); if ((pIPS != NULL) && SUCCEEDED(pIPS->SetValue(key, propvar))) { pIPS->Commit(); return true; } ATLASSERT(FALSE); // something was wrong return false; } // Ribbon modes HRESULT SetRibbonModes(INT32 iModes) { ATLASSERT(IsRibbonUI()); return GetIUIFrameworkPtr()->SetModes(iModes); } // Ribbon contextual tab UI_CONTEXTAVAILABILITY GetRibbonContextAvail(UINT32 uID) { ATLASSERT(GetIUIFrameworkPtr()); PROPVARIANT propvar; if (IsRibbonUI() && SUCCEEDED(GetIUIFrameworkPtr()->GetUICommandProperty(uID, UI_PKEY_ContextAvailable, &propvar))) { UINT uav; if (SUCCEEDED(PropVariantToUInt32(propvar, &uav))) { CUpdateUIBase::UIEnable(uID, uav != UI_CONTEXTAVAILABILITY_NOTAVAILABLE); CUpdateUIBase::UISetCheck(uID, uav == UI_CONTEXTAVAILABILITY_ACTIVE); return (UI_CONTEXTAVAILABILITY)uav; } } return UI_CONTEXTAVAILABILITY_NOTAVAILABLE; } HRESULT SetRibbonContextAvail(UINT32 uID, UI_CONTEXTAVAILABILITY cav) { CUpdateUIBase::UIEnable(uID, cav != UI_CONTEXTAVAILABILITY_NOTAVAILABLE); CUpdateUIBase::UISetCheck(uID, cav == UI_CONTEXTAVAILABILITY_ACTIVE); return SetProperty((WORD)uID, UI_PKEY_ContextAvailable, UINT32(cav)); } // Ribbon context menu bool HasRibbonMenu(UINT32 uID) { ATL::CComPtr pI = GetMenuPtr(uID); return pI != NULL; } HRESULT TrackRibbonMenu(UINT32 uID, INT32 x, INT32 y) { ATLASSERT(HasRibbonMenu(uID)); return IsRibbonUI() ? ATL::CComPtr(GetMenuPtr(uID))->ShowAtLocation(x, y) : E_FAIL; } HRESULT TrackRibbonMenu(UINT32 uID, LPARAM lParam) { return TrackRibbonMenu(uID, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)); } // Overrideables HBITMAP OnRibbonQueryImage(UINT nCmdID, REFPROPERTYKEY /*key*/) { return DefRibbonQueryImage(nCmdID); } LPCWSTR OnRibbonQueryText(UINT nCmdID, REFPROPERTYKEY key) { return DefRibbonQueryText(nCmdID, key); } bool OnRibbonQueryState(UINT nCmdID, REFPROPERTYKEY key) { return DefRibbonQueryState(nCmdID, key); } UI_CONTEXTAVAILABILITY OnRibbonQueryTabAvail(UINT nCmdID) { DWORD dwState = UIGetState(nCmdID); return ((dwState & UPDUI_DISABLED) == UPDUI_DISABLED) ? UI_CONTEXTAVAILABILITY_NOTAVAILABLE : (((dwState & UPDUI_CHECKED) == UPDUI_CHECKED) ? UI_CONTEXTAVAILABILITY_ACTIVE : UI_CONTEXTAVAILABILITY_AVAILABLE); } LPCWSTR OnRibbonQueryComboText(UINT32 /*uCtrlID*/) { return NULL; } LPCWSTR OnRibbonQueryCategoryText(UINT32 /*uCtrlID*/, UINT32 /*uCat*/) { return L"Category"; } UINT32 OnRibbonQueryItemCategory(UINT32 /*uCtrlID*/, UINT32 /*uItem*/) { return 0; } LPCWSTR OnRibbonQueryItemText(UINT32 uCtrlID, UINT32 uItem) { return DefRibbonQueryItemText(uCtrlID, uItem); } bool OnRibbonQuerySelectedItem(UINT32 /*uCtrlID*/, UINT32& /*uSel*/) { return false; } HBITMAP OnRibbonQueryItemImage(UINT32 uCtrlID, UINT32 uItem) { return DefRibbonQueryItemImage(uCtrlID, uItem); } UINT32 OnRibbonQueryItemCommand(UINT32 uCtrlID, UINT32 uItem) { return DefRibbonQueryItemCommand(uCtrlID, uItem); } UI_COMMANDTYPE OnRibbonQueryItemCommandType(UINT32 /*uCtrlID*/, UINT32 /*uItem*/) { return UI_COMMANDTYPE_ACTION; } LPCWSTR OnRibbonQueryRecentItemName(LPCWSTR sPath) { return ::PathFindFileName(sPath); } bool OnRibbonQueryFont(UINT /*nId*/, CHARFORMAT2& /*cf*/) { return false; } bool OnRibbonQuerySpinnerValue(UINT /*nCmdID*/, REFPROPERTYKEY /*key*/, LONG* /*pVal*/) { return false; } bool OnRibbonQueryFloatSpinnerValue(UINT /*nCmdID*/, REFPROPERTYKEY /*key*/, DOUBLE* /*pVal*/) { return false; } COLORREF OnRibbonQueryColor(UINT /*nCmdID*/) { return 0x800080; /*MAGENTA*/ } LPCWSTR OnRibbonQueryColorLabel(UINT /*nCmdID*/, REFPROPERTYKEY /*key*/) { return NULL; } COLORREF* OnRibbonQueryColorArray(UINT /*nCmdID*/, REFPROPERTYKEY /*key*/) { return NULL; } LPCWSTR* OnRibbonQueryColorTooltips(UINT /*nCmdID*/, REFPROPERTYKEY /*key*/) { return NULL; } bool OnRibbonItemSelected(UINT32 uCtrlID, UI_EXECUTIONVERB verb, UINT32 uItem) { DefCommandExecute(MAKELONG(uCtrlID, verb), uItem); return true; } void OnRibbonColorCtrlExecute(UINT32 uCtrlID, UI_EXECUTIONVERB verb, UI_SWATCHCOLORTYPE uType, COLORREF color) { DefRibbonColorCtrlExecute(uCtrlID, verb, uType, color); } void OnRibbonFontCtrlExecute(UINT32 uCtrlID, UI_EXECUTIONVERB verb, CHARFORMAT2* pcf) { DefCommandExecute(MAKELONG(uCtrlID, verb), (LPARAM)pcf); } void OnRibbonSpinnerCtrlExecute(UINT32 uCtrlID, LONG* pVal) { DefCommandExecute(uCtrlID, *pVal); } void OnRibbonSpinnerCtrlExecute(UINT32 uCtrlID, DOUBLE* pVal) { DefCommandExecute(uCtrlID, (LPARAM)pVal); } void OnRibbonCommandExecute(UINT32 uCmdID) { DefCommandExecute(uCmdID); } // Default implementations HBITMAP DefRibbonQueryImage(UINT nCmdID) { return AtlLoadBitmapImage(nCmdID, LR_CREATEDIBSECTION); } bool DefRibbonQueryState(UINT nCmdID, REFPROPERTYKEY key) { DWORD dwState = UIGetState(nCmdID); bool bRet = false; switch (k_(key)) { case k_BooleanValue: bRet = (dwState & UPDUI_CHECKED) == UPDUI_CHECKED; break; case k_Enabled: bRet = (dwState & UPDUI_DISABLED) != UPDUI_DISABLED; break; default: ATLASSERT(FALSE); break; } return bRet; } LPCTSTR DefRibbonQueryText(UINT nCmdID, REFPROPERTYKEY key) { static WCHAR sText[RIBBONUI_MAX_TEXT] = { 0 }; if (k_(key) == k_Label) return UIGetText(nCmdID); if (AtlLoadString(nCmdID, sText, RIBBONUI_MAX_TEXT)) { PWCHAR pTitle = wcschr(sText, L'\n'); switch (k_(key)) { case k_Keytip: if (PWCHAR pAmp = wcschr(sText, L'&')) pTitle = pAmp; if (pTitle != NULL) *(pTitle + 2) = NULL; // fall through case k_TooltipTitle: return pTitle ? ++pTitle : NULL; case k_TooltipDescription: case k_LabelDescription: if (pTitle != NULL) *pTitle = NULL; return sText; } } return NULL; } LPCWSTR DefRibbonQueryItemText(UINT32 uCtrlID, UINT32 uItem) { return DefRibbonQueryText(uCtrlID + 1 + uItem, UI_PKEY_LabelDescription); } HBITMAP DefRibbonQueryItemImage(UINT32 uCtrlID, UINT32 uItem) { return DefRibbonQueryImage(uCtrlID + 1 + uItem); } UINT32 DefRibbonQueryItemCommand(UINT32 uCtrlID, UINT32 uItem) { return uCtrlID + 1 + uItem; } void DefRibbonColorCtrlExecute(UINT32 uCtrlID, UI_EXECUTIONVERB verb, UI_SWATCHCOLORTYPE uType, COLORREF color) { switch(uType) { case UI_SWATCHCOLORTYPE_RGB: break; case UI_SWATCHCOLORTYPE_AUTOMATIC: color = ::GetSysColor(COLOR_WINDOWTEXT); break; case UI_SWATCHCOLORTYPE_NOCOLOR: color = ::GetSysColor(COLOR_WINDOW); break; default: ATLASSERT(FALSE); break; } DefCommandExecute(MAKELONG(uCtrlID, verb), color); } void DefCommandExecute(UINT32 uCmd, LPARAM lParam = 0) { static_cast(this)->PostMessage(WM_COMMAND, uCmd, lParam); } // Elements setting helpers HRESULT InvalidateCtrl(UINT32 nID) { return IsRibbonUI() ? GetIUIFrameworkPtr()->InvalidateUICommand(nID, UI_INVALIDATIONS_ALLPROPERTIES, NULL) : E_FAIL; } HRESULT InvalidateProperty(UINT32 nID, REFPROPERTYKEY key, UI_INVALIDATIONS flags = UI_INVALIDATIONS_PROPERTY) { return IsRibbonUI() ? GetIUIFrameworkPtr()->InvalidateUICommand(nID, flags, &key) : E_FAIL; } template HRESULT SetProperty(WORD wID, REFPROPERTYKEY key, V val) { if (IsRibbonUI()) { PROPVARIANT var; if (SUCCEEDED(RibbonUI::SetPropertyVal(key, val, &var))) { return SetProperty(wID, key, var); } return E_INVALIDARG; } else { return E_FAIL; } } template <> HRESULT SetProperty(WORD nID, REFPROPERTYKEY key, PROPVARIANT var) { return IsRibbonUI() ? GetIUIFrameworkPtr()->SetUICommandProperty(nID, key, var) : E_FAIL; } // Interfaces // IUIApplication STDMETHODIMP OnViewChanged(UINT32, UI_VIEWTYPE, IUnknown*, UI_VIEWVERB verb, INT32) { switch (verb) { case UI_VIEWVERB_CREATE: m_bRibbonUI = true; if (m_hgRibbonSettings != NULL) RestoreRibbonSettings(); break; case UI_VIEWVERB_SIZE: static_cast(this)->UpdateLayout(FALSE); break; case UI_VIEWVERB_DESTROY: SaveRibbonSettings(); m_bRibbonUI = false; break; } return S_OK; } STDMETHODIMP OnCreateUICommand(UINT32 nCmdID, UI_COMMANDTYPE typeID, IUICommandHandler** ppCommandHandler) { UIAddRibbonElement(nCmdID); if (typeID == UI_COMMANDTYPE_CONTEXT) CUpdateUIBase::UIEnable(nCmdID, false); *ppCommandHandler = this; return S_OK; } STDMETHODIMP OnDestroyUICommand(UINT32 nCmdID, UI_COMMANDTYPE, IUICommandHandler*) { UIRemoveRibbonElement(nCmdID); return S_OK; } // IUICommandHandler STDMETHODIMP Execute(UINT nCmdID, UI_EXECUTIONVERB verb, const PROPERTYKEY* key, const PROPVARIANT* ppropvarValue, IUISimplePropertySet* pCommandExecutionProperties) { T* pT =static_cast(this); return pT->GetRibbonCtrl(nCmdID).DoExecute(nCmdID, verb, key, ppropvarValue, pCommandExecutionProperties); } STDMETHODIMP UpdateProperty(UINT nCmdID, REFPROPERTYKEY key, const PROPVARIANT* ppropvarCurrentValue, PROPVARIANT* ppropvarNewValue) { T* pT =static_cast(this); return pT->GetRibbonCtrl(nCmdID).DoUpdateProperty(nCmdID, key, ppropvarCurrentValue, ppropvarNewValue); } #ifdef _DEBUG // IUnknown methods (heavyweight) STDMETHODIMP_(ULONG) AddRef() { return InterlockedIncrement(&m_cRef); } STDMETHODIMP_(ULONG) Release() { LONG cRef = InterlockedDecrement(&m_cRef); if (cRef == 0) // NoOp for breakpoint { cRef = 0; } return cRef; } STDMETHODIMP QueryInterface(REFIID iid, void** ppv) { if (ppv == NULL) { return E_POINTER; } else if ((iid == __uuidof(IUnknown)) || (iid == __uuidof(IUICommandHandler)) || (iid == __uuidof(IUIApplication))) { *ppv = this; AddRef(); return S_OK; } else { return E_NOINTERFACE; } } LONG m_cRef; #else // IUnknown methods (lightweight) STDMETHODIMP QueryInterface(REFIID iid, void** ppv) { if ((iid == __uuidof(IUnknown)) || (iid == __uuidof(IUICommandHandler)) || (iid == __uuidof(IUIApplication))) { *ppv = this; return S_OK; } return E_NOINTERFACE; } ULONG STDMETHODCALLTYPE AddRef() { return 1; } ULONG STDMETHODCALLTYPE Release() { return 1; } #endif // CRibbonImpl ICtrl implementation virtual HRESULT DoExecute(UINT nCmdID, UI_EXECUTIONVERB verb, const PROPERTYKEY* key, const PROPVARIANT* ppropvarValue, IUISimplePropertySet* /*pCommandExecutionProperties*/) { if (key != NULL) { if(k_(*key) != k_BooleanValue) { ATLTRACE(L"Control ID %d is not handled\n", nCmdID); return E_NOTIMPL; } BOOL bChecked = FALSE; ATLVERIFY(SUCCEEDED(PropVariantToBoolean(*ppropvarValue, &bChecked))); CUpdateUIBase::UISetCheck(nCmdID, bChecked); } ATLASSERT(verb == UI_EXECUTIONVERB_EXECUTE); verb; // avoid level 4 warning static_cast(this)->OnRibbonCommandExecute(nCmdID); return S_OK; } virtual HRESULT DoUpdateProperty(UINT nCmdID, REFPROPERTYKEY key, const PROPVARIANT* /*ppropvarCurrentValue*/, PROPVARIANT* ppropvarNewValue) { T* pT = static_cast(this); HRESULT hr = E_NOTIMPL; switch (k_(key)) { case k_LargeImage: case k_LargeHighContrastImage: case k_SmallImage: case k_SmallHighContrastImage: if (HBITMAP hbm = pT->OnRibbonQueryImage(nCmdID, key)) hr = SetPropertyVal(key, GetImage(hbm, UI_OWNERSHIP_TRANSFER), ppropvarNewValue); break; case k_Label: case k_Keytip: case k_TooltipTitle: case k_TooltipDescription: case k_LabelDescription: if (LPCWSTR sText = pT->OnRibbonQueryText(nCmdID, key)) hr = SetPropertyVal(key, sText, ppropvarNewValue); break; case k_BooleanValue: case k_Enabled: hr = SetPropertyVal(key, pT->OnRibbonQueryState(nCmdID, key), ppropvarNewValue); break; case k_ContextAvailable: hr = SetPropertyVal(key, pT->OnRibbonQueryTabAvail(nCmdID), ppropvarNewValue); break; } return hr; } // CRibbonImpl::CRibbonXXXCtrl specialized classes //CRibbonComboCtrl template class CRibbonComboCtrl : public CollectionCtrlImpl, t_items, t_categories>> { public: CRibbonComboCtrl() { } }; // CRibbonItemGalleryCtrl template class CRibbonItemGalleryCtrl : public CollectionCtrlImpl, t_items, t_categories>> { public: CRibbonItemGalleryCtrl() { } }; // CRibbonCommandGalleryCtrl template class CRibbonCommandGalleryCtrl : public CollectionCtrlImpl, t_items, t_categories>> { public: CRibbonCommandGalleryCtrl() { } }; // CRibbonToolbarGalleryCtrl template class CRibbonToolbarGalleryCtrl : public ToolbarGalleryCtrlImpl { }; // CRibbonSimpleComboCtrl template class CRibbonSimpleComboCtrl : public SimpleCollectionCtrlImpl { }; // CRibbonSimpleGalleryCtrl template class CRibbonSimpleGalleryCtrl : public SimpleCollectionCtrlImpl { }; //CRibbonRecentItemsCtrl template class CRibbonRecentItemsCtrl : public RecentItemsCtrlImpl { public: CRibbonRecentItemsCtrl() { } }; // CRibbonColorCtrl template class CRibbonColorCtrl : public ColorCtrlImpl { public: CRibbonColorCtrl() { } }; //CRibbonFontCtrl template class CRibbonFontCtrl : public FontCtrlImpl { public: CRibbonFontCtrl() { } }; // CRibbonSpinnerCtrl template class CRibbonSpinnerCtrl : public SpinnerCtrlImpl { public: CRibbonSpinnerCtrl() { } }; // CRibbonFloatSpinnerCtrl template class CRibbonFloatSpinnerCtrl : public SpinnerCtrlImpl { public: CRibbonFloatSpinnerCtrl() { m_Values[4] = 1; // 1 decimal } }; // CRibbonCommandCtrl template class CRibbonCommandCtrl : public CommandCtrlImpl { public: CRibbonCommandCtrl() { } }; // Control classes access to T instance (re-initialized in constructor) static T* pWndRibbon; }; template __declspec(selectany) T* CRibbonImpl::pWndRibbon; // Control map element #pragma warning (disable : 4510 610) // missing default constructor typedef struct { UINT uID; ICtrl& ctrl; } _ribbonCtrl; #pragma warning (default : 4510 610) // missing default constructor }; // namespace RibbonUI /////////////////////////////////////////////////////////////////////////////// // RibbonUI Control map // Control map macros #define BEGIN_RIBBON_CONTROL_MAP(theClass) \ RibbonUI::ICtrl& GetRibbonCtrl(UINT id) \ { \ RibbonUI::_ribbonCtrl _ctrls[] = \ { #define RIBBON_CONTROL(member) {member.GetID(), static_cast(member)}, #define END_RIBBON_CONTROL_MAP() \ {0, *this} \ }; \ int i = 0; \ for(; i < _countof(_ctrls) - 1; i++) \ if (_ctrls[i].uID == id) \ break; \ return _ctrls[i].ctrl; \ } // Control message map macros #define RIBBON_GALLERY_CONTROL_HANDLER(id, func) \ if(uMsg == WM_COMMAND && id == LOWORD(wParam)) \ { \ bHandled = TRUE; \ lResult = func((UI_EXECUTIONVERB)HIWORD(wParam), LOWORD(wParam), (UINT)lParam, bHandled); \ if(bHandled) \ return TRUE; \ } #define RIBBON_COMBO_CONTROL_HANDLER(id, func) \ RIBBON_GALLERY_CONTROL_HANDLER(id, func) #define RIBBON_FONT_CONTROL_HANDLER(id, func) \ if(uMsg == WM_COMMAND && id == LOWORD(wParam)) \ { \ bHandled = TRUE; \ lResult = func((UI_EXECUTIONVERB)HIWORD(wParam), LOWORD(wParam), (CHARFORMAT2*)lParam, bHandled); \ if(bHandled) \ return TRUE; \ } #define RIBBON_COLOR_CONTROL_HANDLER(id, func) \ if(uMsg == WM_COMMAND && id == LOWORD(wParam)) \ { \ bHandled = TRUE; \ lResult = func((UI_EXECUTIONVERB)HIWORD(wParam), LOWORD(wParam), (COLORREF)lParam, bHandled); \ if(bHandled) \ return TRUE; \ } #define RIBBON_SPINNER_CONTROL_HANDLER(id, func) \ if(uMsg == WM_COMMAND && id == wParam) \ { \ bHandled = TRUE; \ lResult = func((WORD)wParam, (LONG)lParam, bHandled); \ if(bHandled) \ return TRUE; \ } #define RIBBON_FLOATSPINNER_CONTROL_HANDLER(id, func) \ if(uMsg == WM_COMMAND && id == wParam) \ { \ bHandled = TRUE; \ lResult = func((WORD)wParam, (DOUBLE*)lParam, bHandled); \ if(bHandled) \ return TRUE; \ } // Handler prototypes /* LRESULT OnRibbonGalleryCtrl(UI_EXECUTIONVERB verb, WORD wID, UINT uSel, BOOL& bHandled); LRESULT OnRibbonComboCtrl(UI_EXECUTIONVERB verb, WORD wID, UINT uSel, BOOL& bHandled); LRESULT OnRibbonFontCtrl(UI_EXECUTIONVERB verb, WORD wID, CHARFORMAT2* pcf, BOOL& bHandled); LRESULT OnRibbonColorCtrl(UI_EXECUTIONVERB verb, WORD wID, COLORREF color, BOOL& bHandled); LRESULT OnRibbonSpinnerCtrl(WORD wID, LONG lVal, BOOL& bHandled); LRESULT OnRibbonFloatSpinnerCtrl(WORD wID, DOUBLE* pdVal, BOOL& bHandled); */ /////////////////////////////////////////////////////////////////////////////// // Ribbon frame classes // CRibbonFrameWindowImplBase // template class ATL_NO_VTABLE CRibbonFrameWindowImplBase : public TFrameImpl, public RibbonUI::CRibbonImpl { typedef TFrameImpl baseFrame; bool m_bUseCommandBarBitmaps; bool m_bWin7Fix; public: // Construction CRibbonFrameWindowImplBase(bool bUseCommandBarBitmaps = true) : m_bUseCommandBarBitmaps(bUseCommandBarBitmaps), m_bWin7Fix(false) { __if_not_exists(T::m_CmdBar) { m_bUseCommandBarBitmaps = false; } } // Win7 Aero fix helpers void ResetFrame() { const MARGINS margins = { 0 }; ::DwmExtendFrameIntoClientArea(m_hWnd, &margins); } INT CalcWin7Fix() { ResetFrame(); RECT rc = { 0 }; ::AdjustWindowRectEx(&rc, T::GetWndStyle(0), GetMenu() != NULL, T::GetWndExStyle(0)); return -rc.top; } bool NeedWin7Fix() { BOOL bComp = FALSE; return m_bWin7Fix && RunTimeHelper::IsWin7() && SUCCEEDED(DwmIsCompositionEnabled(&bComp)) && bComp; } // Operations bool UseCommandBarBitmaps(bool bUse) { __if_exists(T::m_CmdBar) { return m_bUseCommandBarBitmaps = bUse; } __if_not_exists(T::m_CmdBar) { bUse; // avoid level 4 warning return false; } } bool ShowRibbonUI(bool bShow, INT32 imodes = UI_MAKEAPPMODE(0), LPCWSTR sResName = L"APPLICATION_RIBBON") { if (!RunTimeHelper::IsRibbonUIAvailable()) return false; ATLASSERT(GetIUIFrameworkPtr()); if (IsRibbonUI() == bShow) return bShow; bool bVisible = (IsWindowVisible() != FALSE); if(bVisible && !bShow) SetRedraw(FALSE); if (bShow && ::IsWindow(m_hWndToolBar)) { ::ShowWindow(m_hWndToolBar, SW_HIDE); UpdateLayout(); } m_bWin7Fix = !bShow; HRESULT hr = bShow ? CreateRibbon(sResName) : DestroyRibbon(); m_bWin7Fix = SUCCEEDED(hr) && !bShow; if (SUCCEEDED(hr)) { if(::IsWindow(m_hWndToolBar) && !bShow) { ::ShowWindow(m_hWndToolBar, SW_SHOWNA); UpdateLayout(); } else if (bShow) { PostMessage(WM_SIZE); SetRibbonModes(imodes); } } if(bVisible && !bShow) { SetRedraw(TRUE); RedrawWindow(NULL, NULL, RDW_FRAME | RDW_ERASE | RDW_INVALIDATE | RDW_UPDATENOW | RDW_ALLCHILDREN); } return SUCCEEDED(hr) ? bShow : !bShow; } // Overrideables HBITMAP OnRibbonQueryImage(UINT nCmdID, REFPROPERTYKEY key) { if ((key == UI_PKEY_SmallImage) && m_bUseCommandBarBitmaps) { if (HBITMAP hbm = GetCommandBarBitmap(nCmdID)) return (HBITMAP)::CopyImage(hbm, IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION); } return DefRibbonQueryImage(nCmdID); } BEGIN_MSG_MAP(CRibbonFrameWindowImplBase) if (!IsRibbonUI() && NeedWin7Fix()) { MESSAGE_HANDLER(WM_SIZING, OnSizing) MESSAGE_HANDLER(WM_SIZE, OnSize) MESSAGE_HANDLER(WM_ACTIVATE, OnActivate) MESSAGE_HANDLER(WM_NCCALCSIZE, OnNCCalcSize) } CHAIN_MSG_MAP(CRibbonUpdateUI) CHAIN_MSG_MAP(baseFrame) END_MSG_MAP() // Message handlers for Win7 Aero LRESULT OnSizing(UINT /*uMsg*/, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/) { switch (wParam) { case WMSZ_TOP: case WMSZ_TOPLEFT: case WMSZ_TOPRIGHT: SetWindowPos(NULL, (LPRECT)lParam, SWP_NOMOVE | SWP_NOZORDER | SWP_FRAMECHANGED); break; default: DefWindowProc(); break; } return 1; // handled } LRESULT OnSize(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled) { if (wParam != SIZE_MINIMIZED) SetWindowPos(NULL, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED); bHandled = FALSE; return 1; } LRESULT OnActivate(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled) { if(wParam != WA_INACTIVE) SetWindowPos(NULL, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED); bHandled = FALSE; return 1; } LRESULT OnNCCalcSize(UINT /*uMsg*/, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/) { ATLASSERT(!IsRibbonUI() && NeedWin7Fix()); LRESULT lRet = DefWindowProc(); if(wParam) { LPNCCALCSIZE_PARAMS pParams = (LPNCCALCSIZE_PARAMS)lParam; pParams->rgrc[0].top = pParams->rgrc[1].top + CalcWin7Fix(); } return lRet; } // Overrides void UpdateLayout(BOOL bResizeBars = TRUE) { RECT rect = { 0 }; GetClientRect(&rect); if (IsRibbonUI() && !IsRibbonHidden()) { rect.top += GetRibbonHeight(); } else if (!IsRibbonUI() && NeedWin7Fix()) { ResetFrame(); } // position bars and offset their dimensions UpdateBarsPosition(rect, bResizeBars); // resize client window if(m_hWndClient != NULL) ::SetWindowPos(m_hWndClient, NULL, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, SWP_NOZORDER | SWP_NOACTIVATE); } // Implementation HBITMAP GetCommandBarBitmap(UINT nCmdID) { __if_exists (T::m_CmdBar) { ATLASSERT(RunTimeHelper::IsVista()); T* pT =static_cast(this); int nIndex = pT->m_CmdBar.m_arrCommand.Find((WORD&)nCmdID); return (nIndex == -1) ? NULL : pT->m_CmdBar.m_arrVistaBitmap[nIndex]; } __if_not_exists (T::m_CmdBar) { nCmdID; // avoid level 4 warning return NULL; } } }; // CRibbonFrameWindowImpl // template class ATL_NO_VTABLE CRibbonFrameWindowImpl : public CRibbonFrameWindowImplBase> { }; // CRibbonMDIFrameWindowImpl // template class ATL_NO_VTABLE CRibbonMDIFrameWindowImpl : public CRibbonFrameWindowImplBase> { }; /////////////////////////////////////////////////////////////////////////////// // CRibbonPersist helper for RibbonUI persistency class CRibbonPersist { public: CRibbonPersist(LPCWSTR sAppKey) { ATLASSERT(sAppKey && *sAppKey); m_Key.Create(HKEY_CURRENT_USER, sAppKey); ATLASSERT(m_Key.m_hKey); } CRegKeyEx m_Key; LONG Save(bool bRibbonUI, HGLOBAL hgSettings = NULL) { CRegKeyEx key; const DWORD dwUI = bRibbonUI; LONG lRet = key.Create(m_Key, L"Ribbon"); if(lRet != ERROR_SUCCESS) return lRet; lRet = key.SetDWORDValue(L"UI", dwUI); if(lRet != ERROR_SUCCESS) return lRet; if (hgSettings != NULL) { LPBYTE pVal = (LPBYTE)::GlobalLock(hgSettings); if (pVal != NULL) { lRet = key.SetBinaryValue(L"Settings", pVal, ::GlobalSize(hgSettings)); ::GlobalUnlock(hgSettings); } else { lRet = GetLastError(); } } return lRet; } LONG Restore(bool& bRibbonUI, HGLOBAL& hgSettings) { ATLASSERT(hgSettings == NULL); CRegKeyEx key; LONG lRet = key.Open(m_Key, L"Ribbon"); if(lRet != ERROR_SUCCESS) return lRet; DWORD dwUI = 0xffff; lRet = key.QueryDWORDValue(L"UI", dwUI); if(lRet == ERROR_SUCCESS) bRibbonUI = dwUI == 1; else return lRet; ULONG ulSize = 0; lRet = key.QueryBinaryValue(L"Settings", NULL, &ulSize); if (lRet == ERROR_SUCCESS) { ATLASSERT(ulSize != 0); hgSettings = ::GlobalAlloc(GHND, ulSize); if (hgSettings != NULL) { LPBYTE pData = (LPBYTE)::GlobalLock(hgSettings); if (pData != NULL) { lRet = key.QueryBinaryValue(L"Settings", pData, &ulSize); } else { lRet = GetLastError(); ::GlobalFree(hgSettings); hgSettings = NULL; } } else { lRet = GetLastError(); } } return lRet; } LONG Delete() { return m_Key.DeleteSubKey(L"Ribbon"); } }; } // namespace WTL #endif // __ATLRIBBON_H__