Mercurial > urwid-satext
comparison urwid_satext/sat_widgets.py @ 151:6689aa54b20c default tip
refactoring from camelCase -> snake_case:
This libraries was using camelCase due for historical reasons (related to the use of
Twisted in the initial project).
This patch fixes it by using PEP8 compliant snake_case
author | Goffi <goffi@goffi.org> |
---|---|
date | Sat, 08 Apr 2023 15:38:18 +0200 |
parents | aa8f46b43a71 |
children |
comparison
equal
deleted
inserted
replaced
150:aa8f46b43a71 | 151:6689aa54b20c |
---|---|
28 from .keys import action_key_map as a_key | 28 from .keys import action_key_map as a_key |
29 | 29 |
30 FOCUS_KEYS = (a_key['FOCUS_SWITCH'], a_key['FOCUS_UP'], a_key['FOCUS_DOWN']) | 30 FOCUS_KEYS = (a_key['FOCUS_SWITCH'], a_key['FOCUS_UP'], a_key['FOCUS_DOWN']) |
31 | 31 |
32 | 32 |
33 def getFocusDirection(key, inversed=False): | 33 def get_focus_direction(key, inversed=False): |
34 """Return direction and rotate boolean depending on key | 34 """Return direction and rotate boolean depending on key |
35 @param key: one of FOCUS_KEYS | 35 @param key: one of FOCUS_KEYS |
36 @param inversed: inverse directions if True | 36 @param inversed: inverse directions if True |
37 @return (tuple): (direction, rotate) where | 37 @return (tuple): (direction, rotate) where |
38 - direction is 1 or -1 | 38 - direction is 1 or -1 |
54 - C-k: remove everything on the right of the cursor | 54 - C-k: remove everything on the right of the cursor |
55 - C-w: remove the word on the back | 55 - C-w: remove the word on the back |
56 new behaviour: emit a 'click' signal when enter is pressed""" | 56 new behaviour: emit a 'click' signal when enter is pressed""" |
57 signals = urwid.Edit.signals + ['click'] | 57 signals = urwid.Edit.signals + ['click'] |
58 | 58 |
59 def getValue(self): | 59 def get_value(self): |
60 return self.get_edit_text() | 60 return self.get_edit_text() |
61 | 61 |
62 def setCompletionMethod(self, callback): | 62 def set_completion_method(self, callback): |
63 """Define method called when completion is asked | 63 """Define method called when completion is asked |
64 | 64 |
65 @callback: method with 2 arguments: | 65 @callback: method with 2 arguments: |
66 - the text to complete (part after cursor position is ignored) | 66 - the text to complete (part after cursor position is ignored) |
67 - if there was already a completion, a dict with | 67 - if there was already a completion, a dict with |
173 self._mode = mode | 173 self._mode = mode |
174 self.set_caption(caption) | 174 self.set_caption(caption) |
175 if not mode_key: #we are in NORMAL mode | 175 if not mode_key: #we are in NORMAL mode |
176 self.set_edit_text('') | 176 self.set_edit_text('') |
177 | 177 |
178 def setCompletionMethod(self, callback): | 178 def set_completion_method(self, callback): |
179 """ Same as AdvancedEdit.setCompletionMethod, but with a third argument: current mode""" | 179 """ Same as AdvancedEdit.set_completion_method, but with a third argument: current mode""" |
180 super(ModalEdit, self).setCompletionMethod(lambda text,data: callback(text, data, self._mode)) | 180 super(ModalEdit, self).set_completion_method(lambda text,data: callback(text, data, self._mode)) |
181 | 181 |
182 def keypress(self, size, key): | 182 def keypress(self, size, key): |
183 if key == a_key['MODAL_ESCAPE']: | 183 if key == a_key['MODAL_ESCAPE']: |
184 self.mode = "NORMAL" | 184 self.mode = "NORMAL" |
185 return | 185 return |
225 self._selected = False | 225 self._selected = False |
226 self._was_focused = False | 226 self._was_focused = False |
227 self.header = header | 227 self.header = header |
228 self.text = text | 228 self.text = text |
229 urwid.WidgetWrap.__init__(self, urwid.Text("",align=align)) | 229 urwid.WidgetWrap.__init__(self, urwid.Text("",align=align)) |
230 self.setSelectedText(selected_text) | 230 self.set_selected_text(selected_text) |
231 self.setState(selected) | 231 self.set_state(selected) |
232 | 232 |
233 def getValue(self): | 233 def get_value(self): |
234 if isinstance(self.text,str): | 234 if isinstance(self.text,str): |
235 return self.text | 235 return self.text |
236 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] |
237 txt = "" | 237 txt = "" |
238 for attr in list_attr: | 238 for attr in list_attr: |
242 txt+=attr | 242 txt+=attr |
243 return txt | 243 return txt |
244 | 244 |
245 def get_text(self): | 245 def get_text(self): |
246 """for compatibility with urwid.Text""" | 246 """for compatibility with urwid.Text""" |
247 return self.getValue() | 247 return self.get_value() |
248 | 248 |
249 def set_text(self, text): | 249 def set_text(self, text): |
250 """/!\ set_text doesn't change self.selected_txt !""" | 250 """/!\ set_text doesn't change self.selected_txt !""" |
251 self.text = text | 251 self.text = text |
252 self.setState(self._selected,invisible=True) | 252 self.set_state(self._selected,invisible=True) |
253 | 253 |
254 def setSelectedText(self, text=None): | 254 def set_selected_text(self, text=None): |
255 """Text to display when selected | 255 """Text to display when selected |
256 | 256 |
257 @text: text as in urwid.Text or None for default value | 257 @text: text as in urwid.Text or None for default value |
258 """ | 258 """ |
259 if text == None: | 259 if text == None: |
260 text = ('selected',self.getValue()) | 260 text = ('selected',self.get_value()) |
261 self.selected_txt = text | 261 self.selected_txt = text |
262 if self._selected: | 262 if self._selected: |
263 self.setState(self._selected) | 263 self.set_state(self._selected) |
264 | 264 |
265 def _set_txt(self): | 265 def _set_txt(self): |
266 txt_list = [self.header] | 266 txt_list = [self.header] |
267 txt = self.selected_txt if self._selected else self.text | 267 txt = self.selected_txt if self._selected else self.text |
268 if isinstance(txt,list): | 268 if isinstance(txt,list): |
270 else: | 270 else: |
271 txt_list.append(txt) | 271 txt_list.append(txt) |
272 self._w.base_widget.set_text(txt_list) | 272 self._w.base_widget.set_text(txt_list) |
273 | 273 |
274 | 274 |
275 def setState(self, selected, invisible=False): | 275 def set_state(self, selected, invisible=False): |
276 """Change state | 276 """Change state |
277 | 277 |
278 @param selected: boolean state value | 278 @param selected: boolean state value |
279 @param invisible: don't emit change signal if True | 279 @param invisible: don't emit change signal if True |
280 """ | 280 """ |
284 self._was_focused = False | 284 self._was_focused = False |
285 self._invalidate() | 285 self._invalidate() |
286 if not invisible: | 286 if not invisible: |
287 self._emit("change", self._selected) | 287 self._emit("change", self._selected) |
288 | 288 |
289 def getState(self): | 289 def get_state(self): |
290 return self._selected | 290 return self._selected |
291 | 291 |
292 def selectable(self): | 292 def selectable(self): |
293 return True | 293 return True |
294 | 294 |
295 def keypress(self, size, key): | 295 def keypress(self, size, key): |
296 if key in (a_key['TEXT_SELECT'], a_key['TEXT_SELECT2']): | 296 if key in (a_key['TEXT_SELECT'], a_key['TEXT_SELECT2']): |
297 self.setState(not self._selected) | 297 self.set_state(not self._selected) |
298 else: | 298 else: |
299 return key | 299 return key |
300 | 300 |
301 def mouse_event(self, size, event, button, x, y, focus): | 301 def mouse_event(self, size, event, button, x, y, focus): |
302 if is_mouse_press(event) and button == 1: | 302 if is_mouse_press(event) and button == 1: |
303 self.setState(not self._selected) | 303 self.set_state(not self._selected) |
304 return True | 304 return True |
305 | 305 |
306 return False | 306 return False |
307 | 307 |
308 def render(self, size, focus=False): | 308 def render(self, size, focus=False): |
338 | 338 |
339 | 339 |
340 class ClickableText(SelectableText): | 340 class ClickableText(SelectableText): |
341 signals = SelectableText.signals + ['click'] | 341 signals = SelectableText.signals + ['click'] |
342 | 342 |
343 def setState(self, selected, invisible=False): | 343 def set_state(self, selected, invisible=False): |
344 super(ClickableText,self).setState(False,True) | 344 super(ClickableText,self).set_state(False,True) |
345 if not invisible: | 345 if not invisible: |
346 self._emit('click') | 346 self._emit('click') |
347 | 347 |
348 | 348 |
349 class CustomButton(ClickableText): | 349 class CustomButton(ClickableText): |
355 super(CustomButton, self).__init__([left_border, label, right_border], align=align) | 355 super(CustomButton, self).__init__([left_border, label, right_border], align=align) |
356 self.size = len(self.get_text()) | 356 self.size = len(self.get_text()) |
357 if on_press: | 357 if on_press: |
358 urwid.connect_signal(self, 'click', on_press, user_data) | 358 urwid.connect_signal(self, 'click', on_press, user_data) |
359 | 359 |
360 def getSize(self): | 360 def get_size(self): |
361 """Return representation size of the button""" | 361 """Return representation size of the button""" |
362 return self.size | 362 return self.size |
363 | 363 |
364 def get_label(self): | 364 def get_label(self): |
365 return self.label[1] if isinstance(self.label,tuple) else self.label | 365 return self.label[1] if isinstance(self.label,tuple) else self.label |
421 @value.setter | 421 @value.setter |
422 def value(self, value): | 422 def value(self, value): |
423 self._value = value | 423 self._value = value |
424 | 424 |
425 @staticmethod | 425 @staticmethod |
426 def fromOptions(options): | 426 def from_options(options): |
427 """ convert a list of string/tuple options to a list of listOption | 427 """ convert a list of string/tuple options to a list of listOption |
428 @param options: list of managed option type (basestring, tuple) | 428 @param options: list of managed option type (basestring, tuple) |
429 return: list of ListOption | 429 return: list of ListOption |
430 """ | 430 """ |
431 return [(ListOption(option)) for option in options] | 431 return [(ListOption(option)) for option in options] |
475 for content in contents: | 475 for content in contents: |
476 on_new(content) | 476 on_new(content) |
477 self._on_new = on_new | 477 self._on_new = on_new |
478 self._on_delete = on_delete | 478 self._on_delete = on_delete |
479 | 479 |
480 def __cbSingle(self, item, cb): | 480 def __cb_single(self, item, cb): |
481 try: | 481 try: |
482 cb(item) | 482 cb(item) |
483 except TypeError: | 483 except TypeError: |
484 pass | 484 pass |
485 | 485 |
486 def __cbMulti(self, items, cb): | 486 def __cb_multi(self, items, cb): |
487 if cb is not None: | 487 if cb is not None: |
488 for item in items: | 488 for item in items: |
489 cb(item) | 489 cb(item) |
490 | 490 |
491 def __add__(self, new_list): | 491 def __add__(self, new_list): |
492 self.__cbMulti(new_list, self._on_new) | 492 self.__cb_multi(new_list, self._on_new) |
493 return super(SimpleListWalkerWithCb, self).__add__(new_list) | 493 return super(SimpleListWalkerWithCb, self).__add__(new_list) |
494 | 494 |
495 def __delitem__(self, item): | 495 def __delitem__(self, item): |
496 self.__cbSingle(item, self._on_delete) | 496 self.__cb_single(item, self._on_delete) |
497 return super(SimpleListWalkerWithCb, self).__delitem__(item) | 497 return super(SimpleListWalkerWithCb, self).__delitem__(item) |
498 | 498 |
499 def __delslice__(self, i,j): | 499 def __delslice__(self, i,j): |
500 items = super(SimpleListWalkerWithCb, self).__getslice__(i,j) | 500 items = super(SimpleListWalkerWithCb, self).__getslice__(i,j) |
501 self.__cbMulti(items, self._on_delete) | 501 self.__cb_multi(items, self._on_delete) |
502 return super(SimpleListWalkerWithCb, self).__delslice(i,j) | 502 return super(SimpleListWalkerWithCb, self).__delslice(i,j) |
503 | 503 |
504 def __iadd__(self, y): | 504 def __iadd__(self, y): |
505 raise NotImplementedError | 505 raise NotImplementedError |
506 | 506 |
513 def __rmul__(self, n): | 513 def __rmul__(self, n): |
514 raise NotImplementedError | 514 raise NotImplementedError |
515 | 515 |
516 def __setitem__(self, i, y): | 516 def __setitem__(self, i, y): |
517 parent = super(SimpleListWalkerWithCb, self) | 517 parent = super(SimpleListWalkerWithCb, self) |
518 self.__cbSingle(y, self._on_new) | 518 self.__cb_single(y, self._on_new) |
519 to_delete = parent.__getitem__(i) | 519 to_delete = parent.__getitem__(i) |
520 self.__cbSingle(to_delete, self._on_delete) | 520 self.__cb_single(to_delete, self._on_delete) |
521 return parent.__setitem__(i, y) | 521 return parent.__setitem__(i, y) |
522 | 522 |
523 def __setslice__(self, i, j, y): | 523 def __setslice__(self, i, j, y): |
524 parent = super(SimpleListWalkerWithCb, self) | 524 parent = super(SimpleListWalkerWithCb, self) |
525 items_to_delete = parent.__getslice__(i,j) | 525 items_to_delete = parent.__getslice__(i,j) |
526 self.__cbMulti(items_to_delete, self._on_delete) | 526 self.__cb_multi(items_to_delete, self._on_delete) |
527 if hasattr(y, '__iter__'): | 527 if hasattr(y, '__iter__'): |
528 self.__cbMulti(y, self._on_new) | 528 self.__cb_multi(y, self._on_new) |
529 else: | 529 else: |
530 self.__cbSingle(y, self._on_new) | 530 self.__cb_single(y, self._on_new) |
531 return parent.__setslice__(i, j, y) | 531 return parent.__setslice__(i, j, y) |
532 | 532 |
533 def append(self, obj): | 533 def append(self, obj): |
534 self.__cbSingle(obj, self._on_new) | 534 self.__cb_single(obj, self._on_new) |
535 return super(SimpleListWalkerWithCb, self).append(obj) | 535 return super(SimpleListWalkerWithCb, self).append(obj) |
536 | 536 |
537 def extend(self, it): | 537 def extend(self, it): |
538 self.__cbMulti(it, self.__on_new) | 538 self.__cb_multi(it, self.__on_new) |
539 return super(SimpleListWalkerWithCb, self).extend(it) | 539 return super(SimpleListWalkerWithCb, self).extend(it) |
540 | 540 |
541 def insert(self, idx, obj): | 541 def insert(self, idx, obj): |
542 self.__cbSingle(obj, self.__on_new) | 542 self.__cb_single(obj, self.__on_new) |
543 return super(SimpleListWalkerWithCb, self).insert(idx, obj) | 543 return super(SimpleListWalkerWithCb, self).insert(idx, obj) |
544 | 544 |
545 def pop(self, idx=None): | 545 def pop(self, idx=None): |
546 if idx is None: | 546 if idx is None: |
547 idx=len(self)-1 | 547 idx=len(self)-1 |
548 | 548 |
549 parent = super(SimpleListWalkerWithCb, self) | 549 parent = super(SimpleListWalkerWithCb, self) |
550 to_remove = parent.__getitem__(idx) | 550 to_remove = parent.__getitem__(idx) |
551 self.__cbSingle(to_remove, self._on_delete) | 551 self.__cb_single(to_remove, self._on_delete) |
552 return parent.pop(idx) | 552 return parent.pop(idx) |
553 | 553 |
554 def remove(self, val): | 554 def remove(self, val): |
555 ret = super(SimpleListWalkerWithCb, self).remove(val) | 555 ret = super(SimpleListWalkerWithCb, self).remove(val) |
556 self.__cbSingle(val, self._on_delete) | 556 self.__cb_single(val, self._on_delete) |
557 return ret | 557 return ret |
558 | 558 |
559 | 559 |
560 class GenericList(urwid.ListBox): | 560 class GenericList(urwid.ListBox): |
561 signals = ['click','change'] | 561 signals = ['click','change'] |
589 urwid.connect_signal(self, 'click', on_click, user_data) | 589 urwid.connect_signal(self, 'click', on_click, user_data) |
590 | 590 |
591 if on_change: | 591 if on_change: |
592 urwid.connect_signal(self, 'change', on_change, user_data) | 592 urwid.connect_signal(self, 'change', on_change, user_data) |
593 | 593 |
594 self.content = SimpleListWalkerWithCb([], self._addSignals, lambda widget: self._emit('change')) | 594 self.content = SimpleListWalkerWithCb([], self._add_signals, lambda widget: self._emit('change')) |
595 super(GenericList, self).__init__(self.content) | 595 super(GenericList, self).__init__(self.content) |
596 self.changeValues(options) | 596 self.change_values(options) |
597 | 597 |
598 def _addSignals(self, widget): | 598 def _add_signals(self, widget): |
599 for signal, callback in (('change', self._onStateChange), ('click', self._onClick)): | 599 for signal, callback in (('change', self._on_state_change), ('click', self._on_click)): |
600 try: | 600 try: |
601 urwid.connect_signal(widget, signal, callback) | 601 urwid.connect_signal(widget, signal, callback) |
602 except NameError: | 602 except NameError: |
603 pass #the widget given doesn't support the signal | 603 pass #the widget given doesn't support the signal |
604 | 604 |
605 @property | 605 @property |
606 def contents(self): | 606 def contents(self): |
607 return self.content | 607 return self.content |
608 | 608 |
609 def _onStateChange(self, widget, selected, *args): | 609 def _on_state_change(self, widget, selected, *args): |
610 if self.single: | 610 if self.single: |
611 if not selected and not self.can_select_none: | 611 if not selected and not self.can_select_none: |
612 #if in single mode, it's forbidden to unselect a value | 612 #if in single mode, it's forbidden to unselect a value |
613 widget.setState(True, invisible=True) | 613 widget.set_state(True, invisible=True) |
614 return | 614 return |
615 if selected: | 615 if selected: |
616 self.unselectAll(invisible=True) | 616 self.unselect_all(invisible=True) |
617 widget.setState(True, invisible=True) | 617 widget.set_state(True, invisible=True) |
618 self._emit("change", widget, selected, *args) | 618 self._emit("change", widget, selected, *args) |
619 | 619 |
620 def _onClick(self, widget, *args): | 620 def _on_click(self, widget, *args): |
621 if widget not in self.content: | 621 if widget not in self.content: |
622 urwid.disconnect_signal(widget, "click", self._onClick) | 622 urwid.disconnect_signal(widget, "click", self._on_click) |
623 return | 623 return |
624 self._emit("click", widget, *args) | 624 self._emit("click", widget, *args) |
625 | 625 |
626 def unselectAll(self, invisible=False): | 626 def unselect_all(self, invisible=False): |
627 for widget in self.content: | 627 for widget in self.content: |
628 if widget.getState(): | 628 if widget.get_state(): |
629 widget.setState(False, invisible) | 629 widget.set_state(False, invisible) |
630 widget._invalidate() | 630 widget._invalidate() |
631 | 631 |
632 def deleteValue(self, value): | 632 def delete_value(self, value): |
633 """Delete the first value equal to the param given""" | 633 """Delete the first value equal to the param given""" |
634 for widget in self.content: | 634 for widget in self.content: |
635 if widget.getValue() == value: | 635 if widget.get_value() == value: |
636 self.content.remove(widget) | 636 self.content.remove(widget) |
637 self._emit('change') | 637 self._emit('change') |
638 return | 638 return |
639 raise ValueError("%s ==> %s" % (str(value),str(self.content))) | 639 raise ValueError("%s ==> %s" % (str(value),str(self.content))) |
640 | 640 |
641 def getSelectedValue(self): | 641 def get_selected_value(self): |
642 """Convenience method to get the value selected as a string in single mode, or None""" | 642 """Convenience method to get the value selected as a string in single mode, or None""" |
643 values = self.getSelectedValues() | 643 values = self.get_selected_values() |
644 return values[0] if values else None | 644 return values[0] if values else None |
645 | 645 |
646 def getAllValues(self): | 646 def get_all_values(self): |
647 """Return values of all items""" | 647 """Return values of all items""" |
648 return [widget.getValue() for widget in self.content] | 648 return [widget.get_value() for widget in self.content] |
649 | 649 |
650 def getSelectedValues(self): | 650 def get_selected_values(self): |
651 """Return values of selected items""" | 651 """Return values of selected items""" |
652 result = [] | 652 result = [] |
653 for widget in self.content: | 653 for widget in self.content: |
654 if widget.getState(): | 654 if widget.get_state(): |
655 result.append(widget.getValue()) | 655 result.append(widget.get_value()) |
656 return result | 656 return result |
657 | 657 |
658 def on_option_change(self, wid, *args, **kwargs): | 658 def on_option_change(self, wid, *args, **kwargs): |
659 if self.single: | 659 if self.single: |
660 for w in self.content: | 660 for w in self.content: |
661 if w is not wid: | 661 if w is not wid: |
662 w.setState(False, invisible=True) | 662 w.set_state(False, invisible=True) |
663 | 663 |
664 def changeValues(self, new_values): | 664 def change_values(self, new_values): |
665 """Change all values in one shot""" | 665 """Change all values in one shot""" |
666 new_values = ListOption.fromOptions(new_values) | 666 new_values = ListOption.from_options(new_values) |
667 old_selected = self.getSelectedValues() if not self.first_display else [] | 667 old_selected = self.get_selected_values() if not self.first_display else [] |
668 widgets = [] | 668 widgets = [] |
669 for option in new_values: | 669 for option in new_values: |
670 widget = self.option_type(option, align=self.align) | 670 widget = self.option_type(option, align=self.align) |
671 urwid.connect_signal(widget, "change", self.on_option_change) | 671 urwid.connect_signal(widget, "change", self.on_option_change) |
672 if not self.first_display and option in old_selected: | 672 if not self.first_display and option in old_selected: |
673 widget.setState(True) | 673 widget.set_state(True) |
674 widgets.append(widget) | 674 widgets.append(widget) |
675 self.content[:] = widgets | 675 self.content[:] = widgets |
676 if self.first_display and self.single and new_values and not self.no_first_select: | 676 if self.first_display and self.single and new_values and not self.no_first_select: |
677 self.content[0].setState(True) | 677 self.content[0].set_state(True) |
678 self._emit('change') | 678 self._emit('change') |
679 self.first_display = False | 679 self.first_display = False |
680 | 680 |
681 def selectValue(self, value, move_focus=True): | 681 def select_value(self, value, move_focus=True): |
682 """Select the first item which has the given value. | 682 """Select the first item which has the given value. |
683 | 683 |
684 @param value | 684 @param value |
685 @param move_focus (bool): | 685 @param move_focus (bool): |
686 - True to move the focus on the selected value, | 686 - True to move the focus on the selected value, |
687 - False to leave the focus position unchanged. | 687 - False to leave the focus position unchanged. |
688 | 688 |
689 """ | 689 """ |
690 self.unselectAll() | 690 self.unselect_all() |
691 idx = 0 | 691 idx = 0 |
692 for widget in self.content: | 692 for widget in self.content: |
693 if widget.getValue() == value: | 693 if widget.get_value() == value: |
694 widget.setState(True) | 694 widget.set_state(True) |
695 if move_focus: | 695 if move_focus: |
696 self.focus_position = idx | 696 self.focus_position = idx |
697 return | 697 return |
698 idx+=1 | 698 idx+=1 |
699 | 699 |
700 def selectValues(self, values, move_focus=True): | 700 def select_values(self, values, move_focus=True): |
701 """Select all the given values. | 701 """Select all the given values. |
702 | 702 |
703 @param values [set, list] | 703 @param values [set, list] |
704 @param move_focus (boolean): True to move the focus on the last selected value, | 704 @param move_focus (boolean): True to move the focus on the last selected value, |
705 False to leave the focus position unchanged. | 705 False to leave the focus position unchanged. |
706 """ | 706 """ |
707 if self.single: | 707 if self.single: |
708 if values: | 708 if values: |
709 self.selectValue(values[-1], move_focus) | 709 self.select_value(values[-1], move_focus) |
710 return | 710 return |
711 self.unselectAll() | 711 self.unselect_all() |
712 for value in values: | 712 for value in values: |
713 idx = 0 | 713 idx = 0 |
714 for widget in self.content: | 714 for widget in self.content: |
715 if widget.getValue() == value: | 715 if widget.get_value() == value: |
716 widget.setState(True) | 716 widget.set_state(True) |
717 if move_focus: | 717 if move_focus: |
718 self.focus_position = idx | 718 self.focus_position = idx |
719 idx += 1 | 719 idx += 1 |
720 | 720 |
721 | 721 |
737 | 737 |
738 def selectable(self): | 738 def selectable(self): |
739 return True | 739 return True |
740 | 740 |
741 def get_cursor_coords(self, size): | 741 def get_cursor_coords(self, size): |
742 return self.genericList.get_cursor_coords((size[0], self._getHeight(size, True))) | 742 return self.genericList.get_cursor_coords((size[0], self._get_height(size, True))) |
743 | 743 |
744 def keypress(self, size, key): | 744 def keypress(self, size, key): |
745 return self.displayWidget(size,True).keypress(size, key) | 745 return self.display_widget(size,True).keypress(size, key) |
746 | 746 |
747 def unselectAll(self, invisible=False): | 747 def unselect_all(self, invisible=False): |
748 return self.genericList.unselectAll(invisible) | 748 return self.genericList.unselect_all(invisible) |
749 | 749 |
750 def deleteValue(self, value): | 750 def delete_value(self, value): |
751 return self.genericList.deleteValue(value) | 751 return self.genericList.delete_value(value) |
752 | 752 |
753 def getSelectedValue(self): | 753 def get_selected_value(self): |
754 return self.genericList.getSelectedValue() | 754 return self.genericList.get_selected_value() |
755 | 755 |
756 def getAllValues(self): | 756 def get_all_values(self): |
757 return self.genericList.getAllValues() | 757 return self.genericList.get_all_values() |
758 | 758 |
759 def getSelectedValues(self): | 759 def get_selected_values(self): |
760 return self.genericList.getSelectedValues() | 760 return self.genericList.get_selected_values() |
761 | 761 |
762 def changeValues(self, new_values): | 762 def change_values(self, new_values): |
763 return self.genericList.changeValues(new_values) | 763 return self.genericList.change_values(new_values) |
764 | 764 |
765 def selectValue(self, value, move_focus=True): | 765 def select_value(self, value, move_focus=True): |
766 return self.genericList.selectValue(value, move_focus) | 766 return self.genericList.select_value(value, move_focus) |
767 | 767 |
768 def selectValues(self, values, move_focus=True): | 768 def select_values(self, values, move_focus=True): |
769 return self.genericList.selectValues(values, move_focus) | 769 return self.genericList.select_values(values, move_focus) |
770 | 770 |
771 def render(self, size, focus=False): | 771 def render(self, size, focus=False): |
772 return self.displayWidget(size, focus).render(size, focus) | 772 return self.display_widget(size, focus).render(size, focus) |
773 | 773 |
774 def rows(self, size, focus=False): | 774 def rows(self, size, focus=False): |
775 return self.displayWidget(size, focus).rows(size, focus) | 775 return self.display_widget(size, focus).rows(size, focus) |
776 | 776 |
777 def _getHeight(self, size, focus): | 777 def _get_height(self, size, focus): |
778 list_size = sum([wid.rows(size, focus) for wid in self.genericList.content]) | 778 list_size = sum([wid.rows(size, focus) for wid in self.genericList.content]) |
779 height = min(list_size,self.max_height) or 1 | 779 height = min(list_size,self.max_height) or 1 |
780 return height | 780 return height |
781 | 781 |
782 def displayWidget(self, size, focus): | 782 def display_widget(self, size, focus): |
783 return urwid.BoxAdapter(self.genericList, self._getHeight(size, focus)) | 783 return urwid.BoxAdapter(self.genericList, self._get_height(size, focus)) |
784 | 784 |
785 | 785 |
786 ## MISC ## | 786 ## MISC ## |
787 | 787 |
788 class NotificationBar(urwid.WidgetWrap): | 788 class NotificationBar(urwid.WidgetWrap): |
790 signals = ['change'] | 790 signals = ['change'] |
791 | 791 |
792 def __init__(self): | 792 def __init__(self): |
793 self.waitNotifs = urwid.Text('') | 793 self.waitNotifs = urwid.Text('') |
794 self.message = ClickableText('') | 794 self.message = ClickableText('') |
795 urwid.connect_signal(self.message, 'click', lambda wid: self.showNext()) | 795 urwid.connect_signal(self.message, 'click', lambda wid: self.show_next()) |
796 self.progress = ClickableText('') | 796 self.progress = ClickableText('') |
797 self.columns = urwid.Columns([('fixed',6,self.waitNotifs),self.message,('fixed',4,self.progress)]) | 797 self.columns = urwid.Columns([('fixed',6,self.waitNotifs),self.message,('fixed',4,self.progress)]) |
798 urwid.WidgetWrap.__init__(self, urwid.AttrMap(self.columns,'notifs')) | 798 urwid.WidgetWrap.__init__(self, urwid.AttrMap(self.columns,'notifs')) |
799 self.notifs = [] | 799 self.notifs = [] |
800 | 800 |
801 def _modQueue(self): | 801 def _mod_queue(self): |
802 """must be called each time the notifications queue is changed""" | 802 """must be called each time the notifications queue is changed""" |
803 self.waitNotifs.set_text(('notifs',"(%i)" % len(self.notifs) if self.notifs else '')) | 803 self.waitNotifs.set_text(('notifs',"(%i)" % len(self.notifs) if self.notifs else '')) |
804 self._emit('change') | 804 self._emit('change') |
805 | 805 |
806 def setProgress(self,percentage): | 806 def set_progress(self,percentage): |
807 """Define the progression to show on the right side of the bar""" | 807 """Define the progression to show on the right side of the bar""" |
808 if percentage == None: | 808 if percentage == None: |
809 self.progress.set_text('') | 809 self.progress.set_text('') |
810 else: | 810 else: |
811 self.progress.set_text(('notifs','%02i%%' % percentage)) | 811 self.progress.set_text(('notifs','%02i%%' % percentage)) |
812 if self.columns.focus != self.progress: | 812 if self.columns.focus != self.progress: |
813 self.columns.focus_position = len(self.columns.contents)-1 | 813 self.columns.focus_position = len(self.columns.contents)-1 |
814 self._emit('change') | 814 self._emit('change') |
815 | 815 |
816 def addPopUp(self, pop_up_widget): | 816 def add_pop_up(self, pop_up_widget): |
817 """Add a popup to the waiting queue""" | 817 """Add a popup to the waiting queue""" |
818 self.notifs.append(('popup',pop_up_widget)) | 818 self.notifs.append(('popup',pop_up_widget)) |
819 self._modQueue() | 819 self._mod_queue() |
820 | 820 |
821 def removePopUp(self, pop_up_widget): | 821 def remove_pop_up(self, pop_up_widget): |
822 """Remove a popup from the waiting queue""" | 822 """Remove a popup from the waiting queue""" |
823 for idx, (wid_type, widget) in enumerate(self.notifs): | 823 for idx, (wid_type, widget) in enumerate(self.notifs): |
824 if widget == pop_up_widget: | 824 if widget == pop_up_widget: |
825 del self.notifs[idx] | 825 del self.notifs[idx] |
826 self._modQueue() | 826 self._mod_queue() |
827 return | 827 return |
828 | 828 |
829 raise ValueError("trying to remove an unknown pop_up_widget") | 829 raise ValueError("trying to remove an unknown pop_up_widget") |
830 | 830 |
831 def addMessage(self, message): | 831 def add_message(self, message): |
832 "Add a message to the notificatio bar" | 832 "Add a message to the notificatio bar" |
833 if not self.message.get_text(): | 833 if not self.message.get_text(): |
834 self.message.set_text(('notifs',message)) | 834 self.message.set_text(('notifs',message)) |
835 self._invalidate() | 835 self._invalidate() |
836 self._emit('change') | 836 self._emit('change') |
837 else: | 837 else: |
838 self.notifs.append(('message',message)) | 838 self.notifs.append(('message',message)) |
839 self._modQueue() | 839 self._mod_queue() |
840 | 840 |
841 def showNext(self): | 841 def show_next(self): |
842 """Show next message if any, else delete current message""" | 842 """Show next message if any, else delete current message""" |
843 found = None | 843 found = None |
844 for notif in self.notifs: | 844 for notif in self.notifs: |
845 if notif[0] == "message": | 845 if notif[0] == "message": |
846 found = notif | 846 found = notif |
847 break | 847 break |
848 if found: | 848 if found: |
849 self.notifs.remove(found) | 849 self.notifs.remove(found) |
850 self.message.set_text(('notifs',found[1])) | 850 self.message.set_text(('notifs',found[1])) |
851 self._modQueue() | 851 self._mod_queue() |
852 self.focus_possition = 1 | 852 self.focus_possition = 1 |
853 else: | 853 else: |
854 self.message.set_text('') | 854 self.message.set_text('') |
855 self._emit('change') | 855 self._emit('change') |
856 | 856 |
857 def getNextPopup(self): | 857 def get_next_popup(self): |
858 """Return next pop-up and remove it from the queue | 858 """Return next pop-up and remove it from the queue |
859 @return: pop-up or None if there is no more in the queue""" | 859 @return: pop-up or None if there is no more in the queue""" |
860 ret = None | 860 ret = None |
861 for notif in self.notifs: | 861 for notif in self.notifs: |
862 if notif[0] == 'popup': | 862 if notif[0] == 'popup': |
863 ret = notif[1] | 863 ret = notif[1] |
864 break | 864 break |
865 if ret: | 865 if ret: |
866 self.notifs.remove(notif) | 866 self.notifs.remove(notif) |
867 self._modQueue() | 867 self._mod_queue() |
868 return ret | 868 return ret |
869 | 869 |
870 def isQueueEmpty(self): | 870 def is_queue_empty(self): |
871 return not bool(self.notifs) | 871 return not bool(self.notifs) |
872 | 872 |
873 def canHide(self): | 873 def can_hide(self): |
874 """Return True if there is no important information to show""" | 874 """Return True if there is no important information to show""" |
875 return self.isQueueEmpty() and not self.message.get_text() and not self.progress.get_text() | 875 return self.is_queue_empty() and not self.message.get_text() and not self.progress.get_text() |
876 | 876 |
877 | 877 |
878 class MenuBox(urwid.WidgetWrap): | 878 class MenuBox(urwid.WidgetWrap): |
879 """Show menu items of a category in a box""" | 879 """Show menu items of a category in a box""" |
880 signals = ['click'] | 880 signals = ['click'] |
882 def __init__(self,parent,items): | 882 def __init__(self,parent,items): |
883 self.parent = parent | 883 self.parent = parent |
884 self.selected = None | 884 self.selected = None |
885 content = urwid.SimpleListWalker([ClickableText(('menuitem',text)) for text in items]) | 885 content = urwid.SimpleListWalker([ClickableText(('menuitem',text)) for text in items]) |
886 for wid in content: | 886 for wid in content: |
887 urwid.connect_signal(wid, 'click', self.onClick) | 887 urwid.connect_signal(wid, 'click', self.on_click) |
888 | 888 |
889 self.listBox = urwid.ListBox(content) | 889 self.listBox = urwid.ListBox(content) |
890 menubox = urwid.LineBox(urwid.BoxAdapter(self.listBox,len(items))) | 890 menubox = urwid.LineBox(urwid.BoxAdapter(self.listBox,len(items))) |
891 urwid.WidgetWrap.__init__(self,menubox) | 891 urwid.WidgetWrap.__init__(self,menubox) |
892 | 892 |
893 def getValue(self): | 893 def get_value(self): |
894 return self.selected | 894 return self.selected |
895 | 895 |
896 def keypress(self, size, key): | 896 def keypress(self, size, key): |
897 if key==a_key['MENU_BOX_UP']: | 897 if key==a_key['MENU_BOX_UP']: |
898 if self.listBox.get_focus()[1] == 0: | 898 if self.listBox.get_focus()[1] == 0: |
906 if button == 3: | 906 if button == 3: |
907 self.parent.keypress(size,'up') | 907 self.parent.keypress(size,'up') |
908 return True | 908 return True |
909 return super(MenuBox,self).mouse_event(size, event, button, x, y, focus) | 909 return super(MenuBox,self).mouse_event(size, event, button, x, y, focus) |
910 | 910 |
911 def onClick(self, wid): | 911 def on_click(self, wid): |
912 self.selected = wid.getValue() | 912 self.selected = wid.get_value() |
913 self._emit('click') | 913 self._emit('click') |
914 | 914 |
915 | 915 |
916 class Menu(urwid.WidgetWrap): | 916 class Menu(urwid.WidgetWrap): |
917 | 917 |
930 urwid.WidgetWrap.__init__(self, urwid.AttrMap(col_rol,'menubar')) | 930 urwid.WidgetWrap.__init__(self, urwid.AttrMap(col_rol,'menubar')) |
931 | 931 |
932 def selectable(self): | 932 def selectable(self): |
933 return True | 933 return True |
934 | 934 |
935 def getMenuSize(self): | 935 def get_menu_size(self): |
936 """return the current number of categories in this menu""" | 936 """return the current number of categories in this menu""" |
937 return len(self.menu_keys) | 937 return len(self.menu_keys) |
938 | 938 |
939 def setOrigX(self, orig_x): | 939 def set_orig_x(self, orig_x): |
940 self.x_orig = orig_x | 940 self.x_orig = orig_x |
941 | 941 |
942 def __buildOverlay(self, menu_key, columns): | 942 def __build_overlay(self, menu_key, columns): |
943 """Build the overlay menu which show menuitems | 943 """Build the overlay menu which show menuitems |
944 @param menu_key: name of the category | 944 @param menu_key: name of the category |
945 @param columns: column number where the menubox must be displayed""" | 945 @param columns: column number where the menubox must be displayed""" |
946 max_len = 0 | 946 max_len = 0 |
947 for item in self.menu[menu_key]: | 947 for item in self.menu[menu_key]: |
948 if len(item[0]) > max_len: | 948 if len(item[0]) > max_len: |
949 max_len = len(item[0]) | 949 max_len = len(item[0]) |
950 | 950 |
951 self.save_bottom = self.loop.widget | 951 self.save_bottom = self.loop.widget |
952 menu_box = MenuBox(self,[item[0] for item in self.menu[menu_key]]) | 952 menu_box = MenuBox(self,[item[0] for item in self.menu[menu_key]]) |
953 urwid.connect_signal(menu_box, 'click', self.onItemClick) | 953 urwid.connect_signal(menu_box, 'click', self.on_item_click) |
954 | 954 |
955 self.loop.widget = urwid.Overlay(urwid.AttrMap(menu_box,'menubar'),self.save_bottom,('fixed left', columns),max_len+2,('fixed top',1),None) | 955 self.loop.widget = urwid.Overlay(urwid.AttrMap(menu_box,'menubar'),self.save_bottom,('fixed left', columns),max_len+2,('fixed top',1),None) |
956 | 956 |
957 def keypress(self, size, key): | 957 def keypress(self, size, key): |
958 if key == a_key['MENU_DOWN']: | 958 if key == a_key['MENU_DOWN']: |
962 self.loop.widget = self.save_bottom | 962 self.loop.widget = self.save_bottom |
963 self.save_bottom = None | 963 self.save_bottom = None |
964 | 964 |
965 return self._w.base_widget.keypress(size, key) | 965 return self._w.base_widget.keypress(size, key) |
966 | 966 |
967 def checkShortcuts(self, key): | 967 def check_shortcuts(self, key): |
968 for shortcut in list(self.shortcuts.keys()): | 968 for shortcut in list(self.shortcuts.keys()): |
969 if key == shortcut: | 969 if key == shortcut: |
970 category, item, callback = self.shortcuts[shortcut] | 970 category, item, callback = self.shortcuts[shortcut] |
971 callback((category, item)) | 971 callback((category, item)) |
972 return key | 972 return key |
973 | 973 |
974 def addMenu(self, category, item=None, callback=None, shortcut=None): | 974 def add_menu(self, category, item=None, callback=None, shortcut=None): |
975 """Create the category if new and add a menu item (if item is not None). | 975 """Create the category if new and add a menu item (if item is not None). |
976 | 976 |
977 @param category: category of the menu (e.g. File/Edit) | 977 @param category: category of the menu (e.g. File/Edit) |
978 @param item: menu item (e.g. new/close/about) | 978 @param item: menu item (e.g. new/close/about) |
979 @callback: method to call when item is selected""" | 979 @callback: method to call when item is selected""" |
980 if not category in list(self.menu.keys()): | 980 if not category in list(self.menu.keys()): |
981 self.menu_keys.append(category) | 981 self.menu_keys.append(category) |
982 self.menu[category] = [] | 982 self.menu[category] = [] |
983 button = CustomButton(('menubar',category), self.onCategoryClick, | 983 button = CustomButton(('menubar',category), self.on_category_click, |
984 left_border = ('menubar',"[ "), | 984 left_border = ('menubar',"[ "), |
985 right_border = ('menubar'," ]")) | 985 right_border = ('menubar'," ]")) |
986 self._w.base_widget.addWidget(button,button.getSize()) | 986 self._w.base_widget.add_widget(button,button.get_size()) |
987 if not item: | 987 if not item: |
988 return | 988 return |
989 self.menu[category].append((item, callback)) | 989 self.menu[category].append((item, callback)) |
990 if shortcut: | 990 if shortcut: |
991 assert(shortcut not in list(self.shortcuts.keys())) | 991 assert(shortcut not in list(self.shortcuts.keys())) |
992 self.shortcuts[shortcut] = (category, item, callback) | 992 self.shortcuts[shortcut] = (category, item, callback) |
993 | 993 |
994 def onItemClick(self, widget): | 994 def on_item_click(self, widget): |
995 category = self._w.base_widget.getSelected().get_label() | 995 category = self._w.base_widget.get_selected().get_label() |
996 item = widget.getValue() | 996 item = widget.get_value() |
997 callback = None | 997 callback = None |
998 for menu_item in self.menu[category]: | 998 for menu_item in self.menu[category]: |
999 if item == menu_item[0]: | 999 if item == menu_item[0]: |
1000 callback = menu_item[1] | 1000 callback = menu_item[1] |
1001 break | 1001 break |
1002 if callback: | 1002 if callback: |
1003 self.keypress(None, a_key['MENU_UP']) | 1003 self.keypress(None, a_key['MENU_UP']) |
1004 callback((category, item)) | 1004 callback((category, item)) |
1005 | 1005 |
1006 def onCategoryClick(self, button): | 1006 def on_category_click(self, button): |
1007 self.__buildOverlay(button.get_label(), | 1007 self.__build_overlay(button.get_label(), |
1008 self.x_orig + self._w.base_widget.getStartCol(button)) | 1008 self.x_orig + self._w.base_widget.get_start_col(button)) |
1009 | 1009 |
1010 MenuItem = collections.namedtuple('MenuItem', ('name', 'widget')) | 1010 MenuItem = collections.namedtuple('MenuItem', ('name', 'widget')) |
1011 | 1011 |
1012 class MenuRoller(urwid.WidgetWrap): | 1012 class MenuRoller(urwid.WidgetWrap): |
1013 | 1013 |
1029 try: | 1029 try: |
1030 name, menu, id_ = menu_tuple | 1030 name, menu, id_ = menu_tuple |
1031 except ValueError: | 1031 except ValueError: |
1032 name, menu = menu_tuple | 1032 name, menu = menu_tuple |
1033 id_ = None | 1033 id_ = None |
1034 self.addMenu(name, menu, id_) | 1034 self.add_menu(name, menu, id_) |
1035 | 1035 |
1036 def _showSelected(self): | 1036 def _show_selected(self): |
1037 """show menu selected""" | 1037 """show menu selected""" |
1038 if self.selected is None: | 1038 if self.selected is None: |
1039 self.columns.contents[0] = (urwid.Text(''), ('given', 0, False)) | 1039 self.columns.contents[0] = (urwid.Text(''), ('given', 0, False)) |
1040 self.columns.contents[1] = (urwid.Text(''), ('weight', 1, False)) | 1040 self.columns.contents[1] = (urwid.Text(''), ('weight', 1, False)) |
1041 else: | 1041 else: |
1042 menu_item = self.menu_items[self.selected] | 1042 menu_item = self.menu_items[self.selected] |
1043 name_txt = '\u21c9 ' + menu_item.name + ' \u21c7 ' | 1043 name_txt = '\u21c9 ' + menu_item.name + ' \u21c7 ' |
1044 current_name = ClickableText(name_txt) | 1044 current_name = ClickableText(name_txt) |
1045 name_len = len(name_txt) | 1045 name_len = len(name_txt) |
1046 current_menu = menu_item.widget | 1046 current_menu = menu_item.widget |
1047 current_menu.setOrigX(name_len) | 1047 current_menu.set_orig_x(name_len) |
1048 self.columns.contents[0] = (current_name, ('given', name_len, False)) | 1048 self.columns.contents[0] = (current_name, ('given', name_len, False)) |
1049 self.columns.contents[1] = (current_menu, ('weight', 1, False)) | 1049 self.columns.contents[1] = (current_menu, ('weight', 1, False)) |
1050 | 1050 |
1051 def keypress(self, size, key): | 1051 def keypress(self, size, key): |
1052 menu_ids = list(self.menu_items.keys()) | 1052 menu_ids = list(self.menu_items.keys()) |
1057 | 1057 |
1058 if key==a_key['MENU_ROLLER_UP']: | 1058 if key==a_key['MENU_ROLLER_UP']: |
1059 if self.columns.get_focus_column()==0: | 1059 if self.columns.get_focus_column()==0: |
1060 if idx > 0: | 1060 if idx > 0: |
1061 self.selected = menu_ids[idx-1] | 1061 self.selected = menu_ids[idx-1] |
1062 self._showSelected() | 1062 self._show_selected() |
1063 return | 1063 return |
1064 elif key==a_key['MENU_ROLLER_DOWN']: | 1064 elif key==a_key['MENU_ROLLER_DOWN']: |
1065 if self.columns.get_focus_column()==0: | 1065 if self.columns.get_focus_column()==0: |
1066 if idx < len(menu_ids)-1: | 1066 if idx < len(menu_ids)-1: |
1067 self.selected = menu_ids[idx+1] | 1067 self.selected = menu_ids[idx+1] |
1068 self._showSelected() | 1068 self._show_selected() |
1069 return | 1069 return |
1070 elif key==a_key['MENU_ROLLER_RIGHT']: | 1070 elif key==a_key['MENU_ROLLER_RIGHT']: |
1071 if self.columns.get_focus_column()==0 and \ | 1071 if self.columns.get_focus_column()==0 and \ |
1072 (isinstance(self.columns.contents[1][0], urwid.Text) or \ | 1072 (isinstance(self.columns.contents[1][0], urwid.Text) or \ |
1073 self.menu_items[self.selected].widget.getMenuSize()==0): | 1073 self.menu_items[self.selected].widget.get_menu_size()==0): |
1074 return #if we have no menu or the menu is empty, we don't go the right column | 1074 return #if we have no menu or the menu is empty, we don't go the right column |
1075 | 1075 |
1076 return super(MenuRoller, self).keypress(size, key) | 1076 return super(MenuRoller, self).keypress(size, key) |
1077 | 1077 |
1078 def addMenu(self, name, widget, menu_id=None): | 1078 def add_menu(self, name, widget, menu_id=None): |
1079 """Add a menu | 1079 """Add a menu |
1080 | 1080 |
1081 @param name: name of the menu to add, it name already exists, menu is not added | 1081 @param name: name of the menu to add, it name already exists, menu is not added |
1082 @param widget: instance of Menu | 1082 @param widget: instance of Menu |
1083 @param menu_id: id to use of this menu, or None to generate | 1083 @param menu_id: id to use of this menu, or None to generate |
1092 self.menu_items[id_] = MenuItem(name, widget) | 1092 self.menu_items[id_] = MenuItem(name, widget) |
1093 else: | 1093 else: |
1094 id_ = names[name] | 1094 id_ = names[name] |
1095 menu_item = self.menu_items[id_] | 1095 menu_item = self.menu_items[id_] |
1096 if menu_item.widget is not widget: | 1096 if menu_item.widget is not widget: |
1097 raise ValueError("The menu with id [{}] exists and doesn't contain the given instance. Use replaceMenu if you want to change the menu.".format(id_)) | 1097 raise ValueError("The menu with id [{}] exists and doesn't contain the given instance. Use replace_menu if you want to change the menu.".format(id_)) |
1098 if self.selected is None: | 1098 if self.selected is None: |
1099 self.selected = id_ | 1099 self.selected = id_ |
1100 self._showSelected() | 1100 self._show_selected() |
1101 return id_ | 1101 return id_ |
1102 | 1102 |
1103 def replaceMenu(self, name, widget, menu_id): | 1103 def replace_menu(self, name, widget, menu_id): |
1104 """Add a menu or replace it if the id already exists | 1104 """Add a menu or replace it if the id already exists |
1105 | 1105 |
1106 @param name: name of the menu to add, it name already exists, menu is not added | 1106 @param name: name of the menu to add, it name already exists, menu is not added |
1107 @param widget: instance of Menu | 1107 @param widget: instance of Menu |
1108 @param menu_id: id or the menu | 1108 @param menu_id: id or the menu |
1109 """ | 1109 """ |
1110 assert menu_id is not None | 1110 assert menu_id is not None |
1111 if menu_id in self.menu_items: | 1111 if menu_id in self.menu_items: |
1112 del self.menu_items[menu_id] | 1112 del self.menu_items[menu_id] |
1113 self.addMenu(name, widget, menu_id) | 1113 self.add_menu(name, widget, menu_id) |
1114 if self.selected == menu_id: | 1114 if self.selected == menu_id: |
1115 self._showSelected() #if we are on the menu, we update it | 1115 self._show_selected() #if we are on the menu, we update it |
1116 | 1116 |
1117 def removeMenu(self, menu_id): | 1117 def remove_menu(self, menu_id): |
1118 del self.menu_items[menu_id] | 1118 del self.menu_items[menu_id] |
1119 if self.selected == menu_id: | 1119 if self.selected == menu_id: |
1120 try: | 1120 try: |
1121 self.selected = next(iter(self.menu_items.keys())) | 1121 self.selected = next(iter(self.menu_items.keys())) |
1122 except StopIteration: | 1122 except StopIteration: |
1123 self.selected = None | 1123 self.selected = None |
1124 self._showSelected() | 1124 self._show_selected() |
1125 | 1125 |
1126 def checkShortcuts(self, key): | 1126 def check_shortcuts(self, key): |
1127 for menu_item in list(self.menu_items.values()): | 1127 for menu_item in list(self.menu_items.values()): |
1128 key = menu_item.widget.checkShortcuts(key) | 1128 key = menu_item.widget.check_shortcuts(key) |
1129 return key | 1129 return key |
1130 | 1130 |
1131 | 1131 |
1132 ## DIALOGS ## | 1132 ## DIALOGS ## |
1133 | 1133 |
1154 frame_body = UnselectableListBox(body_content) | 1154 frame_body = UnselectableListBox(body_content) |
1155 frame = FocusFrame(frame_body, frame_header, buttons_flow if self.buttons else None, 'footer' if self.buttons else 'body') | 1155 frame = FocusFrame(frame_body, frame_header, buttons_flow if self.buttons else None, 'footer' if self.buttons else 'body') |
1156 decorated_frame = urwid.LineBox(frame) | 1156 decorated_frame = urwid.LineBox(frame) |
1157 urwid.WidgetWrap.__init__(self, decorated_frame) | 1157 urwid.WidgetWrap.__init__(self, decorated_frame) |
1158 | 1158 |
1159 def setCallback(self, name, callback, data=None): | 1159 def set_callback(self, name, callback, data=None): |
1160 """Set the callback associated with a button press | 1160 """Set the callback associated with a button press |
1161 | 1161 |
1162 @param name: one of "ok", "cancel", "yes", "no" | 1162 @param name: one of "ok", "cancel", "yes", "no" |
1163 @aram callback(callable): method to call on requested action | 1163 @aram callback(callable): method to call on requested action |
1164 @param data: argument to send to the callback (first one will be the button widget) | 1164 @param data: argument to send to the callback (first one will be the button widget) |
1214 self.widget_list = widget_list or [] | 1214 self.widget_list = widget_list or [] |
1215 self.focus_column = focus_column | 1215 self.focus_column = focus_column |
1216 self.__start = 0 | 1216 self.__start = 0 |
1217 self.__next = False | 1217 self.__next = False |
1218 | 1218 |
1219 def addWidget(self, widget, width): | 1219 def add_widget(self, widget, width): |
1220 self.widget_list.append((width,widget)) | 1220 self.widget_list.append((width,widget)) |
1221 if len(self.widget_list) == 1: | 1221 if len(self.widget_list) == 1: |
1222 self.focus_position = 0 | 1222 self.focus_position = 0 |
1223 | 1223 |
1224 def getStartCol(self, widget): | 1224 def get_start_col(self, widget): |
1225 """Return the column of the left corner of the widget""" | 1225 """Return the column of the left corner of the widget""" |
1226 start_col = 0 | 1226 start_col = 0 |
1227 for wid in self.widget_list[self.__start:]: | 1227 for wid in self.widget_list[self.__start:]: |
1228 if wid[1] == widget: | 1228 if wid[1] == widget: |
1229 return start_col | 1229 return start_col |
1249 return | 1249 return |
1250 if self.focus_column<len(self.widget_list): | 1250 if self.focus_column<len(self.widget_list): |
1251 return self.widget_list[self.focus_column][1].keypress(size,key) | 1251 return self.widget_list[self.focus_column][1].keypress(size,key) |
1252 return key | 1252 return key |
1253 | 1253 |
1254 def getSelected(self): | 1254 def get_selected(self): |
1255 """Return selected widget""" | 1255 """Return selected widget""" |
1256 return self.widget_list[self.focus_column][1] | 1256 return self.widget_list[self.focus_column][1] |
1257 | 1257 |
1258 @property | 1258 @property |
1259 def focus_position(self): | 1259 def focus_position(self): |
1288 _next = True | 1288 _next = True |
1289 total_wid-=self.widget_list[end_wid][0] | 1289 total_wid-=self.widget_list[end_wid][0] |
1290 end_wid-=1 | 1290 end_wid-=1 |
1291 | 1291 |
1292 cols_left = maxcol - total_wid | 1292 cols_left = maxcol - total_wid |
1293 self.__start = start_wid #we need to keep it for getStartCol | 1293 self.__start = start_wid #we need to keep it for get_start_col |
1294 return _prev,_next,start_wid,end_wid,cols_left | 1294 return _prev,_next,start_wid,end_wid,cols_left |
1295 | 1295 |
1296 | 1296 |
1297 def mouse_event(self, size, event, button, x, y, focus): | 1297 def mouse_event(self, size, event, button, x, y, focus): |
1298 (maxcol,)=size | 1298 (maxcol,)=size |
1354 ret = super(FocusPile, self).keypress(size, key) | 1354 ret = super(FocusPile, self).keypress(size, key) |
1355 if not ret: | 1355 if not ret: |
1356 return | 1356 return |
1357 | 1357 |
1358 if key in FOCUS_KEYS: | 1358 if key in FOCUS_KEYS: |
1359 direction, rotate = getFocusDirection(key, inversed = self._focus_inversed) | 1359 direction, rotate = get_focus_direction(key, inversed = self._focus_inversed) |
1360 max_pos = len(self.contents) - 1 | 1360 max_pos = len(self.contents) - 1 |
1361 new_pos = self.focus_position + direction | 1361 new_pos = self.focus_position + direction |
1362 if rotate: | 1362 if rotate: |
1363 if new_pos > max_pos: | 1363 if new_pos > max_pos: |
1364 new_pos = 0 | 1364 new_pos = 0 |
1380 ret = super(FocusFrame, self).keypress(size, key) | 1380 ret = super(FocusFrame, self).keypress(size, key) |
1381 if not ret: | 1381 if not ret: |
1382 return | 1382 return |
1383 | 1383 |
1384 if key in FOCUS_KEYS: | 1384 if key in FOCUS_KEYS: |
1385 direction, rotate = getFocusDirection(key) | 1385 direction, rotate = get_focus_direction(key) |
1386 | 1386 |
1387 positions = [pos for pos in self.ordered_positions if pos in self] | 1387 positions = [pos for pos in self.ordered_positions if pos in self] |
1388 selectables = [pos for pos in positions if self.contents[pos][0].selectable()] # keep positions which exists and have a selectable widget | 1388 selectables = [pos for pos in positions if self.contents[pos][0].selectable()] # keep positions which exists and have a selectable widget |
1389 if not selectables: | 1389 if not selectables: |
1390 # no widget is selectable, we just return | 1390 # no widget is selectable, we just return |
1439 urwid.WidgetWrap.__init__(self, self._frame) | 1439 urwid.WidgetWrap.__init__(self, self._frame) |
1440 | 1440 |
1441 def keypress(self, size, key): | 1441 def keypress(self, size, key): |
1442 return self._w.keypress(size,key) | 1442 return self._w.keypress(size,key) |
1443 | 1443 |
1444 def _buttonClicked(self, button, invisible=False): | 1444 def _button_clicked(self, button, invisible=False): |
1445 """Called when a button on the tab is changed, | 1445 """Called when a button on the tab is changed, |
1446 change the page | 1446 change the page |
1447 @param button: button clicked | 1447 @param button: button clicked |
1448 @param invisible: emit signal only if False""" | 1448 @param invisible: emit signal only if False""" |
1449 tab_name = button.get_label() | 1449 tab_name = button.get_label() |
1459 self._current_tab.set_label(self._current_tab.get_label()) | 1459 self._current_tab.set_label(self._current_tab.get_label()) |
1460 self._current_tab = button | 1460 self._current_tab = button |
1461 if not invisible: | 1461 if not invisible: |
1462 self._emit('click') | 1462 self._emit('click') |
1463 | 1463 |
1464 def _appendButton(self, name, selected=False): | 1464 def _append_button(self, name, selected=False): |
1465 """Append a button to the frame header, and link it to the page change method. | 1465 """Append a button to the frame header, and link it to the page change method. |
1466 | 1466 |
1467 @param name (unicode): button name | 1467 @param name (unicode): button name |
1468 @param selected (bool): set to True to select this tab | 1468 @param selected (bool): set to True to select this tab |
1469 """ | 1469 """ |
1470 button = CustomButton(name, self._buttonClicked, left_border = '', right_border=' | ') | 1470 button = CustomButton(name, self._button_clicked, left_border = '', right_border=' | ') |
1471 self._buttons_cont.addWidget(button, button.getSize()) | 1471 self._buttons_cont.add_widget(button, button.get_size()) |
1472 count = len(self._buttons_cont.widget_list) | 1472 count = len(self._buttons_cont.widget_list) |
1473 if selected or count == 1: | 1473 if selected or count == 1: |
1474 # first/selected button: we set the focus and the body | 1474 # first/selected button: we set the focus and the body |
1475 self.selectTab(count - 1) | 1475 self.select_tab(count - 1) |
1476 | 1476 |
1477 def addTab(self, name, content=None, selected=False): | 1477 def add_tab(self, name, content=None, selected=False): |
1478 """Add a page to the container | 1478 """Add a page to the container |
1479 | 1479 |
1480 @param name: name of the page (what appear on the tab) | 1480 @param name: name of the page (what appear on the tab) |
1481 @param content: content of the page: | 1481 @param content: content of the page: |
1482 - if None create and empty Listbox | 1482 - if None create and empty Listbox |
1488 tab = urwid.ListBox(urwid.SimpleListWalker(content or [])) | 1488 tab = urwid.ListBox(urwid.SimpleListWalker(content or [])) |
1489 else: | 1489 else: |
1490 tab = content | 1490 tab = content |
1491 | 1491 |
1492 self.tabs.append([name, tab]) | 1492 self.tabs.append([name, tab]) |
1493 self._appendButton(name, selected) | 1493 self._append_button(name, selected) |
1494 return tab | 1494 return tab |
1495 | 1495 |
1496 def addFooter(self, widget): | 1496 def add_footer(self, widget): |
1497 """Add a widget on the bottom of the tab (will be displayed on all pages) | 1497 """Add a widget on the bottom of the tab (will be displayed on all pages) |
1498 @param widget: FlowWidget""" | 1498 @param widget: FlowWidget""" |
1499 self._w.footer = widget | 1499 self._w.footer = widget |
1500 | 1500 |
1501 def selectTab(self, index): | 1501 def select_tab(self, index): |
1502 """Select a tab. | 1502 """Select a tab. |
1503 | 1503 |
1504 @param index (int): index of the tab to select | 1504 @param index (int): index of the tab to select |
1505 """ | 1505 """ |
1506 self._buttons_cont.focus_position = index | 1506 self._buttons_cont.focus_position = index |
1507 self._buttonClicked(self._buttons_cont.widget_list[index][1], True) | 1507 self._button_clicked(self._buttons_cont.widget_list[index][1], True) |
1508 | 1508 |
1509 | 1509 |
1510 class HighlightColumns(urwid.AttrMap): | 1510 class HighlightColumns(urwid.AttrMap): |
1511 """ Decorated columns which highlight all or some columns """ | 1511 """ Decorated columns which highlight all or some columns """ |
1512 | 1512 |
1541 | 1541 |
1542 @focus_position.setter | 1542 @focus_position.setter |
1543 def focus_position(self, value): | 1543 def focus_position(self, value): |
1544 self.base_widget.focus_position = value | 1544 self.base_widget.focus_position = value |
1545 | 1545 |
1546 def addWidget(self, wid, options): | 1546 def add_widget(self, wid, options): |
1547 """ Add a widget to the columns | 1547 """ Add a widget to the columns |
1548 Widget is wrapped with AttrMap, that's why Columns.contents should not be used directly for appending new widgets | 1548 Widget is wrapped with AttrMap, that's why Columns.contents should not be used directly for appending new widgets |
1549 @param wid: widget to add | 1549 @param wid: widget to add |
1550 @param options: result of Columns.options(...) | 1550 @param options: result of Columns.options(...) |
1551 | 1551 |
1605 self._dividechars = dividechars | 1605 self._dividechars = dividechars |
1606 self._idx = 0 | 1606 self._idx = 0 |
1607 self._longuest = self._columns * [0] | 1607 self._longuest = self._columns * [0] |
1608 self._next_row_idx = None | 1608 self._next_row_idx = None |
1609 for item in items: | 1609 for item in items: |
1610 self.addWidget(item) | 1610 self.add_widget(item) |
1611 | 1611 |
1612 def _getIdealSize(self, widget): | 1612 def _get_ideal_size(self, widget): |
1613 """ return preferred size for widget, or 0 if we can't find it """ | 1613 """ return preferred size for widget, or 0 if we can't find it """ |
1614 try: | 1614 try: |
1615 return len(widget.text) | 1615 return len(widget.text) |
1616 except AttributeError: | 1616 except AttributeError: |
1617 return 0 | 1617 return 0 |
1621 self._emit('click') | 1621 self._emit('click') |
1622 else: | 1622 else: |
1623 return super(TableContainer, self).keypress(size, key) | 1623 return super(TableContainer, self).keypress(size, key) |
1624 | 1624 |
1625 | 1625 |
1626 def addWidget(self, widget): | 1626 def add_widget(self, widget): |
1627 # TODO: use a contents property ? | 1627 # TODO: use a contents property ? |
1628 pile = self._w | 1628 pile = self._w |
1629 col_idx = self._idx % self._columns | 1629 col_idx = self._idx % self._columns |
1630 | 1630 |
1631 options = None | 1631 options = None |
1638 else: | 1638 else: |
1639 columns = pile.contents[-1][0] | 1639 columns = pile.contents[-1][0] |
1640 | 1640 |
1641 if 'ADAPT' in self._options and (col_idx in self._options['ADAPT'] | 1641 if 'ADAPT' in self._options and (col_idx in self._options['ADAPT'] |
1642 or self._options['ADAPT'] == ()): | 1642 or self._options['ADAPT'] == ()): |
1643 current_len = self._getIdealSize(widget) | 1643 current_len = self._get_ideal_size(widget) |
1644 longuest = self._longuest[col_idx] | 1644 longuest = self._longuest[col_idx] |
1645 max_len = max(longuest, current_len) | 1645 max_len = max(longuest, current_len) |
1646 if max_len > longuest: | 1646 if max_len > longuest: |
1647 self._longuest[col_idx] = max_len | 1647 self._longuest[col_idx] = max_len |
1648 for wid,_ in pile.contents[:-1]: | 1648 for wid,_ in pile.contents[:-1]: |
1649 col = wid.base_widget | 1649 col = wid.base_widget |
1650 col.contents[col_idx] = (col.contents[col_idx][0], col.options('given', max_len)) | 1650 col.contents[col_idx] = (col.contents[col_idx][0], col.options('given', max_len)) |
1651 options = columns.options('given', max_len) if max_len else columns.options() | 1651 options = columns.options('given', max_len) if max_len else columns.options() |
1652 | 1652 |
1653 columns.addWidget(widget, options or columns.options()) | 1653 columns.add_widget(widget, options or columns.options()) |
1654 | 1654 |
1655 if self._row_selectable and col_idx == self._columns - 1: | 1655 if self._row_selectable and col_idx == self._columns - 1: |
1656 columns.addWidget(urwid.SelectableIcon(''), columns.options('given', 0)) | 1656 columns.add_widget(urwid.SelectableIcon(''), columns.options('given', 0)) |
1657 | 1657 |
1658 if not columns.selectable() and columns.contents[-1][0].base_widget.selectable(): | 1658 if not columns.selectable() and columns.contents[-1][0].base_widget.selectable(): |
1659 columns.focus_position = len(columns.contents)-1 | 1659 columns.focus_position = len(columns.contents)-1 |
1660 if not self.selectable() and columns.selectable(): | 1660 if not self.selectable() and columns.selectable(): |
1661 pile.focus_position = len(pile.contents) - 1 | 1661 pile.focus_position = len(pile.contents) - 1 |
1662 self._idx += 1 | 1662 self._idx += 1 |
1663 | 1663 |
1664 def setRowIndex(self, idx): | 1664 def set_row_index(self, idx): |
1665 self._next_row_idx = idx | 1665 self._next_row_idx = idx |
1666 | 1666 |
1667 def getSelectedWidgets(self): | 1667 def get_selected_widgets(self): |
1668 columns = self._w.focus | 1668 columns = self._w.focus |
1669 return (wid for wid, _ in columns.contents) | 1669 return (wid for wid, _ in columns.contents) |
1670 | 1670 |
1671 def getSelectedIndex(self): | 1671 def get_selected_index(self): |
1672 columns = self._w.focus | 1672 columns = self._w.focus |
1673 return columns.row_idx | 1673 return columns.row_idx |
1674 | 1674 |
1675 ## DECORATORS ## | 1675 ## DECORATORS ## |
1676 class LabelLine(urwid.LineBox): | 1676 class LabelLine(urwid.LineBox): |