This commit is contained in:
Milan Nikolic 2014-02-09 18:24:41 +01:00
parent 1bed133331
commit 4b6143f9a4
27 changed files with 788 additions and 731 deletions

8
m64py
View file

@ -20,8 +20,8 @@ import os
import sys
import signal
if os.path.isdir(os.path.join(".","src")) and os.path.isfile(
os.path.join(".","setup.py")):
if os.path.isdir(os.path.join(".", "src")) and os.path.isfile(
os.path.join(".", "setup.py")):
sys.path.insert(0, os.path.realpath("src"))
try:
@ -48,8 +48,8 @@ def main():
QApplication.setAttribute(Qt.AA_X11InitThreads)
except AttributeError:
try:
Xlib = load_library('X11')
Xlib.XInitThreads()
xlib = load_library('X11')
xlib.XInitThreads()
except Exception:
pass

View file

@ -19,6 +19,7 @@ sys.path.insert(0, realpath("src"))
from m64py.core.defs import FRONTEND_VERSION
BASE_DIR = dirname(realpath(__file__))
class build_qt(Command):
user_options = []
@ -47,7 +48,7 @@ class build_qt(Command):
path.append(dirname(PyQt4.__file__))
os.putenv("PATH", os.pathsep.join(path))
if subprocess.call(["pyrcc4", qrc_file, "-o", py_file]) > 0:
self.warn("Unable to compile resource file %s" % (qrc_file))
self.warn("Unable to compile resource file %s" % qrc_file)
if not os.path.exists(py_file):
sys.exit(1)
os.putenv('PATH', origpath)
@ -62,9 +63,9 @@ class build_qt(Command):
elif filename.endswith('.qrc'):
self.compile_rc(join(dirpath, filename))
class build_exe(Command):
"""Needs PyQt4, pyUnRAR2, PyLZMA, PyWin32, PyInstaller, Inno Setup 5"""
user_options = []
arch = "i686-w64-mingw32"
url = "https://bitbucket.org/ecsv/mupen64plus-mxe-daily/get/master.zip"
@ -107,13 +108,13 @@ class build_exe(Command):
dest_path = join(self.dist_dir, "m64py")
shutil.copy(unrar_dll, dest_path)
shutil.copyfile(unrar_lic, join(dest_path, "doc", "unrar-license"))
for file in ["AUTHORS", "ChangeLog", "COPYING", "LICENSES", "README.md"]:
shutil.copy(join(BASE_DIR, file), dest_path)
for file_name in ["AUTHORS", "ChangeLog", "COPYING", "LICENSES", "README.md"]:
shutil.copy(join(BASE_DIR, file_name), dest_path)
def remove_files(self):
dest_path = join(self.dist_dir, "m64py")
for dirname in ["api", "include", "man6"]:
shutil.rmtree(join(dest_path, dirname))
for dir_name in ["api", "include", "man6"]:
shutil.rmtree(join(dest_path, dir_name))
def run_build_installer(self):
iss_file = ""
@ -148,6 +149,7 @@ class build_exe(Command):
self.remove_files()
self.run_build_installer()
class build_dmg(Command):
user_options = []
dist_dir = join(BASE_DIR, "dist", "macosx")
@ -161,9 +163,9 @@ class build_dmg(Command):
def set_plist(self):
info_plist = join(self.dist_dir, "dmg", "M64Py.app", "Contents", "Info.plist")
shutil.copy(join(self.dist_dir, "m64py.icns"),
join(self.dist_dir, "dmg", "M64Py.app", "Contents", "Resources"))
join(self.dist_dir, "dmg", "M64Py.app", "Contents", "Resources"))
shutil.copy(join(self.dist_dir, "m64py.sh"),
join(self.dist_dir, "dmg", "M64Py.app", "Contents", "MacOS"))
join(self.dist_dir, "dmg", "M64Py.app", "Contents", "MacOS"))
with open(info_plist, "r") as opts: data = opts.read()
plist_file = ""
lines = data.split("\n")
@ -187,14 +189,14 @@ class build_dmg(Command):
if not os.path.exists(dest_path):
os.mkdir(dest_path)
shutil.move(join(self.dist_dir, "M64Py.app"), dest_path)
for file in ["AUTHORS", "ChangeLog", "COPYING", "LICENSES", "README.md"]:
shutil.copy(join(BASE_DIR, file), dest_path)
for file_name in ["AUTHORS", "ChangeLog", "COPYING", "LICENSES", "README.md"]:
shutil.copy(join(BASE_DIR, file_name), dest_path)
shutil.copy(join(BASE_DIR, "test", "mupen64plus.v64"), dest_path)
def remove_files(self):
dest_path = join(self.dist_dir, "dmg", "M64Py.app", "Contents", "MacOS")
for dirname in ["include", "lib"]:
shutil.rmtree(join(dest_path, dirname))
for dir_name in ["include", "lib"]:
shutil.rmtree(join(dest_path, dir_name))
os.remove(join(self.dist_dir, "dmg", "M64Py.app", "Contents", "Resources", "icon-windowed.icns"))
def run_build_dmg(self):
@ -222,6 +224,7 @@ class build_dmg(Command):
self.set_plist()
self.run_build_dmg()
def set_sdl2():
opts_file = ""
opts_path = join(BASE_DIR, "src", "m64py", "opts.py")
@ -233,12 +236,12 @@ def set_sdl2():
opts_file += line + "\n"
with open(opts_path, "w") as opts: opts.write(opts_file)
def set_rthook():
import PyInstaller
hook_file = ""
module_dir = dirname(PyInstaller.__file__)
rthook = join(module_dir,
"loader", "rthooks", "pyi_rth_qt4plugins.py")
rthook = join(module_dir, "loader", "rthooks", "pyi_rth_qt4plugins.py")
with open(rthook, "r") as hook: data = hook.read()
if "sip.setapi" not in data:
lines = data.split("\n")
@ -250,6 +253,7 @@ def set_rthook():
hook_file += "sip.setapi('QVariant', 2)\n"
with open(rthook, "w") as hook: hook.write(hook_file)
class clean_local(Command):
pats = ['*.py[co]', '*_ui.py', '*_rc.py']
excludedirs = ['.git', 'build', 'dist']
@ -268,51 +272,54 @@ class clean_local(Command):
def _walkpaths(self, path):
for root, _dirs, files in os.walk(path):
if any(root == join(path, e) or root.startswith(
join(path, e, '')) for e in self.excludedirs):
join(path, e, '')) for e in self.excludedirs):
continue
for e in files:
fpath = join(root, e)
if any(fnmatch(fpath, p) for p in self.pats):
yield fpath
class mybuild(build):
def run(self):
self.run_command("build_qt")
build.run(self)
class myclean(clean):
def run(self):
self.run_command("clean_local")
clean.run(self)
cmdclass = {
'build': mybuild,
'build_qt': build_qt,
'build_exe': build_exe,
'build_dmg': build_dmg,
'clean': myclean,
'clean_local': clean_local
}
'build': mybuild,
'build_qt': build_qt,
'build_exe': build_exe,
'build_dmg': build_dmg,
'clean': myclean,
'clean_local': clean_local
}
setup(name = "m64py",
version = FRONTEND_VERSION,
description = "M64Py - A frontend for Mupen64Plus",
long_description = "M64Py is a Qt4 front-end (GUI) for Mupen64Plus 2.0, a cross-platform plugin-based Nintendo 64 emulator.",
author = "Milan Nikolic",
author_email = "gen2brain@gmail.com",
license = "GNU GPLv3",
url = "http://m64py.sourceforge.net",
packages = ["m64py", "m64py.core", "m64py.frontend", "m64py.ui", "m64py.SDL", "m64py.SDL2"],
package_dir = {"": "src"},
scripts = ["m64py"],
requires = ["PyQt4"],
platforms = ["Linux", "Windows", "Darwin"],
cmdclass = cmdclass,
data_files = [
("share/pixmaps", ["xdg/m64py.png"]),
("share/applications", ["xdg/m64py.desktop"]),
("share/mime/packages", ["xdg/application-x-m64py.xml"]),
("share/icons/hicolor/96x96/mimetypes/application-x-m64py.png",
["xdg/application-x-m64py.xml"])
]
)
setup(
name = "m64py",
version = FRONTEND_VERSION,
description = "M64Py - A frontend for Mupen64Plus",
long_description = "M64Py is a Qt4 front-end (GUI) for Mupen64Plus 2.0, a cross-platform plugin-based Nintendo 64 emulator.",
author = "Milan Nikolic",
author_email = "gen2brain@gmail.com",
license = "GNU GPLv3",
url = "http://m64py.sourceforge.net",
packages = ["m64py", "m64py.core", "m64py.frontend", "m64py.ui", "m64py.SDL", "m64py.SDL2"],
package_dir = {"": "src"},
scripts = ["m64py"],
requires = ["PyQt4"],
platforms = ["Linux", "Windows", "Darwin"],
cmdclass = cmdclass,
data_files = [
("share/pixmaps", ["xdg/m64py.png"]),
("share/applications", ["xdg/m64py.desktop"]),
("share/mime/packages", ["xdg/application-x-m64py.xml"]),
("share/icons/hicolor/96x96/mimetypes/application-x-m64py.png",
["xdg/application-x-m64py.xml"])
]
)

View file

@ -28,7 +28,7 @@ try:
import UnRAR2
HAS_RAR = True
RAR_CMD = None
except:
except ImportError:
HAS_RAR = False
RAR_CMD = which("rar") or which("unrar")
@ -36,7 +36,7 @@ try:
from py7zlib import Archive7z
HAS_7Z = True
LZMA_CMD = None
except:
except ImportError:
HAS_7Z = False
LZMA_CMD = which("7z")
@ -52,6 +52,7 @@ ROM_TYPE = {
'40123780': 'n64 (wordswapped)'
}
class Archive():
"""Extracts ROM file from archive."""
@ -59,7 +60,7 @@ class Archive():
"""Opens archive."""
self.file = os.path.realpath(filename)
if not os.path.isfile(self.file) or not os.access(self.file, os.R_OK):
raise IOError("Cannot open %s. No such file." % (self.file))
raise IOError("Cannot open %s. No such file." % self.file)
self.filetype = self.get_filetype()
@ -77,16 +78,16 @@ class Archive():
elif RAR_CMD:
self.fd = RarCmd(self.file)
else:
raise IOError("UnRAR2 module or rar/unrar is needed for %s." % (self.file))
raise IOError("UnRAR2 module or rar/unrar is needed for %s." % self.file)
elif self.filetype == LZMA:
if HAS_7Z:
self.fd = Archive7z(open(self.file, 'rb'))
elif LZMA_CMD:
self.fd = LzmaCmd(self.file)
else:
raise IOError("lzma module or 7z is needed for %s." % (self.file))
raise IOError("lzma module or 7z is needed for %s." % self.file)
else:
raise IOError("File %s is not a N64 ROM file." % (self.file))
raise IOError("File %s is not a N64 ROM file." % self.file)
self.namelist = self.get_namelist()
@ -163,6 +164,7 @@ class Archive():
return ROM
return None
class RarCmd:
"""Extracts ROM file from RAR archive."""
@ -170,6 +172,7 @@ class RarCmd:
"""Opens archive."""
self.fd = None
self.file = archive
self.filename = None
self.namelist = self.namelist()
self.tempdir = tempfile.mkdtemp()
@ -200,6 +203,7 @@ class RarCmd:
self.fd.close()
shutil.rmtree(self.tempdir)
class LzmaCmd:
"""Extracts ROM file from 7z archive."""
@ -207,6 +211,7 @@ class LzmaCmd:
"""Opens archive."""
self.fd = None
self.file = archive
self.filename = None
self.namelist = self.namelist()
self.tempdir = tempfile.mkdtemp()

View file

@ -23,6 +23,7 @@ from m64py.frontend.log import log
SECTIONS_FUNC = C.CFUNCTYPE(None, C.c_void_p, C.c_char_p)
PARAMETERS_FUNC = C.CFUNCTYPE(None, C.c_void_p, C.c_char_p, C.c_int)
class Config:
"""Mupen64Plus configuration"""
@ -48,8 +49,7 @@ class Config:
"""Enumerates the list of sections in config file."""
self.m64p.ConfigListSections.argtypes = [C.c_void_p, C.c_void_p]
rval = self.m64p.ConfigListSections(
C.c_void_p(),
SECTIONS_FUNC(self.list_sections_callback))
C.c_void_p(), SECTIONS_FUNC(self.list_sections_callback))
if rval != M64ERR_SUCCESS:
log.debug("list_sections()")
log.warn(self.core.error_message(rval))
@ -66,7 +66,7 @@ class Config:
config_ptr = C.c_void_p()
self.m64p.ConfigOpenSection.argtypes = [C.c_char_p, C.c_void_p]
rval = self.m64p.ConfigOpenSection(
C.c_char_p(section), C.byref(config_ptr))
C.c_char_p(section), C.byref(config_ptr))
if rval != M64ERR_SUCCESS:
log.debug("open_section()")
log.warn(self.core.error_message(rval))
@ -77,10 +77,10 @@ class Config:
def list_parameters(self):
"""Enumerates the list of parameters in a section."""
self.m64p.ConfigListParameters.argtypes = [
C.c_void_p, C.c_void_p, C.c_void_p]
C.c_void_p, C.c_void_p, C.c_void_p]
rval = self.m64p.ConfigListParameters(
self.config_handle, C.c_void_p(),
PARAMETERS_FUNC(self.list_parameters_callback))
self.config_handle, C.c_void_p(),
PARAMETERS_FUNC(self.list_parameters_callback))
if rval != M64ERR_SUCCESS:
log.debug("list_parameters()")
log.warn(self.core.error_message(rval))
@ -144,10 +144,10 @@ class Config:
param_arg_type = param_ctype
self.m64p.ConfigSetParameter.argtypes = [
C.c_void_p, C.c_char_p, C.c_int, param_arg_type]
C.c_void_p, C.c_char_p, C.c_int, param_arg_type]
rval = self.m64p.ConfigSetParameter(
self.config_handle, C.c_char_p(param_name),
C.c_int(param_type), param_value)
self.config_handle, C.c_char_p(param_name),
C.c_int(param_type), param_value)
if rval != M64ERR_SUCCESS:
log.debug("set_parameter()")
log.warn(self.core.error_message(rval))
@ -168,11 +168,10 @@ class Config:
param_value = C.create_string_buffer(maxsize)
self.m64p.ConfigGetParameter.argtypes = [
C.c_void_p, C.c_char_p, C.c_int, C.c_void_p, C.c_int]
C.c_void_p, C.c_char_p, C.c_int, C.c_void_p, C.c_int]
rval = self.m64p.ConfigGetParameter(
self.config_handle, C.c_char_p(param_name),
C.c_int(param_type), param_value,
C.c_int(maxsize))
self.config_handle, C.c_char_p(param_name),
C.c_int(param_type), param_value, C.c_int(maxsize))
if rval != M64ERR_SUCCESS:
log.debug("get_parameter()")
log.warn(self.core.error_message(rval))
@ -187,10 +186,9 @@ class Config:
"""Retrieves the type of one of the emulator's parameters."""
param_type = C.byref(C.c_int())
self.m64p.ConfigGetParameterHelp.argtypes = [
C.c_void_p, C.c_char_p, C.POINTER(C.c_int)]
C.c_void_p, C.c_char_p, C.POINTER(C.c_int)]
rval = self.m64p.ConfigGetParameterType(
self.config_handle, C.c_char_p(param_name),
param_type)
self.config_handle, C.c_char_p(param_name), param_type)
if rval != M64ERR_SUCCESS:
log.debug("get_parameter_type()")
log.warn(self.core.error_message(rval))
@ -202,7 +200,7 @@ class Config:
self.m64p.ConfigGetParameterHelp.restype = C.c_char_p
self.m64p.ConfigGetParameterHelp.argtypes = [C.c_void_p, C.c_char_p]
rval = self.m64p.ConfigGetParameterHelp(
self.config_handle, C.c_char_p(param_name))
self.config_handle, C.c_char_p(param_name))
return rval
def set_default(self, param_type, param_name, param_value, param_help):
@ -211,20 +209,20 @@ class Config:
param_ctype = M64_CTYPE[param_type]
if param_type == M64TYPE_INT:
rval = self.m64p.ConfigSetDefaultInt(
self.config_handle, C.c_char_p(param_name),
param_ctype(param_value), C.c_char_p(param_help))
self.config_handle, C.c_char_p(param_name),
param_ctype(param_value), C.c_char_p(param_help))
elif param_type == M64TYPE_FLOAT:
rval = self.m64p.ConfigSetDefaultFloat(
self.config_handle, C.c_char_p(param_name),
param_ctype(param_value), C.c_char_p(param_help))
self.config_handle, C.c_char_p(param_name),
param_ctype(param_value), C.c_char_p(param_help))
elif param_type == M64TYPE_BOOL:
rval = self.m64p.ConfigSetDefaultBool(
self.config_handle, C.c_char_p(param_name),
param_ctype(param_value), C.c_char_p(param_help))
self.config_handle, C.c_char_p(param_name),
param_ctype(param_value), C.c_char_p(param_help))
elif param_type == M64TYPE_STRING:
rval = self.m64p.ConfigSetDefaultString(
self.config_handle, C.c_char_p(param_name),
param_ctype(param_value), C.c_char_p(param_help))
self.config_handle, C.c_char_p(param_name),
param_ctype(param_value), C.c_char_p(param_help))
return rval
def get_path(self, path="UserConfig"):
@ -232,7 +230,7 @@ class Config:
if path == "SharedData":
self.m64p.ConfigGetSharedDataFilepath.restype = C.c_char_p
rval = self.m64p.ConfigGetSharedDataFilepath(
C.c_char_p("mupen64plus.ini"))
C.c_char_p("mupen64plus.ini"))
elif path == "UserConfig":
self.m64p.ConfigGetUserConfigPath.restype = C.c_char_p
rval = self.m64p.ConfigGetUserConfigPath()

