You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1268 lines
28 KiB
C++

// XTPRibbonGroups.cpp: implementation of the CXTPRibbonGroups class.
//
// This file is a part of the XTREME RIBBON MFC class library.
// (c)1998-2012 Codejock Software, All Rights Reserved.
//
// THIS SOURCE FILE IS THE PROPERTY OF CODEJOCK SOFTWARE AND IS NOT TO BE
// RE-DISTRIBUTED BY ANY MEANS WHATSOEVER WITHOUT THE EXPRESSED WRITTEN
// CONSENT OF CODEJOCK SOFTWARE.
//
// THIS SOURCE CODE CAN ONLY BE USED UNDER THE TERMS AND CONDITIONS OUTLINED
// IN THE XTREME TOOLKIT PRO LICENSE AGREEMENT. CODEJOCK SOFTWARE GRANTS TO
// YOU (ONE SOFTWARE DEVELOPER) THE LIMITED RIGHT TO USE THIS SOFTWARE ON A
// SINGLE COMPUTER.
//
// CONTACT INFORMATION:
// support@codejock.com
// http://www.codejock.com
//
/////////////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "Common/XTPPropExchange.h"
#include "Common/XTPImageManager.h"
#include "Common/XTPSystemHelpers.h"
#include "Common/XTPHookManager.h"
#include "Common/XTPColorManager.h"
#include "TabManager/XTPTabManager.h"
#include "CommandBars/XTPCommandBarsDefines.h"
#include "CommandBars/XTPCommandBar.h"
#include "CommandBars/XTPToolBar.h"
#include "CommandBars/XTPMenuBar.h"
#include "CommandBars/XTPPopupBar.h"
#include "CommandBars/XTPControls.h"
#include "CommandBars/XTPScrollBase.h"
#include "CommandBars/XTPControl.h"
#include "CommandBars/XTPControlButton.h"
#include "CommandBars/XTPControlPopup.h"
#include "CommandBars/XTPControlEdit.h"
#include "CommandBars/XTPControlComboBox.h"
#include "CommandBars/XTPControlGallery.h"
#include "CommandBars/XTPPaintManager.h"
#include "XTPRibbonGroup.h"
#include "XTPRibbonGroups.h"
#include "XTPRibbonPopups.h"
#include "XTPRibbonBar.h"
#include "XTPRibbonPaintManager.h"
#include "XTPRibbonTab.h"
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
CXTPRibbonGroups::CXTPRibbonGroups()
{
m_pParentTab = NULL;
m_nGroupsScrollPos = 0;
}
CXTPRibbonGroups::~CXTPRibbonGroups()
{
RemoveAll();
}
void CXTPRibbonGroups::RemoveAll()
{
for (int nIndex = 0; nIndex < GetCount(); nIndex++)
{
CXTPRibbonGroup* pGroup = GetAt(nIndex);
pGroup->OnGroupRemoved();
pGroup->InternalRelease();
}
m_arrGroups.RemoveAll();
RefreshIndexes();
}
void CXTPRibbonGroups::RefreshIndexes()
{
for (int nIndex = 0; nIndex < GetCount(); nIndex++)
{
CXTPRibbonGroup* pGroup = GetAt(nIndex);
pGroup->m_nIndex = nIndex;
}
}
CXTPRibbonBar* CXTPRibbonGroups::GetRibbonBar() const
{
return m_pParentTab->GetRibbonBar();
}
CXTPRibbonGroup* CXTPRibbonGroups::Add(LPCTSTR lpszCaption, int nId)
{
return InsertAt(GetCount(), lpszCaption, nId);
}
CXTPRibbonGroup* CXTPRibbonGroups::InsertAt(int nIndex, CXTPRibbonGroup* pGroup)
{
pGroup->m_pGroups = this;
pGroup->m_pRibbonBar = m_pParentTab->GetRibbonBar();
pGroup->m_pParent = m_pParentTab->GetParent();
m_arrGroups.InsertAt(nIndex, pGroup);
RefreshIndexes();
pGroup->OnGroupAdded();
return pGroup;
}
CXTPRibbonGroup* CXTPRibbonGroups::InsertAt(int nIndex, LPCTSTR lpszCaption, int nId)
{
CXTPRibbonGroup* pGroup = new CXTPRibbonGroup;
pGroup->SetID(nId);
pGroup->SetCaption(lpszCaption);
InsertAt(nIndex, pGroup);
pGroup->LoadToolBar(nId);
return pGroup;
}
void CXTPRibbonGroups::Remove(CXTPRibbonGroup* pGroup)
{
for (int nIndex = 0; nIndex < GetCount(); nIndex++)
{
if (pGroup == GetAt(nIndex))
{
Remove(nIndex);
return;
}
}
}
void CXTPRibbonGroups::Remove(int nIndex)
{
if ((nIndex >= 0) && (nIndex < GetCount()))
{
CXTPRibbonGroup* pGroup = GetAt(nIndex);
ASSERT(pGroup);
pGroup->OnGroupRemoved();
m_arrGroups.RemoveAt(nIndex);
pGroup->InternalRelease();
RefreshIndexes();
}
}
CXTPRibbonGroup* CXTPRibbonGroups::HitTest(CPoint point) const
{
for (int nIndex = 0; nIndex < GetCount(); nIndex++)
{
CXTPRibbonGroup* pGroup = GetAt(nIndex);
if (pGroup->IsVisible() && pGroup->GetRect().PtInRect(point))
{
return pGroup;
}
}
return NULL;
}
void CXTPRibbonGroups::Copy(CXTPRibbonGroups* pGroups)
{
RemoveAll();
for (int nIndex = 0; nIndex < pGroups->GetCount(); nIndex++)
{
CXTPRibbonGroup* pGroup = pGroups->GetAt(nIndex);
CXTPRibbonGroup* pClone = (CXTPRibbonGroup*)pGroup->GetRuntimeClass()->CreateObject();
InsertAt(nIndex, pClone);
pClone->Copy(pGroup);
pClone->m_pGroups = this;
}
}
//
struct CXTPRibbonGroup::CONTROLINFO
{
CRect rcControl;
CRect rcRow;
CSize szControl;
BOOL bHide;
BOOL bWrap;
BOOL bBeginGroup;
BOOL bWrapGroup;
XTPButtonStyle buttonStyle;
CXTPControl* pControl;
int nTailWidth;
void EnsureButtonSize(CDC* pDC)
{
if (buttonStyle != pControl->GetStyle())
{
buttonStyle = pControl->GetStyle();
szControl = pControl->GetSize(pDC);
}
}
void Attach(CDC* pDC, CXTPControl* p)
{
pControl = p;
rcRow.SetRectEmpty();
szControl = pControl->GetSize(pDC);
rcControl = pControl->GetRect();
bBeginGroup = pControl->GetBeginGroup();
bWrapGroup = bBeginGroup || (pControl->GetFlags() & xtpFlagWrapRow);
buttonStyle = pControl->GetStyle();
bWrap = bHide = FALSE;
nTailWidth = 0;
}
void Detach()
{
pControl->SetHideWrap(bHide);
pControl->SetRowRect(rcRow);
if (!bHide)
pControl->SetRect(rcControl);
pControl->SetWrap(bWrap);
}
};
struct CXTPRibbonGroup::LAYOUTINFO
{
CONTROLINFO* pControls;
int nControlCount;
int nMinWidth;
int nWidth;
BOOL bOldReduced;
};
BOOL CXTPRibbonGroup::OnExtendSize(int nWidthAvail)
{
int nDataCount = m_pLayoutInfo->nControlCount;
CONTROLINFO* pData = m_pLayoutInfo->pControls;
for (int i = nDataCount - 1; i >= 0; i--)
{
if (pData[i].pControl->GetType() == xtpControlGallery &&
((CXTPControlGallery*)pData[i].pControl)->IsResizable() & 1)
{
CXTPControlGallery* pGallery = (CXTPControlGallery*)pData[i].pControl;
int cx = pGallery->GetItems() ? pGallery->GetItems()->GetItemSize().cx : 0;
if (cx > 0 && cx <= nWidthAvail)
{
int nCount = pGallery->GetItems()->GetItemCount();
CRect rcBorders = pGallery->GetBorders();
int nMaxWidth = nCount * cx + rcBorders.left + rcBorders.right;
if (pData[i].szControl.cx + cx <= nMaxWidth)
{
pData[i].szControl.cx = min(nMaxWidth,
pData[i].szControl.cx + int(nWidthAvail / cx) * cx);
return TRUE;
}
}
return FALSE;
}
}
return FALSE;
}
BOOL CXTPRibbonGroup::OnReduceSize(int nLevel, int nWidthAvail)
{
if (m_pLayoutInfo == NULL)
return FALSE;
if (m_pLayoutInfo->nWidth < m_pLayoutInfo->nMinWidth)
{
if (nLevel == 2 && m_pLayoutInfo->nWidth > 16)
{
m_pLayoutInfo->nMinWidth = max(m_pLayoutInfo->nWidth, m_pLayoutInfo->nMinWidth - nWidthAvail);
return TRUE;
}
return FALSE;
}
BOOL bReduced = FALSE;
int nResultHeight = GetRibbonBar()->CalcGroupsHeight() - 2 -
GetRibbonBar()->GetRibbonPaintManager()->GetGroupCaptionHeight() ;
int nButtonSize = GetRibbonBar()->GetButtonSize().cy;
int nControlsPerGroup = int(nResultHeight / nButtonSize);
int nDataCount = m_pLayoutInfo->nControlCount;
CONTROLINFO* pData = m_pLayoutInfo->pControls;
bReduced = FALSE;
int* pButtons = new int[nControlsPerGroup];
if (nLevel == 0 && !m_bControlsGrouping && m_nAllowReduce > nLevel)
{
if (nControlsPerGroup > 1)
{
for (int i = nDataCount - 1; i >= 2; i--)
{
if (pData[i].bWrapGroup)
continue;
int nItems = 0;
for (int j = i; j >= 0; j--)
{
CONTROLINFO* pControl = &pData[j];
if ((nItems == nControlsPerGroup - 1 || !pControl->bWrapGroup)
&& pControl->pControl->m_buttonRibbonStyle == xtpButtonIconAndCaptionBelow
&& pControl->pControl->GetType() != xtpControlGallery)
{
pButtons[nItems] = j;
nItems += 1;
}
else
{
break;
}
if (nItems == nControlsPerGroup)
break;
}
if (nItems == nControlsPerGroup)
{
for (int k = 0; k < nItems; k++)
pData[pButtons[k]].pControl->m_buttonRibbonStyle = xtpButtonIconAndCaption;
bReduced = TRUE;
break;
}
}
}
}
if (nLevel == 1 && !m_bControlsGrouping && m_nAllowReduce > nLevel)
{
if (nControlsPerGroup > 1)
{
for (int i = nDataCount - 1; i >= 2; i--)
{
if (pData[i].bWrapGroup)
continue;
int nItems = 0;
BOOL bFound = FALSE;
int j;
for (j = i; j >= 0; j--)
{
CONTROLINFO* pControl = &pData[j];
if ((nItems == nControlsPerGroup - 1 || !pControl->bWrapGroup)
&& pControl->pControl->GetType() != xtpControlGallery)
{
pButtons[nItems] = j;
nItems += 1;
bFound = bFound || pControl->pControl->m_buttonRibbonStyle == xtpButtonIconAndCaptionBelow;
}
else
{
break;
}
if (nItems == nControlsPerGroup)
break;
}
i = j;
if (nItems == nControlsPerGroup && bFound)
{
for (int k = 0; k < nItems; k++)
pData[pButtons[k]].pControl->m_buttonRibbonStyle = xtpButtonIconAndCaption;
bReduced = TRUE;
break;
}
}
}
}
if (nLevel == 1 && m_bControlsGrouping && m_nRowCount == 2 && m_nAllowReduce > nLevel)
{
m_nRowCount = 3;
bReduced = TRUE;
}
if (nLevel == 2 && !bReduced && !m_bControlsGrouping && m_nAllowReduce > nLevel)
{
if (nControlsPerGroup > 1)
{
for (int i = nDataCount - 1; i >= 2; i--)
{
if (pData[i].bWrapGroup)
continue;
int nItems = 0;
int nLeft = 0;
for (int j = i; j >= 0; j--)
{
CONTROLINFO* pControl = &pData[j];
int nOffset = pControl->rcControl.left;
if (nItems != 0 && (nOffset != nLeft))
break;
if ((nItems == nControlsPerGroup - 1 || !pControl->bWrapGroup)
&& pControl->pControl->m_buttonRibbonStyle == xtpButtonIconAndCaption
&& pControl->pControl->GetType() != xtpControlGallery)
{
pButtons[nItems] = j;
nItems += 1;
nLeft = nOffset;
}
else
{
break;
}
if (nItems == nControlsPerGroup)
break;
}
if (nItems == nControlsPerGroup && GetCount() > nControlsPerGroup)
{
for (int k = 0; k < nItems; k++)
pData[pButtons[k]].pControl->m_buttonRibbonStyle = xtpButtonIcon;
bReduced = TRUE;
break;
}
}
}
}
if (nLevel == 2 && !bReduced && !m_bControlsGrouping && m_nAllowReduce > nLevel)
{
for (int i = nDataCount - 1; i >= 0; i--)
{
if (pData[i].pControl->GetType() == xtpControlGallery &&
pData[i].pControl->m_buttonRibbonStyle != xtpButtonIconAndCaptionBelow)
{
pData[i].pControl->m_buttonRibbonStyle = xtpButtonIconAndCaptionBelow;
bReduced = TRUE;
break;
}
}
}
delete[] pButtons;
if (nLevel == 3)
{
if (nDataCount > 1 && !m_bReduced && m_nAllowReduce > nLevel)
{
m_bReduced = TRUE;
for (int j = 0; j < nDataCount; j++)
{
CONTROLINFO* pControl = &pData[j];
pControl->bHide = TRUE;
}
bReduced = TRUE;
}
}
return bReduced;
}
void CXTPRibbonGroup::OnBeforeCalcSize(CDC* pDC)
{
CSize szLargeIcon = GetRibbonBar()->GetLargeIconSize(FALSE);
m_pLayoutInfo = new LAYOUTINFO;
m_pLayoutInfo->pControls = NULL;
m_pLayoutInfo->nMinWidth = GetMinimumWidth(pDC);
m_pLayoutInfo->bOldReduced = m_bReduced;
int nVisibleCount = 0;
int j;
for (j = 0; j < GetCount(); j++)
{
CXTPControl* pControl = GetAt(j);
if (pControl->IsVisible(xtpHideWrap))
{
nVisibleCount++;
}
}
m_pLayoutInfo->nControlCount = nVisibleCount;
if (nVisibleCount == 0)
return;
m_pLayoutInfo->pControls = new CONTROLINFO[nVisibleCount];
int k = 0;
for (j = 0; j < GetCount(); j++)
{
CXTPControl* pControl = GetAt(j);
if (pControl->IsVisible(xtpHideWrap))
{
pControl->m_buttonRibbonStyle = xtpButtonAutomatic;
if (!m_bControlsGrouping && pControl->GetStyle() == xtpButtonAutomatic && pControl->GetType() != xtpControlGallery)
{
BOOL bDrawImage = pControl->GetIconId() > 0 ?
pControl->GetImageManager()->IsPrimaryImageExists(pControl->GetIconId(), szLargeIcon.cx) != NULL: FALSE;
pControl->m_buttonRibbonStyle = bDrawImage? xtpButtonIconAndCaptionBelow : xtpButtonIconAndCaption;
}
m_pLayoutInfo->pControls[k].Attach(pDC, pControl);
k++;
}
}
ASSERT(k == nVisibleCount);
m_bReduced = FALSE;
m_nRowCount = 2;
}
void CXTPRibbonGroup::ArrangeEditCaption()
{
CArray<CXTPControl*, CXTPControl*> arrColumn;
int i = 0, j = 0, k;
while (i < m_pLayoutInfo->nControlCount)
{
arrColumn.RemoveAll();
for (j = i; j < m_pLayoutInfo->nControlCount; j++)
{
if (m_pLayoutInfo->pControls[j].rcControl.left != m_pLayoutInfo->pControls[i].rcControl.left ||
m_pLayoutInfo->pControls[j].rcControl.right != m_pLayoutInfo->pControls[i].rcControl.right)
{
break;
}
if (m_pLayoutInfo->pControls[j].pControl->GetType() == xtpControlEdit ||
m_pLayoutInfo->pControls[j].pControl->GetType() == xtpControlComboBox)
{
arrColumn.Add(m_pLayoutInfo->pControls[j].pControl);
}
}
if (arrColumn.GetSize() > 1)
{
int nLabelWidth = 0;
for (k = 0; k < (int)arrColumn.GetSize(); k++)
{
CXTPControl* pControl = arrColumn[k];
if (pControl->GetType() == xtpControlEdit)
{
nLabelWidth = max(nLabelWidth, ((CXTPControlEdit*)pControl)->GetLabelWidth());
}
else
{
nLabelWidth = max(nLabelWidth, ((CXTPControlComboBox*)pControl)->GetLabelWidth());
}
}
for (k = 0; k < (int)arrColumn.GetSize(); k++)
{
CXTPControl* pControl = arrColumn[k];
if (pControl->GetType() == xtpControlEdit)
{
((CXTPControlEdit*)pControl)->SetLabelWidth(nLabelWidth);
}
else
{
((CXTPControlComboBox*)pControl)->SetLabelWidth(nLabelWidth);
}
}
}
i = j;
}
}
void CXTPRibbonGroup::OnAfterCalcSize()
{
if (!m_pLayoutInfo)
return;
if (!m_bReduced && m_bAutoArrangeEditCaption && !m_bControlsGrouping)
ArrangeEditCaption();
for (int i = 0; i < m_pLayoutInfo->nControlCount; i++)
{
if (i == 0)
m_pLayoutInfo->pControls[i].bWrap = TRUE;
m_pLayoutInfo->pControls[i].Detach();
}
if (m_pLayoutInfo->bOldReduced && !m_bReduced)
{
GetRibbonBar()->m_bGroupReducedChanged = TRUE;
}
delete[] m_pLayoutInfo->pControls;
delete m_pLayoutInfo;
}
int CXTPRibbonGroup::_WrapSpecialDynamicSize(int nWidth, BOOL bIncludeTail)
{
int nDataCount = m_pLayoutInfo->nControlCount;
CONTROLINFO* pData = m_pLayoutInfo->pControls;
int nWraps = 0, x = 0;
for (int i = 0; i < nDataCount; i++)
{
CONTROLINFO* pControl = &pData[i];
pControl->bWrap = FALSE;
CSize szControl = pControl->szControl;
BOOL bBeginGroup = pControl->bBeginGroup && i > 0;
BOOL bWrapGroup = pControl->bWrapGroup && i > 0;
if (bWrapGroup && (pControl->pControl->GetFlags() & xtpFlagWrapRow))
{
x = szControl.cx;
pControl->bWrap = TRUE;
nWraps++;
continue;
}
else if (bWrapGroup)
{
if ((bIncludeTail && (x + pControl->nTailWidth >= nWidth))
|| (!bIncludeTail && nWraps == 0 && (x + pControl->nTailWidth >= nWidth)))
{
x = szControl.cx;
pControl->bWrap = TRUE;
nWraps++;
continue;
}
}
if (bBeginGroup)
x += 3;
x += szControl.cx;
}
return nWraps;
}
int CXTPRibbonGroup::_GetSizeSpecialDynamicSize()
{
int nTotalWidth = 0, x = 0, y = 0, nRowHeight = 0;
int nDataCount = m_pLayoutInfo->nControlCount;
CONTROLINFO* pData = m_pLayoutInfo->pControls;
for (int i = 0; i < nDataCount; i++)
{
CONTROLINFO* pControl = &pData[i];
CSize szControl = pControl->szControl;
if (pControl->bWrap)
{
x = 0;
y += nRowHeight;
}
else
{
BOOL bBeginGroup = pControl->bBeginGroup && i > 0;
if (bBeginGroup)
x += 3;
}
pControl->rcControl.SetRect(2 + x, y, 2 + x + szControl.cx, y + szControl.cy);
x += szControl.cx;
nRowHeight = max(nRowHeight, szControl.cy);
nTotalWidth = max(nTotalWidth, x);
}
return nTotalWidth + 4;
}
BOOL CXTPRibbonGroup::_FindBestWrapSpecialDynamicSize()
{
int nMax = _GetSizeSpecialDynamicSize();
int nMin = 0, nMid = 0;
int nCurrent = _WrapSpecialDynamicSize(nMin, TRUE);
int nTarget = 2;
if (nCurrent < nTarget)
return FALSE;
if (nCurrent == nTarget)
return TRUE;
while (nMin < nMax)
{
nMid = (nMin + nMax) / 2;
nCurrent = _WrapSpecialDynamicSize(nMid, TRUE);
if (nCurrent <= nTarget)
{
nMax = nMid;
}
else
{
if (nMin == nMid)
{
_WrapSpecialDynamicSize(nMax, TRUE);
break;
}
nMin = nMid;
}
}
return TRUE;
}
int CXTPRibbonGroup::_CalcSpecialDynamicSize(CDC* /*pDC*/)
{
int nResultHeight = GetRibbonBar()->CalcGroupsHeight() - 9 -
GetRibbonBar()->GetRibbonPaintManager()->GetGroupCaptionHeight();
int i;
int nDataCount = m_pLayoutInfo->nControlCount;
CONTROLINFO* pData = m_pLayoutInfo->pControls;
int nTailWidth = 0;
for (i = nDataCount - 1; i >= 0; i--)
{
CONTROLINFO* pControl = &pData[i];
CSize szControl = pControl->szControl;
nTailWidth += szControl.cx;
pControl->nTailWidth = nTailWidth;
if (pControl->bWrapGroup)
{
nTailWidth = 0;
}
}
int nBaseHeight = GetRibbonBar()->GetRibbonPaintManager()->GetEditHeight();
int nRowCount = _WrapSpecialDynamicSize(32000, FALSE) + 1;
int nTotalWidth = 0;
if (nRowCount == 1)
{
nRowCount = 3;
nTotalWidth = _GetSizeSpecialDynamicSize();
BOOL bAllow3Row = nResultHeight >= nBaseHeight * 3;
BOOL bAllow2Row = nResultHeight >= nBaseHeight * 2 ;
if (!bAllow2Row)
{
_WrapSpecialDynamicSize(32000, FALSE);
nRowCount = 1;
}
else
{
if (!(bAllow3Row && m_nRowCount == 3 && _FindBestWrapSpecialDynamicSize()))
{
nRowCount = _WrapSpecialDynamicSize(nTotalWidth / 2, FALSE) + 1;
}
}
}
nTotalWidth = _GetSizeSpecialDynamicSize();
int nOffset = (nResultHeight + 1 - nBaseHeight * nRowCount) / (nRowCount + 1);
int nTotalOffset = nOffset;
int nRow = 0;
for (i = 0; i < nDataCount; i++)
{
CONTROLINFO* pControl = &pData[i];
if (i > 0 && pControl->bWrap)
{
nOffset = (nResultHeight - nBaseHeight * nRowCount - nTotalOffset) / (nRowCount - nRow);
nTotalOffset += nOffset;
nRow++;
}
pControl->rcControl.OffsetRect(0, nTotalOffset);
}
m_pLayoutInfo->nWidth = nTotalWidth;
return max(m_pLayoutInfo->nWidth, m_pLayoutInfo->nMinWidth);
}
int CXTPRibbonGroup::OnCalcDynamicSize(CDC* pDC)
{
if (m_bReduced)
{
CSize szControl = GetControlGroupPopup()->GetSize(pDC);
return m_pLayoutInfo->nWidth = szControl.cx - 5;
}
if (m_bControlsGrouping)
return _CalcSpecialDynamicSize(pDC);
int nResultHeight = GetRibbonBar()->CalcGroupsHeight() - 9 -
GetRibbonBar()->GetRibbonPaintManager()->GetGroupCaptionHeight() ;
CSize sizeResult(0, nResultHeight);
int dyPrev = 0, dxPrev = 0, x = 2;
int nDataCount = m_pLayoutInfo->nControlCount;
CONTROLINFO* pData = m_pLayoutInfo->pControls;
for (int i = 0; i < nDataCount; i++)
{
CONTROLINFO* pControl = &pData[i];
BOOL bFullRow = pControl->pControl->GetStyle() == xtpButtonIconAndCaptionBelow;
pControl->EnsureButtonSize(pDC);
CSize szControl = pControl->szControl;
int dx = szControl.cx;
int dy = szControl.cy;
BOOL bBeginGroup = pControl->bBeginGroup && i > 0;
BOOL bWrapGroup = pControl->bWrapGroup && i > 0;
if (bBeginGroup)
x += 6;
if (i > 0 && !bWrapGroup && !bFullRow && dyPrev + dy <= nResultHeight)
{
pControl->rcControl.SetRect(x, dyPrev, x + dx, dyPrev + dy);
dxPrev = max(dxPrev, dx);
}
else
{
x += dxPrev;
pControl->rcControl.SetRect(x, 0, x + dx, dy);
dxPrev = dx;
}
sizeResult.cx = max(x + dx, sizeResult.cx);
dyPrev = pControl->rcControl.bottom;
}
m_pLayoutInfo->nWidth = sizeResult.cx + 2;
return max(m_pLayoutInfo->nWidth, m_pLayoutInfo->nMinWidth);
}
void CXTPRibbonGroups::_ReduceSmartLayoutToolBar(CDC* pDC, int* pWidth, int nWidth)
{
int nResult = _CalcSmartLayoutToolBar(pWidth);
if (nResult <= nWidth)
{
if (nResult == nWidth)
return;
for (int i = GetCount() - 1; i >= 0; i--)
{
CXTPRibbonGroup* pGroup = GetAt(i);
if (!pGroup->IsVisible())
continue;
if (pGroup->OnExtendSize(nWidth - nResult))
{
pWidth[i] = pGroup->OnCalcDynamicSize(pDC);
break;
}
}
return;
}
BOOL bReduced = FALSE;
do
{
bReduced = FALSE;
for (int nLevel = 0; nLevel < 4; nLevel++)
{
for (int i = GetCount() - 1; i >= 0; i--)
{
CXTPRibbonGroup* pGroup = GetAt(i);
if (!pGroup->IsVisible())
continue;
if (pGroup->OnReduceSize(nLevel, nResult - nWidth))
{
int nGroupWidth = pGroup->OnCalcDynamicSize(pDC);
nResult -= (pWidth[i] - nGroupWidth);
pWidth[i] = nGroupWidth;
bReduced = TRUE;
break;
}
}
if (bReduced)
break;
}
if (bReduced && nResult <= nWidth)
{
return;
}
}
while (bReduced);
}
int CXTPRibbonGroups::_CalcSmartLayoutToolBar(int* pWidth)
{
int nWidth = 0;
for (int i = 0; i < GetCount(); i++)
{
nWidth += pWidth[i];
if (i != GetCount() - 1 && pWidth[i] != 0)
{
nWidth += 7;
}
}
return nWidth;
}
void CXTPRibbonGroup::CenterColumn(int nFirstItem, int nLastItem, int nGroupHeight)
{
int nHeight = 0;
int i;
for (i = nFirstItem; i <= nLastItem; i++)
{
CONTROLINFO* pControl = &m_pLayoutInfo->pControls[i];
if (pControl->bHide)
continue;
nHeight +=pControl->rcControl.Height();
}
if (nHeight >= nGroupHeight)
return;
int nItems = nLastItem - nFirstItem + 1;
int nOffset = (nGroupHeight - nHeight) / (nItems + 1);
for (i = nFirstItem; i <= nLastItem; i++)
{
CONTROLINFO* pControl = &m_pLayoutInfo->pControls[i];
if (pControl->bHide)
continue;
pControl->rcControl.OffsetRect(0, nOffset);
nOffset += nOffset;
}
}
void CXTPRibbonGroup::OnAdjustBorders(int nWidth, CRect rcBorder)
{
CXTPRibbonPaintManager* pPaintManager = GetRibbonBar()->GetRibbonPaintManager();
int nGroupCaptionHeigh = pPaintManager->GetGroupCaptionHeight();
int nGroupHeight = GetRibbonBar()->CalcGroupsHeight();
int nGroupClientHeight = nGroupHeight - 2 - 3 - 2;
int i;
BOOL bFirstItem = TRUE;
int nFirstItem = 0;
int nColumn = 0;
BOOL bCenterItems = m_bControlsCentering;
if (IsControlsGrouping())
bCenterItems = FALSE;
int nControlCount = m_pLayoutInfo ? m_pLayoutInfo->nControlCount : 0;
int nLeftOffset = 2;
if (m_pLayoutInfo && m_bControlsCentering && m_pLayoutInfo->nWidth < m_pLayoutInfo->nMinWidth && nWidth == m_pLayoutInfo->nMinWidth)
nLeftOffset = 2 + (m_pLayoutInfo->nMinWidth - m_pLayoutInfo->nWidth) / 2;
for (i = 0; i < nControlCount; i++)
{
CONTROLINFO* pControl = &m_pLayoutInfo->pControls[i];
if (pControl->bHide)
continue;
pControl->rcControl.OffsetRect(rcBorder.left + nLeftOffset, rcBorder.top + 2);
pControl->rcRow = CRect(rcBorder.left, rcBorder.top,
rcBorder.left + nWidth, rcBorder.top + nGroupClientHeight - nGroupCaptionHeigh);
if (bCenterItems && !bFirstItem)
{
if (nColumn != pControl->rcControl.left)
{
CenterColumn(nFirstItem, i - 1, nGroupClientHeight - nGroupCaptionHeigh - 3);
nColumn = pControl->rcControl.left;
nFirstItem = i;
}
}
else
{
bFirstItem = FALSE;
nColumn = pControl->rcControl.left;
}
}
if (bCenterItems && nControlCount > 0) CenterColumn(nFirstItem, m_pLayoutInfo->nControlCount - 1, nGroupClientHeight - nGroupCaptionHeigh - 3);
int nBeginGroup = rcBorder.left;
int nEndGroup = nBeginGroup + nWidth + 5;
SetRect(CRect(nBeginGroup, rcBorder.top, nEndGroup, rcBorder.top + nGroupClientHeight));
}
void CXTPRibbonGroups::CalcDynamicSize(CDC* pDC, int nLength, DWORD /*dwMode*/, const CRect& rcBorder)
{
CXTPRibbonScrollableBar* pScrollableBar = GetScrollableBar(m_pParentTab->GetParent());
int nCount = GetCount();
if (nCount == 0)
{
pScrollableBar->EnableGroupsScroll(FALSE, FALSE);
return;
}
int* pData = new int[nCount];
int i;
for (i = 0; i < nCount; i++)
{
CXTPRibbonGroup* pGroup = GetAt(i);
if (pGroup->IsVisible())
{
pGroup->OnBeforeCalcSize(pDC);
}
}
for (i = 0; i < nCount; i++)
{
CXTPRibbonGroup* pGroup = GetAt(i);
pData[i] = pGroup->IsVisible() ? pGroup->OnCalcDynamicSize(pDC) : 0;
}
int nGroupsLength = nLength - rcBorder.right - rcBorder.left;
_ReduceSmartLayoutToolBar(pDC, pData, nGroupsLength);
CRect rcBorders = rcBorder;
const int nGroupSpacing = GetRibbonBar()->GetRibbonPaintManager()->m_nGroupSpacing;
int nTotalWidth = -7;
for (i = 0; i < nCount; i++)
{
CXTPRibbonGroup* pGroup = GetAt(i);
if (pGroup->IsVisible())
{
nTotalWidth += pData[i] + nGroupSpacing + 5;
}
}
int nScrollPos = pScrollableBar->m_nGroupsScrollPos;
if (nTotalWidth > nGroupsLength)
{
if (nScrollPos > nTotalWidth - nGroupsLength)
{
nScrollPos = nTotalWidth - nGroupsLength;
}
}
else
{
nScrollPos = 0;
}
if (nScrollPos < 0) nScrollPos = 0;
m_nGroupsScrollPos = nScrollPos;
pScrollableBar->EnableGroupsScroll(nScrollPos > 0, nTotalWidth - nGroupsLength - nScrollPos > 0);
rcBorders.left -= nScrollPos;
for (i = 0; i < nCount; i++)
{
CXTPRibbonGroup* pGroup = GetAt(i);
if (pGroup->IsVisible())
{
pGroup->OnAdjustBorders(pData[i], rcBorders);
rcBorders.left += pData[i] + nGroupSpacing + 5;
}
}
for (i = 0; i < nCount; i++)
{
CXTPRibbonGroup* pGroup = GetAt(i);
if (pGroup->IsVisible())
{
pGroup->OnAfterCalcSize();
}
}
delete[] pData;
}
void CXTPRibbonGroup::DoPropExchange(CXTPPropExchange* pPX)
{
PX_Int(pPX, _T("Id"), m_nId, 0);
PX_Int(pPX, _T("IconId"), m_nIconId, 0);
PX_Bool(pPX, _T("ShowOptionButton"), m_bShowOptionButton, FALSE);
PX_String(pPX, _T("Caption"), m_strCaption, _T(""));
PX_Bool(pPX, _T("ControlsGrouping"), m_bControlsGrouping, FALSE);
PX_Bool(pPX, _T("ControlsCentering"), m_bControlsCentering, FALSE);
PX_Bool(pPX, _T("Visible"), m_bVisible, TRUE);
if (pPX->IsStoring())
{
CXTPPropExchangeSection secControls(pPX->GetSection(_T("Controls")));
long nCount = 0;
int i;
for (i = 0; i < m_arrControls.GetSize(); i++)
{
CXTPControl* pControl = GetAt(i);
if (!pControl->IsTemporary()) nCount++;
}
CXTPPropExchangeEnumeratorPtr pEnumerator(secControls->GetEnumerator(_T("Control")));
POSITION posEnum = pEnumerator->GetPosition(nCount, FALSE);
for (i = 0; i < (int)m_arrControls.GetSize(); i++)
{
CXTPControl* pControl = GetAt(i);
if (!pControl->IsTemporary())
{
CXTPPropExchangeSection secItem(pEnumerator->GetNext(posEnum));
PX_Object(&secItem, pControl, RUNTIME_CLASS(CXTPControl));
}
}
}
else
{
m_pGroups = (CXTPRibbonGroups*)pPX->m_pOwner;
m_pParent = m_pRibbonBar = m_pGroups->GetRibbonBar();
OnGroupAdded();
CXTPPropExchangeSection secControls(pPX->GetSection(_T("Controls")));
CXTPPropExchangeEnumeratorPtr pEnumerator(secControls->GetEnumerator(_T("Control")));
POSITION posEnum = pEnumerator->GetPosition(0, FALSE);
RemoveAll();
while (posEnum)
{
CXTPPropExchangeSection secItem(pEnumerator->GetNext(posEnum));
CXTPControl* pControl = NULL;
PX_Object(&secItem, pControl, RUNTIME_CLASS(CXTPControl));
if (!pControl)
AfxThrowArchiveException(CArchiveException::badClass);
pControl->m_pRibbonGroup = this;
pControl->InternalAddRef();
m_pRibbonBar->GetControls()->InsertAt(pControl, m_pControlGroupOption->GetIndex());
m_arrControls.Add(pControl);
}
}
CXTPPropExchangeSection secControlGroupOption(pPX->GetSection(_T("ControlGroupOption")));
m_pControlGroupOption->DoPropExchange(&secControlGroupOption);
CXTPPropExchangeSection secControlGroupPopup(pPX->GetSection(_T("ControlGroupPopup")));
m_pControlGroupPopup->DoPropExchange(&secControlGroupPopup);
}
void CXTPRibbonGroups::DoPropExchange(CXTPPropExchange* pPX)
{
if (pPX->IsStoring())
{
long nCount = GetCount();
int i;
CXTPPropExchangeEnumeratorPtr pEnumerator(pPX->GetEnumerator(_T("Group")));
POSITION posEnum = pEnumerator->GetPosition(nCount, FALSE);
for (i = 0; i < nCount; i++)
{
CXTPRibbonGroup* pGroup = GetAt(i);
CXTPPropExchangeSection secItem(pEnumerator->GetNext(posEnum));
PX_Object(&secItem, pGroup, RUNTIME_CLASS(CXTPRibbonGroup));
}
}
else
{
CXTPPropExchangeEnumeratorPtr pEnumerator(pPX->GetEnumerator(_T("Group")));
POSITION posEnum = pEnumerator->GetPosition(0, FALSE);
RemoveAll();
while (posEnum)
{
CXTPPropExchangeSection secItem(pEnumerator->GetNext(posEnum));
secItem->m_pOwner = this;
CXTPRibbonGroup* pGroup = NULL;
PX_Object(&secItem, pGroup, RUNTIME_CLASS(CXTPRibbonGroup));
if (!pGroup)
AfxThrowArchiveException(CArchiveException::badClass);
m_arrGroups.Add(pGroup);
RefreshIndexes();
}
}
}