blob: 4a759b46440f7f501fbed5082a104d1db573e65c [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()
527 self.AddChangedItem('main', 'Theme', 'name', value)
Steven M. Gava052937f2002-02-11 02:20:53 +0000528 self.PaintThemeSample()
529
Terry Jan Reedyae410862014-08-03 23:02:53 -0400530 def VarChanged_customTheme(self, *params):
531 value = self.customTheme.get()
Steven M. Gava49745752002-02-18 01:43:11 +0000532 if value != '- no custom themes -':
Terry Jan Reedyae410862014-08-03 23:02:53 -0400533 self.AddChangedItem('main', 'Theme', 'name', value)
Steven M. Gava49745752002-02-18 01:43:11 +0000534 self.PaintThemeSample()
Steven M. Gava052937f2002-02-11 02:20:53 +0000535
Terry Jan Reedyae410862014-08-03 23:02:53 -0400536 def VarChanged_themeIsBuiltin(self, *params):
537 value = self.themeIsBuiltin.get()
538 self.AddChangedItem('main', 'Theme', 'default', value)
Steven M. Gavaf31eec02002-03-05 00:25:58 +0000539 if value:
540 self.VarChanged_builtinTheme()
541 else:
542 self.VarChanged_customTheme()
Steven M. Gava052937f2002-02-11 02:20:53 +0000543
Terry Jan Reedyae410862014-08-03 23:02:53 -0400544 def VarChanged_highlightTarget(self, *params):
Steven M. Gava052937f2002-02-11 02:20:53 +0000545 self.SetHighlightTarget()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000546
Terry Jan Reedyae410862014-08-03 23:02:53 -0400547 def VarChanged_keyBinding(self, *params):
548 value = self.keyBinding.get()
549 keySet = self.customKeys.get()
550 event = self.listBindings.get(ANCHOR).split()[0]
Steven M. Gavaa498af22002-02-01 01:33:36 +0000551 if idleConf.IsCoreBinding(event):
552 #this is a core keybinding
Terry Jan Reedyae410862014-08-03 23:02:53 -0400553 self.AddChangedItem('keys', keySet, event, value)
Steven M. Gavaa498af22002-02-01 01:33:36 +0000554 else: #this is an extension key binding
Terry Jan Reedyae410862014-08-03 23:02:53 -0400555 extName = idleConf.GetExtnNameForEvent(event)
556 extKeybindSection = extName + '_cfgBindings'
557 self.AddChangedItem('extensions', extKeybindSection, event, value)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000558
Terry Jan Reedyae410862014-08-03 23:02:53 -0400559 def VarChanged_builtinKeys(self, *params):
560 value = self.builtinKeys.get()
561 self.AddChangedItem('main', 'Keys', 'name', value)
Steven M. Gava052937f2002-02-11 02:20:53 +0000562 self.LoadKeysList(value)
563
Terry Jan Reedyae410862014-08-03 23:02:53 -0400564 def VarChanged_customKeys(self, *params):
565 value = self.customKeys.get()
Steven M. Gava49745752002-02-18 01:43:11 +0000566 if value != '- no custom keys -':
Terry Jan Reedyae410862014-08-03 23:02:53 -0400567 self.AddChangedItem('main', 'Keys', 'name', value)
Steven M. Gava49745752002-02-18 01:43:11 +0000568 self.LoadKeysList(value)
Steven M. Gava052937f2002-02-11 02:20:53 +0000569
Terry Jan Reedyae410862014-08-03 23:02:53 -0400570 def VarChanged_keysAreBuiltin(self, *params):
571 value = self.keysAreBuiltin.get()
572 self.AddChangedItem('main', 'Keys', 'default', value)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000573 if value:
Steven M. Gavaf31eec02002-03-05 00:25:58 +0000574 self.VarChanged_builtinKeys()
Steven M. Gava052937f2002-02-11 02:20:53 +0000575 else:
Steven M. Gavaf31eec02002-03-05 00:25:58 +0000576 self.VarChanged_customKeys()
Steven M. Gava052937f2002-02-11 02:20:53 +0000577
Terry Jan Reedyae410862014-08-03 23:02:53 -0400578 def VarChanged_winWidth(self, *params):
579 value = self.winWidth.get()
580 self.AddChangedItem('main', 'EditorWindow', 'width', value)
Steven M. Gavac112cd82002-01-22 05:56:40 +0000581
Terry Jan Reedyae410862014-08-03 23:02:53 -0400582 def VarChanged_winHeight(self, *params):
583 value = self.winHeight.get()
584 self.AddChangedItem('main', 'EditorWindow', 'height', value)
Steven M. Gavac112cd82002-01-22 05:56:40 +0000585
Terry Jan Reedyae410862014-08-03 23:02:53 -0400586 def VarChanged_startupEdit(self, *params):
587 value = self.startupEdit.get()
588 self.AddChangedItem('main', 'General', 'editor-on-startup', value)
Steven M. Gavac112cd82002-01-22 05:56:40 +0000589
Terry Jan Reedyae410862014-08-03 23:02:53 -0400590 def VarChanged_autoSave(self, *params):
591 value = self.autoSave.get()
592 self.AddChangedItem('main', 'General', 'autosave', value)
Kurt B. Kaiser6c638b62003-05-26 06:23:10 +0000593
Terry Jan Reedyae410862014-08-03 23:02:53 -0400594 def VarChanged_encoding(self, *params):
595 value = self.encoding.get()
596 self.AddChangedItem('main', 'EditorWindow', 'encoding', value)
Kurt B. Kaisera053f332003-05-10 00:49:56 +0000597
Steven M. Gavaa498af22002-02-01 01:33:36 +0000598 def ResetChangedItems(self):
Steven M. Gavab77d3432002-03-02 07:16:21 +0000599 #When any config item is changed in this dialog, an entry
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000600 #should be made in the relevant section (config type) of this
601 #dictionary. The key should be the config file section name and the
Steven M. Gavaa498af22002-02-01 01:33:36 +0000602 #value a dictionary, whose key:value pairs are item=value pairs for
603 #that config file section.
Terry Jan Reedyae410862014-08-03 23:02:53 -0400604 self.changedItems = {'main':{}, 'highlight':{}, 'keys':{},
605 'extensions':{}}
Steven M. Gavaa498af22002-02-01 01:33:36 +0000606
Terry Jan Reedyae410862014-08-03 23:02:53 -0400607 def AddChangedItem(self, typ, section, item, value):
608 value = str(value) #make sure we use a string
609 if section not in self.changedItems[typ]:
610 self.changedItems[typ][section] = {}
611 self.changedItems[typ][section][item] = value
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000612
Steven M. Gava5f28e8f2002-01-21 06:38:21 +0000613 def GetDefaultItems(self):
Terry Jan Reedyae410862014-08-03 23:02:53 -0400614 dItems={'main':{}, 'highlight':{}, 'keys':{}, 'extensions':{}}
Terry Jan Reedy110796f2014-07-27 04:07:18 -0400615 for configType in dItems:
Terry Jan Reedyae410862014-08-03 23:02:53 -0400616 sections = idleConf.GetSectionList('default', configType)
Steven M. Gava5f28e8f2002-01-21 06:38:21 +0000617 for section in sections:
Terry Jan Reedyae410862014-08-03 23:02:53 -0400618 dItems[configType][section] = {}
619 options = idleConf.defaultCfg[configType].GetOptionList(section)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000620 for option in options:
Terry Jan Reedyae410862014-08-03 23:02:53 -0400621 dItems[configType][section][option] = (
622 idleConf.defaultCfg[configType].Get(section, option))
Steven M. Gava5f28e8f2002-01-21 06:38:21 +0000623 return dItems
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000624
Steven M. Gava5f28e8f2002-01-21 06:38:21 +0000625 def SetThemeType(self):
626 if self.themeIsBuiltin.get():
627 self.optMenuThemeBuiltin.config(state=NORMAL)
628 self.optMenuThemeCustom.config(state=DISABLED)
629 self.buttonDeleteCustomTheme.config(state=DISABLED)
630 else:
631 self.optMenuThemeBuiltin.config(state=DISABLED)
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000632 self.radioThemeCustom.config(state=NORMAL)
Steven M. Gava5f28e8f2002-01-21 06:38:21 +0000633 self.optMenuThemeCustom.config(state=NORMAL)
634 self.buttonDeleteCustomTheme.config(state=NORMAL)
635
636 def SetKeysType(self):
Steven M. Gava052937f2002-02-11 02:20:53 +0000637 if self.keysAreBuiltin.get():
Steven M. Gava5f28e8f2002-01-21 06:38:21 +0000638 self.optMenuKeysBuiltin.config(state=NORMAL)
639 self.optMenuKeysCustom.config(state=DISABLED)
640 self.buttonDeleteCustomKeys.config(state=DISABLED)
641 else:
642 self.optMenuKeysBuiltin.config(state=DISABLED)
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000643 self.radioKeysCustom.config(state=NORMAL)
Steven M. Gava5f28e8f2002-01-21 06:38:21 +0000644 self.optMenuKeysCustom.config(state=NORMAL)
645 self.buttonDeleteCustomKeys.config(state=NORMAL)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000646
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000647 def GetNewKeys(self):
Terry Jan Reedyae410862014-08-03 23:02:53 -0400648 listIndex = self.listBindings.index(ANCHOR)
649 binding = self.listBindings.get(listIndex)
650 bindName = binding.split()[0] #first part, up to first space
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000651 if self.keysAreBuiltin.get():
Terry Jan Reedyae410862014-08-03 23:02:53 -0400652 currentKeySetName = self.builtinKeys.get()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000653 else:
Terry Jan Reedyae410862014-08-03 23:02:53 -0400654 currentKeySetName = self.customKeys.get()
655 currentBindings = idleConf.GetCurrentKeySet()
Terry Jan Reedy110796f2014-07-27 04:07:18 -0400656 if currentKeySetName in self.changedItems['keys']: #unsaved changes
Terry Jan Reedyae410862014-08-03 23:02:53 -0400657 keySetChanges = self.changedItems['keys'][currentKeySetName]
Terry Jan Reedy110796f2014-07-27 04:07:18 -0400658 for event in keySetChanges:
Terry Jan Reedyae410862014-08-03 23:02:53 -0400659 currentBindings[event] = keySetChanges[event].split()
660 currentKeySequences = currentBindings.values()
661 newKeys = GetKeysDialog(self, 'Get New Keys', bindName,
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000662 currentKeySequences).result
663 if newKeys: #new keys were specified
Steven M. Gava052937f2002-02-11 02:20:53 +0000664 if self.keysAreBuiltin.get(): #current key set is a built-in
Terry Jan Reedyae410862014-08-03 23:02:53 -0400665 message = ('Your changes will be saved as a new Custom Key Set.'
666 ' Enter a name for your new Custom Key Set below.')
667 newKeySet = self.GetNewKeysName(message)
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000668 if not newKeySet: #user cancelled custom key set creation
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000669 self.listBindings.select_set(listIndex)
670 self.listBindings.select_anchor(listIndex)
671 return
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000672 else: #create new custom key set based on previously active key set
673 self.CreateNewKeySet(newKeySet)
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000674 self.listBindings.delete(listIndex)
Terry Jan Reedyae410862014-08-03 23:02:53 -0400675 self.listBindings.insert(listIndex, bindName+' - '+newKeys)
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000676 self.listBindings.select_set(listIndex)
677 self.listBindings.select_anchor(listIndex)
Steven M. Gava052937f2002-02-11 02:20:53 +0000678 self.keyBinding.set(newKeys)
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000679 else:
680 self.listBindings.select_set(listIndex)
681 self.listBindings.select_anchor(listIndex)
682
Terry Jan Reedyae410862014-08-03 23:02:53 -0400683 def GetNewKeysName(self, message):
684 usedNames = (idleConf.GetSectionList('user', 'keys') +
685 idleConf.GetSectionList('default', 'keys'))
686 newKeySet = GetCfgSectionNameDialog(
687 self, 'New Custom Key Set', message, usedNames).result
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000688 return newKeySet
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000689
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000690 def SaveAsNewKeySet(self):
Terry Jan Reedyae410862014-08-03 23:02:53 -0400691 newKeysName = self.GetNewKeysName('New Key Set Name:')
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000692 if newKeysName:
693 self.CreateNewKeySet(newKeysName)
694
Terry Jan Reedyae410862014-08-03 23:02:53 -0400695 def KeyBindingSelected(self, event):
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000696 self.buttonNewKeys.config(state=NORMAL)
697
Terry Jan Reedyae410862014-08-03 23:02:53 -0400698 def CreateNewKeySet(self, newKeySetName):
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000699 #creates new custom key set based on the previously active key set,
700 #and makes the new key set active
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000701 if self.keysAreBuiltin.get():
Terry Jan Reedyae410862014-08-03 23:02:53 -0400702 prevKeySetName = self.builtinKeys.get()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000703 else:
Terry Jan Reedyae410862014-08-03 23:02:53 -0400704 prevKeySetName = self.customKeys.get()
705 prevKeys = idleConf.GetCoreKeys(prevKeySetName)
706 newKeys = {}
Terry Jan Reedy110796f2014-07-27 04:07:18 -0400707 for event in prevKeys: #add key set to changed items
Terry Jan Reedyae410862014-08-03 23:02:53 -0400708 eventName = event[2:-2] #trim off the angle brackets
709 binding = ' '.join(prevKeys[event])
710 newKeys[eventName] = binding
Steven M. Gava052937f2002-02-11 02:20:53 +0000711 #handle any unsaved changes to prev key set
Terry Jan Reedy110796f2014-07-27 04:07:18 -0400712 if prevKeySetName in self.changedItems['keys']:
Terry Jan Reedyae410862014-08-03 23:02:53 -0400713 keySetChanges = self.changedItems['keys'][prevKeySetName]
Terry Jan Reedy110796f2014-07-27 04:07:18 -0400714 for event in keySetChanges:
Terry Jan Reedyae410862014-08-03 23:02:53 -0400715 newKeys[event] = keySetChanges[event]
Steven M. Gava052937f2002-02-11 02:20:53 +0000716 #save the new theme
Terry Jan Reedyae410862014-08-03 23:02:53 -0400717 self.SaveNewKeySet(newKeySetName, newKeys)
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000718 #change gui over to the new key set
Terry Jan Reedyae410862014-08-03 23:02:53 -0400719 customKeyList = idleConf.GetSectionList('user', 'keys')
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000720 customKeyList.sort()
Terry Jan Reedyae410862014-08-03 23:02:53 -0400721 self.optMenuKeysCustom.SetMenu(customKeyList, newKeySetName)
Steven M. Gava052937f2002-02-11 02:20:53 +0000722 self.keysAreBuiltin.set(0)
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000723 self.SetKeysType()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000724
Terry Jan Reedyae410862014-08-03 23:02:53 -0400725 def LoadKeysList(self, keySetName):
726 reselect = 0
727 newKeySet = 0
Steven M. Gava052937f2002-02-11 02:20:53 +0000728 if self.listBindings.curselection():
Terry Jan Reedyae410862014-08-03 23:02:53 -0400729 reselect = 1
730 listIndex = self.listBindings.index(ANCHOR)
731 keySet = idleConf.GetKeySet(keySetName)
732 bindNames = keySet.keys()
Steven M. Gava052937f2002-02-11 02:20:53 +0000733 bindNames.sort()
Terry Jan Reedyae410862014-08-03 23:02:53 -0400734 self.listBindings.delete(0, END)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000735 for bindName in bindNames:
Terry Jan Reedyae410862014-08-03 23:02:53 -0400736 key = ' '.join(keySet[bindName]) #make key(s) into a string
737 bindName = bindName[2:-2] #trim off the angle brackets
Terry Jan Reedy110796f2014-07-27 04:07:18 -0400738 if keySetName in self.changedItems['keys']:
Steven M. Gava052937f2002-02-11 02:20:53 +0000739 #handle any unsaved changes to this key set
Terry Jan Reedy110796f2014-07-27 04:07:18 -0400740 if bindName in self.changedItems['keys'][keySetName]:
Terry Jan Reedyae410862014-08-03 23:02:53 -0400741 key = self.changedItems['keys'][keySetName][bindName]
Steven M. Gava052937f2002-02-11 02:20:53 +0000742 self.listBindings.insert(END, bindName+' - '+key)
Steven M. Gava052937f2002-02-11 02:20:53 +0000743 if reselect:
744 self.listBindings.see(listIndex)
745 self.listBindings.select_set(listIndex)
746 self.listBindings.select_anchor(listIndex)
747
Steven M. Gava49745752002-02-18 01:43:11 +0000748 def DeleteCustomKeys(self):
749 keySetName=self.customKeys.get()
Terry Jan Reedyae410862014-08-03 23:02:53 -0400750 delmsg = 'Are you sure you wish to delete the key set %r ?'
751 if not tkMessageBox.askyesno(
752 'Delete Key Set', delmsg % keySetName, parent=self):
Steven M. Gava49745752002-02-18 01:43:11 +0000753 return
754 #remove key set from config
755 idleConf.userCfg['keys'].remove_section(keySetName)
Benjamin Peterson6e3dbbd2009-10-09 22:15:50 +0000756 if keySetName in self.changedItems['keys']:
Steven M. Gava49745752002-02-18 01:43:11 +0000757 del(self.changedItems['keys'][keySetName])
758 #write changes
759 idleConf.userCfg['keys'].Save()
760 #reload user key set list
Terry Jan Reedyae410862014-08-03 23:02:53 -0400761 itemList = idleConf.GetSectionList('user', 'keys')
Steven M. Gava49745752002-02-18 01:43:11 +0000762 itemList.sort()
763 if not itemList:
764 self.radioKeysCustom.config(state=DISABLED)
Terry Jan Reedyae410862014-08-03 23:02:53 -0400765 self.optMenuKeysCustom.SetMenu(itemList, '- no custom keys -')
Steven M. Gava49745752002-02-18 01:43:11 +0000766 else:
Terry Jan Reedyae410862014-08-03 23:02:53 -0400767 self.optMenuKeysCustom.SetMenu(itemList, itemList[0])
Steven M. Gava49745752002-02-18 01:43:11 +0000768 #revert to default key set
Terry Jan Reedyae410862014-08-03 23:02:53 -0400769 self.keysAreBuiltin.set(idleConf.defaultCfg['main'].Get('Keys', 'default'))
770 self.builtinKeys.set(idleConf.defaultCfg['main'].Get('Keys', 'name'))
Steven M. Gava49745752002-02-18 01:43:11 +0000771 #user can't back out of these changes, they must be applied now
772 self.Apply()
773 self.SetKeysType()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000774
Steven M. Gava49745752002-02-18 01:43:11 +0000775 def DeleteCustomTheme(self):
Terry Jan Reedyae410862014-08-03 23:02:53 -0400776 themeName = self.customTheme.get()
777 delmsg = 'Are you sure you wish to delete the theme %r ?'
778 if not tkMessageBox.askyesno(
779 'Delete Theme', delmsg % themeName, parent=self):
Steven M. Gava49745752002-02-18 01:43:11 +0000780 return
781 #remove theme from config
782 idleConf.userCfg['highlight'].remove_section(themeName)
Benjamin Peterson6e3dbbd2009-10-09 22:15:50 +0000783 if themeName in self.changedItems['highlight']:
Steven M. Gava49745752002-02-18 01:43:11 +0000784 del(self.changedItems['highlight'][themeName])
785 #write changes
786 idleConf.userCfg['highlight'].Save()
787 #reload user theme list
Terry Jan Reedyae410862014-08-03 23:02:53 -0400788 itemList = idleConf.GetSectionList('user', 'highlight')
Steven M. Gava49745752002-02-18 01:43:11 +0000789 itemList.sort()
790 if not itemList:
791 self.radioThemeCustom.config(state=DISABLED)
Terry Jan Reedyae410862014-08-03 23:02:53 -0400792 self.optMenuThemeCustom.SetMenu(itemList, '- no custom themes -')
Steven M. Gava49745752002-02-18 01:43:11 +0000793 else:
Terry Jan Reedyae410862014-08-03 23:02:53 -0400794 self.optMenuThemeCustom.SetMenu(itemList, itemList[0])
Steven M. Gava49745752002-02-18 01:43:11 +0000795 #revert to default theme
Terry Jan Reedyae410862014-08-03 23:02:53 -0400796 self.themeIsBuiltin.set(idleConf.defaultCfg['main'].Get('Theme', 'default'))
797 self.builtinTheme.set(idleConf.defaultCfg['main'].Get('Theme', 'name'))
Steven M. Gava49745752002-02-18 01:43:11 +0000798 #user can't back out of these changes, they must be applied now
799 self.Apply()
800 self.SetThemeType()
801
Steven M. Gava5f28e8f2002-01-21 06:38:21 +0000802 def GetColour(self):
Terry Jan Reedyae410862014-08-03 23:02:53 -0400803 target = self.highlightTarget.get()
804 prevColour = self.frameColourSet.cget('bg')
805 rgbTuplet, colourString = tkColorChooser.askcolor(
806 parent=self, title='Pick new colour for : '+target,
807 initialcolor=prevColour)
808 if colourString and (colourString != prevColour):
Steven M. Gava052937f2002-02-11 02:20:53 +0000809 #user didn't cancel, and they chose a new colour
Terry Jan Reedyae410862014-08-03 23:02:53 -0400810 if self.themeIsBuiltin.get(): #current theme is a built-in
811 message = ('Your changes will be saved as a new Custom Theme. '
812 'Enter a name for your new Custom Theme below.')
813 newTheme = self.GetNewThemeName(message)
814 if not newTheme: #user cancelled custom theme creation
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000815 return
Terry Jan Reedyae410862014-08-03 23:02:53 -0400816 else: #create new custom theme based on previously active theme
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000817 self.CreateNewTheme(newTheme)
Steven M. Gava052937f2002-02-11 02:20:53 +0000818 self.colour.set(colourString)
Terry Jan Reedyae410862014-08-03 23:02:53 -0400819 else: #current theme is user defined
Steven M. Gava052937f2002-02-11 02:20:53 +0000820 self.colour.set(colourString)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000821
Steven M. Gava052937f2002-02-11 02:20:53 +0000822 def OnNewColourSet(self):
823 newColour=self.colour.get()
Terry Jan Reedyae410862014-08-03 23:02:53 -0400824 self.frameColourSet.config(bg=newColour) #set sample
825 plane ='foreground' if self.fgHilite.get() else 'background'
826 sampleElement = self.themeElements[self.highlightTarget.get()][0]
Raymond Hettinger931237e2003-07-09 18:48:24 +0000827 self.textHighlightSample.tag_config(sampleElement, **{plane:newColour})
Terry Jan Reedyae410862014-08-03 23:02:53 -0400828 theme = self.customTheme.get()
829 themeElement = sampleElement + '-' + plane
830 self.AddChangedItem('highlight', theme, themeElement, newColour)
Steven M. Gava052937f2002-02-11 02:20:53 +0000831
Terry Jan Reedyae410862014-08-03 23:02:53 -0400832 def GetNewThemeName(self, message):
833 usedNames = (idleConf.GetSectionList('user', 'highlight') +
834 idleConf.GetSectionList('default', 'highlight'))
835 newTheme = GetCfgSectionNameDialog(
836 self, 'New Custom Theme', message, usedNames).result
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000837 return newTheme
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000838
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000839 def SaveAsNewTheme(self):
Terry Jan Reedyae410862014-08-03 23:02:53 -0400840 newThemeName = self.GetNewThemeName('New Theme Name:')
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000841 if newThemeName:
842 self.CreateNewTheme(newThemeName)
843
Terry Jan Reedyae410862014-08-03 23:02:53 -0400844 def CreateNewTheme(self, newThemeName):
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000845 #creates new custom theme based on the previously active theme,
846 #and makes the new theme active
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000847 if self.themeIsBuiltin.get():
Terry Jan Reedyae410862014-08-03 23:02:53 -0400848 themeType = 'default'
849 themeName = self.builtinTheme.get()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000850 else:
Terry Jan Reedyae410862014-08-03 23:02:53 -0400851 themeType = 'user'
852 themeName = self.customTheme.get()
853 newTheme = idleConf.GetThemeDict(themeType, themeName)
Steven M. Gava052937f2002-02-11 02:20:53 +0000854 #apply any of the old theme's unsaved changes to the new theme
Terry Jan Reedy110796f2014-07-27 04:07:18 -0400855 if themeName in self.changedItems['highlight']:
Terry Jan Reedyae410862014-08-03 23:02:53 -0400856 themeChanges = self.changedItems['highlight'][themeName]
Terry Jan Reedy110796f2014-07-27 04:07:18 -0400857 for element in themeChanges:
Terry Jan Reedyae410862014-08-03 23:02:53 -0400858 newTheme[element] = themeChanges[element]
Steven M. Gava052937f2002-02-11 02:20:53 +0000859 #save the new theme
Terry Jan Reedyae410862014-08-03 23:02:53 -0400860 self.SaveNewTheme(newThemeName, newTheme)
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000861 #change gui over to the new theme
Terry Jan Reedyae410862014-08-03 23:02:53 -0400862 customThemeList = idleConf.GetSectionList('user', 'highlight')
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000863 customThemeList.sort()
Terry Jan Reedyae410862014-08-03 23:02:53 -0400864 self.optMenuThemeCustom.SetMenu(customThemeList, newThemeName)
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000865 self.themeIsBuiltin.set(0)
866 self.SetThemeType()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000867
Terry Jan Reedyae410862014-08-03 23:02:53 -0400868 def OnListFontButtonRelease(self, event):
Kurt B. Kaiser05391692003-05-26 20:35:53 +0000869 font = self.listFontName.get(ANCHOR)
870 self.fontName.set(font.lower())
Steven M. Gava5f28e8f2002-01-21 06:38:21 +0000871 self.SetFontSample()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000872
Terry Jan Reedyae410862014-08-03 23:02:53 -0400873 def SetFontSample(self, event=None):
874 fontName = self.fontName.get()
875 fontWeight = tkFont.BOLD if self.fontBold.get() else tkFont.NORMAL
Ned Deilye3d47122012-10-22 15:13:01 -0700876 newFont = (fontName, self.fontSize.get(), fontWeight)
877 self.labelFontSample.config(font=newFont)
878 self.textHighlightSample.configure(font=newFont)
Steven M. Gava5f28e8f2002-01-21 06:38:21 +0000879
Steven M. Gava5f28e8f2002-01-21 06:38:21 +0000880 def SetHighlightTarget(self):
Terry Jan Reedyae410862014-08-03 23:02:53 -0400881 if self.highlightTarget.get() == 'Cursor': #bg not possible
Steven M. Gava5f28e8f2002-01-21 06:38:21 +0000882 self.radioFg.config(state=DISABLED)
883 self.radioBg.config(state=DISABLED)
884 self.fgHilite.set(1)
Terry Jan Reedyae410862014-08-03 23:02:53 -0400885 else: #both fg and bg can be set
Steven M. Gava5f28e8f2002-01-21 06:38:21 +0000886 self.radioFg.config(state=NORMAL)
887 self.radioBg.config(state=NORMAL)
888 self.fgHilite.set(1)
889 self.SetColourSample()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000890
Terry Jan Reedyae410862014-08-03 23:02:53 -0400891 def SetColourSampleBinding(self, *args):
Steven M. Gava5f28e8f2002-01-21 06:38:21 +0000892 self.SetColourSample()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000893
Steven M. Gava5f28e8f2002-01-21 06:38:21 +0000894 def SetColourSample(self):
895 #set the colour smaple area
Terry Jan Reedyae410862014-08-03 23:02:53 -0400896 tag = self.themeElements[self.highlightTarget.get()][0]
897 plane = 'foreground' if self.fgHilite.get() else 'background'
898 colour = self.textHighlightSample.tag_cget(tag, plane)
Steven M. Gava5f28e8f2002-01-21 06:38:21 +0000899 self.frameColourSet.config(bg=colour)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000900
Steven M. Gava9dd16b32001-11-03 14:54:25 +0000901 def PaintThemeSample(self):
Terry Jan Reedyae410862014-08-03 23:02:53 -0400902 if self.themeIsBuiltin.get(): #a default theme
903 theme = self.builtinTheme.get()
904 else: #a user theme
905 theme = self.customTheme.get()
Terry Jan Reedy110796f2014-07-27 04:07:18 -0400906 for elementTitle in self.themeElements:
Terry Jan Reedyae410862014-08-03 23:02:53 -0400907 element = self.themeElements[elementTitle][0]
908 colours = idleConf.GetHighlight(theme, element)
909 if element == 'cursor': #cursor sample needs special painting
910 colours['background'] = idleConf.GetHighlight(
911 theme, 'normal', fgBg='bg')
Steven M. Gava052937f2002-02-11 02:20:53 +0000912 #handle any unsaved changes to this theme
Terry Jan Reedy110796f2014-07-27 04:07:18 -0400913 if theme in self.changedItems['highlight']:
Terry Jan Reedyae410862014-08-03 23:02:53 -0400914 themeDict = self.changedItems['highlight'][theme]
915 if element + '-foreground' in themeDict:
916 colours['foreground'] = themeDict[element + '-foreground']
917 if element + '-background' in themeDict:
918 colours['background'] = themeDict[element + '-background']
Raymond Hettinger931237e2003-07-09 18:48:24 +0000919 self.textHighlightSample.tag_config(element, **colours)
Steven M. Gava052937f2002-02-11 02:20:53 +0000920 self.SetColourSample()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000921
Terry Jan Reedyae410862014-08-03 23:02:53 -0400922 def HelpSourceSelected(self, event):
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000923 self.SetHelpListButtonStates()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000924
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000925 def SetHelpListButtonStates(self):
Terry Jan Reedyae410862014-08-03 23:02:53 -0400926 if self.listHelp.size() < 1: #no entries in list
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000927 self.buttonHelpListEdit.config(state=DISABLED)
928 self.buttonHelpListRemove.config(state=DISABLED)
929 else: #there are some entries
Terry Jan Reedyae410862014-08-03 23:02:53 -0400930 if self.listHelp.curselection(): #there currently is a selection
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000931 self.buttonHelpListEdit.config(state=NORMAL)
932 self.buttonHelpListRemove.config(state=NORMAL)
933 else: #there currently is not a selection
934 self.buttonHelpListEdit.config(state=DISABLED)
935 self.buttonHelpListRemove.config(state=DISABLED)
936
937 def HelpListItemAdd(self):
Terry Jan Reedyae410862014-08-03 23:02:53 -0400938 helpSource = GetHelpSourceDialog(self, 'New Help Source').result
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000939 if helpSource:
Terry Jan Reedyae410862014-08-03 23:02:53 -0400940 self.userHelpList.append((helpSource[0], helpSource[1]))
941 self.listHelp.insert(END, helpSource[0])
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000942 self.UpdateUserHelpChangedItems()
943 self.SetHelpListButtonStates()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000944
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000945 def HelpListItemEdit(self):
Terry Jan Reedyae410862014-08-03 23:02:53 -0400946 itemIndex = self.listHelp.index(ANCHOR)
947 helpSource = self.userHelpList[itemIndex]
948 newHelpSource = GetHelpSourceDialog(
949 self, 'Edit Help Source', menuItem=helpSource[0],
950 filePath=helpSource[1]).result
951 if (not newHelpSource) or (newHelpSource == helpSource):
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000952 return #no changes
Terry Jan Reedyae410862014-08-03 23:02:53 -0400953 self.userHelpList[itemIndex] = newHelpSource
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000954 self.listHelp.delete(itemIndex)
Terry Jan Reedyae410862014-08-03 23:02:53 -0400955 self.listHelp.insert(itemIndex, newHelpSource[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 HelpListItemRemove(self):
Terry Jan Reedyae410862014-08-03 23:02:53 -0400960 itemIndex = self.listHelp.index(ANCHOR)
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000961 del(self.userHelpList[itemIndex])
962 self.listHelp.delete(itemIndex)
963 self.UpdateUserHelpChangedItems()
964 self.SetHelpListButtonStates()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000965
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000966 def UpdateUserHelpChangedItems(self):
Kurt B. Kaiser8e92bf72003-01-14 22:03:31 +0000967 "Clear and rebuild the HelpFiles section in self.changedItems"
968 self.changedItems['main']['HelpFiles'] = {}
Terry Jan Reedyae410862014-08-03 23:02:53 -0400969 for num in range(1, len(self.userHelpList) + 1):
970 self.AddChangedItem(
971 'main', 'HelpFiles', str(num),
Terry Jan Reedy110796f2014-07-27 04:07:18 -0400972 ';'.join(self.userHelpList[num-1][:2]))
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000973
Steven M. Gava429a86a2001-10-23 10:42:12 +0000974 def LoadFontCfg(self):
975 ##base editor font selection list
Terry Jan Reedyae410862014-08-03 23:02:53 -0400976 fonts = list(tkFont.families(self))
Steven M. Gavac11ccf32001-09-24 09:43:17 +0000977 fonts.sort()
978 for font in fonts:
Terry Jan Reedyae410862014-08-03 23:02:53 -0400979 self.listFontName.insert(END, font)
Terry Jan Reedy12352142015-08-01 18:57:27 -0400980 configuredFont = idleConf.GetFont(self, 'main', 'EditorWindow')
981 fontName = configuredFont[0].lower()
982 fontSize = configuredFont[1]
983 fontBold = configuredFont[2]=='bold'
984 self.fontName.set(fontName)
Kurt B. Kaiser05391692003-05-26 20:35:53 +0000985 lc_fonts = [s.lower() for s in fonts]
Terry Jan Reedy12352142015-08-01 18:57:27 -0400986 try:
987 currentFontIndex = lc_fonts.index(fontName)
Steven M. Gava429a86a2001-10-23 10:42:12 +0000988 self.listFontName.see(currentFontIndex)
989 self.listFontName.select_set(currentFontIndex)
Steven M. Gavac112cd82002-01-22 05:56:40 +0000990 self.listFontName.select_anchor(currentFontIndex)
Terry Jan Reedy12352142015-08-01 18:57:27 -0400991 except ValueError:
992 pass
Steven M. Gava429a86a2001-10-23 10:42:12 +0000993 ##font size dropdown
Terry Jan Reedyae410862014-08-03 23:02:53 -0400994 self.optMenuFontSize.SetMenu(('7', '8', '9', '10', '11', '12', '13',
995 '14', '16', '18', '20', '22'), fontSize )
Steven M. Gavac112cd82002-01-22 05:56:40 +0000996 ##fontWeight
Terry Jan Reedy12352142015-08-01 18:57:27 -0400997 self.fontBold.set(fontBold)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000998 ##font sample
Steven M. Gava429a86a2001-10-23 10:42:12 +0000999 self.SetFontSample()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001000
Steven M. Gava429a86a2001-10-23 10:42:12 +00001001 def LoadTabCfg(self):
Steven M. Gava429a86a2001-10-23 10:42:12 +00001002 ##indent sizes
Terry Jan Reedyae410862014-08-03 23:02:53 -04001003 spaceNum = idleConf.GetOption(
1004 'main', 'Indent', 'num-spaces', default=4, type='int')
Steven M. Gava429a86a2001-10-23 10:42:12 +00001005 self.spaceNum.set(spaceNum)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001006
Steven M. Gava9dd16b32001-11-03 14:54:25 +00001007 def LoadThemeCfg(self):
Steven M. Gava41a85322001-10-29 08:05:34 +00001008 ##current theme type radiobutton
Terry Jan Reedyae410862014-08-03 23:02:53 -04001009 self.themeIsBuiltin.set(idleConf.GetOption(
1010 'main', 'Theme', 'default', type='bool', default=1))
Steven M. Gava41a85322001-10-29 08:05:34 +00001011 ##currently set theme
Terry Jan Reedyae410862014-08-03 23:02:53 -04001012 currentOption = idleConf.CurrentTheme()
Steven M. Gava7c017862001-10-29 11:19:46 +00001013 ##load available theme option menus
Steven M. Gavad0342cd2001-11-04 11:53:10 +00001014 if self.themeIsBuiltin.get(): #default theme selected
Terry Jan Reedyae410862014-08-03 23:02:53 -04001015 itemList = idleConf.GetSectionList('default', 'highlight')
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +00001016 itemList.sort()
Terry Jan Reedyae410862014-08-03 23:02:53 -04001017 self.optMenuThemeBuiltin.SetMenu(itemList, currentOption)
1018 itemList = idleConf.GetSectionList('user', 'highlight')
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +00001019 itemList.sort()
Steven M. Gava41a85322001-10-29 08:05:34 +00001020 if not itemList:
1021 self.radioThemeCustom.config(state=DISABLED)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001022 self.customTheme.set('- no custom themes -')
Steven M. Gava41a85322001-10-29 08:05:34 +00001023 else:
Terry Jan Reedyae410862014-08-03 23:02:53 -04001024 self.optMenuThemeCustom.SetMenu(itemList, itemList[0])
Steven M. Gava9dd16b32001-11-03 14:54:25 +00001025 else: #user theme selected
Terry Jan Reedyae410862014-08-03 23:02:53 -04001026 itemList = idleConf.GetSectionList('user', 'highlight')
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +00001027 itemList.sort()
Terry Jan Reedyae410862014-08-03 23:02:53 -04001028 self.optMenuThemeCustom.SetMenu(itemList, currentOption)
1029 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, itemList[0])
Steven M. Gava7c017862001-10-29 11:19:46 +00001032 self.SetThemeType()
1033 ##load theme element option menu
Terry Jan Reedyae410862014-08-03 23:02:53 -04001034 themeNames = self.themeElements.keys()
Florent Xiclunaa7f242f2010-04-02 08:15:26 +00001035 themeNames.sort(key=lambda x: self.themeElements[x][1])
Terry Jan Reedyae410862014-08-03 23:02:53 -04001036 self.optMenuHighlightTarget.SetMenu(themeNames, themeNames[0])
Steven M. Gava9dd16b32001-11-03 14:54:25 +00001037 self.PaintThemeSample()
Steven M. Gava0cae01c2002-01-04 07:53:06 +00001038 self.SetHighlightTarget()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001039
Steven M. Gava9dd16b32001-11-03 14:54:25 +00001040 def LoadKeyCfg(self):
Steven M. Gava41a85322001-10-29 08:05:34 +00001041 ##current keys type radiobutton
Terry Jan Reedyae410862014-08-03 23:02:53 -04001042 self.keysAreBuiltin.set(idleConf.GetOption(
1043 'main', 'Keys', 'default', type='bool', default=1))
Steven M. Gava41a85322001-10-29 08:05:34 +00001044 ##currently set keys
Terry Jan Reedyae410862014-08-03 23:02:53 -04001045 currentOption = idleConf.CurrentKeys()
Steven M. Gava7c017862001-10-29 11:19:46 +00001046 ##load available keyset option menus
Steven M. Gava052937f2002-02-11 02:20:53 +00001047 if self.keysAreBuiltin.get(): #default theme selected
Terry Jan Reedyae410862014-08-03 23:02:53 -04001048 itemList = idleConf.GetSectionList('default', 'keys')
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +00001049 itemList.sort()
Terry Jan Reedyae410862014-08-03 23:02:53 -04001050 self.optMenuKeysBuiltin.SetMenu(itemList, currentOption)
1051 itemList = idleConf.GetSectionList('user', 'keys')
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +00001052 itemList.sort()
Steven M. Gava41a85322001-10-29 08:05:34 +00001053 if not itemList:
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001054 self.radioKeysCustom.config(state=DISABLED)
1055 self.customKeys.set('- no custom keys -')
Steven M. Gava41a85322001-10-29 08:05:34 +00001056 else:
Terry Jan Reedyae410862014-08-03 23:02:53 -04001057 self.optMenuKeysCustom.SetMenu(itemList, itemList[0])
Steven M. Gavaa498af22002-02-01 01:33:36 +00001058 else: #user key set selected
Terry Jan Reedyae410862014-08-03 23:02:53 -04001059 itemList = idleConf.GetSectionList('user', 'keys')
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +00001060 itemList.sort()
Terry Jan Reedyae410862014-08-03 23:02:53 -04001061 self.optMenuKeysCustom.SetMenu(itemList, currentOption)
1062 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, itemList[0])
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001065 self.SetKeysType()
Steven M. Gavafacfc092002-01-19 00:29:54 +00001066 ##load keyset element list
Terry Jan Reedyae410862014-08-03 23:02:53 -04001067 keySetName = idleConf.CurrentKeys()
Steven M. Gava052937f2002-02-11 02:20:53 +00001068 self.LoadKeysList(keySetName)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001069
Steven M. Gavafacfc092002-01-19 00:29:54 +00001070 def LoadGeneralCfg(self):
Steven M. Gava5f28e8f2002-01-21 06:38:21 +00001071 #startup state
Terry Jan Reedyae410862014-08-03 23:02:53 -04001072 self.startupEdit.set(idleConf.GetOption(
1073 'main', 'General', 'editor-on-startup', default=1, type='bool'))
Kurt B. Kaiser6c638b62003-05-26 06:23:10 +00001074 #autosave state
Terry Jan Reedyae410862014-08-03 23:02:53 -04001075 self.autoSave.set(idleConf.GetOption(
1076 'main', 'General', 'autosave', default=0, type='bool'))
Steven M. Gavafacfc092002-01-19 00:29:54 +00001077 #initial window size
Terry Jan Reedyae410862014-08-03 23:02:53 -04001078 self.winWidth.set(idleConf.GetOption(
1079 'main', 'EditorWindow', 'width', type='int'))
1080 self.winHeight.set(idleConf.GetOption(
1081 'main', 'EditorWindow', 'height', type='int'))
Kurt B. Kaisera053f332003-05-10 00:49:56 +00001082 # default source encoding
Terry Jan Reedyae410862014-08-03 23:02:53 -04001083 self.encoding.set(idleConf.GetOption(
1084 'main', 'EditorWindow', 'encoding', default='none'))
Kurt B. Kaiser8e92bf72003-01-14 22:03:31 +00001085 # additional help sources
1086 self.userHelpList = idleConf.GetAllExtraHelpSourcesList()
Steven M. Gava085eb1b2002-02-05 04:52:32 +00001087 for helpItem in self.userHelpList:
Terry Jan Reedyae410862014-08-03 23:02:53 -04001088 self.listHelp.insert(END, helpItem[0])
Steven M. Gava085eb1b2002-02-05 04:52:32 +00001089 self.SetHelpListButtonStates()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001090
Steven M. Gava429a86a2001-10-23 10:42:12 +00001091 def LoadConfigs(self):
1092 """
1093 load configuration from default and user config files and populate
1094 the widgets on the config dialog pages.
1095 """
1096 ### fonts / tabs page
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001097 self.LoadFontCfg()
1098 self.LoadTabCfg()
Steven M. Gava429a86a2001-10-23 10:42:12 +00001099 ### highlighting page
Steven M. Gava9dd16b32001-11-03 14:54:25 +00001100 self.LoadThemeCfg()
Steven M. Gava429a86a2001-10-23 10:42:12 +00001101 ### keys page
Steven M. Gava9dd16b32001-11-03 14:54:25 +00001102 self.LoadKeyCfg()
Steven M. Gava429a86a2001-10-23 10:42:12 +00001103 ### general page
Steven M. Gavafacfc092002-01-19 00:29:54 +00001104 self.LoadGeneralCfg()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001105
Terry Jan Reedyae410862014-08-03 23:02:53 -04001106 def SaveNewKeySet(self, keySetName, keySet):
Steven M. Gava052937f2002-02-11 02:20:53 +00001107 """
1108 save a newly created core key set.
1109 keySetName - string, the name of the new key set
1110 keySet - dictionary containing the new key set
1111 """
1112 if not idleConf.userCfg['keys'].has_section(keySetName):
1113 idleConf.userCfg['keys'].add_section(keySetName)
Terry Jan Reedy110796f2014-07-27 04:07:18 -04001114 for event in keySet:
Terry Jan Reedyae410862014-08-03 23:02:53 -04001115 value = keySet[event]
1116 idleConf.userCfg['keys'].SetOption(keySetName, event, value)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001117
Terry Jan Reedyae410862014-08-03 23:02:53 -04001118 def SaveNewTheme(self, themeName, theme):
Steven M. Gava052937f2002-02-11 02:20:53 +00001119 """
1120 save a newly created theme.
1121 themeName - string, the name of the new theme
1122 theme - dictionary containing the new theme
1123 """
1124 if not idleConf.userCfg['highlight'].has_section(themeName):
1125 idleConf.userCfg['highlight'].add_section(themeName)
Terry Jan Reedy110796f2014-07-27 04:07:18 -04001126 for element in theme:
Terry Jan Reedyae410862014-08-03 23:02:53 -04001127 value = theme[element]
1128 idleConf.userCfg['highlight'].SetOption(themeName, element, value)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001129
Terry Jan Reedyae410862014-08-03 23:02:53 -04001130 def SetUserValue(self, configType, section, item, value):
1131 if idleConf.defaultCfg[configType].has_option(section, item):
1132 if idleConf.defaultCfg[configType].Get(section, item) == value:
Steven M. Gava2d7bb3f2002-01-29 08:35:29 +00001133 #the setting equals a default setting, remove it from user cfg
Terry Jan Reedyae410862014-08-03 23:02:53 -04001134 return idleConf.userCfg[configType].RemoveOption(section, item)
Steven M. Gava2d7bb3f2002-01-29 08:35:29 +00001135 #if we got here set the option
Terry Jan Reedyae410862014-08-03 23:02:53 -04001136 return idleConf.userCfg[configType].SetOption(section, item, value)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001137
Steven M. Gava052937f2002-02-11 02:20:53 +00001138 def SaveAllChangedConfigs(self):
Kurt B. Kaisere7a161e2003-01-10 20:13:57 +00001139 "Save configuration changes to the user config file."
Steven M. Gava0c5bc8c2002-03-27 02:25:44 +00001140 idleConf.userCfg['main'].Save()
Terry Jan Reedy110796f2014-07-27 04:07:18 -04001141 for configType in self.changedItems:
Kurt B. Kaisere7a161e2003-01-10 20:13:57 +00001142 cfgTypeHasChanges = False
Terry Jan Reedy110796f2014-07-27 04:07:18 -04001143 for section in self.changedItems[configType]:
Kurt B. Kaisere7a161e2003-01-10 20:13:57 +00001144 if section == 'HelpFiles':
1145 #this section gets completely replaced
1146 idleConf.userCfg['main'].remove_section('HelpFiles')
Kurt B. Kaiser8e92bf72003-01-14 22:03:31 +00001147 cfgTypeHasChanges = True
Terry Jan Reedy110796f2014-07-27 04:07:18 -04001148 for item in self.changedItems[configType][section]:
Kurt B. Kaisere7a161e2003-01-10 20:13:57 +00001149 value = self.changedItems[configType][section][item]
Terry Jan Reedyae410862014-08-03 23:02:53 -04001150 if self.SetUserValue(configType, section, item, value):
Kurt B. Kaisere7a161e2003-01-10 20:13:57 +00001151 cfgTypeHasChanges = True
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001152 if cfgTypeHasChanges:
1153 idleConf.userCfg[configType].Save()
Kurt B. Kaiser5acdf932004-11-16 21:28:36 +00001154 for configType in ['keys', 'highlight']:
1155 # save these even if unchanged!
1156 idleConf.userCfg[configType].Save()
Steven M. Gavaa498af22002-02-01 01:33:36 +00001157 self.ResetChangedItems() #clear the changed items dict
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001158
Kurt B. Kaiserb1754452005-11-18 22:05:48 +00001159 def DeactivateCurrentConfig(self):
1160 #Before a config is saved, some cleanup of current
1161 #config must be done - remove the previous keybindings
Terry Jan Reedyae410862014-08-03 23:02:53 -04001162 winInstances = self.parent.instance_dict
Kurt B. Kaiserb1754452005-11-18 22:05:48 +00001163 for instance in winInstances:
1164 instance.RemoveKeybindings()
1165
Steven M. Gava49745752002-02-18 01:43:11 +00001166 def ActivateConfigChanges(self):
Kurt B. Kaiseracdef852005-01-31 03:34:26 +00001167 "Dynamically apply configuration changes"
Terry Jan Reedy110796f2014-07-27 04:07:18 -04001168 winInstances = self.parent.instance_dict.keys()
Steven M. Gavab77d3432002-03-02 07:16:21 +00001169 for instance in winInstances:
1170 instance.ResetColorizer()
Steven M. Gavab1585412002-03-12 00:21:56 +00001171 instance.ResetFont()
Kurt B. Kaiseracdef852005-01-31 03:34:26 +00001172 instance.set_notabs_indentwidth()
Kurt B. Kaiserb1754452005-11-18 22:05:48 +00001173 instance.ApplyKeybindings()
Kurt B. Kaiser8e92bf72003-01-14 22:03:31 +00001174 instance.reset_help_menu_entries()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001175
Steven M. Gava5f28e8f2002-01-21 06:38:21 +00001176 def Cancel(self):
1177 self.destroy()
1178
1179 def Ok(self):
1180 self.Apply()
1181 self.destroy()
1182
1183 def Apply(self):
Kurt B. Kaiserb1754452005-11-18 22:05:48 +00001184 self.DeactivateCurrentConfig()
Steven M. Gava052937f2002-02-11 02:20:53 +00001185 self.SaveAllChangedConfigs()
Steven M. Gava49745752002-02-18 01:43:11 +00001186 self.ActivateConfigChanges()
Steven M. Gava5f28e8f2002-01-21 06:38:21 +00001187
1188 def Help(self):
Steven M. Gavac11ccf32001-09-24 09:43:17 +00001189 pass
1190
Terry Jan Reedy7a162072014-10-22 20:15:12 -04001191class VerticalScrolledFrame(Frame):
1192 """A pure Tkinter vertically scrollable frame.
1193
1194 * Use the 'interior' attribute to place widgets inside the scrollable frame
1195 * Construct and pack/place/grid normally
1196 * This frame only allows vertical scrolling
1197 """
1198 def __init__(self, parent, *args, **kw):
1199 Frame.__init__(self, parent, *args, **kw)
1200
1201 # create a canvas object and a vertical scrollbar for scrolling it
1202 vscrollbar = Scrollbar(self, orient=VERTICAL)
1203 vscrollbar.pack(fill=Y, side=RIGHT, expand=FALSE)
1204 canvas = Canvas(self, bd=0, highlightthickness=0,
1205 yscrollcommand=vscrollbar.set)
1206 canvas.pack(side=LEFT, fill=BOTH, expand=TRUE)
1207 vscrollbar.config(command=canvas.yview)
1208
1209 # reset the view
1210 canvas.xview_moveto(0)
1211 canvas.yview_moveto(0)
1212
1213 # create a frame inside the canvas which will be scrolled with it
1214 self.interior = interior = Frame(canvas)
1215 interior_id = canvas.create_window(0, 0, window=interior, anchor=NW)
1216
1217 # track changes to the canvas and frame width and sync them,
1218 # also updating the scrollbar
1219 def _configure_interior(event):
1220 # update the scrollbars to match the size of the inner frame
1221 size = (interior.winfo_reqwidth(), interior.winfo_reqheight())
1222 canvas.config(scrollregion="0 0 %s %s" % size)
Terry Jan Reedy7a162072014-10-22 20:15:12 -04001223 interior.bind('<Configure>', _configure_interior)
1224
1225 def _configure_canvas(event):
1226 if interior.winfo_reqwidth() != canvas.winfo_width():
1227 # update the inner frame's width to fill the canvas
1228 canvas.itemconfigure(interior_id, width=canvas.winfo_width())
1229 canvas.bind('<Configure>', _configure_canvas)
1230
1231 return
1232
1233def is_int(s):
1234 "Return 's is blank or represents an int'"
1235 if not s:
1236 return True
1237 try:
1238 int(s)
1239 return True
1240 except ValueError:
1241 return False
1242
1243# TODO:
1244# * Revert to default(s)? Per option or per extension?
1245# * List options in their original order (possible??)
1246class ConfigExtensionsDialog(Toplevel):
1247 """A dialog for configuring IDLE extensions.
1248
1249 This dialog is generic - it works for any and all IDLE extensions.
1250
1251 IDLE extensions save their configuration options using idleConf.
1252 ConfigExtensionsDialog reads the current configuration using idleConf,
1253 supplies a GUI interface to change the configuration values, and saves the
1254 changes using idleConf.
1255
1256 Not all changes take effect immediately - some may require restarting IDLE.
1257 This depends on each extension's implementation.
1258
1259 All values are treated as text, and it is up to the user to supply
1260 reasonable values. The only exception to this are the 'enable*' options,
1261 which are boolean, and can be toggled with an True/False button.
1262 """
1263 def __init__(self, parent, title=None, _htest=False):
1264 Toplevel.__init__(self, parent)
1265 self.wm_withdraw()
1266
1267 self.configure(borderwidth=5)
1268 self.geometry(
1269 "+%d+%d" % (parent.winfo_rootx() + 20,
1270 parent.winfo_rooty() + (30 if not _htest else 150)))
1271 self.wm_title(title or 'IDLE Extensions Configuration')
1272
1273 self.defaultCfg = idleConf.defaultCfg['extensions']
1274 self.userCfg = idleConf.userCfg['extensions']
1275 self.is_int = self.register(is_int)
1276 self.load_extensions()
1277 self.create_widgets()
1278
1279 self.resizable(height=FALSE, width=FALSE) # don't allow resizing yet
1280 self.transient(parent)
1281 self.protocol("WM_DELETE_WINDOW", self.Cancel)
1282 self.tabbed_page_set.focus_set()
1283 # wait for window to be generated
1284 self.update()
1285 # set current width as the minimum width
1286 self.wm_minsize(self.winfo_width(), 1)
1287 # now allow resizing
1288 self.resizable(height=TRUE, width=TRUE)
1289
1290 self.wm_deiconify()
1291 if not _htest:
1292 self.grab_set()
1293 self.wait_window()
1294
1295 def load_extensions(self):
1296 "Fill self.extensions with data from the default and user configs."
1297 self.extensions = {}
1298 for ext_name in idleConf.GetExtensions(active_only=False):
1299 self.extensions[ext_name] = []
1300
1301 for ext_name in self.extensions:
1302 opt_list = sorted(self.defaultCfg.GetOptionList(ext_name))
1303
1304 # bring 'enable' options to the beginning of the list
1305 enables = [opt_name for opt_name in opt_list
1306 if opt_name.startswith('enable')]
1307 for opt_name in enables:
1308 opt_list.remove(opt_name)
1309 opt_list = enables + opt_list
1310
1311 for opt_name in opt_list:
1312 def_str = self.defaultCfg.Get(
1313 ext_name, opt_name, raw=True)
1314 try:
1315 def_obj = {'True':True, 'False':False}[def_str]
1316 opt_type = 'bool'
1317 except KeyError:
1318 try:
1319 def_obj = int(def_str)
1320 opt_type = 'int'
1321 except ValueError:
1322 def_obj = def_str
1323 opt_type = None
1324 try:
1325 value = self.userCfg.Get(
1326 ext_name, opt_name, type=opt_type, raw=True,
1327 default=def_obj)
1328 except ValueError: # Need this until .Get fixed
1329 value = def_obj # bad values overwritten by entry
1330 var = StringVar(self)
1331 var.set(str(value))
1332
1333 self.extensions[ext_name].append({'name': opt_name,
1334 'type': opt_type,
1335 'default': def_str,
1336 'value': value,
1337 'var': var,
1338 })
1339
1340 def create_widgets(self):
1341 """Create the dialog's widgets."""
Terry Jan Reedy936a6f12015-08-26 23:13:16 -04001342 self.extension_names = StringVar(self)
Terry Jan Reedy7a162072014-10-22 20:15:12 -04001343 self.rowconfigure(0, weight=1)
Terry Jan Reedy936a6f12015-08-26 23:13:16 -04001344 self.columnconfigure(2, weight=1)
1345 self.extension_list = Listbox(self, listvariable=self.extension_names,
1346 selectmode='browse')
1347 self.extension_list.bind('<<ListboxSelect>>', self.extension_selected)
1348 scroll = Scrollbar(self, command=self.extension_list.yview)
1349 self.extension_list.yscrollcommand=scroll.set
1350 self.details_frame = LabelFrame(self, width=250, height=250)
1351 self.extension_list.grid(column=0, row=0, sticky='nws')
1352 scroll.grid(column=1, row=0, sticky='ns')
1353 self.details_frame.grid(column=2, row=0, sticky='nsew', padx=[10, 0])
1354 self.configure(padx=10, pady=10)
1355 self.config_frame = {}
1356 self.current_extension = None
Terry Jan Reedy7a162072014-10-22 20:15:12 -04001357
Terry Jan Reedy936a6f12015-08-26 23:13:16 -04001358 self.outerframe = self # TEMPORARY
1359 self.tabbed_page_set = self.extension_list # TEMPORARY
Terry Jan Reedy7a162072014-10-22 20:15:12 -04001360
Terry Jan Reedy936a6f12015-08-26 23:13:16 -04001361 # create the individual pages
1362 ext_names = ''
1363 for ext_name in sorted(self.extensions):
1364 self.create_extension_frame(ext_name)
1365 ext_names = ext_names + '{' + ext_name + '} '
1366 self.extension_names.set(ext_names)
1367 self.extension_list.selection_set(0)
1368 self.extension_selected(None)
1369 self.create_action_buttons().grid(row=1, columnspan=3)
1370
1371 def extension_selected(self, event):
1372 newsel = self.extension_list.curselection()
1373 if newsel:
1374 newsel = self.extension_list.get(newsel)
1375 if newsel is None or newsel != self.current_extension:
1376 if self.current_extension:
1377 self.details_frame.config(text='')
1378 self.config_frame[self.current_extension].grid_forget()
1379 self.current_extension = None
1380 if newsel:
1381 self.details_frame.config(text=newsel)
1382 self.config_frame[newsel].grid(column=0, row=0, sticky='nsew')
1383 self.current_extension = newsel
Terry Jan Reedy7a162072014-10-22 20:15:12 -04001384
1385 create_action_buttons = ConfigDialog.create_action_buttons.im_func
1386
Terry Jan Reedy936a6f12015-08-26 23:13:16 -04001387 def create_extension_frame(self, ext_name):
1388 """Create a frame holding the widgets to configure one extension"""
1389 f = VerticalScrolledFrame(self.details_frame, height=250, width=250)
1390 self.config_frame[ext_name] = f
1391 entry_area = f.interior
Terry Jan Reedy7a162072014-10-22 20:15:12 -04001392 # create an entry for each configuration option
1393 for row, opt in enumerate(self.extensions[ext_name]):
1394 # create a row with a label and entry/checkbutton
1395 label = Label(entry_area, text=opt['name'])
1396 label.grid(row=row, column=0, sticky=NW)
1397 var = opt['var']
1398 if opt['type'] == 'bool':
1399 Checkbutton(entry_area, textvariable=var, variable=var,
1400 onvalue='True', offvalue='False',
1401 indicatoron=FALSE, selectcolor='', width=8
Terry Jan Reedy936a6f12015-08-26 23:13:16 -04001402 ).grid(row=row, column=1, sticky=W, padx=7)
Terry Jan Reedy7a162072014-10-22 20:15:12 -04001403 elif opt['type'] == 'int':
1404 Entry(entry_area, textvariable=var, validate='key',
Terry Jan Reedy936a6f12015-08-26 23:13:16 -04001405 validatecommand=(self.is_int, '%P')
1406 ).grid(row=row, column=1, sticky=NSEW, padx=7)
Terry Jan Reedy7a162072014-10-22 20:15:12 -04001407
1408 else:
1409 Entry(entry_area, textvariable=var
Terry Jan Reedy936a6f12015-08-26 23:13:16 -04001410 ).grid(row=row, column=1, sticky=NSEW, padx=7)
Terry Jan Reedy7a162072014-10-22 20:15:12 -04001411 return
1412
1413
1414 Ok = ConfigDialog.Ok.im_func
1415
1416 def Apply(self):
1417 self.save_all_changed_configs()
1418 pass
1419
1420 Cancel = ConfigDialog.Cancel.im_func
1421
1422 def Help(self):
1423 pass
1424
1425 def set_user_value(self, section, opt):
1426 name = opt['name']
1427 default = opt['default']
1428 value = opt['var'].get().strip() or default
1429 opt['var'].set(value)
1430 # if self.defaultCfg.has_section(section):
1431 # Currently, always true; if not, indent to return
1432 if (value == default):
1433 return self.userCfg.RemoveOption(section, name)
1434 # set the option
1435 return self.userCfg.SetOption(section, name, value)
1436
1437 def save_all_changed_configs(self):
1438 """Save configuration changes to the user config file."""
1439 has_changes = False
1440 for ext_name in self.extensions:
1441 options = self.extensions[ext_name]
1442 for opt in options:
1443 if self.set_user_value(ext_name, opt):
1444 has_changes = True
1445 if has_changes:
1446 self.userCfg.Save()
1447
1448
Steven M. Gava44d3d1a2001-07-31 06:59:02 +00001449if __name__ == '__main__':
Terry Jan Reedyaf0dce92014-07-14 23:07:21 -04001450 import unittest
1451 unittest.main('idlelib.idle_test.test_configdialog',
1452 verbosity=2, exit=False)
Terry Jan Reedy76916e82014-05-29 01:46:16 -04001453 from idlelib.idle_test.htest import run
Terry Jan Reedy7a162072014-10-22 20:15:12 -04001454 run(ConfigDialog, ConfigExtensionsDialog)