blob: 5f5bd36f8a1d9dec80058b72a607ff032e9de1b2 [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 Brandl14fc4272008-05-17 18:39:55 +000012from tkinter import *
13import tkinter.messagebox as tkMessageBox
14import tkinter.colorchooser as tkColorChooser
15import tkinter.font as tkFont
Steven M. Gava44d3d1a2001-07-31 06:59:02 +000016
Kurt B. Kaiser2d7f6a02007-08-22 23:01:33 +000017from idlelib.configHandler import idleConf
18from idlelib.dynOptionMenuWidget import DynOptionMenu
Kurt B. Kaiser2d7f6a02007-08-22 23:01:33 +000019from idlelib.keybindingDialog import GetKeysDialog
20from idlelib.configSectionNameDialog import GetCfgSectionNameDialog
21from idlelib.configHelpSourceEdit import GetHelpSourceDialog
Terry Jan Reedya9421fb2014-10-22 20:15:18 -040022from idlelib.tabbedpages import TabbedPageSet
Terry Jan Reedyd0cadba2015-10-11 22:07:31 -040023from idlelib.textView import view_text
Ronald Oussoren9e350042009-02-12 16:02:11 +000024from idlelib import macosxSupport
Terry Jan Reedyd0cadba2015-10-11 22:07:31 -040025
Steven M. Gava44d3d1a2001-07-31 06:59:02 +000026class ConfigDialog(Toplevel):
Kurt B. Kaiseracdef852005-01-31 03:34:26 +000027
Terry Jan Reedycd567362014-10-17 01:31:35 -040028 def __init__(self, parent, title='', _htest=False, _utest=False):
Terry Jan Reedy2e8234a2014-05-29 01:46:26 -040029 """
30 _htest - bool, change box location when running htest
Terry Jan Reedycfa89502014-07-14 23:07:32 -040031 _utest - bool, don't wait_window when running unittest
Terry Jan Reedy2e8234a2014-05-29 01:46:26 -040032 """
Steven M. Gavad721c482001-07-31 10:46:53 +000033 Toplevel.__init__(self, parent)
Terry Jan Reedy22405332014-07-30 19:24:32 -040034 self.parent = parent
Terry Jan Reedy4036d872014-08-03 23:02:58 -040035 if _htest:
36 parent.instance_dict = {}
Guido van Rossum8ce8a782007-11-01 19:42:39 +000037 self.wm_withdraw()
38
Steven M. Gavad721c482001-07-31 10:46:53 +000039 self.configure(borderwidth=5)
Terry Jan Reedycd567362014-10-17 01:31:35 -040040 self.title(title or 'IDLE Preferences')
Terry Jan Reedy4036d872014-08-03 23:02:58 -040041 self.geometry(
42 "+%d+%d" % (parent.winfo_rootx() + 20,
43 parent.winfo_rooty() + (30 if not _htest else 150)))
Georg Brandl7eb4b7d2005-07-22 21:49:32 +000044 #Theme Elements. Each theme element key is its display name.
Steven M. Gava9dd16b32001-11-03 14:54:25 +000045 #The first value of the tuple is the sample area tag name.
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +000046 #The second value is the display name list sort index.
Terry Jan Reedy4036d872014-08-03 23:02:58 -040047 self.themeElements={
Terry Jan Reedya8aa4d52015-10-02 22:12:17 -040048 'Normal Text': ('normal', '00'),
49 'Python Keywords': ('keyword', '01'),
50 'Python Definitions': ('definition', '02'),
51 'Python Builtins': ('builtin', '03'),
52 'Python Comments': ('comment', '04'),
53 'Python Strings': ('string', '05'),
54 'Selected Text': ('hilite', '06'),
55 'Found Text': ('hit', '07'),
56 'Cursor': ('cursor', '08'),
57 'Editor Breakpoint': ('break', '09'),
58 'Shell Normal Text': ('console', '10'),
59 'Shell Error Text': ('error', '11'),
60 'Shell Stdout Text': ('stdout', '12'),
61 'Shell Stderr Text': ('stderr', '13'),
Kurt B. Kaiser73360a32004-03-08 18:15:31 +000062 }
Steven M. Gavaa498af22002-02-01 01:33:36 +000063 self.ResetChangedItems() #load initial values in changed items dict
Steven M. Gavad721c482001-07-31 10:46:53 +000064 self.CreateWidgets()
Terry Jan Reedy4036d872014-08-03 23:02:58 -040065 self.resizable(height=FALSE, width=FALSE)
Steven M. Gavad721c482001-07-31 10:46:53 +000066 self.transient(parent)
67 self.grab_set()
68 self.protocol("WM_DELETE_WINDOW", self.Cancel)
Steven M. Gava2d4e03b2001-12-05 07:54:07 +000069 self.tabPages.focus_set()
Steven M. Gavad721c482001-07-31 10:46:53 +000070 #key bindings for this dialog
Terry Jan Reedy4036d872014-08-03 23:02:58 -040071 #self.bind('<Escape>', self.Cancel) #dismiss dialog, no save
72 #self.bind('<Alt-a>', self.Apply) #apply changes, save
73 #self.bind('<F1>', self.Help) #context help
Steven M. Gava429a86af2001-10-23 10:42:12 +000074 self.LoadConfigs()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +000075 self.AttachVarCallbacks() #avoid callbacks during LoadConfigs
Guido van Rossum8ce8a782007-11-01 19:42:39 +000076
Terry Jan Reedycfa89502014-07-14 23:07:32 -040077 if not _utest:
78 self.wm_deiconify()
79 self.wait_window()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +000080
Steven M. Gavad721c482001-07-31 10:46:53 +000081 def CreateWidgets(self):
Guido van Rossum8ce8a782007-11-01 19:42:39 +000082 self.tabPages = TabbedPageSet(self,
Terry Jan Reedy93f35422015-10-13 22:03:51 -040083 page_names=['Fonts/Tabs', 'Highlighting', 'Keys', 'General',
84 'Extensions'])
Terry Jan Reedy92cb0a32014-10-08 20:29:13 -040085 self.tabPages.pack(side=TOP, expand=TRUE, fill=BOTH)
86 self.CreatePageFontTab()
87 self.CreatePageHighlight()
88 self.CreatePageKeys()
89 self.CreatePageGeneral()
Terry Jan Reedy93f35422015-10-13 22:03:51 -040090 self.CreatePageExtensions()
Terry Jan Reedy92cb0a32014-10-08 20:29:13 -040091 self.create_action_buttons().pack(side=BOTTOM)
Terry Jan Reedyd0cadba2015-10-11 22:07:31 -040092
Terry Jan Reedy92cb0a32014-10-08 20:29:13 -040093 def create_action_buttons(self):
Ned Deilyb7601672014-03-27 20:49:14 -070094 if macosxSupport.isAquaTk():
Terry Jan Reedye3416e62014-07-26 19:40:16 -040095 # Changing the default padding on OSX results in unreadable
96 # text in the buttons
Terry Jan Reedy4036d872014-08-03 23:02:58 -040097 paddingArgs = {}
Ronald Oussoren9e350042009-02-12 16:02:11 +000098 else:
Terry Jan Reedy4036d872014-08-03 23:02:58 -040099 paddingArgs = {'padx':6, 'pady':3}
Terry Jan Reedya9421fb2014-10-22 20:15:18 -0400100 outer = Frame(self, pady=2)
101 buttons = Frame(outer, pady=2)
Terry Jan Reedyd0cadba2015-10-11 22:07:31 -0400102 for txt, cmd in (
103 ('Ok', self.Ok),
104 ('Apply', self.Apply),
105 ('Cancel', self.Cancel),
106 ('Help', self.Help)):
107 Button(buttons, text=txt, command=cmd, takefocus=FALSE,
108 **paddingArgs).pack(side=LEFT, padx=5)
Terry Jan Reedya9421fb2014-10-22 20:15:18 -0400109 # add space above buttons
110 Frame(outer, height=2, borderwidth=0).pack(side=TOP)
111 buttons.pack(side=BOTTOM)
112 return outer
Terry Jan Reedyd0cadba2015-10-11 22:07:31 -0400113
Steven M. Gava60fc7072001-08-04 13:58:22 +0000114 def CreatePageFontTab(self):
Terry Jan Reedy22405332014-07-30 19:24:32 -0400115 parent = self.parent
116 self.fontSize = StringVar(parent)
117 self.fontBold = BooleanVar(parent)
118 self.fontName = StringVar(parent)
119 self.spaceNum = IntVar(parent)
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400120 self.editFont = tkFont.Font(parent, ('courier', 10, 'normal'))
Terry Jan Reedy22405332014-07-30 19:24:32 -0400121
Steven M. Gavaf213ccb2001-08-05 08:00:28 +0000122 ##widget creation
123 #body frame
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400124 frame = self.tabPages.pages['Fonts/Tabs'].frame
Steven M. Gavaf213ccb2001-08-05 08:00:28 +0000125 #body section frames
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400126 frameFont = LabelFrame(
127 frame, borderwidth=2, relief=GROOVE, text=' Base Editor Font ')
128 frameIndent = LabelFrame(
129 frame, borderwidth=2, relief=GROOVE, text=' Indentation Width ')
Steven M. Gavaf213ccb2001-08-05 08:00:28 +0000130 #frameFont
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400131 frameFontName = Frame(frameFont)
132 frameFontParam = Frame(frameFont)
133 labelFontNameTitle = Label(
134 frameFontName, justify=LEFT, text='Font Face :')
135 self.listFontName = Listbox(
136 frameFontName, height=5, takefocus=FALSE, exportselection=FALSE)
137 self.listFontName.bind(
138 '<ButtonRelease-1>', self.OnListFontButtonRelease)
139 scrollFont = Scrollbar(frameFontName)
Steven M. Gavac01e30f2001-08-11 15:48:13 +0000140 scrollFont.config(command=self.listFontName.yview)
141 self.listFontName.config(yscrollcommand=scrollFont.set)
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400142 labelFontSizeTitle = Label(frameFontParam, text='Size :')
143 self.optMenuFontSize = DynOptionMenu(
144 frameFontParam, self.fontSize, None, command=self.SetFontSample)
145 checkFontBold = Checkbutton(
146 frameFontParam, variable=self.fontBold, onvalue=1,
147 offvalue=0, text='Bold', command=self.SetFontSample)
148 frameFontSample = Frame(frameFont, relief=SOLID, borderwidth=1)
149 self.labelFontSample = Label(
150 frameFontSample, justify=LEFT, font=self.editFont,
151 text='AaBbCcDdEe\nFfGgHhIiJjK\n1234567890\n#:+=(){}[]')
Steven M. Gavaf213ccb2001-08-05 08:00:28 +0000152 #frameIndent
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400153 frameIndentSize = Frame(frameIndent)
154 labelSpaceNumTitle = Label(
155 frameIndentSize, justify=LEFT,
156 text='Python Standard: 4 Spaces!')
157 self.scaleSpaceNum = Scale(
158 frameIndentSize, variable=self.spaceNum,
159 orient='horizontal', tickinterval=2, from_=2, to=16)
Terry Jan Reedy22405332014-07-30 19:24:32 -0400160
Steven M. Gavaf213ccb2001-08-05 08:00:28 +0000161 #widget packing
162 #body
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400163 frameFont.pack(side=LEFT, padx=5, pady=5, expand=TRUE, fill=BOTH)
164 frameIndent.pack(side=LEFT, padx=5, pady=5, fill=Y)
Steven M. Gavaf213ccb2001-08-05 08:00:28 +0000165 #frameFont
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400166 frameFontName.pack(side=TOP, padx=5, pady=5, fill=X)
167 frameFontParam.pack(side=TOP, padx=5, pady=5, fill=X)
168 labelFontNameTitle.pack(side=TOP, anchor=W)
169 self.listFontName.pack(side=LEFT, expand=TRUE, fill=X)
170 scrollFont.pack(side=LEFT, fill=Y)
171 labelFontSizeTitle.pack(side=LEFT, anchor=W)
172 self.optMenuFontSize.pack(side=LEFT, anchor=W)
173 checkFontBold.pack(side=LEFT, anchor=W, padx=20)
174 frameFontSample.pack(side=TOP, padx=5, pady=5, expand=TRUE, fill=BOTH)
175 self.labelFontSample.pack(expand=TRUE, fill=BOTH)
Steven M. Gavaf213ccb2001-08-05 08:00:28 +0000176 #frameIndent
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400177 frameIndentSize.pack(side=TOP, fill=X)
178 labelSpaceNumTitle.pack(side=TOP, anchor=W, padx=5)
179 self.scaleSpaceNum.pack(side=TOP, padx=5, fill=X)
Steven M. Gava952d0a52001-08-03 04:43:44 +0000180 return frame
181
182 def CreatePageHighlight(self):
Terry Jan Reedy22405332014-07-30 19:24:32 -0400183 parent = self.parent
184 self.builtinTheme = StringVar(parent)
185 self.customTheme = StringVar(parent)
186 self.fgHilite = BooleanVar(parent)
187 self.colour = StringVar(parent)
188 self.fontName = StringVar(parent)
189 self.themeIsBuiltin = BooleanVar(parent)
190 self.highlightTarget = StringVar(parent)
191
Steven M. Gava952d0a52001-08-03 04:43:44 +0000192 ##widget creation
193 #body frame
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400194 frame = self.tabPages.pages['Highlighting'].frame
Steven M. Gava952d0a52001-08-03 04:43:44 +0000195 #body section frames
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400196 frameCustom = LabelFrame(frame, borderwidth=2, relief=GROOVE,
197 text=' Custom Highlighting ')
198 frameTheme = LabelFrame(frame, borderwidth=2, relief=GROOVE,
199 text=' Highlighting Theme ')
Steven M. Gava952d0a52001-08-03 04:43:44 +0000200 #frameCustom
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400201 self.textHighlightSample=Text(
202 frameCustom, relief=SOLID, borderwidth=1,
203 font=('courier', 12, ''), cursor='hand2', width=21, height=11,
204 takefocus=FALSE, highlightthickness=0, wrap=NONE)
Steven M. Gavae16d94b2001-11-03 05:07:28 +0000205 text=self.textHighlightSample
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400206 text.bind('<Double-Button-1>', lambda e: 'break')
207 text.bind('<B1-Motion>', lambda e: 'break')
208 textAndTags=(
209 ('#you can click here', 'comment'), ('\n', 'normal'),
210 ('#to choose items', 'comment'), ('\n', 'normal'),
211 ('def', 'keyword'), (' ', 'normal'),
212 ('func', 'definition'), ('(param):\n ', 'normal'),
213 ('"""string"""', 'string'), ('\n var0 = ', 'normal'),
214 ("'string'", 'string'), ('\n var1 = ', 'normal'),
215 ("'selected'", 'hilite'), ('\n var2 = ', 'normal'),
216 ("'found'", 'hit'), ('\n var3 = ', 'normal'),
217 ('list', 'builtin'), ('(', 'normal'),
Terry Jan Reedya8aa4d52015-10-02 22:12:17 -0400218 ('None', 'keyword'), (')\n', 'normal'),
219 (' breakpoint("line")', 'break'), ('\n\n', 'normal'),
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400220 (' error ', 'error'), (' ', 'normal'),
221 ('cursor |', 'cursor'), ('\n ', 'normal'),
222 ('shell', 'console'), (' ', 'normal'),
223 ('stdout', 'stdout'), (' ', 'normal'),
224 ('stderr', 'stderr'), ('\n', 'normal'))
Steven M. Gava9dd16b32001-11-03 14:54:25 +0000225 for txTa in textAndTags:
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400226 text.insert(END, txTa[0], txTa[1])
Kurt B. Kaisere0712772007-08-23 05:25:55 +0000227 for element in self.themeElements:
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400228 def tem(event, elem=element):
229 event.widget.winfo_toplevel().highlightTarget.set(elem)
230 text.tag_bind(
231 self.themeElements[element][0], '<ButtonPress-1>', tem)
Steven M. Gavae16d94b2001-11-03 05:07:28 +0000232 text.config(state=DISABLED)
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400233 self.frameColourSet = Frame(frameCustom, relief=SOLID, borderwidth=1)
234 frameFgBg = Frame(frameCustom)
235 buttonSetColour = Button(
236 self.frameColourSet, text='Choose Colour for :',
237 command=self.GetColour, highlightthickness=0)
238 self.optMenuHighlightTarget = DynOptionMenu(
239 self.frameColourSet, self.highlightTarget, None,
240 highlightthickness=0) #, command=self.SetHighlightTargetBinding
241 self.radioFg = Radiobutton(
242 frameFgBg, variable=self.fgHilite, value=1,
243 text='Foreground', command=self.SetColourSampleBinding)
244 self.radioBg=Radiobutton(
245 frameFgBg, variable=self.fgHilite, value=0,
246 text='Background', command=self.SetColourSampleBinding)
Steven M. Gava7c017862001-10-29 11:19:46 +0000247 self.fgHilite.set(1)
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400248 buttonSaveCustomTheme = Button(
249 frameCustom, text='Save as New Custom Theme',
250 command=self.SaveAsNewTheme)
Steven M. Gava952d0a52001-08-03 04:43:44 +0000251 #frameTheme
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400252 labelTypeTitle = Label(frameTheme, text='Select : ')
253 self.radioThemeBuiltin = Radiobutton(
254 frameTheme, variable=self.themeIsBuiltin, value=1,
255 command=self.SetThemeType, text='a Built-in Theme')
256 self.radioThemeCustom = Radiobutton(
257 frameTheme, variable=self.themeIsBuiltin, value=0,
258 command=self.SetThemeType, text='a Custom Theme')
259 self.optMenuThemeBuiltin = DynOptionMenu(
260 frameTheme, self.builtinTheme, None, command=None)
261 self.optMenuThemeCustom=DynOptionMenu(
262 frameTheme, self.customTheme, None, command=None)
263 self.buttonDeleteCustomTheme=Button(
264 frameTheme, text='Delete Custom Theme',
Steven M. Gava49745752002-02-18 01:43:11 +0000265 command=self.DeleteCustomTheme)
Terry Jan Reedyd0c0f002015-11-12 15:02:57 -0500266 self.new_custom_theme = Label(frameTheme, bd=2)
Terry Jan Reedy22405332014-07-30 19:24:32 -0400267
Steven M. Gava952d0a52001-08-03 04:43:44 +0000268 ##widget packing
269 #body
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400270 frameCustom.pack(side=LEFT, padx=5, pady=5, expand=TRUE, fill=BOTH)
271 frameTheme.pack(side=LEFT, padx=5, pady=5, fill=Y)
Steven M. Gava952d0a52001-08-03 04:43:44 +0000272 #frameCustom
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400273 self.frameColourSet.pack(side=TOP, padx=5, pady=5, expand=TRUE, fill=X)
274 frameFgBg.pack(side=TOP, padx=5, pady=0)
275 self.textHighlightSample.pack(
276 side=TOP, padx=5, pady=5, expand=TRUE, fill=BOTH)
277 buttonSetColour.pack(side=TOP, expand=TRUE, fill=X, padx=8, pady=4)
278 self.optMenuHighlightTarget.pack(
279 side=TOP, expand=TRUE, fill=X, padx=8, pady=3)
280 self.radioFg.pack(side=LEFT, anchor=E)
281 self.radioBg.pack(side=RIGHT, anchor=W)
282 buttonSaveCustomTheme.pack(side=BOTTOM, fill=X, padx=5, pady=5)
Steven M. Gava952d0a52001-08-03 04:43:44 +0000283 #frameTheme
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400284 labelTypeTitle.pack(side=TOP, anchor=W, padx=5, pady=5)
285 self.radioThemeBuiltin.pack(side=TOP, anchor=W, padx=5)
286 self.radioThemeCustom.pack(side=TOP, anchor=W, padx=5, pady=2)
287 self.optMenuThemeBuiltin.pack(side=TOP, fill=X, padx=5, pady=5)
288 self.optMenuThemeCustom.pack(side=TOP, fill=X, anchor=W, padx=5, pady=5)
289 self.buttonDeleteCustomTheme.pack(side=TOP, fill=X, padx=5, pady=5)
Terry Jan Reedyd0c0f002015-11-12 15:02:57 -0500290 self.new_custom_theme.pack(side=TOP, fill=X, pady=5)
Steven M. Gava952d0a52001-08-03 04:43:44 +0000291 return frame
292
293 def CreatePageKeys(self):
Terry Jan Reedy22405332014-07-30 19:24:32 -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 Reedy4036d872014-08-03 23:02:58 -0400303 frame = self.tabPages.pages['Keys'].frame
Steven M. Gava60fc7072001-08-04 13:58:22 +0000304 #body section frames
Terry Jan Reedy4036d872014-08-03 23:02:58 -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 Reedy4036d872014-08-03 23:02:58 -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 Reedy4036d872014-08-03 23:02:58 -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
Christian Heimes9a371592007-12-28 14:08:13 +0000326 frames = [Frame(frameKeySets, padx=2, pady=2, borderwidth=0)
327 for i in range(2)]
Terry Jan Reedy4036d872014-08-03 23:02:58 -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 Reedy4036d872014-08-03 23:02:58 -0400341 buttonSaveCustomKeys = Button(
342 frames[1], text='Save as New Custom Key Set',
343 command=self.SaveAsNewKeySet)
Terry Jan Reedy22405332014-07-30 19:24:32 -0400344
Steven M. Gava60fc7072001-08-04 13:58:22 +0000345 ##widget packing
346 #body
Terry Jan Reedy4036d872014-08-03 23:02:58 -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 Reedy4036d872014-08-03 23:02:58 -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 Reedy4036d872014-08-03 23:02:58 -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
Christian Heimes9a371592007-12-28 14:08:13 +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 Reedy4036d872014-08-03 23:02:58 -0400364 self.buttonDeleteCustomKeys.pack(side=LEFT, fill=X, expand=True, padx=2)
365 buttonSaveCustomKeys.pack(side=LEFT, fill=X, expand=True, padx=2)
Christian Heimes9a371592007-12-28 14:08:13 +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 Reedy22405332014-07-30 19:24:32 -0400371 parent = self.parent
372 self.winWidth = StringVar(parent)
373 self.winHeight = StringVar(parent)
Terry Jan Reedy22405332014-07-30 19:24:32 -0400374 self.startupEdit = IntVar(parent)
375 self.autoSave = IntVar(parent)
376 self.encoding = StringVar(parent)
377 self.userHelpBrowser = BooleanVar(parent)
378 self.helpBrowser = StringVar(parent)
379
Steven M. Gava230e5782001-08-07 03:28:25 +0000380 #widget creation
381 #body
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400382 frame = self.tabPages.pages['General'].frame
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000383 #body section frames
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400384 frameRun = LabelFrame(frame, borderwidth=2, relief=GROOVE,
385 text=' Startup Preferences ')
386 frameSave = LabelFrame(frame, borderwidth=2, relief=GROOVE,
387 text=' Autosave Preferences ')
388 frameWinSize = Frame(frame, borderwidth=2, relief=GROOVE)
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400389 frameHelp = LabelFrame(frame, borderwidth=2, relief=GROOVE,
390 text=' Additional Help Sources ')
Steven M. Gava230e5782001-08-07 03:28:25 +0000391 #frameRun
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400392 labelRunChoiceTitle = Label(frameRun, text='At Startup')
393 radioStartupEdit = Radiobutton(
394 frameRun, variable=self.startupEdit, value=1,
395 command=self.SetKeysType, text="Open Edit Window")
396 radioStartupShell = Radiobutton(
397 frameRun, variable=self.startupEdit, value=0,
398 command=self.SetKeysType, text='Open Shell Window')
Kurt B. Kaiser6c638b62003-05-26 06:23:10 +0000399 #frameSave
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400400 labelRunSaveTitle = Label(frameSave, text='At Start of Run (F5) ')
401 radioSaveAsk = Radiobutton(
402 frameSave, variable=self.autoSave, value=0,
403 command=self.SetKeysType, text="Prompt to Save")
404 radioSaveAuto = Radiobutton(
405 frameSave, variable=self.autoSave, value=1,
406 command=self.SetKeysType, text='No Prompt')
Steven M. Gava230e5782001-08-07 03:28:25 +0000407 #frameWinSize
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400408 labelWinSizeTitle = Label(
409 frameWinSize, text='Initial Window Size (in characters)')
410 labelWinWidthTitle = Label(frameWinSize, text='Width')
411 entryWinWidth = Entry(
412 frameWinSize, textvariable=self.winWidth, width=3)
413 labelWinHeightTitle = Label(frameWinSize, text='Height')
414 entryWinHeight = Entry(
415 frameWinSize, textvariable=self.winHeight, width=3)
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000416 #frameHelp
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400417 frameHelpList = Frame(frameHelp)
418 frameHelpListButtons = Frame(frameHelpList)
419 scrollHelpList = Scrollbar(frameHelpList)
420 self.listHelp = Listbox(
421 frameHelpList, height=5, takefocus=FALSE,
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000422 exportselection=FALSE)
423 scrollHelpList.config(command=self.listHelp.yview)
424 self.listHelp.config(yscrollcommand=scrollHelpList.set)
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400425 self.listHelp.bind('<ButtonRelease-1>', self.HelpSourceSelected)
426 self.buttonHelpListEdit = Button(
427 frameHelpListButtons, text='Edit', state=DISABLED,
428 width=8, command=self.HelpListItemEdit)
429 self.buttonHelpListAdd = Button(
430 frameHelpListButtons, text='Add',
431 width=8, command=self.HelpListItemAdd)
432 self.buttonHelpListRemove = Button(
433 frameHelpListButtons, text='Remove', state=DISABLED,
434 width=8, command=self.HelpListItemRemove)
Terry Jan Reedy22405332014-07-30 19:24:32 -0400435
Steven M. Gava230e5782001-08-07 03:28:25 +0000436 #widget packing
437 #body
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400438 frameRun.pack(side=TOP, padx=5, pady=5, fill=X)
439 frameSave.pack(side=TOP, padx=5, pady=5, fill=X)
440 frameWinSize.pack(side=TOP, padx=5, pady=5, fill=X)
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400441 frameHelp.pack(side=TOP, padx=5, pady=5, expand=TRUE, fill=BOTH)
Steven M. Gava230e5782001-08-07 03:28:25 +0000442 #frameRun
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400443 labelRunChoiceTitle.pack(side=LEFT, anchor=W, padx=5, pady=5)
444 radioStartupShell.pack(side=RIGHT, anchor=W, padx=5, pady=5)
445 radioStartupEdit.pack(side=RIGHT, anchor=W, padx=5, pady=5)
Kurt B. Kaiser6c638b62003-05-26 06:23:10 +0000446 #frameSave
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400447 labelRunSaveTitle.pack(side=LEFT, anchor=W, padx=5, pady=5)
448 radioSaveAuto.pack(side=RIGHT, anchor=W, padx=5, pady=5)
449 radioSaveAsk.pack(side=RIGHT, anchor=W, padx=5, pady=5)
Steven M. Gava230e5782001-08-07 03:28:25 +0000450 #frameWinSize
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400451 labelWinSizeTitle.pack(side=LEFT, anchor=W, padx=5, pady=5)
452 entryWinHeight.pack(side=RIGHT, anchor=E, padx=10, pady=5)
453 labelWinHeightTitle.pack(side=RIGHT, anchor=E, pady=5)
454 entryWinWidth.pack(side=RIGHT, anchor=E, padx=10, pady=5)
455 labelWinWidthTitle.pack(side=RIGHT, anchor=E, pady=5)
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000456 #frameHelp
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400457 frameHelpListButtons.pack(side=RIGHT, padx=5, pady=5, fill=Y)
458 frameHelpList.pack(side=TOP, padx=5, pady=5, expand=TRUE, fill=BOTH)
459 scrollHelpList.pack(side=RIGHT, anchor=W, fill=Y)
460 self.listHelp.pack(side=LEFT, anchor=E, expand=TRUE, fill=BOTH)
461 self.buttonHelpListEdit.pack(side=TOP, anchor=W, pady=5)
462 self.buttonHelpListAdd.pack(side=TOP, anchor=W)
463 self.buttonHelpListRemove.pack(side=TOP, anchor=W, pady=5)
Steven M. Gava952d0a52001-08-03 04:43:44 +0000464 return frame
465
Steven M. Gavac112cd82002-01-22 05:56:40 +0000466 def AttachVarCallbacks(self):
Terry Jan Reedyd87d1682015-08-01 18:57:33 -0400467 self.fontSize.trace_variable('w', self.VarChanged_font)
468 self.fontName.trace_variable('w', self.VarChanged_font)
469 self.fontBold.trace_variable('w', self.VarChanged_font)
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400470 self.spaceNum.trace_variable('w', self.VarChanged_spaceNum)
471 self.colour.trace_variable('w', self.VarChanged_colour)
472 self.builtinTheme.trace_variable('w', self.VarChanged_builtinTheme)
473 self.customTheme.trace_variable('w', self.VarChanged_customTheme)
474 self.themeIsBuiltin.trace_variable('w', self.VarChanged_themeIsBuiltin)
475 self.highlightTarget.trace_variable('w', self.VarChanged_highlightTarget)
476 self.keyBinding.trace_variable('w', self.VarChanged_keyBinding)
477 self.builtinKeys.trace_variable('w', self.VarChanged_builtinKeys)
478 self.customKeys.trace_variable('w', self.VarChanged_customKeys)
479 self.keysAreBuiltin.trace_variable('w', self.VarChanged_keysAreBuiltin)
480 self.winWidth.trace_variable('w', self.VarChanged_winWidth)
481 self.winHeight.trace_variable('w', self.VarChanged_winHeight)
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400482 self.startupEdit.trace_variable('w', self.VarChanged_startupEdit)
483 self.autoSave.trace_variable('w', self.VarChanged_autoSave)
484 self.encoding.trace_variable('w', self.VarChanged_encoding)
Steven M. Gava052937f2002-02-11 02:20:53 +0000485
Terry Jan Reedy6b98ce22016-05-16 22:27:28 -0400486 def remove_var_callbacks(self):
487 "Remove callbacks to prevent memory leaks."
488 for var in (
489 self.fontSize, self.fontName, self.fontBold,
490 self.spaceNum, self.colour, self.builtinTheme,
491 self.customTheme, self.themeIsBuiltin, self.highlightTarget,
492 self.keyBinding, self.builtinKeys, self.customKeys,
493 self.keysAreBuiltin, self.winWidth, self.winHeight,
494 self.startupEdit, self.autoSave, self.encoding,):
495 var.trace_vdelete('w', var.trace_vinfo()[0][1])
496
Terry Jan Reedyd87d1682015-08-01 18:57:33 -0400497 def VarChanged_font(self, *params):
498 '''When one font attribute changes, save them all, as they are
499 not independent from each other. In particular, when we are
500 overriding the default font, we need to write out everything.
501 '''
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400502 value = self.fontName.get()
503 self.AddChangedItem('main', 'EditorWindow', 'font', value)
Terry Jan Reedyd87d1682015-08-01 18:57:33 -0400504 value = self.fontSize.get()
505 self.AddChangedItem('main', 'EditorWindow', 'font-size', value)
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400506 value = self.fontBold.get()
507 self.AddChangedItem('main', 'EditorWindow', 'font-bold', value)
Steven M. Gavac112cd82002-01-22 05:56:40 +0000508
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400509 def VarChanged_spaceNum(self, *params):
510 value = self.spaceNum.get()
511 self.AddChangedItem('main', 'Indent', 'num-spaces', value)
Steven M. Gavac112cd82002-01-22 05:56:40 +0000512
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400513 def VarChanged_colour(self, *params):
Steven M. Gava052937f2002-02-11 02:20:53 +0000514 self.OnNewColourSet()
515
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400516 def VarChanged_builtinTheme(self, *params):
517 value = self.builtinTheme.get()
Terry Jan Reedybe5b7a22015-10-04 00:31:05 -0400518 if value == 'IDLE Dark':
Terry Jan Reedyd0c0f002015-11-12 15:02:57 -0500519 if idleConf.GetOption('main', 'Theme', 'name') != 'IDLE New':
520 self.AddChangedItem('main', 'Theme', 'name', 'IDLE Classic')
521 self.AddChangedItem('main', 'Theme', 'name2', value)
522 self.new_custom_theme.config(text='New theme, see Help',
523 fg='#500000')
524 else:
525 self.AddChangedItem('main', 'Theme', 'name', value)
526 self.AddChangedItem('main', 'Theme', 'name2', '')
527 self.new_custom_theme.config(text='', fg='black')
Steven M. Gava052937f2002-02-11 02:20:53 +0000528 self.PaintThemeSample()
529
Terry Jan Reedy4036d872014-08-03 23:02:58 -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 Reedy4036d872014-08-03 23:02:58 -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 Reedy4036d872014-08-03 23:02:58 -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 Reedy4036d872014-08-03 23:02:58 -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 Reedy4036d872014-08-03 23:02:58 -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 Reedy4036d872014-08-03 23:02:58 -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 Reedy4036d872014-08-03 23:02:58 -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 Reedy4036d872014-08-03 23:02:58 -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 Reedy4036d872014-08-03 23:02:58 -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 Reedy4036d872014-08-03 23:02:58 -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 Reedy4036d872014-08-03 23:02:58 -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 Reedy4036d872014-08-03 23:02:58 -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 Reedy4036d872014-08-03 23:02:58 -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 Reedy4036d872014-08-03 23:02:58 -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 Reedy4036d872014-08-03 23:02:58 -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 Reedy4036d872014-08-03 23:02:58 -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 Reedy4036d872014-08-03 23:02:58 -0400604 self.changedItems = {'main':{}, 'highlight':{}, 'keys':{},
605 'extensions':{}}
Steven M. Gavaa498af22002-02-01 01:33:36 +0000606
Terry Jan Reedy4036d872014-08-03 23:02:58 -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 Reedy4036d872014-08-03 23:02:58 -0400614 dItems={'main':{}, 'highlight':{}, 'keys':{}, 'extensions':{}}
Kurt B. Kaisere0712772007-08-23 05:25:55 +0000615 for configType in dItems:
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400616 sections = idleConf.GetSectionList('default', configType)
Steven M. Gava5f28e8f2002-01-21 06:38:21 +0000617 for section in sections:
Terry Jan Reedy4036d872014-08-03 23:02:58 -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 Reedy4036d872014-08-03 23:02:58 -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 Reedy4036d872014-08-03 23:02:58 -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 Reedy4036d872014-08-03 23:02:58 -0400652 currentKeySetName = self.builtinKeys.get()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000653 else:
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400654 currentKeySetName = self.customKeys.get()
655 currentBindings = idleConf.GetCurrentKeySet()
Kurt B. Kaisere0712772007-08-23 05:25:55 +0000656 if currentKeySetName in self.changedItems['keys']: #unsaved changes
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400657 keySetChanges = self.changedItems['keys'][currentKeySetName]
Kurt B. Kaisere0712772007-08-23 05:25:55 +0000658 for event in keySetChanges:
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400659 currentBindings[event] = keySetChanges[event].split()
Kurt B. Kaisere0712772007-08-23 05:25:55 +0000660 currentKeySequences = list(currentBindings.values())
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400661 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 Reedy4036d872014-08-03 23:02:58 -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 Reedy4036d872014-08-03 23:02:58 -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 Reedy4036d872014-08-03 23:02:58 -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 Reedy4036d872014-08-03 23:02:58 -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 Reedy4036d872014-08-03 23:02:58 -0400695 def KeyBindingSelected(self, event):
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000696 self.buttonNewKeys.config(state=NORMAL)
697
Terry Jan Reedy4036d872014-08-03 23:02:58 -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 Reedy4036d872014-08-03 23:02:58 -0400702 prevKeySetName = self.builtinKeys.get()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000703 else:
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400704 prevKeySetName = self.customKeys.get()
705 prevKeys = idleConf.GetCoreKeys(prevKeySetName)
706 newKeys = {}
Kurt B. Kaisere0712772007-08-23 05:25:55 +0000707 for event in prevKeys: #add key set to changed items
Terry Jan Reedy4036d872014-08-03 23:02:58 -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
Kurt B. Kaisere0712772007-08-23 05:25:55 +0000712 if prevKeySetName in self.changedItems['keys']:
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400713 keySetChanges = self.changedItems['keys'][prevKeySetName]
Kurt B. Kaisere0712772007-08-23 05:25:55 +0000714 for event in keySetChanges:
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400715 newKeys[event] = keySetChanges[event]
Steven M. Gava052937f2002-02-11 02:20:53 +0000716 #save the new theme
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400717 self.SaveNewKeySet(newKeySetName, newKeys)
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000718 #change gui over to the new key set
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400719 customKeyList = idleConf.GetSectionList('user', 'keys')
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000720 customKeyList.sort()
Terry Jan Reedy4036d872014-08-03 23:02:58 -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 Reedy4036d872014-08-03 23:02:58 -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 Reedy4036d872014-08-03 23:02:58 -0400729 reselect = 1
730 listIndex = self.listBindings.index(ANCHOR)
731 keySet = idleConf.GetKeySet(keySetName)
Kurt B. Kaisere0712772007-08-23 05:25:55 +0000732 bindNames = list(keySet.keys())
Steven M. Gava052937f2002-02-11 02:20:53 +0000733 bindNames.sort()
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400734 self.listBindings.delete(0, END)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000735 for bindName in bindNames:
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400736 key = ' '.join(keySet[bindName]) #make key(s) into a string
737 bindName = bindName[2:-2] #trim off the angle brackets
Kurt B. Kaisere0712772007-08-23 05:25:55 +0000738 if keySetName in self.changedItems['keys']:
Steven M. Gava052937f2002-02-11 02:20:53 +0000739 #handle any unsaved changes to this key set
Kurt B. Kaisere0712772007-08-23 05:25:55 +0000740 if bindName in self.changedItems['keys'][keySetName]:
Terry Jan Reedy4036d872014-08-03 23:02:58 -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 Reedy4036d872014-08-03 23:02:58 -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
Terry Jan Reedyec844172016-06-14 00:53:25 -0400754 self.DeactivateCurrentConfig()
Steven M. Gava49745752002-02-18 01:43:11 +0000755 #remove key set from config
756 idleConf.userCfg['keys'].remove_section(keySetName)
Guido van Rossum811c4e02006-08-22 15:45:46 +0000757 if keySetName in self.changedItems['keys']:
Steven M. Gava49745752002-02-18 01:43:11 +0000758 del(self.changedItems['keys'][keySetName])
759 #write changes
760 idleConf.userCfg['keys'].Save()
761 #reload user key set list
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400762 itemList = idleConf.GetSectionList('user', 'keys')
Steven M. Gava49745752002-02-18 01:43:11 +0000763 itemList.sort()
764 if not itemList:
765 self.radioKeysCustom.config(state=DISABLED)
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400766 self.optMenuKeysCustom.SetMenu(itemList, '- no custom keys -')
Steven M. Gava49745752002-02-18 01:43:11 +0000767 else:
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400768 self.optMenuKeysCustom.SetMenu(itemList, itemList[0])
Steven M. Gava49745752002-02-18 01:43:11 +0000769 #revert to default key set
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400770 self.keysAreBuiltin.set(idleConf.defaultCfg['main'].Get('Keys', 'default'))
771 self.builtinKeys.set(idleConf.defaultCfg['main'].Get('Keys', 'name'))
Steven M. Gava49745752002-02-18 01:43:11 +0000772 #user can't back out of these changes, they must be applied now
Terry Jan Reedyec844172016-06-14 00:53:25 -0400773 self.SaveAllChangedConfigs()
774 self.ActivateConfigChanges()
Steven M. Gava49745752002-02-18 01:43:11 +0000775 self.SetKeysType()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000776
Steven M. Gava49745752002-02-18 01:43:11 +0000777 def DeleteCustomTheme(self):
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400778 themeName = self.customTheme.get()
779 delmsg = 'Are you sure you wish to delete the theme %r ?'
780 if not tkMessageBox.askyesno(
781 'Delete Theme', delmsg % themeName, parent=self):
Steven M. Gava49745752002-02-18 01:43:11 +0000782 return
Terry Jan Reedyec844172016-06-14 00:53:25 -0400783 self.DeactivateCurrentConfig()
Steven M. Gava49745752002-02-18 01:43:11 +0000784 #remove theme from config
785 idleConf.userCfg['highlight'].remove_section(themeName)
Guido van Rossum811c4e02006-08-22 15:45:46 +0000786 if themeName in self.changedItems['highlight']:
Steven M. Gava49745752002-02-18 01:43:11 +0000787 del(self.changedItems['highlight'][themeName])
788 #write changes
789 idleConf.userCfg['highlight'].Save()
790 #reload user theme list
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400791 itemList = idleConf.GetSectionList('user', 'highlight')
Steven M. Gava49745752002-02-18 01:43:11 +0000792 itemList.sort()
793 if not itemList:
794 self.radioThemeCustom.config(state=DISABLED)
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400795 self.optMenuThemeCustom.SetMenu(itemList, '- no custom themes -')
Steven M. Gava49745752002-02-18 01:43:11 +0000796 else:
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400797 self.optMenuThemeCustom.SetMenu(itemList, itemList[0])
Steven M. Gava49745752002-02-18 01:43:11 +0000798 #revert to default theme
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400799 self.themeIsBuiltin.set(idleConf.defaultCfg['main'].Get('Theme', 'default'))
800 self.builtinTheme.set(idleConf.defaultCfg['main'].Get('Theme', 'name'))
Steven M. Gava49745752002-02-18 01:43:11 +0000801 #user can't back out of these changes, they must be applied now
Terry Jan Reedyec844172016-06-14 00:53:25 -0400802 self.SaveAllChangedConfigs()
803 self.ActivateConfigChanges()
Steven M. Gava49745752002-02-18 01:43:11 +0000804 self.SetThemeType()
805
Steven M. Gava5f28e8f2002-01-21 06:38:21 +0000806 def GetColour(self):
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400807 target = self.highlightTarget.get()
808 prevColour = self.frameColourSet.cget('bg')
809 rgbTuplet, colourString = tkColorChooser.askcolor(
810 parent=self, title='Pick new colour for : '+target,
811 initialcolor=prevColour)
812 if colourString and (colourString != prevColour):
Steven M. Gava052937f2002-02-11 02:20:53 +0000813 #user didn't cancel, and they chose a new colour
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400814 if self.themeIsBuiltin.get(): #current theme is a built-in
815 message = ('Your changes will be saved as a new Custom Theme. '
816 'Enter a name for your new Custom Theme below.')
817 newTheme = self.GetNewThemeName(message)
818 if not newTheme: #user cancelled custom theme creation
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000819 return
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400820 else: #create new custom theme based on previously active theme
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000821 self.CreateNewTheme(newTheme)
Steven M. Gava052937f2002-02-11 02:20:53 +0000822 self.colour.set(colourString)
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400823 else: #current theme is user defined
Steven M. Gava052937f2002-02-11 02:20:53 +0000824 self.colour.set(colourString)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000825
Steven M. Gava052937f2002-02-11 02:20:53 +0000826 def OnNewColourSet(self):
827 newColour=self.colour.get()
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400828 self.frameColourSet.config(bg=newColour) #set sample
829 plane ='foreground' if self.fgHilite.get() else 'background'
830 sampleElement = self.themeElements[self.highlightTarget.get()][0]
Raymond Hettinger931237e2003-07-09 18:48:24 +0000831 self.textHighlightSample.tag_config(sampleElement, **{plane:newColour})
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400832 theme = self.customTheme.get()
833 themeElement = sampleElement + '-' + plane
834 self.AddChangedItem('highlight', theme, themeElement, newColour)
Steven M. Gava052937f2002-02-11 02:20:53 +0000835
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400836 def GetNewThemeName(self, message):
837 usedNames = (idleConf.GetSectionList('user', 'highlight') +
838 idleConf.GetSectionList('default', 'highlight'))
839 newTheme = GetCfgSectionNameDialog(
840 self, 'New Custom Theme', message, usedNames).result
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000841 return newTheme
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000842
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000843 def SaveAsNewTheme(self):
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400844 newThemeName = self.GetNewThemeName('New Theme Name:')
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000845 if newThemeName:
846 self.CreateNewTheme(newThemeName)
847
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400848 def CreateNewTheme(self, newThemeName):
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000849 #creates new custom theme based on the previously active theme,
850 #and makes the new theme active
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000851 if self.themeIsBuiltin.get():
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400852 themeType = 'default'
853 themeName = self.builtinTheme.get()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000854 else:
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400855 themeType = 'user'
856 themeName = self.customTheme.get()
857 newTheme = idleConf.GetThemeDict(themeType, themeName)
Steven M. Gava052937f2002-02-11 02:20:53 +0000858 #apply any of the old theme's unsaved changes to the new theme
Kurt B. Kaisere0712772007-08-23 05:25:55 +0000859 if themeName in self.changedItems['highlight']:
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400860 themeChanges = self.changedItems['highlight'][themeName]
Kurt B. Kaisere0712772007-08-23 05:25:55 +0000861 for element in themeChanges:
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400862 newTheme[element] = themeChanges[element]
Steven M. Gava052937f2002-02-11 02:20:53 +0000863 #save the new theme
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400864 self.SaveNewTheme(newThemeName, newTheme)
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000865 #change gui over to the new theme
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400866 customThemeList = idleConf.GetSectionList('user', 'highlight')
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000867 customThemeList.sort()
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400868 self.optMenuThemeCustom.SetMenu(customThemeList, newThemeName)
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000869 self.themeIsBuiltin.set(0)
870 self.SetThemeType()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000871
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400872 def OnListFontButtonRelease(self, event):
Kurt B. Kaiser05391692003-05-26 20:35:53 +0000873 font = self.listFontName.get(ANCHOR)
874 self.fontName.set(font.lower())
Steven M. Gava5f28e8f2002-01-21 06:38:21 +0000875 self.SetFontSample()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000876
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400877 def SetFontSample(self, event=None):
878 fontName = self.fontName.get()
879 fontWeight = tkFont.BOLD if self.fontBold.get() else tkFont.NORMAL
Ned Deilyfdf0f272012-10-22 15:14:31 -0700880 newFont = (fontName, self.fontSize.get(), fontWeight)
881 self.labelFontSample.config(font=newFont)
882 self.textHighlightSample.configure(font=newFont)
Steven M. Gava5f28e8f2002-01-21 06:38:21 +0000883
Steven M. Gava5f28e8f2002-01-21 06:38:21 +0000884 def SetHighlightTarget(self):
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400885 if self.highlightTarget.get() == 'Cursor': #bg not possible
Steven M. Gava5f28e8f2002-01-21 06:38:21 +0000886 self.radioFg.config(state=DISABLED)
887 self.radioBg.config(state=DISABLED)
888 self.fgHilite.set(1)
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400889 else: #both fg and bg can be set
Steven M. Gava5f28e8f2002-01-21 06:38:21 +0000890 self.radioFg.config(state=NORMAL)
891 self.radioBg.config(state=NORMAL)
892 self.fgHilite.set(1)
893 self.SetColourSample()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000894
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400895 def SetColourSampleBinding(self, *args):
Steven M. Gava5f28e8f2002-01-21 06:38:21 +0000896 self.SetColourSample()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000897
Steven M. Gava5f28e8f2002-01-21 06:38:21 +0000898 def SetColourSample(self):
899 #set the colour smaple area
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400900 tag = self.themeElements[self.highlightTarget.get()][0]
901 plane = 'foreground' if self.fgHilite.get() else 'background'
902 colour = self.textHighlightSample.tag_cget(tag, plane)
Steven M. Gava5f28e8f2002-01-21 06:38:21 +0000903 self.frameColourSet.config(bg=colour)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000904
Steven M. Gava9dd16b32001-11-03 14:54:25 +0000905 def PaintThemeSample(self):
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400906 if self.themeIsBuiltin.get(): #a default theme
907 theme = self.builtinTheme.get()
908 else: #a user theme
909 theme = self.customTheme.get()
Kurt B. Kaisere0712772007-08-23 05:25:55 +0000910 for elementTitle in self.themeElements:
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400911 element = self.themeElements[elementTitle][0]
912 colours = idleConf.GetHighlight(theme, element)
913 if element == 'cursor': #cursor sample needs special painting
914 colours['background'] = idleConf.GetHighlight(
915 theme, 'normal', fgBg='bg')
Steven M. Gava052937f2002-02-11 02:20:53 +0000916 #handle any unsaved changes to this theme
Kurt B. Kaisere0712772007-08-23 05:25:55 +0000917 if theme in self.changedItems['highlight']:
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400918 themeDict = self.changedItems['highlight'][theme]
919 if element + '-foreground' in themeDict:
920 colours['foreground'] = themeDict[element + '-foreground']
921 if element + '-background' in themeDict:
922 colours['background'] = themeDict[element + '-background']
Raymond Hettinger931237e2003-07-09 18:48:24 +0000923 self.textHighlightSample.tag_config(element, **colours)
Steven M. Gava052937f2002-02-11 02:20:53 +0000924 self.SetColourSample()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000925
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400926 def HelpSourceSelected(self, event):
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000927 self.SetHelpListButtonStates()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000928
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000929 def SetHelpListButtonStates(self):
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400930 if self.listHelp.size() < 1: #no entries in list
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000931 self.buttonHelpListEdit.config(state=DISABLED)
932 self.buttonHelpListRemove.config(state=DISABLED)
933 else: #there are some entries
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400934 if self.listHelp.curselection(): #there currently is a selection
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000935 self.buttonHelpListEdit.config(state=NORMAL)
936 self.buttonHelpListRemove.config(state=NORMAL)
937 else: #there currently is not a selection
938 self.buttonHelpListEdit.config(state=DISABLED)
939 self.buttonHelpListRemove.config(state=DISABLED)
940
941 def HelpListItemAdd(self):
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400942 helpSource = GetHelpSourceDialog(self, 'New Help Source').result
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000943 if helpSource:
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400944 self.userHelpList.append((helpSource[0], helpSource[1]))
945 self.listHelp.insert(END, helpSource[0])
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000946 self.UpdateUserHelpChangedItems()
947 self.SetHelpListButtonStates()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000948
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000949 def HelpListItemEdit(self):
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400950 itemIndex = self.listHelp.index(ANCHOR)
951 helpSource = self.userHelpList[itemIndex]
952 newHelpSource = GetHelpSourceDialog(
953 self, 'Edit Help Source', menuItem=helpSource[0],
954 filePath=helpSource[1]).result
955 if (not newHelpSource) or (newHelpSource == helpSource):
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000956 return #no changes
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400957 self.userHelpList[itemIndex] = newHelpSource
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000958 self.listHelp.delete(itemIndex)
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400959 self.listHelp.insert(itemIndex, newHelpSource[0])
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000960 self.UpdateUserHelpChangedItems()
961 self.SetHelpListButtonStates()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000962
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000963 def HelpListItemRemove(self):
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400964 itemIndex = self.listHelp.index(ANCHOR)
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000965 del(self.userHelpList[itemIndex])
966 self.listHelp.delete(itemIndex)
967 self.UpdateUserHelpChangedItems()
968 self.SetHelpListButtonStates()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000969
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000970 def UpdateUserHelpChangedItems(self):
Kurt B. Kaiser8e92bf72003-01-14 22:03:31 +0000971 "Clear and rebuild the HelpFiles section in self.changedItems"
972 self.changedItems['main']['HelpFiles'] = {}
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400973 for num in range(1, len(self.userHelpList) + 1):
974 self.AddChangedItem(
975 'main', 'HelpFiles', str(num),
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000976 ';'.join(self.userHelpList[num-1][:2]))
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000977
Steven M. Gava429a86af2001-10-23 10:42:12 +0000978 def LoadFontCfg(self):
979 ##base editor font selection list
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400980 fonts = list(tkFont.families(self))
Steven M. Gavac11ccf32001-09-24 09:43:17 +0000981 fonts.sort()
982 for font in fonts:
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400983 self.listFontName.insert(END, font)
Terry Jan Reedyd87d1682015-08-01 18:57:33 -0400984 configuredFont = idleConf.GetFont(self, 'main', 'EditorWindow')
985 fontName = configuredFont[0].lower()
986 fontSize = configuredFont[1]
987 fontBold = configuredFont[2]=='bold'
988 self.fontName.set(fontName)
Kurt B. Kaiser05391692003-05-26 20:35:53 +0000989 lc_fonts = [s.lower() for s in fonts]
Terry Jan Reedyd87d1682015-08-01 18:57:33 -0400990 try:
991 currentFontIndex = lc_fonts.index(fontName)
Steven M. Gava429a86af2001-10-23 10:42:12 +0000992 self.listFontName.see(currentFontIndex)
993 self.listFontName.select_set(currentFontIndex)
Steven M. Gavac112cd82002-01-22 05:56:40 +0000994 self.listFontName.select_anchor(currentFontIndex)
Terry Jan Reedyd87d1682015-08-01 18:57:33 -0400995 except ValueError:
996 pass
Steven M. Gava429a86af2001-10-23 10:42:12 +0000997 ##font size dropdown
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400998 self.optMenuFontSize.SetMenu(('7', '8', '9', '10', '11', '12', '13',
999 '14', '16', '18', '20', '22'), fontSize )
Steven M. Gavac112cd82002-01-22 05:56:40 +00001000 ##fontWeight
Terry Jan Reedyd87d1682015-08-01 18:57:33 -04001001 self.fontBold.set(fontBold)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001002 ##font sample
Steven M. Gava429a86af2001-10-23 10:42:12 +00001003 self.SetFontSample()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001004
Steven M. Gava429a86af2001-10-23 10:42:12 +00001005 def LoadTabCfg(self):
Steven M. Gava429a86af2001-10-23 10:42:12 +00001006 ##indent sizes
Terry Jan Reedy4036d872014-08-03 23:02:58 -04001007 spaceNum = idleConf.GetOption(
1008 'main', 'Indent', 'num-spaces', default=4, type='int')
Steven M. Gava429a86af2001-10-23 10:42:12 +00001009 self.spaceNum.set(spaceNum)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001010
Steven M. Gava9dd16b32001-11-03 14:54:25 +00001011 def LoadThemeCfg(self):
Steven M. Gava41a85322001-10-29 08:05:34 +00001012 ##current theme type radiobutton
Terry Jan Reedy4036d872014-08-03 23:02:58 -04001013 self.themeIsBuiltin.set(idleConf.GetOption(
1014 'main', 'Theme', 'default', type='bool', default=1))
Steven M. Gava41a85322001-10-29 08:05:34 +00001015 ##currently set theme
Terry Jan Reedy4036d872014-08-03 23:02:58 -04001016 currentOption = idleConf.CurrentTheme()
Steven M. Gava7c017862001-10-29 11:19:46 +00001017 ##load available theme option menus
Steven M. Gavad0342cd2001-11-04 11:53:10 +00001018 if self.themeIsBuiltin.get(): #default theme selected
Terry Jan Reedy4036d872014-08-03 23:02:58 -04001019 itemList = idleConf.GetSectionList('default', 'highlight')
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +00001020 itemList.sort()
Terry Jan Reedy4036d872014-08-03 23:02:58 -04001021 self.optMenuThemeBuiltin.SetMenu(itemList, currentOption)
1022 itemList = idleConf.GetSectionList('user', 'highlight')
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +00001023 itemList.sort()
Steven M. Gava41a85322001-10-29 08:05:34 +00001024 if not itemList:
1025 self.radioThemeCustom.config(state=DISABLED)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001026 self.customTheme.set('- no custom themes -')
Steven M. Gava41a85322001-10-29 08:05:34 +00001027 else:
Terry Jan Reedy4036d872014-08-03 23:02:58 -04001028 self.optMenuThemeCustom.SetMenu(itemList, itemList[0])
Steven M. Gava9dd16b32001-11-03 14:54:25 +00001029 else: #user theme selected
Terry Jan Reedy4036d872014-08-03 23:02:58 -04001030 itemList = idleConf.GetSectionList('user', 'highlight')
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +00001031 itemList.sort()
Terry Jan Reedy4036d872014-08-03 23:02:58 -04001032 self.optMenuThemeCustom.SetMenu(itemList, currentOption)
1033 itemList = idleConf.GetSectionList('default', 'highlight')
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +00001034 itemList.sort()
Terry Jan Reedy4036d872014-08-03 23:02:58 -04001035 self.optMenuThemeBuiltin.SetMenu(itemList, itemList[0])
Steven M. Gava7c017862001-10-29 11:19:46 +00001036 self.SetThemeType()
1037 ##load theme element option menu
Kurt B. Kaisere0712772007-08-23 05:25:55 +00001038 themeNames = list(self.themeElements.keys())
Kurt B. Kaiser4718bf82008-02-12 21:34:12 +00001039 themeNames.sort(key=lambda x: self.themeElements[x][1])
Terry Jan Reedy4036d872014-08-03 23:02:58 -04001040 self.optMenuHighlightTarget.SetMenu(themeNames, themeNames[0])
Steven M. Gava9dd16b32001-11-03 14:54:25 +00001041 self.PaintThemeSample()
Steven M. Gava0cae01c2002-01-04 07:53:06 +00001042 self.SetHighlightTarget()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001043
Steven M. Gava9dd16b32001-11-03 14:54:25 +00001044 def LoadKeyCfg(self):
Steven M. Gava41a85322001-10-29 08:05:34 +00001045 ##current keys type radiobutton
Terry Jan Reedy4036d872014-08-03 23:02:58 -04001046 self.keysAreBuiltin.set(idleConf.GetOption(
1047 'main', 'Keys', 'default', type='bool', default=1))
Steven M. Gava41a85322001-10-29 08:05:34 +00001048 ##currently set keys
Terry Jan Reedy4036d872014-08-03 23:02:58 -04001049 currentOption = idleConf.CurrentKeys()
Steven M. Gava7c017862001-10-29 11:19:46 +00001050 ##load available keyset option menus
Steven M. Gava052937f2002-02-11 02:20:53 +00001051 if self.keysAreBuiltin.get(): #default theme selected
Terry Jan Reedy4036d872014-08-03 23:02:58 -04001052 itemList = idleConf.GetSectionList('default', 'keys')
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +00001053 itemList.sort()
Terry Jan Reedy4036d872014-08-03 23:02:58 -04001054 self.optMenuKeysBuiltin.SetMenu(itemList, currentOption)
1055 itemList = idleConf.GetSectionList('user', 'keys')
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +00001056 itemList.sort()
Steven M. Gava41a85322001-10-29 08:05:34 +00001057 if not itemList:
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001058 self.radioKeysCustom.config(state=DISABLED)
1059 self.customKeys.set('- no custom keys -')
Steven M. Gava41a85322001-10-29 08:05:34 +00001060 else:
Terry Jan Reedy4036d872014-08-03 23:02:58 -04001061 self.optMenuKeysCustom.SetMenu(itemList, itemList[0])
Steven M. Gavaa498af22002-02-01 01:33:36 +00001062 else: #user key set selected
Terry Jan Reedy4036d872014-08-03 23:02:58 -04001063 itemList = idleConf.GetSectionList('user', 'keys')
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +00001064 itemList.sort()
Terry Jan Reedy4036d872014-08-03 23:02:58 -04001065 self.optMenuKeysCustom.SetMenu(itemList, currentOption)
1066 itemList = idleConf.GetSectionList('default', 'keys')
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +00001067 itemList.sort()
Terry Jan Reedy4036d872014-08-03 23:02:58 -04001068 self.optMenuKeysBuiltin.SetMenu(itemList, itemList[0])
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001069 self.SetKeysType()
Steven M. Gavafacfc092002-01-19 00:29:54 +00001070 ##load keyset element list
Terry Jan Reedy4036d872014-08-03 23:02:58 -04001071 keySetName = idleConf.CurrentKeys()
Steven M. Gava052937f2002-02-11 02:20:53 +00001072 self.LoadKeysList(keySetName)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001073
Steven M. Gavafacfc092002-01-19 00:29:54 +00001074 def LoadGeneralCfg(self):
Steven M. Gava5f28e8f2002-01-21 06:38:21 +00001075 #startup state
Terry Jan Reedy4036d872014-08-03 23:02:58 -04001076 self.startupEdit.set(idleConf.GetOption(
1077 'main', 'General', 'editor-on-startup', default=1, type='bool'))
Kurt B. Kaiser6c638b62003-05-26 06:23:10 +00001078 #autosave state
Terry Jan Reedy4036d872014-08-03 23:02:58 -04001079 self.autoSave.set(idleConf.GetOption(
1080 'main', 'General', 'autosave', default=0, type='bool'))
Steven M. Gavafacfc092002-01-19 00:29:54 +00001081 #initial window size
Terry Jan Reedy4036d872014-08-03 23:02:58 -04001082 self.winWidth.set(idleConf.GetOption(
1083 'main', 'EditorWindow', 'width', type='int'))
1084 self.winHeight.set(idleConf.GetOption(
1085 'main', 'EditorWindow', 'height', type='int'))
Kurt B. Kaisera053f332003-05-10 00:49:56 +00001086 # default source encoding
Terry Jan Reedy4036d872014-08-03 23:02:58 -04001087 self.encoding.set(idleConf.GetOption(
1088 'main', 'EditorWindow', 'encoding', default='none'))
Kurt B. Kaiser8e92bf72003-01-14 22:03:31 +00001089 # additional help sources
1090 self.userHelpList = idleConf.GetAllExtraHelpSourcesList()
Steven M. Gava085eb1b2002-02-05 04:52:32 +00001091 for helpItem in self.userHelpList:
Terry Jan Reedy4036d872014-08-03 23:02:58 -04001092 self.listHelp.insert(END, helpItem[0])
Steven M. Gava085eb1b2002-02-05 04:52:32 +00001093 self.SetHelpListButtonStates()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001094
Steven M. Gava429a86af2001-10-23 10:42:12 +00001095 def LoadConfigs(self):
1096 """
1097 load configuration from default and user config files and populate
1098 the widgets on the config dialog pages.
1099 """
1100 ### fonts / tabs page
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001101 self.LoadFontCfg()
1102 self.LoadTabCfg()
Steven M. Gava429a86af2001-10-23 10:42:12 +00001103 ### highlighting page
Steven M. Gava9dd16b32001-11-03 14:54:25 +00001104 self.LoadThemeCfg()
Steven M. Gava429a86af2001-10-23 10:42:12 +00001105 ### keys page
Steven M. Gava9dd16b32001-11-03 14:54:25 +00001106 self.LoadKeyCfg()
Steven M. Gava429a86af2001-10-23 10:42:12 +00001107 ### general page
Steven M. Gavafacfc092002-01-19 00:29:54 +00001108 self.LoadGeneralCfg()
Terry Jan Reedy93f35422015-10-13 22:03:51 -04001109 # note: extension page handled separately
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001110
Terry Jan Reedy4036d872014-08-03 23:02:58 -04001111 def SaveNewKeySet(self, keySetName, keySet):
Steven M. Gava052937f2002-02-11 02:20:53 +00001112 """
1113 save a newly created core key set.
1114 keySetName - string, the name of the new key set
1115 keySet - dictionary containing the new key set
1116 """
1117 if not idleConf.userCfg['keys'].has_section(keySetName):
1118 idleConf.userCfg['keys'].add_section(keySetName)
Kurt B. Kaisere0712772007-08-23 05:25:55 +00001119 for event in keySet:
Terry Jan Reedy4036d872014-08-03 23:02:58 -04001120 value = keySet[event]
1121 idleConf.userCfg['keys'].SetOption(keySetName, event, value)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001122
Terry Jan Reedy4036d872014-08-03 23:02:58 -04001123 def SaveNewTheme(self, themeName, theme):
Steven M. Gava052937f2002-02-11 02:20:53 +00001124 """
1125 save a newly created theme.
1126 themeName - string, the name of the new theme
1127 theme - dictionary containing the new theme
1128 """
1129 if not idleConf.userCfg['highlight'].has_section(themeName):
1130 idleConf.userCfg['highlight'].add_section(themeName)
Kurt B. Kaisere0712772007-08-23 05:25:55 +00001131 for element in theme:
Terry Jan Reedy4036d872014-08-03 23:02:58 -04001132 value = theme[element]
1133 idleConf.userCfg['highlight'].SetOption(themeName, element, value)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001134
Terry Jan Reedy4036d872014-08-03 23:02:58 -04001135 def SetUserValue(self, configType, section, item, value):
1136 if idleConf.defaultCfg[configType].has_option(section, item):
1137 if idleConf.defaultCfg[configType].Get(section, item) == value:
Steven M. Gava2d7bb3f2002-01-29 08:35:29 +00001138 #the setting equals a default setting, remove it from user cfg
Terry Jan Reedy4036d872014-08-03 23:02:58 -04001139 return idleConf.userCfg[configType].RemoveOption(section, item)
Steven M. Gava2d7bb3f2002-01-29 08:35:29 +00001140 #if we got here set the option
Terry Jan Reedy4036d872014-08-03 23:02:58 -04001141 return idleConf.userCfg[configType].SetOption(section, item, value)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001142
Steven M. Gava052937f2002-02-11 02:20:53 +00001143 def SaveAllChangedConfigs(self):
Kurt B. Kaisere7a161e2003-01-10 20:13:57 +00001144 "Save configuration changes to the user config file."
Steven M. Gava0c5bc8c2002-03-27 02:25:44 +00001145 idleConf.userCfg['main'].Save()
Kurt B. Kaisere0712772007-08-23 05:25:55 +00001146 for configType in self.changedItems:
Kurt B. Kaisere7a161e2003-01-10 20:13:57 +00001147 cfgTypeHasChanges = False
Kurt B. Kaisere0712772007-08-23 05:25:55 +00001148 for section in self.changedItems[configType]:
Kurt B. Kaisere7a161e2003-01-10 20:13:57 +00001149 if section == 'HelpFiles':
1150 #this section gets completely replaced
1151 idleConf.userCfg['main'].remove_section('HelpFiles')
Kurt B. Kaiser8e92bf72003-01-14 22:03:31 +00001152 cfgTypeHasChanges = True
Kurt B. Kaisere0712772007-08-23 05:25:55 +00001153 for item in self.changedItems[configType][section]:
Kurt B. Kaisere7a161e2003-01-10 20:13:57 +00001154 value = self.changedItems[configType][section][item]
Terry Jan Reedy4036d872014-08-03 23:02:58 -04001155 if self.SetUserValue(configType, section, item, value):
Kurt B. Kaisere7a161e2003-01-10 20:13:57 +00001156 cfgTypeHasChanges = True
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001157 if cfgTypeHasChanges:
1158 idleConf.userCfg[configType].Save()
Kurt B. Kaiser5acdf932004-11-16 21:28:36 +00001159 for configType in ['keys', 'highlight']:
1160 # save these even if unchanged!
1161 idleConf.userCfg[configType].Save()
Steven M. Gavaa498af22002-02-01 01:33:36 +00001162 self.ResetChangedItems() #clear the changed items dict
Terry Jan Reedy93f35422015-10-13 22:03:51 -04001163 self.save_all_changed_extensions() # uses a different mechanism
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001164
Kurt B. Kaiserb1754452005-11-18 22:05:48 +00001165 def DeactivateCurrentConfig(self):
1166 #Before a config is saved, some cleanup of current
1167 #config must be done - remove the previous keybindings
Kurt B. Kaisere0712772007-08-23 05:25:55 +00001168 winInstances = self.parent.instance_dict.keys()
Kurt B. Kaiserb1754452005-11-18 22:05:48 +00001169 for instance in winInstances:
1170 instance.RemoveKeybindings()
1171
Steven M. Gava49745752002-02-18 01:43:11 +00001172 def ActivateConfigChanges(self):
Kurt B. Kaiseracdef852005-01-31 03:34:26 +00001173 "Dynamically apply configuration changes"
Kurt B. Kaisere0712772007-08-23 05:25:55 +00001174 winInstances = self.parent.instance_dict.keys()
Steven M. Gavab77d3432002-03-02 07:16:21 +00001175 for instance in winInstances:
1176 instance.ResetColorizer()
Steven M. Gavab1585412002-03-12 00:21:56 +00001177 instance.ResetFont()
Kurt B. Kaiseracdef852005-01-31 03:34:26 +00001178 instance.set_notabs_indentwidth()
Kurt B. Kaiserb1754452005-11-18 22:05:48 +00001179 instance.ApplyKeybindings()
Kurt B. Kaiser8e92bf72003-01-14 22:03:31 +00001180 instance.reset_help_menu_entries()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001181
Steven M. Gava5f28e8f2002-01-21 06:38:21 +00001182 def Cancel(self):
1183 self.destroy()
1184
1185 def Ok(self):
1186 self.Apply()
1187 self.destroy()
1188
1189 def Apply(self):
Kurt B. Kaiserb1754452005-11-18 22:05:48 +00001190 self.DeactivateCurrentConfig()
Steven M. Gava052937f2002-02-11 02:20:53 +00001191 self.SaveAllChangedConfigs()
Steven M. Gava49745752002-02-18 01:43:11 +00001192 self.ActivateConfigChanges()
Steven M. Gava5f28e8f2002-01-21 06:38:21 +00001193
1194 def Help(self):
Terry Jan Reedyd0cadba2015-10-11 22:07:31 -04001195 page = self.tabPages._current_page
1196 view_text(self, title='Help for IDLE preferences',
1197 text=help_common+help_pages.get(page, ''))
1198
Terry Jan Reedy93f35422015-10-13 22:03:51 -04001199 def CreatePageExtensions(self):
1200 """Part of the config dialog used for configuring IDLE extensions.
1201
1202 This code is generic - it works for any and all IDLE extensions.
1203
1204 IDLE extensions save their configuration options using idleConf.
Terry Jan Reedyb2f87602015-10-13 22:09:06 -04001205 This code reads the current configuration using idleConf, supplies a
Terry Jan Reedy93f35422015-10-13 22:03:51 -04001206 GUI interface to change the configuration values, and saves the
1207 changes using idleConf.
1208
1209 Not all changes take effect immediately - some may require restarting IDLE.
1210 This depends on each extension's implementation.
1211
1212 All values are treated as text, and it is up to the user to supply
1213 reasonable values. The only exception to this are the 'enable*' options,
Serhiy Storchaka6a7b3a72016-04-17 08:32:47 +03001214 which are boolean, and can be toggled with a True/False button.
Terry Jan Reedy93f35422015-10-13 22:03:51 -04001215 """
1216 parent = self.parent
1217 frame = self.tabPages.pages['Extensions'].frame
1218 self.ext_defaultCfg = idleConf.defaultCfg['extensions']
1219 self.ext_userCfg = idleConf.userCfg['extensions']
1220 self.is_int = self.register(is_int)
1221 self.load_extensions()
1222 # create widgets - a listbox shows all available extensions, with the
1223 # controls for the extension selected in the listbox to the right
1224 self.extension_names = StringVar(self)
1225 frame.rowconfigure(0, weight=1)
1226 frame.columnconfigure(2, weight=1)
1227 self.extension_list = Listbox(frame, listvariable=self.extension_names,
1228 selectmode='browse')
1229 self.extension_list.bind('<<ListboxSelect>>', self.extension_selected)
1230 scroll = Scrollbar(frame, command=self.extension_list.yview)
1231 self.extension_list.yscrollcommand=scroll.set
1232 self.details_frame = LabelFrame(frame, width=250, height=250)
1233 self.extension_list.grid(column=0, row=0, sticky='nws')
1234 scroll.grid(column=1, row=0, sticky='ns')
1235 self.details_frame.grid(column=2, row=0, sticky='nsew', padx=[10, 0])
1236 frame.configure(padx=10, pady=10)
1237 self.config_frame = {}
1238 self.current_extension = None
1239
1240 self.outerframe = self # TEMPORARY
1241 self.tabbed_page_set = self.extension_list # TEMPORARY
1242
1243 # create the frame holding controls for each extension
1244 ext_names = ''
1245 for ext_name in sorted(self.extensions):
1246 self.create_extension_frame(ext_name)
1247 ext_names = ext_names + '{' + ext_name + '} '
1248 self.extension_names.set(ext_names)
1249 self.extension_list.selection_set(0)
1250 self.extension_selected(None)
1251
1252 def load_extensions(self):
1253 "Fill self.extensions with data from the default and user configs."
1254 self.extensions = {}
1255 for ext_name in idleConf.GetExtensions(active_only=False):
1256 self.extensions[ext_name] = []
1257
1258 for ext_name in self.extensions:
1259 opt_list = sorted(self.ext_defaultCfg.GetOptionList(ext_name))
1260
1261 # bring 'enable' options to the beginning of the list
1262 enables = [opt_name for opt_name in opt_list
1263 if opt_name.startswith('enable')]
1264 for opt_name in enables:
1265 opt_list.remove(opt_name)
1266 opt_list = enables + opt_list
1267
1268 for opt_name in opt_list:
1269 def_str = self.ext_defaultCfg.Get(
1270 ext_name, opt_name, raw=True)
1271 try:
1272 def_obj = {'True':True, 'False':False}[def_str]
1273 opt_type = 'bool'
1274 except KeyError:
1275 try:
1276 def_obj = int(def_str)
1277 opt_type = 'int'
1278 except ValueError:
1279 def_obj = def_str
1280 opt_type = None
1281 try:
1282 value = self.ext_userCfg.Get(
1283 ext_name, opt_name, type=opt_type, raw=True,
1284 default=def_obj)
1285 except ValueError: # Need this until .Get fixed
1286 value = def_obj # bad values overwritten by entry
1287 var = StringVar(self)
1288 var.set(str(value))
1289
1290 self.extensions[ext_name].append({'name': opt_name,
1291 'type': opt_type,
1292 'default': def_str,
1293 'value': value,
1294 'var': var,
1295 })
1296
1297 def extension_selected(self, event):
1298 newsel = self.extension_list.curselection()
1299 if newsel:
1300 newsel = self.extension_list.get(newsel)
1301 if newsel is None or newsel != self.current_extension:
1302 if self.current_extension:
1303 self.details_frame.config(text='')
1304 self.config_frame[self.current_extension].grid_forget()
1305 self.current_extension = None
1306 if newsel:
1307 self.details_frame.config(text=newsel)
1308 self.config_frame[newsel].grid(column=0, row=0, sticky='nsew')
1309 self.current_extension = newsel
1310
1311 def create_extension_frame(self, ext_name):
1312 """Create a frame holding the widgets to configure one extension"""
1313 f = VerticalScrolledFrame(self.details_frame, height=250, width=250)
1314 self.config_frame[ext_name] = f
1315 entry_area = f.interior
1316 # create an entry for each configuration option
1317 for row, opt in enumerate(self.extensions[ext_name]):
1318 # create a row with a label and entry/checkbutton
1319 label = Label(entry_area, text=opt['name'])
1320 label.grid(row=row, column=0, sticky=NW)
1321 var = opt['var']
1322 if opt['type'] == 'bool':
1323 Checkbutton(entry_area, textvariable=var, variable=var,
1324 onvalue='True', offvalue='False',
1325 indicatoron=FALSE, selectcolor='', width=8
1326 ).grid(row=row, column=1, sticky=W, padx=7)
1327 elif opt['type'] == 'int':
1328 Entry(entry_area, textvariable=var, validate='key',
1329 validatecommand=(self.is_int, '%P')
1330 ).grid(row=row, column=1, sticky=NSEW, padx=7)
1331
1332 else:
1333 Entry(entry_area, textvariable=var
1334 ).grid(row=row, column=1, sticky=NSEW, padx=7)
1335 return
1336
1337 def set_extension_value(self, section, opt):
1338 name = opt['name']
1339 default = opt['default']
1340 value = opt['var'].get().strip() or default
1341 opt['var'].set(value)
1342 # if self.defaultCfg.has_section(section):
1343 # Currently, always true; if not, indent to return
1344 if (value == default):
1345 return self.ext_userCfg.RemoveOption(section, name)
1346 # set the option
1347 return self.ext_userCfg.SetOption(section, name, value)
1348
1349 def save_all_changed_extensions(self):
1350 """Save configuration changes to the user config file."""
1351 has_changes = False
1352 for ext_name in self.extensions:
1353 options = self.extensions[ext_name]
1354 for opt in options:
1355 if self.set_extension_value(ext_name, opt):
1356 has_changes = True
1357 if has_changes:
1358 self.ext_userCfg.Save()
1359
1360
Terry Jan Reedyd0cadba2015-10-11 22:07:31 -04001361help_common = '''\
1362When you click either the Apply or Ok buttons, settings in this
1363dialog that are different from IDLE's default are saved in
1364a .idlerc directory in your home directory. Except as noted,
Terry Jan Reedyd0c0f002015-11-12 15:02:57 -05001365these changes apply to all versions of IDLE installed on this
Terry Jan Reedyd0cadba2015-10-11 22:07:31 -04001366machine. Some do not take affect until IDLE is restarted.
1367[Cancel] only cancels changes made since the last save.
1368'''
1369help_pages = {
1370 'Highlighting':'''
1371Highlighting:
Terry Jan Reedyd0c0f002015-11-12 15:02:57 -05001372The IDLE Dark color theme is new in October 2015. It can only
Terry Jan Reedyd0cadba2015-10-11 22:07:31 -04001373be used with older IDLE releases if it is saved as a custom
1374theme, with a different name.
1375'''
1376}
1377
Steven M. Gavac11ccf32001-09-24 09:43:17 +00001378
Terry Jan Reedy93f35422015-10-13 22:03:51 -04001379def is_int(s):
1380 "Return 's is blank or represents an int'"
1381 if not s:
1382 return True
1383 try:
1384 int(s)
1385 return True
1386 except ValueError:
1387 return False
1388
1389
Terry Jan Reedya9421fb2014-10-22 20:15:18 -04001390class VerticalScrolledFrame(Frame):
1391 """A pure Tkinter vertically scrollable frame.
1392
1393 * Use the 'interior' attribute to place widgets inside the scrollable frame
1394 * Construct and pack/place/grid normally
1395 * This frame only allows vertical scrolling
1396 """
1397 def __init__(self, parent, *args, **kw):
1398 Frame.__init__(self, parent, *args, **kw)
1399
1400 # create a canvas object and a vertical scrollbar for scrolling it
1401 vscrollbar = Scrollbar(self, orient=VERTICAL)
1402 vscrollbar.pack(fill=Y, side=RIGHT, expand=FALSE)
1403 canvas = Canvas(self, bd=0, highlightthickness=0,
Terry Jan Reedyd0812292015-10-22 03:27:31 -04001404 yscrollcommand=vscrollbar.set, width=240)
Terry Jan Reedya9421fb2014-10-22 20:15:18 -04001405 canvas.pack(side=LEFT, fill=BOTH, expand=TRUE)
1406 vscrollbar.config(command=canvas.yview)
1407
1408 # reset the view
1409 canvas.xview_moveto(0)
1410 canvas.yview_moveto(0)
1411
1412 # create a frame inside the canvas which will be scrolled with it
1413 self.interior = interior = Frame(canvas)
1414 interior_id = canvas.create_window(0, 0, window=interior, anchor=NW)
1415
1416 # track changes to the canvas and frame width and sync them,
1417 # also updating the scrollbar
1418 def _configure_interior(event):
1419 # update the scrollbars to match the size of the inner frame
1420 size = (interior.winfo_reqwidth(), interior.winfo_reqheight())
1421 canvas.config(scrollregion="0 0 %s %s" % size)
Terry Jan Reedya9421fb2014-10-22 20:15:18 -04001422 interior.bind('<Configure>', _configure_interior)
1423
1424 def _configure_canvas(event):
1425 if interior.winfo_reqwidth() != canvas.winfo_width():
1426 # update the inner frame's width to fill the canvas
1427 canvas.itemconfigure(interior_id, width=canvas.winfo_width())
1428 canvas.bind('<Configure>', _configure_canvas)
1429
1430 return
1431
Terry Jan Reedya9421fb2014-10-22 20:15:18 -04001432
Steven M. Gava44d3d1a2001-07-31 06:59:02 +00001433if __name__ == '__main__':
Terry Jan Reedycfa89502014-07-14 23:07:32 -04001434 import unittest
1435 unittest.main('idlelib.idle_test.test_configdialog',
1436 verbosity=2, exit=False)
Terry Jan Reedy2e8234a2014-05-29 01:46:26 -04001437 from idlelib.idle_test.htest import run
Terry Jan Reedy47304c02015-10-20 02:15:28 -04001438 run(ConfigDialog)