blob: 2187268fd4a6d11b226bf05b440cee768e6fdc4e [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)
374 self.paraWidth = StringVar(parent)
375 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)
390 frameParaSize = Frame(frame, borderwidth=2, relief=GROOVE)
391 frameEncoding = Frame(frame, borderwidth=2, relief=GROOVE)
392 frameHelp = LabelFrame(frame, borderwidth=2, relief=GROOVE,
393 text=' Additional Help Sources ')
Steven M. Gava230e5782001-08-07 03:28:25 +0000394 #frameRun
Terry Jan Reedyae410862014-08-03 23:02:53 -0400395 labelRunChoiceTitle = Label(frameRun, text='At Startup')
396 radioStartupEdit = Radiobutton(
397 frameRun, variable=self.startupEdit, value=1,
398 command=self.SetKeysType, text="Open Edit Window")
399 radioStartupShell = Radiobutton(
400 frameRun, variable=self.startupEdit, value=0,
401 command=self.SetKeysType, text='Open Shell Window')
Kurt B. Kaiser6c638b62003-05-26 06:23:10 +0000402 #frameSave
Terry Jan Reedyae410862014-08-03 23:02:53 -0400403 labelRunSaveTitle = Label(frameSave, text='At Start of Run (F5) ')
404 radioSaveAsk = Radiobutton(
405 frameSave, variable=self.autoSave, value=0,
406 command=self.SetKeysType, text="Prompt to Save")
407 radioSaveAuto = Radiobutton(
408 frameSave, variable=self.autoSave, value=1,
409 command=self.SetKeysType, text='No Prompt')
Steven M. Gava230e5782001-08-07 03:28:25 +0000410 #frameWinSize
Terry Jan Reedyae410862014-08-03 23:02:53 -0400411 labelWinSizeTitle = Label(
412 frameWinSize, text='Initial Window Size (in characters)')
413 labelWinWidthTitle = Label(frameWinSize, text='Width')
414 entryWinWidth = Entry(
415 frameWinSize, textvariable=self.winWidth, width=3)
416 labelWinHeightTitle = Label(frameWinSize, text='Height')
417 entryWinHeight = Entry(
418 frameWinSize, textvariable=self.winHeight, width=3)
Raymond Hettinger4e49b832004-06-04 06:31:08 +0000419 #paragraphFormatWidth
Terry Jan Reedyae410862014-08-03 23:02:53 -0400420 labelParaWidthTitle = Label(
421 frameParaSize, text='Paragraph reformat width (in characters)')
422 entryParaWidth = Entry(
423 frameParaSize, textvariable=self.paraWidth, width=3)
Kurt B. Kaisera053f332003-05-10 00:49:56 +0000424 #frameEncoding
Terry Jan Reedyae410862014-08-03 23:02:53 -0400425 labelEncodingTitle = Label(
426 frameEncoding, text="Default Source Encoding")
427 radioEncLocale = Radiobutton(
428 frameEncoding, variable=self.encoding,
429 value="locale", text="Locale-defined")
430 radioEncUTF8 = Radiobutton(
431 frameEncoding, variable=self.encoding,
432 value="utf-8", text="UTF-8")
433 radioEncNone = Radiobutton(
434 frameEncoding, variable=self.encoding,
435 value="none", text="None")
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000436 #frameHelp
Terry Jan Reedyae410862014-08-03 23:02:53 -0400437 frameHelpList = Frame(frameHelp)
438 frameHelpListButtons = Frame(frameHelpList)
439 scrollHelpList = Scrollbar(frameHelpList)
440 self.listHelp = Listbox(
441 frameHelpList, height=5, takefocus=FALSE,
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000442 exportselection=FALSE)
443 scrollHelpList.config(command=self.listHelp.yview)
444 self.listHelp.config(yscrollcommand=scrollHelpList.set)
Terry Jan Reedyae410862014-08-03 23:02:53 -0400445 self.listHelp.bind('<ButtonRelease-1>', self.HelpSourceSelected)
446 self.buttonHelpListEdit = Button(
447 frameHelpListButtons, text='Edit', state=DISABLED,
448 width=8, command=self.HelpListItemEdit)
449 self.buttonHelpListAdd = Button(
450 frameHelpListButtons, text='Add',
451 width=8, command=self.HelpListItemAdd)
452 self.buttonHelpListRemove = Button(
453 frameHelpListButtons, text='Remove', state=DISABLED,
454 width=8, command=self.HelpListItemRemove)
Terry Jan Reedy19b7a752014-07-30 19:24:26 -0400455
Steven M. Gava230e5782001-08-07 03:28:25 +0000456 #widget packing
457 #body
Terry Jan Reedyae410862014-08-03 23:02:53 -0400458 frameRun.pack(side=TOP, padx=5, pady=5, fill=X)
459 frameSave.pack(side=TOP, padx=5, pady=5, fill=X)
460 frameWinSize.pack(side=TOP, padx=5, pady=5, fill=X)
461 frameParaSize.pack(side=TOP, padx=5, pady=5, fill=X)
462 frameEncoding.pack(side=TOP, padx=5, pady=5, fill=X)
463 frameHelp.pack(side=TOP, padx=5, pady=5, expand=TRUE, fill=BOTH)
Steven M. Gava230e5782001-08-07 03:28:25 +0000464 #frameRun
Terry Jan Reedyae410862014-08-03 23:02:53 -0400465 labelRunChoiceTitle.pack(side=LEFT, anchor=W, padx=5, pady=5)
466 radioStartupShell.pack(side=RIGHT, anchor=W, padx=5, pady=5)
467 radioStartupEdit.pack(side=RIGHT, anchor=W, padx=5, pady=5)
Kurt B. Kaiser6c638b62003-05-26 06:23:10 +0000468 #frameSave
Terry Jan Reedyae410862014-08-03 23:02:53 -0400469 labelRunSaveTitle.pack(side=LEFT, anchor=W, padx=5, pady=5)
470 radioSaveAuto.pack(side=RIGHT, anchor=W, padx=5, pady=5)
471 radioSaveAsk.pack(side=RIGHT, anchor=W, padx=5, pady=5)
Steven M. Gava230e5782001-08-07 03:28:25 +0000472 #frameWinSize
Terry Jan Reedyae410862014-08-03 23:02:53 -0400473 labelWinSizeTitle.pack(side=LEFT, anchor=W, padx=5, pady=5)
474 entryWinHeight.pack(side=RIGHT, anchor=E, padx=10, pady=5)
475 labelWinHeightTitle.pack(side=RIGHT, anchor=E, pady=5)
476 entryWinWidth.pack(side=RIGHT, anchor=E, padx=10, pady=5)
477 labelWinWidthTitle.pack(side=RIGHT, anchor=E, pady=5)
Raymond Hettinger4e49b832004-06-04 06:31:08 +0000478 #paragraphFormatWidth
Terry Jan Reedyae410862014-08-03 23:02:53 -0400479 labelParaWidthTitle.pack(side=LEFT, anchor=W, padx=5, pady=5)
480 entryParaWidth.pack(side=RIGHT, anchor=E, padx=10, pady=5)
Kurt B. Kaisera053f332003-05-10 00:49:56 +0000481 #frameEncoding
Terry Jan Reedyae410862014-08-03 23:02:53 -0400482 labelEncodingTitle.pack(side=LEFT, anchor=W, padx=5, pady=5)
483 radioEncNone.pack(side=RIGHT, anchor=E, pady=5)
484 radioEncUTF8.pack(side=RIGHT, anchor=E, pady=5)
485 radioEncLocale.pack(side=RIGHT, anchor=E, pady=5)
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000486 #frameHelp
Terry Jan Reedyae410862014-08-03 23:02:53 -0400487 frameHelpListButtons.pack(side=RIGHT, padx=5, pady=5, fill=Y)
488 frameHelpList.pack(side=TOP, padx=5, pady=5, expand=TRUE, fill=BOTH)
489 scrollHelpList.pack(side=RIGHT, anchor=W, fill=Y)
490 self.listHelp.pack(side=LEFT, anchor=E, expand=TRUE, fill=BOTH)
491 self.buttonHelpListEdit.pack(side=TOP, anchor=W, pady=5)
492 self.buttonHelpListAdd.pack(side=TOP, anchor=W)
493 self.buttonHelpListRemove.pack(side=TOP, anchor=W, pady=5)
Steven M. Gava952d0a52001-08-03 04:43:44 +0000494 return frame
495
Steven M. Gavac112cd82002-01-22 05:56:40 +0000496 def AttachVarCallbacks(self):
Terry Jan Reedyae410862014-08-03 23:02:53 -0400497 self.fontSize.trace_variable('w', self.VarChanged_fontSize)
498 self.fontName.trace_variable('w', self.VarChanged_fontName)
499 self.fontBold.trace_variable('w', self.VarChanged_fontBold)
500 self.spaceNum.trace_variable('w', self.VarChanged_spaceNum)
501 self.colour.trace_variable('w', self.VarChanged_colour)
502 self.builtinTheme.trace_variable('w', self.VarChanged_builtinTheme)
503 self.customTheme.trace_variable('w', self.VarChanged_customTheme)
504 self.themeIsBuiltin.trace_variable('w', self.VarChanged_themeIsBuiltin)
505 self.highlightTarget.trace_variable('w', self.VarChanged_highlightTarget)
506 self.keyBinding.trace_variable('w', self.VarChanged_keyBinding)
507 self.builtinKeys.trace_variable('w', self.VarChanged_builtinKeys)
508 self.customKeys.trace_variable('w', self.VarChanged_customKeys)
509 self.keysAreBuiltin.trace_variable('w', self.VarChanged_keysAreBuiltin)
510 self.winWidth.trace_variable('w', self.VarChanged_winWidth)
511 self.winHeight.trace_variable('w', self.VarChanged_winHeight)
512 self.paraWidth.trace_variable('w', self.VarChanged_paraWidth)
513 self.startupEdit.trace_variable('w', self.VarChanged_startupEdit)
514 self.autoSave.trace_variable('w', self.VarChanged_autoSave)
515 self.encoding.trace_variable('w', self.VarChanged_encoding)
Steven M. Gava052937f2002-02-11 02:20:53 +0000516
Terry Jan Reedyae410862014-08-03 23:02:53 -0400517 def VarChanged_fontSize(self, *params):
518 value = self.fontSize.get()
519 self.AddChangedItem('main', 'EditorWindow', 'font-size', value)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000520
Terry Jan Reedyae410862014-08-03 23:02:53 -0400521 def VarChanged_fontName(self, *params):
522 value = self.fontName.get()
523 self.AddChangedItem('main', 'EditorWindow', 'font', value)
Steven M. Gavac112cd82002-01-22 05:56:40 +0000524
Terry Jan Reedyae410862014-08-03 23:02:53 -0400525 def VarChanged_fontBold(self, *params):
526 value = self.fontBold.get()
527 self.AddChangedItem('main', 'EditorWindow', 'font-bold', value)
Steven M. Gavac112cd82002-01-22 05:56:40 +0000528
Terry Jan Reedyae410862014-08-03 23:02:53 -0400529 def VarChanged_spaceNum(self, *params):
530 value = self.spaceNum.get()
531 self.AddChangedItem('main', 'Indent', 'num-spaces', value)
Steven M. Gavac112cd82002-01-22 05:56:40 +0000532
Terry Jan Reedyae410862014-08-03 23:02:53 -0400533 def VarChanged_colour(self, *params):
Steven M. Gava052937f2002-02-11 02:20:53 +0000534 self.OnNewColourSet()
535
Terry Jan Reedyae410862014-08-03 23:02:53 -0400536 def VarChanged_builtinTheme(self, *params):
537 value = self.builtinTheme.get()
538 self.AddChangedItem('main', 'Theme', 'name', value)
Steven M. Gava052937f2002-02-11 02:20:53 +0000539 self.PaintThemeSample()
540
Terry Jan Reedyae410862014-08-03 23:02:53 -0400541 def VarChanged_customTheme(self, *params):
542 value = self.customTheme.get()
Steven M. Gava49745752002-02-18 01:43:11 +0000543 if value != '- no custom themes -':
Terry Jan Reedyae410862014-08-03 23:02:53 -0400544 self.AddChangedItem('main', 'Theme', 'name', value)
Steven M. Gava49745752002-02-18 01:43:11 +0000545 self.PaintThemeSample()
Steven M. Gava052937f2002-02-11 02:20:53 +0000546
Terry Jan Reedyae410862014-08-03 23:02:53 -0400547 def VarChanged_themeIsBuiltin(self, *params):
548 value = self.themeIsBuiltin.get()
549 self.AddChangedItem('main', 'Theme', 'default', value)
Steven M. Gavaf31eec02002-03-05 00:25:58 +0000550 if value:
551 self.VarChanged_builtinTheme()
552 else:
553 self.VarChanged_customTheme()
Steven M. Gava052937f2002-02-11 02:20:53 +0000554
Terry Jan Reedyae410862014-08-03 23:02:53 -0400555 def VarChanged_highlightTarget(self, *params):
Steven M. Gava052937f2002-02-11 02:20:53 +0000556 self.SetHighlightTarget()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000557
Terry Jan Reedyae410862014-08-03 23:02:53 -0400558 def VarChanged_keyBinding(self, *params):
559 value = self.keyBinding.get()
560 keySet = self.customKeys.get()
561 event = self.listBindings.get(ANCHOR).split()[0]
Steven M. Gavaa498af22002-02-01 01:33:36 +0000562 if idleConf.IsCoreBinding(event):
563 #this is a core keybinding
Terry Jan Reedyae410862014-08-03 23:02:53 -0400564 self.AddChangedItem('keys', keySet, event, value)
Steven M. Gavaa498af22002-02-01 01:33:36 +0000565 else: #this is an extension key binding
Terry Jan Reedyae410862014-08-03 23:02:53 -0400566 extName = idleConf.GetExtnNameForEvent(event)
567 extKeybindSection = extName + '_cfgBindings'
568 self.AddChangedItem('extensions', extKeybindSection, event, value)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000569
Terry Jan Reedyae410862014-08-03 23:02:53 -0400570 def VarChanged_builtinKeys(self, *params):
571 value = self.builtinKeys.get()
572 self.AddChangedItem('main', 'Keys', 'name', value)
Steven M. Gava052937f2002-02-11 02:20:53 +0000573 self.LoadKeysList(value)
574
Terry Jan Reedyae410862014-08-03 23:02:53 -0400575 def VarChanged_customKeys(self, *params):
576 value = self.customKeys.get()
Steven M. Gava49745752002-02-18 01:43:11 +0000577 if value != '- no custom keys -':
Terry Jan Reedyae410862014-08-03 23:02:53 -0400578 self.AddChangedItem('main', 'Keys', 'name', value)
Steven M. Gava49745752002-02-18 01:43:11 +0000579 self.LoadKeysList(value)
Steven M. Gava052937f2002-02-11 02:20:53 +0000580
Terry Jan Reedyae410862014-08-03 23:02:53 -0400581 def VarChanged_keysAreBuiltin(self, *params):
582 value = self.keysAreBuiltin.get()
583 self.AddChangedItem('main', 'Keys', 'default', value)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000584 if value:
Steven M. Gavaf31eec02002-03-05 00:25:58 +0000585 self.VarChanged_builtinKeys()
Steven M. Gava052937f2002-02-11 02:20:53 +0000586 else:
Steven M. Gavaf31eec02002-03-05 00:25:58 +0000587 self.VarChanged_customKeys()
Steven M. Gava052937f2002-02-11 02:20:53 +0000588
Terry Jan Reedyae410862014-08-03 23:02:53 -0400589 def VarChanged_winWidth(self, *params):
590 value = self.winWidth.get()
591 self.AddChangedItem('main', 'EditorWindow', 'width', value)
Steven M. Gavac112cd82002-01-22 05:56:40 +0000592
Terry Jan Reedyae410862014-08-03 23:02:53 -0400593 def VarChanged_winHeight(self, *params):
594 value = self.winHeight.get()
595 self.AddChangedItem('main', 'EditorWindow', 'height', value)
Steven M. Gavac112cd82002-01-22 05:56:40 +0000596
Terry Jan Reedyae410862014-08-03 23:02:53 -0400597 def VarChanged_paraWidth(self, *params):
598 value = self.paraWidth.get()
599 self.AddChangedItem('main', 'FormatParagraph', 'paragraph', value)
Raymond Hettinger4e49b832004-06-04 06:31:08 +0000600
Terry Jan Reedyae410862014-08-03 23:02:53 -0400601 def VarChanged_startupEdit(self, *params):
602 value = self.startupEdit.get()
603 self.AddChangedItem('main', 'General', 'editor-on-startup', value)
Steven M. Gavac112cd82002-01-22 05:56:40 +0000604
Terry Jan Reedyae410862014-08-03 23:02:53 -0400605 def VarChanged_autoSave(self, *params):
606 value = self.autoSave.get()
607 self.AddChangedItem('main', 'General', 'autosave', value)
Kurt B. Kaiser6c638b62003-05-26 06:23:10 +0000608
Terry Jan Reedyae410862014-08-03 23:02:53 -0400609 def VarChanged_encoding(self, *params):
610 value = self.encoding.get()
611 self.AddChangedItem('main', 'EditorWindow', 'encoding', value)
Kurt B. Kaisera053f332003-05-10 00:49:56 +0000612
Steven M. Gavaa498af22002-02-01 01:33:36 +0000613 def ResetChangedItems(self):
Steven M. Gavab77d3432002-03-02 07:16:21 +0000614 #When any config item is changed in this dialog, an entry
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000615 #should be made in the relevant section (config type) of this
616 #dictionary. The key should be the config file section name and the
Steven M. Gavaa498af22002-02-01 01:33:36 +0000617 #value a dictionary, whose key:value pairs are item=value pairs for
618 #that config file section.
Terry Jan Reedyae410862014-08-03 23:02:53 -0400619 self.changedItems = {'main':{}, 'highlight':{}, 'keys':{},
620 'extensions':{}}
Steven M. Gavaa498af22002-02-01 01:33:36 +0000621
Terry Jan Reedyae410862014-08-03 23:02:53 -0400622 def AddChangedItem(self, typ, section, item, value):
623 value = str(value) #make sure we use a string
624 if section not in self.changedItems[typ]:
625 self.changedItems[typ][section] = {}
626 self.changedItems[typ][section][item] = value
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000627
Steven M. Gava5f28e8f2002-01-21 06:38:21 +0000628 def GetDefaultItems(self):
Terry Jan Reedyae410862014-08-03 23:02:53 -0400629 dItems={'main':{}, 'highlight':{}, 'keys':{}, 'extensions':{}}
Terry Jan Reedy110796f2014-07-27 04:07:18 -0400630 for configType in dItems:
Terry Jan Reedyae410862014-08-03 23:02:53 -0400631 sections = idleConf.GetSectionList('default', configType)
Steven M. Gava5f28e8f2002-01-21 06:38:21 +0000632 for section in sections:
Terry Jan Reedyae410862014-08-03 23:02:53 -0400633 dItems[configType][section] = {}
634 options = idleConf.defaultCfg[configType].GetOptionList(section)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000635 for option in options:
Terry Jan Reedyae410862014-08-03 23:02:53 -0400636 dItems[configType][section][option] = (
637 idleConf.defaultCfg[configType].Get(section, option))
Steven M. Gava5f28e8f2002-01-21 06:38:21 +0000638 return dItems
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000639
Steven M. Gava5f28e8f2002-01-21 06:38:21 +0000640 def SetThemeType(self):
641 if self.themeIsBuiltin.get():
642 self.optMenuThemeBuiltin.config(state=NORMAL)
643 self.optMenuThemeCustom.config(state=DISABLED)
644 self.buttonDeleteCustomTheme.config(state=DISABLED)
645 else:
646 self.optMenuThemeBuiltin.config(state=DISABLED)
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000647 self.radioThemeCustom.config(state=NORMAL)
Steven M. Gava5f28e8f2002-01-21 06:38:21 +0000648 self.optMenuThemeCustom.config(state=NORMAL)
649 self.buttonDeleteCustomTheme.config(state=NORMAL)
650
651 def SetKeysType(self):
Steven M. Gava052937f2002-02-11 02:20:53 +0000652 if self.keysAreBuiltin.get():
Steven M. Gava5f28e8f2002-01-21 06:38:21 +0000653 self.optMenuKeysBuiltin.config(state=NORMAL)
654 self.optMenuKeysCustom.config(state=DISABLED)
655 self.buttonDeleteCustomKeys.config(state=DISABLED)
656 else:
657 self.optMenuKeysBuiltin.config(state=DISABLED)
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000658 self.radioKeysCustom.config(state=NORMAL)
Steven M. Gava5f28e8f2002-01-21 06:38:21 +0000659 self.optMenuKeysCustom.config(state=NORMAL)
660 self.buttonDeleteCustomKeys.config(state=NORMAL)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000661
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000662 def GetNewKeys(self):
Terry Jan Reedyae410862014-08-03 23:02:53 -0400663 listIndex = self.listBindings.index(ANCHOR)
664 binding = self.listBindings.get(listIndex)
665 bindName = binding.split()[0] #first part, up to first space
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000666 if self.keysAreBuiltin.get():
Terry Jan Reedyae410862014-08-03 23:02:53 -0400667 currentKeySetName = self.builtinKeys.get()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000668 else:
Terry Jan Reedyae410862014-08-03 23:02:53 -0400669 currentKeySetName = self.customKeys.get()
670 currentBindings = idleConf.GetCurrentKeySet()
Terry Jan Reedy110796f2014-07-27 04:07:18 -0400671 if currentKeySetName in self.changedItems['keys']: #unsaved changes
Terry Jan Reedyae410862014-08-03 23:02:53 -0400672 keySetChanges = self.changedItems['keys'][currentKeySetName]
Terry Jan Reedy110796f2014-07-27 04:07:18 -0400673 for event in keySetChanges:
Terry Jan Reedyae410862014-08-03 23:02:53 -0400674 currentBindings[event] = keySetChanges[event].split()
675 currentKeySequences = currentBindings.values()
676 newKeys = GetKeysDialog(self, 'Get New Keys', bindName,
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000677 currentKeySequences).result
678 if newKeys: #new keys were specified
Steven M. Gava052937f2002-02-11 02:20:53 +0000679 if self.keysAreBuiltin.get(): #current key set is a built-in
Terry Jan Reedyae410862014-08-03 23:02:53 -0400680 message = ('Your changes will be saved as a new Custom Key Set.'
681 ' Enter a name for your new Custom Key Set below.')
682 newKeySet = self.GetNewKeysName(message)
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000683 if not newKeySet: #user cancelled custom key set creation
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000684 self.listBindings.select_set(listIndex)
685 self.listBindings.select_anchor(listIndex)
686 return
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000687 else: #create new custom key set based on previously active key set
688 self.CreateNewKeySet(newKeySet)
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000689 self.listBindings.delete(listIndex)
Terry Jan Reedyae410862014-08-03 23:02:53 -0400690 self.listBindings.insert(listIndex, bindName+' - '+newKeys)
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000691 self.listBindings.select_set(listIndex)
692 self.listBindings.select_anchor(listIndex)
Steven M. Gava052937f2002-02-11 02:20:53 +0000693 self.keyBinding.set(newKeys)
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000694 else:
695 self.listBindings.select_set(listIndex)
696 self.listBindings.select_anchor(listIndex)
697
Terry Jan Reedyae410862014-08-03 23:02:53 -0400698 def GetNewKeysName(self, message):
699 usedNames = (idleConf.GetSectionList('user', 'keys') +
700 idleConf.GetSectionList('default', 'keys'))
701 newKeySet = GetCfgSectionNameDialog(
702 self, 'New Custom Key Set', message, usedNames).result
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000703 return newKeySet
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000704
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000705 def SaveAsNewKeySet(self):
Terry Jan Reedyae410862014-08-03 23:02:53 -0400706 newKeysName = self.GetNewKeysName('New Key Set Name:')
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000707 if newKeysName:
708 self.CreateNewKeySet(newKeysName)
709
Terry Jan Reedyae410862014-08-03 23:02:53 -0400710 def KeyBindingSelected(self, event):
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000711 self.buttonNewKeys.config(state=NORMAL)
712
Terry Jan Reedyae410862014-08-03 23:02:53 -0400713 def CreateNewKeySet(self, newKeySetName):
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000714 #creates new custom key set based on the previously active key set,
715 #and makes the new key set active
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000716 if self.keysAreBuiltin.get():
Terry Jan Reedyae410862014-08-03 23:02:53 -0400717 prevKeySetName = self.builtinKeys.get()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000718 else:
Terry Jan Reedyae410862014-08-03 23:02:53 -0400719 prevKeySetName = self.customKeys.get()
720 prevKeys = idleConf.GetCoreKeys(prevKeySetName)
721 newKeys = {}
Terry Jan Reedy110796f2014-07-27 04:07:18 -0400722 for event in prevKeys: #add key set to changed items
Terry Jan Reedyae410862014-08-03 23:02:53 -0400723 eventName = event[2:-2] #trim off the angle brackets
724 binding = ' '.join(prevKeys[event])
725 newKeys[eventName] = binding
Steven M. Gava052937f2002-02-11 02:20:53 +0000726 #handle any unsaved changes to prev key set
Terry Jan Reedy110796f2014-07-27 04:07:18 -0400727 if prevKeySetName in self.changedItems['keys']:
Terry Jan Reedyae410862014-08-03 23:02:53 -0400728 keySetChanges = self.changedItems['keys'][prevKeySetName]
Terry Jan Reedy110796f2014-07-27 04:07:18 -0400729 for event in keySetChanges:
Terry Jan Reedyae410862014-08-03 23:02:53 -0400730 newKeys[event] = keySetChanges[event]
Steven M. Gava052937f2002-02-11 02:20:53 +0000731 #save the new theme
Terry Jan Reedyae410862014-08-03 23:02:53 -0400732 self.SaveNewKeySet(newKeySetName, newKeys)
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000733 #change gui over to the new key set
Terry Jan Reedyae410862014-08-03 23:02:53 -0400734 customKeyList = idleConf.GetSectionList('user', 'keys')
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000735 customKeyList.sort()
Terry Jan Reedyae410862014-08-03 23:02:53 -0400736 self.optMenuKeysCustom.SetMenu(customKeyList, newKeySetName)
Steven M. Gava052937f2002-02-11 02:20:53 +0000737 self.keysAreBuiltin.set(0)
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000738 self.SetKeysType()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000739
Terry Jan Reedyae410862014-08-03 23:02:53 -0400740 def LoadKeysList(self, keySetName):
741 reselect = 0
742 newKeySet = 0
Steven M. Gava052937f2002-02-11 02:20:53 +0000743 if self.listBindings.curselection():
Terry Jan Reedyae410862014-08-03 23:02:53 -0400744 reselect = 1
745 listIndex = self.listBindings.index(ANCHOR)
746 keySet = idleConf.GetKeySet(keySetName)
747 bindNames = keySet.keys()
Steven M. Gava052937f2002-02-11 02:20:53 +0000748 bindNames.sort()
Terry Jan Reedyae410862014-08-03 23:02:53 -0400749 self.listBindings.delete(0, END)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000750 for bindName in bindNames:
Terry Jan Reedyae410862014-08-03 23:02:53 -0400751 key = ' '.join(keySet[bindName]) #make key(s) into a string
752 bindName = bindName[2:-2] #trim off the angle brackets
Terry Jan Reedy110796f2014-07-27 04:07:18 -0400753 if keySetName in self.changedItems['keys']:
Steven M. Gava052937f2002-02-11 02:20:53 +0000754 #handle any unsaved changes to this key set
Terry Jan Reedy110796f2014-07-27 04:07:18 -0400755 if bindName in self.changedItems['keys'][keySetName]:
Terry Jan Reedyae410862014-08-03 23:02:53 -0400756 key = self.changedItems['keys'][keySetName][bindName]
Steven M. Gava052937f2002-02-11 02:20:53 +0000757 self.listBindings.insert(END, bindName+' - '+key)
Steven M. Gava052937f2002-02-11 02:20:53 +0000758 if reselect:
759 self.listBindings.see(listIndex)
760 self.listBindings.select_set(listIndex)
761 self.listBindings.select_anchor(listIndex)
762
Steven M. Gava49745752002-02-18 01:43:11 +0000763 def DeleteCustomKeys(self):
764 keySetName=self.customKeys.get()
Terry Jan Reedyae410862014-08-03 23:02:53 -0400765 delmsg = 'Are you sure you wish to delete the key set %r ?'
766 if not tkMessageBox.askyesno(
767 'Delete Key Set', delmsg % keySetName, parent=self):
Steven M. Gava49745752002-02-18 01:43:11 +0000768 return
769 #remove key set from config
770 idleConf.userCfg['keys'].remove_section(keySetName)
Benjamin Peterson6e3dbbd2009-10-09 22:15:50 +0000771 if keySetName in self.changedItems['keys']:
Steven M. Gava49745752002-02-18 01:43:11 +0000772 del(self.changedItems['keys'][keySetName])
773 #write changes
774 idleConf.userCfg['keys'].Save()
775 #reload user key set list
Terry Jan Reedyae410862014-08-03 23:02:53 -0400776 itemList = idleConf.GetSectionList('user', 'keys')
Steven M. Gava49745752002-02-18 01:43:11 +0000777 itemList.sort()
778 if not itemList:
779 self.radioKeysCustom.config(state=DISABLED)
Terry Jan Reedyae410862014-08-03 23:02:53 -0400780 self.optMenuKeysCustom.SetMenu(itemList, '- no custom keys -')
Steven M. Gava49745752002-02-18 01:43:11 +0000781 else:
Terry Jan Reedyae410862014-08-03 23:02:53 -0400782 self.optMenuKeysCustom.SetMenu(itemList, itemList[0])
Steven M. Gava49745752002-02-18 01:43:11 +0000783 #revert to default key set
Terry Jan Reedyae410862014-08-03 23:02:53 -0400784 self.keysAreBuiltin.set(idleConf.defaultCfg['main'].Get('Keys', 'default'))
785 self.builtinKeys.set(idleConf.defaultCfg['main'].Get('Keys', 'name'))
Steven M. Gava49745752002-02-18 01:43:11 +0000786 #user can't back out of these changes, they must be applied now
787 self.Apply()
788 self.SetKeysType()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000789
Steven M. Gava49745752002-02-18 01:43:11 +0000790 def DeleteCustomTheme(self):
Terry Jan Reedyae410862014-08-03 23:02:53 -0400791 themeName = self.customTheme.get()
792 delmsg = 'Are you sure you wish to delete the theme %r ?'
793 if not tkMessageBox.askyesno(
794 'Delete Theme', delmsg % themeName, parent=self):
Steven M. Gava49745752002-02-18 01:43:11 +0000795 return
796 #remove theme from config
797 idleConf.userCfg['highlight'].remove_section(themeName)
Benjamin Peterson6e3dbbd2009-10-09 22:15:50 +0000798 if themeName in self.changedItems['highlight']:
Steven M. Gava49745752002-02-18 01:43:11 +0000799 del(self.changedItems['highlight'][themeName])
800 #write changes
801 idleConf.userCfg['highlight'].Save()
802 #reload user theme list
Terry Jan Reedyae410862014-08-03 23:02:53 -0400803 itemList = idleConf.GetSectionList('user', 'highlight')
Steven M. Gava49745752002-02-18 01:43:11 +0000804 itemList.sort()
805 if not itemList:
806 self.radioThemeCustom.config(state=DISABLED)
Terry Jan Reedyae410862014-08-03 23:02:53 -0400807 self.optMenuThemeCustom.SetMenu(itemList, '- no custom themes -')
Steven M. Gava49745752002-02-18 01:43:11 +0000808 else:
Terry Jan Reedyae410862014-08-03 23:02:53 -0400809 self.optMenuThemeCustom.SetMenu(itemList, itemList[0])
Steven M. Gava49745752002-02-18 01:43:11 +0000810 #revert to default theme
Terry Jan Reedyae410862014-08-03 23:02:53 -0400811 self.themeIsBuiltin.set(idleConf.defaultCfg['main'].Get('Theme', 'default'))
812 self.builtinTheme.set(idleConf.defaultCfg['main'].Get('Theme', 'name'))
Steven M. Gava49745752002-02-18 01:43:11 +0000813 #user can't back out of these changes, they must be applied now
814 self.Apply()
815 self.SetThemeType()
816
Steven M. Gava5f28e8f2002-01-21 06:38:21 +0000817 def GetColour(self):
Terry Jan Reedyae410862014-08-03 23:02:53 -0400818 target = self.highlightTarget.get()
819 prevColour = self.frameColourSet.cget('bg')
820 rgbTuplet, colourString = tkColorChooser.askcolor(
821 parent=self, title='Pick new colour for : '+target,
822 initialcolor=prevColour)
823 if colourString and (colourString != prevColour):
Steven M. Gava052937f2002-02-11 02:20:53 +0000824 #user didn't cancel, and they chose a new colour
Terry Jan Reedyae410862014-08-03 23:02:53 -0400825 if self.themeIsBuiltin.get(): #current theme is a built-in
826 message = ('Your changes will be saved as a new Custom Theme. '
827 'Enter a name for your new Custom Theme below.')
828 newTheme = self.GetNewThemeName(message)
829 if not newTheme: #user cancelled custom theme creation
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000830 return
Terry Jan Reedyae410862014-08-03 23:02:53 -0400831 else: #create new custom theme based on previously active theme
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000832 self.CreateNewTheme(newTheme)
Steven M. Gava052937f2002-02-11 02:20:53 +0000833 self.colour.set(colourString)
Terry Jan Reedyae410862014-08-03 23:02:53 -0400834 else: #current theme is user defined
Steven M. Gava052937f2002-02-11 02:20:53 +0000835 self.colour.set(colourString)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000836
Steven M. Gava052937f2002-02-11 02:20:53 +0000837 def OnNewColourSet(self):
838 newColour=self.colour.get()
Terry Jan Reedyae410862014-08-03 23:02:53 -0400839 self.frameColourSet.config(bg=newColour) #set sample
840 plane ='foreground' if self.fgHilite.get() else 'background'
841 sampleElement = self.themeElements[self.highlightTarget.get()][0]
Raymond Hettinger931237e2003-07-09 18:48:24 +0000842 self.textHighlightSample.tag_config(sampleElement, **{plane:newColour})
Terry Jan Reedyae410862014-08-03 23:02:53 -0400843 theme = self.customTheme.get()
844 themeElement = sampleElement + '-' + plane
845 self.AddChangedItem('highlight', theme, themeElement, newColour)
Steven M. Gava052937f2002-02-11 02:20:53 +0000846
Terry Jan Reedyae410862014-08-03 23:02:53 -0400847 def GetNewThemeName(self, message):
848 usedNames = (idleConf.GetSectionList('user', 'highlight') +
849 idleConf.GetSectionList('default', 'highlight'))
850 newTheme = GetCfgSectionNameDialog(
851 self, 'New Custom Theme', message, usedNames).result
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000852 return newTheme
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000853
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000854 def SaveAsNewTheme(self):
Terry Jan Reedyae410862014-08-03 23:02:53 -0400855 newThemeName = self.GetNewThemeName('New Theme Name:')
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000856 if newThemeName:
857 self.CreateNewTheme(newThemeName)
858
Terry Jan Reedyae410862014-08-03 23:02:53 -0400859 def CreateNewTheme(self, newThemeName):
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000860 #creates new custom theme based on the previously active theme,
861 #and makes the new theme active
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000862 if self.themeIsBuiltin.get():
Terry Jan Reedyae410862014-08-03 23:02:53 -0400863 themeType = 'default'
864 themeName = self.builtinTheme.get()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000865 else:
Terry Jan Reedyae410862014-08-03 23:02:53 -0400866 themeType = 'user'
867 themeName = self.customTheme.get()
868 newTheme = idleConf.GetThemeDict(themeType, themeName)
Steven M. Gava052937f2002-02-11 02:20:53 +0000869 #apply any of the old theme's unsaved changes to the new theme
Terry Jan Reedy110796f2014-07-27 04:07:18 -0400870 if themeName in self.changedItems['highlight']:
Terry Jan Reedyae410862014-08-03 23:02:53 -0400871 themeChanges = self.changedItems['highlight'][themeName]
Terry Jan Reedy110796f2014-07-27 04:07:18 -0400872 for element in themeChanges:
Terry Jan Reedyae410862014-08-03 23:02:53 -0400873 newTheme[element] = themeChanges[element]
Steven M. Gava052937f2002-02-11 02:20:53 +0000874 #save the new theme
Terry Jan Reedyae410862014-08-03 23:02:53 -0400875 self.SaveNewTheme(newThemeName, newTheme)
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000876 #change gui over to the new theme
Terry Jan Reedyae410862014-08-03 23:02:53 -0400877 customThemeList = idleConf.GetSectionList('user', 'highlight')
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000878 customThemeList.sort()
Terry Jan Reedyae410862014-08-03 23:02:53 -0400879 self.optMenuThemeCustom.SetMenu(customThemeList, newThemeName)
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000880 self.themeIsBuiltin.set(0)
881 self.SetThemeType()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000882
Terry Jan Reedyae410862014-08-03 23:02:53 -0400883 def OnListFontButtonRelease(self, event):
Kurt B. Kaiser05391692003-05-26 20:35:53 +0000884 font = self.listFontName.get(ANCHOR)
885 self.fontName.set(font.lower())
Steven M. Gava5f28e8f2002-01-21 06:38:21 +0000886 self.SetFontSample()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000887
Terry Jan Reedyae410862014-08-03 23:02:53 -0400888 def SetFontSample(self, event=None):
889 fontName = self.fontName.get()
890 fontWeight = tkFont.BOLD if self.fontBold.get() else tkFont.NORMAL
Ned Deilye3d47122012-10-22 15:13:01 -0700891 newFont = (fontName, self.fontSize.get(), fontWeight)
892 self.labelFontSample.config(font=newFont)
893 self.textHighlightSample.configure(font=newFont)
Steven M. Gava5f28e8f2002-01-21 06:38:21 +0000894
Steven M. Gava5f28e8f2002-01-21 06:38:21 +0000895 def SetHighlightTarget(self):
Terry Jan Reedyae410862014-08-03 23:02:53 -0400896 if self.highlightTarget.get() == 'Cursor': #bg not possible
Steven M. Gava5f28e8f2002-01-21 06:38:21 +0000897 self.radioFg.config(state=DISABLED)
898 self.radioBg.config(state=DISABLED)
899 self.fgHilite.set(1)
Terry Jan Reedyae410862014-08-03 23:02:53 -0400900 else: #both fg and bg can be set
Steven M. Gava5f28e8f2002-01-21 06:38:21 +0000901 self.radioFg.config(state=NORMAL)
902 self.radioBg.config(state=NORMAL)
903 self.fgHilite.set(1)
904 self.SetColourSample()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000905
Terry Jan Reedyae410862014-08-03 23:02:53 -0400906 def SetColourSampleBinding(self, *args):
Steven M. Gava5f28e8f2002-01-21 06:38:21 +0000907 self.SetColourSample()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000908
Steven M. Gava5f28e8f2002-01-21 06:38:21 +0000909 def SetColourSample(self):
910 #set the colour smaple area
Terry Jan Reedyae410862014-08-03 23:02:53 -0400911 tag = self.themeElements[self.highlightTarget.get()][0]
912 plane = 'foreground' if self.fgHilite.get() else 'background'
913 colour = self.textHighlightSample.tag_cget(tag, plane)
Steven M. Gava5f28e8f2002-01-21 06:38:21 +0000914 self.frameColourSet.config(bg=colour)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000915
Steven M. Gava9dd16b32001-11-03 14:54:25 +0000916 def PaintThemeSample(self):
Terry Jan Reedyae410862014-08-03 23:02:53 -0400917 if self.themeIsBuiltin.get(): #a default theme
918 theme = self.builtinTheme.get()
919 else: #a user theme
920 theme = self.customTheme.get()
Terry Jan Reedy110796f2014-07-27 04:07:18 -0400921 for elementTitle in self.themeElements:
Terry Jan Reedyae410862014-08-03 23:02:53 -0400922 element = self.themeElements[elementTitle][0]
923 colours = idleConf.GetHighlight(theme, element)
924 if element == 'cursor': #cursor sample needs special painting
925 colours['background'] = idleConf.GetHighlight(
926 theme, 'normal', fgBg='bg')
Steven M. Gava052937f2002-02-11 02:20:53 +0000927 #handle any unsaved changes to this theme
Terry Jan Reedy110796f2014-07-27 04:07:18 -0400928 if theme in self.changedItems['highlight']:
Terry Jan Reedyae410862014-08-03 23:02:53 -0400929 themeDict = self.changedItems['highlight'][theme]
930 if element + '-foreground' in themeDict:
931 colours['foreground'] = themeDict[element + '-foreground']
932 if element + '-background' in themeDict:
933 colours['background'] = themeDict[element + '-background']
Raymond Hettinger931237e2003-07-09 18:48:24 +0000934 self.textHighlightSample.tag_config(element, **colours)
Steven M. Gava052937f2002-02-11 02:20:53 +0000935 self.SetColourSample()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000936
Terry Jan Reedyae410862014-08-03 23:02:53 -0400937 def HelpSourceSelected(self, event):
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000938 self.SetHelpListButtonStates()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000939
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000940 def SetHelpListButtonStates(self):
Terry Jan Reedyae410862014-08-03 23:02:53 -0400941 if self.listHelp.size() < 1: #no entries in list
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000942 self.buttonHelpListEdit.config(state=DISABLED)
943 self.buttonHelpListRemove.config(state=DISABLED)
944 else: #there are some entries
Terry Jan Reedyae410862014-08-03 23:02:53 -0400945 if self.listHelp.curselection(): #there currently is a selection
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000946 self.buttonHelpListEdit.config(state=NORMAL)
947 self.buttonHelpListRemove.config(state=NORMAL)
948 else: #there currently is not a selection
949 self.buttonHelpListEdit.config(state=DISABLED)
950 self.buttonHelpListRemove.config(state=DISABLED)
951
952 def HelpListItemAdd(self):
Terry Jan Reedyae410862014-08-03 23:02:53 -0400953 helpSource = GetHelpSourceDialog(self, 'New Help Source').result
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000954 if helpSource:
Terry Jan Reedyae410862014-08-03 23:02:53 -0400955 self.userHelpList.append((helpSource[0], helpSource[1]))
956 self.listHelp.insert(END, helpSource[0])
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000957 self.UpdateUserHelpChangedItems()
958 self.SetHelpListButtonStates()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000959
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000960 def HelpListItemEdit(self):
Terry Jan Reedyae410862014-08-03 23:02:53 -0400961 itemIndex = self.listHelp.index(ANCHOR)
962 helpSource = self.userHelpList[itemIndex]
963 newHelpSource = GetHelpSourceDialog(
964 self, 'Edit Help Source', menuItem=helpSource[0],
965 filePath=helpSource[1]).result
966 if (not newHelpSource) or (newHelpSource == helpSource):
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000967 return #no changes
Terry Jan Reedyae410862014-08-03 23:02:53 -0400968 self.userHelpList[itemIndex] = newHelpSource
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000969 self.listHelp.delete(itemIndex)
Terry Jan Reedyae410862014-08-03 23:02:53 -0400970 self.listHelp.insert(itemIndex, newHelpSource[0])
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000971 self.UpdateUserHelpChangedItems()
972 self.SetHelpListButtonStates()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000973
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000974 def HelpListItemRemove(self):
Terry Jan Reedyae410862014-08-03 23:02:53 -0400975 itemIndex = self.listHelp.index(ANCHOR)
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000976 del(self.userHelpList[itemIndex])
977 self.listHelp.delete(itemIndex)
978 self.UpdateUserHelpChangedItems()
979 self.SetHelpListButtonStates()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000980
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000981 def UpdateUserHelpChangedItems(self):
Kurt B. Kaiser8e92bf72003-01-14 22:03:31 +0000982 "Clear and rebuild the HelpFiles section in self.changedItems"
983 self.changedItems['main']['HelpFiles'] = {}
Terry Jan Reedyae410862014-08-03 23:02:53 -0400984 for num in range(1, len(self.userHelpList) + 1):
985 self.AddChangedItem(
986 'main', 'HelpFiles', str(num),
Terry Jan Reedy110796f2014-07-27 04:07:18 -0400987 ';'.join(self.userHelpList[num-1][:2]))
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000988
Steven M. Gava429a86a2001-10-23 10:42:12 +0000989 def LoadFontCfg(self):
990 ##base editor font selection list
Terry Jan Reedyae410862014-08-03 23:02:53 -0400991 fonts = list(tkFont.families(self))
Steven M. Gavac11ccf32001-09-24 09:43:17 +0000992 fonts.sort()
993 for font in fonts:
Terry Jan Reedyae410862014-08-03 23:02:53 -0400994 self.listFontName.insert(END, font)
995 configuredFont = idleConf.GetOption(
996 'main', 'EditorWindow', 'font', default='courier')
Kurt B. Kaiser05391692003-05-26 20:35:53 +0000997 lc_configuredFont = configuredFont.lower()
998 self.fontName.set(lc_configuredFont)
999 lc_fonts = [s.lower() for s in fonts]
1000 if lc_configuredFont in lc_fonts:
1001 currentFontIndex = lc_fonts.index(lc_configuredFont)
Steven M. Gava429a86a2001-10-23 10:42:12 +00001002 self.listFontName.see(currentFontIndex)
1003 self.listFontName.select_set(currentFontIndex)
Steven M. Gavac112cd82002-01-22 05:56:40 +00001004 self.listFontName.select_anchor(currentFontIndex)
Steven M. Gava429a86a2001-10-23 10:42:12 +00001005 ##font size dropdown
Terry Jan Reedyae410862014-08-03 23:02:53 -04001006 fontSize = idleConf.GetOption(
1007 'main', 'EditorWindow', 'font-size', type='int', default='10')
1008 self.optMenuFontSize.SetMenu(('7', '8', '9', '10', '11', '12', '13',
1009 '14', '16', '18', '20', '22'), fontSize )
Steven M. Gavac112cd82002-01-22 05:56:40 +00001010 ##fontWeight
Terry Jan Reedyae410862014-08-03 23:02:53 -04001011 self.fontBold.set(idleConf.GetOption(
1012 'main', 'EditorWindow', 'font-bold', default=0, type='bool'))
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001013 ##font sample
Steven M. Gava429a86a2001-10-23 10:42:12 +00001014 self.SetFontSample()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001015
Steven M. Gava429a86a2001-10-23 10:42:12 +00001016 def LoadTabCfg(self):
Steven M. Gava429a86a2001-10-23 10:42:12 +00001017 ##indent sizes
Terry Jan Reedyae410862014-08-03 23:02:53 -04001018 spaceNum = idleConf.GetOption(
1019 'main', 'Indent', 'num-spaces', default=4, type='int')
Steven M. Gava429a86a2001-10-23 10:42:12 +00001020 self.spaceNum.set(spaceNum)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001021
Steven M. Gava9dd16b32001-11-03 14:54:25 +00001022 def LoadThemeCfg(self):
Steven M. Gava41a85322001-10-29 08:05:34 +00001023 ##current theme type radiobutton
Terry Jan Reedyae410862014-08-03 23:02:53 -04001024 self.themeIsBuiltin.set(idleConf.GetOption(
1025 'main', 'Theme', 'default', type='bool', default=1))
Steven M. Gava41a85322001-10-29 08:05:34 +00001026 ##currently set theme
Terry Jan Reedyae410862014-08-03 23:02:53 -04001027 currentOption = idleConf.CurrentTheme()
Steven M. Gava7c017862001-10-29 11:19:46 +00001028 ##load available theme option menus
Steven M. Gavad0342cd2001-11-04 11:53:10 +00001029 if self.themeIsBuiltin.get(): #default theme selected
Terry Jan Reedyae410862014-08-03 23:02:53 -04001030 itemList = idleConf.GetSectionList('default', 'highlight')
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +00001031 itemList.sort()
Terry Jan Reedyae410862014-08-03 23:02:53 -04001032 self.optMenuThemeBuiltin.SetMenu(itemList, currentOption)
1033 itemList = idleConf.GetSectionList('user', 'highlight')
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +00001034 itemList.sort()
Steven M. Gava41a85322001-10-29 08:05:34 +00001035 if not itemList:
1036 self.radioThemeCustom.config(state=DISABLED)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001037 self.customTheme.set('- no custom themes -')
Steven M. Gava41a85322001-10-29 08:05:34 +00001038 else:
Terry Jan Reedyae410862014-08-03 23:02:53 -04001039 self.optMenuThemeCustom.SetMenu(itemList, itemList[0])
Steven M. Gava9dd16b32001-11-03 14:54:25 +00001040 else: #user theme selected
Terry Jan Reedyae410862014-08-03 23:02:53 -04001041 itemList = idleConf.GetSectionList('user', 'highlight')
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +00001042 itemList.sort()
Terry Jan Reedyae410862014-08-03 23:02:53 -04001043 self.optMenuThemeCustom.SetMenu(itemList, currentOption)
1044 itemList = idleConf.GetSectionList('default', 'highlight')
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +00001045 itemList.sort()
Terry Jan Reedyae410862014-08-03 23:02:53 -04001046 self.optMenuThemeBuiltin.SetMenu(itemList, itemList[0])
Steven M. Gava7c017862001-10-29 11:19:46 +00001047 self.SetThemeType()
1048 ##load theme element option menu
Terry Jan Reedyae410862014-08-03 23:02:53 -04001049 themeNames = self.themeElements.keys()
Florent Xiclunaa7f242f2010-04-02 08:15:26 +00001050 themeNames.sort(key=lambda x: self.themeElements[x][1])
Terry Jan Reedyae410862014-08-03 23:02:53 -04001051 self.optMenuHighlightTarget.SetMenu(themeNames, themeNames[0])
Steven M. Gava9dd16b32001-11-03 14:54:25 +00001052 self.PaintThemeSample()
Steven M. Gava0cae01c2002-01-04 07:53:06 +00001053 self.SetHighlightTarget()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001054
Steven M. Gava9dd16b32001-11-03 14:54:25 +00001055 def LoadKeyCfg(self):
Steven M. Gava41a85322001-10-29 08:05:34 +00001056 ##current keys type radiobutton
Terry Jan Reedyae410862014-08-03 23:02:53 -04001057 self.keysAreBuiltin.set(idleConf.GetOption(
1058 'main', 'Keys', 'default', type='bool', default=1))
Steven M. Gava41a85322001-10-29 08:05:34 +00001059 ##currently set keys
Terry Jan Reedyae410862014-08-03 23:02:53 -04001060 currentOption = idleConf.CurrentKeys()
Steven M. Gava7c017862001-10-29 11:19:46 +00001061 ##load available keyset option menus
Steven M. Gava052937f2002-02-11 02:20:53 +00001062 if self.keysAreBuiltin.get(): #default theme selected
Terry Jan Reedyae410862014-08-03 23:02:53 -04001063 itemList = idleConf.GetSectionList('default', 'keys')
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +00001064 itemList.sort()
Terry Jan Reedyae410862014-08-03 23:02:53 -04001065 self.optMenuKeysBuiltin.SetMenu(itemList, currentOption)
1066 itemList = idleConf.GetSectionList('user', 'keys')
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +00001067 itemList.sort()
Steven M. Gava41a85322001-10-29 08:05:34 +00001068 if not itemList:
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001069 self.radioKeysCustom.config(state=DISABLED)
1070 self.customKeys.set('- no custom keys -')
Steven M. Gava41a85322001-10-29 08:05:34 +00001071 else:
Terry Jan Reedyae410862014-08-03 23:02:53 -04001072 self.optMenuKeysCustom.SetMenu(itemList, itemList[0])
Steven M. Gavaa498af22002-02-01 01:33:36 +00001073 else: #user key set selected
Terry Jan Reedyae410862014-08-03 23:02:53 -04001074 itemList = idleConf.GetSectionList('user', 'keys')
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +00001075 itemList.sort()
Terry Jan Reedyae410862014-08-03 23:02:53 -04001076 self.optMenuKeysCustom.SetMenu(itemList, currentOption)
1077 itemList = idleConf.GetSectionList('default', 'keys')
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +00001078 itemList.sort()
Terry Jan Reedyae410862014-08-03 23:02:53 -04001079 self.optMenuKeysBuiltin.SetMenu(itemList, itemList[0])
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001080 self.SetKeysType()
Steven M. Gavafacfc092002-01-19 00:29:54 +00001081 ##load keyset element list
Terry Jan Reedyae410862014-08-03 23:02:53 -04001082 keySetName = idleConf.CurrentKeys()
Steven M. Gava052937f2002-02-11 02:20:53 +00001083 self.LoadKeysList(keySetName)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001084
Steven M. Gavafacfc092002-01-19 00:29:54 +00001085 def LoadGeneralCfg(self):
Steven M. Gava5f28e8f2002-01-21 06:38:21 +00001086 #startup state
Terry Jan Reedyae410862014-08-03 23:02:53 -04001087 self.startupEdit.set(idleConf.GetOption(
1088 'main', 'General', 'editor-on-startup', default=1, type='bool'))
Kurt B. Kaiser6c638b62003-05-26 06:23:10 +00001089 #autosave state
Terry Jan Reedyae410862014-08-03 23:02:53 -04001090 self.autoSave.set(idleConf.GetOption(
1091 'main', 'General', 'autosave', default=0, type='bool'))
Steven M. Gavafacfc092002-01-19 00:29:54 +00001092 #initial window size
Terry Jan Reedyae410862014-08-03 23:02:53 -04001093 self.winWidth.set(idleConf.GetOption(
1094 'main', 'EditorWindow', 'width', type='int'))
1095 self.winHeight.set(idleConf.GetOption(
1096 'main', 'EditorWindow', 'height', type='int'))
Raymond Hettinger4e49b832004-06-04 06:31:08 +00001097 #initial paragraph reformat size
Terry Jan Reedyae410862014-08-03 23:02:53 -04001098 self.paraWidth.set(idleConf.GetOption(
1099 'main', 'FormatParagraph', 'paragraph', type='int'))
Kurt B. Kaisera053f332003-05-10 00:49:56 +00001100 # default source encoding
Terry Jan Reedyae410862014-08-03 23:02:53 -04001101 self.encoding.set(idleConf.GetOption(
1102 'main', 'EditorWindow', 'encoding', default='none'))
Kurt B. Kaiser8e92bf72003-01-14 22:03:31 +00001103 # additional help sources
1104 self.userHelpList = idleConf.GetAllExtraHelpSourcesList()
Steven M. Gava085eb1b2002-02-05 04:52:32 +00001105 for helpItem in self.userHelpList:
Terry Jan Reedyae410862014-08-03 23:02:53 -04001106 self.listHelp.insert(END, helpItem[0])
Steven M. Gava085eb1b2002-02-05 04:52:32 +00001107 self.SetHelpListButtonStates()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001108
Steven M. Gava429a86a2001-10-23 10:42:12 +00001109 def LoadConfigs(self):
1110 """
1111 load configuration from default and user config files and populate
1112 the widgets on the config dialog pages.
1113 """
1114 ### fonts / tabs page
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001115 self.LoadFontCfg()
1116 self.LoadTabCfg()
Steven M. Gava429a86a2001-10-23 10:42:12 +00001117 ### highlighting page
Steven M. Gava9dd16b32001-11-03 14:54:25 +00001118 self.LoadThemeCfg()
Steven M. Gava429a86a2001-10-23 10:42:12 +00001119 ### keys page
Steven M. Gava9dd16b32001-11-03 14:54:25 +00001120 self.LoadKeyCfg()
Steven M. Gava429a86a2001-10-23 10:42:12 +00001121 ### general page
Steven M. Gavafacfc092002-01-19 00:29:54 +00001122 self.LoadGeneralCfg()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001123
Terry Jan Reedyae410862014-08-03 23:02:53 -04001124 def SaveNewKeySet(self, keySetName, keySet):
Steven M. Gava052937f2002-02-11 02:20:53 +00001125 """
1126 save a newly created core key set.
1127 keySetName - string, the name of the new key set
1128 keySet - dictionary containing the new key set
1129 """
1130 if not idleConf.userCfg['keys'].has_section(keySetName):
1131 idleConf.userCfg['keys'].add_section(keySetName)
Terry Jan Reedy110796f2014-07-27 04:07:18 -04001132 for event in keySet:
Terry Jan Reedyae410862014-08-03 23:02:53 -04001133 value = keySet[event]
1134 idleConf.userCfg['keys'].SetOption(keySetName, event, value)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001135
Terry Jan Reedyae410862014-08-03 23:02:53 -04001136 def SaveNewTheme(self, themeName, theme):
Steven M. Gava052937f2002-02-11 02:20:53 +00001137 """
1138 save a newly created theme.
1139 themeName - string, the name of the new theme
1140 theme - dictionary containing the new theme
1141 """
1142 if not idleConf.userCfg['highlight'].has_section(themeName):
1143 idleConf.userCfg['highlight'].add_section(themeName)
Terry Jan Reedy110796f2014-07-27 04:07:18 -04001144 for element in theme:
Terry Jan Reedyae410862014-08-03 23:02:53 -04001145 value = theme[element]
1146 idleConf.userCfg['highlight'].SetOption(themeName, element, value)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001147
Terry Jan Reedyae410862014-08-03 23:02:53 -04001148 def SetUserValue(self, configType, section, item, value):
1149 if idleConf.defaultCfg[configType].has_option(section, item):
1150 if idleConf.defaultCfg[configType].Get(section, item) == value:
Steven M. Gava2d7bb3f2002-01-29 08:35:29 +00001151 #the setting equals a default setting, remove it from user cfg
Terry Jan Reedyae410862014-08-03 23:02:53 -04001152 return idleConf.userCfg[configType].RemoveOption(section, item)
Steven M. Gava2d7bb3f2002-01-29 08:35:29 +00001153 #if we got here set the option
Terry Jan Reedyae410862014-08-03 23:02:53 -04001154 return idleConf.userCfg[configType].SetOption(section, item, value)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001155
Steven M. Gava052937f2002-02-11 02:20:53 +00001156 def SaveAllChangedConfigs(self):
Kurt B. Kaisere7a161e2003-01-10 20:13:57 +00001157 "Save configuration changes to the user config file."
Steven M. Gava0c5bc8c2002-03-27 02:25:44 +00001158 idleConf.userCfg['main'].Save()
Terry Jan Reedy110796f2014-07-27 04:07:18 -04001159 for configType in self.changedItems:
Kurt B. Kaisere7a161e2003-01-10 20:13:57 +00001160 cfgTypeHasChanges = False
Terry Jan Reedy110796f2014-07-27 04:07:18 -04001161 for section in self.changedItems[configType]:
Kurt B. Kaisere7a161e2003-01-10 20:13:57 +00001162 if section == 'HelpFiles':
1163 #this section gets completely replaced
1164 idleConf.userCfg['main'].remove_section('HelpFiles')
Kurt B. Kaiser8e92bf72003-01-14 22:03:31 +00001165 cfgTypeHasChanges = True
Terry Jan Reedy110796f2014-07-27 04:07:18 -04001166 for item in self.changedItems[configType][section]:
Kurt B. Kaisere7a161e2003-01-10 20:13:57 +00001167 value = self.changedItems[configType][section][item]
Terry Jan Reedyae410862014-08-03 23:02:53 -04001168 if self.SetUserValue(configType, section, item, value):
Kurt B. Kaisere7a161e2003-01-10 20:13:57 +00001169 cfgTypeHasChanges = True
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001170 if cfgTypeHasChanges:
1171 idleConf.userCfg[configType].Save()
Kurt B. Kaiser5acdf932004-11-16 21:28:36 +00001172 for configType in ['keys', 'highlight']:
1173 # save these even if unchanged!
1174 idleConf.userCfg[configType].Save()
Steven M. Gavaa498af22002-02-01 01:33:36 +00001175 self.ResetChangedItems() #clear the changed items dict
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001176
Kurt B. Kaiserb1754452005-11-18 22:05:48 +00001177 def DeactivateCurrentConfig(self):
1178 #Before a config is saved, some cleanup of current
1179 #config must be done - remove the previous keybindings
Terry Jan Reedyae410862014-08-03 23:02:53 -04001180 winInstances = self.parent.instance_dict
Kurt B. Kaiserb1754452005-11-18 22:05:48 +00001181 for instance in winInstances:
1182 instance.RemoveKeybindings()
1183
Steven M. Gava49745752002-02-18 01:43:11 +00001184 def ActivateConfigChanges(self):
Kurt B. Kaiseracdef852005-01-31 03:34:26 +00001185 "Dynamically apply configuration changes"
Terry Jan Reedy110796f2014-07-27 04:07:18 -04001186 winInstances = self.parent.instance_dict.keys()
Steven M. Gavab77d3432002-03-02 07:16:21 +00001187 for instance in winInstances:
1188 instance.ResetColorizer()
Steven M. Gavab1585412002-03-12 00:21:56 +00001189 instance.ResetFont()
Kurt B. Kaiseracdef852005-01-31 03:34:26 +00001190 instance.set_notabs_indentwidth()
Kurt B. Kaiserb1754452005-11-18 22:05:48 +00001191 instance.ApplyKeybindings()
Kurt B. Kaiser8e92bf72003-01-14 22:03:31 +00001192 instance.reset_help_menu_entries()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001193
Steven M. Gava5f28e8f2002-01-21 06:38:21 +00001194 def Cancel(self):
1195 self.destroy()
1196
1197 def Ok(self):
1198 self.Apply()
1199 self.destroy()
1200
1201 def Apply(self):
Kurt B. Kaiserb1754452005-11-18 22:05:48 +00001202 self.DeactivateCurrentConfig()
Steven M. Gava052937f2002-02-11 02:20:53 +00001203 self.SaveAllChangedConfigs()
Steven M. Gava49745752002-02-18 01:43:11 +00001204 self.ActivateConfigChanges()
Steven M. Gava5f28e8f2002-01-21 06:38:21 +00001205
1206 def Help(self):
Steven M. Gavac11ccf32001-09-24 09:43:17 +00001207 pass
1208
Terry Jan Reedy7a162072014-10-22 20:15:12 -04001209class VerticalScrolledFrame(Frame):
1210 """A pure Tkinter vertically scrollable frame.
1211
1212 * Use the 'interior' attribute to place widgets inside the scrollable frame
1213 * Construct and pack/place/grid normally
1214 * This frame only allows vertical scrolling
1215 """
1216 def __init__(self, parent, *args, **kw):
1217 Frame.__init__(self, parent, *args, **kw)
1218
1219 # create a canvas object and a vertical scrollbar for scrolling it
1220 vscrollbar = Scrollbar(self, orient=VERTICAL)
1221 vscrollbar.pack(fill=Y, side=RIGHT, expand=FALSE)
1222 canvas = Canvas(self, bd=0, highlightthickness=0,
1223 yscrollcommand=vscrollbar.set)
1224 canvas.pack(side=LEFT, fill=BOTH, expand=TRUE)
1225 vscrollbar.config(command=canvas.yview)
1226
1227 # reset the view
1228 canvas.xview_moveto(0)
1229 canvas.yview_moveto(0)
1230
1231 # create a frame inside the canvas which will be scrolled with it
1232 self.interior = interior = Frame(canvas)
1233 interior_id = canvas.create_window(0, 0, window=interior, anchor=NW)
1234
1235 # track changes to the canvas and frame width and sync them,
1236 # also updating the scrollbar
1237 def _configure_interior(event):
1238 # update the scrollbars to match the size of the inner frame
1239 size = (interior.winfo_reqwidth(), interior.winfo_reqheight())
1240 canvas.config(scrollregion="0 0 %s %s" % size)
1241 if interior.winfo_reqwidth() != canvas.winfo_width():
1242 # update the canvas's width to fit the inner frame
1243 canvas.config(width=interior.winfo_reqwidth())
1244 interior.bind('<Configure>', _configure_interior)
1245
1246 def _configure_canvas(event):
1247 if interior.winfo_reqwidth() != canvas.winfo_width():
1248 # update the inner frame's width to fill the canvas
1249 canvas.itemconfigure(interior_id, width=canvas.winfo_width())
1250 canvas.bind('<Configure>', _configure_canvas)
1251
1252 return
1253
1254def is_int(s):
1255 "Return 's is blank or represents an int'"
1256 if not s:
1257 return True
1258 try:
1259 int(s)
1260 return True
1261 except ValueError:
1262 return False
1263
1264# TODO:
1265# * Revert to default(s)? Per option or per extension?
1266# * List options in their original order (possible??)
1267class ConfigExtensionsDialog(Toplevel):
1268 """A dialog for configuring IDLE extensions.
1269
1270 This dialog is generic - it works for any and all IDLE extensions.
1271
1272 IDLE extensions save their configuration options using idleConf.
1273 ConfigExtensionsDialog reads the current configuration using idleConf,
1274 supplies a GUI interface to change the configuration values, and saves the
1275 changes using idleConf.
1276
1277 Not all changes take effect immediately - some may require restarting IDLE.
1278 This depends on each extension's implementation.
1279
1280 All values are treated as text, and it is up to the user to supply
1281 reasonable values. The only exception to this are the 'enable*' options,
1282 which are boolean, and can be toggled with an True/False button.
1283 """
1284 def __init__(self, parent, title=None, _htest=False):
1285 Toplevel.__init__(self, parent)
1286 self.wm_withdraw()
1287
1288 self.configure(borderwidth=5)
1289 self.geometry(
1290 "+%d+%d" % (parent.winfo_rootx() + 20,
1291 parent.winfo_rooty() + (30 if not _htest else 150)))
1292 self.wm_title(title or 'IDLE Extensions Configuration')
1293
1294 self.defaultCfg = idleConf.defaultCfg['extensions']
1295 self.userCfg = idleConf.userCfg['extensions']
1296 self.is_int = self.register(is_int)
1297 self.load_extensions()
1298 self.create_widgets()
1299
1300 self.resizable(height=FALSE, width=FALSE) # don't allow resizing yet
1301 self.transient(parent)
1302 self.protocol("WM_DELETE_WINDOW", self.Cancel)
1303 self.tabbed_page_set.focus_set()
1304 # wait for window to be generated
1305 self.update()
1306 # set current width as the minimum width
1307 self.wm_minsize(self.winfo_width(), 1)
1308 # now allow resizing
1309 self.resizable(height=TRUE, width=TRUE)
1310
1311 self.wm_deiconify()
1312 if not _htest:
1313 self.grab_set()
1314 self.wait_window()
1315
1316 def load_extensions(self):
1317 "Fill self.extensions with data from the default and user configs."
1318 self.extensions = {}
1319 for ext_name in idleConf.GetExtensions(active_only=False):
1320 self.extensions[ext_name] = []
1321
1322 for ext_name in self.extensions:
1323 opt_list = sorted(self.defaultCfg.GetOptionList(ext_name))
1324
1325 # bring 'enable' options to the beginning of the list
1326 enables = [opt_name for opt_name in opt_list
1327 if opt_name.startswith('enable')]
1328 for opt_name in enables:
1329 opt_list.remove(opt_name)
1330 opt_list = enables + opt_list
1331
1332 for opt_name in opt_list:
1333 def_str = self.defaultCfg.Get(
1334 ext_name, opt_name, raw=True)
1335 try:
1336 def_obj = {'True':True, 'False':False}[def_str]
1337 opt_type = 'bool'
1338 except KeyError:
1339 try:
1340 def_obj = int(def_str)
1341 opt_type = 'int'
1342 except ValueError:
1343 def_obj = def_str
1344 opt_type = None
1345 try:
1346 value = self.userCfg.Get(
1347 ext_name, opt_name, type=opt_type, raw=True,
1348 default=def_obj)
1349 except ValueError: # Need this until .Get fixed
1350 value = def_obj # bad values overwritten by entry
1351 var = StringVar(self)
1352 var.set(str(value))
1353
1354 self.extensions[ext_name].append({'name': opt_name,
1355 'type': opt_type,
1356 'default': def_str,
1357 'value': value,
1358 'var': var,
1359 })
1360
1361 def create_widgets(self):
1362 """Create the dialog's widgets."""
1363 self.rowconfigure(0, weight=1)
1364 self.rowconfigure(1, weight=0)
1365 self.columnconfigure(0, weight=1)
1366
1367 # create the tabbed pages
1368 self.tabbed_page_set = TabbedPageSet(
1369 self, page_names=self.extensions.keys(),
1370 n_rows=None, max_tabs_per_row=5,
1371 page_class=TabbedPageSet.PageRemove)
1372 self.tabbed_page_set.grid(row=0, column=0, sticky=NSEW)
1373 for ext_name in self.extensions:
1374 self.create_tab_page(ext_name)
1375
1376 self.create_action_buttons().grid(row=1)
1377
1378 create_action_buttons = ConfigDialog.create_action_buttons.im_func
1379
1380 def create_tab_page(self, ext_name):
1381 """Create the page for an extension."""
1382
1383 page = LabelFrame(self.tabbed_page_set.pages[ext_name].frame,
1384 border=2, padx=2, relief=GROOVE,
1385 text=' %s ' % ext_name)
1386 page.pack(fill=BOTH, expand=True, padx=12, pady=2)
1387
1388 # create the scrollable frame which will contain the entries
1389 scrolled_frame = VerticalScrolledFrame(page, pady=2, height=250)
1390 scrolled_frame.pack(side=BOTTOM, fill=BOTH, expand=TRUE)
1391 entry_area = scrolled_frame.interior
1392 entry_area.columnconfigure(0, weight=0)
1393 entry_area.columnconfigure(1, weight=1)
1394
1395 # create an entry for each configuration option
1396 for row, opt in enumerate(self.extensions[ext_name]):
1397 # create a row with a label and entry/checkbutton
1398 label = Label(entry_area, text=opt['name'])
1399 label.grid(row=row, column=0, sticky=NW)
1400 var = opt['var']
1401 if opt['type'] == 'bool':
1402 Checkbutton(entry_area, textvariable=var, variable=var,
1403 onvalue='True', offvalue='False',
1404 indicatoron=FALSE, selectcolor='', width=8
1405 ).grid(row=row, column=1, sticky=W, padx=7)
1406 elif opt['type'] == 'int':
1407 Entry(entry_area, textvariable=var, validate='key',
1408 validatecommand=(self.is_int, '%P')
1409 ).grid(row=row, column=1, sticky=NSEW, padx=7)
1410
1411 else:
1412 Entry(entry_area, textvariable=var
1413 ).grid(row=row, column=1, sticky=NSEW, padx=7)
1414 return
1415
1416
1417 Ok = ConfigDialog.Ok.im_func
1418
1419 def Apply(self):
1420 self.save_all_changed_configs()
1421 pass
1422
1423 Cancel = ConfigDialog.Cancel.im_func
1424
1425 def Help(self):
1426 pass
1427
1428 def set_user_value(self, section, opt):
1429 name = opt['name']
1430 default = opt['default']
1431 value = opt['var'].get().strip() or default
1432 opt['var'].set(value)
1433 # if self.defaultCfg.has_section(section):
1434 # Currently, always true; if not, indent to return
1435 if (value == default):
1436 return self.userCfg.RemoveOption(section, name)
1437 # set the option
1438 return self.userCfg.SetOption(section, name, value)
1439
1440 def save_all_changed_configs(self):
1441 """Save configuration changes to the user config file."""
1442 has_changes = False
1443 for ext_name in self.extensions:
1444 options = self.extensions[ext_name]
1445 for opt in options:
1446 if self.set_user_value(ext_name, opt):
1447 has_changes = True
1448 if has_changes:
1449 self.userCfg.Save()
1450
1451
Steven M. Gava44d3d1a2001-07-31 06:59:02 +00001452if __name__ == '__main__':
Terry Jan Reedyaf0dce92014-07-14 23:07:21 -04001453 import unittest
1454 unittest.main('idlelib.idle_test.test_configdialog',
1455 verbosity=2, exit=False)
Terry Jan Reedy76916e82014-05-29 01:46:16 -04001456 from idlelib.idle_test.htest import run
Terry Jan Reedy7a162072014-10-22 20:15:12 -04001457 run(ConfigDialog, ConfigExtensionsDialog)