Commit f43cc32f authored by Antoine Lima's avatar Antoine Lima

Settings and untested camera replays

parent 19dd30b9
......@@ -38,6 +38,61 @@ The widget contained by each module are stacked in a QStackedWidget and only one
To get from one to the other, the current module is unloaded current, then the new one is shown and loaded.
Each module can overload the load/unload/other method in order to have a specific behavior.
### Settings
Settings are stored in a JSON file located in the parent's `content` directory, that looks like:
```
{
"app": {
"loglevel": {
"type": "combo",
"value": "debug",
"values": [
"debug",
"info",
"warning",
"error",
"critical"
]
}
},
"ui": {
"fullscreen": {
"type": "boolean",
"value": false
}
},
"picam": {
"resolution": {
"type": "combo",
"value": [640, 480],
"values": [
[1920, 1080],
[1280, 720],
[640, 480]
]
}
},
"replay": {
"duration": {
"type": "range",
"value": 5,
"range": [1, 10]
}
}
}
```
That JSON file is parsed and can be accessed by doing:
```
from settings Import Settings
Settings['ui.fullscreen'] = False
duration = Settings['replay.duration']
```
### Replays
Replays are 5-10 seconds clips played when a goal is scored. Those are stored in the parent's `content` directory under the name `replay0.mp4` and `replay1.mp4`.
For the time being, those are provided by the PI camera module.
### DB
......
......@@ -11,7 +11,7 @@ import logging
from os.path import dirname, abspath, join
from PyQt5 import QtWidgets
from PyQt5.QtWidgets import QGraphicsBlurEffect
from PyQt5.QtWidgets import QGraphicsBlurEffect, QApplication
from PyQt5.QtCore import QTime, Qt
from ui.main_ui import Ui_MainWindow
......@@ -29,10 +29,6 @@ class MainWin(QtWidgets.QMainWindow):
#bgBlur.setBlurRadius(5)
#self.ui.panels.setGraphicsEffect(bgBlur)
# Set the content folder's path
self._contentFolder = join(dirname(dirname(abspath(__file__))), 'content')
print(self._contentFolder)
# Module loading
self.modules = [
MenuModule(self),
......@@ -61,10 +57,22 @@ class MainWin(QtWidgets.QMainWindow):
def displaySystemTime(self):
self.ui.lcdTime.display(QTime.currentTime().toString("hh:mm:ss"))
def getContent(self, path):
return join(self._contentFolder, path)
@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']:
self.showFullScreen()
QApplication.setOverrideCursor(Qt.BlankCursor);
else:
self.showNormal()
QApplication.setOverrideCursor(Qt.ArrowCursor);
if __name__=='__main__':
app = QtWidgets.QApplication(sys.argv)
#logging.basicConfig(filename='babyfoot.log', level=logging.DEBUG)
......
......@@ -6,6 +6,7 @@ Created on Wed Apr 18 18:34:40 2018
@author: Antoine Lima, Leo Reynaert, Domitille Jehenne
"""
import os
import logging
from PyQt5 import QtWidgets
......@@ -14,6 +15,7 @@ from PyQt5.QtCore import QTime, QTimer, QRect, Qt, QUrl
from PyQt5.QtMultimedia import QMediaContent, QMediaPlayer
from PyQt5.QtMultimediaWidgets import QVideoWidget
from replay import Replay
from module import Module
import modules
from ui.game_ui import Ui_Form as GameWidget
......@@ -52,6 +54,8 @@ class GameModule(Module):
# Button connections
self.ui.btnScore1.clicked.connect(lambda: self.goal(0))
self.ui.btnScore2.clicked.connect(lambda: self.goal(1))
self.replayer = Replay()
def load(self):
logging.debug('Loading GameModule')
......@@ -116,16 +120,18 @@ class GameModule(Module):
# Show replay
# May require `sudo apt-get install qtmultimedia5-examples` in order to install the right libraries
self.showingReplay = True
replayFile = self.mainwin.getContent("replay{}.mp4".format(side))
self.player = QMediaPlayer(None, QMediaPlayer.VideoSurface)
self.player.stateChanged.connect(self.endOfReplay)
self.player.setMuted(True)
self.player.setVideoOutput(self.ui.videoWidget)
self.player.setMedia(QMediaContent(QUrl.fromLocalFile(replayFile)))
self.player.play()
self.ui.videoWidget.setFullScreen(True)
if os.path.exists(replayFile):
self.showingReplay = True
self.player = QMediaPlayer(None, QMediaPlayer.VideoSurface)
self.player.stateChanged.connect(self.endOfReplay)
self.player.setMuted(True)
self.player.setVideoOutput(self.ui.videoWidget)
self.player.setMedia(QMediaContent(QUrl.fromLocalFile(replayFile)))
self.player.play()
self.ui.videoWidget.setFullScreen(True)
def endOfReplay(self, status):
if status!=QMediaPlayer.PlayingState:
......
......@@ -11,6 +11,7 @@ import logging
from PyQt5.QtCore import Qt
from PyQt5.QtWidgets import QTableWidgetItem, QComboBox, QApplication
from settings import Settings
from module import Module
import modules
from ui.options_ui import Ui_Form as OptionsWidget
......@@ -47,13 +48,8 @@ class OptionsModule(Module):
self.ui_handleClick_btnSave()
def ui_handleClick_btnSave(self):
if self.ui.options.cellWidget(0, 1).currentText().lower() == 'true':
self.mainwin.showFullScreen()
QApplication.setOverrideCursor(Qt.BlankCursor);
else:
self.mainwin.showNormal()
QApplication.setOverrideCursor(Qt.ArrowCursor);
Settings['ui.fullscreen'] = self.ui.options.cellWidget(0, 1).currentText().lower() == 'true'
self.mainwin._refreshAfterSettings()
self.switchModule(modules.MenuModule)
def ui_handleClick_btnBack(self):
......
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Wed Apr 18 18:34:40 2018
@author: Antoine Lima, Leo Reynaert, Domitille Jehenne
"""
import picamera
import settings import Settings
class Replay():
def __init__(self):
self.cam = picamera.PiCamera()
self.cam.resolution = Settings['picam.resolution']
self.cam.framerate = Settings['picam.fps']
self.cam.hflip = Settings['picam.hflip']
self.cam.vflip = Settings['picam.vflip']
self.format = Settings['picam.format']
self.continue_recording = False
self.stream = picamera.PiCameraCircularIO(self.cam, seconds=Settings['replay.duration'])
def capture(self, fileToSave):
self.cam.start_recording(self.stream, self.format)
self.continue_recording = True
try:
while self.continue_recording:
self.cam.wait_recording(1)
finally:
self.cam.stop_recording()
self.stream.copy_to(fileToSave)
self.cam.close()
self.stream.close()
def stop():
self.continue_recording = False
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Wed Apr 18 18:34:40 2018
@author: Antoine Lima, Leo Reynaert, Domitille Jehenne
"""
import json
from main import MainWin
class Setting(object):
TypeName = ''
def __init__(self, value):
self.value = value
class SettingBoolean(Setting):
TypeName = 'boolean'
def __init__(self, value):
Setting.__init__(self, value)
class SettingCombo(Setting):
TypeName = 'combo'
def __init__(self, value, values):
Setting.__init__(self, value)
self.values = values
if self.value not in values:
raise ValueError('Setting value {} not in list of possible values {}'.format(self.value, self.values))
class SettingRange(Setting):
TypeName = 'range'
def __init__(self, value, limits):
Setting.__init__(self, value)
self.lower_limit = min(limits)
self.upper_limit = max(limits)
if self.value<self.lower_limit or self.value>self.upper_limit:
raise ValueError('Setting value {} not in range {}'.format(self.value, (self.lower_limit, self.upper_limit)))
class SettingsHolder(object):
def __init__(self, settingsPath):
self.settingsPath = settingsPath
self.loadSettingsFromJSON()
def __delitem__(self, key):
pass
def __getitem__(self, key):
subkeys = SettingsHolder._parseKey(key)
if len(subkeys) == 2:
return getattr(self, subkeys[0])[subkeys[1]].value
elif len(subkeys) == 1:
return getattr(self, subkeys[0]).value
else:
raise IndexError('Invalid key {}'.format(key))
def __setitem__(self, key, value):
subkeys = SettingsHolder._parseKey(key)
if len(subkeys) == 2:
getattr(self, subkeys[0])[subkeys[1]].value = value
elif len(subkeys) == 1:
getattr(self, subkeys[0]).value = value
else:
raise IndexError('Invalid key {}'.format(key))
@staticmethod
def _parseKey(key):
return [k for k in key.split('.') if k]
def _init_ui(self):
self.ui.append(Setting())
def loadSettingsFromJSON(self):
settings = list()
with open(self.settingsPath, 'r') as f:
content = json.load(f)
# Outer loop, setting category
for cat in content:
setattr(self, cat, dict())
content_outer = content[cat]
# Inner loop, setting type
for name in content_outer:
content_inner = content_outer[name]
typeName = content_inner['type']
value = content_inner['value']
# Switch over types
if typeName == SettingBoolean.TypeName:
setting = SettingBoolean(value)
elif typeName == SettingCombo.TypeName:
setting = SettingCombo(value, content_inner['values'])
elif typeName == SettingRange.TypeName:
setting = SettingRange(value, content_inner['range'])
else:
raise ValueError('Unknown setting type {}'.format(typeName))
getattr(self, cat)[name] = setting
Settings = SettingsHolder(MainWin.getContent('settings.json'))
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment