blob: ec1de6cc05f93cad7b4f7630bca4e158272d0203 [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
Guido van Rossum8ce8a782007-11-01 19:42:39 +000019from idlelib.tabbedpages import TabbedPageSet
Kurt B. Kaiser2d7f6a02007-08-22 23:01:33 +000020from idlelib.keybindingDialog import GetKeysDialog
21from idlelib.configSectionNameDialog import GetCfgSectionNameDialog
22from idlelib.configHelpSourceEdit import GetHelpSourceDialog
Terry Jan Reedya9421fb2014-10-22 20:15:18 -040023from idlelib.tabbedpages import TabbedPageSet
Ronald Oussoren9e350042009-02-12 16:02:11 +000024from idlelib import macosxSupport
Steven M. Gava44d3d1a2001-07-31 06:59:02 +000025class ConfigDialog(Toplevel):
Kurt B. Kaiseracdef852005-01-31 03:34:26 +000026
Terry Jan Reedycd567362014-10-17 01:31:35 -040027 def __init__(self, parent, title='', _htest=False, _utest=False):
Terry Jan Reedy2e8234a2014-05-29 01:46:26 -040028 """
29 _htest - bool, change box location when running htest
Terry Jan Reedycfa89502014-07-14 23:07:32 -040030 _utest - bool, don't wait_window when running unittest
Terry Jan Reedy2e8234a2014-05-29 01:46:26 -040031 """
Steven M. Gavad721c482001-07-31 10:46:53 +000032 Toplevel.__init__(self, parent)
Terry Jan Reedy22405332014-07-30 19:24:32 -040033 self.parent = parent
Terry Jan Reedy4036d872014-08-03 23:02:58 -040034 if _htest:
35 parent.instance_dict = {}
Guido van Rossum8ce8a782007-11-01 19:42:39 +000036 self.wm_withdraw()
37
Steven M. Gavad721c482001-07-31 10:46:53 +000038 self.configure(borderwidth=5)
Terry Jan Reedycd567362014-10-17 01:31:35 -040039 self.title(title or 'IDLE Preferences')
Terry Jan Reedy4036d872014-08-03 23:02:58 -040040 self.geometry(
41 "+%d+%d" % (parent.winfo_rootx() + 20,
42 parent.winfo_rooty() + (30 if not _htest else 150)))
Georg Brandl7eb4b7d2005-07-22 21:49:32 +000043 #Theme Elements. Each theme element key is its display name.
Steven M. Gava9dd16b32001-11-03 14:54:25 +000044 #The first value of the tuple is the sample area tag name.
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +000045 #The second value is the display name list sort index.
Terry Jan Reedy4036d872014-08-03 23:02:58 -040046 self.themeElements={
47 'Normal Text':('normal', '00'),
48 'Python Keywords':('keyword', '01'),
49 'Python Definitions':('definition', '02'),
Kurt B. Kaiser73360a32004-03-08 18:15:31 +000050 'Python Builtins':('builtin', '03'),
Terry Jan Reedy4036d872014-08-03 23:02:58 -040051 'Python Comments':('comment', '04'),
52 'Python Strings':('string', '05'),
53 'Selected Text':('hilite', '06'),
54 'Found Text':('hit', '07'),
55 'Cursor':('cursor', '08'),
56 'Error Text':('error', '09'),
57 'Shell Normal Text':('console', '10'),
58 'Shell Stdout Text':('stdout', '11'),
59 'Shell Stderr Text':('stderr', '12'),
Kurt B. Kaiser73360a32004-03-08 18:15:31 +000060 }
Steven M. Gavaa498af22002-02-01 01:33:36 +000061 self.ResetChangedItems() #load initial values in changed items dict
Steven M. Gavad721c482001-07-31 10:46:53 +000062 self.CreateWidgets()
Terry Jan Reedy4036d872014-08-03 23:02:58 -040063 self.resizable(height=FALSE, width=FALSE)
Steven M. Gavad721c482001-07-31 10:46:53 +000064 self.transient(parent)
65 self.grab_set()
66 self.protocol("WM_DELETE_WINDOW", self.Cancel)
Steven M. Gava2d4e03b2001-12-05 07:54:07 +000067 self.tabPages.focus_set()
Steven M. Gavad721c482001-07-31 10:46:53 +000068 #key bindings for this dialog
Terry Jan Reedy4036d872014-08-03 23:02:58 -040069 #self.bind('<Escape>', self.Cancel) #dismiss dialog, no save
70 #self.bind('<Alt-a>', self.Apply) #apply changes, save
71 #self.bind('<F1>', self.Help) #context help
Steven M. Gava429a86af2001-10-23 10:42:12 +000072 self.LoadConfigs()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +000073 self.AttachVarCallbacks() #avoid callbacks during LoadConfigs
Guido van Rossum8ce8a782007-11-01 19:42:39 +000074
Terry Jan Reedycfa89502014-07-14 23:07:32 -040075 if not _utest:
76 self.wm_deiconify()
77 self.wait_window()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +000078
Steven M. Gavad721c482001-07-31 10:46:53 +000079 def CreateWidgets(self):
Guido van Rossum8ce8a782007-11-01 19:42:39 +000080 self.tabPages = TabbedPageSet(self,
Terry Jan Reedy4036d872014-08-03 23:02:58 -040081 page_names=['Fonts/Tabs', 'Highlighting', 'Keys', 'General'])
Terry Jan Reedy92cb0a32014-10-08 20:29:13 -040082 self.tabPages.pack(side=TOP, expand=TRUE, fill=BOTH)
83 self.CreatePageFontTab()
84 self.CreatePageHighlight()
85 self.CreatePageKeys()
86 self.CreatePageGeneral()
87 self.create_action_buttons().pack(side=BOTTOM)
Terry Jan Reedy92cb0a32014-10-08 20:29:13 -040088 def create_action_buttons(self):
Ned Deilyb7601672014-03-27 20:49:14 -070089 if macosxSupport.isAquaTk():
Terry Jan Reedye3416e62014-07-26 19:40:16 -040090 # Changing the default padding on OSX results in unreadable
91 # text in the buttons
Terry Jan Reedy4036d872014-08-03 23:02:58 -040092 paddingArgs = {}
Ronald Oussoren9e350042009-02-12 16:02:11 +000093 else:
Terry Jan Reedy4036d872014-08-03 23:02:58 -040094 paddingArgs = {'padx':6, 'pady':3}
Terry Jan Reedya9421fb2014-10-22 20:15:18 -040095 outer = Frame(self, pady=2)
96 buttons = Frame(outer, pady=2)
Terry Jan Reedy4036d872014-08-03 23:02:58 -040097 self.buttonOk = Button(
Terry Jan Reedya9421fb2014-10-22 20:15:18 -040098 buttons, text='Ok', command=self.Ok,
Terry Jan Reedy92cb0a32014-10-08 20:29:13 -040099 takefocus=FALSE, **paddingArgs)
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400100 self.buttonApply = Button(
Terry Jan Reedya9421fb2014-10-22 20:15:18 -0400101 buttons, text='Apply', command=self.Apply,
Terry Jan Reedy92cb0a32014-10-08 20:29:13 -0400102 takefocus=FALSE, **paddingArgs)
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400103 self.buttonCancel = Button(
Terry Jan Reedya9421fb2014-10-22 20:15:18 -0400104 buttons, text='Cancel', command=self.Cancel,
Terry Jan Reedy92cb0a32014-10-08 20:29:13 -0400105 takefocus=FALSE, **paddingArgs)
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400106 self.buttonOk.pack(side=LEFT, padx=5)
107 self.buttonApply.pack(side=LEFT, padx=5)
108 self.buttonCancel.pack(side=LEFT, padx=5)
Terry Jan Reedya9421fb2014-10-22 20:15:18 -0400109# Comment out Help button creation and packing until implement self.Help
110## self.buttonHelp = Button(
111## buttons, text='Help', command=self.Help,
112## takefocus=FALSE, **paddingArgs)
113## self.buttonHelp.pack(side=RIGHT, padx=5)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000114
Terry Jan Reedya9421fb2014-10-22 20:15:18 -0400115 # add space above buttons
116 Frame(outer, height=2, borderwidth=0).pack(side=TOP)
117 buttons.pack(side=BOTTOM)
118 return outer
Steven M. Gava60fc7072001-08-04 13:58:22 +0000119 def CreatePageFontTab(self):
Terry Jan Reedy22405332014-07-30 19:24:32 -0400120 parent = self.parent
121 self.fontSize = StringVar(parent)
122 self.fontBold = BooleanVar(parent)
123 self.fontName = StringVar(parent)
124 self.spaceNum = IntVar(parent)
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400125 self.editFont = tkFont.Font(parent, ('courier', 10, 'normal'))
Terry Jan Reedy22405332014-07-30 19:24:32 -0400126
Steven M. Gavaf213ccb2001-08-05 08:00:28 +0000127 ##widget creation
128 #body frame
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400129 frame = self.tabPages.pages['Fonts/Tabs'].frame
Steven M. Gavaf213ccb2001-08-05 08:00:28 +0000130 #body section frames
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400131 frameFont = LabelFrame(
132 frame, borderwidth=2, relief=GROOVE, text=' Base Editor Font ')
133 frameIndent = LabelFrame(
134 frame, borderwidth=2, relief=GROOVE, text=' Indentation Width ')
Steven M. Gavaf213ccb2001-08-05 08:00:28 +0000135 #frameFont
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400136 frameFontName = Frame(frameFont)
137 frameFontParam = Frame(frameFont)
138 labelFontNameTitle = Label(
139 frameFontName, justify=LEFT, text='Font Face :')
140 self.listFontName = Listbox(
141 frameFontName, height=5, takefocus=FALSE, exportselection=FALSE)
142 self.listFontName.bind(
143 '<ButtonRelease-1>', self.OnListFontButtonRelease)
144 scrollFont = Scrollbar(frameFontName)
Steven M. Gavac01e30f2001-08-11 15:48:13 +0000145 scrollFont.config(command=self.listFontName.yview)
146 self.listFontName.config(yscrollcommand=scrollFont.set)
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400147 labelFontSizeTitle = Label(frameFontParam, text='Size :')
148 self.optMenuFontSize = DynOptionMenu(
149 frameFontParam, self.fontSize, None, command=self.SetFontSample)
150 checkFontBold = Checkbutton(
151 frameFontParam, variable=self.fontBold, onvalue=1,
152 offvalue=0, text='Bold', command=self.SetFontSample)
153 frameFontSample = Frame(frameFont, relief=SOLID, borderwidth=1)
154 self.labelFontSample = Label(
155 frameFontSample, justify=LEFT, font=self.editFont,
156 text='AaBbCcDdEe\nFfGgHhIiJjK\n1234567890\n#:+=(){}[]')
Steven M. Gavaf213ccb2001-08-05 08:00:28 +0000157 #frameIndent
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400158 frameIndentSize = Frame(frameIndent)
159 labelSpaceNumTitle = Label(
160 frameIndentSize, justify=LEFT,
161 text='Python Standard: 4 Spaces!')
162 self.scaleSpaceNum = Scale(
163 frameIndentSize, variable=self.spaceNum,
164 orient='horizontal', tickinterval=2, from_=2, to=16)
Terry Jan Reedy22405332014-07-30 19:24:32 -0400165
Steven M. Gavaf213ccb2001-08-05 08:00:28 +0000166 #widget packing
167 #body
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400168 frameFont.pack(side=LEFT, padx=5, pady=5, expand=TRUE, fill=BOTH)
169 frameIndent.pack(side=LEFT, padx=5, pady=5, fill=Y)
Steven M. Gavaf213ccb2001-08-05 08:00:28 +0000170 #frameFont
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400171 frameFontName.pack(side=TOP, padx=5, pady=5, fill=X)
172 frameFontParam.pack(side=TOP, padx=5, pady=5, fill=X)
173 labelFontNameTitle.pack(side=TOP, anchor=W)
174 self.listFontName.pack(side=LEFT, expand=TRUE, fill=X)
175 scrollFont.pack(side=LEFT, fill=Y)
176 labelFontSizeTitle.pack(side=LEFT, anchor=W)
177 self.optMenuFontSize.pack(side=LEFT, anchor=W)
178 checkFontBold.pack(side=LEFT, anchor=W, padx=20)
179 frameFontSample.pack(side=TOP, padx=5, pady=5, expand=TRUE, fill=BOTH)
180 self.labelFontSample.pack(expand=TRUE, fill=BOTH)
Steven M. Gavaf213ccb2001-08-05 08:00:28 +0000181 #frameIndent
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400182 frameIndentSize.pack(side=TOP, fill=X)
183 labelSpaceNumTitle.pack(side=TOP, anchor=W, padx=5)
184 self.scaleSpaceNum.pack(side=TOP, padx=5, fill=X)
Steven M. Gava952d0a52001-08-03 04:43:44 +0000185 return frame
186
187 def CreatePageHighlight(self):
Terry Jan Reedy22405332014-07-30 19:24:32 -0400188 parent = self.parent
189 self.builtinTheme = StringVar(parent)
190 self.customTheme = StringVar(parent)
191 self.fgHilite = BooleanVar(parent)
192 self.colour = StringVar(parent)
193 self.fontName = StringVar(parent)
194 self.themeIsBuiltin = BooleanVar(parent)
195 self.highlightTarget = StringVar(parent)
196
Steven M. Gava952d0a52001-08-03 04:43:44 +0000197 ##widget creation
198 #body frame
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400199 frame = self.tabPages.pages['Highlighting'].frame
Steven M. Gava952d0a52001-08-03 04:43:44 +0000200 #body section frames
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400201 frameCustom = LabelFrame(frame, borderwidth=2, relief=GROOVE,
202 text=' Custom Highlighting ')
203 frameTheme = LabelFrame(frame, borderwidth=2, relief=GROOVE,
204 text=' Highlighting Theme ')
Steven M. Gava952d0a52001-08-03 04:43:44 +0000205 #frameCustom
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400206 self.textHighlightSample=Text(
207 frameCustom, relief=SOLID, borderwidth=1,
208 font=('courier', 12, ''), cursor='hand2', width=21, height=11,
209 takefocus=FALSE, highlightthickness=0, wrap=NONE)
Steven M. Gavae16d94b2001-11-03 05:07:28 +0000210 text=self.textHighlightSample
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400211 text.bind('<Double-Button-1>', lambda e: 'break')
212 text.bind('<B1-Motion>', lambda e: 'break')
213 textAndTags=(
214 ('#you can click here', 'comment'), ('\n', 'normal'),
215 ('#to choose items', 'comment'), ('\n', 'normal'),
216 ('def', 'keyword'), (' ', 'normal'),
217 ('func', 'definition'), ('(param):\n ', 'normal'),
218 ('"""string"""', 'string'), ('\n var0 = ', 'normal'),
219 ("'string'", 'string'), ('\n var1 = ', 'normal'),
220 ("'selected'", 'hilite'), ('\n var2 = ', 'normal'),
221 ("'found'", 'hit'), ('\n var3 = ', 'normal'),
222 ('list', 'builtin'), ('(', 'normal'),
223 ('None', 'keyword'), (')\n\n', 'normal'),
224 (' error ', 'error'), (' ', 'normal'),
225 ('cursor |', 'cursor'), ('\n ', 'normal'),
226 ('shell', 'console'), (' ', 'normal'),
227 ('stdout', 'stdout'), (' ', 'normal'),
228 ('stderr', 'stderr'), ('\n', 'normal'))
Steven M. Gava9dd16b32001-11-03 14:54:25 +0000229 for txTa in textAndTags:
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400230 text.insert(END, txTa[0], txTa[1])
Kurt B. Kaisere0712772007-08-23 05:25:55 +0000231 for element in self.themeElements:
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400232 def tem(event, elem=element):
233 event.widget.winfo_toplevel().highlightTarget.set(elem)
234 text.tag_bind(
235 self.themeElements[element][0], '<ButtonPress-1>', tem)
Steven M. Gavae16d94b2001-11-03 05:07:28 +0000236 text.config(state=DISABLED)
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400237 self.frameColourSet = Frame(frameCustom, relief=SOLID, borderwidth=1)
238 frameFgBg = Frame(frameCustom)
239 buttonSetColour = Button(
240 self.frameColourSet, text='Choose Colour for :',
241 command=self.GetColour, highlightthickness=0)
242 self.optMenuHighlightTarget = DynOptionMenu(
243 self.frameColourSet, self.highlightTarget, None,
244 highlightthickness=0) #, command=self.SetHighlightTargetBinding
245 self.radioFg = Radiobutton(
246 frameFgBg, variable=self.fgHilite, value=1,
247 text='Foreground', command=self.SetColourSampleBinding)
248 self.radioBg=Radiobutton(
249 frameFgBg, variable=self.fgHilite, value=0,
250 text='Background', command=self.SetColourSampleBinding)
Steven M. Gava7c017862001-10-29 11:19:46 +0000251 self.fgHilite.set(1)
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400252 buttonSaveCustomTheme = Button(
253 frameCustom, text='Save as New Custom Theme',
254 command=self.SaveAsNewTheme)
Steven M. Gava952d0a52001-08-03 04:43:44 +0000255 #frameTheme
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400256 labelTypeTitle = Label(frameTheme, text='Select : ')
257 self.radioThemeBuiltin = Radiobutton(
258 frameTheme, variable=self.themeIsBuiltin, value=1,
259 command=self.SetThemeType, text='a Built-in Theme')
260 self.radioThemeCustom = Radiobutton(
261 frameTheme, variable=self.themeIsBuiltin, value=0,
262 command=self.SetThemeType, text='a Custom Theme')
263 self.optMenuThemeBuiltin = DynOptionMenu(
264 frameTheme, self.builtinTheme, None, command=None)
265 self.optMenuThemeCustom=DynOptionMenu(
266 frameTheme, self.customTheme, None, command=None)
267 self.buttonDeleteCustomTheme=Button(
268 frameTheme, text='Delete Custom Theme',
Steven M. Gava49745752002-02-18 01:43:11 +0000269 command=self.DeleteCustomTheme)
Terry Jan Reedy22405332014-07-30 19:24:32 -0400270
Steven M. Gava952d0a52001-08-03 04:43:44 +0000271 ##widget packing
272 #body
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400273 frameCustom.pack(side=LEFT, padx=5, pady=5, expand=TRUE, fill=BOTH)
274 frameTheme.pack(side=LEFT, padx=5, pady=5, fill=Y)
Steven M. Gava952d0a52001-08-03 04:43:44 +0000275 #frameCustom
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400276 self.frameColourSet.pack(side=TOP, padx=5, pady=5, expand=TRUE, fill=X)
277 frameFgBg.pack(side=TOP, padx=5, pady=0)
278 self.textHighlightSample.pack(
279 side=TOP, padx=5, pady=5, expand=TRUE, fill=BOTH)
280 buttonSetColour.pack(side=TOP, expand=TRUE, fill=X, padx=8, pady=4)
281 self.optMenuHighlightTarget.pack(
282 side=TOP, expand=TRUE, fill=X, padx=8, pady=3)
283 self.radioFg.pack(side=LEFT, anchor=E)
284 self.radioBg.pack(side=RIGHT, anchor=W)
285 buttonSaveCustomTheme.pack(side=BOTTOM, fill=X, padx=5, pady=5)
Steven M. Gava952d0a52001-08-03 04:43:44 +0000286 #frameTheme
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400287 labelTypeTitle.pack(side=TOP, anchor=W, padx=5, pady=5)
288 self.radioThemeBuiltin.pack(side=TOP, anchor=W, padx=5)
289 self.radioThemeCustom.pack(side=TOP, anchor=W, padx=5, pady=2)
290 self.optMenuThemeBuiltin.pack(side=TOP, fill=X, padx=5, pady=5)
291 self.optMenuThemeCustom.pack(side=TOP, fill=X, anchor=W, padx=5, pady=5)
292 self.buttonDeleteCustomTheme.pack(side=TOP, fill=X, padx=5, pady=5)
Steven M. Gava952d0a52001-08-03 04:43:44 +0000293 return frame
294
295 def CreatePageKeys(self):
Terry Jan Reedy22405332014-07-30 19:24:32 -0400296 parent = self.parent
297 self.bindingTarget = StringVar(parent)
298 self.builtinKeys = StringVar(parent)
299 self.customKeys = StringVar(parent)
300 self.keysAreBuiltin = BooleanVar(parent)
301 self.keyBinding = StringVar(parent)
302
Steven M. Gava60fc7072001-08-04 13:58:22 +0000303 ##widget creation
304 #body frame
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400305 frame = self.tabPages.pages['Keys'].frame
Steven M. Gava60fc7072001-08-04 13:58:22 +0000306 #body section frames
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400307 frameCustom = LabelFrame(
308 frame, borderwidth=2, relief=GROOVE,
309 text=' Custom Key Bindings ')
310 frameKeySets = LabelFrame(
311 frame, borderwidth=2, relief=GROOVE, text=' Key Set ')
Steven M. Gava60fc7072001-08-04 13:58:22 +0000312 #frameCustom
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400313 frameTarget = Frame(frameCustom)
314 labelTargetTitle = Label(frameTarget, text='Action - Key(s)')
315 scrollTargetY = Scrollbar(frameTarget)
316 scrollTargetX = Scrollbar(frameTarget, orient=HORIZONTAL)
317 self.listBindings = Listbox(
318 frameTarget, takefocus=FALSE, exportselection=FALSE)
319 self.listBindings.bind('<ButtonRelease-1>', self.KeyBindingSelected)
Steven M. Gavafacfc092002-01-19 00:29:54 +0000320 scrollTargetY.config(command=self.listBindings.yview)
321 scrollTargetX.config(command=self.listBindings.xview)
322 self.listBindings.config(yscrollcommand=scrollTargetY.set)
323 self.listBindings.config(xscrollcommand=scrollTargetX.set)
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400324 self.buttonNewKeys = Button(
325 frameCustom, text='Get New Keys for Selection',
326 command=self.GetNewKeys, state=DISABLED)
Steven M. Gava60fc7072001-08-04 13:58:22 +0000327 #frameKeySets
Christian Heimes9a371592007-12-28 14:08:13 +0000328 frames = [Frame(frameKeySets, padx=2, pady=2, borderwidth=0)
329 for i in range(2)]
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400330 self.radioKeysBuiltin = Radiobutton(
331 frames[0], variable=self.keysAreBuiltin, value=1,
332 command=self.SetKeysType, text='Use a Built-in Key Set')
333 self.radioKeysCustom = Radiobutton(
334 frames[0], variable=self.keysAreBuiltin, value=0,
335 command=self.SetKeysType, text='Use a Custom Key Set')
336 self.optMenuKeysBuiltin = DynOptionMenu(
337 frames[0], self.builtinKeys, None, command=None)
338 self.optMenuKeysCustom = DynOptionMenu(
339 frames[0], self.customKeys, None, command=None)
340 self.buttonDeleteCustomKeys = Button(
341 frames[1], text='Delete Custom Key Set',
Steven M. Gava49745752002-02-18 01:43:11 +0000342 command=self.DeleteCustomKeys)
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400343 buttonSaveCustomKeys = Button(
344 frames[1], text='Save as New Custom Key Set',
345 command=self.SaveAsNewKeySet)
Terry Jan Reedy22405332014-07-30 19:24:32 -0400346
Steven M. Gava60fc7072001-08-04 13:58:22 +0000347 ##widget packing
348 #body
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400349 frameCustom.pack(side=BOTTOM, padx=5, pady=5, expand=TRUE, fill=BOTH)
350 frameKeySets.pack(side=BOTTOM, padx=5, pady=5, fill=BOTH)
Steven M. Gava60fc7072001-08-04 13:58:22 +0000351 #frameCustom
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400352 self.buttonNewKeys.pack(side=BOTTOM, fill=X, padx=5, pady=5)
353 frameTarget.pack(side=LEFT, padx=5, pady=5, expand=TRUE, fill=BOTH)
Steven M. Gavafacfc092002-01-19 00:29:54 +0000354 #frame target
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400355 frameTarget.columnconfigure(0, weight=1)
356 frameTarget.rowconfigure(1, weight=1)
357 labelTargetTitle.grid(row=0, column=0, columnspan=2, sticky=W)
358 self.listBindings.grid(row=1, column=0, sticky=NSEW)
359 scrollTargetY.grid(row=1, column=1, sticky=NS)
360 scrollTargetX.grid(row=2, column=0, sticky=EW)
Steven M. Gava60fc7072001-08-04 13:58:22 +0000361 #frameKeySets
Christian Heimes9a371592007-12-28 14:08:13 +0000362 self.radioKeysBuiltin.grid(row=0, column=0, sticky=W+NS)
363 self.radioKeysCustom.grid(row=1, column=0, sticky=W+NS)
364 self.optMenuKeysBuiltin.grid(row=0, column=1, sticky=NSEW)
365 self.optMenuKeysCustom.grid(row=1, column=1, sticky=NSEW)
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400366 self.buttonDeleteCustomKeys.pack(side=LEFT, fill=X, expand=True, padx=2)
367 buttonSaveCustomKeys.pack(side=LEFT, fill=X, expand=True, padx=2)
Christian Heimes9a371592007-12-28 14:08:13 +0000368 frames[0].pack(side=TOP, fill=BOTH, expand=True)
369 frames[1].pack(side=TOP, fill=X, expand=True, pady=2)
Steven M. Gava952d0a52001-08-03 04:43:44 +0000370 return frame
371
372 def CreatePageGeneral(self):
Terry Jan Reedy22405332014-07-30 19:24:32 -0400373 parent = self.parent
374 self.winWidth = StringVar(parent)
375 self.winHeight = StringVar(parent)
Terry Jan Reedy22405332014-07-30 19:24:32 -0400376 self.startupEdit = IntVar(parent)
377 self.autoSave = IntVar(parent)
378 self.encoding = StringVar(parent)
379 self.userHelpBrowser = BooleanVar(parent)
380 self.helpBrowser = StringVar(parent)
381
Steven M. Gava230e5782001-08-07 03:28:25 +0000382 #widget creation
383 #body
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400384 frame = self.tabPages.pages['General'].frame
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000385 #body section frames
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400386 frameRun = LabelFrame(frame, borderwidth=2, relief=GROOVE,
387 text=' Startup Preferences ')
388 frameSave = LabelFrame(frame, borderwidth=2, relief=GROOVE,
389 text=' Autosave Preferences ')
390 frameWinSize = Frame(frame, borderwidth=2, relief=GROOVE)
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400391 frameHelp = LabelFrame(frame, borderwidth=2, relief=GROOVE,
392 text=' Additional Help Sources ')
Steven M. Gava230e5782001-08-07 03:28:25 +0000393 #frameRun
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400394 labelRunChoiceTitle = Label(frameRun, text='At Startup')
395 radioStartupEdit = Radiobutton(
396 frameRun, variable=self.startupEdit, value=1,
397 command=self.SetKeysType, text="Open Edit Window")
398 radioStartupShell = Radiobutton(
399 frameRun, variable=self.startupEdit, value=0,
400 command=self.SetKeysType, text='Open Shell Window')
Kurt B. Kaiser6c638b62003-05-26 06:23:10 +0000401 #frameSave
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400402 labelRunSaveTitle = Label(frameSave, text='At Start of Run (F5) ')
403 radioSaveAsk = Radiobutton(
404 frameSave, variable=self.autoSave, value=0,
405 command=self.SetKeysType, text="Prompt to Save")
406 radioSaveAuto = Radiobutton(
407 frameSave, variable=self.autoSave, value=1,
408 command=self.SetKeysType, text='No Prompt')
Steven M. Gava230e5782001-08-07 03:28:25 +0000409 #frameWinSize
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400410 labelWinSizeTitle = Label(
411 frameWinSize, text='Initial Window Size (in characters)')
412 labelWinWidthTitle = Label(frameWinSize, text='Width')
413 entryWinWidth = Entry(
414 frameWinSize, textvariable=self.winWidth, width=3)
415 labelWinHeightTitle = Label(frameWinSize, text='Height')
416 entryWinHeight = Entry(
417 frameWinSize, textvariable=self.winHeight, width=3)
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000418 #frameHelp
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400419 frameHelpList = Frame(frameHelp)
420 frameHelpListButtons = Frame(frameHelpList)
421 scrollHelpList = Scrollbar(frameHelpList)
422 self.listHelp = Listbox(
423 frameHelpList, height=5, takefocus=FALSE,
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000424 exportselection=FALSE)
425 scrollHelpList.config(command=self.listHelp.yview)
426 self.listHelp.config(yscrollcommand=scrollHelpList.set)
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400427 self.listHelp.bind('<ButtonRelease-1>', self.HelpSourceSelected)
428 self.buttonHelpListEdit = Button(
429 frameHelpListButtons, text='Edit', state=DISABLED,
430 width=8, command=self.HelpListItemEdit)
431 self.buttonHelpListAdd = Button(
432 frameHelpListButtons, text='Add',
433 width=8, command=self.HelpListItemAdd)
434 self.buttonHelpListRemove = Button(
435 frameHelpListButtons, text='Remove', state=DISABLED,
436 width=8, command=self.HelpListItemRemove)
Terry Jan Reedy22405332014-07-30 19:24:32 -0400437
Steven M. Gava230e5782001-08-07 03:28:25 +0000438 #widget packing
439 #body
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400440 frameRun.pack(side=TOP, padx=5, pady=5, fill=X)
441 frameSave.pack(side=TOP, padx=5, pady=5, fill=X)
442 frameWinSize.pack(side=TOP, padx=5, pady=5, fill=X)
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400443 frameHelp.pack(side=TOP, padx=5, pady=5, expand=TRUE, fill=BOTH)
Steven M. Gava230e5782001-08-07 03:28:25 +0000444 #frameRun
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400445 labelRunChoiceTitle.pack(side=LEFT, anchor=W, padx=5, pady=5)
446 radioStartupShell.pack(side=RIGHT, anchor=W, padx=5, pady=5)
447 radioStartupEdit.pack(side=RIGHT, anchor=W, padx=5, pady=5)
Kurt B. Kaiser6c638b62003-05-26 06:23:10 +0000448 #frameSave
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400449 labelRunSaveTitle.pack(side=LEFT, anchor=W, padx=5, pady=5)
450 radioSaveAuto.pack(side=RIGHT, anchor=W, padx=5, pady=5)
451 radioSaveAsk.pack(side=RIGHT, anchor=W, padx=5, pady=5)
Steven M. Gava230e5782001-08-07 03:28:25 +0000452 #frameWinSize
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400453 labelWinSizeTitle.pack(side=LEFT, anchor=W, padx=5, pady=5)
454 entryWinHeight.pack(side=RIGHT, anchor=E, padx=10, pady=5)
455 labelWinHeightTitle.pack(side=RIGHT, anchor=E, pady=5)
456 entryWinWidth.pack(side=RIGHT, anchor=E, padx=10, pady=5)
457 labelWinWidthTitle.pack(side=RIGHT, anchor=E, pady=5)
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000458 #frameHelp
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400459 frameHelpListButtons.pack(side=RIGHT, padx=5, pady=5, fill=Y)
460 frameHelpList.pack(side=TOP, padx=5, pady=5, expand=TRUE, fill=BOTH)
461 scrollHelpList.pack(side=RIGHT, anchor=W, fill=Y)
462 self.listHelp.pack(side=LEFT, anchor=E, expand=TRUE, fill=BOTH)
463 self.buttonHelpListEdit.pack(side=TOP, anchor=W, pady=5)
464 self.buttonHelpListAdd.pack(side=TOP, anchor=W)
465 self.buttonHelpListRemove.pack(side=TOP, anchor=W, pady=5)
Steven M. Gava952d0a52001-08-03 04:43:44 +0000466 return frame
467
Steven M. Gavac112cd82002-01-22 05:56:40 +0000468 def AttachVarCallbacks(self):
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400469 self.fontSize.trace_variable('w', self.VarChanged_fontSize)
470 self.fontName.trace_variable('w', self.VarChanged_fontName)
471 self.fontBold.trace_variable('w', self.VarChanged_fontBold)
472 self.spaceNum.trace_variable('w', self.VarChanged_spaceNum)
473 self.colour.trace_variable('w', self.VarChanged_colour)
474 self.builtinTheme.trace_variable('w', self.VarChanged_builtinTheme)
475 self.customTheme.trace_variable('w', self.VarChanged_customTheme)
476 self.themeIsBuiltin.trace_variable('w', self.VarChanged_themeIsBuiltin)
477 self.highlightTarget.trace_variable('w', self.VarChanged_highlightTarget)
478 self.keyBinding.trace_variable('w', self.VarChanged_keyBinding)
479 self.builtinKeys.trace_variable('w', self.VarChanged_builtinKeys)
480 self.customKeys.trace_variable('w', self.VarChanged_customKeys)
481 self.keysAreBuiltin.trace_variable('w', self.VarChanged_keysAreBuiltin)
482 self.winWidth.trace_variable('w', self.VarChanged_winWidth)
483 self.winHeight.trace_variable('w', self.VarChanged_winHeight)
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400484 self.startupEdit.trace_variable('w', self.VarChanged_startupEdit)
485 self.autoSave.trace_variable('w', self.VarChanged_autoSave)
486 self.encoding.trace_variable('w', self.VarChanged_encoding)
Steven M. Gava052937f2002-02-11 02:20:53 +0000487
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400488 def VarChanged_fontSize(self, *params):
489 value = self.fontSize.get()
490 self.AddChangedItem('main', 'EditorWindow', 'font-size', value)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000491
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400492 def VarChanged_fontName(self, *params):
493 value = self.fontName.get()
494 self.AddChangedItem('main', 'EditorWindow', 'font', value)
Steven M. Gavac112cd82002-01-22 05:56:40 +0000495
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400496 def VarChanged_fontBold(self, *params):
497 value = self.fontBold.get()
498 self.AddChangedItem('main', 'EditorWindow', 'font-bold', value)
Steven M. Gavac112cd82002-01-22 05:56:40 +0000499
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400500 def VarChanged_spaceNum(self, *params):
501 value = self.spaceNum.get()
502 self.AddChangedItem('main', 'Indent', 'num-spaces', value)
Steven M. Gavac112cd82002-01-22 05:56:40 +0000503
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400504 def VarChanged_colour(self, *params):
Steven M. Gava052937f2002-02-11 02:20:53 +0000505 self.OnNewColourSet()
506
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400507 def VarChanged_builtinTheme(self, *params):
508 value = self.builtinTheme.get()
509 self.AddChangedItem('main', 'Theme', 'name', value)
Steven M. Gava052937f2002-02-11 02:20:53 +0000510 self.PaintThemeSample()
511
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400512 def VarChanged_customTheme(self, *params):
513 value = self.customTheme.get()
Steven M. Gava49745752002-02-18 01:43:11 +0000514 if value != '- no custom themes -':
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400515 self.AddChangedItem('main', 'Theme', 'name', value)
Steven M. Gava49745752002-02-18 01:43:11 +0000516 self.PaintThemeSample()
Steven M. Gava052937f2002-02-11 02:20:53 +0000517
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400518 def VarChanged_themeIsBuiltin(self, *params):
519 value = self.themeIsBuiltin.get()
520 self.AddChangedItem('main', 'Theme', 'default', value)
Steven M. Gavaf31eec02002-03-05 00:25:58 +0000521 if value:
522 self.VarChanged_builtinTheme()
523 else:
524 self.VarChanged_customTheme()
Steven M. Gava052937f2002-02-11 02:20:53 +0000525
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400526 def VarChanged_highlightTarget(self, *params):
Steven M. Gava052937f2002-02-11 02:20:53 +0000527 self.SetHighlightTarget()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000528
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400529 def VarChanged_keyBinding(self, *params):
530 value = self.keyBinding.get()
531 keySet = self.customKeys.get()
532 event = self.listBindings.get(ANCHOR).split()[0]
Steven M. Gavaa498af22002-02-01 01:33:36 +0000533 if idleConf.IsCoreBinding(event):
534 #this is a core keybinding
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400535 self.AddChangedItem('keys', keySet, event, value)
Steven M. Gavaa498af22002-02-01 01:33:36 +0000536 else: #this is an extension key binding
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400537 extName = idleConf.GetExtnNameForEvent(event)
538 extKeybindSection = extName + '_cfgBindings'
539 self.AddChangedItem('extensions', extKeybindSection, event, value)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000540
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400541 def VarChanged_builtinKeys(self, *params):
542 value = self.builtinKeys.get()
543 self.AddChangedItem('main', 'Keys', 'name', value)
Steven M. Gava052937f2002-02-11 02:20:53 +0000544 self.LoadKeysList(value)
545
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400546 def VarChanged_customKeys(self, *params):
547 value = self.customKeys.get()
Steven M. Gava49745752002-02-18 01:43:11 +0000548 if value != '- no custom keys -':
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400549 self.AddChangedItem('main', 'Keys', 'name', value)
Steven M. Gava49745752002-02-18 01:43:11 +0000550 self.LoadKeysList(value)
Steven M. Gava052937f2002-02-11 02:20:53 +0000551
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400552 def VarChanged_keysAreBuiltin(self, *params):
553 value = self.keysAreBuiltin.get()
554 self.AddChangedItem('main', 'Keys', 'default', value)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000555 if value:
Steven M. Gavaf31eec02002-03-05 00:25:58 +0000556 self.VarChanged_builtinKeys()
Steven M. Gava052937f2002-02-11 02:20:53 +0000557 else:
Steven M. Gavaf31eec02002-03-05 00:25:58 +0000558 self.VarChanged_customKeys()
Steven M. Gava052937f2002-02-11 02:20:53 +0000559
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400560 def VarChanged_winWidth(self, *params):
561 value = self.winWidth.get()
562 self.AddChangedItem('main', 'EditorWindow', 'width', value)
Steven M. Gavac112cd82002-01-22 05:56:40 +0000563
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400564 def VarChanged_winHeight(self, *params):
565 value = self.winHeight.get()
566 self.AddChangedItem('main', 'EditorWindow', 'height', value)
Steven M. Gavac112cd82002-01-22 05:56:40 +0000567
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400568 def VarChanged_startupEdit(self, *params):
569 value = self.startupEdit.get()
570 self.AddChangedItem('main', 'General', 'editor-on-startup', value)
Steven M. Gavac112cd82002-01-22 05:56:40 +0000571
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400572 def VarChanged_autoSave(self, *params):
573 value = self.autoSave.get()
574 self.AddChangedItem('main', 'General', 'autosave', value)
Kurt B. Kaiser6c638b62003-05-26 06:23:10 +0000575
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400576 def VarChanged_encoding(self, *params):
577 value = self.encoding.get()
578 self.AddChangedItem('main', 'EditorWindow', 'encoding', value)
Kurt B. Kaisera053f332003-05-10 00:49:56 +0000579
Steven M. Gavaa498af22002-02-01 01:33:36 +0000580 def ResetChangedItems(self):
Steven M. Gavab77d3432002-03-02 07:16:21 +0000581 #When any config item is changed in this dialog, an entry
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000582 #should be made in the relevant section (config type) of this
583 #dictionary. The key should be the config file section name and the
Steven M. Gavaa498af22002-02-01 01:33:36 +0000584 #value a dictionary, whose key:value pairs are item=value pairs for
585 #that config file section.
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400586 self.changedItems = {'main':{}, 'highlight':{}, 'keys':{},
587 'extensions':{}}
Steven M. Gavaa498af22002-02-01 01:33:36 +0000588
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400589 def AddChangedItem(self, typ, section, item, value):
590 value = str(value) #make sure we use a string
591 if section not in self.changedItems[typ]:
592 self.changedItems[typ][section] = {}
593 self.changedItems[typ][section][item] = value
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000594
Steven M. Gava5f28e8f2002-01-21 06:38:21 +0000595 def GetDefaultItems(self):
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400596 dItems={'main':{}, 'highlight':{}, 'keys':{}, 'extensions':{}}
Kurt B. Kaisere0712772007-08-23 05:25:55 +0000597 for configType in dItems:
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400598 sections = idleConf.GetSectionList('default', configType)
Steven M. Gava5f28e8f2002-01-21 06:38:21 +0000599 for section in sections:
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400600 dItems[configType][section] = {}
601 options = idleConf.defaultCfg[configType].GetOptionList(section)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000602 for option in options:
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400603 dItems[configType][section][option] = (
604 idleConf.defaultCfg[configType].Get(section, option))
Steven M. Gava5f28e8f2002-01-21 06:38:21 +0000605 return dItems
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000606
Steven M. Gava5f28e8f2002-01-21 06:38:21 +0000607 def SetThemeType(self):
608 if self.themeIsBuiltin.get():
609 self.optMenuThemeBuiltin.config(state=NORMAL)
610 self.optMenuThemeCustom.config(state=DISABLED)
611 self.buttonDeleteCustomTheme.config(state=DISABLED)
612 else:
613 self.optMenuThemeBuiltin.config(state=DISABLED)
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000614 self.radioThemeCustom.config(state=NORMAL)
Steven M. Gava5f28e8f2002-01-21 06:38:21 +0000615 self.optMenuThemeCustom.config(state=NORMAL)
616 self.buttonDeleteCustomTheme.config(state=NORMAL)
617
618 def SetKeysType(self):
Steven M. Gava052937f2002-02-11 02:20:53 +0000619 if self.keysAreBuiltin.get():
Steven M. Gava5f28e8f2002-01-21 06:38:21 +0000620 self.optMenuKeysBuiltin.config(state=NORMAL)
621 self.optMenuKeysCustom.config(state=DISABLED)
622 self.buttonDeleteCustomKeys.config(state=DISABLED)
623 else:
624 self.optMenuKeysBuiltin.config(state=DISABLED)
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000625 self.radioKeysCustom.config(state=NORMAL)
Steven M. Gava5f28e8f2002-01-21 06:38:21 +0000626 self.optMenuKeysCustom.config(state=NORMAL)
627 self.buttonDeleteCustomKeys.config(state=NORMAL)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000628
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000629 def GetNewKeys(self):
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400630 listIndex = self.listBindings.index(ANCHOR)
631 binding = self.listBindings.get(listIndex)
632 bindName = binding.split()[0] #first part, up to first space
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000633 if self.keysAreBuiltin.get():
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400634 currentKeySetName = self.builtinKeys.get()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000635 else:
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400636 currentKeySetName = self.customKeys.get()
637 currentBindings = idleConf.GetCurrentKeySet()
Kurt B. Kaisere0712772007-08-23 05:25:55 +0000638 if currentKeySetName in self.changedItems['keys']: #unsaved changes
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400639 keySetChanges = self.changedItems['keys'][currentKeySetName]
Kurt B. Kaisere0712772007-08-23 05:25:55 +0000640 for event in keySetChanges:
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400641 currentBindings[event] = keySetChanges[event].split()
Kurt B. Kaisere0712772007-08-23 05:25:55 +0000642 currentKeySequences = list(currentBindings.values())
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400643 newKeys = GetKeysDialog(self, 'Get New Keys', bindName,
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000644 currentKeySequences).result
645 if newKeys: #new keys were specified
Steven M. Gava052937f2002-02-11 02:20:53 +0000646 if self.keysAreBuiltin.get(): #current key set is a built-in
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400647 message = ('Your changes will be saved as a new Custom Key Set.'
648 ' Enter a name for your new Custom Key Set below.')
649 newKeySet = self.GetNewKeysName(message)
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000650 if not newKeySet: #user cancelled custom key set creation
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000651 self.listBindings.select_set(listIndex)
652 self.listBindings.select_anchor(listIndex)
653 return
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000654 else: #create new custom key set based on previously active key set
655 self.CreateNewKeySet(newKeySet)
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000656 self.listBindings.delete(listIndex)
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400657 self.listBindings.insert(listIndex, bindName+' - '+newKeys)
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000658 self.listBindings.select_set(listIndex)
659 self.listBindings.select_anchor(listIndex)
Steven M. Gava052937f2002-02-11 02:20:53 +0000660 self.keyBinding.set(newKeys)
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000661 else:
662 self.listBindings.select_set(listIndex)
663 self.listBindings.select_anchor(listIndex)
664
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400665 def GetNewKeysName(self, message):
666 usedNames = (idleConf.GetSectionList('user', 'keys') +
667 idleConf.GetSectionList('default', 'keys'))
668 newKeySet = GetCfgSectionNameDialog(
669 self, 'New Custom Key Set', message, usedNames).result
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000670 return newKeySet
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000671
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000672 def SaveAsNewKeySet(self):
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400673 newKeysName = self.GetNewKeysName('New Key Set Name:')
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000674 if newKeysName:
675 self.CreateNewKeySet(newKeysName)
676
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400677 def KeyBindingSelected(self, event):
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000678 self.buttonNewKeys.config(state=NORMAL)
679
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400680 def CreateNewKeySet(self, newKeySetName):
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000681 #creates new custom key set based on the previously active key set,
682 #and makes the new key set active
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000683 if self.keysAreBuiltin.get():
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400684 prevKeySetName = self.builtinKeys.get()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000685 else:
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400686 prevKeySetName = self.customKeys.get()
687 prevKeys = idleConf.GetCoreKeys(prevKeySetName)
688 newKeys = {}
Kurt B. Kaisere0712772007-08-23 05:25:55 +0000689 for event in prevKeys: #add key set to changed items
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400690 eventName = event[2:-2] #trim off the angle brackets
691 binding = ' '.join(prevKeys[event])
692 newKeys[eventName] = binding
Steven M. Gava052937f2002-02-11 02:20:53 +0000693 #handle any unsaved changes to prev key set
Kurt B. Kaisere0712772007-08-23 05:25:55 +0000694 if prevKeySetName in self.changedItems['keys']:
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400695 keySetChanges = self.changedItems['keys'][prevKeySetName]
Kurt B. Kaisere0712772007-08-23 05:25:55 +0000696 for event in keySetChanges:
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400697 newKeys[event] = keySetChanges[event]
Steven M. Gava052937f2002-02-11 02:20:53 +0000698 #save the new theme
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400699 self.SaveNewKeySet(newKeySetName, newKeys)
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000700 #change gui over to the new key set
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400701 customKeyList = idleConf.GetSectionList('user', 'keys')
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000702 customKeyList.sort()
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400703 self.optMenuKeysCustom.SetMenu(customKeyList, newKeySetName)
Steven M. Gava052937f2002-02-11 02:20:53 +0000704 self.keysAreBuiltin.set(0)
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000705 self.SetKeysType()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000706
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400707 def LoadKeysList(self, keySetName):
708 reselect = 0
709 newKeySet = 0
Steven M. Gava052937f2002-02-11 02:20:53 +0000710 if self.listBindings.curselection():
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400711 reselect = 1
712 listIndex = self.listBindings.index(ANCHOR)
713 keySet = idleConf.GetKeySet(keySetName)
Kurt B. Kaisere0712772007-08-23 05:25:55 +0000714 bindNames = list(keySet.keys())
Steven M. Gava052937f2002-02-11 02:20:53 +0000715 bindNames.sort()
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400716 self.listBindings.delete(0, END)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000717 for bindName in bindNames:
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400718 key = ' '.join(keySet[bindName]) #make key(s) into a string
719 bindName = bindName[2:-2] #trim off the angle brackets
Kurt B. Kaisere0712772007-08-23 05:25:55 +0000720 if keySetName in self.changedItems['keys']:
Steven M. Gava052937f2002-02-11 02:20:53 +0000721 #handle any unsaved changes to this key set
Kurt B. Kaisere0712772007-08-23 05:25:55 +0000722 if bindName in self.changedItems['keys'][keySetName]:
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400723 key = self.changedItems['keys'][keySetName][bindName]
Steven M. Gava052937f2002-02-11 02:20:53 +0000724 self.listBindings.insert(END, bindName+' - '+key)
Steven M. Gava052937f2002-02-11 02:20:53 +0000725 if reselect:
726 self.listBindings.see(listIndex)
727 self.listBindings.select_set(listIndex)
728 self.listBindings.select_anchor(listIndex)
729
Steven M. Gava49745752002-02-18 01:43:11 +0000730 def DeleteCustomKeys(self):
731 keySetName=self.customKeys.get()
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400732 delmsg = 'Are you sure you wish to delete the key set %r ?'
733 if not tkMessageBox.askyesno(
734 'Delete Key Set', delmsg % keySetName, parent=self):
Steven M. Gava49745752002-02-18 01:43:11 +0000735 return
736 #remove key set from config
737 idleConf.userCfg['keys'].remove_section(keySetName)
Guido van Rossum811c4e02006-08-22 15:45:46 +0000738 if keySetName in self.changedItems['keys']:
Steven M. Gava49745752002-02-18 01:43:11 +0000739 del(self.changedItems['keys'][keySetName])
740 #write changes
741 idleConf.userCfg['keys'].Save()
742 #reload user key set list
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400743 itemList = idleConf.GetSectionList('user', 'keys')
Steven M. Gava49745752002-02-18 01:43:11 +0000744 itemList.sort()
745 if not itemList:
746 self.radioKeysCustom.config(state=DISABLED)
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400747 self.optMenuKeysCustom.SetMenu(itemList, '- no custom keys -')
Steven M. Gava49745752002-02-18 01:43:11 +0000748 else:
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400749 self.optMenuKeysCustom.SetMenu(itemList, itemList[0])
Steven M. Gava49745752002-02-18 01:43:11 +0000750 #revert to default key set
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400751 self.keysAreBuiltin.set(idleConf.defaultCfg['main'].Get('Keys', 'default'))
752 self.builtinKeys.set(idleConf.defaultCfg['main'].Get('Keys', 'name'))
Steven M. Gava49745752002-02-18 01:43:11 +0000753 #user can't back out of these changes, they must be applied now
754 self.Apply()
755 self.SetKeysType()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000756
Steven M. Gava49745752002-02-18 01:43:11 +0000757 def DeleteCustomTheme(self):
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400758 themeName = self.customTheme.get()
759 delmsg = 'Are you sure you wish to delete the theme %r ?'
760 if not tkMessageBox.askyesno(
761 'Delete Theme', delmsg % themeName, parent=self):
Steven M. Gava49745752002-02-18 01:43:11 +0000762 return
763 #remove theme from config
764 idleConf.userCfg['highlight'].remove_section(themeName)
Guido van Rossum811c4e02006-08-22 15:45:46 +0000765 if themeName in self.changedItems['highlight']:
Steven M. Gava49745752002-02-18 01:43:11 +0000766 del(self.changedItems['highlight'][themeName])
767 #write changes
768 idleConf.userCfg['highlight'].Save()
769 #reload user theme list
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400770 itemList = idleConf.GetSectionList('user', 'highlight')
Steven M. Gava49745752002-02-18 01:43:11 +0000771 itemList.sort()
772 if not itemList:
773 self.radioThemeCustom.config(state=DISABLED)
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400774 self.optMenuThemeCustom.SetMenu(itemList, '- no custom themes -')
Steven M. Gava49745752002-02-18 01:43:11 +0000775 else:
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400776 self.optMenuThemeCustom.SetMenu(itemList, itemList[0])
Steven M. Gava49745752002-02-18 01:43:11 +0000777 #revert to default theme
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400778 self.themeIsBuiltin.set(idleConf.defaultCfg['main'].Get('Theme', 'default'))
779 self.builtinTheme.set(idleConf.defaultCfg['main'].Get('Theme', 'name'))
Steven M. Gava49745752002-02-18 01:43:11 +0000780 #user can't back out of these changes, they must be applied now
781 self.Apply()
782 self.SetThemeType()
783
Steven M. Gava5f28e8f2002-01-21 06:38:21 +0000784 def GetColour(self):
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400785 target = self.highlightTarget.get()
786 prevColour = self.frameColourSet.cget('bg')
787 rgbTuplet, colourString = tkColorChooser.askcolor(
788 parent=self, title='Pick new colour for : '+target,
789 initialcolor=prevColour)
790 if colourString and (colourString != prevColour):
Steven M. Gava052937f2002-02-11 02:20:53 +0000791 #user didn't cancel, and they chose a new colour
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400792 if self.themeIsBuiltin.get(): #current theme is a built-in
793 message = ('Your changes will be saved as a new Custom Theme. '
794 'Enter a name for your new Custom Theme below.')
795 newTheme = self.GetNewThemeName(message)
796 if not newTheme: #user cancelled custom theme creation
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000797 return
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400798 else: #create new custom theme based on previously active theme
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000799 self.CreateNewTheme(newTheme)
Steven M. Gava052937f2002-02-11 02:20:53 +0000800 self.colour.set(colourString)
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400801 else: #current theme is user defined
Steven M. Gava052937f2002-02-11 02:20:53 +0000802 self.colour.set(colourString)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000803
Steven M. Gava052937f2002-02-11 02:20:53 +0000804 def OnNewColourSet(self):
805 newColour=self.colour.get()
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400806 self.frameColourSet.config(bg=newColour) #set sample
807 plane ='foreground' if self.fgHilite.get() else 'background'
808 sampleElement = self.themeElements[self.highlightTarget.get()][0]
Raymond Hettinger931237e2003-07-09 18:48:24 +0000809 self.textHighlightSample.tag_config(sampleElement, **{plane:newColour})
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400810 theme = self.customTheme.get()
811 themeElement = sampleElement + '-' + plane
812 self.AddChangedItem('highlight', theme, themeElement, newColour)
Steven M. Gava052937f2002-02-11 02:20:53 +0000813
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400814 def GetNewThemeName(self, message):
815 usedNames = (idleConf.GetSectionList('user', 'highlight') +
816 idleConf.GetSectionList('default', 'highlight'))
817 newTheme = GetCfgSectionNameDialog(
818 self, 'New Custom Theme', message, usedNames).result
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000819 return newTheme
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000820
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000821 def SaveAsNewTheme(self):
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400822 newThemeName = self.GetNewThemeName('New Theme Name:')
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000823 if newThemeName:
824 self.CreateNewTheme(newThemeName)
825
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400826 def CreateNewTheme(self, newThemeName):
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000827 #creates new custom theme based on the previously active theme,
828 #and makes the new theme active
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000829 if self.themeIsBuiltin.get():
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400830 themeType = 'default'
831 themeName = self.builtinTheme.get()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000832 else:
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400833 themeType = 'user'
834 themeName = self.customTheme.get()
835 newTheme = idleConf.GetThemeDict(themeType, themeName)
Steven M. Gava052937f2002-02-11 02:20:53 +0000836 #apply any of the old theme's unsaved changes to the new theme
Kurt B. Kaisere0712772007-08-23 05:25:55 +0000837 if themeName in self.changedItems['highlight']:
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400838 themeChanges = self.changedItems['highlight'][themeName]
Kurt B. Kaisere0712772007-08-23 05:25:55 +0000839 for element in themeChanges:
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400840 newTheme[element] = themeChanges[element]
Steven M. Gava052937f2002-02-11 02:20:53 +0000841 #save the new theme
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400842 self.SaveNewTheme(newThemeName, newTheme)
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000843 #change gui over to the new theme
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400844 customThemeList = idleConf.GetSectionList('user', 'highlight')
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000845 customThemeList.sort()
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400846 self.optMenuThemeCustom.SetMenu(customThemeList, newThemeName)
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000847 self.themeIsBuiltin.set(0)
848 self.SetThemeType()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000849
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400850 def OnListFontButtonRelease(self, event):
Kurt B. Kaiser05391692003-05-26 20:35:53 +0000851 font = self.listFontName.get(ANCHOR)
852 self.fontName.set(font.lower())
Steven M. Gava5f28e8f2002-01-21 06:38:21 +0000853 self.SetFontSample()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000854
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400855 def SetFontSample(self, event=None):
856 fontName = self.fontName.get()
857 fontWeight = tkFont.BOLD if self.fontBold.get() else tkFont.NORMAL
Ned Deilyfdf0f272012-10-22 15:14:31 -0700858 newFont = (fontName, self.fontSize.get(), fontWeight)
859 self.labelFontSample.config(font=newFont)
860 self.textHighlightSample.configure(font=newFont)
Steven M. Gava5f28e8f2002-01-21 06:38:21 +0000861
Steven M. Gava5f28e8f2002-01-21 06:38:21 +0000862 def SetHighlightTarget(self):
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400863 if self.highlightTarget.get() == 'Cursor': #bg not possible
Steven M. Gava5f28e8f2002-01-21 06:38:21 +0000864 self.radioFg.config(state=DISABLED)
865 self.radioBg.config(state=DISABLED)
866 self.fgHilite.set(1)
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400867 else: #both fg and bg can be set
Steven M. Gava5f28e8f2002-01-21 06:38:21 +0000868 self.radioFg.config(state=NORMAL)
869 self.radioBg.config(state=NORMAL)
870 self.fgHilite.set(1)
871 self.SetColourSample()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000872
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400873 def SetColourSampleBinding(self, *args):
Steven M. Gava5f28e8f2002-01-21 06:38:21 +0000874 self.SetColourSample()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000875
Steven M. Gava5f28e8f2002-01-21 06:38:21 +0000876 def SetColourSample(self):
877 #set the colour smaple area
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400878 tag = self.themeElements[self.highlightTarget.get()][0]
879 plane = 'foreground' if self.fgHilite.get() else 'background'
880 colour = self.textHighlightSample.tag_cget(tag, plane)
Steven M. Gava5f28e8f2002-01-21 06:38:21 +0000881 self.frameColourSet.config(bg=colour)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000882
Steven M. Gava9dd16b32001-11-03 14:54:25 +0000883 def PaintThemeSample(self):
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400884 if self.themeIsBuiltin.get(): #a default theme
885 theme = self.builtinTheme.get()
886 else: #a user theme
887 theme = self.customTheme.get()
Kurt B. Kaisere0712772007-08-23 05:25:55 +0000888 for elementTitle in self.themeElements:
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400889 element = self.themeElements[elementTitle][0]
890 colours = idleConf.GetHighlight(theme, element)
891 if element == 'cursor': #cursor sample needs special painting
892 colours['background'] = idleConf.GetHighlight(
893 theme, 'normal', fgBg='bg')
Steven M. Gava052937f2002-02-11 02:20:53 +0000894 #handle any unsaved changes to this theme
Kurt B. Kaisere0712772007-08-23 05:25:55 +0000895 if theme in self.changedItems['highlight']:
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400896 themeDict = self.changedItems['highlight'][theme]
897 if element + '-foreground' in themeDict:
898 colours['foreground'] = themeDict[element + '-foreground']
899 if element + '-background' in themeDict:
900 colours['background'] = themeDict[element + '-background']
Raymond Hettinger931237e2003-07-09 18:48:24 +0000901 self.textHighlightSample.tag_config(element, **colours)
Steven M. Gava052937f2002-02-11 02:20:53 +0000902 self.SetColourSample()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000903
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400904 def HelpSourceSelected(self, event):
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000905 self.SetHelpListButtonStates()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000906
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000907 def SetHelpListButtonStates(self):
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400908 if self.listHelp.size() < 1: #no entries in list
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000909 self.buttonHelpListEdit.config(state=DISABLED)
910 self.buttonHelpListRemove.config(state=DISABLED)
911 else: #there are some entries
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400912 if self.listHelp.curselection(): #there currently is a selection
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000913 self.buttonHelpListEdit.config(state=NORMAL)
914 self.buttonHelpListRemove.config(state=NORMAL)
915 else: #there currently is not a selection
916 self.buttonHelpListEdit.config(state=DISABLED)
917 self.buttonHelpListRemove.config(state=DISABLED)
918
919 def HelpListItemAdd(self):
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400920 helpSource = GetHelpSourceDialog(self, 'New Help Source').result
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000921 if helpSource:
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400922 self.userHelpList.append((helpSource[0], helpSource[1]))
923 self.listHelp.insert(END, helpSource[0])
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000924 self.UpdateUserHelpChangedItems()
925 self.SetHelpListButtonStates()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000926
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000927 def HelpListItemEdit(self):
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400928 itemIndex = self.listHelp.index(ANCHOR)
929 helpSource = self.userHelpList[itemIndex]
930 newHelpSource = GetHelpSourceDialog(
931 self, 'Edit Help Source', menuItem=helpSource[0],
932 filePath=helpSource[1]).result
933 if (not newHelpSource) or (newHelpSource == helpSource):
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000934 return #no changes
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400935 self.userHelpList[itemIndex] = newHelpSource
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000936 self.listHelp.delete(itemIndex)
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400937 self.listHelp.insert(itemIndex, newHelpSource[0])
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000938 self.UpdateUserHelpChangedItems()
939 self.SetHelpListButtonStates()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000940
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000941 def HelpListItemRemove(self):
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400942 itemIndex = self.listHelp.index(ANCHOR)
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000943 del(self.userHelpList[itemIndex])
944 self.listHelp.delete(itemIndex)
945 self.UpdateUserHelpChangedItems()
946 self.SetHelpListButtonStates()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000947
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000948 def UpdateUserHelpChangedItems(self):
Kurt B. Kaiser8e92bf72003-01-14 22:03:31 +0000949 "Clear and rebuild the HelpFiles section in self.changedItems"
950 self.changedItems['main']['HelpFiles'] = {}
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400951 for num in range(1, len(self.userHelpList) + 1):
952 self.AddChangedItem(
953 'main', 'HelpFiles', str(num),
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000954 ';'.join(self.userHelpList[num-1][:2]))
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000955
Steven M. Gava429a86af2001-10-23 10:42:12 +0000956 def LoadFontCfg(self):
957 ##base editor font selection list
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400958 fonts = list(tkFont.families(self))
Steven M. Gavac11ccf32001-09-24 09:43:17 +0000959 fonts.sort()
960 for font in fonts:
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400961 self.listFontName.insert(END, font)
962 configuredFont = idleConf.GetOption(
963 'main', 'EditorWindow', 'font', default='courier')
Kurt B. Kaiser05391692003-05-26 20:35:53 +0000964 lc_configuredFont = configuredFont.lower()
965 self.fontName.set(lc_configuredFont)
966 lc_fonts = [s.lower() for s in fonts]
967 if lc_configuredFont in lc_fonts:
968 currentFontIndex = lc_fonts.index(lc_configuredFont)
Steven M. Gava429a86af2001-10-23 10:42:12 +0000969 self.listFontName.see(currentFontIndex)
970 self.listFontName.select_set(currentFontIndex)
Steven M. Gavac112cd82002-01-22 05:56:40 +0000971 self.listFontName.select_anchor(currentFontIndex)
Steven M. Gava429a86af2001-10-23 10:42:12 +0000972 ##font size dropdown
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400973 fontSize = idleConf.GetOption(
974 'main', 'EditorWindow', 'font-size', type='int', default='10')
975 self.optMenuFontSize.SetMenu(('7', '8', '9', '10', '11', '12', '13',
976 '14', '16', '18', '20', '22'), fontSize )
Steven M. Gavac112cd82002-01-22 05:56:40 +0000977 ##fontWeight
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400978 self.fontBold.set(idleConf.GetOption(
979 'main', 'EditorWindow', 'font-bold', default=0, type='bool'))
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000980 ##font sample
Steven M. Gava429a86af2001-10-23 10:42:12 +0000981 self.SetFontSample()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000982
Steven M. Gava429a86af2001-10-23 10:42:12 +0000983 def LoadTabCfg(self):
Steven M. Gava429a86af2001-10-23 10:42:12 +0000984 ##indent sizes
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400985 spaceNum = idleConf.GetOption(
986 'main', 'Indent', 'num-spaces', default=4, type='int')
Steven M. Gava429a86af2001-10-23 10:42:12 +0000987 self.spaceNum.set(spaceNum)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000988
Steven M. Gava9dd16b32001-11-03 14:54:25 +0000989 def LoadThemeCfg(self):
Steven M. Gava41a85322001-10-29 08:05:34 +0000990 ##current theme type radiobutton
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400991 self.themeIsBuiltin.set(idleConf.GetOption(
992 'main', 'Theme', 'default', type='bool', default=1))
Steven M. Gava41a85322001-10-29 08:05:34 +0000993 ##currently set theme
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400994 currentOption = idleConf.CurrentTheme()
Steven M. Gava7c017862001-10-29 11:19:46 +0000995 ##load available theme option menus
Steven M. Gavad0342cd2001-11-04 11:53:10 +0000996 if self.themeIsBuiltin.get(): #default theme selected
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400997 itemList = idleConf.GetSectionList('default', 'highlight')
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000998 itemList.sort()
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400999 self.optMenuThemeBuiltin.SetMenu(itemList, currentOption)
1000 itemList = idleConf.GetSectionList('user', 'highlight')
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +00001001 itemList.sort()
Steven M. Gava41a85322001-10-29 08:05:34 +00001002 if not itemList:
1003 self.radioThemeCustom.config(state=DISABLED)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001004 self.customTheme.set('- no custom themes -')
Steven M. Gava41a85322001-10-29 08:05:34 +00001005 else:
Terry Jan Reedy4036d872014-08-03 23:02:58 -04001006 self.optMenuThemeCustom.SetMenu(itemList, itemList[0])
Steven M. Gava9dd16b32001-11-03 14:54:25 +00001007 else: #user theme selected
Terry Jan Reedy4036d872014-08-03 23:02:58 -04001008 itemList = idleConf.GetSectionList('user', 'highlight')
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +00001009 itemList.sort()
Terry Jan Reedy4036d872014-08-03 23:02:58 -04001010 self.optMenuThemeCustom.SetMenu(itemList, currentOption)
1011 itemList = idleConf.GetSectionList('default', 'highlight')
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +00001012 itemList.sort()
Terry Jan Reedy4036d872014-08-03 23:02:58 -04001013 self.optMenuThemeBuiltin.SetMenu(itemList, itemList[0])
Steven M. Gava7c017862001-10-29 11:19:46 +00001014 self.SetThemeType()
1015 ##load theme element option menu
Kurt B. Kaisere0712772007-08-23 05:25:55 +00001016 themeNames = list(self.themeElements.keys())
Kurt B. Kaiser4718bf82008-02-12 21:34:12 +00001017 themeNames.sort(key=lambda x: self.themeElements[x][1])
Terry Jan Reedy4036d872014-08-03 23:02:58 -04001018 self.optMenuHighlightTarget.SetMenu(themeNames, themeNames[0])
Steven M. Gava9dd16b32001-11-03 14:54:25 +00001019 self.PaintThemeSample()
Steven M. Gava0cae01c2002-01-04 07:53:06 +00001020 self.SetHighlightTarget()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001021
Steven M. Gava9dd16b32001-11-03 14:54:25 +00001022 def LoadKeyCfg(self):
Steven M. Gava41a85322001-10-29 08:05:34 +00001023 ##current keys type radiobutton
Terry Jan Reedy4036d872014-08-03 23:02:58 -04001024 self.keysAreBuiltin.set(idleConf.GetOption(
1025 'main', 'Keys', 'default', type='bool', default=1))
Steven M. Gava41a85322001-10-29 08:05:34 +00001026 ##currently set keys
Terry Jan Reedy4036d872014-08-03 23:02:58 -04001027 currentOption = idleConf.CurrentKeys()
Steven M. Gava7c017862001-10-29 11:19:46 +00001028 ##load available keyset option menus
Steven M. Gava052937f2002-02-11 02:20:53 +00001029 if self.keysAreBuiltin.get(): #default theme selected
Terry Jan Reedy4036d872014-08-03 23:02:58 -04001030 itemList = idleConf.GetSectionList('default', 'keys')
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +00001031 itemList.sort()
Terry Jan Reedy4036d872014-08-03 23:02:58 -04001032 self.optMenuKeysBuiltin.SetMenu(itemList, currentOption)
1033 itemList = idleConf.GetSectionList('user', 'keys')
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +00001034 itemList.sort()
Steven M. Gava41a85322001-10-29 08:05:34 +00001035 if not itemList:
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001036 self.radioKeysCustom.config(state=DISABLED)
1037 self.customKeys.set('- no custom keys -')
Steven M. Gava41a85322001-10-29 08:05:34 +00001038 else:
Terry Jan Reedy4036d872014-08-03 23:02:58 -04001039 self.optMenuKeysCustom.SetMenu(itemList, itemList[0])
Steven M. Gavaa498af22002-02-01 01:33:36 +00001040 else: #user key set selected
Terry Jan Reedy4036d872014-08-03 23:02:58 -04001041 itemList = idleConf.GetSectionList('user', 'keys')
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +00001042 itemList.sort()
Terry Jan Reedy4036d872014-08-03 23:02:58 -04001043 self.optMenuKeysCustom.SetMenu(itemList, currentOption)
1044 itemList = idleConf.GetSectionList('default', 'keys')
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +00001045 itemList.sort()
Terry Jan Reedy4036d872014-08-03 23:02:58 -04001046 self.optMenuKeysBuiltin.SetMenu(itemList, itemList[0])
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001047 self.SetKeysType()
Steven M. Gavafacfc092002-01-19 00:29:54 +00001048 ##load keyset element list
Terry Jan Reedy4036d872014-08-03 23:02:58 -04001049 keySetName = idleConf.CurrentKeys()
Steven M. Gava052937f2002-02-11 02:20:53 +00001050 self.LoadKeysList(keySetName)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001051
Steven M. Gavafacfc092002-01-19 00:29:54 +00001052 def LoadGeneralCfg(self):
Steven M. Gava5f28e8f2002-01-21 06:38:21 +00001053 #startup state
Terry Jan Reedy4036d872014-08-03 23:02:58 -04001054 self.startupEdit.set(idleConf.GetOption(
1055 'main', 'General', 'editor-on-startup', default=1, type='bool'))
Kurt B. Kaiser6c638b62003-05-26 06:23:10 +00001056 #autosave state
Terry Jan Reedy4036d872014-08-03 23:02:58 -04001057 self.autoSave.set(idleConf.GetOption(
1058 'main', 'General', 'autosave', default=0, type='bool'))
Steven M. Gavafacfc092002-01-19 00:29:54 +00001059 #initial window size
Terry Jan Reedy4036d872014-08-03 23:02:58 -04001060 self.winWidth.set(idleConf.GetOption(
1061 'main', 'EditorWindow', 'width', type='int'))
1062 self.winHeight.set(idleConf.GetOption(
1063 'main', 'EditorWindow', 'height', type='int'))
Kurt B. Kaisera053f332003-05-10 00:49:56 +00001064 # default source encoding
Terry Jan Reedy4036d872014-08-03 23:02:58 -04001065 self.encoding.set(idleConf.GetOption(
1066 'main', 'EditorWindow', 'encoding', default='none'))
Kurt B. Kaiser8e92bf72003-01-14 22:03:31 +00001067 # additional help sources
1068 self.userHelpList = idleConf.GetAllExtraHelpSourcesList()
Steven M. Gava085eb1b2002-02-05 04:52:32 +00001069 for helpItem in self.userHelpList:
Terry Jan Reedy4036d872014-08-03 23:02:58 -04001070 self.listHelp.insert(END, helpItem[0])
Steven M. Gava085eb1b2002-02-05 04:52:32 +00001071 self.SetHelpListButtonStates()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001072
Steven M. Gava429a86af2001-10-23 10:42:12 +00001073 def LoadConfigs(self):
1074 """
1075 load configuration from default and user config files and populate
1076 the widgets on the config dialog pages.
1077 """
1078 ### fonts / tabs page
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001079 self.LoadFontCfg()
1080 self.LoadTabCfg()
Steven M. Gava429a86af2001-10-23 10:42:12 +00001081 ### highlighting page
Steven M. Gava9dd16b32001-11-03 14:54:25 +00001082 self.LoadThemeCfg()
Steven M. Gava429a86af2001-10-23 10:42:12 +00001083 ### keys page
Steven M. Gava9dd16b32001-11-03 14:54:25 +00001084 self.LoadKeyCfg()
Steven M. Gava429a86af2001-10-23 10:42:12 +00001085 ### general page
Steven M. Gavafacfc092002-01-19 00:29:54 +00001086 self.LoadGeneralCfg()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001087
Terry Jan Reedy4036d872014-08-03 23:02:58 -04001088 def SaveNewKeySet(self, keySetName, keySet):
Steven M. Gava052937f2002-02-11 02:20:53 +00001089 """
1090 save a newly created core key set.
1091 keySetName - string, the name of the new key set
1092 keySet - dictionary containing the new key set
1093 """
1094 if not idleConf.userCfg['keys'].has_section(keySetName):
1095 idleConf.userCfg['keys'].add_section(keySetName)
Kurt B. Kaisere0712772007-08-23 05:25:55 +00001096 for event in keySet:
Terry Jan Reedy4036d872014-08-03 23:02:58 -04001097 value = keySet[event]
1098 idleConf.userCfg['keys'].SetOption(keySetName, event, value)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001099
Terry Jan Reedy4036d872014-08-03 23:02:58 -04001100 def SaveNewTheme(self, themeName, theme):
Steven M. Gava052937f2002-02-11 02:20:53 +00001101 """
1102 save a newly created theme.
1103 themeName - string, the name of the new theme
1104 theme - dictionary containing the new theme
1105 """
1106 if not idleConf.userCfg['highlight'].has_section(themeName):
1107 idleConf.userCfg['highlight'].add_section(themeName)
Kurt B. Kaisere0712772007-08-23 05:25:55 +00001108 for element in theme:
Terry Jan Reedy4036d872014-08-03 23:02:58 -04001109 value = theme[element]
1110 idleConf.userCfg['highlight'].SetOption(themeName, element, value)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001111
Terry Jan Reedy4036d872014-08-03 23:02:58 -04001112 def SetUserValue(self, configType, section, item, value):
1113 if idleConf.defaultCfg[configType].has_option(section, item):
1114 if idleConf.defaultCfg[configType].Get(section, item) == value:
Steven M. Gava2d7bb3f2002-01-29 08:35:29 +00001115 #the setting equals a default setting, remove it from user cfg
Terry Jan Reedy4036d872014-08-03 23:02:58 -04001116 return idleConf.userCfg[configType].RemoveOption(section, item)
Steven M. Gava2d7bb3f2002-01-29 08:35:29 +00001117 #if we got here set the option
Terry Jan Reedy4036d872014-08-03 23:02:58 -04001118 return idleConf.userCfg[configType].SetOption(section, item, value)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001119
Steven M. Gava052937f2002-02-11 02:20:53 +00001120 def SaveAllChangedConfigs(self):
Kurt B. Kaisere7a161e2003-01-10 20:13:57 +00001121 "Save configuration changes to the user config file."
Steven M. Gava0c5bc8c2002-03-27 02:25:44 +00001122 idleConf.userCfg['main'].Save()
Kurt B. Kaisere0712772007-08-23 05:25:55 +00001123 for configType in self.changedItems:
Kurt B. Kaisere7a161e2003-01-10 20:13:57 +00001124 cfgTypeHasChanges = False
Kurt B. Kaisere0712772007-08-23 05:25:55 +00001125 for section in self.changedItems[configType]:
Kurt B. Kaisere7a161e2003-01-10 20:13:57 +00001126 if section == 'HelpFiles':
1127 #this section gets completely replaced
1128 idleConf.userCfg['main'].remove_section('HelpFiles')
Kurt B. Kaiser8e92bf72003-01-14 22:03:31 +00001129 cfgTypeHasChanges = True
Kurt B. Kaisere0712772007-08-23 05:25:55 +00001130 for item in self.changedItems[configType][section]:
Kurt B. Kaisere7a161e2003-01-10 20:13:57 +00001131 value = self.changedItems[configType][section][item]
Terry Jan Reedy4036d872014-08-03 23:02:58 -04001132 if self.SetUserValue(configType, section, item, value):
Kurt B. Kaisere7a161e2003-01-10 20:13:57 +00001133 cfgTypeHasChanges = True
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001134 if cfgTypeHasChanges:
1135 idleConf.userCfg[configType].Save()
Kurt B. Kaiser5acdf932004-11-16 21:28:36 +00001136 for configType in ['keys', 'highlight']:
1137 # save these even if unchanged!
1138 idleConf.userCfg[configType].Save()
Steven M. Gavaa498af22002-02-01 01:33:36 +00001139 self.ResetChangedItems() #clear the changed items dict
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001140
Kurt B. Kaiserb1754452005-11-18 22:05:48 +00001141 def DeactivateCurrentConfig(self):
1142 #Before a config is saved, some cleanup of current
1143 #config must be done - remove the previous keybindings
Kurt B. Kaisere0712772007-08-23 05:25:55 +00001144 winInstances = self.parent.instance_dict.keys()
Kurt B. Kaiserb1754452005-11-18 22:05:48 +00001145 for instance in winInstances:
1146 instance.RemoveKeybindings()
1147
Steven M. Gava49745752002-02-18 01:43:11 +00001148 def ActivateConfigChanges(self):
Kurt B. Kaiseracdef852005-01-31 03:34:26 +00001149 "Dynamically apply configuration changes"
Kurt B. Kaisere0712772007-08-23 05:25:55 +00001150 winInstances = self.parent.instance_dict.keys()
Steven M. Gavab77d3432002-03-02 07:16:21 +00001151 for instance in winInstances:
1152 instance.ResetColorizer()
Steven M. Gavab1585412002-03-12 00:21:56 +00001153 instance.ResetFont()
Kurt B. Kaiseracdef852005-01-31 03:34:26 +00001154 instance.set_notabs_indentwidth()
Kurt B. Kaiserb1754452005-11-18 22:05:48 +00001155 instance.ApplyKeybindings()
Kurt B. Kaiser8e92bf72003-01-14 22:03:31 +00001156 instance.reset_help_menu_entries()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001157
Steven M. Gava5f28e8f2002-01-21 06:38:21 +00001158 def Cancel(self):
1159 self.destroy()
1160
1161 def Ok(self):
1162 self.Apply()
1163 self.destroy()
1164
1165 def Apply(self):
Kurt B. Kaiserb1754452005-11-18 22:05:48 +00001166 self.DeactivateCurrentConfig()
Steven M. Gava052937f2002-02-11 02:20:53 +00001167 self.SaveAllChangedConfigs()
Steven M. Gava49745752002-02-18 01:43:11 +00001168 self.ActivateConfigChanges()
Steven M. Gava5f28e8f2002-01-21 06:38:21 +00001169
1170 def Help(self):
Steven M. Gavac11ccf32001-09-24 09:43:17 +00001171 pass
1172
Terry Jan Reedya9421fb2014-10-22 20:15:18 -04001173class VerticalScrolledFrame(Frame):
1174 """A pure Tkinter vertically scrollable frame.
1175
1176 * Use the 'interior' attribute to place widgets inside the scrollable frame
1177 * Construct and pack/place/grid normally
1178 * This frame only allows vertical scrolling
1179 """
1180 def __init__(self, parent, *args, **kw):
1181 Frame.__init__(self, parent, *args, **kw)
1182
1183 # create a canvas object and a vertical scrollbar for scrolling it
1184 vscrollbar = Scrollbar(self, orient=VERTICAL)
1185 vscrollbar.pack(fill=Y, side=RIGHT, expand=FALSE)
1186 canvas = Canvas(self, bd=0, highlightthickness=0,
1187 yscrollcommand=vscrollbar.set)
1188 canvas.pack(side=LEFT, fill=BOTH, expand=TRUE)
1189 vscrollbar.config(command=canvas.yview)
1190
1191 # reset the view
1192 canvas.xview_moveto(0)
1193 canvas.yview_moveto(0)
1194
1195 # create a frame inside the canvas which will be scrolled with it
1196 self.interior = interior = Frame(canvas)
1197 interior_id = canvas.create_window(0, 0, window=interior, anchor=NW)
1198
1199 # track changes to the canvas and frame width and sync them,
1200 # also updating the scrollbar
1201 def _configure_interior(event):
1202 # update the scrollbars to match the size of the inner frame
1203 size = (interior.winfo_reqwidth(), interior.winfo_reqheight())
1204 canvas.config(scrollregion="0 0 %s %s" % size)
1205 if interior.winfo_reqwidth() != canvas.winfo_width():
1206 # update the canvas's width to fit the inner frame
1207 canvas.config(width=interior.winfo_reqwidth())
1208 interior.bind('<Configure>', _configure_interior)
1209
1210 def _configure_canvas(event):
1211 if interior.winfo_reqwidth() != canvas.winfo_width():
1212 # update the inner frame's width to fill the canvas
1213 canvas.itemconfigure(interior_id, width=canvas.winfo_width())
1214 canvas.bind('<Configure>', _configure_canvas)
1215
1216 return
1217
1218def is_int(s):
1219 "Return 's is blank or represents an int'"
1220 if not s:
1221 return True
1222 try:
1223 int(s)
1224 return True
1225 except ValueError:
1226 return False
1227
1228# TODO:
1229# * Revert to default(s)? Per option or per extension?
1230# * List options in their original order (possible??)
1231class ConfigExtensionsDialog(Toplevel):
1232 """A dialog for configuring IDLE extensions.
1233
1234 This dialog is generic - it works for any and all IDLE extensions.
1235
1236 IDLE extensions save their configuration options using idleConf.
1237 ConfigExtensionsDialog reads the current configuration using idleConf,
1238 supplies a GUI interface to change the configuration values, and saves the
1239 changes using idleConf.
1240
1241 Not all changes take effect immediately - some may require restarting IDLE.
1242 This depends on each extension's implementation.
1243
1244 All values are treated as text, and it is up to the user to supply
1245 reasonable values. The only exception to this are the 'enable*' options,
1246 which are boolean, and can be toggled with an True/False button.
1247 """
1248 def __init__(self, parent, title=None, _htest=False):
1249 Toplevel.__init__(self, parent)
1250 self.wm_withdraw()
1251
1252 self.configure(borderwidth=5)
1253 self.geometry(
1254 "+%d+%d" % (parent.winfo_rootx() + 20,
1255 parent.winfo_rooty() + (30 if not _htest else 150)))
1256 self.wm_title(title or 'IDLE Extensions Configuration')
1257
1258 self.defaultCfg = idleConf.defaultCfg['extensions']
1259 self.userCfg = idleConf.userCfg['extensions']
1260 self.is_int = self.register(is_int)
1261 self.load_extensions()
1262 self.create_widgets()
1263
1264 self.resizable(height=FALSE, width=FALSE) # don't allow resizing yet
1265 self.transient(parent)
1266 self.protocol("WM_DELETE_WINDOW", self.Cancel)
1267 self.tabbed_page_set.focus_set()
1268 # wait for window to be generated
1269 self.update()
1270 # set current width as the minimum width
1271 self.wm_minsize(self.winfo_width(), 1)
1272 # now allow resizing
1273 self.resizable(height=TRUE, width=TRUE)
1274
1275 self.wm_deiconify()
1276 if not _htest:
1277 self.grab_set()
1278 self.wait_window()
1279
1280 def load_extensions(self):
1281 "Fill self.extensions with data from the default and user configs."
1282 self.extensions = {}
1283 for ext_name in idleConf.GetExtensions(active_only=False):
1284 self.extensions[ext_name] = []
1285
1286 for ext_name in self.extensions:
1287 opt_list = sorted(self.defaultCfg.GetOptionList(ext_name))
1288
1289 # bring 'enable' options to the beginning of the list
1290 enables = [opt_name for opt_name in opt_list
1291 if opt_name.startswith('enable')]
1292 for opt_name in enables:
1293 opt_list.remove(opt_name)
1294 opt_list = enables + opt_list
1295
1296 for opt_name in opt_list:
1297 def_str = self.defaultCfg.Get(
1298 ext_name, opt_name, raw=True)
1299 try:
1300 def_obj = {'True':True, 'False':False}[def_str]
1301 opt_type = 'bool'
1302 except KeyError:
1303 try:
1304 def_obj = int(def_str)
1305 opt_type = 'int'
1306 except ValueError:
1307 def_obj = def_str
1308 opt_type = None
1309 try:
1310 value = self.userCfg.Get(
1311 ext_name, opt_name, type=opt_type, raw=True,
1312 default=def_obj)
1313 except ValueError: # Need this until .Get fixed
1314 value = def_obj # bad values overwritten by entry
1315 var = StringVar(self)
1316 var.set(str(value))
1317
1318 self.extensions[ext_name].append({'name': opt_name,
1319 'type': opt_type,
1320 'default': def_str,
1321 'value': value,
1322 'var': var,
1323 })
1324
1325 def create_widgets(self):
1326 """Create the dialog's widgets."""
1327 self.rowconfigure(0, weight=1)
1328 self.rowconfigure(1, weight=0)
1329 self.columnconfigure(0, weight=1)
1330
1331 # create the tabbed pages
1332 self.tabbed_page_set = TabbedPageSet(
1333 self, page_names=self.extensions.keys(),
1334 n_rows=None, max_tabs_per_row=5,
1335 page_class=TabbedPageSet.PageRemove)
1336 self.tabbed_page_set.grid(row=0, column=0, sticky=NSEW)
1337 for ext_name in self.extensions:
1338 self.create_tab_page(ext_name)
1339
1340 self.create_action_buttons().grid(row=1)
1341
1342 create_action_buttons = ConfigDialog.create_action_buttons
1343
1344 def create_tab_page(self, ext_name):
1345 """Create the page for an extension."""
1346
1347 page = LabelFrame(self.tabbed_page_set.pages[ext_name].frame,
1348 border=2, padx=2, relief=GROOVE,
1349 text=' %s ' % ext_name)
1350 page.pack(fill=BOTH, expand=True, padx=12, pady=2)
1351
1352 # create the scrollable frame which will contain the entries
1353 scrolled_frame = VerticalScrolledFrame(page, pady=2, height=250)
1354 scrolled_frame.pack(side=BOTTOM, fill=BOTH, expand=TRUE)
1355 entry_area = scrolled_frame.interior
1356 entry_area.columnconfigure(0, weight=0)
1357 entry_area.columnconfigure(1, weight=1)
1358
1359 # create an entry for each configuration option
1360 for row, opt in enumerate(self.extensions[ext_name]):
1361 # create a row with a label and entry/checkbutton
1362 label = Label(entry_area, text=opt['name'])
1363 label.grid(row=row, column=0, sticky=NW)
1364 var = opt['var']
1365 if opt['type'] == 'bool':
1366 Checkbutton(entry_area, textvariable=var, variable=var,
1367 onvalue='True', offvalue='False',
1368 indicatoron=FALSE, selectcolor='', width=8
1369 ).grid(row=row, column=1, sticky=W, padx=7)
1370 elif opt['type'] == 'int':
1371 Entry(entry_area, textvariable=var, validate='key',
1372 validatecommand=(self.is_int, '%P')
1373 ).grid(row=row, column=1, sticky=NSEW, padx=7)
1374
1375 else:
1376 Entry(entry_area, textvariable=var
1377 ).grid(row=row, column=1, sticky=NSEW, padx=7)
1378 return
1379
1380
1381 Ok = ConfigDialog.Ok
1382
1383 def Apply(self):
1384 self.save_all_changed_configs()
1385 pass
1386
1387 Cancel = ConfigDialog.Cancel
1388
1389 def Help(self):
1390 pass
1391
1392 def set_user_value(self, section, opt):
1393 name = opt['name']
1394 default = opt['default']
1395 value = opt['var'].get().strip() or default
1396 opt['var'].set(value)
1397 # if self.defaultCfg.has_section(section):
1398 # Currently, always true; if not, indent to return
1399 if (value == default):
1400 return self.userCfg.RemoveOption(section, name)
1401 # set the option
1402 return self.userCfg.SetOption(section, name, value)
1403
1404 def save_all_changed_configs(self):
1405 """Save configuration changes to the user config file."""
1406 has_changes = False
1407 for ext_name in self.extensions:
1408 options = self.extensions[ext_name]
1409 for opt in options:
1410 if self.set_user_value(ext_name, opt):
1411 has_changes = True
1412 if has_changes:
1413 self.userCfg.Save()
1414
1415
Steven M. Gava44d3d1a2001-07-31 06:59:02 +00001416if __name__ == '__main__':
Terry Jan Reedycfa89502014-07-14 23:07:32 -04001417 import unittest
1418 unittest.main('idlelib.idle_test.test_configdialog',
1419 verbosity=2, exit=False)
Terry Jan Reedy2e8234a2014-05-29 01:46:26 -04001420 from idlelib.idle_test.htest import run
Terry Jan Reedya9421fb2014-10-22 20:15:18 -04001421 run(ConfigDialog, ConfigExtensionsDialog)