Click here to Skip to main content
15,883,535 members
Articles / Web Development / HTML

A Comprehensive CE Class Library to Replace ATL and MFC

Rate me:
Please Sign up or sign in to vote.
4.48/5 (14 votes)
4 Oct 2000CPOL 278.2K   998   70  
A collection of classes for CE that do not use ATL or MFC, plus an FTP client, database viewer, and sample application that solves beam deflection equations.
// DialogScroll.cpp : Implements the CDialogScroll class
//

#include "stdafx.h"
#include "DialogScroll.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

#ifndef UNUSED_ALWAYS
#define UNUSED_ALWAYS(var)
#endif

IMPLEMENT_DYNAMIC(CDialogScroll, CDialog)

// scroll amount that corresponds to a "line"
static const int LINE_AMOUNT=20;

CPtrList CDialogScroll::m_listIdle;

///////////////////////////////////////////////////////////////////////////////
//
//
//
///////////////////////////////////////////////////////////////////////////////
CDialogScroll::CDialogScroll()
{
	m_bEmbedded = TRUE;
	Construct(0, 0, 0);
}


///////////////////////////////////////////////////////////////////////////////
//
//
//
///////////////////////////////////////////////////////////////////////////////
CDialogScroll::CDialogScroll(int nWidth, int nHeight)
{
	m_bEmbedded = FALSE;
	Construct(nWidth, nHeight, 0);
}

///////////////////////////////////////////////////////////////////////////////
//
//
//
///////////////////////////////////////////////////////////////////////////////
CDialogScroll::CDialogScroll(UINT nIDTemplate, int nWidth, int nHeight, CWnd* pParentWnd /*= NULL*/) :
	CDialog(nIDTemplate, pParentWnd)
{
	m_bEmbedded = FALSE;
	Construct(nWidth, nHeight, 0);
}
 
///////////////////////////////////////////////////////////////////////////////
//
//
//
///////////////////////////////////////////////////////////////////////////////
CDialogScroll::CDialogScroll(UINT nIDTemplate, int nWidth, int nHeight, UINT nDlgBarIDTemplate, CWnd* pParentWnd /*= NULL*/) :
	CDialog(nIDTemplate, pParentWnd)
{
	m_bEmbedded = FALSE;
	Construct(nWidth, nHeight, nDlgBarIDTemplate);
}

BEGIN_MESSAGE_MAP(CDialogScroll, CDialog)
	//{{AFX_MSG_MAP(CDialogScroll)
	ON_WM_CREATE()
	ON_WM_SIZE()
	ON_WM_HSCROLL()
	ON_WM_VSCROLL()
	ON_WM_MOVE()
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()
 

///////////////////////////////////////////////////////////////////////////////
//
// Called by all constructors
//
///////////////////////////////////////////////////////////////////////////////
void CDialogScroll::Construct(int nWidth, int nHeight, UINT nDlgBarIDTemplate)
{
	m_bInit = FALSE;
	m_nWidth = nWidth;
	m_nHeight = nHeight;
	m_nDlgBarIDTemplate = nDlgBarIDTemplate;
	
	m_pDlgBar = NULL;
}


///////////////////////////////////////////////////////////////////////////////
//
//
//
///////////////////////////////////////////////////////////////////////////////
CDialogScroll::~CDialogScroll()
{
	CEnvironment* pNode = (CEnvironment*)m_listIdle.RemoveHead();
	
	::UnhookWindowsHookEx(pNode->m_hOldIdleProc);
	::UnhookWindowsHookEx(pNode->m_hOldKeyboardProc);
	//  ::UnhookWindowsHookEx(pNode->m_hOldMessageProc);
	
	delete pNode;
	
	if (NULL != m_pDlgBar)
	{
		m_pDlgBar->DestroyWindow();
		delete m_pDlgBar;
	}
}

/////////////////////////////////////////////////////////////////////////////
// CTestScrollDlg message handlers


///////////////////////////////////////////////////////////////////////////////
//
//
//
///////////////////////////////////////////////////////////////////////////////
int CDialogScroll::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
	if (CDialog::OnCreate(lpCreateStruct) == -1)
		return -1;

	return 0;
}


///////////////////////////////////////////////////////////////////////////////
//
//
//
///////////////////////////////////////////////////////////////////////////////
BOOL CDialogScroll::OnInitDialog() 
{
	CDialog::OnInitDialog();
	
	CRect rect;
	GetClientRect(&rect);
	m_cxOrig = rect.Width();
	m_cyOrig = rect.Height();
	
	m_bVertSBVisible = FALSE;
	m_bHorzSBVisible = FALSE;
	
	m_bInit = TRUE;
	
	{
		CEnvironment* pNode = new CEnvironment;
		
		pNode->m_pThis = this;
		pNode->m_pCtrl = NULL;
		
		//
		// if dialog is embedded within another dialog and we will set 
		// the m_pThisParent to the parent of the embedded dialog 
		// otherwise we will set it to the this pointer
		//
		if (m_bEmbedded)
			pNode->m_pThisParent = this->GetParent();
		else
			pNode->m_pThisParent = this;
		
		
		// hook processing
		pNode->m_hOldIdleProc     = ::SetWindowsHookEx(WH_FOREGROUNDIDLE, 
										IdleProc,     
										AfxGetApp()->m_hInstance, 
										AfxGetThread()->m_nThreadID);

		pNode->m_hOldKeyboardProc = ::SetWindowsHookEx(WH_KEYBOARD, 
										KeyboardProc, 
										AfxGetApp()->m_hInstance, 
										AfxGetThread()->m_nThreadID);
		
		//  MessageProc() functionality not currently needed
		//    pNode->m_hOldMessageProc  = ::SetWindowsHookEx(WH_MSGFILTER, 
		//                                                   MessageProc, 
		//                                                   AfxGetApp()->m_hInstance, 
		//                                                   AfxGetThread()->m_nThreadID);
		
		m_listIdle.AddHead(pNode);
	}
	
	// adjust window size, if desired by caller
	if (0 != m_nWidth || 0 != m_nHeight)
	{
		CRect rect;
		int nSBVWidth = ::GetSystemMetrics(SM_CXVSCROLL);
		int nSBHHeight = ::GetSystemMetrics(SM_CYHSCROLL);
		
		GetWindowRect(&rect);
		
		int nWidth = (0 == m_nWidth ? rect.Width() + nSBVWidth : m_nWidth);
		int nHeight = (0 == m_nHeight ? rect.Height() + nSBHHeight : m_nHeight);
		
		MoveWindow(rect.TopLeft().x, rect.TopLeft().y, nWidth, nHeight);
	}
	
	ASSERT(NULL == m_pDlgBar);
	if (0 != m_nDlgBarIDTemplate)
	{
		// create modeless dialog bar
		m_pDlgBar = new CDlgBar(*this);
		m_pDlgBar->Create(m_nDlgBarIDTemplate, this);
		
		PositionDlgBar();
	}
	
	return TRUE;  // return TRUE unless you set the focus to a control

	// EXCEPTION: OCX Property Pages should return FALSE
}

///////////////////////////////////////////////////////////////////////////////
//
//
//
///////////////////////////////////////////////////////////////////////////////
void CDialogScroll::OnMove(int x, int y) 
{
	CDialog::OnMove(x, y);
	
	PositionDlgBar();
}


