diff --git a/.gitignore b/.gitignore
index 04d5c0d0..1697f268 100644
--- a/.gitignore
+++ b/.gitignore
@@ -40,3 +40,6 @@ fceux-net-server
/output/cheats
/output/snaps
/output/sav
+
+# typical CMake build directory
+/build
diff --git a/INSTALL b/INSTALL
index 249461e2..d77519ce 100644
--- a/INSTALL
+++ b/INSTALL
@@ -1,9 +1,9 @@
-To compile and install FCEUX for SDL, follow the instructions in the README-SDL.md file.
+To compile and install FCEUX for SDL, follow the instructions in the README file.
Users of Microsoft Visual Studio can use the solution files within the vc directory. The Windows XP toolset is required to open and build this solution. If it
is not installed, go to "Tools" > "Get Tools and Features". Select "Individual Components" and then install "C++ Windows XP Support for VS 2017 (v141) tools".
These solution files will compile FCEUX and some included libraries for full functionality.
The SDL port build tool of choice has come full circle back to Cmake. The cmake build tool will compile the new Qt version of the SDL GUI.
-The scons build tool will build the older GTK based GUI which currently only builds on Linux.
+Building of the SDL fceux no longer supports use of the scons build tool.
diff --git a/Makefile.am b/Makefile.am
deleted file mode 100644
index d8505c14..00000000
--- a/Makefile.am
+++ /dev/null
@@ -1,2 +0,0 @@
-ACLOCAL_AMFLAGS = -I m4 --install
-SUBDIRS = src
diff --git a/README b/README
index 59cfcc13..15ee426e 100644
--- a/README
+++ b/README
@@ -1,4 +1,4 @@
-FCEUX SDL 2.2.3 SDL README
+FCEUX SDL 2.3.0 SDL README
==========================
Originally By Lukas Sabota (sf: punkrockguy318)
Updated By mjbudd77
@@ -7,7 +7,7 @@ Updated By mjbudd77
http://www.fceux.com
-Last Modified: July 12, 2020
+Last Modified: October 21, 2020
Table of Contents
-----------------
@@ -22,7 +22,7 @@ Table of Contents
1 - Requirements
----------------
-* sdl2 - Version >= 2.0
+* sdl2 - Version >= 2.0 (sdl2 >= 2.8 recommended)
* cmake - Required to build fceux.
* qt5 OR gtk3 - (qt version >= 5.11 recommended) (gtk3 >= 3.22 recommended)
* liblua5.1 (optional) - Will statically link internally if the system cannot provide this.
@@ -37,15 +37,19 @@ The old scons build system is no longer supported.
Fceux can be compiled and built using the cmake build system. To compile, run:
mkdir build; cd build;
- cmake -DCMAKE_BUILD_TYPE=Release .. # For a release build
+ cmake -DCMAKE_INSTALL_PREFIX=/usr -DCMAKE_BUILD_TYPE=Release .. # For a release build
To build a binary with debug information included in it:
- cmake -DCMAKE_BUILD_TYPE=Debug ..
+ cmake -DCMAKE_INSTALL_PREFIX=/usr -DCMAKE_BUILD_TYPE=Debug ..
The Qt version of the GUI builds by default and this is the preferred GUI for use.
For those who must have GTK/Gnome style,
the GTK version of the GUI can be selected to build with:
- cmake -DCMAKE_BUILD_TYPE=Release -DGTK=1 .. # Release build using GTK GUI
+ cmake -DCMAKE_INSTALL_PREFIX=/usr -DCMAKE_BUILD_TYPE=Release -DGTK=1 .. # Release build using GTK GUI
+
+The Qt version GUI by far exceeds the GTK gui in capability and performance.
+I HIGHLY RECOMMEND USING THE Qt GUI instead of the GTK. See the TODO-SDL file for
+a capability matrix that compares what the two GUIs can do.
To do the actual compiling:
make
@@ -58,9 +62,8 @@ After a sucessful compilation, the fceux binary will be generated to
sudo make install
-You can optionally define a install prefix when running cmake from the previous step:
-
- cmake -DCMAKE_INSTALL_PREFIX=/usr/local install
+By default cmake will use an installation prefix of /usr/local.
+The recommended installation prefix is /usr (this is where the installed fceux.desktop file expects everything to be)
You can choose to install the lua scripts (located in output/luaScripts) to a directory of your choosing:
@@ -88,6 +91,13 @@ OpenGL options:
For Linux builds, the OpenGL library preference can be either GLVND or LEGACY (default).
To use GLVND OpenGL, add a -DGLVND=1 on the cmake command line.
+Qt Styling Options:
+The Qt GUI can use custom Qt widget styling by providing it a Qt stylesheet file. At startup, the GUI will look
+for an environment variable named FCEUX_QT_STYLESHEET that must contain the full path to the file. If the variable
+is defined and the file is readable by the program, then the styling settings will be used by the GUI.
+Bash Shell Setup Example:
+export FCEUX_QT_STYLESHEET=/home/me/myQt.stylesheet
+
5 - LUA Scripting
-----------------
FCEUX provides a LUA 5.1 engine that allows for in-game scripting capabilities. LUA is enabled either way. It is just a matter of whether LUA is statically linked internally or dynamically linked to a system library.
diff --git a/SConstruct b/SConstruct
deleted file mode 100644
index 5d97b46c..00000000
--- a/SConstruct
+++ /dev/null
@@ -1,256 +0,0 @@
-#
-# SConstruct - build script for the SDL port of fceux
-#
-# You can adjust the BoolVariables below to include/exclude features
-# at compile-time. You may also use arguments to specify the parameters.
-# ie: scons RELEASE=1 GTK3=1
-#
-# Use "scons" to compile and "scons install" to install.
-#
-
-import os
-import sys
-import platform
-
-opts = Variables(None, ARGUMENTS)
-opts.AddVariables(
- BoolVariable('DEBUG', 'Build with debugging symbols', 1),
- BoolVariable('RELEASE', 'Set to 1 to build for release', 0),
- BoolVariable('FRAMESKIP', 'Enable frameskipping', 1),
- BoolVariable('OPENGL', 'Enable OpenGL support', 1),
- BoolVariable('LUA', 'Enable Lua support', 1),
- BoolVariable('GTK', 'Enable GTK2 GUI (SDL only)', 0),
- BoolVariable('GTK3', 'Enable GTK3 GUI (SDL only)', 1),
- BoolVariable('NEWPPU', 'Enable new PPU core', 1),
- BoolVariable('CREATE_AVI', 'Enable avi creation support (SDL only)', 1),
- BoolVariable('LOGO', 'Enable a logoscreen when creating avis (SDL only)', 1),
- BoolVariable('SYSTEM_LUA','Use system lua instead of static lua provided with fceux', 0),
- BoolVariable('SYSTEM_MINIZIP', 'Use system minizip instead of static minizip provided with fceux', 0),
- BoolVariable('LSB_FIRST', 'Least signficant byte first (non-PPC)', 1),
- BoolVariable('CLANG', 'Compile with llvm-clang instead of gcc', 0),
- BoolVariable('SDL2', 'Compile using SDL2 instead of SDL 1.2 (experimental/non-functional)', 1)
-)
-AddOption('--prefix', dest='prefix', type='string', nargs=1, action='store', metavar='DIR', help='installation prefix')
-
-prefix = GetOption('prefix')
-env = Environment(options = opts)
-
-if env['RELEASE']:
- env.Append(CPPDEFINES=["PUBLIC_RELEASE"])
- env['DEBUG'] = 0
-
-# LSB_FIRST must be off for PPC to compile
-if platform.system == "ppc":
- env['LSB_FIRST'] = 0
-
-# Default compiler flags:
-env.Append(CCFLAGS = ['-Wall', '-Wno-write-strings', '-Wno-sign-compare', '-Wno-parentheses', '-Wno-unused-local-typedefs'])
-env.Append(CXXFLAGS = ['-std=c++0x'])
-
-if 'PLATFORM' in os.environ:
- env.Replace(PLATFORM = os.environ['PLATFORM'])
-if 'CC' in os.environ:
- env.Replace(CC = os.environ['CC'])
-if 'CXX' in os.environ:
- env.Replace(CXX = os.environ['CXX'])
-if 'WINDRES' in os.environ:
- env.Replace(WINDRES = os.environ['WINDRES'])
-if 'CFLAGS' in os.environ:
- env.Append(CCFLAGS = os.environ['CFLAGS'].split())
-if 'CXXFLAGS' in os.environ:
- env.Append(CXXFLAGS = os.environ['CXXFLAGS'].split())
-if 'CPPFLAGS' in os.environ:
- env.Append(CPPFLAGS = os.environ['CPPFLAGS'].split())
-if 'LDFLAGS' in os.environ:
- env.Append(LINKFLAGS = os.environ['LDFLAGS'].split())
-if 'PKG_CONFIG_PATH' in os.environ:
- env['ENV']['PKG_CONFIG_PATH'] = os.environ['PKG_CONFIG_PATH']
-if 'PKG_CONFIG_PATH' not in os.environ and env['PLATFORM'] == 'darwin':
- env['ENV']['PKG_CONFIG_PATH'] = "/usr/local/lib/pkgconfig:/opt/X11/lib/pkgconfig"
-if 'PKG_CONFIG_LIBDIR' in os.environ:
- env['ENV']['PKG_CONFIG_LIBDIR'] = os.environ['PKG_CONFIG_LIBDIR']
-
-print("platform: ", env['PLATFORM'])
-
-# compile with clang
-if env['CLANG']:
- env.Replace(CC='clang')
- env.Replace(CXX='clang++')
-
-# special flags for cygwin
-# we have to do this here so that the function and lib checks will go through mingw
-if env['PLATFORM'] == 'cygwin':
- env.Append(CCFLAGS = " -mno-cygwin")
- env.Append(LINKFLAGS = " -mno-cygwin")
- env['LIBS'] = ['wsock32'];
-
-if env['PLATFORM'] == 'win32':
- env.Append(CPPPATH = [".", "drivers/win/", "drivers/common/", "drivers/", "drivers/win/zlib", "drivers/win/directx", "drivers/win/lua/include"])
- env.Append(CPPDEFINES = ["PSS_STYLE=2", "WIN32", "_USE_SHARED_MEMORY_", "NETWORK", "FCEUDEF_DEBUGGER", "NOMINMAX", "NEED_MINGW_HACKS", "_WIN32_IE=0x0600"])
- env.Append(LIBS = ["rpcrt4", "comctl32", "vfw32", "winmm", "ws2_32", "comdlg32", "ole32", "gdi32", "htmlhelp"])
-else:
- conf = Configure(env)
- # If libdw is available, compile in backward-cpp support
- if conf.CheckLib('dw'):
- conf.env.Append(CCFLAGS = "-DBACKWARD_HAS_DW=1")
- conf.env.Append(LINKFLAGS = "-ldw")
- if conf.CheckFunc('asprintf'):
- conf.env.Append(CCFLAGS = "-DHAVE_ASPRINTF")
- if env['SYSTEM_MINIZIP']:
- assert env.ParseConfig('pkg-config minizip --cflags --libs'), "please install: libminizip"
- assert env.ParseConfig('pkg-config zlib --cflags --libs'), "please install: zlib"
- #assert conf.CheckLibWithHeader('z', 'zlib.h', 'c', 'inflate;', 1), "please install: zlib"
- env.Append(CPPDEFINES=["_SYSTEM_MINIZIP"])
- else:
- assert env.ParseConfig('pkg-config zlib --cflags --libs'), "please install: zlib"
- #assert conf.CheckLibWithHeader('z', 'zlib.h', 'c', 'inflate;', 1), "please install: zlib"
- if env['SDL2']:
- assert env.ParseConfig('pkg-config sdl2 --cflags --libs'), "please install: sdl2"
- env.Append(CPPDEFINES=["_SDL2"])
- #env.ParseConfig('pkg-config sdl2 --cflags --libs')
- else:
- if not conf.CheckLib('SDL'):
- print('Did not find libSDL or SDL.lib, exiting!')
- Exit(1)
- env.ParseConfig('sdl-config --cflags --libs')
- if env['GTK']:
- if not conf.CheckLib('gtk-x11-2.0'):
- print('Could not find libgtk-2.0, exiting!')
- Exit(1)
- # Add compiler and linker flags from pkg-config
- config_string = 'pkg-config --cflags --libs gtk+-2.0'
- env.ParseConfig(config_string)
- env.Append(CPPDEFINES=["_GTK2"])
- env.Append(CCFLAGS = ["-D_GTK"])
- if env['GTK3']:
- # Add compiler and linker flags from pkg-config
- config_string = 'pkg-config --cflags --libs gtk+-3.0'
- env.ParseConfig(config_string)
- env.Append(CPPDEFINES=["_GTK3"])
- env.Append(CCFLAGS = ["-D_GTK"])
-
- ### Just make every configuration use -ldl, it may be needed for some reason.
- env.Append(LIBS = ["-ldl"])
-
- ### Lua platform defines
- ### Applies to all files even though only lua needs it, but should be ok
- if env['LUA']:
- env.Append(CPPDEFINES=["_S9XLUA_H"])
- if env['PLATFORM'] == 'darwin':
- # Define LUA_USE_MACOSX otherwise we can't bind external libs from lua
- env.Append(CCFLAGS = ["-DLUA_USE_MACOSX"])
- if env['PLATFORM'] == 'posix':
- # If we're POSIX, we use LUA_USE_LINUX since that combines usual lua posix defines with dlfcn calls for dynamic library loading.
- # Should work on any *nix
- env.Append(CCFLAGS = ["-DLUA_USE_LINUX"])
- if env['SYSTEM_LUA']:
- lua_link_flags = ''
- lua_include_dir = ''
-
- if conf.CheckLib('luajit-5.1'):
- lua_link_flags = "-lluajit-5.1"
- lua_include_dir = "/usr/include/luajit-2.0"
- elif conf.CheckLib('lua5.1'):
- lua_link_flags = "-llua5.1"
- lua_include_dir = "/usr/include/lua5.1"
- elif conf.CheckLib('lua-5.1'):
- lua_link_flags = "-llua-5.1"
- lua_include_dir = "/usr/include/lua-5.1"
- elif conf.CheckLib('lua'):
- lua_link_flags = "-llua"
- lua_include_dir = "/usr/include/lua"
-
- if 'LUA_LINKFLAGS' in os.environ:
- lua_link_flags = os.environ['LUA_LINKFLAGS']
- if 'LUA_INCDIR' in os.environ:
- lua_include_dir = os.environ['LUA_INCDIR']
-
- if not lua_link_flags or not lua_include_dir:
- print('Could not find liblua, exiting!')
- Exit(1)
-
- env.Append(LINKFLAGS = lua_link_flags.split())
- env.Append(CCFLAGS = ["-I" + lua_include_dir])
- else:
- env.Append(CCFLAGS = ["-Isrc/lua/src"])
- # "--as-needed" no longer available on OSX (probably BSD as well? TODO: test)
- if env['PLATFORM'] != 'darwin':
- env.Append(LINKFLAGS=['-Wl,--as-needed'])
-
- ### Search for gd if we're not in Windows
- if (env['PLATFORM'] != 'win32' and env['PLATFORM'] != 'cygwin') and (env['CREATE_AVI'] or env['LOGO']):
- gd = conf.CheckLib('gd', autoadd=1)
- if gd == 0:
- env['LOGO'] = 0
- print('Did not find libgd, you won\'t be able to create a logo screen for your avis.')
-
- if env['OPENGL'] and conf.CheckLibWithHeader('GL', 'GL/gl.h', 'c', autoadd=1):
- conf.env.Append(CCFLAGS = "-DOPENGL")
- conf.env.Append(CPPDEFINES = ['PSS_STYLE=1',"FCEUDEF_DEBUGGER"])
-
- env = conf.Finish()
-
-if sys.byteorder == 'little' or env['PLATFORM'] == 'win32':
- env.Append(CPPDEFINES = ['LSB_FIRST'])
-
-if env['FRAMESKIP']:
- env.Append(CPPDEFINES = ['FRAMESKIP'])
-
-print("base CPPDEFINES:",env['CPPDEFINES'])
-print("base CCFLAGS:",env['CCFLAGS'])
-
-if env['DEBUG']:
- env.Append(CPPDEFINES=["_DEBUG"], CCFLAGS = ['-g', '-O0'])
-else:
- env.Append(CCFLAGS = ['-O2'])
-
-if env['PLATFORM'] != 'win32' and env['PLATFORM'] != 'cygwin' and env['CREATE_AVI']:
- env.Append(CPPDEFINES=["CREATE_AVI"])
-else:
- env['CREATE_AVI']=0;
-
-Export('env')
-fceux = SConscript('src/SConscript')
-env.Program(target="fceux-net-server", source=["fceux-server/server.cpp", "fceux-server/md5.cpp", "fceux-server/throttle.cpp"])
-
-# Installation rules
-if prefix == None:
- prefix = "/usr/local"
-
-exe_suffix = ''
-if env['PLATFORM'] == 'win32':
- exe_suffix = '.exe'
-
-fceux_src = 'src/fceux' + exe_suffix
-fceux_dst = 'bin/fceux' + exe_suffix
-
-fceux_net_server_src = 'fceux-net-server' + exe_suffix
-fceux_net_server_dst = 'bin/fceux-net-server' + exe_suffix
-
-auxlib_src = 'src/auxlib.lua'
-auxlib_dst = 'bin/auxlib.lua'
-
-fceux_h_src = 'output/fceux.chm'
-fceux_h_dst = 'bin/fceux.chm'
-
-env.Command(fceux_h_dst, fceux_h_src, [Copy(fceux_h_dst, fceux_h_src)])
-env.Command(fceux_dst, fceux_src, [Copy(fceux_dst, fceux_src)])
-env.Command(fceux_net_server_dst, fceux_net_server_src, [Copy(fceux_net_server_dst, fceux_net_server_src)])
-env.Command(auxlib_dst, auxlib_src, [Copy(auxlib_dst, auxlib_src)])
-
-man_src = 'documentation/fceux.6'
-man_net_src = 'documentation/fceux-net-server.6'
-
-share_src = 'output/'
-
-image_src = 'fceux.png'
-
-desktop_src = 'fceux.desktop'
-
-env.Install(prefix + "/bin/", [fceux, fceux_net_server_src])
-env.InstallAs(prefix + '/share/fceux/', share_src)
-env.Install(prefix + '/share/fceux/', auxlib_src)
-env.Install(prefix + '/share/pixmaps/', image_src)
-env.Install(prefix + '/share/applications/', desktop_src)
-env.Install(prefix + "/share/man/man6/", [man_src, man_net_src])
-env.Alias('install', prefix)
diff --git a/TODO-SDL b/TODO-SDL
index 83f91b5c..5d3a7dde 100644
--- a/TODO-SDL
+++ b/TODO-SDL
@@ -4,6 +4,8 @@ Priorities
* GTK GUI was not cross-platform. A Qt5 version of the GUI has been created to meet this need.
I will keep the GTK GUI around for Linux users who prefer it, but when it comes to adding new features
the Qt GUI is where I plan to add them first (if at all).
+ * The Qt GUI has by far exceeded the capabilities of the older GTK version. Below is a GUI capability
+ matrix showing the differences between the two. I HIGHLY RECOMMEND USING THE Qt GUI.
* Code cleanup. Lots of compiler warnings with newer GCC. Maybe I'm OCD... but these warnings bother me.
Features
@@ -29,7 +31,7 @@ OpenGL graphics | YES | YES
Hot key config window | YES | YES |
Palette config window | YES | YES |
Multi-thread (GUI and emulation on separate threads) | YES | NO |
-Emulation speed control via menu | NO | NO |
+Emulation speed control via menu | YES | NO |
Emulation speed control via hotkeys | YES | YES |
Fullscreen functionality | YES | YES |
AVI Record Functionality | NO | NO |
@@ -38,18 +40,18 @@ Game genie load/enable capability | YES | YES
Movie record/save/play functionality | YES | YES |
Cheat search window | YES | YES |
Active Cheat window | YES | YES |
-RAM Search Window | NO | NO |
-RAM Watch Window | NO | YES |
+RAM Search Window | YES | NO |
+RAM Watch Window | YES | YES |
Memory Watch Window | NO | NO |
TAS Editor | NO | NO |
6502 Debugger Window | YES | YES |
-PPU Viewer | NO | NO |
-Name Table Viewer | NO | NO |
+PPU Viewer | YES | NO |
+Name Table Viewer | YES | NO |
Memory Hex Editor | YES | YES |
Trace Logger | YES | NO |
Code/Data Logger | YES | NO |
-Game Genie Encoder/Decoder | NO | NO |
-iNES Header Editor | NO | NO |
+Game Genie Encoder/Decoder | YES | NO |
+iNES Header Editor | YES | NO |
Built in help pages | NO | NO |
Network play (who actually uses this???) | NO | NO |
-----------------------------------------------------|-------------|-------------|
@@ -59,7 +61,7 @@ Network play (who actually uses this???) | NO | NO
QT
===
* Clean out rest of old GTK comments and #ifdefs
- * GUI Debug Tools TODO
+ * GUI Debug Tools Pretty Much Done
* GUI should compile in windows as well.... but testing is not a priority since the windows gui already has a totally separate backend.
BUGS
diff --git a/_config.yml b/_config.yml
index 4f848b1c..01659313 100644
--- a/_config.yml
+++ b/_config.yml
@@ -5,39 +5,41 @@
# - web/
# - fceux.png
# - index.html
+
exclude:
-- attic
-- fceux-server
-- getSDLKey
-- gfceu
-- m4
-- output
-- pipelines
-- src
-- vc
-- .gitignore
-- COPYING
-- ChangeLog
-- INSTALL
-- Makefile.am
-- NEWS
-- NewPPUtests.txt
-- README
-- SConstruct
-- STYLE-GUIDELINES-SDL
-- TODO-SDL
-- _config.yml
-- appveyor.yml
-- autogen.sh
-- azure-pipelines.yml
-- changelog.txt
-- configure.ac
-- debian-crossbuild.sh
-- doxygen
-- fceux.desktop
-- readme.md
-- fceux-server/fceux-net-server.exe
-- vc/BizHawk.Build.Tool.exe
-- vc/pscp.exe
-- vc/upx.exe
-- vc/zip.exe
+ - attic
+ - fceux-server
+ - getSDLKey
+ - gfceu
+ - m4
+ - output
+ - pipelines
+ - src
+ - vc
+ - .gitignore
+ - COPYING
+ - ChangeLog
+ - INSTALL
+ - Makefile.am
+ - NEWS
+ - NewPPUtests.txt
+ - README
+ - STYLE-GUIDELINES-SDL
+ - TODO-SDL
+ - _config.yml
+ - appveyor.yml
+ - autogen.sh
+ - azure-pipelines.yml
+ - changelog.txt
+ - configure.ac
+ - doxygen
+ - fceux.desktop
+ - readme.md
+ - fceux-server/fceux-net-server.exe
+ - vc/BizHawk.Build.Tool.exe
+ - vc/pscp.exe
+ - vc/upx.exe
+ - vc/zip.exe
+
+# Include all .js and .json files that start with an '_'
+include: [ "_*.js", "_*.json" ]
diff --git a/autogen.sh b/autogen.sh
deleted file mode 100755
index 71c87f37..00000000
--- a/autogen.sh
+++ /dev/null
@@ -1 +0,0 @@
-autoreconf --install || exit 1
diff --git a/configure.ac b/configure.ac
deleted file mode 100644
index 83c74c8a..00000000
--- a/configure.ac
+++ /dev/null
@@ -1,159 +0,0 @@
-AC_INIT([fceux], [2.2.3])
-AC_CONFIG_SRCDIR([src/fceu.cpp])
-AM_INIT_AUTOMAKE
-
-AC_PROG_CC
-AC_PROG_CPP
-AC_PROG_CXX
-AC_PROG_INSTALL
-AC_CONFIG_MACRO_DIR([m4])
-
-AC_CHECK_FUNC(asprintf, AC_DEFINE([HAVE_ASPRINTF]))
-
-## This is almost sure to not work
-AC_ARG_WITH(nativewin32,
- [AC_HELP_STRING([--with-nativewin32],
- [use nativewin32])],
- use_nativewin32=$withval,
- use_nativewin32="no")
-
-AM_CONDITIONAL(WIN32, false)
-AM_CONDITIONAL(UNIX, false)
-AM_CONDITIONAL(NATIVEWIN32,false)
-AM_CONDITIONAL(OPENGL, false)
-AM_CONDITIONAL(GTK2, false)
-AM_CONDITIONAL(GTK3, false)
-AM_CONDITIONAL(LUA, false)
-AM_CONDITIONAL(LUA_BUILTIN, false)
-AM_CONDITIONAL(SYSTEM_MINIZIP, false)
-AM_CONDITIONAL(GD, false)
-AM_CONDITIONAL(FRAMESKIP, true)
-
-## Check for zlib
-AC_CHECK_LIB([z], [zlibVersion],[], AC_MSG_ERROR([*** zlib not found!]))
-LIBS="$LIBS -lz"
-AC_CHECK_LIB([pthread], [pthread_create],[], AC_MSG_ERROR([*** pthread not found!]))
-LIBS="$LIBS -lpthread"
-
-## Platform specific setup
-if expr x"$target" : 'x.*beos' > /dev/null; then
- CFLAGS="-no-fpic $CFLAGS"
- CPPFLAGS="-no-fpic $CPPFLAGS"
- AC_DEFINE([PSS_STYLE],[1])
-elif expr x"$target" : 'x.*mingw' > /dev/null; then
- ## Probably doesn't work
- AC_DEFINE([PSS_STYLE],[2])
- AC_DEFINE([WIN32])
- AM_CONDITIONAL(WIN32, true)
-
- if test x$use_nativewin32 = xyes; then
- LIBS="$LIBS -mwindows -lddraw -ldinput -ldsound -lgdi32 -ldxguid -lwinmm -lshell32 -lwsock32 -lcomdlg32 -lole32"
- AM_CONDITIONAL(NATIVEWIN32,true)
- else
- LIBS="$LIBS -ldsound -lwinmm"
- fi
-elif expr x"$target" : 'x.*darwin' > /dev/null; then
- ## Probably doesn't work
- AC_DEFINE([MACOSX])
-else
- AM_CONDITIONAL(UNIX, true)
- AC_DEFINE([UNIX])
- AC_DEFINE([PSS_STYLE],[1])
-fi
-if test x$use_nativewin32 = xno; then
- ## Check for SDL
- SDL_VERSION=1.2.0
- AM_PATH_SDL($SDL_VERSION, [:],
- AC_MSG_ERROR([*** SDL version $SDL_VERSION not found!]))
- AC_DEFINE([SDL])
-
- LIBS="$LIBS $SDL_LIBS"
- CFLAGS="-Wall -fomit-frame-pointer $CFLAGS $SDL_CFLAGS"
- CPPFLAGS="-Wall -fomit-frame-pointer $CPPFLAGS $SDL_CFLAGS"
-
- ## Check for OpenGL
- AC_ARG_ENABLE([opengl],
- AS_HELP_STRING([--enable-opengl], [Enable OpenGL support]))
- AS_IF([test "x$enable_opengl" != "xno"], [
- AC_CHECK_HEADER([GL/gl.h],[AC_DEFINE([OPENGL]) AM_CONDITIONAL(OPENGL, true)],
- [
- AC_CHECK_HEADER([OpenGL/gl.h],[AC_DEFINE([OPENGL]) AM_CONDITIONAL(OPENGL, true)],[])
- AC_DEFINE([APPLEOPENGL])
- ])
- LIBS="$LIBS -lGL -lGLU"
- ])
-
- ## Check for GTK2
- AC_ARG_ENABLE([gtk2],
- AS_HELP_STRING([--enable-gtk2], [Enable GTK2 GUI]))
- AS_IF([test "x$enable_gtk2" = "xyes"], [
- AM_PATH_GTK_2_0([2.24.0],AM_CONDITIONAL(GTK2, true),AC_MSG_ERROR([Gtk+ 2.24.0 or higher required.]))
- AC_DEFINE([_GTK])
- AC_DEFINE([GTK2])
- ])
-
- ## Check for GTK3
- AC_ARG_ENABLE([gtk3],
- AS_HELP_STRING([--enable-gtk3], [Enable GTK3 GUI]))
- AS_IF([test "x$enable_gtk2" = "xyes" -a "x$enable_gtk3" = "xyes"], [
- AC_MSG_ERROR([GTK2 and GTK3 cannot be simulatenously enabled.])
- ])
- AS_IF([test "x$enable_gtk3" = "xyes"], [
- AM_PATH_GTK_3_0([3.0.0],AM_CONDITIONAL(GTK3, true),AC_MSG_ERROR([Gtk+ 3.0.0 or higher required.]))
- AC_DEFINE([_GTK])
- AC_DEFINE([GTK3])
- ])
-fi
-
-## Check for system lua
-AC_ARG_ENABLE([lua],
- AS_HELP_STRING([--enable-lua], [Use lua libraries found on this system]))
-AS_IF([test "x$enable_lua" = "xyes"], [
- AC_SUBST(LUA, lua5.1)
- AX_PROG_LUA([5.1],[5.2])
- PKG_CHECK_MODULES([lua51], [lua51])
- AX_LUA_LIBS([], AC_MSG_ERROR([Lua libs not found!]))
- AC_DEFINE([_S9XLUA_H])
- AM_CONDITIONAL(LUA, true)
- LIBS="$LIBS $LUA_LIB"
-])
-
-## Check for lua builtin
-AC_ARG_ENABLE([lua-builtin],
- AS_HELP_STRING([--enable-lua-builtin], [Use lua5.1 included with fceux]))
-AS_IF([test "x$enable_lua-builtin" = "xyes"], [
- #AX_LUA_HEADERS([], AC_MSG_ERROR([Lua 5.1 headers not found!]))
- AC_DEFINE([_S9XLUA_H])
- AM_CONDITIONAL(LUA_BUILTIN, true)
-])
-
-## Check for gd
-AC_ARG_ENABLE([gd],
- AS_HELP_STRING([--enable-gd], [Use libgd for AVI creation]))
-AS_IF([test "x$enable_gd" = "xyes"], [
- #AX_LUA_HEADERS([], AC_MSG_ERROR([Lua 5.1 headers not found!]))
- AX_CHECK_GD
- LIBS="$LIBS $GD_LIBS"
- AC_DEFINE([CREATE_AVI])
-])
-
-## Check for system minizip
-AC_ARG_ENABLE([system-minizip],
- AS_HELP_STRING([--enable-system-minizip], [Use minizip from system instead of fceux distribution]))
-AS_IF([test "x$enable_system_minizip" = "xyes"], [
- PKG_CHECK_MODULES([minizip], [minizip])
- AM_CONDITIONAL(SYSTEM_MINIZIP, true)
- LIBS="$LIBS $minizip_LIBS"
-])
-
-AC_C_BIGENDIAN([], [AC_DEFINE([LSB_FIRST])])
-
-## Check for frameskip disable
-AC_ARG_ENABLE([frameskip],
- AS_HELP_STRING([--disable-frameskip], [Disable frameskip feature]))
-
-AS_IF([test "x$disable_frameskip" != "xno"], [
- AC_DEFINE([FRAMESKIP])
-])
-
-AC_OUTPUT([Makefile src/Makefile])
diff --git a/debian-crossbuild.sh b/debian-crossbuild.sh
deleted file mode 100644
index f0623563..00000000
--- a/debian-crossbuild.sh
+++ /dev/null
@@ -1,5 +0,0 @@
-#!/bin/sh
-if [ -f /usr/bin/i586-mingw32msvc-windres ]; then HOST=i586-mingw32msvc
-else HOST=i586-mingw32
-fi
-PLATFORM=win32 CC=${HOST}-gcc CXX=${HOST}-g++ WRC=${HOST}-windres WINDRES=${HOST}-windres scons $@
diff --git a/fceux.desktop b/fceux.desktop
index 60aecf2c..b1a9081e 100644
--- a/fceux.desktop
+++ b/fceux.desktop
@@ -6,7 +6,7 @@ GenericName=NES/Famicom emulator
NoDisplay=false
Comment=Emulate NES ROMs
Exec=/usr/bin/fceux
-Icon=/usr/share/pixmaps/fceux.png
+Icon=/usr/share/pixmaps/fceux1.png
Terminal=false
MimeType=application/x-nes-rom
Categories=Game;Emulator;
diff --git a/fceux.icns b/fceux.icns
index 938275fd..f963e5d2 100644
Binary files a/fceux.icns and b/fceux.icns differ
diff --git a/fceux.pro b/fceux.pro
deleted file mode 100644
index fec9f599..00000000
--- a/fceux.pro
+++ /dev/null
@@ -1,369 +0,0 @@
-######################################################################
-# Automatically generated by qmake (3.1) Sat Jun 20 21:20:47 2020
-######################################################################
-
-TEMPLATE = app
-TARGET = fceux
-INCLUDEPATH += .
-
-# The following define makes your compiler warn you if you use any
-# feature of Qt which has been marked as deprecated (the exact warnings
-# depend on your compiler). Please consult the documentation of the
-# deprecated API in order to know how to port your code away from it.
-DEFINES += QT_DEPRECATED_WARNINGS
-
-# You can also make your code fail to compile if you use deprecated APIs.
-# In order to do so, uncomment the following line.
-# You can also select to disable deprecated APIs only up to a certain version of Qt.
-#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
-
-QT += widgets
-
-CONFIG += object_parallel_to_source
-
-INCLUDEPATH += src src/drivers
-
-ENABLE_LUA = 0
-USE_INTERNAL_LUA = 0
-
-unix {
- QT_CONFIG -= no-pkg-config
- CONFIG += link_pkgconfig
-
- QMAKE_CXXFLAGS += -DPSS_STYLE=1 -DHAVE_ASPRINTF
-
- packagesExist(minizip){
- PKGCONFIG += minizip
- QMAKE_CXXFLAGS += -D_SYSTEM_MINIZIP
- }
-
- packagesExist(zlib){
- PKGCONFIG += zlib
- }
-
- PKGCONFIG += sdl2
-
- packagesExist(lua-5.1){
- PKGCONFIG += lua-5.1
- USE_INTERNAL_LUA = 0;
- QMAKE_CXXFLAGS += -D_S9XLUA_H
- } else {
- USE_INTERNAL_LUA = 1;
- QMAKE_CXXFLAGS += -D_S9XLUA_H
- }
- ENABLE_LUA = 1
-
- QMAKE_CXXFLAGS -= -O2
- QMAKE_CXXFLAGS += -D__QT_DRIVER__ -O0 -g3 -Wall -Wno-write-strings -Wno-sign-compare -Wno-parentheses -Wno-unused-local-typedefs
- QMAKE_CXXFLAGS_RELEASE -= -O2
-
- LIBS += -lz
-}
-
-# Input
-SOURCES += src/asm.cpp
-SOURCES += src/cart.cpp
-SOURCES += src/cheat.cpp
-SOURCES += src/conddebug.cpp
-SOURCES += src/config.cpp
-SOURCES += src/debug.cpp
-SOURCES += src/drawing.cpp
-SOURCES += src/fceu.cpp
-SOURCES += src/fds.cpp
-SOURCES += src/file.cpp
-SOURCES += src/emufile.cpp
-SOURCES += src/filter.cpp
-SOURCES += src/ines.cpp
-SOURCES += src/input.cpp
-SOURCES += src/movie.cpp
-SOURCES += src/netplay.cpp
-SOURCES += src/nsf.cpp
-SOURCES += src/oldmovie.cpp
-SOURCES += src/palette.cpp
-SOURCES += src/ppu.cpp
-SOURCES += src/sound.cpp
-SOURCES += src/state.cpp
-SOURCES += src/unif.cpp
-SOURCES += src/video.cpp
-SOURCES += src/vsuni.cpp
-SOURCES += src/wave.cpp
-SOURCES += src/x6502.cpp
-
-isEqual( ENABLE_LUA, 1 ) {
- isEqual( USE_INTERNAL_LUA, 1 ) {
- message("Enabling Internal LUA")
- INCLUDEPATH += src/lua/src
- SOURCES += src/lua/src/lapi.c
- SOURCES += src/lua/src/lauxlib.c
- SOURCES += src/lua/src/lbaselib.c
- SOURCES += src/lua/src/lcode.c
- SOURCES += src/lua/src/ldblib.c
- SOURCES += src/lua/src/ldebug.c
- SOURCES += src/lua/src/ldo.c
- SOURCES += src/lua/src/ldump.c
- SOURCES += src/lua/src/lfunc.c
- SOURCES += src/lua/src/lgc.c
- SOURCES += src/lua/src/linit.c
- SOURCES += src/lua/src/liolib.c
- SOURCES += src/lua/src/llex.c
- SOURCES += src/lua/src/lmathlib.c
- SOURCES += src/lua/src/lmem.c
- SOURCES += src/lua/src/loadlib.c
- SOURCES += src/lua/src/lobject.c
- SOURCES += src/lua/src/lopcodes.c
- SOURCES += src/lua/src/loslib.c
- SOURCES += src/lua/src/lparser.c
- SOURCES += src/lua/src/lstate.c
- SOURCES += src/lua/src/lstring.c
- SOURCES += src/lua/src/lstrlib.c
- SOURCES += src/lua/src/ltable.c
- SOURCES += src/lua/src/ltablib.c
- SOURCES += src/lua/src/ltm.c
- SOURCES += src/lua/src/lundump.c
- SOURCES += src/lua/src/lvm.c
- SOURCES += src/lua/src/lzio.c
- SOURCES += src/lua/src/print.c
- SOURCES += src/lua-engine.cpp
- } else {
- message("Enabling System LUA")
- SOURCES += src/lua-engine.cpp
- }
- message("Enabling LUA")
-} else {
- message("Disabling LUA")
-}
-
-SOURCES += src/boards/01-222.cpp
-SOURCES += src/boards/09-034a.cpp
-SOURCES += src/boards/103.cpp
-SOURCES += src/boards/106.cpp
-SOURCES += src/boards/108.cpp
-SOURCES += src/boards/112.cpp
-SOURCES += src/boards/116.cpp
-SOURCES += src/boards/117.cpp
-SOURCES += src/boards/120.cpp
-SOURCES += src/boards/121.cpp
-SOURCES += src/boards/12in1.cpp
-SOURCES += src/boards/151.cpp
-SOURCES += src/boards/156.cpp
-SOURCES += src/boards/158B.cpp
-SOURCES += src/boards/15.cpp
-SOURCES += src/boards/164.cpp
-SOURCES += src/boards/168.cpp
-SOURCES += src/boards/170.cpp
-SOURCES += src/boards/175.cpp
-SOURCES += src/boards/176.cpp
-SOURCES += src/boards/177.cpp
-SOURCES += src/boards/178.cpp
-SOURCES += src/boards/183.cpp
-SOURCES += src/boards/185.cpp
-SOURCES += src/boards/186.cpp
-SOURCES += src/boards/187.cpp
-SOURCES += src/boards/189.cpp
-SOURCES += src/boards/18.cpp
-SOURCES += src/boards/190.cpp
-SOURCES += src/boards/193.cpp
-SOURCES += src/boards/199.cpp
-SOURCES += src/boards/206.cpp
-SOURCES += src/boards/208.cpp
-SOURCES += src/boards/222.cpp
-SOURCES += src/boards/225.cpp
-SOURCES += src/boards/228.cpp
-SOURCES += src/boards/230.cpp
-SOURCES += src/boards/232.cpp
-SOURCES += src/boards/234.cpp
-SOURCES += src/boards/235.cpp
-SOURCES += src/boards/244.cpp
-SOURCES += src/boards/246.cpp
-SOURCES += src/boards/252.cpp
-SOURCES += src/boards/253.cpp
-SOURCES += src/boards/28.cpp
-SOURCES += src/boards/32.cpp
-SOURCES += src/boards/33.cpp
-SOURCES += src/boards/34.cpp
-SOURCES += src/boards/36.cpp
-SOURCES += src/boards/3d-block.cpp
-SOURCES += src/boards/40.cpp
-SOURCES += src/boards/411120-c.cpp
-SOURCES += src/boards/41.cpp
-SOURCES += src/boards/42.cpp
-SOURCES += src/boards/43.cpp
-SOURCES += src/boards/46.cpp
-SOURCES += src/boards/50.cpp
-SOURCES += src/boards/51.cpp
-SOURCES += src/boards/57.cpp
-SOURCES += src/boards/603-5052.cpp
-SOURCES += src/boards/62.cpp
-SOURCES += src/boards/65.cpp
-SOURCES += src/boards/67.cpp
-SOURCES += src/boards/68.cpp
-SOURCES += src/boards/69.cpp
-SOURCES += src/boards/71.cpp
-SOURCES += src/boards/72.cpp
-SOURCES += src/boards/77.cpp
-SOURCES += src/boards/79.cpp
-SOURCES += src/boards/80013-B.cpp
-SOURCES += src/boards/80.cpp
-SOURCES += src/boards/8157.cpp
-SOURCES += src/boards/8237.cpp
-SOURCES += src/boards/82.cpp
-SOURCES += src/boards/830118C.cpp
-SOURCES += src/boards/88.cpp
-SOURCES += src/boards/8in1.cpp
-SOURCES += src/boards/90.cpp
-SOURCES += src/boards/91.cpp
-SOURCES += src/boards/96.cpp
-SOURCES += src/boards/99.cpp
-SOURCES += src/boards/a9746.cpp
-SOURCES += src/boards/ac-08.cpp
-SOURCES += src/boards/addrlatch.cpp
-SOURCES += src/boards/ax5705.cpp
-SOURCES += src/boards/bandai.cpp
-SOURCES += src/boards/bb.cpp
-SOURCES += src/boards/bmc13in1jy110.cpp
-SOURCES += src/boards/bmc42in1r.cpp
-SOURCES += src/boards/bmc64in1nr.cpp
-SOURCES += src/boards/bmc70in1.cpp
-SOURCES += src/boards/BMW8544.cpp
-SOURCES += src/boards/bonza.cpp
-SOURCES += src/boards/bs-5.cpp
-SOURCES += src/boards/cheapocabra.cpp
-SOURCES += src/boards/cityfighter.cpp
-SOURCES += src/boards/coolboy.cpp
-SOURCES += src/boards/dance2000.cpp
-SOURCES += src/boards/datalatch.cpp
-SOURCES += src/boards/dream.cpp
-SOURCES += src/boards/__dummy_mapper.cpp
-SOURCES += src/boards/edu2000.cpp
-SOURCES += src/boards/eh8813a.cpp
-SOURCES += src/boards/emu2413.c
-SOURCES += src/boards/et-100.cpp
-SOURCES += src/boards/et-4320.cpp
-SOURCES += src/boards/F-15.cpp
-SOURCES += src/boards/famicombox.cpp
-SOURCES += src/boards/ffe.cpp
-SOURCES += src/boards/fk23c.cpp
-SOURCES += src/boards/fns.cpp
-SOURCES += src/boards/ghostbusters63in1.cpp
-SOURCES += src/boards/gs-2004.cpp
-SOURCES += src/boards/gs-2013.cpp
-SOURCES += src/boards/h2288.cpp
-SOURCES += src/boards/hp10xx_hp20xx.cpp
-SOURCES += src/boards/hp898f.cpp
-SOURCES += src/boards/inlnsf.cpp
-SOURCES += src/boards/karaoke.cpp
-SOURCES += src/boards/kof97.cpp
-SOURCES += src/boards/ks7010.cpp
-SOURCES += src/boards/ks7012.cpp
-SOURCES += src/boards/ks7013.cpp
-SOURCES += src/boards/ks7016.cpp
-SOURCES += src/boards/ks7017.cpp
-SOURCES += src/boards/ks7030.cpp
-SOURCES += src/boards/ks7031.cpp
-SOURCES += src/boards/ks7032.cpp
-SOURCES += src/boards/ks7037.cpp
-SOURCES += src/boards/ks7057.cpp
-SOURCES += src/boards/le05.cpp
-SOURCES += src/boards/lh32.cpp
-SOURCES += src/boards/lh53.cpp
-SOURCES += src/boards/malee.cpp
-SOURCES += src/boards/mihunche.cpp
-SOURCES += src/boards/mmc1.cpp
-SOURCES += src/boards/mmc2and4.cpp
-SOURCES += src/boards/mmc3.cpp
-SOURCES += src/boards/mmc5.cpp
-SOURCES += src/boards/n106.cpp
-SOURCES += src/boards/n625092.cpp
-SOURCES += src/boards/novel.cpp
-SOURCES += src/boards/onebus.cpp
-SOURCES += src/boards/pec-586.cpp
-SOURCES += src/boards/rt-01.cpp
-SOURCES += src/boards/sa-9602b.cpp
-SOURCES += src/boards/sachen.cpp
-SOURCES += src/boards/sb-2000.cpp
-SOURCES += src/boards/sc-127.cpp
-SOURCES += src/boards/sheroes.cpp
-SOURCES += src/boards/sl1632.cpp
-SOURCES += src/boards/subor.cpp
-SOURCES += src/boards/super24.cpp
-SOURCES += src/boards/supervision.cpp
-SOURCES += src/boards/t-227-1.cpp
-SOURCES += src/boards/t-262.cpp
-SOURCES += src/boards/tengen.cpp
-SOURCES += src/boards/tf-1201.cpp
-SOURCES += src/boards/transformer.cpp
-SOURCES += src/boards/unrom512.cpp
-SOURCES += src/boards/vrc1.cpp
-SOURCES += src/boards/vrc2and4.cpp
-SOURCES += src/boards/vrc3.cpp
-SOURCES += src/boards/vrc5.cpp
-SOURCES += src/boards/vrc6.cpp
-SOURCES += src/boards/vrc7.cpp
-SOURCES += src/boards/vrc7p.cpp
-SOURCES += src/boards/yoko.cpp
-SOURCES += src/input/arkanoid.cpp
-SOURCES += src/input/bworld.cpp
-SOURCES += src/input/cursor.cpp
-SOURCES += src/input/fkb.cpp
-SOURCES += src/input/fns.cpp
-SOURCES += src/input/ftrainer.cpp
-SOURCES += src/input/hypershot.cpp
-SOURCES += src/input/mahjong.cpp
-SOURCES += src/input/mouse.cpp
-SOURCES += src/input/oekakids.cpp
-SOURCES += src/input/pec586kb.cpp
-SOURCES += src/input/powerpad.cpp
-SOURCES += src/input/quiz.cpp
-SOURCES += src/input/shadow.cpp
-SOURCES += src/input/snesmouse.cpp
-SOURCES += src/input/suborkb.cpp
-SOURCES += src/input/toprider.cpp
-SOURCES += src/input/virtualboy.cpp
-SOURCES += src/input/zapper.cpp
-SOURCES += src/utils/backward.cpp
-SOURCES += src/utils/ConvertUTF.c
-SOURCES += src/utils/xstring.cpp
-SOURCES += src/utils/crc32.cpp
-SOURCES += src/utils/endian.cpp
-SOURCES += src/utils/general.cpp
-SOURCES += src/utils/guid.cpp
-SOURCES += src/utils/md5.cpp
-SOURCES += src/utils/memory.cpp
-SOURCES += src/drivers/common/args.cpp
-SOURCES += src/drivers/common/cheat.cpp
-SOURCES += src/drivers/common/config.cpp
-SOURCES += src/drivers/common/configSys.cpp
-SOURCES += src/drivers/common/hq2x.cpp
-SOURCES += src/drivers/common/hq3x.cpp
-SOURCES += src/drivers/common/scale2x.cpp
-SOURCES += src/drivers/common/scale3x.cpp
-SOURCES += src/drivers/common/scalebit.cpp
-SOURCES += src/drivers/common/vidblit.cpp
-SOURCES += src/drivers/common/nes_ntsc.c
-
-HEADERS += src/drivers/Qt/ConsoleWindow.h
-HEADERS += src/drivers/Qt/ConsoleViewerGL.h
-HEADERS += src/drivers/Qt/ConsoleViewerSDL.h
-HEADERS += src/drivers/Qt/GamePadConf.h
-HEADERS += src/drivers/Qt/HotKeyConf.h
-HEADERS += src/drivers/Qt/ConsoleVideoConf.h
-HEADERS += src/drivers/Qt/ConsoleSoundConf.h
-SOURCES += src/drivers/Qt/main.cpp
-SOURCES += src/drivers/Qt/ConsoleWindow.cpp
-SOURCES += src/drivers/Qt/ConsoleViewerGL.cpp
-SOURCES += src/drivers/Qt/ConsoleViewerSDL.cpp
-SOURCES += src/drivers/Qt/GamePadConf.cpp
-SOURCES += src/drivers/Qt/HotKeyConf.cpp
-SOURCES += src/drivers/Qt/ConsoleVideoConf.cpp
-SOURCES += src/drivers/Qt/ConsoleSoundConf.cpp
-SOURCES += src/drivers/Qt/fceuWrapper.cpp
-SOURCES += src/drivers/Qt/config.cpp
-SOURCES += src/drivers/Qt/input.cpp
-SOURCES += src/drivers/Qt/nes_shm.cpp
-SOURCES += src/drivers/Qt/keyscan.cpp
-SOURCES += src/drivers/Qt/sdl-sound.cpp
-SOURCES += src/drivers/Qt/sdl-video.cpp
-SOURCES += src/drivers/Qt/sdl-joystick.cpp
-SOURCES += src/drivers/Qt/sdl-throttle.cpp
-SOURCES += src/drivers/Qt/unix-netplay.cpp
-
diff --git a/fceux1.png b/fceux1.png
index f4966c09..5446b16b 100644
Binary files a/fceux1.png and b/fceux1.png differ
diff --git a/icons/application-exit.png b/icons/application-exit.png
new file mode 100644
index 00000000..9512d7e1
Binary files /dev/null and b/icons/application-exit.png differ
diff --git a/icons/camera.png b/icons/camera.png
new file mode 100644
index 00000000..37075dc1
Binary files /dev/null and b/icons/camera.png differ
diff --git a/icons/graphics-palette.png b/icons/graphics-palette.png
new file mode 100644
index 00000000..fc711bdc
Binary files /dev/null and b/icons/graphics-palette.png differ
diff --git a/icons/input-gaming-symbolic.png b/icons/input-gaming-symbolic.png
new file mode 100644
index 00000000..2c82e693
Binary files /dev/null and b/icons/input-gaming-symbolic.png differ
diff --git a/icons/input-gaming.png b/icons/input-gaming.png
new file mode 100644
index 00000000..9d5b1d5f
Binary files /dev/null and b/icons/input-gaming.png differ
diff --git a/icons/input-keyboard.png b/icons/input-keyboard.png
new file mode 100644
index 00000000..631587b1
Binary files /dev/null and b/icons/input-keyboard.png differ
diff --git a/icons/media-record.png b/icons/media-record.png
new file mode 100644
index 00000000..072ed7f9
Binary files /dev/null and b/icons/media-record.png differ
diff --git a/icons/movie.png b/icons/movie.png
new file mode 100644
index 00000000..376ff3a5
Binary files /dev/null and b/icons/movie.png differ
diff --git a/icons/power.png b/icons/power.png
new file mode 100644
index 00000000..2429e9ed
Binary files /dev/null and b/icons/power.png differ
diff --git a/icons/timer.png b/icons/timer.png
new file mode 100644
index 00000000..4e539e1f
Binary files /dev/null and b/icons/timer.png differ
diff --git a/icons/view-fullscreen.png b/icons/view-fullscreen.png
new file mode 100644
index 00000000..731c660f
Binary files /dev/null and b/icons/view-fullscreen.png differ
diff --git a/output/fceux.chm b/output/fceux.chm
index 6102c59d..ccba53ee 100644
Binary files a/output/fceux.chm and b/output/fceux.chm differ
diff --git a/output/taseditor.chm b/output/taseditor.chm
index c0318726..aed0c445 100644
Binary files a/output/taseditor.chm and b/output/taseditor.chm differ
diff --git a/pipelines/debpkg.pl b/pipelines/debpkg.pl
index ba27b62b..b2deb0cc 100755
--- a/pipelines/debpkg.pl
+++ b/pipelines/debpkg.pl
@@ -2,7 +2,7 @@
use strict;
-my $VERSION="2.2.3";
+my $VERSION="2.3.0";
my $INSTALL_PREFIX="/tmp/fceux";
my $CTL_FILENAME="$INSTALL_PREFIX/DEBIAN/control";
my $ARCH="amd64";
diff --git a/pipelines/linux_build.sh b/pipelines/linux_build.sh
index edb7c49d..f97f7289 100755
--- a/pipelines/linux_build.sh
+++ b/pipelines/linux_build.sh
@@ -25,6 +25,10 @@ echo '****************************************'
echo '*** Installing Package Dependencies ***'
echo '****************************************'
echo '****************************************'
+echo '****************************************'
+echo 'Install Dependency Updates'
+echo '****************************************'
+sudo apt-get --assume-yes update
# Install Lua-5.1 development package
echo '****************************************'
echo 'Install Dependency lua5.1-dev'
@@ -89,28 +93,27 @@ echo '**************************'
echo '*** Building Project ***'
echo '**************************'
mkdir -p $INSTALL_PREFIX/usr;
-#scons --clean
-#scons GTK3=1 SYSTEM_LUA=1 SYSTEM_MINIZIP=1 CREATE_AVI=1 install --prefix=$INSTALL_PREFIX/usr
+
echo "Num CPU: `nproc`";
mkdir buildQT; cd buildQT;
cmake \
-DCMAKE_BUILD_TYPE=Release \
- -DCMAKE_INSTALL_PREFIX=$INSTALL_PREFIX/usr \
+ -DCMAKE_INSTALL_PREFIX=/usr \
-DCMAKE_VERBOSE_MAKEFILE:BOOL=ON \
..
make -j `nproc`
-make install
+make install DESTDIR=$INSTALL_PREFIX
cd ..;
mkdir buildGTK; cd buildGTK;
cmake \
-DGTK=1 \
-DCMAKE_BUILD_TYPE=Release \
- -DCMAKE_INSTALL_PREFIX=$INSTALL_PREFIX/usr \
+ -DCMAKE_INSTALL_PREFIX=/usr \
-DCMAKE_VERBOSE_MAKEFILE:BOOL=ON \
..
make -j `nproc`
-make install
+make install DESTDIR=$INSTALL_PREFIX
# Install Files
#cd .. # cd out of build
diff --git a/pipelines/macOS_build.sh b/pipelines/macOS_build.sh
index b096dce2..0b48be4e 100755
--- a/pipelines/macOS_build.sh
+++ b/pipelines/macOS_build.sh
@@ -7,8 +7,8 @@ uname -a
sw_vers
FCEUX_VERSION_MAJOR=2
-FCEUX_VERSION_MINOR=2
-FCEUX_VERSION_PATCH=3
+FCEUX_VERSION_MINOR=3
+FCEUX_VERSION_PATCH=0
SCRIPT_DIR=$( cd $(dirname $BASH_SOURCE[0]); pwd );
@@ -43,7 +43,6 @@ brew install minizip
export PKG_CONFIG_PATH=$PKG_CONFIG_PATH:/usr/local/lib/pkgconfig:
-#QMAKE=`find /usr/local -name qmake`;
QT_CMAKE=`find /usr/local -name Qt5Config.cmake`
echo $QT_CMAKE;
export Qt5_DIR=`dirname $QT_CMAKE`;
@@ -54,11 +53,11 @@ echo '*** Building Project ***'
echo '**************************'
mkdir build;
cd build;
-#$QMAKE ..
cmake \
-DCMAKE_BUILD_TYPE=Release \
-DCMAKE_INSTALL_PREFIX=$INSTALL_PREFIX \
-DCMAKE_VERBOSE_MAKEFILE:BOOL=ON \
+ -DCMAKE_PREFIX_PATH=`brew --prefix qt5` \
-DCMAKE_PROJECT_VERSION_MAJOR=$FCEUX_VERSION_MAJOR \
-DCMAKE_PROJECT_VERSION_MINOR=$FCEUX_VERSION_MINOR \
-DCMAKE_PROJECT_VERSION_PATCH=$FCEUX_VERSION_PATCH \
diff --git a/readme.md b/readme.md
index 5719756b..fc3420fb 100644
--- a/readme.md
+++ b/readme.md
@@ -7,8 +7,8 @@ An open source NES Emulator for Windows and Unix that features solid emulation a
Interim builds:
* Win32: [fceux.zip](https://ci.appveyor.com/api/projects/zeromus/fceux/artifacts/fceux.zip?branch=master&job=Windows%2032)
* Win64: [fceux64.zip](https://ci.appveyor.com/api/projects/zeromus/fceux/artifacts/fceux64.zip?branch=master&job=Windows%2064)
-* Ubuntu: [fceux-2.2.3-amd64.deb](https://ci.appveyor.com/api/projects/zeromus/fceux/artifacts/fceux-2.2.3-amd64.deb?branch=master&job=Ubuntu)
-* MacOSX: [fceux-2.2.3-Darwin.dmg](https://ci.appveyor.com/api/projects/zeromus/fceux/artifacts/fceux-2.2.3-Darwin.dmg?branch=master&job=MacOS)
+* Ubuntu: [fceux-2.3.0-amd64.deb](https://ci.appveyor.com/api/projects/zeromus/fceux/artifacts/fceux-2.3.0-amd64.deb?branch=master&job=Ubuntu)
+* MacOSX: [fceux-2.3.0-Darwin.dmg](https://ci.appveyor.com/api/projects/zeromus/fceux/artifacts/fceux-2.3.0-Darwin.dmg?branch=master&job=MacOS)
* Status: [Appveyor](https://ci.appveyor.com/project/zeromus/fceux/)
But you might like mesen more: https://github.com/SourMesen/Mesen
@@ -17,4 +17,4 @@ You should get releases from here: https://sourceforge.net/projects/fceultra/fil
That's because github forces us to use tags we don't have for releases.
-2.2.3 is the most recent release but most people are using the autobuilds.
+2.3.0 is the most recent release but most people are using the autobuilds.
diff --git a/resources.qrc b/resources.qrc
index 63be737c..58ea0097 100644
--- a/resources.qrc
+++ b/resources.qrc
@@ -2,5 +2,16 @@
fceux.png
fceux1.png
+ icons/power.png
+ icons/media-record.png
+ icons/application-exit.png
+ icons/graphics-palette.png
+ icons/view-fullscreen.png
+ icons/input-keyboard.png
+ icons/input-gaming.png
+ icons/input-gaming-symbolic.png
+ icons/timer.png
+ icons/movie.png
+ icons/camera.png
diff --git a/scripts/linux_makeIcons.sh b/scripts/linux_makeIcons.sh
new file mode 100755
index 00000000..a7aa96b5
--- /dev/null
+++ b/scripts/linux_makeIcons.sh
@@ -0,0 +1,20 @@
+#!/bin/bash
+
+SRC_PNG=../fceux1.png
+ICON_PATH=/usr/share/icons/hicolor
+
+convert -resize 32x32 $SRC_PNG fceux-32x32.png
+convert -resize 48x48 $SRC_PNG fceux-48x48.png
+convert -resize 64x64 $SRC_PNG fceux-64x64.png
+convert -resize 72x72 $SRC_PNG fceux-72x72.png
+convert -resize 96x96 $SRC_PNG fceux-96x96.png
+convert -resize 128x128 $SRC_PNG fceux-128x128.png
+convert -resize 256x256 $SRC_PNG fceux-256x256.png
+
+#sudo cp -f fceux-32x32.png $ICON_PATH/32x32/apps/fceux.png
+#sudo cp -f fceux-48x48.png $ICON_PATH/48x48/apps/fceux.png
+#sudo cp -f fceux-64x64.png $ICON_PATH/64x64/apps/fceux.png
+#sudo cp -f fceux-72x72.png $ICON_PATH/72x72/apps/fceux.png
+#sudo cp -f fceux-96x96.png $ICON_PATH/96x96/apps/fceux.png
+#sudo cp -f fceux-128x128.png $ICON_PATH/128x128/apps/fceux.png
+#sudo cp -f fceux-256x256.png $ICON_PATH/256x256/apps/fceux.png
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 41036c60..7abe867e 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -81,14 +81,16 @@ else(WIN32)
pkg_check_modules( SDL2 REQUIRED sdl2)
if ( ${SDL2_FOUND} )
- add_definitions( ${SDL2_CFLAGS} )
+ add_definitions( ${SDL2_CFLAGS} -D__SDL__ )
endif()
# Check for LUA
- pkg_check_modules( LUA lua-5.1)
+ pkg_search_module( LUA lua5.1 lua-5.1 )
if ( ${LUA_FOUND} )
# Use System LUA
+ message( STATUS "Using System Lua ${LUA_VERSION}" )
+
add_definitions( -D_S9XLUA_H ${LUA_CFLAGS} )
set( LUA_ENGINE_SOURCE ${CMAKE_CURRENT_SOURCE_DIR}/lua-engine.cpp )
@@ -96,6 +98,8 @@ else(WIN32)
else ()
# Use Internal LUA
+ message( STATUS "Using Internal Lua" )
+
add_definitions( -D_S9XLUA_H -I${CMAKE_CURRENT_SOURCE_DIR}/lua/src )
set( LUA_ENGINE_SOURCE
@@ -279,6 +283,7 @@ set(SRC_CORE
${CMAKE_CURRENT_SOURCE_DIR}/boards/BMW8544.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/bonza.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/bs-5.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/boards/bs4xxxr.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/cheapocabra.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/cityfighter.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/coolboy.cpp
@@ -371,6 +376,7 @@ set(SRC_CORE
${CMAKE_CURRENT_SOURCE_DIR}/input/suborkb.cpp
${CMAKE_CURRENT_SOURCE_DIR}/input/toprider.cpp
${CMAKE_CURRENT_SOURCE_DIR}/input/virtualboy.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/input/lcdcompzapper.cpp
${CMAKE_CURRENT_SOURCE_DIR}/input/zapper.cpp
${CMAKE_CURRENT_SOURCE_DIR}/utils/backward.cpp
${CMAKE_CURRENT_SOURCE_DIR}/utils/ConvertUTF.c
@@ -425,22 +431,34 @@ set(SRC_DRIVERS_SDL
${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/ConsoleWindow.cpp
${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/ConsoleViewerGL.cpp
${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/ConsoleViewerSDL.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/InputConf.cpp
${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/GamePadConf.cpp
${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/HotKeyConf.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/TimingConf.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/FrameTimingStats.cpp
${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/PaletteConf.cpp
${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/GuiConf.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/MoviePlay.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/MovieOptions.cpp
${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/LuaControl.cpp
${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/CheatsConf.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/GameGenie.cpp
${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/HexEditor.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/MsgLogViewer.cpp
${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/CodeDataLogger.cpp
${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/SymbolicDebug.cpp
${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/ConsoleDebugger.cpp
${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/ConsoleUtilities.cpp
${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/ConsoleVideoConf.cpp
${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/ConsoleSoundConf.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/iNesHeaderEditor.cpp
${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/TraceLogger.cpp
${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/AboutWindow.cpp
${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/fceuWrapper.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/ppuViewer.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/NameTableViewer.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/RamWatch.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/RamSearch.cpp
${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/config.cpp
${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/input.cpp
${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/nes_shm.cpp
@@ -509,19 +527,24 @@ install( TARGETS ${APP_NAME}
BUNDLE DESTINATION . COMPONENT Runtime
RUNTIME DESTINATION bin COMPONENT Runtime )
-set( APPS ${CMAKE_INSTALL_PREFIX}/${APP_NAME}.app)
-set( DIRS ${CMAKE_BINARY_DIR} /usr/local/lib)
-
-message(STATUS APPS: ${APPS})
-message(STATUS DIRS: ${DIRS} )
+# Use \$ to defer expansion until install script is called; CPack will call it with its own CMAKE_INSTALL_PREFIX
+set(APP \${CMAKE_INSTALL_PREFIX}/${APP_NAME}.app)
set(CPACK_PACKAGE_ICON ${CMAKE_SOURCE_DIR}/fceux.icns )
-set(CPACK_BUNDLE_ICON ${CMAKE_SOURCE_DIR}/fceux.icns )
set(CPACK_GENERATOR "DRAGNDROP")
include(CPACK)
-install( CODE "include(BundleUtilities)
- fixup_bundle( \"${APPS}\" \"\" \"${DIRS}\") "
+# macdeployqt tool that comes with Qt: https://doc.qt.io/qt-5/macos-deployment.html#macdeploy
+# Compared to fixup_bundle, correctly finds and installs Qt-specific resources as well as non-Qt dependencies
+find_program(MACDEPLOYQT macdeployqt)
+if(NOT MACDEPLOYQT)
+ message(FATAL_ERROR "Could not find macdeployqt executable")
+endif()
+
+install( CODE "
+ message(STATUS \"Deploying and fixing up dependencies in app: ${APP}\")
+ execute_process(COMMAND \"${MACDEPLOYQT}\" \"${APP}\" -verbose=1)
+ "
COMPONENT Runtime
)
@@ -532,7 +555,7 @@ install( TARGETS ${APP_NAME}
install( FILES ${CMAKE_CURRENT_SOURCE_DIR}/auxlib.lua DESTINATION share/fceux/luaScripts )
install( DIRECTORY ${CMAKE_SOURCE_DIR}/output/. DESTINATION share/fceux )
-install( FILES ${CMAKE_SOURCE_DIR}/fceux.png DESTINATION share/pixmaps )
+install( FILES ${CMAKE_SOURCE_DIR}/fceux1.png DESTINATION share/pixmaps )
install( FILES ${CMAKE_SOURCE_DIR}/fceux.desktop DESTINATION share/applications )
install( FILES ${CMAKE_SOURCE_DIR}/documentation/fceux.6 DESTINATION share/man/man6 )
install( FILES ${CMAKE_SOURCE_DIR}/documentation/fceux-net-server.6 DESTINATION share/man/man6 )
diff --git a/src/SConscript b/src/SConscript
deleted file mode 100644
index 20011465..00000000
--- a/src/SConscript
+++ /dev/null
@@ -1,42 +0,0 @@
-import glob
-file_list = glob.glob('*.cpp')
-file_list.remove('lua-engine.cpp') # use logic below for this
-
-subdirs = Split("""
-boards
-drivers/common
-fir
-input
-utils
-""")
-#palettes
-
-Import('env')
-Export('env')
-
-if env['LUA']:
- file_list.append('lua-engine.cpp')
- if env['SYSTEM_LUA'] == 0:
- subdirs.append('lua')
-
-if env['CREATE_AVI']:
- subdirs.append('drivers/videolog')
-
-
-
-for dir in subdirs:
- subdir_files = SConscript('%s/SConscript' % dir)
- file_list.append(subdir_files)
-if env['PLATFORM'] == 'win32':
- platform_files = SConscript('drivers/win/SConscript')
-else:
- platform_files = SConscript('drivers/sdl/SConscript')
-file_list.append(platform_files)
-
-print(env['LINKFLAGS'])
-
-if env['PLATFORM'] == 'win32':
- fceux = env.Program('fceux.exe', file_list)
-else:
- fceux = env.Program('fceux', file_list)
-Return('fceux')
diff --git a/src/attic/pc/dface.h b/src/attic/pc/dface.h
index 9981bd08..55fe169a 100644
--- a/src/attic/pc/dface.h
+++ b/src/attic/pc/dface.h
@@ -44,7 +44,7 @@ void LockConsole(void);
void UnlockConsole(void);
void ToggleFS(); /* SDL */
-int LoadGame(const char *path);
+int LoadGame(const char *path, bool silent = false);
int CloseGame(void);
int GUI_Init(int argc, char **argv, int (*dofunc)(void));
int GUI_Idle(void);
diff --git a/src/attic/pc/main.c b/src/attic/pc/main.c
index 6bdd7ce7..1e4bef03 100644
--- a/src/attic/pc/main.c
+++ b/src/attic/pc/main.c
@@ -275,12 +275,12 @@ static void DoArgs(int argc, char *argv[])
provides data necessary for the driver code(number of scanlines to
render, what virtual input devices to use, etc.).
*/
-int LoadGame(const char *path)
+int LoadGame(const char *path, bool silent)
{
FCEUGI *tmp;
CloseGame();
- if(!(tmp=FCEUI_LoadGame(path,1)))
+ if(!(tmp=FCEUI_LoadGame(path,1,silent)))
return 0;
CurGame=tmp;
ParseGI(tmp);
diff --git a/src/boards/SConscript b/src/boards/SConscript
deleted file mode 100644
index f9afb2d5..00000000
--- a/src/boards/SConscript
+++ /dev/null
@@ -1,6 +0,0 @@
-import glob
-source_list = glob.glob('*.cpp')+glob.glob('*.c')
-
-for x in range(len(source_list)):
- source_list[x] = 'boards/' + source_list[x]
-Return('source_list')
diff --git a/src/boards/bs4xxxr.cpp b/src/boards/bs4xxxr.cpp
new file mode 100644
index 00000000..90f6d1a9
--- /dev/null
+++ b/src/boards/bs4xxxr.cpp
@@ -0,0 +1,164 @@
+/* FCE Ultra - NES/Famicom Emulator
+ *
+ * Copyright notice for this file:
+ * Copyright (C) 2020 CaH4e3
+ *
+ * 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
+ *
+ * Double Dragon 310000-in-1 (4040R)
+ * 700000-in-1 (BS-400R)(Unl)
+ */
+
+#include "mapinc.h"
+#include "mmc3.h"
+
+static uint8 pointer;
+static uint8 offset;
+static uint8 *WRAM = NULL;
+static uint32 WRAMSIZE;
+
+static int getPRGBankBS4XXXR(int bank)
+{
+ if (((~bank) & 1) && (pointer & 0x40))
+ bank ^= 2;
+ return (bank & 2) ? (0xFE | (bank & 1)) : EXPREGS[4 | (bank & 1)];
+}
+
+static void BS4XXXRPW(uint32 A, uint8 V) {
+
+ if ((EXPREGS[3] >> 4) & 0x01)
+ {
+ int AND = ((EXPREGS[0] >> 1) & 1) ? 0x0F : 0x0F;
+ int OR = (EXPREGS[0] & 7) << 4;
+ int bank0 = getPRGBankBS4XXXR(0);
+ int bank1 = getPRGBankBS4XXXR(1);
+ if (!((EXPREGS[3] >> 1) & 1)) //16K Mode
+ {
+ setprg8(0x8000, ((bank0) & AND) | OR);
+ setprg8(0xA000, ((bank1) & AND) | OR);
+ setprg8(0xC000, ((bank0) & AND) | OR);
+ setprg8(0xE000, ((bank1) & AND) | OR);
+ }
+ else // 32K Mode
+ {
+ setprg8(0x8000, ((bank0) & AND) | OR);
+ setprg8(0xA000, ((bank1) & AND) | OR);
+ setprg8(0xC000, ((bank0 | 2) & AND) | OR);
+ setprg8(0xE000, ((bank1 | 2) & AND) | OR);
+ }
+ }
+ else // MMC3 Mode
+ {
+ int prgAND = ((EXPREGS[0] >> offset) & 1) ? 0x0F : 0x1F;
+ int prgOR = (EXPREGS[0] & 7) << 4;
+ setprg8(A, (V & prgAND) | (prgOR));
+ }
+ setprg8r(0x10, 0x6000, 0);
+}
+
+static void BS4XXXRCW(uint32 A, uint8 V) {
+ if ((EXPREGS[3] >> 4) & 1)
+ {
+ int AND = ((EXPREGS[0] >> 1) & 1) ? 0x0F : 0x0F;
+ int bank = EXPREGS[2] & AND;
+ int chrOR = ((EXPREGS[0] >> 3) & 7) << 4;
+ setchr8((bank) | (chrOR));
+ }
+ else
+ {
+ int chrAND = ((EXPREGS[0] >> 1) & 1) ? 0xFF : 0xFF;
+ int chrOR = ((EXPREGS[0] >> 3) & 7) << 7;
+ setchr1(A, (V & chrAND) | (chrOR));
+ }
+}
+
+static DECLFW(BS4XXXRHiWrite) {
+// FCEU_printf("w: %04x-%02x\n",A,V)
+ if (A==0x8000)
+ {
+ pointer = MMC3_cmd ^ V;
+ }
+ else if (A == 0x8001)
+ {
+ if((MMC3_cmd & 7) > 5)
+ EXPREGS[4|(MMC3_cmd & 1)] = V;
+ }
+ MMC3_CMDWrite(A, V);
+}
+
+static DECLFW(BS4XXXRLoWrite) {
+// FCEU_printf("w: %04x-%02x\n", A, V);
+ if (A & 0x800)
+ {
+ if (!(EXPREGS[3] & 0x80)) {
+ EXPREGS[A & 0x03] = V;
+ FixMMC3PRG(MMC3_cmd);
+ FixMMC3CHR(MMC3_cmd);
+ }
+ else if (EXPREGS[3] & 0x10)
+ {
+ EXPREGS[A & 0x03] = V;
+ FixMMC3PRG(MMC3_cmd);
+ FixMMC3CHR(MMC3_cmd);
+ }
+ else
+ WRAM[A - 0x6000] = V;
+ }
+ else
+ WRAM[A - 0x6000] = V;
+}
+
+
+static void BSXXXXRPower(void) {
+ EXPREGS[0] = EXPREGS[1] = EXPREGS[2] = EXPREGS[3] = EXPREGS[4] = EXPREGS[5] = 0;
+ GenMMC3Power();
+ SetReadHandler(0x6000, 0x7FFF, CartBR);
+ SetWriteHandler(0x6000, 0x7FFF, BS4XXXRLoWrite);
+ SetWriteHandler(0x8000, 0x9FFF, BS4XXXRHiWrite);
+ FixMMC3PRG(MMC3_cmd);
+ FixMMC3CHR(MMC3_cmd);
+}
+
+static void BS4XXXRClose(void) {
+ if (WRAM)
+ FCEU_gfree(WRAM);
+ WRAM = NULL;
+}
+
+void BSXXXXR_Init(CartInfo *info) {
+ GenMMC3_Init(info, 512, 256, 8, 0);
+ cwrap = BS4XXXRCW;
+ pwrap = BS4XXXRPW;
+
+ info->Power = BSXXXXRPower;
+ info->Close = BS4XXXRClose;
+
+ WRAMSIZE = 8192;
+ WRAM = (uint8*)FCEU_gmalloc(WRAMSIZE);
+ SetupCartPRGMapping(0x10, WRAM, WRAMSIZE, 1);
+ AddExState(WRAM, WRAMSIZE, 0, "WRAM");
+
+ AddExState(EXPREGS, 8, 0, "EXPR");
+}
+
+void BS400R_Init(CartInfo *info) {
+ offset = 1;
+ BSXXXXR_Init(info);
+}
+
+void BS4040R_Init(CartInfo *info) {
+ offset = 6;
+ BSXXXXR_Init(info);
+}
diff --git a/src/boards/mmc5.cpp b/src/boards/mmc5.cpp
index 6fa9a243..0099e409 100644
--- a/src/boards/mmc5.cpp
+++ b/src/boards/mmc5.cpp
@@ -22,6 +22,8 @@
#include "mapinc.h"
+#include
+
#define ABANKS MMC5SPRVPage
#define BBANKS MMC5BGVPage
#define SpriteON (PPU[1] & 0x10) //Show Sprite
@@ -81,10 +83,11 @@ static INLINE void MMC5BGVROM_BANK8(uint32 V) {
}
}
-static uint8 PRGBanks[4];
+static std::array PRGBanks;
static uint8 WRAMPage;
-static uint16 CHRBanksA[8], CHRBanksB[4];
-static uint8 WRAMMaskEnable[2];
+static std::array CHRBanksA;
+static std::array CHRBanksB;
+static std::array WRAMMaskEnable;
uint8 mmc5ABMode; /* A=0, B=1 */
static uint8 IRQScanline, IRQEnable;
@@ -93,7 +96,7 @@ static uint8 CHRMode, NTAMirroring, NTFill, ATFill;
static uint8 MMC5IRQR;
static uint8 MMC5LineCounter;
static uint8 mmc5psize, mmc5vsize;
-static uint8 mul[2];
+static std::array mul;
static uint32 WRAMSIZE = 0;
static uint8 *WRAM = NULL;
@@ -104,8 +107,8 @@ const int MMC5WRAMMAX = 1<<7; // 7 bits in register interface (real MMC5 has onl
static uint8 MMC5WRAMsize; //configuration, not state
static uint8 MMC5WRAMIndex[MMC5WRAMMAX]; //configuration, not state
-static uint8 MMC5ROMWrProtect[4];
-static uint8 MMC5MemIn[5];
+static std::array MMC5ROMWrProtect;
+static std::array MMC5MemIn;
static void MMC5CHRA(void);
static void MMC5CHRB(void);
@@ -895,18 +898,35 @@ void NSFMMC5_Close(void) {
ExRAM = NULL;
}
-static void GenMMC5Reset(void) {
- int x;
+static void GenMMC5Power(void) {
- for (x = 0; x < 4; x++) PRGBanks[x] = ~0;
- for (x = 0; x < 8; x++) CHRBanksA[x] = ~0;
- for (x = 0; x < 4; x++) CHRBanksB[x] = ~0;
- WRAMMaskEnable[0] = WRAMMaskEnable[1] = ~0;
-
- mmc5psize = mmc5vsize = 3;
+ PRGBanks.fill(0xFF);
+ WRAMPage = 0;
+ CHRBanksA.fill(0xFF);
+ CHRBanksB.fill(0xFF);
+ WRAMMaskEnable.fill(0xFF);
+ mmc5ABMode = 0;
+ IRQScanline = 0;
+ IRQEnable = 0;
CHRMode = 0;
-
NTAMirroring = NTFill = ATFill = 0xFF;
+ MMC5IRQR = 0;
+ MMC5LineCounter = 0;
+ mmc5psize = mmc5vsize = 3;
+ mul.fill(0);
+
+ MMC5ROMWrProtect.fill(0);
+ MMC5MemIn.fill(0);
+
+ // MMC5fill is and 8-bit tile index, and a 2-bit attribute implented as a mirrored nametable
+ u8 nval = MMC5fill[0x000];
+ u8 aval = MMC5fill[0x3C0] & 3; aval = aval | (aval << 2) | (aval << 4) | (aval << 6);
+ FCEU_dwmemset(MMC5fill + 0x000, nval | (nval<<8) | (nval<<16) | (nval<<24), 0x3C0);
+ FCEU_dwmemset(MMC5fill + 0x3C0, aval | (aval<<8) | (aval<<16) | (aval<<24), 0x040);
+
+ FCEU_MemoryRand(WRAM, MMC5WRAMsize * 8 * 1024);
+ FCEU_MemoryRand(MMC5fill,1024);
+ FCEU_MemoryRand(ExRAM,1024);
MMC5Synco();
@@ -929,11 +949,11 @@ static void GenMMC5Reset(void) {
}
static SFORMAT MMC5_StateRegs[] = {
- { PRGBanks, 4, "PRGB" },
- { CHRBanksA, 16, "CHRA" },
- { CHRBanksB, 8, "CHRB" },
+ { &PRGBanks, 4, "PRGB" },
+ { &CHRBanksA, 16, "CHRA" },
+ { &CHRBanksB, 8, "CHRB" },
{ &WRAMPage, 1, "WRMP" },
- { WRAMMaskEnable, 2, "WRME" },
+ { &WRAMMaskEnable, 2, "WRME" },
{ &mmc5ABMode, 1, "ABMD" },
{ &IRQScanline, 1, "IRQS" },
{ &IRQEnable, 1, "IRQE" },
@@ -947,9 +967,9 @@ static SFORMAT MMC5_StateRegs[] = {
{ &MMC5LineCounter, 1, "LCTR" },
{ &mmc5psize, 1, "PSIZ" },
{ &mmc5vsize, 1, "VSIZ" },
- { mul, 2, "MUL2" },
- { MMC5ROMWrProtect, 4, "WRPR" },
- { MMC5MemIn, 5, "MEMI" },
+ { &mul, 2, "MUL2" },
+ { &MMC5ROMWrProtect, 4, "WRPR" },
+ { &MMC5MemIn, 5, "MEMI" },
{ &MMC5Sound.wl[0], 2 | FCEUSTATE_RLSB, "SDW0" },
{ &MMC5Sound.wl[1], 2 | FCEUSTATE_RLSB, "SDW1" },
@@ -972,19 +992,14 @@ static SFORMAT MMC5_StateRegs[] = {
static void GenMMC5_Init(CartInfo *info, int wsize, int battery) {
if (wsize) {
- WRAM = (uint8*)FCEU_gmalloc(wsize * 1024);
+ WRAM = (uint8*)FCEU_malloc(wsize * 1024);
SetupCartPRGMapping(0x10, WRAM, wsize * 1024, 1);
AddExState(WRAM, wsize * 1024, 0, "WRAM");
}
- MMC5fill = (uint8*)FCEU_gmalloc(1024);
- ExRAM = (uint8*)FCEU_gmalloc(1024);
+ MMC5fill = (uint8*)FCEU_malloc(1024);
+ ExRAM = (uint8*)FCEU_malloc(1024);
- // MMC5fill is and 8-bit tile index, and a 2-bit attribute implented as a mirrored nametable
- u8 nval = MMC5fill[0x000];
- u8 aval = MMC5fill[0x3C0] & 3; aval = aval | (aval << 2) | (aval << 4) | (aval << 6);
- FCEU_dwmemset(MMC5fill + 0x000, nval | (nval<<8) | (nval<<16) | (nval<<24), 0x3C0);
- FCEU_dwmemset(MMC5fill + 0x3C0, aval | (aval<<8) | (aval<<16) | (aval<<24), 0x040);
AddExState(ExRAM, 1024, 0, "ERAM");
AddExState(&MMC5HackSPMode, 1, 0, "SPLM");
@@ -996,7 +1011,7 @@ static void GenMMC5_Init(CartInfo *info, int wsize, int battery) {
MMC5WRAMsize = wsize / 8;
BuildWRAMSizeTable();
GameStateRestore = MMC5_StateRestore;
- info->Power = GenMMC5Reset;
+ info->Power = GenMMC5Power;
if (battery) {
info->SaveGame[0] = WRAM;
diff --git a/src/cheat.cpp b/src/cheat.cpp
index e2b2ad9b..8eb2ebfd 100644
--- a/src/cheat.cpp
+++ b/src/cheat.cpp
@@ -902,31 +902,31 @@ int FCEU_DisableAllCheats(){
return count;
}
-inline int FCEUI_FindCheatMapByte(uint16 address)
+int FCEUI_FindCheatMapByte(uint16 address)
{
return cheatMap[address / 8] >> (address % 8) & 1;
}
-inline void FCEUI_SetCheatMapByte(uint16 address, bool cheat)
+void FCEUI_SetCheatMapByte(uint16 address, bool cheat)
{
cheat ? cheatMap[address / 8] |= (1 << address % 8) : cheatMap[address / 8] ^= (1 << address % 8);
}
-inline void FCEUI_CreateCheatMap()
+void FCEUI_CreateCheatMap(void)
{
if (!cheatMap)
cheatMap = (unsigned char*)malloc(CHEATMAP_SIZE);
FCEUI_RefreshCheatMap();
}
-inline void FCEUI_RefreshCheatMap()
+void FCEUI_RefreshCheatMap(void)
{
memset(cheatMap, 0, CHEATMAP_SIZE);
for (uint32 i = 0; i < numsubcheats; ++i)
FCEUI_SetCheatMapByte(SubCheats[i].addr, true);
}
-inline void FCEUI_ReleaseCheatMap()
+void FCEUI_ReleaseCheatMap(void)
{
if (cheatMap)
{
diff --git a/src/cheat.h b/src/cheat.h
index 9f3dbe2b..dd9ca0ce 100644
--- a/src/cheat.h
+++ b/src/cheat.h
@@ -18,9 +18,10 @@ typedef unsigned char _8BYTECHEATMAP;
extern int FCEUI_FindCheatMapByte(uint16 address);
extern void FCEUI_SetCheatMapByte(uint16 address, bool cheat);
-extern void FCEUI_CreateCheatMap();
-extern void FCEUI_RefreshCheatMap();
-extern void FCEUI_ReleaseCheatMap();
+extern void FCEUI_CreateCheatMap(void);
+extern void FCEUI_RefreshCheatMap(void);
+extern void FCEUI_ReleaseCheatMap(void);
+extern unsigned int FrozenAddressCount;
int FCEU_CheatGetByte(uint32 A);
void FCEU_CheatSetByte(uint32 A, uint8 V);
diff --git a/src/config.cpp b/src/config.cpp
index f998a749..fcb3a515 100644
--- a/src/config.cpp
+++ b/src/config.cpp
@@ -18,10 +18,10 @@ char *FCEUI_GetAboutString() {
const char *aboutTemplate =
FCEU_NAME_AND_VERSION "\n\n"
"Administrators:\n"
- "zeromus, punkrockguy318 (Lukas Sabota), feos\n"
+ "zeromus, mjbudd77, feos\n"
"\n"
"Current Contributors:\n"
- "CaH4e3, rainwarrior\n"
+ "CaH4e3, rainwarrior, owomomo, punkrockguy318\n"
"\n"
"Past Contributors:\n"
"xhainingx, gocha, AnS\n"
diff --git a/src/drivers/Qt/AboutWindow.cpp b/src/drivers/Qt/AboutWindow.cpp
index b79f0315..aab61613 100644
--- a/src/drivers/Qt/AboutWindow.cpp
+++ b/src/drivers/Qt/AboutWindow.cpp
@@ -9,7 +9,6 @@
#include
#include
#include
-//#include "Qt/icon.xpm"
#include "Qt/AboutWindow.h"
#include "Qt/fceux_git_info.h"
#include "../../version.h"
@@ -41,7 +40,6 @@ AboutWindow::AboutWindow(QWidget *parent)
int i;
QVBoxLayout *mainLayout;
QHBoxLayout *hbox1;
- //QPixmap pm( icon_xpm );
QPixmap pm(":fceux1.png");
QPixmap pm2;
QLabel *lbl;
@@ -121,7 +119,7 @@ AboutWindow::AboutWindow(QWidget *parent)
mainLayout->addLayout( hbox1 );
hbox1 = new QHBoxLayout();
- lbl = new QLabel( tr("© 2016 FceuX Development Team") );
+ lbl = new QLabel( tr("© 2020 FceuX Development Team") );
hbox1->addWidget( lbl );
hbox1->setAlignment( Qt::AlignCenter );
diff --git a/src/drivers/Qt/CheatsConf.cpp b/src/drivers/Qt/CheatsConf.cpp
index 18af6258..83fb1b3d 100644
--- a/src/drivers/Qt/CheatsConf.cpp
+++ b/src/drivers/Qt/CheatsConf.cpp
@@ -27,8 +27,28 @@
static GuiCheatsDialog_t *win = NULL;
//----------------------------------------------------------------------------
+void openCheatDialog(QWidget *parent)
+{
+ if ( win != NULL )
+ {
+ return;
+ }
+ win = new GuiCheatsDialog_t(parent);
+
+ win->show();
+}
+//----------------------------------------------------------------------------
+void updateCheatDialog(void)
+{
+ if ( win == NULL )
+ {
+ return;
+ }
+ win->showActiveCheatList( true );
+}
+//----------------------------------------------------------------------------
GuiCheatsDialog_t::GuiCheatsDialog_t(QWidget *parent)
- : QDialog( parent )
+ : QDialog( parent, Qt::Window )
{
QHBoxLayout *mainLayout, *hbox, *hbox1;
QVBoxLayout *vbox, *vbox1, *vbox2, *vbox3;
@@ -36,14 +56,6 @@ GuiCheatsDialog_t::GuiCheatsDialog_t(QWidget *parent)
QLabel *lbl;
QGroupBox *groupBox;
QFrame *frame;
- QScreen *screen = QGuiApplication::primaryScreen();
- double devPixRatio = 1.0f;
-
- if ( screen != NULL )
- {
- devPixRatio = (int)( screen->devicePixelRatio() + 0.50f);
- //printf("Pix Ratio: %f \n", devPixRatio );
- }
font.setFamily("Courier New");
font.setStyle( QFont::StyleNormal );
@@ -51,8 +63,11 @@ GuiCheatsDialog_t::GuiCheatsDialog_t(QWidget *parent)
QFontMetrics fm(font);
- //fontCharWidth = fm.boundingRect('X').width() * devPixRatio;
- fontCharWidth = 2.00 * fm.averageCharWidth() * devPixRatio;
+#if QT_VERSION > QT_VERSION_CHECK(5, 11, 0)
+ fontCharWidth = 2 * fm.horizontalAdvance(QLatin1Char('2'));
+#else
+ fontCharWidth = 2 * fm.width(QLatin1Char('2'));
+#endif
setWindowTitle("Cheat Search");
@@ -417,6 +432,7 @@ GuiCheatsDialog_t::~GuiCheatsDialog_t(void)
}
wasPausedByCheats = false;
+ win = NULL;
printf("Destroy Cheat Window Event\n");
}
//----------------------------------------------------------------------------
@@ -618,7 +634,7 @@ int GuiCheatsDialog_t::activeCheatListCB (char *name, uint32 a, uint8 v, int c,
if (c >= 0)
{
- sprintf (codeStr, "$%04X:%02X:%02X", a,v,c);
+ sprintf (codeStr, "$%04X?%02X:%02X", a,c,v);
}
else
{
@@ -644,6 +660,7 @@ int GuiCheatsDialog_t::activeCheatListCB (char *name, uint32 a, uint8 v, int c,
item->setTextAlignment( 0, Qt::AlignLeft);
item->setTextAlignment( 1, Qt::AlignLeft);
+ item->setTextAlignment( 2, Qt::AlignLeft);
actvCheatIdx++;
@@ -684,7 +701,7 @@ void GuiCheatsDialog_t::openCheatFile(void)
dialog.setNameFilter(tr("Cheat files (*.cht *.CHT) ;; All files (*)"));
dialog.setViewMode(QFileDialog::List);
- dialog.setFilter( QDir::AllEntries | QDir::Hidden );
+ dialog.setFilter( QDir::AllEntries | QDir::AllDirs | QDir::Hidden );
dialog.setLabelText( QFileDialog::Accept, tr("Open") );
g_config->getOption ("SDL.LastOpenFile", &last );
@@ -749,7 +766,7 @@ void GuiCheatsDialog_t::saveCheatFile(void)
dialog.setNameFilter(tr("Cheat files (*.cht *.CHT) ;; All files (*)"));
dialog.setViewMode(QFileDialog::List);
- dialog.setFilter( QDir::AllEntries | QDir::Hidden );
+ dialog.setFilter( QDir::AllEntries | QDir::AllDirs | QDir::Hidden );
dialog.setLabelText( QFileDialog::Accept, tr("Save") );
if ( GameInfo )
diff --git a/src/drivers/Qt/CheatsConf.h b/src/drivers/Qt/CheatsConf.h
index fbc46a24..9b86631b 100644
--- a/src/drivers/Qt/CheatsConf.h
+++ b/src/drivers/Qt/CheatsConf.h
@@ -32,6 +32,8 @@ class GuiCheatsDialog_t : public QDialog
int activeCheatListCB (char *name, uint32 a, uint8 v, int c, int s, int type, void *data);
+ void showActiveCheatList(bool redraw);
+
protected:
void closeEvent(QCloseEvent *event);
@@ -75,7 +77,6 @@ class GuiCheatsDialog_t : public QDialog
private:
void showCheatSearchResults(void);
- void showActiveCheatList(bool redraw);
public slots:
void closeWindow(void);
@@ -97,3 +98,7 @@ class GuiCheatsDialog_t : public QDialog
void actvCheatItemClicked( QTreeWidgetItem *item, int column);
};
+
+void openCheatDialog(QWidget *parent);
+
+void updateCheatDialog(void);
diff --git a/src/drivers/Qt/CodeDataLogger.cpp b/src/drivers/Qt/CodeDataLogger.cpp
index 3f209fb4..61179e27 100644
--- a/src/drivers/Qt/CodeDataLogger.cpp
+++ b/src/drivers/Qt/CodeDataLogger.cpp
@@ -30,7 +30,7 @@ static char loadedcdfile[512] = {0};
static int getDefaultCDLFile( char *filepath );
//----------------------------------------------------
CodeDataLoggerDialog_t::CodeDataLoggerDialog_t(QWidget *parent)
- : QDialog( parent )
+ : QDialog( parent, Qt::Window )
{
QVBoxLayout *mainLayout, *vbox1, *vbox;
QHBoxLayout *hbox;
@@ -324,7 +324,7 @@ void CodeDataLoggerDialog_t::saveCdlFileAs(void)
dialog.setNameFilter(tr("CDL Files (*.cdl *.CDL) ;; All files (*)"));
dialog.setViewMode(QFileDialog::List);
- dialog.setFilter( QDir::AllEntries | QDir::Hidden );
+ dialog.setFilter( QDir::AllEntries | QDir::AllDirs | QDir::Hidden );
dialog.setLabelText( QFileDialog::Accept, tr("Save") );
dialog.setDefaultSuffix( tr(".cdl") );
@@ -387,7 +387,7 @@ void CodeDataLoggerDialog_t::loadCdlFile(void)
dialog.setNameFilter(tr("CDL files (*.cdl *.CDL) ;; All files (*)"));
dialog.setViewMode(QFileDialog::List);
- dialog.setFilter( QDir::AllEntries | QDir::Hidden );
+ dialog.setFilter( QDir::AllEntries | QDir::AllDirs | QDir::Hidden );
dialog.setLabelText( QFileDialog::Accept, tr("Load") );
romFile = getRomFile();
@@ -470,7 +470,7 @@ void CodeDataLoggerDialog_t::SaveStrippedROM(int invert)
dialog.setDefaultSuffix( tr(".nes") );
}
dialog.setViewMode(QFileDialog::List);
- dialog.setFilter( QDir::AllEntries | QDir::Hidden );
+ dialog.setFilter( QDir::AllEntries | QDir::AllDirs | QDir::Hidden );
dialog.setLabelText( QFileDialog::Accept, tr("Save") );
romFile = getRomFile();
@@ -623,7 +623,14 @@ static int getDefaultCDLFile( char *filepath )
parseFilepath( romFile, dir, baseFile );
- sprintf( filepath, "%s/%s.cdl", dir, baseFile );
+ if ( dir[0] == 0 )
+ {
+ sprintf( filepath, "%s.cdl", baseFile );
+ }
+ else
+ {
+ sprintf( filepath, "%s/%s.cdl", dir, baseFile );
+ }
//printf("%s\n", filepath );
@@ -785,6 +792,8 @@ void CDLoggerROMChanged(void)
ResetCDLog();
RenameCDLog("");
+ g_config->getOption("SDL.AutoResumeCDL", &autoResumeCDL);
+
if (!autoResumeCDL)
return;
@@ -827,7 +836,7 @@ void SaveCDLogFile(void)
FP = fopen(loadedcdfile, "wb");
if (FP == NULL)
{
- FCEUD_PrintError("Error Saving File");
+ FCEUD_PrintError("Error Saving CDL File");
return;
}
fwrite(cdloggerdata, cdloggerdataSize, 1, FP);
diff --git a/src/drivers/Qt/ConsoleDebugger.cpp b/src/drivers/Qt/ConsoleDebugger.cpp
index 9462f4bf..8489c40f 100644
--- a/src/drivers/Qt/ConsoleDebugger.cpp
+++ b/src/drivers/Qt/ConsoleDebugger.cpp
@@ -15,6 +15,10 @@
#include
#include
#include
+#include
+#include
+#include
+#include
#include "../../types.h"
#include "../../fceu.h"
@@ -50,9 +54,11 @@ debuggerBookmarkManager_t dbgBmMgr;
static std::list dbgWinList;
static void DeleteBreak(int sel);
+static bool waitingAtBp = false;
+static int lastBpIdx = 0;
//----------------------------------------------------------------------------
ConsoleDebugger::ConsoleDebugger(QWidget *parent)
- : QDialog( parent )
+ : QDialog( parent, Qt::Window )
{
QHBoxLayout *mainLayout;
QVBoxLayout *vbox, *vbox1, *vbox2, *vbox3, *vbox4;
@@ -61,9 +67,14 @@ ConsoleDebugger::ConsoleDebugger(QWidget *parent)
QPushButton *button;
QFrame *frame;
QLabel *lbl;
+ QMenuBar *menuBar;
+ QMenu *debugMenu, *optMenu, *subMenu;
+ QActionGroup *actGroup;
+ QAction *act;
float fontCharWidth;
QTreeWidgetItem * item;
- int opt;
+ int opt, useNativeMenuBar;
+ fceuDecIntValidtor *validator;
font.setFamily("Courier New");
font.setStyle( QFont::StyleNormal );
@@ -75,9 +86,148 @@ ConsoleDebugger::ConsoleDebugger(QWidget *parent)
setWindowTitle("6502 Debugger");
//resize( 512, 512 );
+
+ menuBar = new QMenuBar(this);
+ // This is needed for menu bar to show up on MacOS
+ g_config->getOption( "SDL.UseNativeMenuBar", &useNativeMenuBar );
+
+ menuBar->setNativeMenuBar( useNativeMenuBar ? true : false );
+
+ //-----------------------------------------------------------------------
+ // Menu Start
+ //-----------------------------------------------------------------------
+ // Debug
+ debugMenu = menuBar->addMenu(tr("Debug"));
+
+ // Debug -> Run
+ act = new QAction(tr("Run"), this);
+ act->setShortcut(QKeySequence( tr("F5") ) );
+ act->setStatusTip(tr("Run"));
+ connect( act, SIGNAL(triggered()), this, SLOT(debugRunCB(void)) );
+
+ debugMenu->addAction(act);
+
+ // Debug -> Step Into
+ act = new QAction(tr("Step Into"), this);
+ act->setShortcut(QKeySequence( tr("F11") ) );
+ act->setStatusTip(tr("Step Into"));
+ connect( act, SIGNAL(triggered()), this, SLOT(debugStepIntoCB(void)) );
+
+ debugMenu->addAction(act);
+
+ // Debug -> Step Out
+ act = new QAction(tr("Step Out"), this);
+ act->setShortcut(QKeySequence( tr("Shift+F11") ) );
+ act->setStatusTip(tr("Step Out"));
+ connect( act, SIGNAL(triggered()), this, SLOT(debugStepOutCB(void)) );
+
+ debugMenu->addAction(act);
+
+ // Debug -> Step Over
+ act = new QAction(tr("Step Over"), this);
+ act->setShortcut(QKeySequence( tr("F10") ) );
+ act->setStatusTip(tr("Step Over"));
+ connect( act, SIGNAL(triggered()), this, SLOT(debugStepOverCB(void)) );
+
+ debugMenu->addAction(act);
+
+ // Debug -> Run to Selected Line
+ act = new QAction(tr("Run to Selected Line"), this);
+ act->setShortcut(QKeySequence( tr("F1") ) );
+ act->setStatusTip(tr("Run to Selected Line"));
+ connect( act, SIGNAL(triggered()), this, SLOT(debugRunToCursorCB(void)) );
+
+ debugMenu->addAction(act);
+
+ // Debug -> Run Line
+ act = new QAction(tr("Run Line"), this);
+ act->setShortcut(QKeySequence( tr("F6") ) );
+ act->setStatusTip(tr("Run Line"));
+ connect( act, SIGNAL(triggered()), this, SLOT(debugRunLineCB(void)) );
+
+ debugMenu->addAction(act);
+
+ // Debug -> Run 128 Lines
+ act = new QAction(tr("Run 128 Lines"), this);
+ act->setShortcut(QKeySequence( tr("F7") ) );
+ act->setStatusTip(tr("Run 128 Lines"));
+ connect( act, SIGNAL(triggered()), this, SLOT(debugRunLine128CB(void)) );
+
+ debugMenu->addAction(act);
+
+ // Options
+ optMenu = menuBar->addMenu(tr("Options"));
+
+ // Options -> PC Position
+ subMenu = optMenu->addMenu(tr("PC Line Positioning"));
+ actGroup = new QActionGroup(this);
+
+ actGroup->setExclusive(true);
+
+ g_config->getOption( "SDL.DebuggerPCPlacement", &opt );
+
+ // Options -> PC Position -> Top Line
+ act = new QAction(tr("Top Line"), this);
+ act->setStatusTip(tr("Top Line"));
+ act->setCheckable(true);
+ act->setChecked( opt == 0 );
+ connect( act, SIGNAL(triggered()), this, SLOT(pcSetPlaceTop(void)) );
+ actGroup->addAction(act);
+ subMenu->addAction(act);
+
+ // Options -> PC Position -> Upper Mid-Line
+ act = new QAction(tr("Upper Mid-Line"), this);
+ act->setStatusTip(tr("Upper Mid-Line"));
+ act->setCheckable(true);
+ act->setChecked( opt == 1 );
+ connect( act, SIGNAL(triggered()), this, SLOT(pcSetPlaceUpperMid(void)) );
+ actGroup->addAction(act);
+ subMenu->addAction(act);
+
+ // Options -> PC Position -> Center Line
+ act = new QAction(tr("Center Line"), this);
+ act->setStatusTip(tr("Center Line"));
+ act->setCheckable(true);
+ act->setChecked( opt == 2 );
+ connect( act, SIGNAL(triggered()), this, SLOT(pcSetPlaceCenter(void)) );
+ actGroup->addAction(act);
+ subMenu->addAction(act);
+
+ // Options -> PC Position -> Lower Mid-Line
+ act = new QAction(tr("Lower Mid-Line"), this);
+ act->setStatusTip(tr("Lower Mid-Line"));
+ act->setCheckable(true);
+ act->setChecked( opt == 3 );
+ connect( act, SIGNAL(triggered()), this, SLOT(pcSetPlaceLowerMid(void)) );
+ actGroup->addAction(act);
+ subMenu->addAction(act);
+
+ // Options -> PC Position -> Bottom
+ act = new QAction(tr("Bottom Line"), this);
+ act->setStatusTip(tr("Bottom Line"));
+ act->setCheckable(true);
+ act->setChecked( opt == 4 );
+ connect( act, SIGNAL(triggered()), this, SLOT(pcSetPlaceBottom(void)) );
+ actGroup->addAction(act);
+ subMenu->addAction(act);
+
+ // Options -> PC Position -> Custom Line
+ act = new QAction(tr("Custom Line Offset"), this);
+ act->setStatusTip(tr("Custom Line Offset"));
+ act->setChecked( opt == 5 );
+ act->setCheckable(true);
+ connect( act, SIGNAL(triggered()), this, SLOT(pcSetPlaceCustom(void)) );
+ actGroup->addAction(act);
+ subMenu->addAction(act);
+
+ //-----------------------------------------------------------------------
+ // Menu End
+ //-----------------------------------------------------------------------
mainLayout = new QHBoxLayout();
+ mainLayout->setMenuBar( menuBar );
+
vbox4 = new QVBoxLayout();
grid = new QGridLayout();
asmView = new QAsmView(this);
@@ -86,6 +236,8 @@ ConsoleDebugger::ConsoleDebugger(QWidget *parent)
asmLineSelLbl = new QLabel( tr("Line Select") );
emuStatLbl = new QLabel( tr("Emulator is Running") );
+ asmLineSelLbl->setWordWrap( true );
+
asmView->setScrollBars( hbar, vbar );
grid->addWidget( asmView, 0, 0 );
@@ -203,15 +355,15 @@ ConsoleDebugger::ConsoleDebugger(QWidget *parent)
vbox2->addLayout( hbox );
stackFrame = new QGroupBox(tr("Stack $0100"));
- stackText = new QPlainTextEdit(this);
+ stackText = new DebuggerStackDisplay(this);
hbox = new QHBoxLayout();
hbox->addWidget( stackText );
vbox2->addWidget( stackFrame );
stackFrame->setLayout( hbox );
stackText->setFont(font);
stackText->setReadOnly(true);
- stackText->setWordWrapMode( QTextOption::WordWrap );
- stackText->setHorizontalScrollBarPolicy( Qt::ScrollBarAlwaysOff );
+ stackText->setWordWrapMode( QTextOption::NoWrap );
+ //stackText->setHorizontalScrollBarPolicy( Qt::ScrollBarAlwaysOff );
//stackText->setMaximumWidth( 16 * fontCharWidth );
bpFrame = new QGroupBox(tr("Breakpoints"));
@@ -338,18 +490,22 @@ ConsoleDebugger::ConsoleDebugger(QWidget *parent)
hbox->addWidget( instrExdVal, 1, Qt::AlignLeft );
hbox2->addLayout( vbox );
+ validator = new fceuDecIntValidtor( 0, 0x3FFFFFFF, this );
cpuCycExdVal->setFont( font );
cpuCycExdVal->setMaxLength( 16 );
- cpuCycExdVal->setInputMask( ">9000000000000000;" );
+ cpuCycExdVal->setValidator( validator );
cpuCycExdVal->setAlignment(Qt::AlignLeft);
cpuCycExdVal->setMaximumWidth( 18 * fontCharWidth );
+ cpuCycExdVal->setCursorPosition(0);
connect( cpuCycExdVal, SIGNAL(textEdited(const QString &)), this, SLOT(cpuCycleThresChanged(const QString &)));
+ validator = new fceuDecIntValidtor( 0, 0x3FFFFFFF, this );
instrExdVal->setFont( font );
instrExdVal->setMaxLength( 16 );
- instrExdVal->setInputMask( ">9000000000000000;" );
+ instrExdVal->setValidator( validator );
instrExdVal->setAlignment(Qt::AlignLeft);
instrExdVal->setMaximumWidth( 18 * fontCharWidth );
+ instrExdVal->setCursorPosition(0);
connect( instrExdVal, SIGNAL(textEdited(const QString &)), this, SLOT(instructionsThresChanged(const QString &)));
brkCpuCycExd->setChecked( break_on_cycles );
@@ -425,8 +581,7 @@ ConsoleDebugger::ConsoleDebugger(QWidget *parent)
vbox->addWidget( regNamChkBox );
symDbgChkBox->setChecked(true);
- //regNamChkBox->setChecked(true);
- regNamChkBox->setEnabled(false); // TODO
+ regNamChkBox->setChecked(true);
connect( romOfsChkBox, SIGNAL(stateChanged(int)), this, SLOT(displayROMoffsetCB(int)) );
connect( symDbgChkBox, SIGNAL(stateChanged(int)), this, SLOT(symbolDebugEnableCB(int)) );
@@ -698,6 +853,8 @@ void ConsoleDebugger::openBpEditWindow( int editIdx, watchpointinfo *wp )
connect( okButton, SIGNAL(clicked(void)), &dialog, SLOT(accept(void)) );
connect( cancelButton, SIGNAL(clicked(void)), &dialog, SLOT(reject(void)) );
+ okButton->setDefault(true);
+
if ( wp != NULL )
{
char stmp[256];
@@ -943,6 +1100,8 @@ void ConsoleDebugger::openDebugSymbolEditWindow( int addr )
connect( okButton, SIGNAL(clicked(void)), &dialog, SLOT(accept(void)) );
connect( cancelButton, SIGNAL(clicked(void)), &dialog, SLOT(reject(void)) );
+ okButton->setDefault(true);
+
if ( sym != NULL )
{
nameEntry->setText( tr(sym->name.c_str()) );
@@ -955,6 +1114,7 @@ void ConsoleDebugger::openDebugSymbolEditWindow( int addr )
if ( ret == QDialog::Accepted )
{
+ fceuWrapperLock();
if ( sym == NULL )
{
sym = new debugSymbol_t();
@@ -969,7 +1129,7 @@ void ConsoleDebugger::openDebugSymbolEditWindow( int addr )
sym->name = nameEntry->text().toStdString();
sym->comment = commentEntry->text().toStdString();
}
- fceuWrapperLock();
+ sym->trimTrailingSpaces();
asmView->updateAssemblyView();
fceuWrapperUnLock();
}
@@ -1424,9 +1584,62 @@ void ConsoleDebugger::debFileAutoLoadCB( int value )
//----------------------------------------------------------------------------
void ConsoleDebugger::reloadSymbolsCB(void)
{
+ fceuWrapperLock();
debugSymbolTable.loadGameSymbols();
asmView->updateAssemblyView();
+ fceuWrapperUnLock();
+}
+//----------------------------------------------------------------------------
+void ConsoleDebugger::pcSetPlaceTop(void)
+{
+ asmView->setPC_placement( 0 );
+}
+//----------------------------------------------------------------------------
+void ConsoleDebugger::pcSetPlaceUpperMid(void)
+{
+ asmView->setPC_placement( 1 );
+}
+//----------------------------------------------------------------------------
+void ConsoleDebugger::pcSetPlaceCenter(void)
+{
+ asmView->setPC_placement( 2 );
+}
+//----------------------------------------------------------------------------
+void ConsoleDebugger::pcSetPlaceLowerMid(void)
+{
+ asmView->setPC_placement( 3 );
+}
+//----------------------------------------------------------------------------
+void ConsoleDebugger::pcSetPlaceBottom(void)
+{
+ asmView->setPC_placement( 4 );
+}
+//----------------------------------------------------------------------------
+void ConsoleDebugger::pcSetPlaceCustom(void)
+{
+ int ret, ofs;
+ QInputDialog dialog(this);
+
+ g_config->getOption("SDL.DebuggerPCLineOffset" , &ofs );
+
+ dialog.setWindowTitle( tr("PC Line Offset") );
+ dialog.setLabelText( tr("Enter a line offset from 0 to 100.") );
+ dialog.setOkButtonText( tr("Ok") );
+ dialog.setInputMode( QInputDialog::IntInput );
+ dialog.setIntRange( 0, 100 );
+ dialog.setIntValue( ofs );
+
+ dialog.show();
+ ret = dialog.exec();
+
+ if ( QDialog::Accepted == ret )
+ {
+ ofs = dialog.intValue();
+
+ asmView->setPC_placement( 5, ofs );
+ }
+
}
//----------------------------------------------------------------------------
void ConsoleDebugger::debugRunCB(void)
@@ -1507,6 +1720,11 @@ void ConsoleDebugger::debugStepOverCB(void)
}
}
//----------------------------------------------------------------------------
+void ConsoleDebugger::debugRunToCursorCB(void)
+{
+ asmView->setBreakpointAtSelectedLine();
+}
+//----------------------------------------------------------------------------
void ConsoleDebugger::debugRunLineCB(void)
{
if (FCEUI_EmulationPaused())
@@ -1580,6 +1798,16 @@ void ConsoleDebugger::resetCountersCB (void)
updateRegisterView();
}
//----------------------------------------------------------------------------
+void ConsoleDebugger::asmViewCtxMenuRunToCursor(void)
+{
+ fceuWrapperLock();
+ watchpoint[64].address = asmView->getCtxMenuAddr();
+ watchpoint[64].flags = WP_E|WP_X;
+
+ FCEUI_SetEmulationPaused(0);
+ fceuWrapperUnLock();
+}
+//----------------------------------------------------------------------------
void ConsoleDebugger::asmViewCtxMenuAddBP(void)
{
watchpointinfo wp;
@@ -1641,6 +1869,43 @@ void ConsoleDebugger::asmViewCtxMenuAddSym(void)
openDebugSymbolEditWindow( asmView->getCtxMenuAddr() );
}
//----------------------------------------------------------------------------
+void QAsmView::setPC_placement( int mode, int ofs )
+{
+ pcLinePlacement = mode;
+
+ if ( mode == 5 )
+ {
+ pcLineOffset = ofs;
+ }
+
+ g_config->setOption("SDL.DebuggerPCPlacement" , pcLinePlacement);
+ g_config->setOption("SDL.DebuggerPCLineOffset" , pcLineOffset );
+ g_config->save();
+}
+//----------------------------------------------------------------------------
+void QAsmView::setBreakpointAtSelectedLine(void)
+{
+ int addr = -1;
+
+ if ( (selAddrLine >= 0) && (selAddrLine < asmEntry.size()) )
+ {
+ if ( selAddrValue == asmEntry[ selAddrLine ]->addr )
+ {
+ addr = selAddrValue;
+ }
+ }
+
+ if ( addr >= 0 )
+ {
+ fceuWrapperLock();
+ watchpoint[64].address = addr;
+ watchpoint[64].flags = WP_E|WP_X;
+
+ FCEUI_SetEmulationPaused(0);
+ fceuWrapperUnLock();
+ }
+}
+//----------------------------------------------------------------------------
int QAsmView::getAsmLineFromAddr(int addr)
{
int line = -1;
@@ -1800,13 +2065,12 @@ static int InstructionUp(int from)
void QAsmView::updateAssemblyView(void)
{
int starting_address, start_address_lp, addr, size;
- int instruction_addr;
+ int instruction_addr, asmFlags = 0;
std::string line;
char chr[64];
uint8 opcode[3];
- const char *disassemblyText = NULL;
+ char asmTxt[256];
dbg_asm_entry_t *a, *d;
- //GtkTextIter iter, next_iter;
char pc_found = 0;
start_address_lp = starting_address = X.PC;
@@ -1836,14 +2100,17 @@ void QAsmView::updateAssemblyView(void)
addr = starting_address;
asmPC = NULL;
+ if ( symbolicDebugEnable )
+ {
+ asmFlags |= ASM_DEBUG_SYMS;
+
+ if ( registerNameEnable )
+ {
+ asmFlags |= ASM_DEBUG_REGS;
+ }
+ }
//asmText->clear();
- //gtk_text_buffer_get_start_iter( textbuf, &iter );
-
- //textview_lines_allocated = gtk_text_buffer_get_line_count( textbuf ) - 1;
-
- //printf("Num Lines: %i\n", textview_lines_allocated );
-
for (int i=0; i < 0xFFFF; i++)
{
line.clear();
@@ -1927,12 +2194,9 @@ void QAsmView::updateAssemblyView(void)
size++;
}
- disassemblyText = Disassemble(addr, opcode);
+ DisassembleWithDebug(addr, opcode, asmFlags, asmTxt, &a->sym);
- if ( disassemblyText )
- {
- line.append( disassemblyText );
- }
+ line.append( asmTxt );
}
for (int j=0; jofs );
- d = new dbg_asm_entry_t();
+ //printf("Debug symbol Found at $%04X \n", dbgSym->ofs );
- *d = *a;
- d->type = dbg_asm_entry_t::SYMBOL_NAME;
- d->text.assign( dbgSym->name );
- d->line = asmEntry.size();
-
- asmEntry.push_back(d);
+ if ( dbgSym->name.size() > 0 )
+ {
+ d = new dbg_asm_entry_t();
+
+ *d = *a;
+ d->type = dbg_asm_entry_t::SYMBOL_NAME;
+ d->text.assign( dbgSym->name );
+ d->text.append( ":");
+ d->line = asmEntry.size();
+
+ asmEntry.push_back(d);
+ }
i=0; j=0;
c = dbgSym->comment.c_str();
@@ -2026,7 +2295,7 @@ void QAsmView::updateAssemblyView(void)
pxLineWidth = maxLineLen * pxCharWidth;
- setMinimumWidth( pxLineWidth );
+ setMinimumWidth( 50 * pxCharWidth );
vbar->setMaximum( asmEntry.size() );
}
@@ -2126,7 +2395,6 @@ void ConsoleDebugger::updateRegisterView(void)
int stackPtr;
char stmp[64];
char str[32], str2[32];
- std::string stackLine;
sprintf( stmp, "%04X", X.PC );
@@ -2157,31 +2425,7 @@ void ConsoleDebugger::updateRegisterView(void)
sprintf( stmp, "Stack: $%04X", stackPtr );
stackFrame->setTitle( tr(stmp) );
-
- stackPtr++;
-
- if ( stackPtr <= 0x01FF )
- {
- sprintf( stmp, "%02X", GetMem(stackPtr) );
-
- stackLine.assign( stmp );
-
- for (int i = 1; i < 128; i++)
- {
- //tmp = ((tmp+1)|0x0100)&0x01FF; //increment and fix pointer to $0100-$01FF range
- stackPtr++;
- if (stackPtr > 0x1FF)
- break;
- if ((i & 7) == 0)
- sprintf( stmp, ",\r\n%02X", GetMem(stackPtr) );
- else
- sprintf( stmp, ",%02X", GetMem(stackPtr) );
-
- stackLine.append( stmp );
- }
- }
-
- stackText->setPlainText( tr(stackLine.c_str()) );
+ stackText->updateText();
// update counters
int64 counter_value = timestampbase + (uint64)timestamp - total_cycles_base;
@@ -2302,15 +2546,33 @@ void ConsoleDebugger::updatePeriodic(void)
emuStatLbl->setStyleSheet("background-color: green; color: white;");
}
+ if ( waitingAtBp && (lastBpIdx == BREAK_TYPE_CYCLES_EXCEED) )
+ {
+ cpuCyclesLbl1->setStyleSheet("background-color: blue; color: white;");
+ }
+ else
+ {
+ cpuCyclesLbl1->setStyleSheet(NULL);
+ }
+
+ if ( waitingAtBp && (lastBpIdx == BREAK_TYPE_INSTRUCTIONS_EXCEED) )
+ {
+ cpuInstrsLbl1->setStyleSheet("background-color: blue; color: white;");
+ }
+ else
+ {
+ cpuInstrsLbl1->setStyleSheet(NULL);
+ }
+
if ( bpTree->topLevelItemCount() != numWPs )
{
- printf("Breakpoint Tree Update\n");
+ //printf("Breakpoint Tree Update\n");
bpListUpdate( true );
}
if ( bmTree->topLevelItemCount() != dbgBmMgr.size() )
{
- printf("Bookmark Tree Update\n");
+ //printf("Bookmark Tree Update\n");
bmListUpdate( true );
}
}
@@ -2337,6 +2599,7 @@ void ConsoleDebugger::breakPointNotify( int bpNum )
if ( item != NULL )
{
item->setSelected(true);
+ bpTree->setCurrentItem( item );
}
bpTree->viewport()->update();
}
@@ -2345,11 +2608,11 @@ void ConsoleDebugger::breakPointNotify( int bpNum )
{
if (bpNum == BREAK_TYPE_CYCLES_EXCEED)
{
- // TODO
+ // Label Coloring done in periodic update
}
else if (bpNum == BREAK_TYPE_INSTRUCTIONS_EXCEED)
{
- // TODO
+ // Label Coloring done in periodic update
}
}
@@ -2376,6 +2639,9 @@ void FCEUD_DebugBreakpoint( int bpNum )
{
return;
}
+ lastBpIdx = bpNum;
+ waitingAtBp = true;
+
printf("Breakpoint Hit: %i \n", bpNum );
fceuWrapperUnLock();
@@ -2387,12 +2653,29 @@ void FCEUD_DebugBreakpoint( int bpNum )
while ( nes_shm->runEmulator && FCEUI_EmulationPaused() && !FCEUI_EmulationFrameStepped())
{
- usleep(100000);
+ // HACK: break when Frame Advance is pressed
+ extern bool frameAdvanceRequested;
+ extern int frameAdvance_Delay_count, frameAdvance_Delay;
+
+ if (frameAdvanceRequested)
+ {
+ if ( (frameAdvance_Delay_count == 0) || (frameAdvance_Delay_count >= frameAdvance_Delay) )
+ {
+ FCEUI_SetEmulationPaused(EMULATIONPAUSED_FA);
+ }
+ if (frameAdvance_Delay_count < frameAdvance_Delay)
+ {
+ frameAdvance_Delay_count++;
+ }
+ }
+ usleep(16667);
}
// since we unfreezed emulation, reset delta_cycles counter
ResetDebugStatisticsDeltaCounters();
fceuWrapperLock();
+
+ waitingAtBp = false;
}
//----------------------------------------------------------------------------
bool debuggerWindowIsOpen(void)
@@ -2466,11 +2749,14 @@ void saveGameDebugBreakpoints(void)
debuggerBookmark_t *bm;
// If no breakpoints are loaded, skip saving
- if ( numWPs == 0 )
+ if ( (numWPs == 0) && (dbgBmMgr.size() == 0) )
+ {
+ return;
+ }
+ if ( getGameDebugBreakpointFileName( stmp ) )
{
return;
}
- getGameDebugBreakpointFileName( stmp );
//printf("Debug Save File: '%s' \n", stmp );
@@ -2606,7 +2892,10 @@ void loadGameDebugBreakpoints(void)
printf("No Debug Windows Open: Skipping loading of breakpoint data\n");
return;
}
- getGameDebugBreakpointFileName( stmp );
+ if ( getGameDebugBreakpointFileName( stmp ) )
+ {
+ return;
+ }
//printf("Debug Load File: '%s' \n", stmp );
@@ -2664,7 +2953,7 @@ void loadGameDebugBreakpoints(void)
else if ( strcmp( id, "flags" ) == 0 )
{
type = 0;
- //enable = (data[0] == 'E'); // Always start with breakpoints disabled.
+ enable = (data[0] == 'E');
if ( data[1] == 'P' )
{
@@ -2750,15 +3039,45 @@ QAsmView::QAsmView(QWidget *parent)
{
QPalette pal;
QColor fg("black"), bg("white");
+ QColor c;
+
+ useDarkTheme = false;
font.setFamily("Courier New");
font.setStyle( QFont::StyleNormal );
font.setStyleHint( QFont::Monospace );
pal = this->palette();
- pal.setColor(QPalette::Base , bg );
- pal.setColor(QPalette::Background, bg );
- pal.setColor(QPalette::WindowText, fg );
+
+ //c = pal.color(QPalette::Base);
+ //printf("Base: R:%i G:%i B:%i \n", c.red(), c.green(), c.blue() );
+
+ //c = pal.color(QPalette::Background);
+ //printf("BackGround: R:%i G:%i B:%i \n", c.red(), c.green(), c.blue() );
+
+ // Figure out if we are using a light or dark theme by checking the
+ // default window text grayscale color. If more white, then we will
+ // use white text on black background, else we do the opposite.
+ c = pal.color(QPalette::WindowText);
+
+ if ( qGray( c.red(), c.green(), c.blue() ) > 128 )
+ {
+ useDarkTheme = true;
+ }
+ //printf("WindowText: R:%i G:%i B:%i \n", c.red(), c.green(), c.blue() );
+
+ if ( useDarkTheme )
+ {
+ pal.setColor(QPalette::Base , fg );
+ pal.setColor(QPalette::Background, fg );
+ pal.setColor(QPalette::WindowText, bg );
+ }
+ else
+ {
+ pal.setColor(QPalette::Base , bg );
+ pal.setColor(QPalette::Background, bg );
+ pal.setColor(QPalette::WindowText, fg );
+ }
this->parent = (ConsoleDebugger*)parent;
this->setPalette(pal);
@@ -2778,7 +3097,37 @@ QAsmView::QAsmView(QWidget *parent)
maxLineOffset = 0;
ctxMenuAddr = -1;
+ mouseLeftBtnDown = false;
+ txtHlgtAnchorLine = -1;
+ txtHlgtAnchorChar = -1;
+ txtHlgtStartChar = -1;
+ txtHlgtStartLine = -1;
+ txtHlgtEndChar = -1;
+ txtHlgtEndLine = -1;
+
+ pcLinePlacement = 0;
+ pcLineOffset = 0;
+
+ g_config->getOption( "SDL.DebuggerPCPlacement" , &pcLinePlacement );
+ g_config->getOption( "SDL.DebuggerPCLineOffset", &pcLineOffset );
+
+ selAddrLine = -1;
+ selAddrChar = 0;
+ selAddrWidth = 0;
+ selAddrValue = -1;
+ memset( selAddrText, 0, sizeof(selAddrText) );
+
+ cursorLineAddr = -1;
+ wheelPixelCounter = 0;
+
//setSizePolicy( QSizePolicy::Preferred, QSizePolicy::Expanding );
+ setFocusPolicy(Qt::StrongFocus);
+
+ clipboard = QGuiApplication::clipboard();
+
+ //printf("clipboard->supportsSelection() : '%i' \n", clipboard->supportsSelection() );
+ //printf("clipboard->supportsFindBuffer(): '%i' \n", clipboard->supportsFindBuffer() );
+
}
//----------------------------------------------------------------------------
QAsmView::~QAsmView(void)
@@ -2816,7 +3165,52 @@ void QAsmView::scrollToPC(void)
{
if ( asmPC != NULL )
{
- lineOffset = asmPC->line;
+ int ofs = 0;
+ int maxOfs = (viewLines-3);
+
+ if ( maxOfs < 0 )
+ {
+ maxOfs = 0;
+ }
+
+ switch ( pcLinePlacement )
+ {
+ default:
+ case 0:
+ ofs = 0;
+ break;
+ case 1:
+ ofs = (viewLines / 4);
+ break;
+ case 2:
+ ofs = (viewLines / 2);
+ break;
+ case 3:
+ ofs = (viewLines*3) / 4;
+ break;
+ case 4:
+ ofs = maxOfs;
+ break;
+ case 5:
+ ofs = pcLineOffset;
+
+ if ( ofs < 0 )
+ {
+ ofs = 0;
+ }
+ else if ( ofs > maxOfs )
+ {
+ ofs = maxOfs;
+ }
+ break;
+ }
+
+ lineOffset = asmPC->line - ofs;
+
+ if ( lineOffset < 0 )
+ {
+ lineOffset = 0;
+ }
vbar->setValue( lineOffset );
}
}
@@ -2827,7 +3221,9 @@ void QAsmView::setDisplayROMoffsets( bool value )
{
displayROMoffsets = value;
+ fceuWrapperLock();
updateAssemblyView();
+ fceuWrapperUnLock();
}
}
//----------------------------------------------------------------------------
@@ -2837,7 +3233,9 @@ void QAsmView::setSymbolDebugEnable( bool value )
{
symbolicDebugEnable = value;
+ fceuWrapperLock();
updateAssemblyView();
+ fceuWrapperUnLock();
}
}
//----------------------------------------------------------------------------
@@ -2847,7 +3245,9 @@ void QAsmView::setRegisterNameEnable( bool value )
{
registerNameEnable = value;
+ fceuWrapperLock();
updateAssemblyView();
+ fceuWrapperUnLock();
}
}
//----------------------------------------------------------------------------
@@ -2897,14 +3297,81 @@ void QAsmView::resizeEvent(QResizeEvent *event)
//----------------------------------------------------------------------------
void QAsmView::keyPressEvent(QKeyEvent *event)
{
- printf("Debug ASM Window Key Press: 0x%x \n", event->key() );
+ //printf("Debug ASM Window Key Press: 0x%x \n", event->key() );
+ if (event->matches(QKeySequence::MoveToPreviousLine))
+ {
+ lineOffset--;
+ if ( lineOffset < 0 )
+ {
+ lineOffset = 0;
+ }
+ vbar->setValue( lineOffset );
+ event->accept();
+ }
+ else if (event->matches(QKeySequence::MoveToNextLine))
+ {
+ lineOffset++;
+
+ if ( lineOffset > maxLineOffset )
+ {
+ lineOffset = maxLineOffset;
+ }
+ vbar->setValue( lineOffset );
+ event->accept();
+ }
+ else if (event->matches(QKeySequence::MoveToNextPage))
+ {
+ lineOffset += ( (3 * viewLines) / 4);
+
+ if ( lineOffset >= maxLineOffset )
+ {
+ lineOffset = maxLineOffset;
+ }
+ vbar->setValue( lineOffset );
+ event->accept();
+ }
+ else if (event->matches(QKeySequence::MoveToPreviousPage))
+ {
+ lineOffset -= ( (3 * viewLines) / 4);
+
+ if ( lineOffset < 0 )
+ {
+ lineOffset = 0;
+ }
+ vbar->setValue( lineOffset );
+ event->accept();
+ }
+ else if ( selAddrValue >= 0 )
+ {
+ ctxMenuAddr = selAddrValue;
+
+ if ( event->key() == Qt::Key_B )
+ {
+ parent->asmViewCtxMenuAddBP();
+ event->accept();
+ }
+ else if ( event->key() == Qt::Key_S )
+ {
+ parent->asmViewCtxMenuAddSym();
+ event->accept();
+ }
+ else if ( event->key() == Qt::Key_M )
+ {
+ parent->asmViewCtxMenuAddBM();
+ event->accept();
+ }
+ else if ( event->key() == Qt::Key_H )
+ {
+ parent->asmViewCtxMenuOpenHexEdit();
+ event->accept();
+ }
+ }
}
//----------------------------------------------------------------------------
void QAsmView::keyReleaseEvent(QKeyEvent *event)
{
- printf("Debug ASM Window Key Release: 0x%x \n", event->key() );
- //assignHotkey( event );
+ //printf("Debug ASM Window Key Release: 0x%x \n", event->key() );
}
//----------------------------------------------------------------------------
QPoint QAsmView::convPixToCursor( QPoint p )
@@ -2944,22 +3411,85 @@ QPoint QAsmView::convPixToCursor( QPoint p )
return c;
}
//----------------------------------------------------------------------------
+bool QAsmView::textIsHighlighted(void)
+{
+ bool set = false;
+
+ if ( txtHlgtStartLine == txtHlgtEndLine )
+ {
+ set = (txtHlgtStartChar != txtHlgtEndChar);
+ }
+ else
+ {
+ set = true;
+ }
+ return set;
+}
+//----------------------------------------------------------------------------
+void QAsmView::setHighlightEndCoord( int x, int y )
+{
+
+ if ( txtHlgtAnchorLine < y )
+ {
+ txtHlgtStartLine = txtHlgtAnchorLine;
+ txtHlgtStartChar = txtHlgtAnchorChar;
+ txtHlgtEndLine = y;
+ txtHlgtEndChar = x;
+ }
+ else if ( txtHlgtAnchorLine > y )
+ {
+ txtHlgtStartLine = y;
+ txtHlgtStartChar = x;
+ txtHlgtEndLine = txtHlgtAnchorLine;
+ txtHlgtEndChar = txtHlgtAnchorChar;
+ }
+ else
+ {
+ txtHlgtStartLine = txtHlgtAnchorLine;
+ txtHlgtEndLine = txtHlgtAnchorLine;
+
+ if ( txtHlgtAnchorChar < x )
+ {
+ txtHlgtStartChar = txtHlgtAnchorChar;
+ txtHlgtEndChar = x;
+ }
+ else if ( txtHlgtAnchorChar > x )
+ {
+ txtHlgtStartChar = x;
+ txtHlgtEndChar = txtHlgtAnchorChar;
+ }
+ else
+ {
+ txtHlgtStartChar = txtHlgtAnchorChar;
+ txtHlgtEndChar = txtHlgtAnchorChar;
+ }
+ }
+ return;
+}
+//----------------------------------------------------------------------------
void QAsmView::mouseMoveEvent(QMouseEvent * event)
{
int line;
- QPoint c = convPixToCursor( event->pos() );
char txt[256];
std::string s;
+ QPoint c = convPixToCursor( event->pos() );
+
line = lineOffset + c.y();
+ if ( mouseLeftBtnDown )
+ {
+ //printf("Left Button Move: (%i,%i)\n", c.x(), c.y() );
+ setHighlightEndCoord( c.x(), line );
+ }
+
//printf("c (%i,%i) : Line %i : %04X \n", c.x(), c.y(), line, asmEntry[line]->addr );
if ( line < asmEntry.size() )
{
int addr;
- addr = asmEntry[line]->addr;
+ cursorLineAddr = addr = asmEntry[line]->addr;
if (addr >= 0x8000)
{
@@ -2981,7 +3511,7 @@ void QAsmView::mouseMoveEvent(QMouseEvent * event)
{
fileName = "...";
}
- sprintf( txt, ", Offset 0x%06X in File \"%s\" (NL file: %X)", romOfs, fileName, bank);
+ sprintf( txt, "\nOffset 0x%06X in File \"%s\" (NL file: %X)", romOfs, fileName, bank);
s.append( txt );
}
@@ -3000,29 +3530,308 @@ void QAsmView::mouseMoveEvent(QMouseEvent * event)
}
}
//----------------------------------------------------------------------------
+void QAsmView::loadClipboard( const char *txt )
+{
+ clipboard->setText( tr(txt), QClipboard::Clipboard );
+
+ if ( clipboard->supportsSelection() )
+ {
+ clipboard->setText( tr(txt), QClipboard::Selection );
+ }
+}
+//----------------------------------------------------------------------------
+void QAsmView::loadHighlightToClipboard(void)
+{
+ if ( !textIsHighlighted() )
+ {
+ return;
+ }
+ int l, row, nrow;
+ std::string txt;
+
+ nrow = (viewHeight / pxLineSpacing) + 1;
+
+ if ( nrow < 1 ) nrow = 1;
+
+ for (row=0; row < nrow; row++)
+ {
+ l = lineOffset + row;
+
+ if ( (l >= txtHlgtStartLine) && (l <= txtHlgtEndLine) )
+ {
+ int hlgtXs, hlgtXe, hlgtXd;
+ std::string s;
+ bool addNewLine;
+
+ if ( l == txtHlgtStartLine )
+ {
+ hlgtXs = txtHlgtStartChar;
+ }
+ else
+ {
+ hlgtXs = 0;
+ }
+
+ if ( l == txtHlgtEndLine )
+ {
+ hlgtXe = txtHlgtEndChar;
+ addNewLine = false;
+ }
+ else
+ {
+ hlgtXe = (viewWidth / pxCharWidth) + 1;
+ addNewLine = true;
+ }
+ hlgtXd = (hlgtXe - hlgtXs);
+
+ if ( hlgtXs < asmEntry[l]->text.size() )
+ {
+ s = asmEntry[l]->text.substr( hlgtXs, hlgtXd );
+ }
+ txt.append(s);
+
+ if ( addNewLine )
+ {
+ txt.append("\n");
+ }
+ }
+ }
+
+ //printf("Load Text to Clipboard:\n%s\n", txt.c_str() );
+
+ loadClipboard( txt.c_str() );
+
+}
+//----------------------------------------------------------------------------
+void QAsmView::mouseReleaseEvent(QMouseEvent * event)
+{
+ int line;
+ QPoint c = convPixToCursor( event->pos() );
+
+ line = lineOffset + c.y();
+
+ if ( event->button() == Qt::LeftButton )
+ {
+ //printf("Left Button Release: (%i,%i)\n", c.x(), c.y() );
+ mouseLeftBtnDown = false;
+ setHighlightEndCoord( c.x(), line );
+
+ loadHighlightToClipboard();
+ }
+}
+//----------------------------------------------------------------------------
void QAsmView::mousePressEvent(QMouseEvent * event)
{
int line;
QPoint c = convPixToCursor( event->pos() );
line = lineOffset + c.y();
+
+ //printf("Mouse Button Pressed: 0x%x (%i,%i)\n", event->button(), c.x(), c.y() );
+ if ( event->button() == Qt::LeftButton )
+ {
+ //printf("Left Button Pressed: (%i,%i)\n", c.x(), c.y() );
+ mouseLeftBtnDown = true;
+ txtHlgtAnchorChar = c.x();
+ txtHlgtAnchorLine = line;
+
+ setHighlightEndCoord( c.x(), line );
+ }
+
+ selAddrLine = -1;
+ selAddrChar = 0;
+ selAddrWidth = 0;
+ selAddrValue = -1;
+ selAddrText[0] = 0;
+
if ( line < asmEntry.size() )
{
- int addr;
+ int i,j, addr = -1, addrTextLoc = -1, selChar;
+ int symTextStart = -1, symTextEnd = -1;
+ char addrClicked = 0;
+ char stmp[64];
- addr = asmEntry[line]->addr;
+ selChar = c.x();
- parent->setBookmarkSelectedAddress( addr );
+ if ( asmEntry[line]->type == dbg_asm_entry_t::ASM_TEXT )
+ {
+ if ( selChar < (int)asmEntry[line]->text.size() )
+ {
+
+ i = selChar;
+
+ if ( asmEntry[line]->sym.name.size() > 0 )
+ {
+ size_t subStrLoc = asmEntry[line]->text.find( asmEntry[line]->sym.name, 22 );
+
+ if ( (subStrLoc != std::string::npos) && (subStrLoc > 22) )
+ {
+ //printf("Line:%i asmEntry DB Sym: %zi '%s'\n", line, subStrLoc, asmEntry[line]->sym.name.c_str() );
+ symTextStart = subStrLoc;
+ symTextEnd = subStrLoc + asmEntry[line]->sym.name.size();
+ }
+ }
+
+ if ( (i >= symTextStart) && (i < symTextEnd) )
+ {
+ selAddrLine = line;
+ selAddrChar = symTextStart;
+ selAddrWidth = symTextEnd - symTextStart;
+ selAddrValue = addr = asmEntry[line]->sym.ofs;
+
+ if ( selAddrWidth >= (int)sizeof(selAddrText) )
+ {
+ selAddrWidth = sizeof(selAddrText)-1;
+ }
+ strncpy( selAddrText, asmEntry[line]->sym.name.c_str(), selAddrWidth );
+ selAddrText[ selAddrWidth ] = 0;
+ }
+ else if ( isxdigit( asmEntry[line]->text[i] ) )
+ {
+ addrClicked = 1;
+ addrTextLoc = i;
+
+ while ( isxdigit( asmEntry[line]->text[i] ) )
+ {
+ addrTextLoc = i;
+ i--;
+ }
+ if ( asmEntry[line]->text[i] == '$' || asmEntry[line]->text[i] == ':' )
+ {
+ i--;
+ }
+ else
+ {
+ addrClicked = 0;
+ }
+ if ( asmEntry[line]->text[i] == '#' )
+ {
+ addrClicked = 0;
+ }
+ if ( addrClicked )
+ {
+ j=0; i = addrTextLoc;
+
+ while ( isxdigit( asmEntry[line]->text[i] ) )
+ {
+ stmp[j] = asmEntry[line]->text[i]; i++; j++;
+ }
+ stmp[j] = 0;
+
+ //printf("Addr: '%s'\n", stmp );
+
+ addr = strtol( stmp, NULL, 16 );
+
+ selAddrLine = line;
+ selAddrChar = addrTextLoc;
+ selAddrWidth = j;
+ selAddrValue = addr;
+ strcpy( selAddrText, stmp );
+ }
+ }
+ }
+ }
+ else if ( asmEntry[line]->type == dbg_asm_entry_t::SYMBOL_NAME )
+ {
+ selAddrLine = line;
+ selAddrChar = 0;
+ selAddrValue = addr = asmEntry[line]->addr;
+
+ if ( asmEntry[line]->text.size() > 0 )
+ {
+ selAddrWidth = asmEntry[line]->text.size()-1;
+ }
+ else
+ {
+ selAddrWidth = 0;
+ }
+ if ( selAddrWidth >= (int)sizeof(selAddrText) )
+ {
+ selAddrWidth = sizeof(selAddrText)-1;
+ }
+ strncpy( selAddrText, asmEntry[line]->text.c_str(), selAddrWidth );
+ selAddrText[ selAddrWidth ] = 0;
+ }
+
+ if ( addr < 0 )
+ {
+ addr = asmEntry[line]->addr;
+ selAddrLine = line;
+ selAddrChar = 4;
+ selAddrWidth = 4;
+ selAddrValue = addr;
+ sprintf( selAddrText, "%04X", addr );
+ }
+ //printf("Line: '%s'\n", asmEntry[line]->text.c_str() );
+
+ if ( addr >= 0 )
+ {
+ parent->setBookmarkSelectedAddress( addr );
+ }
+
+ if ( selAddrText[0] != 0 )
+ {
+ loadClipboard( selAddrText );
+ }
}
}
//----------------------------------------------------------------------------
+void QAsmView::wheelEvent(QWheelEvent *event)
+{
+
+ QPoint numPixels = event->pixelDelta();
+ QPoint numDegrees = event->angleDelta();
+
+ if (!numPixels.isNull())
+ {
+ wheelPixelCounter -= numPixels.y();
+ //printf("numPixels: (%i,%i) \n", numPixels.x(), numPixels.y() );
+ }
+ else if (!numDegrees.isNull())
+ {
+ //QPoint numSteps = numDegrees / 15;
+ //printf("numSteps: (%i,%i) \n", numSteps.x(), numSteps.y() );
+ //printf("numDegrees: (%i,%i) %i\n", numDegrees.x(), numDegrees.y(), pxLineSpacing );
+ wheelPixelCounter -= (pxLineSpacing * numDegrees.y()) / (15*8);
+ }
+ //printf("Wheel Event: %i\n", wheelPixelCounter);
+
+ if ( wheelPixelCounter >= pxLineSpacing )
+ {
+ lineOffset += (wheelPixelCounter / pxLineSpacing);
+
+ if ( lineOffset > maxLineOffset )
+ {
+ lineOffset = maxLineOffset;
+ }
+ vbar->setValue( lineOffset );
+
+ wheelPixelCounter = wheelPixelCounter % pxLineSpacing;
+ }
+ else if ( wheelPixelCounter <= -pxLineSpacing )
+ {
+ lineOffset += (wheelPixelCounter / pxLineSpacing);
+
+ if ( lineOffset < 0 )
+ {
+ lineOffset = 0;
+ }
+ vbar->setValue( lineOffset );
+
+ wheelPixelCounter = wheelPixelCounter % pxLineSpacing;
+ }
+
+ event->accept();
+}
+//----------------------------------------------------------------------------
void QAsmView::contextMenuEvent(QContextMenuEvent *event)
{
int line;
QAction *act;
QMenu menu(this);
QPoint c = convPixToCursor( event->pos() );
+ bool enableRunToCursor = false;
line = lineOffset + c.y();
@@ -3032,32 +3841,74 @@ void QAsmView::contextMenuEvent(QContextMenuEvent *event)
{
int addr;
- ctxMenuAddr = addr = asmEntry[line]->addr;
+ if ( selAddrValue < 0 )
+ {
+ ctxMenuAddr = addr = asmEntry[line]->addr;
- act = new QAction(tr("Add Breakpoint"), this);
+ enableRunToCursor = true;
+ }
+ else
+ {
+ ctxMenuAddr = addr = selAddrValue;
+
+ enableRunToCursor = (selAddrValue == asmEntry[line]->addr);
+ }
+
+ if ( enableRunToCursor )
+ {
+ act = new QAction(tr("Run To Cursor"), &menu);
+ menu.addAction(act);
+ //act->setShortcut( QKeySequence(tr("Ctrl+F10")));
+ connect( act, SIGNAL(triggered(void)), parent, SLOT(asmViewCtxMenuRunToCursor(void)) );
+ }
+
+ act = new QAction(tr("Add Breakpoint"), &menu);
menu.addAction(act);
+ act->setShortcut( QKeySequence(tr("B")));
connect( act, SIGNAL(triggered(void)), parent, SLOT(asmViewCtxMenuAddBP(void)) );
- act = new QAction(tr("Add Symbolic Debug Marker"), this);
+ act = new QAction(tr("Add Symbolic Debug Marker"), &menu);
menu.addAction(act);
+ act->setShortcut( QKeySequence(tr("S")));
connect( act, SIGNAL(triggered(void)), parent, SLOT(asmViewCtxMenuAddSym(void)) );
- act = new QAction(tr("Add Bookmark"), this);
+ act = new QAction(tr("Add Bookmark"), &menu);
menu.addAction(act);
+ act->setShortcut( QKeySequence(tr("M")));
connect( act, SIGNAL(triggered(void)), parent, SLOT(asmViewCtxMenuAddBM(void)) );
- act = new QAction(tr("Open Hex Editor"), this);
+ act = new QAction(tr("Open Hex Editor"), &menu);
menu.addAction(act);
+ act->setShortcut( QKeySequence(tr("H")));
connect( act, SIGNAL(triggered(void)), parent, SLOT(asmViewCtxMenuOpenHexEdit(void)) );
menu.exec(event->globalPos());
}
}
//----------------------------------------------------------------------------
+void QAsmView::drawText( QPainter *painter, int x, int y, const char *txt )
+{
+ int i=0;
+ char c[2];
+
+ c[0] = 0; c[1] = 0;
+
+ while ( txt[i] != 0 )
+ {
+ c[0] = txt[i];
+ painter->drawText( x, y, tr(c) );
+ i++; x += pxCharWidth;
+ }
+}
+//----------------------------------------------------------------------------
void QAsmView::paintEvent(QPaintEvent *event)
{
int x,y,l, row, nrow, selAddr;
QPainter painter(this);
+ QColor white("white"), black("black"), blue("blue");
+ QColor hlgtFG("white"), hlgtBG("blue");
+ bool forceDarkColor = false;
+ bool txtHlgtSet = false;
painter.setFont(font);
viewWidth = event->rect().width();
@@ -3094,17 +3945,21 @@ void QAsmView::paintEvent(QPaintEvent *event)
y = pxLineSpacing;
+ txtHlgtSet = textIsHighlighted();
+
for (row=0; row < nrow; row++)
{
x = -pxLineXScroll;
l = lineOffset + row;
- painter.setPen( this->palette().color(QPalette::WindowText));
+
+ forceDarkColor = false;
if ( asmPC != NULL )
{
if ( l == asmPC->line )
{
painter.fillRect( 0, y - pxLineSpacing + pxLineLead, viewWidth, pxLineSpacing, QColor("pink") );
+ forceDarkColor = true;
}
}
@@ -3113,25 +3968,34 @@ void QAsmView::paintEvent(QPaintEvent *event)
if ( asmEntry[l]->type != dbg_asm_entry_t::ASM_TEXT )
{
painter.fillRect( 0, y - pxLineSpacing + pxLineLead, viewWidth, pxLineSpacing, QColor("light blue") );
+ forceDarkColor = true;
}
- painter.drawText( x, y, tr(asmEntry[l]->text.c_str()) );
- if ( selAddr == asmEntry[l]->addr )
+ if ( forceDarkColor )
+ {
+ painter.setPen( black );
+ }
+ else
+ {
+ painter.setPen( this->palette().color(QPalette::WindowText));
+ }
+ drawText( &painter, x, y, asmEntry[l]->text.c_str() );
+
+ if ( (selAddrLine == l) )
{ // Highlight ASM line for selected address.
- if ( !displayROMoffsets && (asmEntry[l]->type == dbg_asm_entry_t::ASM_TEXT) )
+ if ( !txtHlgtSet && (selAddr == selAddrValue) &&
+ (asmEntry[l]->text.size() >= (selAddrChar + selAddrWidth) ) &&
+ ( asmEntry[l]->text.compare( selAddrChar, selAddrWidth, selAddrText ) == 0 ) )
{
int ax;
- char addrString[16];
- ax = 4*pxCharWidth;
+ ax = x + selAddrChar*pxCharWidth;
- painter.fillRect( ax, y - pxLineSpacing + pxLineLead, 4*pxCharWidth, pxLineSpacing, QColor("blue") );
+ painter.fillRect( ax, y - pxLineSpacing + pxLineLead, selAddrWidth*pxCharWidth, pxLineSpacing, blue );
- sprintf( addrString, "%04X", selAddr );
+ painter.setPen( white );
- painter.setPen( this->palette().color(QPalette::Background));
-
- painter.drawText( ax, y, tr(addrString) );
+ drawText( &painter, ax, y, selAddrText );
painter.setPen( this->palette().color(QPalette::WindowText));
}
@@ -3139,6 +4003,56 @@ void QAsmView::paintEvent(QPaintEvent *event)
}
y += pxLineSpacing;
}
+
+ y = pxLineSpacing;
+
+ painter.setPen( hlgtFG );
+
+ if ( txtHlgtSet )
+ {
+ for (row=0; row < nrow; row++)
+ {
+ x = -pxLineXScroll;
+ l = lineOffset + row;
+
+ if ( (l >= txtHlgtStartLine) && (l <= txtHlgtEndLine) )
+ {
+ int ax, hlgtXs, hlgtXe, hlgtXd;
+ std::string s;
+
+ if ( l == txtHlgtStartLine )
+ {
+ hlgtXs = txtHlgtStartChar;
+ }
+ else
+ {
+ hlgtXs = 0;
+ }
+
+ if ( l == txtHlgtEndLine )
+ {
+ hlgtXe = txtHlgtEndChar;
+ }
+ else
+ {
+ hlgtXe = (viewWidth / pxCharWidth) + 1;
+ }
+ hlgtXd = (hlgtXe - hlgtXs);
+
+ if ( hlgtXs < asmEntry[l]->text.size() )
+ {
+ s = asmEntry[l]->text.substr( hlgtXs, hlgtXd );
+ }
+
+ ax = x + (hlgtXs * pxCharWidth);
+
+ painter.fillRect( ax, y - pxLineSpacing + pxLineLead, hlgtXd * pxCharWidth, pxLineSpacing, hlgtBG );
+
+ drawText( &painter, ax, y, s.c_str() );
+ }
+ y += pxLineSpacing;
+ }
+ }
}
//----------------------------------------------------------------------------
// Bookmark Manager Methods
@@ -3274,3 +4188,164 @@ debuggerBookmark_t *debuggerBookmarkManager_t::getAddr( int addr )
return NULL;
}
//----------------------------------------------------------------------------
+DebuggerStackDisplay::DebuggerStackDisplay(QWidget *parent)
+ : QPlainTextEdit(parent)
+{
+ stackBytesPerLine = 4;
+ showAddrs = true;
+}
+//----------------------------------------------------------------------------
+DebuggerStackDisplay::~DebuggerStackDisplay(void)
+{
+
+}
+//----------------------------------------------------------------------------
+void DebuggerStackDisplay::keyPressEvent(QKeyEvent *event)
+{
+ //printf("Debug Stack Window Key Press: 0x%x \n", event->key() );
+
+ if ( (event->key() >= Qt::Key_1) && ( (event->key() < Qt::Key_9) ) )
+ {
+ stackBytesPerLine = event->key() - Qt::Key_0;
+ updateText();
+ }
+ else if ( event->key() == Qt::Key_A )
+ {
+ showAddrs = !showAddrs;
+ updateText();
+ }
+}
+//----------------------------------------------------------------------------
+void DebuggerStackDisplay::contextMenuEvent(QContextMenuEvent *event)
+{
+ QAction *act;
+ QMenu menu(this);
+ QMenu *subMenu;
+ QActionGroup *group;
+ QAction *bytesPerLineAct[4];
+
+ act = new QAction(tr("Show Addresses"), &menu);
+ act->setCheckable(true);
+ act->setChecked(showAddrs);
+ connect( act, SIGNAL(triggered(void)), this, SLOT(toggleShowAddr(void)) );
+
+ menu.addAction( act );
+
+ subMenu = menu.addMenu(tr("Display Bytes Per Line"));
+ group = new QActionGroup(&menu);
+
+ group->setExclusive(true);
+
+ for (int i=0; i<4; i++)
+ {
+ char stmp[8];
+
+ sprintf( stmp, "%i", i+1 );
+
+ bytesPerLineAct[i] = new QAction(tr(stmp), &menu);
+ bytesPerLineAct[i]->setCheckable(true);
+
+ group->addAction(bytesPerLineAct[i]);
+ subMenu->addAction(bytesPerLineAct[i]);
+
+ bytesPerLineAct[i]->setChecked( stackBytesPerLine == (i+1) );
+ }
+
+ connect( bytesPerLineAct[0], SIGNAL(triggered(void)), this, SLOT(sel1BytePerLine(void)) );
+ connect( bytesPerLineAct[1], SIGNAL(triggered(void)), this, SLOT(sel2BytesPerLine(void)) );
+ connect( bytesPerLineAct[2], SIGNAL(triggered(void)), this, SLOT(sel3BytesPerLine(void)) );
+ connect( bytesPerLineAct[3], SIGNAL(triggered(void)), this, SLOT(sel4BytesPerLine(void)) );
+
+ menu.exec(event->globalPos());
+}
+//----------------------------------------------------------------------------
+void DebuggerStackDisplay::toggleShowAddr(void)
+{
+ showAddrs = !showAddrs;
+
+ updateText();
+}
+//----------------------------------------------------------------------------
+void DebuggerStackDisplay::sel1BytePerLine(void)
+{
+ stackBytesPerLine = 1;
+ updateText();
+}
+//----------------------------------------------------------------------------
+void DebuggerStackDisplay::sel2BytesPerLine(void)
+{
+ stackBytesPerLine = 2;
+ updateText();
+}
+//----------------------------------------------------------------------------
+void DebuggerStackDisplay::sel3BytesPerLine(void)
+{
+ stackBytesPerLine = 3;
+ updateText();
+}
+//----------------------------------------------------------------------------
+void DebuggerStackDisplay::sel4BytesPerLine(void)
+{
+ stackBytesPerLine = 4;
+ updateText();
+}
+//----------------------------------------------------------------------------
+void DebuggerStackDisplay::updateText(void)
+{
+ char stmp[128];
+ int stackPtr = X.S | 0x0100;
+ std::string stackLine;
+
+ stackPtr++;
+
+ if ( stackPtr <= 0x01FF )
+ {
+ if ( showAddrs || (stackBytesPerLine <= 1) )
+ {
+ sprintf( stmp, "%03X: %02X", stackPtr, GetMem(stackPtr) );
+ }
+ else
+ {
+ sprintf( stmp, " %02X", GetMem(stackPtr) );
+ }
+
+ stackLine.assign( stmp );
+
+ for (int i = 1; i < 128; i++)
+ {
+ //tmp = ((tmp+1)|0x0100)&0x01FF; //increment and fix pointer to $0100-$01FF range
+ stackPtr++;
+ if (stackPtr > 0x1FF)
+ break;
+
+ if ( stackBytesPerLine > 1 )
+ {
+ if ((i % stackBytesPerLine) == 0)
+ {
+ if ( showAddrs )
+ {
+ sprintf( stmp, "\n%03X: %02X", stackPtr, GetMem(stackPtr) );
+ }
+ else
+ {
+ sprintf( stmp, "\n %02X", GetMem(stackPtr) );
+ }
+ }
+ else
+ {
+ sprintf( stmp, ",%02X", GetMem(stackPtr) );
+ }
+ }
+ else
+ {
+ sprintf( stmp, "\n%03X: %02X", stackPtr, GetMem(stackPtr) );
+ }
+ stackLine.append( stmp );
+
+ //printf("Stack $%X: %s\n", stackPtr, stmp );
+ }
+ }
+
+ setPlainText( tr(stackLine.c_str()) );
+}
+//----------------------------------------------------------------------------
diff --git a/src/drivers/Qt/ConsoleDebugger.h b/src/drivers/Qt/ConsoleDebugger.h
index 51b6d40c..20f9a1a4 100644
--- a/src/drivers/Qt/ConsoleDebugger.h
+++ b/src/drivers/Qt/ConsoleDebugger.h
@@ -22,6 +22,7 @@
#include
#include
#include
+#include
#include
#include "Qt/main.h"
@@ -37,6 +38,7 @@ struct dbg_asm_entry_t
int line;
uint8 opcode[3];
std::string text;
+ debugSymbol_t sym;
enum
{
@@ -110,23 +112,34 @@ class QAsmView : public QWidget
void setSymbolDebugEnable( bool value );
void setRegisterNameEnable( bool value );
int getCtxMenuAddr(void){ return ctxMenuAddr; };
+ int getCursorAddr(void){ return cursorLineAddr; };
+ void setPC_placement( int mode, int ofs = 0 );
+ void setBreakpointAtSelectedLine(void);
protected:
void paintEvent(QPaintEvent *event);
void keyPressEvent(QKeyEvent *event);
void keyReleaseEvent(QKeyEvent *event);
void mousePressEvent(QMouseEvent * event);
+ void mouseReleaseEvent(QMouseEvent * event);
void mouseMoveEvent(QMouseEvent * event);
void resizeEvent(QResizeEvent *event);
+ void wheelEvent(QWheelEvent *event);
void contextMenuEvent(QContextMenuEvent *event);
+ void loadHighlightToClipboard(void);
void calcFontData(void);
QPoint convPixToCursor( QPoint p );
+ bool textIsHighlighted(void);
+ void setHighlightEndCoord( int x, int y );
+ void loadClipboard( const char *txt );
+ void drawText( QPainter *painter, int x, int y, const char *txt );
private:
ConsoleDebugger *parent;
QFont font;
QScrollBar *vbar;
QScrollBar *hbar;
+ QClipboard *clipboard;
int ctxMenuAddr;
int maxLineLen;
@@ -144,13 +157,59 @@ class QAsmView : public QWidget
int pxLineXScroll;
int cursorPosX;
int cursorPosY;
+ int cursorLineAddr;
+ int pcLinePlacement;
+ int pcLineOffset;
+
+ int selAddrLine;
+ int selAddrChar;
+ int selAddrWidth;
+ int selAddrValue;
+ char selAddrText[128];
+
+ int txtHlgtAnchorChar;
+ int txtHlgtAnchorLine;
+ int txtHlgtStartChar;
+ int txtHlgtStartLine;
+ int txtHlgtEndChar;
+ int txtHlgtEndLine;
+
+ int wheelPixelCounter;
dbg_asm_entry_t *asmPC;
std::vector asmEntry;
+ bool useDarkTheme;
bool displayROMoffsets;
bool symbolicDebugEnable;
bool registerNameEnable;
+ bool mouseLeftBtnDown;
+
+};
+
+class DebuggerStackDisplay : public QPlainTextEdit
+{
+ Q_OBJECT
+
+ public:
+ DebuggerStackDisplay(QWidget *parent = 0);
+ ~DebuggerStackDisplay(void);
+
+ void updateText(void);
+
+ protected:
+ void keyPressEvent(QKeyEvent *event);
+ void contextMenuEvent(QContextMenuEvent *event);
+
+ int stackBytesPerLine;
+ bool showAddrs;
+
+ private slots:
+ void toggleShowAddr(void);
+ void sel1BytePerLine(void);
+ void sel2BytesPerLine(void);
+ void sel3BytesPerLine(void);
+ void sel4BytesPerLine(void);
};
class ConsoleDebugger : public QDialog
@@ -181,7 +240,7 @@ class ConsoleDebugger : public QDialog
QScrollBar *vbar;
QScrollBar *hbar;
QAsmView *asmView;
- QPlainTextEdit *stackText;
+ DebuggerStackDisplay *stackText;
QLineEdit *seekEntry;
QLineEdit *pcEntry;
QLineEdit *regAEntry;
@@ -239,6 +298,7 @@ class ConsoleDebugger : public QDialog
void asmViewCtxMenuAddBM(void);
void asmViewCtxMenuAddSym(void);
void asmViewCtxMenuOpenHexEdit(void);
+ void asmViewCtxMenuRunToCursor(void);
private slots:
void updatePeriodic(void);
void hbarChanged(int value);
@@ -247,6 +307,7 @@ class ConsoleDebugger : public QDialog
void debugStepIntoCB(void);
void debugStepOutCB(void);
void debugStepOverCB(void);
+ void debugRunToCursorCB(void);
void debugRunLineCB(void);
void debugRunLine128CB(void);
void seekToCB(void);
@@ -273,6 +334,12 @@ class ConsoleDebugger : public QDialog
void cpuCycleThresChanged(const QString &txt);
void instructionsThresChanged(const QString &txt);
void selBmAddrChanged(const QString &txt);
+ void pcSetPlaceTop(void);
+ void pcSetPlaceUpperMid(void);
+ void pcSetPlaceCenter(void);
+ void pcSetPlaceLowerMid(void);
+ void pcSetPlaceBottom(void);
+ void pcSetPlaceCustom(void);
};
diff --git a/src/drivers/Qt/ConsoleUtilities.cpp b/src/drivers/Qt/ConsoleUtilities.cpp
index 9bedc75f..b1f70f20 100644
--- a/src/drivers/Qt/ConsoleUtilities.cpp
+++ b/src/drivers/Qt/ConsoleUtilities.cpp
@@ -38,17 +38,52 @@ int getDirFromFile( const char *path, char *dir )
//---------------------------------------------------------------------------
const char *getRomFile( void )
{
+ static char filePath[2048];
+
if ( GameInfo )
{
- return GameInfo->filename;
+ //printf("filename: '%s' \n", GameInfo->filename );
+ //printf("archiveFilename: '%s' \n", GameInfo->archiveFilename );
+
+ if ( GameInfo->archiveFilename != NULL )
+ {
+ char dir[1024], base[512], suffix[64];
+
+ parseFilepath( GameInfo->archiveFilename, dir, base, suffix );
+
+ filePath[0] = 0;
+
+ if ( dir[0] != 0 )
+ {
+ strcat( filePath, dir );
+ }
+
+ parseFilepath( GameInfo->filename, dir, base, suffix );
+
+ strcat( filePath, base );
+ strcat( filePath, suffix );
+
+ //printf("ArchivePath: '%s' \n", filePath );
+
+ return filePath;
+ }
+ else
+ {
+ return GameInfo->filename;
+ }
}
return NULL;
}
//---------------------------------------------------------------------------
// Return file base name stripping out preceding path and trailing suffix.
-int getFileBaseName( const char *filepath, char *base )
+int getFileBaseName( const char *filepath, char *base, char *suffix )
{
int i=0,j=0,end=0;
+
+ if ( suffix != NULL )
+ {
+ suffix[0] = 0;
+ }
if ( filepath == NULL )
{
base[0] = 0;
@@ -77,6 +112,10 @@ int getFileBaseName( const char *filepath, char *base )
j--;
if ( base[j] == '.' )
{
+ if ( suffix != NULL )
+ {
+ strcpy( suffix, &base[j] );
+ }
end=j; base[j] = 0; break;
}
}
@@ -86,6 +125,11 @@ int getFileBaseName( const char *filepath, char *base )
int parseFilepath( const char *filepath, char *dir, char *base, char *suffix )
{
int i=0,j=0,end=0;
+
+ if ( suffix != NULL )
+ {
+ suffix[0] = 0;
+ }
if ( filepath == NULL )
{
if ( dir ) dir[0] = 0;
@@ -145,3 +189,138 @@ int parseFilepath( const char *filepath, char *dir, char *base, char *suffix )
return end;
}
//---------------------------------------------------------------------------
+// FCEU Data Entry Custom Validators
+//---------------------------------------------------------------------------
+fceuDecIntValidtor::fceuDecIntValidtor( int min, int max, QObject *parent)
+ : QValidator(parent)
+{
+ this->min = min;
+ this->max = max;
+}
+//---------------------------------------------------------------------------
+void fceuDecIntValidtor::setMinMax( int min, int max)
+{
+ this->min = min;
+ this->max = max;
+}
+//---------------------------------------------------------------------------
+QValidator::State fceuDecIntValidtor::validate(QString &input, int &pos) const
+{
+ int i, v;
+ //printf("Validate: %i '%s'\n", input.size(), input.toStdString().c_str() );
+
+ if ( input.size() == 0 )
+ {
+ return QValidator::Acceptable;
+ }
+ std::string s = input.toStdString();
+ i=0;
+
+ if (s[i] == '-')
+ {
+ if ( min >= 0 )
+ {
+ return QValidator::Invalid;
+ }
+ i++;
+ }
+ else if ( s[i] == '+' )
+ {
+ i++;
+ }
+
+ if ( s[i] == 0 )
+ {
+ return QValidator::Acceptable;
+ }
+
+ if ( isdigit(s[i]) )
+ {
+ while ( isdigit(s[i]) ) i++;
+
+ if ( s[i] == 0 )
+ {
+ v = strtol( s.c_str(), NULL, 0 );
+
+ if ( v < min )
+ {
+ return QValidator::Invalid;
+ }
+ else if ( v > max )
+ {
+ return QValidator::Invalid;
+ }
+ return QValidator::Acceptable;
+ }
+ }
+ return QValidator::Invalid;
+}
+//---------------------------------------------------------------------------
+// FCEU Data Entry Custom Validators
+//---------------------------------------------------------------------------
+fceuHexIntValidtor::fceuHexIntValidtor( int min, int max, QObject *parent)
+ : QValidator(parent)
+{
+ this->min = min;
+ this->max = max;
+}
+//---------------------------------------------------------------------------
+void fceuHexIntValidtor::setMinMax( int min, int max)
+{
+ this->min = min;
+ this->max = max;
+}
+//---------------------------------------------------------------------------
+QValidator::State fceuHexIntValidtor::validate(QString &input, int &pos) const
+{
+ int i, v;
+ //printf("Validate: %i '%s'\n", input.size(), input.toStdString().c_str() );
+
+ if ( input.size() == 0 )
+ {
+ return QValidator::Acceptable;
+ }
+ input = input.toUpper();
+ std::string s = input.toStdString();
+ i=0;
+
+ if (s[i] == '-')
+ {
+ if ( min >= 0 )
+ {
+ return QValidator::Invalid;
+ }
+ i++;
+ }
+ else if ( s[i] == '+' )
+ {
+ i++;
+ }
+
+ if ( s[i] == 0 )
+ {
+ return QValidator::Acceptable;
+ }
+
+ if ( isxdigit(s[i]) )
+ {
+ while ( isxdigit(s[i]) ) i++;
+
+ if ( s[i] == 0 )
+ {
+ v = strtol( s.c_str(), NULL, 16 );
+
+ if ( v < min )
+ {
+ return QValidator::Invalid;
+ }
+ else if ( v > max )
+ {
+ return QValidator::Invalid;
+ }
+ return QValidator::Acceptable;
+ }
+ }
+ return QValidator::Invalid;
+}
+//---------------------------------------------------------------------------
diff --git a/src/drivers/Qt/ConsoleUtilities.h b/src/drivers/Qt/ConsoleUtilities.h
index 12838ddc..ca1221a8 100644
--- a/src/drivers/Qt/ConsoleUtilities.h
+++ b/src/drivers/Qt/ConsoleUtilities.h
@@ -1,9 +1,41 @@
// ConsoleUtilities.h
+#pragma once
+
+#include
+
int getDirFromFile( const char *path, char *dir );
const char *getRomFile( void );
-int getFileBaseName( const char *filepath, char *base );
+int getFileBaseName( const char *filepath, char *base, char *suffix = NULL );
int parseFilepath( const char *filepath, char *dir, char *base, char *suffix = NULL );
+
+
+class fceuDecIntValidtor : public QValidator
+{
+ public:
+ fceuDecIntValidtor( int min, int max, QObject *parent);
+
+ QValidator::State validate(QString &input, int &pos) const;
+
+ void setMinMax( int min, int max );
+ private:
+ int min;
+ int max;
+};
+
+class fceuHexIntValidtor : public QValidator
+{
+ public:
+ fceuHexIntValidtor( int min, int max, QObject *parent);
+
+ QValidator::State validate(QString &input, int &pos) const;
+
+ void setMinMax( int min, int max );
+ private:
+ int min;
+ int max;
+};
+
diff --git a/src/drivers/Qt/ConsoleVideoConf.cpp b/src/drivers/Qt/ConsoleVideoConf.cpp
index 1da2f639..8c82cf51 100644
--- a/src/drivers/Qt/ConsoleVideoConf.cpp
+++ b/src/drivers/Qt/ConsoleVideoConf.cpp
@@ -7,7 +7,9 @@
#include "Qt/dface.h"
#include "Qt/config.h"
#include "Qt/fceuWrapper.h"
+#include "Qt/ConsoleWindow.h"
#include "Qt/ConsoleVideoConf.h"
+#include "Qt/nes_shm.h"
//----------------------------------------------------
ConsoleVideoConfDialog_t::ConsoleVideoConfDialog_t(QWidget *parent)
@@ -17,6 +19,9 @@ ConsoleVideoConfDialog_t::ConsoleVideoConfDialog_t(QWidget *parent)
QHBoxLayout *hbox1;
QLabel *lbl;
QPushButton *button;
+ QStyle *style;
+
+ style = this->style();
setWindowTitle( tr("Video Config") );
@@ -37,11 +42,36 @@ ConsoleVideoConfDialog_t::ConsoleVideoConfDialog_t(QWidget *parent)
main_vbox->addLayout( hbox1 );
+ // Video Driver Select
+ lbl = new QLabel( tr("Scaler:") );
+
+ scalerSelect = new QComboBox();
+
+ scalerSelect->addItem( tr("None"), 0 );
+ scalerSelect->addItem( tr("hq2x"), 1 );
+ scalerSelect->addItem( tr("scale2x"), 2 );
+ scalerSelect->addItem( tr("NTSC 2x"), 3 );
+ scalerSelect->addItem( tr("hq3x"), 4 );
+ scalerSelect->addItem( tr("scale3x"), 5 );
+ scalerSelect->addItem( tr("Prescale 2x"), 6 );
+ scalerSelect->addItem( tr("Prescale 3x"), 7 );
+ scalerSelect->addItem( tr("Prescale 4x"), 8 );
+ scalerSelect->addItem( tr("PAL"), 9 );
+
+ hbox1 = new QHBoxLayout();
+
+ hbox1->addWidget( lbl );
+ hbox1->addWidget( scalerSelect );
+
+ main_vbox->addLayout( hbox1 );
+
// Enable OpenGL Linear Filter Checkbox
gl_LF_chkBox = new QCheckBox( tr("Enable OpenGL Linear Filter") );
setCheckBoxFromProperty( gl_LF_chkBox , "SDL.OpenGLip");
+ connect(gl_LF_chkBox , SIGNAL(stateChanged(int)), this, SLOT(openGL_linearFilterChanged(int)) );
+
main_vbox->addWidget( gl_LF_chkBox );
// Region Select
@@ -55,9 +85,11 @@ ConsoleVideoConfDialog_t::ConsoleVideoConfDialog_t(QWidget *parent)
setComboBoxFromProperty( regionSelect, "SDL.PAL");
setComboBoxFromProperty( driverSelect, "SDL.VideoDriver");
+ setComboBoxFromProperty( scalerSelect, "SDL.SpecialFilter");
connect(regionSelect, SIGNAL(currentIndexChanged(int)), this, SLOT(regionChanged(int)) );
connect(driverSelect, SIGNAL(currentIndexChanged(int)), this, SLOT(driverChanged(int)) );
+ connect(scalerSelect, SIGNAL(currentIndexChanged(int)), this, SLOT(scalerChanged(int)) );
hbox1 = new QHBoxLayout();
@@ -81,32 +113,106 @@ ConsoleVideoConfDialog_t::ConsoleVideoConfDialog_t(QWidget *parent)
// Show FPS Checkbox
showFPS_cbx = new QCheckBox( tr("Show FPS") );
+ // Auto Scale on Resize
+ autoScaleCbx = new QCheckBox( tr("Auto Scale on Resize") );
+
+ // Square Pixels
+ sqrPixCbx = new QCheckBox( tr("Square Pixels") );
+
setCheckBoxFromProperty( new_PPU_ena , "SDL.NewPPU");
setCheckBoxFromProperty( frmskipcbx , "SDL.Frameskip");
setCheckBoxFromProperty( sprtLimCbx , "SDL.DisableSpriteLimit");
setCheckBoxFromProperty( clipSidesCbx , "SDL.ClipSides");
setCheckBoxFromProperty( showFPS_cbx , "SDL.ShowFPS");
+
+ if ( consoleWindow )
+ {
+ if ( consoleWindow->viewport_GL )
+ {
+ autoScaleCbx->setChecked( consoleWindow->viewport_GL->getAutoScaleOpt() );
+ sqrPixCbx->setChecked( consoleWindow->viewport_GL->getSqrPixelOpt() );
+ }
+ else if ( consoleWindow->viewport_SDL )
+ {
+ autoScaleCbx->setChecked( consoleWindow->viewport_SDL->getAutoScaleOpt() );
+ sqrPixCbx->setChecked( consoleWindow->viewport_SDL->getSqrPixelOpt() );
+ }
+ }
connect(new_PPU_ena , SIGNAL(stateChanged(int)), this, SLOT(use_new_PPU_changed(int)) );
connect(frmskipcbx , SIGNAL(stateChanged(int)), this, SLOT(frameskip_changed(int)) );
connect(sprtLimCbx , SIGNAL(stateChanged(int)), this, SLOT(useSpriteLimitChanged(int)) );
connect(clipSidesCbx, SIGNAL(stateChanged(int)), this, SLOT(clipSidesChanged(int)) );
connect(showFPS_cbx , SIGNAL(stateChanged(int)), this, SLOT(showFPSChanged(int)) );
+ connect(sqrPixCbx , SIGNAL(stateChanged(int)), this, SLOT(sqrPixChanged(int)) );
main_vbox->addWidget( new_PPU_ena );
main_vbox->addWidget( frmskipcbx );
main_vbox->addWidget( sprtLimCbx );
main_vbox->addWidget( clipSidesCbx);
main_vbox->addWidget( showFPS_cbx );
+ main_vbox->addWidget( autoScaleCbx);
+ main_vbox->addWidget( sqrPixCbx );
+
+ xScaleBox = new QDoubleSpinBox(this);
+ yScaleBox = new QDoubleSpinBox(this);
+
+ xScaleBox->setRange( 1.0, 16.0 );
+ yScaleBox->setRange( 1.0, 16.0 );
+
+ xScaleBox->setSingleStep( 0.10 );
+ yScaleBox->setSingleStep( 0.10 );
+
+ if ( consoleWindow )
+ {
+ if ( consoleWindow->viewport_GL )
+ {
+ xScaleBox->setValue( consoleWindow->viewport_GL->getScaleX() );
+ yScaleBox->setValue( consoleWindow->viewport_GL->getScaleY() );
+ }
+ else if ( consoleWindow->viewport_SDL )
+ {
+ xScaleBox->setValue( consoleWindow->viewport_SDL->getScaleX() );
+ yScaleBox->setValue( consoleWindow->viewport_SDL->getScaleY() );
+ }
+ }
+
+ if ( sqrPixCbx->isChecked() )
+ {
+ xScaleLabel = new QLabel( tr("Scale:") );
+ }
+ else
+ {
+ xScaleLabel = new QLabel( tr("X Scale:") );
+ }
+ yScaleLabel = new QLabel( tr("Y Scale:") );
+
+ hbox1 = new QHBoxLayout();
+ hbox1->addWidget( xScaleLabel );
+ hbox1->addWidget( xScaleBox );
+ main_vbox->addLayout( hbox1 );
+
+ hbox1 = new QHBoxLayout();
+ hbox1->addWidget( yScaleLabel );
+ hbox1->addWidget( yScaleBox );
+ main_vbox->addLayout( hbox1 );
+
+ if ( sqrPixCbx->isChecked() )
+ {
+ yScaleLabel->hide();
+ yScaleBox->hide();
+ }
hbox1 = new QHBoxLayout();
button = new QPushButton( tr("Apply") );
hbox1->addWidget( button );
connect(button, SIGNAL(clicked()), this, SLOT(applyChanges(void)) );
+ button->setIcon( style->standardIcon( QStyle::SP_DialogApplyButton ) );
button = new QPushButton( tr("Close") );
hbox1->addWidget( button );
+ button->setIcon( style->standardIcon( QStyle::SP_DialogCloseButton ) );
connect(button, SIGNAL(clicked()), this, SLOT(closeWindow(void)) );
main_vbox->addLayout( hbox1 );
@@ -138,8 +244,10 @@ void ConsoleVideoConfDialog_t::closeWindow(void)
//----------------------------------------------------
void ConsoleVideoConfDialog_t::resetVideo(void)
{
+ fceuWrapperLock();
KillVideo ();
InitVideo (GameInfo);
+ fceuWrapperUnLock();
}
//----------------------------------------------------
void ConsoleVideoConfDialog_t::setCheckBoxFromProperty( QCheckBox *cbx, const char *property )
@@ -164,6 +272,25 @@ void ConsoleVideoConfDialog_t::setComboBoxFromProperty( QComboBox *cbx, const c
}
}
//----------------------------------------------------
+void ConsoleVideoConfDialog_t::openGL_linearFilterChanged( int value )
+{
+ bool opt = (value != Qt::Unchecked);
+ g_config->setOption("SDL.OpenGLip", opt );
+ g_config->save ();
+
+ if ( consoleWindow != NULL )
+ {
+ if ( consoleWindow->viewport_GL )
+ {
+ consoleWindow->viewport_GL->setLinearFilterEnable( opt );
+ }
+ if ( consoleWindow->viewport_SDL )
+ {
+ consoleWindow->viewport_SDL->setLinearFilterEnable( opt );
+ }
+ }
+}
+//----------------------------------------------------
void ConsoleVideoConfDialog_t::use_new_PPU_changed( int value )
{
//printf("Value:%i \n", value );
@@ -219,6 +346,26 @@ void ConsoleVideoConfDialog_t::showFPSChanged( int value )
fceuWrapperUnLock();
}
//----------------------------------------------------
+void ConsoleVideoConfDialog_t::sqrPixChanged( int value )
+{
+ //printf("Value:%i \n", value );
+ int useSqrPix = (value != Qt::Unchecked);
+
+ if ( useSqrPix )
+ {
+ xScaleLabel->setText( tr("Scale:") );
+ yScaleLabel->hide();
+ yScaleBox->hide();
+ }
+ else
+ {
+ xScaleLabel->setText( tr("X Scale:") );
+ yScaleLabel->show();
+ yScaleBox->show();
+ }
+
+}
+//----------------------------------------------------
void ConsoleVideoConfDialog_t::driverChanged(int index)
{
int driver;
@@ -233,6 +380,18 @@ void ConsoleVideoConfDialog_t::driverChanged(int index)
printf("Note: A restart of the application is needed for video driver change to take effect...\n");
}
//----------------------------------------------------
+void ConsoleVideoConfDialog_t::scalerChanged(int index)
+{
+ int scaler;
+ //printf("Scaler: %i : %i \n", index, scalerSelect->itemData(index).toInt() );
+
+ scaler = scalerSelect->itemData(index).toInt();
+
+ g_config->setOption ("SDL.SpecialFilter", scaler);
+
+ g_config->save ();
+}
+//----------------------------------------------------
void ConsoleVideoConfDialog_t::regionChanged(int index)
{
int region;
@@ -250,8 +409,88 @@ void ConsoleVideoConfDialog_t::regionChanged(int index)
fceuWrapperUnLock();
}
//----------------------------------------------------
+QSize ConsoleVideoConfDialog_t::calcNewScreenSize(void)
+{
+ QSize out( GL_NES_WIDTH, GL_NES_HEIGHT );
+
+ if ( consoleWindow )
+ {
+ QSize w, v;
+ double xscale, yscale;
+ int texture_width = nes_shm->video.ncol;
+ int texture_height = nes_shm->video.nrow;
+ int l=0, r=texture_width;
+ int t=0, b=texture_height;
+ int dw=0, dh=0, rw, rh;
+
+ w = consoleWindow->size();
+
+ if ( consoleWindow->viewport_GL )
+ {
+ v = consoleWindow->viewport_GL->size();
+ }
+ else if ( consoleWindow->viewport_SDL )
+ {
+ v = consoleWindow->viewport_SDL->size();
+ }
+
+ dw = w.width() - v.width();
+ dh = w.height() - v.height();
+
+ if ( sqrPixCbx->isChecked() )
+ {
+ xscale = xScaleBox->value();
+
+ yscale = xscale * (double)nes_shm->video.xyRatio;
+ }
+ else
+ {
+ xscale = xScaleBox->value();
+ yscale = yScaleBox->value();
+ }
+ rw=(int)((r-l)*xscale);
+ rh=(int)((b-t)*yscale);
+
+ out.setWidth( rw + dw );
+ out.setHeight( rh + dh );
+ }
+ return out;
+}
+//----------------------------------------------------
void ConsoleVideoConfDialog_t::applyChanges( void )
{
resetVideo();
+
+ if ( consoleWindow )
+ {
+ float xscale, yscale;
+ QSize s = calcNewScreenSize();
+
+ if ( sqrPixCbx->isChecked() )
+ {
+ yscale = xscale = xScaleBox->value();
+ }
+ else
+ {
+ xscale = xScaleBox->value();
+ yscale = yScaleBox->value();
+ }
+
+ if ( consoleWindow->viewport_GL )
+ {
+ consoleWindow->viewport_GL->setSqrPixelOpt( sqrPixCbx->isChecked() );
+ consoleWindow->viewport_GL->setAutoScaleOpt( autoScaleCbx->isChecked() );
+ consoleWindow->viewport_GL->setScaleXY( xscale, yscale );
+ }
+ if ( consoleWindow->viewport_SDL )
+ {
+ consoleWindow->viewport_SDL->setSqrPixelOpt( sqrPixCbx->isChecked() );
+ consoleWindow->viewport_SDL->setAutoScaleOpt( autoScaleCbx->isChecked() );
+ consoleWindow->viewport_SDL->setScaleXY( xscale, yscale );
+ }
+
+ consoleWindow->resize( s );
+ }
+
}
//----------------------------------------------------
diff --git a/src/drivers/Qt/ConsoleVideoConf.h b/src/drivers/Qt/ConsoleVideoConf.h
index 73d86e76..d65b4628 100644
--- a/src/drivers/Qt/ConsoleVideoConf.h
+++ b/src/drivers/Qt/ConsoleVideoConf.h
@@ -15,6 +15,7 @@
#include
#include
#include
+#include
class ConsoleVideoConfDialog_t : public QDialog
{
@@ -28,6 +29,7 @@ class ConsoleVideoConfDialog_t : public QDialog
void closeEvent(QCloseEvent *bar);
QComboBox *driverSelect;
+ QComboBox *scalerSelect;
QComboBox *regionSelect;
QCheckBox *gl_LF_chkBox;
QCheckBox *new_PPU_ena;
@@ -35,17 +37,26 @@ class ConsoleVideoConfDialog_t : public QDialog
QCheckBox *sprtLimCbx;
QCheckBox *clipSidesCbx;
QCheckBox *showFPS_cbx;
+ QCheckBox *autoScaleCbx;
+ QCheckBox *sqrPixCbx;
+ QDoubleSpinBox *xScaleBox;
+ QDoubleSpinBox *yScaleBox;
+ QLabel *xScaleLabel;
+ QLabel *yScaleLabel;
void setCheckBoxFromProperty( QCheckBox *cbx, const char *property );
void setComboBoxFromProperty( QComboBox *cbx, const char *property );
//void setSliderFromProperty( QSlider *slider, QLabel *lbl, const char *property );
void resetVideo(void);
+ QSize calcNewScreenSize(void);
public slots:
void closeWindow(void);
private slots:
+ void openGL_linearFilterChanged( int value );
+ void sqrPixChanged( int value );
void use_new_PPU_changed( int value );
void frameskip_changed( int value );
void useSpriteLimitChanged( int value );
@@ -53,6 +64,7 @@ class ConsoleVideoConfDialog_t : public QDialog
void showFPSChanged( int value );
void regionChanged(int index);
void driverChanged(int index);
+ void scalerChanged(int index);
void applyChanges( void );
};
diff --git a/src/drivers/Qt/ConsoleViewerGL.cpp b/src/drivers/Qt/ConsoleViewerGL.cpp
index b4b19b4a..a64b7a18 100644
--- a/src/drivers/Qt/ConsoleViewerGL.cpp
+++ b/src/drivers/Qt/ConsoleViewerGL.cpp
@@ -7,8 +7,10 @@
#include
#include
+#include
#include "Qt/nes_shm.h"
+#include "Qt/fceuWrapper.h"
#include "Qt/ConsoleViewerGL.h"
extern unsigned int gui_draw_area_width;
@@ -22,15 +24,26 @@ ConsoleViewGL_t::ConsoleViewGL_t(QWidget *parent)
gltexture = 0;
devPixRatio = 1.0f;
linearFilter = false;
+ sqrPixels = true;
+ autoScaleEna = true;
+ xscale = 2.0;
+ yscale = 2.0;
+ sx = 0; sy = 0;
+ rw = 256;
+ rh = 240;
+ mouseButtonMask = 0;
- QScreen *screen = QGuiApplication::primaryScreen();
+ setMinimumWidth( GL_NES_WIDTH );
+ setMinimumHeight( GL_NES_HEIGHT );
- if ( screen != NULL )
- {
+ QScreen *screen = QGuiApplication::primaryScreen();
+
+ if ( screen != NULL )
+ {
devPixRatio = screen->devicePixelRatio();
- //printf("Ratio: %f \n", screen->devicePixelRatio() );
+ //printf("Ratio: %f \n", screen->devicePixelRatio() );
}
- localBufSize = GL_NES_WIDTH * GL_NES_HEIGHT * sizeof(uint32_t);
+ localBufSize = (4 * GL_NES_WIDTH) * (4 * GL_NES_HEIGHT) * sizeof(uint32_t);
localBuf = (uint32_t*)malloc( localBufSize );
@@ -38,6 +51,16 @@ ConsoleViewGL_t::ConsoleViewGL_t(QWidget *parent)
{
memset( localBuf, 0, localBufSize );
}
+
+ linearFilter = false;
+
+ if ( g_config )
+ {
+ int opt;
+ g_config->getOption("SDL.OpenGLip", &opt );
+
+ linearFilter = (opt) ? true : false;
+ }
}
ConsoleViewGL_t::~ConsoleViewGL_t(void)
@@ -69,6 +92,7 @@ int ConsoleViewGL_t::init( void )
void ConsoleViewGL_t::buildTextures(void)
{
+ int w, h;
glEnable(GL_TEXTURE_RECTANGLE);
if ( gltexture )
@@ -87,8 +111,11 @@ void ConsoleViewGL_t::buildTextures(void)
glTexParameteri( GL_TEXTURE_RECTANGLE, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE );
glTexParameteri( GL_TEXTURE_RECTANGLE, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE );
+ w = nes_shm->video.ncol;
+ h = nes_shm->video.nrow;
+
glTexImage2D( GL_TEXTURE_RECTANGLE, 0,
- GL_RGBA8, GL_NES_WIDTH, GL_NES_HEIGHT, 0,
+ GL_RGBA8, w, h, 0,
GL_BGRA, GL_UNSIGNED_BYTE, 0 );
}
@@ -122,33 +149,168 @@ void ConsoleViewGL_t::resizeGL(int w, int h)
buildTextures();
}
+void ConsoleViewGL_t::setLinearFilterEnable( bool ena )
+{
+ if ( linearFilter != ena )
+ {
+ linearFilter = ena;
+
+ buildTextures();
+ }
+}
+
+void ConsoleViewGL_t::setScaleXY( double xs, double ys )
+{
+ float xyRatio = (float)nes_shm->video.xyRatio;
+
+ xscale = xs;
+ yscale = ys;
+
+ if ( sqrPixels )
+ {
+ if ( (xscale*xyRatio) < yscale )
+ {
+ yscale = (xscale*xyRatio);
+ }
+ else
+ {
+ xscale = (yscale/xyRatio);
+ }
+ }
+}
+
void ConsoleViewGL_t::transfer2LocalBuffer(void)
{
- memcpy( localBuf, nes_shm->pixbuf, localBufSize );
+ int i=0, hq = 0;
+ int numPixels = nes_shm->video.ncol * nes_shm->video.nrow;
+ int cpSize = numPixels * 4;
+ uint8_t *src, *dest;
+
+ if ( cpSize > localBufSize )
+ {
+ cpSize = localBufSize;
+ }
+ src = (uint8_t*)nes_shm->pixbuf;
+ dest = (uint8_t*)localBuf;
+
+ hq = (nes_shm->video.preScaler == 1) || (nes_shm->video.preScaler == 4); // hq2x and hq3x
+
+ if ( hq )
+ {
+ for (i=0; ipixbuf, cpSize );
+ }
+}
+
+void ConsoleViewGL_t::mousePressEvent(QMouseEvent * event)
+{
+ //printf("Mouse Button Press: (%i,%i) %x %x\n",
+ // event->pos().x(), event->pos().y(), event->button(), event->buttons() );
+
+ mouseButtonMask = event->buttons();
+}
+
+void ConsoleViewGL_t::mouseReleaseEvent(QMouseEvent * event)
+{
+ //printf("Mouse Button Release: (%i,%i) %x %x\n",
+ // event->pos().x(), event->pos().y(), event->button(), event->buttons() );
+
+ mouseButtonMask = event->buttons();
+}
+
+bool ConsoleViewGL_t::getMouseButtonState( unsigned int btn )
+{
+ return (mouseButtonMask & btn) ? true : false;
+}
+
+void ConsoleViewGL_t::getNormalizedCursorPos( double &x, double &y )
+{
+ QPoint cursor;
+
+ cursor = QCursor::pos();
+
+ //printf("Global Cursor (%i,%i) \n", cursor.x(), cursor.y() );
+
+ cursor = mapFromGlobal( cursor );
+
+ //printf("Window Cursor (%i,%i) \n", cursor.x(), cursor.y() );
+
+ x = (double)(cursor.x() - sx) / (double)rw;
+ y = (double)(cursor.y() - sy) / (double)rh;
+
+ if ( x < 0.0 )
+ {
+ x = 0.0;
+ }
+ else if ( x > 1.0 )
+ {
+ x = 1.0;
+ }
+ if ( y < 0.0 )
+ {
+ y = 0.0;
+ }
+ else if ( y > 1.0 )
+ {
+ y = 1.0;
+ }
+ //printf("Normalized Cursor (%f,%f) \n", x, y );
}
void ConsoleViewGL_t::paintGL(void)
{
- int texture_width = nes_shm->ncol;
- int texture_height = nes_shm->nrow;
+ int texture_width = nes_shm->video.ncol;
+ int texture_height = nes_shm->video.nrow;
int l=0, r=texture_width;
int t=0, b=texture_height;
- float xscale = (float)view_width / (float)texture_width;
- float yscale = (float)view_height / (float)texture_height;
+ float xyRatio = (float)nes_shm->video.xyRatio;
+ float xscaleTmp = (float)(view_width) / (float)(texture_width);
+ float yscaleTmp = (float)(view_height) / (float)(texture_height);
- if (xscale < yscale )
+ if ( sqrPixels )
{
- yscale = xscale;
+ if ( (xscaleTmp*xyRatio) < yscaleTmp )
+ {
+ yscaleTmp = (xscaleTmp*xyRatio);
+ }
+ else
+ {
+ xscaleTmp = (yscaleTmp/xyRatio);
+ }
}
- else
+
+ if ( autoScaleEna )
{
- xscale = yscale;
+ xscale = xscaleTmp;
+ yscale = yscaleTmp;
}
- int rw=(int)((r-l)*xscale);
- int rh=(int)((b-t)*yscale);
- int sx=(view_width-rw)/2;
- int sy=(view_height-rh)/2;
+ else
+ {
+ if ( xscaleTmp > xscale )
+ {
+ xscaleTmp = xscale;
+ }
+ if ( yscaleTmp > yscale )
+ {
+ yscaleTmp = yscale;
+ }
+ }
+ rw=(int)((r-l)*xscaleTmp);
+ rh=(int)((b-t)*yscaleTmp);
+ sx=(view_width-rw)/2;
+ sy=(view_height-rh)/2;
glViewport(sx, sy, rw, rh);
@@ -166,7 +328,7 @@ void ConsoleViewGL_t::paintGL(void)
glBindTexture(GL_TEXTURE_RECTANGLE, gltexture);
glTexSubImage2D(GL_TEXTURE_RECTANGLE, 0,
- 0, 0, GL_NES_WIDTH, GL_NES_HEIGHT,
+ 0, 0, texture_width, texture_height,
GL_BGRA, GL_UNSIGNED_BYTE, localBuf );
glBegin(GL_QUADS);
diff --git a/src/drivers/Qt/ConsoleViewerGL.h b/src/drivers/Qt/ConsoleViewerGL.h
index b45ddcb4..af9ef37f 100644
--- a/src/drivers/Qt/ConsoleViewerGL.h
+++ b/src/drivers/Qt/ConsoleViewerGL.h
@@ -20,20 +20,44 @@ class ConsoleViewGL_t : public QOpenGLWidget, protected QOpenGLFunctions
void transfer2LocalBuffer(void);
+ void setLinearFilterEnable( bool ena );
+
+ bool getSqrPixelOpt(void){ return sqrPixels; };
+ void setSqrPixelOpt( bool val ){ sqrPixels = val; return; };
+ bool getAutoScaleOpt(void){ return autoScaleEna; };
+ void setAutoScaleOpt( bool val ){ autoScaleEna = val; return; };
+ double getScaleX(void){ return xscale; };
+ double getScaleY(void){ return yscale; };
+ void setScaleXY( double xs, double ys );
+ void getNormalizedCursorPos( double &x, double &y );
+ bool getMouseButtonState( unsigned int btn );
+
protected:
void initializeGL(void);
void resizeGL(int w, int h);
void paintGL(void);
+ void mousePressEvent(QMouseEvent * event);
+ void mouseReleaseEvent(QMouseEvent * event);
void buildTextures(void);
void calcPixRemap(void);
void doRemap(void);
double devPixRatio;
+ double xscale;
+ double yscale;
int view_width;
int view_height;
+ int sx;
+ int sy;
+ int rw;
+ int rh;
GLuint gltexture;
bool linearFilter;
+ bool sqrPixels;
+ bool autoScaleEna;
+
+ unsigned int mouseButtonMask;
uint32_t *localBuf;
uint32_t localBufSize;
diff --git a/src/drivers/Qt/ConsoleViewerSDL.cpp b/src/drivers/Qt/ConsoleViewerSDL.cpp
index 4f96346e..f76ab5c5 100644
--- a/src/drivers/Qt/ConsoleViewerSDL.cpp
+++ b/src/drivers/Qt/ConsoleViewerSDL.cpp
@@ -7,6 +7,7 @@
#include
#include "Qt/nes_shm.h"
+#include "Qt/fceuWrapper.h"
#include "Qt/ConsoleViewerSDL.h"
extern unsigned int gui_draw_area_width;
@@ -21,6 +22,9 @@ ConsoleViewSDL_t::ConsoleViewSDL_t(QWidget *parent)
setAutoFillBackground(true);
setPalette(pal);
+ setMinimumWidth( GL_NES_WIDTH );
+ setMinimumHeight( GL_NES_HEIGHT );
+
view_width = GL_NES_WIDTH;
view_height = GL_NES_HEIGHT;
@@ -29,6 +33,8 @@ ConsoleViewSDL_t::ConsoleViewSDL_t(QWidget *parent)
rh = view_height;
sdlRendW = 0;
sdlRendH = 0;
+ xscale = 2.0;
+ yscale = 2.0;
devPixRatio = 1.0f;
sdlWindow = NULL;
@@ -36,8 +42,9 @@ ConsoleViewSDL_t::ConsoleViewSDL_t(QWidget *parent)
sdlTexture = NULL;
vsyncEnabled = false;
+ mouseButtonMask = 0;
- localBufSize = GL_NES_WIDTH * GL_NES_HEIGHT * sizeof(uint32_t);
+ localBufSize = (4 * GL_NES_WIDTH) * (4 * GL_NES_HEIGHT) * sizeof(uint32_t);
localBuf = (uint32_t*)malloc( localBufSize );
@@ -46,6 +53,17 @@ ConsoleViewSDL_t::ConsoleViewSDL_t(QWidget *parent)
memset( localBuf, 0, localBufSize );
}
+ sqrPixels = true;
+ autoScaleEna = true;
+ linearFilter = false;
+
+ if ( g_config )
+ {
+ int opt;
+ g_config->getOption("SDL.OpenGLip", &opt );
+
+ linearFilter = (opt) ? true : false;
+ }
}
ConsoleViewSDL_t::~ConsoleViewSDL_t(void)
@@ -56,15 +74,83 @@ ConsoleViewSDL_t::~ConsoleViewSDL_t(void)
}
}
+void ConsoleViewSDL_t::setLinearFilterEnable( bool ena )
+{
+ if ( ena != linearFilter )
+ {
+ linearFilter = ena;
+
+ reset();
+ }
+}
+
+void ConsoleViewSDL_t::setScaleXY( double xs, double ys )
+{
+ float xyRatio = (float)nes_shm->video.xyRatio;
+
+ xscale = xs;
+ yscale = ys;
+
+ if ( sqrPixels )
+ {
+ if ( (xscale*xyRatio) < yscale )
+ {
+ yscale = (xscale*xyRatio);
+ }
+ else
+ {
+ xscale = (yscale/xyRatio);
+ }
+ }
+}
+
void ConsoleViewSDL_t::transfer2LocalBuffer(void)
{
- memcpy( localBuf, nes_shm->pixbuf, localBufSize );
+ int i=0, hq = 0;
+ int numPixels = nes_shm->video.ncol * nes_shm->video.nrow;
+ int cpSize = numPixels * 4;
+ uint8_t *src, *dest;
+
+ if ( cpSize > localBufSize )
+ {
+ cpSize = localBufSize;
+ }
+ src = (uint8_t*)nes_shm->pixbuf;
+ dest = (uint8_t*)localBuf;
+
+ hq = (nes_shm->video.preScaler == 1) || (nes_shm->video.preScaler == 4); // hq2x and hq3x
+
+ if ( hq )
+ {
+ for (i=0; ipixbuf, cpSize );
+ }
}
int ConsoleViewSDL_t::init(void)
{
WId windowHandle;
+ if ( linearFilter )
+ {
+ SDL_SetHint( SDL_HINT_RENDER_SCALE_QUALITY, "1" );
+ }
+ else
+ {
+ SDL_SetHint( SDL_HINT_RENDER_SCALE_QUALITY, "0" );
+ }
+
if (SDL_InitSubSystem(SDL_INIT_VIDEO) != 0)
{
printf("[SDL] Failed to initialize video subsystem.\n");
@@ -117,11 +203,11 @@ int ConsoleViewSDL_t::init(void)
printf("[SDL] Renderer Output Size: %i x %i \n", sdlRendW, sdlRendH );
- sdlTexture = SDL_CreateTexture(sdlRenderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING, GL_NES_WIDTH, GL_NES_HEIGHT);
+ sdlTexture = SDL_CreateTexture(sdlRenderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING, nes_shm->video.ncol, nes_shm->video.nrow);
if (sdlTexture == NULL)
{
- printf("[SDL] Failed to create texture: %i x %i", GL_NES_WIDTH, GL_NES_HEIGHT );
+ printf("[SDL] Failed to create texture: %i x %i", nes_shm->video.ncol, nes_shm->video.nrow );
return -1;
}
@@ -147,7 +233,7 @@ void ConsoleViewSDL_t::reset(void)
cleanup();
if ( init() == 0 )
{
- //console->GetVideoRenderer()->RegisterRenderingDevice(this);
+
}
else
{
@@ -165,41 +251,110 @@ void ConsoleViewSDL_t::resizeEvent(QResizeEvent *event)
printf("SDL Resize: %i x %i \n", view_width, view_height);
reset();
-
- //sdlViewport.x = sdlRendW - view_width;
- //sdlViewport.y = sdlRendH - view_height;
- //sdlViewport.w = view_width;
- //sdlViewport.h = view_height;
}
-//void ConsoleViewSDL_t::paintEvent( QPaintEvent *event )
+void ConsoleViewSDL_t::mousePressEvent(QMouseEvent * event)
+{
+ //printf("Mouse Button Press: (%i,%i) %x %x\n",
+ // event->pos().x(), event->pos().y(), event->button(), event->buttons() );
+
+ mouseButtonMask = event->buttons();
+}
+
+void ConsoleViewSDL_t::mouseReleaseEvent(QMouseEvent * event)
+{
+ //printf("Mouse Button Release: (%i,%i) %x %x\n",
+ // event->pos().x(), event->pos().y(), event->button(), event->buttons() );
+
+ mouseButtonMask = event->buttons();
+}
+
+bool ConsoleViewSDL_t::getMouseButtonState( unsigned int btn )
+{
+ return (mouseButtonMask & btn) ? true : false;
+}
+
+void ConsoleViewSDL_t::getNormalizedCursorPos( double &x, double &y )
+{
+ QPoint cursor;
+
+ cursor = QCursor::pos();
+
+ //printf("Global Cursor (%i,%i) \n", cursor.x(), cursor.y() );
+
+ cursor = mapFromGlobal( cursor );
+
+ //printf("Window Cursor (%i,%i) \n", cursor.x(), cursor.y() );
+
+ x = (double)(cursor.x() - sx) / (double)rw;
+ y = (double)(cursor.y() - sy) / (double)rh;
+
+ if ( x < 0.0 )
+ {
+ x = 0.0;
+ }
+ else if ( x > 1.0 )
+ {
+ x = 1.0;
+ }
+ if ( y < 0.0 )
+ {
+ y = 0.0;
+ }
+ else if ( y > 1.0 )
+ {
+ y = 1.0;
+ }
+ //printf("Normalized Cursor (%f,%f) \n", x, y );
+}
+
void ConsoleViewSDL_t::render(void)
{
int nesWidth = GL_NES_WIDTH;
int nesHeight = GL_NES_HEIGHT;
+ float xyRatio = 1.0;
if ( nes_shm != NULL )
{
- nesWidth = nes_shm->ncol;
- nesHeight = nes_shm->nrow;
+ nesWidth = nes_shm->video.ncol;
+ nesHeight = nes_shm->video.nrow;
+ xyRatio = (float)nes_shm->video.xyRatio;
}
//printf(" %i x %i \n", nesWidth, nesHeight );
- float xscale = (float)view_width / (float)nesWidth;
- float yscale = (float)view_height / (float)nesHeight;
+ float xscaleTmp = (float)view_width / (float)nesWidth;
+ float yscaleTmp = (float)view_height / (float)nesHeight;
- if (xscale < yscale )
+ if ( sqrPixels )
{
- yscale = xscale;
- }
- else
- {
- xscale = yscale;
+ if ( (xscaleTmp*xyRatio) < yscaleTmp )
+ {
+ yscaleTmp = (xscaleTmp*xyRatio);
+ }
+ else
+ {
+ xscaleTmp = (yscaleTmp/xyRatio);
+ }
}
- rw=(int)(nesWidth*xscale);
- rh=(int)(nesHeight*yscale);
- //sx=sdlViewport.x + (view_width-rw)/2;
- //sy=sdlViewport.y + (view_height-rh)/2;
+ if ( autoScaleEna )
+ {
+ xscale = xscaleTmp;
+ yscale = yscaleTmp;
+ }
+ else
+ {
+ if ( xscaleTmp > xscale )
+ {
+ xscaleTmp = xscale;
+ }
+ if ( yscaleTmp > yscale )
+ {
+ yscaleTmp = yscale;
+ }
+ }
+
+ rw=(int)(nesWidth*xscaleTmp);
+ rh=(int)(nesHeight*yscaleTmp);
sx=(view_width-rw)/2;
sy=(view_height-rh)/2;
@@ -216,12 +371,10 @@ void ConsoleViewSDL_t::render(void)
int rowPitch;
SDL_LockTexture( sdlTexture, nullptr, (void**)&textureBuffer, &rowPitch);
{
- memcpy( textureBuffer, localBuf, GL_NES_HEIGHT*GL_NES_WIDTH*sizeof(uint32_t) );
+ memcpy( textureBuffer, localBuf, nesWidth*nesHeight*sizeof(uint32_t) );
}
SDL_UnlockTexture(sdlTexture);
- //SDL_RenderSetViewport( sdlRenderer, &sdlViewport );
-
SDL_Rect source = {0, 0, nesWidth, nesHeight };
SDL_Rect dest = { sx, sy, rw, rh };
SDL_RenderCopy(sdlRenderer, sdlTexture, &source, &dest);
diff --git a/src/drivers/Qt/ConsoleViewerSDL.h b/src/drivers/Qt/ConsoleViewerSDL.h
index 45de62e7..db4079e6 100644
--- a/src/drivers/Qt/ConsoleViewerSDL.h
+++ b/src/drivers/Qt/ConsoleViewerSDL.h
@@ -23,25 +23,46 @@ class ConsoleViewSDL_t : public QWidget
void transfer2LocalBuffer(void);
+ void setLinearFilterEnable( bool ena );
+
+ bool getSqrPixelOpt(void){ return sqrPixels; };
+ void setSqrPixelOpt( bool val ){ sqrPixels = val; return; };
+ bool getAutoScaleOpt(void){ return autoScaleEna; };
+ void setAutoScaleOpt( bool val ){ autoScaleEna = val; return; };
+ double getScaleX(void){ return xscale; };
+ double getScaleY(void){ return yscale; };
+ void setScaleXY( double xs, double ys );
+ void getNormalizedCursorPos( double &x, double &y );
+ bool getMouseButtonState( unsigned int btn );
+
protected:
//void paintEvent(QPaintEvent *event);
void resizeEvent(QResizeEvent *event);
- int view_width;
- int view_height;
+ void mousePressEvent(QMouseEvent * event);
+ void mouseReleaseEvent(QMouseEvent * event);
- double devPixRatio;
- int rw;
- int rh;
- int sx;
- int sy;
- int sdlRendW;
- int sdlRendH;
+ int view_width;
+ int view_height;
- bool vsyncEnabled;
+ double devPixRatio;
+ double xscale;
+ double yscale;
+ int rw;
+ int rh;
+ int sx;
+ int sy;
+ int sdlRendW;
+ int sdlRendH;
- uint32_t *localBuf;
+ bool vsyncEnabled;
+ bool linearFilter;
+ bool sqrPixels;
+ bool autoScaleEna;
+
+ uint32_t *localBuf;
uint32_t localBufSize;
+ unsigned int mouseButtonMask;
SDL_Window *sdlWindow;
SDL_Renderer *sdlRenderer;
diff --git a/src/drivers/Qt/ConsoleWindow.cpp b/src/drivers/Qt/ConsoleWindow.cpp
index d4f7e723..df1220ff 100644
--- a/src/drivers/Qt/ConsoleWindow.cpp
+++ b/src/drivers/Qt/ConsoleWindow.cpp
@@ -1,10 +1,21 @@
// GameApp.cpp
//
+#ifdef __linux__
+#include
+#include
+#include
+#include
+#include
+#include
+#endif
+
#include
#include
#include
+#include
#include
#include
+#include
#include "../../fceu.h"
#include "../../fds.h"
@@ -18,12 +29,18 @@
#include "Qt/dface.h"
#include "Qt/input.h"
#include "Qt/ConsoleWindow.h"
+#include "Qt/InputConf.h"
#include "Qt/GamePadConf.h"
#include "Qt/HotKeyConf.h"
#include "Qt/PaletteConf.h"
#include "Qt/GuiConf.h"
+#include "Qt/MoviePlay.h"
+#include "Qt/MovieOptions.h"
+#include "Qt/TimingConf.h"
+#include "Qt/FrameTimingStats.h"
#include "Qt/LuaControl.h"
#include "Qt/CheatsConf.h"
+#include "Qt/GameGenie.h"
#include "Qt/HexEditor.h"
#include "Qt/TraceLogger.h"
#include "Qt/CodeDataLogger.h"
@@ -31,23 +48,42 @@
#include "Qt/ConsoleUtilities.h"
#include "Qt/ConsoleSoundConf.h"
#include "Qt/ConsoleVideoConf.h"
+#include "Qt/MsgLogViewer.h"
#include "Qt/AboutWindow.h"
#include "Qt/fceuWrapper.h"
+#include "Qt/ppuViewer.h"
+#include "Qt/NameTableViewer.h"
+#include "Qt/iNesHeaderEditor.h"
+#include "Qt/RamWatch.h"
+#include "Qt/RamSearch.h"
#include "Qt/keyscan.h"
#include "Qt/nes_shm.h"
consoleWin_t::consoleWin_t(QWidget *parent)
: QMainWindow( parent )
{
+ int opt;
int use_SDL_video = false;
+ int setFullScreen = false;
+
+ this->resize( 512, 512 );
+
+ g_config->getOption( "SDL.Fullscreen", &setFullScreen );
+ g_config->setOption( "SDL.Fullscreen", 0 ); // Reset full screen config parameter to false so it is never saved this way
+
+ if ( setFullScreen )
+ {
+ this->showFullScreen();
+ }
createMainMenu();
g_config->getOption( "SDL.VideoDriver", &use_SDL_video );
- errorMsgValid = false;
- viewport_GL = NULL;
- viewport_SDL = NULL;
+ closeRequested = false;
+ errorMsgValid = false;
+ viewport_GL = NULL;
+ viewport_SDL = NULL;
if ( use_SDL_video )
{
@@ -73,15 +109,30 @@ consoleWin_t::consoleWin_t(QWidget *parent)
connect( gameTimer, &QTimer::timeout, this, &consoleWin_t::updatePeriodic );
gameTimer->setTimerType( Qt::PreciseTimer );
- //gameTimer->start( 16 ); // 60hz
gameTimer->start( 8 ); // 120hz
emulatorThread->start();
+ g_config->getOption( "SDL.SetSchedParam", &opt );
+
+ if ( opt )
+ {
+ int policy, prio, nice;
+
+ g_config->getOption( "SDL.GuiSchedPolicy", &policy );
+ g_config->getOption( "SDL.GuiSchedPrioRt", &prio );
+ g_config->getOption( "SDL.GuiSchedNice" , &nice );
+
+ setNicePriority( nice );
+
+ setSchedParam( policy, prio );
+ }
}
consoleWin_t::~consoleWin_t(void)
{
+ QClipboard *clipboard;
+
nes_shm->runEmulator = 0;
gameTimer->stop();
@@ -110,6 +161,24 @@ consoleWin_t::~consoleWin_t(void)
// clear the NetworkIP field so this doesn't happen unintentionally
g_config->setOption ("SDL.NetworkIP", "");
g_config->save ();
+
+ // Clear Clipboard Contents on Program Exit
+ clipboard = QGuiApplication::clipboard();
+
+ if ( clipboard->ownsClipboard() )
+ {
+ clipboard->clear( QClipboard::Clipboard );
+ }
+ if ( clipboard->ownsSelection() )
+ {
+ clipboard->clear( QClipboard::Selection );
+ }
+
+ if ( this == consoleWindow )
+ {
+ consoleWindow = NULL;
+ }
+
}
void consoleWin_t::setCyclePeriodms( int ms )
@@ -150,6 +219,11 @@ void consoleWin_t::closeEvent(QCloseEvent *event)
closeApp();
}
+void consoleWin_t::requestClose(void)
+{
+ closeRequested = true;
+}
+
void consoleWin_t::keyPressEvent(QKeyEvent *event)
{
//printf("Key Press: 0x%x \n", event->key() );
@@ -165,9 +239,13 @@ void consoleWin_t::keyReleaseEvent(QKeyEvent *event)
//---------------------------------------------------------------------------
void consoleWin_t::createMainMenu(void)
{
+ QAction *act;
QMenu *subMenu;
QActionGroup *group;
int useNativeMenuBar;
+ QStyle *style;
+
+ style = this->style();
// This is needed for menu bar to show up on MacOS
g_config->getOption( "SDL.UseNativeMenuBar", &useNativeMenuBar );
@@ -182,6 +260,9 @@ void consoleWin_t::createMainMenu(void)
openROM = new QAction(tr("Open ROM"), this);
openROM->setShortcuts(QKeySequence::Open);
openROM->setStatusTip(tr("Open ROM File"));
+ //openROM->setIcon( QIcon(":icons/rom.png") );
+ //openROM->setIcon( style->standardIcon( QStyle::SP_FileIcon ) );
+ openROM->setIcon( style->standardIcon( QStyle::SP_FileDialogStart ) );
connect(openROM, SIGNAL(triggered()), this, SLOT(openROMFile(void)) );
fileMenu->addAction(openROM);
@@ -190,6 +271,7 @@ void consoleWin_t::createMainMenu(void)
closeROM = new QAction(tr("Close ROM"), this);
closeROM->setShortcut( QKeySequence(tr("Ctrl+C")));
closeROM->setStatusTip(tr("Close Loaded ROM"));
+ closeROM->setIcon( style->standardIcon( QStyle::SP_BrowserStop ) );
connect(closeROM, SIGNAL(triggered()), this, SLOT(closeROMCB(void)) );
fileMenu->addAction(closeROM);
@@ -210,6 +292,7 @@ void consoleWin_t::createMainMenu(void)
loadStateAct = new QAction(tr("Load State From"), this);
//loadStateAct->setShortcut( QKeySequence(tr("Ctrl+N")));
loadStateAct->setStatusTip(tr("Load State From"));
+ loadStateAct->setIcon( style->standardIcon( QStyle::SP_FileDialogStart ) );
connect(loadStateAct, SIGNAL(triggered()), this, SLOT(loadStateFrom(void)) );
fileMenu->addAction(loadStateAct);
@@ -218,6 +301,7 @@ void consoleWin_t::createMainMenu(void)
saveStateAct = new QAction(tr("Save State As"), this);
//loadStateAct->setShortcut( QKeySequence(tr("Ctrl+N")));
saveStateAct->setStatusTip(tr("Save State As"));
+ saveStateAct->setIcon( style->standardIcon( QStyle::SP_DialogSaveButton ) );
connect(saveStateAct, SIGNAL(triggered()), this, SLOT(saveStateAs(void)) );
fileMenu->addAction(saveStateAct);
@@ -276,6 +360,7 @@ void consoleWin_t::createMainMenu(void)
loadLuaAct = new QAction(tr("Load Lua Script"), this);
//loadLuaAct->setShortcut( QKeySequence(tr("F5")));
loadLuaAct->setStatusTip(tr("Load Lua Script"));
+ //loadLuaAct->setIcon( QIcon(":icons/lua-logo.png") );
connect(loadLuaAct, SIGNAL(triggered()), this, SLOT(loadLua(void)) );
fileMenu->addAction(loadLuaAct);
@@ -289,6 +374,7 @@ void consoleWin_t::createMainMenu(void)
scrShotAct = new QAction(tr("Screenshot"), this);
scrShotAct->setShortcut( QKeySequence(tr("F12")));
scrShotAct->setStatusTip(tr("Screenshot"));
+ scrShotAct->setIcon( QIcon(":icons/camera.png") );
connect(scrShotAct, SIGNAL(triggered()), this, SLOT(takeScreenShot()));
fileMenu->addAction(scrShotAct);
@@ -297,6 +383,8 @@ void consoleWin_t::createMainMenu(void)
quitAct = new QAction(tr("Quit"), this);
quitAct->setShortcut( QKeySequence(tr("Ctrl+Q")));
quitAct->setStatusTip(tr("Quit the Application"));
+ //quitAct->setIcon( style->standardIcon( QStyle::SP_DialogCloseButton ) );
+ quitAct->setIcon( QIcon(":icons/application-exit.png") );
connect(quitAct, SIGNAL(triggered()), this, SLOT(closeApp()));
fileMenu->addAction(quitAct);
@@ -305,10 +393,20 @@ void consoleWin_t::createMainMenu(void)
// Options
optMenu = menuBar()->addMenu(tr("Options"));
+ // Options -> Input Config
+ inputConfig = new QAction(tr("Input Config"), this);
+ //inputConfig->setShortcut( QKeySequence(tr("Ctrl+C")));
+ inputConfig->setStatusTip(tr("Input Configure"));
+ inputConfig->setIcon( QIcon(":icons/input-gaming.png") );
+ connect(inputConfig, SIGNAL(triggered()), this, SLOT(openInputConfWin(void)) );
+
+ optMenu->addAction(inputConfig);
+
// Options -> GamePad Config
gamePadConfig = new QAction(tr("GamePad Config"), this);
//gamePadConfig->setShortcut( QKeySequence(tr("Ctrl+C")));
gamePadConfig->setStatusTip(tr("GamePad Configure"));
+ gamePadConfig->setIcon( QIcon(":icons/input-gaming-symbolic.png") );
connect(gamePadConfig, SIGNAL(triggered()), this, SLOT(openGamePadConfWin(void)) );
optMenu->addAction(gamePadConfig);
@@ -317,6 +415,7 @@ void consoleWin_t::createMainMenu(void)
gameSoundConfig = new QAction(tr("Sound Config"), this);
//gameSoundConfig->setShortcut( QKeySequence(tr("Ctrl+C")));
gameSoundConfig->setStatusTip(tr("Sound Configure"));
+ gameSoundConfig->setIcon( style->standardIcon( QStyle::SP_MediaVolume ) );
connect(gameSoundConfig, SIGNAL(triggered()), this, SLOT(openGameSndConfWin(void)) );
optMenu->addAction(gameSoundConfig);
@@ -325,6 +424,7 @@ void consoleWin_t::createMainMenu(void)
gameVideoConfig = new QAction(tr("Video Config"), this);
//gameVideoConfig->setShortcut( QKeySequence(tr("Ctrl+C")));
gameVideoConfig->setStatusTip(tr("Video Preferences"));
+ gameVideoConfig->setIcon( style->standardIcon( QStyle::SP_ComputerIcon ) );
connect(gameVideoConfig, SIGNAL(triggered()), this, SLOT(openGameVideoConfWin(void)) );
optMenu->addAction(gameVideoConfig);
@@ -333,6 +433,7 @@ void consoleWin_t::createMainMenu(void)
hotkeyConfig = new QAction(tr("Hotkey Config"), this);
//hotkeyConfig->setShortcut( QKeySequence(tr("Ctrl+C")));
hotkeyConfig->setStatusTip(tr("Hotkey Configure"));
+ hotkeyConfig->setIcon( QIcon(":icons/input-keyboard.png") );
connect(hotkeyConfig, SIGNAL(triggered()), this, SLOT(openHotkeyConfWin(void)) );
optMenu->addAction(hotkeyConfig);
@@ -341,6 +442,7 @@ void consoleWin_t::createMainMenu(void)
paletteConfig = new QAction(tr("Palette Config"), this);
//paletteConfig->setShortcut( QKeySequence(tr("Ctrl+C")));
paletteConfig->setStatusTip(tr("Palette Configure"));
+ paletteConfig->setIcon( QIcon(":icons/graphics-palette.png") );
connect(paletteConfig, SIGNAL(triggered()), this, SLOT(openPaletteConfWin(void)) );
optMenu->addAction(paletteConfig);
@@ -349,10 +451,29 @@ void consoleWin_t::createMainMenu(void)
guiConfig = new QAction(tr("GUI Config"), this);
//guiConfig->setShortcut( QKeySequence(tr("Ctrl+C")));
guiConfig->setStatusTip(tr("GUI Configure"));
+ guiConfig->setIcon( style->standardIcon( QStyle::SP_TitleBarNormalButton ) );
connect(guiConfig, SIGNAL(triggered()), this, SLOT(openGuiConfWin(void)) );
optMenu->addAction(guiConfig);
+ // Options -> Timing Config
+ timingConfig = new QAction(tr("Timing Config"), this);
+ //timingConfig->setShortcut( QKeySequence(tr("Ctrl+C")));
+ timingConfig->setStatusTip(tr("Timing Configure"));
+ timingConfig->setIcon( QIcon(":icons/timer.png") );
+ connect(timingConfig, SIGNAL(triggered()), this, SLOT(openTimingConfWin(void)) );
+
+ optMenu->addAction(timingConfig);
+
+ // Options -> Movie Options
+ movieConfig = new QAction(tr("Movie Options"), this);
+ //movieConfig->setShortcut( QKeySequence(tr("Ctrl+C")));
+ movieConfig->setStatusTip(tr("Movie Options"));
+ movieConfig->setIcon( QIcon(":icons/movie.png") );
+ connect(movieConfig, SIGNAL(triggered()), this, SLOT(openMovieOptWin(void)) );
+
+ optMenu->addAction(movieConfig);
+
// Options -> Auto-Resume
autoResume = new QAction(tr("Auto-Resume Play"), this);
//autoResume->setShortcut( QKeySequence(tr("Ctrl+C")));
@@ -367,8 +488,9 @@ void consoleWin_t::createMainMenu(void)
// Options -> Full Screen
fullscreen = new QAction(tr("Fullscreen"), this);
fullscreen->setShortcut( QKeySequence(tr("Alt+Return")));
- //fullscreen->setCheckable(true);
fullscreen->setStatusTip(tr("Fullscreen"));
+ //fullscreen->setIcon( style->standardIcon( QStyle::SP_TitleBarMaxButton ) );
+ fullscreen->setIcon( QIcon(":icons/view-fullscreen.png") );
connect(fullscreen, SIGNAL(triggered()), this, SLOT(toggleFullscreen(void)) );
optMenu->addAction(fullscreen);
@@ -381,6 +503,7 @@ void consoleWin_t::createMainMenu(void)
powerAct = new QAction(tr("Power"), this);
//powerAct->setShortcut( QKeySequence(tr("Ctrl+P")));
powerAct->setStatusTip(tr("Power On Console"));
+ powerAct->setIcon( QIcon(":icons/power.png") );
connect(powerAct, SIGNAL(triggered()), this, SLOT(powerConsoleCB(void)) );
emuMenu->addAction(powerAct);
@@ -389,6 +512,7 @@ void consoleWin_t::createMainMenu(void)
resetAct = new QAction(tr("Reset"), this);
//resetAct->setShortcut( QKeySequence(tr("Ctrl+R")));
resetAct->setStatusTip(tr("Reset Console"));
+ resetAct->setIcon( style->standardIcon( QStyle::SP_DialogResetButton ) );
connect(resetAct, SIGNAL(triggered()), this, SLOT(consoleHardReset(void)) );
emuMenu->addAction(resetAct);
@@ -397,6 +521,7 @@ void consoleWin_t::createMainMenu(void)
sresetAct = new QAction(tr("Soft Reset"), this);
//sresetAct->setShortcut( QKeySequence(tr("Ctrl+R")));
sresetAct->setStatusTip(tr("Soft Reset of Console"));
+ sresetAct->setIcon( style->standardIcon( QStyle::SP_BrowserReload ) );
connect(sresetAct, SIGNAL(triggered()), this, SLOT(consoleSoftReset(void)) );
emuMenu->addAction(sresetAct);
@@ -405,6 +530,7 @@ void consoleWin_t::createMainMenu(void)
pauseAct = new QAction(tr("Pause"), this);
pauseAct->setShortcut( QKeySequence(tr("Pause")));
pauseAct->setStatusTip(tr("Pause Console"));
+ pauseAct->setIcon( style->standardIcon( QStyle::SP_MediaPause ) );
connect(pauseAct, SIGNAL(triggered()), this, SLOT(consolePause(void)) );
emuMenu->addAction(pauseAct);
@@ -469,6 +595,76 @@ void consoleWin_t::createMainMenu(void)
subMenu->addAction(fdsLoadBiosAct);
+ emuMenu->addSeparator();
+
+ // Emulation -> Speed
+ subMenu = emuMenu->addMenu(tr("Speed"));
+
+ // Emulation -> Speed -> Speed Up
+ act = new QAction(tr("Speed Up"), this);
+ act->setShortcut( QKeySequence(tr("=")));
+ act->setStatusTip(tr("Speed Up"));
+ act->setIcon( style->standardIcon( QStyle::SP_MediaSeekForward ) );
+ connect(act, SIGNAL(triggered()), this, SLOT(emuSpeedUp(void)) );
+
+ subMenu->addAction(act);
+
+ // Emulation -> Speed -> Slow Down
+ act = new QAction(tr("Slow Down"), this);
+ act->setShortcut( QKeySequence(tr("-")));
+ act->setStatusTip(tr("Slow Down"));
+ act->setIcon( style->standardIcon( QStyle::SP_MediaSeekBackward ) );
+ connect(act, SIGNAL(triggered()), this, SLOT(emuSlowDown(void)) );
+
+ subMenu->addAction(act);
+
+ subMenu->addSeparator();
+
+ // Emulation -> Speed -> Slowest Speed
+ act = new QAction(tr("Slowest"), this);
+ //act->setShortcut( QKeySequence(tr("-")));
+ act->setStatusTip(tr("Slowest"));
+ act->setIcon( style->standardIcon( QStyle::SP_MediaSkipBackward ) );
+ connect(act, SIGNAL(triggered()), this, SLOT(emuSlowestSpd(void)) );
+
+ subMenu->addAction(act);
+
+ // Emulation -> Speed -> Normal Speed
+ act = new QAction(tr("Normal"), this);
+ //act->setShortcut( QKeySequence(tr("-")));
+ act->setStatusTip(tr("Normal"));
+ act->setIcon( style->standardIcon( QStyle::SP_MediaPlay ) );
+ connect(act, SIGNAL(triggered()), this, SLOT(emuNormalSpd(void)) );
+
+ subMenu->addAction(act);
+
+ // Emulation -> Speed -> Fastest Speed
+ act = new QAction(tr("Turbo"), this);
+ //act->setShortcut( QKeySequence(tr("-")));
+ act->setStatusTip(tr("Turbo (Fastest)"));
+ act->setIcon( style->standardIcon( QStyle::SP_MediaSkipForward ) );
+ connect(act, SIGNAL(triggered()), this, SLOT(emuFastestSpd(void)) );
+
+ subMenu->addAction(act);
+
+ // Emulation -> Speed -> Custom Speed
+ act = new QAction(tr("Custom"), this);
+ //act->setShortcut( QKeySequence(tr("-")));
+ act->setStatusTip(tr("Custom"));
+ connect(act, SIGNAL(triggered()), this, SLOT(emuCustomSpd(void)) );
+
+ subMenu->addAction(act);
+
+ subMenu->addSeparator();
+
+ // Emulation -> Speed -> Set Frame Advance Delay
+ act = new QAction(tr("Set Frame Advance Delay"), this);
+ //act->setShortcut( QKeySequence(tr("-")));
+ act->setStatusTip(tr("Set Frame Advance Delay"));
+ connect(act, SIGNAL(triggered()), this, SLOT(emuSetFrameAdvDelay(void)) );
+
+ subMenu->addAction(act);
+
//-----------------------------------------------------------------------
// Tools
toolsMenu = menuBar()->addMenu(tr("Tools"));
@@ -481,6 +677,30 @@ void consoleWin_t::createMainMenu(void)
toolsMenu->addAction(cheatsAct);
+ // Tools -> RAM Search
+ ramSearchAct = new QAction(tr("RAM Search..."), this);
+ //ramSearchAct->setShortcut( QKeySequence(tr("Shift+F7")));
+ ramSearchAct->setStatusTip(tr("Open RAM Search Window"));
+ connect(ramSearchAct, SIGNAL(triggered()), this, SLOT(openRamSearch(void)) );
+
+ toolsMenu->addAction(ramSearchAct);
+
+ // Tools -> RAM Watch
+ ramWatchAct = new QAction(tr("RAM Watch..."), this);
+ //ramWatchAct->setShortcut( QKeySequence(tr("Shift+F7")));
+ ramWatchAct->setStatusTip(tr("Open RAM Watch Window"));
+ connect(ramWatchAct, SIGNAL(triggered()), this, SLOT(openRamWatch(void)) );
+
+ toolsMenu->addAction(ramWatchAct);
+
+ // Tools -> Frame Timing
+ act = new QAction(tr("Frame Timing ..."), this);
+ //act->setShortcut( QKeySequence(tr("Shift+F7")));
+ act->setStatusTip(tr("Open Frame Timing Window"));
+ connect(act, SIGNAL(triggered()), this, SLOT(openTimingStatWin(void)) );
+
+ toolsMenu->addAction(act);
+
//-----------------------------------------------------------------------
// Debug
debugMenu = menuBar()->addMenu(tr("Debug"));
@@ -501,6 +721,22 @@ void consoleWin_t::createMainMenu(void)
debugMenu->addAction(hexEditAct);
+ // Debug -> PPU Viewer
+ ppuViewAct = new QAction(tr("PPU Viewer..."), this);
+ //ppuViewAct->setShortcut( QKeySequence(tr("Shift+F7")));
+ ppuViewAct->setStatusTip(tr("Open PPU Viewer"));
+ connect(ppuViewAct, SIGNAL(triggered()), this, SLOT(openPPUViewer(void)) );
+
+ debugMenu->addAction(ppuViewAct);
+
+ // Debug -> Name Table Viewer
+ ntViewAct = new QAction(tr("Name Table Viewer..."), this);
+ //ntViewAct->setShortcut( QKeySequence(tr("Shift+F7")));
+ ntViewAct->setStatusTip(tr("Open Name Table Viewer"));
+ connect(ntViewAct, SIGNAL(triggered()), this, SLOT(openNTViewer(void)) );
+
+ debugMenu->addAction(ntViewAct);
+
// Debug -> Trace Logger
traceLogAct = new QAction(tr("Trace Logger..."), this);
//traceLogAct->setShortcut( QKeySequence(tr("Shift+F7")));
@@ -517,14 +753,31 @@ void consoleWin_t::createMainMenu(void)
debugMenu->addAction(codeDataLogAct);
+ // Debug -> Game Genie Encode/Decode Viewer
+ ggEncodeAct = new QAction(tr("Game Genie Encode/Decode"), this);
+ //ggEncodeAct->setShortcut( QKeySequence(tr("Shift+F7")));
+ ggEncodeAct->setStatusTip(tr("Open Game Genie Encode/Decode"));
+ connect(ggEncodeAct, SIGNAL(triggered()), this, SLOT(openGGEncoder(void)) );
+
+ debugMenu->addAction(ggEncodeAct);
+
+ // Debug -> iNES Header Editor
+ iNesEditAct = new QAction(tr("iNES Header Editor..."), this);
+ //iNesEditAct->setShortcut( QKeySequence(tr("Shift+F7")));
+ iNesEditAct->setStatusTip(tr("Open iNES Header Editor"));
+ connect(iNesEditAct, SIGNAL(triggered()), this, SLOT(openNesHeaderEditor(void)) );
+
+ debugMenu->addAction(iNesEditAct);
+
//-----------------------------------------------------------------------
// Movie
movieMenu = menuBar()->addMenu(tr("Movie"));
- // Movie -> Open
- openMovAct = new QAction(tr("Open"), this);
+ // Movie -> Play
+ openMovAct = new QAction(tr("Play"), this);
openMovAct->setShortcut( QKeySequence(tr("Shift+F7")));
- openMovAct->setStatusTip(tr("Open Movie File"));
+ openMovAct->setStatusTip(tr("Play Movie File"));
+ openMovAct->setIcon( style->standardIcon( QStyle::SP_MediaPlay ) );
connect(openMovAct, SIGNAL(triggered()), this, SLOT(openMovie(void)) );
movieMenu->addAction(openMovAct);
@@ -533,6 +786,7 @@ void consoleWin_t::createMainMenu(void)
stopMovAct = new QAction(tr("Stop"), this);
//stopMovAct->setShortcut( QKeySequence(tr("Shift+F7")));
stopMovAct->setStatusTip(tr("Stop Movie Recording"));
+ stopMovAct->setIcon( style->standardIcon( QStyle::SP_MediaStop ) );
connect(stopMovAct, SIGNAL(triggered()), this, SLOT(stopMovie(void)) );
movieMenu->addAction(stopMovAct);
@@ -543,6 +797,7 @@ void consoleWin_t::createMainMenu(void)
recMovAct = new QAction(tr("Record"), this);
recMovAct->setShortcut( QKeySequence(tr("Shift+F5")));
recMovAct->setStatusTip(tr("Record Movie"));
+ recMovAct->setIcon( QIcon(":icons/media-record.png") );
connect(recMovAct, SIGNAL(triggered()), this, SLOT(recordMovie(void)) );
movieMenu->addAction(recMovAct);
@@ -562,6 +817,7 @@ void consoleWin_t::createMainMenu(void)
// Help -> About FCEUX
aboutAct = new QAction(tr("About FCEUX"), this);
aboutAct->setStatusTip(tr("About FCEUX"));
+ aboutAct->setIcon( style->standardIcon( QStyle::SP_MessageBoxInformation ) );
connect(aboutAct, SIGNAL(triggered()), this, SLOT(aboutFCEUX(void)) );
helpMenu->addAction(aboutAct);
@@ -569,9 +825,18 @@ void consoleWin_t::createMainMenu(void)
// Help -> About Qt
aboutActQt = new QAction(tr("About Qt"), this);
aboutActQt->setStatusTip(tr("About Qt"));
+ aboutActQt->setIcon( style->standardIcon( QStyle::SP_TitleBarMenuButton ) );
connect(aboutActQt, SIGNAL(triggered()), this, SLOT(aboutQt(void)) );
helpMenu->addAction(aboutActQt);
+
+ // Help -> Message Log
+ msgLogAct = new QAction(tr("Message Log"), this);
+ msgLogAct->setStatusTip(tr("Message Log"));
+ msgLogAct->setIcon( style->standardIcon( QStyle::SP_MessageBoxWarning ) );
+ connect(msgLogAct, SIGNAL(triggered()), this, SLOT(openMsgLogWin(void)) );
+
+ helpMenu->addAction(msgLogAct);
};
//---------------------------------------------------------------------------
void consoleWin_t::closeApp(void)
@@ -594,6 +859,82 @@ void consoleWin_t::closeApp(void)
qApp->quit();
}
//---------------------------------------------------------------------------
+int consoleWin_t::showListSelectDialog( const char *title, std::vector &l )
+{
+ if ( QThread::currentThread() == emulatorThread )
+ {
+ printf("Cannot display list selection dialog from within emulation thread...\n");
+ return 0;
+ }
+ int ret, idx = 0;
+ QDialog dialog(this);
+ QVBoxLayout *mainLayout;
+ QHBoxLayout *hbox;
+ QPushButton *okButton, *cancelButton;
+ QTreeWidget *tree;
+ QTreeWidgetItem *item;
+
+ dialog.setWindowTitle( tr(title) );
+
+ tree = new QTreeWidget();
+
+ tree->setColumnCount(1);
+
+ item = new QTreeWidgetItem();
+ item->setText( 0, QString::fromStdString( "File" ) );
+ item->setTextAlignment( 0, Qt::AlignLeft);
+
+ tree->setHeaderItem( item );
+
+ tree->header()->setSectionResizeMode( QHeaderView::ResizeToContents );
+
+ for (size_t i=0; isetText( 0, QString::fromStdString( l[i] ) );
+
+ item->setTextAlignment( 0, Qt::AlignLeft);
+
+ tree->addTopLevelItem( item );
+ }
+
+ mainLayout = new QVBoxLayout();
+
+ hbox = new QHBoxLayout();
+ okButton = new QPushButton( tr("OK") );
+ cancelButton = new QPushButton( tr("Cancel") );
+
+ mainLayout->addWidget( tree );
+ mainLayout->addLayout( hbox );
+ hbox->addWidget( cancelButton );
+ hbox->addWidget( okButton );
+
+ connect( okButton, SIGNAL(clicked(void)), &dialog, SLOT(accept(void)) );
+ connect( cancelButton, SIGNAL(clicked(void)), &dialog, SLOT(reject(void)) );
+
+ dialog.setLayout( mainLayout );
+
+ ret = dialog.exec();
+
+ if ( ret == QDialog::Accepted )
+ {
+ idx = 0;
+
+ item = tree->currentItem();
+
+ if ( item != NULL )
+ {
+ idx = tree->indexOfTopLevelItem(item);
+ }
+ }
+ else
+ {
+ idx = -1;
+ }
+ return idx;
+}
+//---------------------------------------------------------------------------
void consoleWin_t::openROMFile(void)
{
@@ -603,12 +944,21 @@ void consoleWin_t::openROMFile(void)
char dir[512];
QFileDialog dialog(this, tr("Open ROM File") );
+ const QStringList filters(
+ { "All Useable files (*.nes *.NES *.nsf *.NSF *.fds *.FDS *.unf *.UNF *.unif *.UNIF *.zip *.ZIP)",
+ "NES files (*.nes *.NES)",
+ "NSF files (*.nsf *.NSF)",
+ "UNF files (*.unf *.UNF *.unif *.UNIF)",
+ "FDS files (*.fds *.FDS)",
+ "Any files (*)"
+ });
+
dialog.setFileMode(QFileDialog::ExistingFile);
- dialog.setNameFilter(tr("NES files (*.nes *.NES) ;; All files (*)"));
+ dialog.setNameFilters( filters );
dialog.setViewMode(QFileDialog::List);
- dialog.setFilter( QDir::AllEntries | QDir::Hidden );
+ dialog.setFilter( QDir::AllEntries | QDir::AllDirs | QDir::Hidden );
dialog.setLabelText( QFileDialog::Accept, tr("Open") );
g_config->getOption ("SDL.LastOpenFile", &last );
@@ -672,7 +1022,7 @@ void consoleWin_t::loadNSF(void)
dialog.setNameFilter(tr("NSF Sound Files (*.nsf *.NSF) ;; Zip Files (*.zip *.ZIP) ;; All files (*)"));
dialog.setViewMode(QFileDialog::List);
- dialog.setFilter( QDir::AllEntries | QDir::Hidden );
+ dialog.setFilter( QDir::AllEntries | QDir::AllDirs | QDir::Hidden );
dialog.setLabelText( QFileDialog::Accept, tr("Load") );
g_config->getOption ("SDL.LastOpenNSF", &last );
@@ -726,7 +1076,7 @@ void consoleWin_t::loadStateFrom(void)
dialog.setNameFilter(tr("FCS & SAV Files (*.sav *.SAV *.fc? *.FC?) ;; All files (*)"));
dialog.setViewMode(QFileDialog::List);
- dialog.setFilter( QDir::AllEntries | QDir::Hidden );
+ dialog.setFilter( QDir::AllEntries | QDir::AllDirs | QDir::Hidden );
dialog.setLabelText( QFileDialog::Accept, tr("Load") );
g_config->getOption ("SDL.LastLoadStateFrom", &last );
@@ -780,7 +1130,7 @@ void consoleWin_t::saveStateAs(void)
dialog.setNameFilter(tr("SAV Files (*.sav *.SAV) ;; All files (*)"));
dialog.setViewMode(QFileDialog::List);
- dialog.setFilter( QDir::AllEntries | QDir::Hidden );
+ dialog.setFilter( QDir::AllEntries | QDir::AllDirs | QDir::Hidden );
dialog.setLabelText( QFileDialog::Accept, tr("Save") );
dialog.setDefaultSuffix( tr(".sav") );
@@ -926,6 +1276,13 @@ void consoleWin_t::loadLua(void)
#endif
}
+void consoleWin_t::openInputConfWin(void)
+{
+ //printf("Open Input Config Window\n");
+
+ openInputConfWindow(this);
+}
+
void consoleWin_t::openGamePadConfWin(void)
{
//printf("Open GamePad Config Window\n");
@@ -988,15 +1345,61 @@ void consoleWin_t::openGuiConfWin(void)
guiConfWin->show();
}
+void consoleWin_t::openTimingConfWin(void)
+{
+ TimingConfDialog_t *tmConfWin;
+
+ //printf("Open Timing Config Window\n");
+
+ tmConfWin = new TimingConfDialog_t(this);
+
+ tmConfWin->show();
+}
+
+void consoleWin_t::openTimingStatWin(void)
+{
+ FrameTimingDialog_t *tmStatWin;
+
+ //printf("Open Timing Statistics Window\n");
+
+ tmStatWin = new FrameTimingDialog_t(this);
+
+ tmStatWin->show();
+}
+
+void consoleWin_t::openMovieOptWin(void)
+{
+ MovieOptionsDialog_t *win;
+
+ //printf("Open Movie Options Window\n");
+
+ win = new MovieOptionsDialog_t(this);
+
+ win->show();
+}
+
void consoleWin_t::openCheats(void)
{
- GuiCheatsDialog_t *cheatWin;
-
//printf("Open GUI Cheat Window\n");
- cheatWin = new GuiCheatsDialog_t(this);
+ openCheatDialog(this);
+}
+
+void consoleWin_t::openRamWatch(void)
+{
+ RamWatchDialog_t *ramWatchWin;
+
+ //printf("Open GUI RAM Watch Window\n");
- cheatWin->show();
+ ramWatchWin = new RamWatchDialog_t(this);
+
+ ramWatchWin->show();
+}
+
+void consoleWin_t::openRamSearch(void)
+{
+ //printf("Open GUI RAM Search Window\n");
+ openRamSearchWindow(this);
}
void consoleWin_t::openDebugWindow(void)
@@ -1021,6 +1424,20 @@ void consoleWin_t::openHexEditor(void)
hexEditWin->show();
}
+void consoleWin_t::openPPUViewer(void)
+{
+ //printf("Open GUI PPU Viewer Window\n");
+
+ openPPUViewWindow(this);
+}
+
+void consoleWin_t::openNTViewer(void)
+{
+ //printf("Open GUI Name Table Viewer Window\n");
+
+ openNameTableViewWindow(this);
+}
+
void consoleWin_t::openCodeDataLogger(void)
{
CodeDataLoggerDialog_t *cdlWin;
@@ -1032,6 +1449,35 @@ void consoleWin_t::openCodeDataLogger(void)
cdlWin->show();
}
+void consoleWin_t::openGGEncoder(void)
+{
+ GameGenieDialog_t *win;
+
+ //printf("Open Game Genie Window\n");
+
+ win = new GameGenieDialog_t(this);
+
+ win->show();
+}
+
+void consoleWin_t::openNesHeaderEditor(void)
+{
+ iNesHeaderEditor_t *win;
+
+ //printf("Open iNES Header Editor Window\n");
+
+ win = new iNesHeaderEditor_t(this);
+
+ if ( win->isInitialized() )
+ {
+ win->show();
+ }
+ else
+ {
+ delete win;
+ }
+}
+
void consoleWin_t::openTraceLogger(void)
{
openTraceLoggerWindow(this);
@@ -1116,7 +1562,7 @@ void consoleWin_t::loadGameGenieROM(void)
dialog.setNameFilter(tr("GG ROM File (gg.rom *Genie*.nes) ;; All files (*)"));
dialog.setViewMode(QFileDialog::List);
- dialog.setFilter( QDir::AllEntries | QDir::Hidden );
+ dialog.setFilter( QDir::AllEntries | QDir::AllDirs | QDir::Hidden );
dialog.setLabelText( QFileDialog::Accept, tr("Load") );
g_config->getOption ("SDL.LastOpenFile", &last );
@@ -1199,7 +1645,7 @@ void consoleWin_t::fdsLoadBiosFile(void)
dialog.setNameFilter(tr("ROM files (*.rom *.ROM) ;; All files (*)"));
dialog.setViewMode(QFileDialog::List);
- dialog.setFilter( QDir::AllEntries | QDir::Hidden );
+ dialog.setFilter( QDir::AllEntries | QDir::AllDirs | QDir::Hidden );
dialog.setLabelText( QFileDialog::Accept, tr("Load") );
g_config->getOption ("SDL.LastOpenFile", &last );
@@ -1253,68 +1699,84 @@ void consoleWin_t::fdsLoadBiosFile(void)
return;
}
+void consoleWin_t::emuSpeedUp(void)
+{
+ IncreaseEmulationSpeed();
+}
+
+void consoleWin_t::emuSlowDown(void)
+{
+ DecreaseEmulationSpeed();
+}
+
+void consoleWin_t::emuSlowestSpd(void)
+{
+ FCEUD_SetEmulationSpeed( EMUSPEED_SLOWEST );
+}
+
+void consoleWin_t::emuNormalSpd(void)
+{
+ FCEUD_SetEmulationSpeed( EMUSPEED_NORMAL );
+}
+
+void consoleWin_t::emuFastestSpd(void)
+{
+ FCEUD_SetEmulationSpeed( EMUSPEED_FASTEST );
+}
+
+void consoleWin_t::emuCustomSpd(void)
+{
+ int ret;
+ QInputDialog dialog(this);
+
+ dialog.setWindowTitle( tr("Emulation Speed") );
+ dialog.setLabelText( tr("Enter a percentage from 1 to 1000.") );
+ dialog.setOkButtonText( tr("Ok") );
+ dialog.setInputMode( QInputDialog::IntInput );
+ dialog.setIntRange( 1, 1000 );
+ dialog.setIntValue( 100 );
+
+ dialog.show();
+ ret = dialog.exec();
+
+ if ( QDialog::Accepted == ret )
+ {
+ int spdPercent;
+
+ spdPercent = dialog.intValue();
+
+ CustomEmulationSpeed( spdPercent );
+ }
+}
+
+void consoleWin_t::emuSetFrameAdvDelay(void)
+{
+ int ret;
+ QInputDialog dialog(this);
+
+ dialog.setWindowTitle( tr("Frame Advance Delay") );
+ dialog.setLabelText( tr("How much time should elapse before holding the frame advance unpauses the simulation?") );
+ dialog.setOkButtonText( tr("Ok") );
+ dialog.setInputMode( QInputDialog::IntInput );
+ dialog.setIntRange( 0, 1000 );
+ dialog.setIntValue( frameAdvance_Delay );
+
+ dialog.show();
+ ret = dialog.exec();
+
+ if ( QDialog::Accepted == ret )
+ {
+ frameAdvance_Delay = dialog.intValue();
+ }
+}
+
void consoleWin_t::openMovie(void)
{
- int ret, useNativeFileDialogVal;
- QString filename;
- std::string last;
- char dir[512];
- QFileDialog dialog(this, tr("Open FM2 Movie") );
+ MoviePlayDialog_t *win;
- dialog.setFileMode(QFileDialog::ExistingFile);
+ win = new MoviePlayDialog_t(this);
- dialog.setNameFilter(tr("FM2 Movies (*.fm2) ;; All files (*)"));
-
- dialog.setViewMode(QFileDialog::List);
- dialog.setFilter( QDir::AllEntries | QDir::Hidden );
- dialog.setLabelText( QFileDialog::Accept, tr("Open") );
-
- g_config->getOption ("SDL.LastOpenFile", &last );
-
- getDirFromFile( last.c_str(), dir );
-
- dialog.setDirectory( tr(dir) );
-
- // Check config option to use native file dialog or not
- g_config->getOption ("SDL.UseNativeFileDialog", &useNativeFileDialogVal);
-
- dialog.setOption(QFileDialog::DontUseNativeDialog, !useNativeFileDialogVal);
-
- dialog.show();
- ret = dialog.exec();
-
- if ( ret )
- {
- QStringList fileList;
- fileList = dialog.selectedFiles();
-
- if ( fileList.size() > 0 )
- {
- filename = fileList[0];
- }
- }
-
- if ( filename.isNull() )
- {
- return;
- }
- qDebug() << "selected file path : " << filename.toUtf8();
-
- int pauseframe;
- g_config->getOption ("SDL.PauseFrame", &pauseframe);
- g_config->setOption ("SDL.PauseFrame", 0);
-
- FCEUI_printf ("Playing back movie located at %s\n", filename.toStdString().c_str() );
-
- fceuWrapperLock();
- if (FCEUI_LoadMovie( filename.toStdString().c_str(),
- false, pauseframe ? pauseframe : false) == false)
- {
- printf("Error: Could not open movie file: %s \n", filename.toStdString().c_str() );
- }
- fceuWrapperUnLock();
-
- return;
+ win->show();
}
void consoleWin_t::stopMovie(void)
@@ -1351,10 +1813,10 @@ void consoleWin_t::recordMovieAs(void)
dialog.setNameFilter(tr("FM2 Movies (*.fm2) ;; All files (*)"));
dialog.setViewMode(QFileDialog::List);
- dialog.setFilter( QDir::AllEntries | QDir::Hidden );
+ dialog.setFilter( QDir::AllEntries | QDir::AllDirs | QDir::Hidden );
dialog.setLabelText( QFileDialog::Accept, tr("Save") );
- g_config->getOption ("SDL.LastOpenFile", &last );
+ g_config->getOption ("SDL.LastOpenMovie", &last );
getDirFromFile( last.c_str(), dir );
@@ -1423,6 +1885,171 @@ void consoleWin_t::aboutQt(void)
return;
}
+void consoleWin_t::openMsgLogWin(void)
+{
+ //printf("Open Message Log Window\n");
+ MsgLogViewDialog_t *msgLogWin;
+
+ msgLogWin = new MsgLogViewDialog_t(this);
+
+ msgLogWin->show();
+
+ return;
+}
+
+int consoleWin_t::setNicePriority( int value )
+{
+ int ret = 0;
+#if defined(__linux__)
+
+ if ( value < -20 )
+ {
+ value = -20;
+ }
+ else if ( value > 19 )
+ {
+ value = 19;
+ }
+
+ if ( ::setpriority( PRIO_PROCESS, getpid(), value ) )
+ {
+ perror("Emulator thread setpriority error: ");
+ ret = -1;
+ }
+#elif defined(__APPLE__)
+
+ if ( value < -20 )
+ {
+ value = -20;
+ }
+ else if ( value > 20 )
+ {
+ value = 20;
+ }
+
+ if ( ::setpriority( PRIO_PROCESS, getpid(), value ) )
+ {
+ perror("Emulator thread setpriority error: ");
+ ret = -1;
+ }
+#endif
+ return ret;
+}
+
+int consoleWin_t::getNicePriority(void)
+{
+ return ::getpriority( PRIO_PROCESS, getpid() );
+}
+
+int consoleWin_t::getMinSchedPriority(void)
+{
+ int policy, prio;
+
+ if ( getSchedParam( policy, prio ) )
+ {
+ return 0;
+ }
+ return sched_get_priority_min( policy );
+}
+
+int consoleWin_t::getMaxSchedPriority(void)
+{
+ int policy, prio;
+
+ if ( getSchedParam( policy, prio ) )
+ {
+ return 0;
+ }
+ return sched_get_priority_max( policy );
+}
+
+int consoleWin_t::getSchedParam( int &policy, int &priority )
+{
+ int ret = 0;
+
+#if defined(__linux__)
+ struct sched_param p;
+
+ policy = sched_getscheduler( getpid() );
+
+ if ( sched_getparam( getpid(), &p ) )
+ {
+ perror("GUI thread sched_getparam error: ");
+ ret = -1;
+ priority = 0;
+ }
+ else
+ {
+ priority = p.sched_priority;
+ }
+
+#elif defined(__APPLE__)
+ struct sched_param p;
+
+ if ( pthread_getschedparam( pthread_self(), &policy, &p ) )
+ {
+ perror("GUI thread pthread_getschedparam error: ");
+ ret = -1;
+ priority = 0;
+ }
+ else
+ {
+ priority = p.sched_priority;
+ }
+#endif
+ return ret;
+}
+
+int consoleWin_t::setSchedParam( int policy, int priority )
+{
+ int ret = 0;
+#if defined(__linux__)
+ struct sched_param p;
+ int minPrio, maxPrio;
+
+ minPrio = sched_get_priority_min( policy );
+ maxPrio = sched_get_priority_max( policy );
+
+ if ( priority < minPrio )
+ {
+ priority = minPrio;
+ }
+ else if ( priority > maxPrio )
+ {
+ priority = maxPrio;
+ }
+ p.sched_priority = priority;
+
+ if ( sched_setscheduler( getpid(), policy, &p ) )
+ {
+ perror("GUI thread sched_setscheduler error");
+ ret = -1;
+ }
+#elif defined(__APPLE__)
+ struct sched_param p;
+ int minPrio, maxPrio;
+
+ minPrio = sched_get_priority_min( policy );
+ maxPrio = sched_get_priority_max( policy );
+
+ if ( priority < minPrio )
+ {
+ priority = minPrio;
+ }
+ else if ( priority > maxPrio )
+ {
+ priority = maxPrio;
+ }
+ p.sched_priority = priority;
+
+ if ( ::pthread_setschedparam( pthread_self(), policy, &p ) != 0 )
+ {
+ perror("GUI thread pthread_setschedparam error: ");
+ }
+#endif
+ return ret;
+}
+
void consoleWin_t::syncActionConfig( QAction *act, const char *property )
{
if ( act->isCheckable() )
@@ -1471,14 +2098,214 @@ void consoleWin_t::updatePeriodic(void)
errorMsgValid = false;
}
+ if ( closeRequested )
+ {
+ closeApp();
+ closeRequested = false;
+ }
+
return;
}
+emulatorThread_t::emulatorThread_t(void)
+{
+ #if defined(__linux__) || defined(__APPLE__)
+ pself = 0;
+ #endif
+
+}
+
+#ifdef __linux__
+#ifndef SYS_gettid
+#error "SYS_gettid unavailable on this system"
+#endif
+
+#define gettid() ((pid_t)syscall(SYS_gettid))
+#endif
+
+
+void emulatorThread_t::init(void)
+{
+ int opt;
+
+ #if defined(__linux__) || defined(__APPLE__)
+ if ( pthread_self() == (pthread_t)QThread::currentThreadId() )
+ {
+ pself = pthread_self();
+ //printf("EMU is using PThread: %p\n", (void*)pself);
+ }
+ #endif
+
+ #if defined(__linux__)
+ pid = gettid();
+ #elif defined(__APPLE__)
+ pid = getpid();
+ #endif
+
+ g_config->getOption( "SDL.SetSchedParam", &opt );
+
+ if ( opt )
+ {
+ int policy, prio, nice;
+
+ g_config->getOption( "SDL.EmuSchedPolicy", &policy );
+ g_config->getOption( "SDL.EmuSchedPrioRt", &prio );
+ g_config->getOption( "SDL.EmuSchedNice" , &nice );
+
+ setNicePriority( nice );
+
+ setSchedParam( policy, prio );
+ }
+}
+
+void emulatorThread_t::setPriority( QThread::Priority priority_req )
+{
+ //printf("New Priority: %i \n", priority_req );
+ //printf("Old Priority: %i \n", priority() );
+
+ QThread::setPriority( priority_req );
+
+ //printf("Set Priority: %i \n", priority() );
+}
+
+int emulatorThread_t::setNicePriority( int value )
+{
+ int ret = 0;
+#if defined(__linux__)
+
+ if ( value < -20 )
+ {
+ value = -20;
+ }
+ else if ( value > 19 )
+ {
+ value = 19;
+ }
+
+ if ( ::setpriority( PRIO_PROCESS, pid, value ) )
+ {
+ perror("Emulator thread setpriority error: ");
+ ret = -1;
+ }
+#elif defined(__APPLE__)
+
+ if ( value < -20 )
+ {
+ value = -20;
+ }
+ else if ( value > 20 )
+ {
+ value = 20;
+ }
+
+ if ( ::setpriority( PRIO_PROCESS, pid, value ) )
+ {
+ perror("Emulator thread setpriority error: ");
+ ret = -1;
+ }
+#endif
+ return ret;
+}
+
+int emulatorThread_t::getNicePriority(void)
+{
+ return ::getpriority( PRIO_PROCESS, pid );
+}
+
+int emulatorThread_t::getMinSchedPriority(void)
+{
+ int policy, prio;
+
+ if ( getSchedParam( policy, prio ) )
+ {
+ return 0;
+ }
+ return sched_get_priority_min( policy );
+}
+
+int emulatorThread_t::getMaxSchedPriority(void)
+{
+ int policy, prio;
+
+ if ( getSchedParam( policy, prio ) )
+ {
+ return 0;
+ }
+ return sched_get_priority_max( policy );
+}
+
+int emulatorThread_t::getSchedParam( int &policy, int &priority )
+{
+ struct sched_param p;
+
+ if ( pthread_getschedparam( pself, &policy, &p ) )
+ {
+ perror("Emulator thread pthread_getschedparam error: ");
+ return -1;
+ }
+ priority = p.sched_priority;
+
+ return 0;
+}
+
+int emulatorThread_t::setSchedParam( int policy, int priority )
+{
+ int ret = 0;
+#if defined(__linux__)
+ struct sched_param p;
+ int minPrio, maxPrio;
+
+ minPrio = sched_get_priority_min( policy );
+ maxPrio = sched_get_priority_max( policy );
+
+ if ( priority < minPrio )
+ {
+ priority = minPrio;
+ }
+ else if ( priority > maxPrio )
+ {
+ priority = maxPrio;
+ }
+ p.sched_priority = priority;
+
+ if ( ::pthread_setschedparam( pself, policy, &p ) != 0 )
+ {
+ perror("Emulator thread pthread_setschedparam error: ");
+ ret = -1;
+ }
+
+#elif defined(__APPLE__)
+ struct sched_param p;
+ int minPrio, maxPrio;
+
+ minPrio = sched_get_priority_min( policy );
+ maxPrio = sched_get_priority_max( policy );
+
+ if ( priority < minPrio )
+ {
+ priority = minPrio;
+ }
+ else if ( priority > maxPrio )
+ {
+ priority = maxPrio;
+ }
+ p.sched_priority = priority;
+
+ if ( ::pthread_setschedparam( pself, policy, &p ) != 0 )
+ {
+ perror("Emulator thread pthread_setschedparam error: ");
+ }
+#endif
+ return ret;
+}
+
void emulatorThread_t::run(void)
{
printf("Emulator Start\n");
nes_shm->runEmulator = 1;
+ init();
+
while ( nes_shm->runEmulator )
{
fceuWrapperUpdate();
diff --git a/src/drivers/Qt/ConsoleWindow.h b/src/drivers/Qt/ConsoleWindow.h
index a8d74264..4acb75d9 100644
--- a/src/drivers/Qt/ConsoleWindow.h
+++ b/src/drivers/Qt/ConsoleWindow.h
@@ -4,6 +4,9 @@
#ifndef __GameAppH__
#define __GameAppH__
+#include
+#include
+
#include
#include
#include
@@ -25,10 +28,32 @@ class emulatorThread_t : public QThread
{
Q_OBJECT
- //public slots:
+ protected:
void run( void ) override;
+
+ public:
+ emulatorThread_t(void);
+
+ void setPriority( QThread::Priority priority );
+
+ #if defined(__linux__) || defined(__APPLE__)
+ int setSchedParam( int policy, int priority );
+ int getSchedParam( int &policy, int &priority );
+ int setNicePriority( int value );
+ int getNicePriority( void );
+ int getMinSchedPriority(void);
+ int getMaxSchedPriority(void);
+ #endif
+ private:
+ void init(void);
+
+ #if defined(__linux__) || defined(__APPLE__)
+ pthread_t pself;
+ int pid;
+ #endif
+
signals:
- void finished();
+ void finished();
};
class consoleWin_t : public QMainWindow
@@ -46,8 +71,23 @@ class consoleWin_t : public QMainWindow
QMutex *mutex;
+ void requestClose(void);
+
void QueueErrorMsgWindow( const char *msg );
+ int showListSelectDialog( const char *title, std::vector &l );
+
+ #if defined(__linux__) || defined(__APPLE__)
+ int setSchedParam( int policy, int priority );
+ int getSchedParam( int &policy, int &priority );
+ int setNicePriority( int value );
+ int getNicePriority( void );
+ int getMinSchedPriority(void);
+ int getMaxSchedPriority(void);
+ #endif
+
+ emulatorThread_t *emulatorThread;
+
protected:
QMenu *fileMenu;
QMenu *optMenu;
@@ -67,16 +107,20 @@ class consoleWin_t : public QMainWindow
QAction *loadLuaAct;
QAction *scrShotAct;
QAction *quitAct;
+ QAction *inputConfig;
QAction *gamePadConfig;
QAction *gameSoundConfig;
QAction *gameVideoConfig;
QAction *hotkeyConfig;
QAction *paletteConfig;
QAction *guiConfig;
+ QAction *timingConfig;
+ QAction *movieConfig;
QAction *autoResume;
QAction *fullscreen;
QAction *aboutAct;
QAction *aboutActQt;
+ QAction *msgLogAct;
QAction *state[10];
QAction *powerAct;
QAction *resetAct;
@@ -89,10 +133,16 @@ class consoleWin_t : public QMainWindow
QAction *fdsEjectAct;
QAction *fdsLoadBiosAct;
QAction *cheatsAct;
+ QAction *ramWatchAct;
+ QAction *ramSearchAct;
QAction *debuggerAct;
QAction *codeDataLogAct;
QAction *traceLogAct;
QAction *hexEditAct;
+ QAction *ppuViewAct;
+ QAction *ntViewAct;
+ QAction *ggEncodeAct;
+ QAction *iNesEditAct;
QAction *openMovAct;
QAction *stopMovAct;
QAction *recMovAct;
@@ -100,10 +150,9 @@ class consoleWin_t : public QMainWindow
QTimer *gameTimer;
- emulatorThread_t *emulatorThread;
-
std::string errorMsg;
bool errorMsgValid;
+ bool closeRequested;
protected:
void closeEvent(QCloseEvent *event);
@@ -118,6 +167,7 @@ class consoleWin_t : public QMainWindow
public slots:
void openDebugWindow(void);
void openHexEditor(void);
+ void openGamePadConfWin(void);
private slots:
void closeApp(void);
void openROMFile(void);
@@ -129,12 +179,16 @@ class consoleWin_t : public QMainWindow
void closeROMCB(void);
void aboutFCEUX(void);
void aboutQt(void);
- void openGamePadConfWin(void);
+ void openMsgLogWin(void);
+ void openInputConfWin(void);
void openGameSndConfWin(void);
void openGameVideoConfWin(void);
void openHotkeyConfWin(void);
void openPaletteConfWin(void);
void openGuiConfWin(void);
+ void openTimingConfWin(void);
+ void openTimingStatWin(void);
+ void openMovieOptWin(void);
void openCodeDataLogger(void);
void openTraceLogger(void);
void toggleAutoResume(void);
@@ -162,7 +216,20 @@ class consoleWin_t : public QMainWindow
void fdsSwitchDisk(void);
void fdsEjectDisk(void);
void fdsLoadBiosFile(void);
+ void emuSpeedUp(void);
+ void emuSlowDown(void);
+ void emuSlowestSpd(void);
+ void emuNormalSpd(void);
+ void emuFastestSpd(void);
+ void emuCustomSpd(void);
+ void emuSetFrameAdvDelay(void);
+ void openPPUViewer(void);
+ void openNTViewer(void);
+ void openGGEncoder(void);
+ void openNesHeaderEditor(void);
void openCheats(void);
+ void openRamWatch(void);
+ void openRamSearch(void);
void openMovie(void);
void stopMovie(void);
void recordMovie(void);
diff --git a/src/drivers/Qt/FrameTimingStats.cpp b/src/drivers/Qt/FrameTimingStats.cpp
new file mode 100644
index 00000000..ac35fa83
--- /dev/null
+++ b/src/drivers/Qt/FrameTimingStats.cpp
@@ -0,0 +1,265 @@
+// FrameTimingStats.cpp
+//
+#include
+#include
+#include
+#include
+
+#include
+#include
+#include
+
+#include "Qt/main.h"
+#include "Qt/dface.h"
+#include "Qt/input.h"
+#include "Qt/config.h"
+#include "Qt/keyscan.h"
+#include "Qt/throttle.h"
+#include "Qt/fceuWrapper.h"
+#include "Qt/FrameTimingStats.h"
+
+//----------------------------------------------------------------------------
+FrameTimingDialog_t::FrameTimingDialog_t(QWidget *parent)
+ : QDialog( parent )
+{
+ QVBoxLayout *mainLayout, *vbox;
+ QHBoxLayout *hbox;
+ QGroupBox *frame;
+ QTreeWidgetItem *item;
+ QPushButton *resetBtn;
+ struct frameTimingStat_t stats;
+
+ getFrameTimingStats( &stats );
+
+ setWindowTitle("Frame Timing Statistics");
+
+ resize( 512, 512 );
+
+ mainLayout = new QVBoxLayout();
+ vbox = new QVBoxLayout();
+ frame = new QGroupBox( tr("Timing Statistics") );
+ frame->setLayout( vbox );
+
+ tree = new QTreeWidget();
+ vbox->addWidget( tree );
+
+ tree->setColumnCount(4);
+
+ item = new QTreeWidgetItem();
+ item->setText( 0, tr( "Parameter" ) );
+ item->setText( 1, tr( "Target" ) );
+ item->setText( 2, tr( "Current" ) );
+ item->setText( 3, tr( "Minimum" ) );
+ item->setText( 4, tr( "Maximum" ) );
+ item->setTextAlignment( 0, Qt::AlignLeft);
+ item->setTextAlignment( 1, Qt::AlignCenter);
+ item->setTextAlignment( 2, Qt::AlignCenter);
+ item->setTextAlignment( 3, Qt::AlignCenter);
+ item->setTextAlignment( 4, Qt::AlignCenter);
+
+ tree->setHeaderItem( item );
+ tree->header()->setSectionResizeMode( QHeaderView::Stretch );
+ tree->header()->setSectionResizeMode( 0, QHeaderView::ResizeToContents );
+
+ frameTimeAbs = new QTreeWidgetItem();
+ frameTimeDel = new QTreeWidgetItem();
+ frameTimeWork = new QTreeWidgetItem();
+ frameTimeIdle = new QTreeWidgetItem();
+ frameTimeWorkPct = new QTreeWidgetItem();
+ frameTimeIdlePct = new QTreeWidgetItem();
+ frameLateCount = new QTreeWidgetItem();
+
+ tree->addTopLevelItem( frameTimeAbs );
+ tree->addTopLevelItem( frameTimeDel );
+ tree->addTopLevelItem( frameTimeWork );
+ tree->addTopLevelItem( frameTimeIdle );
+ tree->addTopLevelItem( frameTimeWorkPct );
+ tree->addTopLevelItem( frameTimeIdlePct );
+ tree->addTopLevelItem( frameLateCount );
+
+ frameTimeAbs->setFlags( Qt::ItemIsEnabled | Qt::ItemNeverHasChildren );
+ frameTimeDel->setFlags( Qt::ItemIsEnabled | Qt::ItemNeverHasChildren );
+
+ frameTimeAbs->setText( 0, tr("Frame Period ms") );
+ frameTimeDel->setText( 0, tr("Frame Delta ms") );
+ frameTimeWork->setText( 0, tr("Frame Work ms") );
+ frameTimeIdle->setText( 0, tr("Frame Idle ms") );
+ frameTimeWorkPct->setText( 0, tr("Frame Work %") );
+ frameTimeIdlePct->setText( 0, tr("Frame Idle %") );
+ frameLateCount->setText( 0, tr("Frame Late Count") );
+
+ frameTimeAbs->setTextAlignment( 0, Qt::AlignLeft);
+ frameTimeDel->setTextAlignment( 0, Qt::AlignLeft);
+ frameTimeWork->setTextAlignment( 0, Qt::AlignLeft);
+ frameTimeIdle->setTextAlignment( 0, Qt::AlignLeft);
+ frameTimeWorkPct->setTextAlignment( 0, Qt::AlignLeft);
+ frameTimeIdlePct->setTextAlignment( 0, Qt::AlignLeft);
+ frameLateCount->setTextAlignment( 0, Qt::AlignLeft);
+
+ for (int i=0; i<4; i++)
+ {
+ frameTimeAbs->setTextAlignment( i+1, Qt::AlignCenter);
+ frameTimeDel->setTextAlignment( i+1, Qt::AlignCenter);
+ frameTimeWork->setTextAlignment( i+1, Qt::AlignCenter);
+ frameTimeIdle->setTextAlignment( i+1, Qt::AlignCenter);
+ frameTimeWorkPct->setTextAlignment( i+1, Qt::AlignCenter);
+ frameTimeIdlePct->setTextAlignment( i+1, Qt::AlignCenter);
+ frameLateCount->setTextAlignment( i+1, Qt::AlignCenter);
+ }
+
+ hbox = new QHBoxLayout();
+ timingEnable = new QCheckBox( tr("Enable Timing Statistics Calculations") );
+ resetBtn = new QPushButton( tr("Reset") );
+
+ timingEnable->setChecked( stats.enabled );
+
+ hbox->addWidget( timingEnable );
+ hbox->addWidget( resetBtn );
+
+ connect( timingEnable, SIGNAL(stateChanged(int)), this, SLOT(timingEnableChanged(int)) );
+ connect( resetBtn , SIGNAL(clicked(void)) , this, SLOT(resetTimingClicked(void)) );
+
+ mainLayout->addLayout( hbox );
+ mainLayout->addWidget( frame );
+
+ setLayout( mainLayout );
+
+ updateTimingStats();
+
+ updateTimer = new QTimer( this );
+
+ connect( updateTimer, &QTimer::timeout, this, &FrameTimingDialog_t::updatePeriodic );
+
+ updateTimer->start( 200 ); // 5hz
+
+}
+//----------------------------------------------------------------------------
+FrameTimingDialog_t::~FrameTimingDialog_t(void)
+{
+ printf("Destroy Frame Timing Window\n");
+ updateTimer->stop();
+}
+//----------------------------------------------------------------------------
+void FrameTimingDialog_t::closeEvent(QCloseEvent *event)
+{
+ printf("Frame Timing Close Window Event\n");
+ done(0);
+ deleteLater();
+ event->accept();
+}
+//----------------------------------------------------------------------------
+void FrameTimingDialog_t::closeWindow(void)
+{
+ //printf("Close Window\n");
+ done(0);
+ deleteLater();
+}
+//----------------------------------------------------------------------------
+void FrameTimingDialog_t::updateTimingStats(void)
+{
+ char stmp[128];
+ struct frameTimingStat_t stats;
+
+ getFrameTimingStats( &stats );
+
+ // Absolute
+ sprintf( stmp, "%.3f", stats.frameTimeAbs.tgt * 1e3 );
+ frameTimeAbs->setText( 1, tr(stmp) );
+
+ sprintf( stmp, "%.3f", stats.frameTimeAbs.cur * 1e3 );
+ frameTimeAbs->setText( 2, tr(stmp) );
+
+ sprintf( stmp, "%.3f", stats.frameTimeAbs.min * 1e3 );
+ frameTimeAbs->setText( 3, tr(stmp) );
+
+ sprintf( stmp, "%.3f", stats.frameTimeAbs.max * 1e3 );
+ frameTimeAbs->setText( 4, tr(stmp) );
+
+ // Delta
+ sprintf( stmp, "%.3f", stats.frameTimeDel.tgt * 1e3 );
+ frameTimeDel->setText( 1, tr(stmp) );
+
+ sprintf( stmp, "%.3f", stats.frameTimeDel.cur * 1e3 );
+ frameTimeDel->setText( 2, tr(stmp) );
+
+ sprintf( stmp, "%.3f", stats.frameTimeDel.min * 1e3 );
+ frameTimeDel->setText( 3, tr(stmp) );
+
+ sprintf( stmp, "%.3f", stats.frameTimeDel.max * 1e3 );
+ frameTimeDel->setText( 4, tr(stmp) );
+
+ // Work
+ sprintf( stmp, "lt %.3f", stats.frameTimeWork.tgt * 1e3 );
+ frameTimeWork->setText( 1, tr(stmp) );
+
+ sprintf( stmp, "%.3f", stats.frameTimeWork.cur * 1e3 );
+ frameTimeWork->setText( 2, tr(stmp) );
+
+ sprintf( stmp, "%.3f", stats.frameTimeWork.min * 1e3 );
+ frameTimeWork->setText( 3, tr(stmp) );
+
+ sprintf( stmp, "%.3f", stats.frameTimeWork.max * 1e3 );
+ frameTimeWork->setText( 4, tr(stmp) );
+
+ // Idle
+ sprintf( stmp, "gt %.3f", stats.frameTimeIdle.tgt * 1e3 );
+ frameTimeIdle->setText( 1, tr(stmp) );
+
+ sprintf( stmp, "%.3f", stats.frameTimeIdle.cur * 1e3 );
+ frameTimeIdle->setText( 2, tr(stmp) );
+
+ sprintf( stmp, "%.3f", stats.frameTimeIdle.min * 1e3 );
+ frameTimeIdle->setText( 3, tr(stmp) );
+
+ sprintf( stmp, "%.3f", stats.frameTimeIdle.max * 1e3 );
+ frameTimeIdle->setText( 4, tr(stmp) );
+
+ // Work %
+ sprintf( stmp, "lt %.1f", 100.0 * stats.frameTimeWork.tgt / stats.frameTimeAbs.tgt );
+ frameTimeWorkPct->setText( 1, tr(stmp) );
+
+ sprintf( stmp, "%.1f", 100.0 * stats.frameTimeWork.cur / stats.frameTimeAbs.tgt );
+ frameTimeWorkPct->setText( 2, tr(stmp) );
+
+ sprintf( stmp, "%.1f", 100.0 * stats.frameTimeWork.min / stats.frameTimeAbs.tgt );
+ frameTimeWorkPct->setText( 3, tr(stmp) );
+
+ sprintf( stmp, "%.1f", 100.0 * stats.frameTimeWork.max / stats.frameTimeAbs.tgt );
+ frameTimeWorkPct->setText( 4, tr(stmp) );
+
+ // Idle %
+ sprintf( stmp, "gt %.1f", 100.0 * stats.frameTimeIdle.tgt / stats.frameTimeAbs.tgt );
+ frameTimeIdlePct->setText( 1, tr(stmp) );
+
+ sprintf( stmp, "%.1f", 100.0 * stats.frameTimeIdle.cur / stats.frameTimeAbs.tgt );
+ frameTimeIdlePct->setText( 2, tr(stmp) );
+
+ sprintf( stmp, "%.1f", 100.0 * stats.frameTimeIdle.min / stats.frameTimeAbs.tgt );
+ frameTimeIdlePct->setText( 3, tr(stmp) );
+
+ sprintf( stmp, "%.1f", 100.0 * stats.frameTimeIdle.max / stats.frameTimeAbs.tgt );
+ frameTimeIdlePct->setText( 4, tr(stmp) );
+
+ // Late Count
+ sprintf( stmp, "%u", stats.lateCount );
+ frameLateCount->setText( 1, tr("0") );
+ frameLateCount->setText( 2, tr(stmp) );
+
+ tree->viewport()->update();
+}
+//----------------------------------------------------------------------------
+void FrameTimingDialog_t::updatePeriodic(void)
+{
+ updateTimingStats();
+}
+//----------------------------------------------------------------------------
+void FrameTimingDialog_t::timingEnableChanged(int state)
+{
+ setFrameTimingEnable( state != Qt::Unchecked );
+}
+//----------------------------------------------------------------------------
+void FrameTimingDialog_t::resetTimingClicked(void)
+{
+ resetFrameTiming();
+}
+//----------------------------------------------------------------------------
diff --git a/src/drivers/Qt/FrameTimingStats.h b/src/drivers/Qt/FrameTimingStats.h
new file mode 100644
index 00000000..b63a778f
--- /dev/null
+++ b/src/drivers/Qt/FrameTimingStats.h
@@ -0,0 +1,55 @@
+// FrameTimingStats.h
+//
+
+#pragma once
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "Qt/main.h"
+
+class FrameTimingDialog_t : public QDialog
+{
+ Q_OBJECT
+
+ public:
+ FrameTimingDialog_t(QWidget *parent = 0);
+ ~FrameTimingDialog_t(void);
+
+ protected:
+ void closeEvent(QCloseEvent *event);
+
+ QTimer *updateTimer;
+ QCheckBox *timingEnable;
+ QTreeWidgetItem *frameTimeAbs;
+ QTreeWidgetItem *frameTimeDel;
+ QTreeWidgetItem *frameTimeWork;
+ QTreeWidgetItem *frameTimeWorkPct;
+ QTreeWidgetItem *frameTimeIdle;
+ QTreeWidgetItem *frameTimeIdlePct;
+ QTreeWidgetItem *frameLateCount;
+
+ QTreeWidget *tree;
+
+ private:
+ void updateTimingStats(void);
+
+ public slots:
+ void closeWindow(void);
+ private slots:
+ void updatePeriodic(void);
+ void resetTimingClicked(void);
+ void timingEnableChanged(int state);
+
+};
diff --git a/src/drivers/Qt/GameGenie.cpp b/src/drivers/Qt/GameGenie.cpp
new file mode 100644
index 00000000..bff0cb1e
--- /dev/null
+++ b/src/drivers/Qt/GameGenie.cpp
@@ -0,0 +1,445 @@
+// GameGenie.cpp
+//
+#include
+#include
+#include
+#include
+
+#include
+#include
+
+#include "../../types.h"
+#include "../../fceu.h"
+#include "../../cart.h"
+#include "../../cheat.h"
+#include "../../debug.h"
+#include "../../driver.h"
+
+#include "Qt/main.h"
+#include "Qt/dface.h"
+#include "Qt/dface.h"
+#include "Qt/input.h"
+#include "Qt/config.h"
+#include "Qt/keyscan.h"
+#include "Qt/fceuWrapper.h"
+#include "Qt/HexEditor.h"
+#include "Qt/GameGenie.h"
+
+static const char *GameGenieLetters = "APZLGITYEOXUKSVN";
+
+class fceuGGCodeValidtor : public QValidator
+{
+ public:
+ fceuGGCodeValidtor( QObject *parent)
+ : QValidator(parent)
+ {
+
+ }
+
+ QValidator::State validate(QString &input, int &pos) const
+ {
+ int i,j, ok;
+ //printf("Validate: %i '%s'\n", input.size(), input.toStdString().c_str() );
+
+ if ( input.size() == 0 )
+ {
+ return QValidator::Acceptable;
+ }
+ input = input.toUpper();
+ std::string s = input.toStdString();
+ i=0;
+
+ while ( s[i] != 0 )
+ {
+ j=0; ok=0;
+ while ( GameGenieLetters[j] != 0 )
+ {
+ if ( s[i] == GameGenieLetters[j] )
+ {
+ ok = 1; break;
+ }
+ j++;
+ }
+
+ if ( !ok )
+ {
+ return QValidator::Invalid;
+ }
+ i++;
+ }
+
+ return QValidator::Acceptable;
+ }
+
+ private:
+};
+//----------------------------------------------------------------------------
+GameGenieDialog_t::GameGenieDialog_t(QWidget *parent)
+ : QDialog( parent )
+{
+ int charWidth;
+ QVBoxLayout *mainLayout, *vbox1, *vbox;
+ QHBoxLayout *hbox1, *hbox;
+ QTreeWidgetItem *item;
+ QGroupBox *frame;
+ QFont font;
+ fceuGGCodeValidtor *ggCodeValidator;
+
+ font.setFamily("Courier New");
+ font.setStyle( QFont::StyleNormal );
+ font.setStyleHint( QFont::Monospace );
+
+ QFontMetrics fm(font);
+
+#if QT_VERSION > QT_VERSION_CHECK(5, 11, 0)
+ charWidth = fm.horizontalAdvance(QLatin1Char('2'));
+#else
+ charWidth = fm.width(QLatin1Char('2'));
+#endif
+
+ setWindowTitle("Game Genie Encoder/Decoder Tool");
+
+ mainLayout = new QVBoxLayout();
+ vbox = new QVBoxLayout();
+ vbox1 = new QVBoxLayout();
+ hbox1 = new QHBoxLayout();
+
+ frame = new QGroupBox( tr("Address/Compare/Value") );
+ mainLayout->addLayout( hbox1 );
+ frame->setLayout( vbox );
+
+ hbox1->addWidget( frame );
+ hbox1->addLayout( vbox1 );
+ addr = new QLineEdit();
+ cmp = new QLineEdit();
+ val = new QLineEdit();
+
+ hbox = new QHBoxLayout();
+ vbox->addLayout( hbox );
+ hbox->addWidget( new QLabel( tr("Address:") ), 0, Qt::AlignRight );
+ hbox->addWidget( addr, 0, Qt::AlignLeft );
+
+ hbox = new QHBoxLayout();
+ vbox->addLayout( hbox );
+ hbox->addWidget( new QLabel( tr("Compare:") ), 0, Qt::AlignRight );
+ hbox->addWidget( cmp, 0, Qt::AlignLeft );
+
+ hbox = new QHBoxLayout();
+ vbox->addLayout( hbox );
+ hbox->addWidget( new QLabel( tr("Value:") ), 0, Qt::AlignRight );
+ hbox->addWidget( val, 0, Qt::AlignLeft );
+
+ frame = new QGroupBox( tr("Game Genie Code") );
+ vbox = new QVBoxLayout();
+ vbox1->addWidget( frame );
+ frame->setLayout( vbox );
+
+ ggCode = new QLineEdit();
+ vbox->addWidget( ggCode );
+
+ addCheatBtn = new QPushButton( tr("Add To Cheat List") );
+ vbox1->addWidget( addCheatBtn );
+
+ tree = new QTreeWidget();
+
+ tree->setColumnCount(1);
+
+ item = new QTreeWidgetItem();
+ item->setText( 0, QString::fromStdString( "Possible Affected ROM File Addresses" ) );
+ item->setTextAlignment( 0, Qt::AlignLeft);
+
+ tree->setHeaderItem( item );
+
+ tree->header()->setSectionResizeMode( QHeaderView::ResizeToContents );
+
+ mainLayout->addWidget( tree );
+
+ setLayout( mainLayout );
+
+ addrValidator = new fceuHexIntValidtor( 0, 0xFFFF, this );
+ cmpValidator = new fceuHexIntValidtor( 0, 0x00FF, this );
+ valValidator = new fceuHexIntValidtor( 0, 0x00FF, this );
+
+ ggCodeValidator = new fceuGGCodeValidtor( this );
+
+ addr->setValidator( addrValidator );
+ cmp->setValidator( cmpValidator );
+ val->setValidator( valValidator );
+ ggCode->setValidator( ggCodeValidator );
+
+ addr->setMaxLength( 4 );
+ cmp->setMaxLength( 2 );
+ val->setMaxLength( 2 );
+ ggCode->setMaxLength( 8 );
+
+ addr->setMinimumWidth( 6 * charWidth );
+ cmp->setMinimumWidth( 4 * charWidth );
+ val->setMinimumWidth( 4 * charWidth );
+ addr->setMaximumWidth( 6 * charWidth );
+ cmp->setMaximumWidth( 4 * charWidth );
+ val->setMaximumWidth( 4 * charWidth );
+
+ addr->setAlignment(Qt::AlignCenter);
+ cmp->setAlignment(Qt::AlignCenter);
+ val->setAlignment(Qt::AlignCenter);
+
+ addr->setFont( font );
+ cmp->setFont( font );
+ val->setFont( font );
+ ggCode->setFont( font );
+
+ connect( addCheatBtn, SIGNAL(clicked(void)), this, SLOT(addCheatClicked(void)));
+
+ connect( addr , SIGNAL(textEdited(const QString &)), this, SLOT(addrChanged(const QString &)));
+ connect( cmp , SIGNAL(textEdited(const QString &)), this, SLOT(cmpChanged(const QString &)));
+ connect( val , SIGNAL(textEdited(const QString &)), this, SLOT(valChanged(const QString &)));
+ connect( ggCode, SIGNAL(textEdited(const QString &)), this, SLOT(ggChanged(const QString &)));
+
+ connect( tree, SIGNAL(itemActivated(QTreeWidgetItem*, int)), this, SLOT(romAddrDoubleClicked(QTreeWidgetItem*, int)) );
+
+ addCheatBtn->setEnabled( false );
+}
+//----------------------------------------------------------------------------
+GameGenieDialog_t::~GameGenieDialog_t(void)
+{
+ printf("Destroy Game Genie Window\n");
+}
+//----------------------------------------------------------------------------
+void GameGenieDialog_t::closeEvent(QCloseEvent *event)
+{
+ printf("Game Genie Close Window Event\n");
+ done(0);
+ deleteLater();
+ event->accept();
+}
+//----------------------------------------------------------------------------
+void GameGenieDialog_t::closeWindow(void)
+{
+ //printf("Close Window\n");
+ done(0);
+ deleteLater();
+}
+//----------------------------------------------------------------------------
+void GameGenieDialog_t::addCheatClicked(void)
+{
+ int a = -1, v = -1, c = -1;
+ std::string name;
+
+ name = ggCode->text().toStdString();
+
+ if ( addr->text().size() > 0 )
+ {
+ a = strtol( addr->text().toStdString().c_str(), NULL, 16 );
+ }
+ if ( val->text().size() > 0 )
+ {
+ v = strtol( val->text().toStdString().c_str(), NULL, 16 );
+ }
+ if ( cmp->text().size() > 0 )
+ {
+ c = strtol( cmp->text().toStdString().c_str(), NULL, 16 );
+ }
+
+ fceuWrapperLock();
+ FCEUI_AddCheat( name.c_str(), a, v, c, 1 );
+ fceuWrapperUnLock();
+
+}
+//----------------------------------------------------------------------------
+void GameGenieDialog_t::romAddrDoubleClicked(QTreeWidgetItem *item, int column)
+{
+ int addr;
+
+ addr = strtol( item->text(0).toStdString().c_str(), NULL, 16 );
+
+ printf("ROM Addr: %06X \n", addr );
+
+ hexEditorOpenFromDebugger( QHexEdit::MODE_NES_ROM, addr );
+}
+//----------------------------------------------------------------------------
+void GameGenieDialog_t::addrChanged(const QString &s)
+{
+ int a, v, c = -1;
+ char gg[12];
+
+ a = strtol( s.toStdString().c_str(), NULL, 16 );
+ v = strtol( val->text().toStdString().c_str(), NULL, 16 );
+
+ if ( cmp->text().size() > 0 )
+ {
+ c = strtol( cmp->text().toStdString().c_str(), NULL, 16 );
+ }
+
+ EncodeGG( gg, a, v, c );
+
+ ggCode->setText( tr(gg) );
+
+ ListGGAddresses();
+}
+//----------------------------------------------------------------------------
+void GameGenieDialog_t::cmpChanged(const QString &s)
+{
+ int a, v, c = -1;
+ char gg[12];
+
+ a = strtol( addr->text().toStdString().c_str(), NULL, 16 );
+ v = strtol( val->text().toStdString().c_str(), NULL, 16 );
+
+ if ( s.size() > 0 )
+ {
+ c = strtol( s.toStdString().c_str(), NULL, 16 );
+ }
+
+ EncodeGG( gg, a, v, c );
+
+ ggCode->setText( tr(gg) );
+
+ ListGGAddresses();
+}
+//----------------------------------------------------------------------------
+void GameGenieDialog_t::valChanged(const QString &s)
+{
+ int a, v, c = -1;
+ char gg[12];
+
+ a = strtol( addr->text().toStdString().c_str(), NULL, 16 );
+ v = strtol( s.toStdString().c_str(), NULL, 16 );
+
+ if ( cmp->text().size() > 0 )
+ {
+ c = strtol( cmp->text().toStdString().c_str(), NULL, 16 );
+ }
+ EncodeGG( gg, a, v, c );
+
+ ggCode->setText( tr(gg) );
+
+ ListGGAddresses();
+}
+//----------------------------------------------------------------------------
+void GameGenieDialog_t::ggChanged(const QString &s)
+{
+ int a = -1, c = -1, v = -1;
+ char gg[12];
+ char stmp[32];
+
+ memset( gg, 0, sizeof(gg) );
+
+ strncpy( gg, ggCode->text().toStdString().c_str(), 8 );
+
+ FCEUI_DecodeGG( gg, &a, &v, &c);
+
+ if ( a >= 0 )
+ {
+ sprintf( stmp, "%04X", a );
+
+ addr->setText( tr(stmp) );
+ }
+ else
+ {
+ addr->clear();
+ }
+
+ if ( v >= 0 )
+ {
+ sprintf( stmp, "%02X", v );
+
+ val->setText( tr(stmp) );
+ }
+ else
+ {
+ val->clear();
+ }
+
+ if ( c >= 0 )
+ {
+ sprintf( stmp, "%02X", c );
+
+ cmp->setText( tr(stmp) );
+ }
+ else
+ {
+ cmp->clear();
+ }
+
+ ListGGAddresses();
+}
+//----------------------------------------------------------------------------
+//The code in this function is a modified version
+//of Chris Covell's work - I'd just like to point that out
+void EncodeGG(char *str, int a, int v, int c)
+{
+ uint8 num[8];
+ int i;
+
+ a&=0x7fff;
+
+ num[0]=(v&7)+((v>>4)&8);
+ num[1]=((v>>4)&7)+((a>>4)&8);
+ num[2]=((a>>4)&7);
+ num[3]=(a>>12)+(a&8);
+ num[4]=(a&7)+((a>>8)&8);
+ num[5]=((a>>8)&7);
+
+ if (c == -1){
+ num[5]+=v&8;
+ for(i = 0;i < 6;i++)str[i] = GameGenieLetters[num[i]];
+ str[6] = 0;
+ } else {
+ num[2]+=8;
+ num[5]+=c&8;
+ num[6]=(c&7)+((c>>4)&8);
+ num[7]=((c>>4)&7)+(v&8);
+ for(i = 0;i < 8;i++)str[i] = GameGenieLetters[num[i]];
+ str[8] = 0;
+ }
+ return;
+}
+//----------------------------------------------------------------------------
+void GameGenieDialog_t::ListGGAddresses(void)
+{
+ int i; //mbg merge 7/18/06 changed from int
+ int a = -1; int v = -1; int c = -1;
+ QTreeWidgetItem *item;
+ char str[32];
+ bool addCheatEmable;
+
+ if ( addr->text().size() > 0 )
+ {
+ a = strtol( addr->text().toStdString().c_str(), NULL, 16 );
+ }
+ if ( val->text().size() > 0 )
+ {
+ v = strtol( val->text().toStdString().c_str(), NULL, 16 );
+ }
+ if ( cmp->text().size() > 0 )
+ {
+ c = strtol( cmp->text().toStdString().c_str(), NULL, 16 );
+ }
+ // also enable/disable the add GG button here
+ addCheatEmable = (a >= 0) && ( (ggCode->text().size() == 6) || (ggCode->text().size() == 8) );
+
+ addCheatBtn->setEnabled( addCheatEmable );
+
+ tree->clear();
+
+ if (a != -1 && v != -1)
+ {
+ for (i = 0; i < PRGsize[0]; i += 0x2000)
+ {
+ if (c == -1 || PRGptr[0][i + (a & 0x1FFF)] == c)
+ {
+ item = new QTreeWidgetItem();
+
+ sprintf(str, "%06X", i + (a & 0x1FFF) + 0x10);
+
+ //printf("Added ROM ADDR: %s\n", str );
+ item->setText( 0, tr(str) );
+
+ item->setTextAlignment( 0, Qt::AlignCenter);
+ tree->addTopLevelItem( item );
+ }
+ }
+ }
+ tree->viewport()->update();
+}
+//----------------------------------------------------------------------------
diff --git a/src/drivers/Qt/GameGenie.h b/src/drivers/Qt/GameGenie.h
new file mode 100644
index 00000000..47c4aee6
--- /dev/null
+++ b/src/drivers/Qt/GameGenie.h
@@ -0,0 +1,60 @@
+// GameGenie.h
+//
+
+#pragma once
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "Qt/main.h"
+#include "Qt/ConsoleUtilities.h"
+
+class GameGenieDialog_t : public QDialog
+{
+ Q_OBJECT
+
+ public:
+ GameGenieDialog_t(QWidget *parent = 0);
+ ~GameGenieDialog_t(void);
+
+ protected:
+ void closeEvent(QCloseEvent *event);
+
+ fceuHexIntValidtor *addrValidator;
+ fceuHexIntValidtor *cmpValidator;
+ fceuHexIntValidtor *valValidator;
+
+ QLineEdit *addr;
+ QLineEdit *cmp;
+ QLineEdit *val;
+ QLineEdit *ggCode;
+ QPushButton *addCheatBtn;
+ QTreeWidget *tree;
+
+ private:
+ void ListGGAddresses(void);
+
+ public slots:
+ void closeWindow(void);
+ private slots:
+ void addCheatClicked(void);
+ void addrChanged(const QString &);
+ void cmpChanged(const QString &);
+ void valChanged(const QString &);
+ void ggChanged(const QString &);
+ void romAddrDoubleClicked(QTreeWidgetItem *item, int column);
+
+};
+
+void EncodeGG(char *str, int a, int v, int c);
diff --git a/src/drivers/Qt/GamePadConf.cpp b/src/drivers/Qt/GamePadConf.cpp
index 2847a01c..835aeb2c 100644
--- a/src/drivers/Qt/GamePadConf.cpp
+++ b/src/drivers/Qt/GamePadConf.cpp
@@ -3,6 +3,7 @@
#include
#include
#include
+#include
#include "Qt/GamePadConf.h"
#include "Qt/main.h"
@@ -64,10 +65,12 @@ int closeGamePadConfWindow(void)
GamePadConfDialog_t::GamePadConfDialog_t(QWidget *parent)
: QDialog( parent )
{
- QHBoxLayout *hbox, *hbox1, *hbox2, *hbox3, *hbox4;
- QVBoxLayout *vbox;
+ QWidget *mainWidget;
+ QVBoxLayout *mainLayout;
+ QHBoxLayout *hbox, *hbox1, *hbox2, *hbox3, *hbox4, *hbox5;
+ QVBoxLayout *vbox, *vbox1, *vbox2;
QGridLayout *grid;
- QCheckBox *efs_chkbox, *udlr_chkbox;
+ QCheckBox *udlr_chkbox;
QGroupBox *frame1, *frame2;
QLabel *label;
QPushButton *newProfileButton;
@@ -77,14 +80,21 @@ GamePadConfDialog_t::GamePadConfDialog_t(QWidget *parent)
QPushButton *clearAllButton;
QPushButton *closebutton;
QPushButton *clearButton[GAMEPAD_NUM_BUTTONS];
+ QScrollArea *scroll;
+ QStyle *style;
std::string prefix;
char stmp[256];
+ style = this->style();
+
gamePadConfWin = this;
// Ensure that joysticks are enabled, no harm calling init again.
InitJoysticks();
+ scroll = new QScrollArea(this);
+ mainWidget = new QWidget();
+
portNum = 0;
buttonConfigStatus = 1;
@@ -98,6 +108,7 @@ GamePadConfDialog_t::GamePadConfDialog_t(QWidget *parent)
hbox2 = new QHBoxLayout();
hbox3 = new QHBoxLayout();
hbox4 = new QHBoxLayout();
+ hbox5 = new QHBoxLayout();
label = new QLabel(tr("Console Port:"));
portSel = new QComboBox();
@@ -166,10 +177,12 @@ GamePadConfDialog_t::GamePadConfDialog_t(QWidget *parent)
applyProfileButton = new QPushButton( tr("Load") );
applyProfileButton->setWhatsThis(tr("Sets Current Active Map to the Selected Profile"));
+ applyProfileButton->setIcon( style->standardIcon( QStyle::SP_DialogApplyButton ) );
hbox->addWidget( applyProfileButton );
saveProfileButton = new QPushButton( tr("Save") );
saveProfileButton->setWhatsThis(tr("Stores Current Active Map to the Selected Profile"));
+ saveProfileButton->setIcon( style->standardIcon( QStyle::SP_DialogSaveButton ) );
hbox->addWidget( saveProfileButton );
hbox = new QHBoxLayout();
@@ -177,10 +190,12 @@ GamePadConfDialog_t::GamePadConfDialog_t(QWidget *parent)
newProfileButton = new QPushButton( tr("New") );
newProfileButton->setWhatsThis(tr("Create a New Map Profile"));
+ newProfileButton->setIcon( style->standardIcon( QStyle::SP_FileIcon ) );
hbox->addWidget( newProfileButton );
removeProfileButton = new QPushButton( tr("Delete") );
removeProfileButton->setWhatsThis(tr("Deletes the Selected Map Profile"));
+ removeProfileButton->setIcon( style->standardIcon( QStyle::SP_TrashIcon ) );
hbox->addWidget( removeProfileButton );
mapMsg = new QLabel();
@@ -234,6 +249,9 @@ GamePadConfDialog_t::GamePadConfDialog_t(QWidget *parent)
clearAllButton = new QPushButton(tr("Clear All"));
closebutton = new QPushButton(tr("Close"));
+ clearAllButton->setIcon( style->standardIcon( QStyle::SP_LineEditClearButton ) );
+ closebutton->setIcon( style->standardIcon( QStyle::SP_DialogCloseButton ) );
+
hbox4->addWidget( clearAllButton );
hbox4->addWidget( closebutton );
@@ -272,18 +290,39 @@ GamePadConfDialog_t::GamePadConfDialog_t(QWidget *parent)
connect(efs_chkbox , SIGNAL(stateChanged(int)), this, SLOT(ena4score(int)) );
connect(udlr_chkbox, SIGNAL(stateChanged(int)), this, SLOT(oppDirEna(int)) );
- QVBoxLayout *mainLayout = new QVBoxLayout();
+ mainLayout = new QVBoxLayout();
+ vbox1 = new QVBoxLayout();
+ vbox2 = new QVBoxLayout();
- mainLayout->addLayout( hbox1 );
- mainLayout->addLayout( hbox2 );
- mainLayout->addLayout( hbox3 );
- mainLayout->addWidget( frame1 );
- mainLayout->addWidget( efs_chkbox );
- mainLayout->addWidget( udlr_chkbox );
- mainLayout->addWidget( frame2 );
- mainLayout->addLayout( hbox4 );
+ hbox5->addWidget( efs_chkbox );
+ hbox5->addWidget( udlr_chkbox );
- setLayout( mainLayout );
+ vbox1->addLayout( hbox1 );
+ vbox1->addLayout( hbox2 );
+ vbox1->addLayout( hbox3 );
+ vbox1->addWidget( frame1);
+ vbox1->addLayout( hbox5 );
+
+ vbox2->addWidget( frame2 );
+ vbox2->addLayout( hbox4 );
+
+ mainLayout->addLayout( vbox1 );
+ mainLayout->addLayout( vbox2 );
+
+ mainWidget->setLayout( mainLayout );
+ mainWidget->setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Expanding );
+
+ scroll->setWidget( mainWidget );
+ scroll->setWidgetResizable(true);
+ scroll->setSizeAdjustPolicy( QAbstractScrollArea::AdjustToContents );
+ scroll->setHorizontalScrollBarPolicy( Qt::ScrollBarAsNeeded );
+ scroll->setVerticalScrollBarPolicy( Qt::ScrollBarAsNeeded );
+
+ QHBoxLayout *dialogLayout = new QHBoxLayout();
+
+ dialogLayout->addWidget( scroll );
+
+ setLayout( dialogLayout );
inputTimer->start( 33 ); // 30hz
@@ -881,6 +920,13 @@ void GamePadConfDialog_t::updatePeriodic(void)
keyName[i]->setStyleSheet("color: black;");
}
}
+
+ int fourScore;
+ g_config->getOption("SDL.FourScore", &fourScore);
+ if ( fourScore != efs_chkbox->isChecked() )
+ {
+ efs_chkbox->setChecked( fourScore );
+ }
}
//----------------------------------------------------
GamePadConfigButton_t::GamePadConfigButton_t(int i)
diff --git a/src/drivers/Qt/GamePadConf.h b/src/drivers/Qt/GamePadConf.h
index 7d5fabe2..c7cebfcb 100644
--- a/src/drivers/Qt/GamePadConf.h
+++ b/src/drivers/Qt/GamePadConf.h
@@ -43,6 +43,7 @@ class GamePadConfDialog_t : public QDialog
QComboBox *devSel;
QComboBox *mapSel;
QComboBox *profSel;
+ QCheckBox *efs_chkbox;
QLabel *guidLbl;
QLabel *mapMsg;
QLabel *keyName[GAMEPAD_NUM_BUTTONS];
diff --git a/src/drivers/Qt/HexEditor.cpp b/src/drivers/Qt/HexEditor.cpp
index e5dd46a1..87f5ba1e 100644
--- a/src/drivers/Qt/HexEditor.cpp
+++ b/src/drivers/Qt/HexEditor.cpp
@@ -14,6 +14,7 @@
#include
#include
#include
+#include
#include "../../types.h"
#include "../../fceu.h"
@@ -36,14 +37,181 @@
#include "Qt/keyscan.h"
#include "Qt/fceuWrapper.h"
#include "Qt/HexEditor.h"
+#include "Qt/CheatsConf.h"
#include "Qt/SymbolicDebug.h"
#include "Qt/ConsoleDebugger.h"
#include "Qt/ConsoleUtilities.h"
#include "Qt/ConsoleWindow.h"
+static bool memNeedsCheck = false;
static HexBookMarkManager_t hbm;
static std::list winList;
static const char *memViewNames[] = { "RAM", "PPU", "OAM", "ROM", NULL };
+
+static int getROM( unsigned int offset);
+static int writeMem( int mode, unsigned int addr, int value );
+//----------------------------------------------------------------------------
+struct romEditEntry_t
+{
+ int addr;
+ int size;
+ uint8_t *data;
+
+ romEditEntry_t(void)
+ {
+ addr = -1; size = 0; data = NULL;
+ }
+
+ ~romEditEntry_t(void)
+ {
+ if ( data != NULL )
+ {
+ free(data); data = NULL;
+ }
+ }
+};
+
+struct romEditList_t
+{
+ uint8_t *modMem;
+ int modMemSize;
+
+ std::list undoList;
+ //std::list redoList; // TODO
+
+ romEditList_t(void)
+ {
+ modMem = NULL;
+ modMemSize = 0;
+ }
+
+ ~romEditList_t(void)
+ {
+ clear();
+ }
+
+ void clear(void)
+ {
+ while ( !undoList.empty() )
+ {
+ delete undoList.back();
+
+ undoList.pop_back();
+ }
+ if ( modMem != NULL )
+ {
+ free(modMem); modMem = NULL; modMemSize = 0;
+ }
+ }
+
+ void applyPatch( int addr, int data )
+ {
+ uint8_t u8;
+
+ u8 = data;
+
+ applyPatch( addr, &u8, 1 );
+ }
+
+ void applyPatch( int addr, uint8_t *data, int size )
+ {
+ int ofs;
+ romEditEntry_t *entry;
+
+ if ( GameInfo == NULL )
+ {
+ return;
+ }
+ if ( modMem == NULL )
+ {
+ modMemSize = 16 + CHRsize[0] + PRGsize[0];
+
+ modMem = (uint8_t*)malloc( modMemSize );
+
+ if ( modMem == NULL )
+ {
+ printf("Error: Failed to allocate ROM modification memory buffer\n");
+ return;
+ }
+ memset( modMem, 0, modMemSize );
+ }
+ entry = new romEditEntry_t();
+ entry->addr = addr;
+ entry->size = size;
+ entry->data = (uint8_t*)malloc(sizeof(uint8_t)*size);
+
+ for (int i = 0; i < size; i++)
+ {
+ ofs = addr+i;
+
+ entry->data[i] = getROM(ofs);
+
+ writeMem( QHexEdit::MODE_NES_ROM, ofs, data[i] );
+
+ modMem[ofs]++;
+ }
+ undoList.push_back( entry );
+ }
+
+ int undoPatch(void)
+ {
+ int ofs, ret = -1;
+ romEditEntry_t *entry;
+
+ if ( undoList.empty() )
+ {
+ return ret;
+ }
+ entry = undoList.back(); undoList.pop_back();
+
+ ret = entry->addr;
+
+ for (int i=0; isize; i++)
+ {
+ ofs = entry->addr + i;
+
+ writeMem( QHexEdit::MODE_NES_ROM, ofs, entry->data[i] );
+
+ if ( modMem )
+ {
+ if ( (ofs >= 0) && (ofs < modMemSize) )
+ {
+ if ( modMem[ofs] > 0 )
+ {
+ modMem[ofs]--;
+ }
+ }
+ }
+ }
+ delete entry;
+
+ return ret;
+ }
+
+ bool isModified( int addr )
+ {
+ if ( modMem == NULL )
+ {
+ return false;
+ }
+ if ( addr < 0 )
+ {
+ return false;
+ }
+ else if ( addr >= modMemSize )
+ {
+ return false;
+ }
+ return modMem[addr] ? true : false;
+ }
+
+ size_t undoQueueSize(void)
+ {
+ return undoList.size();
+ }
+};
+
+static romEditList_t romEditList;
//----------------------------------------------------------------------------
static int getRAM( unsigned int i )
{
@@ -177,6 +345,9 @@ static int writeMem( int mode, unsigned int addr, int value )
}
break;
}
+
+ hexEditorRequestUpdateAll();
+
return 0;
}
//----------------------------------------------------------------------------
@@ -533,15 +704,154 @@ void HexBookMarkMenuAction::activateCB(void)
qedit->setAddr( bm->addr );
}
//----------------------------------------------------------------------------
-HexEditorDialog_t::HexEditorDialog_t(QWidget *parent)
+HexEditorFindDialog_t::HexEditorFindDialog_t(QWidget *parent)
: QDialog( parent )
+{
+ QVBoxLayout *mainLayout, *vbox;
+ QHBoxLayout *hbox;
+ QPushButton *nextBtn;
+ QGroupBox *dirGroup, *typeGroup;
+
+ QDialog::setWindowTitle( tr("Find") );
+
+ this->parent = (HexEditorDialog_t*)parent;
+
+ mainLayout = new QVBoxLayout();
+ hbox = new QHBoxLayout();
+
+ searchBox = new QLineEdit();
+ nextBtn = new QPushButton( tr("Find Next") );
+ dirGroup = new QGroupBox( tr("Direction") );
+ typeGroup = new QGroupBox( tr("Type") );
+
+ hbox->addWidget( new QLabel( tr("Find What:") ) );
+ hbox->addWidget( searchBox );
+ hbox->addWidget( nextBtn );
+
+ nextBtn->setDefault(true);
+
+ mainLayout->addLayout( hbox );
+
+ hbox = new QHBoxLayout();
+ hbox->addWidget( dirGroup );
+ hbox->addWidget( typeGroup );
+
+ mainLayout->addLayout( hbox );
+
+ vbox = new QVBoxLayout();
+ upBtn = new QRadioButton( tr("Up") );
+ dnBtn = new QRadioButton( tr("Down") );
+
+ dnBtn->setChecked(true);
+
+ vbox->addWidget( upBtn );
+ vbox->addWidget( dnBtn );
+
+ dirGroup->setLayout( vbox );
+
+ vbox = new QVBoxLayout();
+ hexBtn = new QRadioButton( tr("Hex") );
+ txtBtn = new QRadioButton( tr("Text") );
+
+ vbox->addWidget( hexBtn );
+ vbox->addWidget( txtBtn );
+
+ hexBtn->setChecked(true);
+
+ typeGroup->setLayout( vbox );
+
+ setLayout( mainLayout );
+
+ connect( nextBtn, SIGNAL(clicked(void)), this, SLOT(runSearch(void)) );
+}
+//----------------------------------------------------------------------------
+HexEditorFindDialog_t::~HexEditorFindDialog_t(void)
+{
+ parent->findDialog = NULL;
+}
+//----------------------------------------------------------------------------
+void HexEditorFindDialog_t::closeEvent(QCloseEvent *event)
+{
+ printf("Hex Editor Close Window Event\n");
+ done(0);
+ deleteLater();
+ event->accept();
+}
+//----------------------------------------------------------------------------
+void HexEditorFindDialog_t::closeWindow(void)
+{
+ //printf("Close Window\n");
+ done(0);
+ deleteLater();
+}
+//----------------------------------------------------------------------------
+void HexEditorFindDialog_t::runSearch(void)
+{
+ int i=0;
+ unsigned char v;
+ std::string s = searchBox->text().toStdString();
+ std::vector varray;
+
+ if ( s.size() == 0 )
+ {
+ return;
+ }
+ //printf("Run Search: '%s'\n", s.c_str() );
+
+ if ( hexBtn->isChecked() )
+ {
+ i=0;
+ while ( s[i] != 0 )
+ {
+ while ( isspace(s[i]) ) i++;
+ v = 0;
+
+ if ( isxdigit(s[i]) )
+ {
+ v = convFromXchar(s[i]) << 4; i++;
+ }
+ else
+ {
+ return;
+ }
+
+ if ( isxdigit(s[i]) )
+ {
+ v |= convFromXchar(s[i]); i++;
+ }
+ else
+ {
+ return;
+ }
+ varray.push_back(v);
+
+ while ( isspace(s[i]) ) i++;
+ }
+ }
+ else
+ {
+ i=0;
+ while ( s[i] != 0 )
+ {
+ v = s[i];
+ varray.push_back(v);
+ i++;
+ }
+ }
+ fceuWrapperLock();
+ parent->editor->findPattern( varray, upBtn->isChecked() );
+ fceuWrapperUnLock();
+}
+//----------------------------------------------------------------------------
+HexEditorDialog_t::HexEditorDialog_t(QWidget *parent)
+ : QDialog( parent, Qt::Window )
{
//QVBoxLayout *mainLayout;
QGridLayout *grid;
QMenuBar *menuBar;
- QMenu *fileMenu, *viewMenu, *colorMenu;
+ QMenu *fileMenu, *editMenu, *viewMenu, *colorMenu;
QAction *saveROM, *closeAct;
- QAction *actHlgt, *actHlgtRV, *actColorFG, *actColorBG;
+ QAction *act, *actHlgt, *actHlgtRV, *actColorFG, *actColorBG;
QActionGroup *group;
int useNativeMenuBar;
@@ -551,7 +861,7 @@ HexEditorDialog_t::HexEditorDialog_t(QWidget *parent)
menuBar = new QMenuBar(this);
- // This is needed for menu bar to show up on MacOS
+ // This is needed for menu bar to show up on MacOS
g_config->getOption( "SDL.UseNativeMenuBar", &useNativeMenuBar );
menuBar->setNativeMenuBar( useNativeMenuBar ? true : false );
@@ -559,33 +869,79 @@ HexEditorDialog_t::HexEditorDialog_t(QWidget *parent)
// Menu
//-----------------------------------------------------------------------
// File
- fileMenu = menuBar->addMenu(tr("File"));
+ fileMenu = menuBar->addMenu(tr("File"));
// File -> Save ROM
saveROM = new QAction(tr("Save ROM"), this);
- //saveROM->setShortcuts(QKeySequence::Open);
- saveROM->setStatusTip(tr("Save ROM File"));
- connect(saveROM, SIGNAL(triggered()), this, SLOT(saveRomFile(void)) );
-
- fileMenu->addAction(saveROM);
+ //saveROM->setShortcut(QKeySequence::Open);
+ saveROM->setStatusTip(tr("Save ROM File"));
+ connect(saveROM, SIGNAL(triggered()), this, SLOT(saveRomFile(void)) );
+
+ fileMenu->addAction(saveROM);
// File -> Save ROM As
saveROM = new QAction(tr("Save ROM As"), this);
- //saveROM->setShortcuts(QKeySequence::Open);
- saveROM->setStatusTip(tr("Save ROM File As"));
- connect(saveROM, SIGNAL(triggered()), this, SLOT(saveRomFileAs(void)) );
+ //saveROM->setShortcut(QKeySequence::Open);
+ saveROM->setStatusTip(tr("Save ROM File As"));
+ connect(saveROM, SIGNAL(triggered()), this, SLOT(saveRomFileAs(void)) );
+
+ fileMenu->addAction(saveROM);
- fileMenu->addAction(saveROM);
+ // File -> Goto Address
+ gotoAddrAct = new QAction(tr("Goto Addresss"), this);
+ gotoAddrAct->setShortcut(QKeySequence(tr("Ctrl+A")));
+ gotoAddrAct->setStatusTip(tr("Goto Address"));
+ connect(gotoAddrAct, SIGNAL(triggered()), this, SLOT(openGotoAddrDialog(void)) );
+
+ fileMenu->addAction(gotoAddrAct);
fileMenu->addSeparator();
// File -> Close
closeAct = new QAction(tr("Close"), this);
- //closeAct->setShortcuts(QKeySequence::Open);
- closeAct->setStatusTip(tr("Close Window"));
- connect(closeAct, SIGNAL(triggered()), this, SLOT(closeWindow(void)) );
+ //closeAct->setShortcuts(QKeySequence::Open);
+ closeAct->setStatusTip(tr("Close Window"));
+ connect(closeAct, SIGNAL(triggered()), this, SLOT(closeWindow(void)) );
+
+ fileMenu->addAction(closeAct);
- fileMenu->addAction(closeAct);
+ // Edit
+ editMenu = menuBar->addMenu(tr("Edit"));
+
+ // Edit -> Undo
+ undoEditAct = new QAction(tr("Undo"), this);
+ undoEditAct->setShortcut(QKeySequence(tr("U")));
+ undoEditAct->setStatusTip(tr("Undo Edit"));
+ undoEditAct->setEnabled(false);
+ connect(undoEditAct, SIGNAL(triggered()), this, SLOT(undoRomPatch(void)) );
+
+ editMenu->addAction(undoEditAct);
+ editMenu->addSeparator();
+
+ // Edit -> Copy
+ act = new QAction(tr("Copy"), this);
+ act->setShortcut(QKeySequence(tr("Ctrl+C")));
+ act->setStatusTip(tr("Copy"));
+ connect(act, SIGNAL(triggered()), this, SLOT(copyToClipboard(void)) );
+
+ editMenu->addAction(act);
+
+ // Edit -> Paste
+ act = new QAction(tr("Paste"), this);
+ act->setShortcut(QKeySequence(tr("Ctrl+V")));
+ act->setStatusTip(tr("Paste"));
+ connect(act, SIGNAL(triggered()), this, SLOT(pasteFromClipboard(void)) );
+
+ editMenu->addAction(act);
+ editMenu->addSeparator();
+
+ // Edit -> Find
+ act = new QAction(tr("Find"), this);
+ act->setShortcut(QKeySequence(tr("Ctrl+F")));
+ act->setStatusTip(tr("Find"));
+ connect(act, SIGNAL(triggered()), this, SLOT(openFindDialog(void)) );
+
+ editMenu->addAction(act);
// View
viewMenu = menuBar->addMenu(tr("View"));
@@ -596,13 +952,13 @@ HexEditorDialog_t::HexEditorDialog_t(QWidget *parent)
// View -> RAM
viewRAM = new QAction(tr("RAM"), this);
- //viewRAM->setShortcuts(QKeySequence::Open);
- viewRAM->setStatusTip(tr("View RAM"));
+ //viewRAM->setShortcuts(QKeySequence::Open);
+ viewRAM->setStatusTip(tr("View RAM"));
viewRAM->setCheckable(true);
- connect(viewRAM, SIGNAL(triggered()), this, SLOT(setViewRAM(void)) );
+ connect(viewRAM, SIGNAL(triggered()), this, SLOT(setViewRAM(void)) );
group->addAction(viewRAM);
- viewMenu->addAction(viewRAM);
+ viewMenu->addAction(viewRAM);
// View -> PPU
viewPPU = new QAction(tr("PPU"), this);
@@ -708,6 +1064,8 @@ HexEditorDialog_t::HexEditorDialog_t(QWidget *parent)
connect( hbar, SIGNAL(valueChanged(int)), this, SLOT(hbarChanged(int)) );
connect( vbar, SIGNAL(valueChanged(int)), this, SLOT(vbarChanged(int)) );
+ findDialog = NULL;
+
editor->memModeUpdate();
periodicTimer = new QTimer( this );
@@ -716,10 +1074,17 @@ HexEditorDialog_t::HexEditorDialog_t(QWidget *parent)
periodicTimer->start( 100 ); // 10hz
+ // Lock the mutex before adding a new window to the list,
+ // we want to be sure that the emulator is not iterating the list
+ // when we change it.
+ fceuWrapperLock();
winList.push_back(this);
+ fceuWrapperUnLock();
populateBookmarkMenu();
+ FCEUI_CreateCheatMap();
+
}
//----------------------------------------------------------------------------
HexEditorDialog_t::~HexEditorDialog_t(void)
@@ -729,6 +1094,11 @@ HexEditorDialog_t::~HexEditorDialog_t(void)
printf("Hex Editor Deleted\n");
periodicTimer->stop();
+ // Lock the emulation thread mutex to ensure
+ // that the emulator is not attempting to update memory values
+ // for window while we are destroying it or editing the window list.
+ fceuWrapperLock();
+
for (it = winList.begin(); it != winList.end(); it++)
{
if ( (*it) == this )
@@ -738,6 +1108,7 @@ HexEditorDialog_t::~HexEditorDialog_t(void)
break;
}
}
+ fceuWrapperUnLock();
}
//----------------------------------------------------------------------------
void HexEditorDialog_t::setWindowTitle(void)
@@ -807,16 +1178,16 @@ void HexEditorDialog_t::populateBookmarkMenu(void)
//----------------------------------------------------------------------------
void HexEditorDialog_t::closeEvent(QCloseEvent *event)
{
- printf("Hex Editor Close Window Event\n");
- done(0);
+ printf("Hex Editor Close Window Event\n");
+ done(0);
deleteLater();
- event->accept();
+ event->accept();
}
//----------------------------------------------------------------------------
void HexEditorDialog_t::closeWindow(void)
{
- //printf("Close Window\n");
- done(0);
+ //printf("Close Window\n");
+ done(0);
deleteLater();
}
//----------------------------------------------------------------------------
@@ -883,7 +1254,7 @@ void HexEditorDialog_t::gotoAddress( int newAddr )
//----------------------------------------------------------------------------
void HexEditorDialog_t::saveRomFile(void)
{
- //FlushUndoBuffer();
+ romEditList.clear();
iNesSave();
//UpdateColorTable();
}
@@ -899,7 +1270,7 @@ void HexEditorDialog_t::saveRomFileAs(void)
dialog.setNameFilter(tr("NES Files (*.nes *.NES) ;; All files (*)"));
dialog.setViewMode(QFileDialog::List);
- dialog.setFilter( QDir::AllEntries | QDir::Hidden );
+ dialog.setFilter( QDir::AllEntries | QDir::AllDirs | QDir::Hidden );
dialog.setLabelText( QFileDialog::Accept, tr("Save") );
dialog.setDefaultSuffix( tr(".nes") );
@@ -1059,6 +1430,8 @@ void HexEditorDialog_t::openDebugSymbolEditWindow( int addr )
connect( okButton, SIGNAL(clicked(void)), &dialog, SLOT(accept(void)) );
connect( cancelButton, SIGNAL(clicked(void)), &dialog, SLOT(reject(void)) );
+ okButton->setDefault(true);
+
if ( sym != NULL )
{
nameEntry->setText( tr(sym->name.c_str()) );
@@ -1085,6 +1458,7 @@ void HexEditorDialog_t::openDebugSymbolEditWindow( int addr )
sym->name = nameEntry->text().toStdString();
sym->comment = commentEntry->text().toStdString();
}
+ sym->trimTrailingSpaces();
//fceuWrapperLock();
updateAllDebuggerWindows();
//fceuWrapperUnLock();
@@ -1094,8 +1468,21 @@ void HexEditorDialog_t::openDebugSymbolEditWindow( int addr )
void HexEditorDialog_t::updatePeriodic(void)
{
//printf("Update Periodic\n");
+
+ undoEditAct->setEnabled( romEditList.undoQueueSize() > 0 );
- editor->checkMemActivity();
+ if ( fceuWrapperTryLock(0) )
+ {
+ memNeedsCheck = false;
+
+ editor->checkMemActivity();
+
+ fceuWrapperUnLock();
+ }
+ else
+ {
+ memNeedsCheck = true;
+ }
editor->memModeUpdate();
@@ -1132,6 +1519,42 @@ void HexEditorDialog_t::updatePeriodic(void)
}
}
//----------------------------------------------------------------------------
+void HexEditorDialog_t::undoRomPatch(void)
+{
+ int addr = romEditList.undoPatch();
+
+ if ( addr >= 0 )
+ {
+ editor->setMode( QHexEdit::MODE_NES_ROM );
+ editor->setAddr( addr );
+ }
+}
+//----------------------------------------------------------------------------
+void HexEditorDialog_t::openFindDialog(void)
+{
+ if ( findDialog == NULL )
+ {
+ findDialog = new HexEditorFindDialog_t(this);
+
+ findDialog->show();
+ }
+}
+//----------------------------------------------------------------------------
+void HexEditorDialog_t::openGotoAddrDialog(void)
+{
+ editor->openGotoAddrDialog();
+}
+//----------------------------------------------------------------------------
+void HexEditorDialog_t::copyToClipboard(void)
+{
+ editor->loadHighlightToClipboard();
+}
+//----------------------------------------------------------------------------
+void HexEditorDialog_t::pasteFromClipboard(void)
+{
+ editor->pasteFromClipboard();
+}
+//----------------------------------------------------------------------------
QHexEdit::QHexEdit(QWidget *parent)
: QWidget( parent )
{
@@ -1162,22 +1585,29 @@ QHexEdit::QHexEdit(QWidget *parent)
calcFontData();
memAccessFunc = getRAM;
- viewMode = MODE_NES_RAM;
+ viewMode = MODE_NES_RAM;
lineOffset = 0;
cursorPosX = 0;
cursorPosY = 0;
cursorAddr = 0;
cursorBlink = true;
cursorBlinkCount = 0;
- maxLineOffset = 0;
- editAddr = -1;
- editValue = 0;
- editMask = 0;
+ maxLineOffset = 0;
+ editAddr = -1;
+ editValue = 0;
+ editMask = 0;
reverseVideo = true;
actvHighlightEnable = true;
total_instructions_lp = 0;
pxLineXScroll = 0;
+ frzRamAddr = -1;
+ frzRamVal = 0;
+ frzRamMode = 0;
+ frzIdx = 0;
+
+ wheelPixelCounter = 0;
+
highLightColor[ 0].setRgb( 0x00, 0x00, 0x00 );
highLightColor[ 1].setRgb( 0x35, 0x40, 0x00 );
highLightColor[ 2].setRgb( 0x18, 0x52, 0x18 );
@@ -1215,6 +1645,20 @@ QHexEdit::QHexEdit(QWidget *parent)
}
rvActvTextColor[i].setRgbF( grayScale, grayScale, grayScale );
}
+
+ updateRequested = false;
+ mouseLeftBtnDown = false;
+
+ txtHlgtAnchorChar = -1;
+ txtHlgtAnchorLine = -1;
+ txtHlgtStartChar = -1;
+ txtHlgtStartLine = -1;
+ txtHlgtStartAddr = -1;
+ txtHlgtEndChar = -1;
+ txtHlgtEndLine = -1;
+ txtHlgtEndAddr = -1;
+
+ clipboard = QGuiApplication::clipboard();
}
//----------------------------------------------------------------------------
QHexEdit::~QHexEdit(void)
@@ -1231,14 +1675,14 @@ void QHexEdit::calcFontData(void)
#else
pxCharWidth = metrics.width(QLatin1Char('2'));
#endif
- pxCharHeight = metrics.height();
- pxLineSpacing = metrics.lineSpacing() * 1.25;
- pxLineLead = pxLineSpacing - pxCharHeight;
- pxXoffset = pxCharWidth;
- pxYoffset = pxLineSpacing * 2.0;
- pxHexOffset = pxXoffset + (7*pxCharWidth);
- pxHexAscii = pxHexOffset + (16*3*pxCharWidth) + (pxCharWidth);
- pxLineWidth = pxHexAscii + (17*pxCharWidth);
+ pxCharHeight = metrics.height();
+ pxLineSpacing = metrics.lineSpacing() * 1.25;
+ pxLineLead = pxLineSpacing - pxCharHeight;
+ pxXoffset = pxCharWidth;
+ pxYoffset = pxLineSpacing * 2.0;
+ pxHexOffset = pxXoffset + (7*pxCharWidth);
+ pxHexAscii = pxHexOffset + (16*3*pxCharWidth) + (pxCharWidth);
+ pxLineWidth = pxHexAscii + (17*pxCharWidth);
//_pxGapAdr = _pxCharWidth / 2;
//_pxGapAdrHex = _pxCharWidth;
//_pxGapHexAscii = 2 * _pxCharWidth;
@@ -1287,6 +1731,7 @@ void QHexEdit::setMode( int mode )
{
viewMode = mode;
memModeUpdate();
+ clearHighlight();
}
}
//----------------------------------------------------------------------------
@@ -1305,16 +1750,16 @@ void QHexEdit::setAddr( int newAddr )
lineOffset = 0;
}
else if ( lineOffset >= maxLineOffset )
- {
- lineOffset = maxLineOffset;
- }
+ {
+ lineOffset = maxLineOffset;
+ }
addr = 16*lineOffset;
cursorPosX = 2*((newAddr - addr)%16);
cursorPosY = (newAddr - addr)/16;
- vbar->setValue( lineOffset );
+ vbar->setValue( lineOffset );
}
//----------------------------------------------------------------------------
void QHexEdit::setHorzScroll( int value )
@@ -1361,13 +1806,209 @@ void QHexEdit::resizeEvent(QResizeEvent *event)
}
//----------------------------------------------------------------------------
+void QHexEdit::openGotoAddrDialog(void)
+{
+ int ret;
+ char stmp[128];
+ QInputDialog dialog(this);
+
+ sprintf( stmp, "Specify Address [ 0x0 -> 0x%X ]", mb.size()-1 );
+
+ dialog.setWindowTitle( tr("Goto Address") );
+ dialog.setLabelText( tr(stmp) );
+ dialog.setOkButtonText( tr("Go") );
+ //dialog.setTextValue( tr("0") );
+
+ dialog.show();
+ ret = dialog.exec();
+
+ if ( QDialog::Accepted == ret )
+ {
+ int addr;
+ std::string s = dialog.textValue().toStdString();
+
+ addr = strtol( s.c_str(), NULL, 16 );
+
+ parent->gotoAddress(addr);
+ }
+}
+//----------------------------------------------------------------------------
void QHexEdit::resetCursor(void)
{
cursorBlink = true;
cursorBlinkCount = 0;
- editAddr = -1;
- editValue = 0;
- editMask = 0;
+ editAddr = -1;
+ editValue = 0;
+ editMask = 0;
+}
+//----------------------------------------------------------------------------
+void QHexEdit::clearHighlight(void)
+{
+ txtHlgtAnchorChar = -1;
+ txtHlgtAnchorLine = -1;
+ txtHlgtStartChar = -1;
+ txtHlgtStartLine = -1;
+ txtHlgtStartAddr = -1;
+ txtHlgtEndChar = -1;
+ txtHlgtEndLine = -1;
+ txtHlgtEndAddr = -1;
+}
+//----------------------------------------------------------------------------
+void QHexEdit::loadClipboard( const char *txt )
+{
+ //printf("Load Clipboard: '%s'\n", txt );
+ clipboard->setText( tr(txt), QClipboard::Clipboard );
+
+ if ( clipboard->supportsSelection() )
+ {
+ clipboard->setText( tr(txt), QClipboard::Selection );
+ }
+}
+//----------------------------------------------------------------------------
+void QHexEdit::pasteFromClipboard(void)
+{
+ int i, val, addr;
+ std::string s = clipboard->text().toStdString();
+ const char *c;
+
+ fceuWrapperLock();
+
+ //printf("Paste: '%s'\n", s.c_str() );
+
+ addr = cursorAddr;
+
+ c = s.c_str();
+
+ i=0;
+ while ( c[i] != 0 )
+ {
+ while ( isspace(c[i]) ) i++;
+
+ val = 0;
+
+ if ( isxdigit(c[i]) )
+ {
+ val = convFromXchar(c[i]) << 4; i++;
+ }
+ else
+ {
+ break;
+ }
+
+ if ( isxdigit(c[i]) )
+ {
+ val |= convFromXchar(c[i]); i++;
+ }
+ else
+ {
+ break;
+ }
+
+ if ( viewMode == QHexEdit::MODE_NES_ROM )
+ {
+ romEditList.applyPatch( addr, val );
+ }
+ writeMem( viewMode, addr, val );
+
+ addr++;
+ }
+ fceuWrapperUnLock();
+}
+//----------------------------------------------------------------------------
+void QHexEdit::loadHighlightToClipboard(void)
+{
+ int a, startAddr, endAddr;
+ std::string s;
+ char c[8];
+
+ fceuWrapperLock();
+
+ startAddr = (txtHlgtStartLine*16) + txtHlgtStartChar;
+ endAddr = (txtHlgtEndLine *16) + txtHlgtEndChar;
+
+ for (a=startAddr; a<=endAddr; a++)
+ {
+ sprintf( c, "%02X ", memAccessFunc(a) );
+
+ s.append(c);
+ }
+ fceuWrapperUnLock();
+
+ loadClipboard( s.c_str() );
+}
+//----------------------------------------------------------------------------
+int QHexEdit::findPattern( std::vector &varray, int dir )
+{
+ int addr, inc, match;
+
+ inc = dir ? -1 : 1;
+ addr = cursorAddr;
+ match = 0;
+
+ //printf("Looking for pattern %zi\n", varray.size() );
+
+ while ( !match )
+ {
+ addr = (addr + inc);
+
+ if ( addr < 0 )
+ {
+ addr = mb.size() - 1;
+ }
+ else if ( addr >= mb.size() )
+ {
+ addr = 0;
+ }
+
+ if ( addr == cursorAddr )
+ {
+ return -1;
+ }
+ match = 1;
+ for (int i=0; i= mb.size() )
+ {
+ match = 0; break;
+ }
+ if ( memAccessFunc(addr+i) != varray[i] )
+ {
+ match = 0; break;
+ }
+ }
+ }
+
+ if ( match )
+ {
+ int endAddr = addr + varray.size() - 1;
+ //printf("Found Match at $%04X\n", addr );
+ txtHlgtStartChar = (addr%16);
+ txtHlgtStartLine = (addr/16);
+ txtHlgtStartAddr = addr;
+ txtHlgtEndChar = (endAddr%16);
+ txtHlgtEndLine = (endAddr/16);
+ txtHlgtEndAddr = (endAddr);
+ cursorAddr = addr;
+ cursorPosX = txtHlgtStartChar*2;
+
+ if ( txtHlgtStartLine < lineOffset )
+ {
+ lineOffset = txtHlgtStartLine;
+ vbar->setValue( lineOffset );
+ }
+ else if ( txtHlgtStartLine >= (lineOffset+viewLines-3) )
+ {
+ lineOffset = txtHlgtStartLine - viewLines + 3;
+
+ if ( lineOffset >= maxLineOffset )
+ {
+ lineOffset = maxLineOffset;
+ }
+ vbar->setValue( lineOffset );
+ }
+ cursorPosY = txtHlgtStartLine - lineOffset;
+ }
+ return 0;
}
//----------------------------------------------------------------------------
QPoint QHexEdit::convPixToCursor( QPoint p )
@@ -1470,10 +2111,10 @@ int QHexEdit::convPixToAddr( QPoint p )
//----------------------------------------------------------------------------
void QHexEdit::keyPressEvent(QKeyEvent *event)
{
- printf("Hex Window Key Press: 0x%x \n", event->key() );
+ //printf("Hex Window Key Press: 0x%x \n", event->key() );
if (event->matches(QKeySequence::MoveToNextChar))
- {
+ {
if ( cursorPosX < 32 )
{
if ( cursorPosX % 2 )
@@ -1494,9 +2135,9 @@ void QHexEdit::keyPressEvent(QKeyEvent *event)
cursorPosX = 47;
}
resetCursor();
- }
+ }
else if (event->matches(QKeySequence::MoveToPreviousChar))
- {
+ {
if ( cursorPosX < 33 )
{
if ( cursorPosX % 2 )
@@ -1517,19 +2158,19 @@ void QHexEdit::keyPressEvent(QKeyEvent *event)
cursorPosX = 0;
}
resetCursor();
- }
+ }
else if (event->matches(QKeySequence::MoveToEndOfLine))
- {
+ {
cursorPosX = 47;
resetCursor();
- }
+ }
else if (event->matches(QKeySequence::MoveToStartOfLine))
- {
+ {
cursorPosX = 0;
resetCursor();
- }
+ }
else if (event->matches(QKeySequence::MoveToPreviousLine))
- {
+ {
cursorPosY--;
if ( cursorPosY < 0 )
@@ -1542,145 +2183,247 @@ void QHexEdit::keyPressEvent(QKeyEvent *event)
}
cursorPosY = 0;
- vbar->setValue( lineOffset );
+ vbar->setValue( lineOffset );
}
resetCursor();
- }
+ }
else if (event->matches(QKeySequence::MoveToNextLine))
- {
+ {
cursorPosY++;
if ( cursorPosY >= viewLines )
{
lineOffset++;
- if ( lineOffset >= maxLineOffset )
- {
- lineOffset = maxLineOffset;
- }
+ if ( lineOffset >= maxLineOffset )
+ {
+ lineOffset = maxLineOffset;
+ }
cursorPosY = viewLines-1;
- vbar->setValue( lineOffset );
+ vbar->setValue( lineOffset );
}
resetCursor();
- }
- else if (event->matches(QKeySequence::MoveToNextPage))
- {
- lineOffset += ( (3 * viewLines) / 4);
+ }
+ else if (event->matches(QKeySequence::MoveToNextPage))
+ {
+ lineOffset += ( (3 * viewLines) / 4);
+
+ if ( lineOffset >= maxLineOffset )
+ {
+ lineOffset = maxLineOffset;
+ }
+ vbar->setValue( lineOffset );
+ resetCursor();
+ }
+ else if (event->matches(QKeySequence::MoveToPreviousPage))
+ {
+ lineOffset -= ( (3 * viewLines) / 4);
- if ( lineOffset >= maxLineOffset )
- {
- lineOffset = maxLineOffset;
- }
- vbar->setValue( lineOffset );
+ if ( lineOffset < 0 )
+ {
+ lineOffset = 0;
+ }
+ vbar->setValue( lineOffset );
resetCursor();
- }
- else if (event->matches(QKeySequence::MoveToPreviousPage))
- {
- lineOffset -= ( (3 * viewLines) / 4);
+ }
+ else if (event->matches(QKeySequence::MoveToEndOfDocument))
+ {
+ lineOffset = maxLineOffset;
+ vbar->setValue( lineOffset );
+ resetCursor();
+ }
+ else if (event->matches(QKeySequence::MoveToStartOfDocument))
+ {
+ lineOffset = 0;
+ vbar->setValue( lineOffset );
+ resetCursor();
+ }
+ else if (Qt::ControlModifier == event->modifiers())
+ {
+ if ( event->key() == Qt::Key_A )
+ {
+ openGotoAddrDialog();
+ }
+ }
+ else if (Qt::ShiftModifier == event->modifiers())
+ {
+ if ( event->key() == Qt::Key_F )
+ {
+ frzRamAddr = ctxAddr = cursorAddr;
+ frzRamToggle();
+ }
+ }
+ else if (event->key() == Qt::Key_Tab && (cursorPosX < 32) )
+ { // switch from hex to ascii edit
+ cursorPosX = 32 + (cursorPosX / 2);
+ }
+ else if (event->key() == Qt::Key_Backtab && (cursorPosX >= 32) )
+ { // switch from ascii to hex edit
+ cursorPosX = 2 * (cursorPosX - 32);
+ }
+ else
+ {
+ int key;
+ if ( cursorPosX >= 32 )
+ { // Edit Area is ASCII
+ key = (uchar)event->text()[0].toLatin1();
- if ( lineOffset < 0 )
- {
- lineOffset = 0;
- }
- vbar->setValue( lineOffset );
- resetCursor();
- }
- else if (event->matches(QKeySequence::MoveToEndOfDocument))
- {
- lineOffset = maxLineOffset;
- vbar->setValue( lineOffset );
- resetCursor();
- }
- else if (event->matches(QKeySequence::MoveToStartOfDocument))
- {
- lineOffset = 0;
- vbar->setValue( lineOffset );
- resetCursor();
- }
- else if (event->key() == Qt::Key_Tab && (cursorPosX < 32) )
- { // switch from hex to ascii edit
- cursorPosX = 32 + (cursorPosX / 2);
- }
- else if (event->key() == Qt::Key_Backtab && (cursorPosX >= 32) )
- { // switch from ascii to hex edit
- cursorPosX = 2 * (cursorPosX - 32);
- }
- else
- {
- int key;
- if ( cursorPosX >= 32 )
- { // Edit Area is ASCII
- key = (uchar)event->text()[0].toLatin1();
-
- if ( ::isascii( key ) )
- {
- int offs = (cursorPosX-32);
- int addr = 16*(lineOffset+cursorPosY) + offs;
+ if ( ::isascii( key ) )
+ {
+ int offs = (cursorPosX-32);
+ int addr = 16*(lineOffset+cursorPosY) + offs;
fceuWrapperLock();
- writeMem( viewMode, addr, key );
+ if ( viewMode == QHexEdit::MODE_NES_ROM )
+ {
+ romEditList.applyPatch( addr, key );
+ }
+ writeMem( viewMode, addr, key );
fceuWrapperUnLock();
-
- editAddr = -1;
- editValue = 0;
- editMask = 0;
- }
- }
- else
- { // Edit Area is Hex
- key = int(event->text()[0].toUpper().toLatin1());
-
- if ( ::isxdigit( key ) )
- {
- int offs, nibbleValue, nibbleIndex;
-
- offs = (cursorPosX / 2);
- nibbleIndex = (cursorPosX % 2);
-
- editAddr = 16*(lineOffset+cursorPosY) + offs;
-
- nibbleValue = convFromXchar( key );
-
- if ( nibbleIndex )
- {
- nibbleValue = editValue | nibbleValue;
-
+
+ editAddr = -1;
+ editValue = 0;
+ editMask = 0;
+ }
+ }
+ else
+ { // Edit Area is Hex
+ key = int(event->text()[0].toUpper().toLatin1());
+
+ if ( ::isxdigit( key ) )
+ {
+ int offs, nibbleValue, nibbleIndex;
+
+ offs = (cursorPosX / 2);
+ nibbleIndex = (cursorPosX % 2);
+
+ editAddr = 16*(lineOffset+cursorPosY) + offs;
+
+ nibbleValue = convFromXchar( key );
+
+ if ( nibbleIndex )
+ {
+ nibbleValue = editValue | nibbleValue;
+
fceuWrapperLock();
- writeMem( viewMode, editAddr, nibbleValue );
+ if ( viewMode == QHexEdit::MODE_NES_ROM )
+ {
+ romEditList.applyPatch( editAddr, nibbleValue );
+ }
+ writeMem( viewMode, editAddr, nibbleValue );
fceuWrapperUnLock();
-
- editAddr = -1;
- editValue = 0;
- editMask = 0;
- }
- else
- {
- editValue = (nibbleValue << 4);
- editMask = 0x00f0;
- }
- cursorPosX++;
-
- if ( cursorPosX >= 32 )
- {
- cursorPosX = 0;
- }
- }
- }
- //printf("Key: %c %i \n", key, key);
- }
+
+ editAddr = -1;
+ editValue = 0;
+ editMask = 0;
+ }
+ else
+ {
+ editValue = (nibbleValue << 4);
+ editMask = 0x00f0;
+ }
+ cursorPosX++;
+
+ if ( cursorPosX >= 32 )
+ {
+ cursorPosX = 0;
+ }
+ }
+ }
+ //printf("Key: %c %i \n", key, key);
+ }
}
//----------------------------------------------------------------------------
void QHexEdit::keyReleaseEvent(QKeyEvent *event)
{
- printf("Hex Window Key Release: 0x%x \n", event->key() );
- //assignHotkey( event );
+ //printf("Hex Window Key Release: 0x%x \n", event->key() );
+}
+//----------------------------------------------------------------------------
+bool QHexEdit::textIsHighlighted(void)
+{
+ bool set = false;
+
+ if ( txtHlgtStartLine == txtHlgtEndLine )
+ {
+ set = (txtHlgtStartChar != txtHlgtEndChar);
+ }
+ else
+ {
+ set = true;
+ }
+ return set;
+}
+//----------------------------------------------------------------------------
+void QHexEdit::setHighlightEndCoord( int x, int y )
+{
+
+ if ( txtHlgtAnchorLine < y )
+ {
+ txtHlgtStartLine = txtHlgtAnchorLine;
+ txtHlgtStartChar = txtHlgtAnchorChar;
+ txtHlgtEndLine = y;
+ txtHlgtEndChar = x;
+ }
+ else if ( txtHlgtAnchorLine > y )
+ {
+ txtHlgtStartLine = y;
+ txtHlgtStartChar = x;
+ txtHlgtEndLine = txtHlgtAnchorLine;
+ txtHlgtEndChar = txtHlgtAnchorChar;
+ }
+ else
+ {
+ txtHlgtStartLine = txtHlgtAnchorLine;
+ txtHlgtEndLine = txtHlgtAnchorLine;
+
+ if ( txtHlgtAnchorChar < x )
+ {
+ txtHlgtStartChar = txtHlgtAnchorChar;
+ txtHlgtEndChar = x;
+ }
+ else if ( txtHlgtAnchorChar > x )
+ {
+ txtHlgtStartChar = x;
+ txtHlgtEndChar = txtHlgtAnchorChar;
+ }
+ else
+ {
+ txtHlgtStartChar = txtHlgtAnchorChar;
+ txtHlgtEndChar = txtHlgtAnchorChar;
+ }
+ }
+ txtHlgtStartAddr = (txtHlgtStartLine*16) + txtHlgtStartChar;
+ txtHlgtEndAddr = (txtHlgtEndLine *16) + txtHlgtEndChar;
+
+ //printf(" (%i,%i) -> (%i,%i) \n", txtHlgtStartChar, txtHlgtStartLine, txtHlgtEndChar, txtHlgtEndLine );
+ return;
+}
+//----------------------------------------------------------------------------
+void QHexEdit::mouseMoveEvent(QMouseEvent * event)
+{
+ //int line;
+ //QPoint c = convPixToCursor( event->pos() );
+ int addr = convPixToAddr( event->pos() );
+
+ //line = lineOffset + c.y();
+
+ //printf("Move c: %ix%i \n", c.x(), c.y() );
+
+ if ( mouseLeftBtnDown )
+ {
+ //printf("Left Button Move: (%i,%i)\n", c.x(), c.y() );
+ setHighlightEndCoord( addr % 16, addr / 16 );
+ }
}
//----------------------------------------------------------------------------
void QHexEdit::mousePressEvent(QMouseEvent * event)
{
+ int addr;
QPoint c = convPixToCursor( event->pos() );
+ addr = convPixToAddr( event->pos() );
+ //line = lineOffset + c.y();
//printf("c: %ix%i \n", c.x(), c.y() );
if ( event->button() == Qt::LeftButton )
@@ -1688,10 +2431,86 @@ void QHexEdit::mousePressEvent(QMouseEvent * event)
cursorPosX = c.x();
cursorPosY = c.y();
resetCursor();
+ mouseLeftBtnDown = true;
+
+ txtHlgtAnchorChar = addr % 16;
+ txtHlgtAnchorLine = addr / 16;
+ setHighlightEndCoord( txtHlgtAnchorChar, txtHlgtAnchorLine );
}
}
//----------------------------------------------------------------------------
+void QHexEdit::mouseReleaseEvent(QMouseEvent * event)
+{
+ //int line;
+ //QPoint c = convPixToCursor( event->pos() );
+ int addr = convPixToAddr( event->pos() );
+
+ //line = lineOffset + c.y();
+ //printf("c: %ix%i \n", c.x(), c.y() );
+
+ if ( event->button() == Qt::LeftButton )
+ {
+ mouseLeftBtnDown = false;
+
+ setHighlightEndCoord( addr % 16, addr / 16 );
+
+ if ( textIsHighlighted() )
+ {
+ loadHighlightToClipboard();
+ }
+ }
+
+}
+//----------------------------------------------------------------------------
+void QHexEdit::wheelEvent(QWheelEvent *event)
+{
+
+ QPoint numPixels = event->pixelDelta();
+ QPoint numDegrees = event->angleDelta();
+
+ if (!numPixels.isNull())
+ {
+ wheelPixelCounter -= numPixels.y();
+ //printf("numPixels: (%i,%i) \n", numPixels.x(), numPixels.y() );
+ }
+ else if (!numDegrees.isNull())
+ {
+ //QPoint numSteps = numDegrees / 15;
+ //printf("numSteps: (%i,%i) \n", numSteps.x(), numSteps.y() );
+ //printf("numDegrees: (%i,%i) %i\n", numDegrees.x(), numDegrees.y(), pxLineSpacing );
+ wheelPixelCounter -= (pxLineSpacing * numDegrees.y()) / (15*8);
+ }
+ //printf("Wheel Event: %i\n", wheelPixelCounter);
+
+ if ( wheelPixelCounter >= pxLineSpacing )
+ {
+ lineOffset += (wheelPixelCounter / pxLineSpacing);
+
+ if ( lineOffset > maxLineOffset )
+ {
+ lineOffset = maxLineOffset;
+ }
+ vbar->setValue( lineOffset );
+
+ wheelPixelCounter = wheelPixelCounter % pxLineSpacing;
+ }
+ else if ( wheelPixelCounter <= -pxLineSpacing )
+ {
+ lineOffset += (wheelPixelCounter / pxLineSpacing);
+
+ if ( lineOffset < 0 )
+ {
+ lineOffset = 0;
+ }
+ vbar->setValue( lineOffset );
+
+ wheelPixelCounter = wheelPixelCounter % pxLineSpacing;
+ }
+
+ event->accept();
+}
+//----------------------------------------------------------------------------
void QHexEdit::contextMenuEvent(QContextMenuEvent *event)
{
QAction *act;
@@ -1699,6 +2518,11 @@ void QHexEdit::contextMenuEvent(QContextMenuEvent *event)
int addr;
char stmp[128];
+ QPoint c = convPixToCursor( event->pos() );
+ cursorPosX = c.x();
+ cursorPosY = c.y();
+ resetCursor();
+
ctxAddr = addr = convPixToAddr( event->pos() );
//printf("contextMenuEvent\n");
@@ -1706,22 +2530,45 @@ void QHexEdit::contextMenuEvent(QContextMenuEvent *event)
{
case MODE_NES_RAM:
{
- act = new QAction(tr("Add Symbolic Debug Name"), this);
+ QMenu *subMenu;
+
+ act = new QAction(tr("Add Symbolic Debug Name"), &menu);
menu.addAction(act);
connect( act, SIGNAL(triggered(void)), this, SLOT(addDebugSym(void)) );
+ subMenu = menu.addMenu(tr("Freeze/Unfreeze Address"));
+
+ act = new QAction(tr("Toggle State"), &menu);
+ act->setShortcut( QKeySequence(tr("Shift+F")));
+ subMenu->addAction(act);
+ connect( act, SIGNAL(triggered(void)), this, SLOT(frzRamToggle(void)) );
+
+ act = new QAction(tr("Freeze"), &menu);
+ subMenu->addAction(act);
+ connect( act, SIGNAL(triggered(void)), this, SLOT(frzRamSet(void)) );
+
+ act = new QAction(tr("Unfreeze"), &menu);
+ subMenu->addAction(act);
+ connect( act, SIGNAL(triggered(void)), this, SLOT(frzRamUnset(void)) );
+
+ subMenu->addSeparator();
+
+ act = new QAction(tr("Unfreeze All"), &menu);
+ subMenu->addAction(act);
+ connect( act, SIGNAL(triggered(void)), this, SLOT(frzRamUnsetAll(void)) );
+
sprintf( stmp, "Add Read Breakpoint for Address $%04X", addr );
- act = new QAction(tr(stmp), this);
+ act = new QAction(tr(stmp), &menu);
menu.addAction(act);
connect( act, SIGNAL(triggered(void)), this, SLOT(addRamReadBP(void)) );
sprintf( stmp, "Add Write Breakpoint for Address $%04X", addr );
- act = new QAction(tr(stmp), this);
+ act = new QAction(tr(stmp), &menu);
menu.addAction(act);
connect( act, SIGNAL(triggered(void)), this, SLOT(addRamWriteBP(void)) );
sprintf( stmp, "Add Execute Breakpoint for Address $%04X", addr );
- act = new QAction(tr(stmp), this);
+ act = new QAction(tr(stmp), &menu);
menu.addAction(act);
connect( act, SIGNAL(triggered(void)), this, SLOT(addRamExecuteBP(void)) );
@@ -1733,13 +2580,13 @@ void QHexEdit::contextMenuEvent(QContextMenuEvent *event)
{
jumpToRomValue = romAddr;
sprintf( stmp, "Go Here in ROM File: (%08X)", romAddr );
- act = new QAction(tr(stmp), this);
+ act = new QAction(tr(stmp), &menu);
menu.addAction(act);
connect( act, SIGNAL(triggered(void)), this, SLOT(jumpToROM(void)) );
}
}
- act = new QAction(tr("Add Bookmark"), this);
+ act = new QAction(tr("Add Bookmark"), &menu);
menu.addAction(act);
connect( act, SIGNAL(triggered(void)), this, SLOT(addBookMarkCB(void)) );
}
@@ -1747,30 +2594,30 @@ void QHexEdit::contextMenuEvent(QContextMenuEvent *event)
case MODE_NES_PPU:
{
sprintf( stmp, "Add Read Breakpoint for Address $%04X", addr );
- act = new QAction(tr(stmp), this);
+ act = new QAction(tr(stmp), &menu);
menu.addAction(act);
connect( act, SIGNAL(triggered(void)), this, SLOT(addPpuReadBP(void)) );
sprintf( stmp, "Add Write Breakpoint for Address $%04X", addr );
- act = new QAction(tr(stmp), this);
+ act = new QAction(tr(stmp), &menu);
menu.addAction(act);
connect( act, SIGNAL(triggered(void)), this, SLOT(addPpuWriteBP(void)) );
- act = new QAction(tr("Add Bookmark"), this);
+ act = new QAction(tr("Add Bookmark"), &menu);
menu.addAction(act);
connect( act, SIGNAL(triggered(void)), this, SLOT(addBookMarkCB(void)) );
}
break;
case MODE_NES_OAM:
{
- act = new QAction(tr("Add Bookmark"), this);
+ act = new QAction(tr("Add Bookmark"), &menu);
menu.addAction(act);
connect( act, SIGNAL(triggered(void)), this, SLOT(addBookMarkCB(void)) );
}
break;
case MODE_NES_ROM:
{
- act = new QAction(tr("Add Bookmark"), this);
+ act = new QAction(tr("Add Bookmark"), &menu);
menu.addAction(act);
connect( act, SIGNAL(triggered(void)), this, SLOT(addBookMarkCB(void)) );
}
@@ -1819,6 +2666,160 @@ void QHexEdit::addBookMarkCB(void)
}
}
//----------------------------------------------------------------------------
+static int RamFreezeCB(char *name, uint32 a, uint8 v, int compare,int s,int type, void *data)
+{
+ return ((QHexEdit*)data)->FreezeRam( name, a, v, compare, s, type );
+}
+//----------------------------------------------------------------------------
+int QHexEdit::FreezeRam( const char *name, uint32_t a, uint8_t v, int c, int s, int type )
+{
+
+ //if ( c >= 0 )
+ //{
+ // printf("$%04X?%02X:%02X %i: %s\n", a, c, v, s, name );
+ //}
+ //else
+ //{
+ // printf("$%04X:%02X %i: %s\n", a, v, s, name );
+ //}
+
+ if ( a == frzRamAddr )
+ {
+ switch ( frzRamMode )
+ {
+ case 0: // Toggle
+
+ if ( s )
+ {
+ FCEUI_DelCheat( frzIdx );
+ frzRamAddr = -1;
+ return 0;
+ }
+ break;
+ case 1: // Freeze
+
+ if ( s )
+ {
+ // Already Set so there is nothing further to do
+ frzRamAddr = -1;
+ return 0;
+ }
+ break;
+ case 2: // Unfreeze
+ if ( s )
+ {
+ FCEUI_DelCheat( frzIdx );
+ }
+ break;
+ default:
+ case 3: // Unfreeze All Handled Below
+ // Nothing to do
+ break;
+ }
+ }
+
+ if ( frzRamMode == 3 )
+ {
+ if ( s )
+ {
+ FCEUI_DelCheat( frzIdx );
+ }
+ }
+
+ frzIdx++;
+
+ return 1;
+}
+//----------------------------------------------------------------------------
+bool QHexEdit::frzRamAddrValid( int addr )
+{
+ if ( addr < 0 )
+ {
+ return false;
+ }
+
+ if ( (addr < 0x2000) || ( (addr >= 0x6000) && (addr <= 0x7FFF) ) )
+ {
+ return true;
+ }
+ return false;
+}
+//----------------------------------------------------------------------------
+void QHexEdit::frzRamSet(void)
+{
+ frzIdx = 0;
+ frzRamMode = 1;
+ frzRamAddr = ctxAddr;
+
+ if ( !frzRamAddrValid( frzRamAddr ) )
+ {
+ return;
+ }
+
+ fceuWrapperLock();
+ FCEUI_ListCheats( RamFreezeCB, this);
+
+ if ( (frzRamAddr >= 0) && (FrozenAddressCount < 256) )
+ {
+ FCEUI_AddCheat("", frzRamAddr, GetMem(frzRamAddr), -1, 1);
+ }
+ updateCheatDialog();
+ fceuWrapperUnLock();
+}
+//----------------------------------------------------------------------------
+void QHexEdit::frzRamUnset(void)
+{
+ frzIdx = 0;
+ frzRamMode = 2;
+ frzRamAddr = ctxAddr;
+
+ if ( !frzRamAddrValid( frzRamAddr ) )
+ {
+ return;
+ }
+ fceuWrapperLock();
+ FCEUI_ListCheats( RamFreezeCB, this);
+ updateCheatDialog();
+ fceuWrapperUnLock();
+}
+//----------------------------------------------------------------------------
+void QHexEdit::frzRamUnsetAll(void)
+{
+ frzIdx = 0;
+ frzRamMode = 3;
+ frzRamAddr = ctxAddr;
+
+ if ( !frzRamAddrValid( frzRamAddr ) )
+ {
+ return;
+ }
+ fceuWrapperLock();
+ FCEUI_ListCheats( RamFreezeCB, this);
+ updateCheatDialog();
+ fceuWrapperUnLock();
+}
+//----------------------------------------------------------------------------
+void QHexEdit::frzRamToggle(void)
+{
+ frzIdx = 0;
+ frzRamMode = 0;
+ frzRamAddr = ctxAddr;
+
+ if ( !frzRamAddrValid( frzRamAddr ) )
+ {
+ return;
+ }
+ fceuWrapperLock();
+ FCEUI_ListCheats( RamFreezeCB, this);
+
+ if ( (frzRamAddr >= 0) && (FrozenAddressCount < 256) )
+ {
+ FCEUI_AddCheat("", frzRamAddr, GetMem(frzRamAddr), -1, 1);
+ }
+ updateCheatDialog();
+ fceuWrapperUnLock();
+}
+//----------------------------------------------------------------------------
void QHexEdit::addDebugSym(void)
{
parent->openDebugSymbolEditWindow( ctxAddr );
@@ -1962,6 +2963,14 @@ void QHexEdit::jumpToROM(void)
setAddr( jumpToRomValue );
}
//----------------------------------------------------------------------------
+void QHexEdit::requestUpdate(void)
+{
+ updateRequested = true;
+}
+//----------------------------------------------------------------------------
+// Calling of checkMemActivity must always be synchronized with the emulation
+// thread as calling GetMem while the emulation is executing can mess up certain
+// registers (especially controller registers $4016 and $4017)
int QHexEdit::checkMemActivity(void)
{
int c;
@@ -1970,10 +2979,13 @@ int QHexEdit::checkMemActivity(void)
// 1. In ROM View Mode
// 2. The simulation is not cycling (paused)
- if ( ( viewMode == MODE_NES_ROM ) ||
- ( total_instructions_lp == total_instructions ) )
+ if ( !updateRequested )
{
- return -1;
+ if ( ( viewMode == MODE_NES_ROM ) ||
+ ( total_instructions_lp == total_instructions ) )
+ {
+ return -1;
+ }
}
for (int i=0; i= txtHlgtStartAddr) && (addr <= txtHlgtEndAddr) )
+ {
+ fg.setRgb( 255, 255, 255 ); // white
+ bg.setRgb( 0, 0, 255 ); // blue
+ return 0;
+ }
+ if ( romEditList.isModified( addr ) )
+ {
+ fg.setRgb( 255, 255, 255 ); // white
+ bg.setRgb( 255, 0, 0 ); // red
+ return 0;
+ }
if (cdloggerdataSize == 0)
{
return -1;
@@ -2160,9 +3187,11 @@ void QHexEdit::memModeUpdate(void)
void QHexEdit::paintEvent(QPaintEvent *event)
{
int x, y, w, h, row, col, nrow, addr;
- int c, cx, cy, ca;
+ int c, cx, cy, ca, l;
char txt[32], asciiTxt[4];
QPainter painter(this);
+ QColor white("white"), black("black"), blue("blue");
+ bool txtHlgtSet;
painter.setFont(font);
w = event->rect().width();
@@ -2238,12 +3267,15 @@ void QHexEdit::paintEvent(QPaintEvent *event)
painter.setPen( this->palette().color(QPalette::WindowText));
- //painter.setPen( QColor("white") );
addr = lineOffset * 16;
y = pxYoffset;
+ txtHlgtSet = textIsHighlighted();
+
+
for ( row=0; row < nrow; row++)
{
+ l = lineOffset + row;
x = pxXoffset - pxLineXScroll;
painter.setPen( this->palette().color(QPalette::WindowText));
@@ -2252,6 +3284,59 @@ void QHexEdit::paintEvent(QPaintEvent *event)
x = pxHexOffset - pxLineXScroll;
+ if ( txtHlgtSet && (l >= txtHlgtStartLine) && (l <= txtHlgtEndLine) )
+ {
+ int hlgtXs, hlgtXe, hlgtXd;
+
+ if ( l == txtHlgtStartLine )
+ {
+ hlgtXs = txtHlgtStartChar*3;
+ }
+ else
+ {
+ hlgtXs = 0;
+ }
+
+ if ( l == txtHlgtEndLine )
+ {
+ hlgtXe = (txtHlgtEndChar+1)*3;
+ }
+ else
+ {
+ hlgtXe = 16*3;
+ }
+ hlgtXd = hlgtXe - hlgtXs;
+
+ x = pxHexOffset - pxLineXScroll;
+
+ painter.fillRect( x + (hlgtXs*pxCharWidth), y - pxLineSpacing + pxLineLead, hlgtXd*pxCharWidth, pxLineSpacing, blue );
+
+ if ( l == txtHlgtStartLine )
+ {
+ hlgtXs = txtHlgtStartChar;
+ }
+ else
+ {
+ hlgtXs = 0;
+ }
+
+ if ( l == txtHlgtEndLine )
+ {
+ hlgtXe = (txtHlgtEndChar+1);
+ }
+ else
+ {
+ hlgtXe = 16;
+ }
+ hlgtXd = hlgtXe - hlgtXs;
+
+ x = pxHexAscii - pxLineXScroll;
+
+ painter.fillRect( x + (hlgtXs*pxCharWidth), y - pxLineSpacing + pxLineLead, hlgtXd*pxCharWidth, pxLineSpacing, blue );
+ }
+
+ x = pxHexOffset - pxLineXScroll;
+
for (col=0; col<16; col++)
{
if ( addr < mb.size() )
@@ -2268,17 +3353,17 @@ void QHexEdit::paintEvent(QPaintEvent *event)
}
asciiTxt[1] = 0;
- if ( addr == editAddr )
- { // Set a cell currently being editting to red text
- painter.setPen( QColor("red") );
- txt[0] = convToXchar( (editValue >> 4) & 0x0F );
- txt[1] = convToXchar( c & 0x0F );
- txt[2] = 0;
- painter.drawText( x, y, tr(txt) );
- painter.setPen( this->palette().color(QPalette::WindowText));
- }
- else
- {
+ if ( addr == editAddr )
+ { // Set a cell currently being editting to red text
+ painter.setPen( QColor("red") );
+ txt[0] = convToXchar( (editValue >> 4) & 0x0F );
+ txt[1] = convToXchar( c & 0x0F );
+ txt[2] = 0;
+ painter.drawText( x, y, tr(txt) );
+ painter.setPen( this->palette().color(QPalette::WindowText));
+ }
+ else
+ {
if ( viewMode == MODE_NES_ROM )
{
QColor romBgColor, romFgColor;
@@ -2287,43 +3372,76 @@ void QHexEdit::paintEvent(QPaintEvent *event)
if ( reverseVideo )
{
- painter.setPen( romFgColor );
+ painter.setPen( romFgColor );
painter.fillRect( x - (0.5*pxCharWidth) , y-pxLineSpacing+pxLineLead, 3*pxCharWidth, pxLineSpacing, romBgColor );
painter.fillRect( pxHexAscii + (col*pxCharWidth) - pxLineXScroll, y-pxLineSpacing+pxLineLead, pxCharWidth, pxLineSpacing, romBgColor );
}
else
{
- painter.setPen( romFgColor );
+ painter.setPen( romFgColor );
+ }
+ }
+ else if ( viewMode == MODE_NES_RAM )
+ {
+ if ( FCEUI_FindCheatMapByte( addr ) )
+ {
+ if ( reverseVideo )
+ {
+ painter.setPen( white );
+ painter.fillRect( x - (0.5*pxCharWidth) , y-pxLineSpacing+pxLineLead, 3*pxCharWidth, pxLineSpacing, blue );
+ painter.fillRect( pxHexAscii + (col*pxCharWidth) - pxLineXScroll, y-pxLineSpacing+pxLineLead, pxCharWidth, pxLineSpacing, blue );
+ }
+ else
+ {
+ painter.setPen( blue );
+ }
+ }
+ else if ( actvHighlightEnable && (mb.buf[addr].actv > 0) )
+ {
+ if ( reverseVideo )
+ {
+ painter.setPen( rvActvTextColor[ mb.buf[addr].actv ] );
+ painter.fillRect( x - (0.5*pxCharWidth) , y-pxLineSpacing+pxLineLead, 3*pxCharWidth, pxLineSpacing, highLightColor[ mb.buf[addr].actv ] );
+ painter.fillRect( pxHexAscii + (col*pxCharWidth) - pxLineXScroll, y-pxLineSpacing+pxLineLead, pxCharWidth, pxLineSpacing, highLightColor[ mb.buf[addr].actv ] );
+ }
+ else
+ {
+ painter.setPen( highLightColor[ mb.buf[addr].actv ] );
+ }
+ }
+ else
+ {
+ painter.setPen( this->palette().color(QPalette::WindowText));
}
}
else if ( actvHighlightEnable && (mb.buf[addr].actv > 0) )
{
if ( reverseVideo )
{
- painter.setPen( rvActvTextColor[ mb.buf[addr].actv ] );
+ painter.setPen( rvActvTextColor[ mb.buf[addr].actv ] );
painter.fillRect( x - (0.5*pxCharWidth) , y-pxLineSpacing+pxLineLead, 3*pxCharWidth, pxLineSpacing, highLightColor[ mb.buf[addr].actv ] );
painter.fillRect( pxHexAscii + (col*pxCharWidth) - pxLineXScroll, y-pxLineSpacing+pxLineLead, pxCharWidth, pxLineSpacing, highLightColor[ mb.buf[addr].actv ] );
}
else
{
- painter.setPen( highLightColor[ mb.buf[addr].actv ] );
+ painter.setPen( highLightColor[ mb.buf[addr].actv ] );
}
}
else
{
- painter.setPen( this->palette().color(QPalette::WindowText));
+ painter.setPen( this->palette().color(QPalette::WindowText));
}
- txt[0] = convToXchar( (c >> 4) & 0x0F );
- txt[1] = convToXchar( c & 0x0F );
- txt[2] = 0;
+ txt[0] = convToXchar( (c >> 4) & 0x0F );
+ txt[1] = convToXchar( c & 0x0F );
+ txt[2] = 0;
if ( cursorBlink && (ca == addr) )
{
painter.fillRect( cx , cy, pxCharWidth, pxCursorHeight, QColor("gray") );
}
- painter.drawText( x, y, tr(txt) );
+ painter.drawText( x, y, tr(txt) );
painter.drawText( pxHexAscii + (col*pxCharWidth) - pxLineXScroll, y, tr(asciiTxt) );
- }
+ }
}
x += (3*pxCharWidth);
addr++;
@@ -2333,7 +3451,7 @@ void QHexEdit::paintEvent(QPaintEvent *event)
y += pxLineSpacing;
}
- painter.setPen( this->palette().color(QPalette::WindowText));
+ painter.setPen( this->palette().color(QPalette::WindowText));
painter.drawText( pxHexOffset - pxLineXScroll, pxLineSpacing, "00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F" );
painter.drawLine( pxHexOffset - (pxCharWidth/2) - pxLineXScroll, 0, pxHexOffset - (pxCharWidth/2) - pxLineXScroll, h );
painter.drawLine( pxHexAscii - (pxCharWidth/2) - pxLineXScroll, 0, pxHexAscii - (pxCharWidth/2) - pxLineXScroll, h );
@@ -2368,6 +3486,16 @@ void hexEditorSaveBookmarks(void)
}
}
//----------------------------------------------------------------------------
+void hexEditorRequestUpdateAll(void)
+{
+ std::list ::iterator it;
+
+ for (it = winList.begin(); it != winList.end(); it++)
+ {
+ (*it)->editor->requestUpdate();
+ }
+}
+//----------------------------------------------------------------------------
int hexEditorNumWindows(void)
{
return winList.size();
@@ -2395,3 +3523,20 @@ int hexEditorOpenFromDebugger( int mode, int addr )
return 0;
}
//----------------------------------------------------------------------------
+// This function must be called from within the emulation thread
+void hexEditorUpdateMemoryValues(void)
+{
+ std::list ::iterator it;
+
+ if ( !memNeedsCheck )
+ {
+ return;
+ }
+
+ for (it = winList.begin(); it != winList.end(); it++)
+ {
+ (*it)->editor->checkMemActivity();
+ }
+ memNeedsCheck = false;
+}
+//----------------------------------------------------------------------------
diff --git a/src/drivers/Qt/HexEditor.h b/src/drivers/Qt/HexEditor.h
index a7f5a8b1..7d504e7a 100644
--- a/src/drivers/Qt/HexEditor.h
+++ b/src/drivers/Qt/HexEditor.h
@@ -14,7 +14,9 @@
#include
#include
#include
+#include
#include
+#include
#include
#include
#include
@@ -113,8 +115,15 @@ class QHexEdit : public QWidget
void setForeGroundColor( QColor fg );
void setBackGroundColor( QColor bg );
void memModeUpdate(void);
+ void openGotoAddrDialog(void);
int checkMemActivity(void);
int getAddr(void){ return cursorAddr; };
+ int FreezeRam( const char *name, uint32_t a, uint8_t v, int c, int s, int type );
+ void loadHighlightToClipboard(void);
+ void pasteFromClipboard(void);
+ void clearHighlight(void);
+ int findPattern( std::vector &varray, int dir );
+ void requestUpdate(void);
enum {
MODE_NES_RAM = 0,
@@ -126,15 +135,22 @@ class QHexEdit : public QWidget
protected:
void paintEvent(QPaintEvent *event);
void keyPressEvent(QKeyEvent *event);
- void keyReleaseEvent(QKeyEvent *event);
+ void keyReleaseEvent(QKeyEvent *event);
void mousePressEvent(QMouseEvent * event);
+ void mouseReleaseEvent(QMouseEvent * event);
+ void mouseMoveEvent(QMouseEvent * event);
+ void wheelEvent(QWheelEvent *event);
void resizeEvent(QResizeEvent *event);
void contextMenuEvent(QContextMenuEvent *event);
void calcFontData(void);
void resetCursor(void);
+ bool textIsHighlighted(void);
+ void setHighlightEndCoord( int x, int y );
QPoint convPixToCursor( QPoint p );
int convPixToAddr( QPoint p );
+ bool frzRamAddrValid( int addr );
+ void loadClipboard( const char *txt );
QFont font;
@@ -147,12 +163,13 @@ class QHexEdit : public QWidget
QScrollBar *hbar;
QColor highLightColor[ HIGHLIGHT_ACTIVITY_NUM_COLORS ];
QColor rvActvTextColor[ HIGHLIGHT_ACTIVITY_NUM_COLORS ];
+ QClipboard *clipboard;
HexEditorDialog_t *parent;
uint64_t total_instructions_lp;
- int viewMode;
+ int viewMode;
int lineOffset;
int pxCharWidth;
int pxCharHeight;
@@ -172,16 +189,31 @@ class QHexEdit : public QWidget
int viewLines;
int viewWidth;
int viewHeight;
- int maxLineOffset;
- int editAddr;
- int editValue;
- int editMask;
+ int maxLineOffset;
+ int editAddr;
+ int editValue;
+ int editMask;
int jumpToRomValue;
int ctxAddr;
+ int frzRamAddr;
+ int frzRamVal;
+ int frzRamMode;
+ int frzIdx;
+ int wheelPixelCounter;
+ int txtHlgtAnchorChar;
+ int txtHlgtAnchorLine;
+ int txtHlgtStartChar;
+ int txtHlgtStartLine;
+ int txtHlgtStartAddr;
+ int txtHlgtEndChar;
+ int txtHlgtEndLine;
+ int txtHlgtEndAddr;
bool cursorBlink;
bool reverseVideo;
bool actvHighlightEnable;
+ bool mouseLeftBtnDown;
+ bool updateRequested;
private slots:
void jumpToROM(void);
@@ -192,9 +224,35 @@ class QHexEdit : public QWidget
void addRamExecuteBP(void);
void addPpuReadBP(void);
void addPpuWriteBP(void);
+ void frzRamSet(void);
+ void frzRamUnset(void);
+ void frzRamToggle(void);
+ void frzRamUnsetAll(void);
};
+class HexEditorFindDialog_t : public QDialog
+{
+ Q_OBJECT
+ public:
+ HexEditorFindDialog_t(QWidget *parent = 0);
+ ~HexEditorFindDialog_t(void);
+
+ QLineEdit *searchBox;
+ QRadioButton *upBtn;
+ QRadioButton *dnBtn;
+ QRadioButton *hexBtn;
+ QRadioButton *txtBtn;
+ protected:
+ void closeEvent(QCloseEvent *bar);
+
+ HexEditorDialog_t *parent;
+
+ public slots:
+ void closeWindow(void);
+ void runSearch(void);
+};
+
class HexEditorDialog_t : public QDialog
{
Q_OBJECT
@@ -209,8 +267,9 @@ class HexEditorDialog_t : public QDialog
void openDebugSymbolEditWindow( int addr );
QHexEdit *editor;
- protected:
+ HexEditorFindDialog_t *findDialog;
+ protected:
void closeEvent(QCloseEvent *bar);
QScrollBar *vbar;
@@ -221,11 +280,13 @@ class HexEditorDialog_t : public QDialog
QAction *viewPPU;
QAction *viewOAM;
QAction *viewROM;
+ QAction *gotoAddrAct;
+ QAction *undoEditAct;
private:
- public slots:
- void closeWindow(void);
+ public slots:
+ void closeWindow(void);
private slots:
void updatePeriodic(void);
void vbarMoved(int value);
@@ -242,9 +303,16 @@ class HexEditorDialog_t : public QDialog
void pickForeGroundColor(void);
void pickBackGroundColor(void);
void removeAllBookmarks(void);
+ void openGotoAddrDialog(void);
+ void copyToClipboard(void);
+ void pasteFromClipboard(void);
+ void openFindDialog(void);
+ void undoRomPatch(void);
};
int hexEditorNumWindows(void);
+void hexEditorRequestUpdateAll(void);
+void hexEditorUpdateMemoryValues(void);
void hexEditorLoadBookmarks(void);
void hexEditorSaveBookmarks(void);
int hexEditorOpenFromDebugger( int mode, int addr );
diff --git a/src/drivers/Qt/HotKeyConf.cpp b/src/drivers/Qt/HotKeyConf.cpp
index d1db2131..db3ff4aa 100644
--- a/src/drivers/Qt/HotKeyConf.cpp
+++ b/src/drivers/Qt/HotKeyConf.cpp
@@ -24,7 +24,6 @@ HotKeyConfDialog_t::HotKeyConfDialog_t(QWidget *parent)
QVBoxLayout *mainLayout;
QTreeWidgetItem *item;
std::string prefix = "SDL.Hotkeys.";
- int keycode;
setWindowTitle("Hotkey Configuration");
@@ -48,14 +47,16 @@ HotKeyConfDialog_t::HotKeyConfDialog_t(QWidget *parent)
for (int i=0; igetOption (optionName.c_str (), &keycode);
+ //g_config->getOption (optionName.c_str (), &keycode);
+ Hotkeys[i].getString( keyName );
item = new QTreeWidgetItem();
item->setText( 0, QString::fromStdString( optionName ) );
- item->setText( 1, QString::fromStdString( SDL_GetKeyName (keycode) ) );
+ item->setText( 1, QString::fromStdString( keyName ) );
item->setTextAlignment( 0, Qt::AlignLeft);
item->setTextAlignment( 1, Qt::AlignCenter);
@@ -89,9 +90,17 @@ void HotKeyConfDialog_t::closeWindow(void)
//----------------------------------------------------------------------------
void HotKeyConfDialog_t::assignHotkey(QKeyEvent *event)
{
+ bool keyIsModifier;
SDL_Keycode k = convQtKey2SDLKeyCode( (Qt::Key)event->key() );
+ SDL_Keymod m = convQtKey2SDLModifier( event->modifiers() );
- if ( k != SDLK_UNKNOWN )
+ keyIsModifier = (k == SDLK_LCTRL ) || (k == SDLK_RCTRL ) ||
+ (k == SDLK_LSHIFT) || (k == SDLK_RSHIFT) ||
+ (k == SDLK_LALT ) || (k == SDLK_RALT ) ||
+ (k == SDLK_LGUI ) || (k == SDLK_RGUI ) ||
+ (k == SDLK_CAPSLOCK);
+
+ if ( (k != SDLK_UNKNOWN) && !keyIsModifier )
{
QList l;
@@ -99,21 +108,59 @@ void HotKeyConfDialog_t::assignHotkey(QKeyEvent *event)
for (size_t i=0; i < l.size(); i++)
{
- //int idx;
+ int j,idx;
QString qs;
QTreeWidgetItem *item;
+ std::string keyText;
+ char keyName[128];
+ char buf[256];
+
+
+ keyText.assign(" mod=");
+
+ j=0;
+ if ( m & (KMOD_LSHIFT | KMOD_RSHIFT) )
+ {
+ if ( j > 0 )
+ {
+ keyText.append("+");
+ }
+ keyText.append("Shift"); j++;
+ }
+ if ( m & (KMOD_LALT | KMOD_RALT) )
+ {
+ if ( j > 0 )
+ {
+ keyText.append("+");
+ }
+ keyText.append("Alt"); j++;
+ }
+ if ( m & (KMOD_LCTRL | KMOD_RCTRL) )
+ {
+ if ( j > 0 )
+ {
+ keyText.append("+");
+ }
+ keyText.append("Ctrl"); j++;
+ }
+
+ sprintf( buf, " key=%s", SDL_GetKeyName( k ) );
+
+ keyText.append( buf );
item = l.at(i);
- //idx = tree->indexOfTopLevelItem( item );
+ idx = tree->indexOfTopLevelItem( item );
qs = item->text(0);
- g_config->setOption ( qs.toStdString(), k );
+ g_config->setOption ( qs.toStdString(), keyText );
setHotKeys();
- item->setText( 1, QString::fromStdString( SDL_GetKeyName (k) ) );
+ Hotkeys[idx].getString( keyName );
+
+ item->setText( 1, QString::fromStdString( keyName ) );
//printf("Hotkey Window Key Press: 0x%x item:%p\n '%s' : %i\n",
// k, item, qs.toStdString().c_str(), idx );
diff --git a/src/drivers/Qt/InputConf.cpp b/src/drivers/Qt/InputConf.cpp
new file mode 100644
index 00000000..56d88a23
--- /dev/null
+++ b/src/drivers/Qt/InputConf.cpp
@@ -0,0 +1,562 @@
+// InputConf.cpp
+//
+#include
+#include
+#include
+#include
+
+#include
+#include
+#include
+#include
+#include
+
+#include "Qt/main.h"
+#include "Qt/dface.h"
+#include "Qt/input.h"
+#include "Qt/config.h"
+#include "Qt/keyscan.h"
+#include "Qt/fceuWrapper.h"
+#include "Qt/ConsoleWindow.h"
+#include "Qt/ConsoleUtilities.h"
+#include "Qt/InputConf.h"
+
+static InputConfDialog_t *win = NULL;
+//----------------------------------------------------------------------------
+void openInputConfWindow( QWidget *parent )
+{
+ if ( win != NULL )
+ {
+ return;
+ }
+ win = new InputConfDialog_t(parent);
+
+ win->show();
+}
+//----------------------------------------------------------------------------
+InputConfDialog_t::InputConfDialog_t(QWidget *parent)
+ : QDialog( parent )
+{
+ QVBoxLayout *mainLayout, *vbox1, *vbox;
+ QHBoxLayout *hbox;
+ QGroupBox *nesInputFrame, *port1Frame, *port2Frame;
+ QGroupBox *presetFrame, *expansionPortFrame;
+ QPalette pal;
+ QColor color;
+ char stmp[256];
+ int fourscore, autoInputPreset;
+
+ pal = this->palette();
+
+ inputTimer = new QTimer( this );
+
+ connect( inputTimer, &QTimer::timeout, this, &InputConfDialog_t::updatePeriodic );
+
+ setWindowTitle("Input Configuration");
+
+ mainLayout = new QVBoxLayout();
+
+ nesInputFrame = new QGroupBox( tr("NES-Style Input Ports") );
+ vbox1 = new QVBoxLayout();
+ hbox = new QHBoxLayout();
+ fourScoreEna = new QCheckBox( tr("Attach 4-Score (Implies four gamepads)") );
+ port2Mic = new QCheckBox( tr("Replace Port 2 Start with Microphone") );
+ autoPreset = new QCheckBox( tr("Auto Load/Save Presets at ROM Open/Close") );
+
+ g_config->getOption("SDL.FourScore", &fourscore);
+ fourScoreEna->setChecked( fourscore );
+ port2Mic->setChecked( replaceP2StartWithMicrophone );
+
+ g_config->getOption( "SDL.AutoInputPreset", &autoInputPreset );
+ autoPreset->setChecked( autoInputPreset );
+
+ hbox->addWidget( fourScoreEna );
+ hbox->addWidget( port2Mic );
+ vbox1->addLayout( hbox );
+
+ hbox = new QHBoxLayout();
+ port1Frame = new QGroupBox( tr("Port 1:") );
+ port2Frame = new QGroupBox( tr("Port 2:") );
+
+ hbox->addWidget( port1Frame );
+ hbox->addWidget( port2Frame );
+ vbox1->addLayout( hbox );
+
+ nesPortComboxBox[0] = new QComboBox();
+ nesPortComboxBox[1] = new QComboBox();
+ expPortComboxBox = new QComboBox();
+
+ vbox = new QVBoxLayout();
+ hbox = new QHBoxLayout();
+
+ vbox->addLayout( hbox );
+ hbox->addWidget( nesPortLabel[0] = new QLabel( tr("") ) );
+ hbox->addWidget( nesPortConfButton[0] = new QPushButton( tr("Configure") ) );
+ vbox->addWidget( nesPortComboxBox[0] );
+
+ port1Frame->setLayout( vbox );
+
+ vbox = new QVBoxLayout();
+ hbox = new QHBoxLayout();
+
+ vbox->addLayout( hbox );
+ hbox->addWidget( nesPortLabel[1] = new QLabel( tr("") ) );
+ hbox->addWidget( nesPortConfButton[1] = new QPushButton( tr("Configure") ) );
+ vbox->addWidget( nesPortComboxBox[1] );
+
+ port2Frame->setLayout( vbox );
+
+ nesInputFrame->setLayout( vbox1 );
+ nesPortConfButton[0]->setEnabled(false);
+ nesPortConfButton[1]->setEnabled(false);
+
+ mainLayout->addWidget( nesInputFrame );
+
+ hbox = new QHBoxLayout();
+ presetFrame = new QGroupBox( tr("Input Presets:") );
+ expansionPortFrame = new QGroupBox( tr("Famicom Expansion Port:") );
+
+ hbox->addWidget( presetFrame );
+ hbox->addWidget( expansionPortFrame );
+
+ mainLayout->addLayout( hbox );
+
+ vbox = new QVBoxLayout();
+ hbox = new QHBoxLayout();
+ vbox->addLayout( hbox );
+ hbox->addWidget( autoPreset );
+
+ hbox = new QHBoxLayout();
+ vbox->addLayout( hbox );
+ hbox->addWidget( loadConfigButton = new QPushButton( tr("Load") ) );
+ hbox->addWidget( saveConfigButton = new QPushButton( tr("Save") ) );
+
+ presetFrame->setLayout( vbox );
+
+ vbox = new QVBoxLayout();
+ hbox = new QHBoxLayout();
+
+ vbox->addLayout( hbox );
+ hbox->addWidget( expPortLabel = new QLabel( tr("") ) );
+ hbox->addWidget( expPortConfButton = new QPushButton( tr("Configure") ) );
+ vbox->addWidget( expPortComboxBox );
+
+ expPortConfButton->setEnabled(false);
+ expansionPortFrame->setLayout( vbox );
+
+ color = pal.color(QPalette::WindowText);
+
+ sprintf( stmp, "border: 2px solid #%02X%02X%02X", color.red(), color.green(), color.blue() );
+
+ //printf("%s\n", stmp);
+ nesPortLabel[0]->setAlignment(Qt::AlignCenter);
+ nesPortLabel[1]->setAlignment(Qt::AlignCenter);
+ expPortLabel->setAlignment(Qt::AlignCenter);
+ nesPortLabel[0]->setStyleSheet( stmp );
+ nesPortLabel[1]->setStyleSheet( stmp );
+ expPortLabel->setStyleSheet( stmp );
+
+ setLayout( mainLayout );
+
+ for (int i=0; i<2; i++)
+ {
+ getInputSelection( i, &curNesInput[i], &usrNesInput[i] );
+ nesPortComboxBox[i]->addItem( tr("") , SI_NONE );
+ nesPortComboxBox[i]->addItem( tr("Gamepad") , SI_GAMEPAD );
+ nesPortComboxBox[i]->addItem( tr("Zapper") , SI_ZAPPER );
+ nesPortComboxBox[i]->addItem( tr("Power Pad A") , SI_POWERPADA );
+ nesPortComboxBox[i]->addItem( tr("Power Pad B") , SI_POWERPADB );
+ nesPortComboxBox[i]->addItem( tr("Arkanoid Paddle") , SI_ARKANOID );
+
+ for (int j=0; jcount(); j++)
+ {
+ if ( nesPortComboxBox[i]->itemData(j).toInt() == curNesInput[i] )
+ {
+ nesPortComboxBox[i]->setCurrentIndex( j );
+ }
+ if ( nesPortComboxBox[i]->itemData(j).toInt() == curNesInput[i] )
+ {
+ nesPortLabel[i]->setText( nesPortComboxBox[i]->itemText(j) );
+ }
+ }
+ }
+
+ getInputSelection( 2, &curNesInput[2], &usrNesInput[2] );
+ expPortComboxBox->addItem( tr("") , SIFC_NONE );
+ expPortComboxBox->addItem( tr("Arkanoid Paddle") , SIFC_ARKANOID );
+ expPortComboxBox->addItem( tr("Shadow") , SIFC_SHADOW );
+ expPortComboxBox->addItem( tr("Hyper Shot Gun") , SIFC_HYPERSHOT );
+ expPortComboxBox->addItem( tr("Family Keyboard") , SIFC_FKB );
+ expPortComboxBox->addItem( tr("Mahjong") , SIFC_MAHJONG );
+ expPortComboxBox->addItem( tr("Quiz King Buzzers"), SIFC_QUIZKING );
+ expPortComboxBox->addItem( tr("Family Trainer A") , SIFC_FTRAINERA );
+ expPortComboxBox->addItem( tr("Family Trainer B") , SIFC_FTRAINERB );
+ expPortComboxBox->addItem( tr("Oeka Kids Tablet") , SIFC_OEKAKIDS );
+ expPortComboxBox->addItem( tr("Top Rider") , SIFC_TOPRIDER );
+
+ for (int j=0; jcount(); j++)
+ {
+ if ( expPortComboxBox->itemData(j).toInt() == curNesInput[2] )
+ {
+ expPortComboxBox->setCurrentIndex( j );
+ }
+ if ( expPortComboxBox->itemData(j).toInt() == curNesInput[2] )
+ {
+ expPortLabel->setText( expPortComboxBox->itemText(j) );
+ }
+ }
+
+ connect( fourScoreEna, SIGNAL(stateChanged(int)), this, SLOT(fourScoreChanged(int)) );
+ connect( port2Mic , SIGNAL(stateChanged(int)), this, SLOT(port2MicChanged(int)) );
+ connect( autoPreset , SIGNAL(stateChanged(int)), this, SLOT(autoPresetChanged(int)));
+
+ connect( nesPortComboxBox[0], SIGNAL(activated(int)), this, SLOT(port1Select(int)) );
+ connect( nesPortComboxBox[1], SIGNAL(activated(int)), this, SLOT(port2Select(int)) );
+ connect( expPortComboxBox , SIGNAL(activated(int)), this, SLOT(expSelect(int)) );
+
+ connect( nesPortConfButton[0], SIGNAL(clicked(void)), this, SLOT(port1Configure(void)) );
+ connect( nesPortConfButton[1], SIGNAL(clicked(void)), this, SLOT(port2Configure(void)) );
+
+ connect( loadConfigButton, SIGNAL(clicked(void)), this, SLOT(openLoadPresetFile(void)) );
+ connect( saveConfigButton, SIGNAL(clicked(void)), this, SLOT(openSavePresetFile(void)) );
+
+ updatePortLabels();
+
+ inputTimer->start( 500 ); // 2hz
+}
+//----------------------------------------------------------------------------
+InputConfDialog_t::~InputConfDialog_t(void)
+{
+ printf("Destroy Input Config Window\n");
+ inputTimer->stop();
+
+ if ( win == this )
+ {
+ win = NULL;
+ }
+}
+//----------------------------------------------------------------------------
+void InputConfDialog_t::closeEvent(QCloseEvent *event)
+{
+ printf("Input Config Close Window Event\n");
+ done(0);
+ deleteLater();
+ event->accept();
+}
+//----------------------------------------------------------------------------
+void InputConfDialog_t::closeWindow(void)
+{
+ //printf("Close Window\n");
+ done(0);
+ deleteLater();
+}
+//----------------------------------------------------------------------------
+void InputConfDialog_t::setInputs(void)
+{
+ int idx[3];
+ ESI port[2];
+ ESIFC fcexp;
+ int fourscore = false, microphone = false;
+
+ g_config->getOption("SDL.FourScore", &fourscore);
+
+ microphone = port2Mic->isChecked();
+
+ idx[0] = nesPortComboxBox[0]->currentIndex();
+ idx[1] = nesPortComboxBox[1]->currentIndex();
+ idx[2] = expPortComboxBox->currentIndex();
+
+ port[0] = (ESI)nesPortComboxBox[0]->itemData( idx[0] ).toInt();
+ port[1] = (ESI)nesPortComboxBox[1]->itemData( idx[1] ).toInt();
+ fcexp = (ESIFC)expPortComboxBox->itemData( idx[2] ).toInt();
+
+ FCEUD_SetInput( fourscore, microphone, port[0], port[1], fcexp );
+}
+//----------------------------------------------------------------------------
+void InputConfDialog_t::updatePortLabels(void)
+{
+
+ for (int i=0; i<2; i++)
+ {
+ getInputSelection( i, &curNesInput[i], &usrNesInput[i] );
+
+ for (int j=0; jcount(); j++)
+ {
+ if ( nesPortComboxBox[i]->itemData(j).toInt() == curNesInput[i] )
+ {
+ nesPortLabel[i]->setText( nesPortComboxBox[i]->itemText(j) );
+ }
+ }
+
+ nesPortConfButton[i]->setEnabled( curNesInput[i] == SI_GAMEPAD );
+ }
+
+ getInputSelection( 2, &curNesInput[2], &usrNesInput[2] );
+
+ for (int j=0; jcount(); j++)
+ {
+ if ( expPortComboxBox->itemData(j).toInt() == curNesInput[2] )
+ {
+ expPortLabel->setText( expPortComboxBox->itemText(j) );
+ }
+ }
+}
+//----------------------------------------------------------------------------
+void InputConfDialog_t::updatePortComboBoxes(void)
+{
+ for (int i=0; i<2; i++)
+ {
+ getInputSelection( i, &curNesInput[i], &usrNesInput[i] );
+
+ for (int j=0; jcount(); j++)
+ {
+ if ( nesPortComboxBox[i]->itemData(j).toInt() == curNesInput[i] )
+ {
+ nesPortComboxBox[i]->setCurrentIndex( j );
+ }
+ }
+ }
+
+ getInputSelection( 2, &curNesInput[2], &usrNesInput[2] );
+
+ for (int j=0; jcount(); j++)
+ {
+ if ( expPortComboxBox->itemData(j).toInt() == curNesInput[2] )
+ {
+ expPortComboxBox->setCurrentIndex( j );
+ }
+ }
+}
+//----------------------------------------------------------------------------
+void InputConfDialog_t::port1Select(int index)
+{
+ //printf("Port 1 Number:%i \n", index);
+ setInputs();
+ updatePortLabels();
+}
+//----------------------------------------------------------------------------
+void InputConfDialog_t::port2Select(int index)
+{
+ //printf("Port 2 Number:%i \n", index);
+ setInputs();
+ updatePortLabels();
+}
+//----------------------------------------------------------------------------
+void InputConfDialog_t::expSelect(int index)
+{
+ //printf("Expansion Port Number:%i \n", index);
+ setInputs();
+ updatePortLabels();
+}
+//----------------------------------------------------------------------------
+void InputConfDialog_t::fourScoreChanged(int state)
+{
+ int value = (state == Qt::Unchecked) ? 0 : 1;
+ printf("Set 'SDL.FourScore' = %i\n", value);
+ g_config->setOption("SDL.FourScore", value);
+
+ setInputs();
+ updatePortLabels();
+}
+//----------------------------------------------------------------------------
+void InputConfDialog_t::port2MicChanged(int state)
+{
+ setInputs();
+ updatePortLabels();
+}
+//----------------------------------------------------------------------------
+void InputConfDialog_t::autoPresetChanged(int state)
+{
+ int value = (state == Qt::Unchecked) ? 0 : 1;
+ //printf("Set 'SDL.AutoInputPreset' = %i\n", value);
+ g_config->setOption("SDL.AutoInputPreset", value);
+}
+//----------------------------------------------------------------------------
+void InputConfDialog_t::openPortConfig(int portNum)
+{
+ updatePortLabels();
+
+ switch ( curNesInput[portNum] )
+ {
+ default:
+ case SI_NONE:
+ case SI_ZAPPER:
+ // Do Nothing
+ break;
+ case SI_GAMEPAD:
+ consoleWindow->openGamePadConfWin();
+ break;
+ }
+}
+//----------------------------------------------------------------------------
+void InputConfDialog_t::port1Configure(void)
+{
+ openPortConfig(0);
+}
+//----------------------------------------------------------------------------
+void InputConfDialog_t::port2Configure(void)
+{
+ openPortConfig(1);
+}
+//----------------------------------------------------------------------------
+void InputConfDialog_t::openLoadPresetFile(void)
+{
+ int ret, useNativeFileDialogVal;
+ QString filename;
+ std::string last;
+ std::string path;
+ const char *baseDir;
+ QFileDialog dialog(this, tr("Load Preset From File") );
+ QDir dir;
+
+ baseDir = FCEUI_GetBaseDirectory();
+
+ path = std::string(baseDir) + "/input/presets/";
+
+ dir.mkpath( QString::fromStdString(path) );
+
+ dialog.setFileMode(QFileDialog::ExistingFile);
+
+ dialog.setNameFilter(tr("Preset File (*.pre *.PRE) ;; All files (*)"));
+
+ dialog.setViewMode(QFileDialog::List);
+ dialog.setFilter( QDir::AllEntries | QDir::AllDirs | QDir::Hidden );
+ dialog.setLabelText( QFileDialog::Accept, tr("Load") );
+
+ dialog.setDirectory( tr(path.c_str()) );
+
+ // Check config option to use native file dialog or not
+ g_config->getOption ("SDL.UseNativeFileDialog", &useNativeFileDialogVal);
+
+ dialog.setOption(QFileDialog::DontUseNativeDialog, !useNativeFileDialogVal);
+
+ dialog.show();
+ ret = dialog.exec();
+
+ if ( ret )
+ {
+ QStringList fileList;
+ fileList = dialog.selectedFiles();
+
+ if ( fileList.size() > 0 )
+ {
+ filename = fileList[0];
+ }
+ }
+
+ if ( filename.isNull() )
+ {
+ return;
+ }
+ qDebug() << "selected file path : " << filename.toUtf8();
+
+ fceuWrapperLock();
+ loadInputSettingsFromFile( filename.toStdString().c_str() );
+ fceuWrapperUnLock();
+
+ updatePortLabels();
+ updatePortComboBoxes();
+}
+
+//----------------------------------------------------------------------------
+void InputConfDialog_t::openSavePresetFile(void)
+{
+ int ret, useNativeFileDialogVal;
+ QString filename;
+ std::string path;
+ const char *baseDir, *romFile;
+ QFileDialog dialog(this, tr("Save Preset to File") );
+ QDir dir;
+
+ baseDir = FCEUI_GetBaseDirectory();
+
+ path = std::string(baseDir) + "/input/presets/";
+
+ dir.mkpath( QString::fromStdString(path) );
+
+ dialog.setFileMode(QFileDialog::AnyFile);
+
+ dialog.setNameFilter(tr("Preset Files (*.pre *.PRE) ;; All files (*)"));
+
+ dialog.setViewMode(QFileDialog::List);
+ dialog.setFilter( QDir::AllEntries | QDir::AllDirs | QDir::Hidden );
+ dialog.setLabelText( QFileDialog::Accept, tr("Save") );
+ dialog.setDefaultSuffix( tr(".pre") );
+
+ romFile = getRomFile();
+
+ if ( romFile != NULL )
+ {
+ char dirStr[256], base[256];
+
+ parseFilepath( romFile, dirStr, base );
+
+ strcat( base, ".pre");
+
+ dialog.selectFile( tr(base) );
+ }
+
+ dialog.setDirectory( tr(path.c_str()) );
+
+ // Check config option to use native file dialog or not
+ g_config->getOption ("SDL.UseNativeFileDialog", &useNativeFileDialogVal);
+
+ dialog.setOption(QFileDialog::DontUseNativeDialog, !useNativeFileDialogVal);
+
+ dialog.show();
+ ret = dialog.exec();
+
+ if ( ret )
+ {
+ QStringList fileList;
+ fileList = dialog.selectedFiles();
+
+ if ( fileList.size() > 0 )
+ {
+ filename = fileList[0];
+ }
+ }
+
+ if ( filename.isNull() )
+ {
+ return;
+ }
+ qDebug() << "selected file path : " << filename.toUtf8();
+
+ saveInputSettingsToFile( filename.toStdString().c_str() );
+}
+//----------------------------------------------------------------------------
+void InputConfDialog_t::updatePeriodic(void)
+{
+ bool updateNeeded = false;
+ int tmpCurInputType[3], tmpUsrInputType[3];
+ int fourScoreValue;
+
+ for (int i=0; i<3; i++)
+ {
+ getInputSelection( i, &tmpCurInputType[i], &tmpUsrInputType[i] );
+
+ if ( curNesInput[i] != tmpCurInputType[i] )
+ {
+ updateNeeded = true;
+ }
+ if ( usrNesInput[i] != tmpUsrInputType[i] )
+ {
+ updateNeeded = true;
+ }
+ }
+
+ if ( updateNeeded )
+ {
+ updatePortLabels();
+ updatePortComboBoxes();
+ }
+
+ g_config->getOption("SDL.FourScore", &fourScoreValue);
+
+ if ( fourScoreValue != fourScoreEna->isChecked() )
+ {
+ fourScoreEna->setChecked( fourScoreValue );
+ }
+}
+//----------------------------------------------------------------------------
diff --git a/src/drivers/Qt/InputConf.h b/src/drivers/Qt/InputConf.h
new file mode 100644
index 00000000..cc72d0aa
--- /dev/null
+++ b/src/drivers/Qt/InputConf.h
@@ -0,0 +1,73 @@
+// InputConf.h
+//
+
+#pragma once
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "Qt/main.h"
+
+class InputConfDialog_t : public QDialog
+{
+ Q_OBJECT
+
+ public:
+ InputConfDialog_t(QWidget *parent = 0);
+ ~InputConfDialog_t(void);
+
+ protected:
+ void closeEvent(QCloseEvent *event);
+
+ QTimer *inputTimer;
+ QCheckBox *fourScoreEna;
+ QCheckBox *port2Mic;
+ QCheckBox *autoPreset;
+ QLabel *nesPortLabel[2];
+ QPushButton *nesPortConfButton[2];
+ QComboBox *nesPortComboxBox[2];
+ QLabel *expPortLabel;
+ QPushButton *expPortConfButton;
+ QComboBox *expPortComboxBox;
+ QPushButton *loadConfigButton;
+ QPushButton *saveConfigButton;
+
+ int curNesInput[3];
+ int usrNesInput[3];
+
+ private:
+ void setInputs(void);
+ void updatePortLabels(void);
+ void updatePortComboBoxes(void);
+ void openPortConfig(int portNum);
+
+ public slots:
+ void closeWindow(void);
+ private slots:
+ void port1Configure(void);
+ void port2Configure(void);
+ void port1Select(int index);
+ void port2Select(int index);
+ void expSelect(int index);
+ void fourScoreChanged(int state);
+ void port2MicChanged(int state);
+ void autoPresetChanged(int state);
+ void openLoadPresetFile(void);
+ void openSavePresetFile(void);
+ void updatePeriodic(void);
+
+};
+
+void openInputConfWindow( QWidget *parent );
diff --git a/src/drivers/Qt/LuaControl.cpp b/src/drivers/Qt/LuaControl.cpp
index 2aa40271..7e48c54b 100644
--- a/src/drivers/Qt/LuaControl.cpp
+++ b/src/drivers/Qt/LuaControl.cpp
@@ -1,9 +1,12 @@
// LuaControl.cpp
//
+#include
+#include
#include
#include
#include
+#include
#include "../../fceu.h"
@@ -20,12 +23,64 @@
#include "Qt/ConsoleUtilities.h"
static bool luaScriptRunning = false;
+static bool updateLuaDisplay = false;
+static bool openLuaKillMsgBox = false;
+static int luaKillMsgBoxRetVal = 0;
+
+struct luaConsoleOutputBuffer
+{
+ int head;
+ int tail;
+ int size;
+ char *buf;
+
+ luaConsoleOutputBuffer(void)
+ {
+ tail = head = 0;
+ size = 4096;
+
+ buf = (char*)malloc(size);
+ }
+
+ ~luaConsoleOutputBuffer(void)
+ {
+ if ( buf )
+ {
+ free(buf); buf = NULL;
+ }
+ }
+
+ void addLine( const char *l )
+ {
+ int i=0;
+ //printf("Adding Line %i: '%s'\n", head, l );
+ while ( l[i] != 0 )
+ {
+ buf[head] = l[i]; i++;
+
+ head = (head + 1) % size;
+
+ if ( head == tail )
+ {
+ tail = (tail + 1) % size;
+ }
+ }
+ }
+
+ void clear(void)
+ {
+ tail = head = 0;
+ }
+};
+
+static luaConsoleOutputBuffer outBuf;
-static std::string luaOutputText;
static std::list winList;
+
+static void updateLuaWindows( void );
//----------------------------------------------------
LuaControlDialog_t::LuaControlDialog_t(QWidget *parent)
- : QDialog( parent )
+ : QDialog( parent, Qt::Window )
{
QVBoxLayout *mainLayout;
QHBoxLayout *hbox;
@@ -95,6 +150,12 @@ LuaControlDialog_t::LuaControlDialog_t(QWidget *parent)
setLayout( mainLayout );
winList.push_back( this );
+
+ periodicTimer = new QTimer( this );
+
+ connect( periodicTimer, &QTimer::timeout, this, &LuaControlDialog_t::updatePeriodic );
+
+ periodicTimer->start( 200 ); // 5hz
}
//----------------------------------------------------
@@ -104,6 +165,8 @@ LuaControlDialog_t::~LuaControlDialog_t(void)
printf("Destroy Lua Control Window\n");
+ periodicTimer->stop();
+
for (it = winList.begin(); it != winList.end(); it++)
{
if ( (*it) == this )
@@ -130,6 +193,43 @@ void LuaControlDialog_t::closeWindow(void)
deleteLater();
}
//----------------------------------------------------
+void LuaControlDialog_t::updatePeriodic(void)
+{
+ //printf("Update Lua\n");
+ if ( updateLuaDisplay )
+ {
+ updateLuaWindows();
+ updateLuaDisplay = false;
+ }
+
+ if ( openLuaKillMsgBox )
+ {
+ openLuaKillMessageBox();
+ openLuaKillMsgBox = false;
+ }
+}
+//----------------------------------------------------
+void LuaControlDialog_t::openLuaKillMessageBox(void)
+{
+ int ret;
+ QMessageBox msgBox(this);
+
+ luaKillMsgBoxRetVal = 0;
+
+ msgBox.setIcon( QMessageBox::Warning );
+ msgBox.setText( tr("The Lua script running has been running a long time.\nIt may have gone crazy. Kill it? (I won't ask again if you say No)\n") );
+ msgBox.setStandardButtons(QMessageBox::Yes);
+ msgBox.addButton(QMessageBox::No);
+ msgBox.setDefaultButton(QMessageBox::No);
+
+ ret = msgBox.exec();
+
+ if ( ret == QMessageBox::Yes )
+ {
+ luaKillMsgBoxRetVal = 1;
+ }
+}
+//----------------------------------------------------
void LuaControlDialog_t::openLuaScriptFile(void)
{
#ifdef _S9XLUA_H
@@ -144,7 +244,7 @@ void LuaControlDialog_t::openLuaScriptFile(void)
dialog.setNameFilter(tr("LUA Scripts (*.lua *.LUA) ;; All files (*)"));
dialog.setViewMode(QFileDialog::List);
- dialog.setFilter( QDir::AllEntries | QDir::Hidden );
+ dialog.setFilter( QDir::AllEntries | QDir::AllDirs | QDir::Hidden );
dialog.setLabelText( QFileDialog::Accept, tr("Load") );
g_config->getOption ("SDL.LastLoadLua", &last );
@@ -193,7 +293,7 @@ void LuaControlDialog_t::openLuaScriptFile(void)
void LuaControlDialog_t::startLuaScript(void)
{
#ifdef _S9XLUA_H
- luaOutputText.clear();
+ outBuf.clear();
fceuWrapperLock();
if ( 0 == FCEU_LoadLuaCode( scriptPath->text().toStdString().c_str(), scriptArgs->text().toStdString().c_str() ) )
{
@@ -214,6 +314,9 @@ void LuaControlDialog_t::stopLuaScript(void)
//----------------------------------------------------
void LuaControlDialog_t::refreshState(void)
{
+ int i;
+ std::string luaOutputText;
+
if ( luaScriptRunning )
{
stopButton->setEnabled( true );
@@ -224,10 +327,22 @@ void LuaControlDialog_t::refreshState(void)
stopButton->setEnabled( false );
startButton->setText( tr("Start") );
}
+
+ i = outBuf.tail;
+
+ while ( i != outBuf.head )
+ {
+ luaOutputText.append( 1, outBuf.buf[i] );
+
+ i = (i + 1) % outBuf.size;
+ }
+
luaOutput->setText( luaOutputText.c_str() );
+
+ luaOutput->moveCursor( QTextCursor::End );
}
//----------------------------------------------------
-void updateLuaWindows( void )
+static void updateLuaWindows( void )
{
std::list ::iterator it;
@@ -243,7 +358,7 @@ void WinLuaOnStart(intptr_t hDlgAsInt)
//printf("Lua Script Running: %i \n", luaScriptRunning );
- updateLuaWindows();
+ updateLuaDisplay = true;
}
//----------------------------------------------------
void WinLuaOnStop(intptr_t hDlgAsInt)
@@ -252,15 +367,52 @@ void WinLuaOnStop(intptr_t hDlgAsInt)
//printf("Lua Script Running: %i \n", luaScriptRunning );
- updateLuaWindows();
+ updateLuaDisplay = true;
}
//----------------------------------------------------
void PrintToWindowConsole(intptr_t hDlgAsInt, const char* str)
{
//printf("%s\n", str );
- luaOutputText.append( str );
+ outBuf.addLine( str );
- updateLuaWindows();
+ updateLuaDisplay = true;
+}
+//----------------------------------------------------
+#ifdef WIN32
+int LuaPrintfToWindowConsole(_In_z_ _Printf_format_string_ const char* const format, ...)
+#else
+int LuaPrintfToWindowConsole(const char *__restrict format, ...) throw()
+#endif
+{
+ int retval;
+ va_list args;
+ char msg[2048];
+ va_start( args, format );
+ retval = ::vsnprintf( msg, sizeof(msg), format, args );
+ va_end(args);
+
+ msg[ sizeof(msg)-1 ] = 0;
+
+ outBuf.addLine( msg );
+
+ updateLuaDisplay = true;
+
+ return(retval);
+};
+//----------------------------------------------------
+int LuaKillMessageBox(void)
+{
+ //printf("Kill Lua Prompted\n");
+ luaKillMsgBoxRetVal = 0;
+
+ openLuaKillMsgBox = true;
+
+ while ( openLuaKillMsgBox )
+ {
+ usleep(100000);
+ }
+
+ return luaKillMsgBoxRetVal;
}
//----------------------------------------------------
diff --git a/src/drivers/Qt/LuaControl.h b/src/drivers/Qt/LuaControl.h
index 522e686a..582e60c1 100644
--- a/src/drivers/Qt/LuaControl.h
+++ b/src/drivers/Qt/LuaControl.h
@@ -3,6 +3,8 @@
#pragma once
+#include
+
#include
#include
#include
@@ -30,7 +32,9 @@ class LuaControlDialog_t : public QDialog
protected:
void closeEvent(QCloseEvent *bar);
+ void openLuaKillMessageBox(void);
+ QTimer *periodicTimer;
QLineEdit *scriptPath;
QLineEdit *scriptArgs;
QPushButton *browseButton;
@@ -42,8 +46,28 @@ class LuaControlDialog_t : public QDialog
public slots:
void closeWindow(void);
private slots:
+ void updatePeriodic(void);
void openLuaScriptFile(void);
void startLuaScript(void);
void stopLuaScript(void);
};
+
+// Formatted print
+#ifdef WIN32
+ int LuaPrintfToWindowConsole(_In_z_ _Printf_format_string_ const char* const format, ...) ;
+#elif __linux__
+ #ifdef __THROWNL
+ int LuaPrintfToWindowConsole(const char *__restrict format, ...)
+ __THROWNL __attribute__ ((__format__ (__printf__, 1, 2)));
+ #else
+ int LuaPrintfToWindowConsole(const char *__restrict format, ...)
+ throw() __attribute__ ((__format__ (__printf__, 1, 2)));
+ #endif
+#else
+ int LuaPrintfToWindowConsole(const char *__restrict format, ...) throw();
+#endif
+
+void PrintToWindowConsole(intptr_t hDlgAsInt, const char* str);
+
+int LuaKillMessageBox(void);
diff --git a/src/drivers/Qt/MovieOptions.cpp b/src/drivers/Qt/MovieOptions.cpp
new file mode 100644
index 00000000..007accdc
--- /dev/null
+++ b/src/drivers/Qt/MovieOptions.cpp
@@ -0,0 +1,137 @@
+// MovieOptions.cpp
+//
+#include
+#include
+#include
+#include
+
+#include
+#include
+
+#include "../../fceu.h"
+#include "../../movie.h"
+
+#include "Qt/main.h"
+#include "Qt/dface.h"
+#include "Qt/input.h"
+#include "Qt/config.h"
+#include "Qt/keyscan.h"
+#include "Qt/fceuWrapper.h"
+#include "Qt/MovieOptions.h"
+
+//----------------------------------------------------------------------------
+MovieOptionsDialog_t::MovieOptionsDialog_t(QWidget *parent)
+ : QDialog( parent )
+{
+ QLabel *lbl;
+ QVBoxLayout *mainLayout;
+
+ setWindowTitle("Movie Options");
+
+ mainLayout = new QVBoxLayout();
+
+ readOnlyReplay = new QCheckBox( tr("Always Suggest Read-Only Replay") );
+ pauseAfterPlay = new QCheckBox( tr("Pause After Playback") );
+ closeAfterPlay = new QCheckBox( tr("Close After Playback") );
+ bindSaveStates = new QCheckBox( tr("Bind Save-States to Movies") );
+ dpySubTitles = new QCheckBox( tr("Display Movie Sub Titles") );
+ putSubTitlesAvi = new QCheckBox( tr("Put Movie Sub Titles in AVI") );
+ autoBackUp = new QCheckBox( tr("Automatically Backup Movies") );
+ loadFullStates = new QCheckBox( tr("Load Full Save-State Movies:") );
+
+ lbl = new QLabel( tr("Loading states in record mode will not immediately truncate movie, next frame input will. (VBA-rr and SNES9x style)") );
+ lbl->setWordWrap(true);
+
+ mainLayout->addWidget( readOnlyReplay );
+ mainLayout->addWidget( pauseAfterPlay );
+ mainLayout->addWidget( closeAfterPlay );
+ mainLayout->addWidget( bindSaveStates );
+ mainLayout->addWidget( dpySubTitles );
+ mainLayout->addWidget( putSubTitlesAvi );
+ mainLayout->addWidget( autoBackUp );
+ mainLayout->addWidget( loadFullStates );
+ mainLayout->addWidget( lbl );
+
+ readOnlyReplay->setChecked( suggestReadOnlyReplay );
+ pauseAfterPlay->setChecked( pauseAfterPlayback );
+ closeAfterPlay->setChecked( closeFinishedMovie );
+ bindSaveStates->setChecked( bindSavestate );
+ dpySubTitles->setChecked( movieSubtitles );
+ putSubTitlesAvi->setChecked( subtitlesOnAVI );
+ autoBackUp->setChecked( autoMovieBackup );
+ loadFullStates->setChecked( fullSaveStateLoads );
+
+ setLayout( mainLayout );
+
+ connect( readOnlyReplay , SIGNAL(stateChanged(int)), this, SLOT(readOnlyReplayChanged(int)) );
+ connect( pauseAfterPlay , SIGNAL(stateChanged(int)), this, SLOT(pauseAfterPlayChanged(int)) );
+ connect( closeAfterPlay , SIGNAL(stateChanged(int)), this, SLOT(closeAfterPlayChanged(int)) );
+ connect( bindSaveStates , SIGNAL(stateChanged(int)), this, SLOT(bindSaveStatesChanged(int)) );
+ connect( dpySubTitles , SIGNAL(stateChanged(int)), this, SLOT(dpySubTitlesChanged(int)) );
+ connect( putSubTitlesAvi, SIGNAL(stateChanged(int)), this, SLOT(putSubTitlesAviChanged(int)) );
+ connect( autoBackUp , SIGNAL(stateChanged(int)), this, SLOT(autoBackUpChanged(int)) );
+ connect( loadFullStates , SIGNAL(stateChanged(int)), this, SLOT(loadFullStatesChanged(int)) );
+}
+//----------------------------------------------------------------------------
+MovieOptionsDialog_t::~MovieOptionsDialog_t(void)
+{
+ printf("Destroy Movie Options Window\n");
+}
+//----------------------------------------------------------------------------
+void MovieOptionsDialog_t::closeEvent(QCloseEvent *event)
+{
+ printf("Movie Options Close Window Event\n");
+ done(0);
+ deleteLater();
+ event->accept();
+}
+//----------------------------------------------------------------------------
+void MovieOptionsDialog_t::closeWindow(void)
+{
+ //printf("Close Window\n");
+ done(0);
+ deleteLater();
+}
+//----------------------------------------------------------------------------
+void MovieOptionsDialog_t::readOnlyReplayChanged( int state )
+{
+ suggestReadOnlyReplay = (state != Qt::Unchecked);
+}
+//----------------------------------------------------------------------------
+void MovieOptionsDialog_t::pauseAfterPlayChanged( int state )
+{
+ pauseAfterPlayback = (state != Qt::Unchecked);
+}
+//----------------------------------------------------------------------------
+void MovieOptionsDialog_t::closeAfterPlayChanged( int state )
+{
+ closeFinishedMovie = (state != Qt::Unchecked);
+}
+//----------------------------------------------------------------------------
+void MovieOptionsDialog_t::bindSaveStatesChanged( int state )
+{
+ bindSavestate = (state != Qt::Unchecked);
+}
+//----------------------------------------------------------------------------
+void MovieOptionsDialog_t::dpySubTitlesChanged( int state )
+{
+ movieSubtitles = (state != Qt::Unchecked);
+
+ g_config->setOption("SDL.SubtitleDisplay", movieSubtitles);
+}
+//----------------------------------------------------------------------------
+void MovieOptionsDialog_t::putSubTitlesAviChanged( int state )
+{
+ subtitlesOnAVI = (state != Qt::Unchecked);
+}
+//----------------------------------------------------------------------------
+void MovieOptionsDialog_t::autoBackUpChanged( int state )
+{
+ autoMovieBackup = (state != Qt::Unchecked);
+}
+//----------------------------------------------------------------------------
+void MovieOptionsDialog_t::loadFullStatesChanged( int state )
+{
+ fullSaveStateLoads = (state != Qt::Unchecked);
+}
+//----------------------------------------------------------------------------
diff --git a/src/drivers/Qt/MovieOptions.h b/src/drivers/Qt/MovieOptions.h
new file mode 100644
index 00000000..c229c846
--- /dev/null
+++ b/src/drivers/Qt/MovieOptions.h
@@ -0,0 +1,55 @@
+// MovieOptions.h
+//
+
+#pragma once
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "Qt/main.h"
+
+class MovieOptionsDialog_t : public QDialog
+{
+ Q_OBJECT
+
+ public:
+ MovieOptionsDialog_t(QWidget *parent = 0);
+ ~MovieOptionsDialog_t(void);
+
+ protected:
+ void closeEvent(QCloseEvent *event);
+
+ QCheckBox *readOnlyReplay;
+ QCheckBox *pauseAfterPlay;
+ QCheckBox *closeAfterPlay;
+ QCheckBox *bindSaveStates;
+ QCheckBox *dpySubTitles;
+ QCheckBox *putSubTitlesAvi;
+ QCheckBox *autoBackUp;
+ QCheckBox *loadFullStates;
+
+ private:
+
+ public slots:
+ void closeWindow(void);
+ private slots:
+ void readOnlyReplayChanged( int state );
+ void pauseAfterPlayChanged( int state );
+ void closeAfterPlayChanged( int state );
+ void bindSaveStatesChanged( int state );
+ void dpySubTitlesChanged( int state );
+ void putSubTitlesAviChanged( int state );
+ void autoBackUpChanged( int state );
+ void loadFullStatesChanged( int state );
+
+};
diff --git a/src/drivers/Qt/MoviePlay.cpp b/src/drivers/Qt/MoviePlay.cpp
new file mode 100644
index 00000000..0ae0897d
--- /dev/null
+++ b/src/drivers/Qt/MoviePlay.cpp
@@ -0,0 +1,559 @@
+// MoviePlay.cpp
+//
+#include
+#include
+#include
+#include
+
+#include
+#include
+#include
+#include
+#include
+
+#include "../../fceu.h"
+#include "../../movie.h"
+
+#include "Qt/main.h"
+#include "Qt/dface.h"
+#include "Qt/input.h"
+#include "Qt/config.h"
+#include "Qt/keyscan.h"
+#include "Qt/fceuWrapper.h"
+#include "Qt/ConsoleUtilities.h"
+#include "Qt/MoviePlay.h"
+
+//----------------------------------------------------------------------------
+MoviePlayDialog_t::MoviePlayDialog_t(QWidget *parent)
+ : QDialog( parent )
+{
+ QVBoxLayout *mainLayout, *vbox;
+ QHBoxLayout *hbox;
+ QGroupBox *frame;
+ QGridLayout *grid;
+ QLabel *lbl;
+ QPushButton *okButton, *cancelButton;
+ bool replayReadOnlySetting;
+
+ setWindowTitle("Movie Play");
+
+ mainLayout = new QVBoxLayout();
+ hbox = new QHBoxLayout();
+
+ lbl = new QLabel( tr("File:") );
+ movSelBox = new QComboBox();
+ movBrowseBtn = new QPushButton( tr("Browse") );
+
+ hbox->addWidget( lbl, 1 );
+ hbox->addWidget( movSelBox, 100 );
+ hbox->addWidget( movBrowseBtn, 1 );
+
+ mainLayout->addLayout( hbox );
+
+ frame = new QGroupBox( tr("Parameters:") );
+ vbox = new QVBoxLayout();
+ hbox = new QHBoxLayout();
+
+ frame->setLayout( vbox );
+
+ openReadOnly = new QCheckBox( tr("Open Read-Only") );
+ pauseAtFrame = new QCheckBox( tr("Pause Movie At Frame") );
+
+ validator = new fceuDecIntValidtor( 0, 100000000, this );
+
+ pauseAtFrameEntry = new QLineEdit();
+
+ pauseAtFrameEntry->setValidator( validator );
+
+ vbox->addWidget( openReadOnly );
+ vbox->addLayout( hbox );
+ hbox->addWidget( pauseAtFrame );
+ hbox->addWidget( pauseAtFrameEntry );
+
+ mainLayout->addWidget( frame );
+
+ grid = new QGridLayout();
+ grid->setColumnStretch( 0, 1 );
+ grid->setColumnStretch( 1, 10 );
+
+ mainLayout->addLayout( grid );
+
+ movLenLbl = new QLabel();
+ movFramesLbl = new QLabel();
+ recCountLbl = new QLabel();
+ recFromLbl = new QLabel();
+ romUsedLbl = new QLabel();
+ romCsumLbl = new QLabel();
+ curCsumLbl = new QLabel();
+ emuUsedLbl = new QLabel();
+ palUsedLbl = new QLabel();
+ newppuUsedLbl = new QLabel();
+
+ grid->addWidget( new QLabel( tr("Length:") ) , 0, 0, Qt::AlignRight );
+ grid->addWidget( new QLabel( tr("Frames:") ) , 1, 0, Qt::AlignRight );
+ grid->addWidget( new QLabel( tr("Record Count:") ) , 2, 0, Qt::AlignRight );
+ grid->addWidget( new QLabel( tr("Recorded From:") ) , 3, 0, Qt::AlignRight );
+ grid->addWidget( new QLabel( tr("ROM Used:") ) , 4, 0, Qt::AlignRight );
+ grid->addWidget( new QLabel( tr("ROM Checksum:") ) , 5, 0, Qt::AlignRight );
+ grid->addWidget( new QLabel( tr("Current ROM Sum:") ) , 6, 0, Qt::AlignRight );
+ grid->addWidget( new QLabel( tr("Emulator Used:") ) , 7, 0, Qt::AlignRight );
+ grid->addWidget( new QLabel( tr("PAL:") ) , 8, 0, Qt::AlignRight );
+ grid->addWidget( new QLabel( tr("New PPU:") ) , 9, 0, Qt::AlignRight );
+
+ grid->addWidget( movLenLbl , 0, 1, Qt::AlignLeft );
+ grid->addWidget( movFramesLbl , 1, 1, Qt::AlignLeft );
+ grid->addWidget( recCountLbl , 2, 1, Qt::AlignLeft );
+ grid->addWidget( recFromLbl , 3, 1, Qt::AlignLeft );
+ grid->addWidget( romUsedLbl , 4, 1, Qt::AlignLeft );
+ grid->addWidget( romCsumLbl , 5, 1, Qt::AlignLeft );
+ grid->addWidget( curCsumLbl , 6, 1, Qt::AlignLeft );
+ grid->addWidget( emuUsedLbl , 7, 1, Qt::AlignLeft );
+ grid->addWidget( palUsedLbl , 8, 1, Qt::AlignLeft );
+ grid->addWidget( newppuUsedLbl , 9, 1, Qt::AlignLeft );
+
+ hbox = new QHBoxLayout();
+ okButton = new QPushButton( tr("Play") );
+ cancelButton = new QPushButton( tr("Cancel") );
+ hbox->addWidget( cancelButton );
+ hbox->addWidget( okButton );
+ okButton->setDefault(true);
+ mainLayout->addLayout( hbox );
+
+ setLayout( mainLayout );
+
+ connect( cancelButton , SIGNAL(clicked(void)), this, SLOT(closeWindow(void)) );
+ connect( okButton , SIGNAL(clicked(void)), this, SLOT(playMovie(void)) );
+
+ connect( movBrowseBtn , SIGNAL(clicked(void)) , this, SLOT(openMovie(void)) );
+ connect( movSelBox , SIGNAL(activated(int)), this, SLOT(movieSelect(int)) );
+
+ connect( pauseAtFrame , SIGNAL(stateChanged(int)), this, SLOT(pauseAtFrameChange(int)) );
+
+ if (suggestReadOnlyReplay)
+ {
+ replayReadOnlySetting = true;
+ }
+ else
+ {
+ replayReadOnlySetting = FCEUI_GetMovieToggleReadOnly();
+ }
+ openReadOnly->setChecked( replayReadOnlySetting );
+
+ pauseAtFrameEntry->setEnabled( pauseAtFrame->isChecked() );
+
+ doScan();
+
+ updateMovieText();
+}
+//----------------------------------------------------------------------------
+MoviePlayDialog_t::~MoviePlayDialog_t(void)
+{
+ printf("Destroy Movie Play Window\n");
+}
+//----------------------------------------------------------------------------
+void MoviePlayDialog_t::closeEvent(QCloseEvent *event)
+{
+ printf("Movie Play Close Window Event\n");
+ done(0);
+ deleteLater();
+ event->accept();
+}
+//----------------------------------------------------------------------------
+void MoviePlayDialog_t::closeWindow(void)
+{
+ //printf("Close Window\n");
+ done(0);
+ deleteLater();
+}
+//----------------------------------------------------------------------------
+//void MoviePlayDialog_t::readOnlyReplayChanged( int state )
+//{
+// suggestReadOnlyReplay = (state != Qt::Unchecked);
+//}
+//----------------------------------------------------------------------------
+void MoviePlayDialog_t::movieSelect(int index)
+{
+ updateMovieText();
+}
+//----------------------------------------------------------------------------
+void MoviePlayDialog_t::pauseAtFrameChange(int state)
+{
+ pauseAtFrameEntry->setEnabled( state != Qt::Unchecked );
+}
+//----------------------------------------------------------------------------
+void MoviePlayDialog_t::clearMovieText(void)
+{
+ movLenLbl->clear();
+ movFramesLbl->clear();
+ recCountLbl->clear();
+ recFromLbl->clear();
+ romUsedLbl->clear();
+ romCsumLbl->clear();
+ curCsumLbl->clear();
+ emuUsedLbl->clear();
+ palUsedLbl->clear();
+ newppuUsedLbl->clear();
+ pauseAtFrameEntry->clear();
+}
+//----------------------------------------------------------------------------
+void MoviePlayDialog_t::updateMovieText(void)
+{
+ int idx;
+ std::string path;
+ FCEUFILE* fp;
+ MOVIE_INFO info;
+ bool scanok;
+ char stmp[256];
+
+ if ( movSelBox->count() == 0 )
+ {
+ return;
+ }
+ idx = movSelBox->currentIndex();
+
+ path = movSelBox->itemText(idx).toStdString();
+
+ fp = FCEU_fopen( path.c_str(),0,"rb",0);
+
+ if ( fp == NULL )
+ {
+ sprintf( stmp, "Error: Failed to open file '%s'", path.c_str() );
+ showErrorMsgWindow( stmp );
+ clearMovieText();
+ return;
+ }
+ scanok = FCEUI_MovieGetInfo(fp, info, false);
+
+ if ( scanok )
+ {
+ double div;
+
+ validator->setMinMax( 0, info.num_frames );
+
+ sprintf(stmp, "%u", (unsigned)info.num_frames);
+
+ movFramesLbl->setText( tr(stmp) );
+ pauseAtFrameEntry->setText( tr(stmp) );
+
+ div = (FCEUI_GetCurrentVidSystem(0,0)) ? 50.006977968268290849 : 60.098813897440515532; // PAL timing
+ double tempCount = (info.num_frames / div) + 0.005; // +0.005s for rounding
+ int num_seconds = (int)tempCount;
+ int fraction = (int)((tempCount - num_seconds) * 100);
+ int seconds = num_seconds % 60;
+ int minutes = (num_seconds / 60) % 60;
+ int hours = (num_seconds / 60 / 60) % 60;
+ sprintf(stmp, "%02d:%02d:%02d.%02d", hours, minutes, seconds, fraction);
+
+ movLenLbl->setText( tr(stmp) );
+
+ sprintf(stmp, "%u", (unsigned)info.rerecord_count);
+
+ recCountLbl->setText( tr(stmp) );
+
+ recFromLbl->setText( tr(info.poweron ? "Power-On" : (info.reset?"Soft-Reset":"Savestate") ) );
+
+ romUsedLbl->setText( tr(info.name_of_rom_used.c_str()) );
+
+ romCsumLbl->setText( tr(md5_asciistr(info.md5_of_rom_used)) );
+
+ if ( GameInfo )
+ {
+ curCsumLbl->setText( tr(md5_asciistr(GameInfo->MD5)) );
+ }
+ else
+ {
+ curCsumLbl->clear();
+ }
+
+ if (info.emu_version_used < 20000 )
+ {
+ sprintf( stmp, "FCEU %u.%02u.%02u%s", info.emu_version_used/10000, (info.emu_version_used/100)%100, (info.emu_version_used)%100, info.emu_version_used < 9813 ? " (blip)" : "");
+ }
+ else
+ {
+ sprintf( stmp, "FCEUX %u.%02u.%02u", info.emu_version_used/10000, (info.emu_version_used/100)%100, (info.emu_version_used)%100);
+ }
+ emuUsedLbl->setText( tr(stmp) );
+
+ palUsedLbl->setText( tr(info.pal ? "On" : "Off") );
+
+ newppuUsedLbl->setText( tr(info.ppuflag ? "On" : "Off") );
+
+ if ( GameInfo )
+ {
+ strcpy( stmp, md5_asciistr(GameInfo->MD5) );
+
+ if ( strcmp( stmp, md5_asciistr(info.md5_of_rom_used) ) != 0 )
+ {
+ sprintf( stmp, "Warning: Selected movie file '%s' may not have been created using the currently loaded ROM.", path.c_str() );
+ showWarningMsgWindow( stmp );
+ }
+ }
+ }
+ else
+ {
+ sprintf( stmp, "Error: Selected file '%s' does not have a recognized movie format.", path.c_str() );
+ showErrorMsgWindow( stmp );
+ clearMovieText();
+ }
+ delete fp;
+
+ return;
+}
+//----------------------------------------------------------------------------
+int MoviePlayDialog_t::addFileToList( const char *file, bool setActive )
+{
+ int n=0;
+
+ for (int i=0; icount(); i++)
+ {
+ if ( strcmp( file, movSelBox->itemText(i).toStdString().c_str() ) == 0 )
+ {
+ if ( setActive )
+ {
+ movSelBox->setCurrentIndex(i);
+ }
+ return -1;
+ }
+ }
+
+ n = movSelBox->count();
+
+ movSelBox->addItem( tr(file), n );
+
+ if ( setActive )
+ {
+ movSelBox->setCurrentIndex(n);
+ }
+
+ return 0;
+}
+//----------------------------------------------------------------------------
+bool MoviePlayDialog_t::checkMD5Sum( const char *path, const char *md5 )
+{
+ FCEUFILE* fp;
+ MOVIE_INFO info;
+ bool scanok, md5Match = false;
+
+ fp = FCEU_fopen( path,0,"rb",0);
+
+ if ( fp == NULL )
+ {
+ return md5Match;
+ }
+ scanok = FCEUI_MovieGetInfo(fp, info, true);
+
+ if ( scanok )
+ {
+ if ( strcmp( md5, md5_asciistr(info.md5_of_rom_used) ) == 0 )
+ {
+ md5Match = true;
+ }
+ }
+ delete fp;
+
+ return md5Match;
+}
+//----------------------------------------------------------------------------
+void MoviePlayDialog_t::scanDirectory( const char *dirPath, const char *md5 )
+{
+ QDir dir;
+ QFileInfoList list;
+ std::string path;
+ const QStringList filters( { "*.fm2" } );
+
+ path.assign( dirPath );
+
+ dir.setPath( QString::fromStdString(path) );
+
+ list = dir.entryInfoList( filters, QDir::Files );
+
+ for (int i = 0; i < list.size(); ++i)
+ {
+ QFileInfo fileInfo = list.at(i);
+
+ path = std::string(dirPath) + fileInfo.fileName().toStdString();
+
+ //printf("File: '%s'\n", path.c_str() );
+
+ if ( checkMD5Sum( path.c_str(), md5 ) )
+ {
+ addFileToList( path.c_str() );
+ }
+ }
+
+}
+//----------------------------------------------------------------------------
+void MoviePlayDialog_t::doScan(void)
+{
+ std::string path, last;
+ const char *romFile;
+ const char *baseDir = FCEUI_GetBaseDirectory();
+ char md5[256];
+ char dir[512], base[256];
+
+ md5[0] = 0;
+
+ if ( GameInfo )
+ {
+ strcpy( md5, md5_asciistr(GameInfo->MD5) );
+ }
+
+ path = std::string(baseDir) + "/movies/";
+
+ scanDirectory( path.c_str(), md5 );
+
+ romFile = getRomFile();
+
+ if ( romFile != NULL )
+ {
+ parseFilepath( romFile, dir, base );
+
+ path = std::string(dir);
+
+ scanDirectory( path.c_str(), md5 );
+ }
+
+ g_config->getOption ("SDL.LastOpenMovie", &last );
+
+ getDirFromFile( last.c_str(), dir );
+
+ scanDirectory( dir, md5 );
+}
+//----------------------------------------------------------------------------
+void MoviePlayDialog_t::playMovie(void)
+{
+ int idx, pauseframe = 0;
+ bool replayReadOnlySetting, movieLoadError = false;
+
+ if ( movSelBox->count() == 0 )
+ {
+ return;
+ }
+ std::string path;
+
+ idx = movSelBox->currentIndex();
+
+ path = movSelBox->itemText(idx).toStdString();
+
+ replayReadOnlySetting = openReadOnly->isChecked();
+
+ if ( pauseAtFrame->isChecked() )
+ {
+ pauseframe = strtol( pauseAtFrameEntry->text().toStdString().c_str(), NULL, 0 );
+ }
+
+ fceuWrapperLock();
+ if (FCEUI_LoadMovie( path.c_str(),
+ replayReadOnlySetting, pauseframe ? pauseframe : false) == false)
+ {
+ movieLoadError = true;
+ }
+ fceuWrapperUnLock();
+
+ if ( movieLoadError )
+ {
+ char stmp[256];
+ sprintf( stmp, "Error: Could not load movie file: %s \n", path.c_str() );
+ showErrorMsgWindow( stmp );
+ }
+ else
+ {
+ closeWindow();
+ }
+}
+//----------------------------------------------------------------------------
+void MoviePlayDialog_t::openMovie(void)
+{
+ int ret, useNativeFileDialogVal;
+ QString filename;
+ std::string last;
+ char dir[512];
+ char md5Match = 0;
+ QFileDialog dialog(this, tr("Open FM2 Movie") );
+
+ dialog.setFileMode(QFileDialog::ExistingFile);
+
+ dialog.setNameFilter(tr("FM2 Movies (*.fm2) ;; All files (*)"));
+
+ dialog.setViewMode(QFileDialog::List);
+ dialog.setFilter( QDir::AllEntries | QDir::AllDirs | QDir::Hidden );
+ dialog.setLabelText( QFileDialog::Accept, tr("Open") );
+
+ g_config->getOption ("SDL.LastOpenMovie", &last );
+
+ getDirFromFile( last.c_str(), dir );
+
+ dialog.setDirectory( tr(dir) );
+
+ // Check config option to use native file dialog or not
+ g_config->getOption ("SDL.UseNativeFileDialog", &useNativeFileDialogVal);
+
+ dialog.setOption(QFileDialog::DontUseNativeDialog, !useNativeFileDialogVal);
+
+ dialog.show();
+ ret = dialog.exec();
+
+ if ( ret )
+ {
+ QStringList fileList;
+ fileList = dialog.selectedFiles();
+
+ if ( fileList.size() > 0 )
+ {
+ filename = fileList[0];
+ }
+ }
+
+ if ( filename.isNull() )
+ {
+ return;
+ }
+ qDebug() << "selected file path : " << filename.toUtf8();
+
+ if ( GameInfo )
+ {
+ char md5[256];
+
+ strcpy( md5, md5_asciistr(GameInfo->MD5) );
+
+ if ( checkMD5Sum( filename.toStdString().c_str(), md5 ) )
+ {
+ md5Match = 1;
+ }
+
+ if ( !md5Match )
+ {
+ printf("Warning MD5 Mismatch\n");
+ }
+ }
+
+ addFileToList( filename.toStdString().c_str(), true );
+
+ updateMovieText();
+
+ g_config->setOption ("SDL.LastOpenMovie", filename.toStdString().c_str() );
+
+ return;
+}
+//----------------------------------------------------------------------------
+void MoviePlayDialog_t::showErrorMsgWindow(const char *str)
+{
+ QMessageBox msgBox(this);
+
+ msgBox.setIcon( QMessageBox::Critical );
+ msgBox.setText( tr(str) );
+ msgBox.show();
+ msgBox.exec();
+}
+//----------------------------------------------------------------------------
+void MoviePlayDialog_t::showWarningMsgWindow(const char *str)
+{
+ QMessageBox msgBox(this);
+
+ msgBox.setIcon( QMessageBox::Warning );
+ msgBox.setText( tr(str) );
+ msgBox.show();
+ msgBox.exec();
+}
+//----------------------------------------------------------------------------
diff --git a/src/drivers/Qt/MoviePlay.h b/src/drivers/Qt/MoviePlay.h
new file mode 100644
index 00000000..710e307e
--- /dev/null
+++ b/src/drivers/Qt/MoviePlay.h
@@ -0,0 +1,69 @@
+// MoviePlay.h
+//
+
+#pragma once
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "Qt/main.h"
+#include "Qt/ConsoleUtilities.h"
+
+class MoviePlayDialog_t : public QDialog
+{
+ Q_OBJECT
+
+ public:
+ MoviePlayDialog_t(QWidget *parent = 0);
+ ~MoviePlayDialog_t(void);
+
+ protected:
+ void closeEvent(QCloseEvent *event);
+
+ QComboBox *movSelBox;
+ QPushButton *movBrowseBtn;
+ QCheckBox *openReadOnly;
+ QCheckBox *pauseAtFrame;
+ QLineEdit *pauseAtFrameEntry;
+
+ QLabel *movLenLbl;
+ QLabel *movFramesLbl;
+ QLabel *recCountLbl;
+ QLabel *recFromLbl;
+ QLabel *romUsedLbl;
+ QLabel *romCsumLbl;
+ QLabel *curCsumLbl;
+ QLabel *emuUsedLbl;
+ QLabel *palUsedLbl;
+ QLabel *newppuUsedLbl;
+
+ fceuDecIntValidtor *validator;
+
+ private:
+ void doScan(void);
+ void clearMovieText(void);
+ void updateMovieText(void);
+ int addFileToList( const char *file, bool setActive = false );
+ bool checkMD5Sum( const char *path, const char *md5 );
+ void scanDirectory( const char *dirPath, const char *md5 );
+ void showErrorMsgWindow(const char *str);
+ void showWarningMsgWindow(const char *str);
+
+ public slots:
+ void closeWindow(void);
+ private slots:
+ void openMovie(void);
+ void playMovie(void);
+ void movieSelect(int index);
+ void pauseAtFrameChange(int state);
+
+};
diff --git a/src/drivers/Qt/MsgLogViewer.cpp b/src/drivers/Qt/MsgLogViewer.cpp
new file mode 100644
index 00000000..dc2addad
--- /dev/null
+++ b/src/drivers/Qt/MsgLogViewer.cpp
@@ -0,0 +1,279 @@
+// MsgLogViewer.cpp
+//
+#include
+#include
+#include
+#include
+
+#include
+#include
+#include
+
+#include "Qt/main.h"
+#include "Qt/dface.h"
+#include "Qt/input.h"
+#include "Qt/config.h"
+#include "Qt/keyscan.h"
+#include "Qt/fceuWrapper.h"
+#include "Qt/MsgLogViewer.h"
+#include "Qt/ConsoleWindow.h"
+
+#define MSG_LOG_MAX_LINES 256
+
+class msgLogBuf_t
+{
+ public:
+ msgLogBuf_t(void)
+ {
+ char filename[256];
+
+ strcpy( filename, "/tmp/fceux.log" );
+
+ fp = ::fopen( filename, "w+");
+
+ if ( fp == NULL )
+ {
+ printf("Error: Failed to open message log file: '%s'\n", filename);
+ }
+ maxLines = MSG_LOG_MAX_LINES;
+ totalLines = 0;
+ head = tail = 0;
+
+ for (int i=0; i 0 )
+ {
+ //printf("READ: %li \n", nbytes );
+ buf[ nbytes ] = 0;
+ viewer->setPlainText( buf );
+ }
+ }
+
+ private:
+ FILE *fp;
+ size_t maxLines;
+ size_t totalLines;
+ size_t head;
+ size_t tail;
+
+ long fpOfsList[MSG_LOG_MAX_LINES];
+};
+
+static msgLogBuf_t msgLog;
+//----------------------------------------------------------------------------
+MsgLogViewDialog_t::MsgLogViewDialog_t(QWidget *parent)
+ : QDialog( parent )
+{
+ QVBoxLayout *mainLayout;
+ QHBoxLayout *hbox;
+ QPushButton *clearBtn, *closeBtn;
+
+ setWindowTitle("Message Log Viewer");
+
+ resize( 512, 512 );
+
+ mainLayout = new QVBoxLayout();
+
+ txtView = new QPlainTextEdit();
+ txtView->setReadOnly(true);
+
+ mainLayout->addWidget( txtView );
+
+ hbox = new QHBoxLayout();
+ clearBtn = new QPushButton( tr("Clear") );
+ closeBtn = new QPushButton( tr("Close") );
+ hbox->addWidget( clearBtn );
+ hbox->addWidget( closeBtn );
+
+ connect( clearBtn, SIGNAL(clicked(void)), this, SLOT(clearLog(void)) );
+ connect( closeBtn, SIGNAL(clicked(void)), this, SLOT(closeWindow(void)) );
+
+ mainLayout->addLayout( hbox );
+
+ setLayout( mainLayout );
+
+ totalLines = 0;
+
+ updateTimer = new QTimer( this );
+
+ connect( updateTimer, &QTimer::timeout, this, &MsgLogViewDialog_t::updatePeriodic );
+
+ updateTimer->start( 500 ); // 2hz
+
+ msgLog.loadTextViewer( txtView );
+
+ totalLines = msgLog.getTotalLineCount();
+
+ txtView->moveCursor(QTextCursor::End);
+}
+//----------------------------------------------------------------------------
+MsgLogViewDialog_t::~MsgLogViewDialog_t(void)
+{
+ printf("Destroy Msg Log Key Config Window\n");
+ updateTimer->stop();
+}
+//----------------------------------------------------------------------------
+void MsgLogViewDialog_t::closeEvent(QCloseEvent *event)
+{
+ printf("Msg Log Key Close Window Event\n");
+ done(0);
+ deleteLater();
+ event->accept();
+}
+//----------------------------------------------------------------------------
+void MsgLogViewDialog_t::closeWindow(void)
+{
+ //printf("Close Window\n");
+ done(0);
+ deleteLater();
+}
+//----------------------------------------------------------------------------
+void MsgLogViewDialog_t::clearLog(void)
+{
+ fceuWrapperLock();
+
+ msgLog.clear();
+
+ txtView->clear();
+
+ fceuWrapperUnLock();
+}
+//----------------------------------------------------------------------------
+void MsgLogViewDialog_t::updatePeriodic(void)
+{
+ if ( msgLog.getTotalLineCount() != totalLines )
+ {
+ fceuWrapperLock();
+
+ msgLog.loadTextViewer( txtView );
+
+ totalLines = msgLog.getTotalLineCount();
+
+ fceuWrapperUnLock();
+
+ txtView->moveCursor(QTextCursor::End);
+ }
+}
+//----------------------------------------------------------------------------
+/**
+* Prints a textual message without adding a newline at the end.
+*
+* @param text The text of the message.
+*
+* TODO: This function should have a better name.
+**/
+void FCEUD_Message(const char *text)
+{
+ fputs(text, stdout);
+ //fprintf(stdout, "\n");
+ //
+ msgLog.addLine( text, false );
+}
+//----------------------------------------------------------------------------
+/**
+* Shows an error message in a message box.
+* (For now: prints to stderr.)
+*
+* If running in Qt mode, display a dialog message box of the error.
+*
+* @param errormsg Text of the error message.
+**/
+void FCEUD_PrintError(const char *errormsg)
+{
+ fprintf(stderr, "%s\n", errormsg);
+
+ msgLog.addLine( errormsg, true );
+
+ if ( consoleWindow )
+ {
+ consoleWindow->QueueErrorMsgWindow( errormsg );
+ }
+}
+//----------------------------------------------------------------------------
diff --git a/src/drivers/Qt/MsgLogViewer.h b/src/drivers/Qt/MsgLogViewer.h
new file mode 100644
index 00000000..d43edcf8
--- /dev/null
+++ b/src/drivers/Qt/MsgLogViewer.h
@@ -0,0 +1,46 @@
+// MsgLogViewer.h
+//
+
+#pragma once
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "Qt/main.h"
+
+class MsgLogViewDialog_t : public QDialog
+{
+ Q_OBJECT
+
+ public:
+ MsgLogViewDialog_t(QWidget *parent = 0);
+ ~MsgLogViewDialog_t(void);
+
+ protected:
+ void closeEvent(QCloseEvent *event);
+
+ QTimer *updateTimer;
+ QPlainTextEdit *txtView;
+
+ size_t totalLines;
+
+ private:
+
+ public slots:
+ void closeWindow(void);
+ private slots:
+ void updatePeriodic(void);
+ void clearLog(void);
+
+};
+
diff --git a/src/drivers/Qt/NameTableViewer.cpp b/src/drivers/Qt/NameTableViewer.cpp
new file mode 100644
index 00000000..6936d4dd
--- /dev/null
+++ b/src/drivers/Qt/NameTableViewer.cpp
@@ -0,0 +1,778 @@
+// NameTableViewer.cpp
+#include
+#include
+
+#include
+#include
+#include
+#include
+
+#include "../../types.h"
+#include "../../fceu.h"
+#include "../../cart.h"
+#include "../../ppu.h"
+#include "../../ines.h"
+#include "../../debug.h"
+#include "../../palette.h"
+
+#include "Qt/NameTableViewer.h"
+#include "Qt/main.h"
+#include "Qt/dface.h"
+#include "Qt/input.h"
+#include "Qt/config.h"
+#include "Qt/fceuWrapper.h"
+
+static ppuNameTableViewerDialog_t *nameTableViewWindow = NULL;
+static uint8_t palcache[36]; //palette cache
+static int NTViewScanline = 0;
+static int NTViewSkip = 100;
+static int NTViewRefresh = 1;
+static int chrchanged = 0;
+
+static int xpos = 0, ypos = 0;
+static int attview = 0;
+static int hidepal = 0;
+static bool drawScrollLines = true;
+static bool redrawtables = true;
+
+// checkerboard tile for attribute view
+static const uint8_t ATTRIBUTE_VIEW_TILE[16] = { 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF };
+
+
+static class NTCache
+{
+public:
+ NTCache(void)
+ : curr_vnapage(0)
+ {
+ memset( cache, 0, sizeof(cache) );
+ }
+
+ uint8_t* curr_vnapage;
+ uint8_t cache[0x400];
+} cache[4];
+
+static ppuNameTable_t nameTable[4];
+
+enum NT_MirrorType
+{
+ NT_NONE = -1,
+ NT_HORIZONTAL, NT_VERTICAL, NT_FOUR_SCREEN,
+ NT_SINGLE_SCREEN_TABLE_0, NT_SINGLE_SCREEN_TABLE_1,
+ NT_SINGLE_SCREEN_TABLE_2, NT_SINGLE_SCREEN_TABLE_3,
+ NT_NUM_MIRROR_TYPES
+};
+static NT_MirrorType ntmirroring = NT_NONE, oldntmirroring = NT_NONE;
+
+static void initNameTableViewer(void);
+static void ChangeMirroring(void);
+//----------------------------------------------------
+int openNameTableViewWindow( QWidget *parent )
+{
+ if ( nameTableViewWindow != NULL )
+ {
+ return -1;
+ }
+ initNameTableViewer();
+
+ nameTableViewWindow = new ppuNameTableViewerDialog_t(parent);
+
+ nameTableViewWindow->show();
+
+ return 0;
+}
+//----------------------------------------------------
+ppuNameTableViewerDialog_t::ppuNameTableViewerDialog_t(QWidget *parent)
+ : QDialog( parent, Qt::Window )
+{
+ QVBoxLayout *mainLayout, *vbox;
+ QHBoxLayout *hbox;
+ QGridLayout *grid;
+ QGroupBox *frame;
+ char stmp[64];
+
+ nameTableViewWindow = this;
+
+ setWindowTitle( tr("Name Table Viewer") );
+
+ mainLayout = new QVBoxLayout();
+
+ setLayout( mainLayout );
+
+ vbox = new QVBoxLayout();
+ frame = new QGroupBox( tr("Name Tables") );
+ ntView = new ppuNameTableView_t(this);
+ grid = new QGridLayout();
+
+ vbox->addWidget( ntView );
+ frame->setLayout( vbox );
+ mainLayout->addWidget( frame, 100 );
+ mainLayout->addLayout( grid , 1 );
+
+ showScrollLineCbox = new QCheckBox( tr("Show Scroll Lines") );
+ showAttrbCbox = new QCheckBox( tr("Show Attributes") );
+ ignorePaletteCbox = new QCheckBox( tr("Ignore Palette") );
+
+ showScrollLineCbox->setChecked( drawScrollLines );
+ showAttrbCbox->setChecked( attview );
+ ignorePaletteCbox->setChecked( hidepal );
+
+ grid->addWidget( showScrollLineCbox, 0, 0, Qt::AlignLeft );
+ grid->addWidget( showAttrbCbox , 1, 0, Qt::AlignLeft );
+ grid->addWidget( ignorePaletteCbox , 2, 0, Qt::AlignLeft );
+
+ connect( showScrollLineCbox, SIGNAL(stateChanged(int)), this, SLOT(showScrollLinesChanged(int)));
+ connect( showAttrbCbox , SIGNAL(stateChanged(int)), this, SLOT(showAttrbChanged(int)));
+ connect( ignorePaletteCbox , SIGNAL(stateChanged(int)), this, SLOT(ignorePaletteChanged(int)));
+
+ hbox = new QHBoxLayout();
+ refreshSlider = new QSlider( Qt::Horizontal );
+ hbox->addWidget( new QLabel( tr("Refresh: More") ) );
+ hbox->addWidget( refreshSlider );
+ hbox->addWidget( new QLabel( tr("Less") ) );
+ grid->addLayout( hbox, 0, 1, Qt::AlignRight );
+
+ refreshSlider->setMinimum( 0);
+ refreshSlider->setMaximum(25);
+ refreshSlider->setValue(NTViewRefresh);
+
+ connect( refreshSlider, SIGNAL(valueChanged(int)), this, SLOT(refreshSliderChanged(int)));
+
+ hbox = new QHBoxLayout();
+ scanLineEdit = new QLineEdit();
+ hbox->addWidget( new QLabel( tr("Display on Scanline:") ) );
+ hbox->addWidget( scanLineEdit );
+ grid->addLayout( hbox, 1, 1, Qt::AlignRight );
+
+ scanLineEdit->setMaxLength( 3 );
+ scanLineEdit->setInputMask( ">900;" );
+ sprintf( stmp, "%i", NTViewScanline );
+ scanLineEdit->setText( tr(stmp) );
+
+ connect( scanLineEdit, SIGNAL(textEdited(const QString &)), this, SLOT(scanLineChanged(const QString &)));
+
+ hbox = new QHBoxLayout();
+ frame = new QGroupBox( tr("Current Mirroring") );
+ grid = new QGridLayout();
+
+ mainLayout->addLayout( hbox, 1 );
+ hbox->addWidget( frame );
+ frame->setLayout( grid );
+
+ horzMirrorBtn = new QRadioButton( tr("Horizontal") );
+ vertMirrorBtn = new QRadioButton( tr("Vertical") );
+ fourScreenBtn = new QRadioButton( tr("Four Screen") );
+ singleScreenBtn[0] = new QRadioButton( tr("Single Screen 0") );
+ singleScreenBtn[1] = new QRadioButton( tr("Single Screen 1") );
+ singleScreenBtn[2] = new QRadioButton( tr("Single Screen 2") );
+ singleScreenBtn[3] = new QRadioButton( tr("Single Screen 3") );
+
+ grid->addWidget( horzMirrorBtn, 0, 0, Qt::AlignLeft );
+ grid->addWidget( vertMirrorBtn, 1, 0, Qt::AlignLeft );
+ grid->addWidget( fourScreenBtn, 2, 0, Qt::AlignLeft );
+ grid->addWidget( singleScreenBtn[0], 0, 1, Qt::AlignLeft );
+ grid->addWidget( singleScreenBtn[1], 1, 1, Qt::AlignLeft );
+ grid->addWidget( singleScreenBtn[2], 2, 1, Qt::AlignLeft );
+ grid->addWidget( singleScreenBtn[3], 3, 1, Qt::AlignLeft );
+
+ connect( horzMirrorBtn , SIGNAL(clicked(void)), this, SLOT(horzMirrorClicked(void)));
+ connect( vertMirrorBtn , SIGNAL(clicked(void)), this, SLOT(vertMirrorClicked(void)));
+ connect( fourScreenBtn , SIGNAL(clicked(void)), this, SLOT(fourScreenClicked(void)));
+ connect( singleScreenBtn[0], SIGNAL(clicked(void)), this, SLOT(singleScreen0Clicked(void)));
+ connect( singleScreenBtn[1], SIGNAL(clicked(void)), this, SLOT(singleScreen1Clicked(void)));
+ connect( singleScreenBtn[2], SIGNAL(clicked(void)), this, SLOT(singleScreen2Clicked(void)));
+ connect( singleScreenBtn[3], SIGNAL(clicked(void)), this, SLOT(singleScreen3Clicked(void)));
+
+ updateMirrorButtons();
+
+ vbox = new QVBoxLayout();
+ frame = new QGroupBox( tr("Properties") );
+ hbox->addWidget( frame );
+ frame->setLayout( vbox );
+
+ tileID = new QLabel( tr("Tile ID:") );
+ tileXY = new QLabel( tr("X/Y :") );
+ ppuAddrLbl = new QLabel( tr("PPU Address:") );
+ attrbLbl = new QLabel( tr("Attribute:") );
+
+ vbox->addWidget( tileID );
+ vbox->addWidget( tileXY );
+ vbox->addWidget( ppuAddrLbl );
+ vbox->addWidget( attrbLbl );
+
+ FCEUD_UpdateNTView( -1, true);
+
+ updateTimer = new QTimer( this );
+
+ connect( updateTimer, &QTimer::timeout, this, &ppuNameTableViewerDialog_t::periodicUpdate );
+
+ updateTimer->start( 33 ); // 30hz
+}
+//----------------------------------------------------
+ppuNameTableViewerDialog_t::~ppuNameTableViewerDialog_t(void)
+{
+ updateTimer->stop();
+ nameTableViewWindow = NULL;
+
+ printf("Name Table Viewer Window Deleted\n");
+}
+//----------------------------------------------------
+void ppuNameTableViewerDialog_t::closeEvent(QCloseEvent *event)
+{
+ printf("Name Table Viewer Close Window Event\n");
+ done(0);
+ deleteLater();
+ event->accept();
+}
+//----------------------------------------------------
+void ppuNameTableViewerDialog_t::closeWindow(void)
+{
+ printf("Close Window\n");
+ done(0);
+ deleteLater();
+}
+//----------------------------------------------------
+void ppuNameTableViewerDialog_t::periodicUpdate(void)
+{
+ updateMirrorButtons();
+
+ if ( redrawtables )
+ {
+ this->update();
+ redrawtables = false;
+ }
+}
+//----------------------------------------------------
+void ppuNameTableViewerDialog_t::setPropertyLabels( int TileID, int TileX, int TileY, int NameTable, int PPUAddress, int AttAddress, int Attrib )
+{
+ char stmp[64];
+
+ sprintf( stmp, "Tile ID: %02X", TileID);
+
+ tileID->setText( tr(stmp) );
+
+ sprintf( stmp, "X/Y : %0d/%0d", TileX, TileY);
+
+ tileXY->setText( tr(stmp) );
+
+ sprintf(stmp,"PPU Address: %04X",PPUAddress);
+
+ ppuAddrLbl->setText( tr(stmp) );
+
+ sprintf(stmp,"Attribute: %1X (%04X)",Attrib,AttAddress);
+
+ attrbLbl->setText( tr(stmp) );
+}
+//----------------------------------------------------
+void ppuNameTableViewerDialog_t::updateMirrorButtons(void)
+{
+ switch ( ntmirroring )
+ {
+ default:
+ case NT_NONE:
+ break;
+ case NT_HORIZONTAL:
+ horzMirrorBtn->setChecked(true);
+ break;
+ case NT_VERTICAL:
+ vertMirrorBtn->setChecked(true);
+ break;
+ case NT_FOUR_SCREEN:
+ fourScreenBtn->setChecked(true);
+ break;
+ case NT_SINGLE_SCREEN_TABLE_0:
+ case NT_SINGLE_SCREEN_TABLE_1:
+ case NT_SINGLE_SCREEN_TABLE_2:
+ case NT_SINGLE_SCREEN_TABLE_3:
+ {
+ int i = ntmirroring - NT_SINGLE_SCREEN_TABLE_0;
+
+ singleScreenBtn[i]->setChecked(true);
+ }
+ break;
+ }
+}
+//----------------------------------------------------
+void ppuNameTableViewerDialog_t::horzMirrorClicked(void)
+{
+ ntmirroring = NT_HORIZONTAL;
+ ChangeMirroring();
+}
+//----------------------------------------------------
+void ppuNameTableViewerDialog_t::vertMirrorClicked(void)
+{
+ ntmirroring = NT_VERTICAL;
+ ChangeMirroring();
+}
+//----------------------------------------------------
+void ppuNameTableViewerDialog_t::fourScreenClicked(void)
+{
+ ntmirroring = NT_FOUR_SCREEN;
+ ChangeMirroring();
+}
+//----------------------------------------------------
+void ppuNameTableViewerDialog_t::singleScreen0Clicked(void)
+{
+ ntmirroring = NT_SINGLE_SCREEN_TABLE_0;
+ ChangeMirroring();
+}
+//----------------------------------------------------
+void ppuNameTableViewerDialog_t::singleScreen1Clicked(void)
+{
+ ntmirroring = NT_SINGLE_SCREEN_TABLE_1;
+ ChangeMirroring();
+}
+//----------------------------------------------------
+void ppuNameTableViewerDialog_t::singleScreen2Clicked(void)
+{
+ ntmirroring = NT_SINGLE_SCREEN_TABLE_2;
+ ChangeMirroring();
+}
+//----------------------------------------------------
+void ppuNameTableViewerDialog_t::singleScreen3Clicked(void)
+{
+ ntmirroring = NT_SINGLE_SCREEN_TABLE_3;
+ ChangeMirroring();
+}
+//----------------------------------------------------
+void ppuNameTableViewerDialog_t::scanLineChanged( const QString &txt )
+{
+ std::string s;
+
+ s = txt.toStdString();
+
+ if ( s.size() > 0 )
+ {
+ NTViewScanline = strtoul( s.c_str(), NULL, 10 );
+ }
+ //printf("ScanLine: '%s' %i\n", s.c_str(), PPUViewScanline );
+}
+//----------------------------------------------------
+void ppuNameTableViewerDialog_t::showScrollLinesChanged(int state)
+{
+ drawScrollLines = (state != Qt::Unchecked);
+}
+//----------------------------------------------------
+void ppuNameTableViewerDialog_t::showAttrbChanged(int state)
+{
+ attview = (state != Qt::Unchecked);
+}
+//----------------------------------------------------
+void ppuNameTableViewerDialog_t::ignorePaletteChanged(int state)
+{
+ hidepal = (state != Qt::Unchecked);
+}
+//----------------------------------------------------
+void ppuNameTableViewerDialog_t::refreshSliderChanged(int value)
+{
+ NTViewRefresh = value;
+}
+//----------------------------------------------------
+ppuNameTableView_t::ppuNameTableView_t(QWidget *parent)
+ : QWidget(parent)
+{
+ this->parent = (ppuNameTableViewerDialog_t*)parent;
+ this->setFocusPolicy(Qt::StrongFocus);
+ this->setMouseTracking(true);
+ viewWidth = 256 * 2;
+ viewHeight = 240 * 2;
+ setMinimumWidth( viewWidth );
+ setMinimumHeight( viewHeight );
+}
+//----------------------------------------------------
+ppuNameTableView_t::~ppuNameTableView_t(void)
+{
+
+}
+//----------------------------------------------------
+void ppuNameTableView_t::resizeEvent(QResizeEvent *event)
+{
+ viewWidth = event->size().width();
+ viewHeight = event->size().height();
+
+ //printf("%ix%i\n", viewWidth, viewHeight );
+}
+//----------------------------------------------------
+void ppuNameTableView_t::computeNameTableProperties( int x, int y )
+{
+ int i, xx, yy, w, h, TileID, TileX, TileY, NameTable, PPUAddress, AttAddress, Attrib;
+ ppuNameTable_t *tbl = NULL;
+
+ NameTable = 0;
+
+ if ( vnapage[0] == NULL )
+ {
+ return;
+ }
+ for (i=0; i<4; i++)
+ {
+ xx = nameTable[i].x;
+ yy = nameTable[i].y;
+ w = (nameTable[i].w * 256);
+ h = (nameTable[i].h * 240);
+
+ if ( (x >= xx) && (x < (xx+w) ) &&
+ (y >= yy) && (y < (yy+h) ) )
+ {
+ tbl = &nameTable[i];
+ NameTable = i;
+ break;
+ }
+ }
+
+ if ( tbl == NULL )
+ {
+ //printf("Mouse not over a tile\n");
+ return;
+ }
+ xx = tbl->x; yy = tbl->y;
+ w = tbl->w; h = tbl->h;
+
+ if ( (NameTable%2) == 1 )
+ {
+ TileX = ((x - xx) / (w*8)) + 32;
+ }
+ else
+ {
+ TileX = (x - xx) / (w*8);
+ }
+
+ if ( (NameTable/2) == 1 )
+ {
+ TileY = ((y - yy) / (h*8)) + 30;
+ }
+ else
+ {
+ TileY = (y - yy) / (h*8);
+ }
+
+ PPUAddress = 0x2000+(NameTable*0x400)+((TileY%30)*32)+(TileX%32);
+
+ TileID = vnapage[(PPUAddress>>10)&0x3][PPUAddress&0x3FF];
+
+ AttAddress = 0x23C0 | (PPUAddress & 0x0C00) | ((PPUAddress >> 4) & 0x38) | ((PPUAddress >> 2) & 0x07);
+ Attrib = vnapage[(AttAddress>>10)&0x3][AttAddress&0x3FF];
+ Attrib = (Attrib >> ((PPUAddress&2) | ((PPUAddress&64)>>4))) & 0x3;
+
+ //printf("NT:%i Tile X/Y : %i/%i \n", NameTable, TileX, TileY );
+
+ if ( parent )
+ {
+ parent->setPropertyLabels( TileID, TileX, TileY, NameTable, PPUAddress, AttAddress, Attrib );
+ }
+}
+//----------------------------------------------------
+void ppuNameTableView_t::mouseMoveEvent(QMouseEvent *event)
+{
+ computeNameTableProperties( event->pos().x(), event->pos().y() );
+}
+//----------------------------------------------------------------------------
+void ppuNameTableView_t::mousePressEvent(QMouseEvent * event)
+{
+ //QPoint tile = convPixToTile( event->pos() );
+
+ if ( event->button() == Qt::LeftButton )
+ {
+ }
+ else if ( event->button() == Qt::RightButton )
+ {
+ }
+}
+//----------------------------------------------------
+void ppuNameTableView_t::paintEvent(QPaintEvent *event)
+{
+ ppuNameTable_t *nt;
+ int n,i,j,ii,jj,w,h,x,y,xx,yy,ww,hh;
+ QPainter painter(this);
+ QColor scanLineColor(255,255,255);
+ viewWidth = event->rect().width();
+ viewHeight = event->rect().height();
+
+ w = viewWidth / (256*2);
+ h = viewHeight / (240*2);
+
+ //printf("%ix%i\n", viewWidth, viewHeight );
+
+ xx = 0; yy = 0;
+
+ for (n=0; n<4; n++)
+ {
+ nt = &nameTable[n];
+
+ nt->w = w; nt->h = h;
+
+ nt->x = xx = (n%2) * (viewWidth / 2);
+ nt->y = yy = (n/2) * (viewHeight / 2);
+
+ for (j=0; j<30; j++)
+ {
+ jj = (j*8);
+
+ for (i=0; i<32; i++)
+ {
+ ii = (i*8);
+
+ nt->tile[j][i].x = xx+(ii*w);
+ nt->tile[j][i].y = yy+(jj*h);
+
+ for (y=0; y<8; y++)
+ {
+ for (x=0; x<8; x++)
+ {
+ painter.fillRect( xx+(ii+x)*w, yy+(jj+y)*h, w, h, nt->tile[j][i].pixel[y][x].color );
+ }
+ }
+ }
+ }
+ if ( drawScrollLines )
+ {
+ ww = nt->w * 256;
+ hh = nt->h * 240;
+
+ painter.setPen( scanLineColor );
+
+ if ( (xpos >= xx) && (xpos < (xx+ww)) )
+ {
+ painter.drawLine( xpos, yy, xpos, yy + hh );
+ }
+
+ if ( (ypos >= yy) && (ypos < (yy+hh)) )
+ {
+ painter.drawLine( xx, ypos, xx + ww, ypos );
+ }
+ }
+ }
+
+}
+//----------------------------------------------------
+static void initNameTableViewer(void)
+{
+ //clear cache
+ memset(palcache,0,32);
+
+ // forced palette (e.g. for debugging nametables when palettes are all-black)
+ palcache[(8*4)+0] = 0x0F;
+ palcache[(8*4)+1] = 0x00;
+ palcache[(8*4)+2] = 0x10;
+ palcache[(8*4)+3] = 0x20;
+
+}
+//----------------------------------------------------
+static void ChangeMirroring(void)
+{
+ switch (ntmirroring)
+ {
+ case NT_HORIZONTAL:
+ vnapage[0] = vnapage[1] = &NTARAM[0x000];
+ vnapage[2] = vnapage[3] = &NTARAM[0x400];
+ break;
+ case NT_VERTICAL:
+ vnapage[0] = vnapage[2] = &NTARAM[0x000];
+ vnapage[1] = vnapage[3] = &NTARAM[0x400];
+ break;
+ case NT_FOUR_SCREEN:
+ vnapage[0] = &NTARAM[0x000];
+ vnapage[1] = &NTARAM[0x400];
+ if(ExtraNTARAM)
+ {
+ vnapage[2] = ExtraNTARAM;
+ vnapage[3] = ExtraNTARAM + 0x400;
+ }
+ break;
+ case NT_SINGLE_SCREEN_TABLE_0:
+ vnapage[0] = vnapage[1] = vnapage[2] = vnapage[3] = &NTARAM[0x000];
+ break;
+ case NT_SINGLE_SCREEN_TABLE_1:
+ vnapage[0] = vnapage[1] = vnapage[2] = vnapage[3] = &NTARAM[0x400];
+ break;
+ case NT_SINGLE_SCREEN_TABLE_2:
+ if(ExtraNTARAM)
+ vnapage[0] = vnapage[1] = vnapage[2] = vnapage[3] = ExtraNTARAM;
+ break;
+ case NT_SINGLE_SCREEN_TABLE_3:
+ if(ExtraNTARAM)
+ vnapage[0] = vnapage[1] = vnapage[2] = vnapage[3] = ExtraNTARAM + 0x400;
+ break;
+ default:
+ case NT_NONE:
+ break;
+ }
+ return;
+}
+//----------------------------------------------------
+inline void DrawChr( ppuNameTableTile_t *tile, const uint8_t *chr, int pal)
+{
+ int y, x, tmp, index=0, p=0;
+ uint8 chr0, chr1;
+ //uint8 *table = &VPage[0][0]; //use the background table
+ //pbitmap += 3*
+
+ for (y = 0; y < 8; y++) { //todo: use index for y?
+ chr0 = chr[index];
+ chr1 = chr[index+8];
+ tmp=7;
+ for (x = 0; x < 8; x++) { //todo: use tmp for x?
+ p = (chr0>>tmp)&1;
+ p |= ((chr1>>tmp)&1)<<1;
+ p = palcache[p+(pal*4)];
+ tmp--;
+
+ tile->pixel[y][x].color.setBlue( palo[p].b );
+ tile->pixel[y][x].color.setGreen( palo[p].g );
+ tile->pixel[y][x].color.setRed( palo[p].r );
+ }
+ index++;
+ //pbitmap += (NTWIDTH*3)-24;
+ }
+ //index+=8;
+ //pbitmap -= (((PALETTEBITWIDTH>>2)<<3)-24);
+}
+//----------------------------------------------------
+static void DrawNameTable(int scanline, int ntnum, bool invalidateCache)
+{
+ NTCache &c = cache[ntnum];
+ uint8_t *tablecache = c.cache;
+
+ uint8_t *table = vnapage[ntnum];
+ if (table == NULL)
+ {
+ table = vnapage[ntnum&1];
+ }
+
+ int a, ptable=0;
+
+ if (PPU[0]&0x10){ //use the correct pattern table based on this bit
+ ptable=0x1000;
+ }
+
+ bool invalid = invalidateCache;
+ //if we werent asked to invalidate the cache, maybe we need to invalidate it anyway due to vnapage changing
+ if (!invalid)
+ {
+ invalid = (c.curr_vnapage != vnapage[ntnum]);
+ }
+ c.curr_vnapage = vnapage[ntnum];
+
+ //HACK: never cache anything
+ invalid = true;
+
+ for (int y=0;y<30;y++)
+ {
+ for (int x=0;x<32;x++)
+ {
+ int ntaddr = (y*32)+x;
+ int attraddr = 0x3C0+((y>>2)<<3)+(x>>2);
+ if (invalid
+ || (table[ntaddr] != tablecache[ntaddr])
+ || (table[attraddr] != tablecache[attraddr]))
+ {
+ int temp = (((y&2)<<1)+(x&2));
+ a = (table[attraddr] & (3<> temp;
+
+ //the commented out code below is all allegedly equivalent to the single line above:
+ //tmpx = x>>2;
+ //tmpy = y>>2;
+ //a = 0x3C0+(tmpy*8)+tmpx;
+ //if((((x>>1)&1) == 0) && (((y>>1)&1) == 0)) a = table[a]&0x3;
+ //if((((x>>1)&1) == 1) && (((y>>1)&1) == 0)) a = (table[a]&0xC)>>2;
+ //if((((x>>1)&1) == 0) && (((y>>1)&1) == 1)) a = (table[a]&0x30)>>4;
+ //if((((x>>1)&1) == 1) && (((y>>1)&1) == 1)) a = (table[a]&0xC0)>>6;
+
+ int chr = table[ntaddr]*16;
+
+ extern int FCEUPPU_GetAttr(int ntnum, int xt, int yt);
+
+ //test.. instead of pretending that the nametable is a screen at 0,0 we pretend that it is at the current xscroll and yscroll
+ //int xpos = ((RefreshAddr & 0x400) >> 2) | ((RefreshAddr & 0x1F) << 3) | XOffset;
+ //int ypos = ((RefreshAddr & 0x3E0) >> 2) | ((RefreshAddr & 0x7000) >> 12);
+ //if(RefreshAddr & 0x800) ypos += 240;
+ //int refreshaddr = (xpos/8+x)+(ypos/8+y)*32;
+
+ int refreshaddr = (x)+(y)*32;
+
+ a = FCEUPPU_GetAttr(ntnum,x,y);
+ if (hidepal) a = 8;
+
+ const uint8* chrp = FCEUPPU_GetCHR(ptable+chr,refreshaddr);
+ if (attview) chrp = ATTRIBUTE_VIEW_TILE;
+
+ //a good way to do it:
+ DrawChr( &nameTable[ntnum].tile[y][x], chrp, a);
+
+ tablecache[ntaddr] = table[ntaddr];
+ tablecache[attraddr] = table[attraddr];
+ //one could comment out the line above...
+ //since there are so many fewer attribute values than NT values, it might be best just to refresh the whole attr table below with the memcpy
+
+ //obviously this whole scheme of nt cache doesnt work if an mmc5 game is playing tricks with the attribute table
+ }
+ }
+ }
+}
+//----------------------------------------------------
+void FCEUD_UpdateNTView(int scanline, bool drawall)
+{
+ if (nameTableViewWindow == 0)
+ {
+ return;
+ }
+ if ( (scanline != -1) && (scanline != NTViewScanline) )
+ {
+ return;
+ }
+
+ ppu_getScroll(xpos,ypos);
+
+ if (NTViewSkip < NTViewRefresh)
+ {
+ NTViewSkip++;
+ return;
+ }
+ NTViewSkip = 0;
+
+ if (chrchanged)
+ {
+ drawall = 1;
+ }
+
+ //update palette only if required
+ if (memcmp(palcache,PALRAM,32) != 0)
+ {
+ memcpy(palcache,PALRAM,32);
+ drawall = 1; //palette has changed, so redraw all
+ }
+
+ if ( vnapage[0] == NULL )
+ {
+ return;
+ }
+
+ ntmirroring = NT_NONE;
+ if (vnapage[0] == vnapage[1])ntmirroring = NT_HORIZONTAL;
+ if (vnapage[0] == vnapage[2])ntmirroring = NT_VERTICAL;
+ if ((vnapage[0] != vnapage[1]) && (vnapage[0] != vnapage[2]))ntmirroring = NT_FOUR_SCREEN;
+
+ if ((vnapage[0] == vnapage[1]) && (vnapage[1] == vnapage[2]) && (vnapage[2] == vnapage[3]))
+ {
+ if(vnapage[0] == &NTARAM[0x000])ntmirroring = NT_SINGLE_SCREEN_TABLE_0;
+ if(vnapage[0] == &NTARAM[0x400])ntmirroring = NT_SINGLE_SCREEN_TABLE_1;
+ if(vnapage[0] == ExtraNTARAM)ntmirroring = NT_SINGLE_SCREEN_TABLE_2;
+ if(vnapage[0] == ExtraNTARAM+0x400)ntmirroring = NT_SINGLE_SCREEN_TABLE_3;
+ }
+
+ if (oldntmirroring != ntmirroring)
+ {
+ //UpdateMirroringButtons();
+ oldntmirroring = ntmirroring;
+ }
+
+ for (int i=0;i<4;i++)
+ {
+ DrawNameTable(scanline,i,drawall);
+ }
+
+ chrchanged = 0;
+ redrawtables = true;
+ return;
+}
+//----------------------------------------------------
diff --git a/src/drivers/Qt/NameTableViewer.h b/src/drivers/Qt/NameTableViewer.h
new file mode 100644
index 00000000..f8865249
--- /dev/null
+++ b/src/drivers/Qt/NameTableViewer.h
@@ -0,0 +1,114 @@
+// NameTableViewer.h
+
+#pragma once
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+struct ppuNameTablePixel_t
+{
+ QColor color;
+};
+
+struct ppuNameTableTile_t
+{
+ struct ppuNameTablePixel_t pixel[8][8];
+
+ int x;
+ int y;
+};
+
+struct ppuNameTable_t
+{
+ struct ppuNameTableTile_t tile[30][32];
+
+ int x;
+ int y;
+ int w;
+ int h;
+};
+
+class ppuNameTableViewerDialog_t;
+
+class ppuNameTableView_t : public QWidget
+{
+ Q_OBJECT
+
+ public:
+ ppuNameTableView_t( QWidget *parent = 0);
+ ~ppuNameTableView_t(void);
+
+ protected:
+ void paintEvent(QPaintEvent *event);
+ void resizeEvent(QResizeEvent *event);
+ void mouseMoveEvent(QMouseEvent *event);
+ void mousePressEvent(QMouseEvent * event);
+ void computeNameTableProperties( int x, int y );
+
+ ppuNameTableViewerDialog_t *parent;
+ int viewWidth;
+ int viewHeight;
+};
+
+class ppuNameTableViewerDialog_t : public QDialog
+{
+ Q_OBJECT
+
+ public:
+ ppuNameTableViewerDialog_t(QWidget *parent = 0);
+ ~ppuNameTableViewerDialog_t(void);
+
+ void setPropertyLabels( int TileID, int TileX, int TileY, int NameTable, int PPUAddress, int AttAddress, int Attrib );
+ protected:
+ void closeEvent(QCloseEvent *bar);
+
+ ppuNameTableView_t *ntView;
+ QCheckBox *showScrollLineCbox;
+ QCheckBox *showAttrbCbox;
+ QCheckBox *ignorePaletteCbox;
+ QSlider *refreshSlider;
+ QLineEdit *scanLineEdit;
+ QTimer *updateTimer;
+ QRadioButton *horzMirrorBtn;
+ QRadioButton *vertMirrorBtn;
+ QRadioButton *fourScreenBtn;
+ QRadioButton *singleScreenBtn[4];
+ QLabel *tileID;
+ QLabel *tileXY;
+ QLabel *ppuAddrLbl;
+ QLabel *attrbLbl;
+
+ public slots:
+ void closeWindow(void);
+ private slots:
+ void periodicUpdate(void);
+ void updateMirrorButtons(void);
+ void horzMirrorClicked(void);
+ void vertMirrorClicked(void);
+ void fourScreenClicked(void);
+ void singleScreen0Clicked(void);
+ void singleScreen1Clicked(void);
+ void singleScreen2Clicked(void);
+ void singleScreen3Clicked(void);
+ void showAttrbChanged(int state);
+ void ignorePaletteChanged(int state);
+ void showScrollLinesChanged(int state);
+ void refreshSliderChanged(int value);
+ void scanLineChanged( const QString &txt );
+};
+
+int openNameTableViewWindow( QWidget *parent );
+
diff --git a/src/drivers/Qt/PaletteConf.cpp b/src/drivers/Qt/PaletteConf.cpp
index d799b8ca..7908aaab 100644
--- a/src/drivers/Qt/PaletteConf.cpp
+++ b/src/drivers/Qt/PaletteConf.cpp
@@ -32,10 +32,13 @@ PaletteConfDialog_t::PaletteConfDialog_t(QWidget *parent)
//QPushButton *closebutton;
QPushButton *button;
QTextEdit *comments;
+ QStyle *style;
int hue, tint;
char stmp[64];
std::string paletteFile;
+ style = this->style();
+
resize( 512, 600 );
// sync with config
@@ -63,6 +66,7 @@ PaletteConfDialog_t::PaletteConfDialog_t(QWidget *parent)
connect(deemphSwap, SIGNAL(stateChanged(int)), this, SLOT(deemphswap_Changed(int)) );
button = new QPushButton( tr("Open Palette") );
+ button->setIcon( style->standardIcon( QStyle::SP_FileDialogStart ) );
hbox1->addWidget( button );
connect( button, SIGNAL(clicked(void)), this, SLOT(openPaletteFile(void)) );
@@ -81,6 +85,7 @@ PaletteConfDialog_t::PaletteConfDialog_t(QWidget *parent)
button = new QPushButton( tr("Clear") );
+ button->setIcon( style->standardIcon( QStyle::SP_LineEditClearButton ) );
hbox1->addWidget( button );
connect( button, SIGNAL(clicked(void)), this, SLOT(clearPalette(void)) );
@@ -308,7 +313,7 @@ void PaletteConfDialog_t::openPaletteFile(void)
dialog.setNameFilter(tr("NES Palettes (*.pal *.PAL) ;; All files (*)"));
dialog.setViewMode(QFileDialog::List);
- dialog.setFilter( QDir::AllEntries | QDir::Hidden );
+ dialog.setFilter( QDir::AllEntries | QDir::AllDirs | QDir::Hidden );
dialog.setLabelText( QFileDialog::Accept, tr("Load") );
g_config->getOption ("SDL.Palette", &last );
diff --git a/src/drivers/Qt/RamSearch.cpp b/src/drivers/Qt/RamSearch.cpp
new file mode 100644
index 00000000..664eae49
--- /dev/null
+++ b/src/drivers/Qt/RamSearch.cpp
@@ -0,0 +1,1908 @@
+// RamSearch.cpp
+//
+#include