View file

@ -40,6 +40,7 @@ def debug_callback(context, level, message):
elif level == M64MSG_VERBOSE and VERBOSE:
sys.stderr.write("%s: %s\n" % (context, message))
def state_callback(context, param, value):
if param == M64CORE_VIDEO_SIZE:
pass
@ -52,6 +53,7 @@ STATEFUNC = C.CFUNCTYPE(None, C.c_char_p, C.c_int, C.c_int)
DEBUG_CALLBACK = DEBUGFUNC(debug_callback)
STATE_CALLBACK = STATEFUNC(state_callback)
class Core:
"""Mupen64Plus Core library"""
@ -71,6 +73,7 @@ class Core:
self.rom_length = None
self.rom_header = m64p_rom_header()
self.rom_settings = m64p_rom_settings()
self.core_path = ""
self.core_name = "Mupen64Plus Core"
self.core_version = "Unknown"
self.core_sdl2 = False
@ -98,26 +101,41 @@ class Core:
if version:
plugin_type, plugin_version, plugin_api, plugin_name, plugin_cap = version
if plugin_type != M64PLUGIN_CORE:
raise Exception("library '%s' is invalid, this is not the emulator core." % (
os.path.basename(self.core_path)))
raise Exception(
"library '%s' is invalid, "
"this is not the emulator core." % (
os.path.basename(self.core_path)))
elif plugin_version < MINIMUM_CORE_VERSION:
raise Exception("library '%s' is incompatible, core version %s is below minimum supported %s." % (
os.path.basename(self.core_path), version_split(plugin_version), version_split(MINIMUM_CORE_VERSION)))
raise Exception(
"library '%s' is incompatible, "
"core version %s is below minimum supported %s." % (
os.path.basename(self.core_path),
version_split(plugin_version),
version_split(MINIMUM_CORE_VERSION)))
elif plugin_api & 0xffff0000 != CORE_API_VERSION & 0xffff0000:
raise Exception("library '%s' is incompatible, core API major version %s doesn't match application (%s)." % (
os.path.basename(self.core_path), version_split(plugin_version), version_split(CORE_API_VERSION)))
raise Exception(
"library '%s' is incompatible, "
"core API major version %s doesn't match application (%s)." % (
os.path.basename(self.core_path),
version_split(plugin_version),
version_split(CORE_API_VERSION)))
else:
config_ver, debug_ver, vidext_ver = self.get_api_versions()
if config_ver & 0xffff0000 != CONFIG_API_VERSION & 0xffff0000:
raise Exception("emulator core '%s' is incompatible, config API major version %s doesn't match application: (%s)" % (
os.path.basename(self.core_path), version_split(self.config_version), version_split(CONFIG_API_VERSION)))
raise Exception(
"emulator core '%s' is incompatible, "
"config API major version %s doesn't match application: (%s)" % (
os.path.basename(self.core_path),
version_split(config_ver),
version_split(CONFIG_API_VERSION)))
self.core_name = plugin_name
self.core_version = plugin_version
if LDD_CMD:
proc = subprocess.Popen(LDD_CMD % self.core_path, shell=True,
preexec_fn=lambda: signal.signal(signal.SIGPIPE, signal.SIG_DFL))
proc = subprocess.Popen(
LDD_CMD % self.core_path, shell=True,
preexec_fn=lambda: signal.signal(signal.SIGPIPE, signal.SIG_DFL))
proc.communicate()
if proc.returncode == 0:
self.core_sdl2 = True
@ -140,9 +158,9 @@ class Core:
def core_startup(self, path, use_vidext):
"""Initializes libmupen64plus for use by allocating memory,
creating data structures, and loading the configuration file."""
rval = self.m64p.CoreStartup(C.c_int(CORE_API_VERSION), None,
C.c_char_p(os.path.dirname(path)),
"Core", DEBUG_CALLBACK, "State", STATE_CALLBACK)
rval = self.m64p.CoreStartup(
C.c_int(CORE_API_VERSION), None, C.c_char_p(os.path.dirname(path)),
"Core", DEBUG_CALLBACK, "State", STATE_CALLBACK)
if rval == M64ERR_SUCCESS:
if use_vidext:
self.override_vidext()
@ -167,7 +185,7 @@ class Core:
name_ptr = C.pointer(C.c_char_p())
cap_ptr = C.pointer(C.c_int())
rval = handle.PluginGetVersion(
type_ptr, ver_ptr, api_ptr, name_ptr, cap_ptr)
type_ptr, ver_ptr, api_ptr, name_ptr, cap_ptr)
except AttributeError:
unload_library(handle)
log.warn("library '%s' is invalid, no PluginGetVersion() function found." % (
@ -190,7 +208,7 @@ class Core:
debug_ver_ptr = C.pointer(C.c_int())
vidext_ver_ptr = C.pointer(C.c_int())
rval = self.m64p.CoreGetAPIVersions(
config_ver_ptr, debug_ver_ptr, vidext_ver_ptr, None)
config_ver_ptr, debug_ver_ptr, vidext_ver_ptr, None)
if rval == M64ERR_SUCCESS:
return (config_ver_ptr.contents.value, debug_ver_ptr.contents.value,
vidext_ver_ptr.contents.value)
@ -206,18 +224,18 @@ class Core:
if version:
plugin_type, plugin_version, plugin_api, plugin_desc, plugin_cap = version
plugin_name = os.path.basename(plugin_path)
self.plugin_map[plugin_type][plugin_name] = (plugin_handle, plugin_path,
PLUGIN_NAME[plugin_type], plugin_desc, plugin_version)
self.plugin_map[plugin_type][plugin_name] = (
plugin_handle, plugin_path, PLUGIN_NAME[plugin_type], plugin_desc, plugin_version)
def plugin_startup(self, handle, name, desc):
"""This function initializes plugin for use by allocating memory,
creating data structures, and loading the configuration data."""
rval = handle.PluginStartup(C.c_void_p(self.m64p._handle),
name, DEBUG_CALLBACK)
name, DEBUG_CALLBACK)
if rval != M64ERR_SUCCESS:
log.debug("plugin_startup()")
log.warn(self.error_message(rval))
log.warn("%s failed to start." % (desc))
log.warn("%s failed to start." % desc)
def plugin_shutdown(self, handle, desc):
"""This function destroys data structures and releases
@ -226,9 +244,9 @@ class Core:
if rval != M64ERR_SUCCESS:
log.debug("plugin_shutdown()")
log.warn(self.error_message(rval))
log.warn("%s failed to stop." % (desc))
log.warn("%s failed to stop." % desc)
def attach_plugins(self, plugins={}):
def attach_plugins(self, plugins):
"""Attaches plugins to the emulator core."""
self.plugins = plugins
for plugin_type in PLUGIN_ORDER:
@ -238,11 +256,10 @@ class Core:
else:
plugin_map = self.plugin_map[plugin_type][plugin]
(plugin_handle, plugin_path, plugin_name,
plugin_desc, plugin_version) = plugin_map
plugin_desc, plugin_version) = plugin_map
rval = self.m64p.CoreAttachPlugin(
C.c_int(plugin_type),
C.c_void_p(plugin_handle._handle))
C.c_int(plugin_type), C.c_void_p(plugin_handle._handle))
if rval != M64ERR_SUCCESS:
log.debug("attach_plugins()")
log.warn(self.error_message(rval))
@ -262,7 +279,7 @@ class Core:
else:
plugin_map = self.plugin_map[plugin_type][plugin]
(plugin_handle, plugin_path, plugin_name,
plugin_desc, plugin_version) = plugin_map
plugin_desc, plugin_version) = plugin_map
rval = self.m64p.CoreDetachPlugin(plugin_type)
if rval != M64ERR_SUCCESS:
@ -278,19 +295,18 @@ class Core:
romlength = C.c_int(self.rom_length)
rombuffer = C.c_buffer(romfile)
rval = self.m64p.CoreDoCommand(
M64CMD_ROM_OPEN, romlength, C.byref(rombuffer))
M64CMD_ROM_OPEN, romlength, C.byref(rombuffer))
if rval != M64ERR_SUCCESS:
log.debug("rom_open()")
log.warn(self.error_message(rval))
log.error("core failed to open ROM file '%s'." % (
filename))
log.error("core failed to open ROM file.")
del rombuffer
return rval
def rom_close(self):
"""Closes any currently open ROM."""
rval = self.m64p.CoreDoCommand(
M64CMD_ROM_CLOSE)
M64CMD_ROM_CLOSE)
if rval != M64ERR_SUCCESS:
log.debug("rom_close()")
log.warn(self.error_message(rval))
@ -300,9 +316,9 @@ class Core:
def rom_get_header(self):
"""Retrieves the header data of the currently open ROM."""
rval = self.m64p.CoreDoCommand(
M64CMD_ROM_GET_HEADER,
C.c_int(C.sizeof(self.rom_header)),
C.pointer(self.rom_header))
M64CMD_ROM_GET_HEADER,
C.c_int(C.sizeof(self.rom_header)),
C.pointer(self.rom_header))
if rval != M64ERR_SUCCESS:
log.debug("rom_get_header()")
log.warn("core failed to get ROM header.")
@ -311,9 +327,9 @@ class Core:
def rom_get_settings(self):
"""Retrieves the settings data of the currently open ROM."""
rval = self.m64p.CoreDoCommand(
M64CMD_ROM_GET_SETTINGS,
C.c_int(C.sizeof(self.rom_settings)),
C.pointer(self.rom_settings))
M64CMD_ROM_GET_SETTINGS,
C.c_int(C.sizeof(self.rom_settings)),
C.pointer(self.rom_settings))
if rval != M64ERR_SUCCESS:
log.debug("rom_get_settings()")
log.warn("core failed to get ROM settings.")
@ -322,7 +338,7 @@ class Core:
def execute(self):
"""Starts the emulator and begin executing the ROM image."""
rval = self.m64p.CoreDoCommand(
M64CMD_EXECUTE, 0, None)
M64CMD_EXECUTE, 0, None)
if rval != M64ERR_SUCCESS:
log.warn(self.error_message(rval))
return rval
@ -330,7 +346,7 @@ class Core:
def stop(self):
"""Stops the emulator, if it is currently running."""
rval = self.m64p.CoreDoCommand(
M64CMD_STOP, 0, None)
M64CMD_STOP, 0, None)
if rval != M64ERR_SUCCESS:
log.debug("stop()")
log.warn(self.error_message(rval))
@ -339,7 +355,7 @@ class Core:
def pause(self):
"""Pause the emulator if it is running."""
rval = self.m64p.CoreDoCommand(
M64CMD_PAUSE, 0, None)
M64CMD_PAUSE, 0, None)
if rval != M64ERR_SUCCESS:
log.debug("pause()")
log.warn(self.error_message(rval))
@ -348,7 +364,7 @@ class Core:
def resume(self):
"""Resumes execution of the emulator if it is paused."""
rval = self.m64p.CoreDoCommand(
M64CMD_RESUME, 0, None)
M64CMD_RESUME, 0, None)
if rval != M64ERR_SUCCESS:
log.debug("resume()")
log.warn(self.error_message(rval))
@ -359,8 +375,7 @@ class Core:
value of a state parameter."""
state_ptr = C.pointer(C.c_int())
rval = self.m64p.CoreDoCommand(
M64CMD_CORE_STATE_QUERY,
C.c_int(state), state_ptr)
M64CMD_CORE_STATE_QUERY, C.c_int(state), state_ptr)
if rval != M64ERR_SUCCESS:
log.debug("core_state_query()")
log.warn(self.error_message(rval))
@ -371,8 +386,7 @@ class Core:
parameter in the emulator core."""
value_ptr = C.pointer(C.c_int(value))
rval = self.m64p.CoreDoCommand(
M64CMD_CORE_STATE_SET,
C.c_int(state), value_ptr)
M64CMD_CORE_STATE_SET, C.c_int(state), value_ptr)
if rval != M64ERR_SUCCESS:
log.debug("core_state_set()")
log.warn(self.error_message(rval))
@ -382,7 +396,7 @@ class Core:
"""Loads a saved state file from the current slot."""
path = C.c_char_p(state_path) if state_path else None
rval = self.m64p.CoreDoCommand(
M64CMD_STATE_LOAD, C.c_int(1), path)
M64CMD_STATE_LOAD, C.c_int(1), path)
if rval != M64ERR_SUCCESS:
log.debug("state_load()")
log.warn(self.error_message(rval))
@ -392,7 +406,7 @@ class Core:
"""Saves a state file to the current slot."""
path = C.c_char_p(state_path) if state_path else None
rval = self.m64p.CoreDoCommand(
M64CMD_STATE_SAVE, C.c_int(state_type), path)
M64CMD_STATE_SAVE, C.c_int(state_type), path)
if rval != M64ERR_SUCCESS:
log.debug("state_save()")
log.warn(self.error_message(rval))
@ -401,7 +415,7 @@ class Core:
def state_set_slot(self, slot):
"""Sets the currently selected save slot index."""
rval = self.m64p.CoreDoCommand(
M64CMD_STATE_SET_SLOT, C.c_int(slot))
M64CMD_STATE_SET_SLOT, C.c_int(slot))
if rval != M64ERR_SUCCESS:
log.debug("state_set_slot()")
log.warn(self.error_message(rval))
@ -411,7 +425,7 @@ class Core:
"""Injects an SDL_KEYDOWN event into
the emulator's core event loop."""
rval = self.m64p.CoreDoCommand(
M64CMD_SEND_SDL_KEYDOWN, C.c_int(key))
M64CMD_SEND_SDL_KEYDOWN, C.c_int(key))
if rval != M64ERR_SUCCESS:
log.debug("send_sdl_keydown()")
log.warn(self.error_message(rval))
@ -421,7 +435,7 @@ class Core:
"""Injects an SDL_KEYUP event into
the emulator's core event loop."""
rval = self.m64p.CoreDoCommand(
M64CMD_SEND_SDL_KEYUP, C.c_int(key))
M64CMD_SEND_SDL_KEYUP, C.c_int(key))
if rval != M64ERR_SUCCESS:
log.debug("send_sdl_keyup()")
log.warn(self.error_message(rval))
@ -430,7 +444,7 @@ class Core:
def take_next_screenshot(self):
"""Saves a screenshot at the next possible opportunity."""
rval = self.m64p.CoreDoCommand(
M64CMD_TAKE_NEXT_SCREENSHOT)
M64CMD_TAKE_NEXT_SCREENSHOT)
if rval != M64ERR_SUCCESS:
log.debug("take_next_screenshot()")
log.warn(self.error_message(rval))
@ -439,7 +453,7 @@ class Core:
def reset(self, soft=False):
"""Reset the emulated machine."""
rval = self.m64p.CoreDoCommand(
M64CMD_RESET, C.c_int(int(soft)))
M64CMD_RESET, C.c_int(int(soft)))
if rval != M64ERR_SUCCESS:
log.debug("reset()")
log.warn(self.error_message(rval))
@ -458,8 +472,9 @@ class Core:
def add_cheat(self, cheat_name, cheat_code):
"""Adds a Cheat Function to a list of currently active cheats
which are applied to the open ROM, and set its state to Enabled"""
rval = self.m64p.CoreAddCheat(C.c_char_p(cheat_name),
C.pointer(cheat_code), C.c_int(C.sizeof(cheat_code)))
rval = self.m64p.CoreAddCheat(
C.c_char_p(cheat_name), C.pointer(cheat_code),
C.c_int(C.sizeof(cheat_code)))
if rval != M64ERR_SUCCESS:
log.debug("add_cheat()")
log.info("CoreAddCheat() failed for cheat code '%s'" % cheat_name)
@ -471,7 +486,7 @@ class Core:
def cheat_enabled(self, cheat_name, enabled=True):
"""Enables or disables a specified Cheat Function"""
rval = self.m64p.CoreCheatEnabled(
C.c_char_p(cheat_name), C.c_int(enabled))
C.c_char_p(cheat_name), C.c_int(enabled))
if rval != M64ERR_SUCCESS:
log.debug("cheat_enabled()")
log.info("CoreCheatEnabled() failed for cheat code '%s'" % cheat_name)

