Apply backgroundcolors.patch
[TortoiseGit.git] / src / TortoiseMerge / NativeRibbonApp.cpp
blob52ac8190e6f0f9606a51b2f5e54dbfd0557af490
1 // TortoiseGitMerge - a Diff/Patch program
3 // Copyright (C) 2017, 2019, 2023 - TortoiseGit
4 // Copyright (C) 2017 - TortoiseSVN
6 // This program is free software; you can redistribute it and/or
7 // modify it under the terms of the GNU General Public License
8 // as published by the Free Software Foundation; either version 2
9 // of the License, or (at your option) any later version.
11 // This program is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 // GNU General Public License for more details.
16 // You should have received a copy of the GNU General Public License
17 // along with this program; if not, write to the Free Software Foundation,
18 // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21 #include "stdafx.h"
22 #include "NativeRibbonApp.h"
24 CNativeRibbonApp::CNativeRibbonApp(CFrameWnd* pFrame, IUIFramework* pFramework)
25 : m_pFrame(pFrame)
26 , m_pFramework(pFramework)
30 CNativeRibbonApp::~CNativeRibbonApp()
32 ASSERT(m_cRefCount == 0);
35 STDMETHODIMP CNativeRibbonApp::QueryInterface(REFIID riid, void **ppvObject)
37 if (riid == IID_IUnknown)
39 AddRef();
40 *ppvObject = static_cast<IUICommandHandler*>(this);
41 return S_OK;
43 else if (riid == __uuidof(IUIApplication))
45 AddRef();
46 *ppvObject = static_cast<IUIApplication*>(this);
47 return S_OK;
49 else if (riid == __uuidof(IUICommandHandler))
51 AddRef();
52 *ppvObject = static_cast<IUICommandHandler*>(this);
53 return S_OK;
55 else
57 return E_NOINTERFACE;
61 STDMETHODIMP_(ULONG) CNativeRibbonApp::AddRef(void)
63 return InterlockedIncrement(&m_cRefCount);
66 STDMETHODIMP_(ULONG) CNativeRibbonApp::Release(void)
68 return InterlockedDecrement(&m_cRefCount);
71 STDMETHODIMP CNativeRibbonApp::OnViewChanged(UINT32 /*viewId*/, UI_VIEWTYPE typeID, IUnknown* view, UI_VIEWVERB verb, INT32 /*uReasonCode*/)
73 if (typeID == UI_VIEWTYPE_RIBBON)
75 if (verb == UI_VIEWVERB_CREATE)
77 if (!m_SettingsFileName.IsEmpty())
79 CComQIPtr<IUIRibbon> ribbonView(view);
80 if (ribbonView)
81 LoadRibbonViewSettings(ribbonView, m_SettingsFileName);
84 m_pFrame->RecalcLayout();
86 else if (verb == UI_VIEWVERB_DESTROY)
88 CComQIPtr<IUIRibbon> ribbonView(view);
89 if (ribbonView)
90 SaveRibbonViewSettings(ribbonView, m_SettingsFileName);
92 else if (verb == UI_VIEWVERB_SIZE)
93 m_pFrame->RecalcLayout();
96 return S_OK;
99 STDMETHODIMP CNativeRibbonApp::OnCreateUICommand(UINT32 commandId, UI_COMMANDTYPE typeID, IUICommandHandler** commandHandler)
101 m_commandIds.push_back(commandId);
102 if (typeID == UI_COMMANDTYPE_COLLECTION)
103 m_collectionCommandIds.push_back(commandId);
105 return QueryInterface(IID_PPV_ARGS(commandHandler));
108 STDMETHODIMP CNativeRibbonApp::OnDestroyUICommand(UINT32 commandId, UI_COMMANDTYPE /*typeID*/, IUICommandHandler* /*commandHandler*/)
110 m_commandIds.remove(commandId);
112 return S_OK;
115 STDMETHODIMP CNativeRibbonApp::Execute(UINT32 commandId, UI_EXECUTIONVERB verb, const PROPERTYKEY* key, const PROPVARIANT* currentValue, IUISimplePropertySet* /*commandExecutionProperties*/)
117 if (verb == UI_EXECUTIONVERB_EXECUTE)
119 if (key && IsEqualPropertyKey(*key, UI_PKEY_SelectedItem))
121 CComPtr<IUICollection> items = GetUICommandItemsSource(commandId);
122 UINT32 selectedItemIdx = 0;
123 UIPropertyToUInt32(UI_PKEY_SelectedItem, *currentValue, &selectedItemIdx);
124 UINT32 count = 0;
125 items->GetCount(&count);
127 if (selectedItemIdx < count)
129 CComPtr<IUnknown> selectedItemUnk;
130 items->GetItem(selectedItemIdx, &selectedItemUnk);
131 CComQIPtr<IUISimplePropertySet> selectedItemPropSet(selectedItemUnk);
132 if (selectedItemPropSet)
133 m_pFrame->PostMessage(WM_COMMAND, GetCommandIdProperty(selectedItemPropSet));
136 else
137 m_pFrame->PostMessage(WM_COMMAND, commandId);
139 return S_OK;
142 return S_FALSE;
145 class CRibbonCmdUI : public CCmdUI
147 public:
148 CString m_Text;
149 BOOL m_bOn;
150 int m_nCheck;
151 int m_bCheckChanged;
153 CRibbonCmdUI(int commandId)
154 : m_bOn(FALSE)
155 , m_nCheck(0)
156 , m_bCheckChanged(FALSE)
158 m_nID = commandId;
161 virtual void Enable(BOOL bOn)
163 m_bOn = bOn;
164 m_bEnableChanged = TRUE;
167 virtual void SetCheck(int nCheck)
169 m_nCheck = nCheck;
170 m_bCheckChanged = TRUE;
173 virtual void SetText(LPCWSTR lpszText)
175 m_Text = lpszText;
179 STDMETHODIMP CNativeRibbonApp::UpdateProperty(UINT32 commandId, REFPROPERTYKEY key, const PROPVARIANT* /*currentValue*/, PROPVARIANT* newValue)
181 if (key == UI_PKEY_TooltipTitle)
183 CString str;
184 if (!str.LoadString(commandId))
185 return S_FALSE;
187 int nIndex = str.Find(L'\n');
188 if (nIndex <= 0)
189 return S_FALSE;
191 str = str.Mid(nIndex + 1);
193 CString strLabel;
195 if (m_pFrame != NULL && (CKeyboardManager::FindDefaultAccelerator(commandId, strLabel, m_pFrame, TRUE) ||
196 CKeyboardManager::FindDefaultAccelerator(commandId, strLabel, m_pFrame->GetActiveFrame(), FALSE)))
198 str += _T(" (");
199 str += strLabel;
200 str += _T(')');
203 return UIInitPropertyFromString(UI_PKEY_TooltipTitle, str, newValue);
205 else if (key == UI_PKEY_TooltipDescription)
207 CString str;
208 if (!str.LoadString(commandId))
209 return S_FALSE;
211 int nIndex = str.Find(L'\n');
212 if (nIndex <= 0)
213 return S_FALSE;
215 str = str.Left(nIndex);
217 return UIInitPropertyFromString(UI_PKEY_TooltipDescription, str, newValue);
219 else if (key == UI_PKEY_Enabled)
221 CRibbonCmdUI ui(commandId);
222 ui.DoUpdate(m_pFrame, TRUE);
224 return UIInitPropertyFromBoolean(UI_PKEY_Enabled, ui.m_bOn, newValue);
226 else if (key == UI_PKEY_BooleanValue)
228 CRibbonCmdUI ui(commandId);
229 ui.DoUpdate(m_pFrame, TRUE);
231 return UIInitPropertyFromBoolean(UI_PKEY_BooleanValue, ui.m_nCheck, newValue);
233 else if (key == UI_PKEY_SelectedItem)
235 CComPtr<IUICollection> items = GetUICommandItemsSource(commandId);
236 if (!items)
237 return E_FAIL;
239 UINT32 count;
240 items->GetCount(&count);
241 for (UINT32 idx = 0; idx < count; idx++)
243 CComPtr<IUnknown> item;
244 items->GetItem(idx, &item);
246 CComQIPtr<IUISimplePropertySet> simplePropertySet(item);
247 if (simplePropertySet)
249 PROPVARIANT var = { 0 };
250 UINT32 uiVal;
251 simplePropertySet->GetValue(UI_PKEY_CommandId, &var);
252 UIPropertyToUInt32(UI_PKEY_CommandId, var, &uiVal);
254 CRibbonCmdUI ui(uiVal);
255 ui.DoUpdate(m_pFrame, TRUE);
257 if (ui.m_nCheck)
259 UIInitPropertyFromUInt32(UI_PKEY_SelectedItem, idx, newValue);
260 return S_OK;
265 // No selected item.
266 UIInitPropertyFromUInt32(UI_PKEY_SelectedItem, static_cast<UINT>(-1), newValue);
268 return S_OK;
271 return E_NOTIMPL;
274 HRESULT CNativeRibbonApp::SaveRibbonViewSettings(IUIRibbon* pRibbonView, const CString& fileName)
276 CComPtr<IStream> stream;
277 HRESULT hr = SHCreateStreamOnFileEx(fileName, STGM_WRITE | STGM_CREATE, FILE_ATTRIBUTE_NORMAL, TRUE, nullptr, &stream);
278 if (FAILED(hr))
279 return hr;
281 hr = pRibbonView->SaveSettingsToStream(stream);
282 if (FAILED(hr))
284 stream->Revert();
285 return hr;
288 hr = stream->Commit(STGC_DEFAULT);
290 return hr;
293 HRESULT CNativeRibbonApp::LoadRibbonViewSettings(IUIRibbon* pRibbonView, const CString& fileName)
295 CComPtr<IStream> stream;
296 HRESULT hr = SHCreateStreamOnFileEx(fileName, STGM_READ, FILE_ATTRIBUTE_NORMAL, FALSE, nullptr, &stream);
297 if (FAILED(hr))
298 return hr;
300 hr = pRibbonView->LoadSettingsFromStream(stream);
302 return hr;
305 CComPtr<IUICollection> CNativeRibbonApp::GetUICommandItemsSource(UINT commandId)
307 PROPVARIANT prop = { 0 };
309 m_pFramework->GetUICommandProperty(commandId, UI_PKEY_ItemsSource, &prop);
311 CComPtr<IUICollection> uiCollection;
312 UIPropertyToInterface(UI_PKEY_ItemsSource, prop, &uiCollection);
313 PropVariantClear(&prop);
315 return uiCollection;
318 void CNativeRibbonApp::SetUICommandItemsSource(UINT commandId, IUICollection* pItems)
320 PROPVARIANT prop = { 0 };
322 UIInitPropertyFromInterface(UI_PKEY_ItemsSource, pItems, &prop);
324 m_pFramework->SetUICommandProperty(commandId, UI_PKEY_ItemsSource, prop);
326 PropVariantClear(&prop);
329 UINT CNativeRibbonApp::GetCommandIdProperty(IUISimplePropertySet* propertySet)
331 PROPVARIANT var = { 0 };
332 UINT32 commandId = 0;
334 if (propertySet->GetValue(UI_PKEY_CommandId, &var) == S_OK)
335 UIPropertyToUInt32(UI_PKEY_CommandId, var, &commandId);
337 return commandId;
340 void CNativeRibbonApp::UpdateCmdUI(BOOL bDisableIfNoHandler)
342 for (auto it = m_commandIds.begin(); it != m_commandIds.end(); ++it)
344 CRibbonCmdUI ui(*it);
345 ui.DoUpdate(m_pFrame, bDisableIfNoHandler);
346 if (ui.m_bEnableChanged)
348 PROPVARIANT val = { 0 };
349 UIInitPropertyFromBoolean(UI_PKEY_Enabled, ui.m_bOn, &val);
350 m_pFramework->SetUICommandProperty(*it, UI_PKEY_Enabled, val);
353 if (ui.m_bCheckChanged)
355 PROPVARIANT val = { 0 };
356 UIInitPropertyFromBoolean(UI_PKEY_BooleanValue, ui.m_nCheck, &val);
357 m_pFramework->SetUICommandProperty(*it, UI_PKEY_BooleanValue, val);
361 for (auto it = m_collectionCommandIds.begin(); it != m_collectionCommandIds.end(); ++it)
363 PROPVARIANT currentValue = { 0 };
364 PROPVARIANT newValue = { 0 };
366 UpdateProperty(*it, UI_PKEY_SelectedItem, &currentValue, &newValue);
367 m_pFramework->SetUICommandProperty(*it, UI_PKEY_SelectedItem, newValue);
371 int CNativeRibbonApp::GetRibbonHeight()
373 CComPtr<IUIRibbon> pRibbon;
374 if (SUCCEEDED(m_pFramework->GetView(0, IID_PPV_ARGS(&pRibbon))))
376 UINT32 cy = 0;
377 pRibbon->GetHeight(&cy);
378 return static_cast<int>(cy);
381 return 0;
384 class UIDynamicCommandItem : public IUISimplePropertySet
386 private:
387 ULONG m_RefCount;
388 CString m_Label;
389 int m_CommandId;
390 CComPtr<IUIImage> m_Image;
392 public:
393 class UIDynamicCommandItem(int commandId, LPCWSTR label, IUIImage* image)
394 : m_RefCount(0)
395 , m_Label(label)
396 , m_CommandId(commandId)
397 , m_Image(image)
401 STDMETHOD(QueryInterface)(REFIID riid, void** ppvObject)
403 if (riid == __uuidof(IUnknown))
405 AddRef();
406 *ppvObject = static_cast<IUnknown*>(this);
407 return S_OK;
409 else if (riid == __uuidof(IUISimplePropertySet))
411 AddRef();
412 *ppvObject = static_cast<IUISimplePropertySet*>(this);
413 return S_OK;
415 return E_NOINTERFACE;
418 STDMETHOD_(ULONG, AddRef)(void)
420 return InterlockedIncrement(&m_RefCount);
423 STDMETHOD_(ULONG, Release)(void)
425 if (InterlockedDecrement(&m_RefCount) == 0)
427 delete this;
428 return 0;
430 return m_RefCount;
433 STDMETHOD(GetValue)(REFPROPERTYKEY key, PROPVARIANT* value)
435 if (key == UI_PKEY_Label)
436 return UIInitPropertyFromString(key, m_Label, value);
437 else if (key == UI_PKEY_CommandId)
438 return UIInitPropertyFromUInt32(UI_PKEY_CommandId, m_CommandId, value);
439 else if (key == UI_PKEY_ItemImage)
440 return UIInitPropertyFromInterface(UI_PKEY_ItemImage, m_Image, value);
441 return E_NOTIMPL;
445 void CNativeRibbonApp::SetItems(UINT cmdId, const std::list<CNativeRibbonDynamicItemInfo>& items)
447 CComPtr<IUICollection> uiCollection = GetUICommandItemsSource(cmdId);
448 if (!uiCollection)
449 return;
451 CComPtr<IUIImageFromBitmap> imageFactory;
452 imageFactory.CoCreateInstance(__uuidof(UIRibbonImageFromBitmapFactory));
454 UINT32 idx = 0;
455 UINT32 count = 0;
456 uiCollection->GetCount(&count);
457 for (const auto & item : items)
459 CComPtr<IUIImage> image;
460 if (imageFactory && item.GetImageId() > 0)
462 HBITMAP hbm = static_cast<HBITMAP>(LoadImage( AfxGetResourceHandle(), MAKEINTRESOURCE(item.GetImageId()), IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION));
463 imageFactory->CreateImage(hbm, UI_OWNERSHIP_TRANSFER, &image);
466 if (idx < count)
467 uiCollection->Replace(idx, new UIDynamicCommandItem(item.GetCommandId(), item.GetLabel(), image));
468 else
469 uiCollection->Add(new UIDynamicCommandItem(item.GetCommandId(), item.GetLabel(), image));
470 idx++;
473 for (; idx < count; idx++)
475 uiCollection->RemoveAt(idx);
477 SetUICommandItemsSource(cmdId, uiCollection);