flake8 compliance (except for PyQt5Gui)

This commit is contained in:
Balthasar Reuter
2018-05-24 23:25:32 +02:00
parent e02451a7fd
commit d79317bb79
22 changed files with 303 additions and 413 deletions

View File

@@ -1,7 +1,9 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import configparser, os, logging
import configparser
import logging
import os
class Config:
@@ -14,59 +16,49 @@ class Config:
self.defaults()
self.read()
@property
def filename(self):
return self._filename
@filename.setter
def filename(self, value):
self._filename = value
def defaults(self):
filename = os.path.join(os.path.dirname(__file__), 'defaults.cfg')
logging.info('Reading config file "%s"', filename)
self._cfg.read(filename)
def read(self):
logging.info('Reading config file "%s"', self._filename)
self._cfg.read(self._filename)
def write(self):
logging.info('Writing config file "%s"', self._filename)
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

View File

@@ -1,7 +1,8 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
from gpiozero import LED, Button
from gpiozero import LED, Button
class Gpio:
@@ -10,29 +11,24 @@ class Gpio:
self._buttons = []
self._lamps = []
def setButton(self, bcm_pin, handler):
self._buttons.append(Button(bcm_pin))
self._buttons[-1].when_pressed = handler
def setLamp(self, bcm_pin):
self._lamps.append(LED(bcm_pin))
return len(self._lamps) - 1
def lampOn(self, index):
self._lamps[index].on()
def lampOff(self, index):
self._lamps[index].off()
def lampToggle(self, index):
self._lamps[index].toggle()

View File

@@ -33,46 +33,43 @@ class Photobooth:
self.triggerOff()
def initCamera(self, config, camera):
self._cap = camera
self._pic_dims = PictureDimensions(config, self._cap.getPicture().size)
if ( config.getBool('Photobooth', 'show_preview')
and self._cap.hasPreview ):
if (config.getBool('Photobooth', 'show_preview')
and self._cap.hasPreview):
logging.info('Countdown with preview activated')
self._show_counter = self.showCounterPreview
else:
logging.info('Countdown without preview activated')
self._show_counter = self.showCounterNoPreview
def initGpio(self, config):
if config.getBool('Gpio', 'enable'):
lamp_pin = config.getInt('Gpio', 'lamp_pin')
trigger_pin = config.getInt('Gpio', 'trigger_pin')
exit_pin = config.getInt('Gpio', 'exit_pin')
logging.info('GPIO enabled (lamp_pin=%d, trigger_pin=%d, exit_pin=%d)',
lamp_pin, trigger_pin, exit_pin)
logging.info(('GPIO enabled (lamp_pin=%d, trigger_pin=%d, '
'exit_pin=%d)'), lamp_pin, trigger_pin, exit_pin)
from Gpio import Gpio
self._gpio = Gpio()
lamp = self._gpio.setLamp(lamp_pin)
self._lampOn = lambda : self._gpio.lampOn(lamp)
self._lampOff = lambda : self._gpio.lampOff(lamp)
self._lampOn = lambda: self._gpio.lampOn(lamp)
self._lampOff = lambda: self._gpio.lampOff(lamp)
self._gpio.setButton(trigger_pin, self.gpioTrigger)
self._gpio.setButton(exit_pin, self.gpioExit)
else:
logging.info('GPIO disabled')
self._lampOn = lambda : None
self._lampOff = lambda : None
self._lampOn = lambda: None
self._lampOff = lambda: None
def teardown(self):
@@ -80,7 +77,6 @@ class Photobooth:
self.triggerOff()
self.setCameraIdle()
def recvEvent(self, expected):
event = self._conn.recv()
@@ -93,7 +89,6 @@ class Photobooth:
return event_idx
def recvAck(self):
events = ['ack', 'cancel', 'teardown']
@@ -102,7 +97,6 @@ class Photobooth:
logging.info('Teardown of camera requested')
raise TeardownException()
def recvTriggered(self):
events = ['triggered', 'teardown']
@@ -111,20 +105,17 @@ class Photobooth:
logging.info('Teardown of camera requested')
raise TeardownException()
@property
def showCounter(self):
return self._show_counter
def initRun(self):
self.setCameraIdle()
self._conn.send(gui.IdleState())
self.triggerOn()
def run(self):
self.initRun()
@@ -140,47 +131,41 @@ class Photobooth:
self.trigger()
except RuntimeError as e:
logging.error('Camera error: %s', str(e))
self._conn.send( gui.ErrorState('Camera error', str(e)) )
self._conn.send(gui.ErrorState('Camera error', str(e)))
self.recvAck()
except TeardownException:
self.teardown()
return 123
def setCameraActive(self):
self._cap.setActive()
def setCameraIdle(self):
if self._cap.hasIdle:
self._cap.setIdle()
def showCounterPreview(self):
self._conn.send(gui.CountdownState())
while not self._conn.poll():
self._conn.send(
gui.PreviewState(picture = ImageOps.mirror(self._cap.getPreview())) )
picture = ImageOps.mirror(self._cap.getPreview())
self._conn.send(gui.PreviewState(picture=picture))
self.recvAck()
def showCounterNoPreview(self):
self._conn.send(gui.CountdownState())
self.recvAck()
def showPose(self):
self._conn.send(gui.PoseState())
def captureSinglePicture(self):
self.showCounter()
@@ -190,29 +175,26 @@ class Photobooth:
self.setCameraActive()
return picture
def capturePictures(self):
return [ self.captureSinglePicture() for _ in range(self._pic_dims.totalNumPictures) ]
return [self.captureSinglePicture()
for _ in range(self._pic_dims.totalNumPictures)]
def assemblePictures(self, pictures):
output_image = Image.new('RGB', self._pic_dims.outputSize, (255, 255, 255))
image = Image.new('RGB', self._pic_dims.outputSize, (255, 255, 255))
for i in range(self._pic_dims.totalNumPictures):
output_image.paste(pictures[i].resize(self._pic_dims.thumbnailSize),
self._pic_dims.thumbnailOffset[i])
return output_image
image.paste(pictures[i].resize(self._pic_dims.thumbnailSize),
self._pic_dims.thumbnailOffset[i])
return image
def enqueueWorkerTasks(self, picture):
for task in self._worker_list:
self._queue.put(task.get(picture))
def trigger(self):
logging.info('Photobooth triggered')
@@ -228,7 +210,7 @@ class Photobooth:
img = self.assemblePictures(pics)
self._conn.send(gui.PictureState(img))
self.enqueueWorkerTasks(img)
self.setCameraIdle()
@@ -237,24 +219,20 @@ class Photobooth:
self._conn.send(gui.IdleState())
self.triggerOn()
def gpioTrigger(self):
self._gpioTrigger()
def gpioExit(self):
self._conn.send(gui.TeardownState())
def triggerOff(self):
self._lampOff()
self._gpioTrigger = lambda : None
self._gpioTrigger = lambda: None
def triggerOn(self):
self._lampOn()
self._gpioTrigger = lambda : self._conn.send(gui.TriggerState())
self._gpioTrigger = lambda: self._conn.send(gui.TriggerState())

View File

