diff: More work on showing images
This commit is contained in:
parent
fb5dc8a2ba
commit
a6bce0b221
@ -155,15 +155,59 @@ class DiffHandler(Handler):
|
|||||||
|
|
||||||
def draw_lines(self, num, offset=0):
|
def draw_lines(self, num, offset=0):
|
||||||
offset += self.scroll_pos
|
offset += self.scroll_pos
|
||||||
|
image_involved = False
|
||||||
|
limit = len(self.diff_lines)
|
||||||
for i in range(num):
|
for i in range(num):
|
||||||
lpos = offset + i
|
lpos = offset + i
|
||||||
if lpos >= len(self.diff_lines):
|
if lpos >= limit:
|
||||||
text = ''
|
text = ''
|
||||||
else:
|
else:
|
||||||
text = self.diff_lines[lpos].text
|
line = self.diff_lines[lpos]
|
||||||
|
text = line.text
|
||||||
|
if line.image_data is not None:
|
||||||
|
image_involved = True
|
||||||
self.write('\r' + text + '\x1b[0m')
|
self.write('\r' + text + '\x1b[0m')
|
||||||
if i < num - 1:
|
if i < num - 1:
|
||||||
self.write('\n')
|
self.write('\n')
|
||||||
|
if image_involved:
|
||||||
|
self.place_images()
|
||||||
|
self.cmd.set_cursor_position(0, self.num_lines - 1)
|
||||||
|
|
||||||
|
def place_images(self):
|
||||||
|
offset = self.scroll_pos
|
||||||
|
limit = len(self.diff_lines)
|
||||||
|
in_image = 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:
|
||||||
|
self.place_image(row, left_placement, True)
|
||||||
|
in_image = True
|
||||||
|
if right_placement is not None:
|
||||||
|
self.place_image(row, right_placement, False)
|
||||||
|
in_image = True
|
||||||
|
|
||||||
|
def place_image(self, row, placement, is_left):
|
||||||
|
xpos = (0 if is_left else (self.screen_size.cols // 2)) + placement.image.margin_size
|
||||||
|
image_height_in_rows = placement.image.rows
|
||||||
|
topmost_visible_row = placement.row
|
||||||
|
num_visible_rows = image_height_in_rows - topmost_visible_row
|
||||||
|
visible_frac = min(num_visible_rows / image_height_in_rows, 1)
|
||||||
|
if visible_frac > 0:
|
||||||
|
self.cmd.set_cursor_position(xpos, row)
|
||||||
|
height = int(visible_frac * placement.image.height)
|
||||||
|
top = placement.image.height - height
|
||||||
|
self.image_manager.hide_image(placement.image.image_id)
|
||||||
|
self.image_manager.show_image(placement.image.image_id, src_rect=(
|
||||||
|
0, top, placement.image.width, height))
|
||||||
|
|
||||||
def draw_screen(self):
|
def draw_screen(self):
|
||||||
self.enforce_cursor_state()
|
self.enforce_cursor_state()
|
||||||
|
|||||||
@ -371,40 +371,47 @@ def rename_lines(path, other_path, args, columns, margin_size):
|
|||||||
|
|
||||||
class Image:
|
class Image:
|
||||||
|
|
||||||
def __init__(self, image_id, width, height):
|
def __init__(self, image_id, width, height, margin_size):
|
||||||
self.image_id = image_id
|
self.image_id = image_id
|
||||||
self.width, self.height = width, height
|
self.width, self.height = width, height
|
||||||
ss = screen_size()
|
ss = screen_size()
|
||||||
self.rows = int(ceil(self.height / ss.cell_height))
|
self.rows = int(ceil(self.height / ss.cell_height))
|
||||||
self.columns = int(ceil(self.width / ss.cell_width))
|
self.columns = int(ceil(self.width / ss.cell_width))
|
||||||
|
self.margin_size = margin_size
|
||||||
|
|
||||||
|
|
||||||
|
class ImagePlacement:
|
||||||
|
|
||||||
|
def __init__(self, image, row):
|
||||||
|
self.image = image
|
||||||
|
self.row = row
|
||||||
|
|
||||||
|
|
||||||
def render_image(path, is_left, available_cols, margin_size, image_manager):
|
def render_image(path, is_left, available_cols, margin_size, image_manager):
|
||||||
lnum = 0
|
lnum = 0
|
||||||
m = ' ' * margin_size
|
|
||||||
image_data = None
|
|
||||||
margin_fmt = removed_margin_format if is_left else added_margin_format
|
margin_fmt = removed_margin_format if is_left else added_margin_format
|
||||||
|
m = margin_fmt(' ' * margin_size)
|
||||||
fmt = removed_format if is_left else added_format
|
fmt = removed_format if is_left else added_format
|
||||||
|
|
||||||
def yield_split(text):
|
def yield_split(text):
|
||||||
nonlocal lnum
|
nonlocal lnum
|
||||||
for i, line in enumerate(split_to_size(text, available_cols)):
|
for i, line in enumerate(split_to_size(text, available_cols)):
|
||||||
yield margin_fmt(m) + fmt(place_in(line, available_cols)), Reference(path, LineRef(lnum, i)), image_data
|
yield m + fmt(place_in(line, available_cols)), Reference(path, LineRef(lnum, i)), None
|
||||||
lnum += 1
|
lnum += 1
|
||||||
|
|
||||||
try:
|
try:
|
||||||
image_id, width, height = image_manager.send_image(path, available_cols - 2, screen_size().rows - 1)
|
image_id, width, height = image_manager.send_image(path, available_cols - margin_size, screen_size().rows - 1)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
yield from yield_split(_('Failed to render image, with error:'))
|
yield from yield_split(_('Failed to render image, with error:'))
|
||||||
yield from yield_split(str(e))
|
yield from yield_split(' '.join(str(e).splitlines()))
|
||||||
return
|
return
|
||||||
meta = _('Dimensions: {0}x{1} pixels Size: {2}').format(
|
meta = _('Dimensions: {0}x{1} pixels Size: {2}').format(
|
||||||
width, height, human_readable(len(data_for_path(path))))
|
width, height, human_readable(len(data_for_path(path))))
|
||||||
yield from yield_split(meta)
|
yield from yield_split(meta)
|
||||||
bg_line = margin_fmt(m) + fmt(' ' * available_cols)
|
bg_line = m + fmt(' ' * available_cols)
|
||||||
img = Image(image_id, width, height)
|
img = Image(image_id, width, height, margin_size)
|
||||||
for r in range(img.rows):
|
for r in range(img.rows):
|
||||||
yield bg_line, Reference(path, LineRef(lnum)), (img, r)
|
yield bg_line, Reference(path, LineRef(lnum)), ImagePlacement(img, r)
|
||||||
lnum += 1
|
lnum += 1
|
||||||
|
|
||||||
|
|
||||||
@ -417,12 +424,17 @@ def image_lines(left_path, right_path, columns, margin_size, image_manager):
|
|||||||
right_lines = render_image(right_path, False, available_cols, margin_size, image_manager)
|
right_lines = render_image(right_path, False, available_cols, margin_size, image_manager)
|
||||||
filler = ' ' * (available_cols + margin_size)
|
filler = ' ' * (available_cols + margin_size)
|
||||||
for left, right in zip_longest(left_lines, right_lines):
|
for left, right in zip_longest(left_lines, right_lines):
|
||||||
|
left_placement = right_placement = None
|
||||||
if left is None:
|
if left is None:
|
||||||
left = filler
|
left = filler
|
||||||
right, ref, image_data = right
|
right, ref, right_placement = right
|
||||||
else:
|
elif right is None:
|
||||||
right = filler
|
right = filler
|
||||||
left, ref, image_data = left
|
left, ref, left_placement = left
|
||||||
|
else:
|
||||||
|
right, ref, right_placement = right
|
||||||
|
left, ref, left_placement = left
|
||||||
|
image_data = (left_placement, right_placement) if left_placement or right_placement else None
|
||||||
yield Line(left + right, ref, image_data=image_data)
|
yield Line(left + right, ref, image_data=image_data)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -111,6 +111,7 @@ class ImageManager:
|
|||||||
self.handler = handler
|
self.handler = handler
|
||||||
self.filesystem_ok = None
|
self.filesystem_ok = None
|
||||||
self.image_data = {}
|
self.image_data = {}
|
||||||
|
self.failed_images = {}
|
||||||
self.converted_images = {}
|
self.converted_images = {}
|
||||||
self.sent_images = {}
|
self.sent_images = {}
|
||||||
self.image_id_to_image_data = {}
|
self.image_id_to_image_data = {}
|
||||||
@ -120,7 +121,7 @@ class ImageManager:
|
|||||||
|
|
||||||
@property
|
@property
|
||||||
def next_image_id(self):
|
def next_image_id(self):
|
||||||
return next(self.image_id_counter)
|
return next(self.image_id_counter) + 2
|
||||||
|
|
||||||
def __enter__(self):
|
def __enter__(self):
|
||||||
import tempfile
|
import tempfile
|
||||||
@ -138,7 +139,7 @@ class ImageManager:
|
|||||||
|
|
||||||
def delete_all_sent_images(self):
|
def delete_all_sent_images(self):
|
||||||
for img_id in self.transmission_status:
|
for img_id in self.transmission_status:
|
||||||
self.handler.write(serialize_gr_command({'a': 'D', 'i': img_id}))
|
self.handler.write(serialize_gr_command({'a': 'd', 'i': img_id}))
|
||||||
self.transmission_status.clear()
|
self.transmission_status.clear()
|
||||||
|
|
||||||
def handle_response(self, apc):
|
def handle_response(self, apc):
|
||||||
@ -161,8 +162,8 @@ class ImageManager:
|
|||||||
else:
|
else:
|
||||||
in_flight = self.placements_in_flight[image_id]
|
in_flight = self.placements_in_flight[image_id]
|
||||||
if in_flight:
|
if in_flight:
|
||||||
pl = in_flight.pop(0)
|
pl = in_flight.popleft()
|
||||||
if payload.startswith('ENOENT:') and pl['retry_count'] == 0:
|
if payload.startswith('ENOENT:'):
|
||||||
try:
|
try:
|
||||||
self.resend_image(image_id, pl)
|
self.resend_image(image_id, pl)
|
||||||
except Exception:
|
except Exception:
|
||||||
@ -171,7 +172,6 @@ class ImageManager:
|
|||||||
self.placements_in_flight.pop(image_id, None)
|
self.placements_in_flight.pop(image_id, None)
|
||||||
|
|
||||||
def resend_image(self, image_id, pl):
|
def resend_image(self, image_id, pl):
|
||||||
pl['retry_count'] += 1
|
|
||||||
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)
|
||||||
@ -179,8 +179,14 @@ class ImageManager:
|
|||||||
|
|
||||||
def send_image(self, path, max_cols=None, max_rows=None, scale_up=False):
|
def send_image(self, path, max_cols=None, max_rows=None, scale_up=False):
|
||||||
path = os.path.abspath(path)
|
path = os.path.abspath(path)
|
||||||
|
if path in self.failed_images:
|
||||||
|
raise self.failed_images[path]
|
||||||
if path not in self.image_data:
|
if path not in self.image_data:
|
||||||
|
try:
|
||||||
self.image_data[path] = identify(path)
|
self.image_data[path] = identify(path)
|
||||||
|
except Exception as e:
|
||||||
|
self.failed_images[path] = e
|
||||||
|
raise
|
||||||
m = self.image_data[path]
|
m = self.image_data[path]
|
||||||
ss = screen_size()
|
ss = screen_size()
|
||||||
if max_cols is None:
|
if max_cols is None:
|
||||||
@ -192,7 +198,11 @@ class ImageManager:
|
|||||||
key = path, available_width, available_height
|
key = path, available_width, available_height
|
||||||
skey = self.converted_images.get(key)
|
skey = self.converted_images.get(key)
|
||||||
if skey is None:
|
if skey is None:
|
||||||
|
try:
|
||||||
self.converted_images[key] = skey = self.convert_image(path, available_width, available_height, m, scale_up)
|
self.converted_images[key] = skey = self.convert_image(path, available_width, available_height, m, scale_up)
|
||||||
|
except Exception as e:
|
||||||
|
self.failed_images[path] = e
|
||||||
|
raise
|
||||||
final_width, final_height = skey[1:]
|
final_width, final_height = skey[1:]
|
||||||
if final_width == 0:
|
if final_width == 0:
|
||||||
return 0, 0, 0
|
return 0, 0, 0
|
||||||
@ -208,9 +218,11 @@ class ImageManager:
|
|||||||
def hide_image(self, image_id):
|
def hide_image(self, image_id):
|
||||||
self.handler.write(serialize_gr_command({'a': 'd', 'i': image_id}))
|
self.handler.write(serialize_gr_command({'a': 'd', 'i': image_id}))
|
||||||
|
|
||||||
def show_image(self, image_id):
|
def show_image(self, image_id, src_rect=None):
|
||||||
cmd = {'a': 'p', 'i': image_id}
|
cmd = {'a': 'p', 'i': image_id}
|
||||||
self.placements_in_flight[image_id].append({'cmd': cmd, 'retry_count': 0})
|
if src_rect is not None:
|
||||||
|
cmd['x'], cmd['y'], cmd['w'], cmd['h'] = map(int, src_rect)
|
||||||
|
self.placements_in_flight[image_id].append({'cmd': cmd})
|
||||||
self.handler.write(serialize_gr_command(cmd))
|
self.handler.write(serialize_gr_command(cmd))
|
||||||
|
|
||||||
def convert_image(self, path, available_width, available_height, image_data, scale_up=False):
|
def convert_image(self, path, available_width, available_height, image_data, scale_up=False):
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user