Initial commit
This commit is contained in:
112
.gitignore
vendored
Normal file
112
.gitignore
vendored
Normal file
@@ -0,0 +1,112 @@
|
||||
mame.json
|
||||
mame/*
|
||||
mfe.ini
|
||||
mame.dat
|
||||
mess.dat
|
||||
mame_exclude.txt
|
||||
|
||||
.vscode/tags
|
||||
|
||||
# Mac Files
|
||||
.DS_Store
|
||||
|
||||
# Byte-compiled / optimized / DLL files
|
||||
__pycache__/
|
||||
*.py[cod]
|
||||
*$py.class
|
||||
|
||||
# C extensions
|
||||
*.so
|
||||
|
||||
# Distribution / packaging
|
||||
.Python
|
||||
build/
|
||||
develop-eggs/
|
||||
dist/
|
||||
downloads/
|
||||
eggs/
|
||||
.eggs/
|
||||
lib/
|
||||
lib64/
|
||||
parts/
|
||||
sdist/
|
||||
var/
|
||||
wheels/
|
||||
*.egg-info/
|
||||
.installed.cfg
|
||||
*.egg
|
||||
|
||||
# PyInstaller
|
||||
# Usually these files are written by a python script from a template
|
||||
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
||||
*.manifest
|
||||
*.spec
|
||||
|
||||
# Installer logs
|
||||
pip-log.txt
|
||||
pip-delete-this-directory.txt
|
||||
|
||||
# Unit test / coverage reports
|
||||
htmlcov/
|
||||
.tox/
|
||||
.coverage
|
||||
.coverage.*
|
||||
.cache
|
||||
nosetests.xml
|
||||
coverage.xml
|
||||
*.cover
|
||||
.hypothesis/
|
||||
|
||||
# Translations
|
||||
*.mo
|
||||
*.pot
|
||||
|
||||
# Django stuff:
|
||||
*.log
|
||||
local_settings.py
|
||||
|
||||
# Flask stuff:
|
||||
instance/
|
||||
.webassets-cache
|
||||
|
||||
# Scrapy stuff:
|
||||
.scrapy
|
||||
|
||||
# Sphinx documentation
|
||||
docs/_build/
|
||||
|
||||
# PyBuilder
|
||||
target/
|
||||
|
||||
# Jupyter Notebook
|
||||
.ipynb_checkpoints
|
||||
|
||||
# pyenv
|
||||
.python-version
|
||||
|
||||
# celery beat schedule file
|
||||
celerybeat-schedule
|
||||
|
||||
# SageMath parsed files
|
||||
*.sage.py
|
||||
|
||||
# Environments
|
||||
.env
|
||||
.venv
|
||||
env/
|
||||
venv/
|
||||
ENV/
|
||||
|
||||
# Spyder project settings
|
||||
.spyderproject
|
||||
.spyproject
|
||||
|
||||
# Rope project settings
|
||||
.ropeproject
|
||||
|
||||
# mkdocs documentation
|
||||
/site
|
||||
|
||||
# mypy
|
||||
.mypy_cache/
|
||||
|
||||
60
.vscode/launch.json
vendored
Normal file
60
.vscode/launch.json
vendored
Normal file
@@ -0,0 +1,60 @@
|
||||
{
|
||||
"version": "0.2.0",
|
||||
"configurations": [{
|
||||
"name": "Python",
|
||||
"type": "python",
|
||||
"request": "launch",
|
||||
"stopOnEntry": false,
|
||||
"pythonPath": "${config:python.pythonPath}",
|
||||
"program": "${workspaceRoot}/mfe.py",
|
||||
"cwd": "${workspaceRoot}",
|
||||
"env": {},
|
||||
"envFile": "${workspaceRoot}/.env",
|
||||
"debugOptions": [
|
||||
"RedirectOutput"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Integrated Terminal/Console",
|
||||
"type": "python",
|
||||
"request": "launch",
|
||||
"stopOnEntry": true,
|
||||
"pythonPath": "${config:python.pythonPath}",
|
||||
"program": "${file}",
|
||||
"cwd": "",
|
||||
"console": "integratedTerminal",
|
||||
"env": {},
|
||||
"envFile": "${workspaceRoot}/.env",
|
||||
"debugOptions": [
|
||||
"WaitOnAbnormalExit",
|
||||
"WaitOnNormalExit"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "External Terminal/Console",
|
||||
"type": "python",
|
||||
"request": "launch",
|
||||
"stopOnEntry": true,
|
||||
"pythonPath": "${config:python.pythonPath}",
|
||||
"program": "${file}",
|
||||
"cwd": "",
|
||||
"console": "externalTerminal",
|
||||
"env": {},
|
||||
"envFile": "${workspaceRoot}/.env",
|
||||
"debugOptions": [
|
||||
"WaitOnAbnormalExit",
|
||||
"WaitOnNormalExit"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Attach (Remote Debug)",
|
||||
"type": "python",
|
||||
"request": "attach",
|
||||
"localRoot": "${workspaceRoot}",
|
||||
"remoteRoot": "${workspaceRoot}",
|
||||
"port": 3000,
|
||||
"secret": "my_secret",
|
||||
"host": "localhost"
|
||||
}
|
||||
]
|
||||
}
|
||||
9
.vscode/settings.json
vendored
Normal file
9
.vscode/settings.json
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"python.formatting.provider": "yapf",
|
||||
"python.linting.flake8Enabled": true,
|
||||
"python.linting.flake8Args": ["--ignore", "E501,E722,C0103"],
|
||||
"editor.formatOnPaste": true,
|
||||
"editor.formatOnSave": true,
|
||||
"editor.formatOnType": true,
|
||||
"python.pythonPath": "/Users/rich/.local/share/virtualenvs/mfe-K8QhrIKQ/bin/python",
|
||||
}
|
||||
22
Pipfile
Normal file
22
Pipfile
Normal file
@@ -0,0 +1,22 @@
|
||||
[[source]]
|
||||
url = "https://pypi.org/simple"
|
||||
verify_ssl = true
|
||||
name = "pypi"
|
||||
|
||||
[packages]
|
||||
configobj = ">=5.0.6"
|
||||
appdirs = ">=1.4.3"
|
||||
lxml = ">=3.8.0"
|
||||
titlecase = ">=0.11.0"
|
||||
#pygame = {path = "./../pygame/dist/pygame-1.9.5.dev0-py3.7-macosx-10.14-x86_64.egg"}
|
||||
#Pygame = ">=1.9.3"
|
||||
pygame = {file = "file:///Users/rich/git/pygame/dist/pygame-1.9.5.dev0-cp37-cp37m-macosx_10_14_x86_64.whl"}
|
||||
|
||||
[dev-packages]
|
||||
pylint = "*"
|
||||
flake8 = "*"
|
||||
cx-freeze = {editable = true,git = "https://github.com/anthony-tuininga/cx_Freeze.git"}
|
||||
yapf = "*"
|
||||
|
||||
[requires]
|
||||
python_version = "3.7"
|
||||
210
Pipfile.lock
generated
Normal file
210
Pipfile.lock
generated
Normal file
@@ -0,0 +1,210 @@
|
||||
{
|
||||
"_meta": {
|
||||
"hash": {
|
||||
"sha256": "d7ff85d4507b7eaaf2f2f6433e8450ffcf52bdd74a889e3051a38acd4cd3c62a"
|
||||
},
|
||||
"pipfile-spec": 6,
|
||||
"requires": {
|
||||
"python_version": "3.7"
|
||||
},
|
||||
"sources": [
|
||||
{
|
||||
"name": "pypi",
|
||||
"url": "https://pypi.org/simple",
|
||||
"verify_ssl": true
|
||||
}
|
||||
]
|
||||
},
|
||||
"default": {
|
||||
"appdirs": {
|
||||
"hashes": [
|
||||
"sha256:9e5896d1372858f8dd3344faf4e5014d21849c756c8d5701f78f8a103b372d92",
|
||||
"sha256:d8b24664561d0d34ddfaec54636d502d7cea6e29c3eaf68f3df6180863e2166e"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==1.4.3"
|
||||
},
|
||||
"configobj": {
|
||||
"hashes": [
|
||||
"sha256:a2f5650770e1c87fb335af19a9b7eb73fc05ccf22144eb68db7d00cd2bcb0902"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==5.0.6"
|
||||
},
|
||||
"lxml": {
|
||||
"hashes": [
|
||||
"sha256:02bc220d61f46e9b9d5a53c361ef95e9f5e1d27171cd461dddb17677ae2289a5",
|
||||
"sha256:22f253b542a342755f6cfc047fe4d3a296515cf9b542bc6e261af45a80b8caf6",
|
||||
"sha256:2f31145c7ff665b330919bfa44aacd3a0211a76ca7e7b441039d2a0b0451e415",
|
||||
"sha256:36720698c29e7a9626a0dc802ef8885f8f0239bfd1689628ecd459a061f2807f",
|
||||
"sha256:438a1b0203545521f6616132bfe0f4bca86f8a401364008b30e2b26ec408ce85",
|
||||
"sha256:4815892904c336bbaf73dafd54f45f69f4021c22b5bad7332176bbf4fb830568",
|
||||
"sha256:5be031b0f15ad63910d8e5038b489d95a79929513b3634ad4babf77100602588",
|
||||
"sha256:5c93ae37c3c588e829b037fdfbd64a6e40c901d3f93f7beed6d724c44829a3ad",
|
||||
"sha256:60842230678674cdac4a1cf0f707ef12d75b9a4fc4a565add4f710b5fcf185d5",
|
||||
"sha256:62939a8bb6758d1bf923aa1c13f0bcfa9bf5b2fc0f5fa917a6e25db5fe0cfa4e",
|
||||
"sha256:75830c06a62fe7b8fe3bbb5f269f0b308f19f3949ac81cfd40062f47c1455faf",
|
||||
"sha256:81992565b74332c7c1aff6a913a3e906771aa81c9d0c68c68113cffcae45bc53",
|
||||
"sha256:8c892fb0ee52c594d9a7751c7d7356056a9682674b92cc1c4dc968ff0f30c52f",
|
||||
"sha256:9d862e3cf4fc1f2837dedce9c42269c8c76d027e49820a548ac89fdcee1e361f",
|
||||
"sha256:a623965c086a6e91bb703d4da62dabe59fe88888e82c4117d544e11fd74835d6",
|
||||
"sha256:a7783ab7f6a508b0510490cef9f857b763d796ba7476d9703f89722928d1e113",
|
||||
"sha256:aab09fbe8abfa3b9ce62aaf45aca2d28726b1b9ee44871dbe644050a2fff4940",
|
||||
"sha256:abf181934ac3ef193832fb973fd7f6149b5c531903c2ec0f1220941d73eee601",
|
||||
"sha256:ae07fa0c115733fce1e9da96a3ac3fa24801742ca17e917e0c79d63a01eeb843",
|
||||
"sha256:b9c78242219f674ab645ec571c9a95d70f381319a23911941cd2358a8e0521cf",
|
||||
"sha256:bccb267678b870d9782c3b44d0cefe3ba0e329f9af8c946d32bf3778e7a4f271",
|
||||
"sha256:c4df4d27f4c93b2cef74579f00b1d3a31a929c7d8023f870c4b476f03a274db4",
|
||||
"sha256:caf0e50b546bb60dfa99bb18dfa6748458a83131ecdceaf5c071d74907e7e78a",
|
||||
"sha256:d3266bd3ac59ac4edcd5fa75165dee80b94a3e5c91049df5f7c057ccf097551c",
|
||||
"sha256:db0d213987bcd4e6d41710fb4532b22315b0d8fb439ff901782234456556aed1",
|
||||
"sha256:dbbd5cf7690a40a9f0a9325ab480d0fccf46d16b378eefc08e195d84299bfae1",
|
||||
"sha256:e16e07a0ec3a75b5ee61f2b1003c35696738f937dc8148fbda9fe2147ccb6e61",
|
||||
"sha256:e175a006725c7faadbe69e791877d09936c0ef2cf49d01b60a6c1efcb0e8be6f",
|
||||
"sha256:edd9c13a97f6550f9da2236126bb51c092b3b1ce6187f2bd966533ad794bbb5e",
|
||||
"sha256:fa39ea60d527fbdd94215b5e5552f1c6a912624521093f1384a491a8ad89ad8b"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==4.2.5"
|
||||
},
|
||||
"pygame": {
|
||||
"file": "file:///Users/rich/git/pygame/dist/pygame-1.9.5.dev0-cp37-cp37m-macosx_10_14_x86_64.whl",
|
||||
"hashes": [
|
||||
"sha256:9b811036eebebca68f166683f21427d1682f62159cb6de2b6724dec2be322c2a",
|
||||
"sha256:9fba43308b121628a6c70edc7fac4b07ae5e30ccfe5bf36b914b3a2130e1671a",
|
||||
"sha256:a8e217e5c39c5ea2900f450f2e8acdb97487053a13447f680608200a956e8fe3",
|
||||
"sha256:b48da4cd1b70487791767fcae7e9e3ce8eaf4d340667b5eea14d49a4104e23d1"
|
||||
],
|
||||
"version": "==1.9.5.dev0"
|
||||
},
|
||||
"six": {
|
||||
"hashes": [
|
||||
"sha256:70e8a77beed4562e7f14fe23a786b54f6296e34344c23bc42f07b15018ff98e9",
|
||||
"sha256:832dc0e10feb1aa2c68dcc57dbb658f1c7e65b9b61af69048abc87a2db00a0eb"
|
||||
],
|
||||
"version": "==1.11.0"
|
||||
},
|
||||
"titlecase": {
|
||||
"hashes": [
|
||||
"sha256:84de7a97fb702c400e5ba11c6b30849944b39db12e20fbf4515a23c7538a0611",
|
||||
"sha256:95d643a0c08097c02933aced707adfe1c275c335019e8e514dea782a465c5b84"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==0.12.0"
|
||||
}
|
||||
},
|
||||
"develop": {
|
||||
"astroid": {
|
||||
"hashes": [
|
||||
"sha256:35b032003d6a863f5dcd7ec11abd5cd5893428beaa31ab164982403bcb311f22",
|
||||
"sha256:6a5d668d7dc69110de01cdf7aeec69a679ef486862a0850cc0fd5571505b6b7e"
|
||||
],
|
||||
"version": "==2.1.0"
|
||||
},
|
||||
"cx-freeze": {
|
||||
"editable": true,
|
||||
"git": "https://github.com/anthony-tuininga/cx_Freeze.git",
|
||||
"ref": "9e06b761740a9e93431ee7ea8d0b10f786446a6a"
|
||||
},
|
||||
"flake8": {
|
||||
"hashes": [
|
||||
"sha256:6a35f5b8761f45c5513e3405f110a86bea57982c3b75b766ce7b65217abe1670",
|
||||
"sha256:c01f8a3963b3571a8e6bd7a4063359aff90749e160778e03817cd9b71c9e07d2"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==3.6.0"
|
||||
},
|
||||
"isort": {
|
||||
"hashes": [
|
||||
"sha256:1153601da39a25b14ddc54955dbbacbb6b2d19135386699e2ad58517953b34af",
|
||||
"sha256:b9c40e9750f3d77e6e4d441d8b0266cf555e7cdabdcff33c4fd06366ca761ef8",
|
||||
"sha256:ec9ef8f4a9bc6f71eec99e1806bfa2de401650d996c59330782b89a5555c1497"
|
||||
],
|
||||
"version": "==4.3.4"
|
||||
},
|
||||
"lazy-object-proxy": {
|
||||
"hashes": [
|
||||
"sha256:0ce34342b419bd8f018e6666bfef729aec3edf62345a53b537a4dcc115746a33",
|
||||
"sha256:1b668120716eb7ee21d8a38815e5eb3bb8211117d9a90b0f8e21722c0758cc39",
|
||||
"sha256:209615b0fe4624d79e50220ce3310ca1a9445fd8e6d3572a896e7f9146bbf019",
|
||||
"sha256:27bf62cb2b1a2068d443ff7097ee33393f8483b570b475db8ebf7e1cba64f088",
|
||||
"sha256:27ea6fd1c02dcc78172a82fc37fcc0992a94e4cecf53cb6d73f11749825bd98b",
|
||||
"sha256:2c1b21b44ac9beb0fc848d3993924147ba45c4ebc24be19825e57aabbe74a99e",
|
||||
"sha256:2df72ab12046a3496a92476020a1a0abf78b2a7db9ff4dc2036b8dd980203ae6",
|
||||
"sha256:320ffd3de9699d3892048baee45ebfbbf9388a7d65d832d7e580243ade426d2b",
|
||||
"sha256:50e3b9a464d5d08cc5227413db0d1c4707b6172e4d4d915c1c70e4de0bbff1f5",
|
||||
"sha256:5276db7ff62bb7b52f77f1f51ed58850e315154249aceb42e7f4c611f0f847ff",
|
||||
"sha256:61a6cf00dcb1a7f0c773ed4acc509cb636af2d6337a08f362413c76b2b47a8dd",
|
||||
"sha256:6ae6c4cb59f199d8827c5a07546b2ab7e85d262acaccaacd49b62f53f7c456f7",
|
||||
"sha256:7661d401d60d8bf15bb5da39e4dd72f5d764c5aff5a86ef52a042506e3e970ff",
|
||||
"sha256:7bd527f36a605c914efca5d3d014170b2cb184723e423d26b1fb2fd9108e264d",
|
||||
"sha256:7cb54db3535c8686ea12e9535eb087d32421184eacc6939ef15ef50f83a5e7e2",
|
||||
"sha256:7f3a2d740291f7f2c111d86a1c4851b70fb000a6c8883a59660d95ad57b9df35",
|
||||
"sha256:81304b7d8e9c824d058087dcb89144842c8e0dea6d281c031f59f0acf66963d4",
|
||||
"sha256:933947e8b4fbe617a51528b09851685138b49d511af0b6c0da2539115d6d4514",
|
||||
"sha256:94223d7f060301b3a8c09c9b3bc3294b56b2188e7d8179c762a1cda72c979252",
|
||||
"sha256:ab3ca49afcb47058393b0122428358d2fbe0408cf99f1b58b295cfeb4ed39109",
|
||||
"sha256:bd6292f565ca46dee4e737ebcc20742e3b5be2b01556dafe169f6c65d088875f",
|
||||
"sha256:cb924aa3e4a3fb644d0c463cad5bc2572649a6a3f68a7f8e4fbe44aaa6d77e4c",
|
||||
"sha256:d0fc7a286feac9077ec52a927fc9fe8fe2fabab95426722be4c953c9a8bede92",
|
||||
"sha256:ddc34786490a6e4ec0a855d401034cbd1242ef186c20d79d2166d6a4bd449577",
|
||||
"sha256:e34b155e36fa9da7e1b7c738ed7767fc9491a62ec6af70fe9da4a057759edc2d",
|
||||
"sha256:e5b9e8f6bda48460b7b143c3821b21b452cb3a835e6bbd5dd33aa0c8d3f5137d",
|
||||
"sha256:e81ebf6c5ee9684be8f2c87563880f93eedd56dd2b6146d8a725b50b7e5adb0f",
|
||||
"sha256:eb91be369f945f10d3a49f5f9be8b3d0b93a4c2be8f8a5b83b0571b8123e0a7a",
|
||||
"sha256:f460d1ceb0e4a5dcb2a652db0904224f367c9b3c1470d5a7683c0480e582468b"
|
||||
],
|
||||
"version": "==1.3.1"
|
||||
},
|
||||
"mccabe": {
|
||||
"hashes": [
|
||||
"sha256:ab8a6258860da4b6677da4bd2fe5dc2c659cff31b3ee4f7f5d64e79735b80d42",
|
||||
"sha256:dd8d182285a0fe56bace7f45b5e7d1a6ebcbf524e8f3bd87eb0f125271b8831f"
|
||||
],
|
||||
"version": "==0.6.1"
|
||||
},
|
||||
"pycodestyle": {
|
||||
"hashes": [
|
||||
"sha256:cbc619d09254895b0d12c2c691e237b2e91e9b2ecf5e84c26b35400f93dcfb83",
|
||||
"sha256:cbfca99bd594a10f674d0cd97a3d802a1fdef635d4361e1a2658de47ed261e3a"
|
||||
],
|
||||
"version": "==2.4.0"
|
||||
},
|
||||
"pyflakes": {
|
||||
"hashes": [
|
||||
"sha256:9a7662ec724d0120012f6e29d6248ae3727d821bba522a0e6b356eff19126a49",
|
||||
"sha256:f661252913bc1dbe7fcfcbf0af0db3f42ab65aabd1a6ca68fe5d466bace94dae"
|
||||
],
|
||||
"version": "==2.0.0"
|
||||
},
|
||||
"pylint": {
|
||||
"hashes": [
|
||||
"sha256:689de29ae747642ab230c6d37be2b969bf75663176658851f456619aacf27492",
|
||||
"sha256:771467c434d0d9f081741fec1d64dfb011ed26e65e12a28fe06ca2f61c4d556c"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==2.2.2"
|
||||
},
|
||||
"six": {
|
||||
"hashes": [
|
||||
"sha256:70e8a77beed4562e7f14fe23a786b54f6296e34344c23bc42f07b15018ff98e9",
|
||||
"sha256:832dc0e10feb1aa2c68dcc57dbb658f1c7e65b9b61af69048abc87a2db00a0eb"
|
||||
],
|
||||
"version": "==1.11.0"
|
||||
},
|
||||
"wrapt": {
|
||||
"hashes": [
|
||||
"sha256:d4d560d479f2c21e1b5443bbd15fe7ec4b37fe7e53d335d3b9b0a7b1226fe3c6"
|
||||
],
|
||||
"version": "==1.10.11"
|
||||
},
|
||||
"yapf": {
|
||||
"hashes": [
|
||||
"sha256:8aa7f9abdb97b4da4d3227306b88477982daafef0a96cc41639754ca31f46d55",
|
||||
"sha256:f2df5891481f94ddadfbf8ae8ae499080752cfb06005a31bbb102f3012f8b944"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==0.25.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
305
app.py
Normal file
305
app.py
Normal file
@@ -0,0 +1,305 @@
|
||||
import sys
|
||||
# from pprint import pprint
|
||||
|
||||
import pygame
|
||||
|
||||
import csvfile
|
||||
import gui as guimodule
|
||||
import mame
|
||||
import mess
|
||||
from configfile import cfg, config_write, get_emu, get_emulators, set_emu
|
||||
from utils import addscanlines, image_from_data, run_emulator
|
||||
|
||||
BLACK = (0, 0, 0)
|
||||
WHITE = (255, 255, 255)
|
||||
GREY = (70, 70, 70)
|
||||
DARKGREY = (50, 50, 50)
|
||||
|
||||
|
||||
class app(object):
|
||||
def __init__(self):
|
||||
if get_emu('EmulatorType') == 'MAME':
|
||||
self.roms = mame.MameROMs(cfg['datadir'], cfg['HideMature'],
|
||||
get_emu())
|
||||
if get_emu('EmulatorType') == 'MESS':
|
||||
self.roms = mess.MessROMs(cfg['datadir'], get_emu())
|
||||
if get_emu('EmulatorType') == 'CSV':
|
||||
self.roms = csvfile.csvROMs(cfg['datadir'], get_emu())
|
||||
|
||||
self.update_menus()
|
||||
|
||||
pygame.init()
|
||||
pygame.font.init()
|
||||
|
||||
iconsurface = pygame.image.load("arcade.png")
|
||||
pygame.display.set_icon(iconsurface)
|
||||
|
||||
if cfg['FullScreen']:
|
||||
self.screen = pygame.display.set_mode(
|
||||
(cfg['ResolutionX'], cfg['ResolutionY']), pygame.FULLSCREEN)
|
||||
else:
|
||||
self.screen = pygame.display.set_mode((cfg['ResolutionX'],
|
||||
cfg['ResolutionY']))
|
||||
|
||||
self.font = pygame.font.Font(
|
||||
pygame.font.match_font(cfg['Font']), cfg['FontSize'])
|
||||
|
||||
self.status_surface = pygame.Surface(( # pylint: disable=E1121
|
||||
cfg['ResolutionX'], self.font.get_height()))
|
||||
|
||||
self.oldmouse = pygame.mouse.set_visible(False)
|
||||
|
||||
pygame.key.set_repeat(100, 30)
|
||||
|
||||
self.listwidth = int(cfg['ResolutionX'] / 2)
|
||||
|
||||
self.gui = guimodule.gui(self.screen)
|
||||
|
||||
self.gui.add_menu(
|
||||
0,
|
||||
0,
|
||||
self.listwidth,
|
||||
cfg['ResolutionY'] - self.font.get_height(),
|
||||
border=False,
|
||||
data=self.roms,
|
||||
fg=(255, 255, 255),
|
||||
bg=(0, 0, 0),
|
||||
name='MainList',
|
||||
startitem=get_emu('CurrentGame'),
|
||||
itemattop=get_emu('GameAtTop'))
|
||||
|
||||
self.gui.render()
|
||||
|
||||
def update_menus(self):
|
||||
rootmenu = [
|
||||
'Show Artwork', 'Categories', 'Sort',
|
||||
'Hide Clones' if get_emu('ShowClones') else 'Show Clones',
|
||||
'Change Emulator', 'Quit'
|
||||
]
|
||||
sortmenu = ['Name Asc', 'Name Dec', 'Year Asc', 'Year Dec']
|
||||
emulatormenu = get_emulators()
|
||||
self.menus = {
|
||||
'rootmenu': rootmenu,
|
||||
'sortmenu': sortmenu,
|
||||
'emulatormenu': emulatormenu,
|
||||
'categorymenu': self.roms.categories
|
||||
}
|
||||
|
||||
def run(self):
|
||||
keyup = False
|
||||
quitcount = 0
|
||||
|
||||
while True:
|
||||
event = self.gui.waitevent()
|
||||
if event:
|
||||
if event.type == pygame.QUIT:
|
||||
break
|
||||
if event.type == pygame.KEYDOWN:
|
||||
keyup = False
|
||||
if event.key == pygame.K_ESCAPE and self.gui.currentobject == 1: # Main List
|
||||
quitcount += 1
|
||||
if quitcount == cfg['QuitKeyPresses']:
|
||||
break
|
||||
elif event.key == pygame.K_ESCAPE:
|
||||
quitcount = 0
|
||||
if self.gui.currentobject > 1:
|
||||
self.gui.deletelastobject()
|
||||
else:
|
||||
quitcount = 0
|
||||
if event.key in cfg[
|
||||
'KeySelect'] and self.gui.currentobject == 1:
|
||||
if sys.platform == 'darwin':
|
||||
print('Running %s' %
|
||||
self.roms[self.gui.getcurrentitem()].name)
|
||||
run_emulator(
|
||||
get_emu('EmulatorType'), get_emu('EXE'),
|
||||
self.roms[self.gui.getcurrentitem()].name)
|
||||
elif event.key in cfg[
|
||||
'KeyGameHistory'] and self.gui.currentobject == 1:
|
||||
history = self.roms.get_history(
|
||||
self.roms[self.gui.getcurrentitem()])
|
||||
if history:
|
||||
self.gui.add_notepad(-1, -1, 800, 600, history,
|
||||
True, WHITE, DARKGREY,
|
||||
'history', 'Game History')
|
||||
elif event.key in cfg[
|
||||
'KeyGameInfo'] and self.gui.currentobject == 1:
|
||||
info = self.roms.get_info(
|
||||
self.roms[self.gui.getcurrentitem()])
|
||||
if info:
|
||||
self.gui.add_notepad(-1, -1, 800, 600, info, True,
|
||||
WHITE, DARKGREY, 'info',
|
||||
'Game Information')
|
||||
elif event.key in cfg[
|
||||
'KeyPopup'] and self.gui.currentobject == 1:
|
||||
self.gui.add_menu(40, 40, -1, -1,
|
||||
self.menus['rootmenu'], True, WHITE,
|
||||
GREY, 'rootmenu', 0)
|
||||
elif event.key in cfg[
|
||||
'KeyPopup'] and self.gui.currentobject > 1:
|
||||
self.gui.deletelastobject()
|
||||
elif event.key in cfg['KeyShowArtwork']:
|
||||
pass
|
||||
# TODO: copy from below
|
||||
elif event.key in cfg['KeySelect']:
|
||||
currentitem = self.gui.getcurrentitem()
|
||||
menuname = self.gui.getmenuname()
|
||||
item = self.menus[menuname][currentitem]
|
||||
if menuname == 'rootmenu':
|
||||
if item == 'Quit':
|
||||
break
|
||||
elif item == 'Show Artwork':
|
||||
print('hello')
|
||||
aw = self.roms.get_artwork(
|
||||
self.roms[self.gui.getcurrentitem(0)])
|
||||
if aw != []:
|
||||
self.gui.add_image_notepad(
|
||||
-1, -1, 800, 600, aw, True, WHITE,
|
||||
DARKGREY, 'artwork', 'Artwork')
|
||||
elif item == 'Categories':
|
||||
self.gui.add_menu(
|
||||
80, 45, -1,
|
||||
-(self.screen.get_height() - 45 -
|
||||
(self.font.get_height() * 2) - 8),
|
||||
self.menus['categorymenu'], True, WHITE,
|
||||
GREY, 'categorymenu', 0)
|
||||
elif item == 'Sort':
|
||||
self.gui.add_menu(80, 45, -1, -1,
|
||||
self.menus['sortmenu'], True,
|
||||
WHITE, GREY, 'sortmenu', 0)
|
||||
elif item == 'Show Clones':
|
||||
set_emu('ShowClones', True)
|
||||
self.update_menus()
|
||||
self.roms.filter()
|
||||
self.gui.deleteallmenus()
|
||||
self.gui.setcurrentitem(0)
|
||||
elif item == 'Hide Clones':
|
||||
set_emu('ShowClones', False)
|
||||
self.update_menus()
|
||||
self.roms.filter()
|
||||
self.gui.deleteallmenus()
|
||||
self.gui.setcurrentitem(0)
|
||||
elif item == 'Change Emulator':
|
||||
self.gui.add_menu(
|
||||
80, 45, -1,
|
||||
-(self.screen.get_height() - 45 -
|
||||
(self.font.get_height() * 2) - 8),
|
||||
self.menus['emulatormenu'], True, WHITE,
|
||||
GREY, 'emulatormenu', 0)
|
||||
elif menuname == 'sortmenu':
|
||||
set_emu('Sort', item)
|
||||
self.roms.filter()
|
||||
self.gui.deleteallmenus()
|
||||
elif menuname == 'categorymenu':
|
||||
set_emu('Category', item)
|
||||
self.roms.filter()
|
||||
self.gui.deleteallmenus()
|
||||
self.gui.setcurrentitem(0)
|
||||
elif menuname == 'emulatormenu':
|
||||
cfg['Emulator'] = item
|
||||
if get_emu('EmulatorType') == 'MAME':
|
||||
self.roms = mame.MameROMs(
|
||||
cfg['datadir'], cfg['HideMature'],
|
||||
get_emu())
|
||||
if get_emu('EmulatorType') == 'MESS':
|
||||
self.roms = mess.MessROMs(
|
||||
cfg['datadir'], get_emu())
|
||||
if get_emu('EmulatorType') == 'CSV':
|
||||
self.roms = csvfile.csvROMs(
|
||||
cfg['datadir'], get_emu())
|
||||
|
||||
self.update_menus()
|
||||
self.gui.deleteallmenus()
|
||||
self.gui.deletelastobject()
|
||||
self.gui.add_menu(
|
||||
0,
|
||||
0,
|
||||
self.listwidth,
|
||||
cfg['ResolutionY'] - self.font.get_height(),
|
||||
border=False,
|
||||
data=self.roms,
|
||||
fg=(255, 255, 255),
|
||||
bg=(0, 0, 0),
|
||||
name='MainList',
|
||||
startitem=get_emu('CurrentGame'),
|
||||
itemattop=get_emu('GameAtTop'))
|
||||
|
||||
if event.type == pygame.KEYUP:
|
||||
keyup = True
|
||||
|
||||
if self.gui.currentobject == 1 and self.roms:
|
||||
currentitem = self.gui.getcurrentitem()
|
||||
|
||||
self.screen.fill(BLACK)
|
||||
self.status_surface.fill((128, 128, 128))
|
||||
|
||||
if keyup:
|
||||
pass
|
||||
if cfg['AlwaysChangeSnap'] or keyup:
|
||||
data = self.roms.get_snap(self.roms[currentitem], 'snap')
|
||||
screenshot_surface = image_from_data(data, (508, 480))
|
||||
|
||||
if cfg['ScanLines']:
|
||||
screenshot_surface = addscanlines(screenshot_surface)
|
||||
|
||||
self.screen.blit(
|
||||
screenshot_surface,
|
||||
(self.listwidth + 2 + (
|
||||
(self.screen.get_width() - self.listwidth + 2) / 2)
|
||||
- (screenshot_surface.get_width() / 2), 102))
|
||||
|
||||
data = self.roms.get_snap(self.roms[currentitem],
|
||||
'marquee')
|
||||
marquee_surface = image_from_data(data, (640, 100))
|
||||
|
||||
self.screen.blit(
|
||||
marquee_surface,
|
||||
(self.listwidth + 2 + (
|
||||
(self.screen.get_width() - self.listwidth + 2) / 2)
|
||||
- (marquee_surface.get_width() / 2), 0))
|
||||
|
||||
data = self.roms.get_snap(self.roms[currentitem], 'title')
|
||||
title_surface = image_from_data(
|
||||
data, (640, cfg['ResolutionY'] -
|
||||
(screenshot_surface.get_height() +
|
||||
marquee_surface.get_height() + 4 +
|
||||
self.status_surface.get_height())))
|
||||
|
||||
self.screen.blit(
|
||||
title_surface, (self.listwidth + 2 + (
|
||||
(self.screen.get_width() - self.listwidth + 2) / 2)
|
||||
- (title_surface.get_width() / 2),
|
||||
(screenshot_surface.get_height() +
|
||||
marquee_surface.get_height() + 4)))
|
||||
|
||||
size = self.font.size(
|
||||
'%d / %d %s' % (currentitem + 1, len(self.roms),
|
||||
get_emu('Sort')))[0]
|
||||
|
||||
self.status_surface.blit(
|
||||
self.font.render(
|
||||
'%d / %d %s' % (currentitem + 1, len(self.roms),
|
||||
get_emu('Sort')), True, BLACK,
|
||||
(128, 128, 128)), (cfg['ResolutionX'] - size - 5, 0))
|
||||
self.status_surface.blit(
|
||||
self.font.render(
|
||||
'%s %s' % (self.roms[currentitem].year,
|
||||
self.roms[currentitem].category), True,
|
||||
BLACK, (128, 128, 128)), (5, 0))
|
||||
|
||||
try:
|
||||
self.screen.blit(
|
||||
self.status_surface,
|
||||
(0, cfg['ResolutionY'] - self.font.get_height()))
|
||||
except:
|
||||
pass
|
||||
|
||||
self.gui.render()
|
||||
|
||||
pygame.mouse.set_visible(self.oldmouse)
|
||||
pygame.key.set_repeat()
|
||||
|
||||
set_emu('CurrentGame', self.gui.getcurrentitem())
|
||||
set_emu('GameAtTop', self.gui.getitemattop())
|
||||
|
||||
config_write()
|
||||
BIN
arcade.png
Normal file
BIN
arcade.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 43 KiB |
5
cfg/___empty.cfg
Normal file
5
cfg/___empty.cfg
Normal file
@@ -0,0 +1,5 @@
|
||||
<?xml version="1.0"?>
|
||||
<!-- This file is autogenerated; comments and unknown tags will be stripped -->
|
||||
<mameconfig version="10">
|
||||
<system name="___empty" />
|
||||
</mameconfig>
|
||||
5
cfg/default.cfg
Normal file
5
cfg/default.cfg
Normal file
@@ -0,0 +1,5 @@
|
||||
<?xml version="1.0"?>
|
||||
<!-- This file is autogenerated; comments and unknown tags will be stripped -->
|
||||
<mameconfig version="10">
|
||||
<system name="default" />
|
||||
</mameconfig>
|
||||
137
configfile.py
Normal file
137
configfile.py
Normal file
@@ -0,0 +1,137 @@
|
||||
from __future__ import print_function
|
||||
|
||||
import os
|
||||
|
||||
from appdirs import user_data_dir
|
||||
from configobj import ConfigObj, flatten_errors, Section
|
||||
from validate import Validator
|
||||
|
||||
from exclude import MAME_EXCLUDE
|
||||
from utils import get_pygame_keydict, get_keys
|
||||
|
||||
CFG = '''ResolutionX = integer(default=1024)
|
||||
ResolutionY = integer(default=768)
|
||||
FullScreen = boolean(default=False)
|
||||
Font = string(default='microsoftsansserif')
|
||||
FontSize = integer(default=13)
|
||||
QuitKeyPresses = integer(min=1,default=3)
|
||||
ScanLines = boolean(default=True)
|
||||
Key_Up = list(default=list('K_UP'))
|
||||
Key_Down = list(default=list('K_DOWN'))
|
||||
Key_PgUp = list(default=list('K_LEFT','K_PAGEUP'))
|
||||
Key_PgDn = list(default=list('K_RIGHT','K_PAGEDOWN'))
|
||||
Key_Home = list(default=list('K_HOME'))
|
||||
Key_End = list(default=list('K_END'))
|
||||
Key_Select = list(default=list('K_RETURN','K_1'))
|
||||
Key_GameInfo = list(default=list('K_5'))
|
||||
Key_GameHistory = list(default=list('K_6'))
|
||||
Key_Popup = list(default=list('K_2'))
|
||||
Key_ShowArtwork = list(default=list())
|
||||
AlwaysChangeSnap = boolean(default=True)
|
||||
HideMature = boolean(default=True)
|
||||
Emulator = string()
|
||||
[__many__]
|
||||
EXE = string()
|
||||
Version = string(default=None)
|
||||
ShowClones = boolean(default=True)
|
||||
Category = string(default='All Games')
|
||||
GameAtTop = integer(min=0,default=0)
|
||||
CurrentGame = integer(min=0,default=0)
|
||||
EmulatorType = option('MAME','MESS','CSV',default='MAME')
|
||||
StatusFilter = list(default=list())
|
||||
Sort = option('Name Asc','Name Dec','Year Asc','Year Dec',default='Name Asc')
|
||||
SnapDir = string(default=None)
|
||||
CSVFile = string(default=None)
|
||||
ArtworkDirs = list(default=list())
|
||||
'''
|
||||
|
||||
appname = 'MFE'
|
||||
appauthor = 'RMJ'
|
||||
|
||||
datadir = user_data_dir(appname, appauthor)
|
||||
datadir = os.getcwd()
|
||||
|
||||
if not os.path.isdir(datadir):
|
||||
os.makedirs(datadir)
|
||||
|
||||
spec = CFG.split('\n')
|
||||
cfg = ConfigObj(
|
||||
os.path.join(datadir, 'mfe.ini'), configspec=spec, encoding='UTF8')
|
||||
|
||||
validator = Validator()
|
||||
result = cfg.validate(validator, copy=True, preserve_errors=True)
|
||||
|
||||
stop = False
|
||||
for entry in flatten_errors(cfg, result):
|
||||
section_list, key, error = entry
|
||||
if key is not None:
|
||||
section_list.append(key)
|
||||
else:
|
||||
section_list.append('[missing section]')
|
||||
section_string = ', '.join(section_list)
|
||||
if error is False:
|
||||
error = 'Missing value or section.'
|
||||
print(section_string, ' = ', error)
|
||||
stop = True
|
||||
|
||||
cfg.write()
|
||||
|
||||
if stop:
|
||||
exit()
|
||||
|
||||
cfg["datadir"] = datadir
|
||||
|
||||
if not os.path.isfile(os.path.join(datadir, 'mame_exclude.txt')):
|
||||
with open(os.path.join(datadir, "mame_exclude.txt"), "wt") as f:
|
||||
f.write(MAME_EXCLUDE)
|
||||
|
||||
keys = get_pygame_keydict()
|
||||
cfg['KeyUp'] = get_keys(keys, cfg['Key_Up'])
|
||||
cfg['KeyDown'] = get_keys(keys, cfg['Key_Down'])
|
||||
cfg['KeyPgUp'] = get_keys(keys, cfg['Key_PgUp'])
|
||||
cfg['KeyPgDn'] = get_keys(keys, cfg['Key_PgDn'])
|
||||
cfg['KeyHome'] = get_keys(keys, cfg['Key_Home'])
|
||||
cfg['KeyEnd'] = get_keys(keys, cfg['Key_End'])
|
||||
cfg['KeySelect'] = get_keys(keys, cfg['Key_Select'])
|
||||
cfg['KeyGameInfo'] = get_keys(keys, cfg['Key_GameInfo'])
|
||||
cfg['KeyGameHistory'] = get_keys(keys, cfg['Key_GameHistory'])
|
||||
cfg['KeyPopup'] = get_keys(keys, cfg['Key_Popup'])
|
||||
cfg['KeyShowArtwork'] = get_keys(keys, cfg['Key_ShowArtwork'])
|
||||
|
||||
|
||||
def config_write():
|
||||
Exclude = [
|
||||
'KeyUp', 'KeyDown', 'KeyPgUp', 'KeyPgDn', 'KeySelect', 'KeyGameInfo',
|
||||
'KeyGameHistory', 'KeyPopup', 'KeyHome', 'KeyEnd', 'KeyShowArtwork',
|
||||
'datadir'
|
||||
]
|
||||
|
||||
t = {}
|
||||
for item in Exclude:
|
||||
t[item] = cfg[item]
|
||||
del cfg[item]
|
||||
|
||||
cfg.write()
|
||||
|
||||
for item in t:
|
||||
cfg[item] = t[item]
|
||||
|
||||
|
||||
def get_emu(option=None):
|
||||
if option:
|
||||
r = cfg[cfg['Emulator']][option]
|
||||
else:
|
||||
r = cfg[cfg['Emulator']]
|
||||
return r
|
||||
|
||||
|
||||
def set_emu(option, data):
|
||||
cfg[cfg['Emulator']][option] = data
|
||||
|
||||
|
||||
def get_emulators():
|
||||
r = []
|
||||
for k in cfg.keys():
|
||||
if isinstance(cfg[k], Section):
|
||||
r.append(k)
|
||||
return r
|
||||
143
csvfile.py
Normal file
143
csvfile.py
Normal file
@@ -0,0 +1,143 @@
|
||||
import csv
|
||||
import os
|
||||
import zipfile
|
||||
|
||||
|
||||
class csvROM(object):
|
||||
''' One CSV ROM '''
|
||||
|
||||
def __init__(self):
|
||||
self.name = ''
|
||||
self.cloneof = None
|
||||
self.description = ''
|
||||
self.year = ''
|
||||
self.manufacturer = ''
|
||||
self.status = ''
|
||||
self.category = ''
|
||||
self.snap = None
|
||||
|
||||
def __str__(self):
|
||||
return self.description
|
||||
|
||||
def __repr__(self):
|
||||
return '%s("%s", "%s", "%s", "%s", "%s", "%s", "%s")' % (
|
||||
self.__class__.__name__, self.name, self.cloneof, self.description,
|
||||
self.year, self.manufacturer, self.status, self.category)
|
||||
|
||||
|
||||
class csvROMs(object):
|
||||
''' A Collection of CSV Roms '''
|
||||
|
||||
def __init__(self, data_dir, cfg):
|
||||
self.all_roms = []
|
||||
self.roms = []
|
||||
self.all_categories = []
|
||||
self.categories = []
|
||||
self.catdict = {}
|
||||
self.len = 0
|
||||
self.data_dir = data_dir
|
||||
self.cfg = cfg
|
||||
self.emulator_dir = os.path.split(cfg['EXE'])[0]
|
||||
|
||||
self.parse()
|
||||
self.filter()
|
||||
|
||||
self.snapdir = cfg['SnapDir']
|
||||
if os.path.isfile(os.path.join(self.snapdir, 'snap.zip')):
|
||||
self.snapfile = zipfile.ZipFile(
|
||||
os.path.join(self.snapdir, "snap.zip"))
|
||||
else:
|
||||
self.snapfile = None
|
||||
|
||||
def __len__(self):
|
||||
return self.len
|
||||
|
||||
def __getitem__(self, item):
|
||||
return self.roms[item]
|
||||
|
||||
def filter(self):
|
||||
self.roms = []
|
||||
|
||||
for rom in self.all_roms:
|
||||
if self.cfg["Category"] == "All Games" or self.cfg["Category"] == rom.category:
|
||||
self.roms.append(rom)
|
||||
|
||||
if self.cfg["Sort"] == "Name Asc":
|
||||
self.roms.sort(key=lambda x: x.description.lower(), reverse=False)
|
||||
elif self.cfg["Sort"] == "Name Dec":
|
||||
self.roms.sort(key=lambda x: x.description.lower(), reverse=True)
|
||||
elif self.cfg["Sort"] == "Year Asc":
|
||||
self.roms.sort(key=lambda x: x.year.lower(), reverse=False)
|
||||
elif self.cfg["Sort"] == "Year Dec":
|
||||
self.roms.sort(key=lambda x: x.year.lower(), reverse=True)
|
||||
|
||||
self.len = len(self.roms)
|
||||
|
||||
self.categories = self.all_categories
|
||||
|
||||
def parse(self):
|
||||
''' Parse csv file '''
|
||||
if os.path.isfile(self.cfg['CSVFile']):
|
||||
with open(self.cfg['CSVFile']) as f:
|
||||
reader = csv.DictReader(f)
|
||||
|
||||
for game in reader:
|
||||
rom = csvROM()
|
||||
rom.name = game['romname']
|
||||
rom.description = game[
|
||||
'description'] if 'description' in game.keys(
|
||||
) else game['romname']
|
||||
rom.snap = game['snap'] if 'snap' in game.keys() else game[
|
||||
'romname']
|
||||
rom.year = game[
|
||||
'year'] if 'year' in game.keys() else 'Unknown Year'
|
||||
rom.category = game[
|
||||
'category'] if 'category' in game.keys() else 'Unknown'
|
||||
self.all_roms.append(rom)
|
||||
|
||||
self.all_categories.insert(0, 'All Games')
|
||||
self.all_categories.append('Unknown')
|
||||
|
||||
return True
|
||||
|
||||
def get_snap(self, rom, type_of_image): # pylint : disable=R0912
|
||||
data = None
|
||||
image_file = None
|
||||
image_dir = None
|
||||
|
||||
if type_of_image == 'snap':
|
||||
image_dir = self.snapdir
|
||||
image_file = self.snapfile
|
||||
|
||||
if image_file:
|
||||
try:
|
||||
data = image_file.read(rom.name + ".png")
|
||||
except:
|
||||
try:
|
||||
data = image_file.read(rom.cloneof + '.png')
|
||||
except:
|
||||
data = None
|
||||
elif image_dir:
|
||||
fn = os.path.join(image_dir, rom.name + '.png')
|
||||
if os.path.isfile(fn):
|
||||
with open(fn, 'rb') as f:
|
||||
data = f.read()
|
||||
elif rom.cloneof:
|
||||
fn = os.path.join(image_dir, rom.cloneof + '.png')
|
||||
if os.path.isfile(fn):
|
||||
with open(fn, 'rb') as f:
|
||||
data = f.read()
|
||||
else:
|
||||
data = None
|
||||
else:
|
||||
data = None
|
||||
else:
|
||||
data = None
|
||||
|
||||
return data
|
||||
|
||||
def get_info(self, rom):
|
||||
return
|
||||
|
||||
def get_history(self, rom):
|
||||
return
|
||||
99
exclude.py
Normal file
99
exclude.py
Normal file
@@ -0,0 +1,99 @@
|
||||
MAME_EXCLUDE = """3D Printer
|
||||
Astrological Computer
|
||||
Audio Sequencer
|
||||
Bank-teller Terminal
|
||||
Barcode Printer
|
||||
Bridge Machine
|
||||
Business Computer / Terminal
|
||||
Calculator / Pocket Computer
|
||||
Cash Counter
|
||||
Chess Machine
|
||||
Clock
|
||||
Credit Card Terminal
|
||||
DVD Player
|
||||
DVD Reader/Writer
|
||||
Dame Machine
|
||||
Development Computer
|
||||
Devices
|
||||
Document Processors
|
||||
Dot-Matrix Display
|
||||
Drum Machine
|
||||
EPROM Programmer
|
||||
Educational Game
|
||||
Electromechanical / Change Money
|
||||
Electromechanical / Coin Pusher
|
||||
Electromechanical / Misc.
|
||||
Electromechanical / Pinball
|
||||
Electromechanical / Redemption
|
||||
Electromechanical / Reels
|
||||
Electromechanical / Utilities
|
||||
Electronic Board Game
|
||||
Electronic Typewriter
|
||||
Engine Control Unit
|
||||
Gambling Board
|
||||
Game Console
|
||||
Game Console Expansion
|
||||
Graphic Tablet
|
||||
Graphics Display Controller
|
||||
Handheld Child Computers
|
||||
Handheld Game
|
||||
Handheld Game Console
|
||||
Home Computer
|
||||
In Circuit Emulator
|
||||
JukeBox
|
||||
Kit Computer
|
||||
Laptop / Notebook / Portable
|
||||
Laser Printer
|
||||
Matrix Printer
|
||||
Microcomputer
|
||||
Misc.
|
||||
Misc. * Mature *
|
||||
Mobile Phone
|
||||
Modem
|
||||
Multi-cart Board
|
||||
Network Processor
|
||||
Not Classified
|
||||
Pinball
|
||||
Pinball * Mature *
|
||||
Pinball / Pachinko
|
||||
Pinball / Pachinko * Mature *
|
||||
Player
|
||||
Pocket Device / Pad / PDA
|
||||
Portable Media Player
|
||||
Print Club
|
||||
Printer Handbook
|
||||
Programming Machine
|
||||
Punched Card Computer
|
||||
Quiz / Chinese
|
||||
Quiz / French
|
||||
Quiz / German
|
||||
Quiz / Italian
|
||||
Quiz / Japanese
|
||||
Quiz / Japanese * Mature *
|
||||
Quiz / Japanese - Music
|
||||
Quiz / Korean
|
||||
Quiz / Spanish
|
||||
Rhythm / Dance
|
||||
Rhythm / Instruments
|
||||
Rhythm / Misc.
|
||||
Robot Control
|
||||
Satellite Receiver
|
||||
Single Board Computer
|
||||
Speech Synthesizer
|
||||
Synthesizer
|
||||
System / BIOS
|
||||
System / Device
|
||||
Talking Calculator
|
||||
Telephone / ComputerPhone
|
||||
Test ROM
|
||||
Thermal Printer
|
||||
Toy cars
|
||||
Training Board
|
||||
Utilities / Test
|
||||
Utilities / Update
|
||||
VTR Control
|
||||
Virtual Environment
|
||||
Wavetables Generator
|
||||
Word-processing Machine
|
||||
Workstation / Server
|
||||
"""
|
||||
413
gui.py
Normal file
413
gui.py
Normal file
@@ -0,0 +1,413 @@
|
||||
import pygame
|
||||
# pylint: disable=E0611
|
||||
from pygame.locals import KEYDOWN
|
||||
# pylint: enable=E0611
|
||||
|
||||
from configfile import cfg
|
||||
from utils import wrap_multi_line, image_from_data
|
||||
|
||||
# pylint: disable=E1121,R0902,R0903,R0912,R0913
|
||||
|
||||
WHITE = (255, 255, 255)
|
||||
BLACK = (0, 0, 0)
|
||||
|
||||
|
||||
class baseobject(object):
|
||||
def __init__(self,
|
||||
surface,
|
||||
x,
|
||||
y,
|
||||
width,
|
||||
height,
|
||||
data,
|
||||
font,
|
||||
border=False,
|
||||
fg=WHITE,
|
||||
bg=BLACK,
|
||||
name=None,
|
||||
title=None):
|
||||
self.surface = surface
|
||||
self.x = x
|
||||
self.y = y
|
||||
self.width = width
|
||||
self.height = height
|
||||
self.font = font
|
||||
self.border = border
|
||||
self.fontheight = self.font.get_height()
|
||||
self.fg = fg
|
||||
self.bg = bg
|
||||
self.data = data
|
||||
self.name = name
|
||||
self.title = title
|
||||
|
||||
if self.width < 1:
|
||||
for item in self.data:
|
||||
size = self.font.size(item)[0]
|
||||
if size > self.width:
|
||||
self.width = size
|
||||
if self.width > self.surface.get_width():
|
||||
self.surface.get_width()
|
||||
if self.border:
|
||||
self.width += 8
|
||||
|
||||
if self.height < 1:
|
||||
self.height = self.fontheight * (len(self.data))
|
||||
if self.border:
|
||||
self.height += 8
|
||||
if self.height > self.surface.get_height():
|
||||
if self.border:
|
||||
self.height = self.surface.get_height() - 8 - self.y
|
||||
else:
|
||||
self.height = self.surface.get_height - self.y
|
||||
|
||||
if self.x == -1:
|
||||
self.x = int((self.surface.get_width() / 2) - (self.width / 2))
|
||||
|
||||
if self.y == -1:
|
||||
self.y = int((self.surface.get_height() / 2) - (self.height / 2))
|
||||
|
||||
if self.border:
|
||||
if not self.title:
|
||||
self.textx = self.x + 4
|
||||
self.texty = self.y + 4
|
||||
self.textwidth = self.width - 8
|
||||
self.textheight = self.height - 8
|
||||
else:
|
||||
self.textx = self.x + 4
|
||||
self.texty = self.y + 4 + self.fontheight
|
||||
self.textwidth = self.width - 8
|
||||
self.textheight = self.height - 8 - self.fontheight
|
||||
else:
|
||||
if not self.title:
|
||||
self.textx = self.x
|
||||
self.texty = self.y
|
||||
self.textwidth = self.width
|
||||
self.textheight = self.height
|
||||
else:
|
||||
self.textx = self.x
|
||||
self.texty = self.y + self.fontheight
|
||||
self.textwidth = self.width
|
||||
self.textheight = self.height - self.fontheight
|
||||
|
||||
|
||||
class menu(baseobject):
|
||||
def __init__(self,
|
||||
surface,
|
||||
x,
|
||||
y,
|
||||
width,
|
||||
height,
|
||||
data,
|
||||
font,
|
||||
border=False,
|
||||
fg=WHITE,
|
||||
bg=BLACK,
|
||||
name=None,
|
||||
startitem=0,
|
||||
itemattop=0):
|
||||
baseobject.__init__(self, surface, x, y, width, height, data, font,
|
||||
border, fg, bg, name)
|
||||
self.currentitem = startitem
|
||||
self.itemattop = itemattop
|
||||
self.itemsperpage = int(self.textheight / self.fontheight)
|
||||
self.isrom = True
|
||||
if str(type(self.data[0])) == "<class 'str'>":
|
||||
self.isrom = False
|
||||
|
||||
def processevent(self, event): # pylint: disable=R0912
|
||||
if event.type == KEYDOWN:
|
||||
if event.key in cfg["KeyUp"] and self.currentitem > 0:
|
||||
if self.currentitem == self.itemattop:
|
||||
self.itemattop -= 1
|
||||
self.currentitem -= 1
|
||||
if event.key in cfg["KeyDown"] and self.currentitem < len(
|
||||
self.data) - 1:
|
||||
self.currentitem += 1
|
||||
if self.itemattop + self.itemsperpage <= self.currentitem:
|
||||
self.itemattop += 1
|
||||
if event.key in cfg["KeyPgUp"] and self.currentitem > 0:
|
||||
self.currentitem -= self.itemsperpage - 1
|
||||
while self.itemattop > self.currentitem:
|
||||
self.itemattop -= 1
|
||||
if self.itemattop < 0:
|
||||
self.itemattop = 0
|
||||
self.currentitem = 0
|
||||
if event.key in cfg["KeyPgDn"] and self.currentitem < len(
|
||||
self.data) - 1:
|
||||
self.currentitem += self.itemsperpage - 1
|
||||
while self.currentitem - self.itemattop >= self.itemsperpage:
|
||||
self.itemattop += 1
|
||||
if self.itemattop + self.itemsperpage > len(self.data):
|
||||
self.itemattop = len(self.data) - self.itemsperpage
|
||||
self.currentitem = len(self.data) - 1
|
||||
if event.key in cfg["KeyHome"] and self.currentitem > 0:
|
||||
self.currentitem = 0
|
||||
self.itemattop = 0
|
||||
if event.key in cfg["KeyEnd"] and self.currentitem < len(
|
||||
self.data) - 1:
|
||||
self.currentitem = len(self.data) - 1
|
||||
self.itemattop = self.currentitem - self.itemsperpage + 1
|
||||
|
||||
def render(self):
|
||||
pygame.Surface.fill(
|
||||
self.surface,
|
||||
self.bg,
|
||||
rect=pygame.Rect(self.x, self.y, self.width, self.height))
|
||||
|
||||
if self.border:
|
||||
pygame.draw.rect(self.surface, self.fg,
|
||||
pygame.Rect(self.x + 1, self.y + 1,
|
||||
self.width - 2, self.height - 2), 1)
|
||||
|
||||
for i in range(0, self.itemsperpage):
|
||||
if i > len(self.data) - 1:
|
||||
t = pygame.Surface((self.textwidth, self.fontheight))
|
||||
t.fill(self.bg)
|
||||
self.surface.blit(t, (self.textx,
|
||||
self.texty + i * self.fontheight))
|
||||
continue
|
||||
|
||||
if self.isrom:
|
||||
item = self.data[self.itemattop + i].description
|
||||
else:
|
||||
item = self.data[self.itemattop + i]
|
||||
|
||||
if self.itemattop + i == self.currentitem:
|
||||
s = self.font.render(item, True, self.bg, self.fg)
|
||||
t = pygame.Surface((self.textwidth, self.fontheight))
|
||||
t.fill(self.fg)
|
||||
t.blit(s, (0, 0))
|
||||
self.surface.blit(t, (self.textx,
|
||||
self.texty + i * self.fontheight))
|
||||
else:
|
||||
s = self.font.render(item, True, self.fg, self.bg)
|
||||
t = pygame.Surface((self.textwidth, self.fontheight))
|
||||
t.fill(self.bg)
|
||||
t.blit(s, (0, 0))
|
||||
self.surface.blit(t, (self.textx,
|
||||
self.texty + i * self.fontheight))
|
||||
|
||||
|
||||
class notepad(baseobject):
|
||||
def __init__(self,
|
||||
surface,
|
||||
x,
|
||||
y,
|
||||
width,
|
||||
height,
|
||||
data,
|
||||
font,
|
||||
border=False,
|
||||
fg=WHITE,
|
||||
bg=BLACK,
|
||||
name="None",
|
||||
title=None):
|
||||
baseobject.__init__(self, surface, x, y, width, height, data, font,
|
||||
border, fg, bg, name, title)
|
||||
self.data = wrap_multi_line(data, self.font, self.textwidth)
|
||||
self.lineattop = 0
|
||||
self.linesperpage = int(self.textheight / self.fontheight)
|
||||
self.lasttopline = int(len(self.data) - self.linesperpage)
|
||||
|
||||
def processevent(self, event):
|
||||
if event.type == KEYDOWN:
|
||||
if event.key in cfg["KeyDown"] and self.lineattop < self.lasttopline:
|
||||
self.lineattop += 1
|
||||
elif event.key in cfg["KeyUp"] and self.lineattop > 0:
|
||||
self.lineattop -= 1
|
||||
elif event.key in cfg["KeyPgDn"] and self.lineattop < self.lasttopline:
|
||||
self.lineattop += self.linesperpage
|
||||
if self.lineattop > self.lasttopline:
|
||||
self.lineattop = self.lasttopline
|
||||
elif event.key in cfg["KeyPgUp"] and self.lineattop > 0:
|
||||
self.lineattop -= self.linesperpage
|
||||
if self.lineattop < 0:
|
||||
self.lineattop = 0
|
||||
elif event.key in cfg["KeyHome"] and self.lineattop > 0:
|
||||
self.lineattop = 0
|
||||
elif event.key in cfg["KeyEnd"] and self.lineattop < self.lasttopline:
|
||||
self.lineattop = self.lasttopline
|
||||
|
||||
def render(self):
|
||||
pygame.Surface.fill(
|
||||
self.surface,
|
||||
self.bg,
|
||||
rect=pygame.Rect(self.x, self.y, self.width, self.height))
|
||||
if self.border:
|
||||
pygame.draw.rect(self.surface, self.fg,
|
||||
pygame.Rect(self.x + 1, self.y + 1,
|
||||
self.width - 2, self.height - 2), 1)
|
||||
if self.title:
|
||||
x = (self.textwidth / 2) - (
|
||||
self.font.size('%s' % self.title)[0] / 2)
|
||||
title_surface = pygame.Surface((self.textwidth,
|
||||
self.fontheight))
|
||||
title_surface.fill(self.fg)
|
||||
title_surface.blit(
|
||||
self.font.render('%s' % self.title, True, BLACK, self.fg),
|
||||
(x, 0))
|
||||
self.surface.blit(title_surface,
|
||||
(self.textx, self.texty - self.fontheight))
|
||||
for c in range(0, self.linesperpage):
|
||||
try:
|
||||
itemsurface = self.font.render(self.data[c + self.lineattop],
|
||||
True, self.fg, self.bg)
|
||||
self.surface.blit(itemsurface,
|
||||
(self.textx,
|
||||
self.texty + c * self.fontheight))
|
||||
except:
|
||||
pass
|
||||
|
||||
|
||||
class image_notepad(baseobject):
|
||||
def __init__(self,
|
||||
surface,
|
||||
x,
|
||||
y,
|
||||
width,
|
||||
height,
|
||||
data,
|
||||
font,
|
||||
border=False,
|
||||
fg=WHITE,
|
||||
bg=BLACK,
|
||||
name="None",
|
||||
title=None):
|
||||
baseobject.__init__(self, surface, x, y, width, height, data, font,
|
||||
border, fg, bg, name, title)
|
||||
self.currentitem = 0
|
||||
self.data = data
|
||||
|
||||
def processevent(self, event):
|
||||
if event.type == KEYDOWN:
|
||||
if event.key in cfg["KeyPgDn"]:
|
||||
if self.currentitem < len(self.data) - 1:
|
||||
self.currentitem += 1
|
||||
elif event.key in cfg["KeyPgUp"]:
|
||||
if self.currentitem > 0:
|
||||
self.currentitem -= 1
|
||||
|
||||
def render(self):
|
||||
pygame.Surface.fill(
|
||||
self.surface,
|
||||
self.bg,
|
||||
rect=pygame.Rect(self.x, self.y, self.width, self.height))
|
||||
if self.border:
|
||||
pygame.draw.rect(self.surface, self.fg,
|
||||
pygame.Rect(self.x + 1, self.y + 1,
|
||||
self.width - 2, self.height - 2), 1)
|
||||
x = (self.textwidth / 2) - (self.font.size('%s' % self.title)[0] / 2)
|
||||
title_surface = pygame.Surface((self.textwidth, self.fontheight))
|
||||
title_surface.fill(self.fg)
|
||||
title_surface.blit(
|
||||
self.font.render('%s' % self.data[self.currentitem][0], True,
|
||||
BLACK, self.fg), (x, 0))
|
||||
self.surface.blit(title_surface, (self.textx,
|
||||
self.texty - self.fontheight))
|
||||
|
||||
image_surface = image_from_data(self.data[self.currentitem][1],
|
||||
(self.textwidth, self.textheight))
|
||||
|
||||
w, h = image_surface.get_width(), image_surface.get_height()
|
||||
|
||||
x = (self.textwidth / 2) - (w / 2) + self.textx
|
||||
y = (self.textheight / 2) - (h / 2) + self.texty
|
||||
|
||||
self.surface.blit(image_surface, (x, y))
|
||||
|
||||
|
||||
class gui():
|
||||
def __init__(self, surface):
|
||||
self.surface = surface
|
||||
self.objects = []
|
||||
self.font = pygame.font.Font(
|
||||
pygame.font.match_font(cfg["Font"], bold=True), cfg["FontSize"])
|
||||
# self.fontheight = self.font.get_height()
|
||||
self.currentobject = 0
|
||||
|
||||
def waitevent(self):
|
||||
event = pygame.event.wait()
|
||||
|
||||
if self.objects:
|
||||
self.objects[-1].processevent(event)
|
||||
|
||||
return event
|
||||
|
||||
def add_menu(self,
|
||||
x,
|
||||
y,
|
||||
width,
|
||||
height,
|
||||
data,
|
||||
border=False,
|
||||
fg=WHITE,
|
||||
bg=BLACK,
|
||||
name="None",
|
||||
startitem=0,
|
||||
itemattop=0):
|
||||
self.currentobject += 1
|
||||
self.objects.append(
|
||||
menu(self.surface, x, y, width, height, data, self.font, border,
|
||||
fg, bg, name, startitem, itemattop))
|
||||
|
||||
def add_notepad(self,
|
||||
x,
|
||||
y,
|
||||
width,
|
||||
height,
|
||||
data,
|
||||
border=False,
|
||||
fg=WHITE,
|
||||
bg=BLACK,
|
||||
name="None",
|
||||
title=None):
|
||||
self.currentobject += 1
|
||||
self.objects.append(
|
||||
notepad(self.surface, x, y, width, height, data, self.font, border,
|
||||
fg, bg, name, title))
|
||||
|
||||
def add_image_notepad(self,
|
||||
x,
|
||||
y,
|
||||
width,
|
||||
height,
|
||||
data,
|
||||
border=False,
|
||||
fg=WHITE,
|
||||
bg=BLACK,
|
||||
name="None",
|
||||
title=None):
|
||||
self.currentobject += 1
|
||||
self.objects.append(
|
||||
image_notepad(self.surface, x, y, width, height, data, self.font,
|
||||
border, fg, bg, name, title))
|
||||
|
||||
def deletelastobject(self):
|
||||
del self.objects[-1]
|
||||
self.currentobject -= 1
|
||||
|
||||
def getmenuname(self):
|
||||
return self.objects[-1].name
|
||||
|
||||
def deleteallmenus(self):
|
||||
while self.currentobject > 1:
|
||||
self.deletelastobject()
|
||||
|
||||
def getcurrentitem(self, objnum=None):
|
||||
if objnum is None:
|
||||
return self.objects[-1].currentitem
|
||||
return self.objects[objnum].currentitem
|
||||
|
||||
def getitemattop(self):
|
||||
return self.objects[-1].itemattop
|
||||
|
||||
# TODO: Fix me for itemattop on normal menus
|
||||
def setcurrentitem(self, selected_item):
|
||||
self.objects[-1].itemattop = selected_item
|
||||
self.objects[-1].currentitem = selected_item
|
||||
|
||||
def render(self):
|
||||
for t in self.objects:
|
||||
t.render()
|
||||
|
||||
pygame.display.update()
|
||||
BIN
images/arcade.icns
Normal file
BIN
images/arcade.icns
Normal file
Binary file not shown.
BIN
images/arcade.ico
Normal file
BIN
images/arcade.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 361 KiB |
406
mame.py
Normal file
406
mame.py
Normal file
@@ -0,0 +1,406 @@
|
||||
import os
|
||||
import pickle
|
||||
import re
|
||||
import subprocess
|
||||
import zipfile
|
||||
from glob import glob
|
||||
|
||||
from lxml import etree
|
||||
from titlecase import titlecase
|
||||
|
||||
|
||||
class MameROM(object):
|
||||
''' One Mame ROM '''
|
||||
|
||||
def __init__(self):
|
||||
self.name = ''
|
||||
self.cloneof = None
|
||||
self.description = ''
|
||||
self.year = ''
|
||||
self.manufacturer = ''
|
||||
self.status = ''
|
||||
self.category = ''
|
||||
|
||||
def __str__(self):
|
||||
return self.description
|
||||
|
||||
def __repr__(self):
|
||||
return '%s("%s", "%s", "%s", "%s", "%s", "%s", "%s")' % (
|
||||
self.__class__.__name__, self.name, self.cloneof, self.description,
|
||||
self.year, self.manufacturer, self.status, self.category)
|
||||
|
||||
|
||||
class MameROMs(object):
|
||||
''' A Collection of MAME Roms '''
|
||||
|
||||
def __init__(self, data_dir, hide_mature, cfg):
|
||||
self.all_roms = []
|
||||
self.roms = []
|
||||
self.all_categories = []
|
||||
self.categories = []
|
||||
self.catdict = {}
|
||||
self.len = 0
|
||||
self.data_dir = data_dir
|
||||
self.hide_mature = hide_mature
|
||||
self.cfg = cfg
|
||||
self.emulator_dir = os.path.split(cfg['EXE'])[0]
|
||||
|
||||
self.parse()
|
||||
self.filter()
|
||||
|
||||
self.snapdir = os.path.join(self.emulator_dir, 'snap')
|
||||
if os.path.isfile(os.path.join(self.snapdir, 'snap.zip')):
|
||||
self.snapfile = zipfile.ZipFile(
|
||||
os.path.join(self.snapdir, "snap.zip"))
|
||||
else:
|
||||
self.snapfile = None
|
||||
self.snapdir = os.path.join(self.snapdir, 'snap')
|
||||
|
||||
self.marqueesdir = os.path.join(self.emulator_dir, 'marquees')
|
||||
if os.path.isfile(os.path.join(self.marqueesdir, 'marquees.zip')):
|
||||
self.marqueesfile = zipfile.ZipFile(
|
||||
os.path.join(self.marqueesdir, "marquees.zip"))
|
||||
else:
|
||||
self.marqueesfile = None
|
||||
self.marqueesdir = os.path.join(self.marqueesdir, 'marquees')
|
||||
|
||||
self.titlesdir = os.path.join(self.emulator_dir, 'titles')
|
||||
if os.path.isfile(os.path.join(self.titlesdir, 'titles.zip')):
|
||||
self.titlesfile = zipfile.ZipFile(
|
||||
os.path.join(self.titlesdir, "titles.zip"))
|
||||
else:
|
||||
self.titlesfile = None
|
||||
self.titlesdir = os.path.join(self.titlesdir, 'titles')
|
||||
|
||||
infofn = os.path.join(self.emulator_dir, 'mameinfo.dat')
|
||||
if not os.path.isfile(infofn):
|
||||
self.info = None
|
||||
else:
|
||||
with open(infofn, 'rt', encoding='latin1') as f:
|
||||
self.info = f.read()
|
||||
|
||||
historyfn = os.path.join(self.emulator_dir, 'history.dat')
|
||||
if not os.path.isfile(historyfn):
|
||||
self.history = None
|
||||
else:
|
||||
with open(historyfn, 'rt', encoding='utf-8') as f:
|
||||
self.history = f.read()
|
||||
|
||||
self.artwork_dirs = {}
|
||||
for item in cfg['ArtworkDirs']:
|
||||
directory = os.path.join(self.emulator_dir, item)
|
||||
if os.path.isdir(directory):
|
||||
if os.path.isfile(os.path.join(directory, '%s.zip' % item)):
|
||||
self.artwork_dirs[titlecase(item)] = {
|
||||
"dof": os.path.join(directory, '%s.zip' % item),
|
||||
'type': 'file'
|
||||
}
|
||||
else:
|
||||
self.artwork_dirs[titlecase(item)] = {
|
||||
"dof": directory,
|
||||
'type': 'dir'
|
||||
}
|
||||
|
||||
def __len__(self):
|
||||
return self.len
|
||||
|
||||
def __getitem__(self, item):
|
||||
return self.roms[item]
|
||||
|
||||
def filter(self):
|
||||
self.roms = []
|
||||
|
||||
for rom in self.all_roms:
|
||||
if rom.status in self.cfg['StatusFilter']:
|
||||
if self.cfg["Category"] == "All Games" or self.cfg["Category"] == rom.category:
|
||||
if self.cfg["ShowClones"] or rom.cloneof is None:
|
||||
if not self.hide_mature or '* Mature *' not in rom.category:
|
||||
self.roms.append(rom)
|
||||
|
||||
if self.cfg["Sort"] == "Name Asc":
|
||||
self.roms.sort(key=lambda x: x.description.lower(), reverse=False)
|
||||
elif self.cfg["Sort"] == "Name Dec":
|
||||
self.roms.sort(key=lambda x: x.description.lower(), reverse=True)
|
||||
elif self.cfg["Sort"] == "Year Asc":
|
||||
self.roms.sort(key=lambda x: x.year.lower(), reverse=False)
|
||||
elif self.cfg["Sort"] == "Year Dec":
|
||||
self.roms.sort(key=lambda x: x.year.lower(), reverse=True)
|
||||
|
||||
self.len = len(self.roms)
|
||||
|
||||
if self.hide_mature:
|
||||
self.categories = []
|
||||
for category in self.all_categories:
|
||||
if '* Mature *' not in category:
|
||||
self.categories.append(category)
|
||||
else:
|
||||
self.categories = self.all_categories
|
||||
|
||||
def parse(self):
|
||||
''' Parse xml '''
|
||||
|
||||
mame_version = self.get_mame_version()
|
||||
xmlfile = os.path.join(self.emulator_dir, 'mame.xml')
|
||||
datfile = os.path.join(self.data_dir, 'mame.dat')
|
||||
|
||||
if self.cfg['Version'] != mame_version:
|
||||
self.cfg['Version'] = mame_version
|
||||
|
||||
if os.path.isfile(xmlfile):
|
||||
os.unlink(xmlfile)
|
||||
|
||||
if os.path.isfile(datfile):
|
||||
with open(datfile, 'rb') as i:
|
||||
temp_mame_version = pickle.load(i)
|
||||
|
||||
if temp_mame_version == mame_version:
|
||||
self.all_categories = pickle.load(i)
|
||||
self.all_roms = pickle.load(i)
|
||||
return True
|
||||
else:
|
||||
os.unlink(datfile, 'mame.dat')
|
||||
|
||||
tempcat = {}
|
||||
catfile = open(os.path.join(self.emulator_dir, 'catver.ini'))
|
||||
|
||||
found = False
|
||||
for line in catfile:
|
||||
line = line.strip()
|
||||
if line == '[VerAdded]':
|
||||
break
|
||||
if line == '[Category]':
|
||||
found = True
|
||||
if found and line != '' and line[0] != ';' and line[0] != '[':
|
||||
# zwackery=Platform / Run Jump
|
||||
game, category = line.split('=')
|
||||
tempcat[game] = category
|
||||
if category not in self.all_categories:
|
||||
self.all_categories.append(category)
|
||||
self.catdict[category] = 0
|
||||
|
||||
self.all_categories.sort()
|
||||
self.all_categories.insert(0, 'All Games')
|
||||
self.all_categories.append('Unknown')
|
||||
self.catdict['All Games'] = 1
|
||||
self.catdict['Unknown'] = 0
|
||||
|
||||
if not os.path.isfile(xmlfile):
|
||||
try:
|
||||
with open(xmlfile, 'w') as out:
|
||||
retcode = subprocess.call(
|
||||
[self.cfg['EXE'], '-listxml'], stdout=out)
|
||||
if retcode != 0:
|
||||
try:
|
||||
os.unlink(xmlfile)
|
||||
except:
|
||||
pass
|
||||
return False
|
||||
except OSError:
|
||||
try:
|
||||
os.unlink(xmlfile)
|
||||
except:
|
||||
pass
|
||||
return False
|
||||
|
||||
# pylint: disable=no-member
|
||||
|
||||
with open(os.path.join(self.data_dir, 'mame_exclude.txt'), 'rt') as f:
|
||||
exclude = f.readlines()
|
||||
exclude = [x.strip() for x in exclude]
|
||||
|
||||
tree = etree.parse(xmlfile)
|
||||
|
||||
rom = None
|
||||
for child in tree.getiterator():
|
||||
if child.tag == 'machine':
|
||||
if rom:
|
||||
if rom.category not in exclude:
|
||||
self.all_roms.append(rom)
|
||||
self.catdict[rom.category] += 1
|
||||
rom = None
|
||||
if 'runnable' in child.attrib and child.attrib['runnable'] == 'yes':
|
||||
rom = MameROM()
|
||||
rom.name = child.attrib['name']
|
||||
else:
|
||||
rom = None
|
||||
if rom and 'cloneof' in child.attrib:
|
||||
rom.cloneof = child.attrib['cloneof']
|
||||
if rom and rom.name in tempcat:
|
||||
rom.category = tempcat[rom.name]
|
||||
elif rom and rom.cloneof in tempcat:
|
||||
rom.category = tempcat[rom.cloneof]
|
||||
elif rom:
|
||||
rom.category = 'Unknown'
|
||||
elif rom and child.tag == 'description':
|
||||
rom.description = child.text
|
||||
elif rom and child.tag == 'year':
|
||||
rom.year = child.text
|
||||
elif rom and child.tag == 'manufacturer':
|
||||
rom.manufacturer = child.text
|
||||
elif rom and child.tag == 'driver':
|
||||
rom.status = child.attrib['status']
|
||||
|
||||
if rom:
|
||||
if rom.category not in exclude:
|
||||
self.all_roms.append(rom)
|
||||
|
||||
for cat in self.catdict:
|
||||
if self.catdict[cat] == 0:
|
||||
del self.all_categories[self.all_categories.index(cat)]
|
||||
|
||||
with open(datfile, 'wb') as output:
|
||||
pickle.dump(mame_version, output)
|
||||
pickle.dump(self.all_categories, output)
|
||||
pickle.dump(self.all_roms, output)
|
||||
|
||||
return True
|
||||
|
||||
def get_mame_version(self):
|
||||
mamerun = subprocess.run(
|
||||
[self.cfg['EXE'], '-?'], stdout=subprocess.PIPE)
|
||||
output = mamerun.stdout.decode('utf-8')
|
||||
output = output[output.find('v'):]
|
||||
output = output[:output.find(' ')]
|
||||
|
||||
return output
|
||||
|
||||
def get_info(self, rom):
|
||||
if not self.info:
|
||||
return
|
||||
|
||||
search = re.search("\\$info=%s" % rom.name, self.info)
|
||||
|
||||
if not search:
|
||||
search = re.search("\\$info=%s" % rom.cloneof, self.info)
|
||||
if not search:
|
||||
return None
|
||||
|
||||
start = search.start()
|
||||
|
||||
info = self.info[start:self.info.find('$end', start)].splitlines()
|
||||
|
||||
for i in range(len(info) - 1, -1, -1):
|
||||
if info[i].startswith('$'):
|
||||
del info[i]
|
||||
|
||||
while info[0].strip() == '':
|
||||
del info[0]
|
||||
|
||||
while info[len(info) - 1].strip() == '':
|
||||
del info[len(info) - 1]
|
||||
|
||||
return '\n'.join(info)
|
||||
|
||||
def get_history(self, rom):
|
||||
if not self.history:
|
||||
return
|
||||
|
||||
search = re.search("\\$info=%s" % rom.name, self.history)
|
||||
|
||||
if not search:
|
||||
search = re.search("\\$info=%s" % rom.cloneof, self.history)
|
||||
if not search:
|
||||
return None
|
||||
|
||||
start = search.start()
|
||||
|
||||
info = self.history[start:self.history.find('$end',
|
||||
start)].splitlines()
|
||||
|
||||
for i in range(len(info) - 1, -1, -1):
|
||||
if info[i].startswith('$'):
|
||||
del info[i]
|
||||
|
||||
while info[0].strip() == '':
|
||||
del info[0]
|
||||
|
||||
while info[len(info) - 1].strip() == '':
|
||||
del info[len(info) - 1]
|
||||
|
||||
return '\n'.join(info)
|
||||
|
||||
def get_snap(self, rom, type_of_image): # pylint : disable=R0912
|
||||
data = None
|
||||
image_file = None
|
||||
image_dir = None
|
||||
|
||||
if type_of_image == 'snap':
|
||||
image_dir = self.snapdir
|
||||
image_file = self.snapfile
|
||||
if type_of_image == 'title':
|
||||
image_dir = self.titlesdir
|
||||
image_file = self.titlesfile
|
||||
if type_of_image == 'marquee':
|
||||
image_dir = self.marqueesdir
|
||||
image_file = self.marqueesfile
|
||||
|
||||
if image_file:
|
||||
try:
|
||||
data = image_file.read(rom.name + ".png")
|
||||
except:
|
||||
try:
|
||||
data = image_file.read(rom.cloneof + '.png')
|
||||
except:
|
||||
data = None
|
||||
elif image_dir:
|
||||
fn = os.path.join(image_dir, rom.name + '.png')
|
||||
if os.path.isfile(fn):
|
||||
with open(fn, 'rb') as f:
|
||||
data = f.read()
|
||||
elif rom.cloneof:
|
||||
fn = os.path.join(image_dir, rom.cloneof + '.png')
|
||||
if os.path.isfile(fn):
|
||||
with open(fn, 'rb') as f:
|
||||
data = f.read()
|
||||
else:
|
||||
data = None
|
||||
else:
|
||||
data = None
|
||||
else:
|
||||
data = None
|
||||
|
||||
return data
|
||||
|
||||
def get_artwork(self, rom):
|
||||
result = []
|
||||
|
||||
for item in self.artwork_dirs:
|
||||
title = item
|
||||
dof = self.artwork_dirs[title]['dof']
|
||||
|
||||
if self.artwork_dirs[title]['type'] == 'dir':
|
||||
fn = None
|
||||
if glob('%s/**/%s.*' % (dof, rom.name), recursive=True) != []:
|
||||
fn = glob(
|
||||
'%s/**/%s.*' % (dof, rom.name), recursive=True)[0]
|
||||
elif glob(
|
||||
'%s/**/%s.*' %
|
||||
(dof, rom.cloneof), recursive=True) != []:
|
||||
fn = glob(
|
||||
'%s/**/%s.*' % (dof, rom.cloneof), recursive=True)[0]
|
||||
if fn:
|
||||
data = None
|
||||
if os.path.splitext(fn)[1].lower() in [
|
||||
'.png', '.jpg', '.jpeg'
|
||||
]:
|
||||
with open(fn, 'rb') as f:
|
||||
data = f.read()
|
||||
|
||||
if data:
|
||||
result.append([title, data])
|
||||
else:
|
||||
data = None
|
||||
try:
|
||||
with zipfile.ZipFile(dof) as f:
|
||||
data = f.read('%s.png' % rom.name)
|
||||
except:
|
||||
try:
|
||||
with zipfile.ZipFile(dof) as f:
|
||||
data = f.read('%s.png' % rom.cloneof)
|
||||
except:
|
||||
data = None
|
||||
|
||||
if data:
|
||||
result.append([title, data])
|
||||
|
||||
return result
|
||||
281
mess.py
Normal file
281
mess.py
Normal file
@@ -0,0 +1,281 @@
|
||||
import glob
|
||||
import os
|
||||
import pickle
|
||||
import re
|
||||
import subprocess
|
||||
from xml.sax.saxutils import unescape
|
||||
import zipfile
|
||||
|
||||
from lxml import etree
|
||||
|
||||
|
||||
class MessROM(object):
|
||||
''' One Mame Software List ROM '''
|
||||
|
||||
def __init__(self):
|
||||
self.name = ''
|
||||
self.cloneof = None
|
||||
self.description = ''
|
||||
self.year = ''
|
||||
self.manufacturer = ''
|
||||
self.category = ''
|
||||
|
||||
def __str__(self):
|
||||
return self.description
|
||||
# return '["%s", "%s", "%s", "%s", "%s" "%s", "%s"]' % (
|
||||
# self.name, self.cloneof, self.description, self.year,
|
||||
# self.manufacturer, self.status, self.category)
|
||||
|
||||
def __repr__(self):
|
||||
return '%s("%s", "%s", "%s", "%s", "%s", "%s")' % (
|
||||
self.__class__.__name__, self.name, self.cloneof, self.description,
|
||||
self.year, self.manufacturer, self.category)
|
||||
|
||||
|
||||
class MessROMs(object):
|
||||
''' A Collection of MAME Software List Roms '''
|
||||
|
||||
def __init__(self, data_dir, cfg):
|
||||
self.all_roms = []
|
||||
self.roms = []
|
||||
self.categories = []
|
||||
self.all_categories = []
|
||||
self.catdict = {}
|
||||
self.len = 0
|
||||
self.data_dir = data_dir
|
||||
self.cfg = cfg
|
||||
self.emulator_dir = os.path.split(cfg['EXE'])[0]
|
||||
|
||||
self.parse()
|
||||
self.filter()
|
||||
|
||||
self.snapdir = os.path.join(self.emulator_dir, 'snap')
|
||||
if os.path.isfile(os.path.join(self.snapdir, 'snap.zip')):
|
||||
self.snapfile = zipfile.ZipFile(
|
||||
os.path.join(self.snapdir, "snap.zip"))
|
||||
else:
|
||||
self.snapfile = None
|
||||
self.snapdir = os.path.join(self.snapdir, 'snap')
|
||||
|
||||
infofn = os.path.join(self.emulator_dir, 'messinfo.dat')
|
||||
if not os.path.isfile(infofn):
|
||||
self.info = None
|
||||
else:
|
||||
with open(infofn, 'rt', encoding='latin1') as f:
|
||||
self.info = f.read()
|
||||
|
||||
historyfn = os.path.join(self.emulator_dir, 'history.dat')
|
||||
if not os.path.isfile(historyfn):
|
||||
self.history = None
|
||||
else:
|
||||
with open(historyfn, 'rt', encoding='utf-8') as f:
|
||||
self.history = f.read()
|
||||
|
||||
def __len__(self):
|
||||
return self.len
|
||||
|
||||
def __getitem__(self, item):
|
||||
return self.roms[item]
|
||||
|
||||
def filter(self):
|
||||
self.roms = []
|
||||
|
||||
for rom in self.all_roms:
|
||||
if self.cfg["Category"] == "All Games" or self.cfg["Category"] == rom.category:
|
||||
if self.cfg["ShowClones"] or rom.cloneof is None:
|
||||
self.roms.append(rom)
|
||||
|
||||
if self.cfg["Sort"] == "Name Asc":
|
||||
self.roms.sort(key=lambda x: x.description.lower(), reverse=False)
|
||||
elif self.cfg["Sort"] == "Name Dec":
|
||||
self.roms.sort(key=lambda x: x.description.lower(), reverse=True)
|
||||
elif self.cfg["Sort"] == "Year Asc":
|
||||
self.roms.sort(key=lambda x: x.year.lower(), reverse=False)
|
||||
elif self.cfg["Sort"] == "Year Dec":
|
||||
self.roms.sort(key=lambda x: x.year.lower(), reverse=True)
|
||||
|
||||
self.len = len(self.roms)
|
||||
|
||||
self.categories = self.all_categories
|
||||
|
||||
def parse(self):
|
||||
""" Parse xml """
|
||||
|
||||
mess_version = self.get_mess_version()
|
||||
datfile = os.path.join(self.data_dir, 'mess.dat')
|
||||
|
||||
if self.cfg['Version'] != mess_version:
|
||||
self.cfg['Version'] = mess_version
|
||||
|
||||
if os.path.isfile(datfile):
|
||||
os.unlink(datfile)
|
||||
|
||||
if os.path.isfile(datfile):
|
||||
with open(datfile, 'rb') as i:
|
||||
temp_mess_version = pickle.load(i)
|
||||
|
||||
if temp_mess_version == mess_version:
|
||||
self.all_categories = pickle.load(i)
|
||||
self.all_roms = pickle.load(i)
|
||||
return True
|
||||
else:
|
||||
os.unlink(datfile)
|
||||
|
||||
self.all_categories = []
|
||||
self.catdict = {}
|
||||
|
||||
files = glob.glob(os.path.join(self.emulator_dir, "hash", '*.xml'))
|
||||
for file in files:
|
||||
with open(file, 'rt', encoding='utf-8') as f:
|
||||
line = None
|
||||
while True:
|
||||
line = f.readline().strip()
|
||||
if line.startswith('<softwarelist name'):
|
||||
break
|
||||
self.all_categories.append(
|
||||
unescape(line[line.find('ion=') + 5:-2]))
|
||||
self.catdict[self.all_categories[-1]] = file
|
||||
self.catdict[file] = self.all_categories[-1]
|
||||
# TODO: Fix me for emulator names
|
||||
# <softwarelist name="n64" description="Nintendo 64 cartridges">
|
||||
self.all_categories.sort()
|
||||
|
||||
# pylint: disable=no-member
|
||||
for xmlfile in files:
|
||||
tree = etree.parse(xmlfile)
|
||||
|
||||
rom = None
|
||||
for child in tree.getiterator():
|
||||
if child.tag == 'software':
|
||||
if rom:
|
||||
rom.category = self.catdict[xmlfile]
|
||||
self.all_roms.append(rom)
|
||||
rom = None
|
||||
if 'supported' not in child.attrib or child.attrib['supported'] != 'no':
|
||||
rom = MessROM()
|
||||
rom.name = child.attrib['name']
|
||||
else:
|
||||
rom = None
|
||||
if rom and 'cloneof' in child.attrib:
|
||||
rom.cloneof = child.attrib['cloneof']
|
||||
elif rom and child.tag == 'description':
|
||||
rom.description = child.text
|
||||
elif rom and child.tag == 'year':
|
||||
rom.year = child.text
|
||||
elif rom and child.tag == 'publisher':
|
||||
rom.manufacturer = child.text
|
||||
|
||||
if rom:
|
||||
rom.category = self.catdict[xmlfile]
|
||||
self.all_roms.append(rom)
|
||||
|
||||
self.all_categories.insert(0, 'All Games')
|
||||
self.all_categories.append('Unknown')
|
||||
|
||||
with open(datfile, 'wb') as output:
|
||||
pickle.dump(mess_version, output)
|
||||
pickle.dump(self.all_categories, output)
|
||||
pickle.dump(self.all_roms, output)
|
||||
|
||||
return True
|
||||
|
||||
def get_mess_version(self):
|
||||
mamerun = subprocess.run(
|
||||
[self.cfg['EXE'], '-?'], stdout=subprocess.PIPE)
|
||||
output = mamerun.stdout.decode('utf-8')
|
||||
output = output[output.find('v'):]
|
||||
output = output[:output.find(' ')]
|
||||
|
||||
return output
|
||||
|
||||
def get_snap(self, rom, type_of_image): # pylint : disable=R0912
|
||||
data = None
|
||||
image_file = None
|
||||
image_dir = None
|
||||
|
||||
if type_of_image == 'snap':
|
||||
image_dir = self.snapdir
|
||||
image_file = self.snapfile
|
||||
|
||||
if image_file:
|
||||
try:
|
||||
data = image_file.read(rom.name + ".png")
|
||||
except:
|
||||
try:
|
||||
data = image_file.read(rom.cloneof + '.png')
|
||||
except:
|
||||
data = None
|
||||
elif image_dir:
|
||||
fn = os.path.join(image_dir, rom.name + '.png')
|
||||
if os.path.isfile(fn):
|
||||
with open(fn, 'rb') as f:
|
||||
data = f.read()
|
||||
elif rom.cloneof:
|
||||
fn = os.path.join(image_dir, rom.cloneof + '.png')
|
||||
if os.path.isfile(fn):
|
||||
with open(fn, 'rb') as f:
|
||||
data = f.read()
|
||||
else:
|
||||
data = None
|
||||
else:
|
||||
data = None
|
||||
else:
|
||||
data = None
|
||||
|
||||
return data
|
||||
|
||||
def get_info(self, rom):
|
||||
if not self.info:
|
||||
return
|
||||
|
||||
search = re.search("\\$info=%s" % rom.name, self.info)
|
||||
|
||||
if not search:
|
||||
search = re.search("\\$info=%s" % rom.cloneof, self.info)
|
||||
if not search:
|
||||
return None
|
||||
|
||||
start = search.start()
|
||||
|
||||
info = self.info[start:self.info.find('$end', start)].splitlines()
|
||||
|
||||
for i in range(len(info) - 1, -1, -1):
|
||||
if info[i].startswith('$'):
|
||||
del info[i]
|
||||
|
||||
while info[0].strip() == '':
|
||||
del info[0]
|
||||
|
||||
while info[len(info) - 1].strip() == '':
|
||||
del info[len(info) - 1]
|
||||
|
||||
return '\n'.join(info)
|
||||
|
||||
def get_history(self, rom):
|
||||
print(rom.name)
|
||||
if not self.history:
|
||||
return
|
||||
|
||||
search = re.search("\\$info=%s" % rom.name, self.history)
|
||||
|
||||
if not search:
|
||||
search = re.search("\\$info=%s" % rom.cloneof, self.history)
|
||||
if not search:
|
||||
return None
|
||||
|
||||
start = search.start()
|
||||
|
||||
info = self.history[start:self.history.find('$end',
|
||||
start)].splitlines()
|
||||
|
||||
for i in range(len(info) - 1, -1, -1):
|
||||
if info[i].startswith('$'):
|
||||
del info[i]
|
||||
|
||||
while info[0].strip() == '':
|
||||
del info[0]
|
||||
|
||||
while info[len(info) - 1].strip() == '':
|
||||
del info[len(info) - 1]
|
||||
|
||||
return '\n'.join(info)
|
||||
11
mfe.py
Normal file
11
mfe.py
Normal file
@@ -0,0 +1,11 @@
|
||||
import app
|
||||
|
||||
if __name__ == "__main__":
|
||||
# try:
|
||||
# startat = int(sys.argv[1])
|
||||
# except:
|
||||
# startat = None
|
||||
|
||||
application = app.app()
|
||||
|
||||
application.run()
|
||||
34
mfe_mac.ini
Normal file
34
mfe_mac.ini
Normal file
@@ -0,0 +1,34 @@
|
||||
ResolutionX = 1024
|
||||
ResolutionY = 768
|
||||
FullScreen = False
|
||||
Font = microsoftsansserif
|
||||
FontSize = 13
|
||||
QuitKeyPresses = 1
|
||||
ScanLines = True
|
||||
Key_Up = K_UP,
|
||||
Key_Down = K_DOWN,
|
||||
Key_PgUp = K_LEFT, K_PAGEUP
|
||||
Key_PgDn = K_RIGHT, K_PAGEDOWN
|
||||
Key_Home = K_HOME,
|
||||
Key_End = K_END,
|
||||
Key_Select = K_RETURN, K_1
|
||||
Key_GameInfo = K_5,
|
||||
Key_GameHistory = K_6,
|
||||
Key_Popup = K_2,
|
||||
AlwaysChangeSnap = True
|
||||
HideMature = True
|
||||
Emulator = M.A.M.E.
|
||||
Key_ShowArtwork = ,
|
||||
[M.A.M.E.]
|
||||
EXE = /Users/rich/git/mfe/mame/mame64
|
||||
Version = v0.190
|
||||
ShowClones = False
|
||||
Category = All Games
|
||||
GameAtTop = 0
|
||||
CurrentGame = 6
|
||||
EmulatorType = MAME
|
||||
StatusFilter = good,
|
||||
Sort = Name Asc
|
||||
SnapDir = None
|
||||
CSVFile = None
|
||||
ArtworkDirs = ,
|
||||
4
readme.txt
Normal file
4
readme.txt
Normal file
@@ -0,0 +1,4 @@
|
||||
MFE
|
||||
|
||||
Mac Build
|
||||
python3 setup.py bdist_mac --iconfile=images/arcade.icns
|
||||
6
requirements.txt
Normal file
6
requirements.txt
Normal file
@@ -0,0 +1,6 @@
|
||||
pygame>=1.9.3
|
||||
configobj>=5.0.6
|
||||
appdirs>=1.4.3
|
||||
lxml>=3.8.0
|
||||
titlecase>=0.11.0
|
||||
cx_Freeze>=5.0.2
|
||||
23
setup.py
Normal file
23
setup.py
Normal file
@@ -0,0 +1,23 @@
|
||||
import os.path
|
||||
import sys
|
||||
from cx_Freeze import setup, Executable
|
||||
|
||||
build_exe_options = {
|
||||
"packages": ["os", "pygame", "lxml"],
|
||||
"excludes": ["tkinter", "numpy"],
|
||||
"include_files": ["arcade.png"]
|
||||
}
|
||||
|
||||
base = None
|
||||
if sys.platform == "win32":
|
||||
base = "Win32GUI"
|
||||
|
||||
setup(
|
||||
name="mfe",
|
||||
version="0.1",
|
||||
description="MAME FrontEnd",
|
||||
options={"build_exe": build_exe_options},
|
||||
executables=[
|
||||
Executable(
|
||||
"mfe.py", base=base, icon=os.path.join('images', 'arcade.ico'))
|
||||
])
|
||||
135
utils.py
Normal file
135
utils.py
Normal file
@@ -0,0 +1,135 @@
|
||||
from itertools import chain
|
||||
import io
|
||||
import os
|
||||
import subprocess
|
||||
|
||||
import pygame
|
||||
import pygame.locals
|
||||
|
||||
|
||||
def get_pygame_keydict():
|
||||
result = {}
|
||||
|
||||
pygame_keys = [
|
||||
item for item in dir(pygame.locals) if item.startswith('K_')
|
||||
]
|
||||
|
||||
for key in pygame_keys:
|
||||
result[key] = getattr(pygame.locals, key)
|
||||
|
||||
return result
|
||||
|
||||
|
||||
def get_keys(keys_dict, a):
|
||||
result = []
|
||||
for key in a:
|
||||
result.append(keys_dict[key])
|
||||
return result
|
||||
|
||||
|
||||
def aspect_scale(img, bx, by):
|
||||
""" Scales 'img' to fit into box bx/by.
|
||||
This method will retain the original image's aspect ratio """
|
||||
ix, iy = img.get_size()
|
||||
if ix > iy:
|
||||
# fit to width
|
||||
scale_factor = bx / float(ix)
|
||||
sy = scale_factor * iy
|
||||
if sy > by:
|
||||
scale_factor = by / float(iy)
|
||||
sx = scale_factor * ix
|
||||
sy = by
|
||||
else:
|
||||
sx = bx
|
||||
else:
|
||||
# fit to height
|
||||
scale_factor = by / float(iy)
|
||||
sx = scale_factor * ix
|
||||
if sx > bx:
|
||||
scale_factor = bx / float(ix)
|
||||
sx = bx
|
||||
sy = scale_factor * iy
|
||||
else:
|
||||
sy = by
|
||||
|
||||
return pygame.transform.scale(img, (int(sx), int(sy)))
|
||||
|
||||
|
||||
def image_from_data(data, image_size):
|
||||
if data:
|
||||
with io.BytesIO(data) as f:
|
||||
surface = pygame.image.load(f)
|
||||
surface = aspect_scale(surface, image_size[0], image_size[1])
|
||||
else:
|
||||
surface = pygame.Surface(image_size) # pylint: disable=E1121
|
||||
|
||||
return surface
|
||||
|
||||
|
||||
def addscanlines(surface):
|
||||
width = surface.get_width()
|
||||
for y in range(surface.get_height()):
|
||||
if y % 2:
|
||||
pygame.draw.line(surface, (0, 0, 0), (0, y), (width, y))
|
||||
|
||||
return surface
|
||||
|
||||
|
||||
def truncline(text, font, maxwidth):
|
||||
real = len(text)
|
||||
stext = text
|
||||
l = font.size(text)[0]
|
||||
cut = 0
|
||||
a = 0
|
||||
done = 1
|
||||
while l > maxwidth:
|
||||
a = a + 1
|
||||
n = text.rsplit(None, a)[0]
|
||||
if stext == n:
|
||||
cut += 1
|
||||
stext = n[:-cut]
|
||||
else:
|
||||
stext = n
|
||||
l = font.size(stext)[0]
|
||||
real = len(stext)
|
||||
done = 0
|
||||
return real, done, stext
|
||||
|
||||
|
||||
def wrapline(text, font, maxwidth):
|
||||
done = 0
|
||||
wrapped = []
|
||||
|
||||
while not done:
|
||||
nl, done, stext = truncline(text, font, maxwidth)
|
||||
wrapped.append(stext.strip())
|
||||
text = text[nl:]
|
||||
return wrapped
|
||||
|
||||
|
||||
def wrap_multi_line(text, font, maxwidth):
|
||||
""" returns text taking new lines into account.
|
||||
"""
|
||||
if type(text) is str:
|
||||
lines = chain(*(wrapline(line, font, maxwidth)
|
||||
for line in text.splitlines()))
|
||||
else:
|
||||
lines = chain(*(wrapline(line, font, maxwidth) for line in text))
|
||||
|
||||
return list(lines)
|
||||
|
||||
|
||||
def run_emulator(emu_type, exe, rom):
|
||||
old_path = os.getcwd()
|
||||
os.chdir(os.path.split(exe)[0])
|
||||
|
||||
if emu_type == 'MAME':
|
||||
subprocess.run([exe, rom])
|
||||
elif emu_type == 'MESS':
|
||||
subprocess.run([exe, rom])
|
||||
elif emu_type == 'CSV':
|
||||
subprocess.run([exe.replace('<romname>', rom)])
|
||||
|
||||
os.chdir(old_path)
|
||||
|
||||
return True
|
||||
Reference in New Issue
Block a user