[Python-checkins] bpo-33763: IDLE: Replace label widget with text widget in code context (GH-7367)

Miss Islington (bot) webhook-mailer at python.org
Mon Jun 4 12:33:28 EDT 2018


https://github.com/python/cpython/commit/b7eb1024d06e51598fc8a19ed6e22b91120c6a1e
commit: b7eb1024d06e51598fc8a19ed6e22b91120c6a1e
branch: 3.7
author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com>
committer: GitHub <noreply at github.com>
date: 2018-06-04T09:33:23-07:00
summary:

bpo-33763: IDLE: Replace label widget with text widget in code context (GH-7367)

(cherry picked from commit b609e687a076d77bdd687f5e4def85e29a044bfc)

Co-authored-by: Cheryl Sabella <cheryl.sabella at gmail.com>

files:
A Misc/NEWS.d/next/IDLE/2018-06-03-20-12-57.bpo-33763.URiFlE.rst
M Lib/idlelib/codecontext.py
M Lib/idlelib/idle_test/test_codecontext.py

diff --git a/Lib/idlelib/codecontext.py b/Lib/idlelib/codecontext.py
index 78edf12263a6..73d3ba617429 100644
--- a/Lib/idlelib/codecontext.py
+++ b/Lib/idlelib/codecontext.py
@@ -52,7 +52,7 @@ def __init__(self, editwin):
         self.text is the editor window text widget.
         self.textfont is the editor window font.
 
-        self.label displays the code context text above the editor text.
+        self.context displays the code context text above the editor text.
           Initially None, it is toggled via <<toggle-code-context>>.
         self.topvisible is the number of the top text line displayed.
         self.info is a list of (line number, indent level, line text,
@@ -67,7 +67,7 @@ def __init__(self, editwin):
         self.text = editwin.text
         self.textfont = self.text["font"]
         self.contextcolors = CodeContext.colors
-        self.label = None
+        self.context = None
         self.topvisible = 1
         self.info = [(0, -1, "", False)]
         # Start two update cycles, one for context lines, one for font changes.
@@ -92,11 +92,11 @@ def __del__(self):
     def toggle_code_context_event(self, event=None):
         """Toggle code context display.
 
-        If self.label doesn't exist, create it to match the size of the editor
+        If self.context doesn't exist, create it to match the size of the editor
         window text (toggle on).  If it does exist, destroy it (toggle off).
         Return 'break' to complete the processing of the binding.
         """
-        if not self.label:
+        if not self.context:
             # Calculate the border width and horizontal padding required to
             # align the context with the text in the main Text widget.
             #
@@ -110,20 +110,20 @@ def toggle_code_context_event(self, event=None):
                 padx += widget.tk.getint(widget.pack_info()['padx'])
                 padx += widget.tk.getint(widget.cget('padx'))
                 border += widget.tk.getint(widget.cget('border'))
-            self.label = tkinter.Label(
-                    self.editwin.top, text="",
-                    anchor=W, justify=LEFT, font=self.textfont,
+            self.context = tkinter.Text(
+                    self.editwin.top, font=self.textfont,
                     bg=self.contextcolors['background'],
                     fg=self.contextcolors['foreground'],
+                    height=1,
                     width=1,  # Don't request more than we get.
-                    padx=padx, border=border, relief=SUNKEN)
-            # Pack the label widget before and above the text_frame widget,
+                    padx=padx, border=border, relief=SUNKEN, state='disabled')
+            # Pack the context widget before and above the text_frame widget,
             # thus ensuring that it will appear directly above text_frame.
-            self.label.pack(side=TOP, fill=X, expand=False,
+            self.context.pack(side=TOP, fill=X, expand=False,
                             before=self.editwin.text_frame)
         else:
-            self.label.destroy()
-            self.label = None
+            self.context.destroy()
+            self.context = None
         return "break"
 
     def get_context(self, new_topvisible, stopline=1, stopindent=0):
@@ -161,9 +161,8 @@ def update_code_context(self):
 
         No update is done if the text hasn't been scrolled.  If the text
         was scrolled, the lines that should be shown in the context will
-        be retrieved and the label widget will be updated with the code,
-        padded with blank lines so that the code appears on the bottom of
-        the context label.
+        be retrieved and the context area will be updated with the code,
+        up to the number of maxlines.
         """
         new_topvisible = int(self.text.index("@0,0").split('.')[0])
         if self.topvisible == new_topvisible:      # Haven't scrolled.
@@ -190,24 +189,29 @@ def update_code_context(self):
         # Last context_depth context lines.
         context_strings = [x[2] for x in self.info[-self.context_depth:]]
         showfirst = 0 if context_strings[0] else 1
-        self.label["text"] = '\n'.join(context_strings[showfirst:])
+        # Update widget.
+        self.context['height'] = len(context_strings) - showfirst
+        self.context['state'] = 'normal'
+        self.context.delete('1.0', 'end')
+        self.context.insert('end', '\n'.join(context_strings[showfirst:]))
+        self.context['state'] = 'disabled'
 
     def timer_event(self):
         "Event on editor text widget triggered every UPDATEINTERVAL ms."
-        if self.label:
+        if self.context:
             self.update_code_context()
         self.t1 = self.text.after(UPDATEINTERVAL, self.timer_event)
 
     def config_timer_event(self):
         "Event on editor text widget triggered every CONFIGUPDATEINTERVAL ms."
         newtextfont = self.text["font"]
-        if (self.label and (newtextfont != self.textfont or
+        if (self.context and (newtextfont != self.textfont or
                             CodeContext.colors != self.contextcolors)):
             self.textfont = newtextfont
             self.contextcolors = CodeContext.colors
-            self.label["font"] = self.textfont
-            self.label['background'] = self.contextcolors['background']
-            self.label['foreground'] = self.contextcolors['foreground']
+            self.context["font"] = self.textfont
+            self.context['background'] = self.contextcolors['background']
+            self.context['foreground'] = self.contextcolors['foreground']
         self.t2 = self.text.after(CONFIGUPDATEINTERVAL, self.config_timer_event)
 
 
diff --git a/Lib/idlelib/idle_test/test_codecontext.py b/Lib/idlelib/idle_test/test_codecontext.py
index d446090b0820..07e10b6f7ec5 100644
--- a/Lib/idlelib/idle_test/test_codecontext.py
+++ b/Lib/idlelib/idle_test/test_codecontext.py
@@ -56,7 +56,7 @@ def setUpClass(cls):
         frame = cls.frame = Frame(root)
         text = cls.text = Text(frame)
         text.insert('1.0', code_sample)
-        # Need to pack for creation of code context label widget.
+        # Need to pack for creation of code context text widget.
         frame.pack(side='left', fill='both', expand=1)
         text.pack(side='top', fill='both', expand=1)
         cls.editor = DummyEditwin(root, frame, text)
@@ -75,11 +75,11 @@ def setUp(self):
         self.cc = codecontext.CodeContext(self.editor)
 
     def tearDown(self):
-        if self.cc.label:
-            self.cc.label.destroy()
+        if self.cc.context:
+            self.cc.context.destroy()
         # Explicitly call __del__ to remove scheduled scripts.
         self.cc.__del__()
-        del self.cc.label, self.cc
+        del self.cc.context, self.cc
 
     def test_init(self):
         eq = self.assertEqual
@@ -89,7 +89,7 @@ def test_init(self):
         eq(cc.editwin, ed)
         eq(cc.text, ed.text)
         eq(cc.textfont, ed.text['font'])
-        self.assertIsNone(cc.label)
+        self.assertIsNone(cc.context)
         eq(cc.info, [(0, -1, '', False)])
         eq(cc.topvisible, 1)
         eq(self.root.tk.call('after', 'info', self.cc.t1)[1], 'timer')
@@ -120,20 +120,20 @@ def test_toggle_code_context_event(self):
         toggle = cc.toggle_code_context_event
 
         # Make sure code context is off.
-        if cc.label:
+        if cc.context:
             toggle()
 
         # Toggle on.
         eq(toggle(), 'break')
-        self.assertIsNotNone(cc.label)
-        eq(cc.label['font'], cc.textfont)
-        eq(cc.label['fg'], cc.colors['foreground'])
-        eq(cc.label['bg'], cc.colors['background'])
-        eq(cc.label['text'], '')
+        self.assertIsNotNone(cc.context)
+        eq(cc.context['font'], cc.textfont)
+        eq(cc.context['fg'], cc.colors['foreground'])
+        eq(cc.context['bg'], cc.colors['background'])
+        eq(cc.context.get('1.0', 'end-1c'), '')
 
         # Toggle off.
         eq(toggle(), 'break')
-        self.assertIsNone(cc.label)
+        self.assertIsNone(cc.context)
 
     def test_get_context(self):
         eq = self.assertEqual
@@ -187,7 +187,7 @@ def test_update_code_context(self):
         eq = self.assertEqual
         cc = self.cc
         # Ensure code context is active.
-        if not cc.label:
+        if not cc.context:
             cc.toggle_code_context_event()
 
         # Invoke update_code_context without scrolling - nothing happens.
@@ -200,21 +200,21 @@ def test_update_code_context(self):
         cc.update_code_context()
         eq(cc.info, [(0, -1, '', False)])
         eq(cc.topvisible, 2)
-        eq(cc.label['text'], '')
+        eq(cc.context.get('1.0', 'end-1c'), '')
 
         # Scroll down to line 2.
         cc.text.yview(2)
         cc.update_code_context()
         eq(cc.info, [(0, -1, '', False), (2, 0, 'class C1():', 'class')])
         eq(cc.topvisible, 3)
-        eq(cc.label['text'], 'class C1():')
+        eq(cc.context.get('1.0', 'end-1c'), 'class C1():')
 
         # Scroll down to line 3.  Since it's a comment, nothing changes.
         cc.text.yview(3)
         cc.update_code_context()
         eq(cc.info, [(0, -1, '', False), (2, 0, 'class C1():', 'class')])
         eq(cc.topvisible, 4)
-        eq(cc.label['text'], 'class C1():')
+        eq(cc.context.get('1.0', 'end-1c'), 'class C1():')
 
         # Scroll down to line 4.
         cc.text.yview(4)
@@ -223,7 +223,7 @@ def test_update_code_context(self):
                      (2, 0, 'class C1():', 'class'),
                      (4, 4, '    def __init__(self, a, b):', 'def')])
         eq(cc.topvisible, 5)
-        eq(cc.label['text'], 'class C1():\n'
+        eq(cc.context.get('1.0', 'end-1c'), 'class C1():\n'
                              '    def __init__(self, a, b):')
 
         # Scroll down to line 11.  Last 'def' is removed.
@@ -235,7 +235,7 @@ def test_update_code_context(self):
                      (8, 8, '        if a > b:', 'if'),
                      (10, 8, '        elif a < b:', 'elif')])
         eq(cc.topvisible, 12)
-        eq(cc.label['text'], 'class C1():\n'
+        eq(cc.context.get('1.0', 'end-1c'), 'class C1():\n'
                              '    def compare(self):\n'
                              '        if a > b:\n'
                              '        elif a < b:')
@@ -249,7 +249,7 @@ def test_update_code_context(self):
                      (8, 8, '        if a > b:', 'if'),
                      (10, 8, '        elif a < b:', 'elif')])
         eq(cc.topvisible, 12)
-        eq(cc.label['text'], 'class C1():\n'
+        eq(cc.context.get('1.0', 'end-1c'), 'class C1():\n'
                              '    def compare(self):\n'
                              '        if a > b:\n'
                              '        elif a < b:')
@@ -262,12 +262,12 @@ def test_update_code_context(self):
                      (4, 4, '    def __init__(self, a, b):', 'def')])
         eq(cc.topvisible, 6)
         # context_depth is 1.
-        eq(cc.label['text'], '    def __init__(self, a, b):')
+        eq(cc.context.get('1.0', 'end-1c'), '    def __init__(self, a, b):')
 
     @mock.patch.object(codecontext.CodeContext, 'update_code_context')
     def test_timer_event(self, mock_update):
         # Ensure code context is not active.
-        if self.cc.label:
+        if self.cc.context:
             self.cc.toggle_code_context_event()
         self.cc.timer_event()
         mock_update.assert_not_called()
@@ -286,7 +286,7 @@ def test_config_timer_event(self):
         test_colors = {'background': '#222222', 'foreground': '#ffff00'}
 
         # Ensure code context is not active.
-        if cc.label:
+        if cc.context:
             cc.toggle_code_context_event()
 
         # Nothing updates on inactive code context.
@@ -303,18 +303,18 @@ def test_config_timer_event(self):
         cc.config_timer_event()
         eq(cc.textfont, save_font)
         eq(cc.contextcolors, save_colors)
-        eq(cc.label['font'], save_font)
-        eq(cc.label['background'], save_colors['background'])
-        eq(cc.label['foreground'], save_colors['foreground'])
+        eq(cc.context['font'], save_font)
+        eq(cc.context['background'], save_colors['background'])
+        eq(cc.context['foreground'], save_colors['foreground'])
 
         # Active code context, change font.
         cc.text['font'] = test_font
         cc.config_timer_event()
         eq(cc.textfont, test_font)
         eq(cc.contextcolors, save_colors)
-        eq(cc.label['font'], test_font)
-        eq(cc.label['background'], save_colors['background'])
-        eq(cc.label['foreground'], save_colors['foreground'])
+        eq(cc.context['font'], test_font)
+        eq(cc.context['background'], save_colors['background'])
+        eq(cc.context['foreground'], save_colors['foreground'])
 
         # Active code context, change color.
         cc.text['font'] = save_font
@@ -322,9 +322,9 @@ def test_config_timer_event(self):
         cc.config_timer_event()
         eq(cc.textfont, save_font)
         eq(cc.contextcolors, test_colors)
-        eq(cc.label['font'], save_font)
-        eq(cc.label['background'], test_colors['background'])
-        eq(cc.label['foreground'], test_colors['foreground'])
+        eq(cc.context['font'], save_font)
+        eq(cc.context['background'], test_colors['background'])
+        eq(cc.context['foreground'], test_colors['foreground'])
         codecontext.CodeContext.colors = save_colors
         cc.config_timer_event()
 
diff --git a/Misc/NEWS.d/next/IDLE/2018-06-03-20-12-57.bpo-33763.URiFlE.rst b/Misc/NEWS.d/next/IDLE/2018-06-03-20-12-57.bpo-33763.URiFlE.rst
new file mode 100644
index 000000000000..187ef650cb73
--- /dev/null
+++ b/Misc/NEWS.d/next/IDLE/2018-06-03-20-12-57.bpo-33763.URiFlE.rst
@@ -0,0 +1 @@
+IDLE: Use read-only text widget for code context instead of label widget.



More information about the Python-checkins mailing list