Commit 2cd90258 authored by GeeTransit's avatar GeeTransit Committed by Terry Jan Reedy

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

Modify the wheel event handler so it can also be used for module, path, and stack browsers.
Patch by George Zhang.
parent 87bd2071
......@@ -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.
......
......@@ -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):
......
......@@ -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)
......@@ -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)
......@@ -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()
......
......@@ -1871,6 +1871,7 @@ Nickolai Zeldovich
Yuxiao Zeng
Uwe Zessin
Cheng Zhang
George Zhang
Kai Zhu
Tarek Ziadé
Jelle Zijlstra
......
Add mousewheel scrolling for IDLE module, path, and stack browsers.
Patch by George Zhang.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment