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