blob: 48cd99159264acbbcbaf8e449316d8049878b236 [file] [log] [blame]
Kurt B. Kaisere7a161e2003-01-10 20:13:57 +00001"""IDLE Configuration Dialog: support user customization of IDLE by GUI
2
3Customize font faces, sizes, and colorization attributes. Set indentation
4defaults. Customize keybindings. Colorization and keybindings can be
5saved as user defined sets. Select startup options including shell/editor
6and default window size. Define additional help sources.
7
8Note that tab width in IDLE is currently fixed at eight due to Tk issues.
Kurt B. Kaiseracdef852005-01-31 03:34:26 +00009Refer to comments in EditorWindow autoindent code for details.
Kurt B. Kaisere7a161e2003-01-10 20:13:57 +000010
Steven M. Gava44d3d1a2001-07-31 06:59:02 +000011"""
Georg Brandl14fc4272008-05-17 18:39:55 +000012from tkinter import *
13import tkinter.messagebox as tkMessageBox
14import tkinter.colorchooser as tkColorChooser
15import tkinter.font as tkFont
Steven M. Gava44d3d1a2001-07-31 06:59:02 +000016
Kurt B. Kaiser2d7f6a02007-08-22 23:01:33 +000017from idlelib.configHandler import idleConf
18from idlelib.dynOptionMenuWidget import DynOptionMenu
Kurt B. Kaiser2d7f6a02007-08-22 23:01:33 +000019from idlelib.keybindingDialog import GetKeysDialog
20from idlelib.configSectionNameDialog import GetCfgSectionNameDialog
21from idlelib.configHelpSourceEdit import GetHelpSourceDialog
Terry Jan Reedya9421fb2014-10-22 20:15:18 -040022from idlelib.tabbedpages import TabbedPageSet
Terry Jan Reedyd0cadba2015-10-11 22:07:31 -040023from idlelib.textView import view_text
Ronald Oussoren9e350042009-02-12 16:02:11 +000024from idlelib import macosxSupport
Terry Jan Reedyd0cadba2015-10-11 22:07:31 -040025
Steven M. Gava44d3d1a2001-07-31 06:59:02 +000026class ConfigDialog(Toplevel):
Kurt B. Kaiseracdef852005-01-31 03:34:26 +000027
Terry Jan Reedycd567362014-10-17 01:31:35 -040028 def __init__(self, parent, title='', _htest=False, _utest=False):
Terry Jan Reedy2e8234a2014-05-29 01:46:26 -040029 """
30 _htest - bool, change box location when running htest
Terry Jan Reedycfa89502014-07-14 23:07:32 -040031 _utest - bool, don't wait_window when running unittest
Terry Jan Reedy2e8234a2014-05-29 01:46:26 -040032 """
Steven M. Gavad721c482001-07-31 10:46:53 +000033 Toplevel.__init__(self, parent)
Terry Jan Reedy22405332014-07-30 19:24:32 -040034 self.parent = parent
Terry Jan Reedy4036d872014-08-03 23:02:58 -040035 if _htest:
36 parent.instance_dict = {}
Guido van Rossum8ce8a782007-11-01 19:42:39 +000037 self.wm_withdraw()
38
Steven M. Gavad721c482001-07-31 10:46:53 +000039 self.configure(borderwidth=5)
Terry Jan Reedycd567362014-10-17 01:31:35 -040040 self.title(title or 'IDLE Preferences')
Terry Jan Reedy4036d872014-08-03 23:02:58 -040041 self.geometry(
42 "+%d+%d" % (parent.winfo_rootx() + 20,
43 parent.winfo_rooty() + (30 if not _htest else 150)))
Georg Brandl7eb4b7d2005-07-22 21:49:32 +000044 #Theme Elements. Each theme element key is its display name.
Steven M. Gava9dd16b32001-11-03 14:54:25 +000045 #The first value of the tuple is the sample area tag name.
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +000046 #The second value is the display name list sort index.
Terry Jan Reedy4036d872014-08-03 23:02:58 -040047 self.themeElements={
Terry Jan Reedya8aa4d52015-10-02 22:12:17 -040048 'Normal Text': ('normal', '00'),
49 'Python Keywords': ('keyword', '01'),
50 'Python Definitions': ('definition', '02'),
51 'Python Builtins': ('builtin', '03'),
52 'Python Comments': ('comment', '04'),
53 'Python Strings': ('string', '05'),
54 'Selected Text': ('hilite', '06'),
55 'Found Text': ('hit', '07'),
56 'Cursor': ('cursor', '08'),
57 'Editor Breakpoint': ('break', '09'),
58 'Shell Normal Text': ('console', '10'),
59 'Shell Error Text': ('error', '11'),
60 'Shell Stdout Text': ('stdout', '12'),
61 'Shell Stderr Text': ('stderr', '13'),
Kurt B. Kaiser73360a32004-03-08 18:15:31 +000062 }
Steven M. Gavaa498af22002-02-01 01:33:36 +000063 self.ResetChangedItems() #load initial values in changed items dict
Steven M. Gavad721c482001-07-31 10:46:53 +000064 self.CreateWidgets()
Terry Jan Reedy4036d872014-08-03 23:02:58 -040065 self.resizable(height=FALSE, width=FALSE)
Steven M. Gavad721c482001-07-31 10:46:53 +000066 self.transient(parent)
67 self.grab_set()
68 self.protocol("WM_DELETE_WINDOW", self.Cancel)
Steven M. Gava2d4e03b2001-12-05 07:54:07 +000069 self.tabPages.focus_set()
Steven M. Gavad721c482001-07-31 10:46:53 +000070 #key bindings for this dialog
Terry Jan Reedy4036d872014-08-03 23:02:58 -040071 #self.bind('<Escape>', self.Cancel) #dismiss dialog, no save
72 #self.bind('<Alt-a>', self.Apply) #apply changes, save
73 #self.bind('<F1>', self.Help) #context help
Steven M. Gava429a86af2001-10-23 10:42:12 +000074 self.LoadConfigs()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +000075 self.AttachVarCallbacks() #avoid callbacks during LoadConfigs
Guido van Rossum8ce8a782007-11-01 19:42:39 +000076
Terry Jan Reedycfa89502014-07-14 23:07:32 -040077 if not _utest:
78 self.wm_deiconify()
79 self.wait_window()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +000080
Steven M. Gavad721c482001-07-31 10:46:53 +000081 def CreateWidgets(self):
Guido van Rossum8ce8a782007-11-01 19:42:39 +000082 self.tabPages = TabbedPageSet(self,
Terry Jan Reedy4036d872014-08-03 23:02:58 -040083 page_names=['Fonts/Tabs', 'Highlighting', 'Keys', 'General'])
Terry Jan Reedy92cb0a32014-10-08 20:29:13 -040084 self.tabPages.pack(side=TOP, expand=TRUE, fill=BOTH)
85 self.CreatePageFontTab()
86 self.CreatePageHighlight()
87 self.CreatePageKeys()
88 self.CreatePageGeneral()
89 self.create_action_buttons().pack(side=BOTTOM)
Terry Jan Reedyd0cadba2015-10-11 22:07:31 -040090
Terry Jan Reedy92cb0a32014-10-08 20:29:13 -040091 def create_action_buttons(self):
Ned Deilyb7601672014-03-27 20:49:14 -070092 if macosxSupport.isAquaTk():
Terry Jan Reedye3416e62014-07-26 19:40:16 -040093 # Changing the default padding on OSX results in unreadable
94 # text in the buttons
Terry Jan Reedy4036d872014-08-03 23:02:58 -040095 paddingArgs = {}
Ronald Oussoren9e350042009-02-12 16:02:11 +000096 else:
Terry Jan Reedy4036d872014-08-03 23:02:58 -040097 paddingArgs = {'padx':6, 'pady':3}
Terry Jan Reedya9421fb2014-10-22 20:15:18 -040098 outer = Frame(self, pady=2)
99 buttons = Frame(outer, pady=2)
Terry Jan Reedyd0cadba2015-10-11 22:07:31 -0400100 for txt, cmd in (
101 ('Ok', self.Ok),
102 ('Apply', self.Apply),
103 ('Cancel', self.Cancel),
104 ('Help', self.Help)):
105 Button(buttons, text=txt, command=cmd, takefocus=FALSE,
106 **paddingArgs).pack(side=LEFT, padx=5)
Terry Jan Reedya9421fb2014-10-22 20:15:18 -0400107 # add space above buttons
108 Frame(outer, height=2, borderwidth=0).pack(side=TOP)
109 buttons.pack(side=BOTTOM)
110 return outer
Terry Jan Reedyd0cadba2015-10-11 22:07:31 -0400111
Steven M. Gava60fc7072001-08-04 13:58:22 +0000112 def CreatePageFontTab(self):
Terry Jan Reedy22405332014-07-30 19:24:32 -0400113 parent = self.parent
114 self.fontSize = StringVar(parent)
115 self.fontBold = BooleanVar(parent)
116 self.fontName = StringVar(parent)
117 self.spaceNum = IntVar(parent)
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400118 self.editFont = tkFont.Font(parent, ('courier', 10, 'normal'))
Terry Jan Reedy22405332014-07-30 19:24:32 -0400119
Steven M. Gavaf213ccb2001-08-05 08:00:28 +0000120 ##widget creation
121 #body frame
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400122 frame = self.tabPages.pages['Fonts/Tabs'].frame
Steven M. Gavaf213ccb2001-08-05 08:00:28 +0000123 #body section frames
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400124 frameFont = LabelFrame(
125 frame, borderwidth=2, relief=GROOVE, text=' Base Editor Font ')
126 frameIndent = LabelFrame(
127 frame, borderwidth=2, relief=GROOVE, text=' Indentation Width ')
Steven M. Gavaf213ccb2001-08-05 08:00:28 +0000128 #frameFont
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400129 frameFontName = Frame(frameFont)
130 frameFontParam = Frame(frameFont)
131 labelFontNameTitle = Label(
132 frameFontName, justify=LEFT, text='Font Face :')
133 self.listFontName = Listbox(
134 frameFontName, height=5, takefocus=FALSE, exportselection=FALSE)
135 self.listFontName.bind(
136 '<ButtonRelease-1>', self.OnListFontButtonRelease)
137 scrollFont = Scrollbar(frameFontName)
Steven M. Gavac01e30f2001-08-11 15:48:13 +0000138 scrollFont.config(command=self.listFontName.yview)
139 self.listFontName.config(yscrollcommand=scrollFont.set)
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400140 labelFontSizeTitle = Label(frameFontParam, text='Size :')
141 self.optMenuFontSize = DynOptionMenu(
142 frameFontParam, self.fontSize, None, command=self.SetFontSample)
143 checkFontBold = Checkbutton(
144 frameFontParam, variable=self.fontBold, onvalue=1,
145 offvalue=0, text='Bold', command=self.SetFontSample)
146 frameFontSample = Frame(frameFont, relief=SOLID, borderwidth=1)
147 self.labelFontSample = Label(
148 frameFontSample, justify=LEFT, font=self.editFont,
149 text='AaBbCcDdEe\nFfGgHhIiJjK\n1234567890\n#:+=(){}[]')
Steven M. Gavaf213ccb2001-08-05 08:00:28 +0000150 #frameIndent
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400151 frameIndentSize = Frame(frameIndent)
152 labelSpaceNumTitle = Label(
153 frameIndentSize, justify=LEFT,
154 text='Python Standard: 4 Spaces!')
155 self.scaleSpaceNum = Scale(
156 frameIndentSize, variable=self.spaceNum,
157 orient='horizontal', tickinterval=2, from_=2, to=16)
Terry Jan Reedy22405332014-07-30 19:24:32 -0400158
Steven M. Gavaf213ccb2001-08-05 08:00:28 +0000159 #widget packing
160 #body
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400161 frameFont.pack(side=LEFT, padx=5, pady=5, expand=TRUE, fill=BOTH)
162 frameIndent.pack(side=LEFT, padx=5, pady=5, fill=Y)
Steven M. Gavaf213ccb2001-08-05 08:00:28 +0000163 #frameFont
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400164 frameFontName.pack(side=TOP, padx=5, pady=5, fill=X)
165 frameFontParam.pack(side=TOP, padx=5, pady=5, fill=X)
166 labelFontNameTitle.pack(side=TOP, anchor=W)
167 self.listFontName.pack(side=LEFT, expand=TRUE, fill=X)
168 scrollFont.pack(side=LEFT, fill=Y)
169 labelFontSizeTitle.pack(side=LEFT, anchor=W)
170 self.optMenuFontSize.pack(side=LEFT, anchor=W)
171 checkFontBold.pack(side=LEFT, anchor=W, padx=20)
172 frameFontSample.pack(side=TOP, padx=5, pady=5, expand=TRUE, fill=BOTH)
173 self.labelFontSample.pack(expand=TRUE, fill=BOTH)
Steven M. Gavaf213ccb2001-08-05 08:00:28 +0000174 #frameIndent
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400175 frameIndentSize.pack(side=TOP, fill=X)
176 labelSpaceNumTitle.pack(side=TOP, anchor=W, padx=5)
177 self.scaleSpaceNum.pack(side=TOP, padx=5, fill=X)
Steven M. Gava952d0a52001-08-03 04:43:44 +0000178 return frame
179
180 def CreatePageHighlight(self):
Terry Jan Reedy22405332014-07-30 19:24:32 -0400181 parent = self.parent
182 self.builtinTheme = StringVar(parent)
183 self.customTheme = StringVar(parent)
184 self.fgHilite = BooleanVar(parent)
185 self.colour = StringVar(parent)
186 self.fontName = StringVar(parent)
187 self.themeIsBuiltin = BooleanVar(parent)
188 self.highlightTarget = StringVar(parent)
189
Steven M. Gava952d0a52001-08-03 04:43:44 +0000190 ##widget creation
191 #body frame
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400192 frame = self.tabPages.pages['Highlighting'].frame
Steven M. Gava952d0a52001-08-03 04:43:44 +0000193 #body section frames
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400194 frameCustom = LabelFrame(frame, borderwidth=2, relief=GROOVE,
195 text=' Custom Highlighting ')
196 frameTheme = LabelFrame(frame, borderwidth=2, relief=GROOVE,
197 text=' Highlighting Theme ')
Steven M. Gava952d0a52001-08-03 04:43:44 +0000198 #frameCustom
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400199 self.textHighlightSample=Text(
200 frameCustom, relief=SOLID, borderwidth=1,
201 font=('courier', 12, ''), cursor='hand2', width=21, height=11,
202 takefocus=FALSE, highlightthickness=0, wrap=NONE)
Steven M. Gavae16d94b2001-11-03 05:07:28 +0000203 text=self.textHighlightSample
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400204 text.bind('<Double-Button-1>', lambda e: 'break')
205 text.bind('<B1-Motion>', lambda e: 'break')
206 textAndTags=(
207 ('#you can click here', 'comment'), ('\n', 'normal'),
208 ('#to choose items', 'comment'), ('\n', 'normal'),
209 ('def', 'keyword'), (' ', 'normal'),
210 ('func', 'definition'), ('(param):\n ', 'normal'),
211 ('"""string"""', 'string'), ('\n var0 = ', 'normal'),
212 ("'string'", 'string'), ('\n var1 = ', 'normal'),
213 ("'selected'", 'hilite'), ('\n var2 = ', 'normal'),
214 ("'found'", 'hit'), ('\n var3 = ', 'normal'),
215 ('list', 'builtin'), ('(', 'normal'),
Terry Jan Reedya8aa4d52015-10-02 22:12:17 -0400216 ('None', 'keyword'), (')\n', 'normal'),
217 (' breakpoint("line")', 'break'), ('\n\n', 'normal'),
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400218 (' error ', 'error'), (' ', 'normal'),
219 ('cursor |', 'cursor'), ('\n ', 'normal'),
220 ('shell', 'console'), (' ', 'normal'),
221 ('stdout', 'stdout'), (' ', 'normal'),
222 ('stderr', 'stderr'), ('\n', 'normal'))
Steven M. Gava9dd16b32001-11-03 14:54:25 +0000223 for txTa in textAndTags:
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400224 text.insert(END, txTa[0], txTa[1])
Kurt B. Kaisere0712772007-08-23 05:25:55 +0000225 for element in self.themeElements:
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400226 def tem(event, elem=element):
227 event.widget.winfo_toplevel().highlightTarget.set(elem)
228 text.tag_bind(
229 self.themeElements[element][0], '<ButtonPress-1>', tem)
Steven M. Gavae16d94b2001-11-03 05:07:28 +0000230 text.config(state=DISABLED)
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400231 self.frameColourSet = Frame(frameCustom, relief=SOLID, borderwidth=1)
232 frameFgBg = Frame(frameCustom)
233 buttonSetColour = Button(
234 self.frameColourSet, text='Choose Colour for :',
235 command=self.GetColour, highlightthickness=0)
236 self.optMenuHighlightTarget = DynOptionMenu(
237 self.frameColourSet, self.highlightTarget, None,
238 highlightthickness=0) #, command=self.SetHighlightTargetBinding
239 self.radioFg = Radiobutton(
240 frameFgBg, variable=self.fgHilite, value=1,
241 text='Foreground', command=self.SetColourSampleBinding)
242 self.radioBg=Radiobutton(
243 frameFgBg, variable=self.fgHilite, value=0,
244 text='Background', command=self.SetColourSampleBinding)
Steven M. Gava7c017862001-10-29 11:19:46 +0000245 self.fgHilite.set(1)
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400246 buttonSaveCustomTheme = Button(
247 frameCustom, text='Save as New Custom Theme',
248 command=self.SaveAsNewTheme)
Steven M. Gava952d0a52001-08-03 04:43:44 +0000249 #frameTheme
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400250 labelTypeTitle = Label(frameTheme, text='Select : ')
251 self.radioThemeBuiltin = Radiobutton(
252 frameTheme, variable=self.themeIsBuiltin, value=1,
253 command=self.SetThemeType, text='a Built-in Theme')
254 self.radioThemeCustom = Radiobutton(
255 frameTheme, variable=self.themeIsBuiltin, value=0,
256 command=self.SetThemeType, text='a Custom Theme')
257 self.optMenuThemeBuiltin = DynOptionMenu(
258 frameTheme, self.builtinTheme, None, command=None)
259 self.optMenuThemeCustom=DynOptionMenu(
260 frameTheme, self.customTheme, None, command=None)
261 self.buttonDeleteCustomTheme=Button(
262 frameTheme, text='Delete Custom Theme',
Steven M. Gava49745752002-02-18 01:43:11 +0000263 command=self.DeleteCustomTheme)
Terry Jan Reedy22405332014-07-30 19:24:32 -0400264
Steven M. Gava952d0a52001-08-03 04:43:44 +0000265 ##widget packing
266 #body
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400267 frameCustom.pack(side=LEFT, padx=5, pady=5, expand=TRUE, fill=BOTH)
268 frameTheme.pack(side=LEFT, padx=5, pady=5, fill=Y)
Steven M. Gava952d0a52001-08-03 04:43:44 +0000269 #frameCustom
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400270 self.frameColourSet.pack(side=TOP, padx=5, pady=5, expand=TRUE, fill=X)
271 frameFgBg.pack(side=TOP, padx=5, pady=0)
272 self.textHighlightSample.pack(
273 side=TOP, padx=5, pady=5, expand=TRUE, fill=BOTH)
274 buttonSetColour.pack(side=TOP, expand=TRUE, fill=X, padx=8, pady=4)
275 self.optMenuHighlightTarget.pack(
276 side=TOP, expand=TRUE, fill=X, padx=8, pady=3)
277 self.radioFg.pack(side=LEFT, anchor=E)
278 self.radioBg.pack(side=RIGHT, anchor=W)
279 buttonSaveCustomTheme.pack(side=BOTTOM, fill=X, padx=5, pady=5)
Steven M. Gava952d0a52001-08-03 04:43:44 +0000280 #frameTheme
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400281 labelTypeTitle.pack(side=TOP, anchor=W, padx=5, pady=5)
282 self.radioThemeBuiltin.pack(side=TOP, anchor=W, padx=5)
283 self.radioThemeCustom.pack(side=TOP, anchor=W, padx=5, pady=2)
284 self.optMenuThemeBuiltin.pack(side=TOP, fill=X, padx=5, pady=5)
285 self.optMenuThemeCustom.pack(side=TOP, fill=X, anchor=W, padx=5, pady=5)
286 self.buttonDeleteCustomTheme.pack(side=TOP, fill=X, padx=5, pady=5)
Steven M. Gava952d0a52001-08-03 04:43:44 +0000287 return frame
288
289 def CreatePageKeys(self):
Terry Jan Reedy22405332014-07-30 19:24:32 -0400290 parent = self.parent
291 self.bindingTarget = StringVar(parent)
292 self.builtinKeys = StringVar(parent)
293 self.customKeys = StringVar(parent)
294 self.keysAreBuiltin = BooleanVar(parent)
295 self.keyBinding = StringVar(parent)
296
Steven M. Gava60fc7072001-08-04 13:58:22 +0000297 ##widget creation
298 #body frame
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400299 frame = self.tabPages.pages['Keys'].frame
Steven M. Gava60fc7072001-08-04 13:58:22 +0000300 #body section frames
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400301 frameCustom = LabelFrame(
302 frame, borderwidth=2, relief=GROOVE,
303 text=' Custom Key Bindings ')
304 frameKeySets = LabelFrame(
305 frame, borderwidth=2, relief=GROOVE, text=' Key Set ')
Steven M. Gava60fc7072001-08-04 13:58:22 +0000306 #frameCustom
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400307 frameTarget = Frame(frameCustom)
308 labelTargetTitle = Label(frameTarget, text='Action - Key(s)')
309 scrollTargetY = Scrollbar(frameTarget)
310 scrollTargetX = Scrollbar(frameTarget, orient=HORIZONTAL)
311 self.listBindings = Listbox(
312 frameTarget, takefocus=FALSE, exportselection=FALSE)
313 self.listBindings.bind('<ButtonRelease-1>', self.KeyBindingSelected)
Steven M. Gavafacfc092002-01-19 00:29:54 +0000314 scrollTargetY.config(command=self.listBindings.yview)
315 scrollTargetX.config(command=self.listBindings.xview)
316 self.listBindings.config(yscrollcommand=scrollTargetY.set)
317 self.listBindings.config(xscrollcommand=scrollTargetX.set)
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400318 self.buttonNewKeys = Button(
319 frameCustom, text='Get New Keys for Selection',
320 command=self.GetNewKeys, state=DISABLED)
Steven M. Gava60fc7072001-08-04 13:58:22 +0000321 #frameKeySets
Christian Heimes9a371592007-12-28 14:08:13 +0000322 frames = [Frame(frameKeySets, padx=2, pady=2, borderwidth=0)
323 for i in range(2)]
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400324 self.radioKeysBuiltin = Radiobutton(
325 frames[0], variable=self.keysAreBuiltin, value=1,
326 command=self.SetKeysType, text='Use a Built-in Key Set')
327 self.radioKeysCustom = Radiobutton(
328 frames[0], variable=self.keysAreBuiltin, value=0,
329 command=self.SetKeysType, text='Use a Custom Key Set')
330 self.optMenuKeysBuiltin = DynOptionMenu(
331 frames[0], self.builtinKeys, None, command=None)
332 self.optMenuKeysCustom = DynOptionMenu(
333 frames[0], self.customKeys, None, command=None)
334 self.buttonDeleteCustomKeys = Button(
335 frames[1], text='Delete Custom Key Set',
Steven M. Gava49745752002-02-18 01:43:11 +0000336 command=self.DeleteCustomKeys)
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400337 buttonSaveCustomKeys = Button(
338 frames[1], text='Save as New Custom Key Set',
339 command=self.SaveAsNewKeySet)
Terry Jan Reedy22405332014-07-30 19:24:32 -0400340
Steven M. Gava60fc7072001-08-04 13:58:22 +0000341 ##widget packing
342 #body
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400343 frameCustom.pack(side=BOTTOM, padx=5, pady=5, expand=TRUE, fill=BOTH)
344 frameKeySets.pack(side=BOTTOM, padx=5, pady=5, fill=BOTH)
Steven M. Gava60fc7072001-08-04 13:58:22 +0000345 #frameCustom
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400346 self.buttonNewKeys.pack(side=BOTTOM, fill=X, padx=5, pady=5)
347 frameTarget.pack(side=LEFT, padx=5, pady=5, expand=TRUE, fill=BOTH)
Steven M. Gavafacfc092002-01-19 00:29:54 +0000348 #frame target
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400349 frameTarget.columnconfigure(0, weight=1)
350 frameTarget.rowconfigure(1, weight=1)
351 labelTargetTitle.grid(row=0, column=0, columnspan=2, sticky=W)
352 self.listBindings.grid(row=1, column=0, sticky=NSEW)
353 scrollTargetY.grid(row=1, column=1, sticky=NS)
354 scrollTargetX.grid(row=2, column=0, sticky=EW)
Steven M. Gava60fc7072001-08-04 13:58:22 +0000355 #frameKeySets
Christian Heimes9a371592007-12-28 14:08:13 +0000356 self.radioKeysBuiltin.grid(row=0, column=0, sticky=W+NS)
357 self.radioKeysCustom.grid(row=1, column=0, sticky=W+NS)
358 self.optMenuKeysBuiltin.grid(row=0, column=1, sticky=NSEW)
359 self.optMenuKeysCustom.grid(row=1, column=1, sticky=NSEW)
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400360 self.buttonDeleteCustomKeys.pack(side=LEFT, fill=X, expand=True, padx=2)
361 buttonSaveCustomKeys.pack(side=LEFT, fill=X, expand=True, padx=2)
Christian Heimes9a371592007-12-28 14:08:13 +0000362 frames[0].pack(side=TOP, fill=BOTH, expand=True)
363 frames[1].pack(side=TOP, fill=X, expand=True, pady=2)
Steven M. Gava952d0a52001-08-03 04:43:44 +0000364 return frame
365
366 def CreatePageGeneral(self):
Terry Jan Reedy22405332014-07-30 19:24:32 -0400367 parent = self.parent
368 self.winWidth = StringVar(parent)
369 self.winHeight = StringVar(parent)
Terry Jan Reedy22405332014-07-30 19:24:32 -0400370 self.startupEdit = IntVar(parent)
371 self.autoSave = IntVar(parent)
372 self.encoding = StringVar(parent)
373 self.userHelpBrowser = BooleanVar(parent)
374 self.helpBrowser = StringVar(parent)
375
Steven M. Gava230e5782001-08-07 03:28:25 +0000376 #widget creation
377 #body
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400378 frame = self.tabPages.pages['General'].frame
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000379 #body section frames
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400380 frameRun = LabelFrame(frame, borderwidth=2, relief=GROOVE,
381 text=' Startup Preferences ')
382 frameSave = LabelFrame(frame, borderwidth=2, relief=GROOVE,
383 text=' Autosave Preferences ')
384 frameWinSize = Frame(frame, borderwidth=2, relief=GROOVE)
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400385 frameHelp = LabelFrame(frame, borderwidth=2, relief=GROOVE,
386 text=' Additional Help Sources ')
Steven M. Gava230e5782001-08-07 03:28:25 +0000387 #frameRun
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400388 labelRunChoiceTitle = Label(frameRun, text='At Startup')
389 radioStartupEdit = Radiobutton(
390 frameRun, variable=self.startupEdit, value=1,
391 command=self.SetKeysType, text="Open Edit Window")
392 radioStartupShell = Radiobutton(
393 frameRun, variable=self.startupEdit, value=0,
394 command=self.SetKeysType, text='Open Shell Window')
Kurt B. Kaiser6c638b62003-05-26 06:23:10 +0000395 #frameSave
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400396 labelRunSaveTitle = Label(frameSave, text='At Start of Run (F5) ')
397 radioSaveAsk = Radiobutton(
398 frameSave, variable=self.autoSave, value=0,
399 command=self.SetKeysType, text="Prompt to Save")
400 radioSaveAuto = Radiobutton(
401 frameSave, variable=self.autoSave, value=1,
402 command=self.SetKeysType, text='No Prompt')
Steven M. Gava230e5782001-08-07 03:28:25 +0000403 #frameWinSize
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400404 labelWinSizeTitle = Label(
405 frameWinSize, text='Initial Window Size (in characters)')
406 labelWinWidthTitle = Label(frameWinSize, text='Width')
407 entryWinWidth = Entry(
408 frameWinSize, textvariable=self.winWidth, width=3)
409 labelWinHeightTitle = Label(frameWinSize, text='Height')
410 entryWinHeight = Entry(
411 frameWinSize, textvariable=self.winHeight, width=3)
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000412 #frameHelp
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400413 frameHelpList = Frame(frameHelp)
414 frameHelpListButtons = Frame(frameHelpList)
415 scrollHelpList = Scrollbar(frameHelpList)
416 self.listHelp = Listbox(
417 frameHelpList, height=5, takefocus=FALSE,
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000418 exportselection=FALSE)
419 scrollHelpList.config(command=self.listHelp.yview)
420 self.listHelp.config(yscrollcommand=scrollHelpList.set)
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400421 self.listHelp.bind('<ButtonRelease-1>', self.HelpSourceSelected)
422 self.buttonHelpListEdit = Button(
423 frameHelpListButtons, text='Edit', state=DISABLED,
424 width=8, command=self.HelpListItemEdit)
425 self.buttonHelpListAdd = Button(
426 frameHelpListButtons, text='Add',
427 width=8, command=self.HelpListItemAdd)
428 self.buttonHelpListRemove = Button(
429 frameHelpListButtons, text='Remove', state=DISABLED,
430 width=8, command=self.HelpListItemRemove)
Terry Jan Reedy22405332014-07-30 19:24:32 -0400431
Steven M. Gava230e5782001-08-07 03:28:25 +0000432 #widget packing
433 #body
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400434 frameRun.pack(side=TOP, padx=5, pady=5, fill=X)
435 frameSave.pack(side=TOP, padx=5, pady=5, fill=X)
436 frameWinSize.pack(side=TOP, padx=5, pady=5, fill=X)
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400437 frameHelp.pack(side=TOP, padx=5, pady=5, expand=TRUE, fill=BOTH)
Steven M. Gava230e5782001-08-07 03:28:25 +0000438 #frameRun
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400439 labelRunChoiceTitle.pack(side=LEFT, anchor=W, padx=5, pady=5)
440 radioStartupShell.pack(side=RIGHT, anchor=W, padx=5, pady=5)
441 radioStartupEdit.pack(side=RIGHT, anchor=W, padx=5, pady=5)
Kurt B. Kaiser6c638b62003-05-26 06:23:10 +0000442 #frameSave
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400443 labelRunSaveTitle.pack(side=LEFT, anchor=W, padx=5, pady=5)
444 radioSaveAuto.pack(side=RIGHT, anchor=W, padx=5, pady=5)
445 radioSaveAsk.pack(side=RIGHT, anchor=W, padx=5, pady=5)
Steven M. Gava230e5782001-08-07 03:28:25 +0000446 #frameWinSize
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400447 labelWinSizeTitle.pack(side=LEFT, anchor=W, padx=5, pady=5)
448 entryWinHeight.pack(side=RIGHT, anchor=E, padx=10, pady=5)
449 labelWinHeightTitle.pack(side=RIGHT, anchor=E, pady=5)
450 entryWinWidth.pack(side=RIGHT, anchor=E, padx=10, pady=5)
451 labelWinWidthTitle.pack(side=RIGHT, anchor=E, pady=5)
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000452 #frameHelp
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400453 frameHelpListButtons.pack(side=RIGHT, padx=5, pady=5, fill=Y)
454 frameHelpList.pack(side=TOP, padx=5, pady=5, expand=TRUE, fill=BOTH)
455 scrollHelpList.pack(side=RIGHT, anchor=W, fill=Y)
456 self.listHelp.pack(side=LEFT, anchor=E, expand=TRUE, fill=BOTH)
457 self.buttonHelpListEdit.pack(side=TOP, anchor=W, pady=5)
458 self.buttonHelpListAdd.pack(side=TOP, anchor=W)
459 self.buttonHelpListRemove.pack(side=TOP, anchor=W, pady=5)
Steven M. Gava952d0a52001-08-03 04:43:44 +0000460 return frame
461
Steven M. Gavac112cd82002-01-22 05:56:40 +0000462 def AttachVarCallbacks(self):
Terry Jan Reedyd87d1682015-08-01 18:57:33 -0400463 self.fontSize.trace_variable('w', self.VarChanged_font)
464 self.fontName.trace_variable('w', self.VarChanged_font)
465 self.fontBold.trace_variable('w', self.VarChanged_font)
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400466 self.spaceNum.trace_variable('w', self.VarChanged_spaceNum)
467 self.colour.trace_variable('w', self.VarChanged_colour)
468 self.builtinTheme.trace_variable('w', self.VarChanged_builtinTheme)
469 self.customTheme.trace_variable('w', self.VarChanged_customTheme)
470 self.themeIsBuiltin.trace_variable('w', self.VarChanged_themeIsBuiltin)
471 self.highlightTarget.trace_variable('w', self.VarChanged_highlightTarget)
472 self.keyBinding.trace_variable('w', self.VarChanged_keyBinding)
473 self.builtinKeys.trace_variable('w', self.VarChanged_builtinKeys)
474 self.customKeys.trace_variable('w', self.VarChanged_customKeys)
475 self.keysAreBuiltin.trace_variable('w', self.VarChanged_keysAreBuiltin)
476 self.winWidth.trace_variable('w', self.VarChanged_winWidth)
477 self.winHeight.trace_variable('w', self.VarChanged_winHeight)
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400478 self.startupEdit.trace_variable('w', self.VarChanged_startupEdit)
479 self.autoSave.trace_variable('w', self.VarChanged_autoSave)
480 self.encoding.trace_variable('w', self.VarChanged_encoding)
Steven M. Gava052937f2002-02-11 02:20:53 +0000481
Terry Jan Reedyd87d1682015-08-01 18:57:33 -0400482 def VarChanged_font(self, *params):
483 '''When one font attribute changes, save them all, as they are
484 not independent from each other. In particular, when we are
485 overriding the default font, we need to write out everything.
486 '''
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400487 value = self.fontName.get()
488 self.AddChangedItem('main', 'EditorWindow', 'font', value)
Terry Jan Reedyd87d1682015-08-01 18:57:33 -0400489 value = self.fontSize.get()
490 self.AddChangedItem('main', 'EditorWindow', 'font-size', value)
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400491 value = self.fontBold.get()
492 self.AddChangedItem('main', 'EditorWindow', 'font-bold', value)
Steven M. Gavac112cd82002-01-22 05:56:40 +0000493
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400494 def VarChanged_spaceNum(self, *params):
495 value = self.spaceNum.get()
496 self.AddChangedItem('main', 'Indent', 'num-spaces', value)
Steven M. Gavac112cd82002-01-22 05:56:40 +0000497
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400498 def VarChanged_colour(self, *params):
Steven M. Gava052937f2002-02-11 02:20:53 +0000499 self.OnNewColourSet()
500
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400501 def VarChanged_builtinTheme(self, *params):
502 value = self.builtinTheme.get()
Terry Jan Reedybe5b7a22015-10-04 00:31:05 -0400503 if value == 'IDLE Dark':
504 tkMessageBox.showwarning(
505 title="The 'IDLE Dark' Text Color Theme",
506 message="IDLE Dark is new in October, 2015. Trying to "
507 "run earlier versions of IDLE with it selected "
508 "will disable colorizing, or worse.\n\n"
509 "If you might ever run an earlier release of IDLE, "
510 "then before exiting this version, "
511 "either switch to another theme or "
512 "hit the 'Save as New Custom Theme' button. "
513 "The latter requires a new name, such as "
514 "'Custom Dark', but the custom theme will work "
515 "with any IDLE release, and can be modified.",
516 parent=self)
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400517 self.AddChangedItem('main', 'Theme', 'name', value)
Steven M. Gava052937f2002-02-11 02:20:53 +0000518 self.PaintThemeSample()
519
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400520 def VarChanged_customTheme(self, *params):
521 value = self.customTheme.get()
Steven M. Gava49745752002-02-18 01:43:11 +0000522 if value != '- no custom themes -':
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400523 self.AddChangedItem('main', 'Theme', 'name', value)
Steven M. Gava49745752002-02-18 01:43:11 +0000524 self.PaintThemeSample()
Steven M. Gava052937f2002-02-11 02:20:53 +0000525
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400526 def VarChanged_themeIsBuiltin(self, *params):
527 value = self.themeIsBuiltin.get()
528 self.AddChangedItem('main', 'Theme', 'default', value)
Steven M. Gavaf31eec02002-03-05 00:25:58 +0000529 if value:
530 self.VarChanged_builtinTheme()
531 else:
532 self.VarChanged_customTheme()
Steven M. Gava052937f2002-02-11 02:20:53 +0000533
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400534 def VarChanged_highlightTarget(self, *params):
Steven M. Gava052937f2002-02-11 02:20:53 +0000535 self.SetHighlightTarget()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000536
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400537 def VarChanged_keyBinding(self, *params):
538 value = self.keyBinding.get()
539 keySet = self.customKeys.get()
540 event = self.listBindings.get(ANCHOR).split()[0]
Steven M. Gavaa498af22002-02-01 01:33:36 +0000541 if idleConf.IsCoreBinding(event):
542 #this is a core keybinding
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400543 self.AddChangedItem('keys', keySet, event, value)
Steven M. Gavaa498af22002-02-01 01:33:36 +0000544 else: #this is an extension key binding
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400545 extName = idleConf.GetExtnNameForEvent(event)
546 extKeybindSection = extName + '_cfgBindings'
547 self.AddChangedItem('extensions', extKeybindSection, event, value)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000548
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400549 def VarChanged_builtinKeys(self, *params):
550 value = self.builtinKeys.get()
551 self.AddChangedItem('main', 'Keys', 'name', value)
Steven M. Gava052937f2002-02-11 02:20:53 +0000552 self.LoadKeysList(value)
553
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400554 def VarChanged_customKeys(self, *params):
555 value = self.customKeys.get()
Steven M. Gava49745752002-02-18 01:43:11 +0000556 if value != '- no custom keys -':
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400557 self.AddChangedItem('main', 'Keys', 'name', value)
Steven M. Gava49745752002-02-18 01:43:11 +0000558 self.LoadKeysList(value)
Steven M. Gava052937f2002-02-11 02:20:53 +0000559
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400560 def VarChanged_keysAreBuiltin(self, *params):
561 value = self.keysAreBuiltin.get()
562 self.AddChangedItem('main', 'Keys', 'default', value)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000563 if value:
Steven M. Gavaf31eec02002-03-05 00:25:58 +0000564 self.VarChanged_builtinKeys()
Steven M. Gava052937f2002-02-11 02:20:53 +0000565 else:
Steven M. Gavaf31eec02002-03-05 00:25:58 +0000566 self.VarChanged_customKeys()
Steven M. Gava052937f2002-02-11 02:20:53 +0000567
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400568 def VarChanged_winWidth(self, *params):
569 value = self.winWidth.get()
570 self.AddChangedItem('main', 'EditorWindow', 'width', value)
Steven M. Gavac112cd82002-01-22 05:56:40 +0000571
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400572 def VarChanged_winHeight(self, *params):
573 value = self.winHeight.get()
574 self.AddChangedItem('main', 'EditorWindow', 'height', value)
Steven M. Gavac112cd82002-01-22 05:56:40 +0000575
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400576 def VarChanged_startupEdit(self, *params):
577 value = self.startupEdit.get()
578 self.AddChangedItem('main', 'General', 'editor-on-startup', value)
Steven M. Gavac112cd82002-01-22 05:56:40 +0000579
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400580 def VarChanged_autoSave(self, *params):
581 value = self.autoSave.get()
582 self.AddChangedItem('main', 'General', 'autosave', value)
Kurt B. Kaiser6c638b62003-05-26 06:23:10 +0000583
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400584 def VarChanged_encoding(self, *params):
585 value = self.encoding.get()
586 self.AddChangedItem('main', 'EditorWindow', 'encoding', value)
Kurt B. Kaisera053f332003-05-10 00:49:56 +0000587
Steven M. Gavaa498af22002-02-01 01:33:36 +0000588 def ResetChangedItems(self):
Steven M. Gavab77d3432002-03-02 07:16:21 +0000589 #When any config item is changed in this dialog, an entry
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000590 #should be made in the relevant section (config type) of this
591 #dictionary. The key should be the config file section name and the
Steven M. Gavaa498af22002-02-01 01:33:36 +0000592 #value a dictionary, whose key:value pairs are item=value pairs for
593 #that config file section.
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400594 self.changedItems = {'main':{}, 'highlight':{}, 'keys':{},
595 'extensions':{}}
Steven M. Gavaa498af22002-02-01 01:33:36 +0000596
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400597 def AddChangedItem(self, typ, section, item, value):
598 value = str(value) #make sure we use a string
599 if section not in self.changedItems[typ]:
600 self.changedItems[typ][section] = {}
601 self.changedItems[typ][section][item] = value
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000602
Steven M. Gava5f28e8f2002-01-21 06:38:21 +0000603 def GetDefaultItems(self):
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400604 dItems={'main':{}, 'highlight':{}, 'keys':{}, 'extensions':{}}
Kurt B. Kaisere0712772007-08-23 05:25:55 +0000605 for configType in dItems:
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400606 sections = idleConf.GetSectionList('default', configType)
Steven M. Gava5f28e8f2002-01-21 06:38:21 +0000607 for section in sections:
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400608 dItems[configType][section] = {}
609 options = idleConf.defaultCfg[configType].GetOptionList(section)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000610 for option in options:
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400611 dItems[configType][section][option] = (
612 idleConf.defaultCfg[configType].Get(section, option))
Steven M. Gava5f28e8f2002-01-21 06:38:21 +0000613 return dItems
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000614
Steven M. Gava5f28e8f2002-01-21 06:38:21 +0000615 def SetThemeType(self):
616 if self.themeIsBuiltin.get():
617 self.optMenuThemeBuiltin.config(state=NORMAL)
618 self.optMenuThemeCustom.config(state=DISABLED)
619 self.buttonDeleteCustomTheme.config(state=DISABLED)
620 else:
621 self.optMenuThemeBuiltin.config(state=DISABLED)
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000622 self.radioThemeCustom.config(state=NORMAL)
Steven M. Gava5f28e8f2002-01-21 06:38:21 +0000623 self.optMenuThemeCustom.config(state=NORMAL)
624 self.buttonDeleteCustomTheme.config(state=NORMAL)
625
626 def SetKeysType(self):
Steven M. Gava052937f2002-02-11 02:20:53 +0000627 if self.keysAreBuiltin.get():
Steven M. Gava5f28e8f2002-01-21 06:38:21 +0000628 self.optMenuKeysBuiltin.config(state=NORMAL)
629 self.optMenuKeysCustom.config(state=DISABLED)
630 self.buttonDeleteCustomKeys.config(state=DISABLED)
631 else:
632 self.optMenuKeysBuiltin.config(state=DISABLED)
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000633 self.radioKeysCustom.config(state=NORMAL)
Steven M. Gava5f28e8f2002-01-21 06:38:21 +0000634 self.optMenuKeysCustom.config(state=NORMAL)
635 self.buttonDeleteCustomKeys.config(state=NORMAL)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000636
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000637 def GetNewKeys(self):
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400638 listIndex = self.listBindings.index(ANCHOR)
639 binding = self.listBindings.get(listIndex)
640 bindName = binding.split()[0] #first part, up to first space
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000641 if self.keysAreBuiltin.get():
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400642 currentKeySetName = self.builtinKeys.get()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000643 else:
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400644 currentKeySetName = self.customKeys.get()
645 currentBindings = idleConf.GetCurrentKeySet()
Kurt B. Kaisere0712772007-08-23 05:25:55 +0000646 if currentKeySetName in self.changedItems['keys']: #unsaved changes
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400647 keySetChanges = self.changedItems['keys'][currentKeySetName]
Kurt B. Kaisere0712772007-08-23 05:25:55 +0000648 for event in keySetChanges:
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400649 currentBindings[event] = keySetChanges[event].split()
Kurt B. Kaisere0712772007-08-23 05:25:55 +0000650 currentKeySequences = list(currentBindings.values())
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400651 newKeys = GetKeysDialog(self, 'Get New Keys', bindName,
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000652 currentKeySequences).result
653 if newKeys: #new keys were specified
Steven M. Gava052937f2002-02-11 02:20:53 +0000654 if self.keysAreBuiltin.get(): #current key set is a built-in
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400655 message = ('Your changes will be saved as a new Custom Key Set.'
656 ' Enter a name for your new Custom Key Set below.')
657 newKeySet = self.GetNewKeysName(message)
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000658 if not newKeySet: #user cancelled custom key set creation
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000659 self.listBindings.select_set(listIndex)
660 self.listBindings.select_anchor(listIndex)
661 return
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000662 else: #create new custom key set based on previously active key set
663 self.CreateNewKeySet(newKeySet)
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000664 self.listBindings.delete(listIndex)
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400665 self.listBindings.insert(listIndex, bindName+' - '+newKeys)
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000666 self.listBindings.select_set(listIndex)
667 self.listBindings.select_anchor(listIndex)
Steven M. Gava052937f2002-02-11 02:20:53 +0000668 self.keyBinding.set(newKeys)
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000669 else:
670 self.listBindings.select_set(listIndex)
671 self.listBindings.select_anchor(listIndex)
672
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400673 def GetNewKeysName(self, message):
674 usedNames = (idleConf.GetSectionList('user', 'keys') +
675 idleConf.GetSectionList('default', 'keys'))
676 newKeySet = GetCfgSectionNameDialog(
677 self, 'New Custom Key Set', message, usedNames).result
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000678 return newKeySet
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000679
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000680 def SaveAsNewKeySet(self):
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400681 newKeysName = self.GetNewKeysName('New Key Set Name:')
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000682 if newKeysName:
683 self.CreateNewKeySet(newKeysName)
684
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400685 def KeyBindingSelected(self, event):
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000686 self.buttonNewKeys.config(state=NORMAL)
687
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400688 def CreateNewKeySet(self, newKeySetName):
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000689 #creates new custom key set based on the previously active key set,
690 #and makes the new key set active
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000691 if self.keysAreBuiltin.get():
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400692 prevKeySetName = self.builtinKeys.get()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000693 else:
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400694 prevKeySetName = self.customKeys.get()
695 prevKeys = idleConf.GetCoreKeys(prevKeySetName)
696 newKeys = {}
Kurt B. Kaisere0712772007-08-23 05:25:55 +0000697 for event in prevKeys: #add key set to changed items
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400698 eventName = event[2:-2] #trim off the angle brackets
699 binding = ' '.join(prevKeys[event])
700 newKeys[eventName] = binding
Steven M. Gava052937f2002-02-11 02:20:53 +0000701 #handle any unsaved changes to prev key set
Kurt B. Kaisere0712772007-08-23 05:25:55 +0000702 if prevKeySetName in self.changedItems['keys']:
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400703 keySetChanges = self.changedItems['keys'][prevKeySetName]
Kurt B. Kaisere0712772007-08-23 05:25:55 +0000704 for event in keySetChanges:
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400705 newKeys[event] = keySetChanges[event]
Steven M. Gava052937f2002-02-11 02:20:53 +0000706 #save the new theme
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400707 self.SaveNewKeySet(newKeySetName, newKeys)
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000708 #change gui over to the new key set
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400709 customKeyList = idleConf.GetSectionList('user', 'keys')
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000710 customKeyList.sort()
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400711 self.optMenuKeysCustom.SetMenu(customKeyList, newKeySetName)
Steven M. Gava052937f2002-02-11 02:20:53 +0000712 self.keysAreBuiltin.set(0)
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000713 self.SetKeysType()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000714
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400715 def LoadKeysList(self, keySetName):
716 reselect = 0
717 newKeySet = 0
Steven M. Gava052937f2002-02-11 02:20:53 +0000718 if self.listBindings.curselection():
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400719 reselect = 1
720 listIndex = self.listBindings.index(ANCHOR)
721 keySet = idleConf.GetKeySet(keySetName)
Kurt B. Kaisere0712772007-08-23 05:25:55 +0000722 bindNames = list(keySet.keys())
Steven M. Gava052937f2002-02-11 02:20:53 +0000723 bindNames.sort()
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400724 self.listBindings.delete(0, END)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000725 for bindName in bindNames:
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400726 key = ' '.join(keySet[bindName]) #make key(s) into a string
727 bindName = bindName[2:-2] #trim off the angle brackets
Kurt B. Kaisere0712772007-08-23 05:25:55 +0000728 if keySetName in self.changedItems['keys']:
Steven M. Gava052937f2002-02-11 02:20:53 +0000729 #handle any unsaved changes to this key set
Kurt B. Kaisere0712772007-08-23 05:25:55 +0000730 if bindName in self.changedItems['keys'][keySetName]:
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400731 key = self.changedItems['keys'][keySetName][bindName]
Steven M. Gava052937f2002-02-11 02:20:53 +0000732 self.listBindings.insert(END, bindName+' - '+key)
Steven M. Gava052937f2002-02-11 02:20:53 +0000733 if reselect:
734 self.listBindings.see(listIndex)
735 self.listBindings.select_set(listIndex)
736 self.listBindings.select_anchor(listIndex)
737
Steven M. Gava49745752002-02-18 01:43:11 +0000738 def DeleteCustomKeys(self):
739 keySetName=self.customKeys.get()
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400740 delmsg = 'Are you sure you wish to delete the key set %r ?'
741 if not tkMessageBox.askyesno(
742 'Delete Key Set', delmsg % keySetName, parent=self):
Steven M. Gava49745752002-02-18 01:43:11 +0000743 return
744 #remove key set from config
745 idleConf.userCfg['keys'].remove_section(keySetName)
Guido van Rossum811c4e02006-08-22 15:45:46 +0000746 if keySetName in self.changedItems['keys']:
Steven M. Gava49745752002-02-18 01:43:11 +0000747 del(self.changedItems['keys'][keySetName])
748 #write changes
749 idleConf.userCfg['keys'].Save()
750 #reload user key set list
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400751 itemList = idleConf.GetSectionList('user', 'keys')
Steven M. Gava49745752002-02-18 01:43:11 +0000752 itemList.sort()
753 if not itemList:
754 self.radioKeysCustom.config(state=DISABLED)
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400755 self.optMenuKeysCustom.SetMenu(itemList, '- no custom keys -')
Steven M. Gava49745752002-02-18 01:43:11 +0000756 else:
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400757 self.optMenuKeysCustom.SetMenu(itemList, itemList[0])
Steven M. Gava49745752002-02-18 01:43:11 +0000758 #revert to default key set
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400759 self.keysAreBuiltin.set(idleConf.defaultCfg['main'].Get('Keys', 'default'))
760 self.builtinKeys.set(idleConf.defaultCfg['main'].Get('Keys', 'name'))
Steven M. Gava49745752002-02-18 01:43:11 +0000761 #user can't back out of these changes, they must be applied now
762 self.Apply()
763 self.SetKeysType()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000764
Steven M. Gava49745752002-02-18 01:43:11 +0000765 def DeleteCustomTheme(self):
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400766 themeName = self.customTheme.get()
767 delmsg = 'Are you sure you wish to delete the theme %r ?'
768 if not tkMessageBox.askyesno(
769 'Delete Theme', delmsg % themeName, parent=self):
Steven M. Gava49745752002-02-18 01:43:11 +0000770 return
771 #remove theme from config
772 idleConf.userCfg['highlight'].remove_section(themeName)
Guido van Rossum811c4e02006-08-22 15:45:46 +0000773 if themeName in self.changedItems['highlight']:
Steven M. Gava49745752002-02-18 01:43:11 +0000774 del(self.changedItems['highlight'][themeName])
775 #write changes
776 idleConf.userCfg['highlight'].Save()
777 #reload user theme list
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400778 itemList = idleConf.GetSectionList('user', 'highlight')
Steven M. Gava49745752002-02-18 01:43:11 +0000779 itemList.sort()
780 if not itemList:
781 self.radioThemeCustom.config(state=DISABLED)
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400782 self.optMenuThemeCustom.SetMenu(itemList, '- no custom themes -')
Steven M. Gava49745752002-02-18 01:43:11 +0000783 else:
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400784 self.optMenuThemeCustom.SetMenu(itemList, itemList[0])
Steven M. Gava49745752002-02-18 01:43:11 +0000785 #revert to default theme
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400786 self.themeIsBuiltin.set(idleConf.defaultCfg['main'].Get('Theme', 'default'))
787 self.builtinTheme.set(idleConf.defaultCfg['main'].Get('Theme', 'name'))
Steven M. Gava49745752002-02-18 01:43:11 +0000788 #user can't back out of these changes, they must be applied now
789 self.Apply()
790 self.SetThemeType()
791
Steven M. Gava5f28e8f2002-01-21 06:38:21 +0000792 def GetColour(self):
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400793 target = self.highlightTarget.get()
794 prevColour = self.frameColourSet.cget('bg')
795 rgbTuplet, colourString = tkColorChooser.askcolor(
796 parent=self, title='Pick new colour for : '+target,
797 initialcolor=prevColour)
798 if colourString and (colourString != prevColour):
Steven M. Gava052937f2002-02-11 02:20:53 +0000799 #user didn't cancel, and they chose a new colour
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400800 if self.themeIsBuiltin.get(): #current theme is a built-in
801 message = ('Your changes will be saved as a new Custom Theme. '
802 'Enter a name for your new Custom Theme below.')
803 newTheme = self.GetNewThemeName(message)
804 if not newTheme: #user cancelled custom theme creation
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000805 return
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400806 else: #create new custom theme based on previously active theme
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000807 self.CreateNewTheme(newTheme)
Steven M. Gava052937f2002-02-11 02:20:53 +0000808 self.colour.set(colourString)
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400809 else: #current theme is user defined
Steven M. Gava052937f2002-02-11 02:20:53 +0000810 self.colour.set(colourString)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000811
Steven M. Gava052937f2002-02-11 02:20:53 +0000812 def OnNewColourSet(self):
813 newColour=self.colour.get()
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400814 self.frameColourSet.config(bg=newColour) #set sample
815 plane ='foreground' if self.fgHilite.get() else 'background'
816 sampleElement = self.themeElements[self.highlightTarget.get()][0]
Raymond Hettinger931237e2003-07-09 18:48:24 +0000817 self.textHighlightSample.tag_config(sampleElement, **{plane:newColour})
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400818 theme = self.customTheme.get()
819 themeElement = sampleElement + '-' + plane
820 self.AddChangedItem('highlight', theme, themeElement, newColour)
Steven M. Gava052937f2002-02-11 02:20:53 +0000821
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400822 def GetNewThemeName(self, message):
823 usedNames = (idleConf.GetSectionList('user', 'highlight') +
824 idleConf.GetSectionList('default', 'highlight'))
825 newTheme = GetCfgSectionNameDialog(
826 self, 'New Custom Theme', message, usedNames).result
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000827 return newTheme
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000828
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000829 def SaveAsNewTheme(self):
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400830 newThemeName = self.GetNewThemeName('New Theme Name:')
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000831 if newThemeName:
832 self.CreateNewTheme(newThemeName)
833
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400834 def CreateNewTheme(self, newThemeName):
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000835 #creates new custom theme based on the previously active theme,
836 #and makes the new theme active
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000837 if self.themeIsBuiltin.get():
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400838 themeType = 'default'
839 themeName = self.builtinTheme.get()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000840 else:
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400841 themeType = 'user'
842 themeName = self.customTheme.get()
843 newTheme = idleConf.GetThemeDict(themeType, themeName)
Steven M. Gava052937f2002-02-11 02:20:53 +0000844 #apply any of the old theme's unsaved changes to the new theme
Kurt B. Kaisere0712772007-08-23 05:25:55 +0000845 if themeName in self.changedItems['highlight']:
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400846 themeChanges = self.changedItems['highlight'][themeName]
Kurt B. Kaisere0712772007-08-23 05:25:55 +0000847 for element in themeChanges:
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400848 newTheme[element] = themeChanges[element]
Steven M. Gava052937f2002-02-11 02:20:53 +0000849 #save the new theme
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400850 self.SaveNewTheme(newThemeName, newTheme)
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000851 #change gui over to the new theme
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400852 customThemeList = idleConf.GetSectionList('user', 'highlight')
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000853 customThemeList.sort()
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400854 self.optMenuThemeCustom.SetMenu(customThemeList, newThemeName)
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000855 self.themeIsBuiltin.set(0)
856 self.SetThemeType()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000857
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400858 def OnListFontButtonRelease(self, event):
Kurt B. Kaiser05391692003-05-26 20:35:53 +0000859 font = self.listFontName.get(ANCHOR)
860 self.fontName.set(font.lower())
Steven M. Gava5f28e8f2002-01-21 06:38:21 +0000861 self.SetFontSample()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000862
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400863 def SetFontSample(self, event=None):
864 fontName = self.fontName.get()
865 fontWeight = tkFont.BOLD if self.fontBold.get() else tkFont.NORMAL
Ned Deilyfdf0f272012-10-22 15:14:31 -0700866 newFont = (fontName, self.fontSize.get(), fontWeight)
867 self.labelFontSample.config(font=newFont)
868 self.textHighlightSample.configure(font=newFont)
Steven M. Gava5f28e8f2002-01-21 06:38:21 +0000869
Steven M. Gava5f28e8f2002-01-21 06:38:21 +0000870 def SetHighlightTarget(self):
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400871 if self.highlightTarget.get() == 'Cursor': #bg not possible
Steven M. Gava5f28e8f2002-01-21 06:38:21 +0000872 self.radioFg.config(state=DISABLED)
873 self.radioBg.config(state=DISABLED)
874 self.fgHilite.set(1)
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400875 else: #both fg and bg can be set
Steven M. Gava5f28e8f2002-01-21 06:38:21 +0000876 self.radioFg.config(state=NORMAL)
877 self.radioBg.config(state=NORMAL)
878 self.fgHilite.set(1)
879 self.SetColourSample()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000880
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400881 def SetColourSampleBinding(self, *args):
Steven M. Gava5f28e8f2002-01-21 06:38:21 +0000882 self.SetColourSample()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000883
Steven M. Gava5f28e8f2002-01-21 06:38:21 +0000884 def SetColourSample(self):
885 #set the colour smaple area
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400886 tag = self.themeElements[self.highlightTarget.get()][0]
887 plane = 'foreground' if self.fgHilite.get() else 'background'
888 colour = self.textHighlightSample.tag_cget(tag, plane)
Steven M. Gava5f28e8f2002-01-21 06:38:21 +0000889 self.frameColourSet.config(bg=colour)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000890
Steven M. Gava9dd16b32001-11-03 14:54:25 +0000891 def PaintThemeSample(self):
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400892 if self.themeIsBuiltin.get(): #a default theme
893 theme = self.builtinTheme.get()
894 else: #a user theme
895 theme = self.customTheme.get()
Kurt B. Kaisere0712772007-08-23 05:25:55 +0000896 for elementTitle in self.themeElements:
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400897 element = self.themeElements[elementTitle][0]
898 colours = idleConf.GetHighlight(theme, element)
899 if element == 'cursor': #cursor sample needs special painting
900 colours['background'] = idleConf.GetHighlight(
901 theme, 'normal', fgBg='bg')
Steven M. Gava052937f2002-02-11 02:20:53 +0000902 #handle any unsaved changes to this theme
Kurt B. Kaisere0712772007-08-23 05:25:55 +0000903 if theme in self.changedItems['highlight']:
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400904 themeDict = self.changedItems['highlight'][theme]
905 if element + '-foreground' in themeDict:
906 colours['foreground'] = themeDict[element + '-foreground']
907 if element + '-background' in themeDict:
908 colours['background'] = themeDict[element + '-background']
Raymond Hettinger931237e2003-07-09 18:48:24 +0000909 self.textHighlightSample.tag_config(element, **colours)
Steven M. Gava052937f2002-02-11 02:20:53 +0000910 self.SetColourSample()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000911
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400912 def HelpSourceSelected(self, event):
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000913 self.SetHelpListButtonStates()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000914
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000915 def SetHelpListButtonStates(self):
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400916 if self.listHelp.size() < 1: #no entries in list
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000917 self.buttonHelpListEdit.config(state=DISABLED)
918 self.buttonHelpListRemove.config(state=DISABLED)
919 else: #there are some entries
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400920 if self.listHelp.curselection(): #there currently is a selection
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000921 self.buttonHelpListEdit.config(state=NORMAL)
922 self.buttonHelpListRemove.config(state=NORMAL)
923 else: #there currently is not a selection
924 self.buttonHelpListEdit.config(state=DISABLED)
925 self.buttonHelpListRemove.config(state=DISABLED)
926
927 def HelpListItemAdd(self):
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400928 helpSource = GetHelpSourceDialog(self, 'New Help Source').result
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000929 if helpSource:
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400930 self.userHelpList.append((helpSource[0], helpSource[1]))
931 self.listHelp.insert(END, helpSource[0])
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000932 self.UpdateUserHelpChangedItems()
933 self.SetHelpListButtonStates()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000934
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000935 def HelpListItemEdit(self):
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400936 itemIndex = self.listHelp.index(ANCHOR)
937 helpSource = self.userHelpList[itemIndex]
938 newHelpSource = GetHelpSourceDialog(
939 self, 'Edit Help Source', menuItem=helpSource[0],
940 filePath=helpSource[1]).result
941 if (not newHelpSource) or (newHelpSource == helpSource):
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000942 return #no changes
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400943 self.userHelpList[itemIndex] = newHelpSource
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000944 self.listHelp.delete(itemIndex)
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400945 self.listHelp.insert(itemIndex, newHelpSource[0])
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000946 self.UpdateUserHelpChangedItems()
947 self.SetHelpListButtonStates()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000948
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000949 def HelpListItemRemove(self):
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400950 itemIndex = self.listHelp.index(ANCHOR)
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000951 del(self.userHelpList[itemIndex])
952 self.listHelp.delete(itemIndex)
953 self.UpdateUserHelpChangedItems()
954 self.SetHelpListButtonStates()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000955
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000956 def UpdateUserHelpChangedItems(self):
Kurt B. Kaiser8e92bf72003-01-14 22:03:31 +0000957 "Clear and rebuild the HelpFiles section in self.changedItems"
958 self.changedItems['main']['HelpFiles'] = {}
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400959 for num in range(1, len(self.userHelpList) + 1):
960 self.AddChangedItem(
961 'main', 'HelpFiles', str(num),
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000962 ';'.join(self.userHelpList[num-1][:2]))
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000963
Steven M. Gava429a86af2001-10-23 10:42:12 +0000964 def LoadFontCfg(self):
965 ##base editor font selection list
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400966 fonts = list(tkFont.families(self))
Steven M. Gavac11ccf32001-09-24 09:43:17 +0000967 fonts.sort()
968 for font in fonts:
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400969 self.listFontName.insert(END, font)
Terry Jan Reedyd87d1682015-08-01 18:57:33 -0400970 configuredFont = idleConf.GetFont(self, 'main', 'EditorWindow')
971 fontName = configuredFont[0].lower()
972 fontSize = configuredFont[1]
973 fontBold = configuredFont[2]=='bold'
974 self.fontName.set(fontName)
Kurt B. Kaiser05391692003-05-26 20:35:53 +0000975 lc_fonts = [s.lower() for s in fonts]
Terry Jan Reedyd87d1682015-08-01 18:57:33 -0400976 try:
977 currentFontIndex = lc_fonts.index(fontName)
Steven M. Gava429a86af2001-10-23 10:42:12 +0000978 self.listFontName.see(currentFontIndex)
979 self.listFontName.select_set(currentFontIndex)
Steven M. Gavac112cd82002-01-22 05:56:40 +0000980 self.listFontName.select_anchor(currentFontIndex)
Terry Jan Reedyd87d1682015-08-01 18:57:33 -0400981 except ValueError:
982 pass
Steven M. Gava429a86af2001-10-23 10:42:12 +0000983 ##font size dropdown
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400984 self.optMenuFontSize.SetMenu(('7', '8', '9', '10', '11', '12', '13',
985 '14', '16', '18', '20', '22'), fontSize )
Steven M. Gavac112cd82002-01-22 05:56:40 +0000986 ##fontWeight
Terry Jan Reedyd87d1682015-08-01 18:57:33 -0400987 self.fontBold.set(fontBold)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000988 ##font sample
Steven M. Gava429a86af2001-10-23 10:42:12 +0000989 self.SetFontSample()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000990
Steven M. Gava429a86af2001-10-23 10:42:12 +0000991 def LoadTabCfg(self):
Steven M. Gava429a86af2001-10-23 10:42:12 +0000992 ##indent sizes
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400993 spaceNum = idleConf.GetOption(
994 'main', 'Indent', 'num-spaces', default=4, type='int')
Steven M. Gava429a86af2001-10-23 10:42:12 +0000995 self.spaceNum.set(spaceNum)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000996
Steven M. Gava9dd16b32001-11-03 14:54:25 +0000997 def LoadThemeCfg(self):
Steven M. Gava41a85322001-10-29 08:05:34 +0000998 ##current theme type radiobutton
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400999 self.themeIsBuiltin.set(idleConf.GetOption(
1000 'main', 'Theme', 'default', type='bool', default=1))
Steven M. Gava41a85322001-10-29 08:05:34 +00001001 ##currently set theme
Terry Jan Reedy4036d872014-08-03 23:02:58 -04001002 currentOption = idleConf.CurrentTheme()
Steven M. Gava7c017862001-10-29 11:19:46 +00001003 ##load available theme option menus
Steven M. Gavad0342cd2001-11-04 11:53:10 +00001004 if self.themeIsBuiltin.get(): #default theme selected
Terry Jan Reedy4036d872014-08-03 23:02:58 -04001005 itemList = idleConf.GetSectionList('default', 'highlight')
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +00001006 itemList.sort()
Terry Jan Reedy4036d872014-08-03 23:02:58 -04001007 self.optMenuThemeBuiltin.SetMenu(itemList, currentOption)
1008 itemList = idleConf.GetSectionList('user', 'highlight')
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +00001009 itemList.sort()
Steven M. Gava41a85322001-10-29 08:05:34 +00001010 if not itemList:
1011 self.radioThemeCustom.config(state=DISABLED)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001012 self.customTheme.set('- no custom themes -')
Steven M. Gava41a85322001-10-29 08:05:34 +00001013 else:
Terry Jan Reedy4036d872014-08-03 23:02:58 -04001014 self.optMenuThemeCustom.SetMenu(itemList, itemList[0])
Steven M. Gava9dd16b32001-11-03 14:54:25 +00001015 else: #user theme selected
Terry Jan Reedy4036d872014-08-03 23:02:58 -04001016 itemList = idleConf.GetSectionList('user', 'highlight')
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +00001017 itemList.sort()
Terry Jan Reedy4036d872014-08-03 23:02:58 -04001018 self.optMenuThemeCustom.SetMenu(itemList, currentOption)
1019 itemList = idleConf.GetSectionList('default', 'highlight')
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +00001020 itemList.sort()
Terry Jan Reedy4036d872014-08-03 23:02:58 -04001021 self.optMenuThemeBuiltin.SetMenu(itemList, itemList[0])
Steven M. Gava7c017862001-10-29 11:19:46 +00001022 self.SetThemeType()
1023 ##load theme element option menu
Kurt B. Kaisere0712772007-08-23 05:25:55 +00001024 themeNames = list(self.themeElements.keys())
Kurt B. Kaiser4718bf82008-02-12 21:34:12 +00001025 themeNames.sort(key=lambda x: self.themeElements[x][1])
Terry Jan Reedy4036d872014-08-03 23:02:58 -04001026 self.optMenuHighlightTarget.SetMenu(themeNames, themeNames[0])
Steven M. Gava9dd16b32001-11-03 14:54:25 +00001027 self.PaintThemeSample()
Steven M. Gava0cae01c2002-01-04 07:53:06 +00001028 self.SetHighlightTarget()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001029
Steven M. Gava9dd16b32001-11-03 14:54:25 +00001030 def LoadKeyCfg(self):
Steven M. Gava41a85322001-10-29 08:05:34 +00001031 ##current keys type radiobutton
Terry Jan Reedy4036d872014-08-03 23:02:58 -04001032 self.keysAreBuiltin.set(idleConf.GetOption(
1033 'main', 'Keys', 'default', type='bool', default=1))
Steven M. Gava41a85322001-10-29 08:05:34 +00001034 ##currently set keys
Terry Jan Reedy4036d872014-08-03 23:02:58 -04001035 currentOption = idleConf.CurrentKeys()
Steven M. Gava7c017862001-10-29 11:19:46 +00001036 ##load available keyset option menus
Steven M. Gava052937f2002-02-11 02:20:53 +00001037 if self.keysAreBuiltin.get(): #default theme selected
Terry Jan Reedy4036d872014-08-03 23:02:58 -04001038 itemList = idleConf.GetSectionList('default', 'keys')
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +00001039 itemList.sort()
Terry Jan Reedy4036d872014-08-03 23:02:58 -04001040 self.optMenuKeysBuiltin.SetMenu(itemList, currentOption)
1041 itemList = idleConf.GetSectionList('user', 'keys')
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +00001042 itemList.sort()
Steven M. Gava41a85322001-10-29 08:05:34 +00001043 if not itemList:
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001044 self.radioKeysCustom.config(state=DISABLED)
1045 self.customKeys.set('- no custom keys -')
Steven M. Gava41a85322001-10-29 08:05:34 +00001046 else:
Terry Jan Reedy4036d872014-08-03 23:02:58 -04001047 self.optMenuKeysCustom.SetMenu(itemList, itemList[0])
Steven M. Gavaa498af22002-02-01 01:33:36 +00001048 else: #user key set selected
Terry Jan Reedy4036d872014-08-03 23:02:58 -04001049 itemList = idleConf.GetSectionList('user', 'keys')
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +00001050 itemList.sort()
Terry Jan Reedy4036d872014-08-03 23:02:58 -04001051 self.optMenuKeysCustom.SetMenu(itemList, currentOption)
1052 itemList = idleConf.GetSectionList('default', 'keys')
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +00001053 itemList.sort()
Terry Jan Reedy4036d872014-08-03 23:02:58 -04001054 self.optMenuKeysBuiltin.SetMenu(itemList, itemList[0])
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001055 self.SetKeysType()
Steven M. Gavafacfc092002-01-19 00:29:54 +00001056 ##load keyset element list
Terry Jan Reedy4036d872014-08-03 23:02:58 -04001057 keySetName = idleConf.CurrentKeys()
Steven M. Gava052937f2002-02-11 02:20:53 +00001058 self.LoadKeysList(keySetName)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001059
Steven M. Gavafacfc092002-01-19 00:29:54 +00001060 def LoadGeneralCfg(self):
Steven M. Gava5f28e8f2002-01-21 06:38:21 +00001061 #startup state
Terry Jan Reedy4036d872014-08-03 23:02:58 -04001062 self.startupEdit.set(idleConf.GetOption(
1063 'main', 'General', 'editor-on-startup', default=1, type='bool'))
Kurt B. Kaiser6c638b62003-05-26 06:23:10 +00001064 #autosave state
Terry Jan Reedy4036d872014-08-03 23:02:58 -04001065 self.autoSave.set(idleConf.GetOption(
1066 'main', 'General', 'autosave', default=0, type='bool'))
Steven M. Gavafacfc092002-01-19 00:29:54 +00001067 #initial window size
Terry Jan Reedy4036d872014-08-03 23:02:58 -04001068 self.winWidth.set(idleConf.GetOption(
1069 'main', 'EditorWindow', 'width', type='int'))
1070 self.winHeight.set(idleConf.GetOption(
1071 'main', 'EditorWindow', 'height', type='int'))
Kurt B. Kaisera053f332003-05-10 00:49:56 +00001072 # default source encoding
Terry Jan Reedy4036d872014-08-03 23:02:58 -04001073 self.encoding.set(idleConf.GetOption(
1074 'main', 'EditorWindow', 'encoding', default='none'))
Kurt B. Kaiser8e92bf72003-01-14 22:03:31 +00001075 # additional help sources
1076 self.userHelpList = idleConf.GetAllExtraHelpSourcesList()
Steven M. Gava085eb1b2002-02-05 04:52:32 +00001077 for helpItem in self.userHelpList:
Terry Jan Reedy4036d872014-08-03 23:02:58 -04001078 self.listHelp.insert(END, helpItem[0])
Steven M. Gava085eb1b2002-02-05 04:52:32 +00001079 self.SetHelpListButtonStates()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001080
Steven M. Gava429a86af2001-10-23 10:42:12 +00001081 def LoadConfigs(self):
1082 """
1083 load configuration from default and user config files and populate
1084 the widgets on the config dialog pages.
1085 """
1086 ### fonts / tabs page
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001087 self.LoadFontCfg()
1088 self.LoadTabCfg()
Steven M. Gava429a86af2001-10-23 10:42:12 +00001089 ### highlighting page
Steven M. Gava9dd16b32001-11-03 14:54:25 +00001090 self.LoadThemeCfg()
Steven M. Gava429a86af2001-10-23 10:42:12 +00001091 ### keys page
Steven M. Gava9dd16b32001-11-03 14:54:25 +00001092 self.LoadKeyCfg()
Steven M. Gava429a86af2001-10-23 10:42:12 +00001093 ### general page
Steven M. Gavafacfc092002-01-19 00:29:54 +00001094 self.LoadGeneralCfg()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001095
Terry Jan Reedy4036d872014-08-03 23:02:58 -04001096 def SaveNewKeySet(self, keySetName, keySet):
Steven M. Gava052937f2002-02-11 02:20:53 +00001097 """
1098 save a newly created core key set.
1099 keySetName - string, the name of the new key set
1100 keySet - dictionary containing the new key set
1101 """
1102 if not idleConf.userCfg['keys'].has_section(keySetName):
1103 idleConf.userCfg['keys'].add_section(keySetName)
Kurt B. Kaisere0712772007-08-23 05:25:55 +00001104 for event in keySet:
Terry Jan Reedy4036d872014-08-03 23:02:58 -04001105 value = keySet[event]
1106 idleConf.userCfg['keys'].SetOption(keySetName, event, value)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001107
Terry Jan Reedy4036d872014-08-03 23:02:58 -04001108 def SaveNewTheme(self, themeName, theme):
Steven M. Gava052937f2002-02-11 02:20:53 +00001109 """
1110 save a newly created theme.
1111 themeName - string, the name of the new theme
1112 theme - dictionary containing the new theme
1113 """
1114 if not idleConf.userCfg['highlight'].has_section(themeName):
1115 idleConf.userCfg['highlight'].add_section(themeName)
Kurt B. Kaisere0712772007-08-23 05:25:55 +00001116 for element in theme:
Terry Jan Reedy4036d872014-08-03 23:02:58 -04001117 value = theme[element]
1118 idleConf.userCfg['highlight'].SetOption(themeName, element, value)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001119
Terry Jan Reedy4036d872014-08-03 23:02:58 -04001120 def SetUserValue(self, configType, section, item, value):
1121 if idleConf.defaultCfg[configType].has_option(section, item):
1122 if idleConf.defaultCfg[configType].Get(section, item) == value:
Steven M. Gava2d7bb3f2002-01-29 08:35:29 +00001123 #the setting equals a default setting, remove it from user cfg
Terry Jan Reedy4036d872014-08-03 23:02:58 -04001124 return idleConf.userCfg[configType].RemoveOption(section, item)
Steven M. Gava2d7bb3f2002-01-29 08:35:29 +00001125 #if we got here set the option
Terry Jan Reedy4036d872014-08-03 23:02:58 -04001126 return idleConf.userCfg[configType].SetOption(section, item, value)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001127
Steven M. Gava052937f2002-02-11 02:20:53 +00001128 def SaveAllChangedConfigs(self):
Kurt B. Kaisere7a161e2003-01-10 20:13:57 +00001129 "Save configuration changes to the user config file."
Steven M. Gava0c5bc8c2002-03-27 02:25:44 +00001130 idleConf.userCfg['main'].Save()
Kurt B. Kaisere0712772007-08-23 05:25:55 +00001131 for configType in self.changedItems:
Kurt B. Kaisere7a161e2003-01-10 20:13:57 +00001132 cfgTypeHasChanges = False
Kurt B. Kaisere0712772007-08-23 05:25:55 +00001133 for section in self.changedItems[configType]:
Kurt B. Kaisere7a161e2003-01-10 20:13:57 +00001134 if section == 'HelpFiles':
1135 #this section gets completely replaced
1136 idleConf.userCfg['main'].remove_section('HelpFiles')
Kurt B. Kaiser8e92bf72003-01-14 22:03:31 +00001137 cfgTypeHasChanges = True
Kurt B. Kaisere0712772007-08-23 05:25:55 +00001138 for item in self.changedItems[configType][section]:
Kurt B. Kaisere7a161e2003-01-10 20:13:57 +00001139 value = self.changedItems[configType][section][item]
Terry Jan Reedy4036d872014-08-03 23:02:58 -04001140 if self.SetUserValue(configType, section, item, value):
Kurt B. Kaisere7a161e2003-01-10 20:13:57 +00001141 cfgTypeHasChanges = True
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001142 if cfgTypeHasChanges:
1143 idleConf.userCfg[configType].Save()
Kurt B. Kaiser5acdf932004-11-16 21:28:36 +00001144 for configType in ['keys', 'highlight']:
1145 # save these even if unchanged!
1146 idleConf.userCfg[configType].Save()
Steven M. Gavaa498af22002-02-01 01:33:36 +00001147 self.ResetChangedItems() #clear the changed items dict
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001148
Kurt B. Kaiserb1754452005-11-18 22:05:48 +00001149 def DeactivateCurrentConfig(self):
1150 #Before a config is saved, some cleanup of current
1151 #config must be done - remove the previous keybindings
Kurt B. Kaisere0712772007-08-23 05:25:55 +00001152 winInstances = self.parent.instance_dict.keys()
Kurt B. Kaiserb1754452005-11-18 22:05:48 +00001153 for instance in winInstances:
1154 instance.RemoveKeybindings()
1155
Steven M. Gava49745752002-02-18 01:43:11 +00001156 def ActivateConfigChanges(self):
Kurt B. Kaiseracdef852005-01-31 03:34:26 +00001157 "Dynamically apply configuration changes"
Kurt B. Kaisere0712772007-08-23 05:25:55 +00001158 winInstances = self.parent.instance_dict.keys()
Steven M. Gavab77d3432002-03-02 07:16:21 +00001159 for instance in winInstances:
1160 instance.ResetColorizer()
Steven M. Gavab1585412002-03-12 00:21:56 +00001161 instance.ResetFont()
Kurt B. Kaiseracdef852005-01-31 03:34:26 +00001162 instance.set_notabs_indentwidth()
Kurt B. Kaiserb1754452005-11-18 22:05:48 +00001163 instance.ApplyKeybindings()
Kurt B. Kaiser8e92bf72003-01-14 22:03:31 +00001164 instance.reset_help_menu_entries()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001165
Steven M. Gava5f28e8f2002-01-21 06:38:21 +00001166 def Cancel(self):
1167 self.destroy()
1168
1169 def Ok(self):
1170 self.Apply()
1171 self.destroy()
1172
1173 def Apply(self):
Kurt B. Kaiserb1754452005-11-18 22:05:48 +00001174 self.DeactivateCurrentConfig()
Steven M. Gava052937f2002-02-11 02:20:53 +00001175 self.SaveAllChangedConfigs()
Steven M. Gava49745752002-02-18 01:43:11 +00001176 self.ActivateConfigChanges()
Steven M. Gava5f28e8f2002-01-21 06:38:21 +00001177
1178 def Help(self):
Terry Jan Reedyd0cadba2015-10-11 22:07:31 -04001179 page = self.tabPages._current_page
1180 view_text(self, title='Help for IDLE preferences',
1181 text=help_common+help_pages.get(page, ''))
1182
1183help_common = '''\
1184When you click either the Apply or Ok buttons, settings in this
1185dialog that are different from IDLE's default are saved in
1186a .idlerc directory in your home directory. Except as noted,
1187hese changes apply to all versions of IDLE installed on this
1188machine. Some do not take affect until IDLE is restarted.
1189[Cancel] only cancels changes made since the last save.
1190'''
1191help_pages = {
1192 'Highlighting':'''
1193Highlighting:
1194The IDLE Dark color theme is new in Octover 2015. It can only
1195be used with older IDLE releases if it is saved as a custom
1196theme, with a different name.
1197'''
1198}
1199
Steven M. Gavac11ccf32001-09-24 09:43:17 +00001200
Terry Jan Reedya9421fb2014-10-22 20:15:18 -04001201class VerticalScrolledFrame(Frame):
1202 """A pure Tkinter vertically scrollable frame.
1203
1204 * Use the 'interior' attribute to place widgets inside the scrollable frame
1205 * Construct and pack/place/grid normally
1206 * This frame only allows vertical scrolling
1207 """
1208 def __init__(self, parent, *args, **kw):
1209 Frame.__init__(self, parent, *args, **kw)
1210
1211 # create a canvas object and a vertical scrollbar for scrolling it
1212 vscrollbar = Scrollbar(self, orient=VERTICAL)
1213 vscrollbar.pack(fill=Y, side=RIGHT, expand=FALSE)
1214 canvas = Canvas(self, bd=0, highlightthickness=0,
1215 yscrollcommand=vscrollbar.set)
1216 canvas.pack(side=LEFT, fill=BOTH, expand=TRUE)
1217 vscrollbar.config(command=canvas.yview)
1218
1219 # reset the view
1220 canvas.xview_moveto(0)
1221 canvas.yview_moveto(0)
1222
1223 # create a frame inside the canvas which will be scrolled with it
1224 self.interior = interior = Frame(canvas)
1225 interior_id = canvas.create_window(0, 0, window=interior, anchor=NW)
1226
1227 # track changes to the canvas and frame width and sync them,
1228 # also updating the scrollbar
1229 def _configure_interior(event):
1230 # update the scrollbars to match the size of the inner frame
1231 size = (interior.winfo_reqwidth(), interior.winfo_reqheight())
1232 canvas.config(scrollregion="0 0 %s %s" % size)
Terry Jan Reedya9421fb2014-10-22 20:15:18 -04001233 interior.bind('<Configure>', _configure_interior)
1234
1235 def _configure_canvas(event):
1236 if interior.winfo_reqwidth() != canvas.winfo_width():
1237 # update the inner frame's width to fill the canvas
1238 canvas.itemconfigure(interior_id, width=canvas.winfo_width())
1239 canvas.bind('<Configure>', _configure_canvas)
1240
1241 return
1242
1243def is_int(s):
1244 "Return 's is blank or represents an int'"
1245 if not s:
1246 return True
1247 try:
1248 int(s)
1249 return True
1250 except ValueError:
1251 return False
1252
1253# TODO:
1254# * Revert to default(s)? Per option or per extension?
1255# * List options in their original order (possible??)
1256class ConfigExtensionsDialog(Toplevel):
1257 """A dialog for configuring IDLE extensions.
1258
1259 This dialog is generic - it works for any and all IDLE extensions.
1260
1261 IDLE extensions save their configuration options using idleConf.
1262 ConfigExtensionsDialog reads the current configuration using idleConf,
1263 supplies a GUI interface to change the configuration values, and saves the
1264 changes using idleConf.
1265
1266 Not all changes take effect immediately - some may require restarting IDLE.
1267 This depends on each extension's implementation.
1268
1269 All values are treated as text, and it is up to the user to supply
1270 reasonable values. The only exception to this are the 'enable*' options,
1271 which are boolean, and can be toggled with an True/False button.
1272 """
1273 def __init__(self, parent, title=None, _htest=False):
1274 Toplevel.__init__(self, parent)
1275 self.wm_withdraw()
1276
1277 self.configure(borderwidth=5)
1278 self.geometry(
1279 "+%d+%d" % (parent.winfo_rootx() + 20,
1280 parent.winfo_rooty() + (30 if not _htest else 150)))
1281 self.wm_title(title or 'IDLE Extensions Configuration')
1282
1283 self.defaultCfg = idleConf.defaultCfg['extensions']
1284 self.userCfg = idleConf.userCfg['extensions']
1285 self.is_int = self.register(is_int)
1286 self.load_extensions()
1287 self.create_widgets()
1288
1289 self.resizable(height=FALSE, width=FALSE) # don't allow resizing yet
1290 self.transient(parent)
1291 self.protocol("WM_DELETE_WINDOW", self.Cancel)
1292 self.tabbed_page_set.focus_set()
1293 # wait for window to be generated
1294 self.update()
1295 # set current width as the minimum width
1296 self.wm_minsize(self.winfo_width(), 1)
1297 # now allow resizing
1298 self.resizable(height=TRUE, width=TRUE)
1299
1300 self.wm_deiconify()
1301 if not _htest:
1302 self.grab_set()
1303 self.wait_window()
1304
1305 def load_extensions(self):
1306 "Fill self.extensions with data from the default and user configs."
1307 self.extensions = {}
1308 for ext_name in idleConf.GetExtensions(active_only=False):
1309 self.extensions[ext_name] = []
1310
1311 for ext_name in self.extensions:
1312 opt_list = sorted(self.defaultCfg.GetOptionList(ext_name))
1313
1314 # bring 'enable' options to the beginning of the list
1315 enables = [opt_name for opt_name in opt_list
1316 if opt_name.startswith('enable')]
1317 for opt_name in enables:
1318 opt_list.remove(opt_name)
1319 opt_list = enables + opt_list
1320
1321 for opt_name in opt_list:
1322 def_str = self.defaultCfg.Get(
1323 ext_name, opt_name, raw=True)
1324 try:
1325 def_obj = {'True':True, 'False':False}[def_str]
1326 opt_type = 'bool'
1327 except KeyError:
1328 try:
1329 def_obj = int(def_str)
1330 opt_type = 'int'
1331 except ValueError:
1332 def_obj = def_str
1333 opt_type = None
1334 try:
1335 value = self.userCfg.Get(
1336 ext_name, opt_name, type=opt_type, raw=True,
1337 default=def_obj)
1338 except ValueError: # Need this until .Get fixed
1339 value = def_obj # bad values overwritten by entry
1340 var = StringVar(self)
1341 var.set(str(value))
1342
1343 self.extensions[ext_name].append({'name': opt_name,
1344 'type': opt_type,
1345 'default': def_str,
1346 'value': value,
1347 'var': var,
1348 })
1349
1350 def create_widgets(self):
1351 """Create the dialog's widgets."""
Terry Jan Reedy41a27e02015-08-26 23:13:22 -04001352 self.extension_names = StringVar(self)
Terry Jan Reedya9421fb2014-10-22 20:15:18 -04001353 self.rowconfigure(0, weight=1)
Terry Jan Reedy41a27e02015-08-26 23:13:22 -04001354 self.columnconfigure(2, weight=1)
1355 self.extension_list = Listbox(self, listvariable=self.extension_names,
1356 selectmode='browse')
1357 self.extension_list.bind('<<ListboxSelect>>', self.extension_selected)
1358 scroll = Scrollbar(self, command=self.extension_list.yview)
1359 self.extension_list.yscrollcommand=scroll.set
1360 self.details_frame = LabelFrame(self, width=250, height=250)
1361 self.extension_list.grid(column=0, row=0, sticky='nws')
1362 scroll.grid(column=1, row=0, sticky='ns')
1363 self.details_frame.grid(column=2, row=0, sticky='nsew', padx=[10, 0])
1364 self.configure(padx=10, pady=10)
1365 self.config_frame = {}
1366 self.current_extension = None
Terry Jan Reedya9421fb2014-10-22 20:15:18 -04001367
Terry Jan Reedy41a27e02015-08-26 23:13:22 -04001368 self.outerframe = self # TEMPORARY
1369 self.tabbed_page_set = self.extension_list # TEMPORARY
Terry Jan Reedya9421fb2014-10-22 20:15:18 -04001370
Terry Jan Reedy41a27e02015-08-26 23:13:22 -04001371 # create the individual pages
1372 ext_names = ''
1373 for ext_name in sorted(self.extensions):
1374 self.create_extension_frame(ext_name)
1375 ext_names = ext_names + '{' + ext_name + '} '
1376 self.extension_names.set(ext_names)
1377 self.extension_list.selection_set(0)
1378 self.extension_selected(None)
1379 self.create_action_buttons().grid(row=1, columnspan=3)
1380
1381 def extension_selected(self, event):
1382 newsel = self.extension_list.curselection()
1383 if newsel:
1384 newsel = self.extension_list.get(newsel)
1385 if newsel is None or newsel != self.current_extension:
1386 if self.current_extension:
1387 self.details_frame.config(text='')
1388 self.config_frame[self.current_extension].grid_forget()
1389 self.current_extension = None
1390 if newsel:
1391 self.details_frame.config(text=newsel)
1392 self.config_frame[newsel].grid(column=0, row=0, sticky='nsew')
1393 self.current_extension = newsel
Terry Jan Reedya9421fb2014-10-22 20:15:18 -04001394
1395 create_action_buttons = ConfigDialog.create_action_buttons
1396
Terry Jan Reedy41a27e02015-08-26 23:13:22 -04001397 def create_extension_frame(self, ext_name):
1398 """Create a frame holding the widgets to configure one extension"""
1399 f = VerticalScrolledFrame(self.details_frame, height=250, width=250)
1400 self.config_frame[ext_name] = f
1401 entry_area = f.interior
Terry Jan Reedya9421fb2014-10-22 20:15:18 -04001402 # create an entry for each configuration option
1403 for row, opt in enumerate(self.extensions[ext_name]):
1404 # create a row with a label and entry/checkbutton
1405 label = Label(entry_area, text=opt['name'])
1406 label.grid(row=row, column=0, sticky=NW)
1407 var = opt['var']
1408 if opt['type'] == 'bool':
1409 Checkbutton(entry_area, textvariable=var, variable=var,
1410 onvalue='True', offvalue='False',
1411 indicatoron=FALSE, selectcolor='', width=8
Terry Jan Reedy41a27e02015-08-26 23:13:22 -04001412 ).grid(row=row, column=1, sticky=W, padx=7)
Terry Jan Reedya9421fb2014-10-22 20:15:18 -04001413 elif opt['type'] == 'int':
1414 Entry(entry_area, textvariable=var, validate='key',
Terry Jan Reedy41a27e02015-08-26 23:13:22 -04001415 validatecommand=(self.is_int, '%P')
1416 ).grid(row=row, column=1, sticky=NSEW, padx=7)
Terry Jan Reedya9421fb2014-10-22 20:15:18 -04001417
1418 else:
1419 Entry(entry_area, textvariable=var
Terry Jan Reedy41a27e02015-08-26 23:13:22 -04001420 ).grid(row=row, column=1, sticky=NSEW, padx=7)
Terry Jan Reedya9421fb2014-10-22 20:15:18 -04001421 return
1422
1423
1424 Ok = ConfigDialog.Ok
1425
1426 def Apply(self):
1427 self.save_all_changed_configs()
1428 pass
1429
1430 Cancel = ConfigDialog.Cancel
1431
1432 def Help(self):
1433 pass
1434
1435 def set_user_value(self, section, opt):
1436 name = opt['name']
1437 default = opt['default']
1438 value = opt['var'].get().strip() or default
1439 opt['var'].set(value)
1440 # if self.defaultCfg.has_section(section):
1441 # Currently, always true; if not, indent to return
1442 if (value == default):
1443 return self.userCfg.RemoveOption(section, name)
1444 # set the option
1445 return self.userCfg.SetOption(section, name, value)
1446
1447 def save_all_changed_configs(self):
1448 """Save configuration changes to the user config file."""
1449 has_changes = False
1450 for ext_name in self.extensions:
1451 options = self.extensions[ext_name]
1452 for opt in options:
1453 if self.set_user_value(ext_name, opt):
1454 has_changes = True
1455 if has_changes:
1456 self.userCfg.Save()
1457
1458
Steven M. Gava44d3d1a2001-07-31 06:59:02 +00001459if __name__ == '__main__':
Terry Jan Reedycfa89502014-07-14 23:07:32 -04001460 import unittest
1461 unittest.main('idlelib.idle_test.test_configdialog',
1462 verbosity=2, exit=False)
Terry Jan Reedy2e8234a2014-05-29 01:46:26 -04001463 from idlelib.idle_test.htest import run
Terry Jan Reedya9421fb2014-10-22 20:15:18 -04001464 run(ConfigDialog, ConfigExtensionsDialog)