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
=====
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
provides a user-friendly interface over the Mupen64Plus shared library.
@ -32,14 +32,14 @@ Features
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>`_
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
++++

View file

@ -28,10 +28,10 @@ if os.path.isdir(os.path.join("..", "src")) and os.path.isfile(
os.environ["DBUS_FATAL_WARNINGS"] = "0"
try:
from PyQt5.QtWidgets import QApplication
from PyQt5.QtCore import Qt, QLocale, QTranslator
from PyQt6.QtWidgets import QApplication
from PyQt6.QtCore import Qt, QLocale, QTranslator
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))
sys.exit(1)
@ -42,6 +42,12 @@ except ImportError as err:
os.linesep, str(err), os.linesep))
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):
if issubclass(exc_type, KeyboardInterrupt):
return
@ -73,6 +79,6 @@ if __name__ == "__main__":
signal.signal(signal.SIGINT, signal.SIG_DFL)
except AttributeError:
pass
sys.exit(app.exec_())
sys.exit(app.exec())
except KeyboardInterrupt:
pass

12
dist/debian/control vendored
View file

@ -12,8 +12,8 @@ Build-Depends:
debhelper (>= 9),
dh-python,
python3,
python3-pyqt5,
pyqt5-dev-tools,
python3-pyqt6,
pyqt6-dev-tools,
X-Python3-Version: >= 3.4
Package: m64py
@ -29,10 +29,8 @@ Depends:
mupen64plus-input-all | mupen64plus-input,
mupen64plus-rsp-all | mupen64plus-rsp,
mupen64plus-video-all | mupen64plus-video,
python3-opengl,
python3-pyqt5,
python3-pyqt5.qtopengl,
python3-pyqt5.qtsvg,
python3-pyqt6,
python3-pyqt6.qtsvg,
python3-sdl2,
Provides:
mupen64plus-ui,
@ -41,7 +39,7 @@ Recommends:
python3-lzma | p7zip,
unrar,
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
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]
.br
.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
.SH OPTIONS

View file

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

View file

@ -1,5 +1,5 @@
#!/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 '"'`
sed "s/{VERSION}/$VERSION/g" m64py.spec.in > m64py.spec
cd ../../ && python setup.py sdist

View file

@ -15,10 +15,10 @@ Prefix: %{_prefix}
BuildArch: noarch
Vendor: Milan Nikolic <gen2brain@gmail.com>
Url: http://m64py.sourceforge.net
Requires: PyQt5 PySDL2
Requires: PyQt6 PySDL2
%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
%setup -n %{name}-%{unmangled_version}

View file

@ -32,7 +32,7 @@ Source: "m64py\*.zip"; DestDir: "{app}";
Source: "m64py\*.v64"; DestDir: "{app}";
Source: "m64py\*.pyd"; DestDir: "{app}";
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\COPYING"; 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"]
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)

View file

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

View file