View file

@ -120,48 +120,49 @@ M64TYPE_BOOL = 3
M64TYPE_STRING = 4
M64_CTYPE = {
M64TYPE_INT: C.c_int,
M64TYPE_FLOAT: C.c_float,
M64TYPE_BOOL: C.c_int,
M64TYPE_STRING: C.c_char_p
}
M64TYPE_INT: C.c_int,
M64TYPE_FLOAT: C.c_float,
M64TYPE_BOOL: C.c_int,
M64TYPE_STRING: C.c_char_p
}
PLUGIN_ORDER = [
M64PLUGIN_GFX,
M64PLUGIN_AUDIO,
M64PLUGIN_INPUT,
M64PLUGIN_RSP
]
M64PLUGIN_GFX,
M64PLUGIN_AUDIO,
M64PLUGIN_INPUT,
M64PLUGIN_RSP
]
PLUGIN_NAME = {
M64PLUGIN_NULL: "NULL",
M64PLUGIN_RSP: "RSP",
M64PLUGIN_GFX: "Video",
M64PLUGIN_AUDIO: "Audio",
M64PLUGIN_INPUT: "Input"
}
M64PLUGIN_NULL: "NULL",
M64PLUGIN_RSP: "RSP",
M64PLUGIN_GFX: "Video",
M64PLUGIN_AUDIO: "Audio",
M64PLUGIN_INPUT: "Input"
}
PLUGIN_DEFAULT = {
M64PLUGIN_NULL: "NULL",
M64PLUGIN_RSP: "mupen64plus-rsp-hle%s" % DLL_EXT,
M64PLUGIN_GFX: "mupen64plus-video-rice%s" % DLL_EXT,
M64PLUGIN_AUDIO: "mupen64plus-audio-sdl%s" % DLL_EXT,
M64PLUGIN_INPUT: "mupen64plus-input-sdl%s" % DLL_EXT
}
M64PLUGIN_NULL: "NULL",
M64PLUGIN_RSP: "mupen64plus-rsp-hle%s" % DLL_EXT,
M64PLUGIN_GFX: "mupen64plus-video-rice%s" % DLL_EXT,
M64PLUGIN_AUDIO: "mupen64plus-audio-sdl%s" % DLL_EXT,
M64PLUGIN_INPUT: "mupen64plus-input-sdl%s" % DLL_EXT
}
M64SAV_M64P = 1
M64SAV_PJ64C = 2
M64SAV_PJ64 = 3
M64P_SAVES = {
M64SAV_M64P: ("M64P (*.m64p)", "m64p"),
M64SAV_PJ64C: ("PJ64 compressed (*.zip)", "zip"),
M64SAV_PJ64: ("PJ64 (*.pj)", "pj")
}
M64SAV_M64P: ("M64P (*.m64p)", "m64p"),
M64SAV_PJ64C: ("PJ64 compressed (*.zip)", "zip"),
M64SAV_PJ64: ("PJ64 (*.pj)", "pj")
}
m64p_error = C.c_int
m64p_GLattr = C.c_int
class m64p_rom_header(C.Structure):
_fields_ = [
('init_PI_BSB_DOM1_LAT_REG', C.c_ubyte),
@ -179,7 +180,8 @@ class m64p_rom_header(C.Structure):
('Manufacturer_ID', C.c_uint),
('Cartridge_ID', C.c_ushort),
('Country_code', C.c_ushort)
]
]
class m64p_rom_settings(C.Structure):
_fields_ = [
@ -189,19 +191,21 @@ class m64p_rom_settings(C.Structure):
('status', C.c_ubyte),
('players', C.c_ubyte),
('rumble', C.c_ubyte)
]
]
class m64p_cheat_code(C.Structure):
_fields_ = [
('address', C.c_uint),
('value', C.c_int),
]
]
class m64p_2d_size(C.Structure):
_fields_ = [
('uiWidth', C.c_uint),
('uiHeight', C.c_uint)
]
]
FuncInit = C.CFUNCTYPE(m64p_error)
FuncQuit = C.CFUNCTYPE(m64p_error)
@ -215,6 +219,7 @@ FuncSetCaption = C.CFUNCTYPE(m64p_error, C.c_char_p)
FuncToggleFS = C.CFUNCTYPE(m64p_error)
FuncResizeWindow = C.CFUNCTYPE(m64p_error, C.c_int, C.c_int)
class m64p_video_extension_functions(C.Structure):
_fields_ = [
('Functions', C.c_uint),
@ -231,7 +236,7 @@ class m64p_video_extension_functions(C.Structure):
('VidExtFuncResizeWindow', FuncResizeWindow)
]
LOGO = " __ __ __ _ _ ____ _ \n"
LOGO = " __ __ __ _ _ ____ _ \n"
LOGO += "| \/ |_ _ _ __ ___ _ __ / /_ | || | | _ \| |_ _ ___ \n"
LOGO += "| |\/| | | | | '_ \ / _ \ '_ \| '_ \| || |_| |_) | | | | / __| \n"
LOGO += "| | | | |_| | |_) | __/ | | | (_) |__ _| __/| | |_| \__ \ \n"

View file

@ -54,8 +54,9 @@ try:
except Exception, err:
log.warn(str(err))
MODES = [(1920, 1440), (1600, 1200), (1400, 1050),
(1280, 960), (1152, 864), (1024, 768),
(800, 600), (640, 480), (320, 240)]
(1280, 960), (1152, 864), (1024, 768),
(800, 600), (640, 480), (320, 240)]
class Video():
"""Mupen64Plus video extension"""
@ -64,6 +65,7 @@ class Video():
"""Constructor."""
self.parent = None
self.widget = None
self.glformat = None
self.glcontext = None
def set_widget(self, parent):
@ -114,8 +116,7 @@ class Video():
"""Sets the caption text of the
emulator rendering window. """
title = "M64Py :: %s" % title
self.parent.emit(
SIGNAL("set_caption(PyQt_PyObject)"), title)
self.parent.emit(SIGNAL("set_caption(PyQt_PyObject)"), title)
return M64ERR_SUCCESS
def toggle_fs(self):
@ -136,16 +137,16 @@ class Video():
def gl_set_attr(self, attr, value):
"""Sets OpenGL attributes."""
attr_map = {
M64P_GL_DOUBLEBUFFER: self.glformat.setDoubleBuffer,
M64P_GL_BUFFER_SIZE: self.glformat.setDepthBufferSize,
M64P_GL_DEPTH_SIZE: self.glformat.setDepth,
M64P_GL_RED_SIZE: self.glformat.setRedBufferSize,
M64P_GL_GREEN_SIZE: self.glformat.setGreenBufferSize,
M64P_GL_BLUE_SIZE: self.glformat.setBlueBufferSize,
M64P_GL_ALPHA_SIZE: self.glformat.setAlphaBufferSize,
M64P_GL_SWAP_CONTROL: self.glformat.setSwapInterval,
M64P_GL_MULTISAMPLEBUFFERS: self.glformat.setSampleBuffers,
M64P_GL_MULTISAMPLESAMPLES: self.glformat.setSamples
M64P_GL_DOUBLEBUFFER: self.glformat.setDoubleBuffer,
M64P_GL_BUFFER_SIZE: self.glformat.setDepthBufferSize,
M64P_GL_DEPTH_SIZE: self.glformat.setDepth,
M64P_GL_RED_SIZE: self.glformat.setRedBufferSize,
M64P_GL_GREEN_SIZE: self.glformat.setGreenBufferSize,
M64P_GL_BLUE_SIZE: self.glformat.setBlueBufferSize,
M64P_GL_ALPHA_SIZE: self.glformat.setAlphaBufferSize,
M64P_GL_SWAP_CONTROL: self.glformat.setSwapInterval,
M64P_GL_MULTISAMPLEBUFFERS: self.glformat.setSampleBuffers,
M64P_GL_MULTISAMPLESAMPLES: self.glformat.setSamples
}
set_attr = attr_map[attr]
set_attr(value)
@ -154,16 +155,16 @@ class Video():
def gl_get_attr(self, attr, value):
"""Gets OpenGL attributes."""
attr_map = {
M64P_GL_DOUBLEBUFFER: self.glformat.doubleBuffer,
M64P_GL_BUFFER_SIZE: self.glformat.depthBufferSize,
M64P_GL_DEPTH_SIZE: self.glformat.depth,
M64P_GL_RED_SIZE: self.glformat.redBufferSize,
M64P_GL_GREEN_SIZE: self.glformat.greenBufferSize,
M64P_GL_BLUE_SIZE: self.glformat.blueBufferSize,
M64P_GL_ALPHA_SIZE: self.glformat.alphaBufferSize,
M64P_GL_SWAP_CONTROL: self.glformat.swapInterval,
M64P_GL_MULTISAMPLEBUFFERS: self.glformat.sampleBuffers,
M64P_GL_MULTISAMPLESAMPLES: self.glformat.samples
M64P_GL_DOUBLEBUFFER: self.glformat.doubleBuffer,
M64P_GL_BUFFER_SIZE: self.glformat.depthBufferSize,
M64P_GL_DEPTH_SIZE: self.glformat.depth,
M64P_GL_RED_SIZE: self.glformat.redBufferSize,
M64P_GL_GREEN_SIZE: self.glformat.greenBufferSize,
M64P_GL_BLUE_SIZE: self.glformat.blueBufferSize,
M64P_GL_ALPHA_SIZE: self.glformat.alphaBufferSize,
M64P_GL_SWAP_CONTROL: self.glformat.swapInterval,
M64P_GL_MULTISAMPLEBUFFERS: self.glformat.sampleBuffers,
M64P_GL_MULTISAMPLESAMPLES: self.glformat.samples
}
get_attr = attr_map[attr]
new_value = int(get_attr())

View file

@ -27,6 +27,7 @@ from m64py.frontend.log import log
from m64py.ui.cheat_ui import Ui_CheatDialog
from m64py.ui.choices_ui import Ui_ChoicesDialog
class Cheat(QDialog, Ui_CheatDialog):
"""Cheats dialog"""
@ -106,13 +107,13 @@ class Cheat(QDialog, Ui_CheatDialog):
def on_unmark_all(self):
"""Deactivates all cheats"""
iter = QTreeWidgetItemIterator(self.treeWidget)
while(iter.value()):
item = iter.value()
it = QTreeWidgetItemIterator(self.treeWidget)
while it.value():
item = it.value()
state = item.checkState(0)
if state == Qt.Checked:
item.setCheckState(0, Qt.Unchecked)
iter += 1
it += 1
def activate_cheat(self, item, column):
"""Activates selected cheat"""
@ -184,26 +185,23 @@ class Cheat(QDialog, Ui_CheatDialog):
cheat_codes = []
cheat_file = os.path.join(
self.parent.worker.core.config.get_path(
"SharedData"), 'mupencheat.txt')
self.parent.worker.core.config.get_path( "SharedData"), 'mupencheat.txt')
if not os.path.isfile(cheat_file) or not os.access(cheat_file, os.R_OK):
log.warn("cheat code database file '%s' not found." % cheat_file)
return None
rom_section = "%08X-%08X-C:%X" % (
sl(self.parent.worker.core.rom_header.CRC1),
sl(self.parent.worker.core.rom_header.CRC2),
self.parent.worker.core.rom_header.Country_code & 0xff)
sl(self.parent.worker.core.rom_header.CRC1),
sl(self.parent.worker.core.rom_header.CRC2),
self.parent.worker.core.rom_header.Country_code & 0xff)
rom_section = rom_section.upper()
code_re = re.compile(
'^([0-9A-F]{8})\s+([?|0-9A-F]{4})\s?(.*)$', re.M)
code_re = re.compile('^([0-9A-F]{8})\s+([?|0-9A-F]{4})\s?(.*)$', re.M)
try:
fd = open(cheat_file, 'r')
except IOError:
log.warn("couldn't open cheat code database file '%s'." % (
cheat_file))
log.warn("couldn't open cheat code database file '%s'." % cheat_file)
return None
else:
lines = [line.strip() for line in fd.readlines()]
@ -267,9 +265,10 @@ class Cheat(QDialog, Ui_CheatDialog):
if line:
# otherwise we don't know what this line is
log.warn("unrecognized line in cheat file: '%s'" % (line))
log.warn("unrecognized line in cheat file: '%s'" % line)
return None
class Choices(QDialog, Ui_ChoicesDialog):
"""Choices dialog"""

