diff --git a/subiquitycore/ui/actionmenu.py b/subiquitycore/ui/actionmenu.py index 49320aca..fe7f08f4 100644 --- a/subiquitycore/ui/actionmenu.py +++ b/subiquitycore/ui/actionmenu.py @@ -119,7 +119,8 @@ class ActionMenu(PopUpLauncher): signals = ['action', 'open', 'close'] - def __init__(self, opts, icon=">"): + def __init__(self, opts, + icon="\N{BLACK RIGHT-POINTING SMALL TRIANGLE} ]"): self._actions = [] for opt in opts: if not isinstance(opt, Action): diff --git a/subiquitycore/ui/utils.py b/subiquitycore/ui/utils.py index 2287f0b3..fdae6517 100644 --- a/subiquitycore/ui/utils.py +++ b/subiquitycore/ui/utils.py @@ -22,6 +22,7 @@ from urwid import ( ACTIVATE, AttrMap, CompositeCanvas, + connect_signal, Padding as _Padding, SelectableIcon, Text, @@ -30,6 +31,7 @@ from urwid import ( ) from subiquitycore.ui.container import ListBox, Pile +from subiquitycore.ui.table import TableRow from subiquitycore.ui.width import widget_width @@ -297,3 +299,19 @@ class ClickableIcon(SelectableIcon): if self._command_map[key] != ACTIVATE: return key self._emit('click') + + +def make_action_menu_row( + cells, menu, + attr_map='menu_button', focus_map='menu_button focus', + cursor_x=2): + cells[0].set_text('[ ' + cells[0].text) + row = TableRow(cells + [menu]) + if not isinstance(attr_map, dict): + attr_map = {None: attr_map} + if not isinstance(focus_map, dict): + focus_map = {None: focus_map} + am = AttrMap(CursorOverride(row, cursor_x=cursor_x), attr_map, focus_map) + connect_signal(menu, 'open', lambda menu: am.set_attr_map(focus_map)) + connect_signal(menu, 'close', lambda menu: am.set_attr_map(attr_map)) + return am diff --git a/subiquitycore/ui/views/network.py b/subiquitycore/ui/views/network.py index a45458dc..32458e50 100644 --- a/subiquitycore/ui/views/network.py +++ b/subiquitycore/ui/views/network.py @@ -23,12 +23,14 @@ import logging import textwrap from urwid import ( + connect_signal, LineBox, ProgressBar, Text, ) from urwid import Padding as uPadding +from subiquitycore.ui.actionmenu import ActionMenu from subiquitycore.ui.buttons import back_btn, cancel_btn, done_btn, menu_btn from subiquitycore.ui.container import ( Columns, @@ -36,7 +38,10 @@ from subiquitycore.ui.container import ( Pile, WidgetWrap, ) -from subiquitycore.ui.utils import button_pile, Color, Padding +from subiquitycore.ui.form import Form, StringField, Toggleable +from subiquitycore.ui.stretchy import Stretchy +from subiquitycore.ui.table import ColSpec, TablePile, TableRow +from subiquitycore.ui.utils import button_pile, Color, make_action_menu_row, Padding from subiquitycore.view import BaseView @@ -140,7 +145,8 @@ class NetworkView(BaseView): self.items = [] self.error = Text("", align='center') self.additional_options = Pile(self._build_additional_options()) - self.listbox = ListBox(self._build_model_inputs() + [ + self.device_table = TablePile(self._build_model_inputs(), spacing=2, colspecs={3:ColSpec(can_shrink=True)}) + self.listbox = ListBox([self.device_table] + [ Padding.center_79(self.additional_options), Padding.line_break(""), ]) @@ -164,8 +170,49 @@ class NetworkView(BaseView): done = done_btn(_("Done"), on_press=self.done) return button_pile([done, back]) + def _action_info(self, device): + pass + + def _action(self, sender, action, device): + m = getattr(self, '_action_{}'.format(action)) + m(device) + self.refresh_model_inputs() + def _build_model_inputs(self): netdevs = self.model.get_all_netdevs() + rows = [] + rows.append(TableRow([Color.info_minor(header) for header in [Text(" NAME"), Text("TYPE"), Text("DHCP"), Text("ADDRESSES")]])) + for dev in netdevs: + dhcp = [] + if dev.dhcp4: + dhcp.append('v4') + if dev.dhcp6: + dhcp.append('v6') + if dhcp: + dhcp = ",".join(dhcp) + else: + dhcp = '-' + if dev.configured_ip_addresses: + addresses = ", ".join([str(a) for a in dev.configured_ip_addresses]) + else: + addresses = '-' + actions = [ + ("Info", True, 'info'), + ] + menu = ActionMenu(actions) + connect_signal(menu, 'action', self._action, dev) + rows.append(make_action_menu_row( + [ + Text(dev.name), + Text(dev.type), + Text(dhcp), + Text(addresses, wrap='clip'), + ], + menu, + )) + rows.append(Color.info_minor(TableRow([(4, Text(" " + dev.hwaddr + " " + dev.vendor))]))) + rows.append(Color.info_minor(TableRow([(4, Text(""))]))) + return rows ifname_width = 8 # default padding if netdevs: ifname_width += max(map(lambda dev: len(dev.name), netdevs)) @@ -216,13 +263,7 @@ class NetworkView(BaseView): return iface_menus def refresh_model_inputs(self): - widgets = self._build_model_inputs() + [ - Padding.center_79(self.additional_options), - Padding.line_break(""), - ] - self.listbox.base_widget.body[:] = widgets - self.additional_options.contents = [ - (obj, ('pack', None)) for obj in self._build_additional_options()] + self.device_table.set_contents(self._build_model_inputs()) def _build_additional_options(self): labels = []