commit-gnuradio
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Commit-gnuradio] [gnuradio] 04/10: grc: Added ability to bypass blocks


From: git
Subject: [Commit-gnuradio] [gnuradio] 04/10: grc: Added ability to bypass blocks (Suggested by Chris Headley).
Date: Sun, 14 Jun 2015 16:34:15 +0000 (UTC)

This is an automated email from the git hooks/post-receive script.

jcorgan pushed a commit to branch master
in repository gnuradio.

commit 91dd2fce59ba81d4dc22b9dcdc909211cafe9f5f
Author: Seth Hitefield <address@hidden>
Date:   Wed Jun 10 16:04:51 2015 -0400

    grc: Added ability to bypass blocks (Suggested by Chris Headley).
    
    Only for blocks that have a single source and sink of the same type.
    Feature can be disabled per block using the 'disable_bypass' flag in the 
block definition.
---
 grc/base/Block.py        | 86 ++++++++++++++++++++++++++++++++++++++++++++----
 grc/base/Constants.py    |  6 ++++
 grc/base/FlowGraph.py    | 50 ++++++++++++++++++++++++----
 grc/gui/ActionHandler.py | 42 +++++++++++++++--------
 grc/gui/Actions.py       |  6 ++++
 grc/gui/Bars.py          |  3 ++
 grc/gui/Block.py         |  2 ++
 grc/gui/Colors.py        |  1 +
 grc/gui/FlowGraph.py     | 18 ++++++++--
 grc/python/Generator.py  |  2 +-
 10 files changed, 186 insertions(+), 30 deletions(-)

diff --git a/grc/base/Block.py b/grc/base/Block.py
index d2d7ebf..5e8a717 100644
--- a/grc/base/Block.py
+++ b/grc/base/Block.py
@@ -18,7 +18,9 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 
 02110-1301, USA
 """
 
 from . import odict
-from . Constants import ADVANCED_PARAM_TAB, DEFAULT_PARAM_TAB, 
BLOCK_FLAG_THROTTLE
+from . Constants import ADVANCED_PARAM_TAB, DEFAULT_PARAM_TAB
+from . Constants import BLOCK_FLAG_THROTTLE, BLOCK_FLAG_DISABLE_BYPASS
+from . Constants import BLOCK_ENABLED, BLOCK_BYPASSED, BLOCK_DISABLED
 from Element import Element
 
 from Cheetah.Template import Template
@@ -82,7 +84,8 @@ class Block(Element):
         self._key = n.find('key')
         self._category = n.find('category') or ''
         self._flags = n.find('flags') or ''
-        if n.find('throttle') and BLOCK_FLAG_THROTTLE not in self._flags:  # 
backwards-compatibility
+        # Backwards compatibility
+        if n.find('throttle') and BLOCK_FLAG_THROTTLE not in self._flags:
             self._flags += BLOCK_FLAG_THROTTLE
         self._grc_source = n.find('grc_source') or ''
         self._block_wrapper_path = n.find('block_wrapper_path')
@@ -154,6 +157,10 @@ class Block(Element):
                                      and (self._key != "pad_sink"))
         is_variable = self._key.startswith('variable')
 
+        # Disable blocks that are virtual/pads or variables
+        if not is_not_virtual_or_pad or is_variable:
+            self._flags += BLOCK_FLAG_DISABLE_BYPASS
+
         if is_not_virtual_or_pad and not is_variable:
             self.get_params().append(self.get_parent().get_parent().Param(
                 block=self,
@@ -208,7 +215,6 @@ class Block(Element):
                          })
                 ))
 
-
     def back_ofthe_bus(self, portlist):
         portlist.sort(key=lambda p: p._type == 'bus')
 
@@ -216,6 +222,35 @@ class Block(Element):
         buslist = [p for p in ports if p._type == 'bus']
         return buslist or ports
 
+    # Main functions to get and set the block state
+    # Also kept get_enabled and set_enabled to keep compatibility
+    def get_state(self):
+        """
+        Gets the block's current state.
+
+        Returns:
+            ENABLED - 0
+            BYPASSED - 1
+            DISABLED - 2
+        """
+        try: return int(eval(self.get_param('_enabled').get_value()))
+        except: return BLOCK_ENABLED
+
+    def set_state(self, state):
+        """
+        Sets the state for the block.
+
+        Args:
+            ENABLED - 0
+            BYPASSED - 1
+            DISABLED - 2
+        """
+        if state in [BLOCK_ENABLED, BLOCK_BYPASSED, BLOCK_DISABLED]:
+            self.get_param('_enabled').set_value(str(state))
+        else:
+            self.get_param('_enabled').set_value(str(BLOCK_ENABLED))
+
+    # Enable/Disable Aliases
     def get_enabled(self):
         """
         Get the enabled state of the block.