View file

@ -23,6 +23,7 @@ from m64py.ui.about_ui import Ui_AboutDialog
from m64py.ui.license_ui import Ui_LicenseDialog
from m64py.ui.archive_ui import Ui_ArchiveDialog
class AboutDialog(QDialog, Ui_AboutDialog):
def __init__(self, parent):
QDialog.__init__(self, parent)
@ -37,12 +38,14 @@ class AboutDialog(QDialog, Ui_AboutDialog):
self.labelAbout.setText(text)
self.show()
class LicenseDialog(QDialog, Ui_LicenseDialog):
def __init__(self, parent):
QDialog.__init__(self, parent)
self.setupUi(self)
self.show()
class InfoDialog(QMessageBox):
def __init__(self, parent=None, text=None):
QMessageBox.__init__(self, parent)
@ -50,6 +53,7 @@ class InfoDialog(QMessageBox):
self.setWindowTitle("Info")
self.show()
class ArchiveDialog(QDialog, Ui_ArchiveDialog):
def __init__(self, parent, files):
QDialog.__init__(self, parent)

View file

@ -14,7 +14,6 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
from PyQt4.QtGui import *
from PyQt4.QtCore import *
from PyQt4.QtOpenGL import *
@ -22,6 +21,7 @@ from m64py.core.defs import *
from m64py.opts import SDL2
from m64py.frontend.keymap import QT2SDL, QT2SDL2
class GLWidget(QGLWidget):
toggle_fs = pyqtSignal()
@ -34,7 +34,7 @@ class GLWidget(QGLWidget):
self.setContentsMargins(QMargins())
self.setFocusPolicy(Qt.StrongFocus)
self.setFocus(True)
self.connect(self, SIGNAL("toggle_fs()"), self.toggle_fs)
self.connect(self, SIGNAL("toggle_fs()"), self.toggle_fullscreen)
def showEvent(self, event):
self.setFocus(True)
@ -47,7 +47,7 @@ class GLWidget(QGLWidget):
pass
def mouseDoubleClickEvent(self, event):
self.toggle_fs()
self.emit(SIGNAL("toggle_fs()"))
def keyPressEvent(self, event):
if self.worker.state == M64EMU_RUNNING:
@ -55,7 +55,7 @@ class GLWidget(QGLWidget):
modifiers = event.modifiers()
if modifiers & Qt.AltModifier and \
(key == Qt.Key_Enter or key == Qt.Key_Return):
self.toggle_fs()
self.emit(SIGNAL("toggle_fs()"))
elif key == Qt.Key_F3:
self.worker.save_title()
elif key == Qt.Key_F4:
@ -82,7 +82,7 @@ class GLWidget(QGLWidget):
except KeyError:
pass
def toggle_fs(self):
def toggle_fullscreen(self):
window = self.window()
if window.isFullScreen():
self.parent.menubar.show()

View file

@ -34,6 +34,7 @@ else:
KEY_RE = re.compile("([a-z]+)\((.*)\)")
AXIS_RE = re.compile("([a-z]+)\((.*?),(.*?)\)")
class Input(QDialog, Ui_InputDialog):
def __init__(self, parent):
@ -44,6 +45,9 @@ class Input(QDialog, Ui_InputDialog):
self.controller = 1
self.mode = 0
self.device = -1
self.opts = {}
self.keys = {}
self.section = None
self.is_joystick = False
self.set_section("Input-SDL-Control%d" % self.controller)
self.joystick = Joystick()
@ -59,11 +63,11 @@ class Input(QDialog, Ui_InputDialog):
def connect_signals(self):
self.comboDevice.currentIndexChanged.connect(
self.on_device_changed)
self.on_device_changed)
self.comboController.currentIndexChanged.connect(
self.on_controller_changed)
self.on_controller_changed)
self.comboMode.currentIndexChanged.connect(
self.on_mode_changed)
self.on_mode_changed)
def show_dialog(self):
self.config = self.parent.worker.core.config
@ -102,13 +106,20 @@ class Input(QDialog, Ui_InputDialog):
def add_items(self):
for controller in range(1, 5):
self.comboController.addItem(
self.tr("Controller %s" % controller), controller)
self.tr("Controller %s" % controller), controller)
for plugin, ptype in [(self.tr("None"), 1), (self.tr("Mem pak"), 2), (self.tr("Rumble pak"), 5)]:
for plugin, ptype in [
(self.tr("None"), 1),
(self.tr("Mem pak"), 2),
(self.tr("Rumble pak"), 5)
]:
self.comboPlugin.addItem(plugin, ptype)
for mode, mtype in [(self.tr("Fully Manual"), 0),
(self.tr("Auto with named SDL device"), 1), (self.tr("Fully Automatic"), 2)]:
for mode, mtype in [
(self.tr("Fully Manual"), 0),
(self.tr("Auto with named SDL device"), 1),
(self.tr("Fully Automatic"), 2)
]:
self.comboMode.addItem(mode, mtype)
devices = [(self.tr("Keyboard/Mouse"), -1)]
@ -148,7 +159,7 @@ class Input(QDialog, Ui_InputDialog):
continue
self.config.set_default(M64TYPE_STRING, key, "", "")
self.config.set_default(M64TYPE_STRING, "X Axis", "",
"Analog axis configuration mappings")
"Analog axis configuration mappings")
self.config.set_default(M64TYPE_STRING, "Y Axis", "", "")
for key, val in self.opts.items():
param, tooltip, widget, ptype = val
@ -196,7 +207,7 @@ class Input(QDialog, Ui_InputDialog):
self.config.get_parameter("AnalogPeak"),
self.config.get_parameter_help("AnalogPeak"),
(self.spinPeakX, self.spinPeakY), M64TYPE_STRING)
}
}
def set_opts(self):
for key, val in self.opts.items():
@ -226,19 +237,19 @@ class Input(QDialog, Ui_InputDialog):
for key, val in self.opts.items():
param, tooltip, widget, ptype = val
if ptype == M64TYPE_BOOL:
self.config.set_parameter(key,
widget.isChecked())
self.config.set_parameter(
key, widget.isChecked())
elif ptype == M64TYPE_INT:
self.config.set_parameter(key,
widget.itemData(widget.currentIndex()))
self.config.set_parameter(
key, widget.itemData(widget.currentIndex()))
elif ptype == M64TYPE_STRING:
if key in ["AnalogDeadzone", "AnalogPeak"]:
spin1, spin2 = widget
self.config.set_parameter(key,"%s,%s" % (
spin1.value(), spin2.value()))
else:
self.config.set_parameter(key,
str(widget.text()))
self.config.set_parameter(
key, str(widget.text()))
def get_keys(self):
self.keys = {
@ -282,8 +293,7 @@ class Input(QDialog, Ui_InputDialog):
self.get_key("Y Axis")[0], self.pushY_Axis_U),
"Y Axis D": (
self.get_key("Y Axis")[1], self.pushY_Axis_D)
}
}
def set_keys(self):
for key, val in self.keys.items():
@ -346,23 +356,23 @@ class Input(QDialog, Ui_InputDialog):
xr = KEY_RE.findall(str(self.pushX_Axis_R.text()))
if xl and xr:
xl, xr = xl[0], xr[0]
self.config.set_parameter("X Axis", "%s(%s,%s)" % (xl[0],xl[1],xr[1]))
self.config.set_parameter("X Axis", "%s(%s,%s)" % (xl[0], xl[1], xr[1]))
else:
xl = self.get_sdl_key(self.pushX_Axis_L.text())
xr = self.get_sdl_key(self.pushX_Axis_R.text())
if xl and xr:
self.config.set_parameter("X Axis", "key(%s,%s)" % (xl,xr))
self.config.set_parameter("X Axis", "key(%s,%s)" % (xl, xr))
yu = KEY_RE.findall(str(self.pushY_Axis_U.text()))
yd = KEY_RE.findall(str(self.pushY_Axis_D.text()))
if yu and yd:
yu, yd = yu[0], yd[0]
self.config.set_parameter("Y Axis", "%s(%s,%s)" % (yu[0],yu[1],yd[1]))
self.config.set_parameter("Y Axis", "%s(%s,%s)" % (yu[0], yu[1], yd[1]))
else:
yu = self.get_sdl_key(self.pushY_Axis_U.text())
yd = self.get_sdl_key(self.pushY_Axis_D.text())
if yu and yd:
self.config.set_parameter("Y Axis", "key(%s,%s)" % (yu,yd))
self.config.set_parameter("Y Axis", "key(%s,%s)" % (yu, yd))
def get_key(self, key):
param = self.config.get_parameter(key)
@ -405,7 +415,7 @@ class Input(QDialog, Ui_InputDialog):
from m64py.SDL2.keyboard import SDL_GetScancodeName
try:
text = SDL_GetScancodeName(KEYCODE2SCANCODE[int(sdl_key)])
except:
except Exception:
return self.tr("Select...")
else:
from m64py.SDL.keyboard import SDL_GetKeyName

View file

@ -39,6 +39,7 @@ JOYSTICK_SENSITIVITY = 0
SDL_JOYSTICK_DEFAULT_EVENT_TIMEOUT = 25
SDL_JOYSTICK_DEFAULT_AUTOREPEAT_DELAY = 250
class Joystick(QObject):
axis_value_changed = pyqtSignal(int, int)
@ -47,12 +48,11 @@ class Joystick(QObject):
trackball_value_changed = pyqtSignal(int, int, int)
def __init__(self, do_auto_repeat=True,
repeat_delay=SDL_JOYSTICK_DEFAULT_AUTOREPEAT_DELAY,
joystick_event_timeout=SDL_JOYSTICK_DEFAULT_EVENT_TIMEOUT,
joystick_deadzone=JOYSTICK_DEADZONE,
joystick_sensitivity=JOYSTICK_SENSITIVITY):
repeat_delay=SDL_JOYSTICK_DEFAULT_AUTOREPEAT_DELAY,
joystick_event_timeout=SDL_JOYSTICK_DEFAULT_EVENT_TIMEOUT,
joystick_deadzone=JOYSTICK_DEADZONE,
joystick_sensitivity=JOYSTICK_SENSITIVITY):
QObject.__init__(self)
self.joystick_timer = QTimer()
self.deadzones = {}
@ -81,8 +81,7 @@ class Joystick(QObject):
self.joystick_names.append(SDL_JoystickNameForIndex(i))
else:
self.joystick_names.append(SDL_JoystickName(i))
self.connect(self.joystick_timer, SIGNAL("timeout()"),
self.process_events)
self.connect(self.joystick_timer, SIGNAL("timeout()"), self.process_events)
else:
log.info("couldn't initialize SDL joystick support")

View file

