blob: 3aa66721005ec0bc18f91b6fcd09371e80a7310b [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 Reedy93f35422015-10-13 22:03:51 -040083 page_names=['Fonts/Tabs', 'Highlighting', 'Keys', 'General',
84 'Extensions'])
Terry Jan Reedy92cb0a32014-10-08 20:29:13 -040085 self.tabPages.pack(side=TOP, expand=TRUE, fill=BOTH)
86 self.CreatePageFontTab()
87 self.CreatePageHighlight()
88 self.CreatePageKeys()
89 self.CreatePageGeneral()
Terry Jan Reedy93f35422015-10-13 22:03:51 -040090 self.CreatePageExtensions()
Terry Jan Reedy92cb0a32014-10-08 20:29:13 -040091 self.create_action_buttons().pack(side=BOTTOM)
Terry Jan Reedyd0cadba2015-10-11 22:07:31 -040092
Terry Jan Reedy92cb0a32014-10-08 20:29:13 -040093 def create_action_buttons(self):
Ned Deilyb7601672014-03-27 20:49:14 -070094 if macosxSupport.isAquaTk():
Terry Jan Reedye3416e62014-07-26 19:40:16 -040095 # Changing the default padding on OSX results in unreadable
96 # text in the buttons
Terry Jan Reedy4036d872014-08-03 23:02:58 -040097 paddingArgs = {}
Ronald Oussoren9e350042009-02-12 16:02:11 +000098 else:
Terry Jan Reedy4036d872014-08-03 23:02:58 -040099 paddingArgs = {'padx':6, 'pady':3}
Terry Jan Reedya9421fb2014-10-22 20:15:18 -0400100 outer = Frame(self, pady=2)
101 buttons = Frame(outer, pady=2)
Terry Jan Reedyd0cadba2015-10-11 22:07:31 -0400102 for txt, cmd in (
103 ('Ok', self.Ok),
104 ('Apply', self.Apply),
105 ('Cancel', self.Cancel),
106 ('Help', self.Help)):
107 Button(buttons, text=txt, command=cmd, takefocus=FALSE,
108 **paddingArgs).pack(side=LEFT, padx=5)
Terry Jan Reedya9421fb2014-10-22 20:15:18 -0400109 # add space above buttons
110 Frame(outer, height=2, borderwidth=0).pack(side=TOP)
111 buttons.pack(side=BOTTOM)
112 return outer
Terry Jan Reedyd0cadba2015-10-11 22:07:31 -0400113
Steven M. Gava60fc7072001-08-04 13:58:22 +0000114 def CreatePageFontTab(self):
Terry Jan Reedy22405332014-07-30 19:24:32 -0400115 parent = self.parent
116 self.fontSize = StringVar(parent)
117 self.fontBold = BooleanVar(parent)
118 self.fontName = StringVar(parent)
119 self.spaceNum = IntVar(parent)
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400120 self.editFont = tkFont.Font(parent, ('courier', 10, 'normal'))
Terry Jan Reedy22405332014-07-30 19:24:32 -0400121
Steven M. Gavaf213ccb2001-08-05 08:00:28 +0000122 ##widget creation
123 #body frame
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400124 frame = self.tabPages.pages['Fonts/Tabs'].frame
Steven M. Gavaf213ccb2001-08-05 08:00:28 +0000125 #body section frames
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400126 frameFont = LabelFrame(
127 frame, borderwidth=2, relief=GROOVE, text=' Base Editor Font ')
128 frameIndent = LabelFrame(
129 frame, borderwidth=2, relief=GROOVE, text=' Indentation Width ')
Steven M. Gavaf213ccb2001-08-05 08:00:28 +0000130 #frameFont
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400131 frameFontName = Frame(frameFont)
132 frameFontParam = Frame(frameFont)
133 labelFontNameTitle = Label(
134 frameFontName, justify=LEFT, text='Font Face :')
135 self.listFontName = Listbox(
136 frameFontName, height=5, takefocus=FALSE, exportselection=FALSE)
137 self.listFontName.bind(
138 '<ButtonRelease-1>', self.OnListFontButtonRelease)
139 scrollFont = Scrollbar(frameFontName)
Steven M. Gavac01e30f2001-08-11 15:48:13 +0000140 scrollFont.config(command=self.listFontName.yview)
141 self.listFontName.config(yscrollcommand=scrollFont.set)
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400142 labelFontSizeTitle = Label(frameFontParam, text='Size :')
143 self.optMenuFontSize = DynOptionMenu(
144 frameFontParam, self.fontSize, None, command=self.SetFontSample)
145 checkFontBold = Checkbutton(
146 frameFontParam, variable=self.fontBold, onvalue=1,
147 offvalue=0, text='Bold', command=self.SetFontSample)
148 frameFontSample = Frame(frameFont, relief=SOLID, borderwidth=1)
149 self.labelFontSample = Label(
150 frameFontSample, justify=LEFT, font=self.editFont,
151 text='AaBbCcDdEe\nFfGgHhIiJjK\n1234567890\n#:+=(){}[]')
Steven M. Gavaf213ccb2001-08-05 08:00:28 +0000152 #frameIndent
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400153 frameIndentSize = Frame(frameIndent)
154 labelSpaceNumTitle = Label(
155 frameIndentSize, justify=LEFT,
156 text='Python Standard: 4 Spaces!')
157 self.scaleSpaceNum = Scale(
158 frameIndentSize, variable=self.spaceNum,
159 orient='horizontal', tickinterval=2, from_=2, to=16)
Terry Jan Reedy22405332014-07-30 19:24:32 -0400160
Steven M. Gavaf213ccb2001-08-05 08:00:28 +0000161 #widget packing
162 #body
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400163 frameFont.pack(side=LEFT, padx=5, pady=5, expand=TRUE, fill=BOTH)
164 frameIndent.pack(side=LEFT, padx=5, pady=5, fill=Y)
Steven M. Gavaf213ccb2001-08-05 08:00:28 +0000165 #frameFont
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400166 frameFontName.pack(side=TOP, padx=5, pady=5, fill=X)
167 frameFontParam.pack(side=TOP, padx=5, pady=5, fill=X)
168 labelFontNameTitle.pack(side=TOP, anchor=W)
169 self.listFontName.pack(side=LEFT, expand=TRUE, fill=X)
170 scrollFont.pack(side=LEFT, fill=Y)
171 labelFontSizeTitle.pack(side=LEFT, anchor=W)
172 self.optMenuFontSize.pack(side=LEFT, anchor=W)
173 checkFontBold.pack(side=LEFT, anchor=W, padx=20)
174 frameFontSample.pack(side=TOP, padx=5, pady=5, expand=TRUE, fill=BOTH)
175 self.labelFontSample.pack(expand=TRUE, fill=BOTH)
Steven M. Gavaf213ccb2001-08-05 08:00:28 +0000176 #frameIndent
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400177 frameIndentSize.pack(side=TOP, fill=X)
178 labelSpaceNumTitle.pack(side=TOP, anchor=W, padx=5)
179 self.scaleSpaceNum.pack(side=TOP, padx=5, fill=X)
Steven M. Gava952d0a52001-08-03 04:43:44 +0000180 return frame
181
182 def CreatePageHighlight(self):
Terry Jan Reedy22405332014-07-30 19:24:32 -0400183 parent = self.parent
184 self.builtinTheme = StringVar(parent)
185 self.customTheme = StringVar(parent)
186 self.fgHilite = BooleanVar(parent)
187 self.colour = StringVar(parent)
188 self.fontName = StringVar(parent)
189 self.themeIsBuiltin = BooleanVar(parent)
190 self.highlightTarget = StringVar(parent)
191
Steven M. Gava952d0a52001-08-03 04:43:44 +0000192 ##widget creation
193 #body frame
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400194 frame = self.tabPages.pages['Highlighting'].frame
Steven M. Gava952d0a52001-08-03 04:43:44 +0000195 #body section frames
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400196 frameCustom = LabelFrame(frame, borderwidth=2, relief=GROOVE,
197 text=' Custom Highlighting ')
198 frameTheme = LabelFrame(frame, borderwidth=2, relief=GROOVE,
199 text=' Highlighting Theme ')
Steven M. Gava952d0a52001-08-03 04:43:44 +0000200 #frameCustom
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400201 self.textHighlightSample=Text(
202 frameCustom, relief=SOLID, borderwidth=1,
203 font=('courier', 12, ''), cursor='hand2', width=21, height=11,
204 takefocus=FALSE, highlightthickness=0, wrap=NONE)
Steven M. Gavae16d94b2001-11-03 05:07:28 +0000205 text=self.textHighlightSample
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400206 text.bind('<Double-Button-1>', lambda e: 'break')
207 text.bind('<B1-Motion>', lambda e: 'break')
208 textAndTags=(
209 ('#you can click here', 'comment'), ('\n', 'normal'),
210 ('#to choose items', 'comment'), ('\n', 'normal'),
211 ('def', 'keyword'), (' ', 'normal'),
212 ('func', 'definition'), ('(param):\n ', 'normal'),
213 ('"""string"""', 'string'), ('\n var0 = ', 'normal'),
214 ("'string'", 'string'), ('\n var1 = ', 'normal'),
215 ("'selected'", 'hilite'), ('\n var2 = ', 'normal'),
216 ("'found'", 'hit'), ('\n var3 = ', 'normal'),
217 ('list', 'builtin'), ('(', 'normal'),
Terry Jan Reedya8aa4d52015-10-02 22:12:17 -0400218 ('None', 'keyword'), (')\n', 'normal'),
219 (' breakpoint("line")', 'break'), ('\n\n', 'normal'),
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400220 (' error ', 'error'), (' ', 'normal'),
221 ('cursor |', 'cursor'), ('\n ', 'normal'),
222 ('shell', 'console'), (' ', 'normal'),
223 ('stdout', 'stdout'), (' ', 'normal'),
224 ('stderr', 'stderr'), ('\n', 'normal'))
Steven M. Gava9dd16b32001-11-03 14:54:25 +0000225 for txTa in textAndTags:
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400226 text.insert(END, txTa[0], txTa[1])
Kurt B. Kaisere0712772007-08-23 05:25:55 +0000227 for element in self.themeElements:
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400228 def tem(event, elem=element):
229 event.widget.winfo_toplevel().highlightTarget.set(elem)
230 text.tag_bind(
231 self.themeElements[element][0], '<ButtonPress-1>', tem)
Steven M. Gavae16d94b2001-11-03 05:07:28 +0000232 text.config(state=DISABLED)
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400233 self.frameColourSet = Frame(frameCustom, relief=SOLID, borderwidth=1)
234 frameFgBg = Frame(frameCustom)
235 buttonSetColour = Button(
236 self.frameColourSet, text='Choose Colour for :',
237 command=self.GetColour, highlightthickness=0)
238 self.optMenuHighlightTarget = DynOptionMenu(
239 self.frameColourSet, self.highlightTarget, None,
240 highlightthickness=0) #, command=self.SetHighlightTargetBinding
241 self.radioFg = Radiobutton(
242 frameFgBg, variable=self.fgHilite, value=1,
243 text='Foreground', command=self.SetColourSampleBinding)
244 self.radioBg=Radiobutton(
245 frameFgBg, variable=self.fgHilite, value=0,
246 text='Background', command=self.SetColourSampleBinding)
Steven M. Gava7c017862001-10-29 11:19:46 +0000247 self.fgHilite.set(1)
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400248 buttonSaveCustomTheme = Button(
249 frameCustom, text='Save as New Custom Theme',
250 command=self.SaveAsNewTheme)
Steven M. Gava952d0a52001-08-03 04:43:44 +0000251 #frameTheme
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400252 labelTypeTitle = Label(frameTheme, text='Select : ')
253 self.radioThemeBuiltin = Radiobutton(
254 frameTheme, variable=self.themeIsBuiltin, value=1,
255 command=self.SetThemeType, text='a Built-in Theme')
256 self.radioThemeCustom = Radiobutton(
257 frameTheme, variable=self.themeIsBuiltin, value=0,
258 command=self.SetThemeType, text='a Custom Theme')
259 self.optMenuThemeBuiltin = DynOptionMenu(
260 frameTheme, self.builtinTheme, None, command=None)
261 self.optMenuThemeCustom=DynOptionMenu(
262 frameTheme, self.customTheme, None, command=None)
263 self.buttonDeleteCustomTheme=Button(
264 frameTheme, text='Delete Custom Theme',
Steven M. Gava49745752002-02-18 01:43:11 +0000265 command=self.DeleteCustomTheme)
Terry Jan Reedy22405332014-07-30 19:24:32 -0400266
Steven M. Gava952d0a52001-08-03 04:43:44 +0000267 ##widget packing
268 #body
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400269 frameCustom.pack(side=LEFT, padx=5, pady=5, expand=TRUE, fill=BOTH)
270 frameTheme.pack(side=LEFT, padx=5, pady=5, fill=Y)
Steven M. Gava952d0a52001-08-03 04:43:44 +0000271 #frameCustom
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400272 self.frameColourSet.pack(side=TOP, padx=5, pady=5, expand=TRUE, fill=X)
273 frameFgBg.pack(side=TOP, padx=5, pady=0)
274 self.textHighlightSample.pack(
275 side=TOP, padx=5, pady=5, expand=TRUE, fill=BOTH)
276 buttonSetColour.pack(side=TOP, expand=TRUE, fill=X, padx=8, pady=4)
277 self.optMenuHighlightTarget.pack(
278 side=TOP, expand=TRUE, fill=X, padx=8, pady=3)
279 self.radioFg.pack(side=LEFT, anchor=E)
280 self.radioBg.pack(side=RIGHT, anchor=W)
281 buttonSaveCustomTheme.pack(side=BOTTOM, fill=X, padx=5, pady=5)
Steven M. Gava952d0a52001-08-03 04:43:44 +0000282 #frameTheme
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400283 labelTypeTitle.pack(side=TOP, anchor=W, padx=5, pady=5)
284 self.radioThemeBuiltin.pack(side=TOP, anchor=W, padx=5)
285 self.radioThemeCustom.pack(side=TOP, anchor=W, padx=5, pady=2)
286 self.optMenuThemeBuiltin.pack(side=TOP, fill=X, padx=5, pady=5)
287 self.optMenuThemeCustom.pack(side=TOP, fill=X, anchor=W, padx=5, pady=5)
288 self.buttonDeleteCustomTheme.pack(side=TOP, fill=X, padx=5, pady=5)
Steven M. Gava952d0a52001-08-03 04:43:44 +0000289 return frame
290
291 def CreatePageKeys(self):
Terry Jan Reedy22405332014-07-30 19:24:32 -0400292 parent = self.parent
293 self.bindingTarget = StringVar(parent)
294 self.builtinKeys = StringVar(parent)
295 self.customKeys = StringVar(parent)
296 self.keysAreBuiltin = BooleanVar(parent)
297 self.keyBinding = StringVar(parent)
298
Steven M. Gava60fc7072001-08-04 13:58:22 +0000299 ##widget creation
300 #body frame
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400301 frame = self.tabPages.pages['Keys'].frame
Steven M. Gava60fc7072001-08-04 13:58:22 +0000302 #body section frames
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400303 frameCustom = LabelFrame(
304 frame, borderwidth=2, relief=GROOVE,
305 text=' Custom Key Bindings ')
306 frameKeySets = LabelFrame(
307 frame, borderwidth=2, relief=GROOVE, text=' Key Set ')
Steven M. Gava60fc7072001-08-04 13:58:22 +0000308 #frameCustom
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400309 frameTarget = Frame(frameCustom)
310 labelTargetTitle = Label(frameTarget, text='Action - Key(s)')
311 scrollTargetY = Scrollbar(frameTarget)
312 scrollTargetX = Scrollbar(frameTarget, orient=HORIZONTAL)
313 self.listBindings = Listbox(
314 frameTarget, takefocus=FALSE, exportselection=FALSE)
315 self.listBindings.bind('<ButtonRelease-1>', self.KeyBindingSelected)
Steven M. Gavafacfc092002-01-19 00:29:54 +0000316 scrollTargetY.config(command=self.listBindings.yview)
317 scrollTargetX.config(command=self.listBindings.xview)
318 self.listBindings.config(yscrollcommand=scrollTargetY.set)
319 self.listBindings.config(xscrollcommand=scrollTargetX.set)
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400320 self.buttonNewKeys = Button(
321 frameCustom, text='Get New Keys for Selection',
322 command=self.GetNewKeys, state=DISABLED)
Steven M. Gava60fc7072001-08-04 13:58:22 +0000323 #frameKeySets
Christian Heimes9a371592007-12-28 14:08:13 +0000324 frames = [Frame(frameKeySets, padx=2, pady=2, borderwidth=0)
325 for i in range(2)]
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400326 self.radioKeysBuiltin = Radiobutton(
327 frames[0], variable=self.keysAreBuiltin, value=1,
328 command=self.SetKeysType, text='Use a Built-in Key Set')
329 self.radioKeysCustom = Radiobutton(
330 frames[0], variable=self.keysAreBuiltin, value=0,
331 command=self.SetKeysType, text='Use a Custom Key Set')
332 self.optMenuKeysBuiltin = DynOptionMenu(
333 frames[0], self.builtinKeys, None, command=None)
334 self.optMenuKeysCustom = DynOptionMenu(
335 frames[0], self.customKeys, None, command=None)
336 self.buttonDeleteCustomKeys = Button(
337 frames[1], text='Delete Custom Key Set',
Steven M. Gava49745752002-02-18 01:43:11 +0000338 command=self.DeleteCustomKeys)
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400339 buttonSaveCustomKeys = Button(
340 frames[1], text='Save as New Custom Key Set',
341 command=self.SaveAsNewKeySet)
Terry Jan Reedy22405332014-07-30 19:24:32 -0400342
Steven M. Gava60fc7072001-08-04 13:58:22 +0000343 ##widget packing
344 #body
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400345 frameCustom.pack(side=BOTTOM, padx=5, pady=5, expand=TRUE, fill=BOTH)
346 frameKeySets.pack(side=BOTTOM, padx=5, pady=5, fill=BOTH)
Steven M. Gava60fc7072001-08-04 13:58:22 +0000347 #frameCustom
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400348 self.buttonNewKeys.pack(side=BOTTOM, fill=X, padx=5, pady=5)
349 frameTarget.pack(side=LEFT, padx=5, pady=5, expand=TRUE, fill=BOTH)
Steven M. Gavafacfc092002-01-19 00:29:54 +0000350 #frame target
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400351 frameTarget.columnconfigure(0, weight=1)
352 frameTarget.rowconfigure(1, weight=1)
353 labelTargetTitle.grid(row=0, column=0, columnspan=2, sticky=W)
354 self.listBindings.grid(row=1, column=0, sticky=NSEW)
355 scrollTargetY.grid(row=1, column=1, sticky=NS)
356 scrollTargetX.grid(row=2, column=0, sticky=EW)
Steven M. Gava60fc7072001-08-04 13:58:22 +0000357 #frameKeySets
Christian Heimes9a371592007-12-28 14:08:13 +0000358 self.radioKeysBuiltin.grid(row=0, column=0, sticky=W+NS)
359 self.radioKeysCustom.grid(row=1, column=0, sticky=W+NS)
360 self.optMenuKeysBuiltin.grid(row=0, column=1, sticky=NSEW)
361 self.optMenuKeysCustom.grid(row=1, column=1, sticky=NSEW)
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400362 self.buttonDeleteCustomKeys.pack(side=LEFT, fill=X, expand=True, padx=2)
363 buttonSaveCustomKeys.pack(side=LEFT, fill=X, expand=True, padx=2)
Christian Heimes9a371592007-12-28 14:08:13 +0000364 frames[0].pack(side=TOP, fill=BOTH, expand=True)
365 frames[1].pack(side=TOP, fill=X, expand=True, pady=2)
Steven M. Gava952d0a52001-08-03 04:43:44 +0000366 return frame
367
368 def CreatePageGeneral(self):
Terry Jan Reedy22405332014-07-30 19:24:32 -0400369 parent = self.parent
370 self.winWidth = StringVar(parent)
371 self.winHeight = StringVar(parent)
Terry Jan Reedy22405332014-07-30 19:24:32 -0400372 self.startupEdit = IntVar(parent)
373 self.autoSave = IntVar(parent)
374 self.encoding = StringVar(parent)
375 self.userHelpBrowser = BooleanVar(parent)
376 self.helpBrowser = StringVar(parent)
377
Steven M. Gava230e5782001-08-07 03:28:25 +0000378 #widget creation
379 #body
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400380 frame = self.tabPages.pages['General'].frame
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000381 #body section frames
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400382 frameRun = LabelFrame(frame, borderwidth=2, relief=GROOVE,
383 text=' Startup Preferences ')
384 frameSave = LabelFrame(frame, borderwidth=2, relief=GROOVE,
385 text=' Autosave Preferences ')
386 frameWinSize = Frame(frame, borderwidth=2, relief=GROOVE)
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400387 frameHelp = LabelFrame(frame, borderwidth=2, relief=GROOVE,
388 text=' Additional Help Sources ')
Steven M. Gava230e5782001-08-07 03:28:25 +0000389 #frameRun
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400390 labelRunChoiceTitle = Label(frameRun, text='At Startup')
391 radioStartupEdit = Radiobutton(
392 frameRun, variable=self.startupEdit, value=1,
393 command=self.SetKeysType, text="Open Edit Window")
394 radioStartupShell = Radiobutton(
395 frameRun, variable=self.startupEdit, value=0,
396 command=self.SetKeysType, text='Open Shell Window')
Kurt B. Kaiser6c638b62003-05-26 06:23:10 +0000397 #frameSave
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400398 labelRunSaveTitle = Label(frameSave, text='At Start of Run (F5) ')
399 radioSaveAsk = Radiobutton(
400 frameSave, variable=self.autoSave, value=0,
401 command=self.SetKeysType, text="Prompt to Save")
402 radioSaveAuto = Radiobutton(
403 frameSave, variable=self.autoSave, value=1,
404 command=self.SetKeysType, text='No Prompt')
Steven M. Gava230e5782001-08-07 03:28:25 +0000405 #frameWinSize
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400406 labelWinSizeTitle = Label(
407 frameWinSize, text='Initial Window Size (in characters)')
408 labelWinWidthTitle = Label(frameWinSize, text='Width')
409 entryWinWidth = Entry(
410 frameWinSize, textvariable=self.winWidth, width=3)
411 labelWinHeightTitle = Label(frameWinSize, text='Height')
412 entryWinHeight = Entry(
413 frameWinSize, textvariable=self.winHeight, width=3)
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000414 #frameHelp
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400415 frameHelpList = Frame(frameHelp)
416 frameHelpListButtons = Frame(frameHelpList)
417 scrollHelpList = Scrollbar(frameHelpList)
418 self.listHelp = Listbox(
419 frameHelpList, height=5, takefocus=FALSE,
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000420 exportselection=FALSE)
421 scrollHelpList.config(command=self.listHelp.yview)
422 self.listHelp.config(yscrollcommand=scrollHelpList.set)
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400423 self.listHelp.bind('<ButtonRelease-1>', self.HelpSourceSelected)
424 self.buttonHelpListEdit = Button(
425 frameHelpListButtons, text='Edit', state=DISABLED,
426 width=8, command=self.HelpListItemEdit)
427 self.buttonHelpListAdd = Button(
428 frameHelpListButtons, text='Add',
429 width=8, command=self.HelpListItemAdd)
430 self.buttonHelpListRemove = Button(
431 frameHelpListButtons, text='Remove', state=DISABLED,
432 width=8, command=self.HelpListItemRemove)
Terry Jan Reedy22405332014-07-30 19:24:32 -0400433
Steven M. Gava230e5782001-08-07 03:28:25 +0000434 #widget packing
435 #body
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400436 frameRun.pack(side=TOP, padx=5, pady=5, fill=X)
437 frameSave.pack(side=TOP, padx=5, pady=5, fill=X)
438 frameWinSize.pack(side=TOP, padx=5, pady=5, fill=X)
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400439 frameHelp.pack(side=TOP, padx=5, pady=5, expand=TRUE, fill=BOTH)
Steven M. Gava230e5782001-08-07 03:28:25 +0000440 #frameRun
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400441 labelRunChoiceTitle.pack(side=LEFT, anchor=W, padx=5, pady=5)
442 radioStartupShell.pack(side=RIGHT, anchor=W, padx=5, pady=5)
443 radioStartupEdit.pack(side=RIGHT, anchor=W, padx=5, pady=5)
Kurt B. Kaiser6c638b62003-05-26 06:23:10 +0000444 #frameSave
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400445 labelRunSaveTitle.pack(side=LEFT, anchor=W, padx=5, pady=5)
446 radioSaveAuto.pack(side=RIGHT, anchor=W, padx=5, pady=5)
447 radioSaveAsk.pack(side=RIGHT, anchor=W, padx=5, pady=5)
Steven M. Gava230e5782001-08-07 03:28:25 +0000448 #frameWinSize
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400449 labelWinSizeTitle.pack(side=LEFT, anchor=W, padx=5, pady=5)
450 entryWinHeight.pack(side=RIGHT, anchor=E, padx=10, pady=5)
451 labelWinHeightTitle.pack(side=RIGHT, anchor=E, pady=5)
452 entryWinWidth.pack(side=RIGHT, anchor=E, padx=10, pady=5)
453 labelWinWidthTitle.pack(side=RIGHT, anchor=E, pady=5)
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000454 #frameHelp
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400455 frameHelpListButtons.pack(side=RIGHT, padx=5, pady=5, fill=Y)
456 frameHelpList.pack(side=TOP, padx=5, pady=5, expand=TRUE, fill=BOTH)
457 scrollHelpList.pack(side=RIGHT, anchor=W, fill=Y)
458 self.listHelp.pack(side=LEFT, anchor=E, expand=TRUE, fill=BOTH)
459 self.buttonHelpListEdit.pack(side=TOP, anchor=W, pady=5)
460 self.buttonHelpListAdd.pack(side=TOP, anchor=W)
461 self.buttonHelpListRemove.pack(side=TOP, anchor=W, pady=5)
Steven M. Gava952d0a52001-08-03 04:43:44 +0000462 return frame
463
Steven M. Gavac112cd82002-01-22 05:56:40 +0000464 def AttachVarCallbacks(self):
Terry Jan Reedyd87d1682015-08-01 18:57:33 -0400465 self.fontSize.trace_variable('w', self.VarChanged_font)
466 self.fontName.trace_variable('w', self.VarChanged_font)
467 self.fontBold.trace_variable('w', self.VarChanged_font)
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400468 self.spaceNum.trace_variable('w', self.VarChanged_spaceNum)
469 self.colour.trace_variable('w', self.VarChanged_colour)
470 self.builtinTheme.trace_variable('w', self.VarChanged_builtinTheme)
471 self.customTheme.trace_variable('w', self.VarChanged_customTheme)
472 self.themeIsBuiltin.trace_variable('w', self.VarChanged_themeIsBuiltin)
473 self.highlightTarget.trace_variable('w', self.VarChanged_highlightTarget)
474 self.keyBinding.trace_variable('w', self.VarChanged_keyBinding)
475 self.builtinKeys.trace_variable('w', self.VarChanged_builtinKeys)
476 self.customKeys.trace_variable('w', self.VarChanged_customKeys)
477 self.keysAreBuiltin.trace_variable('w', self.VarChanged_keysAreBuiltin)
478 self.winWidth.trace_variable('w', self.VarChanged_winWidth)
479 self.winHeight.trace_variable('w', self.VarChanged_winHeight)
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400480 self.startupEdit.trace_variable('w', self.VarChanged_startupEdit)
481 self.autoSave.trace_variable('w', self.VarChanged_autoSave)
482 self.encoding.trace_variable('w', self.VarChanged_encoding)
Steven M. Gava052937f2002-02-11 02:20:53 +0000483
Terry Jan Reedyd87d1682015-08-01 18:57:33 -0400484 def VarChanged_font(self, *params):
485 '''When one font attribute changes, save them all, as they are
486 not independent from each other. In particular, when we are
487 overriding the default font, we need to write out everything.
488 '''
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400489 value = self.fontName.get()
490 self.AddChangedItem('main', 'EditorWindow', 'font', value)
Terry Jan Reedyd87d1682015-08-01 18:57:33 -0400491 value = self.fontSize.get()
492 self.AddChangedItem('main', 'EditorWindow', 'font-size', value)
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400493 value = self.fontBold.get()
494 self.AddChangedItem('main', 'EditorWindow', 'font-bold', value)
Steven M. Gavac112cd82002-01-22 05:56:40 +0000495
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400496 def VarChanged_spaceNum(self, *params):
497 value = self.spaceNum.get()
498 self.AddChangedItem('main', 'Indent', 'num-spaces', value)
Steven M. Gavac112cd82002-01-22 05:56:40 +0000499
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400500 def VarChanged_colour(self, *params):
Steven M. Gava052937f2002-02-11 02:20:53 +0000501 self.OnNewColourSet()
502
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400503 def VarChanged_builtinTheme(self, *params):
504 value = self.builtinTheme.get()
Terry Jan Reedybe5b7a22015-10-04 00:31:05 -0400505 if value == 'IDLE Dark':
506 tkMessageBox.showwarning(
507 title="The 'IDLE Dark' Text Color Theme",
508 message="IDLE Dark is new in October, 2015. Trying to "
509 "run earlier versions of IDLE with it selected "
510 "will disable colorizing, or worse.\n\n"
511 "If you might ever run an earlier release of IDLE, "
512 "then before exiting this version, "
513 "either switch to another theme or "
514 "hit the 'Save as New Custom Theme' button. "
515 "The latter requires a new name, such as "
516 "'Custom Dark', but the custom theme will work "
517 "with any IDLE release, and can be modified.",
518 parent=self)
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400519 self.AddChangedItem('main', 'Theme', 'name', value)
Steven M. Gava052937f2002-02-11 02:20:53 +0000520 self.PaintThemeSample()
521
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400522 def VarChanged_customTheme(self, *params):
523 value = self.customTheme.get()
Steven M. Gava49745752002-02-18 01:43:11 +0000524 if value != '- no custom themes -':
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400525 self.AddChangedItem('main', 'Theme', 'name', value)
Steven M. Gava49745752002-02-18 01:43:11 +0000526 self.PaintThemeSample()
Steven M. Gava052937f2002-02-11 02:20:53 +0000527
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400528 def VarChanged_themeIsBuiltin(self, *params):
529 value = self.themeIsBuiltin.get()
530 self.AddChangedItem('main', 'Theme', 'default', value)
Steven M. Gavaf31eec02002-03-05 00:25:58 +0000531 if value:
532 self.VarChanged_builtinTheme()
533 else:
534 self.VarChanged_customTheme()
Steven M. Gava052937f2002-02-11 02:20:53 +0000535
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400536 def VarChanged_highlightTarget(self, *params):
Steven M. Gava052937f2002-02-11 02:20:53 +0000537 self.SetHighlightTarget()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000538
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400539 def VarChanged_keyBinding(self, *params):
540 value = self.keyBinding.get()
541 keySet = self.customKeys.get()
542 event = self.listBindings.get(ANCHOR).split()[0]
Steven M. Gavaa498af22002-02-01 01:33:36 +0000543 if idleConf.IsCoreBinding(event):
544 #this is a core keybinding
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400545 self.AddChangedItem('keys', keySet, event, value)
Steven M. Gavaa498af22002-02-01 01:33:36 +0000546 else: #this is an extension key binding
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400547 extName = idleConf.GetExtnNameForEvent(event)
548 extKeybindSection = extName + '_cfgBindings'
549 self.AddChangedItem('extensions', extKeybindSection, event, value)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000550
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400551 def VarChanged_builtinKeys(self, *params):
552 value = self.builtinKeys.get()
553 self.AddChangedItem('main', 'Keys', 'name', value)
Steven M. Gava052937f2002-02-11 02:20:53 +0000554 self.LoadKeysList(value)
555
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400556 def VarChanged_customKeys(self, *params):
557 value = self.customKeys.get()
Steven M. Gava49745752002-02-18 01:43:11 +0000558 if value != '- no custom keys -':
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400559 self.AddChangedItem('main', 'Keys', 'name', value)
Steven M. Gava49745752002-02-18 01:43:11 +0000560 self.LoadKeysList(value)
Steven M. Gava052937f2002-02-11 02:20:53 +0000561
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400562 def VarChanged_keysAreBuiltin(self, *params):
563 value = self.keysAreBuiltin.get()
564 self.AddChangedItem('main', 'Keys', 'default', value)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000565 if value:
Steven M. Gavaf31eec02002-03-05 00:25:58 +0000566 self.VarChanged_builtinKeys()
Steven M. Gava052937f2002-02-11 02:20:53 +0000567 else:
Steven M. Gavaf31eec02002-03-05 00:25:58 +0000568 self.VarChanged_customKeys()
Steven M. Gava052937f2002-02-11 02:20:53 +0000569
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400570 def VarChanged_winWidth(self, *params):
571 value = self.winWidth.get()
572 self.AddChangedItem('main', 'EditorWindow', 'width', value)
Steven M. Gavac112cd82002-01-22 05:56:40 +0000573
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400574 def VarChanged_winHeight(self, *params):
575 value = self.winHeight.get()
576 self.AddChangedItem('main', 'EditorWindow', 'height', value)
Steven M. Gavac112cd82002-01-22 05:56:40 +0000577
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400578 def VarChanged_startupEdit(self, *params):
579 value = self.startupEdit.get()
580 self.AddChangedItem('main', 'General', 'editor-on-startup', value)
Steven M. Gavac112cd82002-01-22 05:56:40 +0000581
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400582 def VarChanged_autoSave(self, *params):
583 value = self.autoSave.get()
584 self.AddChangedItem('main', 'General', 'autosave', value)
Kurt B. Kaiser6c638b62003-05-26 06:23:10 +0000585
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400586 def VarChanged_encoding(self, *params):
587 value = self.encoding.get()
588 self.AddChangedItem('main', 'EditorWindow', 'encoding', value)
Kurt B. Kaisera053f332003-05-10 00:49:56 +0000589
Steven M. Gavaa498af22002-02-01 01:33:36 +0000590 def ResetChangedItems(self):
Steven M. Gavab77d3432002-03-02 07:16:21 +0000591 #When any config item is changed in this dialog, an entry
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000592 #should be made in the relevant section (config type) of this
593 #dictionary. The key should be the config file section name and the
Steven M. Gavaa498af22002-02-01 01:33:36 +0000594 #value a dictionary, whose key:value pairs are item=value pairs for
595 #that config file section.
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400596 self.changedItems = {'main':{}, 'highlight':{}, 'keys':{},
597 'extensions':{}}
Steven M. Gavaa498af22002-02-01 01:33:36 +0000598
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400599 def AddChangedItem(self, typ, section, item, value):
600 value = str(value) #make sure we use a string
601 if section not in self.changedItems[typ]:
602 self.changedItems[typ][section] = {}
603 self.changedItems[typ][section][item] = value
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000604
Steven M. Gava5f28e8f2002-01-21 06:38:21 +0000605 def GetDefaultItems(self):
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400606 dItems={'main':{}, 'highlight':{}, 'keys':{}, 'extensions':{}}
Kurt B. Kaisere0712772007-08-23 05:25:55 +0000607 for configType in dItems:
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400608 sections = idleConf.GetSectionList('default', configType)
Steven M. Gava5f28e8f2002-01-21 06:38:21 +0000609 for section in sections:
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400610 dItems[configType][section] = {}
611 options = idleConf.defaultCfg[configType].GetOptionList(section)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000612 for option in options:
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400613 dItems[configType][section][option] = (
614 idleConf.defaultCfg[configType].Get(section, option))
Steven M. Gava5f28e8f2002-01-21 06:38:21 +0000615 return dItems
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000616
Steven M. Gava5f28e8f2002-01-21 06:38:21 +0000617 def SetThemeType(self):
618 if self.themeIsBuiltin.get():
619 self.optMenuThemeBuiltin.config(state=NORMAL)
620 self.optMenuThemeCustom.config(state=DISABLED)
621 self.buttonDeleteCustomTheme.config(state=DISABLED)
622 else:
623 self.optMenuThemeBuiltin.config(state=DISABLED)
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000624 self.radioThemeCustom.config(state=NORMAL)
Steven M. Gava5f28e8f2002-01-21 06:38:21 +0000625 self.optMenuThemeCustom.config(state=NORMAL)
626 self.buttonDeleteCustomTheme.config(state=NORMAL)
627
628 def SetKeysType(self):
Steven M. Gava052937f2002-02-11 02:20:53 +0000629 if self.keysAreBuiltin.get():
Steven M. Gava5f28e8f2002-01-21 06:38:21 +0000630 self.optMenuKeysBuiltin.config(state=NORMAL)
631 self.optMenuKeysCustom.config(state=DISABLED)
632 self.buttonDeleteCustomKeys.config(state=DISABLED)
633 else:
634 self.optMenuKeysBuiltin.config(state=DISABLED)
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000635 self.radioKeysCustom.config(state=NORMAL)
Steven M. Gava5f28e8f2002-01-21 06:38:21 +0000636 self.optMenuKeysCustom.config(state=NORMAL)
637 self.buttonDeleteCustomKeys.config(state=NORMAL)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000638
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000639 def GetNewKeys(self):
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400640 listIndex = self.listBindings.index(ANCHOR)
641 binding = self.listBindings.get(listIndex)
642 bindName = binding.split()[0] #first part, up to first space
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000643 if self.keysAreBuiltin.get():
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400644 currentKeySetName = self.builtinKeys.get()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000645 else:
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400646 currentKeySetName = self.customKeys.get()
647 currentBindings = idleConf.GetCurrentKeySet()
Kurt B. Kaisere0712772007-08-23 05:25:55 +0000648 if currentKeySetName in self.changedItems['keys']: #unsaved changes
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400649 keySetChanges = self.changedItems['keys'][currentKeySetName]
Kurt B. Kaisere0712772007-08-23 05:25:55 +0000650 for event in keySetChanges:
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400651 currentBindings[event] = keySetChanges[event].split()
Kurt B. Kaisere0712772007-08-23 05:25:55 +0000652 currentKeySequences = list(currentBindings.values())
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400653 newKeys = GetKeysDialog(self, 'Get New Keys', bindName,
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000654 currentKeySequences).result
655 if newKeys: #new keys were specified
Steven M. Gava052937f2002-02-11 02:20:53 +0000656 if self.keysAreBuiltin.get(): #current key set is a built-in
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400657 message = ('Your changes will be saved as a new Custom Key Set.'
658 ' Enter a name for your new Custom Key Set below.')
659 newKeySet = self.GetNewKeysName(message)
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000660 if not newKeySet: #user cancelled custom key set creation
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000661 self.listBindings.select_set(listIndex)
662 self.listBindings.select_anchor(listIndex)
663 return
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000664 else: #create new custom key set based on previously active key set
665 self.CreateNewKeySet(newKeySet)
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000666 self.listBindings.delete(listIndex)
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400667 self.listBindings.insert(listIndex, bindName+' - '+newKeys)
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000668 self.listBindings.select_set(listIndex)
669 self.listBindings.select_anchor(listIndex)
Steven M. Gava052937f2002-02-11 02:20:53 +0000670 self.keyBinding.set(newKeys)
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000671 else:
672 self.listBindings.select_set(listIndex)
673 self.listBindings.select_anchor(listIndex)
674
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400675 def GetNewKeysName(self, message):
676 usedNames = (idleConf.GetSectionList('user', 'keys') +
677 idleConf.GetSectionList('default', 'keys'))
678 newKeySet = GetCfgSectionNameDialog(
679 self, 'New Custom Key Set', message, usedNames).result
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000680 return newKeySet
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000681
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000682 def SaveAsNewKeySet(self):
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400683 newKeysName = self.GetNewKeysName('New Key Set Name:')
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000684 if newKeysName:
685 self.CreateNewKeySet(newKeysName)
686
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400687 def KeyBindingSelected(self, event):
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000688 self.buttonNewKeys.config(state=NORMAL)
689
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400690 def CreateNewKeySet(self, newKeySetName):
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000691 #creates new custom key set based on the previously active key set,
692 #and makes the new key set active
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000693 if self.keysAreBuiltin.get():
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400694 prevKeySetName = self.builtinKeys.get()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000695 else:
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400696 prevKeySetName = self.customKeys.get()
697 prevKeys = idleConf.GetCoreKeys(prevKeySetName)
698 newKeys = {}
Kurt B. Kaisere0712772007-08-23 05:25:55 +0000699 for event in prevKeys: #add key set to changed items
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400700 eventName = event[2:-2] #trim off the angle brackets
701 binding = ' '.join(prevKeys[event])
702 newKeys[eventName] = binding
Steven M. Gava052937f2002-02-11 02:20:53 +0000703 #handle any unsaved changes to prev key set
Kurt B. Kaisere0712772007-08-23 05:25:55 +0000704 if prevKeySetName in self.changedItems['keys']:
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400705 keySetChanges = self.changedItems['keys'][prevKeySetName]
Kurt B. Kaisere0712772007-08-23 05:25:55 +0000706 for event in keySetChanges:
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400707 newKeys[event] = keySetChanges[event]
Steven M. Gava052937f2002-02-11 02:20:53 +0000708 #save the new theme
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400709 self.SaveNewKeySet(newKeySetName, newKeys)
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000710 #change gui over to the new key set
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400711 customKeyList = idleConf.GetSectionList('user', 'keys')
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000712 customKeyList.sort()
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400713 self.optMenuKeysCustom.SetMenu(customKeyList, newKeySetName)
Steven M. Gava052937f2002-02-11 02:20:53 +0000714 self.keysAreBuiltin.set(0)
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000715 self.SetKeysType()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000716
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400717 def LoadKeysList(self, keySetName):
718 reselect = 0
719 newKeySet = 0
Steven M. Gava052937f2002-02-11 02:20:53 +0000720 if self.listBindings.curselection():
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400721 reselect = 1
722 listIndex = self.listBindings.index(ANCHOR)
723 keySet = idleConf.GetKeySet(keySetName)
Kurt B. Kaisere0712772007-08-23 05:25:55 +0000724 bindNames = list(keySet.keys())
Steven M. Gava052937f2002-02-11 02:20:53 +0000725 bindNames.sort()
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400726 self.listBindings.delete(0, END)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000727 for bindName in bindNames:
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400728 key = ' '.join(keySet[bindName]) #make key(s) into a string
729 bindName = bindName[2:-2] #trim off the angle brackets
Kurt B. Kaisere0712772007-08-23 05:25:55 +0000730 if keySetName in self.changedItems['keys']:
Steven M. Gava052937f2002-02-11 02:20:53 +0000731 #handle any unsaved changes to this key set
Kurt B. Kaisere0712772007-08-23 05:25:55 +0000732 if bindName in self.changedItems['keys'][keySetName]:
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400733 key = self.changedItems['keys'][keySetName][bindName]
Steven M. Gava052937f2002-02-11 02:20:53 +0000734 self.listBindings.insert(END, bindName+' - '+key)
Steven M. Gava052937f2002-02-11 02:20:53 +0000735 if reselect:
736 self.listBindings.see(listIndex)
737 self.listBindings.select_set(listIndex)
738 self.listBindings.select_anchor(listIndex)
739
Steven M. Gava49745752002-02-18 01:43:11 +0000740 def DeleteCustomKeys(self):
741 keySetName=self.customKeys.get()
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400742 delmsg = 'Are you sure you wish to delete the key set %r ?'
743 if not tkMessageBox.askyesno(
744 'Delete Key Set', delmsg % keySetName, parent=self):
Steven M. Gava49745752002-02-18 01:43:11 +0000745 return
746 #remove key set from config
747 idleConf.userCfg['keys'].remove_section(keySetName)
Guido van Rossum811c4e02006-08-22 15:45:46 +0000748 if keySetName in self.changedItems['keys']:
Steven M. Gava49745752002-02-18 01:43:11 +0000749 del(self.changedItems['keys'][keySetName])
750 #write changes
751 idleConf.userCfg['keys'].Save()
752 #reload user key set list
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400753 itemList = idleConf.GetSectionList('user', 'keys')
Steven M. Gava49745752002-02-18 01:43:11 +0000754 itemList.sort()
755 if not itemList:
756 self.radioKeysCustom.config(state=DISABLED)
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400757 self.optMenuKeysCustom.SetMenu(itemList, '- no custom keys -')
Steven M. Gava49745752002-02-18 01:43:11 +0000758 else:
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400759 self.optMenuKeysCustom.SetMenu(itemList, itemList[0])
Steven M. Gava49745752002-02-18 01:43:11 +0000760 #revert to default key set
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400761 self.keysAreBuiltin.set(idleConf.defaultCfg['main'].Get('Keys', 'default'))
762 self.builtinKeys.set(idleConf.defaultCfg['main'].Get('Keys', 'name'))
Steven M. Gava49745752002-02-18 01:43:11 +0000763 #user can't back out of these changes, they must be applied now
764 self.Apply()
765 self.SetKeysType()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000766
Steven M. Gava49745752002-02-18 01:43:11 +0000767 def DeleteCustomTheme(self):
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400768 themeName = self.customTheme.get()
769 delmsg = 'Are you sure you wish to delete the theme %r ?'
770 if not tkMessageBox.askyesno(
771 'Delete Theme', delmsg % themeName, parent=self):
Steven M. Gava49745752002-02-18 01:43:11 +0000772 return
773 #remove theme from config
774 idleConf.userCfg['highlight'].remove_section(themeName)
Guido van Rossum811c4e02006-08-22 15:45:46 +0000775 if themeName in self.changedItems['highlight']:
Steven M. Gava49745752002-02-18 01:43:11 +0000776 del(self.changedItems['highlight'][themeName])
777 #write changes
778 idleConf.userCfg['highlight'].Save()
779 #reload user theme list
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400780 itemList = idleConf.GetSectionList('user', 'highlight')
Steven M. Gava49745752002-02-18 01:43:11 +0000781 itemList.sort()
782 if not itemList:
783 self.radioThemeCustom.config(state=DISABLED)
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400784 self.optMenuThemeCustom.SetMenu(itemList, '- no custom themes -')
Steven M. Gava49745752002-02-18 01:43:11 +0000785 else:
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400786 self.optMenuThemeCustom.SetMenu(itemList, itemList[0])
Steven M. Gava49745752002-02-18 01:43:11 +0000787 #revert to default theme
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400788 self.themeIsBuiltin.set(idleConf.defaultCfg['main'].Get('Theme', 'default'))
789 self.builtinTheme.set(idleConf.defaultCfg['main'].Get('Theme', 'name'))
Steven M. Gava49745752002-02-18 01:43:11 +0000790 #user can't back out of these changes, they must be applied now
791 self.Apply()
792 self.SetThemeType()
793
Steven M. Gava5f28e8f2002-01-21 06:38:21 +0000794 def GetColour(self):
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400795 target = self.highlightTarget.get()
796 prevColour = self.frameColourSet.cget('bg')
797 rgbTuplet, colourString = tkColorChooser.askcolor(
798 parent=self, title='Pick new colour for : '+target,
799 initialcolor=prevColour)
800 if colourString and (colourString != prevColour):
Steven M. Gava052937f2002-02-11 02:20:53 +0000801 #user didn't cancel, and they chose a new colour
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400802 if self.themeIsBuiltin.get(): #current theme is a built-in
803 message = ('Your changes will be saved as a new Custom Theme. '
804 'Enter a name for your new Custom Theme below.')
805 newTheme = self.GetNewThemeName(message)
806 if not newTheme: #user cancelled custom theme creation
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000807 return
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400808 else: #create new custom theme based on previously active theme
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000809 self.CreateNewTheme(newTheme)
Steven M. Gava052937f2002-02-11 02:20:53 +0000810 self.colour.set(colourString)
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400811 else: #current theme is user defined
Steven M. Gava052937f2002-02-11 02:20:53 +0000812 self.colour.set(colourString)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000813
Steven M. Gava052937f2002-02-11 02:20:53 +0000814 def OnNewColourSet(self):
815 newColour=self.colour.get()
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400816 self.frameColourSet.config(bg=newColour) #set sample
817 plane ='foreground' if self.fgHilite.get() else 'background'
818 sampleElement = self.themeElements[self.highlightTarget.get()][0]
Raymond Hettinger931237e2003-07-09 18:48:24 +0000819 self.textHighlightSample.tag_config(sampleElement, **{plane:newColour})
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400820 theme = self.customTheme.get()
821 themeElement = sampleElement + '-' + plane
822 self.AddChangedItem('highlight', theme, themeElement, newColour)
Steven M. Gava052937f2002-02-11 02:20:53 +0000823
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400824 def GetNewThemeName(self, message):
825 usedNames = (idleConf.GetSectionList('user', 'highlight') +
826 idleConf.GetSectionList('default', 'highlight'))
827 newTheme = GetCfgSectionNameDialog(
828 self, 'New Custom Theme', message, usedNames).result
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000829 return newTheme
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000830
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000831 def SaveAsNewTheme(self):
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400832 newThemeName = self.GetNewThemeName('New Theme Name:')
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000833 if newThemeName:
834 self.CreateNewTheme(newThemeName)
835
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400836 def CreateNewTheme(self, newThemeName):
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000837 #creates new custom theme based on the previously active theme,
838 #and makes the new theme active
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000839 if self.themeIsBuiltin.get():
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400840 themeType = 'default'
841 themeName = self.builtinTheme.get()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000842 else:
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400843 themeType = 'user'
844 themeName = self.customTheme.get()
845 newTheme = idleConf.GetThemeDict(themeType, themeName)
Steven M. Gava052937f2002-02-11 02:20:53 +0000846 #apply any of the old theme's unsaved changes to the new theme
Kurt B. Kaisere0712772007-08-23 05:25:55 +0000847 if themeName in self.changedItems['highlight']:
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400848 themeChanges = self.changedItems['highlight'][themeName]
Kurt B. Kaisere0712772007-08-23 05:25:55 +0000849 for element in themeChanges:
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400850 newTheme[element] = themeChanges[element]
Steven M. Gava052937f2002-02-11 02:20:53 +0000851 #save the new theme
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400852 self.SaveNewTheme(newThemeName, newTheme)
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000853 #change gui over to the new theme
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400854 customThemeList = idleConf.GetSectionList('user', 'highlight')
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000855 customThemeList.sort()
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400856 self.optMenuThemeCustom.SetMenu(customThemeList, newThemeName)
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000857 self.themeIsBuiltin.set(0)
858 self.SetThemeType()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000859
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400860 def OnListFontButtonRelease(self, event):
Kurt B. Kaiser05391692003-05-26 20:35:53 +0000861 font = self.listFontName.get(ANCHOR)
862 self.fontName.set(font.lower())
Steven M. Gava5f28e8f2002-01-21 06:38:21 +0000863 self.SetFontSample()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000864
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400865 def SetFontSample(self, event=None):
866 fontName = self.fontName.get()
867 fontWeight = tkFont.BOLD if self.fontBold.get() else tkFont.NORMAL
Ned Deilyfdf0f272012-10-22 15:14:31 -0700868 newFont = (fontName, self.fontSize.get(), fontWeight)
869 self.labelFontSample.config(font=newFont)
870 self.textHighlightSample.configure(font=newFont)
Steven M. Gava5f28e8f2002-01-21 06:38:21 +0000871
Steven M. Gava5f28e8f2002-01-21 06:38:21 +0000872 def SetHighlightTarget(self):
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400873 if self.highlightTarget.get() == 'Cursor': #bg not possible
Steven M. Gava5f28e8f2002-01-21 06:38:21 +0000874 self.radioFg.config(state=DISABLED)
875 self.radioBg.config(state=DISABLED)
876 self.fgHilite.set(1)
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400877 else: #both fg and bg can be set
Steven M. Gava5f28e8f2002-01-21 06:38:21 +0000878 self.radioFg.config(state=NORMAL)
879 self.radioBg.config(state=NORMAL)
880 self.fgHilite.set(1)
881 self.SetColourSample()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000882
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400883 def SetColourSampleBinding(self, *args):
Steven M. Gava5f28e8f2002-01-21 06:38:21 +0000884 self.SetColourSample()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000885
Steven M. Gava5f28e8f2002-01-21 06:38:21 +0000886 def SetColourSample(self):
887 #set the colour smaple area
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400888 tag = self.themeElements[self.highlightTarget.get()][0]
889 plane = 'foreground' if self.fgHilite.get() else 'background'
890 colour = self.textHighlightSample.tag_cget(tag, plane)
Steven M. Gava5f28e8f2002-01-21 06:38:21 +0000891 self.frameColourSet.config(bg=colour)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000892
Steven M. Gava9dd16b32001-11-03 14:54:25 +0000893 def PaintThemeSample(self):
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400894 if self.themeIsBuiltin.get(): #a default theme
895 theme = self.builtinTheme.get()
896 else: #a user theme
897 theme = self.customTheme.get()
Kurt B. Kaisere0712772007-08-23 05:25:55 +0000898 for elementTitle in self.themeElements:
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400899 element = self.themeElements[elementTitle][0]
900 colours = idleConf.GetHighlight(theme, element)
901 if element == 'cursor': #cursor sample needs special painting
902 colours['background'] = idleConf.GetHighlight(
903 theme, 'normal', fgBg='bg')
Steven M. Gava052937f2002-02-11 02:20:53 +0000904 #handle any unsaved changes to this theme
Kurt B. Kaisere0712772007-08-23 05:25:55 +0000905 if theme in self.changedItems['highlight']:
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400906 themeDict = self.changedItems['highlight'][theme]
907 if element + '-foreground' in themeDict:
908 colours['foreground'] = themeDict[element + '-foreground']
909 if element + '-background' in themeDict:
910 colours['background'] = themeDict[element + '-background']
Raymond Hettinger931237e2003-07-09 18:48:24 +0000911 self.textHighlightSample.tag_config(element, **colours)
Steven M. Gava052937f2002-02-11 02:20:53 +0000912 self.SetColourSample()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000913
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400914 def HelpSourceSelected(self, event):
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000915 self.SetHelpListButtonStates()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000916
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000917 def SetHelpListButtonStates(self):
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400918 if self.listHelp.size() < 1: #no entries in list
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000919 self.buttonHelpListEdit.config(state=DISABLED)
920 self.buttonHelpListRemove.config(state=DISABLED)
921 else: #there are some entries
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400922 if self.listHelp.curselection(): #there currently is a selection
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000923 self.buttonHelpListEdit.config(state=NORMAL)
924 self.buttonHelpListRemove.config(state=NORMAL)
925 else: #there currently is not a selection
926 self.buttonHelpListEdit.config(state=DISABLED)
927 self.buttonHelpListRemove.config(state=DISABLED)
928
929 def HelpListItemAdd(self):
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400930 helpSource = GetHelpSourceDialog(self, 'New Help Source').result
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000931 if helpSource:
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400932 self.userHelpList.append((helpSource[0], helpSource[1]))
933 self.listHelp.insert(END, helpSource[0])
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000934 self.UpdateUserHelpChangedItems()
935 self.SetHelpListButtonStates()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000936
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000937 def HelpListItemEdit(self):
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400938 itemIndex = self.listHelp.index(ANCHOR)
939 helpSource = self.userHelpList[itemIndex]
940 newHelpSource = GetHelpSourceDialog(
941 self, 'Edit Help Source', menuItem=helpSource[0],
942 filePath=helpSource[1]).result
943 if (not newHelpSource) or (newHelpSource == helpSource):
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000944 return #no changes
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400945 self.userHelpList[itemIndex] = newHelpSource
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000946 self.listHelp.delete(itemIndex)
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400947 self.listHelp.insert(itemIndex, newHelpSource[0])
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000948 self.UpdateUserHelpChangedItems()
949 self.SetHelpListButtonStates()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000950
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000951 def HelpListItemRemove(self):
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400952 itemIndex = self.listHelp.index(ANCHOR)
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000953 del(self.userHelpList[itemIndex])
954 self.listHelp.delete(itemIndex)
955 self.UpdateUserHelpChangedItems()
956 self.SetHelpListButtonStates()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000957
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000958 def UpdateUserHelpChangedItems(self):
Kurt B. Kaiser8e92bf72003-01-14 22:03:31 +0000959 "Clear and rebuild the HelpFiles section in self.changedItems"
960 self.changedItems['main']['HelpFiles'] = {}
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400961 for num in range(1, len(self.userHelpList) + 1):
962 self.AddChangedItem(
963 'main', 'HelpFiles', str(num),
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000964 ';'.join(self.userHelpList[num-1][:2]))
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000965
Steven M. Gava429a86af2001-10-23 10:42:12 +0000966 def LoadFontCfg(self):
967 ##base editor font selection list
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400968 fonts = list(tkFont.families(self))
Steven M. Gavac11ccf32001-09-24 09:43:17 +0000969 fonts.sort()
970 for font in fonts:
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400971 self.listFontName.insert(END, font)
Terry Jan Reedyd87d1682015-08-01 18:57:33 -0400972 configuredFont = idleConf.GetFont(self, 'main', 'EditorWindow')
973 fontName = configuredFont[0].lower()
974 fontSize = configuredFont[1]
975 fontBold = configuredFont[2]=='bold'
976 self.fontName.set(fontName)
Kurt B. Kaiser05391692003-05-26 20:35:53 +0000977 lc_fonts = [s.lower() for s in fonts]
Terry Jan Reedyd87d1682015-08-01 18:57:33 -0400978 try:
979 currentFontIndex = lc_fonts.index(fontName)
Steven M. Gava429a86af2001-10-23 10:42:12 +0000980 self.listFontName.see(currentFontIndex)
981 self.listFontName.select_set(currentFontIndex)
Steven M. Gavac112cd82002-01-22 05:56:40 +0000982 self.listFontName.select_anchor(currentFontIndex)
Terry Jan Reedyd87d1682015-08-01 18:57:33 -0400983 except ValueError:
984 pass
Steven M. Gava429a86af2001-10-23 10:42:12 +0000985 ##font size dropdown
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400986 self.optMenuFontSize.SetMenu(('7', '8', '9', '10', '11', '12', '13',
987 '14', '16', '18', '20', '22'), fontSize )
Steven M. Gavac112cd82002-01-22 05:56:40 +0000988 ##fontWeight
Terry Jan Reedyd87d1682015-08-01 18:57:33 -0400989 self.fontBold.set(fontBold)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000990 ##font sample
Steven M. Gava429a86af2001-10-23 10:42:12 +0000991 self.SetFontSample()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000992
Steven M. Gava429a86af2001-10-23 10:42:12 +0000993 def LoadTabCfg(self):
Steven M. Gava429a86af2001-10-23 10:42:12 +0000994 ##indent sizes
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400995 spaceNum = idleConf.GetOption(
996 'main', 'Indent', 'num-spaces', default=4, type='int')
Steven M. Gava429a86af2001-10-23 10:42:12 +0000997 self.spaceNum.set(spaceNum)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000998
Steven M. Gava9dd16b32001-11-03 14:54:25 +0000999 def LoadThemeCfg(self):
Steven M. Gava41a85322001-10-29 08:05:34 +00001000 ##current theme type radiobutton
Terry Jan Reedy4036d872014-08-03 23:02:58 -04001001 self.themeIsBuiltin.set(idleConf.GetOption(
1002 'main', 'Theme', 'default', type='bool', default=1))
Steven M. Gava41a85322001-10-29 08:05:34 +00001003 ##currently set theme
Terry Jan Reedy4036d872014-08-03 23:02:58 -04001004 currentOption = idleConf.CurrentTheme()
Steven M. Gava7c017862001-10-29 11:19:46 +00001005 ##load available theme option menus
Steven M. Gavad0342cd2001-11-04 11:53:10 +00001006 if self.themeIsBuiltin.get(): #default theme selected
Terry Jan Reedy4036d872014-08-03 23:02:58 -04001007 itemList = idleConf.GetSectionList('default', 'highlight')
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +00001008 itemList.sort()
Terry Jan Reedy4036d872014-08-03 23:02:58 -04001009 self.optMenuThemeBuiltin.SetMenu(itemList, currentOption)
1010 itemList = idleConf.GetSectionList('user', 'highlight')
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +00001011 itemList.sort()
Steven M. Gava41a85322001-10-29 08:05:34 +00001012 if not itemList:
1013 self.radioThemeCustom.config(state=DISABLED)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001014 self.customTheme.set('- no custom themes -')
Steven M. Gava41a85322001-10-29 08:05:34 +00001015 else:
Terry Jan Reedy4036d872014-08-03 23:02:58 -04001016 self.optMenuThemeCustom.SetMenu(itemList, itemList[0])
Steven M. Gava9dd16b32001-11-03 14:54:25 +00001017 else: #user theme selected
Terry Jan Reedy4036d872014-08-03 23:02:58 -04001018 itemList = idleConf.GetSectionList('user', 'highlight')
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +00001019 itemList.sort()
Terry Jan Reedy4036d872014-08-03 23:02:58 -04001020 self.optMenuThemeCustom.SetMenu(itemList, currentOption)
1021 itemList = idleConf.GetSectionList('default', 'highlight')
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +00001022 itemList.sort()
Terry Jan Reedy4036d872014-08-03 23:02:58 -04001023 self.optMenuThemeBuiltin.SetMenu(itemList, itemList[0])
Steven M. Gava7c017862001-10-29 11:19:46 +00001024 self.SetThemeType()
1025 ##load theme element option menu
Kurt B. Kaisere0712772007-08-23 05:25:55 +00001026 themeNames = list(self.themeElements.keys())
Kurt B. Kaiser4718bf82008-02-12 21:34:12 +00001027 themeNames.sort(key=lambda x: self.themeElements[x][1])
Terry Jan Reedy4036d872014-08-03 23:02:58 -04001028 self.optMenuHighlightTarget.SetMenu(themeNames, themeNames[0])
Steven M. Gava9dd16b32001-11-03 14:54:25 +00001029 self.PaintThemeSample()
Steven M. Gava0cae01c2002-01-04 07:53:06 +00001030 self.SetHighlightTarget()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001031
Steven M. Gava9dd16b32001-11-03 14:54:25 +00001032 def LoadKeyCfg(self):
Steven M. Gava41a85322001-10-29 08:05:34 +00001033 ##current keys type radiobutton
Terry Jan Reedy4036d872014-08-03 23:02:58 -04001034 self.keysAreBuiltin.set(idleConf.GetOption(
1035 'main', 'Keys', 'default', type='bool', default=1))
Steven M. Gava41a85322001-10-29 08:05:34 +00001036 ##currently set keys
Terry Jan Reedy4036d872014-08-03 23:02:58 -04001037 currentOption = idleConf.CurrentKeys()
Steven M. Gava7c017862001-10-29 11:19:46 +00001038 ##load available keyset option menus
Steven M. Gava052937f2002-02-11 02:20:53 +00001039 if self.keysAreBuiltin.get(): #default theme selected
Terry Jan Reedy4036d872014-08-03 23:02:58 -04001040 itemList = idleConf.GetSectionList('default', 'keys')
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +00001041 itemList.sort()
Terry Jan Reedy4036d872014-08-03 23:02:58 -04001042 self.optMenuKeysBuiltin.SetMenu(itemList, currentOption)
1043 itemList = idleConf.GetSectionList('user', 'keys')
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +00001044 itemList.sort()
Steven M. Gava41a85322001-10-29 08:05:34 +00001045 if not itemList:
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001046 self.radioKeysCustom.config(state=DISABLED)
1047 self.customKeys.set('- no custom keys -')
Steven M. Gava41a85322001-10-29 08:05:34 +00001048 else:
Terry Jan Reedy4036d872014-08-03 23:02:58 -04001049 self.optMenuKeysCustom.SetMenu(itemList, itemList[0])
Steven M. Gavaa498af22002-02-01 01:33:36 +00001050 else: #user key set selected
Terry Jan Reedy4036d872014-08-03 23:02:58 -04001051 itemList = idleConf.GetSectionList('user', 'keys')
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +00001052 itemList.sort()
Terry Jan Reedy4036d872014-08-03 23:02:58 -04001053 self.optMenuKeysCustom.SetMenu(itemList, currentOption)
1054 itemList = idleConf.GetSectionList('default', 'keys')
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +00001055 itemList.sort()
Terry Jan Reedy4036d872014-08-03 23:02:58 -04001056 self.optMenuKeysBuiltin.SetMenu(itemList, itemList[0])
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001057 self.SetKeysType()
Steven M. Gavafacfc092002-01-19 00:29:54 +00001058 ##load keyset element list
Terry Jan Reedy4036d872014-08-03 23:02:58 -04001059 keySetName = idleConf.CurrentKeys()
Steven M. Gava052937f2002-02-11 02:20:53 +00001060 self.LoadKeysList(keySetName)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001061
Steven M. Gavafacfc092002-01-19 00:29:54 +00001062 def LoadGeneralCfg(self):
Steven M. Gava5f28e8f2002-01-21 06:38:21 +00001063 #startup state
Terry Jan Reedy4036d872014-08-03 23:02:58 -04001064 self.startupEdit.set(idleConf.GetOption(
1065 'main', 'General', 'editor-on-startup', default=1, type='bool'))
Kurt B. Kaiser6c638b62003-05-26 06:23:10 +00001066 #autosave state
Terry Jan Reedy4036d872014-08-03 23:02:58 -04001067 self.autoSave.set(idleConf.GetOption(
1068 'main', 'General', 'autosave', default=0, type='bool'))
Steven M. Gavafacfc092002-01-19 00:29:54 +00001069 #initial window size
Terry Jan Reedy4036d872014-08-03 23:02:58 -04001070 self.winWidth.set(idleConf.GetOption(
1071 'main', 'EditorWindow', 'width', type='int'))
1072 self.winHeight.set(idleConf.GetOption(
1073 'main', 'EditorWindow', 'height', type='int'))
Kurt B. Kaisera053f332003-05-10 00:49:56 +00001074 # default source encoding
Terry Jan Reedy4036d872014-08-03 23:02:58 -04001075 self.encoding.set(idleConf.GetOption(
1076 'main', 'EditorWindow', 'encoding', default='none'))
Kurt B. Kaiser8e92bf72003-01-14 22:03:31 +00001077 # additional help sources
1078 self.userHelpList = idleConf.GetAllExtraHelpSourcesList()
Steven M. Gava085eb1b2002-02-05 04:52:32 +00001079 for helpItem in self.userHelpList:
Terry Jan Reedy4036d872014-08-03 23:02:58 -04001080 self.listHelp.insert(END, helpItem[0])
Steven M. Gava085eb1b2002-02-05 04:52:32 +00001081 self.SetHelpListButtonStates()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001082
Steven M. Gava429a86af2001-10-23 10:42:12 +00001083 def LoadConfigs(self):
1084 """
1085 load configuration from default and user config files and populate
1086 the widgets on the config dialog pages.
1087 """
1088 ### fonts / tabs page
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001089 self.LoadFontCfg()
1090 self.LoadTabCfg()
Steven M. Gava429a86af2001-10-23 10:42:12 +00001091 ### highlighting page
Steven M. Gava9dd16b32001-11-03 14:54:25 +00001092 self.LoadThemeCfg()
Steven M. Gava429a86af2001-10-23 10:42:12 +00001093 ### keys page
Steven M. Gava9dd16b32001-11-03 14:54:25 +00001094 self.LoadKeyCfg()
Steven M. Gava429a86af2001-10-23 10:42:12 +00001095 ### general page
Steven M. Gavafacfc092002-01-19 00:29:54 +00001096 self.LoadGeneralCfg()
Terry Jan Reedy93f35422015-10-13 22:03:51 -04001097 # note: extension page handled separately
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001098
Terry Jan Reedy4036d872014-08-03 23:02:58 -04001099 def SaveNewKeySet(self, keySetName, keySet):
Steven M. Gava052937f2002-02-11 02:20:53 +00001100 """
1101 save a newly created core key set.
1102 keySetName - string, the name of the new key set
1103 keySet - dictionary containing the new key set
1104 """
1105 if not idleConf.userCfg['keys'].has_section(keySetName):
1106 idleConf.userCfg['keys'].add_section(keySetName)
Kurt B. Kaisere0712772007-08-23 05:25:55 +00001107 for event in keySet:
Terry Jan Reedy4036d872014-08-03 23:02:58 -04001108 value = keySet[event]
1109 idleConf.userCfg['keys'].SetOption(keySetName, event, value)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001110
Terry Jan Reedy4036d872014-08-03 23:02:58 -04001111 def SaveNewTheme(self, themeName, theme):
Steven M. Gava052937f2002-02-11 02:20:53 +00001112 """
1113 save a newly created theme.
1114 themeName - string, the name of the new theme
1115 theme - dictionary containing the new theme
1116 """
1117 if not idleConf.userCfg['highlight'].has_section(themeName):
1118 idleConf.userCfg['highlight'].add_section(themeName)
Kurt B. Kaisere0712772007-08-23 05:25:55 +00001119 for element in theme:
Terry Jan Reedy4036d872014-08-03 23:02:58 -04001120 value = theme[element]
1121 idleConf.userCfg['highlight'].SetOption(themeName, element, value)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001122
Terry Jan Reedy4036d872014-08-03 23:02:58 -04001123 def SetUserValue(self, configType, section, item, value):
1124 if idleConf.defaultCfg[configType].has_option(section, item):
1125 if idleConf.defaultCfg[configType].Get(section, item) == value:
Steven M. Gava2d7bb3f2002-01-29 08:35:29 +00001126 #the setting equals a default setting, remove it from user cfg
Terry Jan Reedy4036d872014-08-03 23:02:58 -04001127 return idleConf.userCfg[configType].RemoveOption(section, item)
Steven M. Gava2d7bb3f2002-01-29 08:35:29 +00001128 #if we got here set the option
Terry Jan Reedy4036d872014-08-03 23:02:58 -04001129 return idleConf.userCfg[configType].SetOption(section, item, value)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001130
Steven M. Gava052937f2002-02-11 02:20:53 +00001131 def SaveAllChangedConfigs(self):
Kurt B. Kaisere7a161e2003-01-10 20:13:57 +00001132 "Save configuration changes to the user config file."
Steven M. Gava0c5bc8c2002-03-27 02:25:44 +00001133 idleConf.userCfg['main'].Save()
Kurt B. Kaisere0712772007-08-23 05:25:55 +00001134 for configType in self.changedItems:
Kurt B. Kaisere7a161e2003-01-10 20:13:57 +00001135 cfgTypeHasChanges = False
Kurt B. Kaisere0712772007-08-23 05:25:55 +00001136 for section in self.changedItems[configType]:
Kurt B. Kaisere7a161e2003-01-10 20:13:57 +00001137 if section == 'HelpFiles':
1138 #this section gets completely replaced
1139 idleConf.userCfg['main'].remove_section('HelpFiles')
Kurt B. Kaiser8e92bf72003-01-14 22:03:31 +00001140 cfgTypeHasChanges = True
Kurt B. Kaisere0712772007-08-23 05:25:55 +00001141 for item in self.changedItems[configType][section]:
Kurt B. Kaisere7a161e2003-01-10 20:13:57 +00001142 value = self.changedItems[configType][section][item]
Terry Jan Reedy4036d872014-08-03 23:02:58 -04001143 if self.SetUserValue(configType, section, item, value):
Kurt B. Kaisere7a161e2003-01-10 20:13:57 +00001144 cfgTypeHasChanges = True
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001145 if cfgTypeHasChanges:
1146 idleConf.userCfg[configType].Save()
Kurt B. Kaiser5acdf932004-11-16 21:28:36 +00001147 for configType in ['keys', 'highlight']:
1148 # save these even if unchanged!
1149 idleConf.userCfg[configType].Save()
Steven M. Gavaa498af22002-02-01 01:33:36 +00001150 self.ResetChangedItems() #clear the changed items dict
Terry Jan Reedy93f35422015-10-13 22:03:51 -04001151 self.save_all_changed_extensions() # uses a different mechanism
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001152
Kurt B. Kaiserb1754452005-11-18 22:05:48 +00001153 def DeactivateCurrentConfig(self):
1154 #Before a config is saved, some cleanup of current
1155 #config must be done - remove the previous keybindings
Kurt B. Kaisere0712772007-08-23 05:25:55 +00001156 winInstances = self.parent.instance_dict.keys()
Kurt B. Kaiserb1754452005-11-18 22:05:48 +00001157 for instance in winInstances:
1158 instance.RemoveKeybindings()
1159
Steven M. Gava49745752002-02-18 01:43:11 +00001160 def ActivateConfigChanges(self):
Kurt B. Kaiseracdef852005-01-31 03:34:26 +00001161 "Dynamically apply configuration changes"
Kurt B. Kaisere0712772007-08-23 05:25:55 +00001162 winInstances = self.parent.instance_dict.keys()
Steven M. Gavab77d3432002-03-02 07:16:21 +00001163 for instance in winInstances:
1164 instance.ResetColorizer()
Steven M. Gavab1585412002-03-12 00:21:56 +00001165 instance.ResetFont()
Kurt B. Kaiseracdef852005-01-31 03:34:26 +00001166 instance.set_notabs_indentwidth()
Kurt B. Kaiserb1754452005-11-18 22:05:48 +00001167 instance.ApplyKeybindings()
Kurt B. Kaiser8e92bf72003-01-14 22:03:31 +00001168 instance.reset_help_menu_entries()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001169
Steven M. Gava5f28e8f2002-01-21 06:38:21 +00001170 def Cancel(self):
1171 self.destroy()
1172
1173 def Ok(self):
1174 self.Apply()
1175 self.destroy()
1176
1177 def Apply(self):
Kurt B. Kaiserb1754452005-11-18 22:05:48 +00001178 self.DeactivateCurrentConfig()
Steven M. Gava052937f2002-02-11 02:20:53 +00001179 self.SaveAllChangedConfigs()
Steven M. Gava49745752002-02-18 01:43:11 +00001180 self.ActivateConfigChanges()
Steven M. Gava5f28e8f2002-01-21 06:38:21 +00001181
1182 def Help(self):
Terry Jan Reedyd0cadba2015-10-11 22:07:31 -04001183 page = self.tabPages._current_page
1184 view_text(self, title='Help for IDLE preferences',
1185 text=help_common+help_pages.get(page, ''))
1186
Terry Jan Reedy93f35422015-10-13 22:03:51 -04001187 def CreatePageExtensions(self):
1188 """Part of the config dialog used for configuring IDLE extensions.
1189
1190 This code is generic - it works for any and all IDLE extensions.
1191
1192 IDLE extensions save their configuration options using idleConf.
Terry Jan Reedyb2f87602015-10-13 22:09:06 -04001193 This code reads the current configuration using idleConf, supplies a
Terry Jan Reedy93f35422015-10-13 22:03:51 -04001194 GUI interface to change the configuration values, and saves the
1195 changes using idleConf.
1196
1197 Not all changes take effect immediately - some may require restarting IDLE.
1198 This depends on each extension's implementation.
1199
1200 All values are treated as text, and it is up to the user to supply
1201 reasonable values. The only exception to this are the 'enable*' options,
1202 which are boolean, and can be toggled with an True/False button.
1203 """
1204 parent = self.parent
1205 frame = self.tabPages.pages['Extensions'].frame
1206 self.ext_defaultCfg = idleConf.defaultCfg['extensions']
1207 self.ext_userCfg = idleConf.userCfg['extensions']
1208 self.is_int = self.register(is_int)
1209 self.load_extensions()
1210 # create widgets - a listbox shows all available extensions, with the
1211 # controls for the extension selected in the listbox to the right
1212 self.extension_names = StringVar(self)
1213 frame.rowconfigure(0, weight=1)
1214 frame.columnconfigure(2, weight=1)
1215 self.extension_list = Listbox(frame, listvariable=self.extension_names,
1216 selectmode='browse')
1217 self.extension_list.bind('<<ListboxSelect>>', self.extension_selected)
1218 scroll = Scrollbar(frame, command=self.extension_list.yview)
1219 self.extension_list.yscrollcommand=scroll.set
1220 self.details_frame = LabelFrame(frame, width=250, height=250)
1221 self.extension_list.grid(column=0, row=0, sticky='nws')
1222 scroll.grid(column=1, row=0, sticky='ns')
1223 self.details_frame.grid(column=2, row=0, sticky='nsew', padx=[10, 0])
1224 frame.configure(padx=10, pady=10)
1225 self.config_frame = {}
1226 self.current_extension = None
1227
1228 self.outerframe = self # TEMPORARY
1229 self.tabbed_page_set = self.extension_list # TEMPORARY
1230
1231 # create the frame holding controls for each extension
1232 ext_names = ''
1233 for ext_name in sorted(self.extensions):
1234 self.create_extension_frame(ext_name)
1235 ext_names = ext_names + '{' + ext_name + '} '
1236 self.extension_names.set(ext_names)
1237 self.extension_list.selection_set(0)
1238 self.extension_selected(None)
1239
1240 def load_extensions(self):
1241 "Fill self.extensions with data from the default and user configs."
1242 self.extensions = {}
1243 for ext_name in idleConf.GetExtensions(active_only=False):
1244 self.extensions[ext_name] = []
1245
1246 for ext_name in self.extensions:
1247 opt_list = sorted(self.ext_defaultCfg.GetOptionList(ext_name))
1248
1249 # bring 'enable' options to the beginning of the list
1250 enables = [opt_name for opt_name in opt_list
1251 if opt_name.startswith('enable')]
1252 for opt_name in enables:
1253 opt_list.remove(opt_name)
1254 opt_list = enables + opt_list
1255
1256 for opt_name in opt_list:
1257 def_str = self.ext_defaultCfg.Get(
1258 ext_name, opt_name, raw=True)
1259 try:
1260 def_obj = {'True':True, 'False':False}[def_str]
1261 opt_type = 'bool'
1262 except KeyError:
1263 try:
1264 def_obj = int(def_str)
1265 opt_type = 'int'
1266 except ValueError:
1267 def_obj = def_str
1268 opt_type = None
1269 try:
1270 value = self.ext_userCfg.Get(
1271 ext_name, opt_name, type=opt_type, raw=True,
1272 default=def_obj)
1273 except ValueError: # Need this until .Get fixed
1274 value = def_obj # bad values overwritten by entry
1275 var = StringVar(self)
1276 var.set(str(value))
1277
1278 self.extensions[ext_name].append({'name': opt_name,
1279 'type': opt_type,
1280 'default': def_str,
1281 'value': value,
1282 'var': var,
1283 })
1284
1285 def extension_selected(self, event):
1286 newsel = self.extension_list.curselection()
1287 if newsel:
1288 newsel = self.extension_list.get(newsel)
1289 if newsel is None or newsel != self.current_extension:
1290 if self.current_extension:
1291 self.details_frame.config(text='')
1292 self.config_frame[self.current_extension].grid_forget()
1293 self.current_extension = None
1294 if newsel:
1295 self.details_frame.config(text=newsel)
1296 self.config_frame[newsel].grid(column=0, row=0, sticky='nsew')
1297 self.current_extension = newsel
1298
1299 def create_extension_frame(self, ext_name):
1300 """Create a frame holding the widgets to configure one extension"""
1301 f = VerticalScrolledFrame(self.details_frame, height=250, width=250)
1302 self.config_frame[ext_name] = f
1303 entry_area = f.interior
1304 # create an entry for each configuration option
1305 for row, opt in enumerate(self.extensions[ext_name]):
1306 # create a row with a label and entry/checkbutton
1307 label = Label(entry_area, text=opt['name'])
1308 label.grid(row=row, column=0, sticky=NW)
1309 var = opt['var']
1310 if opt['type'] == 'bool':
1311 Checkbutton(entry_area, textvariable=var, variable=var,
1312 onvalue='True', offvalue='False',
1313 indicatoron=FALSE, selectcolor='', width=8
1314 ).grid(row=row, column=1, sticky=W, padx=7)
1315 elif opt['type'] == 'int':
1316 Entry(entry_area, textvariable=var, validate='key',
1317 validatecommand=(self.is_int, '%P')
1318 ).grid(row=row, column=1, sticky=NSEW, padx=7)
1319
1320 else:
1321 Entry(entry_area, textvariable=var
1322 ).grid(row=row, column=1, sticky=NSEW, padx=7)
1323 return
1324
1325 def set_extension_value(self, section, opt):
1326 name = opt['name']
1327 default = opt['default']
1328 value = opt['var'].get().strip() or default
1329 opt['var'].set(value)
1330 # if self.defaultCfg.has_section(section):
1331 # Currently, always true; if not, indent to return
1332 if (value == default):
1333 return self.ext_userCfg.RemoveOption(section, name)
1334 # set the option
1335 return self.ext_userCfg.SetOption(section, name, value)
1336
1337 def save_all_changed_extensions(self):
1338 """Save configuration changes to the user config file."""
1339 has_changes = False
1340 for ext_name in self.extensions:
1341 options = self.extensions[ext_name]
1342 for opt in options:
1343 if self.set_extension_value(ext_name, opt):
1344 has_changes = True
1345 if has_changes:
1346 self.ext_userCfg.Save()
1347
1348
Terry Jan Reedyd0cadba2015-10-11 22:07:31 -04001349help_common = '''\
1350When you click either the Apply or Ok buttons, settings in this
1351dialog that are different from IDLE's default are saved in
1352a .idlerc directory in your home directory. Except as noted,
1353hese changes apply to all versions of IDLE installed on this
1354machine. Some do not take affect until IDLE is restarted.
1355[Cancel] only cancels changes made since the last save.
1356'''
1357help_pages = {
1358 'Highlighting':'''
1359Highlighting:
1360The IDLE Dark color theme is new in Octover 2015. It can only
1361be used with older IDLE releases if it is saved as a custom
1362theme, with a different name.
1363'''
1364}
1365
Steven M. Gavac11ccf32001-09-24 09:43:17 +00001366
Terry Jan Reedy93f35422015-10-13 22:03:51 -04001367def is_int(s):
1368 "Return 's is blank or represents an int'"
1369 if not s:
1370 return True
1371 try:
1372 int(s)
1373 return True
1374 except ValueError:
1375 return False
1376
1377
Terry Jan Reedya9421fb2014-10-22 20:15:18 -04001378class VerticalScrolledFrame(Frame):
1379 """A pure Tkinter vertically scrollable frame.
1380
1381 * Use the 'interior' attribute to place widgets inside the scrollable frame
1382 * Construct and pack/place/grid normally
1383 * This frame only allows vertical scrolling
1384 """
1385 def __init__(self, parent, *args, **kw):
1386 Frame.__init__(self, parent, *args, **kw)
1387
1388 # create a canvas object and a vertical scrollbar for scrolling it
1389 vscrollbar = Scrollbar(self, orient=VERTICAL)
1390 vscrollbar.pack(fill=Y, side=RIGHT, expand=FALSE)
1391 canvas = Canvas(self, bd=0, highlightthickness=0,
1392 yscrollcommand=vscrollbar.set)
1393 canvas.pack(side=LEFT, fill=BOTH, expand=TRUE)
1394 vscrollbar.config(command=canvas.yview)
1395
1396 # reset the view
1397 canvas.xview_moveto(0)
1398 canvas.yview_moveto(0)
1399
1400 # create a frame inside the canvas which will be scrolled with it
1401 self.interior = interior = Frame(canvas)
1402 interior_id = canvas.create_window(0, 0, window=interior, anchor=NW)
1403
1404 # track changes to the canvas and frame width and sync them,
1405 # also updating the scrollbar
1406 def _configure_interior(event):
1407 # update the scrollbars to match the size of the inner frame
1408 size = (interior.winfo_reqwidth(), interior.winfo_reqheight())
1409 canvas.config(scrollregion="0 0 %s %s" % size)
Terry Jan Reedya9421fb2014-10-22 20:15:18 -04001410 interior.bind('<Configure>', _configure_interior)
1411
1412 def _configure_canvas(event):
1413 if interior.winfo_reqwidth() != canvas.winfo_width():
1414 # update the inner frame's width to fill the canvas
1415 canvas.itemconfigure(interior_id, width=canvas.winfo_width())
1416 canvas.bind('<Configure>', _configure_canvas)
1417
1418 return
1419
Terry Jan Reedya9421fb2014-10-22 20:15:18 -04001420
Steven M. Gava44d3d1a2001-07-31 06:59:02 +00001421if __name__ == '__main__':
Terry Jan Reedycfa89502014-07-14 23:07:32 -04001422 import unittest
1423 unittest.main('idlelib.idle_test.test_configdialog',
1424 verbosity=2, exit=False)
Terry Jan Reedy2e8234a2014-05-29 01:46:26 -04001425 from idlelib.idle_test.htest import run
Terry Jan Reedy47304c02015-10-20 02:15:28 -04001426 run(ConfigDialog)