...
 
Commits (14)
/__pycache__/ /__pycache__/
*/__pycache__/ */__pycache__/
/.spyproject/
*/*.log */*.log
*/*_ui.py */*_ui.py
*/*_rc.py */*_rc.py
...@@ -103,4 +103,4 @@ For the time being, those are provided by the PI camera module. ...@@ -103,4 +103,4 @@ For the time being, those are provided by the PI camera module.
## Todo ## Todo
* [ ] Filter serial ports to get arduinos or specific serial id * [ ] Add the possibility to stop the replay mid-video by pushing any button
...@@ -7,9 +7,11 @@ pyuic5 --import-from=ui ui/game.ui -o ui/game_ui.py ...@@ -7,9 +7,11 @@ pyuic5 --import-from=ui ui/game.ui -o ui/game_ui.py
pyuic5 --import-from=ui ui/endgame.ui -o ui/endgame_ui.py pyuic5 --import-from=ui ui/endgame.ui -o ui/endgame_ui.py
pyuic5 --import-from=ui ui/options.ui -o ui/options_ui.py pyuic5 --import-from=ui ui/options.ui -o ui/options_ui.py
pyuic5 --import-from=ui ui/authquick.ui -o ui/authquick_ui.py pyuic5 --import-from=ui ui/authquick.ui -o ui/authquick_ui.py
pyuic5 --import-from=ui ui/authleague.ui -o ui/authleague_ui.py
pyuic5 --import-from=ui ui/leaderboard.ui -o ui/leaderboard_ui.py pyuic5 --import-from=ui ui/leaderboard.ui -o ui/leaderboard_ui.py
# Custom widgets # Custom widgets
pyuic5 --import-from=ui ui/playerlist.ui -o ui/playerlist_ui.py pyuic5 --import-from=ui ui/playerlist.ui -o ui/playerlist_ui.py
pyuic5 --import-from=ui ui/delete_dialog.ui -o ui/delete_dialog_ui.py
pyrcc5 -root /ui ui/assets.qrc -o ui/assets_rc.py pyrcc5 -root /ui ui/assets.qrc -o ui/assets_rc.py
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
@author: Antoine Lima, Leo Reynaert, Domitille Jehenne
"""
import sqlite3
class DatabaseError(Exception):
pass
class Database():
__db = None
def __init__(self):
if not Database.__db:
from main import getContent
db_path = getContent('babyfut.sqlite')
self._connection = sqlite3.connect(db_path)
@staticmethod
def instance():
'''
Singleton
'''
if not Database.__db:
Database.__db = Database()
return Database.__db
@property
def _cursor(self):
return self._connection.cursor()
def select_one(self, query, *args):
res = self._cursor.execute(query, args).fetchone()
if not res:
raise DatabaseError('Query \"{}\" returned nothing with args {}'.format(query, args))
return res
def select_guest_team(self):
return self.select_one('SELECT id FROM players WHERE fname LIKE "guest"')[0]
def insert_team(self, players, goals):
if len(players)<2:
players.append(None)
self._cursor.execute('INSERT INTO Teams (nGoals, player1, player2) VALUES (?, ?, ?)', (goals, players[0], players[1],))
self._connection.commit()
return self._cursor.execute('SELECT seq FROM sqlite_sequence WHERE name="Teams"').fetchone()[0]
def insert_match(self, start_time, duration, team1, team2):
self._cursor.execute('INSERT INTO Matchs (timestamp, duration, winningTeam, losingTeam) VALUES (?, ?, ?, ?)', (start_time, duration, team1, team2,))
self._connection.commit()
def select_all_rfid(self, debug=False):
from settings import Settings
if Settings['app.mode']=='prod':
return self._cursor.execute('SELECT rfid FROM Players WHERE rfid>0').fetchall()
else:
return self._cursor.execute('SELECT rfid FROM Players WHERE rfid<-1').fetchall()
def delete_player(self, playerID):
self._cursor.execute('DELETE FROM Players WHERE id==?', (playerID,))
self._connection.commit()
def close(self):
self._connection.close()
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
@author: Antoine Lima, Leo Reynaert, Domitille Jehenne
"""
import logging
import pyautogui # PyPi library
from threading import Thread
from main import OnRasp
if OnRasp:
import RPi.GPIO as GPIO
from player import Side
class GPIOThread(Thread):
_keyButtonBindings = {
26: 'up',
22: 'left',
27: 'right',
23: 'down',
17: 'return',
18: 'escape'
}
def __init__(self, dispatcher):
Thread.__init__(self)
self.dispatcher = dispatcher
self.continueRunning = True
if OnRasp:
GPIO.setwarnings(False)
GPIO.setmode(GPIO.BCM)
for pin in GPIOThread._keyButtonBindings.keys():
print(pin)
GPIO.setup(pin, GPIO.IN, pull_up_down=GPIO.PUD_UP)
GPIO.add_event_detect(pin, GPIO.RISING, callback=self.handleButtonPress)
def run(self):
if OnRasp:
try:
while self.continueRunning:
pass
finally:
GPIOThread.clean()
def handleButtonPress(self, button_pin):
if button_pin not in GPIOThread._keyButtonBindings.keys():
logging.warn('Unknown button pin: {}'.format(button_pin))
else:
key = GPIOThread._keyButtonBindings[button_pin]
logging.debug('Sending {} as {}'.format(button_pin, key))
pyautogui.press(key)
def stop(self):
self.continueRunning = False
@staticmethod
def clean():
if OnRasp:
GPIO.cleanup()
#!/usr/bin/env python3 #!/usr/bin/env python3
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
""" """
Created on Wed Apr 18 18:34:40 2018
@author: Antoine Lima, Leo Reynaert, Domitille Jehenne @author: Antoine Lima, Leo Reynaert, Domitille Jehenne
""" """
import os
OnRasp = os.uname()[1] == 'raspberrypi'
import sys import sys
import logging import logging
from os.path import dirname, abspath, join from os.path import dirname, abspath, join
from PyQt5 import QtWidgets from PyQt5 import QtWidgets
from PyQt5.QtWidgets import QGraphicsBlurEffect, QApplication
from PyQt5.QtCore import QTime, Qt
from ui.main_ui import Ui_MainWindow
from modules import *
class MainWin(QtWidgets.QMainWindow): def getContent(path):
def __init__(self, parent=None): contentFolder = join(dirname(dirname(abspath(__file__))), 'content')
QtWidgets.QWidget.__init__(self, parent) return join(contentFolder, path)
self.ui = Ui_MainWindow()
self.ui.setupUi(self) if __name__=='__main__':
from ui.mainwin import MainWin
from modules import GameModule
from player import Side
from input import GPIOThread
from database import Database
from replay import Replay as ReplayThread
try:
#logging.basicConfig(filename='babyfoot.log', level=logging.DEBUG)
logging.basicConfig(level=logging.DEBUG)
#Background blur app = QtWidgets.QApplication(sys.argv)
bgBlur = QGraphicsBlurEffect() myapp = MainWin()
bgBlur.setBlurHints(QGraphicsBlurEffect.QualityHint)
#bgBlur.setBlurRadius(5)
#self.ui.panels.setGraphicsEffect(bgBlur)
# Module loading if ReplayThread.isCamAvailable():
self.modules = [ threadReplay = ReplayThread(Side.Left)
MenuModule(self), threadReplay.start()
AuthQuickModule(self), myapp.dispatchMessage({'replayThread': threadReplay}, toType=GameModule)
AuthLeagueModule(self),
GameModule(self),
EndGameModule(self),
LeaderboardModule(self),
OptionsModule(self)
]
for mod in self.modules: threadGPIO = GPIOThread(myapp)
self.ui.panels.addWidget(mod) threadGPIO.start()
self.ui.panels.setCurrentIndex(0) myapp.show()
self.ui.panels.currentWidget().setFocus() app.exec_()
self.ui.panels.currentWidget().grabKeyboard()
self.ui.panels.currentWidget().load()
self.displaySystemTime()
self.startTimer(1000)
#def eventFilter(target, event):
# return event.type()==QEvent.KeyPress and event.key() not in acceptedKeys
def timerEvent(self, e):
self.displaySystemTime()
def displaySystemTime(self):
self.ui.lcdTime.display(QTime.currentTime().toString("hh:mm:ss"))
@staticmethod
def getContent(path):
contentFolder = join(dirname(dirname(abspath(__file__))), 'content')
return join(contentFolder, path)
def _refreshAfterSettings(self):
from settings import Settings
if Settings.ui['fullscreen']: threadGPIO.stop()
self.showFullScreen()
QApplication.setOverrideCursor(Qt.BlankCursor); if ReplayThread.isCamAvailable():
else: threadReplay.stop()
self.showNormal() threadReplay.join()
QApplication.setOverrideCursor(Qt.ArrowCursor);
threadGPIO.join()
if __name__=='__main__':
app = QtWidgets.QApplication(sys.argv) finally:
#logging.basicConfig(filename='babyfoot.log', level=logging.DEBUG) GPIOThread.clean()
logging.basicConfig(level=logging.DEBUG) Database.instance().close()
myapp = MainWin()
myapp.show()
app.exec_()
#!/usr/bin/env python3 #!/usr/bin/env python3
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
""" """
Created on Wed Apr 18 18:34:40 2018
@author: Antoine Lima, Leo Reynaert, Domitille Jehenne @author: Antoine Lima, Leo Reynaert, Domitille Jehenne
""" """
import logging import logging
from PyQt5 import QtWidgets from PyQt5.QtWidgets import QApplication, QWidget
from PyQt5.QtCore import QTime, QTimer, Qt
from PyQt5.QtWidgets import QTableWidgetItem, QComboBox, QApplication
from modules import *
class Module(QtWidgets.QWidget): class Module(QWidget):
def __init__(self, parent=None, widget=None): def __init__(self, parent, widget):
# UI Setup # UI Setup
QtWidgets.QWidget.__init__(self, parent) QWidget.__init__(self, parent)
self.mainwin = parent self.mainwin = parent
self.ui = widget self.ui = widget
self.ui.setupUi(self) self.ui.setupUi(self)
def find(self, type):
mod_idx = [i for i, x in enumerate(self.mainwin.modules) if isinstance(x, type)]
return -1 if len(mod_idx)==0 else mod_idx[0]
def switchModule(self, new_type): def switchModule(self, new_type):
curmod_idx = self.find(type(self)) curmod_idx = self.mainwin.findMod(type(self))
newmod_idx = self.find(new_type) newmod_idx = self.mainwin.findMod(new_type)
if curmod_idx<0: if curmod_idx<0:
logging.error('Unknown panel {}'.format(type(self))) logging.error('Unknown panel {}'.format(type(self)))
elif newmod_idx<0: elif newmod_idx<0:
logging.error('Unknown panel {}'.format(new_type)) logging.error('Unknown panel {}'.format(new_type))
else: else:
# Unfocus the current module # Unfocus the current module
self.mainwin.ui.panels.currentWidget().releaseKeyboard()
if QApplication.focusWidget() != None: if QApplication.focusWidget() != None:
QApplication.focusWidget().clearFocus() QApplication.focusWidget().clearFocus()
# Swap modules by unloading, changing the ui then loading # Swap modules by unloading, changing the ui then loading
self.mainwin.modules[curmod_idx].unload() self.mainwin.modules[curmod_idx].unload()
self.mainwin.ui.panels.setCurrentIndex(newmod_idx) self.mainwin.ui.panels.setCurrentIndex(newmod_idx)
self.mainwin.modules[newmod_idx].load() self.mainwin.ui.panels.setFocusProxy(self.mainwin.modules[newmod_idx])
self.mainwin.modules[newmod_idx].setFocus()
# Select first element of the Module # Select first element of the Module
self.mainwin.modules[newmod_idx].focusNextChild() self.mainwin.modules[newmod_idx].focusNextChild()
self.mainwin.modules[newmod_idx].focusPreviousChild() self.mainwin.modules[newmod_idx].focusPreviousChild()
self.mainwin.modules[newmod_idx].grabKeyboard() self.mainwin.modules[newmod_idx].load()
def send(self, to, **kwargs): def send(self, to, **kwargs):
mod_idx = self.find(to) mod_idx = self.mainwin.findMod(to)
if mod_idx<0: if mod_idx<0:
logging.error('Unknown panel {}'.format(to)) logging.error('Unknown panel {}'.format(to))
......
#!/usr/bin/env python3 #!/usr/bin/env python3
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
""" """
Created on Wed Apr 18 18:34:40 2018
@author: Antoine Lima, Leo Reynaert, Domitille Jehenne @author: Antoine Lima, Leo Reynaert, Domitille Jehenne
""" """
...@@ -12,23 +10,26 @@ from PyQt5.QtCore import Qt ...@@ -12,23 +10,26 @@ from PyQt5.QtCore import Qt
import modules import modules
from module import Module from module import Module
from player import Side, Player, PlayerGuest from player import Side, Player
class AuthModuleBase(Module): class AuthModuleBase(Module):
def __init__(self, parent, widget): def __init__(self, parent, widget):
super().__init__(parent, widget) super().__init__(parent, widget)
self.players = {Side.Left: list(), Side.Right: list()} self.createPlayerList()
self.numPlayers = 0
def load(self): def load(self):
pass pass
def unload(self): def unload(self):
self.players = {Side.Left: list(), Side.Right: list()} self.createPlayerList()
self.numPlayers = 0
def other(self, **kwargs): def other(self, **kwargs):
for key, val in kwargs.items(): for key, val in kwargs.items():
if key=='rfid' and 'source' in kwargs: if key=='rfid' and 'source' in kwargs:
side = kwargs['source'] side = kwargs['source']
self.numPlayers += 1
self.addPlayer(side, Player.fromRFID(val)) self.addPlayer(side, Player.fromRFID(val))
def keyPressEvent(self, e): def keyPressEvent(self, e):
...@@ -40,10 +41,10 @@ class AuthModuleBase(Module): ...@@ -40,10 +41,10 @@ class AuthModuleBase(Module):
elif e.key() == Qt.Key_Left or e.key() == Qt.Key_Right: elif e.key() == Qt.Key_Left or e.key() == Qt.Key_Right:
side = Side.Left if e.key() == Qt.Key_Left else Side.Right side = Side.Left if e.key() == Qt.Key_Left else Side.Right
rfid = -2*(side.value+1) - (self.players[side][0]!=PlayerGuest) rfid = -(2 + self.numPlayers%5)
self.send(type(self), rfid=rfid, source=side) self.send(type(self), rfid=rfid, source=side)
def addPlayer(self, side, player): def createPlayerList(self):
logging.warning('Base function meant to be reimplemented') logging.warning('Base function meant to be reimplemented')
def handleCancel(self): def handleCancel(self):
......
#!/usr/bin/env python3 #!/usr/bin/env python3
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
""" """
Created on Wed Apr 18 18:34:40 2018
@author: Antoine Lima, Leo Reynaert, Domitille Jehenne @author: Antoine Lima, Leo Reynaert, Domitille Jehenne
""" """
import logging import logging
from module import Module from PyQt5.QtWidgets import QAbstractItemView
from ui.authquick_ui import Ui_Form as AuthQuickWidget from modules.auth import AuthModuleBase
from ui.authleague_ui import Ui_Form as AuthLeagueWidget
from player import Side, PlayerEmpty
class AuthLeagueModule(Module): class AuthLeagueModule(AuthModuleBase):
def __init__(self, parent): def __init__(self, parent):
super().__init__(parent, AuthQuickWidget()) super().__init__(parent, AuthLeagueWidget())
def load(self): def load(self):
logging.debug('Loading AuthLeagueModule') logging.debug('Loading AuthLeagueModule')
super().load() super().load()
self.addPlayer(Side.Left, PlayerEmpty)
def unload(self): def unload(self):
logging.debug('Loading AuthLeagueModule') logging.debug('Loading AuthLeagueModule')
super().load() super().unload()
self.ui.playersList.clear()
def createPlayerList(self):
'''
Duplicates the player list to be the same on both sides.
That way, adding a player on the left or on the right have the exact same effect,
and thus the AuthModuleBase code can remain generic.
'''
l = list()
self.players = {Side.Left: l, Side.Right: l}
def addPlayer(self, side, player):
# Add the player if not already in the list
if all([p.id!=player.id for p in self.players[side]]):
if player!=PlayerEmpty:
self.players[side].append(player)
# Update the left side description
player.displayImg(self.ui.img)
self.ui.lblName.setText(player.name)
self.ui.lblStat1.setText('{} Victories'.format(player.stats['victories']))
self.ui.lblStat2.setText('{} Games Played'.format(player.stats['games_played']))
self.ui.lblStat3.setText('{} Goals Scored'.format(player.stats['goals_scored']))
if player!=PlayerEmpty:
# Update the right side list, making sure that the added player is showed
self.ui.playersList.addItem('{}. {}'.format(len(self.players[side]), player.name))
widgetItem = self.ui.playersList.item(self.ui.playersList.count()-1)
self.ui.playersList.scrollToItem(widgetItem, QAbstractItemView.PositionAtBottom)
def handleDone(self):
super().handleDone()
#!/usr/bin/env python3 #!/usr/bin/env python3
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
""" """
Created on Wed Apr 18 18:34:40 2018
@author: Antoine Lima, Leo Reynaert, Domitille Jehenne @author: Antoine Lima, Leo Reynaert, Domitille Jehenne
""" """
...@@ -10,10 +8,8 @@ import logging ...@@ -10,10 +8,8 @@ import logging
from PyQt5.QtWidgets import QSizePolicy from PyQt5.QtWidgets import QSizePolicy
import modules
from module import Module
from modules.auth import AuthModuleBase from modules.auth import AuthModuleBase
from player import Side, Player, PlayerGuest from player import Side, PlayerGuest
from ui.authquick_ui import Ui_Form as AuthQuickWidget from ui.authquick_ui import Ui_Form as AuthQuickWidget
class AuthQuickModule(AuthModuleBase): class AuthQuickModule(AuthModuleBase):
...@@ -40,7 +36,11 @@ class AuthQuickModule(AuthModuleBase): ...@@ -40,7 +36,11 @@ class AuthQuickModule(AuthModuleBase):
super().unload() super().unload()
#self.updateSides() #self.updateSides()
def createPlayerList(self):
self.players = {Side.Left: list(), Side.Right: list()}
def addPlayer(self, side, player): def addPlayer(self, side, player):
# If there is a placeholder Guest, clear it from the list, we don't need it anymore
if len(self.players[side])>0 and self.players[side][0]==PlayerGuest: if len(self.players[side])>0 and self.players[side][0]==PlayerGuest:
self.players[side].clear() self.players[side].clear()
......
#!/usr/bin/env python3 #!/usr/bin/env python3
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
""" """
Created on Wed Apr 18 18:34:40 2018
@author: Antoine Lima, Leo Reynaert, Domitille Jehenne @author: Antoine Lima, Leo Reynaert, Domitille Jehenne
""" """
import logging import logging
from PyQt5 import QtWidgets from PyQt5 import QtWidgets
from PyQt5.QtGui import QRegion from PyQt5.QtCore import QTimer, Qt
from PyQt5.QtCore import QTime, QTimer, QRect, Qt
from player import Side from database import Database
from player import Side, PlayerGuest
from module import Module from module import Module
import modules import modules
from ui.endgame_ui import Ui_Form as EndGameWidget from ui.endgame_ui import Ui_Form as EndGameWidget
...@@ -31,13 +29,16 @@ class EndGameModule(Module): ...@@ -31,13 +29,16 @@ class EndGameModule(Module):
self.setActiveP2(len(self.players[self.winSide])>1) self.setActiveP2(len(self.players[self.winSide])>1)
self.displayPlayers() self.displayPlayers()
db = Database.instance()
idTeams = {}
for side in [Side.Left, Side.Right]: for side in [Side.Left, Side.Right]:
for player in self.players[side]: if PlayerGuest in self.players[side]:
player.stats.victories += 1 if side==self.winSide else 0 idTeams[side] = db.select_guest_team()
player.stats.goals_scored += self.scores[side] else:
player.stats.time_played += self.time idTeams[side] = db.insert_team([player.id for player in self.players[side]], self.scores[side])
player.stats.games_played += 1
player.save() db.insert_match(int(self.start_time), int(self.duration), idTeams[self.winSide], idTeams[self.winSide.opposite])
# Quit the screen after 5 seconds if the user doesn't do it before # Quit the screen after 5 seconds if the user doesn't do it before
#self.screenTimeout.start(5000) #self.screenTimeout.start(5000)
...@@ -45,8 +46,13 @@ class EndGameModule(Module): ...@@ -45,8 +46,13 @@ class EndGameModule(Module):
def unload(self): def unload(self):
logging.debug('Unloading EndGameModule') logging.debug('Unloading EndGameModule')
self.screenTimeout.stop() self.screenTimeout.stop()
del self.players del self.players
del self.gameType
del self.winSide del self.winSide
del self.scores
del self.start_time
del self.duration
def other(self, **kwargs): def other(self, **kwargs):
logging.debug('Other EndGameModule') logging.debug('Other EndGameModule')
...@@ -54,14 +60,16 @@ class EndGameModule(Module): ...@@ -54,14 +60,16 @@ class EndGameModule(Module):
for key, val in kwargs.items(): for key, val in kwargs.items():
if key=='players': if key=='players':
self.players = val self.players = val
elif key=='gameType':
self.gameType = val
elif key=='winSide': elif key=='winSide':
self.winSide = val self.winSide = val
elif key=='scores': elif key=='scores':
self.scores = val self.scores = val
elif key=='time': elif key=='start_time':
self.time = val self.start_time = val
#else: elif key=='duration':
# raise ValueError('Unknown message identifier {}'.format(kwargs) self.duration = val
def keyPressEvent(self, e): def keyPressEvent(self, e):
if e.key() == Qt.Key_Escape or e.key() == Qt.Key_Return: if e.key() == Qt.Key_Escape or e.key() == Qt.Key_Return:
......
#!/usr/bin/env python3 #!/usr/bin/env python3
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
""" """
Created on Wed Apr 18 18:34:40 2018
@author: Antoine Lima, Leo Reynaert, Domitille Jehenne @author: Antoine Lima, Leo Reynaert, Domitille Jehenne
""" """
...@@ -10,14 +8,16 @@ import os ...@@ -10,14 +8,16 @@ import os
import logging import logging
from PyQt5 import QtWidgets from PyQt5 import QtWidgets
from PyQt5.QtWidgets import QMessageBox
from PyQt5.QtGui import QRegion from PyQt5.QtGui import QRegion
from PyQt5.QtCore import QTime, QTimer, QRect, Qt, QUrl from PyQt5.QtCore import QDateTime, QDate, QTime, QTimer, QRect, Qt, QUrl
from PyQt5.QtMultimedia import QMediaContent, QMediaPlayer from PyQt5.QtMultimedia import QMediaContent, QMediaPlayer
from PyQt5.QtMultimediaWidgets import QVideoWidget from PyQt5.QtMultimediaWidgets import QVideoWidget
from player import Side, PlayerGuest from player import Side, PlayerGuest
from replay import Replay from replay import Replay
from module import Module from module import Module
from settings import Settings
import modules import modules
from ui.game_ui import Ui_Form as GameWidget from ui.game_ui import Ui_Form as GameWidget
...@@ -25,25 +25,53 @@ class GameOverChecker(): ...@@ -25,25 +25,53 @@ class GameOverChecker():
def __init__(self, conditionType, limit): def __init__(self, conditionType, limit):
self.conditionType = conditionType self.conditionType = conditionType
self.limit = limit self.limit = limit
def check(self, time, scores): def check(self, time, scores):
''' '''
Checks if a game is over and return the winner if that's the case Checks if a game is over and return the winner if that's the case
Returns the winning side or Side.Undef otherwise Returns the winning side or Side.Undef otherwise
Takes the game time is seconds and a list containing the two scores Takes the game time is seconds and a list containing the two scores
''' '''
# Gets the index of the highest scoring player # Gets the index of the highest scoring player
bestPlayer = max(scores, key=scores.get) bestPlayer = max(scores, key=scores.get)
if self.conditionType=='score' and scores[bestPlayer]>=self.limit: if self.conditionType=='score' and scores[bestPlayer]>=self.limit:
return bestPlayer return bestPlayer
elif self.conditionType=='time' and time>self.limit: elif self.conditionType=='time' and time>=self.limit:
return bestPlayer return bestPlayer
else: else:
return Side.Undef return Side.Undef
class ReplayHolder(QVideoWidget):
def __init__(self, mediaPlayer, parent):
super().__init__(parent)
self.mediaPlayer = mediaPlayer
def keyPressEvent(self, e):
self.mediaPlayer.stop_replay(QMediaPlayer.StoppedState)
class ReplayPlayer(QMediaPlayer):
def __init__(self, parent):
super().__init__(parent, QMediaPlayer.VideoSurface)
self.stateChanged.connect(self.stop_replay)
self.setMuted(True)
def start_replay(self, video_file):
self.setMedia(QMediaContent(QUrl.fromLocalFile(video_file)))
self._playerWidget = ReplayHolder(self, self.parent())
self.setVideoOutput(self._playerWidget)
self.play()
self._playerWidget.setFullScreen(True)
def stop_replay(self, status):
if status==QMediaPlayer.StoppedState:
self._playerWidget.setFullScreen(False);
self._playerWidget.setVisible(False);
self.parent().endOfReplay()
class GameModule(Module): class GameModule(Module):
def __init__(self, parent=None): def __init__(self, parent=None):
super().__init__(parent, GameWidget()) super().__init__(parent, GameWidget())
...@@ -56,18 +84,28 @@ class GameModule(Module): ...@@ -56,18 +84,28 @@ class GameModule(Module):
self.ui.btnScore1.clicked.connect(lambda: self.goal(Side.Left)) self.ui.btnScore1.clicked.connect(lambda: self.goal(Side.Left))
self.ui.btnScore2.clicked.connect(lambda: self.goal(Side.Right)) self.ui.btnScore2.clicked.connect(lambda: self.goal(Side.Right))
self.replayer = Replay() self.camera = None
self.video_player = None
def load(self): def load(self):
logging.debug('Loading GameModule') logging.debug('Loading GameModule')
self.gameStartTime = QTime.currentTime() self.gameStartTime = QTime.currentTime()
self.timerUpdateChrono.start(1000) self.timerUpdateChrono.start(1000)
self.ui.lcdChrono.display(QTime(0,0).toString("hh:mm:ss")) self.ui.lcdChrono.display(QTime(0,0).toString("hh:mm:ss"))
self.showingReplay = False self.video_player = None
self.gameoverChecker = GameOverChecker('score', 10) if self.camera:
self.camera.start_recording()
gameover_type = Settings['gameover.type']
gameover_value = Settings['gameover.value']
if gameover_type=='time':
gameover_value *= 60
self.gameoverChecker = GameOverChecker(gameover_type, gameover_value)
if all([len(val)==0 for val in self.players.values()]): if all([len(val)==0 for val in self.players.values()]):
self.players[Side.Left ].append(PlayerGuest) self.players[Side.Left ].append(PlayerGuest)
self.players[Side.Right].append(PlayerGuest) self.players[Side.Right].append(PlayerGuest)
...@@ -77,18 +115,25 @@ class GameModule(Module): ...@@ -77,18 +115,25 @@ class GameModule(Module):
def unload(self): def unload(self):
logging.debug('Unloading GameModule') logging.debug('Unloading GameModule')
del self.gameStartTime
self.timerUpdateChrono.stop() self.timerUpdateChrono.stop()
self.gameStartTime = None
if self.camera:
self.camera.stop_recording()
def other(self, **kwargs): def other(self, **kwargs):
logging.debug('Other GameModule') logging.debug('Other GameModule')
for key, val in kwargs.items(): for key, val in kwargs.items():
if key=='goal' and 'source' in kwargs: if key=='goal' and 'source' in kwargs:
self.goal(kwargs['source']) self.goal(kwargs['source'])
elif key=='players': elif key=='players':
self.players = val self.players = val
elif key=='replayThread':
self.replayer = val
def resizeEvent(self, event): def resizeEvent(self, event):
# 40% of the window width to have (5% margin)-(40% circle)-(10% middle)-(40% circle)-(5% margin) # 40% of the window width to have (5% margin)-(40% circle)-(10% middle)-(40% circle)-(5% margin)
...@@ -98,68 +143,76 @@ class GameModule(Module): ...@@ -98,68 +143,76 @@ class GameModule(Module):
self.ui.btnScore2.setMinimumSize(btnDiameter, btnDiameter) self.ui.btnScore2.setMinimumSize(btnDiameter, btnDiameter)
self.ui.btnScore1.setMask(region) self.ui.btnScore1.setMask(region)
self.ui.btnScore2.setMask(region) self.ui.btnScore2.setMask(region)
QtWidgets.QWidget.resizeEvent(self, event) QtWidgets.QWidget.resizeEvent(self, event)
def keyPressEvent(self, e): def keyPressEvent(self, e):
if e.key() == Qt.Key_Escape: if e.key() == Qt.Key_Escape:
self.handleCancel() ret = QMessageBox.question(self, 'Stop the match?', 'Do you really want to stop this match? It wont be saved.')
if ret == QMessageBox.Yes:
self.handleCancel()
elif e.key() == Qt.Key_Left: elif e.key() == Qt.Key_Left:
self.goal(Side.Left) self.goal(Side.Left)
elif e.key() == Qt.Key_Right: elif e.key() == Qt.Key_Right:
self.goal(Side.Right) self.goal(Side.Right)
def updateChrono(self): def updateChrono(self):
# Updated each second # Updated each second
self.ui.lcdChrono.display(QTime(0,0).addSecs(self.getGameTime()).toString("hh:mm:ss")) self.ui.lcdChrono.display(QTime(0,0).addSecs(self.getGameTime()).toString("hh:mm:ss"))
# Don't check scores while showing a replay to avoid closing the engame screen too soon # Don't check scores while showing a replay to avoid closing the engame screen too soon
if not self.showingReplay: if not self.video_player:
self.checkEndGame() self.checkEndGame()
def getGameTime(self): def getGameTime(self):
return self.gameStartTime.secsTo(QTime.currentTime()) return self.gameStartTime.secsTo(QTime.currentTime())
def updateScores(self): def updateScores(self):
self.ui.btnScore1.setText(str(self.scores[Side.Left])) self.ui.btnScore1.setText(str(self.scores[Side.Left]))
self.ui.btnScore2.setText(str(self.scores[Side.Right])) self.ui.btnScore2.setText(str(self.scores[Side.Right]))
self.checkEndGame() self.checkEndGame()
def goal(self, side): def goal(self, side):
if side not in Side: if side not in Side:
logging.error('Wrong goal side: {}'.format(side)) logging.error('Wrong goal side: {}'.format(side))
else: else:
self.scores[side] += 1 self.scores[side] += 1
# Show replay # Show replay
# May require `sudo apt-get install qtmultimedia5-examples` in order to install the right libraries # May require `sudo apt-get install qtmultimedia5-examples` in order to install the right libraries
replayFile = self.mainwin.getContent('Replay {}.mp4'.format(side.name)) if self.camera:
replayFile = self.camera.stop_recording()
if os.path.exists(replayFile): elif Settings['replay.debug']:
if True: # Debug Mode replayFile = Replay.Dummy()
self.updateScores() else:
else: replayFile = ''
self.showingReplay = True
self.player = QMediaPlayer(None, QMediaPlayer.VideoSurface) if replayFile and os.path.exists(replayFile):
self.player.stateChanged.connect(self.endOfReplay) self.video_player = ReplayPlayer(self)
self.player.setMuted(True) self.video_player.start_replay(replayFile)
self.player.setVideoOutput(self.ui.videoWidget) else:
self.player.setMedia(QMediaContent(QUrl.fromLocalFile(replayFile))) self.updateScores()
self.player.play()
self.ui.videoWidget.setFullScreen(True) def endOfReplay(self):
self.video_player = None
def endOfReplay(self, status):
if status!=QMediaPlayer.PlayingState: if self.gameStartTime:
self.ui.videoWidget.setFullScreen(False);
self.showingReplay = False
self.updateScores() self.updateScores()
if self.camera:
self.camera.start_recording()
def handleCancel(self): def handleCancel(self):
self.switchModule(modules.MenuModule) self.switchModule(modules.MenuModule)
def checkEndGame(self): def checkEndGame(self):
winSide = self.gameoverChecker.check(self.getGameTime(), self.scores) winSide = self.gameoverChecker.check(self.getGameTime(), self.scores)
if winSide!=Side.Undef: if winSide!=Side.Undef:
self.send(modules.EndGameModule, players=self.players, winSide=winSide, scores=self.scores, time=self.getGameTime()) start_timestamp = int(QDateTime(QDate.currentDate(), self.gameStartTime).toMSecsSinceEpoch()/1000)
self.send(modules.EndGameModule, players=self.players, winSide=winSide, scores=self.scores)
self.send(modules.EndGameModule, start_time=start_timestamp, duration=self.getGameTime(), gameType=self)
self.switchModule(modules.EndGameModule) self.switchModule(modules.EndGameModule)
#!/usr/bin/env python3 #!/usr/bin/env python3
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
""" """
Created on Wed Apr 18 18:34:40 2018
@author: Antoine Lima, Leo Reynaert, Domitille Jehenne @author: Antoine Lima, Leo Reynaert, Domitille Jehenne
""" """
import logging import logging
from operator import attrgetter from operator import attrgetter
from PyQt5 import QtWidgets from PyQt5.QtWidgets import QWidget, QDialog, QListWidgetItem
from PyQt5.QtCore import QTime, Qt, QSize, QItemSelectionModel from PyQt5.QtCore import Qt, QItemSelectionModel
from module import Module
import modules import modules
from player import PlayerGuest, Player from module import Module
from ui.leaderboard_ui import Ui_Form as LeaderboardWidget from player import Player, Side
from ui.playerlist_ui import Ui_Form as PlayerListWidget from database import Database
class LeaderboardItemWidget(QtWidgets.QWidget): from ui.leaderboard_ui import Ui_Form as LeaderboardWidget
from ui.playerlist_ui import Ui_Form as PlayerListWidget
from ui.delete_dialog_ui import Ui_Dialog as PlayerDeleteDialog
class LeaderboardItemWidget(QWidget):
def __init__(self, parent, player): def __init__(self, parent, player):
QtWidgets.QWidget.__init__(self, parent) QWidget.__init__(self, parent)
self.ui = PlayerListWidget() self.ui = PlayerListWidget()
self.ui.setupUi(self) self.ui.setupUi(self)
...@@ -28,13 +29,30 @@ class LeaderboardItemWidget(QtWidgets.QWidget): ...@@ -28,13 +29,30 @@ class LeaderboardItemWidget(QtWidgets.QWidget):
self.ui.lblFName.setText(player.fname) self.ui.lblFName.setText(player.fname)
self.ui.lblLName.setText(player.lname) self.ui.lblLName.setText(player.lname)
self.ui.lblVictories.setText (self.ui.lblVictories.text().replace('####', str(player.stats.victories))) self.ui.lblVictories.setText (self.ui.lblVictories.text().replace('####', str(player.stats['victories'])))
self.ui.lblGamesPlayed.setText (self.ui.lblGamesPlayed.text().replace('####', str(player.stats.games_played))) self.ui.lblGamesPlayed.setText (self.ui.lblGamesPlayed.text().replace('####', str(player.stats['games_played'])))
self.ui.lblGoalsScored.setText (self.ui.lblGoalsScored.text().replace('####', str(player.stats.goals_scored))) self.ui.lblGoalsScored.setText (self.ui.lblGoalsScored.text().replace('####', str(player.stats['goals_scored'])))
self.ui.lblMinutesPlayed.setText(self.ui.lblMinutesPlayed.text().replace('####', str(player.stats.time_played))) self.ui.lblMinutesPlayed.setText(self.ui.lblMinutesPlayed.text().replace('####', str(player.stats['time_played'])))
self.ui.pushButton.clicked.connect(lambda: logging.debug('clicked')) self.ui.pushButton.clicked.connect(lambda: logging.debug('clicked'))
class DeleteDialog(QDialog):
def __init__(self, parent, player):
print('DeleteDialog {}'.format(player.name))
QDialog.__init__(self, parent)
self.ui = PlayerDeleteDialog()
self.ui.setupUi(self)
self.player = player
self.ui.lblTitle.setText(self.ui.lblTitle.text().format(player.name))
def check(self, rfid):
return rfid == -self.player.id
# Debug
def keyPressEvent(self, e):
if e.key() == Qt.Key_Return:
self.parent().send(modules.LeaderboardModule, rfid=self.player.rfid, source=Side.Right)
class LeaderboardModule(Module): class LeaderboardModule(Module):
def __init__(self, parent): def __init__(self, parent):
super().__init__(parent, LeaderboardWidget()) super().__init__(parent, LeaderboardWidget())
...@@ -48,13 +66,15 @@ class LeaderboardModule(Module): ...@@ -48,13 +66,15 @@ class LeaderboardModule(Module):
self.selectedSort = 0 self.selectedSort = 0
self.sortMethodRB = [self.ui.rbName, self.ui.rbVictories, self.ui.rbScore, self.ui.rbGamesPlayed, self.ui.rbTimePlayed] self.sortMethodRB = [self.ui.rbName, self.ui.rbVictories, self.ui.rbScore, self.ui.rbGamesPlayed, self.ui.rbTimePlayed]
self.sortMethodAttr = ['lname', 'stats.victories', 'stats.goals_scored', 'stats.games_played', 'stats.time_played'] self.sortMethodAttr = ['lname', 'stats_property.victories', 'stats_property.goals_scored', 'stats_property.games_played', 'stats_property.time_played']
self.sortMethodRB[self.selectedSort].setChecked(True) self.sortMethodRB[self.selectedSort].setChecked(True)
self.deleteDialog = None
def load(self): def load(self):
logging.debug('Loading LeaderboardModule') logging.debug('Loading LeaderboardModule')
self.loadList() self.loadList()
self.setFocus()
def unload(self): def unload(self):
logging.debug('Unloading LeaderboardModule') logging.debug('Unloading LeaderboardModule')
...@@ -62,6 +82,18 @@ class LeaderboardModule(Module): ...@@ -62,6 +82,18 @@ class LeaderboardModule(Module):
def other(self, **kwargs): def other(self, **kwargs):
logging.debug('Other LeaderboardModule') logging.debug('Other LeaderboardModule')
for key, val in kwargs.items():
if key=='rfid' and self.deleteDialog and self.deleteDialog.check(val):
Database.instance().delete_player(self.deleteDialog.player.id)
# Reset the dialog and the player list
self.deleteDialog.close()
del self.deleteDialog
self.deleteDialog = None
self.players = []
self.ui.listWidget.clear()
self.loadList()
def changeSort(self, rbSort): def changeSort(self, rbSort):
self.selectedSort = self.sortMethodRB.index(rbSort) self.selectedSort = self.sortMethodRB.index(rbSort)
...@@ -71,12 +103,12 @@ class LeaderboardModule(Module): ...@@ -71,12 +103,12 @@ class LeaderboardModule(Module):
if self.players: if self.players:
self.ui.listWidget.clear() self.ui.listWidget.clear()
else: else:
self.players = [Player.fromRFID(id) for id in range(-2 , -7, -1)] self.players = Player.allPlayers()
self.players.sort(key=attrgetter(self.sortMethodAttr[self.selectedSort]), reverse=True) self.players.sort(key=attrgetter(self.sortMethodAttr[self.selectedSort]), reverse=True)
for player in self.players: for player in self.players:
item = QtWidgets.QListWidgetItem() item = QListWidgetItem()
playerWidget = LeaderboardItemWidget(self.ui.listWidget, player) playerWidget = LeaderboardItemWidget(self.ui.listWidget, player)
item.setSizeHint(playerWidget.size()) item.setSizeHint(playerWidget.size())
self.ui.listWidget.addItem(item) self.ui.listWidget.addItem(item)
...@@ -106,6 +138,10 @@ class LeaderboardModule(Module): ...@@ -106,6 +138,10 @@ class LeaderboardModule(Module):
elif e.key() == Qt.Key_Right: elif e.key() == Qt.Key_Right:
newSort = curSort+1 if curSort!=len(self.sortMethodRB)-1 else 0 newSort = curSort+1 if curSort!=len(self.sortMethodRB)-1 else 0
self.sortMethodRB[newSort].animateClick() self.sortMethodRB[newSort].animateClick()
elif e.key() == Qt.Key_Delete:
self.deleteDialog = DeleteDialog(self, self.players[curRow])
self.deleteDialog.open()
def handleExit(self): def handleExit(self):
self.switchModule(modules.MenuModule) self.switchModule(modules.MenuModule)
#!/usr/bin/env python3 #!/usr/bin/env python3
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
""" """
Created on Wed Apr 18 18:34:40 2018
@author: Antoine Lima, Leo Reynaert, Domitille Jehenne @author: Antoine Lima, Leo Reynaert, Domitille Jehenne
""" """
...@@ -10,10 +8,10 @@ import logging ...@@ -10,10 +8,10 @@ import logging
from PyQt5.QtWidgets import QApplication from PyQt5.QtWidgets import QApplication
from PyQt5.QtCore import Qt from PyQt5.QtCore import Qt
from PyQt5.QtGui import QFont
from module import Module
import modules import modules
from module import Module
from settings import Settings
from ui.menu_ui import Ui_Form as MenuWidget from ui.menu_ui import Ui_Form as MenuWidget
from player import Side from player import Side
...@@ -42,7 +40,7 @@ class MenuModule(Module): ...@@ -42,7 +40,7 @@ class MenuModule(Module):
self.ui.btnStartQuick.animateClick() self.ui.btnStartQuick.animateClick()
def keyPressEvent(self, e): def keyPressEvent(self, e):
if e.key() == Qt.Key_Escape: if e.key() == Qt.Key_Escape and Settings['app.mode']=='dev':
self.handleExit() self.handleExit()
elif e.key() == Qt.Key_Up: elif e.key() == Qt.Key_Up:
...@@ -55,7 +53,7 @@ class MenuModule(Module): ...@@ -55,7 +53,7 @@ class MenuModule(Module):
self.send(modules.MenuModule, rfid=-2, source=Side.Left) self.send(modules.MenuModule, rfid=-2, source=Side.Left)
elif e.key() == Qt.Key_Right: elif e.key() == Qt.Key_Right:
self.send(modules.MenuModule, rfid=-4, source=Side.Right) self.send(modules.MenuModule, rfid=-3, source=Side.Right)
elif e.key() == Qt.Key_Return: elif e.key() == Qt.Key_Return:
if QApplication.focusWidget()==None: if QApplication.focusWidget()==None:
......
#!/usr/bin/env python3 #!/usr/bin/env python3
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
""" """
Created on Wed Apr 18 18:34:40 2018
@author: Antoine Lima, Leo Reynaert, Domitille Jehenne @author: Antoine Lima, Leo Reynaert, Domitille Jehenne
""" """
import logging import logging
from PyQt5.QtCore import Qt from PyQt5.QtCore import Qt, QEvent
from PyQt5.QtWidgets import QTableWidgetItem, QComboBox, QApplication from PyQt5.QtWidgets import QRadioButton, QSlider
from settings import Settings from settings import Settings
from module import Module from module import Module
...@@ -19,39 +17,85 @@ from ui.options_ui import Ui_Form as OptionsWidget ...@@ -19,39 +17,85 @@ from ui.options_ui import Ui_Form as OptionsWidget
class OptionsModule(Module): class OptionsModule(Module):
def __init__(self, parent): def __init__(self, parent):
super().__init__(parent, OptionsWidget()) super().__init__(parent, OptionsWidget())
self.ui.sliderGameOverValue.valueChanged.connect(self.updateGameOverLabel)
# Button connections self.ui.rbGameOver_Score.clicked.connect(self.updateGameOverLabel)
self.ui.btnSave.clicked.connect(self.handleSave) self.ui.rbGameOver_Time.clicked.connect(self.updateGameOverLabel)
self.ui.btnBack.clicked.connect(self.handleBack)
self.ui.sliderGameOverValue.installEventFilter(self)
def load(self): def load(self):
logging.debug('Loading OptionsModule') logging.debug('Loading OptionsModule')
cbb = QComboBox()
cbb.addItem('true') # Set Gameover condition from settings
cbb.addItem('false') self.ui.rbGameOver_Score.setChecked(Settings['gameover.type']=='score')
self.ui.options.insertRow(self.ui.options.rowCount()) self.ui.rbGameOver_Time.setChecked(Settings['gameover.type']=='time')
self.ui.options.setItem(self.ui.options.rowCount()-1, 0, QTableWidgetItem('FullScreen')) self.ui.sliderGameOverValue.setValue(Settings['gameover.value'])
self.ui.options.setCellWidget(self.ui.options.rowCount()-1, 1, cbb)
# Set League players from settings
self.ui.rbNumPlayerLeague_1.setChecked(Settings['league.playerPerTeam']==1)
self.ui.rbNumPlayerLeague_2.setChecked(Settings['league.playerPerTeam']==2)
# Set Language from settings
self.ui.rbLanguage_English.setChecked(Settings['ui.language']=='en')
self.ui.rbLanguage_French.setChecked(Settings['ui.language']=='fr')
self.selectIndex = 0
self.updateSelection()
self.updateGameOverLabel(0)
def unload(self): def unload(self):
logging.debug('Unloading OptionsModule') logging.debug('Unloading OptionsModule')
# Delete the table's content
self.ui.options.setRowCount(0)
def other(self, **kwargs): def other(self, **kwargs):
logging.debug('Other OptionsModule') logging.debug('Other OptionsModule')
def eventFilter(self, obj, event):
if obj==self.ui.sliderGameOverValue and event.type()==QEvent.KeyPress and (event.key()==Qt.Key_Up or event.key()==Qt.Key_Down):
self.keyPressEvent(event)
return True
return False
def keyPressEvent(self, e): def keyPressEvent(self, e):
if e.key() == Qt.Key_Escape: if e.key() == Qt.Key_Escape:
self.handleBack() self.handleBack()
elif e.key() == Qt.Key_Return: elif e.key() == Qt.Key_Return:
self.handleSave() self.handleSave()
elif e.key() == Qt.Key_Up:
#self.parent().focusPreviousChild()
self.selectIndex = self.selectIndex-1 if self.selectIndex!=0 else len(self.selectables)-1
self.updateSelection()
elif e.key() == Qt.Key_Down:
#self.parent().focusNextChild()
self.selectIndex = self.selectIndex+1 if self.selectIndex!=len(self.selectables)-1 else 0
self.updateSelection()
def updateSelection(self):
self.selectables = []
isSelectable = lambda widget: (isinstance(widget, QRadioButton) and widget.isChecked()) or isinstance(widget, QSlider)
for gb in [self.ui.gbGameOver, self.ui.gbLeaguePlayers, self.ui.gbLanguage]:
self.selectables.extend([child for child in gb.children() if isSelectable(child)])
self.selectables[self.selectIndex].setFocus()
def updateGameOverLabel(self, val):
sliderVal = self.ui.sliderGameOverValue.value()
strPoints = '{} point{}'.format(sliderVal, 's' if sliderVal>1 else '')
strTime = '{} minute{}'.format(sliderVal, 's' if sliderVal>1 else '')
self.ui.lblGameOverValue.setText(strPoints if self.ui.rbGameOver_Score.isChecked() else strTime)
def handleSave(self): def handleSave(self):
Settings['ui.fullscreen'] = self.ui.options.cellWidget(0, 1).currentText().lower() == 'true' Settings['ui.language'] = 'en' if self.ui.rbLanguage_English.isChecked() else 'fr'
self.mainwin._refreshAfterSettings() Settings['gameover.type'] = 'score' if self.ui.rbGameOver_Score.isChecked() else 'time'
Settings['gameover.value'] = self.ui.sliderGameOverValue.value()
Settings['league.playerPerTeam'] = 1 if self.ui.rbNumPlayerLeague_1.isChecked() else 2
Settings.saveSettingsToJSON()
self.mainwin._loadSettings()
self.switchModule(modules.MenuModule) self.switchModule(modules.MenuModule)
def handleBack(self): def handleBack(self):
# ToDo: Maybe add a warning
self.switchModule(modules.MenuModule) self.switchModule(modules.MenuModule)
...@@ -7,6 +7,7 @@ Created on Wed Apr 18 18:34:40 2018 ...@@ -7,6 +7,7 @@ Created on Wed Apr 18 18:34:40 2018
""" """
import logging import logging
from enum import Enum from enum import Enum
class Side(Enum): class Side(Enum):
...@@ -16,45 +17,50 @@ class Side(Enum): ...@@ -16,45 +17,50 @@ class Side(Enum):
Undef = -1 Undef = -1
Left = 0 Left = 0
Right = 1 Right = 1
@property
def opposite(self):
return Side.Right if self==Side.Left else Side.Left
from database import Database, DatabaseError
class Player(): class Player():
def __init__(self, id, fname='', lname='', pic_path=':ui/img/placeholder_head.jpg'): __query_infos = 'SELECT id, fname, lname, pic FROM Players WHERE rfid==?'
__query_time_goals_games = 'SELECT SUM(Matchs.duration) AS timePlayed, SUM(Teams.nGoals) AS goalsScored, COUNT(*) AS gamesPlayed FROM Teams INNER JOIN Matchs ON (Teams.id==Matchs.winningTeam OR Teams.id==Matchs.losingTeam) WHERE (Teams.player1==? OR player2==?)'
__query_victories = 'SELECT COUNT(*) AS victories FROM Players INNER JOIN Teams ON (Players.id==Teams.player1 OR Players.id==Teams.player2) INNER JOIN Matchs ON (Teams.id==Matchs.winningTeam) WHERE Players.id==?'
_placeholder_pic_path = ':ui/img/placeholder_head.jpg'
def __init__(self, id, rfid, fname, lname, pic_path, stats):
self.id = id self.id = id
self.rfid = rfid
self.fname = fname self.fname = fname
self.lname = lname self.lname = lname
self.pic_path = pic_path self.pic_path = pic_path if pic_path else Player._placeholder_pic_path # Default pic if None
self.stats = Stat(id) self.stats = stats
@staticmethod @staticmethod
def fromRFID(id): def fromRFID(rfid):
fname, lname, pic_url = '','','' # Replace with DB calls db = Database.instance()
if id==-1: try:
player = Player(id, 'Guest') # Retrieve generic informations
id, fname, lname, pic = db.select_one(Player.__query_infos, rfid)
elif id==-2:
player = Player(id, 'Alfredo', 'Enrique')
elif id==-3:
player = Player(id, 'Bastien', 'Dali')
player.stats.victories = 1
elif id==-4:
player = Player(id, 'Carim', 'Cuebache')
player.stats.time_played = 1
elif id==-5: # Retrieve stats
player = Player(id, 'Dorian', 'Boulet') stats = {}
player.stats.games_played = 1 stats['time_played'], stats['goals_scored'], stats['games_played'] = db.select_one(Player.__query_time_goals_games, id, id)
stats['victories'], = db.select_one(Player.__query_victories, id)
elif id==-6: for key, val in stats.items():
player = Player(id, 'Enzo', 'Arobaz') if val==None:
player.stats.goals_scored = 1 stats[key] = 0
else: return Player(id, rfid, fname, lname, pic, stats)
player = Player(id, fname, lname, pic_url)
return player except DatabaseError as e:
logging.warn('DB Error: {}'.format(e))
return PlayerGuest
def displayImg(self, containerWidget): def displayImg(self, containerWidget):
containerWidget.setStyleSheet('border-image: url({});'.format(self.pic_path)) containerWidget.setStyleSheet('border-image: url({});'.format(self.pic_path))
...@@ -63,28 +69,30 @@ class Player(): ...@@ -63,28 +69,30 @@ class Player():
''' '''
Update or create the player in database Update or create the player in database
''' '''
# TODO
pass
@property @property
def name(self): def name(self):
return '{} {}'.format(self.fname, self.lname.upper()) return '{} {}'.format(self.fname, self.lname.upper())
@property @property
def pic(self): def stats_property(self):
return QPixmap(self.pic_path) '''
Compatibility property allowing to access stats as a object member and not dict
class Stat(): ex: player.stats['victories'] can be accessed with player.stats_property.victories'
def __init__(self, player_id): This is mostly used for sorting players in leaderboard.py
self.victories = 0 '''
self.time_played = 0 class Stat:
self.games_played = 0 def __init__(self, stats):
self.goals_scored = 0 self.victories = stats['victories']
self.time_played = stats['time_played']
self.goals_scored = stats['goals_scored']
self.games_played = stats['games_played']
if player_id >= 0: return Stat(self.stats)
self.victories = 0
self.time_played = 0 @staticmethod
self.games_played = 0 def allPlayers():
self.goals_scored = 0 return [Player.fromRFID(rfid) for rfid, in Database.instance().select_all_rfid()]
PlayerGuest = Player.fromRFID(-1) PlayerGuest = Player.fromRFID(-1)
PlayerEmpty = Player(-1, -42, '', '', Player._placeholder_pic_path, {'time_played':'', 'goals_scored':'', 'games_played':'', 'victories': ''})
#!/usr/bin/env python3 #!/usr/bin/env python3
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
""" """
Created on Wed Apr 18 18:34:40 2018
@author: Antoine Lima, Leo Reynaert, Domitille Jehenne @author: Antoine Lima, Leo Reynaert, Domitille Jehenne
""" """
import os from threading import Thread, Event
from settings import Settings
onRasp = os.uname()[1] == 'raspberrypi' from main import getContent, OnRasp
from settings import Settings
if onRasp: if OnRasp:
import picamera import picamera
class Replay(Thread):
def __init__(self, side):
Thread.__init__(self)
self.replayPath = getContent('Replay {}.mp4'.format(side.name))
self.shutdown = False
self.start_flag = Event()
self.stop_flag = Event()
self.stopped_flag = Event()
class Replay(): if OnRasp:
def __init__(self):
if onRasp:
self.cam = picamera.PiCamera() self.cam = picamera.PiCamera()
self.cam.resolution = Settings['picam.resolution'] self.cam.resolution = Settings['picam.resolution']
self.cam.framerate = Settings['picam.fps'] self.cam.framerate = Settings['picam.fps']
self.cam.hflip = Settings['picam.hflip'] self.cam.hflip = Settings['picam.hflip']
self.cam.vflip = Settings['picam.vflip'] self.cam.vflip = Settings['picam.vflip']
self.format = Settings['picam.format']