@@ -223,8 +258,7 @@ class Block(Element):
         Returns:
             true for enabled
         """
-        try: return eval(self.get_param('_enabled').get_value())
-        except: return True
+        return not (self.get_state() == BLOCK_DISABLED)
 
     def set_enabled(self, enabled):
         """
@@ -232,8 +266,45 @@ class Block(Element):
 
         Args:
             enabled: true for enabled
+
+        Returns:
+            True if block changed state
+        """
+        old_state = self.get_state()
+        new_state = BLOCK_ENABLED if enabled else BLOCK_DISABLED
+        self.set_state(new_state)
+        return old_state != new_state
+
+    # Block bypassing
+    def get_bypassed(self):
+        """
+        Check if the block is bypassed
+        """
+        return self.get_state() == BLOCK_BYPASSED
+
+    def set_bypassed(self):
+        """
+        Bypass the block
+
+        Returns:
+            True if block chagnes state
         """
-        self.get_param('_enabled').set_value(str(enabled))
+        if self.get_state() != BLOCK_BYPASSED and self.can_bypass():
+            self.set_state(BLOCK_BYPASSED)
+            return True
+        return False
+
+    def can_bypass(self):
+        """ Check the number of sinks and sources and see if this block can be 
bypassed """
+        # Check to make sure this is a single path block
+        # Could possibly support 1 to many blocks
+        if len(self.get_sources()) != 1 or len(self.get_sinks()) != 1:
+            return False
+        if not (self.get_sources()[0].get_type() == 
self.get_sinks()[0].get_type()):
+            return False
+        if self.bypass_disabled():
+            return False
+        return True
 
     def __str__(self): return 'Block - %s - %s(%s)'%(self.get_id(), 
self.get_name(), self.get_key())
 
@@ -252,7 +323,8 @@ class Block(Element):
     def get_comment(self): return self.get_param('comment').get_value()
 
     def get_flags(self): return self._flags
-    def throttle(self): return "throttle" in self._flags
+    def throtteling(self): return BLOCK_FLAG_THROTTLE in self._flags
+    def bypass_disabled(self): return BLOCK_FLAG_DISABLE_BYPASS in self._flags
 
     ##############################################
     # Access Params
diff --git a/grc/base/Constants.py b/grc/base/Constants.py
index 7949708..0c5116c 100644
--- a/grc/base/Constants.py
+++ b/grc/base/Constants.py
@@ -40,3 +40,9 @@ GR_MESSAGE_DOMAIN = "gr_message"
 DEFAULT_DOMAIN = GR_STREAM_DOMAIN
 
 BLOCK_FLAG_THROTTLE = 'throttle'
+BLOCK_FLAG_DISABLE_BYPASS = 'disable_bypass'
+
+# Block States
+BLOCK_DISABLED = 0
+BLOCK_ENABLED = 1
+BLOCK_BYPASSED = 2
diff --git a/grc/base/FlowGraph.py b/grc/base/FlowGraph.py
index 790aed0..7fd8df5 100644
--- a/grc/base/FlowGraph.py
+++ b/grc/base/FlowGraph.py
@@ -78,9 +78,6 @@ class FlowGraph(Element):
                         bus_structure = block.form_bus_structure('sink');
 
                     if 'bus' in map(lambda a: a.get_type(), get_p_gui()):
-
-
-
                         if len(get_p_gui()) > len(bus_structure):
                             times = range(len(bus_structure), 
len(get_p_gui()));
                             for i in times:
@@ -100,8 +97,6 @@ class FlowGraph(Element):
                                 port = 
block.get_parent().get_parent().Port(block=block, n=n, dir=direc);
                                 get_p().append(port);
 
-
-
         for child in self.get_children(): child.rewrite()
         refactor_bus_structure();
 
@@ -159,6 +154,15 @@ class FlowGraph(Element):
         """
         return filter(lambda b: b.get_enabled(), self.get_blocks())
 
