diff kitten: Fix images losing position when scrolling using mouse wheel/touchpad

This commit is contained in:
Kovid Goyal 2020-03-19 18:46:10 +05:30
parent e2339697b9
commit eddd45bbc3
No known key found for this signature in database
GPG Key ID: 06BC317B515ACE7C
3 changed files with 57 additions and 4 deletions

View File

@ -88,6 +88,12 @@ To update |kitty|, :doc:`follow the instructions <binary>`.
- Wayland: Fix a crash when drag and dropping into kitty (:iss:`2432`) - Wayland: Fix a crash when drag and dropping into kitty (:iss:`2432`)
- diff kitten: Fix images lingering as blank rectangles after the kitten quits
(:iss:`2449`)
- diff kitten: Fix images losing position when scrolling using mouse
wheel/touchpad
0.16.0 [2020-01-28] 0.16.0 [2020-01-28]
-------------------- --------------------

View File

@ -36,7 +36,7 @@ from .render import (
) )
from .search import BadRegex, Search from .search import BadRegex, Search
from ..tui.handler import Handler from ..tui.handler import Handler
from ..tui.images import ImageManager from ..tui.images import ImageManager, Placement
from ..tui.line_edit import LineEdit from ..tui.line_edit import LineEdit
from ..tui.loop import Loop from ..tui.loop import Loop
from ..tui.operations import styled from ..tui.operations import styled
@ -322,7 +322,43 @@ class DiffHandler(Handler):
if image_involved: if image_involved:
self.place_images() self.place_images()
def update_image_placement_for_resend(self, image_id: int, pl: Placement) -> bool:
offset = self.scroll_pos
limit = len(self.diff_lines)
in_image = False
def adjust(row: int, candidate: ImagePlacement, is_left: bool) -> bool:
if candidate.image.image_id == image_id:
q = self.xpos_for_image(row, candidate, is_left)
if q is not None:
pl['x'] = q[0]
pl['y'] = row
return True
return False
for row in range(self.num_lines):
lpos = offset + row
if lpos >= limit:
break
line = self.diff_lines[lpos]
if in_image:
if line.image_data is None:
in_image = False
continue
if line.image_data is not None:
left_placement, right_placement = line.image_data
if left_placement is not None:
if adjust(row, left_placement, True):
return True
in_image = True
if right_placement is not None:
if adjust(row, right_placement, False):
return True
in_image = True
return False
def place_images(self) -> None: def place_images(self) -> None:
self.image_manager.update_image_placement_for_resend = self.update_image_placement_for_resend
self.cmd.clear_images_on_screen() self.cmd.clear_images_on_screen()
offset = self.scroll_pos offset = self.scroll_pos
limit = len(self.diff_lines) limit = len(self.diff_lines)
@ -345,13 +381,20 @@ class DiffHandler(Handler):
self.place_image(row, right_placement, False) self.place_image(row, right_placement, False)
in_image = True in_image = True
def place_image(self, row: int, placement: ImagePlacement, is_left: bool) -> None: def xpos_for_image(self, row: int, placement: ImagePlacement, is_left: bool) -> Optional[Tuple[int, float]]:
xpos = (0 if is_left else (self.screen_size.cols // 2)) + placement.image.margin_size xpos = (0 if is_left else (self.screen_size.cols // 2)) + placement.image.margin_size
image_height_in_rows = placement.image.rows image_height_in_rows = placement.image.rows
topmost_visible_row = placement.row topmost_visible_row = placement.row
num_visible_rows = image_height_in_rows - topmost_visible_row num_visible_rows = image_height_in_rows - topmost_visible_row
visible_frac = min(num_visible_rows / image_height_in_rows, 1) visible_frac = min(num_visible_rows / image_height_in_rows, 1)
if visible_frac > 0: if visible_frac <= 0:
return None
return xpos, visible_frac
def place_image(self, row: int, placement: ImagePlacement, is_left: bool) -> None:
q = self.xpos_for_image(row, placement, is_left)
if q is not None:
xpos, visible_frac = q
height = int(visible_frac * placement.image.height) height = int(visible_frac * placement.image.height)
top = placement.image.height - height top = placement.image.height - height
self.image_manager.show_image(placement.image.image_id, xpos, row, src_rect=( self.image_manager.show_image(placement.image.image_id, xpos, row, src_rect=(

View File

@ -10,7 +10,8 @@ from collections import defaultdict, deque
from contextlib import suppress from contextlib import suppress
from itertools import count from itertools import count
from typing import ( from typing import (
Any, DefaultDict, Deque, Dict, List, Optional, Sequence, Tuple, Union Any, Callable, DefaultDict, Deque, Dict, List, Optional, Sequence, Tuple,
Union
) )
from kitty.typing import ( from kitty.typing import (
@ -191,6 +192,7 @@ class ImageManager:
self.image_id_to_converted_data: Dict[int, ImageKey] = {} self.image_id_to_converted_data: Dict[int, ImageKey] = {}
self.transmission_status: Dict[int, Union[str, int]] = {} self.transmission_status: Dict[int, Union[str, int]] = {}
self.placements_in_flight: DefaultDict[int, Deque[Placement]] = defaultdict(deque) self.placements_in_flight: DefaultDict[int, Deque[Placement]] = defaultdict(deque)
self.update_image_placement_for_resend: Optional[Callable[[int, Placement], bool]]
@property @property
def next_image_id(self) -> int: def next_image_id(self) -> int:
@ -254,6 +256,8 @@ class ImageManager:
self.placements_in_flight.pop(image_id, None) self.placements_in_flight.pop(image_id, None)
def resend_image(self, image_id: int, pl: Placement) -> None: def resend_image(self, image_id: int, pl: Placement) -> None:
if self.update_image_placement_for_resend is not None and not self.update_image_placement_for_resend(image_id, pl):
return
image_data = self.image_id_to_image_data[image_id] image_data = self.image_id_to_image_data[image_id]
skey = self.image_id_to_converted_data[image_id] skey = self.image_id_to_converted_data[image_id]
self.transmit_image(image_data, image_id, *skey) self.transmit_image(image_data, image_id, *skey)