@@ -1,51 +1,50 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
class PictureDimensions:
def __init__(self, config, capture_size):
self._num_pictures = ( config.getInt('Picture', 'num_x') ,
config.getInt('Picture', 'num_y') )
self._num_pictures = (config.getInt('Picture', 'num_x'),
config.getInt('Picture', 'num_y'))
self._capture_size = capture_size
self._output_size = ( config.getInt('Picture', 'size_x') ,
config.getInt('Picture', 'size_y') )
self._output_size = (config.getInt('Picture', 'size_x'),
config.getInt('Picture', 'size_y'))
self._min_distance = ( config.getInt('Picture', 'min_dist_x') ,
config.getInt('Picture', 'min_dist_y') )
self._min_distance = (config.getInt('Picture', 'min_dist_x'),
config.getInt('Picture', 'min_dist_y'))
self.computeThumbnailDimensions()
def computeThumbnailDimensions(self):
resize_factor = min( ( (
( self.outputSize[i] - (self.numPictures[i] + 1) * self.minDistance[i] ) /
( self.numPictures[i] * self.captureSize[i]) ) for i in range(2) ) )
resize_factor = min((((self.outputSize[i] - (self.numPictures[i] + 1) *
self.minDistance[i]) /
(self.numPictures[i] * self.captureSize[i]))
for i in range(2)))
self._thumb_size = tuple( int(self.captureSize[i] * resize_factor)
for i in range(2) )
self._thumb_size = tuple(int(self.captureSize[i] * resize_factor)
for i in range(2))
output_picture_dist = tuple( ( self.outputSize[i] - self.numPictures[i] *
self.thumbnailSize[i] ) // (self.numPictures[i] + 1)
for i in range(2) )
thumb_dist = tuple((self.outputSize[i] - self.numPictures[i] *
self.thumbnailSize[i]) // (self.numPictures[i] + 1)
for i in range(2))
self._thumb_offsets = []
for i in range(self.totalNumPictures):
pos = (i % self.numPictures[0], i // self.numPictures[0])
self._thumb_offsets.append( tuple(
(pos[j] + 1) * output_picture_dist[j] +
pos[j] * self.thumbnailSize[j] for j in range(2) ) )
self._thumb_offsets.append(tuple((pos[j] + 1) * thumb_dist[j] +
pos[j] * self.thumbnailSize[j]
for j in range(2)))
@property
def numPictures(self):
return self._num_pictures
@property
def totalNumPictures(self):
@@ -56,25 +55,21 @@ class PictureDimensions:
return self._capture_size
@property
def outputSize(self):
return self._output_size
@property
def minDistance(self):
return self._min_distance
@property
def thumbnailSize(self):
return self._thumb_size
@property
def thumbnailOffset(self):

View File

@@ -1,7 +1,8 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import os, logging
import logging
import os
from glob import glob
@@ -30,10 +31,10 @@ class PictureList:
self.findExistingFiles()
def findExistingFiles(self):
# Find existing files
"""Count number of existing files matchin the given basename
"""
# Find existing files
count_pattern = '[0-9]' * self.count_width
pictures = glob(self.basename + count_pattern + self.suffix)
@@ -48,21 +49,18 @@ class PictureList:
# Print initial infos
logging.info('Number of last existing file: %d', self.counter)
logging.info('Saving assembled pictures as "%s%s.%s"', self.basename,
self.count_width * 'X', 'jpg')
logging.info('Saving assembled pictures as "%s%s.%s"', self.basename,
self.count_width * 'X', 'jpg')
def getFilename(self, count):
"""Return the file name for a given file number"""
return self.basename + str(count).zfill(self.count_width) + self.suffix
def getLast(self):
"""Return the current filename"""
return self.getFilename(self.counter)
def getNext(self):
"""Update counter and return the next filename"""
self.counter += 1
return self.getFilename(self.counter)

View File

@@ -15,13 +15,11 @@ class WorkerTask:
assert not kwargs
def get(self, picture):
raise NotImplementedError()
class PictureSaver(WorkerTask):
def __init__(self, config):
@@ -29,31 +27,27 @@ class PictureSaver(WorkerTask):
super().__init__()
path = os.path.join(config.get('Picture', 'basedir'),
config.get('Picture', 'basename'))
config.get('Picture', 'basename'))
basename = strftime(path, localtime())
self._pic_list = PictureList(basename)
@staticmethod
def do(picture, filename):
logging.info('Saving picture as %s', filename)
picture.save(filename, 'JPEG')
def get(self, picture):
return (self.do, (picture, self._pic_list.getNext()))
class Worker:
def __init__(self, config, queue):
self._queue = queue
def run(self):
for func, args in iter(self._queue.get, 'teardown'):

View File

@@ -6,4 +6,3 @@ from .main import main
if __name__ == "__main__":
sys.exit(main(sys.argv))

View File

@@ -1,5 +1,7 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import sys, photobooth
import sys
import photobooth
sys.exit(photobooth.main(sys.argv))

View File

@@ -1,7 +1,8 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import io, logging
import io
import logging
from PIL import Image
@@ -10,7 +11,6 @@ import gphoto2 as gp
from . import Camera
class CameraGphoto2(Camera):
def __init__(self):
@@ -25,26 +25,24 @@ class CameraGphoto2(Camera):
self._setupLogging()
self._setupCamera()
def cleanup(self):
self._cap.set_config(self._oldconfig)
self._cap.exit(self._ctxt)
def _setupLogging(self):
gp.error_severity[gp.GP_ERROR] = logging.WARNING
gp.check_result(gp.use_python_logging())
def _setupCamera(self):
self._ctxt = gp.Context()
self._cap = gp.Camera()
self._cap.init(self._ctxt)
logging.info('Camera summary: %s', str(self._cap.get_summary(self._ctxt)))
logging.info('Camera summary: %s',
str(self._cap.get_summary(self._ctxt)))
# get configuration tree
# self._config = self._cap.get_config()
@@ -52,30 +50,30 @@ class CameraGphoto2(Camera):
config = self._cap.get_config()
# make sure camera format is not set to raw
if 'raw' in config.get_child_by_name('imageformat').get_value().lower():
imageformat = config.get_child_by_name('imageformat').get_value()
if 'raw' in imageformat.lower():
raise RuntimeError('Camera file format is set to RAW')
self._printConfig(config)
@staticmethod
def _configTreeToText(tree, indent=0):
config_txt = ''
for child in tree.get_children():
for chld in tree.get_children():
config_txt += indent * ' '
config_txt += child.get_label() + ' [' + child.get_name() + ']: '
config_txt += chld.get_label() + ' [' + chld.get_name() + ']: '
if child.count_children() > 0:
config_txt += '\n'
config_txt += CameraGphoto2._configTreeToText(child, indent + 4)
if chld.count_children() > 0:
config_txt += '\n'
config_txt += CameraGphoto2._configTreeToText(chld, indent + 4)
else:
config_txt += str(child.get_value())
config_txt += str(chld.get_value())
try:
choice_txt = ' ('
for c in child.get_choices():
for c in chld.get_choices():
choice_txt += c + ', '
choice_txt += ')'
@@ -86,43 +84,34 @@ class CameraGphoto2(Camera):
return config_txt
@staticmethod
def _printConfig(config):
config_txt = 'Camera configuration:\n'
config_txt += CameraGphoto2._configTreeToText(config)
logging.info(config_txt)
def setActive(self):
config = self._cap.get_config()
# self._config.get_child_by_name('viewfinder').set_value(True)
config.get_child_by_name('output').set_value('PC')
self._cap.set_config(config)
def setIdle(self):
config = self._cap.get_config()
# self._config.get_child_by_name('viewfinder').set_value(False)
config.get_child_by_name('output').set_value('Off')
self._cap.set_config(config)
def getPreview(self):
# self._config.get_child_by_name('autofocusdrive').set_value(1)
# self._cap.set_config(self._config)
camera_file = self._cap.capture_preview()
file_data = camera_file.get_data_and_size()
return Image.open(io.BytesIO(file_data))
def getPicture(self):
file_path = self._cap.capture(gp.GP_CAPTURE_IMAGE)
camera_file = self._cap.file_get(file_path.folder, file_path.name, gp.GP_FILE_TYPE_NORMAL)
camera_file = self._cap.file_get(file_path.folder, file_path.name,
gp.GP_FILE_TYPE_NORMAL)
file_data = camera_file.get_data_and_size()
return Image.open(io.BytesIO(file_data))

View File

@@ -1,7 +1,8 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import io, logging
import io
import logging
from PIL import Image
@@ -23,18 +24,18 @@ class CameraGphoto2Cffi(Camera):
self._setupCamera()
def _setupCamera(self):
self._cap = gp.Camera()
logging.info('Supported operations: %s', self._cap.supported_operations)
logging.info('Supported operations: %s',
self._cap.supported_operations)
if 'raw' in self._cap.config['imgsettings']['imageformat'].value.lower():
imageformat = self._cap.config['imgsettings']['imageformat'].value
if 'raw' in imageformat.lower():
raise RuntimeError('Camera file format is set to RAW')
self._printConfig(self._cap.config)
@staticmethod
def _configTreeToText(config, indent=0):
@@ -46,38 +47,33 @@ class CameraGphoto2Cffi(Camera):
if hasattr(v, '__len__') and len(v) > 1:
config_txt += '\n'
config_txt += CameraGphoto2Cffi._configTreeToText(v, indent + 4)
config_txt += CameraGphoto2Cffi._configTreeToText(v,
indent + 4)
else:
config_txt += str(v) + '\n'
return config_txt
@staticmethod
def _printConfig(config):
config_txt = 'Camera configuration:\n'
config_txt += CameraGphoto2Cffi._configTreeToText(config)
logging.info(config_txt)
def setActive(self):
self._cap._get_config()['actions']['viewfinder'].set(True)
self._cap._get_config()['settings']['output'].set('PC')
def setIdle(self):
self._cap._get_config()['actions']['viewfinder'].set(False)
self._cap._get_config()['settings']['output'].set('Off')
def getPreview(self):
return Image.open(io.BytesIO(self._cap.get_preview()))
def getPicture(self):
return Image.open(io.BytesIO(self._cap.capture()))
return Image.open(io.BytesIO(self._cap.capture()))

