📄 atlsplit.h
字号:
// Windows Template Library - WTL version 7.1
// Copyright (C) 1997-2003 Microsoft Corporation
// All rights reserved.
//
// This file is a part of the Windows Template Library.
// The code and information is provided "as-is" without
// warranty of any kind, either expressed or implied.
#ifndef __ATLSPLIT_H__
#define __ATLSPLIT_H__
#pragma once
#ifndef __cplusplus
#error ATL requires C++ compilation (use a .cpp suffix)
#endif
#ifdef _WIN32_WCE
#error atlsplit.h is not supported on Windows CE
#endif
#ifndef __ATLAPP_H__
#error atlsplit.h requires atlapp.h to be included first
#endif
#ifndef __ATLWIN_H__
#error atlsplit.h requires atlwin.h to be included first
#endif
///////////////////////////////////////////////////////////////////////////////
// Classes in this file:
//
// CSplitterImpl<T, t_bVertical>
// CSplitterWindowImpl<T, t_bVertical, TBase, TWinTraits>
// CSplitterWindowT<t_bVertical>
namespace WTL
{
///////////////////////////////////////////////////////////////////////////////
// CSplitterImpl - Provides splitter support to any window
// Splitter panes constants
#define SPLIT_PANE_LEFT 0
#define SPLIT_PANE_RIGHT 1
#define SPLIT_PANE_TOP SPLIT_PANE_LEFT
#define SPLIT_PANE_BOTTOM SPLIT_PANE_RIGHT
#define SPLIT_PANE_NONE -1
// Splitter extended styles
#define SPLIT_PROPORTIONAL 0x00000001
#define SPLIT_NONINTERACTIVE 0x00000002
#define SPLIT_RIGHTALIGNED 0x00000004
#define SPLIT_BOTTOMALIGNED SPLIT_RIGHTALIGNED
// Note: SPLIT_PROPORTIONAL and SPLIT_RIGHTALIGNED/SPLIT_BOTTOMALIGNED are
// mutually exclusive. If both are set, splitter defaults to SPLIT_PROPORTIONAL
template <class T, bool t_bVertical = true>
class CSplitterImpl
{
public:
enum { m_nPanesCount = 2, m_nPropMax = 10000 };
HWND m_hWndPane[m_nPanesCount];
RECT m_rcSplitter;
int m_xySplitterPos;
int m_nDefActivePane;
int m_cxySplitBar; // splitter bar width/height
static HCURSOR m_hCursor;
int m_cxyMin; // minimum pane size
int m_cxyBarEdge; // splitter bar edge
bool m_bFullDrag;
int m_cxyDragOffset;
int m_nProportionalPos;
bool m_bUpdateProportionalPos;
DWORD m_dwExtendedStyle; // splitter specific extended styles
int m_nSinglePane; // single pane mode
// Constructor
CSplitterImpl() :
m_xySplitterPos(-1), m_nDefActivePane(SPLIT_PANE_NONE),
m_cxySplitBar(0), m_cxyMin(0), m_cxyBarEdge(0), m_bFullDrag(true),
m_cxyDragOffset(0), m_nProportionalPos(0), m_bUpdateProportionalPos(true),
m_dwExtendedStyle(SPLIT_PROPORTIONAL),
m_nSinglePane(SPLIT_PANE_NONE)
{
m_hWndPane[SPLIT_PANE_LEFT] = NULL;
m_hWndPane[SPLIT_PANE_RIGHT] = NULL;
::SetRectEmpty(&m_rcSplitter);
if(m_hCursor == NULL)
{
CStaticDataInitCriticalSectionLock lock;
if(FAILED(lock.Lock()))
{
ATLTRACE2(atlTraceUI, 0, _T("ERROR : Unable to lock critical section in CSplitterImpl::CSplitterImpl.\n"));
ATLASSERT(FALSE);
return;
}
if(m_hCursor == NULL)
m_hCursor = ::LoadCursor(NULL, t_bVertical ? IDC_SIZEWE : IDC_SIZENS);
lock.Unlock();
}
}
// Attributes
void SetSplitterRect(LPRECT lpRect = NULL, bool bUpdate = true)
{
if(lpRect == NULL)
{
T* pT = static_cast<T*>(this);
pT->GetClientRect(&m_rcSplitter);
}
else
{
m_rcSplitter = *lpRect;
}
if(IsProportional())
UpdateProportionalPos();
else if(IsRightAligned())
UpdateRightAlignPos();
if(bUpdate)
UpdateSplitterLayout();
}
void GetSplitterRect(LPRECT lpRect) const
{
ATLASSERT(lpRect != NULL);
*lpRect = m_rcSplitter;
}
bool SetSplitterPos(int xyPos = -1, bool bUpdate = true)
{
if(xyPos == -1) // -1 == middle
{
if(t_bVertical)
xyPos = (m_rcSplitter.right - m_rcSplitter.left - m_cxySplitBar - m_cxyBarEdge) / 2;
else
xyPos = (m_rcSplitter.bottom - m_rcSplitter.top - m_cxySplitBar - m_cxyBarEdge) / 2;
}
// Adjust if out of valid range
int cxyMax = 0;
if(t_bVertical)
cxyMax = m_rcSplitter.right - m_rcSplitter.left;
else
cxyMax = m_rcSplitter.bottom - m_rcSplitter.top;
if(xyPos < m_cxyMin + m_cxyBarEdge)
xyPos = m_cxyMin;
else if(xyPos > (cxyMax - m_cxySplitBar - m_cxyBarEdge - m_cxyMin))
xyPos = cxyMax - m_cxySplitBar - m_cxyBarEdge - m_cxyMin;
// Set new position and update if requested
bool bRet = (m_xySplitterPos != xyPos);
m_xySplitterPos = xyPos;
if(m_bUpdateProportionalPos)
{
if(IsProportional())
StoreProportionalPos();
else if(IsRightAligned())
StoreRightAlignPos();
}
else
{
m_bUpdateProportionalPos = true;
}
if(bUpdate && bRet)
UpdateSplitterLayout();
return bRet;
}
int GetSplitterPos() const
{
return m_xySplitterPos;
}
bool SetSinglePaneMode(int nPane = SPLIT_PANE_NONE)
{
ATLASSERT(nPane == SPLIT_PANE_LEFT || nPane == SPLIT_PANE_RIGHT || nPane == SPLIT_PANE_NONE);
if(!(nPane == SPLIT_PANE_LEFT || nPane == SPLIT_PANE_RIGHT || nPane == SPLIT_PANE_NONE))
return false;
if(nPane != SPLIT_PANE_NONE)
{
if(!::IsWindowVisible(m_hWndPane[nPane]))
::ShowWindow(m_hWndPane[nPane], SW_SHOW);
int nOtherPane = (nPane == SPLIT_PANE_LEFT) ? SPLIT_PANE_RIGHT : SPLIT_PANE_LEFT;
::ShowWindow(m_hWndPane[nOtherPane], SW_HIDE);
if(m_nDefActivePane != nPane)
m_nDefActivePane = nPane;
}
else if(m_nSinglePane != SPLIT_PANE_NONE)
{
int nOtherPane = (m_nSinglePane == SPLIT_PANE_LEFT) ? SPLIT_PANE_RIGHT : SPLIT_PANE_LEFT;
::ShowWindow(m_hWndPane[nOtherPane], SW_SHOW);
}
m_nSinglePane = nPane;
UpdateSplitterLayout();
return true;
}
int GetSinglePaneMode() const
{
return m_nSinglePane;
}
DWORD GetSplitterExtendedStyle() const
{
return m_dwExtendedStyle;
}
DWORD SetSplitterExtendedStyle(DWORD dwExtendedStyle, DWORD dwMask = 0)
{
DWORD dwPrevStyle = m_dwExtendedStyle;
if(dwMask == 0)
m_dwExtendedStyle = dwExtendedStyle;
else
m_dwExtendedStyle = (m_dwExtendedStyle & ~dwMask) | (dwExtendedStyle & dwMask);
#ifdef _DEBUG
if(IsProportional() && IsRightAligned())
ATLTRACE2(atlTraceUI, 0, "CSplitterImpl::SetSplitterExtendedStyle - SPLIT_PROPORTIONAL and SPLIT_RIGHTALIGNED are mutually exclusive, defaulting to SPLIT_PROPORTIONAL.\n");
#endif //_DEBUG
return dwPrevStyle;
}
// Splitter operations
void SetSplitterPanes(HWND hWndLeftTop, HWND hWndRightBottom, bool bUpdate = true)
{
m_hWndPane[SPLIT_PANE_LEFT] = hWndLeftTop;
m_hWndPane[SPLIT_PANE_RIGHT] = hWndRightBottom;
ATLASSERT(m_hWndPane[SPLIT_PANE_LEFT] == NULL || m_hWndPane[SPLIT_PANE_RIGHT] == NULL || m_hWndPane[SPLIT_PANE_LEFT] != m_hWndPane[SPLIT_PANE_RIGHT]);
if(bUpdate)
UpdateSplitterLayout();
}
bool SetSplitterPane(int nPane, HWND hWnd, bool bUpdate = true)
{
ATLASSERT(nPane == SPLIT_PANE_LEFT || nPane == SPLIT_PANE_RIGHT);
if(nPane != SPLIT_PANE_LEFT && nPane != SPLIT_PANE_RIGHT)
return false;
m_hWndPane[nPane] = hWnd;
ATLASSERT(m_hWndPane[SPLIT_PANE_LEFT] == NULL || m_hWndPane[SPLIT_PANE_RIGHT] == NULL || m_hWndPane[SPLIT_PANE_LEFT] != m_hWndPane[SPLIT_PANE_RIGHT]);
if(bUpdate)
UpdateSplitterLayout();
return true;
}
HWND GetSplitterPane(int nPane) const
{
ATLASSERT(nPane == SPLIT_PANE_LEFT || nPane == SPLIT_PANE_RIGHT);
if(nPane != SPLIT_PANE_LEFT && nPane != SPLIT_PANE_RIGHT)
return false;
return m_hWndPane[nPane];
}
bool SetActivePane(int nPane)
{
ATLASSERT(nPane == SPLIT_PANE_LEFT || nPane == SPLIT_PANE_RIGHT);
if(nPane != SPLIT_PANE_LEFT && nPane != SPLIT_PANE_RIGHT)
return false;
if(m_nSinglePane != SPLIT_PANE_NONE && nPane != m_nSinglePane)
return false;
::SetFocus(m_hWndPane[nPane]);
m_nDefActivePane = nPane;
return true;
}
int GetActivePane() const
{
int nRet = SPLIT_PANE_NONE;
HWND hWndFocus = ::GetFocus();
if(hWndFocus != NULL)
{
for(int nPane = 0; nPane < m_nPanesCount; nPane++)
{
if(hWndFocus == m_hWndPane[nPane] || ::IsChild(m_hWndPane[nPane], hWndFocus))
{
nRet = nPane;
break;
}
}
}
return nRet;
}
bool ActivateNextPane(bool bNext = true)
{
int nPane = m_nSinglePane;
if(nPane == SPLIT_PANE_NONE)
{
switch(GetActivePane())
{
case SPLIT_PANE_LEFT:
nPane = SPLIT_PANE_RIGHT;
break;
case SPLIT_PANE_RIGHT:
nPane = SPLIT_PANE_LEFT;
break;
default:
nPane = bNext ? SPLIT_PANE_LEFT : SPLIT_PANE_RIGHT;
break;
}
}
return SetActivePane(nPane);
}
bool SetDefaultActivePane(int nPane)
{
ATLASSERT(nPane == SPLIT_PANE_LEFT || nPane == SPLIT_PANE_RIGHT);
if(nPane != SPLIT_PANE_LEFT && nPane != SPLIT_PANE_RIGHT)
return false;
m_nDefActivePane = nPane;
return true;
}
bool SetDefaultActivePane(HWND hWnd)
{
for(int nPane = 0; nPane < m_nPanesCount; nPane++)
{
if(hWnd == m_hWndPane[nPane])
{
m_nDefActivePane = nPane;
return true;
}
}
return false; // not found
}
int GetDefaultActivePane() const
{
return m_nDefActivePane;
}
void DrawSplitter(CDCHandle dc)
{
ATLASSERT(dc.m_hDC != NULL);
if(m_nSinglePane == SPLIT_PANE_NONE && m_xySplitterPos == -1)
return;
T* pT = static_cast<T*>(this);
if(m_nSinglePane == SPLIT_PANE_NONE)
{
pT->DrawSplitterBar(dc);
for(int nPane = 0; nPane < m_nPanesCount; nPane++)
{
if(m_hWndPane[nPane] == NULL)
pT->DrawSplitterPane(dc, nPane);
}
}
else
{
if(m_hWndPane[m_nSinglePane] == NULL)
pT->DrawSplitterPane(dc, m_nSinglePane);
}
}
// Overrideables
void DrawSplitterBar(CDCHandle dc)
{
RECT rect;
if(GetSplitterBarRect(&rect))
{
dc.FillRect(&rect, COLOR_3DFACE);
// draw 3D edge if needed
T* pT = static_cast<T*>(this);
if((pT->GetExStyle() & WS_EX_CLIENTEDGE) != 0)
dc.DrawEdge(&rect, EDGE_RAISED, t_bVertical ? (BF_LEFT | BF_RIGHT) : (BF_TOP | BF_BOTTOM));
}
}
// called only if pane is empty
void DrawSplitterPane(CDCHandle dc, int nPane)
{
RECT rect;
if(GetSplitterPaneRect(nPane, &rect))
{
T* pT = static_cast<T*>(this);
if((pT->GetExStyle() & WS_EX_CLIENTEDGE) == 0)
dc.DrawEdge(&rect, EDGE_SUNKEN, BF_RECT | BF_ADJUST);
dc.FillRect(&rect, COLOR_APPWORKSPACE);
}
}
// Message map and handlers
BEGIN_MSG_MAP(CSplitterImpl)
MESSAGE_HANDLER(WM_CREATE, OnCreate)
MESSAGE_HANDLER(WM_PAINT, OnPaint)
MESSAGE_HANDLER(WM_PRINTCLIENT, OnPaint)
if(IsInteractive())
{
MESSAGE_HANDLER(WM_SETCURSOR, OnSetCursor)
MESSAGE_HANDLER(WM_MOUSEMOVE, OnMouseMove)
MESSAGE_HANDLER(WM_LBUTTONDOWN, OnLButtonDown)
MESSAGE_HANDLER(WM_LBUTTONUP, OnLButtonUp)
MESSAGE_HANDLER(WM_LBUTTONDBLCLK, OnLButtonDoubleClick)
MESSAGE_HANDLER(WM_CAPTURECHANGED, OnCaptureChanged)
}
MESSAGE_HANDLER(WM_SETFOCUS, OnSetFocus)
MESSAGE_HANDLER(WM_MOUSEACTIVATE, OnMouseActivate)
MESSAGE_HANDLER(WM_SETTINGCHANGE, OnSettingChange)
END_MSG_MAP()
LRESULT OnCreate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)
{
GetSystemSettings(false);
bHandled = FALSE;
return 1;
}
LRESULT OnPaint(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
{
T* pT = static_cast<T*>(this);
// try setting position if not set
if(m_nSinglePane == SPLIT_PANE_NONE && m_xySplitterPos == -1)
pT->SetSplitterPos();
// do painting
CPaintDC dc(pT->m_hWnd);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -