📄 collapsiblepanel.h
字号:
if( m_cxLastWidth == 0 ) return;
// Need to recreate all buttons because view changed
for( int i = 0; i < m_aPanels.GetSize(); i++ ) {
if( m_aPanels[i].hbmpButton != NULL ) {
::DeleteObject(m_aPanels[i].hbmpButton);
m_aPanels[i].hbmpButton = NULL;
}
}
// Calculate button size
CClientDC dc = m_hWnd;
HFONT hOldFont = dc.SelectFont(GetFont());
TEXTMETRIC tm = { 0 };
dc.GetTextMetrics(&tm);
dc.SelectFont(hOldFont);
SIZE szIcons = { 0 };
if( !m_Images.IsNull() ) m_Images.GetIconSize(szIcons);
m_cyBar = max(16 + 6, tm.tmHeight + 6);
m_cyButton = max(m_cyBar, szIcons.cy + IMAGE_GAP);
// Repaint
Invalidate();
}
void _RecalcScrollBar()
{
// Scrollbar support by Anatoly Ivasyuk.
// Check that we can manipulate the scrollbar
if( (m_dwExtStyle & CPS_EX_NOSCROLLBAR) == 0 )
{
// Get the location of the last panel in the list
RECT rc = GetPanelRect(GetItemCount() - 1, FALSE);
// Update the scroll bar based on the total height
SCROLLINFO si;
si.cbSize = sizeof(si);
si.fMask = SIF_RANGE | SIF_PAGE;
si.nMin = 0;
si.nMax = rc.bottom + m_szMargin.cy;
si.nPage = m_cyLastHeight - GetScrollPos(SB_VERT);
SetScrollInfo(SB_VERT, &si, TRUE);
}
}
void _RearrangePanels()
{
for( int i = 0; i < m_aPanels.GetSize(); i++ ) {
RECT rc = GetPanelRect(i, FALSE);
::SetWindowPos(m_aPanels[i].hWnd, NULL, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, SWP_NOZORDER | SWP_NOACTIVATE);
}
Invalidate();
}
void _CreateButton(CDCHandle dc, int iIndex, RECT rcItem)
{
// Create bitmap for button-background
PANEL& panel = m_aPanels[iIndex];
::OffsetRect(&rcItem, -rcItem.left, -rcItem.top);
int cx = rcItem.right - rcItem.left;
int cy = rcItem.bottom - rcItem.top;
CDC dcMem;
dcMem.CreateCompatibleDC(dc);
CBitmapHandle bmp;
bmp.CreateCompatibleBitmap(dc, cx, cy);
HBITMAP hOldBmp = dcMem.SelectBitmap(bmp);
// Clear background
dcMem.FillSolidRect(&rcItem, m_Theme.clrBack);
// Figure out colors
COLORREF clrBar1 = panel.clrBar1;
if( clrBar1 == CLR_INVALID ) clrBar1 = m_Theme.clrBarActive1;
if( iIndex == m_iCurSel && (m_dwExtStyle & CPS_EX_SELHIGHLIGHT) != 0 ) clrBar1 = m_Theme.clrBarSel1;
if( !panel.bEnabled ) clrBar1 = m_Theme.clrBarInactive1;
COLORREF clrBar2 = panel.clrBar2;
if( clrBar2 == CLR_INVALID ) clrBar2 = m_Theme.clrBarActive2;
if( iIndex == m_iCurSel && (m_dwExtStyle & CPS_EX_SELHIGHLIGHT) != 0 ) clrBar2 = m_Theme.clrBarSel2;
if( !panel.bEnabled ) clrBar2 = m_Theme.clrBarInactive2;
// Draw stuff
if( (m_dwExtStyle & CPS_EX_OWNERDRAW) != 0 )
{
#ifndef ODS_INACTIVE
const UINT ODS_INACTIVE = 0x0080;
#endif
DRAWITEMSTRUCT dis = { 0 };
dis.CtlID = GetDlgCtrlID();
dis.CtlType = ODT_STATIC;
dis.itemAction = ODA_DRAWENTIRE;
dis.hwndItem = m_hWnd;
dis.hDC = dc;
dis.itemID = iIndex;
dis.itemState = 0;
if( m_iCurSel == iIndex ) dis.itemState |= ODS_SELECTED;
if( !panel.bExpanded ) dis.itemState |= ODS_INACTIVE;
if( !panel.bEnabled ) dis.itemState |= ODS_DISABLED;
dis.rcItem = GetPanelRect(iIndex, FALSE);
::SendMessage(GetParent(), WM_DRAWITEM, (WPARAM) dis.CtlID, (LPARAM) &dis);
}
else if( (m_dwExtStyle & CPS_EX_FLATSTYLE) != 0 )
{
CPen pen;
pen.CreatePen(PS_SOLID, 1, clrBar2);
CBrush brush;
brush.CreateSolidBrush(clrBar1);
HPEN hOldPen = dcMem.SelectPen(pen);
HBRUSH hOldBrush = dcMem.SelectBrush(brush);
dcMem.Rectangle(&rcItem);
dcMem.SelectBrush(hOldBrush);
dcMem.SelectPen(hOldPen);
}
else
{
// Prepare brushes and pens
CPen pen;
pen.CreatePen(PS_SOLID, 1, clrBar2);
CBrush brush;
brush.CreateSolidBrush(clrBar1);
HPEN hOldPen = dcMem.SelectPen(pen);
HBRUSH hOldBrush = dcMem.SelectBrush(brush);
// Create clip region
CRgn rgn;
rgn.CreateRoundRectRgn(rcItem.left, rcItem.top, rcItem.right, rcItem.bottom + 666, m_Theme.iArc, m_Theme.iArc);
dcMem.SelectClipRgn(rgn);
// Paint gradient
if( dcMem.GetDeviceCaps(BITSPIXEL) > 8 ) {
// This will make 2^6 = 64 fountain steps
const int nShift = 6;
int nSteps = 1 << nShift;
for( int i = 0; i < nSteps; i++ ) {
// Do a little alpha blending
BYTE bR = (BYTE) ((GetRValue(clrBar1) * (nSteps - i) +
GetRValue(clrBar2) * i) >> nShift);
BYTE bG = (BYTE) ((GetGValue(clrBar1) * (nSteps - i) +
GetGValue(clrBar2) * i) >> nShift);
BYTE bB = (BYTE) ((GetBValue(clrBar1) * (nSteps - i) +
GetBValue(clrBar2) * i) >> nShift);
// then paint with the resulting color
RECT r2 = rcItem;
r2.left = rcItem.left + ((i * (rcItem.right - rcItem.left)) >> nShift);
r2.right = rcItem.left + (((i + 1) * (rcItem.right - rcItem.left)) >> nShift);
if( (r2.right - r2.left) > 0 ) dcMem.FillSolidRect(&r2, RGB(bR,bG,bB));
}
}
dcMem.SelectClipRgn(NULL);
// Repaint frame
dcMem.SelectStockBrush(NULL_BRUSH);
dcMem.RoundRect(rcItem.left, rcItem.top, rcItem.right, rcItem.bottom + 666, m_Theme.iArc, m_Theme.iArc);
// Done
dcMem.SelectBrush(hOldBrush);
dcMem.SelectPen(hOldPen);
}
dcMem.SelectBitmap(hOldBmp);
panel.hbmpButton = bmp.Detach();
}
// Message map and handlers
BEGIN_MSG_MAP(CCollapsiblePanelImpl)
MESSAGE_HANDLER(WM_CREATE, OnCreate)
MESSAGE_HANDLER(WM_DESTROY, OnDestroy)
MESSAGE_HANDLER(WM_SIZE, OnSize)
MESSAGE_HANDLER(WM_VSCROLL, OnVScroll)
MESSAGE_HANDLER(WM_TIMER, OnTimer)
MESSAGE_HANDLER(WM_LBUTTONDOWN, OnLButtonDown)
MESSAGE_HANDLER(WM_LBUTTONDBLCLK, OnLButtonDown)
CHAIN_MSG_MAP( COffscreenDrawRect< T > )
END_MSG_MAP()
LRESULT OnCreate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
{
LRESULT lRes = DefWindowProc();
_Init();
return lRes;
}
LRESULT OnDestroy(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)
{
RemoveAllItems();
if( m_bOwnCollapseIcons ) {
if( !m_iconCollapse.IsNull() ) m_iconCollapse.DestroyIcon();
if( !m_iconExpand.IsNull() ) m_iconExpand.DestroyIcon();
}
if( (m_dwExtStyle & CPS_EX_SHAREIMAGELIST) == 0 ) {
if( m_Images.IsNull() ) m_Images.Destroy();
if( m_ImagesGrey.IsNull() ) m_ImagesGrey.Destroy();
}
bHandled = FALSE;
return 0;
}
LRESULT OnSize(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled)
{
if( m_cxLastWidth != LOWORD(lParam) ) {
m_cxLastWidth = LOWORD(lParam);
_RecalcLayout();
_RearrangePanels();
_RecalcScrollBar();
}
if( m_cyLastHeight != HIWORD(lParam) ) {
m_cyLastHeight = HIWORD(lParam);
_RecalcScrollBar();
}
bHandled = FALSE;
return 0;
}
LRESULT OnTimer(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled)
{
bHandled = FALSE;
if( wParam != ANIMATETIMER_ID ) return 0;
// Process movement of any animating panel
bool bStillAnimating = false;
DWORD dwTick = ::GetTickCount();
for( int i = 0; i < m_aPanels.GetSize(); i++ ) {
if( m_aPanels[i].dwAnimateStopTime > 0 ) {
PANEL& panel = m_aPanels[i];
if( dwTick >= panel.dwAnimateStopTime ) {
// Done animating this panel
panel.dwAnimateStopTime = 0;
panel.cy = panel.bExpanded ? panel.szChild.cy : 0;
// Show/hide child window
::ShowWindow(panel.hWnd, panel.bExpanded ? SW_SHOWNOACTIVATE : SW_HIDE);
// Send notification
::SendMessage(GetParent(), WM_COMMAND, MAKEWPARAM(GetDlgCtrlID(), CPN_EXPANDED), (LPARAM) m_hWnd);
}
else
{
// TODO: Need to calculate height based on the current time
// relative to the start time to favour slow machines.
int iDiff = panel.bExpanded ? panel.szChild.cy - panel.cy : panel.cy;
iDiff /= 2;
panel.cy = panel.bExpanded ? panel.szChild.cy - iDiff : iDiff;
bStillAnimating = true;
}
}
}
_RearrangePanels();
if( !bStillAnimating )
{
_RecalcScrollBar();
KillTimer(ANIMATETIMER_ID);
}
return 0;
}
LRESULT OnVScroll(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& /*bHandled*/)
{
// Scrollbar support added by Anatoly Ivasyuk
// Get all the vertial scroll bar information
SCROLLINFO si = { 0 };
si.cbSize = sizeof(si);
si.fMask = SIF_ALL;
GetScrollInfo(SB_VERT, &si);
// Save the position for comparison later on
int yPos = si.nPos;
switch( LOWORD(wParam) ) {
case SB_TOP:
// User clicked the HOME keyboard key
si.nPos = si.nMin;
break;
case SB_BOTTOM:
// User clicked the END keyboard key
si.nPos = si.nMax;
break;
case SB_LINEUP:
// User clicked the top arrow
si.nPos -= 1;
break;
case SB_LINEDOWN:
// User clicked the bottom arrow
si.nPos += 1;
break;
case SB_PAGEUP:
// User clicked the shaft above the scroll box
si.nPos -= si.nPage;
break;
case SB_PAGEDOWN:
// User clicked the shaft below the scroll box
si.nPos += si.nPage;
break;
case SB_THUMBTRACK:
// User dragged the scroll box
si.nPos = si.nTrackPos;
break;
default:
break;
}
// Set the position and then retrieve it. Due to adjustments
// by Windows it may not be the same as the value set.
si.fMask = SIF_POS;
SetScrollInfo(SB_VERT, &si, TRUE);
GetScrollInfo(SB_VERT, &si);
if( si.nPos != yPos ) {
_RecalcLayout();
_RearrangePanels();
Invalidate();
}
return 0;
}
LRESULT OnLButtonDown(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& /*bHandled*/)
{
POINT pt = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };
for( int i = 0; i < m_aPanels.GetSize(); i++ ) {
RECT rc = GetPanelRect(i, TRUE);
rc.top += m_cyButton - m_cyBar;
rc.bottom = rc.top + m_cyBar;
if( (m_dwExtStyle & CPS_EX_EXPANDCLICK) != 0 ) ::SetRect(&rc, rc.right - 30, rc.top + 3, rc.right, rc.bottom - 3);
if( ::PtInRect(&rc, pt) ) {
if( GetItemEnabled(i) ) {
m_iCurSel = i;
SetItemExpanded(i, !GetItemExpanded(i), TRUE);
if( (m_dwExtStyle & CPS_EX_SELHIGHLIGHT) != 0 ) _RecalcLayout();
break;
}
}
}
return 0;
}
// Paint override
void DoPaint(CDCHandle dc, RECT& rect)
{
ATLASSERT(!m_iconExpand.IsNull());
RECT rcClient;
GetClientRect(&rcClient);
dc.FillSolidRect(&rect, m_Theme.clrBack);
::InflateRect(&rcClient, -m_szMargin.cx, -m_szMargin.cy);
HFONT hOldFont = dc.SelectFont(GetFont());
dc.SetBkMode(TRANSPARENT);
for( int i = 0; i < m_aPanels.GetSize(); i++ ) {
RECT rcItem = GetPanelRect(i, TRUE);
// Should we paint this button at all?
RECT rcButton = rcItem;
rcButton.bottom = rcButton.top + m_cyButton;
RECT rcDummy = { 0 };
if( !::IntersectRect(&rcDummy, &rect, &rcButton) ) continue;
// Recreate button bitmap?
const PANEL& panel = m_aPanels[i];
RECT rcBar = { rcButton.left, rcButton.bottom - m_cyBar, rcButton.right, rcButton.bottom };
if( panel.hbmpButton == NULL ) _CreateButton(dc, i, rcBar);
ATLASSERT(panel.hbmpButton!=NULL);
// Paint button
CDC dcBmp;
dcBmp.CreateCompatibleDC(dc);
HBITMAP hOldBmp = dcBmp.SelectBitmap(panel.hbmpButton);
dc.BitBlt(rcBar.left, rcBar.top, rcBar.right - rcBar.left, rcBar.bottom, dcBmp, 0, 0, SRCCOPY);
dcBmp.SelectBitmap(hOldBmp);
// Rect for text
RECT rcText = rcButton;
rcText.left += 10;
rcText.right -= 4;
rcText.top = rcText.bottom - m_cyBar;
// Add expander
if( (m_dwExtStyle & CPS_EX_NOEXPANDBUTTON) == 0 ) {
dc.DrawIconEx(rcBar.right - 24, rcBar.top + 3, panel.bExpanded ? m_iconCollapse : m_iconExpand, 16, 16);
rcText.right -= 26;
}
// Add icon
if( panel.iImage >= 0 && !m_Images.IsNull() ) {
SIZE szIcon;
m_Images.GetIconSize(szIcon);
POINT pt = { rcItem.left + 2, rcItem.top + 2 };
if( !panel.bEnabled && !m_ImagesGrey.IsNull() ) {
m_ImagesGrey.Draw(dc, panel.iImage, pt, ILD_TRANSPARENT);
}
else {
m_Images.Draw(dc, panel.iImage, pt, ILD_TRANSPARENT);
}
rcText.left += szIcon.cx;
}
// Print text
COLORREF clrText = panel.clrText;
if( clrText == CLR_INVALID ) clrText = m_Theme.clrTextActive;
if( i == m_iCurSel && (m_dwExtStyle & CPS_EX_SELHIGHLIGHT) != 0 ) clrText = m_Theme.clrTextSel;
if( !m_aPanels[i].bEnabled ) clrText = m_Theme.clrTextInactive;
dc.SetTextColor(clrText);
dc.DrawText(panel.pstrTitle, -1, &rcText, DT_SINGLELINE | DT_END_ELLIPSIS | DT_VCENTER);
// Optional border around child
if( GetStyle() & WS_BORDER ) {
RECT rcChild = rcItem;
rcChild.top += m_cyButton;
CPen pen;
pen.CreatePen(PS_SOLID, 1, m_Theme.clrBorder);
HPEN hOldPen = dc.SelectPen(pen);
HBRUSH hOldBrush = dc.SelectStockBrush(NULL_BRUSH);
dc.Rectangle(&rcChild);
dc.SelectBrush(hOldBrush);
dc.SelectPen(hOldPen);
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -