XTHexEdit.cpp
上传用户:szled88
上传日期:2015-04-09
资源大小:43957k
文件大小:41k
源码类别:

对话框与窗口

开发平台:

Visual C++

  1. // XTHexEdit.cpp : implementation of the CXTHexEdit class.
  2. //
  3. // This file is a part of the XTREME CONTROLS MFC class library.
  4. // (c)1998-2008 Codejock Software, All Rights Reserved.
  5. //
  6. // THIS SOURCE FILE IS THE PROPERTY OF CODEJOCK SOFTWARE AND IS NOT TO BE
  7. // RE-DISTRIBUTED BY ANY MEANS WHATSOEVER WITHOUT THE EXPRESSED WRITTEN
  8. // CONSENT OF CODEJOCK SOFTWARE.
  9. //
  10. // THIS SOURCE CODE CAN ONLY BE USED UNDER THE TERMS AND CONDITIONS OUTLINED
  11. // IN THE XTREME TOOLKIT PRO LICENSE AGREEMENT. CODEJOCK SOFTWARE GRANTS TO
  12. // YOU (ONE SOFTWARE DEVELOPER) THE LIMITED RIGHT TO USE THIS SOFTWARE ON A
  13. // SINGLE COMPUTER.
  14. //
  15. // CONTACT INFORMATION:
  16. // support@codejock.com
  17. // http://www.codejock.com
  18. //
  19. /////////////////////////////////////////////////////////////////////////////
  20. #include "stdafx.h"
  21. #include "Resource.h"
  22. #include "Common/XTPVC80Helpers.h"  // Visual Studio 2005 helper functions
  23. #include "Common/XTPResourceManager.h"
  24. #include "Common/XTPColorManager.h"
  25. #include "Common/XTPDrawHelpers.h"
  26. #include "XTFunctions.h"
  27. #include "XTHexEdit.h"
  28. #ifdef _DEBUG
  29. #define new DEBUG_NEW
  30. #undef THIS_FILE
  31. static char THIS_FILE[] = __FILE__;
  32. #endif
  33. static const CLIPFORMAT CF_BINARY = (CLIPFORMAT)
  34. ::RegisterClipboardFormat(_T("BinaryData"));
  35. static const BYTE chHexTable[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
  36. #define TOHEX(a, b) {*b++ = chHexTable[a >> 4]; *b++ = chHexTable[a & 0xf];}
  37. /////////////////////////////////////////////////////////////////////////////
  38. // CXTHexEdit
  39. /////////////////////////////////////////////////////////////////////////////
  40. CXTHexEdit::CXTHexEdit()
  41. {
  42. m_pData = NULL;
  43. m_nLength = 0;
  44. m_nTopIndex = 0;
  45. m_nCurrentAddress = 0;
  46. m_nSelStart = -1;
  47. m_nSelEnd = -1;
  48. m_nBytePerRow = 8;
  49. m_bDynamicBPR = FALSE;
  50. m_nLinesPerPage = 1;
  51. m_nLineHeight = 0;
  52. m_nNullWidth = 0;
  53. m_nOffHex = 0;
  54. m_nOffAscii = 0;
  55. m_nOffAddress = 0;
  56. m_bShowHex = TRUE;
  57. m_bShowAscii = TRUE;
  58. m_bShowAddress = TRUE;
  59. m_bAddressIsWide = TRUE;
  60. m_bShowCaret = TRUE;
  61. m_bUpdate = TRUE;
  62. m_bAllowDeletes = true;
  63. m_ptEditPos.x = 0;
  64. m_ptEditPos.y = 0;
  65. m_eEditMode = editNone;
  66. m_szCaret = CSize(0, 0);
  67. m_crBack = GetXtremeColor(COLOR_WINDOW);
  68. m_crText = GetXtremeColor(COLOR_WINDOWTEXT);
  69. m_crDisabledBack = GetXtremeColor(COLOR_3DFACE);
  70. m_crDisabledText = GetXtremeColor(COLOR_GRAYTEXT);
  71. m_crHighlightBack = GetXtremeColor(COLOR_HIGHLIGHT);
  72. m_crHighlightText = GetXtremeColor(COLOR_HIGHLIGHTTEXT);
  73. m_crDisabledHighlightText = GetXtremeColor(COLOR_HIGHLIGHTTEXT);
  74. m_crDisabledHighlightBack = GetXtremeColor(COLOR_3DSHADOW);
  75. m_nMaxLength = 0;
  76. m_dwBaseAddress = 0;
  77. _AFX_THREAD_STATE* pState = AfxGetThreadState();
  78. if (!pState->m_bNeedTerm)
  79. {
  80. AfxOleInit();
  81. }
  82. // create the default font used by the hex edit control.
  83. m_fontHex.CreateFont(-12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, _T("Courier New"));
  84. }
  85. CXTHexEdit::~CXTHexEdit()
  86. {
  87. if (m_fontHex.GetSafeHandle())
  88. m_fontHex.DeleteObject();
  89. if (m_pData)
  90. {
  91. free(m_pData);
  92. m_pData = NULL;
  93. }
  94. }
  95. IMPLEMENT_DYNAMIC(CXTHexEdit, CWnd)
  96. BEGIN_MESSAGE_MAP(CXTHexEdit, CXTHexEditBase)
  97. //{{AFX_MSG_MAP(CXTHexEdit)
  98. ON_WM_CHAR()
  99. ON_WM_KILLFOCUS()
  100. ON_WM_PAINT()
  101. ON_MESSAGE(WM_PRINTCLIENT, OnPrintClient)
  102. ON_WM_SETFOCUS()
  103. ON_WM_SIZE()
  104. ON_WM_VSCROLL()
  105. ON_WM_HSCROLL()
  106. ON_WM_GETDLGCODE()
  107. ON_WM_ERASEBKGND()
  108. ON_WM_LBUTTONDOWN()
  109. ON_WM_LBUTTONDBLCLK()
  110. ON_WM_MOUSEMOVE()
  111. ON_WM_LBUTTONUP()
  112. ON_WM_KEYDOWN()
  113. ON_WM_CONTEXTMENU()
  114. ON_COMMAND(ID_EDIT_CLEAR, OnEditClear)
  115. ON_COMMAND(ID_EDIT_COPY, OnEditCopy)
  116. ON_COMMAND(ID_EDIT_CUT, OnEditCut)
  117. ON_COMMAND(ID_EDIT_PASTE, OnEditPaste)
  118. ON_COMMAND(ID_EDIT_SELECT_ALL, OnEditSelectAll)
  119. ON_COMMAND(ID_EDIT_UNDO, OnEditUndo)
  120. ON_WM_NCPAINT()
  121. ON_WM_MOUSEWHEEL()
  122. //}}AFX_MSG_MAP
  123. END_MESSAGE_MAP()
  124. void CXTHexEdit::RestoreDefaultFont()
  125. {
  126. if (m_fontHex.GetSafeHandle())
  127. m_fontHex.DeleteObject();
  128. // create the default font used by the hex edit control.
  129. m_fontHex.CreateFont(-12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, _T("Courier New"));
  130. }
  131. void CXTHexEdit::SetHexFont(CFont* pFont)
  132. {
  133. ASSERT(pFont->GetSafeHandle());
  134. if (pFont->GetSafeHandle())
  135. {
  136. LOGFONT lf;
  137. pFont->GetLogFont(&lf);
  138. SetHexFont(&lf);
  139. }
  140. }
  141. void CXTHexEdit::SetHexFont(LOGFONT* pLogFont)
  142. {
  143. ASSERT(pLogFont != NULL);
  144. if (m_fontHex.GetSafeHandle())
  145. m_fontHex.DeleteObject();
  146. m_fontHex.CreateFontIndirect(pLogFont);
  147. }
  148. COLORREF CXTHexEdit::GetActualBackColor()
  149. {
  150. if (IsReadOnly())
  151. {
  152. return m_crDisabledBack;
  153. }
  154. return m_crBack;
  155. }
  156. COLORREF CXTHexEdit::GetActualTextColor()
  157. {
  158. if (!IsWindowEnabled())
  159. {
  160. return m_crDisabledText;
  161. }
  162. return m_crText;
  163. }
  164. COLORREF CXTHexEdit::GetActualHighlightBackColor()
  165. {
  166. if (!IsWindowEnabled())
  167. {
  168. return m_crDisabledHighlightBack;
  169. }
  170. return m_crHighlightBack;
  171. }
  172. COLORREF CXTHexEdit::GetActualHighlightTextColor()
  173. {
  174. if (!IsWindowEnabled())
  175. {
  176. return m_crDisabledHighlightText;
  177. }
  178. return m_crHighlightText;
  179. }
  180. void CXTHexEdit::OnPaint()
  181. {
  182. CPaintDC dc(this);
  183. // Paint to a memory device context to help
  184. // eliminate screen flicker.
  185. CXTPBufferDC memDC(dc);
  186. OnDraw(&memDC);
  187. }
  188. LRESULT CXTHexEdit::OnPrintClient(WPARAM wParam, LPARAM /*lParam*/)
  189. {
  190. CDC* pDC = CDC::FromHandle((HDC)wParam);
  191. if (pDC)
  192. {
  193. OnDraw(pDC);
  194. }
  195. return 1;
  196. }
  197. void CXTHexEdit::OnDraw(CDC* pDC)
  198. {
  199. // Get the client rect.
  200. CXTPClientRect rectClient(this);
  201. pDC->FillSolidRect(rectClient, GetActualBackColor());
  202. // Save the current device context, we will restore this just
  203. // before we loose scope.
  204. int nSavedDC = pDC->SaveDC();
  205. ASSERT(m_nCurrentAddress >= 0);
  206. ASSERT(m_nTopIndex >= 0);
  207. pDC->SelectObject(&m_fontHex);
  208. int height = 0;
  209. int x = rectClient.TopLeft().x;
  210. int y = rectClient.TopLeft().y;
  211. TCHAR buf[256];
  212. pDC->SetBoundsRect(&rectClient, DCB_DISABLE);
  213. pDC->SetTextColor(GetActualTextColor());
  214. // Get char dimensions
  215. if (m_bUpdate)
  216. {
  217. const int h_delta = ::GetScrollPos(m_hWnd, SB_HORZ) * m_nNullWidth;
  218. pDC->GetCharWidth('0', '0', &m_nNullWidth);
  219. CSize sz = pDC->GetTextExtent(_T("0"), 1);
  220. m_nLineHeight = sz.cy;
  221. const int width_address = (m_bAddressIsWide ? 9 : 5) * m_nNullWidth;
  222. m_nOffHex = m_bShowAddress ? width_address : 0;
  223. m_nOffAscii = m_nOffHex;
  224. if (m_bShowHex) m_nOffAscii += m_nBytePerRow * 3 * m_nNullWidth;
  225. m_nOffAddress = -h_delta;
  226. m_nOffHex -= h_delta;
  227. m_nOffAscii -= h_delta;
  228. m_nLinesPerPage = rectClient.Height() / m_nLineHeight;
  229. m_bUpdate = FALSE;
  230. UpdateScrollbars();
  231. }
  232. if (m_pData)
  233. {
  234. height = rectClient.Height() / m_nLineHeight;
  235. height *= m_nLineHeight;
  236. if (m_bShowAddress)
  237. {
  238. y = 0;
  239. CRect rcd = rectClient;
  240. rcd.left = m_nOffAddress;
  241. // draw address
  242. int i;
  243. for (i = m_nTopIndex;
  244. (i < (m_nLength + 1)) && (rcd.TopLeft().y < height);
  245. i += m_nBytePerRow)
  246. {
  247. const int width = m_bAddressIsWide ? 8 : 4;
  248. #if (_MSC_VER > 1310) // VS2005
  249. _stprintf_s(buf, _countof(buf),  _T("%0*lX"), width, m_dwBaseAddress + i);
  250. #else
  251. _stprintf(buf, _T("%0*lX"), width, m_dwBaseAddress + i);
  252. #endif
  253. pDC->DrawText(buf, width, rcd,
  254. DT_LEFT | DT_TOP | DT_SINGLELINE | DT_NOPREFIX);
  255. rcd.TopLeft().y += m_nLineHeight;
  256. }
  257. }
  258. if (m_bShowHex)
  259. {
  260. y = 0;
  261. CRect rcd = rectClient;
  262. rcd.left = x = m_nOffHex;
  263. if (m_nSelStart != -1 && (m_eEditMode == editHigh || m_eEditMode == editLow))
  264. {
  265. int  i;
  266. int  n = 0;
  267. int  selStart, selEnd;
  268. GetSel(selStart, selEnd);
  269. for (i = m_nTopIndex; (i < selStart) && (y < height); i++)
  270. {
  271. LPTSTR p = &buf[0];
  272. TOHEX(m_pData[i], p);
  273. *p++ = ' ';
  274. pDC->TextOut(x, y, buf, 3);
  275. x += m_nNullWidth * 3;
  276. n++;
  277. if (n == m_nBytePerRow)
  278. {
  279. n = 0;
  280. x = m_nOffHex;
  281. y += m_nLineHeight;
  282. }
  283. }
  284. pDC->SetTextColor(GetActualHighlightTextColor());
  285. pDC->SetBkColor(GetActualHighlightBackColor());
  286. for (; (i < selEnd) && (i < m_nLength) && (y < height); i++)
  287. {
  288. LPTSTR p = &buf[0];
  289. TOHEX(m_pData[i], p);
  290. *p++ = ' ';
  291. pDC->TextOut(x, y, buf, 3);
  292. x += m_nNullWidth * 3;
  293. n++;
  294. if (n == m_nBytePerRow)
  295. {
  296. n = 0;
  297. x = m_nOffHex;
  298. y += m_nLineHeight;
  299. }
  300. }
  301. pDC->SetTextColor(GetActualTextColor());
  302. pDC->SetBkColor(GetActualBackColor());
  303. for (; (i < m_nLength) && (y < height); i++)
  304. {
  305. LPTSTR p = &buf[0];
  306. TOHEX(m_pData[i], p);
  307. *p++ = ' ';
  308. pDC->TextOut(x, y, buf, 3);
  309. x += m_nNullWidth * 3;
  310. n++;
  311. if (n == m_nBytePerRow)
  312. {
  313. n = 0;
  314. x = m_nOffHex;
  315. y += m_nLineHeight;
  316. }
  317. }
  318. }
  319. else
  320. {
  321. int i;
  322. for (i = m_nTopIndex; (i < m_nLength) && (rcd.TopLeft().y < height);)
  323. {
  324. LPTSTR p = &buf[0];
  325. int n;
  326. for (n = 0; (n < m_nBytePerRow) && (i < m_nLength); n++)
  327. {
  328. TOHEX(m_pData[i], p);
  329. *p++ = ' ';
  330. i++;
  331. }
  332. while (n < m_nBytePerRow)
  333. {
  334. *p++ = ' ';
  335. *p++ = ' ';
  336. *p++ = ' ';
  337. n++;
  338. }
  339. pDC->DrawText(buf, m_nBytePerRow * 3, rcd, DT_LEFT | DT_TOP | DT_SINGLELINE | DT_NOPREFIX);
  340. rcd.TopLeft().y += m_nLineHeight;
  341. }
  342. }
  343. }
  344. if (m_bShowAscii)
  345. {
  346. y = 0;
  347. CRect rcd = rectClient;
  348. rcd.left = x = m_nOffAscii;
  349. if (m_nSelStart != -1 && m_eEditMode == editAscii)
  350. {
  351. int  i;
  352. int  n = 0;
  353. int  selStart, selEnd;
  354. GetSel(selStart, selEnd);
  355. for (i = m_nTopIndex; (i < selStart) && (y < height); i++)
  356. {
  357. buf[0] = isprint(m_pData[i]) ? m_pData[i] : '.';
  358. pDC->TextOut(x, y, buf, 1);
  359. x += m_nNullWidth;
  360. n++;
  361. if (n == m_nBytePerRow)
  362. {
  363. n = 0;
  364. x = m_nOffAscii;
  365. y += m_nLineHeight;
  366. }
  367. }
  368. pDC->SetTextColor(GetActualHighlightTextColor());
  369. pDC->SetBkColor(GetActualHighlightBackColor());
  370. for (; (i < selEnd) && (y < height); i++)
  371. {
  372. buf[0] = isprint(m_pData[i]) ? m_pData[i] : '.';
  373. pDC->TextOut(x, y, buf, 1);
  374. x += m_nNullWidth;
  375. n++;
  376. if (n == m_nBytePerRow)
  377. {
  378. n = 0;
  379. x = m_nOffAscii;
  380. y += m_nLineHeight;
  381. }
  382. }
  383. pDC->SetTextColor(GetActualTextColor());
  384. pDC->SetBkColor(GetActualBackColor());
  385. for (; (i < m_nLength) && y < height; i++)
  386. {
  387. buf[0] = isprint(m_pData[i]) ? m_pData[i] : '.';
  388. pDC->TextOut(x, y, buf, 1);
  389. x += m_nNullWidth;
  390. n++;
  391. if (n == m_nBytePerRow)
  392. {
  393. n = 0;
  394. x = m_nOffAscii;
  395. y += m_nLineHeight;
  396. }
  397. }
  398. }
  399. else
  400. {
  401. int i;
  402. for (i = m_nTopIndex; (i < m_nLength) && (rcd.top < height);)
  403. {
  404. LPTSTR p = &buf[0];
  405. int n;
  406. for (n = 0; (n < m_nBytePerRow) && (i < m_nLength); n++)
  407. {
  408. *p++ = isprint(m_pData[i]) ? m_pData[i] : '.';
  409. i++;
  410. }
  411. pDC->DrawText(buf, n, rcd, DT_LEFT | DT_TOP | DT_SINGLELINE | DT_NOPREFIX);
  412. rcd.top += m_nLineHeight;
  413. }
  414. }
  415. }
  416. }
  417. // Restore the device context.
  418. pDC->RestoreDC(nSavedDC);
  419. }
  420. void CXTHexEdit::OnSetFocus(CWnd* pOldWnd)
  421. {
  422. CXTHexEditBase::OnSetFocus(pOldWnd);
  423. if (m_pData && !IsSelected())
  424. {
  425. if (m_ptEditPos.x == 0 && m_bShowAddress)
  426. {
  427. CreateAddressCaret();
  428. }
  429. else
  430. {
  431. CreateEditCaret();
  432. }
  433. RepositionCaret(m_nCurrentAddress);
  434. }
  435. }
  436. void CXTHexEdit::OnKillFocus(CWnd* pNewWnd)
  437. {
  438. DestroyCaret();
  439. CXTHexEditBase::OnKillFocus(pNewWnd);
  440. }
  441. void CXTHexEdit::OnVScroll(UINT nSBCode, UINT /*nPos*/, CScrollBar* /*pScrollBar*/)
  442. {
  443. DoVScroll(nSBCode, false);
  444. }
  445. void CXTHexEdit::DoVScroll(UINT nSBCode, bool bMoveCaret)
  446. {
  447. if (!m_pData)
  448. {
  449. return;
  450. }
  451. BOOL bVisible = GetStyle() & WS_VISIBLE;
  452. // Turn off redraw while scrolling, this will cause paint problems
  453. // with our control because we are painting off screen to reduce
  454. // flicker.  The default implementation assumes that WM_ERASEBKGND
  455. // has repainted the background, which in our case does not happen.
  456. if (bVisible) SetRedraw(FALSE);
  457. const int oa = m_nTopIndex;
  458. SCROLLINFO  si;
  459. ZeroMemory(&si, sizeof(SCROLLINFO));
  460. si.cbSize = sizeof(SCROLLINFO);
  461. si.fMask = SIF_PAGE | SIF_RANGE | SIF_POS;
  462. if (GetStyle() & WS_VSCROLL)
  463. {
  464. VERIFY(::GetScrollInfo(m_hWnd, SB_VERT, &si));
  465. }
  466. else
  467. {
  468. si.nPage = si.nPos = si.nMin = si.nMax = 0;
  469. }
  470. switch (nSBCode)
  471. {
  472. case SB_LINEDOWN:
  473. if (si.nPos < (si.nMax - (int)si.nPage + 1))
  474. {
  475. m_nTopIndex += m_nBytePerRow;
  476. }
  477. break;
  478. case SB_LINEUP:
  479. if (m_nTopIndex > 0)
  480. {
  481. m_nTopIndex -= m_nBytePerRow;
  482. if (m_nTopIndex < 0) m_nTopIndex = 0;
  483. }
  484. break;
  485. case SB_PAGEDOWN:
  486. si.nPos += si.nPage;
  487. if (si.nPos >= si.nMax) si.nPos = si.nMax;
  488. m_nTopIndex = si.nPos * m_nBytePerRow;
  489. break;
  490. case SB_PAGEUP:
  491. if (oa == 0)
  492. {
  493. m_nCurrentAddress = 0;
  494. }
  495. else
  496. {
  497. m_nTopIndex -= m_nBytePerRow * m_nLinesPerPage;
  498. if (m_nTopIndex < 0)
  499. m_nTopIndex = 0;
  500. }
  501. break;
  502. case SB_THUMBTRACK:
  503. si.fMask = SIF_TRACKPOS;
  504. // Call GetScrollInfo to get current tracking
  505. // position in si.nTrackPos
  506. if (!::GetScrollInfo(m_hWnd, SB_VERT, &si))
  507. {
  508. return ; // GetScrollInfo failed
  509. }
  510. m_nTopIndex = si.nTrackPos * m_nBytePerRow;
  511. break;
  512. }
  513. if (bMoveCaret)
  514. {
  515. m_nCurrentAddress += (m_nTopIndex - oa);
  516. }
  517. // bug fix by John M. Drescher jdrescher@geocities.com
  518. if (m_nCurrentAddress < 0)
  519. {
  520. m_nCurrentAddress = 0;
  521. }
  522. UpdateScrollbars();
  523. RepositionCaret(m_nCurrentAddress);
  524. if (bVisible) SetRedraw(TRUE);
  525. // repaint the list box
  526. Invalidate();
  527. UpdateWindow();
  528. // repaint the scroll bar.
  529. ::SetWindowPos(m_hWnd, NULL, 0, 0, 0, 0,
  530. SWP_NOMOVE | SWP_NOSIZE | SWP_FRAMECHANGED);
  531. }
  532. BOOL CXTHexEdit::PreCreateWindow(CREATESTRUCT& cs)
  533. {
  534. if (!CXTHexEditBase::PreCreateWindow(cs))
  535. return FALSE;
  536. return TRUE;
  537. }
  538. BOOL CXTHexEdit::Create(DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID)
  539. {
  540. return Create(_T("EDIT"), 0, dwStyle, rect, pParentWnd, nID);
  541. }
  542. BOOL CXTHexEdit::Create(LPCTSTR lpszClassName, LPCTSTR lpszWindowName, DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID, CCreateContext* pContext)
  543. {
  544. if (!CWnd::Create(lpszClassName, lpszWindowName, dwStyle, rect, pParentWnd, nID, pContext))
  545. {
  546. TRACE0("Failed to create hex edit control.n");
  547. return FALSE;
  548. }
  549. CWnd::SetFont(&m_fontHex);
  550. return TRUE;
  551. }
  552. BOOL CXTHexEdit::OnEraseBkgnd(CDC* /*pDC*/)
  553. {
  554. return TRUE;
  555. }
  556. void CXTHexEdit::OnLButtonDown(UINT nFlags, CPoint point)
  557. {
  558. SetFocus();
  559. if (!m_pData)
  560. {
  561. return;
  562. }
  563. if (nFlags & MK_SHIFT)
  564. {
  565. m_nSelStart = m_nCurrentAddress;
  566. }
  567. CPoint pt = CalcPos(point.x, point.y);
  568. if (pt.x > -1)
  569. {
  570. m_ptEditPos = pt;
  571. pt.x *= m_nNullWidth;
  572. pt.y *= m_nLineHeight;
  573. if (pt.x == 0 && m_bShowAddress)
  574. {
  575. CreateAddressCaret();
  576. }
  577. else
  578. {
  579. CreateEditCaret();
  580. }
  581. SetCaretPos(pt);
  582. if (nFlags & MK_SHIFT)
  583. {
  584. m_nSelEnd = m_nCurrentAddress;
  585. if (m_eEditMode == editHigh || m_eEditMode == editLow)
  586. {
  587. m_nSelEnd++;
  588. }
  589. RedrawWindow();
  590. }
  591. }
  592. if (!(nFlags & MK_SHIFT))
  593. {
  594. if (::DragDetect(m_hWnd, point))
  595. {
  596. m_nSelStart = m_nCurrentAddress;
  597. m_nSelEnd = m_nSelStart;
  598. SetCapture();
  599. }
  600. else
  601. {
  602. BOOL bsel = m_nSelStart != -1;
  603. m_nSelStart = -1;
  604. m_nSelEnd = -1;
  605. if (bsel)
  606. {
  607. RedrawWindow();
  608. }
  609. }
  610. }
  611. if (!IsSelected())
  612. {
  613. if (m_bShowCaret)
  614. ShowCaret();
  615. }
  616. }
  617. // in: pixels
  618. // out: character coordinates + change of m_nCurrrentAddress
  619. CPoint CXTHexEdit::CalcPos(int x, int y)
  620. {
  621. if (y < 0 || x < 0)
  622. return CPoint(-1, -1);
  623. int lastVisRow = m_nLength / m_nBytePerRow - (m_nTopIndex / m_nBytePerRow);
  624. int row = y / m_nLineHeight;
  625. y = row + (m_nTopIndex / m_nBytePerRow);
  626. //  x += (m_nNullWidth - 1);
  627. x /= m_nNullWidth;
  628. //In address area
  629. const int right_of_address = (m_nOffAddress / m_nNullWidth) + // one past last
  630. (!m_bShowAddress ? -1 : (m_bAddressIsWide ? 8 : 4));
  631. if (x < right_of_address)
  632. {
  633. //Set first byte in line as current.
  634. m_nCurrentAddress = m_nTopIndex + (m_nBytePerRow * row);
  635. m_eEditMode = editNone;
  636. return CPoint(0, row);
  637. }
  638. //In hex area
  639. const int right_of_hex_area = right_of_address +
  640. (!m_bShowHex ? 0 : (m_nBytePerRow * 3)); //3 = 3 chars per byte (e.g. cc<space>)
  641. if (m_bShowHex && x < right_of_hex_area)
  642. {
  643. if ((x % 3) == 2)
  644. {
  645. ++x;
  646. }
  647. const int col = (x - right_of_address) / 3;
  648. m_nCurrentAddress = m_nTopIndex +
  649. (m_nBytePerRow * row) + col;
  650. if (m_nCurrentAddress > m_nLength)  // past end ?
  651. {
  652. x = m_nLength % m_nBytePerRow;
  653. row = lastVisRow;
  654. x *= 3;
  655. x += (right_of_address + 1);
  656. m_nCurrentAddress = m_nLength;
  657. }
  658. m_eEditMode = ((x % 3) == 0) ? editHigh : editLow;
  659. return CPoint(x, row);
  660. }
  661. const int right_of_ascii_area = right_of_hex_area + m_nBytePerRow + 1;
  662. if (m_bShowAscii && x < right_of_ascii_area)
  663. {
  664. if (x == right_of_hex_area) ++x; // advance from margin
  665. const int col = x - right_of_hex_area - 1;
  666. m_nCurrentAddress = m_nTopIndex + (m_nBytePerRow * row) + col;
  667. if (m_nCurrentAddress > m_nLength)  // past end ?
  668. {
  669. x = m_nLength % m_nBytePerRow;
  670. row = lastVisRow;
  671. x += (right_of_hex_area + 1);
  672. m_nCurrentAddress = m_nLength;
  673. }
  674. m_eEditMode = editAscii;
  675. return CPoint(x, row);
  676. }
  677. return CPoint(-1, -1);
  678. }
  679. void CXTHexEdit::CreateAddressCaret()
  680. {
  681. DestroyCaret();
  682. m_szCaret = CSize(m_nNullWidth * (m_bAddressIsWide ? 8 : 4),
  683. m_nLineHeight);
  684. CreateSolidCaret(m_szCaret.cx, m_szCaret.cy);
  685. }
  686. void CXTHexEdit::CreateEditCaret()
  687. {
  688. DestroyCaret();
  689. m_szCaret = CSize(m_nNullWidth, m_nLineHeight);
  690. CreateSolidCaret(m_szCaret.cx, m_szCaret.cy);
  691. }
  692. void CXTHexEdit::OnMouseMove(UINT nFlags, CPoint point)
  693. {
  694. if (!m_pData)
  695. {
  696. return;
  697. }
  698. if (nFlags & MK_LBUTTON && m_nSelStart != -1)
  699. {
  700. CRect rc;
  701. GetClientRect(&rc);
  702. if (!rc.PtInRect(point))
  703. {
  704. if (point.y < 0)
  705. {
  706. DoVScroll(SB_LINEUP, true);
  707. point.y = 0;
  708. }
  709. else if (point.y > rc.Height())
  710. {
  711. DoVScroll(SB_LINEDOWN, true);
  712. point.y = rc.Height() -1;
  713. }
  714. }
  715. //
  716. // we are selecting
  717. //
  718. int  seo = m_nSelEnd;
  719. CPoint pt = CalcPos(point.x, point.y);
  720. if (pt.x > -1)
  721. {
  722. m_nSelEnd = m_nCurrentAddress;
  723. if (m_eEditMode == editHigh || m_eEditMode == editLow)
  724. {
  725. m_nSelEnd++;
  726. }
  727. }
  728. if (IsSelected())
  729. {
  730. DestroyCaret();
  731. }
  732. if (seo != m_nSelEnd)
  733. {
  734. RedrawWindow();
  735. }
  736. }
  737. }
  738. void CXTHexEdit::UpdateScrollbars()
  739. {
  740. DWORD dwStyle = GetStyle();
  741. SCROLLINFO si;
  742. si.cbSize = sizeof(SCROLLINFO);
  743. si.fMask = SIF_PAGE | SIF_RANGE | SIF_POS;
  744. if (dwStyle & WS_VSCROLL)
  745. {
  746. bool bDisable = false;
  747. si.nMin = 0;
  748. si.nMax = m_nLength / m_nBytePerRow - 1; // - m_nLinesPerPage + 1;
  749. if (si.nMax < m_nLinesPerPage - 1)
  750. {
  751. si.nMax = 1;
  752. si.nPage = 1;
  753. bDisable = true;
  754. if (m_nTopIndex)
  755. {
  756. m_nTopIndex = 0;
  757. RepositionCaret(m_nCurrentAddress);
  758. }
  759. }
  760. else
  761. {
  762. si.nPage = m_nLinesPerPage - 1;
  763. while (m_nTopIndex / m_nBytePerRow > (si.nMax - m_nLinesPerPage + 2) &&
  764. m_nTopIndex > 0)
  765. {
  766. m_nTopIndex -= m_nBytePerRow;
  767. RepositionCaret(m_nCurrentAddress);
  768. }
  769. }
  770. if (m_nTopIndex < 0) m_nTopIndex = 0;
  771. si.nPos = m_nTopIndex / m_nBytePerRow;
  772. ModifyStyle(0, WS_VSCROLL);
  773. if (!bDisable)
  774. {
  775. SetScrollInfo(SB_VERT, &si, TRUE);
  776. EnableScrollBar(SB_VERT, ESB_ENABLE_BOTH);
  777. }
  778. else
  779. {
  780. si.nMax = si.nMin + 1;
  781. si.nPage = si.nPos = 0;
  782. SetScrollInfo(SB_VERT, &si, TRUE);
  783. EnableScrollBar(SB_VERT, ESB_DISABLE_BOTH);
  784. }
  785. }
  786. if (dwStyle & (WS_HSCROLL | ES_AUTOHSCROLL))
  787. {
  788. CRect rc;
  789. GetClientRect(&rc);
  790. si.nMin = 0;
  791. si.nMax = ((m_bShowAddress ? (m_bAddressIsWide ? 9 : 5) : 0) +
  792. (m_bShowHex ? m_nBytePerRow * 3 : 0) +
  793. (m_bShowAscii ? m_nBytePerRow : 0));
  794. si.nPage = m_nNullWidth == 0 ? 1 : __min(rc.Width() / m_nNullWidth, si.nMax);
  795. si.nPos = 0;
  796. BOOL bVisible = si.nMax * m_nNullWidth >= (int)rc.Width();
  797. if (dwStyle & ES_AUTOHSCROLL)
  798. {
  799. ShowScrollBar(SB_HORZ, bVisible);
  800. }
  801. si.fMask &= ~SIF_POS;
  802. SetScrollInfo(SB_HORZ, &si, TRUE);
  803. if (bVisible && ((dwStyle & ES_AUTOHSCROLL) == 0))
  804. {
  805. EnableScrollBar(SB_HORZ, ESB_ENABLE_BOTH);
  806. }
  807. }
  808. }
  809. void CXTHexEdit::OnLButtonUp(UINT nFlags, CPoint point)
  810. {
  811. if (IsSelected())
  812. {
  813. ReleaseCapture();
  814. }
  815. CWnd::OnLButtonUp(nFlags, point);
  816. }
  817. BOOL CXTHexEdit::IsReadOnly() const
  818. {
  819. if (!IsWindowEnabled() || (GetStyle() & ES_READONLY) == ES_READONLY)
  820. {
  821. return TRUE;
  822. }
  823. return FALSE;
  824. }
  825. void CXTHexEdit::OnChar(UINT nChar, UINT /*nRepCnt*/, UINT /*nFlags*/)
  826. {
  827. if (!m_pData)
  828. {
  829. return;
  830. }
  831. if (m_nCurrentAddress < 0)   //Shouldn't happen
  832. {
  833. return;
  834. }
  835. if (nChar == 't')
  836. {
  837. return;
  838. }
  839. if (::GetKeyState(VK_CONTROL) < 0)
  840. {
  841. switch (nChar)
  842. {
  843. case 0x03:
  844. if (IsSelected())
  845. {
  846. OnEditCopy();
  847. }
  848. return;
  849. case 0x16:
  850. OnEditPaste();
  851. return;
  852. case 0x18:
  853. if (IsSelected())
  854. {
  855. OnEditCut();
  856. }
  857. return;
  858. case 0x1a:
  859. OnEditUndo();
  860. return;
  861. }
  862. }
  863. if (IsReadOnly())
  864. {
  865. return;
  866. }
  867. if (nChar == 0x08) // backspace
  868. {
  869. if (GetAllowDeletes())
  870. {
  871. if (IsSelected())
  872. {
  873. OnEditClear();
  874. }
  875. else if (m_nCurrentAddress > 0)
  876. {
  877. m_nCurrentAddress--;
  878. SelDelete(m_nCurrentAddress, m_nCurrentAddress + 1);
  879. RepositionCaret(m_nCurrentAddress);
  880. RedrawWindow();
  881. }
  882. else
  883. {
  884. MessageBeep(0);
  885. }
  886. }
  887. return;
  888. }
  889. // can't go past end of buffer
  890. if ((UINT)m_nCurrentAddress >= m_nMaxLength)
  891. {
  892. MessageBeep(0);
  893. return;
  894. }
  895. if (m_eEditMode != editNone)
  896. {
  897. // see if need to grow the buffer
  898. if (m_nCurrentAddress >= m_nLength)
  899. {
  900. int iNewLength = (m_nLength + 1);
  901. LPBYTE p = (LPBYTE) calloc(iNewLength, 1);
  902. MEMCPY_S(p, m_pData, m_nLength);
  903. free(m_pData);
  904. m_pData = p;
  905. SetSel(-1, -1);
  906. m_nLength = iNewLength;
  907. m_bUpdate = TRUE;
  908. }
  909. }
  910. SetSel(-1, -1);
  911. switch (m_eEditMode)
  912. {
  913. case editNone:
  914. return;
  915. case editHigh:
  916. case editLow:
  917. if (isxdigit(nChar))
  918. {
  919. UINT b = 0;
  920. if (nChar >= 'a')
  921. b = 10 + nChar - 'a';
  922. else if (nChar >= 'A')
  923. b = 10 + nChar - 'A';
  924. else if (nChar >= '0')
  925. b = nChar - '0';
  926. else
  927. break;
  928. if (b >= 16)
  929. break;
  930. if (m_eEditMode == editHigh)
  931. {
  932. m_pData[m_nCurrentAddress] = (unsigned char)((m_pData[m_nCurrentAddress] & 0x0f) | (b << 4));
  933. }
  934. else
  935. {
  936. m_pData[m_nCurrentAddress] = (unsigned char)((m_pData[m_nCurrentAddress] & 0xf0) | b);
  937. }
  938. Move(1, 0);
  939. }
  940. break;
  941. case editAscii:
  942. m_pData[m_nCurrentAddress] = (unsigned char)nChar;
  943. Move(1, 0);
  944. break;
  945. }
  946. RedrawWindow();
  947. }
  948. void CXTHexEdit::OnKeyDown(UINT nChar, UINT /*nRepCnt*/, UINT /*nFlags*/)
  949. {
  950. BOOL bShift = (::GetKeyState(VK_SHIFT) < 0);
  951. switch (nChar)
  952. {
  953. case VK_DOWN:
  954. if (bShift)
  955. {
  956. if (!IsSelected())
  957. {
  958. m_nSelStart = m_nCurrentAddress;
  959. }
  960. Move(0, 1);
  961. m_nSelEnd = m_nCurrentAddress;
  962. if (m_eEditMode == editHigh || m_eEditMode == editLow)
  963. {
  964. m_nSelEnd++;
  965. }
  966. RedrawWindow();
  967. break;
  968. }
  969. else
  970. {
  971. SetSel(-1, -1);
  972. }
  973. Move(0, 1);
  974. break;
  975. case VK_UP:
  976. if (bShift)
  977. {
  978. if (!IsSelected())
  979. {
  980. m_nSelStart = m_nCurrentAddress;
  981. }
  982. Move(0, -1);
  983. m_nSelEnd = m_nCurrentAddress;
  984. RedrawWindow();
  985. break;
  986. }
  987. else
  988. {
  989. SetSel(-1, -1);
  990. }
  991. Move(0, -1);
  992. break;
  993. case VK_LEFT:
  994. if (bShift)
  995. {
  996. if (!IsSelected())
  997. {
  998. m_nSelStart = m_nCurrentAddress;
  999. }
  1000. Move(-1, 0);
  1001. m_nSelEnd = m_nCurrentAddress;
  1002. RedrawWindow();
  1003. break;
  1004. }
  1005. else
  1006. {
  1007. SetSel(-1, -1);
  1008. }
  1009. Move(-1, 0);
  1010. break;
  1011. case VK_RIGHT:
  1012. if (bShift)
  1013. {
  1014. if (!IsSelected())
  1015. {
  1016. m_nSelStart = m_nCurrentAddress;
  1017. }
  1018. Move(1, 0);
  1019. m_nSelEnd = m_nCurrentAddress;
  1020. if (m_eEditMode == editHigh || m_eEditMode == editLow)
  1021. {
  1022. m_nSelEnd++;
  1023. }
  1024. RedrawWindow();
  1025. break;
  1026. }
  1027. else
  1028. {
  1029. SetSel(-1, -1);
  1030. }
  1031. Move(1, 0);
  1032. break;
  1033. case VK_PRIOR:
  1034. if (bShift)
  1035. {
  1036. if (!IsSelected())
  1037. {
  1038. m_nSelStart = m_nCurrentAddress;
  1039. }
  1040. DoVScroll(SB_PAGEUP, true);
  1041. Move(0, 0);
  1042. m_nSelEnd = m_nCurrentAddress;
  1043. RedrawWindow();
  1044. break;
  1045. }
  1046. else
  1047. {
  1048. SetSel(-1, -1);
  1049. }
  1050. DoVScroll(SB_PAGEUP, true);
  1051. Move(0, 0);
  1052. break;
  1053. case VK_NEXT:
  1054. if (bShift)
  1055. {
  1056. if (!IsSelected())
  1057. {
  1058. m_nSelStart = m_nCurrentAddress;
  1059. }
  1060. DoVScroll(SB_PAGEDOWN, true);
  1061. Move(0, 0);
  1062. m_nSelEnd = m_nCurrentAddress;
  1063. RedrawWindow();
  1064. break;
  1065. }
  1066. else
  1067. {
  1068. SetSel(-1, -1);
  1069. }
  1070. DoVScroll(SB_PAGEDOWN, true);
  1071. Move(0, 0);
  1072. break;
  1073. case VK_HOME:
  1074. if (m_eEditMode == editLow)
  1075. {
  1076. m_eEditMode = editHigh;
  1077. }
  1078. if (bShift)
  1079. {
  1080. if (!IsSelected())
  1081. {
  1082. m_nSelStart = m_nCurrentAddress;
  1083. }
  1084. if (::GetKeyState(VK_CONTROL) < 0)
  1085. {
  1086. DoVScroll(SB_THUMBTRACK, true);
  1087. Move(0, 0);
  1088. }
  1089. else
  1090. {
  1091. m_nCurrentAddress /= m_nBytePerRow;
  1092. m_nCurrentAddress *= m_nBytePerRow;
  1093. Move(0, 0);
  1094. }
  1095. m_nSelEnd = m_nCurrentAddress;
  1096. RedrawWindow();
  1097. break;
  1098. }
  1099. else
  1100. {
  1101. SetSel(-1, -1);
  1102. }
  1103. if (::GetKeyState(VK_CONTROL) < 0)
  1104. {
  1105. m_nTopIndex = m_nCurrentAddress = 0;
  1106. UpdateScrollbars();
  1107. RepositionCaret(m_nCurrentAddress);
  1108. RedrawWindow();
  1109. }
  1110. else
  1111. {
  1112. m_nCurrentAddress /= m_nBytePerRow;
  1113. m_nCurrentAddress *= m_nBytePerRow;
  1114. Move(0, 0);
  1115. }
  1116. break;
  1117. case VK_END:
  1118. if (m_eEditMode == editLow)
  1119. {
  1120. m_eEditMode = editHigh;
  1121. }
  1122. if (bShift)
  1123. {
  1124. if (!IsSelected())
  1125. {
  1126. m_nSelStart = m_nCurrentAddress;
  1127. }
  1128. if (::GetKeyState(VK_CONTROL) < 0)
  1129. {
  1130. m_nCurrentAddress = m_nLength-1;
  1131. DoVScroll(SB_PAGEDOWN, false);
  1132. Move(0, 0);
  1133. }
  1134. else
  1135. {
  1136. m_nCurrentAddress /= m_nBytePerRow;
  1137. m_nCurrentAddress *= m_nBytePerRow;
  1138. m_nCurrentAddress += m_nBytePerRow - 1;
  1139. if (m_nCurrentAddress > m_nLength)
  1140. {
  1141. m_nCurrentAddress = m_nLength;
  1142. }
  1143. Move(0, 0);
  1144. }
  1145. m_nSelEnd = m_nCurrentAddress;
  1146. RedrawWindow();
  1147. break;
  1148. }
  1149. else
  1150. {
  1151. SetSel(-1, -1);
  1152. }
  1153. if (::GetKeyState(VK_CONTROL) < 0)
  1154. {
  1155. m_nCurrentAddress = m_nLength;
  1156. DoVScroll(SB_PAGEDOWN, false);
  1157. Move(0, 0);
  1158. }
  1159. else
  1160. {
  1161. m_nCurrentAddress /= m_nBytePerRow;
  1162. m_nCurrentAddress *= m_nBytePerRow;
  1163. m_nCurrentAddress += m_nBytePerRow - 1;
  1164. if (m_nCurrentAddress > m_nLength)
  1165. m_nCurrentAddress = m_nLength;
  1166. Move(0, 0);
  1167. }
  1168. break;
  1169. case VK_INSERT:
  1170. SelInsert(m_nCurrentAddress, __max(1, m_nSelEnd-m_nSelStart));
  1171. RepositionCaret(m_nCurrentAddress);
  1172. RedrawWindow();
  1173. break;
  1174. case VK_DELETE:
  1175. if (GetAllowDeletes())
  1176. {
  1177. if (IsSelected())
  1178. {
  1179. OnEditClear();
  1180. }
  1181. else
  1182. {
  1183. if (m_nCurrentAddress < m_nLength)
  1184. {
  1185. SelDelete(m_nCurrentAddress, m_nCurrentAddress + 1);
  1186. RedrawWindow();
  1187. }
  1188. else
  1189. {
  1190. MessageBeep(0);
  1191. }
  1192. }
  1193. }
  1194. break;
  1195. case VK_TAB:
  1196. {
  1197. int next_win_sel = 0;
  1198. switch (m_eEditMode)
  1199. {
  1200. case editNone:
  1201. m_eEditMode = editHigh;
  1202. break;
  1203. case editHigh:
  1204. case editLow:
  1205. if (bShift)
  1206. {
  1207. next_win_sel = GW_HWNDPREV;
  1208. }
  1209. else
  1210. {
  1211. m_eEditMode = editAscii;
  1212. }
  1213. break;
  1214. case editAscii:
  1215. if (bShift)
  1216. {
  1217. m_eEditMode = editHigh;
  1218. }
  1219. else
  1220. {
  1221. next_win_sel = GW_HWNDNEXT;
  1222. }
  1223. break;
  1224. }
  1225. if (next_win_sel)
  1226. {
  1227. CWnd *pWnd = this;
  1228. for (;;)
  1229. {
  1230. pWnd = pWnd->GetNextWindow(next_win_sel);
  1231. if (pWnd == this)
  1232. {
  1233. break;
  1234. }
  1235. if (pWnd == NULL)
  1236. {
  1237. if (next_win_sel == GW_HWNDNEXT)
  1238. {
  1239. pWnd = GetNextWindow(GW_HWNDFIRST);
  1240. }
  1241. else
  1242. {
  1243. pWnd = GetNextWindow(GW_HWNDLAST);
  1244. }
  1245. }
  1246. if (pWnd->GetStyle() & WS_TABSTOP)
  1247. {
  1248. pWnd->SetFocus();
  1249. break;
  1250. }
  1251. if (pWnd == this)
  1252. {
  1253. m_eEditMode = editHigh;
  1254. Move(0, 0);
  1255. break;
  1256. }
  1257. }
  1258. }
  1259. else
  1260. {
  1261. Move(0, 0);
  1262. }
  1263. break;
  1264. }
  1265. }
  1266. }
  1267. void CXTHexEdit::Move(int x, int y)
  1268. {
  1269. switch (m_eEditMode)
  1270. {
  1271. case editNone:
  1272. return;
  1273. case editHigh:
  1274. if (x != 0)
  1275. m_eEditMode = editLow;
  1276. if (x == -1)
  1277. m_nCurrentAddress--;
  1278. m_nCurrentAddress += y* m_nBytePerRow;
  1279. break;
  1280. case editLow:
  1281. if (x != 0)
  1282. m_eEditMode = editHigh;
  1283. if (x == 1)
  1284. m_nCurrentAddress++;
  1285. m_nCurrentAddress += y* m_nBytePerRow;
  1286. break;
  1287. case editAscii:
  1288. {
  1289. m_nCurrentAddress += x;
  1290. m_nCurrentAddress += y*m_nBytePerRow;
  1291. }
  1292. break;
  1293. }
  1294. if (m_nCurrentAddress < 0)
  1295. {
  1296. m_nCurrentAddress = 0;
  1297. }
  1298. if (m_nCurrentAddress >= m_nLength)
  1299. {
  1300. m_nCurrentAddress = m_nLength;
  1301. }
  1302. if ((x | y) != 0 && m_nCurrentAddress < m_nTopIndex)
  1303. {
  1304. DoVScroll(SB_LINEUP, false);
  1305. }
  1306. if ((x | y) != 0 &&
  1307. m_nCurrentAddress >= m_nTopIndex + m_nLinesPerPage*m_nBytePerRow)
  1308. {
  1309. DoVScroll(SB_LINEDOWN, false);
  1310. }
  1311. //ScrollIntoView(m_nCurrentAddress);
  1312. RepositionCaret(m_nCurrentAddress);
  1313. }
  1314. void CXTHexEdit::SetSel(int nSelStart, int nSelEnd)
  1315. {
  1316. #ifdef _DEBUG
  1317. _CrtCheckMemory();
  1318. #endif
  1319. if (GetFocus() == this)
  1320. DestroyCaret();
  1321. m_nSelStart = nSelStart;
  1322. m_nSelEnd = nSelEnd;
  1323. if (!IsWindow(m_hWnd))
  1324. return;
  1325. RedrawWindow();
  1326. if (GetFocus() == this)
  1327. {
  1328. if (m_ptEditPos.x == 0 && m_bShowAddress)
  1329. {
  1330. CreateAddressCaret();
  1331. }
  1332. else
  1333. {
  1334. CreateEditCaret();
  1335. }
  1336. RepositionCaret(m_nCurrentAddress);
  1337. if (m_bShowCaret)
  1338. ShowCaret();
  1339. }
  1340. }
  1341. void CXTHexEdit::RepositionCaret(int p)
  1342. {
  1343. if (GetFocus() != this)
  1344. return;
  1345. int x, y;
  1346. y = (p - m_nTopIndex) / m_nBytePerRow;
  1347. x = (p - m_nTopIndex) % m_nBytePerRow;
  1348. switch (m_eEditMode)
  1349. {
  1350. case editNone:
  1351. CreateAddressCaret();
  1352. x = m_nOffAddress;
  1353. break;
  1354. case editHigh:
  1355. CreateEditCaret();
  1356. x *= m_nNullWidth * 3;
  1357. x += m_nOffHex;
  1358. break;
  1359. case editLow:
  1360. CreateEditCaret();
  1361. x *= m_nNullWidth * 3;
  1362. x += m_nNullWidth;
  1363. x += m_nOffHex;
  1364. break;
  1365. case editAscii:
  1366. CreateEditCaret();
  1367. x *= m_nNullWidth;
  1368. x += m_nOffAscii;
  1369. break;
  1370. }
  1371. m_ptEditPos.x = x;
  1372. m_ptEditPos.y = y*m_nLineHeight;
  1373. CRect rc;
  1374. GetClientRect(&rc);
  1375. CRect rcCarret(m_ptEditPos, m_szCaret);
  1376. CRect rcInt;
  1377. rcInt.IntersectRect(rcCarret, rc);
  1378. if (rcInt == rcCarret)
  1379. {
  1380. SetCaretPos(m_ptEditPos);
  1381. if (m_bShowCaret)
  1382. ShowCaret();
  1383. }
  1384. }
  1385. void CXTHexEdit::ScrollIntoView(int p)
  1386. {
  1387. if (p < m_nTopIndex || p > m_nTopIndex + m_nLinesPerPage*m_nBytePerRow)
  1388. {
  1389. m_nTopIndex = (p/m_nBytePerRow) * m_nBytePerRow;
  1390. m_nTopIndex -= (m_nLinesPerPage / 3) * m_nBytePerRow;
  1391. if (m_nTopIndex < 0)
  1392. {
  1393. m_nTopIndex = 0;
  1394. }
  1395. UpdateScrollbars();
  1396. RedrawWindow();
  1397. }
  1398. }
  1399. void CXTHexEdit::OnContextMenu(CWnd*, CPoint point)
  1400. {
  1401. if (point.x == -1 && point.y == -1)
  1402. {
  1403. //keystroke invocation
  1404. CRect rect;
  1405. GetClientRect(rect);
  1406. ClientToScreen(rect);
  1407. point = rect.TopLeft();
  1408. point.Offset(5, 5);
  1409. }
  1410. CMenu menu;
  1411. XTPResourceManager()->LoadMenu(&menu, XT_IDM_POPUP);
  1412. CMenu* pPopup = menu.GetSubMenu(1);
  1413. ASSERT(pPopup != NULL);
  1414. if (!pPopup)
  1415. return;
  1416. const int DISABLE_FLAGS = MF_GRAYED | MF_DISABLED | MF_BYCOMMAND;
  1417. pPopup->EnableMenuItem(ID_EDIT_UNDO, DISABLE_FLAGS);
  1418. if (!GetAllowDeletes())
  1419. {
  1420. pPopup->EnableMenuItem(ID_EDIT_CLEAR, DISABLE_FLAGS);
  1421. pPopup->EnableMenuItem(ID_EDIT_CUT, DISABLE_FLAGS);
  1422. }
  1423. if (!IsSelected())
  1424. {
  1425. pPopup->EnableMenuItem(ID_EDIT_CLEAR, DISABLE_FLAGS);
  1426. pPopup->EnableMenuItem(ID_EDIT_CUT, DISABLE_FLAGS);
  1427. pPopup->EnableMenuItem(ID_EDIT_COPY, DISABLE_FLAGS);
  1428. }
  1429. if (OpenClipboard())
  1430. {
  1431. if (!IsClipboardFormatAvailable(CF_TEXT) &&
  1432. !IsClipboardFormatAvailable(CF_BINARY))
  1433. {
  1434. pPopup->EnableMenuItem(ID_EDIT_PASTE, DISABLE_FLAGS);
  1435. }
  1436. ::CloseClipboard();
  1437. }
  1438. XTFuncContextMenu(pPopup, TPM_LEFTALIGN | TPM_RIGHTBUTTON, point.x, point.y, this, XT_IDR_TBAR_HEXEDIT);
  1439. }
  1440. void CXTHexEdit::OnEditClear()
  1441. {
  1442. if (IsReadOnly())
  1443. {
  1444. return;
  1445. }
  1446. if (!GetAllowDeletes())
  1447. return;
  1448. NormalizeSel();
  1449. m_nCurrentAddress = m_nSelStart;
  1450. SelDelete(m_nSelStart, m_nSelEnd);
  1451. RepositionCaret(m_nCurrentAddress);
  1452. RedrawWindow();
  1453. }
  1454. void CXTHexEdit::OnEditCopy()
  1455. {
  1456. if (!OpenClipboard()) return;
  1457. NormalizeSel();
  1458. ::EmptyClipboard();
  1459. const int dwLen = m_nSelEnd - m_nSelStart;
  1460. HGLOBAL hMemb = ::GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE | GMEM_ZEROINIT, dwLen);
  1461. if (!hMemb)
  1462. {
  1463. CloseClipboard();
  1464. return;
  1465. }
  1466. // copy binary
  1467. ASSERT(hMemb != NULL);
  1468. LPBYTE  p = (BYTE*)::GlobalLock(hMemb);
  1469. if (!p)
  1470. return;
  1471. MEMCPY_S(p, m_pData + m_nSelStart, dwLen);
  1472. ::GlobalUnlock(hMemb);
  1473. HGLOBAL hMema = NULL;
  1474. if (m_eEditMode != editAscii)
  1475. {
  1476. hMema = ::GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE | GMEM_ZEROINIT, dwLen * 3 + 1);
  1477. if (!hMema)
  1478. {
  1479. CloseClipboard();
  1480. return;
  1481. }
  1482. // copy ascii
  1483. p = (BYTE*)::GlobalLock(hMema);
  1484. if (!p)
  1485. return;
  1486. int i;
  1487. for (i = 0; i < dwLen;)
  1488. {
  1489. TOHEX(m_pData[m_nSelStart + i], p);
  1490. *p++ = ' ';
  1491. i++;
  1492. }
  1493. ::GlobalUnlock(hMema);
  1494. }
  1495. else
  1496. {
  1497. hMema = ::GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE | GMEM_ZEROINIT, dwLen + 1);
  1498. if (!hMema)
  1499. {
  1500. CloseClipboard();
  1501. return;
  1502. }
  1503. // copy ascii
  1504. p = (BYTE*)::GlobalLock(hMema);
  1505. if (!p)
  1506. return;
  1507. MEMCPY_S(p, m_pData + m_nSelStart, dwLen);
  1508. p[dwLen] = 0;
  1509. for (int i = 0; i < dwLen; p++, i++)
  1510. {
  1511. if (!isprint(*p))
  1512. {
  1513. *p = '.';
  1514. }
  1515. }
  1516. ::GlobalUnlock(hMema);
  1517. }
  1518. ::SetClipboardData(CF_TEXT, hMema);
  1519. ::SetClipboardData(CF_BINARY, hMemb);
  1520. VERIFY(CloseClipboard());
  1521. }
  1522. void CXTHexEdit::OnEditCut()
  1523. {
  1524. if (IsReadOnly())
  1525. return;
  1526. OnEditCopy();
  1527. SelDelete(m_nSelStart, m_nSelEnd);
  1528. RedrawWindow();
  1529. }
  1530. void CXTHexEdit::OnEditPaste()
  1531. {
  1532. if (IsReadOnly())
  1533. return;
  1534. if (!OpenClipboard()) return;
  1535. HGLOBAL hmem = NULL;
  1536. LPBYTE p = NULL;
  1537. DWORD dwLen = 0;
  1538. if (::IsClipboardFormatAvailable(CF_BINARY))
  1539. {
  1540. hmem = ::GetClipboardData(CF_BINARY);
  1541. p = hmem ? (BYTE*)::GlobalLock(hmem) : NULL;
  1542. dwLen = hmem ? (DWORD)::GlobalSize(hmem) : 0;
  1543. }
  1544. else if (::IsClipboardFormatAvailable(CF_TEXT))
  1545. {
  1546. hmem = ::GetClipboardData(CF_TEXT);
  1547. p = hmem ? (BYTE*)::GlobalLock(hmem) : NULL;
  1548. dwLen = p ? (DWORD)strlen((char*)p) : 0;
  1549. }
  1550. if (p && dwLen > 0)
  1551. {
  1552. int     insert;
  1553. if (m_nCurrentAddress > m_nLength)
  1554. m_nCurrentAddress = m_nLength;
  1555. int     oa = m_nCurrentAddress;
  1556. NormalizeSel();
  1557. if (m_nSelStart == -1)
  1558. {
  1559. if (m_eEditMode == editLow)
  1560. {
  1561. m_nCurrentAddress++;
  1562. }
  1563. if (m_nCurrentAddress > m_nLength)
  1564. {
  1565. m_nCurrentAddress = m_nLength;
  1566. }
  1567. insert = m_nCurrentAddress;
  1568. SelInsert(m_nCurrentAddress, dwLen);
  1569. }
  1570. else
  1571. {
  1572. insert = m_nSelStart;
  1573. SelDelete(m_nSelStart, m_nSelEnd);
  1574. SelInsert(insert, dwLen);
  1575. SetSel(-1, -1);
  1576. }
  1577. if (insert + dwLen > m_nMaxLength)
  1578. {
  1579. dwLen = m_nMaxLength - insert;
  1580. }
  1581. MEMCPY_S(m_pData + insert, p, dwLen);
  1582. #ifdef _DEBUG
  1583. _CrtCheckMemory();
  1584. #endif
  1585. m_nCurrentAddress = oa;
  1586. RedrawWindow();
  1587. }
  1588. if (hmem)
  1589. {
  1590. ::GlobalUnlock(hmem);
  1591. }
  1592. ::CloseClipboard();
  1593. }
  1594. void CXTHexEdit::OnEditSelectAll()
  1595. {
  1596. m_nSelStart = 0;
  1597. m_nSelEnd = m_nLength;
  1598. DestroyCaret();
  1599. RedrawWindow();
  1600. }
  1601. void CXTHexEdit::OnEditUndo()
  1602. {
  1603. }
  1604. void CXTHexEdit::NormalizeSel()
  1605. {
  1606. if (m_nSelStart > m_nSelEnd)
  1607. {
  1608. int nSelStart = m_nSelStart;
  1609. m_nSelStart = m_nSelEnd;
  1610. m_nSelEnd = nSelStart;
  1611. }
  1612. if (m_nSelStart > m_nLength)
  1613. {
  1614. m_nSelStart = m_nLength;
  1615. }
  1616. if (m_nSelEnd > m_nLength)
  1617. {
  1618. m_nSelEnd = m_nLength;
  1619. }
  1620. }
  1621. void CXTHexEdit::GetSel(int& nSelStart, int& nSelEnd)
  1622. {
  1623. nSelStart = m_nSelStart;
  1624. nSelEnd = m_nSelEnd;
  1625. if (nSelStart > nSelEnd)
  1626. {
  1627. nSelStart = m_nSelEnd;
  1628. nSelEnd = m_nSelStart;
  1629. }
  1630. if (nSelStart > m_nLength)
  1631. nSelStart = m_nLength;
  1632. if (nSelEnd > m_nLength)
  1633. nSelEnd = m_nLength;
  1634. }
  1635. void CXTHexEdit::SelDelete(int nSelStart, int nSelEnd)
  1636. {
  1637. if (!GetAllowDeletes())
  1638. return;
  1639. #ifdef _DEBUG
  1640. _CrtCheckMemory();
  1641. #endif
  1642. if (nSelStart >= m_nLength)
  1643. return;
  1644. NormalizeSel();
  1645. const int nSelSize = (nSelEnd-nSelStart);
  1646. const int newLength = m_nLength - nSelSize;
  1647. if (newLength < 0)
  1648. return;
  1649. MEMMOVE_S(m_pData + nSelStart, m_pData + nSelEnd,
  1650. m_nLength - nSelEnd);
  1651. SetSel(-1, -1);
  1652. m_nLength = newLength;
  1653. if (m_nCurrentAddress > m_nLength)
  1654. {
  1655. m_nCurrentAddress = m_nLength;
  1656. RepositionCaret(m_nCurrentAddress);
  1657. }
  1658. m_bUpdate = TRUE;
  1659. }
  1660. void CXTHexEdit::SelInsert(int nSelStart, int nLength)
  1661. {
  1662. if ((UINT)(m_nLength + nLength) > m_nMaxLength)
  1663. {
  1664. nLength = (int)m_nMaxLength - m_nLength;
  1665. }
  1666. if (nLength <= 0)
  1667. {
  1668. MessageBeep(0);
  1669. return;
  1670. }
  1671. if (nSelStart > m_nLength)
  1672. {
  1673. nSelStart = m_nLength;
  1674. }
  1675. LPBYTE p = (LPBYTE) calloc(m_nLength + nLength, 1);
  1676. MEMCPY_S(p, m_pData, nSelStart);
  1677. if (m_nLength > nSelStart)
  1678. {
  1679. MEMCPY_S(p + nSelStart + nLength, m_pData + nSelStart, (m_nLength - nSelStart));
  1680. }
  1681. free(m_pData);
  1682. m_pData = p;
  1683. SetSel(-1, -1);
  1684. m_nLength = m_nLength + nLength;
  1685. m_bUpdate = TRUE;
  1686. }
  1687. void CXTHexEdit::SetData(LPBYTE p, int nLength, int nMaxLength)
  1688. {
  1689. if (m_pData)
  1690. free(m_pData);
  1691. m_pData = (LPBYTE) malloc(nLength);
  1692. MEMCPY_S(m_pData, p, nLength);
  1693. SetSel(-1, -1);
  1694. m_nMaxLength = nMaxLength < 0 ? -1 : __max(nMaxLength, nLength);
  1695. m_nLength = nLength;
  1696. m_nCurrentAddress = 0;
  1697. m_ptEditPos.x = m_ptEditPos.y = 0;
  1698. m_eEditMode = editHigh;
  1699. m_nTopIndex = 0;
  1700. m_bUpdate = TRUE;
  1701. if (m_hWnd)
  1702. {
  1703. UpdateScrollbars();
  1704. RepositionCaret(m_nCurrentAddress);
  1705. RedrawWindow();
  1706. // this will force the scroll bars to update if this is before the
  1707. // initial update
  1708. if (GetStyle() & WS_VSCROLL)
  1709. {
  1710. PostMessage(WM_VSCROLL, (WPARAM)-1, 0);
  1711. }
  1712. }
  1713. }
  1714. void CXTHexEdit::OnHScroll(UINT nSBCode, UINT /*nPos*/, CScrollBar* /*pScrollBar*/)
  1715. {
  1716. SCROLLINFO si;
  1717. ZeroMemory(&si, sizeof(SCROLLINFO));
  1718. si.cbSize = sizeof(SCROLLINFO);
  1719. si.fMask = SIF_PAGE | SIF_RANGE | SIF_POS | SIF_TRACKPOS;
  1720. VERIFY(::GetScrollInfo(m_hWnd, SB_HORZ, &si));
  1721. int newpos = si.nPos;
  1722. switch (nSBCode)
  1723. {
  1724. case SB_LINELEFT:
  1725. --newpos;
  1726. break;
  1727. case SB_LINERIGHT:
  1728. ++newpos;
  1729. break;
  1730. case SB_PAGELEFT:
  1731. newpos -= si.nPage;
  1732. break;
  1733. case SB_PAGERIGHT:
  1734. newpos += si.nPage;
  1735. break;
  1736. case SB_THUMBTRACK:
  1737. newpos = si.nTrackPos;
  1738. break;
  1739. }
  1740. if (newpos < 0)
  1741. {
  1742. newpos = 0;
  1743. }
  1744. else if (newpos > si.nMax)
  1745. {
  1746. newpos = si.nMax;
  1747. }
  1748. if (newpos != si.nPos)
  1749. {
  1750. m_bUpdate = true;
  1751. ::SetScrollPos(m_hWnd, SB_HORZ, newpos, TRUE);
  1752. RedrawWindow();
  1753. RepositionCaret(m_nCurrentAddress);
  1754. }
  1755. }
  1756. void CXTHexEdit::OnLButtonDblClk(UINT /*nFlags*/, CPoint /*point*/)
  1757. {
  1758. }
  1759. DWORD CXTHexEdit::SetAddressBase(DWORD dwBase)
  1760. {
  1761. DWORD dwOldAddress = m_dwBaseAddress;
  1762. m_dwBaseAddress = dwBase;
  1763. m_bUpdate = TRUE;
  1764. return dwOldAddress;
  1765. }
  1766. void CXTHexEdit::OnSize(UINT nType, int cx, int cy)
  1767. {
  1768. BOOL bVisible = GetStyle() & WS_VISIBLE;
  1769. if (bVisible) SetRedraw(FALSE);
  1770. CXTHexEditBase::OnSize(nType, cx, cy);
  1771. if (m_bDynamicBPR)
  1772. {
  1773. RecalcBPR();
  1774. }
  1775. m_bUpdate = TRUE;
  1776. UpdateScrollbars();
  1777. if (bVisible)
  1778. {
  1779. SetRedraw(TRUE);
  1780. Invalidate();
  1781. UpdateWindow();
  1782. }
  1783. }
  1784. void CXTHexEdit::RecalcBPR()
  1785. {
  1786. CDC* dc = GetDC();
  1787. HGDIOBJ hOldFont = dc->SelectObject(&m_fontHex);
  1788. dc->GetCharWidth('0', '0', &m_nNullWidth);
  1789. CRect rc;
  1790. GetClientRect(rc);
  1791. int cx = rc.Width();
  1792. if (m_bShowAddress)
  1793. cx -= m_nOffHex;
  1794. if (m_bShowAscii && m_bShowHex)
  1795. {
  1796. m_nBytePerRow = ((cx * 2) / 3) / (3 * m_nNullWidth);    // 2/3rd is hex, 1/3rd is ascii
  1797. }
  1798. else if (m_bShowHex)
  1799. {
  1800. m_nBytePerRow = cx / (3 * m_nNullWidth);
  1801. }
  1802. else if (m_bShowAscii)
  1803. {
  1804. m_nBytePerRow = cx / m_nNullWidth;
  1805. }
  1806. m_bUpdate = TRUE;
  1807. if (m_nBytePerRow <= 0)
  1808. m_nBytePerRow = 1;
  1809. dc->SelectObject(hOldFont);
  1810. ReleaseDC(dc);
  1811. }
  1812. void CXTHexEdit::OnNcPaint()
  1813. {
  1814. // Use the OnNcPaint() handler to prevent the caret
  1815. // from being shown when the control is first displayed
  1816. CXTHexEditBase::OnNcPaint(); // Be sure and call the parent class
  1817. //HideCaret();  // Hide the caret
  1818. }
  1819. BOOL CXTHexEdit::OnMouseWheel(UINT /*nFlags*/, short zDelta, CPoint /*pt*/)
  1820. {
  1821. OnVScroll(zDelta < 0 ? SB_LINEDOWN : SB_LINEUP, 0, NULL);
  1822. return TRUE;
  1823. }
  1824. void CXTHexEdit::EnableScrollBars(bool /*bVertical*/, bool /*bHorizontal*/)
  1825. {
  1826. XT_ERROR_MSG(
  1827. "CXTHexEdit::EnableScrollBars has been deprecated.n"
  1828. "n"
  1829. "You should now set scroll bars for the control through WS_HSCROLL/WS_VSCROLL and/or the resource editor."
  1830. );
  1831. }
  1832. int CXTHexEdit::GetData(LPBYTE pData, int nLength)
  1833. {
  1834. MEMCPY_S(pData, m_pData, __min(nLength, m_nLength));
  1835. return m_nLength;
  1836. }