| #! /usr/bin/env python | 
 |  | 
 | # 'clock' -- A simple alarm clock | 
 |  | 
 | # The alarm can be set at 5 minute intervals on a 12 hour basis. | 
 | # It is controlled with the mouse: | 
 | # - Click and drag around the circle to set the alarm. | 
 | # - Click far outside the circle to clear the alarm. | 
 | # - Click near the center to set the alarm at the last time set. | 
 | # The alarm time is indicated by a small triangle just outside the circle, | 
 | # and also by a digital time at the bottom. | 
 | # The indicators disappear when the alarm is not set. | 
 | # When the alarm goes off, it beeps every minute for five minutes, | 
 | # and the clock turns into inverse video. | 
 | # Click or activate the window to turn the ringing off. | 
 |  | 
 | import stdwin | 
 | from stdwinevents import WE_MOUSE_DOWN, WE_MOUSE_MOVE, WE_MOUSE_UP, \ | 
 | 	WE_TIMER, WE_DRAW, WE_SIZE, WE_CLOSE, WE_ACTIVATE | 
 | import mainloop | 
 | import time | 
 | from math import sin, cos, atan2, pi, sqrt | 
 |  | 
 | DEFWIDTH, DEFHEIGHT = 200, 200 | 
 |  | 
 | MOUSE_EVENTS = (WE_MOUSE_DOWN, WE_MOUSE_MOVE, WE_MOUSE_UP) | 
 | ORIGIN = 0, 0 | 
 | FARAWAY = 2000, 2000 | 
 | EVERYWHERE = ORIGIN, FARAWAY | 
 |  | 
 |  | 
 | def main(): | 
 | 	win = makewindow() | 
 | 	del win | 
 | 	mainloop.mainloop() | 
 |  | 
 | def makewindow(): | 
 | 	stdwin.setdefwinsize(DEFWIDTH, DEFHEIGHT + stdwin.lineheight()) | 
 | 	win = stdwin.open('clock') | 
 | 	setdimensions(win) | 
 | 	win.set = 1		# True when alarm is set | 
 | 	win.time = 11*60 + 40	# Time when alarm must go off | 
 | 	win.ring = 0		# True when alarm is ringing | 
 | 	win.dispatch = cdispatch | 
 | 	mainloop.register(win) | 
 | 	settimer(win) | 
 | 	return win | 
 |  | 
 | def cdispatch(event): | 
 | 	type, win, detail = event | 
 | 	if type == WE_DRAW: | 
 | 		drawproc(win, detail) | 
 | 	elif type == WE_TIMER: | 
 | 		settimer(win) | 
 | 		drawproc(win, EVERYWHERE) | 
 | 	elif type in MOUSE_EVENTS: | 
 | 		mouseclick(win, type, detail) | 
 | 	elif type == WE_ACTIVATE: | 
 | 		if win.ring: | 
 | 			# Turn the ringing off | 
 | 			win.ring = 0 | 
 | 			win.begindrawing().invert(win.mainarea) | 
 | 	elif type == WE_SIZE: | 
 | 		win.change(EVERYWHERE) | 
 | 		setdimensions(win) | 
 | 	elif type == WE_CLOSE: | 
 | 		mainloop.unregister(win) | 
 | 		win.close() | 
 |  | 
 | def setdimensions(win): | 
 | 	width, height = win.getwinsize() | 
 | 	height = height - stdwin.lineheight() | 
 | 	if width < height: size = width | 
 | 	else: size = height | 
 | 	halfwidth = width/2 | 
 | 	halfheight = height/2 | 
 | 	win.center = halfwidth, halfheight | 
 | 	win.radius = size*45/100 | 
 | 	win.width = width | 
 | 	win.height = height | 
 | 	win.corner = width, height | 
 | 	win.mainarea = ORIGIN, win.corner | 
 | 	win.lineheight = stdwin.lineheight() | 
 | 	win.farcorner = width, height + win.lineheight | 
 | 	win.statusarea = (0, height), win.farcorner | 
 | 	win.fullarea = ORIGIN, win.farcorner | 
 |  | 
 | def settimer(win): | 
 | 	now = time.time() | 
 | 	hours, minutes, seconds = win.times = calctime(now) | 
 | 	delay = 61 - seconds | 
 | 	win.settimer(10 * delay) | 
 | 	minutes = minutes + hours*60 | 
 | 	if win.ring: | 
 | 		# Is it time to stop the alarm ringing? | 
 | 		since = (minutes - win.time + 720) % 720 | 
 | 		if since >= 5: | 
 | 			# Stop it now | 
 | 			win.ring = 0 | 
 | 		else: | 
 | 			# Ring again, once every minute | 
 | 			stdwin.fleep() | 
 | 	elif win.set and minutes == win.time: | 
 | 		# Start the alarm ringing | 
 | 		win.ring = 1 | 
 | 		stdwin.fleep() | 
 |  | 
 | def drawproc(win, area): | 
 | 	hours, minutes, seconds = win.times | 
 | 	d = win.begindrawing() | 
 | 	d.cliprect(area) | 
 | 	d.erase(EVERYWHERE) | 
 | 	d.circle(win.center, win.radius) | 
 | 	d.line(win.center, calcpoint(win, hours*30 + minutes/2, 0.6)) | 
 | 	d.line(win.center, calcpoint(win, minutes*6, 1.0)) | 
 | 	str = "%02d:%02d" % (hours, minutes) | 
 | 	p = (win.width - d.textwidth(str))/2, win.height * 3 / 4 | 
 | 	d.text(p, str) | 
 | 	if win.set: | 
 | 		drawalarm(win, d) | 
 | 		drawalarmtime(win, d) | 
 | 	if win.ring: | 
 | 		d.invert(win.mainarea) | 
 |  | 
 | def mouseclick(win, type, detail): | 
 | 	d = win.begindrawing() | 
 | 	if win.ring: | 
 | 		# First turn the ringing off | 
 | 		win.ring = 0 | 
 | 		d.invert(win.mainarea) | 
 | 	h, v = detail[0] | 
 | 	ch, cv = win.center | 
 | 	x, y = h-ch, cv-v | 
 | 	dist = sqrt(x*x + y*y) / float(win.radius) | 
 | 	if dist > 1.2: | 
 | 		if win.set: | 
 | 			drawalarm(win, d) | 
 | 			erasealarmtime(win, d) | 
 | 			win.set = 0 | 
 | 	elif dist < 0.8: | 
 | 		if not win.set: | 
 | 			win.set = 1 | 
 | 			drawalarm(win, d) | 
 | 			drawalarmtime(win, d) | 
 | 	else: | 
 | 		# Convert to half-degrees (range 0..720) | 
 | 		alpha = atan2(y, x) | 
 | 		hdeg = alpha*360.0/pi | 
 | 		hdeg = 180.0 - hdeg | 
 | 		hdeg = (hdeg + 720.0) % 720.0 | 
 | 		atime = 5*int(hdeg/5.0 + 0.5) | 
 | 		if atime <> win.time or not win.set: | 
 | 			if win.set: | 
 | 				drawalarm(win, d) | 
 | 				erasealarmtime(win, d) | 
 | 			win.set = 1 | 
 | 			win.time = atime | 
 | 			drawalarm(win, d) | 
 | 			drawalarmtime(win, d) | 
 |  | 
 | def drawalarm(win, d): | 
 | 	p1 = calcpoint(win, float(win.time)/2.0, 1.02) | 
 | 	p2 = calcpoint(win, float(win.time)/2.0 - 4.0, 1.1) | 
 | 	p3 = calcpoint(win, float(win.time)/2.0 + 4.0, 1.1) | 
 | 	d.xorline(p1, p2) | 
 | 	d.xorline(p2, p3) | 
 | 	d.xorline(p3, p1) | 
 |  | 
 | def erasealarmtime(win, d): | 
 | 	d.erase(win.statusarea) | 
 |  | 
 | def drawalarmtime(win, d): | 
 | 	# win.time is in the range 0..720 with origin at 12 o'clock | 
 | 	# Convert to hours (0..12) and minutes (12*(0..60)) | 
 | 	hh = win.time/60 | 
 | 	mm = win.time%60 | 
 | 	str = 'Alarm@%02d:%02d' % (hh, mm) | 
 | 	p1 = (win.width - d.textwidth(str))/2, win.height | 
 | 	d.text(p1, str) | 
 |  | 
 | def calcpoint(win, degrees, size): | 
 | 	alpha = pi/2.0 - float(degrees) * pi/180.0 | 
 | 	x, y = cos(alpha), sin(alpha) | 
 | 	h, v = win.center | 
 | 	r = float(win.radius) | 
 | 	return h + int(x*size*r), v - int(y*size*r) | 
 |  | 
 | def calctime(now): | 
 | 	hours, minutes, seconds = time.localtime(now)[3:6] | 
 | 	hours = hours % 12 | 
 | 	return hours, minutes, seconds | 
 |  | 
 | main() |