Migrate to Qt6

This commit is contained in:
Milan Nikolic 2024-10-10 23:33:51 +02:00
parent 2a9bba7adb
commit aea48bf8e5
No known key found for this signature in database
GPG key ID: 9229D0EAA3AA4E75
32 changed files with 378 additions and 418 deletions

View file

@ -13,7 +13,7 @@
About About
===== =====
M64Py is a Qt5 front-end (GUI) for Mupen64Plus, a cross-platform M64Py is a Qt6 front-end (GUI) for Mupen64Plus, a cross-platform
plugin-based Nintendo 64 emulator. Front-end is written in Python and it plugin-based Nintendo 64 emulator. Front-end is written in Python and it
provides a user-friendly interface over the Mupen64Plus shared library. provides a user-friendly interface over the Mupen64Plus shared library.
@ -32,14 +32,14 @@ Features
Dependencies Dependencies
============ ============
* `PyQt5 <https://www.riverbankcomputing.com/software/pyqt/download5>`_ (QtCore, QtGui, QtWidgets, QtOpenGL) * `PyQt6 <https://www.riverbankcomputing.com/software/pyqt/download5>`_ (QtCore, QtGui, QtWidgets)
* `PySDL2 <https://pysdl2.readthedocs.io>`_ * `PySDL2 <https://pysdl2.readthedocs.io>`_
Ubuntu Ubuntu
++++++ ++++++
``sudo apt install libsdl2-dev qttools5-dev-tools pyqt5-dev-tools python3-pyqt5 python3-pyqt5.qtopengl`` ``sudo apt install libsdl2-dev qttools6-dev-tools pyqt6-dev-tools python3-pyqt6``
PyPi PyPi
++++ ++++

View file

@ -28,10 +28,10 @@ if os.path.isdir(os.path.join("..", "src")) and os.path.isfile(
os.environ["DBUS_FATAL_WARNINGS"] = "0" os.environ["DBUS_FATAL_WARNINGS"] = "0"
try: try:
from PyQt5.QtWidgets import QApplication from PyQt6.QtWidgets import QApplication
from PyQt5.QtCore import Qt, QLocale, QTranslator from PyQt6.QtCore import Qt, QLocale, QTranslator
except ImportError as err: except ImportError as err:
sys.stderr.write("This application needs PyQt5 module%sError:%s%s" % ( sys.stderr.write("This application needs PyQt6 module%sError:%s%s" % (
os.linesep, str(err), os.linesep)) os.linesep, str(err), os.linesep))
sys.exit(1) sys.exit(1)
@ -42,6 +42,12 @@ except ImportError as err:
os.linesep, str(err), os.linesep)) os.linesep, str(err), os.linesep))
sys.exit(1) sys.exit(1)
try:
from m64py.ui import i18n_rc
except ImportError:
sys.stderr.write("You have to run setup.py build first\n")
sys.exit(1)
def handle_exception(exc_type, exc_value, exc_traceback): def handle_exception(exc_type, exc_value, exc_traceback):
if issubclass(exc_type, KeyboardInterrupt): if issubclass(exc_type, KeyboardInterrupt):
return return
@ -73,6 +79,6 @@ if __name__ == "__main__":
signal.signal(signal.SIGINT, signal.SIG_DFL) signal.signal(signal.SIGINT, signal.SIG_DFL)
except AttributeError: except AttributeError:
pass pass
sys.exit(app.exec_()) sys.exit(app.exec())
except KeyboardInterrupt: except KeyboardInterrupt:
pass pass

12
dist/debian/control vendored
View file

@ -12,8 +12,8 @@ Build-Depends:
debhelper (>= 9), debhelper (>= 9),
dh-python, dh-python,
python3, python3,
python3-pyqt5, python3-pyqt6,
pyqt5-dev-tools, pyqt6-dev-tools,
X-Python3-Version: >= 3.4 X-Python3-Version: >= 3.4
Package: m64py Package: m64py
@ -29,10 +29,8 @@ Depends:
mupen64plus-input-all | mupen64plus-input, mupen64plus-input-all | mupen64plus-input,
mupen64plus-rsp-all | mupen64plus-rsp, mupen64plus-rsp-all | mupen64plus-rsp,
mupen64plus-video-all | mupen64plus-video, mupen64plus-video-all | mupen64plus-video,
python3-opengl, python3-pyqt6,
python3-pyqt5, python3-pyqt6.qtsvg,
python3-pyqt5.qtopengl,
python3-pyqt5.qtsvg,
python3-sdl2, python3-sdl2,
Provides: Provides:
mupen64plus-ui, mupen64plus-ui,
@ -41,7 +39,7 @@ Recommends:
python3-lzma | p7zip, python3-lzma | p7zip,
unrar, unrar,
Description: Python based graphical frontend for mupen64plus Description: Python based graphical frontend for mupen64plus
M64Py is a Qt5 front-end (GUI) for Mupen64Plus, a cross-platform M64Py is a Qt6 front-end (GUI) for Mupen64Plus, a cross-platform
plugin-based Nintendo 64 emulator. M64Py is written in Python and it plugin-based Nintendo 64 emulator. M64Py is written in Python and it
provides a user-friendly interface over Mupen64Plus shared library. provides a user-friendly interface over Mupen64Plus shared library.
. .

2
dist/debian/m64py.6 vendored
View file

@ -28,7 +28,7 @@ m64py \- Mupen64plus frontend
.B m64py [\fIoptions\fP] .B m64py [\fIoptions\fP]
.br .br
.SH DESCRIPTION .SH DESCRIPTION
m64py is a graphical Qt5 frontend for the Nintendo64 emulator mupen64plus m64py is a graphical Qt6 frontend for the Nintendo64 emulator mupen64plus
.PP .PP
.PP .PP
.SH OPTIONS .SH OPTIONS

View file

@ -5,7 +5,7 @@ DIST_DIR = os.environ["DIST_DIR"]
BASE_DIR = os.environ["BASE_DIR"] BASE_DIR = os.environ["BASE_DIR"]
a = Analysis([join(BASE_DIR, 'm64py')], pathex=[join(BASE_DIR, 'src')], a = Analysis([join(BASE_DIR, 'm64py')], pathex=[join(BASE_DIR, 'src')],
hiddenimports=['pickle', 'PyQt5.Qt'], hiddenimports=['pickle', 'PyQt6.Qt'],
hookspath=None, hookspath=None,
runtime_hooks=None) runtime_hooks=None)

View file

@ -1,5 +1,5 @@
#!/bin/sh #!/bin/sh
yum install rpm-build PyQt5-devel -y yum install rpm-build PyQt6-devel -y
VERSION=`cat ../../src/m64py/core/defs.py | grep FRONTEND_VERSION | awk -F' = ' '{print $2}' | tr -d '"'` VERSION=`cat ../../src/m64py/core/defs.py | grep FRONTEND_VERSION | awk -F' = ' '{print $2}' | tr -d '"'`
sed "s/{VERSION}/$VERSION/g" m64py.spec.in > m64py.spec sed "s/{VERSION}/$VERSION/g" m64py.spec.in > m64py.spec
cd ../../ && python setup.py sdist cd ../../ && python setup.py sdist

View file

@ -15,10 +15,10 @@ Prefix: %{_prefix}
BuildArch: noarch BuildArch: noarch
Vendor: Milan Nikolic <gen2brain@gmail.com> Vendor: Milan Nikolic <gen2brain@gmail.com>
Url: http://m64py.sourceforge.net Url: http://m64py.sourceforge.net
Requires: PyQt5 PySDL2 Requires: PyQt6 PySDL2
%description %description
M64Py is a Qt5 front-end (GUI) for Mupen64Plus, a cross-platform plugin-based Nintendo 64 emulator. M64Py is a Qt6 front-end (GUI) for Mupen64Plus, a cross-platform plugin-based Nintendo 64 emulator.
%prep %prep
%setup -n %{name}-%{unmangled_version} %setup -n %{name}-%{unmangled_version}

View file

@ -32,7 +32,7 @@ Source: "m64py\*.zip"; DestDir: "{app}";
Source: "m64py\*.v64"; DestDir: "{app}"; Source: "m64py\*.v64"; DestDir: "{app}";
Source: "m64py\*.pyd"; DestDir: "{app}"; Source: "m64py\*.pyd"; DestDir: "{app}";
Source: "m64py\doc\*"; DestDir: "{app}\doc"; Source: "m64py\doc\*"; DestDir: "{app}\doc";
Source: "m64py\PyQt5\*"; DestDir: "{app}\PyQt5"; Flags: recursesubdirs Source: "m64py\PyQt6\*"; DestDir: "{app}\PyQt6"; Flags: recursesubdirs
Source: "m64py\AUTHORS"; DestDir: "{app}"; Source: "m64py\AUTHORS"; DestDir: "{app}";
Source: "m64py\COPYING"; DestDir: "{app}"; Source: "m64py\COPYING"; DestDir: "{app}";
Source: "m64py\README.rst"; DestDir: "{app}"; Source: "m64py\README.rst"; DestDir: "{app}";

View file

@ -4,7 +4,7 @@ from os.path import join
DIST_DIR = os.environ["DIST_DIR"] DIST_DIR = os.environ["DIST_DIR"]
BASE_DIR = os.environ["BASE_DIR"] BASE_DIR = os.environ["BASE_DIR"]
a = Analysis([join(BASE_DIR, 'm64py')], hiddenimports=['pickle', 'PyQt5.Qt'], pathex=[join(BASE_DIR, 'src')]) a = Analysis([join(BASE_DIR, 'm64py')], hiddenimports=['pickle', 'PyQt6.Qt'], pathex=[join(BASE_DIR, 'src')])
pyz = PYZ(a.pure) pyz = PYZ(a.pure)

View file

@ -1,2 +1,2 @@
pyqt5 pyqt6
pysdl2 pysdl2

View file

