8000 bpo-37706: IDLE - fix sidebar code bug and drag tests (GH-15103) · python/cpython@1d2b4db · GitHub
[go: up one dir, main page]

Skip to content

Commit 1d2b4db

Browse files
bpo-37706: IDLE - fix sidebar code bug and drag tests (GH-15103)
Convert mouse y to line number in the sidebar rather than the text. (cherry picked from commit 86f1a18) Co-authored-by: Tal Einat <taleinat+github@gmail.com>
1 parent dd5f8ab commit 1d2b4db

File tree

3 files changed

+61
-35
lines changed

3 files changed

+61
-35
lines changed

Lib/idlelib/idle_test/htest.py

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -210,13 +210,20 @@ def _wrapper(parent): # htest #
210210
'file': 'sidebar',
211211
'kwds': {},
212212
'msg': textwrap.dedent("""\
213-
Click on the line numbers and drag down below the edge of the
213+
1. Click on the line numbers and drag down below the edge of the
214214
window, moving the mouse a bit and then leaving it there for a while.
215215
The text and line numbers should gradually scroll down, with the
216216
selection updated continuously.
217-
Do the same as above, dragging to above the window. The text and line
217+
218+
2. With the lines still selected, click on a line number above the
219+
selected lines. Only the line whose number was clicked should be
220+
selected.
221+
222+
3. Repeat step #1, dragging to above the window. The text and line
218223
numbers should gradually scroll up, with the selection updated
219-
continuously."""),
224+
continuously.
225+
226+
4. Repeat step #2, clicking a line number below the selection."""),
220227
}
221228

222229
_multi_call_spec = {

Lib/idlelib/idle_test/test_sidebar.py

Lines changed: 27 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -240,7 +240,6 @@ def get_width():
240240
self.assert_sidebar_n_lines(1)
241241
self.assertEqual(get_width(), 1)
242242

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

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

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

263-
# Drag from the second line to the fourth line.
264-
start_x, start_y = self.get_line_screen_position(2)
265-
end_x, end_y = self.get_line_screen_position(4)
266260
self.linenumber.sidebar_text.event_generate('<Button-1>',
267261
x=start_x, y=start_y)
268-
self.linenumber.sidebar_text.event_generate('<B1-Motion>',
269-
x=start_x, y=start_y)
270-
self.linenumber.sidebar_text.event_generate('<B1-Motion>',
271-
x=end_x, y=end_y)
262+
self.root.update()
263+
264+
def lerp(a, b, steps):
265+
"""linearly interpolate from a to b (inclusive) in equal steps"""
266+
last_step = steps - 1
267+
for i in range(steps):
268+
yield ((last_step - i) / last_step) * a + (i / last_step) * b
269+
270+
for x, y in zip(
271+
map(int, lerp(start_x, end_x, steps=11)),
272+
map(int, lerp(start_y, end_y, steps=11)),
273+
):
274+
self.linenumber.sidebar_text.event_generate('<B1-Motion>', x=x, y=y)
275+
self.root.update()
276+
272277
self.linenumber.sidebar_text.event_generate('<ButtonRelease-1>',
273278
x=end_x, y=end_y)
274279
self.root.update()
280+
281+
def test_drag_selection_down(self):
282+
self.linenumber.show_sidebar()
283+
self.text.insert('1.0', 'one\ntwo\nthree\nfour\nfive\n')
284+
self.root.update()
285+
286+
# Drag from the second line to the fourth line.
287+
self.simulate_drag(2, 4)
275288
self.assertEqual(self.get_selection(), ('2.0', '5.0'))
276289

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

283295
# Drag from the fourth line to the second line.
284-
start_x, start_y = self.get_line_screen_position(4)
285-
end_x, end_y = self.get_line_screen_position(2)
286-
self.linenumber.sidebar_text.event_generate('<Button-1>',
287-
x=start_x, y=start_y)
288-
self.linenumber.sidebar_text.event_generate('<B1-Motion>',
289-
x=start_x, y=start_y)
290-
self.linenumber.sidebar_text.event_generate('<B1-Motion>',
291-
x=end_x, y=end_y)
292-
self.linenumber.sidebar_text.event_generate('<ButtonRelease-1>',
293-
x=end_x, y=end_y)
294-
self.root.update()
296+
self.simulate_drag(4, 2)
295297
self.assertEqual(self.get_selection(), ('2.0', '5.0'))
296298

297299
def test_scroll(self):

Lib/idlelib/sidebar.py

Lines changed: 24 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -204,10 +204,19 @@ def bind_mouse_event(event_name, target_event_name):
204204
bind_mouse_event(event_name,
205205
target_event_name=f'<Button-{button}>')
206206

207+
# This is set by b1_mousedown_handler() and read by
208+
# drag_update_selection_and_insert_mark(), to know where dragging
209+
# began.
207210
start_line = None
211+
# These are set by b1_motion_handler() and read by selection_handler().
212+
# last_y is passed this way since the mouse Y-coordinate is not
213+
# available on selection event objects. last_yview is passed this way
214+
# to recognize scrolling while the mouse isn't moving.
215+
last_y = last_yview = None
216+
208217
def b1_mousedown_handler(event):
209218
# select the entire line
210-
lineno = self.editwin.getlineno(f"@0,{event.y}")
219+
lineno = int(float(self.sidebar_text.index(f"@0,{event.y}")))
211220
self.text.tag_remove("sel", "1.0", "end")
212221
self.text.tag_add("sel", f"{lineno}.0", f"{lineno+1}.0")
213222
self.text.mark_set("insert", f"{lineno+1}.0")
@@ -217,15 +226,20 @@ def b1_mousedown_handler(event):
217226
start_line = lineno
218227
self.sidebar_text.bind('<Button-1>', b1_mousedown_handler)
219228

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

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

0 commit comments

Comments
 (0)
0