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: