blob: 4a25846238f6e1a30ca9529d9a8a8030a24ee8aa [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"""
csabellabac7d332017-06-26 17:46:26 -040012from tkinter import (Toplevel, Frame, LabelFrame, Listbox, Label, Button,
13 Entry, Text, Scale, Radiobutton, Checkbutton, Canvas,
14 StringVar, BooleanVar, IntVar, TRUE, FALSE,
15 TOP, BOTTOM, RIGHT, LEFT, SOLID, GROOVE, NORMAL, DISABLED,
16 NONE, BOTH, X, Y, W, E, EW, NS, NSEW, NW,
17 HORIZONTAL, VERTICAL, ANCHOR, END)
Terry Jan Reedy01e35752016-06-10 18:19:21 -040018from tkinter.ttk import Scrollbar
Georg Brandl14fc4272008-05-17 18:39:55 +000019import tkinter.colorchooser as tkColorChooser
20import tkinter.font as tkFont
Terry Jan Reedybfbaa6b2016-08-31 00:50:55 -040021import tkinter.messagebox as tkMessageBox
Steven M. Gava44d3d1a2001-07-31 06:59:02 +000022
Terry Jan Reedy6fa5bdc2016-05-28 13:22:31 -040023from idlelib.config import idleConf
Terry Jan Reedy6fa5bdc2016-05-28 13:22:31 -040024from idlelib.config_key import GetKeysDialog
Terry Jan Reedybfbaa6b2016-08-31 00:50:55 -040025from idlelib.dynoption import DynOptionMenu
26from idlelib import macosx
Terry Jan Reedy8b22c0a2016-07-08 00:22:50 -040027from idlelib.query import SectionName, HelpSource
Terry Jan Reedya9421fb2014-10-22 20:15:18 -040028from idlelib.tabbedpages import TabbedPageSet
Terry Jan Reedy6fa5bdc2016-05-28 13:22:31 -040029from idlelib.textview import view_text
Terry Jan Reedyd0cadba2015-10-11 22:07:31 -040030
Steven M. Gava44d3d1a2001-07-31 06:59:02 +000031class ConfigDialog(Toplevel):
Kurt B. Kaiseracdef852005-01-31 03:34:26 +000032
Terry Jan Reedycd567362014-10-17 01:31:35 -040033 def __init__(self, parent, title='', _htest=False, _utest=False):
Terry Jan Reedy2e8234a2014-05-29 01:46:26 -040034 """
35 _htest - bool, change box location when running htest
Terry Jan Reedycfa89502014-07-14 23:07:32 -040036 _utest - bool, don't wait_window when running unittest
Terry Jan Reedy2e8234a2014-05-29 01:46:26 -040037 """
Steven M. Gavad721c482001-07-31 10:46:53 +000038 Toplevel.__init__(self, parent)
Terry Jan Reedy22405332014-07-30 19:24:32 -040039 self.parent = parent
Terry Jan Reedy4036d872014-08-03 23:02:58 -040040 if _htest:
41 parent.instance_dict = {}
csabellabac7d332017-06-26 17:46:26 -040042 self.withdraw()
Guido van Rossum8ce8a782007-11-01 19:42:39 +000043
Steven M. Gavad721c482001-07-31 10:46:53 +000044 self.configure(borderwidth=5)
Terry Jan Reedycd567362014-10-17 01:31:35 -040045 self.title(title or 'IDLE Preferences')
csabellabac7d332017-06-26 17:46:26 -040046 x = parent.winfo_rootx() + 20
47 y = parent.winfo_rooty() + (30 if not _htest else 150)
48 self.geometry(f'+{x}+{y}')
Georg Brandl7eb4b7d2005-07-22 21:49:32 +000049 #Theme Elements. Each theme element key is its display name.
Steven M. Gava9dd16b32001-11-03 14:54:25 +000050 #The first value of the tuple is the sample area tag name.
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +000051 #The second value is the display name list sort index.
csabellabac7d332017-06-26 17:46:26 -040052 self.theme_elements={
Terry Jan Reedya8aa4d52015-10-02 22:12:17 -040053 'Normal Text': ('normal', '00'),
54 'Python Keywords': ('keyword', '01'),
55 'Python Definitions': ('definition', '02'),
56 'Python Builtins': ('builtin', '03'),
57 'Python Comments': ('comment', '04'),
58 'Python Strings': ('string', '05'),
59 'Selected Text': ('hilite', '06'),
60 'Found Text': ('hit', '07'),
61 'Cursor': ('cursor', '08'),
62 'Editor Breakpoint': ('break', '09'),
63 'Shell Normal Text': ('console', '10'),
64 'Shell Error Text': ('error', '11'),
65 'Shell Stdout Text': ('stdout', '12'),
66 'Shell Stderr Text': ('stderr', '13'),
Kurt B. Kaiser73360a32004-03-08 18:15:31 +000067 }
csabellabac7d332017-06-26 17:46:26 -040068 self.reset_changed_items() #load initial values in changed items dict
69 self.create_widgets()
Terry Jan Reedy4036d872014-08-03 23:02:58 -040070 self.resizable(height=FALSE, width=FALSE)
Steven M. Gavad721c482001-07-31 10:46:53 +000071 self.transient(parent)
72 self.grab_set()
csabellabac7d332017-06-26 17:46:26 -040073 self.protocol("WM_DELETE_WINDOW", self.cancel)
74 self.tab_pages.focus_set()
Steven M. Gavad721c482001-07-31 10:46:53 +000075 #key bindings for this dialog
Terry Jan Reedy4036d872014-08-03 23:02:58 -040076 #self.bind('<Escape>', self.Cancel) #dismiss dialog, no save
77 #self.bind('<Alt-a>', self.Apply) #apply changes, save
78 #self.bind('<F1>', self.Help) #context help
csabellabac7d332017-06-26 17:46:26 -040079 self.load_configs()
80 self.attach_var_callbacks() #avoid callbacks during load_configs
Guido van Rossum8ce8a782007-11-01 19:42:39 +000081
Terry Jan Reedycfa89502014-07-14 23:07:32 -040082 if not _utest:
83 self.wm_deiconify()
84 self.wait_window()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +000085
csabellabac7d332017-06-26 17:46:26 -040086 def create_widgets(self):
87 self.tab_pages = TabbedPageSet(self,
Terry Jan Reedy93f35422015-10-13 22:03:51 -040088 page_names=['Fonts/Tabs', 'Highlighting', 'Keys', 'General',
89 'Extensions'])
csabellabac7d332017-06-26 17:46:26 -040090 self.tab_pages.pack(side=TOP, expand=TRUE, fill=BOTH)
91 self.create_page_font_tab()
92 self.create_page_highlight()
93 self.create_page_keys()
94 self.create_page_general()
95 self.create_page_extensions()
Terry Jan Reedy92cb0a32014-10-08 20:29:13 -040096 self.create_action_buttons().pack(side=BOTTOM)
Terry Jan Reedyd0cadba2015-10-11 22:07:31 -040097
Terry Jan Reedy92cb0a32014-10-08 20:29:13 -040098 def create_action_buttons(self):
Terry Jan Reedy6fa5bdc2016-05-28 13:22:31 -040099 if macosx.isAquaTk():
Terry Jan Reedye3416e62014-07-26 19:40:16 -0400100 # Changing the default padding on OSX results in unreadable
101 # text in the buttons
csabellabac7d332017-06-26 17:46:26 -0400102 padding_args = {}
Ronald Oussoren9e350042009-02-12 16:02:11 +0000103 else:
csabellabac7d332017-06-26 17:46:26 -0400104 padding_args = {'padx':6, 'pady':3}
Terry Jan Reedya9421fb2014-10-22 20:15:18 -0400105 outer = Frame(self, pady=2)
106 buttons = Frame(outer, pady=2)
Terry Jan Reedyd0cadba2015-10-11 22:07:31 -0400107 for txt, cmd in (
csabellabac7d332017-06-26 17:46:26 -0400108 ('Ok', self.ok),
109 ('Apply', self.apply),
110 ('Cancel', self.cancel),
111 ('Help', self.help)):
Terry Jan Reedyd0cadba2015-10-11 22:07:31 -0400112 Button(buttons, text=txt, command=cmd, takefocus=FALSE,
csabellabac7d332017-06-26 17:46:26 -0400113 **padding_args).pack(side=LEFT, padx=5)
Terry Jan Reedya9421fb2014-10-22 20:15:18 -0400114 # add space above buttons
115 Frame(outer, height=2, borderwidth=0).pack(side=TOP)
116 buttons.pack(side=BOTTOM)
117 return outer
Terry Jan Reedyd0cadba2015-10-11 22:07:31 -0400118
csabellabac7d332017-06-26 17:46:26 -0400119 def create_page_font_tab(self):
Terry Jan Reedy22405332014-07-30 19:24:32 -0400120 parent = self.parent
csabellabac7d332017-06-26 17:46:26 -0400121 self.font_size = StringVar(parent)
122 self.font_bold = BooleanVar(parent)
123 self.font_name = StringVar(parent)
124 self.space_num = IntVar(parent)
125 self.edit_font = tkFont.Font(parent, ('courier', 10, 'normal'))
Terry Jan Reedy22405332014-07-30 19:24:32 -0400126
Steven M. Gavaf213ccb2001-08-05 08:00:28 +0000127 ##widget creation
128 #body frame
csabellabac7d332017-06-26 17:46:26 -0400129 frame = self.tab_pages.pages['Fonts/Tabs'].frame
Steven M. Gavaf213ccb2001-08-05 08:00:28 +0000130 #body section frames
csabellabac7d332017-06-26 17:46:26 -0400131 frame_font = LabelFrame(
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400132 frame, borderwidth=2, relief=GROOVE, text=' Base Editor Font ')
csabellabac7d332017-06-26 17:46:26 -0400133 frame_indent = LabelFrame(
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400134 frame, borderwidth=2, relief=GROOVE, text=' Indentation Width ')
csabellabac7d332017-06-26 17:46:26 -0400135 #frame_font
136 frame_font_name = Frame(frame_font)
137 frame_font_param = Frame(frame_font)
138 font_name_title = Label(
139 frame_font_name, justify=LEFT, text='Font Face :')
140 self.list_fonts = Listbox(
141 frame_font_name, height=5, takefocus=FALSE, exportselection=FALSE)
142 self.list_fonts.bind(
143 '<ButtonRelease-1>', self.on_list_fonts_button_release)
144 scroll_font = Scrollbar(frame_font_name)
145 scroll_font.config(command=self.list_fonts.yview)
146 self.list_fonts.config(yscrollcommand=scroll_font.set)
147 font_size_title = Label(frame_font_param, text='Size :')
148 self.opt_menu_font_size = DynOptionMenu(
149 frame_font_param, self.font_size, None, command=self.set_font_sample)
150 check_font_bold = Checkbutton(
151 frame_font_param, variable=self.font_bold, onvalue=1,
152 offvalue=0, text='Bold', command=self.set_font_sample)
153 frame_font_sample = Frame(frame_font, relief=SOLID, borderwidth=1)
154 self.font_sample = Label(
155 frame_font_sample, justify=LEFT, font=self.edit_font,
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400156 text='AaBbCcDdEe\nFfGgHhIiJjK\n1234567890\n#:+=(){}[]')
csabellabac7d332017-06-26 17:46:26 -0400157 #frame_indent
158 frame_indent_size = Frame(frame_indent)
159 indent_size_title = Label(
160 frame_indent_size, justify=LEFT,
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400161 text='Python Standard: 4 Spaces!')
csabellabac7d332017-06-26 17:46:26 -0400162 self.scale_indent_size = Scale(
163 frame_indent_size, variable=self.space_num,
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400164 orient='horizontal', tickinterval=2, from_=2, to=16)
Terry Jan Reedy22405332014-07-30 19:24:32 -0400165
Steven M. Gavaf213ccb2001-08-05 08:00:28 +0000166 #widget packing
167 #body
csabellabac7d332017-06-26 17:46:26 -0400168 frame_font.pack(side=LEFT, padx=5, pady=5, expand=TRUE, fill=BOTH)
169 frame_indent.pack(side=LEFT, padx=5, pady=5, fill=Y)
170 #frame_font
171 frame_font_name.pack(side=TOP, padx=5, pady=5, fill=X)
172 frame_font_param.pack(side=TOP, padx=5, pady=5, fill=X)
173 font_name_title.pack(side=TOP, anchor=W)
174 self.list_fonts.pack(side=LEFT, expand=TRUE, fill=X)
175 scroll_font.pack(side=LEFT, fill=Y)
176 font_size_title.pack(side=LEFT, anchor=W)
177 self.opt_menu_font_size.pack(side=LEFT, anchor=W)
178 check_font_bold.pack(side=LEFT, anchor=W, padx=20)
179 frame_font_sample.pack(side=TOP, padx=5, pady=5, expand=TRUE, fill=BOTH)
180 self.font_sample.pack(expand=TRUE, fill=BOTH)
181 #frame_indent
182 frame_indent_size.pack(side=TOP, fill=X)
183 indent_size_title.pack(side=TOP, anchor=W, padx=5)
184 self.scale_indent_size.pack(side=TOP, padx=5, fill=X)
Steven M. Gava952d0a52001-08-03 04:43:44 +0000185 return frame
186
csabellabac7d332017-06-26 17:46:26 -0400187 def create_page_highlight(self):
Terry Jan Reedy22405332014-07-30 19:24:32 -0400188 parent = self.parent
csabellabac7d332017-06-26 17:46:26 -0400189 self.builtin_theme = StringVar(parent)
190 self.custom_theme = StringVar(parent)
191 self.fg_bg_toggle = BooleanVar(parent)
Terry Jan Reedy22405332014-07-30 19:24:32 -0400192 self.colour = StringVar(parent)
csabellabac7d332017-06-26 17:46:26 -0400193 self.font_name = StringVar(parent)
194 self.is_builtin_theme = BooleanVar(parent)
195 self.highlight_target = StringVar(parent)
Terry Jan Reedy22405332014-07-30 19:24:32 -0400196
Steven M. Gava952d0a52001-08-03 04:43:44 +0000197 ##widget creation
198 #body frame
csabellabac7d332017-06-26 17:46:26 -0400199 frame = self.tab_pages.pages['Highlighting'].frame
Steven M. Gava952d0a52001-08-03 04:43:44 +0000200 #body section frames
csabellabac7d332017-06-26 17:46:26 -0400201 frame_custom = LabelFrame(frame, borderwidth=2, relief=GROOVE,
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400202 text=' Custom Highlighting ')
csabellabac7d332017-06-26 17:46:26 -0400203 frame_theme = LabelFrame(frame, borderwidth=2, relief=GROOVE,
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400204 text=' Highlighting Theme ')
csabellabac7d332017-06-26 17:46:26 -0400205 #frame_custom
206 self.text_highlight_sample=Text(
207 frame_custom, relief=SOLID, borderwidth=1,
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400208 font=('courier', 12, ''), cursor='hand2', width=21, height=11,
209 takefocus=FALSE, highlightthickness=0, wrap=NONE)
csabellabac7d332017-06-26 17:46:26 -0400210 text=self.text_highlight_sample
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400211 text.bind('<Double-Button-1>', lambda e: 'break')
212 text.bind('<B1-Motion>', lambda e: 'break')
csabellabac7d332017-06-26 17:46:26 -0400213 text_and_tags=(
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400214 ('#you can click here', 'comment'), ('\n', 'normal'),
215 ('#to choose items', 'comment'), ('\n', 'normal'),
216 ('def', 'keyword'), (' ', 'normal'),
217 ('func', 'definition'), ('(param):\n ', 'normal'),
218 ('"""string"""', 'string'), ('\n var0 = ', 'normal'),
219 ("'string'", 'string'), ('\n var1 = ', 'normal'),
220 ("'selected'", 'hilite'), ('\n var2 = ', 'normal'),
221 ("'found'", 'hit'), ('\n var3 = ', 'normal'),
222 ('list', 'builtin'), ('(', 'normal'),
Terry Jan Reedya8aa4d52015-10-02 22:12:17 -0400223 ('None', 'keyword'), (')\n', 'normal'),
224 (' breakpoint("line")', 'break'), ('\n\n', 'normal'),
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400225 (' error ', 'error'), (' ', 'normal'),
226 ('cursor |', 'cursor'), ('\n ', 'normal'),
227 ('shell', 'console'), (' ', 'normal'),
228 ('stdout', 'stdout'), (' ', 'normal'),
229 ('stderr', 'stderr'), ('\n', 'normal'))
csabellabac7d332017-06-26 17:46:26 -0400230 for texttag in text_and_tags:
231 text.insert(END, texttag[0], texttag[1])
232 for element in self.theme_elements:
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400233 def tem(event, elem=element):
csabellabac7d332017-06-26 17:46:26 -0400234 event.widget.winfo_toplevel().highlight_target.set(elem)
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400235 text.tag_bind(
csabellabac7d332017-06-26 17:46:26 -0400236 self.theme_elements[element][0], '<ButtonPress-1>', tem)
Steven M. Gavae16d94b2001-11-03 05:07:28 +0000237 text.config(state=DISABLED)
csabellabac7d332017-06-26 17:46:26 -0400238 self.frame_colour_set = Frame(frame_custom, relief=SOLID, borderwidth=1)
239 frame_fg_bg_toggle = Frame(frame_custom)
240 button_set_colour = Button(
241 self.frame_colour_set, text='Choose Colour for :',
242 command=self.get_colour, highlightthickness=0)
243 self.opt_menu_highlight_target = DynOptionMenu(
244 self.frame_colour_set, self.highlight_target, None,
245 highlightthickness=0) #, command=self.set_highlight_targetBinding
246 self.radio_fg = Radiobutton(
247 frame_fg_bg_toggle, variable=self.fg_bg_toggle, value=1,
248 text='Foreground', command=self.set_colour_sample_binding)
249 self.radio_bg=Radiobutton(
250 frame_fg_bg_toggle, variable=self.fg_bg_toggle, value=0,
251 text='Background', command=self.set_colour_sample_binding)
252 self.fg_bg_toggle.set(1)
253 button_save_custom_theme = Button(
254 frame_custom, text='Save as New Custom Theme',
255 command=self.save_as_new_theme)
256 #frame_theme
257 theme_type_title = Label(frame_theme, text='Select : ')
258 self.radio_theme_builtin = Radiobutton(
259 frame_theme, variable=self.is_builtin_theme, value=1,
260 command=self.set_theme_type, text='a Built-in Theme')
261 self.radio_theme_custom = Radiobutton(
262 frame_theme, variable=self.is_builtin_theme, value=0,
263 command=self.set_theme_type, text='a Custom Theme')
264 self.opt_menu_theme_builtin = DynOptionMenu(
265 frame_theme, self.builtin_theme, None, command=None)
266 self.opt_menu_theme_custom=DynOptionMenu(
267 frame_theme, self.custom_theme, None, command=None)
268 self.button_delete_custom_theme=Button(
269 frame_theme, text='Delete Custom Theme',
270 command=self.delete_custom_theme)
271 self.new_custom_theme = Label(frame_theme, bd=2)
Terry Jan Reedy22405332014-07-30 19:24:32 -0400272
Steven M. Gava952d0a52001-08-03 04:43:44 +0000273 ##widget packing
274 #body
csabellabac7d332017-06-26 17:46:26 -0400275 frame_custom.pack(side=LEFT, padx=5, pady=5, expand=TRUE, fill=BOTH)
276 frame_theme.pack(side=LEFT, padx=5, pady=5, fill=Y)
277 #frame_custom
278 self.frame_colour_set.pack(side=TOP, padx=5, pady=5, expand=TRUE, fill=X)
279 frame_fg_bg_toggle.pack(side=TOP, padx=5, pady=0)
280 self.text_highlight_sample.pack(
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400281 side=TOP, padx=5, pady=5, expand=TRUE, fill=BOTH)
csabellabac7d332017-06-26 17:46:26 -0400282 button_set_colour.pack(side=TOP, expand=TRUE, fill=X, padx=8, pady=4)
283 self.opt_menu_highlight_target.pack(
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400284 side=TOP, expand=TRUE, fill=X, padx=8, pady=3)
csabellabac7d332017-06-26 17:46:26 -0400285 self.radio_fg.pack(side=LEFT, anchor=E)
286 self.radio_bg.pack(side=RIGHT, anchor=W)
287 button_save_custom_theme.pack(side=BOTTOM, fill=X, padx=5, pady=5)
288 #frame_theme
289 theme_type_title.pack(side=TOP, anchor=W, padx=5, pady=5)
290 self.radio_theme_builtin.pack(side=TOP, anchor=W, padx=5)
291 self.radio_theme_custom.pack(side=TOP, anchor=W, padx=5, pady=2)
292 self.opt_menu_theme_builtin.pack(side=TOP, fill=X, padx=5, pady=5)
293 self.opt_menu_theme_custom.pack(side=TOP, fill=X, anchor=W, padx=5, pady=5)
294 self.button_delete_custom_theme.pack(side=TOP, fill=X, padx=5, pady=5)
Terry Jan Reedyd0c0f002015-11-12 15:02:57 -0500295 self.new_custom_theme.pack(side=TOP, fill=X, pady=5)
Steven M. Gava952d0a52001-08-03 04:43:44 +0000296 return frame
297
csabellabac7d332017-06-26 17:46:26 -0400298 def create_page_keys(self):
Terry Jan Reedy22405332014-07-30 19:24:32 -0400299 parent = self.parent
csabellabac7d332017-06-26 17:46:26 -0400300 self.binding_target = StringVar(parent)
301 self.builtin_keys = StringVar(parent)
302 self.custom_keys = StringVar(parent)
303 self.are_keys_builtin = BooleanVar(parent)
304 self.keybinding = StringVar(parent)
Terry Jan Reedy22405332014-07-30 19:24:32 -0400305
Steven M. Gava60fc7072001-08-04 13:58:22 +0000306 ##widget creation
307 #body frame
csabellabac7d332017-06-26 17:46:26 -0400308 frame = self.tab_pages.pages['Keys'].frame
Steven M. Gava60fc7072001-08-04 13:58:22 +0000309 #body section frames
csabellabac7d332017-06-26 17:46:26 -0400310 frame_custom = LabelFrame(
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400311 frame, borderwidth=2, relief=GROOVE,
312 text=' Custom Key Bindings ')
csabellabac7d332017-06-26 17:46:26 -0400313 frame_key_sets = LabelFrame(
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400314 frame, borderwidth=2, relief=GROOVE, text=' Key Set ')
csabellabac7d332017-06-26 17:46:26 -0400315 #frame_custom
316 frame_target = Frame(frame_custom)
317 target_title = Label(frame_target, text='Action - Key(s)')
318 scroll_target_y = Scrollbar(frame_target)
319 scroll_target_x = Scrollbar(frame_target, orient=HORIZONTAL)
320 self.list_bindings = Listbox(
321 frame_target, takefocus=FALSE, exportselection=FALSE)
322 self.list_bindings.bind('<ButtonRelease-1>', self.keybinding_selected)
323 scroll_target_y.config(command=self.list_bindings.yview)
324 scroll_target_x.config(command=self.list_bindings.xview)
325 self.list_bindings.config(yscrollcommand=scroll_target_y.set)
326 self.list_bindings.config(xscrollcommand=scroll_target_x.set)
327 self.button_new_keys = Button(
328 frame_custom, text='Get New Keys for Selection',
329 command=self.get_new_keys, state=DISABLED)
330 #frame_key_sets
331 frames = [Frame(frame_key_sets, padx=2, pady=2, borderwidth=0)
Christian Heimes9a371592007-12-28 14:08:13 +0000332 for i in range(2)]
csabellabac7d332017-06-26 17:46:26 -0400333 self.radio_keys_builtin = Radiobutton(
334 frames[0], variable=self.are_keys_builtin, value=1,
335 command=self.set_keys_type, text='Use a Built-in Key Set')
336 self.radio_keys_custom = Radiobutton(
337 frames[0], variable=self.are_keys_builtin, value=0,
338 command=self.set_keys_type, text='Use a Custom Key Set')
339 self.opt_menu_keys_builtin = DynOptionMenu(
340 frames[0], self.builtin_keys, None, command=None)
341 self.opt_menu_keys_custom = DynOptionMenu(
342 frames[0], self.custom_keys, None, command=None)
343 self.button_delete_custom_keys = Button(
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400344 frames[1], text='Delete Custom Key Set',
csabellabac7d332017-06-26 17:46:26 -0400345 command=self.delete_custom_keys)
346 button_save_custom_keys = Button(
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400347 frames[1], text='Save as New Custom Key Set',
csabellabac7d332017-06-26 17:46:26 -0400348 command=self.save_as_new_key_set)
Terry Jan Reedy9bdb1ed2016-07-10 13:46:34 -0400349 self.new_custom_keys = Label(frames[0], bd=2)
Terry Jan Reedy22405332014-07-30 19:24:32 -0400350
Steven M. Gava60fc7072001-08-04 13:58:22 +0000351 ##widget packing
352 #body
csabellabac7d332017-06-26 17:46:26 -0400353 frame_custom.pack(side=BOTTOM, padx=5, pady=5, expand=TRUE, fill=BOTH)
354 frame_key_sets.pack(side=BOTTOM, padx=5, pady=5, fill=BOTH)
355 #frame_custom
356 self.button_new_keys.pack(side=BOTTOM, fill=X, padx=5, pady=5)
357 frame_target.pack(side=LEFT, padx=5, pady=5, expand=TRUE, fill=BOTH)
Steven M. Gavafacfc092002-01-19 00:29:54 +0000358 #frame target
csabellabac7d332017-06-26 17:46:26 -0400359 frame_target.columnconfigure(0, weight=1)
360 frame_target.rowconfigure(1, weight=1)
361 target_title.grid(row=0, column=0, columnspan=2, sticky=W)
362 self.list_bindings.grid(row=1, column=0, sticky=NSEW)
363 scroll_target_y.grid(row=1, column=1, sticky=NS)
364 scroll_target_x.grid(row=2, column=0, sticky=EW)
365 #frame_key_sets
366 self.radio_keys_builtin.grid(row=0, column=0, sticky=W+NS)
367 self.radio_keys_custom.grid(row=1, column=0, sticky=W+NS)
368 self.opt_menu_keys_builtin.grid(row=0, column=1, sticky=NSEW)
369 self.opt_menu_keys_custom.grid(row=1, column=1, sticky=NSEW)
Terry Jan Reedy9bdb1ed2016-07-10 13:46:34 -0400370 self.new_custom_keys.grid(row=0, column=2, sticky=NSEW, padx=5, pady=5)
csabellabac7d332017-06-26 17:46:26 -0400371 self.button_delete_custom_keys.pack(side=LEFT, fill=X, expand=True, padx=2)
372 button_save_custom_keys.pack(side=LEFT, fill=X, expand=True, padx=2)
Christian Heimes9a371592007-12-28 14:08:13 +0000373 frames[0].pack(side=TOP, fill=BOTH, expand=True)
374 frames[1].pack(side=TOP, fill=X, expand=True, pady=2)
Steven M. Gava952d0a52001-08-03 04:43:44 +0000375 return frame
376
csabellabac7d332017-06-26 17:46:26 -0400377 def create_page_general(self):
Terry Jan Reedy22405332014-07-30 19:24:32 -0400378 parent = self.parent
csabellabac7d332017-06-26 17:46:26 -0400379 self.win_width = StringVar(parent)
380 self.win_height = StringVar(parent)
381 self.startup_edit = IntVar(parent)
382 self.autosave = IntVar(parent)
Terry Jan Reedy22405332014-07-30 19:24:32 -0400383 self.encoding = StringVar(parent)
csabellabac7d332017-06-26 17:46:26 -0400384 self.user_help_browser = BooleanVar(parent)
385 self.help_browser = StringVar(parent)
Terry Jan Reedy22405332014-07-30 19:24:32 -0400386
Steven M. Gava230e5782001-08-07 03:28:25 +0000387 #widget creation
388 #body
csabellabac7d332017-06-26 17:46:26 -0400389 frame = self.tab_pages.pages['General'].frame
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000390 #body section frames
csabellabac7d332017-06-26 17:46:26 -0400391 frame_run = LabelFrame(frame, borderwidth=2, relief=GROOVE,
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400392 text=' Startup Preferences ')
csabellabac7d332017-06-26 17:46:26 -0400393 frame_save = LabelFrame(frame, borderwidth=2, relief=GROOVE,
394 text=' autosave Preferences ')
395 frame_win_size = Frame(frame, borderwidth=2, relief=GROOVE)
396 frame_help = LabelFrame(frame, borderwidth=2, relief=GROOVE,
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400397 text=' Additional Help Sources ')
csabellabac7d332017-06-26 17:46:26 -0400398 #frame_run
399 startup_title = Label(frame_run, text='At Startup')
400 self.radio_startup_edit = Radiobutton(
401 frame_run, variable=self.startup_edit, value=1,
Terry Jan Reedyf46b7822016-11-07 17:15:01 -0500402 text="Open Edit Window")
csabellabac7d332017-06-26 17:46:26 -0400403 self.radio_startup_shell = Radiobutton(
404 frame_run, variable=self.startup_edit, value=0,
Terry Jan Reedyf46b7822016-11-07 17:15:01 -0500405 text='Open Shell Window')
csabellabac7d332017-06-26 17:46:26 -0400406 #frame_save
407 run_save_title = Label(frame_save, text='At Start of Run (F5) ')
408 self.radio_save_ask = Radiobutton(
409 frame_save, variable=self.autosave, value=0,
Terry Jan Reedyf46b7822016-11-07 17:15:01 -0500410 text="Prompt to Save")
csabellabac7d332017-06-26 17:46:26 -0400411 self.radio_save_auto = Radiobutton(
412 frame_save, variable=self.autosave, value=1,
Terry Jan Reedyf46b7822016-11-07 17:15:01 -0500413 text='No Prompt')
csabellabac7d332017-06-26 17:46:26 -0400414 #frame_win_size
415 win_size_title = Label(
416 frame_win_size, text='Initial Window Size (in characters)')
417 win_width_title = Label(frame_win_size, text='Width')
418 self.entry_win_width = Entry(
419 frame_win_size, textvariable=self.win_width, width=3)
420 win_height_title = Label(frame_win_size, text='Height')
421 self.entry_win_height = Entry(
422 frame_win_size, textvariable=self.win_height, width=3)
423 #frame_help
424 frame_helplist = Frame(frame_help)
425 frame_helplist_buttons = Frame(frame_helplist)
426 scroll_helplist = Scrollbar(frame_helplist)
427 self.list_help = Listbox(
428 frame_helplist, height=5, takefocus=FALSE,
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000429 exportselection=FALSE)
csabellabac7d332017-06-26 17:46:26 -0400430 scroll_helplist.config(command=self.list_help.yview)
431 self.list_help.config(yscrollcommand=scroll_helplist.set)
432 self.list_help.bind('<ButtonRelease-1>', self.help_source_selected)
433 self.button_helplist_edit = Button(
434 frame_helplist_buttons, text='Edit', state=DISABLED,
435 width=8, command=self.helplist_item_edit)
436 self.button_helplist_add = Button(
437 frame_helplist_buttons, text='Add',
438 width=8, command=self.helplist_item_add)
439 self.button_helplist_remove = Button(
440 frame_helplist_buttons, text='Remove', state=DISABLED,
441 width=8, command=self.helplist_item_remove)
Terry Jan Reedy22405332014-07-30 19:24:32 -0400442
Steven M. Gava230e5782001-08-07 03:28:25 +0000443 #widget packing
444 #body
csabellabac7d332017-06-26 17:46:26 -0400445 frame_run.pack(side=TOP, padx=5, pady=5, fill=X)
446 frame_save.pack(side=TOP, padx=5, pady=5, fill=X)
447 frame_win_size.pack(side=TOP, padx=5, pady=5, fill=X)
448 frame_help.pack(side=TOP, padx=5, pady=5, expand=TRUE, fill=BOTH)
449 #frame_run
450 startup_title.pack(side=LEFT, anchor=W, padx=5, pady=5)
451 self.radio_startup_shell.pack(side=RIGHT, anchor=W, padx=5, pady=5)
452 self.radio_startup_edit.pack(side=RIGHT, anchor=W, padx=5, pady=5)
453 #frame_save
454 run_save_title.pack(side=LEFT, anchor=W, padx=5, pady=5)
455 self.radio_save_auto.pack(side=RIGHT, anchor=W, padx=5, pady=5)
456 self.radio_save_ask.pack(side=RIGHT, anchor=W, padx=5, pady=5)
457 #frame_win_size
458 win_size_title.pack(side=LEFT, anchor=W, padx=5, pady=5)
459 self.entry_win_height.pack(side=RIGHT, anchor=E, padx=10, pady=5)
460 win_height_title.pack(side=RIGHT, anchor=E, pady=5)
461 self.entry_win_width.pack(side=RIGHT, anchor=E, padx=10, pady=5)
462 win_width_title.pack(side=RIGHT, anchor=E, pady=5)
463 #frame_help
464 frame_helplist_buttons.pack(side=RIGHT, padx=5, pady=5, fill=Y)
465 frame_helplist.pack(side=TOP, padx=5, pady=5, expand=TRUE, fill=BOTH)
466 scroll_helplist.pack(side=RIGHT, anchor=W, fill=Y)
467 self.list_help.pack(side=LEFT, anchor=E, expand=TRUE, fill=BOTH)
468 self.button_helplist_edit.pack(side=TOP, anchor=W, pady=5)
469 self.button_helplist_add.pack(side=TOP, anchor=W)
470 self.button_helplist_remove.pack(side=TOP, anchor=W, pady=5)
Steven M. Gava952d0a52001-08-03 04:43:44 +0000471 return frame
472
csabellabac7d332017-06-26 17:46:26 -0400473 def attach_var_callbacks(self):
474 self.font_size.trace_add('write', self.var_changed_font)
475 self.font_name.trace_add('write', self.var_changed_font)
476 self.font_bold.trace_add('write', self.var_changed_font)
477 self.space_num.trace_add('write', self.var_changed_space_num)
478 self.colour.trace_add('write', self.var_changed_colour)
479 self.builtin_theme.trace_add('write', self.var_changed_builtin_theme)
480 self.custom_theme.trace_add('write', self.var_changed_custom_theme)
481 self.is_builtin_theme.trace_add('write', self.var_changed_is_builtin_theme)
482 self.highlight_target.trace_add('write', self.var_changed_highlight_target)
483 self.keybinding.trace_add('write', self.var_changed_keybinding)
484 self.builtin_keys.trace_add('write', self.var_changed_builtin_keys)
485 self.custom_keys.trace_add('write', self.var_changed_custom_keys)
486 self.are_keys_builtin.trace_add('write', self.var_changed_are_keys_builtin)
487 self.win_width.trace_add('write', self.var_changed_win_width)
488 self.win_height.trace_add('write', self.var_changed_win_height)
489 self.startup_edit.trace_add('write', self.var_changed_startup_edit)
490 self.autosave.trace_add('write', self.var_changed_autosave)
491 self.encoding.trace_add('write', self.var_changed_encoding)
Steven M. Gava052937f2002-02-11 02:20:53 +0000492
Terry Jan Reedy6b98ce22016-05-16 22:27:28 -0400493 def remove_var_callbacks(self):
494 "Remove callbacks to prevent memory leaks."
495 for var in (
csabellabac7d332017-06-26 17:46:26 -0400496 self.font_size, self.font_name, self.font_bold,
497 self.space_num, self.colour, self.builtin_theme,
498 self.custom_theme, self.is_builtin_theme, self.highlight_target,
499 self.keybinding, self.builtin_keys, self.custom_keys,
500 self.are_keys_builtin, self.win_width, self.win_height,
501 self.startup_edit, self.autosave, self.encoding,):
Serhiy Storchaka81221742016-06-26 09:46:57 +0300502 var.trace_remove('write', var.trace_info()[0][1])
Terry Jan Reedy6b98ce22016-05-16 22:27:28 -0400503
csabellabac7d332017-06-26 17:46:26 -0400504 def var_changed_font(self, *params):
Terry Jan Reedyd87d1682015-08-01 18:57:33 -0400505 '''When one font attribute changes, save them all, as they are
506 not independent from each other. In particular, when we are
507 overriding the default font, we need to write out everything.
508 '''
csabellabac7d332017-06-26 17:46:26 -0400509 value = self.font_name.get()
510 self.add_changed_item('main', 'EditorWindow', 'font', value)
511 value = self.font_size.get()
512 self.add_changed_item('main', 'EditorWindow', 'font-size', value)
513 value = self.font_bold.get()
514 self.add_changed_item('main', 'EditorWindow', 'font-bold', value)
Steven M. Gavac112cd82002-01-22 05:56:40 +0000515
csabellabac7d332017-06-26 17:46:26 -0400516 def var_changed_space_num(self, *params):
517 value = self.space_num.get()
518 self.add_changed_item('main', 'Indent', 'num-spaces', value)
Steven M. Gavac112cd82002-01-22 05:56:40 +0000519
csabellabac7d332017-06-26 17:46:26 -0400520 def var_changed_colour(self, *params):
521 self.on_new_colour_set()
Steven M. Gava052937f2002-02-11 02:20:53 +0000522
csabellabac7d332017-06-26 17:46:26 -0400523 def var_changed_builtin_theme(self, *params):
524 old_themes = ('IDLE Classic', 'IDLE New')
525 value = self.builtin_theme.get()
526 if value not in old_themes:
527 if idleConf.GetOption('main', 'Theme', 'name') not in old_themes:
528 self.add_changed_item('main', 'Theme', 'name', old_themes[0])
529 self.add_changed_item('main', 'Theme', 'name2', value)
Terry Jan Reedyd0c0f002015-11-12 15:02:57 -0500530 self.new_custom_theme.config(text='New theme, see Help',
531 fg='#500000')
532 else:
csabellabac7d332017-06-26 17:46:26 -0400533 self.add_changed_item('main', 'Theme', 'name', value)
534 self.add_changed_item('main', 'Theme', 'name2', '')
Terry Jan Reedyd0c0f002015-11-12 15:02:57 -0500535 self.new_custom_theme.config(text='', fg='black')
csabellabac7d332017-06-26 17:46:26 -0400536 self.paint_theme_sample()
Steven M. Gava052937f2002-02-11 02:20:53 +0000537
csabellabac7d332017-06-26 17:46:26 -0400538 def var_changed_custom_theme(self, *params):
539 value = self.custom_theme.get()
Steven M. Gava49745752002-02-18 01:43:11 +0000540 if value != '- no custom themes -':
csabellabac7d332017-06-26 17:46:26 -0400541 self.add_changed_item('main', 'Theme', 'name', value)
542 self.paint_theme_sample()
Steven M. Gava052937f2002-02-11 02:20:53 +0000543
csabellabac7d332017-06-26 17:46:26 -0400544 def var_changed_is_builtin_theme(self, *params):
545 value = self.is_builtin_theme.get()
546 self.add_changed_item('main', 'Theme', 'default', value)
Steven M. Gavaf31eec02002-03-05 00:25:58 +0000547 if value:
csabellabac7d332017-06-26 17:46:26 -0400548 self.var_changed_builtin_theme()
Steven M. Gavaf31eec02002-03-05 00:25:58 +0000549 else:
csabellabac7d332017-06-26 17:46:26 -0400550 self.var_changed_custom_theme()
Steven M. Gava052937f2002-02-11 02:20:53 +0000551
csabellabac7d332017-06-26 17:46:26 -0400552 def var_changed_highlight_target(self, *params):
553 self.set_highlight_target()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000554
csabellabac7d332017-06-26 17:46:26 -0400555 def var_changed_keybinding(self, *params):
556 value = self.keybinding.get()
557 key_set = self.custom_keys.get()
558 event = self.list_bindings.get(ANCHOR).split()[0]
Steven M. Gavaa498af22002-02-01 01:33:36 +0000559 if idleConf.IsCoreBinding(event):
560 #this is a core keybinding
csabellabac7d332017-06-26 17:46:26 -0400561 self.add_changed_item('keys', key_set, event, value)
Steven M. Gavaa498af22002-02-01 01:33:36 +0000562 else: #this is an extension key binding
csabellabac7d332017-06-26 17:46:26 -0400563 ext_name = idleConf.GetExtnNameForEvent(event)
564 ext_keybind_section = ext_name + '_cfgBindings'
565 self.add_changed_item('extensions', ext_keybind_section, event, value)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000566
csabellabac7d332017-06-26 17:46:26 -0400567 def var_changed_builtin_keys(self, *params):
568 old_keys = (
Terry Jan Reedy9bdb1ed2016-07-10 13:46:34 -0400569 'IDLE Classic Windows',
570 'IDLE Classic Unix',
571 'IDLE Classic Mac',
572 'IDLE Classic OSX',
573 )
csabellabac7d332017-06-26 17:46:26 -0400574 value = self.builtin_keys.get()
575 if value not in old_keys:
576 if idleConf.GetOption('main', 'Keys', 'name') not in old_keys:
577 self.add_changed_item('main', 'Keys', 'name', old_keys[0])
578 self.add_changed_item('main', 'Keys', 'name2', value)
Terry Jan Reedy9bdb1ed2016-07-10 13:46:34 -0400579 self.new_custom_keys.config(text='New key set, see Help',
580 fg='#500000')
581 else:
csabellabac7d332017-06-26 17:46:26 -0400582 self.add_changed_item('main', 'Keys', 'name', value)
583 self.add_changed_item('main', 'Keys', 'name2', '')
Terry Jan Reedy9bdb1ed2016-07-10 13:46:34 -0400584 self.new_custom_keys.config(text='', fg='black')
csabellabac7d332017-06-26 17:46:26 -0400585 self.load_keys_list(value)
Steven M. Gava052937f2002-02-11 02:20:53 +0000586
csabellabac7d332017-06-26 17:46:26 -0400587 def var_changed_custom_keys(self, *params):
588 value = self.custom_keys.get()
Steven M. Gava49745752002-02-18 01:43:11 +0000589 if value != '- no custom keys -':
csabellabac7d332017-06-26 17:46:26 -0400590 self.add_changed_item('main', 'Keys', 'name', value)
591 self.load_keys_list(value)
Steven M. Gava052937f2002-02-11 02:20:53 +0000592
csabellabac7d332017-06-26 17:46:26 -0400593 def var_changed_are_keys_builtin(self, *params):
594 value = self.are_keys_builtin.get()
595 self.add_changed_item('main', 'Keys', 'default', value)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000596 if value:
csabellabac7d332017-06-26 17:46:26 -0400597 self.var_changed_builtin_keys()
Steven M. Gava052937f2002-02-11 02:20:53 +0000598 else:
csabellabac7d332017-06-26 17:46:26 -0400599 self.var_changed_custom_keys()
Steven M. Gava052937f2002-02-11 02:20:53 +0000600
csabellabac7d332017-06-26 17:46:26 -0400601 def var_changed_win_width(self, *params):
602 value = self.win_width.get()
603 self.add_changed_item('main', 'EditorWindow', 'width', value)
Steven M. Gavac112cd82002-01-22 05:56:40 +0000604
csabellabac7d332017-06-26 17:46:26 -0400605 def var_changed_win_height(self, *params):
606 value = self.win_height.get()
607 self.add_changed_item('main', 'EditorWindow', 'height', value)
Steven M. Gavac112cd82002-01-22 05:56:40 +0000608
csabellabac7d332017-06-26 17:46:26 -0400609 def var_changed_startup_edit(self, *params):
610 value = self.startup_edit.get()
611 self.add_changed_item('main', 'General', 'editor-on-startup', value)
Steven M. Gavac112cd82002-01-22 05:56:40 +0000612
csabellabac7d332017-06-26 17:46:26 -0400613 def var_changed_autosave(self, *params):
614 value = self.autosave.get()
615 self.add_changed_item('main', 'General', 'autosave', value)
Kurt B. Kaiser6c638b62003-05-26 06:23:10 +0000616
csabellabac7d332017-06-26 17:46:26 -0400617 def var_changed_encoding(self, *params):
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400618 value = self.encoding.get()
csabellabac7d332017-06-26 17:46:26 -0400619 self.add_changed_item('main', 'EditorWindow', 'encoding', value)
Kurt B. Kaisera053f332003-05-10 00:49:56 +0000620
csabellabac7d332017-06-26 17:46:26 -0400621 def reset_changed_items(self):
Steven M. Gavab77d3432002-03-02 07:16:21 +0000622 #When any config item is changed in this dialog, an entry
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000623 #should be made in the relevant section (config type) of this
624 #dictionary. The key should be the config file section name and the
Steven M. Gavaa498af22002-02-01 01:33:36 +0000625 #value a dictionary, whose key:value pairs are item=value pairs for
626 #that config file section.
csabellabac7d332017-06-26 17:46:26 -0400627 self.changed_items = {'main':{}, 'highlight':{}, 'keys':{},
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400628 'extensions':{}}
Steven M. Gavaa498af22002-02-01 01:33:36 +0000629
csabellabac7d332017-06-26 17:46:26 -0400630 def add_changed_item(self, typ, section, item, value):
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400631 value = str(value) #make sure we use a string
csabellabac7d332017-06-26 17:46:26 -0400632 if section not in self.changed_items[typ]:
633 self.changed_items[typ][section] = {}
634 self.changed_items[typ][section][item] = value
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000635
Steven M. Gava5f28e8f2002-01-21 06:38:21 +0000636 def GetDefaultItems(self):
csabellabac7d332017-06-26 17:46:26 -0400637 d_items={'main':{}, 'highlight':{}, 'keys':{}, 'extensions':{}}
638 for config_type in d_items:
639 sections = idleConf.GetSectionList('default', config_type)
Steven M. Gava5f28e8f2002-01-21 06:38:21 +0000640 for section in sections:
csabellabac7d332017-06-26 17:46:26 -0400641 d_items[config_type][section] = {}
642 options = idleConf.defaultCfg[config_type].GetOptionList(section)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000643 for option in options:
csabellabac7d332017-06-26 17:46:26 -0400644 d_items[config_type][section][option] = (
645 idleConf.defaultCfg[config_type].Get(section, option))
646 return d_items
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000647
csabellabac7d332017-06-26 17:46:26 -0400648 def set_theme_type(self):
649 if self.is_builtin_theme.get():
650 self.opt_menu_theme_builtin.config(state=NORMAL)
651 self.opt_menu_theme_custom.config(state=DISABLED)
652 self.button_delete_custom_theme.config(state=DISABLED)
Steven M. Gava5f28e8f2002-01-21 06:38:21 +0000653 else:
csabellabac7d332017-06-26 17:46:26 -0400654 self.opt_menu_theme_builtin.config(state=DISABLED)
655 self.radio_theme_custom.config(state=NORMAL)
656 self.opt_menu_theme_custom.config(state=NORMAL)
657 self.button_delete_custom_theme.config(state=NORMAL)
Steven M. Gava5f28e8f2002-01-21 06:38:21 +0000658
csabellabac7d332017-06-26 17:46:26 -0400659 def set_keys_type(self):
660 if self.are_keys_builtin.get():
661 self.opt_menu_keys_builtin.config(state=NORMAL)
662 self.opt_menu_keys_custom.config(state=DISABLED)
663 self.button_delete_custom_keys.config(state=DISABLED)
Steven M. Gava5f28e8f2002-01-21 06:38:21 +0000664 else:
csabellabac7d332017-06-26 17:46:26 -0400665 self.opt_menu_keys_builtin.config(state=DISABLED)
666 self.radio_keys_custom.config(state=NORMAL)
667 self.opt_menu_keys_custom.config(state=NORMAL)
668 self.button_delete_custom_keys.config(state=NORMAL)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000669
csabellabac7d332017-06-26 17:46:26 -0400670 def get_new_keys(self):
671 list_index = self.list_bindings.index(ANCHOR)
672 binding = self.list_bindings.get(list_index)
673 bind_name = binding.split()[0] #first part, up to first space
674 if self.are_keys_builtin.get():
675 current_key_set_name = self.builtin_keys.get()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000676 else:
csabellabac7d332017-06-26 17:46:26 -0400677 current_key_set_name = self.custom_keys.get()
678 current_bindings = idleConf.GetCurrentKeySet()
679 if current_key_set_name in self.changed_items['keys']: #unsaved changes
680 key_set_changes = self.changed_items['keys'][current_key_set_name]
681 for event in key_set_changes:
682 current_bindings[event] = key_set_changes[event].split()
683 current_key_sequences = list(current_bindings.values())
684 new_keys = GetKeysDialog(self, 'Get New Keys', bind_name,
685 current_key_sequences).result
686 if new_keys: #new keys were specified
687 if self.are_keys_builtin.get(): #current key set is a built-in
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400688 message = ('Your changes will be saved as a new Custom Key Set.'
689 ' Enter a name for your new Custom Key Set below.')
csabellabac7d332017-06-26 17:46:26 -0400690 new_keyset = self.get_new_keys_name(message)
691 if not new_keyset: #user cancelled custom key set creation
692 self.list_bindings.select_set(list_index)
693 self.list_bindings.select_anchor(list_index)
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000694 return
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000695 else: #create new custom key set based on previously active key set
csabellabac7d332017-06-26 17:46:26 -0400696 self.create_new_key_set(new_keyset)
697 self.list_bindings.delete(list_index)
698 self.list_bindings.insert(list_index, bind_name+' - '+new_keys)
699 self.list_bindings.select_set(list_index)
700 self.list_bindings.select_anchor(list_index)
701 self.keybinding.set(new_keys)
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000702 else:
csabellabac7d332017-06-26 17:46:26 -0400703 self.list_bindings.select_set(list_index)
704 self.list_bindings.select_anchor(list_index)
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000705
csabellabac7d332017-06-26 17:46:26 -0400706 def get_new_keys_name(self, message):
707 used_names = (idleConf.GetSectionList('user', 'keys') +
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400708 idleConf.GetSectionList('default', 'keys'))
csabellabac7d332017-06-26 17:46:26 -0400709 new_keyset = SectionName(
710 self, 'New Custom Key Set', message, used_names).result
711 return new_keyset
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000712
csabellabac7d332017-06-26 17:46:26 -0400713 def save_as_new_key_set(self):
714 new_keys_name = self.get_new_keys_name('New Key Set Name:')
715 if new_keys_name:
716 self.create_new_key_set(new_keys_name)
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000717
csabellabac7d332017-06-26 17:46:26 -0400718 def keybinding_selected(self, event):
719 self.button_new_keys.config(state=NORMAL)
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000720
csabellabac7d332017-06-26 17:46:26 -0400721 def create_new_key_set(self, new_key_set_name):
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000722 #creates new custom key set based on the previously active key set,
723 #and makes the new key set active
csabellabac7d332017-06-26 17:46:26 -0400724 if self.are_keys_builtin.get():
725 prev_key_set_name = self.builtin_keys.get()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000726 else:
csabellabac7d332017-06-26 17:46:26 -0400727 prev_key_set_name = self.custom_keys.get()
728 prev_keys = idleConf.GetCoreKeys(prev_key_set_name)
729 new_keys = {}
730 for event in prev_keys: #add key set to changed items
731 event_name = event[2:-2] #trim off the angle brackets
732 binding = ' '.join(prev_keys[event])
733 new_keys[event_name] = binding
Steven M. Gava052937f2002-02-11 02:20:53 +0000734 #handle any unsaved changes to prev key set
csabellabac7d332017-06-26 17:46:26 -0400735 if prev_key_set_name in self.changed_items['keys']:
736 key_set_changes = self.changed_items['keys'][prev_key_set_name]
737 for event in key_set_changes:
738 new_keys[event] = key_set_changes[event]
Steven M. Gava052937f2002-02-11 02:20:53 +0000739 #save the new theme
csabellabac7d332017-06-26 17:46:26 -0400740 self.save_new_key_set(new_key_set_name, new_keys)
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000741 #change gui over to the new key set
csabellabac7d332017-06-26 17:46:26 -0400742 custom_key_list = idleConf.GetSectionList('user', 'keys')
743 custom_key_list.sort()
744 self.opt_menu_keys_custom.SetMenu(custom_key_list, new_key_set_name)
745 self.are_keys_builtin.set(0)
746 self.set_keys_type()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000747
csabellabac7d332017-06-26 17:46:26 -0400748 def load_keys_list(self, keyset_name):
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400749 reselect = 0
csabellabac7d332017-06-26 17:46:26 -0400750 new_keyset = 0
751 if self.list_bindings.curselection():
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400752 reselect = 1
csabellabac7d332017-06-26 17:46:26 -0400753 list_index = self.list_bindings.index(ANCHOR)
754 keyset = idleConf.GetKeySet(keyset_name)
755 bind_names = list(keyset.keys())
756 bind_names.sort()
757 self.list_bindings.delete(0, END)
758 for bind_name in bind_names:
759 key = ' '.join(keyset[bind_name]) #make key(s) into a string
760 bind_name = bind_name[2:-2] #trim off the angle brackets
761 if keyset_name in self.changed_items['keys']:
Steven M. Gava052937f2002-02-11 02:20:53 +0000762 #handle any unsaved changes to this key set
csabellabac7d332017-06-26 17:46:26 -0400763 if bind_name in self.changed_items['keys'][keyset_name]:
764 key = self.changed_items['keys'][keyset_name][bind_name]
765 self.list_bindings.insert(END, bind_name+' - '+key)
Steven M. Gava052937f2002-02-11 02:20:53 +0000766 if reselect:
csabellabac7d332017-06-26 17:46:26 -0400767 self.list_bindings.see(list_index)
768 self.list_bindings.select_set(list_index)
769 self.list_bindings.select_anchor(list_index)
Steven M. Gava052937f2002-02-11 02:20:53 +0000770
csabellabac7d332017-06-26 17:46:26 -0400771 def delete_custom_keys(self):
772 keyset_name=self.custom_keys.get()
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400773 delmsg = 'Are you sure you wish to delete the key set %r ?'
774 if not tkMessageBox.askyesno(
csabellabac7d332017-06-26 17:46:26 -0400775 'Delete Key Set', delmsg % keyset_name, parent=self):
Steven M. Gava49745752002-02-18 01:43:11 +0000776 return
csabellabac7d332017-06-26 17:46:26 -0400777 self.deactivate_current_config()
Steven M. Gava49745752002-02-18 01:43:11 +0000778 #remove key set from config
csabellabac7d332017-06-26 17:46:26 -0400779 idleConf.userCfg['keys'].remove_section(keyset_name)
780 if keyset_name in self.changed_items['keys']:
781 del(self.changed_items['keys'][keyset_name])
Steven M. Gava49745752002-02-18 01:43:11 +0000782 #write changes
783 idleConf.userCfg['keys'].Save()
784 #reload user key set list
csabellabac7d332017-06-26 17:46:26 -0400785 item_list = idleConf.GetSectionList('user', 'keys')
786 item_list.sort()
787 if not item_list:
788 self.radio_keys_custom.config(state=DISABLED)
789 self.opt_menu_keys_custom.SetMenu(item_list, '- no custom keys -')
Steven M. Gava49745752002-02-18 01:43:11 +0000790 else:
csabellabac7d332017-06-26 17:46:26 -0400791 self.opt_menu_keys_custom.SetMenu(item_list, item_list[0])
Steven M. Gava49745752002-02-18 01:43:11 +0000792 #revert to default key set
csabellabac7d332017-06-26 17:46:26 -0400793 self.are_keys_builtin.set(idleConf.defaultCfg['main']
Terry Jan Reedy9bdb1ed2016-07-10 13:46:34 -0400794 .Get('Keys', 'default'))
csabellabac7d332017-06-26 17:46:26 -0400795 self.builtin_keys.set(idleConf.defaultCfg['main'].Get('Keys', 'name')
Terry Jan Reedy9bdb1ed2016-07-10 13:46:34 -0400796 or idleConf.default_keys())
Steven M. Gava49745752002-02-18 01:43:11 +0000797 #user can't back out of these changes, they must be applied now
csabellabac7d332017-06-26 17:46:26 -0400798 self.save_all_changed_configs()
799 self.activate_config_changes()
800 self.set_keys_type()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000801
csabellabac7d332017-06-26 17:46:26 -0400802 def delete_custom_theme(self):
803 theme_name = self.custom_theme.get()
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400804 delmsg = 'Are you sure you wish to delete the theme %r ?'
805 if not tkMessageBox.askyesno(
csabellabac7d332017-06-26 17:46:26 -0400806 'Delete Theme', delmsg % theme_name, parent=self):
Steven M. Gava49745752002-02-18 01:43:11 +0000807 return
csabellabac7d332017-06-26 17:46:26 -0400808 self.deactivate_current_config()
Steven M. Gava49745752002-02-18 01:43:11 +0000809 #remove theme from config
csabellabac7d332017-06-26 17:46:26 -0400810 idleConf.userCfg['highlight'].remove_section(theme_name)
811 if theme_name in self.changed_items['highlight']:
812 del(self.changed_items['highlight'][theme_name])
Steven M. Gava49745752002-02-18 01:43:11 +0000813 #write changes
814 idleConf.userCfg['highlight'].Save()
815 #reload user theme list
csabellabac7d332017-06-26 17:46:26 -0400816 item_list = idleConf.GetSectionList('user', 'highlight')
817 item_list.sort()
818 if not item_list:
819 self.radio_theme_custom.config(state=DISABLED)
820 self.opt_menu_theme_custom.SetMenu(item_list, '- no custom themes -')
Steven M. Gava49745752002-02-18 01:43:11 +0000821 else:
csabellabac7d332017-06-26 17:46:26 -0400822 self.opt_menu_theme_custom.SetMenu(item_list, item_list[0])
Steven M. Gava49745752002-02-18 01:43:11 +0000823 #revert to default theme
csabellabac7d332017-06-26 17:46:26 -0400824 self.is_builtin_theme.set(idleConf.defaultCfg['main'].Get('Theme', 'default'))
825 self.builtin_theme.set(idleConf.defaultCfg['main'].Get('Theme', 'name'))
Steven M. Gava49745752002-02-18 01:43:11 +0000826 #user can't back out of these changes, they must be applied now
csabellabac7d332017-06-26 17:46:26 -0400827 self.save_all_changed_configs()
828 self.activate_config_changes()
829 self.set_theme_type()
Steven M. Gava49745752002-02-18 01:43:11 +0000830
csabellabac7d332017-06-26 17:46:26 -0400831 def get_colour(self):
832 target = self.highlight_target.get()
833 prev_colour = self.frame_colour_set.cget('bg')
834 rgbTuplet, colour_string = tkColorChooser.askcolor(
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400835 parent=self, title='Pick new colour for : '+target,
csabellabac7d332017-06-26 17:46:26 -0400836 initialcolor=prev_colour)
837 if colour_string and (colour_string != prev_colour):
Steven M. Gava052937f2002-02-11 02:20:53 +0000838 #user didn't cancel, and they chose a new colour
csabellabac7d332017-06-26 17:46:26 -0400839 if self.is_builtin_theme.get(): #current theme is a built-in
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400840 message = ('Your changes will be saved as a new Custom Theme. '
841 'Enter a name for your new Custom Theme below.')
csabellabac7d332017-06-26 17:46:26 -0400842 new_theme = self.get_new_theme_name(message)
843 if not new_theme: #user cancelled custom theme creation
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000844 return
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400845 else: #create new custom theme based on previously active theme
csabellabac7d332017-06-26 17:46:26 -0400846 self.create_new_theme(new_theme)
847 self.colour.set(colour_string)
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400848 else: #current theme is user defined
csabellabac7d332017-06-26 17:46:26 -0400849 self.colour.set(colour_string)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000850
csabellabac7d332017-06-26 17:46:26 -0400851 def on_new_colour_set(self):
852 new_colour=self.colour.get()
853 self.frame_colour_set.config(bg=new_colour) #set sample
854 plane ='foreground' if self.fg_bg_toggle.get() else 'background'
855 sample_element = self.theme_elements[self.highlight_target.get()][0]
856 self.text_highlight_sample.tag_config(sample_element, **{plane:new_colour})
857 theme = self.custom_theme.get()
858 theme_element = sample_element + '-' + plane
859 self.add_changed_item('highlight', theme, theme_element, new_colour)
Steven M. Gava052937f2002-02-11 02:20:53 +0000860
csabellabac7d332017-06-26 17:46:26 -0400861 def get_new_theme_name(self, message):
862 used_names = (idleConf.GetSectionList('user', 'highlight') +
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400863 idleConf.GetSectionList('default', 'highlight'))
csabellabac7d332017-06-26 17:46:26 -0400864 new_theme = SectionName(
865 self, 'New Custom Theme', message, used_names).result
866 return new_theme
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000867
csabellabac7d332017-06-26 17:46:26 -0400868 def save_as_new_theme(self):
869 new_theme_name = self.get_new_theme_name('New Theme Name:')
870 if new_theme_name:
871 self.create_new_theme(new_theme_name)
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000872
csabellabac7d332017-06-26 17:46:26 -0400873 def create_new_theme(self, new_theme_name):
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000874 #creates new custom theme based on the previously active theme,
875 #and makes the new theme active
csabellabac7d332017-06-26 17:46:26 -0400876 if self.is_builtin_theme.get():
877 theme_type = 'default'
878 theme_name = self.builtin_theme.get()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000879 else:
csabellabac7d332017-06-26 17:46:26 -0400880 theme_type = 'user'
881 theme_name = self.custom_theme.get()
882 new_theme = idleConf.GetThemeDict(theme_type, theme_name)
Steven M. Gava052937f2002-02-11 02:20:53 +0000883 #apply any of the old theme's unsaved changes to the new theme
csabellabac7d332017-06-26 17:46:26 -0400884 if theme_name in self.changed_items['highlight']:
885 theme_changes = self.changed_items['highlight'][theme_name]
886 for element in theme_changes:
887 new_theme[element] = theme_changes[element]
Steven M. Gava052937f2002-02-11 02:20:53 +0000888 #save the new theme
csabellabac7d332017-06-26 17:46:26 -0400889 self.save_new_theme(new_theme_name, new_theme)
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000890 #change gui over to the new theme
csabellabac7d332017-06-26 17:46:26 -0400891 custom_theme_list = idleConf.GetSectionList('user', 'highlight')
892 custom_theme_list.sort()
893 self.opt_menu_theme_custom.SetMenu(custom_theme_list, new_theme_name)
894 self.is_builtin_theme.set(0)
895 self.set_theme_type()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000896
csabellabac7d332017-06-26 17:46:26 -0400897 def on_list_fonts_button_release(self, event):
898 font = self.list_fonts.get(ANCHOR)
899 self.font_name.set(font.lower())
900 self.set_font_sample()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000901
csabellabac7d332017-06-26 17:46:26 -0400902 def set_font_sample(self, event=None):
903 font_name = self.font_name.get()
904 font_weight = tkFont.BOLD if self.font_bold.get() else tkFont.NORMAL
905 new_font = (font_name, self.font_size.get(), font_weight)
906 self.font_sample.config(font=new_font)
907 self.text_highlight_sample.configure(font=new_font)
Steven M. Gava5f28e8f2002-01-21 06:38:21 +0000908
csabellabac7d332017-06-26 17:46:26 -0400909 def set_highlight_target(self):
910 if self.highlight_target.get() == 'Cursor': #bg not possible
911 self.radio_fg.config(state=DISABLED)
912 self.radio_bg.config(state=DISABLED)
913 self.fg_bg_toggle.set(1)
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400914 else: #both fg and bg can be set
csabellabac7d332017-06-26 17:46:26 -0400915 self.radio_fg.config(state=NORMAL)
916 self.radio_bg.config(state=NORMAL)
917 self.fg_bg_toggle.set(1)
918 self.set_colour_sample()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000919
csabellabac7d332017-06-26 17:46:26 -0400920 def set_colour_sample_binding(self, *args):
921 self.set_colour_sample()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000922
csabellabac7d332017-06-26 17:46:26 -0400923 def set_colour_sample(self):
Steven M. Gava5f28e8f2002-01-21 06:38:21 +0000924 #set the colour smaple area
csabellabac7d332017-06-26 17:46:26 -0400925 tag = self.theme_elements[self.highlight_target.get()][0]
926 plane = 'foreground' if self.fg_bg_toggle.get() else 'background'
927 colour = self.text_highlight_sample.tag_cget(tag, plane)
928 self.frame_colour_set.config(bg=colour)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000929
csabellabac7d332017-06-26 17:46:26 -0400930 def paint_theme_sample(self):
931 if self.is_builtin_theme.get(): #a default theme
932 theme = self.builtin_theme.get()
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400933 else: #a user theme
csabellabac7d332017-06-26 17:46:26 -0400934 theme = self.custom_theme.get()
935 for element_title in self.theme_elements:
936 element = self.theme_elements[element_title][0]
Terry Jan Reedy4036d872014-08-03 23:02:58 -0400937 colours = idleConf.GetHighlight(theme, element)
938 if element == 'cursor': #cursor sample needs special painting
939 colours['background'] = idleConf.GetHighlight(
940 theme, 'normal', fgBg='bg')
Steven M. Gava052937f2002-02-11 02:20:53 +0000941 #handle any unsaved changes to this theme
csabellabac7d332017-06-26 17:46:26 -0400942 if theme in self.changed_items['highlight']:
943 theme_dict = self.changed_items['highlight'][theme]
944 if element + '-foreground' in theme_dict:
945 colours['foreground'] = theme_dict[element + '-foreground']
946 if element + '-background' in theme_dict:
947 colours['background'] = theme_dict[element + '-background']
948 self.text_highlight_sample.tag_config(element, **colours)
949 self.set_colour_sample()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000950
csabellabac7d332017-06-26 17:46:26 -0400951 def help_source_selected(self, event):
952 self.set_helplist_button_states()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000953
csabellabac7d332017-06-26 17:46:26 -0400954 def set_helplist_button_states(self):
955 if self.list_help.size() < 1: #no entries in list
956 self.button_helplist_edit.config(state=DISABLED)
957 self.button_helplist_remove.config(state=DISABLED)
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000958 else: #there are some entries
csabellabac7d332017-06-26 17:46:26 -0400959 if self.list_help.curselection(): #there currently is a selection
960 self.button_helplist_edit.config(state=NORMAL)
961 self.button_helplist_remove.config(state=NORMAL)
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000962 else: #there currently is not a selection
csabellabac7d332017-06-26 17:46:26 -0400963 self.button_helplist_edit.config(state=DISABLED)
964 self.button_helplist_remove.config(state=DISABLED)
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000965
csabellabac7d332017-06-26 17:46:26 -0400966 def helplist_item_add(self):
967 help_source = HelpSource(self, 'New Help Source',
Terry Jan Reedy8b22c0a2016-07-08 00:22:50 -0400968 ).result
csabellabac7d332017-06-26 17:46:26 -0400969 if help_source:
970 self.user_helplist.append((help_source[0], help_source[1]))
971 self.list_help.insert(END, help_source[0])
972 self.update_user_help_changed_items()
973 self.set_helplist_button_states()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000974
csabellabac7d332017-06-26 17:46:26 -0400975 def helplist_item_edit(self):
976 item_index = self.list_help.index(ANCHOR)
977 help_source = self.user_helplist[item_index]
978 new_help_source = HelpSource(
Terry Jan Reedy8b22c0a2016-07-08 00:22:50 -0400979 self, 'Edit Help Source',
csabellabac7d332017-06-26 17:46:26 -0400980 menuitem=help_source[0],
981 filepath=help_source[1],
Terry Jan Reedy8b22c0a2016-07-08 00:22:50 -0400982 ).result
csabellabac7d332017-06-26 17:46:26 -0400983 if new_help_source and new_help_source != help_source:
984 self.user_helplist[item_index] = new_help_source
985 self.list_help.delete(item_index)
986 self.list_help.insert(item_index, new_help_source[0])
987 self.update_user_help_changed_items()
988 self.set_helplist_button_states()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000989
csabellabac7d332017-06-26 17:46:26 -0400990 def helplist_item_remove(self):
991 item_index = self.list_help.index(ANCHOR)
992 del(self.user_helplist[item_index])
993 self.list_help.delete(item_index)
994 self.update_user_help_changed_items()
995 self.set_helplist_button_states()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000996
csabellabac7d332017-06-26 17:46:26 -0400997 def update_user_help_changed_items(self):
998 "Clear and rebuild the HelpFiles section in self.changed_items"
999 self.changed_items['main']['HelpFiles'] = {}
1000 for num in range(1, len(self.user_helplist) + 1):
1001 self.add_changed_item(
Terry Jan Reedy4036d872014-08-03 23:02:58 -04001002 'main', 'HelpFiles', str(num),
csabellabac7d332017-06-26 17:46:26 -04001003 ';'.join(self.user_helplist[num-1][:2]))
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001004
csabellabac7d332017-06-26 17:46:26 -04001005 def load_font_cfg(self):
Steven M. Gava429a86af2001-10-23 10:42:12 +00001006 ##base editor font selection list
Terry Jan Reedy4036d872014-08-03 23:02:58 -04001007 fonts = list(tkFont.families(self))
Steven M. Gavac11ccf32001-09-24 09:43:17 +00001008 fonts.sort()
1009 for font in fonts:
csabellabac7d332017-06-26 17:46:26 -04001010 self.list_fonts.insert(END, font)
1011 configured_font = idleConf.GetFont(self, 'main', 'EditorWindow')
1012 font_name = configured_font[0].lower()
1013 font_size = configured_font[1]
1014 font_bold = configured_font[2]=='bold'
1015 self.font_name.set(font_name)
Kurt B. Kaiser05391692003-05-26 20:35:53 +00001016 lc_fonts = [s.lower() for s in fonts]
Terry Jan Reedyd87d1682015-08-01 18:57:33 -04001017 try:
csabellabac7d332017-06-26 17:46:26 -04001018 current_font_index = lc_fonts.index(font_name)
1019 self.list_fonts.see(current_font_index)
1020 self.list_fonts.select_set(current_font_index)
1021 self.list_fonts.select_anchor(current_font_index)
Terry Jan Reedyd87d1682015-08-01 18:57:33 -04001022 except ValueError:
1023 pass
Steven M. Gava429a86af2001-10-23 10:42:12 +00001024 ##font size dropdown
csabellabac7d332017-06-26 17:46:26 -04001025 self.opt_menu_font_size.SetMenu(('7', '8', '9', '10', '11', '12', '13',
Terry Jan Reedyda028872016-08-30 20:19:13 -04001026 '14', '16', '18', '20', '22',
csabellabac7d332017-06-26 17:46:26 -04001027 '25', '29', '34', '40'), font_size )
1028 ##font_weight
1029 self.font_bold.set(font_bold)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001030 ##font sample
csabellabac7d332017-06-26 17:46:26 -04001031 self.set_font_sample()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001032
csabellabac7d332017-06-26 17:46:26 -04001033 def load_tab_cfg(self):
Steven M. Gava429a86af2001-10-23 10:42:12 +00001034 ##indent sizes
csabellabac7d332017-06-26 17:46:26 -04001035 space_num = idleConf.GetOption(
Terry Jan Reedy4036d872014-08-03 23:02:58 -04001036 'main', 'Indent', 'num-spaces', default=4, type='int')
csabellabac7d332017-06-26 17:46:26 -04001037 self.space_num.set(space_num)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001038
csabellabac7d332017-06-26 17:46:26 -04001039 def load_theme_cfg(self):
Steven M. Gava41a85322001-10-29 08:05:34 +00001040 ##current theme type radiobutton
csabellabac7d332017-06-26 17:46:26 -04001041 self.is_builtin_theme.set(idleConf.GetOption(
Terry Jan Reedy4036d872014-08-03 23:02:58 -04001042 'main', 'Theme', 'default', type='bool', default=1))
Steven M. Gava41a85322001-10-29 08:05:34 +00001043 ##currently set theme
csabellabac7d332017-06-26 17:46:26 -04001044 current_option = idleConf.CurrentTheme()
Steven M. Gava7c017862001-10-29 11:19:46 +00001045 ##load available theme option menus
csabellabac7d332017-06-26 17:46:26 -04001046 if self.is_builtin_theme.get(): #default theme selected
1047 item_list = idleConf.GetSectionList('default', 'highlight')
1048 item_list.sort()
1049 self.opt_menu_theme_builtin.SetMenu(item_list, current_option)
1050 item_list = idleConf.GetSectionList('user', 'highlight')
1051 item_list.sort()
1052 if not item_list:
1053 self.radio_theme_custom.config(state=DISABLED)
1054 self.custom_theme.set('- no custom themes -')
Steven M. Gava41a85322001-10-29 08:05:34 +00001055 else:
csabellabac7d332017-06-26 17:46:26 -04001056 self.opt_menu_theme_custom.SetMenu(item_list, item_list[0])
Steven M. Gava9dd16b32001-11-03 14:54:25 +00001057 else: #user theme selected
csabellabac7d332017-06-26 17:46:26 -04001058 item_list = idleConf.GetSectionList('user', 'highlight')
1059 item_list.sort()
1060 self.opt_menu_theme_custom.SetMenu(item_list, current_option)
1061 item_list = idleConf.GetSectionList('default', 'highlight')
1062 item_list.sort()
1063 self.opt_menu_theme_builtin.SetMenu(item_list, item_list[0])
1064 self.set_theme_type()
Steven M. Gava7c017862001-10-29 11:19:46 +00001065 ##load theme element option menu
csabellabac7d332017-06-26 17:46:26 -04001066 theme_names = list(self.theme_elements.keys())
1067 theme_names.sort(key=lambda x: self.theme_elements[x][1])
1068 self.opt_menu_highlight_target.SetMenu(theme_names, theme_names[0])
1069 self.paint_theme_sample()
1070 self.set_highlight_target()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001071
csabellabac7d332017-06-26 17:46:26 -04001072 def load_key_cfg(self):
Steven M. Gava41a85322001-10-29 08:05:34 +00001073 ##current keys type radiobutton
csabellabac7d332017-06-26 17:46:26 -04001074 self.are_keys_builtin.set(idleConf.GetOption(
Terry Jan Reedy4036d872014-08-03 23:02:58 -04001075 'main', 'Keys', 'default', type='bool', default=1))
Steven M. Gava41a85322001-10-29 08:05:34 +00001076 ##currently set keys
csabellabac7d332017-06-26 17:46:26 -04001077 current_option = idleConf.CurrentKeys()
Steven M. Gava7c017862001-10-29 11:19:46 +00001078 ##load available keyset option menus
csabellabac7d332017-06-26 17:46:26 -04001079 if self.are_keys_builtin.get(): #default theme selected
1080 item_list = idleConf.GetSectionList('default', 'keys')
1081 item_list.sort()
1082 self.opt_menu_keys_builtin.SetMenu(item_list, current_option)
1083 item_list = idleConf.GetSectionList('user', 'keys')
1084 item_list.sort()
1085 if not item_list:
1086 self.radio_keys_custom.config(state=DISABLED)
1087 self.custom_keys.set('- no custom keys -')
Steven M. Gava41a85322001-10-29 08:05:34 +00001088 else:
csabellabac7d332017-06-26 17:46:26 -04001089 self.opt_menu_keys_custom.SetMenu(item_list, item_list[0])
Steven M. Gavaa498af22002-02-01 01:33:36 +00001090 else: #user key set selected
csabellabac7d332017-06-26 17:46:26 -04001091 item_list = idleConf.GetSectionList('user', 'keys')
1092 item_list.sort()
1093 self.opt_menu_keys_custom.SetMenu(item_list, current_option)
1094 item_list = idleConf.GetSectionList('default', 'keys')
1095 item_list.sort()
1096 self.opt_menu_keys_builtin.SetMenu(item_list, idleConf.default_keys())
1097 self.set_keys_type()
Steven M. Gavafacfc092002-01-19 00:29:54 +00001098 ##load keyset element list
csabellabac7d332017-06-26 17:46:26 -04001099 keyset_name = idleConf.CurrentKeys()
1100 self.load_keys_list(keyset_name)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001101
csabellabac7d332017-06-26 17:46:26 -04001102 def load_general_cfg(self):
Steven M. Gava5f28e8f2002-01-21 06:38:21 +00001103 #startup state
csabellabac7d332017-06-26 17:46:26 -04001104 self.startup_edit.set(idleConf.GetOption(
Terry Jan Reedy4036d872014-08-03 23:02:58 -04001105 'main', 'General', 'editor-on-startup', default=1, type='bool'))
Kurt B. Kaiser6c638b62003-05-26 06:23:10 +00001106 #autosave state
csabellabac7d332017-06-26 17:46:26 -04001107 self.autosave.set(idleConf.GetOption(
Terry Jan Reedy4036d872014-08-03 23:02:58 -04001108 'main', 'General', 'autosave', default=0, type='bool'))
Steven M. Gavafacfc092002-01-19 00:29:54 +00001109 #initial window size
csabellabac7d332017-06-26 17:46:26 -04001110 self.win_width.set(idleConf.GetOption(
Terry Jan Reedy4036d872014-08-03 23:02:58 -04001111 'main', 'EditorWindow', 'width', type='int'))
csabellabac7d332017-06-26 17:46:26 -04001112 self.win_height.set(idleConf.GetOption(
Terry Jan Reedy4036d872014-08-03 23:02:58 -04001113 'main', 'EditorWindow', 'height', type='int'))
Kurt B. Kaisera053f332003-05-10 00:49:56 +00001114 # default source encoding
Terry Jan Reedy4036d872014-08-03 23:02:58 -04001115 self.encoding.set(idleConf.GetOption(
1116 'main', 'EditorWindow', 'encoding', default='none'))
Kurt B. Kaiser8e92bf72003-01-14 22:03:31 +00001117 # additional help sources
csabellabac7d332017-06-26 17:46:26 -04001118 self.user_helplist = idleConf.GetAllExtraHelpSourcesList()
1119 for help_item in self.user_helplist:
1120 self.list_help.insert(END, help_item[0])
1121 self.set_helplist_button_states()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001122
csabellabac7d332017-06-26 17:46:26 -04001123 def load_configs(self):
Steven M. Gava429a86af2001-10-23 10:42:12 +00001124 """
1125 load configuration from default and user config files and populate
1126 the widgets on the config dialog pages.
1127 """
1128 ### fonts / tabs page
csabellabac7d332017-06-26 17:46:26 -04001129 self.load_font_cfg()
1130 self.load_tab_cfg()
Steven M. Gava429a86af2001-10-23 10:42:12 +00001131 ### highlighting page
csabellabac7d332017-06-26 17:46:26 -04001132 self.load_theme_cfg()
Steven M. Gava429a86af2001-10-23 10:42:12 +00001133 ### keys page
csabellabac7d332017-06-26 17:46:26 -04001134 self.load_key_cfg()
Steven M. Gava429a86af2001-10-23 10:42:12 +00001135 ### general page
csabellabac7d332017-06-26 17:46:26 -04001136 self.load_general_cfg()
Terry Jan Reedy93f35422015-10-13 22:03:51 -04001137 # note: extension page handled separately
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001138
csabellabac7d332017-06-26 17:46:26 -04001139 def save_new_key_set(self, keyset_name, keyset):
Steven M. Gava052937f2002-02-11 02:20:53 +00001140 """
1141 save a newly created core key set.
csabellabac7d332017-06-26 17:46:26 -04001142 keyset_name - string, the name of the new key set
1143 keyset - dictionary containing the new key set
Steven M. Gava052937f2002-02-11 02:20:53 +00001144 """
csabellabac7d332017-06-26 17:46:26 -04001145 if not idleConf.userCfg['keys'].has_section(keyset_name):
1146 idleConf.userCfg['keys'].add_section(keyset_name)
1147 for event in keyset:
1148 value = keyset[event]
1149 idleConf.userCfg['keys'].SetOption(keyset_name, event, value)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001150
csabellabac7d332017-06-26 17:46:26 -04001151 def save_new_theme(self, theme_name, theme):
Steven M. Gava052937f2002-02-11 02:20:53 +00001152 """
1153 save a newly created theme.
csabellabac7d332017-06-26 17:46:26 -04001154 theme_name - string, the name of the new theme
Steven M. Gava052937f2002-02-11 02:20:53 +00001155 theme - dictionary containing the new theme
1156 """
csabellabac7d332017-06-26 17:46:26 -04001157 if not idleConf.userCfg['highlight'].has_section(theme_name):
1158 idleConf.userCfg['highlight'].add_section(theme_name)
Kurt B. Kaisere0712772007-08-23 05:25:55 +00001159 for element in theme:
Terry Jan Reedy4036d872014-08-03 23:02:58 -04001160 value = theme[element]
csabellabac7d332017-06-26 17:46:26 -04001161 idleConf.userCfg['highlight'].SetOption(theme_name, element, value)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001162
csabellabac7d332017-06-26 17:46:26 -04001163 def set_user_value(self, config_type, section, item, value):
1164 if idleConf.defaultCfg[config_type].has_option(section, item):
1165 if idleConf.defaultCfg[config_type].Get(section, item) == value:
Steven M. Gava2d7bb3f2002-01-29 08:35:29 +00001166 #the setting equals a default setting, remove it from user cfg
csabellabac7d332017-06-26 17:46:26 -04001167 return idleConf.userCfg[config_type].RemoveOption(section, item)
Steven M. Gava2d7bb3f2002-01-29 08:35:29 +00001168 #if we got here set the option
csabellabac7d332017-06-26 17:46:26 -04001169 return idleConf.userCfg[config_type].SetOption(section, item, value)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001170
csabellabac7d332017-06-26 17:46:26 -04001171 def save_all_changed_configs(self):
Kurt B. Kaisere7a161e2003-01-10 20:13:57 +00001172 "Save configuration changes to the user config file."
Steven M. Gava0c5bc8c2002-03-27 02:25:44 +00001173 idleConf.userCfg['main'].Save()
csabellabac7d332017-06-26 17:46:26 -04001174 for config_type in self.changed_items:
1175 cfg_type_changed = False
1176 for section in self.changed_items[config_type]:
Kurt B. Kaisere7a161e2003-01-10 20:13:57 +00001177 if section == 'HelpFiles':
1178 #this section gets completely replaced
1179 idleConf.userCfg['main'].remove_section('HelpFiles')
csabellabac7d332017-06-26 17:46:26 -04001180 cfg_type_changed = True
1181 for item in self.changed_items[config_type][section]:
1182 value = self.changed_items[config_type][section][item]
1183 if self.set_user_value(config_type, section, item, value):
1184 cfg_type_changed = True
1185 if cfg_type_changed:
1186 idleConf.userCfg[config_type].Save()
1187 for config_type in ['keys', 'highlight']:
Kurt B. Kaiser5acdf932004-11-16 21:28:36 +00001188 # save these even if unchanged!
csabellabac7d332017-06-26 17:46:26 -04001189 idleConf.userCfg[config_type].Save()
1190 self.reset_changed_items() #clear the changed items dict
Terry Jan Reedy93f35422015-10-13 22:03:51 -04001191 self.save_all_changed_extensions() # uses a different mechanism
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001192
csabellabac7d332017-06-26 17:46:26 -04001193 def deactivate_current_config(self):
Kurt B. Kaiserb1754452005-11-18 22:05:48 +00001194 #Before a config is saved, some cleanup of current
1195 #config must be done - remove the previous keybindings
csabellabac7d332017-06-26 17:46:26 -04001196 win_instances = self.parent.instance_dict.keys()
1197 for instance in win_instances:
Kurt B. Kaiserb1754452005-11-18 22:05:48 +00001198 instance.RemoveKeybindings()
1199
csabellabac7d332017-06-26 17:46:26 -04001200 def activate_config_changes(self):
Kurt B. Kaiseracdef852005-01-31 03:34:26 +00001201 "Dynamically apply configuration changes"
csabellabac7d332017-06-26 17:46:26 -04001202 win_instances = self.parent.instance_dict.keys()
1203 for instance in win_instances:
Steven M. Gavab77d3432002-03-02 07:16:21 +00001204 instance.ResetColorizer()
Steven M. Gavab1585412002-03-12 00:21:56 +00001205 instance.ResetFont()
Kurt B. Kaiseracdef852005-01-31 03:34:26 +00001206 instance.set_notabs_indentwidth()
Kurt B. Kaiserb1754452005-11-18 22:05:48 +00001207 instance.ApplyKeybindings()
Kurt B. Kaiser8e92bf72003-01-14 22:03:31 +00001208 instance.reset_help_menu_entries()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001209
csabellabac7d332017-06-26 17:46:26 -04001210 def cancel(self):
Steven M. Gava5f28e8f2002-01-21 06:38:21 +00001211 self.destroy()
1212
csabellabac7d332017-06-26 17:46:26 -04001213 def ok(self):
1214 self.apply()
Steven M. Gava5f28e8f2002-01-21 06:38:21 +00001215 self.destroy()
1216
csabellabac7d332017-06-26 17:46:26 -04001217 def apply(self):
1218 self.deactivate_current_config()
1219 self.save_all_changed_configs()
1220 self.activate_config_changes()
Steven M. Gava5f28e8f2002-01-21 06:38:21 +00001221
csabellabac7d332017-06-26 17:46:26 -04001222 def help(self):
1223 page = self.tab_pages._current_page
Terry Jan Reedyd0cadba2015-10-11 22:07:31 -04001224 view_text(self, title='Help for IDLE preferences',
1225 text=help_common+help_pages.get(page, ''))
1226
csabellabac7d332017-06-26 17:46:26 -04001227 def create_page_extensions(self):
Terry Jan Reedy93f35422015-10-13 22:03:51 -04001228 """Part of the config dialog used for configuring IDLE extensions.
1229
1230 This code is generic - it works for any and all IDLE extensions.
1231
1232 IDLE extensions save their configuration options using idleConf.
Terry Jan Reedyb2f87602015-10-13 22:09:06 -04001233 This code reads the current configuration using idleConf, supplies a
Terry Jan Reedy93f35422015-10-13 22:03:51 -04001234 GUI interface to change the configuration values, and saves the
1235 changes using idleConf.
1236
1237 Not all changes take effect immediately - some may require restarting IDLE.
1238 This depends on each extension's implementation.
1239
1240 All values are treated as text, and it is up to the user to supply
1241 reasonable values. The only exception to this are the 'enable*' options,
Serhiy Storchaka6a7b3a72016-04-17 08:32:47 +03001242 which are boolean, and can be toggled with a True/False button.
Terry Jan Reedy93f35422015-10-13 22:03:51 -04001243 """
1244 parent = self.parent
csabellabac7d332017-06-26 17:46:26 -04001245 frame = self.tab_pages.pages['Extensions'].frame
Terry Jan Reedy93f35422015-10-13 22:03:51 -04001246 self.ext_defaultCfg = idleConf.defaultCfg['extensions']
1247 self.ext_userCfg = idleConf.userCfg['extensions']
1248 self.is_int = self.register(is_int)
1249 self.load_extensions()
1250 # create widgets - a listbox shows all available extensions, with the
1251 # controls for the extension selected in the listbox to the right
1252 self.extension_names = StringVar(self)
1253 frame.rowconfigure(0, weight=1)
1254 frame.columnconfigure(2, weight=1)
1255 self.extension_list = Listbox(frame, listvariable=self.extension_names,
1256 selectmode='browse')
1257 self.extension_list.bind('<<ListboxSelect>>', self.extension_selected)
1258 scroll = Scrollbar(frame, command=self.extension_list.yview)
1259 self.extension_list.yscrollcommand=scroll.set
1260 self.details_frame = LabelFrame(frame, width=250, height=250)
1261 self.extension_list.grid(column=0, row=0, sticky='nws')
1262 scroll.grid(column=1, row=0, sticky='ns')
1263 self.details_frame.grid(column=2, row=0, sticky='nsew', padx=[10, 0])
1264 frame.configure(padx=10, pady=10)
1265 self.config_frame = {}
1266 self.current_extension = None
1267
1268 self.outerframe = self # TEMPORARY
1269 self.tabbed_page_set = self.extension_list # TEMPORARY
1270
1271 # create the frame holding controls for each extension
1272 ext_names = ''
1273 for ext_name in sorted(self.extensions):
1274 self.create_extension_frame(ext_name)
1275 ext_names = ext_names + '{' + ext_name + '} '
1276 self.extension_names.set(ext_names)
1277 self.extension_list.selection_set(0)
1278 self.extension_selected(None)
1279
1280 def load_extensions(self):
1281 "Fill self.extensions with data from the default and user configs."
1282 self.extensions = {}
1283 for ext_name in idleConf.GetExtensions(active_only=False):
1284 self.extensions[ext_name] = []
1285
1286 for ext_name in self.extensions:
1287 opt_list = sorted(self.ext_defaultCfg.GetOptionList(ext_name))
1288
1289 # bring 'enable' options to the beginning of the list
1290 enables = [opt_name for opt_name in opt_list
1291 if opt_name.startswith('enable')]
1292 for opt_name in enables:
1293 opt_list.remove(opt_name)
1294 opt_list = enables + opt_list
1295
1296 for opt_name in opt_list:
1297 def_str = self.ext_defaultCfg.Get(
1298 ext_name, opt_name, raw=True)
1299 try:
1300 def_obj = {'True':True, 'False':False}[def_str]
1301 opt_type = 'bool'
1302 except KeyError:
1303 try:
1304 def_obj = int(def_str)
1305 opt_type = 'int'
1306 except ValueError:
1307 def_obj = def_str
1308 opt_type = None
1309 try:
1310 value = self.ext_userCfg.Get(
1311 ext_name, opt_name, type=opt_type, raw=True,
1312 default=def_obj)
1313 except ValueError: # Need this until .Get fixed
1314 value = def_obj # bad values overwritten by entry
1315 var = StringVar(self)
1316 var.set(str(value))
1317
1318 self.extensions[ext_name].append({'name': opt_name,
1319 'type': opt_type,
1320 'default': def_str,
1321 'value': value,
1322 'var': var,
1323 })
1324
1325 def extension_selected(self, event):
1326 newsel = self.extension_list.curselection()
1327 if newsel:
1328 newsel = self.extension_list.get(newsel)
1329 if newsel is None or newsel != self.current_extension:
1330 if self.current_extension:
1331 self.details_frame.config(text='')
1332 self.config_frame[self.current_extension].grid_forget()
1333 self.current_extension = None
1334 if newsel:
1335 self.details_frame.config(text=newsel)
1336 self.config_frame[newsel].grid(column=0, row=0, sticky='nsew')
1337 self.current_extension = newsel
1338
1339 def create_extension_frame(self, ext_name):
1340 """Create a frame holding the widgets to configure one extension"""
1341 f = VerticalScrolledFrame(self.details_frame, height=250, width=250)
1342 self.config_frame[ext_name] = f
1343 entry_area = f.interior
1344 # create an entry for each configuration option
1345 for row, opt in enumerate(self.extensions[ext_name]):
1346 # create a row with a label and entry/checkbutton
1347 label = Label(entry_area, text=opt['name'])
1348 label.grid(row=row, column=0, sticky=NW)
1349 var = opt['var']
1350 if opt['type'] == 'bool':
1351 Checkbutton(entry_area, textvariable=var, variable=var,
1352 onvalue='True', offvalue='False',
1353 indicatoron=FALSE, selectcolor='', width=8
1354 ).grid(row=row, column=1, sticky=W, padx=7)
1355 elif opt['type'] == 'int':
1356 Entry(entry_area, textvariable=var, validate='key',
1357 validatecommand=(self.is_int, '%P')
1358 ).grid(row=row, column=1, sticky=NSEW, padx=7)
1359
1360 else:
1361 Entry(entry_area, textvariable=var
1362 ).grid(row=row, column=1, sticky=NSEW, padx=7)
1363 return
1364
1365 def set_extension_value(self, section, opt):
1366 name = opt['name']
1367 default = opt['default']
1368 value = opt['var'].get().strip() or default
1369 opt['var'].set(value)
1370 # if self.defaultCfg.has_section(section):
1371 # Currently, always true; if not, indent to return
1372 if (value == default):
1373 return self.ext_userCfg.RemoveOption(section, name)
1374 # set the option
1375 return self.ext_userCfg.SetOption(section, name, value)
1376
1377 def save_all_changed_extensions(self):
1378 """Save configuration changes to the user config file."""
1379 has_changes = False
1380 for ext_name in self.extensions:
1381 options = self.extensions[ext_name]
1382 for opt in options:
1383 if self.set_extension_value(ext_name, opt):
1384 has_changes = True
1385 if has_changes:
1386 self.ext_userCfg.Save()
1387
1388
Terry Jan Reedyd0cadba2015-10-11 22:07:31 -04001389help_common = '''\
1390When you click either the Apply or Ok buttons, settings in this
1391dialog that are different from IDLE's default are saved in
1392a .idlerc directory in your home directory. Except as noted,
Terry Jan Reedyd0c0f002015-11-12 15:02:57 -05001393these changes apply to all versions of IDLE installed on this
Terry Jan Reedyd0cadba2015-10-11 22:07:31 -04001394machine. Some do not take affect until IDLE is restarted.
1395[Cancel] only cancels changes made since the last save.
1396'''
1397help_pages = {
Terry Jan Reedy9bdb1ed2016-07-10 13:46:34 -04001398 'Highlighting': '''
Terry Jan Reedyd0cadba2015-10-11 22:07:31 -04001399Highlighting:
Terry Jan Reedyd0c0f002015-11-12 15:02:57 -05001400The IDLE Dark color theme is new in October 2015. It can only
Terry Jan Reedyd0cadba2015-10-11 22:07:31 -04001401be used with older IDLE releases if it is saved as a custom
1402theme, with a different name.
Terry Jan Reedy9bdb1ed2016-07-10 13:46:34 -04001403''',
1404 'Keys': '''
1405Keys:
1406The IDLE Modern Unix key set is new in June 2016. It can only
1407be used with older IDLE releases if it is saved as a custom
1408key set, with a different name.
1409''',
wohlgangerfae2c352017-06-27 21:36:23 -05001410 'Extensions': '''
1411Extensions:
1412
1413Autocomplete: Popupwait is milleseconds to wait after key char, without
1414cursor movement, before popping up completion box. Key char is '.' after
1415identifier or a '/' (or '\\' on Windows) within a string.
1416
1417FormatParagraph: Max-width is max chars in lines after re-formatting.
1418Use with paragraphs in both strings and comment blocks.
1419
1420ParenMatch: Style indicates what is highlighted when closer is entered:
1421'opener' - opener '({[' corresponding to closer; 'parens' - both chars;
1422'expression' (default) - also everything in between. Flash-delay is how
1423long to highlight if cursor is not moved (0 means forever).
1424'''
Terry Jan Reedyd0cadba2015-10-11 22:07:31 -04001425}
1426
Steven M. Gavac11ccf32001-09-24 09:43:17 +00001427
Terry Jan Reedy93f35422015-10-13 22:03:51 -04001428def is_int(s):
1429 "Return 's is blank or represents an int'"
1430 if not s:
1431 return True
1432 try:
1433 int(s)
1434 return True
1435 except ValueError:
1436 return False
1437
1438
Terry Jan Reedya9421fb2014-10-22 20:15:18 -04001439class VerticalScrolledFrame(Frame):
1440 """A pure Tkinter vertically scrollable frame.
1441
1442 * Use the 'interior' attribute to place widgets inside the scrollable frame
1443 * Construct and pack/place/grid normally
1444 * This frame only allows vertical scrolling
1445 """
1446 def __init__(self, parent, *args, **kw):
1447 Frame.__init__(self, parent, *args, **kw)
1448
1449 # create a canvas object and a vertical scrollbar for scrolling it
1450 vscrollbar = Scrollbar(self, orient=VERTICAL)
1451 vscrollbar.pack(fill=Y, side=RIGHT, expand=FALSE)
1452 canvas = Canvas(self, bd=0, highlightthickness=0,
Terry Jan Reedyd0812292015-10-22 03:27:31 -04001453 yscrollcommand=vscrollbar.set, width=240)
Terry Jan Reedya9421fb2014-10-22 20:15:18 -04001454 canvas.pack(side=LEFT, fill=BOTH, expand=TRUE)
1455 vscrollbar.config(command=canvas.yview)
1456
1457 # reset the view
1458 canvas.xview_moveto(0)
1459 canvas.yview_moveto(0)
1460
1461 # create a frame inside the canvas which will be scrolled with it
1462 self.interior = interior = Frame(canvas)
1463 interior_id = canvas.create_window(0, 0, window=interior, anchor=NW)
1464
1465 # track changes to the canvas and frame width and sync them,
1466 # also updating the scrollbar
1467 def _configure_interior(event):
1468 # update the scrollbars to match the size of the inner frame
1469 size = (interior.winfo_reqwidth(), interior.winfo_reqheight())
1470 canvas.config(scrollregion="0 0 %s %s" % size)
Terry Jan Reedya9421fb2014-10-22 20:15:18 -04001471 interior.bind('<Configure>', _configure_interior)
1472
1473 def _configure_canvas(event):
1474 if interior.winfo_reqwidth() != canvas.winfo_width():
1475 # update the inner frame's width to fill the canvas
1476 canvas.itemconfigure(interior_id, width=canvas.winfo_width())
1477 canvas.bind('<Configure>', _configure_canvas)
1478
1479 return
1480
Terry Jan Reedya9421fb2014-10-22 20:15:18 -04001481
Steven M. Gava44d3d1a2001-07-31 06:59:02 +00001482if __name__ == '__main__':
Terry Jan Reedycfa89502014-07-14 23:07:32 -04001483 import unittest
1484 unittest.main('idlelib.idle_test.test_configdialog',
1485 verbosity=2, exit=False)
Terry Jan Reedy2e8234a2014-05-29 01:46:26 -04001486 from idlelib.idle_test.htest import run
Terry Jan Reedy47304c02015-10-20 02:15:28 -04001487 run(ConfigDialog)