View File

@@ -1,11 +1,15 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import logging
import os
import subprocess
from PIL import Image
import os, subprocess, logging
from . import Camera
class CameraGphoto2CommandLine(Camera):
def __init__(self):
@@ -26,19 +30,17 @@ class CameraGphoto2CommandLine(Camera):
self.setActive()
def setActive(self):
print(self._callGphoto('-a', '/dev/null'))
self._callGphoto('-a', '/dev/null')
def getPicture(self):
self._callGphoto('--capture-image-and-download', self._tmp_filename)
return Image.open(self._tmp_filename)
def _callGphoto(self, action, filename):
cmd = 'gphoto2 --force-overwrite --quiet ' + action + ' --filename ' + filename
return subprocess.check_output(cmd, shell=True, stderr=subprocess.STDOUT)
cmd = 'gphoto2 --force-overwrite --quiet {} --filename {}'
return subprocess.check_output(cmd.format(action, filename),
shell=True, stderr=subprocess.STDOUT)

View File

@@ -9,6 +9,7 @@ import cv2
from . import Camera
class CameraOpenCV(Camera):
def __init__(self):
@@ -22,7 +23,6 @@ class CameraOpenCV(Camera):
self._cap = cv2.VideoCapture()
def setActive(self):
if not self._cap.isOpened():
@@ -30,20 +30,17 @@ class CameraOpenCV(Camera):
if not self._cap.isOpened():
raise RuntimeError('Camera could not be opened')
def setIdle(self):
if self._cap.isOpened():
self._cap.release()
def getPreview(self):
return self.getPicture()
def getPicture(self):
self.setActive()
status, frame = self._cap.read()
if not status:
@@ -52,4 +49,3 @@ class CameraOpenCV(Camera):
# OpenCV yields frames in BGR format, conversion to RGB necessary.
# (See https://stackoverflow.com/a/32270308)
return Image.fromarray(cv2.cvtColor(frame, cv2.COLOR_BGR2RGB))

View File

@@ -6,8 +6,9 @@
modules = (
('python-gphoto2', 'CameraGphoto2', 'CameraGphoto2'),
('gphoto2-cffi', 'CameraGphoto2Cffi', 'CameraGphoto2Cffi'),
('gphoto2-commandline', 'CameraGphoto2CommandLine', 'CameraGphoto2CommandLine'),
('opencv', 'CameraOpenCV', 'CameraOpenCV') )
('gphoto2-commandline', 'CameraGphoto2CommandLine',
'CameraGphoto2CommandLine'),
('opencv', 'CameraOpenCV', 'CameraOpenCV'))
class Camera:
@@ -17,28 +18,23 @@ class Camera:
self.hasPreview = False
self.hasIdle = False
def __enter__(self):
return self
def __exit__(self, exc_type, exc_value, traceback):
self.cleanup()
def cleanup(self):
pass
@property
def hasPreview(self):
return self._has_preview
@hasPreview.setter
def hasPreview(self, value):
@@ -51,7 +47,6 @@ class Camera:
def hasIdle(self):
return self._has_idle
@hasIdle.setter
def hasIdle(self, value):
@@ -61,7 +56,6 @@ class Camera:
self._has_idle = value
def setActive(self):
if not self.hasIdle:
@@ -69,7 +63,6 @@ class Camera:
else:
raise NotImplementedError()
def setIdle(self):
if not self.hasIdle:
@@ -77,7 +70,6 @@ class Camera:
raise NotImplementedError()
def getPreview(self):
if not self.hasPreview:
@@ -85,15 +77,6 @@ class Camera:
raise NotImplementedError()
def getPicture(self):
raise NotImplementedError()
def setIdle(self):
if not self.hasIdle:
raise RuntimeError('Camera does not support idle state')
raise NotImplementedError()

View File

@@ -3,31 +3,26 @@
import logging
from PyQt5.QtWidgets import QMessageBox
from .. import printer
from ..util import lookup_and_import
from .GuiState import PrintState
class GuiPostprocess:
def __init__(self, **kwargs):
assert not kwargs
def get(self, picture):
raise NotImplementedError()
def confirm(self, picture):
raise NotImplementedError()
class PrintPostprocess(GuiPostprocess):
def __init__(self, printer_module, page_size, **kwargs):
@@ -37,16 +32,13 @@ class PrintPostprocess(GuiPostprocess):
Printer = lookup_and_import(printer.modules, printer_module, 'printer')
self._printer = Printer(page_size)
def get(self, picture):
return PrintState(lambda : self.do(picture), False)
return PrintState(lambda: self.do(picture), False)
def confirm(self, picture):
return PrintState(lambda : None, True)
return PrintState(lambda: None, True)
def do(self, picture):

View File

@@ -9,7 +9,6 @@ class GuiState:
assert not kwargs
class ErrorState(GuiState):
def __init__(self, title, message, **kwargs):
@@ -18,26 +17,22 @@ class ErrorState(GuiState):
self.title = title
self.message = message
@property
def title(self):
return self._title
@title.setter
def title(self, title):
self._title = title
@property
def message(self):
return self._message
@message.setter
def message(self, message):
@@ -59,13 +54,11 @@ class PictureState(GuiState):
self.picture = picture
@property
def picture(self):
return self._pic
@picture.setter
def picture(self, picture):
@@ -80,13 +73,11 @@ class MessageState(GuiState):
self.message = message
@property
def message(self):
return self._msg
@message.setter
def message(self, message):
@@ -154,13 +145,11 @@ class PrintState(GuiState):
self.handler = handler
self.confirmed = confirmed
@property
def handler(self):
return self._handler
@handler.setter
def handler(self, handler):
@@ -169,7 +158,6 @@ class PrintState(GuiState):
self._handler = handler
@property
def confirmed(self):
@@ -182,4 +170,3 @@ class PrintState(GuiState):
raise ValueError('confirmed status must be bool')
self._confirmed = confirmed

View File

