Click here to Skip to main content
15,885,869 members
Articles / Desktop Programming / MFC

CPPDumpCtrl - version 1.2

Rate me:
Please Sign up or sign in to vote.
4.88/5 (29 votes)
19 Aug 2002CPOL20 min read 195.2K   6.5K   132  
Class for view and edit data in Hex, Dec, Bin, Oct, Ascii formats
// PPDumpCtrl.cpp : implementation file for the CPPDumpCtrl control class
// written by Eugene Pustovoyt
//

// History
/*
	07 Aug 2002 - First release. Version 1.0
-----------------------------------------------------------------			
	14 Aug 2002:  Release version 1.1
		FIX: Fixed error of the thumbtrack messages when the buffer large 
		     then 32K (thanks to Bill Morrison - Rosinante Software)
		ADD: Support tooltip 
		ADD: New style PPDUMP_DATA_LOW_HIGH
		ADD: New message UDM_PPDUMPCTRL_SELECTION and new structure NM_PPDUMP_SEL
		ADD: Support mouse wheel (thanks to Darren Schroeder)
		FIX: Other minor error
-----------------------------------------------------------------
    19 Aug 2002: Release version 1.2
	    ADD: Added new formating chars to the format string of the tooltip text 
		ADD: Added function SetSpecialCharView and GetTooltip
		ADD: Two functions SetTrackMouseMove, IsTrackMouseMove and new style
			 PPDUMP_TRACK_MOUSE_MOVE
		FIX: Leak memory with GetDC()
		UPD: Now the control based on CWnd instead CEdit
*/
#include "stdafx.h"
#include "PPDumpCtrl.h"
#include "memdc.h"

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

#define nIdEdit	1
const CString m_csNameFields [] = {_T("Addr"), _T("Hex"), _T("Dec"), _T("Bin"), _T("Oct"), _T("Ascii")};

/////////////////////////////////////////////////////////////////////////////
// CPPDumpCtrl

CPPDumpCtrl::CPPDumpCtrl()
{
	RegisterWindowClass();
}

CPPDumpCtrl::~CPPDumpCtrl()
{
	if (m_hMenu)	
		::DestroyMenu(m_hMenu);
	
	KillEdit();
}

BEGIN_MESSAGE_MAP(CPPDumpCtrl, CWnd)
	//{{AFX_MSG_MAP(CPPDumpCtrl)
	ON_WM_ERASEBKGND()
	ON_WM_PAINT()
	ON_WM_VSCROLL()
	ON_WM_SETFOCUS()
	ON_WM_KILLFOCUS()
	ON_WM_MOUSEMOVE()
	ON_WM_RBUTTONDOWN()
	ON_WM_LBUTTONDBLCLK()
	ON_WM_KEYDOWN()
	ON_WM_LBUTTONDOWN()
	ON_WM_LBUTTONUP()
	ON_WM_MOUSEWHEEL()
	ON_WM_SIZE()
	ON_WM_ENABLE()
	//}}AFX_MSG_MAP
	ON_MESSAGE(WM_MOUSELEAVE, OnMouseLeave)
	ON_NOTIFY (UDM_PPNUMEDIT_ENTER, nIdEdit, NotifyEditEnter)
	ON_NOTIFY (UDM_PPNUMEDIT_CANCEL, nIdEdit, NotifyEditCancel)
	ON_NOTIFY (UDM_PPNUMEDIT_MOVE, nIdEdit, NotifyEditMove)
	ON_NOTIFY (UDM_PPNUMEDIT_HOTKEY, nIdEdit, NotifyEditHotKeys)
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CPPDumpCtrl message handlers

// Register the window class if it has not already been registered.
BOOL CPPDumpCtrl::RegisterWindowClass()
{
    WNDCLASS wndcls;
    HINSTANCE hInst = AfxGetInstanceHandle();

    if (!(::GetClassInfo(hInst, PPDUMPCTRL_CLASSNAME, &wndcls)))
    {
        // otherwise we need to register a new class
        wndcls.style            = CS_DBLCLKS | CS_HREDRAW | CS_VREDRAW;
        wndcls.lpfnWndProc      = ::DefWindowProc;
        wndcls.cbClsExtra       = wndcls.cbWndExtra = 0;
        wndcls.hInstance        = hInst;
        wndcls.hIcon            = NULL;
        wndcls.hCursor          = AfxGetApp()->LoadStandardCursor(IDC_ARROW);
        wndcls.hbrBackground    = (HBRUSH) (COLOR_3DFACE + 1);
        wndcls.lpszMenuName     = NULL;
        wndcls.lpszClassName    = PPDUMPCTRL_CLASSNAME;

        if (!AfxRegisterClass(&wndcls))
        {
            AfxThrowResourceException();
            return FALSE;
        }
    }

    return TRUE;
}

BOOL CPPDumpCtrl::Create(const RECT& rect, CWnd* pParentWnd, UINT nID, DWORD dwStyle /* = WS_CHILD | WS_BORDER | WS_TABSTOP | WS_VISIBLE */) 
{
	TRACE(_T("CPPDumpCtrl::Create()\n"));
	ASSERT(pParentWnd->GetSafeHwnd());

    if (!CWnd::Create(PPDUMPCTRL_CLASSNAME, NULL, dwStyle, rect, pParentWnd, nID))
        return FALSE;

	return TRUE;
}

void CPPDumpCtrl::OnEnable(BOOL bEnable) 
{
	CWnd::OnEnable(bEnable);
	
	Invalidate(FALSE);
}

BOOL CPPDumpCtrl::Initialise()
{
	m_pNewData = NULL;
	m_pOldData = NULL;
	m_pEdit = NULL;

	m_hMenu = NULL;
	m_hParentWnd = NULL;

	m_nLengthData = 1;
	m_nRealLengthData = 0;
	m_nOffsetAddress = 0;
	m_nBeginAddress = 0;

	m_nCurArea = -1;
	m_nCurrentAddr = -1;
	m_nEditedArea = -1;
	m_nEditedAddress = -1;
	m_nAddressToolTip = -1;
	SetSelectRange(0, -1, FALSE);

	m_rLastTrackRect.SetRectEmpty();
	SetCharsInData();

	m_bMouseOverCtrl = FALSE;
	m_bFocused = FALSE;
	m_bPressedLButton = FALSE;

	// No tooltip created
	m_pToolTip.m_hWnd = NULL;
	m_sFormatToolTip = "";
	m_chSpecCharView = NULL;

	SetDefaultStyles(FALSE);
	SetDefaultFont(FALSE);
	SetDefaultColors(FALSE);

	m_crDisableFg = ::GetSysColor(COLOR_BTNSHADOW);
	m_crDisableBk = ::GetSysColor(COLOR_BTNFACE);

	return TRUE;
}

BOOL CPPDumpCtrl::PreCreateWindow(CREATESTRUCT& cs) 
{
	TRACE(_T("CPPDumpCtrl::PreCreateWindow()\n"));	
	
	if(!CWnd::PreCreateWindow(cs)) 
		return FALSE;
	
//	cs.style |= WS_VSCROLL | WS_HSCROLL;
	
	return TRUE;
}

void CPPDumpCtrl::PreSubclassWindow() 
{
	TRACE(_T("CPPDumpCtrl::PreSubclassWindow()\n"));

	CWnd::PreSubclassWindow();

	Initialise();
}

BOOL CPPDumpCtrl::PreTranslateMessage(MSG* pMsg) 
{	
	InitToolTip();

	switch (pMsg->message)
	{
	case WM_LBUTTONDOWN:
	case WM_RBUTTONDOWN:
	case WM_MBUTTONDOWN:
	case WM_VSCROLL:
	case WM_HSCROLL:
		if (m_pToolTip.m_hWnd != NULL)
			m_pToolTip.Activate(FALSE);
		m_nAddressToolTip = -1;
		break;
	}
	m_pToolTip.RelayEvent(pMsg);

	// TODO: Add your specialized code here and/or call the base class
	if (pMsg->message == WM_KEYDOWN)
	{
		if (::GetKeyState(VK_CONTROL) < 0)
		{
			switch (pMsg->wParam)
			{
			case 'H':
				HandleHotkeys(PPDUMP_HOTKEY_HEX);
				return TRUE;
			case 'D':
				HandleHotkeys(PPDUMP_HOTKEY_DEC);
				return TRUE;
			case 'B':
				HandleHotkeys(PPDUMP_HOTKEY_BIN);
				return TRUE;
			case 'O':
				HandleHotkeys(PPDUMP_HOTKEY_OCT);
				return TRUE;
			case 'A':
				HandleHotkeys(PPDUMP_HOTKEY_ASCII);
				return TRUE;
			}
		}
		else if (pMsg->wParam == VK_RETURN)
		{
			int nArea = GetNextField(0x11);
			if ((m_pEdit == NULL) && (nArea >= 0))
			{
				m_nEditedAddress = m_nCaretAddrBegin;
				m_nEditedArea = nArea;
				SetEditedValue();
				return TRUE;
			}
		}
	}
	else if (pMsg->message == WM_RBUTTONDOWN)
	{
		if (m_hMenu && !m_rLastTrackRect.IsRectEmpty() && (m_nCurArea > 0x11))
		{
			HMENU hSubMenu = ::GetSubMenu(m_hMenu, 0);
			if (GetNotify())
			{
				NM_PPDUMP_MENU lpnm;
				
				lpnm.iArea = m_nCurArea;
				lpnm.iAddress	  = m_nCurrentAddr;
				lpnm.hMenu		  = hSubMenu;
				lpnm.hdr.hwndFrom = m_hWnd;
				lpnm.hdr.idFrom   = GetDlgCtrlID();
				lpnm.hdr.code     = UDM_PPDUMPCTRL_MENU_CALLBACK;
				
				::SendMessage(m_hParentWnd, WM_NOTIFY, lpnm.hdr.idFrom, (LPARAM)&lpnm);
			}
			if (hSubMenu)
			{
				DWORD dwRetValue = ::TrackPopupMenuEx(hSubMenu, TPM_LEFTALIGN | TPM_LEFTBUTTON | TPM_RIGHTBUTTON | TPM_NONOTIFY | TPM_RETURNCMD, pMsg->pt.x, pMsg->pt.y, m_hParentWnd, NULL);
				if (dwRetValue)
					::PostMessage(m_hParentWnd, WM_COMMAND, MAKEWPARAM(dwRetValue, 0), (LPARAM)NULL);
				m_nCurArea = GetDataUnderCursor(pMsg->pt, &m_nCurrentAddr);
				m_rLastTrackRect = GetRectAddress(m_nCurrentAddr, m_nCurArea);
				Invalidate();
			}
		}
	}

	return CWnd::PreTranslateMessage(pMsg);
}

void CPPDumpCtrl::OnSize(UINT nType, int cx, int cy) 
{
	if (!::IsWindow(m_hWnd))
        return;

	KillEdit();
	CWnd::OnSize(nType, cx, cy);
}

BOOL CPPDumpCtrl::OnEraseBkgnd(CDC* pDC) 
{
	//overridden for flicker-free drawing.
	return TRUE;
}

void CPPDumpCtrl::OnSetFocus(CWnd* pOldWnd) 
{
	TRACE(_T("CPPDumpCtrl::OnSetFocus()\n"));
	m_bFocused = TRUE;
	Invalidate(FALSE);
}

void CPPDumpCtrl::OnKillFocus(CWnd* pNewWnd) 
{
	TRACE(_T("CPPDumpCtrl::OnKillFocus()\n"));

	CWnd::OnKillFocus(pNewWnd);

	m_bFocused = FALSE;
	
	// TODO: Add your message handler code here
	Invalidate(FALSE);
	
}

void CPPDumpCtrl::OnLButtonDown(UINT nFlags, CPoint point) 
{
	TRACE(_T("CPPDumpCtrl::OnLButtonDown()\n"));
	// TODO: Add your message handler code here and/or call default
	if ((!m_rLastTrackRect.IsRectEmpty()) && (m_nCurArea > 0x11))
	{
		KillEdit();
		SetSelectRange(m_nCurrentAddr);
		m_bPressedLButton = IsEnableSelect();
	}
	
	CWnd::OnLButtonDown(nFlags, point);
}

void CPPDumpCtrl::OnLButtonUp(UINT nFlags, CPoint point) 
{
	TRACE(_T("CPPDumpCtrl::OnLButtonUp()\n"));

	if (m_bPressedLButton)
	{
		// Make sure this is a valid window
		if (IsWindow(GetSafeHwnd()) && GetNotify())
		{
			NM_PPDUMP_SEL lpnm;
			GetSelectRange(&lpnm.iFirstAddr, &lpnm.iLastAddr);
			if (lpnm.iFirstAddr != lpnm.iLastAddr)
			{
				lpnm.hdr.hwndFrom = m_hWnd;
				lpnm.hdr.idFrom   = GetDlgCtrlID();
				lpnm.hdr.code     = UDM_PPDUMPCTRL_SELECTION;
				::SendMessage(m_hParentWnd, WM_NOTIFY, lpnm.hdr.idFrom, (LPARAM)&lpnm);
			}
		}
	}
	m_bPressedLButton = FALSE;
	
	CWnd::OnLButtonUp(nFlags, point);
}

void CPPDumpCtrl::OnRButtonDown(UINT nFlags, CPoint point) 
{
	TRACE(_T("CPPDumpCtrl::OnRButtonDown()\n"));
	// TODO: Add your message handler code here and/or call default
//	CWnd::OnRButtonDown(nFlags, point);
}

void CPPDumpCtrl::OnLButtonDblClk(UINT nFlags, CPoint point) 
{
	TRACE(_T("CPPDumpCtrl::OnLButtonDblClk()\n"));
	//If in-place edit is exist, then delete him
	BOOL bExist = FALSE;
	
	if (m_pEdit != NULL)
	{
		//The edit is exist
		if (!m_rLastTrackRect.IsRectEmpty())
		{
			//Under the mouse is real data
			if ((m_nEditedArea != 0x1) && (m_nEditedArea != 0x11))
				CompleteEditValue(m_pEdit->GetValue(), FALSE); //If edit is exist then get the value
			
			bExist = KillEdit();
			//If address field was editing then redraw caontrol
			if ((m_nEditedArea & 0xF) == 0x1)
				Invalidate(FALSE);
		}
		else
		{
			m_pEdit->SetFocus();
			return;
		}
	}

	BOOL bEnable = FALSE;
	if (!m_rLastTrackRect.IsRectEmpty())
	{
		//Under the mouse is real data
		if (IsReadOnly())
		{
			//If the control - read only
			if ((m_nCurArea & 0xF) == 0x1)
				bEnable = TRUE; //With READ_ONLY enabled editing address field
		}
		else bEnable = TRUE; //The edit was enabled
	}

	if (m_nCurArea > 0x11)
		SetSelectRange(m_nCurrentAddr);

	if (bEnable)
	{
		int nAddr = -1;
		if (m_nCurArea == 0x11)
			nAddr = m_nCurrentAddr;
		else if ((!bExist) || (m_nCurArea > 0x10))
			nAddr = m_nCaretAddrBegin;

		SetEditedValue(nAddr, m_nCurArea);
	}
	else
		CWnd::OnLButtonDown(nFlags, point);
}

void CPPDumpCtrl::OnMouseMove(UINT nFlags, CPoint point) 
{
	CDC * pDC = GetDC(); //CClientDC dc(this);

	TrackMouseMove(FALSE, pDC);

//	m_nCurArea = GetAreaCursor(point);
//	m_nCurrentAddr = m_nBeginAddress;

	m_nCurArea = GetDataUnderCursor(point, &m_nCurrentAddr);
	m_rLastTrackRect = GetRectAddress(m_nCurrentAddr, m_nCurArea);

	//Tracking to select data
	if (m_bPressedLButton && (!m_rLastTrackRect.IsRectEmpty()) && (m_nCurArea > 0x11))
	{
		int nBegin = m_nCaretAddrBegin;
		int nEnd = m_nCaretAddrEnd;

		if (m_nCurrentAddr >= m_nCaretAddrFirst)
		{
			nBegin = m_nCaretAddrFirst;
			nEnd = m_nCurrentAddr;
		}
		else if (m_nCurrentAddr < m_nCaretAddrFirst)
		{
			nEnd = m_nCaretAddrFirst;
			nBegin = m_nCurrentAddr;
		}

		if ((nEnd != m_nCaretAddrEnd) || (nBegin != m_nCaretAddrBegin))
		{
			//If select range of the address was changed 
			m_nCaretAddrBegin = nBegin;
			m_nCaretAddrEnd = nEnd;
			Invalidate(FALSE);
		}
	}
	
	TrackMouseMove(TRUE, pDC);
		
	if (((m_nCurArea < 0) || (m_nCurArea > 0x10)) && (m_nStyle & PPDUMP_BAR_ALL))
		UpdateControlBar(pDC);

	CWnd::OnMouseMove(nFlags, point);

	//Setup event of leave mouse
	CWnd*				wndUnderMouse = NULL;
	CWnd*				wndActive = this;
	TRACKMOUSEEVENT		csTME;

	ClientToScreen(&point);
	wndUnderMouse = WindowFromPoint(point);

	wndActive = GetActiveWindow();

	if (wndUnderMouse && wndUnderMouse->m_hWnd == m_hWnd && wndActive)
	{
		if (!m_bMouseOverCtrl)
		{
			m_bMouseOverCtrl = TRUE;
			csTME.cbSize = sizeof(csTME);
			csTME.dwFlags = TME_LEAVE;
			csTME.hwndTrack = m_hWnd;
			::_TrackMouseEvent(&csTME);
		}
	}
	else m_bMouseOverCtrl = FALSE;

	if (m_pToolTip.m_hWnd != NULL)
	{
		if ((m_nCurrentAddr >= 0) && (m_nCurArea > 0x11))
		{
			if (m_nCurrentAddr != m_nAddressToolTip)
			{
				m_pToolTip.Activate(FALSE);
				m_pToolTip.UpdateTipText(GetToolTipString(m_nCurrentAddr), this, 1);
				//			m_pToolTip.Activate(TRUE);
				m_nAddressToolTip = m_nCurrentAddr;
			}
			else m_pToolTip.Activate(TRUE);
		}
		else
		{	
			m_pToolTip.UpdateTipText("", this, 1);
			m_pToolTip.Activate(FALSE);
			m_nAddressToolTip = -1;
		}
	}
	else m_nAddressToolTip = -1;

	if (pDC)
		ReleaseDC(pDC);
}

// Handler for WM_MOUSELEAVE
LRESULT CPPDumpCtrl::OnMouseLeave(WPARAM wParam, LPARAM lParam)
{
	m_bMouseOverCtrl = FALSE;
	TrackMouseMove();

	return 0;
} // End of OnMouseLeave

//Added by Darren Schroeder
BOOL CPPDumpCtrl::OnMouseWheel(UINT nFlags, short zDelta, CPoint pt) 
{
	if (zDelta < 0)
        OnVScroll(SB_LINEDOWN,0,0);
    else
        OnVScroll(SB_LINEUP,0,0);

    return CWnd::OnMouseWheel(nFlags, zDelta, pt);
}

void CPPDumpCtrl::OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar) 
{
	TRACE(_T("CPPDumpCtrl::OnVScroll()\n"));
	//If in-place edit is exist, then delete him
	if (m_nEditedArea > 0x10)
		KillEdit();

	// TODO: Add your message handler code here and/or call default
	int nMax;
	int nMin;
	int nNow = m_pVScroll.GetScrollPos();
	m_pVScroll.GetScrollRange(&nMin, &nMax);
	switch (nSBCode)
	{
	case SB_TOP: 
		nNow = nMin; 
		break;
	case SB_BOTTOM: 
		nNow = nMax; 
		break;
	case SB_LINEDOWN: 
		nNow ++; 
		break;
	case SB_LINEUP: 
		nNow --; 
		break;
	case SB_PAGEDOWN: 
		nNow += (m_nMaxDataOnScreen / m_nDataInLines); 
		break;
	case SB_PAGEUP: 
		nNow -= (m_nMaxDataOnScreen / m_nDataInLines); 
		break;
//	case SB_THUMBPOSITION: 
	case SB_THUMBTRACK: 
		//Added 
		SCROLLINFO si;
		ZeroMemory (&si, sizeof(SCROLLINFO));
		si.cbSize = sizeof(SCROLLINFO);
		si.fMask = SIF_TRACKPOS;
		// Call GetScrollInfo to get current tracking 
		// position in si.nTrackPos
		if (!m_pVScroll.GetScrollInfo (&si, SIF_TRACKPOS))
			return; // GetScrollInfo failed
		nNow = si.nTrackPos ;
		break;
	}

	if (nNow > nMax)
		nNow = nMax;
	else if (nNow < nMin)
		nNow = nMin;

	m_pVScroll.SetScrollPos(nNow, true);
	
	nNow *= m_nDataInLines;
	if (nNow != m_nBeginAddress)
	{
		m_nBeginAddress = nNow;
		Invalidate(FALSE);
		SendNotify(UDM_PPDUMPCTRL_BEGIN_ADDR, m_nBeginAddress, 0);

		CPoint pt;
		::GetCursorPos(&pt);
		ScreenToClient(&pt);
		OnMouseMove(0, pt);
	}
	
	CWnd::OnVScroll(nSBCode, nPos, pScrollBar);
}

void CPPDumpCtrl::OnPaint() 
{
	TRACE(_T("CPPDumpCtrl::OnPaint()\n"));
	CPaintDC dc(this); // device context for painting

	//If the window is not visible then don't draw the control
	if (!::IsWindow(m_hWnd))
		return;

	if (m_nCaretAddrBegin >= m_nLengthData)
	{
		m_nCaretAddrBegin = 0;
		m_nCaretAddrEnd = 0;
	}

	//Set colors of the control
	BOOL bDisable = GetStyle() & WS_DISABLED;
	if (bDisable)
	{
		// if in-place edit is exist
		KillEdit();
	}
	
	//Once create the vertical scrollbar
	if (m_pVScroll.m_hWnd == NULL)
		m_pVScroll.Create (WS_CHILD | WS_VISIBLE | SBS_VERT | SBS_RIGHTALIGN, CRect (0, 0, 100, 100), this, 100);
	m_pVScroll.EnableWindow(!bDisable);
	
	// Get the client rect.
	CRect rect, rcClient;
	GetClientRect(rect);
	rcClient = rect;

	// Create a memory device-context. This is done to help reduce
	// screen flicker, since we will paint the entire control to the
	// off screen device context first.CDC memDC;
	CMemDC memDC(&dc);
//	CDC memDC;
//	CBitmap bitmap;
//	memDC.CreateCompatibleDC(&dc);
//	bitmap.CreateCompatibleBitmap(&dc, rect.Width(), rect.Height());
//	CBitmap* pOldBitmap = memDC.SelectObject(&bitmap);

	memDC.FillSolidRect(rect, bDisable ? m_crDisableBk : m_crColor [PPDUMP_COLOR_DATA_BK]);

	CFont * pFont = memDC.SelectObject(&m_font);
	memDC.SetBkMode(TRANSPARENT);

	memDC.SetTextColor(bDisable ? m_crDisableFg : m_crColor [PPDUMP_COLOR_DATA_FG]);
	
	TEXTMETRIC tm;
	memDC.GetTextMetrics(&tm);
	
	//Gets the size of the current font
	m_nWidthFont = tm.tmAveCharWidth;
	m_nHeightFont = (int)((double)tm.tmHeight * 1.2);

	//Vertical Splits of the client area
	VerticalSplitClientArea(&memDC, rect);

	//Draws the control bar
	rect.top = DrawControlBar(&memDC, rect, bDisable);

	//Draws the status bar
	rect.top = DrawStatusBar(&memDC, rect, bDisable);

	//Adds the rects of the fields
	for (int i = 0; i < (PPDUMP_BAR_MAX_AREAS + 1); i++)
	{
		m_rFieldArea [i].bottom = rect.bottom;
		m_rFieldArea [i].top = rect.top;
	}

	m_nMaxDataOnScreen = GetMaxDataOnScreen();

	//Draws the fields
	if ((m_nStyle & PPDUMP_FIELD_ADDRESS) && m_nDataInLines)
		DrawAddressField(&memDC, bDisable);
	if (m_nStyle & PPDUMP_FIELD_HEX)
		DrawHexField(&memDC, bDisable);
	if (m_nStyle & PPDUMP_FIELD_DEC)
		DrawDecField(&memDC, bDisable);
	if (m_nStyle & PPDUMP_FIELD_BIN)
		DrawBinField(&memDC, bDisable);
	if (m_nStyle & PPDUMP_FIELD_OCT)
		DrawOctField(&memDC, bDisable);
	if (m_nStyle & PPDUMP_FIELD_ASCII)
		DrawASCIIField(&memDC, bDisable);

	//Get the rect of the scrollbar
	rect = m_rFieldArea [PPDUMP_BAR_MAX_AREAS];
	rect.left = rect.right - ::GetSystemMetrics(SM_CXVSCROLL);

	//Calculate the limits of the scrollbar
	int nPagesData = 0;
	if (m_nDataInLines)
	{
		nPagesData = (m_nLengthData - m_nMaxDataOnScreen) / m_nDataInLines;
		if (nPagesData >= 0)
		{
			if (m_nLengthData % m_nDataInLines)
				nPagesData ++;
		}
		else nPagesData = 0;
	}
	else m_nDataInLines = 1; 


	m_pVScroll.SetScrollRange(0, nPagesData, FALSE);
	m_pVScroll.SetScrollPos(nPagesData ? (m_nBeginAddress / m_nDataInLines) : 0, FALSE);
	m_pVScroll.ShowWindow(nPagesData > 0);

	//Redraws the scrollbar
	m_pVScroll.MoveWindow(rect);
	
	if (nPagesData > 0)
	{
		//Get the clip region
		CRgn rgn;
		rgn.CreateRectRgnIndirect(rect);
		if (m_nLengthData > 0)
			dc.SelectClipRgn(&rgn, RGN_XOR);
	}
	TrackMouseMove(TRUE, &memDC);

	if (m_bFocused)
	{
		memDC.SetTextColor(::GetSysColor(COLOR_WINDOWTEXT));
		memDC.SetBkColor(::GetSysColor(COLOR_WINDOW));
		CPen pen (PS_SOLID, 1, ::GetSysColor(COLOR_WINDOWTEXT)),
			* penOld = memDC.SelectObject(&pen);
//		rect = rcClient;
//		rect.DeflateRect(2, 2, 2, 2);
		memDC.DrawFocusRect(rcClient);
		memDC.SelectObject(penOld);
	}

	//Copy the memory device context back into the original DC via BitBlt().
//	dc.BitBlt(rcClient.left, rcClient.top, rcClient.Width(), rcClient.Height(), &memDC, 0,0, SRCCOPY);
	
	//Cleanup resources.
	memDC.SelectObject(pFont);
//	memDC.SelectObject(pOldBitmap);
//	memDC.DeleteDC();
//	bitmap.DeleteObject();
}

BOOL CPPDumpCtrl::KillEdit()
{
	//If edit is exist then kill him
	if (m_pEdit != NULL)
	{
		delete m_pEdit;
		m_pEdit = NULL;
		return TRUE;
	}
	return FALSE;
}

void CPPDumpCtrl::InitToolTip()
{
	if (m_pToolTip.m_hWnd == NULL)
	{
		// Create ToolTip control
		m_pToolTip.Create(this);
		// Create inactive
		m_pToolTip.Activate(TRUE);
		// Enable multiline
		m_pToolTip.SendMessage(TTM_SETMAXTIPWIDTH, 0, 400);
		// Sets delay time to show the tooltip
	} // if*/
}

///////////////////////////////////////////////////////////
//
// Format string:
//   % [direction] [length] [type]
//
//   direction - the direction of data ('+'(blank) = default value or '-' = negative)
//               Default value is a high->low, Negative value is a low->high
//   length    - the number of the byte ('0'-'4', when '0'(blank) default value of the control)
//   type      - the type of the value:
//
//            R - address
//            H - hex
//            D - dec
//            B - bin
//            O - oct
//            A - ascii
//
//
///////////////////////////////////////////////////////////
CString CPPDumpCtrl::GetToolTipString(int nAddress)
{
	//Format string is empty
	if (m_sFormatToolTip.IsEmpty())
		return m_sFormatToolTip;

	CString str = "";

	int nLength = m_sFormatToolTip.GetLength();
	BOOL bCmd = FALSE;
	int  nDir;
	int  nNum;
	int  nBeginLinePos = 0;
	int  j;
	for (int i = 0; i < nLength; i++)
	{
		if (bCmd)
		{
			switch (m_sFormatToolTip.GetAt(i))
			{
			case (TCHAR)'+':
				nDir = 1;
				break;
			case (TCHAR)'-':
				nDir = 2;
				break;
			case (TCHAR)'0':
			case (TCHAR)'1':
			case (TCHAR)'2':
			case (TCHAR)'3':
			case (TCHAR)'4':
				nNum = m_sFormatToolTip.GetAt(i) - (TCHAR)'0';
				break;
			case (TCHAR)'R':
				if (!nNum)
				{
					nNum = m_nCharsData [PPDUMP_BAR_AREA_ADDRESS] / 2;
					if (m_nCharsData [PPDUMP_BAR_AREA_ADDRESS] & 0x1)
						nNum ++;
				}
				str += FormatingString(PPDUMP_BAR_AREA_ADDRESS, nAddress, nNum);
				bCmd = FALSE;
				break;
			case (TCHAR)'H':
				str += FormatingString(PPDUMP_BAR_AREA_HEX, GetDataFromCurrentAddress(nAddress, TRUE ,nDir, nNum), nNum);
				bCmd = FALSE;
				break;
			case (TCHAR)'D':
				str += FormatingString(PPDUMP_BAR_AREA_DEC, GetDataFromCurrentAddress(nAddress, TRUE ,nDir, nNum), nNum);
				bCmd = FALSE;
				break;
			case (TCHAR)'B':
				str += FormatingString(PPDUMP_BAR_AREA_BIN, GetDataFromCurrentAddress(nAddress, TRUE ,nDir, nNum), nNum);
				bCmd = FALSE;
				break;
			case (TCHAR)'O':
				str += FormatingString(PPDUMP_BAR_AREA_OCT, GetDataFromCurrentAddress(nAddress, TRUE ,nDir, nNum), nNum);
				bCmd = FALSE;
				break;
			case (TCHAR)'A':
				str += FormatingString(PPDUMP_BAR_AREA_ASCII, GetDataFromCurrentAddress(nAddress, TRUE ,nDir, nNum), nNum);
				bCmd = FALSE;
				break;
			case (TCHAR)'n':
				str += _T("\r\n");
				nBeginLinePos = str.GetLength();
				bCmd = FALSE;
				break;
			case (TCHAR)'t':
				nNum = 4 - ((str.GetLength() - nBeginLinePos) % 4);
				for (j = 0; j < nNum; j++)
					str += (TCHAR)' '; //emulation of the tabulation
				bCmd = FALSE;
				break;
			default:
				bCmd = FALSE;
				str += m_sFormatToolTip.GetAt(i);
				break;
			}
		}
		else
		{
			if (m_sFormatToolTip.GetAt(i) == (TCHAR)'%')
			{
				bCmd = TRUE;
				nDir = 0;
				nNum = 0;
			}
			else str += m_sFormatToolTip.GetAt(i);
		}
	}

	return str;
}

///////////////////////////////////////////////////////////////////////////
//
// nIndex - the index of the value
//
///////////////////////////////////////////////////////////////////////////
CString CPPDumpCtrl::FormatingString(int nIndex, int nValue, int nLength /* = 0 */)
{
	CString str = "";
	CString str1 = "";
	int i;
	
	if (!nLength)
		nLength = (m_nStyle & PPDUMP_WORD_DATA) ? 2 : 1;
	
	switch (nIndex)
	{
	case PPDUMP_BAR_AREA_ADDRESS:
	case PPDUMP_BAR_AREA_HEX:
		//Hex
		str1.Format(_T("%%.%dX"), nLength * 2); //Two chars to one byte
		str.Format(str1, nValue);
		break;
	case PPDUMP_BAR_AREA_DEC:
		//Dec
		str.Format(_T("%d"), nValue);
		break;
	case PPDUMP_BAR_AREA_BIN:
		//Bin
		nLength *= 8;
		for (i = 0; i < nLength; i++)
		{
			if (!(i % 8) && i)
				str = _T("-") + str;
			str = ((nValue & 0x1) ? (TCHAR)'1' : (TCHAR)'0') + str;
			nValue >>= 1;
		}
		break;
	case PPDUMP_BAR_AREA_OCT:
		//Oct
		str.Format(_T("%o"), nValue);
		break;
	case PPDUMP_BAR_AREA_ASCII:
		//Ascii
		if ((nValue < 0x20) && m_chSpecCharView)
			str = m_chSpecCharView;
		else
			str = (TCHAR)nValue;
		break;
	}

	return str;
}

