You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2146 lines
40 KiB
C++

2 years ago
// XTPHexEdit.cpp : implementation of the CXTPHexEdit class.
//
// This file is a part of the XTREME CONTROLS MFC class library.
// (c)1998-2012 Codejock Software, All Rights Reserved.
//
// THIS SOURCE FILE IS THE PROPERTY OF CODEJOCK SOFTWARE AND IS NOT TO BE
// RE-DISTRIBUTED BY ANY MEANS WHATSOEVER WITHOUT THE EXPRESSED WRITTEN
// CONSENT OF CODEJOCK SOFTWARE.
//
// THIS SOURCE CODE CAN ONLY BE USED UNDER THE TERMS AND CONDITIONS OUTLINED
// IN THE XTREME TOOLKIT PRO LICENSE AGREEMENT. CODEJOCK SOFTWARE GRANTS TO
// YOU (ONE SOFTWARE DEVELOPER) THE LIMITED RIGHT TO USE THIS SOFTWARE ON A
// SINGLE COMPUTER.
//
// CONTACT INFORMATION:
// support@codejock.com
// http://www.codejock.com
//
/////////////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "../Resource.h"
#include "Common/XTPVC80Helpers.h" // Visual Studio 2005 helper functions
#include "Common/XTPResourceManager.h"
#include "Common/XTPColorManager.h"
#include "Common/XTPDrawHelpers.h"
#include "../Util/XTPFunctions.h"
#include "XTPHexEdit.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
static const CLIPFORMAT CF_BINARY = (CLIPFORMAT)
::RegisterClipboardFormat(_T("BinaryData"));
static const BYTE chHexTable[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
#define TOHEX(a, b) {*b++ = chHexTable[a >> 4]; *b++ = chHexTable[a & 0xf];}
/////////////////////////////////////////////////////////////////////////////
// CXTPHexEdit
/////////////////////////////////////////////////////////////////////////////
CXTPHexEdit::CXTPHexEdit()
{
m_pData = NULL;
m_nLength = 0;
m_nTopIndex = 0;
m_nCurrentAddress = 0;
m_nSelStart = -1;
m_nSelEnd = -1;
m_nBytePerRow = 8;
m_bDynamicBPR = FALSE;
m_nLinesPerPage = 1;
m_nLineHeight = 0;
m_nNullWidth = 0;
m_nOffHex = 0;
m_nOffAscii = 0;
m_nOffAddress = 0;
m_bShowHex = TRUE;
m_bShowAscii = TRUE;
m_bShowAddress = TRUE;
m_bAddressIsWide = TRUE;
m_bShowCaret = TRUE;
m_bUpdate = TRUE;
m_bAllowDeletes = true;
m_ptEditPos.x = 0;
m_ptEditPos.y = 0;
m_eEditMode = editNone;
m_szCaret = CSize(0, 0);
m_crBack = GetXtremeColor(COLOR_WINDOW);
m_crText = GetXtremeColor(COLOR_WINDOWTEXT);
m_crDisabledBack = GetXtremeColor(COLOR_3DFACE);
m_crDisabledText = GetXtremeColor(COLOR_GRAYTEXT);
m_crHighlightBack = GetXtremeColor(COLOR_HIGHLIGHT);
m_crHighlightText = GetXtremeColor(COLOR_HIGHLIGHTTEXT);
m_crDisabledHighlightText = GetXtremeColor(COLOR_HIGHLIGHTTEXT);
m_crDisabledHighlightBack = GetXtremeColor(COLOR_3DSHADOW);
m_nMaxLength = 0;
m_dwBaseAddress = 0;
_AFX_THREAD_STATE* pState = AfxGetThreadState();
if (!pState->m_bNeedTerm)
{
AfxOleInit();
}
// create the default font used by the hex edit control.
m_fontHex.CreateFont(-12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, _T("Courier New"));
}
CXTPHexEdit::~CXTPHexEdit()
{
if (m_fontHex.GetSafeHandle())
m_fontHex.DeleteObject();
if (m_pData)
{
free(m_pData);
m_pData = NULL;
}
}
IMPLEMENT_DYNAMIC(CXTPHexEdit, CWnd)
BEGIN_MESSAGE_MAP(CXTPHexEdit, CXTPHexEditBase)
//{{AFX_MSG_MAP(CXTPHexEdit)
ON_WM_CHAR()
ON_WM_KILLFOCUS()
ON_WM_PAINT()
ON_MESSAGE(WM_PRINTCLIENT, OnPrintClient)
ON_WM_SETFOCUS()
ON_WM_SIZE()
ON_WM_VSCROLL()
ON_WM_HSCROLL()
ON_WM_GETDLGCODE()
ON_WM_ERASEBKGND()
ON_WM_LBUTTONDOWN()
ON_WM_LBUTTONDBLCLK()
ON_WM_MOUSEMOVE()
ON_WM_LBUTTONUP()
ON_WM_KEYDOWN()
ON_WM_CONTEXTMENU()
ON_COMMAND(ID_EDIT_CLEAR, OnEditClear)
ON_COMMAND(ID_EDIT_COPY, OnEditCopy)
ON_COMMAND(ID_EDIT_CUT, OnEditCut)
ON_COMMAND(ID_EDIT_PASTE, OnEditPaste)
ON_COMMAND(ID_EDIT_SELECT_ALL, OnEditSelectAll)
ON_COMMAND(ID_EDIT_UNDO, OnEditUndo)
ON_WM_NCPAINT()
ON_WM_MOUSEWHEEL()
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
void CXTPHexEdit::RestoreDefaultFont()
{
if (m_fontHex.GetSafeHandle())
m_fontHex.DeleteObject();
// create the default font used by the hex edit control.
m_fontHex.CreateFont(-12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, _T("Courier New"));
}
void CXTPHexEdit::SetHexFont(CFont* pFont)
{
ASSERT(pFont->GetSafeHandle());
if (pFont->GetSafeHandle())
{
LOGFONT lf;
pFont->GetLogFont(&lf);
SetHexFont(&lf);
}
}
void CXTPHexEdit::SetHexFont(LOGFONT* pLogFont)
{
ASSERT(pLogFont != NULL);
if (m_fontHex.GetSafeHandle())
m_fontHex.DeleteObject();
m_fontHex.CreateFontIndirect(pLogFont);
}
COLORREF CXTPHexEdit::GetActualBackColor()
{
#ifdef _XTP_ACTIVEX
if (!IsWindowEnabled())
#else
if (IsReadOnly())
#endif
{
return m_crDisabledBack;
}
return m_crBack;
}
COLORREF CXTPHexEdit::GetActualTextColor()
{
if (!IsWindowEnabled())
{
return m_crDisabledText;
}
return m_crText;
}
COLORREF CXTPHexEdit::GetActualHighlightBackColor()
{
if (!IsWindowEnabled())
{
return m_crDisabledHighlightBack;
}
return m_crHighlightBack;
}
COLORREF CXTPHexEdit::GetActualHighlightTextColor()
{
if (!IsWindowEnabled())
{
return m_crDisabledHighlightText;
}
return m_crHighlightText;
}
void CXTPHexEdit::OnPaint()
{
CPaintDC dc(this);
// Paint to a memory device context to help
// eliminate screen flicker.
CXTPBufferDC memDC(dc);
OnDraw(&memDC);
}
LRESULT CXTPHexEdit::OnPrintClient(WPARAM wParam, LPARAM /*lParam*/)
{
CDC* pDC = CDC::FromHandle((HDC)wParam);
if (pDC)
{
OnDraw(pDC);
}
return 1;
}
void CXTPHexEdit::OnDraw(CDC* pDC)
{
// Get the client rect.
CXTPClientRect rectClient(this);
pDC->FillSolidRect(rectClient, GetActualBackColor());
// Save the current device context, we will restore this just
// before we loose scope.
int nSavedDC = pDC->SaveDC();
ASSERT(m_nCurrentAddress >= 0);
ASSERT(m_nTopIndex >= 0);
pDC->SelectObject(&m_fontHex);
int height = 0;
int x = rectClient.TopLeft().x;
int y = rectClient.TopLeft().y;
TCHAR buf[256];
pDC->SetBoundsRect(&rectClient, DCB_DISABLE);
pDC->SetTextColor(GetActualTextColor());
// Get char dimensions
if (m_bUpdate)
{
const int h_delta = ::GetScrollPos(m_hWnd, SB_HORZ) * m_nNullWidth;
pDC->GetCharWidth('0', '0', &m_nNullWidth);
CSize sz = pDC->GetTextExtent(_T("0"), 1);
m_nLineHeight = sz.cy;
const int width_address = (m_bAddressIsWide ? 9 : 5) * m_nNullWidth;
m_nOffHex = m_bShowAddress ? width_address : 0;
m_nOffAscii = m_nOffHex;
if (m_bShowHex) m_nOffAscii += m_nBytePerRow * 3 * m_nNullWidth;
m_nOffAddress = -h_delta;
m_nOffHex -= h_delta;
m_nOffAscii -= h_delta;
m_nLinesPerPage = rectClient.Height() / m_nLineHeight;
m_bUpdate = FALSE;
UpdateScrollbars();
}
if (m_pData)
{
height = rectClient.Height() / m_nLineHeight;
height *= m_nLineHeight;
if (m_bShowAddress)
{
y = 0;
CRect rcd = rectClient;
rcd.left = m_nOffAddress;
// draw address
int i;
for (i = m_nTopIndex;
(i < (m_nLength + 1)) && (rcd.TopLeft().y < height);
i += m_nBytePerRow)
{
const int width = m_bAddressIsWide ? 8 : 4;
#if (_MSC_VER > 1310) // VS2005
_stprintf_s(buf, _countof(buf), _T("%0*lX"), width, m_dwBaseAddress + i);
#else
_stprintf(buf, _T("%0*lX"), width, m_dwBaseAddress + i);
#endif
pDC->DrawText(buf, width, rcd,
DT_LEFT | DT_TOP | DT_SINGLELINE | DT_NOPREFIX);
rcd.TopLeft().y += m_nLineHeight;
}
}
if (m_bShowHex)
{
y = 0;
CRect rcd = rectClient;
rcd.left = x = m_nOffHex;
if (m_nSelStart != -1 && (m_eEditMode == editHigh || m_eEditMode == editLow))
{
int i;
int n = 0;
int selStart, selEnd;
GetSel(selStart, selEnd);
for (i = m_nTopIndex; (i < selStart) && (y < height); i++)
{
LPTSTR p = &buf[0];
TOHEX(m_pData[i], p);
*p++ = ' ';
pDC->TextOut(x, y, buf, 3);
x += m_nNullWidth * 3;
n++;
if (n == m_nBytePerRow)
{
n = 0;
x = m_nOffHex;
y += m_nLineHeight;
}
}
pDC->SetTextColor(GetActualHighlightTextColor());
pDC->SetBkColor(GetActualHighlightBackColor());
for (; (i < selEnd) && (i < m_nLength) && (y < height); i++)
{
LPTSTR p = &buf[0];
TOHEX(m_pData[i], p);
*p++ = ' ';
pDC->TextOut(x, y, buf, 3);
x += m_nNullWidth * 3;
n++;
if (n == m_nBytePerRow)
{
n = 0;
x = m_nOffHex;
y += m_nLineHeight;
}
}
pDC->SetTextColor(GetActualTextColor());
pDC->SetBkColor(GetActualBackColor());
for (; (i < m_nLength) && (y < height); i++)
{
LPTSTR p = &buf[0];
TOHEX(m_pData[i], p);
*p++ = ' ';
pDC->TextOut(x, y, buf, 3);
x += m_nNullWidth * 3;
n++;
if (n == m_nBytePerRow)
{
n = 0;
x = m_nOffHex;
y += m_nLineHeight;
}
}
}
else
{
int i;
for (i = m_nTopIndex; (i < m_nLength) && (rcd.TopLeft().y < height);)
{
LPTSTR p = &buf[0];
int n;
for (n = 0; (n < m_nBytePerRow) && (i < m_nLength); n++)
{
TOHEX(m_pData[i], p);
*p++ = ' ';
i++;
}
while (n < m_nBytePerRow)
{
*p++ = ' ';
*p++ = ' ';
*p++ = ' ';
n++;
}
pDC->DrawText(buf, m_nBytePerRow * 3, rcd, DT_LEFT | DT_TOP | DT_SINGLELINE | DT_NOPREFIX);
rcd.TopLeft().y += m_nLineHeight;
}
}
}
if (m_bShowAscii)
{
y = 0;
CRect rcd = rectClient;
rcd.left = x = m_nOffAscii;
if (m_nSelStart != -1 && m_eEditMode == editAscii)
{
int i;
int n = 0;
int selStart, selEnd;
GetSel(selStart, selEnd);
for (i = m_nTopIndex; (i < selStart) && (y < height); i++)
{
buf[0] = isprint(m_pData[i]) ? m_pData[i] : '.';
pDC->TextOut(x, y, buf, 1);
x += m_nNullWidth;
n++;
if (n == m_nBytePerRow)
{
n = 0;
x = m_nOffAscii;
y += m_nLineHeight;
}
}
pDC->SetTextColor(GetActualHighlightTextColor());
pDC->SetBkColor(GetActualHighlightBackColor());
for (; (i < selEnd) && (y < height); i++)
{
buf[0] = isprint(m_pData[i]) ? m_pData[i] : '.';
pDC->TextOut(x, y, buf, 1);
x += m_nNullWidth;
n++;
if (n == m_nBytePerRow)
{
n = 0;
x = m_nOffAscii;
y += m_nLineHeight;
}
}
pDC->SetTextColor(GetActualTextColor());
pDC->SetBkColor(GetActualBackColor());
for (; (i < m_nLength) && y < height; i++)
{
buf[0] = isprint(m_pData[i]) ? m_pData[i] : '.';
pDC->TextOut(x, y, buf, 1);
x += m_nNullWidth;
n++;
if (n == m_nBytePerRow)
{
n = 0;
x = m_nOffAscii;
y += m_nLineHeight;
}
}
}
else
{
int i;
for (i = m_nTopIndex; (i < m_nLength) && (rcd.top < height);)
{
LPTSTR p = &buf[0];
int n;
for (n = 0; (n < m_nBytePerRow) && (i < m_nLength); n++)
{
*p++ = isprint(m_pData[i]) ? m_pData[i] : '.';
i++;
}
pDC->DrawText(buf, n, rcd, DT_LEFT | DT_TOP | DT_SINGLELINE | DT_NOPREFIX);
rcd.top += m_nLineHeight;
}
}
}
}
// Restore the device context.
pDC->RestoreDC(nSavedDC);
}
void CXTPHexEdit::OnSetFocus(CWnd* pOldWnd)
{
CXTPHexEditBase::OnSetFocus(pOldWnd);
if (m_pData && !IsSelected())
{
if (m_ptEditPos.x == 0 && m_bShowAddress)
{
CreateAddressCaret();
}
else
{
CreateEditCaret();
}
RepositionCaret(m_nCurrentAddress);
}
}
void CXTPHexEdit::OnKillFocus(CWnd* pNewWnd)
{
DestroyCaret();
CXTPHexEditBase::OnKillFocus(pNewWnd);
}
void CXTPHexEdit::OnVScroll(UINT nSBCode, UINT /*nPos*/, CScrollBar* /*pScrollBar*/)
{
DoVScroll(nSBCode, false);
}
void CXTPHexEdit::DoVScroll(UINT nSBCode, bool bMoveCaret)
{
if (!m_pData)
{
return;
}
BOOL bVisible = GetStyle() & WS_VISIBLE;
// Turn off redraw while scrolling, this will cause paint problems
// with our control because we are painting off screen to reduce
// flicker. The default implementation assumes that WM_ERASEBKGND
// has repainted the background, which in our case does not happen.
if (bVisible) SetRedraw(FALSE);
const int oa = m_nTopIndex;
SCROLLINFO si;
ZeroMemory(&si, sizeof(SCROLLINFO));
si.cbSize = sizeof(SCROLLINFO);
si.fMask = SIF_PAGE | SIF_RANGE | SIF_POS;
if (GetStyle() & WS_VSCROLL)
{
VERIFY(::GetScrollInfo(m_hWnd, SB_VERT, &si));
}
else
{
si.nPage = si.nPos = si.nMin = si.nMax = 0;
}
switch (nSBCode)
{
case SB_LINEDOWN:
if (si.nPos < (si.nMax - (int)si.nPage + 1))
{
m_nTopIndex += m_nBytePerRow;
}
break;
case SB_LINEUP:
if (m_nTopIndex > 0)
{
m_nTopIndex -= m_nBytePerRow;
if (m_nTopIndex < 0) m_nTopIndex = 0;
}
break;
case SB_PAGEDOWN:
si.nPos += si.nPage;
if (si.nPos >= si.nMax) si.nPos = si.nMax;
m_nTopIndex = si.nPos * m_nBytePerRow;
break;
case SB_PAGEUP:
if (oa == 0)
{
m_nCurrentAddress = 0;
}
else
{
m_nTopIndex -= m_nBytePerRow * m_nLinesPerPage;
if (m_nTopIndex < 0)
m_nTopIndex = 0;
}
break;
case SB_THUMBTRACK:
si.fMask = SIF_TRACKPOS;
// Call GetScrollInfo to get current tracking
// position in si.nTrackPos
if (!::GetScrollInfo(m_hWnd, SB_VERT, &si))
{
return ; // GetScrollInfo failed
}
m_nTopIndex = si.nTrackPos * m_nBytePerRow;
break;
}
if (bMoveCaret)
{
m_nCurrentAddress += (m_nTopIndex - oa);
}
// bug fix by John M. Drescher jdrescher@geocities.com
if (m_nCurrentAddress < 0)
{
m_nCurrentAddress = 0;
}
UpdateScrollbars();
RepositionCaret(m_nCurrentAddress);
if (bVisible) SetRedraw(TRUE);
// repaint the list box
Invalidate();
UpdateWindow();
// repaint the scroll bar.
::SetWindowPos(m_hWnd, NULL, 0, 0, 0, 0,
SWP_NOMOVE | SWP_NOSIZE | SWP_FRAMECHANGED);
}
BOOL CXTPHexEdit::PreCreateWindow(CREATESTRUCT& cs)
{
if (!CXTPHexEditBase::PreCreateWindow(cs))
return FALSE;
return TRUE;
}
BOOL CXTPHexEdit::Create(DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID)
{
return Create(_T("EDIT"), 0, dwStyle, rect, pParentWnd, nID);
}
BOOL CXTPHexEdit::Create(LPCTSTR lpszClassName, LPCTSTR lpszWindowName, DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID, CCreateContext* pContext)
{
if (!CWnd::Create(lpszClassName, lpszWindowName, dwStyle, rect, pParentWnd, nID, pContext))
{
TRACE0("Failed to create hex edit control.\n");
return FALSE;
}
CWnd::SetFont(&m_fontHex);
return TRUE;
}
BOOL CXTPHexEdit::OnEraseBkgnd(CDC* /*pDC*/)
{
return TRUE;
}
void CXTPHexEdit::OnLButtonDown(UINT nFlags, CPoint point)
{
SetFocus();
if (!m_pData)
{
return;
}
if (nFlags & MK_SHIFT)
{
m_nSelStart = m_nCurrentAddress;
}
CPoint pt = CalcPos(point.x, point.y);
if (pt.x > -1)
{
m_ptEditPos = pt;
pt.x *= m_nNullWidth;
pt.y *= m_nLineHeight;
if (pt.x == 0 && m_bShowAddress)
{
CreateAddressCaret();
}
else
{
CreateEditCaret();
}
SetCaretPos(pt);
if (nFlags & MK_SHIFT)
{
m_nSelEnd = m_nCurrentAddress;
if (m_eEditMode == editHigh || m_eEditMode == editLow)
{
m_nSelEnd++;
}
RedrawWindow();
}
}
if (!(nFlags & MK_SHIFT))
{
if (::DragDetect(m_hWnd, point))
{
m_nSelStart = m_nCurrentAddress;
m_nSelEnd = m_nSelStart;
SetCapture();
}
else
{
BOOL bsel = m_nSelStart != -1;
m_nSelStart = -1;
m_nSelEnd = -1;
if (bsel)
{
RedrawWindow();
}
}
}
if (!IsSelected())
{
if (m_bShowCaret)
ShowCaret();
}
}
// in: pixels
// out: character coordinates + change of m_nCurrrentAddress
CPoint CXTPHexEdit::CalcPos(int x, int y)
{
if (y < 0 || x < 0)
return CPoint(-1, -1);
int lastVisRow = m_nLength / m_nBytePerRow - (m_nTopIndex / m_nBytePerRow);
int row = y / m_nLineHeight;
y = row + (m_nTopIndex / m_nBytePerRow);
// x += (m_nNullWidth - 1);
x /= m_nNullWidth;
//In address area
const int right_of_address = (m_nOffAddress / m_nNullWidth) + // one past last
(!m_bShowAddress ? -1 : (m_bAddressIsWide ? 8 : 4));
if (x < right_of_address)
{
//Set first byte in line as current.
m_nCurrentAddress = m_nTopIndex + (m_nBytePerRow * row);
m_eEditMode = editNone;
return CPoint(0, row);
}
//In hex area
const int right_of_hex_area = right_of_address +
(!m_bShowHex ? 0 : (m_nBytePerRow * 3)); //3 = 3 chars per byte (e.g. cc<space>)
if (m_bShowHex && x < right_of_hex_area)
{
if ((x % 3) == 2)
{
++x;
}
const int col = (x - right_of_address) / 3;
m_nCurrentAddress = m_nTopIndex +
(m_nBytePerRow * row) + col;
if (m_nCurrentAddress > m_nLength) // past end ?
{
x = m_nLength % m_nBytePerRow;
row = lastVisRow;
x *= 3;
x += (right_of_address + 1);
m_nCurrentAddress = m_nLength;
}
m_eEditMode = ((x % 3) == 0) ? editHigh : editLow;
return CPoint(x, row);
}
const int right_of_ascii_area = right_of_hex_area + m_nBytePerRow + 1;
if (m_bShowAscii && x < right_of_ascii_area)
{
if (x == right_of_hex_area) ++x; // advance from margin
const int col = x - right_of_hex_area - 1;
m_nCurrentAddress = m_nTopIndex + (m_nBytePerRow * row) + col;
if (m_nCurrentAddress > m_nLength) // past end ?
{
x = m_nLength % m_nBytePerRow;
row = lastVisRow;
x += (right_of_hex_area + 1);
m_nCurrentAddress = m_nLength;
}
m_eEditMode = editAscii;
return CPoint(x, row);
}
return CPoint(-1, -1);
}
void CXTPHexEdit::CreateAddressCaret()
{
DestroyCaret();
m_szCaret = CSize(m_nNullWidth * (m_bAddressIsWide ? 8 : 4),
m_nLineHeight);
CreateSolidCaret(m_szCaret.cx, m_szCaret.cy);
}
void CXTPHexEdit::CreateEditCaret()
{
DestroyCaret();
m_szCaret = CSize(m_nNullWidth, m_nLineHeight);
CreateSolidCaret(m_szCaret.cx, m_szCaret.cy);
}
void CXTPHexEdit::OnMouseMove(UINT nFlags, CPoint point)
{
if (!m_pData)
{
return;
}
if (nFlags & MK_LBUTTON && m_nSelStart != -1)
{
CRect rc;
GetClientRect(&rc);
if (!rc.PtInRect(point))
{
if (point.y < 0)
{
DoVScroll(SB_LINEUP, true);
point.y = 0;
}
else if (point.y > rc.Height())
{
DoVScroll(SB_LINEDOWN, true);
point.y = rc.Height() -1;
}
}
//
// we are selecting
//
int seo = m_nSelEnd;
CPoint pt = CalcPos(point.x, point.y);
if (pt.x > -1)
{
m_nSelEnd = m_nCurrentAddress;
if (m_eEditMode == editHigh || m_eEditMode == editLow)
{
m_nSelEnd++;
}
}
if (IsSelected())
{
DestroyCaret();
}
if (seo != m_nSelEnd)
{
RedrawWindow();
}
}
}
void CXTPHexEdit::UpdateScrollbars()
{
DWORD dwStyle = GetStyle();
SCROLLINFO si;
si.cbSize = sizeof(SCROLLINFO);
si.fMask = SIF_PAGE | SIF_RANGE | SIF_POS;
if (dwStyle & WS_VSCROLL)
{
bool bDisable = false;
si.nMin = 0;
si.nMax = m_nLength / m_nBytePerRow - 1; // - m_nLinesPerPage + 1;
if (si.nMax < m_nLinesPerPage - 1)
{
si.nMax = 1;
si.nPage = 1;
bDisable = true;
if (m_nTopIndex)
{
m_nTopIndex = 0;
RepositionCaret(m_nCurrentAddress);
}
}
else
{
si.nPage = m_nLinesPerPage - 1;
while (m_nTopIndex / m_nBytePerRow > (si.nMax - m_nLinesPerPage + 2) &&
m_nTopIndex > 0)
{
m_nTopIndex -= m_nBytePerRow;
RepositionCaret(m_nCurrentAddress);
}
}
if (m_nTopIndex < 0) m_nTopIndex = 0;
si.nPos = m_nTopIndex / m_nBytePerRow;
ModifyStyle(0, WS_VSCROLL);
if (!bDisable)
{
SetScrollInfo(SB_VERT, &si, TRUE);
EnableScrollBar(SB_VERT, ESB_ENABLE_BOTH);
}
else
{
si.nMax = si.nMin + 1;
si.nPage = si.nPos = 0;
SetScrollInfo(SB_VERT, &si, TRUE);
EnableScrollBar(SB_VERT, ESB_DISABLE_BOTH);
}
}
if (dwStyle & (WS_HSCROLL | ES_AUTOHSCROLL))
{
CRect rc;
GetClientRect(&rc);
si.nMin = 0;
si.nMax = ((m_bShowAddress ? (m_bAddressIsWide ? 9 : 5) : 0) +
(m_bShowHex ? m_nBytePerRow * 3 : 0) +
(m_bShowAscii ? m_nBytePerRow : 0));
si.nPage = m_nNullWidth == 0 ? 1 : __min(rc.Width() / m_nNullWidth, si.nMax);
si.nPos = 0;
BOOL bVisible = si.nMax * m_nNullWidth >= (int)rc.Width();
if (dwStyle & ES_AUTOHSCROLL)
{
ShowScrollBar(SB_HORZ, bVisible);
}
si.fMask &= ~SIF_POS;
SetScrollInfo(SB_HORZ, &si, TRUE);
if (bVisible && ((dwStyle & ES_AUTOHSCROLL) == 0))
{
EnableScrollBar(SB_HORZ, ESB_ENABLE_BOTH);
}
}
}
void CXTPHexEdit::OnLButtonUp(UINT nFlags, CPoint point)
{
if (IsSelected())
{
ReleaseCapture();
}
CWnd::OnLButtonUp(nFlags, point);
}
BOOL CXTPHexEdit::IsReadOnly() const
{
if (!IsWindowEnabled() || (GetStyle() & ES_READONLY) == ES_READONLY)
{
return TRUE;
}
return FALSE;
}
void CXTPHexEdit::OnChar(UINT nChar, UINT /*nRepCnt*/, UINT /*nFlags*/)
{
if (!m_pData)
{
return;
}
if (m_nCurrentAddress < 0) //Shouldn't happen
{
return;
}
if (nChar == '\t')
{
return;
}
if (::GetKeyState(VK_CONTROL) < 0)
{
switch (nChar)
{
case 0x03:
if (IsSelected())
{
OnEditCopy();
}
return;
case 0x16:
OnEditPaste();
return;
case 0x18:
if (IsSelected())
{
OnEditCut();
}
return;
case 0x1a:
OnEditUndo();
return;
}
}
if (IsReadOnly())
{
return;
}
if (nChar == 0x08) // backspace
{
if (GetAllowDeletes())
{
if (IsSelected())
{
OnEditClear();
}
else if (m_nCurrentAddress > 0)
{
m_nCurrentAddress--;
SelDelete(m_nCurrentAddress, m_nCurrentAddress + 1);
RepositionCaret(m_nCurrentAddress);
RedrawWindow();
OnChange();
}
else
{
MessageBeep(0);
}
}
return;
}
// can't go past end of buffer
if ((UINT)m_nCurrentAddress >= m_nMaxLength)
{
MessageBeep(0);
return;
}
if (m_eEditMode != editNone)
{
// see if need to grow the buffer
if (m_nCurrentAddress >= m_nLength)
{
int iNewLength = (m_nLength + 1);
LPBYTE p = (LPBYTE) calloc(iNewLength, 1);
MEMCPY_S(p, m_pData, m_nLength);
free(m_pData);
m_pData = p;
SetSel(-1, -1);
m_nLength = iNewLength;
m_bUpdate = TRUE;
}
}
SetSel(-1, -1);
switch (m_eEditMode)
{
case editNone:
return;
case editHigh:
case editLow:
if (isxdigit(nChar))
{
UINT b = 0;
if (nChar >= 'a')
b = 10 + nChar - 'a';
else if (nChar >= 'A')
b = 10 + nChar - 'A';
else if (nChar >= '0')
b = nChar - '0';
else
break;
if (b >= 16)
break;
if (m_eEditMode == editHigh)
{
m_pData[m_nCurrentAddress] = (unsigned char)((m_pData[m_nCurrentAddress] & 0x0f) | (b << 4));
}
else
{
m_pData[m_nCurrentAddress] = (unsigned char)((m_pData[m_nCurrentAddress] & 0xf0) | b);
}
Move(1, 0);
OnChange();
}
break;
case editAscii:
m_pData[m_nCurrentAddress] = (unsigned char)nChar;
Move(1, 0);
OnChange();
break;
}
RedrawWindow();
}
void CXTPHexEdit::OnKeyDown(UINT nChar, UINT /*nRepCnt*/, UINT /*nFlags*/)
{
BOOL bShift = (::GetKeyState(VK_SHIFT) < 0);
switch (nChar)
{
case VK_DOWN:
if (bShift)
{
if (!IsSelected())
{
m_nSelStart = m_nCurrentAddress;
}
Move(0, 1);
m_nSelEnd = m_nCurrentAddress;
if (m_eEditMode == editHigh || m_eEditMode == editLow)
{
m_nSelEnd++;
}
RedrawWindow();
break;
}
else
{
SetSel(-1, -1);
}
Move(0, 1);
break;
case VK_UP:
if (bShift)
{
if (!IsSelected())
{
m_nSelStart = m_nCurrentAddress;
}
Move(0, -1);
m_nSelEnd = m_nCurrentAddress;
RedrawWindow();
break;
}
else
{
SetSel(-1, -1);
}
Move(0, -1);
break;
case VK_LEFT:
if (bShift)
{
if (!IsSelected())
{
m_nSelStart = m_nCurrentAddress;
}
Move(-1, 0);
m_nSelEnd = m_nCurrentAddress;
RedrawWindow();
break;
}
else
{
SetSel(-1, -1);
}
Move(-1, 0);
break;
case VK_RIGHT:
if (bShift)
{
if (!IsSelected())
{
m_nSelStart = m_nCurrentAddress;
}
Move(1, 0);
m_nSelEnd = m_nCurrentAddress;
if (m_eEditMode == editHigh || m_eEditMode == editLow)
{
m_nSelEnd++;
}
RedrawWindow();
break;
}
else
{
SetSel(-1, -1);
}
Move(1, 0);
break;
case VK_PRIOR:
if (bShift)
{
if (!IsSelected())
{
m_nSelStart = m_nCurrentAddress;
}
DoVScroll(SB_PAGEUP, true);
Move(0, 0);
m_nSelEnd = m_nCurrentAddress;
RedrawWindow();
break;
}
else
{
SetSel(-1, -1);
}
DoVScroll(SB_PAGEUP, true);
Move(0, 0);
break;
case VK_NEXT:
if (bShift)
{
if (!IsSelected())
{
m_nSelStart = m_nCurrentAddress;
}
DoVScroll(SB_PAGEDOWN, true);
Move(0, 0);
m_nSelEnd = m_nCurrentAddress;
RedrawWindow();
break;
}
else
{
SetSel(-1, -1);
}
DoVScroll(SB_PAGEDOWN, true);
Move(0, 0);
break;
case VK_HOME:
if (m_eEditMode == editLow)
{
m_eEditMode = editHigh;
}
if (bShift)
{
if (!IsSelected())
{
m_nSelStart = m_nCurrentAddress;
}
if (::GetKeyState(VK_CONTROL) < 0)
{
DoVScroll(SB_THUMBTRACK, true);
Move(0, 0);
}
else
{
m_nCurrentAddress /= m_nBytePerRow;
m_nCurrentAddress *= m_nBytePerRow;
Move(0, 0);
}
m_nSelEnd = m_nCurrentAddress;
RedrawWindow();
break;
}
else
{
SetSel(-1, -1);
}
if (::GetKeyState(VK_CONTROL) < 0)
{
m_nTopIndex = m_nCurrentAddress = 0;
UpdateScrollbars();
RepositionCaret(m_nCurrentAddress);
RedrawWindow();
}
else
{
m_nCurrentAddress /= m_nBytePerRow;
m_nCurrentAddress *= m_nBytePerRow;
Move(0, 0);
}
break;
case VK_END:
if (m_eEditMode == editLow)
{
m_eEditMode = editHigh;
}
if (bShift)
{
if (!IsSelected())
{
m_nSelStart = m_nCurrentAddress;
}
if (::GetKeyState(VK_CONTROL) < 0)
{
m_nCurrentAddress = m_nLength-1;
DoVScroll(SB_PAGEDOWN, false);
Move(0, 0);
}
else
{
m_nCurrentAddress /= m_nBytePerRow;
m_nCurrentAddress *= m_nBytePerRow;
m_nCurrentAddress += m_nBytePerRow - 1;
if (m_nCurrentAddress > m_nLength)
{
m_nCurrentAddress = m_nLength;
}
Move(0, 0);
}
m_nSelEnd = m_nCurrentAddress;
RedrawWindow();
break;
}
else
{
SetSel(-1, -1);
}
if (::GetKeyState(VK_CONTROL) < 0)
{
m_nCurrentAddress = m_nLength;
DoVScroll(SB_PAGEDOWN, false);
Move(0, 0);
}
else
{
m_nCurrentAddress /= m_nBytePerRow;
m_nCurrentAddress *= m_nBytePerRow;
m_nCurrentAddress += m_nBytePerRow - 1;
if (m_nCurrentAddress > m_nLength)
m_nCurrentAddress = m_nLength;
Move(0, 0);
}
break;
case VK_INSERT:
if (IsReadOnly())
break;
SelInsert(m_nCurrentAddress, __max(1, m_nSelEnd-m_nSelStart));
RepositionCaret(m_nCurrentAddress);
OnChange();
RedrawWindow();
break;
case VK_DELETE:
if (IsReadOnly())
break;
if (GetAllowDeletes())
{
if (IsSelected())
{
OnEditClear();
}
else
{
if (m_nCurrentAddress < m_nLength)
{
SelDelete(m_nCurrentAddress, m_nCurrentAddress + 1);
RedrawWindow();
OnChange();
}
else
{
MessageBeep(0);
}
}
}
break;
case VK_TAB:
{
int next_win_sel = 0;
switch (m_eEditMode)
{
case editNone:
m_eEditMode = editHigh;
break;
case editHigh:
case editLow:
if (bShift)
{
next_win_sel = GW_HWNDPREV;
}
else
{
m_eEditMode = editAscii;
}
break;
case editAscii:
if (bShift)
{
m_eEditMode = editHigh;
}
else
{
next_win_sel = GW_HWNDNEXT;
}
break;
}
if (next_win_sel)
{
CWnd *pWnd = this;
for (;;)
{
pWnd = pWnd->GetNextWindow(next_win_sel);
if (pWnd == this)
{
break;
}
if (pWnd == NULL)
{
if (next_win_sel == GW_HWNDNEXT)
{
pWnd = GetNextWindow(GW_HWNDFIRST);
}
else
{
pWnd = GetNextWindow(GW_HWNDLAST);
}
}
if (pWnd->GetStyle() & WS_TABSTOP)
{
pWnd->SetFocus();
break;
}
if (pWnd == this)
{
m_eEditMode = editHigh;
Move(0, 0);
break;
}
}
}
else
{
Move(0, 0);
}
break;
}
}
}
void CXTPHexEdit::Move(int x, int y)
{
switch (m_eEditMode)
{
case editNone:
return;
case editHigh:
if (x != 0)
m_eEditMode = editLow;
if (x == -1)
m_nCurrentAddress--;
m_nCurrentAddress += y * m_nBytePerRow;
break;
case editLow:
if (x != 0)
m_eEditMode = editHigh;
if (x == 1)
m_nCurrentAddress++;
m_nCurrentAddress += y * m_nBytePerRow;
break;
case editAscii:
{
m_nCurrentAddress += x;
m_nCurrentAddress += y * m_nBytePerRow;
}
break;
}
if (m_nCurrentAddress < 0)
{
m_nCurrentAddress = 0;
}
if (m_nCurrentAddress >= m_nLength)
{
m_nCurrentAddress = m_nLength;
}
if ((x | y) != 0 && m_nCurrentAddress < m_nTopIndex)
{
DoVScroll(SB_LINEUP, false);
}
if ((x | y) != 0 &&
m_nCurrentAddress >= m_nTopIndex + m_nLinesPerPage * m_nBytePerRow)
{
DoVScroll(SB_LINEDOWN, false);
}
//ScrollIntoView(m_nCurrentAddress);
RepositionCaret(m_nCurrentAddress);
}
void CXTPHexEdit::SetSel(int nSelStart, int nSelEnd)
{
#ifdef _DEBUG
_CrtCheckMemory();
#endif
if (GetFocus() == this)
DestroyCaret();
m_nSelStart = nSelStart;
m_nSelEnd = nSelEnd;
if (!IsWindow(m_hWnd))
return;
RedrawWindow();
if (GetFocus() == this)
{
if (m_ptEditPos.x == 0 && m_bShowAddress)
{
CreateAddressCaret();
}
else
{
CreateEditCaret();
}
RepositionCaret(m_nCurrentAddress);
if (m_bShowCaret)
ShowCaret();
}
}
void CXTPHexEdit::RepositionCaret(int p)
{
if (GetFocus() != this)
return;
int x, y;
y = (p - m_nTopIndex) / m_nBytePerRow;
x = (p - m_nTopIndex) % m_nBytePerRow;
switch (m_eEditMode)
{
case editNone:
CreateAddressCaret();
x = m_nOffAddress;
break;
case editHigh:
CreateEditCaret();
x *= m_nNullWidth * 3;
x += m_nOffHex;
break;
case editLow:
CreateEditCaret();
x *= m_nNullWidth * 3;
x += m_nNullWidth;
x += m_nOffHex;
break;
case editAscii:
CreateEditCaret();
x *= m_nNullWidth;
x += m_nOffAscii;
break;
}
m_ptEditPos.x = x;
m_ptEditPos.y = y*m_nLineHeight;
CRect rc;
GetClientRect(&rc);
CRect rcCarret(m_ptEditPos, m_szCaret);
CRect rcInt;
rcInt.IntersectRect(rcCarret, rc);
if (rcInt == rcCarret)
{
SetCaretPos(m_ptEditPos);
if (m_bShowCaret)
ShowCaret();
}
}
void CXTPHexEdit::ScrollIntoView(int p)
{
if (p < m_nTopIndex || p > m_nTopIndex + m_nLinesPerPage*m_nBytePerRow)
{
m_nTopIndex = (p/m_nBytePerRow) * m_nBytePerRow;
m_nTopIndex -= (m_nLinesPerPage / 3) * m_nBytePerRow;
if (m_nTopIndex < 0)
{
m_nTopIndex = 0;
}
UpdateScrollbars();
RedrawWindow();
}
}
void CXTPHexEdit::OnContextMenu(CWnd*, CPoint point)
{
if (point.x == -1 && point.y == -1)
{
//keystroke invocation
CRect rect;
GetClientRect(rect);
ClientToScreen(rect);
point = rect.TopLeft();
point.Offset(5, 5);
}
CMenu menu;
XTPResourceManager()->LoadMenu(&menu, XTP_IDM_POPUP);
CMenu* pPopup = menu.GetSubMenu(1);
ASSERT(pPopup != NULL);
if (!pPopup)
return;
const int DISABLE_FLAGS = MF_GRAYED | MF_DISABLED | MF_BYCOMMAND;
pPopup->EnableMenuItem(ID_EDIT_UNDO, DISABLE_FLAGS);
if (!GetAllowDeletes() || IsReadOnly())
{
pPopup->EnableMenuItem(ID_EDIT_CLEAR, DISABLE_FLAGS);
pPopup->EnableMenuItem(ID_EDIT_CUT, DISABLE_FLAGS);
}
if (!IsSelected())
{
pPopup->EnableMenuItem(ID_EDIT_CLEAR, DISABLE_FLAGS);
pPopup->EnableMenuItem(ID_EDIT_CUT, DISABLE_FLAGS);
pPopup->EnableMenuItem(ID_EDIT_COPY, DISABLE_FLAGS);
}
if (IsReadOnly())
{
pPopup->EnableMenuItem(ID_EDIT_PASTE, DISABLE_FLAGS);
}
else if (OpenClipboard())
{
if (!IsClipboardFormatAvailable(CF_TEXT) &&
!IsClipboardFormatAvailable(CF_BINARY))
{
pPopup->EnableMenuItem(ID_EDIT_PASTE, DISABLE_FLAGS);
}
::CloseClipboard();
}
XTPContextMenu(pPopup, TPM_LEFTALIGN | TPM_RIGHTBUTTON, point.x, point.y, this, XTP_IDR_TBAR_HEXEDIT);
}
void CXTPHexEdit::OnEditClear()
{
if (IsReadOnly())
{
return;
}
if (!GetAllowDeletes())
return;
NormalizeSel();
m_nCurrentAddress = m_nSelStart;
SelDelete(m_nSelStart, m_nSelEnd);
RepositionCaret(m_nCurrentAddress);
RedrawWindow();
OnChange();
}
void CXTPHexEdit::OnEditCopy()
{
if (!OpenClipboard()) return;
NormalizeSel();
::EmptyClipboard();
const int dwLen = m_nSelEnd - m_nSelStart;
HGLOBAL hMemb = ::GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE | GMEM_ZEROINIT, dwLen);
if (!hMemb)
{
CloseClipboard();
return;
}
// copy binary
ASSERT(hMemb != NULL);
LPBYTE p = (BYTE*)::GlobalLock(hMemb);
if (!p)
return;
MEMCPY_S(p, m_pData + m_nSelStart, dwLen);
::GlobalUnlock(hMemb);
HGLOBAL hMema = NULL;
if (m_eEditMode != editAscii)
{
hMema = ::GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE | GMEM_ZEROINIT, dwLen * 3 + 1);
if (!hMema)
{
CloseClipboard();
return;
}
// copy ascii
p = (BYTE*)::GlobalLock(hMema);
if (!p)
return;
int i;
for (i = 0; i < dwLen;)
{
TOHEX(m_pData[m_nSelStart + i], p);
*p++ = ' ';
i++;
}
::GlobalUnlock(hMema);
}
else
{
hMema = ::GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE | GMEM_ZEROINIT, dwLen + 1);
if (!hMema)
{
CloseClipboard();
return;
}
// copy ascii
p = (BYTE*)::GlobalLock(hMema);
if (!p)
return;
MEMCPY_S(p, m_pData + m_nSelStart, dwLen);
p[dwLen] = 0;
for (int i = 0; i < dwLen; p++, i++)
{
if (!isprint(*p))
{
*p = '.';
}
}
::GlobalUnlock(hMema);
}
::SetClipboardData(CF_TEXT, hMema);
::SetClipboardData(CF_BINARY, hMemb);
VERIFY(CloseClipboard());
}
void CXTPHexEdit::OnEditCut()
{
if (IsReadOnly())
return;
OnEditCopy();
SelDelete(m_nSelStart, m_nSelEnd);
RedrawWindow();
}
void CXTPHexEdit::OnEditPaste()
{
if (IsReadOnly())
return;
if (!OpenClipboard()) return;
HGLOBAL hmem = NULL;
LPBYTE p = NULL;
DWORD dwLen = 0;
if (::IsClipboardFormatAvailable(CF_BINARY))
{
hmem = ::GetClipboardData(CF_BINARY);
p = hmem ? (BYTE*)::GlobalLock(hmem) : NULL;
dwLen = hmem ? (DWORD)::GlobalSize(hmem) : 0;
}
else if (::IsClipboardFormatAvailable(CF_TEXT))
{
hmem = ::GetClipboardData(CF_TEXT);
p = hmem ? (BYTE*)::GlobalLock(hmem) : NULL;
dwLen = p ? (DWORD)strlen((char*)p) : 0;
}
if (p && dwLen > 0)
{
int insert;
if (m_nCurrentAddress > m_nLength)
m_nCurrentAddress = m_nLength;
int oa = m_nCurrentAddress;
NormalizeSel();
if (m_nSelStart == -1)
{
if (m_eEditMode == editLow)
{
m_nCurrentAddress++;
}
if (m_nCurrentAddress > m_nLength)
{
m_nCurrentAddress = m_nLength;
}
insert = m_nCurrentAddress;
SelInsert(m_nCurrentAddress, dwLen);
}
else
{
insert = m_nSelStart;
SelDelete(m_nSelStart, m_nSelEnd);
SelInsert(insert, dwLen);
SetSel(-1, -1);
}
if (insert + dwLen > m_nMaxLength)
{
dwLen = m_nMaxLength - insert;
}
MEMCPY_S(m_pData + insert, p, dwLen);
#ifdef _DEBUG
_CrtCheckMemory();
#endif
OnChange();
m_nCurrentAddress = oa;
RedrawWindow();
}
if (hmem)
{
::GlobalUnlock(hmem);
}
::CloseClipboard();
}
void CXTPHexEdit::OnEditSelectAll()
{
m_nSelStart = 0;
m_nSelEnd = m_nLength;
DestroyCaret();
RedrawWindow();
}
void CXTPHexEdit::OnEditUndo()
{
}
void CXTPHexEdit::NormalizeSel()
{
if (m_nSelStart > m_nSelEnd)
{
int nSelStart = m_nSelStart;
m_nSelStart = m_nSelEnd;
m_nSelEnd = nSelStart;
}
if (m_nSelStart > m_nLength)
{
m_nSelStart = m_nLength;
}
if (m_nSelEnd > m_nLength)
{
m_nSelEnd = m_nLength;
}
}
void CXTPHexEdit::GetSel(int& nSelStart, int& nSelEnd)
{
nSelStart = m_nSelStart;
nSelEnd = m_nSelEnd;
if (nSelStart > nSelEnd)
{
nSelStart = m_nSelEnd;
nSelEnd = m_nSelStart;
}
if (nSelStart > m_nLength)
nSelStart = m_nLength;
if (nSelEnd > m_nLength)
nSelEnd = m_nLength;
}
void CXTPHexEdit::OnChange()
{
CWnd* pOwner = GetOwner();
ASSERT_VALID(pOwner);
if (pOwner != NULL)
{
pOwner->SendMessage(WM_COMMAND, MAKEWPARAM(GetDlgCtrlID(), EN_CHANGE), (LPARAM)m_hWnd);
}
}
void CXTPHexEdit::SelDelete(int nSelStart, int nSelEnd)
{
if (!GetAllowDeletes())
return;
#ifdef _DEBUG
_CrtCheckMemory();
#endif
if (nSelStart >= m_nLength)
return;
NormalizeSel();
const int nSelSize = (nSelEnd-nSelStart);
const int newLength = m_nLength - nSelSize;
if (newLength < 0)
return;
MEMMOVE_S(m_pData + nSelStart, m_pData + nSelEnd,
m_nLength - nSelEnd);
SetSel(-1, -1);
m_nLength = newLength;
if (m_nCurrentAddress > m_nLength)
{
m_nCurrentAddress = m_nLength;
RepositionCaret(m_nCurrentAddress);
}
m_bUpdate = TRUE;
}
void CXTPHexEdit::SelInsert(int nSelStart, int nLength)
{
if ((UINT)(m_nLength + nLength) > m_nMaxLength)
{
nLength = (int)m_nMaxLength - m_nLength;
}
if (nLength <= 0)
{
MessageBeep(0);
return;
}
if (nSelStart > m_nLength)
{
nSelStart = m_nLength;
}
LPBYTE p = (LPBYTE) calloc(m_nLength + nLength, 1);
MEMCPY_S(p, m_pData, nSelStart);
if (m_nLength > nSelStart)
{
MEMCPY_S(p + nSelStart + nLength, m_pData + nSelStart, (m_nLength - nSelStart));
}
free(m_pData);
m_pData = p;
SetSel(-1, -1);
m_nLength = m_nLength + nLength;
m_bUpdate = TRUE;
}
void CXTPHexEdit::SetData(LPBYTE p, int nLength, int nMaxLength)
{
if (m_pData)
free(m_pData);
m_pData = (LPBYTE) malloc(nLength);
MEMCPY_S(m_pData, p, nLength);
SetSel(-1, -1);
m_nMaxLength = nMaxLength < 0 ? -1 : __max(nMaxLength, nLength);
m_nLength = nLength;
m_nCurrentAddress = 0;
m_ptEditPos.x = m_ptEditPos.y = 0;
m_eEditMode = editHigh;
m_nTopIndex = 0;
m_bUpdate = TRUE;
if (m_hWnd)
{
UpdateScrollbars();
RepositionCaret(m_nCurrentAddress);
RedrawWindow();
// this will force the scroll bars to update if this is before the
// initial update
if (GetStyle() & WS_VSCROLL)
{
PostMessage(WM_VSCROLL, (WPARAM)-1, 0);
}
}
}
void CXTPHexEdit::OnHScroll(UINT nSBCode, UINT /*nPos*/, CScrollBar* /*pScrollBar*/)
{
SCROLLINFO si;
ZeroMemory(&si, sizeof(SCROLLINFO));
si.cbSize = sizeof(SCROLLINFO);
si.fMask = SIF_PAGE | SIF_RANGE | SIF_POS | SIF_TRACKPOS;
VERIFY(::GetScrollInfo(m_hWnd, SB_HORZ, &si));
int newpos = si.nPos;
switch (nSBCode)
{
case SB_LINELEFT:
--newpos;
break;
case SB_LINERIGHT:
++newpos;
break;
case SB_PAGELEFT:
newpos -= si.nPage;
break;
case SB_PAGERIGHT:
newpos += si.nPage;
break;
case SB_THUMBTRACK:
newpos = si.nTrackPos;
break;
}
if (newpos < 0)
{
newpos = 0;
}
else if (newpos > si.nMax)
{
newpos = si.nMax;
}
if (newpos != si.nPos)
{
m_bUpdate = true;
::SetScrollPos(m_hWnd, SB_HORZ, newpos, TRUE);
RedrawWindow();
RepositionCaret(m_nCurrentAddress);
}
}
void CXTPHexEdit::OnLButtonDblClk(UINT /*nFlags*/, CPoint /*point*/)
{
}
DWORD CXTPHexEdit::SetAddressBase(DWORD dwBase)
{
DWORD dwOldAddress = m_dwBaseAddress;
m_dwBaseAddress = dwBase;
m_bUpdate = TRUE;
return dwOldAddress;
}
void CXTPHexEdit::OnSize(UINT nType, int cx, int cy)
{
BOOL bVisible = GetStyle() & WS_VISIBLE;
if (bVisible) SetRedraw(FALSE);
CXTPHexEditBase::OnSize(nType, cx, cy);
if (m_bDynamicBPR)
{
RecalcBPR();
}
m_bUpdate = TRUE;
UpdateScrollbars();
if (bVisible)
{
SetRedraw(TRUE);
Invalidate();
UpdateWindow();
}
}
void CXTPHexEdit::RecalcBPR()
{
CDC* dc = GetDC();
HGDIOBJ hOldFont = dc->SelectObject(&m_fontHex);
dc->GetCharWidth('0', '0', &m_nNullWidth);
CRect rc;
GetClientRect(rc);
int cx = rc.Width();
if (m_bShowAddress)
cx -= m_nOffHex;
if (m_bShowAscii && m_bShowHex)
{
m_nBytePerRow = ((cx * 2) / 3) / (3 * m_nNullWidth); // 2/3rd is hex, 1/3rd is ascii
}
else if (m_bShowHex)
{
m_nBytePerRow = cx / (3 * m_nNullWidth);
}
else if (m_bShowAscii)
{
m_nBytePerRow = cx / m_nNullWidth;
}
m_bUpdate = TRUE;
if (m_nBytePerRow <= 0)
m_nBytePerRow = 1;
dc->SelectObject(hOldFont);
ReleaseDC(dc);
}
void CXTPHexEdit::OnNcPaint()
{
// Use the OnNcPaint() handler to prevent the caret
// from being shown when the control is first displayed
CXTPHexEditBase::OnNcPaint(); // Be sure and call the parent class
//HideCaret(); // Hide the caret
}
BOOL CXTPHexEdit::OnMouseWheel(UINT /*nFlags*/, short zDelta, CPoint /*pt*/)
{
OnVScroll(zDelta < 0 ? SB_LINEDOWN : SB_LINEUP, 0, NULL);
return TRUE;
}
void CXTPHexEdit::EnableScrollBars(bool /*bVertical*/, bool /*bHorizontal*/)
{
XTP_ERROR_MSG(
"CXTPHexEdit::EnableScrollBars has been deprecated.\n"
"\n"
"You should now set scroll bars for the control through WS_HSCROLL/WS_VSCROLL and/or the resource editor."
);
}
int CXTPHexEdit::GetData(LPBYTE pData, int nLength)
{
MEMCPY_S(pData, m_pData, __min(nLength, m_nLength));
return m_nLength;
}