📄 dotnettabctrl.h
字号:
{
// Tab is not selected
bool bHighlighted = (CDIS_MARKED == (lpNMCustomDraw->nmcd.uItemState & CDIS_MARKED));
int nItem = (int)lpNMCustomDraw->nmcd.dwItemSpec;
WTL::CDCHandle dc( lpNMCustomDraw->nmcd.hdc );
if(bHighlighted)
{
if(CTCS_BOTTOM == (dwStyle & CTCS_BOTTOM))
{
RECT rcHighlight = {rcTab.left+1, rcTab.top+3, rcTab.right-2, rcTab.bottom-1};
if(nItem - 1 == m_iCurSel) rcHighlight.left += 1; // Item to the right of the selected tab
dc.FillSolidRect(&rcHighlight, lpNMCustomDraw->clrHighlight);
}
else
{
RECT rcHighlight = {rcTab.left+1, rcTab.top+2, rcTab.right-2, rcTab.bottom-2};
if(nItem - 1 == m_iCurSel) rcHighlight.left += 1; // Item to the right of the selected tab
dc.FillSolidRect(&rcHighlight, lpNMCustomDraw->clrHighlight);
}
}
// Draw division line on right, unless we're the item
// on the left of the selected tab
if(nItem + 1 == m_iCurSel)
{
// Item just left of selected tab
}
else
{
WTL::CPen pen;
pen.CreatePen(PS_SOLID, 1, lpNMCustomDraw->clrBtnShadow);
WTL::CPenHandle penOld = dc.SelectPen(pen);
if(CTCS_BOTTOM == (dwStyle & CTCS_BOTTOM))
{
// Important! Be sure and keep within "our" tab area horizontally
dc.MoveTo(rcTab.right-1, rcTab.top + 3);
dc.LineTo(rcTab.right-1, rcTab.bottom - 1);
}
else
{
// Important! Be sure and keep within "our" tab area horizontally
dc.MoveTo(rcTab.right-1, rcTab.top + 2);
dc.LineTo(rcTab.right-1, rcTab.bottom - 2);
}
dc.SelectPen(penOld);
}
}
void DrawItem_ImageAndText(DWORD /*dwStyle*/, LPNMCTCCUSTOMDRAW lpNMCustomDraw, int nIconVerticalCenter, RECT& rcTab, RECT& rcText)
{
WTL::CDCHandle dc( lpNMCustomDraw->nmcd.hdc );
bool bHighlighted = (CDIS_MARKED == (lpNMCustomDraw->nmcd.uItemState & CDIS_MARKED));
bool bSelected = (CDIS_SELECTED == (lpNMCustomDraw->nmcd.uItemState & CDIS_SELECTED));
bool bHot = (CDIS_HOT == (lpNMCustomDraw->nmcd.uItemState & CDIS_HOT));
int nItem = (int)lpNMCustomDraw->nmcd.dwItemSpec;
TItem* pItem = this->GetItem(nItem);
HFONT hOldFont = NULL;
if(bSelected)
{
hOldFont = dc.SelectFont(lpNMCustomDraw->hFontSelected);
}
else
{
hOldFont = dc.SelectFont(lpNMCustomDraw->hFontInactive);
}
COLORREF crPrevious = 0;
if(bHighlighted)
{
crPrevious = dc.SetTextColor(lpNMCustomDraw->clrHighlightText);
}
else if(bHot)
{
crPrevious = dc.SetTextColor(lpNMCustomDraw->clrHighlightHotTrack);
}
else if(bSelected)
{
crPrevious = dc.SetTextColor(lpNMCustomDraw->clrTextSelected);
}
else
{
crPrevious = dc.SetTextColor(lpNMCustomDraw->clrTextInactive);
}
//--------------------------------------------
// This is how CDotNetTabCtrlImpl interprets padding, margin, etc.:
//
// M - Margin
// P - Padding
// I - Image
// Text - Tab Text
//
// With image:
// __________________________
//
// | M | I | P | Text | P | M |
// --------------------------
//
// Without image:
// ______________________
//
// | M | P | Text | P | M |
// ----------------------
//rcText.left += (bSelected ? m_settings.iSelMargin : m_settings.iMargin);
rcText.left += m_settings.iMargin;
rcText.right -= m_settings.iMargin;
if (pItem->UsingImage() && !m_imageList.IsNull())
{
// Draw the image.
IMAGEINFO ii = {0};
int nImageIndex = pItem->GetImageIndex();
m_imageList.GetImageInfo(nImageIndex, &ii);
if((ii.rcImage.right - ii.rcImage.left) < (rcTab.right - rcTab.left))
{
int nImageHalfHeight = (ii.rcImage.bottom - ii.rcImage.top) / 2;
m_imageList.Draw(dc, nImageIndex, rcText.left, nIconVerticalCenter - nImageHalfHeight + m_nFontSizeTextTopOffset, ILD_NORMAL);
}
// Offset on the right of the image.
rcText.left += (ii.rcImage.right - ii.rcImage.left);
}
if (rcText.left + m_nMinWidthToDisplayText < rcText.right)
{
::InflateRect(&rcText, -m_settings.iPadding, 0);
_CSTRING_NS::CString sText = pItem->GetText();
dc.DrawText(sText, sText.GetLength(), &rcText, DT_LEFT | DT_VCENTER | DT_SINGLELINE | DT_END_ELLIPSIS);
}
dc.SetTextColor(crPrevious);
dc.SelectFont(hOldFont);
}
void DrawCloseButton(LPNMCTCCUSTOMDRAW lpNMCustomDraw)
{
WTL::CDCHandle dc( lpNMCustomDraw->nmcd.hdc );
WTL::CPen penButtons;
penButtons.CreatePen(PS_SOLID, 1, lpNMCustomDraw->clrTextInactive);
WTL::CBrush brushArrow;
brushArrow.CreateSolidBrush(lpNMCustomDraw->clrTextInactive);
WTL::CPenHandle penOld = dc.SelectPen(penButtons);
WTL::CBrushHandle brushOld = dc.SelectBrush(brushArrow);
RECT rcX = m_rcCloseButton;
if(ectcMouseDownL_CloseButton == (m_dwState & ectcMouseDown))
{
if(ectcMouseOver_CloseButton == (m_dwState & ectcMouseOver))
{
::OffsetRect(&rcX, 1, 1);
}
}
const int sp = 4;
dc.MoveTo(rcX.left+sp+ -1, rcX.top+sp);
dc.LineTo(rcX.right-sp -1, rcX.bottom-sp);
dc.MoveTo(rcX.left+sp, rcX.top+sp);
dc.LineTo(rcX.right-sp, rcX.bottom-sp);
dc.MoveTo(rcX.left+sp -1, rcX.bottom-sp -1);
dc.LineTo(rcX.right-sp -1, rcX.top+sp -1 );
dc.MoveTo(rcX.left+sp, rcX.bottom-sp -1);
dc.LineTo(rcX.right-sp, rcX.top+sp -1);
if(ectcMouseDownL_CloseButton == (m_dwState & ectcMouseDown))
{
if(ectcMouseOver_CloseButton == (m_dwState & ectcMouseOver))
{
dc.DrawEdge(&m_rcCloseButton, BDR_SUNKENOUTER, BF_RECT);
}
}
else if(ectcHotTrack_CloseButton == (m_dwState & ectcHotTrack))
{
dc.DrawEdge(&m_rcCloseButton, BDR_RAISEDINNER, BF_RECT);
}
dc.SelectBrush(brushOld);
dc.SelectPen(penOld);
}
void DrawScrollButtons(LPNMCTCCUSTOMDRAW lpNMCustomDraw)
{
WTL::CDCHandle dc( lpNMCustomDraw->nmcd.hdc );
WTL::CPen penButtons;
penButtons.CreatePen(PS_SOLID, 1, lpNMCustomDraw->clrTextInactive);
WTL::CBrush brushArrow;
brushArrow.CreateSolidBrush(lpNMCustomDraw->clrTextInactive);
WTL::CPenHandle penOld = dc.SelectPen(penButtons);
WTL::CBrushHandle brushOld = dc.SelectBrush(brushArrow);
RECT rcArrowRight = m_rcScrollRight;
RECT rcArrowLeft = m_rcScrollLeft;
if(ectcMouseDownL_ScrollRight == (m_dwState & ectcMouseDown))
{
if(ectcMouseOver_ScrollRight == (m_dwState & ectcMouseOver))
{
if(ectcOverflowRight == (m_dwState & ectcOverflowRight))
{
::OffsetRect(&rcArrowRight, 1, 1);
}
}
}
if(ectcMouseDownL_ScrollLeft == (m_dwState & ectcMouseDown))
{
if(ectcMouseOver_ScrollLeft == (m_dwState & ectcMouseOver))
{
if(ectcOverflowLeft == (m_dwState & ectcOverflowLeft))
{
::OffsetRect(&rcArrowLeft, 1, 1);
}
}
}
const int spRight = 5;
const int spLeft = 6;
POINT ptsArrowRight[] = {
{rcArrowRight.left+spRight, rcArrowRight.top+spRight -2},
{rcArrowRight.left+spRight, rcArrowRight.bottom-spRight +1},
{rcArrowRight.right-spRight -1, (rcArrowRight.bottom + m_rcScrollRight.top) / 2},
{rcArrowRight.left+spRight, rcArrowRight.top+spRight -2}
};
if(ectcOverflowRight != (m_dwState & ectcOverflowRight))
{
dc.Polyline(ptsArrowRight, 4);
}
else
{
dc.Polygon(ptsArrowRight, 4);
if(ectcMouseDownL_ScrollRight == (m_dwState & ectcMouseDown))
{
if(ectcMouseOver_ScrollRight == (m_dwState & ectcMouseOver))
{
dc.DrawEdge(&m_rcScrollRight, BDR_SUNKENOUTER, BF_RECT);
}
}
else if(ectcHotTrack_ScrollRight == (m_dwState & ectcHotTrack))
{
dc.DrawEdge(&m_rcScrollRight, BDR_RAISEDINNER, BF_RECT);
}
}
POINT ptsArrowLeft[] = {
{rcArrowLeft.right-spLeft, rcArrowLeft.top+spLeft -3},
{rcArrowLeft.right-spLeft, rcArrowLeft.bottom-spLeft +2},
{rcArrowLeft.left+spLeft -1, (rcArrowLeft.bottom + m_rcScrollLeft.top) / 2},
{rcArrowLeft.right-spLeft, rcArrowLeft.top+spLeft -3}
};
if(ectcOverflowLeft != (m_dwState & ectcOverflowLeft))
{
dc.Polyline(ptsArrowLeft, 4);
}
else
{
dc.Polygon(ptsArrowLeft, 4);
if(ectcMouseDownL_ScrollLeft == (m_dwState & ectcMouseDown))
{
if(ectcMouseOver_ScrollLeft == (m_dwState & ectcMouseOver))
{
dc.DrawEdge(&m_rcScrollLeft, BDR_SUNKENOUTER, BF_RECT);
}
}
else if(ectcHotTrack_ScrollLeft == (m_dwState & ectcHotTrack))
{
dc.DrawEdge(&m_rcScrollLeft, BDR_RAISEDINNER, BF_RECT);
}
}
dc.SelectBrush(brushOld);
dc.SelectPen(penOld);
}
// Overrides for painting from CCustomTabCtrl
public:
void InitializeDrawStruct(LPNMCTCCUSTOMDRAW lpNMCustomDraw)
{
//DWORD dwStyle = this->GetStyle();
lpNMCustomDraw->hFontInactive = m_font;
lpNMCustomDraw->hFontSelected = m_fontSel;
lpNMCustomDraw->hBrushBackground = m_hbrBackground;
lpNMCustomDraw->clrTextSelected = ::GetSysColor(COLOR_BTNTEXT);
lpNMCustomDraw->clrTextInactive = m_clrTextInactiveTab;
lpNMCustomDraw->clrSelectedTab = m_clrSelectedTab;
lpNMCustomDraw->clrBtnFace = ::GetSysColor(COLOR_BTNFACE);
lpNMCustomDraw->clrBtnShadow = ::GetSysColor(COLOR_BTNSHADOW);
lpNMCustomDraw->clrBtnHighlight = ::GetSysColor(COLOR_BTNHIGHLIGHT);
lpNMCustomDraw->clrBtnText = ::GetSysColor(COLOR_BTNTEXT);
lpNMCustomDraw->clrHighlight = ::GetSysColor(COLOR_HIGHLIGHT);
#if WINVER >= 0x0500 || _WIN32_WINNT >= 0x0500
lpNMCustomDraw->clrHighlightHotTrack = ::GetSysColor(COLOR_HOTLIGHT);
#else
lpNMCustomDraw->clrHighlightHotTrack = ::GetSysColor(COLOR_HIGHLIGHT);
#endif
lpNMCustomDraw->clrHighlightText = ::GetSysColor(COLOR_HIGHLIGHTTEXT);
}
void DoPrePaint(RECT rcClient, LPNMCTCCUSTOMDRAW lpNMCustomDraw)
{
T* pT = static_cast<T*>(this);
pT->DrawBackground(rcClient, lpNMCustomDraw);
}
void DoItemPaint(LPNMCTCCUSTOMDRAW lpNMCustomDraw)
{
T* pT = static_cast<T*>(this);
bool bSelected = (CDIS_SELECTED == (lpNMCustomDraw->nmcd.uItemState & CDIS_SELECTED));
// NOTE: lpNMCustomDraw->nmcd.rc is in logical coordinates
RECT &rcItem = lpNMCustomDraw->nmcd.rc;
DWORD dwStyle = pT->GetStyle();
RECT rcTab = rcItem;
RECT rcText = rcItem;
int nIconVerticalCenter = 0;
pT->DrawItem_InitBounds(dwStyle, rcItem, rcTab, rcText, nIconVerticalCenter);
if(bSelected)
{
pT->DrawItem_TabSelected(dwStyle, lpNMCustomDraw, rcTab);
}
else
{
pT->DrawItem_TabInactive(dwStyle, lpNMCustomDraw, rcTab);
}
pT->DrawItem_ImageAndText(dwStyle, lpNMCustomDraw, nIconVerticalCenter, rcTab, rcText);
}
void DoPostPaint(RECT /*rcClient*/, LPNMCTCCUSTOMDRAW lpNMCustomDraw)
{
T* pT = static_cast<T*>(this);
DWORD dwStyle = this->GetStyle();
if(0 == (dwStyle & (CTCS_CLOSEBUTTON | CTCS_SCROLL)))
{
return;
}
// Close Button
if(CTCS_CLOSEBUTTON == (dwStyle & CTCS_CLOSEBUTTON))
{
if( (m_iCurSel >= 0) && ((size_t)m_iCurSel < m_Items.GetCount()) )
{
TItem* pItem = m_Items[m_iCurSel];
ATLASSERT(pItem != NULL);
if((pItem != NULL) && pItem->CanClose())
{
pT->DrawCloseButton(lpNMCustomDraw);
}
}
}
// Scroll Buttons
if(CTCS_SCROLL == (dwStyle & CTCS_SCROLL))
{
pT->DrawScrollButtons(lpNMCustomDraw);
}
}
// Overrides from CCustomTabCtrl
public:
void CalcSize_NonClient(LPRECT prcTabItemArea)
{
// account for "non-client" areas
// TODO: For the short term, we will use this
// for the non-client areas on the left and right.
// The drawing code for the tabs already accounts
// for the "non-client" areas on the top and bottom, and
// would need to be updated if we account for it here.
// Tab item rect methods also would need to be
// updated to account for the non-client areas
// on top and bottom (and effected drawing code
// would need to be updated).
DWORD dwStyle = this->GetStyle();
if(CTCS_BOTTOM == (dwStyle & CTCS_BOTTOM))
{
// TODO: Update to actually specify the
// non-client areas, and adjust all of the
// effected drawing code, as well as
// tab item rect related things
//prcTabItemArea->top += 3;
}
else
{
prcTabItemArea->left += 2;
prcTabItemArea->right -= 2;
// TODO: Update to actually specify the top and bottom
// non-client areas, and adjust all of the
// effected drawing code, as well as
// tab item rect related things
//prcTabItemArea->top += 1;
//// We would have bottom as 3, but we want the
//// selected tab to actually paint over highlight part
//prcTabItemArea->bottom -= 2;
}
}
void CalcSize_CloseButton(LPRECT prcTabItemArea)
{
//int nButtonSizeX = ::GetSystemMetrics(SM_CXSMSIZE);
//int nButtonSizeY = ::GetSystemMetrics(SM_CYSMSIZE);
// NOTE: After several tests, VS.Net does NOT depend on
// any system metric for the button size, so neither will we.
int nButtonSizeX = 15;
int nButtonSizeY = 15;
if((prcTabItemArea->right - prcTabItemArea->left) < nButtonSizeX)
{
::SetRectEmpty(&m_rcCloseButton);
return;
}
m_rcCloseButton = *prcTabItemArea;
DWORD dwStyle = this->GetStyle();
if (CTCS_BOTTOM == (dwStyle & CTCS_BOTTOM))
{
m_rcCloseButton.top += 3;
m_rcCloseButton.right -= 3;
}
else
{
m_rcCloseButton.top += 1;
m_rcCloseButton.bottom -= 2;
m_rcCloseButton.right -= 2;
}
m_rcCloseButton.top = (m_rcCloseButton.bottom + m_rcCloseButton.top - nButtonSizeY) / 2;
m_rcCloseButton.bottom = m_rcCloseButton.top + nButtonSizeY;
m_rcCloseButton.left = m_rcCloseButton.right - (nButtonSizeX);
if(m_tooltip.IsWindow())
{
m_tooltip.SetToolRect(m_hWnd, (UINT)ectcToolTip_Close, &m_rcCloseButton);
}
// Adjust the tab area
prcTabItemArea->right = m_rcCloseButton.left;
}
void CalcSize_ScrollButtons(LPRECT prcTabItemArea)
{
//int nButtonSizeX = ::GetSystemMetrics(SM_CXSMSIZE);
//int nButtonSizeY = ::GetSystemMetrics(SM_CYSMSIZE);
// NOTE: After several tests, VS.Net does NOT depend on
// any system metric for the button size, so neither will we.
int nButtonSizeX = 15;
int nButtonSizeY = 15;
if((prcTabItemArea->right - prcTabItemArea->left) < nButtonSizeX)
{
::SetRectEmpty(&m_rcScrollRight);
::SetRectEmpty(&m_rcScrollLeft);
return;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -