mirror of
https://github.com/python/cpython.git
synced 2025-08-19 08:11:46 +00:00
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:
parent
6ad0a2c45f
commit
9c2654d1aa
7 changed files with 78 additions and 21 deletions
|
@ -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
|
bpo-35771: To avoid occasional spurious test_idle failures on slower
|
||||||
machines, increase the ``hover_delay`` in test_tooltip.
|
machines, increase the ``hover_delay`` in test_tooltip.
|
||||||
|
|
||||||
|
|
|
@ -26,6 +26,7 @@ from idlelib import pyparse
|
||||||
from idlelib import query
|
from idlelib import query
|
||||||
from idlelib import replace
|
from idlelib import replace
|
||||||
from idlelib import search
|
from idlelib import search
|
||||||
|
from idlelib.tree import wheel_event
|
||||||
from idlelib import window
|
from idlelib import window
|
||||||
|
|
||||||
# The default tab setting for a Text widget, in average-width characters.
|
# The default tab setting for a Text widget, in average-width characters.
|
||||||
|
@ -151,9 +152,10 @@ class EditorWindow(object):
|
||||||
else:
|
else:
|
||||||
# Elsewhere, use right-click for popup menus.
|
# Elsewhere, use right-click for popup menus.
|
||||||
text.bind("<3>",self.right_menu_event)
|
text.bind("<3>",self.right_menu_event)
|
||||||
text.bind('<MouseWheel>', self.mousescroll)
|
|
||||||
text.bind('<Button-4>', self.mousescroll)
|
text.bind('<MouseWheel>', wheel_event)
|
||||||
text.bind('<Button-5>', self.mousescroll)
|
text.bind('<Button-4>', wheel_event)
|
||||||
|
text.bind('<Button-5>', wheel_event)
|
||||||
text.bind('<Configure>', self.handle_winconfig)
|
text.bind('<Configure>', self.handle_winconfig)
|
||||||
text.bind("<<cut>>", self.cut)
|
text.bind("<<cut>>", self.cut)
|
||||||
text.bind("<<copy>>", self.copy)
|
text.bind("<<copy>>", self.copy)
|
||||||
|
@ -502,23 +504,6 @@ class EditorWindow(object):
|
||||||
self.text.yview(event, *args)
|
self.text.yview(event, *args)
|
||||||
return 'break'
|
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
|
rmenu = None
|
||||||
|
|
||||||
def right_menu_event(self, event):
|
def right_menu_event(self, event):
|
||||||
|
|
|
@ -35,6 +35,14 @@ class MultiCallTest(unittest.TestCase):
|
||||||
mctext = self.mc(self.root)
|
mctext = self.mc(self.root)
|
||||||
self.assertIsInstance(mctext._MultiCall__binders, list)
|
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__':
|
if __name__ == '__main__':
|
||||||
unittest.main(verbosity=2)
|
unittest.main(verbosity=2)
|
||||||
|
|
|
@ -4,7 +4,7 @@ from idlelib import tree
|
||||||
import unittest
|
import unittest
|
||||||
from test.support import requires
|
from test.support import requires
|
||||||
requires('gui')
|
requires('gui')
|
||||||
from tkinter import Tk
|
from tkinter import Tk, EventType, SCROLL
|
||||||
|
|
||||||
|
|
||||||
class TreeTest(unittest.TestCase):
|
class TreeTest(unittest.TestCase):
|
||||||
|
@ -29,5 +29,32 @@ class TreeTest(unittest.TestCase):
|
||||||
node.expand()
|
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__':
|
if __name__ == '__main__':
|
||||||
unittest.main(verbosity=2)
|
unittest.main(verbosity=2)
|
||||||
|
|
|
@ -56,6 +56,30 @@ def listicons(icondir=ICONDIR):
|
||||||
column = 0
|
column = 0
|
||||||
root.images = images
|
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:
|
class TreeNode:
|
||||||
|
|
||||||
|
@ -260,6 +284,9 @@ class TreeNode:
|
||||||
anchor="nw", window=self.label)
|
anchor="nw", window=self.label)
|
||||||
self.label.bind("<1>", self.select_or_edit)
|
self.label.bind("<1>", self.select_or_edit)
|
||||||
self.label.bind("<Double-1>", self.flip)
|
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
|
self.text_id = id
|
||||||
|
|
||||||
def select_or_edit(self, event=None):
|
def select_or_edit(self, event=None):
|
||||||
|
@ -410,6 +437,7 @@ class FileTreeItem(TreeItem):
|
||||||
# A canvas widget with scroll bars and some useful bindings
|
# A canvas widget with scroll bars and some useful bindings
|
||||||
|
|
||||||
class ScrolledCanvas:
|
class ScrolledCanvas:
|
||||||
|
|
||||||
def __init__(self, master, **opts):
|
def __init__(self, master, **opts):
|
||||||
if 'yscrollincrement' not in opts:
|
if 'yscrollincrement' not in opts:
|
||||||
opts['yscrollincrement'] = 17
|
opts['yscrollincrement'] = 17
|
||||||
|
@ -431,6 +459,9 @@ class ScrolledCanvas:
|
||||||
self.canvas.bind("<Key-Next>", self.page_down)
|
self.canvas.bind("<Key-Next>", self.page_down)
|
||||||
self.canvas.bind("<Key-Up>", self.unit_up)
|
self.canvas.bind("<Key-Up>", self.unit_up)
|
||||||
self.canvas.bind("<Key-Down>", self.unit_down)
|
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):
|
#if isinstance(master, Toplevel) or isinstance(master, Tk):
|
||||||
self.canvas.bind("<Alt-Key-2>", self.zoom_height)
|
self.canvas.bind("<Alt-Key-2>", self.zoom_height)
|
||||||
self.canvas.focus_set()
|
self.canvas.focus_set()
|
||||||
|
|
|
@ -1863,6 +1863,7 @@ Nickolai Zeldovich
|
||||||
Yuxiao Zeng
|
Yuxiao Zeng
|
||||||
Uwe Zessin
|
Uwe Zessin
|
||||||
Cheng Zhang
|
Cheng Zhang
|
||||||
|
George Zhang
|
||||||
Kai Zhu
|
Kai Zhu
|
||||||
Tarek Ziadé
|
Tarek Ziadé
|
||||||
Jelle Zijlstra
|
Jelle Zijlstra
|
||||||
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
Add mousewheel scrolling for IDLE module, path, and stack browsers.
|
||||||
|
Patch by George Zhang.
|
Loading…
Add table
Add a link
Reference in a new issue