Merge pull request #265 from CanonicalLtd/mwhudson/scrollbars

add scrollbars to listboxes
This commit is contained in:
Michael Hudson-Doyle 2017-11-09 20:04:06 +13:00 committed by GitHub
commit 75fdfb4c4e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 94 additions and 17 deletions

View File

@ -87,6 +87,8 @@ STYLES = [
('string_input focus', 'bg', 'fg'),
('progress_incomplete', 'fg', 'aubergine'),
('progress_complete', 'fg', 'orange'),
('scrollbar_fg', 'orange', 'bg'),
('scrollbar_bg', 'fg', 'bg'),
]
focus_styles = set([

View File

@ -38,10 +38,10 @@ class DiskPartitionView(BaseView):
('pack', Text("")),
Padding.center_79(ListBox(
self._build_model_inputs() + [
Text(""),
self.show_disk_info_w(),
])),
('pack', Pile([
Text(""),
('pack', Padding.center_79(self.show_disk_info_w())),
('pack', Text("")),
self._build_buttons(),
('pack', Text("")),

View File

@ -64,7 +64,7 @@ class FilesystemConfirmationView(WidgetWrap):
Text(""),
])
lb = LineBox(pile, title=_("Confirm destructive action"))
super().__init__(Padding.center_75(lb))
super().__init__(lb)
def ok(self, sender):
self.controller.finish()
@ -261,4 +261,4 @@ class FilesystemView(BaseView):
self.controller.reset()
def done(self, button):
self.show_overlay(FilesystemConfirmationView(self, self.controller))
self.show_overlay(FilesystemConfirmationView(self, self.controller), min_width=0)

View File

@ -40,7 +40,8 @@ class ProgressView(BaseView):
self.model = model
self.controller = controller
self.listwalker = SimpleFocusListWalker([])
self.linebox = MyLineBox(ListBox(self.listwalker))
self.listbox = ListBox(self.listwalker)
self.linebox = MyLineBox(self.listbox)
body = [
('pack', Text("")),
('weight', 1, Padding.center_79(self.linebox)),
@ -50,9 +51,11 @@ class ProgressView(BaseView):
super().__init__(self.pile)
def add_log_tail(self, text):
at_end = len(self.listwalker) == 0 or self.listbox.focus_position == len(self.listwalker) - 1
for line in text.splitlines():
self.listwalker.append(Text(line))
self.listwalker.set_focus(len(self.listwalker) - 1)
if at_end:
self.listbox.set_focus(len(self.listwalker) - 1)
def clear_log_tail(self):
self.listwalker[:] = []

View File

@ -405,7 +405,7 @@ class NetworkController(BaseController):
self.cs.cancel()
self.task_error('canceled')
self.acw = ApplyingConfigWidget(len(tasks), cancel)
self.ui.frame.body.show_overlay(self.acw)
self.ui.frame.body.show_overlay(self.acw, min_width=60)
self.cs = TaskSequence(self.run_in_bg, tasks, self)
self.cs.run()

View File

@ -230,6 +230,78 @@ class FocusTrackingListBox(TabCyclingListBox):
def gained_focus(self):
_maybe_call(self.focus, 'gained_focus')
Columns = FocusTrackingColumns
Pile = FocusTrackingPile
ListBox = FocusTrackingListBox
class ScrollBarListBox(FocusTrackingListBox):
def __init__(self, walker=None):
def f(char, attr):
return urwid.AttrMap(urwid.SolidFill(char), attr)
self.bar = Pile([
('weight', 1, f("\N{BOX DRAWINGS LIGHT VERTICAL}", 'scrollbar_bg')),
('weight', 1, f("\N{FULL BLOCK}", 'scrollbar_fg')),
('weight', 1, f("\N{BOX DRAWINGS LIGHT VERTICAL}", 'scrollbar_bg')),
])
super().__init__(walker)
def render(self, size, focus=False):
visible = self.ends_visible(size, focus)
if len(visible) == 2:
return super().render(size, focus)
else:
# This implementation assumes that the number of rows is
# not too large (and in particular is finite). That's the
# case for all the listboxes we have in subiquity today.
maxcol, maxrow = size
offset, inset = self.get_focus_offset_inset((maxcol - 1, maxrow))
seen_focus = False
height = height_before_focus = 0
focus_widget, focus_pos = self.body.get_focus()
# Scan through the rows calculating total height and the
# height of the rows before the focus widget.
for widget in self.body:
rows = widget.rows((maxcol - 1,))
if widget is focus_widget:
seen_focus = True
elif not seen_focus:
height_before_focus += rows
height += rows
# Calculate the number of rows off the top and bottom of
# the listbox.
if 'top' in visible:
top = 0
else:
top = height_before_focus + inset - offset
if 'bottom' in visible:
bottom = 0
else:
bottom = height - top - maxrow
# Prevent the box from being squished to 0 rows (if it
# gets ('weight', maxrow) gets round(maxrow / (top +
# maxrow + bottom)) and that being < 1 simplifies to the
# below).
if maxrow*maxrow < height:
boxopt = self.bar.options('given', 1)
else:
boxopt = self.bar.options('weight', maxrow)
self.bar.contents[:] = [
(self.bar.contents[0][0], self.bar.options('weight', top)),
(self.bar.contents[1][0], boxopt),
(self.bar.contents[2][0], self.bar.options('weight', bottom)),
]
canvases = [
(super().render((maxcol - 1, maxrow), focus), self.focus_position, True, maxcol - 1),
(self.bar.render((1, maxrow)), None, False, 1)
]
return urwid.CanvasJoin(canvases)
ListBox = ScrollBarListBox

View File

@ -115,11 +115,11 @@ class NetworkView(BaseView):
self.model_inputs = Pile(self._build_model_inputs())
self.additional_options = Pile(self._build_additional_options())
self.body = [
Padding.center_90(self.model_inputs),
self.model_inputs,
Padding.center_79(self.additional_options),
Padding.line_break(""),
]
self.lb = ListBox(self.body)
self.lb = Padding.center_90(ListBox(self.body))
self.footer = Pile([
Text(""),
self._build_buttons(),

View File

@ -34,7 +34,7 @@ class NetworkConfigureInterfaceView(BaseView):
self._build_widgets()
super().__init__(Pile([
('pack', Text("")),
ListBox(self._build_body()),
Padding.center_79(ListBox(self._build_body())),
('pack', Pile([
('pack', Text("")),
self._build_buttons(),
@ -57,16 +57,16 @@ class NetworkConfigureInterfaceView(BaseView):
body = []
if self.dev.type == 'wlan':
body.extend([
Padding.center_79(self.wifi_info),
Padding.center_79(self.wifi_method),
self.wifi_info,
self.wifi_method,
Padding.line_break(""),
])
body.extend([
Padding.center_79(self.ipv4_info),
Padding.center_79(self.ipv4_method),
self.ipv4_info,
self.ipv4_method,
Padding.line_break(""),
Padding.center_79(self.ipv6_info),
Padding.center_79(self.ipv6_method),
self.ipv6_info,
self.ipv6_method,
Padding.line_break(""),
])
return body