Initial commit for the more modular rewrite of the Photobooth.
Basic Qt5-GUI implemented Config-File support implemented Basic settings dialog to change config implemented NO Photobooth functionality, yet
This commit is contained in:
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
photobooth.cfg
|
||||
photobooth/__pycache__
|
||||
68
photobooth/Config.py
Normal file
68
photobooth/Config.py
Normal file
@@ -0,0 +1,68 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import configparser, os
|
||||
|
||||
|
||||
class Config:
|
||||
|
||||
def __init__(self, filename):
|
||||
|
||||
self._filename = filename
|
||||
|
||||
self._cfg = configparser.ConfigParser()
|
||||
self.defaults()
|
||||
self.read()
|
||||
|
||||
|
||||
@property
|
||||
def filename(self):
|
||||
|
||||
return self._filename
|
||||
|
||||
|
||||
@filename.setter
|
||||
def filename(self, value):
|
||||
|
||||
self._filename = value
|
||||
|
||||
|
||||
def defaults(self):
|
||||
|
||||
self._cfg.read(os.path.join(os.path.dirname(__file__), 'defaults.cfg'))
|
||||
|
||||
|
||||
def read(self):
|
||||
|
||||
self._cfg.read(self._filename)
|
||||
|
||||
|
||||
def write(self):
|
||||
|
||||
with open(self._filename, 'w') as configfile:
|
||||
self._cfg.write(configfile)
|
||||
|
||||
|
||||
def get(self, section, key):
|
||||
|
||||
return self._cfg[section][key]
|
||||
|
||||
|
||||
def getInt(self, section, key):
|
||||
|
||||
return self._cfg.getint(section, key)
|
||||
|
||||
|
||||
def getFloat(self, section, key):
|
||||
|
||||
return self._cfg.getfloat(section, key)
|
||||
|
||||
|
||||
def getBool(self, section, key):
|
||||
|
||||
return self._cfg.getboolean(section, key)
|
||||
|
||||
|
||||
def set(self, section, key, value):
|
||||
|
||||
self._cfg[section][key] = value
|
||||
9
photobooth/Photobooth.py
Normal file
9
photobooth/Photobooth.py
Normal file
@@ -0,0 +1,9 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import Config, PyQt5Gui
|
||||
|
||||
def main(argv):
|
||||
|
||||
config = Config.Config('photobooth.cfg')
|
||||
return PyQt5Gui.run(argv, config)
|
||||
257
photobooth/PyQt5Gui.py
Normal file
257
photobooth/PyQt5Gui.py
Normal file
@@ -0,0 +1,257 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from PyQt5.QtCore import Qt
|
||||
from PyQt5.QtWidgets import (QApplication, QCheckBox, QComboBox, QFormLayout, QFrame, QGridLayout, QGroupBox, QHBoxLayout, QLabel, QLayout, QLineEdit, QMainWindow, QMessageBox, QPushButton, QVBoxLayout)
|
||||
|
||||
class PyQt5Gui(QMainWindow):
|
||||
|
||||
def __init__(self):
|
||||
|
||||
super().__init__()
|
||||
|
||||
self.initUI()
|
||||
|
||||
|
||||
def initUI(self):
|
||||
|
||||
global cfg
|
||||
|
||||
self.showStart()
|
||||
self.setWindowTitle('Photobooth')
|
||||
|
||||
if cfg.getBool('Gui', 'fullscreen'):
|
||||
self.showFullScreen()
|
||||
else:
|
||||
self.resize(cfg.getInt('Gui', 'width'),
|
||||
cfg.getInt('Gui', 'height'))
|
||||
self.show()
|
||||
|
||||
|
||||
def showStart(self):
|
||||
|
||||
content = PyQt5Start(self)
|
||||
self.setCentralWidget(content)
|
||||
|
||||
|
||||
def showSettings(self):
|
||||
|
||||
content = PyQt5Settings(self)
|
||||
self.setCentralWidget(content)
|
||||
|
||||
|
||||
def closeEvent(self, e):
|
||||
|
||||
reply = QMessageBox.question(self, 'Confirmation', "Quit Photobooth?",
|
||||
QMessageBox.Yes | QMessageBox.No, QMessageBox.No)
|
||||
|
||||
if reply == QMessageBox.Yes:
|
||||
e.accept()
|
||||
else:
|
||||
e.ignore()
|
||||
|
||||
|
||||
def keyPressEvent(self, e):
|
||||
pass
|
||||
# if self.photobooth.status == Status.idle:
|
||||
# if e.key() == Qt.Key_Escape:
|
||||
# self.showStart()
|
||||
# elif e.key() == Qt.Key_Space:
|
||||
# self.centralWidget().trigger()
|
||||
|
||||
|
||||
|
||||
|
||||
class PyQt5Start(QFrame):
|
||||
|
||||
def __init__(self, parent):
|
||||
|
||||
super().__init__(parent)
|
||||
|
||||
self.initFrame(parent)
|
||||
|
||||
|
||||
def initFrame(self, parent):
|
||||
|
||||
grid = QGridLayout()
|
||||
grid.setSpacing(100)
|
||||
self.setLayout(grid)
|
||||
|
||||
btnStart = QPushButton('Start Photobooth')
|
||||
btnStart.resize(btnStart.sizeHint())
|
||||
# btnStart.clicked.connect(parent.showPhotobooth)
|
||||
grid.addWidget(btnStart, 0, 0)
|
||||
|
||||
btnSettings = QPushButton('Settings')
|
||||
btnSettings.resize(btnSettings.sizeHint())
|
||||
btnSettings.clicked.connect(parent.showSettings)
|
||||
grid.addWidget(btnSettings, 0, 1)
|
||||
|
||||
btnQuit = QPushButton('Quit')
|
||||
btnQuit.resize(btnQuit.sizeHint())
|
||||
btnQuit.clicked.connect(parent.close)
|
||||
grid.addWidget(btnQuit, 0, 2)
|
||||
|
||||
|
||||
|
||||
class PyQt5Settings(QFrame):
|
||||
|
||||
def __init__(self, parent):
|
||||
|
||||
super().__init__(parent)
|
||||
|
||||
self._parent = parent
|
||||
self.initFrame()
|
||||
|
||||
|
||||
def initFrame(self):
|
||||
|
||||
self._value_widgets = {}
|
||||
|
||||
grid = QGridLayout()
|
||||
grid.addWidget(self.createGuiSettings(), 0, 0)
|
||||
grid.addWidget(self.createGpioSettings(), 1, 0)
|
||||
grid.addWidget(self.createCameraSettings(), 0, 1)
|
||||
|
||||
layout = QVBoxLayout()
|
||||
layout.addLayout(grid)
|
||||
layout.addStretch(1)
|
||||
layout.addWidget(self.createButtons())
|
||||
self.setLayout(layout)
|
||||
|
||||
|
||||
def createGuiSettings(self):
|
||||
|
||||
global cfg
|
||||
|
||||
self._value_widgets['Gui'] = {}
|
||||
self._value_widgets['Gui']['fullscreen'] = QCheckBox('Enable fullscreen')
|
||||
if cfg.getBool('Gui', 'fullscreen'):
|
||||
self._value_widgets['Gui']['fullscreen'].toggle()
|
||||
self._value_widgets['Gui']['width'] = QLineEdit(cfg.get('Gui', 'width'))
|
||||
self._value_widgets['Gui']['height'] = QLineEdit(cfg.get('Gui', 'height'))
|
||||
|
||||
layout = QFormLayout()
|
||||
layout.addRow(self._value_widgets['Gui']['fullscreen'])
|
||||
layout.addRow(QLabel('Width:'), self._value_widgets['Gui']['width'])
|
||||
layout.addRow(QLabel('Height:'), self._value_widgets['Gui']['height'])
|
||||
|
||||
widget = QGroupBox('Interface settings (restart required)')
|
||||
widget.setLayout(layout)
|
||||
return widget
|
||||
|
||||
|
||||
def createGpioSettings(self):
|
||||
|
||||
global cfg
|
||||
|
||||
self._value_widgets['Gpio'] = {}
|
||||
self._value_widgets['Gpio']['enable'] = QCheckBox('Enable GPIO (restart required)')
|
||||
if cfg.getBool('Gpio', 'enable'):
|
||||
self._value_widgets['Gpio']['enable'].toggle()
|
||||
self._value_widgets['Gpio']['exit_channel'] = QLineEdit(cfg.get('Gpio', 'exit_channel'))
|
||||
self._value_widgets['Gpio']['trigger_channel'] = QLineEdit(cfg.get('Gpio', 'trigger_channel'))
|
||||
self._value_widgets['Gpio']['lamp_channel'] = QLineEdit(cfg.get('Gpio', 'lamp_channel'))
|
||||
|
||||
layout = QFormLayout()
|
||||
layout.addRow(self._value_widgets['Gpio']['enable'])
|
||||
layout.addRow(QLabel('Exit channel:'), self._value_widgets['Gpio']['exit_channel'])
|
||||
layout.addRow(QLabel('Trigger channel'), self._value_widgets['Gpio']['trigger_channel'])
|
||||
layout.addRow(QLabel('Lamp channel'), self._value_widgets['Gpio']['lamp_channel'])
|
||||
|
||||
widget = QGroupBox('GPIO settings')
|
||||
widget.setLayout(layout)
|
||||
return widget
|
||||
|
||||
|
||||
def createCameraSettings(self):
|
||||
|
||||
global cfg
|
||||
|
||||
wrapper = QComboBox()
|
||||
wrapper.addItem('command line')
|
||||
wrapper.addItem('piggyphoto')
|
||||
wrapper.addItem('gphoto2-cffi')
|
||||
|
||||
current_wrapper = cfg.get('Camera', 'gphoto2_wrapper')
|
||||
if current_wrapper == 'commandline':
|
||||
wrapper.setCurrentIndex(0)
|
||||
elif current_wrapper == 'piggyphoto':
|
||||
wrapper.setCurrentIndex(1)
|
||||
elif current_wrapper == 'gphoto2-cffi':
|
||||
wrapper.setCurrentIndex(2)
|
||||
else:
|
||||
wrapper.setCurrentIndex(-1)
|
||||
|
||||
self._value_widgets['Camera'] = {}
|
||||
self._value_widgets['Camera']['gphoto2_wrapper'] = wrapper
|
||||
|
||||
layout = QFormLayout()
|
||||
layout.addRow(QLabel('gPhoto2 wrapper:'), self._value_widgets['Camera']['gphoto2_wrapper'])
|
||||
|
||||
widget = QGroupBox('Camera settings')
|
||||
widget.setLayout(layout)
|
||||
return widget
|
||||
|
||||
|
||||
def createButtons(self):
|
||||
|
||||
layout = QHBoxLayout()
|
||||
layout.addStretch(1)
|
||||
|
||||
btnSave = QPushButton('Save')
|
||||
btnSave.resize(btnSave.sizeHint())
|
||||
btnSave.clicked.connect(self.storeConfig)
|
||||
layout.addWidget(btnSave)
|
||||
|
||||
btnCancel = QPushButton('Cancel')
|
||||
btnCancel.resize(btnCancel.sizeHint())
|
||||
btnCancel.clicked.connect(self._parent.showStart)
|
||||
layout.addWidget(btnCancel)
|
||||
|
||||
btnRestore = QPushButton('Restore defaults')
|
||||
btnRestore.resize(btnRestore.sizeHint())
|
||||
btnRestore.clicked.connect(self.restoreDefaults)
|
||||
layout.addWidget(btnRestore)
|
||||
|
||||
widget = QGroupBox()
|
||||
widget.setLayout(layout)
|
||||
return widget
|
||||
|
||||
|
||||
def storeConfig(self):
|
||||
|
||||
global cfg
|
||||
|
||||
cfg.set('Gui', 'fullscreen', str(self._value_widgets['Gui']['fullscreen'].isChecked()))
|
||||
cfg.set('Gui', 'width', self._value_widgets['Gui']['width'].text())
|
||||
cfg.set('Gui', 'height', self._value_widgets['Gui']['height'].text())
|
||||
|
||||
cfg.set('Gpio', 'enable', str(self._value_widgets['Gpio']['enable'].isChecked()))
|
||||
cfg.set('Gpio', 'exit_channel', self._value_widgets['Gpio']['exit_channel'].text())
|
||||
cfg.set('Gpio', 'trigger_channel', self._value_widgets['Gpio']['trigger_channel'].text())
|
||||
cfg.set('Gpio', 'lamp_channel', self._value_widgets['Gpio']['lamp_channel'].text())
|
||||
|
||||
wrapper_idx2val = [ 'commandline', 'piggyphoto', 'gphoto2-cffi' ]
|
||||
cfg.set('Camera', 'gphoto2_wrapper', wrapper_idx2val[self._value_widgets['Camera']['gphoto2_wrapper'].currentIndex()])
|
||||
|
||||
cfg.write()
|
||||
self._parent.showStart()
|
||||
|
||||
|
||||
def restoreDefaults(self):
|
||||
|
||||
global cfg
|
||||
|
||||
cfg.defaults()
|
||||
self._parent.showSettings()
|
||||
|
||||
|
||||
def run(argv, config):
|
||||
|
||||
global cfg
|
||||
cfg = config
|
||||
|
||||
app = QApplication(argv)
|
||||
p = PyQt5Gui()
|
||||
return app.exec_()
|
||||
8
photobooth/__init__.py
Normal file
8
photobooth/__init__.py
Normal file
@@ -0,0 +1,8 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import sys, Photobooth
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(Photobooth.main(sys.argv))
|
||||
|
||||
6
photobooth/__main__.py
Normal file
6
photobooth/__main__.py
Normal file
@@ -0,0 +1,6 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import sys, Photobooth
|
||||
|
||||
sys.exit(Photobooth.main(sys.argv))
|
||||
21
photobooth/defaults.cfg
Normal file
21
photobooth/defaults.cfg
Normal file
@@ -0,0 +1,21 @@
|
||||
[Gui]
|
||||
# Start Photobooth in fullscreen mode (True/False)
|
||||
fullscreen = False
|
||||
# Width of Photobooth (if not fullscreen)
|
||||
width = 1024
|
||||
# Height of Photobooth (if not fullscreen)
|
||||
height = 600
|
||||
|
||||
[Camera]
|
||||
# Wrapper to use gPhoto2 (gphoto2-cffi, piggyphoto, commandline)
|
||||
gphoto2_wrapper = commandline
|
||||
|
||||
[Gpio]
|
||||
# Enable use of GPIO (True/False)
|
||||
enable = True
|
||||
# Pin 18 (Channel 24) lets you return to start screen
|
||||
exit_channel = 24
|
||||
# Pin 16 (Channel 23) triggers capturing pictures
|
||||
trigger_channel = 23
|
||||
# Pin 7 (Channel 4) switches the lamp on and off
|
||||
lamp_channel = 4
|
||||
Reference in New Issue
Block a user