bpo-37902: IDLE: Add scrolling for IDLE browsers. (GH-15368)

Modify the wheel event handler so it can also be used for module, path, and stack browsers.
Patch by George Zhang.
(cherry picked from commit 2cd9025858)

Co-authored-by: GeeTransit <geetransit@gmail.com>
This commit is contained in:
Miss Islington (bot) 2019-09-04 18:53:47 -07:00 committed by GitHub
parent 6ad0a2c45f
commit 9c2654d1aa
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 78 additions and 21 deletions

View File

@ -3,6 +3,9 @@ Released on 2019-10-20?
======================================
bpo-37092: Add mousewheel scrolling for IDLE module, path, and stack
browsers. Patch by George Zhang.
bpo-35771: To avoid occasional spurious test_idle failures on slower
machines, increase the ``hover_delay`` in test_tooltip.

View File

@ -26,6 +26,7 @@ from idlelib import pyparse
from idlelib import query
from idlelib import replace
from idlelib import search
from idlelib.tree import wheel_event
from idlelib import window
# The default tab setting for a Text widget, in average-width characters.
@ -151,9 +152,10 @@ class EditorWindow(object):
else:
# Elsewhere, use right-click for popup menus.
text.bind("<3>",self.right_menu_event)
text.bind('<MouseWheel>', self.mousescroll)
text.bind('<Button-4>', self.mousescroll)
text.bind('<Button-5>', self.mousescroll)
text.bind('<MouseWheel>', wheel_event)
text.bind('<Button-4>', wheel_event)
text.bind('<Button-5>', wheel_event)
text.bind('<Configure>', self.handle_winconfig)
text.bind("<<cut>>", self.cut)
text.bind("<<copy>>", self.copy)
@ -502,23 +504,6 @@ class EditorWindow(object):
self.text.yview(event, *args)
return 'break'
def mousescroll(self, event):
"""Handle scrollwheel event.
For wheel up, event.delta = 120*n on Windows, -1*n on darwin,
where n can be > 1 if one scrolls fast. Flicking the wheel
generates up to maybe 20 events with n up to 10 or more 1.
Macs use wheel down (delta = 1*n) to scroll up, so positive
delta means to scroll up on both systems.
X-11 sends Control-Button-4 event instead.
"""
up = {EventType.MouseWheel: event.delta > 0,
EventType.Button: event.num == 4}
lines = -5 if up[event.type] else 5
self.text.yview_scroll(lines, 'units')
return 'break'
rmenu = None
def right_menu_event(self, event):

View File

@ -35,6 +35,14 @@ class MultiCallTest(unittest.TestCase):
mctext = self.mc(self.root)
self.assertIsInstance(mctext._MultiCall__binders, list)
def test_yview(self):
# Added for tree.wheel_event
# (it depends on yview to not be overriden)
mc = self.mc
self.assertIs(mc.yview, Text.yview)
mctext = self.mc(self.root)
self.assertIs(mctext.yview.__func__, Text.yview)
if __name__ == '__main__':
unittest.main(verbosity=2)

View File

@ -4,7 +4,7 @@ from idlelib import tree
import unittest
from test.support import requires
requires('gui')
from tkinter import Tk
from tkinter import Tk, EventType, SCROLL
class TreeTest(unittest.TestCase):
@ -29,5 +29,32 @@ class TreeTest(unittest.TestCase):
node.expand()
class TestScrollEvent(unittest.TestCase):
def test_wheel_event(self):
# Fake widget class containing `yview` only.
class _Widget:
def __init__(widget, *expected):
widget.expected = expected
def yview(widget, *args):
self.assertTupleEqual(widget.expected, args)
# Fake event class
class _Event:
pass
# (type, delta, num, amount)
tests = ((EventType.MouseWheel, 120, -1, -5),
(EventType.MouseWheel, -120, -1, 5),
(EventType.ButtonPress, -1, 4, -5),
(EventType.ButtonPress, -1, 5, 5))
event = _Event()
for ty, delta, num, amount in tests:
event.type = ty
event.delta = delta
event.num = num
res = tree.wheel_event(event, _Widget(SCROLL, amount, "units"))
self.assertEqual(res, "break")
if __name__ == '__main__':
unittest.main(verbosity=2)

View File

@ -56,6 +56,30 @@ def listicons(icondir=ICONDIR):
column = 0
root.images = images
def wheel_event(event, widget=None):
"""Handle scrollwheel event.
For wheel up, event.delta = 120*n on Windows, -1*n on darwin,
where n can be > 1 if one scrolls fast. Flicking the wheel
generates up to maybe 20 events with n up to 10 or more 1.
Macs use wheel down (delta = 1*n) to scroll up, so positive
delta means to scroll up on both systems.
X-11 sends Control-Button-4,5 events instead.
The widget parameter is needed so browser label bindings can pass
the underlying canvas.
This function depends on widget.yview to not be overridden by
a subclass.
"""
up = {EventType.MouseWheel: event.delta > 0,
EventType.ButtonPress: event.num == 4}
lines = -5 if up[event.type] else 5
widget = event.widget if widget is None else widget
widget.yview(SCROLL, lines, 'units')
return 'break'
class TreeNode:
@ -260,6 +284,9 @@ class TreeNode:
anchor="nw", window=self.label)
self.label.bind("<1>", self.select_or_edit)
self.label.bind("<Double-1>", self.flip)
self.label.bind("<MouseWheel>", lambda e: wheel_event(e, self.canvas))
self.label.bind("<Button-4>", lambda e: wheel_event(e, self.canvas))
self.label.bind("<Button-5>", lambda e: wheel_event(e, self.canvas))
self.text_id = id
def select_or_edit(self, event=None):
@ -410,6 +437,7 @@ class FileTreeItem(TreeItem):
# A canvas widget with scroll bars and some useful bindings
class ScrolledCanvas:
def __init__(self, master, **opts):
if 'yscrollincrement' not in opts:
opts['yscrollincrement'] = 17
@ -431,6 +459,9 @@ class ScrolledCanvas:
self.canvas.bind("<Key-Next>", self.page_down)
self.canvas.bind("<Key-Up>", self.unit_up)
self.canvas.bind("<Key-Down>", self.unit_down)
self.canvas.bind("<MouseWheel>", wheel_event)
self.canvas.bind("<Button-4>", wheel_event)
self.canvas.bind("<Button-5>", wheel_event)
#if isinstance(master, Toplevel) or isinstance(master, Tk):
self.canvas.bind("<Alt-Key-2>", self.zoom_height)
self.canvas.focus_set()

View File

@ -1863,6 +1863,7 @@ Nickolai Zeldovich
Yuxiao Zeng
Uwe Zessin
Cheng Zhang
George Zhang
Kai Zhu
Tarek Ziadé
Jelle Zijlstra

View File

@ -0,0 +1,2 @@
Add mousewheel scrolling for IDLE module, path, and stack browsers.
Patch by George Zhang.