#!/usr/bin/env python
import sys
from PySide6.QtCore import *
from PySide6.QtGui import *
from PySide6.QtWidgets import *
from PySide6.QtNetwork import *
import time
from threading import Thread
from datetime import datetime
def parse_time(x):
a = x.split(":")
if len(a) < 2 or len(a) > 3:
raise ValueError("Time should be in the format hh:mm or hh:mm:ss")
if len(a) == 2:
h,m = map(int,a)
s = 0
else:
h,m,s = map(int,a)
return (h,m,s)
def fmtime(x):
h,s = divmod(x,3600)
m,s = divmod(s,60)
return f"{h:02d}:{m:02d}:{s:02d}"
def clamp(x,a,b):
return max(min(x,b),a)
class Countdown(QWidget):
def handleUdp(self):
app.quit()
def __init__(self,t0):
super().__init__()
# so we can kill via sending UDP to 2000, e.g.
# echo hello | nc -u -w1 localhost 2000
self.udpSocket = QUdpSocket()
self.udpSocket.readyRead.connect(self.handleUdp)
try:
if not self.udpSocket.bind(QHostAddress.Any,2000):
raise Exception("Address bind failed")
except Exception:
print(f"Failed to bind UDP port 2000")
exit(1)
app.quit()
m = 100
self.t0 = t0
scr = QGuiApplication.primaryScreen()
geom = scr.geometry()
sh = geom.height()
sw = geom.width()
x = m
y = m
w = sw-2*m
h = sh-2*m
self.w = w
self.h = h
# size and position – possibly necessary to recompute, resize and move depending on hud contents
self.resize(w,h)
self.move(x,y)
#self.resize(600,600)
# attributes for display
self.fontname = "Optima"
self.fontsize = 200
self.font = QFont(self.fontname,self.fontsize)
self.color = QColor(100,255,100)
self.ocolor = Qt.black
self.pen = QPen(self.ocolor,16)
self.content = "Countdown"
# window attributes
self.setWindowFlags(self.windowFlags() | Qt.FramelessWindowHint | Qt.WindowStaysOnTopHint)
self.setAttribute(Qt.WA_TranslucentBackground)
self.n = 60
self.timer = QTimer(self)
self.timer.setInterval(1000)
self.timer.timeout.connect(self.ping)
self.ping()
def go(self):
self.show()
self.timer.start()
def ping(self):
t = int(datetime.now().timestamp())
dt = self.t0 - t
if dt < 0:
app.quit()
self.content = fmtime(dt)
self.update()
def paintEvent(self,event):
with QPainter(self) as p:
text = self.content
metrics = QFontMetrics(self.font)
tw = metrics.horizontalAdvance(text)
x = (self.w-tw)/2
h = metrics.height()
sh = self.h
dh = (sh-h)/2
y = dh+h
path = QPainterPath()
path.addText(x,y,self.font,str(text))
# draw twice so that the black outline is _behind_ the fill
p.setPen(self.pen)
p.drawPath(path)
p.setBrush(self.color)
p.setPen(Qt.NoPen)
p.drawPath(path)
def mousePressEvent(self,e):
self.hide()
super().mousePressEvent(e)
def finish(self):
app.quit()
def compute_secs_until(x):
h,m,s = parse_time(x)
now = datetime.now()
h1 = now.hour
m1 = now.minute
s1 = now.second
secs = 3600*h+60*m+s
secs1 = 3600*h1+60*m1+s1
dt = secs - secs1
if dt < 0:
dt += 24*3600
return dt
args = sys.argv[1:]
if len(args) == 0:
print(f"sleepyqt target-time(h:m:s)")
exit(1)
dt = compute_secs_until(args[0])
t = int(datetime.now().timestamp())
t0 = t+dt
app = QApplication([])
win = Countdown(t0)
win.go()
exit(app.exec())