1 """IDLE Configuration Dialog: support user customization of IDLE by GUI 2 3 Customize font faces, sizes, and colorization attributes. Set indentation 4 defaults. Customize keybindings. Colorization and keybindings can be 5 saved as user defined sets. Select startup options including shell/editor 6 and default window size. Define additional help sources. 7 8 Note that tab width in IDLE is currently fixed at eight due to Tk issues. 9 Refer to comments in EditorWindow autoindent code for details. 10 11 """ 12 from Tkinter import * 13 import tkMessageBox, tkColorChooser, tkFont 14 import string 15 16 from idlelib.configHandler import idleConf 17 from idlelib.dynOptionMenuWidget import DynOptionMenu 18 from idlelib.tabbedpages import TabbedPageSet 19 from idlelib.keybindingDialog import GetKeysDialog 20 from idlelib.configSectionNameDialog import GetCfgSectionNameDialog 21 from idlelib.configHelpSourceEdit import GetHelpSourceDialog 22 from idlelib import macosxSupport 23 24 class ConfigDialog(Toplevel): 25 26 def __init__(self,parent,title): 27 Toplevel.__init__(self, parent) 28 self.wm_withdraw() 29 30 self.configure(borderwidth=5) 31 self.title('IDLE Preferences') 32 self.geometry("+%d+%d" % (parent.winfo_rootx()+20, 33 parent.winfo_rooty()+30)) 34 #Theme Elements. Each theme element key is its display name. 35 #The first value of the tuple is the sample area tag name. 36 #The second value is the display name list sort index. 37 self.themeElements={'Normal Text':('normal','00'), 38 'Python Keywords':('keyword','01'), 39 'Python Definitions':('definition','02'), 40 'Python Builtins':('builtin', '03'), 41 'Python Comments':('comment','04'), 42 'Python Strings':('string','05'), 43 'Selected Text':('hilite','06'), 44 'Found Text':('hit','07'), 45 'Cursor':('cursor','08'), 46 'Error Text':('error','09'), 47 'Shell Normal Text':('console','10'), 48 'Shell Stdout Text':('stdout','11'), 49 'Shell Stderr Text':('stderr','12'), 50 } 51 self.ResetChangedItems() #load initial values in changed items dict 52 self.CreateWidgets() 53 self.resizable(height=FALSE,width=FALSE) 54 self.transient(parent) 55 self.grab_set() 56 self.protocol("WM_DELETE_WINDOW", self.Cancel) 57 self.parent = parent 58 self.tabPages.focus_set() 59 #key bindings for this dialog 60 #self.bind('<Escape>',self.Cancel) #dismiss dialog, no save 61 #self.bind('<Alt-a>',self.Apply) #apply changes, save 62 #self.bind('<F1>',self.Help) #context help 63 self.LoadConfigs() 64 self.AttachVarCallbacks() #avoid callbacks during LoadConfigs 65 66 self.wm_deiconify() 67 self.wait_window() 68 69 def CreateWidgets(self): 70 self.tabPages = TabbedPageSet(self, 71 page_names=['Fonts/Tabs','Highlighting','Keys','General']) 72 frameActionButtons = Frame(self,pady=2) 73 #action buttons 74 if macosxSupport.runningAsOSXApp(): 75 # Changing the default padding on OSX results in unreadable 76 # text in the buttons 77 paddingArgs={} 78 else: 79 paddingArgs={'padx':6, 'pady':3} 80 81 self.buttonHelp = Button(frameActionButtons,text='Help', 82 command=self.Help,takefocus=FALSE, 83 **paddingArgs) 84 self.buttonOk = Button(frameActionButtons,text='Ok', 85 command=self.Ok,takefocus=FALSE, 86 **paddingArgs) 87 self.buttonApply = Button(frameActionButtons,text='Apply', 88 command=self.Apply,takefocus=FALSE, 89 **paddingArgs) 90 self.buttonCancel = Button(frameActionButtons,text='Cancel', 91 command=self.Cancel,takefocus=FALSE, 92 **paddingArgs) 93 self.CreatePageFontTab() 94 self.CreatePageHighlight() 95 self.CreatePageKeys() 96 self.CreatePageGeneral() 97 self.buttonHelp.pack(side=RIGHT,padx=5) 98 self.buttonOk.pack(side=LEFT,padx=5) 99 self.buttonApply.pack(side=LEFT,padx=5) 100 self.buttonCancel.pack(side=LEFT,padx=5) 101 frameActionButtons.pack(side=BOTTOM) 102 Frame(self, height=2, borderwidth=0).pack(side=BOTTOM) 103 self.tabPages.pack(side=TOP,expand=TRUE,fill=BOTH) 104 105 def CreatePageFontTab(self): 106 #tkVars 107 self.fontSize=StringVar(self) 108 self.fontBold=BooleanVar(self) 109 self.fontName=StringVar(self) 110 self.spaceNum=IntVar(self) 111 self.editFont=tkFont.Font(self,('courier',10,'normal')) 112 ##widget creation 113 #body frame 114 frame=self.tabPages.pages['Fonts/Tabs'].frame 115 #body section frames 116 frameFont=LabelFrame(frame,borderwidth=2,relief=GROOVE, 117 text=' Base Editor Font ') 118 frameIndent=LabelFrame(frame,borderwidth=2,relief=GROOVE, 119 text=' Indentation Width ') 120 #frameFont 121 frameFontName=Frame(frameFont) 122 frameFontParam=Frame(frameFont) 123 labelFontNameTitle=Label(frameFontName,justify=LEFT, 124 text='Font Face :') 125 self.listFontName=Listbox(frameFontName,height=5,takefocus=FALSE, 126 exportselection=FALSE) 127 self.listFontName.bind('<ButtonRelease-1>',self.OnListFontButtonRelease) 128 scrollFont=Scrollbar(frameFontName) 129 scrollFont.config(command=self.listFontName.yview) 130 self.listFontName.config(yscrollcommand=scrollFont.set) 131 labelFontSizeTitle=Label(frameFontParam,text='Size :') 132 self.optMenuFontSize=DynOptionMenu(frameFontParam,self.fontSize,None, 133 command=self.SetFontSample) 134 checkFontBold=Checkbutton(frameFontParam,variable=self.fontBold, 135 onvalue=1,offvalue=0,text='Bold',command=self.SetFontSample) 136 frameFontSample=Frame(frameFont,relief=SOLID,borderwidth=1) 137 self.labelFontSample=Label(frameFontSample, 138 text='AaBbCcDdEe\nFfGgHhIiJjK\n1234567890\n#:+=(){}[]', 139 justify=LEFT,font=self.editFont) 140 #frameIndent 141 frameIndentSize=Frame(frameIndent) 142 labelSpaceNumTitle=Label(frameIndentSize, justify=LEFT, 143 text='Python Standard: 4 Spaces!') 144 self.scaleSpaceNum=Scale(frameIndentSize, variable=self.spaceNum, 145 orient='horizontal', 146 tickinterval=2, from_=2, to=16) 147 #widget packing 148 #body 149 frameFont.pack(side=LEFT,padx=5,pady=5,expand=TRUE,fill=BOTH) 150 frameIndent.pack(side=LEFT,padx=5,pady=5,fill=Y) 151 #frameFont 152 frameFontName.pack(side=TOP,padx=5,pady=5,fill=X) 153 frameFontParam.pack(side=TOP,padx=5,pady=5,fill=X) 154 labelFontNameTitle.pack(side=TOP,anchor=W) 155 self.listFontName.pack(side=LEFT,expand=TRUE,fill=X) 156 scrollFont.pack(side=LEFT,fill=Y) 157 labelFontSizeTitle.pack(side=LEFT,anchor=W) 158 self.optMenuFontSize.pack(side=LEFT,anchor=W) 159 checkFontBold.pack(side=LEFT,anchor=W,padx=20) 160 frameFontSample.pack(side=TOP,padx=5,pady=5,expand=TRUE,fill=BOTH) 161 self.labelFontSample.pack(expand=TRUE,fill=BOTH) 162 #frameIndent 163 frameIndentSize.pack(side=TOP,fill=X) 164 labelSpaceNumTitle.pack(side=TOP,anchor=W,padx=5) 165 self.scaleSpaceNum.pack(side=TOP,padx=5,fill=X) 166 return frame 167 168 def CreatePageHighlight(self): 169 self.builtinTheme=StringVar(self) 170 self.customTheme=StringVar(self) 171 self.fgHilite=BooleanVar(self) 172 self.colour=StringVar(self) 173 self.fontName=StringVar(self) 174 self.themeIsBuiltin=BooleanVar(self) 175 self.highlightTarget=StringVar(self) 176 ##widget creation 177 #body frame 178 frame=self.tabPages.pages['Highlighting'].frame 179 #body section frames 180 frameCustom=LabelFrame(frame,borderwidth=2,relief=GROOVE, 181 text=' Custom Highlighting ') 182 frameTheme=LabelFrame(frame,borderwidth=2,relief=GROOVE, 183 text=' Highlighting Theme ') 184 #frameCustom 185 self.textHighlightSample=Text(frameCustom,relief=SOLID,borderwidth=1, 186 font=('courier',12,''),cursor='hand2',width=21,height=11, 187 takefocus=FALSE,highlightthickness=0,wrap=NONE) 188 text=self.textHighlightSample 189 text.bind('<Double-Button-1>',lambda e: 'break') 190 text.bind('<B1-Motion>',lambda e: 'break') 191 textAndTags=(('#you can click here','comment'),('\n','normal'), 192 ('#to choose items','comment'),('\n','normal'),('def','keyword'), 193 (' ','normal'),('func','definition'),('(param):','normal'), 194 ('\n ','normal'),('"""string"""','string'),('\n var0 = ','normal'), 195 ("'string'",'string'),('\n var1 = ','normal'),("'selected'",'hilite'), 196 ('\n var2 = ','normal'),("'found'",'hit'), 197 ('\n var3 = ','normal'),('list', 'builtin'), ('(','normal'), 198 ('None', 'builtin'),(')\n\n','normal'), 199 (' error ','error'),(' ','normal'),('cursor |','cursor'), 200 ('\n ','normal'),('shell','console'),(' ','normal'),('stdout','stdout'), 201 (' ','normal'),('stderr','stderr'),('\n','normal')) 202 for txTa in textAndTags: 203 text.insert(END,txTa[0],txTa[1]) 204 for element in self.themeElements.keys(): 205 text.tag_bind(self.themeElements[element][0],'<ButtonPress-1>', 206 lambda event,elem=element: event.widget.winfo_toplevel() 207 .highlightTarget.set(elem)) 208 text.config(state=DISABLED) 209 self.frameColourSet=Frame(frameCustom,relief=SOLID,borderwidth=1) 210 frameFgBg=Frame(frameCustom) 211 buttonSetColour=Button(self.frameColourSet,text='Choose Colour for :', 212 command=self.GetColour,highlightthickness=0) 213 self.optMenuHighlightTarget=DynOptionMenu(self.frameColourSet, 214 self.highlightTarget,None,highlightthickness=0)#,command=self.SetHighlightTargetBinding 215 self.radioFg=Radiobutton(frameFgBg,variable=self.fgHilite, 216 value=1,text='Foreground',command=self.SetColourSampleBinding) 217 self.radioBg=Radiobutton(frameFgBg,variable=self.fgHilite, 218 value=0,text='Background',command=self.SetColourSampleBinding) 219 self.fgHilite.set(1) 220 buttonSaveCustomTheme=Button(frameCustom, 221 text='Save as New Custom Theme',command=self.SaveAsNewTheme) 222 #frameTheme 223 labelTypeTitle=Label(frameTheme,text='Select : ') 224 self.radioThemeBuiltin=Radiobutton(frameTheme,variable=self.themeIsBuiltin, 225 value=1,command=self.SetThemeType,text='a Built-in Theme') 226 self.radioThemeCustom=Radiobutton(frameTheme,variable=self.themeIsBuiltin, 227 value=0,command=self.SetThemeType,text='a Custom Theme') 228 self.optMenuThemeBuiltin=DynOptionMenu(frameTheme, 229 self.builtinTheme,None,command=None) 230 self.optMenuThemeCustom=DynOptionMenu(frameTheme, 231 self.customTheme,None,command=None) 232 self.buttonDeleteCustomTheme=Button(frameTheme,text='Delete Custom Theme', 233 command=self.DeleteCustomTheme) 234 ##widget packing 235 #body 236 frameCustom.pack(side=LEFT,padx=5,pady=5,expand=TRUE,fill=BOTH) 237 frameTheme.pack(side=LEFT,padx=5,pady=5,fill=Y) 238 #frameCustom 239 self.frameColourSet.pack(side=TOP,padx=5,pady=5,expand=TRUE,fill=X) 240 frameFgBg.pack(side=TOP,padx=5,pady=0) 241 self.textHighlightSample.pack(side=TOP,padx=5,pady=5,expand=TRUE, 242 fill=BOTH) 243 buttonSetColour.pack(side=TOP,expand=TRUE,fill=X,padx=8,pady=4) 244 self.optMenuHighlightTarget.pack(side=TOP,expand=TRUE,fill=X,padx=8,pady=3) 245 self.radioFg.pack(side=LEFT,anchor=E) 246 self.radioBg.pack(side=RIGHT,anchor=W) 247 buttonSaveCustomTheme.pack(side=BOTTOM,fill=X,padx=5,pady=5) 248 #frameTheme 249 labelTypeTitle.pack(side=TOP,anchor=W,padx=5,pady=5) 250 self.radioThemeBuiltin.pack(side=TOP,anchor=W,padx=5) 251 self.radioThemeCustom.pack(side=TOP,anchor=W,padx=5,pady=2) 252 self.optMenuThemeBuiltin.pack(side=TOP,fill=X,padx=5,pady=5) 253 self.optMenuThemeCustom.pack(side=TOP,fill=X,anchor=W,padx=5,pady=5) 254 self.buttonDeleteCustomTheme.pack(side=TOP,fill=X,padx=5,pady=5) 255 return frame 256 257 def CreatePageKeys(self): 258 #tkVars 259 self.bindingTarget=StringVar(self) 260 self.builtinKeys=StringVar(self) 261 self.customKeys=StringVar(self) 262 self.keysAreBuiltin=BooleanVar(self) 263 self.keyBinding=StringVar(self) 264 ##widget creation 265 #body frame 266 frame=self.tabPages.pages['Keys'].frame 267 #body section frames 268 frameCustom=LabelFrame(frame,borderwidth=2,relief=GROOVE, 269 text=' Custom Key Bindings ') 270 frameKeySets=LabelFrame(frame,borderwidth=2,relief=GROOVE, 271 text=' Key Set ') 272 #frameCustom 273 frameTarget=Frame(frameCustom) 274 labelTargetTitle=Label(frameTarget,text='Action - Key(s)') 275 scrollTargetY=Scrollbar(frameTarget) 276 scrollTargetX=Scrollbar(frameTarget,orient=HORIZONTAL) 277 self.listBindings=Listbox(frameTarget,takefocus=FALSE, 278 exportselection=FALSE) 279 self.listBindings.bind('<ButtonRelease-1>',self.KeyBindingSelected) 280 scrollTargetY.config(command=self.listBindings.yview) 281 scrollTargetX.config(command=self.listBindings.xview) 282 self.listBindings.config(yscrollcommand=scrollTargetY.set) 283 self.listBindings.config(xscrollcommand=scrollTargetX.set) 284 self.buttonNewKeys=Button(frameCustom,text='Get New Keys for Selection', 285 command=self.GetNewKeys,state=DISABLED) 286 #frameKeySets 287 frames = [Frame(frameKeySets, padx=2, pady=2, borderwidth=0) 288 for i in range(2)] 289 self.radioKeysBuiltin=Radiobutton(frames[0],variable=self.keysAreBuiltin, 290 value=1,command=self.SetKeysType,text='Use a Built-in Key Set') 291 self.radioKeysCustom=Radiobutton(frames[0],variable=self.keysAreBuiltin, 292 value=0,command=self.SetKeysType,text='Use a Custom Key Set') 293 self.optMenuKeysBuiltin=DynOptionMenu(frames[0], 294 self.builtinKeys,None,command=None) 295 self.optMenuKeysCustom=DynOptionMenu(frames[0], 296 self.customKeys,None,command=None) 297 self.buttonDeleteCustomKeys=Button(frames[1],text='Delete Custom Key Set', 298 command=self.DeleteCustomKeys) 299 buttonSaveCustomKeys=Button(frames[1], 300 text='Save as New Custom Key Set',command=self.SaveAsNewKeySet) 301 ##widget packing 302 #body 303 frameCustom.pack(side=BOTTOM,padx=5,pady=5,expand=TRUE,fill=BOTH) 304 frameKeySets.pack(side=BOTTOM,padx=5,pady=5,fill=BOTH) 305 #frameCustom 306 self.buttonNewKeys.pack(side=BOTTOM,fill=X,padx=5,pady=5) 307 frameTarget.pack(side=LEFT,padx=5,pady=5,expand=TRUE,fill=BOTH) 308 #frame target 309 frameTarget.columnconfigure(0,weight=1) 310 frameTarget.rowconfigure(1,weight=1) 311 labelTargetTitle.grid(row=0,column=0,columnspan=2,sticky=W) 312 self.listBindings.grid(row=1,column=0,sticky=NSEW) 313 scrollTargetY.grid(row=1,column=1,sticky=NS) 314 scrollTargetX.grid(row=2,column=0,sticky=EW) 315 #frameKeySets 316 self.radioKeysBuiltin.grid(row=0, column=0, sticky=W+NS) 317 self.radioKeysCustom.grid(row=1, column=0, sticky=W+NS) 318 self.optMenuKeysBuiltin.grid(row=0, column=1, sticky=NSEW) 319 self.optMenuKeysCustom.grid(row=1, column=1, sticky=NSEW) 320 self.buttonDeleteCustomKeys.pack(side=LEFT,fill=X,expand=True,padx=2) 321 buttonSaveCustomKeys.pack(side=LEFT,fill=X,expand=True,padx=2) 322 frames[0].pack(side=TOP, fill=BOTH, expand=True) 323 frames[1].pack(side=TOP, fill=X, expand=True, pady=2) 324 return frame 325 326 def CreatePageGeneral(self): 327 #tkVars 328 self.winWidth=StringVar(self) 329 self.winHeight=StringVar(self) 330 self.paraWidth=StringVar(self) 331 self.startupEdit=IntVar(self) 332 self.autoSave=IntVar(self) 333 self.encoding=StringVar(self) 334 self.userHelpBrowser=BooleanVar(self) 335 self.helpBrowser=StringVar(self) 336 #widget creation 337 #body 338 frame=self.tabPages.pages['General'].frame 339 #body section frames 340 frameRun=LabelFrame(frame,borderwidth=2,relief=GROOVE, 341 text=' Startup Preferences ') 342 frameSave=LabelFrame(frame,borderwidth=2,relief=GROOVE, 343 text=' Autosave Preferences ') 344 frameWinSize=Frame(frame,borderwidth=2,relief=GROOVE) 345 frameParaSize=Frame(frame,borderwidth=2,relief=GROOVE) 346 frameEncoding=Frame(frame,borderwidth=2,relief=GROOVE) 347 frameHelp=LabelFrame(frame,borderwidth=2,relief=GROOVE, 348 text=' Additional Help Sources ') 349 #frameRun 350 labelRunChoiceTitle=Label(frameRun,text='At Startup') 351 radioStartupEdit=Radiobutton(frameRun,variable=self.startupEdit, 352 value=1,command=self.SetKeysType,text="Open Edit Window") 353 radioStartupShell=Radiobutton(frameRun,variable=self.startupEdit, 354 value=0,command=self.SetKeysType,text='Open Shell Window') 355 #frameSave 356 labelRunSaveTitle=Label(frameSave,text='At Start of Run (F5) ') 357 radioSaveAsk=Radiobutton(frameSave,variable=self.autoSave, 358 value=0,command=self.SetKeysType,text="Prompt to Save") 359 radioSaveAuto=Radiobutton(frameSave,variable=self.autoSave, 360 value=1,command=self.SetKeysType,text='No Prompt') 361 #frameWinSize 362 labelWinSizeTitle=Label(frameWinSize,text='Initial Window Size'+ 363 ' (in characters)') 364 labelWinWidthTitle=Label(frameWinSize,text='Width') 365 entryWinWidth=Entry(frameWinSize,textvariable=self.winWidth, 366 width=3) 367 labelWinHeightTitle=Label(frameWinSize,text='Height') 368 entryWinHeight=Entry(frameWinSize,textvariable=self.winHeight, 369 width=3) 370 #paragraphFormatWidth 371 labelParaWidthTitle=Label(frameParaSize,text='Paragraph reformat'+ 372 ' width (in characters)') 373 entryParaWidth=Entry(frameParaSize,textvariable=self.paraWidth, 374 width=3) 375 #frameEncoding 376 labelEncodingTitle=Label(frameEncoding,text="Default Source Encoding") 377 radioEncLocale=Radiobutton(frameEncoding,variable=self.encoding, 378 value="locale",text="Locale-defined") 379 radioEncUTF8=Radiobutton(frameEncoding,variable=self.encoding, 380 value="utf-8",text="UTF-8") 381 radioEncNone=Radiobutton(frameEncoding,variable=self.encoding, 382 value="none",text="None") 383 #frameHelp 384 frameHelpList=Frame(frameHelp) 385 frameHelpListButtons=Frame(frameHelpList) 386 scrollHelpList=Scrollbar(frameHelpList) 387 self.listHelp=Listbox(frameHelpList,height=5,takefocus=FALSE, 388 exportselection=FALSE) 389 scrollHelpList.config(command=self.listHelp.yview) 390 self.listHelp.config(yscrollcommand=scrollHelpList.set) 391 self.listHelp.bind('<ButtonRelease-1>',self.HelpSourceSelected) 392 self.buttonHelpListEdit=Button(frameHelpListButtons,text='Edit', 393 state=DISABLED,width=8,command=self.HelpListItemEdit) 394 self.buttonHelpListAdd=Button(frameHelpListButtons,text='Add', 395 width=8,command=self.HelpListItemAdd) 396 self.buttonHelpListRemove=Button(frameHelpListButtons,text='Remove', 397 state=DISABLED,width=8,command=self.HelpListItemRemove) 398 #widget packing 399 #body 400 frameRun.pack(side=TOP,padx=5,pady=5,fill=X) 401 frameSave.pack(side=TOP,padx=5,pady=5,fill=X) 402 frameWinSize.pack(side=TOP,padx=5,pady=5,fill=X) 403 frameParaSize.pack(side=TOP,padx=5,pady=5,fill=X) 404 frameEncoding.pack(side=TOP,padx=5,pady=5,fill=X) 405 frameHelp.pack(side=TOP,padx=5,pady=5,expand=TRUE,fill=BOTH) 406 #frameRun 407 labelRunChoiceTitle.pack(side=LEFT,anchor=W,padx=5,pady=5) 408 radioStartupShell.pack(side=RIGHT,anchor=W,padx=5,pady=5) 409 radioStartupEdit.pack(side=RIGHT,anchor=W,padx=5,pady=5) 410 #frameSave 411 labelRunSaveTitle.pack(side=LEFT,anchor=W,padx=5,pady=5) 412 radioSaveAuto.pack(side=RIGHT,anchor=W,padx=5,pady=5) 413 radioSaveAsk.pack(side=RIGHT,anchor=W,padx=5,pady=5) 414 #frameWinSize 415 labelWinSizeTitle.pack(side=LEFT,anchor=W,padx=5,pady=5) 416 entryWinHeight.pack(side=RIGHT,anchor=E,padx=10,pady=5) 417 labelWinHeightTitle.pack(side=RIGHT,anchor=E,pady=5) 418 entryWinWidth.pack(side=RIGHT,anchor=E,padx=10,pady=5) 419 labelWinWidthTitle.pack(side=RIGHT,anchor=E,pady=5) 420 #paragraphFormatWidth 421 labelParaWidthTitle.pack(side=LEFT,anchor=W,padx=5,pady=5) 422 entryParaWidth.pack(side=RIGHT,anchor=E,padx=10,pady=5) 423 #frameEncoding 424 labelEncodingTitle.pack(side=LEFT,anchor=W,padx=5,pady=5) 425 radioEncNone.pack(side=RIGHT,anchor=E,pady=5) 426 radioEncUTF8.pack(side=RIGHT,anchor=E,pady=5) 427 radioEncLocale.pack(side=RIGHT,anchor=E,pady=5) 428 #frameHelp 429 frameHelpListButtons.pack(side=RIGHT,padx=5,pady=5,fill=Y) 430 frameHelpList.pack(side=TOP,padx=5,pady=5,expand=TRUE,fill=BOTH) 431 scrollHelpList.pack(side=RIGHT,anchor=W,fill=Y) 432 self.listHelp.pack(side=LEFT,anchor=E,expand=TRUE,fill=BOTH) 433 self.buttonHelpListEdit.pack(side=TOP,anchor=W,pady=5) 434 self.buttonHelpListAdd.pack(side=TOP,anchor=W) 435 self.buttonHelpListRemove.pack(side=TOP,anchor=W,pady=5) 436 return frame 437 438 def AttachVarCallbacks(self): 439 self.fontSize.trace_variable('w',self.VarChanged_fontSize) 440 self.fontName.trace_variable('w',self.VarChanged_fontName) 441 self.fontBold.trace_variable('w',self.VarChanged_fontBold) 442 self.spaceNum.trace_variable('w',self.VarChanged_spaceNum) 443 self.colour.trace_variable('w',self.VarChanged_colour) 444 self.builtinTheme.trace_variable('w',self.VarChanged_builtinTheme) 445 self.customTheme.trace_variable('w',self.VarChanged_customTheme) 446 self.themeIsBuiltin.trace_variable('w',self.VarChanged_themeIsBuiltin) 447 self.highlightTarget.trace_variable('w',self.VarChanged_highlightTarget) 448 self.keyBinding.trace_variable('w',self.VarChanged_keyBinding) 449 self.builtinKeys.trace_variable('w',self.VarChanged_builtinKeys) 450 self.customKeys.trace_variable('w',self.VarChanged_customKeys) 451 self.keysAreBuiltin.trace_variable('w',self.VarChanged_keysAreBuiltin) 452 self.winWidth.trace_variable('w',self.VarChanged_winWidth) 453 self.winHeight.trace_variable('w',self.VarChanged_winHeight) 454 self.paraWidth.trace_variable('w',self.VarChanged_paraWidth) 455 self.startupEdit.trace_variable('w',self.VarChanged_startupEdit) 456 self.autoSave.trace_variable('w',self.VarChanged_autoSave) 457 self.encoding.trace_variable('w',self.VarChanged_encoding) 458 459 def VarChanged_fontSize(self,*params): 460 value=self.fontSize.get() 461 self.AddChangedItem('main','EditorWindow','font-size',value) 462 463 def VarChanged_fontName(self,*params): 464 value=self.fontName.get() 465 self.AddChangedItem('main','EditorWindow','font',value) 466 467 def VarChanged_fontBold(self,*params): 468 value=self.fontBold.get() 469 self.AddChangedItem('main','EditorWindow','font-bold',value) 470 471 def VarChanged_spaceNum(self,*params): 472 value=self.spaceNum.get() 473 self.AddChangedItem('main','Indent','num-spaces',value) 474 475 def VarChanged_colour(self,*params): 476 self.OnNewColourSet() 477 478 def VarChanged_builtinTheme(self,*params): 479 value=self.builtinTheme.get() 480 self.AddChangedItem('main','Theme','name',value) 481 self.PaintThemeSample() 482 483 def VarChanged_customTheme(self,*params): 484 value=self.customTheme.get() 485 if value != '- no custom themes -': 486 self.AddChangedItem('main','Theme','name',value) 487 self.PaintThemeSample() 488 489 def VarChanged_themeIsBuiltin(self,*params): 490 value=self.themeIsBuiltin.get() 491 self.AddChangedItem('main','Theme','default',value) 492 if value: 493 self.VarChanged_builtinTheme() 494 else: 495 self.VarChanged_customTheme() 496 497 def VarChanged_highlightTarget(self,*params): 498 self.SetHighlightTarget() 499 500 def VarChanged_keyBinding(self,*params): 501 value=self.keyBinding.get() 502 keySet=self.customKeys.get() 503 event=self.listBindings.get(ANCHOR).split()[0] 504 if idleConf.IsCoreBinding(event): 505 #this is a core keybinding 506 self.AddChangedItem('keys',keySet,event,value) 507 else: #this is an extension key binding 508 extName=idleConf.GetExtnNameForEvent(event) 509 extKeybindSection=extName+'_cfgBindings' 510 self.AddChangedItem('extensions',extKeybindSection,event,value) 511 512 def VarChanged_builtinKeys(self,*params): 513 value=self.builtinKeys.get() 514 self.AddChangedItem('main','Keys','name',value) 515 self.LoadKeysList(value) 516 517 def VarChanged_customKeys(self,*params): 518 value=self.customKeys.get() 519 if value != '- no custom keys -': 520 self.AddChangedItem('main','Keys','name',value) 521 self.LoadKeysList(value) 522 523 def VarChanged_keysAreBuiltin(self,*params): 524 value=self.keysAreBuiltin.get() 525 self.AddChangedItem('main','Keys','default',value) 526 if value: 527 self.VarChanged_builtinKeys() 528 else: 529 self.VarChanged_customKeys() 530 531 def VarChanged_winWidth(self,*params): 532 value=self.winWidth.get() 533 self.AddChangedItem('main','EditorWindow','width',value) 534 535 def VarChanged_winHeight(self,*params): 536 value=self.winHeight.get() 537 self.AddChangedItem('main','EditorWindow','height',value) 538 539 def VarChanged_paraWidth(self,*params): 540 value=self.paraWidth.get() 541 self.AddChangedItem('main','FormatParagraph','paragraph',value) 542 543 def VarChanged_startupEdit(self,*params): 544 value=self.startupEdit.get() 545 self.AddChangedItem('main','General','editor-on-startup',value) 546 547 def VarChanged_autoSave(self,*params): 548 value=self.autoSave.get() 549 self.AddChangedItem('main','General','autosave',value) 550 551 def VarChanged_encoding(self,*params): 552 value=self.encoding.get() 553 self.AddChangedItem('main','EditorWindow','encoding',value) 554 555 def ResetChangedItems(self): 556 #When any config item is changed in this dialog, an entry 557 #should be made in the relevant section (config type) of this 558 #dictionary. The key should be the config file section name and the 559 #value a dictionary, whose key:value pairs are item=value pairs for 560 #that config file section. 561 self.changedItems={'main':{},'highlight':{},'keys':{},'extensions':{}} 562 563 def AddChangedItem(self,type,section,item,value): 564 value=str(value) #make sure we use a string 565 if section not in self.changedItems[type]: 566 self.changedItems[type][section]={} 567 self.changedItems[type][section][item]=value 568 569 def GetDefaultItems(self): 570 dItems={'main':{},'highlight':{},'keys':{},'extensions':{}} 571 for configType in dItems.keys(): 572 sections=idleConf.GetSectionList('default',configType) 573 for section in sections: 574 dItems[configType][section]={} 575 options=idleConf.defaultCfg[configType].GetOptionList(section) 576 for option in options: 577 dItems[configType][section][option]=( 578 idleConf.defaultCfg[configType].Get(section,option)) 579 return dItems 580 581 def SetThemeType(self): 582 if self.themeIsBuiltin.get(): 583 self.optMenuThemeBuiltin.config(state=NORMAL) 584 self.optMenuThemeCustom.config(state=DISABLED) 585 self.buttonDeleteCustomTheme.config(state=DISABLED) 586 else: 587 self.optMenuThemeBuiltin.config(state=DISABLED) 588 self.radioThemeCustom.config(state=NORMAL) 589 self.optMenuThemeCustom.config(state=NORMAL) 590 self.buttonDeleteCustomTheme.config(state=NORMAL) 591 592 def SetKeysType(self): 593 if self.keysAreBuiltin.get(): 594 self.optMenuKeysBuiltin.config(state=NORMAL) 595 self.optMenuKeysCustom.config(state=DISABLED) 596 self.buttonDeleteCustomKeys.config(state=DISABLED) 597 else: 598 self.optMenuKeysBuiltin.config(state=DISABLED) 599 self.radioKeysCustom.config(state=NORMAL) 600 self.optMenuKeysCustom.config(state=NORMAL) 601 self.buttonDeleteCustomKeys.config(state=NORMAL) 602 603 def GetNewKeys(self): 604 listIndex=self.listBindings.index(ANCHOR) 605 binding=self.listBindings.get(listIndex) 606 bindName=binding.split()[0] #first part, up to first space 607 if self.keysAreBuiltin.get(): 608 currentKeySetName=self.builtinKeys.get() 609 else: 610 currentKeySetName=self.customKeys.get() 611 currentBindings=idleConf.GetCurrentKeySet() 612 if currentKeySetName in self.changedItems['keys'].keys(): #unsaved changes 613 keySetChanges=self.changedItems['keys'][currentKeySetName] 614 for event in keySetChanges.keys(): 615 currentBindings[event]=keySetChanges[event].split() 616 currentKeySequences=currentBindings.values() 617 newKeys=GetKeysDialog(self,'Get New Keys',bindName, 618 currentKeySequences).result 619 if newKeys: #new keys were specified 620 if self.keysAreBuiltin.get(): #current key set is a built-in 621 message=('Your changes will be saved as a new Custom Key Set. '+ 622 'Enter a name for your new Custom Key Set below.') 623 newKeySet=self.GetNewKeysName(message) 624 if not newKeySet: #user cancelled custom key set creation 625 self.listBindings.select_set(listIndex) 626 self.listBindings.select_anchor(listIndex) 627 return 628 else: #create new custom key set based on previously active key set 629 self.CreateNewKeySet(newKeySet) 630 self.listBindings.delete(listIndex) 631 self.listBindings.insert(listIndex,bindName+' - '+newKeys) 632 self.listBindings.select_set(listIndex) 633 self.listBindings.select_anchor(listIndex) 634 self.keyBinding.set(newKeys) 635 else: 636 self.listBindings.select_set(listIndex) 637 self.listBindings.select_anchor(listIndex) 638 639 def GetNewKeysName(self,message): 640 usedNames=(idleConf.GetSectionList('user','keys')+ 641 idleConf.GetSectionList('default','keys')) 642 newKeySet=GetCfgSectionNameDialog(self,'New Custom Key Set', 643 message,usedNames).result 644 return newKeySet 645 646 def SaveAsNewKeySet(self): 647 newKeysName=self.GetNewKeysName('New Key Set Name:') 648 if newKeysName: 649 self.CreateNewKeySet(newKeysName) 650 651 def KeyBindingSelected(self,event): 652 self.buttonNewKeys.config(state=NORMAL) 653 654 def CreateNewKeySet(self,newKeySetName): 655 #creates new custom key set based on the previously active key set, 656 #and makes the new key set active 657 if self.keysAreBuiltin.get(): 658 prevKeySetName=self.builtinKeys.get() 659 else: 660 prevKeySetName=self.customKeys.get() 661 prevKeys=idleConf.GetCoreKeys(prevKeySetName) 662 newKeys={} 663 for event in prevKeys.keys(): #add key set to changed items 664 eventName=event[2:-2] #trim off the angle brackets 665 binding=string.join(prevKeys[event]) 666 newKeys[eventName]=binding 667 #handle any unsaved changes to prev key set 668 if prevKeySetName in self.changedItems['keys'].keys(): 669 keySetChanges=self.changedItems['keys'][prevKeySetName] 670 for event in keySetChanges.keys(): 671 newKeys[event]=keySetChanges[event] 672 #save the new theme 673 self.SaveNewKeySet(newKeySetName,newKeys) 674 #change gui over to the new key set 675 customKeyList=idleConf.GetSectionList('user','keys') 676 customKeyList.sort() 677 self.optMenuKeysCustom.SetMenu(customKeyList,newKeySetName) 678 self.keysAreBuiltin.set(0) 679 self.SetKeysType() 680 681 def LoadKeysList(self,keySetName): 682 reselect=0 683 newKeySet=0 684 if self.listBindings.curselection(): 685 reselect=1 686 listIndex=self.listBindings.index(ANCHOR) 687 keySet=idleConf.GetKeySet(keySetName) 688 bindNames=keySet.keys() 689 bindNames.sort() 690 self.listBindings.delete(0,END) 691 for bindName in bindNames: 692 key=string.join(keySet[bindName]) #make key(s) into a string 693 bindName=bindName[2:-2] #trim off the angle brackets 694 if keySetName in self.changedItems['keys'].keys(): 695 #handle any unsaved changes to this key set 696 if bindName in self.changedItems['keys'][keySetName].keys(): 697 key=self.changedItems['keys'][keySetName][bindName] 698 self.listBindings.insert(END, bindName+' - '+key) 699 if reselect: 700 self.listBindings.see(listIndex) 701 self.listBindings.select_set(listIndex) 702 self.listBindings.select_anchor(listIndex) 703 704 def DeleteCustomKeys(self): 705 keySetName=self.customKeys.get() 706 if not tkMessageBox.askyesno('Delete Key Set','Are you sure you wish '+ 707 'to delete the key set %r ?' % (keySetName), 708 parent=self): 709 return 710 #remove key set from config 711 idleConf.userCfg['keys'].remove_section(keySetName) 712 if keySetName in self.changedItems['keys']: 713 del(self.changedItems['keys'][keySetName]) 714 #write changes 715 idleConf.userCfg['keys'].Save() 716 #reload user key set list 717 itemList=idleConf.GetSectionList('user','keys') 718 itemList.sort() 719 if not itemList: 720 self.radioKeysCustom.config(state=DISABLED) 721 self.optMenuKeysCustom.SetMenu(itemList,'- no custom keys -') 722 else: 723 self.optMenuKeysCustom.SetMenu(itemList,itemList[0]) 724 #revert to default key set 725 self.keysAreBuiltin.set(idleConf.defaultCfg['main'].Get('Keys','default')) 726 self.builtinKeys.set(idleConf.defaultCfg['main'].Get('Keys','name')) 727 #user can't back out of these changes, they must be applied now 728 self.Apply() 729 self.SetKeysType() 730 731 def DeleteCustomTheme(self): 732 themeName=self.customTheme.get() 733 if not tkMessageBox.askyesno('Delete Theme','Are you sure you wish '+ 734 'to delete the theme %r ?' % (themeName,), 735 parent=self): 736 return 737 #remove theme from config 738 idleConf.userCfg['highlight'].remove_section(themeName) 739 if themeName in self.changedItems['highlight']: 740 del(self.changedItems['highlight'][themeName]) 741 #write changes 742 idleConf.userCfg['highlight'].Save() 743 #reload user theme list 744 itemList=idleConf.GetSectionList('user','highlight') 745 itemList.sort() 746 if not itemList: 747 self.radioThemeCustom.config(state=DISABLED) 748 self.optMenuThemeCustom.SetMenu(itemList,'- no custom themes -') 749 else: 750 self.optMenuThemeCustom.SetMenu(itemList,itemList[0]) 751 #revert to default theme 752 self.themeIsBuiltin.set(idleConf.defaultCfg['main'].Get('Theme','default')) 753 self.builtinTheme.set(idleConf.defaultCfg['main'].Get('Theme','name')) 754 #user can't back out of these changes, they must be applied now 755 self.Apply() 756 self.SetThemeType() 757 758 def GetColour(self): 759 target=self.highlightTarget.get() 760 prevColour=self.frameColourSet.cget('bg') 761 rgbTuplet, colourString = tkColorChooser.askcolor(parent=self, 762 title='Pick new colour for : '+target,initialcolor=prevColour) 763 if colourString and (colourString!=prevColour): 764 #user didn't cancel, and they chose a new colour 765 if self.themeIsBuiltin.get(): #current theme is a built-in 766 message=('Your changes will be saved as a new Custom Theme. '+ 767 'Enter a name for your new Custom Theme below.') 768 newTheme=self.GetNewThemeName(message) 769 if not newTheme: #user cancelled custom theme creation 770 return 771 else: #create new custom theme based on previously active theme 772 self.CreateNewTheme(newTheme) 773 self.colour.set(colourString) 774 else: #current theme is user defined 775 self.colour.set(colourString) 776 777 def OnNewColourSet(self): 778 newColour=self.colour.get() 779 self.frameColourSet.config(bg=newColour)#set sample 780 if self.fgHilite.get(): plane='foreground' 781 else: plane='background' 782 sampleElement=self.themeElements[self.highlightTarget.get()][0] 783 self.textHighlightSample.tag_config(sampleElement, **{plane:newColour}) 784 theme=self.customTheme.get() 785 themeElement=sampleElement+'-'+plane 786 self.AddChangedItem('highlight',theme,themeElement,newColour) 787 788 def GetNewThemeName(self,message): 789 usedNames=(idleConf.GetSectionList('user','highlight')+ 790 idleConf.GetSectionList('default','highlight')) 791 newTheme=GetCfgSectionNameDialog(self,'New Custom Theme', 792 message,usedNames).result 793 return newTheme 794 795 def SaveAsNewTheme(self): 796 newThemeName=self.GetNewThemeName('New Theme Name:') 797 if newThemeName: 798 self.CreateNewTheme(newThemeName) 799 800 def CreateNewTheme(self,newThemeName): 801 #creates new custom theme based on the previously active theme, 802 #and makes the new theme active 803 if self.themeIsBuiltin.get(): 804 themeType='default' 805 themeName=self.builtinTheme.get() 806 else: 807 themeType='user' 808 themeName=self.customTheme.get() 809 newTheme=idleConf.GetThemeDict(themeType,themeName) 810 #apply any of the old theme's unsaved changes to the new theme 811 if themeName in self.changedItems['highlight'].keys(): 812 themeChanges=self.changedItems['highlight'][themeName] 813 for element in themeChanges.keys(): 814 newTheme[element]=themeChanges[element] 815 #save the new theme 816 self.SaveNewTheme(newThemeName,newTheme) 817 #change gui over to the new theme 818 customThemeList=idleConf.GetSectionList('user','highlight') 819 customThemeList.sort() 820 self.optMenuThemeCustom.SetMenu(customThemeList,newThemeName) 821 self.themeIsBuiltin.set(0) 822 self.SetThemeType() 823 824 def OnListFontButtonRelease(self,event): 825 font = self.listFontName.get(ANCHOR) 826 self.fontName.set(font.lower()) 827 self.SetFontSample() 828 829 def SetFontSample(self,event=None): 830 fontName=self.fontName.get() 831 if self.fontBold.get(): 832 fontWeight=tkFont.BOLD 833 else: 834 fontWeight=tkFont.NORMAL 835 newFont = (fontName, self.fontSize.get(), fontWeight) 836 self.labelFontSample.config(font=newFont) 837 self.textHighlightSample.configure(font=newFont) 838 839 def SetHighlightTarget(self): 840 if self.highlightTarget.get()=='Cursor': #bg not possible 841 self.radioFg.config(state=DISABLED) 842 self.radioBg.config(state=DISABLED) 843 self.fgHilite.set(1) 844 else: #both fg and bg can be set 845 self.radioFg.config(state=NORMAL) 846 self.radioBg.config(state=NORMAL) 847 self.fgHilite.set(1) 848 self.SetColourSample() 849 850 def SetColourSampleBinding(self,*args): 851 self.SetColourSample() 852 853 def SetColourSample(self): 854 #set the colour smaple area 855 tag=self.themeElements[self.highlightTarget.get()][0] 856 if self.fgHilite.get(): plane='foreground' 857 else: plane='background' 858 colour=self.textHighlightSample.tag_cget(tag,plane) 859 self.frameColourSet.config(bg=colour) 860 861 def PaintThemeSample(self): 862 if self.themeIsBuiltin.get(): #a default theme 863 theme=self.builtinTheme.get() 864 else: #a user theme 865 theme=self.customTheme.get() 866 for elementTitle in self.themeElements.keys(): 867 element=self.themeElements[elementTitle][0] 868 colours=idleConf.GetHighlight(theme,element) 869 if element=='cursor': #cursor sample needs special painting 870 colours['background']=idleConf.GetHighlight(theme, 871 'normal', fgBg='bg') 872 #handle any unsaved changes to this theme 873 if theme in self.changedItems['highlight'].keys(): 874 themeDict=self.changedItems['highlight'][theme] 875 if element+'-foreground' in themeDict: 876 colours['foreground']=themeDict[element+'-foreground'] 877 if element+'-background' in themeDict: 878 colours['background']=themeDict[element+'-background'] 879 self.textHighlightSample.tag_config(element, **colours) 880 self.SetColourSample() 881 882 def HelpSourceSelected(self,event): 883 self.SetHelpListButtonStates() 884 885 def SetHelpListButtonStates(self): 886 if self.listHelp.size()<1: #no entries in list 887 self.buttonHelpListEdit.config(state=DISABLED) 888 self.buttonHelpListRemove.config(state=DISABLED) 889 else: #there are some entries 890 if self.listHelp.curselection(): #there currently is a selection 891 self.buttonHelpListEdit.config(state=NORMAL) 892 self.buttonHelpListRemove.config(state=NORMAL) 893 else: #there currently is not a selection 894 self.buttonHelpListEdit.config(state=DISABLED) 895 self.buttonHelpListRemove.config(state=DISABLED) 896 897 def HelpListItemAdd(self): 898 helpSource=GetHelpSourceDialog(self,'New Help Source').result 899 if helpSource: 900 self.userHelpList.append( (helpSource[0],helpSource[1]) ) 901 self.listHelp.insert(END,helpSource[0]) 902 self.UpdateUserHelpChangedItems() 903 self.SetHelpListButtonStates() 904 905 def HelpListItemEdit(self): 906 itemIndex=self.listHelp.index(ANCHOR) 907 helpSource=self.userHelpList[itemIndex] 908 newHelpSource=GetHelpSourceDialog(self,'Edit Help Source', 909 menuItem=helpSource[0],filePath=helpSource[1]).result 910 if (not newHelpSource) or (newHelpSource==helpSource): 911 return #no changes 912 self.userHelpList[itemIndex]=newHelpSource 913 self.listHelp.delete(itemIndex) 914 self.listHelp.insert(itemIndex,newHelpSource[0]) 915 self.UpdateUserHelpChangedItems() 916 self.SetHelpListButtonStates() 917 918 def HelpListItemRemove(self): 919 itemIndex=self.listHelp.index(ANCHOR) 920 del(self.userHelpList[itemIndex]) 921 self.listHelp.delete(itemIndex) 922 self.UpdateUserHelpChangedItems() 923 self.SetHelpListButtonStates() 924 925 def UpdateUserHelpChangedItems(self): 926 "Clear and rebuild the HelpFiles section in self.changedItems" 927 self.changedItems['main']['HelpFiles'] = {} 928 for num in range(1,len(self.userHelpList)+1): 929 self.AddChangedItem('main','HelpFiles',str(num), 930 string.join(self.userHelpList[num-1][:2],';')) 931 932 def LoadFontCfg(self): 933 ##base editor font selection list 934 fonts=list(tkFont.families(self)) 935 fonts.sort() 936 for font in fonts: 937 self.listFontName.insert(END,font) 938 configuredFont=idleConf.GetOption('main','EditorWindow','font', 939 default='courier') 940 lc_configuredFont = configuredFont.lower() 941 self.fontName.set(lc_configuredFont) 942 lc_fonts = [s.lower() for s in fonts] 943 if lc_configuredFont in lc_fonts: 944 currentFontIndex = lc_fonts.index(lc_configuredFont) 945 self.listFontName.see(currentFontIndex) 946 self.listFontName.select_set(currentFontIndex) 947 self.listFontName.select_anchor(currentFontIndex) 948 ##font size dropdown 949 fontSize=idleConf.GetOption('main','EditorWindow','font-size', 950 type='int', default='10') 951 self.optMenuFontSize.SetMenu(('7','8','9','10','11','12','13','14', 952 '16','18','20','22'),fontSize ) 953 ##fontWeight 954 self.fontBold.set(idleConf.GetOption('main','EditorWindow', 955 'font-bold',default=0,type='bool')) 956 ##font sample 957 self.SetFontSample() 958 959 def LoadTabCfg(self): 960 ##indent sizes 961 spaceNum=idleConf.GetOption('main','Indent','num-spaces', 962 default=4,type='int') 963 self.spaceNum.set(spaceNum) 964 965 def LoadThemeCfg(self): 966 ##current theme type radiobutton 967 self.themeIsBuiltin.set(idleConf.GetOption('main','Theme','default', 968 type='bool',default=1)) 969 ##currently set theme 970 currentOption=idleConf.CurrentTheme() 971 ##load available theme option menus 972 if self.themeIsBuiltin.get(): #default theme selected 973 itemList=idleConf.GetSectionList('default','highlight') 974 itemList.sort() 975 self.optMenuThemeBuiltin.SetMenu(itemList,currentOption) 976 itemList=idleConf.GetSectionList('user','highlight') 977 itemList.sort() 978 if not itemList: 979 self.radioThemeCustom.config(state=DISABLED) 980 self.customTheme.set('- no custom themes -') 981 else: 982 self.optMenuThemeCustom.SetMenu(itemList,itemList[0]) 983 else: #user theme selected 984 itemList=idleConf.GetSectionList('user','highlight') 985 itemList.sort() 986 self.optMenuThemeCustom.SetMenu(itemList,currentOption) 987 itemList=idleConf.GetSectionList('default','highlight') 988 itemList.sort() 989 self.optMenuThemeBuiltin.SetMenu(itemList,itemList[0]) 990 self.SetThemeType() 991 ##load theme element option menu 992 themeNames=self.themeElements.keys() 993 themeNames.sort(key=lambda x: self.themeElements[x][1]) 994 self.optMenuHighlightTarget.SetMenu(themeNames,themeNames[0]) 995 self.PaintThemeSample() 996 self.SetHighlightTarget() 997 998 def LoadKeyCfg(self): 999 ##current keys type radiobutton 1000 self.keysAreBuiltin.set(idleConf.GetOption('main','Keys','default', 1001 type='bool',default=1)) 1002 ##currently set keys 1003 currentOption=idleConf.CurrentKeys() 1004 ##load available keyset option menus 1005 if self.keysAreBuiltin.get(): #default theme selected 1006 itemList=idleConf.GetSectionList('default','keys') 1007 itemList.sort() 1008 self.optMenuKeysBuiltin.SetMenu(itemList,currentOption) 1009 itemList=idleConf.GetSectionList('user','keys') 1010 itemList.sort() 1011 if not itemList: 1012 self.radioKeysCustom.config(state=DISABLED) 1013 self.customKeys.set('- no custom keys -') 1014 else: 1015 self.optMenuKeysCustom.SetMenu(itemList,itemList[0]) 1016 else: #user key set selected 1017 itemList=idleConf.GetSectionList('user','keys') 1018 itemList.sort() 1019 self.optMenuKeysCustom.SetMenu(itemList,currentOption) 1020 itemList=idleConf.GetSectionList('default','keys') 1021 itemList.sort() 1022 self.optMenuKeysBuiltin.SetMenu(itemList,itemList[0]) 1023 self.SetKeysType() 1024 ##load keyset element list 1025 keySetName=idleConf.CurrentKeys() 1026 self.LoadKeysList(keySetName) 1027 1028 def LoadGeneralCfg(self): 1029 #startup state 1030 self.startupEdit.set(idleConf.GetOption('main','General', 1031 'editor-on-startup',default=1,type='bool')) 1032 #autosave state 1033 self.autoSave.set(idleConf.GetOption('main', 'General', 'autosave', 1034 default=0, type='bool')) 1035 #initial window size 1036 self.winWidth.set(idleConf.GetOption('main','EditorWindow','width', 1037 type='int')) 1038 self.winHeight.set(idleConf.GetOption('main','EditorWindow','height', 1039 type='int')) 1040 #initial paragraph reformat size 1041 self.paraWidth.set(idleConf.GetOption('main','FormatParagraph','paragraph', 1042 type='int')) 1043 # default source encoding 1044 self.encoding.set(idleConf.GetOption('main', 'EditorWindow', 1045 'encoding', default='none')) 1046 # additional help sources 1047 self.userHelpList = idleConf.GetAllExtraHelpSourcesList() 1048 for helpItem in self.userHelpList: 1049 self.listHelp.insert(END,helpItem[0]) 1050 self.SetHelpListButtonStates() 1051 1052 def LoadConfigs(self): 1053 """ 1054 load configuration from default and user config files and populate 1055 the widgets on the config dialog pages. 1056 """ 1057 ### fonts / tabs page 1058 self.LoadFontCfg() 1059 self.LoadTabCfg() 1060 ### highlighting page 1061 self.LoadThemeCfg() 1062 ### keys page 1063 self.LoadKeyCfg() 1064 ### general page 1065 self.LoadGeneralCfg() 1066 1067 def SaveNewKeySet(self,keySetName,keySet): 1068 """ 1069 save a newly created core key set. 1070 keySetName - string, the name of the new key set 1071 keySet - dictionary containing the new key set 1072 """ 1073 if not idleConf.userCfg['keys'].has_section(keySetName): 1074 idleConf.userCfg['keys'].add_section(keySetName) 1075 for event in keySet.keys(): 1076 value=keySet[event] 1077 idleConf.userCfg['keys'].SetOption(keySetName,event,value) 1078 1079 def SaveNewTheme(self,themeName,theme): 1080 """ 1081 save a newly created theme. 1082 themeName - string, the name of the new theme 1083 theme - dictionary containing the new theme 1084 """ 1085 if not idleConf.userCfg['highlight'].has_section(themeName): 1086 idleConf.userCfg['highlight'].add_section(themeName) 1087 for element in theme.keys(): 1088 value=theme[element] 1089 idleConf.userCfg['highlight'].SetOption(themeName,element,value) 1090 1091 def SetUserValue(self,configType,section,item,value): 1092 if idleConf.defaultCfg[configType].has_option(section,item): 1093 if idleConf.defaultCfg[configType].Get(section,item)==value: 1094 #the setting equals a default setting, remove it from user cfg 1095 return idleConf.userCfg[configType].RemoveOption(section,item) 1096 #if we got here set the option 1097 return idleConf.userCfg[configType].SetOption(section,item,value) 1098 1099 def SaveAllChangedConfigs(self): 1100 "Save configuration changes to the user config file." 1101 idleConf.userCfg['main'].Save() 1102 for configType in self.changedItems.keys(): 1103 cfgTypeHasChanges = False 1104 for section in self.changedItems[configType].keys(): 1105 if section == 'HelpFiles': 1106 #this section gets completely replaced 1107 idleConf.userCfg['main'].remove_section('HelpFiles') 1108 cfgTypeHasChanges = True 1109 for item in self.changedItems[configType][section].keys(): 1110 value = self.changedItems[configType][section][item] 1111 if self.SetUserValue(configType,section,item,value): 1112 cfgTypeHasChanges = True 1113 if cfgTypeHasChanges: 1114 idleConf.userCfg[configType].Save() 1115 for configType in ['keys', 'highlight']: 1116 # save these even if unchanged! 1117 idleConf.userCfg[configType].Save() 1118 self.ResetChangedItems() #clear the changed items dict 1119 1120 def DeactivateCurrentConfig(self): 1121 #Before a config is saved, some cleanup of current 1122 #config must be done - remove the previous keybindings 1123 winInstances=self.parent.instance_dict.keys() 1124 for instance in winInstances: 1125 instance.RemoveKeybindings() 1126 1127 def ActivateConfigChanges(self): 1128 "Dynamically apply configuration changes" 1129 winInstances=self.parent.instance_dict.keys() 1130 for instance in winInstances: 1131 instance.ResetColorizer() 1132 instance.ResetFont() 1133 instance.set_notabs_indentwidth() 1134 instance.ApplyKeybindings() 1135 instance.reset_help_menu_entries() 1136 1137 def Cancel(self): 1138 self.destroy() 1139 1140 def Ok(self): 1141 self.Apply() 1142 self.destroy() 1143 1144 def Apply(self): 1145 self.DeactivateCurrentConfig() 1146 self.SaveAllChangedConfigs() 1147 self.ActivateConfigChanges() 1148 1149 def Help(self): 1150 pass 1151 1152 if __name__ == '__main__': 1153 #test the dialog 1154 root=Tk() 1155 Button(root,text='Dialog', 1156 command=lambda:ConfigDialog(root,'Settings')).pack() 1157 root.instance_dict={} 1158 root.mainloop() 1159