Mercurial > urwid-satext
comparison urwid_satext/sat_widgets.py @ 143:144bdf877d21
python 3 port (using 2to3)
author | Goffi <goffi@goffi.org> |
---|---|
date | Tue, 13 Aug 2019 08:55:41 +0200 |
parents | 88722f920b3c |
children | bfab04d0a745 |
comparison
equal
deleted
inserted
replaced
142:2855123621a0 | 143:144bdf877d21 |
---|---|
17 # You should have received a copy of the GNU Lesser General Public License | 17 # You should have received a copy of the GNU Lesser General Public License |
18 # along with this program. If not, see <http://www.gnu.org/licenses/>. | 18 # along with this program. If not, see <http://www.gnu.org/licenses/>. |
19 | 19 |
20 import urwid | 20 import urwid |
21 import logging as log | 21 import logging as log |
22 import encodings | |
23 utf8decode = lambda s: encodings.codecs.utf_8_decode(s)[0] | |
24 | 22 |
25 import uuid | 23 import uuid |
26 | 24 |
27 import collections | 25 import collections |
28 | 26 |
119 | 117 |
120 def __init__(self, *args, **kwargs): | 118 def __init__(self, *args, **kwargs): |
121 """Same args than Edit.__init__ with an additional keyword arg 'hidden_char' | 119 """Same args than Edit.__init__ with an additional keyword arg 'hidden_char' |
122 @param hidden_char: char to show instead of what is actually entered: default '*' | 120 @param hidden_char: char to show instead of what is actually entered: default '*' |
123 """ | 121 """ |
124 self.hidden_char=kwargs['hidden_char'] if kwargs.has_key('hidden_char') else '*' | 122 self.hidden_char=kwargs['hidden_char'] if 'hidden_char' in kwargs else '*' |
125 self.__real_text='' | 123 self.__real_text='' |
126 super(Password, self).__init__(*args, **kwargs) | 124 super(Password, self).__init__(*args, **kwargs) |
127 | 125 |
128 def set_edit_text(self, text): | 126 def set_edit_text(self, text): |
129 self.__real_text = text | 127 self.__real_text = text |
193 | 191 |
194 class SurroundedText(urwid.Widget): | 192 class SurroundedText(urwid.Widget): |
195 """Text centered on a repeated character (like a Divider, but with a text in the center)""" | 193 """Text centered on a repeated character (like a Divider, but with a text in the center)""" |
196 _sizing = frozenset(['flow']) | 194 _sizing = frozenset(['flow']) |
197 | 195 |
198 def __init__(self,text,car=utf8decode('─')): | 196 def __init__(self,text,car='─'): |
199 self.text=text | 197 self.text=text |
200 self.car=car | 198 self.car=car |
201 | 199 |
202 def rows(self,size,focus=False): | 200 def rows(self,size,focus=False): |
203 return self.display_widget(size, focus).rows(size, focus) | 201 return self.display_widget(size, focus).rows(size, focus) |
205 def render(self, size, focus=False): | 203 def render(self, size, focus=False): |
206 return self.display_widget(size, focus).render(size, focus) | 204 return self.display_widget(size, focus).render(size, focus) |
207 | 205 |
208 def display_widget(self, size, focus): | 206 def display_widget(self, size, focus): |
209 (maxcol,) = size | 207 (maxcol,) = size |
210 middle = (maxcol-len(self.text))/2 | 208 middle = (maxcol-len(self.text))//2 |
211 render_text = middle * self.car + self.text + (maxcol - len(self.text) - middle) * self.car | 209 render_text = middle * self.car + self.text + (maxcol - len(self.text) - middle) * self.car |
212 return urwid.Text(render_text) | 210 return urwid.Text(render_text) |
213 | 211 |
214 | 212 |
215 class AlwaysSelectableText(urwid.WidgetWrap): | 213 class AlwaysSelectableText(urwid.WidgetWrap): |
231 urwid.WidgetWrap.__init__(self, urwid.Text("",align=align)) | 229 urwid.WidgetWrap.__init__(self, urwid.Text("",align=align)) |
232 self.setSelectedText(selected_text) | 230 self.setSelectedText(selected_text) |
233 self.setState(selected) | 231 self.setState(selected) |
234 | 232 |
235 def getValue(self): | 233 def getValue(self): |
236 if isinstance(self.text,basestring): | 234 if isinstance(self.text,str): |
237 return self.text | 235 return self.text |
238 list_attr = self.text if isinstance(self.text, list) else [self.text] | 236 list_attr = self.text if isinstance(self.text, list) else [self.text] |
239 txt = "" | 237 txt = "" |
240 for attr in list_attr: | 238 for attr in list_attr: |
241 if isinstance(attr,tuple): | 239 if isinstance(attr,tuple): |
369 def set_label(self, label): | 367 def set_label(self, label): |
370 self.label = label | 368 self.label = label |
371 self.set_text([self.left_border, label, self.right_border]) | 369 self.set_text([self.left_border, label, self.right_border]) |
372 | 370 |
373 | 371 |
374 class ListOption(unicode): | 372 class ListOption(str): |
375 """Unicode which manage label and value | 373 """Unicode which manage label and value |
376 | 374 |
377 This class similar to unicode, but which make the difference between value and label | 375 This class similar to unicode, but which make the difference between value and label |
378 label is show when use as unicode, the .value attribute contain the actual value | 376 label is show when use as unicode, the .value attribute contain the actual value |
379 Can be initialised with: | 377 Can be initialised with: |
383 """ | 381 """ |
384 | 382 |
385 def __new__(cls, option): | 383 def __new__(cls, option): |
386 if (isinstance(option, cls)): | 384 if (isinstance(option, cls)): |
387 return option | 385 return option |
388 elif isinstance(option, basestring): | 386 elif isinstance(option, str): |
389 value = label = option | 387 value = label = option |
390 elif (isinstance(option, tuple) and len(option) == 2): | 388 elif (isinstance(option, tuple) and len(option) == 2): |
391 value, label = option | 389 value, label = option |
392 else: | 390 else: |
393 raise NotImplementedError | 391 raise NotImplementedError |
515 def __setitem__(self, i, y): | 513 def __setitem__(self, i, y): |
516 parent = super(SimpleListWalkerWithCb, self) | 514 parent = super(SimpleListWalkerWithCb, self) |
517 self.__cbSingle(y, self._on_new) | 515 self.__cbSingle(y, self._on_new) |
518 to_delete = parent.__getitem__(i) | 516 to_delete = parent.__getitem__(i) |
519 self.__cbSingle(to_delete, self._on_delete) | 517 self.__cbSingle(to_delete, self._on_delete) |
520 return parent.__setitem__(self, i, y) | 518 return parent.__setitem__(i, y) |
521 | 519 |
522 def __setslice__(self, i, j, y): | 520 def __setslice__(self, i, j, y): |
523 parent = super(SimpleListWalkerWithCb, self) | 521 parent = super(SimpleListWalkerWithCb, self) |
524 items_to_delete = parent.__getslice__(i,j) | 522 items_to_delete = parent.__getslice__(i,j) |
525 self.__cbMulti(items_to_delete, self._on_delete) | 523 self.__cbMulti(items_to_delete, self._on_delete) |
817 if widget == pop_up_widget: | 815 if widget == pop_up_widget: |
818 del self.notifs[idx] | 816 del self.notifs[idx] |
819 self._modQueue() | 817 self._modQueue() |
820 return | 818 return |
821 | 819 |
822 raise ValueError(u"trying to remove an unknown pop_up_widget") | 820 raise ValueError("trying to remove an unknown pop_up_widget") |
823 | 821 |
824 def addMessage(self, message): | 822 def addMessage(self, message): |
825 "Add a message to the notificatio bar" | 823 "Add a message to the notificatio bar" |
826 if not self.message.get_text(): | 824 if not self.message.get_text(): |
827 self.message.set_text(('notifs',message)) | 825 self.message.set_text(('notifs',message)) |
956 self.save_bottom = None | 954 self.save_bottom = None |
957 | 955 |
958 return self._w.base_widget.keypress(size, key) | 956 return self._w.base_widget.keypress(size, key) |
959 | 957 |
960 def checkShortcuts(self, key): | 958 def checkShortcuts(self, key): |
961 for shortcut in self.shortcuts.keys(): | 959 for shortcut in list(self.shortcuts.keys()): |
962 if key == shortcut: | 960 if key == shortcut: |
963 category, item, callback = self.shortcuts[shortcut] | 961 category, item, callback = self.shortcuts[shortcut] |
964 callback((category, item)) | 962 callback((category, item)) |
965 return key | 963 return key |
966 | 964 |
968 """Create the category if new and add a menu item (if item is not None). | 966 """Create the category if new and add a menu item (if item is not None). |
969 | 967 |
970 @param category: category of the menu (e.g. File/Edit) | 968 @param category: category of the menu (e.g. File/Edit) |
971 @param item: menu item (e.g. new/close/about) | 969 @param item: menu item (e.g. new/close/about) |
972 @callback: method to call when item is selected""" | 970 @callback: method to call when item is selected""" |
973 if not category in self.menu.keys(): | 971 if not category in list(self.menu.keys()): |
974 self.menu_keys.append(category) | 972 self.menu_keys.append(category) |
975 self.menu[category] = [] | 973 self.menu[category] = [] |
976 button = CustomButton(('menubar',category), self.onCategoryClick, | 974 button = CustomButton(('menubar',category), self.onCategoryClick, |
977 left_border = ('menubar',"[ "), | 975 left_border = ('menubar',"[ "), |
978 right_border = ('menubar'," ]")) | 976 right_border = ('menubar'," ]")) |
979 self._w.base_widget.addWidget(button,button.getSize()) | 977 self._w.base_widget.addWidget(button,button.getSize()) |
980 if not item: | 978 if not item: |
981 return | 979 return |
982 self.menu[category].append((item, callback)) | 980 self.menu[category].append((item, callback)) |
983 if shortcut: | 981 if shortcut: |
984 assert(shortcut not in self.shortcuts.keys()) | 982 assert(shortcut not in list(self.shortcuts.keys())) |
985 self.shortcuts[shortcut] = (category, item, callback) | 983 self.shortcuts[shortcut] = (category, item, callback) |
986 | 984 |
987 def onItemClick(self, widget): | 985 def onItemClick(self, widget): |
988 category = self._w.base_widget.getSelected().get_label() | 986 category = self._w.base_widget.getSelected().get_label() |
989 item = widget.getValue() | 987 item = widget.getValue() |
1031 if self.selected is None: | 1029 if self.selected is None: |
1032 self.columns.contents[0] = (urwid.Text(''), ('given', 0, False)) | 1030 self.columns.contents[0] = (urwid.Text(''), ('given', 0, False)) |
1033 self.columns.contents[1] = (urwid.Text(''), ('weight', 1, False)) | 1031 self.columns.contents[1] = (urwid.Text(''), ('weight', 1, False)) |
1034 else: | 1032 else: |
1035 menu_item = self.menu_items[self.selected] | 1033 menu_item = self.menu_items[self.selected] |
1036 name_txt = u'\u21c9 ' + menu_item.name + u' \u21c7 ' | 1034 name_txt = '\u21c9 ' + menu_item.name + ' \u21c7 ' |
1037 current_name = ClickableText(name_txt) | 1035 current_name = ClickableText(name_txt) |
1038 name_len = len(name_txt) | 1036 name_len = len(name_txt) |
1039 current_menu = menu_item.widget | 1037 current_menu = menu_item.widget |
1040 current_menu.setOrigX(name_len) | 1038 current_menu.setOrigX(name_len) |
1041 self.columns.contents[0] = (current_name, ('given', name_len, False)) | 1039 self.columns.contents[0] = (current_name, ('given', name_len, False)) |
1042 self.columns.contents[1] = (current_menu, ('weight', 1, False)) | 1040 self.columns.contents[1] = (current_menu, ('weight', 1, False)) |
1043 | 1041 |
1044 def keypress(self, size, key): | 1042 def keypress(self, size, key): |
1045 menu_ids = self.menu_items.keys() | 1043 menu_ids = list(self.menu_items.keys()) |
1046 try: | 1044 try: |
1047 idx = menu_ids.index(self.selected) | 1045 idx = menu_ids.index(self.selected) |
1048 except ValueError: | 1046 except ValueError: |
1049 return super(MenuRoller, self).keypress(size, key) | 1047 return super(MenuRoller, self).keypress(size, key) |
1050 | 1048 |
1074 @param name: name of the menu to add, it name already exists, menu is not added | 1072 @param name: name of the menu to add, it name already exists, menu is not added |
1075 @param widget: instance of Menu | 1073 @param widget: instance of Menu |
1076 @param menu_id: id to use of this menu, or None to generate | 1074 @param menu_id: id to use of this menu, or None to generate |
1077 @return: menu_id | 1075 @return: menu_id |
1078 """ | 1076 """ |
1079 names = {menu_item.name: id_ for id_, menu_item in self.menu_items.iteritems()} | 1077 names = {menu_item.name: id_ for id_, menu_item in self.menu_items.items()} |
1080 | 1078 |
1081 if name not in names: | 1079 if name not in names: |
1082 id_ = menu_id or str(uuid.uuid4()) | 1080 id_ = menu_id or str(uuid.uuid4()) |
1083 if id_ in self.menu_items: | 1081 if id_ in self.menu_items: |
1084 raise ValueError('Conflict: the id [{}] is already used'.format(id_)) | 1082 raise ValueError('Conflict: the id [{}] is already used'.format(id_)) |
1109 | 1107 |
1110 def removeMenu(self, menu_id): | 1108 def removeMenu(self, menu_id): |
1111 del self.menu_items[menu_id] | 1109 del self.menu_items[menu_id] |
1112 if self.selected == menu_id: | 1110 if self.selected == menu_id: |
1113 try: | 1111 try: |
1114 self.selected = self.menu_items.iterkeys().next() | 1112 self.selected = next(iter(self.menu_items.keys())) |
1115 except StopIteration: | 1113 except StopIteration: |
1116 self.selected = None | 1114 self.selected = None |
1117 self._showSelected() | 1115 self._showSelected() |
1118 | 1116 |
1119 def checkShortcuts(self, key): | 1117 def checkShortcuts(self, key): |
1120 for menu_item in self.menu_items.values(): | 1118 for menu_item in list(self.menu_items.values()): |
1121 key = menu_item.widget.checkShortcuts(key) | 1119 key = menu_item.widget.checkShortcuts(key) |
1122 return key | 1120 return key |
1123 | 1121 |
1124 | 1122 |
1125 ## DIALOGS ## | 1123 ## DIALOGS ## |
1140 self.buttons['yes'] = urwid.Button(_("Yes"), kwargs.get('yes_cb'), kwargs.get('yes_value')) | 1138 self.buttons['yes'] = urwid.Button(_("Yes"), kwargs.get('yes_cb'), kwargs.get('yes_value')) |
1141 self.buttons['no'] = urwid.Button(_("No"), kwargs.get('no_cb'), kwargs.get('no_value')) | 1139 self.buttons['no'] = urwid.Button(_("No"), kwargs.get('no_cb'), kwargs.get('no_value')) |
1142 if "OK" in style: | 1140 if "OK" in style: |
1143 self.buttons['ok'] = urwid.Button(_("Ok"), kwargs.get('ok_cb'), kwargs.get('ok_value')) | 1141 self.buttons['ok'] = urwid.Button(_("Ok"), kwargs.get('ok_cb'), kwargs.get('ok_value')) |
1144 if self.buttons: | 1142 if self.buttons: |
1145 buttons_flow = urwid.GridFlow(self.buttons.values(), max([len(button.get_label()) for button in self.buttons.itervalues()])+4, 1, 1, 'center') | 1143 buttons_flow = urwid.GridFlow(list(self.buttons.values()), max([len(button.get_label()) for button in self.buttons.values()])+4, 1, 1, 'center') |
1146 body_content = urwid.SimpleListWalker(widgets_lst) | 1144 body_content = urwid.SimpleListWalker(widgets_lst) |
1147 frame_body = UnselectableListBox(body_content) | 1145 frame_body = UnselectableListBox(body_content) |
1148 frame = FocusFrame(frame_body, frame_header, buttons_flow if self.buttons else None, 'footer' if self.buttons else 'body') | 1146 frame = FocusFrame(frame_body, frame_header, buttons_flow if self.buttons else None, 'footer' if self.buttons else 'body') |
1149 decorated_frame = urwid.LineBox(frame) | 1147 decorated_frame = urwid.LineBox(frame) |
1150 urwid.WidgetWrap.__init__(self, decorated_frame) | 1148 urwid.WidgetWrap.__init__(self, decorated_frame) |
1328 for width,widget in self.widget_list[start_wid:end_wid+1]: | 1326 for width,widget in self.widget_list[start_wid:end_wid+1]: |
1329 _focus = idx == self.focus_column and focus | 1327 _focus = idx == self.focus_column and focus |
1330 render.append((widget.render((width,),_focus),False,_focus,width)) | 1328 render.append((widget.render((width,),_focus),False,_focus,width)) |
1331 idx+=1 | 1329 idx+=1 |
1332 if _prev: | 1330 if _prev: |
1333 render.insert(0,(urwid.Text([u"◀"]).render((1,),False),False,False,1)) | 1331 render.insert(0,(urwid.Text(["◀"]).render((1,),False),False,False,1)) |
1334 if _next: | 1332 if _next: |
1335 render.append((urwid.Text([u"▶"],align='right').render((1+cols_left,),False),False,False,1+cols_left)) | 1333 render.append((urwid.Text(["▶"],align='right').render((1+cols_left,),False),False,False,1+cols_left)) |
1336 else: | 1334 else: |
1337 render.append((urwid.SolidCanvas(" "*cols_left, size[0], 1),False,False,cols_left)) | 1335 render.append((urwid.SolidCanvas(" "*cols_left, size[0], 1),False,False,cols_left)) |
1338 | 1336 |
1339 return urwid.CanvasJoin(render) | 1337 return urwid.CanvasJoin(render) |
1340 | 1338 |
1426 | 1424 |
1427 def __init__(self): | 1425 def __init__(self): |
1428 self._current_tab = None | 1426 self._current_tab = None |
1429 self._buttons_cont = ColumnsRoller() | 1427 self._buttons_cont = ColumnsRoller() |
1430 self.tabs = [] | 1428 self.tabs = [] |
1431 self._frame = FocusFrame(urwid.Filler(urwid.Text('')),urwid.Pile([self._buttons_cont,urwid.Divider(u"─")])) | 1429 self._frame = FocusFrame(urwid.Filler(urwid.Text('')),urwid.Pile([self._buttons_cont,urwid.Divider("─")])) |
1432 urwid.WidgetWrap.__init__(self, self._frame) | 1430 urwid.WidgetWrap.__init__(self, self._frame) |
1433 | 1431 |
1434 def keypress(self, size, key): | 1432 def keypress(self, size, key): |
1435 return self._w.keypress(size,key) | 1433 return self._w.keypress(size,key) |
1436 | 1434 |
1674 top_columns = self._w.widget_list[0] | 1672 top_columns = self._w.widget_list[0] |
1675 top_columns.widget_list[1] = label_widget | 1673 top_columns.widget_list[1] = label_widget |
1676 | 1674 |
1677 | 1675 |
1678 class VerticalSeparator(urwid.WidgetDecoration, urwid.WidgetWrap): | 1676 class VerticalSeparator(urwid.WidgetDecoration, urwid.WidgetWrap): |
1679 def __init__(self, original_widget, left_char = u"│", right_char = ''): | 1677 def __init__(self, original_widget, left_char = "│", right_char = ''): |
1680 """Draw a separator on left and/or right of original_widget.""" | 1678 """Draw a separator on left and/or right of original_widget.""" |
1681 | 1679 |
1682 widgets = [original_widget] | 1680 widgets = [original_widget] |
1683 if left_char: | 1681 if left_char: |
1684 widgets.insert(0, ('fixed', 1, urwid.SolidFill(left_char))) | 1682 widgets.insert(0, ('fixed', 1, urwid.SolidFill(left_char))) |