import webbrowser
from tkinter import *
+from tkinter.font import Font
from tkinter.ttk import Scrollbar
import tkinter.simpledialog as tkSimpleDialog
import tkinter.messagebox as tkMessageBox
self.prompt_last_line = '' # Override in PyShell
self.text_frame = text_frame = Frame(top)
self.vbar = vbar = Scrollbar(text_frame, name='vbar')
- self.width = idleConf.GetOption('main', 'EditorWindow',
- 'width', type='int')
+ width = idleConf.GetOption('main', 'EditorWindow', 'width', type='int')
text_options = {
'name': 'text',
'padx': 5,
'wrap': 'none',
'highlightthickness': 0,
- 'width': self.width,
+ 'width': width,
'tabstyle': 'wordprocessor', # new in 8.5
'height': idleConf.GetOption(
'main', 'EditorWindow', 'height', type='int'),
text.bind('<MouseWheel>', self.mousescroll)
text.bind('<Button-4>', self.mousescroll)
text.bind('<Button-5>', self.mousescroll)
+ text.bind('<Configure>', self.handle_winconfig)
text.bind("<<cut>>", self.cut)
text.bind("<<copy>>", self.copy)
text.bind("<<paste>>", self.paste)
text['font'] = idleConf.GetFont(self.root, 'main', 'EditorWindow')
text.grid(row=1, column=1, sticky=NSEW)
text.focus_set()
+ self.set_width()
# usetabs true -> literal tab characters are used by indent and
# dedent cmds, possibly mixed with spaces if
else:
self.update_menu_state('options', '*Line Numbers', 'disabled')
+ def handle_winconfig(self, event=None):
+ self.set_width()
+
+ def set_width(self):
+ text = self.text
+ inner_padding = sum(map(text.tk.getint, [text.cget('border'),
+ text.cget('padx')]))
+ pixel_width = text.winfo_width() - 2 * inner_padding
+
+ # Divide the width of the Text widget by the font width,
+ # which is taken to be the width of '0' (zero).
+ # http://www.tcl.tk/man/tcl8.6/TkCmd/text.htm#M21
+ zero_char_width = \
+ Font(text, font=text.cget('font')).measure('0')
+ self.width = pixel_width // zero_char_width
+
def _filename_to_unicode(self, filename):
"""Return filename as BMP unicode so displayable in Tk."""
# Decode bytes to unicode.
# Finally, update the main text widget.
new_font = idleConf.GetFont(self.root, 'main', 'EditorWindow')
self.text['font'] = new_font
+ self.set_width()
def RemoveKeybindings(self):
"Remove the keybindings before they are changed."
class SqueezerTest(unittest.TestCase):
"""Tests for the Squeezer class."""
- def tearDown(self):
- # Clean up the Squeezer class's reference to its instance,
- # to avoid side-effects from one test case upon another.
- if Squeezer._instance_weakref is not None:
- Squeezer._instance_weakref = None
-
def make_mock_editor_window(self, with_text_widget=False):
"""Create a mock EditorWindow instance."""
editwin = NonCallableMagicMock()
- # isinstance(editwin, PyShell) must be true for Squeezer to enable
- # auto-squeezing; in practice this will always be true.
- editwin.__class__ = PyShell
+ editwin.width = 80
if with_text_widget:
editwin.root = get_test_tk_root(self)
if editor_window is None:
editor_window = self.make_mock_editor_window()
squeezer = Squeezer(editor_window)
- squeezer.get_line_width = Mock(return_value=80)
return squeezer
def make_text_widget(self, root=None):
line_width=line_width,
expected=expected):
text = eval(text_code)
- squeezer.get_line_width.return_value = line_width
- self.assertEqual(squeezer.count_lines(text), expected)
+ with patch.object(editwin, 'width', line_width):
+ self.assertEqual(squeezer.count_lines(text), expected)
def test_init(self):
"""Test the creation of Squeezer instances."""
"""Test the reload() class-method."""
editwin = self.make_mock_editor_window(with_text_widget=True)
squeezer = self.make_squeezer_instance(editwin)
- squeezer.load_font = Mock()
orig_auto_squeeze_min_lines = squeezer.auto_squeeze_min_lines
Squeezer.reload()
self.assertEqual(squeezer.auto_squeeze_min_lines,
new_auto_squeeze_min_lines)
- squeezer.load_font.assert_called()
def test_reload_no_squeezer_instances(self):
"""Test that Squeezer.reload() runs without any instances existing."""
messages and their tracebacks.
"""
import re
-import weakref
import tkinter as tk
-from tkinter.font import Font
import tkinter.messagebox as tkMessageBox
from idlelib.config import idleConf
This avoids IDLE's shell slowing down considerably, and even becoming
completely unresponsive, when very long outputs are written.
"""
- _instance_weakref = None
-
@classmethod
def reload(cls):
"""Load class variables from config."""
type="int", default=50,
)
- # Loading the font info requires a Tk root. IDLE doesn't rely
- # on Tkinter's "default root", so the instance will reload
- # font info using its editor windows's Tk root.
- if cls._instance_weakref is not None:
- instance = cls._instance_weakref()
- if instance is not None:
- instance.load_font()
-
def __init__(self, editwin):
"""Initialize settings for Squeezer.
# however, needs to make such changes.
self.base_text = editwin.per.bottom
- Squeezer._instance_weakref = weakref.ref(self)
- self.load_font()
-
# Twice the text widget's border width and internal padding;
# pre-calculated here for the get_line_width() method.
self.window_width_delta = 2 * (
Tabs are considered tabwidth characters long.
"""
- linewidth = self.get_line_width()
- return count_lines_with_wrapping(s, linewidth)
-
- def get_line_width(self):
- # The maximum line length in pixels: The width of the text
- # widget, minus twice the border width and internal padding.
- linewidth_pixels = \
- self.base_text.winfo_width() - self.window_width_delta
-
- # Divide the width of the Text widget by the font width,
- # which is taken to be the width of '0' (zero).
- # http://www.tcl.tk/man/tcl8.6/TkCmd/text.htm#M21
- return linewidth_pixels // self.zero_char_width
-
- def load_font(self):
- text = self.base_text
- self.zero_char_width = \
- Font(text, font=text.cget('font')).measure('0')
+ return count_lines_with_wrapping(s, self.editwin.width)
def squeeze_current_text_event(self, event):
"""squeeze-current-text event handler
--- /dev/null
+IDLE Settings dialog now closes properly when there is no shell window.