# HG changeset patch # User Goffi # Date 1278328416 -28800 # Node ID 592cd64933dd00594b2a567491b375e7ba737426 # Parent c94cdbfdf3e8df6ebebb3b7bd2d3437036dfd8ab Primitivus: chat window / text sending. Primitivus has now the most basics features \o/ - core: new getVersion method - primitivus: new debug key (C-d), only work if SàT is in dev version (D in version) - quick_app: new post_init method, used for automatique task like auto-plug - primitivus: lists now use genericList (Box) or List (Flow) - primitivus: List now manage correctly its size - primitivus: new FocusFrame widget which manage focus changing with 'tab' - primitivus: advancedEdit now manage 'click' signal - primitivus: contactList now manager 'change' and 'click' signals - primitivus: Chat window now working diff -r c94cdbfdf3e8 -r 592cd64933dd frontends/primitivus/custom_widgets.py --- a/frontends/primitivus/custom_widgets.py Sat Jul 03 13:56:44 2010 +0800 +++ b/frontends/primitivus/custom_widgets.py Mon Jul 05 19:13:36 2010 +0800 @@ -38,6 +38,7 @@ class AdvancedEdit(urwid.Edit): """Edit box with some custom improvments""" + signals = urwid.Edit.signals + ['click'] def keypress(self, size, key): #TODO: insert mode is not managed yet @@ -53,6 +54,8 @@ pos = before.rstrip().rfind(" ")+1 self.set_edit_text(before[:pos] + self.edit_text[self.edit_pos:]) self.set_edit_pos(pos) + elif key == 'enter': + self._emit('click') return super(AdvancedEdit, self).keypress(size, key) @@ -73,9 +76,9 @@ @param invisible: don't emit change signal if True""" assert(type(selected)==bool) self.__selected=selected + self._invalidate() if not invisible: self._emit("change", self.__selected) - self._invalidate() def getState(self): return self.__selected @@ -101,15 +104,32 @@ attr+="_focus" return urwid.Text((attr,self.text), align=self.align) -class List(urwid.WidgetWrap): - signals = ['change'] +class GenericList(urwid.WidgetWrap): + signals = ['click','change'] - def __init__(self, options, style=[], align='left', on_state_change=None, user_data=None): + def __init__(self, options, style=[], align='left', on_click=None, on_change=None, user_data=None): + """ + Widget managing list of string and their selection + @param options: list of strings used for options + @param style: list of string: + - 'single' if only one must be selected + - 'no_first_select' nothing selected when list is first displayed + - 'can_select_none' if we can select nothing + @param align: alignement of text inside the list + @param on_click: method called when click signal is emited + @param user_data: data sent to the callback for click signal + """ self.single = 'single' in style + self.no_first_select = 'no_first_select' in style + self.can_select_none = 'can_select_none' in style self.align = align + self.first_display = True - if on_state_change: - urwid.connect_signal(self, 'change', on_state_change, user_data) + if on_click: + urwid.connect_signal(self, 'click', on_click, user_data) + + if on_change: + urwid.connect_signal(self, 'change', on_change, user_data) self.content = urwid.SimpleListWalker([]) self.list_box = urwid.ListBox(self.content) @@ -118,14 +138,14 @@ def __onStateChange(self, widget, selected): if self.single: - if not selected: + if not selected and not self.can_select_none: #if in single mode, it's forbidden to unselect a value widget.setState(True, invisible=True) return - else: + if selected: self.unselectAll(invisible=True) widget.setState(True, invisible=True) - self._emit("change") + self._emit("click") def unselectAll(self, invisible=False): @@ -136,45 +156,109 @@ def deleteValue(self, value): """Delete the first value equal to the param given""" - try: - self.content.remove(value) - except ValueError: - raise ValuError("%s ==> %s" % (str(value),str(self.content))) + for widget in self.content: + if widget.getValue() == value: + self.content.remove(widget) + self._emit('change') + return + raise ValueError("%s ==> %s" % (str(value),str(self.content))) - def getValue(self): + def getSelectedValue(self): """Convenience method to get the value selected as a string in single mode, or None""" - values = self.getValues() + values = self.getSelectedValues() return values[0] if values else None - def getValues(self): + def getAllValues(self): + """Return values of all items""" + return [widget.getValue() for widget in self.content] + + def getSelectedValues(self): + """Return values of selected items""" result = [] for widget in self.content: if widget.getState(): result.append(widget.getValue()) return result + def getDisplayWidget(self): + return self.list_box + def changeValues(self, new_values): """Change all value in one shot""" - widgets = [SelectableText(option, self.align) for option in new_values] - for widget in widgets: + if not self.first_display: + old_selected = self.getSelectedValues() + widgets = [] + for option in new_values: + widget = SelectableText(option, self.align) + if not self.first_display and option in old_selected: + widget.setState(True) + widgets.append(widget) urwid.connect_signal(widget, 'change', self.__onStateChange) self.content[:] = widgets - if self.single and new_values: + if self.first_display and self.single and new_values and not self.no_first_select: self.content[0].setState(True) - display_widget = urwid.BoxAdapter(self.list_box, min(len(new_values),5) or 1) + display_widget = self.getDisplayWidget() self._set_w(display_widget) - + self._emit('change') + self.first_display = False + def selectValue(self, value): self.unselectAll() idx = 0 for widget in self.content: - if widget.getValue() == value: + if widget.getSelectedValue() == value: widget.setState(True) self.list_box.set_focus(idx) return idx+=1 -class genericDialog(urwid.WidgetWrap): +class List(urwid.FlowWidget): + """FlowWidget list, same arguments as GenericList, with an additional one 'max_height'""" + signals = ['click','change'] + + def __init__(self, options, style=[], max_height=5, align='left', on_click=None, on_change=None, user_data=None): + self.genericList = GenericList(options, style, align, on_click, on_change, user_data) + self.max_height = max_height + + def selectable(self): + return True + + def keypress(self, size, key): + return self.displayWidget(size,True).keypress(size, key) + + def unselectAll(self, invisible=False): + return self.genericList.unselectAll(invisible) + + def deleteValue(self, value): + return self.genericList.deleteValue(value) + + def getSelectedValue(self): + return self.genericList.getSelectedValue() + + def getAllValues(self): + return self.genericList.getAllValues() + + def getSelectedValues(self): + return self.genericList.getSelectedValues() + + def changeValues(self, new_values): + return self.genericList.changeValues(new_values) + + def selectValue(self, value): + return self.genericList.selectValue(value) + + def render(self, size, focus=False): + return self.displayWidget(size, focus).render(size, focus) + + def rows(self, size, focus=False): + return self.displayWidget(size, focus).rows(size, focus) + + def displayWidget(self, size, focus): + list_size = sum([wid.rows(size, focus) for wid in self.genericList.content]) + height = min(list_size,self.max_height) + return urwid.BoxAdapter(self.genericList, height) + +class GenericDialog(urwid.WidgetWrap): def __init__(self, widgets_lst, title, style=[], **kwargs): frame_header = urwid.AttrMap(urwid.Text(title,'center'),'title') @@ -200,19 +284,35 @@ -class InputDialog(genericDialog): +class InputDialog(GenericDialog): def __init__(self, title, instrucions, style=['OK/CANCEL'], **kwargs): instr_wid = urwid.Text(instrucions+':') edit_box = urwid.Edit() - genericDialog.__init__(self, [instr_wid,edit_box], title, style, ok_value=edit_box, **kwargs) + GenericDialog.__init__(self, [instr_wid,edit_box], title, style, ok_value=edit_box, **kwargs) -class ConfirmDialog(genericDialog): +class ConfirmDialog(GenericDialog): def __init__(self, title, style=['YES/NO'], **kwargs): - genericDialog.__init__(self, [], title, style, yes_value=None, **kwargs) + GenericDialog.__init__(self, [], title, style, yes_value=None, **kwargs) -class Alert(genericDialog): +class Alert(GenericDialog): def __init__(self, title, message, style=['OK'], **kwargs): - genericDialog.__init__(self, [urwid.Text(message, 'center')], title, style, ok_value=None, **kwargs) + GenericDialog.__init__(self, [urwid.Text(message, 'center')], title, style, ok_value=None, **kwargs) + +class FocusFrame(urwid.Frame): + """Frame which manage "tab" key""" + + def keypress(self, size, key): + if key == 'tab': + focus_list = ('header','body','footer') + focus_idx = focus_list.index(self.focus_part) + for i in range(2): + focus_idx = (focus_idx + 1) % len(focus_list) + focus_name = focus_list[focus_idx] + widget = getattr(self,'_'+focus_name) + if widget!=None and widget.selectable(): + self.set_focus(focus_name) + + return urwid.Frame.keypress(self, size, key)