DigitalWatchGUI.py 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621
  1. #
  2. # DigitalWatchGUI.py
  3. #
  4. # class DigitalWatchGUI provides a simple Tkinter GUI for a Digital Watch
  5. # to add: battery dies ... DONE OCT 2008 by Reehan Shaikh reehan.shaikh@cs.mcgill.ca
  6. # Updated for the SCCDXML compiler and AToMPM formalism by Yentl Van Tendeloo
  7. from time import localtime
  8. from tkinter import Frame, PhotoImage, Canvas
  9. from tkinter.constants import BOTH
  10. CANVAS_W = 222
  11. CANVAS_H = 236
  12. OVAL_X0 = 2
  13. OVAL_Y0 = 1
  14. OVAL_X1 = CANVAS_W - OVAL_X0
  15. OVAL_Y1 = CANVAS_H - OVAL_Y0
  16. RECT_X0 = 51
  17. RECT_Y0 = 95
  18. RECT_X1 = CANVAS_W - RECT_X0 + 1
  19. RECT_Y1 = CANVAS_H - RECT_Y0 + 10
  20. FONT_TIME = ("terminal", 14)
  21. FONT_DATE = ("terminal", 8)
  22. FONT_NOTE = ("symbol", 10)
  23. class DigitalWatchGUI:
  24. def __init__(self, parent):
  25. self.controller = DigitalWatchGUI_Controller()
  26. self.staticGUI = DigitalWatchGUI_Static(parent, self.controller)
  27. class DigitalWatchGUI_Controller:
  28. def __init__(self):
  29. self.send_event = None
  30. self.GUI = None
  31. self.battery = True
  32. def bindStatic(self, GUI):
  33. self.GUI = GUI
  34. # Interface for the GUI
  35. def window_close(self):
  36. import sys
  37. sys.exit(0)
  38. self.send_event('GUIQuit')
  39. def topRightPressed(self):
  40. self.send_event('topRightPressed')
  41. def topRightReleased(self):
  42. self.send_event('topRightReleased')
  43. def topLeftPressed(self):
  44. self.send_event('topLeftPressed')
  45. def topLeftReleased(self):
  46. self.send_event('topLeftReleased')
  47. def bottomRightPressed(self):
  48. self.send_event('bottomRightPressed')
  49. def bottomRightReleased(self):
  50. self.send_event('bottomRightReleased')
  51. def bottomLeftPressed(self):
  52. self.send_event('bottomLeftPressed')
  53. def bottomLeftReleased(self):
  54. self.send_event('bottomLeftReleased')
  55. def alarm(self):
  56. self.send_event('alarmStart')
  57. # Interface for the statechart
  58. # synchronize the state with the display:
  59. def batteryHalf(self):
  60. self.battery = False
  61. self.GUI.battery = False
  62. self.refreshDateDisplay()
  63. def batteryFull(self):
  64. self.battery = True
  65. self.GUI.battery = True
  66. self.refreshDateDisplay()
  67. def refreshTimeDisplay(self):
  68. self.GUI.drawTime()
  69. def refreshChronoDisplay(self):
  70. self.GUI.drawChrono()
  71. def refreshDateDisplay(self):
  72. self.GUI.drawDate()
  73. def refreshAlarmDisplay(self):
  74. self.GUI.drawAlarm()
  75. # Modify the state:
  76. def increaseTimeByOne(self):
  77. self.GUI.increaseTimeByOne()
  78. def resetChrono(self):
  79. self.GUI.resetChrono()
  80. def increaseChronoByOne(self):
  81. self.GUI.increaseChronoByOne()
  82. # Select current display:
  83. def startSelection(self):
  84. self.GUI.startSelection()
  85. def selectNext(self):
  86. self.GUI.selectNext()
  87. # Modify the state corresponing to the selection
  88. def increaseSelection(self):
  89. self.GUI.increaseSelection()
  90. def stopSelection(self):
  91. self.GUI.stopSelection()
  92. # Light / Alarm:
  93. def setIndiglo(self):
  94. self.GUI.setIndiglo()
  95. def unsetIndiglo(self):
  96. self.GUI.unsetIndiglo()
  97. def setAlarm(self):
  98. self.GUI.setAlarm()
  99. # Query
  100. def getTime(self):
  101. return self.GUI.getTime()
  102. def getAlarm(self):
  103. return self.GUI.getAlarm()
  104. # Check if time = alarm set time
  105. def checkTime(self):
  106. if self.GUI.getTime()[0] == self.GUI.getAlarm()[0] and self.GUI.getTime()[1] == self.GUI.getAlarm()[1] and self.GUI.getTime()[2] == self.GUI.getAlarm()[2]:
  107. self.alarm()
  108. return True
  109. else:
  110. return False
  111. #======================================================================#
  112. # GUI Static class
  113. class DigitalWatchGUI_Static(Frame):
  114. def __init__(self, parent, controller):
  115. Frame.__init__(self, parent)
  116. self.parent = parent
  117. self.controller = controller
  118. self.controller.bindStatic(self)
  119. self.battery = True
  120. tmpDate = list(localtime()[0:3])
  121. self.curDate = [tmpDate[1], tmpDate[2], int(str(tmpDate[0])[3:]) ]
  122. self.dateTag = None
  123. # self.curTime = list(localtime()[3:6])
  124. self.curTime = [11, 59, 55]
  125. self.timeTag = None
  126. self.curAlarm = [12, 0, 0]
  127. self.alarmTag = None
  128. self.curChrono = [0, 0, 0]
  129. self.chronoTag = None
  130. self.noteImage = PhotoImage(file="./noteSmall.gif")
  131. self.watchImage = PhotoImage(file="./watch.gif")
  132. self.alarmNoteTag = None
  133. self.curSelectionInfo = None
  134. self.curSelection = ["hours", "minutes", "seconds",
  135. "months", "days", "years"]
  136. self.curSelectionIndex = 0
  137. self.lastPressed = ""
  138. self.createWidgets()
  139. # self.b_playpause.focus_force()
  140. parent.protocol("WM_DELETE_WINDOW", self.controller.window_close)
  141. self.drawTime()
  142. self.drawDate()
  143. def getTime(self):
  144. return self.curTime
  145. def getAlarm(self):
  146. return self.curAlarm
  147. def createWidgets(self):
  148. self.pack()
  149. self.displayCanvas = Canvas(master=self,
  150. takefocus=1,
  151. width=CANVAS_W, height=CANVAS_H,
  152. background="black")
  153. self.displayCanvas.pack(fill=BOTH, expand=1)
  154. self.displayCanvas.focus_set()
  155. self.watch = self.displayCanvas.create_image(0, 0, image=self.watchImage, anchor="nw")
  156. self.display = self.displayCanvas.create_rectangle(RECT_X0,
  157. RECT_Y0,
  158. RECT_X1,
  159. RECT_Y1,
  160. fill="#DCDCDC")
  161. self.topRightButton = self.displayCanvas.create_rectangle(CANVAS_W - 13,
  162. 60,
  163. CANVAS_W - 3,
  164. 70,
  165. fill='')
  166. self.topLeftButton = self.displayCanvas.create_rectangle(3,
  167. 62,
  168. 13,
  169. 72,
  170. fill='')
  171. self.bottomRightButton = self.displayCanvas.create_rectangle(CANVAS_W - 10,
  172. 162,
  173. CANVAS_W,
  174. 172,
  175. fill='')
  176. self.bottomLeftButton = self.displayCanvas.create_rectangle(3,
  177. 161,
  178. 13,
  179. 171,
  180. fill='')
  181. self.displayCanvas.bind("<ButtonPress-1>", self.mouse1Click)
  182. self.displayCanvas.bind("<ButtonRelease-1>", self.mouse1Release)
  183. def mouse1Click(self, event):
  184. X = self.displayCanvas.canvasx(event.x)
  185. Y = self.displayCanvas.canvasy(event.y)
  186. objTag = self.displayCanvas.find_closest(X, Y, halo=5)
  187. if self.topRightButton in objTag:
  188. self.controller.topRightPressed()
  189. self.lastPressed = "topRight"
  190. elif self.topLeftButton in objTag:
  191. self.controller.topLeftPressed()
  192. self.lastPressed = "topLeft"
  193. elif self.bottomLeftButton in objTag:
  194. self.controller.bottomLeftPressed()
  195. self.lastPressed = "bottomLeft"
  196. elif self.bottomRightButton in objTag:
  197. self.controller.bottomRightPressed()
  198. self.lastPressed = "bottomRight"
  199. else:
  200. self.lastPressed = ""
  201. def mouse1Release(self, event):
  202. if self.lastPressed == "topRight":
  203. self.controller.topRightReleased()
  204. elif self.lastPressed == "topLeft":
  205. self.controller.topLeftReleased()
  206. elif self.lastPressed == "bottomLeft":
  207. self.controller.bottomLeftReleased()
  208. elif self.lastPressed == "bottomRight":
  209. self.controller.bottomRightReleased()
  210. self.lastPressed = ""
  211. def __intToString(self, i):
  212. if i < 10:
  213. return "0" + str(i)
  214. else:
  215. return str(i)
  216. def __getTimeAsString(self):
  217. hours = self.__intToString(self.curTime[0])
  218. minutes = self.__intToString(self.curTime[1])
  219. seconds = self.__intToString(self.curTime[2])
  220. return hours + ":" + minutes + ":" + seconds
  221. def __getAlarmAsString(self):
  222. hours = self.__intToString(self.curAlarm[0])
  223. minutes = self.__intToString(self.curAlarm[1])
  224. seconds = self.__intToString(self.curAlarm[2])
  225. return hours + ":" + minutes + ":" + seconds
  226. def __getChronoAsString(self):
  227. minutes = self.__intToString(self.curChrono[0])
  228. seconds = self.__intToString(self.curChrono[1])
  229. centisecs = self.__intToString(self.curChrono[2])
  230. return minutes + ":" + seconds + ":" + centisecs
  231. def __getDateAsString(self):
  232. month = self.__intToString(self.curDate[0])
  233. day = self.__intToString(self.curDate[1])
  234. year = self.__intToString(self.curDate[2])
  235. return month + "/" + day + "/" + year
  236. def increaseHoursByOne(self):
  237. if self.timeTag != None:
  238. self.curTime[0] = (self.curTime[0] + 1) % 24
  239. else:
  240. self.curAlarm[0] = (self.curAlarm[0] + 1) % 24
  241. def increaseMinutesByOne(self):
  242. if self.timeTag != None:
  243. self.curTime[1] = (self.curTime[1] + 1) % 60
  244. else:
  245. self.curAlarm[1] = (self.curAlarm[1] + 1) % 60
  246. def increaseSecondsByOne(self):
  247. if self.timeTag != None:
  248. self.curTime[2] = (self.curTime[2] + 1) % 60
  249. else:
  250. self.curAlarm[2] = (self.curAlarm[2] + 1) % 60
  251. def increaseMonthsByOne(self):
  252. self.curDate[0] = (self.curDate[0] + 1) % 13
  253. if self.curDate[0] == 0:
  254. self.curDate[0] = 1
  255. def increaseDaysByOne(self):
  256. numDays = self.getNumDays()
  257. self.curDate[1] = (self.curDate[1] + 1) % (numDays + 1)
  258. if self.curDate[1] == 0:
  259. self.curDate[1] = 1
  260. def increaseYearsByOne(self):
  261. self.curDate[2] = (self.curDate[2] + 1) % 100
  262. if self.curDate[2] == 0:
  263. self.curDate[2] = 1
  264. def getNumDays(self):
  265. month = self.curDate[0]
  266. year = self.curDate[2]
  267. numDays = 0
  268. if month == 2: # february
  269. if year % 4 == 0: # leap year
  270. numDays = 29
  271. else:
  272. numDays = 28
  273. else:
  274. if (month % 2 == 1 and month <= 7) or (month % 2 == 0 and month >= 8):
  275. numDays = 31
  276. else:
  277. numDays = 30
  278. return numDays
  279. def stopSelection(self):
  280. if self.curSelectionInfo != None:
  281. self.parent.after_cancel(self.curSelectionInfo[0])
  282. self.parent.after_cancel(self.curSelectionInfo[1])
  283. self.parent.after_cancel(self.curSelectionInfo[2])
  284. self.curSelectionInfo = None
  285. if self.timeTag != None:
  286. self.drawTime()
  287. self.drawDate()
  288. else:
  289. self.drawAlarm()
  290. def increaseSelection(self):
  291. self.stopSelection()
  292. selection = self.curSelection[self.curSelectionIndex]
  293. if selection == "hours":
  294. self.increaseHoursByOne()
  295. elif selection == "minutes":
  296. self.increaseMinutesByOne()
  297. elif selection == "seconds":
  298. self.increaseSecondsByOne()
  299. elif selection == "months":
  300. self.increaseMonthsByOne()
  301. elif selection == "days":
  302. self.increaseDaysByOne()
  303. elif selection == "years":
  304. self.increaseYearsByOne()
  305. if self.timeTag != None:
  306. self.drawTime()
  307. self.drawDate()
  308. else:
  309. self.drawAlarm()
  310. self.animateSelection()
  311. def selectNext(self):
  312. self.stopSelection()
  313. if self.timeTag != None:
  314. numDigits = len(self.curSelection)
  315. self.drawTime()
  316. self.drawDate()
  317. else:
  318. numDigits = 3
  319. self.drawAlarm()
  320. self.curSelectionIndex = (self.curSelectionIndex + 1) % numDigits
  321. self.animateSelection()
  322. def startSelection(self):
  323. self.curSelectionIndex = 0
  324. self.animateSelection()
  325. def animateSelection(self):
  326. timeFunc = None
  327. if self.timeTag != None:
  328. timeFunc = self.drawTime
  329. else:
  330. timeFunc = self.drawAlarm
  331. curSelection = self.curSelection[self.curSelectionIndex]
  332. deleteEvent = None
  333. creationEvent = None
  334. if curSelection in ["hours", "minutes", "seconds"]:
  335. toDrawTime = ["hours", "minutes", "seconds"]
  336. toDrawTime.remove(curSelection)
  337. deleteEvent = self.parent.after(500, timeFunc, toDrawTime)
  338. creationEvent = self.parent.after(1000, timeFunc)
  339. else:
  340. toDrawDate = ["years", "months", "days"]
  341. toDrawDate.remove(curSelection)
  342. deleteEvent = self.parent.after(500, self.drawDate, toDrawDate)
  343. creationEvent = self.parent.after(1000, self.drawDate)
  344. animationEvent = self.parent.after(1000, self.animateSelection)
  345. self.curSelectionInfo = [deleteEvent,
  346. creationEvent,
  347. animationEvent]
  348. def increaseTimeByOne(self):
  349. self.curTime[2] = self.curTime[2] + 1
  350. self.curTime[1] = (self.curTime[1] + self.curTime[2] // 60)
  351. self.curTime[0] = (self.curTime[0] + self.curTime[1] // 60)
  352. self.curTime[2] = self.curTime[2] % 60
  353. self.curTime[1] = self.curTime[1] % 60
  354. self.curTime[0] = self.curTime[0] % 24
  355. if self.curTime[0] == 0 and\
  356. self.curTime[1] == 0 and\
  357. self.curTime[2] == 0:
  358. self.increaseDateByOne()
  359. def increaseDateByOne(self):
  360. month = self.curDate[0]
  361. day = self.curDate[1]
  362. year = self.curDate[2]
  363. numMonths = 12
  364. numDays = self.getNumDays()
  365. self.curDate[1] = self.curDate[1] + 1
  366. self.curDate[0] = (self.curDate[0] + self.curDate[1] // (numDays + 1))
  367. self.curDate[2] = (self.curDate[2] + self.curDate[0] // (numMonths + 1))
  368. self.curDate[1] = self.curDate[1] % (numDays + 1)
  369. self.curDate[0] = self.curDate[0] % (numMonths + 1)
  370. def increaseChronoByOne(self):
  371. self.curChrono[2] = self.curChrono[2] + 1
  372. self.curChrono[1] = (self.curChrono[1] + self.curChrono[2] // 100)
  373. self.curChrono[0] = (self.curChrono[0] + self.curChrono[1] // 100)
  374. self.curChrono[2] = self.curChrono[2] % 100
  375. self.curChrono[1] = self.curChrono[1] % 100
  376. self.curChrono[0] = self.curChrono[0] % 100
  377. def clearDisplay(self):
  378. if self.alarmTag != None:
  379. self.displayCanvas.delete(self.alarmTag)
  380. self.alarmTag = None
  381. if self.timeTag != None:
  382. self.displayCanvas.delete(self.timeTag)
  383. self.timeTag = None
  384. if self.chronoTag != None:
  385. self.displayCanvas.delete(self.chronoTag)
  386. self.chronoTag = None
  387. def clearDate(self):
  388. if self.dateTag != None:
  389. self.displayCanvas.delete(self.dateTag)
  390. self.dateTag = None
  391. def drawTime(self, toDraw=["hours", "minutes", "seconds"]):
  392. timeToDraw = self.__getTimeAsString()
  393. if "hours" not in toDraw:
  394. timeToDraw = " " + timeToDraw[2:]
  395. if "minutes" not in toDraw:
  396. timeToDraw = timeToDraw[0:3] + " " + timeToDraw[5:]
  397. if "seconds" not in toDraw:
  398. timeToDraw = timeToDraw[0:6] + " "
  399. if not self.battery:
  400. timeToDraw = "88:88:88"
  401. self.clearDisplay()
  402. self.timeTag = self.displayCanvas.create_text((RECT_X0 + RECT_X1) / 2,
  403. (RECT_Y0 + RECT_Y1) / 2 + 5,
  404. font=FONT_TIME,
  405. justify="center",
  406. text=timeToDraw)
  407. def hideTime(self):
  408. if self.timeTag != None:
  409. self.displayCanvas.delete(self.timeTag)
  410. self.timeTag = None
  411. def drawChrono(self):
  412. chronoToDraw = self.__getChronoAsString()
  413. if not self.battery:
  414. chronoToDraw = "88:88:88"
  415. if self.chronoTag:
  416. self.displayCanvas.itemconfigure(self.chronoTag, text=chronoToDraw)
  417. else:
  418. self.clearDisplay()
  419. self.chronoTag = self.displayCanvas.create_text(
  420. (RECT_X0 + RECT_X1) / 2,
  421. (RECT_Y0 + RECT_Y1) / 2 + 5,
  422. font=FONT_TIME,
  423. justify="center",
  424. text=chronoToDraw)
  425. def hideChrono(self):
  426. if self.chronoTag != None:
  427. self.displayCanvas.delete(self.chronoTag)
  428. self.chronoTag = None
  429. def resetChrono(self):
  430. self.curChrono = [0, 0, 0]
  431. def drawDate(self, toDraw=["years", "months", "days"]):
  432. dateToDraw = self.__getDateAsString()
  433. if "months" not in toDraw:
  434. dateToDraw = " " + dateToDraw[2:]
  435. if "days" not in toDraw:
  436. dateToDraw = dateToDraw[0:3] + " " + dateToDraw[5:]
  437. if "years" not in toDraw:
  438. dateToDraw = dateToDraw[0:6] + " "
  439. if not self.battery:
  440. dateToDraw = "88/88/88"
  441. self.clearDate()
  442. self.dateTag = self.displayCanvas.create_text(RECT_X1 - 33,
  443. RECT_Y0 + 7,
  444. font=FONT_DATE,
  445. justify="center",
  446. text=dateToDraw)
  447. def drawAlarm(self, toDraw=["hours", "minutes", "seconds"]):
  448. alarmToDraw = self.__getAlarmAsString()
  449. if "hours" not in toDraw:
  450. alarmToDraw = " " + alarmToDraw[2:]
  451. if "minutes" not in toDraw:
  452. alarmToDraw = alarmToDraw[0:3] + " " + alarmToDraw[5:]
  453. if "seconds" not in toDraw:
  454. alarmToDraw = alarmToDraw[0:6] + " "
  455. if not self.battery:
  456. alarmToDraw = "88:88:88"
  457. self.clearDisplay()
  458. self.alarmTag = self.displayCanvas.create_text((RECT_X0 + RECT_X1) / 2,
  459. (RECT_Y0 + RECT_Y1) / 2 + 5,
  460. font=FONT_TIME,
  461. justify="center",
  462. text=alarmToDraw)
  463. def hideAlarm(self):
  464. if self.alarmTag != None:
  465. self.displayCanvas.delete(self.alarmTag)
  466. self.alarmTag = None
  467. def setAlarm(self):
  468. if self.alarmNoteTag != None:
  469. self.displayCanvas.delete(self.alarmNoteTag)
  470. self.alarmNoteTag = None
  471. else:
  472. self.alarmNoteTag = self.displayCanvas.create_image(RECT_X0 + 5, RECT_Y0 + 3, image=self.noteImage, anchor="nw")
  473. def setIndiglo(self):
  474. self.displayCanvas.itemconfigure(self.display, fill='#96DCFA')
  475. def unsetIndiglo(self):
  476. self.displayCanvas.itemconfigure(self.display, fill="#DCDCDC")