///////////////////////////////////////////////////////////////////////////////
//
//
//
///////////////////////////////////////////////////////////////////////////////
void CDialogScroll::OnSize(UINT nType, int cx, int cy) 
{
	CDialog::OnSize(nType, cx, cy);
	
	if (! m_bInit)
		return;

	if (SIZE_RESTORED == nType)
	{
		if (cy < m_cyOrig)
		{
			// make scrollbar visible, if necessary
			if (! m_bVertSBVisible)
			{
				/*  THIS DOESN'T WORK; window does not stay widened
				// widen the window
					{
						CRect rect;
						int nSBWidth = ::GetSystemMetrics(SM_CXVSCROLL);
					
						GetWindowRect(&rect);
					  
						MoveWindow(rect.TopLeft().x, rect.TopLeft().y, 
						rect.Width()+nSBWidth, rect.Height());
					}
				*/

				ShowScrollBar(SB_VERT, TRUE);
				m_bVertSBVisible = TRUE;
			}
			
			int nPos = GetScrollPos(SB_VERT);
			
			// check for need to scroll window
			if (nPos + cy > m_cyOrig)
			{
				ScrollWindow(0, (nPos + cy) - m_cyOrig);
				nPos = m_cyOrig - cy;
			}
			
			// set scrollbar parameters
			{
				SCROLLINFO scrollinfo;
				
				scrollinfo.cbSize = sizeof(scrollinfo);
				scrollinfo.fMask = SIF_PAGE | SIF_RANGE;
				scrollinfo.nMin = 0;
				scrollinfo.nMax = m_cyOrig - 1;
				scrollinfo.nPage = cy; 
				
				SetScrollInfo(SB_VERT, &scrollinfo);
			}
			
			// adjust scroll position
			SetScrollPos(SB_VERT, nPos);
		}
		else
		{
			// make scrollbar invisible, if necessary
			if (m_bVertSBVisible)
			{
				ShowScrollBar(SB_VERT, FALSE);
				m_bVertSBVisible = FALSE;
				
				/*  THIS DOESN'T WORK; window does not stay narrowed
				// narrow the window
				{
					CRect rect;
					int nSBWidth = ::GetSystemMetrics(SM_CXVSCROLL);
				
					GetWindowRect(&rect);
				  
					MoveWindow(rect.TopLeft().x, rect.TopLeft().y, 
					rect.Width()-nSBWidth, rect.Height());
				}
				*/
			}
		}

		if (cx < m_cxOrig)
		{
			// make scrollbar visible, if necessary
			if (!m_bHorzSBVisible)
			{
				ShowScrollBar(SB_HORZ, TRUE);
				m_bHorzSBVisible = TRUE;
			}
			
			int nPos = GetScrollPos(SB_HORZ);
			
			// check for need to scroll window
			if (nPos + cx > m_cxOrig)
			{
				ScrollWindow((nPos + cx) - m_cxOrig, 0);
				nPos = m_cxOrig - cx;
			}
			
			// set scrollbar parameters
			{
				SCROLLINFO scrollinfo;
				
				scrollinfo.cbSize = sizeof(scrollinfo);
				scrollinfo.fMask = SIF_PAGE | SIF_RANGE;
				scrollinfo.nMin = 0;
				scrollinfo.nMax = m_cxOrig-1;
				scrollinfo.nPage = cx; 
				
				SetScrollInfo(SB_HORZ, &scrollinfo);
			}
			
			// adjust scroll position
			SetScrollPos(SB_HORZ, nPos);
		}
		else
		{
			// make scrollbar invisible, if necessary
			if (m_bHorzSBVisible)
			{
				ShowScrollBar(SB_HORZ, FALSE);
				m_bHorzSBVisible = FALSE;
			}
		}
	}

	PositionDlgBar();
}

