Mercurial > urwid-satext
comparison urwid_satext/sat_widgets.py @ 90:f5992b2a0dbf
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
author | Goffi <goffi@goffi.org> |
---|---|
date | Mon, 08 Sep 2014 15:42:25 +0200 |
parents | 2141f07b5fdd |
children | b447a9c6f1d3 |
comparison
equal
deleted
inserted
replaced
89:2141f07b5fdd | 90:f5992b2a0dbf |
---|---|
22 import encodings | 22 import encodings |
23 utf8decode = lambda s: encodings.codecs.utf_8_decode(s)[0] | 23 utf8decode = lambda s: encodings.codecs.utf_8_decode(s)[0] |
24 | 24 |
25 from urwid.util import is_mouse_press #XXX: is_mouse_press is not included in urwid in 1.0.0 | 25 from urwid.util import is_mouse_press #XXX: is_mouse_press is not included in urwid in 1.0.0 |
26 from .keys import action_key_map as a_key | 26 from .keys import action_key_map as a_key |
27 | |
28 FOCUS_KEYS = (a_key['FOCUS_SWITCH'], a_key['FOCUS_UP'], a_key['FOCUS_DOWN']) | |
27 | 29 |
28 | 30 |
29 class AdvancedEdit(urwid.Edit): | 31 class AdvancedEdit(urwid.Edit): |
30 """Edit box with some custom improvments | 32 """Edit box with some custom improvments |
31 new chars: | 33 new chars: |
1085 render.append((urwid.SolidCanvas(" "*cols_left, size[0], 1),False,False,cols_left)) | 1087 render.append((urwid.SolidCanvas(" "*cols_left, size[0], 1),False,False,cols_left)) |
1086 | 1088 |
1087 return urwid.CanvasJoin(render) | 1089 return urwid.CanvasJoin(render) |
1088 | 1090 |
1089 | 1091 |
1090 class FocusFrame(urwid.Pile): | 1092 class FocusFrame(urwid.Frame): |
1091 """Frame-like which manage 'tab' key""" | 1093 """Frame-like which manage 'tab' key""" |
1092 _sizing = frozenset(['box']) | |
1093 | |
1094 def __init__(self, body, header=None, footer=None, focus_part='body'): | |
1095 self._header = self._footer = None | |
1096 super(FocusFrame, self).__init__([body]) | |
1097 self.header = header | |
1098 self._body = body | |
1099 self.footer = footer | |
1100 self.focus_position = focus_part | |
1101 | |
1102 def _focus_part_recalc(self): | |
1103 self._FOCUS_PARTS=[] | |
1104 if self._header is not None: | |
1105 self._FOCUS_PARTS.append('header') | |
1106 self._FOCUS_PARTS.append('body') | |
1107 if self._footer is not None: | |
1108 self._FOCUS_PARTS.append('footer') | |
1109 assert(len(self._FOCUS_PARTS) == len(self.contents)) | |
1110 | |
1111 @property | |
1112 def header(self): | |
1113 return self._header | |
1114 | |
1115 @header.setter | |
1116 def header(self, widget): | |
1117 content = (widget, ('pack', None)) | |
1118 if widget is None: | |
1119 if self._header is not None: | |
1120 del self.contents[0] | |
1121 elif self._header is None: | |
1122 self.contents.insert(0, content) | |
1123 else: | |
1124 self.contents[0] = content | |
1125 self._header = widget | |
1126 self._focus_part_recalc() | |
1127 | |
1128 @property | |
1129 def body(self): | |
1130 return self._body | |
1131 | |
1132 @body.setter | |
1133 def body(self, widget): | |
1134 assert widget is not None | |
1135 idx = self._FOCUS_PARTS.index('body') | |
1136 self.contents[idx] = (widget, ("weight", 1)) | |
1137 | |
1138 @property | |
1139 def footer(self): | |
1140 return self._footer | |
1141 | |
1142 @footer.setter | |
1143 def footer(self, widget): | |
1144 content = (widget, ('pack', None)) | |
1145 if widget is None: | |
1146 if self._footer is not None: | |
1147 del self.contents[-1] | |
1148 elif self._footer is None: | |
1149 self.contents.append(content) | |
1150 else: | |
1151 self.contents[-1] = content | |
1152 self._footer = widget | |
1153 self._focus_part_recalc() | |
1154 | |
1155 @property | |
1156 def focus_position_named(self): | |
1157 return self._FOCUS_PARTS[self.int_focus_position] | |
1158 | |
1159 @property | |
1160 def focus_position(self): | |
1161 return super(FocusFrame, self).focus_position | |
1162 | |
1163 @focus_position.setter | |
1164 def focus_position(self, position): | |
1165 if isinstance(position, basestring): | |
1166 try: | |
1167 position = self._FOCUS_PARTS.index(position) | |
1168 except IndexError: | |
1169 raise IndexError("This FocusFrame has no %s" % position) | |
1170 urwid.Pile.focus_position.__set__(self, position) | |
1171 | 1094 |
1172 def keypress(self, size, key): | 1095 def keypress(self, size, key): |
1173 ret = super(FocusFrame, self).keypress(size, key) | 1096 ret = super(FocusFrame, self).keypress(size, key) |
1174 if not ret: | 1097 if not ret: |
1175 return | 1098 return |
1176 | 1099 |
1177 if key == a_key['FOCUS_SWITCH']: | 1100 if key in FOCUS_KEYS: |
1101 direction = 1 if key in (a_key['FOCUS_SWITCH'], a_key['FOCUS_UP']) else -1 | |
1102 rotate = key == a_key['FOCUS_SWITCH'] | |
1103 | |
1104 selectables = [] # keep positions which exists and have a selectable widget | |
1105 for position in reversed(self): | |
1106 if self.contents[position][0].selectable(): | |
1107 selectables.append(position) | |
1108 if not selectables: | |
1109 # no widget is selectable, we just return | |
1110 return | |
1111 idx = selectables.index(self.focus_position) + direction | |
1112 if not rotate and (idx < 0 or idx >= len(selectables)): | |
1113 # if we don't rotate, we stay where we are on the first and last position | |
1114 return | |
1178 try: | 1115 try: |
1179 self.focus_position -= 1 | 1116 self.focus_position = selectables[idx] |
1180 except IndexError: | 1117 except IndexError: |
1181 self.focus_position = 2 | 1118 # happen if idx > len(selectables) |
1119 self.focus_position = selectables[0] | |
1120 return | |
1182 | 1121 |
1183 return ret | 1122 return ret |
1123 | |
1124 def get_cursor_coords(self, size): | |
1125 """Return the cursor coordinates of the focus widget.""" | |
1126 if not self.selectable(): | |
1127 return None | |
1128 if not hasattr(self.focus, 'get_cursor_coords'): | |
1129 return None | |
1130 maxcol, maxrow = size | |
1131 try: | |
1132 if self.focus_position != 'body': | |
1133 # only body is a box widget | |
1134 size = (maxcol,) | |
1135 col, row = self.focus.get_cursor_coords(size) | |
1136 except TypeError: | |
1137 return None | |
1138 if self.focus_position == 'header': | |
1139 return (col, row) | |
1140 if self.focus_position == 'body': | |
1141 header_rows = self.header.rows((maxcol,)) | |
1142 return (col, row + header_rows) | |
1143 if self.focus_position == 'footer': | |
1144 footer_rows = self.footer.rows((maxcol,)) | |
1145 return (col, row + (maxrow - footer_rows)) | |
1146 raise Exception('This line should not be reached') | |
1184 | 1147 |
1185 | 1148 |
1186 class TabsContainer(urwid.WidgetWrap): | 1149 class TabsContainer(urwid.WidgetWrap): |
1187 """ Container which can contain multiple box widgets associated to named tabs """ | 1150 """ Container which can contain multiple box widgets associated to named tabs """ |
1188 signals = ['click'] | 1151 signals = ['click'] |
1189 | 1152 |
1190 def __init__(self): | 1153 def __init__(self): |
1191 self._current_tab = None | 1154 self._current_tab = None |
1192 self._buttons_cont = ColumnsRoller() | 1155 self._buttons_cont = ColumnsRoller() |
1193 self.tabs = [] | 1156 self.tabs = [] |
1194 self.__frame = FocusFrame(urwid.Filler(urwid.Text('')),urwid.Pile([self._buttons_cont,urwid.Divider(u"─")])) | 1157 self._frame = FocusFrame(urwid.Filler(urwid.Text('')),urwid.Pile([self._buttons_cont,urwid.Divider(u"─")])) |
1195 urwid.WidgetWrap.__init__(self, self.__frame) | 1158 urwid.WidgetWrap.__init__(self, self._frame) |
1196 | 1159 |
1197 def keypress(self, size, key): | 1160 def keypress(self, size, key): |
1198 return self._w.keypress(size,key) | 1161 return self._w.keypress(size,key) |
1199 | 1162 |
1200 def _buttonClicked(self, button, invisible=False): | 1163 def _buttonClicked(self, button, invisible=False): |
1207 if tab[0] == tab_name: | 1170 if tab[0] == tab_name: |
1208 break | 1171 break |
1209 if tab[0] != tab_name: | 1172 if tab[0] != tab_name: |
1210 log.error(_("INTERNAL ERROR: Tab not found")) | 1173 log.error(_("INTERNAL ERROR: Tab not found")) |
1211 assert(False) | 1174 assert(False) |
1212 self.__frame.body = tab[1] | 1175 self._frame.body = tab[1] |
1213 button.set_label(('title',button.get_label())) | 1176 button.set_label(('title',button.get_label())) |
1214 if self._current_tab: | 1177 if self._current_tab: |
1215 self._current_tab.set_label(self._current_tab.get_label()) | 1178 self._current_tab.set_label(self._current_tab.get_label()) |
1216 self._current_tab = button | 1179 self._current_tab = button |
1217 if not invisible: | 1180 if not invisible: |