DigitalWatchGUI.py 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618
  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.timeTag = None
  125. self.curAlarm = [12, 0, 0]
  126. self.alarmTag = None
  127. self.curChrono = [0, 0, 0]
  128. self.chronoTag = None
  129. self.noteImage = PhotoImage(file="./noteSmall.gif")
  130. self.watchImage = PhotoImage(file="./watch.gif")
  131. self.alarmNoteTag = None
  132. self.curSelectionInfo = None
  133. self.curSelection = ["hours", "minutes", "seconds",
  134. "months", "days", "years"]
  135. self.curSelectionIndex = 0
  136. self.lastPressed = ""
  137. self.createWidgets()
  138. # self.b_playpause.focus_force()
  139. parent.protocol("WM_DELETE_WINDOW", self.controller.window_close)
  140. self.drawTime()
  141. self.drawDate()
  142. def getTime(self):
  143. return self.curTime
  144. def getAlarm(self):
  145. return self.curAlarm
  146. def createWidgets(self):
  147. self.pack()
  148. self.displayCanvas = Canvas(master=self,
  149. takefocus=1,
  150. width=CANVAS_W, height=CANVAS_H,
  151. background="black")
  152. self.displayCanvas.pack(fill=BOTH, expand=1)
  153. self.displayCanvas.focus_set()
  154. self.watch = self.displayCanvas.create_image(0, 0, image=self.watchImage, anchor="nw")
  155. self.display = self.displayCanvas.create_rectangle(RECT_X0,
  156. RECT_Y0,
  157. RECT_X1,
  158. RECT_Y1,
  159. fill="#DCDCDC")
  160. self.topRightButton = self.displayCanvas.create_rectangle(CANVAS_W - 13,
  161. 60,
  162. CANVAS_W - 3,
  163. 70,
  164. fill='')
  165. self.topLeftButton = self.displayCanvas.create_rectangle(3,
  166. 62,
  167. 13,
  168. 72,
  169. fill='')
  170. self.bottomRightButton = self.displayCanvas.create_rectangle(CANVAS_W - 10,
  171. 162,
  172. CANVAS_W,
  173. 172,
  174. fill='')
  175. self.bottomLeftButton = self.displayCanvas.create_rectangle(3,
  176. 161,
  177. 13,
  178. 171,
  179. fill='')
  180. self.displayCanvas.bind("<ButtonPress-1>", self.mouse1Click)
  181. self.displayCanvas.bind("<ButtonRelease-1>", self.mouse1Release)
  182. def mouse1Click(self, event):
  183. X = self.displayCanvas.canvasx(event.x)
  184. Y = self.displayCanvas.canvasy(event.y)
  185. objTag = self.displayCanvas.find_closest(X, Y, halo=5)
  186. if self.topRightButton in objTag:
  187. self.controller.topRightPressed()
  188. self.lastPressed = "topRight"
  189. elif self.topLeftButton in objTag:
  190. self.controller.topLeftPressed()
  191. self.lastPressed = "topLeft"
  192. elif self.bottomLeftButton in objTag:
  193. self.controller.bottomLeftPressed()
  194. self.lastPressed = "bottomLeft"
  195. elif self.bottomRightButton in objTag:
  196. self.controller.bottomRightPressed()
  197. self.lastPressed = "bottomRight"
  198. else:
  199. self.lastPressed = ""
  200. def mouse1Release(self, event):
  201. if self.lastPressed == "topRight":
  202. self.controller.topRightReleased()
  203. elif self.lastPressed == "topLeft":
  204. self.controller.topLeftReleased()
  205. elif self.lastPressed == "bottomLeft":
  206. self.controller.bottomLeftReleased()
  207. elif self.lastPressed == "bottomRight":
  208. self.controller.bottomRightReleased()
  209. self.lastPressed = ""
  210. def __intToString(self, i):
  211. if i < 10:
  212. return "0" + str(i)
  213. else:
  214. return str(i)
  215. def __getTimeAsString(self):
  216. hours = self.__intToString(self.curTime[0])
  217. minutes = self.__intToString(self.curTime[1])
  218. seconds = self.__intToString(self.curTime[2])
  219. return hours + ":" + minutes + ":" + seconds
  220. def __getAlarmAsString(self):
  221. hours = self.__intToString(self.curAlarm[0])
  222. minutes = self.__intToString(self.curAlarm[1])
  223. seconds = self.__intToString(self.curAlarm[2])
  224. return hours + ":" + minutes + ":" + seconds
  225. def __getChronoAsString(self):
  226. minutes = self.__intToString(self.curChrono[0])
  227. seconds = self.__intToString(self.curChrono[1])
  228. centisecs = self.__intToString(self.curChrono[2])
  229. return minutes + ":" + seconds + ":" + centisecs
  230. def __getDateAsString(self):
  231. month = self.__intToString(self.curDate[0])
  232. day = self.__intToString(self.curDate[1])
  233. year = self.__intToString(self.curDate[2])
  234. return month + "/" + day + "/" + year
  235. def increaseHoursByOne(self):
  236. if self.timeTag != None:
  237. self.curTime[0] = (self.curTime[0] + 1) % 24
  238. else:
  239. self.curAlarm[0] = (self.curAlarm[0] + 1) % 24
  240. def increaseMinutesByOne(self):
  241. if self.timeTag != None:
  242. self.curTime[1] = (self.curTime[1] + 1) % 60
  243. else:
  244. self.curAlarm[1] = (self.curAlarm[1] + 1) % 60
  245. def increaseSecondsByOne(self):
  246. if self.timeTag != None:
  247. self.curTime[2] = (self.curTime[2] + 1) % 60
  248. else:
  249. self.curAlarm[2] = (self.curAlarm[2] + 1) % 60
  250. def increaseMonthsByOne(self):
  251. self.curDate[0] = (self.curDate[0] + 1) % 13
  252. if self.curDate[0] == 0:
  253. self.curDate[0] = 1
  254. def increaseDaysByOne(self):
  255. numDays = self.getNumDays()
  256. self.curDate[1] = (self.curDate[1] + 1) % (numDays + 1)
  257. if self.curDate[1] == 0:
  258. self.curDate[1] = 1
  259. def increaseYearsByOne(self):
  260. self.curDate[2] = (self.curDate[2] + 1) % 100
  261. if self.curDate[2] == 0:
  262. self.curDate[2] = 1
  263. def getNumDays(self):
  264. month = self.curDate[0]
  265. year = self.curDate[2]
  266. numDays = 0
  267. if month == 2: # february
  268. if year % 4 == 0: # leap year
  269. numDays = 29
  270. else:
  271. numDays = 28
  272. else:
  273. if (month % 2 == 1 and month <= 7) or (month % 2 == 0 and month >= 8):
  274. numDays = 31
  275. else:
  276. numDays = 30
  277. return numDays
  278. def stopSelection(self):
  279. if self.curSelectionInfo != None:
  280. self.parent.after_cancel(self.curSelectionInfo[0])
  281. self.parent.after_cancel(self.curSelectionInfo[1])
  282. self.parent.after_cancel(self.curSelectionInfo[2])
  283. self.curSelectionInfo = None
  284. if self.timeTag != None:
  285. self.drawTime()
  286. self.drawDate()
  287. else:
  288. self.drawAlarm()
  289. def increaseSelection(self):
  290. self.stopSelection()
  291. selection = self.curSelection[self.curSelectionIndex]
  292. if selection == "hours":
  293. self.increaseHoursByOne()
  294. elif selection == "minutes":
  295. self.increaseMinutesByOne()
  296. elif selection == "seconds":
  297. self.increaseSecondsByOne()
  298. elif selection == "months":
  299. self.increaseMonthsByOne()
  300. elif selection == "days":
  301. self.increaseDaysByOne()
  302. elif selection == "years":
  303. self.increaseYearsByOne()
  304. if self.timeTag != None:
  305. self.drawTime()
  306. self.drawDate()
  307. else:
  308. self.drawAlarm()
  309. self.animateSelection()
  310. def selectNext(self):
  311. self.stopSelection()
  312. if self.timeTag != None:
  313. numDigits = len(self.curSelection)
  314. self.drawTime()
  315. self.drawDate()
  316. else:
  317. numDigits = 3
  318. self.drawAlarm()
  319. self.curSelectionIndex = (self.curSelectionIndex + 1) % numDigits
  320. self.animateSelection()
  321. def startSelection(self):
  322. self.curSelectionIndex = 0
  323. self.animateSelection()
  324. def animateSelection(self):
  325. timeFunc = None
  326. if self.timeTag != None:
  327. timeFunc = self.drawTime
  328. else:
  329. timeFunc = self.drawAlarm
  330. curSelection = self.curSelection[self.curSelectionIndex]
  331. deleteEvent = None
  332. creationEvent = None
  333. if curSelection in ["hours", "minutes", "seconds"]:
  334. toDrawTime = ["hours", "minutes", "seconds"]
  335. toDrawTime.remove(curSelection)
  336. deleteEvent = self.parent.after(500, timeFunc, toDrawTime)
  337. creationEvent = self.parent.after(1000, timeFunc)
  338. else:
  339. toDrawDate = ["years", "months", "days"]
  340. toDrawDate.remove(curSelection)
  341. deleteEvent = self.parent.after(500, self.drawDate, toDrawDate)
  342. creationEvent = self.parent.after(1000, self.drawDate)
  343. animationEvent = self.parent.after(1000, self.animateSelection)
  344. self.curSelectionInfo = [deleteEvent,
  345. creationEvent,
  346. animationEvent]
  347. def increaseTimeByOne(self):
  348. self.curTime[2] = self.curTime[2] + 1
  349. self.curTime[1] = (self.curTime[1] + self.curTime[2] // 60)
  350. self.curTime[0] = (self.curTime[0] + self.curTime[1] // 60)
  351. self.curTime[2] = self.curTime[2] % 60
  352. self.curTime[1] = self.curTime[1] % 60
  353. self.curTime[0] = self.curTime[0] % 24
  354. if self.curTime[0] == 0 and\
  355. self.curTime[1] == 0 and\
  356. self.curTime[2] == 0:
  357. self.increaseDateByOne()
  358. def increaseDateByOne(self):
  359. month = self.curDate[0]
  360. day = self.curDate[1]
  361. year = self.curDate[2]
  362. numMonths = 12
  363. numDays = self.getNumDays()
  364. self.curDate[1] = self.curDate[1] + 1
  365. self.curDate[0] = (self.curDate[0] + self.curDate[1] // (numDays + 1))
  366. self.curDate[2] = (self.curDate[2] + self.curDate[0] // (numMonths + 1))
  367. self.curDate[1] = self.curDate[1] % (numDays + 1)
  368. self.curDate[0] = self.curDate[0] % (numMonths + 1)
  369. def increaseChronoByOne(self):
  370. self.curChrono[2] = self.curChrono[2] + 1
  371. self.curChrono[1] = (self.curChrono[1] + self.curChrono[2] // 100)
  372. self.curChrono[0] = (self.curChrono[0] + self.curChrono[1] // 100)
  373. self.curChrono[2] = self.curChrono[2] % 100
  374. self.curChrono[1] = self.curChrono[1] % 100
  375. self.curChrono[0] = self.curChrono[0] % 100
  376. def clearDisplay(self):
  377. if self.alarmTag != None:
  378. self.displayCanvas.delete(self.alarmTag)
  379. self.alarmTag = None
  380. if self.timeTag != None:
  381. self.displayCanvas.delete(self.timeTag)
  382. self.timeTag = None
  383. if self.chronoTag != None:
  384. self.displayCanvas.delete(self.chronoTag)
  385. self.chronoTag = None
  386. def clearDate(self):
  387. if self.dateTag != None:
  388. self.displayCanvas.delete(self.dateTag)
  389. self.dateTag = None
  390. def drawTime(self, toDraw=["hours", "minutes", "seconds"]):
  391. timeToDraw = self.__getTimeAsString()
  392. if "hours" not in toDraw:
  393. timeToDraw = " " + timeToDraw[2:]
  394. if "minutes" not in toDraw:
  395. timeToDraw = timeToDraw[0:3] + " " + timeToDraw[5:]
  396. if "seconds" not in toDraw:
  397. timeToDraw = timeToDraw[0:6] + " "
  398. if not self.battery:
  399. timeToDraw = "88:88:88"
  400. self.clearDisplay()
  401. self.timeTag = self.displayCanvas.create_text((RECT_X0 + RECT_X1) / 2,
  402. (RECT_Y0 + RECT_Y1) / 2 + 5,
  403. font=FONT_TIME,
  404. justify="center",
  405. text=timeToDraw)
  406. def hideTime(self):
  407. if self.timeTag != None:
  408. self.displayCanvas.delete(self.timeTag)
  409. self.timeTag = None
  410. def drawChrono(self):
  411. chronoToDraw = self.__getChronoAsString()
  412. self.clearDisplay()
  413. if not self.battery:
  414. chronoToDraw = "88:88:88"
  415. self.chronoTag = self.displayCanvas.create_text((RECT_X0 + RECT_X1) / 2,
  416. (RECT_Y0 + RECT_Y1) / 2 + 5,
  417. font=FONT_TIME,
  418. justify="center",
  419. text=chronoToDraw)
  420. def hideChrono(self):
  421. if self.chronoTag != None:
  422. self.displayCanvas.delete(self.chronoTag)
  423. self.chronoTag = None
  424. def resetChrono(self):
  425. self.curChrono = [0, 0, 0]
  426. def drawDate(self, toDraw=["years", "months", "days"]):
  427. dateToDraw = self.__getDateAsString()
  428. if "months" not in toDraw:
  429. dateToDraw = " " + dateToDraw[2:]
  430. if "days" not in toDraw:
  431. dateToDraw = dateToDraw[0:3] + " " + dateToDraw[5:]
  432. if "years" not in toDraw:
  433. dateToDraw = dateToDraw[0:6] + " "
  434. if not self.battery:
  435. dateToDraw = "88/88/88"
  436. self.clearDate()
  437. self.dateTag = self.displayCanvas.create_text(RECT_X1 - 33,
  438. RECT_Y0 + 7,
  439. font=FONT_DATE,
  440. justify="center",
  441. text=dateToDraw)
  442. def drawAlarm(self, toDraw=["hours", "minutes", "seconds"]):
  443. alarmToDraw = self.__getAlarmAsString()
  444. if "hours" not in toDraw:
  445. alarmToDraw = " " + alarmToDraw[2:]
  446. if "minutes" not in toDraw:
  447. alarmToDraw = alarmToDraw[0:3] + " " + alarmToDraw[5:]
  448. if "seconds" not in toDraw:
  449. alarmToDraw = alarmToDraw[0:6] + " "
  450. if not self.battery:
  451. alarmToDraw = "88:88:88"
  452. self.clearDisplay()
  453. self.alarmTag = self.displayCanvas.create_text((RECT_X0 + RECT_X1) / 2,
  454. (RECT_Y0 + RECT_Y1) / 2 + 5,
  455. font=FONT_TIME,
  456. justify="center",
  457. text=alarmToDraw)
  458. def hideAlarm(self):
  459. if self.alarmTag != None:
  460. self.displayCanvas.delete(self.alarmTag)
  461. self.alarmTag = None
  462. def setAlarm(self):
  463. if self.alarmNoteTag != None:
  464. self.displayCanvas.delete(self.alarmNoteTag)
  465. self.alarmNoteTag = None
  466. else:
  467. self.alarmNoteTag = self.displayCanvas.create_image(RECT_X0 + 5, RECT_Y0 + 3, image=self.noteImage, anchor="nw")
  468. def setIndiglo(self):
  469. self.displayCanvas.itemconfigure(self.display, fill='#96DCFA')
  470. def unsetIndiglo(self):
  471. self.displayCanvas.itemconfigure(self.display, fill="#DCDCDC")