LRESULT CPPDumpCtrl::SendNotify(UINT uNotifyCode, UINT nAddress, UINT nValue)
{
	TRACE(_T("CPPDumpCtrl::SendNotify()\t%X\n"), uNotifyCode);

	// Make sure this is a valid window
	if (!IsWindow(GetSafeHwnd()))
		return 0L;

	// See if the user wants to be notified
	if (!GetNotify())
		return 0L;

	NM_PPDUMP_CTRL lpnm;
	
	lpnm.iAddress	  = nAddress;
	lpnm.iValue		  = nValue;
	lpnm.hdr.hwndFrom = m_hWnd;
    lpnm.hdr.idFrom   = GetDlgCtrlID();
    lpnm.hdr.code     = uNotifyCode;
	
	::SendMessage(m_hParentWnd, WM_NOTIFY, lpnm.hdr.idFrom, (LPARAM)&lpnm);

	return 0L;
}

void CPPDumpCtrl::MoveCaretAddress(int nIndex, BOOL bEdited /* = FALSE */, UINT nValue /* = 0 */)
{
	if (bEdited)
		CompleteEditValue(nValue); //The notification from the edit
	else KillEdit();

	//The current address is the caret address
	int nNow = m_nCaretAddrBegin;
	int nBegin = 0;
	
	switch (nIndex)
	{
	case PPDUMP_MOVE_LEFT:
		nNow = m_nCaretAddrBegin - 1;
		break;
	case PPDUMP_MOVE_RIGHT:
		nNow = m_nCaretAddrBegin + 1;
		break;
	case PPDUMP_MOVE_UP:
		nNow = m_nCaretAddrBegin - m_nDataInLines;
		break;
	case PPDUMP_MOVE_DOWN:
		nNow = m_nCaretAddrBegin + m_nDataInLines;
		break;
	case PPDUMP_MOVE_PAGE_UP:
		nNow = m_nCaretAddrBegin - m_nMaxDataOnScreen;
		if (nNow < 0)
		{
			nBegin = 0;
			nNow = m_nCaretAddrBegin % m_nDataInLines;
		}
		break;
	case PPDUMP_MOVE_PAGE_DOWN:
		nNow = m_nCaretAddrBegin + m_nMaxDataOnScreen;
		break;
	case PPDUMP_MOVE_FIRST_DATA:
		nNow = 0;
		break;
	case PPDUMP_MOVE_LAST_DATA:
		nNow = m_nLengthData - 1;
		break;
	case PPDUMP_MOVE_BEGIN_LINE:
		nNow = (nNow / m_nDataInLines) * m_nDataInLines;
		break;
	case PPDUMP_MOVE_END_LINE:
		nNow = (nNow / m_nDataInLines) * m_nDataInLines + m_nDataInLines - 1;
		if (nNow >= m_nLengthData)
			nNow = m_nLengthData - 1;
		break;
	case PPDUMP_MOVE_NEXT_FIELD:
		m_nEditedArea = GetNextField(m_nEditedArea);
		break;
	case PPDUMP_MOVE_PREV_FIELD:
		m_nEditedArea = GetPrevField(m_nEditedArea);
		break;
	}
	
	if (nNow >= m_nLengthData)
	{
		nBegin = (m_nCaretAddrBegin / m_nDataInLines) * m_nDataInLines + m_nDataInLines;
		
		if (nBegin < m_nLengthData)
			nNow = m_nLengthData - 1;
		else
			nNow = m_nCaretAddrBegin;
	}
	else if (nNow >= 0)
		SetSelectRange(nNow, -1, FALSE);
	else nNow = 0;

	SetVisibleAddress(nNow);

	if (bEdited)
	{
		m_nEditedAddress = m_nCaretAddrBegin;
		SetEditedValue();
	}
}

////////////////////////////////////////////////////////////////////
// Sets the first address on the screen, so that the specified
// address on the screen has been seen
//
//
////////////////////////////////////////////////////////////////////
BOOL CPPDumpCtrl::SetVisibleAddress(int nAddress)
{
	BOOL bMove = FALSE; //m_nBeginAddress no move

	//Gets the address of first data in line
	int nVal = (nAddress / m_nDataInLines) * m_nDataInLines;

	if (nVal < m_nBeginAddress)
	{
		//New address less then current
		bMove = TRUE;
		m_nBeginAddress = nVal;
	}
	else if (nVal >= (m_nBeginAddress + m_nMaxDataOnScreen))
	{
		//New address more then current
		bMove = TRUE;
		m_nBeginAddress = nVal - m_nMaxDataOnScreen + m_nDataInLines;
	}

	//If current address was moved then to notify the parent
	if (bMove && GetNotify())
	{
		SendNotify(UDM_PPDUMPCTRL_BEGIN_ADDR, m_nBeginAddress, 0);
	}
	Invalidate(FALSE);

	return bMove;
}

void CPPDumpCtrl::NotifyEditEnter(NMHDR * pNMHDR, LRESULT * result)
{
	TRACE (_T("CPPDumpCtrl::NotifyEditEnter()\n"));

	*result = 0;
	NM_PPNUM_EDIT * pNotify = (NM_PPNUM_EDIT*)pNMHDR;
	CompleteEditValue(pNotify->iValue);
}

void CPPDumpCtrl::NotifyEditCancel(NMHDR * pNMHDR, LRESULT * result)
{
	TRACE (_T("CPPDumpCtrl::NotifyEditCancel()\n"));

	*result = 0;
	KillEdit();
}

void CPPDumpCtrl::NotifyEditMove(NMHDR * pNMHDR, LRESULT * result)
{
	TRACE (_T("CPPDumpCtrl::NotifyEditMove()\n"));

	*result = 0;
	if ((m_nEditedArea == 0x1) || (m_nEditedArea == 0x11))
		return;

	NM_PPNUM_EDIT * pNotify = (NM_PPNUM_EDIT*)pNMHDR;
	MoveCaretAddress(pNotify->iEvent, TRUE, pNotify->iValue);
}

void CPPDumpCtrl::NotifyEditHotKeys(NMHDR * pNMHDR, LRESULT * result)
{
	TRACE (_T("CPPDumpCtrl::NotifyEditHotKeys()\n"));

	*result = 0;
	NM_PPNUM_EDIT * pNotify = (NM_PPNUM_EDIT*)pNMHDR;
	HandleHotkeys(pNotify->iEvent, TRUE, pNotify->iValue);
}

void CPPDumpCtrl::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags) 
{
	switch (nChar)
	{
	case VK_LEFT:
		MoveCaretAddress(PPDUMP_MOVE_LEFT);
		return;
	case VK_RIGHT:
		MoveCaretAddress(PPDUMP_MOVE_RIGHT);
		return;
	case VK_UP:
		MoveCaretAddress(PPDUMP_MOVE_UP);
		return;
	case VK_DOWN:
		MoveCaretAddress(PPDUMP_MOVE_DOWN);
		return;
	case VK_PRIOR:
		MoveCaretAddress(PPDUMP_MOVE_PAGE_UP);
		return;
	case VK_NEXT:
		MoveCaretAddress(PPDUMP_MOVE_PAGE_DOWN);
		return;
	case VK_HOME:
		if (::GetKeyState(VK_CONTROL) < 0)
			MoveCaretAddress(PPDUMP_MOVE_FIRST_DATA);
		else
			MoveCaretAddress(PPDUMP_MOVE_BEGIN_LINE);
		return;
	case VK_END: 
		if (::GetKeyState(VK_CONTROL) < 0)
			MoveCaretAddress(PPDUMP_MOVE_LAST_DATA);
		else
			MoveCaretAddress(PPDUMP_MOVE_END_LINE);
		return;
	}

	CWnd::OnKeyDown(nChar, nRepCnt, nFlags);
}

BOOL CPPDumpCtrl::HandleHotkeys(UINT uNotifyCode, BOOL bFromEdit /* = FALSE */, UINT nValue /* = 0 */)
{
	if (IsReadOnly())
		return FALSE;

	int nArea = -1;
	
	switch(uNotifyCode) 
	{
	case PPDUMP_HOTKEY_HEX:
		if (IsExistField(0x2))
			nArea = 0x2;
		break;
	case PPDUMP_HOTKEY_DEC:
		if (IsExistField(0x3))
			nArea = 0x3;
		break;
	case PPDUMP_HOTKEY_BIN:
		if (IsExistField(0x4))
			nArea = 0x4;
		break;
	case PPDUMP_HOTKEY_OCT:
		if (IsExistField(0x5))
			nArea = 0x5;
		break;
	case PPDUMP_HOTKEY_ASCII:
		if (IsExistField(0x6))
			nArea = 0x6;
		break;
	}

	if (nArea < 0)
		return FALSE;

	if (bFromEdit && (m_nEditedArea == nArea))
		return FALSE;

	if (!bFromEdit)
		m_nEditedAddress = m_nCaretAddrBegin;
	else
		KillEdit();
	
	m_nEditedArea = nArea;
	UpdateControlBar(NULL, FALSE, m_nEditedAddress);
	SetEditedValue();
	
	return TRUE;
}

int CPPDumpCtrl::GetNextField(int nArea)
{
	int nOldArea = nArea;
	for (int i = 0; i < 5; i++)
	{
		nArea ++;
		if ((nArea & 0xF) > 6)
			nArea = (nArea & 0xF0) + 0x2;
		if (IsExistField(nArea))
			return nArea;
	}
	return nOldArea;
}

int CPPDumpCtrl::GetPrevField(int nArea)
{
	int nOldArea = nArea;
	for (int i = 0; i < 5; i++)
	{
		nArea --;
		if ((nArea & 0xF) < 2)
			nArea = (nArea & 0xF0) + 0x6;
		if (IsExistField(nArea))
			return nArea;
	}
	return nOldArea;
}

BOOL CPPDumpCtrl::IsExistField(int nArea)
{
	switch (nArea)
	{
	case 0x01:
		return (m_nStyle & PPDUMP_BAR_ADDRESS);
	case 0x02:
		return (m_nStyle & PPDUMP_BAR_HEX);
	case 0x03:
		return (m_nStyle & PPDUMP_BAR_DEC);
	case 0x04:
		return (m_nStyle & PPDUMP_BAR_BIN);
	case 0x05:
		return (m_nStyle & PPDUMP_BAR_OCT);
	case 0x06:
		return (m_nStyle & PPDUMP_BAR_ASCII);
	case 0x11:
		return (m_nStyle & PPDUMP_FIELD_ADDRESS);
	case 0x12:
		return (m_nStyle & PPDUMP_FIELD_HEX);
	case 0x13:
		return (m_nStyle & PPDUMP_FIELD_DEC);
	case 0x14:
		return (m_nStyle & PPDUMP_FIELD_BIN);
	case 0x15:
		return (m_nStyle & PPDUMP_FIELD_OCT);
	case 0x16:
		return (m_nStyle & PPDUMP_FIELD_ASCII);
	}
	return FALSE;
}

int CPPDumpCtrl::GetAddressForControlBar()
{
	int nAddr = 0;
	if (m_pEdit == NULL)
	{
		//The edit is not exist
		if (m_rLastTrackRect.IsRectEmpty())
			nAddr = m_nCaretAddrBegin;
		else if (m_nCurArea < 0x10)
			nAddr = m_nCaretAddrBegin;
		else
			nAddr = m_nCurrentAddr;
	}
	else
	{
		//The edit is exist
		if (m_nEditedArea < 0x11)
			nAddr = m_nEditedAddress;
		else if (m_rLastTrackRect.IsRectEmpty())
			nAddr = m_nEditedAddress;
		else if (m_nCurArea < 0x10)
			nAddr = m_nEditedAddress;
		else
			nAddr = m_nCurrentAddr;
	}

	return nAddr;
}

int CPPDumpCtrl::GetMaxDataOnScreen()
{
	CRect rect = m_rFieldArea[PPDUMP_BAR_MAX_AREAS];
	rect.top += m_nHeightFont / 4;

	int nLines = rect.Height() / m_nHeightFont;

	return (nLines * m_nDataInLines);
}

BOOL CPPDumpCtrl::CompleteEditValue(UINT nValue, BOOL bDelete /* = TRUE */)
{
	//If edited value is not exist
	if (m_pEdit == NULL)
		return FALSE;

	//If value with error
	if (!m_pEdit->IsValidate())
		return FALSE;

	//If value was not changed
	if (m_pEdit->IsChanged())
	{
		if ((m_nEditedArea & 0xF) == 1)
		{
			//if edited value is an address
			SetSelectRange(nValue - m_nOffsetAddress, -1);
		}
		else
			SendNotify(UDM_PPDUMPCTRL_CHANGE_DATA, m_nEditedAddress, nValue);
	}

	if (bDelete)
	{
		KillEdit();
		Invalidate(FALSE);
	}
	return TRUE;
}

void CPPDumpCtrl::SetEditedValue(int nAddr /* = -1 */, int nArea /* = -1 */)
{
	TRACE(_T("CPPDumpCtrl::SetEditedValue()\n"));
	
	//If editing address as parameter then keep him
	if (nAddr >= 0)
		m_nEditedAddress = nAddr;
	//If editing area as parameter then keep it
	if (nArea >= 0)
		m_nEditedArea = nArea;

	if (IsReadOnly() && ((m_nEditedArea & 0xF) != 0x1))
		return;

	//The editing value must be on the screen
	if (m_nEditedArea > 0x10)
		SetVisibleAddress(m_nEditedAddress);
	
	CRect rect = GetRectAddress(m_nEditedAddress, m_nEditedArea);
	
	m_pEdit = new CPPNumEdit;
	m_pEdit->Create(WS_CHILD | WS_VISIBLE | ES_CENTER, rect, this, nIdEdit);
	m_pEdit->SetFont(&m_font);
	m_pEdit->SetColor(CPPNumEdit::PPNUM_COLOR_VALID_FG, m_crColor [PPDUMP_COLOR_EDIT_FG], FALSE);
	m_pEdit->SetColor(CPPNumEdit::PPNUM_COLOR_VALID_BK, m_crColor [PPDUMP_COLOR_EDIT_BK], FALSE);
	m_pEdit->SetColor(CPPNumEdit::PPNUM_COLOR_NOT_VALID_FG, m_crColor [PPDUMP_COLOR_EDIT_ERR_FG], FALSE);
	m_pEdit->SetColor(CPPNumEdit::PPNUM_COLOR_NOT_VALID_BK, m_crColor [PPDUMP_COLOR_EDIT_ERR_BK]);
	UINT nIndexValue;
	UINT nTypeValue = (m_nStyle & PPDUMP_WORD_DATA) ? CPPNumEdit::PPNUM_VALUE_WORD : CPPNumEdit::PPNUM_VALUE_BYTE;
	UINT nMin = 0;
	UINT nMax = 0x1;
	
	UINT nValue;

	if ((m_nEditedArea & 0x0F) == 0x1)
		nValue = m_nEditedAddress + m_nOffsetAddress;
	else
		nValue = GetDataFromCurrentAddress(m_nEditedAddress);
	
	switch (m_nEditedArea & 0xF)
	{
	case 0x01:
		nTypeValue = CPPNumEdit::PPNUM_VALUE_CUSTOM;
		nMin = m_nOffsetAddress;
		nMax = nMin + m_nLengthData - 1;
	case 0x02:
		nIndexValue = CPPNumEdit::PPNUM_VALUE_HEX;
		break;
	case 0x03:
		nIndexValue = CPPNumEdit::PPNUM_VALUE_DEC;
		break;
	case 0x04:
		nIndexValue = CPPNumEdit::PPNUM_VALUE_BIN;
		break;
	case 0x05:
		nIndexValue = CPPNumEdit::PPNUM_VALUE_OCT;
		break;
	case 0x06:
		nIndexValue = CPPNumEdit::PPNUM_VALUE_ASCII;
		break;
	}
	m_pEdit->SetValue(nValue, nIndexValue, nTypeValue, nMin, nMax);
	
	m_pEdit->SetFocus();
	m_pEdit->SetSel(0, -1);
}

