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.

1782 lines
42 KiB
C++

// XTPControls.cpp : implementation of the CXTPControls class.
//
// This file is a part of the XTREME COMMANDBARS 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 "Resource.h"
#include "Common/XTPImageManager.h"
#include "Common/XTPResourceManager.h"
#include "Common/XTPSystemHelpers.h"
#include "Common/XTPHookManager.h"
#include "Common/XTPColorManager.h"
#include "Common/XTPDrawHelpers.h"
#include "XTPCommandBarsDefines.h"
#include "XTPControls.h"
#include "XTPCommandBar.h"
#include "XTPPopupBar.h"
#include "XTPControl.h"
#include "XTPControlButton.h"
#include "XTPControlPopup.h"
#include "XTPControlEdit.h"
#include "XTPControlComboBox.h"
#include "XTPControlCustom.h"
#include "XTPScrollBase.h"
#include "XTPControlGallery.h"
#include "XTPControlExt.h"
#include "XTPCommandBars.h"
#include "XTPPaintManager.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
/////////////////////////////////////////////////////////////////////////////
// CCommandBarControls
IMPLEMENT_DYNCREATE(CXTPControls, CCmdTarget)
IMPLEMENT_DYNCREATE(CXTPOriginalControls, CXTPControls)
CXTPControls::CXTPControls()
{
EnableAutomation();
m_pParent = 0;
m_pCommandBars = 0;
m_pOriginalControls = 0;
m_bOriginalControls = FALSE;
}
CXTPControls::~CXTPControls()
{
RemoveAll();
CMDTARGET_RELEASE(m_pOriginalControls);
}
CXTPOriginalControls::CXTPOriginalControls()
{
m_bOriginalControls = TRUE;
}
CXTPCommandBars* CXTPControls::GetCommandBars() const
{
return m_pParent ? m_pParent->GetCommandBars() : m_pCommandBars;
}
void CXTPControls::SetCommandBars(CXTPCommandBars* pCommandBars)
{
m_pCommandBars = pCommandBars;
}
void CXTPControls::RefreshIndexes()
{
for (int nIndex = 0; nIndex < GetCount(); nIndex++)
{
CXTPControl* pControl = GetAt(nIndex);
pControl->m_nIndex = nIndex;
pControl->m_pControls = this;
pControl->SetParent(m_pParent);
}
if (m_pParent)
{
m_pParent->OnControlsChanged();
}
}
void CXTPControls::SetParent(CXTPCommandBar* pParent)
{
m_pParent = pParent;
if (GetCount() > 0) RefreshIndexes();
}
CXTPControl* CXTPControls::AddMenuItem(CMenu* pMenu, int nIndex)
{
CMenu* pPopupMenu = pMenu->GetSubMenu(nIndex);
CXTPControl* pControl = NULL;
UINT nID = pMenu->GetMenuItemID(nIndex);
BOOL bDefaultItem = (int)::GetMenuDefaultItem(pMenu->m_hMenu, TRUE, GMDI_USEDISABLED) == nIndex;
if (nID == AFX_IDM_FIRST_MDICHILD)
return NULL;
CString strCaption;
XTPResourceManager()->GetMenuLocaleString(pMenu, nIndex, strCaption, MF_BYPOSITION);
if (pPopupMenu)
{
int iPos = strCaption.Find(_T('\t'));
if (pPopupMenu && iPos > 0)
{
nID = _ttoi(strCaption.Mid(iPos + 1));
if (nID > 0) strCaption.ReleaseBuffer(iPos);
}
}
CWnd* pSite = m_pCommandBars ? m_pCommandBars->GetSite() :
m_pParent ? m_pParent->GetOwnerSite() : NULL;
CXTPCommandBars* pCommandBars = GetCommandBars();
XTPControlType controlType = pPopupMenu ? xtpControlPopup : xtpControlButton;
XTPButtonStyle buttonStyle = xtpButtonAutomatic;
XTP_COMMANDBARS_CREATECONTROL cs;
if (pSite)
{
cs.nID = nID;
cs.pControl = NULL;
cs.bToolBar = FALSE;
cs.pCommandBar = m_pParent;
cs.pMenu = pMenu;
cs.nIndex = nIndex;
cs.strCaption = strCaption;
cs.controlType = controlType;
cs.buttonStyle = buttonStyle;
if (pSite->SendMessage(WM_XTP_BEFORECREATECONTROL, 0, (LPARAM)&cs) != 0)
{
pControl = cs.pControl;
controlType = cs.controlType;
strCaption = cs.strCaption;
nID = cs.nID;
buttonStyle = cs.buttonStyle;
}
}
if (pControl == NULL)
{
switch (controlType)
{
case xtpControlButton:
if (nID == XTP_ID_WINDOWLIST) pControl = (CXTPControl*)CXTPControlWindowList::CreateObject();
else if (nID == XTP_ID_WORKSPACE_ACTIONS) pControl = (CXTPControl*)CXTPControlWorkspaceActions::CreateObject();
else if (nID == ID_VIEW_TOOLBAR) pControl = (CXTPControl*)CXTPControlToolbars::CreateObject();
else if (nID == ID_OLE_VERB_FIRST && strCaption == _T("<<OLE VERBS GO HERE>>")) pControl = (CXTPControl*)CXTPControlOleItems::CreateObject();
else if (nID == ID_FILE_MRU_FILE1) pControl = (CXTPControl*)CXTPControlRecentFileList::CreateObject();
else pControl = (CXTPControl*)CXTPControlButton::CreateObject();
break;
case xtpControlComboBox:
pControl = (CXTPControl*)CXTPControlComboBox::CreateObject();
break;
case xtpControlEdit:
pControl = (CXTPControl*)CXTPControlEdit::CreateObject();
break;
case xtpControlLabel:
pControl = (CXTPControl*)CXTPControlLabel::CreateObject();
break;
case xtpControlCheckBox:
pControl = (CXTPControl*)CXTPControlCheckBox::CreateObject();
break;
case xtpControlRadioButton:
pControl = (CXTPControl*)CXTPControlRadioButton::CreateObject();
break;
case xtpControlGallery:
pControl = (CXTPControl*)CXTPControlGallery::CreateObject();
break;
case xtpControlPopup:
case xtpControlSplitButtonPopup:
case xtpControlButtonPopup:
pControl = CXTPControlPopup::CreateControlPopup(controlType);
CXTPPopupBar* pPopupBar = 0;
CString strCaptionPopup(strCaption);
CXTPPaintManager::StripMnemonics(strCaptionPopup);
if (pSite)
{
XTP_COMMANDBARS_CREATEBAR cb;
ZeroMemory(&cb, sizeof(cb));
cb.bPopup = TRUE;
cb.lpcstrCaption = strCaptionPopup;
cb.nID = nID;
if (pSite->SendMessage(WM_XTP_CREATECOMMANDBAR, 0, (LPARAM)&cb) != 0)
{
pPopupBar = DYNAMIC_DOWNCAST(CXTPPopupBar, cb.pCommandBar);
strCaptionPopup = cb.lpcstrCaption;
}
}
if (pPopupBar == NULL) pPopupBar = CXTPPopupBar::CreatePopupBar(pCommandBars);
pPopupBar->SetTitle(strCaptionPopup);
CMenu menu;
if (!pPopupMenu && nID > 0 && menu.LoadMenu(nID))
{
pPopupMenu = menu.GetSubMenu(0);
}
if (pPopupMenu) pPopupBar->LoadMenu(pPopupMenu, FALSE);
((CXTPControlPopup*)pControl)->m_pCommandBar = pPopupBar;
break;
}
ASSERT(pControl);
if (!pControl)
return NULL;
pControl->m_controlType = controlType;
pControl->SetStyle(buttonStyle);
MENUITEMINFO info;
ZeroMemory(&info, sizeof(MENUITEMINFO));
info.cbSize = sizeof(MENUITEMINFO);
info.fMask = MIIM_DATA;
::GetMenuItemInfo(pMenu->m_hMenu, nIndex, TRUE, &info);
pControl->SetTag(info.dwItemData);
}
CXTPControlAction* pAction = pCommandBars->FindAction(nID);
if (pControl->GetAction() != NULL)
{
}
else if (pAction || (pCommandBars->IsActionsEnabled() && nID > 0 && nID < 0xFFFFFFF))
{
if (pAction == NULL) pAction = pCommandBars->CreateAction(nID);
pControl->SetAction(pAction);
if (pAction->m_strCaption.IsEmpty())
pAction->SetCaption(strCaption);
}
else
{
pControl->SetID(nID);
pControl->SetCaption(strCaption);
}
if (bDefaultItem) pControl->SetItemDefault(bDefaultItem);
m_arrControls.InsertAt(GetCount(), pControl);
OnControlAdded(pControl);
if (pSite)
{
cs.pControl = pControl;
pSite->SendMessage(WM_XTP_AFTERCREATECONTROL, 0, (LPARAM)&cs);
}
return pControl;
}
void CXTPControls::OnControlAdded(CXTPControl* /*pControl*/)
{
RefreshIndexes();
}
void CXTPControls::OnControlRemoved(CXTPControl* pControl)
{
pControl->m_pControls = NULL;
pControl->OnRemoved();
pControl->m_pParent = NULL;
RefreshIndexes();
}
CXTPControl* CXTPControls::Add(XTPControlType controlType, int nId, LPCTSTR strParameter, int nBefore, BOOL bTemporary)
{
CXTPControl* pControl = NULL;
CXTPCommandBars* pCommandBars = GetCommandBars();
switch (controlType)
{
case xtpControlCustom:
return Add(new CXTPControlCustom(), nId, strParameter, nBefore, bTemporary);
case xtpControlButton:
if (nId == XTP_ID_WINDOWLIST) pControl = (CXTPControl*)CXTPControlWindowList::CreateObject();
else if (nId == XTP_ID_WORKSPACE_ACTIONS) pControl = (CXTPControl*)CXTPControlWorkspaceActions::CreateObject();
else if (nId == ID_VIEW_TOOLBAR) pControl = (CXTPControl*)CXTPControlToolbars::CreateObject();
else if (nId == XTP_ID_FILE_MRU && !bTemporary) pControl = (CXTPControl*)CXTPControlRecentFileList::CreateObject();
else
pControl = (CXTPControl*)CXTPControlButton::CreateObject();
break;
case xtpControlComboBox:
pControl = (CXTPControl*)CXTPControlComboBox::CreateObject();
break;
case xtpControlLabel:
pControl = (CXTPControl*)CXTPControlLabel::CreateObject();
break;
case xtpControlCheckBox:
pControl = (CXTPControl*)CXTPControlCheckBox::CreateObject();
break;
case xtpControlRadioButton:
pControl = (CXTPControl*)CXTPControlRadioButton::CreateObject();
break;
case xtpControlGallery:
pControl = (CXTPControl*)CXTPControlGallery::CreateObject();
break;
case xtpControlEdit:
pControl = (CXTPControl*)CXTPControlEdit::CreateObject();
break;
case xtpControlPopup:
case xtpControlSplitButtonPopup:
case xtpControlButtonPopup:
CXTPControlPopup* pControlPopup = (CXTPControlPopup*)CXTPControlPopup::CreateObject();
CXTPPopupBar* pPopupBar = 0;
CMenu menu;
if (nId > 0)
{
CString strCaption;
CMenu* pPopupMenu = NULL;
if (menu.LoadMenu(nId))
{
pPopupMenu = menu.GetSubMenu(0);
XTPResourceManager()->GetMenuLocaleString(&menu, 0, strCaption, MF_BYPOSITION);
}
CWnd* pSite = m_pCommandBars ? m_pCommandBars->GetSite() :
m_pParent ? m_pParent->GetOwnerSite() : NULL;
if (pSite)
{
XTP_COMMANDBARS_CREATEBAR cs;
ZeroMemory(&cs, sizeof(cs));
cs.bPopup = TRUE;
cs.lpcstrCaption = strCaption;
cs.nID = nId;
if (pSite->SendMessage(WM_XTP_CREATECOMMANDBAR, 0, (LPARAM)&cs) != 0)
{
pPopupBar = DYNAMIC_DOWNCAST(CXTPPopupBar, cs.pCommandBar);
}
}
if (pPopupBar == NULL) pPopupBar = CXTPPopupBar::CreatePopupBar(GetCommandBars());
pControlPopup->SetCaption(strCaption);
if (pPopupMenu)
{
pPopupBar->LoadMenu(pPopupMenu);
}
}
if (pPopupBar == NULL) pPopupBar = CXTPPopupBar::CreatePopupBar(pCommandBars);
pControlPopup->m_pCommandBar = pPopupBar;
pControl = pControlPopup;
break;
}
ASSERT(pControl);
if (!pControl)
return NULL;
pControl->m_controlType = controlType;
return Add(pControl, nId, strParameter, nBefore, bTemporary);
}
CXTPControl* CXTPControls::Add(CXTPControl* pControl, int nId, LPCTSTR strParameter, int nBefore, BOOL bTemporary)
{
ASSERT(pControl);
if (!pControl)
return NULL;
pControl->m_strParameter = strParameter;
pControl->m_bTemporary = bTemporary;
CXTPCommandBars* pCommandBars = GetCommandBars();
CXTPControlAction* pAction = pCommandBars->FindAction(nId);
if (pControl->GetAction() != NULL)
{
}
else if (pAction != NULL)
{
pControl->SetAction(pAction);
}
else if (pCommandBars->IsActionsEnabled() && nId > 0 && nId < 0xFFFFFFF)
{
if ((nId >= XTP_COMMANDBARS_RESOURCE_FIRST && nId <= XTP_COMMANDBARS_RESOURCE_LAST)
|| (nId >= 35000 && nId <= 35003))
{
if (!pAction)
{
pControl->SetID(nId);
}
}
else
{
pAction = pCommandBars->CreateAction(nId);
pControl->SetAction(pAction);
}
}
else
{
pControl->SetID(nId);
}
return InsertAt(pControl, nBefore);
}
CXTPControl* CXTPControls::InsertAt(CXTPControl* pControl, int nBefore)
{
if (nBefore < 0 || nBefore >= GetCount())
nBefore = GetCount();
ASSERT(pControl);
m_arrControls.InsertAt(nBefore, pControl);
OnControlAdded(pControl);
return pControl;
}
CXTPControl* CXTPControls::Add(CXTPControl* pControl)
{
return InsertAt(pControl, -1);
}
CXTPControl* CXTPControls::AddClone(CXTPControl* pControl, int nBefore, BOOL bRecursive)
{
CXTPControl* pClone = (CXTPControl*)pControl->GetRuntimeClass()->CreateObject();
ASSERT(pClone);
if (!pClone)
return NULL;
InsertAt(pClone, nBefore);
pClone->Copy(pControl, bRecursive);
return pClone;
}
void CXTPControls::RemoveAll()
{
for (int nIndex = GetCount() - 1; nIndex >= 0; nIndex--)
{
CXTPControl* pControl = GetAt(nIndex);
if (OnControlRemoving(pControl))
continue;
m_arrControls.RemoveAt(nIndex);
OnControlRemoved(pControl);
pControl->SetParent(NULL);
pControl->InternalRelease();
}
}
CXTPControl* CXTPControls::GetFirst() const
{
return GetCount() > 0 ? GetAt(0) : NULL;
}
void CXTPControls::GetNext(CXTPControl*& pControl) const
{
pControl = (!pControl || pControl->m_nIndex >= GetCount() - 1) ? 0 : GetAt(pControl->m_nIndex + 1);
}
CXTPControl* CXTPControls::FindControl(int nId) const
{
return FindControl(xtpControlError, nId, FALSE, FALSE);
}
CXTPControl* CXTPControls::FindControl(XTPControlType type, int nId, BOOL bVisible, BOOL bRecursive) const
{
for (int nIndex = 0; nIndex < GetCount(); nIndex++)
{
CXTPControl* pControl = GetAt(nIndex);
if ((type == xtpControlError || pControl->GetType() == type) &&
(!bVisible || pControl->IsVisible()) &&
(nId == -1 || nId == pControl->GetID()))
return pControl;
if (bRecursive)
{
CXTPCommandBar* pBar = pControl->GetCommandBar();
if (pBar)
{
pControl = pBar->GetControls()->FindControl(type, nId, bVisible, bRecursive);
if (pControl != NULL) return pControl;
}
}
}
return NULL;
}
BOOL CXTPControls::OnControlRemoving(CXTPControl* /*pControl*/)
{
return FALSE;
}
void CXTPControls::Remove(CXTPControl* pControl)
{
if (pControl && pControl->m_pControls == this)
{
if (pControl->GetSelected())
m_pParent->SetSelected(-1);
ASSERT(pControl->m_pControls == this);
//Ensure the index falls within the correct range.
if ((pControl->m_nIndex >= 0) && (pControl->m_nIndex < GetCount()))
{
ASSERT(m_arrControls[pControl->m_nIndex] == pControl);
if (OnControlRemoving(pControl))
return;
m_arrControls.RemoveAt(pControl->m_nIndex);
OnControlRemoved(pControl);
pControl->SetParent(NULL);
pControl->InternalRelease();
}
}
}
void CXTPControls::Remove(int nIndex)
{
CXTPControl* pControl = GetAt(nIndex);
Remove(pControl);
}
CXTPControl* CXTPControls::SetControlType(int nIndex, XTPControlType type)
{
return SetControlType(GetAt(nIndex), type);
}
CXTPControl* CXTPControls::SetControlType(CXTPControl* pControl, XTPControlType type)
{
ASSERT(pControl->m_pControls == this);
ASSERT(pControl);
if (IsPopupControlType(pControl->GetType()) && IsPopupControlType(type))
{
pControl->m_controlType = type;
return pControl;
}
CXTPControl* pNew = Add(type, 0, _T(""), pControl->GetIndex() + 1, FALSE);
pNew->CXTPControl::Copy(pControl, FALSE);
pNew->m_controlType = type;
Remove(pControl);
return pNew;
}
long CXTPControls::GetNext(long nIndex, int nDirection, BOOL bKeyboard, BOOL bSkipTemporary, BOOL bSkipCollapsed) const
{
ASSERT(nDirection == +1 || nDirection == -1);
if (GetCount() == 0) return -1;
long nNext = nIndex + nDirection;
if (nDirection == -1 && nIndex == -1)
{
nNext = GetCount() - 1;
}
DWORD nSkipVisible = xtpHideScroll | (!bSkipCollapsed ? xtpHideExpand : 0);
BOOL bCircle = FALSE;
while (nNext != nIndex)
{
if (nNext >= GetCount())
{
if ((nIndex == -1 && nDirection == +1) || bCircle) return -1;
nNext = 0;
bCircle = TRUE;
}
if (nNext < 0)
{
if ((nIndex == -1 && nDirection == -1) || bCircle) return -1;
nNext = GetCount() - 1;
bCircle = TRUE;
}
if ((GetAt(nNext)->IsVisible(nSkipVisible)) && (!bKeyboard || !(GetAt(nNext)->m_dwFlags & xtpFlagSkipFocus)))
{
if (!bSkipTemporary || !GetAt(nNext)->m_bTemporary)
return nNext;
}
nNext += nDirection;
}
return nNext;
}
CXTPControl* CXTPControls::HitTest(CPoint point) const
{
for (int i = 0; i < GetCount(); i++)
{
CXTPControl* pControl = GetAt(i);
if (pControl->IsVisible())
{
if (pControl->m_rcControl.PtInRect(point))
return pControl;
}
}
return NULL;
}
struct CXTPControls::XTPBUTTONINFO // struct for CalcDynamicSize ;
{
CRect rcControl;
CRect rcRow;
CSize szControl;
BOOL bVisible;
BOOL bWrap;
BOOL bHide;
BOOL bBeginGroup;
XTPButtonStyle buttonStyle;
CXTPControl* pControl;
CSize szSeparators;
CSize szSpacing;
void EnsureButtonSize(CDC* pDC)
{
if (buttonStyle != pControl->GetStyle())
{
buttonStyle = pControl->GetStyle();
szControl = pControl->GetSize(pDC);
}
}
void Attach(CDC* pDC, CXTPControl* p)
{
pControl = p;
bHide = bWrap = FALSE;
rcRow.SetRectEmpty();
szControl = pControl->GetSize(pDC);
rcControl = pControl->GetRect();
bBeginGroup = pControl->GetBeginGroup();
bVisible = pControl->IsVisible(xtpHideWrap);
buttonStyle = pControl->GetStyle();
}
void Detach()
{
pControl->SetHideWrap(bHide);
pControl->SetRowRect(rcRow);
if (!bHide)
pControl->SetRect(rcControl);
pControl->SetWrap(bWrap);
}
};
CSize CXTPControls::_CalcSize(XTPBUTTONINFO* pData, BOOL bVert)
{
const CSize& szSeparators = pData->szSeparators;
const CSize& szSpacing = pData->szSpacing;
CPoint cur(0, 0);
CSize sizeResult(0, 0);
int nRow = 0;
BOOL bFirst = TRUE;
for (int i = 0; i < GetCount(); i++)
{
XTPBUTTONINFO* pControl = &pData[i];
if (!pControl->bVisible || pControl->bHide)
continue;
CSize szControl = pControl->szControl;
if (bVert)
{
if (!pControl->bWrap && !bFirst)
cur.y += pControl->bBeginGroup ? szSeparators.cx : szSpacing.cx;
if (pControl->bWrap)
{
cur.x -= nRow + (pControl->bBeginGroup ? szSeparators.cy : szSpacing.cy);
nRow = cur.y = 0;
}
nRow = max(nRow, szControl.cx);
pControl->rcControl.SetRect(cur.x - szControl.cx, cur.y, cur.x , cur.y + szControl.cy);
sizeResult.cx = max(szControl.cx - cur.x, sizeResult.cx);
sizeResult.cy = max(cur.y + szControl.cy, sizeResult.cy);
cur.y += szControl.cy;
}
else
{
if (!pControl->bWrap && !bFirst)
cur.x += pControl->bBeginGroup ? szSeparators.cx : szSpacing.cx;
if (pControl->bWrap)
{
cur.y += nRow + (pControl->bBeginGroup ? szSeparators.cy : szSpacing.cy);
nRow = cur.x = 0;
}
nRow = max(nRow, szControl.cy);
pControl->rcControl.SetRect(cur.x, cur.y, cur.x + szControl.cx, cur.y + szControl.cy);
sizeResult.cx = max(cur.x + szControl.cx, sizeResult.cx);
sizeResult.cy = max(cur.y + szControl.cy, sizeResult.cy);
cur.x += szControl.cx;
}
bFirst = FALSE;
}
return sizeResult;
}
int CXTPControls::_WrapToolBar(XTPBUTTONINFO* pData, int nWidth, DWORD& dwMode)
{
int nResult = 0, x = 0;
BOOL bVert = dwMode & LM_VERTDOCK;
BOOL bFirst = TRUE;
int nSeparator = pData->szSeparators.cx;
int nSpacing = pData->szSpacing.cx;
for (int i = 0; i < GetCount(); i++)
{
XTPBUTTONINFO* pControl = &pData[i];
pControl->bHide = FALSE;
pControl->bWrap = FALSE;
if (!pControl->bVisible)
continue;
int dx = bVert ? pControl->szControl.cy : pControl->szControl.cx;
if (!bFirst)
dx += pControl->bBeginGroup ? nSeparator : nSpacing;
BOOL bWrap = (x + dx > nWidth) || ((dwMode & LM_POPUP) && pControl->bBeginGroup && !bFirst);
BOOL bRowWrap = FALSE;
if (pControl->pControl->GetFlags() & xtpFlagWrapRow)
bRowWrap = TRUE;
if (bRowWrap)
{
x = bVert ? pData[i].szControl.cy : pData[i].szControl.cx;
pControl->bWrap = TRUE;
nResult++;
}
else if (bWrap)
{
if (dwMode & LM_HIDEWRAP && !bFirst)
{
BOOL bWrapRowFound = FALSE;
for (int j = i; j < GetCount(); j++)
{
if (pData[j].pControl->GetFlags() & xtpFlagWrapRow)
{
bWrapRowFound = TRUE;
i = j - 1;
break;
}
pData[j].bHide = TRUE;
}
dwMode |= LM_STRETCH;
if (bWrapRowFound)
continue;
return nResult;
}
for (int j = i; j >= 0 && pData[j].bWrap == FALSE; j--)
{
// Find last separator
if (pData[j].bBeginGroup && pData[j].bVisible)
{
i = j;
break;
}
}
x = bVert ? pData[i].szControl.cy : pData[i].szControl.cx;
pData[i].bWrap = TRUE;
if (!(dwMode & LM_HIDEWRAP)) dwMode |= LM_STRETCH;
nResult++;
}
else
x += dx;
bFirst = FALSE;
}
return nResult + 1;
}
void CXTPControls::_SizePopupToolBar(XTPBUTTONINFO* pData, DWORD dwMode)
{
CSize sizeMax, sizeMin, sizeMid;
// Wrap ToolBar vertically
_WrapToolBar(pData, 0, dwMode);
sizeMin = _CalcSize(pData, FALSE);
// Wrap ToolBar horizontally
_WrapToolBar(pData, 32767, dwMode);
sizeMax = _CalcSize(pData, FALSE);
while (sizeMin.cx < sizeMax.cx)
{
sizeMid.cx = (sizeMin.cx + sizeMax.cx) / 2;
_WrapToolBar(pData, sizeMid.cx, dwMode);
sizeMid = _CalcSize(pData, FALSE);
if (sizeMid.cy > sizeMid.cx)
{
if (sizeMin == sizeMid)
return;
sizeMin = sizeMid;
}
else if (sizeMid.cy < sizeMid.cx)
sizeMax = sizeMid;
else
return;
}
}
void CXTPControls::_SizeFloatableBar(XTPBUTTONINFO* pData, int nLength, DWORD dwMode)
{
if (! (dwMode & LM_LENGTHY))
{
int nMin, nMax, nTarget, nCurrent, nMid;
// Wrap ToolBar as specified
nMax = nLength;
nTarget = _WrapToolBar(pData, nMax, dwMode);
// Wrap ToolBar vertically
nMin = 0;
nCurrent = _WrapToolBar(pData, nMin, dwMode);
if (nCurrent != nTarget)
{
while (nMin < nMax)
{
nMid = (nMin + nMax) / 2;
nCurrent = _WrapToolBar(pData, nMid, dwMode);
if (nCurrent == nTarget)
nMax = nMid;
else
{
if (nMin == nMid)
{
_WrapToolBar(pData, nMax, dwMode);
break;
}
nMin = nMid;
}
}
}
CSize size = _CalcSize(pData, FALSE);
_WrapToolBar(pData, size.cx, dwMode);
}
else
{
CSize sizeMax, sizeMin, sizeMid;
// Wrap ToolBar vertically
_WrapToolBar(pData, 0, dwMode);
sizeMin = _CalcSize(pData, FALSE);
// Wrap ToolBar horizontally
_WrapToolBar(pData, 32767, dwMode);
sizeMax = _CalcSize(pData, FALSE);
while (sizeMin.cx < sizeMax.cx)
{
sizeMid.cx = (sizeMin.cx + sizeMax.cx) / 2;
_WrapToolBar(pData, sizeMid.cx, dwMode);
sizeMid = _CalcSize(pData, FALSE);
if (nLength < sizeMid.cy)
{
if (sizeMin == sizeMid)
{
_WrapToolBar(pData, sizeMax.cx, dwMode);
return;
}
sizeMin = sizeMid;
}
else if (nLength > sizeMid.cy)
sizeMax = sizeMid;
else
return;
}
}
}
void CXTPControls::_CenterControlsInRow(XTPBUTTONINFO* pData, int nFirst, int nLast, int nHeight, BOOL bVert, CSize sizeResult, CRect rcBorder)
{
for (int i = nFirst; i < nLast; i++)
{
XTPBUTTONINFO* pControl = &pData[i];
CRect rc = pControl->rcControl;
if (bVert)
{
pControl->rcRow.SetRect(rc.right - nHeight, rcBorder.top, rc.right, sizeResult.cy + rcBorder.top);
if (!(m_pParent->GetFlags() & xtpFlagSmartLayout)) pControl->rcControl.OffsetRect(-(nHeight - rc.Width())/2, 0);
}
else
{
pControl->rcRow.SetRect(rcBorder.left, rc.top, sizeResult.cx + rcBorder.left, rc.top + nHeight);
if (!(m_pParent->GetFlags() & xtpFlagSmartLayout)) pControl->rcControl.OffsetRect(0, (nHeight - rc.Height())/2);
}
}
}
void CXTPControls::_AdjustBorders(XTPBUTTONINFO* pData, CSize& sizeResult, DWORD dwMode, CRect rcBorder)
{
if (dwMode & LM_COMMIT)
{
BOOL bVert = dwMode & LM_VERTDOCK;
int nFirstInRow = 0;
int nHeight = 0;
int nBarHeight = 0;
for (int i = 0; i < GetCount(); i++)
{
XTPBUTTONINFO* pControl = &pData[i];
if (!pControl->bVisible || pControl->bHide)
continue;
pControl->rcControl.OffsetRect(rcBorder.left, rcBorder.top);
if (bVert) pControl->rcControl.OffsetRect(sizeResult.cx, 0);
if (pControl->bWrap)
{
_CenterControlsInRow(pData, nFirstInRow, i, nHeight, bVert, sizeResult, rcBorder);
nFirstInRow = i;
nHeight = 0;
}
nBarHeight = bVert ? sizeResult.cx : sizeResult.cy;
nHeight = max(nHeight, bVert ? pControl->rcControl.Width() : pControl->rcControl.Height());
}
_CenterControlsInRow(pData, nFirstInRow, GetCount(), nFirstInRow == 0 ? nBarHeight : nHeight, bVert, sizeResult, rcBorder);
}
sizeResult += CSize(rcBorder.left + rcBorder.right, rcBorder.top + rcBorder.bottom);
}
void CXTPControls::_MoveRightAlligned(XTPBUTTONINFO* pData, CSize sizeResult, CRect rcBorder, DWORD dwMode)
{
BOOL bVert = dwMode & LM_VERTDOCK;
int nRight = bVert ? sizeResult.cy - rcBorder.bottom : sizeResult.cx - rcBorder.right;
int i;
for (i = GetCount() - 1; i >= 0; i--)
{
XTPBUTTONINFO* pControl = &pData[i];
if (!pControl->bVisible || pControl->bHide)
continue;
if (!(GetAt(i)->m_dwFlags & xtpFlagRightAlign))
break;
CRect rc = pControl->rcControl;
if (!bVert)
{
if (nRight - rc.Width() < rcBorder.right)
break;
pControl->rcControl.SetRect(nRight - rc.Width(), rc.top, nRight, rc.bottom);
nRight -= rc.Width();
}
else
{
if (nRight - rc.Height() < rcBorder.top)
break;
pControl->rcControl.SetRect(rc.left, nRight - rc.Height(), rc.right, nRight);
nRight -= rc.Height();
}
if (pControl->bWrap)
break;
}
int nStretchAvail = -1;
int nStretchedCount = 0;
BOOL bSkipRightAligned = FALSE;
nRight = bVert ? sizeResult.cy - rcBorder.bottom : sizeResult.cx - rcBorder.right;
int nLastInRow = GetCount() - 1;
for (i = GetCount() - 1; i >= 0; i--)
{
XTPBUTTONINFO* pControl = &pData[i];
if (pControl->bVisible && !pControl->bHide)
{
if (!bSkipRightAligned && (GetAt(i)->m_dwFlags & xtpFlagRightAlign))
{
nRight = pControl->rcControl.left;
nLastInRow = i - 1;
}
else if (GetAt(i)->m_dwFlags & xtpFlagControlStretched)
{
nStretchedCount++;
bSkipRightAligned = TRUE;
}
if ((nStretchAvail == -1) && (nLastInRow >= i))
{
nStretchAvail = nRight - (!bVert ? pControl->rcControl.right : pControl->rcControl.bottom);
}
}
if ((pControl->bVisible && !pControl->bHide && pControl->bWrap) || (i == 0))
{
if (nStretchedCount > 0 && nStretchAvail > 0)
{
int nOffset = 0;
for (int j = i; j <= nLastInRow; j++)
{
pControl = &pData[j];
if (!pControl->bVisible || pControl->bHide)
continue;
CRect rc = pControl->rcControl;
if (!bVert)
pControl->rcControl.SetRect(nOffset + rc.left, rc.top, nOffset + rc.right, rc.bottom);
else
pControl->rcControl.SetRect(rc.left, nOffset + rc.top, rc.right, nOffset + rc.bottom);
if ((GetAt(j)->m_dwFlags & xtpFlagControlStretched) && (nStretchedCount > 0))
{
int nStretchedOffset = nStretchAvail / nStretchedCount;
if (!bVert)
pControl->rcControl.right += nStretchedOffset;
else
pControl->rcControl.bottom += nStretchedOffset;
nStretchAvail -= nStretchedOffset;
nStretchedCount--;
nOffset += nStretchedOffset;
}
}
}
nRight = bVert ? sizeResult.cy - rcBorder.bottom : sizeResult.cx - rcBorder.right;
bSkipRightAligned = TRUE;
nLastInRow = i - 1;
nStretchAvail = -1;
nStretchedCount = 0;
}
}
}
int CXTPControls::GetVisibleCount(BOOL bIgnoreWraps) const
{
DWORD nFlags = bIgnoreWraps ? 0 : xtpHideWrap;
int nCount = 0;
for (int i = 0; i < GetCount(); i++)
{
if (GetAt(i)->IsVisible(nFlags)) nCount++;
}
return nCount;
}
CXTPControl* CXTPControls::GetVisibleAt(int nIndex, BOOL bIgnoreWraps) const
{
DWORD nFlags = bIgnoreWraps ? 0 : xtpHideWrap;
for (int i = 0; i < GetCount(); i++)
{
if (GetAt(i)->IsVisible(nFlags))
{
if (nIndex == 0)
return GetAt(i);
nIndex--;
}
}
return NULL;
}
CSize CXTPControls::_ReduceSmartLayoutToolBar(CDC* pDC, XTPBUTTONINFO* pData, int nWidth, DWORD& dwMode)
{
CSize sizeResult(0, 0);
BOOL bReduced = FALSE;
BOOL bVert = dwMode & LM_VERTDOCK;
do
{
bReduced = FALSE;
if (!bReduced)
{
for (int i = GetCount() - 1; i >= 2; i--)
{
XTPBUTTONINFO* pControl = &pData[i];
if (!pControl->bVisible || pControl->bBeginGroup)
continue;
int nItems = 0;
int nButtons[3] = {0, 0, 0};
for (int j = i; j >= 0; j--)
{
pControl = &pData[j];
if (!pControl->bVisible)
continue;
if ((nItems == 2 || !pControl->bBeginGroup) && GetAt(j)->m_buttonStyle == xtpButtonIconAndCaptionBelow)
{
nButtons[nItems] = j;
nItems += 1;
}
else
{
break;
}
if (nItems == 3)
break;
}
if (nItems == 3)
{
GetAt(nButtons[0])->m_buttonStyle = xtpButtonIconAndCaption;
GetAt(nButtons[1])->m_buttonStyle = xtpButtonIconAndCaption;
GetAt(nButtons[2])->m_buttonStyle = xtpButtonIconAndCaption;
bReduced = TRUE;
break;
}
}
}
if (!bReduced)
{
for (int i = GetCount() - 1; i >= 2; i--)
{
XTPBUTTONINFO* pControl = &pData[i];
if (!pControl->bVisible || pControl->bBeginGroup)
continue;
int nItems = 0;
int nButtons[3] = {0, 0, 0};
BOOL bFound = FALSE;
int j;
for (j = i; j >= 0; j--)
{
pControl = &pData[j];
if (!pControl->bVisible)
continue;
if ((nItems == 2 || !pControl->bBeginGroup))
{
nButtons[nItems] = j;
nItems += 1;
bFound = bFound || GetAt(j)->m_buttonStyle == xtpButtonIconAndCaptionBelow;
}
else
{
break;
}
if (nItems == 3)
break;
}
i = j;
if (nItems == 3 && bFound)
{
GetAt(nButtons[0])->m_buttonStyle = xtpButtonIconAndCaption;
GetAt(nButtons[1])->m_buttonStyle = xtpButtonIconAndCaption;
GetAt(nButtons[2])->m_buttonStyle = xtpButtonIconAndCaption;
bReduced = TRUE;
break;
}
}
}
if (!bReduced)
{
for (int i = GetCount() - 1; i >= 2; i--)
{
XTPBUTTONINFO* pControl = &pData[i];
if (!pControl->bVisible || pControl->bBeginGroup)
continue;
int nItems = 0;
int nButtons[3] = {0, 0, 0};
int nLeft = 0;
for (int j = i; j >= 0; j--)
{
pControl = &pData[j];
if (!pControl->bVisible)
continue;
int nOffset = (bVert ? pControl->rcControl.top : pControl->rcControl.left);
if (nItems != 0 && (nOffset != nLeft))
break;
if ((nItems == 2 || !pControl->bBeginGroup) && GetAt(j)->m_buttonStyle == xtpButtonIconAndCaption)
{
nButtons[nItems] = j;
nItems += 1;
nLeft = nOffset;
}
else
{
break;
}
if (nItems == 3)
break;
}
if (nItems == 3)
{
GetAt(nButtons[0])->m_buttonStyle = xtpButtonIcon;
GetAt(nButtons[1])->m_buttonStyle = xtpButtonIcon;
GetAt(nButtons[2])->m_buttonStyle = xtpButtonIcon;
bReduced = TRUE;
break;
}
}
}
sizeResult = _CalcSmartLayoutToolBar(pDC, pData, dwMode);
if ((bVert ? sizeResult.cy : sizeResult.cx) < nWidth)
return sizeResult;
}
while (bReduced);
if (dwMode & LM_HIDEWRAP)
{
BOOL bFirst = TRUE;
for (int i = 0; i < GetCount(); i++)
{
XTPBUTTONINFO* pControl = &pData[i];
if (!pControl->bVisible)
continue;
if (!bFirst && ((bVert ? pControl->rcControl.bottom : pControl->rcControl.right) > nWidth))
{
GetAt(i)->m_buttonStyle = xtpButtonIcon;
pControl->bHide = TRUE;
}
bFirst = FALSE;
}
return _CalcSmartLayoutToolBar(pDC, pData, dwMode);
}
return sizeResult;
}
CSize CXTPControls::_CalcSmartLayoutToolBar(CDC* pDC, XTPBUTTONINFO* pData, DWORD& dwMode)
{
BOOL bFirst = TRUE;
BOOL bVert = dwMode & LM_VERTDOCK;
CSize szLargeIcon = m_pParent->GetLargeIconSize(TRUE);
int nResultHeight = szLargeIcon.cy + 7 + m_pParent->GetPaintManager()->GetSplitDropDownHeight();
CSize sizeResult(0, nResultHeight);
int dyPrev = 0, dxPrev = 0, x = 0;
for (int i = 0; i < GetCount(); i++)
{
XTPBUTTONINFO* pControl = &pData[i];
if (!pControl->bVisible || pControl->bHide)
continue;
BOOL bFullRow = GetAt(i)->m_buttonStyle == xtpButtonIconAndCaptionBelow;
pControl->EnsureButtonSize(pDC);
CSize szControl = pControl->szControl;
int dx = bVert ? szControl.cy : szControl.cx;
int dy = !bVert ? szControl.cy : szControl.cx;
BOOL bBeginGroup = pControl->bBeginGroup && !bFirst;
if (bBeginGroup)
x += 6;
if (!bFirst && !bBeginGroup && !bFullRow && dyPrev + dy <= nResultHeight)
{
if (bVert)
pControl->rcControl.SetRect(-dyPrev - dy, x, -dyPrev, x + dx);
else
pControl->rcControl.SetRect(x, dyPrev, x + dx, dyPrev + dy);
dxPrev = max(dxPrev, dx);
}
else
{
x += dxPrev;
if (bVert)
pControl->rcControl.SetRect(-dy, x, 0, x + dx);
else
pControl->rcControl.SetRect(x, 0, x + dx, dy);
sizeResult.cy = max(dy, sizeResult.cy);
dxPrev = dx;
}
sizeResult.cx = max(x + dx, sizeResult.cx);
bFirst = FALSE;
dyPrev = bVert ? -pControl->rcControl.left : pControl->rcControl.bottom;
}
return bVert ? CSize(sizeResult.cy, sizeResult.cx) : sizeResult;
}
CSize CXTPControls::_WrapSmartLayoutToolBar(CDC* pDC, XTPBUTTONINFO* pData, int nWidth, DWORD& dwMode)
{
BOOL bVert = dwMode & LM_VERTDOCK;
CSize szLargeIcon = m_pParent->GetLargeIconSize(FALSE);
for (int i = 0; i < GetCount(); i++)
{
XTPBUTTONINFO* pControl = &pData[i];
if (!pControl->bVisible)
continue;
BOOL bDrawImage = GetAt(i)->GetIconId() > 0 ?
GetAt(i)->GetImageManager()->IsPrimaryImageExists(GetAt(i)->GetIconId(), szLargeIcon.cx) != NULL: FALSE;
pControl->bHide = FALSE;
pControl->bWrap = FALSE;
GetAt(i)->m_buttonStyle = bDrawImage? xtpButtonIconAndCaptionBelow : xtpButtonIconAndCaption;
}
CSize sizeResult = _CalcSmartLayoutToolBar(pDC, pData, dwMode);
if ((bVert ? sizeResult.cy : sizeResult.cx) > nWidth)
{
sizeResult = _ReduceSmartLayoutToolBar(pDC, pData, nWidth, dwMode);
dwMode |= LM_STRETCH;
}
return sizeResult;
}
CSize CXTPControls::CalcDynamicSize(CDC* pDC, int nLength, DWORD dwMode, const CRect& rcBorder, int nWidth)
{
CSize sizeResult(0, 0);
CSize szSeparators(m_pParent->GetPaintManager()->DrawCommandBarSeparator(pDC, m_pParent, NULL, FALSE));
int i;
for (i = GetCount() - 1; i >= 0; i--)
{
GetAt(i)->OnCalcDynamicSize(dwMode);
}
if (GetVisibleCount() > 0)
{
XTPBUTTONINFO* pData = new XTPBUTTONINFO[GetCount()];
for (int j = 0; j < GetCount(); j++)
pData[j].Attach(pDC, GetAt(j));
pData->szSeparators = szSeparators;
pData->szSpacing = m_pParent->m_szButtonSpacing;
if (dwMode & LM_MRUWIDTH)
{
nLength = m_pParent->m_nMRUWidth;
}
if ((m_pParent->GetFlags() & xtpFlagSmartLayout))
{
if (dwMode & LM_VERTDOCK)
{
sizeResult = _WrapSmartLayoutToolBar(pDC, pData, nLength - rcBorder.top - rcBorder.bottom, dwMode);
}
else
{
sizeResult = _WrapSmartLayoutToolBar(pDC, pData, nLength - rcBorder.right - rcBorder.left, dwMode);
}
}
else
{
if (dwMode & LM_POPUP)
{
_WrapToolBar(pData, m_pParent->m_nMRUWidth, dwMode);
CSize sz = _CalcSize(pData, FALSE);
if ((sz.cy > sz.cx * 3) && (m_pParent->m_nMRUWidth <= 0))
{
_SizePopupToolBar(pData, dwMode);
}
else
{
_WrapToolBar(pData, sz.cx , dwMode);
}
}
else if (dwMode & LM_HORZDOCK)
{
_WrapToolBar(pData, nLength - rcBorder.right - rcBorder.left, dwMode);
}
else if (dwMode & LM_VERTDOCK)
{
_WrapToolBar(pData, nLength - rcBorder.top - rcBorder.bottom, dwMode);
}
else
{
_SizeFloatableBar(pData, nLength - ((dwMode & LM_LENGTHY) ? rcBorder.top + rcBorder.bottom : rcBorder.right + rcBorder.left), dwMode);
}
sizeResult = _CalcSize(pData, dwMode & LM_VERTDOCK);
}
if (nWidth > 0)
{
if (dwMode & LM_HORZDOCK)
sizeResult.cy = max(nWidth - rcBorder.top - rcBorder.bottom, sizeResult.cy);
else
sizeResult.cx = max(nWidth - rcBorder.right - rcBorder.left, sizeResult.cx);
}
if (dwMode & LM_STRETCH)
{
if (dwMode & LM_VERTDOCK)
sizeResult.cy = max(nLength - rcBorder.top - rcBorder.bottom, sizeResult.cy);
else
sizeResult.cx = max(nLength - rcBorder.right - rcBorder.left, sizeResult.cx);
}
_AdjustBorders(pData, sizeResult, dwMode, rcBorder);
if (dwMode & LM_COMMIT)
{
if (!(m_pParent->GetFlags() & xtpFlagSmartLayout))
_MoveRightAlligned(pData, sizeResult, rcBorder, dwMode);
for (i = 0; i < GetCount(); i++) pData[i].Detach();
}
delete[] pData;
}
else
{
sizeResult = CSize (23, 22) + CSize(rcBorder.left + rcBorder.right, rcBorder.top + rcBorder.bottom);
if (dwMode & LM_HORZDOCK) sizeResult.cy = max(nWidth, sizeResult.cy);
else sizeResult.cx = max(nWidth, sizeResult.cx);
}
return sizeResult;
}
void CXTPControls::_MakeSameWidth(int nStart, int nLast, int nWidth)
{
for (int i = nStart; i < nLast; i++)
{
CXTPControl* pControl = GetAt(i);
if (!pControl || pControl->GetParent() != m_pParent || !pControl->IsVisible())
continue;
CRect rc = pControl->GetRect();
pControl->SetRect(CRect(rc.left, rc.top, rc.left + nWidth, rc.bottom));
}
}
CSize CXTPControls::CalcPopupSize(CDC* pDC, int nLength, int nMRUWidth, const CRect& rcBorder)
{
RECT rcWork;
SystemParametersInfo(SPI_GETWORKAREA, NULL, &rcWork, 0);
int i;
CXTPPaintManager* pPaintManager = m_pParent->GetPaintManager();
CXTPFontDC fontControl(pDC, pPaintManager->GetCommandBarFont(m_pParent));
CSize szSeparators(pPaintManager->DrawCommandBarSeparator(NULL, m_pParent, NULL, FALSE));
CRect rcControl;
int yPos = rcBorder.top, nWidthColumn = 0, xPos = rcBorder.left, nFirstInColumn = 0, nHeight = 0;
m_pParent->m_bMultiLine = FALSE;
int nCount = GetCount();
BOOL bFirst = TRUE;
for (i = 0; i < nCount; i++)
{
CXTPControl* pControl = GetAt(i);
if (!pControl || pControl->GetParent() != m_pParent)
continue;
pControl->SetHideFlag(xtpHideScroll, FALSE);
if (!pControl->IsVisible())
continue;
CSize szControl = pControl->GetSize(pDC);
pControl->SetWrap(FALSE);
if ((pControl->GetFlags() & xtpFlagWrapRow && !bFirst) || (nLength > 0 && szControl.cy + yPos > nLength - rcBorder.bottom))
{
_MakeSameWidth(nFirstInColumn, i, nWidthColumn);
nHeight = max(yPos - rcBorder.top, nHeight);
yPos = rcBorder.top;
xPos += nWidthColumn + (pControl->GetBeginGroup() ? szSeparators.cx : 0);
pControl->SetWrap(TRUE);
nFirstInColumn = i;
nWidthColumn = 0;
m_pParent->m_bMultiLine = TRUE;
}
else if (pControl->GetBeginGroup() && !bFirst)
{
yPos += szSeparators.cy;
}
bFirst = FALSE;
if (!GetParent()->IsResizable() && CXTPPopupBar::m_dMaxWidthDivisor > 0 && szControl.cx > (CXTPPopupBar::m_dMaxWidthDivisor * rcWork.right))
szControl.cx = int(CXTPPopupBar::m_dMaxWidthDivisor * rcWork.right);
pControl->SetRect(CRect(xPos, yPos, xPos + szControl.cx, yPos + szControl.cy));
yPos += szControl.cy;
if (nWidthColumn < szControl.cx) nWidthColumn = szControl.cx;
}
if (nMRUWidth > 0 && nMRUWidth < 30000)
nWidthColumn = nMRUWidth - rcBorder.left - rcBorder.right;
_MakeSameWidth(nFirstInColumn, GetCount(), nWidthColumn);
int nWidth = xPos - rcBorder.left + nWidthColumn;
nHeight = max(yPos - rcBorder.top, nHeight);
for (i = 0; i < nCount; i++)
{
CXTPControl* pControl = GetAt(i);
pControl->SetRowRect(CRect(pControl->GetRect().left, rcBorder.top, pControl->GetRect().right, rcBorder.top + nHeight));
}
nWidth = max(24, nWidth);
nHeight = (nHeight == 0 ? 22 : nHeight);
return CSize(nWidth + rcBorder.left + rcBorder.right, nHeight + rcBorder.bottom + rcBorder.top);
}
void CXTPControls::Copy(CXTPControls* pControls, BOOL bRecursive)
{
RemoveAll();
for (int i = 0; i < pControls->GetCount(); i++)
{
if (!pControls->GetAt(i)->m_bTemporary)
AddClone(pControls->GetAt(i), -1, bRecursive);
}
if (pControls->m_pOriginalControls)
{
SetOriginalControls((CXTPOriginalControls*)pControls->m_pOriginalControls->Duplicate(bRecursive));
}
else
{
SetOriginalControls(NULL);
}
}
CXTPControls* CXTPControls::Duplicate(BOOL bRecursive)
{
CXTPControls* pControls = (CXTPControls*)GetRuntimeClass()->CreateObject();
for (int i = 0; i < GetCount(); i++)
{
if (!GetAt(i)->m_bTemporary)
pControls->AddClone(GetAt(i), -1, bRecursive);
}
if (m_pOriginalControls)
{
pControls->SetOriginalControls((CXTPOriginalControls*)m_pOriginalControls->Duplicate(bRecursive));
}
return pControls;
}
void CXTPControls::ClearOriginalControls()
{
CMDTARGET_RELEASE(m_pOriginalControls);
}
void CXTPControls::CreateOriginalControls()
{
ClearOriginalControls();
CXTPOriginalControls* pControls = new CXTPOriginalControls();
for (int i = 0; i < GetCount(); i++)
{
if (!GetAt(i)->m_bTemporary)
pControls->AddClone(GetAt(i), -1, TRUE);
}
SetOriginalControls(pControls);
}
void CXTPControls::SetOriginalControls(CXTPOriginalControls* pControls)
{
ClearOriginalControls();
m_pOriginalControls = pControls;
}
void CXTPControls::MoveBefore(CXTPControl* pControl, int nBefore)
{
ASSERT(pControl);
if (!pControl)
return;
ASSERT(pControl->GetControls() == this);
if (pControl->GetIndex() < nBefore) nBefore--;
m_arrControls.RemoveAt(pControl->GetIndex());
m_arrControls.InsertAt(nBefore, pControl);
RefreshIndexes();
}
BOOL CXTPControls::Compare(const CXTPControls* pOther)
{
int j = 0, i = 0;
while (i < GetCount() || j < pOther->GetCount())
{
while (i < GetCount() && GetAt(i)->m_bTemporary)
{
i++;
}
while (j < pOther->GetCount() && pOther->GetAt(j)->m_bTemporary)
{
j++;
}
if (i < GetCount() && j < pOther->GetCount())
{
if (!GetAt(i)->Compare(pOther->GetAt(j)))
return FALSE;
}
else
{
if (i < GetCount() || j < pOther->GetCount())
return FALSE;
}
i++;
j++;
}
return TRUE;
}
BOOL CXTPControls::IsChanged() const
{
if (!m_pOriginalControls)
return TRUE;
return !m_pOriginalControls->Compare(this);
}
int CXTPControls::CommandToIndex(int nIDFind) const
{
for (int iIndex = 0; iIndex < m_arrControls.GetSize(); ++iIndex)
{
CXTPControl* pControl = m_arrControls.GetAt(iIndex);
if (pControl && pControl->GetID() == nIDFind)
return iIndex;
}
return -1;
}
int CXTPControls::CompareByCaption(const CXTPControl** ppItem1, const CXTPControl** ppItem2)
{
CString strCaption1((*ppItem1)->GetCaption());
CString strCaption2((*ppItem2)->GetCaption());
XTPDrawHelpers()->StripMnemonics(strCaption1);
XTPDrawHelpers()->StripMnemonics(strCaption2);
return strCaption1.CompareNoCase(strCaption2);
}
void CXTPControls::Sort()
{
typedef int (_cdecl *GENERICCOMPAREFUNC)(const void *, const void*);
qsort(m_arrControls.GetData(), (size_t)m_arrControls.GetSize(), sizeof(CXTPControl*), (GENERICCOMPAREFUNC)CompareByCaption);
RefreshIndexes();
}