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