ExtControlsCommon.cpp
上传用户:sesekoo
上传日期:2020-07-18
资源大小:21543k
文件大小:275k
源码类别:

界面编程

开发平台:

Visual C++

  1. // This is part of the Professional User Interface Suite library.
  2. // Copyright (C) 2001-2009 FOSS Software, Inc.
  3. // All rights reserved.
  4. //
  5. // http://www.prof-uis.com
  6. // mailto:support@prof-uis.com
  7. //
  8. // This source code can be used, modified and redistributed
  9. // under the terms of the license agreement that is included
  10. // in the Professional User Interface Suite package.
  11. //
  12. // Warranties and Disclaimers:
  13. // THIS SOFTWARE IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND
  14. // INCLUDING, BUT NOT LIMITED TO, WARRANTIES OF MERCHANTABILITY,
  15. // FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
  16. // IN NO EVENT WILL FOSS SOFTWARE INC. BE LIABLE FOR ANY DIRECT,
  17. // INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES,
  18. // INCLUDING DAMAGES FOR LOSS OF PROFITS, LOSS OR INACCURACY OF DATA,
  19. // INCURRED BY ANY PERSON FROM SUCH PERSON'S USAGE OF THIS SOFTWARE
  20. // EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
  21. #include "stdafx.h"
  22. #if (!defined __EXT_CONTROLS_COMMON_H)
  23. #include <ExtControlsCommon.h>
  24. #endif
  25. #if (!defined __EXT_LOCALIZATION_H)
  26. #include <../Src/ExtLocalization.h>
  27. #endif
  28. #include <Resources/Resource.h>
  29. #if (!defined __PROF_UIS_RES_CC_SC_H)
  30. #include <Resources/ResCommonControls/ResCommonControls.h>
  31. #endif
  32. #ifdef _DEBUG
  33. #define new DEBUG_NEW
  34. #undef THIS_FILE
  35. static char THIS_FILE[] = __FILE__;
  36. #endif
  37. #if ( ! defined __EXT_MFC_NO_LIST_VIEW_CTRL )
  38. /////////////////////////////////////////////////////////////////////////////
  39. // CExtListCtrlDataSortOrder
  40. IMPLEMENT_SERIAL( CExtListCtrlDataSortOrder, CObject, VERSIONABLE_SCHEMA|1 );
  41. CExtListCtrlDataSortOrder::CExtListCtrlDataSortOrder()
  42. {
  43. }
  44. CExtListCtrlDataSortOrder::CExtListCtrlDataSortOrder(
  45. const CExtListCtrlDataSortOrder & other
  46. )
  47. {
  48. _AssignFromOther( other );
  49. }
  50. CExtListCtrlDataSortOrder::~CExtListCtrlDataSortOrder()
  51. {
  52. Empty();
  53. }
  54. void CExtListCtrlDataSortOrder::_AssignFromOther(
  55. const CExtListCtrlDataSortOrder & other
  56. )
  57. {
  58. ASSERT_VALID( this );
  59. ASSERT_VALID( (&other) );
  60. Empty();
  61. LONG nCount = (LONG)other.m_arrItems.GetSize();
  62. for( LONG i = 0L; i < nCount; i++ )
  63. {
  64. COLUMN_INFO _itemDst( other.m_arrItems[ i ] );
  65. m_arrItems.Add( _itemDst );
  66. }
  67. ASSERT( nCount == m_arrItems.GetSize() );
  68. }
  69. CExtListCtrlDataSortOrder & CExtListCtrlDataSortOrder::operator =(
  70. const CExtListCtrlDataSortOrder & other
  71. )
  72. {
  73. ASSERT_VALID( this );
  74. ASSERT_VALID( (&other) );
  75. _AssignFromOther( other );
  76. return (*this);
  77. }
  78. bool CExtListCtrlDataSortOrder::operator == (
  79. const CExtListCtrlDataSortOrder & other
  80. ) const
  81. {
  82. ASSERT_VALID( this );
  83. ASSERT_VALID( (&other) );
  84. LONG nCount = (LONG)m_arrItems.GetSize();
  85. LONG i = (LONG)other.m_arrItems.GetSize();
  86. if( nCount != i )
  87. return false;
  88. for( i = 0L; i < nCount; i++ )
  89. {
  90. const COLUMN_INFO & _itemSrc = m_arrItems[ i ];
  91. const COLUMN_INFO & _itemDst = other.m_arrItems[ i ];
  92. if( _itemSrc != _itemDst )
  93. return false;
  94. }
  95. return true;
  96. }
  97. bool CExtListCtrlDataSortOrder::operator != (
  98. const CExtListCtrlDataSortOrder & other
  99. ) const
  100. {
  101. ASSERT_VALID( this );
  102. ASSERT_VALID( (&other) );
  103. if( (*this) == other )
  104. return false;
  105. return true;
  106. }
  107. #ifdef _DEBUG
  108. void CExtListCtrlDataSortOrder::AssertValid() const
  109. {
  110. CObject::AssertValid();
  111. }
  112. void CExtListCtrlDataSortOrder::Dump( CDumpContext & dc ) const
  113. {
  114. CObject::Dump( dc );
  115. }
  116. #endif // _DEBUG
  117. void CExtListCtrlDataSortOrder::Serialize( CArchive & ar )
  118. {
  119. CObject::Serialize( ar );
  120. DWORD i, dwCount;
  121. if( ar.IsStoring() )
  122. {
  123. dwCount = (DWORD)m_arrItems.GetSize();
  124. ar << dwCount;
  125. for( i = 0; i < dwCount; i++ )
  126. {
  127. COLUMN_INFO & _itemSrc = m_arrItems[ i ];
  128. _itemSrc.Serialize( ar );
  129. }
  130. } // if( ar.IsStoring() )
  131. else
  132. {
  133. m_arrItems.RemoveAll();
  134. ar >> dwCount;
  135. for( i = 0; i < dwCount; i++ )
  136. {
  137. COLUMN_INFO _itemSrc;
  138. _itemSrc.Serialize( ar );
  139. m_arrItems.Add( _itemSrc );
  140. }
  141. ASSERT( DWORD( m_arrItems.GetSize() ) == dwCount );
  142. } // else from if( ar.IsStoring() )
  143. }
  144. bool CExtListCtrlDataSortOrder::ItemsUnique() const
  145. {
  146. ASSERT_VALID( this );
  147. LONG nCount = (LONG)m_arrItems.GetSize();
  148. for( LONG i = 0L; i < (nCount - 1L); i++ )
  149. {
  150. const COLUMN_INFO & _itemSrc = m_arrItems[ i ];
  151. for( LONG j = (i + 1L); j < nCount; j++ )
  152. {
  153. const COLUMN_INFO & _itemDst = m_arrItems[ j ];
  154. if( _itemSrc == _itemDst )
  155. return false;
  156. }
  157. }
  158. return true;
  159. }
  160. void CExtListCtrlDataSortOrder::MakeItemsUnique()
  161. {
  162. ASSERT_VALID( this );
  163. LONG nCount = (LONG)m_arrItems.GetSize();
  164. for( LONG i = 0L; i < (nCount - 1L); i++ )
  165. {
  166. const COLUMN_INFO & _itemSrc = m_arrItems[ i ];
  167. for( LONG j = (i + 1L); j < nCount; )
  168. {
  169. const COLUMN_INFO & _itemDst = m_arrItems[ j ];
  170. if( _itemSrc != _itemDst )
  171. {
  172. j++;
  173. continue;
  174. }
  175. nCount--;
  176. m_arrItems.RemoveAt( j, 1 );
  177. }
  178. }
  179. }
  180. bool CExtListCtrlDataSortOrder::IsEmpty() const
  181. {
  182. ASSERT_VALID( this );
  183. if( m_arrItems.GetSize() > 0L )
  184. return false;
  185. else
  186. return true;
  187. }
  188. void CExtListCtrlDataSortOrder::Empty()
  189. {
  190. ASSERT_VALID( this );
  191. m_arrItems.RemoveAll();
  192. }
  193. LONG CExtListCtrlDataSortOrder::GetColPos( LONG nColNo ) const
  194. {
  195. ASSERT_VALID( this );
  196. LONG nCount = (LONG)m_arrItems.GetSize();
  197. for( LONG i = 0L; i < nCount; i++ )
  198. {
  199. const COLUMN_INFO & _itemSrc = m_arrItems[ i ];
  200. if( _itemSrc.m_nColNo == nColNo )
  201. return i;
  202. }
  203. return -1L;
  204. }
  205. void CExtListCtrlDataSortOrder::SetupOrder(
  206. const CExtListCtrlDataSortOrder & _gdsoUpdate,
  207. bool bInvertIntersectionSortOrder
  208. )
  209. {
  210. ASSERT_VALID( this );
  211. ASSERT( ItemsUnique() );
  212. ASSERT_VALID( (&_gdsoUpdate) );
  213. ASSERT( _gdsoUpdate.ItemsUnique() );
  214. LONG nCount = (LONG)m_arrItems.GetSize();
  215. if( nCount == 0 )
  216. {
  217. (*this) = _gdsoUpdate;
  218. return;
  219. } // if( nCount == 0 )
  220. LONG nCountUpdate = (LONG)_gdsoUpdate.m_arrItems.GetSize();
  221. for( LONG u = 0L; u < nCountUpdate; u++ )
  222. {
  223. const COLUMN_INFO & _itemUpdate = _gdsoUpdate.m_arrItems[ u ];
  224. COLUMN_INFO _itemSetup( _itemUpdate );
  225. LONG i = GetColPos( _itemUpdate.m_nColNo );
  226. if( i < 0L )
  227. {
  228. m_arrItems.Add( _itemSetup );
  229. continue;
  230. }
  231. COLUMN_INFO & _itemDst = m_arrItems[ i ];
  232. ASSERT( _itemDst.m_nColNo == _itemUpdate.m_nColNo );
  233. if( _itemDst == _itemUpdate
  234. && (! bInvertIntersectionSortOrder )
  235. )
  236. continue;
  237. if( bInvertIntersectionSortOrder )
  238. _itemSetup.m_bAscending = (! _itemDst.m_bAscending);
  239. m_arrItems.SetAt( i, _itemSetup );
  240. }
  241. ASSERT_VALID( this );
  242. ASSERT( ItemsUnique() );
  243. }
  244. void CExtListCtrlDataSortOrder::UpdateIndices(
  245. LONG nColNo,
  246. LONG nInsertRemoveCount,
  247. bool bInsert
  248. )
  249. {
  250. ASSERT_VALID( this );
  251. ASSERT( nColNo >= 0L );
  252. ASSERT( nInsertRemoveCount >= 0L );
  253. if( nInsertRemoveCount == 0L )
  254. return;
  255. LONG nCount = (LONG)m_arrItems.GetSize();
  256. for( LONG i = 0L; i < nCount; )
  257. {
  258. COLUMN_INFO _itemUpdate( m_arrItems[ i ] );
  259. if( bInsert )
  260. {
  261. if( _itemUpdate.m_nColNo >= nColNo )
  262. {
  263. _itemUpdate.m_nColNo += nInsertRemoveCount;
  264. m_arrItems.SetAt( i, _itemUpdate );
  265. }
  266. i++;
  267. }
  268. else
  269. {
  270. if( _itemUpdate.m_nColNo >= (nColNo+nInsertRemoveCount) )
  271. {
  272. _itemUpdate.m_nColNo -= nInsertRemoveCount;
  273. m_arrItems.SetAt( i, _itemUpdate );
  274. i++;
  275. }
  276. else if( _itemUpdate.m_nColNo >= nColNo )
  277. {
  278. m_arrItems.RemoveAt( i, 1 );
  279. nCount--;
  280. }
  281. else
  282. i++;
  283. }
  284. }
  285. }
  286. void CExtListCtrlDataSortOrder::SwapDroppedSeries(
  287. LONG nColNoSrc,
  288. LONG nColNoDropBefore
  289. )
  290. {
  291. ASSERT_VALID( this );
  292. ASSERT( nColNoSrc >= 0L );
  293. ASSERT( nColNoDropBefore >= 0L );
  294. if( nColNoSrc == nColNoDropBefore
  295. || (nColNoSrc+1L) == nColNoDropBefore
  296. )
  297. return;
  298. LONG nCount = (LONG)m_arrItems.GetSize();
  299. for( LONG i = 0L; i < nCount; i++ )
  300. {
  301. COLUMN_INFO _itemUpdate( m_arrItems[ i ] );
  302. if( nColNoSrc < nColNoDropBefore )
  303. {
  304. if( _itemUpdate.m_nColNo > nColNoSrc
  305. && _itemUpdate.m_nColNo < nColNoDropBefore
  306. )
  307. {
  308. _itemUpdate.m_nColNo --;
  309. m_arrItems.SetAt( i, _itemUpdate );
  310. }
  311. else if( _itemUpdate.m_nColNo == nColNoSrc )
  312. {
  313. _itemUpdate.m_nColNo = nColNoDropBefore - 1L;
  314. m_arrItems.SetAt( i, _itemUpdate );
  315. }
  316. } // if( nColNoSrc < nColNoDropBefore )
  317. else
  318. {
  319. ASSERT( nColNoSrc > nColNoDropBefore );
  320. if( _itemUpdate.m_nColNo < nColNoSrc
  321. && _itemUpdate.m_nColNo >= nColNoDropBefore
  322. )
  323. {
  324. _itemUpdate.m_nColNo ++;
  325. m_arrItems.SetAt( i, _itemUpdate );
  326. }
  327. else if( _itemUpdate.m_nColNo == nColNoSrc )
  328. {
  329. _itemUpdate.m_nColNo = nColNoDropBefore;
  330. m_arrItems.SetAt( i, _itemUpdate );
  331. }
  332. } // else from if( nColNoSrc < nColNoDropBefore )
  333. } // for( LONG i = 0L; i < nCount; i++ )
  334. }
  335. CExtListCtrlDataSortOrder::COLUMN_INFO::COLUMN_INFO(
  336. LONG nColNo, // = -1L
  337. bool bAscending // = true
  338. )
  339. : m_nColNo( nColNo )
  340. , m_bAscending( bAscending )
  341. {
  342. }
  343. CExtListCtrlDataSortOrder::COLUMN_INFO::COLUMN_INFO( const CExtListCtrlDataSortOrder::COLUMN_INFO & other )
  344. : m_nColNo( other.m_nColNo )
  345. , m_bAscending( other.m_bAscending )
  346. {
  347. }
  348. CExtListCtrlDataSortOrder::COLUMN_INFO & CExtListCtrlDataSortOrder::COLUMN_INFO::operator = ( const CExtListCtrlDataSortOrder::COLUMN_INFO & other )
  349. {
  350. m_nColNo = other.m_nColNo;
  351. m_bAscending = other.m_bAscending;
  352. return (*this);
  353. }
  354. void CExtListCtrlDataSortOrder::COLUMN_INFO::Serialize( CArchive & ar )
  355. {
  356. BYTE nFlags = 0;
  357. if( ar.IsStoring() )
  358. {
  359. if( m_bAscending )
  360. nFlags |= 0x01;
  361. ar.Write( &m_nColNo, sizeof(m_nColNo) );
  362. ar.Write( &nFlags, sizeof(nFlags) );
  363. } // if( ar.IsStoring() )
  364. else
  365. {
  366. ar.Read( &m_nColNo, sizeof(m_nColNo) );
  367. ar.Read( &nFlags, sizeof(nFlags) );
  368. if( (nFlags&0x01) != 0 )
  369. m_bAscending = true;
  370. else
  371. m_bAscending = false;
  372. } // else from if( ar.IsStoring() )
  373. }
  374. int CExtListCtrlDataSortOrder::COLUMN_INFO::Cmp( const CExtListCtrlDataSortOrder::COLUMN_INFO & other ) const
  375. {
  376. if( m_nColNo < other.m_nColNo )
  377. return -1;
  378. if( m_nColNo > other.m_nColNo )
  379. return 1;
  380. if( m_bAscending )
  381. {
  382. if( ! other.m_bAscending )
  383. return 1;
  384. } // if( m_bAscending )
  385. else
  386. {
  387. if( other.m_bAscending )
  388. return -1;
  389. } // else from if( m_bAscending )
  390. return 0;
  391. }
  392. bool CExtListCtrlDataSortOrder::COLUMN_INFO::operator == ( const CExtListCtrlDataSortOrder::COLUMN_INFO & other ) const
  393. {
  394. return ( (Cmp(other) == 0) ? true : false );
  395. }
  396. bool CExtListCtrlDataSortOrder::COLUMN_INFO::operator != ( const CExtListCtrlDataSortOrder::COLUMN_INFO & other ) const
  397. {
  398. return ( (Cmp(other) != 0) ? true : false );
  399. }
  400. bool CExtListCtrlDataSortOrder::COLUMN_INFO::operator <= ( const CExtListCtrlDataSortOrder::COLUMN_INFO & other ) const
  401. {
  402. return ( (Cmp(other) <= 0) ? true : false );
  403. }
  404. bool CExtListCtrlDataSortOrder::COLUMN_INFO::operator >= ( const CExtListCtrlDataSortOrder::COLUMN_INFO & other ) const
  405. {
  406. return ( (Cmp(other) >= 0) ? true : false );
  407. }
  408. bool CExtListCtrlDataSortOrder::COLUMN_INFO::operator < ( const CExtListCtrlDataSortOrder::COLUMN_INFO & other ) const
  409. {
  410. return ( (Cmp(other) < 0) ? true : false );
  411. }
  412. bool CExtListCtrlDataSortOrder::COLUMN_INFO::operator > ( const CExtListCtrlDataSortOrder::COLUMN_INFO & other ) const
  413. {
  414. return ( (Cmp(other) > 0) ? true : false );
  415. }
  416. /////////////////////////////////////////////////////////////////////////////
  417. // CExtHeaderCtrl
  418. IMPLEMENT_DYNCREATE( CExtHeaderCtrl, CHeaderCtrl );
  419. const UINT CExtHeaderCtrl::g_nMsgHeaderButtonClick =
  420. ::RegisterWindowMessage( _T("CExtHeaderCtrl::g_nMsgHeaderButtonClick") );
  421. bool CExtHeaderCtrl::g_bEnableOnIdleCalls = false;
  422. CExtHeaderCtrl::CExtHeaderCtrl()
  423. : m_nHoverColNo( -1 )
  424. , m_nHoverIndex( -1 )
  425. , m_nPressingColNo( -1 )
  426. , m_nPressingIndex( -1 )
  427. , m_ptScreenPressing( -32767, -32767 )
  428. , m_nHelperInitialResizingExtent( -32767 )
  429. , m_bOnButton( false )
  430. , m_bOnDividerAtRight( false )
  431. , m_bCancelingActions( false )
  432. , m_nDividerHalfExtent( 2 )
  433. , m_nAdvancedTipStyle( INT(CExtPopupMenuTipWnd::__ETS_RECTANGLE_NO_ICON) )
  434. , m_bShowTipsOverHeader( true )
  435. {
  436. m_hCursorDefault = ::LoadCursor( NULL, IDC_ARROW );
  437. ASSERT( m_hCursorDefault != NULL );
  438. CExtLocalResourceHelper _LRH;
  439. CWinApp * pApp = ::AfxGetApp();
  440. ASSERT_VALID( pApp );
  441. m_hCursorResizingH1 =  pApp->LoadCursor( MAKEINTRESOURCE( IDC_EXT_RESIZE_H1 ) );
  442. ASSERT( m_hCursorResizingH1 != NULL );
  443. m_hCursorResizingH2 =  pApp->LoadCursor( MAKEINTRESOURCE( IDC_EXT_RESIZE_H2 ) );
  444. ASSERT( m_hCursorResizingH2 != NULL );
  445. m_hCursorOuterDragOK = ::LoadCursor( NULL, IDC_ARROW );
  446. ASSERT( m_hCursorOuterDragOK != NULL );
  447. m_hCursorOuterDragCancel = pApp->LoadCursor( MAKEINTRESOURCE( IDC_EXT_BIG_X_CROSS ) );
  448. ASSERT( m_hCursorOuterDragCancel != NULL );
  449. PmBridge_Install( true );
  450. }
  451. CExtHeaderCtrl::~CExtHeaderCtrl()
  452. {
  453. PmBridge_Uninstall();
  454. if( m_hCursorDefault != NULL )
  455. ::DestroyCursor( m_hCursorDefault );
  456. if( m_hCursorResizingH1 != NULL )
  457. ::DestroyCursor( m_hCursorResizingH1 );
  458. if( m_hCursorResizingH2 != NULL )
  459. ::DestroyCursor( m_hCursorResizingH2 );
  460. if( m_hCursorOuterDragOK != NULL )
  461. ::DestroyCursor( m_hCursorOuterDragOK );
  462. if( m_hCursorOuterDragCancel != NULL )
  463. ::DestroyCursor( m_hCursorOuterDragCancel );
  464. }
  465. void CExtHeaderCtrl::PmBridge_OnPaintManagerChanged(
  466. CExtPaintManager * pGlobalPM
  467. )
  468. {
  469. ASSERT_VALID( this );
  470. CExtPmBridge::PmBridge_OnPaintManagerChanged( pGlobalPM );
  471. if( GetSafeHwnd() == NULL )
  472. return;
  473. Invalidate();
  474. }
  475. void CExtHeaderCtrl::_CancelActions()
  476. {
  477. ASSERT_VALID( this );
  478. if( m_bCancelingActions )
  479. return;
  480. m_bCancelingActions = true;
  481. if( m_bOnDividerAtRight )
  482. {
  483. HWND hWndParent = ::GetParent( m_hWnd );
  484. if( hWndParent != NULL )
  485. {
  486. UINT nOwnID = UINT( GetDlgCtrlID() );
  487. HD_NOTIFY _data, _data2;
  488. ::memset( &_data, 0, sizeof(HD_NOTIFY) );
  489. ::memset( &_data2, 0, sizeof(HD_NOTIFY) );
  490. _data.hdr.hwndFrom = m_hWnd;
  491. _data.hdr.idFrom = nOwnID;
  492. _data.iButton = 0;
  493. _data.iItem = m_nPressingColNo; //nColNo;
  494. _data.hdr.code = HDN_ENDTRACK;
  495. HDITEM hdItemBuffer; // to avoid common controls crashing
  496. ::memset( &hdItemBuffer, 0, sizeof(HDITEM) );
  497. _data.pitem = &hdItemBuffer;
  498. ::memcpy( &_data2, &_data, sizeof(HD_NOTIFY) );
  499. ::SendMessage( hWndParent, WM_NOTIFY, WPARAM(nOwnID), LPARAM(&_data) );
  500. _data2.hdr.code = HDN_ITEMCHANGED;
  501. ::SendMessage( hWndParent, WM_NOTIFY, WPARAM(nOwnID), LPARAM(&_data2) );
  502. if( ::IsWindow( hWndParent ) && ::IsWindowVisible( hWndParent ) )
  503. ::InvalidateRect( hWndParent, NULL, TRUE );
  504. } // if( hWndParent != NULL )
  505. } // if( m_bOnDividerAtRight )
  506. if( ( m_nHoverColNo >= 0 || m_nPressingColNo >= 0 )
  507. && GetSafeHwnd() != NULL
  508. )
  509. Invalidate();
  510. m_ptScreenPressing.x = m_ptScreenPressing.y = m_nHelperInitialResizingExtent = -32767;
  511. m_nHoverColNo = m_nHoverIndex = m_nPressingColNo = m_nPressingIndex = -1;
  512. m_bOnButton = m_bOnDividerAtRight = false;
  513. if( ::GetCapture() == m_hWnd )
  514. ReleaseCapture();
  515. m_bCancelingActions = false;
  516. }
  517. BEGIN_MESSAGE_MAP( CExtHeaderCtrl, CHeaderCtrl )
  518. //{{AFX_MSG_MAP(CExtHeaderCtrl)
  519. ON_WM_PAINT()
  520. ON_WM_ERASEBKGND()
  521. ON_WM_WINDOWPOSCHANGING()
  522. ON_WM_SETCURSOR()
  523. ON_WM_MOUSEMOVE()
  524. ON_WM_LBUTTONDOWN()
  525. ON_WM_LBUTTONUP()
  526. ON_WM_LBUTTONDBLCLK()
  527. ON_WM_RBUTTONDOWN()
  528. ON_WM_RBUTTONUP()
  529. ON_WM_RBUTTONDBLCLK()
  530. ON_WM_MBUTTONDOWN()
  531. ON_WM_MBUTTONUP()
  532. ON_WM_MBUTTONDBLCLK()
  533. ON_WM_CANCELMODE()
  534. ON_WM_CAPTURECHANGED()
  535. //}}AFX_MSG_MAP
  536. ON_REGISTERED_MESSAGE(
  537. CExtContentExpandWnd::g_nMsgPaintItemContent,
  538. _OnPaintExpandedItemContent
  539. )
  540. END_MESSAGE_MAP()
  541. /////////////////////////////////////////////////////////////////////////////
  542. // CExtHeaderCtrl message handlers
  543. LRESULT CExtHeaderCtrl::_OnPaintExpandedItemContent( WPARAM wParam, LPARAM lParam )
  544. {
  545. ASSERT_VALID( this );
  546. lParam;
  547. CExtContentExpandWnd::PAINT_ITEM_CONTENT_DATA * p_picd =
  548. (CExtContentExpandWnd::PAINT_ITEM_CONTENT_DATA *)wParam;
  549. ASSERT( p_picd != NULL );
  550. ASSERT( p_picd->m_dc.GetSafeHdc() != NULL );
  551. if( ! _PaintExpandedItemContent(*p_picd) )
  552. return 0;
  553. return (!0);
  554. }
  555. void CExtHeaderCtrl::SortRulesGet(
  556. CExtListCtrlDataSortOrder & _sortOrder
  557. ) const
  558. {
  559. ASSERT_VALID( this );
  560. _sortOrder = m_sortOrder;
  561. }
  562. void CExtHeaderCtrl::SortRulesSet(
  563. const CExtListCtrlDataSortOrder & _sortOrder
  564. )
  565. {
  566. ASSERT_VALID( this );
  567. m_sortOrder = _sortOrder;
  568. if( GetSafeHwnd() != NULL )
  569. Invalidate();
  570. }
  571. void CExtHeaderCtrl::OnPaint() 
  572. {
  573. ASSERT_VALID( this );
  574. CRect rcClient;
  575. GetClientRect( &rcClient );
  576. CPaintDC dcPaint( this );
  577. CExtMemoryDC dc( &dcPaint, &rcClient );
  578. OnEraseHeaderBackground( dc, rcClient );
  579. INT nColNo, nColCount = INT(GetItemCount());
  580. for( nColNo = 0; nColNo < nColCount; nColNo++ )
  581. {
  582. CRect _rcItemEntire;
  583. if( ! GetItemRect( nColNo, &_rcItemEntire ) )
  584. continue;
  585. if( ! dc.RectVisible( &_rcItemEntire ) )
  586. continue;
  587. HD_ITEM _item;
  588. ::memset( &_item, 0, sizeof(HD_ITEM) );
  589. _item.mask = UINT(-1);
  590. TCHAR strText[ 1024 ];
  591. _item.cchTextMax = sizeof( strText ) / sizeof( strText[0] );
  592. _item.pszText = strText;
  593. GetItem( nColNo, &_item );
  594. OnPaintHeaderItem( dc, _item, nColNo, _rcItemEntire );
  595. }
  596. }
  597. void CExtHeaderCtrl::OnEraseHeaderBackground(
  598. CDC & dc,
  599. const CRect & rcClient
  600. ) const
  601. {
  602. ASSERT_VALID( this );
  603. ASSERT( dc.GetSafeHdc() != NULL );
  604. PmBridge_GetPM()->Header_PaintBackground(
  605. dc,
  606. rcClient,
  607. (CObject*)this
  608. );
  609. }
  610. CSize CExtHeaderCtrl::OnCalcHeaderItemSize(
  611. INT nColNo
  612. ) const
  613. {
  614. ASSERT_VALID( this );
  615. if( GetSafeHwnd() == NULL )
  616. return CSize( 0, 0 );
  617. INT nColCount = INT( GetItemCount() );
  618. ASSERT( 0 <= nColNo && nColNo < nColCount );
  619. CExtPaintManager * pPM = PmBridge_GetPM();
  620. ASSERT_VALID( pPM );
  621. const EXTENDED_ITEM_DATA & _eii = ExtendedItemDataGet( nColNo );
  622. CSize _sizeEntireItem( 0, 0 );
  623. if( ! _eii.m_iconButton.IsEmpty() )
  624. {
  625. CSize sizeButton = _eii.m_iconButton.GetSize();
  626. INT nButtonPaddingBefore = 0, nButtonPaddingAfter = 0;
  627. pPM->Header_GetButtonPadding( nButtonPaddingBefore, nButtonPaddingAfter, nColNo, nColCount, (CObject*)this );
  628. sizeButton.cx += nButtonPaddingBefore + nButtonPaddingAfter;
  629. _sizeEntireItem.cx += sizeButton.cx;
  630. _sizeEntireItem.cy = max( _sizeEntireItem.cy, sizeButton.cy );
  631. }
  632. if( ! _eii.m_iconItem.IsEmpty() )
  633. {
  634. INT nBetweenIconAndText = pPM->Header_GetDistanceBetweenIconAndText( nColNo, nColCount, (CObject*)this );
  635. CSize _sizeIcon = _eii.m_iconItem.GetSize();
  636. _sizeIcon.cx += nBetweenIconAndText;
  637. _sizeEntireItem.cx += _sizeIcon.cx;
  638. _sizeEntireItem.cy = max( _sizeEntireItem.cy, _sizeIcon.cy );
  639. }
  640. INT nSortRuleNo = m_sortOrder.GetColPos( nColNo );
  641. if( nSortRuleNo >= 0 )
  642. {
  643. INT nBetweenIconAndSortArrow = pPM->Header_GetDistanceBetweenIconAndSortArrow( nColNo, nColCount, (CObject*)this );
  644. INT nSortArrowExtent = pPM->Header_GetSortArrowWidth( nColNo, nColCount, (CObject*)this );
  645. _sizeEntireItem.cx += nSortArrowExtent + nBetweenIconAndSortArrow;
  646. }
  647. HD_ITEM _item;
  648. ::memset( &_item, 0, sizeof(HD_ITEM) );
  649. _item.mask = UINT(HDI_TEXT);
  650. TCHAR strText[ 1024 ];
  651. _item.cchTextMax = sizeof( strText ) / sizeof( strText[0] );
  652. _item.pszText = strText;
  653. GetItem( nColNo, &_item );
  654. CExtSafeString s;
  655. s = _item.pszText;
  656. CFont * pFont = &pPM->m_FontNormal; //GetFont();
  657. if( pFont->GetSafeHandle() == NULL )
  658. pFont = &(pPM->m_FontNormal);
  659. CClientDC dc( (CWnd*)this );
  660. CSize _sizeText = CExtPaintManager::stat_CalcTextDimension( dc, *pFont, s ).Size();
  661. _sizeEntireItem.cx += _sizeText.cx;
  662. _sizeEntireItem.cy = max( _sizeEntireItem.cy, _sizeText.cy );
  663. CRect rcItemPadding = pPM->Header_GetItemPadding( nColNo, nColCount, (CObject*)this );
  664. _sizeEntireItem.cx += rcItemPadding.left + rcItemPadding.right;
  665. _sizeEntireItem.cy += rcItemPadding.top + rcItemPadding.bottom;
  666. return _sizeEntireItem;
  667. }
  668. void CExtHeaderCtrl::OnCalcHeaderItemLayout(
  669. INT nColNo,
  670. const CRect & _rcItemEntire,
  671. CRect & _rcItem,
  672. CRect & _rcIcon,
  673. CRect & _rcText,
  674. CRect & _rcSortArrow,
  675. CRect & _rcButton,
  676. CRect & _rcButtonIcon,
  677. bool * p_bSorted, // = NULL
  678. bool * p_bSortedAscending // = NULL
  679. ) const
  680. {
  681. ASSERT_VALID( this );
  682. INT nColCount = INT( GetItemCount() );
  683. ASSERT( 0 <= nColNo && nColNo < nColCount );
  684. CExtPaintManager * pPM = PmBridge_GetPM();
  685. ASSERT_VALID( pPM );
  686. _rcItem = _rcItemEntire;
  687. const EXTENDED_ITEM_DATA & _eii = ExtendedItemDataGet( nColNo );
  688. _rcButton.SetRect( 0, 0, 0, 0 );
  689. _rcButtonIcon.SetRect( 0, 0, 0, 0 );
  690. if( ! _eii.m_iconButton.IsEmpty() )
  691. {
  692. CSize sizeButton = _eii.m_iconButton.GetSize();
  693. INT nButtonPaddingBefore = 0, nButtonPaddingAfter = 0;
  694. pPM->Header_GetButtonPadding( nButtonPaddingBefore, nButtonPaddingAfter, nColNo, nColCount, (CObject*)this );
  695. INT nButtonExtent = sizeButton.cx + nButtonPaddingBefore + nButtonPaddingAfter;
  696. _rcButton = _rcItem;
  697. _rcItem.right -= nButtonExtent;
  698. _rcButton.left = _rcItem.right;
  699. _rcButtonIcon = _rcButton;
  700. _rcButtonIcon.DeflateRect( nButtonPaddingBefore, 0, nButtonPaddingAfter, 0 );
  701. if( _rcButtonIcon.Height() != sizeButton.cy )
  702. {
  703. _rcButtonIcon.top += ( _rcButtonIcon.Height() - sizeButton.cy ) / 2;
  704. _rcButtonIcon.bottom = _rcButtonIcon.top + sizeButton.cy;
  705. }
  706. }
  707. CRect rcItemPadding = pPM->Header_GetItemPadding( nColNo, nColCount, (CObject*)this );
  708. _rcItem.DeflateRect( &rcItemPadding );
  709. _rcText = _rcItem;
  710. _rcIcon.SetRect( 0, 0, 0, 0 );
  711. if( ! _eii.m_iconItem.IsEmpty() )
  712. {
  713. INT nBetweenIconAndText = pPM->Header_GetDistanceBetweenIconAndText( nColNo, nColCount, (CObject*)this );
  714. CSize _sizeIcon = _eii.m_iconItem.GetSize();
  715. _rcText.left += _sizeIcon.cx + nBetweenIconAndText;
  716. _rcIcon = _rcItem;
  717. _rcIcon.right = _rcIcon.left + _sizeIcon.cx;
  718. if( _rcIcon.Height() != _sizeIcon.cy )
  719. {
  720. _rcIcon.top += ( _rcIcon.Height() - _sizeIcon.cy ) / 2;
  721. _rcIcon.bottom = _rcIcon.top + _sizeIcon.cy;
  722. }
  723. }
  724. _rcSortArrow.SetRect( 0, 0, 0, 0 );
  725. bool bSorted = false, bSortedAscending = false;
  726. INT nSortRuleNo = m_sortOrder.GetColPos( nColNo );
  727. if( nSortRuleNo >= 0 )
  728. {
  729. INT nSortArrowExtent = pPM->Header_GetSortArrowWidth( nColNo, nColCount, (CObject*)this );
  730. const CExtListCtrlDataSortOrder::COLUMN_INFO & _columnInfo = m_sortOrder.m_arrItems[ nSortRuleNo ];
  731. _rcSortArrow = _rcText;
  732. _rcSortArrow.left = _rcSortArrow.right - nSortArrowExtent;
  733. if( _rcSortArrow.left >= _rcText. left )
  734. {
  735. INT nBetweenIconAndSortArrow = pPM->Header_GetDistanceBetweenIconAndSortArrow( nColNo, nColCount, (CObject*)this );
  736. _rcText.right = _rcSortArrow.left - nBetweenIconAndSortArrow;
  737. bSorted = true;
  738. bSortedAscending = _columnInfo.m_bAscending;
  739. }
  740. }
  741. if( p_bSorted != NULL )
  742. (*p_bSorted) = bSorted;
  743. if( p_bSortedAscending != NULL )
  744. (*p_bSortedAscending) = bSortedAscending;
  745. }
  746. void CExtHeaderCtrl::OnPaintHeaderItem(
  747. CDC & dc,
  748. const HD_ITEM & _item,
  749. INT nColNo,
  750. const CRect & _rcItemEntire,
  751. bool bDND // = false
  752. ) const
  753. {
  754. ASSERT_VALID( this );
  755. ASSERT( dc.GetSafeHdc() != NULL );
  756. INT nColCount = INT( GetItemCount() );
  757. ASSERT( 0 <= nColNo && nColNo < nColCount );
  758. CExtPaintManager * pPM = PmBridge_GetPM();
  759. ASSERT_VALID( pPM );
  760. CRect _rcItem, _rcIcon, _rcText, _rcSortArrow, _rcButton, _rcButtonIcon;
  761. bool bSorted = false,  bSortedAscending = false;
  762. OnCalcHeaderItemLayout(
  763. nColNo,
  764. _rcItemEntire,
  765. _rcItem,
  766. _rcIcon,
  767. _rcText,
  768. _rcSortArrow,
  769. _rcButton,
  770. _rcButtonIcon,
  771. &bSorted,
  772. &bSortedAscending
  773. );
  774. const EXTENDED_ITEM_DATA & _eii = ExtendedItemDataGet( nColNo );
  775. bool bHover       = ( (!bDND) && (!m_bOnDividerAtRight) && nColNo == m_nHoverColNo && ( nColNo == m_nPressingColNo || m_nPressingColNo < 0 ) ) ? true : false;
  776. bool bPressed     = ( (!bDND) && (!m_bOnDividerAtRight) && nColNo == m_nPressingColNo ) ? true : false;
  777. bool bButtonEvent = ( (!bDND) && (!m_bOnDividerAtRight) && m_bOnButton ) ? true : false;
  778. pPM->Header_PaintItem(
  779. dc,
  780. _rcItemEntire,
  781. _rcItem,
  782. _rcIcon,
  783. _rcText,
  784. _rcSortArrow,
  785. _rcButton,
  786. _rcButtonIcon,
  787. bSorted,
  788. bSortedAscending,
  789. nColNo,
  790. nColCount,
  791. _eii.m_iconItem,
  792. _eii.m_iconButton,
  793. bHover,
  794. bPressed,
  795. bButtonEvent,
  796. __EXT_MFC_SAFE_LPCTSTR(_item.pszText),
  797. (CObject*)this
  798. );
  799. }
  800. void CExtHeaderCtrl::OnCancelMode()
  801. {
  802. ASSERT_VALID( this );
  803. _CancelActions();
  804. CHeaderCtrl::OnCancelMode();
  805. }
  806. void CExtHeaderCtrl::OnCaptureChanged( CWnd * pWnd ) 
  807. {
  808. ASSERT_VALID( this );
  809. _CancelActions();
  810. CHeaderCtrl::OnCaptureChanged( pWnd );
  811. }
  812. CExtPopupMenuTipWnd * CExtHeaderCtrl::OnAdvancedPopupMenuTipWndGet() const
  813. {
  814. if( m_nAdvancedTipStyle == INT(CExtPopupMenuTipWnd::__ETS_NONE) )
  815. return NULL;
  816. return (&( CExtPopupMenuSite::g_DefPopupMenuSite.GetTip() ));
  817. }
  818. void CExtHeaderCtrl::OnAdvancedPopupMenuTipWndDisplay(
  819. CExtPopupMenuTipWnd & _ATTW,
  820. const RECT & rcExcludeArea,
  821. __EXT_MFC_SAFE_LPCTSTR strToolTipText
  822. ) const
  823. {
  824. ASSERT_VALID( this );
  825. if( ( ! m_bShowTipsOverHeader ) || LPCTSTR(strToolTipText) == NULL || _tcslen( LPCTSTR(strToolTipText) ) == 0 )
  826. {
  827. _ATTW.Hide();
  828. return;
  829. }
  830. _ATTW.SetText( LPCTSTR(strToolTipText) );
  831. _ATTW.SetTipStyle( (CExtPopupMenuTipWnd::e_tip_style_t)m_nAdvancedTipStyle );
  832. _ATTW.Show( (CWnd*)this, rcExcludeArea );
  833. }
  834. INT CExtHeaderCtrl::ColNo2VisualIndex( INT nColNo ) const // convert column number to visual index
  835. {
  836. ASSERT_VALID( this );
  837. if( nColNo < 0 || GetSafeHwnd() == NULL )
  838. return -1;
  839. INT nColCount = INT(GetItemCount());
  840. ASSERT( nColCount >= 0 );
  841. if( nColNo >= nColCount )
  842. return -1;
  843. INT * pArr = NULL, nIndex = -1;
  844. try
  845. {
  846. pArr = new INT[ nColCount ];
  847. if( ! ( const_cast < CExtHeaderCtrl * > ( this ) ) -> GetOrderArray( pArr, nColCount ) )
  848. ::AfxThrowUserException();
  849. for( nIndex = 0; nIndex < nColCount; nIndex ++ )
  850. {
  851. if( pArr[nIndex] == nColNo )
  852. break;
  853. }
  854. }
  855. catch( CException * pException )
  856. {
  857. pException->Delete();
  858. }
  859. if( pArr != NULL )
  860. delete pArr;
  861. if( nIndex >= nColCount )
  862. return -1;
  863. return nIndex;
  864. }
  865. INT CExtHeaderCtrl::VisualIndex2ColNo( INT nIndex ) const // convert visual index to column number
  866. {
  867. ASSERT_VALID( this );
  868. if( nIndex < 0 || GetSafeHwnd() == NULL )
  869. return -1;
  870. INT nColCount = INT(GetItemCount());
  871. ASSERT( nColCount >= 0 );
  872. if( nIndex >= nColCount )
  873. return -1;
  874. INT * pArr = NULL, nColNo = -1;
  875. try
  876. {
  877. pArr = new INT[ nColCount ];
  878. if( ! ( const_cast < CExtHeaderCtrl * > ( this ) ) -> GetOrderArray( pArr, nColCount ) )
  879. ::AfxThrowUserException();
  880. nColNo = pArr[nIndex];
  881. }
  882. catch( CException * pException )
  883. {
  884. pException->Delete();
  885. }
  886. if( pArr != NULL )
  887. delete pArr;
  888. if( nColNo >= nColCount )
  889. return -1;
  890. return nColNo;
  891. }
  892. INT CExtHeaderCtrl::HitTestHeaderItem(
  893. const POINT & ptClient,
  894. bool * p_bOnButton, // = NULL
  895. bool * p_bOnDividerAtRight, // = NULL
  896. bool bComputeZeroWidthItem // = true
  897. ) const
  898. {
  899. ASSERT_VALID( this );
  900. if( p_bOnButton != NULL )
  901. (*p_bOnButton) = false;
  902. if( p_bOnDividerAtRight != NULL )
  903. (*p_bOnDividerAtRight) = false;
  904. if( GetSafeHwnd() == NULL )
  905. return -1;
  906. INT nColCount = INT(GetItemCount());
  907. ASSERT( nColCount >= 0 );
  908. if( nColCount == 0 )
  909. return -1;
  910. bool bOnButton = false, bOnDividerAtRight = false;
  911. HDHITTESTINFO _hdhti;
  912. ::memset( &_hdhti, 0, sizeof(HDHITTESTINFO) );
  913. _hdhti.pt = ptClient;
  914. ::SendMessage( m_hWnd, HDM_HITTEST, 0, LPARAM( &_hdhti ) );
  915. INT nColNo = INT(_hdhti.iItem);
  916. CRect _rcItemEntire, _rcItem, _rcIcon, _rcText, _rcSortArrow, _rcButton, _rcButtonIcon;
  917. bool bCheckLast = false;
  918. if( nColNo >= 0 )
  919. {
  920. if( ! GetItemRect( nColNo, &_rcItemEntire ) )
  921. return -1;
  922. OnCalcHeaderItemLayout(
  923. nColNo,
  924. _rcItemEntire,
  925. _rcItem,
  926. _rcIcon,
  927. _rcText,
  928. _rcSortArrow,
  929. _rcButton,
  930. _rcButtonIcon
  931. );
  932. if( _rcButton.PtInRect( ptClient ) )
  933. bOnButton = true;
  934. CRect rc = _rcItemEntire;
  935. rc.left = rc.right - m_nDividerHalfExtent;
  936. if( rc.PtInRect( ptClient ) )
  937. bOnDividerAtRight = true;
  938. else
  939. {
  940. INT nIndex = ColNo2VisualIndex( nColNo );
  941. if( nIndex > 0 )
  942. {
  943. rc = _rcItemEntire;
  944. rc.right = rc.left + m_nDividerHalfExtent;
  945. if( rc.PtInRect( ptClient ) )
  946. {
  947. bOnDividerAtRight = true;
  948. nIndex --;
  949. nColNo = VisualIndex2ColNo( nIndex );
  950. } // if( rc.PtInRect( ptClient ) )
  951. else if( nIndex < ( nColCount - 1 ) )
  952. {
  953. INT nColNoNext = VisualIndex2ColNo( nIndex + 1 );
  954. if( nColNoNext >= 0 )
  955. {
  956. CRect rcNext;
  957. if( GetItemRect( nColNoNext, &rcNext ) )
  958. {
  959. CRect rc = rcNext;
  960. rc.right = rc.left + m_nDividerHalfExtent;
  961. if( rc.PtInRect( ptClient ) )
  962. bOnDividerAtRight = true;
  963. } // if( GetItemRect( nColNoNext, &rcNext ) )
  964. } // if( nColNoNext >= 0 )
  965. } // else if( nIndex < ( nColCount - 1 ) )
  966. else if( nIndex == ( nColCount - 1 ) )
  967. bCheckLast = true;
  968. } // if( nIndex > 0 )
  969. } // else from if( rc.PtInRect( ptClient ) )
  970. } // if( nColNo >= 0 )
  971. if( bCheckLast )
  972. {
  973. INT nColNoLast = VisualIndex2ColNo( nColCount - 1 );
  974. if( ! GetItemRect( nColNoLast, &_rcItemEntire ) )
  975. return -1;
  976. OnCalcHeaderItemLayout(
  977. nColNoLast,
  978. _rcItemEntire,
  979. _rcItem,
  980. _rcIcon,
  981. _rcText,
  982. _rcSortArrow,
  983. _rcButton,
  984. _rcButtonIcon
  985. );
  986. CRect rc = _rcItemEntire;
  987. rc.left = rc.right;
  988. rc.right += m_nDividerHalfExtent;
  989. if( rc.PtInRect( ptClient ) )
  990. {
  991. bOnDividerAtRight = true;
  992. nColNo = nColNoLast;
  993. } // if( rc.PtInRect( ptClient ) )
  994. } // if( bCheckLast )
  995. if( bOnDividerAtRight )
  996. {
  997. const EXTENDED_ITEM_DATA & _eii = m_arrExtendedData.ElementAt( nColNo );
  998. if( ! _eii.CanBeResized() )
  999. bOnDividerAtRight = false;
  1000. }
  1001. if( bOnDividerAtRight )
  1002. {
  1003. bOnButton = false;
  1004. if( nColNo >= 0 && bComputeZeroWidthItem )
  1005. {
  1006. INT nIndex = ColNo2VisualIndex( nColNo );
  1007. if( nIndex >= 0 )
  1008. {
  1009. for( nIndex ++; nIndex < nColCount; nIndex++ )
  1010. {
  1011. CRect _rcItemEntire( 0, 32767, 0, 0 );
  1012. INT nTmpColNo = VisualIndex2ColNo( nIndex );
  1013. if( nTmpColNo <= 0 )
  1014. break;
  1015. if( ! GetItemRect( nTmpColNo, &_rcItemEntire ) )
  1016. break;
  1017. if( _rcItemEntire.Width() > 0 )
  1018. break;
  1019. nColNo = nTmpColNo;
  1020. }
  1021. } // if( nIndex >= 0 )
  1022. } // if( nColNo >= 0 && bComputeZeroWidthItem )
  1023. } // if( bOnDividerAtRight )
  1024. else
  1025. {
  1026. if( nColNo >= 0 && bComputeZeroWidthItem )
  1027. {
  1028. INT nIndex = ColNo2VisualIndex( nColNo );
  1029. for( ; 0 <= nIndex && nIndex < nColCount; nIndex++ )
  1030. {
  1031. CRect _rcItemEntire( 0, 32767, 0, 0 );
  1032. INT nTmpColNo = VisualIndex2ColNo( nIndex );
  1033. if( nTmpColNo <= 0 )
  1034. break;
  1035. if( ! GetItemRect( nTmpColNo, &_rcItemEntire ) )
  1036. break;
  1037. if( _rcItemEntire.Width() > 0 )
  1038. break;
  1039. nColNo = nTmpColNo;
  1040. bOnButton = false;
  1041. bOnDividerAtRight = true;
  1042. } // for( ; 0 <= nIndex && nIndex < nColCount; nIndex++ )
  1043. }
  1044. } // else from if( bOnDividerAtRight )
  1045. if( p_bOnButton != NULL )
  1046. (*p_bOnButton) = bOnButton;
  1047. if( p_bOnDividerAtRight != NULL )
  1048. (*p_bOnDividerAtRight) = bOnDividerAtRight;
  1049. return nColNo;
  1050. }
  1051. bool CExtHeaderCtrl::_DndIsAllowed(
  1052. INT nColNo // = -1
  1053. ) const
  1054. {
  1055. ASSERT_VALID( this );
  1056. if( GetSafeHwnd() == NULL )
  1057. return false;
  1058. CWnd * pWndParent = GetParent();
  1059. if( pWndParent != NULL
  1060. && pWndParent->IsKindOf( RUNTIME_CLASS(CListCtrl) )
  1061. )
  1062. {
  1063. if( ( ((CListCtrl*)pWndParent)->GetExtendedStyle() & LVS_EX_HEADERDRAGDROP ) == 0 )
  1064. return false;
  1065. }
  1066. else
  1067. {
  1068. if( ( GetStyle() & HDS_DRAGDROP ) == 0 )
  1069. return false;
  1070. }
  1071. if( nColNo < 0 )
  1072. return true;
  1073. INT nColCount = INT( GetItemCount() );
  1074. if( nColNo >= nColCount )
  1075. return false;
  1076. const EXTENDED_ITEM_DATA & _eii = ExtendedItemDataGet( nColNo );
  1077. if( _eii.m_bDisableDnd )
  1078. return false;
  1079. return true;
  1080. }
  1081. CPoint CExtHeaderCtrl::_DndGetStartOffset() const
  1082. {
  1083. ASSERT_VALID( this );
  1084. return CPoint( 3, 3 );
  1085. }
  1086. INT CExtHeaderCtrl::_DndCalcOuterDropTarget( CPoint point ) const
  1087. {
  1088. ASSERT_VALID( this );
  1089. ASSERT( GetSafeHwnd() != NULL );
  1090. INT nColCount = INT( GetItemCount() );
  1091. if( nColCount == 0 )
  1092. return -1;
  1093. INT nColNoToDropBefore = HitTestHeaderItem( point, NULL, NULL, false );
  1094. if( nColNoToDropBefore < 0 )
  1095. {
  1096. CRect rcClient;
  1097. GetClientRect( &rcClient);
  1098. if( rcClient.top <= point.y && point.y <= rcClient.bottom )
  1099. {
  1100. INT nColNoLast = VisualIndex2ColNo( nColCount - 1 );
  1101. if( nColNoLast >= 0 )
  1102. {
  1103. CRect rcItem;
  1104. if( GetItemRect( nColNoLast, &rcItem )
  1105. && point.x >= rcItem.right
  1106. )
  1107. return nColCount;
  1108. } // if( nColNoLast >= 0 )
  1109. } // if( rcClient.top <= point.y && point.y <= rcClient.bottom )
  1110. return -1;
  1111. } // if( nColNoToDropBefore < 0 )
  1112. CRect rcItem;
  1113. if( ! GetItemRect( nColNoToDropBefore, &rcItem ) )
  1114. return -1;
  1115. INT nDistanceLeft = abs( point.x - rcItem.left );
  1116. INT nDistanceRight = abs( point.x - rcItem.right );
  1117. if( nDistanceLeft > nDistanceRight )
  1118. {
  1119. INT nIndexToDropBefore = ColNo2VisualIndex( nColNoToDropBefore );
  1120. if( nIndexToDropBefore >= 0 )
  1121. {
  1122. ASSERT( nIndexToDropBefore < nColCount );
  1123. nIndexToDropBefore ++;
  1124. ASSERT( nIndexToDropBefore <= nColCount );
  1125. if( nIndexToDropBefore == nColCount )
  1126. nColNoToDropBefore = nColCount;
  1127. else
  1128. nColNoToDropBefore = VisualIndex2ColNo( nIndexToDropBefore );
  1129. } // if( nIndexToDropBefore >= 0 )
  1130. } // if( nDistanceLeft > nDistanceRight )
  1131. ASSERT( nColNoToDropBefore <= nColCount );
  1132. return nColNoToDropBefore;
  1133. }
  1134. void CExtHeaderCtrl::_DndDo(
  1135. INT nColNo,
  1136. CPoint ptStartDrag,
  1137. bool bNotify // = true // send HDN_BEGINDRAG and HDN_ENDDRAG messages
  1138. )
  1139. {
  1140. ASSERT_VALID( this );
  1141. HWND hWndOwn = GetSafeHwnd();
  1142. ASSERT( hWndOwn != NULL );
  1143. INT nColCount = INT( GetItemCount() );
  1144. if( nColCount == 0 )
  1145. return;
  1146. ASSERT( 0 <= nColNo && nColNo <= nColCount );
  1147. HWND hWndParent = ::GetParent( hWndOwn );
  1148. if( hWndParent == NULL )
  1149. bNotify = false;
  1150. UINT nOwnID = UINT( GetDlgCtrlID() );
  1151. HD_NOTIFY _data;
  1152. ::memset( &_data, 0, sizeof(HD_NOTIFY) );
  1153. _data.hdr.hwndFrom = hWndOwn;
  1154. _data.hdr.idFrom = nOwnID;
  1155. _data.hdr.code = NM_CLICK;
  1156. _data.iButton = 0;
  1157. _data.iItem = nColNo;
  1158. HDITEM hdItemBuffer; // to avoid common controls crashing
  1159. ::memset( &hdItemBuffer, 0, sizeof(HDITEM) );
  1160. _data.pitem = &hdItemBuffer;
  1161. if( bNotify )
  1162. {
  1163. HD_NOTIFY _dataA;
  1164. ::memcpy( &_dataA, &_data, sizeof(HD_NOTIFY) );
  1165. _dataA.hdr.code = HDN_BEGINDRAG;
  1166. if( ::SendMessage( hWndParent, WM_NOTIFY, WPARAM(nOwnID), LPARAM(&_dataA) ) != 0 )
  1167. return;
  1168. }
  1169. CExtPopupMenuTipWnd * pATTW = OnAdvancedPopupMenuTipWndGet();
  1170. if( pATTW != NULL )
  1171. pATTW->Hide();
  1172. CRect rcDND;
  1173. if( ! GetItemRect( nColNo, &rcDND ) )
  1174. return;
  1175. ClientToScreen( &rcDND );
  1176. CExtContentExpandWnd wndDND, wndArrows;
  1177. if( ! wndDND.Activate(
  1178. rcDND,
  1179. this,
  1180. __ECWAF_DEF_EXPANDED_ITEM_PAINTER
  1181. |__ECWAF_NO_CAPTURE
  1182. |__ECWAF_REDIRECT_MOUSE
  1183. |__ECWAF_REDIRECT_NO_DEACTIVATE
  1184. |__ECWAF_REDIRECT_AND_HANDLE
  1185. |__ECWAF_HANDLE_MOUSE_ACTIVATE
  1186. |__ECWAF_MA_NOACTIVATE
  1187. )
  1188. )
  1189. {
  1190. ASSERT( FALSE );
  1191. return;
  1192. }
  1193. CPoint ptShiftLast( 0, 0 );
  1194. CRect rcInitialWndDND;
  1195. wndDND.GetWindowRect( &rcInitialWndDND );
  1196. ASSERT( m_hCursorOuterDragOK != NULL );
  1197. ASSERT( m_hCursorOuterDragCancel != NULL );
  1198. ::SetCursor( m_hCursorOuterDragOK );
  1199. bool bStopFlag = false;
  1200. INT nLastTargetColNoToDropBefore = -1;
  1201. INT nLastTargetIndexToDropBefore = -1;
  1202. CRect rcArrows( 0, 0, 0, 0 );
  1203. for( MSG msg;
  1204. ::IsWindow( hWndOwn )
  1205. && (!bStopFlag)
  1206. ;
  1207. )
  1208. { // main message loop
  1209. if( ! ::PeekMessage( &msg, NULL, 0, 0, PM_NOREMOVE ) )
  1210. {
  1211. if( ( ! ::IsWindow( hWndOwn ) )
  1212. || bStopFlag
  1213. )
  1214. break;
  1215. if( g_bEnableOnIdleCalls )
  1216. {
  1217. for( LONG nIdleCounter = 0L;
  1218. ::AfxGetThread()->OnIdle(nIdleCounter);
  1219. nIdleCounter ++
  1220. );
  1221. }
  1222. ::WaitMessage();
  1223. continue;
  1224. } // if( ! ::PeekMessage( &msg, NULL, 0, 0, PM_NOREMOVE ) )
  1225. switch( msg.message )
  1226. {
  1227. case WM_KILLFOCUS:
  1228. if( msg.hwnd == hWndOwn )
  1229. bStopFlag = true;
  1230. break;
  1231. case WM_CANCELMODE:
  1232. case WM_ACTIVATEAPP:
  1233. case WM_SYSCOMMAND:
  1234. case WM_SETTINGCHANGE:
  1235. case WM_SYSCOLORCHANGE:
  1236. bStopFlag = true;
  1237. break;
  1238. case WM_COMMAND:
  1239. if( (HIWORD(msg.wParam)) == 0
  1240. || (HIWORD(msg.wParam)) == 1
  1241. )
  1242. bStopFlag = true;
  1243. break;
  1244. case WM_CAPTURECHANGED:
  1245. if( (HWND)msg.wParam != hWndOwn )
  1246. bStopFlag = true;
  1247. break;
  1248. case WM_MOUSEWHEEL:
  1249. if( msg.hwnd != hWndOwn )
  1250. bStopFlag = true;
  1251. else
  1252. {
  1253. ::PeekMessage(&msg,NULL,msg.message,msg.message,PM_REMOVE);
  1254. continue;
  1255. } // else from if( msg.hwnd != hWndOwn )
  1256. break;
  1257. case WM_MOUSEMOVE:
  1258. if( msg.hwnd != hWndOwn )
  1259. bStopFlag = true;
  1260. else
  1261. {
  1262. ASSERT_VALID( this );
  1263. ::PeekMessage(&msg,NULL,msg.message,msg.message,PM_REMOVE);
  1264. CPoint point;
  1265. point = DWORD( msg.lParam );
  1266. CPoint ptShift = point - ptStartDrag;
  1267. if( ptShift != ptShiftLast )
  1268. {
  1269. INT nColNoDropBefore = _DndCalcOuterDropTarget( point );
  1270. INT nIndexDropBefore = -1;
  1271. ASSERT( nColNoDropBefore <= nColCount );
  1272. if( nColNoDropBefore >= 0 )
  1273. {
  1274. if( nColNoDropBefore == nColCount )
  1275. nIndexDropBefore = nColCount;
  1276. else
  1277. {
  1278. nIndexDropBefore = ColNo2VisualIndex( nColNoDropBefore );
  1279. if( nIndexDropBefore < 0 )
  1280. nColNoDropBefore = -1;
  1281. }
  1282. }
  1283. if( nLastTargetIndexToDropBefore != nIndexDropBefore )
  1284. {
  1285. nLastTargetColNoToDropBefore = nColNoDropBefore;
  1286. nLastTargetIndexToDropBefore = nIndexDropBefore;
  1287. rcArrows.SetRect( 0, 0, 0, 0 );
  1288. if( nLastTargetIndexToDropBefore >= 0 )
  1289. {
  1290. if( nLastTargetIndexToDropBefore == nColCount )
  1291. {
  1292. INT nColNoLast = VisualIndex2ColNo( nColCount - 1 );
  1293. if( GetItemRect( nColNoLast, &rcArrows ) )
  1294. rcArrows.left = rcArrows.right;
  1295. else
  1296. rcArrows.SetRect( 0, 0, 0, 0 );
  1297. }
  1298. else
  1299. {
  1300. if( GetItemRect( nLastTargetColNoToDropBefore, &rcArrows ) )
  1301. rcArrows.right = rcArrows.left;
  1302. else
  1303. rcArrows.SetRect( 0, 0, 0, 0 );
  1304. }
  1305. if( rcArrows.Height() == 0 )
  1306. nLastTargetColNoToDropBefore = -1;
  1307. } // if( nLastTargetColNoToDropBefore >= 0 )
  1308. if( nLastTargetColNoToDropBefore >= 0 )
  1309. {
  1310. VERIFY(
  1311. wndArrows.Activate(
  1312. rcArrows,
  1313. this,
  1314. __ECWAF_DRAW_RED_ARROWS
  1315. |__ECWAF_TRANSPARENT_ITEM
  1316. |__ECWAF_NO_CAPTURE
  1317. |__ECWAF_REDIRECT_MOUSE
  1318. |__ECWAF_REDIRECT_NO_DEACTIVATE
  1319. |__ECWAF_REDIRECT_AND_HANDLE
  1320. |__ECWAF_HANDLE_MOUSE_ACTIVATE
  1321. |__ECWAF_MA_NOACTIVATE
  1322. )
  1323. );
  1324. if( wndArrows.GetSafeHwnd() != NULL )
  1325. {
  1326. wndArrows.SetWindowPos(
  1327. &wndDND, 0, 0, 0, 0,
  1328. SWP_NOMOVE|SWP_NOSIZE|SWP_NOACTIVATE
  1329. );
  1330. ::SetCursor( m_hCursorOuterDragOK );
  1331. }
  1332. else
  1333. nLastTargetColNoToDropBefore = -1;
  1334. } // if( nLastTargetColNoToDropBefore >= 0 )
  1335. } // if( nLastTargetIndexToDropBefore != nIndexDropBefore )
  1336. if( nLastTargetColNoToDropBefore < 0 )
  1337. {
  1338. wndArrows.Deactivate();
  1339. ::SetCursor( m_hCursorOuterDragCancel );
  1340. }
  1341. ptShiftLast = ptShift;
  1342. CRect rcWnd( rcInitialWndDND );
  1343. rcWnd.OffsetRect( ptShift );
  1344. wndDND.MoveWindow( &rcWnd );
  1345. wndDND.UpdateWindow();
  1346. if( wndArrows.GetSafeHwnd() != NULL )
  1347. wndArrows.UpdateWindow();
  1348. UpdateWindow();
  1349. CExtPaintManager::stat_PassPaintMessages();
  1350. } // if( ptShift != ptShiftLast )
  1351. continue;
  1352. } // else from if( msg.hwnd != hWndOwn )
  1353. break;
  1354. case WM_LBUTTONUP:
  1355. case WM_RBUTTONUP:
  1356. case WM_MBUTTONUP:
  1357. bStopFlag = true;
  1358. ::PeekMessage(&msg,NULL,msg.message,msg.message,PM_REMOVE);
  1359. break;
  1360. case WM_LBUTTONDBLCLK:
  1361. case WM_LBUTTONDOWN:
  1362. case WM_RBUTTONDBLCLK:
  1363. case WM_RBUTTONDOWN:
  1364. case WM_MBUTTONDBLCLK:
  1365. case WM_MBUTTONDOWN:
  1366. case WM_CONTEXTMENU:
  1367. case WM_NCLBUTTONUP:
  1368. case WM_NCLBUTTONDBLCLK:
  1369. case WM_NCLBUTTONDOWN:
  1370. case WM_NCRBUTTONUP:
  1371. case WM_NCRBUTTONDBLCLK:
  1372. case WM_NCRBUTTONDOWN:
  1373. case WM_NCMBUTTONUP:
  1374. case WM_NCMBUTTONDBLCLK:
  1375. case WM_NCMBUTTONDOWN:
  1376. bStopFlag = true;
  1377. break;
  1378. default:
  1379. if(    WM_KEYFIRST <= msg.message
  1380. && msg.message <= WM_KEYLAST
  1381. )
  1382. {
  1383. bStopFlag = true;
  1384. ::PeekMessage(&msg,NULL,msg.message,msg.message,PM_REMOVE);
  1385. }
  1386. break;
  1387. } // switch( msg.message )
  1388. if( bStopFlag )
  1389. break;
  1390. if( ! ::AfxGetThread() -> PumpMessage() )
  1391. break;
  1392. } // message loop
  1393. wndDND.Deactivate();
  1394. wndArrows.Deactivate();
  1395. if( ! ::IsWindow( hWndOwn ) )
  1396. return;
  1397. _CancelActions();
  1398. _DoSetCursor();
  1399. if( nLastTargetColNoToDropBefore >= 0 )
  1400. _DndSwap( nColNo, nLastTargetColNoToDropBefore );
  1401. if( bNotify && (! ::IsWindow( hWndParent ) ) )
  1402. bNotify = false;
  1403. if( bNotify )
  1404. {
  1405. HD_NOTIFY _dataA;
  1406. HDITEM hdItemBuffer; // to avoid common controls crashing
  1407. ::memset( &hdItemBuffer, 0, sizeof(HDITEM) );
  1408. _data.pitem = &hdItemBuffer;
  1409. ::memcpy( &_dataA, &_data, sizeof(HD_NOTIFY) );
  1410. _dataA.hdr.code = HDN_ENDDRAG;
  1411. ::SendMessage( hWndParent, WM_NOTIFY, WPARAM(nOwnID), LPARAM(&_dataA) );
  1412. }
  1413. Invalidate();
  1414. UpdateWindow();
  1415. }
  1416. void CExtHeaderCtrl::_DndSwap( INT nColNo, INT nColNoToDropBefore )
  1417. {
  1418. ASSERT_VALID( this );
  1419. ASSERT( GetSafeHwnd() != NULL );
  1420. if( nColNo < 0 || nColNoToDropBefore < 0 )
  1421. return;
  1422. INT nColCount = INT( GetItemCount() );
  1423. if( nColCount == 0 )
  1424. return;
  1425. INT nIndex = ColNo2VisualIndex( nColNo );
  1426. if( nIndex < 0 )
  1427. return;
  1428. INT nIndexToDropBefore = ( nColNoToDropBefore == nColCount ) ? nColCount : ColNo2VisualIndex( nColNoToDropBefore );
  1429. if( nIndexToDropBefore < 0 )
  1430. return;
  1431. if( nIndexToDropBefore == nIndex || nIndexToDropBefore == (nIndex+1) )
  1432. return;
  1433. if( nColNo >= nColCount || nColNoToDropBefore > nColCount )
  1434. return;
  1435. if( nIndex >= nColCount || nIndexToDropBefore > nColCount )
  1436. return;
  1437. INT * pArr = NULL;
  1438. try
  1439. {
  1440. pArr = new INT[ nColCount ];
  1441. if( ! GetOrderArray( pArr, nColCount ) )
  1442. ::AfxThrowUserException();
  1443. if( nIndexToDropBefore < nIndex )
  1444. {
  1445. INT nVal = pArr[nIndex];
  1446. INT nPos = nIndex;
  1447. for( ; nPos > nIndexToDropBefore; nPos -- )
  1448. pArr[nPos] = pArr[nPos-1];
  1449. pArr[nIndexToDropBefore] = nVal;
  1450. }
  1451. else
  1452. {
  1453. ASSERT( nIndexToDropBefore > (nIndex+1) );
  1454. INT nVal = pArr[nIndex];
  1455. INT nPos = nIndexToDropBefore-1;
  1456. for( ; nPos > nIndex; nPos -- )
  1457. pArr[nPos] = pArr[nPos-1];
  1458. pArr[nIndexToDropBefore-1] = nVal;
  1459. }
  1460. VERIFY( SetOrderArray( nColCount, pArr ) );
  1461. }
  1462. catch( CException * pException )
  1463. {
  1464. pException->Delete();
  1465. }
  1466. if( pArr != NULL )
  1467. delete pArr;
  1468. }
  1469. bool CExtHeaderCtrl::_PaintExpandedItemContent(
  1470. CExtContentExpandWnd::PAINT_ITEM_CONTENT_DATA & picd
  1471. ) const
  1472. {
  1473. ASSERT_VALID( this );
  1474. ASSERT( picd.m_dc.GetSafeHdc() != NULL );
  1475. if( m_nPressingColNo >= 0 )
  1476. { // drag-n-dropped item
  1477. OnEraseHeaderBackground( picd.m_dc, picd.m_rcItem );
  1478. HD_ITEM _item;
  1479. ::memset( &_item, 0, sizeof(HD_ITEM) );
  1480. _item.mask = UINT(-1);
  1481. TCHAR strText[ 1024 ];
  1482. ::memset( strText, 0, sizeof( strText ) );
  1483. _item.cchTextMax = sizeof( strText ) / sizeof( strText[0] );
  1484. _item.pszText = strText;
  1485. GetItem( m_nPressingColNo, &_item );
  1486. OnPaintHeaderItem( picd.m_dc, _item, m_nPressingColNo, picd.m_rcItem, true );
  1487. return true;
  1488. } // drag-n-dropped item
  1489. return false;
  1490. }
  1491. bool CExtHeaderCtrl::_DoSetCursor()
  1492. {
  1493. ASSERT_VALID( this );
  1494. ASSERT( GetSafeHwnd() != NULL );
  1495. return _DoSetCursor( CPoint(-32767,-32767) );
  1496. }
  1497. bool CExtHeaderCtrl::_DoSetCursor( const POINT ptScreen ) // CPoint(-32767,-32767) means invoke ::GetCursorPos()
  1498. {
  1499. ASSERT_VALID( this );
  1500. ASSERT( GetSafeHwnd() != NULL );
  1501. CPoint point = ptScreen;
  1502. if( point.x == -32767 || point.y == -32767 )
  1503. {
  1504. if( ! ::GetCursorPos( &point ) )
  1505. return false;
  1506. }
  1507. HCURSOR hCursor = NULL;
  1508. HWND hWndFromPoint = ::WindowFromPoint( point );
  1509. if( hWndFromPoint == m_hWnd )
  1510. {
  1511. ScreenToClient( &point );
  1512. bool bZeroResizing = false, bResizing = ( m_nPressingColNo >= 0 && m_bOnDividerAtRight ) ? true : false;
  1513. if( ! bResizing )
  1514. {
  1515. bool bOnButton = false, bOnDividerAtRight = false;
  1516. INT nColNo = -1, nIndex = -1;
  1517. if( CExtPopupMenuWnd::TestHoverEnabledFromActiveHWND( m_hWnd ) )
  1518. {
  1519. nColNo = HitTestHeaderItem( point, &bOnButton, &bOnDividerAtRight );
  1520. nIndex = ColNo2VisualIndex( nColNo );
  1521. }
  1522. bResizing = ( nIndex >= 0 && bOnDividerAtRight ) ? true : false;
  1523. if( bResizing )
  1524. {
  1525. CRect rcItem( 0, 32767, 0, 0 );
  1526. if( GetItemRect( nColNo, &rcItem )
  1527. && rcItem.Width() == 0
  1528. )
  1529. bZeroResizing = true;
  1530. }
  1531. } // if( ! bResizing )
  1532. hCursor =
  1533. bResizing
  1534. ? ( bZeroResizing ? m_hCursorResizingH2 : m_hCursorResizingH1 )
  1535. : m_hCursorDefault
  1536. ;
  1537. if( hCursor == NULL )
  1538. hCursor = ::LoadCursor( NULL, bResizing ? IDC_SIZEWE : IDC_ARROW );
  1539. } // if( hWndFromPoint == m_hWnd )
  1540. if( hCursor == NULL )
  1541. return false;
  1542. ::SetCursor( hCursor );
  1543. return true;
  1544. }
  1545. BOOL CExtHeaderCtrl::OnSetCursor( CWnd * pWnd, UINT nHitTest, UINT message )
  1546. {
  1547. ASSERT_VALID( this );
  1548. pWnd;
  1549. nHitTest;
  1550. message;
  1551. return _DoSetCursor() ? TRUE : FALSE;
  1552. }
  1553. INT CExtHeaderCtrl::HeaderItemExtentGet( INT nColNo ) const
  1554. {
  1555. ASSERT_VALID( this );
  1556. ASSERT( 0 <= nColNo && nColNo < INT(GetItemCount()) );
  1557. if( GetSafeHwnd() == NULL )
  1558. return 0;
  1559. HD_ITEM _item;
  1560. ::memset( &_item, 0, sizeof(HD_ITEM) );
  1561. _item.mask = HDI_WIDTH;
  1562. GetItem( nColNo, &_item );
  1563. INT nCurrentItemExtent = INT(_item.cxy);
  1564. return nCurrentItemExtent;
  1565. }
  1566. void CExtHeaderCtrl::HeaderItemExtentSet(
  1567. INT nColNo,
  1568. INT nExtent,
  1569. bool bRedraw // = true
  1570. )
  1571. {
  1572. ASSERT_VALID( this );
  1573. ASSERT( 0 <= nColNo && nColNo < INT(GetItemCount()) );
  1574. if( GetSafeHwnd() == NULL )
  1575. return;
  1576. const EXTENDED_ITEM_DATA & _eii = m_arrExtendedData.ElementAt( nColNo );
  1577. if( nExtent < _eii.m_nExtentMin )
  1578. nExtent = _eii.m_nExtentMin;
  1579. if( nExtent > _eii.m_nExtentMax )
  1580. nExtent = _eii.m_nExtentMax;
  1581. if( nExtent < 0 )
  1582. nExtent = 0;
  1583. HD_ITEM _item;
  1584. ::memset( &_item, 0, sizeof(HD_ITEM) );
  1585. _item.mask = HDI_WIDTH;
  1586. GetItem( nColNo, &_item );
  1587. INT nCurrentItemExtent = INT(_item.cxy);
  1588. if( nCurrentItemExtent == nExtent )
  1589. return;
  1590. _item.mask = HDI_WIDTH;
  1591. _item.cxy = nExtent;
  1592. SetItem( nColNo, &_item );
  1593. if( bRedraw )
  1594. Invalidate();
  1595. }
  1596. void CExtHeaderCtrl::OnMouseMove( UINT nFlags, CPoint point )
  1597. {
  1598. ASSERT_VALID( this );
  1599. // CHeaderCtrl::OnMouseMove( nFlags, point );
  1600. nFlags;
  1601. if( m_nPressingColNo >= 0 )
  1602. {
  1603. CExtPopupMenuTipWnd * pATTW = OnAdvancedPopupMenuTipWndGet();
  1604. if( pATTW != NULL )
  1605. pATTW->Hide();
  1606. if( m_bOnDividerAtRight )
  1607. {
  1608. CPoint ptScreenPressing = point;
  1609. ClientToScreen( &ptScreenPressing );
  1610. INT nExtent = ptScreenPressing.x - m_ptScreenPressing.x + m_nHelperInitialResizingExtent;
  1611. HeaderItemExtentSet( m_nPressingColNo, nExtent );
  1612. _DoSetCursor();
  1613. if( m_bOnDividerAtRight )
  1614. {
  1615. HWND hWndParent = ::GetParent( m_hWnd );
  1616. if( hWndParent != NULL )
  1617. {
  1618. UINT nOwnID = UINT( GetDlgCtrlID() );
  1619. HD_NOTIFY _data, _data2;
  1620. ::memset( &_data, 0, sizeof(HD_NOTIFY) );
  1621. ::memset( &_data2, 0, sizeof(HD_NOTIFY) );
  1622. _data.hdr.hwndFrom = m_hWnd;
  1623. _data.hdr.idFrom = nOwnID;
  1624. _data.iButton = 0;
  1625. _data.iItem = m_nPressingColNo; // nColNo;
  1626. _data.hdr.code = HDN_TRACK;
  1627. HDITEM hdItemBuffer; // to avoid common controls crashing
  1628. ::memset( &hdItemBuffer, 0, sizeof(HDITEM) );
  1629. _data.pitem = &hdItemBuffer;
  1630. ::memcpy( &_data2, &_data, sizeof(HD_NOTIFY) );
  1631. ::SendMessage( hWndParent, WM_NOTIFY, WPARAM(nOwnID), LPARAM(&_data) );
  1632. _data2.hdr.code = HDN_ITEMCHANGED;
  1633. ::SendMessage( hWndParent, WM_NOTIFY, WPARAM(nOwnID), LPARAM(&_data2) );
  1634. if( ::IsWindow( hWndParent ) && ::IsWindowVisible( hWndParent ) )
  1635. ::InvalidateRect( hWndParent, NULL, TRUE );
  1636. } // if( hWndParent != NULL )
  1637. } // if( m_bOnDividerAtRight )
  1638. return;
  1639. }
  1640. else if( ! m_bOnButton )
  1641. {
  1642. if( _DndIsAllowed( m_nPressingColNo ) )
  1643. {
  1644. CPoint ptOffset = _DndGetStartOffset();
  1645. CPoint ptClientPressing;
  1646. ptClientPressing = m_ptScreenPressing;
  1647. ScreenToClient( &ptClientPressing );
  1648. CPoint ptDiff = ptClientPressing - point;
  1649. if( abs(ptDiff.x) >= ptOffset.x || abs(ptDiff.y) >= ptOffset.y )
  1650. {
  1651. _DndDo( m_nPressingColNo, m_ptScreenPressing );
  1652. return;
  1653. }
  1654. }
  1655. }
  1656. }
  1657. bool bOnButton = false, bOnDividerAtRight = false;
  1658. INT nColNo = -1;
  1659. if( CExtPopupMenuWnd::TestHoverEnabledFromActiveHWND( m_hWnd ) )
  1660. {
  1661. CPoint ptScreen;
  1662. ptScreen = point;
  1663. ClientToScreen( &ptScreen );
  1664. if( ::WindowFromPoint( ptScreen ) == m_hWnd )
  1665. nColNo = HitTestHeaderItem( point, &bOnButton, &bOnDividerAtRight );
  1666. }
  1667. bool bHoverChanged = false;
  1668. if( m_nHoverColNo != nColNo
  1669. || m_bOnButton != bOnButton
  1670. || ( m_bOnDividerAtRight != bOnDividerAtRight && ( ! CExtPopupMenuWnd::IsKeyPressed( VK_LBUTTON ) ) )
  1671. )
  1672. {
  1673. bHoverChanged = true;
  1674. m_nHoverColNo = nColNo;
  1675. m_nHoverIndex = ColNo2VisualIndex( m_nHoverColNo );
  1676. m_bOnButton = bOnButton;
  1677. m_bOnDividerAtRight = bOnDividerAtRight;
  1678. if( m_bOnDividerAtRight )
  1679. {
  1680. HWND hWndParent = ::GetParent( m_hWnd );
  1681. if( hWndParent != NULL )
  1682. {
  1683. UINT nOwnID = UINT( GetDlgCtrlID() );
  1684. HD_NOTIFY _data;
  1685. ::memset( &_data, 0, sizeof(HD_NOTIFY) );
  1686. _data.hdr.hwndFrom = m_hWnd;
  1687. _data.hdr.idFrom = nOwnID;
  1688. _data.iButton = 0;
  1689. _data.iItem = nColNo;
  1690. _data.hdr.code = HDN_BEGINTRACK;
  1691. HDITEM hdItemBuffer; // to avoid common controls crashing
  1692. ::memset( &hdItemBuffer, 0, sizeof(HDITEM) );
  1693. _data.pitem = &hdItemBuffer;
  1694. ::SendMessage( hWndParent, WM_NOTIFY, WPARAM(nOwnID), LPARAM(&_data) );
  1695. } // if( hWndParent != NULL )
  1696. } // if( m_bOnDividerAtRight )
  1697. }
  1698. if( bHoverChanged )
  1699. {
  1700. if( m_nPressingColNo < 0 )
  1701. {
  1702. HWND hWndCapture = ::GetCapture();
  1703. if( m_nHoverColNo >= 0 )
  1704. {
  1705. if( m_hWnd != hWndCapture )
  1706. SetCapture();
  1707. if( m_nAdvancedTipStyle != INT(CExtPopupMenuTipWnd::__ETS_NONE)
  1708. && (! CExtPopupMenuWnd::IsMenuTracking() )
  1709. )
  1710. {
  1711. CExtPopupMenuTipWnd * pATTW = OnAdvancedPopupMenuTipWndGet();
  1712. if( pATTW != NULL )
  1713. {
  1714. const CExtHeaderCtrl::EXTENDED_ITEM_DATA & _eii = ExtendedItemDataGet( m_nHoverColNo );
  1715. CRect rcArea;
  1716. if( GetItemRect( m_nHoverColNo, rcArea ) )
  1717. {
  1718. CRect _rcItem, _rcIcon, _rcText, _rcSortArrow, _rcButton, _rcButtonIcon;
  1719. bool bSorted = false,  bSortedAscending = false;
  1720. OnCalcHeaderItemLayout(
  1721. m_nHoverColNo,
  1722. rcArea,
  1723. _rcItem,
  1724. _rcIcon,
  1725. _rcText,
  1726. _rcSortArrow,
  1727. _rcButton,
  1728. _rcButtonIcon,
  1729. &bSorted,
  1730. &bSortedAscending
  1731. );
  1732. if( m_bOnButton )
  1733. {
  1734. rcArea.left = _rcButton.left;
  1735. rcArea.right = _rcButton.right;
  1736. }
  1737. else
  1738. {
  1739. rcArea.left = _rcItem.left;
  1740. rcArea.right = _rcItem.right;
  1741. }
  1742. ClientToScreen( &rcArea );
  1743. OnAdvancedPopupMenuTipWndDisplay(
  1744. *pATTW,
  1745. rcArea,
  1746. m_bOnButton ? LPCTSTR(_eii.m_strTipTextButton) : LPCTSTR(_eii.m_strTipTextItem)
  1747. );
  1748. }
  1749. } // if( pATTW != NULL )
  1750. }
  1751. }
  1752. else
  1753. {
  1754. if( m_hWnd == hWndCapture )
  1755. ReleaseCapture();
  1756. }
  1757. } // if( m_nPressingColNo < 0 )
  1758. Invalidate();
  1759. _DoSetCursor();
  1760. } // if( bHoverChanged )
  1761. }
  1762. void CExtHeaderCtrl::OnLButtonDown( UINT nFlags, CPoint point )
  1763. {
  1764. ASSERT_VALID( this );
  1765. // CHeaderCtrl::OnLButtonDown( nFlags, point );
  1766. nFlags;
  1767. m_ptScreenPressing.x = m_ptScreenPressing.y = m_nHelperInitialResizingExtent = -32767;
  1768. ActivateTopParent();
  1769. _DoSetCursor();
  1770. bool bOnButton = false, bOnDividerAtRight = false;
  1771. INT nColNo = HitTestHeaderItem( point, &bOnButton, &bOnDividerAtRight );
  1772. if( nColNo < 0 )
  1773. return;
  1774. m_nPressingColNo = nColNo;
  1775. m_nPressingIndex = ColNo2VisualIndex( m_nPressingColNo );
  1776. m_bOnButton = bOnButton;
  1777. m_bOnDividerAtRight = bOnDividerAtRight;
  1778. m_ptScreenPressing = point;
  1779. ClientToScreen( &m_ptScreenPressing );
  1780. m_nHelperInitialResizingExtent = HeaderItemExtentGet( nColNo );
  1781. Invalidate();
  1782. HWND hWndCapture = ::GetCapture();
  1783. if( m_hWnd != hWndCapture )
  1784. SetCapture();
  1785. CExtPopupMenuTipWnd * pATTW = OnAdvancedPopupMenuTipWndGet();
  1786. if( pATTW != NULL )
  1787. pATTW->Hide();
  1788. if( m_bOnDividerAtRight )
  1789. {
  1790. HWND hWndParent = ::GetParent( m_hWnd );
  1791. if( hWndParent != NULL )
  1792. {
  1793. UINT nOwnID = UINT( GetDlgCtrlID() );
  1794. HD_NOTIFY _data;
  1795. ::memset( &_data, 0, sizeof(HD_NOTIFY) );
  1796. _data.hdr.hwndFrom = m_hWnd;
  1797. _data.hdr.idFrom = nOwnID;
  1798. _data.iButton = 0;
  1799. _data.iItem = nColNo;
  1800. _data.hdr.code = HDN_BEGINTRACK;
  1801. HDITEM hdItemBuffer; // to avoid common controls crashing
  1802. ::memset( &hdItemBuffer, 0, sizeof(HDITEM) );
  1803. _data.pitem = &hdItemBuffer;
  1804. ::SendMessage( hWndParent, WM_NOTIFY, WPARAM(nOwnID), LPARAM(&_data) );
  1805. } // if( hWndParent != NULL )
  1806. } // if( m_bOnDividerAtRight )
  1807. }
  1808. void CExtHeaderCtrl::OnLButtonUp( UINT nFlags, CPoint point )
  1809. {
  1810. ASSERT_VALID( this );
  1811. // CHeaderCtrl::OnLButtonUp( nFlags, point );
  1812. nFlags;
  1813. point;
  1814. if( m_nPressingColNo < 0 )
  1815. return;
  1816. bool bOnButton = false, bOnDividerAtRight = false;
  1817. INT nColNo = -1;
  1818. CPoint ptScreen;
  1819. ptScreen = point;
  1820. ClientToScreen( &ptScreen );
  1821. if( ::WindowFromPoint( ptScreen ) == m_hWnd )
  1822. nColNo = HitTestHeaderItem( point, &bOnButton, &bOnDividerAtRight );
  1823. if( nColNo == m_nPressingColNo )
  1824. {
  1825. bool bResizing = m_bOnDividerAtRight;
  1826. bool bButtonClick = ( m_bOnButton && (!m_bOnDividerAtRight) ) ? true : false;
  1827. if( bResizing )
  1828. {
  1829. _CancelActions();
  1830. return;
  1831. }
  1832. if( m_bOnButton && bButtonClick )
  1833. {
  1834. _CancelActions();
  1835. OnHeaderItemButtonClick( nColNo );
  1836. return;
  1837. }
  1838. _CancelActions();
  1839. OnHeaderItemClick( nColNo, 0 );
  1840. }
  1841. else
  1842. _CancelActions();
  1843. }
  1844. void CExtHeaderCtrl::OnHeaderItemClick(
  1845. INT nColNo,
  1846. INT nMouseButton // 0 - left button, 1 - right button, 2 - middle button
  1847. )
  1848. {
  1849. ASSERT_VALID( this );
  1850. ASSERT( 0 <= nColNo && nColNo < INT(GetItemCount()) );
  1851. nColNo;
  1852. HWND hWndParent = ::GetParent( m_hWnd );
  1853. if( hWndParent == NULL )
  1854. return;
  1855. UINT nOwnID = UINT( GetDlgCtrlID() );
  1856. HD_NOTIFY _data;
  1857. ::memset( &_data, 0, sizeof(HD_NOTIFY) );
  1858. _data.hdr.hwndFrom = m_hWnd;
  1859. _data.hdr.idFrom = nOwnID;
  1860. _data.hdr.code = HDN_ITEMCLICK;
  1861. _data.iButton = nMouseButton;
  1862. _data.iItem = nColNo;
  1863. HDITEM hdItemBuffer; // to avoid common controls crashing
  1864. ::memset( &hdItemBuffer, 0, sizeof(HDITEM) );
  1865. _data.pitem = &hdItemBuffer;
  1866. ::SendMessage( hWndParent, WM_NOTIFY, WPARAM(nOwnID), LPARAM(&_data) );
  1867. }
  1868. void CExtHeaderCtrl::OnHeaderItemButtonClick( INT nColNo )
  1869. {
  1870. ASSERT_VALID( this );
  1871. ASSERT( 0 <= nColNo && nColNo < INT(GetItemCount()) );
  1872. nColNo;
  1873. GetParent()->SendMessage( CExtHeaderCtrl::g_nMsgHeaderButtonClick, WPARAM(nColNo), LPARAM(this) );
  1874. }
  1875. void CExtHeaderCtrl::OnHeaderItemDividerAtRightDoubleClick( INT nColNo )
  1876. {
  1877. ASSERT_VALID( this );
  1878. ASSERT( 0 <= nColNo && nColNo < INT(GetItemCount()) );
  1879. HWND hWndParent = ::GetParent( m_hWnd );
  1880. if( hWndParent == NULL )
  1881. return;
  1882. UINT nOwnID = UINT( GetDlgCtrlID() );
  1883. HD_NOTIFY _data;
  1884. ::memset( &_data, 0, sizeof(HD_NOTIFY) );
  1885. _data.hdr.hwndFrom = m_hWnd;
  1886. _data.hdr.idFrom = nOwnID;
  1887. _data.hdr.code = HDN_ITEMDBLCLICK;
  1888. _data.iButton = 0;
  1889. _data.iItem = nColNo;
  1890. HDITEM hdItemBuffer; // to avoid common controls crashing
  1891. ::memset( &hdItemBuffer, 0, sizeof(HDITEM) );
  1892. _data.pitem = &hdItemBuffer;
  1893. ::SendMessage( hWndParent, WM_NOTIFY, WPARAM(nOwnID), LPARAM(&_data) );}
  1894. void CExtHeaderCtrl::OnLButtonDblClk( UINT nFlags, CPoint point )
  1895. {
  1896. ASSERT_VALID( this );
  1897. // CHeaderCtrl::OnLButtonDown( nFlags, point );
  1898. nFlags;
  1899. bool bOnButton = false, bOnDividerAtRight = false;
  1900. INT nColNo = HitTestHeaderItem( point, &bOnButton, &bOnDividerAtRight );
  1901. if( nColNo < 0 )
  1902. return;
  1903. if( ! bOnDividerAtRight )
  1904. return;
  1905. OnHeaderItemDividerAtRightDoubleClick( nColNo );
  1906. }
  1907. void CExtHeaderCtrl::OnRButtonDown( UINT nFlags, CPoint point )
  1908. {
  1909. ASSERT_VALID( this );
  1910. // CHeaderCtrl::OnRButtonDown( nFlags, point );
  1911. nFlags;
  1912. INT nColNo = HitTestHeaderItem( point, NULL, NULL, false );
  1913. if( nColNo >= 0 )
  1914. {
  1915. _CancelActions();
  1916. OnHeaderItemClick( nColNo, 1 );
  1917. }
  1918. }
  1919. void CExtHeaderCtrl::OnRButtonUp( UINT nFlags, CPoint point )
  1920. {
  1921. ASSERT_VALID( this );
  1922. // CHeaderCtrl::OnRButtonUp( nFlags, point );
  1923. nFlags;
  1924. point;
  1925. }
  1926. void CExtHeaderCtrl::OnRButtonDblClk( UINT nFlags, CPoint point )
  1927. {
  1928. ASSERT_VALID( this );
  1929. // CHeaderCtrl::OnRButtonDown( nFlags, point );
  1930. nFlags;
  1931. point;
  1932. }
  1933. void CExtHeaderCtrl::OnMButtonDown( UINT nFlags, CPoint point )
  1934. {
  1935. ASSERT_VALID( this );
  1936. // CHeaderCtrl::OnMButtonDown( nFlags, point );
  1937. nFlags;
  1938. INT nColNo = HitTestHeaderItem( point, NULL, NULL, false );
  1939. if( nColNo >= 0 )
  1940. {
  1941. _CancelActions();
  1942. OnHeaderItemClick( nColNo, 2 );
  1943. }
  1944. }
  1945. void CExtHeaderCtrl::OnMButtonUp( UINT nFlags, CPoint point )
  1946. {
  1947. ASSERT_VALID( this );
  1948. // CHeaderCtrl::OnMButtonUp( nFlags, point );
  1949. nFlags;
  1950. point;
  1951. }
  1952. void CExtHeaderCtrl::OnMButtonDblClk( UINT nFlags, CPoint point )
  1953. {
  1954. ASSERT_VALID( this );
  1955. // CHeaderCtrl::OnMButtonDown( nFlags, point );
  1956. nFlags;
  1957. point;
  1958. }
  1959. void CExtHeaderCtrl::OnWindowPosChanging( WINDOWPOS FAR * lpwndpos ) 
  1960. {
  1961. CHeaderCtrl::OnWindowPosChanging(lpwndpos);
  1962. Invalidate();
  1963. }
  1964. BOOL CExtHeaderCtrl::OnEraseBkgnd( CDC * pDC )
  1965. {
  1966. ASSERT_VALID( this );
  1967. pDC;
  1968. return TRUE;
  1969. }
  1970. LRESULT CExtHeaderCtrl::WindowProc(UINT message, WPARAM wParam, LPARAM lParam) 
  1971. {
  1972. switch( message )
  1973. {
  1974. case HDM_INSERTITEM:
  1975. {
  1976. ASSERT( m_arrExtendedData.GetSize() == GetItemCount() );
  1977. static EXTENDED_ITEM_DATA g_eii;
  1978. m_arrExtendedData.InsertAt( (INT) wParam, g_eii, 1 );
  1979. //ASSERT( m_arrExtendedData.GetSize() == GetItemCount() );
  1980. _CancelActions();
  1981. }
  1982. break;
  1983. case HDM_DELETEITEM:
  1984. {
  1985. //ASSERT( m_arrExtendedData.GetSize() == GetItemCount() );
  1986. m_arrExtendedData.RemoveAt( ( int ) wParam );
  1987. //ASSERT( m_arrExtendedData.GetSize() == GetItemCount() );
  1988. _CancelActions();
  1989. }
  1990. break;
  1991. case HDM_HITTEST:
  1992. {
  1993. HDHITTESTINFO * pHDHTI = reinterpret_cast < HDHITTESTINFO * > ( lParam );
  1994. if( pHDHTI == NULL )
  1995. return -1;
  1996. pHDHTI->iItem = -1;
  1997. pHDHTI->flags = HHT_NOWHERE;
  1998. CRect rcClient;
  1999. GetClientRect( &rcClient );
  2000. if( pHDHTI->pt.y < rcClient.top )
  2001. {
  2002. pHDHTI->flags = HHT_ABOVE;
  2003. return -1;
  2004. }
  2005. if( pHDHTI->pt.y > rcClient.bottom )
  2006. {
  2007. pHDHTI->flags = HHT_BELOW;
  2008. return -1;
  2009. }
  2010. INT nColNo, nColCount = INT(GetItemCount()), nWalkWay = 0;
  2011. for( nColNo = 0; nColNo < nColCount; nColNo++ )
  2012. {
  2013. CRect _rcItemEntire;
  2014. if( ! GetItemRect( nColNo, &_rcItemEntire ) )
  2015. continue;
  2016. if( ! _rcItemEntire.PtInRect( pHDHTI->pt ) )
  2017. continue;
  2018. pHDHTI->iItem = nColNo;
  2019. pHDHTI->flags = 0;
  2020. CRect rc = _rcItemEntire;
  2021. rc.right = rc.left + m_nDividerHalfExtent;
  2022. if( rc.PtInRect( pHDHTI->pt ) )
  2023. {
  2024. nWalkWay = -1;
  2025. pHDHTI->flags |= HHT_ONDIVIDER;
  2026. }
  2027. else
  2028. {
  2029. rc = _rcItemEntire;
  2030. rc.left = rc.right - m_nDividerHalfExtent;
  2031. if( rc.PtInRect( pHDHTI->pt ) )
  2032. {
  2033. nWalkWay = 1;
  2034. pHDHTI->flags |= HHT_ONDIVIDER;
  2035. }
  2036. }
  2037. INT nTestColNo = VisualIndex2ColNo( ColNo2VisualIndex( nColNo ) + nWalkWay );
  2038. if( nTestColNo >= 0 )
  2039. {
  2040. CRect rcTest;
  2041. if( GetItemRect( nTestColNo, &rcTest )
  2042. && rcTest.Width() == 0
  2043. )
  2044. pHDHTI->flags |= HHT_ONDIVOPEN;
  2045. }
  2046. break;
  2047. } // for( nColNo = 0; nColNo < nColCount; nColNo++ )
  2048. return pHDHTI->iItem;
  2049. }
  2050. //break;
  2051. } // switch( message )
  2052. // __try
  2053. // {
  2054. return CHeaderCtrl::WindowProc(message, wParam, lParam);
  2055. // }
  2056. // __except( EXCEPTION_EXECUTE_HANDLER )
  2057. // {
  2058. // }
  2059. // return 0L;
  2060. }
  2061. void CExtHeaderCtrl::PreSubclassWindow() 
  2062. {
  2063. m_arrExtendedData.RemoveAll();
  2064. m_bCancelingActions = false;
  2065. m_ptScreenPressing.x = m_ptScreenPressing.y = m_nHelperInitialResizingExtent = -32767;
  2066. m_nHoverColNo = m_nHoverIndex = m_nPressingColNo = m_nPressingIndex = -1;
  2067. m_bOnButton = m_bOnDividerAtRight = false;
  2068. CHeaderCtrl::PreSubclassWindow();
  2069. }
  2070. void CExtHeaderCtrl::PostNcDestroy() 
  2071. {
  2072. m_bCancelingActions = false;
  2073. m_ptScreenPressing.x = m_ptScreenPressing.y = m_nHelperInitialResizingExtent = -32767;
  2074. m_nHoverColNo = m_nHoverIndex = m_nPressingColNo = m_nPressingIndex = -1;
  2075. m_bOnButton = m_bOnDividerAtRight = false;
  2076. CHeaderCtrl::PostNcDestroy();
  2077. m_arrExtendedData.RemoveAll();
  2078. }
  2079. const CExtHeaderCtrl::EXTENDED_ITEM_DATA & CExtHeaderCtrl::ExtendedItemDataGet( INT nColNo ) const
  2080. {
  2081. ASSERT_VALID( this );
  2082. return ( const_cast < CExtHeaderCtrl * > ( this ) ) -> ExtendedItemDataGet( nColNo );
  2083. }
  2084. CExtHeaderCtrl::EXTENDED_ITEM_DATA & CExtHeaderCtrl::ExtendedItemDataGet( INT nColNo )
  2085. {
  2086. ASSERT_VALID( this );
  2087. ASSERT( GetSafeHwnd() != NULL );
  2088. INT nArraySize = INT( m_arrExtendedData.GetSize() );
  2089. INT nItemCount = INT( GetItemCount() );
  2090. for( ; nArraySize < nItemCount; nArraySize ++ )
  2091. {
  2092. static EXTENDED_ITEM_DATA g_eii;
  2093. m_arrExtendedData.InsertAt( nArraySize, g_eii, 1 );
  2094. }
  2095. if( nArraySize > nItemCount )
  2096. m_arrExtendedData.RemoveAt( nArraySize - nItemCount, nArraySize - nItemCount );
  2097. EXTENDED_ITEM_DATA & _eii = m_arrExtendedData.ElementAt( nColNo );
  2098. // if( _eii.m_iconItem.IsEmpty() )
  2099. // {
  2100. // HICON hIconTest = AfxGetApp()->LoadIcon( IDR_MAINFRAME );
  2101. // _eii.m_iconItem.AssignFromHICON( hIconTest, false );
  2102. // _eii.m_iconItem.Scale( CSize(13,13) );
  2103. // }
  2104. // if( _eii.m_iconButton.IsEmpty() )
  2105. // {
  2106. // HICON hIconTest = AfxGetApp()->LoadIcon( IDR_MAINFRAME );
  2107. // _eii.m_iconButton.AssignFromHICON( hIconTest, false );
  2108. // _eii.m_iconButton.Scale( CSize(13,13) );
  2109. // }
  2110. return _eii;
  2111. }
  2112. CExtHeaderCtrl::EXTENDED_ITEM_DATA::EXTENDED_ITEM_DATA()
  2113. : m_nExtentMin( 0 )
  2114. , m_nExtentMax( 32767 )
  2115. , m_bDisableDnd( false )
  2116. {
  2117. }
  2118. CExtHeaderCtrl::EXTENDED_ITEM_DATA::EXTENDED_ITEM_DATA( const CExtHeaderCtrl::EXTENDED_ITEM_DATA & other )
  2119. {
  2120. AssignFromOther( other );
  2121. }
  2122. CExtHeaderCtrl::EXTENDED_ITEM_DATA::~EXTENDED_ITEM_DATA()
  2123. {
  2124. }
  2125. void CExtHeaderCtrl::EXTENDED_ITEM_DATA::AssignFromOther( const CExtHeaderCtrl::EXTENDED_ITEM_DATA & other )
  2126. {
  2127. m_iconItem          = other.m_iconItem;
  2128. m_iconButton        = other.m_iconButton;
  2129. m_strTipTextItem    = other.m_strTipTextItem;
  2130. m_strTipTextButton  = other.m_strTipTextButton;
  2131. m_nExtentMin        = other.m_nExtentMin;
  2132. m_nExtentMax        = other.m_nExtentMax;
  2133. m_bDisableDnd       = other.m_bDisableDnd;
  2134. }
  2135. CExtHeaderCtrl::EXTENDED_ITEM_DATA & CExtHeaderCtrl::EXTENDED_ITEM_DATA::operator = ( const CExtHeaderCtrl::EXTENDED_ITEM_DATA & other )
  2136. {
  2137. AssignFromOther( other );
  2138. return ( *this );
  2139. }
  2140. bool CExtHeaderCtrl::EXTENDED_ITEM_DATA::CanBeResized() const
  2141. {
  2142. if( m_nExtentMin < m_nExtentMax )
  2143. return true;
  2144. else
  2145. return false;
  2146. }
  2147. /////////////////////////////////////////////////////////////////////////////
  2148. // CExtListCtrl
  2149. CExtListCtrl::CExtListCtrl()
  2150. : m_bSortEnabled( true )
  2151. , m_bSortEnabledMultiple( true )
  2152. , m_bColumnAutoSizingByData( false )
  2153. , m_bColumnAutoSizingByHeader( true )
  2154. , m_bReadOnlyLabels( false )
  2155. {
  2156. PmBridge_Install( true );
  2157. }
  2158. CExtListCtrl::~CExtListCtrl()
  2159. {
  2160. PmBridge_Uninstall();
  2161. }
  2162. void CExtListCtrl::PmBridge_OnPaintManagerChanged(
  2163. CExtPaintManager * pGlobalPM
  2164. )
  2165. {
  2166. CExtPmBridge::PmBridge_OnPaintManagerChanged( pGlobalPM );
  2167. if( GetSafeHwnd() == NULL )
  2168. return;
  2169. Invalidate();
  2170. }
  2171. IMPLEMENT_DYNCREATE( CExtListCtrl, CListCtrl );
  2172. BEGIN_MESSAGE_MAP(CExtListCtrl, CListCtrl)
  2173. //{{AFX_MSG_MAP(CExtListCtrl)
  2174. ON_NOTIFY(HDN_ITEMCLICK, 0, OnHeaderItemClick) 
  2175. ON_NOTIFY(HDN_ITEMDBLCLICK, 0, OnHeaderItemDoubleClick) 
  2176. ON_WM_DESTROY()
  2177. ON_WM_CREATE()
  2178. ON_WM_WINDOWPOSCHANGING()
  2179. ON_NOTIFY_REFLECT(LVN_DELETEITEM, OnDeleteItem)
  2180. ON_NOTIFY_REFLECT(LVN_DELETEALLITEMS, OnDeleteAllItems)
  2181. ON_NOTIFY_REFLECT(LVN_BEGINLABELEDIT, OnBeginLabelEdit)
  2182. ON_NOTIFY(HDN_BEGINDRAG, 0, OnBeginDrag)
  2183. ON_NOTIFY(HDN_ENDDRAG, 0, OnEndDrag)
  2184. //}}AFX_MSG_MAP
  2185. END_MESSAGE_MAP()
  2186. /////////////////////////////////////////////////////////////////////////////
  2187. // CExtListCtrl message handlers
  2188. void CExtListCtrl::OnHeaderItemClick( NMHDR * pNMHDR, LRESULT * pResult ) 
  2189. {
  2190. ASSERT_VALID( this );
  2191. (*pResult) = 0;
  2192. if( ! m_bSortEnabled )
  2193. return;
  2194. HD_NOTIFY * pHdNotify = (HD_NOTIFY *)pNMHDR;
  2195. if( pHdNotify->iButton == 0 )
  2196. {
  2197. CExtListCtrlDataSortOrder _sortOrder;
  2198. CExtHeaderCtrl & wndHeader = GetHeaderCtrl();
  2199. wndHeader.SortRulesGet( _sortOrder );
  2200. if( m_bSortEnabledMultiple
  2201. && CExtPopupMenuWnd::IsKeyPressed( VK_SHIFT )
  2202. )
  2203. {
  2204. CExtListCtrlDataSortOrder _sortOrderUpdateFrom;
  2205. CExtListCtrlDataSortOrder::COLUMN_INFO _columnInfo( INT(pHdNotify->iItem), true );
  2206. _sortOrderUpdateFrom.m_arrItems.Add( _columnInfo );
  2207. _sortOrder.SetupOrder( _sortOrderUpdateFrom, true );
  2208. }
  2209. else
  2210. {
  2211. if( _sortOrder.m_arrItems.GetSize() == 1
  2212. && _sortOrder.m_arrItems[ 0 ] == INT(pHdNotify->iItem)
  2213. )
  2214. _sortOrder.m_arrItems.ElementAt( 0 ).m_bAscending =
  2215. ! _sortOrder.m_arrItems[ 0 ].m_bAscending;
  2216. else
  2217. {
  2218. _sortOrder.m_arrItems.RemoveAll();
  2219. CExtListCtrlDataSortOrder::COLUMN_INFO _columnInfo( INT(pHdNotify->iItem), true );
  2220. _sortOrder.m_arrItems.Add( _columnInfo );
  2221. }
  2222. }
  2223. SortItems( _sortOrder );
  2224. Invalidate();
  2225. wndHeader.SortRulesSet( _sortOrder );
  2226. } // if( pHdNotify->iButton == 0 )
  2227. }
  2228. void CExtListCtrl::OnHeaderItemDoubleClick( NMHDR * pNMHDR, LRESULT * pResult ) 
  2229. {
  2230. ASSERT_VALID( this );
  2231. (*pResult) = 0;
  2232. HD_NOTIFY * pHdNotify = (HD_NOTIFY *)pNMHDR;
  2233. if( pHdNotify->iButton == 0 )
  2234. {
  2235. INT nColNo = INT( pHdNotify->iItem );
  2236. ColumnAutoSize(
  2237. nColNo,
  2238. m_bColumnAutoSizingByData,
  2239. m_bColumnAutoSizingByHeader
  2240. );
  2241. return;
  2242. }
  2243. }
  2244. CExtHeaderCtrl & CExtListCtrl::_OnQueryHeaderCtrl()
  2245. {
  2246. ASSERT_VALID( this );
  2247. _Init();
  2248. return m_wndHeaderCtrl;
  2249. }
  2250. CExtHeaderCtrl & CExtListCtrl::GetHeaderCtrl()
  2251. {
  2252. ASSERT_VALID( this );
  2253. return _OnQueryHeaderCtrl();
  2254. }
  2255. const CExtHeaderCtrl & CExtListCtrl::GetHeaderCtrl() const
  2256. {
  2257. ASSERT_VALID( this );
  2258. return ( const_cast < CExtListCtrl * > ( this ) ) -> GetHeaderCtrl();
  2259. }
  2260. void CExtListCtrl::GetSelectedItemsList(
  2261. CList < INT, INT > & _listSelectedItems, 
  2262. bool bAddToTail // = true
  2263. )
  2264. {
  2265. ASSERT_VALID( this );
  2266. _listSelectedItems.RemoveAll();
  2267. POSITION posSelItems = GetFirstSelectedItemPosition();
  2268. if( posSelItems == NULL )
  2269. return;
  2270. for( ; posSelItems != NULL ; )
  2271. {
  2272. INT nSelItem = (INT)GetNextSelectedItem( posSelItems );
  2273. if( bAddToTail )
  2274. _listSelectedItems.AddTail( nSelItem );
  2275. else
  2276. _listSelectedItems.AddHead( nSelItem );
  2277. }
  2278. }
  2279. bool CExtListCtrl::VerifySortOrder(
  2280. const CExtListCtrlDataSortOrder & _sortOrder
  2281. ) const
  2282. {
  2283. ASSERT_VALID( this );
  2284. const CExtHeaderCtrl & wndHeader = GetHeaderCtrl();
  2285. ASSERT( wndHeader.GetSafeHwnd() != NULL );
  2286. INT nColCount = INT( wndHeader.GetItemCount() );
  2287. INT nSortColNo, nSortColCount = INT(_sortOrder.m_arrItems.GetSize());
  2288. for( nSortColNo = 0; nSortColNo < nSortColCount; nSortColNo ++ )
  2289. {
  2290. const CExtListCtrlDataSortOrder::COLUMN_INFO & _columnInfo = _sortOrder.m_arrItems[ nSortColNo ];
  2291. if( _columnInfo.m_nColNo < 0 )
  2292. return false;
  2293. if( _columnInfo.m_nColNo >= nColCount )
  2294. return false;
  2295. }
  2296. return true;
  2297. }
  2298. INT CExtListCtrl::CompareItems(
  2299. const CExtListCtrlDataSortOrder & _sortOrder,
  2300. INT nItemIndex1,
  2301. INT nItemIndex2
  2302. ) const
  2303. {
  2304. ASSERT_VALID( this );
  2305. ASSERT( ! _sortOrder.IsEmpty() );
  2306. if( nItemIndex1 == nItemIndex2 )
  2307. return 0;
  2308. INT nSortColNo, nSortColCount = INT(_sortOrder.m_arrItems.GetSize());
  2309. for( nSortColNo = 0; nSortColNo < nSortColCount; nSortColNo ++ )
  2310. {
  2311. const CExtListCtrlDataSortOrder::COLUMN_INFO & _columnInfo = _sortOrder.m_arrItems[ nSortColNo ];
  2312. CExtSafeString strText1 = GetItemText( nItemIndex1, _columnInfo.m_nColNo );
  2313. CExtSafeString strText2 = GetItemText( nItemIndex2, _columnInfo.m_nColNo );
  2314. int nCmpResult = strText1.Compare( strText2 );
  2315. if( nCmpResult == 0 )
  2316. continue;
  2317. return _columnInfo.m_bAscending ? (nCmpResult) : (-nCmpResult);
  2318. }
  2319. return 0;
  2320. }
  2321. void CExtListCtrl::SwapItems(
  2322. INT nItemIndex1,
  2323. INT nItemIndex2
  2324. )
  2325. {
  2326. ASSERT_VALID( this );
  2327. ASSERT( nItemIndex1 != nItemIndex2 );
  2328. LV_ITEM _item1, _item2;
  2329. ::memset( &_item1, 0, sizeof(LV_ITEM) );
  2330. ::memset( &_item2, 0, sizeof(LV_ITEM) );
  2331. CExtHeaderCtrl & wndHeader = GetHeaderCtrl();
  2332. ASSERT( wndHeader.GetSafeHwnd() != NULL );
  2333. INT nColNo, nColCount = INT( wndHeader.GetItemCount() );
  2334. CStringArray arrItemTextValues;
  2335. arrItemTextValues.SetSize( nColCount );
  2336. for( nColNo = 0; nColNo < nColCount; nColNo ++ )
  2337. arrItemTextValues[nColNo] = GetItemText( nItemIndex1, nColNo );
  2338. _item1.mask = LVIF_IMAGE|LVIF_PARAM|LVIF_STATE;
  2339. _item1.iItem = nItemIndex1;
  2340. _item1.iSubItem = 0;
  2341. _item1.stateMask = LVIS_CUT|LVIS_DROPHILITED|LVIS_FOCUSED|LVIS_SELECTED|LVIS_OVERLAYMASK|LVIS_STATEIMAGEMASK;
  2342. _item2 = _item1;
  2343. _item2.iItem = nItemIndex2;
  2344. GetItem( &_item1 );
  2345. GetItem( &_item2 );
  2346. for( nColNo = 0; nColNo < nColCount; nColNo ++ )
  2347. SetItemText( nItemIndex1, nColNo, GetItemText( nItemIndex2, nColNo ) );
  2348. _item2.iItem = nItemIndex1;
  2349. SetItem( &_item2 );
  2350. for( nColNo = 0; nColNo < nColCount; nColNo ++ )
  2351. SetItemText(nItemIndex2, nColNo, arrItemTextValues[nColNo]);
  2352. _item1.iItem = nItemIndex2;
  2353. SetItem( &_item1 );
  2354. }
  2355. bool CExtListCtrl::SortItems(
  2356. INT nItemIndexLow, //= 0 
  2357. INT nItemIndexHigh // -1
  2358. )
  2359. {
  2360. ASSERT_VALID( this );
  2361. if( GetSafeHwnd() == NULL )
  2362. return false;
  2363. CExtHeaderCtrl & wndHeader = GetHeaderCtrl();
  2364. ASSERT( wndHeader.GetSafeHwnd() != NULL );
  2365. return SortItems( wndHeader.m_sortOrder, nItemIndexLow, nItemIndexHigh );
  2366. }
  2367. bool CExtListCtrl::SortItems(
  2368. const CExtListCtrlDataSortOrder & _sortOrder,
  2369. INT nItemIndexLow, //= 0 
  2370. INT nItemIndexHigh // -1
  2371. )
  2372. {
  2373. ASSERT_VALID( this );
  2374. if( GetSafeHwnd() == NULL )
  2375. return false;
  2376. //ASSERT( m_bSortEnabled );
  2377. if( _sortOrder.IsEmpty() || GetItemCount() == 0 )
  2378. return true;
  2379. if( ! VerifySortOrder( _sortOrder ) )
  2380. return false;
  2381. if( nItemIndexHigh < 0 )
  2382. nItemIndexHigh = GetItemCount() - 1;
  2383. INT nReviewIndexLow = nItemIndexLow;
  2384. INT nReviewIndexHigh = nItemIndexHigh;
  2385. if( nReviewIndexHigh <= nReviewIndexLow )
  2386. return false;
  2387. LONG nViewMin = nItemIndexLow, nViewMax = nItemIndexHigh, nViewMiddle = ( nItemIndexLow + nItemIndexHigh ) / 2L;
  2388. for( ; nViewMin <= nViewMax; )
  2389. {
  2390. for( ; ( nViewMin < nItemIndexHigh ) && ( CompareItems( _sortOrder, nViewMin, nViewMiddle ) < 0 ); ++ nViewMin );
  2391. for( ; ( nViewMax > nItemIndexLow ) && ( CompareItems( _sortOrder, nViewMax, nViewMiddle ) > 0 ); -- nViewMax );
  2392. if( nViewMin <= nViewMax )
  2393. {
  2394. if( nViewMin != nViewMax && CompareItems( _sortOrder, nViewMin, nViewMax ) != 0 )
  2395. {
  2396. if( nViewMiddle == nViewMin )
  2397. nViewMiddle = nViewMax;
  2398. else if( nViewMiddle == nViewMax )
  2399. nViewMiddle = nViewMin;
  2400. SwapItems( nViewMin, nViewMax );
  2401. }
  2402. ++ nViewMin;
  2403. -- nViewMax;
  2404. }
  2405. }
  2406. if( nItemIndexLow < nViewMax )
  2407. {
  2408. if( ! SortItems( _sortOrder, nItemIndexLow, nViewMax ) )
  2409. {
  2410. ASSERT( FALSE );
  2411. return false;
  2412. }
  2413. }
  2414. if( nViewMin < nItemIndexHigh )
  2415. {
  2416. if( ! SortItems( _sortOrder, nViewMin, nItemIndexHigh ) )
  2417. {
  2418. ASSERT( FALSE );
  2419. return false;
  2420. }
  2421. }
  2422. return true;
  2423. }
  2424. void CExtListCtrl::StateSerialize(
  2425. CArchive & ar,
  2426. bool bExtents, // = true
  2427. bool bOrder, // = true
  2428. bool bSortOrder, // = true
  2429. bool bListViewMode // = true
  2430. )
  2431. {
  2432. ASSERT_VALID( this );
  2433. ASSERT( GetSafeHwnd() != NULL );
  2434. DWORD dwSerializedDataMask = 0;
  2435. if( bExtents )
  2436. dwSerializedDataMask |= ( 1 << 0 );
  2437. if( bOrder )
  2438. dwSerializedDataMask |= ( 1 << 1 );
  2439. if( bSortOrder )
  2440. dwSerializedDataMask |= ( 1 << 2 );
  2441. if( bListViewMode )
  2442. dwSerializedDataMask |= ( 1 << 3 );
  2443. if( dwSerializedDataMask == 0 )
  2444. ::AfxThrowUserException();
  2445. CExtHeaderCtrl & wndHeader = GetHeaderCtrl();
  2446. ASSERT( wndHeader.GetSafeHwnd() != NULL );
  2447. INT nColNo, nColCount = INT( wndHeader.GetItemCount() );
  2448. DWORD dwGap = 0;
  2449. INT * pArr = NULL;
  2450. try
  2451. {
  2452. if( ar.IsStoring() )
  2453. {
  2454. ar << dwGap;
  2455. ar << dwSerializedDataMask;
  2456. ar << DWORD( nColCount );
  2457. if( bExtents )
  2458. {
  2459. for( nColNo = 0; nColNo < nColCount; nColNo ++ )
  2460. {
  2461. const CExtHeaderCtrl::EXTENDED_ITEM_DATA & _eii = wndHeader.ExtendedItemDataGet( nColNo );
  2462. DWORD dwExtent = (DWORD)ColumnExtentGet( nColNo );
  2463. ar << dwExtent;
  2464. ar << DWORD(_eii.m_nExtentMin);
  2465. ar << DWORD(_eii.m_nExtentMax);
  2466. } // for( nColNo = 0; nColNo < nColCount; nColNo ++ )
  2467. } // if( bExtents )
  2468. if( bOrder )
  2469. {
  2470. try
  2471. {
  2472. pArr = new INT[ nColCount ];
  2473. if( ! wndHeader.GetOrderArray( pArr, nColCount ) )
  2474. ::AfxThrowUserException();
  2475. for( nColNo = 0; nColNo < nColCount; nColNo ++ )
  2476. ar << DWORD( pArr[nColNo] );
  2477. }
  2478. catch( CException * pException )
  2479. {
  2480. pException->Delete();
  2481. }
  2482. } // if( bOrder )
  2483. if( bListViewMode )
  2484. {
  2485. DWORD dwMode = (DWORD)( GetStyle() & LVS_TYPEMASK );
  2486. ar << dwMode;
  2487. }
  2488. } // if( ar.IsStoring() )
  2489. else
  2490. {
  2491. ar >> dwGap;
  2492. DWORD dwSerializedDataMask2 = 0;
  2493. ar >> dwSerializedDataMask2;
  2494. if( dwSerializedDataMask2 == 0 || dwSerializedDataMask2 != dwSerializedDataMask )
  2495. ::AfxThrowUserException();
  2496. DWORD dwColCountToLoad;
  2497. ar >> dwColCountToLoad;
  2498. if( INT(dwColCountToLoad) != nColCount )
  2499. ::AfxThrowArchiveException( CArchiveException::badSchema );
  2500. if( bExtents )
  2501. {
  2502. for( nColNo = 0; nColNo < nColCount; nColNo ++ )
  2503. {
  2504. CExtHeaderCtrl::EXTENDED_ITEM_DATA & _eii = wndHeader.ExtendedItemDataGet( nColNo );
  2505. DWORD dwExtent;
  2506. ar >> dwExtent;
  2507. ColumnExtentSet( nColNo, INT(dwExtent) );
  2508. ar >> dwExtent;
  2509. _eii.m_nExtentMin = INT(dwExtent);
  2510. ar >> dwExtent;
  2511. _eii.m_nExtentMax = INT(dwExtent);
  2512. } // for( nColNo = 0; nColNo < nColCount; nColNo ++ )
  2513. } // if( bExtents )
  2514. if( bOrder )
  2515. {
  2516. try
  2517. {
  2518. pArr = new INT[ nColCount ];
  2519. for( nColNo = 0; nColNo < nColCount; nColNo ++ )
  2520. {
  2521. DWORD dwTmp;
  2522. ar >> dwTmp;
  2523. pArr[nColNo] = INT(dwTmp);
  2524. } // for( nColNo = 0; nColNo < nColCount; nColNo ++ )
  2525. if( ! wndHeader.SetOrderArray( nColCount, pArr ) )
  2526. ::AfxThrowUserException();
  2527. }
  2528. catch( CException * pException )
  2529. {
  2530. pException->Delete();
  2531. }
  2532. } // if( bOrder )
  2533. if( bListViewMode )
  2534. {
  2535. DWORD dwMode = 0;
  2536. ar >> dwMode;
  2537. if( ( dwMode & LVS_TYPEMASK ) != dwMode )
  2538. ::AfxThrowUserException();
  2539. ModifyStyle( LVS_TYPEMASK, 0 );
  2540. ModifyStyle( 0, dwMode );
  2541. }
  2542. } // else from if( ar.IsStoring() )
  2543. if( bSortOrder )
  2544. {
  2545. wndHeader.m_sortOrder.Serialize( ar );
  2546. if( ar.IsLoading()
  2547. && (! wndHeader.m_sortOrder.IsEmpty() )
  2548. && VerifySortOrder( wndHeader.m_sortOrder )
  2549. )
  2550. SortItems( wndHeader.m_sortOrder );
  2551. } // if( bSortOrder )
  2552. } // try
  2553. catch( ... )
  2554. {
  2555. if( pArr != NULL )
  2556. delete [] pArr;
  2557. throw;
  2558. } // catch( ... )
  2559. if( pArr != NULL )
  2560. delete [] pArr;
  2561. }
  2562. static CExtSafeString productsection2regkeypath(
  2563. __EXT_MFC_SAFE_LPCTSTR sCppClassName,
  2564. __EXT_MFC_SAFE_LPCTSTR sProfileName,
  2565. __EXT_MFC_SAFE_LPCTSTR sSectionNameCompany, // under HKEY_CURRENT_USERSoftware
  2566. __EXT_MFC_SAFE_LPCTSTR sSectionNameProduct // under HKEY_CURRENT_USERSoftware%sSectionNameCompany%
  2567. )
  2568. {
  2569. return CExtCmdManager::GetSubSystemRegKeyPath(
  2570. sCppClassName,
  2571. sProfileName,
  2572. sSectionNameCompany,
  2573. sSectionNameProduct
  2574. );
  2575. }
  2576. bool CExtListCtrl::StateLoad(
  2577. __EXT_MFC_SAFE_LPCTSTR sSectionNameCompany, // under HKEY_CURRENT_USERSoftware
  2578. __EXT_MFC_SAFE_LPCTSTR sSectionNameProduct, // under HKEY_CURRENT_USERSoftware%sSectionNameCompany%
  2579. __EXT_MFC_SAFE_LPCTSTR sSectionNameProfile, // under HKEY_CURRENT_USERSoftware%sSectionNameCompany%%sSectionNameProfile%
  2580. HKEY hKeyRoot, // = HKEY_CURRENT_USER
  2581. bool bExtents, // = true
  2582. bool bOrder, // = true
  2583. bool bSortOrder, // = true
  2584. bool bListViewMode // = true
  2585. )
  2586. {
  2587. ASSERT_VALID( this );
  2588. ASSERT( GetSafeHwnd() != NULL );
  2589. CExtSafeString sRegKeyPath=
  2590. productsection2regkeypath(
  2591. _T("CExtListCtrl"),
  2592. sSectionNameProfile,
  2593. sSectionNameCompany,
  2594. sSectionNameProduct
  2595. );
  2596. try
  2597. {
  2598. CMemFile _file;
  2599. if( ! CExtCmdManager::FileObjFromRegistry( _file, sRegKeyPath, hKeyRoot, false ) )
  2600. return false;
  2601. CArchive ar( &_file, CArchive::load );
  2602. StateSerialize( ar, bExtents, bOrder, bSortOrder, bListViewMode );
  2603. return true;
  2604. }
  2605. catch( CException * pXept )
  2606. {
  2607. pXept->Delete();
  2608. }
  2609. catch( ... )
  2610. {
  2611. }
  2612. return false;
  2613. }
  2614. bool CExtListCtrl::StateSave(
  2615. __EXT_MFC_SAFE_LPCTSTR sSectionNameCompany, // under HKEY_CURRENT_USERSoftware
  2616. __EXT_MFC_SAFE_LPCTSTR sSectionNameProduct, // under HKEY_CURRENT_USERSoftware%sSectionNameCompany%
  2617. __EXT_MFC_SAFE_LPCTSTR sSectionNameProfile, // under HKEY_CURRENT_USERSoftware%sSectionNameCompany%%sSectionNameProfile%
  2618. HKEY hKeyRoot, // = HKEY_CURRENT_USER
  2619. bool bExtents, // = true
  2620. bool bOrder, // = true
  2621. bool bSortOrder, // = true
  2622. bool bListViewMode // = true
  2623. )
  2624. {
  2625. ASSERT_VALID( this );
  2626. ASSERT( GetSafeHwnd() != NULL );
  2627. CExtSafeString sRegKeyPath =
  2628. productsection2regkeypath(
  2629. _T("CExtListCtrl"),
  2630. sSectionNameProfile,
  2631. sSectionNameCompany,
  2632. sSectionNameProduct
  2633. );
  2634. try
  2635. {
  2636. CMemFile _file;
  2637. CArchive ar( &_file, CArchive::store );
  2638. StateSerialize( ar, bExtents, bOrder, bSortOrder, bListViewMode );
  2639. ar.Flush();
  2640. ar.Close();
  2641. if( ! CExtCmdManager::FileObjToRegistry( _file, sRegKeyPath, hKeyRoot, false ) )
  2642. return false;
  2643. return true;
  2644. }
  2645. catch( CException * pXept )
  2646. {
  2647. pXept->Delete();
  2648. }
  2649. catch( ... )
  2650. {
  2651. }
  2652. return false;
  2653. }
  2654. INT CExtListCtrl::ColumnExtentGet( INT nColNo ) const
  2655. {
  2656. ASSERT_VALID( this );
  2657. ASSERT( GetSafeHwnd() != NULL );
  2658. const CExtHeaderCtrl & wndHeader = GetHeaderCtrl();
  2659. ASSERT( wndHeader.GetSafeHwnd() != NULL );
  2660. //#ifdef _DEBUG
  2661. //INT nColCount = INT( wndHeader.GetItemCount() );
  2662. // ASSERT( 0 <= nColNo && nColNo < nColCount );
  2663. //#endif // _DEBUG
  2664. INT nColCount = INT( wndHeader.GetItemCount() );
  2665. if( ! ( 0 <= nColNo && nColNo < nColCount ) )
  2666. return 120; // some default width
  2667. INT nExtent = CListCtrl::GetColumnWidth( nColNo );
  2668. return nExtent;
  2669. }
  2670. void CExtListCtrl::ColumnExtentSet( INT nColNo, INT nExtent )
  2671. {
  2672. ASSERT_VALID( this );
  2673. ASSERT( GetSafeHwnd() != NULL );
  2674. CExtHeaderCtrl & wndHeader = GetHeaderCtrl();
  2675. ASSERT( wndHeader.GetSafeHwnd() != NULL );
  2676. //#ifdef _DEBUG
  2677. //INT nColCount = INT( wndHeader.GetItemCount() );
  2678. // ASSERT( 0 <= nColNo && nColNo < nColCount );
  2679. //#endif // _DEBUG
  2680. INT nColCount = INT( wndHeader.GetItemCount() );
  2681. if( ! ( 0 <= nColNo && nColNo < nColCount ) )
  2682. return;
  2683. CListCtrl::SetColumnWidth( nColNo, nExtent );
  2684. }
  2685. void CExtListCtrl::ColumnAutoSize(
  2686. INT nColNo,
  2687. bool bAutoSizeByData, // = true,
  2688. bool bAutoSizeByHeader // = true
  2689. )
  2690. {
  2691. ASSERT_VALID( this );
  2692. if( ! ( bAutoSizeByData || bAutoSizeByHeader ) )
  2693. return;
  2694. if( GetSafeHwnd() == NULL )
  2695. return;
  2696. CExtHeaderCtrl & wndHeader = GetHeaderCtrl();
  2697. ASSERT( wndHeader.GetSafeHwnd() != NULL );
  2698. #ifdef _DEBUG
  2699. INT nColCount = INT( wndHeader.GetItemCount() );
  2700. ASSERT( 0 <= nColNo && nColNo < nColCount );
  2701. #endif // _DEBUG
  2702. SetRedraw( FALSE );
  2703. INT nInitialWidth = CListCtrl::GetColumnWidth( nColNo );
  2704. INT nResultWidth = 0;
  2705. if( bAutoSizeByHeader )
  2706. {
  2707. //CListCtrl::SetColumnWidth( nColNo, LVSCW_AUTOSIZE_USEHEADER );
  2708. //INT nWidth = CListCtrl::GetColumnWidth( nColNo );
  2709. INT nWidth = wndHeader.OnCalcHeaderItemSize( nColNo ).cx;
  2710. nResultWidth = max( nResultWidth, nWidth );
  2711. }
  2712. if( bAutoSizeByData )
  2713. {
  2714. CListCtrl::SetColumnWidth( nColNo, LVSCW_AUTOSIZE );
  2715. INT nWidth = CListCtrl::GetColumnWidth( nColNo ); 
  2716. nResultWidth = max( nResultWidth, nWidth );
  2717. }
  2718. if( nInitialWidth != nResultWidth )
  2719. CListCtrl::SetColumnWidth( nColNo, nResultWidth );
  2720. SetRedraw( TRUE );
  2721. if( nInitialWidth != nResultWidth )
  2722. Invalidate();
  2723. }
  2724. void CExtListCtrl::OnDestroy() 
  2725. {
  2726. CListCtrl::OnDestroy();
  2727. }
  2728. void CExtListCtrl::ModifyExtendedStyle( DWORD dwRemove, DWORD dwAdd )
  2729. {
  2730. LPARAM nStyleOld = (LPARAM) ::SendMessage( m_hWnd, LVM_GETEXTENDEDLISTVIEWSTYLE, 0, 0 );
  2731. LPARAM nStyleNew = nStyleOld;
  2732. nStyleNew &= ~( (LPARAM) dwRemove );
  2733. nStyleNew |= (LPARAM) dwAdd;
  2734. if( nStyleNew != nStyleOld )
  2735. ::SendMessage( m_hWnd, LVM_SETEXTENDEDLISTVIEWSTYLE, 0, nStyleNew );
  2736. }
  2737. int CExtListCtrl::OnCreate(LPCREATESTRUCT lpCreateStruct) 
  2738. {
  2739. if( CListCtrl::OnCreate( lpCreateStruct ) == -1 )
  2740. return -1;
  2741. //return _Init() ? 0 : -1;
  2742. PostMessage( (WM_USER+123) );
  2743. return 0;
  2744. }
  2745. void CExtListCtrl::PreSubclassWindow() 
  2746. {
  2747. CListCtrl::PreSubclassWindow();
  2748. PostMessage( (WM_USER+123) );
  2749. //_Init();
  2750. }
  2751. LRESULT CExtListCtrl::WindowProc(UINT message, WPARAM wParam, LPARAM lParam) 
  2752. {
  2753. HWND hWndOwn = GetSafeHwnd();
  2754. switch( message )
  2755. {
  2756. case (WM_USER+123):
  2757. _Init();
  2758. break;
  2759. case WM_ERASEBKGND:
  2760. return FALSE;
  2761. case WM_PAINT:
  2762. {
  2763. CPaintDC dcPaint( this );
  2764. CExtPaintManager::stat_ExcludeChildAreas(
  2765. dcPaint.GetSafeHdc(),
  2766. GetSafeHwnd()
  2767. );
  2768. CRect rcClient;
  2769. GetClientRect( &rcClient );
  2770. CExtMemoryDC dc( &dcPaint, &rcClient );
  2771. DefWindowProc(
  2772. WM_ERASEBKGND,
  2773. WPARAM( dc.GetSafeHdc() ),
  2774. LPARAM(0)
  2775. );
  2776. DefWindowProc(
  2777. WM_PAINT,
  2778. WPARAM( dc.GetSafeHdc() ),
  2779. LPARAM(0)
  2780. );
  2781. }
  2782. return TRUE;
  2783. case WM_KEYDOWN:
  2784. {
  2785. switch( wParam )
  2786. {
  2787. case VK_F2:
  2788. if( ( GetStyle() & LVS_EDITLABELS ) != 0
  2789. && ( ! ReadOnlyLabelsGet() )
  2790. )
  2791. {
  2792. int nItemIndex = FocusedItemGet();
  2793. if( nItemIndex >= 0 )
  2794. EditLabel( nItemIndex );
  2795. return 0L;
  2796. }
  2797. break;
  2798. case VK_APPS:
  2799. {
  2800. CRect rcItem;
  2801. int nItemFocused = FocusedItemGet();
  2802. if( nItemFocused < 0 )
  2803. return 0L;
  2804. EnsureVisible( nItemFocused, TRUE );
  2805. GetItemRect( nItemFocused, &rcItem, TRUE );
  2806. CPoint ptScreen = rcItem.CenterPoint();
  2807. ClientToScreen( &ptScreen );
  2808. SendMessage( WM_CONTEXTMENU, WPARAM(m_hWnd), MAKELPARAM(ptScreen.x, ptScreen.y) );
  2809. }
  2810. break;
  2811. case VK_TAB:
  2812. if( ( GetStyle() & WS_TABSTOP ) != 0 )
  2813. {
  2814. GetParent()->SendMessage(
  2815. WM_NEXTDLGCTL,
  2816. CExtPopupMenuWnd::IsKeyPressed(VK_SHIFT) ? 1 : 0,
  2817. 0
  2818. );
  2819. return 0L;
  2820. }
  2821. break;
  2822. } // switch( wParam )
  2823. }
  2824. break;
  2825. default:
  2826. if( message == CExtHeaderCtrl::g_nMsgHeaderButtonClick )
  2827. return GetParent()->SendMessage( CExtHeaderCtrl::g_nMsgHeaderButtonClick, wParam, lParam );
  2828. break;
  2829. } // switch( message )
  2830. LRESULT lResult = CListCtrl::WindowProc(message , wParam, lParam );
  2831. switch( message )
  2832. {
  2833. case WM_GETDLGCODE:
  2834. lResult |= DLGC_WANTMESSAGE;
  2835. break;
  2836. case WM_KEYDOWN:
  2837. switch( wParam )
  2838. {
  2839. case VK_RETURN:
  2840. case VK_ESCAPE:
  2841. if( (!( CExtPopupMenuWnd::IsKeyPressed( VK_MENU )
  2842. || CExtPopupMenuWnd::IsKeyPressed( VK_CONTROL )
  2843. || CExtPopupMenuWnd::IsKeyPressed( VK_SHIFT )
  2844. ))
  2845. && ::IsWindow( hWndOwn )
  2846. && IsWindowEnabled()
  2847. && ( GetStyle() & WS_VISIBLE ) != 0
  2848. )
  2849. {
  2850. UINT nCmdID = ( wParam == VK_RETURN ) ? IDOK : IDCANCEL;
  2851. bool bSendOkCancel = true;
  2852. CWnd * pWndParent = GetParent();
  2853. for( ; pWndParent != NULL
  2854. && ( pWndParent->GetStyle() & WS_CHILD ) != 0
  2855. ;
  2856. )
  2857. {
  2858. if( ( ! pWndParent->IsWindowEnabled() )
  2859. || ( pWndParent->GetStyle() & WS_VISIBLE ) == 0
  2860. )
  2861. {
  2862. bSendOkCancel = false;
  2863. break;
  2864. }
  2865. pWndParent = pWndParent->GetParent();
  2866. }
  2867. if( bSendOkCancel && pWndParent != NULL )
  2868. {
  2869. CWnd * pWndOkCancel = pWndParent->GetDlgItem( nCmdID );
  2870. if( pWndOkCancel != NULL
  2871. && ( (! pWndOkCancel->IsWindowEnabled() )
  2872. || ( pWndOkCancel->GetStyle() & WS_VISIBLE ) == 0
  2873. )
  2874. )
  2875. bSendOkCancel = false;
  2876. else if( ( pWndParent->GetStyle() & WS_CHILD ) == 0 )
  2877. {
  2878. MENUITEMINFO _mii;
  2879. ::memset( &_mii, 0, sizeof(MENUITEMINFO) );
  2880. _mii.cbSize = sizeof(MENUITEMINFO);
  2881. _mii.fMask = MIIM_STATE;
  2882. CMenu * pMenu = pWndParent->GetSystemMenu( FALSE );
  2883. if( pMenu->GetSafeHmenu() != NULL
  2884. && pMenu->GetMenuItemInfo( SC_CLOSE, &_mii, FALSE )
  2885. && ( _mii.fState & ( MF_DISABLED | MF_GRAYED ) ) != 0
  2886. )
  2887. bSendOkCancel = false;
  2888. } // else if( ( pWndParent->GetStyle() & WS_CHILD ) == 0 )
  2889. } // if( bSendOkCancel && pWndParent != NULL )
  2890. if( bSendOkCancel )
  2891. pWndParent->SendMessage( WM_COMMAND, WPARAM(nCmdID) );
  2892. }
  2893. break;
  2894. } // switch( wParam )
  2895. break;
  2896. case WM_HSCROLL:
  2897. {
  2898. CExtHeaderCtrl & wndHeader = GetHeaderCtrl();
  2899. if( wndHeader.GetSafeHwnd() != NULL
  2900. && ( wndHeader.GetStyle() & WS_VISIBLE ) != 0
  2901. )
  2902. {
  2903. wndHeader.Invalidate();
  2904. wndHeader.UpdateWindow();
  2905. }
  2906. }
  2907. break;
  2908. } // switch( message )
  2909. return lResult;
  2910. }
  2911. bool CExtListCtrl::_Init()
  2912. {
  2913. CExtHeaderCtrl & wndHeader = m_wndHeaderCtrl; // GetHeaderCtrl();
  2914. if( wndHeader.GetSafeHwnd() != NULL )
  2915. return true;
  2916. if( ! wndHeader.SubclassWindow( GetDlgItem(0)->GetSafeHwnd()) )
  2917. return false;
  2918. return true;
  2919. }
  2920. void CExtListCtrl::OnWindowPosChanging(WINDOWPOS FAR* lpwndpos) 
  2921. {
  2922. CListCtrl::OnWindowPosChanging(lpwndpos);
  2923. Invalidate(FALSE);
  2924. }
  2925. void CExtListCtrl::OnDeleteItem( NMHDR * pNMHDR, LRESULT * pResult ) 
  2926. {
  2927. pNMHDR;
  2928. //NM_LISTVIEW * pNMListView = (NM_LISTVIEW *)pNMHDR;
  2929. (*pResult) = 0;
  2930. }
  2931. void CExtListCtrl::OnDeleteAllItems( NMHDR * pNMHDR, LRESULT * pResult ) 
  2932. {
  2933. pNMHDR;
  2934. //NM_LISTVIEW * pNMListView = (NM_LISTVIEW *)pNMHDR;
  2935. (*pResult) = 0;
  2936. }
  2937. bool CExtListCtrl::ReadOnlyLabelsGet() const
  2938. {
  2939. ASSERT_VALID( this );
  2940. return m_bReadOnlyLabels;
  2941. }
  2942. void CExtListCtrl::ReadOnlyLabelsSet( bool bReadOnlyLabels )
  2943. {
  2944. ASSERT_VALID( this );
  2945. m_bReadOnlyLabels = bReadOnlyLabels;
  2946. }
  2947. void CExtListCtrl::OnBeginLabelEdit( NMHDR * pNMHDR, LRESULT * pResult )
  2948. {
  2949. pNMHDR;
  2950. //NMLVDISPINFO * pNMDI = (NMLVDISPINFO*)pNMHDR;
  2951. (*pResult) = 0;
  2952. if( ReadOnlyLabelsGet() )
  2953. {
  2954. CEdit * pEdit = GetEditControl();
  2955. if( pEdit->GetSafeHwnd() != NULL )
  2956. pEdit->SetReadOnly( TRUE );
  2957. }
  2958. }
  2959. void CExtListCtrl::SelectedItemsListGet(
  2960. CList < INT, INT > & _listSelectedItems,
  2961. bool bAddToTail // = true
  2962. ) const
  2963. {
  2964. ASSERT_VALID( this );
  2965. _listSelectedItems.RemoveAll();
  2966. if( GetSafeHwnd() == NULL )
  2967. return;
  2968. POSITION pos = GetFirstSelectedItemPosition();
  2969. for( ; pos != NULL; )
  2970. {
  2971. INT nItemIndex = GetNextSelectedItem( pos );
  2972. if( bAddToTail )
  2973. _listSelectedItems.AddTail( nItemIndex );
  2974. else
  2975. _listSelectedItems.AddHead( nItemIndex );
  2976. }
  2977. }
  2978. void CExtListCtrl::SelectedItemsListSet(
  2979. const CList < INT, INT > & _listSelectedItems
  2980. )
  2981. {
  2982. ASSERT_VALID( this );
  2983. if( GetSafeHwnd() == NULL )
  2984. return;
  2985. INT nItemIndex, nItemCount = GetItemCount();
  2986. if( nItemCount <= 0 )
  2987. return;
  2988. CList < INT, INT > _listSelectedItems2;
  2989. _listSelectedItems2.AddTail( const_cast < CList < INT, INT > * > ( &_listSelectedItems ) );
  2990. for( nItemIndex = 0; nItemIndex < nItemCount; nItemIndex ++ )
  2991. {
  2992. POSITION pos = _listSelectedItems2.Find( nItemIndex );
  2993. SetItemState( nItemIndex, ( pos != NULL ) ? LVIS_SELECTED : 0, LVIS_SELECTED );
  2994. if( pos != NULL )
  2995. _listSelectedItems2.RemoveAt( pos );
  2996. }
  2997. }
  2998. bool CExtListCtrl::IsItemSelected(
  2999. INT nItemIndex
  3000. ) const
  3001. {
  3002. ASSERT_VALID( this );
  3003. if( nItemIndex < 0 )
  3004. return false;
  3005. if( GetSafeHwnd() == NULL )
  3006. return false;
  3007. INT nItemCount = INT( GetItemCount() );
  3008. if( nItemIndex >= nItemCount )
  3009. return false;
  3010. bool bSelected = ( GetItemState( nItemIndex, LVIS_SELECTED ) != 0 ) ? true : false;
  3011. return bSelected;
  3012. }
  3013. void CExtListCtrl::SelectItem(
  3014. INT nItemIndex,
  3015. bool bSelect // = true
  3016. )
  3017. {
  3018. ASSERT_VALID( this );
  3019. if( nItemIndex < 0 )
  3020. return;
  3021. if( GetSafeHwnd() == NULL )
  3022. return;
  3023. INT nItemCount = INT( GetItemCount() );
  3024. if( nItemIndex >= nItemCount )
  3025. return;
  3026. bool bSelected = ( GetItemState( nItemIndex, LVIS_SELECTED ) != 0 ) ? true : false;
  3027. if( ( bSelected && bSelect ) || ( (!bSelected) && (!bSelect) ) )
  3028. return;
  3029. SetItemState( nItemIndex, bSelect ? LVIS_SELECTED : 0, LVIS_SELECTED );
  3030. }
  3031. INT CExtListCtrl::FocusedItemGet() const
  3032. {
  3033. ASSERT_VALID( this );
  3034. if( GetSafeHwnd() == NULL )
  3035. return -1;
  3036. INT nItemIndex = GetNextItem( -1, LVNI_FOCUSED );
  3037. return nItemIndex;
  3038. }
  3039. INT CExtListCtrl::FocusedItemSet( // returns previous focused item index
  3040. INT nItemIndex,
  3041. bool bSelectFocusedItem, // = true
  3042. bool bUnselectOtherItems // = true
  3043. )
  3044. {
  3045. ASSERT_VALID( this );
  3046. if( GetSafeHwnd() == NULL )
  3047. return -1;
  3048. INT nPrevFocusedItemIndex = GetNextItem( -1, LVNI_FOCUSED );
  3049. if( nItemIndex < 0 )
  3050. return nPrevFocusedItemIndex;
  3051. INT nItemCount = INT( GetItemCount() );
  3052. if( nItemIndex >= nItemCount )
  3053. return nPrevFocusedItemIndex;
  3054. if( nPrevFocusedItemIndex == nItemIndex
  3055. && ( ! ( bSelectFocusedItem || bUnselectOtherItems ) )
  3056. )
  3057. return nPrevFocusedItemIndex;
  3058. if( bUnselectOtherItems )
  3059. {
  3060. INT nWalkIndex;
  3061. for( nWalkIndex = 0; nWalkIndex < nItemCount; nWalkIndex ++ )
  3062. {
  3063. if( bSelectFocusedItem && nWalkIndex == nItemIndex )
  3064. SetItemState( nWalkIndex, LVIS_SELECTED, LVIS_SELECTED );
  3065. else
  3066. SetItemState( nWalkIndex, 0, LVIS_SELECTED );
  3067. }
  3068. }
  3069. else if( bSelectFocusedItem )
  3070. SetItemState( nItemIndex, LVIS_SELECTED, LVIS_SELECTED );
  3071. SetItemState( nItemIndex, LVIS_FOCUSED, LVIS_FOCUSED );
  3072. return nPrevFocusedItemIndex;
  3073. }
  3074. void CExtListCtrl::OnBeginDrag( NMHDR * pNMHDR, LRESULT * pResult ) 
  3075. {
  3076. ASSERT_VALID( this );
  3077. pNMHDR;
  3078. //HD_NOTIFY * phdn = (HD_NOTIFY *) pNMHDR;
  3079. *pResult = 0;
  3080. }
  3081. void CExtListCtrl::OnEndDrag( NMHDR * pNMHDR, LRESULT * pResult ) 
  3082. {
  3083. ASSERT_VALID( this );
  3084. pNMHDR;
  3085. //HD_NOTIFY * phdn = (HD_NOTIFY *) pNMHDR;
  3086. *pResult = 0;
  3087. Invalidate();
  3088. UpdateWindow();
  3089. }
  3090. CExtNCSB < CExtListCtrl > :: CExtNCSB(
  3091. bool bNcsbDelayedInitialization, // = false
  3092. bool bNcsbForceMiddleContainerMode // = false
  3093. )
  3094. : CExtNCSB_Impl < CExtListCtrl > (
  3095. bNcsbDelayedInitialization,
  3096. bNcsbForceMiddleContainerMode
  3097. )
  3098. {
  3099. }
  3100. CExtNCSB < CExtListCtrl > :: ~CExtNCSB()
  3101. {
  3102. }
  3103. void CExtNCSB < CExtListCtrl > :: AdjustScrollMetrics()
  3104. {
  3105. ASSERT_VALID( this );
  3106. if( GetSafeHwnd() == NULL )
  3107. return;
  3108. DWORD dwType = DWORD( GetStyle() & LVS_TYPEMASK );
  3109. CExtNCSB_ScrollContainer * pWndH = NCSB_GetContainer( CExtNCSB_ScrollContainer::__EM_HORIZONTAL_SCROLL_BAR );
  3110. CExtNCSB_ScrollContainer * pWndV = NCSB_GetContainer( CExtNCSB_ScrollContainer::__EM_VERTICAL_SCROLL_BAR );
  3111. CExtScrollBar * pSBH = ( pWndH != NULL ) ? pWndH->GetScrollBarInContainer() : NULL;
  3112. CExtScrollBar * pSBV = ( pWndV != NULL ) ? pWndV->GetScrollBarInContainer() : NULL;
  3113. INT m_nStepSizeH = -1, m_nStepSizeV = -1;
  3114. switch( dwType )
  3115. {
  3116. case LVS_ICON:
  3117. m_nStepSizeV = 64;
  3118. break;
  3119. case LVS_SMALLICON:
  3120. case LVS_LIST:
  3121. m_nStepSizeV = 16;
  3122. break;
  3123. case LVS_REPORT:
  3124. m_nStepSizeV = 1;
  3125. break;
  3126. } // switch( dwType )
  3127. if( m_nStepSizeH > 0 && pSBH != NULL )
  3128. pSBH->m_nStepSize = m_nStepSizeH;
  3129. if( m_nStepSizeV > 0 && pSBV != NULL )
  3130. pSBV->m_nStepSize = m_nStepSizeV;
  3131. }
  3132. LRESULT CExtNCSB < CExtListCtrl > :: WindowProc( UINT message, WPARAM wParam, LPARAM lParam )
  3133. {
  3134. switch( message )
  3135. {
  3136. case WM_HSCROLL:
  3137. {
  3138. UINT nSBCode = UINT(LOWORD(DWORD(wParam))), nPos = UINT(HIWORD(DWORD(wParam)));
  3139. //TRACE2( "WM_HSCROLL, nSBCode = %d, nPos = %drn", nSBCode, nPos );
  3140. INT nItemExtent = 1;
  3141. DWORD dwStyle = GetStyle();
  3142. DWORD dwListCtrlType = dwStyle&LVS_TYPEMASK;
  3143. switch( dwListCtrlType )