@ -9,10 +9,8 @@ import sys
import tempfile import tempfile
import urllib import urllib
import zipfile import zipfile
import fileinput
import distutils
import distutils.command.build as distutils_build
import distutils.command.clean as distutils_clean
import setuptools import setuptools
try: try:
@ -42,52 +40,52 @@ class BuildQt(setuptools.Command):
pass pass
def compile_rc(self, qrc_file): def compile_rc(self, qrc_file):
import PyQt5
py_file = os.path.splitext(qrc_file)[0] + "_rc.py" py_file = os.path.splitext(qrc_file)[0] + "_rc.py"
if not newer(qrc_file, py_file): if not newer(qrc_file, py_file):
return return
origpath = os.getenv("PATH") path = os.getenv("PATH").split(os.pathsep)
path = origpath.split(os.pathsep) path.extend(["/usr/lib64/qt6/bin", "/usr/lib64/qt6/libexec",
path.append(os.path.dirname(PyQt5.__file__)) "/usr/lib/qt6/bin", "/usr/lib/qt6/libexec",
os.putenv("PATH", os.pathsep.join(path)) "/usr/lib/x86_64-linux-gnu/qt6/bin", "/usr/lib/x86_64-linux-gnu/qt6/libexec"])
if subprocess.call(["pyrcc5", qrc_file, "-o", py_file]) > 0: os.environ["PATH"] = os.pathsep.join(path)
rcc_exe = shutil.which("rcc")
if rcc_exe is None:
self.warn("Unable to find Qt Resource Compiler (rcc)")
sys.exit(1)
if subprocess.call(["rcc", "-g", "python", qrc_file, "-o", py_file]) > 0:
self.warn("Unable to compile resource file {}".format(qrc_file)) self.warn("Unable to compile resource file {}".format(qrc_file))
if not os.path.exists(py_file): if not os.path.exists(py_file):
sys.exit(1) sys.exit(1)
os.putenv("PATH", origpath) for line in fileinput.input(py_file, inplace=True):
if "PySide6" in line:
line = line.replace("PySide6", "PyQt6")
sys.stdout.write(line)
def compile_ui(self, ui_file): def compile_ui(self, ui_file):
from PyQt5 import uic from PyQt6 import uic
py_file = os.path.splitext(ui_file)[0] + "_ui.py" py_file = os.path.splitext(ui_file)[0] + "_ui.py"
if not newer(ui_file, py_file): if not newer(ui_file, py_file):
return return
with open(py_file, "w") as a_file: with open(py_file, "w") as a_file:
uic.compileUi(ui_file, a_file, from_imports=True) uic.compileUi(ui_file, a_file)
def compile_ts(self, ts_file): def compile_ts(self, ts_file):
import PyQt5
from PyQt5.QtCore import QLibraryInfo
qm_file = os.path.splitext(ts_file)[0] + ".qm" qm_file = os.path.splitext(ts_file)[0] + ".qm"
if not newer(ts_file, qm_file): if not newer(ts_file, qm_file):
return return
origpath = os.getenv("PATH") path = os.getenv("PATH").split(os.pathsep)
path = origpath.split(os.pathsep) path.extend(["/usr/lib64/qt6/bin", "/usr/lib64/qt6/libexec",
path.append(os.path.dirname(PyQt5.__file__)) "/usr/lib/qt6/bin", "/usr/lib/qt6/libexec",
os.putenv("PATH", os.pathsep.join(path)) "/usr/lib/x86_64-linux-gnu/qt6/bin", "/usr/lib/x86_64-linux-gnu/qt6/libexec"])
lr_exe = QLibraryInfo.location(QLibraryInfo.LibraryLocation.BinariesPath) os.environ["PATH"] = os.pathsep.join(path)
if lr_exe: lr_exe = shutil.which("lrelease")
lr_exe = os.path.join(lr_exe, "lrelease")
if not os.path.exists(lr_exe):
lr_exe = None
lr_exe = lr_exe or distutils.spawn.find_executable("lrelease") or distutils.spawn.find_executable("lrelease-qt5")
if lr_exe is None: if lr_exe is None:
self.warn("Unable to find Qt's Linguist lrelease or lrelease-qt5 tools") self.warn("Unable to find Qt Linguist (lrelease)")
sys.exit(1) sys.exit(1)
if subprocess.call([lr_exe, ts_file, "-qm", qm_file]) > 0: if subprocess.call([lr_exe, ts_file, "-qm", qm_file]) > 0:
self.warn("Unable to compile translation file {}".format(qm_file)) self.warn("Unable to compile translation file {}".format(qm_file))
if not os.path.exists(qm_file): if not os.path.exists(qm_file):
sys.exit(1) sys.exit(1)
os.putenv("PATH", origpath)
def run(self): def run(self):
basepath = os.path.join(os.path.dirname(__file__), "src", "m64py", "ui") basepath = os.path.join(os.path.dirname(__file__), "src", "m64py", "ui")
@ -120,7 +118,7 @@ class BuildDmg(setuptools.Command):
def copy_emulator(self): def copy_emulator(self):
src_path = os.path.join(self.dist_dir, "mupen64plus", "Contents") src_path = os.path.join(self.dist_dir, "mupen64plus", "Contents")
dest_path = os.path.join(self.dist_dir, "dmg", "M64Py.app", "Contents") dest_path = os.path.join(self.dist_dir, "dmg", "M64Py.app", "Contents")
distutils.dir_util.copy_tree(src_path, dest_path) shutil.copytree(src_path, dest_path, dirs_exist_ok=True)
def copy_files(self): def copy_files(self):
dest_path = os.path.join(self.dist_dir, "dmg") dest_path = os.path.join(self.dist_dir, "dmg")
@ -189,7 +187,7 @@ class BuildDmg(setuptools.Command):
class BuildExe(setuptools.Command): class BuildExe(setuptools.Command):
""" """
Requires PyQt5, rarfile, PyLZMA, PyWin32, PyInstaller and Inno Requires PyQt6, rarfile, PyLZMA, PyWin32, PyInstaller and Inno
Setup 5. Setup 5.
""" """
@ -233,7 +231,7 @@ class BuildExe(setuptools.Command):
rar_dir = os.path.join(os.environ["ProgramFiles(x86)"], "Unrar") rar_dir = os.path.join(os.environ["ProgramFiles(x86)"], "Unrar")
if not os.path.isfile(os.path.join(rar_dir, "UnRAR.exe")): if not os.path.isfile(os.path.join(rar_dir, "UnRAR.exe")):
tempdir = tempfile.mkdtemp() tempdir = tempfile.mkdtemp()
urllib.request.urlretrieve("http://www.rarlab.com/rar/unrarw32.exe", urllib.request.urlretrieve("http://www.rarlab.com/rar/unrarw64.exe",
os.path.join(tempdir, "unrar.exe")) os.path.join(tempdir, "unrar.exe"))
subprocess.call([os.path.join(tempdir, "unrar.exe"), "-s"]) subprocess.call([os.path.join(tempdir, "unrar.exe"), "-s"])
shutil.rmtree(tempdir) shutil.rmtree(tempdir)
@ -248,12 +246,12 @@ class BuildExe(setuptools.Command):
for dir_name in ["api", "man6", "applications", "apps"]: for dir_name in ["api", "man6", "applications", "apps"]:
shutil.rmtree(os.path.join(dest_path, dir_name), True) shutil.rmtree(os.path.join(dest_path, dir_name), True)
for dir_name in ["qml", "translations"]: for dir_name in ["qml", "translations"]:
shutil.rmtree(os.path.join(dest_path, "PyQt5", "Qt", dir_name), True) shutil.rmtree(os.path.join(dest_path, "PyQt6", "Qt", dir_name), True)
for file_name in glob.glob(os.path.join(dest_path, "PyQt5", "Qt*.pyd")): for file_name in glob.glob(os.path.join(dest_path, "PyQt6", "Qt*.pyd")):
if os.path.basename(file_name) not in ["Qt.pyd", "QtCore.pyd", "QtGui.pyd", "QtWidgets.pyd", "QtOpenGL.pyd"]: if os.path.basename(file_name) not in ["Qt.pyd", "QtCore.pyd", "QtGui.pyd", "QtWidgets.pyd"]:
os.remove(file_name) os.remove(file_name)
for file_name in glob.glob(os.path.join(dest_path, "Qt5*.dll")): for file_name in glob.glob(os.path.join(dest_path, "Qt6*.dll")):
if os.path.basename(file_name) not in ["Qt5Core.dll", "Qt5Gui.dll", "Qt5Widgets.dll", "Qt5OpenGL.dll"]: if os.path.basename(file_name) not in ["Qt6Core.dll", "Qt6Gui.dll", "Qt6Widgets.dll"]:
os.remove(file_name) os.remove(file_name)
def run_build(self): def run_build(self):
@ -381,23 +379,11 @@ class CleanLocal(setuptools.Command):
os.remove(a_path) os.remove(a_path)
class MyBuild(distutils_build.build):
def run(self):
self.run_command("build_qt")
distutils_build.build.run(self)
class MyClean(distutils_clean.clean):
def run(self):
self.run_command("clean_local")
distutils_clean.clean.run(self)
setuptools.setup( setuptools.setup(
name="m64py", name="m64py",
version=FRONTEND_VERSION, version=FRONTEND_VERSION,
description="A frontend for Mupen64Plus", description="A frontend for Mupen64Plus",
long_description="A Qt5 front-end (GUI) for Mupen64Plus, a cross-platform plugin-based Nintendo 64 emulator.", long_description="A Qt6 front-end (GUI) for Mupen64Plus, a cross-platform plugin-based Nintendo 64 emulator.",
author="Milan Nikolic", author="Milan Nikolic",
author_email="gen2brain@gmail.com", author_email="gen2brain@gmail.com",
license="GNU GPLv3", license="GNU GPLv3",
@ -405,16 +391,15 @@ setuptools.setup(
package_dir={'': "src"}, package_dir={'': "src"},
packages=["m64py", "m64py.core", "m64py.frontend", "m64py.ui"], packages=["m64py", "m64py.core", "m64py.frontend", "m64py.ui"],
scripts=["bin/m64py"], scripts=["bin/m64py"],
requires=["PyQt5", "PySDL2"], requires=["PyQt6", "PySDL2"],
platforms=["Linux", "Windows", "Darwin"], platforms=["Linux", "Windows", "Darwin"],
cmdclass={ cmdclass={
'build': MyBuild, 'build': BuildQt,
'build_dmg': BuildDmg, 'build_dmg': BuildDmg,
'build_exe': BuildExe, 'build_exe': BuildExe,
'build_qt': BuildQt, 'build_qt': BuildQt,
'build_zip': BuildZip, 'build_zip': BuildZip,
'clean': MyClean, 'clean': CleanLocal
'clean_local': CleanLocal
}, },
data_files=[ data_files=[
("share/pixmaps", ["xdg/m64py.png"]), ("share/pixmaps", ["xdg/m64py.png"]),

View file

@ -23,7 +23,7 @@ CORE_API_VERSION = 0x20001
CONFIG_API_VERSION = 0x20302 CONFIG_API_VERSION = 0x20302
VIDEXT_API_VERSION = 0x030300 VIDEXT_API_VERSION = 0x030300
MINIMUM_CORE_VERSION = 0x020600 MINIMUM_CORE_VERSION = 0x020600
FRONTEND_VERSION = "0.2.6" FRONTEND_VERSION = "0.3.0"
SIZE_1X = (320, 240) SIZE_1X = (320, 240)
SIZE_2X = (640, 480) SIZE_2X = (640, 480)

View file

@ -16,8 +16,8 @@
import ctypes import ctypes
from PyQt5.QtWidgets import QApplication from PyQt6.QtWidgets import QApplication
from PyQt5.QtGui import QSurfaceFormat from PyQt6.QtGui import QSurfaceFormat
from sdl2 import SDL_WasInit, SDL_InitSubSystem, SDL_QuitSubSystem, SDL_INIT_VIDEO from sdl2 import SDL_WasInit, SDL_InitSubSystem, SDL_QuitSubSystem, SDL_INIT_VIDEO
from sdl2 import SDL_GetNumDisplayModes, SDL_DisplayMode, SDL_GetDisplayMode from sdl2 import SDL_GetNumDisplayModes, SDL_DisplayMode, SDL_GetDisplayMode
@ -62,9 +62,9 @@ class Video:
if not self.glcontext: if not self.glcontext:
self.glformat = QSurfaceFormat.defaultFormat() self.glformat = QSurfaceFormat.defaultFormat()
self.glformat.setVersion(3, 3) self.glformat.setVersion(3, 3)
self.glformat.setOption(QSurfaceFormat.DeprecatedFunctions, 1) self.glformat.setOption(QSurfaceFormat.FormatOption.DeprecatedFunctions, 1)
self.glformat.setProfile(QSurfaceFormat.CompatibilityProfile) self.glformat.setProfile(QSurfaceFormat.OpenGLContextProfile.CompatibilityProfile)
self.glformat.setRenderableType(QSurfaceFormat.OpenGL) self.glformat.setRenderableType(QSurfaceFormat.RenderableType.OpenGL)
self.glformat.setDepthBufferSize(24) self.glformat.setDepthBufferSize(24)
self.glformat.setSwapInterval(0) self.glformat.setSwapInterval(0)
@ -220,29 +220,29 @@ class Video:
def set_profile(self, value): def set_profile(self, value):
if value == M64P_GL_CONTEXT_PROFILE_CORE: if value == M64P_GL_CONTEXT_PROFILE_CORE:
self.glformat.setProfile(QSurfaceFormat.CoreProfile) self.glformat.setProfile(QSurfaceFormat.OpenGLContextProfile.CoreProfile)
elif value == M64P_GL_CONTEXT_PROFILE_COMPATIBILITY: elif value == M64P_GL_CONTEXT_PROFILE_COMPATIBILITY:
self.glformat.setProfile(QSurfaceFormat.CompatibilityProfile) self.glformat.setProfile(QSurfaceFormat.OpenGLContextProfile.CompatibilityProfile)
else: else:
self.glformat.setProfile(QSurfaceFormat.CompatibilityProfile) self.glformat.setProfile(QSurfaceFormat.OpenGLContextProfile.CompatibilityProfile)
def get_profile(self): def get_profile(self):
profile = self.glformat.profile() profile = self.glformat.profile()
if profile == QSurfaceFormat.CoreProfile: if profile == QSurfaceFormat.OpenGLContextProfile.CoreProfile:
return M64P_GL_CONTEXT_PROFILE_CORE return M64P_GL_CONTEXT_PROFILE_CORE
elif profile == QSurfaceFormat.CompatibilityProfile: elif profile == QSurfaceFormat.OpenGLContextProfile.CompatibilityProfile:
return M64P_GL_CONTEXT_PROFILE_COMPATIBILITY return M64P_GL_CONTEXT_PROFILE_COMPATIBILITY
else: else:
return M64P_GL_CONTEXT_PROFILE_COMPATIBILITY return M64P_GL_CONTEXT_PROFILE_COMPATIBILITY
def set_doublebuffer(self, value): def set_doublebuffer(self, value):
if value == 1: if value == 1:
self.glformat.setSwapBehavior(QSurfaceFormat.DoubleBuffer) self.glformat.setSwapBehavior(QSurfaceFormat.SwapBehavior.DoubleBuffer)
elif value == 0: elif value == 0:
self.glformat.setSwapBehavior(QSurfaceFormat.SingleBuffer) self.glformat.setSwapBehavior(QSurfaceFormat.SwapBehavior.SingleBuffer)
def get_doublebuffer(self): def get_doublebuffer(self):
if self.glformat.swapBehavior() == QSurfaceFormat.DoubleBuffer: if self.glformat.swapBehavior() == QSurfaceFormat.SwapBehavior.DoubleBuffer:
return 1 return 1
return 0 return 0

View file

@ -18,8 +18,8 @@ import os
import re import re
from collections import defaultdict from collections import defaultdict
from PyQt5.QtWidgets import QDialog, QTreeWidgetItem, QListWidgetItem, QTreeWidgetItemIterator from PyQt6.QtWidgets import QDialog, QTreeWidgetItem, QListWidgetItem, QTreeWidgetItemIterator
from PyQt5.QtCore import Qt from PyQt6.QtCore import Qt
from m64py.core.defs import * from m64py.core.defs import *
from m64py.utils import sl from m64py.utils import sl
@ -69,41 +69,31 @@ class Cheat(QDialog, Ui_CheatDialog):
for k3,v3 in sorted(v2.items()): for k3,v3 in sorted(v2.items()):
child2 = QTreeWidgetItem(child1) child2 = QTreeWidgetItem(child1)
child2.setText(0, k3) child2.setText(0, k3)
child2.setCheckState(0, Qt.Unchecked) child2.setCheckState(0, Qt.CheckState.Unchecked)
child2.setData(0, Qt.UserRole, v3) child2.setData(0, Qt.ItemDataRole.UserRole, v3)
self.treeWidget.addTopLevelItem(child2) self.treeWidget.addTopLevelItem(child2)
else: else:
child1.setCheckState(0, Qt.Unchecked) child1.setCheckState(0, Qt.CheckState.Unchecked)
child1.setData(0, Qt.UserRole, v2) child1.setData(0, Qt.ItemDataRole.UserRole, v2)
else: else:
top.setCheckState(0, Qt.Unchecked) top.setCheckState(0, Qt.CheckState.Unchecked)
top.setData(0, Qt.UserRole, v1) top.setData(0, Qt.ItemDataRole.UserRole, v1)
self.treeWidget.sortItems(0, Qt.AscendingOrder) self.treeWidget.sortItems(0, Qt.SortOrder.AscendingOrder)
self.treeWidget.itemChanged.connect(self.activate_cheat) self.treeWidget.itemChanged.connect(self.activate_cheat)
self.treeWidget.itemClicked.connect(self.on_item_clicked) self.treeWidget.itemClicked.connect(self.on_item_clicked)
self.treeWidget.itemSelectionChanged.connect(self.on_selection_changed)
self.pushUnmarkAll.clicked.connect(self.on_unmark_all) self.pushUnmarkAll.clicked.connect(self.on_unmark_all)
def on_selection_changed(self):
"""Sets description"""
items = self.treeWidget.selectedItems()
for item in items:
data = item.data(0, Qt.UserRole)
if data:
for cheat in data:
cd, address, value, choices = cheat
desc = cd if cd else ""
self.labelDesc.setText(desc)
def on_item_clicked(self, item, column): def on_item_clicked(self, item, column):
"""Sets description""" """Sets description"""
data = item.data(column, Qt.UserRole) data = item.data(column, Qt.ItemDataRole.UserRole)
if data: if data:
for cheat in data: for cheat in data:
cd, address, value, choices = cheat cd, address, value, choices = cheat
desc = cd if cd else "" desc = cd if cd else ""
self.labelDesc.setText(desc) self.labelDesc.setText(desc)
if desc:
break
def on_unmark_all(self): def on_unmark_all(self):
"""Deactivates all cheats""" """Deactivates all cheats"""
@ -111,8 +101,8 @@ class Cheat(QDialog, Ui_CheatDialog):
while it.value(): while it.value():
item = it.value() item = it.value()
state = item.checkState(0) state = item.checkState(0)
if state == Qt.Checked: if state == Qt.CheckState.Checked:
item.setCheckState(0, Qt.Unchecked) item.setCheckState(0, Qt.CheckState.Unchecked)
it += 1 it += 1
def activate_cheat(self, item, column): def activate_cheat(self, item, column):
@ -125,8 +115,8 @@ class Cheat(QDialog, Ui_CheatDialog):
parent = parent.parent() parent = parent.parent()
if parent: if parent:
name = "%s\\%s" % (parent.text(column), name) name = "%s\\%s" % (parent.text(column), name)
data = item.data(column, Qt.UserRole) data = item.data(column, Qt.ItemDataRole.UserRole)
if state == Qt.Checked: if state == Qt.CheckState.Checked:
codes_type = M64pCheatCode * len(data) codes_type = M64pCheatCode * len(data)
codes = codes_type() codes = codes_type()
for num, cheat in enumerate(data): for num, cheat in enumerate(data):
@ -136,7 +126,7 @@ class Cheat(QDialog, Ui_CheatDialog):
rval = choices.exec_() rval = choices.exec_()
if rval == QDialog.Accepted: if rval == QDialog.Accepted:
curr_item = choices.listWidget.currentItem() curr_item = choices.listWidget.currentItem()
value = curr_item.data(Qt.UserRole) value = curr_item.data(Qt.ItemDataRole.UserRole)
else: else:
#item.setCheckState(0, Qt.Unchecked) #item.setCheckState(0, Qt.Unchecked)
return return
@ -282,5 +272,5 @@ class Choices(QDialog, Ui_ChoicesDialog):
for choice in sorted(self.choices, key=lambda choice: choice[1]): for choice in sorted(self.choices, key=lambda choice: choice[1]):
value, name = choice value, name = choice
item = QListWidgetItem(name.replace('"', '')) item = QListWidgetItem(name.replace('"', ''))
item.setData(Qt.UserRole, value) item.setData(Qt.ItemDataRole.UserRole, value)
self.listWidget.addItem(item) self.listWidget.addItem(item)

View file

@ -15,19 +15,15 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
import sys import sys
from PyQt5.QtCore import Qt from PyQt6.QtCore import Qt
from PyQt5.QtWidgets import QDialog, QMessageBox, QListWidgetItem from PyQt6.QtWidgets import QDialog, QMessageBox, QListWidgetItem
from m64py.utils import version_split from m64py.utils import version_split
from m64py.core.defs import FRONTEND_VERSION from m64py.core.defs import FRONTEND_VERSION
try: from m64py.ui.about_ui import Ui_AboutDialog
from m64py.ui.about_ui import Ui_AboutDialog from m64py.ui.license_ui import Ui_LicenseDialog
from m64py.ui.license_ui import Ui_LicenseDialog from m64py.ui.archive_ui import Ui_ArchiveDialog
from m64py.ui.archive_ui import Ui_ArchiveDialog
except ModuleNotFoundError:
sys.stderr.write("You have to run setup.py build first\n")
sys.exit(1)
class AboutDialog(QDialog, Ui_AboutDialog): class AboutDialog(QDialog, Ui_AboutDialog):
@ -70,6 +66,6 @@ class ArchiveDialog(QDialog, Ui_ArchiveDialog):
self.listWidget.clear() self.listWidget.clear()
for fname in files: for fname in files:
item = QListWidgetItem(fname) item = QListWidgetItem(fname)
item.setData(Qt.UserRole, fname) item.setData(Qt.ItemDataRole.UserRole, fname)
self.listWidget.addItem(item) self.listWidget.addItem(item)
self.listWidget.setCurrentRow(0) self.listWidget.setCurrentRow(0)

View file

@ -14,11 +14,7 @@
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
from PyQt5.QtCore import Qt from PyQt6.QtGui import QWindow, QOpenGLContext, QSurface
from PyQt5.QtGui import QWindow, QOpenGLContext
from m64py.core.defs import *
from m64py.frontend.keymap import QT2SDL2
class GLWidget(QWindow): class GLWidget(QWindow):
@ -27,7 +23,7 @@ class GLWidget(QWindow):
self.parent = parent self.parent = parent
QWindow.__init__(self, None) QWindow.__init__(self, None)
self.setSurfaceType(QWindow.OpenGLSurface) self.setSurfaceType(QSurface.SurfaceType.OpenGLSurface)
self.ctx = QOpenGLContext() self.ctx = QOpenGLContext()
def context(self): def context(self):
@ -40,34 +36,3 @@ class GLWidget(QWindow):
def mouseDoubleClickEvent(self, event): def mouseDoubleClickEvent(self, event):
self.parent.toggle_fs.emit() self.parent.toggle_fs.emit()
def keyPressEvent(self, event):
if self.parent.worker.state != M64EMU_RUNNING:
return
key = event.key()
modifiers = event.modifiers()
if modifiers & Qt.AltModifier and (key == Qt.Key_Enter or key == Qt.Key_Return):
self.parent.toggle_fs.emit()
elif key == Qt.Key_F3:
self.parent.worker.save_title()
elif key == Qt.Key_F4:
self.parent.worker.save_snapshot()
else:
try:
sdl_key = QT2SDL2[key]
self.parent.worker.send_sdl_keydown(sdl_key)
except KeyError:
pass
def keyReleaseEvent(self, event):
if self.parent.worker.state != M64EMU_RUNNING:
return
key = event.key()
try:
sdl_key = QT2SDL2[key]
self.parent.worker.send_sdl_keyup(sdl_key)
except KeyError:
pass

View file

@ -16,8 +16,7 @@
import re import re
from PyQt5.QtWidgets import QDialog from PyQt6.QtWidgets import QDialog
from PyQt5.QtGui import QKeySequence
from sdl2 import SDL_WasInit, SDL_InitSubSystem, SDL_QuitSubSystem, SDL_INIT_VIDEO from sdl2 import SDL_WasInit, SDL_InitSubSystem, SDL_QuitSubSystem, SDL_INIT_VIDEO
from sdl2.keyboard import SDL_GetScancodeName, SDL_GetScancodeFromName from sdl2.keyboard import SDL_GetScancodeName, SDL_GetScancodeFromName

View file

@ -17,7 +17,7 @@
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
from PyQt5.QtCore import QObject, pyqtSignal, QTime, QTimer from PyQt6.QtCore import QObject, pyqtSignal, QTime, QTimer
from sdl2 import SDL_WasInit, SDL_InitSubSystem, SDL_INIT_JOYSTICK from sdl2 import SDL_WasInit, SDL_InitSubSystem, SDL_INIT_JOYSTICK
from sdl2 import SDL_JoystickOpen, SDL_JoystickClose, SDL_NumJoysticks, SDL_JoystickNameForIndex from sdl2 import SDL_JoystickOpen, SDL_JoystickClose, SDL_NumJoysticks, SDL_JoystickNameForIndex
@ -195,6 +195,6 @@ class Joystick(QObject):
elif self.auto_repeat and changed != 0: elif self.auto_repeat and changed != 0:
if self.button_repeat_timers[i].elapsed() >= self.auto_repeat_delay: if self.button_repeat_timers[i].elapsed() >= self.auto_repeat_delay:
self.button_value_changed.emit(i, changed) self.button_value_changed.emit(i, changed)
self.button[si] = changed self.button[i] = changed
else: else:
self.button_repeat_timers[i].restart() self.button_repeat_timers[i].restart()

View file

@ -14,7 +14,7 @@
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
from PyQt5.QtCore import Qt from PyQt6.QtCore import Qt
from m64py.frontend.keycodes import * from m64py.frontend.keycodes import *
@ -22,100 +22,100 @@ QT2SDL2 = dict()
SCANCODE2KEYCODE = dict() SCANCODE2KEYCODE = dict()
KEYCODE2SCANCODE = dict() KEYCODE2SCANCODE = dict()
QT2SDL2[Qt.Key_A] = SDL_SCANCODE_A QT2SDL2[Qt.Key.Key_A] = SDL_SCANCODE_A
QT2SDL2[Qt.Key_B] = SDL_SCANCODE_B QT2SDL2[Qt.Key.Key_B] = SDL_SCANCODE_B
QT2SDL2[Qt.Key_C] = SDL_SCANCODE_C QT2SDL2[Qt.Key.Key_C] = SDL_SCANCODE_C
QT2SDL2[Qt.Key_D] = SDL_SCANCODE_D QT2SDL2[Qt.Key.Key_D] = SDL_SCANCODE_D
QT2SDL2[Qt.Key_E] = SDL_SCANCODE_E QT2SDL2[Qt.Key.Key_E] = SDL_SCANCODE_E
QT2SDL2[Qt.Key_F] = SDL_SCANCODE_F QT2SDL2[Qt.Key.Key_F] = SDL_SCANCODE_F
QT2SDL2[Qt.Key_G] = SDL_SCANCODE_G QT2SDL2[Qt.Key.Key_G] = SDL_SCANCODE_G
QT2SDL2[Qt.Key_H] = SDL_SCANCODE_H QT2SDL2[Qt.Key.Key_H] = SDL_SCANCODE_H
QT2SDL2[Qt.Key_I] = SDL_SCANCODE_I QT2SDL2[Qt.Key.Key_I] = SDL_SCANCODE_I
QT2SDL2[Qt.Key_J] = SDL_SCANCODE_J QT2SDL2[Qt.Key.Key_J] = SDL_SCANCODE_J
QT2SDL2[Qt.Key_K] = SDL_SCANCODE_K QT2SDL2[Qt.Key.Key_K] = SDL_SCANCODE_K
QT2SDL2[Qt.Key_L] = SDL_SCANCODE_L QT2SDL2[Qt.Key.Key_L] = SDL_SCANCODE_L
QT2SDL2[Qt.Key_M] = SDL_SCANCODE_M QT2SDL2[Qt.Key.Key_M] = SDL_SCANCODE_M
QT2SDL2[Qt.Key_N] = SDL_SCANCODE_N QT2SDL2[Qt.Key.Key_N] = SDL_SCANCODE_N
QT2SDL2[Qt.Key_O] = SDL_SCANCODE_O QT2SDL2[Qt.Key.Key_O] = SDL_SCANCODE_O
QT2SDL2[Qt.Key_P] = SDL_SCANCODE_P QT2SDL2[Qt.Key.Key_P] = SDL_SCANCODE_P
QT2SDL2[Qt.Key_Q] = SDL_SCANCODE_Q QT2SDL2[Qt.Key.Key_Q] = SDL_SCANCODE_Q
QT2SDL2[Qt.Key_R] = SDL_SCANCODE_R QT2SDL2[Qt.Key.Key_R] = SDL_SCANCODE_R
QT2SDL2[Qt.Key_S] = SDL_SCANCODE_S QT2SDL2[Qt.Key.Key_S] = SDL_SCANCODE_S
QT2SDL2[Qt.Key_T] = SDL_SCANCODE_T QT2SDL2[Qt.Key.Key_T] = SDL_SCANCODE_T
QT2SDL2[Qt.Key_U] = SDL_SCANCODE_U QT2SDL2[Qt.Key.Key_U] = SDL_SCANCODE_U
QT2SDL2[Qt.Key_V] = SDL_SCANCODE_V QT2SDL2[Qt.Key.Key_V] = SDL_SCANCODE_V
QT2SDL2[Qt.Key_W] = SDL_SCANCODE_W QT2SDL2[Qt.Key.Key_W] = SDL_SCANCODE_W
QT2SDL2[Qt.Key_X] = SDL_SCANCODE_X QT2SDL2[Qt.Key.Key_X] = SDL_SCANCODE_X
QT2SDL2[Qt.Key_Y] = SDL_SCANCODE_Y QT2SDL2[Qt.Key.Key_Y] = SDL_SCANCODE_Y
QT2SDL2[Qt.Key_Z] = SDL_SCANCODE_Z QT2SDL2[Qt.Key.Key_Z] = SDL_SCANCODE_Z
QT2SDL2[Qt.Key_0] = SDL_SCANCODE_0 QT2SDL2[Qt.Key.Key_0] = SDL_SCANCODE_0
QT2SDL2[Qt.Key_1] = SDL_SCANCODE_1 QT2SDL2[Qt.Key.Key_1] = SDL_SCANCODE_1
QT2SDL2[Qt.Key_2] = SDL_SCANCODE_2 QT2SDL2[Qt.Key.Key_2] = SDL_SCANCODE_2
QT2SDL2[Qt.Key_3] = SDL_SCANCODE_3 QT2SDL2[Qt.Key.Key_3] = SDL_SCANCODE_3
QT2SDL2[Qt.Key_4] = SDL_SCANCODE_4 QT2SDL2[Qt.Key.Key_4] = SDL_SCANCODE_4
QT2SDL2[Qt.Key_5] = SDL_SCANCODE_5 QT2SDL2[Qt.Key.Key_5] = SDL_SCANCODE_5
QT2SDL2[Qt.Key_6] = SDL_SCANCODE_6 QT2SDL2[Qt.Key.Key_6] = SDL_SCANCODE_6
QT2SDL2[Qt.Key_7] = SDL_SCANCODE_7 QT2SDL2[Qt.Key.Key_7] = SDL_SCANCODE_7
QT2SDL2[Qt.Key_8] = SDL_SCANCODE_8 QT2SDL2[Qt.Key.Key_8] = SDL_SCANCODE_8
QT2SDL2[Qt.Key_9] = SDL_SCANCODE_9 QT2SDL2[Qt.Key.Key_9] = SDL_SCANCODE_9
QT2SDL2[Qt.Key_F1] = SDL_SCANCODE_F1 QT2SDL2[Qt.Key.Key_F1] = SDL_SCANCODE_F1
QT2SDL2[Qt.Key_F2] = SDL_SCANCODE_F2 QT2SDL2[Qt.Key.Key_F2] = SDL_SCANCODE_F2
QT2SDL2[Qt.Key_F3] = SDL_SCANCODE_F3 QT2SDL2[Qt.Key.Key_F3] = SDL_SCANCODE_F3
QT2SDL2[Qt.Key_F4] = SDL_SCANCODE_F4 QT2SDL2[Qt.Key.Key_F4] = SDL_SCANCODE_F4
QT2SDL2[Qt.Key_F5] = SDL_SCANCODE_F5 QT2SDL2[Qt.Key.Key_F5] = SDL_SCANCODE_F5
QT2SDL2[Qt.Key_F6] = SDL_SCANCODE_F6 QT2SDL2[Qt.Key.Key_F6] = SDL_SCANCODE_F6
QT2SDL2[Qt.Key_F7] = SDL_SCANCODE_F7 QT2SDL2[Qt.Key.Key_F7] = SDL_SCANCODE_F7
QT2SDL2[Qt.Key_F8] = SDL_SCANCODE_F8 QT2SDL2[Qt.Key.Key_F8] = SDL_SCANCODE_F8
QT2SDL2[Qt.Key_F9] = SDL_SCANCODE_F9 QT2SDL2[Qt.Key.Key_F9] = SDL_SCANCODE_F9
QT2SDL2[Qt.Key_F10] = SDL_SCANCODE_F10 QT2SDL2[Qt.Key.Key_F10] = SDL_SCANCODE_F10
QT2SDL2[Qt.Key_F11] = SDL_SCANCODE_F11 QT2SDL2[Qt.Key.Key_F11] = SDL_SCANCODE_F11
QT2SDL2[Qt.Key_F12] = SDL_SCANCODE_F12 QT2SDL2[Qt.Key.Key_F12] = SDL_SCANCODE_F12
QT2SDL2[Qt.Key_F13] = SDL_SCANCODE_F13 QT2SDL2[Qt.Key.Key_F13] = SDL_SCANCODE_F13
QT2SDL2[Qt.Key_F14] = SDL_SCANCODE_F14 QT2SDL2[Qt.Key.Key_F14] = SDL_SCANCODE_F14
QT2SDL2[Qt.Key_F15] = SDL_SCANCODE_F15 QT2SDL2[Qt.Key.Key_F15] = SDL_SCANCODE_F15
QT2SDL2[Qt.Key_Insert] = SDL_SCANCODE_INSERT QT2SDL2[Qt.Key.Key_Insert] = SDL_SCANCODE_INSERT
QT2SDL2[Qt.Key_Delete] = SDL_SCANCODE_DELETE QT2SDL2[Qt.Key.Key_Delete] = SDL_SCANCODE_DELETE
QT2SDL2[Qt.Key_Home] = SDL_SCANCODE_HOME QT2SDL2[Qt.Key.Key_Home] = SDL_SCANCODE_HOME
QT2SDL2[Qt.Key_End] = SDL_SCANCODE_END QT2SDL2[Qt.Key.Key_End] = SDL_SCANCODE_END
QT2SDL2[Qt.Key_PageUp] = SDL_SCANCODE_PAGEUP QT2SDL2[Qt.Key.Key_PageUp] = SDL_SCANCODE_PAGEUP
QT2SDL2[Qt.Key_PageDown] = SDL_SCANCODE_PAGEDOWN QT2SDL2[Qt.Key.Key_PageDown] = SDL_SCANCODE_PAGEDOWN
QT2SDL2[Qt.Key_Up] = SDL_SCANCODE_UP QT2SDL2[Qt.Key.Key_Up] = SDL_SCANCODE_UP
QT2SDL2[Qt.Key_Down] = SDL_SCANCODE_DOWN QT2SDL2[Qt.Key.Key_Down] = SDL_SCANCODE_DOWN
QT2SDL2[Qt.Key_Left] = SDL_SCANCODE_LEFT QT2SDL2[Qt.Key.Key_Left] = SDL_SCANCODE_LEFT
QT2SDL2[Qt.Key_Right] = SDL_SCANCODE_RIGHT QT2SDL2[Qt.Key.Key_Right] = SDL_SCANCODE_RIGHT
QT2SDL2[Qt.Key_Return] = SDL_SCANCODE_RETURN QT2SDL2[Qt.Key.Key_Return] = SDL_SCANCODE_RETURN
QT2SDL2[Qt.Key_Enter] = SDL_SCANCODE_RETURN2 QT2SDL2[Qt.Key.Key_Enter] = SDL_SCANCODE_RETURN2
QT2SDL2[Qt.Key_Escape] = SDL_SCANCODE_ESCAPE QT2SDL2[Qt.Key.Key_Escape] = SDL_SCANCODE_ESCAPE
QT2SDL2[Qt.Key_Pause] = SDL_SCANCODE_PAUSE QT2SDL2[Qt.Key.Key_Pause] = SDL_SCANCODE_PAUSE
QT2SDL2[Qt.Key_QuoteLeft] = SDL_SCANCODE_GRAVE QT2SDL2[Qt.Key.Key_QuoteLeft] = SDL_SCANCODE_GRAVE
QT2SDL2[Qt.Key_Backspace] = SDL_SCANCODE_BACKSPACE QT2SDL2[Qt.Key.Key_Backspace] = SDL_SCANCODE_BACKSPACE
QT2SDL2[Qt.Key_Tab] = SDL_SCANCODE_TAB QT2SDL2[Qt.Key.Key_Tab] = SDL_SCANCODE_TAB
QT2SDL2[Qt.Key_CapsLock] = SDL_SCANCODE_CAPSLOCK QT2SDL2[Qt.Key.Key_CapsLock] = SDL_SCANCODE_CAPSLOCK
QT2SDL2[Qt.Key_Space] = SDL_SCANCODE_SPACE QT2SDL2[Qt.Key.Key_Space] = SDL_SCANCODE_SPACE
QT2SDL2[Qt.Key_Slash] = SDL_SCANCODE_SLASH QT2SDL2[Qt.Key.Key_Slash] = SDL_SCANCODE_SLASH
QT2SDL2[Qt.Key_Backslash] = SDL_SCANCODE_BACKSLASH QT2SDL2[Qt.Key.Key_Backslash] = SDL_SCANCODE_BACKSLASH
QT2SDL2[Qt.Key_Minus] = SDL_SCANCODE_MINUS QT2SDL2[Qt.Key.Key_Minus] = SDL_SCANCODE_MINUS
QT2SDL2[Qt.Key_Plus] = SDL_SCANCODE_UNKNOWN QT2SDL2[Qt.Key.Key_Plus] = SDL_SCANCODE_UNKNOWN
QT2SDL2[Qt.Key_Equal] = SDL_SCANCODE_EQUALS QT2SDL2[Qt.Key.Key_Equal] = SDL_SCANCODE_EQUALS
QT2SDL2[Qt.Key_BracketLeft] = SDL_SCANCODE_LEFTBRACKET QT2SDL2[Qt.Key.Key_BracketLeft] = SDL_SCANCODE_LEFTBRACKET
QT2SDL2[Qt.Key_BracketRight] = SDL_SCANCODE_RIGHTBRACKET QT2SDL2[Qt.Key.Key_BracketRight] = SDL_SCANCODE_RIGHTBRACKET
QT2SDL2[Qt.Key_Semicolon] = SDL_SCANCODE_SEMICOLON QT2SDL2[Qt.Key.Key_Semicolon] = SDL_SCANCODE_SEMICOLON
QT2SDL2[Qt.Key_Apostrophe] = SDL_SCANCODE_APOSTROPHE QT2SDL2[Qt.Key.Key_Apostrophe] = SDL_SCANCODE_APOSTROPHE
QT2SDL2[Qt.Key_Comma] = SDL_SCANCODE_COMMA QT2SDL2[Qt.Key.Key_Comma] = SDL_SCANCODE_COMMA
QT2SDL2[Qt.Key_Period] = SDL_SCANCODE_PERIOD QT2SDL2[Qt.Key.Key_Period] = SDL_SCANCODE_PERIOD
QT2SDL2[Qt.Key_Alt] = SDL_SCANCODE_LALT QT2SDL2[Qt.Key.Key_Alt] = SDL_SCANCODE_LALT
QT2SDL2[Qt.Key_Control] = SDL_SCANCODE_LCTRL QT2SDL2[Qt.Key.Key_Control] = SDL_SCANCODE_LCTRL
QT2SDL2[Qt.Key_Shift] = SDL_SCANCODE_LSHIFT QT2SDL2[Qt.Key.Key_Shift] = SDL_SCANCODE_LSHIFT
QT2SDL2[Qt.AltModifier.__int__()] = SDL_SCANCODE_LALT QT2SDL2[Qt.KeyboardModifier.AltModifier] = SDL_SCANCODE_LALT
QT2SDL2[Qt.ControlModifier.__int__()] = SDL_SCANCODE_LCTRL QT2SDL2[Qt.KeyboardModifier.ControlModifier] = SDL_SCANCODE_LCTRL
QT2SDL2[Qt.ShiftModifier.__int__()] = SDL_SCANCODE_LSHIFT QT2SDL2[Qt.KeyboardModifier.ShiftModifier] = SDL_SCANCODE_LSHIFT
QT2SDL2[Qt.Key_Print] = SDL_SCANCODE_PRINTSCREEN QT2SDL2[Qt.Key.Key_Print] = SDL_SCANCODE_PRINTSCREEN
QT2SDL2[Qt.Key_ScrollLock] = SDL_SCANCODE_SCROLLLOCK QT2SDL2[Qt.Key.Key_ScrollLock] = SDL_SCANCODE_SCROLLLOCK
QT2SDL2[Qt.Key_Meta] = SDL_SCANCODE_LGUI QT2SDL2[Qt.Key.Key_Meta] = SDL_SCANCODE_LGUI
QT2SDL2[Qt.MetaModifier.__int__()] = SDL_SCANCODE_LGUI QT2SDL2[Qt.KeyboardModifier.MetaModifier] = SDL_SCANCODE_LGUI
QT2SDL2[Qt.Key_Super_L] = SDL_SCANCODE_LGUI QT2SDL2[Qt.Key.Key_Super_L] = SDL_SCANCODE_LGUI
QT2SDL2[Qt.Key_Super_R] = SDL_SCANCODE_RGUI QT2SDL2[Qt.Key.Key_Super_R] = SDL_SCANCODE_RGUI
QT2SDL2[Qt.Key_unknown] = SDL_SCANCODE_UNKNOWN QT2SDL2[Qt.Key.Key_unknown] = SDL_SCANCODE_UNKNOWN
SCANCODE2KEYCODE[SDL_SCANCODE_A] = SDLK_a SCANCODE2KEYCODE[SDL_SCANCODE_A] = SDLK_a
SCANCODE2KEYCODE[SDL_SCANCODE_B] = SDLK_b SCANCODE2KEYCODE[SDL_SCANCODE_B] = SDLK_b

View file

@ -17,17 +17,17 @@
import sys import sys
import logging import logging
from PyQt5.QtCore import pyqtSignal from PyQt6.QtCore import pyqtSignal
from PyQt5.QtWidgets import QDialog from PyQt6.QtWidgets import QDialog
from PyQt5.QtGui import QTextCursor from PyQt6.QtGui import QTextCursor
from m64py.ui.logview_ui import Ui_LogView from m64py.ui.logview_ui import Ui_LogView
class Log: class Log:
def __init__(self, out=None, logview=None): def __init__(self, out=None, view=None):
self.out = out self.out = out
self.logview = logview self.logview = view
def write(self, msg): def write(self, msg):
if self.out: if self.out:
@ -50,7 +50,7 @@ class LogView(QDialog, Ui_LogView):
self.msg_written.connect(self.on_msg_written) self.msg_written.connect(self.on_msg_written)
def on_msg_written(self, msg): def on_msg_written(self, msg):
self.textEdit.moveCursor(QTextCursor.End) self.textEdit.moveCursor(QTextCursor.MoveOperation.End)
self.textEdit.insertPlainText(msg) self.textEdit.insertPlainText(msg)

View file

@ -17,10 +17,10 @@
import os import os
import sys import sys
from PyQt5.QtGui import QKeySequence, QPixmap, QOpenGLContext from PyQt6.QtGui import QKeySequence, QPixmap, QOpenGLContext, QAction, QActionGroup
from PyQt5.QtWidgets import QApplication, QMainWindow, QGraphicsView, QGraphicsScene, QGraphicsPixmapItem from PyQt6.QtWidgets import QApplication, QMainWindow, QGraphicsView, QGraphicsScene, QGraphicsPixmapItem
from PyQt5.QtWidgets import QAction, QLabel, QFileDialog, QStackedWidget, QActionGroup, QSizePolicy, QWidget, QDialog from PyQt6.QtWidgets import QLabel, QFileDialog, QStackedWidget, QSizePolicy, QWidget, QDialog
from PyQt5.QtCore import Qt, QTimer, QFileInfo, QEvent, QMargins, pyqtSignal, pyqtSlot from PyQt6.QtCore import Qt, QTimer, QFileInfo, QEvent, QMargins, pyqtSignal, pyqtSlot
from m64py.core.defs import * from m64py.core.defs import *
from m64py.frontend.dialogs import * from m64py.frontend.dialogs import *
@ -34,6 +34,9 @@ from m64py.frontend.settings import Settings
from m64py.frontend.glwidget import GLWidget from m64py.frontend.glwidget import GLWidget
from m64py.ui.mainwindow_ui import Ui_MainWindow from m64py.ui.mainwindow_ui import Ui_MainWindow
from m64py.frontend.recentfiles import RecentFiles from m64py.frontend.recentfiles import RecentFiles
from m64py.frontend.keymap import QT2SDL2
from m64py.ui import icons_rc
from m64py.ui import images_rc
class MainWindow(QMainWindow, Ui_MainWindow): class MainWindow(QMainWindow, Ui_MainWindow):
@ -61,11 +64,11 @@ class MainWindow(QMainWindow, Ui_MainWindow):
self._initialize_attempt = 0 self._initialize_attempt = 0
logview.setParent(self) logview.setParent(self)
logview.setWindowFlags(Qt.Dialog) logview.setWindowFlags(Qt.WindowType.Dialog)
self.statusbar_label = QLabel() self.statusbar_label = QLabel()
self.statusbar_label.setIndent(2) self.statusbar_label.setIndent(2)
self.statusbar_label.setSizePolicy(QSizePolicy.Ignored, QSizePolicy.Fixed) self.statusbar_label.setSizePolicy(QSizePolicy.Policy.Ignored, QSizePolicy.Policy.Fixed)
self.statusbar.addPermanentWidget(self.statusbar_label, 1) self.statusbar.addPermanentWidget(self.statusbar_label, 1)
self.update_status(self.tr( self.update_status(self.tr(
"Welcome to M64Py version %s." % FRONTEND_VERSION)) "Welcome to M64Py version %s." % FRONTEND_VERSION))
@ -97,10 +100,11 @@ class MainWindow(QMainWindow, Ui_MainWindow):
self.worker.quit() self.worker.quit()
def changeEvent(self, event): def changeEvent(self, event):
if event.type() == QEvent.WindowStateChange: if event.type() == QEvent.Type.WindowStateChange:
if event.oldState() == Qt.WindowMaximized: if event.oldState() == Qt.WindowState.WindowMaximized:
self.maximized = False self.maximized = False
elif event.oldState() == Qt.WindowNoState and self.windowState() == Qt.WindowMaximized: elif (event.oldState() == Qt.WindowState.WindowNoState and
self.windowState() == Qt.WindowState.WindowMaximized):
self.maximized = True self.maximized = True
def resizeEvent(self, event): def resizeEvent(self, event):
@ -123,6 +127,37 @@ class MainWindow(QMainWindow, Ui_MainWindow):
self.create_size_actions() self.create_size_actions()
self.center_widget() self.center_widget()
def keyPressEvent(self, event):
if self.worker.state != M64EMU_RUNNING:
return
key = event.key()
modifiers = event.modifiers()
if modifiers & Qt.KeyboardModifier.AltModifier and (key == Qt.Key.Key_Enter or key == Qt.Key.Key_Return):
self.toggle_fs.emit()
elif key == Qt.Key.Key_F3:
self.worker.save_title()
elif key == Qt.Key.Key_F4:
self.worker.save_snapshot()
else:
try:
sdl_key = QT2SDL2[key]
self.worker.send_sdl_keydown(sdl_key)
except KeyError:
pass
def keyReleaseEvent(self, event):
if self.worker.state != M64EMU_RUNNING:
return
key = event.key()
try:
sdl_key = QT2SDL2[key]
self.worker.send_sdl_keyup(sdl_key)
except KeyError:
pass
def window_size_triggered(self, size): def window_size_triggered(self, size):
window_width, window_height = size window_width, window_height = size
if self.vidext and self.worker.core.get_handle(): if self.vidext and self.worker.core.get_handle():
@ -172,7 +207,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
def center_widget(self): def center_widget(self):
"""Centers widget on desktop.""" """Centers widget on desktop."""
size = self.size() size = self.size()
desktop = QApplication.desktop() desktop = self.screen().geometry()
width, height = size.width(), size.height() width, height = size.width(), size.height()
dwidth, dheight = desktop.width(), desktop.height() dwidth, dheight = desktop.width(), desktop.height()
cw, ch = (dwidth/2)-(width/2), (dheight/2)-(height/2) cw, ch = (dwidth/2)-(width/2), (dheight/2)-(height/2)
@ -196,7 +231,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
"""Creates central widgets.""" """Creates central widgets."""
self.stack = QStackedWidget(None) self.stack = QStackedWidget(None)
palette = self.stack.palette() palette = self.stack.palette()
palette.setColor(self.stack.backgroundRole(), Qt.black) palette.setColor(self.stack.backgroundRole(), Qt.GlobalColor.black)
self.stack.setPalette(palette) self.stack.setPalette(palette)
self.stack.setAutoFillBackground(True) self.stack.setAutoFillBackground(True)
@ -251,13 +286,16 @@ class MainWindow(QMainWindow, Ui_MainWindow):
else: else:
self.menubar.hide() self.menubar.hide()
self.statusbar.hide() self.statusbar.hide()
self.setWindowState(self.windowState() ^ Qt.WindowFullScreen) self.setWindowState(self.windowState() ^ Qt.WindowState.WindowFullScreen)
def on_file_open(self, filepath=None, filename=None): def on_file_open(self, filepath=None, filename=None):
"""Opens ROM file.""" """Opens ROM file."""
if not filepath: if not filepath:
action = self.sender() action = self.sender()
filepath = action.data() filepath = action.data()
if not os.path.isfile(filepath):
InfoDialog(self, "File %s not found." % filepath).exec()
return
self.worker.core_state_query(M64CORE_EMU_STATE) self.worker.core_state_query(M64CORE_EMU_STATE)
if self.worker.state in [M64EMU_RUNNING, M64EMU_PAUSED]: if self.worker.state in [M64EMU_RUNNING, M64EMU_PAUSED]:
self.worker.stop() self.worker.stop()
@ -291,10 +329,10 @@ class MainWindow(QMainWindow, Ui_MainWindow):
def on_archive_dialog(self, files): def on_archive_dialog(self, files):
"""Shows archive dialog.""" """Shows archive dialog."""
archive = ArchiveDialog(self, files) archive = ArchiveDialog(self, files)
rval = archive.exec_() rval = archive.exec()
if rval == QDialog.Accepted: if rval == QDialog.DialogCode.Accepted:
curr_item = archive.listWidget.currentItem() curr_item = archive.listWidget.currentItem()
fname = curr_item.data(Qt.UserRole) fname = curr_item.data(Qt.ItemDataRole.UserRole)
self.worker.filename = fname self.worker.filename = fname
def on_state_changed(self, states): def on_state_changed(self, states):
@ -324,9 +362,9 @@ class MainWindow(QMainWindow, Ui_MainWindow):
self.actionGraphics.setEnabled(not action) self.actionGraphics.setEnabled(not action)
self.actionPlugins.setEnabled(not action) self.actionPlugins.setEnabled(not action)
def wait_for_initialize(self):
"""Wait up to 10 seconds for core initialization, checking once a second. """Wait up to 10 seconds for core initialization, checking once a second.
If not yet initialized, start another QTimer. Else, toggle UI actions.""" If not yet initialized, start another QTimer. Else, toggle UI actions."""
def wait_for_initialize(self):
if self.worker.core_state_query(M64CORE_EMU_STATE) == M64EMU_STOPPED: if self.worker.core_state_query(M64CORE_EMU_STATE) == M64EMU_STOPPED:
self._initialize_attempt += 1 self._initialize_attempt += 1
if self._initialize_attempt < 10: if self._initialize_attempt < 10:
@ -361,7 +399,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
def on_actionManually_triggered(self): def on_actionManually_triggered(self):
"""Shows ROM file dialog.""" """Shows ROM file dialog."""
dialog = QFileDialog() dialog = QFileDialog()
dialog.setFileMode(QFileDialog.ExistingFile) dialog.setFileMode(QFileDialog.FileMode.ExistingFile)
last_dir = self.settings.qset.value("last_dir") last_dir = self.settings.qset.value("last_dir")
file_path, _ = dialog.getOpenFileName( file_path, _ = dialog.getOpenFileName(
self, self.tr("Load ROM Image"), last_dir, self, self.tr("Load ROM Image"), last_dir,
@ -395,7 +433,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
def on_actionLoadFrom_triggered(self): def on_actionLoadFrom_triggered(self):
"""Loads state from file.""" """Loads state from file."""
dialog = QFileDialog() dialog = QFileDialog()
dialog.setFileMode(QFileDialog.ExistingFile) dialog.setFileMode(QFileDialog.FileMode.ExistingFile)
file_path, _ = dialog.getOpenFileName( file_path, _ = dialog.getOpenFileName(
self, self.tr("Load State From File"), self, self.tr("Load State From File"),
os.path.join(self.worker.core.config.get_path("UserData"), "save"), os.path.join(self.worker.core.config.get_path("UserData"), "save"),
@ -518,6 +556,6 @@ class View(QGraphicsView):
QGraphicsView.__init__(self, parent) QGraphicsView.__init__(self, parent)
self.setContentsMargins(QMargins()) self.setContentsMargins(QMargins())
self.setStyleSheet("QGraphicsView {border:0px solid;margin:0px;}") self.setStyleSheet("QGraphicsView {border:0px solid;margin:0px;}")
self.setResizeAnchor(QGraphicsView.AnchorViewCenter) self.setResizeAnchor(QGraphicsView.ViewportAnchor.AnchorViewCenter)
self.setScene(QGraphicsScene(self)) self.setScene(QGraphicsScene(self))
self.scene().addItem(QGraphicsPixmapItem(QPixmap(":/images/front.png"))) self.scene().addItem(QGraphicsPixmapItem(QPixmap(":/images/front.png")))

View file

@ -14,8 +14,8 @@
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
from PyQt5.QtCore import Qt from PyQt6.QtCore import Qt
from PyQt5.QtWidgets import QDialog, QLabel, QSpinBox, QComboBox, QLineEdit, QCheckBox from PyQt6.QtWidgets import QDialog, QLabel, QSpinBox, QComboBox, QLineEdit, QCheckBox
import re import re
from m64py.core.defs import * from m64py.core.defs import *
@ -84,8 +84,8 @@ class Plugin(QDialog, Ui_PluginDialog):
widget = QLineEdit() widget = QLineEdit()
widget.setToolTip(param_help) widget.setToolTip(param_help)
self.gridLayout.addWidget( self.gridLayout.addWidget(
QLabel(format_label(param_desc)), row1, 1, Qt.AlignRight) QLabel(format_label(param_desc)), row1, 1, Qt.AlignmentFlag.AlignRight)
self.gridLayout.addWidget(widget, row1, 2, Qt.AlignLeft) self.gridLayout.addWidget(widget, row1, 2, Qt.AlignmentFlag.AlignLeft)
self.widgets[param_name] = (widget, widget.__class__, opts) self.widgets[param_name] = (widget, widget.__class__, opts)
elif param_type == M64TYPE_INT: elif param_type == M64TYPE_INT:
row1 += 1 row1 += 1
@ -98,7 +98,7 @@ class Plugin(QDialog, Ui_PluginDialog):
widget = QComboBox() widget = QComboBox()
widget.setToolTip(param_help) widget.setToolTip(param_help)
widget.setMinimumContentsLength(14) widget.setMinimumContentsLength(14)
widget.setSizeAdjustPolicy(QComboBox.AdjustToMinimumContentsLength) widget.setSizeAdjustPolicy(QComboBox.SizeAdjustPolicy.AdjustToMinimumContentsLengthWithIcon)
for idx, key in enumerate(sorted(opts.keys())): for idx, key in enumerate(sorted(opts.keys())):
value = opts[key] value = opts[key]
opts[key] = (idx, value) opts[key] = (idx, value)
@ -106,8 +106,8 @@ class Plugin(QDialog, Ui_PluginDialog):
widget.addItem(value) widget.addItem(value)
widget.setItemData(idx, data) widget.setItemData(idx, data)
self.gridLayout.addWidget( self.gridLayout.addWidget(
QLabel(format_label(param_desc)), row1, 1, Qt.AlignRight) QLabel(format_label(param_desc)), row1, 1, Qt.AlignmentFlag.AlignRight)
self.gridLayout.addWidget(widget, row1, 2, Qt.AlignLeft) self.gridLayout.addWidget(widget, row1, 2, Qt.AlignmentFlag.AlignLeft)
self.widgets[param_name] = (widget, widget.__class__, opts) self.widgets[param_name] = (widget, widget.__class__, opts)
elif param_type == M64TYPE_BOOL: elif param_type == M64TYPE_BOOL:
row2 += 1 row2 += 1

View file

@ -14,9 +14,8 @@
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
from PyQt5.QtGui import QIcon, QPixmap from PyQt6.QtGui import QIcon, QPixmap, QAction
from PyQt5.QtWidgets import QAction from PyQt6.QtCore import QFileInfo
from PyQt5.QtCore import QFileInfo
class RecentFiles(): class RecentFiles():

View file

@ -16,7 +16,7 @@
import os import os
from PyQt5.QtWidgets import QMessageBox from PyQt6.QtWidgets import QMessageBox
from m64py.utils import sl from m64py.utils import sl

View file

@ -16,9 +16,9 @@
import os import os
from PyQt5.QtCore import Qt from PyQt6.QtCore import Qt
from PyQt5.QtGui import QPixmap from PyQt6.QtGui import QPixmap
from PyQt5.QtWidgets import QMainWindow, QDesktopWidget, QListWidgetItem, QGraphicsPixmapItem from PyQt6.QtWidgets import QMainWindow, QListWidgetItem, QGraphicsPixmapItem
from m64py.frontend.romreader import ROMReader from m64py.frontend.romreader import ROMReader
from m64py.ui.romlist_ui import Ui_ROMList from m64py.ui.romlist_ui import Ui_ROMList
@ -37,7 +37,7 @@ class ROMList(QMainWindow, Ui_ROMList):
"""Constructor.""" """Constructor."""
QMainWindow.__init__(self, parent) QMainWindow.__init__(self, parent)
self.setupUi(self) self.setupUi(self)
self.setAttribute(Qt.WA_DeleteOnClose, True) self.setAttribute(Qt.WidgetAttribute.WA_DeleteOnClose, True)
self.parent = parent self.parent = parent
self.core = self.parent.worker.core self.core = self.parent.worker.core
@ -47,7 +47,7 @@ class ROMList(QMainWindow, Ui_ROMList):
self.snapshot_item = None self.snapshot_item = None
rect = self.frameGeometry() rect = self.frameGeometry()
rect.moveCenter(QDesktopWidget().availableGeometry().center()) rect.moveCenter(self.screen().geometry().center())
self.move(rect.topLeft()) self.move(rect.topLeft())
self.splitter.setStretchFactor(0, 1) self.splitter.setStretchFactor(0, 1)
self.splitter.setStretchFactor(1, 2) self.splitter.setStretchFactor(1, 2)
@ -73,7 +73,7 @@ class ROMList(QMainWindow, Ui_ROMList):
self.reader.stop() self.reader.stop()
def keyPressEvent(self, event): def keyPressEvent(self, event):
if event.key() == Qt.Key_Escape: if event.key() == Qt.Key.Key_Escape:
self.close() self.close()
def connect_signals(self): def connect_signals(self):
@ -95,7 +95,7 @@ class ROMList(QMainWindow, Ui_ROMList):
if isinstance(goodname, bytes): if isinstance(goodname, bytes):
goodname = goodname.decode() goodname = goodname.decode()
list_item = QListWidgetItem(goodname) list_item = QListWidgetItem(goodname)
list_item.setData(Qt.UserRole, (crc, goodname, path, fname)) list_item.setData(Qt.ItemDataRole.UserRole, (crc, goodname, path, fname))
self.listWidget.addItem(list_item) self.listWidget.addItem(list_item)
self.progressBar.setValue(0) self.progressBar.setValue(0)
self.progressBar.hide() self.progressBar.hide()
@ -135,19 +135,19 @@ class ROMList(QMainWindow, Ui_ROMList):
def on_item_open(self): def on_item_open(self):
item = self.listWidget.currentItem() item = self.listWidget.currentItem()
crc, goodname, path, fname = item.data(Qt.UserRole) crc, goodname, path, fname = item.data(Qt.ItemDataRole.UserRole)
if path: if path:
self.file_open(path, fname) self.file_open(path, fname)
def on_item_activated(self, item): def on_item_activated(self, item):
crc, goodname, path, fname = item.data(Qt.UserRole) crc, goodname, path, fname = item.data(Qt.ItemDataRole.UserRole)
if path: if path:
self.file_open(path, fname) self.file_open(path, fname)
def on_item_changed(self, current, previous): def on_item_changed(self, current, previous):
if not current: if not current:
return return
crc, goodname, path, fname = current.data(Qt.UserRole) crc, goodname, path, fname = current.data(Qt.ItemDataRole.UserRole)
title = QPixmap(os.path.join( title = QPixmap(os.path.join(
self.user_data_path, "title", "%s.png") % crc) self.user_data_path, "title", "%s.png") % crc)
@ -169,9 +169,9 @@ class ROMList(QMainWindow, Ui_ROMList):
self.snapshotView.scene().removeItem(self.snapshot_item) self.snapshotView.scene().removeItem(self.snapshot_item)
title_pixmap = title.scaled( title_pixmap = title.scaled(
self.titleView.size(), Qt.KeepAspectRatio, Qt.SmoothTransformation) self.titleView.size(), Qt.AspectRatioMode.KeepAspectRatio, Qt.TransformationMode.SmoothTransformation)
snapshot_pixmap = snapshot.scaled( snapshot_pixmap = snapshot.scaled(
self.snapshotView.size(), Qt.KeepAspectRatio, Qt.SmoothTransformation) self.snapshotView.size(), Qt.AspectRatioMode.KeepAspectRatio, Qt.TransformationMode.SmoothTransformation)
title_item = QGraphicsPixmapItem(title_pixmap) title_item = QGraphicsPixmapItem(title_pixmap)
snapshot_item = QGraphicsPixmapItem(snapshot_pixmap) snapshot_item = QGraphicsPixmapItem(snapshot_pixmap)

View file

@ -18,7 +18,7 @@ import os
import ctypes import ctypes
import fnmatch import fnmatch
from PyQt5.QtCore import QThread from PyQt6.QtCore import QThread
from m64py.utils import sl from m64py.utils import sl
from m64py.core.defs import M64pRomHeader from m64py.core.defs import M64pRomHeader
@ -99,7 +99,7 @@ class ROMReader(QThread):
crc2 |= ((crc2_pre >> 24) & 0xff) << 0 crc2 |= ((crc2_pre >> 24) & 0xff) << 0
else: else:
return None return None
return (crc1, crc2) return crc1, crc2
def read_files(self): def read_files(self):
"""Reads files.""" """Reads files."""
@ -115,9 +115,11 @@ class ROMReader(QThread):
if crc_tuple: if crc_tuple:
rom_settings = self.parent.core.get_rom_settings( rom_settings = self.parent.core.get_rom_settings(
crc_tuple[0], crc_tuple[1]) crc_tuple[0], crc_tuple[1])
if rom_settings:
crc = "%X%X" % (crc_tuple[0], crc_tuple[1]) crc = "%X%X" % (crc_tuple[0], crc_tuple[1])
if rom_settings:
self.roms.append((crc, rom_settings.goodname, fullpath, fname)) self.roms.append((crc, rom_settings.goodname, fullpath, fname))
else:
self.roms.append((crc, os.path.splitext(os.path.basename(fname))[0], fullpath, fname))
archive.close() archive.close()
except Exception as err: except Exception as err:
log.warn(str(err)) log.warn(str(err))
@ -135,4 +137,4 @@ class ROMReader(QThread):
def run(self): def run(self):
"""Starts thread.""" """Starts thread."""
self.read_files() self.read_files()
self.exec_() self.exec()

View file

@ -17,8 +17,8 @@
import os import os
import sys import sys
from PyQt5.QtCore import Qt, QSettings from PyQt6.QtCore import Qt, QSettings
from PyQt5.QtWidgets import QDialog, QFileDialog, QRadioButton, QVBoxLayout from PyQt6.QtWidgets import QDialog, QFileDialog, QRadioButton, QVBoxLayout
from m64py.core.defs import * from m64py.core.defs import *
from m64py.loader import find_library from m64py.loader import find_library
@ -42,7 +42,7 @@ class Settings(QDialog, Ui_Settings):
self.combomap = {} self.combomap = {}
self.qset = QSettings("m64py", "m64py") self.qset = QSettings("m64py", "m64py")
self.qset.setDefaultFormat(QSettings.IniFormat) self.qset.setDefaultFormat(QSettings.Format.IniFormat)
self.add_items() self.add_items()
self.connect_signals() self.connect_signals()
@ -130,11 +130,11 @@ class Settings(QDialog, Ui_Settings):
widget, groupbox, directory = args widget, groupbox, directory = args
dialog = QFileDialog() dialog = QFileDialog()
if directory: if directory:
dialog.setFileMode(QFileDialog.Directory) dialog.setFileMode(QFileDialog.FileMode.Directory)
path = dialog.getExistingDirectory( path = dialog.getExistingDirectory(
self, groupbox.title(), widget.text(), QFileDialog.ShowDirsOnly) self, groupbox.title(), widget.text(), QFileDialog.Option.ShowDirsOnly)
else: else:
dialog.setFileMode(QFileDialog.ExistingFile) dialog.setFileMode(QFileDialog.FileMode.ExistingFile)
path, _ = dialog.getOpenFileName( path, _ = dialog.getOpenFileName(
self, groupbox.title(), widget.text(), self, groupbox.title(), widget.text(),
"%s (*%s);;All files (*)" % (groupbox.title(), DLL_FILTER)) "%s (*%s);;All files (*)" % (groupbox.title(), DLL_FILTER))
@ -297,7 +297,7 @@ class Settings(QDialog, Ui_Settings):
combo.addItem(name) combo.addItem(name)
index = combo.findText(str(name)) index = combo.findText(str(name))
combo.setItemData(index, plugin_desc) combo.setItemData(index, plugin_desc)
combo.setItemData(index, plugin_desc, Qt.ToolTipRole) combo.setItemData(index, plugin_desc, Qt.ItemDataRole.ToolTipRole)
current = self.qset.value("Plugins/%s" % ( current = self.qset.value("Plugins/%s" % (
PLUGIN_NAME[plugin_type]), PLUGIN_DEFAULT[plugin_type]) PLUGIN_NAME[plugin_type]), PLUGIN_DEFAULT[plugin_type])
index = combo.findText(current) index = combo.findText(current)
@ -319,7 +319,7 @@ class Settings(QDialog, Ui_Settings):
"%sx%s" % (w, h), (w, h)) "%sx%s" % (w, h), (w, h))
index = self.comboResolution.findText( index = self.comboResolution.findText(
"%sx%s" % (width, height), Qt.MatchExactly) "%sx%s" % (width, height), Qt.MatchFlag.MatchExactly)
if index == -1: index = 0 if index == -1: index = 0
self.comboResolution.setCurrentIndex(index) self.comboResolution.setCurrentIndex(index)
self.comboResolution.setEnabled(not self.parent.vidext) self.comboResolution.setEnabled(not self.parent.vidext)

View file

@ -17,7 +17,7 @@
import os import os
import shutil import shutil
from PyQt5.QtCore import QThread, QTimer from PyQt6.QtCore import QThread, QTimer
from sdl2 import SDL_EnableScreenSaver, SDL_DisableScreenSaver from sdl2 import SDL_EnableScreenSaver, SDL_DisableScreenSaver
from m64py.utils import sl from m64py.utils import sl

View file

@ -45,10 +45,9 @@
&lt;html&gt;&lt;head&gt;&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; /&gt;&lt;style type=&quot;text/css&quot;&gt; &lt;html&gt;&lt;head&gt;&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; /&gt;&lt;style type=&quot;text/css&quot;&gt;
p, li { white-space: pre-wrap; } p, li { white-space: pre-wrap; }
&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:'Sans Serif'; font-size:9pt; font-weight:400; font-style:normal;&quot;&gt; &lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:'Sans Serif'; font-size:9pt; font-weight:400; font-style:normal;&quot;&gt;
&lt;p align=&quot;center&quot; style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-size:10pt; color:#000000;&quot;&gt;M64Py version: FRONTEND_VERSION&lt;/span&gt;&lt;/p&gt; &lt;p align=&quot;center&quot; style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;a href=&quot;https://m64py.sourceforge.net/&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#0000ff;&quot;&gt;M64Py&lt;/span&gt;&lt;/a&gt;&lt;span style=&quot; font-size:10pt;&quot;&gt; version: FRONTEND_VERSION&lt;/span&gt;&lt;/p&gt;
&lt;p align=&quot;center&quot; style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-size:10pt; font-style:italic;&quot;&gt;A frontend for Mupen64Plus.&lt;/span&gt;&lt;/p&gt; &lt;p align=&quot;center&quot; style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-size:10pt; font-style:italic;&quot;&gt;A frontend for Mupen64Plus.&lt;/span&gt;&lt;/p&gt;
&lt;p align=&quot;center&quot; style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;a href=&quot;http://m64py.sourceforge.net&quot;&gt;&lt;span style=&quot; font-size:10pt; text-decoration: underline; color:#0000ff;&quot;&gt;http://m64py.sourceforge.net&lt;/span&gt;&lt;/a&gt;&lt;/p&gt; &lt;p align=&quot;center&quot; style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p align=&quot;center&quot; style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:10pt; text-decoration: underline; color:#0000ff;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p align=&quot;center&quot; style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-size:10pt;&quot;&gt;Author: Milan Nikolic (gen2brain)&lt;/span&gt;&lt;/p&gt; &lt;p align=&quot;center&quot; style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-size:10pt;&quot;&gt;Author: Milan Nikolic (gen2brain)&lt;/span&gt;&lt;/p&gt;
&lt;p align=&quot;center&quot; style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-size:10pt;&quot;&gt;This program is released under the terms of the&lt;/span&gt;&lt;/p&gt; &lt;p align=&quot;center&quot; style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-size:10pt;&quot;&gt;This program is released under the terms of the&lt;/span&gt;&lt;/p&gt;
&lt;p align=&quot;center&quot; style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;a href=&quot;http://www.gnu.org/licenses/gpl-3.0.txt&quot;&gt;&lt;span style=&quot; font-size:10pt; text-decoration: underline; color:#0000ff;&quot;&gt;GNU General Public License version 3&lt;/span&gt;&lt;/a&gt;&lt;span style=&quot; font-size:10pt;&quot;&gt;.&lt;/span&gt;&lt;/p&gt; &lt;p align=&quot;center&quot; style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;a href=&quot;http://www.gnu.org/licenses/gpl-3.0.txt&quot;&gt;&lt;span style=&quot; font-size:10pt; text-decoration: underline; color:#0000ff;&quot;&gt;GNU General Public License version 3&lt;/span&gt;&lt;/a&gt;&lt;span style=&quot; font-size:10pt;&quot;&gt;.&lt;/span&gt;&lt;/p&gt;
@ -68,65 +67,65 @@ p, li { white-space: pre-wrap; }
<string notr="true">&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.0//EN&quot; &quot;http://www.w3.org/TR/REC-html40/strict.dtd&quot;&gt; <string notr="true">&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.0//EN&quot; &quot;http://www.w3.org/TR/REC-html40/strict.dtd&quot;&gt;
&lt;html&gt;&lt;head&gt;&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; /&gt;&lt;style type=&quot;text/css&quot;&gt; &lt;html&gt;&lt;head&gt;&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; /&gt;&lt;style type=&quot;text/css&quot;&gt;
p, li { white-space: pre-wrap; } p, li { white-space: pre-wrap; }
&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:'Liberation Sans'; font-size:10pt; font-weight:400; font-style:normal;&quot;&gt; &lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:'Sans Serif'; font-size:9pt; font-weight:400; font-style:normal;&quot;&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'Sans Serif';&quot;&gt;Mupen64Plus is licensed under the&lt;/span&gt;&lt;/p&gt; &lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-size:10pt;&quot;&gt;Mupen64Plus is licensed under the&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;a href=&quot;http://www.gnu.org/licenses/gpl-2.0.txt&quot;&gt;&lt;span style=&quot; font-family:'Sans Serif'; text-decoration: underline; color:#0000ff;&quot;&gt;GNU General Public License version 2&lt;/span&gt;&lt;/a&gt;&lt;span style=&quot; font-family:'Sans Serif';&quot;&gt;.&lt;/span&gt;&lt;/p&gt; &lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;a href=&quot;http://www.gnu.org/licenses/gpl-2.0.txt&quot;&gt;&lt;span style=&quot; font-size:10pt; text-decoration: underline; color:#0000ff;&quot;&gt;GNU General Public License version 2&lt;/span&gt;&lt;/a&gt;&lt;span style=&quot; font-size:10pt;&quot;&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Sans Serif';&quot;&gt;&lt;br /&gt;&lt;/p&gt; &lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:10pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'Sans Serif';&quot;&gt;The authors of Mupen64Plus are:&lt;/span&gt;&lt;/p&gt; &lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-size:10pt;&quot;&gt;The authors of Mupen64Plus are:&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'Sans Serif';&quot;&gt; * Richard Goedeken (Richard42)&lt;/span&gt;&lt;/p&gt; &lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-size:10pt;&quot;&gt; * Richard Goedeken (Richard42)&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'Sans Serif';&quot;&gt; * Sven Eckelmann (ecsv)&lt;/span&gt;&lt;/p&gt; &lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-size:10pt;&quot;&gt; * Sven Eckelmann (ecsv)&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'Sans Serif';&quot;&gt; * John Chadwick (NMN)&lt;/span&gt;&lt;/p&gt; &lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-size:10pt;&quot;&gt; * John Chadwick (NMN)&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'Sans Serif';&quot;&gt; * James Hood (Ebenblues)&lt;/span&gt;&lt;/p&gt; &lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-size:10pt;&quot;&gt; * James Hood (Ebenblues)&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'Sans Serif';&quot;&gt; * Scott Gorman (okaygo)&lt;/span&gt;&lt;/p&gt; &lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-size:10pt;&quot;&gt; * Scott Gorman (okaygo)&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'Sans Serif';&quot;&gt; * Scott Knauert (Tillin9)&lt;/span&gt;&lt;/p&gt; &lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-size:10pt;&quot;&gt; * Scott Knauert (Tillin9)&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'Sans Serif';&quot;&gt; * Jesse Dean (DarkJezter)&lt;/span&gt;&lt;/p&gt; &lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-size:10pt;&quot;&gt; * Jesse Dean (DarkJezter)&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'Sans Serif';&quot;&gt; * Louai Al-Khanji (slougi)&lt;/span&gt;&lt;/p&gt; &lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-size:10pt;&quot;&gt; * Louai Al-Khanji (slougi)&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'Sans Serif';&quot;&gt; * Bob Forder (orbitaldecay)&lt;/span&gt;&lt;/p&gt; &lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-size:10pt;&quot;&gt; * Bob Forder (orbitaldecay)&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'Sans Serif';&quot;&gt; * Jason Espinosa (hasone)&lt;/span&gt;&lt;/p&gt; &lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-size:10pt;&quot;&gt; * Jason Espinosa (hasone)&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'Sans Serif';&quot;&gt; * Bobby Smiles (bsmiles32)&lt;/span&gt;&lt;/p&gt; &lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-size:10pt;&quot;&gt; * Bobby Smiles (bsmiles32)&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'Sans Serif';&quot;&gt; * Dorian Fevrier (Narann)&lt;/span&gt;&lt;/p&gt; &lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-size:10pt;&quot;&gt; * Dorian Fevrier (Narann)&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'Sans Serif';&quot;&gt; * Richard Hender (ricrpi)&lt;/span&gt;&lt;/p&gt; &lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-size:10pt;&quot;&gt; * Richard Hender (ricrpi)&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'Sans Serif';&quot;&gt; * Will Nayes (wnayes)&lt;/span&gt;&lt;/p&gt; &lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-size:10pt;&quot;&gt; * Will Nayes (wnayes)&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'Sans Serif';&quot;&gt; * Conchur Navid&lt;/span&gt;&lt;/p&gt; &lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-size:10pt;&quot;&gt; * Conchur Navid&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'Sans Serif';&quot;&gt; * Gillou68310&lt;/span&gt;&lt;/p&gt; &lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-size:10pt;&quot;&gt; * Gillou68310&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'Sans Serif';&quot;&gt; * HyperHacker&lt;/span&gt;&lt;/p&gt; &lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-size:10pt;&quot;&gt; * HyperHacker&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'Sans Serif';&quot;&gt; * littleguy77&lt;/span&gt;&lt;/p&gt; &lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-size:10pt;&quot;&gt; * littleguy77&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'Sans Serif';&quot;&gt; * Nebuleon&lt;/span&gt;&lt;/p&gt; &lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-size:10pt;&quot;&gt; * Nebuleon&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'Sans Serif';&quot;&gt; * and others.&lt;/span&gt;&lt;/p&gt; &lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-size:10pt;&quot;&gt; * and others.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Sans Serif';&quot;&gt;&lt;br /&gt;&lt;/p&gt; &lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:10pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'Sans Serif';&quot;&gt;The Mupen64Plus API documentation (located in doc/emuwiki-api-doc/*) is Copyright(C) 2009-2011&lt;/span&gt;&lt;/p&gt; &lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-size:10pt;&quot;&gt;The Mupen64Plus API documentation (located in doc/emuwiki-api-doc/*) is Copyright(C) 2009-2011&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'Sans Serif';&quot;&gt;by Richard Goedeken and is licensed under the GNU General Public License version 2.&lt;/span&gt;&lt;/p&gt; &lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-size:10pt;&quot;&gt;by Richard Goedeken and is licensed under the GNU General Public License version 2.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Sans Serif';&quot;&gt;&lt;br /&gt;&lt;/p&gt; &lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:10pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'Sans Serif';&quot;&gt;Mupen64Plus is based on GPL-licensed source code from Mupen64 v0.5, originally written by:&lt;/span&gt;&lt;/p&gt; &lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-size:10pt;&quot;&gt;Mupen64Plus is based on GPL-licensed source code from Mupen64 v0.5, originally written by:&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'Sans Serif';&quot;&gt; * Hacktarux&lt;/span&gt;&lt;/p&gt; &lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-size:10pt;&quot;&gt; * Hacktarux&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'Sans Serif';&quot;&gt; * Dave2001&lt;/span&gt;&lt;/p&gt; &lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-size:10pt;&quot;&gt; * Dave2001&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'Sans Serif';&quot;&gt; * Zilmar&lt;/span&gt;&lt;/p&gt; &lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-size:10pt;&quot;&gt; * Zilmar&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'Sans Serif';&quot;&gt; * Gregor Anich (Blight)&lt;/span&gt;&lt;/p&gt; &lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-size:10pt;&quot;&gt; * Gregor Anich (Blight)&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'Sans Serif';&quot;&gt; * Juha Luotio (JttL)&lt;/span&gt;&lt;/p&gt; &lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-size:10pt;&quot;&gt; * Juha Luotio (JttL)&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'Sans Serif';&quot;&gt; * and others.&lt;/span&gt;&lt;/p&gt; &lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-size:10pt;&quot;&gt; * and others.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Sans Serif';&quot;&gt;&lt;br /&gt;&lt;/p&gt; &lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:10pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'Sans Serif';&quot;&gt;GPL-license demo rom (mupen64plus.v64) is written by:&lt;/span&gt;&lt;/p&gt; &lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-size:10pt;&quot;&gt;GPL-license demo rom (mupen64plus.v64) is written by:&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'Sans Serif';&quot;&gt; * Marshallh&lt;/span&gt;&lt;/p&gt; &lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-size:10pt;&quot;&gt; * Marshallh&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Sans Serif';&quot;&gt;&lt;br /&gt;&lt;/p&gt; &lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:10pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'Sans Serif';&quot;&gt;The OGLFT library used for the On-Screen Display is based on GPL/LGPL-licensed code Copyright 2002 lignum Computing.&lt;/span&gt;&lt;/p&gt; &lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-size:10pt;&quot;&gt;The OGLFT library used for the On-Screen Display is based on GPL/LGPL-licensed code Copyright 2002 lignum Computing.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'Sans Serif';&quot;&gt;More information about this library is available at the following websites:&lt;/span&gt;&lt;/p&gt; &lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-size:10pt;&quot;&gt;More information about this library is available at the following websites:&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'Sans Serif';&quot;&gt; - &lt;/span&gt;&lt;a href=&quot;http://oglft.sourceforge.net/index.html&quot;&gt;&lt;span style=&quot; font-family:'Sans Serif'; text-decoration: underline; color:#0000ff;&quot;&gt;http://oglft.sourceforge.net/index.html&lt;/span&gt;&lt;/a&gt;&lt;/p&gt; &lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-size:10pt;&quot;&gt; - &lt;/span&gt;&lt;a href=&quot;http://oglft.sourceforge.net/index.html&quot;&gt;&lt;span style=&quot; font-size:10pt; text-decoration: underline; color:#0000ff;&quot;&gt;http://oglft.sourceforge.net/index.html&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'Sans Serif';&quot;&gt; - &lt;/span&gt;&lt;a href=&quot;http://directory.fsf.org/project/OGLFT/&quot;&gt;&lt;span style=&quot; font-family:'Sans Serif'; text-decoration: underline; color:#0000ff;&quot;&gt;http://directory.fsf.org/project/OGLFT/&lt;/span&gt;&lt;/a&gt;&lt;/p&gt; &lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-size:10pt;&quot;&gt; - &lt;/span&gt;&lt;a href=&quot;http://directory.fsf.org/project/OGLFT/&quot;&gt;&lt;span style=&quot; font-size:10pt; text-decoration: underline; color:#0000ff;&quot;&gt;http://directory.fsf.org/project/OGLFT/&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Sans Serif';&quot;&gt;&lt;br /&gt;&lt;/p&gt; &lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:10pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'Sans Serif';&quot;&gt;Additionally, mupen includes a number of components licensed under other OSI approved licenses:&lt;/span&gt;&lt;/p&gt; &lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-size:10pt;&quot;&gt;Additionally, mupen includes a number of components licensed under other OSI approved licenses:&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Sans Serif';&quot;&gt;&lt;br /&gt;&lt;/p&gt; &lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:10pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'Sans Serif';&quot;&gt;The BSD license:&lt;/span&gt;&lt;/p&gt; &lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-size:10pt;&quot;&gt;The BSD license:&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'Sans Serif';&quot;&gt; * minizip by Gilles Vollant and others,&lt;/span&gt;&lt;/p&gt; &lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-size:10pt;&quot;&gt; * minizip by Gilles Vollant and others,&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;a href=&quot;ftp://ftp.info-zip.org/pub/infozip/license.html&quot;&gt;&lt;span style=&quot; font-family:'Sans Serif'; text-decoration: underline; color:#0000ff;&quot;&gt;ftp://ftp.info-zip.org/pub/infozip/license.html&lt;/span&gt;&lt;/a&gt;&lt;/p&gt; &lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;a href=&quot;ftp://ftp.info-zip.org/pub/infozip/license.html&quot;&gt;&lt;span style=&quot; font-size:10pt; text-decoration: underline; color:#0000ff;&quot;&gt;ftp://ftp.info-zip.org/pub/infozip/license.html&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Sans Serif';&quot;&gt;&lt;br /&gt;&lt;/p&gt; &lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:10pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'Sans Serif';&quot;&gt;The zlib/libpng license:&lt;/span&gt;&lt;/p&gt; &lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-size:10pt;&quot;&gt;The zlib/libpng license:&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'Sans Serif';&quot;&gt; * Adler-32 by Mark Adler&lt;/span&gt;&lt;/p&gt; &lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-size:10pt;&quot;&gt; * Adler-32 by Mark Adler&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'Sans Serif';&quot;&gt; * libpng by Glenn Randers-Pehrson, Peter Deutsch, and Guy Eric Schalnat&lt;/span&gt;&lt;/p&gt; &lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-size:10pt;&quot;&gt; * libpng by Glenn Randers-Pehrson, Peter Deutsch, and Guy Eric Schalnat&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'Sans Serif';&quot;&gt; * MD5 hashing code by Peter Deutsch&lt;/span&gt;&lt;/p&gt; &lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-size:10pt;&quot;&gt; * MD5 hashing code by Peter Deutsch&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Sans Serif';&quot;&gt;&lt;br /&gt;&lt;/p&gt; &lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:10pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'Sans Serif';&quot;&gt;The Bitstream license:&lt;/span&gt;&lt;/p&gt; &lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-size:10pt;&quot;&gt;The Bitstream license:&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'Sans Serif';&quot;&gt; * The TrueType font (data/font.ttf) is licensed by the Bitstream license.&lt;/span&gt;&lt;/p&gt; &lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-size:10pt;&quot;&gt; * The TrueType font (data/font.ttf) is licensed by the Bitstream license.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Sans Serif';&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string> &lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:10pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property> </property>
<property name="openExternalLinks"> <property name="openExternalLinks">
<bool>true</bool> <bool>true</bool>

View file

@ -159,38 +159,18 @@ QGroupBox::title {
<verstretch>0</verstretch> <verstretch>0</verstretch>
</sizepolicy> </sizepolicy>
</property> </property>
<property name="styleSheet">
<string notr="true">background: #FFF;</string>
</property>
<property name="widgetResizable"> <property name="widgetResizable">
<bool>true</bool> <bool>true</bool>
</property> </property>
<widget class="QWidget" name="scrollAreaWidgetContents_2"> <widget class="QWidget" name="scrollAreaWidgetContents_2">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>308</width>
<height>44</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Minimum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<layout class="QVBoxLayout" name="verticalLayout_4"> <layout class="QVBoxLayout" name="verticalLayout_4">
<item> <item>
<widget class="QLabel" name="labelDesc"> <widget class="QLabel" name="labelDesc">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text"> <property name="text">
<string/> <string notr="true"/>
</property>
<property name="textFormat">
<enum>Qt::PlainText</enum>
</property> </property>
<property name="alignment"> <property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set> <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
@ -198,6 +178,9 @@ QGroupBox::title {
<property name="wordWrap"> <property name="wordWrap">
<bool>true</bool> <bool>true</bool>
</property> </property>
<property name="textInteractionFlags">
<set>Qt::TextSelectableByMouse</set>
</property>
</widget> </widget>
</item> </item>
</layout> </layout>

View file

@ -14,8 +14,8 @@
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
from PyQt5.QtWidgets import QGraphicsView, QGraphicsScene from PyQt6.QtWidgets import QGraphicsView, QGraphicsScene
from PyQt5.QtCore import Qt, QRectF from PyQt6.QtCore import Qt, QRectF
class ImageView(QGraphicsView): class ImageView(QGraphicsView):
@ -28,7 +28,7 @@ class ImageView(QGraphicsView):
for item in self.scene().items(): for item in self.scene().items():
pixmap = item.pixmap() pixmap = item.pixmap()
pixmap = pixmap.scaled( pixmap = pixmap.scaled(
size, Qt.KeepAspectRatio, Qt.SmoothTransformation) size, Qt.AspectRatioMode.KeepAspectRatio, Qt.TransformationMode.SmoothTransformation)
item.setPixmap(pixmap) item.setPixmap(pixmap)
self.ensureVisible(item) self.ensureVisible(item)
self.centerOn(item) self.centerOn(item)

View file

@ -14,8 +14,8 @@
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
from PyQt5.QtWidgets import QPushButton from PyQt6.QtWidgets import QPushButton
from PyQt5.QtCore import Qt from PyQt6.QtCore import Qt
from sdl2.keyboard import SDL_GetScancodeName from sdl2.keyboard import SDL_GetScancodeName
@ -35,7 +35,7 @@ class InputButton(QPushButton):
self.parent = parent self.parent = parent
self.input = None self.input = None
self.joystick = None self.joystick = None
self.setFocusPolicy(Qt.ClickFocus) self.setFocusPolicy(Qt.FocusPolicy.ClickFocus)
def showEvent(self, event): def showEvent(self, event):
dialog = self.parent.parentWidget().parent() dialog = self.parent.parentWidget().parent()
@ -55,15 +55,15 @@ class InputButton(QPushButton):
def keyPressEvent(self, event): def keyPressEvent(self, event):
modifier = event.modifiers() modifier = event.modifiers()
if modifier == Qt.NoModifier or modifier == Qt.KeypadModifier: if modifier == Qt.KeyboardModifier.NoModifier or modifier == Qt.KeyboardModifier.KeypadModifier:
key = event.key() key = event.key()
else: else:
key = modifier.__int__() key = modifier.__int__()
if key == Qt.Key_Escape: if key == Qt.Key.Key_Escape:
text = self.key text = self.key
self.setCheckable(False) self.setCheckable(False)
elif key == Qt.Key_Backspace: elif key == Qt.Key.Key_Backspace:
text = self.tr("Select...") text = self.tr("Select...")
self.setCheckable(False) self.setCheckable(False)
else: else: