Countdown prettier

This commit is contained in:
Balthasar Reuter
2018-05-10 23:23:04 +02:00
parent e13ccc5eb5
commit ee1518086a
2 changed files with 340 additions and 8 deletions

View File

@@ -4,18 +4,21 @@
from PIL import ImageQt
from PyQt5.QtCore import Qt, QObject, QPoint, QThread, QTimer, pyqtSignal
from PyQt5.QtWidgets import (QApplication, QCheckBox, QComboBox, QFormLayout, QFrame, QGridLayout, QGroupBox, QHBoxLayout, QLabel, QLayout, QLineEdit, QMainWindow, QMessageBox, QPushButton, QVBoxLayout)
from PyQt5.QtWidgets import (QApplication, QCheckBox, QComboBox, QFormLayout, QFrame, QGridLayout, QGroupBox, QHBoxLayout, QLabel, QLayout, QLineEdit, QMainWindow, QMessageBox, QPushButton, QVBoxLayout, QWidget)
from PyQt5.QtGui import QImage, QPainter, QPixmap
import math
from PyQt5.QtGui import QBrush, QPen, QColor
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):
def __init__(self, argv, config):
@@ -649,17 +652,20 @@ class PyQt5WaitMessage(QFrame):
self.update()
class PyQt5CountdownMessage(QFrame):
def __init__(self, time, action):
super().__init__()
self._counter = time
self._step_size = 100
self._counter = time * (1000 // self._step_size)
self._action = action
self._picture = None
self.initFrame()
self.initProgressBar(time)
def initFrame(self):
@@ -667,6 +673,27 @@ class PyQt5CountdownMessage(QFrame):
self.setStyleSheet('background-color: white;')
def initProgressBar(self, time):
self._bar = QRoundProgressBar()
self._bar.setBarStyle(QRoundProgressBar.StyleLine)
self._bar.setFixedSize(200, 200)
self._bar.setDataPenWidth(7)
self._bar.setOutlinePenWidth(10)
self._bar.setDecimals(0)
self._bar.setFormat('%v')
self._bar.setRange(0, time)
self._bar.setValue(time)
def updateProgressBar(self):
self._bar.setValue(self._counter / (1000 // self._step_size))
@property
def counter(self):
@@ -694,28 +721,34 @@ class PyQt5CountdownMessage(QFrame):
if self._picture != None:
pix = QPixmap.fromImage(self._picture)
pix = pix.scaled(self.rect().size(), Qt.KeepAspectRatio, Qt.FastTransformation)
origin = ( (self.rect().width() - pix.width()) // 2,
(self.rect().height() - pix.height()) // 2 )
pix = pix.scaled(self.size(), Qt.KeepAspectRatio, Qt.FastTransformation)
origin = ( (self.width() - pix.width()) // 2,
(self.height() - pix.height()) // 2 )
painter.drawPixmap(QPoint(*origin), pix)
painter.drawText(event.rect(), Qt.AlignCenter, str(self.counter))
# painter.drawText(event.rect(), Qt.AlignCenter, str(self.counter))
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)
def showEvent(self, event):
self._timer = self.startTimer(1000)
self._timer = self.startTimer(self._step_size)
def timerEvent(self, event):
self._counter -= 1
self.update()
if self._counter == 0:
self.killTimer(self._timer)
self._action()
else:
self.updateProgressBar()
self.update()
class PyQt5PictureMessage(QFrame):

View File

@@ -0,0 +1,299 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# Adaptation of QRoundProgressBar from
# https://sourceforge.net/projects/qroundprogressbar/
# to PyQt5, using the PyQt4-version offered at
# https://stackoverflow.com/a/33583019
from math import ceil
from PyQt5 import QtCore, QtGui, Qt, QtWidgets
class QRoundProgressBar(QtWidgets.QWidget):
StyleDonut = 1
StylePie = 2
StyleLine = 3
PositionLeft = 180
PositionTop = 90
PositionRight = 0
PositionBottom = -90
UF_VALUE = 1
UF_PERCENT = 2
UF_MAX = 4
def __init__(self):
super().__init__()
self.min = 0
self.max = 100
self.value = 25
self.nullPosition = self.PositionTop
self.barStyle = self.StyleDonut
self.outlinePenWidth =1
self.dataPenWidth = 1
self.rebuildBrush = False
self.format = "%p%"
self.decimals = 1
self.updateFlags = self.UF_PERCENT
self.gradientData = []
self.donutThicknessRatio = 0.75
def setRange(self, min, max):
self.min = min
self.max = max
if self.max < self.min:
self.max, self.min = self.min, self.max
if self.value < self.min:
self.value = self.min
elif self.value > self.max:
self.value = self.max
if not self.gradientData:
self.rebuildBrush = True
self.update()
def setMinimum(self, min):
self.setRange(min, self.max)
def setMaximum(self, max):
self.setRange(self.min, max)
def setValue(self, val):
if self.value != val:
if val < self.min:
self.value = self.min
elif val > self.max:
self.value = self.max
else:
self.value = val
self.update()
def setNullPosition(self, position):
if position != self.nullPosition:
self.nullPosition = position
if not self.gradientData:
self.rebuildBrush = True
self.update()
def setBarStyle(self, style):
if style != self.barStyle:
self.barStyle = style
self.update()
def setOutlinePenWidth(self, penWidth):
if penWidth != self.outlinePenWidth:
self.outlinePenWidth = penWidth
self.update()
def setDataPenWidth(self, penWidth):
if penWidth != self.dataPenWidth:
self.dataPenWidth = penWidth
self.update()
def setDataColors(self, stopPoints):
if stopPoints != self.gradientData:
self.gradientData = stopPoints
self.rebuildBrush = True
self.update()
def setFormat(self, format):
if format != self.format:
self.format = format
self.valueFormatChanged()
def resetFormat(self):
self.format = ''
self.valueFormatChanged()
def setDecimals(self, count):
if count >= 0 and count != self.decimals:
self.decimals = count
self.valueFormatChanged()
def setDonutThicknessRatio(self, val):
self.donutThicknessRatio = max(0., min(val, 1.))
self.update()
def paintEvent(self, event):
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.fill(0)
p = QtGui.QPainter(buffer)
p.setRenderHint(QtGui.QPainter.Antialiasing)
# data brush
self.rebuildDataBrushIfNeeded()
# background
# self.drawBackground(p, buffer.rect())
# base circle
self.drawBase(p, baseRect)
# data circle
arcStep = 360.0 / (self.max - self.min) * self.value
self.drawValue(p, baseRect, self.value, arcStep)
# center circle
innerRect, innerRadius = self.calculateInnerRect(baseRect, outerRadius)
self.drawInnerBackground(p, innerRect)
# text
self.drawText(p, innerRect, innerRadius, ceil(self.value))
# finally draw the bar
p.end()
painter = QtGui.QPainter(self)
painter.drawImage(0, 0, buffer)
def drawBackground(self, p, baseRect):
p.fillRect(baseRect, self.palette().window())
def drawBase(self, p, baseRect):
bs = self.barStyle
if bs == self.StyleDonut:
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.setBrush(self.palette().base())
p.drawEllipse(baseRect)
elif bs == self.StyleLine:
color = self.palette().base().color()
color.setAlpha(100)
brush = self.palette().base()
brush.setColor(color)
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.setBrush(Qt.Qt.NoBrush)
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
if value == self.min:
return
# for Line style
if self.barStyle == self.StyleLine:
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),
self.nullPosition * 16,
-arcLength * 16)
return
# for Pie and Donut styles
dataPath = QtGui.QPainterPath()
dataPath.setFillRule(Qt.Qt.WindingFill)
# pie segment outer
dataPath.moveTo(baseRect.center())
dataPath.arcTo(baseRect, self.nullPosition, -arcLength)
dataPath.lineTo(baseRect.center())
p.setBrush(self.palette().highlight())
p.setPen(QtGui.QPen(self.palette().shadow().color(), self.dataPenWidth))
p.drawPath(dataPath)
def calculateInnerRect(self, baseRect, outerRadius):
# for Line style
if self.barStyle == self.StyleLine:
innerRadius = outerRadius - self.outlinePenWidth
else: # for Pie and Donut styles
innerRadius = outerRadius * self.donutThicknessRatio
delta = (outerRadius - innerRadius) / 2.
innerRect = QtCore.QRectF(delta, delta, innerRadius, innerRadius)
return innerRect, innerRadius
def drawInnerBackground(self, p, innerRect):
if self.barStyle == self.StyleDonut:
p.setBrush(self.palette().alternateBase())
cmod = p.compositionMode()
p.setCompositionMode(QtGui.QPainter.CompositionMode_Source)
p.drawEllipse(innerRect)
p.setCompositionMode(cmod)
def drawText(self, p, innerRect, innerRadius, value):
if not self.format:
return
text = self.valueToText(value)
# !!! 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)
textRect = innerRect
p.setPen(self.palette().text().color())
p.drawText(textRect, Qt.Qt.AlignCenter, text)
def valueToText(self, value):
textToDraw = self.format
format_string = '{' + ':.{}f'.format(self.decimals) + '}'
if self.updateFlags & self.UF_VALUE:
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))
if self.updateFlags & self.UF_MAX:
m = self.max - self.min + 1
textToDraw = textToDraw.replace("%m", format_string.format(m))
return textToDraw
def valueFormatChanged(self):
self.updateFlags = 0;
if "%v" in self.format:
self.updateFlags |= self.UF_VALUE
if "%p" in self.format:
self.updateFlags |= self.UF_PERCENT
if "%m" in self.format:
self.updateFlags |= self.UF_MAX
self.update()
def rebuildDataBrushIfNeeded(self):
if self.rebuildBrush:
self.rebuildBrush = False
dataBrush = QtGui.QConicalGradient()
dataBrush.setCenter(0.5,0.5)
dataBrush.setCoordinateMode(QtGui.QGradient.StretchToDeviceMode)
for pos, color in self.gradientData:
dataBrush.setColorAt(1.0 - pos, color)
# angle
dataBrush.setAngle(self.nullPosition)
p = self.palette()
p.setBrush(QtGui.QPalette.Highlight, dataBrush)
self.setPalette(p)