OLD | NEW |
(Empty) | |
| 1 // Windows Template Library - WTL version 8.0 |
| 2 // Copyright (C) Microsoft Corporation. All rights reserved. |
| 3 // |
| 4 // This file is a part of the Windows Template Library. |
| 5 // The use and distribution terms for this software are covered by the |
| 6 // Microsoft Permissive License (Ms-PL) which can be found in the file |
| 7 // Ms-PL.txt at the root of this distribution. |
| 8 |
| 9 #ifndef __ATLSPLIT_H__ |
| 10 #define __ATLSPLIT_H__ |
| 11 |
| 12 #pragma once |
| 13 |
| 14 #ifndef __cplusplus |
| 15 #error ATL requires C++ compilation (use a .cpp suffix) |
| 16 #endif |
| 17 |
| 18 #ifndef __ATLAPP_H__ |
| 19 #error atlsplit.h requires atlapp.h to be included first |
| 20 #endif |
| 21 |
| 22 #ifndef __ATLWIN_H__ |
| 23 #error atlsplit.h requires atlwin.h to be included first |
| 24 #endif |
| 25 |
| 26 |
| 27 /////////////////////////////////////////////////////////////////////////////// |
| 28 // Classes in this file: |
| 29 // |
| 30 // CSplitterImpl<T, t_bVertical> |
| 31 // CSplitterWindowImpl<T, t_bVertical, TBase, TWinTraits> |
| 32 // CSplitterWindowT<t_bVertical> |
| 33 |
| 34 |
| 35 namespace WTL |
| 36 { |
| 37 |
| 38 /////////////////////////////////////////////////////////////////////////////// |
| 39 // CSplitterImpl - Provides splitter support to any window |
| 40 |
| 41 // Splitter panes constants |
| 42 #define SPLIT_PANE_LEFT 0 |
| 43 #define SPLIT_PANE_RIGHT 1 |
| 44 #define SPLIT_PANE_TOP SPLIT_PANE_LEFT |
| 45 #define SPLIT_PANE_BOTTOM SPLIT_PANE_RIGHT |
| 46 #define SPLIT_PANE_NONE -1 |
| 47 |
| 48 // Splitter extended styles |
| 49 #define SPLIT_PROPORTIONAL 0x00000001 |
| 50 #define SPLIT_NONINTERACTIVE 0x00000002 |
| 51 #define SPLIT_RIGHTALIGNED 0x00000004 |
| 52 #define SPLIT_BOTTOMALIGNED SPLIT_RIGHTALIGNED |
| 53 |
| 54 // Note: SPLIT_PROPORTIONAL and SPLIT_RIGHTALIGNED/SPLIT_BOTTOMALIGNED are |
| 55 // mutually exclusive. If both are set, splitter defaults to SPLIT_PROPORTIONAL |
| 56 |
| 57 |
| 58 template <class T, bool t_bVertical = true> |
| 59 class CSplitterImpl |
| 60 { |
| 61 public: |
| 62 enum { m_nPanesCount = 2, m_nPropMax = 10000 }; |
| 63 |
| 64 HWND m_hWndPane[m_nPanesCount]; |
| 65 RECT m_rcSplitter; |
| 66 int m_xySplitterPos; |
| 67 int m_nDefActivePane; |
| 68 int m_cxySplitBar; // splitter bar width/height |
| 69 static HCURSOR m_hCursor; |
| 70 int m_cxyMin; // minimum pane size |
| 71 int m_cxyBarEdge; // splitter bar edge |
| 72 bool m_bFullDrag; |
| 73 int m_cxyDragOffset; |
| 74 int m_nProportionalPos; |
| 75 bool m_bUpdateProportionalPos; |
| 76 DWORD m_dwExtendedStyle; // splitter specific extended styles |
| 77 int m_nSinglePane; // single pane mode |
| 78 |
| 79 // Constructor |
| 80 CSplitterImpl() : |
| 81 m_xySplitterPos(-1), m_nDefActivePane(SPLIT_PANE_NONE), |
| 82 m_cxySplitBar(0), m_cxyMin(0), m_cxyBarEdge(0), m_bFullD
rag(true), |
| 83 m_cxyDragOffset(0), m_nProportionalPos(0), m_bUpdateProp
ortionalPos(true), |
| 84 m_dwExtendedStyle(SPLIT_PROPORTIONAL), |
| 85 m_nSinglePane(SPLIT_PANE_NONE) |
| 86 { |
| 87 m_hWndPane[SPLIT_PANE_LEFT] = NULL; |
| 88 m_hWndPane[SPLIT_PANE_RIGHT] = NULL; |
| 89 |
| 90 ::SetRectEmpty(&m_rcSplitter); |
| 91 |
| 92 if(m_hCursor == NULL) |
| 93 { |
| 94 CStaticDataInitCriticalSectionLock lock; |
| 95 if(FAILED(lock.Lock())) |
| 96 { |
| 97 ATLTRACE2(atlTraceUI, 0, _T("ERROR : Unable to l
ock critical section in CSplitterImpl::CSplitterImpl.\n")); |
| 98 ATLASSERT(FALSE); |
| 99 return; |
| 100 } |
| 101 |
| 102 if(m_hCursor == NULL) |
| 103 m_hCursor = ::LoadCursor(NULL, t_bVertical ? IDC
_SIZEWE : IDC_SIZENS); |
| 104 |
| 105 lock.Unlock(); |
| 106 } |
| 107 } |
| 108 |
| 109 // Attributes |
| 110 void SetSplitterRect(LPRECT lpRect = NULL, bool bUpdate = true) |
| 111 { |
| 112 if(lpRect == NULL) |
| 113 { |
| 114 T* pT = static_cast<T*>(this); |
| 115 pT->GetClientRect(&m_rcSplitter); |
| 116 } |
| 117 else |
| 118 { |
| 119 m_rcSplitter = *lpRect; |
| 120 } |
| 121 |
| 122 if(IsProportional()) |
| 123 UpdateProportionalPos(); |
| 124 else if(IsRightAligned()) |
| 125 UpdateRightAlignPos(); |
| 126 |
| 127 if(bUpdate) |
| 128 UpdateSplitterLayout(); |
| 129 } |
| 130 |
| 131 void GetSplitterRect(LPRECT lpRect) const |
| 132 { |
| 133 ATLASSERT(lpRect != NULL); |
| 134 *lpRect = m_rcSplitter; |
| 135 } |
| 136 |
| 137 bool SetSplitterPos(int xyPos = -1, bool bUpdate = true) |
| 138 { |
| 139 if(xyPos == -1) // -1 == middle |
| 140 { |
| 141 if(t_bVertical) |
| 142 xyPos = (m_rcSplitter.right - m_rcSplitter.left
- m_cxySplitBar - m_cxyBarEdge) / 2; |
| 143 else |
| 144 xyPos = (m_rcSplitter.bottom - m_rcSplitter.top
- m_cxySplitBar - m_cxyBarEdge) / 2; |
| 145 } |
| 146 |
| 147 // Adjust if out of valid range |
| 148 int cxyMax = 0; |
| 149 if(t_bVertical) |
| 150 cxyMax = m_rcSplitter.right - m_rcSplitter.left; |
| 151 else |
| 152 cxyMax = m_rcSplitter.bottom - m_rcSplitter.top; |
| 153 |
| 154 if(xyPos < m_cxyMin + m_cxyBarEdge) |
| 155 xyPos = m_cxyMin; |
| 156 else if(xyPos > (cxyMax - m_cxySplitBar - m_cxyBarEdge - m_cxyMi
n)) |
| 157 xyPos = cxyMax - m_cxySplitBar - m_cxyBarEdge - m_cxyMin
; |
| 158 |
| 159 // Set new position and update if requested |
| 160 bool bRet = (m_xySplitterPos != xyPos); |
| 161 m_xySplitterPos = xyPos; |
| 162 |
| 163 if(m_bUpdateProportionalPos) |
| 164 { |
| 165 if(IsProportional()) |
| 166 StoreProportionalPos(); |
| 167 else if(IsRightAligned()) |
| 168 StoreRightAlignPos(); |
| 169 } |
| 170 else |
| 171 { |
| 172 m_bUpdateProportionalPos = true; |
| 173 } |
| 174 |
| 175 if(bUpdate && bRet) |
| 176 UpdateSplitterLayout(); |
| 177 |
| 178 return bRet; |
| 179 } |
| 180 |
| 181 void SetSplitterPosPct(int nPct, bool bUpdate = true) |
| 182 { |
| 183 ATLASSERT(nPct >= 0 && nPct <= 100); |
| 184 |
| 185 m_nProportionalPos = ::MulDiv(nPct, m_nPropMax, 100); |
| 186 UpdateProportionalPos(); |
| 187 |
| 188 if(bUpdate) |
| 189 UpdateSplitterLayout(); |
| 190 } |
| 191 |
| 192 int GetSplitterPos() const |
| 193 { |
| 194 return m_xySplitterPos; |
| 195 } |
| 196 |
| 197 bool SetSinglePaneMode(int nPane = SPLIT_PANE_NONE) |
| 198 { |
| 199 ATLASSERT(nPane == SPLIT_PANE_LEFT || nPane == SPLIT_PANE_RIGHT
|| nPane == SPLIT_PANE_NONE); |
| 200 if(!(nPane == SPLIT_PANE_LEFT || nPane == SPLIT_PANE_RIGHT || nP
ane == SPLIT_PANE_NONE)) |
| 201 return false; |
| 202 |
| 203 if(nPane != SPLIT_PANE_NONE) |
| 204 { |
| 205 if(!::IsWindowVisible(m_hWndPane[nPane])) |
| 206 ::ShowWindow(m_hWndPane[nPane], SW_SHOW); |
| 207 int nOtherPane = (nPane == SPLIT_PANE_LEFT) ? SPLIT_PANE
_RIGHT : SPLIT_PANE_LEFT; |
| 208 ::ShowWindow(m_hWndPane[nOtherPane], SW_HIDE); |
| 209 if(m_nDefActivePane != nPane) |
| 210 m_nDefActivePane = nPane; |
| 211 } |
| 212 else if(m_nSinglePane != SPLIT_PANE_NONE) |
| 213 { |
| 214 int nOtherPane = (m_nSinglePane == SPLIT_PANE_LEFT) ? SP
LIT_PANE_RIGHT : SPLIT_PANE_LEFT; |
| 215 ::ShowWindow(m_hWndPane[nOtherPane], SW_SHOW); |
| 216 } |
| 217 |
| 218 m_nSinglePane = nPane; |
| 219 UpdateSplitterLayout(); |
| 220 return true; |
| 221 } |
| 222 |
| 223 int GetSinglePaneMode() const |
| 224 { |
| 225 return m_nSinglePane; |
| 226 } |
| 227 |
| 228 DWORD GetSplitterExtendedStyle() const |
| 229 { |
| 230 return m_dwExtendedStyle; |
| 231 } |
| 232 |
| 233 DWORD SetSplitterExtendedStyle(DWORD dwExtendedStyle, DWORD dwMask = 0) |
| 234 { |
| 235 DWORD dwPrevStyle = m_dwExtendedStyle; |
| 236 if(dwMask == 0) |
| 237 m_dwExtendedStyle = dwExtendedStyle; |
| 238 else |
| 239 m_dwExtendedStyle = (m_dwExtendedStyle & ~dwMask) | (dwE
xtendedStyle & dwMask); |
| 240 #ifdef _DEBUG |
| 241 if(IsProportional() && IsRightAligned()) |
| 242 ATLTRACE2(atlTraceUI, 0, _T("CSplitterImpl::SetSplitterE
xtendedStyle - SPLIT_PROPORTIONAL and SPLIT_RIGHTALIGNED are mutually exclusive,
defaulting to SPLIT_PROPORTIONAL.\n")); |
| 243 #endif // _DEBUG |
| 244 return dwPrevStyle; |
| 245 } |
| 246 |
| 247 // Splitter operations |
| 248 void SetSplitterPanes(HWND hWndLeftTop, HWND hWndRightBottom, bool bUpda
te = true) |
| 249 { |
| 250 m_hWndPane[SPLIT_PANE_LEFT] = hWndLeftTop; |
| 251 m_hWndPane[SPLIT_PANE_RIGHT] = hWndRightBottom; |
| 252 ATLASSERT(m_hWndPane[SPLIT_PANE_LEFT] == NULL || m_hWndPane[SPLI
T_PANE_RIGHT] == NULL || m_hWndPane[SPLIT_PANE_LEFT] != m_hWndPane[SPLIT_PANE_RI
GHT]); |
| 253 if(bUpdate) |
| 254 UpdateSplitterLayout(); |
| 255 } |
| 256 |
| 257 bool SetSplitterPane(int nPane, HWND hWnd, bool bUpdate = true) |
| 258 { |
| 259 ATLASSERT(nPane == SPLIT_PANE_LEFT || nPane == SPLIT_PANE_RIGHT)
; |
| 260 |
| 261 if(nPane != SPLIT_PANE_LEFT && nPane != SPLIT_PANE_RIGHT) |
| 262 return false; |
| 263 m_hWndPane[nPane] = hWnd; |
| 264 ATLASSERT(m_hWndPane[SPLIT_PANE_LEFT] == NULL || m_hWndPane[SPLI
T_PANE_RIGHT] == NULL || m_hWndPane[SPLIT_PANE_LEFT] != m_hWndPane[SPLIT_PANE_RI
GHT]); |
| 265 if(bUpdate) |
| 266 UpdateSplitterLayout(); |
| 267 return true; |
| 268 } |
| 269 |
| 270 HWND GetSplitterPane(int nPane) const |
| 271 { |
| 272 ATLASSERT(nPane == SPLIT_PANE_LEFT || nPane == SPLIT_PANE_RIGHT)
; |
| 273 |
| 274 if(nPane != SPLIT_PANE_LEFT && nPane != SPLIT_PANE_RIGHT) |
| 275 return false; |
| 276 return m_hWndPane[nPane]; |
| 277 } |
| 278 |
| 279 bool SetActivePane(int nPane) |
| 280 { |
| 281 ATLASSERT(nPane == SPLIT_PANE_LEFT || nPane == SPLIT_PANE_RIGHT)
; |
| 282 |
| 283 if(nPane != SPLIT_PANE_LEFT && nPane != SPLIT_PANE_RIGHT) |
| 284 return false; |
| 285 if(m_nSinglePane != SPLIT_PANE_NONE && nPane != m_nSinglePane) |
| 286 return false; |
| 287 ::SetFocus(m_hWndPane[nPane]); |
| 288 m_nDefActivePane = nPane; |
| 289 return true; |
| 290 } |
| 291 |
| 292 int GetActivePane() const |
| 293 { |
| 294 int nRet = SPLIT_PANE_NONE; |
| 295 HWND hWndFocus = ::GetFocus(); |
| 296 if(hWndFocus != NULL) |
| 297 { |
| 298 for(int nPane = 0; nPane < m_nPanesCount; nPane++) |
| 299 { |
| 300 if(hWndFocus == m_hWndPane[nPane] || ::IsChild(m
_hWndPane[nPane], hWndFocus)) |
| 301 { |
| 302 nRet = nPane; |
| 303 break; |
| 304 } |
| 305 } |
| 306 } |
| 307 return nRet; |
| 308 } |
| 309 |
| 310 bool ActivateNextPane(bool bNext = true) |
| 311 { |
| 312 int nPane = m_nSinglePane; |
| 313 if(nPane == SPLIT_PANE_NONE) |
| 314 { |
| 315 switch(GetActivePane()) |
| 316 { |
| 317 case SPLIT_PANE_LEFT: |
| 318 nPane = SPLIT_PANE_RIGHT; |
| 319 break; |
| 320 case SPLIT_PANE_RIGHT: |
| 321 nPane = SPLIT_PANE_LEFT; |
| 322 break; |
| 323 default: |
| 324 nPane = bNext ? SPLIT_PANE_LEFT : SPLIT_PANE_RIG
HT; |
| 325 break; |
| 326 } |
| 327 } |
| 328 return SetActivePane(nPane); |
| 329 } |
| 330 |
| 331 bool SetDefaultActivePane(int nPane) |
| 332 { |
| 333 ATLASSERT(nPane == SPLIT_PANE_LEFT || nPane == SPLIT_PANE_RIGHT)
; |
| 334 |
| 335 if(nPane != SPLIT_PANE_LEFT && nPane != SPLIT_PANE_RIGHT) |
| 336 return false; |
| 337 m_nDefActivePane = nPane; |
| 338 return true; |
| 339 } |
| 340 |
| 341 bool SetDefaultActivePane(HWND hWnd) |
| 342 { |
| 343 for(int nPane = 0; nPane < m_nPanesCount; nPane++) |
| 344 { |
| 345 if(hWnd == m_hWndPane[nPane]) |
| 346 { |
| 347 m_nDefActivePane = nPane; |
| 348 return true; |
| 349 } |
| 350 } |
| 351 return false; // not found |
| 352 } |
| 353 |
| 354 int GetDefaultActivePane() const |
| 355 { |
| 356 return m_nDefActivePane; |
| 357 } |
| 358 |
| 359 void DrawSplitter(CDCHandle dc) |
| 360 { |
| 361 ATLASSERT(dc.m_hDC != NULL); |
| 362 if(m_nSinglePane == SPLIT_PANE_NONE && m_xySplitterPos == -1) |
| 363 return; |
| 364 |
| 365 T* pT = static_cast<T*>(this); |
| 366 if(m_nSinglePane == SPLIT_PANE_NONE) |
| 367 { |
| 368 pT->DrawSplitterBar(dc); |
| 369 |
| 370 for(int nPane = 0; nPane < m_nPanesCount; nPane++) |
| 371 { |
| 372 if(m_hWndPane[nPane] == NULL) |
| 373 pT->DrawSplitterPane(dc, nPane); |
| 374 } |
| 375 } |
| 376 else |
| 377 { |
| 378 if(m_hWndPane[m_nSinglePane] == NULL) |
| 379 pT->DrawSplitterPane(dc, m_nSinglePane); |
| 380 } |
| 381 } |
| 382 |
| 383 // Overrideables |
| 384 void DrawSplitterBar(CDCHandle dc) |
| 385 { |
| 386 RECT rect; |
| 387 if(GetSplitterBarRect(&rect)) |
| 388 { |
| 389 dc.FillRect(&rect, COLOR_3DFACE); |
| 390 // draw 3D edge if needed |
| 391 T* pT = static_cast<T*>(this); |
| 392 if((pT->GetExStyle() & WS_EX_CLIENTEDGE) != 0) |
| 393 dc.DrawEdge(&rect, EDGE_RAISED, t_bVertical ? (B
F_LEFT | BF_RIGHT) : (BF_TOP | BF_BOTTOM)); |
| 394 } |
| 395 } |
| 396 |
| 397 // called only if pane is empty |
| 398 void DrawSplitterPane(CDCHandle dc, int nPane) |
| 399 { |
| 400 RECT rect; |
| 401 if(GetSplitterPaneRect(nPane, &rect)) |
| 402 { |
| 403 T* pT = static_cast<T*>(this); |
| 404 if((pT->GetExStyle() & WS_EX_CLIENTEDGE) == 0) |
| 405 dc.DrawEdge(&rect, EDGE_SUNKEN, BF_RECT | BF_ADJ
UST); |
| 406 dc.FillRect(&rect, COLOR_APPWORKSPACE); |
| 407 } |
| 408 } |
| 409 |
| 410 // Message map and handlers |
| 411 BEGIN_MSG_MAP(CSplitterImpl) |
| 412 MESSAGE_HANDLER(WM_CREATE, OnCreate) |
| 413 MESSAGE_HANDLER(WM_PAINT, OnPaint) |
| 414 #ifndef _WIN32_WCE |
| 415 MESSAGE_HANDLER(WM_PRINTCLIENT, OnPaint) |
| 416 #endif // !_WIN32_WCE |
| 417 if(IsInteractive()) |
| 418 { |
| 419 MESSAGE_HANDLER(WM_SETCURSOR, OnSetCursor) |
| 420 MESSAGE_HANDLER(WM_MOUSEMOVE, OnMouseMove) |
| 421 MESSAGE_HANDLER(WM_LBUTTONDOWN, OnLButtonDown) |
| 422 MESSAGE_HANDLER(WM_LBUTTONUP, OnLButtonUp) |
| 423 MESSAGE_HANDLER(WM_LBUTTONDBLCLK, OnLButtonDoubleClick) |
| 424 MESSAGE_HANDLER(WM_CAPTURECHANGED, OnCaptureChanged) |
| 425 } |
| 426 MESSAGE_HANDLER(WM_SETFOCUS, OnSetFocus) |
| 427 #ifndef _WIN32_WCE |
| 428 MESSAGE_HANDLER(WM_MOUSEACTIVATE, OnMouseActivate) |
| 429 #endif // !_WIN32_WCE |
| 430 MESSAGE_HANDLER(WM_SETTINGCHANGE, OnSettingChange) |
| 431 END_MSG_MAP() |
| 432 |
| 433 LRESULT OnCreate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BO
OL& bHandled) |
| 434 { |
| 435 GetSystemSettings(false); |
| 436 bHandled = FALSE; |
| 437 return 1; |
| 438 } |
| 439 |
| 440 LRESULT OnPaint(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOO
L& /*bHandled*/) |
| 441 { |
| 442 T* pT = static_cast<T*>(this); |
| 443 // try setting position if not set |
| 444 if(m_nSinglePane == SPLIT_PANE_NONE && m_xySplitterPos == -1) |
| 445 pT->SetSplitterPos(); |
| 446 // do painting |
| 447 CPaintDC dc(pT->m_hWnd); |
| 448 pT->DrawSplitter(dc.m_hDC); |
| 449 return 0; |
| 450 } |
| 451 |
| 452 LRESULT OnSetCursor(UINT /*uMsg*/, WPARAM wParam, LPARAM lParam, BOOL& b
Handled) |
| 453 { |
| 454 T* pT = static_cast<T*>(this); |
| 455 if((HWND)wParam == pT->m_hWnd && LOWORD(lParam) == HTCLIENT) |
| 456 { |
| 457 DWORD dwPos = ::GetMessagePos(); |
| 458 POINT ptPos = { GET_X_LPARAM(dwPos), GET_Y_LPARAM(dwPos)
}; |
| 459 pT->ScreenToClient(&ptPos); |
| 460 if(IsOverSplitterBar(ptPos.x, ptPos.y)) |
| 461 return 1; |
| 462 } |
| 463 |
| 464 bHandled = FALSE; |
| 465 return 0; |
| 466 } |
| 467 |
| 468 LRESULT OnMouseMove(UINT /*uMsg*/, WPARAM wParam, LPARAM lParam, BOOL& b
Handled) |
| 469 { |
| 470 T* pT = static_cast<T*>(this); |
| 471 int xPos = GET_X_LPARAM(lParam); |
| 472 int yPos = GET_Y_LPARAM(lParam); |
| 473 if((wParam & MK_LBUTTON) && ::GetCapture() == pT->m_hWnd) |
| 474 { |
| 475 int xyNewSplitPos = 0; |
| 476 if(t_bVertical) |
| 477 xyNewSplitPos = xPos - m_rcSplitter.left - m_cxy
DragOffset; |
| 478 else |
| 479 xyNewSplitPos = yPos - m_rcSplitter.top - m_cxyD
ragOffset; |
| 480 |
| 481 if(xyNewSplitPos == -1) // avoid -1, that means middle |
| 482 xyNewSplitPos = -2; |
| 483 |
| 484 if(m_xySplitterPos != xyNewSplitPos) |
| 485 { |
| 486 if(m_bFullDrag) |
| 487 { |
| 488 if(pT->SetSplitterPos(xyNewSplitPos, tru
e)) |
| 489 pT->UpdateWindow(); |
| 490 } |
| 491 else |
| 492 { |
| 493 DrawGhostBar(); |
| 494 pT->SetSplitterPos(xyNewSplitPos, false)
; |
| 495 DrawGhostBar(); |
| 496 } |
| 497 } |
| 498 } |
| 499 else // not dragging, just set cursor |
| 500 { |
| 501 if(IsOverSplitterBar(xPos, yPos)) |
| 502 ::SetCursor(m_hCursor); |
| 503 bHandled = FALSE; |
| 504 } |
| 505 |
| 506 return 0; |
| 507 } |
| 508 |
| 509 LRESULT OnLButtonDown(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, B
OOL& bHandled) |
| 510 { |
| 511 int xPos = GET_X_LPARAM(lParam); |
| 512 int yPos = GET_Y_LPARAM(lParam); |
| 513 if(IsOverSplitterBar(xPos, yPos)) |
| 514 { |
| 515 T* pT = static_cast<T*>(this); |
| 516 pT->SetCapture(); |
| 517 ::SetCursor(m_hCursor); |
| 518 if(!m_bFullDrag) |
| 519 DrawGhostBar(); |
| 520 if(t_bVertical) |
| 521 m_cxyDragOffset = xPos - m_rcSplitter.left - m_x
ySplitterPos; |
| 522 else |
| 523 m_cxyDragOffset = yPos - m_rcSplitter.top - m_xy
SplitterPos; |
| 524 } |
| 525 bHandled = FALSE; |
| 526 return 1; |
| 527 } |
| 528 |
| 529 LRESULT OnLButtonUp(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/,
BOOL& bHandled) |
| 530 { |
| 531 ::ReleaseCapture(); |
| 532 bHandled = FALSE; |
| 533 return 1; |
| 534 } |
| 535 |
| 536 LRESULT OnLButtonDoubleClick(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*
lParam*/, BOOL& /*bHandled*/) |
| 537 { |
| 538 T* pT = static_cast<T*>(this); |
| 539 pT->SetSplitterPos(); // middle |
| 540 return 0; |
| 541 } |
| 542 |
| 543 LRESULT OnCaptureChanged(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lPar
am*/, BOOL& /*bHandled*/) |
| 544 { |
| 545 if(!m_bFullDrag) |
| 546 { |
| 547 DrawGhostBar(); |
| 548 UpdateSplitterLayout(); |
| 549 T* pT = static_cast<T*>(this); |
| 550 pT->UpdateWindow(); |
| 551 } |
| 552 return 0; |
| 553 } |
| 554 |
| 555 LRESULT OnSetFocus(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM, BOOL& bHand
led) |
| 556 { |
| 557 if(m_nSinglePane == SPLIT_PANE_NONE) |
| 558 { |
| 559 if(m_nDefActivePane == SPLIT_PANE_LEFT || m_nDefActivePa
ne == SPLIT_PANE_RIGHT) |
| 560 ::SetFocus(m_hWndPane[m_nDefActivePane]); |
| 561 } |
| 562 else |
| 563 { |
| 564 ::SetFocus(m_hWndPane[m_nSinglePane]); |
| 565 } |
| 566 bHandled = FALSE; |
| 567 return 1; |
| 568 } |
| 569 |
| 570 #ifndef _WIN32_WCE |
| 571 LRESULT OnMouseActivate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /
*bHandled*/) |
| 572 { |
| 573 T* pT = static_cast<T*>(this); |
| 574 LRESULT lRet = pT->DefWindowProc(uMsg, wParam, lParam); |
| 575 if(lRet == MA_ACTIVATE || lRet == MA_ACTIVATEANDEAT) |
| 576 { |
| 577 DWORD dwPos = ::GetMessagePos(); |
| 578 POINT pt = { GET_X_LPARAM(dwPos), GET_Y_LPARAM(dwPos) }; |
| 579 pT->ScreenToClient(&pt); |
| 580 RECT rcPane; |
| 581 for(int nPane = 0; nPane < m_nPanesCount; nPane++) |
| 582 { |
| 583 if(GetSplitterPaneRect(nPane, &rcPane) && ::PtIn
Rect(&rcPane, pt)) |
| 584 { |
| 585 m_nDefActivePane = nPane; |
| 586 break; |
| 587 } |
| 588 } |
| 589 } |
| 590 return lRet; |
| 591 } |
| 592 #endif // !_WIN32_WCE |
| 593 |
| 594 LRESULT OnSettingChange(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lPara
m*/, BOOL& /*bHandled*/) |
| 595 { |
| 596 GetSystemSettings(true); |
| 597 return 0; |
| 598 } |
| 599 |
| 600 // Implementation - internal helpers |
| 601 void UpdateSplitterLayout() |
| 602 { |
| 603 if(m_nSinglePane == SPLIT_PANE_NONE && m_xySplitterPos == -1) |
| 604 return; |
| 605 |
| 606 T* pT = static_cast<T*>(this); |
| 607 RECT rect = { 0, 0, 0, 0 }; |
| 608 if(m_nSinglePane == SPLIT_PANE_NONE) |
| 609 { |
| 610 if(GetSplitterBarRect(&rect)) |
| 611 pT->InvalidateRect(&rect); |
| 612 |
| 613 for(int nPane = 0; nPane < m_nPanesCount; nPane++) |
| 614 { |
| 615 if(GetSplitterPaneRect(nPane, &rect)) |
| 616 { |
| 617 if(m_hWndPane[nPane] != NULL) |
| 618 ::SetWindowPos(m_hWndPane[nPane]
, NULL, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, SWP
_NOZORDER); |
| 619 else |
| 620 pT->InvalidateRect(&rect); |
| 621 } |
| 622 } |
| 623 } |
| 624 else |
| 625 { |
| 626 if(GetSplitterPaneRect(m_nSinglePane, &rect)) |
| 627 { |
| 628 if(m_hWndPane[m_nSinglePane] != NULL) |
| 629 ::SetWindowPos(m_hWndPane[m_nSinglePane]
, NULL, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, SWP
_NOZORDER); |
| 630 else |
| 631 pT->InvalidateRect(&rect); |
| 632 } |
| 633 } |
| 634 } |
| 635 |
| 636 bool GetSplitterBarRect(LPRECT lpRect) const |
| 637 { |
| 638 ATLASSERT(lpRect != NULL); |
| 639 if(m_nSinglePane != SPLIT_PANE_NONE || m_xySplitterPos == -1) |
| 640 return false; |
| 641 |
| 642 if(t_bVertical) |
| 643 { |
| 644 lpRect->left = m_rcSplitter.left + m_xySplitterPos; |
| 645 lpRect->top = m_rcSplitter.top; |
| 646 lpRect->right = m_rcSplitter.left + m_xySplitterPos + m_
cxySplitBar + m_cxyBarEdge; |
| 647 lpRect->bottom = m_rcSplitter.bottom; |
| 648 } |
| 649 else |
| 650 { |
| 651 lpRect->left = m_rcSplitter.left; |
| 652 lpRect->top = m_rcSplitter.top + m_xySplitterPos; |
| 653 lpRect->right = m_rcSplitter.right; |
| 654 lpRect->bottom = m_rcSplitter.top + m_xySplitterPos + m_
cxySplitBar + m_cxyBarEdge; |
| 655 } |
| 656 |
| 657 return true; |
| 658 } |
| 659 |
| 660 bool GetSplitterPaneRect(int nPane, LPRECT lpRect) const |
| 661 { |
| 662 ATLASSERT(nPane == SPLIT_PANE_LEFT || nPane == SPLIT_PANE_RIGHT)
; |
| 663 ATLASSERT(lpRect != NULL); |
| 664 bool bRet = true; |
| 665 if(m_nSinglePane != SPLIT_PANE_NONE) |
| 666 { |
| 667 if(nPane == m_nSinglePane) |
| 668 *lpRect = m_rcSplitter; |
| 669 else |
| 670 bRet = false; |
| 671 } |
| 672 else if(nPane == SPLIT_PANE_LEFT) |
| 673 { |
| 674 if(t_bVertical) |
| 675 { |
| 676 lpRect->left = m_rcSplitter.left; |
| 677 lpRect->top = m_rcSplitter.top; |
| 678 lpRect->right = m_rcSplitter.left + m_xySplitter
Pos; |
| 679 lpRect->bottom = m_rcSplitter.bottom; |
| 680 } |
| 681 else |
| 682 { |
| 683 lpRect->left = m_rcSplitter.left; |
| 684 lpRect->top = m_rcSplitter.top; |
| 685 lpRect->right = m_rcSplitter.right; |
| 686 lpRect->bottom = m_rcSplitter.top + m_xySplitter
Pos; |
| 687 } |
| 688 } |
| 689 else if(nPane == SPLIT_PANE_RIGHT) |
| 690 { |
| 691 if(t_bVertical) |
| 692 { |
| 693 lpRect->left = m_rcSplitter.left + m_xySplitterP
os + m_cxySplitBar + m_cxyBarEdge; |
| 694 lpRect->top = m_rcSplitter.top; |
| 695 lpRect->right = m_rcSplitter.right; |
| 696 lpRect->bottom = m_rcSplitter.bottom; |
| 697 } |
| 698 else |
| 699 { |
| 700 lpRect->left = m_rcSplitter.left; |
| 701 lpRect->top = m_rcSplitter.top + m_xySplitterPos
+ m_cxySplitBar + m_cxyBarEdge; |
| 702 lpRect->right = m_rcSplitter.right; |
| 703 lpRect->bottom = m_rcSplitter.bottom; |
| 704 } |
| 705 } |
| 706 else |
| 707 { |
| 708 bRet = false; |
| 709 } |
| 710 return bRet; |
| 711 } |
| 712 |
| 713 bool IsOverSplitterRect(int x, int y) const |
| 714 { |
| 715 // -1 == don't check |
| 716 return ((x == -1 || (x >= m_rcSplitter.left && x <= m_rcSplitter
.right)) && |
| 717 (y == -1 || (y >= m_rcSplitter.top && y <= m_rcSplitter.
bottom))); |
| 718 } |
| 719 |
| 720 bool IsOverSplitterBar(int x, int y) const |
| 721 { |
| 722 if(m_nSinglePane != SPLIT_PANE_NONE) |
| 723 return false; |
| 724 if(m_xySplitterPos == -1 || !IsOverSplitterRect(x, y)) |
| 725 return false; |
| 726 int xy = t_bVertical ? x : y; |
| 727 int xyOff = t_bVertical ? m_rcSplitter.left : m_rcSplitter.top; |
| 728 return ((xy >= (xyOff + m_xySplitterPos)) && (xy < xyOff + m_xyS
plitterPos + m_cxySplitBar + m_cxyBarEdge)); |
| 729 } |
| 730 |
| 731 void DrawGhostBar() |
| 732 { |
| 733 RECT rect = { 0, 0, 0, 0 }; |
| 734 if(GetSplitterBarRect(&rect)) |
| 735 { |
| 736 // invert the brush pattern (looks just like frame windo
w sizing) |
| 737 T* pT = static_cast<T*>(this); |
| 738 CWindowDC dc(pT->m_hWnd); |
| 739 CBrush brush = CDCHandle::GetHalftoneBrush(); |
| 740 if(brush.m_hBrush != NULL) |
| 741 { |
| 742 CBrushHandle brushOld = dc.SelectBrush(brush); |
| 743 dc.PatBlt(rect.left, rect.top, rect.right - rect
.left, rect.bottom - rect.top, PATINVERT); |
| 744 dc.SelectBrush(brushOld); |
| 745 } |
| 746 } |
| 747 } |
| 748 |
| 749 void GetSystemSettings(bool bUpdate) |
| 750 { |
| 751 #ifndef _WIN32_WCE |
| 752 m_cxySplitBar = ::GetSystemMetrics(t_bVertical ? SM_CXSIZEFRAME
: SM_CYSIZEFRAME); |
| 753 #else // CE specific |
| 754 m_cxySplitBar = 2 * ::GetSystemMetrics(t_bVertical ? SM_CXEDGE :
SM_CYEDGE); |
| 755 #endif // _WIN32_WCE |
| 756 |
| 757 T* pT = static_cast<T*>(this); |
| 758 if((pT->GetExStyle() & WS_EX_CLIENTEDGE)) |
| 759 { |
| 760 m_cxyBarEdge = 2 * ::GetSystemMetrics(t_bVertical ? SM_C
XEDGE : SM_CYEDGE); |
| 761 m_cxyMin = 0; |
| 762 } |
| 763 else |
| 764 { |
| 765 m_cxyBarEdge = 0; |
| 766 m_cxyMin = 2 * ::GetSystemMetrics(t_bVertical ? SM_CXEDG
E : SM_CYEDGE); |
| 767 } |
| 768 |
| 769 #ifndef _WIN32_WCE |
| 770 ::SystemParametersInfo(SPI_GETDRAGFULLWINDOWS, 0, &m_bFullDrag,
0); |
| 771 #endif // !_WIN32_WCE |
| 772 |
| 773 if(bUpdate) |
| 774 UpdateSplitterLayout(); |
| 775 } |
| 776 |
| 777 bool IsProportional() const |
| 778 { |
| 779 return ((m_dwExtendedStyle & SPLIT_PROPORTIONAL) != 0); |
| 780 } |
| 781 |
| 782 void StoreProportionalPos() |
| 783 { |
| 784 int cxyTotal = t_bVertical ? (m_rcSplitter.right - m_rcSplitter.
left - m_cxySplitBar - m_cxyBarEdge) : (m_rcSplitter.bottom - m_rcSplitter.top -
m_cxySplitBar - m_cxyBarEdge); |
| 785 if(cxyTotal > 0) |
| 786 m_nProportionalPos = ::MulDiv(m_xySplitterPos, m_nPropMa
x, cxyTotal); |
| 787 else |
| 788 m_nProportionalPos = 0; |
| 789 ATLTRACE2(atlTraceUI, 0, _T("CSplitterImpl::StoreProportionalPos
- %i\n"), m_nProportionalPos); |
| 790 } |
| 791 |
| 792 void UpdateProportionalPos() |
| 793 { |
| 794 int cxyTotal = t_bVertical ? (m_rcSplitter.right - m_rcSplitter.
left - m_cxySplitBar - m_cxyBarEdge) : (m_rcSplitter.bottom - m_rcSplitter.top -
m_cxySplitBar - m_cxyBarEdge); |
| 795 if(cxyTotal > 0) |
| 796 { |
| 797 int xyNewPos = ::MulDiv(m_nProportionalPos, cxyTotal, m_
nPropMax); |
| 798 m_bUpdateProportionalPos = false; |
| 799 T* pT = static_cast<T*>(this); |
| 800 pT->SetSplitterPos(xyNewPos, false); |
| 801 } |
| 802 } |
| 803 |
| 804 bool IsRightAligned() const |
| 805 { |
| 806 return ((m_dwExtendedStyle & SPLIT_RIGHTALIGNED) != 0); |
| 807 } |
| 808 |
| 809 void StoreRightAlignPos() |
| 810 { |
| 811 int cxyTotal = t_bVertical ? (m_rcSplitter.right - m_rcSplitter.
left - m_cxySplitBar - m_cxyBarEdge) : (m_rcSplitter.bottom - m_rcSplitter.top -
m_cxySplitBar - m_cxyBarEdge); |
| 812 if(cxyTotal > 0) |
| 813 m_nProportionalPos = cxyTotal - m_xySplitterPos; |
| 814 else |
| 815 m_nProportionalPos = 0; |
| 816 ATLTRACE2(atlTraceUI, 0, _T("CSplitterImpl::StoreRightAlignPos -
%i\n"), m_nProportionalPos); |
| 817 } |
| 818 |
| 819 void UpdateRightAlignPos() |
| 820 { |
| 821 int cxyTotal = t_bVertical ? (m_rcSplitter.right - m_rcSplitter.
left - m_cxySplitBar - m_cxyBarEdge) : (m_rcSplitter.bottom - m_rcSplitter.top -
m_cxySplitBar - m_cxyBarEdge); |
| 822 if(cxyTotal > 0) |
| 823 { |
| 824 m_bUpdateProportionalPos = false; |
| 825 T* pT = static_cast<T*>(this); |
| 826 pT->SetSplitterPos(cxyTotal - m_nProportionalPos, false)
; |
| 827 } |
| 828 } |
| 829 |
| 830 bool IsInteractive() const |
| 831 { |
| 832 return ((m_dwExtendedStyle & SPLIT_NONINTERACTIVE) == 0); |
| 833 } |
| 834 }; |
| 835 |
| 836 template <class T, bool t_bVertical> HCURSOR CSplitterImpl< T, t_bVertical>::m_h
Cursor = NULL; |
| 837 |
| 838 |
| 839 /////////////////////////////////////////////////////////////////////////////// |
| 840 // CSplitterWindowImpl - Implements a splitter window |
| 841 |
| 842 template <class T, bool t_bVertical = true, class TBase = ATL::CWindow, class TW
inTraits = ATL::CControlWinTraits> |
| 843 class ATL_NO_VTABLE CSplitterWindowImpl : public ATL::CWindowImpl< T, TBase, TWi
nTraits >, public CSplitterImpl< T , t_bVertical > |
| 844 { |
| 845 public: |
| 846 DECLARE_WND_CLASS_EX(NULL, CS_DBLCLKS, COLOR_WINDOW) |
| 847 |
| 848 typedef CSplitterImpl< T , t_bVertical > _baseClass; |
| 849 |
| 850 BEGIN_MSG_MAP(CSplitterWindowImpl) |
| 851 MESSAGE_HANDLER(WM_ERASEBKGND, OnEraseBackground) |
| 852 MESSAGE_HANDLER(WM_SIZE, OnSize) |
| 853 CHAIN_MSG_MAP(_baseClass) |
| 854 FORWARD_NOTIFICATIONS() |
| 855 END_MSG_MAP() |
| 856 |
| 857 LRESULT OnEraseBackground(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lPa
ram*/, BOOL& /*bHandled*/) |
| 858 { |
| 859 // handled, no background painting needed |
| 860 return 1; |
| 861 } |
| 862 |
| 863 LRESULT OnSize(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bH
andled) |
| 864 { |
| 865 if(wParam != SIZE_MINIMIZED) |
| 866 SetSplitterRect(); |
| 867 |
| 868 bHandled = FALSE; |
| 869 return 1; |
| 870 } |
| 871 }; |
| 872 |
| 873 |
| 874 /////////////////////////////////////////////////////////////////////////////// |
| 875 // CSplitterWindow - Implements a splitter window to be used as is |
| 876 |
| 877 template <bool t_bVertical = true> |
| 878 class CSplitterWindowT : public CSplitterWindowImpl<CSplitterWindowT<t_bVertical
>, t_bVertical> |
| 879 { |
| 880 public: |
| 881 DECLARE_WND_CLASS_EX(_T("WTL_SplitterWindow"), CS_DBLCLKS, COLOR_WINDOW) |
| 882 }; |
| 883 |
| 884 typedef CSplitterWindowT<true> CSplitterWindow; |
| 885 typedef CSplitterWindowT<false> CHorSplitterWindow; |
| 886 |
| 887 }; // namespace WTL |
| 888 |
| 889 #endif // __ATLSPLIT_H__ |
OLD | NEW |