///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
void CDialogScroll::OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar) 
{
	pScrollBar;  // fix warning
	
	if (! m_bHorzSBVisible)
		// nothing; no scrollbar
		return;

	CRect rect;
	int nMin;
	int nMax;
	int nOrig = GetScrollPos(SB_HORZ);
	int nNew;
	
	GetClientRect(&rect);
	
	GetScrollRange(SB_HORZ, &nMin, &nMax);
	
	
	switch (nSBCode)
	{
	case SB_BOTTOM:   // Scroll to bottom.
		nNew = nMax;
		break;
		
	case SB_LINEDOWN: //�Scroll one line down.
		nNew = nOrig + LINE_AMOUNT;
		break;
		
	case SB_LINEUP:   // Scroll one line up.
		nNew = nOrig - LINE_AMOUNT;
		break;
		
	case SB_PAGEDOWN: //�Scroll one page down.
		nNew = nOrig + rect.Width();
		break;
		
	case SB_PAGEUP:   //�Scroll one page up.
		nNew = nOrig - rect.Width();;
		break;
		
	case SB_THUMBTRACK: //�Drag scroll box to specified position. The current position is provided in nPos.
		nNew = nPos;
		break;
		
	case SB_TOP:      //���Scroll to top.
		nNew = 0;
		break;
		
	default:
		nNew = nOrig;
		break;
	}
	
	if (nNew < 0)
		nNew = 0;
	else
	{
		int nLimit = nMax - rect.Width() + 1;
		
		if (nNew > nLimit)
			nNew = nLimit;
	}
	
	if (nNew != nOrig)
	{
		ScrollWindow(nOrig-nNew, 0);
		SetScrollPos(SB_HORZ, nNew);
	}
}


///////////////////////////////////////////////////////////////////////////////
//
//
//
///////////////////////////////////////////////////////////////////////////////
void CDialogScroll::OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar) 
{
	UNUSED_ALWAYS(pScrollBar);

	if (! m_bVertSBVisible)
		// nothing; no scrollbar
		return;

	CRect rect;
	int nMin;
	int nMax;
	int nOrig = GetScrollPos(SB_VERT);
	int nNew;
	
	GetClientRect(&rect);
	GetScrollRange(SB_VERT, &nMin, &nMax);
	
	switch (nSBCode)
	{
	case SB_BOTTOM: 	nNew = nMax;					break;
	case SB_LINEDOWN:	nNew = nOrig + LINE_AMOUNT;		break;
	case SB_LINEUP:		nNew = nOrig - LINE_AMOUNT;		break;
	case SB_PAGEDOWN:	nNew = nOrig + rect.Height();	break;
	case SB_PAGEUP:		nNew = nOrig - rect.Height();	break;

	//�Drag scroll box to specified position.
	// The current position is provided in nPos.
	case SB_THUMBTRACK:	nNew = nPos;					break;
	case SB_TOP:		nNew = 0;						break;
	default:
		nNew = nOrig;
		break;
	}
	
	if (nNew < 0)
		nNew = 0;
	else 
	{
		int nLimit = nMax - rect.Height() + 1;
		
		if (nNew > nLimit)
			nNew = nLimit;
	}
	
	if (nNew != nOrig)
	{
		ScrollWindow(0, nOrig - nNew);
		SetScrollPos(SB_VERT, nNew);
	}
}



///////////////////////////////////////////////////////////////////////////////
//      Internal helper functions
///////////////////////////////////////////////////////////////////////////////
BOOL CDialogScroll::CreateAsChild(UINT nTemplateID, UINT nWndToReplaceID, BOOL bBorder, CWnd* pParent) 
{
  ASSERT(pParent);

  CRect rect;
  CWnd* tempWnd;  // wnd that dialog will be placed at
  
  tempWnd = pParent->GetDlgItem(nWndToReplaceID);
  tempWnd->GetWindowRect(&rect);
  pParent->ScreenToClient(&rect);
  

  if (! (Create(nTemplateID, pParent)))
    return FALSE;
  
  // add border if needed
  if (bBorder)
    ModifyStyle(0, WS_BORDER);

  SetWindowPos(tempWnd, rect.left, rect.top, rect.Width(), rect.Height(), SWP_SHOWWINDOW);

  // destroy window that we are replacing
  tempWnd->DestroyWindow();

  return TRUE;
}


