blob: 8184582a3e2ff32ae8d4749df6d7aebcc2a0812a [file] [log] [blame]
Kurt B. Kaisere7a161e2003-01-10 20:13:57 +00001"""IDLE Configuration Dialog: support user customization of IDLE by GUI
2
3Customize font faces, sizes, and colorization attributes. Set indentation
4defaults. Customize keybindings. Colorization and keybindings can be
5saved as user defined sets. Select startup options including shell/editor
6and default window size. Define additional help sources.
7
8Note that tab width in IDLE is currently fixed at eight due to Tk issues.
Kurt B. Kaiseracdef852005-01-31 03:34:26 +00009Refer to comments in EditorWindow autoindent code for details.
Kurt B. Kaisere7a161e2003-01-10 20:13:57 +000010
Steven M. Gava44d3d1a2001-07-31 06:59:02 +000011"""
Georg Brandl14fc4272008-05-17 18:39:55 +000012from tkinter import *
Terry Jan Reedy01e35752016-06-10 18:19:21 -040013from tkinter.ttk import Scrollbar
Georg Brandl14fc4272008-05-17 18:39:55 +000014import tkinter.colorchooser as tkColorChooser
15import tkinter.font as tkFont
Terry Jan Reedybfbaa6b2016-08-31 00:50:55 -040016import tkinter.messagebox as tkMessageBox
Steven M. Gava44d3d1a2001-07-31 06:59:02 +000017
Terry Jan Reedy6fa5bdc2016-05-28 13:22:31 -040018from idlelib.config import idleConf
Terry Jan Reedy6fa5bdc2016-05-28 13:22:31 -040019from idlelib.config_key import GetKeysDialog
Terry Jan Reedybfbaa6b2016-08-31 00:50:55 -040020from idlelib.dynoption import DynOptionMenu
21from idlelib import macosx
Terry Jan Reedy8b22c0a2016-07-08 00:22:50 -040022from idlelib.query import SectionName, HelpSource
Terry Jan Reedya9421fb2014-10-22 20:15:18 -040023from idlelib.tabbedpages import TabbedPageSet
Terry Jan Reedy6fa5bdc2016-05-28 13:22:31 -040024from idlelib.textview import view_text
Terry Jan Reedyd0cadba2015-10-11 22:07:31 -040025
Steven M. Gava44d3d1a2001-07-31 06:59:02 +000026class ConfigDialog(Toplevel):
Kurt B. Kaiseracdef852005-01-31 03:34:26 +000027
Terry Jan Reedycd567362014-10-17 01:31:35 -040028 def __init__(self, parent, title='', _htest=False, _utest=False):
Terry Jan Reedy2e8234a2014-05-29 01:46:26 -040029 """
30 _htest - bool, change box location when running htest
Terry Jan Reedycfa89502014-07-14 23:07:32 -040031 _utest - bool, don't wait_window when running unittest
Terry Jan Reedy2e8234a2014-05-29 01:46:26 -040032 """
Steven M. Gavad721c482001-07-31 10:46:53 +000033 Toplevel.__init__(self, parent)
Terry Jan Reedy22405332014-07-30 19:24:32 -040034 self.parent = parent
Terry Jan Reedy4036d872014-08-03 23:02:58 -040035 if _htest:
36 parent.instance_dict = {}
Guido van Rossum8ce8a782007-11-01 19:42:39 +000037 self.wm_withdraw()
38
Steven M. Gavad721c482001-07-31 10:46:53 +000039 self.configure(borderwidth=5)
Terry Jan Reedycd567362014-10-17 01:31:35 -040040 self.title(title or 'IDLE Preferences')
Terry Jan Reedy4036d872014-08-03 23:02:58 -040041 self.geometry(
42 "+%d+%d" % (parent.winfo_rootx() + 20,
43 parent.winfo_rooty() + (30 if not _htest else 150)))
Georg Brandl7eb4b7d2005-07-22 21:49:32 +000044 #Theme Elements. Each theme element key is its display name.
Steven M. Gava9dd16b32001-11-03 14:54:25 +000045 #The first value of the tuple is the sample area tag name.
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +000046 #The second value is the display name list sort index.
Terry Jan Reedy4036d872014-08-03 23:02:58 -040047 self.themeElements={
Terry Jan Reedya8aa4d52015-10-02 22:12:17 -040048 'Normal Text': ('normal', '00'),
49 'Python Keywords': ('keyword', '01'),
50 'Python Definitions': ('definition', '02'),
51 'Python Builtins': ('builtin', '03'),
52 'Python Comments': ('comment', '04'),
53 'Python Strings': ('string', '05'),
54 'Selected Text': ('hilite', '06'),
55 'Found Text': ('hit', '07'),
56 'Cursor': ('cursor', '08'),
57 'Editor Breakpoint': ('break', '09'),
58 'Shell Normal Text': ('console', '10'),
59 'Shell Error Text': ('error', '11'),
60 'Shell Stdout Text': ('stdout', '12'),
61 'Shell Stderr Text': ('stderr', '13'),
Kurt B. Kaiser73360a32004-03-08 18:15:31 +000062 }
Steven M. Gavaa498af22002-02-01 01:33:36 +000063 self.ResetChangedItems() #load initial values in changed items dict
Steven M. Gavad721c482001-07-31 10:46:53 +000064 self.CreateWidgets()
Terry Jan Reedy4036d872014-08-03 23:02:58 -040065 self.resizable(height=FALSE, width=FALSE)
Steven M. Gavad721c482001-07-31 10:46:53 +000066 self.transient(parent)
67 self.grab_set()
68 self.protocol("WM_DELETE_WINDOW", self.Cancel)
Steven M. Gava2d4e03b2001-12-05 07:54:07 +000069 self.tabPages.focus_set()
Steven M. Gavad721c482001-07-31 10:46:53 +000070 #key bindings for this dialog
Terry Jan Reedy4036d872014-08-03 23:02:58 -040071 #self.bind('<Escape>', self.Cancel) #dismiss dialog, no save
72 #self.bind('<Alt-a>', self.Apply) #apply changes, save
73 #self.bind('<F1>', self.Help) #context help
Steven M. Gava429a86af2001-10-23 10:42:12 +000074 self.LoadConfigs()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +000075 self.AttachVarCallbacks() #avoid callbacks during LoadConfigs
Guido van Rossum8ce8a782007-11-01 19:42:39 +000076
Terry Jan Reedycfa89502014-07-14 23:07:32 -040077 if not _utest:
78 self.wm_deiconify()
79 self.wait_window()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +000080
Steven M. Gavad721c482001-07-31 10:46:53 +000081 def CreateWidgets(self):
Guido van Rossum8ce8a782007-11-01 19:42:39 +000082 self.tabPages = TabbedPageSet(self,
Terry Jan Reedy93f35422015-10-13 22:03:51 -040083 page_names=['Fonts/Tabs', 'Highlighting', 'Keys', 'General',
84 'Extensions'])
Terry Jan Reedy92cb0a32014-10-08 20:29:13 -040085 self.tabPages.pack(side=TOP, expand=TRUE, fill=BOTH)
86 self.CreatePageFontTab()
87 self.CreatePageHighlight()
88 self.CreatePageKeys()
89 self.CreatePageGeneral()
Terry Jan Reedy93f35422015-10-13 22:03:51 -040090 self.CreatePageExtensions()
Terry Jan Reedy92cb0a32014-10-08 20:29:13 -040091 self.create_action_buttons().pack(side=BOTTOM)
Terry Jan Reedyd0cadba2015-10-11 22:07:31 -040092
Terry Jan Reedy92cb0a32014-10-08 20:29:13 -040093 def create_action_buttons(self):
Terry Jan Reedy6fa5bdc2016-05-28 13:22:31 -040094 if macosx.isAquaTk():
Terry Jan Reedye3416e62014-07-26 19:40:16 -040095 # Changing the default padding on OSX results in unreadable
96 # text in the buttons
Terry Jan Reedy4036d872014-08-03 23:02:58 -040097 paddingArgs = {}
Ronald Oussoren9e350042009-02-12 16:02:11 +000098 else:
Terry Jan Reedy4036d872014-08-03 23:02:58 -040099 paddingArgs = {'padx':6, 'pady':3}
Terry Jan Reedya9421fb2014-10-22 20:15:18 -0400100 outer = Frame(self, pady=2)
101 buttons = Frame(outer, pady=2)
Terry Jan Reedyd0cadba2015-10-11 22:07:31 -0400102 for txt, cmd in (
103 ('Ok', self.Ok),
104 ('Apply', self.Apply),
105 ('Cancel', self.Cancel),
106 ('Help', self.Help)):
107 Button(buttons, text=txt, command=cmd, takefocus=FALSE,
108 **paddingArgs).pack(side=LEFT, padx=5)
Terry Jan Reedya9421fb2014-10-22 20:15:18 -0400109 # add space above buttons
110 Frame(outer, height=2, borderwidth=0).pack(side=TOP)
111 buttons.pack(side=BOTTOM)
112 return outer
Terry Jan Reedyd0cadba2015-10-11 22:07:31 -0400113
Steven M. Gava60fc7072001-08-04 13:58:22 +0000114 def CreatePageFontTab(self):
Terry Jan Reedy22405332014-07-30 19:24:32 -0400115 parent = self.parent
116 self.fontSize = StringVar(parent)
117 self.fontBold = BooleanVar(parent)
118 self.fontName = StringVar(parent)
119 self.spaceNum = IntVar(parent)
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400120 self.editFont = tkFont.Font(parent, ('courier', 10, 'normal'))
Terry Jan Reedy22405332014-07-30 19:24:32 -0400121
Steven M. Gavaf213ccb2001-08-05 08:00:28 +0000122 ##widget creation
123 #body frame
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400124 frame = self.tabPages.pages['Fonts/Tabs'].frame
Steven M. Gavaf213ccb2001-08-05 08:00:28 +0000125 #body section frames
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400126 frameFont = LabelFrame(
127 frame, borderwidth=2, relief=GROOVE, text=' Base Editor Font ')
128 frameIndent = LabelFrame(
129 frame, borderwidth=2, relief=GROOVE, text=' Indentation Width ')
Steven M. Gavaf213ccb2001-08-05 08:00:28 +0000130 #frameFont
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400131 frameFontName = Frame(frameFont)
132 frameFontParam = Frame(frameFont)
133 labelFontNameTitle = Label(
134 frameFontName, justify=LEFT, text='Font Face :')
135 self.listFontName = Listbox(
136 frameFontName, height=5, takefocus=FALSE, exportselection=FALSE)
137 self.listFontName.bind(
138 '<ButtonRelease-1>', self.OnListFontButtonRelease)
139 scrollFont = Scrollbar(frameFontName)
Steven M. Gavac01e30f2001-08-11 15:48:13 +0000140 scrollFont.config(command=self.listFontName.yview)
141 self.listFontName.config(yscrollcommand=scrollFont.set)
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400142 labelFontSizeTitle = Label(frameFontParam, text='Size :')
143 self.optMenuFontSize = DynOptionMenu(
144 frameFontParam, self.fontSize, None, command=self.SetFontSample)
145 checkFontBold = Checkbutton(
146 frameFontParam, variable=self.fontBold, onvalue=1,
147 offvalue=0, text='Bold', command=self.SetFontSample)
148 frameFontSample = Frame(frameFont, relief=SOLID, borderwidth=1)
149 self.labelFontSample = Label(
150 frameFontSample, justify=LEFT, font=self.editFont,
151 text='AaBbCcDdEe\nFfGgHhIiJjK\n1234567890\n#:+=(){}[]')
Steven M. Gavaf213ccb2001-08-05 08:00:28 +0000152 #frameIndent
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400153 frameIndentSize = Frame(frameIndent)
154 labelSpaceNumTitle = Label(
155 frameIndentSize, justify=LEFT,
156 text='Python Standard: 4 Spaces!')
157 self.scaleSpaceNum = Scale(
158 frameIndentSize, variable=self.spaceNum,
159 orient='horizontal', tickinterval=2, from_=2, to=16)
Terry Jan Reedy22405332014-07-30 19:24:32 -0400160
Steven M. Gavaf213ccb2001-08-05 08:00:28 +0000161 #widget packing
162 #body
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400163 frameFont.pack(side=LEFT, padx=5, pady=5, expand=TRUE, fill=BOTH)
164 frameIndent.pack(side=LEFT, padx=5, pady=5, fill=Y)
Steven M. Gavaf213ccb2001-08-05 08:00:28 +0000165 #frameFont
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400166 frameFontName.pack(side=TOP, padx=5, pady=5, fill=X)
167 frameFontParam.pack(side=TOP, padx=5, pady=5, fill=X)
168 labelFontNameTitle.pack(side=TOP, anchor=W)
169 self.listFontName.pack(side=LEFT, expand=TRUE, fill=X)
170 scrollFont.pack(side=LEFT, fill=Y)
171 labelFontSizeTitle.pack(side=LEFT, anchor=W)
172 self.optMenuFontSize.pack(side=LEFT, anchor=W)
173 checkFontBold.pack(side=LEFT, anchor=W, padx=20)
174 frameFontSample.pack(side=TOP, padx=5, pady=5, expand=TRUE, fill=BOTH)
175 self.labelFontSample.pack(expand=TRUE, fill=BOTH)
Steven M. Gavaf213ccb2001-08-05 08:00:28 +0000176 #frameIndent
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400177 frameIndentSize.pack(side=TOP, fill=X)
178 labelSpaceNumTitle.pack(side=TOP, anchor=W, padx=5)
179 self.scaleSpaceNum.pack(side=TOP, padx=5, fill=X)
Steven M. Gava952d0a52001-08-03 04:43:44 +0000180 return frame
181
182 def CreatePageHighlight(self):
Terry Jan Reedy22405332014-07-30 19:24:32 -0400183 parent = self.parent
184 self.builtinTheme = StringVar(parent)
185 self.customTheme = StringVar(parent)
186 self.fgHilite = BooleanVar(parent)
187 self.colour = StringVar(parent)
188 self.fontName = StringVar(parent)
189 self.themeIsBuiltin = BooleanVar(parent)
190 self.highlightTarget = StringVar(parent)
191
Steven M. Gava952d0a52001-08-03 04:43:44 +0000192 ##widget creation
193 #body frame
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400194 frame = self.tabPages.pages['Highlighting'].frame
Steven M. Gava952d0a52001-08-03 04:43:44 +0000195 #body section frames
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400196 frameCustom = LabelFrame(frame, borderwidth=2, relief=GROOVE,
197 text=' Custom Highlighting ')
198 frameTheme = LabelFrame(frame, borderwidth=2, relief=GROOVE,
199 text=' Highlighting Theme ')
Steven M. Gava952d0a52001-08-03 04:43:44 +0000200 #frameCustom
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400201 self.textHighlightSample=Text(
202 frameCustom, relief=SOLID, borderwidth=1,
203 font=('courier', 12, ''), cursor='hand2', width=21, height=11,
204 takefocus=FALSE, highlightthickness=0, wrap=NONE)
Steven M. Gavae16d94b2001-11-03 05:07:28 +0000205 text=self.textHighlightSample
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400206 text.bind('<Double-Button-1>', lambda e: 'break')
207 text.bind('<B1-Motion>', lambda e: 'break')
208 textAndTags=(
209 ('#you can click here', 'comment'), ('\n', 'normal'),
210 ('#to choose items', 'comment'), ('\n', 'normal'),
211 ('def', 'keyword'), (' ', 'normal'),
212 ('func', 'definition'), ('(param):\n ', 'normal'),
213 ('"""string"""', 'string'), ('\n var0 = ', 'normal'),
214 ("'string'", 'string'), ('\n var1 = ', 'normal'),
215 ("'selected'", 'hilite'), ('\n var2 = ', 'normal'),
216 ("'found'", 'hit'), ('\n var3 = ', 'normal'),
217 ('list', 'builtin'), ('(', 'normal'),
Terry Jan Reedya8aa4d52015-10-02 22:12:17 -0400218 ('None', 'keyword'), (')\n', 'normal'),
219 (' breakpoint("line")', 'break'), ('\n\n', 'normal'),
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400220 (' error ', 'error'), (' ', 'normal'),
221 ('cursor |', 'cursor'), ('\n ', 'normal'),
222 ('shell', 'console'), (' ', 'normal'),
223 ('stdout', 'stdout'), (' ', 'normal'),
224 ('stderr', 'stderr'), ('\n', 'normal'))
Steven M. Gava9dd16b32001-11-03 14:54:25 +0000225 for txTa in textAndTags:
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400226 text.insert(END, txTa[0], txTa[1])
Kurt B. Kaisere0712772007-08-23 05:25:55 +0000227 for element in self.themeElements:
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400228 def tem(event, elem=element):
229 event.widget.winfo_toplevel().highlightTarget.set(elem)
230 text.tag_bind(
231 self.themeElements[element][0], '<ButtonPress-1>', tem)
Steven M. Gavae16d94b2001-11-03 05:07:28 +0000232 text.config(state=DISABLED)
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400233 self.frameColourSet = Frame(frameCustom, relief=SOLID, borderwidth=1)
234 frameFgBg = Frame(frameCustom)
235 buttonSetColour = Button(
236 self.frameColourSet, text='Choose Colour for :',
237 command=self.GetColour, highlightthickness=0)
238 self.optMenuHighlightTarget = DynOptionMenu(
239 self.frameColourSet, self.highlightTarget, None,
240 highlightthickness=0) #, command=self.SetHighlightTargetBinding
241 self.radioFg = Radiobutton(
242 frameFgBg, variable=self.fgHilite, value=1,
243 text='Foreground', command=self.SetColourSampleBinding)
244 self.radioBg=Radiobutton(
245 frameFgBg, variable=self.fgHilite, value=0,
246 text='Background', command=self.SetColourSampleBinding)
Steven M. Gava7c017862001-10-29 11:19:46 +0000247 self.fgHilite.set(1)
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400248 buttonSaveCustomTheme = Button(
249 frameCustom, text='Save as New Custom Theme',
250 command=self.SaveAsNewTheme)
Steven M. Gava952d0a52001-08-03 04:43:44 +0000251 #frameTheme
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400252 labelTypeTitle = Label(frameTheme, text='Select : ')
253 self.radioThemeBuiltin = Radiobutton(
254 frameTheme, variable=self.themeIsBuiltin, value=1,
255 command=self.SetThemeType, text='a Built-in Theme')
256 self.radioThemeCustom = Radiobutton(
257 frameTheme, variable=self.themeIsBuiltin, value=0,
258 command=self.SetThemeType, text='a Custom Theme')
259 self.optMenuThemeBuiltin = DynOptionMenu(
260 frameTheme, self.builtinTheme, None, command=None)
261 self.optMenuThemeCustom=DynOptionMenu(
262 frameTheme, self.customTheme, None, command=None)
263 self.buttonDeleteCustomTheme=Button(
264 frameTheme, text='Delete Custom Theme',
Steven M. Gava49745752002-02-18 01:43:11 +0000265 command=self.DeleteCustomTheme)
Terry Jan Reedyd0c0f002015-11-12 15:02:57 -0500266 self.new_custom_theme = Label(frameTheme, bd=2)
Terry Jan Reedy22405332014-07-30 19:24:32 -0400267
Steven M. Gava952d0a52001-08-03 04:43:44 +0000268 ##widget packing
269 #body
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400270 frameCustom.pack(side=LEFT, padx=5, pady=5, expand=TRUE, fill=BOTH)
271 frameTheme.pack(side=LEFT, padx=5, pady=5, fill=Y)
Steven M. Gava952d0a52001-08-03 04:43:44 +0000272 #frameCustom
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400273 self.frameColourSet.pack(side=TOP, padx=5, pady=5, expand=TRUE, fill=X)
274 frameFgBg.pack(side=TOP, padx=5, pady=0)
275 self.textHighlightSample.pack(
276 side=TOP, padx=5, pady=5, expand=TRUE, fill=BOTH)
277 buttonSetColour.pack(side=TOP, expand=TRUE, fill=X, padx=8, pady=4)
278 self.optMenuHighlightTarget.pack(
279 side=TOP, expand=TRUE, fill=X, padx=8, pady=3)
280 self.radioFg.pack(side=LEFT, anchor=E)
281 self.radioBg.pack(side=RIGHT, anchor=W)
282 buttonSaveCustomTheme.pack(side=BOTTOM, fill=X, padx=5, pady=5)
Steven M. Gava952d0a52001-08-03 04:43:44 +0000283 #frameTheme
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400284 labelTypeTitle.pack(side=TOP, anchor=W, padx=5, pady=5)
285 self.radioThemeBuiltin.pack(side=TOP, anchor=W, padx=5)
286 self.radioThemeCustom.pack(side=TOP, anchor=W, padx=5, pady=2)
287 self.optMenuThemeBuiltin.pack(side=TOP, fill=X, padx=5, pady=5)
288 self.optMenuThemeCustom.pack(side=TOP, fill=X, anchor=W, padx=5, pady=5)
289 self.buttonDeleteCustomTheme.pack(side=TOP, fill=X, padx=5, pady=5)
Terry Jan Reedyd0c0f002015-11-12 15:02:57 -0500290 self.new_custom_theme.pack(side=TOP, fill=X, pady=5)
Steven M. Gava952d0a52001-08-03 04:43:44 +0000291 return frame
292
293 def CreatePageKeys(self):
Terry Jan Reedy22405332014-07-30 19:24:32 -0400294 parent = self.parent
295 self.bindingTarget = StringVar(parent)
296 self.builtinKeys = StringVar(parent)
297 self.customKeys = StringVar(parent)
298 self.keysAreBuiltin = BooleanVar(parent)
299 self.keyBinding = StringVar(parent)
300
Steven M. Gava60fc7072001-08-04 13:58:22 +0000301 ##widget creation
302 #body frame
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400303 frame = self.tabPages.pages['Keys'].frame
Steven M. Gava60fc7072001-08-04 13:58:22 +0000304 #body section frames
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400305 frameCustom = LabelFrame(
306 frame, borderwidth=2, relief=GROOVE,
307 text=' Custom Key Bindings ')
308 frameKeySets = LabelFrame(
309 frame, borderwidth=2, relief=GROOVE, text=' Key Set ')
Steven M. Gava60fc7072001-08-04 13:58:22 +0000310 #frameCustom
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400311 frameTarget = Frame(frameCustom)
312 labelTargetTitle = Label(frameTarget, text='Action - Key(s)')
313 scrollTargetY = Scrollbar(frameTarget)
314 scrollTargetX = Scrollbar(frameTarget, orient=HORIZONTAL)
315 self.listBindings = Listbox(
316 frameTarget, takefocus=FALSE, exportselection=FALSE)
317 self.listBindings.bind('<ButtonRelease-1>', self.KeyBindingSelected)
Steven M. Gavafacfc092002-01-19 00:29:54 +0000318 scrollTargetY.config(command=self.listBindings.yview)
319 scrollTargetX.config(command=self.listBindings.xview)
320 self.listBindings.config(yscrollcommand=scrollTargetY.set)
321 self.listBindings.config(xscrollcommand=scrollTargetX.set)
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400322 self.buttonNewKeys = Button(
323 frameCustom, text='Get New Keys for Selection',
324 command=self.GetNewKeys, state=DISABLED)
Steven M. Gava60fc7072001-08-04 13:58:22 +0000325 #frameKeySets
Christian Heimes9a371592007-12-28 14:08:13 +0000326 frames = [Frame(frameKeySets, padx=2, pady=2, borderwidth=0)
327 for i in range(2)]
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400328 self.radioKeysBuiltin = Radiobutton(
329 frames[0], variable=self.keysAreBuiltin, value=1,
330 command=self.SetKeysType, text='Use a Built-in Key Set')
331 self.radioKeysCustom = Radiobutton(
332 frames[0], variable=self.keysAreBuiltin, value=0,
333 command=self.SetKeysType, text='Use a Custom Key Set')
334 self.optMenuKeysBuiltin = DynOptionMenu(
335 frames[0], self.builtinKeys, None, command=None)
336 self.optMenuKeysCustom = DynOptionMenu(
337 frames[0], self.customKeys, None, command=None)
338 self.buttonDeleteCustomKeys = Button(
339 frames[1], text='Delete Custom Key Set',
Steven M. Gava49745752002-02-18 01:43:11 +0000340 command=self.DeleteCustomKeys)
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400341 buttonSaveCustomKeys = Button(
342 frames[1], text='Save as New Custom Key Set',
343 command=self.SaveAsNewKeySet)
Terry Jan Reedy9bdb1ed2016-07-10 13:46:34 -0400344 self.new_custom_keys = Label(frames[0], bd=2)
Terry Jan Reedy22405332014-07-30 19:24:32 -0400345
Steven M. Gava60fc7072001-08-04 13:58:22 +0000346 ##widget packing
347 #body
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400348 frameCustom.pack(side=BOTTOM, padx=5, pady=5, expand=TRUE, fill=BOTH)
349 frameKeySets.pack(side=BOTTOM, padx=5, pady=5, fill=BOTH)
Steven M. Gava60fc7072001-08-04 13:58:22 +0000350 #frameCustom
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400351 self.buttonNewKeys.pack(side=BOTTOM, fill=X, padx=5, pady=5)
352 frameTarget.pack(side=LEFT, padx=5, pady=5, expand=TRUE, fill=BOTH)
Steven M. Gavafacfc092002-01-19 00:29:54 +0000353 #frame target
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400354 frameTarget.columnconfigure(0, weight=1)
355 frameTarget.rowconfigure(1, weight=1)
356 labelTargetTitle.grid(row=0, column=0, columnspan=2, sticky=W)
357 self.listBindings.grid(row=1, column=0, sticky=NSEW)
358 scrollTargetY.grid(row=1, column=1, sticky=NS)
359 scrollTargetX.grid(row=2, column=0, sticky=EW)
Steven M. Gava60fc7072001-08-04 13:58:22 +0000360 #frameKeySets
Christian Heimes9a371592007-12-28 14:08:13 +0000361 self.radioKeysBuiltin.grid(row=0, column=0, sticky=W+NS)
362 self.radioKeysCustom.grid(row=1, column=0, sticky=W+NS)
363 self.optMenuKeysBuiltin.grid(row=0, column=1, sticky=NSEW)
364 self.optMenuKeysCustom.grid(row=1, column=1, sticky=NSEW)
Terry Jan Reedy9bdb1ed2016-07-10 13:46:34 -0400365 self.new_custom_keys.grid(row=0, column=2, sticky=NSEW, padx=5, pady=5)
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400366 self.buttonDeleteCustomKeys.pack(side=LEFT, fill=X, expand=True, padx=2)
367 buttonSaveCustomKeys.pack(side=LEFT, fill=X, expand=True, padx=2)
Christian Heimes9a371592007-12-28 14:08:13 +0000368 frames[0].pack(side=TOP, fill=BOTH, expand=True)
369 frames[1].pack(side=TOP, fill=X, expand=True, pady=2)
Steven M. Gava952d0a52001-08-03 04:43:44 +0000370 return frame
371
372 def CreatePageGeneral(self):
Terry Jan Reedy22405332014-07-30 19:24:32 -0400373 parent = self.parent
374 self.winWidth = StringVar(parent)
375 self.winHeight = StringVar(parent)
Terry Jan Reedy22405332014-07-30 19:24:32 -0400376 self.startupEdit = IntVar(parent)
377 self.autoSave = IntVar(parent)
378 self.encoding = StringVar(parent)
379 self.userHelpBrowser = BooleanVar(parent)
380 self.helpBrowser = StringVar(parent)
381
Steven M. Gava230e5782001-08-07 03:28:25 +0000382 #widget creation
383 #body
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400384 frame = self.tabPages.pages['General'].frame
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000385 #body section frames
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400386 frameRun = LabelFrame(frame, borderwidth=2, relief=GROOVE,
387 text=' Startup Preferences ')
388 frameSave = LabelFrame(frame, borderwidth=2, relief=GROOVE,
389 text=' Autosave Preferences ')
390 frameWinSize = Frame(frame, borderwidth=2, relief=GROOVE)
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400391 frameHelp = LabelFrame(frame, borderwidth=2, relief=GROOVE,
392 text=' Additional Help Sources ')
Steven M. Gava230e5782001-08-07 03:28:25 +0000393 #frameRun
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400394 labelRunChoiceTitle = Label(frameRun, text='At Startup')
Terry Jan Reedyf46b7822016-11-07 17:15:01 -0500395 self.radioStartupEdit = Radiobutton(
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400396 frameRun, variable=self.startupEdit, value=1,
Terry Jan Reedyf46b7822016-11-07 17:15:01 -0500397 text="Open Edit Window")
398 self.radioStartupShell = Radiobutton(
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400399 frameRun, variable=self.startupEdit, value=0,
Terry Jan Reedyf46b7822016-11-07 17:15:01 -0500400 text='Open Shell Window')
Kurt B. Kaiser6c638b62003-05-26 06:23:10 +0000401 #frameSave
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400402 labelRunSaveTitle = Label(frameSave, text='At Start of Run (F5) ')
Terry Jan Reedyf46b7822016-11-07 17:15:01 -0500403 self.radioSaveAsk = Radiobutton(
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400404 frameSave, variable=self.autoSave, value=0,
Terry Jan Reedyf46b7822016-11-07 17:15:01 -0500405 text="Prompt to Save")
406 self.radioSaveAuto = Radiobutton(
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400407 frameSave, variable=self.autoSave, value=1,
Terry Jan Reedyf46b7822016-11-07 17:15:01 -0500408 text='No Prompt')
Steven M. Gava230e5782001-08-07 03:28:25 +0000409 #frameWinSize
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400410 labelWinSizeTitle = Label(
411 frameWinSize, text='Initial Window Size (in characters)')
412 labelWinWidthTitle = Label(frameWinSize, text='Width')
Terry Jan Reedyf46b7822016-11-07 17:15:01 -0500413 self.entryWinWidth = Entry(
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400414 frameWinSize, textvariable=self.winWidth, width=3)
415 labelWinHeightTitle = Label(frameWinSize, text='Height')
Terry Jan Reedyf46b7822016-11-07 17:15:01 -0500416 self.entryWinHeight = Entry(
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400417 frameWinSize, textvariable=self.winHeight, width=3)
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000418 #frameHelp
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400419 frameHelpList = Frame(frameHelp)
420 frameHelpListButtons = Frame(frameHelpList)
421 scrollHelpList = Scrollbar(frameHelpList)
422 self.listHelp = Listbox(
423 frameHelpList, height=5, takefocus=FALSE,
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000424 exportselection=FALSE)
425 scrollHelpList.config(command=self.listHelp.yview)
426 self.listHelp.config(yscrollcommand=scrollHelpList.set)
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400427 self.listHelp.bind('<ButtonRelease-1>', self.HelpSourceSelected)
428 self.buttonHelpListEdit = Button(
429 frameHelpListButtons, text='Edit', state=DISABLED,
430 width=8, command=self.HelpListItemEdit)
431 self.buttonHelpListAdd = Button(
432 frameHelpListButtons, text='Add',
433 width=8, command=self.HelpListItemAdd)
434 self.buttonHelpListRemove = Button(
435 frameHelpListButtons, text='Remove', state=DISABLED,
436 width=8, command=self.HelpListItemRemove)
Terry Jan Reedy22405332014-07-30 19:24:32 -0400437
Steven M. Gava230e5782001-08-07 03:28:25 +0000438 #widget packing
439 #body
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400440 frameRun.pack(side=TOP, padx=5, pady=5, fill=X)
441 frameSave.pack(side=TOP, padx=5, pady=5, fill=X)
442 frameWinSize.pack(side=TOP, padx=5, pady=5, fill=X)
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400443 frameHelp.pack(side=TOP, padx=5, pady=5, expand=TRUE, fill=BOTH)
Steven M. Gava230e5782001-08-07 03:28:25 +0000444 #frameRun
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400445 labelRunChoiceTitle.pack(side=LEFT, anchor=W, padx=5, pady=5)
Terry Jan Reedyf46b7822016-11-07 17:15:01 -0500446 self.radioStartupShell.pack(side=RIGHT, anchor=W, padx=5, pady=5)
447 self.radioStartupEdit.pack(side=RIGHT, anchor=W, padx=5, pady=5)
Kurt B. Kaiser6c638b62003-05-26 06:23:10 +0000448 #frameSave
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400449 labelRunSaveTitle.pack(side=LEFT, anchor=W, padx=5, pady=5)
Terry Jan Reedyf46b7822016-11-07 17:15:01 -0500450 self.radioSaveAuto.pack(side=RIGHT, anchor=W, padx=5, pady=5)
451 self.radioSaveAsk.pack(side=RIGHT, anchor=W, padx=5, pady=5)
Steven M. Gava230e5782001-08-07 03:28:25 +0000452 #frameWinSize
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400453 labelWinSizeTitle.pack(side=LEFT, anchor=W, padx=5, pady=5)
Terry Jan Reedyf46b7822016-11-07 17:15:01 -0500454 self.entryWinHeight.pack(side=RIGHT, anchor=E, padx=10, pady=5)
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400455 labelWinHeightTitle.pack(side=RIGHT, anchor=E, pady=5)
Terry Jan Reedyf46b7822016-11-07 17:15:01 -0500456 self.entryWinWidth.pack(side=RIGHT, anchor=E, padx=10, pady=5)
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400457 labelWinWidthTitle.pack(side=RIGHT, anchor=E, pady=5)
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000458 #frameHelp
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400459 frameHelpListButtons.pack(side=RIGHT, padx=5, pady=5, fill=Y)
460 frameHelpList.pack(side=TOP, padx=5, pady=5, expand=TRUE, fill=BOTH)
461 scrollHelpList.pack(side=RIGHT, anchor=W, fill=Y)
462 self.listHelp.pack(side=LEFT, anchor=E, expand=TRUE, fill=BOTH)
463 self.buttonHelpListEdit.pack(side=TOP, anchor=W, pady=5)
464 self.buttonHelpListAdd.pack(side=TOP, anchor=W)
465 self.buttonHelpListRemove.pack(side=TOP, anchor=W, pady=5)
Steven M. Gava952d0a52001-08-03 04:43:44 +0000466 return frame
467
Steven M. Gavac112cd82002-01-22 05:56:40 +0000468 def AttachVarCallbacks(self):
Serhiy Storchaka81221742016-06-26 09:46:57 +0300469 self.fontSize.trace_add('write', self.VarChanged_font)
470 self.fontName.trace_add('write', self.VarChanged_font)
471 self.fontBold.trace_add('write', self.VarChanged_font)
472 self.spaceNum.trace_add('write', self.VarChanged_spaceNum)
473 self.colour.trace_add('write', self.VarChanged_colour)
474 self.builtinTheme.trace_add('write', self.VarChanged_builtinTheme)
475 self.customTheme.trace_add('write', self.VarChanged_customTheme)
476 self.themeIsBuiltin.trace_add('write', self.VarChanged_themeIsBuiltin)
477 self.highlightTarget.trace_add('write', self.VarChanged_highlightTarget)
478 self.keyBinding.trace_add('write', self.VarChanged_keyBinding)
479 self.builtinKeys.trace_add('write', self.VarChanged_builtinKeys)
480 self.customKeys.trace_add('write', self.VarChanged_customKeys)
481 self.keysAreBuiltin.trace_add('write', self.VarChanged_keysAreBuiltin)
482 self.winWidth.trace_add('write', self.VarChanged_winWidth)
483 self.winHeight.trace_add('write', self.VarChanged_winHeight)
484 self.startupEdit.trace_add('write', self.VarChanged_startupEdit)
485 self.autoSave.trace_add('write', self.VarChanged_autoSave)
486 self.encoding.trace_add('write', self.VarChanged_encoding)
Steven M. Gava052937f2002-02-11 02:20:53 +0000487
Terry Jan Reedy6b98ce22016-05-16 22:27:28 -0400488 def remove_var_callbacks(self):
489 "Remove callbacks to prevent memory leaks."
490 for var in (
491 self.fontSize, self.fontName, self.fontBold,
492 self.spaceNum, self.colour, self.builtinTheme,
493 self.customTheme, self.themeIsBuiltin, self.highlightTarget,
494 self.keyBinding, self.builtinKeys, self.customKeys,
495 self.keysAreBuiltin, self.winWidth, self.winHeight,
496 self.startupEdit, self.autoSave, self.encoding,):
Serhiy Storchaka81221742016-06-26 09:46:57 +0300497 var.trace_remove('write', var.trace_info()[0][1])
Terry Jan Reedy6b98ce22016-05-16 22:27:28 -0400498
Terry Jan Reedyd87d1682015-08-01 18:57:33 -0400499 def VarChanged_font(self, *params):
500 '''When one font attribute changes, save them all, as they are
501 not independent from each other. In particular, when we are
502 overriding the default font, we need to write out everything.
503 '''
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400504 value = self.fontName.get()
505 self.AddChangedItem('main', 'EditorWindow', 'font', value)
Terry Jan Reedyd87d1682015-08-01 18:57:33 -0400506 value = self.fontSize.get()
507 self.AddChangedItem('main', 'EditorWindow', 'font-size', value)
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400508 value = self.fontBold.get()
509 self.AddChangedItem('main', 'EditorWindow', 'font-bold', value)
Steven M. Gavac112cd82002-01-22 05:56:40 +0000510
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400511 def VarChanged_spaceNum(self, *params):
512 value = self.spaceNum.get()
513 self.AddChangedItem('main', 'Indent', 'num-spaces', value)
Steven M. Gavac112cd82002-01-22 05:56:40 +0000514
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400515 def VarChanged_colour(self, *params):
Steven M. Gava052937f2002-02-11 02:20:53 +0000516 self.OnNewColourSet()
517
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400518 def VarChanged_builtinTheme(self, *params):
Terry Jan Reedy9bdb1ed2016-07-10 13:46:34 -0400519 oldthemes = ('IDLE Classic', 'IDLE New')
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400520 value = self.builtinTheme.get()
Terry Jan Reedy9bdb1ed2016-07-10 13:46:34 -0400521 if value not in oldthemes:
522 if idleConf.GetOption('main', 'Theme', 'name') not in oldthemes:
523 self.AddChangedItem('main', 'Theme', 'name', oldthemes[0])
Terry Jan Reedyd0c0f002015-11-12 15:02:57 -0500524 self.AddChangedItem('main', 'Theme', 'name2', value)
525 self.new_custom_theme.config(text='New theme, see Help',
526 fg='#500000')
527 else:
528 self.AddChangedItem('main', 'Theme', 'name', value)
529 self.AddChangedItem('main', 'Theme', 'name2', '')
530 self.new_custom_theme.config(text='', fg='black')
Steven M. Gava052937f2002-02-11 02:20:53 +0000531 self.PaintThemeSample()
532
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400533 def VarChanged_customTheme(self, *params):
534 value = self.customTheme.get()
Steven M. Gava49745752002-02-18 01:43:11 +0000535 if value != '- no custom themes -':
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400536 self.AddChangedItem('main', 'Theme', 'name', value)
Steven M. Gava49745752002-02-18 01:43:11 +0000537 self.PaintThemeSample()
Steven M. Gava052937f2002-02-11 02:20:53 +0000538
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400539 def VarChanged_themeIsBuiltin(self, *params):
540 value = self.themeIsBuiltin.get()
541 self.AddChangedItem('main', 'Theme', 'default', value)
Steven M. Gavaf31eec02002-03-05 00:25:58 +0000542 if value:
543 self.VarChanged_builtinTheme()
544 else:
545 self.VarChanged_customTheme()
Steven M. Gava052937f2002-02-11 02:20:53 +0000546
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400547 def VarChanged_highlightTarget(self, *params):
Steven M. Gava052937f2002-02-11 02:20:53 +0000548 self.SetHighlightTarget()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000549
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400550 def VarChanged_keyBinding(self, *params):
551 value = self.keyBinding.get()
552 keySet = self.customKeys.get()
553 event = self.listBindings.get(ANCHOR).split()[0]
Steven M. Gavaa498af22002-02-01 01:33:36 +0000554 if idleConf.IsCoreBinding(event):
555 #this is a core keybinding
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400556 self.AddChangedItem('keys', keySet, event, value)
Steven M. Gavaa498af22002-02-01 01:33:36 +0000557 else: #this is an extension key binding
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400558 extName = idleConf.GetExtnNameForEvent(event)
559 extKeybindSection = extName + '_cfgBindings'
560 self.AddChangedItem('extensions', extKeybindSection, event, value)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000561
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400562 def VarChanged_builtinKeys(self, *params):
Terry Jan Reedy9bdb1ed2016-07-10 13:46:34 -0400563 oldkeys = (
564 'IDLE Classic Windows',
565 'IDLE Classic Unix',
566 'IDLE Classic Mac',
567 'IDLE Classic OSX',
568 )
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400569 value = self.builtinKeys.get()
Terry Jan Reedy9bdb1ed2016-07-10 13:46:34 -0400570 if value not in oldkeys:
571 if idleConf.GetOption('main', 'Keys', 'name') not in oldkeys:
572 self.AddChangedItem('main', 'Keys', 'name', oldkeys[0])
573 self.AddChangedItem('main', 'Keys', 'name2', value)
574 self.new_custom_keys.config(text='New key set, see Help',
575 fg='#500000')
576 else:
577 self.AddChangedItem('main', 'Keys', 'name', value)
578 self.AddChangedItem('main', 'Keys', 'name2', '')
579 self.new_custom_keys.config(text='', fg='black')
Steven M. Gava052937f2002-02-11 02:20:53 +0000580 self.LoadKeysList(value)
581
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400582 def VarChanged_customKeys(self, *params):
583 value = self.customKeys.get()
Steven M. Gava49745752002-02-18 01:43:11 +0000584 if value != '- no custom keys -':
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400585 self.AddChangedItem('main', 'Keys', 'name', value)
Steven M. Gava49745752002-02-18 01:43:11 +0000586 self.LoadKeysList(value)
Steven M. Gava052937f2002-02-11 02:20:53 +0000587
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400588 def VarChanged_keysAreBuiltin(self, *params):
589 value = self.keysAreBuiltin.get()
590 self.AddChangedItem('main', 'Keys', 'default', value)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000591 if value:
Steven M. Gavaf31eec02002-03-05 00:25:58 +0000592 self.VarChanged_builtinKeys()
Steven M. Gava052937f2002-02-11 02:20:53 +0000593 else:
Steven M. Gavaf31eec02002-03-05 00:25:58 +0000594 self.VarChanged_customKeys()
Steven M. Gava052937f2002-02-11 02:20:53 +0000595
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400596 def VarChanged_winWidth(self, *params):
597 value = self.winWidth.get()
598 self.AddChangedItem('main', 'EditorWindow', 'width', value)
Steven M. Gavac112cd82002-01-22 05:56:40 +0000599
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400600 def VarChanged_winHeight(self, *params):
601 value = self.winHeight.get()
602 self.AddChangedItem('main', 'EditorWindow', 'height', value)
Steven M. Gavac112cd82002-01-22 05:56:40 +0000603
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400604 def VarChanged_startupEdit(self, *params):
605 value = self.startupEdit.get()
606 self.AddChangedItem('main', 'General', 'editor-on-startup', value)
Steven M. Gavac112cd82002-01-22 05:56:40 +0000607
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400608 def VarChanged_autoSave(self, *params):
609 value = self.autoSave.get()
610 self.AddChangedItem('main', 'General', 'autosave', value)
Kurt B. Kaiser6c638b62003-05-26 06:23:10 +0000611
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400612 def VarChanged_encoding(self, *params):
613 value = self.encoding.get()
614 self.AddChangedItem('main', 'EditorWindow', 'encoding', value)
Kurt B. Kaisera053f332003-05-10 00:49:56 +0000615
Steven M. Gavaa498af22002-02-01 01:33:36 +0000616 def ResetChangedItems(self):
Steven M. Gavab77d3432002-03-02 07:16:21 +0000617 #When any config item is changed in this dialog, an entry
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000618 #should be made in the relevant section (config type) of this
619 #dictionary. The key should be the config file section name and the
Steven M. Gavaa498af22002-02-01 01:33:36 +0000620 #value a dictionary, whose key:value pairs are item=value pairs for
621 #that config file section.
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400622 self.changedItems = {'main':{}, 'highlight':{}, 'keys':{},
623 'extensions':{}}
Steven M. Gavaa498af22002-02-01 01:33:36 +0000624
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400625 def AddChangedItem(self, typ, section, item, value):
626 value = str(value) #make sure we use a string
627 if section not in self.changedItems[typ]:
628 self.changedItems[typ][section] = {}
629 self.changedItems[typ][section][item] = value
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000630
Steven M. Gava5f28e8f2002-01-21 06:38:21 +0000631 def GetDefaultItems(self):
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400632 dItems={'main':{}, 'highlight':{}, 'keys':{}, 'extensions':{}}
Kurt B. Kaisere0712772007-08-23 05:25:55 +0000633 for configType in dItems:
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400634 sections = idleConf.GetSectionList('default', configType)
Steven M. Gava5f28e8f2002-01-21 06:38:21 +0000635 for section in sections:
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400636 dItems[configType][section] = {}
637 options = idleConf.defaultCfg[configType].GetOptionList(section)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000638 for option in options:
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400639 dItems[configType][section][option] = (
640 idleConf.defaultCfg[configType].Get(section, option))
Steven M. Gava5f28e8f2002-01-21 06:38:21 +0000641 return dItems
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000642
Steven M. Gava5f28e8f2002-01-21 06:38:21 +0000643 def SetThemeType(self):
644 if self.themeIsBuiltin.get():
645 self.optMenuThemeBuiltin.config(state=NORMAL)
646 self.optMenuThemeCustom.config(state=DISABLED)
647 self.buttonDeleteCustomTheme.config(state=DISABLED)
648 else:
649 self.optMenuThemeBuiltin.config(state=DISABLED)
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000650 self.radioThemeCustom.config(state=NORMAL)
Steven M. Gava5f28e8f2002-01-21 06:38:21 +0000651 self.optMenuThemeCustom.config(state=NORMAL)
652 self.buttonDeleteCustomTheme.config(state=NORMAL)
653
654 def SetKeysType(self):
Steven M. Gava052937f2002-02-11 02:20:53 +0000655 if self.keysAreBuiltin.get():
Steven M. Gava5f28e8f2002-01-21 06:38:21 +0000656 self.optMenuKeysBuiltin.config(state=NORMAL)
657 self.optMenuKeysCustom.config(state=DISABLED)
658 self.buttonDeleteCustomKeys.config(state=DISABLED)
659 else:
660 self.optMenuKeysBuiltin.config(state=DISABLED)
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000661 self.radioKeysCustom.config(state=NORMAL)
Steven M. Gava5f28e8f2002-01-21 06:38:21 +0000662 self.optMenuKeysCustom.config(state=NORMAL)
663 self.buttonDeleteCustomKeys.config(state=NORMAL)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000664
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000665 def GetNewKeys(self):
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400666 listIndex = self.listBindings.index(ANCHOR)
667 binding = self.listBindings.get(listIndex)
668 bindName = binding.split()[0] #first part, up to first space
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000669 if self.keysAreBuiltin.get():
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400670 currentKeySetName = self.builtinKeys.get()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000671 else:
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400672 currentKeySetName = self.customKeys.get()
673 currentBindings = idleConf.GetCurrentKeySet()
Kurt B. Kaisere0712772007-08-23 05:25:55 +0000674 if currentKeySetName in self.changedItems['keys']: #unsaved changes
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400675 keySetChanges = self.changedItems['keys'][currentKeySetName]
Kurt B. Kaisere0712772007-08-23 05:25:55 +0000676 for event in keySetChanges:
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400677 currentBindings[event] = keySetChanges[event].split()
Kurt B. Kaisere0712772007-08-23 05:25:55 +0000678 currentKeySequences = list(currentBindings.values())
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400679 newKeys = GetKeysDialog(self, 'Get New Keys', bindName,
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000680 currentKeySequences).result
681 if newKeys: #new keys were specified
Steven M. Gava052937f2002-02-11 02:20:53 +0000682 if self.keysAreBuiltin.get(): #current key set is a built-in
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400683 message = ('Your changes will be saved as a new Custom Key Set.'
684 ' Enter a name for your new Custom Key Set below.')
685 newKeySet = self.GetNewKeysName(message)
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000686 if not newKeySet: #user cancelled custom key set creation
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000687 self.listBindings.select_set(listIndex)
688 self.listBindings.select_anchor(listIndex)
689 return
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000690 else: #create new custom key set based on previously active key set
691 self.CreateNewKeySet(newKeySet)
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000692 self.listBindings.delete(listIndex)
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400693 self.listBindings.insert(listIndex, bindName+' - '+newKeys)
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000694 self.listBindings.select_set(listIndex)
695 self.listBindings.select_anchor(listIndex)
Steven M. Gava052937f2002-02-11 02:20:53 +0000696 self.keyBinding.set(newKeys)
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000697 else:
698 self.listBindings.select_set(listIndex)
699 self.listBindings.select_anchor(listIndex)
700
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400701 def GetNewKeysName(self, message):
702 usedNames = (idleConf.GetSectionList('user', 'keys') +
703 idleConf.GetSectionList('default', 'keys'))
Terry Jan Reedy68a53c52016-06-26 22:05:10 -0400704 newKeySet = SectionName(
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400705 self, 'New Custom Key Set', message, usedNames).result
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000706 return newKeySet
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000707
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000708 def SaveAsNewKeySet(self):
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400709 newKeysName = self.GetNewKeysName('New Key Set Name:')
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000710 if newKeysName:
711 self.CreateNewKeySet(newKeysName)
712
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400713 def KeyBindingSelected(self, event):
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000714 self.buttonNewKeys.config(state=NORMAL)
715
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400716 def CreateNewKeySet(self, newKeySetName):
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000717 #creates new custom key set based on the previously active key set,
718 #and makes the new key set active
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000719 if self.keysAreBuiltin.get():
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400720 prevKeySetName = self.builtinKeys.get()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000721 else:
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400722 prevKeySetName = self.customKeys.get()
723 prevKeys = idleConf.GetCoreKeys(prevKeySetName)
724 newKeys = {}
Kurt B. Kaisere0712772007-08-23 05:25:55 +0000725 for event in prevKeys: #add key set to changed items
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400726 eventName = event[2:-2] #trim off the angle brackets
727 binding = ' '.join(prevKeys[event])
728 newKeys[eventName] = binding
Steven M. Gava052937f2002-02-11 02:20:53 +0000729 #handle any unsaved changes to prev key set
Kurt B. Kaisere0712772007-08-23 05:25:55 +0000730 if prevKeySetName in self.changedItems['keys']:
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400731 keySetChanges = self.changedItems['keys'][prevKeySetName]
Kurt B. Kaisere0712772007-08-23 05:25:55 +0000732 for event in keySetChanges:
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400733 newKeys[event] = keySetChanges[event]
Steven M. Gava052937f2002-02-11 02:20:53 +0000734 #save the new theme
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400735 self.SaveNewKeySet(newKeySetName, newKeys)
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000736 #change gui over to the new key set
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400737 customKeyList = idleConf.GetSectionList('user', 'keys')
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000738 customKeyList.sort()
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400739 self.optMenuKeysCustom.SetMenu(customKeyList, newKeySetName)
Steven M. Gava052937f2002-02-11 02:20:53 +0000740 self.keysAreBuiltin.set(0)
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000741 self.SetKeysType()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000742
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400743 def LoadKeysList(self, keySetName):
744 reselect = 0
745 newKeySet = 0
Steven M. Gava052937f2002-02-11 02:20:53 +0000746 if self.listBindings.curselection():
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400747 reselect = 1
748 listIndex = self.listBindings.index(ANCHOR)
749 keySet = idleConf.GetKeySet(keySetName)
Kurt B. Kaisere0712772007-08-23 05:25:55 +0000750 bindNames = list(keySet.keys())
Steven M. Gava052937f2002-02-11 02:20:53 +0000751 bindNames.sort()
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400752 self.listBindings.delete(0, END)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000753 for bindName in bindNames:
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400754 key = ' '.join(keySet[bindName]) #make key(s) into a string
755 bindName = bindName[2:-2] #trim off the angle brackets
Kurt B. Kaisere0712772007-08-23 05:25:55 +0000756 if keySetName in self.changedItems['keys']:
Steven M. Gava052937f2002-02-11 02:20:53 +0000757 #handle any unsaved changes to this key set
Kurt B. Kaisere0712772007-08-23 05:25:55 +0000758 if bindName in self.changedItems['keys'][keySetName]:
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400759 key = self.changedItems['keys'][keySetName][bindName]
Steven M. Gava052937f2002-02-11 02:20:53 +0000760 self.listBindings.insert(END, bindName+' - '+key)
Steven M. Gava052937f2002-02-11 02:20:53 +0000761 if reselect:
762 self.listBindings.see(listIndex)
763 self.listBindings.select_set(listIndex)
764 self.listBindings.select_anchor(listIndex)
765
Steven M. Gava49745752002-02-18 01:43:11 +0000766 def DeleteCustomKeys(self):
767 keySetName=self.customKeys.get()
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400768 delmsg = 'Are you sure you wish to delete the key set %r ?'
769 if not tkMessageBox.askyesno(
770 'Delete Key Set', delmsg % keySetName, parent=self):
Steven M. Gava49745752002-02-18 01:43:11 +0000771 return
Terry Jan Reedyec844172016-06-14 00:53:25 -0400772 self.DeactivateCurrentConfig()
Steven M. Gava49745752002-02-18 01:43:11 +0000773 #remove key set from config
774 idleConf.userCfg['keys'].remove_section(keySetName)
Guido van Rossum811c4e02006-08-22 15:45:46 +0000775 if keySetName in self.changedItems['keys']:
Steven M. Gava49745752002-02-18 01:43:11 +0000776 del(self.changedItems['keys'][keySetName])
777 #write changes
778 idleConf.userCfg['keys'].Save()
779 #reload user key set list
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400780 itemList = idleConf.GetSectionList('user', 'keys')
Steven M. Gava49745752002-02-18 01:43:11 +0000781 itemList.sort()
782 if not itemList:
783 self.radioKeysCustom.config(state=DISABLED)
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400784 self.optMenuKeysCustom.SetMenu(itemList, '- no custom keys -')
Steven M. Gava49745752002-02-18 01:43:11 +0000785 else:
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400786 self.optMenuKeysCustom.SetMenu(itemList, itemList[0])
Steven M. Gava49745752002-02-18 01:43:11 +0000787 #revert to default key set
Terry Jan Reedy9bdb1ed2016-07-10 13:46:34 -0400788 self.keysAreBuiltin.set(idleConf.defaultCfg['main']
789 .Get('Keys', 'default'))
790 self.builtinKeys.set(idleConf.defaultCfg['main'].Get('Keys', 'name')
791 or idleConf.default_keys())
Steven M. Gava49745752002-02-18 01:43:11 +0000792 #user can't back out of these changes, they must be applied now
Terry Jan Reedyec844172016-06-14 00:53:25 -0400793 self.SaveAllChangedConfigs()
794 self.ActivateConfigChanges()
Steven M. Gava49745752002-02-18 01:43:11 +0000795 self.SetKeysType()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000796
Steven M. Gava49745752002-02-18 01:43:11 +0000797 def DeleteCustomTheme(self):
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400798 themeName = self.customTheme.get()
799 delmsg = 'Are you sure you wish to delete the theme %r ?'
800 if not tkMessageBox.askyesno(
801 'Delete Theme', delmsg % themeName, parent=self):
Steven M. Gava49745752002-02-18 01:43:11 +0000802 return
Terry Jan Reedyec844172016-06-14 00:53:25 -0400803 self.DeactivateCurrentConfig()
Steven M. Gava49745752002-02-18 01:43:11 +0000804 #remove theme from config
805 idleConf.userCfg['highlight'].remove_section(themeName)
Guido van Rossum811c4e02006-08-22 15:45:46 +0000806 if themeName in self.changedItems['highlight']:
Steven M. Gava49745752002-02-18 01:43:11 +0000807 del(self.changedItems['highlight'][themeName])
808 #write changes
809 idleConf.userCfg['highlight'].Save()
810 #reload user theme list
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400811 itemList = idleConf.GetSectionList('user', 'highlight')
Steven M. Gava49745752002-02-18 01:43:11 +0000812 itemList.sort()
813 if not itemList:
814 self.radioThemeCustom.config(state=DISABLED)
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400815 self.optMenuThemeCustom.SetMenu(itemList, '- no custom themes -')
Steven M. Gava49745752002-02-18 01:43:11 +0000816 else:
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400817 self.optMenuThemeCustom.SetMenu(itemList, itemList[0])
Steven M. Gava49745752002-02-18 01:43:11 +0000818 #revert to default theme
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400819 self.themeIsBuiltin.set(idleConf.defaultCfg['main'].Get('Theme', 'default'))
820 self.builtinTheme.set(idleConf.defaultCfg['main'].Get('Theme', 'name'))
Steven M. Gava49745752002-02-18 01:43:11 +0000821 #user can't back out of these changes, they must be applied now
Terry Jan Reedyec844172016-06-14 00:53:25 -0400822 self.SaveAllChangedConfigs()
823 self.ActivateConfigChanges()
Steven M. Gava49745752002-02-18 01:43:11 +0000824 self.SetThemeType()
825
Steven M. Gava5f28e8f2002-01-21 06:38:21 +0000826 def GetColour(self):
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400827 target = self.highlightTarget.get()
828 prevColour = self.frameColourSet.cget('bg')
829 rgbTuplet, colourString = tkColorChooser.askcolor(
830 parent=self, title='Pick new colour for : '+target,
831 initialcolor=prevColour)
832 if colourString and (colourString != prevColour):
Steven M. Gava052937f2002-02-11 02:20:53 +0000833 #user didn't cancel, and they chose a new colour
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400834 if self.themeIsBuiltin.get(): #current theme is a built-in
835 message = ('Your changes will be saved as a new Custom Theme. '
836 'Enter a name for your new Custom Theme below.')
837 newTheme = self.GetNewThemeName(message)
838 if not newTheme: #user cancelled custom theme creation
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000839 return
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400840 else: #create new custom theme based on previously active theme
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000841 self.CreateNewTheme(newTheme)
Steven M. Gava052937f2002-02-11 02:20:53 +0000842 self.colour.set(colourString)
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400843 else: #current theme is user defined
Steven M. Gava052937f2002-02-11 02:20:53 +0000844 self.colour.set(colourString)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000845
Steven M. Gava052937f2002-02-11 02:20:53 +0000846 def OnNewColourSet(self):
847 newColour=self.colour.get()
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400848 self.frameColourSet.config(bg=newColour) #set sample
849 plane ='foreground' if self.fgHilite.get() else 'background'
850 sampleElement = self.themeElements[self.highlightTarget.get()][0]
Raymond Hettinger931237e2003-07-09 18:48:24 +0000851 self.textHighlightSample.tag_config(sampleElement, **{plane:newColour})
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400852 theme = self.customTheme.get()
853 themeElement = sampleElement + '-' + plane
854 self.AddChangedItem('highlight', theme, themeElement, newColour)
Steven M. Gava052937f2002-02-11 02:20:53 +0000855
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400856 def GetNewThemeName(self, message):
857 usedNames = (idleConf.GetSectionList('user', 'highlight') +
858 idleConf.GetSectionList('default', 'highlight'))
Terry Jan Reedy68a53c52016-06-26 22:05:10 -0400859 newTheme = SectionName(
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400860 self, 'New Custom Theme', message, usedNames).result
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000861 return newTheme
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000862
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000863 def SaveAsNewTheme(self):
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400864 newThemeName = self.GetNewThemeName('New Theme Name:')
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000865 if newThemeName:
866 self.CreateNewTheme(newThemeName)
867
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400868 def CreateNewTheme(self, newThemeName):
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000869 #creates new custom theme based on the previously active theme,
870 #and makes the new theme active
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000871 if self.themeIsBuiltin.get():
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400872 themeType = 'default'
873 themeName = self.builtinTheme.get()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000874 else:
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400875 themeType = 'user'
876 themeName = self.customTheme.get()
877 newTheme = idleConf.GetThemeDict(themeType, themeName)
Steven M. Gava052937f2002-02-11 02:20:53 +0000878 #apply any of the old theme's unsaved changes to the new theme
Kurt B. Kaisere0712772007-08-23 05:25:55 +0000879 if themeName in self.changedItems['highlight']:
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400880 themeChanges = self.changedItems['highlight'][themeName]
Kurt B. Kaisere0712772007-08-23 05:25:55 +0000881 for element in themeChanges:
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400882 newTheme[element] = themeChanges[element]
Steven M. Gava052937f2002-02-11 02:20:53 +0000883 #save the new theme
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400884 self.SaveNewTheme(newThemeName, newTheme)
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000885 #change gui over to the new theme
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400886 customThemeList = idleConf.GetSectionList('user', 'highlight')
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000887 customThemeList.sort()
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400888 self.optMenuThemeCustom.SetMenu(customThemeList, newThemeName)
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000889 self.themeIsBuiltin.set(0)
890 self.SetThemeType()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000891
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400892 def OnListFontButtonRelease(self, event):
Kurt B. Kaiser05391692003-05-26 20:35:53 +0000893 font = self.listFontName.get(ANCHOR)
894 self.fontName.set(font.lower())
Steven M. Gava5f28e8f2002-01-21 06:38:21 +0000895 self.SetFontSample()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000896
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400897 def SetFontSample(self, event=None):
898 fontName = self.fontName.get()
899 fontWeight = tkFont.BOLD if self.fontBold.get() else tkFont.NORMAL
Ned Deilyfdf0f272012-10-22 15:14:31 -0700900 newFont = (fontName, self.fontSize.get(), fontWeight)
901 self.labelFontSample.config(font=newFont)
902 self.textHighlightSample.configure(font=newFont)
Steven M. Gava5f28e8f2002-01-21 06:38:21 +0000903
Steven M. Gava5f28e8f2002-01-21 06:38:21 +0000904 def SetHighlightTarget(self):
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400905 if self.highlightTarget.get() == 'Cursor': #bg not possible
Steven M. Gava5f28e8f2002-01-21 06:38:21 +0000906 self.radioFg.config(state=DISABLED)
907 self.radioBg.config(state=DISABLED)
908 self.fgHilite.set(1)
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400909 else: #both fg and bg can be set
Steven M. Gava5f28e8f2002-01-21 06:38:21 +0000910 self.radioFg.config(state=NORMAL)
911 self.radioBg.config(state=NORMAL)
912 self.fgHilite.set(1)
913 self.SetColourSample()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000914
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400915 def SetColourSampleBinding(self, *args):
Steven M. Gava5f28e8f2002-01-21 06:38:21 +0000916 self.SetColourSample()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000917
Steven M. Gava5f28e8f2002-01-21 06:38:21 +0000918 def SetColourSample(self):
919 #set the colour smaple area
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400920 tag = self.themeElements[self.highlightTarget.get()][0]
921 plane = 'foreground' if self.fgHilite.get() else 'background'
922 colour = self.textHighlightSample.tag_cget(tag, plane)
Steven M. Gava5f28e8f2002-01-21 06:38:21 +0000923 self.frameColourSet.config(bg=colour)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000924
Steven M. Gava9dd16b32001-11-03 14:54:25 +0000925 def PaintThemeSample(self):
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400926 if self.themeIsBuiltin.get(): #a default theme
927 theme = self.builtinTheme.get()
928 else: #a user theme
929 theme = self.customTheme.get()
Kurt B. Kaisere0712772007-08-23 05:25:55 +0000930 for elementTitle in self.themeElements:
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400931 element = self.themeElements[elementTitle][0]
932 colours = idleConf.GetHighlight(theme, element)
933 if element == 'cursor': #cursor sample needs special painting
934 colours['background'] = idleConf.GetHighlight(
935 theme, 'normal', fgBg='bg')
Steven M. Gava052937f2002-02-11 02:20:53 +0000936 #handle any unsaved changes to this theme
Kurt B. Kaisere0712772007-08-23 05:25:55 +0000937 if theme in self.changedItems['highlight']:
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400938 themeDict = self.changedItems['highlight'][theme]
939 if element + '-foreground' in themeDict:
940 colours['foreground'] = themeDict[element + '-foreground']
941 if element + '-background' in themeDict:
942 colours['background'] = themeDict[element + '-background']
Raymond Hettinger931237e2003-07-09 18:48:24 +0000943 self.textHighlightSample.tag_config(element, **colours)
Steven M. Gava052937f2002-02-11 02:20:53 +0000944 self.SetColourSample()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000945
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400946 def HelpSourceSelected(self, event):
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000947 self.SetHelpListButtonStates()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000948
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000949 def SetHelpListButtonStates(self):
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400950 if self.listHelp.size() < 1: #no entries in list
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000951 self.buttonHelpListEdit.config(state=DISABLED)
952 self.buttonHelpListRemove.config(state=DISABLED)
953 else: #there are some entries
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400954 if self.listHelp.curselection(): #there currently is a selection
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000955 self.buttonHelpListEdit.config(state=NORMAL)
956 self.buttonHelpListRemove.config(state=NORMAL)
957 else: #there currently is not a selection
958 self.buttonHelpListEdit.config(state=DISABLED)
959 self.buttonHelpListRemove.config(state=DISABLED)
960
961 def HelpListItemAdd(self):
Terry Jan Reedy8b22c0a2016-07-08 00:22:50 -0400962 helpSource = HelpSource(self, 'New Help Source',
963 ).result
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000964 if helpSource:
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400965 self.userHelpList.append((helpSource[0], helpSource[1]))
966 self.listHelp.insert(END, helpSource[0])
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000967 self.UpdateUserHelpChangedItems()
968 self.SetHelpListButtonStates()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000969
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000970 def HelpListItemEdit(self):
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400971 itemIndex = self.listHelp.index(ANCHOR)
972 helpSource = self.userHelpList[itemIndex]
Terry Jan Reedy8b22c0a2016-07-08 00:22:50 -0400973 newHelpSource = HelpSource(
974 self, 'Edit Help Source',
975 menuitem=helpSource[0],
976 filepath=helpSource[1],
977 ).result
978 if newHelpSource and newHelpSource != helpSource:
979 self.userHelpList[itemIndex] = newHelpSource
980 self.listHelp.delete(itemIndex)
981 self.listHelp.insert(itemIndex, newHelpSource[0])
982 self.UpdateUserHelpChangedItems()
983 self.SetHelpListButtonStates()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000984
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000985 def HelpListItemRemove(self):
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400986 itemIndex = self.listHelp.index(ANCHOR)
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000987 del(self.userHelpList[itemIndex])
988 self.listHelp.delete(itemIndex)
989 self.UpdateUserHelpChangedItems()
990 self.SetHelpListButtonStates()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000991
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000992 def UpdateUserHelpChangedItems(self):
Kurt B. Kaiser8e92bf72003-01-14 22:03:31 +0000993 "Clear and rebuild the HelpFiles section in self.changedItems"
994 self.changedItems['main']['HelpFiles'] = {}
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400995 for num in range(1, len(self.userHelpList) + 1):
996 self.AddChangedItem(
997 'main', 'HelpFiles', str(num),
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000998 ';'.join(self.userHelpList[num-1][:2]))
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000999
Steven M. Gava429a86af2001-10-23 10:42:12 +00001000 def LoadFontCfg(self):
1001 ##base editor font selection list
Terry Jan Reedy4036d872014-08-03 23:02:58 -04001002 fonts = list(tkFont.families(self))
Steven M. Gavac11ccf32001-09-24 09:43:17 +00001003 fonts.sort()
1004 for font in fonts:
Terry Jan Reedy4036d872014-08-03 23:02:58 -04001005 self.listFontName.insert(END, font)
Terry Jan Reedyd87d1682015-08-01 18:57:33 -04001006 configuredFont = idleConf.GetFont(self, 'main', 'EditorWindow')
1007 fontName = configuredFont[0].lower()
1008 fontSize = configuredFont[1]
1009 fontBold = configuredFont[2]=='bold'
1010 self.fontName.set(fontName)
Kurt B. Kaiser05391692003-05-26 20:35:53 +00001011 lc_fonts = [s.lower() for s in fonts]
Terry Jan Reedyd87d1682015-08-01 18:57:33 -04001012 try:
1013 currentFontIndex = lc_fonts.index(fontName)
Steven M. Gava429a86af2001-10-23 10:42:12 +00001014 self.listFontName.see(currentFontIndex)
1015 self.listFontName.select_set(currentFontIndex)
Steven M. Gavac112cd82002-01-22 05:56:40 +00001016 self.listFontName.select_anchor(currentFontIndex)
Terry Jan Reedyd87d1682015-08-01 18:57:33 -04001017 except ValueError:
1018 pass
Steven M. Gava429a86af2001-10-23 10:42:12 +00001019 ##font size dropdown
Terry Jan Reedy4036d872014-08-03 23:02:58 -04001020 self.optMenuFontSize.SetMenu(('7', '8', '9', '10', '11', '12', '13',
Terry Jan Reedyda028872016-08-30 20:19:13 -04001021 '14', '16', '18', '20', '22',
1022 '25', '29', '34', '40'), fontSize )
Steven M. Gavac112cd82002-01-22 05:56:40 +00001023 ##fontWeight
Terry Jan Reedyd87d1682015-08-01 18:57:33 -04001024 self.fontBold.set(fontBold)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001025 ##font sample
Steven M. Gava429a86af2001-10-23 10:42:12 +00001026 self.SetFontSample()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001027
Steven M. Gava429a86af2001-10-23 10:42:12 +00001028 def LoadTabCfg(self):
Steven M. Gava429a86af2001-10-23 10:42:12 +00001029 ##indent sizes
Terry Jan Reedy4036d872014-08-03 23:02:58 -04001030 spaceNum = idleConf.GetOption(
1031 'main', 'Indent', 'num-spaces', default=4, type='int')
Steven M. Gava429a86af2001-10-23 10:42:12 +00001032 self.spaceNum.set(spaceNum)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001033
Steven M. Gava9dd16b32001-11-03 14:54:25 +00001034 def LoadThemeCfg(self):
Steven M. Gava41a85322001-10-29 08:05:34 +00001035 ##current theme type radiobutton
Terry Jan Reedy4036d872014-08-03 23:02:58 -04001036 self.themeIsBuiltin.set(idleConf.GetOption(
1037 'main', 'Theme', 'default', type='bool', default=1))
Steven M. Gava41a85322001-10-29 08:05:34 +00001038 ##currently set theme
Terry Jan Reedy4036d872014-08-03 23:02:58 -04001039 currentOption = idleConf.CurrentTheme()
Steven M. Gava7c017862001-10-29 11:19:46 +00001040 ##load available theme option menus
Steven M. Gavad0342cd2001-11-04 11:53:10 +00001041 if self.themeIsBuiltin.get(): #default theme selected
Terry Jan Reedy4036d872014-08-03 23:02:58 -04001042 itemList = idleConf.GetSectionList('default', 'highlight')
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +00001043 itemList.sort()
Terry Jan Reedy4036d872014-08-03 23:02:58 -04001044 self.optMenuThemeBuiltin.SetMenu(itemList, currentOption)
1045 itemList = idleConf.GetSectionList('user', 'highlight')
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +00001046 itemList.sort()
Steven M. Gava41a85322001-10-29 08:05:34 +00001047 if not itemList:
1048 self.radioThemeCustom.config(state=DISABLED)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001049 self.customTheme.set('- no custom themes -')
Steven M. Gava41a85322001-10-29 08:05:34 +00001050 else:
Terry Jan Reedy4036d872014-08-03 23:02:58 -04001051 self.optMenuThemeCustom.SetMenu(itemList, itemList[0])
Steven M. Gava9dd16b32001-11-03 14:54:25 +00001052 else: #user theme selected
Terry Jan Reedy4036d872014-08-03 23:02:58 -04001053 itemList = idleConf.GetSectionList('user', 'highlight')
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +00001054 itemList.sort()
Terry Jan Reedy4036d872014-08-03 23:02:58 -04001055 self.optMenuThemeCustom.SetMenu(itemList, currentOption)
1056 itemList = idleConf.GetSectionList('default', 'highlight')
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +00001057 itemList.sort()
Terry Jan Reedy4036d872014-08-03 23:02:58 -04001058 self.optMenuThemeBuiltin.SetMenu(itemList, itemList[0])
Steven M. Gava7c017862001-10-29 11:19:46 +00001059 self.SetThemeType()
1060 ##load theme element option menu
Kurt B. Kaisere0712772007-08-23 05:25:55 +00001061 themeNames = list(self.themeElements.keys())
Kurt B. Kaiser4718bf82008-02-12 21:34:12 +00001062 themeNames.sort(key=lambda x: self.themeElements[x][1])
Terry Jan Reedy4036d872014-08-03 23:02:58 -04001063 self.optMenuHighlightTarget.SetMenu(themeNames, themeNames[0])
Steven M. Gava9dd16b32001-11-03 14:54:25 +00001064 self.PaintThemeSample()
Steven M. Gava0cae01c2002-01-04 07:53:06 +00001065 self.SetHighlightTarget()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001066
Steven M. Gava9dd16b32001-11-03 14:54:25 +00001067 def LoadKeyCfg(self):
Steven M. Gava41a85322001-10-29 08:05:34 +00001068 ##current keys type radiobutton
Terry Jan Reedy4036d872014-08-03 23:02:58 -04001069 self.keysAreBuiltin.set(idleConf.GetOption(
1070 'main', 'Keys', 'default', type='bool', default=1))
Steven M. Gava41a85322001-10-29 08:05:34 +00001071 ##currently set keys
Terry Jan Reedy4036d872014-08-03 23:02:58 -04001072 currentOption = idleConf.CurrentKeys()
Steven M. Gava7c017862001-10-29 11:19:46 +00001073 ##load available keyset option menus
Steven M. Gava052937f2002-02-11 02:20:53 +00001074 if self.keysAreBuiltin.get(): #default theme selected
Terry Jan Reedy4036d872014-08-03 23:02:58 -04001075 itemList = idleConf.GetSectionList('default', 'keys')
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +00001076 itemList.sort()
Terry Jan Reedy4036d872014-08-03 23:02:58 -04001077 self.optMenuKeysBuiltin.SetMenu(itemList, currentOption)
1078 itemList = idleConf.GetSectionList('user', 'keys')
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +00001079 itemList.sort()
Steven M. Gava41a85322001-10-29 08:05:34 +00001080 if not itemList:
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001081 self.radioKeysCustom.config(state=DISABLED)
1082 self.customKeys.set('- no custom keys -')
Steven M. Gava41a85322001-10-29 08:05:34 +00001083 else:
Terry Jan Reedy4036d872014-08-03 23:02:58 -04001084 self.optMenuKeysCustom.SetMenu(itemList, itemList[0])
Steven M. Gavaa498af22002-02-01 01:33:36 +00001085 else: #user key set selected
Terry Jan Reedy4036d872014-08-03 23:02:58 -04001086 itemList = idleConf.GetSectionList('user', 'keys')
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +00001087 itemList.sort()
Terry Jan Reedy4036d872014-08-03 23:02:58 -04001088 self.optMenuKeysCustom.SetMenu(itemList, currentOption)
1089 itemList = idleConf.GetSectionList('default', 'keys')
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +00001090 itemList.sort()
Terry Jan Reedy9bdb1ed2016-07-10 13:46:34 -04001091 self.optMenuKeysBuiltin.SetMenu(itemList, idleConf.default_keys())
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001092 self.SetKeysType()
Steven M. Gavafacfc092002-01-19 00:29:54 +00001093 ##load keyset element list
Terry Jan Reedy4036d872014-08-03 23:02:58 -04001094 keySetName = idleConf.CurrentKeys()
Steven M. Gava052937f2002-02-11 02:20:53 +00001095 self.LoadKeysList(keySetName)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001096
Steven M. Gavafacfc092002-01-19 00:29:54 +00001097 def LoadGeneralCfg(self):
Steven M. Gava5f28e8f2002-01-21 06:38:21 +00001098 #startup state
Terry Jan Reedy4036d872014-08-03 23:02:58 -04001099 self.startupEdit.set(idleConf.GetOption(
1100 'main', 'General', 'editor-on-startup', default=1, type='bool'))
Kurt B. Kaiser6c638b62003-05-26 06:23:10 +00001101 #autosave state
Terry Jan Reedy4036d872014-08-03 23:02:58 -04001102 self.autoSave.set(idleConf.GetOption(
1103 'main', 'General', 'autosave', default=0, type='bool'))
Steven M. Gavafacfc092002-01-19 00:29:54 +00001104 #initial window size
Terry Jan Reedy4036d872014-08-03 23:02:58 -04001105 self.winWidth.set(idleConf.GetOption(
1106 'main', 'EditorWindow', 'width', type='int'))
1107 self.winHeight.set(idleConf.GetOption(
1108 'main', 'EditorWindow', 'height', type='int'))
Kurt B. Kaisera053f332003-05-10 00:49:56 +00001109 # default source encoding
Terry Jan Reedy4036d872014-08-03 23:02:58 -04001110 self.encoding.set(idleConf.GetOption(
1111 'main', 'EditorWindow', 'encoding', default='none'))
Kurt B. Kaiser8e92bf72003-01-14 22:03:31 +00001112 # additional help sources
1113 self.userHelpList = idleConf.GetAllExtraHelpSourcesList()
Steven M. Gava085eb1b2002-02-05 04:52:32 +00001114 for helpItem in self.userHelpList:
Terry Jan Reedy4036d872014-08-03 23:02:58 -04001115 self.listHelp.insert(END, helpItem[0])
Steven M. Gava085eb1b2002-02-05 04:52:32 +00001116 self.SetHelpListButtonStates()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001117
Steven M. Gava429a86af2001-10-23 10:42:12 +00001118 def LoadConfigs(self):
1119 """
1120 load configuration from default and user config files and populate
1121 the widgets on the config dialog pages.
1122 """
1123 ### fonts / tabs page
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001124 self.LoadFontCfg()
1125 self.LoadTabCfg()
Steven M. Gava429a86af2001-10-23 10:42:12 +00001126 ### highlighting page
Steven M. Gava9dd16b32001-11-03 14:54:25 +00001127 self.LoadThemeCfg()
Steven M. Gava429a86af2001-10-23 10:42:12 +00001128 ### keys page
Steven M. Gava9dd16b32001-11-03 14:54:25 +00001129 self.LoadKeyCfg()
Steven M. Gava429a86af2001-10-23 10:42:12 +00001130 ### general page
Steven M. Gavafacfc092002-01-19 00:29:54 +00001131 self.LoadGeneralCfg()
Terry Jan Reedy93f35422015-10-13 22:03:51 -04001132 # note: extension page handled separately
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001133
Terry Jan Reedy4036d872014-08-03 23:02:58 -04001134 def SaveNewKeySet(self, keySetName, keySet):
Steven M. Gava052937f2002-02-11 02:20:53 +00001135 """
1136 save a newly created core key set.
1137 keySetName - string, the name of the new key set
1138 keySet - dictionary containing the new key set
1139 """
1140 if not idleConf.userCfg['keys'].has_section(keySetName):
1141 idleConf.userCfg['keys'].add_section(keySetName)
Kurt B. Kaisere0712772007-08-23 05:25:55 +00001142 for event in keySet:
Terry Jan Reedy4036d872014-08-03 23:02:58 -04001143 value = keySet[event]
1144 idleConf.userCfg['keys'].SetOption(keySetName, event, value)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001145
Terry Jan Reedy4036d872014-08-03 23:02:58 -04001146 def SaveNewTheme(self, themeName, theme):
Steven M. Gava052937f2002-02-11 02:20:53 +00001147 """
1148 save a newly created theme.
1149 themeName - string, the name of the new theme
1150 theme - dictionary containing the new theme
1151 """
1152 if not idleConf.userCfg['highlight'].has_section(themeName):
1153 idleConf.userCfg['highlight'].add_section(themeName)
Kurt B. Kaisere0712772007-08-23 05:25:55 +00001154 for element in theme:
Terry Jan Reedy4036d872014-08-03 23:02:58 -04001155 value = theme[element]
1156 idleConf.userCfg['highlight'].SetOption(themeName, element, value)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001157
Terry Jan Reedy4036d872014-08-03 23:02:58 -04001158 def SetUserValue(self, configType, section, item, value):
1159 if idleConf.defaultCfg[configType].has_option(section, item):
1160 if idleConf.defaultCfg[configType].Get(section, item) == value:
Steven M. Gava2d7bb3f2002-01-29 08:35:29 +00001161 #the setting equals a default setting, remove it from user cfg
Terry Jan Reedy4036d872014-08-03 23:02:58 -04001162 return idleConf.userCfg[configType].RemoveOption(section, item)
Steven M. Gava2d7bb3f2002-01-29 08:35:29 +00001163 #if we got here set the option
Terry Jan Reedy4036d872014-08-03 23:02:58 -04001164 return idleConf.userCfg[configType].SetOption(section, item, value)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001165
Steven M. Gava052937f2002-02-11 02:20:53 +00001166 def SaveAllChangedConfigs(self):
Kurt B. Kaisere7a161e2003-01-10 20:13:57 +00001167 "Save configuration changes to the user config file."
Steven M. Gava0c5bc8c2002-03-27 02:25:44 +00001168 idleConf.userCfg['main'].Save()
Kurt B. Kaisere0712772007-08-23 05:25:55 +00001169 for configType in self.changedItems:
Kurt B. Kaisere7a161e2003-01-10 20:13:57 +00001170 cfgTypeHasChanges = False
Kurt B. Kaisere0712772007-08-23 05:25:55 +00001171 for section in self.changedItems[configType]:
Kurt B. Kaisere7a161e2003-01-10 20:13:57 +00001172 if section == 'HelpFiles':
1173 #this section gets completely replaced
1174 idleConf.userCfg['main'].remove_section('HelpFiles')
Kurt B. Kaiser8e92bf72003-01-14 22:03:31 +00001175 cfgTypeHasChanges = True
Kurt B. Kaisere0712772007-08-23 05:25:55 +00001176 for item in self.changedItems[configType][section]:
Kurt B. Kaisere7a161e2003-01-10 20:13:57 +00001177 value = self.changedItems[configType][section][item]
Terry Jan Reedy4036d872014-08-03 23:02:58 -04001178 if self.SetUserValue(configType, section, item, value):
Kurt B. Kaisere7a161e2003-01-10 20:13:57 +00001179 cfgTypeHasChanges = True
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001180 if cfgTypeHasChanges:
1181 idleConf.userCfg[configType].Save()
Kurt B. Kaiser5acdf932004-11-16 21:28:36 +00001182 for configType in ['keys', 'highlight']:
1183 # save these even if unchanged!
1184 idleConf.userCfg[configType].Save()
Steven M. Gavaa498af22002-02-01 01:33:36 +00001185 self.ResetChangedItems() #clear the changed items dict
Terry Jan Reedy93f35422015-10-13 22:03:51 -04001186 self.save_all_changed_extensions() # uses a different mechanism
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001187
Kurt B. Kaiserb1754452005-11-18 22:05:48 +00001188 def DeactivateCurrentConfig(self):
1189 #Before a config is saved, some cleanup of current
1190 #config must be done - remove the previous keybindings
Kurt B. Kaisere0712772007-08-23 05:25:55 +00001191 winInstances = self.parent.instance_dict.keys()
Kurt B. Kaiserb1754452005-11-18 22:05:48 +00001192 for instance in winInstances:
1193 instance.RemoveKeybindings()
1194
Steven M. Gava49745752002-02-18 01:43:11 +00001195 def ActivateConfigChanges(self):
Kurt B. Kaiseracdef852005-01-31 03:34:26 +00001196 "Dynamically apply configuration changes"
Kurt B. Kaisere0712772007-08-23 05:25:55 +00001197 winInstances = self.parent.instance_dict.keys()
Steven M. Gavab77d3432002-03-02 07:16:21 +00001198 for instance in winInstances:
1199 instance.ResetColorizer()
Steven M. Gavab1585412002-03-12 00:21:56 +00001200 instance.ResetFont()
Kurt B. Kaiseracdef852005-01-31 03:34:26 +00001201 instance.set_notabs_indentwidth()
Kurt B. Kaiserb1754452005-11-18 22:05:48 +00001202 instance.ApplyKeybindings()
Kurt B. Kaiser8e92bf72003-01-14 22:03:31 +00001203 instance.reset_help_menu_entries()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001204
Steven M. Gava5f28e8f2002-01-21 06:38:21 +00001205 def Cancel(self):
1206 self.destroy()
1207
1208 def Ok(self):
1209 self.Apply()
1210 self.destroy()
1211
1212 def Apply(self):
Kurt B. Kaiserb1754452005-11-18 22:05:48 +00001213 self.DeactivateCurrentConfig()
Steven M. Gava052937f2002-02-11 02:20:53 +00001214 self.SaveAllChangedConfigs()
Steven M. Gava49745752002-02-18 01:43:11 +00001215 self.ActivateConfigChanges()
Steven M. Gava5f28e8f2002-01-21 06:38:21 +00001216
1217 def Help(self):
Terry Jan Reedyd0cadba2015-10-11 22:07:31 -04001218 page = self.tabPages._current_page
1219 view_text(self, title='Help for IDLE preferences',
1220 text=help_common+help_pages.get(page, ''))
1221
Terry Jan Reedy93f35422015-10-13 22:03:51 -04001222 def CreatePageExtensions(self):
1223 """Part of the config dialog used for configuring IDLE extensions.
1224
1225 This code is generic - it works for any and all IDLE extensions.
1226
1227 IDLE extensions save their configuration options using idleConf.
Terry Jan Reedyb2f87602015-10-13 22:09:06 -04001228 This code reads the current configuration using idleConf, supplies a
Terry Jan Reedy93f35422015-10-13 22:03:51 -04001229 GUI interface to change the configuration values, and saves the
1230 changes using idleConf.
1231
1232 Not all changes take effect immediately - some may require restarting IDLE.
1233 This depends on each extension's implementation.
1234
1235 All values are treated as text, and it is up to the user to supply
1236 reasonable values. The only exception to this are the 'enable*' options,
Serhiy Storchaka6a7b3a72016-04-17 08:32:47 +03001237 which are boolean, and can be toggled with a True/False button.
Terry Jan Reedy93f35422015-10-13 22:03:51 -04001238 """
1239 parent = self.parent
1240 frame = self.tabPages.pages['Extensions'].frame
1241 self.ext_defaultCfg = idleConf.defaultCfg['extensions']
1242 self.ext_userCfg = idleConf.userCfg['extensions']
1243 self.is_int = self.register(is_int)
1244 self.load_extensions()
1245 # create widgets - a listbox shows all available extensions, with the
1246 # controls for the extension selected in the listbox to the right
1247 self.extension_names = StringVar(self)
1248 frame.rowconfigure(0, weight=1)
1249 frame.columnconfigure(2, weight=1)
1250 self.extension_list = Listbox(frame, listvariable=self.extension_names,
1251 selectmode='browse')
1252 self.extension_list.bind('<<ListboxSelect>>', self.extension_selected)
1253 scroll = Scrollbar(frame, command=self.extension_list.yview)
1254 self.extension_list.yscrollcommand=scroll.set
1255 self.details_frame = LabelFrame(frame, width=250, height=250)
1256 self.extension_list.grid(column=0, row=0, sticky='nws')
1257 scroll.grid(column=1, row=0, sticky='ns')
1258 self.details_frame.grid(column=2, row=0, sticky='nsew', padx=[10, 0])
1259 frame.configure(padx=10, pady=10)
1260 self.config_frame = {}
1261 self.current_extension = None
1262
1263 self.outerframe = self # TEMPORARY
1264 self.tabbed_page_set = self.extension_list # TEMPORARY
1265
1266 # create the frame holding controls for each extension
1267 ext_names = ''
1268 for ext_name in sorted(self.extensions):
1269 self.create_extension_frame(ext_name)
1270 ext_names = ext_names + '{' + ext_name + '} '
1271 self.extension_names.set(ext_names)
1272 self.extension_list.selection_set(0)
1273 self.extension_selected(None)
1274
1275 def load_extensions(self):
1276 "Fill self.extensions with data from the default and user configs."
1277 self.extensions = {}
1278 for ext_name in idleConf.GetExtensions(active_only=False):
1279 self.extensions[ext_name] = []
1280
1281 for ext_name in self.extensions:
1282 opt_list = sorted(self.ext_defaultCfg.GetOptionList(ext_name))
1283
1284 # bring 'enable' options to the beginning of the list
1285 enables = [opt_name for opt_name in opt_list
1286 if opt_name.startswith('enable')]
1287 for opt_name in enables:
1288 opt_list.remove(opt_name)
1289 opt_list = enables + opt_list
1290
1291 for opt_name in opt_list:
1292 def_str = self.ext_defaultCfg.Get(
1293 ext_name, opt_name, raw=True)
1294 try:
1295 def_obj = {'True':True, 'False':False}[def_str]
1296 opt_type = 'bool'
1297 except KeyError:
1298 try:
1299 def_obj = int(def_str)
1300 opt_type = 'int'
1301 except ValueError:
1302 def_obj = def_str
1303 opt_type = None
1304 try:
1305 value = self.ext_userCfg.Get(
1306 ext_name, opt_name, type=opt_type, raw=True,
1307 default=def_obj)
1308 except ValueError: # Need this until .Get fixed
1309 value = def_obj # bad values overwritten by entry
1310 var = StringVar(self)
1311 var.set(str(value))
1312
1313 self.extensions[ext_name].append({'name': opt_name,
1314 'type': opt_type,
1315 'default': def_str,
1316 'value': value,
1317 'var': var,
1318 })
1319
1320 def extension_selected(self, event):
1321 newsel = self.extension_list.curselection()
1322 if newsel:
1323 newsel = self.extension_list.get(newsel)
1324 if newsel is None or newsel != self.current_extension:
1325 if self.current_extension:
1326 self.details_frame.config(text='')
1327 self.config_frame[self.current_extension].grid_forget()
1328 self.current_extension = None
1329 if newsel:
1330 self.details_frame.config(text=newsel)
1331 self.config_frame[newsel].grid(column=0, row=0, sticky='nsew')
1332 self.current_extension = newsel
1333
1334 def create_extension_frame(self, ext_name):
1335 """Create a frame holding the widgets to configure one extension"""
1336 f = VerticalScrolledFrame(self.details_frame, height=250, width=250)
1337 self.config_frame[ext_name] = f
1338 entry_area = f.interior
1339 # create an entry for each configuration option
1340 for row, opt in enumerate(self.extensions[ext_name]):
1341 # create a row with a label and entry/checkbutton
1342 label = Label(entry_area, text=opt['name'])
1343 label.grid(row=row, column=0, sticky=NW)
1344 var = opt['var']
1345 if opt['type'] == 'bool':
1346 Checkbutton(entry_area, textvariable=var, variable=var,
1347 onvalue='True', offvalue='False',
1348 indicatoron=FALSE, selectcolor='', width=8
1349 ).grid(row=row, column=1, sticky=W, padx=7)
1350 elif opt['type'] == 'int':
1351 Entry(entry_area, textvariable=var, validate='key',
1352 validatecommand=(self.is_int, '%P')
1353 ).grid(row=row, column=1, sticky=NSEW, padx=7)
1354
1355 else:
1356 Entry(entry_area, textvariable=var
1357 ).grid(row=row, column=1, sticky=NSEW, padx=7)
1358 return
1359
1360 def set_extension_value(self, section, opt):
1361 name = opt['name']
1362 default = opt['default']
1363 value = opt['var'].get().strip() or default
1364 opt['var'].set(value)
1365 # if self.defaultCfg.has_section(section):
1366 # Currently, always true; if not, indent to return
1367 if (value == default):
1368 return self.ext_userCfg.RemoveOption(section, name)
1369 # set the option
1370 return self.ext_userCfg.SetOption(section, name, value)
1371
1372 def save_all_changed_extensions(self):
1373 """Save configuration changes to the user config file."""
1374 has_changes = False
1375 for ext_name in self.extensions:
1376 options = self.extensions[ext_name]
1377 for opt in options:
1378 if self.set_extension_value(ext_name, opt):
1379 has_changes = True
1380 if has_changes:
1381 self.ext_userCfg.Save()
1382
1383
Terry Jan Reedyd0cadba2015-10-11 22:07:31 -04001384help_common = '''\
1385When you click either the Apply or Ok buttons, settings in this
1386dialog that are different from IDLE's default are saved in
1387a .idlerc directory in your home directory. Except as noted,
Terry Jan Reedyd0c0f002015-11-12 15:02:57 -05001388these changes apply to all versions of IDLE installed on this
Terry Jan Reedyd0cadba2015-10-11 22:07:31 -04001389machine. Some do not take affect until IDLE is restarted.
1390[Cancel] only cancels changes made since the last save.
1391'''
1392help_pages = {
Terry Jan Reedy9bdb1ed2016-07-10 13:46:34 -04001393 'Highlighting': '''
Terry Jan Reedyd0cadba2015-10-11 22:07:31 -04001394Highlighting:
Terry Jan Reedyd0c0f002015-11-12 15:02:57 -05001395The IDLE Dark color theme is new in October 2015. It can only
Terry Jan Reedyd0cadba2015-10-11 22:07:31 -04001396be used with older IDLE releases if it is saved as a custom
1397theme, with a different name.
Terry Jan Reedy9bdb1ed2016-07-10 13:46:34 -04001398''',
1399 'Keys': '''
1400Keys:
1401The IDLE Modern Unix key set is new in June 2016. It can only
1402be used with older IDLE releases if it is saved as a custom
1403key set, with a different name.
1404''',
Terry Jan Reedyd0cadba2015-10-11 22:07:31 -04001405}
1406
Steven M. Gavac11ccf32001-09-24 09:43:17 +00001407
Terry Jan Reedy93f35422015-10-13 22:03:51 -04001408def is_int(s):
1409 "Return 's is blank or represents an int'"
1410 if not s:
1411 return True
1412 try:
1413 int(s)
1414 return True
1415 except ValueError:
1416 return False
1417
1418
Terry Jan Reedya9421fb2014-10-22 20:15:18 -04001419class VerticalScrolledFrame(Frame):
1420 """A pure Tkinter vertically scrollable frame.
1421
1422 * Use the 'interior' attribute to place widgets inside the scrollable frame
1423 * Construct and pack/place/grid normally
1424 * This frame only allows vertical scrolling
1425 """
1426 def __init__(self, parent, *args, **kw):
1427 Frame.__init__(self, parent, *args, **kw)
1428
1429 # create a canvas object and a vertical scrollbar for scrolling it
1430 vscrollbar = Scrollbar(self, orient=VERTICAL)
1431 vscrollbar.pack(fill=Y, side=RIGHT, expand=FALSE)
1432 canvas = Canvas(self, bd=0, highlightthickness=0,
Terry Jan Reedyd0812292015-10-22 03:27:31 -04001433 yscrollcommand=vscrollbar.set, width=240)
Terry Jan Reedya9421fb2014-10-22 20:15:18 -04001434 canvas.pack(side=LEFT, fill=BOTH, expand=TRUE)
1435 vscrollbar.config(command=canvas.yview)
1436
1437 # reset the view
1438 canvas.xview_moveto(0)
1439 canvas.yview_moveto(0)
1440
1441 # create a frame inside the canvas which will be scrolled with it
1442 self.interior = interior = Frame(canvas)
1443 interior_id = canvas.create_window(0, 0, window=interior, anchor=NW)
1444
1445 # track changes to the canvas and frame width and sync them,
1446 # also updating the scrollbar
1447 def _configure_interior(event):
1448 # update the scrollbars to match the size of the inner frame
1449 size = (interior.winfo_reqwidth(), interior.winfo_reqheight())
1450 canvas.config(scrollregion="0 0 %s %s" % size)
Terry Jan Reedya9421fb2014-10-22 20:15:18 -04001451 interior.bind('<Configure>', _configure_interior)
1452
1453 def _configure_canvas(event):
1454 if interior.winfo_reqwidth() != canvas.winfo_width():
1455 # update the inner frame's width to fill the canvas
1456 canvas.itemconfigure(interior_id, width=canvas.winfo_width())
1457 canvas.bind('<Configure>', _configure_canvas)
1458
1459 return
1460
Terry Jan Reedya9421fb2014-10-22 20:15:18 -04001461
Steven M. Gava44d3d1a2001-07-31 06:59:02 +00001462if __name__ == '__main__':
Terry Jan Reedycfa89502014-07-14 23:07:32 -04001463 import unittest
1464 unittest.main('idlelib.idle_test.test_configdialog',
1465 verbosity=2, exit=False)
Terry Jan Reedy2e8234a2014-05-29 01:46:26 -04001466 from idlelib.idle_test.htest import run
Terry Jan Reedy47304c02015-10-20 02:15:28 -04001467 run(ConfigDialog)