// MmRibbonBar.h
/// /// \enum eSearchPosition /// enum eSearchPosition { eSearchPositionTabControl = 0, ///< Next to the tab control, similar to Office 2016 products. eSearchPositionTitleBar, ///< In the frame hook title bar, similar to Office 365 (late 2019). eSearchPositionDefault = eSearchPositionTabControl };
#define SEARCH_MINIMUM_WIDTH XPT_DPI_X(40) #define SEARCH_MAXIMUM_WIDTH XTP_DPI_X(220) #define SEARCH_HEIGHT XTP_DPI_Y(22)
...
// MmRibbonBar.cpp
CSize CMmRibbonBar::CalcDockingLayout(int nLength, DWORD dwMode, int nWidth /*= 0*/) { CXTPControl *pControlSearch = NULL; if (dwMode & LM_COMMIT) { pControlSearch = m_pControls->FindControl(xtpControlEdit, ID_COMMAND_SEARCH, TRUE, FALSE); if (pControlSearch) { if (m_searchPosition == eSearchPositionTabControl) { pControlSearch->SetVisible(TRUE); // Minimum width and padding. pControlSearch->SetWidth(SEARCH_MINIMUM_WIDTH + XTP_DPI_X(16)); } else { // Hide before base calc docking layout to avoid this control effecting the size. pControlSearch->SetVisible(FALSE); } } }
const CSize sz = CXTPRibbonBar::CalcDockingLayout(nLength, dwMode, nWidth);
if (dwMode & LM_COMMIT) { if (pControlSearch) { // Left align the left-most right aligned edit control to the last visible tab item. CRect rcSearch = GetSearchControlRect(pControlSearch);
if (IsBackstageViewVisible()) { // Hide when backstage view is active. pControlSearch->SetVisible(FALSE); } else if (m_searchPosition == eSearchPositionTabControl) { ASSERT(pControlSearch->IsVisible()); pControlSearch->SetWidth(rcSearch.Width()); pControlSearch->SetRect(rcSearch);
if (m_pControlTab && m_rcTabControl.right > rcSearch.left) { // Resize tab control. // Don't want overlap between the edit control and the tab control as it messes with hit testing. m_rcTabControl.right = rcSearch.left; m_pControlTab->SetRect(m_rcTabControl); } } else { // If there is not enough room, hide the control. if (rcSearch.Width() >= SEARCH_MINIMUM_WIDTH) { pControlSearch->SetRect(rcSearch); pControlSearch->SetVisible(TRUE); } } } }
return sz; } CRect CMmRibbonBar::GetSearchControlRect(CXTPControl *pControlSearch) const { using std::min; using std::max;
CRect rcControl;
switch (m_searchPosition) { case eSearchPositionTabControl: { // Get last visible tab item. const CXTPTabManagerItem *pLastTabItem = NULL; for (int i = m_pControlTab->GetItemCount() - 1; i >= 0; --i) { const CXTPTabManagerItem *pTabItem = m_pControlTab->GetItem(i); if (pTabItem->IsVisible()) { pLastTabItem = pTabItem; break; } }
// Get next visible ribbon background control to the right of this control. CXTPControl *pRHSControl = NULL; for (int i = pControlSearch->GetIndex() + 1; i < GetControlCount(); ++i) { CXTPControl *pControl = GetControl(i); if (pControl && pControl->IsVisible() && pControl->GetFlags() & (xtpFlagRightAlign | xtpFlagRibbonTabBackground) && pControl->GetID() != ID_COMMAND_SEARCH) { pRHSControl = pControl; break; } }
if (pLastTabItem) { const CRect rcLastTab = pLastTabItem->GetRect();
CRect rcClient; GetClientRect(&rcClient);
int nLeft = rcLastTab.right + XTP_DPI_X(8); int nTop = rcLastTab.top; int nRight = rcClient.right - XTP_DPI_X(8); if (pRHSControl) nRight = pRHSControl->GetRect().left - XTP_DPI_X(8); int nBottom = rcLastTab.bottom - XTP_DPI_Y(2);
int nSearchMinWidth = SEARCH_MINIMUM_WIDTH; int nSearchMaxWidth = SEARCH_MAXIMUM_WIDTH;
int nSearchWidth = max(nSearchMinWidth, min(nSearchMaxWidth, nRight - nLeft)); int nSearchHeight = SEARCH_HEIGHT;
// Left align the left-most right aligned edit control to the last visible tab item. rcControl = CRect(nLeft, nTop + (nBottom - nTop) / 2 - nSearchHeight / 2, nLeft + nSearchWidth, nTop + (nBottom - nTop) / 2 + nSearchHeight / 2); } } break; case eSearchPositionTitleBar: { // Get frame hook caption button. CXTPControl *pMinimize = m_pControls->FindControl(SC_MINIMIZE);
// Get last visible tab item. const CXTPRibbonTabContextHeader *pFirstContextHeader = NULL; const CXTPRibbonTabContextHeader *pLastContextHeader = NULL; for (int i = m_pControlTab->GetItemCount() - 1; i >= 0; --i) { CXTPRibbonTab *pTab = DYNAMIC_DOWNCAST(CXTPRibbonTab, m_pControlTab->GetItem(i)); if (pTab && pTab->IsVisible()) { CXTPRibbonTabContextHeader *pContextHeader = pTab->GetContextHeader(); if (pContextHeader) { if (!pLastContextHeader) pLastContextHeader = pContextHeader; pFirstContextHeader = pContextHeader; } } }
if (pMinimize) { CRect rcMinimize = pMinimize->GetRect(); CRect rcCaption = m_rcCaptionText;
int nMaxSearchWidth = SEARCH_MAXIMUM_WIDTH;
int nTop = rcMinimize.top + XTP_DPI_Y(4); int nBottom = rcMinimize.bottom - XTP_DPI_Y(4); int nLeft, nRight; if (pFirstContextHeader && pLastContextHeader) { // pFirstContextHeader can be equal to pLastContextHeader if only a single context is up. CRect rcFirstContextTab = pFirstContextHeader->m_rcRect; CRect rcLastContextTab = pLastContextHeader->m_rcRect;
// Left side of context titles. int nLeftLeft = rcCaption.right + XTP_DPI_X(8); int nLeftRight = rcFirstContextTab.left - XTP_DPI_X(8);
// Right side of context titles (preferred). int nRightLeft = std::max(rcCaption.right, rcLastContextTab.right) + XTP_DPI_X(8); int nRightRight = rcMinimize.left - XTP_DPI_X(8);
if (nLeftRight - nLeftLeft > nRightRight - nRightLeft && nRightRight - nRightLeft < nMaxSearchWidth) // Prefer right if it can fit max width. { nLeft = nLeftLeft; nRight = nLeftRight; } else { nLeft = nRightLeft; nRight = nRightRight; } } else { nLeft = rcCaption.right + XTP_DPI_X(8); nRight = rcMinimize.left - XTP_DPI_X(8); }
int nSearchWidth = min(nMaxSearchWidth, nRight - nLeft); int nSearchHeight = SEARCH_HEIGHT;
// Right align to the left-most caption button (minimize button). rcControl = CRect(nLeft + (nRight - nLeft) / 2 - nSearchWidth / 2, nTop + (nBottom - nTop) / 2 - nSearchHeight / 2, nLeft + (nRight - nLeft) / 2 + nSearchWidth / 2, nTop + (nBottom - nTop) / 2 + nSearchHeight / 2); } } break; default: ASSERT(0); }
return rcControl; }
|