| Index: third_party/wtl/include/atlsplit.h
|
| diff --git a/third_party/wtl/include/atlsplit.h b/third_party/wtl/include/atlsplit.h
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..9f9424b22535b06e7866b4f33d9e0241f89c5ef9
|
| --- /dev/null
|
| +++ b/third_party/wtl/include/atlsplit.h
|
| @@ -0,0 +1,889 @@
|
| +// Windows Template Library - WTL version 8.0
|
| +// Copyright (C) Microsoft Corporation. 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 Permissive License (Ms-PL) which can be found in the file
|
| +// Ms-PL.txt at the root of this distribution.
|
| +
|
| +#ifndef __ATLSPLIT_H__
|
| +#define __ATLSPLIT_H__
|
| +
|
| +#pragma once
|
| +
|
| +#ifndef __cplusplus
|
| + #error ATL requires C++ compilation (use a .cpp suffix)
|
| +#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;
|
| + }
|
| +
|
| + void SetSplitterPosPct(int nPct, bool bUpdate = true)
|
| + {
|
| + ATLASSERT(nPct >= 0 && nPct <= 100);
|
| +
|
| + m_nProportionalPos = ::MulDiv(nPct, m_nPropMax, 100);
|
| + UpdateProportionalPos();
|
| +
|
| + if(bUpdate)
|
| + UpdateSplitterLayout();
|
| + }
|
| +
|
| + 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, _T("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)
|
| +#ifndef _WIN32_WCE
|
| + MESSAGE_HANDLER(WM_PRINTCLIENT, OnPaint)
|
| +#endif // !_WIN32_WCE
|
| + 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)
|
| +#ifndef _WIN32_WCE
|
| + MESSAGE_HANDLER(WM_MOUSEACTIVATE, OnMouseActivate)
|
| +#endif // !_WIN32_WCE
|
| + 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);
|
| + 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;
|
| + }
|
| +
|
| +#ifndef _WIN32_WCE
|
| + 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;
|
| + }
|
| +#endif // !_WIN32_WCE
|
| +
|
| + 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)
|
| + {
|
| +#ifndef _WIN32_WCE
|
| + m_cxySplitBar = ::GetSystemMetrics(t_bVertical ? SM_CXSIZEFRAME : SM_CYSIZEFRAME);
|
| +#else // CE specific
|
| + m_cxySplitBar = 2 * ::GetSystemMetrics(t_bVertical ? SM_CXEDGE : SM_CYEDGE);
|
| +#endif // _WIN32_WCE
|
| +
|
| + 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);
|
| + }
|
| +
|
| +#ifndef _WIN32_WCE
|
| + ::SystemParametersInfo(SPI_GETDRAGFULLWINDOWS, 0, &m_bFullDrag, 0);
|
| +#endif // !_WIN32_WCE
|
| +
|
| + 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, _T("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, _T("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__
|
|
|