Professional UI Solutions
Site Map   /  Register
 
 

Forum

Please Log In to post a new message or reply to an existing one. If you are not registered, please register.

NOTE: Some forums may be read-only if you are not currently subscribed to our technical support services.

Forums » Prof-UIS Tech Support » Problem with CExtTreeCtrl Collapse All
Subject Author Date
Lars Mohr Apr 30, 2009 - 9:12 AM

Hello Support Team!


The select status of an item is changed with a left-button-up message, but is there a delay of > 2 sec between down and up message the select status change doesn’t work. You can see this with Prof-UIS Controls sample, too.


 


Regards

Technical Support Apr 30, 2009 - 10:01 AM

Thank you for reporting us this issue. To fix it please update the source code for the following two methods:

bool CExtTreeCtrl::OnTreeMouseClick(
	HTREEITEM hti,
	DWORD dwHitTestFlags,
	int nMouseButton,
	int nClick,
	UINT nMouseEventFlags,
	CPoint point
	)
{
	ASSERT_VALID( this );
	if( hti == NULL )
		return false;
	switch( nMouseButton )
	{
	case VK_LBUTTON:
	{
		DWORD dwTreeStyle = TreeGetStyle();
		bool bMultiSelection       = ( ( dwTreeStyle & __EXT_TREE_MULTIPLE_SELECTION ) != 0 ) ? true : false;
		bool bSelectDisabledItems  = ( ( dwTreeStyle & __EXT_TREE_SELECT_DISABLE_ITEMS ) != 0 ) ? true : false;
		bool bFocusDisabledItems   = ( ( dwTreeStyle & __EXT_TREE_FOCUS_DISABLE_ITEMS ) != 0 ) ? true : false;
		bool bSelectCollapsedItems = ( ( dwTreeStyle & __EXT_TREE_SELECT_COLLAPSED_ITEMS ) != 0 ) ? true : false;
		bool bSubtractSelection    = ( ( dwTreeStyle & __EXT_TREE_SUBTRACT_SELECTION ) != 0 ) ? true : false;
		bool bSingleExpand         = ( ( GetStyle() & TVS_SINGLEEXPAND ) != 0 ) ? true : false;
		bool bEditLabels		   = ( ( GetStyle() & TVS_EDITLABELS ) != 0 ) ? true : false;
		bool bItemIsEnabled        = OnQueryItemEnabledState( hti );
		static HTREEITEM g_htiLastLButtonDownItem = NULL;
		switch( nClick )
		{
		case 0:
			g_htiLastLButtonDownItem = hti;
			// continue falling after drag detection ...
		case 1:
		{
			if( ::GetFocus() != m_hWnd )
				SetFocus();
			if( g_htiLastLButtonDownItem != hti )
				return true;
			if( ( dwHitTestFlags & __EXT_TVHT_ONCONTROL ) != 0 )
			{
				CRect rcControl;
				VERIFY( TreeItemRectGet( hti, rcControl, e_tirt_control ) );
				ASSERT( ! rcControl.IsRectEmpty() );
				if( m_hWndChildControl != NULL )
				{
					CRect rc;
					::GetWindowRect( m_hWndChildControl, &rc );
					if( rc == rcControl )
						return true;
					SendMessage( WM_CANCELMODE );
				}
				m_hWndChildControl = OnInplaceControlCreate( hti, rcControl );
				if( m_hWndChildControl != NULL )
					m_htiInplaceEdited = hti;
				return true;
			}
			if( ( dwHitTestFlags & __EXT_TVHT_ONITEMBUTTON ) != 0 )
			{
				//if( ( nMouseEventFlags & (MK_CONTROL|MK_SHIFT) ) != 0 )
				//	return true;
				HTREEITEM htiFocus = GetFocusedItem();
				if( htiFocus != NULL )
				{
					if(		TreeItemIsExpanded( hti )
						&&	HasAncestor( hti, htiFocus )
						)
					{
						if(		( ! bFocusDisabledItems )
							&&	( ! bItemIsEnabled )
							)
							FocusItem( NULL, false, false );
						else
							FocusItem( hti, bSelectDisabledItems || bItemIsEnabled, true );
					}
				}
				SendMessage( WM_CANCELMODE );
				Expand( hti, TVE_TOGGLE );
				Invalidate();
				return true;
			}
			DWORD dwSelectionAreaFlags =
				__EXT_TVHT_ONITEMICON|__EXT_TVHT_ONITEMLABEL
				|__EXT_TVHT_ONCONTROL|__EXT_TVHT_ONCHECKBOX;
			bool bFullRowSelection = ( ( GetStyle() & TVS_FULLROWSELECT ) != 0 ) ? true : false;
			if( bFullRowSelection )
				dwSelectionAreaFlags |= __EXT_TVHT_ONITEMINDENT|__EXT_TVHT_ONITEMRIGHT;
			if(		( dwHitTestFlags & dwSelectionAreaFlags ) != 0
				&&	( bFocusDisabledItems || bItemIsEnabled )
				)
			{
				TREEITEMINFO_t & _TII = TreeItemInfoGet( hti );
				
				if(		bEditLabels
					&&	(hti == GetFocusedItem())
					&&	(	bFullRowSelection
						||	( dwHitTestFlags & __EXT_TVHT_ONITEMLABEL ) != 0
						)
					)
				{
					if(		(	m_hWndChildControl == NULL
							||	( ! ::IsWindow( m_hWndChildControl ) )
							)
						&&	::GetFocus() == m_hWnd
						&&	m_nLastMouseButtonEventType[0] == 0 // if WM_LBUTTONUP after WM_LBUTTONDOWN, i.e. if not after WM_LBUTTONDBLCLK
						)
					{
						KillTimer( m_nDelayedEditingTimerID );
						m_wndContentExpand.Deactivate();
						SetTimer( m_nDelayedEditingTimerID, ::GetDoubleClickTime() + 1 , NULL );
					}
					return true;
				}
				
				if( OnQueryItemEnabledState( hti ) )
				{
					switch( _TII.m_eCheckBoxType )
					{
					case e_cbt_check_box:
						switch( _TII.m_nCheckBoxState )
						{
						case 0:
							_TII.m_nCheckBoxState = 1;
							break;
						case 1:
							_TII.m_nCheckBoxState = 0;
							break;
						}
					break;
					case e_cbt_tri_state_check_box:
						switch( _TII.m_nCheckBoxState )
						{
						case 0:
							_TII.m_nCheckBoxState = 1;
							break;
						case 1:
							_TII.m_nCheckBoxState = 2;
							break;
						case 2:
							_TII.m_nCheckBoxState = 0;
							break;
						}
					break;
					case e_cbt_radio:
						_CheckRadioBox( hti );
					break;
					} // switch( _TII.m_eCheckBoxType )
				} // if( OnQueryItemEnabledState( hti ) )
				HTREEITEM htiFocus = GetFocusedItem();
				if(		bSingleExpand
					&&	htiFocus == hti
					&&	( nMouseEventFlags & (MK_CONTROL|MK_SHIFT) ) == 0
					)
				{
					SendMessage( WM_CANCELMODE );
					Expand( hti, TVE_TOGGLE );
					Invalidate();
					return true;
				}
				bool bSelectFocusedFinally = true;
				if(		bSubtractSelection
					&&	( nMouseEventFlags & (MK_CONTROL|MK_SHIFT) ) == MK_CONTROL
					)
				{
					AnchorItemSet( hti );
					SendMessage( WM_CANCELMODE );
					SelectItem( hti, !IsItemSelected( hti ), IsItemSelected( hti ) );
					FocusItem( hti );
					Invalidate();
					if( m_wndContentExpand.GetSafeHwnd() != NULL )
						m_wndContentExpand.Invalidate();
					return true;
				}
				HTREEITEM htiAnchor = AnchorItemGet();
				if( ( nMouseEventFlags & (MK_CONTROL|MK_SHIFT) ) != MK_SHIFT )
					AnchorItemSet( hti );
				if( htiFocus != NULL )
				{
					if(		bMultiSelection
						&&	( nMouseEventFlags & MK_SHIFT ) == MK_SHIFT
						)
					{
						if( bSubtractSelection && htiAnchor != NULL )
							SelectItemRange( htiAnchor, htiFocus, false, !bSelectCollapsedItems, bSelectDisabledItems );
						SelectItemRange( hti, htiAnchor, true, !bSelectCollapsedItems, bSelectDisabledItems );
					}
				}
				bool bUnselectOtherItems =
					(
						( ! bMultiSelection )
					||	( ( nMouseEventFlags & (MK_CONTROL|MK_SHIFT) ) == 0 )
					)
					? true : false;
				SendMessage( WM_CANCELMODE );
				if( ( ! bSelectDisabledItems ) && ( ! bItemIsEnabled ) )
					bSelectFocusedFinally = false;
				if( ! bSelectFocusedFinally )
					SelectItem( hti, false );
				FocusItem( hti, bSelectFocusedFinally, bUnselectOtherItems, true );
				Invalidate();
				if( m_wndContentExpand.GetSafeHwnd() != NULL )
					m_wndContentExpand.Invalidate();
				if( nClick == 0 && OnTreeItemDoDragDetect( hti, dwHitTestFlags, nMouseButton, nClick, nMouseEventFlags, point ) )
				{
					g_htiLastLButtonDownItem = NULL;
					return true;
				}
				return true;
			}
		}
		break;
		case 2:
			g_htiLastLButtonDownItem = NULL;
			if(		( dwHitTestFlags & (__EXT_TVHT_ONITEMICON|__EXT_TVHT_ONITEMLABEL) ) != 0
				&&	( bFocusDisabledItems || bItemIsEnabled )
				&&	! bSingleExpand
				)
			{
				if( ::GetFocus() != m_hWnd )
					SetFocus();
				SendMessage( WM_CANCELMODE );
				if( ItemHasChildren( hti ) )
					Expand( hti, TVE_TOGGLE );

				Invalidate();
				return true;
			}
		break;
		} // switch( nClick )
	}
	return true; // case VK_LBUTTON
	case VK_RBUTTON:
	{
		if( ::GetFocus() != m_hWnd )
			SetFocus();
		switch( nClick )
		{
		case 0:
			if( OnTreeItemDoDragDetect( hti, dwHitTestFlags, nMouseButton, nClick, nMouseEventFlags, point ) )
				return true;
			// continue falling after drag detection ...
		case 1:
		{
			CPoint ptScreen = point;
			ClientToScreen( &ptScreen );
			SendMessage( WM_CONTEXTMENU, WPARAM(m_hWnd), MAKELPARAM(ptScreen.x,ptScreen.y) );
		}
		return true;
		} // switch( nClick )
	}
	break; // case VK_RBUTTON
	default:
		switch( nClick )
		{
		case 0:
			if( OnTreeItemDoDragDetect( hti, dwHitTestFlags, nMouseButton, nClick, nMouseEventFlags, point ) )
				return true;
			// continue falling after drag detection ...
		} // switch( nClick )
	break;
	} // switch( nMouseButton )
	return false;
}

