##---------------------------------------------------------------------------## ## ## pyChing -- a Python program to cast and interpret I Ching hexagrams ## ## Copyright (C) 1999-2003 Stephen M. Gava ## ## This program is free software; you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation; either version 2 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be of some ## interest to somebody, but WITHOUT ANY WARRANTY; without even the ## implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. ## See the GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program; see the file COPYING or COPYING.txt. If not, ## write to the Free Software Foundation, Inc., ## 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ## The license can also be found at the GNU/FSF website: http://www.gnu.org ## ## Stephen M. Gava ## ## http://pyching.sourgeforge.net ## ##---------------------------------------------------------------------------## """ tkinter interface module for pyching """ #python library imports import string, sys, os, time, copy, htmllib, formatter #tkinter imports from Tkinter import * import tkFileDialog, tkMessageBox, tkColorChooser #pyChing source specific imports import pyching_engine, pyching_cimages, pyching_idimage_data import pyching_int_data, pyching_hlhtx_data #smg library module imports from smgDialog import smgDialog from smgHtmlView import smgHtmlView from smgAbout import smgAbout class WidgetColors: """ colours for widgets in the reading display area """ def __init__(self): #maybe colour defaults for all platforms #and platform defaults if started with a --mono switch (?) #if pyching.osType in ('posix','nt'): #non-default values for X & win32 style tk widgets #self.BgReading = '#7e7e7e' #self.bgReading = '#cd5c5c' self.bgReading = '#323c4a' self.bgLabelHint = '#FFE4B5' self.fgLabelHint = '#000000' #self.fgLabelPlaces = '#D3D3D3' #self.fgLabelPlaces = '#F08080' self.fgLabelPlaces = '#FFA07A' self.fgLabelHexTitles = '#FFFFFF' self.fgLabelLines = '#FFFFFF' self.fgMessageQuestion = '#FFFFFF' self.lineBody = '#DAA520' self.lineHighlight = '#EEE8AA' self.lineShadow = '#B8860B' #self.bgHtmlViewer = '#e8e8e8' #self.fgHtmlViewer = '#000000' #else: #values default to the platform standards # self.bgReading = None # self.bgLabelHint = None # self.fgLabelHint = None # self.fgLabelPlaces = None # self.fgLabelHexTitles = None # self.fgLabelLines = None # self.fgMessageQuestion = None # self.lineBody = 'Gray' # self.lineHighlight = 'LightGray' # self.lineShadow = 'DarkGray' class WidgetFonts: """ fonts for widgets in the main window """ def __init__(self): if pyching.osType == 'posix': #non-default values for X style tk widgets self.menu = '-*-Helvetica-Normal-R-*--*-120-*-*-*-*-ISO8859-1' self.button = '-*-Helvetica-Normal-R-*--*-120-*-*-*-*-ISO8859-1' self.label = '-*-Helvetica-Normal-R-*--*-120-*-*-*-*-ISO8859-1' self.labelHexTitles = '-*-Helvetica-Bold-R-*--*-140-*-*-*-*-ISO8859-1' self.labelLineHint = '-*-Helvetica-Normal-R-*--*-120-*-*-*-*-ISO8859-1' elif pyching.osType == 'nt': #values for win32 style tk widgets self.menu = None self.button = None self.label = None self.labelHexTitles = '-*-Helvetica-Bold-R-*--*-150-*-*-*-*-ISO8859-1' self.labelLineHint = None else: #use default values for any other (untested :-) platform self.menu = None self.button = None self.label = None self.labelHexTitles = None self.labelLineHint = None class WindowMain: """ main application window """ def __init__(self, master): self.master = master self.master.resizable(height=FALSE,width=FALSE) #self.master.colormapwindows([self.master])#debug, does this solve the 256 color problem?? self.images = pyching_cimages.CoinImages() try: self.master.iconbitmap(bitmap='@'+pyching.execPath+'/icon.xbm') except TclError: #sys.stderr.write("can't load icon bitmap") pass #just ignore this self.master.title(pyching.title + ' ' + pyching.version) #application-wide event bindings self.master.bind('',self.HelpBinding) #help key #bind_all self.master.bind('',self.CastButtonBinding) #cast button self.master.bind('',self.ViewHex1InfoButtonBinding) #view hex 1 info button self.master.bind('',self.ViewHex2InfoButtonBinding) #view hex 2 info button #application-wide protocol bindings self.master.protocol("WM_DELETE_WINDOW", self.Quit) #configuration attributes self.showPlaces = BooleanVar() self.showPlaces.set(TRUE) self.showLineHints = BooleanVar() self.showLineHints.set(TRUE) self.castAll = BooleanVar() self.castAll.set(TRUE) #instantiate default colour and font values self.colors = WidgetColors() self.fonts = WidgetFonts() #load configuration file (if any) self.LoadSettings() self.MakeMenus(self.master) self.MakeStatusBar(self.master) #main frame frameMainBevel = Frame(self.master,borderwidth=2,relief=SUNKEN,highlightthickness=0) frameMainBevel.pack(expand=TRUE,fill=BOTH,padx=4)#used as a bevel for the main frame self.frameMain = Frame(frameMainBevel,bg=self.colors.bgReading)#highlightthickness=4,borderwidth=4,relief=SUNKEN)#,borderwidth=1,relief=SOLID self.frameMain.pack(expand=TRUE,fill=BOTH) self.MakeCastDisplay(self.frameMain) self.MakeQuestionDisplay(self.frameMain) self.MakeHexDisplay(self.frameMain) self.hexes = None #so we can test if a reading has been performed yet def Quit(self): #print 'bye now'#debug self.master.quit() def __AddMenu(self,parent,title): if title == 'Help': menuName = 'help'#name option to right justify help menu under X else: menuName = None _menu = Menu(parent,name=menuName,tearoff=0,font=self.fonts.menu)#create the menu if parent == self.master:#this is the menubar itself parent.configure(menu=_menu)#make _menu the menubar _menu.configure(borderwidth=0) else: #this is a dropdown from the menubar parent.add_cascade(label=title,underline=0,menu=_menu)#add the menu to the menubar return _menu def MakeMenus(self, parent): self.menuMain = self.__AddMenu(parent,'')#create the menubar self.menuMainFile = self.__AddMenu(self.menuMain,'File')#create the file menu self.menuMainSettings = self.__AddMenu(self.menuMain,'Settings')#create the settings menu self.menuMainHelp = self.__AddMenu(self.menuMain,'Help')#create the help menu def AddMenuItems(menu, items): for item in items: if item[0] == 's':#add a separator menu.add_separator() elif item[0] == 'c':#add a command menu.add_command(label=item[1],underline=item[2],command=item[3]) elif item[0] == 'k':#add a checkbutton menu.add_checkbutton(label=item[1],underline=item[2],command=item[3],variable=item[4]) elif item[0] == 'r':#add a radiobutton menu.add_radiobutton(label=item[1],underline=item[2],command=item[3],variable=item[4],value=item[5]) #elif item[0] == 'm':#add a submenu # pass #not implemented AddMenuItems(self.menuMainFile,(('c','Load Reading...',0,self.LoadReading), ('c','Save Reading...',0,self.SaveReading),('s',), ('c','Save Reading As Text...',16,self.SaveReadingAsText),('s',), ('c','Exit',1,self.Quit)) ) AddMenuItems(self.menuMainSettings,(('k','Show Places',5,self.__ToggleLabelsPlaces,self.showPlaces), ('k','Show Line Hints',10,None,self.showLineHints),('s',), ('r','Cast Each Line Separately',10,None,self.castAll,FALSE), ('r','Cast Entire Hexagram Automatically',12,None,self.castAll,TRUE),('s',), ('c','Configure Colors...',10,self.SetColors),('s',), ('c','Save Settings',0,self.SaveSettings)) ) AddMenuItems(self.menuMainHelp,( ('c','Using '+pyching.title,0,self.ShowHelpUsingPyching), ('c','Introduction to the I Ching',0,self.ShowHelpIChingIntro), ('c','Browse Hexagram Information',0,self.ShowHelpHexInfo), ('s',), ('c','About '+pyching.title+'...',0,self.ShowAbout)) ) #self.ShowText(title='Help - Using '+pyching.title,textFile='help.txt')), self.menuMainFile.entryconfigure(1,state=DISABLED)#disable save item by default self.menuMainFile.entryconfigure(3,state=DISABLED)#disable save as text item by default def HelpBinding(self,event): #main window binding for the F1 key #try: self.ShowHelpUsingPyching() #except KeyError: # pass #this error is raised while pressing F1 over a tk file dialog, ignore it def CastButtonBinding(self,event): #binding for the Meta-c hotkey on buttonCast if self.buttonCast.cget('state') == 'normal': #if the button isn't disabled self.buttonCast.invoke() def ViewHex1InfoButtonBinding(self, event): #binding for the Meta-v hotkey on buttonViewHex1Info if self.buttonViewHex1Info.cget('state') == 'normal': #if the button isn't disabled self.buttonViewHex1Info.invoke() def ViewHex2InfoButtonBinding(self, event): #binding for the Meta-i hotkey on buttonViewHex1Info if self.buttonViewHex2Info.cget('state') == 'normal': #if the button isn't disabled self.buttonViewHex2Info.invoke() def ShowHelpUsingPyching(self): self.ShowHtml(title=pyching.title + ' - Help', htmlSource='pyching_hlhtx_data.hlHelpData()', index='pyching_hlhtx_data.hlHelpData()') def ShowHelpIChingIntro(self): self.ShowHtml(title=pyching.title + ' - Help', htmlSource='pyching_hlhtx_data.hlIntroData()', index='pyching_hlhtx_data.hlHelpData()') def ShowHelpHexInfo(self): self.ShowHtml(title=pyching.title + ' - Hexagram Infomation Browser', hexBrowser=1) def ShowText(self,title=None,textFile=None): #dialogTxt = DialogShowHtml(self.master,title=title,htmlFile=textFile, # plainText=1) dialogTxt = smgHtmlView(self.master,title=title,htmlSource=textFile, plainText=1) def ShowHtml(self,title=None,htmlSource=None,index=None,hexBrowser=0): #dialoghtml = DialogShowHtml(self.master,title=title,htmlFile=textFile, # indexFile=indexFile) dialoghtml = smgHtmlView(self.master,title=title, htmlSource=htmlSource, internalLink=None,index=index,hexBrowser=hexBrowser) def ShowAbout(self): #dialogAbout = DialogAbout(self.master,currentColors=self.colors) aboutPicData="""R0lGODlhMgAyAKEAAAICBP4CBAIC/P///yH+Dk1hZGUgd2l0aCBHSU1QACH5BAEKAAMALAAA AAAyADIAAAL+nI+ZwO0Ko1SOhYvvmzw2YWUi1nTmwAgqMLYic0rp6tYkEC+AStt+AMvNeKyf L2ga9oxHXEe5ZNqQnh0v2nIwqZQrcXot/pwQqxdUM3+NZAR0nT2Lm90zNqO+pxd2+CiPJtUG GAbmx3bw5jX31yB1Y0C4+EjpJDlJuRXZh5k5hsIp58l2acc42hhqeoqqUcoZ0nqjGuooq0i7 GJuJmyvHOvbqGwacJjxcKHiMfDgFyuxbjLcJnStNQl1New0UuUzcG2icyDxXKj2IfHqJzhf9 B7un8/4Sn9VGbg3fB4zvRq+hVpYJ4cC9WudvnjZRLxJS+KaKEReCEPk1zIGiIkMfVxgTaVwy EWNBU5A6lhkJgkUJkxRxVXDIssrLkCYKAAA7""" dialogAbout = smgAbout(self.master,title='About '+pyching.title, appTitle=pyching.title, version='Version: '+pyching.version, copyright='Copyright (c) 1999-2003 Stephen M. Gava', licence='Released under the GNU General Public Licence', email='email: '+pyching.emailAddress, www='web: '+pyching.webAddress, pictureData=aboutPicData, licenceFile=pyching.execPath+'COPYING', creditsFile=pyching.execPath+'CREDITS', fontAppTitle=self.fonts.labelHexTitles, fontText=self.fonts.label, fg=self.colors.fgLabelHexTitles, bg=self.colors.bgReading ) def SetColors(self): dialogSetColors = DialogSetColors(self.master,currentColors=copy.copy(self.colors)) if dialogSetColors.result: #user didn't cancel self.RepaintColors(dialogSetColors.result) def SaveSettings(self): if os.path.expanduser('~') != '~': #unix-style home directories if not os.path.exists(pyching.configPath): #failsafe if user deleted ~/.pyching while program running :) os.mkdir(pyching.configPath)#make the config dir castAllValue = self.castAll.get() showPlacesValue = self.showPlaces.get() showLineHintsValue = self.showLineHints.get() configData = (pyching.version,self.colors,castAllValue,showPlacesValue,showLineHintsValue) try: pyching_engine.Storage(pyching.configFile, data=configData) except IOError: #print '\n error: unable to write config file', pyching.configFile tkMessageBox.showerror(title='File Error', message='Unable to write configuration file:\n'+pyching.configFile) else: #print '\n saved file:', fileName self.labelStatus.configure(text='saved settings') def LoadSettings(self): if os.path.exists(pyching.configFile): #if a saved configuration exists try: configData= pyching_engine.Storage(pyching.configFile, data=None) except IOError: #just silently let this past?? #print '\n error: unable to read configuration file', pyching.configFile sys.stderr.write('\n error (IOError): unable to read configuration file'+pyching.configFile+'\n') #tkMessageBox.showerror(title='File Error', # message='Unable to read configuration file:\n'+pyching.configFile) pass except 'pychingUnpickleError': #just silently let this past?? #print '\n error: invalid configuration file', pyching.configFile sys.stderr.write('\n error (pychingUnpickleError): invalid configuration file'+pyching.configFile+'\n') #tkMessageBox.showerror(title='File Error', # message='Invalid configuration file:\n'+pyching.configFile) pass else: #version can be tested against pyching.version for config file compatability version,self.colors,castAllValue,showPlacesValue,showLineHintsValue = configData self.castAll.set(castAllValue) self.showPlaces.set(showPlacesValue) self.showLineHints.set(showLineHintsValue) #print '\n loaded config file:', pyching.configFile def __HideLabel(self,label): label.configure(fg=label.cget('bg'))#fg=bg to hide label def __ToggleLabelsPlaces(self): if self.hexes: #if there's been a reading yet for label in self.labelsHexPlaces: if label.cget('fg') == self.colors.fgLabelPlaces: self.__HideLabel(label) else: label.configure(fg=self.colors.fgLabelPlaces) def ClearReading(self): self.HideInfoButtons()#get rid of any info buttons for coin in self.labelsCoins:#clear coins display coin.configure(image=self.images.coinFrames[16]) #blank both hexagram displays for i in range(2): for line in self.hexLines[i]: line.Draw(linetype=None) for label in self.labelsHexPlaces: self.__HideLabel(label) for key in self.labelsNoMovingLines.keys(): self.labelsNoMovingLines[key].lower()#hide the 'no moving lines' labels self.__HideLabel(self.labelBecomes) self.labelH1Title.configure(text='') self.labelH2Title.configure(text='') self.messageQuestion.configure(text='') #wiped stuff still appears on win32?? - try below self.master.update() def CastHexes(self): self.labelLineHint.show = 0 #disable line hints #get the question questionDialog = DialogGetQuestion(self.master) self.master.update()#makes sure the main app window gets redrawn properly (seems only to be a problem on win32) if questionDialog.result: #the user didn't cancel self.ClearReading() for coin in self.labelsCoins:#initialise coins display coin.configure(image=self.images.coinFrames[0]) self.hexes = pyching_engine.Hexagrams('coin') self.hexes.question = questionDialog.result self.ShowQuestion() if self.castAll.get():#cast all lines automatically self.CastAllLines() else:#cast 1 line at a time for menuItem in range(3,5):#disable cast-type changing while casting self.menuMainSettings.entryconfigure(menuItem,state=DISABLED) self.buttonCast.configure(text='Cast Line 1 of 6',command=self.CastNextLine) self.labelStatus.configure(text='Waiting to cast line 1 of 6 ...') else: #the user cancelled self.labelLineHint.show = 1 #re-enable line hints def CastNextLine(self): self.buttonCast.configure(state=DISABLED) self.CastLine() self.buttonCast.configure(state=NORMAL) if self.hexes.hex1.lineValues[5] == 0:#if hex1 is'nt fully built yet self.buttonCast.configure(text='Cast Line '+`self.hexes.currentLine+1`+' of 6') self.labelStatus.configure(text='Waiting to cast line '+`self.hexes.currentLine+1`+ ' of 6 ...') else:#hex1 is fully built now for menuItem in range(3,5):#re-enable cast-type changing self.menuMainSettings.entryconfigure(menuItem,state=NORMAL) self.buttonCast.configure(text='Create 2nd Hexagram',command=self.BuildHex2) self.labelStatus.configure(text='Waiting to create 2nd hexagram ...') def CastAllLines(self,loadingSaveFile=0): self.buttonCast.configure(state=DISABLED) if loadingSaveFile: self.hexes.currentLine = 0 self.ShowQuestion() for line in self.hexLines[0]:#build and display hexagram 1 if loadingSaveFile: #increment the current line self.hexes.currentLine = self.hexes.currentLine + 1 self.CastLine(loadingFromFile=loadingSaveFile) self.master.update_idletasks() if not loadingSaveFile: time.sleep(1)#pause to let user see the thrown coins self.BuildHex2()#show second hexagram self.buttonCast.configure(state=NORMAL) #self.master.update_idletasks() def CastLine(self,loadingFromFile=0): if not loadingFromFile: self.hexes.NewLine() self.labelStatus.configure(text='Casting Line '+`self.hexes.currentLine`+' of 6 ...') #for spins in range(3): for spins in range(2): for frameNum in range(14): for coin in self.labelsCoins: coin.configure(image=self.images.coinFrames[frameNum]) self.master.update_idletasks() #time.sleep(0.06) #time.sleep(0.04) time.sleep(0.02) for i in range(3): self.labelsCoins[i].configure(image=self.images.coinFrames[self.hexes.currentOracleValues[i]+12]) self.master.update_idletasks() #self.hexes.hex1.lineValues[self.hexes.currentLine-1] = 8#debug!! if self.showPlaces.get():#if places should be shown self.labelsHexPlaces[self.hexes.currentLine-1].configure(fg=self.colors.fgLabelPlaces)#show the place name #self.__ShowLabel(self.labelsHexPlaces[self.hexes.currentLine-1])#show the place name self.hexLines[0][self.hexes.currentLine-1].Draw(self.hexes.hex1.lineValues[self.hexes.currentLine-1]) #if loadingFromFile: self.hexLines[0][self.hexes.currentLine-1].update() #self.master.update_idletasks() def BuildHex2(self): #if self.hexes.hex1.lineValues[5] != 0:#hex1 is fully built self.labelH1Title.configure(text=self.hexes.hex1.number+'. '+self.hexes.hex1.name) if self.hexes.hex2.lineValues[0] != 0:#if there were moving lines self.labelBecomes.configure(fg=self.colors.fgLabelLines)#show the 'becomes' label #self.__ShowLabel(self.labelBecomes)#show the 'becomes' label self.labelH2Title.configure(text=self.hexes.hex2.number+'. '+self.hexes.hex2.name) #self.hexes.hex2.lineValues = [0,0,0,0,0,0]#debug i = 0#a counter for line in self.hexLines[1]:#display hexagram 2 if self.hexes.hex2.lineValues[i] == 0:#empty hexagram 2 #for lines 3,4,5 display 'no, moving, lines' message if self.labelsNoMovingLines.has_key(i): self.labelsNoMovingLines[i].tkraise() #self.labelsNoMovingLines[i].update() #print self.labelsNoMovingLines[i].cget('text') #debug else:#hexagram2 has lines line.Draw(self.hexes.hex2.lineValues[i]) self.master.update_idletasks() i = i+1#increment counter self.labelStatus.configure(text='') self.labelLineHint.show = 1 #enable line hints for coin in self.labelsCoins:#blank coins display coin.configure(image=self.images.coinFrames[16]) if not self.castAll.get():#if we were casting a line at a time self.buttonCast.configure(text='Cast New Hexagram',command=self.CastHexes) self.ShowInfoButtons()#show the info buttons self.menuMainFile.entryconfigure(1,state=NORMAL)#enable save menuitem self.menuMainFile.entryconfigure(3,state=NORMAL)#enable save as text menuitem def MakeCastDisplay(self, parent): self.frameCast = Frame(parent,bg=self.colors.bgReading) self.frameCast.pack(anchor=NW,side=TOP)#,padx=20,pady=20 self.buttonCast = Button(self.frameCast,text='Cast New Hexagram',underline=0, width=20,bg=None,fg=None,font=self.fonts.button,highlightthickness=0, takefocus=FALSE,command=self.CastHexes) #self.buttonCast.focus_set() self.buttonCast.grid(column=0,row=0,sticky=NW,padx=20,pady=20) self.labelsCoins = [] for i in range(3): self.labelsCoins.append(Label(self.frameCast,image=self.images.coinFrames[16], bg=self.colors.bgReading) ) self.labelsCoins[i].grid(column=i+1,row=0,padx=10,pady=10) #the following widgets are not initially shown or enabled self.frameInfoButtons = Frame(self.frameCast,bg=self.colors.bgReading) self.buttonViewHex1Info = Button(self.frameInfoButtons,text=None,underline=0, width=30,bg=None,fg=None,font=self.fonts.button,highlightthickness=0, takefocus=FALSE,state=DISABLED,command=self.ViewHex1Info) self.buttonViewHex2Info = Button(self.frameInfoButtons,text=None,underline=1, width=30,bg=None,fg=None,font=self.fonts.button,highlightthickness=0, takefocus=FALSE,state=DISABLED,command=self.ViewHex2Info) def ShowInfoButtons(self): #show, setup and enable the required info buttons textStub = 'View information on: ' if self.hexes.hex2.lineValues[0] != 0:#there is a hex 2 self.buttonViewHex2Info.configure(text=textStub+self.hexes.hex2.number+ '. '+self.hexes.hex2.name,state=NORMAL) self.buttonViewHex2Info.grid(column=0,row=1) button1Pad = 5 else: self.buttonViewHex2Info.grid_forget() button1Pad = 15 self.buttonViewHex1Info.configure(text=textStub+self.hexes.hex1.number+ '. '+self.hexes.hex1.name,state=NORMAL) self.buttonViewHex1Info.grid(column=0,row=0,pady=button1Pad) self.frameInfoButtons.grid(column=1,row=0,columnspan=3,sticky=NW,pady=5) #self.frameInfoButtons.lift() def HideInfoButtons(self): #hide and disable the info buttons self.frameInfoButtons.grid_forget() self.buttonViewHex1Info.configure(state=DISABLED) self.buttonViewHex2Info.configure(state=DISABLED) def ViewHex1Info(self): self.ShowHtml(title='Hexagram Information - '+self.hexes.hex1.number+'. '+self.hexes.hex1.name, htmlSource=self.hexes.hex1.infoSource) def ViewHex2Info(self): self.ShowHtml(title='Hexagram Information - '+self.hexes.hex2.number+'. '+self.hexes.hex2.name, htmlSource=self.hexes.hex2.infoSource) def MakeHexDisplay(self, parent): self.frameHexes = Frame(parent,bg=self.colors.bgReading) self.frameHexes.pack(anchor=NW,side=TOP,padx=20) self.frameSpacerC4R1 = Frame(self.frameHexes,height=8,bg=self.colors.bgReading) self.frameSpacerC4R1.grid(column=4,row=1) self.labelsHexPlaces = [] labelsTexts = ('topmost','fifth','fourth','third','second','bottom') for labelNum in range(6): self.labelsHexPlaces.append(Label(self.frameHexes,text=labelsTexts[labelNum], bg=self.colors.bgReading,fg=self.colors.bgReading,font=self.fonts.label) )#fg=bg because label starts off hidden self.__HideLabel(self.labelsHexPlaces[labelNum]) self.labelsHexPlaces[labelNum].grid(column=0,row=labelNum+2,sticky=E) self.labelsHexPlaces.reverse()#puts the labels in order of appearance self.labelH1Title = Label(self.frameHexes,text='',bg=self.colors.bgReading, fg=self.colors.fgLabelHexTitles,font=self.fonts.labelHexTitles) self.labelH1Title.grid(column=1,row=0) self.labelH2Title = Label(self.frameHexes,text='',bg=self.colors.bgReading, fg=self.colors.fgLabelHexTitles,font=self.fonts.labelHexTitles) self.labelH2Title.grid(column=3,row=0) self.labelBecomes = Label(self.frameHexes,text='becomes',bg=self.colors.bgReading, fg=self.colors.bgReading,font=self.fonts.label)#fg=bg because label starts off hidden #self.__HideLabel(self.labelBecomes) self.labelBecomes.grid(column=2,row=4) #lineTexts = ('no','moving','lines')#lineTexts[key-3] self.labelsNoMovingLines = {3:'no',4:'moving',5:'lines'} for key in self.labelsNoMovingLines.keys(): self.labelsNoMovingLines[key] = Label(self.frameHexes, text=self.labelsNoMovingLines[key],bg=self.colors.bgReading, fg=self.colors.fgLabelLines,font=self.fonts.label) self.labelsNoMovingLines[key].grid(row=key,column=3) self.hexLines = ([],[]) for hexNum in range(2): for lineNum in range(6): self.hexLines[hexNum].append(HexLine(self.frameHexes, bindingEnter=self.ShowLineDetails,bindingLeave=self.ClearLineDetails, currentColors=self.colors)) if hexNum == 0: colNum = 1 else: colNum = 3 #set the corect grid column self.hexLines[hexNum][lineNum].grid(column=colNum,row=lineNum+2,padx=20,pady=1) self.hexLines[hexNum].reverse()#puts the labels in hex filling order self.frameSpacerC4R7 = Frame(self.frameHexes,width=20,bg=self.colors.bgReading) self.frameSpacerC4R7.grid(column=4,row=8) self.labelLineHint = Label(self.master,text=None,bg=self.colors.bgLabelHint, fg=self.colors.fgLabelHint,font=self.fonts.labelLineHint, borderwidth=1,relief=SOLID,padx=6) self.labelLineHint.place_forget() #add an attribute to the hint label to indicate if it can currently be #shown or not (eg. hints should not be shown during hex building). #this is independent of the user preference held in self.showLineHints . self.labelLineHint.show = 0 def ShowLineDetails(self,event): if self.labelLineHint.show and event.widget.hint: #if hints can be shown and there is a hint for the line self.labelStatus.configure(text=event.widget.hint)#show line details on the status line if self.showLineHints.get():#if the user wants to see line details hints, show them self.labelLineHint.configure(text=event.widget.hint) self.labelLineHint.place(relx=0.1,rely=1.0,x=2,y=2,in_=event.widget) #self.labelLineHint.tkraise() self.labelLineHint.update() def ClearLineDetails(self,event): if event.widget.hint: #if there's a hint for the line self.labelStatus.configure(text='') if self.showLineHints.get(): self.labelLineHint.configure(text=None) self.labelLineHint.place_forget() def MakeQuestionDisplay(self,parent): #print self.frameMain.winfo_width()#cget('width')#.winfo_width()#cget(key) self.frameQuestion=Frame(parent,bg=self.colors.bgReading,borderwidth=2) self.frameQuestion.pack(anchor=SW,side=BOTTOM,expand=TRUE,fill=X,padx=10,pady=5) self.messageQuestion = Message(self.frameQuestion,width=20,text=None,justify=LEFT, bg=self.colors.bgReading,fg=self.colors.fgMessageQuestion, font=self.fonts.label) self.messageQuestion.pack(anchor=W) def ShowQuestion(self): #self.frameQuestion.configure(relief=GROOVE) self.messageQuestion.configure(width=self.frameQuestion.winfo_width(), text=self.hexes.question) def HideQuestion(self): #self.frameQuestion.configure(relief=FLAT) self.messageQuestion.configure(width=20,text=None) def MakeStatusBar(self, parent): self.frameStatusBar = Frame(parent,borderwidth=2,relief=SUNKEN,highlightthickness=2) self.frameStatusBar.pack(anchor=SW,side=BOTTOM,fill=X,padx=2)#,expand=TRUE self.labelStatus = Label(self.frameStatusBar, text=pyching.title + ' ' + pyching.version,font=self.fonts.label) self.labelStatus.pack() #button for debug/testing purposes only #self.buttonDebug = Button(self.frameStatusBar,text='DEBUG',command=self.DEBUG) #self.buttonDebug.pack(anchor=E) def DEBUG(self): #run any routines in test or debug from here print 'begin debug\n' # print sys.path # print '\nend debug' def RepaintColors(self,newColors): oldColors=self.colors #save them for comparison below self.colors=newColors #these are always repainted self.frameMain.configure(bg=self.colors.bgReading) self.frameCast.configure(bg=self.colors.bgReading) for i in range(3): self.labelsCoins[i].configure(bg=self.colors.bgReading) self.frameHexes.configure(bg=self.colors.bgReading) self.frameInfoButtons.configure(bg=self.colors.bgReading) self.frameSpacerC4R1.configure(bg=self.colors.bgReading) self.frameSpacerC4R7.configure(bg=self.colors.bgReading) self.frameQuestion.configure(bg=self.colors.bgReading) self.labelLineHint.configure(bg=self.colors.bgLabelHint,fg=self.colors.fgLabelHint) self.messageQuestion.configure(bg=self.colors.bgReading,fg=self.colors.fgMessageQuestion) self.labelH1Title.configure(bg=self.colors.bgReading,fg=self.colors.fgLabelHexTitles) self.labelH2Title.configure(bg=self.colors.bgReading,fg=self.colors.fgLabelHexTitles) for key in self.labelsNoMovingLines.keys(): self.labelsNoMovingLines[key].configure(bg=self.colors.bgReading,fg=self.colors.fgLabelLines) #the backgrounds of these are always repainted for hexNum in range(2): for lineNum in range(6): self.hexLines[hexNum][lineNum].configure(bg=self.colors.bgReading) self.hexLines[hexNum][lineNum].colors = self.colors #so they will draw correctly next time #self.frameMain.update() #the backgrounds of these are always repainted, and fg=bg to hide them as #fg will be repainted in the correct color below if required for labelNum in range(6): self.labelsHexPlaces[labelNum].configure(bg=self.colors.bgReading,fg=self.colors.bgReading) self.labelBecomes.configure(bg=self.colors.bgReading,fg=self.colors.bgReading) #the foreground of these are only repainted here if a reading has been performed #otherwise they will paint in the new colors next time they are shown if self.hexes: #a reading has been performed if self.showPlaces.get():#if places should be shown for labelNum in range(6): self.labelsHexPlaces[labelNum].configure(fg=self.colors.fgLabelPlaces) if self.hexes.hex2.lineValues[0] != 0: #if there is a second hexagram self.labelBecomes.configure(fg=self.colors.fgLabelLines) #only redraw all lines now if their fg colors have changed if (oldColors.lineBody != self.colors.lineBody) or \ (oldColors.lineHighlight != self.colors.lineHighlight) or \ (oldColors.lineShadow != self.colors.lineShadow): for hexNum in range(2): for lineNum in range(6): self.hexLines[hexNum][lineNum].Draw(self.hexLines[hexNum][lineNum].value) elif oldColors.bgReading != self.colors.bgReading: #but if only the bg color has changed for hexNum in range(2): #repaint any 9 lines, to give the correct color in their inner circle for lineNum in range(6): if self.hexLines[hexNum][lineNum].value == 9: self.hexLines[hexNum][lineNum].Draw(self.hexLines[hexNum][lineNum].value) def SaveReading(self): fileName = tkFileDialog.asksaveasfilename(parent=self.master, title='Save Reading',defaultextension=pyching.saveFileExt, filetypes=[(pyching.title+' save files','*'+pyching.saveFileExt)], initialdir=pyching.savePath) #print fileName #debug if not fileName: return #user cancelled so get out #if not self.hexes: #we need an instance to work with # self.hexes = pyching_engine.Hexagrams() try: #pass self.hexes.Save(fileName) except IOError: #print '\n error: unable to write save file', fileName tkMessageBox.showerror(title='File Error', message='Unable to write save file:\n'+fileName) else: #print '\n saved file:', fileName self.labelStatus.configure(text='saved reading: '+fileName) def LoadReading(self): self.labelLineHint.show = 0 #disable line hints fileName = tkFileDialog.askopenfilename(parent=self.master, title='Load Saved Reading',defaultextension=pyching.saveFileExt, filetypes=[(pyching.title+' save files','*'+pyching.saveFileExt)], initialdir=pyching.savePath) #print fileName #debug if not fileName: self.labelLineHint.show = 1 #re-enable line hints return #user cancelled so get out tempHexes = pyching_engine.Hexagrams() try: saveFileID = tempHexes.Load(fileName) except IOError: #print '\n error: unable to read save file', fileName tkMessageBox.showerror(title='File Error', message='Unable to load save file:\n'+fileName) except 'pychingUnpickleError': #the file couldn't be unpickled, most likely it isn't a pickled file #print '\n error: unable to unpickle file', fileName tkMessageBox.showerror(title='Not A Save File', message='The file you attempted to load:\n\n'+fileName+\ '\n\nis not a '+pyching.title+' save file.') else: if not saveFileID[0] == pyching.saveFileID[0]: #this isn't a valid pyching savefile #print '\n invalid save file:', fileName tkMessageBox.showerror(title='Not A Save File', message='The file you attempted to load:\n\n'+fileName+\ '\n\nis not a '+pyching.title+' save file.') #elif not saveFileID[1] == pyching.saveFileID[1]: #savefile fails version check # pass #handle any savefile version issues here else: self.hexes = tempHexes self.ClearReading() self.CastAllLines(loadingSaveFile=1) self.labelStatus.configure(text='loaded reading: '+fileName) self.labelLineHint.show = 1 #re-enable line hints def SaveReadingAsText(self): fileName = tkFileDialog.asksaveasfilename(parent=self.master, title='Save Reading As Text',defaultextension='.txt', filetypes=[('text files','*.txt')], initialdir=pyching.savePath) if not fileName: return #user cancelled so get out textData = self.hexes.ReadingAsText() #print textData #debug try: textFile = open(fileName, 'w') except IOError: #print '\n error: unable to create text file', fileName tkMessageBox.showerror(title='File Error', message='Unable to create text file:\n'+fileName) else: #no exception, so proceed try: try: textFile.write(textData) except IOError: #print '\n error: unable to write text file', fileName tkMessageBox.showerror(title='File Error', message='Unable to write text file:\n'+fileName) finally: textFile.close() class HexLine(Canvas): """ creates a hexagram line object """ def __init__(self,parent,bindingEnter=None,bindingLeave=None,currentColors=None): self.value=None self.hint=None if currentColors: self.colors = currentColors else: self.colors = WidgetColors() Canvas.__init__(self,parent,height=25,width=145,bg=self.colors.bgReading, takefocus=FALSE,highlightthickness=0) #self.tag_bind('all','',bindingEnter)#when the mouse enters the drawing self.bind('',bindingEnter)#when the mouse enters the canvas self.bind('',bindingLeave)#when the mouse leaves the canvas def Draw(self,linetype=None): #draw the required linetype and set the relevant value and hint hints = {6: 'line value = 6 (moving yin)',7: 'line value = 7 (yang)', 8: 'line value = 8 (yin)',9: 'line value = 9 (moving yang)'} self.configure(bg=self.colors.bgReading) self.update() if linetype == 6: self.value=linetype self.hint=hints[linetype] self.DrawBevelRectangle(origin=(1,6),height=13,width=60) self.DrawBevelRectangle(origin=(84,6),height=13,width=60) self.DrawBevelX(origin=(62,2),height=20,width=20) elif linetype == 7: self.value=linetype self.hint=hints[linetype] self.DrawBevelRectangle(origin=(2,6),height=13,width=141) elif linetype == 8: self.value=linetype self.hint=hints[linetype] self.DrawBevelRectangle(origin=(2,6),height=13,width=60) self.DrawBevelRectangle(origin=(83,6),height=13,width=60) elif linetype == 9: self.value=linetype self.hint=hints[linetype] self.DrawBevelRectangle(origin=(2,6),height=13,width=60) self.DrawBevelRectangle(origin=(83,6),height=13,width=60) self.DrawBevelO(origin=(62,2),height=20,width=20) else: #blank the canvas (clear any existing drawing) self.value=None self.hint=None self.delete('all') def DrawBevelRectangle(self,origin=(0,0),height=13,width=0,bevel=2): color=self.colors.lineBody highlightcolor=self.colors.lineHighlight, shadowcolor=self.colors.lineShadow #fill with fg colour self.create_rectangle( ((origin[0],origin[1]), (origin[0]+width-1,origin[1]+height-1)),width=0, outline=color,fill=color,tags='BODY') #draw bevels for i in range(bevel): #draw highlight bevel if pyching.osType == 'nt': #allow for differences in tk canvas on win32 self.create_line( ((origin[0]+i,origin[1]+height-i-1), (origin[0]+i,origin[1]+i), (origin[0]+width-i,origin[1]+i)),width=1,fill=highlightcolor,tags='HIGHLIGHT') else: #just draw without above modifications self.create_line( ((origin[0]+i,origin[1]+height-i), (origin[0]+i,origin[1]+i), (origin[0]+width-i,origin[1]+i)),width=1,fill=highlightcolor,tags='HIGHLIGHT') #draw shadow bevel if pyching.osType == 'nt': #allow for differences in tk canvas on win32 self.create_line( ( (origin[0]+i+1,origin[1]+((height-i)-1)), (origin[0]+(width-i),origin[1]+((height-i)-1)) ), width=1,fill=shadowcolor,tags='SHADOW') self.create_line( ( (origin[0]+(width-i)-1,origin[1]+((height-i)-1)), (origin[0]+(width-i)-1,origin[1]+i) ), width=1,fill=shadowcolor,tags='SHADOW') else: #just draw without above modifications self.create_line( ( (origin[0]+i+1,origin[1]+((height-i)-1)), (origin[0]+(width-i),origin[1]+((height-i)-1)) ), width=1,fill=shadowcolor,tags='SHADOW') self.create_line( ( (origin[0]+(width-i)-1,origin[1]+((height-i)-1)), (origin[0]+(width-i)-1,origin[1]+i+1) ), width=1,fill=shadowcolor,tags='SHADOW') def DrawBevelX(self,origin=(0,0),height=0,width=0,thickness=4): color=self.colors.lineBody highlightcolor=self.colors.lineHighlight, shadowcolor=self.colors.lineShadow #filled cross with shadowcolor outline centre = ( origin[0]+width/2 , origin[1]+height/2 ) iCO = thickness/2+2 #insideCornerOffset self.create_polygon(( ( origin[0]+thickness , origin[1] ), ( centre[0] , centre[1]-iCO ), ( origin[0]+width-thickness , origin[1] ), ( origin[0]+width , origin[1]+thickness ), ( centre[0]+iCO , centre[1] ), ( origin[0]+width , origin[1]+height-thickness ), ( origin[0]+width-thickness , origin[1]+height ), ( centre[0] , centre[1]+iCO ), ( origin[0]+thickness , origin[1]+height ), ( origin[0] , origin[1]+height-thickness ), ( centre[0]-iCO , centre[1] ), ( origin[0] , origin[1]+thickness ) ), outline=shadowcolor,width=1,fill=color,tags='BODY') #pad the shadow to bevel width self.create_line( ( ( origin[0] +2, origin[1]+thickness +1), ( centre[0]-iCO +1, centre[1] ) ), width=1,fill=shadowcolor,tags='SHADOW') self.create_line( ( ( centre[0]+iCO , centre[1] -1), ( origin[0]+width -1, origin[1]+thickness) ), width=1,fill=shadowcolor,tags='SHADOW') self.create_line( ( ( origin[0] +2, origin[1]+height-thickness +1), ( origin[0]+thickness , origin[1]+height -1), ( centre[0] , centre[1]+iCO -1), ( origin[0]+width-thickness , origin[1]+height -1), ( origin[0]+width -1, origin[1]+height-thickness) ), width=1,fill=shadowcolor,tags='SHADOW') #add the highlight self.create_line( ( ( origin[0] , origin[1]+height-thickness ), ( centre[0]-iCO +1 , centre[1] -1 ) ), width=1,fill=highlightcolor,tags='HIGHLIGHT') self.create_line( ( ( origin[0] +1, origin[1]+height-thickness ), ( centre[0]-iCO +1 +1, centre[1] -1 ) ), width=1,fill=highlightcolor,tags='HIGHLIGHT') self.create_line( ( ( centre[0]+iCO , centre[1] ), ( origin[0]+width +1 , origin[1]+height-thickness +1 ) ), width=1,fill=highlightcolor,tags='HIGHLIGHT') self.create_line( ( ( centre[0]+iCO -1, centre[1] ), ( origin[0]+width, origin[1]+height-thickness +1) ), width=1,fill=highlightcolor,tags='HIGHLIGHT') self.create_line( ( ( origin[0] , origin[1]+thickness ), ( origin[0]+thickness , origin[1] ), ( centre[0] , centre[1]-iCO ), ( origin[0]+width-thickness , origin[1] ), ( origin[0]+width +1 , origin[1]+thickness +1 ) ), width=1,fill=highlightcolor,tags='HIGHLIGHT') self.create_line( ( ( origin[0] +1 , origin[1]+thickness ), ( origin[0]+thickness , origin[1] +1), ( centre[0] , centre[1]-iCO +1), ( origin[0]+width-thickness , origin[1] +1), ( origin[0]+width , origin[1]+thickness +1 ) ), width=1,fill=highlightcolor,tags='HIGHLIGHT') def DrawBevelO(self,origin=(0,0),height=0,width=0,thickness=4): color=self.colors.lineBody highlightcolor=self.colors.lineHighlight, shadowcolor=self.colors.lineShadow #draw filled O with shadowcolor border self.create_oval( ( ( origin[0] , origin[1] ), ( origin[0]+width , origin[1]+height ) ), outline=shadowcolor,width=1,fill=shadowcolor) self.create_oval( ( ( origin[0]+1 , origin[1]+1 ), ( origin[0]+width-1 , origin[1]+height-1 ) ), outline=shadowcolor,width=1,fill=color,tags='BODY')#,fill=color #draw central O with shadowcolor border self.create_oval( ( ( origin[0]+thickness+1 , origin[1]+thickness+1 ), ( origin[0]+width-thickness-1 , origin[1]+height-thickness-1) ), outline=shadowcolor,width=1,fill=shadowcolor) self.create_oval( ( ( origin[0]+thickness+2 , origin[1]+thickness+2 ), ( origin[0]+width-thickness-2 , origin[1]+height-thickness-2) ), outline=shadowcolor,width=1,fill=self.cget('bg'),tags='SHADOW')#,fill='DarkGray' #add highlights #top self.create_arc( ( ( origin[0] , origin[1] ), ( origin[0]+width , origin[1]+height ) ), start=40,extent=180, style='arc',width=1,outline=highlightcolor,tags='HIGHLIGHT')#'red' self.create_arc( ( ( origin[0]+1 , origin[1]+1 ), ( origin[0]+width-1 , origin[1]+height-1 ) ), start=35,extent=180, style='arc',width=1,outline=highlightcolor,tags='HIGHLIGHT')#'black' highlightcolor #lower inside self.create_arc( ( ( origin[0]+thickness+1 , origin[1]+thickness+1 ), ( origin[0]+width-thickness-1 , origin[1]+height-thickness-1) ), start=220,extent=180, style='arc',width=1,outline=highlightcolor,tags='HIGHLIGHT')#'red' self.create_arc( ( ( origin[0]+thickness+2 , origin[1]+thickness+2 ), ( origin[0]+width-thickness-2 , origin[1]+height-thickness-2) ), start=215,extent=180, style='arc',width=1,outline=highlightcolor,tags='HIGHLIGHT')#'black' #patch the highlight drawing to compensate for #differences(!) in behaviour of tk canvas on win32 if pyching.osType == 'nt': self.create_line( ( (origin[0]+1 , origin[1]+13), (origin[0]+1 , origin[1]+6), (origin[0]+6 , origin[1]+1), (origin[0]+8 , origin[1]+1), (origin[0]+14 , origin[1]+1), (origin[0]+16 , origin[1]+3) ), width=1,fill=highlightcolor,tags='HIGHLIGHT') self.create_line( ( (origin[0]+7 , origin[1]+13), (origin[0]+8 , origin[1]+14), (origin[0]+12 , origin[1]+14), (origin[0]+15 , origin[1]+11) ), width=1,fill=highlightcolor,tags='HIGHLIGHT') class DialogSetColors(smgDialog): """ display a colour configuration dialog """ def __init__(self,parent,currentColors=None): if currentColors: self.colors=currentColors else: self.colors=WidgetColors() self.fonts=WidgetFonts() smgDialog.__init__(self,parent,title='Configure Colors', buttons=[{'name':'buttonOk','title':'Ok','binding':'Ok','underline':None,'hotKey':''}, {'name':'buttonCancel','title':'Cancel','binding':'Cancel','underline':None,'hotKey':''}], buttonsDef=-1, buttonsWidth=0,buttonsPad=5, resizeable=0, transient=1, wait=1)#buttonsPos='BOTTOM', def Body(self,master): master.configure(borderwidth=2,relief=SUNKEN,highlightthickness=4) self.frameDemo = Frame(master,bg=self.colors.bgReading,borderwidth=2,relief=FLAT) self.frameDemo.grid(row=1,column=0,padx=0,pady=10) self.frameDemo.bind('',self.SetColorExampleDetails) self.labelTitleDemo = Label(self.frameDemo,text='Hexagram Title', font=self.fonts.labelHexTitles,borderwidth=0, fg=self.colors.fgLabelHexTitles,bg=self.colors.bgReading) self.labelTitleDemo.grid(row=0,column=0,pady=5) self.labelTitleDemo.bind('',self.SetColorExampleDetails) self.lineDemos = [] for i in range(4): self.lineDemos.append(HexLine(self.frameDemo,currentColors=self.colors)) #self.lineDemos[i].colors = self.colors self.lineDemos[i].Draw(linetype=i +6) self.lineDemos[i].grid(row=i+1,column=0,padx=10) self.lineDemos[i].bind('',self.SetColorExampleDetails) #self.tag_bind('BODY','',self.SetColorExampleDetails) #self.tag_bind('HIGHLIGHT','',self.SetColorExampleDetails) #self.tag_bind('SHADOW','',self.SetColorExampleDetails) self.labelQuestionDemo = Label(self.frameDemo,text='Reading Question', font=self.fonts.label,borderwidth=0, fg=self.colors.fgMessageQuestion,bg=self.colors.bgReading) self.labelQuestionDemo.grid(row=5,column=0,pady=5) self.labelQuestionDemo.bind('',self.SetColorExampleDetails) self.labelPlaceDemo = Label(self.frameDemo,text='place name', font=self.fonts.label,borderwidth=0, fg=self.colors.fgLabelPlaces,bg=self.colors.bgReading) self.labelPlaceDemo.grid(row=1,column=1,padx=5) self.labelPlaceDemo.bind('',self.SetColorExampleDetails) self.labelBecomesDemo = Label(self.frameDemo,text='becomes', font=self.fonts.label,borderwidth=0, fg=self.colors.fgLabelLines,bg=self.colors.bgReading) self.labelBecomesDemo.grid(row=2,column=1,padx=5) self.labelBecomesDemo.bind('',self.SetColorExampleDetails) self.labelNoMovingDemo = Label(self.frameDemo,text='no moving lines', font=self.fonts.label,borderwidth=0, fg=self.colors.fgLabelLines,bg=self.colors.bgReading) self.labelNoMovingDemo.grid(row=3,column=1,padx=5) self.labelNoMovingDemo.bind('',self.SetColorExampleDetails) self.frameHintBgDemo = Label(self.frameDemo,text='line hint', font=self.fonts.labelLineHint,relief=SOLID,borderwidth=1, bg=self.colors.bgLabelHint) self.frameHintBgDemo.grid(row=4,column=1,sticky=(N,S,E,W),padx=5)#padx=5 self.frameHintBgDemo.bind('',self.SetColorExampleDetails) self.labelHintDemo = Label(self.frameHintBgDemo,text='line hint', font=self.fonts.labelLineHint,borderwidth=0, fg=self.colors.fgLabelHint,bg=self.colors.bgLabelHint) self.labelHintDemo.grid(row=0,column=0) self.labelHintDemo.bind('',self.SetColorExampleDetails) self.SetColorButtonDetails() self.colorExampleDetails = { 'name': self.colorButtonDetails[0][0], 'color': self.colorButtonDetails[0][1] } self.frameColorSelect = Frame(master,bg=self.colorExampleDetails['color'], relief=SOLID,borderwidth=1) self.frameColorSelect.grid(row=0,column=0,padx=10,pady=10,ipadx=10,ipady=10) self.buttonGetColor = Button(self.frameColorSelect,text='Set Color of:', underline=0,highlightthickness=0,font=self.fonts.button, takefocus=FALSE,command=self.GetColor) self.buttonGetColor.grid(row=0,column=0,padx=2) self.menubuttonOptions = Menubutton(self.frameColorSelect,width=32, text=self.colorButtonDetails[0][0],font=self.fonts.menu,indicatoron=TRUE, underline=string.find(self.colorButtonDetails[0][0],'e'), relief=RAISED,highlightthickness=0) self.menubuttonOptions.grid(row=0,column=1,padx=2,sticky=(N,S))#sticky=(N,S) makes the menubutton the smae height as buttonGetCOlor self.menuOptions = Menu(self.menubuttonOptions,tearoff=0,font=self.fonts.menu) self.menubuttonOptions.configure(menu=self.menuOptions) for item in self.colorButtonDetails: #build the menu self.menuOptions.add_command(label=item[0],command=self.SetColorExample) #self.menuOptions.bind('<>',self.SetColorExampleDetails) self.buttonDefaults = Button(master, text='Reset All Colors To '+pyching.title+' Defaults', underline=0,highlightthickness=0,font=self.fonts.button, takefocus=FALSE,command=self.SetDefaultColors) self.buttonDefaults.grid(row=2,column=0,padx=10,pady=10,sticky=(W,E)) #return self.menubuttonOptions #control for initial focus #hot key bindings for this dialog self.bind('',self.SetColorButtonBinding) #set color button self.bind('',self.ScreenElementButtonBinding) #screen element selection button self.bind('',self.ResetColorsButtonBinding) #reset default colors button def SetColorButtonBinding(self,event): self.buttonGetColor.invoke() def ScreenElementButtonBinding(self,event): #self.menubuttonOptions.invoke() #print self.menubuttonOptions.winfo_rootx(),self.menubuttonOptions.winfo_rooty(),\ # self.menubuttonOptions.winfo_height() #debug self.menuOptions.post(self.menubuttonOptions.winfo_rootx(), self.menubuttonOptions.winfo_rooty()+self.menubuttonOptions.winfo_height()) #self.menuOptions.tk_mbPost() def ResetColorsButtonBinding(self,event): self.buttonDefaults.invoke() def SetColorButtonDetails(self): self.colorButtonDetails=( ('Reading Background',self.colors.bgReading), ('Hexagram Titles',self.colors.fgLabelHexTitles), ('Reading Question',self.colors.fgMessageQuestion), ('Place Names',self.colors.fgLabelPlaces), ("'becomes' & 'no moving lines'",self.colors.fgLabelLines), ('Line Hint Background',self.colors.bgLabelHint), ('Line Hint Text',self.colors.fgLabelHint), ('Hexagram Line Body',self.colors.lineBody), ('Hexagram Line Highlight',self.colors.lineHighlight), ('Hexagram Line Shadow',self.colors.lineShadow) ) def SetColorExampleDetails(self,event): if event.widget == self.frameDemo: self.colorExampleDetails['name']=self.colorButtonDetails[0][0] self.colorExampleDetails['color']=self.colorButtonDetails[0][1] elif event.widget == self.labelTitleDemo: self.colorExampleDetails['name']=self.colorButtonDetails[1][0] self.colorExampleDetails['color']=self.colorButtonDetails[1][1] elif event.widget == self.labelQuestionDemo: self.colorExampleDetails['name']=self.colorButtonDetails[2][0] self.colorExampleDetails['color']=self.colorButtonDetails[2][1] elif event.widget == self.labelPlaceDemo: self.colorExampleDetails['name']=self.colorButtonDetails[3][0] self.colorExampleDetails['color']=self.colorButtonDetails[3][1] elif event.widget == self.labelBecomesDemo: self.colorExampleDetails['name']=self.colorButtonDetails[4][0] self.colorExampleDetails['color']=self.colorButtonDetails[4][1] elif event.widget == self.labelNoMovingDemo: self.colorExampleDetails['name']=self.colorButtonDetails[4][0] self.colorExampleDetails['color']=self.colorButtonDetails[4][1] elif event.widget == self.frameHintBgDemo: self.colorExampleDetails['name']=self.colorButtonDetails[5][0] self.colorExampleDetails['color']=self.colorButtonDetails[5][1] elif event.widget == self.labelHintDemo: self.colorExampleDetails['name']=self.colorButtonDetails[6][0] self.colorExampleDetails['color']=self.colorButtonDetails[6][1] elif event.widget in self.lineDemos: tags = string.split(event.widget.itemcget('current','tags')) #print tags if 'SHADOW' in tags: self.colorExampleDetails['name']=self.colorButtonDetails[9][0] self.colorExampleDetails['color']=self.colorButtonDetails[9][1] elif 'HIGHLIGHT' in tags: self.colorExampleDetails['name']=self.colorButtonDetails[8][0] self.colorExampleDetails['color']=self.colorButtonDetails[8][1] elif 'BODY' in tags: self.colorExampleDetails['name']=self.colorButtonDetails[7][0] self.colorExampleDetails['color']=self.colorButtonDetails[7][1] else: #background clicked self.colorExampleDetails['name']=self.colorButtonDetails[0][0] self.colorExampleDetails['color']=self.colorButtonDetails[0][1] self.SetColorExample() def SetColorExample(self): #print 'active menuitem is:',self.menuOptions.index('active') #debug if self.menuOptions.index('active') != None: #if this routine was called by self.menuOptions self.colorExampleDetails['name']=self.colorButtonDetails[self.menuOptions.index('active')][0] self.colorExampleDetails['color']=self.colorButtonDetails[self.menuOptions.index('active')][1] self.menubuttonOptions.configure(text=self.colorExampleDetails['name'], underline=string.find(self.colorExampleDetails['name'],'e')) self.frameColorSelect.configure(bg=self.colorExampleDetails['color']) def GetColor(self): rgbTuplet, colorString = tkColorChooser.askcolor(parent=self, title='Pick a new colour for: '+self.colorExampleDetails['name'], initialcolor=self.colorExampleDetails['color'])#._root() if colorString: #user didn't cancel self.frameDemo.update() #redraw after dialog #print 'GetColor colorString =',colorString self.colorExampleDetails['color']=colorString self.frameColorSelect.configure(bg=colorString) self.UpdateColors() self.RepaintColors() #self.frameDemo.update() #redraw new colors def UpdateColors(self): if self.colorExampleDetails['name'] == self.colorButtonDetails[0][0]: self.colors.bgReading = self.colorExampleDetails['color'] elif self.colorExampleDetails['name'] == self.colorButtonDetails[1][0]: self.colors.fgLabelHexTitles = self.colorExampleDetails['color'] elif self.colorExampleDetails['name'] == self.colorButtonDetails[2][0]: self.colors.fgMessageQuestion = self.colorExampleDetails['color'] elif self.colorExampleDetails['name'] == self.colorButtonDetails[3][0]: self.colors.fgLabelPlaces = self.colorExampleDetails['color'] elif self.colorExampleDetails['name'] == self.colorButtonDetails[4][0]: self.colors.fgLabelLines = self.colorExampleDetails['color'] elif self.colorExampleDetails['name'] == self.colorButtonDetails[5][0]: self.colors.bgLabelHint = self.colorExampleDetails['color'] elif self.colorExampleDetails['name'] == self.colorButtonDetails[6][0]: self.colors.fgLabelHint = self.colorExampleDetails['color'] elif self.colorExampleDetails['name'] == self.colorButtonDetails[7][0]: self.colors.lineBody = self.colorExampleDetails['color'] elif self.colorExampleDetails['name'] == self.colorButtonDetails[8][0]: self.colors.lineHighlight = self.colorExampleDetails['color'] elif self.colorExampleDetails['name'] == self.colorButtonDetails[9][0]: self.colors.lineShadow = self.colorExampleDetails['color'] def RepaintColors(self): #print 'ConfigureWidgetCustomColors frameDemo bg was =',self.frameDemo.cget('bg') self.frameDemo.configure(bg=self.colors.bgReading) #print 'ConfigureWidgetCustomColors frameDemo bg is =',self.frameDemo.cget('bg') self.labelTitleDemo.configure(fg=self.colors.fgLabelHexTitles,bg=self.colors.bgReading) self.labelQuestionDemo.configure(fg=self.colors.fgMessageQuestion,bg=self.colors.bgReading) self.labelPlaceDemo.configure(fg=self.colors.fgLabelPlaces,bg=self.colors.bgReading) self.labelBecomesDemo.configure(fg=self.colors.fgLabelLines,bg=self.colors.bgReading) self.labelNoMovingDemo.configure(fg=self.colors.fgLabelLines,bg=self.colors.bgReading) self.frameHintBgDemo.configure(bg=self.colors.bgLabelHint) self.labelHintDemo.configure(fg=self.colors.fgLabelHint,bg=self.colors.bgLabelHint) self.frameDemo.update() for item in self.lineDemos: #item.configure(bg=self.colors.bgReading) item.colors = self.colors item.Draw(linetype=item.value) self.SetColorButtonDetails() def SetDefaultColors(self): self.colors=WidgetColors() self.RepaintColors() self.colorExampleDetails['name']=self.colorButtonDetails[0][0] self.colorExampleDetails['color']=self.colorButtonDetails[0][1] self.SetColorExample() def Apply(self): self.result = self.colors class DialogGetQuestion(smgDialog): """ gets the question for a reading """ def __init__(self,parent): smgDialog.__init__(self,parent,title='Enter Question', buttons=[{'name':'buttonOk','title':'Ok','binding':'Ok','underline':None,'hotKey':''}, {'name':'buttonCancel','title':'Cancel','binding':'Cancel','underline':None,'hotKey':''}], buttonsDef=-1,buttonsWidth=0,buttonsPad=5, resizeable=0, transient=1, wait=1) # buttonsPos='BOTTOM', def Body(self,master): labelPrompt = Label(master,text='Enter a question to ask the I Ching (maximum 70 characters):', ).grid(column=0,row=0,sticky=W,padx=5,pady=5) self.questionText = StringVar() self.questionText.set('Tell me about my current circumstances.') self.entryQuestion = Entry(master,textvariable=self.questionText,width=70) self.entryQuestion.grid(column=0,row=1,sticky=W,padx=5) return self.entryQuestion def Apply(self): self.result = self.questionText.get() def Validate(self): if len(self.questionText.get()) > 70:#question too long tkMessageBox.showerror(title='Question Too Long', message='The question you have entered is longer than 70 characters.') return 0 elif len(string.strip(self.questionText.get())) == 0:#null question tkMessageBox.showerror(title='No Question Entered', message='You have entered a blank question.') return 0 else: return 1 #create an instance of the app details for use throughout this module pyching = pyching_engine.PychingAppDetails() windowRoot = Tk() windowMain = WindowMain(windowRoot) windowRoot.mainloop()