# HG changeset patch # User Goffi # Date 1410183745 -7200 # Node ID f5992b2a0dbfa4c175c3946613ba2347d116360e # Parent 2141f07b5fdd787534e9e8f52ad43b2d48ea7f1a FocusFrame refactoring: it's based on Urwid.Frame again, no more Pile, and it's simplified a lot. Now it just add FOCUS_* keys management diff -r 2141f07b5fdd -r f5992b2a0dbf urwid_satext/sat_widgets.py --- a/urwid_satext/sat_widgets.py Mon Sep 08 15:42:25 2014 +0200 +++ b/urwid_satext/sat_widgets.py Mon Sep 08 15:42:25 2014 +0200 @@ -25,6 +25,8 @@ from urwid.util import is_mouse_press #XXX: is_mouse_press is not included in urwid in 1.0.0 from .keys import action_key_map as a_key +FOCUS_KEYS = (a_key['FOCUS_SWITCH'], a_key['FOCUS_UP'], a_key['FOCUS_DOWN']) + class AdvancedEdit(urwid.Edit): """Edit box with some custom improvments @@ -1087,101 +1089,62 @@ return urwid.CanvasJoin(render) -class FocusFrame(urwid.Pile): +class FocusFrame(urwid.Frame): """Frame-like which manage 'tab' key""" - _sizing = frozenset(['box']) - - def __init__(self, body, header=None, footer=None, focus_part='body'): - self._header = self._footer = None - super(FocusFrame, self).__init__([body]) - self.header = header - self._body = body - self.footer = footer - self.focus_position = focus_part - - def _focus_part_recalc(self): - self._FOCUS_PARTS=[] - if self._header is not None: - self._FOCUS_PARTS.append('header') - self._FOCUS_PARTS.append('body') - if self._footer is not None: - self._FOCUS_PARTS.append('footer') - assert(len(self._FOCUS_PARTS) == len(self.contents)) - - @property - def header(self): - return self._header - - @header.setter - def header(self, widget): - content = (widget, ('pack', None)) - if widget is None: - if self._header is not None: - del self.contents[0] - elif self._header is None: - self.contents.insert(0, content) - else: - self.contents[0] = content - self._header = widget - self._focus_part_recalc() - - @property - def body(self): - return self._body - - @body.setter - def body(self, widget): - assert widget is not None - idx = self._FOCUS_PARTS.index('body') - self.contents[idx] = (widget, ("weight", 1)) - - @property - def footer(self): - return self._footer - - @footer.setter - def footer(self, widget): - content = (widget, ('pack', None)) - if widget is None: - if self._footer is not None: - del self.contents[-1] - elif self._footer is None: - self.contents.append(content) - else: - self.contents[-1] = content - self._footer = widget - self._focus_part_recalc() - - @property - def focus_position_named(self): - return self._FOCUS_PARTS[self.int_focus_position] - - @property - def focus_position(self): - return super(FocusFrame, self).focus_position - - @focus_position.setter - def focus_position(self, position): - if isinstance(position, basestring): - try: - position = self._FOCUS_PARTS.index(position) - except IndexError: - raise IndexError("This FocusFrame has no %s" % position) - urwid.Pile.focus_position.__set__(self, position) def keypress(self, size, key): ret = super(FocusFrame, self).keypress(size, key) if not ret: return - if key == a_key['FOCUS_SWITCH']: + if key in FOCUS_KEYS: + direction = 1 if key in (a_key['FOCUS_SWITCH'], a_key['FOCUS_UP']) else -1 + rotate = key == a_key['FOCUS_SWITCH'] + + selectables = [] # keep positions which exists and have a selectable widget + for position in reversed(self): + if self.contents[position][0].selectable(): + selectables.append(position) + if not selectables: + # no widget is selectable, we just return + return + idx = selectables.index(self.focus_position) + direction + if not rotate and (idx < 0 or idx >= len(selectables)): + # if we don't rotate, we stay where we are on the first and last position + return try: - self.focus_position -= 1 + self.focus_position = selectables[idx] except IndexError: - self.focus_position = 2 + # happen if idx > len(selectables) + self.focus_position = selectables[0] + return return ret + def get_cursor_coords(self, size): + """Return the cursor coordinates of the focus widget.""" + if not self.selectable(): + return None + if not hasattr(self.focus, 'get_cursor_coords'): + return None + maxcol, maxrow = size + try: + if self.focus_position != 'body': + # only body is a box widget + size = (maxcol,) + col, row = self.focus.get_cursor_coords(size) + except TypeError: + return None + if self.focus_position == 'header': + return (col, row) + if self.focus_position == 'body': + header_rows = self.header.rows((maxcol,)) + return (col, row + header_rows) + if self.focus_position == 'footer': + footer_rows = self.footer.rows((maxcol,)) + return (col, row + (maxrow - footer_rows)) + raise Exception('This line should not be reached') + class TabsContainer(urwid.WidgetWrap): """ Container which can contain multiple box widgets associated to named tabs """ @@ -1191,8 +1154,8 @@ self._current_tab = None self._buttons_cont = ColumnsRoller() self.tabs = [] - self.__frame = FocusFrame(urwid.Filler(urwid.Text('')),urwid.Pile([self._buttons_cont,urwid.Divider(u"─")])) - urwid.WidgetWrap.__init__(self, self.__frame) + self._frame = FocusFrame(urwid.Filler(urwid.Text('')),urwid.Pile([self._buttons_cont,urwid.Divider(u"─")])) + urwid.WidgetWrap.__init__(self, self._frame) def keypress(self, size, key): return self._w.keypress(size,key) @@ -1209,7 +1172,7 @@ if tab[0] != tab_name: log.error(_("INTERNAL ERROR: Tab not found")) assert(False) - self.__frame.body = tab[1] + self._frame.body = tab[1] button.set_label(('title',button.get_label())) if self._current_tab: self._current_tab.set_label(self._current_tab.get_label())