bool CExtControlBar::stat_DoDragDetect(
	HWND hWnd,
	const POINT & ptWndClient
	)
{
	if( hWnd == NULL || (! ::IsWindow( hWnd ) ) )
		return false;
CPoint ptScreen = ptWndClient;
	::ClientToScreen( hWnd, &ptScreen );
	while( ::DragDetect( hWnd, ptScreen ) )
	{
		POINT ptCursorPos = { -32767, -32767 };
		if( ! ::GetCursorPos( &ptCursorPos ) )
			return false;
		if(  ptScreen == ptCursorPos )
			continue; //only drag time elapsed but mouse is not moved
		return true;
	}
	return false;
}

Technical Support Apr 30, 2009 - 9:21 AM

This message is related to the first issue only. You described situation when the page size is changed during scrolling. We improved this situation handling in the CExtScrollBar class. Please update the source code for the following method:

void CExtScrollBar::ScrollBar_TrackMouseLButtonDown( MSG * pMSG )
{
	ASSERT_VALID( this );
	if( ! m_bCompleteRepaint )
		return;
CPoint point( short(LOWORD(DWORD(pMSG->lParam))), short(HIWORD(DWORD(pMSG->lParam))) );
CExtPopupMenuTipWnd * pATTW = OnAdvancedPopupMenuTipWndGet();
CExtPaintManager::PAINTSCROLLBARDATA _psbd( this );
	_psbd.AdjustHT( point );
	if( (! m_bProcessingHover) || m_bProcessingClick || (! _psbd.m_bEnabled ) || _psbd.m_eSBMHT == CExtPaintManager::__ESBMHT_NOWHERE )
	{
		if( _psbd.m_eSBMHT == CExtPaintManager::__ESBMHT_NOWHERE || (! _psbd.m_bEnabled ) )
		{
			if( pATTW != NULL )
				pATTW->Hide();
			SendMessage( WM_CANCELMODE );
			Invalidate();
			UpdateWindow();
			return;
		}
	}
	if( ! m_bPopupInactiveLightMode )
		ActivateTopParent();
bool bAnimationLocked = AnimationClient_CacheGeneratorIsLocked();
	if( ! bAnimationLocked )
	{
		AnimationClient_CacheGeneratorLock();
		AnimationClient_CacheNextStateMinInfo( false, __EAPT_BY_PRESSED_STATE_TURNED_ON );
	}
	if( m_bEnableHookSpy )
		HookSpyUnregister();
	m_nSBMHT = INT(_psbd.m_eSBMHT);
	m_bProcessingClick = m_bProcessingHover = true;
	m_bProcessingOutClick = false;
	if( ! bAnimationLocked )
	{
 		AnimationClient_CacheNextStateMinInfo( true, __EAPT_BY_PRESSED_STATE_TURNED_ON );
		AnimationClient_CacheGeneratorUnlock();
	}
	Invalidate();
	UpdateWindow();
	if( pATTW != NULL )
		OnAdvancedPopupMenuTipWndDisplay( *pATTW, m_nSBMHT, true );
INT nScrollPosStart = _psbd.m_DSI.nPos, nScrollPos = _psbd.m_DSI.nPos;
	m_nHelperTrackPos = _psbd.m_DSI.nPos;
	m_bHelperHaveTrackPos = true;
CRect rcArea = _psbd.GetAreaRectHT();
const UINT nTimerID_zero_start = 401;
const UINT nTimerID_1st_slow = 402;
const UINT nTimerEllapse_1st_slow = 400;
const UINT nTimerID_2nd_fast = 403;
const UINT nTimerEllapse_2nd_fast = 100;
HWND hWndOwn = GetSafeHwnd();
	ASSERT( hWndOwn != NULL && ::IsWindow( hWndOwn ) );
HWND hWndParent = ::GetParent( hWndOwn );
bool bVirtualMode = false, bFinalNotify = true;
#if (!defined __EXT_MFC_NO_SCROLLWND)
CExtScrollWnd * pExtScrollWnd = NULL;
	if( hWndParent != NULL )
	{
		CWnd * pWndParentPermanent = CWnd::FromHandlePermanent( hWndParent );
		if( pWndParentPermanent != NULL )
		{
			pExtScrollWnd = DYNAMIC_DOWNCAST( CExtScrollWnd, pWndParentPermanent );
#if (!defined __EXT_MFC_NO_SCROLLITEMWND)
			if( pExtScrollWnd != NULL )
			{
				CExtScrollItemWnd * pExtScrollItemWnd = DYNAMIC_DOWNCAST( CExtScrollItemWnd, pWndParentPermanent );
				if( pExtScrollItemWnd != NULL )
				{
					DWORD dwScrollType = __ESIW_ST_NONE;
					if( _psbd.m_bHorzBar )
						dwScrollType = pExtScrollItemWnd->SiwScrollTypeHGet();
					else
						dwScrollType = pExtScrollItemWnd->SiwScrollTypeVGet();
					if( dwScrollType == __ESIW_ST_VIRTUAL )
						bVirtualMode = true;
				}
			}
#endif
		}
	}
#endif
bool bStopFlag = false;
CPoint ptCursor( point );
INT nStepSize = 0L;
bool bUpStep = false;
bool bMouseButtonsNotSwapped = ( ::GetSystemMetrics( SM_SWAPBUTTON ) != 0 ) ? false : true;
	switch( _psbd.m_eSBMHT )
	{
	case CExtPaintManager::__ESBMHT_BUTTON_UP:
		bUpStep = true;
		// continue falling here ...
	case CExtPaintManager::__ESBMHT_BUTTON_DOWN:
		nStepSize = GetStepSize();
#if (!defined __EXT_MFC_NO_SCROLLWND)
		if( pExtScrollWnd != NULL )
		{
			int nDir = ( _psbd.m_eSBMHT == CExtPaintManager::__ESBMHT_BUTTON_DOWN ) ? (+1) : (-1);
			CSize _size = pExtScrollWnd->OnSwGetLineSize( nDir );
			nStepSize = _psbd.m_bHorzBar ? _size.cx : _size.cy;
			if( nStepSize <= 0L )
				nStepSize = GetStepSize();
		}
#endif
		break;
	case CExtPaintManager::__ESBMHT_PAGE_UP:
		bUpStep = true;
		// continue falling here ...
	case CExtPaintManager::__ESBMHT_PAGE_DOWN:
		nStepSize = (INT)_psbd.m_DSI.nPage;
#if (!defined __EXT_MFC_NO_SCROLLWND)
		if( pExtScrollWnd != NULL )
		{
			int nDir = ( _psbd.m_eSBMHT == CExtPaintManager::__ESBMHT_PAGE_DOWN ) ? (+1) : (-1);
			CSize _size = pExtScrollWnd->OnSwGetPageSize( nDir );
			nStepSize = _psbd.m_bHorzBar ? _size.cx : _size.cy;
		}
#endif
		if( nStepSize <= 0L )
			nStepSize = GetStepSize();
		break;
	case CExtPaintManager::__ESBMHT_THUMB:
		break;
	}
bool bMenuMode = false;
	if( CExtPopupMenuWnd::IsMenuTracking() )
	{
		CWnd * pWnd = GetParent();
		for( ; pWnd != NULL; pWnd = pWnd->GetParent() )
		{
			if( pWnd->IsKindOf( RUNTIME_CLASS(CExtPopupMenuWnd) ) )
			{
				bMenuMode = true;
				break;
			}
			if( (pWnd->GetStyle()&WS_CHILD) == 0 )
				break;
		}
	}
INT nMx = INT( _psbd.m_DSI.nMax - _psbd.m_DSI.nPage + 1 );
INT nScrollLimit = _psbd.m_DSI.nMax - _psbd.m_DSI.nMin - _psbd.m_DSI.nPage + 1;
	ASSERT( nScrollLimit >= 0 );
	if( nStepSize > nScrollLimit )
		nStepSize = nScrollLimit;
CRect rcScrollable = _psbd.m_rcBar;
	if( _psbd.m_bHorzBar )
	{
		rcScrollable.left = _psbd.m_rcButtonUp.right;
		rcScrollable.right = _psbd.m_rcButtonDown.left;
	}
	else
	{
		rcScrollable.top = _psbd.m_rcButtonUp.bottom;
		rcScrollable.bottom = _psbd.m_rcButtonDown.top;
	}
	ScrollBar_CaptureSet();
	if( nStepSize != 0L )
		::PostMessage( hWndOwn, WM_TIMER, WPARAM(nTimerID_zero_start), LPARAM(0L) );
	for( MSG msg; ::IsWindow( hWndOwn ) && (!bStopFlag); )
	{
		if( ! PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE) )
		{
			if( ! ::IsWindow( hWndOwn ) )
				break;
			::WaitMessage();
			continue;
		}
		bool bAnalyzeThumb = false;
		switch( msg.message )
		{
		case WM_LBUTTONDBLCLK:
		case WM_LBUTTONUP:
		case WM_RBUTTONDBLCLK:
		case WM_RBUTTONDOWN:
		case WM_RBUTTONUP:
		case WM_MBUTTONDBLCLK:
		case WM_MBUTTONDOWN:
		case WM_MBUTTONUP:
		case WM_CANCELMODE:
		case WM_ACTIVATEAPP:
		case WM_KEYDOWN:
		case WM_KEYUP:
			bStopFlag = true;
		break;
		case WM_CAPTURECHANGED:
			if( (HWND)msg.wParam != hWndOwn )
				bStopFlag = true;
		break;
		case WM_MOUSEMOVE:
			if( m_nSBMHT == INT(CExtPaintManager::__ESBMHT_THUMB) )
			{
				if(		( ! CExtPopupMenuWnd::IsKeyPressed( bMouseButtonsNotSwapped ? VK_LBUTTON : VK_RBUTTON,true) )
					||	CExtPopupMenuWnd::IsKeyPressed( VK_MBUTTON )
					||	CExtPopupMenuWnd::IsKeyPressed( bMouseButtonsNotSwapped ?  VK_RBUTTON : VK_LBUTTON,true )
					||	( (!bMenuMode) && CExtPopupMenuWnd::IsMenuTracking() )
					)
				{
					bStopFlag = true;
					break;
				}
				PeekMessage(&msg,NULL,msg.message,msg.message,PM_REMOVE);
				bAnalyzeThumb = true;
				::GetCursorPos( &ptCursor );
				::ScreenToClient( hWndOwn, &ptCursor );
				break;
			}
			if( nStepSize == 0 )
				break;
		case WM_TIMER:
			{
				if(		( ! CExtPopupMenuWnd::IsKeyPressed( bMouseButtonsNotSwapped ? VK_LBUTTON : VK_RBUTTON,true) )
					||	CExtPopupMenuWnd::IsKeyPressed( VK_MBUTTON )
					||	CExtPopupMenuWnd::IsKeyPressed( bMouseButtonsNotSwapped ? VK_RBUTTON : VK_LBUTTON,true )
					||	( (!bMenuMode) && CExtPopupMenuWnd::IsMenuTracking() )
					)
				{
					bStopFlag = true;
					break;
				}
				if( msg.hwnd != hWndOwn )
					break;
				if( msg.wParam != nTimerID_zero_start && msg.wParam != nTimerID_1st_slow && msg.wParam != nTimerID_2nd_fast )
					break;
				if( msg.wParam == nTimerID_zero_start )
					::SetTimer( hWndOwn, nTimerID_1st_slow, nTimerEllapse_1st_slow, NULL );
				else if( msg.wParam == nTimerID_1st_slow )
				{
					::KillTimer( hWndOwn, nTimerID_1st_slow );
					CExtPaintManager::stat_PassPaintMessages();
					::SetTimer( hWndOwn, nTimerID_2nd_fast, nTimerEllapse_2nd_fast, NULL );
				}
				ASSERT( nStepSize != 0L );
				PeekMessage(&msg,NULL,msg.message,msg.message,PM_REMOVE);
				::GetCursorPos( &ptCursor );
				::ScreenToClient( hWndOwn, &ptCursor );
				bool bPause = false;
				if( ! rcArea.PtInRect( ptCursor ) )
					bPause = true;
				else
				{
					if( m_nSBMHT == INT(CExtPaintManager::__ESBMHT_PAGE_UP) || m_nSBMHT == INT(CExtPaintManager::__ESBMHT_PAGE_DOWN) )
					{
						CExtPaintManager::PAINTSCROLLBARDATA _psbd2( this );
						_psbd2.AdjustHT( ptCursor );
						INT nSBMHT2 = INT( _psbd.m_eSBMHT );
						if( nSBMHT2 != m_nSBMHT )
							bPause = true;
						else
						{
							CRect rcArea2 = _psbd2.GetAreaRectHT();
							if( ! rcArea2.PtInRect( ptCursor ) )
								bPause = true;
							else
							{
								if( _psbd2.m_bHorzBar )
								{
									if( m_nSBMHT == INT(CExtPaintManager::__ESBMHT_PAGE_UP) )
									{
										if( ptCursor.x >= _psbd2.m_rcThumb.left )
											bPause = true;
									}
									else if( m_nSBMHT == INT(CExtPaintManager::__ESBMHT_PAGE_DOWN) )
									{
										if( ptCursor.x <= _psbd2.m_rcThumb.right )
											bPause = true;
									}
								}
								else
								{
									if( m_nSBMHT == INT(CExtPaintManager::__ESBMHT_PAGE_UP) )
									{
										if( ptCursor.y >= _psbd2.m_rcThumb.top )
											bPause = true;
									}
									else if( m_nSBMHT == INT(CExtPaintManager::__ESBMHT_PAGE_DOWN) )
									{
										if( ptCursor.y <= _psbd2.m_rcThumb.bottom )
											bPause = true;
									}
								}
							}
						}
					}
				}
				if( bPause )
				{
					if( ! m_bProcessingOutClick )
					{
						m_bProcessingOutClick = true;
						Invalidate();
					}
					if( pATTW != NULL )
						pATTW->Hide();
					continue;
				}
				if( bUpStep )
				{
					nScrollPos -= nStepSize;
					if( nScrollPos < _psbd.m_DSI.nMin )
						nScrollPos = _psbd.m_DSI.nMin;
				}
				else
				{
					nScrollPos += nStepSize;
					if( nScrollPos > nMx )
						nScrollPos = nMx;
				}
				if( _GetScrollPos( true ) != nScrollPos )
				{
					bool bSendScrollingNotification = true, bTrackPos = true;
					if( hWndParent != NULL )
					{
						switch( m_nSBMHT )
						{
						case (CExtPaintManager::__ESBMHT_BUTTON_UP):
							if( m_bSendActionNotifications )
								::SendMessage(
									hWndParent,
									_psbd.m_bHorzBar ? WM_HSCROLL : WM_VSCROLL,
									MAKEWPARAM( ( _psbd.m_bHorzBar ? SB_LINELEFT : SB_LINEUP ), 0 ),
									LPARAM(m_hWnd)
									);
							if( ! bVirtualMode )
								_SetScrollPos( nScrollPos, bTrackPos, true, bSendScrollingNotification );
							else
								bFinalNotify = (!m_bSendActionNotifications);
						break;
						case (CExtPaintManager::__ESBMHT_BUTTON_DOWN):
							if( m_bSendActionNotifications )
								::SendMessage(
									hWndParent,
									_psbd.m_bHorzBar ? WM_HSCROLL : WM_VSCROLL,
									MAKEWPARAM( ( _psbd.m_bHorzBar ? SB_LINERIGHT : SB_LINEDOWN ), 0 ),
									LPARAM(m_hWnd)
									);
							if( ! bVirtualMode )
								_SetScrollPos( nScrollPos, bTrackPos, true, bSendScrollingNotification );
							else
								bFinalNotify = (!m_bSendActionNotifications);
						break;
						case (CExtPaintManager::__ESBMHT_PAGE_UP):
							if( m_bSendActionNotifications )
								::SendMessage(
									hWndParent,
									_psbd.m_bHorzBar ? WM_HSCROLL : WM_VSCROLL,
									MAKEWPARAM( ( _psbd.m_bHorzBar ? SB_PAGELEFT : SB_PAGEUP ), 0 ),
									LPARAM(m_hWnd)
									);
							if( ! bVirtualMode )
								_SetScrollPos( nScrollPos, bTrackPos, true, bSendScrollingNotification );
							else
								bFinalNotify = (!m_bSendActionNotifications);
						break;
						case (CExtPaintManager::__ESBMHT_PAGE_DOWN):
							if( m_bSendActionNotifications )
								::SendMessage(
									hWndParent,
									_psbd.m_bHorzBar ? WM_HSCROLL : WM_VSCROLL,
									MAKEWPARAM( ( _psbd.m_bHorzBar ? SB_PAGERIGHT : SB_PAGEDOWN ), 0 ),
									LPARAM(m_hWnd)
									);
							if( ! bVirtualMode )
								_SetScrollPos( nScrollPos, bTrackPos, true, bSendScrollingNotification );
							else
								bFinalNotify = (!m_bSendActionNotifications);
						break;
						case (CExtPaintManager::__ESBMHT_THUMB):
							bTrackPos = true;
							if( ! bVirtualMode )
								_SetScrollPos( nScrollPos, bTrackPos, true, bSendScrollingNotification );
							else
								bFinalNotify = false;
						break;
						}
					}
					if( pATTW != NULL && ( ! bAnalyzeThumb ) )
						OnAdvancedPopupMenuTipWndDisplay( *pATTW, m_nSBMHT, true );
				}
				CExtPaintManager::PAINTSCROLLBARDATA _psbd2( this );
				::memcpy( &_psbd.m_DSI, &_psbd2.m_DSI, sizeof(SCROLLINFO) );
				nMx = INT( _psbd.m_DSI.nMax - _psbd.m_DSI.nPage + 1 );
				nScrollLimit = _psbd.m_DSI.nMax - _psbd.m_DSI.nMin - _psbd.m_DSI.nPage + 1;
				ASSERT( nScrollLimit >= 0 );
				if( nStepSize > nScrollLimit )
					nStepSize = nScrollLimit;
				_psbd.AdjustHT( ptCursor );
				bool bProcessingOutClick =
					( m_nSBMHT == INT(_psbd.m_eSBMHT) )
						? false : true;
				rcArea = _psbd.GetAreaRect( CExtPaintManager::e_scroll_bar_mouse_hover_type_t(m_nSBMHT) );
				if( m_bProcessingOutClick != bProcessingOutClick )
				{
					bool bAnimationLocked = AnimationClient_CacheGeneratorIsLocked();
					if( ! bAnimationLocked )
					{
						AnimationClient_CacheGeneratorLock();
 						AnimationClient_CacheNextStateMinInfo( false, __EAPT_BY_PRESSED_STATE_TURNED_OFF );
					}
					m_bProcessingOutClick = bProcessingOutClick;
					if( ! bAnimationLocked )
					{
 						AnimationClient_CacheNextStateMinInfo( true, __EAPT_BY_PRESSED_STATE_TURNED_OFF );
						AnimationClient_CacheGeneratorUnlock();
					}
					Invalidate();
					UpdateWindow();
				}
			}
		break;
		default:
		{
			if(		( ! CExtPopupMenuWnd::IsKeyPressed( bMouseButtonsNotSwapped ? VK_LBUTTON : VK_RBUTTON,true) )
				||	CExtPopupMenuWnd::IsKeyPressed( VK_MBUTTON )
				||	CExtPopupMenuWnd::IsKeyPressed( bMouseButtonsNotSwapped ? VK_RBUTTON : VK_LBUTTON,true )
				||	( (!bMenuMode) && CExtPopupMenuWnd::IsMenuTracking() )
				)
				bStopFlag = true;
		}
		break;
		}
		if( ! ::IsWindow( hWndOwn ) )
			bStopFlag = true;
		if( bStopFlag || nScrollLimit == 0L )
			break;
		if( bAnalyzeThumb )
		{
			LONG nPixelOffset = _psbd.m_bHorzBar ? (ptCursor.x - point.x) : (ptCursor.y - point.y);
			LONG nPixelExtent = _psbd.m_bHorzBar ? (rcScrollable.Width() - _psbd.m_rcThumb.Width()) : (rcScrollable.Height() - _psbd.m_rcThumb.Height());
			if( nPixelExtent <= 0 )
			{
				bStopFlag = true;
				break;
			}
			if( abs(nPixelOffset) > nPixelExtent )
				nPixelOffset = (nPixelOffset < 0) ? (-nPixelExtent) : nPixelExtent;
			INT nShift = ( nPixelExtent == 0 || nPixelOffset == 0 ) ? 0 : ::MulDiv( nScrollLimit, abs(nPixelOffset), nPixelExtent );
			nScrollPos = nScrollPosStart;
			if( nPixelOffset < 0 )
			{
				nScrollPos -= nShift;
				if( nScrollPos < _psbd.m_DSI.nMin )
					nScrollPos = _psbd.m_DSI.nMin;
			}
			else
			{
				nScrollPos += nShift;
				if( nScrollPos > nMx )
					nScrollPos = nMx;
			}
			if( ! bVirtualMode )
			{
				if( _GetScrollPos( true ) != nScrollPos )
				{
					_SetScrollPos( nScrollPos, true );
					if( pATTW != NULL )
						OnAdvancedPopupMenuTipWndDisplay( *pATTW, m_nSBMHT, true );
				}
				bFinalNotify = true;
			}
			CExtPaintManager::PAINTSCROLLBARDATA _psbd2( this );
			::memcpy( &_psbd.m_DSI, &_psbd2.m_DSI, sizeof(SCROLLINFO) );
			nMx = INT( _psbd.m_DSI.nMax - _psbd.m_DSI.nPage + 1 );
			nScrollLimit = _psbd.m_DSI.nMax - _psbd.m_DSI.nMin - _psbd.m_DSI.nPage + 1;
			ASSERT( nScrollLimit >= 0 );
			if( nStepSize > nScrollLimit )
				nStepSize = nScrollLimit;
			_psbd.AdjustHT( ptCursor );
			rcArea = _psbd.GetAreaRect( CExtPaintManager::__ESBMHT_THUMB );
			continue;
		}
		if(		m_bPopupInactiveLightMode
			&&	(	msg.message == WM_TIMER
				||	(__EXT_MFC_WM_MOUSEFIRST <= msg.message && msg.message <= __EXT_MFC_WM_MOUSELAST )
				)
			)
			::PeekMessage(&msg,NULL,msg.message,msg.message,PM_REMOVE);
		else
		if( ! AfxGetThread()->PumpMessage() )
			break;
	}
	if( ! ::IsWindow( hWndOwn ) )
		return;
	if( nStepSize != 0L )
	{
		::KillTimer( hWndOwn, nTimerID_1st_slow );
		::KillTimer( hWndOwn, nTimerID_2nd_fast );
	}
	bAnimationLocked = AnimationClient_CacheGeneratorIsLocked();
	if( ! bAnimationLocked )
	{
		AnimationClient_CacheGeneratorLock();
		if( AnimationClient_StateGet(true).IsEmpty() )
			AnimationClient_CacheNextStateMinInfo( false, __EAPT_BY_PRESSED_STATE_TURNED_OFF );
	}
	if( bFinalNotify )
		_SetScrollPos( nScrollPos, false, true, true );
	m_nSBMHT = INT(CExtPaintManager::__ESBMHT_NOWHERE);
	m_bProcessingClick = m_bProcessingOutClick = m_bProcessingHover = false;
	if( ! bAnimationLocked )
	{
		::GetCursorPos( &ptCursor );
		ScreenToClient( &ptCursor );
		_psbd.AdjustHT( ptCursor );
		m_nSBMHT = INT(_psbd.m_eSBMHT);
 		AnimationClient_CacheNextStateMinInfo( true, __EAPT_BY_PRESSED_STATE_TURNED_OFF );
		AnimationClient_CacheGeneratorUnlock();
	}
	Invalidate();
	UpdateWindow();
	m_nHelperTrackPos = -1;
	m_bHelperHaveTrackPos = false;
	ScrollBar_CaptureRelease();
	if( pATTW != NULL )
		OnAdvancedPopupMenuTipWndDisplay( *pATTW, INT(_psbd.m_eSBMHT), false );
	::SendMessage( hWndParent, _psbd.m_bHorzBar ? WM_HSCROLL : WM_VSCROLL, MAKEWPARAM( SB_ENDSCROLL, 0 ), LPARAM(m_hWnd) );
	if( m_bEnableHookSpy )
		HookSpyRegister( __EHSEF_MOUSE_ALL_WITHOUT_WHEEL|__EHSEF_WND_PROC_IN|__EHSEF_PRE_TRANSLATION );
}