///////////////////////////////////////////////////////////////////
//
// int GetDataUnderCursor(CPoint pt, LPINT nAddress)
// Gets the data under the cursor
// 
// Parameters:
//   pt       [in]  - the current coordinates of the cursor
//   nAddress [out] - the address of the data (if exist) under the cursor
// 
// Return value
//   The area of the data under the cursor
//
///////////////////////////////////////////////////////////////////
int CPPDumpCtrl::GetDataUnderCursor(CPoint pt, LPINT nAddress)
{
	*nAddress = -1;
	int nArea = -1;
	CRect rect;

	//Determines the area under the cursor
	if (m_nStyle & PPDUMP_BAR_ALL)
	{
		if (m_rBarArea [PPDUMP_BAR_MAX_AREAS].PtInRect(pt))
		{
			//The cursor into the Control Bar
			for (int i = 0; (i < 6) && (nArea == -1); i++)
			{
				if (IsExistField(i + 1))
				{
					if (m_rBarArea [i].PtInRect(pt))
					{
						nArea = i + 1;
						rect = m_rBarArea [i];
					}
				}
			}
			if (nArea == -1)
				return -1;
		}
	}

	if ((m_nStyle & PPDUMP_FIELD_ALL) && (nArea == -1))
	{
		if (m_rFieldArea [PPDUMP_BAR_MAX_AREAS].PtInRect(pt))
		{
			//The cursor into the Data Fields
			for (int i = 0; (i < 6) && (nArea == -1); i++)
			{
				if (IsExistField(i + 0x11))
				{
					if (m_rFieldArea [i].PtInRect(pt))
					{
						nArea = i + 0x11;
						rect = m_rFieldArea [i];
					}
				}
			}
			if (nArea == -1)
				return -1;
		}
	}

	//Determines address under the cursor
	if (nArea < 0x10)
	{
		//The cursor over the control bar
		*nAddress = GetAddressForControlBar();
		return nArea;
	}

	int nColumn;
	rect.top += m_nHeightFont / 4;
	rect.bottom = rect.top + (rect.Height() / m_nHeightFont) * m_nHeightFont;
	if (nArea != 0x16)
	{
		//For all data fields except Ascii Data Field
		rect.left += m_nWidthFont / 2;
		rect.right -= (m_nWidthFont / 2 + 1);
		nColumn = (pt.x - rect.left) / m_nWidthFont / (m_nCharsData [nArea - 0x11] + 1);
	}
	else
	{
		//For Ascii Data Field Only
		rect.left += m_nWidthFont - 1;
		rect.right -= (m_nWidthFont + 1);
		nColumn = (pt.x - rect.left) / (m_nWidthFont + 1);
	}
	//Retrive row and column data
	int nRow = (pt.y - rect.top) / m_nHeightFont;

	int nAddr = m_nBeginAddress + nRow * m_nDataInLines + nColumn; 

	if ((nAddr >= m_nLengthData) || !rect.PtInRect(pt))
		return - 1;
	
	*nAddress = nAddr;
	
	return nArea;
}

//////////////////////////////////////////////////////////////////////////
// Gets the rect of the address in specified area
//
//  In: nArea - the specified area
//      nAddress - the requered address
// Out: The bounding rect
//////////////////////////////////////////////////////////////////////////
CRect CPPDumpCtrl::GetRectAddress(int nAddress, int nArea)
{
	CRect rect;
	if (nArea > 0x10)
	{
		nArea -= 0x11;

		int nRow = (nAddress - m_nBeginAddress) / m_nDataInLines;
		int nCol = (nAddress - m_nBeginAddress) % m_nDataInLines;
		
		rect = m_rFieldArea [nArea];
		
		rect.top += nRow * m_nHeightFont + m_nHeightFont / 4;
		rect.bottom = rect.top + m_nHeightFont;
		
		if (nArea != PPDUMP_BAR_AREA_ASCII)
		{
			rect.left += m_nWidthFont / 2;
			rect.left = rect.left + nCol * m_nWidthFont * (m_nCharsData [nArea] + 1);
			rect.right = rect.left + m_nWidthFont * (m_nCharsData [nArea] + 1);
		}
		else
		{
			rect.left += m_nWidthFont - 1;
			rect.left += nCol * (m_nWidthFont + 1);
			rect.right = rect.left + m_nWidthFont + 2;
		}
	}
	else if (nArea > 0)
		rect = m_rBarArea [nArea - 1];
	else
		rect.SetRectEmpty();
	
	return rect;
}

void CPPDumpCtrl::TrackMouseMove(BOOL bDrawn /* = FALSE */, CDC * pDC /* = NULL */)
{
	if (!m_rLastTrackRect.IsRectEmpty() && IsTrackMouseMove())
	{
		BOOL bReleaseDC = FALSE;
		if (pDC == NULL)
		{
			pDC = GetDC();
			bReleaseDC = TRUE;
		}

		if (bDrawn)
		{
			pDC->Draw3dRect(m_rLastTrackRect, m_crColor[PPDUMP_COLOR_MOUSE_TRACK], m_crColor[PPDUMP_COLOR_MOUSE_TRACK]);
		}
		else
		{
			pDC->Draw3dRect(m_rLastTrackRect, m_crColor[PPDUMP_COLOR_DATA_BK], m_crColor[PPDUMP_COLOR_DATA_BK]);
			m_rLastTrackRect.SetRectEmpty();
		}
		if (bReleaseDC)
			ReleaseDC(pDC);

	}
}

/////////////////////////////////////////////////////////////////////////////
//
//  CPPDumpCtrl::TrackDataField  (public member function)
//    Track the data of the hex field
//
//  Parameters :
//		point	    [in] - Specifies the x- and y-coordinate of the cursor
//
//  Returns :
//		Number of the Data under the mouse, if none = -1
//
/////////////////////////////////////////////////////////////////////////////
BOOL CPPDumpCtrl::TrackDataField(UINT nIndex, CPoint point)
{
	CRect rect = m_rFieldArea [nIndex];
	rect.left += m_nWidthFont / 2;
	rect.right -= (m_nWidthFont / 2 + 1);
	rect.top += m_nHeightFont / 4;
	rect.bottom = rect.top + (rect.Height() / m_nHeightFont) * m_nHeightFont;

	if (!rect.PtInRect(point))
		return FALSE;
	
	//Retrive row and column data
	int nColumn = (point.x - rect.left) / m_nWidthFont / (m_nCharsData [nIndex] + 1);
	int nRow = (point.y - rect.top) / m_nHeightFont;

	int nData = nRow * m_nDataInLines + nColumn; 
	
	if ((m_nBeginAddress + nData) < m_nLengthData)
	{
		m_nCurrentAddr = m_nBeginAddress + nData;

		m_rLastTrackRect.left = rect.left + nColumn * m_nWidthFont * (m_nCharsData [nIndex] + 1);
		m_rLastTrackRect.top = rect.top + m_nHeightFont * nRow;
		m_rLastTrackRect.right = m_rLastTrackRect.left + m_nWidthFont * (m_nCharsData [nIndex] + 1);
		m_rLastTrackRect.bottom = m_rLastTrackRect.top + m_nHeightFont;

		return TRUE;
	}

	return FALSE;
}

/////////////////////////////////////////////////////////////////////////////
//
//  CPPDumpCtrl::TrackDataAsciiField  (public member function)
//    Track the data of the hex field
//
//  Parameters :
//		point	    [in] - Specifies the x- and y-coordinate of the cursor
//
//  Returns :
//		Number of the Data under the mouse, if none = -1
//
/////////////////////////////////////////////////////////////////////////////
BOOL CPPDumpCtrl::TrackDataAsciiField(CPoint point)
{
	CRect rect = m_rFieldArea [PPDUMP_BAR_AREA_ASCII];
	rect.left += m_nWidthFont - 1;
	rect.right -= (m_nWidthFont + 1);
	rect.top += m_nHeightFont / 4;
	rect.bottom = rect.top + (rect.Height() / m_nHeightFont) * m_nHeightFont;

	if (!rect.PtInRect(point))
		return FALSE;
	
	int nColumn = (point.x - rect.left) / (m_nWidthFont + 1);
	int nRow = (point.y - rect.top) / m_nHeightFont;

	int nData = nRow * m_nDataInLines + nColumn; 
	
	if ((m_nBeginAddress + nData) < m_nLengthData)
	{
		m_nCurrentAddr = m_nBeginAddress + nData;

		m_rLastTrackRect.left = rect.left + nColumn * (m_nWidthFont + 1);
		m_rLastTrackRect.top = rect.top + m_nHeightFont * nRow;
		m_rLastTrackRect.right = m_rLastTrackRect.left + m_nWidthFont + 2;
		m_rLastTrackRect.bottom = m_rLastTrackRect.top + m_nHeightFont;

		return TRUE;
	}

	return FALSE;
}

/////////////////////////////////////////////////////////////////////////////
//
//  CPPDumpCtrl::DrawAddressField  (public member function)
//    Draws the address field of the control
//
//  Parameters :
//		pDC		    [in] - the device context
//
//  Returns :
//		None
//
/////////////////////////////////////////////////////////////////////////////
void CPPDumpCtrl::DrawAddressField(CDC * pDC, BOOL bDisable)
{
	if (!(m_nStyle & PPDUMP_FIELD_ADDRESS))
		return;

	COLORREF crTemp = pDC->SetTextColor(bDisable ? m_crDisableFg : m_crColor [PPDUMP_COLOR_ADDRESS_FG]);
	CPen pen(PS_SOLID, 0, bDisable ? m_crDisableFg : m_crColor [PPDUMP_COLOR_SEPARATORS]);
	CPen * penOld = pDC->SelectObject(&pen);

	CRect rect = m_rFieldArea [PPDUMP_BAR_AREA_ADDRESS];

	if (m_nStyle & PPDUMP_SEPARATOR_LINES)
	{
		pDC->MoveTo(rect.right, rect.top);
		pDC->LineTo(rect.right, rect.bottom);
	}

	rect.DeflateRect(0, m_nHeightFont / 4, 0, m_nHeightFont);

	for (int nAddr = m_nBeginAddress; (nAddr < m_nLengthData) && (rect.top <= rect.bottom); nAddr += m_nDataInLines)
	{
		DrawAddressValue(pDC, rect, nAddr + m_nOffsetAddress, FALSE, bDisable);
		rect.top += m_nHeightFont;
	}
	pDC->SelectObject(penOld);
	pDC->SetTextColor(crTemp);
}

/////////////////////////////////////////////////////////////////////////////
//
//  CPPDumpCtrl::DrawHexField  (public member function)
//    Draws the hex field of the control
//
//  Parameters :
//		pDC		    [in] - the device context
//
//  Returns :
//		None
//
/////////////////////////////////////////////////////////////////////////////
void CPPDumpCtrl::DrawHexField(CDC * pDC, BOOL bDisable)
{
	if (!(m_nStyle & PPDUMP_FIELD_HEX))
		return;

	COLORREF crTemp = pDC->SetTextColor(bDisable ? m_crDisableFg : m_crColor [PPDUMP_COLOR_DATA_FG]);
	CPen pen(PS_SOLID, 0, bDisable ? m_crDisableFg : m_crColor [PPDUMP_COLOR_SEPARATORS]);
	CPen * penOld = pDC->SelectObject(&pen);

	CRect rect = m_rFieldArea [PPDUMP_BAR_AREA_HEX];

	if (m_nStyle & PPDUMP_SEPARATOR_LINES)
	{
		pDC->MoveTo(rect.right, rect.top);
		pDC->LineTo(rect.right, rect.bottom);
	}

	rect.DeflateRect(0, m_nHeightFont / 4, 0, m_nHeightFont);

	UINT nNewValue, nOldValue;
	CRect rData;

	for (int nAddr = m_nBeginAddress; (nAddr < m_nLengthData) && (rect.top <= rect.bottom); NULL)
	{
		rData = rect;
		for (int i = 0; (i < m_nDataInLines) && (nAddr < m_nLengthData); i++)
		{
			nNewValue = GetDataFromCurrentAddress(nAddr);
			nOldValue = GetDataFromCurrentAddress(nAddr, FALSE);
			if (!bDisable)
				pDC->SetTextColor((nNewValue == nOldValue) ? m_crColor [PPDUMP_COLOR_DATA_FG] : m_crColor [PPDUMP_COLOR_DATA_CHANGE_FG]);
			rData.left = DrawHexValue(pDC, rData, nNewValue, FALSE, IsAddressSelected(nAddr), bDisable);
			rData.left -= m_nWidthFont;
			nAddr ++;
		}
		rect.top += m_nHeightFont;
	}
	pDC->SelectObject(penOld);
	pDC->SetTextColor(crTemp);
}

/////////////////////////////////////////////////////////////////////////////
//
//  CPPDumpCtrl::DrawDecField  (public member function)
//    Draws the dec field of the control
//
//  Parameters :
//		pDC		    [in] - the device context
//
//  Returns :
//		None
//
/////////////////////////////////////////////////////////////////////////////
void CPPDumpCtrl::DrawDecField(CDC * pDC, BOOL bDisable)
{
	if (!(m_nStyle & PPDUMP_FIELD_DEC))
		return;

	COLORREF crTemp = pDC->SetTextColor(bDisable ? m_crDisableFg : m_crColor [PPDUMP_COLOR_DATA_FG]);
	CPen pen(PS_SOLID, 0, bDisable ? m_crDisableFg : m_crColor [PPDUMP_COLOR_SEPARATORS]);
	CPen * penOld = pDC->SelectObject(&pen);

	CRect rect = m_rFieldArea [PPDUMP_BAR_AREA_DEC];

	if (m_nStyle & PPDUMP_SEPARATOR_LINES)
	{
		pDC->MoveTo(rect.right, rect.top);
		pDC->LineTo(rect.right, rect.bottom);
	}

	rect.DeflateRect(0, m_nHeightFont / 4, 0, m_nHeightFont);

	UINT nNewValue, nOldValue;
	CRect rData;

	for (int nAddr = m_nBeginAddress; (nAddr < m_nLengthData) && (rect.top <= rect.bottom); NULL)
	{
		rData = rect;
		for (int i = 0; (i < m_nDataInLines) && (nAddr < m_nLengthData); i++)
		{
			nNewValue = GetDataFromCurrentAddress(nAddr);
			nOldValue = GetDataFromCurrentAddress(nAddr, FALSE);
			if (!bDisable)
				pDC->SetTextColor((nNewValue == nOldValue) ? m_crColor [PPDUMP_COLOR_DATA_FG] : m_crColor [PPDUMP_COLOR_DATA_CHANGE_FG]);
			rData.left = DrawDecValue(pDC, rData, nNewValue, FALSE, IsAddressSelected(nAddr), bDisable);
			rData.left -= m_nWidthFont;
			nAddr ++;
		}
		rect.top += m_nHeightFont;
	}
	pDC->SelectObject(penOld);
	pDC->SetTextColor(crTemp);
}

/////////////////////////////////////////////////////////////////////////////
//
//  CPPDumpCtrl::DrawBinField  (public member function)
//    Draws the bin field of the control
//
//  Parameters :
//		pDC		    [in] - the device context
//
//  Returns :
//		None
//
/////////////////////////////////////////////////////////////////////////////
void CPPDumpCtrl::DrawBinField(CDC * pDC, BOOL bDisable)
{
	if (!(m_nStyle & PPDUMP_FIELD_BIN))
		return;

	COLORREF crTemp = pDC->SetTextColor(bDisable ? m_crDisableFg : m_crColor [PPDUMP_COLOR_DATA_FG]);
	CPen pen(PS_SOLID, 0, bDisable ? m_crDisableFg : m_crColor [PPDUMP_COLOR_SEPARATORS]);
	CPen * penOld = pDC->SelectObject(&pen);

	CRect rect = m_rFieldArea [PPDUMP_BAR_AREA_BIN];

	if (m_nStyle & PPDUMP_SEPARATOR_LINES)
	{
		pDC->MoveTo(rect.right, rect.top);
		pDC->LineTo(rect.right, rect.bottom);
	}

	rect.DeflateRect(0, m_nHeightFont / 4, 0, m_nHeightFont);

	UINT nNewValue, nOldValue;
	CRect rData;

	for (int nAddr = m_nBeginAddress; (nAddr < m_nLengthData) && (rect.top <= rect.bottom); NULL)
	{
		rData = rect;
		for (int i = 0; (i < m_nDataInLines) && (nAddr < m_nLengthData); i++)
		{
			nNewValue = GetDataFromCurrentAddress(nAddr);
			nOldValue = GetDataFromCurrentAddress(nAddr, FALSE);
			if (!bDisable)
				pDC->SetTextColor((nNewValue == nOldValue) ? m_crColor [PPDUMP_COLOR_DATA_FG] : m_crColor [PPDUMP_COLOR_DATA_CHANGE_FG]);
			rData.left = DrawBinValue(pDC, rData, nNewValue, FALSE, IsAddressSelected(nAddr), bDisable);
			rData.left -= m_nWidthFont;
			nAddr ++;
		}
		rect.top += m_nHeightFont;
	}
	pDC->SelectObject(penOld);
	pDC->SetTextColor(crTemp);
}

