Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[3.7] bpo-37706: IDLE - fix sidebar code bug and drag tests (GH-15103) #15108

Merged
merged 1 commit into from
Aug 4, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 10 additions & 3 deletions Lib/idlelib/idle_test/htest.py
Original file line number Diff line number Diff line change
Expand Up @@ -210,13 +210,20 @@ def _wrapper(parent): # htest #
'file': 'sidebar',
'kwds': {},
'msg': textwrap.dedent("""\
Click on the line numbers and drag down below the edge of the
1. Click on the line numbers and drag down below the edge of the
window, moving the mouse a bit and then leaving it there for a while.
The text and line numbers should gradually scroll down, with the
selection updated continuously.
Do the same as above, dragging to above the window. The text and line

2. With the lines still selected, click on a line number above the
selected lines. Only the line whose number was clicked should be
selected.

3. Repeat step #1, dragging to above the window. The text and line
numbers should gradually scroll up, with the selection updated
continuously."""),
continuously.

4. Repeat step #2, clicking a line number below the selection."""),
}

_multi_call_spec = {
Expand Down
52 changes: 27 additions & 25 deletions Lib/idlelib/idle_test/test_sidebar.py
Original file line number Diff line number Diff line change
Expand Up @@ -240,7 +240,6 @@ def get_width():
self.assert_sidebar_n_lines(1)
self.assertEqual(get_width(), 1)

@unittest.skipIf(platform == 'darwin', 'test tk version dependent')
def test_click_selection(self):
self.linenumber.show_sidebar()
self.text.insert('1.0', 'one\ntwo\nthree\nfour\n')
Expand All @@ -254,44 +253,47 @@ def test_click_selection(self):

self.assertEqual(self.get_selection(), ('2.0', '3.0'))

@unittest.skipIf(platform == 'darwin', 'test tk version dependent')
def test_drag_selection_down(self):
self.linenumber.show_sidebar()
self.text.insert('1.0', 'one\ntwo\nthree\nfour\nfive\n')
self.root.update()
def simulate_drag(self, start_line, end_line):
start_x, start_y = self.get_line_screen_position(start_line)
end_x, end_y = self.get_line_screen_position(end_line)

# Drag from the second line to the fourth line.
start_x, start_y = self.get_line_screen_position(2)
end_x, end_y = self.get_line_screen_position(4)
self.linenumber.sidebar_text.event_generate('<Button-1>',
x=start_x, y=start_y)
self.linenumber.sidebar_text.event_generate('<B1-Motion>',
x=start_x, y=start_y)
self.linenumber.sidebar_text.event_generate('<B1-Motion>',
x=end_x, y=end_y)
self.root.update()

def lerp(a, b, steps):
"""linearly interpolate from a to b (inclusive) in equal steps"""
last_step = steps - 1
for i in range(steps):
yield ((last_step - i) / last_step) * a + (i / last_step) * b

for x, y in zip(
map(int, lerp(start_x, end_x, steps=11)),
map(int, lerp(start_y, end_y, steps=11)),
):
self.linenumber.sidebar_text.event_generate('<B1-Motion>', x=x, y=y)
self.root.update()

self.linenumber.sidebar_text.event_generate('<ButtonRelease-1>',
x=end_x, y=end_y)
self.root.update()

def test_drag_selection_down(self):
self.linenumber.show_sidebar()
self.text.insert('1.0', 'one\ntwo\nthree\nfour\nfive\n')
self.root.update()

# Drag from the second line to the fourth line.
self.simulate_drag(2, 4)
self.assertEqual(self.get_selection(), ('2.0', '5.0'))

@unittest.skipIf(platform == 'darwin', 'test tk version dependent')
def test_drag_selection_up(self):
self.linenumber.show_sidebar()
self.text.insert('1.0', 'one\ntwo\nthree\nfour\nfive\n')
self.root.update()

# Drag from the fourth line to the second line.
start_x, start_y = self.get_line_screen_position(4)
end_x, end_y = self.get_line_screen_position(2)
self.linenumber.sidebar_text.event_generate('<Button-1>',
x=start_x, y=start_y)
self.linenumber.sidebar_text.event_generate('<B1-Motion>',
x=start_x, y=start_y)
self.linenumber.sidebar_text.event_generate('<B1-Motion>',
x=end_x, y=end_y)
self.linenumber.sidebar_text.event_generate('<ButtonRelease-1>',
x=end_x, y=end_y)
self.root.update()
self.simulate_drag(4, 2)
self.assertEqual(self.get_selection(), ('2.0', '5.0'))

def test_scroll(self):
Expand Down
31 changes: 24 additions & 7 deletions Lib/idlelib/sidebar.py
Original file line number Diff line number Diff line change
Expand Up @@ -204,10 +204,19 @@ def bind_mouse_event(event_name, target_event_name):
bind_mouse_event(event_name,
target_event_name=f'<Button-{button}>')

# This is set by b1_mousedown_handler() and read by
# drag_update_selection_and_insert_mark(), to know where dragging
# began.
start_line = None
# These are set by b1_motion_handler() and read by selection_handler().
# last_y is passed this way since the mouse Y-coordinate is not
# available on selection event objects. last_yview is passed this way
# to recognize scrolling while the mouse isn't moving.
last_y = last_yview = None

def b1_mousedown_handler(event):
# select the entire line
lineno = self.editwin.getlineno(f"@0,{event.y}")
lineno = int(float(self.sidebar_text.index(f"@0,{event.y}")))
self.text.tag_remove("sel", "1.0", "end")
self.text.tag_add("sel", f"{lineno}.0", f"{lineno+1}.0")
self.text.mark_set("insert", f"{lineno+1}.0")
Expand All @@ -217,15 +226,20 @@ def b1_mousedown_handler(event):
start_line = lineno
self.sidebar_text.bind('<Button-1>', b1_mousedown_handler)

# These are set by b1_motion_handler() and read by selection_handler();
# see below. last_y is passed this way since the mouse Y-coordinate
# is not available on selection event objects. last_yview is passed
# this way to recognize scrolling while the mouse isn't moving.
last_y = last_yview = None
def b1_mouseup_handler(event):
# On mouse up, we're no longer dragging. Set the shared persistent
# variables to None to represent this.
nonlocal start_line
nonlocal last_y
nonlocal last_yview
start_line = None
last_y = None
last_yview = None
self.sidebar_text.bind('<ButtonRelease-1>', b1_mouseup_handler)

def drag_update_selection_and_insert_mark(y_coord):
"""Helper function for drag and selection event handlers."""
lineno = self.editwin.getlineno(f"@0,{y_coord}")
lineno = int(float(self.sidebar_text.index(f"@0,{y_coord}")))
a, b = sorted([start_line, lineno])
self.text.tag_remove("sel", "1.0", "end")
self.text.tag_add("sel", f"{a}.0", f"{b+1}.0")
Expand Down Expand Up @@ -253,6 +267,9 @@ def b1_drag_handler(event, *args):
# while the mouse isn't moving, leading to the above fix not scrolling
# properly.
def selection_handler(event):
if last_yview is None:
# This logic is only needed while dragging.
return
yview = self.sidebar_text.yview()
if yview != last_yview:
self.text.yview_moveto(yview[0])
Expand Down