summaryrefslogtreecommitdiff
path: root/grc
diff options
context:
space:
mode:
Diffstat (limited to 'grc')
-rw-r--r--grc/base/Block.py98
-rw-r--r--grc/base/Constants.py10
-rw-r--r--grc/base/FlowGraph.py68
-rw-r--r--grc/base/Param.py2
-rw-r--r--grc/blocks/.gitignore1
-rw-r--r--grc/blocks/CMakeLists.txt22
-rw-r--r--grc/blocks/options.xml22
-rw-r--r--grc/blocks/variable_struct.xml.py98
-rw-r--r--grc/grc.conf.in2
-rw-r--r--grc/gui/ActionHandler.py52
-rw-r--r--grc/gui/Actions.py37
-rw-r--r--grc/gui/Bars.py5
-rw-r--r--grc/gui/Block.py24
-rw-r--r--grc/gui/Colors.py1
-rw-r--r--grc/gui/Constants.py74
-rw-r--r--grc/gui/FlowGraph.py18
-rw-r--r--grc/gui/Platform.py2
-rw-r--r--grc/gui/Port.py46
-rw-r--r--grc/gui/Preferences.py98
-rw-r--r--grc/gui/PropsDialog.py58
-rw-r--r--grc/python/Block.py43
-rw-r--r--grc/python/Constants.py66
-rw-r--r--grc/python/FlowGraph.py1
-rw-r--r--grc/python/Generator.py39
-rw-r--r--grc/python/Port.py13
-rw-r--r--grc/python/block.dtd5
-rw-r--r--grc/python/default_flow_graph.grc4
-rw-r--r--grc/python/flow_graph.tmpl33
-rwxr-xr-xgrc/scripts/gnuradio-companion9
29 files changed, 727 insertions, 224 deletions
diff --git a/grc/base/Block.py b/grc/base/Block.py
index afe326bbf4..5e8a7179ac 100644
--- a/grc/base/Block.py
+++ b/grc/base/Block.py
@@ -19,12 +19,17 @@ 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 . 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
from UserDict import UserDict
from itertools import imap
+from .. gui import Messages
+
+
class TemplateArg(UserDict):
"""
A cheetah template argument created from a param.
@@ -46,11 +51,16 @@ class TemplateArg(UserDict):
def __call__(self):
return self._param.get_evaluated()
-def _get_keys(lst): return [elem.get_key() for elem in lst]
+
+def _get_keys(lst):
+ return [elem.get_key() for elem in lst]
+
+
def _get_elem(lst, key):
try: return lst[_get_keys(lst).index(key)]
except ValueError: raise ValueError, 'Key "%s" not found in %s.'%(key, _get_keys(lst))
+
class Block(Element):
def __init__(self, flow_graph, n):
@@ -73,6 +83,10 @@ class Block(Element):
self._name = n.find('name')
self._key = n.find('key')
self._category = n.find('category') or ''
+ self._flags = n.find('flags') or ''
+ # 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')
self._bussify_sink = n.find('bus_sink')
@@ -143,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,
@@ -197,7 +215,6 @@ class Block(Element):
})
))
-
def back_ofthe_bus(self, portlist):
portlist.sort(key=lambda p: p._type == 'bus')
@@ -205,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.
@@ -212,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):
"""
@@ -221,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
"""
- self.get_param('_enabled').set_value(str(enabled))
+ return self.get_state() == BLOCK_BYPASSED
+
+ def set_bypassed(self):
+ """
+ Bypass the block
+
+ Returns:
+ True if block chagnes state
+ """
+ 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())
@@ -240,6 +322,10 @@ class Block(Element):
def get_block_wrapper_path(self): return self._block_wrapper_path
def get_comment(self): return self.get_param('comment').get_value()
+ def get_flags(self): return 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
##############################################
@@ -414,7 +500,7 @@ class Block(Element):
"""
n = odict()
n['key'] = self.get_key()
- n['param'] = map(lambda p: p.export_data(), self.get_params())
+ n['param'] = map(lambda p: p.export_data(), sorted(self.get_params(), key=str))
if 'bus' in map(lambda a: a.get_type(), self.get_sinks()):
n['bus_sink'] = str(1);
if 'bus' in map(lambda a: a.get_type(), self.get_sources()):
diff --git a/grc/base/Constants.py b/grc/base/Constants.py
index efae0ecbb5..1e83de63b5 100644
--- a/grc/base/Constants.py
+++ b/grc/base/Constants.py
@@ -38,3 +38,13 @@ DOMAIN_DTD = os.path.join(DATA_DIR, 'domain.dtd')
GR_STREAM_DOMAIN = "gr_stream"
GR_MESSAGE_DOMAIN = "gr_message"
DEFAULT_DOMAIN = GR_STREAM_DOMAIN
+
+BLOCK_FLAG_THROTTLE = 'throttle'
+BLOCK_FLAG_DISABLE_BYPASS = 'disable_bypass'
+BLOCK_FLAG_NEED_QT_GUI = 'need_qt_gui'
+BLOCK_FLAG_NEED_WX_GUI = 'need_ex_gui'
+
+# Block States
+BLOCK_DISABLED = 0
+BLOCK_ENABLED = 1
+BLOCK_BYPASSED = 2
diff --git a/grc/base/FlowGraph.py b/grc/base/FlowGraph.py
index fb25b46821..7fd8df5f64 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();
@@ -126,13 +121,13 @@ class FlowGraph(Element):
def get_block(self, id): return filter(lambda b: b.get_id() == id, self.get_blocks())[0]
def get_blocks_unordered(self): return filter(lambda e: e.is_block(), self.get_elements())
def get_blocks(self):
- blocks = self.get_blocks_unordered();
- for i in range(len(blocks)):
- if blocks[i].get_key() == 'variable':
- blk = blocks[i];
- blocks.remove(blk);
- blocks.insert(1, blk);
- return blocks;
+ # refactored the slow, ugly version
+ # don't know why we need this here, using it for sorted export_data()
+ return sorted(self.get_blocks_unordered(), key=lambda b: (
+ b.get_key() != 'options', # options to the front
+ not b.get_key().startswith('variable'), # then vars
+ str(b)
+ ))
def get_connections(self): return filter(lambda e: e.is_connection(), self.get_elements())
def get_children(self): return self.get_elements()
def get_elements(self):
@@ -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):
"""
@@ -250,8 +288,8 @@ class FlowGraph(Element):
"""
n = odict()
n['timestamp'] = self._timestamp
- n['block'] = [block.export_data() for block in self.get_blocks()]
- n['connection'] = [connection.export_data() for connection in self.get_connections()]
+ n['block'] = [b.export_data() for b in self.get_blocks()] # already sorted
+ n['connection'] = [c.export_data() for c in sorted(self.get_connections(), key=str)]
instructions = odict({
'created': self.get_parent().get_version_short(),
'format': FLOW_GRAPH_FILE_FORMAT_VERSION,
diff --git a/grc/base/Param.py b/grc/base/Param.py
index 94be8b0fe0..c2f413ccbe 100644
--- a/grc/base/Param.py
+++ b/grc/base/Param.py
@@ -140,7 +140,7 @@ class Param(Element):
def get_color(self): return '#FFFFFF'
def __str__(self): return 'Param - %s(%s)'%(self.get_name(), self.get_key())
def is_param(self): return True
- def get_name(self): return self._name
+ def get_name(self): return self.get_parent().resolve_dependencies(self._name).strip()
def get_key(self): return self._key
def get_hide(self): return self.get_parent().resolve_dependencies(self._hide).strip()
diff --git a/grc/blocks/.gitignore b/grc/blocks/.gitignore
new file mode 100644
index 0000000000..2ac4a79e69
--- /dev/null
+++ b/grc/blocks/.gitignore
@@ -0,0 +1 @@
+variable_struct.xml
diff --git a/grc/blocks/CMakeLists.txt b/grc/blocks/CMakeLists.txt
index 98b6512a09..0c2a1f7901 100644
--- a/grc/blocks/CMakeLists.txt
+++ b/grc/blocks/CMakeLists.txt
@@ -18,6 +18,26 @@
# Boston, MA 02110-1301, USA.
########################################################################
+include(GrPython)
+
file(GLOB xml_files "*.xml")
-install(FILES ${xml_files} DESTINATION ${GRC_BLOCKS_DIR} COMPONENT "grc")
+macro(GEN_BLOCK_XML _generator _xml_block)
+ set(generator ${CMAKE_CURRENT_SOURCE_DIR}/${_generator})
+ set(xml_block ${CMAKE_CURRENT_BINARY_DIR}/${_xml_block})
+ list(APPEND generated_xml_files ${xml_block})
+ add_custom_command(
+ DEPENDS ${generator} OUTPUT ${xml_block}
+ COMMAND ${PYTHON_EXECUTABLE} ${generator} ${xml_block}
+ )
+endmacro(GEN_BLOCK_XML)
+
+GEN_BLOCK_XML(variable_struct.xml.py variable_struct.xml)
+
+add_custom_target(grc_generated_xml ALL DEPENDS ${generated_xml_files})
+
+install(
+ FILES ${xml_files} ${generated_xml_files}
+ DESTINATION ${GRC_BLOCKS_DIR}
+ COMPONENT "grc"
+)
diff --git a/grc/blocks/options.xml b/grc/blocks/options.xml
index 6588dc72d0..dc02b83c2a 100644
--- a/grc/blocks/options.xml
+++ b/grc/blocks/options.xml
@@ -19,7 +19,7 @@ import wx
from PyQt4 import Qt
import sys
#end if
-#if $generate_options() != 'hb'
+#if not $generate_options().startswith('hb')
from optparse import OptionParser
from gnuradio.eng_option import eng_option
from gnuradio import eng_notation
@@ -49,9 +49,9 @@ else: self.stop(); self.wait()</callback>
<hide>#if $description() then 'none' else 'part'#</hide>
</param>
<param>
- <name>Window Size</name>
+ <name>Canvas Size</name>
<key>window_size</key>
- <value>1280, 1024</value>
+ <value></value>
<type>int_vector</type>
<hide>part</hide>
</param>
@@ -76,13 +76,17 @@ else: self.stop(); self.wait()</callback>
<name>Hier Block</name>
<key>hb</key>
</option>
+ <option>
+ <name>QT GUI Hier Block</name>
+ <key>hb_qt_gui</key>
+ </option>
</param>
<param>
<name>Category</name>
<key>category</key>
<value>Custom</value>
<type>string</type>
- <hide>#if $generate_options() == 'hb' then 'none' else 'all'#</hide>
+ <hide>#if $generate_options().startswith('hb') then 'none' else 'all'#</hide>
</param>
<param>
<name>Run Options</name>
@@ -129,7 +133,7 @@ else: self.stop(); self.wait()</callback>
<key>max_nouts</key>
<value>0</value>
<type>int</type>
- <hide>#if $generate_options() == 'hb'
+ <hide>#if $generate_options().startswith('hb')
all#slurp
#elif $max_nouts()
none#slurp
@@ -142,7 +146,7 @@ part#slurp
<key>realtime_scheduling</key>
<value></value>
<type>enum</type>
- <hide>#if $generate_options() == 'hb'
+ <hide>#if $generate_options().startswith('hb')
all#slurp
#elif $realtime_scheduling()
none#slurp
@@ -174,9 +178,9 @@ part#slurp
</option>
<tab>Advanced</tab>
</param>
- <check>len($window_size) == 2</check>
- <check>300 &lt;= $(window_size)[0] &lt;= 4096</check>
- <check>300 &lt;= $(window_size)[1] &lt;= 4096</check>
+ <check>not $window_size or len($window_size) == 2</check>
+ <check>not $window_size or 300 &lt;= $(window_size)[0] &lt;= 4096</check>
+ <check>not $window_size or 300 &lt;= $(window_size)[1] &lt;= 4096</check>
<doc>
The options block sets special parameters for the flow graph. \
Only one option block is allowed per flow graph.
diff --git a/grc/blocks/variable_struct.xml.py b/grc/blocks/variable_struct.xml.py
new file mode 100644
index 0000000000..e43200828b
--- /dev/null
+++ b/grc/blocks/variable_struct.xml.py
@@ -0,0 +1,98 @@
+#!/usr/bin/env python
+
+MAX_NUM_FIELDS = 20
+
+HEADER = """\
+<block>
+ <name>Struct Variable</name>
+ <key>variable_struct</key>
+ <category>Variables</category>
+ <import>def struct(data): return type('Struct', (object,), data)()</import>
+ <var_make>self.$id = $id = struct({{#slurp
+#for $i in range({0}):
+#set $field = $getVar('field' + str(i))
+#if len(str($field)) > 2
+$field: $getVar('value' + str(i)), #slurp
+#end if
+#end for
+}})</var_make>
+ <var_value>struct({{#slurp
+#for $i in range({0}):
+#set $field = $getVar('field' + str(i))
+#if len(str($field)) > 2
+$field: $getVar('value' + str(i)), #slurp
+#end if
+#end for
+}})</var_value>
+ <make></make>
+"""
+
+FIELD0 = """\
+ <param>
+ <name>Field 0</name>
+ <key>field0</key>
+ <value>field0</value>
+ <type>string</type>
+ <hide>part</hide>
+ <tab>Fields</tab>
+ </param>
+"""
+
+FIELDS = """\
+ <param>
+ <name>Field {0}</name>
+ <key>field{0}</key>
+ <value></value>
+ <type>string</type>
+ <hide>part</hide>
+ <tab>Fields</tab>
+ </param>
+"""
+
+VALUES = """\
+ <param>
+ <name>$field{0}()</name>
+ <key>value{0}</key>
+ <value>0</value>
+ <type>raw</type>
+ <hide>#if $field{0}() then 'none' else 'all'#</hide>
+ </param>
+"""
+
+CHECKS = """\
+ <check>($str($field{0}) or "a")[0].isalpha()</check>
+ <check>($str($field{0}) or "a").isalnum()</check>
+"""
+
+FOOTER = """\
+ <doc>This is a simple struct/record like variable.
+
+Attribute/field names can be specified in the tab 'Fields'.
+For each non-empty field a parameter with type raw is shown.
+Value access via the dot operator, e.g. "variable_struct_0.field0"
+ </doc>
+</block>
+"""
+
+
+def make_xml(num_fields):
+ return ''.join((
+ HEADER.format(num_fields),
+ FIELD0, ''.join(FIELDS.format(i) for i in range(1, num_fields)),
+ ''.join(VALUES.format(i) for i in range(num_fields)),
+ ''.join(CHECKS.format(i) for i in range(num_fields)),
+ FOOTER
+ ))
+
+
+if __name__ == '__main__':
+ import sys
+ try:
+ filename = sys.argv[1]
+ except IndexError:
+ filename = __file__[:-3]
+
+ data = make_xml(MAX_NUM_FIELDS)
+
+ with open(filename, 'w') as fp:
+ fp.write(data.encode())
diff --git a/grc/grc.conf.in b/grc/grc.conf.in
index 99ae9caff5..71c4f63bca 100644
--- a/grc/grc.conf.in
+++ b/grc/grc.conf.in
@@ -6,3 +6,5 @@
global_blocks_path = @blocksdir@
local_blocks_path =
xterm_executable = @GRC_XTERM_EXE@
+canvas_font_size = 8
+canvas_default_size = 1280, 1024
diff --git a/grc/gui/ActionHandler.py b/grc/gui/ActionHandler.py
index fee96624bb..15565127e3 100644
--- a/grc/gui/ActionHandler.py
+++ b/grc/gui/ActionHandler.py
@@ -18,7 +18,6 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
"""
import os
-import signal
from Constants import IMAGE_FILE_EXTENSION
import Actions
import pygtk
@@ -29,15 +28,17 @@ 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
import Dialogs
from FileDialogs import OpenFlowGraphFileDialog, SaveFlowGraphFileDialog, SaveReportsFileDialog, SaveImageFileDialog
+from . Constants import DEFAULT_CANVAS_SIZE
gobject.threads_init()
+
class ActionHandler:
"""
The action handler will setup all the major window components,
@@ -124,6 +125,7 @@ class ActionHandler:
Actions.CLEAR_REPORTS, Actions.SAVE_REPORTS,
Actions.TOGGLE_AUTO_HIDE_PORT_LABELS, Actions.TOGGLE_SNAP_TO_GRID,
Actions.TOGGLE_SHOW_BLOCK_COMMENTS,
+ Actions.TOGGLE_SHOW_CODE_PREVIEW_TAB,
): action.set_sensitive(True)
if ParseXML.xml_failures:
Messages.send_xml_errors_if_any(ParseXML.xml_failures)
@@ -146,6 +148,7 @@ class ActionHandler:
Actions.TOGGLE_SCROLL_LOCK,
Actions.TOGGLE_SNAP_TO_GRID,
Actions.TOGGLE_SHOW_BLOCK_COMMENTS,
+ Actions.TOGGLE_SHOW_CODE_PREVIEW_TAB,
): action.load_from_preferences()
elif action == Actions.APPLICATION_QUIT:
if self.main_window.close_pages():
@@ -171,6 +174,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
##################################################
@@ -405,6 +413,8 @@ class ActionHandler:
action.save_to_preferences()
elif action == Actions.TOGGLE_SHOW_BLOCK_COMMENTS:
action.save_to_preferences()
+ elif action == Actions.TOGGLE_SHOW_CODE_PREVIEW_TAB:
+ action.save_to_preferences()
##################################################
# Param Modifications
##################################################
@@ -553,23 +563,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
@@ -578,7 +599,8 @@ class ActionHandler:
Actions.FLOW_GRAPH_SAVE.set_sensitive(not self.get_page().get_saved())
self.main_window.update()
try: #set the size of the flow graph area (if changed)
- new_size = self.get_flow_graph().get_option('window_size')
+ new_size = (self.get_flow_graph().get_option('window_size') or
+ DEFAULT_CANVAS_SIZE)
if self.get_flow_graph().get_size() != tuple(new_size):
self.get_flow_graph().set_size(*new_size)
except: pass
diff --git a/grc/gui/Actions.py b/grc/gui/Actions.py
index b2b3a76386..d864db7e16 100644
--- a/grc/gui/Actions.py
+++ b/grc/gui/Actions.py
@@ -106,7 +106,8 @@ class Action(gtk.Action, _ActionBase):
Pass additional arguments such as keypresses.
"""
- def __init__(self, keypresses=(), name=None, label=None, tooltip=None, stock_id=None):
+ def __init__(self, keypresses=(), name=None, label=None, tooltip=None,
+ stock_id=None):
"""
Create a new Action instance.
@@ -129,7 +130,8 @@ class ToggleAction(gtk.ToggleAction, _ActionBase):
Pass additional arguments such as keypresses.
"""
- def __init__(self, keypresses=(), name=None, label=None, tooltip=None, stock_id=None, preference_name=None):
+ def __init__(self, keypresses=(), name=None, label=None, tooltip=None,
+ stock_id=None, preference_name=None, default=True):
"""
Create a new ToggleAction instance.
@@ -137,22 +139,24 @@ class ToggleAction(gtk.ToggleAction, _ActionBase):
key_presses: a tuple of (keyval1, mod_mask1, keyval2, mod_mask2, ...)
the: regular gtk.Action parameters (defaults to None)
"""
- if name is None: name = label
+ if name is None:
+ name = label
gtk.ToggleAction.__init__(self,
- name=name, label=label,
- tooltip=tooltip, stock_id=stock_id,
+ name=name, label=label, tooltip=tooltip, stock_id=stock_id,
)
- #register this action
_ActionBase.__init__(self, label, keypresses)
self.preference_name = preference_name
+ self.default = default
def load_from_preferences(self):
if self.preference_name is not None:
- self.set_active(Preferences.bool_entry(self.preference_name))
+ self.set_active(Preferences.bool_entry(self.preference_name,
+ default=self.default))
def save_to_preferences(self):
if self.preference_name is not None:
- Preferences.bool_entry(self.preference_name, self.get_active())
+ Preferences.bool_entry(self.preference_name,
+ value=self.get_active())
########################################################################
# Actions
@@ -247,6 +251,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',
@@ -268,6 +278,13 @@ TOGGLE_SHOW_BLOCK_COMMENTS = ToggleAction(
tooltip="Show comment beneath each block",
preference_name='show_block_comments'
)
+TOGGLE_SHOW_CODE_PREVIEW_TAB = ToggleAction(
+ label='Generated Code Preview',
+ tooltip="Show a preview of the code generated for each Block in its "
+ "Properties Dialog",
+ preference_name='show_generated_code_tab',
+ default=False,
+)
BLOCK_CREATE_HIER = Action(
label='C_reate Hier',
tooltip='Create hier block from selected blocks',
@@ -298,13 +315,13 @@ ERRORS_WINDOW_DISPLAY = Action(
stock_id=gtk.STOCK_DIALOG_ERROR,
)
TOGGLE_REPORTS_WINDOW = ToggleAction(
- label='Show _Reports',
+ label='Show _Reports Panel',
tooltip='Toggle visibility of the Report widget',
keypresses=(gtk.keysyms.r, gtk.gdk.CONTROL_MASK),
preference_name='reports_window_visible'
)
TOGGLE_BLOCKS_WINDOW = ToggleAction(
- label='Show _Block Tree',
+ label='Show _Block Tree Panel',
tooltip='Toggle visibility of the block tree widget',
keypresses=(gtk.keysyms.b, gtk.gdk.CONTROL_MASK),
preference_name='blocks_window_visible'
diff --git a/grc/gui/Bars.py b/grc/gui/Bars.py
index 40ce20536c..f0f8dac7fb 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,
]),
@@ -101,6 +103,8 @@ MENU_BAR_LIST = (
Actions.TOGGLE_SNAP_TO_GRID,
Actions.TOGGLE_SHOW_BLOCK_COMMENTS,
None,
+ Actions.TOGGLE_SHOW_CODE_PREVIEW_TAB,
+ None,
Actions.ERRORS_WINDOW_DISPLAY,
Actions.FIND_BLOCKS,
]),
@@ -134,6 +138,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 60f19fc1a4..11273a537b 100644
--- a/grc/gui/Block.py
+++ b/grc/gui/Block.py
@@ -22,10 +22,10 @@ import Utils
import Colors
from .. base import odict
from Constants import BORDER_PROXIMITY_SENSITIVITY
-from Constants import \
- BLOCK_LABEL_PADDING, \
- PORT_SEPARATION, LABEL_SEPARATION, \
+from Constants import (
+ BLOCK_LABEL_PADDING, PORT_SPACING, PORT_SEPARATION, LABEL_SEPARATION,
PORT_BORDER_SEPARATION, POSSIBLE_ROTATIONS, BLOCK_FONT, PARAM_FONT
+)
import Actions
import pygtk
pygtk.require('2.0')
@@ -72,6 +72,7 @@ class Block(Element):
))
Element.__init__(self)
self._comment_pixmap = None
+ self.has_busses = [False, False] # source, sink
def get_coordinate(self):
"""
@@ -145,7 +146,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('')
@@ -188,13 +191,14 @@ class Block(Element):
self.vertical_label = self.get_parent().new_pixmap(height, width)
Utils.rotate_pixmap(gc, self.horizontal_label, self.vertical_label)
#calculate width and height needed
- self.W = self.label_width + 2*BLOCK_LABEL_PADDING
+ self.W = self.label_width + 2 * BLOCK_LABEL_PADDING
+
def get_min_height_for_ports():
visible_ports = filter(lambda p: not p.get_hide(), ports)
H = 2*PORT_BORDER_SEPARATION + len(visible_ports) * PORT_SEPARATION
if visible_ports: H -= ports[0].H
return H
- self.H = max(*(
+ self.H = max(
[ # labels
self.label_height + 2 * BLOCK_LABEL_PADDING
] +
@@ -202,11 +206,15 @@ class Block(Element):
get_min_height_for_ports() for ports in (self.get_sources_gui(), self.get_sinks_gui())
] +
[ # bus ports only
- 4 * PORT_BORDER_SEPARATION +
- sum([port.H + PORT_SEPARATION for port in ports if port.get_type() == 'bus']) - PORT_SEPARATION
+ 2 * PORT_BORDER_SEPARATION +
+ sum([port.H + PORT_SPACING for port in ports if port.get_type() == 'bus']) - PORT_SPACING
for ports in (self.get_sources_gui(), self.get_sinks_gui())
]
- ))
+ )
+ self.has_busses = [
+ any(port.get_type() == 'bus' for port in ports)
+ for ports in (self.get_sources_gui(), self.get_sinks_gui())
+ ]
self.create_comment_label()
def create_comment_label(self):
diff --git a/grc/gui/Colors.py b/grc/gui/Colors.py
index f64106b03f..52c95e8edf 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/Constants.py b/grc/gui/Constants.py
index 0dc6279fd2..a8395f631e 100644
--- a/grc/gui/Constants.py
+++ b/grc/gui/Constants.py
@@ -18,78 +18,104 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
"""
import pygtk
+
pygtk.require('2.0')
import gtk
import os
+import sys
+from gnuradio import gr
+
+_gr_prefs = gr.prefs()
+
-##default path for the open/save dialogs
+# default path for the open/save dialogs
DEFAULT_FILE_PATH = os.getcwd()
-##file extensions
+# file extensions
IMAGE_FILE_EXTENSION = '.png'
TEXT_FILE_EXTENSION = '.txt'
-##name for new/unsaved flow graphs
+# name for new/unsaved flow graphs
NEW_FLOGRAPH_TITLE = 'untitled'
-##main window constraints
+# main window constraints
MIN_WINDOW_WIDTH = 600
MIN_WINDOW_HEIGHT = 400
-##dialog constraints
+# dialog constraints
MIN_DIALOG_WIDTH = 500
MIN_DIALOG_HEIGHT = 500
-##default sizes
+# default sizes
DEFAULT_BLOCKS_WINDOW_WIDTH = 100
DEFAULT_REPORTS_WINDOW_WIDTH = 100
-## flow-graph canvas fonts
+
+try: # ugly, but matches current code style
+ raw = _gr_prefs.get_string('grc', 'canvas_default_size', '1280, 1024')
+ DEFAULT_CANVAS_SIZE = tuple(int(x.strip('() ')) for x in raw.split(','))
+ if len(DEFAULT_CANVAS_SIZE) != 2 or not all(300 < x < 4096 for x in DEFAULT_CANVAS_SIZE):
+ raise Exception()
+except:
+ DEFAULT_CANVAS_SIZE = 1280, 1024
+ print >> sys.stderr, "Error: invalid 'canvas_default_size' setting."
+
+# flow-graph canvas fonts
+try: # ugly, but matches current code style
+ FONT_SIZE = _gr_prefs.get_long('grc', 'canvas_font_size', 8)
+ if FONT_SIZE <= 0:
+ raise Exception()
+except:
+ FONT_SIZE = 8
+ print >> sys.stderr, "Error: invalid 'canvas_font_size' setting."
FONT_FAMILY = "Sans"
-FONT_SIZE = 8
BLOCK_FONT = "%s %f" % (FONT_FAMILY, FONT_SIZE)
PORT_FONT = BLOCK_FONT
PARAM_FONT = "%s %f" % (FONT_FAMILY, FONT_SIZE - 0.5)
-##The size of the state saving cache in the flow graph (for undo/redo functionality)
+# size of the state saving cache in the flow graph (undo/redo functionality)
STATE_CACHE_SIZE = 42
-##Shared targets for drag and drop of blocks
+# Shared targets for drag and drop of blocks
DND_TARGETS = [('STRING', gtk.TARGET_SAME_APP, 0)]
-#label constraint dimensions
+# label constraint dimensions
LABEL_SEPARATION = 3
BLOCK_LABEL_PADDING = 7
PORT_LABEL_PADDING = 2
-#port constraint dimensions
-PORT_SEPARATION = 32
-PORT_BORDER_SEPARATION = 9
+# canvas grid size
+CANVAS_GRID_SIZE = 8
+
+# port constraint dimensions
+PORT_BORDER_SEPARATION = 8
+PORT_SPACING = 2 * PORT_BORDER_SEPARATION
+PORT_SEPARATION = PORT_SPACING + 2 * PORT_LABEL_PADDING + int(1.5 * FONT_SIZE)
+PORT_SEPARATION += -PORT_SEPARATION % (2 * CANVAS_GRID_SIZE) # even multiple
+
PORT_MIN_WIDTH = 20
PORT_LABEL_HIDDEN_WIDTH = 10
-#minimal length of connector
+# minimal length of connector
CONNECTOR_EXTENSION_MINIMAL = 11
-#increment length for connector
+# increment length for connector
CONNECTOR_EXTENSION_INCREMENT = 11
-#connection arrow dimensions
+# connection arrow dimensions
CONNECTOR_ARROW_BASE = 13
CONNECTOR_ARROW_HEIGHT = 17
-#possible rotations in degrees
+# possible rotations in degrees
POSSIBLE_ROTATIONS = (0, 90, 180, 270)
-#How close can the mouse get to the window border before mouse events are ignored.
+# How close can the mouse get to the window border before mouse events are ignored.
BORDER_PROXIMITY_SENSITIVITY = 50
-#How close the mouse can get to the edge of the visible window before scrolling is invoked.
+# How close the mouse can get to the edge of the visible window before scrolling is invoked.
SCROLL_PROXIMITY_SENSITIVITY = 30
-#When the window has to be scrolled, move it this distance in the required direction.
+# When the window has to be scrolled, move it this distance in the required direction.
SCROLL_DISTANCE = 15
-#How close the mouse click can be to a line and register a connection select.
+# How close the mouse click can be to a line and register a connection select.
LINE_SELECT_SENSITIVITY = 5
-# canvas grid size
-CANVAS_GRID_SIZE = 8
diff --git a/grc/gui/FlowGraph.py b/grc/gui/FlowGraph.py
index 97f814f1bf..bf6e1eed78 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/gui/Platform.py b/grc/gui/Platform.py
index db77ff2112..eda28a0e94 100644
--- a/grc/gui/Platform.py
+++ b/grc/gui/Platform.py
@@ -25,4 +25,4 @@ class Platform(Element):
self._prefs_file = prefs_file
- def get_prefs_file(self): return self._prefs_file \ No newline at end of file
+ def get_prefs_file(self): return self._prefs_file
diff --git a/grc/gui/Port.py b/grc/gui/Port.py
index 9abda878bf..93372ead93 100644
--- a/grc/gui/Port.py
+++ b/grc/gui/Port.py
@@ -18,10 +18,11 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
"""
from Element import Element
-from Constants import \
- PORT_SEPARATION, CONNECTOR_EXTENSION_MINIMAL, \
- CONNECTOR_EXTENSION_INCREMENT, \
+from Constants import (
+ PORT_SEPARATION, PORT_SPACING, CONNECTOR_EXTENSION_MINIMAL,
+ CONNECTOR_EXTENSION_INCREMENT, CANVAS_GRID_SIZE,
PORT_LABEL_PADDING, PORT_MIN_WIDTH, PORT_LABEL_HIDDEN_WIDTH, PORT_FONT
+)
from .. base.Constants import DEFAULT_DOMAIN, GR_MESSAGE_DOMAIN
import Utils
import Actions
@@ -79,56 +80,55 @@ class Port(Element):
#reverse the order of ports for these rotations
if rotation in (180, 270):
index = length-index-1
- offset = (self.get_parent().H - (length-1)*PORT_SEPARATION - self.H)/2
+
+ port_separation = PORT_SEPARATION \
+ if self.get_parent().has_busses[self.is_source()] \
+ else max([port.H for port in ports]) + PORT_SPACING
+
+ offset = (self.get_parent().H - (length-1)*port_separation - self.H)/2
#create areas and connector coordinates
if (self.is_sink() and rotation == 0) or (self.is_source() and rotation == 180):
- x = -1*W
- y = PORT_SEPARATION*index+offset
+ x = -W
+ y = port_separation*index+offset
self.add_area((x, y), (W, self.H))
self._connector_coordinate = (x-1, y+self.H/2)
elif (self.is_source() and rotation == 0) or (self.is_sink() and rotation == 180):
x = self.get_parent().W
- y = PORT_SEPARATION*index+offset
+ y = port_separation*index+offset
self.add_area((x, y), (W, self.H))
self._connector_coordinate = (x+1+W, y+self.H/2)
elif (self.is_source() and rotation == 90) or (self.is_sink() and rotation == 270):
- y = -1*W
- x = PORT_SEPARATION*index+offset
+ y = -W
+ x = port_separation*index+offset
self.add_area((x, y), (self.H, W))
self._connector_coordinate = (x+self.H/2, y-1)
elif (self.is_sink() and rotation == 90) or (self.is_source() and rotation == 270):
y = self.get_parent().W
- x = PORT_SEPARATION*index+offset
+ x = port_separation*index+offset
self.add_area((x, y), (self.H, W))
self._connector_coordinate = (x+self.H/2, y+1+W)
#the connector length
self._connector_length = CONNECTOR_EXTENSION_MINIMAL + CONNECTOR_EXTENSION_INCREMENT*index
- def modify_height(self, start_height):
- type_dict = {'bus':(lambda a: a * 3)};
-
- if self.get_type() in type_dict:
- return type_dict[self.get_type()](start_height);
- else:
- return start_height;
-
def create_labels(self):
"""Create the labels for the socket."""
Element.create_labels(self)
self._bg_color = Colors.get_color(self.get_color())
- #create the layout
+ # create the layout
layout = gtk.DrawingArea().create_pango_layout('')
layout.set_markup(Utils.parse_template(PORT_MARKUP_TMPL, port=self, font=PORT_FONT))
self.w, self.h = layout.get_pixel_size()
- self.W, self.H = 2*PORT_LABEL_PADDING + self.w, 2*PORT_LABEL_PADDING+self.h
- self.H = self.modify_height(self.H)
- #create the pixmap
+ self.W = 2 * PORT_LABEL_PADDING + self.w
+ self.H = 2 * PORT_LABEL_PADDING + self.h * (
+ 3 if self.get_type() == 'bus' else 1)
+ self.H += self.H % 2
+ # create the pixmap
pixmap = self.get_parent().get_parent().new_pixmap(self.w, self.h)
gc = pixmap.new_gc()
gc.set_foreground(self._bg_color)
pixmap.draw_rectangle(gc, True, 0, 0, self.w, self.h)
pixmap.draw_layout(gc, 0, 0, layout)
- #create vertical and horizontal pixmaps
+ # create vertical and horizontal pixmaps
self.horizontal_label = pixmap
if self.is_vertical():
self.vertical_label = self.get_parent().get_parent().new_pixmap(self.h, self.w)
diff --git a/grc/gui/Preferences.py b/grc/gui/Preferences.py
index e7b05519ea..109fe5e85e 100644
--- a/grc/gui/Preferences.py
+++ b/grc/gui/Preferences.py
@@ -18,24 +18,34 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
"""
import ConfigParser
-import os
+
_platform = None
_config_parser = ConfigParser.ConfigParser()
-def file_extension(): return '.'+_platform.get_key()
+
+def file_extension():
+ return '.'+_platform.get_key()
+
def load(platform):
global _platform
_platform = platform
- #create sections
+ # create sections
_config_parser.add_section('main')
_config_parser.add_section('files_open')
- try: _config_parser.read(_platform.get_prefs_file())
- except: pass
+ try:
+ _config_parser.read(_platform.get_prefs_file())
+ except:
+ pass
+
+
def save():
- try: _config_parser.write(open(_platform.get_prefs_file(), 'w'))
- except: pass
+ try:
+ _config_parser.write(open(_platform.get_prefs_file(), 'w'))
+ except:
+ pass
+
###########################################################################
# Special methods for specific program functionalities
@@ -46,49 +56,63 @@ def main_window_size(size=None):
_config_parser.set('main', 'main_window_width', size[0])
_config_parser.set('main', 'main_window_height', size[1])
else:
- try: return (
- _config_parser.getint('main', 'main_window_width'),
- _config_parser.getint('main', 'main_window_height'),
- )
- except: return (1, 1)
-
-def file_open(file=None):
- if file is not None: _config_parser.set('main', 'file_open', file)
+ try:
+ w = _config_parser.getint('main', 'main_window_width')
+ h = _config_parser.getint('main', 'main_window_height')
+ except:
+ w, h = 1, 1
+ return w, h
+
+
+def file_open(filename=None):
+ if filename is not None:
+ _config_parser.set('main', 'file_open', filename)
else:
- try: return _config_parser.get('main', 'file_open')
- except: return ''
+ try:
+ return _config_parser.get('main', 'file_open')
+ except:
+ return ''
+
def files_open(files=None):
if files is not None:
- _config_parser.remove_section('files_open') #clear section
+ _config_parser.remove_section('files_open') # clear section
_config_parser.add_section('files_open')
- for i, file in enumerate(files):
- _config_parser.set('files_open', 'file_open_%d'%i, file)
+ for i, filename in enumerate(files):
+ _config_parser.set('files_open', 'file_open_%d' % i, filename)
+
else:
- files = list()
- i = 0
- while True:
- try:
- files.append(_config_parser.get('files_open', 'file_open_%d'%i))
- except:
- return files
- i += 1
+ try:
+ files = [value for name, value in _config_parser.items('files_open')
+ if name.startswith('file_open_')]
+ except:
+ files = []
+ return files
+
def reports_window_position(pos=None):
- if pos is not None: _config_parser.set('main', 'reports_window_position', pos)
+ if pos is not None:
+ _config_parser.set('main', 'reports_window_position', pos)
else:
- try: return _config_parser.getint('main', 'reports_window_position') or 1 #greater than 0
- except: return -1
+ try:
+ return _config_parser.getint('main', 'reports_window_position') or 1 #greater than 0
+ except:
+ return -1
+
def blocks_window_position(pos=None):
- if pos is not None: _config_parser.set('main', 'blocks_window_position', pos)
+ if pos is not None:
+ _config_parser.set('main', 'blocks_window_position', pos)
else:
- try: return _config_parser.getint('main', 'blocks_window_position') or 1 #greater than 0
- except: return -1
+ try:
+ return _config_parser.getint('main', 'blocks_window_position') or 1 #greater than 0
+ except:
+ return -1
+
-def bool_entry(key, active=None, default=True):
- if active is not None:
- _config_parser.set('main', key, active)
+def bool_entry(key, value=None, default=True):
+ if value is not None:
+ _config_parser.set('main', key, value)
else:
try:
return _config_parser.getboolean('main', key)
diff --git a/grc/gui/PropsDialog.py b/grc/gui/PropsDialog.py
index 470e2d59d8..abf242691f 100644
--- a/grc/gui/PropsDialog.py
+++ b/grc/gui/PropsDialog.py
@@ -21,9 +21,11 @@ import pygtk
pygtk.require('2.0')
import gtk
+import Actions
from Dialogs import SimpleTextDisplay
-from Constants import MIN_DIALOG_WIDTH, MIN_DIALOG_HEIGHT
+from Constants import MIN_DIALOG_WIDTH, MIN_DIALOG_HEIGHT, FONT_SIZE
import Utils
+import pango
TAB_LABEL_MARKUP_TMPL="""\
#set $foreground = $valid and 'black' or 'red'
@@ -101,6 +103,20 @@ class PropsDialog(gtk.Dialog):
self._docs_box.add_with_viewport(self._docs_text_display)
notebook.append_page(self._docs_box, gtk.Label("Documentation"))
+ # Generated code for the block
+ if Actions.TOGGLE_SHOW_CODE_PREVIEW_TAB.get_active():
+ self._code_text_display = code_view = SimpleTextDisplay()
+ code_view.set_wrap_mode(gtk.WRAP_NONE)
+ code_view.get_buffer().create_tag('b', weight=pango.WEIGHT_BOLD)
+ code_view.modify_font(pango.FontDescription(
+ 'monospace %d' % FONT_SIZE))
+ code_box = gtk.ScrolledWindow()
+ code_box.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
+ code_box.add_with_viewport(self._code_text_display)
+ notebook.append_page(code_box, gtk.Label("Generated Code"))
+ else:
+ self._code_text_display = None
+
# Error Messages for the block
self._error_messages_text_display = SimpleTextDisplay()
self._error_box = gtk.ScrolledWindow()
@@ -127,9 +143,10 @@ class PropsDialog(gtk.Dialog):
true if changed
"""
old_hash = self._hash
- #create a tuple of things from each param that affects the params box
+ # create a tuple of things from each param that affects the params box
self._hash = hash(tuple([(
- hash(param), param.get_type(), param.get_hide() == 'all',
+ hash(param), param.get_name(), param.get_type(),
+ param.get_hide() == 'all',
) for param in self._block.get_params()]))
return self._hash != old_hash
@@ -138,7 +155,7 @@ class PropsDialog(gtk.Dialog):
A change occurred within a param:
Rewrite/validate the block and update the gui.
"""
- #update for the block
+ # update for the block
self._block.rewrite()
self._block.validate()
self._update_gui()
@@ -155,9 +172,9 @@ class PropsDialog(gtk.Dialog):
Update the documentation block.
Hide the box if there are no docs.
"""
- #update the params box
+ # update the params box
if self._params_changed():
- #hide params box before changing
+ # hide params box before changing
for tab, label, vbox in self._params_boxes:
vbox.hide_all()
# empty the params box
@@ -173,17 +190,38 @@ class PropsDialog(gtk.Dialog):
input_widget = param.get_input(self._handle_changed, self._activate_apply)
vbox.pack_start(input_widget, input_widget.expand)
label.set_markup(Utils.parse_template(TAB_LABEL_MARKUP_TMPL, valid=box_all_valid, tab=tab))
- #show params box with new params
+ # show params box with new params
vbox.show_all()
- #update the errors box
+ # update the errors box
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
+ # update the docs box
self._docs_text_display.set_text(self._block.get_doc())
+ # update the generated code
+ self._update_generated_code_page()
+
+ def _update_generated_code_page(self):
+ if not self._code_text_display:
+ return # user disabled code preview
+
+ buffer = self._code_text_display.get_buffer()
+ block = self._block
+
+ def insert(header, text):
+ if not text:
+ return
+ buffer.insert_with_tags_by_name(buffer.get_end_iter(), header, 'b')
+ buffer.insert(buffer.get_end_iter(), text)
+
+ buffer.delete(buffer.get_start_iter(), buffer.get_end_iter())
+ insert('# Imports\n', '\n'.join(block.get_imports()))
+ if block.get_key().startswith('variable'):
+ insert('\n\n# Variables\n', block.get_var_make())
+ insert('\n\n# Blocks\n', block.get_make())
def _handle_key_press(self, widget, event):
"""
@@ -209,3 +247,5 @@ class PropsDialog(gtk.Dialog):
self.set_response_sensitive(gtk.RESPONSE_APPLY, False)
return True
return False
+
+
diff --git a/grc/python/Block.py b/grc/python/Block.py
index 48b827792e..303aa85ed5 100644
--- a/grc/python/Block.py
+++ b/grc/python/Block.py
@@ -17,22 +17,18 @@ along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
"""
-from collections import defaultdict
+import itertools
+import collections
+from .. base.Constants import BLOCK_FLAG_NEED_QT_GUI, BLOCK_FLAG_NEED_WX_GUI
from .. base.Block import Block as _Block
from .. gui.Block import Block as _GUIBlock
+
from . FlowGraph import _variable_matcher
import extract_docs
-class Block(_Block, _GUIBlock):
-
- def is_virtual_sink(self): return self.get_key() == 'virtual_sink'
- def is_virtual_source(self): return self.get_key() == 'virtual_source'
- ##for make source to keep track of indexes
- _source_count = 0
- ##for make sink to keep track of indexes
- _sink_count = 0
+class Block(_Block, _GUIBlock):
def __init__(self, flow_graph, n):
"""
@@ -52,9 +48,9 @@ class Block(_Block, _GUIBlock):
self._var_make = n.find('var_make')
self._checks = n.findall('check')
self._callbacks = n.findall('callback')
- self._throttle = n.find('throttle') or ''
self._bus_structure_source = n.find('bus_structure_source') or ''
self._bus_structure_sink = n.find('bus_structure_sink') or ''
+ self.port_counters = [itertools.count(), itertools.count()]
#build the block
_Block.__init__(
self,
@@ -78,8 +74,6 @@ class Block(_Block, _GUIBlock):
except: return ''
- def throttle(self): return bool(self._throttle)
-
def validate(self):
"""
Validate this block.
@@ -102,13 +96,22 @@ class Block(_Block, _GUIBlock):
self.get_parent().evaluate(value)
except Exception as err:
self.add_error_message('Value "%s" cannot be evaluated:\n%s' % (value, err))
+
# check if this is a GUI block and matches the selected generate option
current_generate_option = self.get_parent().get_option('generate_options')
- for label, option in (('WX GUI', 'wx_gui'), ('QT GUI', 'qt_gui')):
- if self.get_name().startswith(label) and current_generate_option != option:
+
+ def check_generate_mode(label, flag, valid_options):
+ block_requires_mode = (
+ flag in self.get_flags() or
+ self.get_name().upper().startswith(label)
+ )
+ if block_requires_mode and current_generate_option not in valid_options:
self.add_error_message("Can't generate this block in mode " +
repr(current_generate_option))
+ check_generate_mode('WX GUI', BLOCK_FLAG_NEED_WX_GUI, ('wx_gui',))
+ check_generate_mode('QT GUI', BLOCK_FLAG_NEED_QT_GUI, ('qt_gui', 'hb_qt_gui'))
+
def rewrite(self):
"""
Add and remove ports to adjust for the nports.
@@ -130,13 +133,13 @@ class Block(_Block, _GUIBlock):
master_port.remove_clone(port)
ports.remove(port)
# add more cloned ports
- for i in range(num_ports, nports):
+ for j in range(num_ports, nports):
port = master_port.add_clone()
- ports.insert(ports.index(master_port) + i, port)
+ ports.insert(ports.index(master_port) + j, port)
self.back_ofthe_bus(ports)
# renumber non-message/-msg ports
- domain_specific_port_index = defaultdict(int)
+ domain_specific_port_index = collections.defaultdict(int)
for port in filter(lambda p: p.get_key().isdigit(), ports):
domain = port.get_domain()
port._key = str(domain_specific_port_index[domain])
@@ -204,3 +207,9 @@ class Block(_Block, _GUIBlock):
if 'self.' in callback: return callback
return 'self.%s.%s'%(self.get_id(), callback)
return map(make_callback, self._callbacks)
+
+ def is_virtual_sink(self):
+ return self.get_key() == 'virtual_sink'
+
+ def is_virtual_source(self):
+ return self.get_key() == 'virtual_source'
diff --git a/grc/python/Constants.py b/grc/python/Constants.py
index 79ff8bab35..1df1fc492b 100644
--- a/grc/python/Constants.py
+++ b/grc/python/Constants.py
@@ -50,31 +50,55 @@ FLOW_GRAPH_TEMPLATE = os.path.join(DATA_DIR, 'flow_graph.tmpl')
BLOCK_DTD = os.path.join(DATA_DIR, 'block.dtd')
DEFAULT_FLOW_GRAPH = os.path.join(DATA_DIR, 'default_flow_graph.grc')
+
+# Updating colors. Using the standard color pallette from:
+# http://www.google.com/design/spec/style/color.html#color-color-palette
+# Most are based on the main, primary color standard. Some are within
+# that color's spectrum when it was deemed necessary.
+GRC_COLOR_BROWN = '#795548'
+GRC_COLOR_BLUE = '#2196F3'
+GRC_COLOR_LIGHT_GREEN = '#8BC34A'
+GRC_COLOR_GREEN = '#4CAF50'
+GRC_COLOR_AMBER = '#FFC107'
+GRC_COLOR_PURPLE = '#9C27B0'
+GRC_COLOR_CYAN = '#00BCD4'
+GRC_COLOR_GR_ORANGE = '#FF6905'
+GRC_COLOR_ORANGE = '#F57C00'
+GRC_COLOR_LIME = '#CDDC39'
+GRC_COLOR_TEAL = '#009688'
+GRC_COLOR_YELLOW = '#FFEB3B'
+GRC_COLOR_PINK = '#F50057'
+GRC_COLOR_LIGHT_PURPLE = '#E040FB'
+GRC_COLOR_DARK_GREY = '#72706F'
+GRC_COLOR_GREY = '#BDBDBD'
+GRC_COLOR_WHITE = '#FFFFFF'
+
+
CORE_TYPES = ( #name, key, sizeof, color
- ('Complex Float 64', 'fc64', 16, '#CC8C69'),
- ('Complex Float 32', 'fc32', 8, '#3399FF'),
- ('Complex Integer 64', 'sc64', 16, '#66CC00'),
- ('Complex Integer 32', 'sc32', 8, '#33cc66'),
- ('Complex Integer 16', 'sc16', 4, '#cccc00'),
- ('Complex Integer 8', 'sc8', 2, '#cc00cc'),
- ('Float 64', 'f64', 8, '#66CCCC'),
- ('Float 32', 'f32', 4, '#FF8C69'),
- ('Integer 64', 's64', 8, '#99FF33'),
- ('Integer 32', 's32', 4, '#00FF99'),
- ('Integer 16', 's16', 2, '#FFFF66'),
- ('Integer 8', 's8', 1, '#FF66FF'),
- ('Message Queue', 'msg', 0, '#777777'),
- ('Async Message', 'message', 0, '#C0C0C0'),
- ('Bus Connection', 'bus', 0, '#FFFFFF'),
- ('Wildcard', '', 0, '#FFFFFF'),
+ ('Complex Float 64', 'fc64', 16, GRC_COLOR_BROWN),
+ ('Complex Float 32', 'fc32', 8, GRC_COLOR_BLUE),
+ ('Complex Integer 64', 'sc64', 16, GRC_COLOR_LIGHT_GREEN),
+ ('Complex Integer 32', 'sc32', 8, GRC_COLOR_GREEN),
+ ('Complex Integer 16', 'sc16', 4, GRC_COLOR_AMBER),
+ ('Complex Integer 8', 'sc8', 2, GRC_COLOR_PURPLE),
+ ('Float 64', 'f64', 8, GRC_COLOR_CYAN),
+ ('Float 32', 'f32', 4, GRC_COLOR_ORANGE),
+ ('Integer 64', 's64', 8, GRC_COLOR_LIME),
+ ('Integer 32', 's32', 4, GRC_COLOR_TEAL),
+ ('Integer 16', 's16', 2, GRC_COLOR_YELLOW),
+ ('Integer 8', 's8', 1, GRC_COLOR_LIGHT_PURPLE),
+ ('Message Queue', 'msg', 0, GRC_COLOR_DARK_GREY),
+ ('Async Message', 'message', 0, GRC_COLOR_GREY),
+ ('Bus Connection', 'bus', 0, GRC_COLOR_WHITE),
+ ('Wildcard', '', 0, GRC_COLOR_WHITE),
)
ALIAS_TYPES = {
- 'complex' : (8, '#3399FF'),
- 'float' : (4, '#FF8C69'),
- 'int' : (4, '#00FF99'),
- 'short' : (2, '#FFFF66'),
- 'byte' : (1, '#FF66FF'),
+ 'complex' : (8, GRC_COLOR_BLUE),
+ 'float' : (4, GRC_COLOR_ORANGE),
+ 'int' : (4, GRC_COLOR_TEAL),
+ 'short' : (2, GRC_COLOR_YELLOW),
+ 'byte' : (1, GRC_COLOR_LIGHT_PURPLE),
}
TYPE_TO_COLOR = dict()
diff --git a/grc/python/FlowGraph.py b/grc/python/FlowGraph.py
index d7337b8a96..49530af8a3 100644
--- a/grc/python/FlowGraph.py
+++ b/grc/python/FlowGraph.py
@@ -20,7 +20,6 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
import expr_utils
from .. base.FlowGraph import FlowGraph as _FlowGraph
from .. gui.FlowGraph import FlowGraph as _GUIFlowGraph
-from .. base.odict import odict
import re
_variable_matcher = re.compile('^(variable\w*)$')
diff --git a/grc/python/Generator.py b/grc/python/Generator.py
index a3f9f10fc1..98b671dde5 100644
--- a/grc/python/Generator.py
+++ b/grc/python/Generator.py
@@ -27,6 +27,7 @@ from Cheetah.Template import Template
from .. gui import Messages
from .. base import ParseXML
from .. base import odict
+from .. base.Constants import BLOCK_FLAG_NEED_QT_GUI
from . Constants import TOP_BLOCK_FILE_MODE, FLOW_GRAPH_TEMPLATE, \
XTERM_EXECUTABLE, HIER_BLOCK_FILE_MODE, HIER_BLOCKS_LIB_DIR, BLOCK_DTD
@@ -47,9 +48,13 @@ class Generator(object):
"""
self._generate_options = flow_graph.get_option('generate_options')
if self._generate_options == 'hb':
- self._generator = HierBlockGenerator(flow_graph, file_path)
+ generator_cls = HierBlockGenerator
+ elif self._generate_options == 'hb_qt_gui':
+ generator_cls = QtHierBlockGenerator
else:
- self._generator = TopBlockGenerator(flow_graph, file_path)
+ generator_cls = TopBlockGenerator
+
+ self._generator = generator_cls(flow_graph, file_path)
def get_generate_options(self):
return self._generate_options
@@ -86,8 +91,8 @@ 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())
- if not throttling_blocks and self._generate_options != 'hb':
+ throttling_blocks = filter(lambda b: b.throtteling(), self._flow_graph.get_enabled_blocks())
+ if not throttling_blocks and not self._generate_options.startswith('hb'):
Messages.send_warning("This flow graph may not have flow control: "
"no audio or RF hardware blocks found. "
"Add a Misc->Throttle block to your flow "
@@ -325,3 +330,29 @@ class HierBlockGenerator(TopBlockGenerator):
n = {'block': block_n}
return n
+
+
+class QtHierBlockGenerator(HierBlockGenerator):
+
+ def _build_block_n_from_flow_graph_io(self):
+ n = HierBlockGenerator._build_block_n_from_flow_graph_io(self)
+ block_n = n['block']
+
+ if not block_n['name'].upper().startswith('QT GUI'):
+ block_n['name'] = 'QT GUI ' + block_n['name']
+
+ block_n.insert_after('category', 'flags', BLOCK_FLAG_NEED_QT_GUI)
+
+ gui_hint_param = odict()
+ gui_hint_param['name'] = 'GUI Hint'
+ gui_hint_param['key'] = 'gui_hint'
+ gui_hint_param['value'] = ''
+ gui_hint_param['type'] = 'gui_hint'
+ gui_hint_param['hide'] = 'part'
+ block_n['param'].append(gui_hint_param)
+
+ block_n['make'] += (
+ "\n#set $win = 'self.%s' % $id"
+ "\n${gui_hint()($win)}"
+ )
+ return n
diff --git a/grc/python/Port.py b/grc/python/Port.py
index 765e1d7423..249d7aed71 100644
--- a/grc/python/Port.py
+++ b/grc/python/Port.py
@@ -100,14 +100,11 @@ class Port(_Port, _GUIPort):
elif n['domain'] == GR_MESSAGE_DOMAIN:
n['key'] = n['name']
n['type'] = 'message' # for port color
- if n['type'] == 'msg': n['key'] = 'msg'
- if dir == 'source' and not n.find('key'):
- n['key'] = str(block._source_count)
- block._source_count += 1
- if dir == 'sink' and not n.find('key'):
- n['key'] = str(block._sink_count)
- block._sink_count += 1
- #build the port
+ if n['type'] == 'msg':
+ n['key'] = 'msg'
+ if not n.find('key'):
+ n['key'] = str(next(block.port_counters[dir == 'source']))
+ # build the port
_Port.__init__(
self,
block=block,
diff --git a/grc/python/block.dtd b/grc/python/block.dtd
index 8cfd3dd392..145f4d8610 100644
--- a/grc/python/block.dtd
+++ b/grc/python/block.dtd
@@ -25,7 +25,9 @@ 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?, var_value?, make, callback*, param_tab_order?, param*, bus_sink?, bus_source?, check*, sink*, source*, bus_structure_sink?, bus_structure_source?, doc?, grc_source?)>
+<!ELEMENT block (name, key, category?, throttle?, flags?, import*, var_make?, var_value?,
+ 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.
-->
@@ -64,3 +66,4 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
<!ELEMENT callback (#PCDATA)>
<!ELEMENT optional (#PCDATA)>
<!ELEMENT throttle (#PCDATA)>
+<!ELEMENT flags (#PCDATA)>
diff --git a/grc/python/default_flow_graph.grc b/grc/python/default_flow_graph.grc
index 53d39e885a..059509d34b 100644
--- a/grc/python/default_flow_graph.grc
+++ b/grc/python/default_flow_graph.grc
@@ -14,7 +14,7 @@
</param>
<param>
<key>_coordinate</key>
- <value>(10, 10)</value>
+ <value>(8, 8)</value>
</param>
<param>
<key>_rotation</key>
@@ -33,7 +33,7 @@
</param>
<param>
<key>_coordinate</key>
- <value>(10, 170)</value>
+ <value>(8, 160)</value>
</param>
<param>
<key>_rotation</key>
diff --git a/grc/python/flow_graph.tmpl b/grc/python/flow_graph.tmpl
index 814b513213..3dd772b6ee 100644
--- a/grc/python/flow_graph.tmpl
+++ b/grc/python/flow_graph.tmpl
@@ -1,4 +1,4 @@
-#if $generate_options != 'hb'
+#if not $generate_options.startswith('hb')
#!/usr/bin/env python2
#end if
########################################################
@@ -61,7 +61,8 @@ sys.path.append(os.environ.get('GRC_HIER_PATH', os.path.expanduser('~/.grc_gnura
#end if
#for $imp in $imports
-$(imp.replace(" # grc-generated hier_block", ""))
+##$(imp.replace(" # grc-generated hier_block", ""))
+$imp
#end for
########################################################
@@ -76,6 +77,7 @@ $(imp.replace(" # grc-generated hier_block", ""))
#if $generate_options == 'wx_gui'
#import gtk
#set $icon = gtk.IconTheme().lookup_icon('gnuradio-grc', 32, 0)
+
class $(class_name)(grc_wxgui.top_block_gui):
def __init__($param_str):
@@ -85,7 +87,7 @@ class $(class_name)(grc_wxgui.top_block_gui):
self.SetIcon(wx.Icon(_icon_path, wx.BITMAP_TYPE_ANY))
#end if
#elif $generate_options == 'qt_gui'
-from distutils.version import StrictVersion
+
class $(class_name)(gr.top_block, Qt.QWidget):
def __init__($param_str):
@@ -110,16 +112,21 @@ class $(class_name)(gr.top_block, Qt.QWidget):
self.settings = Qt.QSettings("GNU Radio", "$class_name")
self.restoreGeometry(self.settings.value("geometry").toByteArray())
-
#elif $generate_options == 'no_gui'
+
class $(class_name)(gr.top_block):
def __init__($param_str):
gr.top_block.__init__(self, "$title")
-#elif $generate_options == 'hb'
+#elif $generate_options.startswith('hb')
#set $in_sigs = $flow_graph.get_hier_block_stream_io('in')
#set $out_sigs = $flow_graph.get_hier_block_stream_io('out')
+
+#if $generate_options == 'hb_qt_gui'
+class $(class_name)(gr.hier_block2, Qt.QWidget):
+#else
class $(class_name)(gr.hier_block2):
+#end if
#def make_io_sig($io_sigs)
#set $size_strs = ['%s*%s'%(io_sig['size'], io_sig['vlen']) for io_sig in $io_sigs]
#if len($io_sigs) == 0
@@ -143,6 +150,14 @@ gr.io_signaturev($(len($io_sigs)), $(len($io_sigs)), [$(', '.join($size_strs))])
#for $pad in $flow_graph.get_hier_block_message_io('out')
self.message_port_register_hier_in("$pad['label']")
#end for
+ #if $generate_options == 'hb_qt_gui'
+
+ Qt.QWidget.__init__(self)
+ self.top_layout = Qt.QVBoxLayout()
+ self.top_grid_layout = Qt.QGridLayout()
+ self.top_layout.addLayout(self.top_grid_layout)
+ self.setLayout(self.top_layout)
+ #end if
#end if
#if $flow_graph.get_option('thread_safe_setters')
@@ -304,7 +319,7 @@ $param.get_make()#slurp
#end if
$short_id#slurp
#end def
-#if $generate_options != 'hb'
+#if not $generate_options.startswith('hb')
if __name__ == '__main__':
parser = OptionParser(option_class=eng_option, usage="%prog: [options]")
@@ -334,7 +349,8 @@ if __name__ == '__main__':
tb.Wait()
#end if
#elif $generate_options == 'qt_gui'
- if(StrictVersion(Qt.qVersion()) >= StrictVersion("4.5.0")):
+ from distutils.version import StrictVersion
+ if StrictVersion(Qt.qVersion()) >= StrictVersion("4.5.0"):
Qt.QApplication.setGraphicsSystem(gr.prefs().get_string('qtgui','style','raster'))
qapp = Qt.QApplication(sys.argv)
tb = $(class_name)($(', '.join($params_eq_list)))
@@ -346,6 +362,7 @@ if __name__ == '__main__':
#end if
#end if
tb.show()
+
def quitting():
tb.stop()
tb.wait()
@@ -358,7 +375,7 @@ if __name__ == '__main__':
sys.stderr.write("Monitor '{0}' does not have an enable ('en') parameter.".format("tb.$m.get_id()"))
#end for
qapp.exec_()
- tb = None #to clean up Qt widgets
+ tb = None # to clean up Qt widgets
#elif $generate_options == 'no_gui'
tb = $(class_name)($(', '.join($params_eq_list)))
#set $run_options = $flow_graph.get_option('run_options')
diff --git a/grc/scripts/gnuradio-companion b/grc/scripts/gnuradio-companion
index 6b7a8295ba..77345bed1a 100755
--- a/grc/scripts/gnuradio-companion
+++ b/grc/scripts/gnuradio-companion
@@ -61,6 +61,14 @@ def show_gtk_error_dialog(title, message):
d.run()
+def check_gtk_init():
+ try:
+ gtk.init_check()
+ except RuntimeError:
+ print 'GTK initialization failed - bailing'
+ exit(-1)
+
+
def check_gnuradio_import():
try:
from gnuradio import gr
@@ -114,6 +122,7 @@ def main():
if __name__ == '__main__':
+ check_gtk_init()
check_gnuradio_import()
ensure_blocks_path()
main()