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++
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;
|
||
|
}
|