Skip to content

Instantly share code, notes, and snippets.

@hhsprings
Last active March 18, 2022 09:06
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save hhsprings/bc2a181ce30824661760d6b709dd608d to your computer and use it in GitHub Desktop.
Save hhsprings/bc2a181ce30824661760d6b709dd608d to your computer and use it in GitHub Desktop.
Something like a kitchen timer (intended for a tkinter demo)
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
import sys
import re
import time
import operator
import functools
try:
import tkinter
from tkinter.simpledialog import Dialog
except ImportError:
import Tkinter as tkinter # python 2.x, but sorry, I'm not testing it.
from tkSimpleDialog import Dialog
try:
import idlelib # for ToolTip, etc.
try:
from idlelib.tooltip import Hovertip
except ImportError:
from idlelib.ToolTip import ToolTip as Hovertip
except ImportError:
def Hovertip(*args): pass
def _split_by_units(src, factors=(24, 60, 60), first_prod=True):
result = []
f = functools.reduce(operator.mul, factors)
d = abs(src) * (f if first_prod else 1.0)
for fi in factors:
d, m = divmod(d, f)
result.append(d)
d = m
f /= fi
result.append(m)
return result
class OkCancelTimeout(Dialog):
def __init__(self, parent, title, elapse, timeout_is_cancel):
self._title = title
self._arrivetime = time.time() + elapse
self._pausedtime = None
self._timeout_is_cancel = timeout_is_cancel
self.excode = 1 # for sys.exit(1)
Dialog.__init__(self, parent, "settings")
def _fmtresttime(self, now):
secs = int(now - self._arrivetime)
r = _split_by_units(secs, first_prod=False)
r = [(int(r[i]), u) for i, u in enumerate(("d", "h", "m", "s"))]
return " ".join(["{}{}".format(v, u) for v, u in r if v])
def body(self, master):
font = ["courier", 16, "normal"]
self._master = master
fr = tkinter.Frame(master)
tit = tkinter.Label(fr, text=self._title, font=font)
tit.pack()
self._cdtxt = tkinter.StringVar()
self._cdtxt.set(self._fmtresttime(time.time()))
cdt = tkinter.Entry(fr, textvariable=self._cdtxt, font=font, state="readonly")
cdt.pack()
fr.pack()
if Hovertip is not None:
Hovertip(fr, "try ^p, Up/Dn, and PgUp/PgDn to modify elapse")
cdt.bind("<Control-p>", self._toggle_pause_timer)
cdt.bind("<Up>", functools.partial(self._adv_arrivetime, 1))
cdt.bind("<Control-Up>", functools.partial(self._adv_arrivetime, 15))
cdt.bind("<Alt-Up>", functools.partial(self._adv_arrivetime, 60))
cdt.bind("<Prior>", functools.partial(self._adv_arrivetime, 15*60))
cdt.bind("<Control-Prior>", functools.partial(self._adv_arrivetime, 30*60))
cdt.bind("<Alt-Prior>", functools.partial(self._adv_arrivetime, 60*60))
cdt.bind("<Down>", functools.partial(self._adv_arrivetime, -1))
cdt.bind("<Control-Down>", functools.partial(self._adv_arrivetime, -15))
cdt.bind("<Alt-Down>", functools.partial(self._adv_arrivetime, -60))
cdt.bind("<Next>", functools.partial(self._adv_arrivetime, -15*60))
cdt.bind("<Control-Next>", functools.partial(self._adv_arrivetime, -30*60))
cdt.bind("<Alt-Next>", functools.partial(self._adv_arrivetime, -60*60))
self._master.after(100, self._timerfun)
return cdt
def _timerfun(self, *args):
if self._pausedtime:
return
now = time.time()
self._cdtxt.set(self._fmtresttime(now))
if now < self._arrivetime:
self._master.after(100, self._timerfun)
else:
if not self._timeout_is_cancel:
self.ok()
else:
self.cancel()
def _toggle_pause_timer(self, *args):
if not self._pausedtime:
self._pausedtime = time.time()
else:
self._arrivetime += (time.time() - self._pausedtime)
self._pausedtime = None
self._master.after(100, self._timerfun)
def _adv_arrivetime(self, *args):
self._arrivetime += args[0]
def apply(self):
self.excode = 0
if __name__ == '__main__':
import argparse
ap = argparse.ArgumentParser()
ap.add_argument(
"elapse", nargs="?",
default="3m",
help="NUMBER[SUFFIX]: SUFFIX may be `s' for seconds (the default), \
`m' for minutes, `h' for hours or `d' for days. Unlike most implementations \
that require NUMBER be an integer, here NUMBER may be an arbitrary floating \
point number.")
ap.add_argument("--title", default="Please wait...")
ap.add_argument(
"--timeout_is_cancel", action="store_true")
args = ap.parse_args()
elapse = args.elapse.strip()
m = re.match(r"^([\d.eE+-]+)([smhd]){0,1}$", elapse)
if not m:
ap.error("invalid elapse")
v = float(m.group(1))
s = m.group(2)
elapse = (v * {"m": 60, "h": 60*60, "d": 60*60*24, "s": 1, None: 1}[s])
root = tkinter.Tk()
root.withdraw()
dlg = OkCancelTimeout(root, args.title, elapse, args.timeout_is_cancel)
sys.exit(dlg.excode)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment