blob: 57565ae60e4698c2e42d79ada0c8fce1b2ea3888 [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)
376 self.paraWidth = StringVar(parent)
377 self.startupEdit = IntVar(parent)
378 self.autoSave = IntVar(parent)
379 self.encoding = StringVar(parent)
380 self.userHelpBrowser = BooleanVar(parent)
381 self.helpBrowser = StringVar(parent)
382
Steven M. Gava230e5782001-08-07 03:28:25 +0000383 #widget creation
384 #body
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400385 frame = self.tabPages.pages['General'].frame
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000386 #body section frames
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400387 frameRun = LabelFrame(frame, borderwidth=2, relief=GROOVE,
388 text=' Startup Preferences ')
389 frameSave = LabelFrame(frame, borderwidth=2, relief=GROOVE,
390 text=' Autosave Preferences ')
391 frameWinSize = Frame(frame, borderwidth=2, relief=GROOVE)
392 frameParaSize = Frame(frame, borderwidth=2, relief=GROOVE)
393 frameHelp = LabelFrame(frame, borderwidth=2, relief=GROOVE,
394 text=' Additional Help Sources ')
Steven M. Gava230e5782001-08-07 03:28:25 +0000395 #frameRun
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400396 labelRunChoiceTitle = Label(frameRun, text='At Startup')
397 radioStartupEdit = Radiobutton(
398 frameRun, variable=self.startupEdit, value=1,
399 command=self.SetKeysType, text="Open Edit Window")
400 radioStartupShell = Radiobutton(
401 frameRun, variable=self.startupEdit, value=0,
402 command=self.SetKeysType, text='Open Shell Window')
Kurt B. Kaiser6c638b62003-05-26 06:23:10 +0000403 #frameSave
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400404 labelRunSaveTitle = Label(frameSave, text='At Start of Run (F5) ')
405 radioSaveAsk = Radiobutton(
406 frameSave, variable=self.autoSave, value=0,
407 command=self.SetKeysType, text="Prompt to Save")
408 radioSaveAuto = Radiobutton(
409 frameSave, variable=self.autoSave, value=1,
410 command=self.SetKeysType, text='No Prompt')
Steven M. Gava230e5782001-08-07 03:28:25 +0000411 #frameWinSize
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400412 labelWinSizeTitle = Label(
413 frameWinSize, text='Initial Window Size (in characters)')
414 labelWinWidthTitle = Label(frameWinSize, text='Width')
415 entryWinWidth = Entry(
416 frameWinSize, textvariable=self.winWidth, width=3)
417 labelWinHeightTitle = Label(frameWinSize, text='Height')
418 entryWinHeight = Entry(
419 frameWinSize, textvariable=self.winHeight, width=3)
Raymond Hettinger4e49b832004-06-04 06:31:08 +0000420 #paragraphFormatWidth
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400421 labelParaWidthTitle = Label(
422 frameParaSize, text='Paragraph reformat width (in characters)')
423 entryParaWidth = Entry(
424 frameParaSize, textvariable=self.paraWidth, width=3)
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000425 #frameHelp
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400426 frameHelpList = Frame(frameHelp)
427 frameHelpListButtons = Frame(frameHelpList)
428 scrollHelpList = Scrollbar(frameHelpList)
429 self.listHelp = Listbox(
430 frameHelpList, height=5, takefocus=FALSE,
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000431 exportselection=FALSE)
432 scrollHelpList.config(command=self.listHelp.yview)
433 self.listHelp.config(yscrollcommand=scrollHelpList.set)
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400434 self.listHelp.bind('<ButtonRelease-1>', self.HelpSourceSelected)
435 self.buttonHelpListEdit = Button(
436 frameHelpListButtons, text='Edit', state=DISABLED,
437 width=8, command=self.HelpListItemEdit)
438 self.buttonHelpListAdd = Button(
439 frameHelpListButtons, text='Add',
440 width=8, command=self.HelpListItemAdd)
441 self.buttonHelpListRemove = Button(
442 frameHelpListButtons, text='Remove', state=DISABLED,
443 width=8, command=self.HelpListItemRemove)
Terry Jan Reedy22405332014-07-30 19:24:32 -0400444
Steven M. Gava230e5782001-08-07 03:28:25 +0000445 #widget packing
446 #body
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400447 frameRun.pack(side=TOP, padx=5, pady=5, fill=X)
448 frameSave.pack(side=TOP, padx=5, pady=5, fill=X)
449 frameWinSize.pack(side=TOP, padx=5, pady=5, fill=X)
450 frameParaSize.pack(side=TOP, padx=5, pady=5, fill=X)
451 frameHelp.pack(side=TOP, padx=5, pady=5, expand=TRUE, fill=BOTH)
Steven M. Gava230e5782001-08-07 03:28:25 +0000452 #frameRun
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400453 labelRunChoiceTitle.pack(side=LEFT, anchor=W, padx=5, pady=5)
454 radioStartupShell.pack(side=RIGHT, anchor=W, padx=5, pady=5)
455 radioStartupEdit.pack(side=RIGHT, anchor=W, padx=5, pady=5)
Kurt B. Kaiser6c638b62003-05-26 06:23:10 +0000456 #frameSave
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400457 labelRunSaveTitle.pack(side=LEFT, anchor=W, padx=5, pady=5)
458 radioSaveAuto.pack(side=RIGHT, anchor=W, padx=5, pady=5)
459 radioSaveAsk.pack(side=RIGHT, anchor=W, padx=5, pady=5)
Steven M. Gava230e5782001-08-07 03:28:25 +0000460 #frameWinSize
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400461 labelWinSizeTitle.pack(side=LEFT, anchor=W, padx=5, pady=5)
462 entryWinHeight.pack(side=RIGHT, anchor=E, padx=10, pady=5)
463 labelWinHeightTitle.pack(side=RIGHT, anchor=E, pady=5)
464 entryWinWidth.pack(side=RIGHT, anchor=E, padx=10, pady=5)
465 labelWinWidthTitle.pack(side=RIGHT, anchor=E, pady=5)
Raymond Hettinger4e49b832004-06-04 06:31:08 +0000466 #paragraphFormatWidth
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400467 labelParaWidthTitle.pack(side=LEFT, anchor=W, padx=5, pady=5)
468 entryParaWidth.pack(side=RIGHT, anchor=E, padx=10, pady=5)
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000469 #frameHelp
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400470 frameHelpListButtons.pack(side=RIGHT, padx=5, pady=5, fill=Y)
471 frameHelpList.pack(side=TOP, padx=5, pady=5, expand=TRUE, fill=BOTH)
472 scrollHelpList.pack(side=RIGHT, anchor=W, fill=Y)
473 self.listHelp.pack(side=LEFT, anchor=E, expand=TRUE, fill=BOTH)
474 self.buttonHelpListEdit.pack(side=TOP, anchor=W, pady=5)
475 self.buttonHelpListAdd.pack(side=TOP, anchor=W)
476 self.buttonHelpListRemove.pack(side=TOP, anchor=W, pady=5)
Steven M. Gava952d0a52001-08-03 04:43:44 +0000477 return frame
478
Steven M. Gavac112cd82002-01-22 05:56:40 +0000479 def AttachVarCallbacks(self):
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400480 self.fontSize.trace_variable('w', self.VarChanged_fontSize)
481 self.fontName.trace_variable('w', self.VarChanged_fontName)
482 self.fontBold.trace_variable('w', self.VarChanged_fontBold)
483 self.spaceNum.trace_variable('w', self.VarChanged_spaceNum)
484 self.colour.trace_variable('w', self.VarChanged_colour)
485 self.builtinTheme.trace_variable('w', self.VarChanged_builtinTheme)
486 self.customTheme.trace_variable('w', self.VarChanged_customTheme)
487 self.themeIsBuiltin.trace_variable('w', self.VarChanged_themeIsBuiltin)
488 self.highlightTarget.trace_variable('w', self.VarChanged_highlightTarget)
489 self.keyBinding.trace_variable('w', self.VarChanged_keyBinding)
490 self.builtinKeys.trace_variable('w', self.VarChanged_builtinKeys)
491 self.customKeys.trace_variable('w', self.VarChanged_customKeys)
492 self.keysAreBuiltin.trace_variable('w', self.VarChanged_keysAreBuiltin)
493 self.winWidth.trace_variable('w', self.VarChanged_winWidth)
494 self.winHeight.trace_variable('w', self.VarChanged_winHeight)
495 self.paraWidth.trace_variable('w', self.VarChanged_paraWidth)
496 self.startupEdit.trace_variable('w', self.VarChanged_startupEdit)
497 self.autoSave.trace_variable('w', self.VarChanged_autoSave)
498 self.encoding.trace_variable('w', self.VarChanged_encoding)
Steven M. Gava052937f2002-02-11 02:20:53 +0000499
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400500 def VarChanged_fontSize(self, *params):
501 value = self.fontSize.get()
502 self.AddChangedItem('main', 'EditorWindow', 'font-size', value)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000503
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400504 def VarChanged_fontName(self, *params):
505 value = self.fontName.get()
506 self.AddChangedItem('main', 'EditorWindow', 'font', value)
Steven M. Gavac112cd82002-01-22 05:56:40 +0000507
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400508 def VarChanged_fontBold(self, *params):
509 value = self.fontBold.get()
510 self.AddChangedItem('main', 'EditorWindow', 'font-bold', value)
Steven M. Gavac112cd82002-01-22 05:56:40 +0000511
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400512 def VarChanged_spaceNum(self, *params):
513 value = self.spaceNum.get()
514 self.AddChangedItem('main', 'Indent', 'num-spaces', value)
Steven M. Gavac112cd82002-01-22 05:56:40 +0000515
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400516 def VarChanged_colour(self, *params):
Steven M. Gava052937f2002-02-11 02:20:53 +0000517 self.OnNewColourSet()
518
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400519 def VarChanged_builtinTheme(self, *params):
520 value = self.builtinTheme.get()
521 self.AddChangedItem('main', 'Theme', 'name', value)
Steven M. Gava052937f2002-02-11 02:20:53 +0000522 self.PaintThemeSample()
523
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400524 def VarChanged_customTheme(self, *params):
525 value = self.customTheme.get()
Steven M. Gava49745752002-02-18 01:43:11 +0000526 if value != '- no custom themes -':
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400527 self.AddChangedItem('main', 'Theme', 'name', value)
Steven M. Gava49745752002-02-18 01:43:11 +0000528 self.PaintThemeSample()
Steven M. Gava052937f2002-02-11 02:20:53 +0000529
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400530 def VarChanged_themeIsBuiltin(self, *params):
531 value = self.themeIsBuiltin.get()
532 self.AddChangedItem('main', 'Theme', 'default', value)
Steven M. Gavaf31eec02002-03-05 00:25:58 +0000533 if value:
534 self.VarChanged_builtinTheme()
535 else:
536 self.VarChanged_customTheme()
Steven M. Gava052937f2002-02-11 02:20:53 +0000537
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400538 def VarChanged_highlightTarget(self, *params):
Steven M. Gava052937f2002-02-11 02:20:53 +0000539 self.SetHighlightTarget()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000540
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400541 def VarChanged_keyBinding(self, *params):
542 value = self.keyBinding.get()
543 keySet = self.customKeys.get()
544 event = self.listBindings.get(ANCHOR).split()[0]
Steven M. Gavaa498af22002-02-01 01:33:36 +0000545 if idleConf.IsCoreBinding(event):
546 #this is a core keybinding
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400547 self.AddChangedItem('keys', keySet, event, value)
Steven M. Gavaa498af22002-02-01 01:33:36 +0000548 else: #this is an extension key binding
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400549 extName = idleConf.GetExtnNameForEvent(event)
550 extKeybindSection = extName + '_cfgBindings'
551 self.AddChangedItem('extensions', extKeybindSection, event, value)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000552
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400553 def VarChanged_builtinKeys(self, *params):
554 value = self.builtinKeys.get()
555 self.AddChangedItem('main', 'Keys', 'name', value)
Steven M. Gava052937f2002-02-11 02:20:53 +0000556 self.LoadKeysList(value)
557
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400558 def VarChanged_customKeys(self, *params):
559 value = self.customKeys.get()
Steven M. Gava49745752002-02-18 01:43:11 +0000560 if value != '- no custom keys -':
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400561 self.AddChangedItem('main', 'Keys', 'name', value)
Steven M. Gava49745752002-02-18 01:43:11 +0000562 self.LoadKeysList(value)
Steven M. Gava052937f2002-02-11 02:20:53 +0000563
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400564 def VarChanged_keysAreBuiltin(self, *params):
565 value = self.keysAreBuiltin.get()
566 self.AddChangedItem('main', 'Keys', 'default', value)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000567 if value:
Steven M. Gavaf31eec02002-03-05 00:25:58 +0000568 self.VarChanged_builtinKeys()
Steven M. Gava052937f2002-02-11 02:20:53 +0000569 else:
Steven M. Gavaf31eec02002-03-05 00:25:58 +0000570 self.VarChanged_customKeys()
Steven M. Gava052937f2002-02-11 02:20:53 +0000571
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400572 def VarChanged_winWidth(self, *params):
573 value = self.winWidth.get()
574 self.AddChangedItem('main', 'EditorWindow', 'width', value)
Steven M. Gavac112cd82002-01-22 05:56:40 +0000575
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400576 def VarChanged_winHeight(self, *params):
577 value = self.winHeight.get()
578 self.AddChangedItem('main', 'EditorWindow', 'height', value)
Steven M. Gavac112cd82002-01-22 05:56:40 +0000579
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400580 def VarChanged_paraWidth(self, *params):
581 value = self.paraWidth.get()
582 self.AddChangedItem('main', 'FormatParagraph', 'paragraph', value)
Raymond Hettinger4e49b832004-06-04 06:31:08 +0000583
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400584 def VarChanged_startupEdit(self, *params):
585 value = self.startupEdit.get()
586 self.AddChangedItem('main', 'General', 'editor-on-startup', value)
Steven M. Gavac112cd82002-01-22 05:56:40 +0000587
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400588 def VarChanged_autoSave(self, *params):
589 value = self.autoSave.get()
590 self.AddChangedItem('main', 'General', 'autosave', value)
Kurt B. Kaiser6c638b62003-05-26 06:23:10 +0000591
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400592 def VarChanged_encoding(self, *params):
593 value = self.encoding.get()
594 self.AddChangedItem('main', 'EditorWindow', 'encoding', value)
Kurt B. Kaisera053f332003-05-10 00:49:56 +0000595
Steven M. Gavaa498af22002-02-01 01:33:36 +0000596 def ResetChangedItems(self):
Steven M. Gavab77d3432002-03-02 07:16:21 +0000597 #When any config item is changed in this dialog, an entry
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000598 #should be made in the relevant section (config type) of this
599 #dictionary. The key should be the config file section name and the
Steven M. Gavaa498af22002-02-01 01:33:36 +0000600 #value a dictionary, whose key:value pairs are item=value pairs for
601 #that config file section.
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400602 self.changedItems = {'main':{}, 'highlight':{}, 'keys':{},
603 'extensions':{}}
Steven M. Gavaa498af22002-02-01 01:33:36 +0000604
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400605 def AddChangedItem(self, typ, section, item, value):
606 value = str(value) #make sure we use a string
607 if section not in self.changedItems[typ]:
608 self.changedItems[typ][section] = {}
609 self.changedItems[typ][section][item] = value
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000610
Steven M. Gava5f28e8f2002-01-21 06:38:21 +0000611 def GetDefaultItems(self):
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400612 dItems={'main':{}, 'highlight':{}, 'keys':{}, 'extensions':{}}
Kurt B. Kaisere0712772007-08-23 05:25:55 +0000613 for configType in dItems:
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400614 sections = idleConf.GetSectionList('default', configType)
Steven M. Gava5f28e8f2002-01-21 06:38:21 +0000615 for section in sections:
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400616 dItems[configType][section] = {}
617 options = idleConf.defaultCfg[configType].GetOptionList(section)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000618 for option in options:
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400619 dItems[configType][section][option] = (
620 idleConf.defaultCfg[configType].Get(section, option))
Steven M. Gava5f28e8f2002-01-21 06:38:21 +0000621 return dItems
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000622
Steven M. Gava5f28e8f2002-01-21 06:38:21 +0000623 def SetThemeType(self):
624 if self.themeIsBuiltin.get():
625 self.optMenuThemeBuiltin.config(state=NORMAL)
626 self.optMenuThemeCustom.config(state=DISABLED)
627 self.buttonDeleteCustomTheme.config(state=DISABLED)
628 else:
629 self.optMenuThemeBuiltin.config(state=DISABLED)
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000630 self.radioThemeCustom.config(state=NORMAL)
Steven M. Gava5f28e8f2002-01-21 06:38:21 +0000631 self.optMenuThemeCustom.config(state=NORMAL)
632 self.buttonDeleteCustomTheme.config(state=NORMAL)
633
634 def SetKeysType(self):
Steven M. Gava052937f2002-02-11 02:20:53 +0000635 if self.keysAreBuiltin.get():
Steven M. Gava5f28e8f2002-01-21 06:38:21 +0000636 self.optMenuKeysBuiltin.config(state=NORMAL)
637 self.optMenuKeysCustom.config(state=DISABLED)
638 self.buttonDeleteCustomKeys.config(state=DISABLED)
639 else:
640 self.optMenuKeysBuiltin.config(state=DISABLED)
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000641 self.radioKeysCustom.config(state=NORMAL)
Steven M. Gava5f28e8f2002-01-21 06:38:21 +0000642 self.optMenuKeysCustom.config(state=NORMAL)
643 self.buttonDeleteCustomKeys.config(state=NORMAL)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000644
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000645 def GetNewKeys(self):
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400646 listIndex = self.listBindings.index(ANCHOR)
647 binding = self.listBindings.get(listIndex)
648 bindName = binding.split()[0] #first part, up to first space
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000649 if self.keysAreBuiltin.get():
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400650 currentKeySetName = self.builtinKeys.get()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000651 else:
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400652 currentKeySetName = self.customKeys.get()
653 currentBindings = idleConf.GetCurrentKeySet()
Kurt B. Kaisere0712772007-08-23 05:25:55 +0000654 if currentKeySetName in self.changedItems['keys']: #unsaved changes
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400655 keySetChanges = self.changedItems['keys'][currentKeySetName]
Kurt B. Kaisere0712772007-08-23 05:25:55 +0000656 for event in keySetChanges:
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400657 currentBindings[event] = keySetChanges[event].split()
Kurt B. Kaisere0712772007-08-23 05:25:55 +0000658 currentKeySequences = list(currentBindings.values())
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400659 newKeys = GetKeysDialog(self, 'Get New Keys', bindName,
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000660 currentKeySequences).result
661 if newKeys: #new keys were specified
Steven M. Gava052937f2002-02-11 02:20:53 +0000662 if self.keysAreBuiltin.get(): #current key set is a built-in
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400663 message = ('Your changes will be saved as a new Custom Key Set.'
664 ' Enter a name for your new Custom Key Set below.')
665 newKeySet = self.GetNewKeysName(message)
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000666 if not newKeySet: #user cancelled custom key set creation
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000667 self.listBindings.select_set(listIndex)
668 self.listBindings.select_anchor(listIndex)
669 return
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000670 else: #create new custom key set based on previously active key set
671 self.CreateNewKeySet(newKeySet)
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000672 self.listBindings.delete(listIndex)
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400673 self.listBindings.insert(listIndex, bindName+' - '+newKeys)
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000674 self.listBindings.select_set(listIndex)
675 self.listBindings.select_anchor(listIndex)
Steven M. Gava052937f2002-02-11 02:20:53 +0000676 self.keyBinding.set(newKeys)
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000677 else:
678 self.listBindings.select_set(listIndex)
679 self.listBindings.select_anchor(listIndex)
680
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400681 def GetNewKeysName(self, message):
682 usedNames = (idleConf.GetSectionList('user', 'keys') +
683 idleConf.GetSectionList('default', 'keys'))
684 newKeySet = GetCfgSectionNameDialog(
685 self, 'New Custom Key Set', message, usedNames).result
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000686 return newKeySet
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000687
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000688 def SaveAsNewKeySet(self):
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400689 newKeysName = self.GetNewKeysName('New Key Set Name:')
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000690 if newKeysName:
691 self.CreateNewKeySet(newKeysName)
692
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400693 def KeyBindingSelected(self, event):
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000694 self.buttonNewKeys.config(state=NORMAL)
695
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400696 def CreateNewKeySet(self, newKeySetName):
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000697 #creates new custom key set based on the previously active key set,
698 #and makes the new key set active
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000699 if self.keysAreBuiltin.get():
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400700 prevKeySetName = self.builtinKeys.get()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000701 else:
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400702 prevKeySetName = self.customKeys.get()
703 prevKeys = idleConf.GetCoreKeys(prevKeySetName)
704 newKeys = {}
Kurt B. Kaisere0712772007-08-23 05:25:55 +0000705 for event in prevKeys: #add key set to changed items
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400706 eventName = event[2:-2] #trim off the angle brackets
707 binding = ' '.join(prevKeys[event])
708 newKeys[eventName] = binding
Steven M. Gava052937f2002-02-11 02:20:53 +0000709 #handle any unsaved changes to prev key set
Kurt B. Kaisere0712772007-08-23 05:25:55 +0000710 if prevKeySetName in self.changedItems['keys']:
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400711 keySetChanges = self.changedItems['keys'][prevKeySetName]
Kurt B. Kaisere0712772007-08-23 05:25:55 +0000712 for event in keySetChanges:
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400713 newKeys[event] = keySetChanges[event]
Steven M. Gava052937f2002-02-11 02:20:53 +0000714 #save the new theme
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400715 self.SaveNewKeySet(newKeySetName, newKeys)
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000716 #change gui over to the new key set
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400717 customKeyList = idleConf.GetSectionList('user', 'keys')
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000718 customKeyList.sort()
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400719 self.optMenuKeysCustom.SetMenu(customKeyList, newKeySetName)
Steven M. Gava052937f2002-02-11 02:20:53 +0000720 self.keysAreBuiltin.set(0)
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000721 self.SetKeysType()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000722
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400723 def LoadKeysList(self, keySetName):
724 reselect = 0
725 newKeySet = 0
Steven M. Gava052937f2002-02-11 02:20:53 +0000726 if self.listBindings.curselection():
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400727 reselect = 1
728 listIndex = self.listBindings.index(ANCHOR)
729 keySet = idleConf.GetKeySet(keySetName)
Kurt B. Kaisere0712772007-08-23 05:25:55 +0000730 bindNames = list(keySet.keys())
Steven M. Gava052937f2002-02-11 02:20:53 +0000731 bindNames.sort()
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400732 self.listBindings.delete(0, END)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000733 for bindName in bindNames:
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400734 key = ' '.join(keySet[bindName]) #make key(s) into a string
735 bindName = bindName[2:-2] #trim off the angle brackets
Kurt B. Kaisere0712772007-08-23 05:25:55 +0000736 if keySetName in self.changedItems['keys']:
Steven M. Gava052937f2002-02-11 02:20:53 +0000737 #handle any unsaved changes to this key set
Kurt B. Kaisere0712772007-08-23 05:25:55 +0000738 if bindName in self.changedItems['keys'][keySetName]:
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400739 key = self.changedItems['keys'][keySetName][bindName]
Steven M. Gava052937f2002-02-11 02:20:53 +0000740 self.listBindings.insert(END, bindName+' - '+key)
Steven M. Gava052937f2002-02-11 02:20:53 +0000741 if reselect:
742 self.listBindings.see(listIndex)
743 self.listBindings.select_set(listIndex)
744 self.listBindings.select_anchor(listIndex)
745
Steven M. Gava49745752002-02-18 01:43:11 +0000746 def DeleteCustomKeys(self):
747 keySetName=self.customKeys.get()
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400748 delmsg = 'Are you sure you wish to delete the key set %r ?'
749 if not tkMessageBox.askyesno(
750 'Delete Key Set', delmsg % keySetName, parent=self):
Steven M. Gava49745752002-02-18 01:43:11 +0000751 return
752 #remove key set from config
753 idleConf.userCfg['keys'].remove_section(keySetName)
Guido van Rossum811c4e02006-08-22 15:45:46 +0000754 if keySetName in self.changedItems['keys']:
Steven M. Gava49745752002-02-18 01:43:11 +0000755 del(self.changedItems['keys'][keySetName])
756 #write changes
757 idleConf.userCfg['keys'].Save()
758 #reload user key set list
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400759 itemList = idleConf.GetSectionList('user', 'keys')
Steven M. Gava49745752002-02-18 01:43:11 +0000760 itemList.sort()
761 if not itemList:
762 self.radioKeysCustom.config(state=DISABLED)
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400763 self.optMenuKeysCustom.SetMenu(itemList, '- no custom keys -')
Steven M. Gava49745752002-02-18 01:43:11 +0000764 else:
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400765 self.optMenuKeysCustom.SetMenu(itemList, itemList[0])
Steven M. Gava49745752002-02-18 01:43:11 +0000766 #revert to default key set
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400767 self.keysAreBuiltin.set(idleConf.defaultCfg['main'].Get('Keys', 'default'))
768 self.builtinKeys.set(idleConf.defaultCfg['main'].Get('Keys', 'name'))
Steven M. Gava49745752002-02-18 01:43:11 +0000769 #user can't back out of these changes, they must be applied now
770 self.Apply()
771 self.SetKeysType()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000772
Steven M. Gava49745752002-02-18 01:43:11 +0000773 def DeleteCustomTheme(self):
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400774 themeName = self.customTheme.get()
775 delmsg = 'Are you sure you wish to delete the theme %r ?'
776 if not tkMessageBox.askyesno(
777 'Delete Theme', delmsg % themeName, parent=self):
Steven M. Gava49745752002-02-18 01:43:11 +0000778 return
779 #remove theme from config
780 idleConf.userCfg['highlight'].remove_section(themeName)
Guido van Rossum811c4e02006-08-22 15:45:46 +0000781 if themeName in self.changedItems['highlight']:
Steven M. Gava49745752002-02-18 01:43:11 +0000782 del(self.changedItems['highlight'][themeName])
783 #write changes
784 idleConf.userCfg['highlight'].Save()
785 #reload user theme list
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400786 itemList = idleConf.GetSectionList('user', 'highlight')
Steven M. Gava49745752002-02-18 01:43:11 +0000787 itemList.sort()
788 if not itemList:
789 self.radioThemeCustom.config(state=DISABLED)
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400790 self.optMenuThemeCustom.SetMenu(itemList, '- no custom themes -')
Steven M. Gava49745752002-02-18 01:43:11 +0000791 else:
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400792 self.optMenuThemeCustom.SetMenu(itemList, itemList[0])
Steven M. Gava49745752002-02-18 01:43:11 +0000793 #revert to default theme
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400794 self.themeIsBuiltin.set(idleConf.defaultCfg['main'].Get('Theme', 'default'))
795 self.builtinTheme.set(idleConf.defaultCfg['main'].Get('Theme', 'name'))
Steven M. Gava49745752002-02-18 01:43:11 +0000796 #user can't back out of these changes, they must be applied now
797 self.Apply()
798 self.SetThemeType()
799
Steven M. Gava5f28e8f2002-01-21 06:38:21 +0000800 def GetColour(self):
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400801 target = self.highlightTarget.get()
802 prevColour = self.frameColourSet.cget('bg')
803 rgbTuplet, colourString = tkColorChooser.askcolor(
804 parent=self, title='Pick new colour for : '+target,
805 initialcolor=prevColour)
806 if colourString and (colourString != prevColour):
Steven M. Gava052937f2002-02-11 02:20:53 +0000807 #user didn't cancel, and they chose a new colour
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400808 if self.themeIsBuiltin.get(): #current theme is a built-in
809 message = ('Your changes will be saved as a new Custom Theme. '
810 'Enter a name for your new Custom Theme below.')
811 newTheme = self.GetNewThemeName(message)
812 if not newTheme: #user cancelled custom theme creation
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000813 return
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400814 else: #create new custom theme based on previously active theme
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000815 self.CreateNewTheme(newTheme)
Steven M. Gava052937f2002-02-11 02:20:53 +0000816 self.colour.set(colourString)
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400817 else: #current theme is user defined
Steven M. Gava052937f2002-02-11 02:20:53 +0000818 self.colour.set(colourString)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000819
Steven M. Gava052937f2002-02-11 02:20:53 +0000820 def OnNewColourSet(self):
821 newColour=self.colour.get()
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400822 self.frameColourSet.config(bg=newColour) #set sample
823 plane ='foreground' if self.fgHilite.get() else 'background'
824 sampleElement = self.themeElements[self.highlightTarget.get()][0]
Raymond Hettinger931237e2003-07-09 18:48:24 +0000825 self.textHighlightSample.tag_config(sampleElement, **{plane:newColour})
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400826 theme = self.customTheme.get()
827 themeElement = sampleElement + '-' + plane
828 self.AddChangedItem('highlight', theme, themeElement, newColour)
Steven M. Gava052937f2002-02-11 02:20:53 +0000829
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400830 def GetNewThemeName(self, message):
831 usedNames = (idleConf.GetSectionList('user', 'highlight') +
832 idleConf.GetSectionList('default', 'highlight'))
833 newTheme = GetCfgSectionNameDialog(
834 self, 'New Custom Theme', message, usedNames).result
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000835 return newTheme
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000836
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000837 def SaveAsNewTheme(self):
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400838 newThemeName = self.GetNewThemeName('New Theme Name:')
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000839 if newThemeName:
840 self.CreateNewTheme(newThemeName)
841
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400842 def CreateNewTheme(self, newThemeName):
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000843 #creates new custom theme based on the previously active theme,
844 #and makes the new theme active
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000845 if self.themeIsBuiltin.get():
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400846 themeType = 'default'
847 themeName = self.builtinTheme.get()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000848 else:
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400849 themeType = 'user'
850 themeName = self.customTheme.get()
851 newTheme = idleConf.GetThemeDict(themeType, themeName)
Steven M. Gava052937f2002-02-11 02:20:53 +0000852 #apply any of the old theme's unsaved changes to the new theme
Kurt B. Kaisere0712772007-08-23 05:25:55 +0000853 if themeName in self.changedItems['highlight']:
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400854 themeChanges = self.changedItems['highlight'][themeName]
Kurt B. Kaisere0712772007-08-23 05:25:55 +0000855 for element in themeChanges:
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400856 newTheme[element] = themeChanges[element]
Steven M. Gava052937f2002-02-11 02:20:53 +0000857 #save the new theme
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400858 self.SaveNewTheme(newThemeName, newTheme)
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000859 #change gui over to the new theme
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400860 customThemeList = idleConf.GetSectionList('user', 'highlight')
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000861 customThemeList.sort()
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400862 self.optMenuThemeCustom.SetMenu(customThemeList, newThemeName)
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000863 self.themeIsBuiltin.set(0)
864 self.SetThemeType()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000865
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400866 def OnListFontButtonRelease(self, event):
Kurt B. Kaiser05391692003-05-26 20:35:53 +0000867 font = self.listFontName.get(ANCHOR)
868 self.fontName.set(font.lower())
Steven M. Gava5f28e8f2002-01-21 06:38:21 +0000869 self.SetFontSample()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000870
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400871 def SetFontSample(self, event=None):
872 fontName = self.fontName.get()
873 fontWeight = tkFont.BOLD if self.fontBold.get() else tkFont.NORMAL
Ned Deilyfdf0f272012-10-22 15:14:31 -0700874 newFont = (fontName, self.fontSize.get(), fontWeight)
875 self.labelFontSample.config(font=newFont)
876 self.textHighlightSample.configure(font=newFont)
Steven M. Gava5f28e8f2002-01-21 06:38:21 +0000877
Steven M. Gava5f28e8f2002-01-21 06:38:21 +0000878 def SetHighlightTarget(self):
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400879 if self.highlightTarget.get() == 'Cursor': #bg not possible
Steven M. Gava5f28e8f2002-01-21 06:38:21 +0000880 self.radioFg.config(state=DISABLED)
881 self.radioBg.config(state=DISABLED)
882 self.fgHilite.set(1)
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400883 else: #both fg and bg can be set
Steven M. Gava5f28e8f2002-01-21 06:38:21 +0000884 self.radioFg.config(state=NORMAL)
885 self.radioBg.config(state=NORMAL)
886 self.fgHilite.set(1)
887 self.SetColourSample()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000888
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400889 def SetColourSampleBinding(self, *args):
Steven M. Gava5f28e8f2002-01-21 06:38:21 +0000890 self.SetColourSample()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000891
Steven M. Gava5f28e8f2002-01-21 06:38:21 +0000892 def SetColourSample(self):
893 #set the colour smaple area
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400894 tag = self.themeElements[self.highlightTarget.get()][0]
895 plane = 'foreground' if self.fgHilite.get() else 'background'
896 colour = self.textHighlightSample.tag_cget(tag, plane)
Steven M. Gava5f28e8f2002-01-21 06:38:21 +0000897 self.frameColourSet.config(bg=colour)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000898
Steven M. Gava9dd16b32001-11-03 14:54:25 +0000899 def PaintThemeSample(self):
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400900 if self.themeIsBuiltin.get(): #a default theme
901 theme = self.builtinTheme.get()
902 else: #a user theme
903 theme = self.customTheme.get()
Kurt B. Kaisere0712772007-08-23 05:25:55 +0000904 for elementTitle in self.themeElements:
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400905 element = self.themeElements[elementTitle][0]
906 colours = idleConf.GetHighlight(theme, element)
907 if element == 'cursor': #cursor sample needs special painting
908 colours['background'] = idleConf.GetHighlight(
909 theme, 'normal', fgBg='bg')
Steven M. Gava052937f2002-02-11 02:20:53 +0000910 #handle any unsaved changes to this theme
Kurt B. Kaisere0712772007-08-23 05:25:55 +0000911 if theme in self.changedItems['highlight']:
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400912 themeDict = self.changedItems['highlight'][theme]
913 if element + '-foreground' in themeDict:
914 colours['foreground'] = themeDict[element + '-foreground']
915 if element + '-background' in themeDict:
916 colours['background'] = themeDict[element + '-background']
Raymond Hettinger931237e2003-07-09 18:48:24 +0000917 self.textHighlightSample.tag_config(element, **colours)
Steven M. Gava052937f2002-02-11 02:20:53 +0000918 self.SetColourSample()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000919
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400920 def HelpSourceSelected(self, event):
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000921 self.SetHelpListButtonStates()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000922
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000923 def SetHelpListButtonStates(self):
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400924 if self.listHelp.size() < 1: #no entries in list
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000925 self.buttonHelpListEdit.config(state=DISABLED)
926 self.buttonHelpListRemove.config(state=DISABLED)
927 else: #there are some entries
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400928 if self.listHelp.curselection(): #there currently is a selection
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000929 self.buttonHelpListEdit.config(state=NORMAL)
930 self.buttonHelpListRemove.config(state=NORMAL)
931 else: #there currently is not a selection
932 self.buttonHelpListEdit.config(state=DISABLED)
933 self.buttonHelpListRemove.config(state=DISABLED)
934
935 def HelpListItemAdd(self):
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400936 helpSource = GetHelpSourceDialog(self, 'New Help Source').result
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000937 if helpSource:
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400938 self.userHelpList.append((helpSource[0], helpSource[1]))
939 self.listHelp.insert(END, helpSource[0])
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000940 self.UpdateUserHelpChangedItems()
941 self.SetHelpListButtonStates()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000942
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000943 def HelpListItemEdit(self):
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400944 itemIndex = self.listHelp.index(ANCHOR)
945 helpSource = self.userHelpList[itemIndex]
946 newHelpSource = GetHelpSourceDialog(
947 self, 'Edit Help Source', menuItem=helpSource[0],
948 filePath=helpSource[1]).result
949 if (not newHelpSource) or (newHelpSource == helpSource):
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000950 return #no changes
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400951 self.userHelpList[itemIndex] = newHelpSource
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000952 self.listHelp.delete(itemIndex)
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400953 self.listHelp.insert(itemIndex, newHelpSource[0])
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000954 self.UpdateUserHelpChangedItems()
955 self.SetHelpListButtonStates()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000956
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000957 def HelpListItemRemove(self):
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400958 itemIndex = self.listHelp.index(ANCHOR)
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000959 del(self.userHelpList[itemIndex])
960 self.listHelp.delete(itemIndex)
961 self.UpdateUserHelpChangedItems()
962 self.SetHelpListButtonStates()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000963
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000964 def UpdateUserHelpChangedItems(self):
Kurt B. Kaiser8e92bf72003-01-14 22:03:31 +0000965 "Clear and rebuild the HelpFiles section in self.changedItems"
966 self.changedItems['main']['HelpFiles'] = {}
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400967 for num in range(1, len(self.userHelpList) + 1):
968 self.AddChangedItem(
969 'main', 'HelpFiles', str(num),
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000970 ';'.join(self.userHelpList[num-1][:2]))
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000971
Steven M. Gava429a86af2001-10-23 10:42:12 +0000972 def LoadFontCfg(self):
973 ##base editor font selection list
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400974 fonts = list(tkFont.families(self))
Steven M. Gavac11ccf32001-09-24 09:43:17 +0000975 fonts.sort()
976 for font in fonts:
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400977 self.listFontName.insert(END, font)
978 configuredFont = idleConf.GetOption(
979 'main', 'EditorWindow', 'font', default='courier')
Kurt B. Kaiser05391692003-05-26 20:35:53 +0000980 lc_configuredFont = configuredFont.lower()
981 self.fontName.set(lc_configuredFont)
982 lc_fonts = [s.lower() for s in fonts]
983 if lc_configuredFont in lc_fonts:
984 currentFontIndex = lc_fonts.index(lc_configuredFont)
Steven M. Gava429a86af2001-10-23 10:42:12 +0000985 self.listFontName.see(currentFontIndex)
986 self.listFontName.select_set(currentFontIndex)
Steven M. Gavac112cd82002-01-22 05:56:40 +0000987 self.listFontName.select_anchor(currentFontIndex)
Steven M. Gava429a86af2001-10-23 10:42:12 +0000988 ##font size dropdown
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400989 fontSize = idleConf.GetOption(
990 'main', 'EditorWindow', 'font-size', type='int', default='10')
991 self.optMenuFontSize.SetMenu(('7', '8', '9', '10', '11', '12', '13',
992 '14', '16', '18', '20', '22'), fontSize )
Steven M. Gavac112cd82002-01-22 05:56:40 +0000993 ##fontWeight
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400994 self.fontBold.set(idleConf.GetOption(
995 'main', 'EditorWindow', 'font-bold', default=0, type='bool'))
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000996 ##font sample
Steven M. Gava429a86af2001-10-23 10:42:12 +0000997 self.SetFontSample()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000998
Steven M. Gava429a86af2001-10-23 10:42:12 +0000999 def LoadTabCfg(self):
Steven M. Gava429a86af2001-10-23 10:42:12 +00001000 ##indent sizes
Terry Jan Reedy4036d872014-08-03 23:02:58 -04001001 spaceNum = idleConf.GetOption(
1002 'main', 'Indent', 'num-spaces', default=4, type='int')
Steven M. Gava429a86af2001-10-23 10:42:12 +00001003 self.spaceNum.set(spaceNum)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001004
Steven M. Gava9dd16b32001-11-03 14:54:25 +00001005 def LoadThemeCfg(self):
Steven M. Gava41a85322001-10-29 08:05:34 +00001006 ##current theme type radiobutton
Terry Jan Reedy4036d872014-08-03 23:02:58 -04001007 self.themeIsBuiltin.set(idleConf.GetOption(
1008 'main', 'Theme', 'default', type='bool', default=1))
Steven M. Gava41a85322001-10-29 08:05:34 +00001009 ##currently set theme
Terry Jan Reedy4036d872014-08-03 23:02:58 -04001010 currentOption = idleConf.CurrentTheme()
Steven M. Gava7c017862001-10-29 11:19:46 +00001011 ##load available theme option menus
Steven M. Gavad0342cd2001-11-04 11:53:10 +00001012 if self.themeIsBuiltin.get(): #default theme selected
Terry Jan Reedy4036d872014-08-03 23:02:58 -04001013 itemList = idleConf.GetSectionList('default', 'highlight')
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +00001014 itemList.sort()
Terry Jan Reedy4036d872014-08-03 23:02:58 -04001015 self.optMenuThemeBuiltin.SetMenu(itemList, currentOption)
1016 itemList = idleConf.GetSectionList('user', 'highlight')
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +00001017 itemList.sort()
Steven M. Gava41a85322001-10-29 08:05:34 +00001018 if not itemList:
1019 self.radioThemeCustom.config(state=DISABLED)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001020 self.customTheme.set('- no custom themes -')
Steven M. Gava41a85322001-10-29 08:05:34 +00001021 else:
Terry Jan Reedy4036d872014-08-03 23:02:58 -04001022 self.optMenuThemeCustom.SetMenu(itemList, itemList[0])
Steven M. Gava9dd16b32001-11-03 14:54:25 +00001023 else: #user theme selected
Terry Jan Reedy4036d872014-08-03 23:02:58 -04001024 itemList = idleConf.GetSectionList('user', 'highlight')
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +00001025 itemList.sort()
Terry Jan Reedy4036d872014-08-03 23:02:58 -04001026 self.optMenuThemeCustom.SetMenu(itemList, currentOption)
1027 itemList = idleConf.GetSectionList('default', 'highlight')
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +00001028 itemList.sort()
Terry Jan Reedy4036d872014-08-03 23:02:58 -04001029 self.optMenuThemeBuiltin.SetMenu(itemList, itemList[0])
Steven M. Gava7c017862001-10-29 11:19:46 +00001030 self.SetThemeType()
1031 ##load theme element option menu
Kurt B. Kaisere0712772007-08-23 05:25:55 +00001032 themeNames = list(self.themeElements.keys())
Kurt B. Kaiser4718bf82008-02-12 21:34:12 +00001033 themeNames.sort(key=lambda x: self.themeElements[x][1])
Terry Jan Reedy4036d872014-08-03 23:02:58 -04001034 self.optMenuHighlightTarget.SetMenu(themeNames, themeNames[0])
Steven M. Gava9dd16b32001-11-03 14:54:25 +00001035 self.PaintThemeSample()
Steven M. Gava0cae01c2002-01-04 07:53:06 +00001036 self.SetHighlightTarget()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001037
Steven M. Gava9dd16b32001-11-03 14:54:25 +00001038 def LoadKeyCfg(self):
Steven M. Gava41a85322001-10-29 08:05:34 +00001039 ##current keys type radiobutton
Terry Jan Reedy4036d872014-08-03 23:02:58 -04001040 self.keysAreBuiltin.set(idleConf.GetOption(
1041 'main', 'Keys', 'default', type='bool', default=1))
Steven M. Gava41a85322001-10-29 08:05:34 +00001042 ##currently set keys
Terry Jan Reedy4036d872014-08-03 23:02:58 -04001043 currentOption = idleConf.CurrentKeys()
Steven M. Gava7c017862001-10-29 11:19:46 +00001044 ##load available keyset option menus
Steven M. Gava052937f2002-02-11 02:20:53 +00001045 if self.keysAreBuiltin.get(): #default theme selected
Terry Jan Reedy4036d872014-08-03 23:02:58 -04001046 itemList = idleConf.GetSectionList('default', 'keys')
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +00001047 itemList.sort()
Terry Jan Reedy4036d872014-08-03 23:02:58 -04001048 self.optMenuKeysBuiltin.SetMenu(itemList, currentOption)
1049 itemList = idleConf.GetSectionList('user', 'keys')
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +00001050 itemList.sort()
Steven M. Gava41a85322001-10-29 08:05:34 +00001051 if not itemList:
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001052 self.radioKeysCustom.config(state=DISABLED)
1053 self.customKeys.set('- no custom keys -')
Steven M. Gava41a85322001-10-29 08:05:34 +00001054 else:
Terry Jan Reedy4036d872014-08-03 23:02:58 -04001055 self.optMenuKeysCustom.SetMenu(itemList, itemList[0])
Steven M. Gavaa498af22002-02-01 01:33:36 +00001056 else: #user key set selected
Terry Jan Reedy4036d872014-08-03 23:02:58 -04001057 itemList = idleConf.GetSectionList('user', 'keys')
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +00001058 itemList.sort()
Terry Jan Reedy4036d872014-08-03 23:02:58 -04001059 self.optMenuKeysCustom.SetMenu(itemList, currentOption)
1060 itemList = idleConf.GetSectionList('default', 'keys')
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +00001061 itemList.sort()
Terry Jan Reedy4036d872014-08-03 23:02:58 -04001062 self.optMenuKeysBuiltin.SetMenu(itemList, itemList[0])
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001063 self.SetKeysType()
Steven M. Gavafacfc092002-01-19 00:29:54 +00001064 ##load keyset element list
Terry Jan Reedy4036d872014-08-03 23:02:58 -04001065 keySetName = idleConf.CurrentKeys()
Steven M. Gava052937f2002-02-11 02:20:53 +00001066 self.LoadKeysList(keySetName)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001067
Steven M. Gavafacfc092002-01-19 00:29:54 +00001068 def LoadGeneralCfg(self):
Steven M. Gava5f28e8f2002-01-21 06:38:21 +00001069 #startup state
Terry Jan Reedy4036d872014-08-03 23:02:58 -04001070 self.startupEdit.set(idleConf.GetOption(
1071 'main', 'General', 'editor-on-startup', default=1, type='bool'))
Kurt B. Kaiser6c638b62003-05-26 06:23:10 +00001072 #autosave state
Terry Jan Reedy4036d872014-08-03 23:02:58 -04001073 self.autoSave.set(idleConf.GetOption(
1074 'main', 'General', 'autosave', default=0, type='bool'))
Steven M. Gavafacfc092002-01-19 00:29:54 +00001075 #initial window size
Terry Jan Reedy4036d872014-08-03 23:02:58 -04001076 self.winWidth.set(idleConf.GetOption(
1077 'main', 'EditorWindow', 'width', type='int'))
1078 self.winHeight.set(idleConf.GetOption(
1079 'main', 'EditorWindow', 'height', type='int'))
Raymond Hettinger4e49b832004-06-04 06:31:08 +00001080 #initial paragraph reformat size
Terry Jan Reedy4036d872014-08-03 23:02:58 -04001081 self.paraWidth.set(idleConf.GetOption(
1082 'main', 'FormatParagraph', 'paragraph', type='int'))
Kurt B. Kaisera053f332003-05-10 00:49:56 +00001083 # default source encoding
Terry Jan Reedy4036d872014-08-03 23:02:58 -04001084 self.encoding.set(idleConf.GetOption(
1085 'main', 'EditorWindow', 'encoding', default='none'))
Kurt B. Kaiser8e92bf72003-01-14 22:03:31 +00001086 # additional help sources
1087 self.userHelpList = idleConf.GetAllExtraHelpSourcesList()
Steven M. Gava085eb1b2002-02-05 04:52:32 +00001088 for helpItem in self.userHelpList:
Terry Jan Reedy4036d872014-08-03 23:02:58 -04001089 self.listHelp.insert(END, helpItem[0])
Steven M. Gava085eb1b2002-02-05 04:52:32 +00001090 self.SetHelpListButtonStates()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001091
Steven M. Gava429a86af2001-10-23 10:42:12 +00001092 def LoadConfigs(self):
1093 """
1094 load configuration from default and user config files and populate
1095 the widgets on the config dialog pages.
1096 """
1097 ### fonts / tabs page
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001098 self.LoadFontCfg()
1099 self.LoadTabCfg()
Steven M. Gava429a86af2001-10-23 10:42:12 +00001100 ### highlighting page
Steven M. Gava9dd16b32001-11-03 14:54:25 +00001101 self.LoadThemeCfg()
Steven M. Gava429a86af2001-10-23 10:42:12 +00001102 ### keys page
Steven M. Gava9dd16b32001-11-03 14:54:25 +00001103 self.LoadKeyCfg()
Steven M. Gava429a86af2001-10-23 10:42:12 +00001104 ### general page
Steven M. Gavafacfc092002-01-19 00:29:54 +00001105 self.LoadGeneralCfg()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001106
Terry Jan Reedy4036d872014-08-03 23:02:58 -04001107 def SaveNewKeySet(self, keySetName, keySet):
Steven M. Gava052937f2002-02-11 02:20:53 +00001108 """
1109 save a newly created core key set.
1110 keySetName - string, the name of the new key set
1111 keySet - dictionary containing the new key set
1112 """
1113 if not idleConf.userCfg['keys'].has_section(keySetName):
1114 idleConf.userCfg['keys'].add_section(keySetName)
Kurt B. Kaisere0712772007-08-23 05:25:55 +00001115 for event in keySet:
Terry Jan Reedy4036d872014-08-03 23:02:58 -04001116 value = keySet[event]
1117 idleConf.userCfg['keys'].SetOption(keySetName, event, value)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001118
Terry Jan Reedy4036d872014-08-03 23:02:58 -04001119 def SaveNewTheme(self, themeName, theme):
Steven M. Gava052937f2002-02-11 02:20:53 +00001120 """
1121 save a newly created theme.
1122 themeName - string, the name of the new theme
1123 theme - dictionary containing the new theme
1124 """
1125 if not idleConf.userCfg['highlight'].has_section(themeName):
1126 idleConf.userCfg['highlight'].add_section(themeName)
Kurt B. Kaisere0712772007-08-23 05:25:55 +00001127 for element in theme:
Terry Jan Reedy4036d872014-08-03 23:02:58 -04001128 value = theme[element]
1129 idleConf.userCfg['highlight'].SetOption(themeName, element, value)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001130
Terry Jan Reedy4036d872014-08-03 23:02:58 -04001131 def SetUserValue(self, configType, section, item, value):
1132 if idleConf.defaultCfg[configType].has_option(section, item):
1133 if idleConf.defaultCfg[configType].Get(section, item) == value:
Steven M. Gava2d7bb3f2002-01-29 08:35:29 +00001134 #the setting equals a default setting, remove it from user cfg
Terry Jan Reedy4036d872014-08-03 23:02:58 -04001135 return idleConf.userCfg[configType].RemoveOption(section, item)
Steven M. Gava2d7bb3f2002-01-29 08:35:29 +00001136 #if we got here set the option
Terry Jan Reedy4036d872014-08-03 23:02:58 -04001137 return idleConf.userCfg[configType].SetOption(section, item, value)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001138
Steven M. Gava052937f2002-02-11 02:20:53 +00001139 def SaveAllChangedConfigs(self):
Kurt B. Kaisere7a161e2003-01-10 20:13:57 +00001140 "Save configuration changes to the user config file."
Steven M. Gava0c5bc8c2002-03-27 02:25:44 +00001141 idleConf.userCfg['main'].Save()
Kurt B. Kaisere0712772007-08-23 05:25:55 +00001142 for configType in self.changedItems:
Kurt B. Kaisere7a161e2003-01-10 20:13:57 +00001143 cfgTypeHasChanges = False
Kurt B. Kaisere0712772007-08-23 05:25:55 +00001144 for section in self.changedItems[configType]:
Kurt B. Kaisere7a161e2003-01-10 20:13:57 +00001145 if section == 'HelpFiles':
1146 #this section gets completely replaced
1147 idleConf.userCfg['main'].remove_section('HelpFiles')
Kurt B. Kaiser8e92bf72003-01-14 22:03:31 +00001148 cfgTypeHasChanges = True
Kurt B. Kaisere0712772007-08-23 05:25:55 +00001149 for item in self.changedItems[configType][section]:
Kurt B. Kaisere7a161e2003-01-10 20:13:57 +00001150 value = self.changedItems[configType][section][item]
Terry Jan Reedy4036d872014-08-03 23:02:58 -04001151 if self.SetUserValue(configType, section, item, value):
Kurt B. Kaisere7a161e2003-01-10 20:13:57 +00001152 cfgTypeHasChanges = True
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001153 if cfgTypeHasChanges:
1154 idleConf.userCfg[configType].Save()
Kurt B. Kaiser5acdf932004-11-16 21:28:36 +00001155 for configType in ['keys', 'highlight']:
1156 # save these even if unchanged!
1157 idleConf.userCfg[configType].Save()
Steven M. Gavaa498af22002-02-01 01:33:36 +00001158 self.ResetChangedItems() #clear the changed items dict
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001159
Kurt B. Kaiserb1754452005-11-18 22:05:48 +00001160 def DeactivateCurrentConfig(self):
1161 #Before a config is saved, some cleanup of current
1162 #config must be done - remove the previous keybindings
Kurt B. Kaisere0712772007-08-23 05:25:55 +00001163 winInstances = self.parent.instance_dict.keys()
Kurt B. Kaiserb1754452005-11-18 22:05:48 +00001164 for instance in winInstances:
1165 instance.RemoveKeybindings()
1166
Steven M. Gava49745752002-02-18 01:43:11 +00001167 def ActivateConfigChanges(self):
Kurt B. Kaiseracdef852005-01-31 03:34:26 +00001168 "Dynamically apply configuration changes"
Kurt B. Kaisere0712772007-08-23 05:25:55 +00001169 winInstances = self.parent.instance_dict.keys()
Steven M. Gavab77d3432002-03-02 07:16:21 +00001170 for instance in winInstances:
1171 instance.ResetColorizer()
Steven M. Gavab1585412002-03-12 00:21:56 +00001172 instance.ResetFont()
Kurt B. Kaiseracdef852005-01-31 03:34:26 +00001173 instance.set_notabs_indentwidth()
Kurt B. Kaiserb1754452005-11-18 22:05:48 +00001174 instance.ApplyKeybindings()
Kurt B. Kaiser8e92bf72003-01-14 22:03:31 +00001175 instance.reset_help_menu_entries()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001176
Steven M. Gava5f28e8f2002-01-21 06:38:21 +00001177 def Cancel(self):
1178 self.destroy()
1179
1180 def Ok(self):
1181 self.Apply()
1182 self.destroy()
1183
1184 def Apply(self):
Kurt B. Kaiserb1754452005-11-18 22:05:48 +00001185 self.DeactivateCurrentConfig()
Steven M. Gava052937f2002-02-11 02:20:53 +00001186 self.SaveAllChangedConfigs()
Steven M. Gava49745752002-02-18 01:43:11 +00001187 self.ActivateConfigChanges()
Steven M. Gava5f28e8f2002-01-21 06:38:21 +00001188
1189 def Help(self):
Steven M. Gavac11ccf32001-09-24 09:43:17 +00001190 pass
1191
Terry Jan Reedya9421fb2014-10-22 20:15:18 -04001192class VerticalScrolledFrame(Frame):
1193 """A pure Tkinter vertically scrollable frame.
1194
1195 * Use the 'interior' attribute to place widgets inside the scrollable frame
1196 * Construct and pack/place/grid normally
1197 * This frame only allows vertical scrolling
1198 """
1199 def __init__(self, parent, *args, **kw):
1200 Frame.__init__(self, parent, *args, **kw)
1201
1202 # create a canvas object and a vertical scrollbar for scrolling it
1203 vscrollbar = Scrollbar(self, orient=VERTICAL)
1204 vscrollbar.pack(fill=Y, side=RIGHT, expand=FALSE)
1205 canvas = Canvas(self, bd=0, highlightthickness=0,
1206 yscrollcommand=vscrollbar.set)
1207 canvas.pack(side=LEFT, fill=BOTH, expand=TRUE)
1208 vscrollbar.config(command=canvas.yview)
1209
1210 # reset the view
1211 canvas.xview_moveto(0)
1212 canvas.yview_moveto(0)
1213
1214 # create a frame inside the canvas which will be scrolled with it
1215 self.interior = interior = Frame(canvas)
1216 interior_id = canvas.create_window(0, 0, window=interior, anchor=NW)
1217
1218 # track changes to the canvas and frame width and sync them,
1219 # also updating the scrollbar
1220 def _configure_interior(event):
1221 # update the scrollbars to match the size of the inner frame
1222 size = (interior.winfo_reqwidth(), interior.winfo_reqheight())
1223 canvas.config(scrollregion="0 0 %s %s" % size)
1224 if interior.winfo_reqwidth() != canvas.winfo_width():
1225 # update the canvas's width to fit the inner frame
1226 canvas.config(width=interior.winfo_reqwidth())
1227 interior.bind('<Configure>', _configure_interior)
1228
1229 def _configure_canvas(event):
1230 if interior.winfo_reqwidth() != canvas.winfo_width():
1231 # update the inner frame's width to fill the canvas
1232 canvas.itemconfigure(interior_id, width=canvas.winfo_width())
1233 canvas.bind('<Configure>', _configure_canvas)
1234
1235 return
1236
1237def is_int(s):
1238 "Return 's is blank or represents an int'"
1239 if not s:
1240 return True
1241 try:
1242 int(s)
1243 return True
1244 except ValueError:
1245 return False
1246
1247# TODO:
1248# * Revert to default(s)? Per option or per extension?
1249# * List options in their original order (possible??)
1250class ConfigExtensionsDialog(Toplevel):
1251 """A dialog for configuring IDLE extensions.
1252
1253 This dialog is generic - it works for any and all IDLE extensions.
1254
1255 IDLE extensions save their configuration options using idleConf.
1256 ConfigExtensionsDialog reads the current configuration using idleConf,
1257 supplies a GUI interface to change the configuration values, and saves the
1258 changes using idleConf.
1259
1260 Not all changes take effect immediately - some may require restarting IDLE.
1261 This depends on each extension's implementation.
1262
1263 All values are treated as text, and it is up to the user to supply
1264 reasonable values. The only exception to this are the 'enable*' options,
1265 which are boolean, and can be toggled with an True/False button.
1266 """
1267 def __init__(self, parent, title=None, _htest=False):
1268 Toplevel.__init__(self, parent)
1269 self.wm_withdraw()
1270
1271 self.configure(borderwidth=5)
1272 self.geometry(
1273 "+%d+%d" % (parent.winfo_rootx() + 20,
1274 parent.winfo_rooty() + (30 if not _htest else 150)))
1275 self.wm_title(title or 'IDLE Extensions Configuration')
1276
1277 self.defaultCfg = idleConf.defaultCfg['extensions']
1278 self.userCfg = idleConf.userCfg['extensions']
1279 self.is_int = self.register(is_int)
1280 self.load_extensions()
1281 self.create_widgets()
1282
1283 self.resizable(height=FALSE, width=FALSE) # don't allow resizing yet
1284 self.transient(parent)
1285 self.protocol("WM_DELETE_WINDOW", self.Cancel)
1286 self.tabbed_page_set.focus_set()
1287 # wait for window to be generated
1288 self.update()
1289 # set current width as the minimum width
1290 self.wm_minsize(self.winfo_width(), 1)
1291 # now allow resizing
1292 self.resizable(height=TRUE, width=TRUE)
1293
1294 self.wm_deiconify()
1295 if not _htest:
1296 self.grab_set()
1297 self.wait_window()
1298
1299 def load_extensions(self):
1300 "Fill self.extensions with data from the default and user configs."
1301 self.extensions = {}
1302 for ext_name in idleConf.GetExtensions(active_only=False):
1303 self.extensions[ext_name] = []
1304
1305 for ext_name in self.extensions:
1306 opt_list = sorted(self.defaultCfg.GetOptionList(ext_name))
1307
1308 # bring 'enable' options to the beginning of the list
1309 enables = [opt_name for opt_name in opt_list
1310 if opt_name.startswith('enable')]
1311 for opt_name in enables:
1312 opt_list.remove(opt_name)
1313 opt_list = enables + opt_list
1314
1315 for opt_name in opt_list:
1316 def_str = self.defaultCfg.Get(
1317 ext_name, opt_name, raw=True)
1318 try:
1319 def_obj = {'True':True, 'False':False}[def_str]
1320 opt_type = 'bool'
1321 except KeyError:
1322 try:
1323 def_obj = int(def_str)
1324 opt_type = 'int'
1325 except ValueError:
1326 def_obj = def_str
1327 opt_type = None
1328 try:
1329 value = self.userCfg.Get(
1330 ext_name, opt_name, type=opt_type, raw=True,
1331 default=def_obj)
1332 except ValueError: # Need this until .Get fixed
1333 value = def_obj # bad values overwritten by entry
1334 var = StringVar(self)
1335 var.set(str(value))
1336
1337 self.extensions[ext_name].append({'name': opt_name,
1338 'type': opt_type,
1339 'default': def_str,
1340 'value': value,
1341 'var': var,
1342 })
1343
1344 def create_widgets(self):
1345 """Create the dialog's widgets."""
1346 self.rowconfigure(0, weight=1)
1347 self.rowconfigure(1, weight=0)
1348 self.columnconfigure(0, weight=1)
1349
1350 # create the tabbed pages
1351 self.tabbed_page_set = TabbedPageSet(
1352 self, page_names=self.extensions.keys(),
1353 n_rows=None, max_tabs_per_row=5,
1354 page_class=TabbedPageSet.PageRemove)
1355 self.tabbed_page_set.grid(row=0, column=0, sticky=NSEW)
1356 for ext_name in self.extensions:
1357 self.create_tab_page(ext_name)
1358
1359 self.create_action_buttons().grid(row=1)
1360
1361 create_action_buttons = ConfigDialog.create_action_buttons
1362
1363 def create_tab_page(self, ext_name):
1364 """Create the page for an extension."""
1365
1366 page = LabelFrame(self.tabbed_page_set.pages[ext_name].frame,
1367 border=2, padx=2, relief=GROOVE,
1368 text=' %s ' % ext_name)
1369 page.pack(fill=BOTH, expand=True, padx=12, pady=2)
1370
1371 # create the scrollable frame which will contain the entries
1372 scrolled_frame = VerticalScrolledFrame(page, pady=2, height=250)
1373 scrolled_frame.pack(side=BOTTOM, fill=BOTH, expand=TRUE)
1374 entry_area = scrolled_frame.interior
1375 entry_area.columnconfigure(0, weight=0)
1376 entry_area.columnconfigure(1, weight=1)
1377
1378 # create an entry for each configuration option
1379 for row, opt in enumerate(self.extensions[ext_name]):
1380 # create a row with a label and entry/checkbutton
1381 label = Label(entry_area, text=opt['name'])
1382 label.grid(row=row, column=0, sticky=NW)
1383 var = opt['var']
1384 if opt['type'] == 'bool':
1385 Checkbutton(entry_area, textvariable=var, variable=var,
1386 onvalue='True', offvalue='False',
1387 indicatoron=FALSE, selectcolor='', width=8
1388 ).grid(row=row, column=1, sticky=W, padx=7)
1389 elif opt['type'] == 'int':
1390 Entry(entry_area, textvariable=var, validate='key',
1391 validatecommand=(self.is_int, '%P')
1392 ).grid(row=row, column=1, sticky=NSEW, padx=7)
1393
1394 else:
1395 Entry(entry_area, textvariable=var
1396 ).grid(row=row, column=1, sticky=NSEW, padx=7)
1397 return
1398
1399
1400 Ok = ConfigDialog.Ok
1401
1402 def Apply(self):
1403 self.save_all_changed_configs()
1404 pass
1405
1406 Cancel = ConfigDialog.Cancel
1407
1408 def Help(self):
1409 pass
1410
1411 def set_user_value(self, section, opt):
1412 name = opt['name']
1413 default = opt['default']
1414 value = opt['var'].get().strip() or default
1415 opt['var'].set(value)
1416 # if self.defaultCfg.has_section(section):
1417 # Currently, always true; if not, indent to return
1418 if (value == default):
1419 return self.userCfg.RemoveOption(section, name)
1420 # set the option
1421 return self.userCfg.SetOption(section, name, value)
1422
1423 def save_all_changed_configs(self):
1424 """Save configuration changes to the user config file."""
1425 has_changes = False
1426 for ext_name in self.extensions:
1427 options = self.extensions[ext_name]
1428 for opt in options:
1429 if self.set_user_value(ext_name, opt):
1430 has_changes = True
1431 if has_changes:
1432 self.userCfg.Save()
1433
1434
Steven M. Gava44d3d1a2001-07-31 06:59:02 +00001435if __name__ == '__main__':
Terry Jan Reedycfa89502014-07-14 23:07:32 -04001436 import unittest
1437 unittest.main('idlelib.idle_test.test_configdialog',
1438 verbosity=2, exit=False)
Terry Jan Reedy2e8234a2014-05-29 01:46:26 -04001439 from idlelib.idle_test.htest import run
Terry Jan Reedya9421fb2014-10-22 20:15:18 -04001440 run(ConfigDialog, ConfigExtensionsDialog)