+    def get_bypassed_blocks(self):
+        """
+        Get a list of all blocks that are bypassed.
+
+        Returns:
+            a list of blocks
+        """
+        return filter(lambda b: b.get_bypassed(), self.get_blocks())
+
     def get_enabled_connections(self):
         """
         Get a list of all connections that are enabled.
@@ -166,7 +170,41 @@ class FlowGraph(Element):
         Returns:
             a list of connections
         """
-        return filter(lambda c: c.get_enabled(), self.get_connections())
+        # First get all the enabled connections, then get the bypassed blocks.
+        connections = filter(lambda c: c.get_enabled(), self.get_connections())
+        bypassed_blocks = self.get_bypassed_blocks()
+
+        # Bypassing blocks: Need to find all the enabled connections for the 
block using
+        # the *connections* object rather than get_connections(). Create new 
connections
+        # that bypass the selected block and remove the existing ones. This 
allows adjacent
+        # bypassed blocks to see the newly created connections to downstream 
blocks,
+        # allowing them to correctly construct bypass connections.
+
+        for block in bypassed_blocks:
+            # Get the upstream connection (off of the sink ports)
+            # Use *connections* not get_connections()
+            get_source_connection = lambda c: c.get_sink() == 
block.get_sinks()[0]
+            source_connection = filter(get_source_connection, connections)
+            # The source connection should never have more than one element.
+            assert (len(source_connection) == 1)
+
+            # Get the source of the connection.
+            source_port = source_connection[0].get_source()
+
+            # Loop through all the downstream connections
+            get_sink_connections = lambda c: c.get_source() == 
block.get_sources()[0]
+            for sink in filter(get_sink_connections, connections):
+                if not sink.get_enabled():
+                    # Ignore disabled connections
+                    continue
+                sink_port = sink.get_sink()
+                connection = self.get_parent().Connection(flow_graph=self, 
porta=source_port, portb=sink_port)
+                connections.append(connection)
+                # Remove this sink connection
+                connections.remove(sink)
+            # Remove the source connection
+            connections.remove(source_connection[0])
+        return connections
 
     def get_new_block(self, key):
         """
diff --git a/grc/gui/ActionHandler.py b/grc/gui/ActionHandler.py
index fee9662..1ce4aed 100644
--- a/grc/gui/ActionHandler.py
+++ b/grc/gui/ActionHandler.py
@@ -29,7 +29,7 @@ import subprocess
 import Preferences
 from threading import Thread
 import Messages
-from .. base import ParseXML
+from .. base import ParseXML, Constants
 from MainWindow import MainWindow
 from PropsDialog import PropsDialog
 from ParserErrorsDialog import ParserErrorsDialog
@@ -171,6 +171,11 @@ class ActionHandler:
                 self.get_flow_graph().update()
                 
self.get_page().get_state_cache().save_new_state(self.get_flow_graph().export_data())
                 self.get_page().set_saved(False)
+        elif action == Actions.BLOCK_BYPASS:
+            if self.get_flow_graph().bypass_selected():
+                self.get_flow_graph().update()
+                
self.get_page().get_state_cache().save_new_state(self.get_flow_graph().export_data())
+                self.get_page().set_saved(False)
         ##################################################
         # Cut/Copy/Paste
         ##################################################
@@ -553,23 +558,34 @@ class ActionHandler:
         ##################################################
         # Global Actions for all States
         ##################################################
+        selected_block = self.get_flow_graph().get_selected_block()
+        selected_blocks = self.get_flow_graph().get_selected_blocks()
+
         #update general buttons
         Actions.ERRORS_WINDOW_DISPLAY.set_sensitive(not 
self.get_flow_graph().is_valid())
         
Actions.ELEMENT_DELETE.set_sensitive(bool(self.get_flow_graph().get_selected_elements()))
-        
Actions.BLOCK_PARAM_MODIFY.set_sensitive(bool(self.get_flow_graph().get_selected_block()))
-        
Actions.BLOCK_ROTATE_CCW.set_sensitive(bool(self.get_flow_graph().get_selected_blocks()))
-        
Actions.BLOCK_ROTATE_CW.set_sensitive(bool(self.get_flow_graph().get_selected_blocks()))
+        Actions.BLOCK_PARAM_MODIFY.set_sensitive(bool(selected_block))
+        Actions.BLOCK_ROTATE_CCW.set_sensitive(bool(selected_blocks))
+        Actions.BLOCK_ROTATE_CW.set_sensitive(bool(selected_blocks))
         #update cut/copy/paste
-        
Actions.BLOCK_CUT.set_sensitive(bool(self.get_flow_graph().get_selected_blocks()))
-        
Actions.BLOCK_COPY.set_sensitive(bool(self.get_flow_graph().get_selected_blocks()))
+        Actions.BLOCK_CUT.set_sensitive(bool(selected_blocks))
+        Actions.BLOCK_COPY.set_sensitive(bool(selected_blocks))
         Actions.BLOCK_PASTE.set_sensitive(bool(self.clipboard))
-        #update enable/disable
-        
Actions.BLOCK_ENABLE.set_sensitive(bool(self.get_flow_graph().get_selected_blocks()))
-        
Actions.BLOCK_DISABLE.set_sensitive(bool(self.get_flow_graph().get_selected_blocks()))
-        
Actions.BLOCK_CREATE_HIER.set_sensitive(bool(self.get_flow_graph().get_selected_blocks()))
-        
Actions.OPEN_HIER.set_sensitive(bool(self.get_flow_graph().get_selected_blocks()))
-        
Actions.BUSSIFY_SOURCES.set_sensitive(bool(self.get_flow_graph().get_selected_blocks()))
-        
Actions.BUSSIFY_SINKS.set_sensitive(bool(self.get_flow_graph().get_selected_blocks()))
+        #update enable/disable/bypass
+        can_enable = any(block.get_state() != Constants.BLOCK_ENABLED
+                         for block in selected_blocks)
+        can_disable = any(block.get_state() != Constants.BLOCK_DISABLED
+                          for block in selected_blocks)
+        can_bypass_all = all(block.can_bypass() for block in selected_blocks) \
+                          and any (not block.get_bypassed() for block in 
selected_blocks)
+        Actions.BLOCK_ENABLE.set_sensitive(can_enable)
+        Actions.BLOCK_DISABLE.set_sensitive(can_disable)
+        Actions.BLOCK_BYPASS.set_sensitive(can_bypass_all)
+
+        Actions.BLOCK_CREATE_HIER.set_sensitive(bool(selected_blocks))
+        Actions.OPEN_HIER.set_sensitive(bool(selected_blocks))
+        Actions.BUSSIFY_SOURCES.set_sensitive(bool(selected_blocks))
+        Actions.BUSSIFY_SINKS.set_sensitive(bool(selected_blocks))
         Actions.RELOAD_BLOCKS.set_sensitive(True)
         Actions.FIND_BLOCKS.set_sensitive(True)
         #set the exec and stop buttons
diff --git a/grc/gui/Actions.py b/grc/gui/Actions.py
index b2b3a76..a028a33 100644
--- a/grc/gui/Actions.py
+++ b/grc/gui/Actions.py
@@ -247,6 +247,12 @@ BLOCK_DISABLE = Action(
     stock_id=gtk.STOCK_DISCONNECT,
     keypresses=(gtk.keysyms.d, NO_MODS_MASK),
 )
+BLOCK_BYPASS = Action(
+    label='_Bypass',
+    tooltip='Bypass the selected block',
+    stock_id=gtk.STOCK_MEDIA_FORWARD,
+    keypresses=(gtk.keysyms.b, NO_MODS_MASK),
+)
 TOGGLE_SNAP_TO_GRID = ToggleAction(
     label='_Snap to grid',
     tooltip='Snap blocks to a grid for an easier connection alignment',
diff --git a/grc/gui/Bars.py b/grc/gui/Bars.py
index 40ce205..abcc3c6 100644
--- a/grc/gui/Bars.py
+++ b/grc/gui/Bars.py
@@ -49,6 +49,7 @@ TOOLBAR_LIST = (
     None,
     Actions.BLOCK_ENABLE,
     Actions.BLOCK_DISABLE,
+    Actions.BLOCK_BYPASS,
     Actions.TOGGLE_HIDE_DISABLED_BLOCKS,
     None,
     Actions.FIND_BLOCKS,
@@ -85,6 +86,7 @@ MENU_BAR_LIST = (
         None,
         Actions.BLOCK_ENABLE,
         Actions.BLOCK_DISABLE,
+        Actions.BLOCK_BYPASS,
         None,
         Actions.BLOCK_PARAM_MODIFY,
     ]),
@@ -134,6 +136,7 @@ CONTEXT_MENU_LIST = [
     Actions.BLOCK_ROTATE_CW,
     Actions.BLOCK_ENABLE,
     Actions.BLOCK_DISABLE,
+    Actions.BLOCK_BYPASS,
     None,
     (gtk.Action('More', '_More', None, None), [
         Actions.BLOCK_CREATE_HIER,
diff --git a/grc/gui/Block.py b/grc/gui/Block.py
index 60f19fc..83706ed 100644
--- a/grc/gui/Block.py
+++ b/grc/gui/Block.py
@@ -145,7 +145,9 @@ class Block(Element):
         """Create the labels for the signal block."""
         Element.create_labels(self)
         self._bg_color = self.is_dummy_block() and 
Colors.MISSING_BLOCK_BACKGROUND_COLOR or \
+                         self.get_bypassed() and Colors.BLOCK_BYPASSED_COLOR 
or \
                          self.get_enabled() and Colors.BLOCK_ENABLED_COLOR or 
Colors.BLOCK_DISABLED_COLOR
+
         layouts = list()
         #create the main layout
         layout = gtk.DrawingArea().create_pango_layout('')
diff --git a/grc/gui/Colors.py b/grc/gui/Colors.py
index f64106b..52c95e8 100644
--- a/grc/gui/Colors.py
+++ b/grc/gui/Colors.py
@@ -38,6 +38,7 @@ try:
     #block color constants
     BLOCK_ENABLED_COLOR = get_color('#F1ECFF')
     BLOCK_DISABLED_COLOR = get_color('#CCCCCC')
+    BLOCK_BYPASSED_COLOR = get_color('#FFFFE6')
     #connection color constants
     CONNECTION_ENABLED_COLOR = get_color('black')
     CONNECTION_DISABLED_COLOR = get_color('#BBBBBB')
diff --git a/grc/gui/FlowGraph.py b/grc/gui/FlowGraph.py
index 97f814f..bf6e1ee 100644
--- a/grc/gui/FlowGraph.py
+++ b/grc/gui/FlowGraph.py
@@ -211,9 +211,21 @@ class FlowGraph(Element):
         """
         changed = False
         for selected_block in self.get_selected_blocks():
