From b2a294302e5cd72ec41b5471f3f8dc5da9abff66 Mon Sep 17 00:00:00 2001 From: Spencer Ross <brashendeavours@gmail.com> Date: Thu, 17 Aug 2017 19:41:04 -0400 Subject: Fixes #1297, adds grc gui_hint collision detection --- grc/core/Param.py | 128 ++++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 106 insertions(+), 22 deletions(-) (limited to 'grc/core/Param.py') diff --git a/grc/core/Param.py b/grc/core/Param.py index 00c9e7d827..6c2c83fda8 100644 --- a/grc/core/Param.py +++ b/grc/core/Param.py @@ -533,37 +533,121 @@ class Param(Element): # GUI Position/Hint ######################### elif t == 'gui_hint': - if ':' in v: - tab, pos = v.split(':') - elif '@' in v: - tab, pos = v, '' - else: - tab, pos = '', v - - if '@' in tab: - tab, index = tab.split('@') - else: - index = '?' - - # TODO: Problem with this code. Produces bad tabs - widget_str = ({ - (True, True): 'self.%(tab)s_grid_layout_%(index)s.addWidget(%(widget)s, %(pos)s)', - (True, False): 'self.%(tab)s_layout_%(index)s.addWidget(%(widget)s)', - (False, True): 'self.top_grid_layout.addWidget(%(widget)s, %(pos)s)', - (False, False): 'self.top_layout.addWidget(%(widget)s)', - }[bool(tab), bool(pos)]) % {'tab': tab, 'index': index, 'widget': '%s', 'pos': pos} - + # FIXME: Move replace(...) into the make template of the qtgui blocks # Return a string here class GuiHint(object): def __init__(self, ws): self._ws = ws - + def __call__(self, w): return (self._ws.replace('addWidget', 'addLayout') if 'layout' in w else self._ws) % w - + def __str__(self): return self._ws + + if (self.get_parent().get_state() == Constants.BLOCK_DISABLED): + return GuiHint('') + + # Parsing + if ':' in v: + tab, pos = v.split(':') + elif '@' in v: + tab, pos = v, '' + else: + tab, pos = '', v + + if '@' in tab: + tab, index = tab.split('@') + else: + index = '0' + + position_set = bool(pos) + tab_set = bool(tab) + + # Validation + if position_set: + e = self.get_parent().get_parent().evaluate(pos) + + if len(e) == 2: + e = e + (1,1) + row, col, row_span, col_span = e + + if not isinstance(e, (list, tuple)) or not (len(e) == 2 or len(e) == 4) or not all([isinstance(ei, int) for ei in e]): + raise Exception('Invalid GUI Hint entered: {e!s:s} (Must be a list of {{2,4}} non-negative integers).'.format(e=e)) + + if (row < 0) or (col < 0): + raise Exception('Invalid GUI Hint entered: {e!s:s} (non-negative integers only).'.format(e=e)) + + if (row_span < 1) or (col_span < 1): + raise Exception('Invalid GUI Hint entered: {e!s:s} (positive row/column span required).'.format(e=e)) + + if tab_set: + enabled_blocks = self.get_parent().get_parent().get_enabled_blocks() + tab_list = filter(lambda block: str(block.get_key()) == 'qtgui_tab_widget', enabled_blocks) + tab_match = filter(lambda t: t.get_id() == tab, tab_list) + if not tab_match: + raise Exception('Invalid tab name entered: {tab!s:s} (Tab name not found).'.format(tab=tab)) + + tab_index_size = tab_match[0].get_param('num_tabs').get_value() + if index >= tab_index_size: + raise Exception('Invalid tab index entered: {tab!s:s}@{index!s:s} (Index out of range).'.format(tab=tab, + index=index)) + + # Code Generation + if position_set and tab_set: + widget_str = 'self.{tab:s}_grid_layout_{index:s}.addWidget({widget:s}, {e!s:s})' + widget_str += '\n[self.{tab:s}_grid_layout_{index:s}.setRowStretch(r,1) for r in range({fRow:d},{lRow:d})]' + widget_str += '\n[self.{tab:s}_grid_layout_{index:s}.setColumnStretch(c,1) for c in range({fCol:d},{lCol:d})]' + widget_str = widget_str.format(tab=tab, + index=index, + widget='%s', + e=str(e)[1:-1], + fRow=row, + lRow=(row + row_span), + fCol=col, + lCol=(col + col_span)) + + elif position_set and not tab_set: + widget_str = 'self.top_grid_layout.addWidget({widget:s}, {e!s:s})' + widget_str += '\n[self.top_grid_layout.setRowStretch(r,1) for r in range({fRow:d},{lRow:d})]' + widget_str += '\n[self.top_grid_layout.setColumnStretch(c,1) for c in range({fCol:d},{lCol:d})]' + widget_str = widget_str.format(widget='%s', + e=str(e)[1:-1], + fRow=row, + lRow=(row + row_span), + fCol=col, + lCol=(col + col_span)) + + elif not position_set and tab_set: + widget_str = 'self.{tab:s}_layout_{index:s}.addWidget({widget:s})' + widget_str = widget_str.format(tab=tab, + index=index, + widget='%s') + + elif not position_set and not tab_set: + widget_str = 'self.top_layout.addWidget({widget:s})' + widget_str = widget_str.format(widget='%s') + + # Collision Detection + if position_set: + if tab_set: + my_parent = '{tab:s}@{index:s}'.format(tab=tab, + index=index) + else: + my_parent = 'main' + # Calculate hostage cells + for r in range(row, row + row_span): + for c in range(col, col + col_span): + self._hostage_cells.append((my_parent, (r, c))) + # Avoid collisions + params = filter(lambda p: p is not self, self.get_all_params('gui_hint')) + for param in params: + for parent, cell in param._hostage_cells: + if (parent, cell) in self._hostage_cells: + raise Exception('Another graphical element is using parent "{parent!s:s}", cell "{cell!s:s}".'.format(parent=parent, + cell=cell)) + return GuiHint(widget_str) ######################### # Grid Position Type -- cgit v1.2.3 From 2b35d7086f9585bb18fff3456b9d37d027d0f901 Mon Sep 17 00:00:00 2001 From: Spencer Ross <brashendeavours@gmail.com> Date: Sat, 19 Aug 2017 23:16:38 -0400 Subject: moves gui_hint logic into parsing function, removes GuiHint class from Param.py, cleans up gr-qtgui blocks <make> functions --- gr-qtgui/grc/qtgui_ber_sink_b.xml | 2 +- gr-qtgui/grc/qtgui_check_box.xml | 3 +- gr-qtgui/grc/qtgui_chooser.xml | 3 +- gr-qtgui/grc/qtgui_const_sink_x.xml | 3 +- gr-qtgui/grc/qtgui_edit_box_msg.xml | 2 +- gr-qtgui/grc/qtgui_entry.xml | 5 +- gr-qtgui/grc/qtgui_freq_sink_x.xml | 3 +- gr-qtgui/grc/qtgui_histogram_sink_x.xml | 4 +- gr-qtgui/grc/qtgui_label.xml | 3 +- gr-qtgui/grc/qtgui_number_sink.xml | 3 +- gr-qtgui/grc/qtgui_push_button.xml | 4 +- gr-qtgui/grc/qtgui_range.xml | 3 +- gr-qtgui/grc/qtgui_sink_x.xml | 2 +- gr-qtgui/grc/qtgui_tab_widget.xml | 3 +- gr-qtgui/grc/qtgui_time_raster_x.xml | 3 +- gr-qtgui/grc/qtgui_time_sink_x.xml | 3 +- gr-qtgui/grc/qtgui_vector_sink_f.xml | 3 +- gr-qtgui/grc/qtgui_waterfall_sink_x.xml | 3 +- grc/core/Param.py | 232 ++++++++++++++++---------------- grc/core/generator/Generator.py | 2 +- 20 files changed, 154 insertions(+), 135 deletions(-) (limited to 'grc/core/Param.py') diff --git a/gr-qtgui/grc/qtgui_ber_sink_b.xml b/gr-qtgui/grc/qtgui_ber_sink_b.xml index da3fc6ebf8..851502a774 100644 --- a/gr-qtgui/grc/qtgui_ber_sink_b.xml +++ b/gr-qtgui/grc/qtgui_ber_sink_b.xml @@ -47,7 +47,7 @@ for i in xrange($num_curves): self.$(id).set_line_alpha(i, alphas[i]) self._$(id)_win = sip.wrapinstance(self.$(id).pyqwidget(), Qt.QWidget) -$(gui_hint()($win))</make> +$(gui_hint() % $win)</make> <param> <name>esno</name> diff --git a/gr-qtgui/grc/qtgui_check_box.xml b/gr-qtgui/grc/qtgui_check_box.xml index 67c8848a22..a02c83e3cf 100644 --- a/gr-qtgui/grc/qtgui_check_box.xml +++ b/gr-qtgui/grc/qtgui_check_box.xml @@ -20,7 +20,8 @@ self._$(id)_choices_inv = dict((v,k) for k,v in self._$(id)_choices.iteritems()) self._$(id)_callback = lambda i: Qt.QMetaObject.invokeMethod($(win), "setChecked", Qt.Q_ARG("bool", self._$(id)_choices_inv[i])) self._$(id)_callback(self.$id) $(win).stateChanged.connect(lambda i: self.set_$(id)(self._$(id)_choices[bool(i)])) -$(gui_hint()($win))</make> +$(gui_hint() % $win)</make> + <callback>self.set_$(id)($value)</callback> <callback>self._$(id)_callback($id)</callback> <param> diff --git a/gr-qtgui/grc/qtgui_chooser.xml b/gr-qtgui/grc/qtgui_chooser.xml index f018354dd4..b91566ae74 100644 --- a/gr-qtgui/grc/qtgui_chooser.xml +++ b/gr-qtgui/grc/qtgui_chooser.xml @@ -86,7 +86,8 @@ self._$(id)_callback(self.$id) self._$(id)_button_group.buttonClicked[int].connect( lambda i: self.set_$(id)(self._$(id)_options[i])) #end if -$(gui_hint()($win))</make> +$(gui_hint() % $win)</make> + <callback>self.set_$(id)($value)</callback> <callback>self._$(id)_callback($id)</callback> <param> diff --git a/gr-qtgui/grc/qtgui_const_sink_x.xml b/gr-qtgui/grc/qtgui_const_sink_x.xml index 755f12f964..6bf31d5190 100644 --- a/gr-qtgui/grc/qtgui_const_sink_x.xml +++ b/gr-qtgui/grc/qtgui_const_sink_x.xml @@ -51,7 +51,8 @@ for i in xrange(#if $type.t == 'message' then 1 else $nconnections#): self.$(id).set_line_alpha(i, alphas[i]) self._$(id)_win = sip.wrapinstance(self.$(id).pyqwidget(), Qt.QWidget) -$(gui_hint()($win))</make> +$(gui_hint() % $win)</make> + <callback>set_resize($width, $height)</callback> <callback>set_update_time($update_time)</callback> <callback>set_title($which, $title)</callback> diff --git a/gr-qtgui/grc/qtgui_edit_box_msg.xml b/gr-qtgui/grc/qtgui_edit_box_msg.xml index c7c758a612..276cfe9801 100644 --- a/gr-qtgui/grc/qtgui_edit_box_msg.xml +++ b/gr-qtgui/grc/qtgui_edit_box_msg.xml @@ -13,7 +13,7 @@ <make>#set $win = 'self._%s_win'%$id qtgui.edit_box_msg($(type.t), $value, $label, $is_pair, $is_static, $key) self._$(id)_win = sip.wrapinstance(self.$(id).pyqwidget(), Qt.QWidget) -$(gui_hint()($win))</make> +$(gui_hint() % $win)</make> <param> <name>Type</name> diff --git a/gr-qtgui/grc/qtgui_entry.xml b/gr-qtgui/grc/qtgui_entry.xml index cce2edb4b2..ab35aec858 100644 --- a/gr-qtgui/grc/qtgui_entry.xml +++ b/gr-qtgui/grc/qtgui_entry.xml @@ -21,9 +21,12 @@ self._$(id)_line_edit = Qt.QLineEdit(str(self.$id)) self._$(id)_tool_bar.addWidget(self._$(id)_line_edit) self._$(id)_line_edit.returnPressed.connect( lambda: self.set_$(id)($(type.conv)(str(self._$(id)_line_edit.text().toAscii())))) -$(gui_hint()($win))</make> +$(gui_hint() % $win)</make> + <callback>self.set_$(id)($value)</callback> + <callback>Qt.QMetaObject.invokeMethod(self._$(id)_line_edit, "setText", Qt.Q_ARG("QString", $(type.str)($id)))</callback> + <param> <name>Label</name> <key>label</key> diff --git a/gr-qtgui/grc/qtgui_freq_sink_x.xml b/gr-qtgui/grc/qtgui_freq_sink_x.xml index 009a184327..5c6595cb33 100644 --- a/gr-qtgui/grc/qtgui_freq_sink_x.xml +++ b/gr-qtgui/grc/qtgui_freq_sink_x.xml @@ -54,7 +54,8 @@ for i in xrange(#if $type.t == 'message' then 1 else $nconnections#): self.$(id).set_line_alpha(i, alphas[i]) self._$(id)_win = sip.wrapinstance(self.$(id).pyqwidget(), Qt.QWidget) -$(gui_hint()($win))</make> +$(gui_hint() % $win)</make> + <callback>set_frequency_range($fc, $bw)</callback> <callback>set_update_time($update_time)</callback> <callback>set_title($which, $title)</callback> diff --git a/gr-qtgui/grc/qtgui_histogram_sink_x.xml b/gr-qtgui/grc/qtgui_histogram_sink_x.xml index a789d2e4fa..8bf9662b74 100644 --- a/gr-qtgui/grc/qtgui_histogram_sink_x.xml +++ b/gr-qtgui/grc/qtgui_histogram_sink_x.xml @@ -53,8 +53,8 @@ for i in xrange(#if $type.t == 'message' then 1 else $nconnections#): self.$(id).set_line_alpha(i, alphas[i]) self._$(id)_win = sip.wrapinstance(self.$(id).pyqwidget(), Qt.QWidget) -$(gui_hint()($win)) - </make> +$(gui_hint() % $win)</make> + <callback>set_update_time($update_time)</callback> <callback>set_title($which, $title)</callback> <callback>set_color($which, $color)</callback> diff --git a/gr-qtgui/grc/qtgui_label.xml b/gr-qtgui/grc/qtgui_label.xml index d67f3d7500..90b77fa968 100644 --- a/gr-qtgui/grc/qtgui_label.xml +++ b/gr-qtgui/grc/qtgui_label.xml @@ -26,8 +26,7 @@ else: $(win).addWidget(Qt.QLabel($label+": ")) self._$(id)_label = Qt.QLabel(str(self._$(id)_formatter(self.$id))) self._$(id)_tool_bar.addWidget(self._$(id)_label) -$(gui_hint()($win)) - </make> +$(gui_hint() % $win)</make> <callback>self.set_$(id)(self._$(id)_formatter($value))</callback> <callback>Qt.QMetaObject.invokeMethod(self._$(id)_label, "setText", Qt.Q_ARG("QString", $id))</callback> diff --git a/gr-qtgui/grc/qtgui_number_sink.xml b/gr-qtgui/grc/qtgui_number_sink.xml index d10b7325c0..264baae667 100644 --- a/gr-qtgui/grc/qtgui_number_sink.xml +++ b/gr-qtgui/grc/qtgui_number_sink.xml @@ -41,7 +41,8 @@ for i in xrange($nconnections): self.$(id).enable_autoscale($autoscale) self._$(id)_win = sip.wrapinstance(self.$(id).pyqwidget(), Qt.QWidget) -$(gui_hint()($win))</make> +$(gui_hint() % $win)</make> + <callback>set_update_time($update_time)</callback> <param_tab_order> diff --git a/gr-qtgui/grc/qtgui_push_button.xml b/gr-qtgui/grc/qtgui_push_button.xml index a535bb6473..e4f598e725 100644 --- a/gr-qtgui/grc/qtgui_push_button.xml +++ b/gr-qtgui/grc/qtgui_push_button.xml @@ -18,8 +18,10 @@ $win = Qt.QPushButton($label) self._$(id)_choices = {'Pressed': $pressed, 'Released': $released} $(win).pressed.connect(lambda: self.set_$(id)(self._$(id)_choices['Pressed'])) $(win).released.connect(lambda: self.set_$(id)(self._$(id)_choices['Released'])) -$(gui_hint()($win))</make> +$(gui_hint() % $win)</make> + <callback>self.set_$(id)($value)</callback> + <param> <name>Label</name> <key>label</key> diff --git a/gr-qtgui/grc/qtgui_range.xml b/gr-qtgui/grc/qtgui_range.xml index 71b614cc5e..0999311a0b 100644 --- a/gr-qtgui/grc/qtgui_range.xml +++ b/gr-qtgui/grc/qtgui_range.xml @@ -17,7 +17,8 @@ #end if $(range) = Range($start, $stop, $step, $value, $min_len) $(win) = RangeWidget($range, self.set_$(id), $label, "$widget", $rangeType) -$(gui_hint()($win))</make> +$(gui_hint() % $win)</make> + <callback>self.set_$(id)($value)</callback> <param> diff --git a/gr-qtgui/grc/qtgui_sink_x.xml b/gr-qtgui/grc/qtgui_sink_x.xml index 7488ea59d8..4dbf0e6375 100644 --- a/gr-qtgui/grc/qtgui_sink_x.xml +++ b/gr-qtgui/grc/qtgui_sink_x.xml @@ -25,7 +25,7 @@ qtgui.$(type.fcn)( ) self.$(id).set_update_time(1.0/$rate) self._$(id)_win = sip.wrapinstance(self.$(id).pyqwidget(), Qt.QWidget) -$(gui_hint()($win)) +$(gui_hint() % $win) self.$(id).enable_rf_freq($showrf) diff --git a/gr-qtgui/grc/qtgui_tab_widget.xml b/gr-qtgui/grc/qtgui_tab_widget.xml index 1bbadc8e51..fc8ad0553a 100644 --- a/gr-qtgui/grc/qtgui_tab_widget.xml +++ b/gr-qtgui/grc/qtgui_tab_widget.xml @@ -21,7 +21,8 @@ self.$(id)_grid_layout_$(i) = Qt.QGridLayout() self.$(id)_layout_$(i).addLayout(self.$(id)_grid_layout_$(i)) $(win).addTab(self.$(id)_widget_$(i), $label) #end for -$(gui_hint()($win))</make> +$(gui_hint() % $win)</make> + <param> <name>Num Tabs</name> <key>num_tabs</key> diff --git a/gr-qtgui/grc/qtgui_time_raster_x.xml b/gr-qtgui/grc/qtgui_time_raster_x.xml index 0359dc3b71..2d2f3cbff4 100644 --- a/gr-qtgui/grc/qtgui_time_raster_x.xml +++ b/gr-qtgui/grc/qtgui_time_raster_x.xml @@ -41,7 +41,8 @@ for i in xrange(#if $type.t == 'message' then 1 else $nconnections#): self.$(id).set_line_alpha(i, alphas[i]) self._$(id)_win = sip.wrapinstance(self.$(id).pyqwidget(), Qt.QWidget) -$(gui_hint()($win))</make> +$(gui_hint() % $win)</make> + <callback>set_num_rows($nrows)</callback> <callback>set_num_cols($ncols)</callback> <callback>set_multiplier($mult)</callback> diff --git a/gr-qtgui/grc/qtgui_time_sink_x.xml b/gr-qtgui/grc/qtgui_time_sink_x.xml index fbee4ca483..726e9fdf34 100644 --- a/gr-qtgui/grc/qtgui_time_sink_x.xml +++ b/gr-qtgui/grc/qtgui_time_sink_x.xml @@ -74,7 +74,8 @@ for i in xrange(#if $type.t == 'message' then 1 else $nconnections#): #end if self._$(id)_win = sip.wrapinstance(self.$(id).pyqwidget(), Qt.QWidget) -$(gui_hint()($win))</make> +$(gui_hint() % $win)</make> + <callback>set_time_domain_axis($min, $max)</callback> <callback>set_update_time($update_time)</callback> <callback>set_title($which, $title)</callback> diff --git a/gr-qtgui/grc/qtgui_vector_sink_f.xml b/gr-qtgui/grc/qtgui_vector_sink_f.xml index 9f40d57729..1c17b8256a 100644 --- a/gr-qtgui/grc/qtgui_vector_sink_f.xml +++ b/gr-qtgui/grc/qtgui_vector_sink_f.xml @@ -46,7 +46,8 @@ for i in xrange($nconnections): self.$(id).set_line_alpha(i, alphas[i]) self._$(id)_win = sip.wrapinstance(self.$(id).pyqwidget(), Qt.QWidget) -$(gui_hint()($win))</make> +$(gui_hint() % $win)</make> + <callback>set_update_time($update_time)</callback> <callback>set_title($title)</callback> <callback>set_color($which, $color)</callback> diff --git a/gr-qtgui/grc/qtgui_waterfall_sink_x.xml b/gr-qtgui/grc/qtgui_waterfall_sink_x.xml index cdecd5cce1..206318e30d 100644 --- a/gr-qtgui/grc/qtgui_waterfall_sink_x.xml +++ b/gr-qtgui/grc/qtgui_waterfall_sink_x.xml @@ -47,7 +47,8 @@ for i in xrange(#if $type.t == 'message' then 1 else $nconnections#): self.$(id).set_intensity_range($int_min, $int_max) self._$(id)_win = sip.wrapinstance(self.$(id).pyqwidget(), Qt.QWidget) -$(gui_hint()($win))</make> +$(gui_hint() % $win)</make> + <callback>set_frequency_range($fc, $bw)</callback> <callback>set_update_time($update_time)</callback> <callback>set_title($which, $title)</callback> diff --git a/grc/core/Param.py b/grc/core/Param.py index 6c2c83fda8..00336737b0 100644 --- a/grc/core/Param.py +++ b/grc/core/Param.py @@ -533,122 +533,10 @@ class Param(Element): # GUI Position/Hint ######################### elif t == 'gui_hint': - - # FIXME: Move replace(...) into the make template of the qtgui blocks - # Return a string here - class GuiHint(object): - def __init__(self, ws): - self._ws = ws - - def __call__(self, w): - return (self._ws.replace('addWidget', 'addLayout') if 'layout' in w else self._ws) % w - - def __str__(self): - return self._ws - if (self.get_parent().get_state() == Constants.BLOCK_DISABLED): - return GuiHint('') - - # Parsing - if ':' in v: - tab, pos = v.split(':') - elif '@' in v: - tab, pos = v, '' - else: - tab, pos = '', v - - if '@' in tab: - tab, index = tab.split('@') + return '' else: - index = '0' - - position_set = bool(pos) - tab_set = bool(tab) - - # Validation - if position_set: - e = self.get_parent().get_parent().evaluate(pos) - - if len(e) == 2: - e = e + (1,1) - row, col, row_span, col_span = e - - if not isinstance(e, (list, tuple)) or not (len(e) == 2 or len(e) == 4) or not all([isinstance(ei, int) for ei in e]): - raise Exception('Invalid GUI Hint entered: {e!s:s} (Must be a list of {{2,4}} non-negative integers).'.format(e=e)) - - if (row < 0) or (col < 0): - raise Exception('Invalid GUI Hint entered: {e!s:s} (non-negative integers only).'.format(e=e)) - - if (row_span < 1) or (col_span < 1): - raise Exception('Invalid GUI Hint entered: {e!s:s} (positive row/column span required).'.format(e=e)) - - if tab_set: - enabled_blocks = self.get_parent().get_parent().get_enabled_blocks() - tab_list = filter(lambda block: str(block.get_key()) == 'qtgui_tab_widget', enabled_blocks) - tab_match = filter(lambda t: t.get_id() == tab, tab_list) - if not tab_match: - raise Exception('Invalid tab name entered: {tab!s:s} (Tab name not found).'.format(tab=tab)) - - tab_index_size = tab_match[0].get_param('num_tabs').get_value() - if index >= tab_index_size: - raise Exception('Invalid tab index entered: {tab!s:s}@{index!s:s} (Index out of range).'.format(tab=tab, - index=index)) - - # Code Generation - if position_set and tab_set: - widget_str = 'self.{tab:s}_grid_layout_{index:s}.addWidget({widget:s}, {e!s:s})' - widget_str += '\n[self.{tab:s}_grid_layout_{index:s}.setRowStretch(r,1) for r in range({fRow:d},{lRow:d})]' - widget_str += '\n[self.{tab:s}_grid_layout_{index:s}.setColumnStretch(c,1) for c in range({fCol:d},{lCol:d})]' - widget_str = widget_str.format(tab=tab, - index=index, - widget='%s', - e=str(e)[1:-1], - fRow=row, - lRow=(row + row_span), - fCol=col, - lCol=(col + col_span)) - - elif position_set and not tab_set: - widget_str = 'self.top_grid_layout.addWidget({widget:s}, {e!s:s})' - widget_str += '\n[self.top_grid_layout.setRowStretch(r,1) for r in range({fRow:d},{lRow:d})]' - widget_str += '\n[self.top_grid_layout.setColumnStretch(c,1) for c in range({fCol:d},{lCol:d})]' - widget_str = widget_str.format(widget='%s', - e=str(e)[1:-1], - fRow=row, - lRow=(row + row_span), - fCol=col, - lCol=(col + col_span)) - - elif not position_set and tab_set: - widget_str = 'self.{tab:s}_layout_{index:s}.addWidget({widget:s})' - widget_str = widget_str.format(tab=tab, - index=index, - widget='%s') - - elif not position_set and not tab_set: - widget_str = 'self.top_layout.addWidget({widget:s})' - widget_str = widget_str.format(widget='%s') - - # Collision Detection - if position_set: - if tab_set: - my_parent = '{tab:s}@{index:s}'.format(tab=tab, - index=index) - else: - my_parent = 'main' - # Calculate hostage cells - for r in range(row, row + row_span): - for c in range(col, col + col_span): - self._hostage_cells.append((my_parent, (r, c))) - # Avoid collisions - params = filter(lambda p: p is not self, self.get_all_params('gui_hint')) - for param in params: - for parent, cell in param._hostage_cells: - if (parent, cell) in self._hostage_cells: - raise Exception('Another graphical element is using parent "{parent!s:s}", cell "{cell!s:s}".'.format(parent=parent, - cell=cell)) - - return GuiHint(widget_str) + return self.parse_gui_hint(v) ######################### # Grid Position Type ######################### @@ -837,3 +725,119 @@ class Param(Element): n['key'] = self.get_key() n['value'] = self.get_value() return n + + ############################################## + # GUI Hint + ############################################## + def parse_gui_hint(self, v): + """ + Parse/validate gui hint value. + + Args: + v: gui_hint string from a block's 'gui_hint' param + + Returns: + string of python code for positioning GUI elements in pyQT + """ + + # Parsing + if ':' in v: + tab, pos = v.split(':') + elif ',' in v: + tab, pos = '', v + else: + tab, pos = v, '' + + if '@' in tab: + tab, index = tab.split('@') + else: + index = '0' + index = int(index) + + position_set = bool(pos) + tab_set = bool(tab) + + # Validation + if position_set: + e = self.get_parent().get_parent().evaluate(pos) + + if len(e) == 2: + e = e + (1,1) + row, col, row_span, col_span = e + + if not isinstance(e, (list, tuple)) or not (len(e) == 2 or len(e) == 4) or not all([isinstance(ei, int) for ei in e]): + raise Exception('Invalid GUI Hint entered: {e!s:s} (Must be a list of {{2,4}} non-negative integers).'.format(e=e)) + + if (row < 0) or (col < 0): + raise Exception('Invalid GUI Hint entered: {e!s:s} (non-negative integers only).'.format(e=e)) + + if (row_span < 1) or (col_span < 1): + raise Exception('Invalid GUI Hint entered: {e!s:s} (positive row/column span required).'.format(e=e)) + + if tab_set: + enabled_blocks = self.get_parent().get_parent().get_enabled_blocks() + tab_list = filter(lambda block: str(block.get_key()) == 'qtgui_tab_widget', enabled_blocks) + tab_match = filter(lambda t: t.get_id() == tab, tab_list) + if not tab_match: + raise Exception('Invalid tab name entered: {tab!s:s} (Tab name not found).'.format(tab=tab)) + + tab_index_size = int(tab_match[0].get_param('num_tabs').get_value()) + if index >= tab_index_size: + raise Exception('Invalid tab index entered: {tab!s:s}@{index!s:s} (Index out of range).'.format(tab=tab, + index=index)) + + # Code Generation + if position_set and tab_set: + widget_str = 'self.{tab:s}_grid_layout_{index!s:s}.addWidget({widget:s}, {e!s:s})' + widget_str += '\n[self.{tab:s}_grid_layout_{index!s:s}.setRowStretch(r,1) for r in range({fRow:d},{lRow:d})]' + widget_str += '\n[self.{tab:s}_grid_layout_{index!s:s}.setColumnStretch(c,1) for c in range({fCol:d},{lCol:d})]' + widget_str = widget_str.format(tab=tab, + index=index, + widget='%s', + e=str(e)[1:-1], + fRow=row, + lRow=(row + row_span), + fCol=col, + lCol=(col + col_span)) + + elif position_set and not tab_set: + widget_str = 'self.top_grid_layout.addWidget({widget:s}, {e!s:s})' + widget_str += '\n[self.top_grid_layout.setRowStretch(r,1) for r in range({fRow:d},{lRow:d})]' + widget_str += '\n[self.top_grid_layout.setColumnStretch(c,1) for c in range({fCol:d},{lCol:d})]' + widget_str = widget_str.format(widget='%s', + e=str(e)[1:-1], + fRow=row, + lRow=(row + row_span), + fCol=col, + lCol=(col + col_span)) + + elif not position_set and tab_set: + widget_str = 'self.{tab:s}_layout_{index!s:s}.addWidget({widget:s})' + widget_str = widget_str.format(tab=tab, + index=index, + widget='%s') + + elif not position_set and not tab_set: + widget_str = 'self.top_layout.addWidget({widget:s})' + widget_str = widget_str.format(widget='%s') + + # Collision Detection + if position_set: + if tab_set: + my_parent = '{tab:s}@{index!s:s}'.format(tab=tab, + index=index) + else: + my_parent = 'main' + # Calculate hostage cells + for r in range(row, row + row_span): + for c in range(col, col + col_span): + self._hostage_cells.append((my_parent, (r, c))) + # Avoid collisions + params = filter(lambda p: p is not self, self.get_all_params('gui_hint')) + for param in params: + for parent, cell in param._hostage_cells: + if (parent, cell) in self._hostage_cells: + raise Exception('Another graphical element is using parent "{parent!s:s}", cell "{cell!s:s}".'.format(parent=parent, + cell=cell)) + + return widget_str \ No newline at end of file diff --git a/grc/core/generator/Generator.py b/grc/core/generator/Generator.py index 8c1cd9a6b0..2e639d4985 100644 --- a/grc/core/generator/Generator.py +++ b/grc/core/generator/Generator.py @@ -398,6 +398,6 @@ class QtHierBlockGenerator(HierBlockGenerator): block_n['make'] += ( "\n#set $win = 'self.%s' % $id" - "\n${gui_hint()($win)}" + "\n${gui_hint() % $win}" ) return n -- cgit v1.2.3 From 5a8799f5bd477d5e8e520dd0dab1b8874db0e68e Mon Sep 17 00:00:00 2001 From: Sebastian Koslowski <sebastian.koslowski@gmail.com> Date: Sat, 30 Sep 2017 21:11:09 +0200 Subject: [grc] refactor #1418 --- grc/core/Param.py | 142 ++++++++++++++++++++++++++---------------------------- 1 file changed, 68 insertions(+), 74 deletions(-) (limited to 'grc/core/Param.py') diff --git a/grc/core/Param.py b/grc/core/Param.py index 00336737b0..01697919d0 100644 --- a/grc/core/Param.py +++ b/grc/core/Param.py @@ -20,6 +20,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA import ast import weakref import re +import textwrap from . import Constants from .Constants import VECTOR_TYPES, COMPLEX_TYPES, REAL_TYPES, INT_TYPES @@ -212,7 +213,7 @@ class Param(Element): self._value = value or '' self._default = value self._init = False - self._hostage_cells = list() + self.hostage_cells = set() self.template_arg = TemplateArg(self) def get_types(self): @@ -395,7 +396,6 @@ class Param(Element): self._init = True self._lisitify_flag = False self._stringify_flag = False - self._hostage_cells = list() t = self.get_type() v = self.get_value() @@ -562,12 +562,12 @@ class Param(Element): # Calculate hostage cells for r in range(row_span): for c in range(col_span): - self._hostage_cells.append((my_parent, (row+r, col+c))) + self.hostage_cells.append((my_parent, (row + r, col + c))) # Avoid collisions params = filter(lambda p: p is not self, self.get_all_params('grid_pos')) for param in params: for parent, cell in param._hostage_cells: - if (parent, cell) in self._hostage_cells: + if (parent, cell) in self.hostage_cells: raise Exception('Another graphical element is using parent "{0}", cell "{1}".'.format(str(parent), str(cell))) return e ######################### @@ -739,6 +739,7 @@ class Param(Element): Returns: string of python code for positioning GUI elements in pyQT """ + self.hostage_cells.clear() # Parsing if ':' in v: @@ -754,90 +755,83 @@ class Param(Element): index = '0' index = int(index) - position_set = bool(pos) - tab_set = bool(tab) - # Validation - if position_set: + def parse_pos(): e = self.get_parent().get_parent().evaluate(pos) - if len(e) == 2: - e = e + (1,1) - row, col, row_span, col_span = e + if not isinstance(e, (list, tuple)) or len(e) not in (2, 4) or not all(isinstance(ei, int) for ei in e): + raise Exception('Invalid GUI Hint entered: {e!r} (Must be a list of {{2,4}} non-negative integers).'.format(e=e)) - if not isinstance(e, (list, tuple)) or not (len(e) == 2 or len(e) == 4) or not all([isinstance(ei, int) for ei in e]): - raise Exception('Invalid GUI Hint entered: {e!s:s} (Must be a list of {{2,4}} non-negative integers).'.format(e=e)) + if len(e) == 2: + row, col = e + row_span = col_span = 1 + else: + row, col, row_span, col_span = e if (row < 0) or (col < 0): - raise Exception('Invalid GUI Hint entered: {e!s:s} (non-negative integers only).'.format(e=e)) + raise Exception('Invalid GUI Hint entered: {e!r} (non-negative integers only).'.format(e=e)) if (row_span < 1) or (col_span < 1): - raise Exception('Invalid GUI Hint entered: {e!s:s} (positive row/column span required).'.format(e=e)) + raise Exception('Invalid GUI Hint entered: {e!r} (positive row/column span required).'.format(e=e)) - if tab_set: - enabled_blocks = self.get_parent().get_parent().get_enabled_blocks() - tab_list = filter(lambda block: str(block.get_key()) == 'qtgui_tab_widget', enabled_blocks) - tab_match = filter(lambda t: t.get_id() == tab, tab_list) - if not tab_match: - raise Exception('Invalid tab name entered: {tab!s:s} (Tab name not found).'.format(tab=tab)) + return row, col, row_span, col_span - tab_index_size = int(tab_match[0].get_param('num_tabs').get_value()) - if index >= tab_index_size: - raise Exception('Invalid tab index entered: {tab!s:s}@{index!s:s} (Index out of range).'.format(tab=tab, - index=index)) + def validate_tab(): + enabled_blocks = self.get_parent().get_parent().iter_enabled_blocks() + tabs = (block for block in enabled_blocks + if block.get_key() == 'qtgui_tab_widget' and block.get_id() == tab) + tab_block = next(iter(tabs), None) + if not tab_block: + raise Exception('Invalid tab name entered: {tab} (Tab name not found).'.format(tab=tab)) - # Code Generation - if position_set and tab_set: - widget_str = 'self.{tab:s}_grid_layout_{index!s:s}.addWidget({widget:s}, {e!s:s})' - widget_str += '\n[self.{tab:s}_grid_layout_{index!s:s}.setRowStretch(r,1) for r in range({fRow:d},{lRow:d})]' - widget_str += '\n[self.{tab:s}_grid_layout_{index!s:s}.setColumnStretch(c,1) for c in range({fCol:d},{lCol:d})]' - widget_str = widget_str.format(tab=tab, - index=index, - widget='%s', - e=str(e)[1:-1], - fRow=row, - lRow=(row + row_span), - fCol=col, - lCol=(col + col_span)) - - elif position_set and not tab_set: - widget_str = 'self.top_grid_layout.addWidget({widget:s}, {e!s:s})' - widget_str += '\n[self.top_grid_layout.setRowStretch(r,1) for r in range({fRow:d},{lRow:d})]' - widget_str += '\n[self.top_grid_layout.setColumnStretch(c,1) for c in range({fCol:d},{lCol:d})]' - widget_str = widget_str.format(widget='%s', - e=str(e)[1:-1], - fRow=row, - lRow=(row + row_span), - fCol=col, - lCol=(col + col_span)) - - elif not position_set and tab_set: - widget_str = 'self.{tab:s}_layout_{index!s:s}.addWidget({widget:s})' - widget_str = widget_str.format(tab=tab, - index=index, - widget='%s') - - elif not position_set and not tab_set: - widget_str = 'self.top_layout.addWidget({widget:s})' - widget_str = widget_str.format(widget='%s') + tab_index_size = int(tab_block.get_param('num_tabs').get_value()) + if index >= tab_index_size: + raise Exception('Invalid tab index entered: {tab}@{index} (Index out of range).'.format( + tab=tab, index=index)) # Collision Detection - if position_set: - if tab_set: - my_parent = '{tab:s}@{index!s:s}'.format(tab=tab, - index=index) - else: - my_parent = 'main' + def collision_detection(row, col, row_span, col_span): + my_parent = '{tab}@{index}'.format(tab=tab, index=index) if tab else 'main' # Calculate hostage cells for r in range(row, row + row_span): for c in range(col, col + col_span): - self._hostage_cells.append((my_parent, (r, c))) - # Avoid collisions - params = filter(lambda p: p is not self, self.get_all_params('gui_hint')) - for param in params: - for parent, cell in param._hostage_cells: - if (parent, cell) in self._hostage_cells: - raise Exception('Another graphical element is using parent "{parent!s:s}", cell "{cell!s:s}".'.format(parent=parent, - cell=cell)) + self.hostage_cells.add((my_parent, (r, c))) + + for other in self.get_all_params('gui_hint'): + if other is self: + continue + collision = next(iter(self.hostage_cells & other.hostage_cells), None) + if collision: + raise Exception('Block {block!r} is also using parent {parent!r}, cell {cell!r}.'.format( + block=other.get_parent().get_id(), parent=collision[0], cell=collision[1] + )) + + # Code Generation + if tab: + validate_tab() + layout = '{tab}_grid_layout_{index}'.format(tab=tab, index=index) + else: + layout = 'top_grid_layout' + + widget = '%s' # to be fill-out in the mail template + + if pos: + row, col, row_span, col_span = parse_pos() + collision_detection(row, col, row_span, col_span) + + widget_str = textwrap.dedent(""" + self.{layout}.addWidget({widget}, {row}, {col}, {row_span}, {col_span}) + for r in range({row}, {row_end}): + self.{layout}.setRowStretch(r, 1) + for c in range({col}, {col_end}): + self.{layout}.setColumnStretch(c, 1) + """.strip('\n')).format( + layout=layout, widget=widget, + row=row, row_span=row_span, row_end=row+row_span, + col=col, col_span=col_span, col_end=col+col_span, + ) + + else: + widget_str = 'self.{layout}.addWidget({widget})'.format(layout=layout, widget=widget) - return widget_str \ No newline at end of file + return widget_str -- cgit v1.2.3