From 44401cde8a45c59d4a90d2d45ee665791c168a87 Mon Sep 17 00:00:00 2001 From: Cheryl Sabella Date: Tue, 20 Jun 2017 18:48:23 -0400 Subject: [PATCH 1/5] bpo-27388: IDLE: Refactor configdialog to PEP8 names and add docstrings --- Lib/idlelib/configdialog.py | 2140 +++++++++++++++++++---------------- 1 file changed, 1160 insertions(+), 980 deletions(-) diff --git a/Lib/idlelib/configdialog.py b/Lib/idlelib/configdialog.py index 8184582a3e2ff3..2128b3b47241b3 100644 --- a/Lib/idlelib/configdialog.py +++ b/Lib/idlelib/configdialog.py @@ -9,7 +9,12 @@ Refer to comments in EditorWindow autoindent code for details. """ -from tkinter import * +from tkinter import Toplevel, Frame, LabelFrame, Listbox, Label, Button, Entry +from tkinter import Text, Scale, Radiobutton, Checkbutton, Canvas +from tkinter import StringVar, BooleanVar, IntVar +from tkinter import TOP, BOTTOM, RIGHT, LEFT, SOLID, GROOVE, NORMAL, DISABLED +from tkinter import NONE, BOTH, X, Y, W, E, EW, NS, NSEW, NW +from tkinter import HORIZONTAL, VERTICAL, ANCHOR, END from tkinter.ttk import Scrollbar import tkinter.colorchooser as tkColorChooser import tkinter.font as tkFont @@ -23,10 +28,16 @@ from idlelib.tabbedpages import TabbedPageSet from idlelib.textview import view_text + class ConfigDialog(Toplevel): + """Config dialog for IDLE. + """ def __init__(self, parent, title='', _htest=False, _utest=False): - """ + """Show the tabbed dialog for user configuration. + + parent - parent of this dialog + title - string which is the title of this popup dialog _htest - bool, change box location when running htest _utest - bool, don't wait_window when running unittest """ @@ -34,17 +45,17 @@ def __init__(self, parent, title='', _htest=False, _utest=False): self.parent = parent if _htest: parent.instance_dict = {} - self.wm_withdraw() + self.withdraw() self.configure(borderwidth=5) self.title(title or 'IDLE Preferences') - self.geometry( - "+%d+%d" % (parent.winfo_rootx() + 20, - parent.winfo_rooty() + (30 if not _htest else 150))) - #Theme Elements. Each theme element key is its display name. - #The first value of the tuple is the sample area tag name. - #The second value is the display name list sort index. - self.themeElements={ + x = parent.winfo_rootx() + 20 + y = parent.winfo_rooty() + (30 if not _htest else 150) + self.geometry(f'+{x}+{y}') + # theme_elements. Each theme element key is its display name. + # The first value of the tuple is the sample area tag name. + # The second value is the display name list sort index. + self.theme_elements = { 'Normal Text': ('normal', '00'), 'Python Keywords': ('keyword', '01'), 'Python Definitions': ('definition', '02'), @@ -60,154 +71,185 @@ def __init__(self, parent, title='', _htest=False, _utest=False): 'Shell Stdout Text': ('stdout', '12'), 'Shell Stderr Text': ('stderr', '13'), } - self.ResetChangedItems() #load initial values in changed items dict - self.CreateWidgets() - self.resizable(height=FALSE, width=FALSE) + self.reset_changed_items() # load initial values in changed items dict + self.create_widgets() + self.resizable(height=False, width=False) self.transient(parent) self.grab_set() - self.protocol("WM_DELETE_WINDOW", self.Cancel) - self.tabPages.focus_set() - #key bindings for this dialog - #self.bind('', self.Cancel) #dismiss dialog, no save - #self.bind('', self.Apply) #apply changes, save - #self.bind('', self.Help) #context help - self.LoadConfigs() - self.AttachVarCallbacks() #avoid callbacks during LoadConfigs + self.protocol("WM_DELETE_WINDOW", self.cancel) + self.tab_pages.focus_set() + # key bindings for this dialog + # self.bind('', self.Cancel) #dismiss dialog, no save + # self.bind('', self.Apply) #apply changes, save + # self.bind('', self.Help) #context help + self.load_configs() + self.attach_var_callbacks() # avoid callbacks during load_configs if not _utest: self.wm_deiconify() self.wait_window() - def CreateWidgets(self): - self.tabPages = TabbedPageSet(self, - page_names=['Fonts/Tabs', 'Highlighting', 'Keys', 'General', - 'Extensions']) - self.tabPages.pack(side=TOP, expand=TRUE, fill=BOTH) - self.CreatePageFontTab() - self.CreatePageHighlight() - self.CreatePageKeys() - self.CreatePageGeneral() - self.CreatePageExtensions() + def create_widgets(self): + "Create and place widgets for tabbed dialog." + self.tab_pages = TabbedPageSet( + self, page_names=['Fonts/Tabs', 'Highlighting', 'Keys', + 'General', 'Extensions']) + self.tab_pages.pack(side=TOP, expand=True, fill=BOTH) + self.create_page_font_tab() + self.create_page_highlight() + self.create_page_keys() + self.create_page_general() + self.create_page_extensions() self.create_action_buttons().pack(side=BOTTOM) def create_action_buttons(self): + "Return frame of action buttons for dialog." if macosx.isAquaTk(): # Changing the default padding on OSX results in unreadable # text in the buttons - paddingArgs = {} + padding_args = {} else: - paddingArgs = {'padx':6, 'pady':3} + padding_args = {'padx': 6, 'pady': 3} outer = Frame(self, pady=2) buttons = Frame(outer, pady=2) - for txt, cmd in ( - ('Ok', self.Ok), - ('Apply', self.Apply), - ('Cancel', self.Cancel), - ('Help', self.Help)): - Button(buttons, text=txt, command=cmd, takefocus=FALSE, - **paddingArgs).pack(side=LEFT, padx=5) + for txt, cmd in (('Ok', self.ok), + ('Apply', self.apply), + ('Cancel', self.cancel), + ('Help', self.help)): + Button(buttons, text=txt, command=cmd, takefocus=False, + **padding_args).pack(side=LEFT, padx=5) # add space above buttons Frame(outer, height=2, borderwidth=0).pack(side=TOP) buttons.pack(side=BOTTOM) return outer - def CreatePageFontTab(self): + def create_page_font_tab(self): + """Return frame of widgets for Font/Tabs tab. + + Configuration attributes: + font_size: Font size. + font_bold: Select font bold or not. + font_name: Font face. + space_num: Indentation width. + edit_font: Font widget with default font. + """ parent = self.parent - self.fontSize = StringVar(parent) - self.fontBold = BooleanVar(parent) - self.fontName = StringVar(parent) - self.spaceNum = IntVar(parent) - self.editFont = tkFont.Font(parent, ('courier', 10, 'normal')) - - ##widget creation - #body frame - frame = self.tabPages.pages['Fonts/Tabs'].frame - #body section frames - frameFont = LabelFrame( - frame, borderwidth=2, relief=GROOVE, text=' Base Editor Font ') - frameIndent = LabelFrame( - frame, borderwidth=2, relief=GROOVE, text=' Indentation Width ') - #frameFont - frameFontName = Frame(frameFont) - frameFontParam = Frame(frameFont) - labelFontNameTitle = Label( - frameFontName, justify=LEFT, text='Font Face :') - self.listFontName = Listbox( - frameFontName, height=5, takefocus=FALSE, exportselection=FALSE) - self.listFontName.bind( - '', self.OnListFontButtonRelease) - scrollFont = Scrollbar(frameFontName) - scrollFont.config(command=self.listFontName.yview) - self.listFontName.config(yscrollcommand=scrollFont.set) - labelFontSizeTitle = Label(frameFontParam, text='Size :') - self.optMenuFontSize = DynOptionMenu( - frameFontParam, self.fontSize, None, command=self.SetFontSample) - checkFontBold = Checkbutton( - frameFontParam, variable=self.fontBold, onvalue=1, - offvalue=0, text='Bold', command=self.SetFontSample) - frameFontSample = Frame(frameFont, relief=SOLID, borderwidth=1) - self.labelFontSample = Label( - frameFontSample, justify=LEFT, font=self.editFont, + self.font_size = StringVar(parent) + self.font_bold = BooleanVar(parent) + self.font_name = StringVar(parent) + self.space_num = IntVar(parent) + self.edit_font = tkFont.Font(parent, ('courier', 10, 'normal')) + + # widget creation + # body frame + frame = self.tab_pages.pages['Fonts/Tabs'].frame + + # body section frames + frame_font = LabelFrame(frame, borderwidth=2, relief=GROOVE, + text=' Base Editor Font ') + frame_indent = LabelFrame(frame, borderwidth=2, relief=GROOVE, + text=' Indentation Width ') + + # frame_font + frame_font_name = Frame(frame_font) + frame_font_param = Frame(frame_font) + # frame_font_name + font_name_title = Label( + frame_font_name, justify=LEFT, text='Font Face :') + self.list_fonts = Listbox(frame_font_name, height=5, takefocus=False, + exportselection=False) + self.list_fonts.bind('', + self.on_list_fonts_button_release) + scroll_font = Scrollbar(frame_font_name) + scroll_font.config(command=self.list_fonts.yview) + self.list_fonts.config(yscrollcommand=scroll_font.set) + # frame_font_param + font_size_title = Label(frame_font_param, text='Size :') + self.opt_menu_font_size = DynOptionMenu( + frame_font_param, self.font_size, None, + command=self.set_font_sample) + check_font_bold = Checkbutton( + frame_font_param, variable=self.font_bold, onvalue=1, + offvalue=0, text='Bold', command=self.set_font_sample) + frame_font_sample = Frame(frame_font, relief=SOLID, borderwidth=1) + self.font_sample = Label( + frame_font_sample, justify=LEFT, font=self.edit_font, text='AaBbCcDdEe\nFfGgHhIiJjK\n1234567890\n#:+=(){}[]') - #frameIndent - frameIndentSize = Frame(frameIndent) - labelSpaceNumTitle = Label( - frameIndentSize, justify=LEFT, + + # frame_indent + frame_indent_size = Frame(frame_indent) + indent_size_title = Label( + frame_indent_size, justify=LEFT, text='Python Standard: 4 Spaces!') - self.scaleSpaceNum = Scale( - frameIndentSize, variable=self.spaceNum, + self.scale_indent_size = Scale( + frame_indent_size, variable=self.space_num, orient='horizontal', tickinterval=2, from_=2, to=16) - #widget packing - #body - frameFont.pack(side=LEFT, padx=5, pady=5, expand=TRUE, fill=BOTH) - frameIndent.pack(side=LEFT, padx=5, pady=5, fill=Y) - #frameFont - frameFontName.pack(side=TOP, padx=5, pady=5, fill=X) - frameFontParam.pack(side=TOP, padx=5, pady=5, fill=X) - labelFontNameTitle.pack(side=TOP, anchor=W) - self.listFontName.pack(side=LEFT, expand=TRUE, fill=X) - scrollFont.pack(side=LEFT, fill=Y) - labelFontSizeTitle.pack(side=LEFT, anchor=W) - self.optMenuFontSize.pack(side=LEFT, anchor=W) - checkFontBold.pack(side=LEFT, anchor=W, padx=20) - frameFontSample.pack(side=TOP, padx=5, pady=5, expand=TRUE, fill=BOTH) - self.labelFontSample.pack(expand=TRUE, fill=BOTH) - #frameIndent - frameIndentSize.pack(side=TOP, fill=X) - labelSpaceNumTitle.pack(side=TOP, anchor=W, padx=5) - self.scaleSpaceNum.pack(side=TOP, padx=5, fill=X) + # widget packing + # body + frame_font.pack(side=LEFT, padx=5, pady=5, expand=True, fill=BOTH) + frame_indent.pack(side=LEFT, padx=5, pady=5, fill=Y) + + # frame_font + frame_font_name.pack(side=TOP, padx=5, pady=5, fill=X) + frame_font_param.pack(side=TOP, padx=5, pady=5, fill=X) + font_name_title.pack(side=TOP, anchor=W) + self.list_fonts.pack(side=LEFT, expand=True, fill=X) + scroll_font.pack(side=LEFT, fill=Y) + font_size_title.pack(side=LEFT, anchor=W) + self.opt_menu_font_size.pack(side=LEFT, anchor=W) + check_font_bold.pack(side=LEFT, anchor=W, padx=20) + frame_font_sample.pack(side=TOP, padx=5, pady=5, + expand=True, fill=BOTH) + self.font_sample.pack(expand=True, fill=BOTH) + + # frame_indent + frame_indent_size.pack(side=TOP, fill=X) + indent_size_title.pack(side=TOP, anchor=W, padx=5) + self.scale_indent_size.pack(side=TOP, padx=5, fill=X) return frame - def CreatePageHighlight(self): + def create_page_highlight(self): + """Return frame of widgets for Highlighting tab. + + Configuration attributes: + builtin_theme: Menu variable for built-in theme. + custom_theme: Menu variable for custom theme. + fg_bg_toggle: Toggle for foreground/background color. + color: Color of selected target. + is_builtin_theme: Selector for built-in or custom theme. + highlight_target: Menu variable for the highlight target. + """ parent = self.parent - self.builtinTheme = StringVar(parent) - self.customTheme = StringVar(parent) - self.fgHilite = BooleanVar(parent) - self.colour = StringVar(parent) - self.fontName = StringVar(parent) - self.themeIsBuiltin = BooleanVar(parent) - self.highlightTarget = StringVar(parent) - - ##widget creation - #body frame - frame = self.tabPages.pages['Highlighting'].frame - #body section frames - frameCustom = LabelFrame(frame, borderwidth=2, relief=GROOVE, - text=' Custom Highlighting ') - frameTheme = LabelFrame(frame, borderwidth=2, relief=GROOVE, - text=' Highlighting Theme ') - #frameCustom - self.textHighlightSample=Text( - frameCustom, relief=SOLID, borderwidth=1, + self.builtin_theme = StringVar(parent) + self.custom_theme = StringVar(parent) + self.fg_bg_toggle = BooleanVar(parent) + self.color = StringVar(parent) + # self.font_name = StringVar(parent) + self.is_builtin_theme = BooleanVar(parent) + self.highlight_target = StringVar(parent) + + # widget creation + # body frame + frame = self.tab_pages.pages['Highlighting'].frame + + # body section frames + frame_custom = LabelFrame(frame, borderwidth=2, relief=GROOVE, + text=' Custom Highlighting ') + frame_theme = LabelFrame(frame, borderwidth=2, relief=GROOVE, + text=' Highlighting Theme ') + + # frame_custom + self.text_highlight_sample = Text( + frame_custom, relief=SOLID, borderwidth=1, font=('courier', 12, ''), cursor='hand2', width=21, height=11, - takefocus=FALSE, highlightthickness=0, wrap=NONE) - text=self.textHighlightSample + takefocus=False, highlightthickness=0, wrap=NONE) + text = self.text_highlight_sample text.bind('', lambda e: 'break') text.bind('', lambda e: 'break') - textAndTags=( - ('#you can click here', 'comment'), ('\n', 'normal'), - ('#to choose items', 'comment'), ('\n', 'normal'), + txt_and_tags = ( + ('# you can click here', 'comment'), ('\n', 'normal'), + ('# to choose items', 'comment'), ('\n', 'normal'), ('def', 'keyword'), (' ', 'normal'), ('func', 'definition'), ('(param):\n ', 'normal'), ('"""string"""', 'string'), ('\n var0 = ', 'normal'), @@ -222,1004 +264,1136 @@ def CreatePageHighlight(self): ('shell', 'console'), (' ', 'normal'), ('stdout', 'stdout'), (' ', 'normal'), ('stderr', 'stderr'), ('\n', 'normal')) - for txTa in textAndTags: - text.insert(END, txTa[0], txTa[1]) - for element in self.themeElements: + for txt, tag in txt_and_tags: + text.insert(END, txt, tag) + for element in self.theme_elements: def tem(event, elem=element): - event.widget.winfo_toplevel().highlightTarget.set(elem) + event.widget.winfo_toplevel().highlight_target.set(elem) text.tag_bind( - self.themeElements[element][0], '', tem) + self.theme_elements[element][0], '', tem) text.config(state=DISABLED) - self.frameColourSet = Frame(frameCustom, relief=SOLID, borderwidth=1) - frameFgBg = Frame(frameCustom) - buttonSetColour = Button( - self.frameColourSet, text='Choose Colour for :', - command=self.GetColour, highlightthickness=0) - self.optMenuHighlightTarget = DynOptionMenu( - self.frameColourSet, self.highlightTarget, None, - highlightthickness=0) #, command=self.SetHighlightTargetBinding - self.radioFg = Radiobutton( - frameFgBg, variable=self.fgHilite, value=1, - text='Foreground', command=self.SetColourSampleBinding) - self.radioBg=Radiobutton( - frameFgBg, variable=self.fgHilite, value=0, - text='Background', command=self.SetColourSampleBinding) - self.fgHilite.set(1) - buttonSaveCustomTheme = Button( - frameCustom, text='Save as New Custom Theme', - command=self.SaveAsNewTheme) - #frameTheme - labelTypeTitle = Label(frameTheme, text='Select : ') - self.radioThemeBuiltin = Radiobutton( - frameTheme, variable=self.themeIsBuiltin, value=1, - command=self.SetThemeType, text='a Built-in Theme') - self.radioThemeCustom = Radiobutton( - frameTheme, variable=self.themeIsBuiltin, value=0, - command=self.SetThemeType, text='a Custom Theme') - self.optMenuThemeBuiltin = DynOptionMenu( - frameTheme, self.builtinTheme, None, command=None) - self.optMenuThemeCustom=DynOptionMenu( - frameTheme, self.customTheme, None, command=None) - self.buttonDeleteCustomTheme=Button( - frameTheme, text='Delete Custom Theme', - command=self.DeleteCustomTheme) - self.new_custom_theme = Label(frameTheme, bd=2) - - ##widget packing - #body - frameCustom.pack(side=LEFT, padx=5, pady=5, expand=TRUE, fill=BOTH) - frameTheme.pack(side=LEFT, padx=5, pady=5, fill=Y) - #frameCustom - self.frameColourSet.pack(side=TOP, padx=5, pady=5, expand=TRUE, fill=X) - frameFgBg.pack(side=TOP, padx=5, pady=0) - self.textHighlightSample.pack( - side=TOP, padx=5, pady=5, expand=TRUE, fill=BOTH) - buttonSetColour.pack(side=TOP, expand=TRUE, fill=X, padx=8, pady=4) - self.optMenuHighlightTarget.pack( - side=TOP, expand=TRUE, fill=X, padx=8, pady=3) - self.radioFg.pack(side=LEFT, anchor=E) - self.radioBg.pack(side=RIGHT, anchor=W) - buttonSaveCustomTheme.pack(side=BOTTOM, fill=X, padx=5, pady=5) - #frameTheme - labelTypeTitle.pack(side=TOP, anchor=W, padx=5, pady=5) - self.radioThemeBuiltin.pack(side=TOP, anchor=W, padx=5) - self.radioThemeCustom.pack(side=TOP, anchor=W, padx=5, pady=2) - self.optMenuThemeBuiltin.pack(side=TOP, fill=X, padx=5, pady=5) - self.optMenuThemeCustom.pack(side=TOP, fill=X, anchor=W, padx=5, pady=5) - self.buttonDeleteCustomTheme.pack(side=TOP, fill=X, padx=5, pady=5) + + self.frame_color_set = Frame(frame_custom, relief=SOLID, + borderwidth=1) + frame_fg_bg_toggle = Frame(frame_custom) + button_set_color = Button( + self.frame_color_set, text='Choose color for :', + command=self.get_color, highlightthickness=0) + self.opt_menu_highlight_target = DynOptionMenu( + self.frame_color_set, self.highlight_target, None, + highlightthickness=0) # command=self.SetHighlightTargetBinding + self.radio_fg = Radiobutton( + frame_fg_bg_toggle, variable=self.fg_bg_toggle, value=1, + text='Foreground', command=self.set_color_sample_binding) + self.radio_bg = Radiobutton( + frame_fg_bg_toggle, variable=self.fg_bg_toggle, value=0, + text='Background', command=self.set_color_sample_binding) + self.fg_bg_toggle.set(1) + + button_save_custom_theme = Button( + frame_custom, text='Save as New Custom Theme', + command=self.save_as_new_theme) + + # frame_theme + theme_type_title = Label(frame_theme, text='Select : ') + self.radio_theme_builtin = Radiobutton( + frame_theme, variable=self.is_builtin_theme, value=1, + command=self.set_theme_type, text='a Built-in Theme') + self.radio_theme_custom = Radiobutton( + frame_theme, variable=self.is_builtin_theme, value=0, + command=self.set_theme_type, text='a Custom Theme') + self.opt_menu_theme_builtin = DynOptionMenu( + frame_theme, self.builtin_theme, None, command=None) + self.opt_menu_theme_custom = DynOptionMenu( + frame_theme, self.custom_theme, None, command=None) + self.button_delete_custom_theme = Button( + frame_theme, text='Delete Custom Theme', + command=self.delete_custom_theme) + self.new_custom_theme = Label(frame_theme, bd=2) + + # widget packing + # body + frame_custom.pack(side=LEFT, padx=5, pady=5, expand=True, fill=BOTH) + frame_theme.pack(side=LEFT, padx=5, pady=5, fill=Y) + + # frame_custom + self.frame_color_set.pack(side=TOP, padx=5, pady=5, + expand=True, fill=X) + frame_fg_bg_toggle.pack(side=TOP, padx=5, pady=0) + self.text_highlight_sample.pack( + side=TOP, padx=5, pady=5, expand=True, fill=BOTH) + button_set_color.pack(side=TOP, expand=True, fill=X, padx=8, pady=4) + self.opt_menu_highlight_target.pack( + side=TOP, expand=True, fill=X, padx=8, pady=3) + self.radio_fg.pack(side=LEFT, anchor=E) + self.radio_bg.pack(side=RIGHT, anchor=W) + button_save_custom_theme.pack(side=BOTTOM, fill=X, padx=5, pady=5) + + # frame_theme + theme_type_title.pack(side=TOP, anchor=W, padx=5, pady=5) + self.radio_theme_builtin.pack(side=TOP, anchor=W, padx=5) + self.radio_theme_custom.pack(side=TOP, anchor=W, padx=5, pady=2) + self.opt_menu_theme_builtin.pack(side=TOP, fill=X, padx=5, pady=5) + self.opt_menu_theme_custom.pack(side=TOP, fill=X, anchor=W, + padx=5, pady=5) + self.button_delete_custom_theme.pack(side=TOP, fill=X, padx=5, pady=5) self.new_custom_theme.pack(side=TOP, fill=X, pady=5) return frame - def CreatePageKeys(self): + def create_page_keys(self): + """Return frame of widgets for Keys tab. + + Configuration attributes: + builtin_keys: Menu variable for built-in keybindings. + custom_keys: Menu variable for custom keybindings. + are_keys_builtin: Selector for built-in or custom keybindings. + keybinding: Action/key bindings. + """ parent = self.parent - self.bindingTarget = StringVar(parent) - self.builtinKeys = StringVar(parent) - self.customKeys = StringVar(parent) - self.keysAreBuiltin = BooleanVar(parent) - self.keyBinding = StringVar(parent) - - ##widget creation - #body frame - frame = self.tabPages.pages['Keys'].frame - #body section frames - frameCustom = LabelFrame( - frame, borderwidth=2, relief=GROOVE, - text=' Custom Key Bindings ') - frameKeySets = LabelFrame( - frame, borderwidth=2, relief=GROOVE, text=' Key Set ') - #frameCustom - frameTarget = Frame(frameCustom) - labelTargetTitle = Label(frameTarget, text='Action - Key(s)') - scrollTargetY = Scrollbar(frameTarget) - scrollTargetX = Scrollbar(frameTarget, orient=HORIZONTAL) - self.listBindings = Listbox( - frameTarget, takefocus=FALSE, exportselection=FALSE) - self.listBindings.bind('', self.KeyBindingSelected) - scrollTargetY.config(command=self.listBindings.yview) - scrollTargetX.config(command=self.listBindings.xview) - self.listBindings.config(yscrollcommand=scrollTargetY.set) - self.listBindings.config(xscrollcommand=scrollTargetX.set) - self.buttonNewKeys = Button( - frameCustom, text='Get New Keys for Selection', - command=self.GetNewKeys, state=DISABLED) - #frameKeySets - frames = [Frame(frameKeySets, padx=2, pady=2, borderwidth=0) + # self.binding_target = StringVar(parent) + self.builtin_keys = StringVar(parent) + self.custom_keys = StringVar(parent) + self.are_keys_builtin = BooleanVar(parent) + self.keybinding = StringVar(parent) + + # widget creation + # body frame + frame = self.tab_pages.pages['Keys'].frame + + # body section frames + frame_custom = LabelFrame(frame, borderwidth=2, relief=GROOVE, + text=' Custom Key Bindings ') + frame_key_sets = LabelFrame(frame, borderwidth=2, relief=GROOVE, + text=' Key Set ') + + # frame custom + frame_target = Frame(frame_custom) + target_title = Label(frame_target, text='Action - Key(s)') + scroll_target_y = Scrollbar(frame_target) + scroll_target_x = Scrollbar(frame_target, orient=HORIZONTAL) + self.list_bindings = Listbox( + frame_target, takefocus=False, exportselection=False) + self.list_bindings.bind('', self.keybinding_selected) + scroll_target_y.config(command=self.list_bindings.yview) + scroll_target_x.config(command=self.list_bindings.xview) + self.list_bindings.config(yscrollcommand=scroll_target_y.set) + self.list_bindings.config(xscrollcommand=scroll_target_x.set) + self.button_new_keys = Button( + frame_custom, text='Get New Keys for Selection', + command=self.get_new_keys, state=DISABLED) + + # frame_key_sets + frames = [Frame(frame_key_sets, padx=2, pady=2, borderwidth=0) for i in range(2)] - self.radioKeysBuiltin = Radiobutton( - frames[0], variable=self.keysAreBuiltin, value=1, - command=self.SetKeysType, text='Use a Built-in Key Set') - self.radioKeysCustom = Radiobutton( - frames[0], variable=self.keysAreBuiltin, value=0, - command=self.SetKeysType, text='Use a Custom Key Set') - self.optMenuKeysBuiltin = DynOptionMenu( - frames[0], self.builtinKeys, None, command=None) - self.optMenuKeysCustom = DynOptionMenu( - frames[0], self.customKeys, None, command=None) - self.buttonDeleteCustomKeys = Button( + self.radio_keys_builtin = Radiobutton( + frames[0], variable=self.are_keys_builtin, value=1, + command=self.set_keys_type, text='Use a Built-in Key Set') + self.radio_keys_custom = Radiobutton( + frames[0], variable=self.are_keys_builtin, value=0, + command=self.set_keys_type, text='Use a Custom Key Set') + self.opt_menu_keys_builtin = DynOptionMenu( + frames[0], self.builtin_keys, None, command=None) + self.opt_menu_keys_custom = DynOptionMenu( + frames[0], self.custom_keys, None, command=None) + self.button_delete_custom_keys = Button( frames[1], text='Delete Custom Key Set', - command=self.DeleteCustomKeys) - buttonSaveCustomKeys = Button( + command=self.delete_custom_keys) + button_save_custom_keys = Button( frames[1], text='Save as New Custom Key Set', - command=self.SaveAsNewKeySet) + command=self.save_as_new_key_set) self.new_custom_keys = Label(frames[0], bd=2) - ##widget packing - #body - frameCustom.pack(side=BOTTOM, padx=5, pady=5, expand=TRUE, fill=BOTH) - frameKeySets.pack(side=BOTTOM, padx=5, pady=5, fill=BOTH) - #frameCustom - self.buttonNewKeys.pack(side=BOTTOM, fill=X, padx=5, pady=5) - frameTarget.pack(side=LEFT, padx=5, pady=5, expand=TRUE, fill=BOTH) - #frame target - frameTarget.columnconfigure(0, weight=1) - frameTarget.rowconfigure(1, weight=1) - labelTargetTitle.grid(row=0, column=0, columnspan=2, sticky=W) - self.listBindings.grid(row=1, column=0, sticky=NSEW) - scrollTargetY.grid(row=1, column=1, sticky=NS) - scrollTargetX.grid(row=2, column=0, sticky=EW) - #frameKeySets - self.radioKeysBuiltin.grid(row=0, column=0, sticky=W+NS) - self.radioKeysCustom.grid(row=1, column=0, sticky=W+NS) - self.optMenuKeysBuiltin.grid(row=0, column=1, sticky=NSEW) - self.optMenuKeysCustom.grid(row=1, column=1, sticky=NSEW) + # widget packing + # body + frame_custom.pack(side=BOTTOM, padx=5, pady=5, expand=True, fill=BOTH) + frame_key_sets.pack(side=BOTTOM, padx=5, pady=5, fill=BOTH) + + # frame_custom + self.button_new_keys.pack(side=BOTTOM, fill=X, padx=5, pady=5) + frame_target.pack(side=LEFT, padx=5, pady=5, expand=True, fill=BOTH) + + # frame target + frame_target.columnconfigure(0, weight=1) + frame_target.rowconfigure(1, weight=1) + target_title.grid(row=0, column=0, columnspan=2, sticky=W) + self.list_bindings.grid(row=1, column=0, sticky=NSEW) + scroll_target_y.grid(row=1, column=1, sticky=NS) + scroll_target_x.grid(row=2, column=0, sticky=EW) + + # frame_key_sets + self.radio_keys_builtin.grid(row=0, column=0, sticky=W+NS) + self.radio_keys_custom.grid(row=1, column=0, sticky=W+NS) + self.opt_menu_keys_builtin.grid(row=0, column=1, sticky=NSEW) + self.opt_menu_keys_custom.grid(row=1, column=1, sticky=NSEW) self.new_custom_keys.grid(row=0, column=2, sticky=NSEW, padx=5, pady=5) - self.buttonDeleteCustomKeys.pack(side=LEFT, fill=X, expand=True, padx=2) - buttonSaveCustomKeys.pack(side=LEFT, fill=X, expand=True, padx=2) + self.button_delete_custom_keys.pack(side=LEFT, fill=X, expand=True, + padx=2) + button_save_custom_keys.pack(side=LEFT, fill=X, expand=True, padx=2) frames[0].pack(side=TOP, fill=BOTH, expand=True) frames[1].pack(side=TOP, fill=X, expand=True, pady=2) return frame - def CreatePageGeneral(self): + def create_page_general(self): + """Return frame of widgets for General tab. + + Configuration attributes: + win_width: Initial window width in characters. + win_height: Initial window height in characters. + startup_edit: Selector for opening in editor or shell mode. + autosave: Selector for save prompt popup when using Run. + encoding: ? + """ parent = self.parent - self.winWidth = StringVar(parent) - self.winHeight = StringVar(parent) - self.startupEdit = IntVar(parent) - self.autoSave = IntVar(parent) + self.win_width = StringVar(parent) + self.win_height = StringVar(parent) + self.startup_edit = IntVar(parent) + self.autosave = IntVar(parent) self.encoding = StringVar(parent) - self.userHelpBrowser = BooleanVar(parent) - self.helpBrowser = StringVar(parent) - - #widget creation - #body - frame = self.tabPages.pages['General'].frame - #body section frames - frameRun = LabelFrame(frame, borderwidth=2, relief=GROOVE, - text=' Startup Preferences ') - frameSave = LabelFrame(frame, borderwidth=2, relief=GROOVE, - text=' Autosave Preferences ') - frameWinSize = Frame(frame, borderwidth=2, relief=GROOVE) - frameHelp = LabelFrame(frame, borderwidth=2, relief=GROOVE, - text=' Additional Help Sources ') - #frameRun - labelRunChoiceTitle = Label(frameRun, text='At Startup') - self.radioStartupEdit = Radiobutton( - frameRun, variable=self.startupEdit, value=1, + # self.user_help_browser = BooleanVar(parent) + # self.help_browser = StringVar(parent) + + # widget creation + # body + frame = self.tab_pages.pages['General'].frame + + # body section frames + frame_run = LabelFrame(frame, borderwidth=2, relief=GROOVE, + text=' Startup Preferences ') + frame_save = LabelFrame(frame, borderwidth=2, relief=GROOVE, + text=' Autosave Preferences ') + frame_win_size = Frame(frame, borderwidth=2, relief=GROOVE) + frame_help = LabelFrame(frame, borderwidth=2, relief=GROOVE, + text=' Additional Help Sources ') + + # frame run + startup_title = Label(frame_run, text='At Startup') + self.radio_startup_edit = Radiobutton( + frame_run, variable=self.startup_edit, value=1, text="Open Edit Window") - self.radioStartupShell = Radiobutton( - frameRun, variable=self.startupEdit, value=0, + self.radio_startup_shell = Radiobutton( + frame_run, variable=self.startup_edit, value=0, text='Open Shell Window') - #frameSave - labelRunSaveTitle = Label(frameSave, text='At Start of Run (F5) ') - self.radioSaveAsk = Radiobutton( - frameSave, variable=self.autoSave, value=0, + + # frame_save + run_save_title = Label(frame_save, text='At Start of Run (F5) ') + self.radio_save_ask = Radiobutton( + frame_save, variable=self.autosave, value=0, text="Prompt to Save") - self.radioSaveAuto = Radiobutton( - frameSave, variable=self.autoSave, value=1, + self.radio_save_auto = Radiobutton( + frame_save, variable=self.autosave, value=1, text='No Prompt') - #frameWinSize - labelWinSizeTitle = Label( - frameWinSize, text='Initial Window Size (in characters)') - labelWinWidthTitle = Label(frameWinSize, text='Width') - self.entryWinWidth = Entry( - frameWinSize, textvariable=self.winWidth, width=3) - labelWinHeightTitle = Label(frameWinSize, text='Height') - self.entryWinHeight = Entry( - frameWinSize, textvariable=self.winHeight, width=3) - #frameHelp - frameHelpList = Frame(frameHelp) - frameHelpListButtons = Frame(frameHelpList) - scrollHelpList = Scrollbar(frameHelpList) - self.listHelp = Listbox( - frameHelpList, height=5, takefocus=FALSE, - exportselection=FALSE) - scrollHelpList.config(command=self.listHelp.yview) - self.listHelp.config(yscrollcommand=scrollHelpList.set) - self.listHelp.bind('', self.HelpSourceSelected) - self.buttonHelpListEdit = Button( - frameHelpListButtons, text='Edit', state=DISABLED, - width=8, command=self.HelpListItemEdit) - self.buttonHelpListAdd = Button( - frameHelpListButtons, text='Add', - width=8, command=self.HelpListItemAdd) - self.buttonHelpListRemove = Button( - frameHelpListButtons, text='Remove', state=DISABLED, - width=8, command=self.HelpListItemRemove) - - #widget packing - #body - frameRun.pack(side=TOP, padx=5, pady=5, fill=X) - frameSave.pack(side=TOP, padx=5, pady=5, fill=X) - frameWinSize.pack(side=TOP, padx=5, pady=5, fill=X) - frameHelp.pack(side=TOP, padx=5, pady=5, expand=TRUE, fill=BOTH) - #frameRun - labelRunChoiceTitle.pack(side=LEFT, anchor=W, padx=5, pady=5) - self.radioStartupShell.pack(side=RIGHT, anchor=W, padx=5, pady=5) - self.radioStartupEdit.pack(side=RIGHT, anchor=W, padx=5, pady=5) - #frameSave - labelRunSaveTitle.pack(side=LEFT, anchor=W, padx=5, pady=5) - self.radioSaveAuto.pack(side=RIGHT, anchor=W, padx=5, pady=5) - self.radioSaveAsk.pack(side=RIGHT, anchor=W, padx=5, pady=5) - #frameWinSize - labelWinSizeTitle.pack(side=LEFT, anchor=W, padx=5, pady=5) - self.entryWinHeight.pack(side=RIGHT, anchor=E, padx=10, pady=5) - labelWinHeightTitle.pack(side=RIGHT, anchor=E, pady=5) - self.entryWinWidth.pack(side=RIGHT, anchor=E, padx=10, pady=5) - labelWinWidthTitle.pack(side=RIGHT, anchor=E, pady=5) - #frameHelp - frameHelpListButtons.pack(side=RIGHT, padx=5, pady=5, fill=Y) - frameHelpList.pack(side=TOP, padx=5, pady=5, expand=TRUE, fill=BOTH) - scrollHelpList.pack(side=RIGHT, anchor=W, fill=Y) - self.listHelp.pack(side=LEFT, anchor=E, expand=TRUE, fill=BOTH) - self.buttonHelpListEdit.pack(side=TOP, anchor=W, pady=5) - self.buttonHelpListAdd.pack(side=TOP, anchor=W) - self.buttonHelpListRemove.pack(side=TOP, anchor=W, pady=5) + + # frame_win_size + win_size_title = Label( + frame_win_size, text='Initial Window Size (in characters)') + win_width_title = Label(frame_win_size, text='Width') + self.entry_win_width = Entry( + frame_win_size, textvariable=self.win_width, width=3) + win_height_title = Label(frame_win_size, text='Height') + self.entry_win_height = Entry( + frame_win_size, textvariable=self.win_height, width=3) + + # frame_help + frame_helplist = Frame(frame_help) + frame_helplist_buttons = Frame(frame_helplist) + scroll_helplist = Scrollbar(frame_helplist) + self.list_help = Listbox( + frame_helplist, height=5, takefocus=False, + exportselection=False) + scroll_helplist.config(command=self.list_help.yview) + self.list_help.config(yscrollcommand=scroll_helplist.set) + self.list_help.bind('', self.help_source_selected) + self.button_helplist_edit = Button( + frame_helplist_buttons, text='Edit', state=DISABLED, + width=8, command=self.helplist_item_edit) + self.button_helplist_add = Button( + frame_helplist_buttons, text='Add', + width=8, command=self.helplist_item_add) + self.button_helplist_remove = Button( + frame_helplist_buttons, text='Remove', state=DISABLED, + width=8, command=self.helplist_item_remove) + + # widget packing + # body + frame_run.pack(side=TOP, padx=5, pady=5, fill=X) + frame_save.pack(side=TOP, padx=5, pady=5, fill=X) + frame_win_size.pack(side=TOP, padx=5, pady=5, fill=X) + frame_help.pack(side=TOP, padx=5, pady=5, expand=True, fill=BOTH) + + # frame_run + startup_title.pack(side=LEFT, anchor=W, padx=5, pady=5) + self.radio_startup_shell.pack(side=RIGHT, anchor=W, padx=5, pady=5) + self.radio_startup_edit.pack(side=RIGHT, anchor=W, padx=5, pady=5) + + # frame_save + run_save_title.pack(side=LEFT, anchor=W, padx=5, pady=5) + self.radio_save_auto.pack(side=RIGHT, anchor=W, padx=5, pady=5) + self.radio_save_ask.pack(side=RIGHT, anchor=W, padx=5, pady=5) + + # frame_win_size + win_size_title.pack(side=LEFT, anchor=W, padx=5, pady=5) + self.entry_win_height.pack(side=RIGHT, anchor=E, padx=10, pady=5) + win_height_title.pack(side=RIGHT, anchor=E, pady=5) + self.entry_win_width.pack(side=RIGHT, anchor=E, padx=10, pady=5) + win_width_title.pack(side=RIGHT, anchor=E, pady=5) + + # frame_help + frame_helplist_buttons.pack(side=RIGHT, padx=5, pady=5, fill=Y) + frame_helplist.pack(side=TOP, padx=5, pady=5, expand=True, fill=BOTH) + scroll_helplist.pack(side=RIGHT, anchor=W, fill=Y) + self.list_help.pack(side=LEFT, anchor=E, expand=True, fill=BOTH) + self.button_helplist_edit.pack(side=TOP, anchor=W, pady=5) + self.button_helplist_add.pack(side=TOP, anchor=W) + self.button_helplist_remove.pack(side=TOP, anchor=W, pady=5) return frame - def AttachVarCallbacks(self): - self.fontSize.trace_add('write', self.VarChanged_font) - self.fontName.trace_add('write', self.VarChanged_font) - self.fontBold.trace_add('write', self.VarChanged_font) - self.spaceNum.trace_add('write', self.VarChanged_spaceNum) - self.colour.trace_add('write', self.VarChanged_colour) - self.builtinTheme.trace_add('write', self.VarChanged_builtinTheme) - self.customTheme.trace_add('write', self.VarChanged_customTheme) - self.themeIsBuiltin.trace_add('write', self.VarChanged_themeIsBuiltin) - self.highlightTarget.trace_add('write', self.VarChanged_highlightTarget) - self.keyBinding.trace_add('write', self.VarChanged_keyBinding) - self.builtinKeys.trace_add('write', self.VarChanged_builtinKeys) - self.customKeys.trace_add('write', self.VarChanged_customKeys) - self.keysAreBuiltin.trace_add('write', self.VarChanged_keysAreBuiltin) - self.winWidth.trace_add('write', self.VarChanged_winWidth) - self.winHeight.trace_add('write', self.VarChanged_winHeight) - self.startupEdit.trace_add('write', self.VarChanged_startupEdit) - self.autoSave.trace_add('write', self.VarChanged_autoSave) - self.encoding.trace_add('write', self.VarChanged_encoding) + def attach_var_callbacks(self): + "Attach callbacks to variables that can be changed." + self.font_size.trace_add('write', self.var_changed_font) + self.font_name.trace_add('write', self.var_changed_font) + self.font_bold.trace_add('write', self.var_changed_font) + self.space_num.trace_add('write', self.var_changed_space_num) + self.color.trace_add('write', self.var_changed_color) + self.builtin_theme.trace_add('write', self.var_changed_builtin_theme) + self.custom_theme.trace_add('write', self.var_changed_custom_theme) + self.is_builtin_theme.trace_add('write', self.var_changed_is_builtin_theme) + self.highlight_target.trace_add('write', self.var_changed_highlight_target) + self.keybinding.trace_add('write', self.var_changed_keybinding) + self.builtin_keys.trace_add('write', self.var_changed_builtin_keys) + self.custom_keys.trace_add('write', self.var_changed_custom_keys) + self.are_keys_builtin.trace_add('write', self.var_changed_are_keys_builtin) + self.win_width.trace_add('write', self.var_changed_win_width) + self.win_height.trace_add('write', self.var_changed_win_height) + self.startup_edit.trace_add('write', self.var_changed_startup_edit) + self.autosave.trace_add('write', self.var_changed_autosave) + self.encoding.trace_add('write', self.var_changed_encoding) def remove_var_callbacks(self): "Remove callbacks to prevent memory leaks." for var in ( - self.fontSize, self.fontName, self.fontBold, - self.spaceNum, self.colour, self.builtinTheme, - self.customTheme, self.themeIsBuiltin, self.highlightTarget, - self.keyBinding, self.builtinKeys, self.customKeys, - self.keysAreBuiltin, self.winWidth, self.winHeight, - self.startupEdit, self.autoSave, self.encoding,): + self.font_size, self.font_name, self.font_bold, + self.space_num, self.builtin_theme, self.custom_theme, + self.color, self.is_builtin_theme, self.highlight_target, + self.keybinding, self.builtin_keys, self.custom_keys, + self.are_keys_builtin, self.win_width, self.win_height, + self.startup_edit, self.autosave, self.encoding,): var.trace_remove('write', var.trace_info()[0][1]) - def VarChanged_font(self, *params): - '''When one font attribute changes, save them all, as they are + def var_changed_font(self, *params): + """When one font attribute changes, save them all, as they are not independent from each other. In particular, when we are overriding the default font, we need to write out everything. - ''' - value = self.fontName.get() - self.AddChangedItem('main', 'EditorWindow', 'font', value) - value = self.fontSize.get() - self.AddChangedItem('main', 'EditorWindow', 'font-size', value) - value = self.fontBold.get() - self.AddChangedItem('main', 'EditorWindow', 'font-bold', value) - - def VarChanged_spaceNum(self, *params): - value = self.spaceNum.get() - self.AddChangedItem('main', 'Indent', 'num-spaces', value) - - def VarChanged_colour(self, *params): - self.OnNewColourSet() - - def VarChanged_builtinTheme(self, *params): - oldthemes = ('IDLE Classic', 'IDLE New') - value = self.builtinTheme.get() - if value not in oldthemes: - if idleConf.GetOption('main', 'Theme', 'name') not in oldthemes: - self.AddChangedItem('main', 'Theme', 'name', oldthemes[0]) - self.AddChangedItem('main', 'Theme', 'name2', value) + """ + value = self.font_name.get() + self.add_changed_item('main', 'EditorWindow', 'font', value) + value = self.font_size.get() + self.add_changed_item('main', 'EditorWindow', 'font-size', value) + value = self.font_bold.get() + self.add_changed_item('main', 'EditorWindow', 'font-bold', value) + + def var_changed_space_num(self, *params): + value = self.space_num.get() + self.add_changed_item('main', 'Indent', 'num-spaces', value) + + def var_changed_color(self, *params): + self.on_new_color_set() + + def var_changed_builtin_theme(self, *params): + old_themes = ('IDLE Classic', 'IDLE New') + value = self.builtin_theme.get() + if value not in old_themes: + if idleConf.GetOption('main', 'Theme', 'name') not in old_themes: + self.add_changed_item('main', 'Theme', 'name', old_themes[0]) + self.add_changed_item('main', 'Theme', 'name2', value) self.new_custom_theme.config(text='New theme, see Help', fg='#500000') else: - self.AddChangedItem('main', 'Theme', 'name', value) - self.AddChangedItem('main', 'Theme', 'name2', '') + self.add_changed_item('main', 'Theme', 'name', value) + self.add_changed_item('main', 'Theme', 'name2', '') self.new_custom_theme.config(text='', fg='black') - self.PaintThemeSample() + self.paint_theme_sample() - def VarChanged_customTheme(self, *params): - value = self.customTheme.get() + def var_changed_custom_theme(self, *params): + value = self.custom_theme.get() if value != '- no custom themes -': - self.AddChangedItem('main', 'Theme', 'name', value) - self.PaintThemeSample() + self.add_changed_item('main', 'Theme', 'name', value) + self.paint_theme_sample() - def VarChanged_themeIsBuiltin(self, *params): - value = self.themeIsBuiltin.get() - self.AddChangedItem('main', 'Theme', 'default', value) + def var_changed_is_builtin_theme(self, *params): + value = self.is_builtin_theme.get() + self.add_changed_item('main', 'Theme', 'default', value) if value: - self.VarChanged_builtinTheme() + self.var_changed_builtin_theme() else: - self.VarChanged_customTheme() + self.var_changed_custom_theme() - def VarChanged_highlightTarget(self, *params): - self.SetHighlightTarget() + def var_changed_highlight_target(self, *params): + self.set_highlight_target() - def VarChanged_keyBinding(self, *params): - value = self.keyBinding.get() - keySet = self.customKeys.get() - event = self.listBindings.get(ANCHOR).split()[0] + def var_changed_keybinding(self, *params): + value = self.keybinding.get() + key_set = self.custom_keys.get() + event = self.list_bindings.get(ANCHOR).split()[0] if idleConf.IsCoreBinding(event): - #this is a core keybinding - self.AddChangedItem('keys', keySet, event, value) - else: #this is an extension key binding - extName = idleConf.GetExtnNameForEvent(event) - extKeybindSection = extName + '_cfgBindings' - self.AddChangedItem('extensions', extKeybindSection, event, value) - - def VarChanged_builtinKeys(self, *params): - oldkeys = ( + # this is a core keybinding + self.add_changed_item('keys', key_set, event, value) + else: # this is an extension key binding + ext_name = idleConf.GetExtnNameForEvent(event) + ext_keybind_section = ext_name + '_cfgBindings' + self.add_changed_item('extensions', ext_keybind_section, event, value) + + def var_changed_builtin_keys(self, *params): + old_keys = ( 'IDLE Classic Windows', 'IDLE Classic Unix', 'IDLE Classic Mac', 'IDLE Classic OSX', ) - value = self.builtinKeys.get() - if value not in oldkeys: - if idleConf.GetOption('main', 'Keys', 'name') not in oldkeys: - self.AddChangedItem('main', 'Keys', 'name', oldkeys[0]) - self.AddChangedItem('main', 'Keys', 'name2', value) + value = self.builtin_keys.get() + if value not in old_keys: + if idleConf.GetOption('main', 'Keys', 'name') not in old_keys: + self.add_changed_item('main', 'Keys', 'name', old_keys[0]) + self.add_changed_item('main', 'Keys', 'name2', value) self.new_custom_keys.config(text='New key set, see Help', fg='#500000') else: - self.AddChangedItem('main', 'Keys', 'name', value) - self.AddChangedItem('main', 'Keys', 'name2', '') + self.add_changed_item('main', 'Keys', 'name', value) + self.add_changed_item('main', 'Keys', 'name2', '') self.new_custom_keys.config(text='', fg='black') - self.LoadKeysList(value) + self.load_keys_list(value) - def VarChanged_customKeys(self, *params): - value = self.customKeys.get() + def var_changed_custom_keys(self, *params): + value = self.custom_keys.get() if value != '- no custom keys -': - self.AddChangedItem('main', 'Keys', 'name', value) - self.LoadKeysList(value) + self.add_changed_item('main', 'Keys', 'name', value) + self.load_keys_list(value) - def VarChanged_keysAreBuiltin(self, *params): - value = self.keysAreBuiltin.get() - self.AddChangedItem('main', 'Keys', 'default', value) + def var_changed_are_keys_builtin(self, *params): + value = self.are_keys_builtin.get() + self.add_changed_item('main', 'Keys', 'default', value) if value: - self.VarChanged_builtinKeys() + self.var_changed_builtin_keys() else: - self.VarChanged_customKeys() + self.var_changed_custom_keys() - def VarChanged_winWidth(self, *params): - value = self.winWidth.get() - self.AddChangedItem('main', 'EditorWindow', 'width', value) + def var_changed_win_width(self, *params): + value = self.win_width.get() + self.add_changed_item('main', 'EditorWindow', 'width', value) - def VarChanged_winHeight(self, *params): - value = self.winHeight.get() - self.AddChangedItem('main', 'EditorWindow', 'height', value) + def var_changed_win_height(self, *params): + value = self.win_height.get() + self.add_changed_item('main', 'EditorWindow', 'height', value) - def VarChanged_startupEdit(self, *params): - value = self.startupEdit.get() - self.AddChangedItem('main', 'General', 'editor-on-startup', value) + def var_changed_startup_edit(self, *params): + value = self.startup_edit.get() + self.add_changed_item('main', 'General', 'editor-on-startup', value) - def VarChanged_autoSave(self, *params): - value = self.autoSave.get() - self.AddChangedItem('main', 'General', 'autosave', value) + def var_changed_autosave(self, *params): + value = self.autosave.get() + self.add_changed_item('main', 'General', 'autosave', value) - def VarChanged_encoding(self, *params): + def var_changed_encoding(self, *params): value = self.encoding.get() - self.AddChangedItem('main', 'EditorWindow', 'encoding', value) - - def ResetChangedItems(self): - #When any config item is changed in this dialog, an entry - #should be made in the relevant section (config type) of this - #dictionary. The key should be the config file section name and the - #value a dictionary, whose key:value pairs are item=value pairs for - #that config file section. - self.changedItems = {'main':{}, 'highlight':{}, 'keys':{}, - 'extensions':{}} - - def AddChangedItem(self, typ, section, item, value): - value = str(value) #make sure we use a string - if section not in self.changedItems[typ]: - self.changedItems[typ][section] = {} - self.changedItems[typ][section][item] = value - - def GetDefaultItems(self): - dItems={'main':{}, 'highlight':{}, 'keys':{}, 'extensions':{}} - for configType in dItems: - sections = idleConf.GetSectionList('default', configType) + self.add_changed_item('main', 'EditorWindow', 'encoding', value) + + def reset_changed_items(self): + "Reset dictionary containing the items changed on each tab." + # When any config item is changed in this dialog, an entry + # should be made in the relevant section (config type) of this + # dictionary. The key should be the config file section name and the + # value a dictionary, whose key:value pairs are item=value pairs for + # that config file section. + self.changed_items = {'main': {}, 'highlight': {}, 'keys': {}, + 'extensions': {}} + + def add_changed_item(self, typ, section, item, value): + "Add item/value pair to changed items dictionary for typ and section." + value = str(value) # make sure we use a string + if section not in self.changed_items[typ]: + self.changed_items[typ][section] = {} + self.changed_items[typ][section][item] = value + + def get_default_items(self): + "Return dictionary of default configuration settings." + d_items = {'main': {}, 'highlight': {}, 'keys': {}, 'extensions': {}} + for config_type in d_items: + sections = idleConf.GetSectionList('default', config_type) for section in sections: - dItems[configType][section] = {} - options = idleConf.defaultCfg[configType].GetOptionList(section) + d_items[config_type][section] = {} + options = idleConf.defaultCfg[config_type].GetOptionList(section) for option in options: - dItems[configType][section][option] = ( - idleConf.defaultCfg[configType].Get(section, option)) - return dItems - - def SetThemeType(self): - if self.themeIsBuiltin.get(): - self.optMenuThemeBuiltin.config(state=NORMAL) - self.optMenuThemeCustom.config(state=DISABLED) - self.buttonDeleteCustomTheme.config(state=DISABLED) + d_items[config_type][section][option] = ( + idleConf.defaultCfg[config_type].Get(section, option)) + return d_items + + def set_theme_type(self): + "Set screen options based on theme type of builtin or custom." + if self.is_builtin_theme.get(): + self.opt_menu_theme_builtin.config(state=NORMAL) + self.opt_menu_theme_custom.config(state=DISABLED) + self.button_delete_custom_theme.config(state=DISABLED) else: - self.optMenuThemeBuiltin.config(state=DISABLED) - self.radioThemeCustom.config(state=NORMAL) - self.optMenuThemeCustom.config(state=NORMAL) - self.buttonDeleteCustomTheme.config(state=NORMAL) - - def SetKeysType(self): - if self.keysAreBuiltin.get(): - self.optMenuKeysBuiltin.config(state=NORMAL) - self.optMenuKeysCustom.config(state=DISABLED) - self.buttonDeleteCustomKeys.config(state=DISABLED) + self.opt_menu_theme_builtin.config(state=DISABLED) + self.radio_theme_custom.config(state=NORMAL) + self.opt_menu_theme_custom.config(state=NORMAL) + self.button_delete_custom_theme.config(state=NORMAL) + + def set_keys_type(self): + "Set screen options based on keys type of builtin or custom." + if self.are_keys_builtin.get(): + self.opt_menu_keys_builtin.config(state=NORMAL) + self.opt_menu_keys_custom.config(state=DISABLED) + self.button_delete_custom_keys.config(state=DISABLED) else: - self.optMenuKeysBuiltin.config(state=DISABLED) - self.radioKeysCustom.config(state=NORMAL) - self.optMenuKeysCustom.config(state=NORMAL) - self.buttonDeleteCustomKeys.config(state=NORMAL) - - def GetNewKeys(self): - listIndex = self.listBindings.index(ANCHOR) - binding = self.listBindings.get(listIndex) - bindName = binding.split()[0] #first part, up to first space - if self.keysAreBuiltin.get(): - currentKeySetName = self.builtinKeys.get() + self.opt_menu_keys_builtin.config(state=DISABLED) + self.radio_keys_custom.config(state=NORMAL) + self.opt_menu_keys_custom.config(state=NORMAL) + self.button_delete_custom_keys.config(state=NORMAL) + + def get_new_keys(self): + """Handle event to change key binding for selected line. + + A selection of a key/binding in the list of current + bindings pops up a dialog to enter a new binding. If + the current key set is builtin and a binding has + changed, then a name for a custom key set needs to be + entered for the change to be applied. + """ + list_index = self.list_bindings.index(ANCHOR) + binding = self.list_bindings.get(list_index) + bind_name = binding.split()[0] # first part, up to first space + if self.are_keys_builtin.get(): + current_key_set_name = self.builtin_keys.get() else: - currentKeySetName = self.customKeys.get() - currentBindings = idleConf.GetCurrentKeySet() - if currentKeySetName in self.changedItems['keys']: #unsaved changes - keySetChanges = self.changedItems['keys'][currentKeySetName] - for event in keySetChanges: - currentBindings[event] = keySetChanges[event].split() - currentKeySequences = list(currentBindings.values()) - newKeys = GetKeysDialog(self, 'Get New Keys', bindName, - currentKeySequences).result - if newKeys: #new keys were specified - if self.keysAreBuiltin.get(): #current key set is a built-in + current_key_set_name = self.custom_keys.get() + current_bindings = idleConf.GetCurrentKeySet() + if current_key_set_name in self.changed_items['keys']: # unsaved changes + key_set_changes = self.changed_items['keys'][current_key_set_name] + for event in key_set_changes: + current_bindings[event] = key_set_changes[event].split() + current_key_sequences = list(current_bindings.values()) + new_keys = GetKeysDialog(self, 'Get New Keys', bind_name, + current_key_sequences).result + if new_keys: # new keys were specified + if self.are_keys_builtin.get(): # current key set is a built-in message = ('Your changes will be saved as a new Custom Key Set.' ' Enter a name for your new Custom Key Set below.') - newKeySet = self.GetNewKeysName(message) - if not newKeySet: #user cancelled custom key set creation - self.listBindings.select_set(listIndex) - self.listBindings.select_anchor(listIndex) + new_key_set = self.get_new_keys_name(message) + if not new_key_set: # user cancelled custom key set creation + self.list_bindings.select_set(list_index) + self.list_bindings.select_anchor(list_index) return - else: #create new custom key set based on previously active key set - self.CreateNewKeySet(newKeySet) - self.listBindings.delete(listIndex) - self.listBindings.insert(listIndex, bindName+' - '+newKeys) - self.listBindings.select_set(listIndex) - self.listBindings.select_anchor(listIndex) - self.keyBinding.set(newKeys) + else: # create new custom key set based on previously active key set + self.create_new_key_set(new_key_set) + self.list_bindings.delete(list_index) + self.list_bindings.insert(list_index, bind_name + ' - ' + new_keys) + self.list_bindings.select_set(list_index) + self.list_bindings.select_anchor(list_index) + self.keybinding.set(new_keys) else: - self.listBindings.select_set(listIndex) - self.listBindings.select_anchor(listIndex) - - def GetNewKeysName(self, message): - usedNames = (idleConf.GetSectionList('user', 'keys') + - idleConf.GetSectionList('default', 'keys')) - newKeySet = SectionName( - self, 'New Custom Key Set', message, usedNames).result - return newKeySet - - def SaveAsNewKeySet(self): - newKeysName = self.GetNewKeysName('New Key Set Name:') - if newKeysName: - self.CreateNewKeySet(newKeysName) - - def KeyBindingSelected(self, event): - self.buttonNewKeys.config(state=NORMAL) - - def CreateNewKeySet(self, newKeySetName): - #creates new custom key set based on the previously active key set, - #and makes the new key set active - if self.keysAreBuiltin.get(): - prevKeySetName = self.builtinKeys.get() + self.list_bindings.select_set(list_index) + self.list_bindings.select_anchor(list_index) + + def get_new_keys_name(self, message): + "Return new key set name from query popup." + used_names = (idleConf.GetSectionList('user', 'keys') + + idleConf.GetSectionList('default', 'keys')) + new_key_set = SectionName( + self, 'New Custom Key Set', message, used_names).result + return new_key_set + + def save_as_new_key_set(self): + "Prompt for name of new key set and save changes using that name." + new_keys_name = self.get_new_keys_name('New Key Set Name:') + if new_keys_name: + self.create_new_key_set(new_keys_name) + + def keybinding_selected(self, event): + "Activate button to assign new keys to selected action." + self.button_new_keys.config(state=NORMAL) + + def create_new_key_set(self, new_key_set_name): + """Create a new custom key set with the given name. + + Create the new key set based on the previously active set + with the current changes applied. Once it is saved, then + activate the new key set. + """ + # creates new custom key set based on the previously active key set, + # and makes the new key set active + if self.are_keys_builtin.get(): + prev_key_set_name = self.builtin_keys.get() else: - prevKeySetName = self.customKeys.get() - prevKeys = idleConf.GetCoreKeys(prevKeySetName) - newKeys = {} - for event in prevKeys: #add key set to changed items - eventName = event[2:-2] #trim off the angle brackets - binding = ' '.join(prevKeys[event]) - newKeys[eventName] = binding - #handle any unsaved changes to prev key set - if prevKeySetName in self.changedItems['keys']: - keySetChanges = self.changedItems['keys'][prevKeySetName] - for event in keySetChanges: - newKeys[event] = keySetChanges[event] - #save the new theme - self.SaveNewKeySet(newKeySetName, newKeys) - #change gui over to the new key set - customKeyList = idleConf.GetSectionList('user', 'keys') - customKeyList.sort() - self.optMenuKeysCustom.SetMenu(customKeyList, newKeySetName) - self.keysAreBuiltin.set(0) - self.SetKeysType() - - def LoadKeysList(self, keySetName): + prev_key_set_name = self.custom_keys.get() + prev_keys = idleConf.GetCoreKeys(prev_key_set_name) + new_keys = {} + for event in prev_keys: # add key set to changed items + event_name = event[2:-2] # trim off the angle brackets + binding = ' '.join(prev_keys[event]) + new_keys[event_name] = binding + # handle any unsaved changes to prev key set + if prev_key_set_name in self.changed_items['keys']: + key_set_changes = self.changed_items['keys'][prev_key_set_name] + for event in key_set_changes: + new_keys[event] = key_set_changes[event] + # save the new theme + self.save_new_key_set(new_key_set_name, new_keys) + # change gui over to the new key set + custom_key_list = idleConf.GetSectionList('user', 'keys') + custom_key_list.sort() + self.opt_menu_keys_custom.SetMenu(custom_key_list, new_key_set_name) + self.are_keys_builtin.set(0) + self.set_keys_type() + + def load_keys_list(self, key_set_name): + """Load the list of action/key binding pairs for the active key set. + + An action/key binding can be selected to change the key binding. + """ reselect = 0 - newKeySet = 0 - if self.listBindings.curselection(): + # new_key_set = 0 + if self.list_bindings.curselection(): reselect = 1 - listIndex = self.listBindings.index(ANCHOR) - keySet = idleConf.GetKeySet(keySetName) - bindNames = list(keySet.keys()) - bindNames.sort() - self.listBindings.delete(0, END) - for bindName in bindNames: - key = ' '.join(keySet[bindName]) #make key(s) into a string - bindName = bindName[2:-2] #trim off the angle brackets - if keySetName in self.changedItems['keys']: - #handle any unsaved changes to this key set - if bindName in self.changedItems['keys'][keySetName]: - key = self.changedItems['keys'][keySetName][bindName] - self.listBindings.insert(END, bindName+' - '+key) + list_index = self.list_bindings.index(ANCHOR) + key_set = idleConf.GetKeySet(key_set_name) + bind_names = list(key_set.keys()) + bind_names.sort() + self.list_bindings.delete(0, END) + for bind_name in bind_names: + key = ' '.join(key_set[bind_name]) # make key(s) into a string + bind_name = bind_name[2:-2] # trim off the angle brackets + if key_set_name in self.changed_items['keys']: + # handle any unsaved changes to this key set + if bind_name in self.changed_items['keys'][key_set_name]: + key = self.changed_items['keys'][key_set_name][bind_name] + self.list_bindings.insert(END, bind_name + ' - ' + key) if reselect: - self.listBindings.see(listIndex) - self.listBindings.select_set(listIndex) - self.listBindings.select_anchor(listIndex) + self.list_bindings.see(list_index) + self.list_bindings.select_set(list_index) + self.list_bindings.select_anchor(list_index) + + def delete_custom_keys(self): + """Handle event to delete a custom key set. - def DeleteCustomKeys(self): - keySetName=self.customKeys.get() + Applying the delete deactivates the current configuration and + reverts to the default. The custom key set is permanently + deleted from the config file. + """ + + key_set_name = self.custom_keys.get() delmsg = 'Are you sure you wish to delete the key set %r ?' if not tkMessageBox.askyesno( - 'Delete Key Set', delmsg % keySetName, parent=self): + 'Delete Key Set', delmsg % key_set_name, parent=self): return - self.DeactivateCurrentConfig() - #remove key set from config - idleConf.userCfg['keys'].remove_section(keySetName) - if keySetName in self.changedItems['keys']: - del(self.changedItems['keys'][keySetName]) - #write changes + self.deactivate_current_config() + # remove key set from config + idleConf.userCfg['keys'].remove_section(key_set_name) + if key_set_name in self.changed_items['keys']: + del(self.changed_items['keys'][key_set_name]) + # write changes idleConf.userCfg['keys'].Save() - #reload user key set list - itemList = idleConf.GetSectionList('user', 'keys') - itemList.sort() - if not itemList: - self.radioKeysCustom.config(state=DISABLED) - self.optMenuKeysCustom.SetMenu(itemList, '- no custom keys -') + # reload user key set list + item_list = idleConf.GetSectionList('user', 'keys') + item_list.sort() + if not item_list: + self.radio_keys_custom.config(state=DISABLED) + self.opt_menu_keys_custom.SetMenu(item_list, '- no custom keys -') else: - self.optMenuKeysCustom.SetMenu(itemList, itemList[0]) - #revert to default key set - self.keysAreBuiltin.set(idleConf.defaultCfg['main'] - .Get('Keys', 'default')) - self.builtinKeys.set(idleConf.defaultCfg['main'].Get('Keys', 'name') - or idleConf.default_keys()) - #user can't back out of these changes, they must be applied now - self.SaveAllChangedConfigs() - self.ActivateConfigChanges() - self.SetKeysType() - - def DeleteCustomTheme(self): - themeName = self.customTheme.get() + self.opt_menu_keys_custom.SetMenu(item_list, item_list[0]) + # revert to default key set + self.are_keys_builtin.set(idleConf.defaultCfg['main'] + .Get('Keys', 'default')) + self.builtin_keys.set(idleConf.defaultCfg['main'].Get('Keys', 'name') + or idleConf.default_keys()) + # user can't back out of these changes, they must be applied now + self.save_all_changed_configs() + self.activate_config_changes() + self.set_keys_type() + + def delete_custom_theme(self): + """Handle event to delete custom theme. + + The current theme is deactivated and the default theme is + activated. The custom theme is permanently removed from + the config file. + """ + theme_name = self.custom_theme.get() delmsg = 'Are you sure you wish to delete the theme %r ?' if not tkMessageBox.askyesno( - 'Delete Theme', delmsg % themeName, parent=self): + 'Delete Theme', delmsg % theme_name, parent=self): return - self.DeactivateCurrentConfig() - #remove theme from config - idleConf.userCfg['highlight'].remove_section(themeName) - if themeName in self.changedItems['highlight']: - del(self.changedItems['highlight'][themeName]) - #write changes + self.deactivate_current_config() + # remove theme from config + idleConf.userCfg['highlight'].remove_section(theme_name) + if theme_name in self.changed_items['highlight']: + del(self.changed_items['highlight'][theme_name]) + # write changes idleConf.userCfg['highlight'].Save() - #reload user theme list - itemList = idleConf.GetSectionList('user', 'highlight') - itemList.sort() - if not itemList: - self.radioThemeCustom.config(state=DISABLED) - self.optMenuThemeCustom.SetMenu(itemList, '- no custom themes -') + # reload user theme list + item_list = idleConf.GetSectionList('user', 'highlight') + item_list.sort() + if not item_list: + self.radio_theme_custom.config(state=DISABLED) + self.opt_menu_theme_custom.SetMenu(item_list, '- no custom themes -') else: - self.optMenuThemeCustom.SetMenu(itemList, itemList[0]) - #revert to default theme - self.themeIsBuiltin.set(idleConf.defaultCfg['main'].Get('Theme', 'default')) - self.builtinTheme.set(idleConf.defaultCfg['main'].Get('Theme', 'name')) - #user can't back out of these changes, they must be applied now - self.SaveAllChangedConfigs() - self.ActivateConfigChanges() - self.SetThemeType() - - def GetColour(self): - target = self.highlightTarget.get() - prevColour = self.frameColourSet.cget('bg') - rgbTuplet, colourString = tkColorChooser.askcolor( - parent=self, title='Pick new colour for : '+target, - initialcolor=prevColour) - if colourString and (colourString != prevColour): - #user didn't cancel, and they chose a new colour - if self.themeIsBuiltin.get(): #current theme is a built-in + self.opt_menu_theme_custom.SetMenu(item_list, item_list[0]) + # revert to default theme + self.is_builtin_theme.set(idleConf.defaultCfg['main'].Get('Theme', 'default')) + self.builtin_theme.set(idleConf.defaultCfg['main'].Get('Theme', 'name')) + # user can't back out of these changes, they must be applied now + self.save_all_changed_configs() + self.activate_config_changes() + self.set_theme_type() + + def get_color(self): + """Handle button to select a new color for the target tag. + + If a new color is selected while using a builtin theme, a + name must be supplied to create a custom theme. + """ + target = self.highlight_target.get() + prev_color = self.frame_color_set.cget('bg') + rgb_tuplet, color_string = tkColorChooser.askcolor( + parent=self, title='Pick new color for : ' + target, + initialcolor=prev_color) + if color_string and (color_string != prev_color): + # user didn't cancel, and they chose a new color + if self.is_builtin_theme.get(): # current theme is a built-in message = ('Your changes will be saved as a new Custom Theme. ' 'Enter a name for your new Custom Theme below.') - newTheme = self.GetNewThemeName(message) - if not newTheme: #user cancelled custom theme creation + new_theme = self.get_new_theme_name(message) + if not new_theme: # user cancelled custom theme creation return - else: #create new custom theme based on previously active theme - self.CreateNewTheme(newTheme) - self.colour.set(colourString) - else: #current theme is user defined - self.colour.set(colourString) - - def OnNewColourSet(self): - newColour=self.colour.get() - self.frameColourSet.config(bg=newColour) #set sample - plane ='foreground' if self.fgHilite.get() else 'background' - sampleElement = self.themeElements[self.highlightTarget.get()][0] - self.textHighlightSample.tag_config(sampleElement, **{plane:newColour}) - theme = self.customTheme.get() - themeElement = sampleElement + '-' + plane - self.AddChangedItem('highlight', theme, themeElement, newColour) - - def GetNewThemeName(self, message): - usedNames = (idleConf.GetSectionList('user', 'highlight') + - idleConf.GetSectionList('default', 'highlight')) - newTheme = SectionName( - self, 'New Custom Theme', message, usedNames).result - return newTheme - - def SaveAsNewTheme(self): - newThemeName = self.GetNewThemeName('New Theme Name:') - if newThemeName: - self.CreateNewTheme(newThemeName) - - def CreateNewTheme(self, newThemeName): - #creates new custom theme based on the previously active theme, - #and makes the new theme active - if self.themeIsBuiltin.get(): - themeType = 'default' - themeName = self.builtinTheme.get() + else: # create new custom theme based on previously active theme + self.create_new_theme(new_theme) + self.color.set(color_string) + else: # current theme is user defined + self.color.set(color_string) + + def on_new_color_set(self): + "Handle a color change by displaying sample of it on the dialog." + new_color = self.color.get() + self.frame_color_set.config(bg=new_color) # set sample + plane = 'foreground' if self.fg_bg_toggle.get() else 'background' + sample_element = self.theme_elements[self.highlight_target.get()][0] + self.text_highlight_sample.tag_config(sample_element, **{plane:new_color}) + theme = self.custom_theme.get() + theme_element = sample_element + '-' + plane + self.add_changed_item('highlight', theme, theme_element, new_color) + + def get_new_theme_name(self, message): + "Return name of new theme from query popup." + used_names = (idleConf.GetSectionList('user', 'highlight') + + idleConf.GetSectionList('default', 'highlight')) + new_theme = SectionName( + self, 'New Custom Theme', message, used_names).result + return new_theme + + def save_as_new_theme(self): + "Prompt for new theme name and create the theme." + new_theme_name = self.get_new_theme_name('New Theme Name:') + if new_theme_name: + self.create_new_theme(new_theme_name) + + def create_new_theme(self, new_theme_name): + """Create a new custom theme with the given name. + + Create the new theme based on the previously active theme + with the current changes applied. Once it is saved, then + activate the new theme. + """ + + # creates new custom theme based on the previously active theme, + # and makes the new theme active + if self.is_builtin_theme.get(): + theme_type = 'default' + theme_name = self.builtin_theme.get() else: - themeType = 'user' - themeName = self.customTheme.get() - newTheme = idleConf.GetThemeDict(themeType, themeName) - #apply any of the old theme's unsaved changes to the new theme - if themeName in self.changedItems['highlight']: - themeChanges = self.changedItems['highlight'][themeName] - for element in themeChanges: - newTheme[element] = themeChanges[element] - #save the new theme - self.SaveNewTheme(newThemeName, newTheme) - #change gui over to the new theme - customThemeList = idleConf.GetSectionList('user', 'highlight') - customThemeList.sort() - self.optMenuThemeCustom.SetMenu(customThemeList, newThemeName) - self.themeIsBuiltin.set(0) - self.SetThemeType() - - def OnListFontButtonRelease(self, event): - font = self.listFontName.get(ANCHOR) - self.fontName.set(font.lower()) - self.SetFontSample() - - def SetFontSample(self, event=None): - fontName = self.fontName.get() - fontWeight = tkFont.BOLD if self.fontBold.get() else tkFont.NORMAL - newFont = (fontName, self.fontSize.get(), fontWeight) - self.labelFontSample.config(font=newFont) - self.textHighlightSample.configure(font=newFont) - - def SetHighlightTarget(self): - if self.highlightTarget.get() == 'Cursor': #bg not possible - self.radioFg.config(state=DISABLED) - self.radioBg.config(state=DISABLED) - self.fgHilite.set(1) - else: #both fg and bg can be set - self.radioFg.config(state=NORMAL) - self.radioBg.config(state=NORMAL) - self.fgHilite.set(1) - self.SetColourSample() - - def SetColourSampleBinding(self, *args): - self.SetColourSample() - - def SetColourSample(self): - #set the colour smaple area - tag = self.themeElements[self.highlightTarget.get()][0] - plane = 'foreground' if self.fgHilite.get() else 'background' - colour = self.textHighlightSample.tag_cget(tag, plane) - self.frameColourSet.config(bg=colour) - - def PaintThemeSample(self): - if self.themeIsBuiltin.get(): #a default theme - theme = self.builtinTheme.get() - else: #a user theme - theme = self.customTheme.get() - for elementTitle in self.themeElements: - element = self.themeElements[elementTitle][0] - colours = idleConf.GetHighlight(theme, element) - if element == 'cursor': #cursor sample needs special painting - colours['background'] = idleConf.GetHighlight( + theme_type = 'user' + theme_name = self.custom_theme.get() + new_theme = idleConf.GetThemeDict(theme_type, theme_name) + # apply any of the old theme's unsaved changes to the new theme + if theme_name in self.changed_items['highlight']: + theme_changes = self.changed_items['highlight'][theme_name] + for element in theme_changes: + new_theme[element] = theme_changes[element] + # save the new theme + self.save_new_theme(new_theme_name, new_theme) + # change gui over to the new theme + custom_theme_list = idleConf.GetSectionList('user', 'highlight') + custom_theme_list.sort() + self.opt_menu_theme_custom.SetMenu(custom_theme_list, new_theme_name) + self.is_builtin_theme.set(0) + self.set_theme_type() + + def on_list_fonts_button_release(self, event): + """Handle event of selecting a font from the list. + + Change the font name to the font selected from the list + and update sample text to show that font. + """ + font = self.list_fonts.get(ANCHOR) + self.font_name.set(font.lower()) + self.set_font_sample() + + def set_font_sample(self, event=None): + "Update the screen samples with the font settings from the dialog." + font_name = self.font_name.get() + font_weight = tkFont.BOLD if self.font_bold.get() else tkFont.NORMAL + new_font = (font_name, self.font_size.get(), font_weight) + self.font_sample.config(font=new_font) + self.text_highlight_sample.configure(font=new_font) + + def set_highlight_target(self): + "Set fg/bg toggle and color based on highlight target." + if self.highlight_target.get() == 'Cursor': # bg not possible + self.radio_fg.config(state=DISABLED) + self.radio_bg.config(state=DISABLED) + self.fg_bg_toggle.set(1) + else: # both fg and bg can be set + self.radio_fg.config(state=NORMAL) + self.radio_bg.config(state=NORMAL) + self.fg_bg_toggle.set(1) + self.set_color_sample() + + def set_color_sample_binding(self, *args): + "Change color based on foreground/background toggle." + self.set_color_sample() + + def set_color_sample(self): + "Set the color of the frame background to reflect the selected target." + # set the color sample area + tag = self.theme_elements[self.highlight_target.get()][0] + plane = 'foreground' if self.fg_bg_toggle.get() else 'background' + color = self.text_highlight_sample.tag_cget(tag, plane) + self.frame_color_set.config(bg=color) + + def paint_theme_sample(self): + "Apply the theme colors to each element tag in the sample text." + if self.is_builtin_theme.get(): # a default theme + theme = self.builtin_theme.get() + else: # a user theme + theme = self.custom_theme.get() + for element_title in self.theme_elements: + element = self.theme_elements[element_title][0] + colors = idleConf.GetHighlight(theme, element) + if element == 'cursor': # cursor sample needs special painting + colors['background'] = idleConf.GetHighlight( theme, 'normal', fgBg='bg') - #handle any unsaved changes to this theme - if theme in self.changedItems['highlight']: - themeDict = self.changedItems['highlight'][theme] - if element + '-foreground' in themeDict: - colours['foreground'] = themeDict[element + '-foreground'] - if element + '-background' in themeDict: - colours['background'] = themeDict[element + '-background'] - self.textHighlightSample.tag_config(element, **colours) - self.SetColourSample() - - def HelpSourceSelected(self, event): - self.SetHelpListButtonStates() - - def SetHelpListButtonStates(self): - if self.listHelp.size() < 1: #no entries in list - self.buttonHelpListEdit.config(state=DISABLED) - self.buttonHelpListRemove.config(state=DISABLED) - else: #there are some entries - if self.listHelp.curselection(): #there currently is a selection - self.buttonHelpListEdit.config(state=NORMAL) - self.buttonHelpListRemove.config(state=NORMAL) - else: #there currently is not a selection - self.buttonHelpListEdit.config(state=DISABLED) - self.buttonHelpListRemove.config(state=DISABLED) - - def HelpListItemAdd(self): - helpSource = HelpSource(self, 'New Help Source', - ).result - if helpSource: - self.userHelpList.append((helpSource[0], helpSource[1])) - self.listHelp.insert(END, helpSource[0]) - self.UpdateUserHelpChangedItems() - self.SetHelpListButtonStates() - - def HelpListItemEdit(self): - itemIndex = self.listHelp.index(ANCHOR) - helpSource = self.userHelpList[itemIndex] - newHelpSource = HelpSource( + # handle any unsaved changes to this theme + if theme in self.changed_items['highlight']: + theme_dict = self.changed_items['highlight'][theme] + if element + '-foreground' in theme_dict: + colors['foreground'] = theme_dict[element + '-foreground'] + if element + '-background' in theme_dict: + colors['background'] = theme_dict[element + '-background'] + self.text_highlight_sample.tag_config(element, **colors) + self.set_color_sample() + + def help_source_selected(self, event): + "Handle event for selecting additional help." + self.set_helplist_button_states() + + def set_helplist_button_states(self): + "Toggle the state for the help list buttons." + if self.list_help.size() < 1: # no entries in list + self.button_helplist_edit.config(state=DISABLED) + self.button_helplist_remove.config(state=DISABLED) + else: # there are some entries + if self.list_help.curselection(): # there currently is a selection + self.button_helplist_edit.config(state=NORMAL) + self.button_helplist_remove.config(state=NORMAL) + else: # there currently is not a selection + self.button_helplist_edit.config(state=DISABLED) + self.button_helplist_remove.config(state=DISABLED) + + def helplist_item_add(self): + """Handle add button for help list. + + Query for name and location of new help sources and add + them to the list. + """ + help_source = HelpSource(self, 'New Help Source',).result + if help_source: + self.user_helplist.append((help_source[0], help_source[1])) + self.list_help.insert(END, help_source[0]) + self.update_user_help_changed_items() + self.set_helplist_button_states() + + def helplist_item_edit(self): + """Handle edit button for help list. + + Query with existing help source information and update + config if the values are changed. + """ + item_index = self.list_help.index(ANCHOR) + help_source = self.user_helplist[item_index] + new_help_source = HelpSource( self, 'Edit Help Source', - menuitem=helpSource[0], - filepath=helpSource[1], + menuitem=help_source[0], + filepath=help_source[1], ).result - if newHelpSource and newHelpSource != helpSource: - self.userHelpList[itemIndex] = newHelpSource - self.listHelp.delete(itemIndex) - self.listHelp.insert(itemIndex, newHelpSource[0]) - self.UpdateUserHelpChangedItems() - self.SetHelpListButtonStates() - - def HelpListItemRemove(self): - itemIndex = self.listHelp.index(ANCHOR) - del(self.userHelpList[itemIndex]) - self.listHelp.delete(itemIndex) - self.UpdateUserHelpChangedItems() - self.SetHelpListButtonStates() - - def UpdateUserHelpChangedItems(self): - "Clear and rebuild the HelpFiles section in self.changedItems" - self.changedItems['main']['HelpFiles'] = {} - for num in range(1, len(self.userHelpList) + 1): - self.AddChangedItem( + if new_help_source and new_help_source != help_source: + self.user_helplist[item_index] = new_help_source + self.list_help.delete(item_index) + self.list_help.insert(item_index, new_help_source[0]) + self.update_user_help_changed_items() + self.set_helplist_button_states() + + def helplist_item_remove(self): + """Handle remove button for help list. + + Delete the help list item from config. + """ + item_index = self.list_help.index(ANCHOR) + del(self.user_helplist[item_index]) + self.list_help.delete(item_index) + self.update_user_help_changed_items() + self.set_helplist_button_states() + + def update_user_help_changed_items(self): + "Clear and rebuild the HelpFiles section in self.changed_items." + self.changed_items['main']['HelpFiles'] = {} + for num in range(1, len(self.user_helplist) + 1): + self.add_changed_item( 'main', 'HelpFiles', str(num), - ';'.join(self.userHelpList[num-1][:2])) + ';'.join(self.user_helplist[num-1][:2])) - def LoadFontCfg(self): - ##base editor font selection list + def load_font_cfg(self): + "Load current configuration settings for the font options." + # base editor font selection list fonts = list(tkFont.families(self)) fonts.sort() for font in fonts: - self.listFontName.insert(END, font) + self.list_fonts.insert(END, font) configuredFont = idleConf.GetFont(self, 'main', 'EditorWindow') - fontName = configuredFont[0].lower() - fontSize = configuredFont[1] - fontBold = configuredFont[2]=='bold' - self.fontName.set(fontName) + font_name = configuredFont[0].lower() + font_size = configuredFont[1] + font_bold = configuredFont[2] == 'bold' + self.font_name.set(font_name) lc_fonts = [s.lower() for s in fonts] try: - currentFontIndex = lc_fonts.index(fontName) - self.listFontName.see(currentFontIndex) - self.listFontName.select_set(currentFontIndex) - self.listFontName.select_anchor(currentFontIndex) + current_font_index = lc_fonts.index(font_name) + self.list_fonts.see(current_font_index) + self.list_fonts.select_set(current_font_index) + self.list_fonts.select_anchor(current_font_index) except ValueError: pass - ##font size dropdown - self.optMenuFontSize.SetMenu(('7', '8', '9', '10', '11', '12', '13', - '14', '16', '18', '20', '22', - '25', '29', '34', '40'), fontSize ) - ##fontWeight - self.fontBold.set(fontBold) - ##font sample - self.SetFontSample() - - def LoadTabCfg(self): - ##indent sizes - spaceNum = idleConf.GetOption( + # font size dropdown + self.opt_menu_font_size.SetMenu(('7', '8', '9', '10', '11', '12', '13', + '14', '16', '18', '20', '22', + '25', '29', '34', '40'), font_size) + # fontWeight + self.font_bold.set(font_bold) + # font sample + self.set_font_sample() + + def load_tab_cfg(self): + "Load current configuration settings for the tab options." + # indent sizes + space_num = idleConf.GetOption( 'main', 'Indent', 'num-spaces', default=4, type='int') - self.spaceNum.set(spaceNum) + self.space_num.set(space_num) - def LoadThemeCfg(self): - ##current theme type radiobutton - self.themeIsBuiltin.set(idleConf.GetOption( + def load_theme_cfg(self): + "Load current configuration settings for the theme options." + # current theme type radiobutton + self.is_builtin_theme.set(idleConf.GetOption( 'main', 'Theme', 'default', type='bool', default=1)) - ##currently set theme - currentOption = idleConf.CurrentTheme() - ##load available theme option menus - if self.themeIsBuiltin.get(): #default theme selected - itemList = idleConf.GetSectionList('default', 'highlight') - itemList.sort() - self.optMenuThemeBuiltin.SetMenu(itemList, currentOption) - itemList = idleConf.GetSectionList('user', 'highlight') - itemList.sort() - if not itemList: - self.radioThemeCustom.config(state=DISABLED) - self.customTheme.set('- no custom themes -') + # currently set theme + current_option = idleConf.CurrentTheme() + # load available theme option menus + if self.is_builtin_theme.get(): # default theme selected + item_list = idleConf.GetSectionList('default', 'highlight') + item_list.sort() + self.opt_menu_theme_builtin.SetMenu(item_list, current_option) + item_list = idleConf.GetSectionList('user', 'highlight') + item_list.sort() + if not item_list: + self.radio_theme_custom.config(state=DISABLED) + self.custom_theme.set('- no custom themes -') else: - self.optMenuThemeCustom.SetMenu(itemList, itemList[0]) - else: #user theme selected - itemList = idleConf.GetSectionList('user', 'highlight') - itemList.sort() - self.optMenuThemeCustom.SetMenu(itemList, currentOption) - itemList = idleConf.GetSectionList('default', 'highlight') - itemList.sort() - self.optMenuThemeBuiltin.SetMenu(itemList, itemList[0]) - self.SetThemeType() - ##load theme element option menu - themeNames = list(self.themeElements.keys()) - themeNames.sort(key=lambda x: self.themeElements[x][1]) - self.optMenuHighlightTarget.SetMenu(themeNames, themeNames[0]) - self.PaintThemeSample() - self.SetHighlightTarget() - - def LoadKeyCfg(self): - ##current keys type radiobutton - self.keysAreBuiltin.set(idleConf.GetOption( + self.opt_menu_theme_custom.SetMenu(item_list, item_list[0]) + else: # user theme selected + item_list = idleConf.GetSectionList('user', 'highlight') + item_list.sort() + self.opt_menu_theme_custom.SetMenu(item_list, current_option) + item_list = idleConf.GetSectionList('default', 'highlight') + item_list.sort() + self.opt_menu_theme_builtin.SetMenu(item_list, item_list[0]) + self.set_theme_type() + # load theme element option menu + theme_names = list(self.theme_elements.keys()) + theme_names.sort(key=lambda x: self.theme_elements[x][1]) + self.opt_menu_highlight_target.SetMenu(theme_names, theme_names[0]) + self.paint_theme_sample() + self.set_highlight_target() + + def load_key_cfg(self): + "Load current configuration settings for the keybinding options." + # current keys type radiobutton + self.are_keys_builtin.set(idleConf.GetOption( 'main', 'Keys', 'default', type='bool', default=1)) - ##currently set keys - currentOption = idleConf.CurrentKeys() - ##load available keyset option menus - if self.keysAreBuiltin.get(): #default theme selected - itemList = idleConf.GetSectionList('default', 'keys') - itemList.sort() - self.optMenuKeysBuiltin.SetMenu(itemList, currentOption) - itemList = idleConf.GetSectionList('user', 'keys') - itemList.sort() - if not itemList: - self.radioKeysCustom.config(state=DISABLED) - self.customKeys.set('- no custom keys -') + # currently set keys + current_option = idleConf.CurrentKeys() + # load available keyset option menus + if self.are_keys_builtin.get(): # default theme selected + item_list = idleConf.GetSectionList('default', 'keys') + item_list.sort() + self.opt_menu_keys_builtin.SetMenu(item_list, current_option) + item_list = idleConf.GetSectionList('user', 'keys') + item_list.sort() + if not item_list: + self.radio_keys_custom.config(state=DISABLED) + self.custom_keys.set('- no custom keys -') else: - self.optMenuKeysCustom.SetMenu(itemList, itemList[0]) - else: #user key set selected - itemList = idleConf.GetSectionList('user', 'keys') - itemList.sort() - self.optMenuKeysCustom.SetMenu(itemList, currentOption) - itemList = idleConf.GetSectionList('default', 'keys') - itemList.sort() - self.optMenuKeysBuiltin.SetMenu(itemList, idleConf.default_keys()) - self.SetKeysType() - ##load keyset element list - keySetName = idleConf.CurrentKeys() - self.LoadKeysList(keySetName) - - def LoadGeneralCfg(self): - #startup state - self.startupEdit.set(idleConf.GetOption( + self.opt_menu_keys_custom.SetMenu(item_list, item_list[0]) + else: # user key set selected + item_list = idleConf.GetSectionList('user', 'keys') + item_list.sort() + self.opt_menu_keys_custom.SetMenu(item_list, current_option) + item_list = idleConf.GetSectionList('default', 'keys') + item_list.sort() + self.opt_menu_keys_builtin.SetMenu(item_list, idleConf.default_keys()) + self.set_keys_type() + # load keyset element list + key_set_name = idleConf.CurrentKeys() + self.load_keys_list(key_set_name) + + def load_general_cfg(self): + "Load current configuration settings for the general options." + # startup state + self.startup_edit.set(idleConf.GetOption( 'main', 'General', 'editor-on-startup', default=1, type='bool')) - #autosave state - self.autoSave.set(idleConf.GetOption( + # autosave state + self.autosave.set(idleConf.GetOption( 'main', 'General', 'autosave', default=0, type='bool')) - #initial window size - self.winWidth.set(idleConf.GetOption( + # initial window size + self.win_width.set(idleConf.GetOption( 'main', 'EditorWindow', 'width', type='int')) - self.winHeight.set(idleConf.GetOption( + self.win_height.set(idleConf.GetOption( 'main', 'EditorWindow', 'height', type='int')) # default source encoding self.encoding.set(idleConf.GetOption( 'main', 'EditorWindow', 'encoding', default='none')) # additional help sources - self.userHelpList = idleConf.GetAllExtraHelpSourcesList() - for helpItem in self.userHelpList: - self.listHelp.insert(END, helpItem[0]) - self.SetHelpListButtonStates() + self.user_helplist = idleConf.GetAllExtraHelpSourcesList() + for help_item in self.user_helplist: + self.list_help.insert(END, help_item[0]) + self.set_helplist_button_states() - def LoadConfigs(self): - """ - load configuration from default and user config files and populate + def load_configs(self): + """Load configuration for each page. + + Load configuration from default and user config files and populate the widgets on the config dialog pages. """ - ### fonts / tabs page - self.LoadFontCfg() - self.LoadTabCfg() - ### highlighting page - self.LoadThemeCfg() - ### keys page - self.LoadKeyCfg() - ### general page - self.LoadGeneralCfg() + # fonts/tabs page + self.load_font_cfg() + self.load_tab_cfg() + # highlighting page + self.load_theme_cfg() + # keys page + self.load_key_cfg() + # general page + self.load_general_cfg() # note: extension page handled separately - def SaveNewKeySet(self, keySetName, keySet): - """ - save a newly created core key set. - keySetName - string, the name of the new key set - keySet - dictionary containing the new key set - """ - if not idleConf.userCfg['keys'].has_section(keySetName): - idleConf.userCfg['keys'].add_section(keySetName) - for event in keySet: - value = keySet[event] - idleConf.userCfg['keys'].SetOption(keySetName, event, value) + def save_new_key_set(self, key_set_name, key_set): + """Save a newly created custom key set. - def SaveNewTheme(self, themeName, theme): + key_set_name - string, the name of the new key set + key_set - dictionary containing the new key set """ - save a newly created theme. - themeName - string, the name of the new theme + if not idleConf.userCfg['keys'].has_section(key_set_name): + idleConf.userCfg['keys'].add_section(key_set_name) + for event in key_set: + value = key_set[event] + idleConf.userCfg['keys'].SetOption(key_set_name, event, value) + + def save_new_theme(self, theme_name, theme): + """Save a newly created custom theme. + + theme_name - string, the name of the new theme theme - dictionary containing the new theme """ - if not idleConf.userCfg['highlight'].has_section(themeName): - idleConf.userCfg['highlight'].add_section(themeName) + if not idleConf.userCfg['highlight'].has_section(theme_name): + idleConf.userCfg['highlight'].add_section(theme_name) for element in theme: value = theme[element] - idleConf.userCfg['highlight'].SetOption(themeName, element, value) - - def SetUserValue(self, configType, section, item, value): - if idleConf.defaultCfg[configType].has_option(section, item): - if idleConf.defaultCfg[configType].Get(section, item) == value: - #the setting equals a default setting, remove it from user cfg - return idleConf.userCfg[configType].RemoveOption(section, item) - #if we got here set the option - return idleConf.userCfg[configType].SetOption(section, item, value) - - def SaveAllChangedConfigs(self): - "Save configuration changes to the user config file." + idleConf.userCfg['highlight'].SetOption(theme_name, element, value) + + def set_user_value(self, config_type, section, item, value): + "Return True if configuration value added or changed." + if idleConf.defaultCfg[config_type].has_option(section, item): + if idleConf.defaultCfg[config_type].Get(section, item) == value: + # the setting equals a default setting, remove it from user cfg + return idleConf.userCfg[config_type].RemoveOption(section, item) + # if we got here set the option + return idleConf.userCfg[config_type].SetOption(section, item, value) + + def save_all_changed_configs(self): + "Save all configuration changes to the user config file." idleConf.userCfg['main'].Save() - for configType in self.changedItems: - cfgTypeHasChanges = False - for section in self.changedItems[configType]: + for config_type in self.changed_items: + cfg_type_changed = False + for section in self.changed_items[config_type]: if section == 'HelpFiles': - #this section gets completely replaced + # this section gets completely replaced idleConf.userCfg['main'].remove_section('HelpFiles') - cfgTypeHasChanges = True - for item in self.changedItems[configType][section]: - value = self.changedItems[configType][section][item] - if self.SetUserValue(configType, section, item, value): - cfgTypeHasChanges = True - if cfgTypeHasChanges: - idleConf.userCfg[configType].Save() - for configType in ['keys', 'highlight']: + cfg_type_changed = True + for item in self.changed_items[config_type][section]: + value = self.changed_items[config_type][section][item] + if self.set_user_value(config_type, section, item, value): + cfg_type_changed = True + if cfg_type_changed: + idleConf.userCfg[config_type].Save() + for config_type in ['keys', 'highlight']: # save these even if unchanged! - idleConf.userCfg[configType].Save() - self.ResetChangedItems() #clear the changed items dict + idleConf.userCfg[config_type].Save() + self.reset_changed_items() # clear the changed items dict self.save_all_changed_extensions() # uses a different mechanism - def DeactivateCurrentConfig(self): - #Before a config is saved, some cleanup of current - #config must be done - remove the previous keybindings - winInstances = self.parent.instance_dict.keys() - for instance in winInstances: + def deactivate_current_config(self): + "Remove current key bindings." + # Before a config is saved, some cleanup of current + # config must be done - remove the previous keybindings + win_instances = self.parent.instance_dict.keys() + for instance in win_instances: instance.RemoveKeybindings() - def ActivateConfigChanges(self): + def activate_config_changes(self): "Dynamically apply configuration changes" - winInstances = self.parent.instance_dict.keys() - for instance in winInstances: + win_instances = self.parent.instance_dict.keys() + for instance in win_instances: instance.ResetColorizer() instance.ResetFont() instance.set_notabs_indentwidth() instance.ApplyKeybindings() instance.reset_help_menu_entries() - def Cancel(self): + def cancel(self): + "Dismiss config dialog." self.destroy() - def Ok(self): - self.Apply() + def ok(self): + "Apply config changes, then dismiss dialog." + self.apply() self.destroy() - def Apply(self): - self.DeactivateCurrentConfig() - self.SaveAllChangedConfigs() - self.ActivateConfigChanges() + def apply(self): + "Apply config changes and leave dialog open." + self.deactivate_current_config() + self.save_all_changed_configs() + self.activate_config_changes() - def Help(self): - page = self.tabPages._current_page + def help(self): + "Create textview for config dialog help." + page = self.tab_pages._current_page view_text(self, title='Help for IDLE preferences', - text=help_common+help_pages.get(page, '')) + text=help_common + help_pages.get(page, '')) - def CreatePageExtensions(self): + def create_page_extensions(self): """Part of the config dialog used for configuring IDLE extensions. This code is generic - it works for any and all IDLE extensions. @@ -1229,15 +1403,15 @@ def CreatePageExtensions(self): GUI interface to change the configuration values, and saves the changes using idleConf. - Not all changes take effect immediately - some may require restarting IDLE. - This depends on each extension's implementation. + Not all changes take effect immediately - some may require restarting + IDLE. This depends on each extension's implementation. All values are treated as text, and it is up to the user to supply reasonable values. The only exception to this are the 'enable*' options, which are boolean, and can be toggled with a True/False button. """ parent = self.parent - frame = self.tabPages.pages['Extensions'].frame + frame = self.tab_pages.pages['Extensions'].frame self.ext_defaultCfg = idleConf.defaultCfg['extensions'] self.ext_userCfg = idleConf.userCfg['extensions'] self.is_int = self.register(is_int) @@ -1251,7 +1425,7 @@ def CreatePageExtensions(self): selectmode='browse') self.extension_list.bind('<>', self.extension_selected) scroll = Scrollbar(frame, command=self.extension_list.yview) - self.extension_list.yscrollcommand=scroll.set + self.extension_list.yscrollcommand = scroll.set self.details_frame = LabelFrame(frame, width=250, height=250) self.extension_list.grid(column=0, row=0, sticky='nws') scroll.grid(column=1, row=0, sticky='ns') @@ -1292,7 +1466,7 @@ def load_extensions(self): def_str = self.ext_defaultCfg.Get( ext_name, opt_name, raw=True) try: - def_obj = {'True':True, 'False':False}[def_str] + def_obj = {'True': True, 'False': False}[def_str] opt_type = 'bool' except KeyError: try: @@ -1318,6 +1492,7 @@ def load_extensions(self): }) def extension_selected(self, event): + "Handle selection of an extension from the list." newsel = self.extension_list.curselection() if newsel: newsel = self.extension_list.get(newsel) @@ -1332,7 +1507,7 @@ def extension_selected(self, event): self.current_extension = newsel def create_extension_frame(self, ext_name): - """Create a frame holding the widgets to configure one extension""" + """Create a frame holding the widgets to configure one extension.""" f = VerticalScrolledFrame(self.details_frame, height=250, width=250) self.config_frame[ext_name] = f entry_area = f.interior @@ -1345,7 +1520,7 @@ def create_extension_frame(self, ext_name): if opt['type'] == 'bool': Checkbutton(entry_area, textvariable=var, variable=var, onvalue='True', offvalue='False', - indicatoron=FALSE, selectcolor='', width=8 + indicatoron=False, selectcolor='', width=8 ).grid(row=row, column=1, sticky=W, padx=7) elif opt['type'] == 'int': Entry(entry_area, textvariable=var, validate='key', @@ -1358,6 +1533,11 @@ def create_extension_frame(self, ext_name): return def set_extension_value(self, section, opt): + """Return True if configuration added or changed. + + If the value is the same as the default, then remove it + from user config file. + """ name = opt['name'] default = opt['default'] value = opt['var'].get().strip() or default @@ -1428,10 +1608,10 @@ def __init__(self, parent, *args, **kw): # create a canvas object and a vertical scrollbar for scrolling it vscrollbar = Scrollbar(self, orient=VERTICAL) - vscrollbar.pack(fill=Y, side=RIGHT, expand=FALSE) + vscrollbar.pack(fill=Y, side=RIGHT, expand=False) canvas = Canvas(self, bd=0, highlightthickness=0, yscrollcommand=vscrollbar.set, width=240) - canvas.pack(side=LEFT, fill=BOTH, expand=TRUE) + canvas.pack(side=LEFT, fill=BOTH, expand=True) vscrollbar.config(command=canvas.yview) # reset the view From 9361976577d28eeb870889d1e08919d128392e2b Mon Sep 17 00:00:00 2001 From: Cheryl Sabella Date: Tue, 20 Jun 2017 18:53:02 -0400 Subject: [PATCH 2/5] bpo-27388: IDLE: Refactor configdialog to PEP8 names and add docstrings --- Lib/idlelib/idle_test/test_configdialog.py | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/Lib/idlelib/idle_test/test_configdialog.py b/Lib/idlelib/idle_test/test_configdialog.py index 3f94493733ba0b..3dadfa27a2885a 100644 --- a/Lib/idlelib/idle_test/test_configdialog.py +++ b/Lib/idlelib/idle_test/test_configdialog.py @@ -26,7 +26,7 @@ # For testing, record args in a list for comparison with expected. changes = [] class TestDialog(ConfigDialog): - def AddChangedItem(self, *args): + def add_changed_item(self, *args): changes.append(args) def setUpModule(): @@ -58,21 +58,21 @@ def test_font(self): dfont = idleConf.GetFont(root, 'main', 'EditorWindow') dsize = str(dfont[1]) dbold = dfont[2] == 'bold' - configure.fontName.set('Test Font') + configure.font_name.set('Test Font') expected = [ ('main', 'EditorWindow', 'font', 'Test Font'), ('main', 'EditorWindow', 'font-size', dsize), ('main', 'EditorWindow', 'font-bold', dbold)] self.assertEqual(changes, expected) changes.clear() - configure.fontSize.set(20) + configure.font_size.set(20) expected = [ ('main', 'EditorWindow', 'font', 'Test Font'), ('main', 'EditorWindow', 'font-size', '20'), ('main', 'EditorWindow', 'font-bold', dbold)] self.assertEqual(changes, expected) changes.clear() - configure.fontBold.set(not dbold) + configure.font_bold.set(not dbold) expected = [ ('main', 'EditorWindow', 'font', 'Test Font'), ('main', 'EditorWindow', 'font-size', '20'), @@ -82,7 +82,7 @@ def test_font(self): #def test_sample(self): pass # TODO def test_tabspace(self): - configure.spaceNum.set(6) + configure.space_num.set(6) self.assertEqual(changes, [('main', 'Indent', 'num-spaces', 6)]) @@ -106,19 +106,19 @@ def setUp(self): changes.clear() def test_startup(self): - configure.radioStartupEdit.invoke() + configure.radio_startup_edit.invoke() self.assertEqual(changes, [('main', 'General', 'editor-on-startup', 1)]) def test_autosave(self): - configure.radioSaveAuto.invoke() + configure.radio_save_auto.invoke() self.assertEqual(changes, [('main', 'General', 'autosave', 1)]) def test_editor_size(self): - configure.entryWinHeight.insert(0, '1') + configure.entry_win_height.insert(0, '1') self.assertEqual(changes, [('main', 'EditorWindow', 'height', '140')]) changes.clear() - configure.entryWinWidth.insert(0, '1') + configure.entry_win_width.insert(0, '1') self.assertEqual(changes, [('main', 'EditorWindow', 'width', '180')]) #def test_help_sources(self): pass # TODO From a264bb14effc8f4615bca2ab8354990ab053a4e6 Mon Sep 17 00:00:00 2001 From: Cheryl Sabella Date: Sun, 25 Jun 2017 13:40:53 -0400 Subject: [PATCH 3/5] bpo-30728: IDLE: Refactor configdialog to PEP8 names --- Lib/idlelib/configdialog.py | 803 ++++++++------------- Lib/idlelib/idle_test/test_configdialog.py | 24 +- 2 files changed, 328 insertions(+), 499 deletions(-) diff --git a/Lib/idlelib/configdialog.py b/Lib/idlelib/configdialog.py index 2128b3b47241b3..96682a92214769 100644 --- a/Lib/idlelib/configdialog.py +++ b/Lib/idlelib/configdialog.py @@ -9,12 +9,12 @@ Refer to comments in EditorWindow autoindent code for details. """ -from tkinter import Toplevel, Frame, LabelFrame, Listbox, Label, Button, Entry -from tkinter import Text, Scale, Radiobutton, Checkbutton, Canvas -from tkinter import StringVar, BooleanVar, IntVar -from tkinter import TOP, BOTTOM, RIGHT, LEFT, SOLID, GROOVE, NORMAL, DISABLED -from tkinter import NONE, BOTH, X, Y, W, E, EW, NS, NSEW, NW -from tkinter import HORIZONTAL, VERTICAL, ANCHOR, END +from tkinter import (Toplevel, Frame, LabelFrame, Listbox, Label, Button, + Entry, Text, Scale, Radiobutton, Checkbutton, Canvas, + StringVar, BooleanVar, IntVar, TRUE, FALSE, + TOP, BOTTOM, RIGHT, LEFT, SOLID, GROOVE, NORMAL, DISABLED, + NONE, BOTH, X, Y, W, E, EW, NS, NSEW, NW, + HORIZONTAL, VERTICAL, ANCHOR, END) from tkinter.ttk import Scrollbar import tkinter.colorchooser as tkColorChooser import tkinter.font as tkFont @@ -28,16 +28,10 @@ from idlelib.tabbedpages import TabbedPageSet from idlelib.textview import view_text - class ConfigDialog(Toplevel): - """Config dialog for IDLE. - """ def __init__(self, parent, title='', _htest=False, _utest=False): - """Show the tabbed dialog for user configuration. - - parent - parent of this dialog - title - string which is the title of this popup dialog + """ _htest - bool, change box location when running htest _utest - bool, don't wait_window when running unittest """ @@ -52,10 +46,10 @@ def __init__(self, parent, title='', _htest=False, _utest=False): x = parent.winfo_rootx() + 20 y = parent.winfo_rooty() + (30 if not _htest else 150) self.geometry(f'+{x}+{y}') - # theme_elements. Each theme element key is its display name. - # The first value of the tuple is the sample area tag name. - # The second value is the display name list sort index. - self.theme_elements = { + #Theme Elements. Each theme element key is its display name. + #The first value of the tuple is the sample area tag name. + #The second value is the display name list sort index. + self.theme_elements={ 'Normal Text': ('normal', '00'), 'Python Keywords': ('keyword', '01'), 'Python Definitions': ('definition', '02'), @@ -71,30 +65,29 @@ def __init__(self, parent, title='', _htest=False, _utest=False): 'Shell Stdout Text': ('stdout', '12'), 'Shell Stderr Text': ('stderr', '13'), } - self.reset_changed_items() # load initial values in changed items dict + self.reset_changed_items() #load initial values in changed items dict self.create_widgets() - self.resizable(height=False, width=False) + self.resizable(height=FALSE, width=FALSE) self.transient(parent) self.grab_set() self.protocol("WM_DELETE_WINDOW", self.cancel) self.tab_pages.focus_set() - # key bindings for this dialog - # self.bind('', self.Cancel) #dismiss dialog, no save - # self.bind('', self.Apply) #apply changes, save - # self.bind('', self.Help) #context help + #key bindings for this dialog + #self.bind('', self.Cancel) #dismiss dialog, no save + #self.bind('', self.Apply) #apply changes, save + #self.bind('', self.Help) #context help self.load_configs() - self.attach_var_callbacks() # avoid callbacks during load_configs + self.attach_var_callbacks() #avoid callbacks during load_configs if not _utest: self.wm_deiconify() self.wait_window() def create_widgets(self): - "Create and place widgets for tabbed dialog." - self.tab_pages = TabbedPageSet( - self, page_names=['Fonts/Tabs', 'Highlighting', 'Keys', - 'General', 'Extensions']) - self.tab_pages.pack(side=TOP, expand=True, fill=BOTH) + self.tab_pages = TabbedPageSet(self, + page_names=['Fonts/Tabs', 'Highlighting', 'Keys', 'General', + 'Extensions']) + self.tab_pages.pack(side=TOP, expand=TRUE, fill=BOTH) self.create_page_font_tab() self.create_page_highlight() self.create_page_keys() @@ -103,20 +96,20 @@ def create_widgets(self): self.create_action_buttons().pack(side=BOTTOM) def create_action_buttons(self): - "Return frame of action buttons for dialog." if macosx.isAquaTk(): # Changing the default padding on OSX results in unreadable # text in the buttons padding_args = {} else: - padding_args = {'padx': 6, 'pady': 3} + padding_args = {'padx':6, 'pady':3} outer = Frame(self, pady=2) buttons = Frame(outer, pady=2) - for txt, cmd in (('Ok', self.ok), - ('Apply', self.apply), - ('Cancel', self.cancel), - ('Help', self.help)): - Button(buttons, text=txt, command=cmd, takefocus=False, + for txt, cmd in ( + ('Ok', self.ok), + ('Apply', self.apply), + ('Cancel', self.cancel), + ('Help', self.help)): + Button(buttons, text=txt, command=cmd, takefocus=FALSE, **padding_args).pack(side=LEFT, padx=5) # add space above buttons Frame(outer, height=2, borderwidth=0).pack(side=TOP) @@ -124,15 +117,6 @@ def create_action_buttons(self): return outer def create_page_font_tab(self): - """Return frame of widgets for Font/Tabs tab. - - Configuration attributes: - font_size: Font size. - font_bold: Select font bold or not. - font_name: Font face. - space_num: Indentation width. - edit_font: Font widget with default font. - """ parent = self.parent self.font_size = StringVar(parent) self.font_bold = BooleanVar(parent) @@ -140,34 +124,29 @@ def create_page_font_tab(self): self.space_num = IntVar(parent) self.edit_font = tkFont.Font(parent, ('courier', 10, 'normal')) - # widget creation - # body frame + ##widget creation + #body frame frame = self.tab_pages.pages['Fonts/Tabs'].frame - - # body section frames - frame_font = LabelFrame(frame, borderwidth=2, relief=GROOVE, - text=' Base Editor Font ') - frame_indent = LabelFrame(frame, borderwidth=2, relief=GROOVE, - text=' Indentation Width ') - - # frame_font + #body section frames + frame_font = LabelFrame( + frame, borderwidth=2, relief=GROOVE, text=' Base Editor Font ') + frame_indent = LabelFrame( + frame, borderwidth=2, relief=GROOVE, text=' Indentation Width ') + #frame_font frame_font_name = Frame(frame_font) frame_font_param = Frame(frame_font) - # frame_font_name font_name_title = Label( frame_font_name, justify=LEFT, text='Font Face :') - self.list_fonts = Listbox(frame_font_name, height=5, takefocus=False, - exportselection=False) - self.list_fonts.bind('', - self.on_list_fonts_button_release) + self.list_fonts = Listbox( + frame_font_name, height=5, takefocus=FALSE, exportselection=FALSE) + self.list_fonts.bind( + '', self.on_list_fonts_button_release) scroll_font = Scrollbar(frame_font_name) scroll_font.config(command=self.list_fonts.yview) self.list_fonts.config(yscrollcommand=scroll_font.set) - # frame_font_param font_size_title = Label(frame_font_param, text='Size :') self.opt_menu_font_size = DynOptionMenu( - frame_font_param, self.font_size, None, - command=self.set_font_sample) + frame_font_param, self.font_size, None, command=self.set_font_sample) check_font_bold = Checkbutton( frame_font_param, variable=self.font_bold, onvalue=1, offvalue=0, text='Bold', command=self.set_font_sample) @@ -175,8 +154,7 @@ def create_page_font_tab(self): self.font_sample = Label( frame_font_sample, justify=LEFT, font=self.edit_font, text='AaBbCcDdEe\nFfGgHhIiJjK\n1234567890\n#:+=(){}[]') - - # frame_indent + #frame_indent frame_indent_size = Frame(frame_indent) indent_size_title = Label( frame_indent_size, justify=LEFT, @@ -185,71 +163,56 @@ def create_page_font_tab(self): frame_indent_size, variable=self.space_num, orient='horizontal', tickinterval=2, from_=2, to=16) - # widget packing - # body - frame_font.pack(side=LEFT, padx=5, pady=5, expand=True, fill=BOTH) + #widget packing + #body + frame_font.pack(side=LEFT, padx=5, pady=5, expand=TRUE, fill=BOTH) frame_indent.pack(side=LEFT, padx=5, pady=5, fill=Y) - - # frame_font + #frame_font frame_font_name.pack(side=TOP, padx=5, pady=5, fill=X) frame_font_param.pack(side=TOP, padx=5, pady=5, fill=X) font_name_title.pack(side=TOP, anchor=W) - self.list_fonts.pack(side=LEFT, expand=True, fill=X) + self.list_fonts.pack(side=LEFT, expand=TRUE, fill=X) scroll_font.pack(side=LEFT, fill=Y) font_size_title.pack(side=LEFT, anchor=W) self.opt_menu_font_size.pack(side=LEFT, anchor=W) check_font_bold.pack(side=LEFT, anchor=W, padx=20) - frame_font_sample.pack(side=TOP, padx=5, pady=5, - expand=True, fill=BOTH) - self.font_sample.pack(expand=True, fill=BOTH) - - # frame_indent + frame_font_sample.pack(side=TOP, padx=5, pady=5, expand=TRUE, fill=BOTH) + self.font_sample.pack(expand=TRUE, fill=BOTH) + #frame_indent frame_indent_size.pack(side=TOP, fill=X) indent_size_title.pack(side=TOP, anchor=W, padx=5) self.scale_indent_size.pack(side=TOP, padx=5, fill=X) return frame def create_page_highlight(self): - """Return frame of widgets for Highlighting tab. - - Configuration attributes: - builtin_theme: Menu variable for built-in theme. - custom_theme: Menu variable for custom theme. - fg_bg_toggle: Toggle for foreground/background color. - color: Color of selected target. - is_builtin_theme: Selector for built-in or custom theme. - highlight_target: Menu variable for the highlight target. - """ parent = self.parent self.builtin_theme = StringVar(parent) self.custom_theme = StringVar(parent) self.fg_bg_toggle = BooleanVar(parent) - self.color = StringVar(parent) - # self.font_name = StringVar(parent) + self.colour = StringVar(parent) + self.font_name = StringVar(parent) self.is_builtin_theme = BooleanVar(parent) self.highlight_target = StringVar(parent) - # widget creation - # body frame + ##widget creation + #body frame frame = self.tab_pages.pages['Highlighting'].frame - - # body section frames + #body section frames frame_custom = LabelFrame(frame, borderwidth=2, relief=GROOVE, - text=' Custom Highlighting ') + text=' Custom Highlighting ') frame_theme = LabelFrame(frame, borderwidth=2, relief=GROOVE, - text=' Highlighting Theme ') - - # frame_custom - self.text_highlight_sample = Text( + text=' Highlighting Theme ') + #frame_custom + self.text_highlight_sample=Text( frame_custom, relief=SOLID, borderwidth=1, font=('courier', 12, ''), cursor='hand2', width=21, height=11, - takefocus=False, highlightthickness=0, wrap=NONE) - text = self.text_highlight_sample + takefocus=FALSE, highlightthickness=0, wrap=NONE) + text=self.text_highlight_sample text.bind('', lambda e: 'break') text.bind('', lambda e: 'break') - txt_and_tags = ( - ('# you can click here', 'comment'), ('\n', 'normal'), - ('# to choose items', 'comment'), ('\n', 'normal'), + text_and_tags=( + ('#you can click here', 'comment'), ('\n', 'normal'), + ('#to choose items', 'comment'), ('\n', 'normal'), ('def', 'keyword'), (' ', 'normal'), ('func', 'definition'), ('(param):\n ', 'normal'), ('"""string"""', 'string'), ('\n var0 = ', 'normal'), @@ -264,37 +227,33 @@ def create_page_highlight(self): ('shell', 'console'), (' ', 'normal'), ('stdout', 'stdout'), (' ', 'normal'), ('stderr', 'stderr'), ('\n', 'normal')) - for txt, tag in txt_and_tags: - text.insert(END, txt, tag) + for texttag in text_and_tags: + text.insert(END, texttag[0], texttag[1]) for element in self.theme_elements: def tem(event, elem=element): event.widget.winfo_toplevel().highlight_target.set(elem) text.tag_bind( self.theme_elements[element][0], '', tem) text.config(state=DISABLED) - - self.frame_color_set = Frame(frame_custom, relief=SOLID, - borderwidth=1) + self.frame_colour_set = Frame(frame_custom, relief=SOLID, borderwidth=1) frame_fg_bg_toggle = Frame(frame_custom) - button_set_color = Button( - self.frame_color_set, text='Choose color for :', - command=self.get_color, highlightthickness=0) + button_set_colour = Button( + self.frame_colour_set, text='Choose Colour for :', + command=self.get_colour, highlightthickness=0) self.opt_menu_highlight_target = DynOptionMenu( - self.frame_color_set, self.highlight_target, None, - highlightthickness=0) # command=self.SetHighlightTargetBinding + self.frame_colour_set, self.highlight_target, None, + highlightthickness=0) #, command=self.set_highlight_targetBinding self.radio_fg = Radiobutton( frame_fg_bg_toggle, variable=self.fg_bg_toggle, value=1, - text='Foreground', command=self.set_color_sample_binding) - self.radio_bg = Radiobutton( + text='Foreground', command=self.set_colour_sample_binding) + self.radio_bg=Radiobutton( frame_fg_bg_toggle, variable=self.fg_bg_toggle, value=0, - text='Background', command=self.set_color_sample_binding) + text='Background', command=self.set_colour_sample_binding) self.fg_bg_toggle.set(1) - button_save_custom_theme = Button( frame_custom, text='Save as New Custom Theme', command=self.save_as_new_theme) - - # frame_theme + #frame_theme theme_type_title = Label(frame_theme, text='Select : ') self.radio_theme_builtin = Radiobutton( frame_theme, variable=self.is_builtin_theme, value=1, @@ -304,75 +263,62 @@ def tem(event, elem=element): command=self.set_theme_type, text='a Custom Theme') self.opt_menu_theme_builtin = DynOptionMenu( frame_theme, self.builtin_theme, None, command=None) - self.opt_menu_theme_custom = DynOptionMenu( + self.opt_menu_theme_custom=DynOptionMenu( frame_theme, self.custom_theme, None, command=None) - self.button_delete_custom_theme = Button( + self.button_delete_custom_theme=Button( frame_theme, text='Delete Custom Theme', command=self.delete_custom_theme) self.new_custom_theme = Label(frame_theme, bd=2) - # widget packing - # body - frame_custom.pack(side=LEFT, padx=5, pady=5, expand=True, fill=BOTH) + ##widget packing + #body + frame_custom.pack(side=LEFT, padx=5, pady=5, expand=TRUE, fill=BOTH) frame_theme.pack(side=LEFT, padx=5, pady=5, fill=Y) - - # frame_custom - self.frame_color_set.pack(side=TOP, padx=5, pady=5, - expand=True, fill=X) + #frame_custom + self.frame_colour_set.pack(side=TOP, padx=5, pady=5, expand=TRUE, fill=X) frame_fg_bg_toggle.pack(side=TOP, padx=5, pady=0) self.text_highlight_sample.pack( - side=TOP, padx=5, pady=5, expand=True, fill=BOTH) - button_set_color.pack(side=TOP, expand=True, fill=X, padx=8, pady=4) + side=TOP, padx=5, pady=5, expand=TRUE, fill=BOTH) + button_set_colour.pack(side=TOP, expand=TRUE, fill=X, padx=8, pady=4) self.opt_menu_highlight_target.pack( - side=TOP, expand=True, fill=X, padx=8, pady=3) + side=TOP, expand=TRUE, fill=X, padx=8, pady=3) self.radio_fg.pack(side=LEFT, anchor=E) self.radio_bg.pack(side=RIGHT, anchor=W) button_save_custom_theme.pack(side=BOTTOM, fill=X, padx=5, pady=5) - - # frame_theme + #frame_theme theme_type_title.pack(side=TOP, anchor=W, padx=5, pady=5) self.radio_theme_builtin.pack(side=TOP, anchor=W, padx=5) self.radio_theme_custom.pack(side=TOP, anchor=W, padx=5, pady=2) self.opt_menu_theme_builtin.pack(side=TOP, fill=X, padx=5, pady=5) - self.opt_menu_theme_custom.pack(side=TOP, fill=X, anchor=W, - padx=5, pady=5) + self.opt_menu_theme_custom.pack(side=TOP, fill=X, anchor=W, padx=5, pady=5) self.button_delete_custom_theme.pack(side=TOP, fill=X, padx=5, pady=5) self.new_custom_theme.pack(side=TOP, fill=X, pady=5) return frame def create_page_keys(self): - """Return frame of widgets for Keys tab. - - Configuration attributes: - builtin_keys: Menu variable for built-in keybindings. - custom_keys: Menu variable for custom keybindings. - are_keys_builtin: Selector for built-in or custom keybindings. - keybinding: Action/key bindings. - """ parent = self.parent - # self.binding_target = StringVar(parent) + self.binding_target = StringVar(parent) self.builtin_keys = StringVar(parent) self.custom_keys = StringVar(parent) self.are_keys_builtin = BooleanVar(parent) self.keybinding = StringVar(parent) - # widget creation - # body frame + ##widget creation + #body frame frame = self.tab_pages.pages['Keys'].frame - - # body section frames - frame_custom = LabelFrame(frame, borderwidth=2, relief=GROOVE, - text=' Custom Key Bindings ') - frame_key_sets = LabelFrame(frame, borderwidth=2, relief=GROOVE, - text=' Key Set ') - - # frame custom + #body section frames + frame_custom = LabelFrame( + frame, borderwidth=2, relief=GROOVE, + text=' Custom Key Bindings ') + frame_key_sets = LabelFrame( + frame, borderwidth=2, relief=GROOVE, text=' Key Set ') + #frame_custom frame_target = Frame(frame_custom) target_title = Label(frame_target, text='Action - Key(s)') scroll_target_y = Scrollbar(frame_target) scroll_target_x = Scrollbar(frame_target, orient=HORIZONTAL) self.list_bindings = Listbox( - frame_target, takefocus=False, exportselection=False) + frame_target, takefocus=FALSE, exportselection=FALSE) self.list_bindings.bind('', self.keybinding_selected) scroll_target_y.config(command=self.list_bindings.yview) scroll_target_x.config(command=self.list_bindings.xview) @@ -381,15 +327,14 @@ def create_page_keys(self): self.button_new_keys = Button( frame_custom, text='Get New Keys for Selection', command=self.get_new_keys, state=DISABLED) - - # frame_key_sets + #frame_key_sets frames = [Frame(frame_key_sets, padx=2, pady=2, borderwidth=0) for i in range(2)] self.radio_keys_builtin = Radiobutton( frames[0], variable=self.are_keys_builtin, value=1, command=self.set_keys_type, text='Use a Built-in Key Set') self.radio_keys_custom = Radiobutton( - frames[0], variable=self.are_keys_builtin, value=0, + frames[0], variable=self.are_keys_builtin, value=0, command=self.set_keys_type, text='Use a Custom Key Set') self.opt_menu_keys_builtin = DynOptionMenu( frames[0], self.builtin_keys, None, command=None) @@ -403,69 +348,54 @@ def create_page_keys(self): command=self.save_as_new_key_set) self.new_custom_keys = Label(frames[0], bd=2) - # widget packing - # body - frame_custom.pack(side=BOTTOM, padx=5, pady=5, expand=True, fill=BOTH) + ##widget packing + #body + frame_custom.pack(side=BOTTOM, padx=5, pady=5, expand=TRUE, fill=BOTH) frame_key_sets.pack(side=BOTTOM, padx=5, pady=5, fill=BOTH) - - # frame_custom + #frame_custom self.button_new_keys.pack(side=BOTTOM, fill=X, padx=5, pady=5) - frame_target.pack(side=LEFT, padx=5, pady=5, expand=True, fill=BOTH) - - # frame target + frame_target.pack(side=LEFT, padx=5, pady=5, expand=TRUE, fill=BOTH) + #frame target frame_target.columnconfigure(0, weight=1) frame_target.rowconfigure(1, weight=1) target_title.grid(row=0, column=0, columnspan=2, sticky=W) self.list_bindings.grid(row=1, column=0, sticky=NSEW) scroll_target_y.grid(row=1, column=1, sticky=NS) scroll_target_x.grid(row=2, column=0, sticky=EW) - - # frame_key_sets + #frame_key_sets self.radio_keys_builtin.grid(row=0, column=0, sticky=W+NS) self.radio_keys_custom.grid(row=1, column=0, sticky=W+NS) self.opt_menu_keys_builtin.grid(row=0, column=1, sticky=NSEW) self.opt_menu_keys_custom.grid(row=1, column=1, sticky=NSEW) self.new_custom_keys.grid(row=0, column=2, sticky=NSEW, padx=5, pady=5) - self.button_delete_custom_keys.pack(side=LEFT, fill=X, expand=True, - padx=2) + self.button_delete_custom_keys.pack(side=LEFT, fill=X, expand=True, padx=2) button_save_custom_keys.pack(side=LEFT, fill=X, expand=True, padx=2) frames[0].pack(side=TOP, fill=BOTH, expand=True) frames[1].pack(side=TOP, fill=X, expand=True, pady=2) return frame def create_page_general(self): - """Return frame of widgets for General tab. - - Configuration attributes: - win_width: Initial window width in characters. - win_height: Initial window height in characters. - startup_edit: Selector for opening in editor or shell mode. - autosave: Selector for save prompt popup when using Run. - encoding: ? - """ parent = self.parent self.win_width = StringVar(parent) self.win_height = StringVar(parent) self.startup_edit = IntVar(parent) self.autosave = IntVar(parent) self.encoding = StringVar(parent) - # self.user_help_browser = BooleanVar(parent) - # self.help_browser = StringVar(parent) + self.user_help_browser = BooleanVar(parent) + self.help_browser = StringVar(parent) - # widget creation - # body + #widget creation + #body frame = self.tab_pages.pages['General'].frame - - # body section frames + #body section frames frame_run = LabelFrame(frame, borderwidth=2, relief=GROOVE, - text=' Startup Preferences ') + text=' Startup Preferences ') frame_save = LabelFrame(frame, borderwidth=2, relief=GROOVE, - text=' Autosave Preferences ') + text=' autosave Preferences ') frame_win_size = Frame(frame, borderwidth=2, relief=GROOVE) frame_help = LabelFrame(frame, borderwidth=2, relief=GROOVE, - text=' Additional Help Sources ') - - # frame run + text=' Additional Help Sources ') + #frame_run startup_title = Label(frame_run, text='At Startup') self.radio_startup_edit = Radiobutton( frame_run, variable=self.startup_edit, value=1, @@ -473,8 +403,7 @@ def create_page_general(self): self.radio_startup_shell = Radiobutton( frame_run, variable=self.startup_edit, value=0, text='Open Shell Window') - - # frame_save + #frame_save run_save_title = Label(frame_save, text='At Start of Run (F5) ') self.radio_save_ask = Radiobutton( frame_save, variable=self.autosave, value=0, @@ -482,8 +411,7 @@ def create_page_general(self): self.radio_save_auto = Radiobutton( frame_save, variable=self.autosave, value=1, text='No Prompt') - - # frame_win_size + #frame_win_size win_size_title = Label( frame_win_size, text='Initial Window Size (in characters)') win_width_title = Label(frame_win_size, text='Width') @@ -492,14 +420,13 @@ def create_page_general(self): win_height_title = Label(frame_win_size, text='Height') self.entry_win_height = Entry( frame_win_size, textvariable=self.win_height, width=3) - - # frame_help + #frame_help frame_helplist = Frame(frame_help) frame_helplist_buttons = Frame(frame_helplist) scroll_helplist = Scrollbar(frame_helplist) self.list_help = Listbox( - frame_helplist, height=5, takefocus=False, - exportselection=False) + frame_helplist, height=5, takefocus=FALSE, + exportselection=FALSE) scroll_helplist.config(command=self.list_help.yview) self.list_help.config(yscrollcommand=scroll_helplist.set) self.list_help.bind('', self.help_source_selected) @@ -513,47 +440,42 @@ def create_page_general(self): frame_helplist_buttons, text='Remove', state=DISABLED, width=8, command=self.helplist_item_remove) - # widget packing - # body + #widget packing + #body frame_run.pack(side=TOP, padx=5, pady=5, fill=X) frame_save.pack(side=TOP, padx=5, pady=5, fill=X) frame_win_size.pack(side=TOP, padx=5, pady=5, fill=X) - frame_help.pack(side=TOP, padx=5, pady=5, expand=True, fill=BOTH) - - # frame_run + frame_help.pack(side=TOP, padx=5, pady=5, expand=TRUE, fill=BOTH) + #frame_run startup_title.pack(side=LEFT, anchor=W, padx=5, pady=5) self.radio_startup_shell.pack(side=RIGHT, anchor=W, padx=5, pady=5) self.radio_startup_edit.pack(side=RIGHT, anchor=W, padx=5, pady=5) - - # frame_save + #frame_save run_save_title.pack(side=LEFT, anchor=W, padx=5, pady=5) self.radio_save_auto.pack(side=RIGHT, anchor=W, padx=5, pady=5) self.radio_save_ask.pack(side=RIGHT, anchor=W, padx=5, pady=5) - - # frame_win_size + #frame_win_size win_size_title.pack(side=LEFT, anchor=W, padx=5, pady=5) self.entry_win_height.pack(side=RIGHT, anchor=E, padx=10, pady=5) win_height_title.pack(side=RIGHT, anchor=E, pady=5) self.entry_win_width.pack(side=RIGHT, anchor=E, padx=10, pady=5) win_width_title.pack(side=RIGHT, anchor=E, pady=5) - - # frame_help + #frame_help frame_helplist_buttons.pack(side=RIGHT, padx=5, pady=5, fill=Y) - frame_helplist.pack(side=TOP, padx=5, pady=5, expand=True, fill=BOTH) + frame_helplist.pack(side=TOP, padx=5, pady=5, expand=TRUE, fill=BOTH) scroll_helplist.pack(side=RIGHT, anchor=W, fill=Y) - self.list_help.pack(side=LEFT, anchor=E, expand=True, fill=BOTH) + self.list_help.pack(side=LEFT, anchor=E, expand=TRUE, fill=BOTH) self.button_helplist_edit.pack(side=TOP, anchor=W, pady=5) self.button_helplist_add.pack(side=TOP, anchor=W) self.button_helplist_remove.pack(side=TOP, anchor=W, pady=5) return frame def attach_var_callbacks(self): - "Attach callbacks to variables that can be changed." self.font_size.trace_add('write', self.var_changed_font) self.font_name.trace_add('write', self.var_changed_font) self.font_bold.trace_add('write', self.var_changed_font) self.space_num.trace_add('write', self.var_changed_space_num) - self.color.trace_add('write', self.var_changed_color) + self.colour.trace_add('write', self.var_changed_colour) self.builtin_theme.trace_add('write', self.var_changed_builtin_theme) self.custom_theme.trace_add('write', self.var_changed_custom_theme) self.is_builtin_theme.trace_add('write', self.var_changed_is_builtin_theme) @@ -572,18 +494,18 @@ def remove_var_callbacks(self): "Remove callbacks to prevent memory leaks." for var in ( self.font_size, self.font_name, self.font_bold, - self.space_num, self.builtin_theme, self.custom_theme, - self.color, self.is_builtin_theme, self.highlight_target, + self.space_num, self.colour, self.builtin_theme, + self.custom_theme, self.is_builtin_theme, self.highlight_target, self.keybinding, self.builtin_keys, self.custom_keys, self.are_keys_builtin, self.win_width, self.win_height, self.startup_edit, self.autosave, self.encoding,): var.trace_remove('write', var.trace_info()[0][1]) def var_changed_font(self, *params): - """When one font attribute changes, save them all, as they are + '''When one font attribute changes, save them all, as they are not independent from each other. In particular, when we are overriding the default font, we need to write out everything. - """ + ''' value = self.font_name.get() self.add_changed_item('main', 'EditorWindow', 'font', value) value = self.font_size.get() @@ -595,8 +517,8 @@ def var_changed_space_num(self, *params): value = self.space_num.get() self.add_changed_item('main', 'Indent', 'num-spaces', value) - def var_changed_color(self, *params): - self.on_new_color_set() + def var_changed_colour(self, *params): + self.on_new_colour_set() def var_changed_builtin_theme(self, *params): old_themes = ('IDLE Classic', 'IDLE New') @@ -635,9 +557,9 @@ def var_changed_keybinding(self, *params): key_set = self.custom_keys.get() event = self.list_bindings.get(ANCHOR).split()[0] if idleConf.IsCoreBinding(event): - # this is a core keybinding + #this is a core keybinding self.add_changed_item('keys', key_set, event, value) - else: # this is an extension key binding + else: #this is an extension key binding ext_name = idleConf.GetExtnNameForEvent(event) ext_keybind_section = ext_name + '_cfgBindings' self.add_changed_item('extensions', ext_keybind_section, event, value) @@ -697,25 +619,22 @@ def var_changed_encoding(self, *params): self.add_changed_item('main', 'EditorWindow', 'encoding', value) def reset_changed_items(self): - "Reset dictionary containing the items changed on each tab." - # When any config item is changed in this dialog, an entry - # should be made in the relevant section (config type) of this - # dictionary. The key should be the config file section name and the - # value a dictionary, whose key:value pairs are item=value pairs for - # that config file section. - self.changed_items = {'main': {}, 'highlight': {}, 'keys': {}, - 'extensions': {}} + #When any config item is changed in this dialog, an entry + #should be made in the relevant section (config type) of this + #dictionary. The key should be the config file section name and the + #value a dictionary, whose key:value pairs are item=value pairs for + #that config file section. + self.changed_items = {'main':{}, 'highlight':{}, 'keys':{}, + 'extensions':{}} def add_changed_item(self, typ, section, item, value): - "Add item/value pair to changed items dictionary for typ and section." - value = str(value) # make sure we use a string + value = str(value) #make sure we use a string if section not in self.changed_items[typ]: self.changed_items[typ][section] = {} self.changed_items[typ][section][item] = value - def get_default_items(self): - "Return dictionary of default configuration settings." - d_items = {'main': {}, 'highlight': {}, 'keys': {}, 'extensions': {}} + def GetDefaultItems(self): + d_items={'main':{}, 'highlight':{}, 'keys':{}, 'extensions':{}} for config_type in d_items: sections = idleConf.GetSectionList('default', config_type) for section in sections: @@ -727,7 +646,6 @@ def get_default_items(self): return d_items def set_theme_type(self): - "Set screen options based on theme type of builtin or custom." if self.is_builtin_theme.get(): self.opt_menu_theme_builtin.config(state=NORMAL) self.opt_menu_theme_custom.config(state=DISABLED) @@ -739,7 +657,6 @@ def set_theme_type(self): self.button_delete_custom_theme.config(state=NORMAL) def set_keys_type(self): - "Set screen options based on keys type of builtin or custom." if self.are_keys_builtin.get(): self.opt_menu_keys_builtin.config(state=NORMAL) self.opt_menu_keys_custom.config(state=DISABLED) @@ -751,42 +668,34 @@ def set_keys_type(self): self.button_delete_custom_keys.config(state=NORMAL) def get_new_keys(self): - """Handle event to change key binding for selected line. - - A selection of a key/binding in the list of current - bindings pops up a dialog to enter a new binding. If - the current key set is builtin and a binding has - changed, then a name for a custom key set needs to be - entered for the change to be applied. - """ list_index = self.list_bindings.index(ANCHOR) binding = self.list_bindings.get(list_index) - bind_name = binding.split()[0] # first part, up to first space + bind_name = binding.split()[0] #first part, up to first space if self.are_keys_builtin.get(): current_key_set_name = self.builtin_keys.get() else: current_key_set_name = self.custom_keys.get() current_bindings = idleConf.GetCurrentKeySet() - if current_key_set_name in self.changed_items['keys']: # unsaved changes + if current_key_set_name in self.changed_items['keys']: #unsaved changes key_set_changes = self.changed_items['keys'][current_key_set_name] for event in key_set_changes: current_bindings[event] = key_set_changes[event].split() current_key_sequences = list(current_bindings.values()) new_keys = GetKeysDialog(self, 'Get New Keys', bind_name, - current_key_sequences).result - if new_keys: # new keys were specified - if self.are_keys_builtin.get(): # current key set is a built-in + current_key_sequences).result + if new_keys: #new keys were specified + if self.are_keys_builtin.get(): #current key set is a built-in message = ('Your changes will be saved as a new Custom Key Set.' ' Enter a name for your new Custom Key Set below.') - new_key_set = self.get_new_keys_name(message) - if not new_key_set: # user cancelled custom key set creation + new_keyset = self.get_new_keys_name(message) + if not new_keyset: #user cancelled custom key set creation self.list_bindings.select_set(list_index) self.list_bindings.select_anchor(list_index) return - else: # create new custom key set based on previously active key set - self.create_new_key_set(new_key_set) + else: #create new custom key set based on previously active key set + self.create_new_key_set(new_keyset) self.list_bindings.delete(list_index) - self.list_bindings.insert(list_index, bind_name + ' - ' + new_keys) + self.list_bindings.insert(list_index, bind_name+' - '+new_keys) self.list_bindings.select_set(list_index) self.list_bindings.select_anchor(list_index) self.keybinding.set(new_keys) @@ -795,104 +704,84 @@ def get_new_keys(self): self.list_bindings.select_anchor(list_index) def get_new_keys_name(self, message): - "Return new key set name from query popup." used_names = (idleConf.GetSectionList('user', 'keys') + - idleConf.GetSectionList('default', 'keys')) - new_key_set = SectionName( + idleConf.GetSectionList('default', 'keys')) + new_keyset = SectionName( self, 'New Custom Key Set', message, used_names).result - return new_key_set + return new_keyset def save_as_new_key_set(self): - "Prompt for name of new key set and save changes using that name." new_keys_name = self.get_new_keys_name('New Key Set Name:') if new_keys_name: self.create_new_key_set(new_keys_name) def keybinding_selected(self, event): - "Activate button to assign new keys to selected action." self.button_new_keys.config(state=NORMAL) def create_new_key_set(self, new_key_set_name): - """Create a new custom key set with the given name. - - Create the new key set based on the previously active set - with the current changes applied. Once it is saved, then - activate the new key set. - """ - # creates new custom key set based on the previously active key set, - # and makes the new key set active + #creates new custom key set based on the previously active key set, + #and makes the new key set active if self.are_keys_builtin.get(): prev_key_set_name = self.builtin_keys.get() else: prev_key_set_name = self.custom_keys.get() prev_keys = idleConf.GetCoreKeys(prev_key_set_name) new_keys = {} - for event in prev_keys: # add key set to changed items - event_name = event[2:-2] # trim off the angle brackets + for event in prev_keys: #add key set to changed items + event_name = event[2:-2] #trim off the angle brackets binding = ' '.join(prev_keys[event]) new_keys[event_name] = binding - # handle any unsaved changes to prev key set + #handle any unsaved changes to prev key set if prev_key_set_name in self.changed_items['keys']: key_set_changes = self.changed_items['keys'][prev_key_set_name] for event in key_set_changes: new_keys[event] = key_set_changes[event] - # save the new theme + #save the new theme self.save_new_key_set(new_key_set_name, new_keys) - # change gui over to the new key set + #change gui over to the new key set custom_key_list = idleConf.GetSectionList('user', 'keys') custom_key_list.sort() self.opt_menu_keys_custom.SetMenu(custom_key_list, new_key_set_name) self.are_keys_builtin.set(0) self.set_keys_type() - def load_keys_list(self, key_set_name): - """Load the list of action/key binding pairs for the active key set. - - An action/key binding can be selected to change the key binding. - """ + def load_keys_list(self, keyset_name): reselect = 0 - # new_key_set = 0 + new_keyset = 0 if self.list_bindings.curselection(): reselect = 1 list_index = self.list_bindings.index(ANCHOR) - key_set = idleConf.GetKeySet(key_set_name) - bind_names = list(key_set.keys()) + keyset = idleConf.GetKeySet(keyset_name) + bind_names = list(keyset.keys()) bind_names.sort() self.list_bindings.delete(0, END) for bind_name in bind_names: - key = ' '.join(key_set[bind_name]) # make key(s) into a string - bind_name = bind_name[2:-2] # trim off the angle brackets - if key_set_name in self.changed_items['keys']: - # handle any unsaved changes to this key set - if bind_name in self.changed_items['keys'][key_set_name]: - key = self.changed_items['keys'][key_set_name][bind_name] - self.list_bindings.insert(END, bind_name + ' - ' + key) + key = ' '.join(keyset[bind_name]) #make key(s) into a string + bind_name = bind_name[2:-2] #trim off the angle brackets + if keyset_name in self.changed_items['keys']: + #handle any unsaved changes to this key set + if bind_name in self.changed_items['keys'][keyset_name]: + key = self.changed_items['keys'][keyset_name][bind_name] + self.list_bindings.insert(END, bind_name+' - '+key) if reselect: self.list_bindings.see(list_index) self.list_bindings.select_set(list_index) self.list_bindings.select_anchor(list_index) def delete_custom_keys(self): - """Handle event to delete a custom key set. - - Applying the delete deactivates the current configuration and - reverts to the default. The custom key set is permanently - deleted from the config file. - """ - - key_set_name = self.custom_keys.get() + keyset_name=self.custom_keys.get() delmsg = 'Are you sure you wish to delete the key set %r ?' if not tkMessageBox.askyesno( - 'Delete Key Set', delmsg % key_set_name, parent=self): + 'Delete Key Set', delmsg % keyset_name, parent=self): return self.deactivate_current_config() - # remove key set from config - idleConf.userCfg['keys'].remove_section(key_set_name) - if key_set_name in self.changed_items['keys']: - del(self.changed_items['keys'][key_set_name]) - # write changes + #remove key set from config + idleConf.userCfg['keys'].remove_section(keyset_name) + if keyset_name in self.changed_items['keys']: + del(self.changed_items['keys'][keyset_name]) + #write changes idleConf.userCfg['keys'].Save() - # reload user key set list + #reload user key set list item_list = idleConf.GetSectionList('user', 'keys') item_list.sort() if not item_list: @@ -900,36 +789,30 @@ def delete_custom_keys(self): self.opt_menu_keys_custom.SetMenu(item_list, '- no custom keys -') else: self.opt_menu_keys_custom.SetMenu(item_list, item_list[0]) - # revert to default key set + #revert to default key set self.are_keys_builtin.set(idleConf.defaultCfg['main'] - .Get('Keys', 'default')) + .Get('Keys', 'default')) self.builtin_keys.set(idleConf.defaultCfg['main'].Get('Keys', 'name') - or idleConf.default_keys()) - # user can't back out of these changes, they must be applied now + or idleConf.default_keys()) + #user can't back out of these changes, they must be applied now self.save_all_changed_configs() self.activate_config_changes() self.set_keys_type() def delete_custom_theme(self): - """Handle event to delete custom theme. - - The current theme is deactivated and the default theme is - activated. The custom theme is permanently removed from - the config file. - """ theme_name = self.custom_theme.get() delmsg = 'Are you sure you wish to delete the theme %r ?' if not tkMessageBox.askyesno( 'Delete Theme', delmsg % theme_name, parent=self): return self.deactivate_current_config() - # remove theme from config + #remove theme from config idleConf.userCfg['highlight'].remove_section(theme_name) if theme_name in self.changed_items['highlight']: del(self.changed_items['highlight'][theme_name]) - # write changes + #write changes idleConf.userCfg['highlight'].Save() - # reload user theme list + #reload user theme list item_list = idleConf.GetSectionList('user', 'highlight') item_list.sort() if not item_list: @@ -937,74 +820,59 @@ def delete_custom_theme(self): self.opt_menu_theme_custom.SetMenu(item_list, '- no custom themes -') else: self.opt_menu_theme_custom.SetMenu(item_list, item_list[0]) - # revert to default theme + #revert to default theme self.is_builtin_theme.set(idleConf.defaultCfg['main'].Get('Theme', 'default')) self.builtin_theme.set(idleConf.defaultCfg['main'].Get('Theme', 'name')) - # user can't back out of these changes, they must be applied now + #user can't back out of these changes, they must be applied now self.save_all_changed_configs() self.activate_config_changes() self.set_theme_type() - def get_color(self): - """Handle button to select a new color for the target tag. - - If a new color is selected while using a builtin theme, a - name must be supplied to create a custom theme. - """ + def get_colour(self): target = self.highlight_target.get() - prev_color = self.frame_color_set.cget('bg') - rgb_tuplet, color_string = tkColorChooser.askcolor( - parent=self, title='Pick new color for : ' + target, - initialcolor=prev_color) - if color_string and (color_string != prev_color): - # user didn't cancel, and they chose a new color - if self.is_builtin_theme.get(): # current theme is a built-in + prev_colour = self.frame_colour_set.cget('bg') + rgbTuplet, colour_string = tkColorChooser.askcolor( + parent=self, title='Pick new colour for : '+target, + initialcolor=prev_colour) + if colour_string and (colour_string != prev_colour): + #user didn't cancel, and they chose a new colour + if self.is_builtin_theme.get(): #current theme is a built-in message = ('Your changes will be saved as a new Custom Theme. ' 'Enter a name for your new Custom Theme below.') new_theme = self.get_new_theme_name(message) - if not new_theme: # user cancelled custom theme creation + if not new_theme: #user cancelled custom theme creation return - else: # create new custom theme based on previously active theme + else: #create new custom theme based on previously active theme self.create_new_theme(new_theme) - self.color.set(color_string) - else: # current theme is user defined - self.color.set(color_string) - - def on_new_color_set(self): - "Handle a color change by displaying sample of it on the dialog." - new_color = self.color.get() - self.frame_color_set.config(bg=new_color) # set sample - plane = 'foreground' if self.fg_bg_toggle.get() else 'background' + self.colour.set(colour_string) + else: #current theme is user defined + self.colour.set(colour_string) + + def on_new_colour_set(self): + new_colour=self.colour.get() + self.frame_colour_set.config(bg=new_colour) #set sample + plane ='foreground' if self.fg_bg_toggle.get() else 'background' sample_element = self.theme_elements[self.highlight_target.get()][0] - self.text_highlight_sample.tag_config(sample_element, **{plane:new_color}) + self.text_highlight_sample.tag_config(sample_element, **{plane:new_colour}) theme = self.custom_theme.get() theme_element = sample_element + '-' + plane - self.add_changed_item('highlight', theme, theme_element, new_color) + self.add_changed_item('highlight', theme, theme_element, new_colour) def get_new_theme_name(self, message): - "Return name of new theme from query popup." used_names = (idleConf.GetSectionList('user', 'highlight') + - idleConf.GetSectionList('default', 'highlight')) + idleConf.GetSectionList('default', 'highlight')) new_theme = SectionName( self, 'New Custom Theme', message, used_names).result return new_theme def save_as_new_theme(self): - "Prompt for new theme name and create the theme." new_theme_name = self.get_new_theme_name('New Theme Name:') if new_theme_name: self.create_new_theme(new_theme_name) def create_new_theme(self, new_theme_name): - """Create a new custom theme with the given name. - - Create the new theme based on the previously active theme - with the current changes applied. Once it is saved, then - activate the new theme. - """ - - # creates new custom theme based on the previously active theme, - # and makes the new theme active + #creates new custom theme based on the previously active theme, + #and makes the new theme active if self.is_builtin_theme.get(): theme_type = 'default' theme_name = self.builtin_theme.get() @@ -1012,14 +880,14 @@ def create_new_theme(self, new_theme_name): theme_type = 'user' theme_name = self.custom_theme.get() new_theme = idleConf.GetThemeDict(theme_type, theme_name) - # apply any of the old theme's unsaved changes to the new theme + #apply any of the old theme's unsaved changes to the new theme if theme_name in self.changed_items['highlight']: theme_changes = self.changed_items['highlight'][theme_name] for element in theme_changes: new_theme[element] = theme_changes[element] - # save the new theme + #save the new theme self.save_new_theme(new_theme_name, new_theme) - # change gui over to the new theme + #change gui over to the new theme custom_theme_list = idleConf.GetSectionList('user', 'highlight') custom_theme_list.sort() self.opt_menu_theme_custom.SetMenu(custom_theme_list, new_theme_name) @@ -1027,17 +895,11 @@ def create_new_theme(self, new_theme_name): self.set_theme_type() def on_list_fonts_button_release(self, event): - """Handle event of selecting a font from the list. - - Change the font name to the font selected from the list - and update sample text to show that font. - """ font = self.list_fonts.get(ANCHOR) self.font_name.set(font.lower()) self.set_font_sample() def set_font_sample(self, event=None): - "Update the screen samples with the font settings from the dialog." font_name = self.font_name.get() font_weight = tkFont.BOLD if self.font_bold.get() else tkFont.NORMAL new_font = (font_name, self.font_size.get(), font_weight) @@ -1045,75 +907,65 @@ def set_font_sample(self, event=None): self.text_highlight_sample.configure(font=new_font) def set_highlight_target(self): - "Set fg/bg toggle and color based on highlight target." - if self.highlight_target.get() == 'Cursor': # bg not possible + if self.highlight_target.get() == 'Cursor': #bg not possible self.radio_fg.config(state=DISABLED) self.radio_bg.config(state=DISABLED) self.fg_bg_toggle.set(1) - else: # both fg and bg can be set + else: #both fg and bg can be set self.radio_fg.config(state=NORMAL) self.radio_bg.config(state=NORMAL) self.fg_bg_toggle.set(1) - self.set_color_sample() + self.set_colour_sample() - def set_color_sample_binding(self, *args): - "Change color based on foreground/background toggle." - self.set_color_sample() + def set_colour_sample_binding(self, *args): + self.set_colour_sample() - def set_color_sample(self): - "Set the color of the frame background to reflect the selected target." - # set the color sample area + def set_colour_sample(self): + #set the colour smaple area tag = self.theme_elements[self.highlight_target.get()][0] plane = 'foreground' if self.fg_bg_toggle.get() else 'background' - color = self.text_highlight_sample.tag_cget(tag, plane) - self.frame_color_set.config(bg=color) + colour = self.text_highlight_sample.tag_cget(tag, plane) + self.frame_colour_set.config(bg=colour) def paint_theme_sample(self): - "Apply the theme colors to each element tag in the sample text." - if self.is_builtin_theme.get(): # a default theme + if self.is_builtin_theme.get(): #a default theme theme = self.builtin_theme.get() - else: # a user theme + else: #a user theme theme = self.custom_theme.get() for element_title in self.theme_elements: element = self.theme_elements[element_title][0] - colors = idleConf.GetHighlight(theme, element) - if element == 'cursor': # cursor sample needs special painting - colors['background'] = idleConf.GetHighlight( + colours = idleConf.GetHighlight(theme, element) + if element == 'cursor': #cursor sample needs special painting + colours['background'] = idleConf.GetHighlight( theme, 'normal', fgBg='bg') - # handle any unsaved changes to this theme + #handle any unsaved changes to this theme if theme in self.changed_items['highlight']: theme_dict = self.changed_items['highlight'][theme] if element + '-foreground' in theme_dict: - colors['foreground'] = theme_dict[element + '-foreground'] + colours['foreground'] = theme_dict[element + '-foreground'] if element + '-background' in theme_dict: - colors['background'] = theme_dict[element + '-background'] - self.text_highlight_sample.tag_config(element, **colors) - self.set_color_sample() + colours['background'] = theme_dict[element + '-background'] + self.text_highlight_sample.tag_config(element, **colours) + self.set_colour_sample() def help_source_selected(self, event): - "Handle event for selecting additional help." self.set_helplist_button_states() def set_helplist_button_states(self): - "Toggle the state for the help list buttons." - if self.list_help.size() < 1: # no entries in list + if self.list_help.size() < 1: #no entries in list self.button_helplist_edit.config(state=DISABLED) self.button_helplist_remove.config(state=DISABLED) - else: # there are some entries - if self.list_help.curselection(): # there currently is a selection + else: #there are some entries + if self.list_help.curselection(): #there currently is a selection self.button_helplist_edit.config(state=NORMAL) self.button_helplist_remove.config(state=NORMAL) - else: # there currently is not a selection + else: #there currently is not a selection self.button_helplist_edit.config(state=DISABLED) self.button_helplist_remove.config(state=DISABLED) def helplist_item_add(self): - """Handle add button for help list. - - Query for name and location of new help sources and add - them to the list. - """ - help_source = HelpSource(self, 'New Help Source',).result + help_source = HelpSource(self, 'New Help Source', + ).result if help_source: self.user_helplist.append((help_source[0], help_source[1])) self.list_help.insert(END, help_source[0]) @@ -1121,11 +973,6 @@ def helplist_item_add(self): self.set_helplist_button_states() def helplist_item_edit(self): - """Handle edit button for help list. - - Query with existing help source information and update - config if the values are changed. - """ item_index = self.list_help.index(ANCHOR) help_source = self.user_helplist[item_index] new_help_source = HelpSource( @@ -1141,10 +988,6 @@ def helplist_item_edit(self): self.set_helplist_button_states() def helplist_item_remove(self): - """Handle remove button for help list. - - Delete the help list item from config. - """ item_index = self.list_help.index(ANCHOR) del(self.user_helplist[item_index]) self.list_help.delete(item_index) @@ -1152,7 +995,7 @@ def helplist_item_remove(self): self.set_helplist_button_states() def update_user_help_changed_items(self): - "Clear and rebuild the HelpFiles section in self.changed_items." + "Clear and rebuild the HelpFiles section in self.changed_items" self.changed_items['main']['HelpFiles'] = {} for num in range(1, len(self.user_helplist) + 1): self.add_changed_item( @@ -1160,16 +1003,15 @@ def update_user_help_changed_items(self): ';'.join(self.user_helplist[num-1][:2])) def load_font_cfg(self): - "Load current configuration settings for the font options." - # base editor font selection list + ##base editor font selection list fonts = list(tkFont.families(self)) fonts.sort() for font in fonts: self.list_fonts.insert(END, font) - configuredFont = idleConf.GetFont(self, 'main', 'EditorWindow') - font_name = configuredFont[0].lower() - font_size = configuredFont[1] - font_bold = configuredFont[2] == 'bold' + configured_font = idleConf.GetFont(self, 'main', 'EditorWindow') + font_name = configured_font[0].lower() + font_size = configured_font[1] + font_bold = configured_font[2]=='bold' self.font_name.set(font_name) lc_fonts = [s.lower() for s in fonts] try: @@ -1179,31 +1021,29 @@ def load_font_cfg(self): self.list_fonts.select_anchor(current_font_index) except ValueError: pass - # font size dropdown + ##font size dropdown self.opt_menu_font_size.SetMenu(('7', '8', '9', '10', '11', '12', '13', - '14', '16', '18', '20', '22', - '25', '29', '34', '40'), font_size) - # fontWeight + '14', '16', '18', '20', '22', + '25', '29', '34', '40'), font_size ) + ##font_weight self.font_bold.set(font_bold) - # font sample + ##font sample self.set_font_sample() def load_tab_cfg(self): - "Load current configuration settings for the tab options." - # indent sizes + ##indent sizes space_num = idleConf.GetOption( 'main', 'Indent', 'num-spaces', default=4, type='int') self.space_num.set(space_num) def load_theme_cfg(self): - "Load current configuration settings for the theme options." - # current theme type radiobutton + ##current theme type radiobutton self.is_builtin_theme.set(idleConf.GetOption( 'main', 'Theme', 'default', type='bool', default=1)) - # currently set theme + ##currently set theme current_option = idleConf.CurrentTheme() - # load available theme option menus - if self.is_builtin_theme.get(): # default theme selected + ##load available theme option menus + if self.is_builtin_theme.get(): #default theme selected item_list = idleConf.GetSectionList('default', 'highlight') item_list.sort() self.opt_menu_theme_builtin.SetMenu(item_list, current_option) @@ -1214,7 +1054,7 @@ def load_theme_cfg(self): self.custom_theme.set('- no custom themes -') else: self.opt_menu_theme_custom.SetMenu(item_list, item_list[0]) - else: # user theme selected + else: #user theme selected item_list = idleConf.GetSectionList('user', 'highlight') item_list.sort() self.opt_menu_theme_custom.SetMenu(item_list, current_option) @@ -1222,7 +1062,7 @@ def load_theme_cfg(self): item_list.sort() self.opt_menu_theme_builtin.SetMenu(item_list, item_list[0]) self.set_theme_type() - # load theme element option menu + ##load theme element option menu theme_names = list(self.theme_elements.keys()) theme_names.sort(key=lambda x: self.theme_elements[x][1]) self.opt_menu_highlight_target.SetMenu(theme_names, theme_names[0]) @@ -1230,14 +1070,13 @@ def load_theme_cfg(self): self.set_highlight_target() def load_key_cfg(self): - "Load current configuration settings for the keybinding options." - # current keys type radiobutton + ##current keys type radiobutton self.are_keys_builtin.set(idleConf.GetOption( 'main', 'Keys', 'default', type='bool', default=1)) - # currently set keys + ##currently set keys current_option = idleConf.CurrentKeys() - # load available keyset option menus - if self.are_keys_builtin.get(): # default theme selected + ##load available keyset option menus + if self.are_keys_builtin.get(): #default theme selected item_list = idleConf.GetSectionList('default', 'keys') item_list.sort() self.opt_menu_keys_builtin.SetMenu(item_list, current_option) @@ -1248,7 +1087,7 @@ def load_key_cfg(self): self.custom_keys.set('- no custom keys -') else: self.opt_menu_keys_custom.SetMenu(item_list, item_list[0]) - else: # user key set selected + else: #user key set selected item_list = idleConf.GetSectionList('user', 'keys') item_list.sort() self.opt_menu_keys_custom.SetMenu(item_list, current_option) @@ -1256,19 +1095,18 @@ def load_key_cfg(self): item_list.sort() self.opt_menu_keys_builtin.SetMenu(item_list, idleConf.default_keys()) self.set_keys_type() - # load keyset element list - key_set_name = idleConf.CurrentKeys() - self.load_keys_list(key_set_name) + ##load keyset element list + keyset_name = idleConf.CurrentKeys() + self.load_keys_list(keyset_name) def load_general_cfg(self): - "Load current configuration settings for the general options." - # startup state + #startup state self.startup_edit.set(idleConf.GetOption( 'main', 'General', 'editor-on-startup', default=1, type='bool')) - # autosave state + #autosave state self.autosave.set(idleConf.GetOption( 'main', 'General', 'autosave', default=0, type='bool')) - # initial window size + #initial window size self.win_width.set(idleConf.GetOption( 'main', 'EditorWindow', 'width', type='int')) self.win_height.set(idleConf.GetOption( @@ -1283,37 +1121,36 @@ def load_general_cfg(self): self.set_helplist_button_states() def load_configs(self): - """Load configuration for each page. - - Load configuration from default and user config files and populate + """ + load configuration from default and user config files and populate the widgets on the config dialog pages. """ - # fonts/tabs page + ### fonts / tabs page self.load_font_cfg() self.load_tab_cfg() - # highlighting page + ### highlighting page self.load_theme_cfg() - # keys page + ### keys page self.load_key_cfg() - # general page + ### general page self.load_general_cfg() # note: extension page handled separately - def save_new_key_set(self, key_set_name, key_set): - """Save a newly created custom key set. - - key_set_name - string, the name of the new key set - key_set - dictionary containing the new key set + def save_new_key_set(self, keyset_name, keyset): + """ + save a newly created core key set. + keyset_name - string, the name of the new key set + keyset - dictionary containing the new key set """ - if not idleConf.userCfg['keys'].has_section(key_set_name): - idleConf.userCfg['keys'].add_section(key_set_name) - for event in key_set: - value = key_set[event] - idleConf.userCfg['keys'].SetOption(key_set_name, event, value) + if not idleConf.userCfg['keys'].has_section(keyset_name): + idleConf.userCfg['keys'].add_section(keyset_name) + for event in keyset: + value = keyset[event] + idleConf.userCfg['keys'].SetOption(keyset_name, event, value) def save_new_theme(self, theme_name, theme): - """Save a newly created custom theme. - + """ + save a newly created theme. theme_name - string, the name of the new theme theme - dictionary containing the new theme """ @@ -1324,22 +1161,21 @@ def save_new_theme(self, theme_name, theme): idleConf.userCfg['highlight'].SetOption(theme_name, element, value) def set_user_value(self, config_type, section, item, value): - "Return True if configuration value added or changed." if idleConf.defaultCfg[config_type].has_option(section, item): if idleConf.defaultCfg[config_type].Get(section, item) == value: - # the setting equals a default setting, remove it from user cfg + #the setting equals a default setting, remove it from user cfg return idleConf.userCfg[config_type].RemoveOption(section, item) - # if we got here set the option + #if we got here set the option return idleConf.userCfg[config_type].SetOption(section, item, value) def save_all_changed_configs(self): - "Save all configuration changes to the user config file." + "Save configuration changes to the user config file." idleConf.userCfg['main'].Save() for config_type in self.changed_items: cfg_type_changed = False for section in self.changed_items[config_type]: if section == 'HelpFiles': - # this section gets completely replaced + #this section gets completely replaced idleConf.userCfg['main'].remove_section('HelpFiles') cfg_type_changed = True for item in self.changed_items[config_type][section]: @@ -1351,13 +1187,12 @@ def save_all_changed_configs(self): for config_type in ['keys', 'highlight']: # save these even if unchanged! idleConf.userCfg[config_type].Save() - self.reset_changed_items() # clear the changed items dict + self.reset_changed_items() #clear the changed items dict self.save_all_changed_extensions() # uses a different mechanism def deactivate_current_config(self): - "Remove current key bindings." - # Before a config is saved, some cleanup of current - # config must be done - remove the previous keybindings + #Before a config is saved, some cleanup of current + #config must be done - remove the previous keybindings win_instances = self.parent.instance_dict.keys() for instance in win_instances: instance.RemoveKeybindings() @@ -1373,25 +1208,21 @@ def activate_config_changes(self): instance.reset_help_menu_entries() def cancel(self): - "Dismiss config dialog." self.destroy() def ok(self): - "Apply config changes, then dismiss dialog." self.apply() self.destroy() def apply(self): - "Apply config changes and leave dialog open." self.deactivate_current_config() self.save_all_changed_configs() self.activate_config_changes() def help(self): - "Create textview for config dialog help." page = self.tab_pages._current_page view_text(self, title='Help for IDLE preferences', - text=help_common + help_pages.get(page, '')) + text=help_common+help_pages.get(page, '')) def create_page_extensions(self): """Part of the config dialog used for configuring IDLE extensions. @@ -1403,8 +1234,8 @@ def create_page_extensions(self): GUI interface to change the configuration values, and saves the changes using idleConf. - Not all changes take effect immediately - some may require restarting - IDLE. This depends on each extension's implementation. + Not all changes take effect immediately - some may require restarting IDLE. + This depends on each extension's implementation. All values are treated as text, and it is up to the user to supply reasonable values. The only exception to this are the 'enable*' options, @@ -1425,7 +1256,7 @@ def create_page_extensions(self): selectmode='browse') self.extension_list.bind('<>', self.extension_selected) scroll = Scrollbar(frame, command=self.extension_list.yview) - self.extension_list.yscrollcommand = scroll.set + self.extension_list.yscrollcommand=scroll.set self.details_frame = LabelFrame(frame, width=250, height=250) self.extension_list.grid(column=0, row=0, sticky='nws') scroll.grid(column=1, row=0, sticky='ns') @@ -1466,7 +1297,7 @@ def load_extensions(self): def_str = self.ext_defaultCfg.Get( ext_name, opt_name, raw=True) try: - def_obj = {'True': True, 'False': False}[def_str] + def_obj = {'True':True, 'False':False}[def_str] opt_type = 'bool' except KeyError: try: @@ -1492,7 +1323,6 @@ def load_extensions(self): }) def extension_selected(self, event): - "Handle selection of an extension from the list." newsel = self.extension_list.curselection() if newsel: newsel = self.extension_list.get(newsel) @@ -1507,7 +1337,7 @@ def extension_selected(self, event): self.current_extension = newsel def create_extension_frame(self, ext_name): - """Create a frame holding the widgets to configure one extension.""" + """Create a frame holding the widgets to configure one extension""" f = VerticalScrolledFrame(self.details_frame, height=250, width=250) self.config_frame[ext_name] = f entry_area = f.interior @@ -1520,7 +1350,7 @@ def create_extension_frame(self, ext_name): if opt['type'] == 'bool': Checkbutton(entry_area, textvariable=var, variable=var, onvalue='True', offvalue='False', - indicatoron=False, selectcolor='', width=8 + indicatoron=FALSE, selectcolor='', width=8 ).grid(row=row, column=1, sticky=W, padx=7) elif opt['type'] == 'int': Entry(entry_area, textvariable=var, validate='key', @@ -1533,11 +1363,6 @@ def create_extension_frame(self, ext_name): return def set_extension_value(self, section, opt): - """Return True if configuration added or changed. - - If the value is the same as the default, then remove it - from user config file. - """ name = opt['name'] default = opt['default'] value = opt['var'].get().strip() or default @@ -1608,10 +1433,10 @@ def __init__(self, parent, *args, **kw): # create a canvas object and a vertical scrollbar for scrolling it vscrollbar = Scrollbar(self, orient=VERTICAL) - vscrollbar.pack(fill=Y, side=RIGHT, expand=False) + vscrollbar.pack(fill=Y, side=RIGHT, expand=FALSE) canvas = Canvas(self, bd=0, highlightthickness=0, yscrollcommand=vscrollbar.set, width=240) - canvas.pack(side=LEFT, fill=BOTH, expand=True) + canvas.pack(side=LEFT, fill=BOTH, expand=TRUE) vscrollbar.config(command=canvas.yview) # reset the view diff --git a/Lib/idlelib/idle_test/test_configdialog.py b/Lib/idlelib/idle_test/test_configdialog.py index 3dadfa27a2885a..4946f02306a786 100644 --- a/Lib/idlelib/idle_test/test_configdialog.py +++ b/Lib/idlelib/idle_test/test_configdialog.py @@ -21,14 +21,19 @@ 'extensions': config.IdleUserConfParser(''), } -# ConfigDialog.changedItems is a 3-level hierarchical dictionary of +# ConfigDialog.changed_items is a 3-level hierarchical dictionary of # pending changes that mirrors the multilevel user config dict. # For testing, record args in a list for comparison with expected. changes = [] +root = None +configure = None + + class TestDialog(ConfigDialog): def add_changed_item(self, *args): changes.append(args) + def setUpModule(): global root, configure idleConf.userCfg = testcfg @@ -49,34 +54,33 @@ def tearDownModule(): class FontTabTest(unittest.TestCase): - def setUp(self): changes.clear() def test_font(self): # Set values guaranteed not to be defaults. - dfont = idleConf.GetFont(root, 'main', 'EditorWindow') - dsize = str(dfont[1]) - dbold = dfont[2] == 'bold' + default_font = idleConf.GetFont(root, 'main', 'EditorWindow') + default_size = str(default_font[1]) + default_bold = default_font[2] == 'bold' configure.font_name.set('Test Font') expected = [ ('main', 'EditorWindow', 'font', 'Test Font'), - ('main', 'EditorWindow', 'font-size', dsize), - ('main', 'EditorWindow', 'font-bold', dbold)] + ('main', 'EditorWindow', 'font-size', default_size), + ('main', 'EditorWindow', 'font-bold', default_bold)] self.assertEqual(changes, expected) changes.clear() configure.font_size.set(20) expected = [ ('main', 'EditorWindow', 'font', 'Test Font'), ('main', 'EditorWindow', 'font-size', '20'), - ('main', 'EditorWindow', 'font-bold', dbold)] + ('main', 'EditorWindow', 'font-bold', default_bold)] self.assertEqual(changes, expected) changes.clear() - configure.font_bold.set(not dbold) + configure.font_bold.set(not default_bold) expected = [ ('main', 'EditorWindow', 'font', 'Test Font'), ('main', 'EditorWindow', 'font-size', '20'), - ('main', 'EditorWindow', 'font-bold', not dbold)] + ('main', 'EditorWindow', 'font-bold', not default_bold)] self.assertEqual(changes, expected) #def test_sample(self): pass # TODO From c6d5ec4150d54a28a6550c96f912ee40a19b2ad0 Mon Sep 17 00:00:00 2001 From: Terry Jan Reedy Date: Mon, 26 Jun 2017 15:47:39 -0400 Subject: [PATCH 4/5] Add news entry --- Misc/NEWS.d/next/IDLE/2017-06-26-15-47-13.bpo-30728.qH4TGL.rst | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 Misc/NEWS.d/next/IDLE/2017-06-26-15-47-13.bpo-30728.qH4TGL.rst diff --git a/Misc/NEWS.d/next/IDLE/2017-06-26-15-47-13.bpo-30728.qH4TGL.rst b/Misc/NEWS.d/next/IDLE/2017-06-26-15-47-13.bpo-30728.qH4TGL.rst new file mode 100644 index 00000000000000..5fc8516aad951e --- /dev/null +++ b/Misc/NEWS.d/next/IDLE/2017-06-26-15-47-13.bpo-30728.qH4TGL.rst @@ -0,0 +1,2 @@ +Modernize idlelib.configdialog: * replace import * with specific imports; * +lowercase method and attribute lines. Patch by Cheryl Sabella. From 01aa47de898301d62b663404b08f107d105de517 Mon Sep 17 00:00:00 2001 From: terryjreedy Date: Mon, 26 Jun 2017 16:52:00 -0400 Subject: [PATCH 5/5] Update 2017-06-26-15-47-13.bpo-30728.qH4TGL.rst --- .../next/IDLE/2017-06-26-15-47-13.bpo-30728.qH4TGL.rst | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Misc/NEWS.d/next/IDLE/2017-06-26-15-47-13.bpo-30728.qH4TGL.rst b/Misc/NEWS.d/next/IDLE/2017-06-26-15-47-13.bpo-30728.qH4TGL.rst index 5fc8516aad951e..014eff369de735 100644 --- a/Misc/NEWS.d/next/IDLE/2017-06-26-15-47-13.bpo-30728.qH4TGL.rst +++ b/Misc/NEWS.d/next/IDLE/2017-06-26-15-47-13.bpo-30728.qH4TGL.rst @@ -1,2 +1,4 @@ -Modernize idlelib.configdialog: * replace import * with specific imports; * -lowercase method and attribute lines. Patch by Cheryl Sabella. +Review and change idlelib.configdialog names. +Lowercase method and attribute names. +Replace 'colour' with 'color', expand overly cryptic names, delete unneeded underscores. +Replace ``import *`` with specific imports. Patches by Cheryl Sabella.