blob: 671882b18d8f111562f14d3f79a80301b416903c [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
Terry Jan Reedyc0a053e2015-10-11 22:07:25 -040021from idlelib.textView import view_text
Florent Xiclunad630c042010-04-02 07:24:52 +000022from idlelib import macosxSupport
Terry Jan Reedyc0a053e2015-10-11 22:07:25 -040023
Steven M. Gava44d3d1a2001-07-31 06:59:02 +000024class ConfigDialog(Toplevel):
Kurt B. Kaiseracdef852005-01-31 03:34:26 +000025
Terry Jan Reedycf834762014-10-17 01:31:29 -040026 def __init__(self, parent, title='', _htest=False, _utest=False):
Terry Jan Reedy76916e82014-05-29 01:46:16 -040027 """
28 _htest - bool, change box location when running htest
Terry Jan Reedyaf0dce92014-07-14 23:07:21 -040029 _utest - bool, don't wait_window when running unittest
Terry Jan Reedy76916e82014-05-29 01:46:16 -040030 """
Steven M. Gavad721c482001-07-31 10:46:53 +000031 Toplevel.__init__(self, parent)
Terry Jan Reedy19b7a752014-07-30 19:24:26 -040032 self.parent = parent
Terry Jan Reedyae410862014-08-03 23:02:53 -040033 if _htest:
34 parent.instance_dict = {}
Kurt B. Kaisere3fde8f2007-10-04 03:11:12 +000035 self.wm_withdraw()
36
Steven M. Gavad721c482001-07-31 10:46:53 +000037 self.configure(borderwidth=5)
Terry Jan Reedycf834762014-10-17 01:31:29 -040038 self.title(title or 'IDLE Preferences')
Terry Jan Reedyae410862014-08-03 23:02:53 -040039 self.geometry(
40 "+%d+%d" % (parent.winfo_rootx() + 20,
41 parent.winfo_rooty() + (30 if not _htest else 150)))
Georg Brandl7eb4b7d2005-07-22 21:49:32 +000042 #Theme Elements. Each theme element key is its display name.
Steven M. Gava9dd16b32001-11-03 14:54:25 +000043 #The first value of the tuple is the sample area tag name.
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +000044 #The second value is the display name list sort index.
Terry Jan Reedyae410862014-08-03 23:02:53 -040045 self.themeElements={
Terry Jan Reedyc30475e2015-10-02 22:12:09 -040046 'Normal Text': ('normal', '00'),
47 'Python Keywords': ('keyword', '01'),
48 'Python Definitions': ('definition', '02'),
49 'Python Builtins': ('builtin', '03'),
50 'Python Comments': ('comment', '04'),
51 'Python Strings': ('string', '05'),
52 'Selected Text': ('hilite', '06'),
53 'Found Text': ('hit', '07'),
54 'Cursor': ('cursor', '08'),
55 'Editor Breakpoint': ('break', '09'),
56 'Shell Normal Text': ('console', '10'),
57 'Shell Error Text': ('error', '11'),
58 'Shell Stdout Text': ('stdout', '12'),
59 'Shell Stderr Text': ('stderr', '13'),
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 Reedyae410862014-08-03 23:02:53 -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 Reedyae410862014-08-03 23:02:53 -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. Gava429a86a2001-10-23 10:42:12 +000072 self.LoadConfigs()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +000073 self.AttachVarCallbacks() #avoid callbacks during LoadConfigs
Kurt B. Kaisere3fde8f2007-10-04 03:11:12 +000074
Terry Jan Reedyaf0dce92014-07-14 23:07:21 -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):
Kurt B. Kaiser20172f92007-10-30 02:38:54 +000080 self.tabPages = TabbedPageSet(self,
Terry Jan Reedy1c49ec02015-10-13 22:03:44 -040081 page_names=['Fonts/Tabs', 'Highlighting', 'Keys', 'General',
82 'Extensions'])
Terry Jan Reedy23030db2014-10-08 20:29:05 -040083 self.tabPages.pack(side=TOP, expand=TRUE, fill=BOTH)
84 self.CreatePageFontTab()
85 self.CreatePageHighlight()
86 self.CreatePageKeys()
87 self.CreatePageGeneral()
Terry Jan Reedy1c49ec02015-10-13 22:03:44 -040088 self.CreatePageExtensions()
Terry Jan Reedy23030db2014-10-08 20:29:05 -040089 self.create_action_buttons().pack(side=BOTTOM)
Terry Jan Reedyc0a053e2015-10-11 22:07:25 -040090
Terry Jan Reedy23030db2014-10-08 20:29:05 -040091 def create_action_buttons(self):
Ned Deily57847df2014-03-27 20:47:04 -070092 if macosxSupport.isAquaTk():
Ronald Oussorena97063a2009-03-04 21:35:05 +000093 # Changing the default padding on OSX results in unreadable
94 # text in the buttons
Terry Jan Reedyae410862014-08-03 23:02:53 -040095 paddingArgs = {}
Ronald Oussorena97063a2009-03-04 21:35:05 +000096 else:
Terry Jan Reedyae410862014-08-03 23:02:53 -040097 paddingArgs = {'padx':6, 'pady':3}
Terry Jan Reedy7a162072014-10-22 20:15:12 -040098 outer = Frame(self, pady=2)
99 buttons = Frame(outer, pady=2)
Terry Jan Reedyc0a053e2015-10-11 22:07:25 -0400100 for txt, cmd in (
101 ('Ok', self.Ok),
102 ('Apply', self.Apply),
103 ('Cancel', self.Cancel),
104 ('Help', self.Help)):
105 Button(buttons, text=txt, command=cmd, takefocus=FALSE,
106 **paddingArgs).pack(side=LEFT, padx=5)
Terry Jan Reedy7a162072014-10-22 20:15:12 -0400107 # add space above buttons
108 Frame(outer, height=2, borderwidth=0).pack(side=TOP)
109 buttons.pack(side=BOTTOM)
110 return outer
Terry Jan Reedyc0a053e2015-10-11 22:07:25 -0400111
Steven M. Gava60fc7072001-08-04 13:58:22 +0000112 def CreatePageFontTab(self):
Terry Jan Reedy19b7a752014-07-30 19:24:26 -0400113 parent = self.parent
114 self.fontSize = StringVar(parent)
115 self.fontBold = BooleanVar(parent)
116 self.fontName = StringVar(parent)
117 self.spaceNum = IntVar(parent)
Terry Jan Reedyae410862014-08-03 23:02:53 -0400118 self.editFont = tkFont.Font(parent, ('courier', 10, 'normal'))
Terry Jan Reedy19b7a752014-07-30 19:24:26 -0400119
Steven M. Gavaf213ccb2001-08-05 08:00:28 +0000120 ##widget creation
121 #body frame
Terry Jan Reedyae410862014-08-03 23:02:53 -0400122 frame = self.tabPages.pages['Fonts/Tabs'].frame
Steven M. Gavaf213ccb2001-08-05 08:00:28 +0000123 #body section frames
Terry Jan Reedyae410862014-08-03 23:02:53 -0400124 frameFont = LabelFrame(
125 frame, borderwidth=2, relief=GROOVE, text=' Base Editor Font ')
126 frameIndent = LabelFrame(
127 frame, borderwidth=2, relief=GROOVE, text=' Indentation Width ')
Steven M. Gavaf213ccb2001-08-05 08:00:28 +0000128 #frameFont
Terry Jan Reedyae410862014-08-03 23:02:53 -0400129 frameFontName = Frame(frameFont)
130 frameFontParam = Frame(frameFont)
131 labelFontNameTitle = Label(
132 frameFontName, justify=LEFT, text='Font Face :')
133 self.listFontName = Listbox(
134 frameFontName, height=5, takefocus=FALSE, exportselection=FALSE)
135 self.listFontName.bind(
136 '<ButtonRelease-1>', self.OnListFontButtonRelease)
137 scrollFont = Scrollbar(frameFontName)
Steven M. Gavac01e30f2001-08-11 15:48:13 +0000138 scrollFont.config(command=self.listFontName.yview)
139 self.listFontName.config(yscrollcommand=scrollFont.set)
Terry Jan Reedyae410862014-08-03 23:02:53 -0400140 labelFontSizeTitle = Label(frameFontParam, text='Size :')
141 self.optMenuFontSize = DynOptionMenu(
142 frameFontParam, self.fontSize, None, command=self.SetFontSample)
143 checkFontBold = Checkbutton(
144 frameFontParam, variable=self.fontBold, onvalue=1,
145 offvalue=0, text='Bold', command=self.SetFontSample)
146 frameFontSample = Frame(frameFont, relief=SOLID, borderwidth=1)
147 self.labelFontSample = Label(
148 frameFontSample, justify=LEFT, font=self.editFont,
149 text='AaBbCcDdEe\nFfGgHhIiJjK\n1234567890\n#:+=(){}[]')
Steven M. Gavaf213ccb2001-08-05 08:00:28 +0000150 #frameIndent
Terry Jan Reedyae410862014-08-03 23:02:53 -0400151 frameIndentSize = Frame(frameIndent)
152 labelSpaceNumTitle = Label(
153 frameIndentSize, justify=LEFT,
154 text='Python Standard: 4 Spaces!')
155 self.scaleSpaceNum = Scale(
156 frameIndentSize, variable=self.spaceNum,
157 orient='horizontal', tickinterval=2, from_=2, to=16)
Terry Jan Reedy19b7a752014-07-30 19:24:26 -0400158
Steven M. Gavaf213ccb2001-08-05 08:00:28 +0000159 #widget packing
160 #body
Terry Jan Reedyae410862014-08-03 23:02:53 -0400161 frameFont.pack(side=LEFT, padx=5, pady=5, expand=TRUE, fill=BOTH)
162 frameIndent.pack(side=LEFT, padx=5, pady=5, fill=Y)
Steven M. Gavaf213ccb2001-08-05 08:00:28 +0000163 #frameFont
Terry Jan Reedyae410862014-08-03 23:02:53 -0400164 frameFontName.pack(side=TOP, padx=5, pady=5, fill=X)
165 frameFontParam.pack(side=TOP, padx=5, pady=5, fill=X)
166 labelFontNameTitle.pack(side=TOP, anchor=W)
167 self.listFontName.pack(side=LEFT, expand=TRUE, fill=X)
168 scrollFont.pack(side=LEFT, fill=Y)
169 labelFontSizeTitle.pack(side=LEFT, anchor=W)
170 self.optMenuFontSize.pack(side=LEFT, anchor=W)
171 checkFontBold.pack(side=LEFT, anchor=W, padx=20)
172 frameFontSample.pack(side=TOP, padx=5, pady=5, expand=TRUE, fill=BOTH)
173 self.labelFontSample.pack(expand=TRUE, fill=BOTH)
Steven M. Gavaf213ccb2001-08-05 08:00:28 +0000174 #frameIndent
Terry Jan Reedyae410862014-08-03 23:02:53 -0400175 frameIndentSize.pack(side=TOP, fill=X)
176 labelSpaceNumTitle.pack(side=TOP, anchor=W, padx=5)
177 self.scaleSpaceNum.pack(side=TOP, padx=5, fill=X)
Steven M. Gava952d0a52001-08-03 04:43:44 +0000178 return frame
179
180 def CreatePageHighlight(self):
Terry Jan Reedy19b7a752014-07-30 19:24:26 -0400181 parent = self.parent
182 self.builtinTheme = StringVar(parent)
183 self.customTheme = StringVar(parent)
184 self.fgHilite = BooleanVar(parent)
185 self.colour = StringVar(parent)
186 self.fontName = StringVar(parent)
187 self.themeIsBuiltin = BooleanVar(parent)
188 self.highlightTarget = StringVar(parent)
189
Steven M. Gava952d0a52001-08-03 04:43:44 +0000190 ##widget creation
191 #body frame
Terry Jan Reedyae410862014-08-03 23:02:53 -0400192 frame = self.tabPages.pages['Highlighting'].frame
Steven M. Gava952d0a52001-08-03 04:43:44 +0000193 #body section frames
Terry Jan Reedyae410862014-08-03 23:02:53 -0400194 frameCustom = LabelFrame(frame, borderwidth=2, relief=GROOVE,
195 text=' Custom Highlighting ')
196 frameTheme = LabelFrame(frame, borderwidth=2, relief=GROOVE,
197 text=' Highlighting Theme ')
Steven M. Gava952d0a52001-08-03 04:43:44 +0000198 #frameCustom
Terry Jan Reedyae410862014-08-03 23:02:53 -0400199 self.textHighlightSample=Text(
200 frameCustom, relief=SOLID, borderwidth=1,
201 font=('courier', 12, ''), cursor='hand2', width=21, height=11,
202 takefocus=FALSE, highlightthickness=0, wrap=NONE)
Steven M. Gavae16d94b2001-11-03 05:07:28 +0000203 text=self.textHighlightSample
Terry Jan Reedyae410862014-08-03 23:02:53 -0400204 text.bind('<Double-Button-1>', lambda e: 'break')
205 text.bind('<B1-Motion>', lambda e: 'break')
206 textAndTags=(
207 ('#you can click here', 'comment'), ('\n', 'normal'),
208 ('#to choose items', 'comment'), ('\n', 'normal'),
209 ('def', 'keyword'), (' ', 'normal'),
210 ('func', 'definition'), ('(param):\n ', 'normal'),
211 ('"""string"""', 'string'), ('\n var0 = ', 'normal'),
212 ("'string'", 'string'), ('\n var1 = ', 'normal'),
213 ("'selected'", 'hilite'), ('\n var2 = ', 'normal'),
214 ("'found'", 'hit'), ('\n var3 = ', 'normal'),
215 ('list', 'builtin'), ('(', 'normal'),
Terry Jan Reedyc30475e2015-10-02 22:12:09 -0400216 ('None', 'builtin'), (')\n', 'normal'),
217 (' breakpoint("line")', 'break'), ('\n\n', 'normal'),
Terry Jan Reedyae410862014-08-03 23:02:53 -0400218 (' error ', 'error'), (' ', 'normal'),
219 ('cursor |', 'cursor'), ('\n ', 'normal'),
220 ('shell', 'console'), (' ', 'normal'),
221 ('stdout', 'stdout'), (' ', 'normal'),
222 ('stderr', 'stderr'), ('\n', 'normal'))
Steven M. Gava9dd16b32001-11-03 14:54:25 +0000223 for txTa in textAndTags:
Terry Jan Reedyae410862014-08-03 23:02:53 -0400224 text.insert(END, txTa[0], txTa[1])
Terry Jan Reedy110796f2014-07-27 04:07:18 -0400225 for element in self.themeElements:
Terry Jan Reedyae410862014-08-03 23:02:53 -0400226 def tem(event, elem=element):
227 event.widget.winfo_toplevel().highlightTarget.set(elem)
228 text.tag_bind(
229 self.themeElements[element][0], '<ButtonPress-1>', tem)
Steven M. Gavae16d94b2001-11-03 05:07:28 +0000230 text.config(state=DISABLED)
Terry Jan Reedyae410862014-08-03 23:02:53 -0400231 self.frameColourSet = Frame(frameCustom, relief=SOLID, borderwidth=1)
232 frameFgBg = Frame(frameCustom)
233 buttonSetColour = Button(
234 self.frameColourSet, text='Choose Colour for :',
235 command=self.GetColour, highlightthickness=0)
236 self.optMenuHighlightTarget = DynOptionMenu(
237 self.frameColourSet, self.highlightTarget, None,
238 highlightthickness=0) #, command=self.SetHighlightTargetBinding
239 self.radioFg = Radiobutton(
240 frameFgBg, variable=self.fgHilite, value=1,
241 text='Foreground', command=self.SetColourSampleBinding)
242 self.radioBg=Radiobutton(
243 frameFgBg, variable=self.fgHilite, value=0,
244 text='Background', command=self.SetColourSampleBinding)
Steven M. Gava7c017862001-10-29 11:19:46 +0000245 self.fgHilite.set(1)
Terry Jan Reedyae410862014-08-03 23:02:53 -0400246 buttonSaveCustomTheme = Button(
247 frameCustom, text='Save as New Custom Theme',
248 command=self.SaveAsNewTheme)
Steven M. Gava952d0a52001-08-03 04:43:44 +0000249 #frameTheme
Terry Jan Reedyae410862014-08-03 23:02:53 -0400250 labelTypeTitle = Label(frameTheme, text='Select : ')
251 self.radioThemeBuiltin = Radiobutton(
252 frameTheme, variable=self.themeIsBuiltin, value=1,
253 command=self.SetThemeType, text='a Built-in Theme')
254 self.radioThemeCustom = Radiobutton(
255 frameTheme, variable=self.themeIsBuiltin, value=0,
256 command=self.SetThemeType, text='a Custom Theme')
257 self.optMenuThemeBuiltin = DynOptionMenu(
258 frameTheme, self.builtinTheme, None, command=None)
259 self.optMenuThemeCustom=DynOptionMenu(
260 frameTheme, self.customTheme, None, command=None)
261 self.buttonDeleteCustomTheme=Button(
262 frameTheme, text='Delete Custom Theme',
Steven M. Gava49745752002-02-18 01:43:11 +0000263 command=self.DeleteCustomTheme)
Terry Jan Reedy35aa5d02015-11-12 15:02:50 -0500264 self.new_custom_theme = Label(frameTheme, bd=2)
Terry Jan Reedy19b7a752014-07-30 19:24:26 -0400265
Steven M. Gava952d0a52001-08-03 04:43:44 +0000266 ##widget packing
267 #body
Terry Jan Reedyae410862014-08-03 23:02:53 -0400268 frameCustom.pack(side=LEFT, padx=5, pady=5, expand=TRUE, fill=BOTH)
269 frameTheme.pack(side=LEFT, padx=5, pady=5, fill=Y)
Steven M. Gava952d0a52001-08-03 04:43:44 +0000270 #frameCustom
Terry Jan Reedyae410862014-08-03 23:02:53 -0400271 self.frameColourSet.pack(side=TOP, padx=5, pady=5, expand=TRUE, fill=X)
272 frameFgBg.pack(side=TOP, padx=5, pady=0)
273 self.textHighlightSample.pack(
274 side=TOP, padx=5, pady=5, expand=TRUE, fill=BOTH)
275 buttonSetColour.pack(side=TOP, expand=TRUE, fill=X, padx=8, pady=4)
276 self.optMenuHighlightTarget.pack(
277 side=TOP, expand=TRUE, fill=X, padx=8, pady=3)
278 self.radioFg.pack(side=LEFT, anchor=E)
279 self.radioBg.pack(side=RIGHT, anchor=W)
280 buttonSaveCustomTheme.pack(side=BOTTOM, fill=X, padx=5, pady=5)
Steven M. Gava952d0a52001-08-03 04:43:44 +0000281 #frameTheme
Terry Jan Reedyae410862014-08-03 23:02:53 -0400282 labelTypeTitle.pack(side=TOP, anchor=W, padx=5, pady=5)
283 self.radioThemeBuiltin.pack(side=TOP, anchor=W, padx=5)
284 self.radioThemeCustom.pack(side=TOP, anchor=W, padx=5, pady=2)
285 self.optMenuThemeBuiltin.pack(side=TOP, fill=X, padx=5, pady=5)
286 self.optMenuThemeCustom.pack(side=TOP, fill=X, anchor=W, padx=5, pady=5)
287 self.buttonDeleteCustomTheme.pack(side=TOP, fill=X, padx=5, pady=5)
Terry Jan Reedy35aa5d02015-11-12 15:02:50 -0500288 self.new_custom_theme.pack(side=TOP, fill=X, pady=5)
Steven M. Gava952d0a52001-08-03 04:43:44 +0000289 return frame
290
291 def CreatePageKeys(self):
Terry Jan Reedy19b7a752014-07-30 19:24:26 -0400292 parent = self.parent
293 self.bindingTarget = StringVar(parent)
294 self.builtinKeys = StringVar(parent)
295 self.customKeys = StringVar(parent)
296 self.keysAreBuiltin = BooleanVar(parent)
297 self.keyBinding = StringVar(parent)
298
Steven M. Gava60fc7072001-08-04 13:58:22 +0000299 ##widget creation
300 #body frame
Terry Jan Reedyae410862014-08-03 23:02:53 -0400301 frame = self.tabPages.pages['Keys'].frame
Steven M. Gava60fc7072001-08-04 13:58:22 +0000302 #body section frames
Terry Jan Reedyae410862014-08-03 23:02:53 -0400303 frameCustom = LabelFrame(
304 frame, borderwidth=2, relief=GROOVE,
305 text=' Custom Key Bindings ')
306 frameKeySets = LabelFrame(
307 frame, borderwidth=2, relief=GROOVE, text=' Key Set ')
Steven M. Gava60fc7072001-08-04 13:58:22 +0000308 #frameCustom
Terry Jan Reedyae410862014-08-03 23:02:53 -0400309 frameTarget = Frame(frameCustom)
310 labelTargetTitle = Label(frameTarget, text='Action - Key(s)')
311 scrollTargetY = Scrollbar(frameTarget)
312 scrollTargetX = Scrollbar(frameTarget, orient=HORIZONTAL)
313 self.listBindings = Listbox(
314 frameTarget, takefocus=FALSE, exportselection=FALSE)
315 self.listBindings.bind('<ButtonRelease-1>', self.KeyBindingSelected)
Steven M. Gavafacfc092002-01-19 00:29:54 +0000316 scrollTargetY.config(command=self.listBindings.yview)
317 scrollTargetX.config(command=self.listBindings.xview)
318 self.listBindings.config(yscrollcommand=scrollTargetY.set)
319 self.listBindings.config(xscrollcommand=scrollTargetX.set)
Terry Jan Reedyae410862014-08-03 23:02:53 -0400320 self.buttonNewKeys = Button(
321 frameCustom, text='Get New Keys for Selection',
322 command=self.GetNewKeys, state=DISABLED)
Steven M. Gava60fc7072001-08-04 13:58:22 +0000323 #frameKeySets
Kurt B. Kaiser28c7bcf2007-12-28 04:18:01 +0000324 frames = [Frame(frameKeySets, padx=2, pady=2, borderwidth=0)
325 for i in range(2)]
Terry Jan Reedyae410862014-08-03 23:02:53 -0400326 self.radioKeysBuiltin = Radiobutton(
327 frames[0], variable=self.keysAreBuiltin, value=1,
328 command=self.SetKeysType, text='Use a Built-in Key Set')
329 self.radioKeysCustom = Radiobutton(
330 frames[0], variable=self.keysAreBuiltin, value=0,
331 command=self.SetKeysType, text='Use a Custom Key Set')
332 self.optMenuKeysBuiltin = DynOptionMenu(
333 frames[0], self.builtinKeys, None, command=None)
334 self.optMenuKeysCustom = DynOptionMenu(
335 frames[0], self.customKeys, None, command=None)
336 self.buttonDeleteCustomKeys = Button(
337 frames[1], text='Delete Custom Key Set',
Steven M. Gava49745752002-02-18 01:43:11 +0000338 command=self.DeleteCustomKeys)
Terry Jan Reedyae410862014-08-03 23:02:53 -0400339 buttonSaveCustomKeys = Button(
340 frames[1], text='Save as New Custom Key Set',
341 command=self.SaveAsNewKeySet)
Terry Jan Reedy19b7a752014-07-30 19:24:26 -0400342
Steven M. Gava60fc7072001-08-04 13:58:22 +0000343 ##widget packing
344 #body
Terry Jan Reedyae410862014-08-03 23:02:53 -0400345 frameCustom.pack(side=BOTTOM, padx=5, pady=5, expand=TRUE, fill=BOTH)
346 frameKeySets.pack(side=BOTTOM, padx=5, pady=5, fill=BOTH)
Steven M. Gava60fc7072001-08-04 13:58:22 +0000347 #frameCustom
Terry Jan Reedyae410862014-08-03 23:02:53 -0400348 self.buttonNewKeys.pack(side=BOTTOM, fill=X, padx=5, pady=5)
349 frameTarget.pack(side=LEFT, padx=5, pady=5, expand=TRUE, fill=BOTH)
Steven M. Gavafacfc092002-01-19 00:29:54 +0000350 #frame target
Terry Jan Reedyae410862014-08-03 23:02:53 -0400351 frameTarget.columnconfigure(0, weight=1)
352 frameTarget.rowconfigure(1, weight=1)
353 labelTargetTitle.grid(row=0, column=0, columnspan=2, sticky=W)
354 self.listBindings.grid(row=1, column=0, sticky=NSEW)
355 scrollTargetY.grid(row=1, column=1, sticky=NS)
356 scrollTargetX.grid(row=2, column=0, sticky=EW)
Steven M. Gava60fc7072001-08-04 13:58:22 +0000357 #frameKeySets
Kurt B. Kaiser28c7bcf2007-12-28 04:18:01 +0000358 self.radioKeysBuiltin.grid(row=0, column=0, sticky=W+NS)
359 self.radioKeysCustom.grid(row=1, column=0, sticky=W+NS)
360 self.optMenuKeysBuiltin.grid(row=0, column=1, sticky=NSEW)
361 self.optMenuKeysCustom.grid(row=1, column=1, sticky=NSEW)
Terry Jan Reedyae410862014-08-03 23:02:53 -0400362 self.buttonDeleteCustomKeys.pack(side=LEFT, fill=X, expand=True, padx=2)
363 buttonSaveCustomKeys.pack(side=LEFT, fill=X, expand=True, padx=2)
Kurt B. Kaiser28c7bcf2007-12-28 04:18:01 +0000364 frames[0].pack(side=TOP, fill=BOTH, expand=True)
365 frames[1].pack(side=TOP, fill=X, expand=True, pady=2)
Steven M. Gava952d0a52001-08-03 04:43:44 +0000366 return frame
367
368 def CreatePageGeneral(self):
Terry Jan Reedy19b7a752014-07-30 19:24:26 -0400369 parent = self.parent
370 self.winWidth = StringVar(parent)
371 self.winHeight = StringVar(parent)
Terry Jan Reedy19b7a752014-07-30 19:24:26 -0400372 self.startupEdit = IntVar(parent)
373 self.autoSave = IntVar(parent)
374 self.encoding = StringVar(parent)
375 self.userHelpBrowser = BooleanVar(parent)
376 self.helpBrowser = StringVar(parent)
377
Steven M. Gava230e5782001-08-07 03:28:25 +0000378 #widget creation
379 #body
Terry Jan Reedyae410862014-08-03 23:02:53 -0400380 frame = self.tabPages.pages['General'].frame
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000381 #body section frames
Terry Jan Reedyae410862014-08-03 23:02:53 -0400382 frameRun = LabelFrame(frame, borderwidth=2, relief=GROOVE,
383 text=' Startup Preferences ')
384 frameSave = LabelFrame(frame, borderwidth=2, relief=GROOVE,
385 text=' Autosave Preferences ')
386 frameWinSize = Frame(frame, borderwidth=2, relief=GROOVE)
Terry Jan Reedyae410862014-08-03 23:02:53 -0400387 frameEncoding = Frame(frame, borderwidth=2, relief=GROOVE)
388 frameHelp = LabelFrame(frame, borderwidth=2, relief=GROOVE,
389 text=' Additional Help Sources ')
Steven M. Gava230e5782001-08-07 03:28:25 +0000390 #frameRun
Terry Jan Reedyae410862014-08-03 23:02:53 -0400391 labelRunChoiceTitle = Label(frameRun, text='At Startup')
392 radioStartupEdit = Radiobutton(
393 frameRun, variable=self.startupEdit, value=1,
394 command=self.SetKeysType, text="Open Edit Window")
395 radioStartupShell = Radiobutton(
396 frameRun, variable=self.startupEdit, value=0,
397 command=self.SetKeysType, text='Open Shell Window')
Kurt B. Kaiser6c638b62003-05-26 06:23:10 +0000398 #frameSave
Terry Jan Reedyae410862014-08-03 23:02:53 -0400399 labelRunSaveTitle = Label(frameSave, text='At Start of Run (F5) ')
400 radioSaveAsk = Radiobutton(
401 frameSave, variable=self.autoSave, value=0,
402 command=self.SetKeysType, text="Prompt to Save")
403 radioSaveAuto = Radiobutton(
404 frameSave, variable=self.autoSave, value=1,
405 command=self.SetKeysType, text='No Prompt')
Steven M. Gava230e5782001-08-07 03:28:25 +0000406 #frameWinSize
Terry Jan Reedyae410862014-08-03 23:02:53 -0400407 labelWinSizeTitle = Label(
408 frameWinSize, text='Initial Window Size (in characters)')
409 labelWinWidthTitle = Label(frameWinSize, text='Width')
410 entryWinWidth = Entry(
411 frameWinSize, textvariable=self.winWidth, width=3)
412 labelWinHeightTitle = Label(frameWinSize, text='Height')
413 entryWinHeight = Entry(
414 frameWinSize, textvariable=self.winHeight, width=3)
Kurt B. Kaisera053f332003-05-10 00:49:56 +0000415 #frameEncoding
Terry Jan Reedyae410862014-08-03 23:02:53 -0400416 labelEncodingTitle = Label(
417 frameEncoding, text="Default Source Encoding")
418 radioEncLocale = Radiobutton(
419 frameEncoding, variable=self.encoding,
420 value="locale", text="Locale-defined")
421 radioEncUTF8 = Radiobutton(
422 frameEncoding, variable=self.encoding,
423 value="utf-8", text="UTF-8")
424 radioEncNone = Radiobutton(
425 frameEncoding, variable=self.encoding,
426 value="none", text="None")
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000427 #frameHelp
Terry Jan Reedyae410862014-08-03 23:02:53 -0400428 frameHelpList = Frame(frameHelp)
429 frameHelpListButtons = Frame(frameHelpList)
430 scrollHelpList = Scrollbar(frameHelpList)
431 self.listHelp = Listbox(
432 frameHelpList, height=5, takefocus=FALSE,
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000433 exportselection=FALSE)
434 scrollHelpList.config(command=self.listHelp.yview)
435 self.listHelp.config(yscrollcommand=scrollHelpList.set)
Terry Jan Reedyae410862014-08-03 23:02:53 -0400436 self.listHelp.bind('<ButtonRelease-1>', self.HelpSourceSelected)
437 self.buttonHelpListEdit = Button(
438 frameHelpListButtons, text='Edit', state=DISABLED,
439 width=8, command=self.HelpListItemEdit)
440 self.buttonHelpListAdd = Button(
441 frameHelpListButtons, text='Add',
442 width=8, command=self.HelpListItemAdd)
443 self.buttonHelpListRemove = Button(
444 frameHelpListButtons, text='Remove', state=DISABLED,
445 width=8, command=self.HelpListItemRemove)
Terry Jan Reedy19b7a752014-07-30 19:24:26 -0400446
Steven M. Gava230e5782001-08-07 03:28:25 +0000447 #widget packing
448 #body
Terry Jan Reedyae410862014-08-03 23:02:53 -0400449 frameRun.pack(side=TOP, padx=5, pady=5, fill=X)
450 frameSave.pack(side=TOP, padx=5, pady=5, fill=X)
451 frameWinSize.pack(side=TOP, padx=5, pady=5, fill=X)
Terry Jan Reedyae410862014-08-03 23:02:53 -0400452 frameEncoding.pack(side=TOP, padx=5, pady=5, fill=X)
453 frameHelp.pack(side=TOP, padx=5, pady=5, expand=TRUE, fill=BOTH)
Steven M. Gava230e5782001-08-07 03:28:25 +0000454 #frameRun
Terry Jan Reedyae410862014-08-03 23:02:53 -0400455 labelRunChoiceTitle.pack(side=LEFT, anchor=W, padx=5, pady=5)
456 radioStartupShell.pack(side=RIGHT, anchor=W, padx=5, pady=5)
457 radioStartupEdit.pack(side=RIGHT, anchor=W, padx=5, pady=5)
Kurt B. Kaiser6c638b62003-05-26 06:23:10 +0000458 #frameSave
Terry Jan Reedyae410862014-08-03 23:02:53 -0400459 labelRunSaveTitle.pack(side=LEFT, anchor=W, padx=5, pady=5)
460 radioSaveAuto.pack(side=RIGHT, anchor=W, padx=5, pady=5)
461 radioSaveAsk.pack(side=RIGHT, anchor=W, padx=5, pady=5)
Steven M. Gava230e5782001-08-07 03:28:25 +0000462 #frameWinSize
Terry Jan Reedyae410862014-08-03 23:02:53 -0400463 labelWinSizeTitle.pack(side=LEFT, anchor=W, padx=5, pady=5)
464 entryWinHeight.pack(side=RIGHT, anchor=E, padx=10, pady=5)
465 labelWinHeightTitle.pack(side=RIGHT, anchor=E, pady=5)
466 entryWinWidth.pack(side=RIGHT, anchor=E, padx=10, pady=5)
467 labelWinWidthTitle.pack(side=RIGHT, anchor=E, pady=5)
Kurt B. Kaisera053f332003-05-10 00:49:56 +0000468 #frameEncoding
Terry Jan Reedyae410862014-08-03 23:02:53 -0400469 labelEncodingTitle.pack(side=LEFT, anchor=W, padx=5, pady=5)
470 radioEncNone.pack(side=RIGHT, anchor=E, pady=5)
471 radioEncUTF8.pack(side=RIGHT, anchor=E, pady=5)
472 radioEncLocale.pack(side=RIGHT, anchor=E, pady=5)
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000473 #frameHelp
Terry Jan Reedyae410862014-08-03 23:02:53 -0400474 frameHelpListButtons.pack(side=RIGHT, padx=5, pady=5, fill=Y)
475 frameHelpList.pack(side=TOP, padx=5, pady=5, expand=TRUE, fill=BOTH)
476 scrollHelpList.pack(side=RIGHT, anchor=W, fill=Y)
477 self.listHelp.pack(side=LEFT, anchor=E, expand=TRUE, fill=BOTH)
478 self.buttonHelpListEdit.pack(side=TOP, anchor=W, pady=5)
479 self.buttonHelpListAdd.pack(side=TOP, anchor=W)
480 self.buttonHelpListRemove.pack(side=TOP, anchor=W, pady=5)
Steven M. Gava952d0a52001-08-03 04:43:44 +0000481 return frame
482
Steven M. Gavac112cd82002-01-22 05:56:40 +0000483 def AttachVarCallbacks(self):
Terry Jan Reedy12352142015-08-01 18:57:27 -0400484 self.fontSize.trace_variable('w', self.VarChanged_font)
485 self.fontName.trace_variable('w', self.VarChanged_font)
486 self.fontBold.trace_variable('w', self.VarChanged_font)
Terry Jan Reedyae410862014-08-03 23:02:53 -0400487 self.spaceNum.trace_variable('w', self.VarChanged_spaceNum)
488 self.colour.trace_variable('w', self.VarChanged_colour)
489 self.builtinTheme.trace_variable('w', self.VarChanged_builtinTheme)
490 self.customTheme.trace_variable('w', self.VarChanged_customTheme)
491 self.themeIsBuiltin.trace_variable('w', self.VarChanged_themeIsBuiltin)
492 self.highlightTarget.trace_variable('w', self.VarChanged_highlightTarget)
493 self.keyBinding.trace_variable('w', self.VarChanged_keyBinding)
494 self.builtinKeys.trace_variable('w', self.VarChanged_builtinKeys)
495 self.customKeys.trace_variable('w', self.VarChanged_customKeys)
496 self.keysAreBuiltin.trace_variable('w', self.VarChanged_keysAreBuiltin)
497 self.winWidth.trace_variable('w', self.VarChanged_winWidth)
498 self.winHeight.trace_variable('w', self.VarChanged_winHeight)
Terry Jan Reedyae410862014-08-03 23:02:53 -0400499 self.startupEdit.trace_variable('w', self.VarChanged_startupEdit)
500 self.autoSave.trace_variable('w', self.VarChanged_autoSave)
501 self.encoding.trace_variable('w', self.VarChanged_encoding)
Steven M. Gava052937f2002-02-11 02:20:53 +0000502
Terry Jan Reedy12352142015-08-01 18:57:27 -0400503 def VarChanged_font(self, *params):
504 '''When one font attribute changes, save them all, as they are
505 not independent from each other. In particular, when we are
506 overriding the default font, we need to write out everything.
507 '''
Terry Jan Reedyae410862014-08-03 23:02:53 -0400508 value = self.fontName.get()
509 self.AddChangedItem('main', 'EditorWindow', 'font', value)
Terry Jan Reedy12352142015-08-01 18:57:27 -0400510 value = self.fontSize.get()
511 self.AddChangedItem('main', 'EditorWindow', 'font-size', value)
Terry Jan Reedyae410862014-08-03 23:02:53 -0400512 value = self.fontBold.get()
513 self.AddChangedItem('main', 'EditorWindow', 'font-bold', value)
Steven M. Gavac112cd82002-01-22 05:56:40 +0000514
Terry Jan Reedyae410862014-08-03 23:02:53 -0400515 def VarChanged_spaceNum(self, *params):
516 value = self.spaceNum.get()
517 self.AddChangedItem('main', 'Indent', 'num-spaces', value)
Steven M. Gavac112cd82002-01-22 05:56:40 +0000518
Terry Jan Reedyae410862014-08-03 23:02:53 -0400519 def VarChanged_colour(self, *params):
Steven M. Gava052937f2002-02-11 02:20:53 +0000520 self.OnNewColourSet()
521
Terry Jan Reedyae410862014-08-03 23:02:53 -0400522 def VarChanged_builtinTheme(self, *params):
523 value = self.builtinTheme.get()
Terry Jan Reedy9f37eae2015-10-04 00:30:59 -0400524 if value == 'IDLE Dark':
Terry Jan Reedy35aa5d02015-11-12 15:02:50 -0500525 if idleConf.GetOption('main', 'Theme', 'name') != 'IDLE New':
526 self.AddChangedItem('main', 'Theme', 'name', 'IDLE Classic')
527 self.AddChangedItem('main', 'Theme', 'name2', value)
528 self.new_custom_theme.config(text='New theme, see Help',
529 fg='#500000')
530 else:
531 self.AddChangedItem('main', 'Theme', 'name', value)
532 self.AddChangedItem('main', 'Theme', 'name2', '')
533 self.new_custom_theme.config(text='', fg='black')
Steven M. Gava052937f2002-02-11 02:20:53 +0000534 self.PaintThemeSample()
535
Terry Jan Reedyae410862014-08-03 23:02:53 -0400536 def VarChanged_customTheme(self, *params):
537 value = self.customTheme.get()
Steven M. Gava49745752002-02-18 01:43:11 +0000538 if value != '- no custom themes -':
Terry Jan Reedyae410862014-08-03 23:02:53 -0400539 self.AddChangedItem('main', 'Theme', 'name', value)
Steven M. Gava49745752002-02-18 01:43:11 +0000540 self.PaintThemeSample()
Steven M. Gava052937f2002-02-11 02:20:53 +0000541
Terry Jan Reedyae410862014-08-03 23:02:53 -0400542 def VarChanged_themeIsBuiltin(self, *params):
543 value = self.themeIsBuiltin.get()
544 self.AddChangedItem('main', 'Theme', 'default', value)
Steven M. Gavaf31eec02002-03-05 00:25:58 +0000545 if value:
546 self.VarChanged_builtinTheme()
547 else:
548 self.VarChanged_customTheme()
Steven M. Gava052937f2002-02-11 02:20:53 +0000549
Terry Jan Reedyae410862014-08-03 23:02:53 -0400550 def VarChanged_highlightTarget(self, *params):
Steven M. Gava052937f2002-02-11 02:20:53 +0000551 self.SetHighlightTarget()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000552
Terry Jan Reedyae410862014-08-03 23:02:53 -0400553 def VarChanged_keyBinding(self, *params):
554 value = self.keyBinding.get()
555 keySet = self.customKeys.get()
556 event = self.listBindings.get(ANCHOR).split()[0]
Steven M. Gavaa498af22002-02-01 01:33:36 +0000557 if idleConf.IsCoreBinding(event):
558 #this is a core keybinding
Terry Jan Reedyae410862014-08-03 23:02:53 -0400559 self.AddChangedItem('keys', keySet, event, value)
Steven M. Gavaa498af22002-02-01 01:33:36 +0000560 else: #this is an extension key binding
Terry Jan Reedyae410862014-08-03 23:02:53 -0400561 extName = idleConf.GetExtnNameForEvent(event)
562 extKeybindSection = extName + '_cfgBindings'
563 self.AddChangedItem('extensions', extKeybindSection, event, value)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000564
Terry Jan Reedyae410862014-08-03 23:02:53 -0400565 def VarChanged_builtinKeys(self, *params):
566 value = self.builtinKeys.get()
567 self.AddChangedItem('main', 'Keys', 'name', value)
Steven M. Gava052937f2002-02-11 02:20:53 +0000568 self.LoadKeysList(value)
569
Terry Jan Reedyae410862014-08-03 23:02:53 -0400570 def VarChanged_customKeys(self, *params):
571 value = self.customKeys.get()
Steven M. Gava49745752002-02-18 01:43:11 +0000572 if value != '- no custom keys -':
Terry Jan Reedyae410862014-08-03 23:02:53 -0400573 self.AddChangedItem('main', 'Keys', 'name', value)
Steven M. Gava49745752002-02-18 01:43:11 +0000574 self.LoadKeysList(value)
Steven M. Gava052937f2002-02-11 02:20:53 +0000575
Terry Jan Reedyae410862014-08-03 23:02:53 -0400576 def VarChanged_keysAreBuiltin(self, *params):
577 value = self.keysAreBuiltin.get()
578 self.AddChangedItem('main', 'Keys', 'default', value)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000579 if value:
Steven M. Gavaf31eec02002-03-05 00:25:58 +0000580 self.VarChanged_builtinKeys()
Steven M. Gava052937f2002-02-11 02:20:53 +0000581 else:
Steven M. Gavaf31eec02002-03-05 00:25:58 +0000582 self.VarChanged_customKeys()
Steven M. Gava052937f2002-02-11 02:20:53 +0000583
Terry Jan Reedyae410862014-08-03 23:02:53 -0400584 def VarChanged_winWidth(self, *params):
585 value = self.winWidth.get()
586 self.AddChangedItem('main', 'EditorWindow', 'width', value)
Steven M. Gavac112cd82002-01-22 05:56:40 +0000587
Terry Jan Reedyae410862014-08-03 23:02:53 -0400588 def VarChanged_winHeight(self, *params):
589 value = self.winHeight.get()
590 self.AddChangedItem('main', 'EditorWindow', 'height', value)
Steven M. Gavac112cd82002-01-22 05:56:40 +0000591
Terry Jan Reedyae410862014-08-03 23:02:53 -0400592 def VarChanged_startupEdit(self, *params):
593 value = self.startupEdit.get()
594 self.AddChangedItem('main', 'General', 'editor-on-startup', value)
Steven M. Gavac112cd82002-01-22 05:56:40 +0000595
Terry Jan Reedyae410862014-08-03 23:02:53 -0400596 def VarChanged_autoSave(self, *params):
597 value = self.autoSave.get()
598 self.AddChangedItem('main', 'General', 'autosave', value)
Kurt B. Kaiser6c638b62003-05-26 06:23:10 +0000599
Terry Jan Reedyae410862014-08-03 23:02:53 -0400600 def VarChanged_encoding(self, *params):
601 value = self.encoding.get()
602 self.AddChangedItem('main', 'EditorWindow', 'encoding', value)
Kurt B. Kaisera053f332003-05-10 00:49:56 +0000603
Steven M. Gavaa498af22002-02-01 01:33:36 +0000604 def ResetChangedItems(self):
Steven M. Gavab77d3432002-03-02 07:16:21 +0000605 #When any config item is changed in this dialog, an entry
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000606 #should be made in the relevant section (config type) of this
607 #dictionary. The key should be the config file section name and the
Steven M. Gavaa498af22002-02-01 01:33:36 +0000608 #value a dictionary, whose key:value pairs are item=value pairs for
609 #that config file section.
Terry Jan Reedyae410862014-08-03 23:02:53 -0400610 self.changedItems = {'main':{}, 'highlight':{}, 'keys':{},
611 'extensions':{}}
Steven M. Gavaa498af22002-02-01 01:33:36 +0000612
Terry Jan Reedyae410862014-08-03 23:02:53 -0400613 def AddChangedItem(self, typ, section, item, value):
614 value = str(value) #make sure we use a string
615 if section not in self.changedItems[typ]:
616 self.changedItems[typ][section] = {}
617 self.changedItems[typ][section][item] = value
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000618
Steven M. Gava5f28e8f2002-01-21 06:38:21 +0000619 def GetDefaultItems(self):
Terry Jan Reedyae410862014-08-03 23:02:53 -0400620 dItems={'main':{}, 'highlight':{}, 'keys':{}, 'extensions':{}}
Terry Jan Reedy110796f2014-07-27 04:07:18 -0400621 for configType in dItems:
Terry Jan Reedyae410862014-08-03 23:02:53 -0400622 sections = idleConf.GetSectionList('default', configType)
Steven M. Gava5f28e8f2002-01-21 06:38:21 +0000623 for section in sections:
Terry Jan Reedyae410862014-08-03 23:02:53 -0400624 dItems[configType][section] = {}
625 options = idleConf.defaultCfg[configType].GetOptionList(section)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000626 for option in options:
Terry Jan Reedyae410862014-08-03 23:02:53 -0400627 dItems[configType][section][option] = (
628 idleConf.defaultCfg[configType].Get(section, option))
Steven M. Gava5f28e8f2002-01-21 06:38:21 +0000629 return dItems
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000630
Steven M. Gava5f28e8f2002-01-21 06:38:21 +0000631 def SetThemeType(self):
632 if self.themeIsBuiltin.get():
633 self.optMenuThemeBuiltin.config(state=NORMAL)
634 self.optMenuThemeCustom.config(state=DISABLED)
635 self.buttonDeleteCustomTheme.config(state=DISABLED)
636 else:
637 self.optMenuThemeBuiltin.config(state=DISABLED)
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000638 self.radioThemeCustom.config(state=NORMAL)
Steven M. Gava5f28e8f2002-01-21 06:38:21 +0000639 self.optMenuThemeCustom.config(state=NORMAL)
640 self.buttonDeleteCustomTheme.config(state=NORMAL)
641
642 def SetKeysType(self):
Steven M. Gava052937f2002-02-11 02:20:53 +0000643 if self.keysAreBuiltin.get():
Steven M. Gava5f28e8f2002-01-21 06:38:21 +0000644 self.optMenuKeysBuiltin.config(state=NORMAL)
645 self.optMenuKeysCustom.config(state=DISABLED)
646 self.buttonDeleteCustomKeys.config(state=DISABLED)
647 else:
648 self.optMenuKeysBuiltin.config(state=DISABLED)
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000649 self.radioKeysCustom.config(state=NORMAL)
Steven M. Gava5f28e8f2002-01-21 06:38:21 +0000650 self.optMenuKeysCustom.config(state=NORMAL)
651 self.buttonDeleteCustomKeys.config(state=NORMAL)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000652
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000653 def GetNewKeys(self):
Terry Jan Reedyae410862014-08-03 23:02:53 -0400654 listIndex = self.listBindings.index(ANCHOR)
655 binding = self.listBindings.get(listIndex)
656 bindName = binding.split()[0] #first part, up to first space
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000657 if self.keysAreBuiltin.get():
Terry Jan Reedyae410862014-08-03 23:02:53 -0400658 currentKeySetName = self.builtinKeys.get()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000659 else:
Terry Jan Reedyae410862014-08-03 23:02:53 -0400660 currentKeySetName = self.customKeys.get()
661 currentBindings = idleConf.GetCurrentKeySet()
Terry Jan Reedy110796f2014-07-27 04:07:18 -0400662 if currentKeySetName in self.changedItems['keys']: #unsaved changes
Terry Jan Reedyae410862014-08-03 23:02:53 -0400663 keySetChanges = self.changedItems['keys'][currentKeySetName]
Terry Jan Reedy110796f2014-07-27 04:07:18 -0400664 for event in keySetChanges:
Terry Jan Reedyae410862014-08-03 23:02:53 -0400665 currentBindings[event] = keySetChanges[event].split()
666 currentKeySequences = currentBindings.values()
667 newKeys = GetKeysDialog(self, 'Get New Keys', bindName,
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000668 currentKeySequences).result
669 if newKeys: #new keys were specified
Steven M. Gava052937f2002-02-11 02:20:53 +0000670 if self.keysAreBuiltin.get(): #current key set is a built-in
Terry Jan Reedyae410862014-08-03 23:02:53 -0400671 message = ('Your changes will be saved as a new Custom Key Set.'
672 ' Enter a name for your new Custom Key Set below.')
673 newKeySet = self.GetNewKeysName(message)
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000674 if not newKeySet: #user cancelled custom key set creation
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000675 self.listBindings.select_set(listIndex)
676 self.listBindings.select_anchor(listIndex)
677 return
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000678 else: #create new custom key set based on previously active key set
679 self.CreateNewKeySet(newKeySet)
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000680 self.listBindings.delete(listIndex)
Terry Jan Reedyae410862014-08-03 23:02:53 -0400681 self.listBindings.insert(listIndex, bindName+' - '+newKeys)
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000682 self.listBindings.select_set(listIndex)
683 self.listBindings.select_anchor(listIndex)
Steven M. Gava052937f2002-02-11 02:20:53 +0000684 self.keyBinding.set(newKeys)
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000685 else:
686 self.listBindings.select_set(listIndex)
687 self.listBindings.select_anchor(listIndex)
688
Terry Jan Reedyae410862014-08-03 23:02:53 -0400689 def GetNewKeysName(self, message):
690 usedNames = (idleConf.GetSectionList('user', 'keys') +
691 idleConf.GetSectionList('default', 'keys'))
692 newKeySet = GetCfgSectionNameDialog(
693 self, 'New Custom Key Set', message, usedNames).result
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000694 return newKeySet
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000695
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000696 def SaveAsNewKeySet(self):
Terry Jan Reedyae410862014-08-03 23:02:53 -0400697 newKeysName = self.GetNewKeysName('New Key Set Name:')
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000698 if newKeysName:
699 self.CreateNewKeySet(newKeysName)
700
Terry Jan Reedyae410862014-08-03 23:02:53 -0400701 def KeyBindingSelected(self, event):
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000702 self.buttonNewKeys.config(state=NORMAL)
703
Terry Jan Reedyae410862014-08-03 23:02:53 -0400704 def CreateNewKeySet(self, newKeySetName):
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000705 #creates new custom key set based on the previously active key set,
706 #and makes the new key set active
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000707 if self.keysAreBuiltin.get():
Terry Jan Reedyae410862014-08-03 23:02:53 -0400708 prevKeySetName = self.builtinKeys.get()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000709 else:
Terry Jan Reedyae410862014-08-03 23:02:53 -0400710 prevKeySetName = self.customKeys.get()
711 prevKeys = idleConf.GetCoreKeys(prevKeySetName)
712 newKeys = {}
Terry Jan Reedy110796f2014-07-27 04:07:18 -0400713 for event in prevKeys: #add key set to changed items
Terry Jan Reedyae410862014-08-03 23:02:53 -0400714 eventName = event[2:-2] #trim off the angle brackets
715 binding = ' '.join(prevKeys[event])
716 newKeys[eventName] = binding
Steven M. Gava052937f2002-02-11 02:20:53 +0000717 #handle any unsaved changes to prev key set
Terry Jan Reedy110796f2014-07-27 04:07:18 -0400718 if prevKeySetName in self.changedItems['keys']:
Terry Jan Reedyae410862014-08-03 23:02:53 -0400719 keySetChanges = self.changedItems['keys'][prevKeySetName]
Terry Jan Reedy110796f2014-07-27 04:07:18 -0400720 for event in keySetChanges:
Terry Jan Reedyae410862014-08-03 23:02:53 -0400721 newKeys[event] = keySetChanges[event]
Steven M. Gava052937f2002-02-11 02:20:53 +0000722 #save the new theme
Terry Jan Reedyae410862014-08-03 23:02:53 -0400723 self.SaveNewKeySet(newKeySetName, newKeys)
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000724 #change gui over to the new key set
Terry Jan Reedyae410862014-08-03 23:02:53 -0400725 customKeyList = idleConf.GetSectionList('user', 'keys')
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000726 customKeyList.sort()
Terry Jan Reedyae410862014-08-03 23:02:53 -0400727 self.optMenuKeysCustom.SetMenu(customKeyList, newKeySetName)
Steven M. Gava052937f2002-02-11 02:20:53 +0000728 self.keysAreBuiltin.set(0)
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000729 self.SetKeysType()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000730
Terry Jan Reedyae410862014-08-03 23:02:53 -0400731 def LoadKeysList(self, keySetName):
732 reselect = 0
733 newKeySet = 0
Steven M. Gava052937f2002-02-11 02:20:53 +0000734 if self.listBindings.curselection():
Terry Jan Reedyae410862014-08-03 23:02:53 -0400735 reselect = 1
736 listIndex = self.listBindings.index(ANCHOR)
737 keySet = idleConf.GetKeySet(keySetName)
738 bindNames = keySet.keys()
Steven M. Gava052937f2002-02-11 02:20:53 +0000739 bindNames.sort()
Terry Jan Reedyae410862014-08-03 23:02:53 -0400740 self.listBindings.delete(0, END)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000741 for bindName in bindNames:
Terry Jan Reedyae410862014-08-03 23:02:53 -0400742 key = ' '.join(keySet[bindName]) #make key(s) into a string
743 bindName = bindName[2:-2] #trim off the angle brackets
Terry Jan Reedy110796f2014-07-27 04:07:18 -0400744 if keySetName in self.changedItems['keys']:
Steven M. Gava052937f2002-02-11 02:20:53 +0000745 #handle any unsaved changes to this key set
Terry Jan Reedy110796f2014-07-27 04:07:18 -0400746 if bindName in self.changedItems['keys'][keySetName]:
Terry Jan Reedyae410862014-08-03 23:02:53 -0400747 key = self.changedItems['keys'][keySetName][bindName]
Steven M. Gava052937f2002-02-11 02:20:53 +0000748 self.listBindings.insert(END, bindName+' - '+key)
Steven M. Gava052937f2002-02-11 02:20:53 +0000749 if reselect:
750 self.listBindings.see(listIndex)
751 self.listBindings.select_set(listIndex)
752 self.listBindings.select_anchor(listIndex)
753
Steven M. Gava49745752002-02-18 01:43:11 +0000754 def DeleteCustomKeys(self):
755 keySetName=self.customKeys.get()
Terry Jan Reedyae410862014-08-03 23:02:53 -0400756 delmsg = 'Are you sure you wish to delete the key set %r ?'
757 if not tkMessageBox.askyesno(
758 'Delete Key Set', delmsg % keySetName, parent=self):
Steven M. Gava49745752002-02-18 01:43:11 +0000759 return
760 #remove key set from config
761 idleConf.userCfg['keys'].remove_section(keySetName)
Benjamin Peterson6e3dbbd2009-10-09 22:15:50 +0000762 if keySetName in self.changedItems['keys']:
Steven M. Gava49745752002-02-18 01:43:11 +0000763 del(self.changedItems['keys'][keySetName])
764 #write changes
765 idleConf.userCfg['keys'].Save()
766 #reload user key set list
Terry Jan Reedyae410862014-08-03 23:02:53 -0400767 itemList = idleConf.GetSectionList('user', 'keys')
Steven M. Gava49745752002-02-18 01:43:11 +0000768 itemList.sort()
769 if not itemList:
770 self.radioKeysCustom.config(state=DISABLED)
Terry Jan Reedyae410862014-08-03 23:02:53 -0400771 self.optMenuKeysCustom.SetMenu(itemList, '- no custom keys -')
Steven M. Gava49745752002-02-18 01:43:11 +0000772 else:
Terry Jan Reedyae410862014-08-03 23:02:53 -0400773 self.optMenuKeysCustom.SetMenu(itemList, itemList[0])
Steven M. Gava49745752002-02-18 01:43:11 +0000774 #revert to default key set
Terry Jan Reedyae410862014-08-03 23:02:53 -0400775 self.keysAreBuiltin.set(idleConf.defaultCfg['main'].Get('Keys', 'default'))
776 self.builtinKeys.set(idleConf.defaultCfg['main'].Get('Keys', 'name'))
Steven M. Gava49745752002-02-18 01:43:11 +0000777 #user can't back out of these changes, they must be applied now
778 self.Apply()
779 self.SetKeysType()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000780
Steven M. Gava49745752002-02-18 01:43:11 +0000781 def DeleteCustomTheme(self):
Terry Jan Reedyae410862014-08-03 23:02:53 -0400782 themeName = self.customTheme.get()
783 delmsg = 'Are you sure you wish to delete the theme %r ?'
784 if not tkMessageBox.askyesno(
785 'Delete Theme', delmsg % themeName, parent=self):
Steven M. Gava49745752002-02-18 01:43:11 +0000786 return
787 #remove theme from config
788 idleConf.userCfg['highlight'].remove_section(themeName)
Benjamin Peterson6e3dbbd2009-10-09 22:15:50 +0000789 if themeName in self.changedItems['highlight']:
Steven M. Gava49745752002-02-18 01:43:11 +0000790 del(self.changedItems['highlight'][themeName])
791 #write changes
792 idleConf.userCfg['highlight'].Save()
793 #reload user theme list
Terry Jan Reedyae410862014-08-03 23:02:53 -0400794 itemList = idleConf.GetSectionList('user', 'highlight')
Steven M. Gava49745752002-02-18 01:43:11 +0000795 itemList.sort()
796 if not itemList:
797 self.radioThemeCustom.config(state=DISABLED)
Terry Jan Reedyae410862014-08-03 23:02:53 -0400798 self.optMenuThemeCustom.SetMenu(itemList, '- no custom themes -')
Steven M. Gava49745752002-02-18 01:43:11 +0000799 else:
Terry Jan Reedyae410862014-08-03 23:02:53 -0400800 self.optMenuThemeCustom.SetMenu(itemList, itemList[0])
Steven M. Gava49745752002-02-18 01:43:11 +0000801 #revert to default theme
Terry Jan Reedyae410862014-08-03 23:02:53 -0400802 self.themeIsBuiltin.set(idleConf.defaultCfg['main'].Get('Theme', 'default'))
803 self.builtinTheme.set(idleConf.defaultCfg['main'].Get('Theme', 'name'))
Steven M. Gava49745752002-02-18 01:43:11 +0000804 #user can't back out of these changes, they must be applied now
805 self.Apply()
806 self.SetThemeType()
807
Steven M. Gava5f28e8f2002-01-21 06:38:21 +0000808 def GetColour(self):
Terry Jan Reedyae410862014-08-03 23:02:53 -0400809 target = self.highlightTarget.get()
810 prevColour = self.frameColourSet.cget('bg')
811 rgbTuplet, colourString = tkColorChooser.askcolor(
812 parent=self, title='Pick new colour for : '+target,
813 initialcolor=prevColour)
814 if colourString and (colourString != prevColour):
Steven M. Gava052937f2002-02-11 02:20:53 +0000815 #user didn't cancel, and they chose a new colour
Terry Jan Reedyae410862014-08-03 23:02:53 -0400816 if self.themeIsBuiltin.get(): #current theme is a built-in
817 message = ('Your changes will be saved as a new Custom Theme. '
818 'Enter a name for your new Custom Theme below.')
819 newTheme = self.GetNewThemeName(message)
820 if not newTheme: #user cancelled custom theme creation
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000821 return
Terry Jan Reedyae410862014-08-03 23:02:53 -0400822 else: #create new custom theme based on previously active theme
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000823 self.CreateNewTheme(newTheme)
Steven M. Gava052937f2002-02-11 02:20:53 +0000824 self.colour.set(colourString)
Terry Jan Reedyae410862014-08-03 23:02:53 -0400825 else: #current theme is user defined
Steven M. Gava052937f2002-02-11 02:20:53 +0000826 self.colour.set(colourString)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000827
Steven M. Gava052937f2002-02-11 02:20:53 +0000828 def OnNewColourSet(self):
829 newColour=self.colour.get()
Terry Jan Reedyae410862014-08-03 23:02:53 -0400830 self.frameColourSet.config(bg=newColour) #set sample
831 plane ='foreground' if self.fgHilite.get() else 'background'
832 sampleElement = self.themeElements[self.highlightTarget.get()][0]
Raymond Hettinger931237e2003-07-09 18:48:24 +0000833 self.textHighlightSample.tag_config(sampleElement, **{plane:newColour})
Terry Jan Reedyae410862014-08-03 23:02:53 -0400834 theme = self.customTheme.get()
835 themeElement = sampleElement + '-' + plane
836 self.AddChangedItem('highlight', theme, themeElement, newColour)
Steven M. Gava052937f2002-02-11 02:20:53 +0000837
Terry Jan Reedyae410862014-08-03 23:02:53 -0400838 def GetNewThemeName(self, message):
839 usedNames = (idleConf.GetSectionList('user', 'highlight') +
840 idleConf.GetSectionList('default', 'highlight'))
841 newTheme = GetCfgSectionNameDialog(
842 self, 'New Custom Theme', message, usedNames).result
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000843 return newTheme
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000844
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000845 def SaveAsNewTheme(self):
Terry Jan Reedyae410862014-08-03 23:02:53 -0400846 newThemeName = self.GetNewThemeName('New Theme Name:')
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000847 if newThemeName:
848 self.CreateNewTheme(newThemeName)
849
Terry Jan Reedyae410862014-08-03 23:02:53 -0400850 def CreateNewTheme(self, newThemeName):
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000851 #creates new custom theme based on the previously active theme,
852 #and makes the new theme active
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000853 if self.themeIsBuiltin.get():
Terry Jan Reedyae410862014-08-03 23:02:53 -0400854 themeType = 'default'
855 themeName = self.builtinTheme.get()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000856 else:
Terry Jan Reedyae410862014-08-03 23:02:53 -0400857 themeType = 'user'
858 themeName = self.customTheme.get()
859 newTheme = idleConf.GetThemeDict(themeType, themeName)
Steven M. Gava052937f2002-02-11 02:20:53 +0000860 #apply any of the old theme's unsaved changes to the new theme
Terry Jan Reedy110796f2014-07-27 04:07:18 -0400861 if themeName in self.changedItems['highlight']:
Terry Jan Reedyae410862014-08-03 23:02:53 -0400862 themeChanges = self.changedItems['highlight'][themeName]
Terry Jan Reedy110796f2014-07-27 04:07:18 -0400863 for element in themeChanges:
Terry Jan Reedyae410862014-08-03 23:02:53 -0400864 newTheme[element] = themeChanges[element]
Steven M. Gava052937f2002-02-11 02:20:53 +0000865 #save the new theme
Terry Jan Reedyae410862014-08-03 23:02:53 -0400866 self.SaveNewTheme(newThemeName, newTheme)
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000867 #change gui over to the new theme
Terry Jan Reedyae410862014-08-03 23:02:53 -0400868 customThemeList = idleConf.GetSectionList('user', 'highlight')
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000869 customThemeList.sort()
Terry Jan Reedyae410862014-08-03 23:02:53 -0400870 self.optMenuThemeCustom.SetMenu(customThemeList, newThemeName)
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000871 self.themeIsBuiltin.set(0)
872 self.SetThemeType()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000873
Terry Jan Reedyae410862014-08-03 23:02:53 -0400874 def OnListFontButtonRelease(self, event):
Kurt B. Kaiser05391692003-05-26 20:35:53 +0000875 font = self.listFontName.get(ANCHOR)
876 self.fontName.set(font.lower())
Steven M. Gava5f28e8f2002-01-21 06:38:21 +0000877 self.SetFontSample()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000878
Terry Jan Reedyae410862014-08-03 23:02:53 -0400879 def SetFontSample(self, event=None):
880 fontName = self.fontName.get()
881 fontWeight = tkFont.BOLD if self.fontBold.get() else tkFont.NORMAL
Ned Deilye3d47122012-10-22 15:13:01 -0700882 newFont = (fontName, self.fontSize.get(), fontWeight)
883 self.labelFontSample.config(font=newFont)
884 self.textHighlightSample.configure(font=newFont)
Steven M. Gava5f28e8f2002-01-21 06:38:21 +0000885
Steven M. Gava5f28e8f2002-01-21 06:38:21 +0000886 def SetHighlightTarget(self):
Terry Jan Reedyae410862014-08-03 23:02:53 -0400887 if self.highlightTarget.get() == 'Cursor': #bg not possible
Steven M. Gava5f28e8f2002-01-21 06:38:21 +0000888 self.radioFg.config(state=DISABLED)
889 self.radioBg.config(state=DISABLED)
890 self.fgHilite.set(1)
Terry Jan Reedyae410862014-08-03 23:02:53 -0400891 else: #both fg and bg can be set
Steven M. Gava5f28e8f2002-01-21 06:38:21 +0000892 self.radioFg.config(state=NORMAL)
893 self.radioBg.config(state=NORMAL)
894 self.fgHilite.set(1)
895 self.SetColourSample()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000896
Terry Jan Reedyae410862014-08-03 23:02:53 -0400897 def SetColourSampleBinding(self, *args):
Steven M. Gava5f28e8f2002-01-21 06:38:21 +0000898 self.SetColourSample()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000899
Steven M. Gava5f28e8f2002-01-21 06:38:21 +0000900 def SetColourSample(self):
901 #set the colour smaple area
Terry Jan Reedyae410862014-08-03 23:02:53 -0400902 tag = self.themeElements[self.highlightTarget.get()][0]
903 plane = 'foreground' if self.fgHilite.get() else 'background'
904 colour = self.textHighlightSample.tag_cget(tag, plane)
Steven M. Gava5f28e8f2002-01-21 06:38:21 +0000905 self.frameColourSet.config(bg=colour)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000906
Steven M. Gava9dd16b32001-11-03 14:54:25 +0000907 def PaintThemeSample(self):
Terry Jan Reedyae410862014-08-03 23:02:53 -0400908 if self.themeIsBuiltin.get(): #a default theme
909 theme = self.builtinTheme.get()
910 else: #a user theme
911 theme = self.customTheme.get()
Terry Jan Reedy110796f2014-07-27 04:07:18 -0400912 for elementTitle in self.themeElements:
Terry Jan Reedyae410862014-08-03 23:02:53 -0400913 element = self.themeElements[elementTitle][0]
914 colours = idleConf.GetHighlight(theme, element)
915 if element == 'cursor': #cursor sample needs special painting
916 colours['background'] = idleConf.GetHighlight(
917 theme, 'normal', fgBg='bg')
Steven M. Gava052937f2002-02-11 02:20:53 +0000918 #handle any unsaved changes to this theme
Terry Jan Reedy110796f2014-07-27 04:07:18 -0400919 if theme in self.changedItems['highlight']:
Terry Jan Reedyae410862014-08-03 23:02:53 -0400920 themeDict = self.changedItems['highlight'][theme]
921 if element + '-foreground' in themeDict:
922 colours['foreground'] = themeDict[element + '-foreground']
923 if element + '-background' in themeDict:
924 colours['background'] = themeDict[element + '-background']
Raymond Hettinger931237e2003-07-09 18:48:24 +0000925 self.textHighlightSample.tag_config(element, **colours)
Steven M. Gava052937f2002-02-11 02:20:53 +0000926 self.SetColourSample()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000927
Terry Jan Reedyae410862014-08-03 23:02:53 -0400928 def HelpSourceSelected(self, event):
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000929 self.SetHelpListButtonStates()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000930
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000931 def SetHelpListButtonStates(self):
Terry Jan Reedyae410862014-08-03 23:02:53 -0400932 if self.listHelp.size() < 1: #no entries in list
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000933 self.buttonHelpListEdit.config(state=DISABLED)
934 self.buttonHelpListRemove.config(state=DISABLED)
935 else: #there are some entries
Terry Jan Reedyae410862014-08-03 23:02:53 -0400936 if self.listHelp.curselection(): #there currently is a selection
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000937 self.buttonHelpListEdit.config(state=NORMAL)
938 self.buttonHelpListRemove.config(state=NORMAL)
939 else: #there currently is not a selection
940 self.buttonHelpListEdit.config(state=DISABLED)
941 self.buttonHelpListRemove.config(state=DISABLED)
942
943 def HelpListItemAdd(self):
Terry Jan Reedyae410862014-08-03 23:02:53 -0400944 helpSource = GetHelpSourceDialog(self, 'New Help Source').result
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000945 if helpSource:
Terry Jan Reedyae410862014-08-03 23:02:53 -0400946 self.userHelpList.append((helpSource[0], helpSource[1]))
947 self.listHelp.insert(END, helpSource[0])
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000948 self.UpdateUserHelpChangedItems()
949 self.SetHelpListButtonStates()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000950
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000951 def HelpListItemEdit(self):
Terry Jan Reedyae410862014-08-03 23:02:53 -0400952 itemIndex = self.listHelp.index(ANCHOR)
953 helpSource = self.userHelpList[itemIndex]
954 newHelpSource = GetHelpSourceDialog(
955 self, 'Edit Help Source', menuItem=helpSource[0],
956 filePath=helpSource[1]).result
957 if (not newHelpSource) or (newHelpSource == helpSource):
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000958 return #no changes
Terry Jan Reedyae410862014-08-03 23:02:53 -0400959 self.userHelpList[itemIndex] = newHelpSource
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000960 self.listHelp.delete(itemIndex)
Terry Jan Reedyae410862014-08-03 23:02:53 -0400961 self.listHelp.insert(itemIndex, newHelpSource[0])
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000962 self.UpdateUserHelpChangedItems()
963 self.SetHelpListButtonStates()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000964
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000965 def HelpListItemRemove(self):
Terry Jan Reedyae410862014-08-03 23:02:53 -0400966 itemIndex = self.listHelp.index(ANCHOR)
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000967 del(self.userHelpList[itemIndex])
968 self.listHelp.delete(itemIndex)
969 self.UpdateUserHelpChangedItems()
970 self.SetHelpListButtonStates()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000971
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000972 def UpdateUserHelpChangedItems(self):
Kurt B. Kaiser8e92bf72003-01-14 22:03:31 +0000973 "Clear and rebuild the HelpFiles section in self.changedItems"
974 self.changedItems['main']['HelpFiles'] = {}
Terry Jan Reedyae410862014-08-03 23:02:53 -0400975 for num in range(1, len(self.userHelpList) + 1):
976 self.AddChangedItem(
977 'main', 'HelpFiles', str(num),
Terry Jan Reedy110796f2014-07-27 04:07:18 -0400978 ';'.join(self.userHelpList[num-1][:2]))
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000979
Steven M. Gava429a86a2001-10-23 10:42:12 +0000980 def LoadFontCfg(self):
981 ##base editor font selection list
Terry Jan Reedyae410862014-08-03 23:02:53 -0400982 fonts = list(tkFont.families(self))
Steven M. Gavac11ccf32001-09-24 09:43:17 +0000983 fonts.sort()
984 for font in fonts:
Terry Jan Reedyae410862014-08-03 23:02:53 -0400985 self.listFontName.insert(END, font)
Terry Jan Reedy12352142015-08-01 18:57:27 -0400986 configuredFont = idleConf.GetFont(self, 'main', 'EditorWindow')
987 fontName = configuredFont[0].lower()
988 fontSize = configuredFont[1]
989 fontBold = configuredFont[2]=='bold'
990 self.fontName.set(fontName)
Kurt B. Kaiser05391692003-05-26 20:35:53 +0000991 lc_fonts = [s.lower() for s in fonts]
Terry Jan Reedy12352142015-08-01 18:57:27 -0400992 try:
993 currentFontIndex = lc_fonts.index(fontName)
Steven M. Gava429a86a2001-10-23 10:42:12 +0000994 self.listFontName.see(currentFontIndex)
995 self.listFontName.select_set(currentFontIndex)
Steven M. Gavac112cd82002-01-22 05:56:40 +0000996 self.listFontName.select_anchor(currentFontIndex)
Terry Jan Reedy12352142015-08-01 18:57:27 -0400997 except ValueError:
998 pass
Steven M. Gava429a86a2001-10-23 10:42:12 +0000999 ##font size dropdown
Terry Jan Reedyae410862014-08-03 23:02:53 -04001000 self.optMenuFontSize.SetMenu(('7', '8', '9', '10', '11', '12', '13',
1001 '14', '16', '18', '20', '22'), fontSize )
Steven M. Gavac112cd82002-01-22 05:56:40 +00001002 ##fontWeight
Terry Jan Reedy12352142015-08-01 18:57:27 -04001003 self.fontBold.set(fontBold)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001004 ##font sample
Steven M. Gava429a86a2001-10-23 10:42:12 +00001005 self.SetFontSample()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001006
Steven M. Gava429a86a2001-10-23 10:42:12 +00001007 def LoadTabCfg(self):
Steven M. Gava429a86a2001-10-23 10:42:12 +00001008 ##indent sizes
Terry Jan Reedyae410862014-08-03 23:02:53 -04001009 spaceNum = idleConf.GetOption(
1010 'main', 'Indent', 'num-spaces', default=4, type='int')
Steven M. Gava429a86a2001-10-23 10:42:12 +00001011 self.spaceNum.set(spaceNum)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001012
Steven M. Gava9dd16b32001-11-03 14:54:25 +00001013 def LoadThemeCfg(self):
Steven M. Gava41a85322001-10-29 08:05:34 +00001014 ##current theme type radiobutton
Terry Jan Reedyae410862014-08-03 23:02:53 -04001015 self.themeIsBuiltin.set(idleConf.GetOption(
1016 'main', 'Theme', 'default', type='bool', default=1))
Steven M. Gava41a85322001-10-29 08:05:34 +00001017 ##currently set theme
Terry Jan Reedyae410862014-08-03 23:02:53 -04001018 currentOption = idleConf.CurrentTheme()
Steven M. Gava7c017862001-10-29 11:19:46 +00001019 ##load available theme option menus
Steven M. Gavad0342cd2001-11-04 11:53:10 +00001020 if self.themeIsBuiltin.get(): #default theme selected
Terry Jan Reedyae410862014-08-03 23:02:53 -04001021 itemList = idleConf.GetSectionList('default', 'highlight')
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +00001022 itemList.sort()
Terry Jan Reedyae410862014-08-03 23:02:53 -04001023 self.optMenuThemeBuiltin.SetMenu(itemList, currentOption)
1024 itemList = idleConf.GetSectionList('user', 'highlight')
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +00001025 itemList.sort()
Steven M. Gava41a85322001-10-29 08:05:34 +00001026 if not itemList:
1027 self.radioThemeCustom.config(state=DISABLED)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001028 self.customTheme.set('- no custom themes -')
Steven M. Gava41a85322001-10-29 08:05:34 +00001029 else:
Terry Jan Reedyae410862014-08-03 23:02:53 -04001030 self.optMenuThemeCustom.SetMenu(itemList, itemList[0])
Steven M. Gava9dd16b32001-11-03 14:54:25 +00001031 else: #user theme selected
Terry Jan Reedyae410862014-08-03 23:02:53 -04001032 itemList = idleConf.GetSectionList('user', 'highlight')
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +00001033 itemList.sort()
Terry Jan Reedyae410862014-08-03 23:02:53 -04001034 self.optMenuThemeCustom.SetMenu(itemList, currentOption)
1035 itemList = idleConf.GetSectionList('default', 'highlight')
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +00001036 itemList.sort()
Terry Jan Reedyae410862014-08-03 23:02:53 -04001037 self.optMenuThemeBuiltin.SetMenu(itemList, itemList[0])
Steven M. Gava7c017862001-10-29 11:19:46 +00001038 self.SetThemeType()
1039 ##load theme element option menu
Terry Jan Reedyae410862014-08-03 23:02:53 -04001040 themeNames = self.themeElements.keys()
Florent Xiclunaa7f242f2010-04-02 08:15:26 +00001041 themeNames.sort(key=lambda x: self.themeElements[x][1])
Terry Jan Reedyae410862014-08-03 23:02:53 -04001042 self.optMenuHighlightTarget.SetMenu(themeNames, themeNames[0])
Steven M. Gava9dd16b32001-11-03 14:54:25 +00001043 self.PaintThemeSample()
Steven M. Gava0cae01c2002-01-04 07:53:06 +00001044 self.SetHighlightTarget()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001045
Steven M. Gava9dd16b32001-11-03 14:54:25 +00001046 def LoadKeyCfg(self):
Steven M. Gava41a85322001-10-29 08:05:34 +00001047 ##current keys type radiobutton
Terry Jan Reedyae410862014-08-03 23:02:53 -04001048 self.keysAreBuiltin.set(idleConf.GetOption(
1049 'main', 'Keys', 'default', type='bool', default=1))
Steven M. Gava41a85322001-10-29 08:05:34 +00001050 ##currently set keys
Terry Jan Reedyae410862014-08-03 23:02:53 -04001051 currentOption = idleConf.CurrentKeys()
Steven M. Gava7c017862001-10-29 11:19:46 +00001052 ##load available keyset option menus
Steven M. Gava052937f2002-02-11 02:20:53 +00001053 if self.keysAreBuiltin.get(): #default theme selected
Terry Jan Reedyae410862014-08-03 23:02:53 -04001054 itemList = idleConf.GetSectionList('default', 'keys')
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +00001055 itemList.sort()
Terry Jan Reedyae410862014-08-03 23:02:53 -04001056 self.optMenuKeysBuiltin.SetMenu(itemList, currentOption)
1057 itemList = idleConf.GetSectionList('user', 'keys')
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +00001058 itemList.sort()
Steven M. Gava41a85322001-10-29 08:05:34 +00001059 if not itemList:
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001060 self.radioKeysCustom.config(state=DISABLED)
1061 self.customKeys.set('- no custom keys -')
Steven M. Gava41a85322001-10-29 08:05:34 +00001062 else:
Terry Jan Reedyae410862014-08-03 23:02:53 -04001063 self.optMenuKeysCustom.SetMenu(itemList, itemList[0])
Steven M. Gavaa498af22002-02-01 01:33:36 +00001064 else: #user key set selected
Terry Jan Reedyae410862014-08-03 23:02:53 -04001065 itemList = idleConf.GetSectionList('user', 'keys')
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +00001066 itemList.sort()
Terry Jan Reedyae410862014-08-03 23:02:53 -04001067 self.optMenuKeysCustom.SetMenu(itemList, currentOption)
1068 itemList = idleConf.GetSectionList('default', 'keys')
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +00001069 itemList.sort()
Terry Jan Reedyae410862014-08-03 23:02:53 -04001070 self.optMenuKeysBuiltin.SetMenu(itemList, itemList[0])
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001071 self.SetKeysType()
Steven M. Gavafacfc092002-01-19 00:29:54 +00001072 ##load keyset element list
Terry Jan Reedyae410862014-08-03 23:02:53 -04001073 keySetName = idleConf.CurrentKeys()
Steven M. Gava052937f2002-02-11 02:20:53 +00001074 self.LoadKeysList(keySetName)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001075
Steven M. Gavafacfc092002-01-19 00:29:54 +00001076 def LoadGeneralCfg(self):
Steven M. Gava5f28e8f2002-01-21 06:38:21 +00001077 #startup state
Terry Jan Reedyae410862014-08-03 23:02:53 -04001078 self.startupEdit.set(idleConf.GetOption(
1079 'main', 'General', 'editor-on-startup', default=1, type='bool'))
Kurt B. Kaiser6c638b62003-05-26 06:23:10 +00001080 #autosave state
Terry Jan Reedyae410862014-08-03 23:02:53 -04001081 self.autoSave.set(idleConf.GetOption(
1082 'main', 'General', 'autosave', default=0, type='bool'))
Steven M. Gavafacfc092002-01-19 00:29:54 +00001083 #initial window size
Terry Jan Reedyae410862014-08-03 23:02:53 -04001084 self.winWidth.set(idleConf.GetOption(
1085 'main', 'EditorWindow', 'width', type='int'))
1086 self.winHeight.set(idleConf.GetOption(
1087 'main', 'EditorWindow', 'height', type='int'))
Kurt B. Kaisera053f332003-05-10 00:49:56 +00001088 # default source encoding
Terry Jan Reedyae410862014-08-03 23:02:53 -04001089 self.encoding.set(idleConf.GetOption(
1090 'main', 'EditorWindow', 'encoding', default='none'))
Kurt B. Kaiser8e92bf72003-01-14 22:03:31 +00001091 # additional help sources
1092 self.userHelpList = idleConf.GetAllExtraHelpSourcesList()
Steven M. Gava085eb1b2002-02-05 04:52:32 +00001093 for helpItem in self.userHelpList:
Terry Jan Reedyae410862014-08-03 23:02:53 -04001094 self.listHelp.insert(END, helpItem[0])
Steven M. Gava085eb1b2002-02-05 04:52:32 +00001095 self.SetHelpListButtonStates()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001096
Steven M. Gava429a86a2001-10-23 10:42:12 +00001097 def LoadConfigs(self):
1098 """
1099 load configuration from default and user config files and populate
1100 the widgets on the config dialog pages.
1101 """
1102 ### fonts / tabs page
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001103 self.LoadFontCfg()
1104 self.LoadTabCfg()
Steven M. Gava429a86a2001-10-23 10:42:12 +00001105 ### highlighting page
Steven M. Gava9dd16b32001-11-03 14:54:25 +00001106 self.LoadThemeCfg()
Steven M. Gava429a86a2001-10-23 10:42:12 +00001107 ### keys page
Steven M. Gava9dd16b32001-11-03 14:54:25 +00001108 self.LoadKeyCfg()
Steven M. Gava429a86a2001-10-23 10:42:12 +00001109 ### general page
Steven M. Gavafacfc092002-01-19 00:29:54 +00001110 self.LoadGeneralCfg()
Terry Jan Reedy1c49ec02015-10-13 22:03:44 -04001111 # note: extension page handled separately
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001112
Terry Jan Reedyae410862014-08-03 23:02:53 -04001113 def SaveNewKeySet(self, keySetName, keySet):
Steven M. Gava052937f2002-02-11 02:20:53 +00001114 """
1115 save a newly created core key set.
1116 keySetName - string, the name of the new key set
1117 keySet - dictionary containing the new key set
1118 """
1119 if not idleConf.userCfg['keys'].has_section(keySetName):
1120 idleConf.userCfg['keys'].add_section(keySetName)
Terry Jan Reedy110796f2014-07-27 04:07:18 -04001121 for event in keySet:
Terry Jan Reedyae410862014-08-03 23:02:53 -04001122 value = keySet[event]
1123 idleConf.userCfg['keys'].SetOption(keySetName, event, value)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001124
Terry Jan Reedyae410862014-08-03 23:02:53 -04001125 def SaveNewTheme(self, themeName, theme):
Steven M. Gava052937f2002-02-11 02:20:53 +00001126 """
1127 save a newly created theme.
1128 themeName - string, the name of the new theme
1129 theme - dictionary containing the new theme
1130 """
1131 if not idleConf.userCfg['highlight'].has_section(themeName):
1132 idleConf.userCfg['highlight'].add_section(themeName)
Terry Jan Reedy110796f2014-07-27 04:07:18 -04001133 for element in theme:
Terry Jan Reedyae410862014-08-03 23:02:53 -04001134 value = theme[element]
1135 idleConf.userCfg['highlight'].SetOption(themeName, element, value)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001136
Terry Jan Reedyae410862014-08-03 23:02:53 -04001137 def SetUserValue(self, configType, section, item, value):
1138 if idleConf.defaultCfg[configType].has_option(section, item):
1139 if idleConf.defaultCfg[configType].Get(section, item) == value:
Steven M. Gava2d7bb3f2002-01-29 08:35:29 +00001140 #the setting equals a default setting, remove it from user cfg
Terry Jan Reedyae410862014-08-03 23:02:53 -04001141 return idleConf.userCfg[configType].RemoveOption(section, item)
Steven M. Gava2d7bb3f2002-01-29 08:35:29 +00001142 #if we got here set the option
Terry Jan Reedyae410862014-08-03 23:02:53 -04001143 return idleConf.userCfg[configType].SetOption(section, item, value)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001144
Steven M. Gava052937f2002-02-11 02:20:53 +00001145 def SaveAllChangedConfigs(self):
Kurt B. Kaisere7a161e2003-01-10 20:13:57 +00001146 "Save configuration changes to the user config file."
Steven M. Gava0c5bc8c2002-03-27 02:25:44 +00001147 idleConf.userCfg['main'].Save()
Terry Jan Reedy110796f2014-07-27 04:07:18 -04001148 for configType in self.changedItems:
Kurt B. Kaisere7a161e2003-01-10 20:13:57 +00001149 cfgTypeHasChanges = False
Terry Jan Reedy110796f2014-07-27 04:07:18 -04001150 for section in self.changedItems[configType]:
Kurt B. Kaisere7a161e2003-01-10 20:13:57 +00001151 if section == 'HelpFiles':
1152 #this section gets completely replaced
1153 idleConf.userCfg['main'].remove_section('HelpFiles')
Kurt B. Kaiser8e92bf72003-01-14 22:03:31 +00001154 cfgTypeHasChanges = True
Terry Jan Reedy110796f2014-07-27 04:07:18 -04001155 for item in self.changedItems[configType][section]:
Kurt B. Kaisere7a161e2003-01-10 20:13:57 +00001156 value = self.changedItems[configType][section][item]
Terry Jan Reedyae410862014-08-03 23:02:53 -04001157 if self.SetUserValue(configType, section, item, value):
Kurt B. Kaisere7a161e2003-01-10 20:13:57 +00001158 cfgTypeHasChanges = True
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001159 if cfgTypeHasChanges:
1160 idleConf.userCfg[configType].Save()
Kurt B. Kaiser5acdf932004-11-16 21:28:36 +00001161 for configType in ['keys', 'highlight']:
1162 # save these even if unchanged!
1163 idleConf.userCfg[configType].Save()
Steven M. Gavaa498af22002-02-01 01:33:36 +00001164 self.ResetChangedItems() #clear the changed items dict
Terry Jan Reedy1c49ec02015-10-13 22:03:44 -04001165 self.save_all_changed_extensions() # uses a different mechanism
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001166
Kurt B. Kaiserb1754452005-11-18 22:05:48 +00001167 def DeactivateCurrentConfig(self):
1168 #Before a config is saved, some cleanup of current
1169 #config must be done - remove the previous keybindings
Terry Jan Reedyae410862014-08-03 23:02:53 -04001170 winInstances = self.parent.instance_dict
Kurt B. Kaiserb1754452005-11-18 22:05:48 +00001171 for instance in winInstances:
1172 instance.RemoveKeybindings()
1173
Steven M. Gava49745752002-02-18 01:43:11 +00001174 def ActivateConfigChanges(self):
Kurt B. Kaiseracdef852005-01-31 03:34:26 +00001175 "Dynamically apply configuration changes"
Terry Jan Reedy110796f2014-07-27 04:07:18 -04001176 winInstances = self.parent.instance_dict.keys()
Steven M. Gavab77d3432002-03-02 07:16:21 +00001177 for instance in winInstances:
1178 instance.ResetColorizer()
Steven M. Gavab1585412002-03-12 00:21:56 +00001179 instance.ResetFont()
Kurt B. Kaiseracdef852005-01-31 03:34:26 +00001180 instance.set_notabs_indentwidth()
Kurt B. Kaiserb1754452005-11-18 22:05:48 +00001181 instance.ApplyKeybindings()
Kurt B. Kaiser8e92bf72003-01-14 22:03:31 +00001182 instance.reset_help_menu_entries()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001183
Steven M. Gava5f28e8f2002-01-21 06:38:21 +00001184 def Cancel(self):
1185 self.destroy()
1186
1187 def Ok(self):
1188 self.Apply()
1189 self.destroy()
1190
1191 def Apply(self):
Kurt B. Kaiserb1754452005-11-18 22:05:48 +00001192 self.DeactivateCurrentConfig()
Steven M. Gava052937f2002-02-11 02:20:53 +00001193 self.SaveAllChangedConfigs()
Steven M. Gava49745752002-02-18 01:43:11 +00001194 self.ActivateConfigChanges()
Steven M. Gava5f28e8f2002-01-21 06:38:21 +00001195
1196 def Help(self):
Terry Jan Reedyc0a053e2015-10-11 22:07:25 -04001197 page = self.tabPages._current_page
1198 view_text(self, title='Help for IDLE preferences',
1199 text=help_common+help_pages.get(page, ''))
1200
Terry Jan Reedy1c49ec02015-10-13 22:03:44 -04001201 def CreatePageExtensions(self):
1202 """Part of the config dialog used for configuring IDLE extensions.
1203
1204 This code is generic - it works for any and all IDLE extensions.
1205
1206 IDLE extensions save their configuration options using idleConf.
Terry Jan Reedy4922ac12015-10-13 22:08:45 -04001207 This code reads the current configuration using idleConf, supplies a
Terry Jan Reedy1c49ec02015-10-13 22:03:44 -04001208 GUI interface to change the configuration values, and saves the
1209 changes using idleConf.
1210
1211 Not all changes take effect immediately - some may require restarting IDLE.
1212 This depends on each extension's implementation.
1213
1214 All values are treated as text, and it is up to the user to supply
1215 reasonable values. The only exception to this are the 'enable*' options,
Serhiy Storchaka9a118f12016-04-17 09:37:36 +03001216 which are boolean, and can be toggled with a True/False button.
Terry Jan Reedy1c49ec02015-10-13 22:03:44 -04001217 """
1218 parent = self.parent
1219 frame = self.tabPages.pages['Extensions'].frame
1220 self.ext_defaultCfg = idleConf.defaultCfg['extensions']
1221 self.ext_userCfg = idleConf.userCfg['extensions']
1222 self.is_int = self.register(is_int)
1223 self.load_extensions()
1224 # create widgets - a listbox shows all available extensions, with the
1225 # controls for the extension selected in the listbox to the right
1226 self.extension_names = StringVar(self)
1227 frame.rowconfigure(0, weight=1)
1228 frame.columnconfigure(2, weight=1)
1229 self.extension_list = Listbox(frame, listvariable=self.extension_names,
1230 selectmode='browse')
1231 self.extension_list.bind('<<ListboxSelect>>', self.extension_selected)
1232 scroll = Scrollbar(frame, command=self.extension_list.yview)
1233 self.extension_list.yscrollcommand=scroll.set
1234 self.details_frame = LabelFrame(frame, width=250, height=250)
1235 self.extension_list.grid(column=0, row=0, sticky='nws')
1236 scroll.grid(column=1, row=0, sticky='ns')
1237 self.details_frame.grid(column=2, row=0, sticky='nsew', padx=[10, 0])
1238 frame.configure(padx=10, pady=10)
1239 self.config_frame = {}
1240 self.current_extension = None
1241
1242 self.outerframe = self # TEMPORARY
1243 self.tabbed_page_set = self.extension_list # TEMPORARY
1244
1245 # create the frame holding controls for each extension
1246 ext_names = ''
1247 for ext_name in sorted(self.extensions):
1248 self.create_extension_frame(ext_name)
1249 ext_names = ext_names + '{' + ext_name + '} '
1250 self.extension_names.set(ext_names)
1251 self.extension_list.selection_set(0)
1252 self.extension_selected(None)
1253
1254 def load_extensions(self):
1255 "Fill self.extensions with data from the default and user configs."
1256 self.extensions = {}
1257 for ext_name in idleConf.GetExtensions(active_only=False):
1258 self.extensions[ext_name] = []
1259
1260 for ext_name in self.extensions:
1261 opt_list = sorted(self.ext_defaultCfg.GetOptionList(ext_name))
1262
1263 # bring 'enable' options to the beginning of the list
1264 enables = [opt_name for opt_name in opt_list
1265 if opt_name.startswith('enable')]
1266 for opt_name in enables:
1267 opt_list.remove(opt_name)
1268 opt_list = enables + opt_list
1269
1270 for opt_name in opt_list:
1271 def_str = self.ext_defaultCfg.Get(
1272 ext_name, opt_name, raw=True)
1273 try:
1274 def_obj = {'True':True, 'False':False}[def_str]
1275 opt_type = 'bool'
1276 except KeyError:
1277 try:
1278 def_obj = int(def_str)
1279 opt_type = 'int'
1280 except ValueError:
1281 def_obj = def_str
1282 opt_type = None
1283 try:
1284 value = self.ext_userCfg.Get(
1285 ext_name, opt_name, type=opt_type, raw=True,
1286 default=def_obj)
1287 except ValueError: # Need this until .Get fixed
1288 value = def_obj # bad values overwritten by entry
1289 var = StringVar(self)
1290 var.set(str(value))
1291
1292 self.extensions[ext_name].append({'name': opt_name,
1293 'type': opt_type,
1294 'default': def_str,
1295 'value': value,
1296 'var': var,
1297 })
1298
1299 def extension_selected(self, event):
1300 newsel = self.extension_list.curselection()
1301 if newsel:
1302 newsel = self.extension_list.get(newsel)
1303 if newsel is None or newsel != self.current_extension:
1304 if self.current_extension:
1305 self.details_frame.config(text='')
1306 self.config_frame[self.current_extension].grid_forget()
1307 self.current_extension = None
1308 if newsel:
1309 self.details_frame.config(text=newsel)
1310 self.config_frame[newsel].grid(column=0, row=0, sticky='nsew')
1311 self.current_extension = newsel
1312
1313 def create_extension_frame(self, ext_name):
1314 """Create a frame holding the widgets to configure one extension"""
1315 f = VerticalScrolledFrame(self.details_frame, height=250, width=250)
1316 self.config_frame[ext_name] = f
1317 entry_area = f.interior
1318 # create an entry for each configuration option
1319 for row, opt in enumerate(self.extensions[ext_name]):
1320 # create a row with a label and entry/checkbutton
1321 label = Label(entry_area, text=opt['name'])
1322 label.grid(row=row, column=0, sticky=NW)
1323 var = opt['var']
1324 if opt['type'] == 'bool':
1325 Checkbutton(entry_area, textvariable=var, variable=var,
1326 onvalue='True', offvalue='False',
1327 indicatoron=FALSE, selectcolor='', width=8
1328 ).grid(row=row, column=1, sticky=W, padx=7)
1329 elif opt['type'] == 'int':
1330 Entry(entry_area, textvariable=var, validate='key',
1331 validatecommand=(self.is_int, '%P')
1332 ).grid(row=row, column=1, sticky=NSEW, padx=7)
1333
1334 else:
1335 Entry(entry_area, textvariable=var
1336 ).grid(row=row, column=1, sticky=NSEW, padx=7)
1337 return
1338
1339 def set_extension_value(self, section, opt):
1340 name = opt['name']
1341 default = opt['default']
1342 value = opt['var'].get().strip() or default
1343 opt['var'].set(value)
1344 # if self.defaultCfg.has_section(section):
1345 # Currently, always true; if not, indent to return
1346 if (value == default):
1347 return self.ext_userCfg.RemoveOption(section, name)
1348 # set the option
1349 return self.ext_userCfg.SetOption(section, name, value)
1350
1351 def save_all_changed_extensions(self):
1352 """Save configuration changes to the user config file."""
1353 has_changes = False
1354 for ext_name in self.extensions:
1355 options = self.extensions[ext_name]
1356 for opt in options:
1357 if self.set_extension_value(ext_name, opt):
1358 has_changes = True
1359 if has_changes:
1360 self.ext_userCfg.Save()
1361
1362
Terry Jan Reedyc0a053e2015-10-11 22:07:25 -04001363help_common = '''\
1364When you click either the Apply or Ok buttons, settings in this
1365dialog that are different from IDLE's default are saved in
1366a .idlerc directory in your home directory. Except as noted,
Terry Jan Reedy35aa5d02015-11-12 15:02:50 -05001367these changes apply to all versions of IDLE installed on this
Terry Jan Reedyc0a053e2015-10-11 22:07:25 -04001368machine. Some do not take affect until IDLE is restarted.
1369[Cancel] only cancels changes made since the last save.
1370'''
1371help_pages = {
1372 'Highlighting':'''
1373Highlighting:
Terry Jan Reedy35aa5d02015-11-12 15:02:50 -05001374The IDLE Dark color theme is new in October 2015. It can only
Terry Jan Reedyc0a053e2015-10-11 22:07:25 -04001375be used with older IDLE releases if it is saved as a custom
1376theme, with a different name.
1377'''
1378}
1379
Steven M. Gavac11ccf32001-09-24 09:43:17 +00001380
Terry Jan Reedy1c49ec02015-10-13 22:03:44 -04001381def is_int(s):
1382 "Return 's is blank or represents an int'"
1383 if not s:
1384 return True
1385 try:
1386 int(s)
1387 return True
1388 except ValueError:
1389 return False
1390
1391
Terry Jan Reedy7a162072014-10-22 20:15:12 -04001392class VerticalScrolledFrame(Frame):
1393 """A pure Tkinter vertically scrollable frame.
1394
1395 * Use the 'interior' attribute to place widgets inside the scrollable frame
1396 * Construct and pack/place/grid normally
1397 * This frame only allows vertical scrolling
1398 """
1399 def __init__(self, parent, *args, **kw):
1400 Frame.__init__(self, parent, *args, **kw)
1401
1402 # create a canvas object and a vertical scrollbar for scrolling it
1403 vscrollbar = Scrollbar(self, orient=VERTICAL)
1404 vscrollbar.pack(fill=Y, side=RIGHT, expand=FALSE)
1405 canvas = Canvas(self, bd=0, highlightthickness=0,
Terry Jan Reedy1256b3c2015-10-22 03:27:27 -04001406 yscrollcommand=vscrollbar.set, width=240)
Terry Jan Reedy7a162072014-10-22 20:15:12 -04001407 canvas.pack(side=LEFT, fill=BOTH, expand=TRUE)
1408 vscrollbar.config(command=canvas.yview)
1409
1410 # reset the view
1411 canvas.xview_moveto(0)
1412 canvas.yview_moveto(0)
1413
1414 # create a frame inside the canvas which will be scrolled with it
1415 self.interior = interior = Frame(canvas)
1416 interior_id = canvas.create_window(0, 0, window=interior, anchor=NW)
1417
1418 # track changes to the canvas and frame width and sync them,
1419 # also updating the scrollbar
1420 def _configure_interior(event):
1421 # update the scrollbars to match the size of the inner frame
1422 size = (interior.winfo_reqwidth(), interior.winfo_reqheight())
1423 canvas.config(scrollregion="0 0 %s %s" % size)
Terry Jan Reedy7a162072014-10-22 20:15:12 -04001424 interior.bind('<Configure>', _configure_interior)
1425
1426 def _configure_canvas(event):
1427 if interior.winfo_reqwidth() != canvas.winfo_width():
1428 # update the inner frame's width to fill the canvas
1429 canvas.itemconfigure(interior_id, width=canvas.winfo_width())
1430 canvas.bind('<Configure>', _configure_canvas)
1431
1432 return
1433
Terry Jan Reedy7a162072014-10-22 20:15:12 -04001434
Steven M. Gava44d3d1a2001-07-31 06:59:02 +00001435if __name__ == '__main__':
Terry Jan Reedyaf0dce92014-07-14 23:07:21 -04001436 import unittest
1437 unittest.main('idlelib.idle_test.test_configdialog',
1438 verbosity=2, exit=False)
Terry Jan Reedy76916e82014-05-29 01:46:16 -04001439 from idlelib.idle_test.htest import run
Terry Jan Reedy91885162015-10-20 02:15:23 -04001440 run(ConfigDialog)