Project reorganization to use with fbs

This commit is contained in:
adrienmalin 2018-09-28 15:11:21 +02:00
parent 1a308f456a
commit 67b48eeb0b
63 changed files with 316 additions and 213 deletions

5
.gitignore vendored
View File

@ -18,8 +18,7 @@ lib/
lib64/
parts/
sdist/
Tetris2000.build/
Tetris2000.build/
target/
var/
wheels/
*.egg-info/
@ -31,7 +30,7 @@ MANIFEST
# 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
*.spec
# Installer logs
pip-log.txt

View File

@ -1,22 +0,0 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Another TETRIS® clone
Tetris Game Design by Alexey Pajitnov.
Parts of comments issued from 2009 Tetris Design Guideline
"""
import sys
from qtpy import QtWidgets
from source.game_gui import Window
app = QtWidgets.QApplication.instance() or QtWidgets.QApplication(sys.argv)
win = Window()
win.show()
win.frames.new_game()
sys.exit(app.exec_())

View File

@ -1,43 +0,0 @@
# -*- mode: python -*-
block_cipher = None
a = Analysis(['TETRIS2000.py'],
pathex=[],
binaries=[],
datas=[
("backgrounds/*", "backgrounds"),
("fonts/*.ttf", "fonts"),
("fonts/*.otf", "fonts"),
("icons/*.ico", "icons"),
("icons/splash_screen.png", "icons"),
("locale/*.qm", "locale"),
("musics/*.mp3", "musics"),
("sfx/*.wav", "sfx")
],
hiddenimports=[],
hookspath=[],
runtime_hooks=[],
excludes=["PyQt4", "PySide", "PySide2"],
win_no_prefer_redirects=False,
win_private_assemblies=False,
cipher=block_cipher)
pyz = PYZ(a.pure, a.zipped_data,
cipher=block_cipher)
exe = EXE(pyz,
a.scripts,
exclude_binaries=True,
name='TETRIS2000',
debug=False,
strip=False,
upx=False,
console=False,
icon='icons\icon.ico')
coll = COLLECT(exe,
a.binaries,
a.zipfiles,
a.datas,
strip=False,
upx=False,
name='TETRIS2000')

101
src/main/NSIS/Installer.nsi Normal file
View File

@ -0,0 +1,101 @@
!include MUI2.nsh
!include FileFunc.nsh
;--------------------------------
;Perform Machine-level install, if possible
!define MULTIUSER_EXECUTIONLEVEL Highest
;Add support for command-line args that let uninstaller know whether to
;uninstall machine- or user installation:
!define MULTIUSER_INSTALLMODE_COMMANDLINE
!include MultiUser.nsh
!include LogicLib.nsh
Function .onInit
!insertmacro MULTIUSER_INIT
;Do not use InstallDir at all so we can detect empty $InstDir!
${If} $InstDir == "" ; /D not used
${If} $MultiUser.InstallMode == "AllUsers"
StrCpy $InstDir "$PROGRAMFILES\%{app_name}"
${Else}
StrCpy $InstDir "$LOCALAPPDATA\%{app_name}"
${EndIf}
${EndIf}
FunctionEnd
Function un.onInit
!insertmacro MULTIUSER_UNINIT
FunctionEnd
;--------------------------------
;General
Name "%{app_name}"
OutFile "..\%{app_name}Setup.exe"
;--------------------------------
;Interface Settings
!define MUI_ABORTWARNING
;--------------------------------
;Pages
!define MUI_WELCOMEPAGE_TEXT "This wizard will guide you through the installation of %{app_name}.$\r$\n$\r$\n$\r$\nClick Next to continue."
!insertmacro MUI_PAGE_WELCOME
!insertmacro MUI_PAGE_DIRECTORY
!insertmacro MUI_PAGE_INSTFILES
!define MUI_FINISHPAGE_NOAUTOCLOSE
!define MUI_FINISHPAGE_RUN
!define MUI_FINISHPAGE_RUN_CHECKED
!define MUI_FINISHPAGE_RUN_TEXT "Run %{app_name}"
!define MUI_FINISHPAGE_RUN_FUNCTION "LaunchLink"
!insertmacro MUI_PAGE_FINISH
!insertmacro MUI_UNPAGE_CONFIRM
!insertmacro MUI_UNPAGE_INSTFILES
;--------------------------------
;Languages
!insertmacro MUI_LANGUAGE "English"
;--------------------------------
;Installer Sections
!define UNINST_KEY \
"Software\Microsoft\Windows\CurrentVersion\Uninstall\%{app_name}"
Section
SetOutPath "$InstDir"
File /r "..\%{app_name}\*"
WriteRegStr SHCTX "Software\%{app_name}" "" $InstDir
WriteUninstaller "$InstDir\uninstall.exe"
CreateShortCut "$SMPROGRAMS\%{app_name}.lnk" "$InstDir\%{app_name}.exe"
WriteRegStr SHCTX "${UNINST_KEY}" "DisplayName" "%{app_name}"
WriteRegStr SHCTX "${UNINST_KEY}" "UninstallString" \
"$\"$InstDir\uninstall.exe$\" /$MultiUser.InstallMode"
WriteRegStr SHCTX "${UNINST_KEY}" "QuietUninstallString" \
"$\"$InstDir\uninstall.exe$\" /$MultiUser.InstallMode /S"
WriteRegStr SHCTX "${UNINST_KEY}" "Publisher" "%{author}"
${GetSize} "$InstDir" "/S=0K" $0 $1 $2
IntFmt $0 "0x%08X" $0
WriteRegDWORD SHCTX "${UNINST_KEY}" "EstimatedSize" "$0"
SectionEnd
;--------------------------------
;Uninstaller Section
Section "Uninstall"
RMDir /r "$InstDir"
Delete "$SMPROGRAMS\%{app_name}.lnk"
DeleteRegKey /ifempty SHCTX "Software\%{app_name}"
DeleteRegKey SHCTX "${UNINST_KEY}"
SectionEnd
Function LaunchLink
!addplugindir "."
ShellExecAsUser::ShellExecAsUser "open" "$SMPROGRAMS\%{app_name}.lnk"
FunctionEnd

Binary file not shown.

View File

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 15 KiB

11
src/main/icons/README.md Normal file
View File

@ -0,0 +1,11 @@
![Sample app icon](linux/128.png)
This directory contains the icons that are displayed for your app. Feel free to
change them.
The difference between the icons on Mac and the other platforms is that on Mac,
they contain a ~5% transparent margin. This is because otherwise they look too
big (eg. in the Dock or in the app switcher).
You can create Icon.ico from the .png files with
[an online tool](http://icoconvert.com/Multi_Image_to_one_icon/).

View File

Before

Width:  |  Height:  |  Size: 183 B

After

Width:  |  Height:  |  Size: 183 B

View File

Before

Width:  |  Height:  |  Size: 802 B

After

Width:  |  Height:  |  Size: 802 B

View File

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

BIN
src/main/icons/linux/16.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 183 B

BIN
src/main/icons/linux/32.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 802 B

BIN
src/main/icons/linux/48.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

BIN
src/main/icons/mac/16.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 183 B

BIN
src/main/icons/mac/32.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 802 B

BIN
src/main/icons/mac/48.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

@ -3,30 +3,27 @@
import os
from qtpy import QtGui
from PyQt5 import QtGui
# Paths
PATH = os.path.dirname(os.path.abspath(__file__))
PATH = os.path.dirname(PATH)
ICON_PATH = os.path.join(PATH, "icons", "icon.ico")
BG_IMAGE_DIR = os.path.join(PATH, "backgrounds")
START_BG_IMAGE_NAME = "01-spacefield_a-000.png"
MUSICS_DIR = os.path.join(PATH, "musics")
SFX_DIR = os.path.join(PATH, "sfx")
ICON_PATH = "icons/icon.ico"
BG_IMAGE_DIR = "backgrounds"
START_BG_IMAGE_PATH = os.path.join(BG_IMAGE_DIR, "01-spacefield_a-000.png")
MUSICS_DIR = "musics"
SFX_DIR = "sfx"
LINE_CLEAR_SFX_PATH = os.path.join(SFX_DIR, "line_clear.wav")
TETRIS_SFX_PATH = os.path.join(SFX_DIR, "tetris.wav")
ROTATE_SFX_PATH = os.path.join(SFX_DIR, "rotate.wav")
HARD_DROP_SFX_PATH = os.path.join(SFX_DIR, "hard_drop.wav")
WALL_SFX_PATH = os.path.join(SFX_DIR, "wall.wav")
LOCALE_PATH = os.path.join(PATH, "locale")
FONTS_DIR = os.path.join(PATH, "fonts")
LOCALE_PATH = "locale"
FONTS_DIR = "fonts"
STATS_FONT_PATH = os.path.join(FONTS_DIR, "PixelCaps!.otf")
STATS_FONT_NAME = "PixelCaps!"
MATRIX_FONT_PATH = os.path.join(FONTS_DIR, "maass slicer Italic.ttf")
MATRIX_FONT_NAME = "Maassslicer"
SPLASH_SCREEN_PATH = os.path.join(PATH, "icons", "splash_screen.png")
SPLASH_SCREEN_PATH = "splashscreen/splashscreen.png"
# Coordinates and direction
L, R, U, D = -1, 1, -1, 1 # Left, Right, Up, Down

View File

@ -7,13 +7,14 @@ import itertools
import locale
import os
import time
from qtpy import QtWidgets, QtCore, QtGui, QtMultimedia
from PyQt5 import QtWidgets, QtCore, QtGui, QtMultimedia
QtCore.Signal = QtCore.pyqtSignal
from . import consts
from .consts import L, R, CLOCKWISE, COUNTERCLOCKWISE
from .__version__ import __title__, __author__, __version__
from .point import Point
from .tetromino import Block, Tetromino, GhostPiece
import consts
from consts import L, R, CLOCKWISE, COUNTERCLOCKWISE
from __version__ import __title__, __author__, __version__
from point import Point
from tetromino import Block, Tetromino, GhostPiece
class Grid(QtWidgets.QWidget):
@ -92,10 +93,10 @@ class Matrix(Grid):
drop_signal = QtCore.Signal(int)
lock_signal = QtCore.Signal(int, str)
def __init__(self, frames):
def __init__(self, frames, app):
super().__init__(frames)
self.load_sfx()
self.load_sfx(app)
self.game_over = False
self.text = ""
@ -112,17 +113,17 @@ class Matrix(Grid):
self.cells = []
def load_sfx(self):
def load_sfx(self, app):
self.wall_sfx = QtMultimedia.QSoundEffect(self)
url = QtCore.QUrl.fromLocalFile(consts.WALL_SFX_PATH)
url = QtCore.QUrl.fromLocalFile(app.get_resource(consts.WALL_SFX_PATH))
self.wall_sfx.setSource(url)
self.rotate_sfx = QtMultimedia.QSoundEffect(self)
url = QtCore.QUrl.fromLocalFile(consts.ROTATE_SFX_PATH)
url = QtCore.QUrl.fromLocalFile(app.get_resource(consts.ROTATE_SFX_PATH))
self.rotate_sfx.setSource(url)
self.hard_drop_sfx = QtMultimedia.QSoundEffect(self)
url = QtCore.QUrl.fromLocalFile(consts.HARD_DROP_SFX_PATH)
url = QtCore.QUrl.fromLocalFile(app.get_resource(consts.HARD_DROP_SFX_PATH))
self.hard_drop_sfx.setSource(url)
def new_game(self):
@ -551,12 +552,12 @@ class Stats(QtWidgets.QWidget):
temporary_text = QtCore.Signal(str)
def __init__(self, frames):
def __init__(self, frames, app):
super().__init__(frames)
self.frames = frames
self.setStyleSheet("background-color: transparent")
self.load_sfx()
self.load_sfx(app)
self.setSizePolicy(
QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding
@ -569,13 +570,13 @@ class Stats(QtWidgets.QWidget):
self.high_score = int(qsettings.value(self.tr("High score"), 0))
def load_sfx(self):
def load_sfx(self, app):
self.line_clear_sfx = QtMultimedia.QSoundEffect(self)
url = QtCore.QUrl.fromLocalFile(consts.LINE_CLEAR_SFX_PATH)
url = QtCore.QUrl.fromLocalFile(app.get_resource(consts.LINE_CLEAR_SFX_PATH))
self.line_clear_sfx.setSource(url)
self.tetris_sfx = QtMultimedia.QSoundEffect(self)
url = QtCore.QUrl.fromLocalFile(consts.TETRIS_SFX_PATH)
url = QtCore.QUrl.fromLocalFile(app.get_resource(consts.TETRIS_SFX_PATH))
self.tetris_sfx.setSource(url)
def new_game(self):
@ -790,8 +791,9 @@ class Frames(QtWidgets.QWidget):
Manage interactions between them.
"""
def __init__(self, parent):
def __init__(self, parent, app):
super().__init__(parent)
self.app = app
self.setSizePolicy(
QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding
)
@ -801,9 +803,9 @@ class Frames(QtWidgets.QWidget):
self.load_music()
self.hold_queue = HoldQueue(self)
self.matrix = Matrix(self)
self.matrix = Matrix(self, app)
self.next_piece = Grid(self)
self.stats = Stats(self)
self.stats = Stats(self, app)
self.next_queue = NextQueue(self)
self.matrices = (self.hold_queue, self.matrix, self.next_piece)
@ -852,7 +854,7 @@ class Frames(QtWidgets.QWidget):
self.matrix.lock_signal.connect(self.stats.update_score)
self.bg_image = QtGui.QImage(
os.path.join(consts.BG_IMAGE_DIR, consts.START_BG_IMAGE_NAME)
os.path.join(app.get_resource(consts.START_BG_IMAGE_PATH))
)
self.resize_bg_image()
@ -860,8 +862,9 @@ class Frames(QtWidgets.QWidget):
def load_music(self):
playlist = QtMultimedia.QMediaPlaylist(self)
for entry in os.scandir(consts.MUSICS_DIR):
path = os.path.join(consts.MUSICS_DIR, entry.name)
MUSICS_DIR = self.app.get_resource(consts.MUSICS_DIR)
for entry in os.scandir(MUSICS_DIR):
path = os.path.join(MUSICS_DIR, entry.name)
url = QtCore.QUrl.fromLocalFile(path)
music = QtMultimedia.QMediaContent(url)
playlist.addMedia(music)
@ -901,9 +904,10 @@ class Frames(QtWidgets.QWidget):
self.resize_bg_image()
def reset_backgrounds(self):
BG_IMAGE_DIR = self.app.get_resource(consts.BG_IMAGE_DIR)
backgrounds = tuple(
QtGui.QImage((os.path.join(consts.BG_IMAGE_DIR, entry.name)))
for entry in os.scandir(consts.BG_IMAGE_DIR)
QtGui.QImage((os.path.join(BG_IMAGE_DIR, entry.name)))
for entry in os.scandir(BG_IMAGE_DIR)
)
self.backgrounds_cycle = itertools.cycle(backgrounds)
@ -1223,21 +1227,21 @@ class SettingsDialog(QtWidgets.QDialog):
class Window(QtWidgets.QMainWindow):
""" Main window """
def __init__(self):
def __init__(self, app):
splash_screen = QtWidgets.QSplashScreen(
QtGui.QPixmap(consts.SPLASH_SCREEN_PATH)
QtGui.QPixmap(app.get_resource(consts.SPLASH_SCREEN_PATH))
)
splash_screen.show()
self.set_locale()
self.load_settings()
super().__init__()
self.setWindowTitle(__title__.upper())
self.setAttribute(QtCore.Qt.WA_DeleteOnClose)
self.setWindowIcon(QtGui.QIcon(consts.ICON_PATH))
self.set_locale(app)
self.load_settings()
self.setWindowIcon(app.app_icon)
# Windows' taskbar icon
try:
ctypes.windll.shell32.SetCurrentProcessExplicitAppUserModelID(
@ -1252,16 +1256,14 @@ class Window(QtWidgets.QMainWindow):
except ImportError:
pass
else:
os.environ['QT_API'] = 'pyqt5'
self.setStyleSheet(qdarkstyle.load_stylesheet_from_environment())
for font_path in consts.STATS_FONT_PATH, consts.MATRIX_FONT_PATH:
QtGui.QFontDatabase.addApplicationFont(font_path)
QtGui.QFontDatabase.addApplicationFont(app.get_resource(font_path))
self.frames = Frames(self)
self.frames = Frames(self, app)
self.setCentralWidget(self.frames)
self.hold_queue = self.frames.hold_queue
self.matrix = self.frames.matrix
self.stats = self.frames.stats
self.menu = self.menuBar()
@ -1278,24 +1280,28 @@ class Window(QtWidgets.QMainWindow):
splash_screen.finish(self)
def set_locale(self):
app = QtWidgets.QApplication.instance()
def show(self):
super().show()
self.frames.new_game()
def set_locale(self, app):
qapp = QtWidgets.QApplication.instance()
# Set appropriate thounsand separator characters
locale.setlocale(locale.LC_ALL, "")
# Qt
language = QtCore.QLocale.system().name()[:2]
qt_translator = QtCore.QTranslator(app)
qt_translator = QtCore.QTranslator(qapp)
qt_translation_path = QtCore.QLibraryInfo.location(
QtCore.QLibraryInfo.TranslationsPath
)
if qt_translator.load("qt_" + language, qt_translation_path):
app.installTranslator(qt_translator)
qapp.installTranslator(qt_translator)
tetris2000_translator = QtCore.QTranslator(app)
if tetris2000_translator.load(language, consts.LOCALE_PATH):
app.installTranslator(tetris2000_translator)
tetris2000_translator = QtCore.QTranslator(qapp)
if tetris2000_translator.load(language, app.get_resource(consts.LOCALE_PATH)):
qapp.installTranslator(tetris2000_translator)
def load_settings(self):
global s
@ -1517,7 +1523,7 @@ Sound effects made with voc-one by Simple-Media"""
self.frames.music.stop()
# Save settings
qsettings.setValue(self.tr("High score"), self.stats.high_score)
qsettings.setValue(self.tr("High score"), self.frames.stats.high_score)
qsettings.setValue("WindowGeometry", self.saveGeometry())
qsettings.setValue("WindowState", int(self.windowState()))

25
src/main/python/main.py Normal file
View File

@ -0,0 +1,25 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Another TETRIS® clone
Tetris Game Design by Alexey Pajitnov.
Parts of comments issued from 2009 Tetris Design Guideline
"""
from fbs_runtime.application_context import ApplicationContext
from game_gui import Window
import sys
class AppContext(ApplicationContext): # 1. Subclass ApplicationContext
def run(self): # 2. Implement run()
win = Window(self)
win.show()
return self.app.exec_() # 3. End run() with this line
if __name__ == '__main__':
appctxt = AppContext() # 4. Instantiate the subclass
exit_code = appctxt.run() # 5. Invoke run()
sys.exit(exit_code)

View File

@ -2,9 +2,9 @@
# -*- coding: utf-8 -*-
from qtpy import QtCore
from PyQt5 import QtCore
from .consts import CLOCKWISE
from consts import CLOCKWISE
class Point(QtCore.QPoint):

View File

@ -3,11 +3,11 @@
import random
from qtpy import QtCore, QtGui
from PyQt5 import QtCore, QtGui
from . import consts
from .consts import L, R, U, D, CLOCKWISE, COUNTERCLOCKWISE
from .point import Point
import consts
from consts import L, R, U, D, CLOCKWISE, COUNTERCLOCKWISE
from point import Point
class Block:

View File

Before

Width:  |  Height:  |  Size: 444 KiB

After

Width:  |  Height:  |  Size: 444 KiB

View File

Before

Width:  |  Height:  |  Size: 291 KiB

After

Width:  |  Height:  |  Size: 291 KiB

View File

Before

Width:  |  Height:  |  Size: 220 KiB

After

Width:  |  Height:  |  Size: 220 KiB

View File

Before

Width:  |  Height:  |  Size: 945 KiB

After

Width:  |  Height:  |  Size: 945 KiB

View File

Before

Width:  |  Height:  |  Size: 456 KiB

After

Width:  |  Height:  |  Size: 456 KiB

View File

Before

Width:  |  Height:  |  Size: 549 KiB

After

Width:  |  Height:  |  Size: 549 KiB

View File

Before

Width:  |  Height:  |  Size: 754 KiB

After

Width:  |  Height:  |  Size: 754 KiB

View File

Before

Width:  |  Height:  |  Size: 642 KiB

After

Width:  |  Height:  |  Size: 642 KiB

View File

Before

Width:  |  Height:  |  Size: 377 KiB

After

Width:  |  Height:  |  Size: 377 KiB

View File

Before

Width:  |  Height:  |  Size: 526 KiB

After

Width:  |  Height:  |  Size: 526 KiB

View File

Before

Width:  |  Height:  |  Size: 669 KiB

After

Width:  |  Height:  |  Size: 669 KiB

View File

Before

Width:  |  Height:  |  Size: 597 KiB

After

Width:  |  Height:  |  Size: 597 KiB

View File

Before

Width:  |  Height:  |  Size: 800 KiB

After

Width:  |  Height:  |  Size: 800 KiB

View File

Before

Width:  |  Height:  |  Size: 416 KiB

After

Width:  |  Height:  |  Size: 416 KiB

View File

Before

Width:  |  Height:  |  Size: 37 KiB

After

Width:  |  Height:  |  Size: 37 KiB

View File

Before

Width:  |  Height:  |  Size: 80 KiB

After

Width:  |  Height:  |  Size: 80 KiB

View File

@ -0,0 +1,29 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleExecutable</key>
<string>${app_name}</string>
<key>CFBundleDisplayName</key>
<string>${app_name}</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleIconFile</key>
<string>Icon.icns</string>
<key>CFBundleIdentifier</key>
<string>${mac_bundle_identifier}</string>
<key>LSBackgroundOnly</key>
<string>0</string>
<key>CFBundleShortVersionString</key>
<string>${version}</string>
<key>CFBundleVersion</key>
<string>${version}</string>
<key>CFBundleName</key>
<string>${app_name}</string>
<!-- Enable Retina support on OS X: -->
<key>NSPrincipalClass</key>
<string>NSApplication</string>
</dict>
</plist>

View File

Before

Width:  |  Height:  |  Size: 5.2 KiB

After

Width:  |  Height:  |  Size: 5.2 KiB