make_menu_src.py


directory : D:\2018_py_proj\TkGridGUI\tkgridgui
Line Count : 293
Line Clip Size : No Clipping

tab_of_notebook_changed  Word MatchCase (0) 
1 #!/usr/bin/env python 2 # -*- coding: ascii -*- 3 from __future__ import print_function 4 from __future__ import unicode_literals 5 6 from builtins import range 7 from builtins import object 8 from tkgridgui.src_templates import legalPythonIdentifier, letters, digits 9 sampleMenuStr=''' 10 File 11 New 12 Worksheet 13 Text File 14 Open 15 Save 16 17 Exit 18 Edit 19 Find 20 Copy 21 Cut 22 Paste 23 ''' 24 25 class myMenuItem( object ): 26 27 def __init__(self, label): 28 self.label = label 29 self.subLabelL = [] 30 self.parent = None 31 self.underline = -1 32 self.ctrl_char = '' 33 34 def addSubItem(self, subItem): 35 self.subLabelL.append( subItem ) 36 subItem.parent = self 37 def lenSubmenu(self): 38 return len(self.subLabelL) 39 40 def getSubItemAtLevel(self, N): 41 m = self 42 for i in range(N-1): 43 if len(m.subLabelL)>0: 44 m = m.subLabelL[-1] 45 return m 46 47 def make_ctrl_key(self, taken_uc_charL): 48 """taken_uc_charL is the list of upper case characters already taken by other myMenuItem objects""" 49 50 # only submenu items get a ctrl_char 51 if len(self.subLabelL) > 0: 52 for s in self.subLabelL: 53 s.make_ctrl_key( taken_uc_charL ) 54 else: 55 for ic,c in enumerate( self.label ): 56 c = c.upper() 57 if c in letters: 58 if c not in taken_uc_charL: 59 self.underline = ic 60 self.ctrl_char = c 61 taken_uc_charL.append( c ) 62 return 63 # since no letter was found, try a number 64 for ic,d in enumerate(digits): 65 if d not in taken_uc_charL: 66 self.underline = id 67 self.ctrl_char = d 68 taken_uc_charL.append( d ) 69 return 70 # if here then no good ctrl_char found... return without one. 71 72 def printSum(self): 73 74 sSubs = '' 75 for sub in self.subLabelL: 76 sSubs += sub.label + ' -- ' 77 78 print( '------------ start -----------------' ) 79 print( '"%s"'%self.label, 'len list =',len(self.subLabelL),sSubs ) 80 print( '------------- end -----------------' ) 81 for sub in self.subLabelL: 82 sub.printSum() 83 print( '----' ) 84 85 def numIndentSpaces( s ): 86 return len(s) - len(s.lstrip()) 87 88 def buildMenuSource( descStr ): 89 90 # prune beginning and ending blank lines 91 #print('descStr =', descStr) 92 #print('repr(descStr) =', repr(descStr) ) 93 descL = descStr.split('\n') 94 95 #print( 'len(descL)=',len(descL) ) 96 for i in range( len(descL)-1, -1, -1): 97 if descL[i].strip() != '': 98 break 99 del descL[i] 100 #print( 'len(descL)=',len(descL) ) 101 for i in range( len(descL)): 102 if descL[i].strip() != '': 103 break 104 del descL[i] 105 #print( 'len(descL)=',len(descL) ) 106 #print( 'descL =',descL ) 107 #print() 108 # now interpret the pruned list for indentation 109 110 if len(descL)==0: 111 return '' 112 113 i = 0 114 nspaceLast = numIndentSpaces( descL[0] ) 115 indentL = [] 116 for label in descL: 117 118 # assume a blank line is simply a seperator at the same indent level 119 if label.strip() == '': 120 nspace = nspaceLast 121 else: 122 nspace = numIndentSpaces( label ) 123 124 if nspace > nspaceLast: 125 i += 1 126 elif nspace < nspaceLast: 127 i -= 1 128 129 if i<0: i=0 130 indentL.append( [i,label.strip()] ) 131 nspaceLast = nspace 132 133 #print( 'indentL',indentL ) 134 #print() 135 136 # make list of menu Items 137 menuL = [] 138 for N,label in indentL: 139 m = myMenuItem(label) 140 if N==0: 141 menuL.append(m) 142 else: 143 try: 144 mtop = menuL[-1] 145 madd = mtop.getSubItemAtLevel(N) 146 madd.addSubItem(m) 147 except: 148 menuL.append(m) 149 150 #for mItem in menuL: 151 # mItem.printSum() 152 153 return menuL 154 155 sMenuBar = ' self.menuBar = Menu(%s, relief = "raised", bd=2)\n' 156 sMenu = '\n top_%s = Menu(self.menuBar, tearoff=0)\n' 157 sItem = ' top_%s.add("command", label = "%s", command = self.%s)\n' 158 sItemAcc = ' top_%s.add("command", label = "%s", command=self.%s, underline=%i, accelerator="Ctrl+%s")\n' 159 160 sSpacer = ' top_%s.add_separator()\n' 161 sCascade = ' self.menuBar.add("cascade", label="%s", menu=top_%s)\n' 162 sCascade2= ' top_%s.add("cascade", label="%s", menu=top_%s)\n' 163 sMenuConfig = '\n %s.config(menu=self.menuBar)\n' 164 def getSubmenuSource( mItem ): 165 topName = legalPythonIdentifier( mItem.label ) 166 sL = [sMenu%topName] 167 bindL = [] 168 169 for s in mItem.subLabelL: 170 if s.lenSubmenu()==0: 171 if s.label.strip() != '': 172 name = 'menu_%s_%s'%(mItem.label, s.label) 173 name = legalPythonIdentifier( name ) 174 if s.ctrl_char: 175 sL.append(sItemAcc%(topName, s.label, name, s.underline, s.ctrl_char)) 176 bindL.append(' self.master.bind("<Control-%s>", lambda event: self.%s())\n'%(s.ctrl_char, name) ) 177 bindL.append(' self.master.bind("<Control-%s>", lambda event: self.%s())\n'%(s.ctrl_char.lower(), name) ) 178 else: 179 sL.append(sItem%(topName, s.label, name)) 180 else: 181 sL.append(sSpacer%topName) 182 else: 183 s2L, b2L = getSubmenuSource(s) 184 sL.extend( s2L ) 185 bindL.extend( b2L ) 186 187 if mItem.parent: 188 topNameParent = legalPythonIdentifier( mItem.parent.label ) 189 sL.append(sCascade2%(topNameParent, mItem.label, topName)) 190 else: 191 sL.append(sCascade%(mItem.label, topName)) 192 return sL, bindL 193 194 195 def getMenuSource( menuL, rootName='MainWin', add_ctrl_keys=True, imADialog=False ): 196 197 if imADialog: 198 srcList = [sMenuBar%'self'] 199 else: 200 srcList = [sMenuBar%rootName] 201 202 bindL = [' # use both upper and lower characters for keyboard accelerator options.\n'] # any ctrl_char bindings that might happen 203 204 if add_ctrl_keys: 205 taken_uc_charL = [] 206 for m in menuL: 207 m.make_ctrl_key( taken_uc_charL ) 208 209 for m in menuL: 210 # most top level menu items will have subitems 211 if m.lenSubmenu()>0: 212 s2L, b2L = getSubmenuSource(m) 213 srcList.extend( s2L ) 214 bindL.extend( b2L ) 215 else: 216 name = 'menu_%s'%(legalPythonIdentifier( m.label )) 217 if m.ctrl_char: 218 sTopItem= ' self.menuBar.add("command", label = "%s", command=self.%s, underline=%i, accelerator="Ctrl+%s")\n' 219 srcList.append( sTopItem%( m.label, name, m.underline, m.ctrl_char) ) 220 bindL.append(' self.master.bind("<Control-%s>", lambda event: self.%s())\n'%(m.ctrl_char, name) ) 221 bindL.append(' self.master.bind("<Control-%s>", lambda event: self.%s())\n'%(m.ctrl_char.lower(), name) ) 222 else: 223 sTopItem= ' self.menuBar.add("command", label = "%s", command = self.%s)\n' 224 srcList.append( sTopItem%( m.label, name) ) 225 226 if imADialog: 227 srcList.append( sMenuConfig%'self' ) 228 else: 229 srcList.append( sMenuConfig%rootName ) 230 231 srcList.append('\n\n') 232 233 if imADialog: 234 target = 'self.' + rootName 235 bindL = [b.replace(target,'self') for b in bindL] 236 237 srcList.extend( bindL ) 238 239 #print('In getMenuSource') 240 #for src in srcList: 241 # print(src) 242 #print() 243 244 return srcList 245 246 247 def getMenuFunctionSource( menuL, rootName='MainWin' ): 248 pass 249 250 if __name__ == "__main__": 251 252 descStr=''' 253 File 254 New 255 Worksheet 256 Text File 257 Open 258 Save 259 260 Exit 261 Edit 262 Find 263 Copy 264 Cut 265 Paste 266 ''' 267 268 menuL = buildMenuSource( descStr ) 269 print( menuL ) 270 print( '-'*55 ) 271 272 menuSrcL = getMenuSource( menuL, rootName='master' ) 273 for line in menuSrcL: 274 print(line, end='') 275 print( '======================================================' ) 276 277 #fOut = open('test.py','w') 278 print( ''' 279 from Tkinter import * 280 281 class Mytestapp: 282 def __init__(self, %s): 283 '''%'master' ) 284 for line in menuSrcL: 285 print( line, end='') 286 287 print( '''root = Tk() 288 app = Mytestapp(root) 289 root.mainloop() 290 ''' ) 291 292 #fOut.close() 293