Fix ListView to make sense.
[matthijs/upstream/mobilegtd.git] / src / gui / gui.py
index 30ae4e2745bd6290ac47487bfdffca6d57c748f9..20f4d05a34ac3f8aa8294a3525f4e32700909aeb 100644 (file)
@@ -137,58 +137,79 @@ class View(object):
     def exit(self):
         self.exit_flag = True
         self.lock.signal()
     def exit(self):
         self.exit_flag = True
         self.lock.signal()
-        super(View, self).exit()
+
+    def update(self,subject=None):
+        """
+        Update the current view (e.g., make sure refresh is called). We
+        can't call it directly, since we're in another thread.
+        """
+        if self.lock:
+            self.lock.signal()
 
     def refresh(self):
         """
 
     def refresh(self):
         """
-        Update the gui after a change in model or some user interaction.
-        Should be filled by subclasses.
+        Called when the current view must be updated. Never call
+        directly. Subclasses should extend this method, not update.
+        """
+        appuifw.app.menu=self.get_menu_entries()
+
+    def get_menu_entries(self):
+        """ Returns a list of menu entries to display. Will be
+        automatically updated on each refresh.
+
+        Each menu entry is a tuple of a title for the entry and a
+        function to call when the entry is selected.
         """
         """
-        super(View, self).refresh()
+        return []
 
 class ListView(View):
     def __init__(self):
         super(ListView, self).__init__()
 
 class ListView(View):
     def __init__(self):
         super(ListView, self).__init__()
-        self.set_view(appuifw.Listbox(self.items(),self.change_entry))
+        self.set_view(appuifw.Listbox(self.items(),self.entry_selected))
+        self.view.bind(EKeyUpArrow,lambda: self.arrow_key_pressed(-1))
+        self.view.bind(EKeyDownArrow,lambda: self.arrow_key_pressed(1))
+
+    def arrow_key_pressed(self, dir):
+        """
+        This function is called when an arrow key is pressed. Since we
+        don't get any "current list index has changed" events, we'll
+        have to create these ourselves this way.
+
+        Since the current index is only updated after the key event,
+        we'll have to adjust the index with the direction of the
+        keypress (-1 for up, +1 for down).
+        """
+        new_index = (self.selected_index() + dir) % len(self.items())
+        self.index_changed(new_index)
 
 
-    def change_entry(self):
+    def entry_selected(self):
         """
         This function is called when the user selects an an entry (e.g.,
         navigates to it and push the ok button).
         """
         """
         This function is called when the user selects an an entry (e.g.,
         navigates to it and push the ok button).
         """
-        super(ListView).change_entry()
-    
-    def update(self,subject=None):
-        #logger.log(u'Updated %s'%repr(self))
-        if self.lock:
-            self.lock.signal()
-        #pass
+        pass
 
 
-    def index_changed(self,adjustment=None):
-        if adjustment:
-            index = self.selected_index() + adjustment
-        else:
-            index = self.selected_index()
-        if index < 0:
-            index = len(self.widgets) - 1
-        if index >= len(self.widgets):
-            index = 0
-        self.set_bindings_for_selection(index)
+    def index_changed(self,new_index):
+        """
+        This function is called when the index changes. The given index
+        is the new index (don't use self.selected_index() here, since it
+        won't be correct yet!).
+        """
+        pass
 
 
-    def refresh(self):
-        appuifw.app.menu=self.get_menu_entries()
+    def items(self):
+        """ This function should return the list of items to display.
+        See appuifw.ListBox for valid elements for this list. """
+        return []
 
     def set_index(self,index):
 
     def set_index(self,index):
-        if index > len(self.widgets):
-            index = len(self.widgets)
-        if index < 0:
-            index = 0
-        self.view.set_list(self.items(),index)
+        """ Changes the currently selected item to index. """
+        self.view.set_list(self.items(),index % len(self.items()))
 
     def selected_index(self):
 
     def selected_index(self):
+        """ Returns the currently selected index. """
         return self.view.current()
 
         return self.view.current()
 
-
 class WidgetBasedListView(ListView):
     def __init__(self):
         self.widgets = self.generate_widgets()
 class WidgetBasedListView(ListView):
     def __init__(self):
         self.widgets = self.generate_widgets()
@@ -199,6 +220,10 @@ class WidgetBasedListView(ListView):
         self.set_bindings_for_selection(0)
         ListView.run(self)
 
         self.set_bindings_for_selection(0)
         ListView.run(self)
 
+    def index_changed(self,new_index):
+        self.set_bindings_for_selection(new_index)
+        super(WidgeteBasedListView, self).index_changed(new_index)
+
     def notify(self,object,attribute,new=None,old=None):
         self.refresh()
     def refresh(self):
     def notify(self,object,attribute,new=None,old=None):
         self.refresh()
     def refresh(self):
@@ -218,7 +243,7 @@ class WidgetBasedListView(ListView):
         return self.widgets[self.selected_index()]
         
 
         return self.widgets[self.selected_index()]
         
 
-class KeyBindingView(object):
+class KeyBindingView(View):
     
     def __init__(self):
         self.binding_map = {}
     
     def __init__(self):
         self.binding_map = {}
@@ -248,15 +273,14 @@ class KeyBindingView(object):
                     description='    '+description
                 menu_entries.append((description,function)) 
         menu_entries.append((u'Exit', self.exit))
                     description='    '+description
                 menu_entries.append((description,function)) 
         menu_entries.append((u'Exit', self.exit))
-        return menu_entries       
+        return menu_entries + super(KeyBindingView, self).get_menu_entries()
+
     def set_bindings_for_selection(self,selected_index):
         self.remove_all_key_bindings()
         
         for key,key_name,description,function in self.key_and_menu_bindings(selected_index):
             if key:
                 self.view.bind(key,function)
     def set_bindings_for_selection(self,selected_index):
         self.remove_all_key_bindings()
         
         for key,key_name,description,function in self.key_and_menu_bindings(selected_index):
             if key:
                 self.view.bind(key,function)
-        self.view.bind(EKeyUpArrow,lambda: self.index_changed(-1))
-        self.view.bind(EKeyDownArrow,lambda: self.index_changed(1))
         
     def remove_all_key_bindings(self):
         for key in all_key_values():
         
     def remove_all_key_bindings(self):
         for key in all_key_values():
@@ -310,7 +334,7 @@ class EditableListView(SearchableListView,KeyBindingView):
             key_and_menu_bindings.append((get_key(key),key,description,execute_and_update_function))
         return key_and_menu_bindings
 
             key_and_menu_bindings.append((get_key(key),key,description,execute_and_update_function))
         return key_and_menu_bindings
 
-    def change_entry(self):
+    def entry_selected(self):
         self.current_widget().change()
         self.refresh()
     def execute_and_update(self,function):
         self.current_widget().change()
         self.refresh()
     def execute_and_update(self,function):