diff options
author | Sebastian Koslowski <koslowski@kit.edu> | 2014-03-14 21:20:32 +0100 |
---|---|---|
committer | Sebastian Koslowski <koslowski@kit.edu> | 2014-03-15 13:42:12 +0100 |
commit | 8fc80149c385d36e8eb44c7ccf5f05649aaed335 (patch) | |
tree | 388255249fba4fd671a5cfd6e61261744546f196 | |
parent | 69dcaa75b629af4ebc465a073f54af84b7c75a11 (diff) |
grc: tabbed PropsDialog
-rw-r--r-- | grc/base/Block.py | 17 | ||||
-rw-r--r-- | grc/base/Constants.py | 4 | ||||
-rw-r--r-- | grc/base/Param.py | 4 | ||||
-rw-r--r-- | grc/gui/PropsDialog.py | 133 | ||||
-rw-r--r-- | grc/python/block.dtd | 6 |
5 files changed, 103 insertions, 61 deletions
diff --git a/grc/base/Block.py b/grc/base/Block.py index 668675c685..faa48d99b4 100644 --- a/grc/base/Block.py +++ b/grc/base/Block.py @@ -18,11 +18,12 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA """ from . import odict +from . Constants import ADVANCED_PARAM_TAB, DEFAULT_PARAM_TAB from Element import Element from Cheetah.Template import Template from UserDict import UserDict -from .. gui import Actions + class TemplateArg(UserDict): """ @@ -76,6 +77,11 @@ class Block(Element): self._block_wrapper_path = n.find('block_wrapper_path') self._bussify_sink = n.find('bus_sink') self._bussify_source = n.find('bus_source') + + # get list of param tabs + n_tabs = n.find('param_tab_order') or None + self._param_tab_labels = n_tabs.findall('tab') if n_tabs is not None else [DEFAULT_PARAM_TAB] + #create the param objects self._params = list() #add the id param @@ -142,6 +148,7 @@ class Block(Element): 'key': 'affinity', 'type': 'int_vector', 'hide': 'part', + 'tab': ADVANCED_PARAM_TAB }) )) if len(sources) and is_not_virtual_or_pad: @@ -151,7 +158,8 @@ class Block(Element): 'key': 'minoutbuf', 'type': 'int', 'hide': 'part', - 'value': '0' + 'value': '0', + 'tab': ADVANCED_PARAM_TAB }) )) self.get_params().append(self.get_parent().get_parent().Param( @@ -160,14 +168,14 @@ class Block(Element): 'key': 'maxoutbuf', 'type': 'int', 'hide': 'part', - 'value': '0' + 'value': '0', + 'tab': ADVANCED_PARAM_TAB }) )) def back_ofthe_bus(self, portlist): portlist.sort(key=lambda a: a.get_type() == 'bus'); - def filter_bus_port(self, ports): buslist = [i for i in ports if i.get_type() == 'bus']; @@ -213,6 +221,7 @@ class Block(Element): ############################################## # Access Params ############################################## + def get_param_tab_labels(self): return self._param_tab_labels def get_param_keys(self): return _get_keys(self._params) def get_param(self, key): return _get_elem(self._params, key) def get_params(self): return self._params diff --git a/grc/base/Constants.py b/grc/base/Constants.py index ef45be8dfe..e5026d9da7 100644 --- a/grc/base/Constants.py +++ b/grc/base/Constants.py @@ -23,3 +23,7 @@ import os DATA_DIR = os.path.dirname(__file__) FLOW_GRAPH_DTD = os.path.join(DATA_DIR, 'flow_graph.dtd') BLOCK_TREE_DTD = os.path.join(DATA_DIR, 'block_tree.dtd') + +# Param tabs +DEFAULT_PARAM_TAB = "General" +ADVANCED_PARAM_TAB = "Advanced" diff --git a/grc/base/Param.py b/grc/base/Param.py index 8b8362ac1a..f8bfe0d256 100644 --- a/grc/base/Param.py +++ b/grc/base/Param.py @@ -74,6 +74,9 @@ class Param(Element): value = n.find('value') or '' self._type = n.find('type') self._hide = n.find('hide') or '' + self._tab_label = n.find('tab') or block.get_param_tab_labels()[0] + if not self._tab_label in block.get_param_tab_labels(): + block.get_param_tab_labels().append(self._tab_label) #build the param Element.__init__(self, block) #create the Option objects from the n data @@ -143,6 +146,7 @@ class Param(Element): def set_value(self, value): self._value = str(value) #must be a string def get_type(self): return self.get_parent().resolve_dependencies(self._type) + def get_tab_label(self): return self._tab_label def is_enum(self): return self._type == 'enum' def __repr__(self): 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): """ diff --git a/grc/python/block.dtd b/grc/python/block.dtd index 21ffbe09af..b37c0ff760 100644 --- a/grc/python/block.dtd +++ b/grc/python/block.dtd @@ -25,11 +25,12 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA Top level element. A block contains a name, ...parameters list, and list of IO ports. --> -<!ELEMENT block (name, key, category?, throttle?, import*, var_make?, make, callback*, param*, bus_sink?, bus_source?, check*, sink*, source*, bus_structure_sink?, bus_structure_source?, doc?, grc_source?)> +<!ELEMENT block (name, key, category?, throttle?, import*, var_make?, make, callback*, param_tab_order?, param*, bus_sink?, bus_source?, check*, sink*, source*, bus_structure_sink?, bus_structure_source?, doc?, grc_source?)> <!-- Sub level elements. --> -<!ELEMENT param (name, key, value?, type, hide?, option*)> +<!ELEMENT param_tab_order (tab+)> +<!ELEMENT param (name, key, value?, type, hide?, option*, tab?)> <!ELEMENT option (name, key, opt*)> <!ELEMENT sink (name, type, vlen?, nports?, optional?)> <!ELEMENT source (name, type, vlen?, nports?, optional?)> @@ -41,6 +42,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA <!ELEMENT import (#PCDATA)> <!ELEMENT doc (#PCDATA)> <!ELEMENT grc_source (#PCDATA)> +<!ELEMENT tab (#PCDATA)> <!ELEMENT name (#PCDATA)> <!ELEMENT key (#PCDATA)> <!ELEMENT check (#PCDATA)> |