@ -239,237 +239,237 @@ SDL_SCANCODE_EJECT = 281
SDL_SCANCODE_SLEEP = 282
SDL_NUM_SCANCODES = 512
SDLK_UNKNOWN = 0
SDLK_FIRST = 0
SDLK_BACKSPACE = 8
SDLK_TAB = 9
SDLK_CLEAR = 12
SDLK_RETURN = 13
SDLK_PAUSE = 19
SDLK_ESCAPE = 27
SDLK_SPACE = 32
SDLK_EXCLAIM = 33
SDLK_QUOTEDBL = 34
SDLK_HASH = 35
SDLK_DOLLAR = 36
SDLK_AMPERSAND = 38
SDLK_QUOTE = 39
SDLK_LEFTPAREN = 40
SDLK_RIGHTPAREN = 41
SDLK_ASTERISK = 42
SDLK_PLUS = 43
SDLK_COMMA = 44
SDLK_MINUS = 45
SDLK_PERIOD = 46
SDLK_SLASH = 47
SDLK_0 = 48
SDLK_1 = 49
SDLK_2 = 50
SDLK_3 = 51
SDLK_4 = 52
SDLK_5 = 53
SDLK_6 = 54
SDLK_7 = 55
SDLK_8 = 56
SDLK_9 = 57
SDLK_COLON = 58
SDLK_SEMICOLON = 59
SDLK_LESS = 60
SDLK_EQUALS = 61
SDLK_GREATER = 62
SDLK_QUESTION = 63
SDLK_AT = 64
SDLK_LEFTBRACKET = 91
SDLK_BACKSLASH = 92
SDLK_RIGHTBRACKET = 93
SDLK_CARET = 94
SDLK_UNDERSCORE = 95
SDLK_BACKQUOTE = 96
SDLK_a = 97
SDLK_b = 98
SDLK_c = 99
SDLK_d = 100
SDLK_e = 101
SDLK_f = 102
SDLK_g = 103
SDLK_h = 104
SDLK_i = 105
SDLK_j = 106
SDLK_k = 107
SDLK_l = 108
SDLK_m = 109
SDLK_n = 110
SDLK_o = 111
SDLK_p = 112
SDLK_q = 113
SDLK_r = 114
SDLK_s = 115
SDLK_t = 116
SDLK_u = 117
SDLK_v = 118
SDLK_w = 119
SDLK_x = 120
SDLK_y = 121
SDLK_z = 122
SDLK_DELETE = 127
SDLK_WORLD_0 = 160
SDLK_WORLD_1 = 161
SDLK_WORLD_2 = 162
SDLK_WORLD_3 = 163
SDLK_WORLD_4 = 164
SDLK_WORLD_5 = 165
SDLK_WORLD_6 = 166
SDLK_WORLD_7 = 167
SDLK_WORLD_8 = 168
SDLK_WORLD_9 = 169
SDLK_WORLD_10 = 170
SDLK_WORLD_11 = 171
SDLK_WORLD_12 = 172
SDLK_WORLD_13 = 173
SDLK_WORLD_14 = 174
SDLK_WORLD_15 = 175
SDLK_WORLD_16 = 176
SDLK_WORLD_17 = 177
SDLK_WORLD_18 = 178
SDLK_WORLD_19 = 179
SDLK_WORLD_20 = 180
SDLK_WORLD_21 = 181
SDLK_WORLD_22 = 182
SDLK_WORLD_23 = 183
SDLK_WORLD_24 = 184
SDLK_WORLD_25 = 185
SDLK_WORLD_26 = 186
SDLK_WORLD_27 = 187
SDLK_WORLD_28 = 188
SDLK_WORLD_29 = 189
SDLK_WORLD_30 = 190
SDLK_WORLD_31 = 191
SDLK_WORLD_32 = 192
SDLK_WORLD_33 = 193
SDLK_WORLD_34 = 194
SDLK_WORLD_35 = 195
SDLK_WORLD_36 = 196
SDLK_WORLD_37 = 197
SDLK_WORLD_38 = 198
SDLK_WORLD_39 = 199
SDLK_WORLD_40 = 200
SDLK_WORLD_41 = 201
SDLK_WORLD_42 = 202
SDLK_WORLD_43 = 203
SDLK_WORLD_44 = 204
SDLK_WORLD_45 = 205
SDLK_WORLD_46 = 206
SDLK_WORLD_47 = 207
SDLK_WORLD_48 = 208
SDLK_WORLD_49 = 209
SDLK_WORLD_50 = 210
SDLK_WORLD_51 = 211
SDLK_WORLD_52 = 212
SDLK_WORLD_53 = 213
SDLK_WORLD_54 = 214
SDLK_WORLD_55 = 215
SDLK_WORLD_56 = 216
SDLK_WORLD_57 = 217
SDLK_WORLD_58 = 218
SDLK_WORLD_59 = 219
SDLK_WORLD_60 = 220
SDLK_WORLD_61 = 221
SDLK_WORLD_62 = 222
SDLK_WORLD_63 = 223
SDLK_WORLD_64 = 224
SDLK_WORLD_65 = 225
SDLK_WORLD_66 = 226
SDLK_WORLD_67 = 227
SDLK_WORLD_68 = 228
SDLK_WORLD_69 = 229
SDLK_WORLD_70 = 230
SDLK_WORLD_71 = 231
SDLK_WORLD_72 = 232
SDLK_WORLD_73 = 233
SDLK_WORLD_74 = 234
SDLK_WORLD_75 = 235
SDLK_WORLD_76 = 236
SDLK_WORLD_77 = 237
SDLK_WORLD_78 = 238
SDLK_WORLD_79 = 239
SDLK_WORLD_80 = 240
SDLK_WORLD_81 = 241
SDLK_WORLD_82 = 242
SDLK_WORLD_83 = 243
SDLK_WORLD_84 = 244
SDLK_WORLD_85 = 245
SDLK_WORLD_86 = 246
SDLK_WORLD_87 = 247
SDLK_WORLD_88 = 248
SDLK_WORLD_89 = 249
SDLK_WORLD_90 = 250
SDLK_WORLD_91 = 251
SDLK_WORLD_92 = 252
SDLK_WORLD_93 = 253
SDLK_WORLD_94 = 254
SDLK_WORLD_95 = 255
SDLK_KP0 = 256
SDLK_KP1 = 257
SDLK_KP2 = 258
SDLK_KP3 = 259
SDLK_KP4 = 260
SDLK_KP5 = 261
SDLK_KP6 = 262
SDLK_KP7 = 263
SDLK_KP8 = 264
SDLK_KP9 = 265
SDLK_KP_PERIOD = 266
SDLK_KP_DIVIDE = 267
SDLK_KP_MULTIPLY = 268
SDLK_KP_MINUS = 269
SDLK_KP_PLUS = 270
SDLK_KP_ENTER = 271
SDLK_KP_EQUALS = 272
SDLK_UP = 273
SDLK_DOWN = 274
SDLK_RIGHT = 275
SDLK_LEFT = 276
SDLK_INSERT = 277
SDLK_HOME = 278
SDLK_END = 279
SDLK_PAGEUP = 280
SDLK_PAGEDOWN = 281
SDLK_F1 = 282
SDLK_F2 = 283
SDLK_F3 = 284
SDLK_F4 = 285
SDLK_F5 = 286
SDLK_F6 = 287
SDLK_F7 = 288
SDLK_F8 = 289
SDLK_F9 = 290
SDLK_F10 = 291
SDLK_F11 = 292
SDLK_F12 = 293
SDLK_F13 = 294
SDLK_F14 = 295
SDLK_F15 = 296
SDLK_NUMLOCK = 300
SDLK_CAPSLOCK = 301
SDLK_SCROLLOCK = 302
SDLK_RSHIFT = 303
SDLK_LSHIFT = 304
SDLK_RCTRL = 305
SDLK_LCTRL = 306
SDLK_RALT = 307
SDLK_LALT = 308
SDLK_RMETA = 309
SDLK_LMETA = 310
SDLK_LSUPER = 311
SDLK_RSUPER = 312
SDLK_MODE = 313
SDLK_COMPOSE = 314
SDLK_HELP = 315
SDLK_PRINT = 316
SDLK_SYSREQ = 317
SDLK_BREAK = 318
SDLK_MENU = 319
SDLK_POWER = 320
SDLK_EURO = 321
SDLK_UNDO = 322
SDLK_LAST = 323
SDLK_UNKNOWN = 0
SDLK_FIRST = 0
SDLK_BACKSPACE = 8
SDLK_TAB = 9
SDLK_CLEAR = 12
SDLK_RETURN = 13
SDLK_PAUSE = 19
SDLK_ESCAPE = 27
SDLK_SPACE = 32
SDLK_EXCLAIM = 33
SDLK_QUOTEDBL = 34
SDLK_HASH = 35
SDLK_DOLLAR = 36
SDLK_AMPERSAND = 38
SDLK_QUOTE = 39
SDLK_LEFTPAREN = 40
SDLK_RIGHTPAREN = 41
SDLK_ASTERISK = 42
SDLK_PLUS = 43
SDLK_COMMA = 44
SDLK_MINUS = 45
SDLK_PERIOD = 46
SDLK_SLASH = 47
SDLK_0 = 48
SDLK_1 = 49
SDLK_2 = 50
SDLK_3 = 51
SDLK_4 = 52
SDLK_5 = 53
SDLK_6 = 54
SDLK_7 = 55
SDLK_8 = 56
SDLK_9 = 57
SDLK_COLON = 58
SDLK_SEMICOLON = 59
SDLK_LESS = 60
SDLK_EQUALS = 61
SDLK_GREATER = 62
SDLK_QUESTION = 63
SDLK_AT = 64
SDLK_LEFTBRACKET = 91
SDLK_BACKSLASH = 92
SDLK_RIGHTBRACKET = 93
SDLK_CARET = 94
SDLK_UNDERSCORE = 95
SDLK_BACKQUOTE = 96
SDLK_a = 97
SDLK_b = 98
SDLK_c = 99
SDLK_d = 100
SDLK_e = 101
SDLK_f = 102
SDLK_g = 103
SDLK_h = 104
SDLK_i = 105
SDLK_j = 106
SDLK_k = 107
SDLK_l = 108
SDLK_m = 109
SDLK_n = 110
SDLK_o = 111
SDLK_p = 112
SDLK_q = 113
SDLK_r = 114
SDLK_s = 115
SDLK_t = 116
SDLK_u = 117
SDLK_v = 118
SDLK_w = 119
SDLK_x = 120
SDLK_y = 121
SDLK_z = 122
SDLK_DELETE = 127
SDLK_WORLD_0 = 160
SDLK_WORLD_1 = 161
SDLK_WORLD_2 = 162
SDLK_WORLD_3 = 163
SDLK_WORLD_4 = 164
SDLK_WORLD_5 = 165
SDLK_WORLD_6 = 166
SDLK_WORLD_7 = 167
SDLK_WORLD_8 = 168
SDLK_WORLD_9 = 169
SDLK_WORLD_10 = 170
SDLK_WORLD_11 = 171
SDLK_WORLD_12 = 172
SDLK_WORLD_13 = 173
SDLK_WORLD_14 = 174
SDLK_WORLD_15 = 175
SDLK_WORLD_16 = 176
SDLK_WORLD_17 = 177
SDLK_WORLD_18 = 178
SDLK_WORLD_19 = 179
SDLK_WORLD_20 = 180
SDLK_WORLD_21 = 181
SDLK_WORLD_22 = 182
SDLK_WORLD_23 = 183
SDLK_WORLD_24 = 184
SDLK_WORLD_25 = 185
SDLK_WORLD_26 = 186
SDLK_WORLD_27 = 187
SDLK_WORLD_28 = 188
SDLK_WORLD_29 = 189
SDLK_WORLD_30 = 190
SDLK_WORLD_31 = 191
SDLK_WORLD_32 = 192
SDLK_WORLD_33 = 193
SDLK_WORLD_34 = 194
SDLK_WORLD_35 = 195
SDLK_WORLD_36 = 196
SDLK_WORLD_37 = 197
SDLK_WORLD_38 = 198
SDLK_WORLD_39 = 199
SDLK_WORLD_40 = 200
SDLK_WORLD_41 = 201
SDLK_WORLD_42 = 202
SDLK_WORLD_43 = 203
SDLK_WORLD_44 = 204
SDLK_WORLD_45 = 205
SDLK_WORLD_46 = 206
SDLK_WORLD_47 = 207
SDLK_WORLD_48 = 208
SDLK_WORLD_49 = 209
SDLK_WORLD_50 = 210
SDLK_WORLD_51 = 211
SDLK_WORLD_52 = 212
SDLK_WORLD_53 = 213
SDLK_WORLD_54 = 214
SDLK_WORLD_55 = 215
SDLK_WORLD_56 = 216
SDLK_WORLD_57 = 217
SDLK_WORLD_58 = 218
SDLK_WORLD_59 = 219
SDLK_WORLD_60 = 220
SDLK_WORLD_61 = 221
SDLK_WORLD_62 = 222
SDLK_WORLD_63 = 223
SDLK_WORLD_64 = 224
SDLK_WORLD_65 = 225
SDLK_WORLD_66 = 226
SDLK_WORLD_67 = 227
SDLK_WORLD_68 = 228
SDLK_WORLD_69 = 229
SDLK_WORLD_70 = 230
SDLK_WORLD_71 = 231
SDLK_WORLD_72 = 232
SDLK_WORLD_73 = 233
SDLK_WORLD_74 = 234
SDLK_WORLD_75 = 235
SDLK_WORLD_76 = 236
SDLK_WORLD_77 = 237
SDLK_WORLD_78 = 238
SDLK_WORLD_79 = 239
SDLK_WORLD_80 = 240
SDLK_WORLD_81 = 241
SDLK_WORLD_82 = 242
SDLK_WORLD_83 = 243
SDLK_WORLD_84 = 244
SDLK_WORLD_85 = 245
SDLK_WORLD_86 = 246
SDLK_WORLD_87 = 247
SDLK_WORLD_88 = 248
SDLK_WORLD_89 = 249
SDLK_WORLD_90 = 250
SDLK_WORLD_91 = 251
SDLK_WORLD_92 = 252
SDLK_WORLD_93 = 253
SDLK_WORLD_94 = 254
SDLK_WORLD_95 = 255
SDLK_KP0 = 256
SDLK_KP1 = 257
SDLK_KP2 = 258
SDLK_KP3 = 259
SDLK_KP4 = 260
SDLK_KP5 = 261
SDLK_KP6 = 262
SDLK_KP7 = 263
SDLK_KP8 = 264
SDLK_KP9 = 265
SDLK_KP_PERIOD = 266
SDLK_KP_DIVIDE = 267
SDLK_KP_MULTIPLY = 268
SDLK_KP_MINUS = 269
SDLK_KP_PLUS = 270
SDLK_KP_ENTER = 271
SDLK_KP_EQUALS = 272
SDLK_UP = 273
SDLK_DOWN = 274
SDLK_RIGHT = 275
SDLK_LEFT = 276
SDLK_INSERT = 277
SDLK_HOME = 278
SDLK_END = 279
SDLK_PAGEUP = 280
SDLK_PAGEDOWN = 281
SDLK_F1 = 282
SDLK_F2 = 283
SDLK_F3 = 284
SDLK_F4 = 285
SDLK_F5 = 286
SDLK_F6 = 287
SDLK_F7 = 288
SDLK_F8 = 289
SDLK_F9 = 290
SDLK_F10 = 291
SDLK_F11 = 292
SDLK_F12 = 293
SDLK_F13 = 294
SDLK_F14 = 295
SDLK_F15 = 296
SDLK_NUMLOCK = 300
SDLK_CAPSLOCK = 301
SDLK_SCROLLOCK = 302
SDLK_RSHIFT = 303
SDLK_LSHIFT = 304
SDLK_RCTRL = 305
SDLK_LCTRL = 306
SDLK_RALT = 307
SDLK_LALT = 308
SDLK_RMETA = 309
SDLK_LMETA = 310
SDLK_LSUPER = 311
SDLK_RSUPER = 312
SDLK_MODE = 313
SDLK_COMPOSE = 314
SDLK_HELP = 315
SDLK_PRINT = 316
SDLK_SYSREQ = 317
SDLK_BREAK = 318
SDLK_MENU = 319
SDLK_POWER = 320
SDLK_EURO = 321
SDLK_UNDO = 322
SDLK_LAST = 323

View file

@ -22,6 +22,7 @@ from PyQt4.QtGui import QDialog, QTextCursor
from m64py.ui.logview_ui import Ui_LogView
class Log:
def __init__(self, out=None, logview=None):
self.out = out
@ -31,8 +32,9 @@ class Log:
if self.out:
self.out.write(msg)
if self.logview:
self.logview.emit(
SIGNAL("msg_written(PyQt_PyObject)"), msg)
self.logview.emit(SIGNAL(
"msg_written(PyQt_PyObject)"), msg)
class LogView(QDialog, Ui_LogView):
msg_written = pyqtSignal(str)
@ -41,13 +43,14 @@ class LogView(QDialog, Ui_LogView):
QDialog.__init__(self, parent)
self.setupUi(self)
self.textEdit.setReadOnly(True)
self.connect(self, SIGNAL("msg_written(PyQt_PyObject)"),
self.on_msg_written)
self.connect(self, SIGNAL(
"msg_written(PyQt_PyObject)"), self.on_msg_written)
def on_msg_written(self, msg):
self.textEdit.moveCursor(QTextCursor.End)
self.textEdit.insertPlainText(msg)
class Logger():
def __init__(self):
log_format = 'Frontend: %(levelname)s: %(message)s'

View file

