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