@@ -8,21 +8,15 @@ from os.path import expanduser
from PIL import ImageQt
from PyQt5.QtCore import Qt, QObject, QPoint, QThread, QTimer, pyqtSignal
from PyQt5.QtWidgets import (QFileDialog, QTabWidget, QApplication, QCheckBox, QComboBox, QFormLayout, QFrame, QGridLayout, QGroupBox, QHBoxLayout, QLabel, QLayout, QLineEdit, QMainWindow, QMessageBox, QPushButton, QVBoxLayout, QWidget)
from PyQt5.QtGui import QImage, QPainter, QPixmap
from PyQt5 import QtGui, QtCore, QtWidgets
import math
from PyQt5.QtGui import QBrush, QPen, QColor, QFont
from PyQt5.QtCore import QRect
from .PyQt5GuiHelpers import QRoundProgressBar
from . import *
from .. import camera, printer
from ..printer.PrinterPyQt5 import PrinterPyQt5 as Printer
class PyQt5Gui(Gui):
@@ -33,7 +27,7 @@ class PyQt5Gui(Gui):
global cfg
cfg = config
self._app = QApplication(argv)
self._app = QtWidgets.QApplication(argv)
self._p = PyQt5MainWindow()
self._lastState = self.showStart
@@ -94,15 +88,15 @@ class PyQt5Gui(Gui):
def handleKeypressEvent(self, event):
if event.key() == Qt.Key_Escape:
if event.key() == QtCore.Qt.Key_Escape:
self.handleState(TeardownState())
elif event.key() == Qt.Key_Space:
elif event.key() == QtCore.Qt.Key_Space:
self.handleState(TriggerState())
def handleKeypressEventNoTrigger(self, event):
if event.key() == Qt.Key_Escape:
if event.key() == QtCore.Qt.Key_Escape:
self.handleState(TeardownState())
@@ -122,7 +116,7 @@ class PyQt5Gui(Gui):
self._p.handleKeypressEvent = self.handleKeypressEventNoTrigger
self._p.setCentralWidget( PyQt5GreeterMessage(
cfg.getInt('Picture', 'num_x'), cfg.getInt('Picture', 'num_y') ) )
QTimer.singleShot(cfg.getInt('Photobooth', 'greeter_time') * 1000, self.sendAck)
QtCore.QTimer.singleShot(cfg.getInt('Photobooth', 'greeter_time') * 1000, self.sendAck)
elif isinstance(state, CountdownState):
self._p.setCentralWidget(PyQt5CountdownMessage(cfg.getInt('Photobooth', 'countdown_time'), self.sendAck))
@@ -140,7 +134,7 @@ class PyQt5Gui(Gui):
elif isinstance(state, PictureState):
img = ImageQt.ImageQt(state.picture)
self._p.setCentralWidget(PyQt5PictureMessage(img))
QTimer.singleShot(cfg.getInt('Photobooth', 'display_time') * 1000,
QtCore.QTimer.singleShot(cfg.getInt('Photobooth', 'display_time') * 1000,
lambda : self.postprocessPicture(state.picture))
elif isinstance(state, TeardownState):
@@ -172,13 +166,13 @@ class PyQt5Gui(Gui):
break
else:
if isinstance(task, PrintState):
reply = QMessageBox.question(self._p, 'Print picture?',
reply = QtWidgets.QMessageBox.question(self._p, 'Print picture?',
'Do you want to print the picture?',
QMessageBox.Yes | QMessageBox.No, QMessageBox.No)
if reply == QMessageBox.Yes:
QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No, QtWidgets.QMessageBox.No)
if reply == QtWidgets.QMessageBox.Yes:
task.handler()
QMessageBox.information(self._p, 'Printing',
'Picture sent to printer.', QMessageBox.Ok)
QtWidgets.QMessageBox.information(self._p, 'Printing',
'Picture sent to printer.', QtWidgets.QMessageBox.Ok)
else:
raise ValueError('Unknown task')
@@ -188,8 +182,8 @@ class PyQt5Gui(Gui):
self._p.handleKeypressEvent = lambda event : None
self._lastState = self.showStart
self._p.setCentralWidget(PyQt5Start(self))
if QApplication.overrideCursor() != 0:
QApplication.restoreOverrideCursor()
if QtWidgets.QApplication.overrideCursor() != 0:
QtWidgets.QApplication.restoreOverrideCursor()
def showSettings(self):
@@ -205,7 +199,7 @@ class PyQt5Gui(Gui):
self._conn.send('start')
self._p.setCentralWidget(PyQt5WaitMessage('Starting the photobooth...'))
if cfg.getBool('Gui', 'hide_cursor'):
QApplication.setOverrideCursor(Qt.BlankCursor)
QtWidgets.QApplication.setOverrideCursor(QtCore.Qt.BlankCursor)
def showIdle(self):
@@ -218,9 +212,9 @@ class PyQt5Gui(Gui):
def showError(self, title, message):
logging.error('%s: %s', title, message)
reply = QMessageBox.warning(self._p, title, message,
QMessageBox.Close | QMessageBox.Retry, QMessageBox.Retry)
if reply == QMessageBox.Retry:
reply = QtWidgets.QMessageBox.warning(self._p, title, message,
QtWidgets.QMessageBox.Close | QtWidgets.QMessageBox.Retry, QtWidgets.QMessageBox.Retry)
if reply == QtWidgets.QMessageBox.Retry:
self.sendAck()
self._lastState()
else:
@@ -228,9 +222,9 @@ class PyQt5Gui(Gui):
self.showStart()
class PyQt5Receiver(QThread):
class PyQt5Receiver(QtCore.QThread):
notify = pyqtSignal(object)
notify = QtCore.pyqtSignal(object)
def __init__(self, conn):
@@ -257,7 +251,7 @@ class PyQt5Receiver(QThread):
class PyQt5MainWindow(QMainWindow):
class PyQt5MainWindow(QtWidgets.QMainWindow):
def __init__(self):
@@ -299,10 +293,10 @@ class PyQt5MainWindow(QMainWindow):
def closeEvent(self, e):
reply = QMessageBox.question(self, 'Confirmation', "Quit Photobooth?",
QMessageBox.Yes | QMessageBox.No, QMessageBox.No)
reply = QtWidgets.QMessageBox.question(self, 'Confirmation', "Quit Photobooth?",
QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No, QtWidgets.QMessageBox.No)
if reply == QMessageBox.Yes:
if reply == QtWidgets.QMessageBox.Yes:
e.accept()
else:
e.ignore()
@@ -315,7 +309,7 @@ class PyQt5MainWindow(QMainWindow):
class PyQt5Start(QFrame):
class PyQt5Start(QtWidgets.QFrame):
def __init__(self, gui):
@@ -326,28 +320,28 @@ class PyQt5Start(QFrame):
def initFrame(self, gui):
grid = QGridLayout()
grid = QtWidgets.QGridLayout()
grid.setSpacing(100)
self.setLayout(grid)
btnStart = QPushButton('Start Photobooth')
btnStart = QtWidgets.QPushButton('Start Photobooth')
btnStart.resize(btnStart.sizeHint())
btnStart.clicked.connect(gui.showStartPhotobooth)
grid.addWidget(btnStart, 0, 0)
btnSettings = QPushButton('Settings')
btnSettings = QtWidgets.QPushButton('Settings')
btnSettings.resize(btnSettings.sizeHint())
btnSettings.clicked.connect(gui.showSettings)
grid.addWidget(btnSettings, 0, 1)
btnQuit = QPushButton('Quit')
btnQuit = QtWidgets.QPushButton('Quit')
btnQuit.resize(btnQuit.sizeHint())
btnQuit.clicked.connect(gui.close)
grid.addWidget(btnQuit, 0, 2)
class PyQt5Settings(QFrame):
class PyQt5Settings(QtWidgets.QFrame):
def __init__(self, gui):
@@ -362,7 +356,7 @@ class PyQt5Settings(QFrame):
self._value_widgets = {}
layout = QVBoxLayout()
layout = QtWidgets.QVBoxLayout()
layout.addWidget(self.createTabs())
layout.addStretch(1)
layout.addWidget(self.createButtons())
@@ -371,7 +365,7 @@ class PyQt5Settings(QFrame):
def createTabs(self):
tabs = QTabWidget()
tabs = QtWidgets.QTabWidget()
tabs.addTab(self.createGuiSettings(), 'Interface')
tabs.addTab(self.createPhotoboothSettings(), 'Photobooth')
tabs.addTab(self.createCameraSettings(), 'Camera')
@@ -384,32 +378,32 @@ class PyQt5Settings(QFrame):
def createButtons(self):
layout = QHBoxLayout()
layout = QtWidgets.QHBoxLayout()
layout.addStretch(1)
btnSave = QPushButton('Save and restart')
btnSave = QtWidgets.QPushButton('Save and restart')
btnSave.resize(btnSave.sizeHint())
btnSave.clicked.connect(self.storeConfigAndRestart)
layout.addWidget(btnSave)
btnCancel = QPushButton('Cancel')
btnCancel = QtWidgets.QPushButton('Cancel')
btnCancel.resize(btnCancel.sizeHint())
btnCancel.clicked.connect(self._gui.showStart)
layout.addWidget(btnCancel)
btnRestore = QPushButton('Restore defaults')
btnRestore = QtWidgets.QPushButton('Restore defaults')
btnRestore.resize(btnRestore.sizeHint())
btnRestore.clicked.connect(self.restoreDefaults)
layout.addWidget(btnRestore)
widget = QGroupBox()
widget = QtWidgets.QGroupBox()
widget.setLayout(layout)
return widget
def createModuleComboBox(self, module_list, current_module):
cb = QComboBox()
cb = QtWidgets.QComboBox()
for m in module_list:
cb.addItem(m[0])
@@ -424,30 +418,30 @@ class PyQt5Settings(QFrame):
global cfg
self._value_widgets['Gui'] = {}
self._value_widgets['Gui']['fullscreen'] = QCheckBox('Enable fullscreen')
self._value_widgets['Gui']['fullscreen'] = QtWidgets.QCheckBox('Enable fullscreen')
if cfg.getBool('Gui', 'fullscreen'):
self._value_widgets['Gui']['fullscreen'].toggle()
self._value_widgets['Gui']['module'] = self.createModuleComboBox(modules, cfg.get('Gui', 'module'))
self._value_widgets['Gui']['width'] = QLineEdit(cfg.get('Gui', 'width'))
self._value_widgets['Gui']['height'] = QLineEdit(cfg.get('Gui', 'height'))
self._value_widgets['Gui']['hide_cursor'] = QCheckBox('Hide cursor')
self._value_widgets['Gui']['width'] = QtWidgets.QLineEdit(cfg.get('Gui', 'width'))
self._value_widgets['Gui']['height'] = QtWidgets.QLineEdit(cfg.get('Gui', 'height'))
self._value_widgets['Gui']['hide_cursor'] = QtWidgets.QCheckBox('Hide cursor')
if cfg.getBool('Gui', 'hide_cursor'):
self._value_widgets['Gui']['hide_cursor'].toggle()
layout = QFormLayout()
layout = QtWidgets.QFormLayout()
layout.addRow(self._value_widgets['Gui']['fullscreen'])
layout.addRow(QLabel('Gui module:'), self._value_widgets['Gui']['module'])
layout.addRow(QtWidgets.QLabel('Gui module:'), self._value_widgets['Gui']['module'])
sublayout_size = QHBoxLayout()
sublayout_size.addWidget(QLabel('Window size [px]:'))
sublayout_size = QtWidgets.QHBoxLayout()
sublayout_size.addWidget(QtWidgets.QLabel('Window size [px]:'))
sublayout_size.addWidget(self._value_widgets['Gui']['width'])
sublayout_size.addWidget(QLabel('x'))
sublayout_size.addWidget(QtWidgets.QLabel('x'))
sublayout_size.addWidget(self._value_widgets['Gui']['height'])
layout.addRow(sublayout_size)
layout.addRow(self._value_widgets['Gui']['hide_cursor'])
widget = QWidget()
widget = QtWidgets.QWidget()
widget.setLayout(layout)
return widget
@@ -457,21 +451,20 @@ class PyQt5Settings(QFrame):
global cfg
self._value_widgets['Gpio'] = {}
self._value_widgets['Gpio']['enable'] = QCheckBox('Enable GPIO')
self._value_widgets['Gpio']['enable'] = QtWidgets.QCheckBox('Enable GPIO')
if cfg.getBool('Gpio', 'enable'):
self._value_widgets['Gpio']['enable'].toggle()
self._value_widgets['Gpio']['exit_pin'] = QLineEdit(cfg.get('Gpio', 'exit_pin'))
self._value_widgets['Gpio']['trigger_pin'] = QLineEdit(cfg.get('Gpio', 'trigger_pin'))
self._value_widgets['Gpio']['lamp_pin'] = QLineEdit(cfg.get('Gpio', 'lamp_pin'))
self._value_widgets['Gpio']['exit_pin'] = QtWidgets.QLineEdit(cfg.get('Gpio', 'exit_pin'))
self._value_widgets['Gpio']['trigger_pin'] = QtWidgets.QLineEdit(cfg.get('Gpio', 'trigger_pin'))
self._value_widgets['Gpio']['lamp_pin'] = QtWidgets.QLineEdit(cfg.get('Gpio', 'lamp_pin'))
layout = QFormLayout()
layout = QtWidgets.QFormLayout()
layout.addRow(self._value_widgets['Gpio']['enable'])
layout.addRow(QLabel('Exit pin (BCM numbering):'), self._value_widgets['Gpio']['exit_pin'])
layout.addRow(QLabel('Trigger pin (BCM numbering):'), self._value_widgets['Gpio']['trigger_pin'])
layout.addRow(QLabel('Lamp pin (BCM numbering):'), self._value_widgets['Gpio']['lamp_pin'])
layout.addRow(QtWidgets.QLabel('Exit pin (BCM numbering):'), self._value_widgets['Gpio']['exit_pin'])
layout.addRow(QtWidgets.QLabel('Trigger pin (BCM numbering):'), self._value_widgets['Gpio']['trigger_pin'])
layout.addRow(QtWidgets.QLabel('Lamp pin (BCM numbering):'), self._value_widgets['Gpio']['lamp_pin'])
# widget = QGroupBox('GPIO settings')
widget = QWidget()
widget = QtWidgets.QWidget()
widget.setLayout(layout)
return widget
@@ -481,26 +474,25 @@ class PyQt5Settings(QFrame):
global cfg
self._value_widgets['Printer'] = {}
self._value_widgets['Printer']['enable'] = QCheckBox('Enable Printing')
self._value_widgets['Printer']['enable'] = QtWidgets.QCheckBox('Enable Printing')
if cfg.getBool('Printer', 'enable'):
self._value_widgets['Printer']['enable'].toggle()
self._value_widgets['Printer']['module'] = self.createModuleComboBox(printer.modules, cfg.get('Printer', 'module'))
self._value_widgets['Printer']['width'] = QLineEdit(cfg.get('Printer', 'width'))
self._value_widgets['Printer']['height'] = QLineEdit(cfg.get('Printer', 'height'))
self._value_widgets['Printer']['width'] = QtWidgets.QLineEdit(cfg.get('Printer', 'width'))
self._value_widgets['Printer']['height'] = QtWidgets.QLineEdit(cfg.get('Printer', 'height'))
layout = QFormLayout()
layout = QtWidgets.QFormLayout()
layout.addRow(self._value_widgets['Printer']['enable'])
layout.addRow(QLabel('Printer module:'), self._value_widgets['Printer']['module'])
layout.addRow(QtWidgets.QLabel('Printer module:'), self._value_widgets['Printer']['module'])
sublayout_size = QHBoxLayout()
sublayout_size.addWidget(QLabel('Paper size [mm]:'))
sublayout_size = QtWidgets.QHBoxLayout()
sublayout_size.addWidget(QtWidgets.QLabel('Paper size [mm]:'))
sublayout_size.addWidget(self._value_widgets['Printer']['width'])
sublayout_size.addWidget(QLabel('x'))
sublayout_size.addWidget(QtWidgets.QLabel('x'))
sublayout_size.addWidget(self._value_widgets['Printer']['height'])
layout.addRow(sublayout_size)
# widget = QGroupBox('Printer settings')
widget = QWidget()
widget = QtWidgets.QWidget()
widget.setLayout(layout)
return widget
@@ -512,11 +504,10 @@ class PyQt5Settings(QFrame):
self._value_widgets['Camera'] = {}
self._value_widgets['Camera']['module'] = self.createModuleComboBox(camera.modules, cfg.get('Camera', 'module'))
layout = QFormLayout()
layout.addRow(QLabel('Camera module:'), self._value_widgets['Camera']['module'])
layout = QtWidgets.QFormLayout()
layout.addRow(QtWidgets.QLabel('Camera module:'), self._value_widgets['Camera']['module'])
# widget = QGroupBox('Camera settings')
widget = QWidget()
widget = QtWidgets.QWidget()
widget.setLayout(layout)
return widget
@@ -526,21 +517,20 @@ class PyQt5Settings(QFrame):
global cfg
self._value_widgets['Photobooth'] = {}
self._value_widgets['Photobooth']['show_preview'] = QCheckBox('Show preview while countdown')
self._value_widgets['Photobooth']['show_preview'] = QtWidgets.QCheckBox('Show preview while countdown')
if cfg.getBool('Photobooth', 'show_preview'):
self._value_widgets['Photobooth']['show_preview'].toggle()
self._value_widgets['Photobooth']['greeter_time'] = QLineEdit(cfg.get('Photobooth', 'greeter_time'))
self._value_widgets['Photobooth']['countdown_time'] = QLineEdit(cfg.get('Photobooth', 'countdown_time'))
self._value_widgets['Photobooth']['display_time'] = QLineEdit(cfg.get('Photobooth', 'display_time'))
self._value_widgets['Photobooth']['greeter_time'] = QtWidgets.QLineEdit(cfg.get('Photobooth', 'greeter_time'))
self._value_widgets['Photobooth']['countdown_time'] = QtWidgets.QLineEdit(cfg.get('Photobooth', 'countdown_time'))
self._value_widgets['Photobooth']['display_time'] = QtWidgets.QLineEdit(cfg.get('Photobooth', 'display_time'))
layout = QFormLayout()
layout = QtWidgets.QFormLayout()
layout.addRow(self._value_widgets['Photobooth']['show_preview'])
layout.addRow(QLabel('Greeter time [s]:'), self._value_widgets['Photobooth']['greeter_time'])
layout.addRow(QLabel('Countdown time [s]:'), self._value_widgets['Photobooth']['countdown_time'])
layout.addRow(QLabel('Display time [s]:'), self._value_widgets['Photobooth']['display_time'])
layout.addRow(QtWidgets.QLabel('Greeter time [s]:'), self._value_widgets['Photobooth']['greeter_time'])
layout.addRow(QtWidgets.QLabel('Countdown time [s]:'), self._value_widgets['Photobooth']['countdown_time'])
layout.addRow(QtWidgets.QLabel('Display time [s]:'), self._value_widgets['Photobooth']['display_time'])
# widget = QGroupBox('Photobooth settings')
widget = QWidget()
widget = QtWidgets.QWidget()
widget.setLayout(layout)
return widget
@@ -550,54 +540,54 @@ class PyQt5Settings(QFrame):
global cfg
self._value_widgets['Picture'] = {}
self._value_widgets['Picture']['num_x'] = QLineEdit(cfg.get('Picture', 'num_x'))
self._value_widgets['Picture']['num_y'] = QLineEdit(cfg.get('Picture', 'num_y'))
self._value_widgets['Picture']['size_x'] = QLineEdit(cfg.get('Picture', 'size_x'))
self._value_widgets['Picture']['size_y'] = QLineEdit(cfg.get('Picture', 'size_y'))
self._value_widgets['Picture']['min_dist_x'] = QLineEdit(cfg.get('Picture', 'min_dist_x'))
self._value_widgets['Picture']['min_dist_y'] = QLineEdit(cfg.get('Picture', 'min_dist_y'))
self._value_widgets['Picture']['basedir'] = QLineEdit(cfg.get('Picture', 'basedir'))
self._value_widgets['Picture']['basename'] = QLineEdit(cfg.get('Picture', 'basename'))
self._value_widgets['Picture']['num_x'] = QtWidgets.QLineEdit(cfg.get('Picture', 'num_x'))
self._value_widgets['Picture']['num_y'] = QtWidgets.QLineEdit(cfg.get('Picture', 'num_y'))
self._value_widgets['Picture']['size_x'] = QtWidgets.QLineEdit(cfg.get('Picture', 'size_x'))
self._value_widgets['Picture']['size_y'] = QtWidgets.QLineEdit(cfg.get('Picture', 'size_y'))
self._value_widgets['Picture']['min_dist_x'] = QtWidgets.QLineEdit(cfg.get('Picture', 'min_dist_x'))
self._value_widgets['Picture']['min_dist_y'] = QtWidgets.QLineEdit(cfg.get('Picture', 'min_dist_y'))
self._value_widgets['Picture']['basedir'] = QtWidgets.QLineEdit(cfg.get('Picture', 'basedir'))
self._value_widgets['Picture']['basename'] = QtWidgets.QLineEdit(cfg.get('Picture', 'basename'))
layout = QFormLayout()
layout = QtWidgets.QFormLayout()
sublayout_num = QHBoxLayout()
sublayout_num.addWidget(QLabel('Number of shots per picture:'))
sublayout_num = QtWidgets.QHBoxLayout()
sublayout_num.addWidget(QtWidgets.QLabel('Number of shots per picture:'))
sublayout_num.addWidget(self._value_widgets['Picture']['num_x'])
sublayout_num.addWidget(QLabel('x'))
sublayout_num.addWidget(QtWidgets.QLabel('x'))
sublayout_num.addWidget(self._value_widgets['Picture']['num_y'])
layout.addRow(sublayout_num)
sublayout_size = QHBoxLayout()
sublayout_size.addWidget(QLabel('Size of assembled picture:'))
sublayout_size = QtWidgets.QHBoxLayout()
sublayout_size.addWidget(QtWidgets.QLabel('Size of assembled picture:'))
sublayout_size.addWidget(self._value_widgets['Picture']['size_x'])
sublayout_size.addWidget(QLabel('x'))
sublayout_size.addWidget(QtWidgets.QLabel('x'))
sublayout_size.addWidget(self._value_widgets['Picture']['size_y'])
layout.addRow(sublayout_size)
sublayout_dist = QHBoxLayout()
sublayout_dist.addWidget(QLabel('Min. distance between shots in picture:'))
sublayout_dist = QtWidgets.QHBoxLayout()
sublayout_dist.addWidget(QtWidgets.QLabel('Min. distance between shots in picture:'))
sublayout_dist.addWidget(self._value_widgets['Picture']['min_dist_x'])
sublayout_dist.addWidget(QLabel('x'))
sublayout_dist.addWidget(QtWidgets.QLabel('x'))
sublayout_dist.addWidget(self._value_widgets['Picture']['min_dist_y'])
layout.addRow(sublayout_dist)
file_dialog = lambda : self._value_widgets['Picture']['basedir'].setText(
QFileDialog.getExistingDirectory(self, 'Select directory',
expanduser('~'), QFileDialog.ShowDirsOnly))
file_button = QPushButton('Select directory')
QtWidgets.QFileDialog.getExistingDirectory(self, 'Select directory',
expanduser('~'), QtWidgets.QFileDialog.ShowDirsOnly))
file_button = QtWidgets.QPushButton('Select directory')
file_button.resize(file_button.sizeHint())
file_button.clicked.connect(file_dialog)
sublayout_path = QHBoxLayout()
sublayout_path.addWidget(QLabel('Basename of output files:'))
sublayout_path = QtWidgets.QHBoxLayout()
sublayout_path.addWidget(QtWidgets.QLabel('Basename of output files:'))
sublayout_path.addWidget(self._value_widgets['Picture']['basedir'])
sublayout_path.addWidget(QLabel('/'))
sublayout_path.addWidget(QtWidgets.QLabel('/'))
sublayout_path.addWidget(self._value_widgets['Picture']['basename'])
sublayout_path.addWidget(file_button)
layout.addRow(sublayout_path)
widget = QWidget()
widget = QtWidgets.QWidget()
widget.setLayout(layout)
return widget
@@ -652,7 +642,7 @@ class PyQt5Settings(QFrame):
class PyQt5WaitMessage(QFrame):
class PyQt5WaitMessage(QtWidgets.QFrame):
# With spinning wait clock, inspired by
# https://wiki.python.org/moin/PyQt/A%20full%20widget%20waiting%20indicator
@@ -672,17 +662,17 @@ class PyQt5WaitMessage(QFrame):
def paintEvent(self, event):
painter = QPainter(self)
painter = QtGui.QPainter(self)
f = self.font()
f.setPixelSize(self.height() / 8)
painter.setFont(f)
rect = QRect(0, self.height() * 3 / 5, self.width(), self.height() * 3 / 10)
painter.drawText(rect, Qt.AlignCenter, self._message)
rect = QtCore.QRect(0, self.height() * 3 / 5, self.width(), self.height() * 3 / 10)
painter.drawText(rect, QtCore.Qt.AlignCenter, self._message)
painter.setRenderHint(QPainter.Antialiasing)
painter.setPen(QPen(Qt.NoPen))
painter.setRenderHint(QtGui.QPainter.Antialiasing)
painter.setPen(QtGui.QPen(QtCore.Qt.NoPen))
center = (self.width() / 2, self.height() / 2)
@@ -693,7 +683,7 @@ class PyQt5WaitMessage(QFrame):
distance = (pos - i) % dots
color = (distance + 1) / (dots + 1) * 255
painter.setBrush(QBrush(QColor(color, color, color)))
painter.setBrush(QtGui.QBrush(QtGui.QColor(color, color, color)))
painter.drawEllipse(
center[0] + 180 / dots * math.cos(2 * math.pi * i / dots) - 20,
@@ -716,7 +706,7 @@ class PyQt5WaitMessage(QFrame):
class PyQt5IdleMessage(QFrame):
class PyQt5IdleMessage(QtWidgets.QFrame):
def __init__(self):
@@ -732,19 +722,19 @@ class PyQt5IdleMessage(QFrame):
def paintEvent(self, event):
painter = QPainter(self)
painter = QtGui.QPainter(self)
f = self.font()
f.setPixelSize(self.height() / 5)
painter.setFont(f)
painter.drawText(event.rect(), Qt.AlignCenter, 'Hit the button!')
painter.drawText(event.rect(), QtCore.Qt.AlignCenter, 'Hit the button!')
painter.end()
class PyQt5GreeterMessage(QFrame):
class PyQt5GreeterMessage(QtWidgets.QFrame):
def __init__(self, num_x, num_y):
@@ -765,24 +755,24 @@ class PyQt5GreeterMessage(QFrame):
def paintEvent(self, event):
painter = QPainter(self)
painter = QtGui.QPainter(self)
f = self.font()
f.setPixelSize(self.height() / 5)
painter.setFont(f)
rect = QRect(0, self.height() * 1 / 5, self.width(), self.height() * 3 / 10)
painter.drawText(rect, Qt.AlignCenter, self._title)
rect = QtCore.QRect(0, self.height() * 1 / 5, self.width(), self.height() * 3 / 10)
painter.drawText(rect, QtCore.Qt.AlignCenter, self._title)
f.setPixelSize(self.height() / 8)
painter.setFont(f)
rect = QRect(0, self.height() * 3 / 5, self.width(), self.height() * 3 / 10)
painter.drawText(rect, Qt.AlignCenter, self._text)
rect = QtCore.QRect(0, self.height() * 3 / 5, self.width(), self.height() * 3 / 10)
painter.drawText(rect, QtCore.Qt.AlignCenter, self._text)
painter.end()
class PyQt5CountdownMessage(QFrame):
class PyQt5CountdownMessage(QtWidgets.QFrame):
def __init__(self, time, action):
@@ -838,28 +828,28 @@ class PyQt5CountdownMessage(QFrame):
@picture.setter
def picture(self, pic):
if not isinstance(pic, QImage):
raise ValueError('picture must be a QImage')
if not isinstance(pic, QtGui.QImage):
raise ValueError('picture must be a QtGui.QImage')
self._picture = pic
def paintEvent(self, event):
painter = QPainter(self)
painter = QtGui.QPainter(self)
if self._picture != None:
pix = QPixmap.fromImage(self._picture)
pix = pix.scaled(self.size(), Qt.KeepAspectRatio, Qt.FastTransformation)
pix = QtGui.QPixmap.fromImage(self._picture)
pix = pix.scaled(self.size(), QtCore.Qt.KeepAspectRatio, QtCore.Qt.FastTransformation)
origin = ( (self.width() - pix.width()) // 2,
(self.height() - pix.height()) // 2 )
painter.drawPixmap(QPoint(*origin), pix)
painter.drawPixmap(QtCore.QPoint(*origin), pix)
painter.end()
offset = ( (self.width() - self._bar.width()) // 2,
(self.height() - self._bar.height()) // 2 )
self._bar.render(self, QPoint(*offset), self._bar.visibleRegion(), QWidget.DrawChildren)
self._bar.render(self, QtCore.QPoint(*offset), self._bar.visibleRegion(), QtWidgets.QWidget.DrawChildren)
def showEvent(self, event):
@@ -880,7 +870,7 @@ class PyQt5CountdownMessage(QFrame):
class PyQt5PoseMessage(QFrame):
class PyQt5PoseMessage(QtWidgets.QFrame):
def __init__(self):
@@ -896,19 +886,19 @@ class PyQt5PoseMessage(QFrame):
def paintEvent(self, event):
painter = QPainter(self)
painter = QtGui.QPainter(self)
f = self.font()
f.setPixelSize(self.height() / 3)
painter.setFont(f)
painter.drawText(event.rect(), Qt.AlignCenter, 'Pose!')
painter.drawText(event.rect(), QtCore.Qt.AlignCenter, 'Pose!')
painter.end()
class PyQt5PictureMessage(QFrame):
class PyQt5PictureMessage(QtWidgets.QFrame):
def __init__(self, picture):
@@ -926,17 +916,17 @@ class PyQt5PictureMessage(QFrame):
def paintEvent(self, event):
painter = QPainter(self)
painter = QtGui.QPainter(self)
if isinstance(self._picture, QImage):
pix = QPixmap.fromImage(self._picture)
if isinstance(self._picture, QtGui.QImage):
pix = QtGui.QPixmap.fromImage(self._picture)
else:
pix = QPixmap(self._picture)
pix = pix.scaled(self.rect().size(), Qt.KeepAspectRatio, Qt.SmoothTransformation)
pix = QtGui.QPixmap(self._picture)
pix = pix.scaled(self.rect().size(), QtCore.Qt.KeepAspectRatio, QtCore.Qt.SmoothTransformation)
origin = ( (self.rect().width() - pix.width()) // 2,
(self.rect().height() - pix.height()) // 2 )
painter.drawPixmap(QPoint(*origin), pix)
painter.drawPixmap(QtCore.QPoint(*origin), pix)
painter.end()

View File

@@ -10,6 +10,7 @@ from math import ceil
from PyQt5 import QtCore, QtGui, Qt, QtWidgets
class QRoundProgressBar(QtWidgets.QWidget):
StyleDonut = 1
@@ -33,7 +34,7 @@ class QRoundProgressBar(QtWidgets.QWidget):
self.nullPosition = self.PositionTop
self.barStyle = self.StyleDonut
self.outlinePenWidth =1
self.outlinePenWidth = 1
self.dataPenWidth = 1
self.rebuildBrush = False
self.format = "%p%"
@@ -124,7 +125,8 @@ class QRoundProgressBar(QtWidgets.QWidget):
outerRadius = min(self.width(), self.height())
baseRect = QtCore.QRectF(1, 1, outerRadius-2, outerRadius-2)
buffer = QtGui.QImage(outerRadius, outerRadius, QtGui.QImage.Format_ARGB32)
buffer = QtGui.QImage(outerRadius, outerRadius,
QtGui.QImage.Format_ARGB32)
buffer.fill(0)
p = QtGui.QPainter(buffer)
@@ -162,11 +164,13 @@ class QRoundProgressBar(QtWidgets.QWidget):
def drawBase(self, p, baseRect):
bs = self.barStyle
if bs == self.StyleDonut:
p.setPen(QtGui.QPen(self.palette().shadow().color(), self.outlinePenWidth))
p.setPen(QtGui.QPen(self.palette().shadow().color(),
self.outlinePenWidth))
p.setBrush(self.palette().base())
p.drawEllipse(baseRect)
elif bs == self.StylePie:
p.setPen(QtGui.QPen(self.palette().base().color(), self.outlinePenWidth))
p.setPen(QtGui.QPen(self.palette().base().color(),
self.outlinePenWidth))
p.setBrush(self.palette().base())
p.drawEllipse(baseRect)
elif bs == self.StyleLine:
@@ -174,13 +178,17 @@ class QRoundProgressBar(QtWidgets.QWidget):
color.setAlpha(100)
brush = self.palette().base()
brush.setColor(color)
p.setPen(QtGui.QPen(self.palette().base().color(), self.outlinePenWidth))
p.setPen(QtGui.QPen(self.palette().base().color(),
self.outlinePenWidth))
p.setBrush(brush)
# p.drawEllipse(baseRect)
# p.setPen(QtGui.QPen(self.palette().base().color(), self.outlinePenWidth))
# p.setPen(QtGui.QPen(self.palette().base().color(),
# self.outlinePenWidth))
# p.setBrush(Qt.Qt.NoBrush)
p.drawEllipse(baseRect.adjusted(self.outlinePenWidth/2, self.outlinePenWidth/2, -self.outlinePenWidth/2, -self.outlinePenWidth/2))
p.drawEllipse(baseRect.adjusted(self.outlinePenWidth/2,
self.outlinePenWidth/2,
-self.outlinePenWidth/2,
-self.outlinePenWidth/2))
def drawValue(self, p, baseRect, value, arcLength):
# nothing to draw
@@ -189,9 +197,13 @@ class QRoundProgressBar(QtWidgets.QWidget):
# for Line style
if self.barStyle == self.StyleLine:
p.setPen(QtGui.QPen(self.palette().highlight().color(), self.dataPenWidth))
p.setPen(QtGui.QPen(self.palette().highlight().color(),
self.dataPenWidth))
p.setBrush(Qt.Qt.NoBrush)
p.drawArc(baseRect.adjusted(self.outlinePenWidth/2, self.outlinePenWidth/2, -self.outlinePenWidth/2, -self.outlinePenWidth/2),
p.drawArc(baseRect.adjusted(self.outlinePenWidth/2,
self.outlinePenWidth/2,
-self.outlinePenWidth/2,
-self.outlinePenWidth/2),
self.nullPosition * 16,
-arcLength * 16)
return
@@ -206,7 +218,8 @@ class QRoundProgressBar(QtWidgets.QWidget):
dataPath.lineTo(baseRect.center())
p.setBrush(self.palette().highlight())
p.setPen(QtGui.QPen(self.palette().shadow().color(), self.dataPenWidth))
p.setPen(QtGui.QPen(self.palette().shadow().color(),
self.dataPenWidth))
p.drawPath(dataPath)
def calculateInnerRect(self, baseRect, outerRadius):
@@ -239,8 +252,6 @@ class QRoundProgressBar(QtWidgets.QWidget):
# !!! to revise
f = self.font()
# f.setPixelSize(innerRadius * max(0.05, (0.35 - self.decimals * 0.08)))
# f.setPixelSize(innerRadius * 1.8 / len(text))
f.setPixelSize(innerRadius * 0.8 / len(text))
p.setFont(f)
@@ -257,8 +268,8 @@ class QRoundProgressBar(QtWidgets.QWidget):
textToDraw = textToDraw.replace("%v", format_string.format(value))
if self.updateFlags & self.UF_PERCENT:
percent = (value - self.min) / (self.max - self.min) * 100.0
textToDraw = textToDraw.replace("%p", format_string.format(percent))
perc = (value - self.min) / (self.max - self.min) * 100.0
textToDraw = textToDraw.replace("%p", format_string.format(perc))
if self.updateFlags & self.UF_MAX:
m = self.max - self.min + 1
@@ -267,7 +278,7 @@ class QRoundProgressBar(QtWidgets.QWidget):
return textToDraw
def valueFormatChanged(self):
self.updateFlags = 0;
self.updateFlags = 0
if "%v" in self.format:
self.updateFlags |= self.UF_VALUE
@@ -285,7 +296,7 @@ class QRoundProgressBar(QtWidgets.QWidget):
self.rebuildBrush = False
dataBrush = QtGui.QConicalGradient()
dataBrush.setCenter(0.5,0.5)
dataBrush.setCenter(0.5, 0.5)
dataBrush.setCoordinateMode(QtGui.QGradient.StretchToDeviceMode)
for pos, color in self.gradientData:
@@ -296,4 +307,4 @@ class QRoundProgressBar(QtWidgets.QWidget):
p = self.palette()
p.setBrush(QtGui.QPalette.Highlight, dataBrush)
self.setPalette(p)
self.setPalette(p)

View File

@@ -1,13 +1,11 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
from .GuiState import *
from .GuiPostprocess import *
from .GuiState import * # noqa
from .GuiPostprocess import * # noqa
# Available gui modules as tuples of (config name, module name, class name)
modules = ( ('qt5', 'PyQt5Gui', 'PyQt5Gui'), )
modules = (('qt5', 'PyQt5Gui', 'PyQt5Gui'), )
class Gui:
@@ -16,9 +14,6 @@ class Gui:
pass
def run(self, camera_conn, worker_queue):
raise NotImplementedError()

View File

@@ -7,9 +7,10 @@ try:
except DistributionNotFound:
__version__ = 'unknown'
import sys
import logging
import logging.handlers
import multiprocessing as mp
import logging, logging.handlers
import sys
from . import camera, gui
from .Config import Config
@@ -17,6 +18,7 @@ from .Photobooth import Photobooth
from .util import lookup_and_import
from .Worker import Worker
class CameraProcess(mp.Process):
def __init__(self, config, conn, worker_queue):
@@ -28,7 +30,6 @@ class CameraProcess(mp.Process):
self.conn = conn
self.worker_queue = worker_queue
def run_camera(self):
try:
@@ -40,7 +41,7 @@ class CameraProcess(mp.Process):
return photobooth.run()
except BaseException as e:
self.conn.send( gui.ErrorState('Camera error', str(e)) )
self.conn.send(gui.ErrorState('Camera error', str(e)))
event = self.conn.recv()
if str(event) in ('cancel', 'ack'):
return 123
@@ -48,7 +49,6 @@ class CameraProcess(mp.Process):
logging.error('Unknown event received: %s', str(event))
raise RuntimeError('Unknown event received', str(event))
def run(self):
status_code = 123
@@ -76,7 +76,6 @@ class WorkerProcess(mp.Process):
self.cfg = config
self.queue = queue
def run(self):
sys.exit(Worker(self.cfg, self.queue).run())
@@ -93,10 +92,10 @@ class GuiProcess(mp.Process):
self.conn = conn
self.queue = queue
def run(self):
Gui = lookup_and_import(gui.modules, self.cfg.get('Gui', 'module'), 'gui')
Gui = lookup_and_import(gui.modules, self.cfg.get('Gui', 'module'),
'gui')
sys.exit(Gui(self.argv, self.cfg).run(self.conn, self.queue))
@@ -107,7 +106,7 @@ def run(argv):
# Load configuration
config = Config('photobooth.cfg')
# Create communication objects:
# Create communication objects:
# 1. We use a pipe to connect GUI and camera process
# 2. We use a queue to feed tasks to the postprocessing process
gui_conn, camera_conn = mp.Pipe()
@@ -129,7 +128,7 @@ def run(argv):
# Close endpoints
gui_conn.close()
camera_conn.close()
# Wait for processes to finish
gui_proc.join()
worker_queue.put('teardown')
@@ -150,12 +149,12 @@ def main(argv):
ch.setFormatter(formatter)
# create file handler and set format
fh = logging.handlers.TimedRotatingFileHandler('photobooth.log',
when='d', interval=1, backupCount=10)
fh = logging.handlers.TimedRotatingFileHandler('photobooth.log', when='d',
interval=1, backupCount=10)
fh.setFormatter(formatter)
# Apply config
logging.basicConfig(level=log_level, handlers=(ch,fh))
logging.basicConfig(level=log_level, handlers=(ch, fh))
# Set of known status codes which trigger a restart of the application
known_status_codes = {

View File

@@ -5,12 +5,12 @@ import logging
from PIL import ImageQt
from PyQt5.QtCore import Qt, QPoint, QSizeF
from PyQt5.QtGui import QPageSize, QPainter, QPixmap
from PyQt5 import QtCore, QtGui
from PyQt5.QtPrintSupport import QPrinter
from . import Printer
class PrinterPyQt5(Printer):
def __init__(self, page_size, print_pdf=False):
@@ -18,7 +18,8 @@ class PrinterPyQt5(Printer):
super().__init__(page_size)
self._printer = QPrinter(QPrinter.HighResolution)
self._printer.setPageSize(QPageSize(QSizeF(*page_size), QPageSize.Millimeter))
self._printer.setPageSize(QtGui.QPageSize(QtCore.QSizeF(*page_size),
QtGui.QPageSize.Millimeter))
self._printer.setColorMode(QPrinter.Color)
logging.info('Using printer "%s"', self._printer.printerName())
@@ -30,21 +31,21 @@ class PrinterPyQt5(Printer):
self._printer.setOutputFormat(QPrinter.PdfFormat)
self._printer.setFullPage(True)
def print(self, picture):
if self._print_pdf:
self._printer.setOutputFileName('print_' + str(self._counter) + '.pdf')
self._printer.setOutputFileName('print_%d.pdf' % self._counter)
self._counter += 1
img = ImageQt.ImageQt(picture)
img = img.scaled(self._printer.pageRect().size(), Qt.KeepAspectRatio,
Qt.SmoothTransformation)
img = img.scaled(self._printer.pageRect().size(),
QtCore.Qt.KeepAspectRatio,
QtCore.Qt.SmoothTransformation)
printable_size = self._printer.pageRect(QPrinter.DevicePixel)
origin = ( (printable_size.width() - img.width()) // 2,
(printable_size.height() - img.height()) // 2 )
painter = QPainter(self._printer)
painter.drawImage(QPoint(*origin), img)
origin = ((printable_size.width() - img.width()) // 2,
(printable_size.height() - img.height()) // 2)
painter = QtGui.QPainter(self._printer)
painter.drawImage(QtCore.QPoint(*origin), img)
painter.end()

View File

@@ -13,13 +13,11 @@ class Printer:
self.pageSize = page_size
@property
def pageSize(self):
return self._page_size
@pageSize.setter
def pageSize(self, page_size):
@@ -28,8 +26,6 @@ class Printer:
self._page_size = page_size
def print(self, picture):
raise NotImplementedError('print function not implemented!')

View File

@@ -1,23 +1,22 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import importlib
def lookup_and_import(module_list, name, package=None):
result = next(((mod_name, class_name)
for config_name, mod_name, class_name in module_list
if name == config_name), None)
if package == None:
result = next(((mod_name, class_name)
for config_name, mod_name, class_name in module_list
if name == config_name), None)
if package is None:
import_module = importlib.import_module('photobooth.' + result[0])
else:
import_module = importlib.import_module(
'photobooth.' + package + '.' + result[0])
if result[1] == None:
if result[1] is None:
return import_module
else:
return getattr(import_module, result[1])