blob: 6d152bdf5c8e4c7d9d27fe6ec1fc4342eeafd9fc [file] [log] [blame]
Kurt B. Kaisere7a161e2003-01-10 20:13:57 +00001"""IDLE Configuration Dialog: support user customization of IDLE by GUI
2
3Customize font faces, sizes, and colorization attributes. Set indentation
4defaults. Customize keybindings. Colorization and keybindings can be
5saved as user defined sets. Select startup options including shell/editor
6and default window size. Define additional help sources.
7
8Note that tab width in IDLE is currently fixed at eight due to Tk issues.
Kurt B. Kaiseracdef852005-01-31 03:34:26 +00009Refer to comments in EditorWindow autoindent code for details.
Kurt B. Kaisere7a161e2003-01-10 20:13:57 +000010
Steven M. Gava44d3d1a2001-07-31 06:59:02 +000011"""
Georg Brandl6634bf22008-05-20 07:13:37 +000012from Tkinter import *
13import tkMessageBox, tkColorChooser, tkFont
Steven M. Gava44d3d1a2001-07-31 06:59:02 +000014
Florent Xiclunad630c042010-04-02 07:24:52 +000015from idlelib.configHandler import idleConf
16from idlelib.dynOptionMenuWidget import DynOptionMenu
Florent Xiclunad630c042010-04-02 07:24:52 +000017from idlelib.keybindingDialog import GetKeysDialog
18from idlelib.configSectionNameDialog import GetCfgSectionNameDialog
19from idlelib.configHelpSourceEdit import GetHelpSourceDialog
Terry Jan Reedy7a162072014-10-22 20:15:12 -040020from idlelib.tabbedpages import TabbedPageSet
Florent Xiclunad630c042010-04-02 07:24:52 +000021from idlelib import macosxSupport
Steven M. Gava44d3d1a2001-07-31 06:59:02 +000022class ConfigDialog(Toplevel):
Kurt B. Kaiseracdef852005-01-31 03:34:26 +000023
Terry Jan Reedycf834762014-10-17 01:31:29 -040024 def __init__(self, parent, title='', _htest=False, _utest=False):
Terry Jan Reedy76916e82014-05-29 01:46:16 -040025 """
26 _htest - bool, change box location when running htest
Terry Jan Reedyaf0dce92014-07-14 23:07:21 -040027 _utest - bool, don't wait_window when running unittest
Terry Jan Reedy76916e82014-05-29 01:46:16 -040028 """
Steven M. Gavad721c482001-07-31 10:46:53 +000029 Toplevel.__init__(self, parent)
Terry Jan Reedy19b7a752014-07-30 19:24:26 -040030 self.parent = parent
Terry Jan Reedyae410862014-08-03 23:02:53 -040031 if _htest:
32 parent.instance_dict = {}
Kurt B. Kaisere3fde8f2007-10-04 03:11:12 +000033 self.wm_withdraw()
34
Steven M. Gavad721c482001-07-31 10:46:53 +000035 self.configure(borderwidth=5)
Terry Jan Reedycf834762014-10-17 01:31:29 -040036 self.title(title or 'IDLE Preferences')
Terry Jan Reedyae410862014-08-03 23:02:53 -040037 self.geometry(
38 "+%d+%d" % (parent.winfo_rootx() + 20,
39 parent.winfo_rooty() + (30 if not _htest else 150)))
Georg Brandl7eb4b7d2005-07-22 21:49:32 +000040 #Theme Elements. Each theme element key is its display name.
Steven M. Gava9dd16b32001-11-03 14:54:25 +000041 #The first value of the tuple is the sample area tag name.
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +000042 #The second value is the display name list sort index.
Terry Jan Reedyae410862014-08-03 23:02:53 -040043 self.themeElements={
44 'Normal Text':('normal', '00'),
45 'Python Keywords':('keyword', '01'),
46 'Python Definitions':('definition', '02'),
Kurt B. Kaiser73360a32004-03-08 18:15:31 +000047 'Python Builtins':('builtin', '03'),
Terry Jan Reedyae410862014-08-03 23:02:53 -040048 'Python Comments':('comment', '04'),
49 'Python Strings':('string', '05'),
50 'Selected Text':('hilite', '06'),
51 'Found Text':('hit', '07'),
52 'Cursor':('cursor', '08'),
53 'Error Text':('error', '09'),
54 'Shell Normal Text':('console', '10'),
55 'Shell Stdout Text':('stdout', '11'),
56 'Shell Stderr Text':('stderr', '12'),
Kurt B. Kaiser73360a32004-03-08 18:15:31 +000057 }
Steven M. Gavaa498af22002-02-01 01:33:36 +000058 self.ResetChangedItems() #load initial values in changed items dict
Steven M. Gavad721c482001-07-31 10:46:53 +000059 self.CreateWidgets()
Terry Jan Reedyae410862014-08-03 23:02:53 -040060 self.resizable(height=FALSE, width=FALSE)
Steven M. Gavad721c482001-07-31 10:46:53 +000061 self.transient(parent)
62 self.grab_set()
63 self.protocol("WM_DELETE_WINDOW", self.Cancel)
Steven M. Gava2d4e03b2001-12-05 07:54:07 +000064 self.tabPages.focus_set()
Steven M. Gavad721c482001-07-31 10:46:53 +000065 #key bindings for this dialog
Terry Jan Reedyae410862014-08-03 23:02:53 -040066 #self.bind('<Escape>', self.Cancel) #dismiss dialog, no save
67 #self.bind('<Alt-a>', self.Apply) #apply changes, save
68 #self.bind('<F1>', self.Help) #context help
Steven M. Gava429a86a2001-10-23 10:42:12 +000069 self.LoadConfigs()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +000070 self.AttachVarCallbacks() #avoid callbacks during LoadConfigs
Kurt B. Kaisere3fde8f2007-10-04 03:11:12 +000071
Terry Jan Reedyaf0dce92014-07-14 23:07:21 -040072 if not _utest:
73 self.wm_deiconify()
74 self.wait_window()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +000075
Steven M. Gavad721c482001-07-31 10:46:53 +000076 def CreateWidgets(self):
Kurt B. Kaiser20172f92007-10-30 02:38:54 +000077 self.tabPages = TabbedPageSet(self,
Terry Jan Reedyae410862014-08-03 23:02:53 -040078 page_names=['Fonts/Tabs', 'Highlighting', 'Keys', 'General'])
Terry Jan Reedy23030db2014-10-08 20:29:05 -040079 self.tabPages.pack(side=TOP, expand=TRUE, fill=BOTH)
80 self.CreatePageFontTab()
81 self.CreatePageHighlight()
82 self.CreatePageKeys()
83 self.CreatePageGeneral()
84 self.create_action_buttons().pack(side=BOTTOM)
Terry Jan Reedy23030db2014-10-08 20:29:05 -040085 def create_action_buttons(self):
Ned Deily57847df2014-03-27 20:47:04 -070086 if macosxSupport.isAquaTk():
Ronald Oussorena97063a2009-03-04 21:35:05 +000087 # Changing the default padding on OSX results in unreadable
88 # text in the buttons
Terry Jan Reedyae410862014-08-03 23:02:53 -040089 paddingArgs = {}
Ronald Oussorena97063a2009-03-04 21:35:05 +000090 else:
Terry Jan Reedyae410862014-08-03 23:02:53 -040091 paddingArgs = {'padx':6, 'pady':3}
Terry Jan Reedy7a162072014-10-22 20:15:12 -040092 outer = Frame(self, pady=2)
93 buttons = Frame(outer, pady=2)
Terry Jan Reedyae410862014-08-03 23:02:53 -040094 self.buttonOk = Button(
Terry Jan Reedy7a162072014-10-22 20:15:12 -040095 buttons, text='Ok', command=self.Ok,
Terry Jan Reedy23030db2014-10-08 20:29:05 -040096 takefocus=FALSE, **paddingArgs)
Terry Jan Reedyae410862014-08-03 23:02:53 -040097 self.buttonApply = Button(
Terry Jan Reedy7a162072014-10-22 20:15:12 -040098 buttons, text='Apply', command=self.Apply,
Terry Jan Reedy23030db2014-10-08 20:29:05 -040099 takefocus=FALSE, **paddingArgs)
Terry Jan Reedyae410862014-08-03 23:02:53 -0400100 self.buttonCancel = Button(
Terry Jan Reedy7a162072014-10-22 20:15:12 -0400101 buttons, text='Cancel', command=self.Cancel,
Terry Jan Reedy23030db2014-10-08 20:29:05 -0400102 takefocus=FALSE, **paddingArgs)
Terry Jan Reedyae410862014-08-03 23:02:53 -0400103 self.buttonOk.pack(side=LEFT, padx=5)
104 self.buttonApply.pack(side=LEFT, padx=5)
105 self.buttonCancel.pack(side=LEFT, padx=5)
Terry Jan Reedy7a162072014-10-22 20:15:12 -0400106# Comment out Help button creation and packing until implement self.Help
107## self.buttonHelp = Button(
108## buttons, text='Help', command=self.Help,
109## takefocus=FALSE, **paddingArgs)
110## self.buttonHelp.pack(side=RIGHT, padx=5)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000111
Terry Jan Reedy7a162072014-10-22 20:15:12 -0400112 # add space above buttons
113 Frame(outer, height=2, borderwidth=0).pack(side=TOP)
114 buttons.pack(side=BOTTOM)
115 return outer
Steven M. Gava60fc7072001-08-04 13:58:22 +0000116 def CreatePageFontTab(self):
Terry Jan Reedy19b7a752014-07-30 19:24:26 -0400117 parent = self.parent
118 self.fontSize = StringVar(parent)
119 self.fontBold = BooleanVar(parent)
120 self.fontName = StringVar(parent)
121 self.spaceNum = IntVar(parent)
Terry Jan Reedyae410862014-08-03 23:02:53 -0400122 self.editFont = tkFont.Font(parent, ('courier', 10, 'normal'))
Terry Jan Reedy19b7a752014-07-30 19:24:26 -0400123
Steven M. Gavaf213ccb2001-08-05 08:00:28 +0000124 ##widget creation
125 #body frame
Terry Jan Reedyae410862014-08-03 23:02:53 -0400126 frame = self.tabPages.pages['Fonts/Tabs'].frame
Steven M. Gavaf213ccb2001-08-05 08:00:28 +0000127 #body section frames
Terry Jan Reedyae410862014-08-03 23:02:53 -0400128 frameFont = LabelFrame(
129 frame, borderwidth=2, relief=GROOVE, text=' Base Editor Font ')
130 frameIndent = LabelFrame(
131 frame, borderwidth=2, relief=GROOVE, text=' Indentation Width ')
Steven M. Gavaf213ccb2001-08-05 08:00:28 +0000132 #frameFont
Terry Jan Reedyae410862014-08-03 23:02:53 -0400133 frameFontName = Frame(frameFont)
134 frameFontParam = Frame(frameFont)
135 labelFontNameTitle = Label(
136 frameFontName, justify=LEFT, text='Font Face :')
137 self.listFontName = Listbox(
138 frameFontName, height=5, takefocus=FALSE, exportselection=FALSE)
139 self.listFontName.bind(
140 '<ButtonRelease-1>', self.OnListFontButtonRelease)
141 scrollFont = Scrollbar(frameFontName)
Steven M. Gavac01e30f2001-08-11 15:48:13 +0000142 scrollFont.config(command=self.listFontName.yview)
143 self.listFontName.config(yscrollcommand=scrollFont.set)
Terry Jan Reedyae410862014-08-03 23:02:53 -0400144 labelFontSizeTitle = Label(frameFontParam, text='Size :')
145 self.optMenuFontSize = DynOptionMenu(
146 frameFontParam, self.fontSize, None, command=self.SetFontSample)
147 checkFontBold = Checkbutton(
148 frameFontParam, variable=self.fontBold, onvalue=1,
149 offvalue=0, text='Bold', command=self.SetFontSample)
150 frameFontSample = Frame(frameFont, relief=SOLID, borderwidth=1)
151 self.labelFontSample = Label(
152 frameFontSample, justify=LEFT, font=self.editFont,
153 text='AaBbCcDdEe\nFfGgHhIiJjK\n1234567890\n#:+=(){}[]')
Steven M. Gavaf213ccb2001-08-05 08:00:28 +0000154 #frameIndent
Terry Jan Reedyae410862014-08-03 23:02:53 -0400155 frameIndentSize = Frame(frameIndent)
156 labelSpaceNumTitle = Label(
157 frameIndentSize, justify=LEFT,
158 text='Python Standard: 4 Spaces!')
159 self.scaleSpaceNum = Scale(
160 frameIndentSize, variable=self.spaceNum,
161 orient='horizontal', tickinterval=2, from_=2, to=16)
Terry Jan Reedy19b7a752014-07-30 19:24:26 -0400162
Steven M. Gavaf213ccb2001-08-05 08:00:28 +0000163 #widget packing
164 #body
Terry Jan Reedyae410862014-08-03 23:02:53 -0400165 frameFont.pack(side=LEFT, padx=5, pady=5, expand=TRUE, fill=BOTH)
166 frameIndent.pack(side=LEFT, padx=5, pady=5, fill=Y)
Steven M. Gavaf213ccb2001-08-05 08:00:28 +0000167 #frameFont
Terry Jan Reedyae410862014-08-03 23:02:53 -0400168 frameFontName.pack(side=TOP, padx=5, pady=5, fill=X)
169 frameFontParam.pack(side=TOP, padx=5, pady=5, fill=X)
170 labelFontNameTitle.pack(side=TOP, anchor=W)
171 self.listFontName.pack(side=LEFT, expand=TRUE, fill=X)
172 scrollFont.pack(side=LEFT, fill=Y)
173 labelFontSizeTitle.pack(side=LEFT, anchor=W)
174 self.optMenuFontSize.pack(side=LEFT, anchor=W)
175 checkFontBold.pack(side=LEFT, anchor=W, padx=20)
176 frameFontSample.pack(side=TOP, padx=5, pady=5, expand=TRUE, fill=BOTH)
177 self.labelFontSample.pack(expand=TRUE, fill=BOTH)
Steven M. Gavaf213ccb2001-08-05 08:00:28 +0000178 #frameIndent
Terry Jan Reedyae410862014-08-03 23:02:53 -0400179 frameIndentSize.pack(side=TOP, fill=X)
180 labelSpaceNumTitle.pack(side=TOP, anchor=W, padx=5)
181 self.scaleSpaceNum.pack(side=TOP, padx=5, fill=X)
Steven M. Gava952d0a52001-08-03 04:43:44 +0000182 return frame
183
184 def CreatePageHighlight(self):
Terry Jan Reedy19b7a752014-07-30 19:24:26 -0400185 parent = self.parent
186 self.builtinTheme = StringVar(parent)
187 self.customTheme = StringVar(parent)
188 self.fgHilite = BooleanVar(parent)
189 self.colour = StringVar(parent)
190 self.fontName = StringVar(parent)
191 self.themeIsBuiltin = BooleanVar(parent)
192 self.highlightTarget = StringVar(parent)
193
Steven M. Gava952d0a52001-08-03 04:43:44 +0000194 ##widget creation
195 #body frame
Terry Jan Reedyae410862014-08-03 23:02:53 -0400196 frame = self.tabPages.pages['Highlighting'].frame
Steven M. Gava952d0a52001-08-03 04:43:44 +0000197 #body section frames
Terry Jan Reedyae410862014-08-03 23:02:53 -0400198 frameCustom = LabelFrame(frame, borderwidth=2, relief=GROOVE,
199 text=' Custom Highlighting ')
200 frameTheme = LabelFrame(frame, borderwidth=2, relief=GROOVE,
201 text=' Highlighting Theme ')
Steven M. Gava952d0a52001-08-03 04:43:44 +0000202 #frameCustom
Terry Jan Reedyae410862014-08-03 23:02:53 -0400203 self.textHighlightSample=Text(
204 frameCustom, relief=SOLID, borderwidth=1,
205 font=('courier', 12, ''), cursor='hand2', width=21, height=11,
206 takefocus=FALSE, highlightthickness=0, wrap=NONE)
Steven M. Gavae16d94b2001-11-03 05:07:28 +0000207 text=self.textHighlightSample
Terry Jan Reedyae410862014-08-03 23:02:53 -0400208 text.bind('<Double-Button-1>', lambda e: 'break')
209 text.bind('<B1-Motion>', lambda e: 'break')
210 textAndTags=(
211 ('#you can click here', 'comment'), ('\n', 'normal'),
212 ('#to choose items', 'comment'), ('\n', 'normal'),
213 ('def', 'keyword'), (' ', 'normal'),
214 ('func', 'definition'), ('(param):\n ', 'normal'),
215 ('"""string"""', 'string'), ('\n var0 = ', 'normal'),
216 ("'string'", 'string'), ('\n var1 = ', 'normal'),
217 ("'selected'", 'hilite'), ('\n var2 = ', 'normal'),
218 ("'found'", 'hit'), ('\n var3 = ', 'normal'),
219 ('list', 'builtin'), ('(', 'normal'),
220 ('None', 'builtin'), (')\n\n', 'normal'),
221 (' error ', 'error'), (' ', 'normal'),
222 ('cursor |', 'cursor'), ('\n ', 'normal'),
223 ('shell', 'console'), (' ', 'normal'),
224 ('stdout', 'stdout'), (' ', 'normal'),
225 ('stderr', 'stderr'), ('\n', 'normal'))
Steven M. Gava9dd16b32001-11-03 14:54:25 +0000226 for txTa in textAndTags:
Terry Jan Reedyae410862014-08-03 23:02:53 -0400227 text.insert(END, txTa[0], txTa[1])
Terry Jan Reedy110796f2014-07-27 04:07:18 -0400228 for element in self.themeElements:
Terry Jan Reedyae410862014-08-03 23:02:53 -0400229 def tem(event, elem=element):
230 event.widget.winfo_toplevel().highlightTarget.set(elem)
231 text.tag_bind(
232 self.themeElements[element][0], '<ButtonPress-1>', tem)
Steven M. Gavae16d94b2001-11-03 05:07:28 +0000233 text.config(state=DISABLED)
Terry Jan Reedyae410862014-08-03 23:02:53 -0400234 self.frameColourSet = Frame(frameCustom, relief=SOLID, borderwidth=1)
235 frameFgBg = Frame(frameCustom)
236 buttonSetColour = Button(
237 self.frameColourSet, text='Choose Colour for :',
238 command=self.GetColour, highlightthickness=0)
239 self.optMenuHighlightTarget = DynOptionMenu(
240 self.frameColourSet, self.highlightTarget, None,
241 highlightthickness=0) #, command=self.SetHighlightTargetBinding
242 self.radioFg = Radiobutton(
243 frameFgBg, variable=self.fgHilite, value=1,
244 text='Foreground', command=self.SetColourSampleBinding)
245 self.radioBg=Radiobutton(
246 frameFgBg, variable=self.fgHilite, value=0,
247 text='Background', command=self.SetColourSampleBinding)
Steven M. Gava7c017862001-10-29 11:19:46 +0000248 self.fgHilite.set(1)
Terry Jan Reedyae410862014-08-03 23:02:53 -0400249 buttonSaveCustomTheme = Button(
250 frameCustom, text='Save as New Custom Theme',
251 command=self.SaveAsNewTheme)
Steven M. Gava952d0a52001-08-03 04:43:44 +0000252 #frameTheme
Terry Jan Reedyae410862014-08-03 23:02:53 -0400253 labelTypeTitle = Label(frameTheme, text='Select : ')
254 self.radioThemeBuiltin = Radiobutton(
255 frameTheme, variable=self.themeIsBuiltin, value=1,
256 command=self.SetThemeType, text='a Built-in Theme')
257 self.radioThemeCustom = Radiobutton(
258 frameTheme, variable=self.themeIsBuiltin, value=0,
259 command=self.SetThemeType, text='a Custom Theme')
260 self.optMenuThemeBuiltin = DynOptionMenu(
261 frameTheme, self.builtinTheme, None, command=None)
262 self.optMenuThemeCustom=DynOptionMenu(
263 frameTheme, self.customTheme, None, command=None)
264 self.buttonDeleteCustomTheme=Button(
265 frameTheme, text='Delete Custom Theme',
Steven M. Gava49745752002-02-18 01:43:11 +0000266 command=self.DeleteCustomTheme)
Terry Jan Reedy19b7a752014-07-30 19:24:26 -0400267
Steven M. Gava952d0a52001-08-03 04:43:44 +0000268 ##widget packing
269 #body
Terry Jan Reedyae410862014-08-03 23:02:53 -0400270 frameCustom.pack(side=LEFT, padx=5, pady=5, expand=TRUE, fill=BOTH)
271 frameTheme.pack(side=LEFT, padx=5, pady=5, fill=Y)
Steven M. Gava952d0a52001-08-03 04:43:44 +0000272 #frameCustom
Terry Jan Reedyae410862014-08-03 23:02:53 -0400273 self.frameColourSet.pack(side=TOP, padx=5, pady=5, expand=TRUE, fill=X)
274 frameFgBg.pack(side=TOP, padx=5, pady=0)
275 self.textHighlightSample.pack(
276 side=TOP, padx=5, pady=5, expand=TRUE, fill=BOTH)
277 buttonSetColour.pack(side=TOP, expand=TRUE, fill=X, padx=8, pady=4)
278 self.optMenuHighlightTarget.pack(
279 side=TOP, expand=TRUE, fill=X, padx=8, pady=3)
280 self.radioFg.pack(side=LEFT, anchor=E)
281 self.radioBg.pack(side=RIGHT, anchor=W)
282 buttonSaveCustomTheme.pack(side=BOTTOM, fill=X, padx=5, pady=5)
Steven M. Gava952d0a52001-08-03 04:43:44 +0000283 #frameTheme
Terry Jan Reedyae410862014-08-03 23:02:53 -0400284 labelTypeTitle.pack(side=TOP, anchor=W, padx=5, pady=5)
285 self.radioThemeBuiltin.pack(side=TOP, anchor=W, padx=5)
286 self.radioThemeCustom.pack(side=TOP, anchor=W, padx=5, pady=2)
287 self.optMenuThemeBuiltin.pack(side=TOP, fill=X, padx=5, pady=5)
288 self.optMenuThemeCustom.pack(side=TOP, fill=X, anchor=W, padx=5, pady=5)
289 self.buttonDeleteCustomTheme.pack(side=TOP, fill=X, padx=5, pady=5)
Steven M. Gava952d0a52001-08-03 04:43:44 +0000290 return frame
291
292 def CreatePageKeys(self):
Terry Jan Reedy19b7a752014-07-30 19:24:26 -0400293 parent = self.parent
294 self.bindingTarget = StringVar(parent)
295 self.builtinKeys = StringVar(parent)
296 self.customKeys = StringVar(parent)
297 self.keysAreBuiltin = BooleanVar(parent)
298 self.keyBinding = StringVar(parent)
299
Steven M. Gava60fc7072001-08-04 13:58:22 +0000300 ##widget creation
301 #body frame
Terry Jan Reedyae410862014-08-03 23:02:53 -0400302 frame = self.tabPages.pages['Keys'].frame
Steven M. Gava60fc7072001-08-04 13:58:22 +0000303 #body section frames
Terry Jan Reedyae410862014-08-03 23:02:53 -0400304 frameCustom = LabelFrame(
305 frame, borderwidth=2, relief=GROOVE,
306 text=' Custom Key Bindings ')
307 frameKeySets = LabelFrame(
308 frame, borderwidth=2, relief=GROOVE, text=' Key Set ')
Steven M. Gava60fc7072001-08-04 13:58:22 +0000309 #frameCustom
Terry Jan Reedyae410862014-08-03 23:02:53 -0400310 frameTarget = Frame(frameCustom)
311 labelTargetTitle = Label(frameTarget, text='Action - Key(s)')
312 scrollTargetY = Scrollbar(frameTarget)
313 scrollTargetX = Scrollbar(frameTarget, orient=HORIZONTAL)
314 self.listBindings = Listbox(
315 frameTarget, takefocus=FALSE, exportselection=FALSE)
316 self.listBindings.bind('<ButtonRelease-1>', self.KeyBindingSelected)
Steven M. Gavafacfc092002-01-19 00:29:54 +0000317 scrollTargetY.config(command=self.listBindings.yview)
318 scrollTargetX.config(command=self.listBindings.xview)
319 self.listBindings.config(yscrollcommand=scrollTargetY.set)
320 self.listBindings.config(xscrollcommand=scrollTargetX.set)
Terry Jan Reedyae410862014-08-03 23:02:53 -0400321 self.buttonNewKeys = Button(
322 frameCustom, text='Get New Keys for Selection',
323 command=self.GetNewKeys, state=DISABLED)
Steven M. Gava60fc7072001-08-04 13:58:22 +0000324 #frameKeySets
Kurt B. Kaiser28c7bcf2007-12-28 04:18:01 +0000325 frames = [Frame(frameKeySets, padx=2, pady=2, borderwidth=0)
326 for i in range(2)]
Terry Jan Reedyae410862014-08-03 23:02:53 -0400327 self.radioKeysBuiltin = Radiobutton(
328 frames[0], variable=self.keysAreBuiltin, value=1,
329 command=self.SetKeysType, text='Use a Built-in Key Set')
330 self.radioKeysCustom = Radiobutton(
331 frames[0], variable=self.keysAreBuiltin, value=0,
332 command=self.SetKeysType, text='Use a Custom Key Set')
333 self.optMenuKeysBuiltin = DynOptionMenu(
334 frames[0], self.builtinKeys, None, command=None)
335 self.optMenuKeysCustom = DynOptionMenu(
336 frames[0], self.customKeys, None, command=None)
337 self.buttonDeleteCustomKeys = Button(
338 frames[1], text='Delete Custom Key Set',
Steven M. Gava49745752002-02-18 01:43:11 +0000339 command=self.DeleteCustomKeys)
Terry Jan Reedyae410862014-08-03 23:02:53 -0400340 buttonSaveCustomKeys = Button(
341 frames[1], text='Save as New Custom Key Set',
342 command=self.SaveAsNewKeySet)
Terry Jan Reedy19b7a752014-07-30 19:24:26 -0400343
Steven M. Gava60fc7072001-08-04 13:58:22 +0000344 ##widget packing
345 #body
Terry Jan Reedyae410862014-08-03 23:02:53 -0400346 frameCustom.pack(side=BOTTOM, padx=5, pady=5, expand=TRUE, fill=BOTH)
347 frameKeySets.pack(side=BOTTOM, padx=5, pady=5, fill=BOTH)
Steven M. Gava60fc7072001-08-04 13:58:22 +0000348 #frameCustom
Terry Jan Reedyae410862014-08-03 23:02:53 -0400349 self.buttonNewKeys.pack(side=BOTTOM, fill=X, padx=5, pady=5)
350 frameTarget.pack(side=LEFT, padx=5, pady=5, expand=TRUE, fill=BOTH)
Steven M. Gavafacfc092002-01-19 00:29:54 +0000351 #frame target
Terry Jan Reedyae410862014-08-03 23:02:53 -0400352 frameTarget.columnconfigure(0, weight=1)
353 frameTarget.rowconfigure(1, weight=1)
354 labelTargetTitle.grid(row=0, column=0, columnspan=2, sticky=W)
355 self.listBindings.grid(row=1, column=0, sticky=NSEW)
356 scrollTargetY.grid(row=1, column=1, sticky=NS)
357 scrollTargetX.grid(row=2, column=0, sticky=EW)
Steven M. Gava60fc7072001-08-04 13:58:22 +0000358 #frameKeySets
Kurt B. Kaiser28c7bcf2007-12-28 04:18:01 +0000359 self.radioKeysBuiltin.grid(row=0, column=0, sticky=W+NS)
360 self.radioKeysCustom.grid(row=1, column=0, sticky=W+NS)
361 self.optMenuKeysBuiltin.grid(row=0, column=1, sticky=NSEW)
362 self.optMenuKeysCustom.grid(row=1, column=1, sticky=NSEW)
Terry Jan Reedyae410862014-08-03 23:02:53 -0400363 self.buttonDeleteCustomKeys.pack(side=LEFT, fill=X, expand=True, padx=2)
364 buttonSaveCustomKeys.pack(side=LEFT, fill=X, expand=True, padx=2)
Kurt B. Kaiser28c7bcf2007-12-28 04:18:01 +0000365 frames[0].pack(side=TOP, fill=BOTH, expand=True)
366 frames[1].pack(side=TOP, fill=X, expand=True, pady=2)
Steven M. Gava952d0a52001-08-03 04:43:44 +0000367 return frame
368
369 def CreatePageGeneral(self):
Terry Jan Reedy19b7a752014-07-30 19:24:26 -0400370 parent = self.parent
371 self.winWidth = StringVar(parent)
372 self.winHeight = StringVar(parent)
Terry Jan Reedy19b7a752014-07-30 19:24:26 -0400373 self.startupEdit = IntVar(parent)
374 self.autoSave = IntVar(parent)
375 self.encoding = StringVar(parent)
376 self.userHelpBrowser = BooleanVar(parent)
377 self.helpBrowser = StringVar(parent)
378
Steven M. Gava230e5782001-08-07 03:28:25 +0000379 #widget creation
380 #body
Terry Jan Reedyae410862014-08-03 23:02:53 -0400381 frame = self.tabPages.pages['General'].frame
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000382 #body section frames
Terry Jan Reedyae410862014-08-03 23:02:53 -0400383 frameRun = LabelFrame(frame, borderwidth=2, relief=GROOVE,
384 text=' Startup Preferences ')
385 frameSave = LabelFrame(frame, borderwidth=2, relief=GROOVE,
386 text=' Autosave Preferences ')
387 frameWinSize = Frame(frame, borderwidth=2, relief=GROOVE)
Terry Jan Reedyae410862014-08-03 23:02:53 -0400388 frameEncoding = Frame(frame, borderwidth=2, relief=GROOVE)
389 frameHelp = LabelFrame(frame, borderwidth=2, relief=GROOVE,
390 text=' Additional Help Sources ')
Steven M. Gava230e5782001-08-07 03:28:25 +0000391 #frameRun
Terry Jan Reedyae410862014-08-03 23:02:53 -0400392 labelRunChoiceTitle = Label(frameRun, text='At Startup')
393 radioStartupEdit = Radiobutton(
394 frameRun, variable=self.startupEdit, value=1,
395 command=self.SetKeysType, text="Open Edit Window")
396 radioStartupShell = Radiobutton(
397 frameRun, variable=self.startupEdit, value=0,
398 command=self.SetKeysType, text='Open Shell Window')
Kurt B. Kaiser6c638b62003-05-26 06:23:10 +0000399 #frameSave
Terry Jan Reedyae410862014-08-03 23:02:53 -0400400 labelRunSaveTitle = Label(frameSave, text='At Start of Run (F5) ')
401 radioSaveAsk = Radiobutton(
402 frameSave, variable=self.autoSave, value=0,
403 command=self.SetKeysType, text="Prompt to Save")
404 radioSaveAuto = Radiobutton(
405 frameSave, variable=self.autoSave, value=1,
406 command=self.SetKeysType, text='No Prompt')
Steven M. Gava230e5782001-08-07 03:28:25 +0000407 #frameWinSize
Terry Jan Reedyae410862014-08-03 23:02:53 -0400408 labelWinSizeTitle = Label(
409 frameWinSize, text='Initial Window Size (in characters)')
410 labelWinWidthTitle = Label(frameWinSize, text='Width')
411 entryWinWidth = Entry(
412 frameWinSize, textvariable=self.winWidth, width=3)
413 labelWinHeightTitle = Label(frameWinSize, text='Height')
414 entryWinHeight = Entry(
415 frameWinSize, textvariable=self.winHeight, width=3)
Kurt B. Kaisera053f332003-05-10 00:49:56 +0000416 #frameEncoding
Terry Jan Reedyae410862014-08-03 23:02:53 -0400417 labelEncodingTitle = Label(
418 frameEncoding, text="Default Source Encoding")
419 radioEncLocale = Radiobutton(
420 frameEncoding, variable=self.encoding,
421 value="locale", text="Locale-defined")
422 radioEncUTF8 = Radiobutton(
423 frameEncoding, variable=self.encoding,
424 value="utf-8", text="UTF-8")
425 radioEncNone = Radiobutton(
426 frameEncoding, variable=self.encoding,
427 value="none", text="None")
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000428 #frameHelp
Terry Jan Reedyae410862014-08-03 23:02:53 -0400429 frameHelpList = Frame(frameHelp)
430 frameHelpListButtons = Frame(frameHelpList)
431 scrollHelpList = Scrollbar(frameHelpList)
432 self.listHelp = Listbox(
433 frameHelpList, height=5, takefocus=FALSE,
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000434 exportselection=FALSE)
435 scrollHelpList.config(command=self.listHelp.yview)
436 self.listHelp.config(yscrollcommand=scrollHelpList.set)
Terry Jan Reedyae410862014-08-03 23:02:53 -0400437 self.listHelp.bind('<ButtonRelease-1>', self.HelpSourceSelected)
438 self.buttonHelpListEdit = Button(
439 frameHelpListButtons, text='Edit', state=DISABLED,
440 width=8, command=self.HelpListItemEdit)
441 self.buttonHelpListAdd = Button(
442 frameHelpListButtons, text='Add',
443 width=8, command=self.HelpListItemAdd)
444 self.buttonHelpListRemove = Button(
445 frameHelpListButtons, text='Remove', state=DISABLED,
446 width=8, command=self.HelpListItemRemove)
Terry Jan Reedy19b7a752014-07-30 19:24:26 -0400447
Steven M. Gava230e5782001-08-07 03:28:25 +0000448 #widget packing
449 #body
Terry Jan Reedyae410862014-08-03 23:02:53 -0400450 frameRun.pack(side=TOP, padx=5, pady=5, fill=X)
451 frameSave.pack(side=TOP, padx=5, pady=5, fill=X)
452 frameWinSize.pack(side=TOP, padx=5, pady=5, fill=X)
Terry Jan Reedyae410862014-08-03 23:02:53 -0400453 frameEncoding.pack(side=TOP, padx=5, pady=5, fill=X)
454 frameHelp.pack(side=TOP, padx=5, pady=5, expand=TRUE, fill=BOTH)
Steven M. Gava230e5782001-08-07 03:28:25 +0000455 #frameRun
Terry Jan Reedyae410862014-08-03 23:02:53 -0400456 labelRunChoiceTitle.pack(side=LEFT, anchor=W, padx=5, pady=5)
457 radioStartupShell.pack(side=RIGHT, anchor=W, padx=5, pady=5)
458 radioStartupEdit.pack(side=RIGHT, anchor=W, padx=5, pady=5)
Kurt B. Kaiser6c638b62003-05-26 06:23:10 +0000459 #frameSave
Terry Jan Reedyae410862014-08-03 23:02:53 -0400460 labelRunSaveTitle.pack(side=LEFT, anchor=W, padx=5, pady=5)
461 radioSaveAuto.pack(side=RIGHT, anchor=W, padx=5, pady=5)
462 radioSaveAsk.pack(side=RIGHT, anchor=W, padx=5, pady=5)
Steven M. Gava230e5782001-08-07 03:28:25 +0000463 #frameWinSize
Terry Jan Reedyae410862014-08-03 23:02:53 -0400464 labelWinSizeTitle.pack(side=LEFT, anchor=W, padx=5, pady=5)
465 entryWinHeight.pack(side=RIGHT, anchor=E, padx=10, pady=5)
466 labelWinHeightTitle.pack(side=RIGHT, anchor=E, pady=5)
467 entryWinWidth.pack(side=RIGHT, anchor=E, padx=10, pady=5)
468 labelWinWidthTitle.pack(side=RIGHT, anchor=E, pady=5)
Kurt B. Kaisera053f332003-05-10 00:49:56 +0000469 #frameEncoding
Terry Jan Reedyae410862014-08-03 23:02:53 -0400470 labelEncodingTitle.pack(side=LEFT, anchor=W, padx=5, pady=5)
471 radioEncNone.pack(side=RIGHT, anchor=E, pady=5)
472 radioEncUTF8.pack(side=RIGHT, anchor=E, pady=5)
473 radioEncLocale.pack(side=RIGHT, anchor=E, pady=5)
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000474 #frameHelp
Terry Jan Reedyae410862014-08-03 23:02:53 -0400475 frameHelpListButtons.pack(side=RIGHT, padx=5, pady=5, fill=Y)
476 frameHelpList.pack(side=TOP, padx=5, pady=5, expand=TRUE, fill=BOTH)
477 scrollHelpList.pack(side=RIGHT, anchor=W, fill=Y)
478 self.listHelp.pack(side=LEFT, anchor=E, expand=TRUE, fill=BOTH)
479 self.buttonHelpListEdit.pack(side=TOP, anchor=W, pady=5)
480 self.buttonHelpListAdd.pack(side=TOP, anchor=W)
481 self.buttonHelpListRemove.pack(side=TOP, anchor=W, pady=5)
Steven M. Gava952d0a52001-08-03 04:43:44 +0000482 return frame
483
Steven M. Gavac112cd82002-01-22 05:56:40 +0000484 def AttachVarCallbacks(self):
Terry Jan Reedy12352142015-08-01 18:57:27 -0400485 self.fontSize.trace_variable('w', self.VarChanged_font)
486 self.fontName.trace_variable('w', self.VarChanged_font)
487 self.fontBold.trace_variable('w', self.VarChanged_font)
Terry Jan Reedyae410862014-08-03 23:02:53 -0400488 self.spaceNum.trace_variable('w', self.VarChanged_spaceNum)
489 self.colour.trace_variable('w', self.VarChanged_colour)
490 self.builtinTheme.trace_variable('w', self.VarChanged_builtinTheme)
491 self.customTheme.trace_variable('w', self.VarChanged_customTheme)
492 self.themeIsBuiltin.trace_variable('w', self.VarChanged_themeIsBuiltin)
493 self.highlightTarget.trace_variable('w', self.VarChanged_highlightTarget)
494 self.keyBinding.trace_variable('w', self.VarChanged_keyBinding)
495 self.builtinKeys.trace_variable('w', self.VarChanged_builtinKeys)
496 self.customKeys.trace_variable('w', self.VarChanged_customKeys)
497 self.keysAreBuiltin.trace_variable('w', self.VarChanged_keysAreBuiltin)
498 self.winWidth.trace_variable('w', self.VarChanged_winWidth)
499 self.winHeight.trace_variable('w', self.VarChanged_winHeight)
Terry Jan Reedyae410862014-08-03 23:02:53 -0400500 self.startupEdit.trace_variable('w', self.VarChanged_startupEdit)
501 self.autoSave.trace_variable('w', self.VarChanged_autoSave)
502 self.encoding.trace_variable('w', self.VarChanged_encoding)
Steven M. Gava052937f2002-02-11 02:20:53 +0000503
Terry Jan Reedy12352142015-08-01 18:57:27 -0400504 def VarChanged_font(self, *params):
505 '''When one font attribute changes, save them all, as they are
506 not independent from each other. In particular, when we are
507 overriding the default font, we need to write out everything.
508 '''
Terry Jan Reedyae410862014-08-03 23:02:53 -0400509 value = self.fontName.get()
510 self.AddChangedItem('main', 'EditorWindow', 'font', value)
Terry Jan Reedy12352142015-08-01 18:57:27 -0400511 value = self.fontSize.get()
512 self.AddChangedItem('main', 'EditorWindow', 'font-size', value)
Terry Jan Reedyae410862014-08-03 23:02:53 -0400513 value = self.fontBold.get()
514 self.AddChangedItem('main', 'EditorWindow', 'font-bold', value)
Steven M. Gavac112cd82002-01-22 05:56:40 +0000515
Terry Jan Reedyae410862014-08-03 23:02:53 -0400516 def VarChanged_spaceNum(self, *params):
517 value = self.spaceNum.get()
518 self.AddChangedItem('main', 'Indent', 'num-spaces', value)
Steven M. Gavac112cd82002-01-22 05:56:40 +0000519
Terry Jan Reedyae410862014-08-03 23:02:53 -0400520 def VarChanged_colour(self, *params):
Steven M. Gava052937f2002-02-11 02:20:53 +0000521 self.OnNewColourSet()
522
Terry Jan Reedyae410862014-08-03 23:02:53 -0400523 def VarChanged_builtinTheme(self, *params):
524 value = self.builtinTheme.get()
525 self.AddChangedItem('main', 'Theme', 'name', value)
Steven M. Gava052937f2002-02-11 02:20:53 +0000526 self.PaintThemeSample()
527
Terry Jan Reedyae410862014-08-03 23:02:53 -0400528 def VarChanged_customTheme(self, *params):
529 value = self.customTheme.get()
Steven M. Gava49745752002-02-18 01:43:11 +0000530 if value != '- no custom themes -':
Terry Jan Reedyae410862014-08-03 23:02:53 -0400531 self.AddChangedItem('main', 'Theme', 'name', value)
Steven M. Gava49745752002-02-18 01:43:11 +0000532 self.PaintThemeSample()
Steven M. Gava052937f2002-02-11 02:20:53 +0000533
Terry Jan Reedyae410862014-08-03 23:02:53 -0400534 def VarChanged_themeIsBuiltin(self, *params):
535 value = self.themeIsBuiltin.get()
536 self.AddChangedItem('main', 'Theme', 'default', value)
Steven M. Gavaf31eec02002-03-05 00:25:58 +0000537 if value:
538 self.VarChanged_builtinTheme()
539 else:
540 self.VarChanged_customTheme()
Steven M. Gava052937f2002-02-11 02:20:53 +0000541
Terry Jan Reedyae410862014-08-03 23:02:53 -0400542 def VarChanged_highlightTarget(self, *params):
Steven M. Gava052937f2002-02-11 02:20:53 +0000543 self.SetHighlightTarget()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000544
Terry Jan Reedyae410862014-08-03 23:02:53 -0400545 def VarChanged_keyBinding(self, *params):
546 value = self.keyBinding.get()
547 keySet = self.customKeys.get()
548 event = self.listBindings.get(ANCHOR).split()[0]
Steven M. Gavaa498af22002-02-01 01:33:36 +0000549 if idleConf.IsCoreBinding(event):
550 #this is a core keybinding
Terry Jan Reedyae410862014-08-03 23:02:53 -0400551 self.AddChangedItem('keys', keySet, event, value)
Steven M. Gavaa498af22002-02-01 01:33:36 +0000552 else: #this is an extension key binding
Terry Jan Reedyae410862014-08-03 23:02:53 -0400553 extName = idleConf.GetExtnNameForEvent(event)
554 extKeybindSection = extName + '_cfgBindings'
555 self.AddChangedItem('extensions', extKeybindSection, event, value)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000556
Terry Jan Reedyae410862014-08-03 23:02:53 -0400557 def VarChanged_builtinKeys(self, *params):
558 value = self.builtinKeys.get()
559 self.AddChangedItem('main', 'Keys', 'name', value)
Steven M. Gava052937f2002-02-11 02:20:53 +0000560 self.LoadKeysList(value)
561
Terry Jan Reedyae410862014-08-03 23:02:53 -0400562 def VarChanged_customKeys(self, *params):
563 value = self.customKeys.get()
Steven M. Gava49745752002-02-18 01:43:11 +0000564 if value != '- no custom keys -':
Terry Jan Reedyae410862014-08-03 23:02:53 -0400565 self.AddChangedItem('main', 'Keys', 'name', value)
Steven M. Gava49745752002-02-18 01:43:11 +0000566 self.LoadKeysList(value)
Steven M. Gava052937f2002-02-11 02:20:53 +0000567
Terry Jan Reedyae410862014-08-03 23:02:53 -0400568 def VarChanged_keysAreBuiltin(self, *params):
569 value = self.keysAreBuiltin.get()
570 self.AddChangedItem('main', 'Keys', 'default', value)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000571 if value:
Steven M. Gavaf31eec02002-03-05 00:25:58 +0000572 self.VarChanged_builtinKeys()
Steven M. Gava052937f2002-02-11 02:20:53 +0000573 else:
Steven M. Gavaf31eec02002-03-05 00:25:58 +0000574 self.VarChanged_customKeys()
Steven M. Gava052937f2002-02-11 02:20:53 +0000575
Terry Jan Reedyae410862014-08-03 23:02:53 -0400576 def VarChanged_winWidth(self, *params):
577 value = self.winWidth.get()
578 self.AddChangedItem('main', 'EditorWindow', 'width', value)
Steven M. Gavac112cd82002-01-22 05:56:40 +0000579
Terry Jan Reedyae410862014-08-03 23:02:53 -0400580 def VarChanged_winHeight(self, *params):
581 value = self.winHeight.get()
582 self.AddChangedItem('main', 'EditorWindow', 'height', value)
Steven M. Gavac112cd82002-01-22 05:56:40 +0000583
Terry Jan Reedyae410862014-08-03 23:02:53 -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 Reedyae410862014-08-03 23:02:53 -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 Reedyae410862014-08-03 23:02:53 -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 Reedyae410862014-08-03 23:02:53 -0400602 self.changedItems = {'main':{}, 'highlight':{}, 'keys':{},
603 'extensions':{}}
Steven M. Gavaa498af22002-02-01 01:33:36 +0000604
Terry Jan Reedyae410862014-08-03 23:02:53 -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 Reedyae410862014-08-03 23:02:53 -0400612 dItems={'main':{}, 'highlight':{}, 'keys':{}, 'extensions':{}}
Terry Jan Reedy110796f2014-07-27 04:07:18 -0400613 for configType in dItems:
Terry Jan Reedyae410862014-08-03 23:02:53 -0400614 sections = idleConf.GetSectionList('default', configType)
Steven M. Gava5f28e8f2002-01-21 06:38:21 +0000615 for section in sections:
Terry Jan Reedyae410862014-08-03 23:02:53 -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 Reedyae410862014-08-03 23:02:53 -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 Reedyae410862014-08-03 23:02:53 -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 Reedyae410862014-08-03 23:02:53 -0400650 currentKeySetName = self.builtinKeys.get()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000651 else:
Terry Jan Reedyae410862014-08-03 23:02:53 -0400652 currentKeySetName = self.customKeys.get()
653 currentBindings = idleConf.GetCurrentKeySet()
Terry Jan Reedy110796f2014-07-27 04:07:18 -0400654 if currentKeySetName in self.changedItems['keys']: #unsaved changes
Terry Jan Reedyae410862014-08-03 23:02:53 -0400655 keySetChanges = self.changedItems['keys'][currentKeySetName]
Terry Jan Reedy110796f2014-07-27 04:07:18 -0400656 for event in keySetChanges:
Terry Jan Reedyae410862014-08-03 23:02:53 -0400657 currentBindings[event] = keySetChanges[event].split()
658 currentKeySequences = currentBindings.values()
659 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 Reedyae410862014-08-03 23:02:53 -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 Reedyae410862014-08-03 23:02:53 -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 Reedyae410862014-08-03 23:02:53 -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 Reedyae410862014-08-03 23:02:53 -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 Reedyae410862014-08-03 23:02:53 -0400693 def KeyBindingSelected(self, event):
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000694 self.buttonNewKeys.config(state=NORMAL)
695
Terry Jan Reedyae410862014-08-03 23:02:53 -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 Reedyae410862014-08-03 23:02:53 -0400700 prevKeySetName = self.builtinKeys.get()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000701 else:
Terry Jan Reedyae410862014-08-03 23:02:53 -0400702 prevKeySetName = self.customKeys.get()
703 prevKeys = idleConf.GetCoreKeys(prevKeySetName)
704 newKeys = {}
Terry Jan Reedy110796f2014-07-27 04:07:18 -0400705 for event in prevKeys: #add key set to changed items
Terry Jan Reedyae410862014-08-03 23:02:53 -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
Terry Jan Reedy110796f2014-07-27 04:07:18 -0400710 if prevKeySetName in self.changedItems['keys']:
Terry Jan Reedyae410862014-08-03 23:02:53 -0400711 keySetChanges = self.changedItems['keys'][prevKeySetName]
Terry Jan Reedy110796f2014-07-27 04:07:18 -0400712 for event in keySetChanges:
Terry Jan Reedyae410862014-08-03 23:02:53 -0400713 newKeys[event] = keySetChanges[event]
Steven M. Gava052937f2002-02-11 02:20:53 +0000714 #save the new theme
Terry Jan Reedyae410862014-08-03 23:02:53 -0400715 self.SaveNewKeySet(newKeySetName, newKeys)
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000716 #change gui over to the new key set
Terry Jan Reedyae410862014-08-03 23:02:53 -0400717 customKeyList = idleConf.GetSectionList('user', 'keys')
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000718 customKeyList.sort()
Terry Jan Reedyae410862014-08-03 23:02:53 -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 Reedyae410862014-08-03 23:02:53 -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 Reedyae410862014-08-03 23:02:53 -0400727 reselect = 1
728 listIndex = self.listBindings.index(ANCHOR)
729 keySet = idleConf.GetKeySet(keySetName)
730 bindNames = keySet.keys()
Steven M. Gava052937f2002-02-11 02:20:53 +0000731 bindNames.sort()
Terry Jan Reedyae410862014-08-03 23:02:53 -0400732 self.listBindings.delete(0, END)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000733 for bindName in bindNames:
Terry Jan Reedyae410862014-08-03 23:02:53 -0400734 key = ' '.join(keySet[bindName]) #make key(s) into a string
735 bindName = bindName[2:-2] #trim off the angle brackets
Terry Jan Reedy110796f2014-07-27 04:07:18 -0400736 if keySetName in self.changedItems['keys']:
Steven M. Gava052937f2002-02-11 02:20:53 +0000737 #handle any unsaved changes to this key set
Terry Jan Reedy110796f2014-07-27 04:07:18 -0400738 if bindName in self.changedItems['keys'][keySetName]:
Terry Jan Reedyae410862014-08-03 23:02:53 -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 Reedyae410862014-08-03 23:02:53 -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)
Benjamin Peterson6e3dbbd2009-10-09 22:15:50 +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 Reedyae410862014-08-03 23:02:53 -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 Reedyae410862014-08-03 23:02:53 -0400763 self.optMenuKeysCustom.SetMenu(itemList, '- no custom keys -')
Steven M. Gava49745752002-02-18 01:43:11 +0000764 else:
Terry Jan Reedyae410862014-08-03 23:02:53 -0400765 self.optMenuKeysCustom.SetMenu(itemList, itemList[0])
Steven M. Gava49745752002-02-18 01:43:11 +0000766 #revert to default key set
Terry Jan Reedyae410862014-08-03 23:02:53 -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 Reedyae410862014-08-03 23:02:53 -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)
Benjamin Peterson6e3dbbd2009-10-09 22:15:50 +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 Reedyae410862014-08-03 23:02:53 -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 Reedyae410862014-08-03 23:02:53 -0400790 self.optMenuThemeCustom.SetMenu(itemList, '- no custom themes -')
Steven M. Gava49745752002-02-18 01:43:11 +0000791 else:
Terry Jan Reedyae410862014-08-03 23:02:53 -0400792 self.optMenuThemeCustom.SetMenu(itemList, itemList[0])
Steven M. Gava49745752002-02-18 01:43:11 +0000793 #revert to default theme
Terry Jan Reedyae410862014-08-03 23:02:53 -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 Reedyae410862014-08-03 23:02:53 -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 Reedyae410862014-08-03 23:02:53 -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 Reedyae410862014-08-03 23:02:53 -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 Reedyae410862014-08-03 23:02:53 -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 Reedyae410862014-08-03 23:02:53 -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 Reedyae410862014-08-03 23:02:53 -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 Reedyae410862014-08-03 23:02:53 -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 Reedyae410862014-08-03 23:02:53 -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 Reedyae410862014-08-03 23:02:53 -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 Reedyae410862014-08-03 23:02:53 -0400846 themeType = 'default'
847 themeName = self.builtinTheme.get()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000848 else:
Terry Jan Reedyae410862014-08-03 23:02:53 -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
Terry Jan Reedy110796f2014-07-27 04:07:18 -0400853 if themeName in self.changedItems['highlight']:
Terry Jan Reedyae410862014-08-03 23:02:53 -0400854 themeChanges = self.changedItems['highlight'][themeName]
Terry Jan Reedy110796f2014-07-27 04:07:18 -0400855 for element in themeChanges:
Terry Jan Reedyae410862014-08-03 23:02:53 -0400856 newTheme[element] = themeChanges[element]
Steven M. Gava052937f2002-02-11 02:20:53 +0000857 #save the new theme
Terry Jan Reedyae410862014-08-03 23:02:53 -0400858 self.SaveNewTheme(newThemeName, newTheme)
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000859 #change gui over to the new theme
Terry Jan Reedyae410862014-08-03 23:02:53 -0400860 customThemeList = idleConf.GetSectionList('user', 'highlight')
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000861 customThemeList.sort()
Terry Jan Reedyae410862014-08-03 23:02:53 -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 Reedyae410862014-08-03 23:02:53 -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 Reedyae410862014-08-03 23:02:53 -0400871 def SetFontSample(self, event=None):
872 fontName = self.fontName.get()
873 fontWeight = tkFont.BOLD if self.fontBold.get() else tkFont.NORMAL
Ned Deilye3d47122012-10-22 15:13:01 -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 Reedyae410862014-08-03 23:02:53 -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 Reedyae410862014-08-03 23:02:53 -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 Reedyae410862014-08-03 23:02:53 -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 Reedyae410862014-08-03 23:02:53 -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 Reedyae410862014-08-03 23:02:53 -0400900 if self.themeIsBuiltin.get(): #a default theme
901 theme = self.builtinTheme.get()
902 else: #a user theme
903 theme = self.customTheme.get()
Terry Jan Reedy110796f2014-07-27 04:07:18 -0400904 for elementTitle in self.themeElements:
Terry Jan Reedyae410862014-08-03 23:02:53 -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
Terry Jan Reedy110796f2014-07-27 04:07:18 -0400911 if theme in self.changedItems['highlight']:
Terry Jan Reedyae410862014-08-03 23:02:53 -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 Reedyae410862014-08-03 23:02:53 -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 Reedyae410862014-08-03 23:02:53 -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 Reedyae410862014-08-03 23:02:53 -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 Reedyae410862014-08-03 23:02:53 -0400936 helpSource = GetHelpSourceDialog(self, 'New Help Source').result
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000937 if helpSource:
Terry Jan Reedyae410862014-08-03 23:02:53 -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 Reedyae410862014-08-03 23:02:53 -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 Reedyae410862014-08-03 23:02:53 -0400951 self.userHelpList[itemIndex] = newHelpSource
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000952 self.listHelp.delete(itemIndex)
Terry Jan Reedyae410862014-08-03 23:02:53 -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 Reedyae410862014-08-03 23:02:53 -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 Reedyae410862014-08-03 23:02:53 -0400967 for num in range(1, len(self.userHelpList) + 1):
968 self.AddChangedItem(
969 'main', 'HelpFiles', str(num),
Terry Jan Reedy110796f2014-07-27 04:07:18 -0400970 ';'.join(self.userHelpList[num-1][:2]))
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000971
Steven M. Gava429a86a2001-10-23 10:42:12 +0000972 def LoadFontCfg(self):
973 ##base editor font selection list
Terry Jan Reedyae410862014-08-03 23:02:53 -0400974 fonts = list(tkFont.families(self))
Steven M. Gavac11ccf32001-09-24 09:43:17 +0000975 fonts.sort()
976 for font in fonts:
Terry Jan Reedyae410862014-08-03 23:02:53 -0400977 self.listFontName.insert(END, font)
Terry Jan Reedy12352142015-08-01 18:57:27 -0400978 configuredFont = idleConf.GetFont(self, 'main', 'EditorWindow')
979 fontName = configuredFont[0].lower()
980 fontSize = configuredFont[1]
981 fontBold = configuredFont[2]=='bold'
982 self.fontName.set(fontName)
Kurt B. Kaiser05391692003-05-26 20:35:53 +0000983 lc_fonts = [s.lower() for s in fonts]
Terry Jan Reedy12352142015-08-01 18:57:27 -0400984 try:
985 currentFontIndex = lc_fonts.index(fontName)
Steven M. Gava429a86a2001-10-23 10:42:12 +0000986 self.listFontName.see(currentFontIndex)
987 self.listFontName.select_set(currentFontIndex)
Steven M. Gavac112cd82002-01-22 05:56:40 +0000988 self.listFontName.select_anchor(currentFontIndex)
Terry Jan Reedy12352142015-08-01 18:57:27 -0400989 except ValueError:
990 pass
Steven M. Gava429a86a2001-10-23 10:42:12 +0000991 ##font size dropdown
Terry Jan Reedyae410862014-08-03 23:02:53 -0400992 self.optMenuFontSize.SetMenu(('7', '8', '9', '10', '11', '12', '13',
993 '14', '16', '18', '20', '22'), fontSize )
Steven M. Gavac112cd82002-01-22 05:56:40 +0000994 ##fontWeight
Terry Jan Reedy12352142015-08-01 18:57:27 -0400995 self.fontBold.set(fontBold)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000996 ##font sample
Steven M. Gava429a86a2001-10-23 10:42:12 +0000997 self.SetFontSample()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000998
Steven M. Gava429a86a2001-10-23 10:42:12 +0000999 def LoadTabCfg(self):
Steven M. Gava429a86a2001-10-23 10:42:12 +00001000 ##indent sizes
Terry Jan Reedyae410862014-08-03 23:02:53 -04001001 spaceNum = idleConf.GetOption(
1002 'main', 'Indent', 'num-spaces', default=4, type='int')
Steven M. Gava429a86a2001-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 Reedyae410862014-08-03 23:02:53 -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 Reedyae410862014-08-03 23:02:53 -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 Reedyae410862014-08-03 23:02:53 -04001013 itemList = idleConf.GetSectionList('default', 'highlight')
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +00001014 itemList.sort()
Terry Jan Reedyae410862014-08-03 23:02:53 -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 Reedyae410862014-08-03 23:02:53 -04001022 self.optMenuThemeCustom.SetMenu(itemList, itemList[0])
Steven M. Gava9dd16b32001-11-03 14:54:25 +00001023 else: #user theme selected
Terry Jan Reedyae410862014-08-03 23:02:53 -04001024 itemList = idleConf.GetSectionList('user', 'highlight')
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +00001025 itemList.sort()
Terry Jan Reedyae410862014-08-03 23:02:53 -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 Reedyae410862014-08-03 23:02:53 -04001029 self.optMenuThemeBuiltin.SetMenu(itemList, itemList[0])
Steven M. Gava7c017862001-10-29 11:19:46 +00001030 self.SetThemeType()
1031 ##load theme element option menu
Terry Jan Reedyae410862014-08-03 23:02:53 -04001032 themeNames = self.themeElements.keys()
Florent Xiclunaa7f242f2010-04-02 08:15:26 +00001033 themeNames.sort(key=lambda x: self.themeElements[x][1])
Terry Jan Reedyae410862014-08-03 23:02:53 -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 Reedyae410862014-08-03 23:02:53 -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 Reedyae410862014-08-03 23:02:53 -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 Reedyae410862014-08-03 23:02:53 -04001046 itemList = idleConf.GetSectionList('default', 'keys')
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +00001047 itemList.sort()
Terry Jan Reedyae410862014-08-03 23:02:53 -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 Reedyae410862014-08-03 23:02:53 -04001055 self.optMenuKeysCustom.SetMenu(itemList, itemList[0])
Steven M. Gavaa498af22002-02-01 01:33:36 +00001056 else: #user key set selected
Terry Jan Reedyae410862014-08-03 23:02:53 -04001057 itemList = idleConf.GetSectionList('user', 'keys')
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +00001058 itemList.sort()
Terry Jan Reedyae410862014-08-03 23:02:53 -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 Reedyae410862014-08-03 23:02:53 -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 Reedyae410862014-08-03 23:02:53 -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 Reedyae410862014-08-03 23:02:53 -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 Reedyae410862014-08-03 23:02:53 -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 Reedyae410862014-08-03 23:02:53 -04001076 self.winWidth.set(idleConf.GetOption(
1077 'main', 'EditorWindow', 'width', type='int'))
1078 self.winHeight.set(idleConf.GetOption(
1079 'main', 'EditorWindow', 'height', type='int'))
Kurt B. Kaisera053f332003-05-10 00:49:56 +00001080 # default source encoding
Terry Jan Reedyae410862014-08-03 23:02:53 -04001081 self.encoding.set(idleConf.GetOption(
1082 'main', 'EditorWindow', 'encoding', default='none'))
Kurt B. Kaiser8e92bf72003-01-14 22:03:31 +00001083 # additional help sources
1084 self.userHelpList = idleConf.GetAllExtraHelpSourcesList()
Steven M. Gava085eb1b2002-02-05 04:52:32 +00001085 for helpItem in self.userHelpList:
Terry Jan Reedyae410862014-08-03 23:02:53 -04001086 self.listHelp.insert(END, helpItem[0])
Steven M. Gava085eb1b2002-02-05 04:52:32 +00001087 self.SetHelpListButtonStates()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001088
Steven M. Gava429a86a2001-10-23 10:42:12 +00001089 def LoadConfigs(self):
1090 """
1091 load configuration from default and user config files and populate
1092 the widgets on the config dialog pages.
1093 """
1094 ### fonts / tabs page
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001095 self.LoadFontCfg()
1096 self.LoadTabCfg()
Steven M. Gava429a86a2001-10-23 10:42:12 +00001097 ### highlighting page
Steven M. Gava9dd16b32001-11-03 14:54:25 +00001098 self.LoadThemeCfg()
Steven M. Gava429a86a2001-10-23 10:42:12 +00001099 ### keys page
Steven M. Gava9dd16b32001-11-03 14:54:25 +00001100 self.LoadKeyCfg()
Steven M. Gava429a86a2001-10-23 10:42:12 +00001101 ### general page
Steven M. Gavafacfc092002-01-19 00:29:54 +00001102 self.LoadGeneralCfg()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001103
Terry Jan Reedyae410862014-08-03 23:02:53 -04001104 def SaveNewKeySet(self, keySetName, keySet):
Steven M. Gava052937f2002-02-11 02:20:53 +00001105 """
1106 save a newly created core key set.
1107 keySetName - string, the name of the new key set
1108 keySet - dictionary containing the new key set
1109 """
1110 if not idleConf.userCfg['keys'].has_section(keySetName):
1111 idleConf.userCfg['keys'].add_section(keySetName)
Terry Jan Reedy110796f2014-07-27 04:07:18 -04001112 for event in keySet:
Terry Jan Reedyae410862014-08-03 23:02:53 -04001113 value = keySet[event]
1114 idleConf.userCfg['keys'].SetOption(keySetName, event, value)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001115
Terry Jan Reedyae410862014-08-03 23:02:53 -04001116 def SaveNewTheme(self, themeName, theme):
Steven M. Gava052937f2002-02-11 02:20:53 +00001117 """
1118 save a newly created theme.
1119 themeName - string, the name of the new theme
1120 theme - dictionary containing the new theme
1121 """
1122 if not idleConf.userCfg['highlight'].has_section(themeName):
1123 idleConf.userCfg['highlight'].add_section(themeName)
Terry Jan Reedy110796f2014-07-27 04:07:18 -04001124 for element in theme:
Terry Jan Reedyae410862014-08-03 23:02:53 -04001125 value = theme[element]
1126 idleConf.userCfg['highlight'].SetOption(themeName, element, value)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001127
Terry Jan Reedyae410862014-08-03 23:02:53 -04001128 def SetUserValue(self, configType, section, item, value):
1129 if idleConf.defaultCfg[configType].has_option(section, item):
1130 if idleConf.defaultCfg[configType].Get(section, item) == value:
Steven M. Gava2d7bb3f2002-01-29 08:35:29 +00001131 #the setting equals a default setting, remove it from user cfg
Terry Jan Reedyae410862014-08-03 23:02:53 -04001132 return idleConf.userCfg[configType].RemoveOption(section, item)
Steven M. Gava2d7bb3f2002-01-29 08:35:29 +00001133 #if we got here set the option
Terry Jan Reedyae410862014-08-03 23:02:53 -04001134 return idleConf.userCfg[configType].SetOption(section, item, value)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001135
Steven M. Gava052937f2002-02-11 02:20:53 +00001136 def SaveAllChangedConfigs(self):
Kurt B. Kaisere7a161e2003-01-10 20:13:57 +00001137 "Save configuration changes to the user config file."
Steven M. Gava0c5bc8c2002-03-27 02:25:44 +00001138 idleConf.userCfg['main'].Save()
Terry Jan Reedy110796f2014-07-27 04:07:18 -04001139 for configType in self.changedItems:
Kurt B. Kaisere7a161e2003-01-10 20:13:57 +00001140 cfgTypeHasChanges = False
Terry Jan Reedy110796f2014-07-27 04:07:18 -04001141 for section in self.changedItems[configType]:
Kurt B. Kaisere7a161e2003-01-10 20:13:57 +00001142 if section == 'HelpFiles':
1143 #this section gets completely replaced
1144 idleConf.userCfg['main'].remove_section('HelpFiles')
Kurt B. Kaiser8e92bf72003-01-14 22:03:31 +00001145 cfgTypeHasChanges = True
Terry Jan Reedy110796f2014-07-27 04:07:18 -04001146 for item in self.changedItems[configType][section]:
Kurt B. Kaisere7a161e2003-01-10 20:13:57 +00001147 value = self.changedItems[configType][section][item]
Terry Jan Reedyae410862014-08-03 23:02:53 -04001148 if self.SetUserValue(configType, section, item, value):
Kurt B. Kaisere7a161e2003-01-10 20:13:57 +00001149 cfgTypeHasChanges = True
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001150 if cfgTypeHasChanges:
1151 idleConf.userCfg[configType].Save()
Kurt B. Kaiser5acdf932004-11-16 21:28:36 +00001152 for configType in ['keys', 'highlight']:
1153 # save these even if unchanged!
1154 idleConf.userCfg[configType].Save()
Steven M. Gavaa498af22002-02-01 01:33:36 +00001155 self.ResetChangedItems() #clear the changed items dict
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001156
Kurt B. Kaiserb1754452005-11-18 22:05:48 +00001157 def DeactivateCurrentConfig(self):
1158 #Before a config is saved, some cleanup of current
1159 #config must be done - remove the previous keybindings
Terry Jan Reedyae410862014-08-03 23:02:53 -04001160 winInstances = self.parent.instance_dict
Kurt B. Kaiserb1754452005-11-18 22:05:48 +00001161 for instance in winInstances:
1162 instance.RemoveKeybindings()
1163
Steven M. Gava49745752002-02-18 01:43:11 +00001164 def ActivateConfigChanges(self):
Kurt B. Kaiseracdef852005-01-31 03:34:26 +00001165 "Dynamically apply configuration changes"
Terry Jan Reedy110796f2014-07-27 04:07:18 -04001166 winInstances = self.parent.instance_dict.keys()
Steven M. Gavab77d3432002-03-02 07:16:21 +00001167 for instance in winInstances:
1168 instance.ResetColorizer()
Steven M. Gavab1585412002-03-12 00:21:56 +00001169 instance.ResetFont()
Kurt B. Kaiseracdef852005-01-31 03:34:26 +00001170 instance.set_notabs_indentwidth()
Kurt B. Kaiserb1754452005-11-18 22:05:48 +00001171 instance.ApplyKeybindings()
Kurt B. Kaiser8e92bf72003-01-14 22:03:31 +00001172 instance.reset_help_menu_entries()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001173
Steven M. Gava5f28e8f2002-01-21 06:38:21 +00001174 def Cancel(self):
1175 self.destroy()
1176
1177 def Ok(self):
1178 self.Apply()
1179 self.destroy()
1180
1181 def Apply(self):
Kurt B. Kaiserb1754452005-11-18 22:05:48 +00001182 self.DeactivateCurrentConfig()
Steven M. Gava052937f2002-02-11 02:20:53 +00001183 self.SaveAllChangedConfigs()
Steven M. Gava49745752002-02-18 01:43:11 +00001184 self.ActivateConfigChanges()
Steven M. Gava5f28e8f2002-01-21 06:38:21 +00001185
1186 def Help(self):
Steven M. Gavac11ccf32001-09-24 09:43:17 +00001187 pass
1188
Terry Jan Reedy7a162072014-10-22 20:15:12 -04001189class VerticalScrolledFrame(Frame):
1190 """A pure Tkinter vertically scrollable frame.
1191
1192 * Use the 'interior' attribute to place widgets inside the scrollable frame
1193 * Construct and pack/place/grid normally
1194 * This frame only allows vertical scrolling
1195 """
1196 def __init__(self, parent, *args, **kw):
1197 Frame.__init__(self, parent, *args, **kw)
1198
1199 # create a canvas object and a vertical scrollbar for scrolling it
1200 vscrollbar = Scrollbar(self, orient=VERTICAL)
1201 vscrollbar.pack(fill=Y, side=RIGHT, expand=FALSE)
1202 canvas = Canvas(self, bd=0, highlightthickness=0,
1203 yscrollcommand=vscrollbar.set)
1204 canvas.pack(side=LEFT, fill=BOTH, expand=TRUE)
1205 vscrollbar.config(command=canvas.yview)
1206
1207 # reset the view
1208 canvas.xview_moveto(0)
1209 canvas.yview_moveto(0)
1210
1211 # create a frame inside the canvas which will be scrolled with it
1212 self.interior = interior = Frame(canvas)
1213 interior_id = canvas.create_window(0, 0, window=interior, anchor=NW)
1214
1215 # track changes to the canvas and frame width and sync them,
1216 # also updating the scrollbar
1217 def _configure_interior(event):
1218 # update the scrollbars to match the size of the inner frame
1219 size = (interior.winfo_reqwidth(), interior.winfo_reqheight())
1220 canvas.config(scrollregion="0 0 %s %s" % size)
1221 if interior.winfo_reqwidth() != canvas.winfo_width():
1222 # update the canvas's width to fit the inner frame
1223 canvas.config(width=interior.winfo_reqwidth())
1224 interior.bind('<Configure>', _configure_interior)
1225
1226 def _configure_canvas(event):
1227 if interior.winfo_reqwidth() != canvas.winfo_width():
1228 # update the inner frame's width to fill the canvas
1229 canvas.itemconfigure(interior_id, width=canvas.winfo_width())
1230 canvas.bind('<Configure>', _configure_canvas)
1231
1232 return
1233
1234def is_int(s):
1235 "Return 's is blank or represents an int'"
1236 if not s:
1237 return True
1238 try:
1239 int(s)
1240 return True
1241 except ValueError:
1242 return False
1243
1244# TODO:
1245# * Revert to default(s)? Per option or per extension?
1246# * List options in their original order (possible??)
1247class ConfigExtensionsDialog(Toplevel):
1248 """A dialog for configuring IDLE extensions.
1249
1250 This dialog is generic - it works for any and all IDLE extensions.
1251
1252 IDLE extensions save their configuration options using idleConf.
1253 ConfigExtensionsDialog reads the current configuration using idleConf,
1254 supplies a GUI interface to change the configuration values, and saves the
1255 changes using idleConf.
1256
1257 Not all changes take effect immediately - some may require restarting IDLE.
1258 This depends on each extension's implementation.
1259
1260 All values are treated as text, and it is up to the user to supply
1261 reasonable values. The only exception to this are the 'enable*' options,
1262 which are boolean, and can be toggled with an True/False button.
1263 """
1264 def __init__(self, parent, title=None, _htest=False):
1265 Toplevel.__init__(self, parent)
1266 self.wm_withdraw()
1267
1268 self.configure(borderwidth=5)
1269 self.geometry(
1270 "+%d+%d" % (parent.winfo_rootx() + 20,
1271 parent.winfo_rooty() + (30 if not _htest else 150)))
1272 self.wm_title(title or 'IDLE Extensions Configuration')
1273
1274 self.defaultCfg = idleConf.defaultCfg['extensions']
1275 self.userCfg = idleConf.userCfg['extensions']
1276 self.is_int = self.register(is_int)
1277 self.load_extensions()
1278 self.create_widgets()
1279
1280 self.resizable(height=FALSE, width=FALSE) # don't allow resizing yet
1281 self.transient(parent)
1282 self.protocol("WM_DELETE_WINDOW", self.Cancel)
1283 self.tabbed_page_set.focus_set()
1284 # wait for window to be generated
1285 self.update()
1286 # set current width as the minimum width
1287 self.wm_minsize(self.winfo_width(), 1)
1288 # now allow resizing
1289 self.resizable(height=TRUE, width=TRUE)
1290
1291 self.wm_deiconify()
1292 if not _htest:
1293 self.grab_set()
1294 self.wait_window()
1295
1296 def load_extensions(self):
1297 "Fill self.extensions with data from the default and user configs."
1298 self.extensions = {}
1299 for ext_name in idleConf.GetExtensions(active_only=False):
1300 self.extensions[ext_name] = []
1301
1302 for ext_name in self.extensions:
1303 opt_list = sorted(self.defaultCfg.GetOptionList(ext_name))
1304
1305 # bring 'enable' options to the beginning of the list
1306 enables = [opt_name for opt_name in opt_list
1307 if opt_name.startswith('enable')]
1308 for opt_name in enables:
1309 opt_list.remove(opt_name)
1310 opt_list = enables + opt_list
1311
1312 for opt_name in opt_list:
1313 def_str = self.defaultCfg.Get(
1314 ext_name, opt_name, raw=True)
1315 try:
1316 def_obj = {'True':True, 'False':False}[def_str]
1317 opt_type = 'bool'
1318 except KeyError:
1319 try:
1320 def_obj = int(def_str)
1321 opt_type = 'int'
1322 except ValueError:
1323 def_obj = def_str
1324 opt_type = None
1325 try:
1326 value = self.userCfg.Get(
1327 ext_name, opt_name, type=opt_type, raw=True,
1328 default=def_obj)
1329 except ValueError: # Need this until .Get fixed
1330 value = def_obj # bad values overwritten by entry
1331 var = StringVar(self)
1332 var.set(str(value))
1333
1334 self.extensions[ext_name].append({'name': opt_name,
1335 'type': opt_type,
1336 'default': def_str,
1337 'value': value,
1338 'var': var,
1339 })
1340
1341 def create_widgets(self):
1342 """Create the dialog's widgets."""
1343 self.rowconfigure(0, weight=1)
1344 self.rowconfigure(1, weight=0)
1345 self.columnconfigure(0, weight=1)
1346
1347 # create the tabbed pages
1348 self.tabbed_page_set = TabbedPageSet(
1349 self, page_names=self.extensions.keys(),
1350 n_rows=None, max_tabs_per_row=5,
1351 page_class=TabbedPageSet.PageRemove)
1352 self.tabbed_page_set.grid(row=0, column=0, sticky=NSEW)
1353 for ext_name in self.extensions:
1354 self.create_tab_page(ext_name)
1355
1356 self.create_action_buttons().grid(row=1)
1357
1358 create_action_buttons = ConfigDialog.create_action_buttons.im_func
1359
1360 def create_tab_page(self, ext_name):
1361 """Create the page for an extension."""
1362
1363 page = LabelFrame(self.tabbed_page_set.pages[ext_name].frame,
1364 border=2, padx=2, relief=GROOVE,
1365 text=' %s ' % ext_name)
1366 page.pack(fill=BOTH, expand=True, padx=12, pady=2)
1367
1368 # create the scrollable frame which will contain the entries
1369 scrolled_frame = VerticalScrolledFrame(page, pady=2, height=250)
1370 scrolled_frame.pack(side=BOTTOM, fill=BOTH, expand=TRUE)
1371 entry_area = scrolled_frame.interior
1372 entry_area.columnconfigure(0, weight=0)
1373 entry_area.columnconfigure(1, weight=1)
1374
1375 # create an entry for each configuration option
1376 for row, opt in enumerate(self.extensions[ext_name]):
1377 # create a row with a label and entry/checkbutton
1378 label = Label(entry_area, text=opt['name'])
1379 label.grid(row=row, column=0, sticky=NW)
1380 var = opt['var']
1381 if opt['type'] == 'bool':
1382 Checkbutton(entry_area, textvariable=var, variable=var,
1383 onvalue='True', offvalue='False',
1384 indicatoron=FALSE, selectcolor='', width=8
1385 ).grid(row=row, column=1, sticky=W, padx=7)
1386 elif opt['type'] == 'int':
1387 Entry(entry_area, textvariable=var, validate='key',
1388 validatecommand=(self.is_int, '%P')
1389 ).grid(row=row, column=1, sticky=NSEW, padx=7)
1390
1391 else:
1392 Entry(entry_area, textvariable=var
1393 ).grid(row=row, column=1, sticky=NSEW, padx=7)
1394 return
1395
1396
1397 Ok = ConfigDialog.Ok.im_func
1398
1399 def Apply(self):
1400 self.save_all_changed_configs()
1401 pass
1402
1403 Cancel = ConfigDialog.Cancel.im_func
1404
1405 def Help(self):
1406 pass
1407
1408 def set_user_value(self, section, opt):
1409 name = opt['name']
1410 default = opt['default']
1411 value = opt['var'].get().strip() or default
1412 opt['var'].set(value)
1413 # if self.defaultCfg.has_section(section):
1414 # Currently, always true; if not, indent to return
1415 if (value == default):
1416 return self.userCfg.RemoveOption(section, name)
1417 # set the option
1418 return self.userCfg.SetOption(section, name, value)
1419
1420 def save_all_changed_configs(self):
1421 """Save configuration changes to the user config file."""
1422 has_changes = False
1423 for ext_name in self.extensions:
1424 options = self.extensions[ext_name]
1425 for opt in options:
1426 if self.set_user_value(ext_name, opt):
1427 has_changes = True
1428 if has_changes:
1429 self.userCfg.Save()
1430
1431
Steven M. Gava44d3d1a2001-07-31 06:59:02 +00001432if __name__ == '__main__':
Terry Jan Reedyaf0dce92014-07-14 23:07:21 -04001433 import unittest
1434 unittest.main('idlelib.idle_test.test_configdialog',
1435 verbosity=2, exit=False)
Terry Jan Reedy76916e82014-05-29 01:46:16 -04001436 from idlelib.idle_test.htest import run
Terry Jan Reedy7a162072014-10-22 20:15:12 -04001437 run(ConfigDialog, ConfigExtensionsDialog)