diff frontends/primitivus/custom_widgets.py @ 119:ded2431cea5a

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
author Goffi <goffi@goffi.org>
date Mon, 05 Jul 2010 19:13:36 +0800
parents 76055a209ed9
children 1ca5f254ce41
line wrap: on
line diff
--- 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)