123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641 |
- #
- # 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 Tkinter import *
- import tkFont
- from time import *
- from Tkinter import PhotoImage
- import python_runtime.statecharts_core as statecharts_core
- 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)
- self.dynamicGUI = DigitalWatchGUI_Dynamic(self.controller)
-
- class DigitalWatchGUI_Controller:
- def __init__(self):
- self.statechart = None
- self.GUI = None
- self.battery = True
-
- def bindDynamic(self, statechart):
- self.statechart = statechart
-
- def bindStatic(self, GUI):
- self.GUI = GUI
-
- #Interface for the GUI
- def window_close(self):
- import sys
- sys.exit(0)
- self.statechart.event('GUI Quit')
- def topRightPressed(self):
- self.statechart.event('topRightPressed')
- def topRightReleased(self):
- self.statechart.event('topRightReleased')
-
- def topLeftPressed(self):
- self.statechart.event('topLeftPressed')
-
- def topLeftReleased(self):
- self.statechart.event('topLeftReleased')
-
- def bottomRightPressed(self):
- self.statechart.event('bottomRightPressed')
- def bottomRightReleased(self):
- self.statechart.event('bottomRightReleased')
-
- def bottomLeftPressed(self):
- self.statechart.event('bottomLeftPressed')
-
- def bottomLeftReleased(self):
- self.statechart.event('bottomLeftReleased')
- def alarm(self):
- self.statechart.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
-
- class DigitalWatchGUI_Dynamic:
-
- def __init__(self, controller):
- self.controller = controller
- self.controller.bindDynamic(self)
- def setStatechart(self, controller):
- print("STATECHART set")
- self.controller_SCCD = controller
-
- def event(self, evt, param=[]):
- self.controller_SCCD.addInput(statecharts_core.Event(evt, "tkinter_input", param), 0.0)
- #======================================================================#
- # 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.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("<ButtonPress-1>", self.mouse1Click)
- self.displayCanvas.bind("<ButtonRelease-1>", 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()
- self.clearDisplay()
-
- if not self.battery:
- chronoToDraw = "88:88:88"
-
- 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")
|