///////////////////////////////////////////////////////////////////////////////
//
//
//
///////////////////////////////////////////////////////////////////////////////
LRESULT CALLBACK CDialogScroll::IdleProc(int nCode, WPARAM wParam, LPARAM lParam)
{
	CEnvironment* pNode = (CEnvironment*)m_listIdle.GetHead();
	
	ASSERT(NULL != pNode);
	
	if (nCode >= 0 && HC_ACTION == nCode)	// MUST return DefHookProc
	{
		CDialogScroll* pThis = pNode->m_pThis;  // to reduce indirection
		ASSERT(NULL != pThis);
		
		HWND foreGround_hWnd = pThis->GetForegroundWindow()->m_hWnd;
		HWND embedded_hWnd = pNode->GetEmbeddedWnd()->m_hWnd;
		
		if (foreGround_hWnd == embedded_hWnd)
		{
			CWnd* pCtrl = pThis->GetFocus();
			
			if (pCtrl->GetParent()->m_hWnd == pThis->m_hWnd)
			{
				if (pCtrl != pNode->m_pCtrl)
				{
					pNode->m_pCtrl = pCtrl;
					
					if (NULL != pCtrl)
					{
						RECT rectDlg;
						RECT rectCtrl;
						BOOL bScrolled = FALSE;
						
						pThis->GetClientRect(&rectDlg);
						pThis->ClientToScreen(&rectDlg);
						pCtrl->GetWindowRect(&rectCtrl);
						
						// bring the control into view if it has scrolled out of view
						if (rectCtrl.bottom > rectDlg.bottom)
						{
							pThis->ScrollWindow(0, rectDlg.bottom - rectCtrl.bottom);
							pThis->SetScrollPos(SB_VERT, pThis->GetScrollPos(SB_VERT) + (rectCtrl.bottom - rectDlg.bottom));
							bScrolled = TRUE;
						}
						else if (rectCtrl.top < rectDlg.top)
						{
							pThis->ScrollWindow(0, rectDlg.top - rectCtrl.top);
							pThis->SetScrollPos(SB_VERT, pThis->GetScrollPos(SB_VERT) + (rectCtrl.top - rectDlg.top));
							bScrolled = TRUE;
						}
						// else nothing
						
						if (rectCtrl.right > rectDlg.right)
						{
							pThis->ScrollWindow(rectDlg.right - rectCtrl.right, 0);
							pThis->SetScrollPos(SB_HORZ, pThis->GetScrollPos(SB_HORZ) + (rectCtrl.right - rectDlg.right));
							bScrolled = TRUE;
						}
						else if (rectCtrl.left < rectDlg.left)
						{
							pThis->ScrollWindow(rectDlg.left - rectCtrl.left, 0);
							pThis->SetScrollPos(SB_HORZ, pThis->GetScrollPos(SB_HORZ) + (rectCtrl.left - rectDlg.left));
							bScrolled = TRUE;
						}
						// else nothing
						
						if (bScrolled)
						{
							// We scrolled.  If control is a ComboBox and box is dropped, 
							// need to hide it since it probably got drawn in the wrong place.
							TCHAR szClassName[100];
							HWND hWnd = pCtrl->m_hWnd;
							
							::GetClassName(hWnd, szClassName, sizeof(szClassName));
							if (CString(_T("ComboBox")) == szClassName)
							{
								BOOL bDropped = ::SendMessage(hWnd, CB_GETDROPPEDSTATE, 0, 0);
								
								// undrop
								::PostMessage(hWnd, CB_SHOWDROPDOWN, FALSE, 0);
								
								if (bDropped)
								{
									// Redrop
									::PostMessage(hWnd, CB_SHOWDROPDOWN, TRUE, 0);
								}
							}
						}
					}
				}
				// else nothing; focus did not change
				
				// handled it
				return 1L;    
			}
		}
		// else nothing; ours is not the foreground window
	}
	
	// did not handle it
	return CallNextHookEx(pNode->m_hOldIdleProc, nCode, wParam, lParam);
}


///////////////////////////////////////////////////////////////////////////////
//
//
//
///////////////////////////////////////////////////////////////////////////////
LRESULT CALLBACK CDialogScroll::KeyboardProc(int nCode, WPARAM wVKeyCode, LPARAM lFlags)
{
	CEnvironment* pNode = (CEnvironment*)m_listIdle.GetHead();
	
	ASSERT(NULL != pNode);
	
	if (nCode >= 0 && HC_ACTION == nCode)
	{
		CDialogScroll* pThis = pNode->m_pThis;  // to reduce indirection
		ASSERT(NULL != pThis);
		
		HWND foreGround_hWnd = pThis->GetForegroundWindow()->m_hWnd;
		HWND embedded_hWnd = pNode->GetEmbeddedWnd()->m_hWnd;
		
		if (foreGround_hWnd == embedded_hWnd)
		{
			CWnd* pCtrl = pThis->GetFocus();
			if (pCtrl->GetParent()->m_hWnd == pThis->m_hWnd)
			{
				if (0 == (HIWORD(lFlags) & (KF_UP | KF_ALTDOWN | KF_MENUMODE)))
				{
					// key pressed that we may be interested in
					switch (wVKeyCode)
					{
					case VK_PRIOR:
						pThis->OnVScroll(SB_PAGEUP, 0, NULL);
						return 1L; // handled
						break;
					case VK_NEXT:
						pThis->OnVScroll(SB_PAGEDOWN, 0, NULL);
						return 1L; // handled
						break;
					default:
						// do nothing
						break;
					}
				}
			}
		}
		// else nothing; ours is not the foreground window
	}
	
	// did not handle it
	return CallNextHookEx(pNode->m_hOldKeyboardProc, nCode, wVKeyCode, lFlags);
}


///////////////////////////////////////////////////////////////////////////////
//
//
//
///////////////////////////////////////////////////////////////////////////////
LRESULT CALLBACK CDialogScroll::MessageProc(int nCode, WPARAM wUnused, LPARAM lMsg)
{
	CEnvironment* pNode = (CEnvironment*)m_listIdle.GetHead();
	ASSERT(NULL != pNode);

/*  MessageProc() functionality not currently needed
	if (nCode >= 0)                         // MUST return DefHookProc
	{
		if (MSGF_DIALOGBOX == nCode)
		{
			CDialogScroll* pThis = pNode->m_pThis;  // to reduce indirection
			
			ASSERT(NULL != pThis);
			
			MSG* pMsg = (MSG*)lMsg;
			HWND hDlgBar     = pThis->m_pDlgBar->m_hWnd;
			
			if (pMsg->hwnd == hDlgBar)
			{
				if (WM_SETFOCUS == pMsg->message)
				{
					// prevent dlg bar from getting the focus
					pThis->SetFocus();
					
					// handled
					return 1L;
				}
			}
			// else nothing; not a message for the dlg bar
		}
		// else nothing; not HC_ACTION
	}
	// else nothing; nCode < 0
*/

  // did not handle it
  return CallNextHookEx(pNode->m_hOldMessageProc, nCode, wUnused, lMsg);
}


///////////////////////////////////////////////////////////////////////////////
//
//
//
///////////////////////////////////////////////////////////////////////////////
void CDialogScroll::PositionDlgBar()
{
	if (NULL == m_pDlgBar)
		//nothing; no dlg bar
		return;

	CRect rectParent;
	CRect rectDlgBar;
		
	GetClientRect(&rectParent);
	ClientToScreen(&rectParent);
	m_pDlgBar->GetWindowRect(&rectDlgBar);
	
	rectDlgBar.OffsetRect(rectParent.right - rectDlgBar.right, 
		rectParent.top   - rectDlgBar.top);
	
	m_pDlgBar->MoveWindow(&rectDlgBar);
}



//
//
// CDlgBar functions
//
//

///////////////////////////////////////////////////////////////////////////////
//
//
//
///////////////////////////////////////////////////////////////////////////////
CDialogScroll::CDlgBar::CDlgBar(CDialogScroll& DialogScroll)
	: m_DialogScroll(DialogScroll)
{
}


///////////////////////////////////////////////////////////////////////////////
//
//
//
///////////////////////////////////////////////////////////////////////////////
BOOL CDialogScroll::CDlgBar::OnCommand(WPARAM wParam, LPARAM lParam )
{
	// redirect message:
	return m_DialogScroll.OnCommand(wParam, lParam);
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
United States United States
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions