📄 tabctrl.h
字号:
{
CSize size(lpwndpos->cx, lpwndpos->cy);
m_wndUpDown.MoveWindow(size.cx - s_kcxUpDown, size.cy - s_kcyUpDown, s_kcxUpDown, s_kcyUpDown);
_ShowOrHideUpDownCtrl(CRect(0, 0, size.cx, size.cy));
if (m_dwTabCtrl2ExtendedStyle & TAB2_EX_MULTILINE) {
_UpdateMultiLineLayout(size.cx);
if (m_dwTabCtrl2ExtendedStyle & TAB2_EX_SUPPORTREBAR) {
RefreshBandInfo();
}
}
}
return 0;
}
bool _MustBeInvalidateOnMultiLine(CSize size)
{
CRect rc; GetClientRect(rc);
if (rc.Width() < size.cx) // expanding
return true;
int cxLeft = 0;
for (int i = 0; i < m_items.size(); ++i) {
cxLeft = max(m_items[i].m_rcItem.right, cxLeft);
}
if (cxLeft != 0 && cxLeft < size.cx) {
return false;
}
else
return true;
}
LRESULT OnEraseBackground(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled)
{
if (m_dwTabCtrl2ExtendedStyle & TAB2_EX_TRANSPARENT) {
bHandled = FALSE;
return 0;
}
RECT rect;
GetClientRect(&rect);
::FillRect((HDC)wParam, &rect, (HBRUSH)LongToPtr(COLOR_BTNFACE + 1));
return 1; // don't do the default erase
}
LRESULT OnPaint(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
if (wParam != NULL) {
_DoPaint((HDC)wParam);
}
else {
CPaintDC dc(m_hWnd);
_DoPaint(dc.m_hDC, &dc.m_ps.rcPaint);
}
return 0;
}
LRESULT OnLButtonDown(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
TCTRACE(_T("OnLButtonDown\n"));
POINT pt = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };
int nIndex = HitTest(pt);
if (nIndex != -1) {
ATLASSERT(_IsValidIndex(nIndex));
if ((wParam & MK_CONTROL) && GetCurSel() != nIndex) {
if (!_FindIndexFromCurMultiSelected(nIndex)) {
if (m_items[nIndex].ModifyState(TCISTATE_SELECTED, TCISTATE_MSELECTED))
InvalidateRect(m_items[nIndex].m_rcItem);
}
else {
if (m_items[nIndex].ModifyState(TCISTATE_MSELECTED, 0))
InvalidateRect(m_items[nIndex].m_rcItem);
}
}
else {
_PressItem(nIndex);
SetCapture();
}
}
return 0;
}
LRESULT OnLButtonUp(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
TCTRACE(_T("OnLButtonUp\n"));
POINT pt = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };
if (GetCapture() == m_hWnd) {
ReleaseCapture();
int nIndex = HitTest(pt);
if (nIndex != -1 && nIndex == m_nPressedIndex) {
TCTRACE(_T(" change current selelected item\n"));
ATLASSERT(_IsValidIndex(nIndex));
_PressItem();// always clean up pressed flag
SetCurSel(nIndex, true);
NMHDR nmhdr = { m_hWnd, GetDlgCtrlID(), TCN_SELCHANGE };
::SendMessage(GetParent(), WM_NOTIFY, (WPARAM)GetDlgCtrlID(), (LPARAM)&nmhdr);
}
else {
_PressItem();// always clean up pressed flag
}
}
return 0;
}
// Implementation
bool _FindIndexFromCurMultiSelected(int nIndex)
{
CSimpleArray<int> arrCurMultiSel;
GetCurMultiSel(arrCurMultiSel, false);
if (arrCurMultiSel.Find(nIndex) != -1)
return true;
return false;
}
// void _UpdateItems(int nFirst)
// {
// _InvalidateItemsRect(nFirst, m_items.size()); // first, invalidate prev rects
// _UpdateLayout(); // rect updated
// _InvalidateItemsRect(nFirst, m_items.size()); // add invalidate rects
// UpdateWindow(); // redraw now
// }
void _UpdateLayout()
{
if (m_items.size() == 0) {
m_arrSeparators.RemoveAll();
Invalidate();
if (m_dwTabCtrl2ExtendedStyle & TAB2_EX_SUPPORTREBAR)
RefreshBandInfo();
return;
}
CRect rc;
GetClientRect(&rc);
if (m_dwTabCtrl2ExtendedStyle & TAB2_EX_MULTILINE) {
_UpdateMultiLineLayout(rc.Width());
}
else {
_UpdateSingleLineLayout(m_nFirstIndexOnSingleLine);
}
_ShowOrHideUpDownCtrl(rc);
if (m_dwTabCtrl2ExtendedStyle & TAB2_EX_SUPPORTREBAR)
RefreshBandInfo();
UpdateWindow();
}
void _HotItem(int nNewHotIndex = -1)
{
TCTRACE(_T("_HotItem\n"));
// clean up
if (_IsValidIndex(m_nHotIndex)) {
TCTRACE(_T(" clean up - %d\n"), m_nHotIndex);
CTabCtrlItem& item = m_items[m_nHotIndex];
if (item.ModifyState(TCISTATE_HOT, 0))
InvalidateRect(item.m_rcItem);
}
m_nHotIndex = nNewHotIndex;
if (_IsValidIndex(m_nHotIndex)) {
TCTRACE(_T(" hot - %d\n"), m_nHotIndex);
CTabCtrlItem& item = m_items[m_nHotIndex];
if (item.ModifyState(0, TCISTATE_HOT))
InvalidateRect(item.m_rcItem);
}
}
void _PressItem(int nPressedIndex = -1)
{
TCTRACE(_T("_PressItem\n"));
// clean up prev
if (_IsValidIndex(m_nPressedIndex)) {
TCTRACE(_T(" clean up - %d\n"), m_nPressedIndex);
CTabCtrlItem& item = m_items[m_nPressedIndex];
if (item.ModifyState(TCISTATE_PRESSED, 0))
InvalidateRect(item.m_rcItem);
}
m_nPressedIndex = nPressedIndex;
if (_IsValidIndex(m_nPressedIndex)) {
TCTRACE(_T(" press - %d\n"), m_nPressedIndex);
CTabCtrlItem& item = m_items[m_nPressedIndex];
if (item.ModifyState(0, TCISTATE_PRESSED))
InvalidateRect(item.m_rcItem);
}
}
void _ResetMultiSelectedItems()
{
for (int i = 0; i < m_items.size(); ++i) {
if (m_items[i].ModifyState(TCISTATE_MSELECTED, 0))
InvalidateRect(m_items[i].m_rcItem);
}
}
void _DoPaint(CDCHandle dc, LPCRECT lpRect = NULL)
{
CFontHandle fontOld = dc.SelectFont(m_font.m_hFont);
int modeOld = dc.SetBkMode(TRANSPARENT);
int i = m_dwTabCtrl2ExtendedStyle & TAB2_EX_MULTILINE ? 0 : m_nFirstIndexOnSingleLine;
for (; i < m_items.size(); ++i) {
if (lpRect == NULL || MtlIsCrossRect(m_items[i].m_rcItem, lpRect)) {
m_items[i].Update(dc.m_hDC, m_imgs.m_hImageList, _check_flag(TAB2_EX_ANCHORCOLOR, m_dwTabCtrl2ExtendedStyle));
}
}
_DrawSeparators(dc, lpRect);
dc.SelectFont(fontOld);
dc.SetBkMode(modeOld);
}
void _UpdateSingleLineLayout(int nFirstIndex, bool bForce = false)
{
TCTRACE(_T("_UpdateSingleLineLayout index(%d)\n"), nFirstIndex);
ATLASSERT(_IsValidIndex(nFirstIndex));
m_arrSeparators.RemoveAll();
// clean invisible items
int i;
for (i = 0; i < nFirstIndex && i < m_items.size(); ++i) {
m_items[i].m_rcItem.SetRectEmpty();
}
int cxOffset = 0;//s_kcxGap;
for (i = nFirstIndex; i < m_items.size(); ++i) {
CTabCtrlItem& item = m_items[i];
CRect rcSrc = item.m_rcItem;
// update the rect
if (m_dwTabCtrl2ExtendedStyle & TAB2_EX_FIXEDSIZE)
item.m_rcItem = CRect(cxOffset, 0, cxOffset + m_sizeItem.cx, m_sizeItem.cy);
else
item.m_rcItem = _MeasureItem(m_items[i].m_strItem) + CPoint(cxOffset, 0);
cxOffset = cxOffset + item.m_rcItem.Width();
cxOffset += s_kcxGap;
m_arrSeparators.Add(CPoint(cxOffset, 0));
cxOffset += s_kcxSeparator + s_kcxGap;
//
if (bForce || rcSrc != item.m_rcItem) {
InvalidateRect(_InflateGapWidth(rcSrc));
InvalidateRect(_InflateGapWidth(item.m_rcItem));
}
}
}
void _UpdateMultiLineLayout(int nWidth)
{
TCTRACE(_T("_UpdateMultiLineLayout\n"));
m_arrSeparators.RemoveAll();
int cxOffset = 0;
int cyOffset = 0;
for (int i = 0; i < m_items.size(); ++i) {
CTabCtrlItem& item = m_items[i];
CRect rcSrc = item.m_rcItem;
// update the rect
if (m_dwTabCtrl2ExtendedStyle & TAB2_EX_FIXEDSIZE)
item.m_rcItem = CRect(cxOffset, cyOffset, cxOffset + m_sizeItem.cx, cyOffset + m_sizeItem.cy);
else
item.m_rcItem = _MeasureItem(m_items[i].m_strItem) + CPoint(cxOffset, cyOffset);
if (i != 0 && item.m_rcItem.right > nWidth) { // do wrap
cxOffset = 0;
cyOffset += GetItemHeight() + s_kcyGap;
if (m_dwTabCtrl2ExtendedStyle & TAB2_EX_FIXEDSIZE)
item.m_rcItem = CRect(cxOffset, cyOffset, cxOffset + m_sizeItem.cx, cyOffset + m_sizeItem.cy);
else
item.m_rcItem = _MeasureItem(m_items[i].m_strItem) + CPoint(cxOffset, cyOffset);
}
cxOffset = cxOffset + m_items[i].m_rcItem.Width();
cxOffset += s_kcxGap;
m_arrSeparators.Add(CPoint(cxOffset, cyOffset));
cxOffset += s_kcxSeparator + s_kcxGap;
//
if (rcSrc != item.m_rcItem) {
InvalidateRect(_InflateGapWidth(rcSrc));
InvalidateRect(_InflateGapWidth(item.m_rcItem));
}
}
}
void _ShowOrHideUpDownCtrl(const CRect& rcClient)
{
TCTRACE(_T("_ShowOrHideUpDownCtrl\n"));
if ((m_dwTabCtrl2ExtendedStyle & TAB2_EX_MULTILINE) || m_items.size() < 1) {
m_wndUpDown.ShowWindow(SW_HIDE);
return;
}
m_wndUpDown.SetRange(0, GetItemCount());
if (m_nFirstIndexOnSingleLine != 0) {
m_wndUpDown.ShowWindow(SW_SHOWNORMAL);
return;
}
else if (m_items[m_items.size() - 1].m_rcItem.right > rcClient.right) {
TCTRACE(_T(" show!\n"));
m_wndUpDown.ShowWindow(SW_SHOWNORMAL);
return;
}
m_wndUpDown.ShowWindow(SW_HIDE);
}
CRect _MeasureItem(const CString& strText)
{
if (m_dwTabCtrl2ExtendedStyle & TAB2_EX_FIXEDSIZE)
return CRect(0, 0, m_sizeItem.cx, m_sizeItem.cy);
// compute size of text - use DrawText with DT_CALCRECT
int cx = MtlComputeWidthOfText(strText, m_font);
int cxIcon = 0, cyIcon = 0;
if (m_imgs.m_hImageList != NULL)
m_imgs.GetIconSize(cxIcon, cyIcon);
LOGFONT lf;
m_font.GetLogFont(lf);
int cy = lf.lfHeight;
if(cy < 0)
cy = -cy;
cy += 2 * s_kcyTextMargin;
// height of item is the bigger of these two
cy = MtlMax(cy, cyIcon);
// width is width of text plus a bunch of stuff
cx += 2 * s_kcxTextMargin; // L/R margin for readability
// ATLTRACE(_T("(cx, cy) = (%d, %d)\n"), cx, cy);
return CRect(0, 0, cx, cy);
}
int _GetRequiredHeight()
{
if (GetItemCount () == 0) {
return GetItemHeight();
}
else {
return m_items[m_items.size() - 1].m_rcItem.bottom;
}
return 0;
}
bool _IsValidIndex(int nIndex)
{
if (0 <= nIndex && nIndex < m_items.size())
return true;
else
return false;
}
void _ClearAll()
{
m_items.clear();
}
CRect _InflateGapWidth(const CRect& rc)
{
int cxSeparatorOffset = s_kcxGap*2 + s_kcxSeparator;
return CRect(rc.left, rc.top, rc.right + cxSeparatorOffset, rc.bottom);
}
// void _InvalidateItemsRect(int nFirst, int nLast, bool bAlsoSeparator = true)
// {
// int cxSeparatorOffset = bAlsoSeparator ? s_kcxGap*2 + s_kcxSeparator : 0;
//
// for (int i = nFirst; i < nLast; ++i) {
// CRect rc = m_items[i].m_rcItem;
// InvalidateRect(CRect(rc.left, rc.top, rc.right + cxSeparatorOffset, rc.bottom));
// }
// }
// void _InvalidateItemRect(int nIndex, bool bAlsoSepartor = true)
// {
// int cxSeparatorOffset = bAlsoSeparator ? s_kcxGap*2 + s_kcxSeparator : 0;
//
// InvalidateRect(CRect(rc.left, rc.top, rc.right + cxSeparatorOffset, rc.bottom));
// }
void _DrawSeparators(CDCHandle dc, LPCRECT lpRect = NULL)
{
int cy = GetItemHeight();
CRect rect(lpRect);
for (int i = 0; i < m_arrSeparators.GetSize(); ++i) {
CPoint& pt = m_arrSeparators[i];
CRect rc(pt.x, pt.y + 2, pt.x + 2, pt.y + cy - 2);
if (lpRect == NULL || MtlIsCrossRect(rc, lpRect)) {
dc.DrawEdge(rc, EDGE_ETCHED, BF_LEFT); // draw separator line
}
}
}
void GetSystemSettings()
{
// refresh our font
NONCLIENTMETRICS info;
info.cbSize = sizeof(info);
::SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(info), &info, 0);
LOGFONT logfont;
memset(&logfont, 0, sizeof(LOGFONT));
if(m_font.m_hFont != NULL)
m_font.GetLogFont(logfont);
if(logfont.lfHeight != info.lfMenuFont.lfHeight ||
logfont.lfWidth != info.lfMenuFont.lfWidth ||
logfont.lfEscapement != info.lfMenuFont.lfEscapement ||
logfont.lfOrientation != info.lfMenuFont.lfOrientation ||
logfont.lfWeight != info.lfMenuFont.lfWeight ||
logfont.lfItalic != info.lfMenuFont.lfItalic ||
logfont.lfUnderline != info.lfMenuFont.lfUnderline ||
logfont.lfStrikeOut != info.lfMenuFont.lfStrikeOut ||
logfont.lfCharSet != info.lfMenuFont.lfCharSet ||
logfont.lfOutPrecision != info.lfMenuFont.lfOutPrecision ||
logfont.lfClipPrecision != info.lfMenuFont.lfClipPrecision ||
logfont.lfQuality != info.lfMenuFont.lfQuality ||
logfont.lfPitchAndFamily != info.lfMenuFont.lfPitchAndFamily ||
lstrcmp(logfont.lfFaceName, info.lfMenuFont.lfFaceName) != 0)
{
HFONT hFontMenu = ::CreateFontIndirect(&info.lfMenuFont);
ATLASSERT(hFontMenu != NULL);
if(hFontMenu != NULL)
{
if(m_font.m_hFont != NULL)
m_font.DeleteObject();
m_font.Attach(hFontMenu);
SetFont(m_font);
}
}
}
void _InitToolTip()
{
// create a tool tip
m_tip.Create(m_hWnd);
ATLASSERT(m_tip.IsWindow());
CToolInfo tinfo(TTF_SUBCLASS, m_hWnd);
tinfo.hwnd = m_hWnd; // WTL always sucks...
m_tip.AddTool(tinfo);
m_tip.SetMaxTipWidth(SHRT_MAX);
}
};
class CTabCtrl2 : public CTabCtrl2Impl<CTabCtrl2>
{
public:
DECLARE_WND_CLASS_EX(_T("MTL_TabCtrl2"), CS_DBLCLKS, COLOR_BTNFACE)
};
////////////////////////////////////////////////////////////////////////////
} //namespace MTL
#ifndef _MTL_NO_AUTOMATIC_NAMESPACE
using namespace MTL;
#endif //!_MTL_NO_AUTOMATIC_NAMESPACE
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -