From 9890e119404440576a1aee3ecd6538d84330cf21 Mon Sep 17 00:00:00 2001 From: Cheryl Sabella Date: Fri, 18 Aug 2017 21:18:36 -0400 Subject: [PATCH 1/5] bpo-31206: IDLE: Factor HighPage class from ConfigDialog --- Lib/idlelib/configdialog.py | 1465 ++++++++++---------- Lib/idlelib/idle_test/test_configdialog.py | 56 +- 2 files changed, 750 insertions(+), 771 deletions(-) diff --git a/Lib/idlelib/configdialog.py b/Lib/idlelib/configdialog.py index 587f16ec9df4433..5e328812443c90e 100644 --- a/Lib/idlelib/configdialog.py +++ b/Lib/idlelib/configdialog.py @@ -75,8 +75,7 @@ def __init__(self, parent, title='', _htest=False, _utest=False): # self.bind('', self.Cancel) #dismiss dialog, no save # self.bind('', self.Apply) #apply changes, save # self.bind('', self.Help) #context help - self.load_configs() - # Avoid callbacks during load_configs. + # Attach callbacks after loading config to avoid calling them. tracers.attach() if not _utest: @@ -84,777 +83,756 @@ def __init__(self, parent, title='', _htest=False, _utest=False): self.wm_deiconify() self.wait_window() - def create_widgets(self): """Create and place widgets for tabbed dialog. Widgets Bound to self: note: Notebook - highpage: self.create_page_highlight + highpage: HighPage fontpage: FontPage keyspage: KeysPage genpage: GenPage - extpage: self.create_page_extensions - - Methods: - create_action_buttons - load_configs: Load pages except for extensions. - activate_config_changes: Tell editors to reload. - """ - self.note = note = Notebook(self, width=450, height=450) - self.highpage = self.create_page_highlight() - self.fontpage = FontPage(note, self.highpage) - self.keyspage = KeysPage(note) - self.genpage = GenPage(note) - self.extpage = self.create_page_extensions() - note.add(self.fontpage, text='Fonts/Tabs') - note.add(self.highpage, text='Highlights') - note.add(self.keyspage, text=' Keys ') - note.add(self.genpage, text=' General ') - note.add(self.extpage, text='Extensions') - note.enable_traversal() - note.pack(side=TOP, expand=TRUE, fill=BOTH) - self.create_action_buttons().pack(side=BOTTOM) - - 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. - - Methods: - load_font_cfg - load_tab_cfg - load_theme_cfg - load_key_cfg - load_general_cfg - """ - #self.load_font_cfg() - #self.load_tab_cfg() - self.load_theme_cfg() - # self.load_key_cfg() - # self.load_general_cfg() - # note: extension page handled separately - - def create_action_buttons(self): - """Return frame of action buttons for dialog. - - Methods: - ok - apply - cancel - help - - Widget Structure: - outer: Frame - buttons: Frame - (no assignment): Button (ok) - (no assignment): Button (apply) - (no assignment): Button (cancel) - (no assignment): Button (help) - (no assignment): Frame - """ - 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} - 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, - **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 ok(self): - """Apply config changes, then dismiss dialog. - - Methods: - apply - destroy: inherited - """ - self.apply() - self.destroy() - - def apply(self): - """Apply config changes and leave dialog open. - - Methods: - deactivate_current_config - save_all_changed_extensions - activate_config_changes - """ - self.deactivate_current_config() - changes.save_all() - self.save_all_changed_extensions() - self.activate_config_changes() - - def cancel(self): - """Dismiss config dialog. - - Methods: - destroy: inherited - """ - self.destroy() - - def help(self): - """Create textview for config dialog help. - - Attrbutes accessed: - tab_pages - - Methods: - view_text: Method from textview module. - """ - page = self.tab_pages._current_page - view_text(self, title='Help for IDLE preferences', - text=help_common+help_pages.get(page, '')) - - - def create_page_highlight(self): - """Return frame of widgets for Highlighting tab. - - Enable users to provisionally change foreground and background - colors applied to textual tags. Color mappings are stored in - complete listings called themes. Built-in themes in - idlelib/config-highlight.def are fixed as far as the dialog is - concerned. Any theme can be used as the base for a new custom - theme, stored in .idlerc/config-highlight.cfg. - - Function load_theme_cfg() initializes tk variables and theme - lists and calls paint_theme_sample() and set_highlight_target() - for the current theme. Radiobuttons builtin_theme_on and - custom_theme_on toggle var theme_source, which controls if the - current set of colors are from a builtin or custom theme. - DynOptionMenus builtinlist and customlist contain lists of the - builtin and custom themes, respectively, and the current item - from each list is stored in vars builtin_name and custom_name. - - Function paint_theme_sample() applies the colors from the theme - to the tags in text widget highlight_sample and then invokes - set_color_sample(). Function set_highlight_target() sets the state - of the radiobuttons fg_on and bg_on based on the tag and it also - invokes set_color_sample(). - - Function set_color_sample() sets the background color for the frame - holding the color selector. This provides a larger visual of the - color for the current tag and plane (foreground/background). - - Note: set_color_sample() is called from many places and is often - called more than once when a change is made. It is invoked when - foreground or background is selected (radiobuttons), from - paint_theme_sample() (theme is changed or load_cfg is called), and - from set_highlight_target() (target tag is changed or load_cfg called). - - Button delete_custom invokes delete_custom() to delete - a custom theme from idleConf.userCfg['highlight'] and changes. - Button save_custom invokes save_as_new_theme() which calls - get_new_theme_name() and create_new() to save a custom theme - and its colors to idleConf.userCfg['highlight']. - - Radiobuttons fg_on and bg_on toggle var fg_bg_toggle to control - if the current selected color for a tag is for the foreground or - background. - - DynOptionMenu targetlist contains a readable description of the - tags applied to Python source within IDLE. Selecting one of the - tags from this list populates highlight_target, which has a callback - function set_highlight_target(). - - Text widget highlight_sample displays a block of text (which is - mock Python code) in which is embedded the defined tags and reflects - the color attributes of the current theme and changes for those tags. - Mouse button 1 allows for selection of a tag and updates - highlight_target with that tag value. - - Note: The font in highlight_sample is set through the config in - the fonts tab. - - In other words, a tag can be selected either from targetlist or - by clicking on the sample text within highlight_sample. The - plane (foreground/background) is selected via the radiobutton. - Together, these two (tag and plane) control what color is - shown in set_color_sample() for the current theme. Button set_color - invokes get_color() which displays a ColorChooser to change the - color for the selected tag/plane. If a new color is picked, - it will be saved to changes and the highlight_sample and - frame background will be updated. - - Tk Variables: - color: Color of selected target. - builtin_name: Menu variable for built-in theme. - custom_name: Menu variable for custom theme. - fg_bg_toggle: Toggle for foreground/background color. - Note: this has no callback. - theme_source: Selector for built-in or custom theme. - highlight_target: Menu variable for the highlight tag target. - - Instance Data Attributes: - theme_elements: Dictionary of tags for text highlighting. - The key is the display name and the value is a tuple of - (tag name, display sort order). - - Methods [attachment]: - load_theme_cfg: Load current highlight colors. - get_color: Invoke colorchooser [button_set_color]. - set_color_sample_binding: Call set_color_sample [fg_bg_toggle]. - set_highlight_target: set fg_bg_toggle, set_color_sample(). - set_color_sample: Set frame background to target. - on_new_color_set: Set new color and add option. - paint_theme_sample: Recolor sample. - get_new_theme_name: Get from popup. - create_new: Combine theme with changes and save. - save_as_new_theme: Save [button_save_custom]. - set_theme_type: Command for [theme_source]. - delete_custom: Activate default [button_delete_custom]. - save_new: Save to userCfg['theme'] (is function). - - Widgets of highlights page frame: (*) widgets bound to self - frame_custom: LabelFrame - (*)highlight_sample: Text - (*)frame_color_set: Frame - (*)button_set_color: Button - (*)targetlist: DynOptionMenu - highlight_target - frame_fg_bg_toggle: Frame - (*)fg_on: Radiobutton - fg_bg_toggle - (*)bg_on: Radiobutton - fg_bg_toggle - (*)button_save_custom: Button - frame_theme: LabelFrame - theme_type_title: Label - (*)builtin_theme_on: Radiobutton - theme_source - (*)custom_theme_on: Radiobutton - theme_source - (*)builtinlist: DynOptionMenu - builtin_name - (*)customlist: DynOptionMenu - custom_name - (*)button_delete_custom: Button - (*)theme_message: Label - """ - self.theme_elements={ - 'Normal Text': ('normal', '00'), - 'Python Keywords': ('keyword', '01'), - 'Python Definitions': ('definition', '02'), - 'Python Builtins': ('builtin', '03'), - 'Python Comments': ('comment', '04'), - 'Python Strings': ('string', '05'), - 'Selected Text': ('hilite', '06'), - 'Found Text': ('hit', '07'), - 'Cursor': ('cursor', '08'), - 'Editor Breakpoint': ('break', '09'), - 'Shell Normal Text': ('console', '10'), - 'Shell Error Text': ('error', '11'), - 'Shell Stdout Text': ('stdout', '12'), - 'Shell Stderr Text': ('stderr', '13'), - } - parent = self.parent - self.builtin_name = tracers.add( - StringVar(parent), self.var_changed_builtin_name) - self.custom_name = tracers.add( - StringVar(parent), self.var_changed_custom_name) - self.fg_bg_toggle = BooleanVar(parent) - self.color = tracers.add( - StringVar(parent), self.var_changed_color) - self.theme_source = tracers.add( - BooleanVar(parent), self.var_changed_theme_source) - self.highlight_target = tracers.add( - StringVar(parent), self.var_changed_highlight_target) - - # Create widgets: - # body frame and section frames. - frame = Frame(self.note) - frame_custom = LabelFrame(frame, borderwidth=2, relief=GROOVE, - text=' Custom Highlighting ') - frame_theme = LabelFrame(frame, borderwidth=2, relief=GROOVE, - text=' Highlighting Theme ') - # frame_custom. - text = self.highlight_sample = frame.highlight_sample = Text( - frame_custom, relief=SOLID, borderwidth=1, - font=('courier', 12, ''), cursor='hand2', width=21, height=13, - takefocus=FALSE, highlightthickness=0, wrap=NONE) - text.bind('', lambda e: 'break') - text.bind('', lambda e: 'break') - text_and_tags=(('\n', 'normal'), - ('#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'), - ("'string'", 'string'), ('\n var1 = ', 'normal'), - ("'selected'", 'hilite'), ('\n var2 = ', 'normal'), - ("'found'", 'hit'), ('\n var3 = ', 'normal'), - ('list', 'builtin'), ('(', 'normal'), - ('None', 'keyword'), (')\n', 'normal'), - (' breakpoint("line")', 'break'), ('\n\n', 'normal'), - (' error ', 'error'), (' ', 'normal'), - ('cursor |', 'cursor'), ('\n ', 'normal'), - ('shell', 'console'), (' ', 'normal'), - ('stdout', 'stdout'), (' ', 'normal'), - ('stderr', 'stderr'), ('\n\n', 'normal')) - 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['state'] = DISABLED - self.frame_color_set = Frame(frame_custom, relief=SOLID, borderwidth=1) - frame_fg_bg_toggle = Frame(frame_custom) - self.button_set_color = Button( - self.frame_color_set, text='Choose Color for :', - command=self.get_color, highlightthickness=0) - self.targetlist = DynOptionMenu( - self.frame_color_set, self.highlight_target, None, - highlightthickness=0) #, command=self.set_highlight_targetBinding - self.fg_on = Radiobutton( - frame_fg_bg_toggle, variable=self.fg_bg_toggle, value=1, - text='Foreground', command=self.set_color_sample_binding) - self.bg_on = 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) - self.button_save_custom = 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.builtin_theme_on = Radiobutton( - frame_theme, variable=self.theme_source, value=1, - command=self.set_theme_type, text='a Built-in Theme') - self.custom_theme_on = Radiobutton( - frame_theme, variable=self.theme_source, value=0, - command=self.set_theme_type, text='a Custom Theme') - self.builtinlist = DynOptionMenu( - frame_theme, self.builtin_name, None, command=None) - self.customlist = DynOptionMenu( - frame_theme, self.custom_name, None, command=None) - self.button_delete_custom = Button( - frame_theme, text='Delete Custom Theme', - command=self.delete_custom) - self.theme_message = Label(frame_theme, bd=2) - - # Pack widgets: - # 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.highlight_sample.pack( - side=TOP, padx=5, pady=5, expand=TRUE, fill=BOTH) - self.button_set_color.pack(side=TOP, expand=TRUE, fill=X, padx=8, pady=4) - self.targetlist.pack(side=TOP, expand=TRUE, fill=X, padx=8, pady=3) - self.fg_on.pack(side=LEFT, anchor=E) - self.bg_on.pack(side=RIGHT, anchor=W) - self.button_save_custom.pack(side=BOTTOM, fill=X, padx=5, pady=5) - # frame_theme. - theme_type_title.pack(side=TOP, anchor=W, padx=5, pady=5) - self.builtin_theme_on.pack(side=TOP, anchor=W, padx=5) - self.custom_theme_on.pack(side=TOP, anchor=W, padx=5, pady=2) - self.builtinlist.pack(side=TOP, fill=X, padx=5, pady=5) - self.customlist.pack(side=TOP, fill=X, anchor=W, padx=5, pady=5) - self.button_delete_custom.pack(side=TOP, fill=X, padx=5, pady=5) - self.theme_message.pack(side=TOP, fill=X, pady=5) - return frame - - def load_theme_cfg(self): - """Load current configuration settings for the theme options. - - Based on the theme_source toggle, the theme is set as - either builtin or custom and the initial widget values - reflect the current settings from idleConf. - - Attributes updated: - theme_source: Set from idleConf. - builtinlist: List of default themes from idleConf. - customlist: List of custom themes from idleConf. - custom_theme_on: Disabled if there are no custom themes. - custom_theme: Message with additional information. - targetlist: Create menu from self.theme_elements. - - Methods: - set_theme_type - paint_theme_sample - set_highlight_target - """ - # Set current theme type radiobutton. - self.theme_source.set(idleConf.GetOption( - 'main', 'Theme', 'default', type='bool', default=1)) - # Set current theme. - current_option = idleConf.CurrentTheme() - # Load available theme option menus. - if self.theme_source.get(): # Default theme selected. - item_list = idleConf.GetSectionList('default', 'highlight') - item_list.sort() - self.builtinlist.SetMenu(item_list, current_option) - item_list = idleConf.GetSectionList('user', 'highlight') - item_list.sort() - if not item_list: - self.custom_theme_on['state'] = DISABLED - self.custom_name.set('- no custom themes -') - else: - self.customlist.SetMenu(item_list, item_list[0]) - else: # User theme selected. - item_list = idleConf.GetSectionList('user', 'highlight') - item_list.sort() - self.customlist.SetMenu(item_list, current_option) - item_list = idleConf.GetSectionList('default', 'highlight') - item_list.sort() - self.builtinlist.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.targetlist.SetMenu(theme_names, theme_names[0]) - self.paint_theme_sample() - self.set_highlight_target() - - def var_changed_builtin_name(self, *params): - """Process new builtin theme selection. - - Add the changed theme's name to the changed_items and recreate - the sample with the values from the selected theme. - """ - old_themes = ('IDLE Classic', 'IDLE New') - value = self.builtin_name.get() - if value not in old_themes: - if idleConf.GetOption('main', 'Theme', 'name') not in old_themes: - changes.add_option('main', 'Theme', 'name', old_themes[0]) - changes.add_option('main', 'Theme', 'name2', value) - self.theme_message['text'] = 'New theme, see Help' - self.theme_message['fg'] = '#500000' - else: - changes.add_option('main', 'Theme', 'name', value) - changes.add_option('main', 'Theme', 'name2', '') - self.theme_message['text'] = '' - self.theme_message['fg'] = 'black' - self.paint_theme_sample() - - def var_changed_custom_name(self, *params): - """Process new custom theme selection. - - If a new custom theme is selected, add the name to the - changed_items and apply the theme to the sample. - """ - value = self.custom_name.get() - if value != '- no custom themes -': - changes.add_option('main', 'Theme', 'name', value) - self.paint_theme_sample() - - def var_changed_theme_source(self, *params): - """Process toggle between builtin and custom theme. - - Update the default toggle value and apply the newly - selected theme type. - """ - value = self.theme_source.get() - changes.add_option('main', 'Theme', 'default', value) - if value: - self.var_changed_builtin_name() - else: - self.var_changed_custom_name() - - def var_changed_color(self, *params): - "Process change to color choice." - self.on_new_color_set() - - def var_changed_highlight_target(self, *params): - "Process selection of new target tag for highlighting." - self.set_highlight_target() - - def set_theme_type(self): - """Set available screen options based on builtin or custom theme. - - Attributes accessed: - theme_source - - Attributes updated: - builtinlist - customlist - button_delete_custom - custom_theme_on - - Called from: - handler for builtin_theme_on and custom_theme_on - delete_custom - create_new - load_theme_cfg - """ - if self.theme_source.get(): - self.builtinlist['state'] = NORMAL - self.customlist['state'] = DISABLED - self.button_delete_custom['state'] = DISABLED - else: - self.builtinlist['state'] = DISABLED - self.custom_theme_on['state'] = NORMAL - self.customlist['state'] = NORMAL - self.button_delete_custom['state'] = NORMAL - - 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. - - Attributes accessed: - highlight_target - frame_color_set - theme_source - - Attributes updated: - color - - Methods: - get_new_theme_name - create_new - """ - target = self.highlight_target.get() - prev_color = self.frame_color_set.cget('bg') - rgbTuplet, 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.theme_source.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. - return - else: # Create new custom theme based on previously active theme. - self.create_new(new_theme) - self.color.set(color_string) - else: # Current theme is user defined. - self.color.set(color_string) - - def on_new_color_set(self): - "Display sample of new color selection on the dialog." - new_color = self.color.get() - self.frame_color_set['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.highlight_sample.tag_config(sample_element, **{plane: new_color}) - theme = self.custom_name.get() - theme_element = sample_element + '-' + plane - changes.add_option('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. + extpage: self.create_page_extensions Methods: - get_new_theme_name - create_new + create_action_buttons + load_configs: Load pages except for extensions. + activate_config_changes: Tell editors to reload. """ - new_theme_name = self.get_new_theme_name('New Theme Name:') - if new_theme_name: - self.create_new(new_theme_name) - - def create_new(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. + self.note = note = Notebook(self, width=450, height=450) + self.highpage = HighPage(note) + self.fontpage = FontPage(note, self.highpage) + self.keyspage = KeysPage(note) + self.genpage = GenPage(note) + self.extpage = self.create_page_extensions() + note.add(self.fontpage, text='Fonts/Tabs') + note.add(self.highpage, text='Highlights') + note.add(self.keyspage, text=' Keys ') + note.add(self.genpage, text=' General ') + note.add(self.extpage, text='Extensions') + note.enable_traversal() + note.pack(side=TOP, expand=TRUE, fill=BOTH) + self.create_action_buttons().pack(side=BOTTOM) - Attributes accessed: - builtin_name - custom_name + def create_action_buttons(self): + """Return frame of action buttons for dialog. - Attributes updated: - customlist - theme_source + Methods: + ok + apply + cancel + help - Method: - save_new - set_theme_type + Widget Structure: + outer: Frame + buttons: Frame + (no assignment): Button (ok) + (no assignment): Button (apply) + (no assignment): Button (cancel) + (no assignment): Button (help) + (no assignment): Frame """ - if self.theme_source.get(): - theme_type = 'default' - theme_name = self.builtin_name.get() + if macosx.isAquaTk(): + # Changing the default padding on OSX results in unreadable + # text in the buttons. + padding_args = {} else: - theme_type = 'user' - theme_name = self.custom_name.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 changes['highlight']: - theme_changes = changes['highlight'][theme_name] - for element in theme_changes: - new_theme[element] = theme_changes[element] - # Save the new theme. - self.save_new(new_theme_name, new_theme) - # Change GUI over to the new theme. - custom_theme_list = idleConf.GetSectionList('user', 'highlight') - custom_theme_list.sort() - self.customlist.SetMenu(custom_theme_list, new_theme_name) - self.theme_source.set(0) - self.set_theme_type() - - def set_highlight_target(self): - """Set fg/bg toggle and color based on highlight tag target. - - Instance variables accessed: - highlight_target + 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, + **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 - Attributes updated: - fg_on - bg_on - fg_bg_toggle + def ok(self): + """Apply config changes, then dismiss dialog. Methods: - set_color_sample - - Called from: - var_changed_highlight_target - load_theme_cfg + apply + destroy: inherited """ - if self.highlight_target.get() == 'Cursor': # bg not possible - self.fg_on['state'] = DISABLED - self.bg_on['state'] = DISABLED - self.fg_bg_toggle.set(1) - else: # Both fg and bg can be set. - self.fg_on['state'] = NORMAL - self.bg_on['state'] = NORMAL - self.fg_bg_toggle.set(1) - self.set_color_sample() + self.apply() + self.destroy() - def set_color_sample_binding(self, *args): - """Change color sample based on foreground/background toggle. + def apply(self): + """Apply config changes and leave dialog open. Methods: - set_color_sample + deactivate_current_config + save_all_changed_extensions + activate_config_changes """ - self.set_color_sample() - - def set_color_sample(self): - """Set the color of the frame background to reflect the selected target. + self.deactivate_current_config() + changes.save_all() + self.save_all_changed_extensions() + self.activate_config_changes() - Instance variables accessed: - theme_elements - highlight_target - fg_bg_toggle - highlight_sample + def cancel(self): + """Dismiss config dialog. - Attributes updated: - frame_color_set + Methods: + destroy: inherited """ - # 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.highlight_sample.tag_cget(tag, plane) - self.frame_color_set['bg'] = color - - def paint_theme_sample(self): - """Apply the theme colors to each element tag in the sample text. + self.destroy() - Instance attributes accessed: - theme_elements - theme_source - builtin_name - custom_name + def help(self): + """Create textview for config dialog help. - Attributes updated: - highlight_sample: Set the tag elements to the theme. + Attrbutes accessed: + tab_pages Methods: - set_color_sample - - Called from: - var_changed_builtin_name - var_changed_custom_name - load_theme_cfg - """ - if self.theme_source.get(): # Default theme - theme = self.builtin_name.get() - else: # User theme - theme = self.custom_name.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 changes['highlight']: - theme_dict = changes['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.highlight_sample.tag_config(element, **colors) - self.set_color_sample() - - def save_new(self, theme_name, theme): - """Save a newly created theme to idleConf. - - theme_name - string, the name of the new theme - theme - dictionary containing the new theme + view_text: Method from textview module. """ - 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(theme_name, element, value) - - def delete_custom(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. - - Attributes accessed: - custom_name + page = self.tab_pages._current_page + view_text(self, title='Help for IDLE preferences', + text=help_common+help_pages.get(page, '')) - Attributes updated: - custom_theme_on - customlist - theme_source - builtin_name - Methods: - deactivate_current_config - save_all_changed_extensions - activate_config_changes - set_theme_type - """ - theme_name = self.custom_name.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 changes, config, and file. - changes.delete_section('highlight', theme_name) - # Reload user theme list. - item_list = idleConf.GetSectionList('user', 'highlight') - item_list.sort() - if not item_list: - self.custom_theme_on['state'] = DISABLED - self.customlist.SetMenu(item_list, '- no custom themes -') - else: - self.customlist.SetMenu(item_list, item_list[0]) - # Revert to default theme. - self.theme_source.set(idleConf.defaultCfg['main'].Get('Theme', 'default')) - self.builtin_name.set(idleConf.defaultCfg['main'].Get('Theme', 'name')) - # User can't back out of these changes, they must be applied now. - changes.save_all() - self.save_all_changed_extensions() - self.activate_config_changes() - self.set_theme_type() +# def create_page_highlight(self): +# """Return frame of widgets for Highlighting tab. +# +# Enable users to provisionally change foreground and background +# colors applied to textual tags. Color mappings are stored in +# complete listings called themes. Built-in themes in +# idlelib/config-highlight.def are fixed as far as the dialog is +# concerned. Any theme can be used as the base for a new custom +# theme, stored in .idlerc/config-highlight.cfg. +# +# Function load_theme_cfg() initializes tk variables and theme +# lists and calls paint_theme_sample() and set_highlight_target() +# for the current theme. Radiobuttons builtin_theme_on and +# custom_theme_on toggle var theme_source, which controls if the +# current set of colors are from a builtin or custom theme. +# DynOptionMenus builtinlist and customlist contain lists of the +# builtin and custom themes, respectively, and the current item +# from each list is stored in vars builtin_name and custom_name. +# +# Function paint_theme_sample() applies the colors from the theme +# to the tags in text widget highlight_sample and then invokes +# set_color_sample(). Function set_highlight_target() sets the state +# of the radiobuttons fg_on and bg_on based on the tag and it also +# invokes set_color_sample(). +# +# Function set_color_sample() sets the background color for the frame +# holding the color selector. This provides a larger visual of the +# color for the current tag and plane (foreground/background). +# +# Note: set_color_sample() is called from many places and is often +# called more than once when a change is made. It is invoked when +# foreground or background is selected (radiobuttons), from +# paint_theme_sample() (theme is changed or load_cfg is called), and +# from set_highlight_target() (target tag is changed or load_cfg called). +# +# Button delete_custom invokes delete_custom() to delete +# a custom theme from idleConf.userCfg['highlight'] and changes. +# Button save_custom invokes save_as_new_theme() which calls +# get_new_theme_name() and create_new() to save a custom theme +# and its colors to idleConf.userCfg['highlight']. +# +# Radiobuttons fg_on and bg_on toggle var fg_bg_toggle to control +# if the current selected color for a tag is for the foreground or +# background. +# +# DynOptionMenu targetlist contains a readable description of the +# tags applied to Python source within IDLE. Selecting one of the +# tags from this list populates highlight_target, which has a callback +# function set_highlight_target(). +# +# Text widget highlight_sample displays a block of text (which is +# mock Python code) in which is embedded the defined tags and reflects +# the color attributes of the current theme and changes for those tags. +# Mouse button 1 allows for selection of a tag and updates +# highlight_target with that tag value. +# +# Note: The font in highlight_sample is set through the config in +# the fonts tab. +# +# In other words, a tag can be selected either from targetlist or +# by clicking on the sample text within highlight_sample. The +# plane (foreground/background) is selected via the radiobutton. +# Together, these two (tag and plane) control what color is +# shown in set_color_sample() for the current theme. Button set_color +# invokes get_color() which displays a ColorChooser to change the +# color for the selected tag/plane. If a new color is picked, +# it will be saved to changes and the highlight_sample and +# frame background will be updated. +# +# Tk Variables: +# color: Color of selected target. +# builtin_name: Menu variable for built-in theme. +# custom_name: Menu variable for custom theme. +# fg_bg_toggle: Toggle for foreground/background color. +# Note: this has no callback. +# theme_source: Selector for built-in or custom theme. +# highlight_target: Menu variable for the highlight tag target. +# +# Instance Data Attributes: +# theme_elements: Dictionary of tags for text highlighting. +# The key is the display name and the value is a tuple of +# (tag name, display sort order). +# +# Methods [attachment]: +# load_theme_cfg: Load current highlight colors. +# get_color: Invoke colorchooser [button_set_color]. +# set_color_sample_binding: Call set_color_sample [fg_bg_toggle]. +# set_highlight_target: set fg_bg_toggle, set_color_sample(). +# set_color_sample: Set frame background to target. +# on_new_color_set: Set new color and add option. +# paint_theme_sample: Recolor sample. +# get_new_theme_name: Get from popup. +# create_new: Combine theme with changes and save. +# save_as_new_theme: Save [button_save_custom]. +# set_theme_type: Command for [theme_source]. +# delete_custom: Activate default [button_delete_custom]. +# save_new: Save to userCfg['theme'] (is function). +# +# Widgets of highlights page frame: (*) widgets bound to self +# frame_custom: LabelFrame +# (*)highlight_sample: Text +# (*)frame_color_set: Frame +# (*)button_set_color: Button +# (*)targetlist: DynOptionMenu - highlight_target +# frame_fg_bg_toggle: Frame +# (*)fg_on: Radiobutton - fg_bg_toggle +# (*)bg_on: Radiobutton - fg_bg_toggle +# (*)button_save_custom: Button +# frame_theme: LabelFrame +# theme_type_title: Label +# (*)builtin_theme_on: Radiobutton - theme_source +# (*)custom_theme_on: Radiobutton - theme_source +# (*)builtinlist: DynOptionMenu - builtin_name +# (*)customlist: DynOptionMenu - custom_name +# (*)button_delete_custom: Button +# (*)theme_message: Label +# """ +# self.theme_elements={ +# 'Normal Text': ('normal', '00'), +# 'Python Keywords': ('keyword', '01'), +# 'Python Definitions': ('definition', '02'), +# 'Python Builtins': ('builtin', '03'), +# 'Python Comments': ('comment', '04'), +# 'Python Strings': ('string', '05'), +# 'Selected Text': ('hilite', '06'), +# 'Found Text': ('hit', '07'), +# 'Cursor': ('cursor', '08'), +# 'Editor Breakpoint': ('break', '09'), +# 'Shell Normal Text': ('console', '10'), +# 'Shell Error Text': ('error', '11'), +# 'Shell Stdout Text': ('stdout', '12'), +# 'Shell Stderr Text': ('stderr', '13'), +# } +# parent = self.parent +# self.builtin_name = tracers.add( +# StringVar(parent), self.var_changed_builtin_name) +# self.custom_name = tracers.add( +# StringVar(parent), self.var_changed_custom_name) +# self.fg_bg_toggle = BooleanVar(parent) +# self.color = tracers.add( +# StringVar(parent), self.var_changed_color) +# self.theme_source = tracers.add( +# BooleanVar(parent), self.var_changed_theme_source) +# self.highlight_target = tracers.add( +# StringVar(parent), self.var_changed_highlight_target) +# +# # Create widgets: +# # body frame and section frames. +# frame = Frame(self.note) +# frame_custom = LabelFrame(frame, borderwidth=2, relief=GROOVE, +# text=' Custom Highlighting ') +# frame_theme = LabelFrame(frame, borderwidth=2, relief=GROOVE, +# text=' Highlighting Theme ') +# # frame_custom. +# text = self.highlight_sample = frame.highlight_sample = Text( +# frame_custom, relief=SOLID, borderwidth=1, +# font=('courier', 12, ''), cursor='hand2', width=21, height=13, +# takefocus=FALSE, highlightthickness=0, wrap=NONE) +# text.bind('', lambda e: 'break') +# text.bind('', lambda e: 'break') +# text_and_tags=(('\n', 'normal'), +# ('#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'), +# ("'string'", 'string'), ('\n var1 = ', 'normal'), +# ("'selected'", 'hilite'), ('\n var2 = ', 'normal'), +# ("'found'", 'hit'), ('\n var3 = ', 'normal'), +# ('list', 'builtin'), ('(', 'normal'), +# ('None', 'keyword'), (')\n', 'normal'), +# (' breakpoint("line")', 'break'), ('\n\n', 'normal'), +# (' error ', 'error'), (' ', 'normal'), +# ('cursor |', 'cursor'), ('\n ', 'normal'), +# ('shell', 'console'), (' ', 'normal'), +# ('stdout', 'stdout'), (' ', 'normal'), +# ('stderr', 'stderr'), ('\n\n', 'normal')) +# 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['state'] = DISABLED +# self.frame_color_set = Frame(frame_custom, relief=SOLID, borderwidth=1) +# frame_fg_bg_toggle = Frame(frame_custom) +# self.button_set_color = Button( +# self.frame_color_set, text='Choose Color for :', +# command=self.get_color, highlightthickness=0) +# self.targetlist = DynOptionMenu( +# self.frame_color_set, self.highlight_target, None, +# highlightthickness=0) #, command=self.set_highlight_targetBinding +# self.fg_on = Radiobutton( +# frame_fg_bg_toggle, variable=self.fg_bg_toggle, value=1, +# text='Foreground', command=self.set_color_sample_binding) +# self.bg_on = 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) +# self.button_save_custom = 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.builtin_theme_on = Radiobutton( +# frame_theme, variable=self.theme_source, value=1, +# command=self.set_theme_type, text='a Built-in Theme') +# self.custom_theme_on = Radiobutton( +# frame_theme, variable=self.theme_source, value=0, +# command=self.set_theme_type, text='a Custom Theme') +# self.builtinlist = DynOptionMenu( +# frame_theme, self.builtin_name, None, command=None) +# self.customlist = DynOptionMenu( +# frame_theme, self.custom_name, None, command=None) +# self.button_delete_custom = Button( +# frame_theme, text='Delete Custom Theme', +# command=self.delete_custom) +# self.theme_message = Label(frame_theme, bd=2) +# +# # Pack widgets: +# # 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.highlight_sample.pack( +# side=TOP, padx=5, pady=5, expand=TRUE, fill=BOTH) +# self.button_set_color.pack(side=TOP, expand=TRUE, fill=X, padx=8, pady=4) +# self.targetlist.pack(side=TOP, expand=TRUE, fill=X, padx=8, pady=3) +# self.fg_on.pack(side=LEFT, anchor=E) +# self.bg_on.pack(side=RIGHT, anchor=W) +# self.button_save_custom.pack(side=BOTTOM, fill=X, padx=5, pady=5) +# # frame_theme. +# theme_type_title.pack(side=TOP, anchor=W, padx=5, pady=5) +# self.builtin_theme_on.pack(side=TOP, anchor=W, padx=5) +# self.custom_theme_on.pack(side=TOP, anchor=W, padx=5, pady=2) +# self.builtinlist.pack(side=TOP, fill=X, padx=5, pady=5) +# self.customlist.pack(side=TOP, fill=X, anchor=W, padx=5, pady=5) +# self.button_delete_custom.pack(side=TOP, fill=X, padx=5, pady=5) +# self.theme_message.pack(side=TOP, fill=X, pady=5) +# return frame +# +# def load_theme_cfg(self): +# """Load current configuration settings for the theme options. +# +# Based on the theme_source toggle, the theme is set as +# either builtin or custom and the initial widget values +# reflect the current settings from idleConf. +# +# Attributes updated: +# theme_source: Set from idleConf. +# builtinlist: List of default themes from idleConf. +# customlist: List of custom themes from idleConf. +# custom_theme_on: Disabled if there are no custom themes. +# custom_theme: Message with additional information. +# targetlist: Create menu from self.theme_elements. +# +# Methods: +# set_theme_type +# paint_theme_sample +# set_highlight_target +# """ +# # Set current theme type radiobutton. +# self.theme_source.set(idleConf.GetOption( +# 'main', 'Theme', 'default', type='bool', default=1)) +# # Set current theme. +# current_option = idleConf.CurrentTheme() +# # Load available theme option menus. +# if self.theme_source.get(): # Default theme selected. +# item_list = idleConf.GetSectionList('default', 'highlight') +# item_list.sort() +# self.builtinlist.SetMenu(item_list, current_option) +# item_list = idleConf.GetSectionList('user', 'highlight') +# item_list.sort() +# if not item_list: +# self.custom_theme_on['state'] = DISABLED +# self.custom_name.set('- no custom themes -') +# else: +# self.customlist.SetMenu(item_list, item_list[0]) +# else: # User theme selected. +# item_list = idleConf.GetSectionList('user', 'highlight') +# item_list.sort() +# self.customlist.SetMenu(item_list, current_option) +# item_list = idleConf.GetSectionList('default', 'highlight') +# item_list.sort() +# self.builtinlist.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.targetlist.SetMenu(theme_names, theme_names[0]) +# self.paint_theme_sample() +# self.set_highlight_target() +# +# def var_changed_builtin_name(self, *params): +# """Process new builtin theme selection. +# +# Add the changed theme's name to the changed_items and recreate +# the sample with the values from the selected theme. +# """ +# old_themes = ('IDLE Classic', 'IDLE New') +# value = self.builtin_name.get() +# if value not in old_themes: +# if idleConf.GetOption('main', 'Theme', 'name') not in old_themes: +# changes.add_option('main', 'Theme', 'name', old_themes[0]) +# changes.add_option('main', 'Theme', 'name2', value) +# self.theme_message['text'] = 'New theme, see Help' +# self.theme_message['fg'] = '#500000' +# else: +# changes.add_option('main', 'Theme', 'name', value) +# changes.add_option('main', 'Theme', 'name2', '') +# self.theme_message['text'] = '' +# self.theme_message['fg'] = 'black' +# self.paint_theme_sample() +# +# def var_changed_custom_name(self, *params): +# """Process new custom theme selection. +# +# If a new custom theme is selected, add the name to the +# changed_items and apply the theme to the sample. +# """ +# value = self.custom_name.get() +# if value != '- no custom themes -': +# changes.add_option('main', 'Theme', 'name', value) +# self.paint_theme_sample() +# +# def var_changed_theme_source(self, *params): +# """Process toggle between builtin and custom theme. +# +# Update the default toggle value and apply the newly +# selected theme type. +# """ +# value = self.theme_source.get() +# changes.add_option('main', 'Theme', 'default', value) +# if value: +# self.var_changed_builtin_name() +# else: +# self.var_changed_custom_name() +# +# def var_changed_color(self, *params): +# "Process change to color choice." +# self.on_new_color_set() +# +# def var_changed_highlight_target(self, *params): +# "Process selection of new target tag for highlighting." +# self.set_highlight_target() +# +# def set_theme_type(self): +# """Set available screen options based on builtin or custom theme. +# +# Attributes accessed: +# theme_source +# +# Attributes updated: +# builtinlist +# customlist +# button_delete_custom +# custom_theme_on +# +# Called from: +# handler for builtin_theme_on and custom_theme_on +# delete_custom +# create_new +# load_theme_cfg +# """ +# if self.theme_source.get(): +# self.builtinlist['state'] = NORMAL +# self.customlist['state'] = DISABLED +# self.button_delete_custom['state'] = DISABLED +# else: +# self.builtinlist['state'] = DISABLED +# self.custom_theme_on['state'] = NORMAL +# self.customlist['state'] = NORMAL +# self.button_delete_custom['state'] = NORMAL +# +# 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. +# +# Attributes accessed: +# highlight_target +# frame_color_set +# theme_source +# +# Attributes updated: +# color +# +# Methods: +# get_new_theme_name +# create_new +# """ +# target = self.highlight_target.get() +# prev_color = self.frame_color_set.cget('bg') +# rgbTuplet, 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.theme_source.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. +# return +# else: # Create new custom theme based on previously active theme. +# self.create_new(new_theme) +# self.color.set(color_string) +# else: # Current theme is user defined. +# self.color.set(color_string) +# +# def on_new_color_set(self): +# "Display sample of new color selection on the dialog." +# new_color = self.color.get() +# self.frame_color_set['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.highlight_sample.tag_config(sample_element, **{plane: new_color}) +# theme = self.custom_name.get() +# theme_element = sample_element + '-' + plane +# changes.add_option('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. +# +# Methods: +# get_new_theme_name +# create_new +# """ +# new_theme_name = self.get_new_theme_name('New Theme Name:') +# if new_theme_name: +# self.create_new(new_theme_name) +# +# def create_new(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. +# +# Attributes accessed: +# builtin_name +# custom_name +# +# Attributes updated: +# customlist +# theme_source +# +# Method: +# save_new +# set_theme_type +# """ +# if self.theme_source.get(): +# theme_type = 'default' +# theme_name = self.builtin_name.get() +# else: +# theme_type = 'user' +# theme_name = self.custom_name.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 changes['highlight']: +# theme_changes = changes['highlight'][theme_name] +# for element in theme_changes: +# new_theme[element] = theme_changes[element] +# # Save the new theme. +# self.save_new(new_theme_name, new_theme) +# # Change GUI over to the new theme. +# custom_theme_list = idleConf.GetSectionList('user', 'highlight') +# custom_theme_list.sort() +# self.customlist.SetMenu(custom_theme_list, new_theme_name) +# self.theme_source.set(0) +# self.set_theme_type() +# +# def set_highlight_target(self): +# """Set fg/bg toggle and color based on highlight tag target. +# +# Instance variables accessed: +# highlight_target +# +# Attributes updated: +# fg_on +# bg_on +# fg_bg_toggle +# +# Methods: +# set_color_sample +# +# Called from: +# var_changed_highlight_target +# load_theme_cfg +# """ +# if self.highlight_target.get() == 'Cursor': # bg not possible +# self.fg_on['state'] = DISABLED +# self.bg_on['state'] = DISABLED +# self.fg_bg_toggle.set(1) +# else: # Both fg and bg can be set. +# self.fg_on['state'] = NORMAL +# self.bg_on['state'] = NORMAL +# self.fg_bg_toggle.set(1) +# self.set_color_sample() +# +# def set_color_sample_binding(self, *args): +# """Change color sample based on foreground/background toggle. +# +# Methods: +# set_color_sample +# """ +# self.set_color_sample() +# +# def set_color_sample(self): +# """Set the color of the frame background to reflect the selected target. +# +# Instance variables accessed: +# theme_elements +# highlight_target +# fg_bg_toggle +# highlight_sample +# +# Attributes updated: +# frame_color_set +# """ +# # 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.highlight_sample.tag_cget(tag, plane) +# self.frame_color_set['bg'] = color +# +# def paint_theme_sample(self): +# """Apply the theme colors to each element tag in the sample text. +# +# Instance attributes accessed: +# theme_elements +# theme_source +# builtin_name +# custom_name +# +# Attributes updated: +# highlight_sample: Set the tag elements to the theme. +# +# Methods: +# set_color_sample +# +# Called from: +# var_changed_builtin_name +# var_changed_custom_name +# load_theme_cfg +# """ +# if self.theme_source.get(): # Default theme +# theme = self.builtin_name.get() +# else: # User theme +# theme = self.custom_name.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 changes['highlight']: +# theme_dict = changes['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.highlight_sample.tag_config(element, **colors) +# self.set_color_sample() +# +# def save_new(self, theme_name, theme): +# """Save a newly created theme to idleConf. +# +# theme_name - string, the name of the new theme +# theme - dictionary containing the new theme +# """ +# 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(theme_name, element, value) +# +# def delete_custom(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. +# +# Attributes accessed: +# custom_name +# +# Attributes updated: +# custom_theme_on +# customlist +# theme_source +# builtin_name +# +# Methods: +# deactivate_current_config +# save_all_changed_extensions +# activate_config_changes +# set_theme_type +# """ +# theme_name = self.custom_name.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 changes, config, and file. +# changes.delete_section('highlight', theme_name) +# # Reload user theme list. +# item_list = idleConf.GetSectionList('user', 'highlight') +# item_list.sort() +# if not item_list: +# self.custom_theme_on['state'] = DISABLED +# self.customlist.SetMenu(item_list, '- no custom themes -') +# else: +# self.customlist.SetMenu(item_list, item_list[0]) +# # Revert to default theme. +# self.theme_source.set(idleConf.defaultCfg['main'].Get('Theme', 'default')) +# self.builtin_name.set(idleConf.defaultCfg['main'].Get('Theme', 'name')) +# # User can't back out of these changes, they must be applied now. +# changes.save_all() +# self.save_all_changed_extensions() +# self.activate_config_changes() +# self.set_theme_type() def deactivate_current_config(self): """Remove current key bindings. @@ -1477,7 +1455,8 @@ def create_page_highlight(self): 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) + # event.widget.winfo_top_level().highlight_target.set(elem) + self.highlight_target.set(elem) text.tag_bind( self.theme_elements[element][0], '', tem) text['state'] = DISABLED @@ -1912,7 +1891,7 @@ def delete_custom(self): if not tkMessageBox.askyesno( 'Delete Theme', delmsg % theme_name, parent=self): return - cd.deactivate_current_config() + self.cd.deactivate_current_config() # Remove theme from changes, config, and file. changes.delete_section('highlight', theme_name) # Reload user theme list. @@ -1928,8 +1907,8 @@ def delete_custom(self): self.builtin_name.set(idleConf.defaultCfg['main'].Get('Theme', 'name')) # User can't back out of these changes, they must be applied now. changes.save_all() - cd.save_all_changed_extensions() - cd.activate_config_changes() + self.cd.save_all_changed_extensions() + self.cd.activate_config_changes() self.set_theme_type() diff --git a/Lib/idlelib/idle_test/test_configdialog.py b/Lib/idlelib/idle_test/test_configdialog.py index 966a72b50a99a50..df801c32b73a4b0 100644 --- a/Lib/idlelib/idle_test/test_configdialog.py +++ b/Lib/idlelib/idle_test/test_configdialog.py @@ -1,7 +1,7 @@ """Test idlelib.configdialog. Half the class creates dialog, half works with user customizations. -Coverage: 81%. +Coverage: 95%. """ from idlelib import configdialog from test.support import requires @@ -226,7 +226,7 @@ def test_indent_scale(self): self.assertEqual(mainpage, {'Indent': {'num-spaces': '16'}}) -class HighlightTest(unittest.TestCase): +class HighPageTest(unittest.TestCase): """Test that highlight tab widgets enable users to make changes. Test that widget actions set vars, that var changes add @@ -235,21 +235,21 @@ class HighlightTest(unittest.TestCase): @classmethod def setUpClass(cls): - d = dialog - dialog.note.select(d.highpage) - d.set_theme_type = Func() - d.paint_theme_sample = Func() - d.set_highlight_target = Func() - d.set_color_sample = Func() + page = cls.page = dialog.highpage + dialog.note.select(page) + page.set_theme_type = Func() + page.paint_theme_sample = Func() + page.set_highlight_target = Func() + page.set_color_sample = Func() @classmethod def tearDownClass(cls): - d = dialog + d = cls.page del d.set_theme_type, d.paint_theme_sample del d.set_highlight_target, d.set_color_sample def setUp(self): - d = dialog + d = self.page # The following is needed for test_load_key_cfg, _delete_custom_keys. # This may indicate a defect in some test or function. for section in idleConf.GetSectionList('user', 'highlight'): @@ -262,7 +262,7 @@ def setUp(self): def test_load_theme_cfg(self): tracers.detach() - d = dialog + d = self.page eq = self.assertEqual # Use builtin theme with no user themes created. @@ -303,7 +303,7 @@ def test_load_theme_cfg(self): def test_theme_source(self): eq = self.assertEqual - d = dialog + d = self.page # Test these separately. d.var_changed_builtin_name = Func() d.var_changed_custom_name = Func() @@ -324,7 +324,7 @@ def test_theme_source(self): def test_builtin_name(self): eq = self.assertEqual - d = dialog + d = self.page item_list = ['IDLE Classic', 'IDLE Dark', 'IDLE New'] # Not in old_themes, defaults name to first item. @@ -351,7 +351,7 @@ def test_builtin_name(self): eq(d.paint_theme_sample.called, 3) def test_custom_name(self): - d = dialog + d = self.page # If no selections, doesn't get added. d.customlist.SetMenu([], '- no custom themes -') @@ -365,7 +365,7 @@ def test_custom_name(self): self.assertEqual(d.paint_theme_sample.called, 1) def test_color(self): - d = dialog + d = self.page d.on_new_color_set = Func() # self.color is only set in get_color through ColorChooser. d.color.set('green') @@ -375,7 +375,7 @@ def test_color(self): def test_highlight_target_list_mouse(self): # Set highlight_target through targetlist. eq = self.assertEqual - d = dialog + d = self.page d.targetlist.SetMenu(['a', 'b', 'c'], 'c') eq(d.highlight_target.get(), 'c') @@ -384,7 +384,7 @@ def test_highlight_target_list_mouse(self): def test_highlight_target_text_mouse(self): # Set highlight_target through clicking highlight_sample. eq = self.assertEqual - d = dialog + d = self.page elem = {} count = 0 @@ -420,7 +420,7 @@ def click_it(start): def test_set_theme_type(self): eq = self.assertEqual - d = dialog + d = self.page del d.set_theme_type # Builtin theme selected. @@ -441,7 +441,7 @@ def test_set_theme_type(self): def test_get_color(self): eq = self.assertEqual - d = dialog + d = self.page orig_chooser = configdialog.tkColorChooser.askcolor chooser = configdialog.tkColorChooser.askcolor = Func() gntn = d.get_new_theme_name = Func() @@ -487,7 +487,7 @@ def test_get_color(self): configdialog.tkColorChooser.askcolor = orig_chooser def test_on_new_color_set(self): - d = dialog + d = self.page color = '#3f7cae' d.custom_name.set('Python') d.highlight_target.set('Selected Text') @@ -502,7 +502,7 @@ def test_on_new_color_set(self): def test_get_new_theme_name(self): orig_sectionname = configdialog.SectionName sn = configdialog.SectionName = Func(return_self=True) - d = dialog + d = self.page sn.result = 'New Theme' self.assertEqual(d.get_new_theme_name(''), 'New Theme') @@ -510,7 +510,7 @@ def test_get_new_theme_name(self): configdialog.SectionName = orig_sectionname def test_save_as_new_theme(self): - d = dialog + d = self.page gntn = d.get_new_theme_name = Func() d.theme_source.set(True) @@ -530,7 +530,7 @@ def test_save_as_new_theme(self): def test_create_new_and_save_new(self): eq = self.assertEqual - d = dialog + d = self.page # Use default as previously active theme. d.theme_source.set(True) @@ -562,7 +562,7 @@ def test_create_new_and_save_new(self): def test_set_highlight_target(self): eq = self.assertEqual - d = dialog + d = self.page del d.set_highlight_target # Target is cursor. @@ -582,7 +582,7 @@ def test_set_highlight_target(self): d.set_highlight_target = Func() def test_set_color_sample_binding(self): - d = dialog + d = self.page scs = d.set_color_sample d.fg_on.invoke() @@ -592,7 +592,7 @@ def test_set_color_sample_binding(self): self.assertEqual(scs.called, 2) def test_set_color_sample(self): - d = dialog + d = self.page del d.set_color_sample d.highlight_target.set('Selected Text') d.fg_bg_toggle.set(True) @@ -603,7 +603,7 @@ def test_set_color_sample(self): def test_paint_theme_sample(self): eq = self.assertEqual - d = dialog + d = self.page del d.paint_theme_sample hs_tag = d.highlight_sample.tag_cget gh = idleConf.GetHighlight @@ -640,7 +640,7 @@ def test_paint_theme_sample(self): def test_delete_custom(self): eq = self.assertEqual - d = dialog + d = self.page d.button_delete_custom['state'] = NORMAL yesno = configdialog.tkMessageBox.askyesno = Func() dialog.deactivate_current_config = Func() From 897652bb8cb5d4499325c7ccdbdcc3649af0aa8b Mon Sep 17 00:00:00 2001 From: Cheryl Sabella Date: Sat, 19 Aug 2017 08:33:24 -0400 Subject: [PATCH 2/5] bpo-31206: IDLE: Factor HighPage class from ConfigDialog --- Lib/idlelib/configdialog.py | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/Lib/idlelib/configdialog.py b/Lib/idlelib/configdialog.py index 5e328812443c90e..d55081dc96e72f6 100644 --- a/Lib/idlelib/configdialog.py +++ b/Lib/idlelib/configdialog.py @@ -114,6 +114,26 @@ def create_widgets(self): note.pack(side=TOP, expand=TRUE, fill=BOTH) self.create_action_buttons().pack(side=BOTTOM) +# 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. +# +# Methods: +# load_font_cfg +# load_tab_cfg +# load_theme_cfg +# load_key_cfg +# load_general_cfg +# """ +# #self.load_font_cfg() +# #self.load_tab_cfg() +# # self.load_theme_cfg() +# # self.load_key_cfg() +# # self.load_general_cfg() +# # note: extension page handled separately + def create_action_buttons(self): """Return frame of action buttons for dialog. From 2371b83aceb68920d577a2c0c0e46ab6453dc7e2 Mon Sep 17 00:00:00 2001 From: Terry Jan Reedy Date: Sat, 19 Aug 2017 21:32:58 -0400 Subject: [PATCH 3/5] Update configdialog.py --- Lib/idlelib/configdialog.py | 1314 +++++++++++++++++------------------ 1 file changed, 656 insertions(+), 658 deletions(-) diff --git a/Lib/idlelib/configdialog.py b/Lib/idlelib/configdialog.py index d55081dc96e72f6..aa83d6b4501c25a 100644 --- a/Lib/idlelib/configdialog.py +++ b/Lib/idlelib/configdialog.py @@ -114,31 +114,29 @@ def create_widgets(self): note.pack(side=TOP, expand=TRUE, fill=BOTH) self.create_action_buttons().pack(side=BOTTOM) -# 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. -# -# Methods: -# load_font_cfg -# load_tab_cfg -# load_theme_cfg -# load_key_cfg -# load_general_cfg -# """ -# #self.load_font_cfg() -# #self.load_tab_cfg() -# # self.load_theme_cfg() -# # self.load_key_cfg() -# # self.load_general_cfg() -# # note: extension page handled separately + def load_configs(self): + """Load configuration for each page. - def create_action_buttons(self): - """Return frame of action buttons for dialog. + Load configuration from default and user config files and populate + the widgets on the config dialog pages. Methods: - ok + load_font_cfg + load_tab_cfg + load_theme_cfg + load_key_cfg + load_general_cfg + """ + #self.load_font_cfg() + #self.load_tab_cfg() + # self.load_theme_cfg() + # self.load_key_cfg() + # self.load_general_cfg() + # note: extension page handled separately + def create_action_buttons(self): + """Return frame of action buttons for dialog. + Methods: + ok apply cancel help @@ -217,642 +215,642 @@ def help(self): text=help_common+help_pages.get(page, '')) -# def create_page_highlight(self): -# """Return frame of widgets for Highlighting tab. -# -# Enable users to provisionally change foreground and background -# colors applied to textual tags. Color mappings are stored in -# complete listings called themes. Built-in themes in -# idlelib/config-highlight.def are fixed as far as the dialog is -# concerned. Any theme can be used as the base for a new custom -# theme, stored in .idlerc/config-highlight.cfg. -# -# Function load_theme_cfg() initializes tk variables and theme -# lists and calls paint_theme_sample() and set_highlight_target() -# for the current theme. Radiobuttons builtin_theme_on and -# custom_theme_on toggle var theme_source, which controls if the -# current set of colors are from a builtin or custom theme. -# DynOptionMenus builtinlist and customlist contain lists of the -# builtin and custom themes, respectively, and the current item -# from each list is stored in vars builtin_name and custom_name. -# -# Function paint_theme_sample() applies the colors from the theme -# to the tags in text widget highlight_sample and then invokes -# set_color_sample(). Function set_highlight_target() sets the state -# of the radiobuttons fg_on and bg_on based on the tag and it also -# invokes set_color_sample(). -# -# Function set_color_sample() sets the background color for the frame -# holding the color selector. This provides a larger visual of the -# color for the current tag and plane (foreground/background). -# -# Note: set_color_sample() is called from many places and is often -# called more than once when a change is made. It is invoked when -# foreground or background is selected (radiobuttons), from -# paint_theme_sample() (theme is changed or load_cfg is called), and -# from set_highlight_target() (target tag is changed or load_cfg called). -# -# Button delete_custom invokes delete_custom() to delete -# a custom theme from idleConf.userCfg['highlight'] and changes. -# Button save_custom invokes save_as_new_theme() which calls -# get_new_theme_name() and create_new() to save a custom theme -# and its colors to idleConf.userCfg['highlight']. -# -# Radiobuttons fg_on and bg_on toggle var fg_bg_toggle to control -# if the current selected color for a tag is for the foreground or -# background. -# -# DynOptionMenu targetlist contains a readable description of the -# tags applied to Python source within IDLE. Selecting one of the -# tags from this list populates highlight_target, which has a callback -# function set_highlight_target(). -# -# Text widget highlight_sample displays a block of text (which is -# mock Python code) in which is embedded the defined tags and reflects -# the color attributes of the current theme and changes for those tags. -# Mouse button 1 allows for selection of a tag and updates -# highlight_target with that tag value. -# -# Note: The font in highlight_sample is set through the config in -# the fonts tab. -# -# In other words, a tag can be selected either from targetlist or -# by clicking on the sample text within highlight_sample. The -# plane (foreground/background) is selected via the radiobutton. -# Together, these two (tag and plane) control what color is -# shown in set_color_sample() for the current theme. Button set_color -# invokes get_color() which displays a ColorChooser to change the -# color for the selected tag/plane. If a new color is picked, -# it will be saved to changes and the highlight_sample and -# frame background will be updated. -# -# Tk Variables: -# color: Color of selected target. -# builtin_name: Menu variable for built-in theme. -# custom_name: Menu variable for custom theme. -# fg_bg_toggle: Toggle for foreground/background color. -# Note: this has no callback. -# theme_source: Selector for built-in or custom theme. -# highlight_target: Menu variable for the highlight tag target. -# -# Instance Data Attributes: -# theme_elements: Dictionary of tags for text highlighting. -# The key is the display name and the value is a tuple of -# (tag name, display sort order). -# -# Methods [attachment]: -# load_theme_cfg: Load current highlight colors. -# get_color: Invoke colorchooser [button_set_color]. -# set_color_sample_binding: Call set_color_sample [fg_bg_toggle]. -# set_highlight_target: set fg_bg_toggle, set_color_sample(). -# set_color_sample: Set frame background to target. -# on_new_color_set: Set new color and add option. -# paint_theme_sample: Recolor sample. -# get_new_theme_name: Get from popup. -# create_new: Combine theme with changes and save. -# save_as_new_theme: Save [button_save_custom]. -# set_theme_type: Command for [theme_source]. -# delete_custom: Activate default [button_delete_custom]. -# save_new: Save to userCfg['theme'] (is function). -# -# Widgets of highlights page frame: (*) widgets bound to self -# frame_custom: LabelFrame -# (*)highlight_sample: Text -# (*)frame_color_set: Frame -# (*)button_set_color: Button -# (*)targetlist: DynOptionMenu - highlight_target -# frame_fg_bg_toggle: Frame -# (*)fg_on: Radiobutton - fg_bg_toggle -# (*)bg_on: Radiobutton - fg_bg_toggle -# (*)button_save_custom: Button -# frame_theme: LabelFrame -# theme_type_title: Label -# (*)builtin_theme_on: Radiobutton - theme_source -# (*)custom_theme_on: Radiobutton - theme_source -# (*)builtinlist: DynOptionMenu - builtin_name -# (*)customlist: DynOptionMenu - custom_name -# (*)button_delete_custom: Button -# (*)theme_message: Label -# """ -# self.theme_elements={ -# 'Normal Text': ('normal', '00'), -# 'Python Keywords': ('keyword', '01'), -# 'Python Definitions': ('definition', '02'), -# 'Python Builtins': ('builtin', '03'), -# 'Python Comments': ('comment', '04'), -# 'Python Strings': ('string', '05'), -# 'Selected Text': ('hilite', '06'), -# 'Found Text': ('hit', '07'), -# 'Cursor': ('cursor', '08'), -# 'Editor Breakpoint': ('break', '09'), -# 'Shell Normal Text': ('console', '10'), -# 'Shell Error Text': ('error', '11'), -# 'Shell Stdout Text': ('stdout', '12'), -# 'Shell Stderr Text': ('stderr', '13'), -# } -# parent = self.parent -# self.builtin_name = tracers.add( -# StringVar(parent), self.var_changed_builtin_name) -# self.custom_name = tracers.add( -# StringVar(parent), self.var_changed_custom_name) -# self.fg_bg_toggle = BooleanVar(parent) -# self.color = tracers.add( -# StringVar(parent), self.var_changed_color) -# self.theme_source = tracers.add( -# BooleanVar(parent), self.var_changed_theme_source) -# self.highlight_target = tracers.add( -# StringVar(parent), self.var_changed_highlight_target) -# -# # Create widgets: -# # body frame and section frames. -# frame = Frame(self.note) -# frame_custom = LabelFrame(frame, borderwidth=2, relief=GROOVE, -# text=' Custom Highlighting ') -# frame_theme = LabelFrame(frame, borderwidth=2, relief=GROOVE, -# text=' Highlighting Theme ') -# # frame_custom. -# text = self.highlight_sample = frame.highlight_sample = Text( -# frame_custom, relief=SOLID, borderwidth=1, -# font=('courier', 12, ''), cursor='hand2', width=21, height=13, -# takefocus=FALSE, highlightthickness=0, wrap=NONE) -# text.bind('', lambda e: 'break') -# text.bind('', lambda e: 'break') -# text_and_tags=(('\n', 'normal'), -# ('#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'), -# ("'string'", 'string'), ('\n var1 = ', 'normal'), -# ("'selected'", 'hilite'), ('\n var2 = ', 'normal'), -# ("'found'", 'hit'), ('\n var3 = ', 'normal'), -# ('list', 'builtin'), ('(', 'normal'), -# ('None', 'keyword'), (')\n', 'normal'), -# (' breakpoint("line")', 'break'), ('\n\n', 'normal'), -# (' error ', 'error'), (' ', 'normal'), -# ('cursor |', 'cursor'), ('\n ', 'normal'), -# ('shell', 'console'), (' ', 'normal'), -# ('stdout', 'stdout'), (' ', 'normal'), -# ('stderr', 'stderr'), ('\n\n', 'normal')) -# 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['state'] = DISABLED -# self.frame_color_set = Frame(frame_custom, relief=SOLID, borderwidth=1) -# frame_fg_bg_toggle = Frame(frame_custom) -# self.button_set_color = Button( -# self.frame_color_set, text='Choose Color for :', -# command=self.get_color, highlightthickness=0) -# self.targetlist = DynOptionMenu( -# self.frame_color_set, self.highlight_target, None, -# highlightthickness=0) #, command=self.set_highlight_targetBinding -# self.fg_on = Radiobutton( -# frame_fg_bg_toggle, variable=self.fg_bg_toggle, value=1, -# text='Foreground', command=self.set_color_sample_binding) -# self.bg_on = 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) -# self.button_save_custom = 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.builtin_theme_on = Radiobutton( -# frame_theme, variable=self.theme_source, value=1, -# command=self.set_theme_type, text='a Built-in Theme') -# self.custom_theme_on = Radiobutton( -# frame_theme, variable=self.theme_source, value=0, -# command=self.set_theme_type, text='a Custom Theme') -# self.builtinlist = DynOptionMenu( -# frame_theme, self.builtin_name, None, command=None) -# self.customlist = DynOptionMenu( -# frame_theme, self.custom_name, None, command=None) -# self.button_delete_custom = Button( -# frame_theme, text='Delete Custom Theme', -# command=self.delete_custom) -# self.theme_message = Label(frame_theme, bd=2) -# -# # Pack widgets: -# # 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.highlight_sample.pack( -# side=TOP, padx=5, pady=5, expand=TRUE, fill=BOTH) -# self.button_set_color.pack(side=TOP, expand=TRUE, fill=X, padx=8, pady=4) -# self.targetlist.pack(side=TOP, expand=TRUE, fill=X, padx=8, pady=3) -# self.fg_on.pack(side=LEFT, anchor=E) -# self.bg_on.pack(side=RIGHT, anchor=W) -# self.button_save_custom.pack(side=BOTTOM, fill=X, padx=5, pady=5) -# # frame_theme. -# theme_type_title.pack(side=TOP, anchor=W, padx=5, pady=5) -# self.builtin_theme_on.pack(side=TOP, anchor=W, padx=5) -# self.custom_theme_on.pack(side=TOP, anchor=W, padx=5, pady=2) -# self.builtinlist.pack(side=TOP, fill=X, padx=5, pady=5) -# self.customlist.pack(side=TOP, fill=X, anchor=W, padx=5, pady=5) -# self.button_delete_custom.pack(side=TOP, fill=X, padx=5, pady=5) -# self.theme_message.pack(side=TOP, fill=X, pady=5) -# return frame -# -# def load_theme_cfg(self): -# """Load current configuration settings for the theme options. -# -# Based on the theme_source toggle, the theme is set as -# either builtin or custom and the initial widget values -# reflect the current settings from idleConf. -# -# Attributes updated: -# theme_source: Set from idleConf. -# builtinlist: List of default themes from idleConf. -# customlist: List of custom themes from idleConf. -# custom_theme_on: Disabled if there are no custom themes. -# custom_theme: Message with additional information. -# targetlist: Create menu from self.theme_elements. -# -# Methods: -# set_theme_type -# paint_theme_sample -# set_highlight_target -# """ -# # Set current theme type radiobutton. -# self.theme_source.set(idleConf.GetOption( -# 'main', 'Theme', 'default', type='bool', default=1)) -# # Set current theme. -# current_option = idleConf.CurrentTheme() -# # Load available theme option menus. -# if self.theme_source.get(): # Default theme selected. -# item_list = idleConf.GetSectionList('default', 'highlight') -# item_list.sort() -# self.builtinlist.SetMenu(item_list, current_option) -# item_list = idleConf.GetSectionList('user', 'highlight') -# item_list.sort() -# if not item_list: -# self.custom_theme_on['state'] = DISABLED -# self.custom_name.set('- no custom themes -') -# else: -# self.customlist.SetMenu(item_list, item_list[0]) -# else: # User theme selected. -# item_list = idleConf.GetSectionList('user', 'highlight') -# item_list.sort() -# self.customlist.SetMenu(item_list, current_option) -# item_list = idleConf.GetSectionList('default', 'highlight') -# item_list.sort() -# self.builtinlist.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.targetlist.SetMenu(theme_names, theme_names[0]) -# self.paint_theme_sample() -# self.set_highlight_target() -# -# def var_changed_builtin_name(self, *params): -# """Process new builtin theme selection. -# -# Add the changed theme's name to the changed_items and recreate -# the sample with the values from the selected theme. -# """ -# old_themes = ('IDLE Classic', 'IDLE New') -# value = self.builtin_name.get() -# if value not in old_themes: -# if idleConf.GetOption('main', 'Theme', 'name') not in old_themes: -# changes.add_option('main', 'Theme', 'name', old_themes[0]) -# changes.add_option('main', 'Theme', 'name2', value) -# self.theme_message['text'] = 'New theme, see Help' -# self.theme_message['fg'] = '#500000' -# else: -# changes.add_option('main', 'Theme', 'name', value) -# changes.add_option('main', 'Theme', 'name2', '') -# self.theme_message['text'] = '' -# self.theme_message['fg'] = 'black' -# self.paint_theme_sample() -# -# def var_changed_custom_name(self, *params): -# """Process new custom theme selection. -# -# If a new custom theme is selected, add the name to the -# changed_items and apply the theme to the sample. -# """ -# value = self.custom_name.get() -# if value != '- no custom themes -': -# changes.add_option('main', 'Theme', 'name', value) -# self.paint_theme_sample() -# -# def var_changed_theme_source(self, *params): -# """Process toggle between builtin and custom theme. -# -# Update the default toggle value and apply the newly -# selected theme type. -# """ -# value = self.theme_source.get() -# changes.add_option('main', 'Theme', 'default', value) -# if value: -# self.var_changed_builtin_name() -# else: -# self.var_changed_custom_name() -# -# def var_changed_color(self, *params): -# "Process change to color choice." -# self.on_new_color_set() -# -# def var_changed_highlight_target(self, *params): -# "Process selection of new target tag for highlighting." -# self.set_highlight_target() -# -# def set_theme_type(self): -# """Set available screen options based on builtin or custom theme. -# -# Attributes accessed: -# theme_source -# -# Attributes updated: -# builtinlist -# customlist -# button_delete_custom -# custom_theme_on -# -# Called from: -# handler for builtin_theme_on and custom_theme_on -# delete_custom -# create_new -# load_theme_cfg -# """ -# if self.theme_source.get(): -# self.builtinlist['state'] = NORMAL -# self.customlist['state'] = DISABLED -# self.button_delete_custom['state'] = DISABLED -# else: -# self.builtinlist['state'] = DISABLED -# self.custom_theme_on['state'] = NORMAL -# self.customlist['state'] = NORMAL -# self.button_delete_custom['state'] = NORMAL -# -# 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. -# -# Attributes accessed: -# highlight_target -# frame_color_set -# theme_source -# -# Attributes updated: -# color -# -# Methods: -# get_new_theme_name -# create_new -# """ -# target = self.highlight_target.get() -# prev_color = self.frame_color_set.cget('bg') -# rgbTuplet, 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.theme_source.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. -# return -# else: # Create new custom theme based on previously active theme. -# self.create_new(new_theme) -# self.color.set(color_string) -# else: # Current theme is user defined. -# self.color.set(color_string) -# -# def on_new_color_set(self): -# "Display sample of new color selection on the dialog." -# new_color = self.color.get() -# self.frame_color_set['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.highlight_sample.tag_config(sample_element, **{plane: new_color}) -# theme = self.custom_name.get() -# theme_element = sample_element + '-' + plane -# changes.add_option('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. -# -# Methods: -# get_new_theme_name -# create_new -# """ -# new_theme_name = self.get_new_theme_name('New Theme Name:') -# if new_theme_name: -# self.create_new(new_theme_name) -# -# def create_new(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. -# -# Attributes accessed: -# builtin_name -# custom_name -# -# Attributes updated: -# customlist -# theme_source -# -# Method: -# save_new -# set_theme_type -# """ -# if self.theme_source.get(): -# theme_type = 'default' -# theme_name = self.builtin_name.get() -# else: -# theme_type = 'user' -# theme_name = self.custom_name.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 changes['highlight']: -# theme_changes = changes['highlight'][theme_name] -# for element in theme_changes: -# new_theme[element] = theme_changes[element] -# # Save the new theme. -# self.save_new(new_theme_name, new_theme) -# # Change GUI over to the new theme. -# custom_theme_list = idleConf.GetSectionList('user', 'highlight') -# custom_theme_list.sort() -# self.customlist.SetMenu(custom_theme_list, new_theme_name) -# self.theme_source.set(0) -# self.set_theme_type() -# -# def set_highlight_target(self): -# """Set fg/bg toggle and color based on highlight tag target. -# -# Instance variables accessed: -# highlight_target -# -# Attributes updated: -# fg_on -# bg_on -# fg_bg_toggle -# -# Methods: -# set_color_sample -# -# Called from: -# var_changed_highlight_target -# load_theme_cfg -# """ -# if self.highlight_target.get() == 'Cursor': # bg not possible -# self.fg_on['state'] = DISABLED -# self.bg_on['state'] = DISABLED -# self.fg_bg_toggle.set(1) -# else: # Both fg and bg can be set. -# self.fg_on['state'] = NORMAL -# self.bg_on['state'] = NORMAL -# self.fg_bg_toggle.set(1) -# self.set_color_sample() -# -# def set_color_sample_binding(self, *args): -# """Change color sample based on foreground/background toggle. -# -# Methods: -# set_color_sample -# """ -# self.set_color_sample() -# -# def set_color_sample(self): -# """Set the color of the frame background to reflect the selected target. -# -# Instance variables accessed: -# theme_elements -# highlight_target -# fg_bg_toggle -# highlight_sample -# -# Attributes updated: -# frame_color_set -# """ -# # 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.highlight_sample.tag_cget(tag, plane) -# self.frame_color_set['bg'] = color -# -# def paint_theme_sample(self): -# """Apply the theme colors to each element tag in the sample text. -# -# Instance attributes accessed: -# theme_elements -# theme_source -# builtin_name -# custom_name -# -# Attributes updated: -# highlight_sample: Set the tag elements to the theme. -# -# Methods: -# set_color_sample -# -# Called from: -# var_changed_builtin_name -# var_changed_custom_name -# load_theme_cfg -# """ -# if self.theme_source.get(): # Default theme -# theme = self.builtin_name.get() -# else: # User theme -# theme = self.custom_name.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 changes['highlight']: -# theme_dict = changes['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.highlight_sample.tag_config(element, **colors) -# self.set_color_sample() -# -# def save_new(self, theme_name, theme): -# """Save a newly created theme to idleConf. -# -# theme_name - string, the name of the new theme -# theme - dictionary containing the new theme -# """ -# 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(theme_name, element, value) -# -# def delete_custom(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. -# -# Attributes accessed: -# custom_name -# -# Attributes updated: -# custom_theme_on -# customlist -# theme_source -# builtin_name -# -# Methods: -# deactivate_current_config -# save_all_changed_extensions -# activate_config_changes -# set_theme_type -# """ -# theme_name = self.custom_name.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 changes, config, and file. -# changes.delete_section('highlight', theme_name) -# # Reload user theme list. -# item_list = idleConf.GetSectionList('user', 'highlight') -# item_list.sort() -# if not item_list: -# self.custom_theme_on['state'] = DISABLED -# self.customlist.SetMenu(item_list, '- no custom themes -') -# else: -# self.customlist.SetMenu(item_list, item_list[0]) -# # Revert to default theme. -# self.theme_source.set(idleConf.defaultCfg['main'].Get('Theme', 'default')) -# self.builtin_name.set(idleConf.defaultCfg['main'].Get('Theme', 'name')) -# # User can't back out of these changes, they must be applied now. -# changes.save_all() -# self.save_all_changed_extensions() -# self.activate_config_changes() -# self.set_theme_type() + def create_page_highlight(self): + """Return frame of widgets for Highlighting tab. + + Enable users to provisionally change foreground and background + colors applied to textual tags. Color mappings are stored in + complete listings called themes. Built-in themes in + idlelib/config-highlight.def are fixed as far as the dialog is + concerned. Any theme can be used as the base for a new custom + theme, stored in .idlerc/config-highlight.cfg. + + Function load_theme_cfg() initializes tk variables and theme + lists and calls paint_theme_sample() and set_highlight_target() + for the current theme. Radiobuttons builtin_theme_on and + custom_theme_on toggle var theme_source, which controls if the + current set of colors are from a builtin or custom theme. + DynOptionMenus builtinlist and customlist contain lists of the + builtin and custom themes, respectively, and the current item + from each list is stored in vars builtin_name and custom_name. + + Function paint_theme_sample() applies the colors from the theme + to the tags in text widget highlight_sample and then invokes + set_color_sample(). Function set_highlight_target() sets the state + of the radiobuttons fg_on and bg_on based on the tag and it also + invokes set_color_sample(). + + Function set_color_sample() sets the background color for the frame + holding the color selector. This provides a larger visual of the + color for the current tag and plane (foreground/background). + + Note: set_color_sample() is called from many places and is often + called more than once when a change is made. It is invoked when + foreground or background is selected (radiobuttons), from + paint_theme_sample() (theme is changed or load_cfg is called), and + from set_highlight_target() (target tag is changed or load_cfg called). + + Button delete_custom invokes delete_custom() to delete + a custom theme from idleConf.userCfg['highlight'] and changes. + Button save_custom invokes save_as_new_theme() which calls + get_new_theme_name() and create_new() to save a custom theme + and its colors to idleConf.userCfg['highlight']. + + Radiobuttons fg_on and bg_on toggle var fg_bg_toggle to control + if the current selected color for a tag is for the foreground or + background. + + DynOptionMenu targetlist contains a readable description of the + tags applied to Python source within IDLE. Selecting one of the + tags from this list populates highlight_target, which has a callback + function set_highlight_target(). + + Text widget highlight_sample displays a block of text (which is + mock Python code) in which is embedded the defined tags and reflects + the color attributes of the current theme and changes for those tags. + Mouse button 1 allows for selection of a tag and updates + highlight_target with that tag value. + + Note: The font in highlight_sample is set through the config in + the fonts tab. + + In other words, a tag can be selected either from targetlist or + by clicking on the sample text within highlight_sample. The + plane (foreground/background) is selected via the radiobutton. + Together, these two (tag and plane) control what color is + shown in set_color_sample() for the current theme. Button set_color + invokes get_color() which displays a ColorChooser to change the + color for the selected tag/plane. If a new color is picked, + it will be saved to changes and the highlight_sample and + frame background will be updated. + + Tk Variables: + color: Color of selected target. + builtin_name: Menu variable for built-in theme. + custom_name: Menu variable for custom theme. + fg_bg_toggle: Toggle for foreground/background color. + Note: this has no callback. + theme_source: Selector for built-in or custom theme. + highlight_target: Menu variable for the highlight tag target. + + Instance Data Attributes: + theme_elements: Dictionary of tags for text highlighting. + The key is the display name and the value is a tuple of + (tag name, display sort order). + + Methods [attachment]: + load_theme_cfg: Load current highlight colors. + get_color: Invoke colorchooser [button_set_color]. + set_color_sample_binding: Call set_color_sample [fg_bg_toggle]. + set_highlight_target: set fg_bg_toggle, set_color_sample(). + set_color_sample: Set frame background to target. + on_new_color_set: Set new color and add option. + paint_theme_sample: Recolor sample. + get_new_theme_name: Get from popup. + create_new: Combine theme with changes and save. + save_as_new_theme: Save [button_save_custom]. + set_theme_type: Command for [theme_source]. + delete_custom: Activate default [button_delete_custom]. + save_new: Save to userCfg['theme'] (is function). + + Widgets of highlights page frame: (*) widgets bound to self + frame_custom: LabelFrame + (*)highlight_sample: Text + (*)frame_color_set: Frame + (*)button_set_color: Button + (*)targetlist: DynOptionMenu - highlight_target + frame_fg_bg_toggle: Frame + (*)fg_on: Radiobutton - fg_bg_toggle + (*)bg_on: Radiobutton - fg_bg_toggle + (*)button_save_custom: Button + frame_theme: LabelFrame + theme_type_title: Label + (*)builtin_theme_on: Radiobutton - theme_source + (*)custom_theme_on: Radiobutton - theme_source + (*)builtinlist: DynOptionMenu - builtin_name + (*)customlist: DynOptionMenu - custom_name + (*)button_delete_custom: Button + (*)theme_message: Label + """ + self.theme_elements={ + 'Normal Text': ('normal', '00'), + 'Python Keywords': ('keyword', '01'), + 'Python Definitions': ('definition', '02'), + 'Python Builtins': ('builtin', '03'), + 'Python Comments': ('comment', '04'), + 'Python Strings': ('string', '05'), + 'Selected Text': ('hilite', '06'), + 'Found Text': ('hit', '07'), + 'Cursor': ('cursor', '08'), + 'Editor Breakpoint': ('break', '09'), + 'Shell Normal Text': ('console', '10'), + 'Shell Error Text': ('error', '11'), + 'Shell Stdout Text': ('stdout', '12'), + 'Shell Stderr Text': ('stderr', '13'), + } + parent = self.parent + self.builtin_name = tracers.add( + StringVar(parent), self.var_changed_builtin_name) + self.custom_name = tracers.add( + StringVar(parent), self.var_changed_custom_name) + self.fg_bg_toggle = BooleanVar(parent) + self.color = tracers.add( + StringVar(parent), self.var_changed_color) + self.theme_source = tracers.add( + BooleanVar(parent), self.var_changed_theme_source) + self.highlight_target = tracers.add( + StringVar(parent), self.var_changed_highlight_target) + + # Create widgets: + # body frame and section frames. + frame = Frame(self.note) + frame_custom = LabelFrame(frame, borderwidth=2, relief=GROOVE, + text=' Custom Highlighting ') + frame_theme = LabelFrame(frame, borderwidth=2, relief=GROOVE, + text=' Highlighting Theme ') + # frame_custom. + text = self.highlight_sample = frame.highlight_sample = Text( + frame_custom, relief=SOLID, borderwidth=1, + font=('courier', 12, ''), cursor='hand2', width=21, height=13, + takefocus=FALSE, highlightthickness=0, wrap=NONE) + text.bind('', lambda e: 'break') + text.bind('', lambda e: 'break') + text_and_tags=(('\n', 'normal'), + ('#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'), + ("'string'", 'string'), ('\n var1 = ', 'normal'), + ("'selected'", 'hilite'), ('\n var2 = ', 'normal'), + ("'found'", 'hit'), ('\n var3 = ', 'normal'), + ('list', 'builtin'), ('(', 'normal'), + ('None', 'keyword'), (')\n', 'normal'), + (' breakpoint("line")', 'break'), ('\n\n', 'normal'), + (' error ', 'error'), (' ', 'normal'), + ('cursor |', 'cursor'), ('\n ', 'normal'), + ('shell', 'console'), (' ', 'normal'), + ('stdout', 'stdout'), (' ', 'normal'), + ('stderr', 'stderr'), ('\n\n', 'normal')) + 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['state'] = DISABLED + self.frame_color_set = Frame(frame_custom, relief=SOLID, borderwidth=1) + frame_fg_bg_toggle = Frame(frame_custom) + self.button_set_color = Button( + self.frame_color_set, text='Choose Color for :', + command=self.get_color, highlightthickness=0) + self.targetlist = DynOptionMenu( + self.frame_color_set, self.highlight_target, None, + highlightthickness=0) #, command=self.set_highlight_targetBinding + self.fg_on = Radiobutton( + frame_fg_bg_toggle, variable=self.fg_bg_toggle, value=1, + text='Foreground', command=self.set_color_sample_binding) + self.bg_on = 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) + self.button_save_custom = 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.builtin_theme_on = Radiobutton( + frame_theme, variable=self.theme_source, value=1, + command=self.set_theme_type, text='a Built-in Theme') + self.custom_theme_on = Radiobutton( + frame_theme, variable=self.theme_source, value=0, + command=self.set_theme_type, text='a Custom Theme') + self.builtinlist = DynOptionMenu( + frame_theme, self.builtin_name, None, command=None) + self.customlist = DynOptionMenu( + frame_theme, self.custom_name, None, command=None) + self.button_delete_custom = Button( + frame_theme, text='Delete Custom Theme', + command=self.delete_custom) + self.theme_message = Label(frame_theme, bd=2) + + # Pack widgets: + # 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.highlight_sample.pack( + side=TOP, padx=5, pady=5, expand=TRUE, fill=BOTH) + self.button_set_color.pack(side=TOP, expand=TRUE, fill=X, padx=8, pady=4) + self.targetlist.pack(side=TOP, expand=TRUE, fill=X, padx=8, pady=3) + self.fg_on.pack(side=LEFT, anchor=E) + self.bg_on.pack(side=RIGHT, anchor=W) + self.button_save_custom.pack(side=BOTTOM, fill=X, padx=5, pady=5) + # frame_theme. + theme_type_title.pack(side=TOP, anchor=W, padx=5, pady=5) + self.builtin_theme_on.pack(side=TOP, anchor=W, padx=5) + self.custom_theme_on.pack(side=TOP, anchor=W, padx=5, pady=2) + self.builtinlist.pack(side=TOP, fill=X, padx=5, pady=5) + self.customlist.pack(side=TOP, fill=X, anchor=W, padx=5, pady=5) + self.button_delete_custom.pack(side=TOP, fill=X, padx=5, pady=5) + self.theme_message.pack(side=TOP, fill=X, pady=5) + return frame + + def load_theme_cfg(self): + """Load current configuration settings for the theme options. + + Based on the theme_source toggle, the theme is set as + either builtin or custom and the initial widget values + reflect the current settings from idleConf. + + Attributes updated: + theme_source: Set from idleConf. + builtinlist: List of default themes from idleConf. + customlist: List of custom themes from idleConf. + custom_theme_on: Disabled if there are no custom themes. + custom_theme: Message with additional information. + targetlist: Create menu from self.theme_elements. + + Methods: + set_theme_type + paint_theme_sample + set_highlight_target + """ + # Set current theme type radiobutton. + self.theme_source.set(idleConf.GetOption( + 'main', 'Theme', 'default', type='bool', default=1)) + # Set current theme. + current_option = idleConf.CurrentTheme() + # Load available theme option menus. + if self.theme_source.get(): # Default theme selected. + item_list = idleConf.GetSectionList('default', 'highlight') + item_list.sort() + self.builtinlist.SetMenu(item_list, current_option) + item_list = idleConf.GetSectionList('user', 'highlight') + item_list.sort() + if not item_list: + self.custom_theme_on['state'] = DISABLED + self.custom_name.set('- no custom themes -') + else: + self.customlist.SetMenu(item_list, item_list[0]) + else: # User theme selected. + item_list = idleConf.GetSectionList('user', 'highlight') + item_list.sort() + self.customlist.SetMenu(item_list, current_option) + item_list = idleConf.GetSectionList('default', 'highlight') + item_list.sort() + self.builtinlist.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.targetlist.SetMenu(theme_names, theme_names[0]) + self.paint_theme_sample() + self.set_highlight_target() + + def var_changed_builtin_name(self, *params): + """Process new builtin theme selection. + + Add the changed theme's name to the changed_items and recreate + the sample with the values from the selected theme. + """ + old_themes = ('IDLE Classic', 'IDLE New') + value = self.builtin_name.get() + if value not in old_themes: + if idleConf.GetOption('main', 'Theme', 'name') not in old_themes: + changes.add_option('main', 'Theme', 'name', old_themes[0]) + changes.add_option('main', 'Theme', 'name2', value) + self.theme_message['text'] = 'New theme, see Help' + self.theme_message['fg'] = '#500000' + else: + changes.add_option('main', 'Theme', 'name', value) + changes.add_option('main', 'Theme', 'name2', '') + self.theme_message['text'] = '' + self.theme_message['fg'] = 'black' + self.paint_theme_sample() + + def var_changed_custom_name(self, *params): + """Process new custom theme selection. + + If a new custom theme is selected, add the name to the + changed_items and apply the theme to the sample. + """ + value = self.custom_name.get() + if value != '- no custom themes -': + changes.add_option('main', 'Theme', 'name', value) + self.paint_theme_sample() + + def var_changed_theme_source(self, *params): + """Process toggle between builtin and custom theme. + + Update the default toggle value and apply the newly + selected theme type. + """ + value = self.theme_source.get() + changes.add_option('main', 'Theme', 'default', value) + if value: + self.var_changed_builtin_name() + else: + self.var_changed_custom_name() + + def var_changed_color(self, *params): + "Process change to color choice." + self.on_new_color_set() + + def var_changed_highlight_target(self, *params): + "Process selection of new target tag for highlighting." + self.set_highlight_target() + + def set_theme_type(self): + """Set available screen options based on builtin or custom theme. + + Attributes accessed: + theme_source + + Attributes updated: + builtinlist + customlist + button_delete_custom + custom_theme_on + + Called from: + handler for builtin_theme_on and custom_theme_on + delete_custom + create_new + load_theme_cfg + """ + if self.theme_source.get(): + self.builtinlist['state'] = NORMAL + self.customlist['state'] = DISABLED + self.button_delete_custom['state'] = DISABLED + else: + self.builtinlist['state'] = DISABLED + self.custom_theme_on['state'] = NORMAL + self.customlist['state'] = NORMAL + self.button_delete_custom['state'] = NORMAL + + 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. + + Attributes accessed: + highlight_target + frame_color_set + theme_source + + Attributes updated: + color + + Methods: + get_new_theme_name + create_new + """ + target = self.highlight_target.get() + prev_color = self.frame_color_set.cget('bg') + rgbTuplet, 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.theme_source.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. + return + else: # Create new custom theme based on previously active theme. + self.create_new(new_theme) + self.color.set(color_string) + else: # Current theme is user defined. + self.color.set(color_string) + + def on_new_color_set(self): + "Display sample of new color selection on the dialog." + new_color = self.color.get() + self.frame_color_set['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.highlight_sample.tag_config(sample_element, **{plane: new_color}) + theme = self.custom_name.get() + theme_element = sample_element + '-' + plane + changes.add_option('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. + + Methods: + get_new_theme_name + create_new + """ + new_theme_name = self.get_new_theme_name('New Theme Name:') + if new_theme_name: + self.create_new(new_theme_name) + + def create_new(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. + + Attributes accessed: + builtin_name + custom_name + + Attributes updated: + customlist + theme_source + + Method: + save_new + set_theme_type + """ + if self.theme_source.get(): + theme_type = 'default' + theme_name = self.builtin_name.get() + else: + theme_type = 'user' + theme_name = self.custom_name.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 changes['highlight']: + theme_changes = changes['highlight'][theme_name] + for element in theme_changes: + new_theme[element] = theme_changes[element] + # Save the new theme. + self.save_new(new_theme_name, new_theme) + # Change GUI over to the new theme. + custom_theme_list = idleConf.GetSectionList('user', 'highlight') + custom_theme_list.sort() + self.customlist.SetMenu(custom_theme_list, new_theme_name) + self.theme_source.set(0) + self.set_theme_type() + + def set_highlight_target(self): + """Set fg/bg toggle and color based on highlight tag target. + + Instance variables accessed: + highlight_target + + Attributes updated: + fg_on + bg_on + fg_bg_toggle + + Methods: + set_color_sample + + Called from: + var_changed_highlight_target + load_theme_cfg + """ + if self.highlight_target.get() == 'Cursor': # bg not possible + self.fg_on['state'] = DISABLED + self.bg_on['state'] = DISABLED + self.fg_bg_toggle.set(1) + else: # Both fg and bg can be set. + self.fg_on['state'] = NORMAL + self.bg_on['state'] = NORMAL + self.fg_bg_toggle.set(1) + self.set_color_sample() + + def set_color_sample_binding(self, *args): + """Change color sample based on foreground/background toggle. + + Methods: + set_color_sample + """ + self.set_color_sample() + + def set_color_sample(self): + """Set the color of the frame background to reflect the selected target. + + Instance variables accessed: + theme_elements + highlight_target + fg_bg_toggle + highlight_sample + + Attributes updated: + frame_color_set + """ + # 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.highlight_sample.tag_cget(tag, plane) + self.frame_color_set['bg'] = color + + def paint_theme_sample(self): + """Apply the theme colors to each element tag in the sample text. + + Instance attributes accessed: + theme_elements + theme_source + builtin_name + custom_name + + Attributes updated: + highlight_sample: Set the tag elements to the theme. + + Methods: + set_color_sample + + Called from: + var_changed_builtin_name + var_changed_custom_name + load_theme_cfg + """ + if self.theme_source.get(): # Default theme + theme = self.builtin_name.get() + else: # User theme + theme = self.custom_name.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 changes['highlight']: + theme_dict = changes['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.highlight_sample.tag_config(element, **colors) + self.set_color_sample() + + def save_new(self, theme_name, theme): + """Save a newly created theme to idleConf. + + theme_name - string, the name of the new theme + theme - dictionary containing the new theme + """ + 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(theme_name, element, value) + + def delete_custom(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. + + Attributes accessed: + custom_name + + Attributes updated: + custom_theme_on + customlist + theme_source + builtin_name + + Methods: + deactivate_current_config + save_all_changed_extensions + activate_config_changes + set_theme_type + """ + theme_name = self.custom_name.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 changes, config, and file. + changes.delete_section('highlight', theme_name) + # Reload user theme list. + item_list = idleConf.GetSectionList('user', 'highlight') + item_list.sort() + if not item_list: + self.custom_theme_on['state'] = DISABLED + self.customlist.SetMenu(item_list, '- no custom themes -') + else: + self.customlist.SetMenu(item_list, item_list[0]) + # Revert to default theme. + self.theme_source.set(idleConf.defaultCfg['main'].Get('Theme', 'default')) + self.builtin_name.set(idleConf.defaultCfg['main'].Get('Theme', 'name')) + # User can't back out of these changes, they must be applied now. + changes.save_all() + self.save_all_changed_extensions() + self.activate_config_changes() + self.set_theme_type() def deactivate_current_config(self): """Remove current key bindings. From dc56922ea6e167640cb6d9427ecbacd55681cefe Mon Sep 17 00:00:00 2001 From: Terry Jan Reedy Date: Sat, 19 Aug 2017 21:39:39 -0400 Subject: [PATCH 4/5] Update configdialog.py --- Lib/idlelib/configdialog.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/Lib/idlelib/configdialog.py b/Lib/idlelib/configdialog.py index aa83d6b4501c25a..2af0994f21b433e 100644 --- a/Lib/idlelib/configdialog.py +++ b/Lib/idlelib/configdialog.py @@ -134,7 +134,8 @@ def load_configs(self): # self.load_general_cfg() # note: extension page handled separately def create_action_buttons(self): - """Return frame of action buttons for dialog. + """Return frame of action buttons for dialog. + Methods: ok apply @@ -432,7 +433,7 @@ def tem(event, elem=element): frame_theme, self.custom_name, None, command=None) self.button_delete_custom = Button( frame_theme, text='Delete Custom Theme', - command=self.delete_custom) + command=self.delete_custom) self.theme_message = Label(frame_theme, bd=2) # Pack widgets: @@ -740,7 +741,7 @@ def set_color_sample(self): Instance variables accessed: theme_elements - highlight_target + highlight_target fg_bg_toggle highlight_sample From 109d286998e27e2972cca0d1e50ca7021f129439 Mon Sep 17 00:00:00 2001 From: Terry Jan Reedy Date: Sat, 19 Aug 2017 21:43:41 -0400 Subject: [PATCH 5/5] Update configdialog.py --- Lib/idlelib/configdialog.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Lib/idlelib/configdialog.py b/Lib/idlelib/configdialog.py index 2af0994f21b433e..a9863023a76ca54 100644 --- a/Lib/idlelib/configdialog.py +++ b/Lib/idlelib/configdialog.py @@ -134,10 +134,10 @@ def load_configs(self): # self.load_general_cfg() # note: extension page handled separately def create_action_buttons(self): - """Return frame of action buttons for dialog. + """Return frame of action buttons for dialog. Methods: - ok + ok apply cancel help