📄 atlsplit.h
字号:
pT->DrawSplitter(dc.m_hDC);
return 0;
}
LRESULT OnSetCursor(UINT /*uMsg*/, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
T* pT = static_cast<T*>(this);
if((HWND)wParam == pT->m_hWnd && LOWORD(lParam) == HTCLIENT)
{
DWORD dwPos = ::GetMessagePos();
POINT ptPos = { GET_X_LPARAM(dwPos), GET_Y_LPARAM(dwPos) };
pT->ScreenToClient(&ptPos);
if(IsOverSplitterBar(ptPos.x, ptPos.y))
return 1;
}
bHandled = FALSE;
return 0;
}
LRESULT OnMouseMove(UINT /*uMsg*/, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
T* pT = static_cast<T*>(this);
int xPos = GET_X_LPARAM(lParam);
int yPos = GET_Y_LPARAM(lParam);
if((wParam & MK_LBUTTON) && ::GetCapture() == pT->m_hWnd)
{
int xyNewSplitPos = 0;
if(t_bVertical)
xyNewSplitPos = xPos - m_rcSplitter.left - m_cxyDragOffset;
else
xyNewSplitPos = yPos - m_rcSplitter.top - m_cxyDragOffset;
if(xyNewSplitPos == -1) // avoid -1, that means middle
xyNewSplitPos = -2;
if(m_xySplitterPos != xyNewSplitPos)
{
if(m_bFullDrag)
{
if(pT->SetSplitterPos(xyNewSplitPos, true))
pT->UpdateWindow();
}
else
{
DrawGhostBar();
pT->SetSplitterPos(xyNewSplitPos, false);
DrawGhostBar();
}
}
}
else // not dragging, just set cursor
{
if(IsOverSplitterBar(xPos, yPos))
::SetCursor(m_hCursor);
bHandled = FALSE;
}
return 0;
}
LRESULT OnLButtonDown(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled)
{
int xPos = GET_X_LPARAM(lParam);
int yPos = GET_Y_LPARAM(lParam);
if(IsOverSplitterBar(xPos, yPos))
{
T* pT = static_cast<T*>(this);
pT->SetCapture();
::SetCursor(m_hCursor);
if(!m_bFullDrag)
DrawGhostBar();
if(t_bVertical)
m_cxyDragOffset = xPos - m_rcSplitter.left - m_xySplitterPos;
else
m_cxyDragOffset = yPos - m_rcSplitter.top - m_xySplitterPos;
}
bHandled = FALSE;
return 1;
}
LRESULT OnLButtonUp(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)
{
::ReleaseCapture();
bHandled = FALSE;
return 1;
}
LRESULT OnLButtonDoubleClick(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
{
T* pT = static_cast<T*>(this);
pT->SetSplitterPos(); // middle
return 0;
}
LRESULT OnCaptureChanged(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
{
if(!m_bFullDrag)
{
DrawGhostBar();
UpdateSplitterLayout();
T* pT = static_cast<T*>(this);
pT->UpdateWindow();
}
return 0;
}
LRESULT OnSetFocus(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM, BOOL& bHandled)
{
if(m_nSinglePane == SPLIT_PANE_NONE)
{
if(m_nDefActivePane == SPLIT_PANE_LEFT || m_nDefActivePane == SPLIT_PANE_RIGHT)
::SetFocus(m_hWndPane[m_nDefActivePane]);
}
else
{
::SetFocus(m_hWndPane[m_nSinglePane]);
}
bHandled = FALSE;
return 1;
}
LRESULT OnMouseActivate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/)
{
T* pT = static_cast<T*>(this);
LRESULT lRet = pT->DefWindowProc(uMsg, wParam, lParam);
if(lRet == MA_ACTIVATE || lRet == MA_ACTIVATEANDEAT)
{
DWORD dwPos = ::GetMessagePos();
POINT pt = { GET_X_LPARAM(dwPos), GET_Y_LPARAM(dwPos) };
pT->ScreenToClient(&pt);
RECT rcPane;
for(int nPane = 0; nPane < m_nPanesCount; nPane++)
{
if(GetSplitterPaneRect(nPane, &rcPane) && ::PtInRect(&rcPane, pt))
{
m_nDefActivePane = nPane;
break;
}
}
}
return lRet;
}
LRESULT OnSettingChange(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
{
GetSystemSettings(true);
return 0;
}
// Implementation - internal helpers
void UpdateSplitterLayout()
{
if(m_nSinglePane == SPLIT_PANE_NONE && m_xySplitterPos == -1)
return;
T* pT = static_cast<T*>(this);
RECT rect = { 0, 0, 0, 0 };
if(m_nSinglePane == SPLIT_PANE_NONE)
{
if(GetSplitterBarRect(&rect))
pT->InvalidateRect(&rect);
for(int nPane = 0; nPane < m_nPanesCount; nPane++)
{
if(GetSplitterPaneRect(nPane, &rect))
{
if(m_hWndPane[nPane] != NULL)
::SetWindowPos(m_hWndPane[nPane], NULL, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, SWP_NOZORDER);
else
pT->InvalidateRect(&rect);
}
}
}
else
{
if(GetSplitterPaneRect(m_nSinglePane, &rect))
{
if(m_hWndPane[m_nSinglePane] != NULL)
::SetWindowPos(m_hWndPane[m_nSinglePane], NULL, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, SWP_NOZORDER);
else
pT->InvalidateRect(&rect);
}
}
}
bool GetSplitterBarRect(LPRECT lpRect) const
{
ATLASSERT(lpRect != NULL);
if(m_nSinglePane != SPLIT_PANE_NONE || m_xySplitterPos == -1)
return false;
if(t_bVertical)
{
lpRect->left = m_rcSplitter.left + m_xySplitterPos;
lpRect->top = m_rcSplitter.top;
lpRect->right = m_rcSplitter.left + m_xySplitterPos + m_cxySplitBar + m_cxyBarEdge;
lpRect->bottom = m_rcSplitter.bottom;
}
else
{
lpRect->left = m_rcSplitter.left;
lpRect->top = m_rcSplitter.top + m_xySplitterPos;
lpRect->right = m_rcSplitter.right;
lpRect->bottom = m_rcSplitter.top + m_xySplitterPos + m_cxySplitBar + m_cxyBarEdge;
}
return true;
}
bool GetSplitterPaneRect(int nPane, LPRECT lpRect) const
{
ATLASSERT(nPane == SPLIT_PANE_LEFT || nPane == SPLIT_PANE_RIGHT);
ATLASSERT(lpRect != NULL);
bool bRet = true;
if(m_nSinglePane != SPLIT_PANE_NONE)
{
if(nPane == m_nSinglePane)
*lpRect = m_rcSplitter;
else
bRet = false;
}
else if(nPane == SPLIT_PANE_LEFT)
{
if(t_bVertical)
{
lpRect->left = m_rcSplitter.left;
lpRect->top = m_rcSplitter.top;
lpRect->right = m_rcSplitter.left + m_xySplitterPos;
lpRect->bottom = m_rcSplitter.bottom;
}
else
{
lpRect->left = m_rcSplitter.left;
lpRect->top = m_rcSplitter.top;
lpRect->right = m_rcSplitter.right;
lpRect->bottom = m_rcSplitter.top + m_xySplitterPos;
}
}
else if(nPane == SPLIT_PANE_RIGHT)
{
if(t_bVertical)
{
lpRect->left = m_rcSplitter.left + m_xySplitterPos + m_cxySplitBar + m_cxyBarEdge;
lpRect->top = m_rcSplitter.top;
lpRect->right = m_rcSplitter.right;
lpRect->bottom = m_rcSplitter.bottom;
}
else
{
lpRect->left = m_rcSplitter.left;
lpRect->top = m_rcSplitter.top + m_xySplitterPos + m_cxySplitBar + m_cxyBarEdge;
lpRect->right = m_rcSplitter.right;
lpRect->bottom = m_rcSplitter.bottom;
}
}
else
{
bRet = false;
}
return bRet;
}
bool IsOverSplitterRect(int x, int y) const
{
// -1 == don't check
return ((x == -1 || (x >= m_rcSplitter.left && x <= m_rcSplitter.right)) &&
(y == -1 || (y >= m_rcSplitter.top && y <= m_rcSplitter.bottom)));
}
bool IsOverSplitterBar(int x, int y) const
{
if(m_nSinglePane != SPLIT_PANE_NONE)
return false;
if(m_xySplitterPos == -1 || !IsOverSplitterRect(x, y))
return false;
int xy = t_bVertical ? x : y;
int xyOff = t_bVertical ? m_rcSplitter.left : m_rcSplitter.top;
return ((xy >= (xyOff + m_xySplitterPos)) && (xy < xyOff + m_xySplitterPos + m_cxySplitBar + m_cxyBarEdge));
}
void DrawGhostBar()
{
RECT rect = { 0, 0, 0, 0 };
if(GetSplitterBarRect(&rect))
{
// invert the brush pattern (looks just like frame window sizing)
T* pT = static_cast<T*>(this);
CWindowDC dc(pT->m_hWnd);
CBrush brush = CDCHandle::GetHalftoneBrush();
if(brush.m_hBrush != NULL)
{
CBrushHandle brushOld = dc.SelectBrush(brush);
dc.PatBlt(rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, PATINVERT);
dc.SelectBrush(brushOld);
}
}
}
void GetSystemSettings(bool bUpdate)
{
m_cxySplitBar = ::GetSystemMetrics(t_bVertical ? SM_CXSIZEFRAME : SM_CYSIZEFRAME);
T* pT = static_cast<T*>(this);
if((pT->GetExStyle() & WS_EX_CLIENTEDGE))
{
m_cxyBarEdge = 2 * ::GetSystemMetrics(t_bVertical ? SM_CXEDGE : SM_CYEDGE);
m_cxyMin = 0;
}
else
{
m_cxyBarEdge = 0;
m_cxyMin = 2 * ::GetSystemMetrics(t_bVertical ? SM_CXEDGE : SM_CYEDGE);
}
::SystemParametersInfo(SPI_GETDRAGFULLWINDOWS, 0, &m_bFullDrag, 0);
if(bUpdate)
UpdateSplitterLayout();
}
bool IsProportional() const
{
return ((m_dwExtendedStyle & SPLIT_PROPORTIONAL) != 0);
}
void StoreProportionalPos()
{
int cxyTotal = t_bVertical ? (m_rcSplitter.right - m_rcSplitter.left - m_cxySplitBar - m_cxyBarEdge) : (m_rcSplitter.bottom - m_rcSplitter.top - m_cxySplitBar - m_cxyBarEdge);
if(cxyTotal > 0)
m_nProportionalPos = ::MulDiv(m_xySplitterPos, m_nPropMax, cxyTotal);
else
m_nProportionalPos = 0;
ATLTRACE2(atlTraceUI, 0, "CSplitterImpl::StoreProportionalPos - %i\n", m_nProportionalPos);
}
void UpdateProportionalPos()
{
int cxyTotal = t_bVertical ? (m_rcSplitter.right - m_rcSplitter.left - m_cxySplitBar - m_cxyBarEdge) : (m_rcSplitter.bottom - m_rcSplitter.top - m_cxySplitBar - m_cxyBarEdge);
if(cxyTotal > 0)
{
int xyNewPos = ::MulDiv(m_nProportionalPos, cxyTotal, m_nPropMax);
m_bUpdateProportionalPos = false;
T* pT = static_cast<T*>(this);
pT->SetSplitterPos(xyNewPos, false);
}
}
bool IsRightAligned() const
{
return ((m_dwExtendedStyle & SPLIT_RIGHTALIGNED) != 0);
}
void StoreRightAlignPos()
{
int cxyTotal = t_bVertical ? (m_rcSplitter.right - m_rcSplitter.left - m_cxySplitBar - m_cxyBarEdge) : (m_rcSplitter.bottom - m_rcSplitter.top - m_cxySplitBar - m_cxyBarEdge);
if(cxyTotal > 0)
m_nProportionalPos = cxyTotal - m_xySplitterPos;
else
m_nProportionalPos = 0;
ATLTRACE2(atlTraceUI, 0, "CSplitterImpl::StoreRightAlignPos - %i\n", m_nProportionalPos);
}
void UpdateRightAlignPos()
{
int cxyTotal = t_bVertical ? (m_rcSplitter.right - m_rcSplitter.left - m_cxySplitBar - m_cxyBarEdge) : (m_rcSplitter.bottom - m_rcSplitter.top - m_cxySplitBar - m_cxyBarEdge);
if(cxyTotal > 0)
{
m_bUpdateProportionalPos = false;
T* pT = static_cast<T*>(this);
pT->SetSplitterPos(cxyTotal - m_nProportionalPos, false);
}
}
bool IsInteractive() const
{
return ((m_dwExtendedStyle & SPLIT_NONINTERACTIVE) == 0);
}
};
template <class T, bool t_bVertical> HCURSOR CSplitterImpl< T, t_bVertical>::m_hCursor = NULL;
///////////////////////////////////////////////////////////////////////////////
// CSplitterWindowImpl - Implements a splitter window
template <class T, bool t_bVertical = true, class TBase = ATL::CWindow, class TWinTraits = ATL::CControlWinTraits>
class ATL_NO_VTABLE CSplitterWindowImpl : public ATL::CWindowImpl< T, TBase, TWinTraits >, public CSplitterImpl< T , t_bVertical >
{
public:
DECLARE_WND_CLASS_EX(NULL, CS_DBLCLKS, COLOR_WINDOW)
typedef CSplitterImpl< T , t_bVertical > _baseClass;
BEGIN_MSG_MAP(CSplitterWindowImpl)
MESSAGE_HANDLER(WM_ERASEBKGND, OnEraseBackground)
MESSAGE_HANDLER(WM_SIZE, OnSize)
CHAIN_MSG_MAP(_baseClass)
FORWARD_NOTIFICATIONS()
END_MSG_MAP()
LRESULT OnEraseBackground(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
{
// handled, no background painting needed
return 1;
}
LRESULT OnSize(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled)
{
if(wParam != SIZE_MINIMIZED)
SetSplitterRect();
bHandled = FALSE;
return 1;
}
};
///////////////////////////////////////////////////////////////////////////////
// CSplitterWindow - Implements a splitter window to be used as is
template <bool t_bVertical = true>
class CSplitterWindowT : public CSplitterWindowImpl<CSplitterWindowT<t_bVertical>, t_bVertical>
{
public:
DECLARE_WND_CLASS_EX(_T("WTL_SplitterWindow"), CS_DBLCLKS, COLOR_WINDOW)
};
typedef CSplitterWindowT<true> CSplitterWindow;
typedef CSplitterWindowT<false> CHorSplitterWindow;
}; //namespace WTL
#endif // __ATLSPLIT_H__
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -