mirror of
https://git.code.sf.net/p/fuse-emulator/fuse
synced 2026-01-27 01:41:34 +03:00
To avoid clashes with any similarly named system files (thanks, BogDan Vatra and Sergio Baldoví).
382 lines
10 KiB
C
382 lines
10 KiB
C
/* memorybrowser.c: the Win32 memory browser
|
|
Copyright (c) 2008 Marek Januszewski
|
|
|
|
This program is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation; either version 2 of the License, or
|
|
(at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License along
|
|
with this program; if not, write to the Free Software Foundation, Inc.,
|
|
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
|
|
Author contact information:
|
|
|
|
E-mail: philip-fuse@shadowmagic.org.uk
|
|
|
|
*/
|
|
|
|
#include <config.h>
|
|
|
|
#include <libspectrum.h>
|
|
#include <tchar.h>
|
|
#include <windows.h>
|
|
|
|
#include "compat.h"
|
|
#include "fuse.h"
|
|
#include "memory_pages.h"
|
|
#include "win32internals.h"
|
|
|
|
#include "memorybrowser.h"
|
|
|
|
static INT_PTR CALLBACK
|
|
memorybrowser_proc( HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam );
|
|
|
|
static LRESULT CALLBACK
|
|
memory_listview_proc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam );
|
|
|
|
static void
|
|
memorybrowser_init( HWND hwndDlg );
|
|
|
|
void
|
|
menu_machine_memorybrowser( int action );
|
|
|
|
/* helper constants for memory listview's scrollbar */
|
|
static const int memorysb_min = 0x0000;
|
|
static const int memorysb_max = 0x10000;
|
|
static const int memorysb_step = 0x10;
|
|
|
|
/* Visual styles could change visible rows */
|
|
static int memorysb_page_inc = 0xa0;
|
|
static int memorysb_page_size = 0x140;
|
|
static int memorysb_page_rows = 20;
|
|
|
|
/* Address of first visible row */
|
|
static libspectrum_word memaddr = 0x0000;
|
|
|
|
static void
|
|
update_display( HWND hwndDlg, libspectrum_word base )
|
|
{
|
|
int i, j;
|
|
|
|
TCHAR buffer[ 8 + 64 + 20 ];
|
|
TCHAR *text[] = { &buffer[0], &buffer[ 8 ], &buffer[ 8 + 64 ] };
|
|
TCHAR buffer2[ 8 ];
|
|
|
|
memaddr = base;
|
|
|
|
SendDlgItemMessage( hwndDlg, IDC_MEM_LV, LVM_DELETEALLITEMS, 0, 0 );
|
|
|
|
LV_ITEM lvi;
|
|
lvi.mask = LVIF_TEXT;
|
|
|
|
for( i = 0; i < memorysb_page_rows; i++ ) {
|
|
_sntprintf( text[0], 8, TEXT( "%04X" ), base );
|
|
|
|
text[1][0] = '\0';
|
|
for( j = 0; j < memorysb_step; j++, base++ ) {
|
|
|
|
libspectrum_byte b = readbyte_internal( base );
|
|
|
|
_sntprintf( buffer2, 4, TEXT( "%02X " ), b );
|
|
_tcsncat( text[1], buffer2, 4 );
|
|
|
|
text[2][j] = ( b >= 32 && b < 127 ) ? b : '.';
|
|
}
|
|
text[2][ 0x10 ] = '\0';
|
|
|
|
/* append the item */
|
|
lvi.iItem = SendDlgItemMessage( hwndDlg, IDC_MEM_LV,
|
|
LVM_GETITEMCOUNT, 0, 0 );
|
|
lvi.iSubItem = 0;
|
|
lvi.pszText = text[0];
|
|
SendDlgItemMessage( hwndDlg, IDC_MEM_LV, LVM_INSERTITEM, 0,
|
|
( LPARAM ) &lvi );
|
|
lvi.iSubItem = 1;
|
|
lvi.pszText = text[1];
|
|
SendDlgItemMessage( hwndDlg, IDC_MEM_LV, LVM_SETITEM, 0,
|
|
( LPARAM ) &lvi );
|
|
lvi.iSubItem = 2;
|
|
lvi.pszText = text[2];
|
|
SendDlgItemMessage( hwndDlg, IDC_MEM_LV, LVM_SETITEM, 0,
|
|
( LPARAM ) &lvi );
|
|
}
|
|
}
|
|
|
|
static int
|
|
scroller( HWND hwndDlg, WPARAM scroll_command )
|
|
{
|
|
libspectrum_word base;
|
|
SCROLLINFO si;
|
|
|
|
memset( &si, 0, sizeof( si ) );
|
|
si.cbSize = sizeof(si);
|
|
si.fMask = SIF_POS;
|
|
GetScrollInfo( GetDlgItem( hwndDlg, IDC_MEM_SB ), SB_CTL, &si );
|
|
|
|
int value = si.nPos;
|
|
int selected = 0;
|
|
|
|
/* in Windows we have to read the command and scroll the scrollbar manually */
|
|
switch( LOWORD( scroll_command ) ) {
|
|
case SB_BOTTOM:
|
|
value = memorysb_max;
|
|
selected = memorysb_page_rows - 1;
|
|
break;
|
|
case SB_TOP:
|
|
value = memorysb_min;
|
|
break;
|
|
case SB_LINEDOWN:
|
|
value += memorysb_step;
|
|
selected = 1;
|
|
break;
|
|
case SB_LINEUP:
|
|
value -= memorysb_step;
|
|
break;
|
|
case SB_PAGEUP:
|
|
value -= memorysb_page_inc;
|
|
break;
|
|
case SB_PAGEDOWN:
|
|
value += memorysb_page_inc;
|
|
selected = memorysb_page_rows - 1;
|
|
break;
|
|
case SB_THUMBPOSITION:
|
|
case SB_THUMBTRACK:
|
|
value = HIWORD( scroll_command );
|
|
break;
|
|
default:
|
|
return 1;
|
|
}
|
|
|
|
if( value > memorysb_max - memorysb_page_size )
|
|
value = memorysb_max - memorysb_page_size;
|
|
if( value < memorysb_min ) value = memorysb_min;
|
|
|
|
/* Drop the low bits before displaying anything */
|
|
base = value; base &= 0xfff0;
|
|
|
|
if( base != memaddr ) {
|
|
/* set the new scrollbar position */
|
|
memset( &si, 0, sizeof(si) );
|
|
si.cbSize = sizeof(si);
|
|
si.fMask = SIF_POS;
|
|
si.nPos = base;
|
|
SetScrollInfo( GetDlgItem( hwndDlg, IDC_MEM_SB ), SB_CTL, &si, TRUE );
|
|
|
|
update_display( hwndDlg, base );
|
|
}
|
|
|
|
/* Select row according to last scroll command */
|
|
ListView_SetItemState( GetDlgItem( hwndDlg, IDC_MEM_LV ), selected,
|
|
LVIS_SELECTED, LVIS_SELECTED );
|
|
|
|
return 0;
|
|
}
|
|
|
|
void
|
|
menu_machine_memorybrowser( int action GCC_UNUSED )
|
|
{
|
|
fuse_emulation_pause();
|
|
|
|
DialogBox( fuse_hInstance, MAKEINTRESOURCE( IDD_MEM ),
|
|
fuse_hWnd, (DLGPROC) memorybrowser_proc );
|
|
|
|
fuse_emulation_unpause();
|
|
return;
|
|
}
|
|
|
|
static INT_PTR CALLBACK
|
|
memorybrowser_proc( HWND hwndDlg, UINT uMsg, WPARAM wParam,
|
|
LPARAM lParam GCC_UNUSED )
|
|
{
|
|
switch( uMsg )
|
|
{
|
|
case WM_INITDIALOG:
|
|
memorybrowser_init( hwndDlg );
|
|
return TRUE;
|
|
|
|
case WM_COMMAND:
|
|
if( LOWORD( wParam ) == IDCLOSE ||
|
|
LOWORD( wParam ) == IDCANCEL ) {
|
|
EndDialog( hwndDlg, 0 );
|
|
return TRUE;
|
|
}
|
|
break;
|
|
|
|
case WM_CLOSE: {
|
|
EndDialog( hwndDlg, 0 );
|
|
return TRUE;
|
|
}
|
|
|
|
case WM_VSCROLL:
|
|
/* Accept vertical scroll from listview too */
|
|
scroller( hwndDlg, wParam );
|
|
return TRUE;
|
|
|
|
case WM_MOUSEWHEEL:
|
|
{
|
|
/* get current position */
|
|
SCROLLINFO si;
|
|
memset( &si, 0, sizeof(si) );
|
|
si.cbSize = sizeof(si);
|
|
si.fMask = SIF_POS;
|
|
GetScrollInfo( GetDlgItem( hwndDlg, IDC_MEM_SB ), SB_CTL, &si );
|
|
|
|
/* convert delta displacement to memory displacement */
|
|
short delta = (short) HIWORD( wParam ) / WHEEL_DELTA;
|
|
int value = si.nPos - delta * memorysb_step;
|
|
if( value > memorysb_max - memorysb_page_size )
|
|
value = memorysb_max - memorysb_page_size;
|
|
if( value < memorysb_min ) value = memorysb_min;
|
|
|
|
/* scroll to new position */
|
|
scroller( hwndDlg, MAKEWPARAM( SB_THUMBPOSITION, value ) );
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
static LRESULT CALLBACK
|
|
memory_listview_proc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam )
|
|
{
|
|
switch( msg ) {
|
|
|
|
case WM_DESTROY:
|
|
{
|
|
WNDPROC orig_proc = (WNDPROC) GetProp( hWnd, "original_proc" );
|
|
SetWindowLongPtr( hWnd, GWLP_WNDPROC, (LONG_PTR) orig_proc );
|
|
RemoveProp( hWnd, "original_proc" );
|
|
break;
|
|
}
|
|
|
|
case WM_KEYDOWN:
|
|
{
|
|
WORD scroll_notify = 0xffff;
|
|
|
|
switch( wParam )
|
|
{
|
|
case VK_UP:
|
|
scroll_notify = SB_LINEUP;
|
|
break;
|
|
|
|
case VK_PRIOR:
|
|
scroll_notify = SB_PAGEUP;
|
|
break;
|
|
|
|
case VK_NEXT:
|
|
scroll_notify = SB_PAGEDOWN;
|
|
break;
|
|
|
|
case VK_DOWN:
|
|
scroll_notify = SB_LINEDOWN;
|
|
break;
|
|
|
|
case VK_HOME:
|
|
scroll_notify = SB_TOP;
|
|
break;
|
|
|
|
case VK_END:
|
|
scroll_notify = SB_BOTTOM;
|
|
break;
|
|
}
|
|
|
|
/* Inform parent window about key scrolling */
|
|
if( scroll_notify != 0xffff ) {
|
|
SendMessage( GetParent( hWnd ), WM_VSCROLL,
|
|
MAKEWPARAM( scroll_notify, 0 ), (LPARAM) NULL );
|
|
return 0;
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case WM_MOUSEWHEEL:
|
|
{
|
|
/* Inform parent window about mouse scrolling */
|
|
SendMessage( GetParent( hWnd ), WM_MOUSEWHEEL, wParam, lParam );
|
|
return 0;
|
|
}
|
|
|
|
}
|
|
|
|
WNDPROC orig_proc = (WNDPROC) GetProp( hWnd, "original_proc" );
|
|
return CallWindowProc( orig_proc, hWnd, msg, wParam, lParam );
|
|
}
|
|
|
|
static void
|
|
memorybrowser_init( HWND hwndDlg )
|
|
{
|
|
size_t i;
|
|
int error;
|
|
HFONT font;
|
|
|
|
const TCHAR *titles[] = { "Address", "Hex", "Data" };
|
|
int column_widths[] = { 62, 348, 124 };
|
|
|
|
error = win32ui_get_monospaced_font( &font ); if( error ) return;
|
|
|
|
/* subclass listview to catch keydown and mousewheel messages */
|
|
HWND hwnd_list = GetDlgItem( hwndDlg, IDC_MEM_LV );
|
|
WNDPROC orig_proc = (WNDPROC) GetWindowLongPtr( hwnd_list, GWLP_WNDPROC );
|
|
SetProp( hwnd_list, "original_proc", (HANDLE) orig_proc );
|
|
SetWindowLongPtr( hwnd_list, GWLP_WNDPROC,
|
|
(LONG_PTR) (WNDPROC) memory_listview_proc );
|
|
|
|
/* set extended listview style to select full row, when an item is selected */
|
|
DWORD lv_ext_style;
|
|
lv_ext_style = SendDlgItemMessage( hwndDlg, IDC_MEM_LV,
|
|
LVM_GETEXTENDEDLISTVIEWSTYLE, 0, 0 );
|
|
lv_ext_style |= LVS_EX_FULLROWSELECT;
|
|
lv_ext_style |= LVS_EX_DOUBLEBUFFER;
|
|
SendDlgItemMessage( hwndDlg, IDC_MEM_LV,
|
|
LVM_SETEXTENDEDLISTVIEWSTYLE, 0, lv_ext_style );
|
|
|
|
/* create columns */
|
|
LVCOLUMN lvc;
|
|
lvc.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT ;
|
|
lvc.fmt = LVCFMT_LEFT;
|
|
|
|
for( i = 0; i < 3; i++ ) {
|
|
if( i != 0 )
|
|
lvc.mask |= LVCF_SUBITEM;
|
|
lvc.cx = column_widths[i];
|
|
lvc.pszText = (TCHAR *)titles[i];
|
|
SendDlgItemMessage( hwndDlg, IDC_MEM_LV, LVM_INSERTCOLUMN, i,
|
|
( LPARAM ) &lvc );
|
|
}
|
|
|
|
/* set font of the listview to monospaced one */
|
|
SendDlgItemMessage( hwndDlg, IDC_MEM_LV , WM_SETFONT,
|
|
(WPARAM) font, FALSE );
|
|
|
|
/* Recalculate visible rows, Visual Styles could change rows height */
|
|
memorysb_page_rows = SendDlgItemMessage( hwndDlg, IDC_MEM_LV,
|
|
LVM_GETCOUNTPERPAGE, 0, 0 );
|
|
memorysb_page_size = memorysb_page_rows * memorysb_step;
|
|
memorysb_page_inc = memorysb_page_size / 2;
|
|
|
|
/* set the scrollbar parameters */
|
|
SCROLLINFO si;
|
|
si.cbSize = sizeof(si);
|
|
si.fMask = SIF_POS | SIF_RANGE | SIF_PAGE;
|
|
si.nPos = memaddr;
|
|
si.nMin = memorysb_min;
|
|
si.nMax = memorysb_max;
|
|
si.nPage = memorysb_page_size;
|
|
SetScrollInfo( GetDlgItem( hwndDlg, IDC_MEM_SB ), SB_CTL, &si, TRUE );
|
|
|
|
update_display( hwndDlg, memaddr );
|
|
|
|
/* Recalculate columns width, high DPI resolutions have larger sizes */
|
|
ListView_SetColumnWidth( hwnd_list, 0, LVSCW_AUTOSIZE_USEHEADER );
|
|
ListView_SetColumnWidth( hwnd_list, 1, LVSCW_AUTOSIZE );
|
|
ListView_SetColumnWidth( hwnd_list, 2, LVSCW_AUTOSIZE_USEHEADER );
|
|
}
|