@ -33,6 +33,7 @@ from m64py.frontend.glwidget import GLWidget
from m64py.ui.mainwindow_ui import Ui_MainWindow
from m64py.frontend.recentfiles import RecentFiles
class MainWindow(QMainWindow, Ui_MainWindow):
"""Frontend main window"""
@ -55,9 +56,9 @@ class MainWindow(QMainWindow, Ui_MainWindow):
logview.setParent(self)
logview.setWindowFlags(Qt.Dialog)
self.statusbarLabel = QLabel()
self.statusbarLabel.setIndent(2)
self.statusbar.addPermanentWidget(self.statusbarLabel, 1)
self.statusbar_label = QLabel()
self.statusbar_label.setIndent(2)
self.statusbar.addPermanentWidget(self.statusbar_label, 1)
self.update_status(self.tr(
"Welcome to M64Py version %s." % FRONTEND_VERSION))
@ -66,6 +67,10 @@ class MainWindow(QMainWindow, Ui_MainWindow):
SIZE_2X: self.action2X,
SIZE_3X: self.action3X}
self.slots = {}
self.view = None
self.stack = None
self.glwidget = None
self.cheats = None
self.maximized = False
self.widgets_height = None
@ -73,8 +78,8 @@ class MainWindow(QMainWindow, Ui_MainWindow):
self.settings = Settings(self)
self.worker = Worker(self)
self.vidext = bool(int(
self.settings.qset.value("enable_vidext", 1)))
self.vidext = bool(
int(self.settings.qset.value("enable_vidext", 1)))
self.create_state_slots()
self.create_widgets()
@ -174,24 +179,15 @@ class MainWindow(QMainWindow, Ui_MainWindow):
def connect_signals(self):
"""Connects signals."""
self.connect(self, SIGNAL("rom_opened()"),
self.on_rom_opened)
self.connect(self, SIGNAL("rom_closed()"),
self.on_rom_closed)
self.connect(self, SIGNAL("file_open(PyQt_PyObject, PyQt_PyObject)"),
self.file_open)
self.connect(self, SIGNAL("file_opening(PyQt_PyObject)"),
self.on_file_opening)
self.connect(self, SIGNAL("set_caption(PyQt_PyObject)"),
self.on_set_caption)
self.connect(self, SIGNAL("state_changed(PyQt_PyObject)"),
self.on_state_changed)
self.connect(self, SIGNAL("save_image(PyQt_PyObject)"),
self.on_save_image)
self.connect(self, SIGNAL("info_dialog(PyQt_PyObject)"),
self.on_info_dialog)
self.connect(self, SIGNAL("archive_dialog(PyQt_PyObject)"),
self.on_archive_dialog)
self.connect(self, SIGNAL("rom_opened()"), self.on_rom_opened)
self.connect(self, SIGNAL("rom_closed()"), self.on_rom_closed)
self.connect(self, SIGNAL("file_open(PyQt_PyObject, PyQt_PyObject)"), self.file_open)
self.connect(self, SIGNAL("file_opening(PyQt_PyObject)"), self.on_file_opening)
self.connect(self, SIGNAL("set_caption(PyQt_PyObject)"), self.on_set_caption)
self.connect(self, SIGNAL("state_changed(PyQt_PyObject)"), self.on_state_changed)
self.connect(self, SIGNAL("save_image(PyQt_PyObject)"), self.on_save_image)
self.connect(self, SIGNAL("info_dialog(PyQt_PyObject)"), self.on_info_dialog)
self.connect(self, SIGNAL("archive_dialog(PyQt_PyObject)"), self.on_archive_dialog)
def create_widgets(self):
"""Creates central widgets."""
@ -207,7 +203,6 @@ class MainWindow(QMainWindow, Ui_MainWindow):
def create_state_slots(self):
"""Creates state slot actions."""
self.slots = {}
group = QActionGroup(self)
group.setExclusive(True)
for slot in range(10):
@ -220,13 +215,12 @@ class MainWindow(QMainWindow, Ui_MainWindow):
self.slots[0].setChecked(True)
for slot, action in self.slots.items():
self.connect(action, SIGNAL("triggered()"),
lambda s=slot:self.worker.state_set_slot(s))
lambda s=slot: self.worker.state_set_slot(s))
def create_size_actions(self):
"""Creates window size actions."""
group = QActionGroup(self)
group.setExclusive(True)
size = self.settings.qset.value("size", SIZE_1X)
for num, size in enumerate(
sorted(self.sizes.keys()), 1):
width, height = size
@ -236,7 +230,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
action.setText("%dX" % num)
action.setToolTip("%sx%s" % (width, height))
self.connect(action, SIGNAL("triggered()"),
lambda w=w,h=h:self.resize(w, h))
lambda wi=w, he=h: self.resize(wi, he))
def file_open(self, filepath=None, filename=None):
"""Opens ROM file."""
@ -252,7 +246,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
def update_status(self, status):
"""Updates label in status bar."""
self.statusbarLabel.setText(status)
self.statusbar_label.setText(status)
def on_set_caption(self, title):
"""Sets window title."""
@ -284,7 +278,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
def on_state_changed(self, states):
"""Toggles actions state."""
load,pause,action,cheats = states
load, pause, action, cheats = states
self.menuLoad.setEnabled(load)
self.menuRecent.setEnabled(load)
self.menuStateSlot.setEnabled(load)
@ -370,9 +364,9 @@ class MainWindow(QMainWindow, Ui_MainWindow):
dialog = QFileDialog()
dialog.setFileMode(QFileDialog.ExistingFile)
file_path = dialog.getOpenFileName(
self, self.tr("Load State From File"),
os.path.join(self.worker.core.config.get_path("UserData"), "save"),
"M64P/PJ64 Saves (*.st* *.zip *.pj);;All files (*)")
self, self.tr("Load State From File"),
os.path.join(self.worker.core.config.get_path("UserData"), "save"),
"M64P/PJ64 Saves (*.st* *.zip *.pj);;All files (*)")
if file_path:
self.worker.state_load(file_path)
@ -381,10 +375,10 @@ class MainWindow(QMainWindow, Ui_MainWindow):
"""Saves state to file."""
dialog = QFileDialog()
file_path, file_filter = dialog.getSaveFileNameAndFilter(
self, self.tr("Save State To File"),
os.path.join(self.worker.core.config.get_path("UserData"), "save"),
";;".join([save_filter for save_filter, save_ext in M64P_SAVES.values()]),
M64P_SAVES[M64SAV_M64P][0])
self, self.tr("Save State To File"),
os.path.join(self.worker.core.config.get_path("UserData"), "save"),
";;".join([save_filter for save_filter, save_ext in M64P_SAVES.values()]),
M64P_SAVES[M64SAV_M64P][0])
if file_path:
for save_type, filters in M64P_SAVES.items():
save_filter, save_ext = filters
@ -485,6 +479,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
"""Shows log dialog."""
logview.show()
class View(QGraphicsView):
def __init__(self, parent=None):
QGraphicsView.__init__(self, parent)
@ -493,5 +488,4 @@ class View(QGraphicsView):
self.setStyleSheet("QGraphicsView {border:0px solid;margin:0px;}")
self.setResizeAnchor(QGraphicsView.AnchorViewCenter)
self.setScene(QGraphicsScene(self))
self.scene().addItem(
QGraphicsPixmapItem(QPixmap(":/images/front.png")))
self.scene().addItem(QGraphicsPixmapItem(QPixmap(":/images/front.png")))

View file

@ -21,12 +21,17 @@ from m64py.core.defs import *
from m64py.utils import format_label, format_options
from m64py.ui.plugin_ui import Ui_PluginDialog
class Plugin(QDialog, Ui_PluginDialog):
"""Plugin settings dialog"""
def __init__(self, parent):
QDialog.__init__(self, parent)
self.parent = parent
self.widgets = {}
self.items = None
self.config = None
self.section = None
self.setupUi(self)
def showEvent(self, event):
@ -61,7 +66,6 @@ class Plugin(QDialog, Ui_PluginDialog):
del item
def add_items(self):
self.widgets = {}
row1, row2 = 0, 0
for count, item in enumerate(self.items):
param_name, param_type = item
@ -73,7 +77,7 @@ class Plugin(QDialog, Ui_PluginDialog):
widget = QLineEdit()
widget.setToolTip(param_help)
self.gridLayout.addWidget(
QLabel(format_label(param_name)), row1, 1, Qt.AlignRight)
QLabel(format_label(param_name)), row1, 1, Qt.AlignRight)
self.gridLayout.addWidget(widget, row1, 2, Qt.AlignLeft)
self.widgets[param_name] = (widget, widget.__class__, opts)
elif param_type == M64TYPE_INT:
@ -94,14 +98,15 @@ class Plugin(QDialog, Ui_PluginDialog):
widget.addItem(value)
widget.setItemData(idx, data)
self.gridLayout.addWidget(
QLabel(format_label(param_name)), row1, 1, Qt.AlignRight)
QLabel(format_label(param_name)), row1, 1, Qt.AlignRight)
self.gridLayout.addWidget(widget, row1, 2, Qt.AlignLeft)
self.widgets[param_name] = (widget, widget.__class__, opts)
elif param_type == M64TYPE_BOOL:
row2 += 1
widget = QCheckBox()
widget.setText(format_label(param_name))
if param_help: widget.setToolTip(param_help)
if param_help:
widget.setToolTip(param_help)
self.gridLayout.addWidget(widget, row2, 3)
self.widgets[param_name] = (widget, widget.__class__, opts)

View file

@ -17,6 +17,7 @@
from PyQt4.QtGui import QAction, QIcon, QPixmap
from PyQt4.QtCore import QFileInfo, SIGNAL
class RecentFiles():
"""Keeps track of last opened files."""
@ -24,8 +25,9 @@ class RecentFiles():
"""Constructor"""
self.parent = parent
self.max_recent = 5
self.recent_actions = []
self.recent_files = []
self.recent_actions = []
self.action_clear_history = QAction(self.parent)
self.create()
self.update()
@ -36,19 +38,18 @@ class RecentFiles():
action.setIcon(QIcon(QPixmap(":/icons/action_rom.png")))
self.recent_actions.append(action)
self.recent_actions[i].setVisible(False)
self.parent.connect(self.recent_actions[i],
SIGNAL("triggered()"), self.parent.file_open)
self.parent.connect(
self.recent_actions[i], SIGNAL("triggered()"), self.parent.file_open)
self.parent.menuRecent.addAction(self.recent_actions[i])
self.parent.menuRecent.addSeparator()
self.actionClearHistory = QAction(self.parent)
self.actionClearHistory.setText("&Clear history")
self.actionClearHistory.setEnabled(False)
self.actionClearHistory.setVisible(True)
self.actionClearHistory.setIcon(
QIcon(QPixmap(":/icons/action_clear.png")))
self.parent.connect(self.actionClearHistory,
SIGNAL("triggered()"), self.clear)
self.parent.menuRecent.addAction(self.actionClearHistory)
self.action_clear_history.setText("&Clear history")
self.action_clear_history.setEnabled(False)
self.action_clear_history.setVisible(True)
self.action_clear_history.setIcon(
QIcon(QPixmap(":/icons/action_clear.png")))
self.parent.connect(
self.action_clear_history, SIGNAL("triggered()"), self.clear)
self.parent.menuRecent.addAction(self.action_clear_history)
def update(self):
"""Updates list of recent files."""
@ -63,7 +64,7 @@ class RecentFiles():
self.recent_files[i]).filePath())
for j in range(num_files, self.max_recent):
self.recent_actions[j].setVisible(False)
self.actionClearHistory.setEnabled((num_files > 0))
self.action_clear_history.setEnabled((num_files > 0))
def add(self, filepath):
"""Adds file to recent files list."""
@ -73,7 +74,7 @@ class RecentFiles():
while len(self.recent_files) > 5:
self.recent_files.pop(len(self.recent_files) - 1)
self.parent.settings.qset.setValue(
"recent_files", self.recent_files)
"recent_files", self.recent_files)
self.update()
def clear(self):

View file

@ -20,6 +20,7 @@ from PyQt4.QtGui import QMessageBox
from m64py.utils import sl
class RomInfo():
"""ROM information dialog"""
@ -27,16 +28,16 @@ class RomInfo():
self.parent = parent
self.core = self.parent.worker.core
rom_info = [
('GoodName', self.core.rom_settings.goodname),
('Name', self.core.rom_header.Name),
('MD5', self.core.rom_settings.MD5),
('CRC1', '%x' % sl(self.core.rom_header.CRC1)),
('CRC2', '%x' % sl(self.core.rom_header.CRC2)),
('Type', self.core.rom_type),
('Size', self.get_rom_size()),
('Country', self.get_country_name()),
('Manufacturer', self.get_manufacturer())
]
('GoodName', self.core.rom_settings.goodname),
('Name', self.core.rom_header.Name),
('MD5', self.core.rom_settings.MD5),
('CRC1', '%x' % sl(self.core.rom_header.CRC1)),
('CRC2', '%x' % sl(self.core.rom_header.CRC2)),
('Type', self.core.rom_type),
('Size', self.get_rom_size()),
('Country', self.get_country_name()),
('Manufacturer', self.get_manufacturer())
]
info = os.linesep.join([k+': '+str(v) for k, v in rom_info if str(v)])
QMessageBox.information(self.parent, 'ROM Information', info)
@ -72,7 +73,7 @@ class RomInfo():
elif code in [int(0x55), int(0x59)]:
name = 'Australia'
elif code in [int(0x50), int(0x58), int(0x20),
int(0x21), int(0x38), int(0x70)]:
int(0x21), int(0x38), int(0x70)]:
name = 'Europe'
else:
name = 'Unknown 0x%x' % code

View file

