PyXR

c:\python24\lib \ idlelib \ keybindingDialog.py



0001 """
0002 Dialog for building Tkinter accelerator key bindings
0003 """
0004 from Tkinter import *
0005 import tkMessageBox
0006 import string, os
0007 
0008 class GetKeysDialog(Toplevel):
0009     def __init__(self,parent,title,action,currentKeySequences):
0010         """
0011         action - string, the name of the virtual event these keys will be
0012                  mapped to
0013         currentKeys - list, a list of all key sequence lists currently mapped
0014                  to virtual events, for overlap checking
0015         """
0016         Toplevel.__init__(self, parent)
0017         self.configure(borderwidth=5)
0018         self.resizable(height=FALSE,width=FALSE)
0019         self.title(title)
0020         self.transient(parent)
0021         self.grab_set()
0022         self.protocol("WM_DELETE_WINDOW", self.Cancel)
0023         self.parent = parent
0024         self.action=action
0025         self.currentKeySequences=currentKeySequences
0026         self.result=''
0027         self.keyString=StringVar(self)
0028         self.keyString.set('')
0029         self.SetModifiersForPlatform()
0030         self.modifier_vars = []
0031         for modifier in self.modifiers:
0032             variable = StringVar(self)
0033             variable.set('')
0034             self.modifier_vars.append(variable)
0035         self.CreateWidgets()
0036         self.LoadFinalKeyList()
0037         self.withdraw() #hide while setting geometry
0038         self.update_idletasks()
0039         self.geometry("+%d+%d" %
0040             ((parent.winfo_rootx()+((parent.winfo_width()/2)
0041                 -(self.winfo_reqwidth()/2)),
0042               parent.winfo_rooty()+((parent.winfo_height()/2)
0043                 -(self.winfo_reqheight()/2)) )) ) #centre dialog over parent
0044         self.deiconify() #geometry set, unhide
0045         self.wait_window()
0046 
0047     def CreateWidgets(self):
0048         frameMain = Frame(self,borderwidth=2,relief=SUNKEN)
0049         frameMain.pack(side=TOP,expand=TRUE,fill=BOTH)
0050         frameButtons=Frame(self)
0051         frameButtons.pack(side=BOTTOM,fill=X)
0052         self.buttonOK = Button(frameButtons,text='OK',
0053                 width=8,command=self.OK)
0054         self.buttonOK.grid(row=0,column=0,padx=5,pady=5)
0055         self.buttonCancel = Button(frameButtons,text='Cancel',
0056                 width=8,command=self.Cancel)
0057         self.buttonCancel.grid(row=0,column=1,padx=5,pady=5)
0058         self.frameKeySeqBasic = Frame(frameMain)
0059         self.frameKeySeqAdvanced = Frame(frameMain)
0060         self.frameControlsBasic = Frame(frameMain)
0061         self.frameHelpAdvanced = Frame(frameMain)
0062         self.frameKeySeqAdvanced.grid(row=0,column=0,sticky=NSEW,padx=5,pady=5)
0063         self.frameKeySeqBasic.grid(row=0,column=0,sticky=NSEW,padx=5,pady=5)
0064         self.frameKeySeqBasic.lift()
0065         self.frameHelpAdvanced.grid(row=1,column=0,sticky=NSEW,padx=5)
0066         self.frameControlsBasic.grid(row=1,column=0,sticky=NSEW,padx=5)
0067         self.frameControlsBasic.lift()
0068         self.buttonLevel = Button(frameMain,command=self.ToggleLevel,
0069                 text='Advanced Key Binding Entry >>')
0070         self.buttonLevel.grid(row=2,column=0,stick=EW,padx=5,pady=5)
0071         labelTitleBasic = Label(self.frameKeySeqBasic,
0072                 text="New keys for  '"+self.action+"' :")
0073         labelTitleBasic.pack(anchor=W)
0074         labelKeysBasic = Label(self.frameKeySeqBasic,justify=LEFT,
0075                 textvariable=self.keyString,relief=GROOVE,borderwidth=2)
0076         labelKeysBasic.pack(ipadx=5,ipady=5,fill=X)
0077         self.modifier_checkbuttons = {}
0078         column = 0
0079         for modifier, variable in zip(self.modifiers, self.modifier_vars):
0080             label = self.modifier_label.get(modifier, modifier)
0081             check=Checkbutton(self.frameControlsBasic,
0082                 command=self.BuildKeyString,
0083                 text=label,variable=variable,onvalue=modifier,offvalue='')
0084             check.grid(row=0,column=column,padx=2,sticky=W)
0085             self.modifier_checkbuttons[modifier] = check
0086             column += 1
0087         labelFnAdvice=Label(self.frameControlsBasic,justify=LEFT,
0088                             text=\
0089                             "Select the desired modifier keys\n"+
0090                             "above, and the final key from the\n"+
0091                             "list on the right.\n\n" +
0092                             "Use upper case Symbols when using\n" +
0093                             "the Shift modifier.  (Letters will be\n" +
0094                             "converted automatically.)")
0095         labelFnAdvice.grid(row=1,column=0,columnspan=4,padx=2,sticky=W)
0096         self.listKeysFinal=Listbox(self.frameControlsBasic,width=15,height=10,
0097                 selectmode=SINGLE)
0098         self.listKeysFinal.bind('<ButtonRelease-1>',self.FinalKeySelected)
0099         self.listKeysFinal.grid(row=0,column=4,rowspan=4,sticky=NS)
0100         scrollKeysFinal=Scrollbar(self.frameControlsBasic,orient=VERTICAL,
0101                 command=self.listKeysFinal.yview)
0102         self.listKeysFinal.config(yscrollcommand=scrollKeysFinal.set)
0103         scrollKeysFinal.grid(row=0,column=5,rowspan=4,sticky=NS)
0104         self.buttonClear=Button(self.frameControlsBasic,
0105                 text='Clear Keys',command=self.ClearKeySeq)
0106         self.buttonClear.grid(row=2,column=0,columnspan=4)
0107         labelTitleAdvanced = Label(self.frameKeySeqAdvanced,justify=LEFT,
0108                 text="Enter new binding(s) for  '"+self.action+"' :\n"+
0109                 "(These bindings will not be checked for validity!)")
0110         labelTitleAdvanced.pack(anchor=W)
0111         self.entryKeysAdvanced=Entry(self.frameKeySeqAdvanced,
0112                 textvariable=self.keyString)
0113         self.entryKeysAdvanced.pack(fill=X)
0114         labelHelpAdvanced=Label(self.frameHelpAdvanced,justify=LEFT,
0115             text="Key bindings are specified using Tkinter keysyms as\n"+
0116                  "in these samples: <Control-f>, <Shift-F2>, <F12>,\n"
0117                  "<Control-space>, <Meta-less>, <Control-Alt-Shift-X>.\n"
0118                  "Upper case is used when the Shift modifier is present!\n\n" +
0119                  "'Emacs style' multi-keystroke bindings are specified as\n" +
0120                  "follows: <Control-x><Control-y>, where the first key\n" +
0121                  "is the 'do-nothing' keybinding.\n\n" +
0122                  "Multiple separate bindings for one action should be\n"+
0123                  "separated by a space, eg., <Alt-v> <Meta-v>." )
0124         labelHelpAdvanced.grid(row=0,column=0,sticky=NSEW)
0125 
0126     def SetModifiersForPlatform(self):
0127         """Determine list of names of key modifiers for this platform.
0128 
0129         The names are used to build Tk bindings -- it doesn't matter if the
0130         keyboard has these keys, it matters if Tk understands them. The
0131         order is also important: key binding equality depends on it, so
0132         config-keys.def must use the same ordering.
0133         """
0134         import sys
0135         if sys.platform == 'darwin' and sys.executable.count('.app'):
0136             self.modifiers = ['Shift', 'Control', 'Option', 'Command']
0137         else:
0138             self.modifiers = ['Control', 'Alt', 'Shift']
0139         self.modifier_label = {'Control': 'Ctrl'}
0140 
0141     def ToggleLevel(self):
0142         if  self.buttonLevel.cget('text')[:8]=='Advanced':
0143             self.ClearKeySeq()
0144             self.buttonLevel.config(text='<< Basic Key Binding Entry')
0145             self.frameKeySeqAdvanced.lift()
0146             self.frameHelpAdvanced.lift()
0147             self.entryKeysAdvanced.focus_set()
0148         else:
0149             self.ClearKeySeq()
0150             self.buttonLevel.config(text='Advanced Key Binding Entry >>')
0151             self.frameKeySeqBasic.lift()
0152             self.frameControlsBasic.lift()
0153 
0154     def FinalKeySelected(self,event):
0155         self.BuildKeyString()
0156 
0157     def BuildKeyString(self):
0158         keyList = modifiers = self.GetModifiers()
0159         finalKey = self.listKeysFinal.get(ANCHOR)
0160         if finalKey:
0161             finalKey = self.TranslateKey(finalKey, modifiers)
0162             keyList.append(finalKey)
0163         self.keyString.set('<' + string.join(keyList,'-') + '>')
0164 
0165     def GetModifiers(self):
0166         modList = [variable.get() for variable in self.modifier_vars]
0167         return filter(None, modList)
0168 
0169     def ClearKeySeq(self):
0170         self.listKeysFinal.select_clear(0,END)
0171         self.listKeysFinal.yview(MOVETO, '0.0')
0172         for variable in self.modifier_vars:
0173             variable.set('')
0174         self.keyString.set('')
0175 
0176     def LoadFinalKeyList(self):
0177         #these tuples are also available for use in validity checks
0178         self.functionKeys=('F1','F2','F2','F4','F5','F6','F7','F8','F9',
0179                 'F10','F11','F12')
0180         self.alphanumKeys=tuple(string.ascii_lowercase+string.digits)
0181         self.punctuationKeys=tuple('~!@#%^&*()_-+={}[]|;:,.<>/?')
0182         self.whitespaceKeys=('Tab','Space','Return')
0183         self.editKeys=('BackSpace','Delete','Insert')
0184         self.moveKeys=('Home','End','Page Up','Page Down','Left Arrow',
0185                 'Right Arrow','Up Arrow','Down Arrow')
0186         #make a tuple of most of the useful common 'final' keys
0187         keys=(self.alphanumKeys+self.punctuationKeys+self.functionKeys+
0188                 self.whitespaceKeys+self.editKeys+self.moveKeys)
0189         self.listKeysFinal.insert(END, *keys)
0190 
0191     def TranslateKey(self, key, modifiers):
0192         "Translate from keycap symbol to the Tkinter keysym"
0193         translateDict = {'Space':'space',
0194                 '~':'asciitilde','!':'exclam','@':'at','#':'numbersign',
0195                 '%':'percent','^':'asciicircum','&':'ampersand','*':'asterisk',
0196                 '(':'parenleft',')':'parenright','_':'underscore','-':'minus',
0197                 '+':'plus','=':'equal','{':'braceleft','}':'braceright',
0198                 '[':'bracketleft',']':'bracketright','|':'bar',';':'semicolon',
0199                 ':':'colon',',':'comma','.':'period','<':'less','>':'greater',
0200                 '/':'slash','?':'question','Page Up':'Prior','Page Down':'Next',
0201                 'Left Arrow':'Left','Right Arrow':'Right','Up Arrow':'Up',
0202                 'Down Arrow': 'Down', 'Tab':'tab'}
0203         if key in translateDict.keys():
0204             key = translateDict[key]
0205         if 'Shift' in modifiers and key in string.ascii_lowercase:
0206             key = key.upper()
0207         key = 'Key-' + key
0208         return key
0209 
0210     def OK(self, event=None):
0211         if self.KeysOK():
0212             self.result=self.keyString.get()
0213             self.destroy()
0214 
0215     def Cancel(self, event=None):
0216         self.result=''
0217         self.destroy()
0218 
0219     def KeysOK(self):
0220         "Validity check on user's keybinding selection"
0221         keys = self.keyString.get()
0222         keys.strip()
0223         finalKey = self.listKeysFinal.get(ANCHOR)
0224         modifiers = self.GetModifiers()
0225         # create a key sequence list for overlap check:
0226         keySequence = keys.split()
0227         keysOK = False
0228         title = 'Key Sequence Error'
0229         if not keys:
0230             tkMessageBox.showerror(title=title, parent=self,
0231                                    message='No keys specified.')
0232         elif not keys.endswith('>'):
0233             tkMessageBox.showerror(title=title, parent=self,
0234                                    message='Missing the final Key')
0235         elif not modifiers and finalKey not in self.functionKeys:
0236             tkMessageBox.showerror(title=title, parent=self,
0237                                    message='No modifier key(s) specified.')
0238         elif (modifiers == ['Shift']) \
0239                  and (finalKey not in
0240                       self.functionKeys + ('Tab', 'Space')):
0241             msg = 'The shift modifier by itself may not be used with' \
0242                   ' this key symbol; only with F1-F12, Tab, or Space'
0243             tkMessageBox.showerror(title=title, parent=self,
0244                                    message=msg)
0245         elif keySequence in self.currentKeySequences:
0246             msg = 'This key combination is already in use.'
0247             tkMessageBox.showerror(title=title, parent=self,
0248                                    message=msg)
0249         else:
0250             keysOK = True
0251         return keysOK
0252 
0253 if __name__ == '__main__':
0254     #test the dialog
0255     root=Tk()
0256     def run():
0257         keySeq=''
0258         dlg=GetKeysDialog(root,'Get Keys','find-again',[])
0259         print dlg.result
0260     Button(root,text='Dialog',command=run).pack()
0261     root.mainloop()
0262 

Generated by PyXR 0.9.4
SourceForge.net Logo