#Boa:Dialog:KeyDefsDialog # XXX fix accel names/ key codes when 2.5 is used for resource config values import string import wx import Preferences, Utils class InvalidValueError(Exception): pass [wxID_KEYDEFSDIALOG, wxID_KEYDEFSDIALOGALTFLAGCHB, wxID_KEYDEFSDIALOGCANCELBTN, wxID_KEYDEFSDIALOGCTRLFLAGCHB, wxID_KEYDEFSDIALOGKEYCODECBB, wxID_KEYDEFSDIALOGOKBTN, wxID_KEYDEFSDIALOGSHIFTFLAGCHB, wxID_KEYDEFSDIALOGSHORTCUTTC, wxID_KEYDEFSDIALOGSTATICBOX1, wxID_KEYDEFSDIALOGSTATICTEXT1, wxID_KEYDEFSDIALOGSTATICTEXT2, ] = [wx.NewId() for _init_ctrls in range(11)] class KeyDefsDialog(wx.Dialog): def _init_ctrls(self, prnt): # generated method, don't edit wx.Dialog.__init__(self, id=wxID_KEYDEFSDIALOG, name='KeyDefsDialog', parent=prnt, pos=wx.Point(430, 271), size=wx.Size(298, 184), style=wx.DEFAULT_DIALOG_STYLE, title=self.entryTitle) self.SetClientSize(wx.Size(290, 157)) self.staticBox1 = wx.StaticBox(id=wxID_KEYDEFSDIALOGSTATICBOX1, label='Flags', name='staticBox1', parent=self, pos=wx.Point(8, 8), size=wx.Size(136, 96), style=0) self.ctrlFlagChb = wx.CheckBox(id=wxID_KEYDEFSDIALOGCTRLFLAGCHB, label='wx.ACCEL_CTRL', name='ctrlFlagChb', parent=self, pos=wx.Point(16, 24), size=wx.Size(120, 19), style=0) self.ctrlFlagChb.Bind(wx.EVT_CHECKBOX, self.OnUpdateShortcut, id=wxID_KEYDEFSDIALOGCTRLFLAGCHB) self.altFlagChb = wx.CheckBox(id=wxID_KEYDEFSDIALOGALTFLAGCHB, label='wx.ACCEL_ALT', name='altFlagChb', parent=self, pos=wx.Point(16, 48), size=wx.Size(120, 19), style=0) self.altFlagChb.Bind(wx.EVT_CHECKBOX, self.OnUpdateShortcut, id=wxID_KEYDEFSDIALOGALTFLAGCHB) self.shiftFlagChb = wx.CheckBox(id=wxID_KEYDEFSDIALOGSHIFTFLAGCHB, label='wx.ACCEL_SHIFT', name='shiftFlagChb', parent=self, pos=wx.Point(16, 72), size=wx.Size(120, 19), style=0) self.shiftFlagChb.Bind(wx.EVT_CHECKBOX, self.OnUpdateShortcut, id=wxID_KEYDEFSDIALOGSHIFTFLAGCHB) self.keyCodeCbb = wx.ComboBox(choices=self.preDefKeys, id=wxID_KEYDEFSDIALOGKEYCODECBB, name='keyCodeCbb', parent=self, pos=wx.Point(152, 32), size=wx.Size(125, 21), style=0, value='') self.keyCodeCbb.Bind(wx.EVT_COMBOBOX, self.OnUpdateShortcutKeyCodeCbb, id=wxID_KEYDEFSDIALOGKEYCODECBB) self.keyCodeCbb.Bind(wx.EVT_TEXT, self.OnUpdateShortcutKeyCodeCbb, id=wxID_KEYDEFSDIALOGKEYCODECBB) self.staticText1 = wx.StaticText(id=wxID_KEYDEFSDIALOGSTATICTEXT1, label='Key code:', name='staticText1', parent=self, pos=wx.Point(152, 16), size=wx.Size(120, 13), style=0) self.staticText2 = wx.StaticText(id=wxID_KEYDEFSDIALOGSTATICTEXT2, label='Shortcut text:', name='staticText2', parent=self, pos=wx.Point(152, 64), size=wx.Size(120, 13), style=0) self.shortcutTc = wx.TextCtrl(id=wxID_KEYDEFSDIALOGSHORTCUTTC, name='shortcutTc', parent=self, pos=wx.Point(152, 80), size=wx.Size(124, 21), style=0, value='') self.okBtn = wx.Button(id=wxID_KEYDEFSDIALOGOKBTN, label='OK', name='okBtn', parent=self, pos=wx.Point(120, 120), size=wx.Size(75, 23), style=0) self.okBtn.Bind(wx.EVT_BUTTON, self.OnOkbtnButton, id=wxID_KEYDEFSDIALOGOKBTN) self.cancelBtn = wx.Button(id=wxID_KEYDEFSDIALOGCANCELBTN, label='Cancel', name='cancelBtn', parent=self, pos=wx.Point(200, 120), size=wx.Size(75, 23), style=0) self.cancelBtn.Bind(wx.EVT_BUTTON, self.OnCancelbtnButton, id=wxID_KEYDEFSDIALOGCANCELBTN) def __init__(self, parent, entryName, accelEntry): #possibly raise exception for invalid format before creating the dialog # XXX fix when 2.5 is used for resource config values flags, keyCode, shortcut = eval(accelEntry, {'wx': wx})[0] self.preDefKeys = [] self.preDefKeys = specialKeys.keys() + otherKeys1 + otherKeys2 self.entryTitle = 'Key binding definition:' self.entryTitle = 'Key binding definition: %s' % entryName self._init_ctrls(parent) self.SetAcceleratorTable( wx.AcceleratorTable([ Utils.setupCloseWindowOnEscape(self) ])) self.flagCtrls = ((self.ctrlFlagChb, wx.ACCEL_CTRL), (self.altFlagChb, wx.ACCEL_ALT), (self.shiftFlagChb, wx.ACCEL_SHIFT)) for ctrl, flag in self.flagCtrls: ctrl.SetValue((flags & flag) == flag) if valNameMap.has_key(keyCode): self.keyCodeCbb.SetValue(valNameMap[keyCode]) else: self.keyCodeCbb.SetValue(chr(keyCode)) self.shortcutTc.SetValue(shortcut) def validateCtrls(self): flags = [] for ctrl, flag in self.flagCtrls: if ctrl.GetValue(): flags.append(flagValNames[flag][0]) if flags: flags = ' | '.join(flags) else: flags = 'wx.ACCEL_NORMAL' keyCode = self.keyCodeCbb.GetValue() if not keyCode: raise InvalidValueError('Key code may not be blank') if keyCode not in specialKeys.keys() + otherKeys1 + otherKeys2: if len(keyCode) != 1 or keyCode not in string.letters+string.digits: raise InvalidValueError('Key code must either be a single character (letter or digit) or an identifier selected from the combobox') keyCode = "ord('%s')" % keyCode.upper() shortcut = self.shortcutTc.GetValue() if not shortcut: raise InvalidValueError('Shortcut may not be blank, enter a concise description, e.g. Ctrl-Shift-S') return "(%s, %s, '%s')," % (flags, keyCode, shortcut) def deriveShortcut(self, keyCode=None): segs = [] for ctrl, flag in self.flagCtrls: if ctrl.GetValue(): segs.append(flagValNames[flag][1]) if keyCode is None: keyCode = self.keyCodeCbb.GetValue() if keyCode: segs.append(printableKeyCode(keyCode)) self.shortcutTc.SetValue('-'.join(segs)) def OnOkbtnButton(self, event): try: self.result = self.validateCtrls() except InvalidValueError, err: wx.MessageBox(str(err), 'Invalid value error', wx.OK | wx.ICON_ERROR, self) else: self.EndModal(wx.ID_OK) def OnCancelbtnButton(self, event): self.EndModal(wx.ID_CANCEL) def OnUpdateShortcut(self, event): self.deriveShortcut() def OnUpdateShortcutKeyCodeCbb(self, event): self.deriveShortcut(event.GetString()) def printableKeyCode(keyCode): if len(keyCode) >=8 and keyCode[:7] == 'wx.WXK_': return keyCode[7:].capitalize() else: return keyCode.upper() flagValNames = {wx.ACCEL_CTRL: ('wx.ACCEL_CTRL', 'Ctrl'), wx.ACCEL_ALT: ('wx.ACCEL_ALT', 'Alt'), wx.ACCEL_SHIFT: ('wx.ACCEL_SHIFT', 'Shift')} specialKeys = {'wx.WXK_BACK': 8, 'wx.WXK_TAB': 9, 'wx.WXK_RETURN': 13, 'wx.WXK_ESCAPE': 27, 'wx.WXK_SPACE': 32, 'wx.WXK_DELETE': 127} # values 300+ otherKeys1 = ['wx.WXK_START', 'wx.WXK_LBUTTON', 'wx.WXK_RBUTTON', 'wx.WXK_CANCEL', 'wx.WXK_MBUTTON', 'wx.WXK_CLEAR', 'wx.WXK_SHIFT'] # values 308+ otherKeys2 = ['wx.WXK_CONTROL', 'wx.WXK_MENU', 'wx.WXK_PAUSE', 'wx.WXK_CAPITAL', 'wx.WXK_PRIOR', 'wx.WXK_NEXT', 'wx.WXK_END', 'wx.WXK_HOME', 'wx.WXK_LEFT', 'wx.WXK_UP', 'wx.WXK_RIGHT', 'wx.WXK_DOWN', 'wx.WXK_SELECT', 'wx.WXK_PRINT', 'wx.WXK_EXECUTE', 'wx.WXK_SNAPSHOT', 'wx.WXK_INSERT', 'wx.WXK_HELP', 'wx.WXK_NUMPAD0', 'wx.WXK_NUMPAD1', 'wx.WXK_NUMPAD2', 'wx.WXK_NUMPAD3', 'wx.WXK_NUMPAD4', 'wx.WXK_NUMPAD5', 'wx.WXK_NUMPAD6', 'wx.WXK_NUMPAD7', 'wx.WXK_NUMPAD8', 'wx.WXK_NUMPAD9', 'wx.WXK_MULTIPLY', 'wx.WXK_ADD', 'wx.WXK_SEPARATOR', 'wx.WXK_SUBTRACT', 'wx.WXK_DECIMAL', 'wx.WXK_DIVIDE', 'wx.WXK_F1', 'wx.WXK_F2', 'wx.WXK_F3', 'wx.WXK_F4', 'wx.WXK_F5', 'wx.WXK_F6', 'wx.WXK_F7', 'wx.WXK_F8', 'wx.WXK_F9', 'wx.WXK_F10', 'wx.WXK_F11', 'wx.WXK_F12', 'wx.WXK_F13', 'wx.WXK_F14', 'wx.WXK_F15', 'wx.WXK_F16', 'wx.WXK_F17', 'wx.WXK_F18', 'wx.WXK_F19', 'wx.WXK_F20', 'wx.WXK_F21', 'wx.WXK_F22', 'wx.WXK_F23', 'wx.WXK_F24', 'wx.WXK_NUMLOCK', 'wx.WXK_SCROLL', 'wx.WXK_PAGEUP', 'wx.WXK_PAGEDOWN', ] # build reverse mapping valNameMap = {} for name, val in specialKeys.items(): valNameMap[val] = name val = 300 for name in otherKeys1: valNameMap[val] = name val = val + 1 val = 308 for name in otherKeys2: valNameMap[val] = name val = val + 1 #------------------------------------------------------------------------------- if __name__ == '__main__': app =wx.PySimpleApp() dlg = KeyDefsDialog(None, 'ContextHelp', "(wx.ACCEL_NORMAL, wx.WXK_F1, 'F1'),") try: if dlg.ShowModal() == wx.ID_OK: print dlg.result finally: dlg.Destroy() app.MainLoop()