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