1130 lines
30 KiB
C++
1130 lines
30 KiB
C++
// Windows Template Library - WTL version 10.0
|
|
// Copyright (C) Microsoft Corporation, WTL Team. All rights reserved.
|
|
//
|
|
// This file is a part of the Windows Template Library.
|
|
// The use and distribution terms for this software are covered by the
|
|
// Microsoft Public License (http://opensource.org/licenses/MS-PL)
|
|
// which can be found in the file MS-PL.txt at the root folder.
|
|
|
|
#ifndef __ATLSPLIT_H__
|
|
#define __ATLSPLIT_H__
|
|
|
|
#pragma once
|
|
|
|
#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>
|
|
// CSplitterWindowImpl<T, TBase, TWinTraits>
|
|
// CSplitterWindowT<t_bVertical> - CSplitterWindow, CHorSplitterWindow
|
|
|
|
|
|
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
|
|
#define SPLIT_GRADIENTBAR 0x00000008
|
|
#define SPLIT_FLATBAR 0x00000020
|
|
#define SPLIT_FIXEDBARSIZE 0x00000010
|
|
|
|
// Note: SPLIT_PROPORTIONAL and SPLIT_RIGHTALIGNED/SPLIT_BOTTOMALIGNED are
|
|
// mutually exclusive. If both are set, splitter defaults to SPLIT_PROPORTIONAL.
|
|
// Also, SPLIT_FLATBAR overrides SPLIT_GRADIENTBAR if both are set.
|
|
|
|
|
|
template <class T>
|
|
class CSplitterImpl
|
|
{
|
|
public:
|
|
enum { m_nPanesCount = 2, m_nPropMax = INT_MAX, m_cxyStep = 10 };
|
|
|
|
bool m_bVertical;
|
|
HWND m_hWndPane[m_nPanesCount];
|
|
RECT m_rcSplitter;
|
|
int m_xySplitterPos; // splitter bar position
|
|
int m_xySplitterPosNew; // internal - new position while moving
|
|
HWND m_hWndFocusSave;
|
|
int m_nDefActivePane;
|
|
int m_cxySplitBar; // splitter bar width/height
|
|
HCURSOR m_hCursor;
|
|
int m_cxyMin; // minimum pane size
|
|
int m_cxyBarEdge; // splitter bar edge
|
|
bool m_bFullDrag;
|
|
int m_cxyDragOffset; // internal
|
|
int m_nProportionalPos;
|
|
bool m_bUpdateProportionalPos;
|
|
DWORD m_dwExtendedStyle; // splitter specific extended styles
|
|
int m_nSinglePane; // single pane mode
|
|
int m_xySplitterDefPos; // default position
|
|
bool m_bProportionalDefPos; // porportinal def pos
|
|
|
|
// Constructor
|
|
CSplitterImpl(bool bVertical = true) :
|
|
m_bVertical(bVertical), m_xySplitterPos(-1), m_xySplitterPosNew(-1), m_hWndFocusSave(NULL),
|
|
m_nDefActivePane(SPLIT_PANE_NONE), m_cxySplitBar(4), m_hCursor(NULL), 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_xySplitterDefPos(-1), m_bProportionalDefPos(false)
|
|
{
|
|
m_hWndPane[SPLIT_PANE_LEFT] = NULL;
|
|
m_hWndPane[SPLIT_PANE_RIGHT] = NULL;
|
|
|
|
::SetRectEmpty(&m_rcSplitter);
|
|
}
|
|
|
|
// 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 == default position
|
|
{
|
|
if(m_bProportionalDefPos)
|
|
{
|
|
ATLASSERT((m_xySplitterDefPos >= 0) && (m_xySplitterDefPos <= m_nPropMax));
|
|
|
|
if(m_bVertical)
|
|
xyPos = ::MulDiv(m_xySplitterDefPos, m_rcSplitter.right - m_rcSplitter.left - m_cxySplitBar - m_cxyBarEdge, m_nPropMax);
|
|
else
|
|
xyPos = ::MulDiv(m_xySplitterDefPos, m_rcSplitter.bottom - m_rcSplitter.top - m_cxySplitBar - m_cxyBarEdge, m_nPropMax);
|
|
}
|
|
else if(m_xySplitterDefPos != -1)
|
|
{
|
|
xyPos = m_xySplitterDefPos;
|
|
}
|
|
else // not set, use middle position
|
|
{
|
|
if(m_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(m_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;
|
|
}
|
|
|
|
void SetSplitterPosPct(int nPct, bool bUpdate = true)
|
|
{
|
|
ATLASSERT((nPct >= 0) && (nPct <= 100));
|
|
|
|
m_nProportionalPos = ::MulDiv(nPct, m_nPropMax, 100);
|
|
UpdateProportionalPos();
|
|
|
|
if(bUpdate)
|
|
UpdateSplitterLayout();
|
|
}
|
|
|
|
int GetSplitterPosPct() const
|
|
{
|
|
int cxyTotal = m_bVertical ? (m_rcSplitter.right - m_rcSplitter.left - m_cxySplitBar - m_cxyBarEdge) : (m_rcSplitter.bottom - m_rcSplitter.top - m_cxySplitBar - m_cxyBarEdge);
|
|
return ((cxyTotal > 0) && (m_xySplitterPos >= 0)) ? ::MulDiv(m_xySplitterPos, 100, cxyTotal) : -1;
|
|
}
|
|
|
|
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]) == FALSE)
|
|
::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, _T("CSplitterImpl::SetSplitterExtendedStyle - SPLIT_PROPORTIONAL and SPLIT_RIGHTALIGNED are mutually exclusive, defaulting to SPLIT_PROPORTIONAL.\n"));
|
|
#endif // _DEBUG
|
|
|
|
return dwPrevStyle;
|
|
}
|
|
|
|
void SetSplitterDefaultPos(int xyPos = -1)
|
|
{
|
|
m_xySplitterDefPos = xyPos;
|
|
m_bProportionalDefPos = false;
|
|
}
|
|
|
|
void SetSplitterDefaultPosPct(int nPct)
|
|
{
|
|
ATLASSERT((nPct >= 0) && (nPct <= 100));
|
|
|
|
m_xySplitterDefPos = ::MulDiv(nPct, m_nPropMax, 100);
|
|
m_bProportionalDefPos = true;
|
|
}
|
|
|
|
// 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 NULL;
|
|
|
|
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) != FALSE))
|
|
{
|
|
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);
|
|
}
|
|
}
|
|
|
|
// call to initiate moving splitter bar with keyboard
|
|
void MoveSplitterBar()
|
|
{
|
|
T* pT = static_cast<T*>(this);
|
|
|
|
int x = 0;
|
|
int y = 0;
|
|
if(m_bVertical)
|
|
{
|
|
x = m_xySplitterPos + (m_cxySplitBar / 2) + m_cxyBarEdge;
|
|
y = (m_rcSplitter.bottom - m_rcSplitter.top - m_cxySplitBar - m_cxyBarEdge) / 2;
|
|
}
|
|
else
|
|
{
|
|
x = (m_rcSplitter.right - m_rcSplitter.left - m_cxySplitBar - m_cxyBarEdge) / 2;
|
|
y = m_xySplitterPos + (m_cxySplitBar / 2) + m_cxyBarEdge;
|
|
}
|
|
|
|
POINT pt = { x, y };
|
|
pT->ClientToScreen(&pt);
|
|
::SetCursorPos(pt.x, pt.y);
|
|
|
|
m_xySplitterPosNew = m_xySplitterPos;
|
|
pT->SetCapture();
|
|
m_hWndFocusSave = pT->SetFocus();
|
|
::SetCursor(m_hCursor);
|
|
if(!m_bFullDrag)
|
|
DrawGhostBar();
|
|
if(m_bVertical)
|
|
m_cxyDragOffset = x - m_rcSplitter.left - m_xySplitterPos;
|
|
else
|
|
m_cxyDragOffset = y - m_rcSplitter.top - m_xySplitterPos;
|
|
}
|
|
|
|
void SetOrientation(bool bVertical, bool bUpdate = true)
|
|
{
|
|
if(m_bVertical != bVertical)
|
|
{
|
|
m_bVertical = bVertical;
|
|
|
|
m_hCursor = ::LoadCursor(NULL, m_bVertical ? IDC_SIZEWE : IDC_SIZENS);
|
|
|
|
T* pT = static_cast<T*>(this);
|
|
pT->GetSystemSettings(false);
|
|
|
|
if(m_bVertical)
|
|
m_xySplitterPos = ::MulDiv(m_xySplitterPos, m_rcSplitter.right - m_rcSplitter.left, m_rcSplitter.bottom - m_rcSplitter.top);
|
|
else
|
|
m_xySplitterPos = ::MulDiv(m_xySplitterPos, m_rcSplitter.bottom - m_rcSplitter.top, m_rcSplitter.right - m_rcSplitter.left);
|
|
}
|
|
|
|
if(bUpdate)
|
|
UpdateSplitterLayout();
|
|
}
|
|
|
|
// Overrideables
|
|
void DrawSplitterBar(CDCHandle dc)
|
|
{
|
|
RECT rect = {};
|
|
if(GetSplitterBarRect(&rect))
|
|
{
|
|
dc.FillRect(&rect, COLOR_3DFACE);
|
|
|
|
if((m_dwExtendedStyle & SPLIT_FLATBAR) != 0)
|
|
{
|
|
RECT rect1 = rect;
|
|
if(m_bVertical)
|
|
rect1.right = rect1.left + 1;
|
|
else
|
|
rect1.bottom = rect1.top + 1;
|
|
dc.FillRect(&rect1, COLOR_WINDOW);
|
|
|
|
rect1 = rect;
|
|
if(m_bVertical)
|
|
rect1.left = rect1.right - 1;
|
|
else
|
|
rect1.top = rect1.bottom - 1;
|
|
dc.FillRect(&rect1, COLOR_3DSHADOW);
|
|
}
|
|
else if((m_dwExtendedStyle & SPLIT_GRADIENTBAR) != 0)
|
|
{
|
|
RECT rect2 = rect;
|
|
if(m_bVertical)
|
|
rect2.left = (rect.left + rect.right) / 2 - 1;
|
|
else
|
|
rect2.top = (rect.top + rect.bottom) / 2 - 1;
|
|
|
|
dc.GradientFillRect(rect2, ::GetSysColor(COLOR_3DFACE), ::GetSysColor(COLOR_3DSHADOW), m_bVertical);
|
|
}
|
|
|
|
// draw 3D edge if needed
|
|
T* pT = static_cast<T*>(this);
|
|
if((pT->GetExStyle() & WS_EX_CLIENTEDGE) != 0)
|
|
dc.DrawEdge(&rect, EDGE_RAISED, m_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_KEYDOWN, OnKeyDown)
|
|
}
|
|
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)
|
|
{
|
|
T* pT = static_cast<T*>(this);
|
|
pT->Init();
|
|
|
|
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
|
|
if(wParam != NULL)
|
|
{
|
|
pT->DrawSplitter((HDC)wParam);
|
|
}
|
|
else
|
|
{
|
|
CPaintDC dc(pT->m_hWnd);
|
|
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(::GetCapture() == pT->m_hWnd)
|
|
{
|
|
int xyNewSplitPos = 0;
|
|
if(m_bVertical)
|
|
xyNewSplitPos = xPos - m_rcSplitter.left - m_cxyDragOffset;
|
|
else
|
|
xyNewSplitPos = yPos - m_rcSplitter.top - m_cxyDragOffset;
|
|
|
|
if(xyNewSplitPos == -1) // avoid -1, that means default position
|
|
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)
|
|
{
|
|
T* pT = static_cast<T*>(this);
|
|
int xPos = GET_X_LPARAM(lParam);
|
|
int yPos = GET_Y_LPARAM(lParam);
|
|
if((::GetCapture() != pT->m_hWnd) && IsOverSplitterBar(xPos, yPos))
|
|
{
|
|
m_xySplitterPosNew = m_xySplitterPos;
|
|
pT->SetCapture();
|
|
m_hWndFocusSave = pT->SetFocus();
|
|
::SetCursor(m_hCursor);
|
|
if(!m_bFullDrag)
|
|
DrawGhostBar();
|
|
if(m_bVertical)
|
|
m_cxyDragOffset = xPos - m_rcSplitter.left - m_xySplitterPos;
|
|
else
|
|
m_cxyDragOffset = yPos - m_rcSplitter.top - m_xySplitterPos;
|
|
}
|
|
else if((::GetCapture() == pT->m_hWnd) && !IsOverSplitterBar(xPos, yPos))
|
|
{
|
|
::ReleaseCapture();
|
|
}
|
|
|
|
bHandled = FALSE;
|
|
return 1;
|
|
}
|
|
|
|
LRESULT OnLButtonUp(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)
|
|
{
|
|
T* pT = static_cast<T*>(this);
|
|
if(::GetCapture() == pT->m_hWnd)
|
|
{
|
|
m_xySplitterPosNew = m_xySplitterPos;
|
|
::ReleaseCapture();
|
|
}
|
|
|
|
bHandled = FALSE;
|
|
return 1;
|
|
}
|
|
|
|
LRESULT OnLButtonDoubleClick(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
|
|
{
|
|
T* pT = static_cast<T*>(this);
|
|
pT->SetSplitterPos(); // default
|
|
|
|
return 0;
|
|
}
|
|
|
|
LRESULT OnCaptureChanged(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
|
|
{
|
|
if(!m_bFullDrag)
|
|
DrawGhostBar();
|
|
|
|
if((m_xySplitterPosNew != -1) && (!m_bFullDrag || (m_xySplitterPos != m_xySplitterPosNew)))
|
|
{
|
|
m_xySplitterPos = m_xySplitterPosNew;
|
|
m_xySplitterPosNew = -1;
|
|
UpdateSplitterLayout();
|
|
T* pT = static_cast<T*>(this);
|
|
pT->UpdateWindow();
|
|
}
|
|
|
|
if(m_hWndFocusSave != NULL)
|
|
::SetFocus(m_hWndFocusSave);
|
|
|
|
return 0;
|
|
}
|
|
|
|
LRESULT OnKeyDown(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled)
|
|
{
|
|
T* pT = static_cast<T*>(this);
|
|
if(::GetCapture() == pT->m_hWnd)
|
|
{
|
|
switch(wParam)
|
|
{
|
|
case VK_RETURN:
|
|
m_xySplitterPosNew = m_xySplitterPos;
|
|
// FALLTHROUGH
|
|
case VK_ESCAPE:
|
|
::ReleaseCapture();
|
|
break;
|
|
case VK_LEFT:
|
|
case VK_RIGHT:
|
|
if(m_bVertical)
|
|
{
|
|
POINT pt = {};
|
|
::GetCursorPos(&pt);
|
|
int xyPos = m_xySplitterPos + ((wParam == VK_LEFT) ? -pT->m_cxyStep : pT->m_cxyStep);
|
|
int cxyMax = m_rcSplitter.right - m_rcSplitter.left;
|
|
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;
|
|
pt.x += xyPos - m_xySplitterPos;
|
|
::SetCursorPos(pt.x, pt.y);
|
|
}
|
|
break;
|
|
case VK_UP:
|
|
case VK_DOWN:
|
|
if(!m_bVertical)
|
|
{
|
|
POINT pt = {};
|
|
::GetCursorPos(&pt);
|
|
int xyPos = m_xySplitterPos + ((wParam == VK_UP) ? -pT->m_cxyStep : pT->m_cxyStep);
|
|
int 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;
|
|
pt.y += xyPos - m_xySplitterPos;
|
|
::SetCursorPos(pt.x, pt.y);
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
bHandled = FALSE;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
LRESULT OnSetFocus(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM, BOOL& bHandled)
|
|
{
|
|
T* pT = static_cast<T*>(this);
|
|
if(::GetCapture() != pT->m_hWnd)
|
|
{
|
|
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) != FALSE))
|
|
{
|
|
m_nDefActivePane = nPane;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
return lRet;
|
|
}
|
|
|
|
LRESULT OnSettingChange(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
|
|
{
|
|
T* pT = static_cast<T*>(this);
|
|
pT->GetSystemSettings(true);
|
|
|
|
return 0;
|
|
}
|
|
|
|
// Implementation - internal helpers
|
|
void Init()
|
|
{
|
|
m_hCursor = ::LoadCursor(NULL, m_bVertical ? IDC_SIZEWE : IDC_SIZENS);
|
|
|
|
T* pT = static_cast<T*>(this);
|
|
pT->GetSystemSettings(false);
|
|
}
|
|
|
|
void UpdateSplitterLayout()
|
|
{
|
|
if((m_nSinglePane == SPLIT_PANE_NONE) && (m_xySplitterPos == -1))
|
|
return;
|
|
|
|
T* pT = static_cast<T*>(this);
|
|
RECT rect = {};
|
|
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(m_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(m_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(m_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 = m_bVertical ? x : y;
|
|
int xyOff = m_bVertical ? m_rcSplitter.left : m_rcSplitter.top;
|
|
|
|
return ((xy >= (xyOff + m_xySplitterPos)) && (xy < (xyOff + m_xySplitterPos + m_cxySplitBar + m_cxyBarEdge)));
|
|
}
|
|
|
|
void DrawGhostBar()
|
|
{
|
|
RECT rect = {};
|
|
if(GetSplitterBarRect(&rect))
|
|
{
|
|
// convert client to window coordinates
|
|
T* pT = static_cast<T*>(this);
|
|
RECT rcWnd = {};
|
|
pT->GetWindowRect(&rcWnd);
|
|
::MapWindowPoints(NULL, pT->m_hWnd, (LPPOINT)&rcWnd, 2);
|
|
::OffsetRect(&rect, -rcWnd.left, -rcWnd.top);
|
|
|
|
// invert the brush pattern (looks just like frame window sizing)
|
|
CBrush brush(CDCHandle::GetHalftoneBrush());
|
|
if(brush.m_hBrush != NULL)
|
|
{
|
|
CWindowDC dc(pT->m_hWnd);
|
|
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)
|
|
{
|
|
if((m_dwExtendedStyle & SPLIT_FIXEDBARSIZE) == 0)
|
|
{
|
|
m_cxySplitBar = ::GetSystemMetrics(m_bVertical ? SM_CXSIZEFRAME : SM_CYSIZEFRAME);
|
|
}
|
|
|
|
T* pT = static_cast<T*>(this);
|
|
if((pT->GetExStyle() & WS_EX_CLIENTEDGE) != 0)
|
|
{
|
|
m_cxyBarEdge = 2 * ::GetSystemMetrics(m_bVertical ? SM_CXEDGE : SM_CYEDGE);
|
|
m_cxyMin = 0;
|
|
}
|
|
else
|
|
{
|
|
m_cxyBarEdge = 0;
|
|
m_cxyMin = 2 * ::GetSystemMetrics(m_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 = m_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, _T("CSplitterImpl::StoreProportionalPos - %i\n"), m_nProportionalPos);
|
|
}
|
|
|
|
void UpdateProportionalPos()
|
|
{
|
|
int cxyTotal = m_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 = m_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, _T("CSplitterImpl::StoreRightAlignPos - %i\n"), m_nProportionalPos);
|
|
}
|
|
|
|
void UpdateRightAlignPos()
|
|
{
|
|
int cxyTotal = m_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);
|
|
}
|
|
};
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// CSplitterWindowImpl - Implements a splitter window
|
|
|
|
template <class T, class TBase = ATL::CWindow, class TWinTraits = ATL::CControlWinTraits>
|
|
class ATL_NO_VTABLE CSplitterWindowImpl : public ATL::CWindowImpl< T, TBase, TWinTraits >, public CSplitterImpl< T >
|
|
{
|
|
public:
|
|
DECLARE_WND_CLASS_EX2(NULL, T, CS_DBLCLKS, COLOR_WINDOW)
|
|
|
|
CSplitterWindowImpl(bool bVertical = true) : CSplitterImpl< T >(bVertical)
|
|
{ }
|
|
|
|
BOOL SubclassWindow(HWND hWnd)
|
|
{
|
|
BOOL bRet = ATL::CWindowImpl< T, TBase, TWinTraits >::SubclassWindow(hWnd);
|
|
if(bRet != FALSE)
|
|
{
|
|
T* pT = static_cast<T*>(this);
|
|
pT->Init();
|
|
|
|
this->SetSplitterRect();
|
|
}
|
|
|
|
return bRet;
|
|
}
|
|
|
|
BEGIN_MSG_MAP(CSplitterWindowImpl)
|
|
MESSAGE_HANDLER(WM_ERASEBKGND, OnEraseBackground)
|
|
MESSAGE_HANDLER(WM_SIZE, OnSize)
|
|
CHAIN_MSG_MAP(CSplitterImpl< T >)
|
|
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)
|
|
this->SetSplitterRect();
|
|
|
|
bHandled = FALSE;
|
|
return 1;
|
|
}
|
|
};
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// CSplitterWindow/CHorSplitterWindow - Implements splitter windows to be used as is
|
|
|
|
template <bool t_bVertical = true>
|
|
class CSplitterWindowT : public CSplitterWindowImpl<CSplitterWindowT<t_bVertical> >
|
|
{
|
|
public:
|
|
DECLARE_WND_CLASS_EX2(_T("WTL_SplitterWindow"), CSplitterWindowT<t_bVertical>, CS_DBLCLKS, COLOR_WINDOW)
|
|
|
|
CSplitterWindowT() : CSplitterWindowImpl<CSplitterWindowT<t_bVertical> >(t_bVertical)
|
|
{ }
|
|
};
|
|
|
|
typedef CSplitterWindowT<true> CSplitterWindow;
|
|
typedef CSplitterWindowT<false> CHorSplitterWindow;
|
|
|
|
} // namespace WTL
|
|
|
|
#endif // __ATLSPLIT_H__
|