-            if selected_block.get_enabled() != enable:
-                selected_block.set_enabled(enable)
-                changed = True
+            if selected_block.set_enabled(enable): changed = True
+        return changed
+
+    def bypass_selected(self):
+        """
+        Bypass the selected blocks.
+
+        Args:
+            None
+        Returns:
+            true if changed
+        """
+        changed = False
+        for selected_block in self.get_selected_blocks():
+            if selected_block.set_bypassed(): changed = True
         return changed
 
     def move_selected(self, delta_coordinate):
diff --git a/grc/python/Generator.py b/grc/python/Generator.py
index a3f9f10..d9e92cd 100644
--- a/grc/python/Generator.py
+++ b/grc/python/Generator.py
@@ -86,7 +86,7 @@ class TopBlockGenerator(object):
     def write(self):
         """generate output and write it to files"""
         # do throttle warning
-        throttling_blocks = filter(lambda b: b.throttle(), 
self._flow_graph.get_enabled_blocks())
+        throttling_blocks = filter(lambda b: b.throtteling(), 
self._flow_graph.get_enabled_blocks())
         if not throttling_blocks and self._generate_options != 'hb':
             Messages.send_warning("This flow graph may not have flow control: "
                                   "no audio or RF hardware blocks found. "



reply via email to

[Prev in Thread] Current Thread [Next in Thread]