blob: f5a1c4bbcb15361bb571170705088a90e0332471 [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
Florent Xiclunad630c042010-04-02 07:24:52 +000021from idlelib import macosxSupport
Steven M. Gava44d3d1a2001-07-31 06:59:02 +000022class ConfigDialog(Toplevel):
Kurt B. Kaiseracdef852005-01-31 03:34:26 +000023
Terry Jan Reedycf834762014-10-17 01:31:29 -040024 def __init__(self, parent, title='', _htest=False, _utest=False):
Terry Jan Reedy76916e82014-05-29 01:46:16 -040025 """
26 _htest - bool, change box location when running htest
Terry Jan Reedyaf0dce92014-07-14 23:07:21 -040027 _utest - bool, don't wait_window when running unittest
Terry Jan Reedy76916e82014-05-29 01:46:16 -040028 """
Steven M. Gavad721c482001-07-31 10:46:53 +000029 Toplevel.__init__(self, parent)
Terry Jan Reedy19b7a752014-07-30 19:24:26 -040030 self.parent = parent
Terry Jan Reedyae410862014-08-03 23:02:53 -040031 if _htest:
32 parent.instance_dict = {}
Kurt B. Kaisere3fde8f2007-10-04 03:11:12 +000033 self.wm_withdraw()
34
Steven M. Gavad721c482001-07-31 10:46:53 +000035 self.configure(borderwidth=5)
Terry Jan Reedycf834762014-10-17 01:31:29 -040036 self.title(title or 'IDLE Preferences')
Terry Jan Reedyae410862014-08-03 23:02:53 -040037 self.geometry(
38 "+%d+%d" % (parent.winfo_rootx() + 20,
39 parent.winfo_rooty() + (30 if not _htest else 150)))
Georg Brandl7eb4b7d2005-07-22 21:49:32 +000040 #Theme Elements. Each theme element key is its display name.
Steven M. Gava9dd16b32001-11-03 14:54:25 +000041 #The first value of the tuple is the sample area tag name.
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +000042 #The second value is the display name list sort index.
Terry Jan Reedyae410862014-08-03 23:02:53 -040043 self.themeElements={
Terry Jan Reedyc30475e2015-10-02 22:12:09 -040044 'Normal Text': ('normal', '00'),
45 'Python Keywords': ('keyword', '01'),
46 'Python Definitions': ('definition', '02'),
47 'Python Builtins': ('builtin', '03'),
48 'Python Comments': ('comment', '04'),
49 'Python Strings': ('string', '05'),
50 'Selected Text': ('hilite', '06'),
51 'Found Text': ('hit', '07'),
52 'Cursor': ('cursor', '08'),
53 'Editor Breakpoint': ('break', '09'),
54 'Shell Normal Text': ('console', '10'),
55 'Shell Error Text': ('error', '11'),
56 'Shell Stdout Text': ('stdout', '12'),
57 'Shell Stderr Text': ('stderr', '13'),
Kurt B. Kaiser73360a32004-03-08 18:15:31 +000058 }
Steven M. Gavaa498af22002-02-01 01:33:36 +000059 self.ResetChangedItems() #load initial values in changed items dict
Steven M. Gavad721c482001-07-31 10:46:53 +000060 self.CreateWidgets()
Terry Jan Reedyae410862014-08-03 23:02:53 -040061 self.resizable(height=FALSE, width=FALSE)
Steven M. Gavad721c482001-07-31 10:46:53 +000062 self.transient(parent)
63 self.grab_set()
64 self.protocol("WM_DELETE_WINDOW", self.Cancel)
Steven M. Gava2d4e03b2001-12-05 07:54:07 +000065 self.tabPages.focus_set()
Steven M. Gavad721c482001-07-31 10:46:53 +000066 #key bindings for this dialog
Terry Jan Reedyae410862014-08-03 23:02:53 -040067 #self.bind('<Escape>', self.Cancel) #dismiss dialog, no save
68 #self.bind('<Alt-a>', self.Apply) #apply changes, save
69 #self.bind('<F1>', self.Help) #context help
Steven M. Gava429a86a2001-10-23 10:42:12 +000070 self.LoadConfigs()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +000071 self.AttachVarCallbacks() #avoid callbacks during LoadConfigs
Kurt B. Kaisere3fde8f2007-10-04 03:11:12 +000072
Terry Jan Reedyaf0dce92014-07-14 23:07:21 -040073 if not _utest:
74 self.wm_deiconify()
75 self.wait_window()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +000076
Steven M. Gavad721c482001-07-31 10:46:53 +000077 def CreateWidgets(self):
Kurt B. Kaiser20172f92007-10-30 02:38:54 +000078 self.tabPages = TabbedPageSet(self,
Terry Jan Reedyae410862014-08-03 23:02:53 -040079 page_names=['Fonts/Tabs', 'Highlighting', 'Keys', 'General'])
Terry Jan Reedy23030db2014-10-08 20:29:05 -040080 self.tabPages.pack(side=TOP, expand=TRUE, fill=BOTH)
81 self.CreatePageFontTab()
82 self.CreatePageHighlight()
83 self.CreatePageKeys()
84 self.CreatePageGeneral()
85 self.create_action_buttons().pack(side=BOTTOM)
Terry Jan Reedy23030db2014-10-08 20:29:05 -040086 def create_action_buttons(self):
Ned Deily57847df2014-03-27 20:47:04 -070087 if macosxSupport.isAquaTk():
Ronald Oussorena97063a2009-03-04 21:35:05 +000088 # Changing the default padding on OSX results in unreadable
89 # text in the buttons
Terry Jan Reedyae410862014-08-03 23:02:53 -040090 paddingArgs = {}
Ronald Oussorena97063a2009-03-04 21:35:05 +000091 else:
Terry Jan Reedyae410862014-08-03 23:02:53 -040092 paddingArgs = {'padx':6, 'pady':3}
Terry Jan Reedy7a162072014-10-22 20:15:12 -040093 outer = Frame(self, pady=2)
94 buttons = Frame(outer, pady=2)
Terry Jan Reedyae410862014-08-03 23:02:53 -040095 self.buttonOk = Button(
Terry Jan Reedy7a162072014-10-22 20:15:12 -040096 buttons, text='Ok', command=self.Ok,
Terry Jan Reedy23030db2014-10-08 20:29:05 -040097 takefocus=FALSE, **paddingArgs)
Terry Jan Reedyae410862014-08-03 23:02:53 -040098 self.buttonApply = Button(
Terry Jan Reedy7a162072014-10-22 20:15:12 -040099 buttons, text='Apply', command=self.Apply,
Terry Jan Reedy23030db2014-10-08 20:29:05 -0400100 takefocus=FALSE, **paddingArgs)
Terry Jan Reedyae410862014-08-03 23:02:53 -0400101 self.buttonCancel = Button(
Terry Jan Reedy7a162072014-10-22 20:15:12 -0400102 buttons, text='Cancel', command=self.Cancel,
Terry Jan Reedy23030db2014-10-08 20:29:05 -0400103 takefocus=FALSE, **paddingArgs)
Terry Jan Reedyae410862014-08-03 23:02:53 -0400104 self.buttonOk.pack(side=LEFT, padx=5)
105 self.buttonApply.pack(side=LEFT, padx=5)
106 self.buttonCancel.pack(side=LEFT, padx=5)
Terry Jan Reedy7a162072014-10-22 20:15:12 -0400107# Comment out Help button creation and packing until implement self.Help
108## self.buttonHelp = Button(
109## buttons, text='Help', command=self.Help,
110## takefocus=FALSE, **paddingArgs)
111## self.buttonHelp.pack(side=RIGHT, padx=5)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000112
Terry Jan Reedy7a162072014-10-22 20:15:12 -0400113 # add space above buttons
114 Frame(outer, height=2, borderwidth=0).pack(side=TOP)
115 buttons.pack(side=BOTTOM)
116 return outer
Steven M. Gava60fc7072001-08-04 13:58:22 +0000117 def CreatePageFontTab(self):
Terry Jan Reedy19b7a752014-07-30 19:24:26 -0400118 parent = self.parent
119 self.fontSize = StringVar(parent)
120 self.fontBold = BooleanVar(parent)
121 self.fontName = StringVar(parent)
122 self.spaceNum = IntVar(parent)
Terry Jan Reedyae410862014-08-03 23:02:53 -0400123 self.editFont = tkFont.Font(parent, ('courier', 10, 'normal'))
Terry Jan Reedy19b7a752014-07-30 19:24:26 -0400124
Steven M. Gavaf213ccb2001-08-05 08:00:28 +0000125 ##widget creation
126 #body frame
Terry Jan Reedyae410862014-08-03 23:02:53 -0400127 frame = self.tabPages.pages['Fonts/Tabs'].frame
Steven M. Gavaf213ccb2001-08-05 08:00:28 +0000128 #body section frames
Terry Jan Reedyae410862014-08-03 23:02:53 -0400129 frameFont = LabelFrame(
130 frame, borderwidth=2, relief=GROOVE, text=' Base Editor Font ')
131 frameIndent = LabelFrame(
132 frame, borderwidth=2, relief=GROOVE, text=' Indentation Width ')
Steven M. Gavaf213ccb2001-08-05 08:00:28 +0000133 #frameFont
Terry Jan Reedyae410862014-08-03 23:02:53 -0400134 frameFontName = Frame(frameFont)
135 frameFontParam = Frame(frameFont)
136 labelFontNameTitle = Label(
137 frameFontName, justify=LEFT, text='Font Face :')
138 self.listFontName = Listbox(
139 frameFontName, height=5, takefocus=FALSE, exportselection=FALSE)
140 self.listFontName.bind(
141 '<ButtonRelease-1>', self.OnListFontButtonRelease)
142 scrollFont = Scrollbar(frameFontName)
Steven M. Gavac01e30f2001-08-11 15:48:13 +0000143 scrollFont.config(command=self.listFontName.yview)
144 self.listFontName.config(yscrollcommand=scrollFont.set)
Terry Jan Reedyae410862014-08-03 23:02:53 -0400145 labelFontSizeTitle = Label(frameFontParam, text='Size :')
146 self.optMenuFontSize = DynOptionMenu(
147 frameFontParam, self.fontSize, None, command=self.SetFontSample)
148 checkFontBold = Checkbutton(
149 frameFontParam, variable=self.fontBold, onvalue=1,
150 offvalue=0, text='Bold', command=self.SetFontSample)
151 frameFontSample = Frame(frameFont, relief=SOLID, borderwidth=1)
152 self.labelFontSample = Label(
153 frameFontSample, justify=LEFT, font=self.editFont,
154 text='AaBbCcDdEe\nFfGgHhIiJjK\n1234567890\n#:+=(){}[]')
Steven M. Gavaf213ccb2001-08-05 08:00:28 +0000155 #frameIndent
Terry Jan Reedyae410862014-08-03 23:02:53 -0400156 frameIndentSize = Frame(frameIndent)
157 labelSpaceNumTitle = Label(
158 frameIndentSize, justify=LEFT,
159 text='Python Standard: 4 Spaces!')
160 self.scaleSpaceNum = Scale(
161 frameIndentSize, variable=self.spaceNum,
162 orient='horizontal', tickinterval=2, from_=2, to=16)
Terry Jan Reedy19b7a752014-07-30 19:24:26 -0400163
Steven M. Gavaf213ccb2001-08-05 08:00:28 +0000164 #widget packing
165 #body
Terry Jan Reedyae410862014-08-03 23:02:53 -0400166 frameFont.pack(side=LEFT, padx=5, pady=5, expand=TRUE, fill=BOTH)
167 frameIndent.pack(side=LEFT, padx=5, pady=5, fill=Y)
Steven M. Gavaf213ccb2001-08-05 08:00:28 +0000168 #frameFont
Terry Jan Reedyae410862014-08-03 23:02:53 -0400169 frameFontName.pack(side=TOP, padx=5, pady=5, fill=X)
170 frameFontParam.pack(side=TOP, padx=5, pady=5, fill=X)
171 labelFontNameTitle.pack(side=TOP, anchor=W)
172 self.listFontName.pack(side=LEFT, expand=TRUE, fill=X)
173 scrollFont.pack(side=LEFT, fill=Y)
174 labelFontSizeTitle.pack(side=LEFT, anchor=W)
175 self.optMenuFontSize.pack(side=LEFT, anchor=W)
176 checkFontBold.pack(side=LEFT, anchor=W, padx=20)
177 frameFontSample.pack(side=TOP, padx=5, pady=5, expand=TRUE, fill=BOTH)
178 self.labelFontSample.pack(expand=TRUE, fill=BOTH)
Steven M. Gavaf213ccb2001-08-05 08:00:28 +0000179 #frameIndent
Terry Jan Reedyae410862014-08-03 23:02:53 -0400180 frameIndentSize.pack(side=TOP, fill=X)
181 labelSpaceNumTitle.pack(side=TOP, anchor=W, padx=5)
182 self.scaleSpaceNum.pack(side=TOP, padx=5, fill=X)
Steven M. Gava952d0a52001-08-03 04:43:44 +0000183 return frame
184
185 def CreatePageHighlight(self):
Terry Jan Reedy19b7a752014-07-30 19:24:26 -0400186 parent = self.parent
187 self.builtinTheme = StringVar(parent)
188 self.customTheme = StringVar(parent)
189 self.fgHilite = BooleanVar(parent)
190 self.colour = StringVar(parent)
191 self.fontName = StringVar(parent)
192 self.themeIsBuiltin = BooleanVar(parent)
193 self.highlightTarget = StringVar(parent)
194
Steven M. Gava952d0a52001-08-03 04:43:44 +0000195 ##widget creation
196 #body frame
Terry Jan Reedyae410862014-08-03 23:02:53 -0400197 frame = self.tabPages.pages['Highlighting'].frame
Steven M. Gava952d0a52001-08-03 04:43:44 +0000198 #body section frames
Terry Jan Reedyae410862014-08-03 23:02:53 -0400199 frameCustom = LabelFrame(frame, borderwidth=2, relief=GROOVE,
200 text=' Custom Highlighting ')
201 frameTheme = LabelFrame(frame, borderwidth=2, relief=GROOVE,
202 text=' Highlighting Theme ')
Steven M. Gava952d0a52001-08-03 04:43:44 +0000203 #frameCustom
Terry Jan Reedyae410862014-08-03 23:02:53 -0400204 self.textHighlightSample=Text(
205 frameCustom, relief=SOLID, borderwidth=1,
206 font=('courier', 12, ''), cursor='hand2', width=21, height=11,
207 takefocus=FALSE, highlightthickness=0, wrap=NONE)
Steven M. Gavae16d94b2001-11-03 05:07:28 +0000208 text=self.textHighlightSample
Terry Jan Reedyae410862014-08-03 23:02:53 -0400209 text.bind('<Double-Button-1>', lambda e: 'break')
210 text.bind('<B1-Motion>', lambda e: 'break')
211 textAndTags=(
212 ('#you can click here', 'comment'), ('\n', 'normal'),
213 ('#to choose items', 'comment'), ('\n', 'normal'),
214 ('def', 'keyword'), (' ', 'normal'),
215 ('func', 'definition'), ('(param):\n ', 'normal'),
216 ('"""string"""', 'string'), ('\n var0 = ', 'normal'),
217 ("'string'", 'string'), ('\n var1 = ', 'normal'),
218 ("'selected'", 'hilite'), ('\n var2 = ', 'normal'),
219 ("'found'", 'hit'), ('\n var3 = ', 'normal'),
220 ('list', 'builtin'), ('(', 'normal'),
Terry Jan Reedyc30475e2015-10-02 22:12:09 -0400221 ('None', 'builtin'), (')\n', 'normal'),
222 (' breakpoint("line")', 'break'), ('\n\n', 'normal'),
Terry Jan Reedyae410862014-08-03 23:02:53 -0400223 (' error ', 'error'), (' ', 'normal'),
224 ('cursor |', 'cursor'), ('\n ', 'normal'),
225 ('shell', 'console'), (' ', 'normal'),
226 ('stdout', 'stdout'), (' ', 'normal'),
227 ('stderr', 'stderr'), ('\n', 'normal'))
Steven M. Gava9dd16b32001-11-03 14:54:25 +0000228 for txTa in textAndTags:
Terry Jan Reedyae410862014-08-03 23:02:53 -0400229 text.insert(END, txTa[0], txTa[1])
Terry Jan Reedy110796f2014-07-27 04:07:18 -0400230 for element in self.themeElements:
Terry Jan Reedyae410862014-08-03 23:02:53 -0400231 def tem(event, elem=element):
232 event.widget.winfo_toplevel().highlightTarget.set(elem)
233 text.tag_bind(
234 self.themeElements[element][0], '<ButtonPress-1>', tem)
Steven M. Gavae16d94b2001-11-03 05:07:28 +0000235 text.config(state=DISABLED)
Terry Jan Reedyae410862014-08-03 23:02:53 -0400236 self.frameColourSet = Frame(frameCustom, relief=SOLID, borderwidth=1)
237 frameFgBg = Frame(frameCustom)
238 buttonSetColour = Button(
239 self.frameColourSet, text='Choose Colour for :',
240 command=self.GetColour, highlightthickness=0)
241 self.optMenuHighlightTarget = DynOptionMenu(
242 self.frameColourSet, self.highlightTarget, None,
243 highlightthickness=0) #, command=self.SetHighlightTargetBinding
244 self.radioFg = Radiobutton(
245 frameFgBg, variable=self.fgHilite, value=1,
246 text='Foreground', command=self.SetColourSampleBinding)
247 self.radioBg=Radiobutton(
248 frameFgBg, variable=self.fgHilite, value=0,
249 text='Background', command=self.SetColourSampleBinding)
Steven M. Gava7c017862001-10-29 11:19:46 +0000250 self.fgHilite.set(1)
Terry Jan Reedyae410862014-08-03 23:02:53 -0400251 buttonSaveCustomTheme = Button(
252 frameCustom, text='Save as New Custom Theme',
253 command=self.SaveAsNewTheme)
Steven M. Gava952d0a52001-08-03 04:43:44 +0000254 #frameTheme
Terry Jan Reedyae410862014-08-03 23:02:53 -0400255 labelTypeTitle = Label(frameTheme, text='Select : ')
256 self.radioThemeBuiltin = Radiobutton(
257 frameTheme, variable=self.themeIsBuiltin, value=1,
258 command=self.SetThemeType, text='a Built-in Theme')
259 self.radioThemeCustom = Radiobutton(
260 frameTheme, variable=self.themeIsBuiltin, value=0,
261 command=self.SetThemeType, text='a Custom Theme')
262 self.optMenuThemeBuiltin = DynOptionMenu(
263 frameTheme, self.builtinTheme, None, command=None)
264 self.optMenuThemeCustom=DynOptionMenu(
265 frameTheme, self.customTheme, None, command=None)
266 self.buttonDeleteCustomTheme=Button(
267 frameTheme, text='Delete Custom Theme',
Steven M. Gava49745752002-02-18 01:43:11 +0000268 command=self.DeleteCustomTheme)
Terry Jan Reedy19b7a752014-07-30 19:24:26 -0400269
Steven M. Gava952d0a52001-08-03 04:43:44 +0000270 ##widget packing
271 #body
Terry Jan Reedyae410862014-08-03 23:02:53 -0400272 frameCustom.pack(side=LEFT, padx=5, pady=5, expand=TRUE, fill=BOTH)
273 frameTheme.pack(side=LEFT, padx=5, pady=5, fill=Y)
Steven M. Gava952d0a52001-08-03 04:43:44 +0000274 #frameCustom
Terry Jan Reedyae410862014-08-03 23:02:53 -0400275 self.frameColourSet.pack(side=TOP, padx=5, pady=5, expand=TRUE, fill=X)
276 frameFgBg.pack(side=TOP, padx=5, pady=0)
277 self.textHighlightSample.pack(
278 side=TOP, padx=5, pady=5, expand=TRUE, fill=BOTH)
279 buttonSetColour.pack(side=TOP, expand=TRUE, fill=X, padx=8, pady=4)
280 self.optMenuHighlightTarget.pack(
281 side=TOP, expand=TRUE, fill=X, padx=8, pady=3)
282 self.radioFg.pack(side=LEFT, anchor=E)
283 self.radioBg.pack(side=RIGHT, anchor=W)
284 buttonSaveCustomTheme.pack(side=BOTTOM, fill=X, padx=5, pady=5)
Steven M. Gava952d0a52001-08-03 04:43:44 +0000285 #frameTheme
Terry Jan Reedyae410862014-08-03 23:02:53 -0400286 labelTypeTitle.pack(side=TOP, anchor=W, padx=5, pady=5)
287 self.radioThemeBuiltin.pack(side=TOP, anchor=W, padx=5)
288 self.radioThemeCustom.pack(side=TOP, anchor=W, padx=5, pady=2)
289 self.optMenuThemeBuiltin.pack(side=TOP, fill=X, padx=5, pady=5)
290 self.optMenuThemeCustom.pack(side=TOP, fill=X, anchor=W, padx=5, pady=5)
291 self.buttonDeleteCustomTheme.pack(side=TOP, fill=X, padx=5, pady=5)
Steven M. Gava952d0a52001-08-03 04:43:44 +0000292 return frame
293
294 def CreatePageKeys(self):
Terry Jan Reedy19b7a752014-07-30 19:24:26 -0400295 parent = self.parent
296 self.bindingTarget = StringVar(parent)
297 self.builtinKeys = StringVar(parent)
298 self.customKeys = StringVar(parent)
299 self.keysAreBuiltin = BooleanVar(parent)
300 self.keyBinding = StringVar(parent)
301
Steven M. Gava60fc7072001-08-04 13:58:22 +0000302 ##widget creation
303 #body frame
Terry Jan Reedyae410862014-08-03 23:02:53 -0400304 frame = self.tabPages.pages['Keys'].frame
Steven M. Gava60fc7072001-08-04 13:58:22 +0000305 #body section frames
Terry Jan Reedyae410862014-08-03 23:02:53 -0400306 frameCustom = LabelFrame(
307 frame, borderwidth=2, relief=GROOVE,
308 text=' Custom Key Bindings ')
309 frameKeySets = LabelFrame(
310 frame, borderwidth=2, relief=GROOVE, text=' Key Set ')
Steven M. Gava60fc7072001-08-04 13:58:22 +0000311 #frameCustom
Terry Jan Reedyae410862014-08-03 23:02:53 -0400312 frameTarget = Frame(frameCustom)
313 labelTargetTitle = Label(frameTarget, text='Action - Key(s)')
314 scrollTargetY = Scrollbar(frameTarget)
315 scrollTargetX = Scrollbar(frameTarget, orient=HORIZONTAL)
316 self.listBindings = Listbox(
317 frameTarget, takefocus=FALSE, exportselection=FALSE)
318 self.listBindings.bind('<ButtonRelease-1>', self.KeyBindingSelected)
Steven M. Gavafacfc092002-01-19 00:29:54 +0000319 scrollTargetY.config(command=self.listBindings.yview)
320 scrollTargetX.config(command=self.listBindings.xview)
321 self.listBindings.config(yscrollcommand=scrollTargetY.set)
322 self.listBindings.config(xscrollcommand=scrollTargetX.set)
Terry Jan Reedyae410862014-08-03 23:02:53 -0400323 self.buttonNewKeys = Button(
324 frameCustom, text='Get New Keys for Selection',
325 command=self.GetNewKeys, state=DISABLED)
Steven M. Gava60fc7072001-08-04 13:58:22 +0000326 #frameKeySets
Kurt B. Kaiser28c7bcf2007-12-28 04:18:01 +0000327 frames = [Frame(frameKeySets, padx=2, pady=2, borderwidth=0)
328 for i in range(2)]
Terry Jan Reedyae410862014-08-03 23:02:53 -0400329 self.radioKeysBuiltin = Radiobutton(
330 frames[0], variable=self.keysAreBuiltin, value=1,
331 command=self.SetKeysType, text='Use a Built-in Key Set')
332 self.radioKeysCustom = Radiobutton(
333 frames[0], variable=self.keysAreBuiltin, value=0,
334 command=self.SetKeysType, text='Use a Custom Key Set')
335 self.optMenuKeysBuiltin = DynOptionMenu(
336 frames[0], self.builtinKeys, None, command=None)
337 self.optMenuKeysCustom = DynOptionMenu(
338 frames[0], self.customKeys, None, command=None)
339 self.buttonDeleteCustomKeys = Button(
340 frames[1], text='Delete Custom Key Set',
Steven M. Gava49745752002-02-18 01:43:11 +0000341 command=self.DeleteCustomKeys)
Terry Jan Reedyae410862014-08-03 23:02:53 -0400342 buttonSaveCustomKeys = Button(
343 frames[1], text='Save as New Custom Key Set',
344 command=self.SaveAsNewKeySet)
Terry Jan Reedy19b7a752014-07-30 19:24:26 -0400345
Steven M. Gava60fc7072001-08-04 13:58:22 +0000346 ##widget packing
347 #body
Terry Jan Reedyae410862014-08-03 23:02:53 -0400348 frameCustom.pack(side=BOTTOM, padx=5, pady=5, expand=TRUE, fill=BOTH)
349 frameKeySets.pack(side=BOTTOM, padx=5, pady=5, fill=BOTH)
Steven M. Gava60fc7072001-08-04 13:58:22 +0000350 #frameCustom
Terry Jan Reedyae410862014-08-03 23:02:53 -0400351 self.buttonNewKeys.pack(side=BOTTOM, fill=X, padx=5, pady=5)
352 frameTarget.pack(side=LEFT, padx=5, pady=5, expand=TRUE, fill=BOTH)
Steven M. Gavafacfc092002-01-19 00:29:54 +0000353 #frame target
Terry Jan Reedyae410862014-08-03 23:02:53 -0400354 frameTarget.columnconfigure(0, weight=1)
355 frameTarget.rowconfigure(1, weight=1)
356 labelTargetTitle.grid(row=0, column=0, columnspan=2, sticky=W)
357 self.listBindings.grid(row=1, column=0, sticky=NSEW)
358 scrollTargetY.grid(row=1, column=1, sticky=NS)
359 scrollTargetX.grid(row=2, column=0, sticky=EW)
Steven M. Gava60fc7072001-08-04 13:58:22 +0000360 #frameKeySets
Kurt B. Kaiser28c7bcf2007-12-28 04:18:01 +0000361 self.radioKeysBuiltin.grid(row=0, column=0, sticky=W+NS)
362 self.radioKeysCustom.grid(row=1, column=0, sticky=W+NS)
363 self.optMenuKeysBuiltin.grid(row=0, column=1, sticky=NSEW)
364 self.optMenuKeysCustom.grid(row=1, column=1, sticky=NSEW)
Terry Jan Reedyae410862014-08-03 23:02:53 -0400365 self.buttonDeleteCustomKeys.pack(side=LEFT, fill=X, expand=True, padx=2)
366 buttonSaveCustomKeys.pack(side=LEFT, fill=X, expand=True, padx=2)
Kurt B. Kaiser28c7bcf2007-12-28 04:18:01 +0000367 frames[0].pack(side=TOP, fill=BOTH, expand=True)
368 frames[1].pack(side=TOP, fill=X, expand=True, pady=2)
Steven M. Gava952d0a52001-08-03 04:43:44 +0000369 return frame
370
371 def CreatePageGeneral(self):
Terry Jan Reedy19b7a752014-07-30 19:24:26 -0400372 parent = self.parent
373 self.winWidth = StringVar(parent)
374 self.winHeight = StringVar(parent)
Terry Jan Reedy19b7a752014-07-30 19:24:26 -0400375 self.startupEdit = IntVar(parent)
376 self.autoSave = IntVar(parent)
377 self.encoding = StringVar(parent)
378 self.userHelpBrowser = BooleanVar(parent)
379 self.helpBrowser = StringVar(parent)
380
Steven M. Gava230e5782001-08-07 03:28:25 +0000381 #widget creation
382 #body
Terry Jan Reedyae410862014-08-03 23:02:53 -0400383 frame = self.tabPages.pages['General'].frame
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000384 #body section frames
Terry Jan Reedyae410862014-08-03 23:02:53 -0400385 frameRun = LabelFrame(frame, borderwidth=2, relief=GROOVE,
386 text=' Startup Preferences ')
387 frameSave = LabelFrame(frame, borderwidth=2, relief=GROOVE,
388 text=' Autosave Preferences ')
389 frameWinSize = Frame(frame, borderwidth=2, relief=GROOVE)
Terry Jan Reedyae410862014-08-03 23:02:53 -0400390 frameEncoding = Frame(frame, borderwidth=2, relief=GROOVE)
391 frameHelp = LabelFrame(frame, borderwidth=2, relief=GROOVE,
392 text=' Additional Help Sources ')
Steven M. Gava230e5782001-08-07 03:28:25 +0000393 #frameRun
Terry Jan Reedyae410862014-08-03 23:02:53 -0400394 labelRunChoiceTitle = Label(frameRun, text='At Startup')
395 radioStartupEdit = Radiobutton(
396 frameRun, variable=self.startupEdit, value=1,
397 command=self.SetKeysType, text="Open Edit Window")
398 radioStartupShell = Radiobutton(
399 frameRun, variable=self.startupEdit, value=0,
400 command=self.SetKeysType, text='Open Shell Window')
Kurt B. Kaiser6c638b62003-05-26 06:23:10 +0000401 #frameSave
Terry Jan Reedyae410862014-08-03 23:02:53 -0400402 labelRunSaveTitle = Label(frameSave, text='At Start of Run (F5) ')
403 radioSaveAsk = Radiobutton(
404 frameSave, variable=self.autoSave, value=0,
405 command=self.SetKeysType, text="Prompt to Save")
406 radioSaveAuto = Radiobutton(
407 frameSave, variable=self.autoSave, value=1,
408 command=self.SetKeysType, text='No Prompt')
Steven M. Gava230e5782001-08-07 03:28:25 +0000409 #frameWinSize
Terry Jan Reedyae410862014-08-03 23:02:53 -0400410 labelWinSizeTitle = Label(
411 frameWinSize, text='Initial Window Size (in characters)')
412 labelWinWidthTitle = Label(frameWinSize, text='Width')
413 entryWinWidth = Entry(
414 frameWinSize, textvariable=self.winWidth, width=3)
415 labelWinHeightTitle = Label(frameWinSize, text='Height')
416 entryWinHeight = Entry(
417 frameWinSize, textvariable=self.winHeight, width=3)
Kurt B. Kaisera053f332003-05-10 00:49:56 +0000418 #frameEncoding
Terry Jan Reedyae410862014-08-03 23:02:53 -0400419 labelEncodingTitle = Label(
420 frameEncoding, text="Default Source Encoding")
421 radioEncLocale = Radiobutton(
422 frameEncoding, variable=self.encoding,
423 value="locale", text="Locale-defined")
424 radioEncUTF8 = Radiobutton(
425 frameEncoding, variable=self.encoding,
426 value="utf-8", text="UTF-8")
427 radioEncNone = Radiobutton(
428 frameEncoding, variable=self.encoding,
429 value="none", text="None")
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000430 #frameHelp
Terry Jan Reedyae410862014-08-03 23:02:53 -0400431 frameHelpList = Frame(frameHelp)
432 frameHelpListButtons = Frame(frameHelpList)
433 scrollHelpList = Scrollbar(frameHelpList)
434 self.listHelp = Listbox(
435 frameHelpList, height=5, takefocus=FALSE,
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000436 exportselection=FALSE)
437 scrollHelpList.config(command=self.listHelp.yview)
438 self.listHelp.config(yscrollcommand=scrollHelpList.set)
Terry Jan Reedyae410862014-08-03 23:02:53 -0400439 self.listHelp.bind('<ButtonRelease-1>', self.HelpSourceSelected)
440 self.buttonHelpListEdit = Button(
441 frameHelpListButtons, text='Edit', state=DISABLED,
442 width=8, command=self.HelpListItemEdit)
443 self.buttonHelpListAdd = Button(
444 frameHelpListButtons, text='Add',
445 width=8, command=self.HelpListItemAdd)
446 self.buttonHelpListRemove = Button(
447 frameHelpListButtons, text='Remove', state=DISABLED,
448 width=8, command=self.HelpListItemRemove)
Terry Jan Reedy19b7a752014-07-30 19:24:26 -0400449
Steven M. Gava230e5782001-08-07 03:28:25 +0000450 #widget packing
451 #body
Terry Jan Reedyae410862014-08-03 23:02:53 -0400452 frameRun.pack(side=TOP, padx=5, pady=5, fill=X)
453 frameSave.pack(side=TOP, padx=5, pady=5, fill=X)
454 frameWinSize.pack(side=TOP, padx=5, pady=5, fill=X)
Terry Jan Reedyae410862014-08-03 23:02:53 -0400455 frameEncoding.pack(side=TOP, padx=5, pady=5, fill=X)
456 frameHelp.pack(side=TOP, padx=5, pady=5, expand=TRUE, fill=BOTH)
Steven M. Gava230e5782001-08-07 03:28:25 +0000457 #frameRun
Terry Jan Reedyae410862014-08-03 23:02:53 -0400458 labelRunChoiceTitle.pack(side=LEFT, anchor=W, padx=5, pady=5)
459 radioStartupShell.pack(side=RIGHT, anchor=W, padx=5, pady=5)
460 radioStartupEdit.pack(side=RIGHT, anchor=W, padx=5, pady=5)
Kurt B. Kaiser6c638b62003-05-26 06:23:10 +0000461 #frameSave
Terry Jan Reedyae410862014-08-03 23:02:53 -0400462 labelRunSaveTitle.pack(side=LEFT, anchor=W, padx=5, pady=5)
463 radioSaveAuto.pack(side=RIGHT, anchor=W, padx=5, pady=5)
464 radioSaveAsk.pack(side=RIGHT, anchor=W, padx=5, pady=5)
Steven M. Gava230e5782001-08-07 03:28:25 +0000465 #frameWinSize
Terry Jan Reedyae410862014-08-03 23:02:53 -0400466 labelWinSizeTitle.pack(side=LEFT, anchor=W, padx=5, pady=5)
467 entryWinHeight.pack(side=RIGHT, anchor=E, padx=10, pady=5)
468 labelWinHeightTitle.pack(side=RIGHT, anchor=E, pady=5)
469 entryWinWidth.pack(side=RIGHT, anchor=E, padx=10, pady=5)
470 labelWinWidthTitle.pack(side=RIGHT, anchor=E, pady=5)
Kurt B. Kaisera053f332003-05-10 00:49:56 +0000471 #frameEncoding
Terry Jan Reedyae410862014-08-03 23:02:53 -0400472 labelEncodingTitle.pack(side=LEFT, anchor=W, padx=5, pady=5)
473 radioEncNone.pack(side=RIGHT, anchor=E, pady=5)
474 radioEncUTF8.pack(side=RIGHT, anchor=E, pady=5)
475 radioEncLocale.pack(side=RIGHT, anchor=E, pady=5)
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000476 #frameHelp
Terry Jan Reedyae410862014-08-03 23:02:53 -0400477 frameHelpListButtons.pack(side=RIGHT, padx=5, pady=5, fill=Y)
478 frameHelpList.pack(side=TOP, padx=5, pady=5, expand=TRUE, fill=BOTH)
479 scrollHelpList.pack(side=RIGHT, anchor=W, fill=Y)
480 self.listHelp.pack(side=LEFT, anchor=E, expand=TRUE, fill=BOTH)
481 self.buttonHelpListEdit.pack(side=TOP, anchor=W, pady=5)
482 self.buttonHelpListAdd.pack(side=TOP, anchor=W)
483 self.buttonHelpListRemove.pack(side=TOP, anchor=W, pady=5)
Steven M. Gava952d0a52001-08-03 04:43:44 +0000484 return frame
485
Steven M. Gavac112cd82002-01-22 05:56:40 +0000486 def AttachVarCallbacks(self):
Terry Jan Reedy12352142015-08-01 18:57:27 -0400487 self.fontSize.trace_variable('w', self.VarChanged_font)
488 self.fontName.trace_variable('w', self.VarChanged_font)
489 self.fontBold.trace_variable('w', self.VarChanged_font)
Terry Jan Reedyae410862014-08-03 23:02:53 -0400490 self.spaceNum.trace_variable('w', self.VarChanged_spaceNum)
491 self.colour.trace_variable('w', self.VarChanged_colour)
492 self.builtinTheme.trace_variable('w', self.VarChanged_builtinTheme)
493 self.customTheme.trace_variable('w', self.VarChanged_customTheme)
494 self.themeIsBuiltin.trace_variable('w', self.VarChanged_themeIsBuiltin)
495 self.highlightTarget.trace_variable('w', self.VarChanged_highlightTarget)
496 self.keyBinding.trace_variable('w', self.VarChanged_keyBinding)
497 self.builtinKeys.trace_variable('w', self.VarChanged_builtinKeys)
498 self.customKeys.trace_variable('w', self.VarChanged_customKeys)
499 self.keysAreBuiltin.trace_variable('w', self.VarChanged_keysAreBuiltin)
500 self.winWidth.trace_variable('w', self.VarChanged_winWidth)
501 self.winHeight.trace_variable('w', self.VarChanged_winHeight)
Terry Jan Reedyae410862014-08-03 23:02:53 -0400502 self.startupEdit.trace_variable('w', self.VarChanged_startupEdit)
503 self.autoSave.trace_variable('w', self.VarChanged_autoSave)
504 self.encoding.trace_variable('w', self.VarChanged_encoding)
Steven M. Gava052937f2002-02-11 02:20:53 +0000505
Terry Jan Reedy12352142015-08-01 18:57:27 -0400506 def VarChanged_font(self, *params):
507 '''When one font attribute changes, save them all, as they are
508 not independent from each other. In particular, when we are
509 overriding the default font, we need to write out everything.
510 '''
Terry Jan Reedyae410862014-08-03 23:02:53 -0400511 value = self.fontName.get()
512 self.AddChangedItem('main', 'EditorWindow', 'font', value)
Terry Jan Reedy12352142015-08-01 18:57:27 -0400513 value = self.fontSize.get()
514 self.AddChangedItem('main', 'EditorWindow', 'font-size', value)
Terry Jan Reedyae410862014-08-03 23:02:53 -0400515 value = self.fontBold.get()
516 self.AddChangedItem('main', 'EditorWindow', 'font-bold', value)
Steven M. Gavac112cd82002-01-22 05:56:40 +0000517
Terry Jan Reedyae410862014-08-03 23:02:53 -0400518 def VarChanged_spaceNum(self, *params):
519 value = self.spaceNum.get()
520 self.AddChangedItem('main', 'Indent', 'num-spaces', value)
Steven M. Gavac112cd82002-01-22 05:56:40 +0000521
Terry Jan Reedyae410862014-08-03 23:02:53 -0400522 def VarChanged_colour(self, *params):
Steven M. Gava052937f2002-02-11 02:20:53 +0000523 self.OnNewColourSet()
524
Terry Jan Reedyae410862014-08-03 23:02:53 -0400525 def VarChanged_builtinTheme(self, *params):
526 value = self.builtinTheme.get()
Terry Jan Reedy9f37eae2015-10-04 00:30:59 -0400527 if value == 'IDLE Dark':
528 tkMessageBox.showwarning(
529 title="The 'IDLE Dark' Text Color Theme",
530 message="IDLE Dark is new in October, 2015. Trying to "
531 "run earlier versions of IDLE with it selected "
532 "will disable colorizing, or worse.\n\n"
533 "If you might ever run an earlier release of IDLE, "
534 "then before exiting this version, "
535 "either switch to another theme or "
536 "hit the 'Save as New Custom Theme' button. "
537 "The latter requires a new name, such as "
538 "'Custom Dark', but the custom theme will work "
539 "with any IDLE release, and can be modified.",
540 parent=self)
Terry Jan Reedyae410862014-08-03 23:02:53 -0400541 self.AddChangedItem('main', 'Theme', 'name', value)
Steven M. Gava052937f2002-02-11 02:20:53 +0000542 self.PaintThemeSample()
543
Terry Jan Reedyae410862014-08-03 23:02:53 -0400544 def VarChanged_customTheme(self, *params):
545 value = self.customTheme.get()
Steven M. Gava49745752002-02-18 01:43:11 +0000546 if value != '- no custom themes -':
Terry Jan Reedyae410862014-08-03 23:02:53 -0400547 self.AddChangedItem('main', 'Theme', 'name', value)
Steven M. Gava49745752002-02-18 01:43:11 +0000548 self.PaintThemeSample()
Steven M. Gava052937f2002-02-11 02:20:53 +0000549
Terry Jan Reedyae410862014-08-03 23:02:53 -0400550 def VarChanged_themeIsBuiltin(self, *params):
551 value = self.themeIsBuiltin.get()
552 self.AddChangedItem('main', 'Theme', 'default', value)
Steven M. Gavaf31eec02002-03-05 00:25:58 +0000553 if value:
554 self.VarChanged_builtinTheme()
555 else:
556 self.VarChanged_customTheme()
Steven M. Gava052937f2002-02-11 02:20:53 +0000557
Terry Jan Reedyae410862014-08-03 23:02:53 -0400558 def VarChanged_highlightTarget(self, *params):
Steven M. Gava052937f2002-02-11 02:20:53 +0000559 self.SetHighlightTarget()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000560
Terry Jan Reedyae410862014-08-03 23:02:53 -0400561 def VarChanged_keyBinding(self, *params):
562 value = self.keyBinding.get()
563 keySet = self.customKeys.get()
564 event = self.listBindings.get(ANCHOR).split()[0]
Steven M. Gavaa498af22002-02-01 01:33:36 +0000565 if idleConf.IsCoreBinding(event):
566 #this is a core keybinding
Terry Jan Reedyae410862014-08-03 23:02:53 -0400567 self.AddChangedItem('keys', keySet, event, value)
Steven M. Gavaa498af22002-02-01 01:33:36 +0000568 else: #this is an extension key binding
Terry Jan Reedyae410862014-08-03 23:02:53 -0400569 extName = idleConf.GetExtnNameForEvent(event)
570 extKeybindSection = extName + '_cfgBindings'
571 self.AddChangedItem('extensions', extKeybindSection, event, value)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000572
Terry Jan Reedyae410862014-08-03 23:02:53 -0400573 def VarChanged_builtinKeys(self, *params):
574 value = self.builtinKeys.get()
575 self.AddChangedItem('main', 'Keys', 'name', value)
Steven M. Gava052937f2002-02-11 02:20:53 +0000576 self.LoadKeysList(value)
577
Terry Jan Reedyae410862014-08-03 23:02:53 -0400578 def VarChanged_customKeys(self, *params):
579 value = self.customKeys.get()
Steven M. Gava49745752002-02-18 01:43:11 +0000580 if value != '- no custom keys -':
Terry Jan Reedyae410862014-08-03 23:02:53 -0400581 self.AddChangedItem('main', 'Keys', 'name', value)
Steven M. Gava49745752002-02-18 01:43:11 +0000582 self.LoadKeysList(value)
Steven M. Gava052937f2002-02-11 02:20:53 +0000583
Terry Jan Reedyae410862014-08-03 23:02:53 -0400584 def VarChanged_keysAreBuiltin(self, *params):
585 value = self.keysAreBuiltin.get()
586 self.AddChangedItem('main', 'Keys', 'default', value)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000587 if value:
Steven M. Gavaf31eec02002-03-05 00:25:58 +0000588 self.VarChanged_builtinKeys()
Steven M. Gava052937f2002-02-11 02:20:53 +0000589 else:
Steven M. Gavaf31eec02002-03-05 00:25:58 +0000590 self.VarChanged_customKeys()
Steven M. Gava052937f2002-02-11 02:20:53 +0000591
Terry Jan Reedyae410862014-08-03 23:02:53 -0400592 def VarChanged_winWidth(self, *params):
593 value = self.winWidth.get()
594 self.AddChangedItem('main', 'EditorWindow', 'width', value)
Steven M. Gavac112cd82002-01-22 05:56:40 +0000595
Terry Jan Reedyae410862014-08-03 23:02:53 -0400596 def VarChanged_winHeight(self, *params):
597 value = self.winHeight.get()
598 self.AddChangedItem('main', 'EditorWindow', 'height', value)
Steven M. Gavac112cd82002-01-22 05:56:40 +0000599
Terry Jan Reedyae410862014-08-03 23:02:53 -0400600 def VarChanged_startupEdit(self, *params):
601 value = self.startupEdit.get()
602 self.AddChangedItem('main', 'General', 'editor-on-startup', value)
Steven M. Gavac112cd82002-01-22 05:56:40 +0000603
Terry Jan Reedyae410862014-08-03 23:02:53 -0400604 def VarChanged_autoSave(self, *params):
605 value = self.autoSave.get()
606 self.AddChangedItem('main', 'General', 'autosave', value)
Kurt B. Kaiser6c638b62003-05-26 06:23:10 +0000607
Terry Jan Reedyae410862014-08-03 23:02:53 -0400608 def VarChanged_encoding(self, *params):
609 value = self.encoding.get()
610 self.AddChangedItem('main', 'EditorWindow', 'encoding', value)
Kurt B. Kaisera053f332003-05-10 00:49:56 +0000611
Steven M. Gavaa498af22002-02-01 01:33:36 +0000612 def ResetChangedItems(self):
Steven M. Gavab77d3432002-03-02 07:16:21 +0000613 #When any config item is changed in this dialog, an entry
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000614 #should be made in the relevant section (config type) of this
615 #dictionary. The key should be the config file section name and the
Steven M. Gavaa498af22002-02-01 01:33:36 +0000616 #value a dictionary, whose key:value pairs are item=value pairs for
617 #that config file section.
Terry Jan Reedyae410862014-08-03 23:02:53 -0400618 self.changedItems = {'main':{}, 'highlight':{}, 'keys':{},
619 'extensions':{}}
Steven M. Gavaa498af22002-02-01 01:33:36 +0000620
Terry Jan Reedyae410862014-08-03 23:02:53 -0400621 def AddChangedItem(self, typ, section, item, value):
622 value = str(value) #make sure we use a string
623 if section not in self.changedItems[typ]:
624 self.changedItems[typ][section] = {}
625 self.changedItems[typ][section][item] = value
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000626
Steven M. Gava5f28e8f2002-01-21 06:38:21 +0000627 def GetDefaultItems(self):
Terry Jan Reedyae410862014-08-03 23:02:53 -0400628 dItems={'main':{}, 'highlight':{}, 'keys':{}, 'extensions':{}}
Terry Jan Reedy110796f2014-07-27 04:07:18 -0400629 for configType in dItems:
Terry Jan Reedyae410862014-08-03 23:02:53 -0400630 sections = idleConf.GetSectionList('default', configType)
Steven M. Gava5f28e8f2002-01-21 06:38:21 +0000631 for section in sections:
Terry Jan Reedyae410862014-08-03 23:02:53 -0400632 dItems[configType][section] = {}
633 options = idleConf.defaultCfg[configType].GetOptionList(section)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000634 for option in options:
Terry Jan Reedyae410862014-08-03 23:02:53 -0400635 dItems[configType][section][option] = (
636 idleConf.defaultCfg[configType].Get(section, option))
Steven M. Gava5f28e8f2002-01-21 06:38:21 +0000637 return dItems
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000638
Steven M. Gava5f28e8f2002-01-21 06:38:21 +0000639 def SetThemeType(self):
640 if self.themeIsBuiltin.get():
641 self.optMenuThemeBuiltin.config(state=NORMAL)
642 self.optMenuThemeCustom.config(state=DISABLED)
643 self.buttonDeleteCustomTheme.config(state=DISABLED)
644 else:
645 self.optMenuThemeBuiltin.config(state=DISABLED)
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000646 self.radioThemeCustom.config(state=NORMAL)
Steven M. Gava5f28e8f2002-01-21 06:38:21 +0000647 self.optMenuThemeCustom.config(state=NORMAL)
648 self.buttonDeleteCustomTheme.config(state=NORMAL)
649
650 def SetKeysType(self):
Steven M. Gava052937f2002-02-11 02:20:53 +0000651 if self.keysAreBuiltin.get():
Steven M. Gava5f28e8f2002-01-21 06:38:21 +0000652 self.optMenuKeysBuiltin.config(state=NORMAL)
653 self.optMenuKeysCustom.config(state=DISABLED)
654 self.buttonDeleteCustomKeys.config(state=DISABLED)
655 else:
656 self.optMenuKeysBuiltin.config(state=DISABLED)
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000657 self.radioKeysCustom.config(state=NORMAL)
Steven M. Gava5f28e8f2002-01-21 06:38:21 +0000658 self.optMenuKeysCustom.config(state=NORMAL)
659 self.buttonDeleteCustomKeys.config(state=NORMAL)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000660
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000661 def GetNewKeys(self):
Terry Jan Reedyae410862014-08-03 23:02:53 -0400662 listIndex = self.listBindings.index(ANCHOR)
663 binding = self.listBindings.get(listIndex)
664 bindName = binding.split()[0] #first part, up to first space
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000665 if self.keysAreBuiltin.get():
Terry Jan Reedyae410862014-08-03 23:02:53 -0400666 currentKeySetName = self.builtinKeys.get()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000667 else:
Terry Jan Reedyae410862014-08-03 23:02:53 -0400668 currentKeySetName = self.customKeys.get()
669 currentBindings = idleConf.GetCurrentKeySet()
Terry Jan Reedy110796f2014-07-27 04:07:18 -0400670 if currentKeySetName in self.changedItems['keys']: #unsaved changes
Terry Jan Reedyae410862014-08-03 23:02:53 -0400671 keySetChanges = self.changedItems['keys'][currentKeySetName]
Terry Jan Reedy110796f2014-07-27 04:07:18 -0400672 for event in keySetChanges:
Terry Jan Reedyae410862014-08-03 23:02:53 -0400673 currentBindings[event] = keySetChanges[event].split()
674 currentKeySequences = currentBindings.values()
675 newKeys = GetKeysDialog(self, 'Get New Keys', bindName,
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000676 currentKeySequences).result
677 if newKeys: #new keys were specified
Steven M. Gava052937f2002-02-11 02:20:53 +0000678 if self.keysAreBuiltin.get(): #current key set is a built-in
Terry Jan Reedyae410862014-08-03 23:02:53 -0400679 message = ('Your changes will be saved as a new Custom Key Set.'
680 ' Enter a name for your new Custom Key Set below.')
681 newKeySet = self.GetNewKeysName(message)
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000682 if not newKeySet: #user cancelled custom key set creation
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000683 self.listBindings.select_set(listIndex)
684 self.listBindings.select_anchor(listIndex)
685 return
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000686 else: #create new custom key set based on previously active key set
687 self.CreateNewKeySet(newKeySet)
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000688 self.listBindings.delete(listIndex)
Terry Jan Reedyae410862014-08-03 23:02:53 -0400689 self.listBindings.insert(listIndex, bindName+' - '+newKeys)
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000690 self.listBindings.select_set(listIndex)
691 self.listBindings.select_anchor(listIndex)
Steven M. Gava052937f2002-02-11 02:20:53 +0000692 self.keyBinding.set(newKeys)
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000693 else:
694 self.listBindings.select_set(listIndex)
695 self.listBindings.select_anchor(listIndex)
696
Terry Jan Reedyae410862014-08-03 23:02:53 -0400697 def GetNewKeysName(self, message):
698 usedNames = (idleConf.GetSectionList('user', 'keys') +
699 idleConf.GetSectionList('default', 'keys'))
700 newKeySet = GetCfgSectionNameDialog(
701 self, 'New Custom Key Set', message, usedNames).result
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000702 return newKeySet
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000703
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000704 def SaveAsNewKeySet(self):
Terry Jan Reedyae410862014-08-03 23:02:53 -0400705 newKeysName = self.GetNewKeysName('New Key Set Name:')
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000706 if newKeysName:
707 self.CreateNewKeySet(newKeysName)
708
Terry Jan Reedyae410862014-08-03 23:02:53 -0400709 def KeyBindingSelected(self, event):
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000710 self.buttonNewKeys.config(state=NORMAL)
711
Terry Jan Reedyae410862014-08-03 23:02:53 -0400712 def CreateNewKeySet(self, newKeySetName):
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000713 #creates new custom key set based on the previously active key set,
714 #and makes the new key set active
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000715 if self.keysAreBuiltin.get():
Terry Jan Reedyae410862014-08-03 23:02:53 -0400716 prevKeySetName = self.builtinKeys.get()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000717 else:
Terry Jan Reedyae410862014-08-03 23:02:53 -0400718 prevKeySetName = self.customKeys.get()
719 prevKeys = idleConf.GetCoreKeys(prevKeySetName)
720 newKeys = {}
Terry Jan Reedy110796f2014-07-27 04:07:18 -0400721 for event in prevKeys: #add key set to changed items
Terry Jan Reedyae410862014-08-03 23:02:53 -0400722 eventName = event[2:-2] #trim off the angle brackets
723 binding = ' '.join(prevKeys[event])
724 newKeys[eventName] = binding
Steven M. Gava052937f2002-02-11 02:20:53 +0000725 #handle any unsaved changes to prev key set
Terry Jan Reedy110796f2014-07-27 04:07:18 -0400726 if prevKeySetName in self.changedItems['keys']:
Terry Jan Reedyae410862014-08-03 23:02:53 -0400727 keySetChanges = self.changedItems['keys'][prevKeySetName]
Terry Jan Reedy110796f2014-07-27 04:07:18 -0400728 for event in keySetChanges:
Terry Jan Reedyae410862014-08-03 23:02:53 -0400729 newKeys[event] = keySetChanges[event]
Steven M. Gava052937f2002-02-11 02:20:53 +0000730 #save the new theme
Terry Jan Reedyae410862014-08-03 23:02:53 -0400731 self.SaveNewKeySet(newKeySetName, newKeys)
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000732 #change gui over to the new key set
Terry Jan Reedyae410862014-08-03 23:02:53 -0400733 customKeyList = idleConf.GetSectionList('user', 'keys')
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000734 customKeyList.sort()
Terry Jan Reedyae410862014-08-03 23:02:53 -0400735 self.optMenuKeysCustom.SetMenu(customKeyList, newKeySetName)
Steven M. Gava052937f2002-02-11 02:20:53 +0000736 self.keysAreBuiltin.set(0)
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000737 self.SetKeysType()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000738
Terry Jan Reedyae410862014-08-03 23:02:53 -0400739 def LoadKeysList(self, keySetName):
740 reselect = 0
741 newKeySet = 0
Steven M. Gava052937f2002-02-11 02:20:53 +0000742 if self.listBindings.curselection():
Terry Jan Reedyae410862014-08-03 23:02:53 -0400743 reselect = 1
744 listIndex = self.listBindings.index(ANCHOR)
745 keySet = idleConf.GetKeySet(keySetName)
746 bindNames = keySet.keys()
Steven M. Gava052937f2002-02-11 02:20:53 +0000747 bindNames.sort()
Terry Jan Reedyae410862014-08-03 23:02:53 -0400748 self.listBindings.delete(0, END)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000749 for bindName in bindNames:
Terry Jan Reedyae410862014-08-03 23:02:53 -0400750 key = ' '.join(keySet[bindName]) #make key(s) into a string
751 bindName = bindName[2:-2] #trim off the angle brackets
Terry Jan Reedy110796f2014-07-27 04:07:18 -0400752 if keySetName in self.changedItems['keys']:
Steven M. Gava052937f2002-02-11 02:20:53 +0000753 #handle any unsaved changes to this key set
Terry Jan Reedy110796f2014-07-27 04:07:18 -0400754 if bindName in self.changedItems['keys'][keySetName]:
Terry Jan Reedyae410862014-08-03 23:02:53 -0400755 key = self.changedItems['keys'][keySetName][bindName]
Steven M. Gava052937f2002-02-11 02:20:53 +0000756 self.listBindings.insert(END, bindName+' - '+key)
Steven M. Gava052937f2002-02-11 02:20:53 +0000757 if reselect:
758 self.listBindings.see(listIndex)
759 self.listBindings.select_set(listIndex)
760 self.listBindings.select_anchor(listIndex)
761
Steven M. Gava49745752002-02-18 01:43:11 +0000762 def DeleteCustomKeys(self):
763 keySetName=self.customKeys.get()
Terry Jan Reedyae410862014-08-03 23:02:53 -0400764 delmsg = 'Are you sure you wish to delete the key set %r ?'
765 if not tkMessageBox.askyesno(
766 'Delete Key Set', delmsg % keySetName, parent=self):
Steven M. Gava49745752002-02-18 01:43:11 +0000767 return
768 #remove key set from config
769 idleConf.userCfg['keys'].remove_section(keySetName)
Benjamin Peterson6e3dbbd2009-10-09 22:15:50 +0000770 if keySetName in self.changedItems['keys']:
Steven M. Gava49745752002-02-18 01:43:11 +0000771 del(self.changedItems['keys'][keySetName])
772 #write changes
773 idleConf.userCfg['keys'].Save()
774 #reload user key set list
Terry Jan Reedyae410862014-08-03 23:02:53 -0400775 itemList = idleConf.GetSectionList('user', 'keys')
Steven M. Gava49745752002-02-18 01:43:11 +0000776 itemList.sort()
777 if not itemList:
778 self.radioKeysCustom.config(state=DISABLED)
Terry Jan Reedyae410862014-08-03 23:02:53 -0400779 self.optMenuKeysCustom.SetMenu(itemList, '- no custom keys -')
Steven M. Gava49745752002-02-18 01:43:11 +0000780 else:
Terry Jan Reedyae410862014-08-03 23:02:53 -0400781 self.optMenuKeysCustom.SetMenu(itemList, itemList[0])
Steven M. Gava49745752002-02-18 01:43:11 +0000782 #revert to default key set
Terry Jan Reedyae410862014-08-03 23:02:53 -0400783 self.keysAreBuiltin.set(idleConf.defaultCfg['main'].Get('Keys', 'default'))
784 self.builtinKeys.set(idleConf.defaultCfg['main'].Get('Keys', 'name'))
Steven M. Gava49745752002-02-18 01:43:11 +0000785 #user can't back out of these changes, they must be applied now
786 self.Apply()
787 self.SetKeysType()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000788
Steven M. Gava49745752002-02-18 01:43:11 +0000789 def DeleteCustomTheme(self):
Terry Jan Reedyae410862014-08-03 23:02:53 -0400790 themeName = self.customTheme.get()
791 delmsg = 'Are you sure you wish to delete the theme %r ?'
792 if not tkMessageBox.askyesno(
793 'Delete Theme', delmsg % themeName, parent=self):
Steven M. Gava49745752002-02-18 01:43:11 +0000794 return
795 #remove theme from config
796 idleConf.userCfg['highlight'].remove_section(themeName)
Benjamin Peterson6e3dbbd2009-10-09 22:15:50 +0000797 if themeName in self.changedItems['highlight']:
Steven M. Gava49745752002-02-18 01:43:11 +0000798 del(self.changedItems['highlight'][themeName])
799 #write changes
800 idleConf.userCfg['highlight'].Save()
801 #reload user theme list
Terry Jan Reedyae410862014-08-03 23:02:53 -0400802 itemList = idleConf.GetSectionList('user', 'highlight')
Steven M. Gava49745752002-02-18 01:43:11 +0000803 itemList.sort()
804 if not itemList:
805 self.radioThemeCustom.config(state=DISABLED)
Terry Jan Reedyae410862014-08-03 23:02:53 -0400806 self.optMenuThemeCustom.SetMenu(itemList, '- no custom themes -')
Steven M. Gava49745752002-02-18 01:43:11 +0000807 else:
Terry Jan Reedyae410862014-08-03 23:02:53 -0400808 self.optMenuThemeCustom.SetMenu(itemList, itemList[0])
Steven M. Gava49745752002-02-18 01:43:11 +0000809 #revert to default theme
Terry Jan Reedyae410862014-08-03 23:02:53 -0400810 self.themeIsBuiltin.set(idleConf.defaultCfg['main'].Get('Theme', 'default'))
811 self.builtinTheme.set(idleConf.defaultCfg['main'].Get('Theme', 'name'))
Steven M. Gava49745752002-02-18 01:43:11 +0000812 #user can't back out of these changes, they must be applied now
813 self.Apply()
814 self.SetThemeType()
815
Steven M. Gava5f28e8f2002-01-21 06:38:21 +0000816 def GetColour(self):
Terry Jan Reedyae410862014-08-03 23:02:53 -0400817 target = self.highlightTarget.get()
818 prevColour = self.frameColourSet.cget('bg')
819 rgbTuplet, colourString = tkColorChooser.askcolor(
820 parent=self, title='Pick new colour for : '+target,
821 initialcolor=prevColour)
822 if colourString and (colourString != prevColour):
Steven M. Gava052937f2002-02-11 02:20:53 +0000823 #user didn't cancel, and they chose a new colour
Terry Jan Reedyae410862014-08-03 23:02:53 -0400824 if self.themeIsBuiltin.get(): #current theme is a built-in
825 message = ('Your changes will be saved as a new Custom Theme. '
826 'Enter a name for your new Custom Theme below.')
827 newTheme = self.GetNewThemeName(message)
828 if not newTheme: #user cancelled custom theme creation
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000829 return
Terry Jan Reedyae410862014-08-03 23:02:53 -0400830 else: #create new custom theme based on previously active theme
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000831 self.CreateNewTheme(newTheme)
Steven M. Gava052937f2002-02-11 02:20:53 +0000832 self.colour.set(colourString)
Terry Jan Reedyae410862014-08-03 23:02:53 -0400833 else: #current theme is user defined
Steven M. Gava052937f2002-02-11 02:20:53 +0000834 self.colour.set(colourString)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000835
Steven M. Gava052937f2002-02-11 02:20:53 +0000836 def OnNewColourSet(self):
837 newColour=self.colour.get()
Terry Jan Reedyae410862014-08-03 23:02:53 -0400838 self.frameColourSet.config(bg=newColour) #set sample
839 plane ='foreground' if self.fgHilite.get() else 'background'
840 sampleElement = self.themeElements[self.highlightTarget.get()][0]
Raymond Hettinger931237e2003-07-09 18:48:24 +0000841 self.textHighlightSample.tag_config(sampleElement, **{plane:newColour})
Terry Jan Reedyae410862014-08-03 23:02:53 -0400842 theme = self.customTheme.get()
843 themeElement = sampleElement + '-' + plane
844 self.AddChangedItem('highlight', theme, themeElement, newColour)
Steven M. Gava052937f2002-02-11 02:20:53 +0000845
Terry Jan Reedyae410862014-08-03 23:02:53 -0400846 def GetNewThemeName(self, message):
847 usedNames = (idleConf.GetSectionList('user', 'highlight') +
848 idleConf.GetSectionList('default', 'highlight'))
849 newTheme = GetCfgSectionNameDialog(
850 self, 'New Custom Theme', message, usedNames).result
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000851 return newTheme
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000852
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000853 def SaveAsNewTheme(self):
Terry Jan Reedyae410862014-08-03 23:02:53 -0400854 newThemeName = self.GetNewThemeName('New Theme Name:')
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000855 if newThemeName:
856 self.CreateNewTheme(newThemeName)
857
Terry Jan Reedyae410862014-08-03 23:02:53 -0400858 def CreateNewTheme(self, newThemeName):
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000859 #creates new custom theme based on the previously active theme,
860 #and makes the new theme active
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000861 if self.themeIsBuiltin.get():
Terry Jan Reedyae410862014-08-03 23:02:53 -0400862 themeType = 'default'
863 themeName = self.builtinTheme.get()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000864 else:
Terry Jan Reedyae410862014-08-03 23:02:53 -0400865 themeType = 'user'
866 themeName = self.customTheme.get()
867 newTheme = idleConf.GetThemeDict(themeType, themeName)
Steven M. Gava052937f2002-02-11 02:20:53 +0000868 #apply any of the old theme's unsaved changes to the new theme
Terry Jan Reedy110796f2014-07-27 04:07:18 -0400869 if themeName in self.changedItems['highlight']:
Terry Jan Reedyae410862014-08-03 23:02:53 -0400870 themeChanges = self.changedItems['highlight'][themeName]
Terry Jan Reedy110796f2014-07-27 04:07:18 -0400871 for element in themeChanges:
Terry Jan Reedyae410862014-08-03 23:02:53 -0400872 newTheme[element] = themeChanges[element]
Steven M. Gava052937f2002-02-11 02:20:53 +0000873 #save the new theme
Terry Jan Reedyae410862014-08-03 23:02:53 -0400874 self.SaveNewTheme(newThemeName, newTheme)
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000875 #change gui over to the new theme
Terry Jan Reedyae410862014-08-03 23:02:53 -0400876 customThemeList = idleConf.GetSectionList('user', 'highlight')
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000877 customThemeList.sort()
Terry Jan Reedyae410862014-08-03 23:02:53 -0400878 self.optMenuThemeCustom.SetMenu(customThemeList, newThemeName)
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000879 self.themeIsBuiltin.set(0)
880 self.SetThemeType()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000881
Terry Jan Reedyae410862014-08-03 23:02:53 -0400882 def OnListFontButtonRelease(self, event):
Kurt B. Kaiser05391692003-05-26 20:35:53 +0000883 font = self.listFontName.get(ANCHOR)
884 self.fontName.set(font.lower())
Steven M. Gava5f28e8f2002-01-21 06:38:21 +0000885 self.SetFontSample()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000886
Terry Jan Reedyae410862014-08-03 23:02:53 -0400887 def SetFontSample(self, event=None):
888 fontName = self.fontName.get()
889 fontWeight = tkFont.BOLD if self.fontBold.get() else tkFont.NORMAL
Ned Deilye3d47122012-10-22 15:13:01 -0700890 newFont = (fontName, self.fontSize.get(), fontWeight)
891 self.labelFontSample.config(font=newFont)
892 self.textHighlightSample.configure(font=newFont)
Steven M. Gava5f28e8f2002-01-21 06:38:21 +0000893
Steven M. Gava5f28e8f2002-01-21 06:38:21 +0000894 def SetHighlightTarget(self):
Terry Jan Reedyae410862014-08-03 23:02:53 -0400895 if self.highlightTarget.get() == 'Cursor': #bg not possible
Steven M. Gava5f28e8f2002-01-21 06:38:21 +0000896 self.radioFg.config(state=DISABLED)
897 self.radioBg.config(state=DISABLED)
898 self.fgHilite.set(1)
Terry Jan Reedyae410862014-08-03 23:02:53 -0400899 else: #both fg and bg can be set
Steven M. Gava5f28e8f2002-01-21 06:38:21 +0000900 self.radioFg.config(state=NORMAL)
901 self.radioBg.config(state=NORMAL)
902 self.fgHilite.set(1)
903 self.SetColourSample()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000904
Terry Jan Reedyae410862014-08-03 23:02:53 -0400905 def SetColourSampleBinding(self, *args):
Steven M. Gava5f28e8f2002-01-21 06:38:21 +0000906 self.SetColourSample()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000907
Steven M. Gava5f28e8f2002-01-21 06:38:21 +0000908 def SetColourSample(self):
909 #set the colour smaple area
Terry Jan Reedyae410862014-08-03 23:02:53 -0400910 tag = self.themeElements[self.highlightTarget.get()][0]
911 plane = 'foreground' if self.fgHilite.get() else 'background'
912 colour = self.textHighlightSample.tag_cget(tag, plane)
Steven M. Gava5f28e8f2002-01-21 06:38:21 +0000913 self.frameColourSet.config(bg=colour)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000914
Steven M. Gava9dd16b32001-11-03 14:54:25 +0000915 def PaintThemeSample(self):
Terry Jan Reedyae410862014-08-03 23:02:53 -0400916 if self.themeIsBuiltin.get(): #a default theme
917 theme = self.builtinTheme.get()
918 else: #a user theme
919 theme = self.customTheme.get()
Terry Jan Reedy110796f2014-07-27 04:07:18 -0400920 for elementTitle in self.themeElements:
Terry Jan Reedyae410862014-08-03 23:02:53 -0400921 element = self.themeElements[elementTitle][0]
922 colours = idleConf.GetHighlight(theme, element)
923 if element == 'cursor': #cursor sample needs special painting
924 colours['background'] = idleConf.GetHighlight(
925 theme, 'normal', fgBg='bg')
Steven M. Gava052937f2002-02-11 02:20:53 +0000926 #handle any unsaved changes to this theme
Terry Jan Reedy110796f2014-07-27 04:07:18 -0400927 if theme in self.changedItems['highlight']:
Terry Jan Reedyae410862014-08-03 23:02:53 -0400928 themeDict = self.changedItems['highlight'][theme]
929 if element + '-foreground' in themeDict:
930 colours['foreground'] = themeDict[element + '-foreground']
931 if element + '-background' in themeDict:
932 colours['background'] = themeDict[element + '-background']
Raymond Hettinger931237e2003-07-09 18:48:24 +0000933 self.textHighlightSample.tag_config(element, **colours)
Steven M. Gava052937f2002-02-11 02:20:53 +0000934 self.SetColourSample()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000935
Terry Jan Reedyae410862014-08-03 23:02:53 -0400936 def HelpSourceSelected(self, event):
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000937 self.SetHelpListButtonStates()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000938
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000939 def SetHelpListButtonStates(self):
Terry Jan Reedyae410862014-08-03 23:02:53 -0400940 if self.listHelp.size() < 1: #no entries in list
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000941 self.buttonHelpListEdit.config(state=DISABLED)
942 self.buttonHelpListRemove.config(state=DISABLED)
943 else: #there are some entries
Terry Jan Reedyae410862014-08-03 23:02:53 -0400944 if self.listHelp.curselection(): #there currently is a selection
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000945 self.buttonHelpListEdit.config(state=NORMAL)
946 self.buttonHelpListRemove.config(state=NORMAL)
947 else: #there currently is not a selection
948 self.buttonHelpListEdit.config(state=DISABLED)
949 self.buttonHelpListRemove.config(state=DISABLED)
950
951 def HelpListItemAdd(self):
Terry Jan Reedyae410862014-08-03 23:02:53 -0400952 helpSource = GetHelpSourceDialog(self, 'New Help Source').result
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000953 if helpSource:
Terry Jan Reedyae410862014-08-03 23:02:53 -0400954 self.userHelpList.append((helpSource[0], helpSource[1]))
955 self.listHelp.insert(END, helpSource[0])
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000956 self.UpdateUserHelpChangedItems()
957 self.SetHelpListButtonStates()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000958
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000959 def HelpListItemEdit(self):
Terry Jan Reedyae410862014-08-03 23:02:53 -0400960 itemIndex = self.listHelp.index(ANCHOR)
961 helpSource = self.userHelpList[itemIndex]
962 newHelpSource = GetHelpSourceDialog(
963 self, 'Edit Help Source', menuItem=helpSource[0],
964 filePath=helpSource[1]).result
965 if (not newHelpSource) or (newHelpSource == helpSource):
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000966 return #no changes
Terry Jan Reedyae410862014-08-03 23:02:53 -0400967 self.userHelpList[itemIndex] = newHelpSource
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000968 self.listHelp.delete(itemIndex)
Terry Jan Reedyae410862014-08-03 23:02:53 -0400969 self.listHelp.insert(itemIndex, newHelpSource[0])
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000970 self.UpdateUserHelpChangedItems()
971 self.SetHelpListButtonStates()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000972
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000973 def HelpListItemRemove(self):
Terry Jan Reedyae410862014-08-03 23:02:53 -0400974 itemIndex = self.listHelp.index(ANCHOR)
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000975 del(self.userHelpList[itemIndex])
976 self.listHelp.delete(itemIndex)
977 self.UpdateUserHelpChangedItems()
978 self.SetHelpListButtonStates()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000979
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000980 def UpdateUserHelpChangedItems(self):
Kurt B. Kaiser8e92bf72003-01-14 22:03:31 +0000981 "Clear and rebuild the HelpFiles section in self.changedItems"
982 self.changedItems['main']['HelpFiles'] = {}
Terry Jan Reedyae410862014-08-03 23:02:53 -0400983 for num in range(1, len(self.userHelpList) + 1):
984 self.AddChangedItem(
985 'main', 'HelpFiles', str(num),
Terry Jan Reedy110796f2014-07-27 04:07:18 -0400986 ';'.join(self.userHelpList[num-1][:2]))
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000987
Steven M. Gava429a86a2001-10-23 10:42:12 +0000988 def LoadFontCfg(self):
989 ##base editor font selection list
Terry Jan Reedyae410862014-08-03 23:02:53 -0400990 fonts = list(tkFont.families(self))
Steven M. Gavac11ccf32001-09-24 09:43:17 +0000991 fonts.sort()
992 for font in fonts:
Terry Jan Reedyae410862014-08-03 23:02:53 -0400993 self.listFontName.insert(END, font)
Terry Jan Reedy12352142015-08-01 18:57:27 -0400994 configuredFont = idleConf.GetFont(self, 'main', 'EditorWindow')
995 fontName = configuredFont[0].lower()
996 fontSize = configuredFont[1]
997 fontBold = configuredFont[2]=='bold'
998 self.fontName.set(fontName)
Kurt B. Kaiser05391692003-05-26 20:35:53 +0000999 lc_fonts = [s.lower() for s in fonts]
Terry Jan Reedy12352142015-08-01 18:57:27 -04001000 try:
1001 currentFontIndex = lc_fonts.index(fontName)
Steven M. Gava429a86a2001-10-23 10:42:12 +00001002 self.listFontName.see(currentFontIndex)
1003 self.listFontName.select_set(currentFontIndex)
Steven M. Gavac112cd82002-01-22 05:56:40 +00001004 self.listFontName.select_anchor(currentFontIndex)
Terry Jan Reedy12352142015-08-01 18:57:27 -04001005 except ValueError:
1006 pass
Steven M. Gava429a86a2001-10-23 10:42:12 +00001007 ##font size dropdown
Terry Jan Reedyae410862014-08-03 23:02:53 -04001008 self.optMenuFontSize.SetMenu(('7', '8', '9', '10', '11', '12', '13',
1009 '14', '16', '18', '20', '22'), fontSize )
Steven M. Gavac112cd82002-01-22 05:56:40 +00001010 ##fontWeight
Terry Jan Reedy12352142015-08-01 18:57:27 -04001011 self.fontBold.set(fontBold)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001012 ##font sample
Steven M. Gava429a86a2001-10-23 10:42:12 +00001013 self.SetFontSample()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001014
Steven M. Gava429a86a2001-10-23 10:42:12 +00001015 def LoadTabCfg(self):
Steven M. Gava429a86a2001-10-23 10:42:12 +00001016 ##indent sizes
Terry Jan Reedyae410862014-08-03 23:02:53 -04001017 spaceNum = idleConf.GetOption(
1018 'main', 'Indent', 'num-spaces', default=4, type='int')
Steven M. Gava429a86a2001-10-23 10:42:12 +00001019 self.spaceNum.set(spaceNum)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001020
Steven M. Gava9dd16b32001-11-03 14:54:25 +00001021 def LoadThemeCfg(self):
Steven M. Gava41a85322001-10-29 08:05:34 +00001022 ##current theme type radiobutton
Terry Jan Reedyae410862014-08-03 23:02:53 -04001023 self.themeIsBuiltin.set(idleConf.GetOption(
1024 'main', 'Theme', 'default', type='bool', default=1))
Steven M. Gava41a85322001-10-29 08:05:34 +00001025 ##currently set theme
Terry Jan Reedyae410862014-08-03 23:02:53 -04001026 currentOption = idleConf.CurrentTheme()
Steven M. Gava7c017862001-10-29 11:19:46 +00001027 ##load available theme option menus
Steven M. Gavad0342cd2001-11-04 11:53:10 +00001028 if self.themeIsBuiltin.get(): #default theme selected
Terry Jan Reedyae410862014-08-03 23:02:53 -04001029 itemList = idleConf.GetSectionList('default', 'highlight')
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +00001030 itemList.sort()
Terry Jan Reedyae410862014-08-03 23:02:53 -04001031 self.optMenuThemeBuiltin.SetMenu(itemList, currentOption)
1032 itemList = idleConf.GetSectionList('user', 'highlight')
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +00001033 itemList.sort()
Steven M. Gava41a85322001-10-29 08:05:34 +00001034 if not itemList:
1035 self.radioThemeCustom.config(state=DISABLED)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001036 self.customTheme.set('- no custom themes -')
Steven M. Gava41a85322001-10-29 08:05:34 +00001037 else:
Terry Jan Reedyae410862014-08-03 23:02:53 -04001038 self.optMenuThemeCustom.SetMenu(itemList, itemList[0])
Steven M. Gava9dd16b32001-11-03 14:54:25 +00001039 else: #user theme selected
Terry Jan Reedyae410862014-08-03 23:02:53 -04001040 itemList = idleConf.GetSectionList('user', 'highlight')
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +00001041 itemList.sort()
Terry Jan Reedyae410862014-08-03 23:02:53 -04001042 self.optMenuThemeCustom.SetMenu(itemList, currentOption)
1043 itemList = idleConf.GetSectionList('default', 'highlight')
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +00001044 itemList.sort()
Terry Jan Reedyae410862014-08-03 23:02:53 -04001045 self.optMenuThemeBuiltin.SetMenu(itemList, itemList[0])
Steven M. Gava7c017862001-10-29 11:19:46 +00001046 self.SetThemeType()
1047 ##load theme element option menu
Terry Jan Reedyae410862014-08-03 23:02:53 -04001048 themeNames = self.themeElements.keys()
Florent Xiclunaa7f242f2010-04-02 08:15:26 +00001049 themeNames.sort(key=lambda x: self.themeElements[x][1])
Terry Jan Reedyae410862014-08-03 23:02:53 -04001050 self.optMenuHighlightTarget.SetMenu(themeNames, themeNames[0])
Steven M. Gava9dd16b32001-11-03 14:54:25 +00001051 self.PaintThemeSample()
Steven M. Gava0cae01c2002-01-04 07:53:06 +00001052 self.SetHighlightTarget()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001053
Steven M. Gava9dd16b32001-11-03 14:54:25 +00001054 def LoadKeyCfg(self):
Steven M. Gava41a85322001-10-29 08:05:34 +00001055 ##current keys type radiobutton
Terry Jan Reedyae410862014-08-03 23:02:53 -04001056 self.keysAreBuiltin.set(idleConf.GetOption(
1057 'main', 'Keys', 'default', type='bool', default=1))
Steven M. Gava41a85322001-10-29 08:05:34 +00001058 ##currently set keys
Terry Jan Reedyae410862014-08-03 23:02:53 -04001059 currentOption = idleConf.CurrentKeys()
Steven M. Gava7c017862001-10-29 11:19:46 +00001060 ##load available keyset option menus
Steven M. Gava052937f2002-02-11 02:20:53 +00001061 if self.keysAreBuiltin.get(): #default theme selected
Terry Jan Reedyae410862014-08-03 23:02:53 -04001062 itemList = idleConf.GetSectionList('default', 'keys')
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +00001063 itemList.sort()
Terry Jan Reedyae410862014-08-03 23:02:53 -04001064 self.optMenuKeysBuiltin.SetMenu(itemList, currentOption)
1065 itemList = idleConf.GetSectionList('user', 'keys')
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +00001066 itemList.sort()
Steven M. Gava41a85322001-10-29 08:05:34 +00001067 if not itemList:
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001068 self.radioKeysCustom.config(state=DISABLED)
1069 self.customKeys.set('- no custom keys -')
Steven M. Gava41a85322001-10-29 08:05:34 +00001070 else:
Terry Jan Reedyae410862014-08-03 23:02:53 -04001071 self.optMenuKeysCustom.SetMenu(itemList, itemList[0])
Steven M. Gavaa498af22002-02-01 01:33:36 +00001072 else: #user key set selected
Terry Jan Reedyae410862014-08-03 23:02:53 -04001073 itemList = idleConf.GetSectionList('user', 'keys')
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +00001074 itemList.sort()
Terry Jan Reedyae410862014-08-03 23:02:53 -04001075 self.optMenuKeysCustom.SetMenu(itemList, currentOption)
1076 itemList = idleConf.GetSectionList('default', 'keys')
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +00001077 itemList.sort()
Terry Jan Reedyae410862014-08-03 23:02:53 -04001078 self.optMenuKeysBuiltin.SetMenu(itemList, itemList[0])
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001079 self.SetKeysType()
Steven M. Gavafacfc092002-01-19 00:29:54 +00001080 ##load keyset element list
Terry Jan Reedyae410862014-08-03 23:02:53 -04001081 keySetName = idleConf.CurrentKeys()
Steven M. Gava052937f2002-02-11 02:20:53 +00001082 self.LoadKeysList(keySetName)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001083
Steven M. Gavafacfc092002-01-19 00:29:54 +00001084 def LoadGeneralCfg(self):
Steven M. Gava5f28e8f2002-01-21 06:38:21 +00001085 #startup state
Terry Jan Reedyae410862014-08-03 23:02:53 -04001086 self.startupEdit.set(idleConf.GetOption(
1087 'main', 'General', 'editor-on-startup', default=1, type='bool'))
Kurt B. Kaiser6c638b62003-05-26 06:23:10 +00001088 #autosave state
Terry Jan Reedyae410862014-08-03 23:02:53 -04001089 self.autoSave.set(idleConf.GetOption(
1090 'main', 'General', 'autosave', default=0, type='bool'))
Steven M. Gavafacfc092002-01-19 00:29:54 +00001091 #initial window size
Terry Jan Reedyae410862014-08-03 23:02:53 -04001092 self.winWidth.set(idleConf.GetOption(
1093 'main', 'EditorWindow', 'width', type='int'))
1094 self.winHeight.set(idleConf.GetOption(
1095 'main', 'EditorWindow', 'height', type='int'))
Kurt B. Kaisera053f332003-05-10 00:49:56 +00001096 # default source encoding
Terry Jan Reedyae410862014-08-03 23:02:53 -04001097 self.encoding.set(idleConf.GetOption(
1098 'main', 'EditorWindow', 'encoding', default='none'))
Kurt B. Kaiser8e92bf72003-01-14 22:03:31 +00001099 # additional help sources
1100 self.userHelpList = idleConf.GetAllExtraHelpSourcesList()
Steven M. Gava085eb1b2002-02-05 04:52:32 +00001101 for helpItem in self.userHelpList:
Terry Jan Reedyae410862014-08-03 23:02:53 -04001102 self.listHelp.insert(END, helpItem[0])
Steven M. Gava085eb1b2002-02-05 04:52:32 +00001103 self.SetHelpListButtonStates()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001104
Steven M. Gava429a86a2001-10-23 10:42:12 +00001105 def LoadConfigs(self):
1106 """
1107 load configuration from default and user config files and populate
1108 the widgets on the config dialog pages.
1109 """
1110 ### fonts / tabs page
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001111 self.LoadFontCfg()
1112 self.LoadTabCfg()
Steven M. Gava429a86a2001-10-23 10:42:12 +00001113 ### highlighting page
Steven M. Gava9dd16b32001-11-03 14:54:25 +00001114 self.LoadThemeCfg()
Steven M. Gava429a86a2001-10-23 10:42:12 +00001115 ### keys page
Steven M. Gava9dd16b32001-11-03 14:54:25 +00001116 self.LoadKeyCfg()
Steven M. Gava429a86a2001-10-23 10:42:12 +00001117 ### general page
Steven M. Gavafacfc092002-01-19 00:29:54 +00001118 self.LoadGeneralCfg()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001119
Terry Jan Reedyae410862014-08-03 23:02:53 -04001120 def SaveNewKeySet(self, keySetName, keySet):
Steven M. Gava052937f2002-02-11 02:20:53 +00001121 """
1122 save a newly created core key set.
1123 keySetName - string, the name of the new key set
1124 keySet - dictionary containing the new key set
1125 """
1126 if not idleConf.userCfg['keys'].has_section(keySetName):
1127 idleConf.userCfg['keys'].add_section(keySetName)
Terry Jan Reedy110796f2014-07-27 04:07:18 -04001128 for event in keySet:
Terry Jan Reedyae410862014-08-03 23:02:53 -04001129 value = keySet[event]
1130 idleConf.userCfg['keys'].SetOption(keySetName, event, value)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001131
Terry Jan Reedyae410862014-08-03 23:02:53 -04001132 def SaveNewTheme(self, themeName, theme):
Steven M. Gava052937f2002-02-11 02:20:53 +00001133 """
1134 save a newly created theme.
1135 themeName - string, the name of the new theme
1136 theme - dictionary containing the new theme
1137 """
1138 if not idleConf.userCfg['highlight'].has_section(themeName):
1139 idleConf.userCfg['highlight'].add_section(themeName)
Terry Jan Reedy110796f2014-07-27 04:07:18 -04001140 for element in theme:
Terry Jan Reedyae410862014-08-03 23:02:53 -04001141 value = theme[element]
1142 idleConf.userCfg['highlight'].SetOption(themeName, element, value)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001143
Terry Jan Reedyae410862014-08-03 23:02:53 -04001144 def SetUserValue(self, configType, section, item, value):
1145 if idleConf.defaultCfg[configType].has_option(section, item):
1146 if idleConf.defaultCfg[configType].Get(section, item) == value:
Steven M. Gava2d7bb3f2002-01-29 08:35:29 +00001147 #the setting equals a default setting, remove it from user cfg
Terry Jan Reedyae410862014-08-03 23:02:53 -04001148 return idleConf.userCfg[configType].RemoveOption(section, item)
Steven M. Gava2d7bb3f2002-01-29 08:35:29 +00001149 #if we got here set the option
Terry Jan Reedyae410862014-08-03 23:02:53 -04001150 return idleConf.userCfg[configType].SetOption(section, item, value)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001151
Steven M. Gava052937f2002-02-11 02:20:53 +00001152 def SaveAllChangedConfigs(self):
Kurt B. Kaisere7a161e2003-01-10 20:13:57 +00001153 "Save configuration changes to the user config file."
Steven M. Gava0c5bc8c2002-03-27 02:25:44 +00001154 idleConf.userCfg['main'].Save()
Terry Jan Reedy110796f2014-07-27 04:07:18 -04001155 for configType in self.changedItems:
Kurt B. Kaisere7a161e2003-01-10 20:13:57 +00001156 cfgTypeHasChanges = False
Terry Jan Reedy110796f2014-07-27 04:07:18 -04001157 for section in self.changedItems[configType]:
Kurt B. Kaisere7a161e2003-01-10 20:13:57 +00001158 if section == 'HelpFiles':
1159 #this section gets completely replaced
1160 idleConf.userCfg['main'].remove_section('HelpFiles')
Kurt B. Kaiser8e92bf72003-01-14 22:03:31 +00001161 cfgTypeHasChanges = True
Terry Jan Reedy110796f2014-07-27 04:07:18 -04001162 for item in self.changedItems[configType][section]:
Kurt B. Kaisere7a161e2003-01-10 20:13:57 +00001163 value = self.changedItems[configType][section][item]
Terry Jan Reedyae410862014-08-03 23:02:53 -04001164 if self.SetUserValue(configType, section, item, value):
Kurt B. Kaisere7a161e2003-01-10 20:13:57 +00001165 cfgTypeHasChanges = True
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001166 if cfgTypeHasChanges:
1167 idleConf.userCfg[configType].Save()
Kurt B. Kaiser5acdf932004-11-16 21:28:36 +00001168 for configType in ['keys', 'highlight']:
1169 # save these even if unchanged!
1170 idleConf.userCfg[configType].Save()
Steven M. Gavaa498af22002-02-01 01:33:36 +00001171 self.ResetChangedItems() #clear the changed items dict
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001172
Kurt B. Kaiserb1754452005-11-18 22:05:48 +00001173 def DeactivateCurrentConfig(self):
1174 #Before a config is saved, some cleanup of current
1175 #config must be done - remove the previous keybindings
Terry Jan Reedyae410862014-08-03 23:02:53 -04001176 winInstances = self.parent.instance_dict
Kurt B. Kaiserb1754452005-11-18 22:05:48 +00001177 for instance in winInstances:
1178 instance.RemoveKeybindings()
1179
Steven M. Gava49745752002-02-18 01:43:11 +00001180 def ActivateConfigChanges(self):
Kurt B. Kaiseracdef852005-01-31 03:34:26 +00001181 "Dynamically apply configuration changes"
Terry Jan Reedy110796f2014-07-27 04:07:18 -04001182 winInstances = self.parent.instance_dict.keys()
Steven M. Gavab77d3432002-03-02 07:16:21 +00001183 for instance in winInstances:
1184 instance.ResetColorizer()
Steven M. Gavab1585412002-03-12 00:21:56 +00001185 instance.ResetFont()
Kurt B. Kaiseracdef852005-01-31 03:34:26 +00001186 instance.set_notabs_indentwidth()
Kurt B. Kaiserb1754452005-11-18 22:05:48 +00001187 instance.ApplyKeybindings()
Kurt B. Kaiser8e92bf72003-01-14 22:03:31 +00001188 instance.reset_help_menu_entries()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001189
Steven M. Gava5f28e8f2002-01-21 06:38:21 +00001190 def Cancel(self):
1191 self.destroy()
1192
1193 def Ok(self):
1194 self.Apply()
1195 self.destroy()
1196
1197 def Apply(self):
Kurt B. Kaiserb1754452005-11-18 22:05:48 +00001198 self.DeactivateCurrentConfig()
Steven M. Gava052937f2002-02-11 02:20:53 +00001199 self.SaveAllChangedConfigs()
Steven M. Gava49745752002-02-18 01:43:11 +00001200 self.ActivateConfigChanges()
Steven M. Gava5f28e8f2002-01-21 06:38:21 +00001201
1202 def Help(self):
Steven M. Gavac11ccf32001-09-24 09:43:17 +00001203 pass
1204
Terry Jan Reedy7a162072014-10-22 20:15:12 -04001205class VerticalScrolledFrame(Frame):
1206 """A pure Tkinter vertically scrollable frame.
1207
1208 * Use the 'interior' attribute to place widgets inside the scrollable frame
1209 * Construct and pack/place/grid normally
1210 * This frame only allows vertical scrolling
1211 """
1212 def __init__(self, parent, *args, **kw):
1213 Frame.__init__(self, parent, *args, **kw)
1214
1215 # create a canvas object and a vertical scrollbar for scrolling it
1216 vscrollbar = Scrollbar(self, orient=VERTICAL)
1217 vscrollbar.pack(fill=Y, side=RIGHT, expand=FALSE)
1218 canvas = Canvas(self, bd=0, highlightthickness=0,
1219 yscrollcommand=vscrollbar.set)
1220 canvas.pack(side=LEFT, fill=BOTH, expand=TRUE)
1221 vscrollbar.config(command=canvas.yview)
1222
1223 # reset the view
1224 canvas.xview_moveto(0)
1225 canvas.yview_moveto(0)
1226
1227 # create a frame inside the canvas which will be scrolled with it
1228 self.interior = interior = Frame(canvas)
1229 interior_id = canvas.create_window(0, 0, window=interior, anchor=NW)
1230
1231 # track changes to the canvas and frame width and sync them,
1232 # also updating the scrollbar
1233 def _configure_interior(event):
1234 # update the scrollbars to match the size of the inner frame
1235 size = (interior.winfo_reqwidth(), interior.winfo_reqheight())
1236 canvas.config(scrollregion="0 0 %s %s" % size)
Terry Jan Reedy7a162072014-10-22 20:15:12 -04001237 interior.bind('<Configure>', _configure_interior)
1238
1239 def _configure_canvas(event):
1240 if interior.winfo_reqwidth() != canvas.winfo_width():
1241 # update the inner frame's width to fill the canvas
1242 canvas.itemconfigure(interior_id, width=canvas.winfo_width())
1243 canvas.bind('<Configure>', _configure_canvas)
1244
1245 return
1246
1247def is_int(s):
1248 "Return 's is blank or represents an int'"
1249 if not s:
1250 return True
1251 try:
1252 int(s)
1253 return True
1254 except ValueError:
1255 return False
1256
1257# TODO:
1258# * Revert to default(s)? Per option or per extension?
1259# * List options in their original order (possible??)
1260class ConfigExtensionsDialog(Toplevel):
1261 """A dialog for configuring IDLE extensions.
1262
1263 This dialog is generic - it works for any and all IDLE extensions.
1264
1265 IDLE extensions save their configuration options using idleConf.
1266 ConfigExtensionsDialog reads the current configuration using idleConf,
1267 supplies a GUI interface to change the configuration values, and saves the
1268 changes using idleConf.
1269
1270 Not all changes take effect immediately - some may require restarting IDLE.
1271 This depends on each extension's implementation.
1272
1273 All values are treated as text, and it is up to the user to supply
1274 reasonable values. The only exception to this are the 'enable*' options,
1275 which are boolean, and can be toggled with an True/False button.
1276 """
1277 def __init__(self, parent, title=None, _htest=False):
1278 Toplevel.__init__(self, parent)
1279 self.wm_withdraw()
1280
1281 self.configure(borderwidth=5)
1282 self.geometry(
1283 "+%d+%d" % (parent.winfo_rootx() + 20,
1284 parent.winfo_rooty() + (30 if not _htest else 150)))
1285 self.wm_title(title or 'IDLE Extensions Configuration')
1286
1287 self.defaultCfg = idleConf.defaultCfg['extensions']
1288 self.userCfg = idleConf.userCfg['extensions']
1289 self.is_int = self.register(is_int)
1290 self.load_extensions()
1291 self.create_widgets()
1292
1293 self.resizable(height=FALSE, width=FALSE) # don't allow resizing yet
1294 self.transient(parent)
1295 self.protocol("WM_DELETE_WINDOW", self.Cancel)
1296 self.tabbed_page_set.focus_set()
1297 # wait for window to be generated
1298 self.update()
1299 # set current width as the minimum width
1300 self.wm_minsize(self.winfo_width(), 1)
1301 # now allow resizing
1302 self.resizable(height=TRUE, width=TRUE)
1303
1304 self.wm_deiconify()
1305 if not _htest:
1306 self.grab_set()
1307 self.wait_window()
1308
1309 def load_extensions(self):
1310 "Fill self.extensions with data from the default and user configs."
1311 self.extensions = {}
1312 for ext_name in idleConf.GetExtensions(active_only=False):
1313 self.extensions[ext_name] = []
1314
1315 for ext_name in self.extensions:
1316 opt_list = sorted(self.defaultCfg.GetOptionList(ext_name))
1317
1318 # bring 'enable' options to the beginning of the list
1319 enables = [opt_name for opt_name in opt_list
1320 if opt_name.startswith('enable')]
1321 for opt_name in enables:
1322 opt_list.remove(opt_name)
1323 opt_list = enables + opt_list
1324
1325 for opt_name in opt_list:
1326 def_str = self.defaultCfg.Get(
1327 ext_name, opt_name, raw=True)
1328 try:
1329 def_obj = {'True':True, 'False':False}[def_str]
1330 opt_type = 'bool'
1331 except KeyError:
1332 try:
1333 def_obj = int(def_str)
1334 opt_type = 'int'
1335 except ValueError:
1336 def_obj = def_str
1337 opt_type = None
1338 try:
1339 value = self.userCfg.Get(
1340 ext_name, opt_name, type=opt_type, raw=True,
1341 default=def_obj)
1342 except ValueError: # Need this until .Get fixed
1343 value = def_obj # bad values overwritten by entry
1344 var = StringVar(self)
1345 var.set(str(value))
1346
1347 self.extensions[ext_name].append({'name': opt_name,
1348 'type': opt_type,
1349 'default': def_str,
1350 'value': value,
1351 'var': var,
1352 })
1353
1354 def create_widgets(self):
1355 """Create the dialog's widgets."""
Terry Jan Reedy936a6f12015-08-26 23:13:16 -04001356 self.extension_names = StringVar(self)
Terry Jan Reedy7a162072014-10-22 20:15:12 -04001357 self.rowconfigure(0, weight=1)
Terry Jan Reedy936a6f12015-08-26 23:13:16 -04001358 self.columnconfigure(2, weight=1)
1359 self.extension_list = Listbox(self, listvariable=self.extension_names,
1360 selectmode='browse')
1361 self.extension_list.bind('<<ListboxSelect>>', self.extension_selected)
1362 scroll = Scrollbar(self, command=self.extension_list.yview)
1363 self.extension_list.yscrollcommand=scroll.set
1364 self.details_frame = LabelFrame(self, width=250, height=250)
1365 self.extension_list.grid(column=0, row=0, sticky='nws')
1366 scroll.grid(column=1, row=0, sticky='ns')
1367 self.details_frame.grid(column=2, row=0, sticky='nsew', padx=[10, 0])
1368 self.configure(padx=10, pady=10)
1369 self.config_frame = {}
1370 self.current_extension = None
Terry Jan Reedy7a162072014-10-22 20:15:12 -04001371
Terry Jan Reedy936a6f12015-08-26 23:13:16 -04001372 self.outerframe = self # TEMPORARY
1373 self.tabbed_page_set = self.extension_list # TEMPORARY
Terry Jan Reedy7a162072014-10-22 20:15:12 -04001374
Terry Jan Reedy936a6f12015-08-26 23:13:16 -04001375 # create the individual pages
1376 ext_names = ''
1377 for ext_name in sorted(self.extensions):
1378 self.create_extension_frame(ext_name)
1379 ext_names = ext_names + '{' + ext_name + '} '
1380 self.extension_names.set(ext_names)
1381 self.extension_list.selection_set(0)
1382 self.extension_selected(None)
1383 self.create_action_buttons().grid(row=1, columnspan=3)
1384
1385 def extension_selected(self, event):
1386 newsel = self.extension_list.curselection()
1387 if newsel:
1388 newsel = self.extension_list.get(newsel)
1389 if newsel is None or newsel != self.current_extension:
1390 if self.current_extension:
1391 self.details_frame.config(text='')
1392 self.config_frame[self.current_extension].grid_forget()
1393 self.current_extension = None
1394 if newsel:
1395 self.details_frame.config(text=newsel)
1396 self.config_frame[newsel].grid(column=0, row=0, sticky='nsew')
1397 self.current_extension = newsel
Terry Jan Reedy7a162072014-10-22 20:15:12 -04001398
1399 create_action_buttons = ConfigDialog.create_action_buttons.im_func
1400
Terry Jan Reedy936a6f12015-08-26 23:13:16 -04001401 def create_extension_frame(self, ext_name):
1402 """Create a frame holding the widgets to configure one extension"""
1403 f = VerticalScrolledFrame(self.details_frame, height=250, width=250)
1404 self.config_frame[ext_name] = f
1405 entry_area = f.interior
Terry Jan Reedy7a162072014-10-22 20:15:12 -04001406 # create an entry for each configuration option
1407 for row, opt in enumerate(self.extensions[ext_name]):
1408 # create a row with a label and entry/checkbutton
1409 label = Label(entry_area, text=opt['name'])
1410 label.grid(row=row, column=0, sticky=NW)
1411 var = opt['var']
1412 if opt['type'] == 'bool':
1413 Checkbutton(entry_area, textvariable=var, variable=var,
1414 onvalue='True', offvalue='False',
1415 indicatoron=FALSE, selectcolor='', width=8
Terry Jan Reedy936a6f12015-08-26 23:13:16 -04001416 ).grid(row=row, column=1, sticky=W, padx=7)
Terry Jan Reedy7a162072014-10-22 20:15:12 -04001417 elif opt['type'] == 'int':
1418 Entry(entry_area, textvariable=var, validate='key',
Terry Jan Reedy936a6f12015-08-26 23:13:16 -04001419 validatecommand=(self.is_int, '%P')
1420 ).grid(row=row, column=1, sticky=NSEW, padx=7)
Terry Jan Reedy7a162072014-10-22 20:15:12 -04001421
1422 else:
1423 Entry(entry_area, textvariable=var
Terry Jan Reedy936a6f12015-08-26 23:13:16 -04001424 ).grid(row=row, column=1, sticky=NSEW, padx=7)
Terry Jan Reedy7a162072014-10-22 20:15:12 -04001425 return
1426
1427
1428 Ok = ConfigDialog.Ok.im_func
1429
1430 def Apply(self):
1431 self.save_all_changed_configs()
1432 pass
1433
1434 Cancel = ConfigDialog.Cancel.im_func
1435
1436 def Help(self):
1437 pass
1438
1439 def set_user_value(self, section, opt):
1440 name = opt['name']
1441 default = opt['default']
1442 value = opt['var'].get().strip() or default
1443 opt['var'].set(value)
1444 # if self.defaultCfg.has_section(section):
1445 # Currently, always true; if not, indent to return
1446 if (value == default):
1447 return self.userCfg.RemoveOption(section, name)
1448 # set the option
1449 return self.userCfg.SetOption(section, name, value)
1450
1451 def save_all_changed_configs(self):
1452 """Save configuration changes to the user config file."""
1453 has_changes = False
1454 for ext_name in self.extensions:
1455 options = self.extensions[ext_name]
1456 for opt in options:
1457 if self.set_user_value(ext_name, opt):
1458 has_changes = True
1459 if has_changes:
1460 self.userCfg.Save()
1461
1462
Steven M. Gava44d3d1a2001-07-31 06:59:02 +00001463if __name__ == '__main__':
Terry Jan Reedyaf0dce92014-07-14 23:07:21 -04001464 import unittest
1465 unittest.main('idlelib.idle_test.test_configdialog',
1466 verbosity=2, exit=False)
Terry Jan Reedy76916e82014-05-29 01:46:16 -04001467 from idlelib.idle_test.htest import run
Terry Jan Reedy7a162072014-10-22 20:15:12 -04001468 run(ConfigDialog, ConfigExtensionsDialog)