home *** CD-ROM | disk | FTP | other *** search
/ Chip 2004 July / CMCD0704.ISO / Software / Freeware / Utilitare / VisualBoyAdvance-1.7.2 / src / win32 / MemoryViewer.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2004-05-13  |  13.3 KB  |  623 lines

  1. // VisualBoyAdvance - Nintendo Gameboy/GameboyAdvance (TM) emulator.
  2. // Copyright (C) 1999-2003 Forgotten
  3. // Copyright (C) 2004 Forgotten and the VBA development team
  4.  
  5. // This program is free software; you can redistribute it and/or modify
  6. // it under the terms of the GNU General Public License as published by
  7. // the Free Software Foundation; either version 2, or(at your option)
  8. // any later version.
  9. //
  10. // This program is distributed in the hope that it will be useful,
  11. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13. // GNU General Public License for more details.
  14. //
  15. // You should have received a copy of the GNU General Public License
  16. // along with this program; if not, write to the Free Software Foundation,
  17. // Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  18.  
  19. // MemoryViewer.cpp : implementation file
  20. //
  21.  
  22. #include "stdafx.h"
  23. #include "vba.h"
  24. #include "MemoryViewer.h"
  25.  
  26. #include "../System.h"
  27. extern int emulating;
  28.  
  29. #ifdef _DEBUG
  30. #define new DEBUG_NEW
  31. #undef THIS_FILE
  32. static char THIS_FILE[] = __FILE__;
  33. #endif
  34.  
  35. /////////////////////////////////////////////////////////////////////////////
  36. // MemoryViewer
  37.  
  38. bool MemoryViewer::isRegistered = false;
  39.  
  40. MemoryViewer::MemoryViewer()
  41. {
  42.   address = 0;
  43.   addressSize = 0;
  44.   dataSize = 0;
  45.   editAddress = 0;
  46.   editNibble = 0;
  47.   displayedLines = 0;
  48.   hasCaret = false;
  49.   maxNibble = 0;
  50.   font = (HFONT)GetStockObject(SYSTEM_FIXED_FONT);
  51.   fontSize.cx = fontSize.cy = 0;
  52.   beginAscii = 0;
  53.   beginHex = 0;
  54.   dlg = NULL;
  55.   registerClass();
  56. }
  57.  
  58. MemoryViewer::~MemoryViewer()
  59. {
  60. }
  61.  
  62.  
  63. BEGIN_MESSAGE_MAP(MemoryViewer, CWnd)
  64.   //{{AFX_MSG_MAP(MemoryViewer)
  65.   ON_WM_ERASEBKGND()
  66.   ON_WM_PAINT()
  67.   ON_WM_VSCROLL()
  68.   ON_WM_GETDLGCODE()
  69.   ON_WM_LBUTTONDOWN()
  70.   ON_WM_SETFOCUS()
  71.   ON_WM_KILLFOCUS()
  72.   ON_WM_KEYDOWN()
  73.   //}}AFX_MSG_MAP
  74.   ON_MESSAGE(WM_CHAR, OnWMChar)
  75.   END_MESSAGE_MAP()
  76.  
  77.  
  78.   /////////////////////////////////////////////////////////////////////////////
  79. // MemoryViewer message handlers
  80.  
  81. void MemoryViewer::setDialog(IMemoryViewerDlg *d)
  82. {
  83.   dlg = d;
  84. }
  85.  
  86.  
  87. void MemoryViewer::setAddress(u32 a)
  88. {
  89.   address = a;
  90.   if(displayedLines) {
  91.     if(addressSize) {
  92.       u16 addr = address;
  93.       if((u16)(addr+(displayedLines<<4)) < addr) {
  94.         address = 0xffff - (displayedLines<<4) + 1;
  95.       }      
  96.     } else {
  97.       if((address+(displayedLines<<4)) < address) {
  98.         address = 0xffffffff - (displayedLines<<4) + 1;
  99.       }
  100.     }
  101.   }
  102.   if(addressSize)
  103.     address &= 0xffff;
  104.   setCaretPos();
  105.   InvalidateRect(NULL, TRUE);
  106. }
  107.  
  108.  
  109. void MemoryViewer::setSize(int s)
  110. {
  111.   dataSize = s;
  112.   if(s == 0)
  113.     maxNibble = 1;
  114.   else if(s == 1)
  115.     maxNibble = 3;
  116.   else
  117.     maxNibble = 7;
  118.   
  119.   InvalidateRect(NULL, TRUE);
  120. }
  121.  
  122. BOOL MemoryViewer::OnEraseBkgnd(CDC* pDC) 
  123. {
  124.   return TRUE;
  125. }
  126.  
  127. void MemoryViewer::updateScrollInfo(int lines)
  128. {
  129.   int page = lines * 16;
  130.   SCROLLINFO si;
  131.   ZeroMemory(&si, sizeof(si));
  132.   si.cbSize = sizeof(si);
  133.   si.fMask = SIF_PAGE | SIF_RANGE | SIF_DISABLENOSCROLL | SIF_POS;
  134.   si.nMin = 0;
  135.   if(addressSize) {
  136.     si.nMax = 0x10000/page;
  137.     si.nPage = 1;
  138.   } else {
  139.     si.nMax = 0xa000000 / page;
  140.     si.nPage = page;
  141.   }
  142.  
  143.   si.nPos = address / page;
  144.   SetScrollInfo(SB_VERT,
  145.                 &si,
  146.                 TRUE);
  147. }
  148.  
  149. void MemoryViewer::OnPaint() 
  150. {
  151.   CPaintDC dc(this); // device context for painting
  152.   
  153.   RECT rect;
  154.   GetClientRect(&rect);
  155.   int w = rect.right - rect.left;
  156.   int h = rect.bottom - rect.top - 6;
  157.   
  158.   CDC memDC;
  159.   memDC.CreateCompatibleDC(&dc);
  160.   CBitmap bitmap, *pOldBitmap;
  161.   bitmap.CreateCompatibleBitmap(&dc, w, rect.bottom - rect.top);
  162.   pOldBitmap = memDC.SelectObject(&bitmap);
  163.   
  164.   memDC.FillRect(&rect, CBrush::FromHandle((HBRUSH)GetStockObject(WHITE_BRUSH)));
  165.   memDC.DrawEdge(&rect, EDGE_ETCHED, BF_RECT);
  166.   
  167.   CFont *oldFont = memDC.SelectObject(CFont::FromHandle(font));
  168.   
  169.   fontSize = memDC.GetTextExtent("0", 1);
  170.   
  171.   int lines = h / fontSize.cy;
  172.   
  173.   displayedLines = lines;
  174.   
  175.   updateScrollInfo(lines);
  176.   
  177.   u32 addr = address;
  178.   
  179.   memDC.SetTextColor(RGB(0,0,0));
  180.   
  181.   u8 data[32];
  182.   
  183.   RECT r;
  184.   r.top = 3;
  185.   r.left = 3;
  186.   r.bottom = r.top+fontSize.cy;
  187.   r.right = rect.right-3;
  188.   
  189.   int line = 0;
  190.   
  191.   for(int i = 0; i < lines; i++) {
  192.     CString buffer;
  193.     if(addressSize)
  194.       buffer.Format("%04X", addr);
  195.     else
  196.       buffer.Format("%08X", addr);
  197.     memDC.DrawText(buffer, &r, DT_TOP | DT_LEFT | DT_NOPREFIX);
  198.     r.left += 10*fontSize.cx;
  199.     beginHex = r.left;
  200.     readData(addr, 16, data);
  201.     
  202.     int j;
  203.     
  204.     if(dataSize == 0) {
  205.       for(j = 0; j < 16; j++) {
  206.         buffer.Format("%02X", data[j]);
  207.         memDC.DrawText(buffer, &r, DT_TOP | DT_LEFT | DT_NOPREFIX);
  208.         r.left += 3*fontSize.cx;
  209.       }
  210.     }
  211.     if(dataSize == 1) {
  212.       for(j = 0; j < 16; j += 2) {
  213.         buffer.Format("%04X", data[j] | data[j+1]<<8);
  214.         memDC.DrawText(buffer, &r, DT_TOP | DT_LEFT | DT_NOPREFIX);
  215.         r.left += 5*fontSize.cx;
  216.       }      
  217.     }
  218.     if(dataSize == 2) {
  219.       for(j = 0; j < 16; j += 4) {
  220.         buffer.Format("%08X", data[j] | data[j+1]<<8 |
  221.                       data[j+2] << 16 | data[j+3] << 24);
  222.         memDC.DrawText(buffer, &r, DT_TOP | DT_LEFT | DT_NOPREFIX);
  223.         r.left += 9*fontSize.cx;
  224.       }            
  225.     }
  226.     
  227.     line = r.left;
  228.     
  229.     r.left += fontSize.cx;
  230.     beginAscii = r.left;
  231.     buffer.Empty();
  232.     for(j = 0; j < 16; j++) {
  233.       char c = data[j];
  234.       if(c >= 32 && c <= 127) {
  235.         buffer += c;
  236.       } else
  237.         buffer += '.';
  238.     }
  239.     
  240.     memDC.DrawText(buffer, &r, DT_TOP | DT_LEFT | DT_NOPREFIX);
  241.     addr += 16;
  242.     if(addressSize)
  243.       addr &= 0xffff;
  244.     r.top += fontSize.cy;
  245.     r.bottom += fontSize.cy;
  246.     r.left = 3;
  247.   }
  248.   CPen pen;
  249.   pen.CreatePen(PS_SOLID, 1, RGB(0,0,0));
  250.   CPen *old = memDC.SelectObject(&pen);
  251.   
  252.   memDC.MoveTo(3+fontSize.cx*9, 3);
  253.   memDC.LineTo(3+fontSize.cx*9, 3+displayedLines*fontSize.cy);
  254.   
  255.   memDC.MoveTo(line, 3);
  256.   memDC.LineTo(line, 3+displayedLines*fontSize.cy);
  257.   
  258.   memDC.SelectObject(old);
  259.   pen.DeleteObject();
  260.   
  261.   memDC.SelectObject(oldFont);
  262.   
  263.   dc.BitBlt(0, 0, w, rect.bottom - rect.top, &memDC, 0, 0, SRCCOPY);
  264.   
  265.   memDC.SelectObject(pOldBitmap);
  266.   memDC.DeleteDC();
  267.   bitmap.DeleteObject();
  268. }
  269.  
  270. void MemoryViewer::OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar) 
  271. {
  272.   int address = this->address;
  273.   switch(nSBCode) {
  274.   case SB_BOTTOM:
  275.     address = 0xffffff00;
  276.     break;
  277.   case SB_LINEDOWN:
  278.     address += 0x10;
  279.     break;
  280.   case SB_LINEUP:
  281.     address -= 0x10;
  282.     break;
  283.   case SB_PAGEDOWN:
  284.     address += (displayedLines<<4);
  285.     break;
  286.   case SB_PAGEUP:
  287.     address -= (displayedLines<<4);
  288.     break;
  289.   case SB_TOP:
  290.     address = 0;
  291.     break;
  292.   case SB_THUMBTRACK:
  293.     {
  294.       int page = displayedLines * 16;      
  295.       SCROLLINFO si;
  296.       ZeroMemory(&si, sizeof(si));
  297.       si.cbSize = sizeof(si);
  298.       si.fMask = SIF_TRACKPOS;
  299.       GetScrollInfo(SB_VERT, &si);
  300.       address = page * si.nTrackPos;
  301.     }
  302.     break;
  303.   }
  304.   setAddress(address);
  305. }
  306.  
  307. UINT MemoryViewer::OnGetDlgCode() 
  308. {
  309.   return DLGC_WANTALLKEYS;
  310. }
  311.  
  312. void MemoryViewer::createEditCaret(int w, int h)
  313. {
  314.   if(!hasCaret || caretWidth != w || caretHeight != h) {
  315.     hasCaret = true;
  316.     caretWidth = w;
  317.     caretHeight = h;
  318.     ::CreateCaret(m_hWnd, (HBITMAP)0, w, h);
  319.   }
  320. }
  321.  
  322.  
  323. void MemoryViewer::destroyEditCaret()
  324. {
  325.   hasCaret = false;
  326.   DestroyCaret();
  327. }
  328.  
  329. void MemoryViewer::setCaretPos()
  330. {
  331.   if(GetFocus() != this) {
  332.     destroyEditCaret();
  333.     return;
  334.   }
  335.  
  336.   if(dlg)
  337.     dlg->setCurrentAddress(editAddress);
  338.   
  339.   if(editAddress < address || editAddress > (address -1 + (displayedLines<<4))) {
  340.     destroyEditCaret();
  341.     return;
  342.   }
  343.  
  344.   int subAddress = (editAddress - address);
  345.  
  346.   int x = 3+10*fontSize.cx+editNibble*fontSize.cx;
  347.   int y = 3+fontSize.cy*((editAddress-address)>>4);
  348.  
  349.   if(editAscii) {
  350.     x = beginAscii + fontSize.cx*(subAddress&15);
  351.   } else {
  352.     switch(dataSize) {
  353.     case 0:
  354.       x += 3*fontSize.cx*(subAddress & 15);
  355.       break;
  356.     case 1:
  357.       x += 5*fontSize.cx*((subAddress>>1) & 7);
  358.       break;
  359.     case 2:
  360.       x += 9*fontSize.cx*((subAddress>>2) & 3);
  361.       break;
  362.     }
  363.   }
  364.  
  365.   RECT r;
  366.   GetClientRect(&r);
  367.   r.right -= 3;
  368.   if(x >= r.right) {
  369.     destroyEditCaret();
  370.     return;
  371.   }
  372.   int w = fontSize.cx;
  373.   if((x+fontSize.cx)>=r.right)
  374.     w = r.right - x;
  375.   createEditCaret(w, fontSize.cy);
  376.   ::SetCaretPos(x, y);
  377.   ShowCaret();
  378. }
  379.  
  380. void MemoryViewer::OnLButtonDown(UINT nFlags, CPoint point) 
  381. {
  382.   int x = point.x;
  383.   int y = point.y;
  384.   int line = (y-3)/fontSize.cy;
  385.   int beforeAscii = beginHex;
  386.   int inc = 1;
  387.   int sub = 3*fontSize.cx;
  388.   switch(dataSize) {
  389.   case 0:
  390.     beforeAscii += 47*fontSize.cx;
  391.     break;
  392.   case 1:
  393.     beforeAscii += 39*fontSize.cx;
  394.     inc = 2;
  395.     sub = 5*fontSize.cx;
  396.     break;
  397.   case 2:
  398.     beforeAscii += 35*fontSize.cx;
  399.     inc = 4;
  400.     sub = 9*fontSize.cx;
  401.     break;
  402.   }
  403.   
  404.   editAddress = address + (line<<4);
  405.   if(x >= beginHex && x < beforeAscii) {
  406.     x -= beginHex;
  407.     editNibble = 0;
  408.     while(x > 0) {
  409.       x -= sub;
  410.       if(x >= 0)
  411.         editAddress += inc;
  412.       else {
  413.         editNibble = (x + sub)/fontSize.cx;
  414.       }
  415.     }
  416.     editAscii = false;
  417.   } else if(x >= beginAscii) {
  418.     int afterAscii = beginAscii+16*fontSize.cx;
  419.     if(x >= afterAscii) 
  420.       x = afterAscii-1;
  421.     editAddress += (x-beginAscii)/fontSize.cx;
  422.     editNibble = 0;
  423.     editAscii = true;
  424.   } else {
  425.     return;
  426.   }
  427.  
  428.   if(editNibble > maxNibble)
  429.     editNibble = maxNibble;
  430.   SetFocus();
  431.   setCaretPos();
  432. }
  433.  
  434. void MemoryViewer::OnSetFocus(CWnd* pOldWnd) 
  435. {
  436.   setCaretPos();
  437.   InvalidateRect(NULL, TRUE);
  438. }
  439.  
  440. void MemoryViewer::OnKillFocus(CWnd* pNewWnd) 
  441. {
  442.   destroyEditCaret();
  443.   InvalidateRect(NULL, TRUE);
  444. }
  445.  
  446. void MemoryViewer::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags) 
  447. {
  448.   bool isShift = (GetKeyState(VK_SHIFT) & 0x80000000) == 0x80000000;
  449.  
  450.   switch(nChar) {
  451.   case VK_RIGHT:
  452.     if(editAscii)
  453.       moveAddress(1,0);
  454.     else if(isShift)
  455.       moveAddress((maxNibble+1)>>1,0);
  456.     else
  457.       moveAddress(0, 1);
  458.     break;
  459.   case VK_LEFT:
  460.     if(editAscii)
  461.       moveAddress(-1, 0);
  462.     else if(isShift)
  463.       moveAddress(-((maxNibble+1)>>1),0);
  464.     else
  465.       moveAddress(0, -1);
  466.     break;  
  467.   case VK_DOWN:
  468.     moveAddress(16, 0);
  469.     break;
  470.   case VK_UP:
  471.     moveAddress(-16, 0);
  472.     break;
  473.   case VK_TAB:
  474.     GetNextDlgTabItem(GetParent(), isShift)->SetFocus();
  475.     break;
  476.   }
  477. }
  478.  
  479. void MemoryViewer::moveAddress(s32 offset, int nibbleOff)
  480. {
  481.   if(offset == 0) {
  482.     if(nibbleOff == -1) {
  483.       editNibble--;
  484.       if(editNibble == -1) {
  485.         editAddress -= (maxNibble + 1) >> 1;
  486.         editNibble = maxNibble;
  487.       }
  488.       if(address == 0 && (editAddress >= (u32)(displayedLines<<4))) {
  489.         editAddress = 0;
  490.         editNibble = 0;
  491.         beep();
  492.       }
  493.       if(editAddress < address)
  494.         setAddress(address - 16);
  495.     } else {
  496.       editNibble++;
  497.       if(editNibble > maxNibble) {
  498.         editNibble = 0;
  499.         editAddress += (maxNibble + 1) >> 1;
  500.       }
  501.       if(editAddress < address) {
  502.         editAddress -= (maxNibble + 1) >> 1;
  503.         editNibble = maxNibble;
  504.         beep();
  505.       }
  506.       if(editAddress >= (address+(displayedLines<<4)))
  507.         setAddress(address+16);
  508.     }
  509.   } else {
  510.     editAddress += offset;
  511.     if(offset < 0 && editAddress > (address-1+(displayedLines<<4))) {
  512.       editAddress -= offset;
  513.       beep();
  514.       return;
  515.     }
  516.     if(offset > 0 && (editAddress < address)) {
  517.       editAddress -= offset;
  518.       beep();
  519.       return;
  520.     }
  521.     if(editAddress < address) {
  522.       if(offset & 15)
  523.         setAddress((address+offset-16) & ~15);
  524.       else
  525.         setAddress(address+offset);
  526.     } else if(editAddress > (address - 1 + (displayedLines<<4))) {
  527.       if(offset & 15)
  528.         setAddress((address+offset+16) & ~15);
  529.       else
  530.         setAddress(address+offset);
  531.     }
  532.   }
  533.  
  534.   setCaretPos();
  535. }
  536.  
  537. LRESULT MemoryViewer::OnWMChar(WPARAM wParam, LPARAM LPARAM)
  538. {
  539.   if(OnEditInput(wParam))
  540.     return 0;
  541.   return 1;
  542. }
  543.  
  544. bool MemoryViewer::OnEditInput(UINT c)
  545. {
  546.   if(c > 255 || !emulating) {
  547.     beep();
  548.     return false;
  549.   }
  550.  
  551.   if(!editAscii)
  552.     c = tolower(c);
  553.  
  554.   u32 value = 256;
  555.  
  556.   if(c >= 'a' && c <= 'f')
  557.     value = 10 + (c - 'a');
  558.   else if(c >= '0' && c <= '9')
  559.     value = (c - '0');
  560.   if(editAscii) {
  561.     editData(editAddress, 8, 0, c);
  562.     moveAddress(1, 0);
  563.     InvalidateRect(NULL, TRUE);
  564.   } else {
  565.     if(value != 256) {
  566.       value <<= 4*(maxNibble-editNibble);
  567.       u32 mask = ~(15 << 4*(maxNibble - editNibble));
  568.       switch(dataSize) {
  569.       case 0:
  570.         editData(editAddress, 8, mask, value);
  571.         break;
  572.       case 1:
  573.         editData(editAddress, 16, mask, value);
  574.         break;
  575.       case 2:
  576.         editData(editAddress, 32, mask, value);
  577.         break;
  578.       }
  579.       moveAddress(0, 1);
  580.       InvalidateRect(NULL, TRUE);
  581.     }
  582.   }
  583.   return true;
  584. }
  585.  
  586. void MemoryViewer::beep()
  587. {
  588.   MessageBeep((UINT)-1);
  589. }
  590.  
  591. void MemoryViewer::registerClass()
  592. {
  593.   if(!isRegistered) {
  594.     WNDCLASS wc;
  595.     ZeroMemory(&wc, sizeof(wc));
  596.     wc.style = CS_PARENTDC | CS_HREDRAW | CS_VREDRAW | CS_GLOBALCLASS;
  597.     wc.lpfnWndProc = (WNDPROC)::DefWindowProc;
  598.     wc.hInstance = AfxGetInstanceHandle();
  599.     wc.hCursor = LoadCursor(NULL, IDC_ARROW);
  600.     wc.hbrBackground = (HBRUSH )GetStockObject(WHITE_BRUSH);
  601.     wc.lpszMenuName = NULL;
  602.     wc.lpszClassName = "VbaMemoryViewer";
  603.     AfxRegisterClass(&wc);
  604.     isRegistered = true;
  605.   }
  606. }
  607.  
  608. void MemoryViewer::setAddressSize(int s)
  609. {
  610.   addressSize = s;
  611. }
  612.  
  613.  
  614. u32 MemoryViewer::getCurrentAddress()
  615. {
  616.   return editAddress;
  617. }
  618.  
  619. int MemoryViewer::getSize()
  620. {
  621.   return dataSize;
  622. }
  623.