/////////////////////////////////////////////////////////////////////////////
//
//  CPPDumpCtrl::DrawOctField  (public member function)
//    Draws the oct field of the control
//
//  Parameters :
//		pDC		    [in] - the device context
//
//  Returns :
//		None
//
/////////////////////////////////////////////////////////////////////////////
void CPPDumpCtrl::DrawOctField(CDC * pDC, BOOL bDisable)
{
	if (!(m_nStyle & PPDUMP_FIELD_OCT))
		return;

	COLORREF crTemp = pDC->SetTextColor(bDisable ? m_crDisableFg : m_crColor [PPDUMP_COLOR_DATA_FG]);
	CPen pen(PS_SOLID, 0, bDisable ? m_crDisableFg : m_crColor [PPDUMP_COLOR_SEPARATORS]);
	CPen * penOld = pDC->SelectObject(&pen);

	CRect rect = m_rFieldArea [PPDUMP_BAR_AREA_OCT];

	if (m_nStyle & PPDUMP_SEPARATOR_LINES)
	{
		pDC->MoveTo(rect.right, rect.top);
		pDC->LineTo(rect.right, rect.bottom);
	}

	rect.DeflateRect(0, m_nHeightFont / 4, 0, m_nHeightFont);

	UINT nNewValue, nOldValue;
	CRect rData;

	for (int nAddr = m_nBeginAddress; (nAddr < m_nLengthData) && (rect.top <= rect.bottom); NULL)
	{
		rData = rect;
		for (int i = 0; (i < m_nDataInLines) && (nAddr < m_nLengthData); i++)
		{
			nNewValue = GetDataFromCurrentAddress(nAddr);
			nOldValue = GetDataFromCurrentAddress(nAddr, FALSE);
			if (!bDisable)
				pDC->SetTextColor((nNewValue == nOldValue) ? m_crColor [PPDUMP_COLOR_DATA_FG] : m_crColor [PPDUMP_COLOR_DATA_CHANGE_FG]);
			rData.left = DrawOctValue(pDC, rData, nNewValue, FALSE, IsAddressSelected(nAddr), bDisable);
			rData.left -= m_nWidthFont;
			nAddr ++;
		}
		rect.top += m_nHeightFont;
	}
	pDC->SelectObject(penOld);
	pDC->SetTextColor(crTemp);
}

/////////////////////////////////////////////////////////////////////////////
//
//  CPPDumpCtrl::DrawAsciiField  (public member function)
//    Draws the ascii field of the control
//
//  Parameters :
//		pDC		    [in] - the device context
//
//  Returns :
//		None
//
/////////////////////////////////////////////////////////////////////////////
void CPPDumpCtrl::DrawASCIIField(CDC * pDC, BOOL bDisable)
{
	if (!(m_nStyle & PPDUMP_FIELD_ASCII))
		return;

	COLORREF crTemp = pDC->SetTextColor(bDisable ? m_crDisableFg : m_crColor [PPDUMP_COLOR_DATA_FG]);
	CPen pen(PS_SOLID, 0, bDisable ? m_crDisableFg : m_crColor [PPDUMP_COLOR_SEPARATORS]);
	CPen * penOld = pDC->SelectObject(&pen);

	CRect rect = m_rFieldArea [PPDUMP_BAR_AREA_ASCII];

	if (m_nStyle & PPDUMP_SEPARATOR_LINES)
	{
		pDC->MoveTo(rect.right, rect.top);
		pDC->LineTo(rect.right, rect.bottom);
	}

	rect.DeflateRect(0, m_nHeightFont / 4, 0, m_nHeightFont);

	UINT nNewValue, nOldValue;
	CRect rData;

	for (int nAddr = m_nBeginAddress; (nAddr < m_nLengthData) && (rect.top <= rect.bottom); NULL)
	{
		rData = rect;
		for (int i = 0; (i < m_nDataInLines) && (nAddr < m_nLengthData); i++)
		{
			nNewValue = GetDataFromCurrentAddress(nAddr);
			nOldValue = GetDataFromCurrentAddress(nAddr, FALSE);
			if (!bDisable)
				pDC->SetTextColor((nNewValue == nOldValue) ? m_crColor [PPDUMP_COLOR_DATA_FG] : m_crColor [PPDUMP_COLOR_DATA_CHANGE_FG]);
			rData.left = DrawAsciiValue(pDC, rData, nNewValue, FALSE, IsAddressSelected(nAddr), bDisable);
			rData.left -= m_nWidthFont * 2;
			nAddr ++;
		}
		rect.top += m_nHeightFont;
	}
	pDC->SelectObject(penOld);
	pDC->SetTextColor(crTemp);
}

/////////////////////////////////////////////////////////////////////////////
//
//  CPPDumpCtrl::VerticalSplitClientArea  (public member function)
//    The Verical spliting of the client area to the areas of the data fields
//
//  Parameters :
//		pDC		    [in] - the device context
//		rect		[in] - rect of the control
//
//  Returns :
//		None
//
/////////////////////////////////////////////////////////////////////////////
void CPPDumpCtrl::VerticalSplitClientArea(CDC * pDC, CRect rect)
{
	m_rFieldArea [PPDUMP_BAR_MAX_AREAS] = rect;
	if (m_nStyle & PPDUMP_FIELD_ADDRESS)
	{
		m_rFieldArea [PPDUMP_BAR_AREA_ADDRESS] = rect;
		m_rFieldArea [PPDUMP_BAR_AREA_ADDRESS].right = m_rFieldArea [PPDUMP_BAR_AREA_ADDRESS].left + m_nWidthFont * (m_nCharsData [PPDUMP_BAR_AREA_ADDRESS] + 2);
		rect.left = m_rFieldArea [PPDUMP_BAR_AREA_ADDRESS].right;
	}

	UINT nTemp = 0;
	int nMaxChars = (rect.Width() - ::GetSystemMetrics(SM_CXVSCROLL)) / m_nWidthFont;
	double nWidth = rect.Width() - ::GetSystemMetrics(SM_CXVSCROLL);
	double nOneData = 0;

	if (m_nStyle & PPDUMP_FIELD_HEX)
	{
		nTemp += m_nCharsData [PPDUMP_BAR_AREA_HEX] + 1;
		nMaxChars --;
		nOneData += (m_nCharsData [PPDUMP_BAR_AREA_HEX] + 1) * m_nWidthFont;
		nWidth -= m_nWidthFont;
	}
	if (m_nStyle & PPDUMP_FIELD_DEC)
	{
		nTemp += m_nCharsData [PPDUMP_BAR_AREA_DEC] + 1;
		nMaxChars --;
		nOneData += (m_nCharsData [PPDUMP_BAR_AREA_DEC] + 1) * m_nWidthFont;
		nWidth -= m_nWidthFont;
	}
	if (m_nStyle & PPDUMP_FIELD_BIN)
	{
		nTemp += m_nCharsData [PPDUMP_BAR_AREA_BIN] + 1;
		nMaxChars --;
		nOneData += (m_nCharsData [PPDUMP_BAR_AREA_BIN] + 1) * m_nWidthFont;
		nWidth -= m_nWidthFont;
	}
	if (m_nStyle & PPDUMP_FIELD_OCT)
	{
		nTemp += m_nCharsData [PPDUMP_BAR_AREA_OCT] + 1;
		nMaxChars --;
		nOneData += (m_nCharsData [PPDUMP_BAR_AREA_OCT] + 1) * m_nWidthFont;
		nWidth -= m_nWidthFont;
	}
	if (m_nStyle & PPDUMP_FIELD_ASCII)
	{
		nTemp += m_nCharsData [PPDUMP_BAR_AREA_ASCII];
		nMaxChars -= 2;
		nOneData += (m_nCharsData [PPDUMP_BAR_AREA_ASCII]) * m_nWidthFont + 1;
		nWidth -= (m_nWidthFont * 2 - 1);
	}
	if ((nMaxChars <= 0) || (nTemp == 0))
	{
		m_nDataInLines = 0;
		return;
	}

	m_nDataInLines = (int)(nWidth / nOneData);
	
	if (m_nStyle & PPDUMP_FIELD_HEX)
	{
		m_rFieldArea [PPDUMP_BAR_AREA_HEX] = rect;
		rect.left += m_nWidthFont * (m_nDataInLines * (m_nCharsData [PPDUMP_BAR_AREA_HEX] + 1) + 1);
		m_rFieldArea [PPDUMP_BAR_AREA_HEX].right = rect.left;
	}
	if (m_nStyle & PPDUMP_FIELD_DEC)
	{
		m_rFieldArea [PPDUMP_BAR_AREA_DEC] = rect;
		rect.left += m_nWidthFont * (m_nDataInLines * (m_nCharsData [PPDUMP_BAR_AREA_DEC] + 1) + 1);
		m_rFieldArea [PPDUMP_BAR_AREA_DEC].right = rect.left;
	}
	if (m_nStyle & PPDUMP_FIELD_BIN)
	{
		m_rFieldArea [PPDUMP_BAR_AREA_BIN] = rect;
		rect.left += m_nWidthFont * (m_nDataInLines * (m_nCharsData [PPDUMP_BAR_AREA_BIN] + 1) + 1);
		m_rFieldArea [PPDUMP_BAR_AREA_BIN].right = rect.left;
	}
	if (m_nStyle & PPDUMP_FIELD_OCT)
	{
		m_rFieldArea [PPDUMP_BAR_AREA_OCT] = rect;
		rect.left += m_nWidthFont * (m_nDataInLines * (m_nCharsData [PPDUMP_BAR_AREA_OCT] + 1) + 1);
		m_rFieldArea [PPDUMP_BAR_AREA_OCT].right = rect.left;
	}
	if (m_nStyle & PPDUMP_FIELD_ASCII)
	{
		m_rFieldArea [PPDUMP_BAR_AREA_ASCII] = rect;
		rect.left += m_nWidthFont * (m_nDataInLines * m_nCharsData [PPDUMP_BAR_AREA_ASCII] + 2) + m_nDataInLines;
		m_rFieldArea [PPDUMP_BAR_AREA_ASCII].right = rect.left;
	}
}

/////////////////////////////////////////////////////////////////////////////
//
//  CPPDumpCtrl::UpdateControlBar  (public member function)
//    Update the control bar of the control
//
//  Parameters :
//		pDC		    [in] - the device context
//
//  Returns :
//		None
//
/////////////////////////////////////////////////////////////////////////////
void CPPDumpCtrl::UpdateControlBar(CDC * pDC /* = NULL */, BOOL bDisable /* = FALSE */, int nNewAddr /* = -1 */)
{
//	CClientDC dc(this);
	BOOL bReleaseDC = FALSE;
	if (pDC == NULL)
	{
		pDC = GetDC(); //&dc;
		bReleaseDC = TRUE;
	}

	pDC->SetTextColor(bDisable ? m_crDisableFg : m_crColor [PPDUMP_COLOR_DATA_FG]);
	
	CFont * pFont = pDC->SelectObject(&m_font);
	pDC->SetBkMode(TRANSPARENT);

	int nAddr;

	if (nNewAddr < 0)
	{
		if ((m_pEdit != NULL) && (m_nEditedArea < 0x10))
		{
				return;
		}
		else nAddr = GetAddressForControlBar();
	}
	else nAddr = nNewAddr;
	
	//get current and previous values
	UINT nNewValue = GetDataFromCurrentAddress(nAddr);

	if (m_nStyle & PPDUMP_BAR_ADDRESS)
		DrawAddressValue(pDC, m_rBarArea [PPDUMP_BAR_AREA_ADDRESS], nAddr + m_nOffsetAddress, TRUE, bDisable);
	if (m_nStyle & PPDUMP_BAR_HEX)
		DrawHexValue(pDC, m_rBarArea [PPDUMP_BAR_AREA_HEX], nNewValue, TRUE, bDisable);
	if (m_nStyle & PPDUMP_BAR_DEC)
		DrawDecValue(pDC, m_rBarArea [PPDUMP_BAR_AREA_DEC], nNewValue, TRUE, bDisable);
	if (m_nStyle & PPDUMP_BAR_BIN)
		DrawBinValue(pDC, m_rBarArea [PPDUMP_BAR_AREA_BIN], nNewValue, TRUE, bDisable);
	if (m_nStyle & PPDUMP_BAR_OCT)
		DrawOctValue(pDC, m_rBarArea [PPDUMP_BAR_AREA_OCT], nNewValue, TRUE, bDisable);
	if (m_nStyle & PPDUMP_BAR_ASCII)
		DrawAsciiValue(pDC, m_rBarArea [PPDUMP_BAR_AREA_ASCII], nNewValue, TRUE, bDisable);


	pDC->SelectObject(pFont);

	if (bReleaseDC)
		ReleaseDC(pDC);
}

/////////////////////////////////////////////////////////////////////////////
//
//  CPPDumpCtrl::DrawControlBar  (public member function)
//    Draws the control bar of the control
//
//  Parameters :
//		pDC		    [in] - the device context
//		rect		[in] - rect of the control
//
//  Returns :
//		rect.bottom		 - the bottom of the control bar
//
/////////////////////////////////////////////////////////////////////////////
int CPPDumpCtrl::DrawControlBar(CDC * pDC, CRect rect, BOOL bDisable /* = FALSE */)
{
	if (!(m_nStyle & PPDUMP_BAR_ALL))
		return rect.top;

	rect.bottom = CalculateControlBar(rect);

	//draws the background and the frame of the control bar
//	pDC->DrawFrameControl(rect, DFC_BUTTON, DFCS_BUTTONPUSH);
	pDC->FillSolidRect(rect, ::GetSysColor(COLOR_3DFACE));
	pDC->Draw3dRect(rect, ::GetSysColor(COLOR_3DLIGHT), ::GetSysColor(COLOR_3DSHADOW));
	m_rBarArea [PPDUMP_BAR_MAX_AREAS] = rect; //remember the rect of the control bar

	int nAddr = GetAddressForControlBar();

	//get current and previous values
	UINT nNewValue = GetDataFromCurrentAddress(nAddr);

	int nLength = 0;
	if (m_nStyle & PPDUMP_BAR_ADDRESS)
	{
		pDC->TextOut(m_rBarArea [PPDUMP_BAR_AREA_ADDRESS].left - (m_csNameFields [PPDUMP_BAR_AREA_ADDRESS].GetLength() + 1) * m_nWidthFont, 
			m_rBarArea [PPDUMP_BAR_AREA_ADDRESS].top, m_csNameFields [PPDUMP_BAR_AREA_ADDRESS] + _T(":"));
		DrawAddressValue(pDC, m_rBarArea [PPDUMP_BAR_AREA_ADDRESS], nAddr + m_nOffsetAddress, TRUE, bDisable);
	}

	if (m_nStyle & PPDUMP_BAR_HEX)
	{
		pDC->TextOut(m_rBarArea [PPDUMP_BAR_AREA_HEX].left - (m_csNameFields [PPDUMP_BAR_AREA_HEX].GetLength() + 1) * m_nWidthFont, 
			m_rBarArea [PPDUMP_BAR_AREA_HEX].top, m_csNameFields [PPDUMP_BAR_AREA_HEX] + _T(":"));
		DrawHexValue(pDC, m_rBarArea [PPDUMP_BAR_AREA_HEX], nNewValue, TRUE, FALSE, bDisable);
	}

	if (m_nStyle & PPDUMP_BAR_DEC)
	{
		pDC->TextOut(m_rBarArea [PPDUMP_BAR_AREA_DEC].left - (m_csNameFields [PPDUMP_BAR_AREA_DEC].GetLength() + 1) * m_nWidthFont, 
			m_rBarArea [PPDUMP_BAR_AREA_DEC].top, m_csNameFields [PPDUMP_BAR_AREA_DEC] + _T(":"));
		DrawDecValue(pDC, m_rBarArea [PPDUMP_BAR_AREA_DEC], nNewValue, TRUE, FALSE, bDisable);
	}

	if (m_nStyle & PPDUMP_BAR_BIN)
	{
		pDC->TextOut(m_rBarArea [PPDUMP_BAR_AREA_BIN].left - (m_csNameFields [PPDUMP_BAR_AREA_BIN].GetLength() + 1) * m_nWidthFont, 
			m_rBarArea [PPDUMP_BAR_AREA_BIN].top, m_csNameFields [PPDUMP_BAR_AREA_BIN] + _T(":"));
		DrawBinValue(pDC, m_rBarArea [PPDUMP_BAR_AREA_BIN], nNewValue, TRUE, FALSE, bDisable);
	}

	if (m_nStyle & PPDUMP_BAR_OCT)
	{
		pDC->TextOut(m_rBarArea [PPDUMP_BAR_AREA_OCT].left - (m_csNameFields [PPDUMP_BAR_AREA_OCT].GetLength() + 1) * m_nWidthFont, 
			m_rBarArea [PPDUMP_BAR_AREA_OCT].top, m_csNameFields [PPDUMP_BAR_AREA_OCT] + _T(":"));
		rect.left = DrawOctValue(pDC, m_rBarArea [PPDUMP_BAR_AREA_OCT], nNewValue, TRUE, FALSE, bDisable);
	}

	if (m_nStyle & PPDUMP_BAR_ASCII)
	{
		pDC->TextOut(m_rBarArea [PPDUMP_BAR_AREA_ASCII].left - (m_csNameFields [PPDUMP_BAR_AREA_ASCII].GetLength() + 1) * m_nWidthFont, 
			m_rBarArea [PPDUMP_BAR_AREA_ASCII].top, m_csNameFields [PPDUMP_BAR_AREA_ASCII] + _T(":"));
		rect.left = DrawAsciiValue(pDC, m_rBarArea [PPDUMP_BAR_AREA_ASCII], nNewValue, TRUE, FALSE, bDisable);
	}

	return m_rBarArea [PPDUMP_BAR_MAX_AREAS].bottom;
}

