Skip to content

Commit

Permalink
bpo-37902: IDLE: Add scrolling for IDLE browsers. (#15368)
Browse files Browse the repository at this point in the history
Modify the wheel event handler so it can also be used for module, path, and stack browsers.
Patch by George Zhang.
  • Loading branch information
GeeTransit authored and terryjreedy committed Sep 5, 2019
1 parent 87bd207 commit 2cd9025
Show file tree
Hide file tree
Showing 7 changed files with 78 additions and 21 deletions.
3 changes: 3 additions & 0 deletions Lib/idlelib/NEWS.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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.

Expand Down
25 changes: 5 additions & 20 deletions Lib/idlelib/editor.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
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.
Expand Down Expand Up @@ -151,9 +152,10 @@ def __init__(self, flist=None, filename=None, key=None, root=None):
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)
Expand Down Expand Up @@ -502,23 +504,6 @@ def handle_yview(self, event, *args):
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):
Expand Down
8 changes: 8 additions & 0 deletions Lib/idlelib/idle_test/test_multicall.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,14 @@ def test_init(self):
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)
29 changes: 28 additions & 1 deletion Lib/idlelib/idle_test/test_tree.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import unittest
from test.support import requires
requires('gui')
from tkinter import Tk
from tkinter import Tk, EventType, SCROLL


class TreeTest(unittest.TestCase):
Expand All @@ -29,5 +29,32 @@ def test_init(self):
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)
31 changes: 31 additions & 0 deletions Lib/idlelib/tree.py
Original file line number Diff line number Diff line change
Expand Up @@ -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:

Expand Down Expand Up @@ -260,6 +284,9 @@ def drawtext(self):
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):
Expand Down Expand Up @@ -410,6 +437,7 @@ def GetSubList(self):
# 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
Expand All @@ -431,6 +459,9 @@ def __init__(self, master, **opts):
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()
Expand Down
1 change: 1 addition & 0 deletions Misc/ACKS
Original file line number Diff line number Diff line change
Expand Up @@ -1871,6 +1871,7 @@ Nickolai Zeldovich
Yuxiao Zeng
Uwe Zessin
Cheng Zhang
George Zhang
Kai Zhu
Tarek Ziadé
Jelle Zijlstra
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Add mousewheel scrolling for IDLE module, path, and stack browsers.
Patch by George Zhang.

0 comments on commit 2cd9025

Please sign in to comment.