blob: 579b9b3643eb60d083729430d8e94323fcf8a389 [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 Brandl6634bf22008-05-20 07:13:37 +000012from Tkinter import *
13import tkMessageBox, tkColorChooser, tkFont
Steven M. Gava44d3d1a2001-07-31 06:59:02 +000014
Florent Xiclunad630c042010-04-02 07:24:52 +000015from idlelib.configHandler import idleConf
16from idlelib.dynOptionMenuWidget import DynOptionMenu
Florent Xiclunad630c042010-04-02 07:24:52 +000017from idlelib.keybindingDialog import GetKeysDialog
18from idlelib.configSectionNameDialog import GetCfgSectionNameDialog
19from idlelib.configHelpSourceEdit import GetHelpSourceDialog
Terry Jan Reedy7a162072014-10-22 20:15:12 -040020from idlelib.tabbedpages import TabbedPageSet
Terry Jan Reedyc0a053e2015-10-11 22:07:25 -040021from idlelib.textView import view_text
Florent Xiclunad630c042010-04-02 07:24:52 +000022from idlelib import macosxSupport
Terry Jan Reedyc0a053e2015-10-11 22:07:25 -040023
Steven M. Gava44d3d1a2001-07-31 06:59:02 +000024class ConfigDialog(Toplevel):
Kurt B. Kaiseracdef852005-01-31 03:34:26 +000025
Terry Jan Reedycf834762014-10-17 01:31:29 -040026 def __init__(self, parent, title='', _htest=False, _utest=False):
Terry Jan Reedy76916e82014-05-29 01:46:16 -040027 """
28 _htest - bool, change box location when running htest
Terry Jan Reedyaf0dce92014-07-14 23:07:21 -040029 _utest - bool, don't wait_window when running unittest
Terry Jan Reedy76916e82014-05-29 01:46:16 -040030 """
Steven M. Gavad721c482001-07-31 10:46:53 +000031 Toplevel.__init__(self, parent)
Terry Jan Reedy19b7a752014-07-30 19:24:26 -040032 self.parent = parent
Terry Jan Reedyae410862014-08-03 23:02:53 -040033 if _htest:
34 parent.instance_dict = {}
Kurt B. Kaisere3fde8f2007-10-04 03:11:12 +000035 self.wm_withdraw()
36
Steven M. Gavad721c482001-07-31 10:46:53 +000037 self.configure(borderwidth=5)
Terry Jan Reedycf834762014-10-17 01:31:29 -040038 self.title(title or 'IDLE Preferences')
Terry Jan Reedyae410862014-08-03 23:02:53 -040039 self.geometry(
40 "+%d+%d" % (parent.winfo_rootx() + 20,
41 parent.winfo_rooty() + (30 if not _htest else 150)))
Georg Brandl7eb4b7d2005-07-22 21:49:32 +000042 #Theme Elements. Each theme element key is its display name.
Steven M. Gava9dd16b32001-11-03 14:54:25 +000043 #The first value of the tuple is the sample area tag name.
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +000044 #The second value is the display name list sort index.
Terry Jan Reedyae410862014-08-03 23:02:53 -040045 self.themeElements={
Terry Jan Reedyc30475e2015-10-02 22:12:09 -040046 'Normal Text': ('normal', '00'),
47 'Python Keywords': ('keyword', '01'),
48 'Python Definitions': ('definition', '02'),
49 'Python Builtins': ('builtin', '03'),
50 'Python Comments': ('comment', '04'),
51 'Python Strings': ('string', '05'),
52 'Selected Text': ('hilite', '06'),
53 'Found Text': ('hit', '07'),
54 'Cursor': ('cursor', '08'),
55 'Editor Breakpoint': ('break', '09'),
56 'Shell Normal Text': ('console', '10'),
57 'Shell Error Text': ('error', '11'),
58 'Shell Stdout Text': ('stdout', '12'),
59 'Shell Stderr Text': ('stderr', '13'),
Kurt B. Kaiser73360a32004-03-08 18:15:31 +000060 }
Steven M. Gavaa498af22002-02-01 01:33:36 +000061 self.ResetChangedItems() #load initial values in changed items dict
Steven M. Gavad721c482001-07-31 10:46:53 +000062 self.CreateWidgets()
Terry Jan Reedyae410862014-08-03 23:02:53 -040063 self.resizable(height=FALSE, width=FALSE)
Steven M. Gavad721c482001-07-31 10:46:53 +000064 self.transient(parent)
65 self.grab_set()
66 self.protocol("WM_DELETE_WINDOW", self.Cancel)
Steven M. Gava2d4e03b2001-12-05 07:54:07 +000067 self.tabPages.focus_set()
Steven M. Gavad721c482001-07-31 10:46:53 +000068 #key bindings for this dialog
Terry Jan Reedyae410862014-08-03 23:02:53 -040069 #self.bind('<Escape>', self.Cancel) #dismiss dialog, no save
70 #self.bind('<Alt-a>', self.Apply) #apply changes, save
71 #self.bind('<F1>', self.Help) #context help
Steven M. Gava429a86a2001-10-23 10:42:12 +000072 self.LoadConfigs()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +000073 self.AttachVarCallbacks() #avoid callbacks during LoadConfigs
Kurt B. Kaisere3fde8f2007-10-04 03:11:12 +000074
Terry Jan Reedyaf0dce92014-07-14 23:07:21 -040075 if not _utest:
76 self.wm_deiconify()
77 self.wait_window()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +000078
Steven M. Gavad721c482001-07-31 10:46:53 +000079 def CreateWidgets(self):
Kurt B. Kaiser20172f92007-10-30 02:38:54 +000080 self.tabPages = TabbedPageSet(self,
Terry Jan Reedy1c49ec02015-10-13 22:03:44 -040081 page_names=['Fonts/Tabs', 'Highlighting', 'Keys', 'General',
82 'Extensions'])
Terry Jan Reedy23030db2014-10-08 20:29:05 -040083 self.tabPages.pack(side=TOP, expand=TRUE, fill=BOTH)
84 self.CreatePageFontTab()
85 self.CreatePageHighlight()
86 self.CreatePageKeys()
87 self.CreatePageGeneral()
Terry Jan Reedy1c49ec02015-10-13 22:03:44 -040088 self.CreatePageExtensions()
Terry Jan Reedy23030db2014-10-08 20:29:05 -040089 self.create_action_buttons().pack(side=BOTTOM)
Terry Jan Reedyc0a053e2015-10-11 22:07:25 -040090
Terry Jan Reedy23030db2014-10-08 20:29:05 -040091 def create_action_buttons(self):
Ned Deily57847df2014-03-27 20:47:04 -070092 if macosxSupport.isAquaTk():
Ronald Oussorena97063a2009-03-04 21:35:05 +000093 # Changing the default padding on OSX results in unreadable
94 # text in the buttons
Terry Jan Reedyae410862014-08-03 23:02:53 -040095 paddingArgs = {}
Ronald Oussorena97063a2009-03-04 21:35:05 +000096 else:
Terry Jan Reedyae410862014-08-03 23:02:53 -040097 paddingArgs = {'padx':6, 'pady':3}
Terry Jan Reedy7a162072014-10-22 20:15:12 -040098 outer = Frame(self, pady=2)
99 buttons = Frame(outer, pady=2)
Terry Jan Reedyc0a053e2015-10-11 22:07:25 -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 Reedy7a162072014-10-22 20:15:12 -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 Reedyc0a053e2015-10-11 22:07:25 -0400111
Steven M. Gava60fc7072001-08-04 13:58:22 +0000112 def CreatePageFontTab(self):
Terry Jan Reedy19b7a752014-07-30 19:24:26 -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 Reedyae410862014-08-03 23:02:53 -0400118 self.editFont = tkFont.Font(parent, ('courier', 10, 'normal'))
Terry Jan Reedy19b7a752014-07-30 19:24:26 -0400119
Steven M. Gavaf213ccb2001-08-05 08:00:28 +0000120 ##widget creation
121 #body frame
Terry Jan Reedyae410862014-08-03 23:02:53 -0400122 frame = self.tabPages.pages['Fonts/Tabs'].frame
Steven M. Gavaf213ccb2001-08-05 08:00:28 +0000123 #body section frames
Terry Jan Reedyae410862014-08-03 23:02:53 -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 Reedyae410862014-08-03 23:02:53 -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 Reedyae410862014-08-03 23:02:53 -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 Reedyae410862014-08-03 23:02:53 -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 Reedy19b7a752014-07-30 19:24:26 -0400158
Steven M. Gavaf213ccb2001-08-05 08:00:28 +0000159 #widget packing
160 #body
Terry Jan Reedyae410862014-08-03 23:02:53 -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 Reedyae410862014-08-03 23:02:53 -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 Reedyae410862014-08-03 23:02:53 -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 Reedy19b7a752014-07-30 19:24:26 -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 Reedyae410862014-08-03 23:02:53 -0400192 frame = self.tabPages.pages['Highlighting'].frame
Steven M. Gava952d0a52001-08-03 04:43:44 +0000193 #body section frames
Terry Jan Reedyae410862014-08-03 23:02:53 -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 Reedyae410862014-08-03 23:02:53 -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 Reedyae410862014-08-03 23:02:53 -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 Reedyc30475e2015-10-02 22:12:09 -0400216 ('None', 'builtin'), (')\n', 'normal'),
217 (' breakpoint("line")', 'break'), ('\n\n', 'normal'),
Terry Jan Reedyae410862014-08-03 23:02:53 -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 Reedyae410862014-08-03 23:02:53 -0400224 text.insert(END, txTa[0], txTa[1])
Terry Jan Reedy110796f2014-07-27 04:07:18 -0400225 for element in self.themeElements:
Terry Jan Reedyae410862014-08-03 23:02:53 -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 Reedyae410862014-08-03 23:02:53 -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 Reedyae410862014-08-03 23:02:53 -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 Reedyae410862014-08-03 23:02:53 -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 Reedy19b7a752014-07-30 19:24:26 -0400264
Steven M. Gava952d0a52001-08-03 04:43:44 +0000265 ##widget packing
266 #body
Terry Jan Reedyae410862014-08-03 23:02:53 -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 Reedyae410862014-08-03 23:02:53 -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 Reedyae410862014-08-03 23:02:53 -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 Reedy19b7a752014-07-30 19:24:26 -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 Reedyae410862014-08-03 23:02:53 -0400299 frame = self.tabPages.pages['Keys'].frame
Steven M. Gava60fc7072001-08-04 13:58:22 +0000300 #body section frames
Terry Jan Reedyae410862014-08-03 23:02:53 -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 Reedyae410862014-08-03 23:02:53 -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 Reedyae410862014-08-03 23:02:53 -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
Kurt B. Kaiser28c7bcf2007-12-28 04:18:01 +0000322 frames = [Frame(frameKeySets, padx=2, pady=2, borderwidth=0)
323 for i in range(2)]
Terry Jan Reedyae410862014-08-03 23:02:53 -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 Reedyae410862014-08-03 23:02:53 -0400337 buttonSaveCustomKeys = Button(
338 frames[1], text='Save as New Custom Key Set',
339 command=self.SaveAsNewKeySet)
Terry Jan Reedy19b7a752014-07-30 19:24:26 -0400340
Steven M. Gava60fc7072001-08-04 13:58:22 +0000341 ##widget packing
342 #body
Terry Jan Reedyae410862014-08-03 23:02:53 -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 Reedyae410862014-08-03 23:02:53 -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 Reedyae410862014-08-03 23:02:53 -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
Kurt B. Kaiser28c7bcf2007-12-28 04:18:01 +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 Reedyae410862014-08-03 23:02:53 -0400360 self.buttonDeleteCustomKeys.pack(side=LEFT, fill=X, expand=True, padx=2)
361 buttonSaveCustomKeys.pack(side=LEFT, fill=X, expand=True, padx=2)
Kurt B. Kaiser28c7bcf2007-12-28 04:18:01 +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 Reedy19b7a752014-07-30 19:24:26 -0400367 parent = self.parent
368 self.winWidth = StringVar(parent)
369 self.winHeight = StringVar(parent)
Terry Jan Reedy19b7a752014-07-30 19:24:26 -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 Reedyae410862014-08-03 23:02:53 -0400378 frame = self.tabPages.pages['General'].frame
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000379 #body section frames
Terry Jan Reedyae410862014-08-03 23:02:53 -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 Reedyae410862014-08-03 23:02:53 -0400385 frameEncoding = Frame(frame, borderwidth=2, relief=GROOVE)
386 frameHelp = LabelFrame(frame, borderwidth=2, relief=GROOVE,
387 text=' Additional Help Sources ')
Steven M. Gava230e5782001-08-07 03:28:25 +0000388 #frameRun
Terry Jan Reedyae410862014-08-03 23:02:53 -0400389 labelRunChoiceTitle = Label(frameRun, text='At Startup')
390 radioStartupEdit = Radiobutton(
391 frameRun, variable=self.startupEdit, value=1,
392 command=self.SetKeysType, text="Open Edit Window")
393 radioStartupShell = Radiobutton(
394 frameRun, variable=self.startupEdit, value=0,
395 command=self.SetKeysType, text='Open Shell Window')
Kurt B. Kaiser6c638b62003-05-26 06:23:10 +0000396 #frameSave
Terry Jan Reedyae410862014-08-03 23:02:53 -0400397 labelRunSaveTitle = Label(frameSave, text='At Start of Run (F5) ')
398 radioSaveAsk = Radiobutton(
399 frameSave, variable=self.autoSave, value=0,
400 command=self.SetKeysType, text="Prompt to Save")
401 radioSaveAuto = Radiobutton(
402 frameSave, variable=self.autoSave, value=1,
403 command=self.SetKeysType, text='No Prompt')
Steven M. Gava230e5782001-08-07 03:28:25 +0000404 #frameWinSize
Terry Jan Reedyae410862014-08-03 23:02:53 -0400405 labelWinSizeTitle = Label(
406 frameWinSize, text='Initial Window Size (in characters)')
407 labelWinWidthTitle = Label(frameWinSize, text='Width')
408 entryWinWidth = Entry(
409 frameWinSize, textvariable=self.winWidth, width=3)
410 labelWinHeightTitle = Label(frameWinSize, text='Height')
411 entryWinHeight = Entry(
412 frameWinSize, textvariable=self.winHeight, width=3)
Kurt B. Kaisera053f332003-05-10 00:49:56 +0000413 #frameEncoding
Terry Jan Reedyae410862014-08-03 23:02:53 -0400414 labelEncodingTitle = Label(
415 frameEncoding, text="Default Source Encoding")
416 radioEncLocale = Radiobutton(
417 frameEncoding, variable=self.encoding,
418 value="locale", text="Locale-defined")
419 radioEncUTF8 = Radiobutton(
420 frameEncoding, variable=self.encoding,
421 value="utf-8", text="UTF-8")
422 radioEncNone = Radiobutton(
423 frameEncoding, variable=self.encoding,
424 value="none", text="None")
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000425 #frameHelp
Terry Jan Reedyae410862014-08-03 23:02:53 -0400426 frameHelpList = Frame(frameHelp)
427 frameHelpListButtons = Frame(frameHelpList)
428 scrollHelpList = Scrollbar(frameHelpList)
429 self.listHelp = Listbox(
430 frameHelpList, height=5, takefocus=FALSE,
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000431 exportselection=FALSE)
432 scrollHelpList.config(command=self.listHelp.yview)
433 self.listHelp.config(yscrollcommand=scrollHelpList.set)
Terry Jan Reedyae410862014-08-03 23:02:53 -0400434 self.listHelp.bind('<ButtonRelease-1>', self.HelpSourceSelected)
435 self.buttonHelpListEdit = Button(
436 frameHelpListButtons, text='Edit', state=DISABLED,
437 width=8, command=self.HelpListItemEdit)
438 self.buttonHelpListAdd = Button(
439 frameHelpListButtons, text='Add',
440 width=8, command=self.HelpListItemAdd)
441 self.buttonHelpListRemove = Button(
442 frameHelpListButtons, text='Remove', state=DISABLED,
443 width=8, command=self.HelpListItemRemove)
Terry Jan Reedy19b7a752014-07-30 19:24:26 -0400444
Steven M. Gava230e5782001-08-07 03:28:25 +0000445 #widget packing
446 #body
Terry Jan Reedyae410862014-08-03 23:02:53 -0400447 frameRun.pack(side=TOP, padx=5, pady=5, fill=X)
448 frameSave.pack(side=TOP, padx=5, pady=5, fill=X)
449 frameWinSize.pack(side=TOP, padx=5, pady=5, fill=X)
Terry Jan Reedyae410862014-08-03 23:02:53 -0400450 frameEncoding.pack(side=TOP, padx=5, pady=5, fill=X)
451 frameHelp.pack(side=TOP, padx=5, pady=5, expand=TRUE, fill=BOTH)
Steven M. Gava230e5782001-08-07 03:28:25 +0000452 #frameRun
Terry Jan Reedyae410862014-08-03 23:02:53 -0400453 labelRunChoiceTitle.pack(side=LEFT, anchor=W, padx=5, pady=5)
454 radioStartupShell.pack(side=RIGHT, anchor=W, padx=5, pady=5)
455 radioStartupEdit.pack(side=RIGHT, anchor=W, padx=5, pady=5)
Kurt B. Kaiser6c638b62003-05-26 06:23:10 +0000456 #frameSave
Terry Jan Reedyae410862014-08-03 23:02:53 -0400457 labelRunSaveTitle.pack(side=LEFT, anchor=W, padx=5, pady=5)
458 radioSaveAuto.pack(side=RIGHT, anchor=W, padx=5, pady=5)
459 radioSaveAsk.pack(side=RIGHT, anchor=W, padx=5, pady=5)
Steven M. Gava230e5782001-08-07 03:28:25 +0000460 #frameWinSize
Terry Jan Reedyae410862014-08-03 23:02:53 -0400461 labelWinSizeTitle.pack(side=LEFT, anchor=W, padx=5, pady=5)
462 entryWinHeight.pack(side=RIGHT, anchor=E, padx=10, pady=5)
463 labelWinHeightTitle.pack(side=RIGHT, anchor=E, pady=5)
464 entryWinWidth.pack(side=RIGHT, anchor=E, padx=10, pady=5)
465 labelWinWidthTitle.pack(side=RIGHT, anchor=E, pady=5)
Kurt B. Kaisera053f332003-05-10 00:49:56 +0000466 #frameEncoding
Terry Jan Reedyae410862014-08-03 23:02:53 -0400467 labelEncodingTitle.pack(side=LEFT, anchor=W, padx=5, pady=5)
468 radioEncNone.pack(side=RIGHT, anchor=E, pady=5)
469 radioEncUTF8.pack(side=RIGHT, anchor=E, pady=5)
470 radioEncLocale.pack(side=RIGHT, anchor=E, pady=5)
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000471 #frameHelp
Terry Jan Reedyae410862014-08-03 23:02:53 -0400472 frameHelpListButtons.pack(side=RIGHT, padx=5, pady=5, fill=Y)
473 frameHelpList.pack(side=TOP, padx=5, pady=5, expand=TRUE, fill=BOTH)
474 scrollHelpList.pack(side=RIGHT, anchor=W, fill=Y)
475 self.listHelp.pack(side=LEFT, anchor=E, expand=TRUE, fill=BOTH)
476 self.buttonHelpListEdit.pack(side=TOP, anchor=W, pady=5)
477 self.buttonHelpListAdd.pack(side=TOP, anchor=W)
478 self.buttonHelpListRemove.pack(side=TOP, anchor=W, pady=5)
Steven M. Gava952d0a52001-08-03 04:43:44 +0000479 return frame
480
Steven M. Gavac112cd82002-01-22 05:56:40 +0000481 def AttachVarCallbacks(self):
Terry Jan Reedy12352142015-08-01 18:57:27 -0400482 self.fontSize.trace_variable('w', self.VarChanged_font)
483 self.fontName.trace_variable('w', self.VarChanged_font)
484 self.fontBold.trace_variable('w', self.VarChanged_font)
Terry Jan Reedyae410862014-08-03 23:02:53 -0400485 self.spaceNum.trace_variable('w', self.VarChanged_spaceNum)
486 self.colour.trace_variable('w', self.VarChanged_colour)
487 self.builtinTheme.trace_variable('w', self.VarChanged_builtinTheme)
488 self.customTheme.trace_variable('w', self.VarChanged_customTheme)
489 self.themeIsBuiltin.trace_variable('w', self.VarChanged_themeIsBuiltin)
490 self.highlightTarget.trace_variable('w', self.VarChanged_highlightTarget)
491 self.keyBinding.trace_variable('w', self.VarChanged_keyBinding)
492 self.builtinKeys.trace_variable('w', self.VarChanged_builtinKeys)
493 self.customKeys.trace_variable('w', self.VarChanged_customKeys)
494 self.keysAreBuiltin.trace_variable('w', self.VarChanged_keysAreBuiltin)
495 self.winWidth.trace_variable('w', self.VarChanged_winWidth)
496 self.winHeight.trace_variable('w', self.VarChanged_winHeight)
Terry Jan Reedyae410862014-08-03 23:02:53 -0400497 self.startupEdit.trace_variable('w', self.VarChanged_startupEdit)
498 self.autoSave.trace_variable('w', self.VarChanged_autoSave)
499 self.encoding.trace_variable('w', self.VarChanged_encoding)
Steven M. Gava052937f2002-02-11 02:20:53 +0000500
Terry Jan Reedy12352142015-08-01 18:57:27 -0400501 def VarChanged_font(self, *params):
502 '''When one font attribute changes, save them all, as they are
503 not independent from each other. In particular, when we are
504 overriding the default font, we need to write out everything.
505 '''
Terry Jan Reedyae410862014-08-03 23:02:53 -0400506 value = self.fontName.get()
507 self.AddChangedItem('main', 'EditorWindow', 'font', value)
Terry Jan Reedy12352142015-08-01 18:57:27 -0400508 value = self.fontSize.get()
509 self.AddChangedItem('main', 'EditorWindow', 'font-size', value)
Terry Jan Reedyae410862014-08-03 23:02:53 -0400510 value = self.fontBold.get()
511 self.AddChangedItem('main', 'EditorWindow', 'font-bold', value)
Steven M. Gavac112cd82002-01-22 05:56:40 +0000512
Terry Jan Reedyae410862014-08-03 23:02:53 -0400513 def VarChanged_spaceNum(self, *params):
514 value = self.spaceNum.get()
515 self.AddChangedItem('main', 'Indent', 'num-spaces', value)
Steven M. Gavac112cd82002-01-22 05:56:40 +0000516
Terry Jan Reedyae410862014-08-03 23:02:53 -0400517 def VarChanged_colour(self, *params):
Steven M. Gava052937f2002-02-11 02:20:53 +0000518 self.OnNewColourSet()
519
Terry Jan Reedyae410862014-08-03 23:02:53 -0400520 def VarChanged_builtinTheme(self, *params):
521 value = self.builtinTheme.get()
Terry Jan Reedy9f37eae2015-10-04 00:30:59 -0400522 if value == 'IDLE Dark':
523 tkMessageBox.showwarning(
524 title="The 'IDLE Dark' Text Color Theme",
525 message="IDLE Dark is new in October, 2015. Trying to "
526 "run earlier versions of IDLE with it selected "
527 "will disable colorizing, or worse.\n\n"
528 "If you might ever run an earlier release of IDLE, "
529 "then before exiting this version, "
530 "either switch to another theme or "
531 "hit the 'Save as New Custom Theme' button. "
532 "The latter requires a new name, such as "
533 "'Custom Dark', but the custom theme will work "
534 "with any IDLE release, and can be modified.",
535 parent=self)
Terry Jan Reedyae410862014-08-03 23:02:53 -0400536 self.AddChangedItem('main', 'Theme', 'name', value)
Steven M. Gava052937f2002-02-11 02:20:53 +0000537 self.PaintThemeSample()
538
Terry Jan Reedyae410862014-08-03 23:02:53 -0400539 def VarChanged_customTheme(self, *params):
540 value = self.customTheme.get()
Steven M. Gava49745752002-02-18 01:43:11 +0000541 if value != '- no custom themes -':
Terry Jan Reedyae410862014-08-03 23:02:53 -0400542 self.AddChangedItem('main', 'Theme', 'name', value)
Steven M. Gava49745752002-02-18 01:43:11 +0000543 self.PaintThemeSample()
Steven M. Gava052937f2002-02-11 02:20:53 +0000544
Terry Jan Reedyae410862014-08-03 23:02:53 -0400545 def VarChanged_themeIsBuiltin(self, *params):
546 value = self.themeIsBuiltin.get()
547 self.AddChangedItem('main', 'Theme', 'default', value)
Steven M. Gavaf31eec02002-03-05 00:25:58 +0000548 if value:
549 self.VarChanged_builtinTheme()
550 else:
551 self.VarChanged_customTheme()
Steven M. Gava052937f2002-02-11 02:20:53 +0000552
Terry Jan Reedyae410862014-08-03 23:02:53 -0400553 def VarChanged_highlightTarget(self, *params):
Steven M. Gava052937f2002-02-11 02:20:53 +0000554 self.SetHighlightTarget()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000555
Terry Jan Reedyae410862014-08-03 23:02:53 -0400556 def VarChanged_keyBinding(self, *params):
557 value = self.keyBinding.get()
558 keySet = self.customKeys.get()
559 event = self.listBindings.get(ANCHOR).split()[0]
Steven M. Gavaa498af22002-02-01 01:33:36 +0000560 if idleConf.IsCoreBinding(event):
561 #this is a core keybinding
Terry Jan Reedyae410862014-08-03 23:02:53 -0400562 self.AddChangedItem('keys', keySet, event, value)
Steven M. Gavaa498af22002-02-01 01:33:36 +0000563 else: #this is an extension key binding
Terry Jan Reedyae410862014-08-03 23:02:53 -0400564 extName = idleConf.GetExtnNameForEvent(event)
565 extKeybindSection = extName + '_cfgBindings'
566 self.AddChangedItem('extensions', extKeybindSection, event, value)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000567
Terry Jan Reedyae410862014-08-03 23:02:53 -0400568 def VarChanged_builtinKeys(self, *params):
569 value = self.builtinKeys.get()
570 self.AddChangedItem('main', 'Keys', 'name', value)
Steven M. Gava052937f2002-02-11 02:20:53 +0000571 self.LoadKeysList(value)
572
Terry Jan Reedyae410862014-08-03 23:02:53 -0400573 def VarChanged_customKeys(self, *params):
574 value = self.customKeys.get()
Steven M. Gava49745752002-02-18 01:43:11 +0000575 if value != '- no custom keys -':
Terry Jan Reedyae410862014-08-03 23:02:53 -0400576 self.AddChangedItem('main', 'Keys', 'name', value)
Steven M. Gava49745752002-02-18 01:43:11 +0000577 self.LoadKeysList(value)
Steven M. Gava052937f2002-02-11 02:20:53 +0000578
Terry Jan Reedyae410862014-08-03 23:02:53 -0400579 def VarChanged_keysAreBuiltin(self, *params):
580 value = self.keysAreBuiltin.get()
581 self.AddChangedItem('main', 'Keys', 'default', value)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000582 if value:
Steven M. Gavaf31eec02002-03-05 00:25:58 +0000583 self.VarChanged_builtinKeys()
Steven M. Gava052937f2002-02-11 02:20:53 +0000584 else:
Steven M. Gavaf31eec02002-03-05 00:25:58 +0000585 self.VarChanged_customKeys()
Steven M. Gava052937f2002-02-11 02:20:53 +0000586
Terry Jan Reedyae410862014-08-03 23:02:53 -0400587 def VarChanged_winWidth(self, *params):
588 value = self.winWidth.get()
589 self.AddChangedItem('main', 'EditorWindow', 'width', value)
Steven M. Gavac112cd82002-01-22 05:56:40 +0000590
Terry Jan Reedyae410862014-08-03 23:02:53 -0400591 def VarChanged_winHeight(self, *params):
592 value = self.winHeight.get()
593 self.AddChangedItem('main', 'EditorWindow', 'height', value)
Steven M. Gavac112cd82002-01-22 05:56:40 +0000594
Terry Jan Reedyae410862014-08-03 23:02:53 -0400595 def VarChanged_startupEdit(self, *params):
596 value = self.startupEdit.get()
597 self.AddChangedItem('main', 'General', 'editor-on-startup', value)
Steven M. Gavac112cd82002-01-22 05:56:40 +0000598
Terry Jan Reedyae410862014-08-03 23:02:53 -0400599 def VarChanged_autoSave(self, *params):
600 value = self.autoSave.get()
601 self.AddChangedItem('main', 'General', 'autosave', value)
Kurt B. Kaiser6c638b62003-05-26 06:23:10 +0000602
Terry Jan Reedyae410862014-08-03 23:02:53 -0400603 def VarChanged_encoding(self, *params):
604 value = self.encoding.get()
605 self.AddChangedItem('main', 'EditorWindow', 'encoding', value)
Kurt B. Kaisera053f332003-05-10 00:49:56 +0000606
Steven M. Gavaa498af22002-02-01 01:33:36 +0000607 def ResetChangedItems(self):
Steven M. Gavab77d3432002-03-02 07:16:21 +0000608 #When any config item is changed in this dialog, an entry
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000609 #should be made in the relevant section (config type) of this
610 #dictionary. The key should be the config file section name and the
Steven M. Gavaa498af22002-02-01 01:33:36 +0000611 #value a dictionary, whose key:value pairs are item=value pairs for
612 #that config file section.
Terry Jan Reedyae410862014-08-03 23:02:53 -0400613 self.changedItems = {'main':{}, 'highlight':{}, 'keys':{},
614 'extensions':{}}
Steven M. Gavaa498af22002-02-01 01:33:36 +0000615
Terry Jan Reedyae410862014-08-03 23:02:53 -0400616 def AddChangedItem(self, typ, section, item, value):
617 value = str(value) #make sure we use a string
618 if section not in self.changedItems[typ]:
619 self.changedItems[typ][section] = {}
620 self.changedItems[typ][section][item] = value
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000621
Steven M. Gava5f28e8f2002-01-21 06:38:21 +0000622 def GetDefaultItems(self):
Terry Jan Reedyae410862014-08-03 23:02:53 -0400623 dItems={'main':{}, 'highlight':{}, 'keys':{}, 'extensions':{}}
Terry Jan Reedy110796f2014-07-27 04:07:18 -0400624 for configType in dItems:
Terry Jan Reedyae410862014-08-03 23:02:53 -0400625 sections = idleConf.GetSectionList('default', configType)
Steven M. Gava5f28e8f2002-01-21 06:38:21 +0000626 for section in sections:
Terry Jan Reedyae410862014-08-03 23:02:53 -0400627 dItems[configType][section] = {}
628 options = idleConf.defaultCfg[configType].GetOptionList(section)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000629 for option in options:
Terry Jan Reedyae410862014-08-03 23:02:53 -0400630 dItems[configType][section][option] = (
631 idleConf.defaultCfg[configType].Get(section, option))
Steven M. Gava5f28e8f2002-01-21 06:38:21 +0000632 return dItems
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000633
Steven M. Gava5f28e8f2002-01-21 06:38:21 +0000634 def SetThemeType(self):
635 if self.themeIsBuiltin.get():
636 self.optMenuThemeBuiltin.config(state=NORMAL)
637 self.optMenuThemeCustom.config(state=DISABLED)
638 self.buttonDeleteCustomTheme.config(state=DISABLED)
639 else:
640 self.optMenuThemeBuiltin.config(state=DISABLED)
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000641 self.radioThemeCustom.config(state=NORMAL)
Steven M. Gava5f28e8f2002-01-21 06:38:21 +0000642 self.optMenuThemeCustom.config(state=NORMAL)
643 self.buttonDeleteCustomTheme.config(state=NORMAL)
644
645 def SetKeysType(self):
Steven M. Gava052937f2002-02-11 02:20:53 +0000646 if self.keysAreBuiltin.get():
Steven M. Gava5f28e8f2002-01-21 06:38:21 +0000647 self.optMenuKeysBuiltin.config(state=NORMAL)
648 self.optMenuKeysCustom.config(state=DISABLED)
649 self.buttonDeleteCustomKeys.config(state=DISABLED)
650 else:
651 self.optMenuKeysBuiltin.config(state=DISABLED)
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000652 self.radioKeysCustom.config(state=NORMAL)
Steven M. Gava5f28e8f2002-01-21 06:38:21 +0000653 self.optMenuKeysCustom.config(state=NORMAL)
654 self.buttonDeleteCustomKeys.config(state=NORMAL)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000655
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000656 def GetNewKeys(self):
Terry Jan Reedyae410862014-08-03 23:02:53 -0400657 listIndex = self.listBindings.index(ANCHOR)
658 binding = self.listBindings.get(listIndex)
659 bindName = binding.split()[0] #first part, up to first space
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000660 if self.keysAreBuiltin.get():
Terry Jan Reedyae410862014-08-03 23:02:53 -0400661 currentKeySetName = self.builtinKeys.get()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000662 else:
Terry Jan Reedyae410862014-08-03 23:02:53 -0400663 currentKeySetName = self.customKeys.get()
664 currentBindings = idleConf.GetCurrentKeySet()
Terry Jan Reedy110796f2014-07-27 04:07:18 -0400665 if currentKeySetName in self.changedItems['keys']: #unsaved changes
Terry Jan Reedyae410862014-08-03 23:02:53 -0400666 keySetChanges = self.changedItems['keys'][currentKeySetName]
Terry Jan Reedy110796f2014-07-27 04:07:18 -0400667 for event in keySetChanges:
Terry Jan Reedyae410862014-08-03 23:02:53 -0400668 currentBindings[event] = keySetChanges[event].split()
669 currentKeySequences = currentBindings.values()
670 newKeys = GetKeysDialog(self, 'Get New Keys', bindName,
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000671 currentKeySequences).result
672 if newKeys: #new keys were specified
Steven M. Gava052937f2002-02-11 02:20:53 +0000673 if self.keysAreBuiltin.get(): #current key set is a built-in
Terry Jan Reedyae410862014-08-03 23:02:53 -0400674 message = ('Your changes will be saved as a new Custom Key Set.'
675 ' Enter a name for your new Custom Key Set below.')
676 newKeySet = self.GetNewKeysName(message)
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000677 if not newKeySet: #user cancelled custom key set creation
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000678 self.listBindings.select_set(listIndex)
679 self.listBindings.select_anchor(listIndex)
680 return
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000681 else: #create new custom key set based on previously active key set
682 self.CreateNewKeySet(newKeySet)
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000683 self.listBindings.delete(listIndex)
Terry Jan Reedyae410862014-08-03 23:02:53 -0400684 self.listBindings.insert(listIndex, bindName+' - '+newKeys)
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000685 self.listBindings.select_set(listIndex)
686 self.listBindings.select_anchor(listIndex)
Steven M. Gava052937f2002-02-11 02:20:53 +0000687 self.keyBinding.set(newKeys)
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000688 else:
689 self.listBindings.select_set(listIndex)
690 self.listBindings.select_anchor(listIndex)
691
Terry Jan Reedyae410862014-08-03 23:02:53 -0400692 def GetNewKeysName(self, message):
693 usedNames = (idleConf.GetSectionList('user', 'keys') +
694 idleConf.GetSectionList('default', 'keys'))
695 newKeySet = GetCfgSectionNameDialog(
696 self, 'New Custom Key Set', message, usedNames).result
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000697 return newKeySet
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000698
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000699 def SaveAsNewKeySet(self):
Terry Jan Reedyae410862014-08-03 23:02:53 -0400700 newKeysName = self.GetNewKeysName('New Key Set Name:')
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000701 if newKeysName:
702 self.CreateNewKeySet(newKeysName)
703
Terry Jan Reedyae410862014-08-03 23:02:53 -0400704 def KeyBindingSelected(self, event):
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000705 self.buttonNewKeys.config(state=NORMAL)
706
Terry Jan Reedyae410862014-08-03 23:02:53 -0400707 def CreateNewKeySet(self, newKeySetName):
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000708 #creates new custom key set based on the previously active key set,
709 #and makes the new key set active
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000710 if self.keysAreBuiltin.get():
Terry Jan Reedyae410862014-08-03 23:02:53 -0400711 prevKeySetName = self.builtinKeys.get()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000712 else:
Terry Jan Reedyae410862014-08-03 23:02:53 -0400713 prevKeySetName = self.customKeys.get()
714 prevKeys = idleConf.GetCoreKeys(prevKeySetName)
715 newKeys = {}
Terry Jan Reedy110796f2014-07-27 04:07:18 -0400716 for event in prevKeys: #add key set to changed items
Terry Jan Reedyae410862014-08-03 23:02:53 -0400717 eventName = event[2:-2] #trim off the angle brackets
718 binding = ' '.join(prevKeys[event])
719 newKeys[eventName] = binding
Steven M. Gava052937f2002-02-11 02:20:53 +0000720 #handle any unsaved changes to prev key set
Terry Jan Reedy110796f2014-07-27 04:07:18 -0400721 if prevKeySetName in self.changedItems['keys']:
Terry Jan Reedyae410862014-08-03 23:02:53 -0400722 keySetChanges = self.changedItems['keys'][prevKeySetName]
Terry Jan Reedy110796f2014-07-27 04:07:18 -0400723 for event in keySetChanges:
Terry Jan Reedyae410862014-08-03 23:02:53 -0400724 newKeys[event] = keySetChanges[event]
Steven M. Gava052937f2002-02-11 02:20:53 +0000725 #save the new theme
Terry Jan Reedyae410862014-08-03 23:02:53 -0400726 self.SaveNewKeySet(newKeySetName, newKeys)
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000727 #change gui over to the new key set
Terry Jan Reedyae410862014-08-03 23:02:53 -0400728 customKeyList = idleConf.GetSectionList('user', 'keys')
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000729 customKeyList.sort()
Terry Jan Reedyae410862014-08-03 23:02:53 -0400730 self.optMenuKeysCustom.SetMenu(customKeyList, newKeySetName)
Steven M. Gava052937f2002-02-11 02:20:53 +0000731 self.keysAreBuiltin.set(0)
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000732 self.SetKeysType()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000733
Terry Jan Reedyae410862014-08-03 23:02:53 -0400734 def LoadKeysList(self, keySetName):
735 reselect = 0
736 newKeySet = 0
Steven M. Gava052937f2002-02-11 02:20:53 +0000737 if self.listBindings.curselection():
Terry Jan Reedyae410862014-08-03 23:02:53 -0400738 reselect = 1
739 listIndex = self.listBindings.index(ANCHOR)
740 keySet = idleConf.GetKeySet(keySetName)
741 bindNames = keySet.keys()
Steven M. Gava052937f2002-02-11 02:20:53 +0000742 bindNames.sort()
Terry Jan Reedyae410862014-08-03 23:02:53 -0400743 self.listBindings.delete(0, END)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000744 for bindName in bindNames:
Terry Jan Reedyae410862014-08-03 23:02:53 -0400745 key = ' '.join(keySet[bindName]) #make key(s) into a string
746 bindName = bindName[2:-2] #trim off the angle brackets
Terry Jan Reedy110796f2014-07-27 04:07:18 -0400747 if keySetName in self.changedItems['keys']:
Steven M. Gava052937f2002-02-11 02:20:53 +0000748 #handle any unsaved changes to this key set
Terry Jan Reedy110796f2014-07-27 04:07:18 -0400749 if bindName in self.changedItems['keys'][keySetName]:
Terry Jan Reedyae410862014-08-03 23:02:53 -0400750 key = self.changedItems['keys'][keySetName][bindName]
Steven M. Gava052937f2002-02-11 02:20:53 +0000751 self.listBindings.insert(END, bindName+' - '+key)
Steven M. Gava052937f2002-02-11 02:20:53 +0000752 if reselect:
753 self.listBindings.see(listIndex)
754 self.listBindings.select_set(listIndex)
755 self.listBindings.select_anchor(listIndex)
756
Steven M. Gava49745752002-02-18 01:43:11 +0000757 def DeleteCustomKeys(self):
758 keySetName=self.customKeys.get()
Terry Jan Reedyae410862014-08-03 23:02:53 -0400759 delmsg = 'Are you sure you wish to delete the key set %r ?'
760 if not tkMessageBox.askyesno(
761 'Delete Key Set', delmsg % keySetName, parent=self):
Steven M. Gava49745752002-02-18 01:43:11 +0000762 return
763 #remove key set from config
764 idleConf.userCfg['keys'].remove_section(keySetName)
Benjamin Peterson6e3dbbd2009-10-09 22:15:50 +0000765 if keySetName in self.changedItems['keys']:
Steven M. Gava49745752002-02-18 01:43:11 +0000766 del(self.changedItems['keys'][keySetName])
767 #write changes
768 idleConf.userCfg['keys'].Save()
769 #reload user key set list
Terry Jan Reedyae410862014-08-03 23:02:53 -0400770 itemList = idleConf.GetSectionList('user', 'keys')
Steven M. Gava49745752002-02-18 01:43:11 +0000771 itemList.sort()
772 if not itemList:
773 self.radioKeysCustom.config(state=DISABLED)
Terry Jan Reedyae410862014-08-03 23:02:53 -0400774 self.optMenuKeysCustom.SetMenu(itemList, '- no custom keys -')
Steven M. Gava49745752002-02-18 01:43:11 +0000775 else:
Terry Jan Reedyae410862014-08-03 23:02:53 -0400776 self.optMenuKeysCustom.SetMenu(itemList, itemList[0])
Steven M. Gava49745752002-02-18 01:43:11 +0000777 #revert to default key set
Terry Jan Reedyae410862014-08-03 23:02:53 -0400778 self.keysAreBuiltin.set(idleConf.defaultCfg['main'].Get('Keys', 'default'))
779 self.builtinKeys.set(idleConf.defaultCfg['main'].Get('Keys', 'name'))
Steven M. Gava49745752002-02-18 01:43:11 +0000780 #user can't back out of these changes, they must be applied now
781 self.Apply()
782 self.SetKeysType()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000783
Steven M. Gava49745752002-02-18 01:43:11 +0000784 def DeleteCustomTheme(self):
Terry Jan Reedyae410862014-08-03 23:02:53 -0400785 themeName = self.customTheme.get()
786 delmsg = 'Are you sure you wish to delete the theme %r ?'
787 if not tkMessageBox.askyesno(
788 'Delete Theme', delmsg % themeName, parent=self):
Steven M. Gava49745752002-02-18 01:43:11 +0000789 return
790 #remove theme from config
791 idleConf.userCfg['highlight'].remove_section(themeName)
Benjamin Peterson6e3dbbd2009-10-09 22:15:50 +0000792 if themeName in self.changedItems['highlight']:
Steven M. Gava49745752002-02-18 01:43:11 +0000793 del(self.changedItems['highlight'][themeName])
794 #write changes
795 idleConf.userCfg['highlight'].Save()
796 #reload user theme list
Terry Jan Reedyae410862014-08-03 23:02:53 -0400797 itemList = idleConf.GetSectionList('user', 'highlight')
Steven M. Gava49745752002-02-18 01:43:11 +0000798 itemList.sort()
799 if not itemList:
800 self.radioThemeCustom.config(state=DISABLED)
Terry Jan Reedyae410862014-08-03 23:02:53 -0400801 self.optMenuThemeCustom.SetMenu(itemList, '- no custom themes -')
Steven M. Gava49745752002-02-18 01:43:11 +0000802 else:
Terry Jan Reedyae410862014-08-03 23:02:53 -0400803 self.optMenuThemeCustom.SetMenu(itemList, itemList[0])
Steven M. Gava49745752002-02-18 01:43:11 +0000804 #revert to default theme
Terry Jan Reedyae410862014-08-03 23:02:53 -0400805 self.themeIsBuiltin.set(idleConf.defaultCfg['main'].Get('Theme', 'default'))
806 self.builtinTheme.set(idleConf.defaultCfg['main'].Get('Theme', 'name'))
Steven M. Gava49745752002-02-18 01:43:11 +0000807 #user can't back out of these changes, they must be applied now
808 self.Apply()
809 self.SetThemeType()
810
Steven M. Gava5f28e8f2002-01-21 06:38:21 +0000811 def GetColour(self):
Terry Jan Reedyae410862014-08-03 23:02:53 -0400812 target = self.highlightTarget.get()
813 prevColour = self.frameColourSet.cget('bg')
814 rgbTuplet, colourString = tkColorChooser.askcolor(
815 parent=self, title='Pick new colour for : '+target,
816 initialcolor=prevColour)
817 if colourString and (colourString != prevColour):
Steven M. Gava052937f2002-02-11 02:20:53 +0000818 #user didn't cancel, and they chose a new colour
Terry Jan Reedyae410862014-08-03 23:02:53 -0400819 if self.themeIsBuiltin.get(): #current theme is a built-in
820 message = ('Your changes will be saved as a new Custom Theme. '
821 'Enter a name for your new Custom Theme below.')
822 newTheme = self.GetNewThemeName(message)
823 if not newTheme: #user cancelled custom theme creation
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000824 return
Terry Jan Reedyae410862014-08-03 23:02:53 -0400825 else: #create new custom theme based on previously active theme
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000826 self.CreateNewTheme(newTheme)
Steven M. Gava052937f2002-02-11 02:20:53 +0000827 self.colour.set(colourString)
Terry Jan Reedyae410862014-08-03 23:02:53 -0400828 else: #current theme is user defined
Steven M. Gava052937f2002-02-11 02:20:53 +0000829 self.colour.set(colourString)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000830
Steven M. Gava052937f2002-02-11 02:20:53 +0000831 def OnNewColourSet(self):
832 newColour=self.colour.get()
Terry Jan Reedyae410862014-08-03 23:02:53 -0400833 self.frameColourSet.config(bg=newColour) #set sample
834 plane ='foreground' if self.fgHilite.get() else 'background'
835 sampleElement = self.themeElements[self.highlightTarget.get()][0]
Raymond Hettinger931237e2003-07-09 18:48:24 +0000836 self.textHighlightSample.tag_config(sampleElement, **{plane:newColour})
Terry Jan Reedyae410862014-08-03 23:02:53 -0400837 theme = self.customTheme.get()
838 themeElement = sampleElement + '-' + plane
839 self.AddChangedItem('highlight', theme, themeElement, newColour)
Steven M. Gava052937f2002-02-11 02:20:53 +0000840
Terry Jan Reedyae410862014-08-03 23:02:53 -0400841 def GetNewThemeName(self, message):
842 usedNames = (idleConf.GetSectionList('user', 'highlight') +
843 idleConf.GetSectionList('default', 'highlight'))
844 newTheme = GetCfgSectionNameDialog(
845 self, 'New Custom Theme', message, usedNames).result
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000846 return newTheme
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000847
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000848 def SaveAsNewTheme(self):
Terry Jan Reedyae410862014-08-03 23:02:53 -0400849 newThemeName = self.GetNewThemeName('New Theme Name:')
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000850 if newThemeName:
851 self.CreateNewTheme(newThemeName)
852
Terry Jan Reedyae410862014-08-03 23:02:53 -0400853 def CreateNewTheme(self, newThemeName):
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000854 #creates new custom theme based on the previously active theme,
855 #and makes the new theme active
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000856 if self.themeIsBuiltin.get():
Terry Jan Reedyae410862014-08-03 23:02:53 -0400857 themeType = 'default'
858 themeName = self.builtinTheme.get()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000859 else:
Terry Jan Reedyae410862014-08-03 23:02:53 -0400860 themeType = 'user'
861 themeName = self.customTheme.get()
862 newTheme = idleConf.GetThemeDict(themeType, themeName)
Steven M. Gava052937f2002-02-11 02:20:53 +0000863 #apply any of the old theme's unsaved changes to the new theme
Terry Jan Reedy110796f2014-07-27 04:07:18 -0400864 if themeName in self.changedItems['highlight']:
Terry Jan Reedyae410862014-08-03 23:02:53 -0400865 themeChanges = self.changedItems['highlight'][themeName]
Terry Jan Reedy110796f2014-07-27 04:07:18 -0400866 for element in themeChanges:
Terry Jan Reedyae410862014-08-03 23:02:53 -0400867 newTheme[element] = themeChanges[element]
Steven M. Gava052937f2002-02-11 02:20:53 +0000868 #save the new theme
Terry Jan Reedyae410862014-08-03 23:02:53 -0400869 self.SaveNewTheme(newThemeName, newTheme)
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000870 #change gui over to the new theme
Terry Jan Reedyae410862014-08-03 23:02:53 -0400871 customThemeList = idleConf.GetSectionList('user', 'highlight')
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000872 customThemeList.sort()
Terry Jan Reedyae410862014-08-03 23:02:53 -0400873 self.optMenuThemeCustom.SetMenu(customThemeList, newThemeName)
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000874 self.themeIsBuiltin.set(0)
875 self.SetThemeType()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000876
Terry Jan Reedyae410862014-08-03 23:02:53 -0400877 def OnListFontButtonRelease(self, event):
Kurt B. Kaiser05391692003-05-26 20:35:53 +0000878 font = self.listFontName.get(ANCHOR)
879 self.fontName.set(font.lower())
Steven M. Gava5f28e8f2002-01-21 06:38:21 +0000880 self.SetFontSample()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000881
Terry Jan Reedyae410862014-08-03 23:02:53 -0400882 def SetFontSample(self, event=None):
883 fontName = self.fontName.get()
884 fontWeight = tkFont.BOLD if self.fontBold.get() else tkFont.NORMAL
Ned Deilye3d47122012-10-22 15:13:01 -0700885 newFont = (fontName, self.fontSize.get(), fontWeight)
886 self.labelFontSample.config(font=newFont)
887 self.textHighlightSample.configure(font=newFont)
Steven M. Gava5f28e8f2002-01-21 06:38:21 +0000888
Steven M. Gava5f28e8f2002-01-21 06:38:21 +0000889 def SetHighlightTarget(self):
Terry Jan Reedyae410862014-08-03 23:02:53 -0400890 if self.highlightTarget.get() == 'Cursor': #bg not possible
Steven M. Gava5f28e8f2002-01-21 06:38:21 +0000891 self.radioFg.config(state=DISABLED)
892 self.radioBg.config(state=DISABLED)
893 self.fgHilite.set(1)
Terry Jan Reedyae410862014-08-03 23:02:53 -0400894 else: #both fg and bg can be set
Steven M. Gava5f28e8f2002-01-21 06:38:21 +0000895 self.radioFg.config(state=NORMAL)
896 self.radioBg.config(state=NORMAL)
897 self.fgHilite.set(1)
898 self.SetColourSample()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000899
Terry Jan Reedyae410862014-08-03 23:02:53 -0400900 def SetColourSampleBinding(self, *args):
Steven M. Gava5f28e8f2002-01-21 06:38:21 +0000901 self.SetColourSample()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000902
Steven M. Gava5f28e8f2002-01-21 06:38:21 +0000903 def SetColourSample(self):
904 #set the colour smaple area
Terry Jan Reedyae410862014-08-03 23:02:53 -0400905 tag = self.themeElements[self.highlightTarget.get()][0]
906 plane = 'foreground' if self.fgHilite.get() else 'background'
907 colour = self.textHighlightSample.tag_cget(tag, plane)
Steven M. Gava5f28e8f2002-01-21 06:38:21 +0000908 self.frameColourSet.config(bg=colour)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000909
Steven M. Gava9dd16b32001-11-03 14:54:25 +0000910 def PaintThemeSample(self):
Terry Jan Reedyae410862014-08-03 23:02:53 -0400911 if self.themeIsBuiltin.get(): #a default theme
912 theme = self.builtinTheme.get()
913 else: #a user theme
914 theme = self.customTheme.get()
Terry Jan Reedy110796f2014-07-27 04:07:18 -0400915 for elementTitle in self.themeElements:
Terry Jan Reedyae410862014-08-03 23:02:53 -0400916 element = self.themeElements[elementTitle][0]
917 colours = idleConf.GetHighlight(theme, element)
918 if element == 'cursor': #cursor sample needs special painting
919 colours['background'] = idleConf.GetHighlight(
920 theme, 'normal', fgBg='bg')
Steven M. Gava052937f2002-02-11 02:20:53 +0000921 #handle any unsaved changes to this theme
Terry Jan Reedy110796f2014-07-27 04:07:18 -0400922 if theme in self.changedItems['highlight']:
Terry Jan Reedyae410862014-08-03 23:02:53 -0400923 themeDict = self.changedItems['highlight'][theme]
924 if element + '-foreground' in themeDict:
925 colours['foreground'] = themeDict[element + '-foreground']
926 if element + '-background' in themeDict:
927 colours['background'] = themeDict[element + '-background']
Raymond Hettinger931237e2003-07-09 18:48:24 +0000928 self.textHighlightSample.tag_config(element, **colours)
Steven M. Gava052937f2002-02-11 02:20:53 +0000929 self.SetColourSample()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000930
Terry Jan Reedyae410862014-08-03 23:02:53 -0400931 def HelpSourceSelected(self, event):
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000932 self.SetHelpListButtonStates()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000933
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000934 def SetHelpListButtonStates(self):
Terry Jan Reedyae410862014-08-03 23:02:53 -0400935 if self.listHelp.size() < 1: #no entries in list
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000936 self.buttonHelpListEdit.config(state=DISABLED)
937 self.buttonHelpListRemove.config(state=DISABLED)
938 else: #there are some entries
Terry Jan Reedyae410862014-08-03 23:02:53 -0400939 if self.listHelp.curselection(): #there currently is a selection
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000940 self.buttonHelpListEdit.config(state=NORMAL)
941 self.buttonHelpListRemove.config(state=NORMAL)
942 else: #there currently is not a selection
943 self.buttonHelpListEdit.config(state=DISABLED)
944 self.buttonHelpListRemove.config(state=DISABLED)
945
946 def HelpListItemAdd(self):
Terry Jan Reedyae410862014-08-03 23:02:53 -0400947 helpSource = GetHelpSourceDialog(self, 'New Help Source').result
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000948 if helpSource:
Terry Jan Reedyae410862014-08-03 23:02:53 -0400949 self.userHelpList.append((helpSource[0], helpSource[1]))
950 self.listHelp.insert(END, helpSource[0])
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000951 self.UpdateUserHelpChangedItems()
952 self.SetHelpListButtonStates()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000953
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000954 def HelpListItemEdit(self):
Terry Jan Reedyae410862014-08-03 23:02:53 -0400955 itemIndex = self.listHelp.index(ANCHOR)
956 helpSource = self.userHelpList[itemIndex]
957 newHelpSource = GetHelpSourceDialog(
958 self, 'Edit Help Source', menuItem=helpSource[0],
959 filePath=helpSource[1]).result
960 if (not newHelpSource) or (newHelpSource == helpSource):
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000961 return #no changes
Terry Jan Reedyae410862014-08-03 23:02:53 -0400962 self.userHelpList[itemIndex] = newHelpSource
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000963 self.listHelp.delete(itemIndex)
Terry Jan Reedyae410862014-08-03 23:02:53 -0400964 self.listHelp.insert(itemIndex, newHelpSource[0])
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000965 self.UpdateUserHelpChangedItems()
966 self.SetHelpListButtonStates()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000967
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000968 def HelpListItemRemove(self):
Terry Jan Reedyae410862014-08-03 23:02:53 -0400969 itemIndex = self.listHelp.index(ANCHOR)
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000970 del(self.userHelpList[itemIndex])
971 self.listHelp.delete(itemIndex)
972 self.UpdateUserHelpChangedItems()
973 self.SetHelpListButtonStates()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000974
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000975 def UpdateUserHelpChangedItems(self):
Kurt B. Kaiser8e92bf72003-01-14 22:03:31 +0000976 "Clear and rebuild the HelpFiles section in self.changedItems"
977 self.changedItems['main']['HelpFiles'] = {}
Terry Jan Reedyae410862014-08-03 23:02:53 -0400978 for num in range(1, len(self.userHelpList) + 1):
979 self.AddChangedItem(
980 'main', 'HelpFiles', str(num),
Terry Jan Reedy110796f2014-07-27 04:07:18 -0400981 ';'.join(self.userHelpList[num-1][:2]))
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000982
Steven M. Gava429a86a2001-10-23 10:42:12 +0000983 def LoadFontCfg(self):
984 ##base editor font selection list
Terry Jan Reedyae410862014-08-03 23:02:53 -0400985 fonts = list(tkFont.families(self))
Steven M. Gavac11ccf32001-09-24 09:43:17 +0000986 fonts.sort()
987 for font in fonts:
Terry Jan Reedyae410862014-08-03 23:02:53 -0400988 self.listFontName.insert(END, font)
Terry Jan Reedy12352142015-08-01 18:57:27 -0400989 configuredFont = idleConf.GetFont(self, 'main', 'EditorWindow')
990 fontName = configuredFont[0].lower()
991 fontSize = configuredFont[1]
992 fontBold = configuredFont[2]=='bold'
993 self.fontName.set(fontName)
Kurt B. Kaiser05391692003-05-26 20:35:53 +0000994 lc_fonts = [s.lower() for s in fonts]
Terry Jan Reedy12352142015-08-01 18:57:27 -0400995 try:
996 currentFontIndex = lc_fonts.index(fontName)
Steven M. Gava429a86a2001-10-23 10:42:12 +0000997 self.listFontName.see(currentFontIndex)
998 self.listFontName.select_set(currentFontIndex)
Steven M. Gavac112cd82002-01-22 05:56:40 +0000999 self.listFontName.select_anchor(currentFontIndex)
Terry Jan Reedy12352142015-08-01 18:57:27 -04001000 except ValueError:
1001 pass
Steven M. Gava429a86a2001-10-23 10:42:12 +00001002 ##font size dropdown
Terry Jan Reedyae410862014-08-03 23:02:53 -04001003 self.optMenuFontSize.SetMenu(('7', '8', '9', '10', '11', '12', '13',
1004 '14', '16', '18', '20', '22'), fontSize )
Steven M. Gavac112cd82002-01-22 05:56:40 +00001005 ##fontWeight
Terry Jan Reedy12352142015-08-01 18:57:27 -04001006 self.fontBold.set(fontBold)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001007 ##font sample
Steven M. Gava429a86a2001-10-23 10:42:12 +00001008 self.SetFontSample()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001009
Steven M. Gava429a86a2001-10-23 10:42:12 +00001010 def LoadTabCfg(self):
Steven M. Gava429a86a2001-10-23 10:42:12 +00001011 ##indent sizes
Terry Jan Reedyae410862014-08-03 23:02:53 -04001012 spaceNum = idleConf.GetOption(
1013 'main', 'Indent', 'num-spaces', default=4, type='int')
Steven M. Gava429a86a2001-10-23 10:42:12 +00001014 self.spaceNum.set(spaceNum)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001015
Steven M. Gava9dd16b32001-11-03 14:54:25 +00001016 def LoadThemeCfg(self):
Steven M. Gava41a85322001-10-29 08:05:34 +00001017 ##current theme type radiobutton
Terry Jan Reedyae410862014-08-03 23:02:53 -04001018 self.themeIsBuiltin.set(idleConf.GetOption(
1019 'main', 'Theme', 'default', type='bool', default=1))
Steven M. Gava41a85322001-10-29 08:05:34 +00001020 ##currently set theme
Terry Jan Reedyae410862014-08-03 23:02:53 -04001021 currentOption = idleConf.CurrentTheme()
Steven M. Gava7c017862001-10-29 11:19:46 +00001022 ##load available theme option menus
Steven M. Gavad0342cd2001-11-04 11:53:10 +00001023 if self.themeIsBuiltin.get(): #default theme selected
Terry Jan Reedyae410862014-08-03 23:02:53 -04001024 itemList = idleConf.GetSectionList('default', 'highlight')
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +00001025 itemList.sort()
Terry Jan Reedyae410862014-08-03 23:02:53 -04001026 self.optMenuThemeBuiltin.SetMenu(itemList, currentOption)
1027 itemList = idleConf.GetSectionList('user', 'highlight')
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +00001028 itemList.sort()
Steven M. Gava41a85322001-10-29 08:05:34 +00001029 if not itemList:
1030 self.radioThemeCustom.config(state=DISABLED)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001031 self.customTheme.set('- no custom themes -')
Steven M. Gava41a85322001-10-29 08:05:34 +00001032 else:
Terry Jan Reedyae410862014-08-03 23:02:53 -04001033 self.optMenuThemeCustom.SetMenu(itemList, itemList[0])
Steven M. Gava9dd16b32001-11-03 14:54:25 +00001034 else: #user theme selected
Terry Jan Reedyae410862014-08-03 23:02:53 -04001035 itemList = idleConf.GetSectionList('user', 'highlight')
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +00001036 itemList.sort()
Terry Jan Reedyae410862014-08-03 23:02:53 -04001037 self.optMenuThemeCustom.SetMenu(itemList, currentOption)
1038 itemList = idleConf.GetSectionList('default', 'highlight')
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +00001039 itemList.sort()
Terry Jan Reedyae410862014-08-03 23:02:53 -04001040 self.optMenuThemeBuiltin.SetMenu(itemList, itemList[0])
Steven M. Gava7c017862001-10-29 11:19:46 +00001041 self.SetThemeType()
1042 ##load theme element option menu
Terry Jan Reedyae410862014-08-03 23:02:53 -04001043 themeNames = self.themeElements.keys()
Florent Xiclunaa7f242f2010-04-02 08:15:26 +00001044 themeNames.sort(key=lambda x: self.themeElements[x][1])
Terry Jan Reedyae410862014-08-03 23:02:53 -04001045 self.optMenuHighlightTarget.SetMenu(themeNames, themeNames[0])
Steven M. Gava9dd16b32001-11-03 14:54:25 +00001046 self.PaintThemeSample()
Steven M. Gava0cae01c2002-01-04 07:53:06 +00001047 self.SetHighlightTarget()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001048
Steven M. Gava9dd16b32001-11-03 14:54:25 +00001049 def LoadKeyCfg(self):
Steven M. Gava41a85322001-10-29 08:05:34 +00001050 ##current keys type radiobutton
Terry Jan Reedyae410862014-08-03 23:02:53 -04001051 self.keysAreBuiltin.set(idleConf.GetOption(
1052 'main', 'Keys', 'default', type='bool', default=1))
Steven M. Gava41a85322001-10-29 08:05:34 +00001053 ##currently set keys
Terry Jan Reedyae410862014-08-03 23:02:53 -04001054 currentOption = idleConf.CurrentKeys()
Steven M. Gava7c017862001-10-29 11:19:46 +00001055 ##load available keyset option menus
Steven M. Gava052937f2002-02-11 02:20:53 +00001056 if self.keysAreBuiltin.get(): #default theme selected
Terry Jan Reedyae410862014-08-03 23:02:53 -04001057 itemList = idleConf.GetSectionList('default', 'keys')
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +00001058 itemList.sort()
Terry Jan Reedyae410862014-08-03 23:02:53 -04001059 self.optMenuKeysBuiltin.SetMenu(itemList, currentOption)
1060 itemList = idleConf.GetSectionList('user', 'keys')
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +00001061 itemList.sort()
Steven M. Gava41a85322001-10-29 08:05:34 +00001062 if not itemList:
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001063 self.radioKeysCustom.config(state=DISABLED)
1064 self.customKeys.set('- no custom keys -')
Steven M. Gava41a85322001-10-29 08:05:34 +00001065 else:
Terry Jan Reedyae410862014-08-03 23:02:53 -04001066 self.optMenuKeysCustom.SetMenu(itemList, itemList[0])
Steven M. Gavaa498af22002-02-01 01:33:36 +00001067 else: #user key set selected
Terry Jan Reedyae410862014-08-03 23:02:53 -04001068 itemList = idleConf.GetSectionList('user', 'keys')
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +00001069 itemList.sort()
Terry Jan Reedyae410862014-08-03 23:02:53 -04001070 self.optMenuKeysCustom.SetMenu(itemList, currentOption)
1071 itemList = idleConf.GetSectionList('default', 'keys')
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +00001072 itemList.sort()
Terry Jan Reedyae410862014-08-03 23:02:53 -04001073 self.optMenuKeysBuiltin.SetMenu(itemList, itemList[0])
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001074 self.SetKeysType()
Steven M. Gavafacfc092002-01-19 00:29:54 +00001075 ##load keyset element list
Terry Jan Reedyae410862014-08-03 23:02:53 -04001076 keySetName = idleConf.CurrentKeys()
Steven M. Gava052937f2002-02-11 02:20:53 +00001077 self.LoadKeysList(keySetName)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001078
Steven M. Gavafacfc092002-01-19 00:29:54 +00001079 def LoadGeneralCfg(self):
Steven M. Gava5f28e8f2002-01-21 06:38:21 +00001080 #startup state
Terry Jan Reedyae410862014-08-03 23:02:53 -04001081 self.startupEdit.set(idleConf.GetOption(
1082 'main', 'General', 'editor-on-startup', default=1, type='bool'))
Kurt B. Kaiser6c638b62003-05-26 06:23:10 +00001083 #autosave state
Terry Jan Reedyae410862014-08-03 23:02:53 -04001084 self.autoSave.set(idleConf.GetOption(
1085 'main', 'General', 'autosave', default=0, type='bool'))
Steven M. Gavafacfc092002-01-19 00:29:54 +00001086 #initial window size
Terry Jan Reedyae410862014-08-03 23:02:53 -04001087 self.winWidth.set(idleConf.GetOption(
1088 'main', 'EditorWindow', 'width', type='int'))
1089 self.winHeight.set(idleConf.GetOption(
1090 'main', 'EditorWindow', 'height', type='int'))
Kurt B. Kaisera053f332003-05-10 00:49:56 +00001091 # default source encoding
Terry Jan Reedyae410862014-08-03 23:02:53 -04001092 self.encoding.set(idleConf.GetOption(
1093 'main', 'EditorWindow', 'encoding', default='none'))
Kurt B. Kaiser8e92bf72003-01-14 22:03:31 +00001094 # additional help sources
1095 self.userHelpList = idleConf.GetAllExtraHelpSourcesList()
Steven M. Gava085eb1b2002-02-05 04:52:32 +00001096 for helpItem in self.userHelpList:
Terry Jan Reedyae410862014-08-03 23:02:53 -04001097 self.listHelp.insert(END, helpItem[0])
Steven M. Gava085eb1b2002-02-05 04:52:32 +00001098 self.SetHelpListButtonStates()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001099
Steven M. Gava429a86a2001-10-23 10:42:12 +00001100 def LoadConfigs(self):
1101 """
1102 load configuration from default and user config files and populate
1103 the widgets on the config dialog pages.
1104 """
1105 ### fonts / tabs page
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001106 self.LoadFontCfg()
1107 self.LoadTabCfg()
Steven M. Gava429a86a2001-10-23 10:42:12 +00001108 ### highlighting page
Steven M. Gava9dd16b32001-11-03 14:54:25 +00001109 self.LoadThemeCfg()
Steven M. Gava429a86a2001-10-23 10:42:12 +00001110 ### keys page
Steven M. Gava9dd16b32001-11-03 14:54:25 +00001111 self.LoadKeyCfg()
Steven M. Gava429a86a2001-10-23 10:42:12 +00001112 ### general page
Steven M. Gavafacfc092002-01-19 00:29:54 +00001113 self.LoadGeneralCfg()
Terry Jan Reedy1c49ec02015-10-13 22:03:44 -04001114 # note: extension page handled separately
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001115
Terry Jan Reedyae410862014-08-03 23:02:53 -04001116 def SaveNewKeySet(self, keySetName, keySet):
Steven M. Gava052937f2002-02-11 02:20:53 +00001117 """
1118 save a newly created core key set.
1119 keySetName - string, the name of the new key set
1120 keySet - dictionary containing the new key set
1121 """
1122 if not idleConf.userCfg['keys'].has_section(keySetName):
1123 idleConf.userCfg['keys'].add_section(keySetName)
Terry Jan Reedy110796f2014-07-27 04:07:18 -04001124 for event in keySet:
Terry Jan Reedyae410862014-08-03 23:02:53 -04001125 value = keySet[event]
1126 idleConf.userCfg['keys'].SetOption(keySetName, event, value)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001127
Terry Jan Reedyae410862014-08-03 23:02:53 -04001128 def SaveNewTheme(self, themeName, theme):
Steven M. Gava052937f2002-02-11 02:20:53 +00001129 """
1130 save a newly created theme.
1131 themeName - string, the name of the new theme
1132 theme - dictionary containing the new theme
1133 """
1134 if not idleConf.userCfg['highlight'].has_section(themeName):
1135 idleConf.userCfg['highlight'].add_section(themeName)
Terry Jan Reedy110796f2014-07-27 04:07:18 -04001136 for element in theme:
Terry Jan Reedyae410862014-08-03 23:02:53 -04001137 value = theme[element]
1138 idleConf.userCfg['highlight'].SetOption(themeName, element, value)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001139
Terry Jan Reedyae410862014-08-03 23:02:53 -04001140 def SetUserValue(self, configType, section, item, value):
1141 if idleConf.defaultCfg[configType].has_option(section, item):
1142 if idleConf.defaultCfg[configType].Get(section, item) == value:
Steven M. Gava2d7bb3f2002-01-29 08:35:29 +00001143 #the setting equals a default setting, remove it from user cfg
Terry Jan Reedyae410862014-08-03 23:02:53 -04001144 return idleConf.userCfg[configType].RemoveOption(section, item)
Steven M. Gava2d7bb3f2002-01-29 08:35:29 +00001145 #if we got here set the option
Terry Jan Reedyae410862014-08-03 23:02:53 -04001146 return idleConf.userCfg[configType].SetOption(section, item, value)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001147
Steven M. Gava052937f2002-02-11 02:20:53 +00001148 def SaveAllChangedConfigs(self):
Kurt B. Kaisere7a161e2003-01-10 20:13:57 +00001149 "Save configuration changes to the user config file."
Steven M. Gava0c5bc8c2002-03-27 02:25:44 +00001150 idleConf.userCfg['main'].Save()
Terry Jan Reedy110796f2014-07-27 04:07:18 -04001151 for configType in self.changedItems:
Kurt B. Kaisere7a161e2003-01-10 20:13:57 +00001152 cfgTypeHasChanges = False
Terry Jan Reedy110796f2014-07-27 04:07:18 -04001153 for section in self.changedItems[configType]:
Kurt B. Kaisere7a161e2003-01-10 20:13:57 +00001154 if section == 'HelpFiles':
1155 #this section gets completely replaced
1156 idleConf.userCfg['main'].remove_section('HelpFiles')
Kurt B. Kaiser8e92bf72003-01-14 22:03:31 +00001157 cfgTypeHasChanges = True
Terry Jan Reedy110796f2014-07-27 04:07:18 -04001158 for item in self.changedItems[configType][section]:
Kurt B. Kaisere7a161e2003-01-10 20:13:57 +00001159 value = self.changedItems[configType][section][item]
Terry Jan Reedyae410862014-08-03 23:02:53 -04001160 if self.SetUserValue(configType, section, item, value):
Kurt B. Kaisere7a161e2003-01-10 20:13:57 +00001161 cfgTypeHasChanges = True
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001162 if cfgTypeHasChanges:
1163 idleConf.userCfg[configType].Save()
Kurt B. Kaiser5acdf932004-11-16 21:28:36 +00001164 for configType in ['keys', 'highlight']:
1165 # save these even if unchanged!
1166 idleConf.userCfg[configType].Save()
Steven M. Gavaa498af22002-02-01 01:33:36 +00001167 self.ResetChangedItems() #clear the changed items dict
Terry Jan Reedy1c49ec02015-10-13 22:03:44 -04001168 self.save_all_changed_extensions() # uses a different mechanism
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001169
Kurt B. Kaiserb1754452005-11-18 22:05:48 +00001170 def DeactivateCurrentConfig(self):
1171 #Before a config is saved, some cleanup of current
1172 #config must be done - remove the previous keybindings
Terry Jan Reedyae410862014-08-03 23:02:53 -04001173 winInstances = self.parent.instance_dict
Kurt B. Kaiserb1754452005-11-18 22:05:48 +00001174 for instance in winInstances:
1175 instance.RemoveKeybindings()
1176
Steven M. Gava49745752002-02-18 01:43:11 +00001177 def ActivateConfigChanges(self):
Kurt B. Kaiseracdef852005-01-31 03:34:26 +00001178 "Dynamically apply configuration changes"
Terry Jan Reedy110796f2014-07-27 04:07:18 -04001179 winInstances = self.parent.instance_dict.keys()
Steven M. Gavab77d3432002-03-02 07:16:21 +00001180 for instance in winInstances:
1181 instance.ResetColorizer()
Steven M. Gavab1585412002-03-12 00:21:56 +00001182 instance.ResetFont()
Kurt B. Kaiseracdef852005-01-31 03:34:26 +00001183 instance.set_notabs_indentwidth()
Kurt B. Kaiserb1754452005-11-18 22:05:48 +00001184 instance.ApplyKeybindings()
Kurt B. Kaiser8e92bf72003-01-14 22:03:31 +00001185 instance.reset_help_menu_entries()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001186
Steven M. Gava5f28e8f2002-01-21 06:38:21 +00001187 def Cancel(self):
1188 self.destroy()
1189
1190 def Ok(self):
1191 self.Apply()
1192 self.destroy()
1193
1194 def Apply(self):
Kurt B. Kaiserb1754452005-11-18 22:05:48 +00001195 self.DeactivateCurrentConfig()
Steven M. Gava052937f2002-02-11 02:20:53 +00001196 self.SaveAllChangedConfigs()
Steven M. Gava49745752002-02-18 01:43:11 +00001197 self.ActivateConfigChanges()
Steven M. Gava5f28e8f2002-01-21 06:38:21 +00001198
1199 def Help(self):
Terry Jan Reedyc0a053e2015-10-11 22:07:25 -04001200 page = self.tabPages._current_page
1201 view_text(self, title='Help for IDLE preferences',
1202 text=help_common+help_pages.get(page, ''))
1203
Terry Jan Reedy1c49ec02015-10-13 22:03:44 -04001204 def CreatePageExtensions(self):
1205 """Part of the config dialog used for configuring IDLE extensions.
1206
1207 This code is generic - it works for any and all IDLE extensions.
1208
1209 IDLE extensions save their configuration options using idleConf.
Terry Jan Reedy4922ac12015-10-13 22:08:45 -04001210 This code reads the current configuration using idleConf, supplies a
Terry Jan Reedy1c49ec02015-10-13 22:03:44 -04001211 GUI interface to change the configuration values, and saves the
1212 changes using idleConf.
1213
1214 Not all changes take effect immediately - some may require restarting IDLE.
1215 This depends on each extension's implementation.
1216
1217 All values are treated as text, and it is up to the user to supply
1218 reasonable values. The only exception to this are the 'enable*' options,
1219 which are boolean, and can be toggled with an True/False button.
1220 """
1221 parent = self.parent
1222 frame = self.tabPages.pages['Extensions'].frame
1223 self.ext_defaultCfg = idleConf.defaultCfg['extensions']
1224 self.ext_userCfg = idleConf.userCfg['extensions']
1225 self.is_int = self.register(is_int)
1226 self.load_extensions()
1227 # create widgets - a listbox shows all available extensions, with the
1228 # controls for the extension selected in the listbox to the right
1229 self.extension_names = StringVar(self)
1230 frame.rowconfigure(0, weight=1)
1231 frame.columnconfigure(2, weight=1)
1232 self.extension_list = Listbox(frame, listvariable=self.extension_names,
1233 selectmode='browse')
1234 self.extension_list.bind('<<ListboxSelect>>', self.extension_selected)
1235 scroll = Scrollbar(frame, command=self.extension_list.yview)
1236 self.extension_list.yscrollcommand=scroll.set
1237 self.details_frame = LabelFrame(frame, width=250, height=250)
1238 self.extension_list.grid(column=0, row=0, sticky='nws')
1239 scroll.grid(column=1, row=0, sticky='ns')
1240 self.details_frame.grid(column=2, row=0, sticky='nsew', padx=[10, 0])
1241 frame.configure(padx=10, pady=10)
1242 self.config_frame = {}
1243 self.current_extension = None
1244
1245 self.outerframe = self # TEMPORARY
1246 self.tabbed_page_set = self.extension_list # TEMPORARY
1247
1248 # create the frame holding controls for each extension
1249 ext_names = ''
1250 for ext_name in sorted(self.extensions):
1251 self.create_extension_frame(ext_name)
1252 ext_names = ext_names + '{' + ext_name + '} '
1253 self.extension_names.set(ext_names)
1254 self.extension_list.selection_set(0)
1255 self.extension_selected(None)
1256
1257 def load_extensions(self):
1258 "Fill self.extensions with data from the default and user configs."
1259 self.extensions = {}
1260 for ext_name in idleConf.GetExtensions(active_only=False):
1261 self.extensions[ext_name] = []
1262
1263 for ext_name in self.extensions:
1264 opt_list = sorted(self.ext_defaultCfg.GetOptionList(ext_name))
1265
1266 # bring 'enable' options to the beginning of the list
1267 enables = [opt_name for opt_name in opt_list
1268 if opt_name.startswith('enable')]
1269 for opt_name in enables:
1270 opt_list.remove(opt_name)
1271 opt_list = enables + opt_list
1272
1273 for opt_name in opt_list:
1274 def_str = self.ext_defaultCfg.Get(
1275 ext_name, opt_name, raw=True)
1276 try:
1277 def_obj = {'True':True, 'False':False}[def_str]
1278 opt_type = 'bool'
1279 except KeyError:
1280 try:
1281 def_obj = int(def_str)
1282 opt_type = 'int'
1283 except ValueError:
1284 def_obj = def_str
1285 opt_type = None
1286 try:
1287 value = self.ext_userCfg.Get(
1288 ext_name, opt_name, type=opt_type, raw=True,
1289 default=def_obj)
1290 except ValueError: # Need this until .Get fixed
1291 value = def_obj # bad values overwritten by entry
1292 var = StringVar(self)
1293 var.set(str(value))
1294
1295 self.extensions[ext_name].append({'name': opt_name,
1296 'type': opt_type,
1297 'default': def_str,
1298 'value': value,
1299 'var': var,
1300 })
1301
1302 def extension_selected(self, event):
1303 newsel = self.extension_list.curselection()
1304 if newsel:
1305 newsel = self.extension_list.get(newsel)
1306 if newsel is None or newsel != self.current_extension:
1307 if self.current_extension:
1308 self.details_frame.config(text='')
1309 self.config_frame[self.current_extension].grid_forget()
1310 self.current_extension = None
1311 if newsel:
1312 self.details_frame.config(text=newsel)
1313 self.config_frame[newsel].grid(column=0, row=0, sticky='nsew')
1314 self.current_extension = newsel
1315
1316 def create_extension_frame(self, ext_name):
1317 """Create a frame holding the widgets to configure one extension"""
1318 f = VerticalScrolledFrame(self.details_frame, height=250, width=250)
1319 self.config_frame[ext_name] = f
1320 entry_area = f.interior
1321 # create an entry for each configuration option
1322 for row, opt in enumerate(self.extensions[ext_name]):
1323 # create a row with a label and entry/checkbutton
1324 label = Label(entry_area, text=opt['name'])
1325 label.grid(row=row, column=0, sticky=NW)
1326 var = opt['var']
1327 if opt['type'] == 'bool':
1328 Checkbutton(entry_area, textvariable=var, variable=var,
1329 onvalue='True', offvalue='False',
1330 indicatoron=FALSE, selectcolor='', width=8
1331 ).grid(row=row, column=1, sticky=W, padx=7)
1332 elif opt['type'] == 'int':
1333 Entry(entry_area, textvariable=var, validate='key',
1334 validatecommand=(self.is_int, '%P')
1335 ).grid(row=row, column=1, sticky=NSEW, padx=7)
1336
1337 else:
1338 Entry(entry_area, textvariable=var
1339 ).grid(row=row, column=1, sticky=NSEW, padx=7)
1340 return
1341
1342 def set_extension_value(self, section, opt):
1343 name = opt['name']
1344 default = opt['default']
1345 value = opt['var'].get().strip() or default
1346 opt['var'].set(value)
1347 # if self.defaultCfg.has_section(section):
1348 # Currently, always true; if not, indent to return
1349 if (value == default):
1350 return self.ext_userCfg.RemoveOption(section, name)
1351 # set the option
1352 return self.ext_userCfg.SetOption(section, name, value)
1353
1354 def save_all_changed_extensions(self):
1355 """Save configuration changes to the user config file."""
1356 has_changes = False
1357 for ext_name in self.extensions:
1358 options = self.extensions[ext_name]
1359 for opt in options:
1360 if self.set_extension_value(ext_name, opt):
1361 has_changes = True
1362 if has_changes:
1363 self.ext_userCfg.Save()
1364
1365
Terry Jan Reedyc0a053e2015-10-11 22:07:25 -04001366help_common = '''\
1367When you click either the Apply or Ok buttons, settings in this
1368dialog that are different from IDLE's default are saved in
1369a .idlerc directory in your home directory. Except as noted,
1370hese changes apply to all versions of IDLE installed on this
1371machine. Some do not take affect until IDLE is restarted.
1372[Cancel] only cancels changes made since the last save.
1373'''
1374help_pages = {
1375 'Highlighting':'''
1376Highlighting:
1377The IDLE Dark color theme is new in Octover 2015. It can only
1378be used with older IDLE releases if it is saved as a custom
1379theme, with a different name.
1380'''
1381}
1382
Steven M. Gavac11ccf32001-09-24 09:43:17 +00001383
Terry Jan Reedy1c49ec02015-10-13 22:03:44 -04001384def is_int(s):
1385 "Return 's is blank or represents an int'"
1386 if not s:
1387 return True
1388 try:
1389 int(s)
1390 return True
1391 except ValueError:
1392 return False
1393
1394
Terry Jan Reedy7a162072014-10-22 20:15:12 -04001395class VerticalScrolledFrame(Frame):
1396 """A pure Tkinter vertically scrollable frame.
1397
1398 * Use the 'interior' attribute to place widgets inside the scrollable frame
1399 * Construct and pack/place/grid normally
1400 * This frame only allows vertical scrolling
1401 """
1402 def __init__(self, parent, *args, **kw):
1403 Frame.__init__(self, parent, *args, **kw)
1404
1405 # create a canvas object and a vertical scrollbar for scrolling it
1406 vscrollbar = Scrollbar(self, orient=VERTICAL)
1407 vscrollbar.pack(fill=Y, side=RIGHT, expand=FALSE)
1408 canvas = Canvas(self, bd=0, highlightthickness=0,
Terry Jan Reedy1256b3c2015-10-22 03:27:27 -04001409 yscrollcommand=vscrollbar.set, width=240)
Terry Jan Reedy7a162072014-10-22 20:15:12 -04001410 canvas.pack(side=LEFT, fill=BOTH, expand=TRUE)
1411 vscrollbar.config(command=canvas.yview)
1412
1413 # reset the view
1414 canvas.xview_moveto(0)
1415 canvas.yview_moveto(0)
1416
1417 # create a frame inside the canvas which will be scrolled with it
1418 self.interior = interior = Frame(canvas)
1419 interior_id = canvas.create_window(0, 0, window=interior, anchor=NW)
1420
1421 # track changes to the canvas and frame width and sync them,
1422 # also updating the scrollbar
1423 def _configure_interior(event):
1424 # update the scrollbars to match the size of the inner frame
1425 size = (interior.winfo_reqwidth(), interior.winfo_reqheight())
1426 canvas.config(scrollregion="0 0 %s %s" % size)
Terry Jan Reedy7a162072014-10-22 20:15:12 -04001427 interior.bind('<Configure>', _configure_interior)
1428
1429 def _configure_canvas(event):
1430 if interior.winfo_reqwidth() != canvas.winfo_width():
1431 # update the inner frame's width to fill the canvas
1432 canvas.itemconfigure(interior_id, width=canvas.winfo_width())
1433 canvas.bind('<Configure>', _configure_canvas)
1434
1435 return
1436
Terry Jan Reedy7a162072014-10-22 20:15:12 -04001437
Steven M. Gava44d3d1a2001-07-31 06:59:02 +00001438if __name__ == '__main__':
Terry Jan Reedyaf0dce92014-07-14 23:07:21 -04001439 import unittest
1440 unittest.main('idlelib.idle_test.test_configdialog',
1441 verbosity=2, exit=False)
Terry Jan Reedy76916e82014-05-29 01:46:16 -04001442 from idlelib.idle_test.htest import run
Terry Jan Reedy91885162015-10-20 02:15:23 -04001443 run(ConfigDialog)