int CPPDumpCtrl::CalculateControlBar(CRect rect)
{
	int nLength = 0;
	
	rect.left += m_nWidthFont;
	rect.right -= m_nWidthFont;
	rect.top += m_nHeightFont / 6;
	rect.bottom = rect.top + m_nHeightFont;

	CRect rBar = rect;

	for (int i = 0; i < PPDUMP_BAR_MAX_AREAS; i++)
		m_rBarArea [i].SetRectEmpty();

	if (m_nStyle & PPDUMP_BAR_ADDRESS)
	{
		nLength = m_nWidthFont * (m_nCharsData [PPDUMP_BAR_AREA_ADDRESS] + 3 + m_csNameFields [PPDUMP_BAR_AREA_ADDRESS].GetLength());
		if (rBar.Width() > nLength)
		{
			if ((rect.left + nLength) > rect.right)
			{
				rect.left = rBar.left;
				rect.top += m_nHeightFont;
				rect.bottom += m_nHeightFont;
			}
			m_rBarArea [PPDUMP_BAR_AREA_ADDRESS].right = rect.left + nLength;
			m_rBarArea [PPDUMP_BAR_AREA_ADDRESS].left = m_rBarArea [PPDUMP_BAR_AREA_ADDRESS].right - m_nWidthFont * (m_nCharsData [PPDUMP_BAR_AREA_ADDRESS] + 2);
			m_rBarArea [PPDUMP_BAR_AREA_ADDRESS].top = rect.top;
			m_rBarArea [PPDUMP_BAR_AREA_ADDRESS].bottom = rect.bottom - m_nHeightFont / 6;
			rect.left = m_rBarArea [PPDUMP_BAR_AREA_ADDRESS].right + m_nWidthFont;
		}
	}

	if (m_nStyle & PPDUMP_BAR_HEX)
	{
		nLength = m_nWidthFont * (m_nCharsData [PPDUMP_BAR_AREA_HEX] + 3 + m_csNameFields [PPDUMP_BAR_AREA_HEX].GetLength());
		if (rBar.Width() > nLength)
		{
			if ((rect.left + nLength) > rect.right)
			{
				rect.left = rBar.left;
				rect.top += m_nHeightFont;
				rect.bottom += m_nHeightFont;
			}
			m_rBarArea [PPDUMP_BAR_AREA_HEX].right = rect.left + nLength;
			m_rBarArea [PPDUMP_BAR_AREA_HEX].left = m_rBarArea [PPDUMP_BAR_AREA_HEX].right - m_nWidthFont * (m_nCharsData [PPDUMP_BAR_AREA_HEX] + 2);
			m_rBarArea [PPDUMP_BAR_AREA_HEX].top = rect.top;
			m_rBarArea [PPDUMP_BAR_AREA_HEX].bottom = rect.bottom - m_nHeightFont / 6;
			rect.left = m_rBarArea [PPDUMP_BAR_AREA_HEX].right + m_nWidthFont;
		}
	}

	if (m_nStyle & PPDUMP_BAR_DEC)
	{
		nLength = m_nWidthFont * (m_nCharsData [PPDUMP_BAR_AREA_DEC] + 3 + m_csNameFields [PPDUMP_BAR_AREA_DEC].GetLength());
		if (rBar.Width() > nLength)
		{
			if ((rect.left + nLength) > rect.right)
			{
				rect.left = rBar.left;
				rect.top += m_nHeightFont;
				rect.bottom += m_nHeightFont;
			}
			m_rBarArea [PPDUMP_BAR_AREA_DEC].right = rect.left + nLength;
			m_rBarArea [PPDUMP_BAR_AREA_DEC].left = m_rBarArea [PPDUMP_BAR_AREA_DEC].right - m_nWidthFont * (m_nCharsData [PPDUMP_BAR_AREA_DEC] + 2);
			m_rBarArea [PPDUMP_BAR_AREA_DEC].top = rect.top;
			m_rBarArea [PPDUMP_BAR_AREA_DEC].bottom = rect.bottom - m_nHeightFont / 6;
			rect.left = m_rBarArea [PPDUMP_BAR_AREA_DEC].right + m_nWidthFont;
		}
	}

	if (m_nStyle & PPDUMP_BAR_BIN)
	{
		nLength = m_nWidthFont * (m_nCharsData [PPDUMP_BAR_AREA_BIN] + 3 + m_csNameFields [PPDUMP_BAR_AREA_BIN].GetLength());
		if (rBar.Width() > nLength)
		{
			if ((rect.left + nLength) > rect.right)
			{
				rect.left = rBar.left;
				rect.top += m_nHeightFont;
				rect.bottom += m_nHeightFont;
			}
			m_rBarArea [PPDUMP_BAR_AREA_BIN].right = rect.left + nLength;
			m_rBarArea [PPDUMP_BAR_AREA_BIN].left = m_rBarArea [PPDUMP_BAR_AREA_BIN].right - m_nWidthFont * (m_nCharsData [PPDUMP_BAR_AREA_BIN] + 2);
			m_rBarArea [PPDUMP_BAR_AREA_BIN].top = rect.top;
			m_rBarArea [PPDUMP_BAR_AREA_BIN].bottom = rect.bottom - m_nHeightFont / 6;
			rect.left = m_rBarArea [PPDUMP_BAR_AREA_BIN].right + m_nWidthFont;
		}
	}

	if (m_nStyle & PPDUMP_BAR_OCT)
	{
		nLength = m_nWidthFont * (m_nCharsData [PPDUMP_BAR_AREA_OCT] + 3 + m_csNameFields [PPDUMP_BAR_AREA_OCT].GetLength());
		if (rBar.Width() > nLength)
		{
			if ((rect.left + nLength) > rect.right)
			{
				rect.left = rBar.left;
				rect.top += m_nHeightFont;
				rect.bottom += m_nHeightFont;
			}
			m_rBarArea [PPDUMP_BAR_AREA_OCT].right = rect.left + nLength;
			m_rBarArea [PPDUMP_BAR_AREA_OCT].left = m_rBarArea [PPDUMP_BAR_AREA_OCT].right - m_nWidthFont * (m_nCharsData [PPDUMP_BAR_AREA_OCT] + 2);
			m_rBarArea [PPDUMP_BAR_AREA_OCT].top = rect.top;
			m_rBarArea [PPDUMP_BAR_AREA_OCT].bottom = rect.bottom - m_nHeightFont / 6;
			rect.left = m_rBarArea [PPDUMP_BAR_AREA_OCT].right + m_nWidthFont;
		}
	}

	if (m_nStyle & PPDUMP_BAR_ASCII)
	{
		nLength = m_nWidthFont * (m_nCharsData [PPDUMP_BAR_AREA_ASCII] + 3 + m_csNameFields [PPDUMP_BAR_AREA_ASCII].GetLength());
		if (rBar.Width() > nLength)
		{
			if ((rect.left + nLength) > rect.right)
			{
				rect.left = rBar.left;
				rect.top += m_nHeightFont;
				rect.bottom += m_nHeightFont;
			}
			m_rBarArea [PPDUMP_BAR_AREA_ASCII].right = rect.left + nLength;
			m_rBarArea [PPDUMP_BAR_AREA_ASCII].left = m_rBarArea [PPDUMP_BAR_AREA_ASCII].right - m_nWidthFont * (m_nCharsData [PPDUMP_BAR_AREA_ASCII] + 2);
			m_rBarArea [PPDUMP_BAR_AREA_ASCII].top = rect.top;
			m_rBarArea [PPDUMP_BAR_AREA_ASCII].bottom = rect.bottom - m_nHeightFont / 6;
			rect.left = m_rBarArea [PPDUMP_BAR_AREA_ASCII].right + m_nWidthFont;
		}
	}
	return rect.bottom;
}

int CPPDumpCtrl::DrawAddressValue(CDC * pDC, CRect rect, UINT nAddress, BOOL bBkgnd /* = FALSE */, BOOL bDisable /* = FALSE */)
{
	int nLength = m_nCharsData [PPDUMP_BAR_AREA_ADDRESS] / 2;
	if (m_nCharsData [PPDUMP_BAR_AREA_ADDRESS] & 0x1)
		nLength ++;

	CString str = FormatingString(PPDUMP_BAR_AREA_ADDRESS, nAddress, nLength);
	str = str.Right(m_nCharsData [PPDUMP_BAR_AREA_ADDRESS]);
	str = (TCHAR)' ' + str + (TCHAR)' ';
	
	return DrawStringValue(pDC, rect, str, bBkgnd, FALSE, bDisable);
}

int CPPDumpCtrl::DrawHexValue(CDC * pDC, CRect rect, UINT nValue, BOOL bBkgnd /* = FALSE */, BOOL bCaret /* = FALSE */, BOOL bDisable /* = FALSE */)
{
	CString str = FormatingString(PPDUMP_BAR_AREA_HEX, nValue);
	str = (TCHAR)' ' + str + (TCHAR)' ';
	
	return DrawStringValue(pDC, rect, str, bBkgnd, bCaret, bDisable);
}

int CPPDumpCtrl::DrawDecValue(CDC * pDC, CRect rect, UINT nValue, BOOL bBkgnd /* = FALSE */, BOOL bCaret /* = FALSE */, BOOL bDisable /* = FALSE */)
{
	CString str = FormatingString(PPDUMP_BAR_AREA_DEC, nValue);

	str = _T("        ") + str;
	str += (TCHAR)' ';
	str = str.Right(m_nCharsData [PPDUMP_BAR_AREA_DEC] + 2);

	return DrawStringValue(pDC, rect, str, bBkgnd, bCaret, bDisable);
}

int CPPDumpCtrl::DrawOctValue(CDC * pDC, CRect rect, UINT nValue, BOOL bBkgnd /* = FALSE */, BOOL bCaret /* = FALSE */, BOOL bDisable /* = FALSE */)
{
	CString str = FormatingString(PPDUMP_BAR_AREA_OCT, nValue);

	str = _T("        ") + str;
	str += (TCHAR)' ';
	str = str.Right(m_nCharsData [PPDUMP_BAR_AREA_OCT] + 2);
	
	return DrawStringValue(pDC, rect, str, bBkgnd, bCaret, bDisable);
}

int CPPDumpCtrl::DrawBinValue(CDC * pDC, CRect rect, UINT nValue, BOOL bBkgnd /* = FALSE */, BOOL bCaret /* = FALSE */, BOOL bDisable /* = FALSE */)
{
	CString str = FormatingString(PPDUMP_BAR_AREA_BIN, nValue);
	str = (TCHAR)' ' + str + (TCHAR)' ';
	
	return DrawStringValue(pDC, rect, str, bBkgnd, bCaret, bDisable);
}

int CPPDumpCtrl::DrawAsciiValue(CDC * pDC, CRect rect, UINT nValue, BOOL bBkgnd /* = FALSE */, BOOL bCaret /* = FALSE */, BOOL bDisable /* = FALSE */)
{
	CString str = FormatingString(PPDUMP_BAR_AREA_ASCII, nValue);
	str = (TCHAR)' ' + str + (TCHAR)' ';

	CSize size = pDC->GetTextExtent(str);
	rect.right = rect.left + size.cx + 1;
	
	if (!bDisable)
	{
		if (bBkgnd)
		{
			pDC->FillSolidRect(rect, m_crColor [PPDUMP_COLOR_DATA_BK]);
		}
		
		if (bCaret)
		{
			CRect rCaret = rect;
			rCaret.bottom = rCaret.top + m_nHeightFont;
			rCaret.DeflateRect(m_nWidthFont, 1, m_nWidthFont + 1, 1);
			pDC->FillSolidRect(rCaret, m_crColor [PPDUMP_COLOR_CARET_BK]);
		}
	}

	pDC->TextOut(rect.left, rect.top, str);

	return rect.right;
}

int CPPDumpCtrl::DrawStringValue(CDC * pDC, CRect rect, CString str, BOOL bBkgnd /* = FALSE */, BOOL bCaret /* = TRUE */, BOOL bDisable /* = FALSE */)
{
	CSize size = pDC->GetTextExtent(str);
	rect.right = rect.left + size.cx;
	
	if (!bDisable)
	{
		if (bBkgnd)
			pDC->FillSolidRect(rect, m_crColor [PPDUMP_COLOR_DATA_BK]);
		
		if (bCaret)
		{
			CRect rCaret = rect;
			rCaret.bottom = rCaret.top + m_nHeightFont;
			rCaret.DeflateRect(m_nWidthFont / 2 + 1, 1, m_nWidthFont / 2 + 2, 1);
			pDC->FillSolidRect(rCaret, m_crColor [PPDUMP_COLOR_CARET_BK]);
		}
	}

	pDC->TextOut(rect.left, rect.top, str);

	return rect.right;
}