@ -29,11 +29,10 @@ from m64py.ui.romlist_ui import Ui_ROMList
try:
from m64py.ui import title_rc
from m64py.ui import snapshot_rc
bool(title_rc)
bool(snapshot_rc)
except ImportError:
pass
class ROMList(QMainWindow, Ui_ROMList):
"""ROM list window"""
@ -46,6 +45,11 @@ class ROMList(QMainWindow, Ui_ROMList):
self.setAttribute(Qt.WA_DeleteOnClose, True)
self.qset = self.parent.settings.qset
self.romlist = {}
self.title_item = None
self.snapshot_item = None
self.roms = self.qset.value("rom_list", [])
rect = self.frameGeometry()
rect.moveCenter(QDesktopWidget().availableGeometry().center())
self.move(rect.topLeft())
@ -70,7 +74,6 @@ class ROMList(QMainWindow, Ui_ROMList):
def init(self):
self.read_rom_list()
self.roms = self.qset.value("rom_list", [])
if bool(int(self.qset.value("show_available", 0))):
self.add_available_items(self.roms)
else:
@ -78,29 +81,20 @@ class ROMList(QMainWindow, Ui_ROMList):
def connect_signals(self):
"""Connects signals."""
self.listWidget.currentItemChanged.connect(
self.on_item_changed)
self.listWidget.itemDoubleClicked.connect(
self.on_item_activated)
self.listWidget.itemActivated.connect(
self.on_item_activated)
self.checkAvailable.clicked.connect(
self.on_available_clicked)
self.progressBar.valueChanged.connect(
self.on_progress_bar_changed)
self.pushRefresh.clicked.connect(
self.refresh_items)
self.pushOpen.clicked.connect(
self.on_item_open)
self.connect(self.reader, SIGNAL("finished()"),
self.add_available_items)
self.listWidget.currentItemChanged.connect(self.on_item_changed)
self.listWidget.itemDoubleClicked.connect(self.on_item_activated)
self.listWidget.itemActivated.connect(self.on_item_activated)
self.checkAvailable.clicked.connect(self.on_available_clicked)
self.progressBar.valueChanged.connect(self.on_progress_bar_changed)
self.pushRefresh.clicked.connect(self.refresh_items)
self.pushOpen.clicked.connect(self.on_item_open)
self.connect(self.reader, SIGNAL("finished()"), self.add_available_items)
def read_rom_list(self):
"""Reads ROM list from ini file."""
inifile = os.path.join(self.shared_data_path, "mupen64plus.ini")
self.parser.read(inifile)
sections = self.parser.sections()
self.romlist = {}
for section in sections:
items = self.parser.items(section)
self.romlist[section] = dict(items)
@ -180,7 +174,8 @@ class ROMList(QMainWindow, Ui_ROMList):
self.file_open(path, fname)
def on_item_changed(self, current, previous):
if not current: return
if not current:
return
md5, path, fname = current.data(Qt.UserRole)
title = QPixmap(os.path.join(
@ -197,20 +192,20 @@ class ROMList(QMainWindow, Ui_ROMList):
snapshot = QPixmap(":/images/default.png")
if previous is not None:
self.titleView.scene().removeItem(self.titleItem)
self.snapshotView.scene().removeItem(self.snapshotItem)
self.titleView.scene().removeItem(self.title_item)
self.snapshotView.scene().removeItem(self.snapshot_item)
title_pixmap = title.scaled(self.titleView.size(),
Qt.KeepAspectRatio, Qt.SmoothTransformation)
snapshot_pixmap = snapshot.scaled(self.snapshotView.size(),
Qt.KeepAspectRatio, Qt.SmoothTransformation)
title_pixmap = title.scaled(
self.titleView.size(), Qt.KeepAspectRatio, Qt.SmoothTransformation)
snapshot_pixmap = snapshot.scaled(
self.snapshotView.size(), Qt.KeepAspectRatio, Qt.SmoothTransformation)
titleItem = QGraphicsPixmapItem(title_pixmap)
snapshotItem = QGraphicsPixmapItem(snapshot_pixmap)
self.titleView.scene().addItem(titleItem)
self.snapshotView.scene().addItem(snapshotItem)
self.titleItem = titleItem
self.snapshotItem = snapshotItem
title_item = QGraphicsPixmapItem(title_pixmap)
snapshot_item = QGraphicsPixmapItem(snapshot_pixmap)
self.titleView.scene().addItem(title_item)
self.snapshotView.scene().addItem(snapshot_item)
self.title_item = title_item
self.snapshot_item = snapshot_item
def on_available_clicked(self):
is_checked = self.checkAvailable.isChecked()
@ -224,6 +219,7 @@ class ROMList(QMainWindow, Ui_ROMList):
self.reader.stop()
self.add_items()
class ROMReader(QThread):
"""ROM reader thread"""
@ -269,8 +265,7 @@ class ROMReader(QThread):
log.warn(str(err))
continue
percent = float(filenum) / float(num_files) * 100
self.parent.progressBar.emit(
SIGNAL("valueChanged(int)"), percent)
self.parent.progressBar.emit(SIGNAL("valueChanged(int)"), percent)
self.exit()
def stop(self):

View file

@ -28,6 +28,7 @@ from m64py.frontend.plugin import Plugin
from m64py.frontend.input import Input
from m64py.ui.settings_ui import Ui_Settings
class Settings(QDialog, Ui_Settings):
"""Settings dialog"""
@ -37,6 +38,8 @@ class Settings(QDialog, Ui_Settings):
self.setupUi(self)
self.core = None
self.plugins = []
self.emumode = []
self.combomap = {}
self.qset = QSettings("m64py", "m64py")
self.input = Input(self.parent)
self.add_items()
@ -50,23 +53,25 @@ class Settings(QDialog, Ui_Settings):
def add_items(self):
self.combomap = {
M64PLUGIN_RSP: (
self.comboRSP, self.pushButtonRSP,
Plugin(self.parent)),
M64PLUGIN_GFX: (
self.comboVideo, self.pushButtonVideo,
Plugin(self.parent)),
M64PLUGIN_AUDIO: (
self.comboAudio, self.pushButtonAudio,
Plugin(self.parent)),
M64PLUGIN_INPUT: (
self.comboInput, self.pushButtonInput,
self.input)}
M64PLUGIN_RSP: (
self.comboRSP, self.pushButtonRSP,
Plugin(self.parent)),
M64PLUGIN_GFX: (
self.comboVideo, self.pushButtonVideo,
Plugin(self.parent)),
M64PLUGIN_AUDIO: (
self.comboAudio, self.pushButtonAudio,
Plugin(self.parent)),
M64PLUGIN_INPUT: (
self.comboInput, self.pushButtonInput,
self.input)
}
self.emumode = [
QRadioButton(self.tr("Pure Interpreter")),
QRadioButton(self.tr("Cached Interpreter")),
QRadioButton(self.tr("Dynamic Recompiler"))]
QRadioButton(self.tr("Pure Interpreter")),
QRadioButton(self.tr("Cached Interpreter")),
QRadioButton(self.tr("Dynamic Recompiler"))
]
vbox = QVBoxLayout(self.groupEmuMode)
for widget in self.emumode:
@ -94,22 +99,22 @@ class Settings(QDialog, Ui_Settings):
def connect_signals(self):
self.browseLibrary.clicked.connect(lambda: self.browse_dialog(
(self.pathLibrary, self.groupLibrary, False)))
(self.pathLibrary, self.groupLibrary, False)))
self.browsePlugins.clicked.connect(lambda: self.browse_dialog(
(self.pathPlugins, self.groupPlugins, True)))
(self.pathPlugins, self.groupPlugins, True)))
self.browseData.clicked.connect(lambda: self.browse_dialog(
(self.pathData, self.groupData, True)))
(self.pathData, self.groupData, True)))
self.browseROM.clicked.connect(lambda: self.browse_dialog(
(self.pathROM, self.groupROM, True)))
(self.pathROM, self.groupROM, True)))
for plugin_type in self.combomap:
self.connect_combo_signals(self.combomap[plugin_type])
def connect_combo_signals(self, combomap):
combo,button,settings = combomap
combo, button, settings = combomap
if settings is not None:
if combo != self.comboInput:
combo.activated.connect(
lambda: self.set_section(combo,button,settings))
lambda: self.set_section(combo, button, settings))
button.clicked.connect(settings.show_dialog)
def browse_dialog(self, args):
@ -118,12 +123,12 @@ class Settings(QDialog, Ui_Settings):
if directory:
dialog.setFileMode(QFileDialog.Directory)
path = dialog.getExistingDirectory(
self, groupbox.title(), "", QFileDialog.ShowDirsOnly)
self, groupbox.title(), "", QFileDialog.ShowDirsOnly)
else:
dialog.setFileMode(QFileDialog.ExistingFile)
path = dialog.getOpenFileName(
self, groupbox.title(), "",
"%s (*%s);;All files (*)" % (groupbox.title(), DLL_FILTER))
self, groupbox.title(), "",
"%s (*%s);;All files (*)" % (groupbox.title(), DLL_FILTER))
if not path: return
widget.setText(path)
@ -151,7 +156,7 @@ class Settings(QDialog, Ui_Settings):
desc = combo.itemData(index)
name = os.path.splitext(plugin)[0][12:]
section = "-".join([n.capitalize() for n in name.split("-")[0:2]])
return (section, desc)
return section, desc
def set_section(self, combo, button, settings):
if settings:
@ -160,7 +165,7 @@ class Settings(QDialog, Ui_Settings):
settings.set_section(section, desc)
self.core.config.open_section(section)
items = self.core.config.parameters[
self.core.config.section].items()
self.core.config.section].items()
if items:
button.setEnabled(True)
else:
@ -171,10 +176,10 @@ class Settings(QDialog, Ui_Settings):
button.setEnabled(False)
def set_paths(self):
path_library = self.qset.value("Paths/Library",
find_library(CORE_NAME))
path_data = self.qset.value("Paths/Data",
self.core.config.get_path("SharedData"))
path_library = self.qset.value(
"Paths/Library", find_library(CORE_NAME))
path_data = self.qset.value(
"Paths/Data", self.core.config.get_path("SharedData"))
path_roms = self.qset.value("Paths/ROM")
try:
@ -197,22 +202,22 @@ class Settings(QDialog, Ui_Settings):
for mode in MODES:
width, height = mode
self.comboResolution.addItem(
"%sx%s" % (width, height), (width, height))
"%sx%s" % (width, height), (width, height))
self.comboResolution.setCurrentIndex(0)
self.comboResolution.setEnabled(not self.parent.vidext)
self.core.config.open_section("Video-General")
width = self.core.config.get_parameter("ScreenWidth")
height = self.core.config.get_parameter("ScreenHeight")
index = self.comboResolution.findText(
"%sx%s" % (width, height))
"%sx%s" % (width, height))
if index == -1: index = 0
self.comboResolution.setCurrentIndex(index)
self.checkEnableVidExt.setChecked(
bool(int(self.qset.value("enable_vidext", 1))))
bool(int(self.qset.value("enable_vidext", 1))))
self.checkFullscreen.setChecked(
bool(self.core.config.get_parameter("Fullscreen")))
bool(self.core.config.get_parameter("Fullscreen")))
self.checkFullscreen.setEnabled(not self.parent.vidext)
if sys.platform == "win32":
@ -230,34 +235,34 @@ class Settings(QDialog, Ui_Settings):
mode = self.core.config.get_parameter("R4300Emulator")
self.emumode[mode].setChecked(True)
self.checkOSD.setChecked(
self.core.config.get_parameter("OnScreenDisplay"))
self.core.config.get_parameter("OnScreenDisplay"))
self.checkOSD.setToolTip(
self.core.config.get_parameter_help("OnScreenDisplay"))
self.core.config.get_parameter_help("OnScreenDisplay"))
self.checkNoCompiledJump.setChecked(
self.core.config.get_parameter("NoCompiledJump"))
self.core.config.get_parameter("NoCompiledJump"))
self.checkNoCompiledJump.setToolTip(
self.core.config.get_parameter_help("NoCompiledJump"))
self.core.config.get_parameter_help("NoCompiledJump"))
self.checkDisableExtraMem.setChecked(
self.core.config.get_parameter("DisableExtraMem"))
self.core.config.get_parameter("DisableExtraMem"))
self.checkDisableExtraMem.setToolTip(
self.core.config.get_parameter_help("DisableExtraMem"))
self.core.config.get_parameter_help("DisableExtraMem"))
self.checkDelaySI.setChecked(
self.core.config.get_parameter("DelaySI"))
self.core.config.get_parameter("DelaySI"))
self.checkDelaySI.setToolTip(
self.core.config.get_parameter_help("DelaySI"))
self.core.config.get_parameter_help("DelaySI"))
self.comboCountPerOp.setCurrentIndex(
self.core.config.get_parameter("CountPerOp"))
self.core.config.get_parameter("CountPerOp"))
self.comboCountPerOp.setToolTip(
self.core.config.get_parameter_help("CountPerOp"))
self.core.config.get_parameter_help("CountPerOp"))
def set_plugins(self):
plugin_map = self.core.plugin_map
for plugin_type in self.combomap:
combo,button,settings = self.combomap[plugin_type]
combo, button, settings = self.combomap[plugin_type]
combo.clear()
for plugin in plugin_map[plugin_type].values():
(plugin_handle, plugin_path, plugin_name,
plugin_desc, plugin_version) = plugin
plugin_desc, plugin_version) = plugin
name = os.path.basename(plugin_path)
combo.addItem(name)
index = combo.findText(str(name))
@ -266,19 +271,16 @@ class Settings(QDialog, Ui_Settings):
current = self.qset.value("Plugins/%s" % (
PLUGIN_NAME[plugin_type]), PLUGIN_DEFAULT[plugin_type])
index = combo.findText(current)
if index == -1: index = 0
if index == -1:
index = 0
combo.setCurrentIndex(index)
self.set_section(combo, button, settings)
def save_paths(self):
self.qset.setValue("Paths/Library",
self.pathLibrary.text())
self.qset.setValue("Paths/Plugins",
self.pathPlugins.text())
self.qset.setValue("Paths/Data",
self.pathData.text())
self.qset.setValue("Paths/ROM",
self.pathROM.text())
self.qset.setValue("Paths/Library", self.pathLibrary.text())
self.qset.setValue("Paths/Plugins", self.pathPlugins.text())
self.qset.setValue("Paths/Data", self.pathData.text())
self.qset.setValue("Paths/ROM", self.pathROM.text())
def save_video(self):
if not self.parent.vidext:
@ -294,24 +296,15 @@ class Settings(QDialog, Ui_Settings):
def save_core(self):
self.core.config.open_section("Core")
emumode = [n for n,m in enumerate(self.emumode) if m.isChecked()][0]
self.core.config.set_parameter("R4300Emulator",
emumode)
self.core.config.set_parameter("OnScreenDisplay",
self.checkOSD.isChecked())
self.core.config.set_parameter("NoCompiledJump",
self.checkNoCompiledJump.isChecked())
self.core.config.set_parameter("DisableExtraMem",
self.checkDisableExtraMem.isChecked())
self.core.config.set_parameter("DelaySI",
self.checkDelaySI.isChecked())
self.core.config.set_parameter("CountPerOp",
self.comboCountPerOp.currentIndex())
self.core.config.set_parameter("SharedDataPath",
self.pathData.text())
self.core.config.set_parameter("R4300Emulator", emumode)
self.core.config.set_parameter("OnScreenDisplay", self.checkOSD.isChecked())
self.core.config.set_parameter("NoCompiledJump", self.checkNoCompiledJump.isChecked())
self.core.config.set_parameter("DisableExtraMem", self.checkDisableExtraMem.isChecked())
self.core.config.set_parameter("DelaySI", self.checkDelaySI.isChecked())
self.core.config.set_parameter("CountPerOp", self.comboCountPerOp.currentIndex())
self.core.config.set_parameter("SharedDataPath", self.pathData.text())
def save_plugins(self):
for plugin_type in self.combomap:
combo,button,settings = self.combomap[plugin_type]
self.qset.setValue("Plugins/%s" %
PLUGIN_NAME[plugin_type],
combo.currentText())
combo, button, settings = self.combomap[plugin_type]
self.qset.setValue("Plugins/%s" % PLUGIN_NAME[plugin_type], combo.currentText())

View file

