diff frontends/primitivus/custom_widgets.py @ 18:bdc83e857093

Primitivus: new widget ColumnsRoller which show FlowWidgets on the same row, and can roll between them if there is not enough space
author Goffi <goffi@goffi.org>
date Mon, 09 Aug 2010 19:09:13 +0800
parents 222aa33716ad
children 0b83dd2b15d1
line wrap: on
line diff
--- a/frontends/primitivus/custom_widgets.py	Fri Aug 06 12:18:50 2010 +0800
+++ b/frontends/primitivus/custom_widgets.py	Mon Aug 09 19:09:13 2010 +0800
@@ -692,6 +692,126 @@
 
 ## CONTAINERS ##
 
+class ColumnsRoller(urwid.FlowWidget):
+    
+    def __init__(self, widget_list = None, focus_column=0):
+        self.widget_list = widget_list or []
+        self.focus_column = focus_column
+        self.__start = 0
+        self.__next = False
+
+    def addWidget(self, widget, width):
+        self.widget_list.append((width,widget))
+        if len(self.widget_list) == 1:
+            self.set_focus(0)
+
+    def selectable(self):
+        try:
+            return self.widget_list[self.focus_column][1].selectable()
+        except IndexError:
+            return False
+    
+    def keypress(self, size, key):
+        if key=='left':
+            if self.focus_column>0:
+                self.focus_column-=1
+                self._invalidate()
+                return
+        if key=='right':
+            if self.focus_column<len(self.widget_list)-1:
+                self.focus_column+=1
+                self._invalidate()
+                return
+        if self.focus_column<len(self.widget_list):
+            return self.widget_list[self.focus_column][1].keypress(size,key)
+        return key
+
+    def set_focus(self, idx):
+        if idx>len(self.widget_list)-1:
+            idx = len(self.widget_list)-1
+        self.focus_column = idx
+
+    def rows(self,size,focus=False):
+        return 1
+
+    def __calculate_limits(self, size):
+        (maxcol,) = size
+        _prev = _next = False
+        start_wid = 0
+        end_wid = len(self.widget_list)-1
+        
+        total_wid = sum([w[0] for w in self.widget_list])
+        while total_wid > maxcol:
+            if self.focus_column == end_wid:
+                if not _prev:
+                    total_wid+=1
+                    _prev = True
+                total_wid-=self.widget_list[start_wid][0]
+                start_wid+=1
+            else:
+                if not _next:
+                    total_wid+=1
+                    _next = True
+                total_wid-=self.widget_list[end_wid][0]
+                end_wid-=1
+        
+        cols_left = maxcol - total_wid
+
+        return _prev,_next,start_wid,end_wid,cols_left
+        
+
+    def mouse_event(self, size, event, button, x, y, focus):
+        (maxcol,)=size
+
+        if urwid.is_mouse_press(event) and button == 1:
+            _prev,_next,start_wid,end_wid,cols_left = self.__calculate_limits(size)
+            if x==0 and _prev:
+                self.keypress(size,'left')
+                return True
+            if x==maxcol-1 and _next:
+                self.keypress(size,'right')
+                return True
+            
+            current_pos = 1 if _prev else 0
+            idx = 0
+            while current_pos<x and idx<len(self.widget_list):
+                width,widget = self.widget_list[idx]
+                if x<=current_pos+width:
+                    self.focus_column = idx
+                    self._invalidate()
+                    if not hasattr(widget,'mouse_event'):
+                        return False
+                    return widget.mouse_event((width,0), event, button, 
+                        x-current_pos, 0, focus)
+
+                current_pos+=self.widget_list[idx][0]
+                idx+=1
+        
+        return False
+    
+    def render(self, size, focus=False):
+        if not self.widget_list:
+            return SolidCanvas(" ", size[0], 1)
+
+        _prev,_next,start_wid,end_wid,cols_left = self.__calculate_limits(size)
+        
+        idx=start_wid
+        render = []
+
+        for width,widget in self.widget_list[start_wid:end_wid+1]:
+            _focus = idx == self.focus_column and focus
+            render.append((widget.render((width,),_focus),False,_focus,width))
+            idx+=1
+        if _prev:
+            render.insert(0,(urwid.Text([u"◀"]).render((1,),False),False,False,1))
+        if _next:
+            render.append((urwid.Text([u"▶"],align='right').render((1+cols_left,),False),False,False,1+cols_left))
+        else:
+            render.append((urwid.SolidCanvas(" "*cols_left, size[0], 1),False,False,cols_left))
+
+        return urwid.CanvasJoin(render)
+
+
 class FocusFrame(urwid.Frame):
     """Frame which manage 'tab' key"""
 
@@ -713,9 +833,9 @@
 
     def __init__(self):
         #self._current_tab = 0
-        self._buttons_cont = urwid.GridFlow([],19,1,0,'left')
+        self._buttons_cont = ColumnsRoller()
         self.tabs = []
-        self.__frame = urwid.Frame(urwid.Text(''),urwid.Pile([self._buttons_cont,urwid.Divider(u"─")]))
+        self.__frame = urwid.Frame(urwid.Filler(urwid.Text('')),urwid.Pile([self._buttons_cont,urwid.Divider(u"─")]))
         urwid.WidgetWrap.__init__(self, self.__frame)
 
     """def selectable(self):
@@ -743,9 +863,9 @@
     def __appendButton(self, name):
         """Append a button to the frame header,
         and link it to the page change method"""
-        button = CustomButton(name, self.__buttonClicked, left_border = '', right_border=' |')
-        self._buttons_cont.cells.append(button)
-        if len(self._buttons_cont.cells):
+        button = CustomButton(name, self.__buttonClicked, left_border = '', right_border=' | ')
+        self._buttons_cont.addWidget(button, button.getSize())
+        if len(self._buttons_cont.widget_list) == 1:
             #first button: we set the focus and the body
             self._buttons_cont.set_focus(0)
             self.__buttonClicked(button,True)