# # DigitalWatchGUI.py # # class DigitalWatchGUI provides a simple Tkinter GUI for a Digital Watch # to add: battery dies ... DONE OCT 2008 by Reehan Shaikh reehan.shaikh@cs.mcgill.ca # Updated for the SCCDXML compiler and AToMPM formalism by Yentl Van Tendeloo from time import localtime from tkinter import Frame, PhotoImage, Canvas from tkinter.constants import BOTH CANVAS_W = 222 CANVAS_H = 236 OVAL_X0 = 2 OVAL_Y0 = 1 OVAL_X1 = CANVAS_W - OVAL_X0 OVAL_Y1 = CANVAS_H - OVAL_Y0 RECT_X0 = 51 RECT_Y0 = 95 RECT_X1 = CANVAS_W - RECT_X0 + 1 RECT_Y1 = CANVAS_H - RECT_Y0 + 10 FONT_TIME = ("terminal", 14) FONT_DATE = ("terminal", 8) FONT_NOTE = ("symbol", 10) class DigitalWatchGUI: def __init__(self, parent): self.controller = DigitalWatchGUI_Controller() self.staticGUI = DigitalWatchGUI_Static(parent, self.controller) class DigitalWatchGUI_Controller: def __init__(self): self.send_event = None self.GUI = None self.battery = True def bindStatic(self, GUI): self.GUI = GUI # Interface for the GUI def window_close(self): import sys sys.exit(0) self.send_event('GUIQuit') def topRightPressed(self): self.send_event('topRightPressed') def topRightReleased(self): self.send_event('topRightReleased') def topLeftPressed(self): self.send_event('topLeftPressed') def topLeftReleased(self): self.send_event('topLeftReleased') def bottomRightPressed(self): self.send_event('bottomRightPressed') def bottomRightReleased(self): self.send_event('bottomRightReleased') def bottomLeftPressed(self): self.send_event('bottomLeftPressed') def bottomLeftReleased(self): self.send_event('bottomLeftReleased') def alarm(self): self.send_event('alarmStart') # Interface for the statechart # synchronize the state with the display: def batteryHalf(self): self.battery = False self.GUI.battery = False self.refreshDateDisplay() def batteryFull(self): self.battery = True self.GUI.battery = True self.refreshDateDisplay() def refreshTimeDisplay(self): self.GUI.drawTime() def refreshChronoDisplay(self): self.GUI.drawChrono() def refreshDateDisplay(self): self.GUI.drawDate() def refreshAlarmDisplay(self): self.GUI.drawAlarm() # Modify the state: def increaseTimeByOne(self): self.GUI.increaseTimeByOne() def resetChrono(self): self.GUI.resetChrono() def increaseChronoByOne(self): self.GUI.increaseChronoByOne() # Select current display: def startSelection(self): self.GUI.startSelection() def selectNext(self): self.GUI.selectNext() # Modify the state corresponing to the selection def increaseSelection(self): self.GUI.increaseSelection() def stopSelection(self): self.GUI.stopSelection() # Light / Alarm: def setIndiglo(self): self.GUI.setIndiglo() def unsetIndiglo(self): self.GUI.unsetIndiglo() def setAlarm(self): self.GUI.setAlarm() # Query def getTime(self): return self.GUI.getTime() def getAlarm(self): return self.GUI.getAlarm() # Check if time = alarm set time def checkTime(self): 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]: self.alarm() return True else: return False #======================================================================# # GUI Static class class DigitalWatchGUI_Static(Frame): def __init__(self, parent, controller): Frame.__init__(self, parent) self.parent = parent self.controller = controller self.controller.bindStatic(self) self.battery = True tmpDate = list(localtime()[0:3]) self.curDate = [tmpDate[1], tmpDate[2], int(str(tmpDate[0])[3:]) ] self.dateTag = None # self.curTime = list(localtime()[3:6]) self.curTime = [11, 59, 55] self.timeTag = None self.curAlarm = [12, 0, 0] self.alarmTag = None self.curChrono = [0, 0, 0] self.chronoTag = None self.noteImage = PhotoImage(file="./noteSmall.gif") self.watchImage = PhotoImage(file="./watch.gif") self.alarmNoteTag = None self.curSelectionInfo = None self.curSelection = ["hours", "minutes", "seconds", "months", "days", "years"] self.curSelectionIndex = 0 self.lastPressed = "" self.createWidgets() # self.b_playpause.focus_force() parent.protocol("WM_DELETE_WINDOW", self.controller.window_close) self.drawTime() self.drawDate() def getTime(self): return self.curTime def getAlarm(self): return self.curAlarm def createWidgets(self): self.pack() self.displayCanvas = Canvas(master=self, takefocus=1, width=CANVAS_W, height=CANVAS_H, background="black") self.displayCanvas.pack(fill=BOTH, expand=1) self.displayCanvas.focus_set() self.watch = self.displayCanvas.create_image(0, 0, image=self.watchImage, anchor="nw") self.display = self.displayCanvas.create_rectangle(RECT_X0, RECT_Y0, RECT_X1, RECT_Y1, fill="#DCDCDC") self.topRightButton = self.displayCanvas.create_rectangle(CANVAS_W - 13, 60, CANVAS_W - 3, 70, fill='') self.topLeftButton = self.displayCanvas.create_rectangle(3, 62, 13, 72, fill='') self.bottomRightButton = self.displayCanvas.create_rectangle(CANVAS_W - 10, 162, CANVAS_W, 172, fill='') self.bottomLeftButton = self.displayCanvas.create_rectangle(3, 161, 13, 171, fill='') self.displayCanvas.bind("", self.mouse1Click) self.displayCanvas.bind("", self.mouse1Release) def mouse1Click(self, event): X = self.displayCanvas.canvasx(event.x) Y = self.displayCanvas.canvasy(event.y) objTag = self.displayCanvas.find_closest(X, Y, halo=5) if self.topRightButton in objTag: self.controller.topRightPressed() self.lastPressed = "topRight" elif self.topLeftButton in objTag: self.controller.topLeftPressed() self.lastPressed = "topLeft" elif self.bottomLeftButton in objTag: self.controller.bottomLeftPressed() self.lastPressed = "bottomLeft" elif self.bottomRightButton in objTag: self.controller.bottomRightPressed() self.lastPressed = "bottomRight" else: self.lastPressed = "" def mouse1Release(self, event): if self.lastPressed == "topRight": self.controller.topRightReleased() elif self.lastPressed == "topLeft": self.controller.topLeftReleased() elif self.lastPressed == "bottomLeft": self.controller.bottomLeftReleased() elif self.lastPressed == "bottomRight": self.controller.bottomRightReleased() self.lastPressed = "" def __intToString(self, i): if i < 10: return "0" + str(i) else: return str(i) def __getTimeAsString(self): hours = self.__intToString(self.curTime[0]) minutes = self.__intToString(self.curTime[1]) seconds = self.__intToString(self.curTime[2]) return hours + ":" + minutes + ":" + seconds def __getAlarmAsString(self): hours = self.__intToString(self.curAlarm[0]) minutes = self.__intToString(self.curAlarm[1]) seconds = self.__intToString(self.curAlarm[2]) return hours + ":" + minutes + ":" + seconds def __getChronoAsString(self): minutes = self.__intToString(self.curChrono[0]) seconds = self.__intToString(self.curChrono[1]) centisecs = self.__intToString(self.curChrono[2]) return minutes + ":" + seconds + ":" + centisecs def __getDateAsString(self): month = self.__intToString(self.curDate[0]) day = self.__intToString(self.curDate[1]) year = self.__intToString(self.curDate[2]) return month + "/" + day + "/" + year def increaseHoursByOne(self): if self.timeTag != None: self.curTime[0] = (self.curTime[0] + 1) % 24 else: self.curAlarm[0] = (self.curAlarm[0] + 1) % 24 def increaseMinutesByOne(self): if self.timeTag != None: self.curTime[1] = (self.curTime[1] + 1) % 60 else: self.curAlarm[1] = (self.curAlarm[1] + 1) % 60 def increaseSecondsByOne(self): if self.timeTag != None: self.curTime[2] = (self.curTime[2] + 1) % 60 else: self.curAlarm[2] = (self.curAlarm[2] + 1) % 60 def increaseMonthsByOne(self): self.curDate[0] = (self.curDate[0] + 1) % 13 if self.curDate[0] == 0: self.curDate[0] = 1 def increaseDaysByOne(self): numDays = self.getNumDays() self.curDate[1] = (self.curDate[1] + 1) % (numDays + 1) if self.curDate[1] == 0: self.curDate[1] = 1 def increaseYearsByOne(self): self.curDate[2] = (self.curDate[2] + 1) % 100 if self.curDate[2] == 0: self.curDate[2] = 1 def getNumDays(self): month = self.curDate[0] year = self.curDate[2] numDays = 0 if month == 2: # february if year % 4 == 0: # leap year numDays = 29 else: numDays = 28 else: if (month % 2 == 1 and month <= 7) or (month % 2 == 0 and month >= 8): numDays = 31 else: numDays = 30 return numDays def stopSelection(self): if self.curSelectionInfo != None: self.parent.after_cancel(self.curSelectionInfo[0]) self.parent.after_cancel(self.curSelectionInfo[1]) self.parent.after_cancel(self.curSelectionInfo[2]) self.curSelectionInfo = None if self.timeTag != None: self.drawTime() self.drawDate() else: self.drawAlarm() def increaseSelection(self): self.stopSelection() selection = self.curSelection[self.curSelectionIndex] if selection == "hours": self.increaseHoursByOne() elif selection == "minutes": self.increaseMinutesByOne() elif selection == "seconds": self.increaseSecondsByOne() elif selection == "months": self.increaseMonthsByOne() elif selection == "days": self.increaseDaysByOne() elif selection == "years": self.increaseYearsByOne() if self.timeTag != None: self.drawTime() self.drawDate() else: self.drawAlarm() self.animateSelection() def selectNext(self): self.stopSelection() if self.timeTag != None: numDigits = len(self.curSelection) self.drawTime() self.drawDate() else: numDigits = 3 self.drawAlarm() self.curSelectionIndex = (self.curSelectionIndex + 1) % numDigits self.animateSelection() def startSelection(self): self.curSelectionIndex = 0 self.animateSelection() def animateSelection(self): timeFunc = None if self.timeTag != None: timeFunc = self.drawTime else: timeFunc = self.drawAlarm curSelection = self.curSelection[self.curSelectionIndex] deleteEvent = None creationEvent = None if curSelection in ["hours", "minutes", "seconds"]: toDrawTime = ["hours", "minutes", "seconds"] toDrawTime.remove(curSelection) deleteEvent = self.parent.after(500, timeFunc, toDrawTime) creationEvent = self.parent.after(1000, timeFunc) else: toDrawDate = ["years", "months", "days"] toDrawDate.remove(curSelection) deleteEvent = self.parent.after(500, self.drawDate, toDrawDate) creationEvent = self.parent.after(1000, self.drawDate) animationEvent = self.parent.after(1000, self.animateSelection) self.curSelectionInfo = [deleteEvent, creationEvent, animationEvent] def increaseTimeByOne(self): self.curTime[2] = self.curTime[2] + 1 self.curTime[1] = (self.curTime[1] + self.curTime[2] // 60) self.curTime[0] = (self.curTime[0] + self.curTime[1] // 60) self.curTime[2] = self.curTime[2] % 60 self.curTime[1] = self.curTime[1] % 60 self.curTime[0] = self.curTime[0] % 24 if self.curTime[0] == 0 and\ self.curTime[1] == 0 and\ self.curTime[2] == 0: self.increaseDateByOne() def increaseDateByOne(self): month = self.curDate[0] day = self.curDate[1] year = self.curDate[2] numMonths = 12 numDays = self.getNumDays() self.curDate[1] = self.curDate[1] + 1 self.curDate[0] = (self.curDate[0] + self.curDate[1] // (numDays + 1)) self.curDate[2] = (self.curDate[2] + self.curDate[0] // (numMonths + 1)) self.curDate[1] = self.curDate[1] % (numDays + 1) self.curDate[0] = self.curDate[0] % (numMonths + 1) def increaseChronoByOne(self): self.curChrono[2] = self.curChrono[2] + 1 self.curChrono[1] = (self.curChrono[1] + self.curChrono[2] // 100) self.curChrono[0] = (self.curChrono[0] + self.curChrono[1] // 100) self.curChrono[2] = self.curChrono[2] % 100 self.curChrono[1] = self.curChrono[1] % 100 self.curChrono[0] = self.curChrono[0] % 100 def clearDisplay(self): if self.alarmTag != None: self.displayCanvas.delete(self.alarmTag) self.alarmTag = None if self.timeTag != None: self.displayCanvas.delete(self.timeTag) self.timeTag = None if self.chronoTag != None: self.displayCanvas.delete(self.chronoTag) self.chronoTag = None def clearDate(self): if self.dateTag != None: self.displayCanvas.delete(self.dateTag) self.dateTag = None def drawTime(self, toDraw=["hours", "minutes", "seconds"]): timeToDraw = self.__getTimeAsString() if "hours" not in toDraw: timeToDraw = " " + timeToDraw[2:] if "minutes" not in toDraw: timeToDraw = timeToDraw[0:3] + " " + timeToDraw[5:] if "seconds" not in toDraw: timeToDraw = timeToDraw[0:6] + " " if not self.battery: timeToDraw = "88:88:88" self.clearDisplay() self.timeTag = self.displayCanvas.create_text((RECT_X0 + RECT_X1) / 2, (RECT_Y0 + RECT_Y1) / 2 + 5, font=FONT_TIME, justify="center", text=timeToDraw) def hideTime(self): if self.timeTag != None: self.displayCanvas.delete(self.timeTag) self.timeTag = None def drawChrono(self): chronoToDraw = self.__getChronoAsString() if not self.battery: chronoToDraw = "88:88:88" if self.chronoTag: self.displayCanvas.itemconfigure(self.chronoTag, text=chronoToDraw) else: self.clearDisplay() self.chronoTag = self.displayCanvas.create_text( (RECT_X0 + RECT_X1) / 2, (RECT_Y0 + RECT_Y1) / 2 + 5, font=FONT_TIME, justify="center", text=chronoToDraw) def hideChrono(self): if self.chronoTag != None: self.displayCanvas.delete(self.chronoTag) self.chronoTag = None def resetChrono(self): self.curChrono = [0, 0, 0] def drawDate(self, toDraw=["years", "months", "days"]): dateToDraw = self.__getDateAsString() if "months" not in toDraw: dateToDraw = " " + dateToDraw[2:] if "days" not in toDraw: dateToDraw = dateToDraw[0:3] + " " + dateToDraw[5:] if "years" not in toDraw: dateToDraw = dateToDraw[0:6] + " " if not self.battery: dateToDraw = "88/88/88" self.clearDate() self.dateTag = self.displayCanvas.create_text(RECT_X1 - 33, RECT_Y0 + 7, font=FONT_DATE, justify="center", text=dateToDraw) def drawAlarm(self, toDraw=["hours", "minutes", "seconds"]): alarmToDraw = self.__getAlarmAsString() if "hours" not in toDraw: alarmToDraw = " " + alarmToDraw[2:] if "minutes" not in toDraw: alarmToDraw = alarmToDraw[0:3] + " " + alarmToDraw[5:] if "seconds" not in toDraw: alarmToDraw = alarmToDraw[0:6] + " " if not self.battery: alarmToDraw = "88:88:88" self.clearDisplay() self.alarmTag = self.displayCanvas.create_text((RECT_X0 + RECT_X1) / 2, (RECT_Y0 + RECT_Y1) / 2 + 5, font=FONT_TIME, justify="center", text=alarmToDraw) def hideAlarm(self): if self.alarmTag != None: self.displayCanvas.delete(self.alarmTag) self.alarmTag = None def setAlarm(self): if self.alarmNoteTag != None: self.displayCanvas.delete(self.alarmNoteTag) self.alarmNoteTag = None else: self.alarmNoteTag = self.displayCanvas.create_image(RECT_X0 + 5, RECT_Y0 + 3, image=self.noteImage, anchor="nw") def setIndiglo(self): self.displayCanvas.itemconfigure(self.display, fill='#96DCFA') def unsetIndiglo(self): self.displayCanvas.itemconfigure(self.display, fill="#DCDCDC")