/////////////////////////////////////////////////////////////////////////////
//
//  CPPDumpCtrl::DrawStatusBar  (public member function)
//    Draws the status bar of the control
//
//  Parameters :
//		pDC		    [in] - the device context
//		rect		[in] - rect of the control
//
//  Returns :
//		rect.bottom		 - the top of the control bar
//
/////////////////////////////////////////////////////////////////////////////
int CPPDumpCtrl::DrawStatusBar(CDC * pDC, CRect rect, BOOL bDisable /* = FALSE */)
{
	if (!(m_nStyle & PPDUMP_NAMED_FIELDS))
		return rect.top;

	rect.bottom = rect.top + m_nHeightFont;
	
	//draws the background and the frame of the control bar
	pDC->FillSolidRect(rect, bDisable ? m_crDisableBk : m_crColor [PPDUMP_COLOR_DATA_BK]);
	pDC->SetTextColor(bDisable ? m_crDisableFg : m_crColor [PPDUMP_COLOR_TEXT_HEADER]);
	CPen pen (PS_SOLID, 1, bDisable ? m_crDisableFg : m_crColor [PPDUMP_COLOR_SEPARATORS]);
	CPen * penOld = pDC->SelectObject(&pen);
	pDC->MoveTo(rect.left, rect.bottom);
	pDC->LineTo(rect.right, rect.bottom);

	if (m_nStyle & PPDUMP_FIELD_ADDRESS)
	{
		rect.left = m_rFieldArea [PPDUMP_BAR_AREA_ADDRESS].left;
		rect.right = m_rFieldArea [PPDUMP_BAR_AREA_ADDRESS].right;
		pDC->DrawText(m_csNameFields [PPDUMP_BAR_AREA_ADDRESS], rect, DT_SINGLELINE | DT_CENTER | DT_VCENTER);
		pDC->MoveTo(rect.right, rect.top);
		pDC->LineTo(rect.right, rect.bottom);
	}

	if (m_nStyle & PPDUMP_FIELD_HEX)
	{
		rect.left = m_rFieldArea [PPDUMP_BAR_AREA_HEX].left;
		rect.right = m_rFieldArea [PPDUMP_BAR_AREA_HEX].right;
		pDC->DrawText(m_csNameFields [PPDUMP_BAR_AREA_HEX], rect, DT_SINGLELINE | DT_CENTER | DT_VCENTER);
		pDC->MoveTo(rect.right, rect.top);
		pDC->LineTo(rect.right, rect.bottom);
	}

	if (m_nStyle & PPDUMP_FIELD_DEC)
	{
		rect.left = m_rFieldArea [PPDUMP_BAR_AREA_DEC].left;
		rect.right = m_rFieldArea [PPDUMP_BAR_AREA_DEC].right;
		pDC->DrawText(m_csNameFields [PPDUMP_BAR_AREA_DEC], rect, DT_SINGLELINE | DT_CENTER | DT_VCENTER);
		pDC->MoveTo(rect.right, rect.top);
		pDC->LineTo(rect.right, rect.bottom);
	}

	if (m_nStyle & PPDUMP_FIELD_BIN)
	{
		rect.left = m_rFieldArea [PPDUMP_BAR_AREA_BIN].left;
		rect.right = m_rFieldArea [PPDUMP_BAR_AREA_BIN].right;
		pDC->DrawText(m_csNameFields [PPDUMP_BAR_AREA_BIN], rect, DT_SINGLELINE | DT_CENTER | DT_VCENTER);
		pDC->MoveTo(rect.right, rect.top);
		pDC->LineTo(rect.right, rect.bottom);
	}

	if (m_nStyle & PPDUMP_FIELD_OCT)
	{
		rect.left = m_rFieldArea [PPDUMP_BAR_AREA_OCT].left;
		rect.right = m_rFieldArea [PPDUMP_BAR_AREA_OCT].right;
		pDC->DrawText(m_csNameFields [PPDUMP_BAR_AREA_OCT], rect, DT_SINGLELINE | DT_CENTER | DT_VCENTER);
		pDC->MoveTo(rect.right, rect.top);
		pDC->LineTo(rect.right, rect.bottom);
	}

	if (m_nStyle & PPDUMP_FIELD_ASCII)
	{
		rect.left = m_rFieldArea [PPDUMP_BAR_AREA_ASCII].left;
		rect.right = m_rFieldArea [PPDUMP_BAR_AREA_ASCII].right;
		pDC->DrawText(m_csNameFields [PPDUMP_BAR_AREA_ASCII], rect, DT_SINGLELINE | DT_CENTER | DT_VCENTER);
		pDC->MoveTo(rect.right, rect.top);
		pDC->LineTo(rect.right, rect.bottom);
	}
	pDC->SelectObject(penOld);

	return rect.bottom;
}

///////////////////////////////////////////////////////////////////
// CPPDumpCtrl::RecalculateWorkData()
// Recalculates working length of the data depending on their type
///////////////////////////////////////////////////////////////////
void CPPDumpCtrl::RecalculateWorkData(DWORD nNewStyle)
{
	if ((nNewStyle ^ m_nStyle) & PPDUMP_WORD_DATA)
		m_nBeginAddress = 0;

	m_nLengthData = (nNewStyle & PPDUMP_WORD_DATA) ? m_nRealLengthData / 2 : m_nRealLengthData;
} //End of RecalculateWorkData

///////////////////////////////////////////////////////////////////
// CPPDumpCtrl::SetCharsInData()
// Recalculate the sizes of other fields
///////////////////////////////////////////////////////////////////
void CPPDumpCtrl::SetCharsInData()
{
	//Calculate the length of the address fields
	m_nCharsData [PPDUMP_BAR_AREA_ADDRESS] = 4;
	UINT nLength = (m_nOffsetAddress + m_nLengthData - 1) >> 16;
	if (nLength)
	{
		while (nLength)
		{
			nLength >>= 4;
			m_nCharsData [PPDUMP_BAR_AREA_ADDRESS] ++;
		}
	}

	//Customize the length of the fields
	m_nCharsData [PPDUMP_BAR_AREA_ASCII] = 1; //the ascii field - 1 chars always
	if (m_nStyle & PPDUMP_WORD_DATA)
	{
		m_nCharsData [PPDUMP_BAR_AREA_DEC] = 5;
		m_nCharsData [PPDUMP_BAR_AREA_HEX] = 4;
		m_nCharsData [PPDUMP_BAR_AREA_BIN] = 17;
		m_nCharsData [PPDUMP_BAR_AREA_OCT] = 6;
	}
	else
	{
		m_nCharsData [PPDUMP_BAR_AREA_DEC] = 3;
		m_nCharsData [PPDUMP_BAR_AREA_HEX] = 2;
		m_nCharsData [PPDUMP_BAR_AREA_BIN] = 8;
		m_nCharsData [PPDUMP_BAR_AREA_OCT] = 3;
	}
} //End of SetCharsInData

/////////////////////////////////////////////////////////////////////////////
//
//  CPPDumpCtrl::GetDataFromCurrentAddress (protected member function)
//    Gets data specified by address from array
//
//  Parameters :
//		nAddress    [in] - the address into array
//		bNewData	[in] - if TRUE then data gets from pNewData array, else from pOldData array
//		nDir	    [in] - the direction reading data
//
//  Returns :
//		the data from specified address
//
/////////////////////////////////////////////////////////////////////////////
DWORD CPPDumpCtrl::GetDataFromCurrentAddress(DWORD nAddress, BOOL bNewData /* = TRUE */, int nDir /* = 0 */, int nByte /* = 0 */)
{
	BYTE * pArray = bNewData ? m_pNewData : m_pOldData;
	
	if (pArray == NULL)
		return 0;
	
	if ((m_nStyle & PPDUMP_WORD_DATA))
		nAddress *= 2;

	//Customize the length of the data
	if (!nByte)
		nByte = (m_nStyle & PPDUMP_WORD_DATA) ? 2 : 1;

	//Customize the direction reading data
	if (!nDir)
		nDir = (m_nStyle & PPDUMP_DATA_LOW_HIGH) ? 2 : 1;

	if (nDir == 2)
		nAddress += (nByte - 1);

	DWORD nData = 0;
	for (int i = 0; i < nByte; i++)
	{
		nData <<= 8;
		nData += *(pArray + nAddress);
		nAddress = (nDir == 2) ? nAddress - 1 : nAddress + 1;
	}

	return nData;
} // end of GetDataFromCurrentAddress

//***************************************************************************//
//* Public methods
//***************************************************************************//

/////////////////////////////////////////////////////////////////////////////
//
//  CPPDumpCtrl::SetFont  (public member function)
//    Sets the new font to the control
//
//  Parameters :
//		font		[in] - new font
//		bRedraw		[in] - redraw control
//
//  Returns :
//		Nonzero if successful; otherwise 0.
//
/////////////////////////////////////////////////////////////////////////////
BOOL CPPDumpCtrl::SetFont(CFont & font, BOOL bRedraw /* = TRUE */)
{
	LOGFONT lf;
	font.GetLogFont (&lf);

	return SetFont(lf, bRedraw);;
}  // End of SetFont

/////////////////////////////////////////////////////////////////////////////
//
//  CPPDumpCtrl::SetFont  (public member function)
//    Sets the new font to the control
//
//  Parameters :
//		lf			[in] - structure LOGFONT for the new font
//		bRedraw		[in] - redraw control
//
//  Returns :
//		Nonzero if successful; otherwise 0.
//
/////////////////////////////////////////////////////////////////////////////
BOOL CPPDumpCtrl::SetFont(LOGFONT & lf, BOOL bRedraw /* = TRUE */)
{
	KillEdit();

	if (NULL != (HFONT)m_font) 
		m_font.DeleteObject();

	BOOL bReturn = m_font.CreateFontIndirect (&lf);
	
	if (bRedraw)
	{
		// Redraw control
		Invalidate(FALSE);
	}

	return bReturn;
}  // End of SetFont

/////////////////////////////////////////////////////////////////////////////
//
//  CPPDumpCtrl::SetFont  (public member function)
//    Sets the new font to the control
//
//  Parameters :
//		font		[in] - new font
//		bRedraw		[in] - redraw control
//
//  Returns :
//		Nonzero if successful; otherwise 0.
//
/////////////////////////////////////////////////////////////////////////////
BOOL CPPDumpCtrl::SetFont(LPCTSTR lpszFaceName, int nSizePoints /* = 8 */,
									BOOL bUnderline /* = FALSE */, BOOL bBold /* = FALSE */,
									BOOL bStrikeOut /* = FALSE */, BOOL bItalic /* = FALSE */, 
									BOOL bRedraw /* = TRUE */)
{
	CDC* pDC = GetDC ();
	LOGFONT lf;
	memset (&lf, 0, sizeof(LOGFONT));

	strcpy (lf.lfFaceName, lpszFaceName);
	lf.lfHeight = -MulDiv (nSizePoints, GetDeviceCaps (pDC->m_hDC, LOGPIXELSY), 72);
	lf.lfUnderline = bUnderline;
	if (TRUE == bBold) 
	{
		lf.lfWeight = FW_BOLD;
	}
	lf.lfStrikeOut = bStrikeOut;
	lf.lfItalic = bItalic;

	if (pDC)
		ReleaseDC(pDC);

	return SetFont(lf, bRedraw);
}  // End of SetFont

/////////////////////////////////////////////////////////////////////////////
//
//  CPPDumpCtrl::SetDefaultFonts  (public member function)
//    Sets default fonts of the control
//
//  Parameters :
//		bRedraw		[in] - redraw control
//
//  Returns :
//		None
//
/////////////////////////////////////////////////////////////////////////////
void CPPDumpCtrl::SetDefaultFont(BOOL bRedraw /* = TRUE */)
{
	SetFont(_T("Courier"), 8, FALSE, FALSE, FALSE, FALSE, bRedraw);
} // End of SetDefaultFonts

/////////////////////////////////////////////////////////////////////////////
//
//  CPPDumpCtrl::SetPointerData  (public member function)
//    Sets pointers to the new data array and the old data array
//
//  Parameters :
//		nLenght		[in] - lenght data array
//		pNewData	[in] - pointer to the new data array
//		pOldData	[in] - pointer to the old data array. If NULL, then pOldData = pNewData
//		bRedraw		[in] - redraw control
//
//  Returns :
//		None
//
/////////////////////////////////////////////////////////////////////////////
void CPPDumpCtrl::SetPointerData(DWORD nLength, LPBYTE pNewData, LPBYTE pOldData /* = NULL */, BOOL bRedraw /* = TRUE */)
{
	KillEdit();

	//Sets the pointers to the data arrays
	m_pNewData = pNewData;
	if (NULL == pOldData)
		m_pOldData = pNewData;
	else
		m_pOldData = pOldData;

	m_nRealLengthData = nLength; //remember the real length of array
	m_nBeginAddress = 0;
	m_nLengthData = (m_nStyle & PPDUMP_WORD_DATA) ? nLength / 2 : nLength;

	SetCharsInData(); //recalculates the sizes of other fields
	SetBeginAddress(0, FALSE); //sets the first address on the screen
	SetSelectRange(m_nBeginAddress, -1, FALSE); //reset the selection block

	if (bRedraw)
	{
		// Redraw control
		Invalidate(FALSE);
	}
} // End of SetPointerData

/////////////////////////////////////////////////////////////////////////////
//
//  CPPDumpCtrl::SetPointerData  (public member function)
//    Sets address which will add to the real address data array for view
//
//  Parameters :
//		nAddress	[in] - offset address
//		bRedraw		[in] - redraw control
//
//  Returns :
//		None
//
/////////////////////////////////////////////////////////////////////////////
void CPPDumpCtrl::SetOffsetViewAddress(int nAddress /* = 0 */, BOOL bRedraw /* = TRUE */)
{
	KillEdit();

	if (nAddress < 0)
		nAddress = 0;

	m_nOffsetAddress = nAddress;
	SetCharsInData(); //recalculates the sizes of other fields
	SetSelectRange(m_nBeginAddress, -1, FALSE); //reset the selection block
	
	if (bRedraw)
	{
		// Redraw control
		Invalidate(FALSE);
	}
} // End of SetOffsetViewAddress

/////////////////////////////////////////////////////////////////////////////
//
//  CPPDumpCtrl::SetStyles  (public member function)
//    Sets the new styles of the control
//
//  Parameters :
//		nStyle		[in] - new style
//		bRedraw		[in] - redraw control
//
//  Returns :
//		Old styles
//
/////////////////////////////////////////////////////////////////////////////
void CPPDumpCtrl::SetStyles(DWORD nStyle, BOOL bRedraw /* = TRUE */)
{
	ModifyStyles(nStyle, -1, bRedraw);
}  // End of SetStyles

/////////////////////////////////////////////////////////////////////////////
//
//  CPPDumpCtrl::ModifyStyles  (public member function)
//    Modifify the styles of the control
//
//  Parameters :
//		nAddStyle	 [in] - The styles to add
//		nRemoveStyle [in] - The styles to remove
//		bRedraw		 [in] - redraw control
//
//  Returns :
//		Old styles
//
/////////////////////////////////////////////////////////////////////////////
void CPPDumpCtrl::ModifyStyles(DWORD nAddStyle, DWORD nRemoveStyle, BOOL bRedraw /* = TRUE */)
{
	KillEdit();

	DWORD nTemp = m_nStyle;

	nTemp &= ~nRemoveStyle;
	nTemp |= nAddStyle;

	//
	RecalculateWorkData(nTemp);
	m_nStyle = nTemp;
	
	//Re-sets how much chars in the data of the fields
	SetCharsInData();
	SetBeginAddress(0, FALSE);
	SetSelectRange(m_nBeginAddress, -1, FALSE);
	
	if (bRedraw)
	{
		// Redraw control
		Invalidate(FALSE);
	}
}  // End of ModifyStyles

/////////////////////////////////////////////////////////////////////////////
//
//  CPPDumpCtrl::GetStyles (public member function)
//    Gets the current styles of the control
//
//  Parameters :
//
//  Returns :
//		Current styles
//
/////////////////////////////////////////////////////////////////////////////
DWORD CPPDumpCtrl::GetStyles()
{
	return m_nStyle;
}  // End of GetStyles

/////////////////////////////////////////////////////////////////////////////
//
//  CPPDumpCtrl::SetDefaultStyles  (public member function)
//    Sets the new styles of the control
//
//  Parameters :
//		bRedraw		[in] - redraw control
//
//  Returns :
//		None
//
/////////////////////////////////////////////////////////////////////////////
void CPPDumpCtrl::SetDefaultStyles(BOOL bRedraw /* = TRUE */)
{
	ModifyStyles(PPDUMP_FIELD_ADDRESS | PPDUMP_FIELD_HEX | PPDUMP_FIELD_ASCII |
			     PPDUMP_BAR_ADDRESS | PPDUMP_BAR_DEC | PPDUMP_BAR_HEX | PPDUMP_BAR_BIN |
			     PPDUMP_BAR_ASCII | PPDUMP_TRACK_MOUSE_MOVE,
				 -1, bRedraw);
}  // End of SetDefaultStyles

/////////////////////////////////////////////////////////////////////////////
//
//  CPPDumpCtrl::SetSpecialCharView  (public member function)
//    Sets the character which will drawn instead special characters (0 - 31)
//
//  Parameters :
//		chSymbol	[in] - the character which will draw instead the special characters (0 - 31)
//		bRedraw		[in] - redraw control
//
/////////////////////////////////////////////////////////////////////////////
void CPPDumpCtrl::SetSpecialCharView(TCHAR chSymbol /* = NULL */, BOOL bRedraw /* = TRUE */)
{
	m_chSpecCharView = chSymbol;
	if (bRedraw)
	{
		// Redraw control
		Invalidate(FALSE);
	}
}

/////////////////////////////////////////////////////////////////////////////
//
//  CPPDumpCtrl::SetBeginAddress  (public member function)
//    Sets the new styles of the control
//
//  Parameters :
//		nAddress    [in] - the first viewing address
//		bRedraw		[in] - redraw control
//
//  Returns :
//		None
//
/////////////////////////////////////////////////////////////////////////////
void CPPDumpCtrl::SetBeginAddress(int nAddress /* = 0 */, BOOL bRedraw /* = TRUE */)
{
	if (nAddress < 0)
		nAddress = 0;

	if ((nAddress >= m_nLengthData) || !m_nDataInLines)
		return;

	KillEdit();

	m_nBeginAddress = (nAddress / m_nDataInLines) * m_nDataInLines;
	if (bRedraw)
	{
		// Redraw control
		Invalidate(FALSE);
	}
}  // End of SetBeginAddress

/////////////////////////////////////////////////////////////////////////////
//
//  CPPDumpCtrl::GetBeginAddress  (public member function)
//    Gets the first viewing address
//
//  Parameters :
//		None
//
//  Returns :
//		The first viewing address on the screen
//
/////////////////////////////////////////////////////////////////////////////
int CPPDumpCtrl::GetBeginAddress()
{
	return m_nBeginAddress;
}  // End of GetBeginAddress

/////////////////////////////////////////////////////////////////////////////
//
//  CPPDumpCtrl::SetColor (public member function)
//    Set the color
//
//  Parameters :
//		nIndex  [in] - index of the color
//		crColor [in] - new color
//		bRedraw [in] - redraw control
//
//  Returns :
//		Previous color
//
/////////////////////////////////////////////////////////////////////////////
COLORREF CPPDumpCtrl::SetColor(int nIndex, COLORREF crColor, BOOL bRedraw /* = TRUE */)
{
	if (nIndex >= PPDUMP_COLOR_MAX)
		return RGB (0, 0, 0);

	COLORREF crReturn = m_crColor [nIndex];
	m_crColor [nIndex] = crColor;
	
	if (m_pEdit != NULL)
	{
		switch (nIndex)
		{
		case PPDUMP_COLOR_EDIT_FG:
			m_pEdit->SetColor(CPPNumEdit::PPNUM_COLOR_VALID_FG, crColor, bRedraw);
			bRedraw = FALSE;
			break;
		case PPDUMP_COLOR_EDIT_BK:
			m_pEdit->SetColor(CPPNumEdit::PPNUM_COLOR_VALID_BK, crColor, bRedraw);
			bRedraw = FALSE;
			break;
		case PPDUMP_COLOR_EDIT_ERR_FG:
			m_pEdit->SetColor(CPPNumEdit::PPNUM_COLOR_NOT_VALID_FG, crColor, bRedraw);
			bRedraw = FALSE;
			break;
		case PPDUMP_COLOR_EDIT_ERR_BK:
			m_pEdit->SetColor(CPPNumEdit::PPNUM_COLOR_NOT_VALID_BK, crColor, bRedraw);
			bRedraw = FALSE;
			break;
		}
	}

	if (bRedraw)
	{
		// Redraw control
		Invalidate(FALSE);
	}

	return crReturn;
}  // End of SetColor

/////////////////////////////////////////////////////////////////////////////
//
//  CPPDumpCtrl::GetColor (public member function)
//    Set the color
//
//  Parameters :
//		nIndex  [in] - index of the color
//
//  Returns :
//		Current color
//
/////////////////////////////////////////////////////////////////////////////
COLORREF CPPDumpCtrl::GetColor(int nIndex)
{
	if (nIndex >= PPDUMP_COLOR_MAX)
		return RGB (0, 0, 0);

	return m_crColor [nIndex];
}  // End of GetColor

/////////////////////////////////////////////////////////////////////////////
//
//  CPPDumpCtrl::SetDefaultColors (public member function)
//    Set the color as default
//
//  Parameters :
//		bRedraw [in] - redraw control
//
//  Returns :
//		None
//
/////////////////////////////////////////////////////////////////////////////
void CPPDumpCtrl::SetDefaultColors(BOOL bRedraw /* = TRUE */)
{
	SetColor (PPDUMP_COLOR_DATA_FG, ::GetSysColor(COLOR_WINDOWTEXT), FALSE);
	SetColor (PPDUMP_COLOR_DATA_BK, ::GetSysColor(COLOR_WINDOW), FALSE);
	SetColor (PPDUMP_COLOR_DATA_CHANGE_FG, RGB (255, 0, 0), FALSE);
	SetColor (PPDUMP_COLOR_EDIT_FG, RGB (0, 0, 0), FALSE);
	SetColor (PPDUMP_COLOR_EDIT_BK, RGB (255, 255, 0), FALSE);
	SetColor (PPDUMP_COLOR_EDIT_ERR_FG, RGB (255, 255, 255), FALSE);
	SetColor (PPDUMP_COLOR_EDIT_ERR_BK, RGB (255, 0, 0), FALSE);
	SetColor (PPDUMP_COLOR_CARET_BK, RGB (0, 255, 255), FALSE);
	SetColor (PPDUMP_COLOR_ADDRESS_FG, RGB (0, 176, 0), FALSE);
	SetColor (PPDUMP_COLOR_SEPARATORS, ::GetSysColor(COLOR_BTNSHADOW), FALSE);
	SetColor (PPDUMP_COLOR_TEXT_HEADER, ::GetSysColor(COLOR_BTNSHADOW), FALSE);
	SetColor (PPDUMP_COLOR_MOUSE_TRACK, ::GetSysColor(COLOR_3DSHADOW), bRedraw);
}  // End of SetDefaultColors

/////////////////////////////////////////////////////////////////////////////
//
//  CPPDumpCtrl::SetSelectRange (public member function)
//    Sets the range of the caret
//
//  Parameters :
//		nBegin   [in] - Begin of caret
//		nEnd     [in] - End of caret
//		bVisible [in] - Moves begin address on the screen
//
//  Returns :
//		None
//
/////////////////////////////////////////////////////////////////////////////
void CPPDumpCtrl::SetSelectRange(int nBegin /* = 0 */, int nEnd /* = -1 */, BOOL bVisible /* = TRUE */)
{
	//If first address is negative
	if (nBegin < 0)
		nBegin = 0;

	if ((nEnd < 0) || !IsEnableSelect())
		nEnd = nBegin; //nEnd equal nBegin
	else if (nEnd < nBegin)
	{
		//If nEnd less nBegin then to swap nBegin and nEnd
		int nTemp = nBegin;
		nBegin = nEnd;
		nEnd = nTemp;
	}

	//If nBegin or nAddr more then length of the data
	if ((nBegin >= m_nLengthData) || (nEnd >= m_nLengthData))
		return;

	KillEdit();

	m_nCaretAddrFirst = nBegin;
	m_nCaretAddrBegin = nBegin;
	m_nCaretAddrEnd = nEnd;
	
	if (bVisible)
		SetVisibleAddress(m_nCaretAddrBegin);
} //End of SetSelectRange

/////////////////////////////////////////////////////////////////////////////
//
//  CPPDumpCtrl::GetSelectRange (public member function)
//    Gets the range of the caret
//
//  Parameters :
//		nBegin [out] - Begin address
//		nEnd   [out] - End address
//
//  Returns :
//		None
//
/////////////////////////////////////////////////////////////////////////////
void CPPDumpCtrl::GetSelectRange(LPINT nBegin, LPINT nEnd)
{
	*nBegin = m_nCaretAddrBegin;
	*nEnd = m_nCaretAddrEnd;
} //End of GetSelectRange

/////////////////////////////////////////////////////////////////////////////
//
//  CPPDumpCtrl::IsAddressSelected (public member function)
//    ...
//
//  Parameters :
//		nAddress [in] - Test address
//
//  Returns :
//		If testing address in the caret range then - TRUE, else - FALSE
//
/////////////////////////////////////////////////////////////////////////////
BOOL CPPDumpCtrl::IsAddressSelected(int nAddress)
{
	return ((nAddress >= m_nCaretAddrBegin) && (nAddress <= m_nCaretAddrEnd));
} //End of AddressInCaretRange


/////////////////////////////////////////////////////////////////////////////
//
//  CPPDumpCtrl::SetReadOnly (public member function)
//    Sets the read only style
//
//  Parameters :
//		bReadOnly [in] - If TRUE the control will available for read only
//
/////////////////////////////////////////////////////////////////////////////
void CPPDumpCtrl::SetReadOnly(BOOL bReadOnly /* = TRUE */)
{
	if ((m_pEdit != NULL) && ((m_nEditedArea & 0xF) > 0x1) && bReadOnly)
		KillEdit();

	if (bReadOnly) 
		ModifyStyles(PPDUMP_READ_ONLY, 0);
	else 
		ModifyStyles(0, PPDUMP_READ_ONLY);
} // End of ReadOnly

/////////////////////////////////////////////////////////////////////////////
//
//  CPPDumpCtrl::IsReadOnly (public member function)
//    Call this member function to determine if the control is read-only.
//    User can view the data, but cannot change it.
//
//  Returns :
//    TRUE if the control is read-only
//
/////////////////////////////////////////////////////////////////////////////
BOOL CPPDumpCtrl::IsReadOnly()
{
	return (BOOL)(m_nStyle & PPDUMP_READ_ONLY);
} // End of IsReadOnly

/////////////////////////////////////////////////////////////////////////////
//
//  CPPDumpCtrl::EnableSelect (public member function)
//    Enables/Disables the selection of the block of the data
//
//  Parameters :
//		bEnable [in] - If TRUE the control can selecting the block of the data
//
/////////////////////////////////////////////////////////////////////////////
void CPPDumpCtrl::EnableSelect(BOOL bEnable /* = TRUE */)
{
	if (bEnable) 
		ModifyStyles(PPDUMP_SELECTING_DATA, 0);
	else 
		ModifyStyles(0, PPDUMP_SELECTING_DATA);

	if (!bEnable)
	{
		//If select is enabled
		m_bPressedLButton = FALSE;
		SetSelectRange(m_nCaretAddrBegin);
	}
} //End of EnableSelect

/////////////////////////////////////////////////////////////////////////////
//
//  CPPDumpCtrl::IsEnableSelect (public member function)
//    Determines can user select the data or not.
//
//  Returns :
//    TRUE if user can select the block of the data.
//
/////////////////////////////////////////////////////////////////////////////
BOOL CPPDumpCtrl::IsEnableSelect()
{
	return (BOOL)(m_nStyle & PPDUMP_SELECTING_DATA);
} // End of IsEnableSelect

/////////////////////////////////////////////////////////////////////
// This function associates a menu to the control.
// The menu will be displayed clicking the control.
//
// Parameters:
//		[IN]	nMenu
//				ID number of the menu resource.
//				Pass NULL to remove any menu from the control.
//		[IN]	bRedraw
//				If TRUE the control will be repainted.
//
// Return value:
//		TRUE - Function executed successfully.
//		FALSE - Failed loading the specified resource.
//
///////////////////////////////////////////////////////////////////////
BOOL CPPDumpCtrl::SetMenu(UINT nMenu, BOOL bRedraw /* = TRUE */)
{
	HINSTANCE	hInstResource = NULL;

	// Destroy any previous menu
	if (m_hMenu)
	{
		::DestroyMenu(m_hMenu);
		m_hMenu = NULL;
	} // if

	// Load menu
	if (nMenu)
	{
		// Find correct resource handle
		hInstResource = AfxFindResourceHandle(MAKEINTRESOURCE(nMenu), RT_MENU);
		// Load menu resource
		m_hMenu = ::LoadMenu(hInstResource, MAKEINTRESOURCE(nMenu));
		// If something wrong
		if (m_hMenu == NULL)
			return FALSE;
	} // if

	// Repaint the control
	if (bRedraw) 
		Invalidate();

	return TRUE;
} // End of SetMenu

/////////////////////////////////////////////////////////////////////
// This function sets or removes the notification messages from the control.
//
// Parameters:
//		bNotify [in] - If TRUE the control will be send the notification 
//					   to parent window
//					   Else the notification will not send
///////////////////////////////////////////////////////////////////////
void CPPDumpCtrl::SetNotify(BOOL bNotify /* = TRUE */)
{
	HWND hWnd = NULL;

	if (bNotify)
		hWnd = GetParent()->m_hWnd;

	SetNotify(hWnd);
} //End SetNotify

/////////////////////////////////////////////////////////////////////
// This function sets or removes the notification messages from the control.
//
// Parameters:
//		hWnd [in] -    If non-NULL the control will be send the notification 
//					   to specified window
//					   Else the notification will not send
///////////////////////////////////////////////////////////////////////
void CPPDumpCtrl::SetNotify(HWND hWnd)
{
	m_hParentWnd = hWnd;
} //End SetNotify

/////////////////////////////////////////////////////////////////////
// This function determines will be send the notification messages from 
// the control or not.
//
// Return value:
//	TRUE if the control will be notified the specified window
///////////////////////////////////////////////////////////////////////
BOOL CPPDumpCtrl::GetNotify()
{
	return (m_hParentWnd != NULL);
}  //End GetNotify

///////////////////////////////////////////////////////////////////////
// This function sets the format string of the text to show in the control tooltip.
//
// Parameters:
//		[IN]	nText
//				ID number of the string resource containing the format string
//			    of the text to show.
//		[IN]	bActivate
//				If TRUE the tooltip will be created active.
///////////////////////////////////////////////////////////////////////
void CPPDumpCtrl::SetTooltipText(int nText, BOOL bActivate /* = TRUE */)
{
	CString sToolTip;
	// Load string resource
	sToolTip.LoadString(nText);
	// If string resource is not empty
	SetTooltipText(sToolTip, bActivate);
} // End of SetTooltipText

///////////////////////////////////////////////////////////////////////
// This function sets the format string of the text to show in the control tooltip.
//
// Parameters:
//		[IN]	sFormatTip
//				Pointer to a null-terminated string containing the format string
//			    of the text to show.
//		[IN]	bActivate
//				If TRUE the tooltip will be created active.
///////////////////////////////////////////////////////////////////////
void CPPDumpCtrl::SetTooltipText(CString sFormatTip, BOOL bActivate /* = TRUE */)
{
	// Initialize ToolTip
	InitToolTip();

	m_sFormatToolTip = sFormatTip;
	if (sFormatTip.IsEmpty())
		bActivate = FALSE;

	// If there is no tooltip defined then add it
	if (m_pToolTip.GetToolCount() == 0)
	{
		CRect rect; 
		GetClientRect(rect);
		m_pToolTip.AddTool(this, "", rect, 1);
	} // if

	m_pToolTip.Activate(bActivate);
} // End of SetTooltipText

////////////////////////////////////////////////////////////////////////
// This function enables or disables the control tooltip.
//
// Parameters:
//		[IN]	bActivate
//				If TRUE the tooltip will be activated.
////////////////////////////////////////////////////////////////////////
void CPPDumpCtrl::ActivateTooltip(BOOL bActivate /* = TRUE */)
{
	// If there is no tooltip then do nothing
	if (m_pToolTip.GetToolCount() == 0) 
		return;

	// Activate tooltip
	m_pToolTip.Activate(bActivate);
} // End of ActivateTooltip

////////////////////////////////////////////////////////////////////////
// This function gets pointer to the tooltip object
//
// Return values:
//	Function returns the pointer to the tooltip object
////////////////////////////////////////////////////////////////////////
CToolTipCtrl * CPPDumpCtrl::GetTooltip()
{
	// Initialize ToolTip
	InitToolTip();

	return &m_pToolTip;
} // End of GetTooltip

/////////////////////////////////////////////////////////////////////
// This function enables or disables the track mouse.
//
// Parameters:
//	bTrack	[in] - If TRUE the track mouse will enable
//	bRedraw	[in] - If TRUE the control will be repainted.
//
///////////////////////////////////////////////////////////////////////
void CPPDumpCtrl::SetTrackMouseMove(BOOL bTrack /* = TRUE */, BOOL bRedraw /* = TRUE */)
{
	if (IsTrackMouseMove() != bTrack)
	{
		if (bTrack)
			m_nStyle |= PPDUMP_TRACK_MOUSE_MOVE;
		else
			m_nStyle &= ~PPDUMP_TRACK_MOUSE_MOVE;
		// Repaint the control
		if (bRedraw) 
			Invalidate();
	}
} // End of SetTrackMouseMove

////////////////////////////////////////////////////////////////////////
// CPPDumpCtrl::IsTrackMouseMove
// This function returns whether the track mouse is enabled
//
// Return values:
//	Function returns TRUE if track mouse is enabled
////////////////////////////////////////////////////////////////////////
BOOL CPPDumpCtrl::IsTrackMouseMove()
{
	return (BOOL)(m_nStyle & PPDUMP_TRACK_MOUSE_MOVE);
} // End of IsTrackMouseMove

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
Software Developer SvyazInvest
Belarus Belarus
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions