Okay, here is my code.
I did run into wrong direction with resizeable dialogs, so here
is the version for static dialogs only. Couldn't contact the
original author by email, that's why I post here.
New features:
1. You can add controls and the splitter will resize them automatically.
2. You can show/hide controls of a pane (e.g all control left from splitter)
header file (load in VC and doesn't look strange formated)
#if !defined(AFX_SPLITTERCONTROL_H__C5E28DD6_B347_44F2_9DA0_20C4CFD50B5D__INCLUDED_)
#define AFX_SPLITTERCONTROL_H__C5E28DD6_B347_44F2_9DA0_20C4CFD50B5D__INCLUDED_
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
class CSplitterControl : public CStatic
{
public:
CSplitterControl();
virtual ~CSplitterControl();
enum { TYPE_VERTICAL = 0, TYPE_HORIZONTAL };
enum { PANE_NONE = 0,
PANE_LEFT = 1, PANE_RIGHT,
PANE_TOP = 1, PANE_BOTTOM,
PANE_ALL = 3
};
enum { DRAGGING_NOCHANGE = 0, DRAGGING_RESIZE, DRAGGING_REPOSITION };
typedef struct {
HWND hWnd;
int nPane;
int nDraggingAction;
} SCO_SplitterEntry;
public:
void GetType(BOOL& bUpdateWhileDragging, BOOL& bDrawSplitter, BOOL& bDrawRubberband) const
{ bUpdateWhileDragging = m_bUpdateWhileDragging;
bDrawSplitter = m_bDrawSplitter;
bDrawRubberband = m_bDrawRubberband;
}
void SetType(BOOL bUpdateWhileDragging = TRUE, BOOL bDrawSplitter = FALSE, BOOL bDrawRubberband = FALSE)
{ m_bUpdateWhileDragging = bUpdateWhileDragging;
m_bDrawSplitter = bDrawSplitter;
m_bDrawRubberband = bDrawRubberband;
}
void SetBorder(int nBorderLeftTop = 0, int nBorderRightBottom = 0);
void SetRangeRelative(int nDiffNegative, int nDiffPositive);
void SetResize(BOOL bLeft, BOOL bTop, BOOL bWidth, BOOL bHeight);
int GetSplitterPos();
void SetSplitterPos(int nPos);
BOOL Add(HWND hWnd, int nPane, BOOL bResize = TRUE, BOOL bDragChange = TRUE);
BOOL Add(CWnd* pWnd, int nPane, BOOL bResize = TRUE, BOOL bDragChange = TRUE);
BOOL Add(UINT nID, int nPane, BOOL bResize = TRUE, BOOL bDragChange = TRUE);
BOOL Remove(HWND hWnd);
BOOL Remove(CWnd* pWnd);
BOOL Remove(UINT nID);
BOOL IsChildControl(HWND hWnd) const;
BOOL IsChildControl(CWnd* pWnd) const;
BOOL IsChildControl(UINT nID) const;
BOOL ShowPane(int nPane, BOOL bShow = TRUE);
BOOL HidePane(int nPane) { return ShowPane(nPane, FALSE); }
int GetHiddenPane() const;
int GetOtherPane(int nPane) const;
BOOL IsValidPane(int nPane) const { return nPane>=PANE_LEFT && nPane<=PANE_BOTTOM; }
BOOL IsPaneVisible(int nPane) const;
void RecalcLayout();
void ChangePos(HWND hWnd, int dx, int dy);
void ChangePos(CWnd* pWnd, int dx, int dy);
void ChangeWidth(HWND hWnd, int dx, int nAlignPane);
void ChangeWidth(CWnd* pWnd, int dx, int nAlignPane);
void ChangeHeight(HWND hWnd, int dy, int nAlignPane);
void ChangeHeight(CWnd* pWnd, int dy, int nAlignPane);
protected:
protected:
virtual void PreSubclassWindow();
afx_msg void OnPaint();
afx_msg void OnMouseMove(UINT nFlags, CPoint point);
afx_msg BOOL OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message);
afx_msg void OnLButtonDown(UINT nFlags, CPoint point);
afx_msg void OnLButtonUp(UINT nFlags, CPoint point);
afx_msg void OnMove(int x, int y);
DECLARE_MESSAGE_MAP()
HWND GetCommonParent();
void LoadDefaultCursors();
void SetDraggingPos(CPoint& point);
void DrawRubberBand(BOOL bDraw);
void MoveSplitter(int nDelta);
void ResizeControls(int nDelta, int nPanes = PANE_ALL, BOOL bMoveSplitter = TRUE);
void ShowControls(int nPane, BOOL bShow);
void CalcRange(HWND hWnd, int nPane, int nSplitterPos);
int CalcHiddenRange(int nPane, BOOL bShow);
void CalcHiddenRange(HWND hWnd, int nPane);
private:
int m_nType;
BOOL m_bUpdateWhileDragging;
BOOL m_bDrawSplitter;
BOOL m_bDrawRubberband;
HWND m_hWndParent;
std::vector<SCO_SplitterEntry> m_ControlsArray;
BOOL m_bNotify;
BOOL m_bPaneLeftTopVisible;
BOOL m_bPaneRightBottomVisible;
BOOL m_bButtonPressed;
BOOL m_bUpdating;
int m_nBorderLeftTop;
int m_nBorderRightBottom;
int m_nParentPosMin, m_nParentPosMax;
int m_nParentPanePosMin, m_nParentPanePosMax;
int m_nDistanceLeftTop;
int m_nDistanceRightBottom;
int m_nDragPosStart;
int m_nDragPosStartOfset;
int m_nDragPosX, m_nDragPosY;
int m_nDraggedDelta;
HCURSOR m_hCursorHorizontal;
HCURSOR m_hCursorVertical;
};
#endif // !defined(AFX_SPLITTERCONTROL_H__C5E28DD6_B347_44F2_9DA0_20C4CFD50B5D__INCLUDED_)
source code:
#include "stdafx.h"
#include "SplitterControl.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
#ifndef DEBUG_VERBOSE //... you have been warned. :-)
#undef TRACEV
#define TRACEV (void)0
#else
#undef TRACEV
#define TRACEV TRACE
#endif
const int SCO_BORDER_WIDTH = 6;
CSplitterControl::CSplitterControl()
{
m_nType = 0;
m_bUpdateWhileDragging = TRUE;
m_bDrawSplitter = FALSE;
#ifdef DEBUG_VERBOSE
m_bDrawRubberband = TRUE;
#else
m_bDrawRubberband = FALSE;
#endif
m_hWndParent = NULL;
m_bNotify = FALSE;
m_bPaneLeftTopVisible = TRUE;
m_bPaneRightBottomVisible = TRUE;
m_bButtonPressed = FALSE;
m_bUpdating = FALSE;
m_nBorderLeftTop = 0;
m_nBorderRightBottom = 0;
m_nParentPosMin = m_nParentPosMax = 0;
m_nParentPanePosMin = m_nParentPanePosMax = 0;
m_nDistanceLeftTop = 0;
m_nDistanceRightBottom = 0;
m_nDragPosStart = 0;
m_nDragPosStartOfset = 0;
m_nDragPosX = m_nDragPosY = 0;
m_nDraggedDelta = 0;
m_hCursorHorizontal = NULL;
m_hCursorVertical = NULL;
LoadDefaultCursors();
}
CSplitterControl::~CSplitterControl()
{
}
BEGIN_MESSAGE_MAP(CSplitterControl, CStatic)
ON_WM_PAINT()
ON_WM_MOUSEMOVE()
ON_WM_SETCURSOR()
ON_WM_LBUTTONDOWN()
ON_WM_LBUTTONUP()
ON_WM_MOVE()
END_MESSAGE_MAP()
void CSplitterControl::PreSubclassWindow()
{
CRect rect;
GetClientRect(rect);
m_nType = (rect.Width() < rect.Height())?TYPE_VERTICAL:TYPE_HORIZONTAL;
m_hWndParent = GetCommonParent();
ASSERT(m_hWndParent);
m_bNotify = GetStyle() & SS_NOTIFY;
ModifyStyle(0, SS_NOTIFY | WS_CHILD);
SetBorder(SCO_BORDER_WIDTH, SCO_BORDER_WIDTH);
CStatic::PreSubclassWindow();
}
HWND CSplitterControl::GetCommonParent()
{
return GetParent()->GetSafeHwnd();
}
void CSplitterControl::LoadDefaultCursors()
{
m_hCursorHorizontal = AfxGetApp()->LoadStandardCursor(IDC_SIZEWE);
m_hCursorVertical = AfxGetApp()->LoadStandardCursor(IDC_SIZENS);
}
int CSplitterControl::GetSplitterPos()
{
ASSERT(m_hWndParent);
RECT rect;
::GetWindowRect(m_hWnd, &rect);
POINT point = { rect.left, rect.top };
::ScreenToClient(m_hWndParent, (LPPOINT)&point);
return (m_nType==TYPE_VERTICAL)?point.x:point.y;
}
void CSplitterControl::SetSplitterPos(int nPos)
{
if(nPos >= m_nParentPosMin && nPos <= m_nParentPosMax)
{
int nDelta = nPos - GetSplitterPos();
ResizeControls(nDelta);
}
}
void CSplitterControl::SetBorder(int nBorderLeftTop, int nBorderRightBottom)
{
ASSERT(nBorderLeftTop>=0 && nBorderRightBottom>=0);
m_nBorderLeftTop = nBorderLeftTop;
m_nBorderRightBottom = nBorderRightBottom;
TRACEV("[SCO] SetRangeBorder %d, %d\n", m_nBorderLeftTop, m_nBorderRightBottom);
RecalcLayout();
}
void CSplitterControl::SetRangeRelative(int nDiffNegative, int nDiffPositive)
{
ASSERT(nDiffNegative<=0 && nDiffPositive>=0);
int nSplitterPos = GetSplitterPos();
m_nParentPosMin = nSplitterPos + nDiffNegative;
m_nParentPosMax = nSplitterPos + nDiffPositive;
TRACEV("[SCO] SetRangeRelative %d (base pos %d) +%d\n", nDiffNegative, nSplitterPos, nDiffPositive);
}
void CSplitterControl::SetResize(BOOL bLeft, BOOL bTop, BOOL bWidth, BOOL bHeight)
{
}
void CSplitterControl::RecalcLayout()
{
ASSERT(m_hWndParent);
if(m_bUpdating) return;
int nSplitterPos = GetSplitterPos();
RECT rect;
::GetClientRect(m_hWndParent, &rect);
if(m_nType == TYPE_VERTICAL)
{
m_nParentPosMin = rect.left;
m_nParentPosMax = rect.right;
m_nDistanceLeftTop = m_nDistanceRightBottom = rect.right-rect.left;
} else {
m_nParentPosMin = rect.top;
m_nParentPosMax = rect.bottom;
m_nDistanceLeftTop = m_nDistanceRightBottom = rect.bottom-rect.top;
}
std::vector<SCO_SplitterEntry>::const_iterator itControl;
for(itControl=m_ControlsArray.begin();itControl!=m_ControlsArray.end();itControl++)
{
if((*itControl).nDraggingAction == DRAGGING_RESIZE)
CalcRange((*itControl).hWnd, (*itControl).nPane, nSplitterPos);
}
TRACEV("[SCO] RecalcLayout PosSplitter %d, PosMin=%d, PosMax=%d (distance %d, %d)\n", nSplitterPos, m_nParentPosMin, m_nParentPosMax, m_nDistanceLeftTop, m_nDistanceRightBottom);
}
void CSplitterControl::CalcRange(HWND hWnd, int nPane, int nSplitterPos)
{
ASSERT(hWnd);
ASSERT(m_hWndParent);
ASSERT(IsValidPane(nPane));
RECT rect;
::GetWindowRect(hWnd, &rect);
::ScreenToClient(m_hWndParent, (LPPOINT)&rect);
::ScreenToClient(m_hWndParent, ((LPPOINT)&rect)+1);
if(m_nType == TYPE_VERTICAL)
{
if(nPane == PANE_LEFT) {
int nDistance = nSplitterPos - rect.right;
if(rect.left + nDistance + m_nBorderLeftTop > m_nParentPosMin)
m_nParentPosMin = rect.left + nDistance + m_nBorderLeftTop;
if(nDistance < m_nDistanceLeftTop)
m_nDistanceLeftTop = nDistance;
} else {
int nDistance = rect.left - nSplitterPos;
if(rect.right - nDistance - m_nBorderRightBottom < m_nParentPosMax)
m_nParentPosMax = rect.right - nDistance - m_nBorderRightBottom;
if(nDistance < m_nDistanceRightBottom)
m_nDistanceRightBottom = nDistance;
}
} else {
if(nPane == PANE_TOP) {
int nDistance = nSplitterPos - rect.bottom;
if(rect.top + nDistance + m_nBorderLeftTop > m_nParentPosMin)
m_nParentPosMin = rect.top + nDistance + m_nBorderLeftTop;
if(nDistance < m_nDistanceLeftTop)
m_nDistanceLeftTop = nDistance;
} else {
int nDistance = rect.top - nSplitterPos;
if(rect.bottom - nDistance - m_nBorderRightBottom < m_nParentPosMax)
m_nParentPosMax = rect.bottom - nDistance - m_nBorderRightBottom;
if(nDistance < m_nDistanceRightBottom)
m_nDistanceRightBottom = nDistance;
}
}
}
int CSplitterControl::CalcHiddenRange(int nPane, BOOL bShow)
{
ASSERT(IsValidPane(nPane));
ASSERT(PANE_LEFT==PANE_TOP && PANE_RIGHT == PANE_BOTTOM);
ASSERT(m_hWndParent);
int nPos = GetSplitterPos();
if(!bShow)
{
m_nParentPanePosMin = m_nParentPanePosMax = nPos;
std::vector<SCO_SplitterEntry>::const_iterator itControl;
for(itControl=m_ControlsArray.begin();itControl!=m_ControlsArray.end();itControl++)
{
if((*itControl).nPane == nPane)
CalcHiddenRange((*itControl).hWnd, nPane);
}
return (nPane==PANE_LEFT)?m_nParentPanePosMin-nPos:m_nParentPanePosMax-nPos;
} else {
return (nPane==PANE_LEFT)?nPos-m_nParentPanePosMin:nPos-m_nParentPanePosMax;
}
}
void CSplitterControl::CalcHiddenRange(HWND hWnd, int nPane)
{
ASSERT(hWnd);
ASSERT(m_hWndParent);
ASSERT(IsValidPane(nPane));
RECT rect;
::GetWindowRect(hWnd, &rect);
::ScreenToClient(m_hWndParent, (LPPOINT)&rect);
::ScreenToClient(m_hWndParent, ((LPPOINT)&rect)+1);
if(m_nType == TYPE_VERTICAL)
{
if(nPane == PANE_LEFT) {
if(rect.left - m_nDistanceRightBottom < m_nParentPanePosMin)
m_nParentPanePosMin = rect.left - m_nDistanceRightBottom;
} else {
if(rect.right + m_nDistanceLeftTop > m_nParentPanePosMax)
m_nParentPanePosMax = rect.right + m_nDistanceLeftTop;
}
} else {
if(nPane == PANE_TOP) {
if(rect.top - m_nDistanceRightBottom < m_nParentPanePosMin)
m_nParentPanePosMin = rect.top - m_nDistanceRightBottom;
} else {
if(rect.bottom + m_nDistanceLeftTop > m_nParentPanePosMax)
m_nParentPanePosMax = rect.bottom + m_nDistanceLeftTop;
}
}
}
BOOL CSplitterControl::ShowPane(int nPane, BOOL bShow)
{
ASSERT(IsValidPane(nPane));
if(bShow) {
if(nPane != GetHiddenPane()) return FALSE;
} else {
if(GetHiddenPane()) return FALSE;
}
ShowControls(nPane, bShow);
ShowWindow(bShow);
int nDelta = CalcHiddenRange(nPane, bShow);
ResizeControls(nDelta, GetOtherPane(nPane), FALSE);
return TRUE;
}
void CSplitterControl::ShowControls(int nPane, BOOL bShow)
{
ASSERT(IsValidPane(nPane));
ASSERT(PANE_LEFT==PANE_TOP && PANE_RIGHT == PANE_BOTTOM);
std::vector<SCO_SplitterEntry>::const_iterator itControl;
for(itControl=m_ControlsArray.begin();itControl!=m_ControlsArray.end();itControl++)
{
if((*itControl).nPane == nPane)
::ShowWindow((*itControl).hWnd, bShow);
}
if(nPane == PANE_LEFT) m_bPaneLeftTopVisible = bShow;
else m_bPaneRightBottomVisible = bShow;
}
BOOL CSplitterControl::IsPaneVisible(int nPane) const
{
ASSERT(IsValidPane(nPane));
ASSERT(PANE_LEFT==PANE_TOP && PANE_RIGHT == PANE_BOTTOM);
return (nPane==PANE_LEFT)?m_bPaneLeftTopVisible:m_bPaneRightBottomVisible;
}
int CSplitterControl::GetHiddenPane() const
{
if(!m_bPaneLeftTopVisible) return (m_nType == TYPE_VERTICAL)?PANE_LEFT:PANE_TOP;
if(!m_bPaneRightBottomVisible) return (m_nType == TYPE_VERTICAL)?PANE_RIGHT:PANE_BOTTOM;
return PANE_NONE;
}
int CSplitterControl::GetOtherPane(int nPane) const
{
ASSERT(IsValidPane(nPane));
ASSERT(PANE_LEFT==PANE_TOP && PANE_RIGHT == PANE_BOTTOM);
return (nPane==PANE_LEFT)?PANE_RIGHT:PANE_LEFT;
}
BOOL CSplitterControl::Add(HWND hWnd, int nPane, BOOL bResize, BOOL bDragChange)
{
ASSERT(hWnd);
ASSERT(IsValidPane(nPane));
ASSERT(m_hWndParent == ::GetParent(hWnd));
SCO_SplitterEntry Control;
Control.hWnd = hWnd;
Control.nPane = nPane;
Control.nDraggingAction = bResize?DRAGGING_RESIZE:DRAGGING_REPOSITION;
if(!bDragChange) Control.nDraggingAction = DRAGGING_NOCHANGE;
ASSERT(!IsChildControl(hWnd));
m_ControlsArray.push_back(Control);
if(Control.nDraggingAction == DRAGGING_RESIZE)
{
CalcRange(hWnd, nPane, GetSplitterPos());
}
return TRUE;
}
BOOL CSplitterControl::Add(CWnd* pWnd, int nPane, BOOL bResize, BOOL bDragChange)
{
return Add(pWnd->GetSafeHwnd(), nPane, bResize, bDragChange);
}
BOOL CSplitterControl::Add(UINT nID, int nPane, BOOL bResize, BOOL bDragChange)
{
ASSERT(m_hWndParent);
return Add(::GetDlgItem(m_hWndParent, nID), nPane, bResize, bDragChange);
}
BOOL CSplitterControl::IsChildControl(HWND hWnd) const
{
std::vector<SCO_SplitterEntry>::const_iterator itControl;
for(itControl=m_ControlsArray.begin();itControl!=m_ControlsArray.end();itControl++)
if((*itControl).hWnd == hWnd) return TRUE;
return FALSE;
}
BOOL CSplitterControl::IsChildControl(CWnd* pWnd) const
{
return IsChildControl(pWnd->GetSafeHwnd());
}
BOOL CSplitterControl::IsChildControl(UINT nID) const
{
ASSERT(m_hWndParent);
return IsChildControl(::GetDlgItem(m_hWndParent, nID));
}
BOOL CSplitterControl::Remove(HWND hWnd)
{
std::vector<SCO_SplitterEntry>::iterator itControl;
for(itControl=m_ControlsArray.begin();itControl!=m_ControlsArray.end();itControl++)
{
if((*itControl).hWnd == hWnd)
{
m_ControlsArray.erase(itControl);
RecalcLayout();
return TRUE;
}
}
return FALSE;
}
BOOL CSplitterControl::Remove(CWnd* pWnd)
{
return Remove(pWnd->GetSafeHwnd());
}
BOOL CSplitterControl::Remove(UINT nID)
{
ASSERT(m_hWndParent);
return Remove(::GetDlgItem(m_hWndParent, nID));
}
void CSplitterControl::OnPaint()
{
if(m_bDrawSplitter)
{
CPaintDC dc(this);
CRect rcClient;
GetClientRect(rcClient);
dc.Draw3dRect(rcClient,
::GetSysColor(COLOR_BTNHIGHLIGHT),
::GetSysColor(COLOR_BTNSHADOW));
} else ValidateRect(NULL);
}
void CSplitterControl::OnMove(int x, int y)
{
CStatic::OnMove(x, y);
TRACEV("[SCO] OnMove PosSplitter %d, PosMinOld=%d, PosMaxOld=%d (distance %d, %d)\n", x, m_nParentPosMin, m_nParentPosMax, m_nDistanceLeftTop, m_nDistanceRightBottom);
int nSplitterPos = x;
ASSERT(nSplitterPos>=m_nParentPosMin);
RecalcLayout();
}
BOOL CSplitterControl::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message)
{
if(m_nType == TYPE_VERTICAL) ::SetCursor(m_hCursorHorizontal);
else ::SetCursor(m_hCursorVertical);
return 0;
}
void CSplitterControl::OnLButtonDown(UINT nFlags, CPoint point)
{
CStatic::OnLButtonDown(nFlags, point);
if(!m_bButtonPressed)
{
m_bButtonPressed = TRUE;
SetCapture();
CRect rcWnd;
GetWindowRect(rcWnd);
if(m_nType == TYPE_VERTICAL)
{
m_nDragPosStart = m_nDragPosX = rcWnd.left + point.x;
m_nDragPosStartOfset = point.x;
} else {
m_nDragPosStart = m_nDragPosY = rcWnd.top + point.y;
m_nDragPosStartOfset = point.y;
}
m_nDraggedDelta = 0;
DrawRubberBand(TRUE);
}
}
void CSplitterControl::OnMouseMove(UINT nFlags, CPoint point)
{
if(m_bButtonPressed)
{
DrawRubberBand(FALSE);
SetDraggingPos(point);
if(m_bUpdateWhileDragging)
{
int nDelta;
if(m_nType == TYPE_VERTICAL)
nDelta = m_nDragPosX - m_nDragPosStart;
else
nDelta = m_nDragPosY - m_nDragPosStart;
ResizeControls(nDelta-m_nDraggedDelta);
m_nDraggedDelta = nDelta;
}
DrawRubberBand(TRUE);
}
CStatic::OnMouseMove(nFlags, point);
}
void CSplitterControl::OnLButtonUp(UINT nFlags, CPoint point)
{
if(m_bButtonPressed)
{
m_bButtonPressed = FALSE;
ReleaseCapture();
DrawRubberBand(FALSE);
SetDraggingPos(point);
int nDelta;
if(m_nType == TYPE_VERTICAL)
nDelta = m_nDragPosX - m_nDragPosStart;
else
nDelta = m_nDragPosY - m_nDragPosStart;
ResizeControls(nDelta-m_nDraggedDelta);
}
CStatic::OnLButtonUp(nFlags, point);
}
void CSplitterControl::SetDraggingPos(CPoint& point)
{
ASSERT(m_hWndParent);
if(m_nParentPosMin == m_nParentPosMax) return;
ClientToScreen(&point);
::ScreenToClient(m_hWndParent, &point);
if(m_nType == TYPE_VERTICAL)
{
if(point.x < m_nParentPosMin + m_nDragPosStartOfset)
point.x = m_nParentPosMin + m_nDragPosStartOfset;
else if(point.x > m_nParentPosMax + m_nDragPosStartOfset)
point.x = m_nParentPosMax + m_nDragPosStartOfset;
} else {
if(point.y < m_nParentPosMin + m_nDragPosStartOfset)
point.y = m_nParentPosMin + m_nDragPosStartOfset;
else if(point.y > m_nParentPosMax + m_nDragPosStartOfset)
point.y = m_nParentPosMax + m_nDragPosStartOfset;
}
::ClientToScreen(m_hWndParent, &point);
m_nDragPosX = point.x;
m_nDragPosY = point.y;
}
void CSplitterControl::DrawRubberBand(BOOL bDraw)
{
if(!m_bDrawRubberband) return;
CWindowDC dc(NULL);
CRect rcWnd;
GetWindowRect(&rcWnd);
if(!m_bUpdateWhileDragging)
rcWnd.OffsetRect(m_nDragPosX-m_nDragPosStart, 0);
CSize sizeBar(rcWnd.Width(), rcWnd.Height());
dc.DrawDragRect(&rcWnd, sizeBar, NULL, sizeBar);
#ifdef DEBUG_VERBOSE //also show splitter range in verbose debug mode
int nOldRop = dc.SetROP2(R2_NOTXORPEN);
CPen pen(PS_DOT, 1, RGB(0,0,0));
CPen* pOldPen = dc.SelectObject(&pen);
if(m_nType == TYPE_VERTICAL)
{
CPoint point(m_nParentPosMin, 0);
::ClientToScreen(m_hWndParent, &point);
dc.MoveTo(point.x, rcWnd.top);
dc.LineTo(point.x, rcWnd.bottom);
point.x = m_nParentPosMax;
::ClientToScreen(m_hWndParent, &point);
dc.MoveTo(point.x, rcWnd.top);
dc.LineTo(point.x, rcWnd.bottom);
} else {
CPoint point(0, m_nParentPosMin);
::ClientToScreen(m_hWndParent, &point);
dc.MoveTo(rcWnd.left, point.y);
dc.LineTo(rcWnd.right, point.y);
point.y = m_nParentPosMax;
::ClientToScreen(m_hWndParent, &point);
dc.MoveTo(rcWnd.left, point.y);
dc.LineTo(rcWnd.right, point.y);
}
dc.SetROP2(nOldRop);
dc.SelectObject(pOldPen);
#endif
}
void CSplitterControl::ResizeControls(int nDelta, int nPanes, BOOL bMoveSplitter)
{
ASSERT(m_hWndParent);
ASSERT(nPanes != PANE_NONE);
if(!nDelta) return;
m_bUpdating = TRUE;
TRACEV("[SCO] ResizeControls delta %d, %sPosSplitter %d\n", nDelta, bMoveSplitter?"":"virtual ", GetSplitterPos()+nDelta);
if(bMoveSplitter) MoveSplitter(nDelta);
if(m_nType == TYPE_VERTICAL)
{
std::vector<SCO_SplitterEntry>::iterator itControl;
for(itControl=m_ControlsArray.begin();itControl!=m_ControlsArray.end();itControl++)
{
switch((*itControl).nDraggingAction)
{
case DRAGGING_RESIZE:
if((*itControl).nPane == PANE_LEFT) {
if(nPanes & PANE_LEFT) ChangeWidth((*itControl).hWnd, nDelta, PANE_LEFT);
} else {
if(nPanes & PANE_RIGHT) ChangeWidth((*itControl).hWnd, -nDelta, PANE_RIGHT);
}
break;
case DRAGGING_REPOSITION:
if((*itControl).nPane == PANE_LEFT) {
if(nPanes & PANE_LEFT) ChangePos((*itControl).hWnd, nDelta, 0);
} else {
if(nPanes & PANE_RIGHT) ChangePos((*itControl).hWnd, nDelta, 0);
}
break;
}
}
} else {
std::vector<SCO_SplitterEntry>::iterator itControl;
for(itControl=m_ControlsArray.begin();itControl!=m_ControlsArray.end();itControl++)
{
switch((*itControl).nDraggingAction)
{
case DRAGGING_RESIZE:
if((*itControl).nPane == PANE_TOP) {
if(nPanes & PANE_TOP) ChangeHeight((*itControl).hWnd, nDelta, PANE_TOP);
} else {
if(nPanes & PANE_BOTTOM) ChangeHeight((*itControl).hWnd, -nDelta, PANE_BOTTOM);
}
break;
case DRAGGING_REPOSITION:
if((*itControl).nPane == PANE_TOP) {
if(nPanes & PANE_TOP) ChangePos((*itControl).hWnd, 0, nDelta);
} else {
if(nPanes & PANE_BOTTOM) ChangePos((*itControl).hWnd, 0, nDelta);
}
break;
}
}
}
::UpdateWindow(m_hWndParent);
if(m_bNotify)
{
NMHDR nmh;
nmh.hwndFrom = m_hWnd;
nmh.idFrom = GetDlgCtrlID();
nmh.code = nDelta;
ASSERT(m_hWndParent && nmh.idFrom);
::SendMessage(m_hWndParent, WM_NOTIFY, nmh.idFrom, (LPARAM)&nmh);
}
m_bUpdating = FALSE;
}
void CSplitterControl::MoveSplitter(int nDelta)
{
if(m_nType == TYPE_VERTICAL) ChangePos(m_hWnd, nDelta, 0);
else ChangePos(m_hWnd, 0, nDelta);
}
void CSplitterControl::ChangeWidth(HWND hWnd, int dx, int nAlignPane)
{
ASSERT(hWnd);
ASSERT(m_hWndParent == ::GetParent(hWnd));
ASSERT(nAlignPane==PANE_LEFT || nAlignPane==PANE_RIGHT);
RECT rect;
::GetWindowRect(hWnd, &rect);
::ScreenToClient(m_hWndParent, (LPPOINT)&rect);
::ScreenToClient(m_hWndParent, ((LPPOINT)&rect)+1);
if(dx<0) ::InvalidateRect(m_hWndParent, &rect, TRUE);
if(nAlignPane == PANE_LEFT) rect.right += dx;
else rect.left -= dx;
::MoveWindow(hWnd, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, FALSE);
::InvalidateRect(m_hWndParent, &rect, FALSE);
}
void CSplitterControl::ChangeWidth(CWnd* pWnd, int dx, int nAlignPane)
{
ChangeWidth(pWnd->GetSafeHwnd(), dx, nAlignPane);
}
void CSplitterControl::ChangeHeight(HWND hWnd, int dy, int nAlignPane)
{
ASSERT(hWnd);
ASSERT(m_hWndParent == ::GetParent(hWnd));
ASSERT(nAlignPane==PANE_TOP || nAlignPane==PANE_BOTTOM);
RECT rect;
::GetWindowRect(hWnd, &rect);
::ScreenToClient(m_hWndParent, (LPPOINT)&rect);
::ScreenToClient(m_hWndParent, ((LPPOINT)&rect)+1);
if(dy<0) ::InvalidateRect(m_hWndParent, &rect, TRUE);
if(nAlignPane == PANE_TOP) rect.bottom += dy;
else rect.top -= dy;
::MoveWindow(hWnd, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, FALSE);
::InvalidateRect(m_hWndParent, &rect, FALSE);
}
void CSplitterControl::ChangeHeight(CWnd *pWnd, int dy, int nAlignPane)
{
ChangeHeight(pWnd->GetSafeHwnd(), dy, nAlignPane);
}
void CSplitterControl::ChangePos(HWND hWnd, int dx, int dy)
{
ASSERT(hWnd);
ASSERT(m_hWndParent == ::GetParent(hWnd));
RECT rect;
::GetWindowRect(hWnd, &rect);
::ScreenToClient(m_hWndParent, (LPPOINT)&rect);
::ScreenToClient(m_hWndParent, ((LPPOINT)&rect)+1);
::InvalidateRect(m_hWndParent, &rect, TRUE);
::OffsetRect(&rect, dx, dy);
::MoveWindow(hWnd, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, FALSE);
::InvalidateRect(m_hWndParent, &rect, FALSE);
}
void CSplitterControl::ChangePos(CWnd* pWnd, int dx, int dy)
{
ChangePos(pWnd->GetSafeHwnd(), dx, dy);
}
|