1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129 |
- // 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__
|