From 8fc80149c385d36e8eb44c7ccf5f05649aaed335 Mon Sep 17 00:00:00 2001
From: Sebastian Koslowski <koslowski@kit.edu>
Date: Fri, 14 Mar 2014 21:20:32 +0100
Subject: grc: tabbed PropsDialog

---
 grc/gui/PropsDialog.py | 133 +++++++++++++++++++++++++++++--------------------
 1 file changed, 78 insertions(+), 55 deletions(-)

(limited to 'grc/gui/PropsDialog.py')

diff --git a/grc/gui/PropsDialog.py b/grc/gui/PropsDialog.py
index 5c09f7cac1..0e85a4b7ee 100644
--- a/grc/gui/PropsDialog.py
+++ b/grc/gui/PropsDialog.py
@@ -23,6 +23,12 @@ import gtk
 
 from Dialogs import TextDisplay
 from Constants import MIN_DIALOG_WIDTH, MIN_DIALOG_HEIGHT
+import Utils
+
+TAB_LABEL_MARKUP_TMPL="""\
+#set $foreground = $valid and 'black' or 'red'
+<span foreground="$foreground">$encode($tab)</span>"""
+
 
 def get_title_label(title):
     """
@@ -41,6 +47,7 @@ def get_title_label(title):
     hbox.pack_start(label, False, False, padding=11)
     return hbox
 
+
 class PropsDialog(gtk.Dialog):
     """
     A dialog to set block parameters, view errors, and view documentation.
@@ -48,57 +55,69 @@ class PropsDialog(gtk.Dialog):
 
     def __init__(self, block):
         """
-        Properties dialog contructor.
+        Properties dialog constructor.
         
         Args:
             block: a block instance
         """
         self._hash = 0
-        LABEL_SPACING = 7
-        gtk.Dialog.__init__(self,
-            title='Properties: %s'%block.get_name(),
+
+        gtk.Dialog.__init__(
+            self,
+            title='Properties: %s' % block.get_name(),
             buttons=(gtk.STOCK_CANCEL, gtk.RESPONSE_REJECT, gtk.STOCK_OK, gtk.RESPONSE_ACCEPT),
         )
         self._block = block
         self.set_size_request(MIN_DIALOG_WIDTH, MIN_DIALOG_HEIGHT)
-        vbox = gtk.VBox()
-        #Create the scrolled window to hold all the parameters
-        scrolled_window = gtk.ScrolledWindow()
-        scrolled_window.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
-        scrolled_window.add_with_viewport(vbox)
-        self.vbox.pack_start(scrolled_window, True)
-        #Params box for block parameters
-        self._params_box = gtk.VBox()
-        self._params_box.pack_start(get_title_label('Parameters'), False)
-        self._input_object_params = list()
-        #Error Messages for the block
-        self._error_box = gtk.VBox()
-        self._error_messages_text_display = TextDisplay()
-        self._error_box.pack_start(gtk.Label(), False, False, LABEL_SPACING)
-        self._error_box.pack_start(get_title_label('Error Messages'), False)
-        self._error_box.pack_start(self._error_messages_text_display, False)
-        #Docs for the block
-        self._docs_box = err_box = gtk.VBox()
+
+        vpaned = gtk.VPaned()
+        self.vbox.pack_start(vpaned)
+
+        # Notebook to hold param boxes
+        notebook = gtk.Notebook()
+        notebook.set_show_border(False)
+        notebook.set_scrollable(True)  # scroll arrows for page tabs
+        notebook.set_tab_pos(gtk.POS_TOP)
+        vpaned.pack1(notebook, True)
+
+        # Params boxes for block parameters
+        self._params_boxes = list()
+        for tab in block.get_param_tab_labels():
+            label = gtk.Label()
+            vbox = gtk.VBox()
+            input_objects = []
+            scroll_box = gtk.ScrolledWindow()
+            scroll_box.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
+            scroll_box.add_with_viewport(vbox)
+            notebook.append_page(scroll_box, label)
+            self._params_boxes.append((tab, label, vbox, input_objects))
+
+        # Docs for the block
         self._docs_text_display = TextDisplay()
-        self._docs_box.pack_start(gtk.Label(), False, False, LABEL_SPACING)
-        self._docs_box.pack_start(get_title_label('Documentation'), False)
-        self._docs_box.pack_start(self._docs_text_display, False)
-        #Add the boxes
-        vbox.pack_start(self._params_box, False)
-        vbox.pack_start(self._error_box, False)
-        vbox.pack_start(self._docs_box, False)
-        #connect events
+        self._docs_box = gtk.ScrolledWindow()
+        self._docs_box.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
+        self._docs_box.add_with_viewport(self._docs_text_display)
+        notebook.append_page(self._docs_box, gtk.Label("Documentation"))
+
+        # Error Messages for the block
+        self._error_messages_text_display = TextDisplay()
+        self._error_box = gtk.ScrolledWindow()
+        self._error_box.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
+        self._error_box.add_with_viewport(self._error_messages_text_display)
+        self._error_box.set_size_request(-1, 40)
+        vpaned.pack2(self._error_box)
+
+        # Connect events
         self.connect('key-press-event', self._handle_key_press)
         self.connect('show', self._update_gui)
-        #show all (performs initial gui update)
-        self.show_all()
+        self.show_all()  # show all (performs initial gui update)
 
     def _params_changed(self):
         """
         Have the params in this dialog changed?
         Ex: Added, removed, type change, hide change...
         To the props dialog, the hide setting of 'none' and 'part' are identical.
-        Therfore, the props dialog only cares if the hide setting is/not 'all'.
+        Therefore, the props dialog only cares if the hide setting is/not 'all'.
         Make a hash that uniquely represents the params' state.
         
         Returns:
@@ -113,7 +132,7 @@ class PropsDialog(gtk.Dialog):
 
     def _handle_changed(self, *args):
         """
-        A change occured within a param:
+        A change occurred within a param:
         Rewrite/validate the block and update the gui.
         """
         #update for the block
@@ -123,7 +142,7 @@ class PropsDialog(gtk.Dialog):
 
     def _update_gui(self, *args):
         """
-        Repopulate the parameters box (if changed).
+        Repopulate the parameters boxes (if changed).
         Update all the input parameters.
         Update the error messages box.
         Hide the box if there are no errors.
@@ -133,28 +152,32 @@ class PropsDialog(gtk.Dialog):
         #update the params box
         if self._params_changed():
             #hide params box before changing
-            self._params_box.hide_all()
-            #empty the params box
-            for io_param in list(self._input_object_params):
-                self._params_box.remove(io_param)
-                self._input_object_params.remove(io_param)
-                io_param.destroy()
-            #repopulate the params box
-            for param in self._block.get_params():
-                if param.get_hide() == 'all': continue
-                io_param = param.get_input(self._handle_changed)
-                self._input_object_params.append(io_param)
-                self._params_box.pack_start(io_param, False)
-            #show params box with new params
-            self._params_box.show_all()
+            for tab, label, vbox, input_objects in self._params_boxes:
+                vbox.hide_all()
+                # empty the params box
+                for io_param in input_objects:
+                    vbox.remove(io_param)
+                    input_objects.remove(io_param)
+                    io_param.destroy()
+                # repopulate the params box
+                box_all_valid = True
+                for param in filter(lambda p: p.get_tab_label() == tab, self._block.get_params()):
+                    if param.get_hide() == 'all': continue
+                    io_param = param.get_input(self._handle_changed)
+                    input_objects.append(io_param)
+                    vbox.pack_start(io_param, False)
+                    box_all_valid = box_all_valid and param.is_valid()
+                label.set_markup(Utils.parse_template(TAB_LABEL_MARKUP_TMPL, valid=box_all_valid, tab=tab))
+                #show params box with new params
+                vbox.show_all()
         #update the errors box
-        if self._block.is_valid(): self._error_box.hide()
-        else: self._error_box.show()
+        if self._block.is_valid():
+            self._error_box.hide()
+        else:
+            self._error_box.show()
         messages = '\n\n'.join(self._block.get_error_messages())
         self._error_messages_text_display.set_text(messages)
         #update the docs box
-        if self._block.get_doc(): self._docs_box.show()
-        else: self._docs_box.hide()
         self._docs_text_display.set_text(self._block.get_doc())
 
     def _handle_key_press(self, widget, event):
@@ -167,8 +190,8 @@ class PropsDialog(gtk.Dialog):
         """
         if event.keyval == gtk.keysyms.Return:
             self.response(gtk.RESPONSE_ACCEPT)
-            return True #handled here
-        return False #forward the keypress
+            return True  # handled here
+        return False  # forward the keypress
 
     def run(self):
         """
-- 
cgit v1.2.3