@ -29,6 +29,7 @@ from m64py.core.vidext import video
from m64py.archive import Archive
from m64py.platform import DLL_EXT, DEFAULT_DYNLIB, SEARCH_DIRS
class Worker(QThread):
"""Mupen64Plus thread worker"""
@ -38,6 +39,9 @@ class Worker(QThread):
self.parent = parent
self.video = video
self.plugin_files = []
self.archive = None
self.filepath = None
self.filename = None
self.library_path = None
self.state = M64EMU_STOPPED
self.settings = self.parent.settings
@ -53,13 +57,13 @@ class Worker(QThread):
self.parent.settings.core = self.core
if self.parent.args:
self.parent.emit(SIGNAL("file_open(PyQt_PyObject, PyQt_PyObject)"),
self.parent.args[0], None)
self.parent.emit(SIGNAL(
"file_open(PyQt_PyObject, PyQt_PyObject)"), self.parent.args[0], None)
else:
self.parent.emit(SIGNAL("state_changed(PyQt_PyObject)"),
(False, False, False, False))
self.parent.emit(SIGNAL("info_dialog(PyQt_PyObject)"),
self.tr("Mupen64Plus library not found."))
self.parent.emit(SIGNAL(
"state_changed(PyQt_PyObject)"), (False, False, False, False))
self.parent.emit(SIGNAL(
"info_dialog(PyQt_PyObject)"), self.tr("Mupen64Plus library not found."))
def quit(self):
if self.state in [M64EMU_RUNNING, M64EMU_PAUSED]:
@ -87,7 +91,7 @@ class Worker(QThread):
self.library_path = path
else:
self.library_path = self.settings.qset.value(
"Paths/Library", find_library(CORE_NAME))
"Paths/Library", find_library(CORE_NAME))
self.core.core_load(str(self.library_path))
def core_unload(self):
@ -101,7 +105,7 @@ class Worker(QThread):
"""Startups core library."""
if self.core.get_handle():
self.core.core_startup(
str(self.library_path), self.parent.vidext)
str(self.library_path), self.parent.vidext)
def core_shutdown(self):
@ -142,7 +146,7 @@ class Worker(QThread):
for plugin_type in self.core.plugin_map.keys():
for plugin_map in self.core.plugin_map[plugin_type].values():
(plugin_handle, plugin_path, plugin_name,
plugin_desc, plugin_version) = plugin_map
plugin_desc, plugin_version) = plugin_map
unload_library(plugin_handle)
del plugin_handle
@ -151,7 +155,7 @@ class Worker(QThread):
for plugin_type in self.core.plugin_map.keys():
for plugin_map in self.core.plugin_map[plugin_type].values():
(plugin_handle, plugin_path, plugin_name,
plugin_desc, plugin_version) = plugin_map
plugin_desc, plugin_version) = plugin_map
self.core.plugin_startup(plugin_handle, plugin_name, plugin_desc)
def plugins_shutdown(self):
@ -159,7 +163,7 @@ class Worker(QThread):
for plugin_type in self.core.plugin_map.keys():
for plugin_map in self.core.plugin_map[plugin_type].values():
(plugin_handle, plugin_path, plugin_name,
plugin_desc, plugin_version) = plugin_map
plugin_desc, plugin_version) = plugin_map
self.core.plugin_shutdown(plugin_handle, plugin_desc)
def rom_open(self):
@ -180,7 +184,7 @@ class Worker(QThread):
self.core.rom_get_header()
self.core.rom_get_settings()
if bool(int(self.settings.qset.value(
"disable_screensaver", 1))):
"disable_screensaver", 1))):
screensaver.disable()
self.parent.emit(SIGNAL("rom_opened()"))
self.parent.recent_files.add(self.filepath)
@ -189,7 +193,7 @@ class Worker(QThread):
"""Closes ROM."""
self.core.rom_close()
if bool(int(self.settings.qset.value(
"disable_screensaver", 1))):
"disable_screensaver", 1))):
screensaver.enable()
self.parent.emit(SIGNAL("rom_closed()"))
@ -208,7 +212,7 @@ class Worker(QThread):
def get_screenshot(self, path):
"""Gets last saved screenshot."""
rom_name = str(self.core.rom_header.Name).replace(
' ', '_').lower()
' ', '_').lower()
screenshots = []
for filename in os.listdir(path):
if filename.startswith(rom_name):
@ -226,15 +230,14 @@ class Worker(QThread):
if not os.path.isdir(dst_path):
os.makedirs(dst_path)
screenshot = self.get_screenshot(
os.path.join(data_path, "screenshot"))
os.path.join(data_path, "screenshot"))
if screenshot:
image_name = "%s.png" % self.core.rom_settings.MD5
try:
shutil.copyfile(screenshot,
os.path.join(dst_path, image_name))
shutil.copyfile(screenshot, os.path.join(dst_path, image_name))
log.info("Captured %s" % capture)
except IOError:
log.exception("couldn't save image %s" % image)
log.exception("couldn't save image %s" % image_name)
def save_title(self):
"""Saves title."""
@ -309,12 +312,12 @@ class Worker(QThread):
if self.state == M64EMU_RUNNING:
self.core.pause()
if bool(int(self.settings.qset.value(
"disable_screensaver", 1))):
"disable_screensaver", 1))):
screensaver.enable()
elif self.state == M64EMU_PAUSED:
self.core.resume()
if bool(int(self.settings.qset.value(
"disable_screensaver", 1))):
"disable_screensaver", 1))):
screensaver.disable()
self.toggle_actions()
@ -339,13 +342,13 @@ class Worker(QThread):
self.state = self.core_state_query(M64CORE_EMU_STATE)
cheat = bool(self.parent.cheats.cheats) if self.parent.cheats else False
if self.state == M64EMU_STOPPED:
(load,pause,action,cheats) = True,False,False,False
(load, pause, action, cheats) = True, False, False, False
elif self.state == M64EMU_PAUSED:
(load,pause,action,cheats) = True,True,True,cheat
(load, pause, action, cheats) = True, True, True, cheat
elif self.state == M64EMU_RUNNING:
(load,pause,action,cheats) = True,True,True,cheat
(load, pause, action, cheats) = True, True, True, cheat
self.parent.emit(SIGNAL(
"state_changed(PyQt_PyObject)"), (load,pause,action,cheats))
"state_changed(PyQt_PyObject)"), (load, pause, action, cheats))
def stop(self):
"""Stops thread."""
@ -356,7 +359,7 @@ class Worker(QThread):
"""Starts thread."""
self.rom_open()
self.core.attach_plugins(
self.get_plugins())
self.get_plugins())
self.core.execute()
self.core.detach_plugins()
self.rom_close()

View file

@ -51,9 +51,10 @@ def _environ_path(name):
else:
return []
class LibraryLoader(object):
def __init__(self):
self.other_dirs=[]
self.other_dirs = []
def find_library(self, libname):
paths = self.getpaths(libname)
@ -82,7 +83,7 @@ class LibraryLoader(object):
return ctypes.CDLL(path, ctypes.RTLD_GLOBAL)
else:
return ctypes.cdll.LoadLibrary(path)
except OSError,e:
except OSError, e:
raise ImportError(e)
def getpaths(self, libname):
@ -102,7 +103,7 @@ class LibraryLoader(object):
class DarwinLibraryLoader(LibraryLoader):
name_formats = ["lib%s.dylib", "lib%s.so", "lib%s.bundle",
"%s.dylib", "%s.framework", "%s.so", "%s.bundle", "%s"]
"%s.dylib", "%s.framework", "%s.so", "%s.bundle", "%s"]
def find_library(self, libname):
paths = self.getpaths(libname)
@ -126,7 +127,7 @@ class DarwinLibraryLoader(LibraryLoader):
if os.path.pathsep in libname:
names = [libname]
else:
names = [format % libname for format in self.name_formats]
names = [f % libname for f in self.name_formats]
for dirname in self.getdirs(libname):
for name in names:
@ -180,10 +181,10 @@ class PosixLibraryLoader(LibraryLoader):
directories = []
for name in ("LD_LIBRARY_PATH",
"SHLIB_PATH", # HPUX
"LIBPATH", # OS/2, AIX
"LIBRARY_PATH", # BE/OS
):
"SHLIB_PATH", # HPUX
"LIBPATH", # OS/2, AIX
"LIBRARY_PATH", # BE/OS
):
if name in os.environ:
directories.extend(os.environ[name].split(os.pathsep))
directories.extend(self.other_dirs)
@ -194,23 +195,23 @@ class PosixLibraryLoader(LibraryLoader):
except IOError:
pass
directories.extend(['/lib', '/usr/lib', '/lib64',
'/usr/lib64', '/usr/games/lib', '/usr/games/lib64',
'/usr/lib/x86_64-linux-gnu', '/usr/lib/i386-linux-gnu'])
directories.extend(['/lib', '/usr/lib', '/lib64', '/usr/lib64',
'/usr/games/lib', '/usr/games/lib64',
'/usr/lib/x86_64-linux-gnu', '/usr/lib/i386-linux-gnu'])
cache = {}
lib_re = re.compile(r'lib(.*)\.s[ol]')
for dir in directories:
for d in directories:
try:
for path in glob.glob("%s/*.s[ol]*" % dir):
file = os.path.basename(path)
for path in glob.glob("%s/*.s[ol]*" % d):
f = os.path.basename(path)
# Index by filename
if file not in cache:
cache[file] = path
if f not in cache:
cache[f] = path
# Index by library name
match = lib_re.match(file)
match = lib_re.match(f)
if match:
library = match.group(1)
if library not in cache:
@ -225,10 +226,13 @@ class PosixLibraryLoader(LibraryLoader):
self._create_ld_so_cache()
result = self._ld_so_cache.get(libname)
if result: yield result
if result:
yield result
path = ctypes.util.find_library(libname)
if path: yield os.path.join("/lib",path)
if path:
yield os.path.join("/lib", path)
class _WindowsLibrary(object):
def __init__(self, path):
@ -244,9 +248,11 @@ class _WindowsLibrary(object):
self.windll = ctypes.windll.LoadLibrary(path)
def __getattr__(self, name):
try: return getattr(self.cdll,name)
try:
return getattr(self.cdll, name)
except AttributeError:
try: return getattr(self.windll,name)
try:
return getattr(self.windll, name)
except AttributeError:
raise

View file

@ -23,24 +23,24 @@ if sys.platform.startswith("linux"):
DLL_FILTER = ".so.2"
DEFAULT_DYNLIB = "libmupen64plus.so.2"
SEARCH_DIRS = [
"/usr/local/lib/mupen64plus",
"/usr/lib/mupen64plus",
"/usr/games/lib64/mupen64plus",
"/usr/games/lib/mupen64plus",
"/usr/lib/x86_64-linux-gnu/mupen64plus",
"/usr/lib/i386-linux-gnu/mupen64plus",
"."
]
"/usr/local/lib/mupen64plus",
"/usr/lib/mupen64plus",
"/usr/games/lib64/mupen64plus",
"/usr/games/lib/mupen64plus",
"/usr/lib/x86_64-linux-gnu/mupen64plus",
"/usr/lib/i386-linux-gnu/mupen64plus",
"."
]
elif sys.platform == "darwin":
LDD_CMD = "otool -L %s | grep -q SDL2"
DLL_EXT = ".dylib"
DLL_FILTER = ".dylib"
DEFAULT_DYNLIB = "libmupen64plus.dylib"
SEARCH_DIRS = [
"/usr/local/lib/mupen64plus",
"/usr/lib/mupen64plus",
"."
]
"/usr/local/lib/mupen64plus",
"/usr/lib/mupen64plus",
"."
]
elif sys.platform == "win32":
LDD_CMD = ""
DLL_EXT = ".dll"

View file

@ -20,6 +20,7 @@ import subprocess
from m64py.frontend.log import log
class LinuxScreenSaver:
cookie = None
screensaver = None
@ -28,14 +29,15 @@ class LinuxScreenSaver:
try:
import dbus
self.screensaver = dbus.SessionBus().get_object(
"org.freedesktop.ScreenSaver", "/ScreenSaver")
"org.freedesktop.ScreenSaver", "/ScreenSaver")
except Exception, err:
log.info("ScreenSaver not available: %s" % str(err))
def disable(self):
if self.screensaver:
try:
self.cookie = self.screensaver.Inhibit("M64Py", "Emulation started")
self.cookie = self.screensaver.Inhibit(
"M64Py", "Emulation started")
log.info("ScreenSaver disabled")
except Exception, err:
log.exception(str(err))
@ -49,27 +51,29 @@ class LinuxScreenSaver:
except Exception, err:
log.exception(str(err))
class DarwinScreenSaver:
def __init__(self):
try:
self.idle_time = subprocess.check_output(
"defaults -currentHost read com.apple.screensaver idleTime",
shell=True).strip()
"defaults -currentHost read com.apple.screensaver idleTime",
shell=True).strip()
except subprocess.CalledProcessError:
self.idle_time = 0
def disable(self):
subprocess.call(
"defaults -currentHost write com.apple.screensaver idleTime 0",
shell=True)
"defaults -currentHost write com.apple.screensaver idleTime 0",
shell=True)
log.info("ScreenSaver disabled")
def enable(self):
subprocess.call(
"defaults -currentHost write com.apple.screensaver idleTime %s" % self.idle_time,
shell=True)
"defaults -currentHost write com.apple.screensaver idleTime %s" % self.idle_time,
shell=True)
log.info("ScreenSaver enabled")
class WindowsScreenSaver:
sys_param_info = None
SPI_SETSCREENSAVEACTIVE = 17

View file

@ -27,8 +27,8 @@ class ImageView(QGraphicsView):
size = event.size()
for item in self.scene().items():
pixmap = item.pixmap()
pixmap = pixmap.scaled(size,
Qt.KeepAspectRatio, Qt.SmoothTransformation)
pixmap = pixmap.scaled(
size, Qt.KeepAspectRatio, Qt.SmoothTransformation)
item.setPixmap(pixmap)
self.ensureVisible(item)
self.centerOn(item)

View file

@ -31,6 +31,8 @@ class InputButton(QPushButton):
QPushButton.__init__(self, parent)
self.key = None
self.parent = parent
self.input = None
self.joystick = None
self.setFocusPolicy(Qt.ClickFocus)
def showEvent(self, event):
@ -46,14 +48,14 @@ class InputButton(QPushButton):
def connect_signals(self):
self.connect(self.joystick,
SIGNAL("axis_value_changed(PyQt_PyObject, PyQt_PyObject)"),
self.on_axis_value_changed)
SIGNAL("axis_value_changed(PyQt_PyObject, PyQt_PyObject)"),
self.on_axis_value_changed)
self.connect(self.joystick,
SIGNAL("button_value_changed(PyQt_PyObject, PyQt_PyObject)"),
self.on_button_value_changed)
SIGNAL("button_value_changed(PyQt_PyObject, PyQt_PyObject)"),
self.on_button_value_changed)
self.connect(self.joystick,
SIGNAL("hat_value_changed(PyQt_PyObject, PyQt_PyObject)"),
self.on_hat_value_changed)
SIGNAL("hat_value_changed(PyQt_PyObject, PyQt_PyObject)"),
self.on_hat_value_changed)
def keyPressEvent(self, event):
modifier = event.modifiers()
@ -88,7 +90,7 @@ class InputButton(QPushButton):
self.setText(self.tr("Press Key"))
self.setCheckable(True)
self.window().statusLabel.setText(
self.tr("Press <em>Escape</em> to cancel, <em>Backspace</em> to delete."))
self.tr("Press <em>Escape</em> to cancel, <em>Backspace</em> to delete."))
def focusOutEvent(self, event):
if self.input.is_joystick:

View file

@ -17,6 +17,7 @@ import os
import re
from hashlib import md5
def md5sum(filename=None, filedata=None, buf_size=8192):
m = md5()
if filename:
@ -31,6 +32,7 @@ def md5sum(filename=None, filedata=None, buf_size=8192):
m.update(data)
return m.hexdigest()
def which(prog):
def is_exe(fpath):
return os.path.exists(fpath) and os.access(fpath, os.X_OK)
@ -45,17 +47,20 @@ def which(prog):
return filename
return None
def version_split(ver):
return "%d.%d.%d" % (
(((ver) >> 16) & 0xffff),
(((ver) >> 8) & 0xff),
(((ver) & 0xff)))
((ver >> 16) & 0xffff),
((ver >> 8) & 0xff),
((ver & 0xff)))
def sl(mot):
return ((mot & 0x000000FF) << 24) |\
((mot & 0x0000FF00) << 8) |\
((mot & 0x00FF0000) >> 8) |\
((mot & 0xFF000000) >> 24)
((mot & 0x0000FF00) << 8) |\
((mot & 0x00FF0000) >> 8) |\
((mot & 0xFF000000) >> 24)
def format_tooltip(tooltip):
if len(tooltip) > 80:
@ -67,6 +72,7 @@ def format_tooltip(tooltip):
tooltip += "\n"
return tooltip
def format_label(label):
words = label.split("_")
if len(words) > 1:
@ -75,12 +81,13 @@ def format_label(label):
label = label.capitalize()
return label
def format_options(param_help):
opts = {}
if not param_help:
return None
items = re.findall(
"(\d+|[\d,-]+)\s?=\s?([\w %-]+)", param_help)
"(\d+|[\d,-]+)\s?=\s?([\w %-]+)", param_help)
for item in items:
key, value = item
if '-' in key or ',' in key: