blob: c416151d9d5869f8886a00da66aa24a4fea71729 [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
17from idlelib.tabbedpages import TabbedPageSet
18from idlelib.keybindingDialog import GetKeysDialog
19from idlelib.configSectionNameDialog import GetCfgSectionNameDialog
20from idlelib.configHelpSourceEdit import GetHelpSourceDialog
Terry Jan Reedy7a162072014-10-22 20:15:12 -040021from idlelib.tabbedpages import TabbedPageSet
Florent Xiclunad630c042010-04-02 07:24:52 +000022from idlelib import macosxSupport
Steven M. Gava44d3d1a2001-07-31 06:59:02 +000023class ConfigDialog(Toplevel):
Kurt B. Kaiseracdef852005-01-31 03:34:26 +000024
Terry Jan Reedycf834762014-10-17 01:31:29 -040025 def __init__(self, parent, title='', _htest=False, _utest=False):
Terry Jan Reedy76916e82014-05-29 01:46:16 -040026 """
27 _htest - bool, change box location when running htest
Terry Jan Reedyaf0dce92014-07-14 23:07:21 -040028 _utest - bool, don't wait_window when running unittest
Terry Jan Reedy76916e82014-05-29 01:46:16 -040029 """
Steven M. Gavad721c482001-07-31 10:46:53 +000030 Toplevel.__init__(self, parent)
Terry Jan Reedy19b7a752014-07-30 19:24:26 -040031 self.parent = parent
Terry Jan Reedyae410862014-08-03 23:02:53 -040032 if _htest:
33 parent.instance_dict = {}
Kurt B. Kaisere3fde8f2007-10-04 03:11:12 +000034 self.wm_withdraw()
35
Steven M. Gavad721c482001-07-31 10:46:53 +000036 self.configure(borderwidth=5)
Terry Jan Reedycf834762014-10-17 01:31:29 -040037 self.title(title or 'IDLE Preferences')
Terry Jan Reedyae410862014-08-03 23:02:53 -040038 self.geometry(
39 "+%d+%d" % (parent.winfo_rootx() + 20,
40 parent.winfo_rooty() + (30 if not _htest else 150)))
Georg Brandl7eb4b7d2005-07-22 21:49:32 +000041 #Theme Elements. Each theme element key is its display name.
Steven M. Gava9dd16b32001-11-03 14:54:25 +000042 #The first value of the tuple is the sample area tag name.
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +000043 #The second value is the display name list sort index.
Terry Jan Reedyae410862014-08-03 23:02:53 -040044 self.themeElements={
45 'Normal Text':('normal', '00'),
46 'Python Keywords':('keyword', '01'),
47 'Python Definitions':('definition', '02'),
Kurt B. Kaiser73360a32004-03-08 18:15:31 +000048 'Python Builtins':('builtin', '03'),
Terry Jan Reedyae410862014-08-03 23:02:53 -040049 'Python Comments':('comment', '04'),
50 'Python Strings':('string', '05'),
51 'Selected Text':('hilite', '06'),
52 'Found Text':('hit', '07'),
53 'Cursor':('cursor', '08'),
54 'Error Text':('error', '09'),
55 'Shell Normal Text':('console', '10'),
56 'Shell Stdout Text':('stdout', '11'),
57 'Shell Stderr Text':('stderr', '12'),
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'),
221 ('None', 'builtin'), (')\n\n', 'normal'),
222 (' error ', 'error'), (' ', 'normal'),
223 ('cursor |', 'cursor'), ('\n ', 'normal'),
224 ('shell', 'console'), (' ', 'normal'),
225 ('stdout', 'stdout'), (' ', 'normal'),
226 ('stderr', 'stderr'), ('\n', 'normal'))
Steven M. Gava9dd16b32001-11-03 14:54:25 +0000227 for txTa in textAndTags:
Terry Jan Reedyae410862014-08-03 23:02:53 -0400228 text.insert(END, txTa[0], txTa[1])
Terry Jan Reedy110796f2014-07-27 04:07:18 -0400229 for element in self.themeElements:
Terry Jan Reedyae410862014-08-03 23:02:53 -0400230 def tem(event, elem=element):
231 event.widget.winfo_toplevel().highlightTarget.set(elem)
232 text.tag_bind(
233 self.themeElements[element][0], '<ButtonPress-1>', tem)
Steven M. Gavae16d94b2001-11-03 05:07:28 +0000234 text.config(state=DISABLED)
Terry Jan Reedyae410862014-08-03 23:02:53 -0400235 self.frameColourSet = Frame(frameCustom, relief=SOLID, borderwidth=1)
236 frameFgBg = Frame(frameCustom)
237 buttonSetColour = Button(
238 self.frameColourSet, text='Choose Colour for :',
239 command=self.GetColour, highlightthickness=0)
240 self.optMenuHighlightTarget = DynOptionMenu(
241 self.frameColourSet, self.highlightTarget, None,
242 highlightthickness=0) #, command=self.SetHighlightTargetBinding
243 self.radioFg = Radiobutton(
244 frameFgBg, variable=self.fgHilite, value=1,
245 text='Foreground', command=self.SetColourSampleBinding)
246 self.radioBg=Radiobutton(
247 frameFgBg, variable=self.fgHilite, value=0,
248 text='Background', command=self.SetColourSampleBinding)
Steven M. Gava7c017862001-10-29 11:19:46 +0000249 self.fgHilite.set(1)
Terry Jan Reedyae410862014-08-03 23:02:53 -0400250 buttonSaveCustomTheme = Button(
251 frameCustom, text='Save as New Custom Theme',
252 command=self.SaveAsNewTheme)
Steven M. Gava952d0a52001-08-03 04:43:44 +0000253 #frameTheme
Terry Jan Reedyae410862014-08-03 23:02:53 -0400254 labelTypeTitle = Label(frameTheme, text='Select : ')
255 self.radioThemeBuiltin = Radiobutton(
256 frameTheme, variable=self.themeIsBuiltin, value=1,
257 command=self.SetThemeType, text='a Built-in Theme')
258 self.radioThemeCustom = Radiobutton(
259 frameTheme, variable=self.themeIsBuiltin, value=0,
260 command=self.SetThemeType, text='a Custom Theme')
261 self.optMenuThemeBuiltin = DynOptionMenu(
262 frameTheme, self.builtinTheme, None, command=None)
263 self.optMenuThemeCustom=DynOptionMenu(
264 frameTheme, self.customTheme, None, command=None)
265 self.buttonDeleteCustomTheme=Button(
266 frameTheme, text='Delete Custom Theme',
Steven M. Gava49745752002-02-18 01:43:11 +0000267 command=self.DeleteCustomTheme)
Terry Jan Reedy19b7a752014-07-30 19:24:26 -0400268
Steven M. Gava952d0a52001-08-03 04:43:44 +0000269 ##widget packing
270 #body
Terry Jan Reedyae410862014-08-03 23:02:53 -0400271 frameCustom.pack(side=LEFT, padx=5, pady=5, expand=TRUE, fill=BOTH)
272 frameTheme.pack(side=LEFT, padx=5, pady=5, fill=Y)
Steven M. Gava952d0a52001-08-03 04:43:44 +0000273 #frameCustom
Terry Jan Reedyae410862014-08-03 23:02:53 -0400274 self.frameColourSet.pack(side=TOP, padx=5, pady=5, expand=TRUE, fill=X)
275 frameFgBg.pack(side=TOP, padx=5, pady=0)
276 self.textHighlightSample.pack(
277 side=TOP, padx=5, pady=5, expand=TRUE, fill=BOTH)
278 buttonSetColour.pack(side=TOP, expand=TRUE, fill=X, padx=8, pady=4)
279 self.optMenuHighlightTarget.pack(
280 side=TOP, expand=TRUE, fill=X, padx=8, pady=3)
281 self.radioFg.pack(side=LEFT, anchor=E)
282 self.radioBg.pack(side=RIGHT, anchor=W)
283 buttonSaveCustomTheme.pack(side=BOTTOM, fill=X, padx=5, pady=5)
Steven M. Gava952d0a52001-08-03 04:43:44 +0000284 #frameTheme
Terry Jan Reedyae410862014-08-03 23:02:53 -0400285 labelTypeTitle.pack(side=TOP, anchor=W, padx=5, pady=5)
286 self.radioThemeBuiltin.pack(side=TOP, anchor=W, padx=5)
287 self.radioThemeCustom.pack(side=TOP, anchor=W, padx=5, pady=2)
288 self.optMenuThemeBuiltin.pack(side=TOP, fill=X, padx=5, pady=5)
289 self.optMenuThemeCustom.pack(side=TOP, fill=X, anchor=W, padx=5, pady=5)
290 self.buttonDeleteCustomTheme.pack(side=TOP, fill=X, padx=5, pady=5)
Steven M. Gava952d0a52001-08-03 04:43:44 +0000291 return frame
292
293 def CreatePageKeys(self):
Terry Jan Reedy19b7a752014-07-30 19:24:26 -0400294 parent = self.parent
295 self.bindingTarget = StringVar(parent)
296 self.builtinKeys = StringVar(parent)
297 self.customKeys = StringVar(parent)
298 self.keysAreBuiltin = BooleanVar(parent)
299 self.keyBinding = StringVar(parent)
300
Steven M. Gava60fc7072001-08-04 13:58:22 +0000301 ##widget creation
302 #body frame
Terry Jan Reedyae410862014-08-03 23:02:53 -0400303 frame = self.tabPages.pages['Keys'].frame
Steven M. Gava60fc7072001-08-04 13:58:22 +0000304 #body section frames
Terry Jan Reedyae410862014-08-03 23:02:53 -0400305 frameCustom = LabelFrame(
306 frame, borderwidth=2, relief=GROOVE,
307 text=' Custom Key Bindings ')
308 frameKeySets = LabelFrame(
309 frame, borderwidth=2, relief=GROOVE, text=' Key Set ')
Steven M. Gava60fc7072001-08-04 13:58:22 +0000310 #frameCustom
Terry Jan Reedyae410862014-08-03 23:02:53 -0400311 frameTarget = Frame(frameCustom)
312 labelTargetTitle = Label(frameTarget, text='Action - Key(s)')
313 scrollTargetY = Scrollbar(frameTarget)
314 scrollTargetX = Scrollbar(frameTarget, orient=HORIZONTAL)
315 self.listBindings = Listbox(
316 frameTarget, takefocus=FALSE, exportselection=FALSE)
317 self.listBindings.bind('<ButtonRelease-1>', self.KeyBindingSelected)
Steven M. Gavafacfc092002-01-19 00:29:54 +0000318 scrollTargetY.config(command=self.listBindings.yview)
319 scrollTargetX.config(command=self.listBindings.xview)
320 self.listBindings.config(yscrollcommand=scrollTargetY.set)
321 self.listBindings.config(xscrollcommand=scrollTargetX.set)
Terry Jan Reedyae410862014-08-03 23:02:53 -0400322 self.buttonNewKeys = Button(
323 frameCustom, text='Get New Keys for Selection',
324 command=self.GetNewKeys, state=DISABLED)
Steven M. Gava60fc7072001-08-04 13:58:22 +0000325 #frameKeySets
Kurt B. Kaiser28c7bcf2007-12-28 04:18:01 +0000326 frames = [Frame(frameKeySets, padx=2, pady=2, borderwidth=0)
327 for i in range(2)]
Terry Jan Reedyae410862014-08-03 23:02:53 -0400328 self.radioKeysBuiltin = Radiobutton(
329 frames[0], variable=self.keysAreBuiltin, value=1,
330 command=self.SetKeysType, text='Use a Built-in Key Set')
331 self.radioKeysCustom = Radiobutton(
332 frames[0], variable=self.keysAreBuiltin, value=0,
333 command=self.SetKeysType, text='Use a Custom Key Set')
334 self.optMenuKeysBuiltin = DynOptionMenu(
335 frames[0], self.builtinKeys, None, command=None)
336 self.optMenuKeysCustom = DynOptionMenu(
337 frames[0], self.customKeys, None, command=None)
338 self.buttonDeleteCustomKeys = Button(
339 frames[1], text='Delete Custom Key Set',
Steven M. Gava49745752002-02-18 01:43:11 +0000340 command=self.DeleteCustomKeys)
Terry Jan Reedyae410862014-08-03 23:02:53 -0400341 buttonSaveCustomKeys = Button(
342 frames[1], text='Save as New Custom Key Set',
343 command=self.SaveAsNewKeySet)
Terry Jan Reedy19b7a752014-07-30 19:24:26 -0400344
Steven M. Gava60fc7072001-08-04 13:58:22 +0000345 ##widget packing
346 #body
Terry Jan Reedyae410862014-08-03 23:02:53 -0400347 frameCustom.pack(side=BOTTOM, padx=5, pady=5, expand=TRUE, fill=BOTH)
348 frameKeySets.pack(side=BOTTOM, padx=5, pady=5, fill=BOTH)
Steven M. Gava60fc7072001-08-04 13:58:22 +0000349 #frameCustom
Terry Jan Reedyae410862014-08-03 23:02:53 -0400350 self.buttonNewKeys.pack(side=BOTTOM, fill=X, padx=5, pady=5)
351 frameTarget.pack(side=LEFT, padx=5, pady=5, expand=TRUE, fill=BOTH)
Steven M. Gavafacfc092002-01-19 00:29:54 +0000352 #frame target
Terry Jan Reedyae410862014-08-03 23:02:53 -0400353 frameTarget.columnconfigure(0, weight=1)
354 frameTarget.rowconfigure(1, weight=1)
355 labelTargetTitle.grid(row=0, column=0, columnspan=2, sticky=W)
356 self.listBindings.grid(row=1, column=0, sticky=NSEW)
357 scrollTargetY.grid(row=1, column=1, sticky=NS)
358 scrollTargetX.grid(row=2, column=0, sticky=EW)
Steven M. Gava60fc7072001-08-04 13:58:22 +0000359 #frameKeySets
Kurt B. Kaiser28c7bcf2007-12-28 04:18:01 +0000360 self.radioKeysBuiltin.grid(row=0, column=0, sticky=W+NS)
361 self.radioKeysCustom.grid(row=1, column=0, sticky=W+NS)
362 self.optMenuKeysBuiltin.grid(row=0, column=1, sticky=NSEW)
363 self.optMenuKeysCustom.grid(row=1, column=1, sticky=NSEW)
Terry Jan Reedyae410862014-08-03 23:02:53 -0400364 self.buttonDeleteCustomKeys.pack(side=LEFT, fill=X, expand=True, padx=2)
365 buttonSaveCustomKeys.pack(side=LEFT, fill=X, expand=True, padx=2)
Kurt B. Kaiser28c7bcf2007-12-28 04:18:01 +0000366 frames[0].pack(side=TOP, fill=BOTH, expand=True)
367 frames[1].pack(side=TOP, fill=X, expand=True, pady=2)
Steven M. Gava952d0a52001-08-03 04:43:44 +0000368 return frame
369
370 def CreatePageGeneral(self):
Terry Jan Reedy19b7a752014-07-30 19:24:26 -0400371 parent = self.parent
372 self.winWidth = StringVar(parent)
373 self.winHeight = StringVar(parent)
Terry Jan Reedy19b7a752014-07-30 19:24:26 -0400374 self.startupEdit = IntVar(parent)
375 self.autoSave = IntVar(parent)
376 self.encoding = StringVar(parent)
377 self.userHelpBrowser = BooleanVar(parent)
378 self.helpBrowser = StringVar(parent)
379
Steven M. Gava230e5782001-08-07 03:28:25 +0000380 #widget creation
381 #body
Terry Jan Reedyae410862014-08-03 23:02:53 -0400382 frame = self.tabPages.pages['General'].frame
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000383 #body section frames
Terry Jan Reedyae410862014-08-03 23:02:53 -0400384 frameRun = LabelFrame(frame, borderwidth=2, relief=GROOVE,
385 text=' Startup Preferences ')
386 frameSave = LabelFrame(frame, borderwidth=2, relief=GROOVE,
387 text=' Autosave Preferences ')
388 frameWinSize = Frame(frame, borderwidth=2, relief=GROOVE)
Terry Jan Reedyae410862014-08-03 23:02:53 -0400389 frameEncoding = Frame(frame, borderwidth=2, relief=GROOVE)
390 frameHelp = LabelFrame(frame, borderwidth=2, relief=GROOVE,
391 text=' Additional Help Sources ')
Steven M. Gava230e5782001-08-07 03:28:25 +0000392 #frameRun
Terry Jan Reedyae410862014-08-03 23:02:53 -0400393 labelRunChoiceTitle = Label(frameRun, text='At Startup')
394 radioStartupEdit = Radiobutton(
395 frameRun, variable=self.startupEdit, value=1,
396 command=self.SetKeysType, text="Open Edit Window")
397 radioStartupShell = Radiobutton(
398 frameRun, variable=self.startupEdit, value=0,
399 command=self.SetKeysType, text='Open Shell Window')
Kurt B. Kaiser6c638b62003-05-26 06:23:10 +0000400 #frameSave
Terry Jan Reedyae410862014-08-03 23:02:53 -0400401 labelRunSaveTitle = Label(frameSave, text='At Start of Run (F5) ')
402 radioSaveAsk = Radiobutton(
403 frameSave, variable=self.autoSave, value=0,
404 command=self.SetKeysType, text="Prompt to Save")
405 radioSaveAuto = Radiobutton(
406 frameSave, variable=self.autoSave, value=1,
407 command=self.SetKeysType, text='No Prompt')
Steven M. Gava230e5782001-08-07 03:28:25 +0000408 #frameWinSize
Terry Jan Reedyae410862014-08-03 23:02:53 -0400409 labelWinSizeTitle = Label(
410 frameWinSize, text='Initial Window Size (in characters)')
411 labelWinWidthTitle = Label(frameWinSize, text='Width')
412 entryWinWidth = Entry(
413 frameWinSize, textvariable=self.winWidth, width=3)
414 labelWinHeightTitle = Label(frameWinSize, text='Height')
415 entryWinHeight = Entry(
416 frameWinSize, textvariable=self.winHeight, width=3)
Kurt B. Kaisera053f332003-05-10 00:49:56 +0000417 #frameEncoding
Terry Jan Reedyae410862014-08-03 23:02:53 -0400418 labelEncodingTitle = Label(
419 frameEncoding, text="Default Source Encoding")
420 radioEncLocale = Radiobutton(
421 frameEncoding, variable=self.encoding,
422 value="locale", text="Locale-defined")
423 radioEncUTF8 = Radiobutton(
424 frameEncoding, variable=self.encoding,
425 value="utf-8", text="UTF-8")
426 radioEncNone = Radiobutton(
427 frameEncoding, variable=self.encoding,
428 value="none", text="None")
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000429 #frameHelp
Terry Jan Reedyae410862014-08-03 23:02:53 -0400430 frameHelpList = Frame(frameHelp)
431 frameHelpListButtons = Frame(frameHelpList)
432 scrollHelpList = Scrollbar(frameHelpList)
433 self.listHelp = Listbox(
434 frameHelpList, height=5, takefocus=FALSE,
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000435 exportselection=FALSE)
436 scrollHelpList.config(command=self.listHelp.yview)
437 self.listHelp.config(yscrollcommand=scrollHelpList.set)
Terry Jan Reedyae410862014-08-03 23:02:53 -0400438 self.listHelp.bind('<ButtonRelease-1>', self.HelpSourceSelected)
439 self.buttonHelpListEdit = Button(
440 frameHelpListButtons, text='Edit', state=DISABLED,
441 width=8, command=self.HelpListItemEdit)
442 self.buttonHelpListAdd = Button(
443 frameHelpListButtons, text='Add',
444 width=8, command=self.HelpListItemAdd)
445 self.buttonHelpListRemove = Button(
446 frameHelpListButtons, text='Remove', state=DISABLED,
447 width=8, command=self.HelpListItemRemove)
Terry Jan Reedy19b7a752014-07-30 19:24:26 -0400448
Steven M. Gava230e5782001-08-07 03:28:25 +0000449 #widget packing
450 #body
Terry Jan Reedyae410862014-08-03 23:02:53 -0400451 frameRun.pack(side=TOP, padx=5, pady=5, fill=X)
452 frameSave.pack(side=TOP, padx=5, pady=5, fill=X)
453 frameWinSize.pack(side=TOP, padx=5, pady=5, fill=X)
Terry Jan Reedyae410862014-08-03 23:02:53 -0400454 frameEncoding.pack(side=TOP, padx=5, pady=5, fill=X)
455 frameHelp.pack(side=TOP, padx=5, pady=5, expand=TRUE, fill=BOTH)
Steven M. Gava230e5782001-08-07 03:28:25 +0000456 #frameRun
Terry Jan Reedyae410862014-08-03 23:02:53 -0400457 labelRunChoiceTitle.pack(side=LEFT, anchor=W, padx=5, pady=5)
458 radioStartupShell.pack(side=RIGHT, anchor=W, padx=5, pady=5)
459 radioStartupEdit.pack(side=RIGHT, anchor=W, padx=5, pady=5)
Kurt B. Kaiser6c638b62003-05-26 06:23:10 +0000460 #frameSave
Terry Jan Reedyae410862014-08-03 23:02:53 -0400461 labelRunSaveTitle.pack(side=LEFT, anchor=W, padx=5, pady=5)
462 radioSaveAuto.pack(side=RIGHT, anchor=W, padx=5, pady=5)
463 radioSaveAsk.pack(side=RIGHT, anchor=W, padx=5, pady=5)
Steven M. Gava230e5782001-08-07 03:28:25 +0000464 #frameWinSize
Terry Jan Reedyae410862014-08-03 23:02:53 -0400465 labelWinSizeTitle.pack(side=LEFT, anchor=W, padx=5, pady=5)
466 entryWinHeight.pack(side=RIGHT, anchor=E, padx=10, pady=5)
467 labelWinHeightTitle.pack(side=RIGHT, anchor=E, pady=5)
468 entryWinWidth.pack(side=RIGHT, anchor=E, padx=10, pady=5)
469 labelWinWidthTitle.pack(side=RIGHT, anchor=E, pady=5)
Kurt B. Kaisera053f332003-05-10 00:49:56 +0000470 #frameEncoding
Terry Jan Reedyae410862014-08-03 23:02:53 -0400471 labelEncodingTitle.pack(side=LEFT, anchor=W, padx=5, pady=5)
472 radioEncNone.pack(side=RIGHT, anchor=E, pady=5)
473 radioEncUTF8.pack(side=RIGHT, anchor=E, pady=5)
474 radioEncLocale.pack(side=RIGHT, anchor=E, pady=5)
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000475 #frameHelp
Terry Jan Reedyae410862014-08-03 23:02:53 -0400476 frameHelpListButtons.pack(side=RIGHT, padx=5, pady=5, fill=Y)
477 frameHelpList.pack(side=TOP, padx=5, pady=5, expand=TRUE, fill=BOTH)
478 scrollHelpList.pack(side=RIGHT, anchor=W, fill=Y)
479 self.listHelp.pack(side=LEFT, anchor=E, expand=TRUE, fill=BOTH)
480 self.buttonHelpListEdit.pack(side=TOP, anchor=W, pady=5)
481 self.buttonHelpListAdd.pack(side=TOP, anchor=W)
482 self.buttonHelpListRemove.pack(side=TOP, anchor=W, pady=5)
Steven M. Gava952d0a52001-08-03 04:43:44 +0000483 return frame
484
Steven M. Gavac112cd82002-01-22 05:56:40 +0000485 def AttachVarCallbacks(self):
Terry Jan Reedyae410862014-08-03 23:02:53 -0400486 self.fontSize.trace_variable('w', self.VarChanged_fontSize)
487 self.fontName.trace_variable('w', self.VarChanged_fontName)
488 self.fontBold.trace_variable('w', self.VarChanged_fontBold)
489 self.spaceNum.trace_variable('w', self.VarChanged_spaceNum)
490 self.colour.trace_variable('w', self.VarChanged_colour)
491 self.builtinTheme.trace_variable('w', self.VarChanged_builtinTheme)
492 self.customTheme.trace_variable('w', self.VarChanged_customTheme)
493 self.themeIsBuiltin.trace_variable('w', self.VarChanged_themeIsBuiltin)
494 self.highlightTarget.trace_variable('w', self.VarChanged_highlightTarget)
495 self.keyBinding.trace_variable('w', self.VarChanged_keyBinding)
496 self.builtinKeys.trace_variable('w', self.VarChanged_builtinKeys)
497 self.customKeys.trace_variable('w', self.VarChanged_customKeys)
498 self.keysAreBuiltin.trace_variable('w', self.VarChanged_keysAreBuiltin)
499 self.winWidth.trace_variable('w', self.VarChanged_winWidth)
500 self.winHeight.trace_variable('w', self.VarChanged_winHeight)
Terry Jan Reedyae410862014-08-03 23:02:53 -0400501 self.startupEdit.trace_variable('w', self.VarChanged_startupEdit)
502 self.autoSave.trace_variable('w', self.VarChanged_autoSave)
503 self.encoding.trace_variable('w', self.VarChanged_encoding)
Steven M. Gava052937f2002-02-11 02:20:53 +0000504
Terry Jan Reedyae410862014-08-03 23:02:53 -0400505 def VarChanged_fontSize(self, *params):
506 value = self.fontSize.get()
507 self.AddChangedItem('main', 'EditorWindow', 'font-size', value)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000508
Terry Jan Reedyae410862014-08-03 23:02:53 -0400509 def VarChanged_fontName(self, *params):
510 value = self.fontName.get()
511 self.AddChangedItem('main', 'EditorWindow', 'font', value)
Steven M. Gavac112cd82002-01-22 05:56:40 +0000512
Terry Jan Reedyae410862014-08-03 23:02:53 -0400513 def VarChanged_fontBold(self, *params):
514 value = self.fontBold.get()
515 self.AddChangedItem('main', 'EditorWindow', 'font-bold', value)
Steven M. Gavac112cd82002-01-22 05:56:40 +0000516
Terry Jan Reedyae410862014-08-03 23:02:53 -0400517 def VarChanged_spaceNum(self, *params):
518 value = self.spaceNum.get()
519 self.AddChangedItem('main', 'Indent', 'num-spaces', value)
Steven M. Gavac112cd82002-01-22 05:56:40 +0000520
Terry Jan Reedyae410862014-08-03 23:02:53 -0400521 def VarChanged_colour(self, *params):
Steven M. Gava052937f2002-02-11 02:20:53 +0000522 self.OnNewColourSet()
523
Terry Jan Reedyae410862014-08-03 23:02:53 -0400524 def VarChanged_builtinTheme(self, *params):
525 value = self.builtinTheme.get()
526 self.AddChangedItem('main', 'Theme', 'name', value)
Steven M. Gava052937f2002-02-11 02:20:53 +0000527 self.PaintThemeSample()
528
Terry Jan Reedyae410862014-08-03 23:02:53 -0400529 def VarChanged_customTheme(self, *params):
530 value = self.customTheme.get()
Steven M. Gava49745752002-02-18 01:43:11 +0000531 if value != '- no custom themes -':
Terry Jan Reedyae410862014-08-03 23:02:53 -0400532 self.AddChangedItem('main', 'Theme', 'name', value)
Steven M. Gava49745752002-02-18 01:43:11 +0000533 self.PaintThemeSample()
Steven M. Gava052937f2002-02-11 02:20:53 +0000534
Terry Jan Reedyae410862014-08-03 23:02:53 -0400535 def VarChanged_themeIsBuiltin(self, *params):
536 value = self.themeIsBuiltin.get()
537 self.AddChangedItem('main', 'Theme', 'default', value)
Steven M. Gavaf31eec02002-03-05 00:25:58 +0000538 if value:
539 self.VarChanged_builtinTheme()
540 else:
541 self.VarChanged_customTheme()
Steven M. Gava052937f2002-02-11 02:20:53 +0000542
Terry Jan Reedyae410862014-08-03 23:02:53 -0400543 def VarChanged_highlightTarget(self, *params):
Steven M. Gava052937f2002-02-11 02:20:53 +0000544 self.SetHighlightTarget()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000545
Terry Jan Reedyae410862014-08-03 23:02:53 -0400546 def VarChanged_keyBinding(self, *params):
547 value = self.keyBinding.get()
548 keySet = self.customKeys.get()
549 event = self.listBindings.get(ANCHOR).split()[0]
Steven M. Gavaa498af22002-02-01 01:33:36 +0000550 if idleConf.IsCoreBinding(event):
551 #this is a core keybinding
Terry Jan Reedyae410862014-08-03 23:02:53 -0400552 self.AddChangedItem('keys', keySet, event, value)
Steven M. Gavaa498af22002-02-01 01:33:36 +0000553 else: #this is an extension key binding
Terry Jan Reedyae410862014-08-03 23:02:53 -0400554 extName = idleConf.GetExtnNameForEvent(event)
555 extKeybindSection = extName + '_cfgBindings'
556 self.AddChangedItem('extensions', extKeybindSection, event, value)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000557
Terry Jan Reedyae410862014-08-03 23:02:53 -0400558 def VarChanged_builtinKeys(self, *params):
559 value = self.builtinKeys.get()
560 self.AddChangedItem('main', 'Keys', 'name', value)
Steven M. Gava052937f2002-02-11 02:20:53 +0000561 self.LoadKeysList(value)
562
Terry Jan Reedyae410862014-08-03 23:02:53 -0400563 def VarChanged_customKeys(self, *params):
564 value = self.customKeys.get()
Steven M. Gava49745752002-02-18 01:43:11 +0000565 if value != '- no custom keys -':
Terry Jan Reedyae410862014-08-03 23:02:53 -0400566 self.AddChangedItem('main', 'Keys', 'name', value)
Steven M. Gava49745752002-02-18 01:43:11 +0000567 self.LoadKeysList(value)
Steven M. Gava052937f2002-02-11 02:20:53 +0000568
Terry Jan Reedyae410862014-08-03 23:02:53 -0400569 def VarChanged_keysAreBuiltin(self, *params):
570 value = self.keysAreBuiltin.get()
571 self.AddChangedItem('main', 'Keys', 'default', value)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000572 if value:
Steven M. Gavaf31eec02002-03-05 00:25:58 +0000573 self.VarChanged_builtinKeys()
Steven M. Gava052937f2002-02-11 02:20:53 +0000574 else:
Steven M. Gavaf31eec02002-03-05 00:25:58 +0000575 self.VarChanged_customKeys()
Steven M. Gava052937f2002-02-11 02:20:53 +0000576
Terry Jan Reedyae410862014-08-03 23:02:53 -0400577 def VarChanged_winWidth(self, *params):
578 value = self.winWidth.get()
579 self.AddChangedItem('main', 'EditorWindow', 'width', value)
Steven M. Gavac112cd82002-01-22 05:56:40 +0000580
Terry Jan Reedyae410862014-08-03 23:02:53 -0400581 def VarChanged_winHeight(self, *params):
582 value = self.winHeight.get()
583 self.AddChangedItem('main', 'EditorWindow', 'height', value)
Steven M. Gavac112cd82002-01-22 05:56:40 +0000584
Terry Jan Reedyae410862014-08-03 23:02:53 -0400585 def VarChanged_startupEdit(self, *params):
586 value = self.startupEdit.get()
587 self.AddChangedItem('main', 'General', 'editor-on-startup', value)
Steven M. Gavac112cd82002-01-22 05:56:40 +0000588
Terry Jan Reedyae410862014-08-03 23:02:53 -0400589 def VarChanged_autoSave(self, *params):
590 value = self.autoSave.get()
591 self.AddChangedItem('main', 'General', 'autosave', value)
Kurt B. Kaiser6c638b62003-05-26 06:23:10 +0000592
Terry Jan Reedyae410862014-08-03 23:02:53 -0400593 def VarChanged_encoding(self, *params):
594 value = self.encoding.get()
595 self.AddChangedItem('main', 'EditorWindow', 'encoding', value)
Kurt B. Kaisera053f332003-05-10 00:49:56 +0000596
Steven M. Gavaa498af22002-02-01 01:33:36 +0000597 def ResetChangedItems(self):
Steven M. Gavab77d3432002-03-02 07:16:21 +0000598 #When any config item is changed in this dialog, an entry
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000599 #should be made in the relevant section (config type) of this
600 #dictionary. The key should be the config file section name and the
Steven M. Gavaa498af22002-02-01 01:33:36 +0000601 #value a dictionary, whose key:value pairs are item=value pairs for
602 #that config file section.
Terry Jan Reedyae410862014-08-03 23:02:53 -0400603 self.changedItems = {'main':{}, 'highlight':{}, 'keys':{},
604 'extensions':{}}
Steven M. Gavaa498af22002-02-01 01:33:36 +0000605
Terry Jan Reedyae410862014-08-03 23:02:53 -0400606 def AddChangedItem(self, typ, section, item, value):
607 value = str(value) #make sure we use a string
608 if section not in self.changedItems[typ]:
609 self.changedItems[typ][section] = {}
610 self.changedItems[typ][section][item] = value
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000611
Steven M. Gava5f28e8f2002-01-21 06:38:21 +0000612 def GetDefaultItems(self):
Terry Jan Reedyae410862014-08-03 23:02:53 -0400613 dItems={'main':{}, 'highlight':{}, 'keys':{}, 'extensions':{}}
Terry Jan Reedy110796f2014-07-27 04:07:18 -0400614 for configType in dItems:
Terry Jan Reedyae410862014-08-03 23:02:53 -0400615 sections = idleConf.GetSectionList('default', configType)
Steven M. Gava5f28e8f2002-01-21 06:38:21 +0000616 for section in sections:
Terry Jan Reedyae410862014-08-03 23:02:53 -0400617 dItems[configType][section] = {}
618 options = idleConf.defaultCfg[configType].GetOptionList(section)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000619 for option in options:
Terry Jan Reedyae410862014-08-03 23:02:53 -0400620 dItems[configType][section][option] = (
621 idleConf.defaultCfg[configType].Get(section, option))
Steven M. Gava5f28e8f2002-01-21 06:38:21 +0000622 return dItems
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000623
Steven M. Gava5f28e8f2002-01-21 06:38:21 +0000624 def SetThemeType(self):
625 if self.themeIsBuiltin.get():
626 self.optMenuThemeBuiltin.config(state=NORMAL)
627 self.optMenuThemeCustom.config(state=DISABLED)
628 self.buttonDeleteCustomTheme.config(state=DISABLED)
629 else:
630 self.optMenuThemeBuiltin.config(state=DISABLED)
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000631 self.radioThemeCustom.config(state=NORMAL)
Steven M. Gava5f28e8f2002-01-21 06:38:21 +0000632 self.optMenuThemeCustom.config(state=NORMAL)
633 self.buttonDeleteCustomTheme.config(state=NORMAL)
634
635 def SetKeysType(self):
Steven M. Gava052937f2002-02-11 02:20:53 +0000636 if self.keysAreBuiltin.get():
Steven M. Gava5f28e8f2002-01-21 06:38:21 +0000637 self.optMenuKeysBuiltin.config(state=NORMAL)
638 self.optMenuKeysCustom.config(state=DISABLED)
639 self.buttonDeleteCustomKeys.config(state=DISABLED)
640 else:
641 self.optMenuKeysBuiltin.config(state=DISABLED)
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000642 self.radioKeysCustom.config(state=NORMAL)
Steven M. Gava5f28e8f2002-01-21 06:38:21 +0000643 self.optMenuKeysCustom.config(state=NORMAL)
644 self.buttonDeleteCustomKeys.config(state=NORMAL)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000645
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000646 def GetNewKeys(self):
Terry Jan Reedyae410862014-08-03 23:02:53 -0400647 listIndex = self.listBindings.index(ANCHOR)
648 binding = self.listBindings.get(listIndex)
649 bindName = binding.split()[0] #first part, up to first space
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000650 if self.keysAreBuiltin.get():
Terry Jan Reedyae410862014-08-03 23:02:53 -0400651 currentKeySetName = self.builtinKeys.get()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000652 else:
Terry Jan Reedyae410862014-08-03 23:02:53 -0400653 currentKeySetName = self.customKeys.get()
654 currentBindings = idleConf.GetCurrentKeySet()
Terry Jan Reedy110796f2014-07-27 04:07:18 -0400655 if currentKeySetName in self.changedItems['keys']: #unsaved changes
Terry Jan Reedyae410862014-08-03 23:02:53 -0400656 keySetChanges = self.changedItems['keys'][currentKeySetName]
Terry Jan Reedy110796f2014-07-27 04:07:18 -0400657 for event in keySetChanges:
Terry Jan Reedyae410862014-08-03 23:02:53 -0400658 currentBindings[event] = keySetChanges[event].split()
659 currentKeySequences = currentBindings.values()
660 newKeys = GetKeysDialog(self, 'Get New Keys', bindName,
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000661 currentKeySequences).result
662 if newKeys: #new keys were specified
Steven M. Gava052937f2002-02-11 02:20:53 +0000663 if self.keysAreBuiltin.get(): #current key set is a built-in
Terry Jan Reedyae410862014-08-03 23:02:53 -0400664 message = ('Your changes will be saved as a new Custom Key Set.'
665 ' Enter a name for your new Custom Key Set below.')
666 newKeySet = self.GetNewKeysName(message)
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000667 if not newKeySet: #user cancelled custom key set creation
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000668 self.listBindings.select_set(listIndex)
669 self.listBindings.select_anchor(listIndex)
670 return
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000671 else: #create new custom key set based on previously active key set
672 self.CreateNewKeySet(newKeySet)
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000673 self.listBindings.delete(listIndex)
Terry Jan Reedyae410862014-08-03 23:02:53 -0400674 self.listBindings.insert(listIndex, bindName+' - '+newKeys)
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000675 self.listBindings.select_set(listIndex)
676 self.listBindings.select_anchor(listIndex)
Steven M. Gava052937f2002-02-11 02:20:53 +0000677 self.keyBinding.set(newKeys)
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000678 else:
679 self.listBindings.select_set(listIndex)
680 self.listBindings.select_anchor(listIndex)
681
Terry Jan Reedyae410862014-08-03 23:02:53 -0400682 def GetNewKeysName(self, message):
683 usedNames = (idleConf.GetSectionList('user', 'keys') +
684 idleConf.GetSectionList('default', 'keys'))
685 newKeySet = GetCfgSectionNameDialog(
686 self, 'New Custom Key Set', message, usedNames).result
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000687 return newKeySet
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000688
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000689 def SaveAsNewKeySet(self):
Terry Jan Reedyae410862014-08-03 23:02:53 -0400690 newKeysName = self.GetNewKeysName('New Key Set Name:')
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000691 if newKeysName:
692 self.CreateNewKeySet(newKeysName)
693
Terry Jan Reedyae410862014-08-03 23:02:53 -0400694 def KeyBindingSelected(self, event):
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000695 self.buttonNewKeys.config(state=NORMAL)
696
Terry Jan Reedyae410862014-08-03 23:02:53 -0400697 def CreateNewKeySet(self, newKeySetName):
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000698 #creates new custom key set based on the previously active key set,
699 #and makes the new key set active
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000700 if self.keysAreBuiltin.get():
Terry Jan Reedyae410862014-08-03 23:02:53 -0400701 prevKeySetName = self.builtinKeys.get()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000702 else:
Terry Jan Reedyae410862014-08-03 23:02:53 -0400703 prevKeySetName = self.customKeys.get()
704 prevKeys = idleConf.GetCoreKeys(prevKeySetName)
705 newKeys = {}
Terry Jan Reedy110796f2014-07-27 04:07:18 -0400706 for event in prevKeys: #add key set to changed items
Terry Jan Reedyae410862014-08-03 23:02:53 -0400707 eventName = event[2:-2] #trim off the angle brackets
708 binding = ' '.join(prevKeys[event])
709 newKeys[eventName] = binding
Steven M. Gava052937f2002-02-11 02:20:53 +0000710 #handle any unsaved changes to prev key set
Terry Jan Reedy110796f2014-07-27 04:07:18 -0400711 if prevKeySetName in self.changedItems['keys']:
Terry Jan Reedyae410862014-08-03 23:02:53 -0400712 keySetChanges = self.changedItems['keys'][prevKeySetName]
Terry Jan Reedy110796f2014-07-27 04:07:18 -0400713 for event in keySetChanges:
Terry Jan Reedyae410862014-08-03 23:02:53 -0400714 newKeys[event] = keySetChanges[event]
Steven M. Gava052937f2002-02-11 02:20:53 +0000715 #save the new theme
Terry Jan Reedyae410862014-08-03 23:02:53 -0400716 self.SaveNewKeySet(newKeySetName, newKeys)
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000717 #change gui over to the new key set
Terry Jan Reedyae410862014-08-03 23:02:53 -0400718 customKeyList = idleConf.GetSectionList('user', 'keys')
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000719 customKeyList.sort()
Terry Jan Reedyae410862014-08-03 23:02:53 -0400720 self.optMenuKeysCustom.SetMenu(customKeyList, newKeySetName)
Steven M. Gava052937f2002-02-11 02:20:53 +0000721 self.keysAreBuiltin.set(0)
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000722 self.SetKeysType()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000723
Terry Jan Reedyae410862014-08-03 23:02:53 -0400724 def LoadKeysList(self, keySetName):
725 reselect = 0
726 newKeySet = 0
Steven M. Gava052937f2002-02-11 02:20:53 +0000727 if self.listBindings.curselection():
Terry Jan Reedyae410862014-08-03 23:02:53 -0400728 reselect = 1
729 listIndex = self.listBindings.index(ANCHOR)
730 keySet = idleConf.GetKeySet(keySetName)
731 bindNames = keySet.keys()
Steven M. Gava052937f2002-02-11 02:20:53 +0000732 bindNames.sort()
Terry Jan Reedyae410862014-08-03 23:02:53 -0400733 self.listBindings.delete(0, END)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000734 for bindName in bindNames:
Terry Jan Reedyae410862014-08-03 23:02:53 -0400735 key = ' '.join(keySet[bindName]) #make key(s) into a string
736 bindName = bindName[2:-2] #trim off the angle brackets
Terry Jan Reedy110796f2014-07-27 04:07:18 -0400737 if keySetName in self.changedItems['keys']:
Steven M. Gava052937f2002-02-11 02:20:53 +0000738 #handle any unsaved changes to this key set
Terry Jan Reedy110796f2014-07-27 04:07:18 -0400739 if bindName in self.changedItems['keys'][keySetName]:
Terry Jan Reedyae410862014-08-03 23:02:53 -0400740 key = self.changedItems['keys'][keySetName][bindName]
Steven M. Gava052937f2002-02-11 02:20:53 +0000741 self.listBindings.insert(END, bindName+' - '+key)
Steven M. Gava052937f2002-02-11 02:20:53 +0000742 if reselect:
743 self.listBindings.see(listIndex)
744 self.listBindings.select_set(listIndex)
745 self.listBindings.select_anchor(listIndex)
746
Steven M. Gava49745752002-02-18 01:43:11 +0000747 def DeleteCustomKeys(self):
748 keySetName=self.customKeys.get()
Terry Jan Reedyae410862014-08-03 23:02:53 -0400749 delmsg = 'Are you sure you wish to delete the key set %r ?'
750 if not tkMessageBox.askyesno(
751 'Delete Key Set', delmsg % keySetName, parent=self):
Steven M. Gava49745752002-02-18 01:43:11 +0000752 return
753 #remove key set from config
754 idleConf.userCfg['keys'].remove_section(keySetName)
Benjamin Peterson6e3dbbd2009-10-09 22:15:50 +0000755 if keySetName in self.changedItems['keys']:
Steven M. Gava49745752002-02-18 01:43:11 +0000756 del(self.changedItems['keys'][keySetName])
757 #write changes
758 idleConf.userCfg['keys'].Save()
759 #reload user key set list
Terry Jan Reedyae410862014-08-03 23:02:53 -0400760 itemList = idleConf.GetSectionList('user', 'keys')
Steven M. Gava49745752002-02-18 01:43:11 +0000761 itemList.sort()
762 if not itemList:
763 self.radioKeysCustom.config(state=DISABLED)
Terry Jan Reedyae410862014-08-03 23:02:53 -0400764 self.optMenuKeysCustom.SetMenu(itemList, '- no custom keys -')
Steven M. Gava49745752002-02-18 01:43:11 +0000765 else:
Terry Jan Reedyae410862014-08-03 23:02:53 -0400766 self.optMenuKeysCustom.SetMenu(itemList, itemList[0])
Steven M. Gava49745752002-02-18 01:43:11 +0000767 #revert to default key set
Terry Jan Reedyae410862014-08-03 23:02:53 -0400768 self.keysAreBuiltin.set(idleConf.defaultCfg['main'].Get('Keys', 'default'))
769 self.builtinKeys.set(idleConf.defaultCfg['main'].Get('Keys', 'name'))
Steven M. Gava49745752002-02-18 01:43:11 +0000770 #user can't back out of these changes, they must be applied now
771 self.Apply()
772 self.SetKeysType()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000773
Steven M. Gava49745752002-02-18 01:43:11 +0000774 def DeleteCustomTheme(self):
Terry Jan Reedyae410862014-08-03 23:02:53 -0400775 themeName = self.customTheme.get()
776 delmsg = 'Are you sure you wish to delete the theme %r ?'
777 if not tkMessageBox.askyesno(
778 'Delete Theme', delmsg % themeName, parent=self):
Steven M. Gava49745752002-02-18 01:43:11 +0000779 return
780 #remove theme from config
781 idleConf.userCfg['highlight'].remove_section(themeName)
Benjamin Peterson6e3dbbd2009-10-09 22:15:50 +0000782 if themeName in self.changedItems['highlight']:
Steven M. Gava49745752002-02-18 01:43:11 +0000783 del(self.changedItems['highlight'][themeName])
784 #write changes
785 idleConf.userCfg['highlight'].Save()
786 #reload user theme list
Terry Jan Reedyae410862014-08-03 23:02:53 -0400787 itemList = idleConf.GetSectionList('user', 'highlight')
Steven M. Gava49745752002-02-18 01:43:11 +0000788 itemList.sort()
789 if not itemList:
790 self.radioThemeCustom.config(state=DISABLED)
Terry Jan Reedyae410862014-08-03 23:02:53 -0400791 self.optMenuThemeCustom.SetMenu(itemList, '- no custom themes -')
Steven M. Gava49745752002-02-18 01:43:11 +0000792 else:
Terry Jan Reedyae410862014-08-03 23:02:53 -0400793 self.optMenuThemeCustom.SetMenu(itemList, itemList[0])
Steven M. Gava49745752002-02-18 01:43:11 +0000794 #revert to default theme
Terry Jan Reedyae410862014-08-03 23:02:53 -0400795 self.themeIsBuiltin.set(idleConf.defaultCfg['main'].Get('Theme', 'default'))
796 self.builtinTheme.set(idleConf.defaultCfg['main'].Get('Theme', 'name'))
Steven M. Gava49745752002-02-18 01:43:11 +0000797 #user can't back out of these changes, they must be applied now
798 self.Apply()
799 self.SetThemeType()
800
Steven M. Gava5f28e8f2002-01-21 06:38:21 +0000801 def GetColour(self):
Terry Jan Reedyae410862014-08-03 23:02:53 -0400802 target = self.highlightTarget.get()
803 prevColour = self.frameColourSet.cget('bg')
804 rgbTuplet, colourString = tkColorChooser.askcolor(
805 parent=self, title='Pick new colour for : '+target,
806 initialcolor=prevColour)
807 if colourString and (colourString != prevColour):
Steven M. Gava052937f2002-02-11 02:20:53 +0000808 #user didn't cancel, and they chose a new colour
Terry Jan Reedyae410862014-08-03 23:02:53 -0400809 if self.themeIsBuiltin.get(): #current theme is a built-in
810 message = ('Your changes will be saved as a new Custom Theme. '
811 'Enter a name for your new Custom Theme below.')
812 newTheme = self.GetNewThemeName(message)
813 if not newTheme: #user cancelled custom theme creation
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000814 return
Terry Jan Reedyae410862014-08-03 23:02:53 -0400815 else: #create new custom theme based on previously active theme
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000816 self.CreateNewTheme(newTheme)
Steven M. Gava052937f2002-02-11 02:20:53 +0000817 self.colour.set(colourString)
Terry Jan Reedyae410862014-08-03 23:02:53 -0400818 else: #current theme is user defined
Steven M. Gava052937f2002-02-11 02:20:53 +0000819 self.colour.set(colourString)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000820
Steven M. Gava052937f2002-02-11 02:20:53 +0000821 def OnNewColourSet(self):
822 newColour=self.colour.get()
Terry Jan Reedyae410862014-08-03 23:02:53 -0400823 self.frameColourSet.config(bg=newColour) #set sample
824 plane ='foreground' if self.fgHilite.get() else 'background'
825 sampleElement = self.themeElements[self.highlightTarget.get()][0]
Raymond Hettinger931237e2003-07-09 18:48:24 +0000826 self.textHighlightSample.tag_config(sampleElement, **{plane:newColour})
Terry Jan Reedyae410862014-08-03 23:02:53 -0400827 theme = self.customTheme.get()
828 themeElement = sampleElement + '-' + plane
829 self.AddChangedItem('highlight', theme, themeElement, newColour)
Steven M. Gava052937f2002-02-11 02:20:53 +0000830
Terry Jan Reedyae410862014-08-03 23:02:53 -0400831 def GetNewThemeName(self, message):
832 usedNames = (idleConf.GetSectionList('user', 'highlight') +
833 idleConf.GetSectionList('default', 'highlight'))
834 newTheme = GetCfgSectionNameDialog(
835 self, 'New Custom Theme', message, usedNames).result
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000836 return newTheme
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000837
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000838 def SaveAsNewTheme(self):
Terry Jan Reedyae410862014-08-03 23:02:53 -0400839 newThemeName = self.GetNewThemeName('New Theme Name:')
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000840 if newThemeName:
841 self.CreateNewTheme(newThemeName)
842
Terry Jan Reedyae410862014-08-03 23:02:53 -0400843 def CreateNewTheme(self, newThemeName):
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000844 #creates new custom theme based on the previously active theme,
845 #and makes the new theme active
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000846 if self.themeIsBuiltin.get():
Terry Jan Reedyae410862014-08-03 23:02:53 -0400847 themeType = 'default'
848 themeName = self.builtinTheme.get()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000849 else:
Terry Jan Reedyae410862014-08-03 23:02:53 -0400850 themeType = 'user'
851 themeName = self.customTheme.get()
852 newTheme = idleConf.GetThemeDict(themeType, themeName)
Steven M. Gava052937f2002-02-11 02:20:53 +0000853 #apply any of the old theme's unsaved changes to the new theme
Terry Jan Reedy110796f2014-07-27 04:07:18 -0400854 if themeName in self.changedItems['highlight']:
Terry Jan Reedyae410862014-08-03 23:02:53 -0400855 themeChanges = self.changedItems['highlight'][themeName]
Terry Jan Reedy110796f2014-07-27 04:07:18 -0400856 for element in themeChanges:
Terry Jan Reedyae410862014-08-03 23:02:53 -0400857 newTheme[element] = themeChanges[element]
Steven M. Gava052937f2002-02-11 02:20:53 +0000858 #save the new theme
Terry Jan Reedyae410862014-08-03 23:02:53 -0400859 self.SaveNewTheme(newThemeName, newTheme)
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000860 #change gui over to the new theme
Terry Jan Reedyae410862014-08-03 23:02:53 -0400861 customThemeList = idleConf.GetSectionList('user', 'highlight')
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000862 customThemeList.sort()
Terry Jan Reedyae410862014-08-03 23:02:53 -0400863 self.optMenuThemeCustom.SetMenu(customThemeList, newThemeName)
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000864 self.themeIsBuiltin.set(0)
865 self.SetThemeType()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000866
Terry Jan Reedyae410862014-08-03 23:02:53 -0400867 def OnListFontButtonRelease(self, event):
Kurt B. Kaiser05391692003-05-26 20:35:53 +0000868 font = self.listFontName.get(ANCHOR)
869 self.fontName.set(font.lower())
Steven M. Gava5f28e8f2002-01-21 06:38:21 +0000870 self.SetFontSample()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000871
Terry Jan Reedyae410862014-08-03 23:02:53 -0400872 def SetFontSample(self, event=None):
873 fontName = self.fontName.get()
874 fontWeight = tkFont.BOLD if self.fontBold.get() else tkFont.NORMAL
Ned Deilye3d47122012-10-22 15:13:01 -0700875 newFont = (fontName, self.fontSize.get(), fontWeight)
876 self.labelFontSample.config(font=newFont)
877 self.textHighlightSample.configure(font=newFont)
Steven M. Gava5f28e8f2002-01-21 06:38:21 +0000878
Steven M. Gava5f28e8f2002-01-21 06:38:21 +0000879 def SetHighlightTarget(self):
Terry Jan Reedyae410862014-08-03 23:02:53 -0400880 if self.highlightTarget.get() == 'Cursor': #bg not possible
Steven M. Gava5f28e8f2002-01-21 06:38:21 +0000881 self.radioFg.config(state=DISABLED)
882 self.radioBg.config(state=DISABLED)
883 self.fgHilite.set(1)
Terry Jan Reedyae410862014-08-03 23:02:53 -0400884 else: #both fg and bg can be set
Steven M. Gava5f28e8f2002-01-21 06:38:21 +0000885 self.radioFg.config(state=NORMAL)
886 self.radioBg.config(state=NORMAL)
887 self.fgHilite.set(1)
888 self.SetColourSample()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000889
Terry Jan Reedyae410862014-08-03 23:02:53 -0400890 def SetColourSampleBinding(self, *args):
Steven M. Gava5f28e8f2002-01-21 06:38:21 +0000891 self.SetColourSample()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000892
Steven M. Gava5f28e8f2002-01-21 06:38:21 +0000893 def SetColourSample(self):
894 #set the colour smaple area
Terry Jan Reedyae410862014-08-03 23:02:53 -0400895 tag = self.themeElements[self.highlightTarget.get()][0]
896 plane = 'foreground' if self.fgHilite.get() else 'background'
897 colour = self.textHighlightSample.tag_cget(tag, plane)
Steven M. Gava5f28e8f2002-01-21 06:38:21 +0000898 self.frameColourSet.config(bg=colour)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000899
Steven M. Gava9dd16b32001-11-03 14:54:25 +0000900 def PaintThemeSample(self):
Terry Jan Reedyae410862014-08-03 23:02:53 -0400901 if self.themeIsBuiltin.get(): #a default theme
902 theme = self.builtinTheme.get()
903 else: #a user theme
904 theme = self.customTheme.get()
Terry Jan Reedy110796f2014-07-27 04:07:18 -0400905 for elementTitle in self.themeElements:
Terry Jan Reedyae410862014-08-03 23:02:53 -0400906 element = self.themeElements[elementTitle][0]
907 colours = idleConf.GetHighlight(theme, element)
908 if element == 'cursor': #cursor sample needs special painting
909 colours['background'] = idleConf.GetHighlight(
910 theme, 'normal', fgBg='bg')
Steven M. Gava052937f2002-02-11 02:20:53 +0000911 #handle any unsaved changes to this theme
Terry Jan Reedy110796f2014-07-27 04:07:18 -0400912 if theme in self.changedItems['highlight']:
Terry Jan Reedyae410862014-08-03 23:02:53 -0400913 themeDict = self.changedItems['highlight'][theme]
914 if element + '-foreground' in themeDict:
915 colours['foreground'] = themeDict[element + '-foreground']
916 if element + '-background' in themeDict:
917 colours['background'] = themeDict[element + '-background']
Raymond Hettinger931237e2003-07-09 18:48:24 +0000918 self.textHighlightSample.tag_config(element, **colours)
Steven M. Gava052937f2002-02-11 02:20:53 +0000919 self.SetColourSample()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000920
Terry Jan Reedyae410862014-08-03 23:02:53 -0400921 def HelpSourceSelected(self, event):
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000922 self.SetHelpListButtonStates()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000923
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000924 def SetHelpListButtonStates(self):
Terry Jan Reedyae410862014-08-03 23:02:53 -0400925 if self.listHelp.size() < 1: #no entries in list
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000926 self.buttonHelpListEdit.config(state=DISABLED)
927 self.buttonHelpListRemove.config(state=DISABLED)
928 else: #there are some entries
Terry Jan Reedyae410862014-08-03 23:02:53 -0400929 if self.listHelp.curselection(): #there currently is a selection
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000930 self.buttonHelpListEdit.config(state=NORMAL)
931 self.buttonHelpListRemove.config(state=NORMAL)
932 else: #there currently is not a selection
933 self.buttonHelpListEdit.config(state=DISABLED)
934 self.buttonHelpListRemove.config(state=DISABLED)
935
936 def HelpListItemAdd(self):
Terry Jan Reedyae410862014-08-03 23:02:53 -0400937 helpSource = GetHelpSourceDialog(self, 'New Help Source').result
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000938 if helpSource:
Terry Jan Reedyae410862014-08-03 23:02:53 -0400939 self.userHelpList.append((helpSource[0], helpSource[1]))
940 self.listHelp.insert(END, helpSource[0])
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000941 self.UpdateUserHelpChangedItems()
942 self.SetHelpListButtonStates()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000943
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000944 def HelpListItemEdit(self):
Terry Jan Reedyae410862014-08-03 23:02:53 -0400945 itemIndex = self.listHelp.index(ANCHOR)
946 helpSource = self.userHelpList[itemIndex]
947 newHelpSource = GetHelpSourceDialog(
948 self, 'Edit Help Source', menuItem=helpSource[0],
949 filePath=helpSource[1]).result
950 if (not newHelpSource) or (newHelpSource == helpSource):
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000951 return #no changes
Terry Jan Reedyae410862014-08-03 23:02:53 -0400952 self.userHelpList[itemIndex] = newHelpSource
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000953 self.listHelp.delete(itemIndex)
Terry Jan Reedyae410862014-08-03 23:02:53 -0400954 self.listHelp.insert(itemIndex, newHelpSource[0])
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000955 self.UpdateUserHelpChangedItems()
956 self.SetHelpListButtonStates()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000957
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000958 def HelpListItemRemove(self):
Terry Jan Reedyae410862014-08-03 23:02:53 -0400959 itemIndex = self.listHelp.index(ANCHOR)
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000960 del(self.userHelpList[itemIndex])
961 self.listHelp.delete(itemIndex)
962 self.UpdateUserHelpChangedItems()
963 self.SetHelpListButtonStates()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000964
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000965 def UpdateUserHelpChangedItems(self):
Kurt B. Kaiser8e92bf72003-01-14 22:03:31 +0000966 "Clear and rebuild the HelpFiles section in self.changedItems"
967 self.changedItems['main']['HelpFiles'] = {}
Terry Jan Reedyae410862014-08-03 23:02:53 -0400968 for num in range(1, len(self.userHelpList) + 1):
969 self.AddChangedItem(
970 'main', 'HelpFiles', str(num),
Terry Jan Reedy110796f2014-07-27 04:07:18 -0400971 ';'.join(self.userHelpList[num-1][:2]))
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000972
Steven M. Gava429a86a2001-10-23 10:42:12 +0000973 def LoadFontCfg(self):
974 ##base editor font selection list
Terry Jan Reedyae410862014-08-03 23:02:53 -0400975 fonts = list(tkFont.families(self))
Steven M. Gavac11ccf32001-09-24 09:43:17 +0000976 fonts.sort()
977 for font in fonts:
Terry Jan Reedyae410862014-08-03 23:02:53 -0400978 self.listFontName.insert(END, font)
979 configuredFont = idleConf.GetOption(
980 'main', 'EditorWindow', 'font', default='courier')
Kurt B. Kaiser05391692003-05-26 20:35:53 +0000981 lc_configuredFont = configuredFont.lower()
982 self.fontName.set(lc_configuredFont)
983 lc_fonts = [s.lower() for s in fonts]
984 if lc_configuredFont in lc_fonts:
985 currentFontIndex = lc_fonts.index(lc_configuredFont)
Steven M. Gava429a86a2001-10-23 10:42:12 +0000986 self.listFontName.see(currentFontIndex)
987 self.listFontName.select_set(currentFontIndex)
Steven M. Gavac112cd82002-01-22 05:56:40 +0000988 self.listFontName.select_anchor(currentFontIndex)
Steven M. Gava429a86a2001-10-23 10:42:12 +0000989 ##font size dropdown
Terry Jan Reedyae410862014-08-03 23:02:53 -0400990 fontSize = idleConf.GetOption(
991 'main', 'EditorWindow', 'font-size', type='int', default='10')
992 self.optMenuFontSize.SetMenu(('7', '8', '9', '10', '11', '12', '13',
993 '14', '16', '18', '20', '22'), fontSize )
Steven M. Gavac112cd82002-01-22 05:56:40 +0000994 ##fontWeight
Terry Jan Reedyae410862014-08-03 23:02:53 -0400995 self.fontBold.set(idleConf.GetOption(
996 'main', 'EditorWindow', 'font-bold', default=0, type='bool'))
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000997 ##font sample
Steven M. Gava429a86a2001-10-23 10:42:12 +0000998 self.SetFontSample()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000999
Steven M. Gava429a86a2001-10-23 10:42:12 +00001000 def LoadTabCfg(self):
Steven M. Gava429a86a2001-10-23 10:42:12 +00001001 ##indent sizes
Terry Jan Reedyae410862014-08-03 23:02:53 -04001002 spaceNum = idleConf.GetOption(
1003 'main', 'Indent', 'num-spaces', default=4, type='int')
Steven M. Gava429a86a2001-10-23 10:42:12 +00001004 self.spaceNum.set(spaceNum)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001005
Steven M. Gava9dd16b32001-11-03 14:54:25 +00001006 def LoadThemeCfg(self):
Steven M. Gava41a85322001-10-29 08:05:34 +00001007 ##current theme type radiobutton
Terry Jan Reedyae410862014-08-03 23:02:53 -04001008 self.themeIsBuiltin.set(idleConf.GetOption(
1009 'main', 'Theme', 'default', type='bool', default=1))
Steven M. Gava41a85322001-10-29 08:05:34 +00001010 ##currently set theme
Terry Jan Reedyae410862014-08-03 23:02:53 -04001011 currentOption = idleConf.CurrentTheme()
Steven M. Gava7c017862001-10-29 11:19:46 +00001012 ##load available theme option menus
Steven M. Gavad0342cd2001-11-04 11:53:10 +00001013 if self.themeIsBuiltin.get(): #default theme selected
Terry Jan Reedyae410862014-08-03 23:02:53 -04001014 itemList = idleConf.GetSectionList('default', 'highlight')
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +00001015 itemList.sort()
Terry Jan Reedyae410862014-08-03 23:02:53 -04001016 self.optMenuThemeBuiltin.SetMenu(itemList, currentOption)
1017 itemList = idleConf.GetSectionList('user', 'highlight')
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +00001018 itemList.sort()
Steven M. Gava41a85322001-10-29 08:05:34 +00001019 if not itemList:
1020 self.radioThemeCustom.config(state=DISABLED)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001021 self.customTheme.set('- no custom themes -')
Steven M. Gava41a85322001-10-29 08:05:34 +00001022 else:
Terry Jan Reedyae410862014-08-03 23:02:53 -04001023 self.optMenuThemeCustom.SetMenu(itemList, itemList[0])
Steven M. Gava9dd16b32001-11-03 14:54:25 +00001024 else: #user theme selected
Terry Jan Reedyae410862014-08-03 23:02:53 -04001025 itemList = idleConf.GetSectionList('user', 'highlight')
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +00001026 itemList.sort()
Terry Jan Reedyae410862014-08-03 23:02:53 -04001027 self.optMenuThemeCustom.SetMenu(itemList, currentOption)
1028 itemList = idleConf.GetSectionList('default', 'highlight')
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +00001029 itemList.sort()
Terry Jan Reedyae410862014-08-03 23:02:53 -04001030 self.optMenuThemeBuiltin.SetMenu(itemList, itemList[0])
Steven M. Gava7c017862001-10-29 11:19:46 +00001031 self.SetThemeType()
1032 ##load theme element option menu
Terry Jan Reedyae410862014-08-03 23:02:53 -04001033 themeNames = self.themeElements.keys()
Florent Xiclunaa7f242f2010-04-02 08:15:26 +00001034 themeNames.sort(key=lambda x: self.themeElements[x][1])
Terry Jan Reedyae410862014-08-03 23:02:53 -04001035 self.optMenuHighlightTarget.SetMenu(themeNames, themeNames[0])
Steven M. Gava9dd16b32001-11-03 14:54:25 +00001036 self.PaintThemeSample()
Steven M. Gava0cae01c2002-01-04 07:53:06 +00001037 self.SetHighlightTarget()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001038
Steven M. Gava9dd16b32001-11-03 14:54:25 +00001039 def LoadKeyCfg(self):
Steven M. Gava41a85322001-10-29 08:05:34 +00001040 ##current keys type radiobutton
Terry Jan Reedyae410862014-08-03 23:02:53 -04001041 self.keysAreBuiltin.set(idleConf.GetOption(
1042 'main', 'Keys', 'default', type='bool', default=1))
Steven M. Gava41a85322001-10-29 08:05:34 +00001043 ##currently set keys
Terry Jan Reedyae410862014-08-03 23:02:53 -04001044 currentOption = idleConf.CurrentKeys()
Steven M. Gava7c017862001-10-29 11:19:46 +00001045 ##load available keyset option menus
Steven M. Gava052937f2002-02-11 02:20:53 +00001046 if self.keysAreBuiltin.get(): #default theme selected
Terry Jan Reedyae410862014-08-03 23:02:53 -04001047 itemList = idleConf.GetSectionList('default', 'keys')
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +00001048 itemList.sort()
Terry Jan Reedyae410862014-08-03 23:02:53 -04001049 self.optMenuKeysBuiltin.SetMenu(itemList, currentOption)
1050 itemList = idleConf.GetSectionList('user', 'keys')
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +00001051 itemList.sort()
Steven M. Gava41a85322001-10-29 08:05:34 +00001052 if not itemList:
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001053 self.radioKeysCustom.config(state=DISABLED)
1054 self.customKeys.set('- no custom keys -')
Steven M. Gava41a85322001-10-29 08:05:34 +00001055 else:
Terry Jan Reedyae410862014-08-03 23:02:53 -04001056 self.optMenuKeysCustom.SetMenu(itemList, itemList[0])
Steven M. Gavaa498af22002-02-01 01:33:36 +00001057 else: #user key set selected
Terry Jan Reedyae410862014-08-03 23:02:53 -04001058 itemList = idleConf.GetSectionList('user', 'keys')
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +00001059 itemList.sort()
Terry Jan Reedyae410862014-08-03 23:02:53 -04001060 self.optMenuKeysCustom.SetMenu(itemList, currentOption)
1061 itemList = idleConf.GetSectionList('default', 'keys')
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +00001062 itemList.sort()
Terry Jan Reedyae410862014-08-03 23:02:53 -04001063 self.optMenuKeysBuiltin.SetMenu(itemList, itemList[0])
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001064 self.SetKeysType()
Steven M. Gavafacfc092002-01-19 00:29:54 +00001065 ##load keyset element list
Terry Jan Reedyae410862014-08-03 23:02:53 -04001066 keySetName = idleConf.CurrentKeys()
Steven M. Gava052937f2002-02-11 02:20:53 +00001067 self.LoadKeysList(keySetName)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001068
Steven M. Gavafacfc092002-01-19 00:29:54 +00001069 def LoadGeneralCfg(self):
Steven M. Gava5f28e8f2002-01-21 06:38:21 +00001070 #startup state
Terry Jan Reedyae410862014-08-03 23:02:53 -04001071 self.startupEdit.set(idleConf.GetOption(
1072 'main', 'General', 'editor-on-startup', default=1, type='bool'))
Kurt B. Kaiser6c638b62003-05-26 06:23:10 +00001073 #autosave state
Terry Jan Reedyae410862014-08-03 23:02:53 -04001074 self.autoSave.set(idleConf.GetOption(
1075 'main', 'General', 'autosave', default=0, type='bool'))
Steven M. Gavafacfc092002-01-19 00:29:54 +00001076 #initial window size
Terry Jan Reedyae410862014-08-03 23:02:53 -04001077 self.winWidth.set(idleConf.GetOption(
1078 'main', 'EditorWindow', 'width', type='int'))
1079 self.winHeight.set(idleConf.GetOption(
1080 'main', 'EditorWindow', 'height', type='int'))
Kurt B. Kaisera053f332003-05-10 00:49:56 +00001081 # default source encoding
Terry Jan Reedyae410862014-08-03 23:02:53 -04001082 self.encoding.set(idleConf.GetOption(
1083 'main', 'EditorWindow', 'encoding', default='none'))
Kurt B. Kaiser8e92bf72003-01-14 22:03:31 +00001084 # additional help sources
1085 self.userHelpList = idleConf.GetAllExtraHelpSourcesList()
Steven M. Gava085eb1b2002-02-05 04:52:32 +00001086 for helpItem in self.userHelpList:
Terry Jan Reedyae410862014-08-03 23:02:53 -04001087 self.listHelp.insert(END, helpItem[0])
Steven M. Gava085eb1b2002-02-05 04:52:32 +00001088 self.SetHelpListButtonStates()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001089
Steven M. Gava429a86a2001-10-23 10:42:12 +00001090 def LoadConfigs(self):
1091 """
1092 load configuration from default and user config files and populate
1093 the widgets on the config dialog pages.
1094 """
1095 ### fonts / tabs page
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001096 self.LoadFontCfg()
1097 self.LoadTabCfg()
Steven M. Gava429a86a2001-10-23 10:42:12 +00001098 ### highlighting page
Steven M. Gava9dd16b32001-11-03 14:54:25 +00001099 self.LoadThemeCfg()
Steven M. Gava429a86a2001-10-23 10:42:12 +00001100 ### keys page
Steven M. Gava9dd16b32001-11-03 14:54:25 +00001101 self.LoadKeyCfg()
Steven M. Gava429a86a2001-10-23 10:42:12 +00001102 ### general page
Steven M. Gavafacfc092002-01-19 00:29:54 +00001103 self.LoadGeneralCfg()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001104
Terry Jan Reedyae410862014-08-03 23:02:53 -04001105 def SaveNewKeySet(self, keySetName, keySet):
Steven M. Gava052937f2002-02-11 02:20:53 +00001106 """
1107 save a newly created core key set.
1108 keySetName - string, the name of the new key set
1109 keySet - dictionary containing the new key set
1110 """
1111 if not idleConf.userCfg['keys'].has_section(keySetName):
1112 idleConf.userCfg['keys'].add_section(keySetName)
Terry Jan Reedy110796f2014-07-27 04:07:18 -04001113 for event in keySet:
Terry Jan Reedyae410862014-08-03 23:02:53 -04001114 value = keySet[event]
1115 idleConf.userCfg['keys'].SetOption(keySetName, event, value)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001116
Terry Jan Reedyae410862014-08-03 23:02:53 -04001117 def SaveNewTheme(self, themeName, theme):
Steven M. Gava052937f2002-02-11 02:20:53 +00001118 """
1119 save a newly created theme.
1120 themeName - string, the name of the new theme
1121 theme - dictionary containing the new theme
1122 """
1123 if not idleConf.userCfg['highlight'].has_section(themeName):
1124 idleConf.userCfg['highlight'].add_section(themeName)
Terry Jan Reedy110796f2014-07-27 04:07:18 -04001125 for element in theme:
Terry Jan Reedyae410862014-08-03 23:02:53 -04001126 value = theme[element]
1127 idleConf.userCfg['highlight'].SetOption(themeName, element, value)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001128
Terry Jan Reedyae410862014-08-03 23:02:53 -04001129 def SetUserValue(self, configType, section, item, value):
1130 if idleConf.defaultCfg[configType].has_option(section, item):
1131 if idleConf.defaultCfg[configType].Get(section, item) == value:
Steven M. Gava2d7bb3f2002-01-29 08:35:29 +00001132 #the setting equals a default setting, remove it from user cfg
Terry Jan Reedyae410862014-08-03 23:02:53 -04001133 return idleConf.userCfg[configType].RemoveOption(section, item)
Steven M. Gava2d7bb3f2002-01-29 08:35:29 +00001134 #if we got here set the option
Terry Jan Reedyae410862014-08-03 23:02:53 -04001135 return idleConf.userCfg[configType].SetOption(section, item, value)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001136
Steven M. Gava052937f2002-02-11 02:20:53 +00001137 def SaveAllChangedConfigs(self):
Kurt B. Kaisere7a161e2003-01-10 20:13:57 +00001138 "Save configuration changes to the user config file."
Steven M. Gava0c5bc8c2002-03-27 02:25:44 +00001139 idleConf.userCfg['main'].Save()
Terry Jan Reedy110796f2014-07-27 04:07:18 -04001140 for configType in self.changedItems:
Kurt B. Kaisere7a161e2003-01-10 20:13:57 +00001141 cfgTypeHasChanges = False
Terry Jan Reedy110796f2014-07-27 04:07:18 -04001142 for section in self.changedItems[configType]:
Kurt B. Kaisere7a161e2003-01-10 20:13:57 +00001143 if section == 'HelpFiles':
1144 #this section gets completely replaced
1145 idleConf.userCfg['main'].remove_section('HelpFiles')
Kurt B. Kaiser8e92bf72003-01-14 22:03:31 +00001146 cfgTypeHasChanges = True
Terry Jan Reedy110796f2014-07-27 04:07:18 -04001147 for item in self.changedItems[configType][section]:
Kurt B. Kaisere7a161e2003-01-10 20:13:57 +00001148 value = self.changedItems[configType][section][item]
Terry Jan Reedyae410862014-08-03 23:02:53 -04001149 if self.SetUserValue(configType, section, item, value):
Kurt B. Kaisere7a161e2003-01-10 20:13:57 +00001150 cfgTypeHasChanges = True
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001151 if cfgTypeHasChanges:
1152 idleConf.userCfg[configType].Save()
Kurt B. Kaiser5acdf932004-11-16 21:28:36 +00001153 for configType in ['keys', 'highlight']:
1154 # save these even if unchanged!
1155 idleConf.userCfg[configType].Save()
Steven M. Gavaa498af22002-02-01 01:33:36 +00001156 self.ResetChangedItems() #clear the changed items dict
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001157
Kurt B. Kaiserb1754452005-11-18 22:05:48 +00001158 def DeactivateCurrentConfig(self):
1159 #Before a config is saved, some cleanup of current
1160 #config must be done - remove the previous keybindings
Terry Jan Reedyae410862014-08-03 23:02:53 -04001161 winInstances = self.parent.instance_dict
Kurt B. Kaiserb1754452005-11-18 22:05:48 +00001162 for instance in winInstances:
1163 instance.RemoveKeybindings()
1164
Steven M. Gava49745752002-02-18 01:43:11 +00001165 def ActivateConfigChanges(self):
Kurt B. Kaiseracdef852005-01-31 03:34:26 +00001166 "Dynamically apply configuration changes"
Terry Jan Reedy110796f2014-07-27 04:07:18 -04001167 winInstances = self.parent.instance_dict.keys()
Steven M. Gavab77d3432002-03-02 07:16:21 +00001168 for instance in winInstances:
1169 instance.ResetColorizer()
Steven M. Gavab1585412002-03-12 00:21:56 +00001170 instance.ResetFont()
Kurt B. Kaiseracdef852005-01-31 03:34:26 +00001171 instance.set_notabs_indentwidth()
Kurt B. Kaiserb1754452005-11-18 22:05:48 +00001172 instance.ApplyKeybindings()
Kurt B. Kaiser8e92bf72003-01-14 22:03:31 +00001173 instance.reset_help_menu_entries()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001174
Steven M. Gava5f28e8f2002-01-21 06:38:21 +00001175 def Cancel(self):
1176 self.destroy()
1177
1178 def Ok(self):
1179 self.Apply()
1180 self.destroy()
1181
1182 def Apply(self):
Kurt B. Kaiserb1754452005-11-18 22:05:48 +00001183 self.DeactivateCurrentConfig()
Steven M. Gava052937f2002-02-11 02:20:53 +00001184 self.SaveAllChangedConfigs()
Steven M. Gava49745752002-02-18 01:43:11 +00001185 self.ActivateConfigChanges()
Steven M. Gava5f28e8f2002-01-21 06:38:21 +00001186
1187 def Help(self):
Steven M. Gavac11ccf32001-09-24 09:43:17 +00001188 pass
1189
Terry Jan Reedy7a162072014-10-22 20:15:12 -04001190class VerticalScrolledFrame(Frame):
1191 """A pure Tkinter vertically scrollable frame.
1192
1193 * Use the 'interior' attribute to place widgets inside the scrollable frame
1194 * Construct and pack/place/grid normally
1195 * This frame only allows vertical scrolling
1196 """
1197 def __init__(self, parent, *args, **kw):
1198 Frame.__init__(self, parent, *args, **kw)
1199
1200 # create a canvas object and a vertical scrollbar for scrolling it
1201 vscrollbar = Scrollbar(self, orient=VERTICAL)
1202 vscrollbar.pack(fill=Y, side=RIGHT, expand=FALSE)
1203 canvas = Canvas(self, bd=0, highlightthickness=0,
1204 yscrollcommand=vscrollbar.set)
1205 canvas.pack(side=LEFT, fill=BOTH, expand=TRUE)
1206 vscrollbar.config(command=canvas.yview)
1207
1208 # reset the view
1209 canvas.xview_moveto(0)
1210 canvas.yview_moveto(0)
1211
1212 # create a frame inside the canvas which will be scrolled with it
1213 self.interior = interior = Frame(canvas)
1214 interior_id = canvas.create_window(0, 0, window=interior, anchor=NW)
1215
1216 # track changes to the canvas and frame width and sync them,
1217 # also updating the scrollbar
1218 def _configure_interior(event):
1219 # update the scrollbars to match the size of the inner frame
1220 size = (interior.winfo_reqwidth(), interior.winfo_reqheight())
1221 canvas.config(scrollregion="0 0 %s %s" % size)
1222 if interior.winfo_reqwidth() != canvas.winfo_width():
1223 # update the canvas's width to fit the inner frame
1224 canvas.config(width=interior.winfo_reqwidth())
1225 interior.bind('<Configure>', _configure_interior)
1226
1227 def _configure_canvas(event):
1228 if interior.winfo_reqwidth() != canvas.winfo_width():
1229 # update the inner frame's width to fill the canvas
1230 canvas.itemconfigure(interior_id, width=canvas.winfo_width())
1231 canvas.bind('<Configure>', _configure_canvas)
1232
1233 return
1234
1235def is_int(s):
1236 "Return 's is blank or represents an int'"
1237 if not s:
1238 return True
1239 try:
1240 int(s)
1241 return True
1242 except ValueError:
1243 return False
1244
1245# TODO:
1246# * Revert to default(s)? Per option or per extension?
1247# * List options in their original order (possible??)
1248class ConfigExtensionsDialog(Toplevel):
1249 """A dialog for configuring IDLE extensions.
1250
1251 This dialog is generic - it works for any and all IDLE extensions.
1252
1253 IDLE extensions save their configuration options using idleConf.
1254 ConfigExtensionsDialog reads the current configuration using idleConf,
1255 supplies a GUI interface to change the configuration values, and saves the
1256 changes using idleConf.
1257
1258 Not all changes take effect immediately - some may require restarting IDLE.
1259 This depends on each extension's implementation.
1260
1261 All values are treated as text, and it is up to the user to supply
1262 reasonable values. The only exception to this are the 'enable*' options,
1263 which are boolean, and can be toggled with an True/False button.
1264 """
1265 def __init__(self, parent, title=None, _htest=False):
1266 Toplevel.__init__(self, parent)
1267 self.wm_withdraw()
1268
1269 self.configure(borderwidth=5)
1270 self.geometry(
1271 "+%d+%d" % (parent.winfo_rootx() + 20,
1272 parent.winfo_rooty() + (30 if not _htest else 150)))
1273 self.wm_title(title or 'IDLE Extensions Configuration')
1274
1275 self.defaultCfg = idleConf.defaultCfg['extensions']
1276 self.userCfg = idleConf.userCfg['extensions']
1277 self.is_int = self.register(is_int)
1278 self.load_extensions()
1279 self.create_widgets()
1280
1281 self.resizable(height=FALSE, width=FALSE) # don't allow resizing yet
1282 self.transient(parent)
1283 self.protocol("WM_DELETE_WINDOW", self.Cancel)
1284 self.tabbed_page_set.focus_set()
1285 # wait for window to be generated
1286 self.update()
1287 # set current width as the minimum width
1288 self.wm_minsize(self.winfo_width(), 1)
1289 # now allow resizing
1290 self.resizable(height=TRUE, width=TRUE)
1291
1292 self.wm_deiconify()
1293 if not _htest:
1294 self.grab_set()
1295 self.wait_window()
1296
1297 def load_extensions(self):
1298 "Fill self.extensions with data from the default and user configs."
1299 self.extensions = {}
1300 for ext_name in idleConf.GetExtensions(active_only=False):
1301 self.extensions[ext_name] = []
1302
1303 for ext_name in self.extensions:
1304 opt_list = sorted(self.defaultCfg.GetOptionList(ext_name))
1305
1306 # bring 'enable' options to the beginning of the list
1307 enables = [opt_name for opt_name in opt_list
1308 if opt_name.startswith('enable')]
1309 for opt_name in enables:
1310 opt_list.remove(opt_name)
1311 opt_list = enables + opt_list
1312
1313 for opt_name in opt_list:
1314 def_str = self.defaultCfg.Get(
1315 ext_name, opt_name, raw=True)
1316 try:
1317 def_obj = {'True':True, 'False':False}[def_str]
1318 opt_type = 'bool'
1319 except KeyError:
1320 try:
1321 def_obj = int(def_str)
1322 opt_type = 'int'
1323 except ValueError:
1324 def_obj = def_str
1325 opt_type = None
1326 try:
1327 value = self.userCfg.Get(
1328 ext_name, opt_name, type=opt_type, raw=True,
1329 default=def_obj)
1330 except ValueError: # Need this until .Get fixed
1331 value = def_obj # bad values overwritten by entry
1332 var = StringVar(self)
1333 var.set(str(value))
1334
1335 self.extensions[ext_name].append({'name': opt_name,
1336 'type': opt_type,
1337 'default': def_str,
1338 'value': value,
1339 'var': var,
1340 })
1341
1342 def create_widgets(self):
1343 """Create the dialog's widgets."""
1344 self.rowconfigure(0, weight=1)
1345 self.rowconfigure(1, weight=0)
1346 self.columnconfigure(0, weight=1)
1347
1348 # create the tabbed pages
1349 self.tabbed_page_set = TabbedPageSet(
1350 self, page_names=self.extensions.keys(),
1351 n_rows=None, max_tabs_per_row=5,
1352 page_class=TabbedPageSet.PageRemove)
1353 self.tabbed_page_set.grid(row=0, column=0, sticky=NSEW)
1354 for ext_name in self.extensions:
1355 self.create_tab_page(ext_name)
1356
1357 self.create_action_buttons().grid(row=1)
1358
1359 create_action_buttons = ConfigDialog.create_action_buttons.im_func
1360
1361 def create_tab_page(self, ext_name):
1362 """Create the page for an extension."""
1363
1364 page = LabelFrame(self.tabbed_page_set.pages[ext_name].frame,
1365 border=2, padx=2, relief=GROOVE,
1366 text=' %s ' % ext_name)
1367 page.pack(fill=BOTH, expand=True, padx=12, pady=2)
1368
1369 # create the scrollable frame which will contain the entries
1370 scrolled_frame = VerticalScrolledFrame(page, pady=2, height=250)
1371 scrolled_frame.pack(side=BOTTOM, fill=BOTH, expand=TRUE)
1372 entry_area = scrolled_frame.interior
1373 entry_area.columnconfigure(0, weight=0)
1374 entry_area.columnconfigure(1, weight=1)
1375
1376 # create an entry for each configuration option
1377 for row, opt in enumerate(self.extensions[ext_name]):
1378 # create a row with a label and entry/checkbutton
1379 label = Label(entry_area, text=opt['name'])
1380 label.grid(row=row, column=0, sticky=NW)
1381 var = opt['var']
1382 if opt['type'] == 'bool':
1383 Checkbutton(entry_area, textvariable=var, variable=var,
1384 onvalue='True', offvalue='False',
1385 indicatoron=FALSE, selectcolor='', width=8
1386 ).grid(row=row, column=1, sticky=W, padx=7)
1387 elif opt['type'] == 'int':
1388 Entry(entry_area, textvariable=var, validate='key',
1389 validatecommand=(self.is_int, '%P')
1390 ).grid(row=row, column=1, sticky=NSEW, padx=7)
1391
1392 else:
1393 Entry(entry_area, textvariable=var
1394 ).grid(row=row, column=1, sticky=NSEW, padx=7)
1395 return
1396
1397
1398 Ok = ConfigDialog.Ok.im_func
1399
1400 def Apply(self):
1401 self.save_all_changed_configs()
1402 pass
1403
1404 Cancel = ConfigDialog.Cancel.im_func
1405
1406 def Help(self):
1407 pass
1408
1409 def set_user_value(self, section, opt):
1410 name = opt['name']
1411 default = opt['default']
1412 value = opt['var'].get().strip() or default
1413 opt['var'].set(value)
1414 # if self.defaultCfg.has_section(section):
1415 # Currently, always true; if not, indent to return
1416 if (value == default):
1417 return self.userCfg.RemoveOption(section, name)
1418 # set the option
1419 return self.userCfg.SetOption(section, name, value)
1420
1421 def save_all_changed_configs(self):
1422 """Save configuration changes to the user config file."""
1423 has_changes = False
1424 for ext_name in self.extensions:
1425 options = self.extensions[ext_name]
1426 for opt in options:
1427 if self.set_user_value(ext_name, opt):
1428 has_changes = True
1429 if has_changes:
1430 self.userCfg.Save()
1431
1432
Steven M. Gava44d3d1a2001-07-31 06:59:02 +00001433if __name__ == '__main__':
Terry Jan Reedyaf0dce92014-07-14 23:07:21 -04001434 import unittest
1435 unittest.main('idlelib.idle_test.test_configdialog',
1436 verbosity=2, exit=False)
Terry Jan Reedy76916e82014-05-29 01:46:16 -04001437 from idlelib.idle_test.htest import run
Terry Jan Reedy7a162072014-10-22 20:15:12 -04001438 run(ConfigDialog, ConfigExtensionsDialog)