@@ 222,6 222,7 @@ class changesetwalker(
'{node}', '{rev}', '{graphnode}', '{p1rev}', '{children}', config.TEMPLATE])
class graph_line_widget(
+ mixin.horizontal_scroll_text,
mixin.one_line_widget,
urwid.Text):
pass
@@ 448,6 449,7 @@ class descriptionwalker(_patchdetailwalk
class graphlistbox(
+ mixin.horizontal_scroll_listbox,
mixin.changeable_listbox,
mixin.filterable_listbox,
mixin.searchable_listbox,
@@ 5,6 5,7 @@
"""UI widgets for lairucrem."""
import asyncio
+import itertools
import re
from functools import reduce
from operator import or_
@@ 203,7 204,27 @@ class link(_key_to_signal):
}
-class horizontal_scroll_text(modifiable_widget, _key_to_signal):
+class horizontal_scroll_text(modifiable_widget):
+ """Scroll horizontally one line text."""
+
+ _horizontal_offset = 0
+
+ def _calc_line_translation(self, text, maxcol):
+ trans = super()._calc_line_translation(text, maxcol)
+ if not self._horizontal_offset:
+ return trans
+ assert len(trans) == 1, 'horizontal_scroll_text works on on_line_text only.'
+ amount = self._horizontal_offset - 1
+ return ([shift_line(trans[0], -amount)])
+
+ def setup_horizontal_offset(self, size, offset):
+ (maxcol, *_dummy) = size
+ self._horizontal_offset = offset
+ self._modified()
+ return (maxcol + self._horizontal_offset - 1) >= len(self._text)
+
+
+class horizontal_scroll_listbox(modifiable_widget, _key_to_signal):
signals = ['slideleft', 'slideright', 'modified']
key_to_signal_map = {
@@ 211,6 232,8 @@ class horizontal_scroll_text(modifiable_
config.CURSOR_RIGHT: 'slideright',
}
_horizontal_offset = 0
+ _horizontal_end_reached = False
+ _amount = 5
def _connect_signals(self):
urwid.signals.connect_signal(
@@ 219,23 242,46 @@ class horizontal_scroll_text(modifiable_
self, 'slideright', self.__class__.slide_right)
def slide_left(self, size):
- self._horizontal_offset = max(0, self._horizontal_offset - 2)
+ # self._horizontal_offset = max(0, self._horizontal_offset - 2)
+ if self._horizontal_offset <= 0:
+ return
+ self._horizontal_end_reached = False
+ self._horizontal_offset -= self._amount
+ self._propagate_horizontal_offset(size)
self._modified()
def slide_right(self, size):
- (maxcol, *dummy) = size
- self._horizontal_offset = min((len(self.text) - maxcol) + 1, self._horizontal_offset + 2)
+ if self._horizontal_end_reached:
+ return
+ self._horizontal_offset += self._amount
+ self._propagate_horizontal_offset(size)
self._modified()
- def _calc_line_translation(self, text, maxcol):
- trans = super()._calc_line_translation(text, maxcol)
- x, y = calc_coords(text, trans, maxcol + self._horizontal_offset - 2)
- # raise ValueError(x, y, trans, len(text), maxcol)
- if x < 0:
- trans = (trans[:y] + [shift_line(trans[y], -x)] + trans[y+1:])
- elif x >= maxcol:
- trans = (trans[:y] + [shift_line(trans[y], -(x-maxcol+1))] + trans[y+1:])
- return trans
+ def render(self, size, focus=False):
+ self._propagate_horizontal_offset(size, focus=focus)
+ return super().render(size, focus=focus)
+
+ def _propagate_horizontal_offset(self, size, focus=False):
+ middle, top, bottom = self.calculate_visible(size, focus=focus)
+ if not middle:
+ return # There's no widget
+ end_reached = True
+ _dummy, focus_widget, *_dummy = middle
+ try:
+ end_reached &= focus_widget.setup_horizontal_offset(
+ size, self._horizontal_offset
+ )
+ except AttributeError:
+ pass
+ visible_widgets = itertools.chain(top[1], bottom[1])
+ for widget, _dummy, _dummy in visible_widgets:
+ try:
+ end_reached &= widget.setup_horizontal_offset(
+ size, self._horizontal_offset
+ )
+ except AttributeError:
+ pass
+ self._horizontal_end_reached = end_reached
class filterable_listbox(_key_to_signal):