@ -9,10 +9,8 @@ import sys
import tempfile
import urllib
import zipfile
import fileinput
import distutils
import distutils.command.build as distutils_build
import distutils.command.clean as distutils_clean
import setuptools
try:
@ -42,52 +40,52 @@ class BuildQt(setuptools.Command):
pass
def compile_rc(self, qrc_file):
import PyQt5
py_file = os.path.splitext(qrc_file)[0] + "_rc.py"
if not newer(qrc_file, py_file):
return
origpath = os.getenv("PATH")
path = origpath.split(os.pathsep)
path.append(os.path.dirname(PyQt5.__file__))
os.putenv("PATH", os.pathsep.join(path))
if subprocess.call(["pyrcc5", qrc_file, "-o", py_file]) > 0:
path = os.getenv("PATH").split(os.pathsep)
path.extend(["/usr/lib64/qt6/bin", "/usr/lib64/qt6/libexec",
"/usr/lib/qt6/bin", "/usr/lib/qt6/libexec",
"/usr/lib/x86_64-linux-gnu/qt6/bin", "/usr/lib/x86_64-linux-gnu/qt6/libexec"])
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))
if not os.path.exists(py_file):
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):
from PyQt5 import uic
from PyQt6 import uic
py_file = os.path.splitext(ui_file)[0] + "_ui.py"
if not newer(ui_file, py_file):
return
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):
import PyQt5
from PyQt5.QtCore import QLibraryInfo
qm_file = os.path.splitext(ts_file)[0] + ".qm"
if not newer(ts_file, qm_file):
return
origpath = os.getenv("PATH")
path = origpath.split(os.pathsep)
path.append(os.path.dirname(PyQt5.__file__))
os.putenv("PATH", os.pathsep.join(path))
lr_exe = QLibraryInfo.location(QLibraryInfo.LibraryLocation.BinariesPath)
if lr_exe:
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")
path = os.getenv("PATH").split(os.pathsep)
path.extend(["/usr/lib64/qt6/bin", "/usr/lib64/qt6/libexec",
"/usr/lib/qt6/bin", "/usr/lib/qt6/libexec",
"/usr/lib/x86_64-linux-gnu/qt6/bin", "/usr/lib/x86_64-linux-gnu/qt6/libexec"])
os.environ["PATH"] = os.pathsep.join(path)
lr_exe = shutil.which("lrelease")
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)
if subprocess.call([lr_exe, ts_file, "-qm", qm_file]) > 0:
self.warn("Unable to compile translation file {}".format(qm_file))
if not os.path.exists(qm_file):
sys.exit(1)
os.putenv("PATH", origpath)
def run(self):
basepath = os.path.join(os.path.dirname(__file__), "src", "m64py", "ui")
@ -120,7 +118,7 @@ class BuildDmg(setuptools.Command):
def copy_emulator(self):
src_path = os.path.join(self.dist_dir, "mupen64plus", "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):
dest_path = os.path.join(self.dist_dir, "dmg")
@ -189,7 +187,7 @@ class BuildDmg(setuptools.Command):
class BuildExe(setuptools.Command):
"""
Requires PyQt5, rarfile, PyLZMA, PyWin32, PyInstaller and Inno
Requires PyQt6, rarfile, PyLZMA, PyWin32, PyInstaller and Inno
Setup 5.
"""
@ -233,7 +231,7 @@ class BuildExe(setuptools.Command):
rar_dir = os.path.join(os.environ["ProgramFiles(x86)"], "Unrar")
if not os.path.isfile(os.path.join(rar_dir, "UnRAR.exe")):
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"))
subprocess.call([os.path.join(tempdir, "unrar.exe"), "-s"])
shutil.rmtree(tempdir)
@ -248,12 +246,12 @@ class BuildExe(setuptools.Command):
for dir_name in ["api", "man6", "applications", "apps"]:
shutil.rmtree(os.path.join(dest_path, dir_name), True)
for dir_name in ["qml", "translations"]:
shutil.rmtree(os.path.join(dest_path, "PyQt5", "Qt", dir_name), True)
for file_name in glob.glob(os.path.join(dest_path, "PyQt5", "Qt*.pyd")):
if os.path.basename(file_name) not in ["Qt.pyd", "QtCore.pyd", "QtGui.pyd", "QtWidgets.pyd", "QtOpenGL.pyd"]:
shutil.rmtree(os.path.join(dest_path, "PyQt6", "Qt", dir_name), True)
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"]:
os.remove(file_name)
for file_name in glob.glob(os.path.join(dest_path, "Qt5*.dll")):
if os.path.basename(file_name) not in ["Qt5Core.dll", "Qt5Gui.dll", "Qt5Widgets.dll", "Qt5OpenGL.dll"]:
for file_name in glob.glob(os.path.join(dest_path, "Qt6*.dll")):
if os.path.basename(file_name) not in ["Qt6Core.dll", "Qt6Gui.dll", "Qt6Widgets.dll"]:
os.remove(file_name)
def run_build(self):
@ -381,23 +379,11 @@ class CleanLocal(setuptools.Command):
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(
name="m64py",
version=FRONTEND_VERSION,
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_email="gen2brain@gmail.com",
license="GNU GPLv3",
@ -405,16 +391,15 @@ setuptools.setup(
package_dir={'': "src"},
packages=["m64py", "m64py.core", "m64py.frontend", "m64py.ui"],
scripts=["bin/m64py"],
requires=["PyQt5", "PySDL2"],
requires=["PyQt6", "PySDL2"],
platforms=["Linux", "Windows", "Darwin"],
cmdclass={
'build': MyBuild,
'build': BuildQt,
'build_dmg': BuildDmg,
'build_exe': BuildExe,
'build_qt': BuildQt,
'build_zip': BuildZip,
'clean': MyClean,
'clean_local': CleanLocal
'clean': CleanLocal
},
data_files=[
("share/pixmaps", ["xdg/m64py.png"]),

View file

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

View file

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

View file

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

View file

@ -15,19 +15,15 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import sys
from PyQt5.QtCore import Qt
from PyQt5.QtWidgets import QDialog, QMessageBox, QListWidgetItem
from PyQt6.QtCore import Qt
from PyQt6.QtWidgets import QDialog, QMessageBox, QListWidgetItem
from m64py.utils import version_split
from m64py.core.defs import FRONTEND_VERSION
try:
from m64py.ui.about_ui import Ui_AboutDialog
from m64py.ui.license_ui import Ui_LicenseDialog
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)
from m64py.ui.about_ui import Ui_AboutDialog
from m64py.ui.license_ui import Ui_LicenseDialog
from m64py.ui.archive_ui import Ui_ArchiveDialog
class AboutDialog(QDialog, Ui_AboutDialog):
@ -70,6 +66,6 @@ class ArchiveDialog(QDialog, Ui_ArchiveDialog):
self.listWidget.clear()
for fname in files:
item = QListWidgetItem(fname)
item.setData(Qt.UserRole, fname)
item.setData(Qt.ItemDataRole.UserRole, fname)
self.listWidget.addItem(item)
self.listWidget.setCurrentRow(0)

View file

@ -14,11 +14,7 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
from PyQt5.QtCore import Qt
from PyQt5.QtGui import QWindow, QOpenGLContext
from m64py.core.defs import *
from m64py.frontend.keymap import QT2SDL2
from PyQt6.QtGui import QWindow, QOpenGLContext, QSurface
class GLWidget(QWindow):
@ -27,7 +23,7 @@ class GLWidget(QWindow):
self.parent = parent
QWindow.__init__(self, None)
self.setSurfaceType(QWindow.OpenGLSurface)
self.setSurfaceType(QSurface.SurfaceType.OpenGLSurface)
self.ctx = QOpenGLContext()
def context(self):
@ -40,34 +36,3 @@ class GLWidget(QWindow):
def mouseDoubleClickEvent(self, event):
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
from PyQt5.QtWidgets import QDialog
from PyQt5.QtGui import QKeySequence
from PyQt6.QtWidgets import QDialog
from sdl2 import SDL_WasInit, SDL_InitSubSystem, SDL_QuitSubSystem, SDL_INIT_VIDEO
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
# 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_JoystickOpen, SDL_JoystickClose, SDL_NumJoysticks, SDL_JoystickNameForIndex
@ -195,6 +195,6 @@ class Joystick(QObject):
elif self.auto_repeat and changed != 0:
if self.button_repeat_timers[i].elapsed() >= self.auto_repeat_delay:
self.button_value_changed.emit(i, changed)
self.button[si] = changed
self.button[i] = changed
else:
self.button_repeat_timers[i].restart()

View file

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

View file

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

View file

@ -17,10 +17,10 @@
import os
import sys
from PyQt5.QtGui import QKeySequence, QPixmap, QOpenGLContext
from PyQt5.QtWidgets import QApplication, QMainWindow, QGraphicsView, QGraphicsScene, QGraphicsPixmapItem
from PyQt5.QtWidgets import QAction, QLabel, QFileDialog, QStackedWidget, QActionGroup, QSizePolicy, QWidget, QDialog
from PyQt5.QtCore import Qt, QTimer, QFileInfo, QEvent, QMargins, pyqtSignal, pyqtSlot
from PyQt6.QtGui import QKeySequence, QPixmap, QOpenGLContext, QAction, QActionGroup
from PyQt6.QtWidgets import QApplication, QMainWindow, QGraphicsView, QGraphicsScene, QGraphicsPixmapItem
from PyQt6.QtWidgets import QLabel, QFileDialog, QStackedWidget, QSizePolicy, QWidget, QDialog
from PyQt6.QtCore import Qt, QTimer, QFileInfo, QEvent, QMargins, pyqtSignal, pyqtSlot
from m64py.core.defs import *
from m64py.frontend.dialogs import *
@ -34,6 +34,9 @@ from m64py.frontend.settings import Settings
from m64py.frontend.glwidget import GLWidget
from m64py.ui.mainwindow_ui import Ui_MainWindow
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):
@ -61,11 +64,11 @@ class MainWindow(QMainWindow, Ui_MainWindow):
self._initialize_attempt = 0
logview.setParent(self)
logview.setWindowFlags(Qt.Dialog)
logview.setWindowFlags(Qt.WindowType.Dialog)
self.statusbar_label = QLabel()
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.update_status(self.tr(
"Welcome to M64Py version %s." % FRONTEND_VERSION))
@ -97,10 +100,11 @@ class MainWindow(QMainWindow, Ui_MainWindow):
self.worker.quit()
def changeEvent(self, event):
if event.type() == QEvent.WindowStateChange:
if event.oldState() == Qt.WindowMaximized:
if event.type() == QEvent.Type.WindowStateChange:
if event.oldState() == Qt.WindowState.WindowMaximized:
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
def resizeEvent(self, event):
@ -123,6 +127,37 @@ class MainWindow(QMainWindow, Ui_MainWindow):
self.create_size_actions()
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):
window_width, window_height = size
if self.vidext and self.worker.core.get_handle():
@ -172,7 +207,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
def center_widget(self):
"""Centers widget on desktop."""
size = self.size()
desktop = QApplication.desktop()
desktop = self.screen().geometry()
width, height = size.width(), size.height()
dwidth, dheight = desktop.width(), desktop.height()
cw, ch = (dwidth/2)-(width/2), (dheight/2)-(height/2)
@ -196,7 +231,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
"""Creates central widgets."""
self.stack = QStackedWidget(None)
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.setAutoFillBackground(True)
@ -251,13 +286,16 @@ class MainWindow(QMainWindow, Ui_MainWindow):
else:
self.menubar.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):
"""Opens ROM file."""
if not filepath:
action = self.sender()
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)
if self.worker.state in [M64EMU_RUNNING, M64EMU_PAUSED]:
self.worker.stop()
@ -291,10 +329,10 @@ class MainWindow(QMainWindow, Ui_MainWindow):
def on_archive_dialog(self, files):
"""Shows archive dialog."""
archive = ArchiveDialog(self, files)
rval = archive.exec_()
if rval == QDialog.Accepted:
rval = archive.exec()
if rval == QDialog.DialogCode.Accepted:
curr_item = archive.listWidget.currentItem()
fname = curr_item.data(Qt.UserRole)
fname = curr_item.data(Qt.ItemDataRole.UserRole)
self.worker.filename = fname
def on_state_changed(self, states):
@ -324,9 +362,9 @@ class MainWindow(QMainWindow, Ui_MainWindow):
self.actionGraphics.setEnabled(not action)
self.actionPlugins.setEnabled(not action)
"""Wait up to 10 seconds for core initialization, checking once a second.
If not yet initialized, start another QTimer. Else, toggle UI actions."""
def wait_for_initialize(self):
"""Wait up to 10 seconds for core initialization, checking once a second.
If not yet initialized, start another QTimer. Else, toggle UI actions."""
if self.worker.core_state_query(M64CORE_EMU_STATE) == M64EMU_STOPPED:
self._initialize_attempt += 1
if self._initialize_attempt < 10:
@ -361,7 +399,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
def on_actionManually_triggered(self):
"""Shows ROM file dialog."""
dialog = QFileDialog()
dialog.setFileMode(QFileDialog.ExistingFile)
dialog.setFileMode(QFileDialog.FileMode.ExistingFile)
last_dir = self.settings.qset.value("last_dir")
file_path, _ = dialog.getOpenFileName(
self, self.tr("Load ROM Image"), last_dir,
@ -395,7 +433,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
def on_actionLoadFrom_triggered(self):
"""Loads state from file."""
dialog = QFileDialog()
dialog.setFileMode(QFileDialog.ExistingFile)
dialog.setFileMode(QFileDialog.FileMode.ExistingFile)
file_path, _ = dialog.getOpenFileName(
self, self.tr("Load State From File"),
os.path.join(self.worker.core.config.get_path("UserData"), "save"),
@ -518,6 +556,6 @@ class View(QGraphicsView):
QGraphicsView.__init__(self, parent)
self.setContentsMargins(QMargins())
self.setStyleSheet("QGraphicsView {border:0px solid;margin:0px;}")
self.setResizeAnchor(QGraphicsView.AnchorViewCenter)
self.setResizeAnchor(QGraphicsView.ViewportAnchor.AnchorViewCenter)
self.setScene(QGraphicsScene(self))
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
# along with this program. If not, see <http://www.gnu.org/licenses/>.
from PyQt5.QtCore import Qt
from PyQt5.QtWidgets import QDialog, QLabel, QSpinBox, QComboBox, QLineEdit, QCheckBox
from PyQt6.QtCore import Qt
from PyQt6.QtWidgets import QDialog, QLabel, QSpinBox, QComboBox, QLineEdit, QCheckBox
import re
from m64py.core.defs import *
@ -84,8 +84,8 @@ class Plugin(QDialog, Ui_PluginDialog):
widget = QLineEdit()
widget.setToolTip(param_help)
self.gridLayout.addWidget(
QLabel(format_label(param_desc)), row1, 1, Qt.AlignRight)
self.gridLayout.addWidget(widget, row1, 2, Qt.AlignLeft)
QLabel(format_label(param_desc)), row1, 1, Qt.AlignmentFlag.AlignRight)
self.gridLayout.addWidget(widget, row1, 2, Qt.AlignmentFlag.AlignLeft)
self.widgets[param_name] = (widget, widget.__class__, opts)
elif param_type == M64TYPE_INT:
row1 += 1
@ -98,7 +98,7 @@ class Plugin(QDialog, Ui_PluginDialog):
widget = QComboBox()
widget.setToolTip(param_help)
widget.setMinimumContentsLength(14)
widget.setSizeAdjustPolicy(QComboBox.AdjustToMinimumContentsLength)
widget.setSizeAdjustPolicy(QComboBox.SizeAdjustPolicy.AdjustToMinimumContentsLengthWithIcon)
for idx, key in enumerate(sorted(opts.keys())):
value = opts[key]
opts[key] = (idx, value)
@ -106,8 +106,8 @@ class Plugin(QDialog, Ui_PluginDialog):
widget.addItem(value)
widget.setItemData(idx, data)
self.gridLayout.addWidget(
QLabel(format_label(param_desc)), row1, 1, Qt.AlignRight)
self.gridLayout.addWidget(widget, row1, 2, Qt.AlignLeft)
QLabel(format_label(param_desc)), row1, 1, Qt.AlignmentFlag.AlignRight)
self.gridLayout.addWidget(widget, row1, 2, Qt.AlignmentFlag.AlignLeft)
self.widgets[param_name] = (widget, widget.__class__, opts)
elif param_type == M64TYPE_BOOL:
row2 += 1

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -17,7 +17,7 @@
import os
import shutil
from PyQt5.QtCore import QThread, QTimer
from PyQt6.QtCore import QThread, QTimer
from sdl2 import SDL_EnableScreenSaver, SDL_DisableScreenSaver
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;
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;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;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; font-size:10pt; text-decoration: underline; color:#0000ff;&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;&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;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;
@ -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;
&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; }
&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;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;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;-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; 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-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-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-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-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-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-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-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-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-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-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-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-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-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-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-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-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-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-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-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-family:'Sans Serif';&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; 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-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;-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; 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-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-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-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-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-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-family:'Sans Serif';&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; 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-family:'Sans Serif';&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; 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-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-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-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;-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; 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;-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; 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-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;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;-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; 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-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-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-family:'Sans Serif';&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; 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-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;-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;/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-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-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-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-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-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-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-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-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-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-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-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-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-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-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-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-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-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-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-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-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-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-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-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-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-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-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-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-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-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-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-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-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-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-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-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-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-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-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-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-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-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-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-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-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-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-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-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-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-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-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-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-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-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-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-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-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-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-size:10pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="openExternalLinks">
<bool>true</bool>

View file

@ -159,38 +159,18 @@ QGroupBox::title {
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="styleSheet">
<string notr="true">background: #FFF;</string>
</property>
<property name="widgetResizable">
<bool>true</bool>
</property>
<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">
<item>
<widget class="QLabel" name="labelDesc">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string/>
<string notr="true"/>
</property>
<property name="textFormat">
<enum>Qt::PlainText</enum>
</property>
<property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
@ -198,6 +178,9 @@ QGroupBox::title {
<property name="wordWrap">
<bool>true</bool>
</property>
<property name="textInteractionFlags">
<set>Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
</layout>

View file

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

View file

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