From 9988664127b367fa8fee4409f8460673d6f265e1 Mon Sep 17 00:00:00 2001 From: jblum Date: Tue, 23 Jun 2009 20:38:18 +0000 Subject: Merging r11186:11273 from grc branch. Fixes, features, and reorganization for grc. Minor fixes and features for wxgui forms. git-svn-id: http://gnuradio.org/svn/gnuradio/trunk@11274 221aa14e-8319-0410-a670-987f0aec2ac5 --- grc/src/platforms/Makefile.am | 31 -- grc/src/platforms/__init__.py | 1 - grc/src/platforms/base/Block.py | 259 ------------- grc/src/platforms/base/Connection.py | 94 ----- grc/src/platforms/base/Constants.py.in | 30 -- grc/src/platforms/base/Element.py | 96 ----- grc/src/platforms/base/FlowGraph.py | 224 ------------ grc/src/platforms/base/Makefile.am | 46 --- grc/src/platforms/base/Param.py | 271 -------------- grc/src/platforms/base/Platform.py | 143 -------- grc/src/platforms/base/Port.py | 80 ---- grc/src/platforms/base/__init__.py | 1 - grc/src/platforms/gui/Block.py | 199 ---------- grc/src/platforms/gui/Colors.py | 37 -- grc/src/platforms/gui/Connection.py | 140 ------- grc/src/platforms/gui/Constants.py | 44 --- grc/src/platforms/gui/Element.py | 226 ------------ grc/src/platforms/gui/FlowGraph.py | 488 ------------------------- grc/src/platforms/gui/Makefile.am | 37 -- grc/src/platforms/gui/Param.py | 103 ------ grc/src/platforms/gui/Platform.py | 48 --- grc/src/platforms/gui/Port.py | 190 ---------- grc/src/platforms/gui/Utils.py | 82 ----- grc/src/platforms/gui/__init__.py | 1 - grc/src/platforms/python/Block.py | 152 -------- grc/src/platforms/python/Connection.py | 34 -- grc/src/platforms/python/Constants.py.in | 54 --- grc/src/platforms/python/FlowGraph.py | 162 -------- grc/src/platforms/python/Generator.py | 142 ------- grc/src/platforms/python/Makefile.am | 48 --- grc/src/platforms/python/Param.py | 402 -------------------- grc/src/platforms/python/Platform.py | 69 ---- grc/src/platforms/python/Port.py | 129 ------- grc/src/platforms/python/__init__.py | 1 - grc/src/platforms/python/utils/Makefile.am | 30 -- grc/src/platforms/python/utils/__init__.py | 1 - grc/src/platforms/python/utils/convert_hier.py | 78 ---- grc/src/platforms/python/utils/expr_utils.py | 137 ------- grc/src/platforms/python/utils/extract_docs.py | 92 ----- 39 files changed, 4402 deletions(-) delete mode 100644 grc/src/platforms/Makefile.am delete mode 100644 grc/src/platforms/__init__.py delete mode 100644 grc/src/platforms/base/Block.py delete mode 100644 grc/src/platforms/base/Connection.py delete mode 100644 grc/src/platforms/base/Constants.py.in delete mode 100644 grc/src/platforms/base/Element.py delete mode 100644 grc/src/platforms/base/FlowGraph.py delete mode 100644 grc/src/platforms/base/Makefile.am delete mode 100644 grc/src/platforms/base/Param.py delete mode 100644 grc/src/platforms/base/Platform.py delete mode 100644 grc/src/platforms/base/Port.py delete mode 100644 grc/src/platforms/base/__init__.py delete mode 100644 grc/src/platforms/gui/Block.py delete mode 100644 grc/src/platforms/gui/Colors.py delete mode 100644 grc/src/platforms/gui/Connection.py delete mode 100644 grc/src/platforms/gui/Constants.py delete mode 100644 grc/src/platforms/gui/Element.py delete mode 100644 grc/src/platforms/gui/FlowGraph.py delete mode 100644 grc/src/platforms/gui/Makefile.am delete mode 100644 grc/src/platforms/gui/Param.py delete mode 100644 grc/src/platforms/gui/Platform.py delete mode 100644 grc/src/platforms/gui/Port.py delete mode 100644 grc/src/platforms/gui/Utils.py delete mode 100644 grc/src/platforms/gui/__init__.py delete mode 100644 grc/src/platforms/python/Block.py delete mode 100644 grc/src/platforms/python/Connection.py delete mode 100644 grc/src/platforms/python/Constants.py.in delete mode 100644 grc/src/platforms/python/FlowGraph.py delete mode 100644 grc/src/platforms/python/Generator.py delete mode 100644 grc/src/platforms/python/Makefile.am delete mode 100644 grc/src/platforms/python/Param.py delete mode 100644 grc/src/platforms/python/Platform.py delete mode 100644 grc/src/platforms/python/Port.py delete mode 100644 grc/src/platforms/python/__init__.py delete mode 100644 grc/src/platforms/python/utils/Makefile.am delete mode 100644 grc/src/platforms/python/utils/__init__.py delete mode 100644 grc/src/platforms/python/utils/convert_hier.py delete mode 100644 grc/src/platforms/python/utils/expr_utils.py delete mode 100644 grc/src/platforms/python/utils/extract_docs.py (limited to 'grc/src/platforms') diff --git a/grc/src/platforms/Makefile.am b/grc/src/platforms/Makefile.am deleted file mode 100644 index 1d3c385c2..000000000 --- a/grc/src/platforms/Makefile.am +++ /dev/null @@ -1,31 +0,0 @@ -# -# Copyright 2008 Free Software Foundation, Inc. -# -# This file is part of GNU Radio -# -# GNU Radio is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 3, or (at your option) -# any later version. -# -# GNU Radio is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with GNU Radio; see the file COPYING. If not, write to -# the Free Software Foundation, Inc., 51 Franklin Street, -# Boston, MA 02110-1301, USA. -# - -include $(top_srcdir)/grc/Makefile.inc - -SUBDIRS = \ - base \ - gui \ - python - -ourpythondir = $(grc_src_prefix)/platforms - -ourpython_PYTHON = __init__.py diff --git a/grc/src/platforms/__init__.py b/grc/src/platforms/__init__.py deleted file mode 100644 index 8b1378917..000000000 --- a/grc/src/platforms/__init__.py +++ /dev/null @@ -1 +0,0 @@ - diff --git a/grc/src/platforms/base/Block.py b/grc/src/platforms/base/Block.py deleted file mode 100644 index 25688472c..000000000 --- a/grc/src/platforms/base/Block.py +++ /dev/null @@ -1,259 +0,0 @@ -""" -Copyright 2008, 2009 Free Software Foundation, Inc. -This file is part of GNU Radio - -GNU Radio Companion is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or (at your option) any later version. - -GNU Radio Companion is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA -""" - -from ... utils import odict -from Element import Element -from Param import Param -from Port import Port - -from Cheetah.Template import Template -from UserDict import UserDict - -class TemplateArg(UserDict): - """ - A cheetah template argument created from a param. - The str of this class evaluates to the param's to code method. - The use of this class as a dictionary (enum only) will reveal the enum opts. - The __call__ or () method can return the param evaluated to a raw python data type. - """ - - def __init__(self, param): - UserDict.__init__(self) - self._param = param - if param.is_enum(): - for key in param.get_opt_keys(): - self[key] = str(param.get_opt(key)) - - def __str__(self): - return str(self._param.to_code()) - - def __call__(self): - return self._param.evaluate() - -class Block(Element): - - def __init__(self, flow_graph, n): - """ - Make a new block from nested data. - @param flow graph the parent element - @param n the nested odict - @return block a new block - """ - #build the block - Element.__init__(self, flow_graph) - #grab the data - params = n.findall('param') - sources = n.findall('source') - sinks = n.findall('sink') - self._name = n.find('name') - self._key = n.find('key') - self._category = n.find('category') or '' - self._block_wrapper_path = n.find('block_wrapper_path') - #create the param objects - self._params = odict() - #add the id param - self._params['id'] = self.get_parent().get_parent().Param( - self, - odict({ - 'name': 'ID', - 'key': 'id', - 'type': 'id', - }) - ) - self._params['_enabled'] = self.get_parent().get_parent().Param( - self, - odict({ - 'name': 'Enabled', - 'key': '_enabled', - 'type': 'raw', - 'value': 'True', - 'hide': 'all', - }) - ) - for param in map(lambda n: self.get_parent().get_parent().Param(self, n), params): - key = param.get_key() - #test against repeated keys - try: assert(key not in self.get_param_keys()) - except AssertionError: self._exit_with_error('Key "%s" already exists in params'%key) - #store the param - self._params[key] = param - #create the source objects - self._sources = odict() - for source in map(lambda n: self.get_parent().get_parent().Source(self, n), sources): - key = source.get_key() - #test against repeated keys - try: assert(key not in self.get_source_keys()) - except AssertionError: self._exit_with_error('Key "%s" already exists in sources'%key) - #store the port - self._sources[key] = source - #create the sink objects - self._sinks = odict() - for sink in map(lambda n: self.get_parent().get_parent().Sink(self, n), sinks): - key = sink.get_key() - #test against repeated keys - try: assert(key not in self.get_sink_keys()) - except AssertionError: self._exit_with_error('Key "%s" already exists in sinks'%key) - #store the port - self._sinks[key] = sink - #begin the testing - self.test() - - def test(self): - """ - Call test on all children. - """ - map(lambda c: c.test(), self.get_params() + self.get_sinks() + self.get_sources()) - - def get_enabled(self): - """ - Get the enabled state of the block. - @return true for enabled - """ - try: return eval(self.get_param('_enabled').get_value()) - except: return True - - def set_enabled(self, enabled): - """ - Set the enabled state of the block. - @param enabled true for enabled - """ - self.get_param('_enabled').set_value(str(enabled)) - - def validate(self): - """ - Validate the block. - All ports and params must be valid. - All checks must evaluate to true. - """ - for c in self.get_params() + self.get_ports() + self.get_connections(): - try: assert(c.is_valid()) - except AssertionError: - for msg in c.get_error_messages(): - self._add_error_message('>>> %s:\n\t%s'%(c, msg)) - - def __str__(self): return 'Block - %s - %s(%s)'%(self.get_id(), self.get_name(), self.get_key()) - - def get_id(self): return self.get_param('id').get_value() - def is_block(self): return True - def get_name(self): return self._name - def get_key(self): return self._key - def get_category(self): return self._category - def get_doc(self): return '' - def get_ports(self): return self.get_sources() + self.get_sinks() - def get_block_wrapper_path(self): return self._block_wrapper_path - - ############################################## - # Access Params - ############################################## - def get_param_keys(self): return self._params.keys() - def get_param(self, key): return self._params[key] - def get_params(self): return self._params.values() - - ############################################## - # Access Sinks - ############################################## - def get_sink_keys(self): return self._sinks.keys() - def get_sink(self, key): return self._sinks[key] - def get_sinks(self): return self._sinks.values() - - ############################################## - # Access Sources - ############################################## - def get_source_keys(self): return self._sources.keys() - def get_source(self, key): return self._sources[key] - def get_sources(self): return self._sources.values() - - def get_connections(self): - return sum([port.get_connections() for port in self.get_ports()], []) - - def resolve_dependencies(self, tmpl): - """ - Resolve a paramater dependency with cheetah templates. - @param tmpl the string with dependencies - @return the resolved value - """ - tmpl = str(tmpl) - if '$' not in tmpl: return tmpl - n = dict((p.get_key(), TemplateArg(p)) for p in self.get_params()) - try: return str(Template(tmpl, n)) - except Exception, e: return "-------->\n%s: %s\n<--------"%(e, tmpl) - - ############################################## - # Controller Modify - ############################################## - def type_controller_modify(self, direction): - """ - Change the type controller. - @param direction +1 or -1 - @return true for change - """ - changed = False - type_param = None - for param in filter(lambda p: p.is_enum(), self.get_params()): - children = self.get_ports() + self.get_params() - #priority to the type controller - if param.get_key() in ' '.join(map(lambda p: p._type, children)): type_param = param - #use param if type param is unset - if not type_param: type_param = param - if type_param: - #try to increment the enum by direction - try: - keys = type_param.get_option_keys() - old_index = keys.index(type_param.get_value()) - new_index = (old_index + direction + len(keys))%len(keys) - type_param.set_value(keys[new_index]) - changed = True - except: pass - return changed - - def port_controller_modify(self, direction): - """ - Change the port controller. - @param direction +1 or -1 - @return true for change - """ - return False - - ############################################## - ## Import/Export Methods - ############################################## - def export_data(self): - """ - Export this block's params to nested data. - @return a nested data odict - """ - n = odict() - n['key'] = self.get_key() - n['param'] = map(lambda p: p.export_data(), self.get_params()) - return n - - def import_data(self, n): - """ - Import this block's params from nested data. - Any param keys that do not exist will be ignored. - @param n the nested data odict - """ - params_n = n.findall('param') - for param_n in params_n: - key = param_n.find('key') - value = param_n.find('value') - #the key must exist in this block's params - if key in self.get_param_keys(): - self.get_param(key).set_value(value) - self.validate() diff --git a/grc/src/platforms/base/Connection.py b/grc/src/platforms/base/Connection.py deleted file mode 100644 index b8b75ac13..000000000 --- a/grc/src/platforms/base/Connection.py +++ /dev/null @@ -1,94 +0,0 @@ -""" -Copyright 2008 Free Software Foundation, Inc. -This file is part of GNU Radio - -GNU Radio Companion is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or (at your option) any later version. - -GNU Radio Companion is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA -""" - -from Element import Element -from ... utils import odict - -class Connection(Element): - - def __init__(self, flow_graph, porta, portb): - """ - Make a new connection given the parent and 2 ports. - @param flow_graph the parent of this element - @param porta a port (any direction) - @param portb a port (any direction) - @throws Error cannot make connection - @return a new connection - """ - Element.__init__(self, flow_graph) - source = sink = None - #separate the source and sink - for port in (porta, portb): - if port.is_source(): source = port - if port.is_sink(): sink = port - assert(source and sink) - #ensure that this connection (source -> sink) is unique - for connection in self.get_parent().get_connections(): - assert not (connection.get_source() is source and connection.get_sink() is sink) - self._source = source - self._sink = sink - - def __str__(self): - return 'Connection (\n\t%s\n\t\t%s\n\t%s\n\t\t%s\n)'%( - self.get_source().get_parent(), - self.get_source(), - self.get_sink().get_parent(), - self.get_sink(), - ) - - def is_connection(self): return True - - def validate(self): - """ - Validate the connections. - The ports must match in type. - """ - source_type = self.get_source().get_type() - sink_type = self.get_sink().get_type() - try: assert source_type == sink_type - except AssertionError: self._add_error_message('Source type "%s" does not match sink type "%s".'%(source_type, sink_type)) - - def get_enabled(self): - """ - Get the enabled state of this connection. - @return true if source and sink blocks are enabled - """ - return self.get_source().get_parent().get_enabled() and \ - self.get_sink().get_parent().get_enabled() - - ############################# - # Access Ports - ############################# - def get_sink(self): return self._sink - def get_source(self): return self._source - - ############################################## - ## Import/Export Methods - ############################################## - def export_data(self): - """ - Export this connection's info. - @return a nested data odict - """ - n = odict() - n['source_block_id'] = self.get_source().get_parent().get_id() - n['sink_block_id'] = self.get_sink().get_parent().get_id() - n['source_key'] = self.get_source().get_key() - n['sink_key'] = self.get_sink().get_key() - return n diff --git a/grc/src/platforms/base/Constants.py.in b/grc/src/platforms/base/Constants.py.in deleted file mode 100644 index da958a6f4..000000000 --- a/grc/src/platforms/base/Constants.py.in +++ /dev/null @@ -1,30 +0,0 @@ -""" -Copyright 2008 Free Software Foundation, Inc. -This file is part of GNU Radio - -GNU Radio Companion is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or (at your option) any later version. - -GNU Radio Companion is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA -""" - -import os - -#package and version constants -PACKAGE = '@PACKAGE@' -VERSION = '@VERSION@' - -#setup paths -PKG_DIR = os.environ.get('GR_DATADIR', '@pkgdatadir@') -DATA_DIR = os.path.join(PKG_DIR, '@reldatadir@') -FLOW_GRAPH_DTD = os.path.join(DATA_DIR, 'flow_graph.dtd') -BLOCK_TREE_DTD = os.path.join(DATA_DIR, 'block_tree.dtd') diff --git a/grc/src/platforms/base/Element.py b/grc/src/platforms/base/Element.py deleted file mode 100644 index a16be9127..000000000 --- a/grc/src/platforms/base/Element.py +++ /dev/null @@ -1,96 +0,0 @@ -""" -Copyright 2008 Free Software Foundation, Inc. -This file is part of GNU Radio - -GNU Radio Companion is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or (at your option) any later version. - -GNU Radio Companion is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA -""" - -class Element(object): - - def __init__(self, parent=None): - self._parent = parent - self._error_messages = [] - self.flag() - - def test(self): - """ - Test the element against failures. - Overload this method in sub-classes. - """ - pass - - def validate(self): - """ - Validate the data in this element. - Set the error message non blank for errors. - Overload this method in sub-classes. - """ - pass - - def is_valid(self): - self._error_messages = []#reset err msgs - if self.get_enabled(): - try: self.validate() - except: pass - return not self.get_error_messages() - - def get_enabled(self): return True - - def _add_error_message(self, msg): - self._error_messages.append(msg) - - def get_error_messages(self): - return self._error_messages - - def get_parent(self): - return self._parent - - def _exit_with_error(self, error): - parent = self - #build hier list of elements - elements = list() - while(parent): - elements.insert(0, parent) - parent = parent.get_parent() - #build error string - err_str = ">>> Error:" - for i, element in enumerate(elements + [error]): - err_str = err_str + '\n' + ''.join(' '*(i+2)) + str(element) - err_str = err_str + '\n' - exit(err_str) - - ############################################## - ## Update flagging - ############################################## - def is_flagged(self): return self._flag - def flag(self): - self._flag = True - if self.get_parent(): self.get_parent().flag() - def deflag(self): - self._flag = False - if self.get_parent(): self.get_parent().deflag() - - ############################################## - ## Type testing methods - ############################################## - def is_element(self): return True - def is_platform(self): return False - def is_flow_graph(self): return False - def is_connection(self): return False - def is_block(self): return False - def is_source(self): return False - def is_sink(self): return False - def is_port(self): return False - def is_param(self): return False diff --git a/grc/src/platforms/base/FlowGraph.py b/grc/src/platforms/base/FlowGraph.py deleted file mode 100644 index 6aeef2fa7..000000000 --- a/grc/src/platforms/base/FlowGraph.py +++ /dev/null @@ -1,224 +0,0 @@ -""" -Copyright 2008, 2009 Free Software Foundation, Inc. -This file is part of GNU Radio - -GNU Radio Companion is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or (at your option) any later version. - -GNU Radio Companion is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA -""" - -from ... utils import odict -from Element import Element -from Block import Block -from Connection import Connection -from ... gui import Messages - -class FlowGraph(Element): - - def __init__(self, platform): - """ - Make a flow graph from the arguments. - @param platform a platforms with blocks and contrcutors - @return the flow graph object - """ - #initialize - Element.__init__(self, platform) - #inital blank import - self.import_data() - - def _get_unique_id(self, base_id=''): - """ - Get a unique id starting with the base id. - @param base_id the id starts with this and appends a count - @return a unique id - """ - index = 0 - while True: - id = '%s_%d'%(base_id, index) - index = index + 1 - #make sure that the id is not used by another block - if not filter(lambda b: b.get_id() == id, self.get_blocks()): return id - - def __str__(self): return 'FlowGraph - %s(%s)'%(self.get_option('title'), self.get_option('id')) - - def get_option(self, key): - """ - Get the option for a given key. - The option comes from the special options block. - @param key the param key for the options block - @return the value held by that param - """ - return self._options_block.get_param(key).evaluate() - - def is_flow_graph(self): return True - - ############################################## - ## Access Elements - ############################################## - def get_block(self, id): return filter(lambda b: b.get_id() == id, self.get_blocks())[0] - def get_blocks(self): return filter(lambda e: e.is_block(), self.get_elements()) - def get_connections(self): return filter(lambda e: e.is_connection(), self.get_elements()) - def get_elements(self): - """ - Get a list of all the elements. - Always ensure that the options block is in the list (only once). - @return the element list - """ - options_block_count = self._elements.count(self._options_block) - if not options_block_count: - self._elements.append(self._options_block) - for i in range(options_block_count-1): - self._elements.remove(self._options_block) - return self._elements - - def get_enabled_blocks(self): - """ - Get a list of all blocks that are enabled. - @return a list of blocks - """ - return filter(lambda b: b.get_enabled(), self.get_blocks()) - - def get_enabled_connections(self): - """ - Get a list of all connections that are enabled. - @return a list of connections - """ - return filter(lambda c: c.get_enabled(), self.get_connections()) - - def get_new_block(self, key): - """ - Get a new block of the specified key. - Add the block to the list of elements. - @param key the block key - @return the new block or None if not found - """ - self.flag() - if key not in self.get_parent().get_block_keys(): return None - block = self.get_parent().get_new_block(self, key) - self.get_elements().append(block) - return block - - def connect(self, porta, portb): - """ - Create a connection between porta and portb. - @param porta a port - @param portb another port - @throw Exception bad connection - @return the new connection - """ - self.flag() - connection = self.get_parent().Connection(self, porta, portb) - self.get_elements().append(connection) - return connection - - def remove_element(self, element): - """ - Remove the element from the list of elements. - If the element is a port, remove the whole block. - If the element is a block, remove its connections. - If the element is a connection, just remove the connection. - """ - self.flag() - if element not in self.get_elements(): return - #found a port, set to parent signal block - if element.is_port(): - element = element.get_parent() - #remove block, remove all involved connections - if element.is_block(): - for port in element.get_ports(): - map(self.remove_element, port.get_connections()) - self.get_elements().remove(element) - - def evaluate(self, expr): - """ - Evaluate the expression. - @param expr the string expression - @throw NotImplementedError - """ - raise NotImplementedError - - def validate(self): - """ - Validate the flow graph. - All connections and blocks must be valid. - """ - for c in self.get_elements(): - try: assert c.is_valid() - except AssertionError: self._add_error_message('Element "%s" is not valid.'%c) - - ############################################## - ## Import/Export Methods - ############################################## - def export_data(self): - """ - Export this flow graph to nested data. - Export all block and connection data. - @return a nested data odict - """ - import time - n = odict() - n['timestamp'] = time.ctime() - n['block'] = [block.export_data() for block in self.get_blocks()] - n['connection'] = [connection.export_data() for connection in self.get_connections()] - return odict({'flow_graph': n}) - - def import_data(self, n=None): - """ - Import blocks and connections into this flow graph. - Clear this flowgraph of all previous blocks and connections. - Any blocks or connections in error will be ignored. - @param n the nested data odict - """ - #remove previous elements - self._elements = list() - #use blank data if none provided - fg_n = n and n.find('flow_graph') or odict() - blocks_n = fg_n.findall('block') - connections_n = fg_n.findall('connection') - #create option block - self._options_block = self.get_parent().get_new_block(self, 'options') - #build the blocks - for block_n in blocks_n: - key = block_n.find('key') - if key == 'options': block = self._options_block - else: block = self.get_new_block(key) - #only load the block when the block key was valid - if block: block.import_data(block_n) - else: Messages.send_error_load('Block key "%s" not found in %s'%(key, self.get_parent())) - #build the connections - for connection_n in connections_n: - #try to make the connection - try: - #get the block ids - source_block_id = connection_n.find('source_block_id') - sink_block_id = connection_n.find('sink_block_id') - #get the port keys - source_key = connection_n.find('source_key') - sink_key = connection_n.find('sink_key') - #verify the blocks - block_ids = map(lambda b: b.get_id(), self.get_blocks()) - assert(source_block_id in block_ids) - assert(sink_block_id in block_ids) - #get the blocks - source_block = self.get_block(source_block_id) - sink_block = self.get_block(sink_block_id) - #verify the ports - assert(source_key in source_block.get_source_keys()) - assert(sink_key in sink_block.get_sink_keys()) - #get the ports - source = source_block.get_source(source_key) - sink = sink_block.get_sink(sink_key) - #build the connection - self.connect(source, sink) - except AssertionError: Messages.send_error_load('Connection between %s(%s) and %s(%s) could not be made.'%(source_block_id, source_key, sink_block_id, sink_key)) - self.validate() diff --git a/grc/src/platforms/base/Makefile.am b/grc/src/platforms/base/Makefile.am deleted file mode 100644 index 805c7b2b3..000000000 --- a/grc/src/platforms/base/Makefile.am +++ /dev/null @@ -1,46 +0,0 @@ -# -# Copyright 2008,2009 Free Software Foundation, Inc. -# -# This file is part of GNU Radio -# -# GNU Radio is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 3, or (at your option) -# any later version. -# -# GNU Radio is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with GNU Radio; see the file COPYING. If not, write to -# the Free Software Foundation, Inc., 51 Franklin Street, -# Boston, MA 02110-1301, USA. -# - -include $(top_srcdir)/grc/Makefile.inc - -ourpythondir = $(grc_src_prefix)/platforms/base - -ourpython_PYTHON = \ - Block.py \ - Connection.py \ - Constants.py \ - Element.py \ - FlowGraph.py \ - Param.py \ - Platform.py \ - Port.py \ - __init__.py - -Constants.py: $(srcdir)/Constants.py.in Makefile - sed \ - -e 's|@PACKAGE[@]|$(PACKAGE)|g' \ - -e 's|@VERSION[@]|$(VERSION)|g' \ - -e 's|@pkgdatadir[@]|$(pkgdatadir)|g' \ - -e 's|@reldatadir[@]|$(grc_base_data_reldir)|g' \ - $< > $@ - -EXTRA_DIST = $(srcdir)/Constants.py.in -BUILT_SOURCES = Constants.py diff --git a/grc/src/platforms/base/Param.py b/grc/src/platforms/base/Param.py deleted file mode 100644 index 81783c791..000000000 --- a/grc/src/platforms/base/Param.py +++ /dev/null @@ -1,271 +0,0 @@ -""" -Copyright 2008, 2009 Free Software Foundation, Inc. -This file is part of GNU Radio - -GNU Radio Companion is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or (at your option) any later version. - -GNU Radio Companion is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA -""" - -from ... utils import odict -from Element import Element -import pygtk -pygtk.require('2.0') -import gtk - -class InputParam(gtk.HBox): - """The base class for an input parameter inside the input parameters dialog.""" - - def __init__(self, param, _handle_changed): - gtk.HBox.__init__(self) - self.param = param - self._handle_changed = _handle_changed - self.label = gtk.Label('') #no label, markup is added by set_markup - self.label.set_size_request(150, -1) - self.pack_start(self.label, False) - self.set_markup = lambda m: self.label.set_markup(m) - self.tp = None - def set_color(self, color): pass - -class EntryParam(InputParam): - """Provide an entry box for strings and numbers.""" - - def __init__(self, *args, **kwargs): - InputParam.__init__(self, *args, **kwargs) - self.entry = input = gtk.Entry() - input.set_text(self.param.get_value()) - input.connect('changed', self._handle_changed) - self.pack_start(input, True) - self.get_text = input.get_text - #tool tip - self.tp = gtk.Tooltips() - self.tp.set_tip(self.entry, '') - self.tp.enable() - def set_color(self, color): self.entry.modify_base(gtk.STATE_NORMAL, gtk.gdk.color_parse(color)) - -class EnumParam(InputParam): - """Provide an entry box for Enum types with a drop down menu.""" - - def __init__(self, *args, **kwargs): - InputParam.__init__(self, *args, **kwargs) - self._input = gtk.combo_box_new_text() - for option in self.param.get_options(): self._input.append_text(option.get_name()) - self._input.set_active(self.param.get_option_keys().index(self.param.get_value())) - self._input.connect('changed', self._handle_changed) - self.pack_start(self._input, False) - def get_text(self): return self.param.get_option_keys()[self._input.get_active()] - -class EnumEntryParam(InputParam): - """Provide an entry box and drop down menu for Raw Enum types.""" - - def __init__(self, *args, **kwargs): - InputParam.__init__(self, *args, **kwargs) - self._input = gtk.combo_box_entry_new_text() - for option in self.param.get_options(): self._input.append_text(option.get_name()) - try: self._input.set_active(self.param.get_option_keys().index(self.param.get_value())) - except: - self._input.set_active(-1) - self._input.get_child().set_text(self.param.get_value()) - self._input.connect('changed', self._handle_changed) - self._input.get_child().connect('changed', self._handle_changed) - self.pack_start(self._input, False) - def get_text(self): - if self._input.get_active() == -1: return self._input.get_child().get_text() - return self.param.get_option_keys()[self._input.get_active()] - def set_color(self, color): - if self._input.get_active() == -1: #custom entry, use color - self._input.get_child().modify_base(gtk.STATE_NORMAL, gtk.gdk.color_parse(color)) - else: #from enum, make white background - self._input.get_child().modify_base(gtk.STATE_NORMAL, gtk.gdk.color_parse('#ffffff')) - -class Option(Element): - - def __init__(self, param, n): - Element.__init__(self, param) - self._name = n.find('name') - self._key = n.find('key') - self._opts = dict() - opts = n.findall('opt') - #test against opts when non enum - try: assert self.get_parent().is_enum() or not opts - except AssertionError: self._exit_with_error('Options for non-enum types cannot have sub-options') - #extract opts - for opt in opts: - #separate the key:value - try: key, value = opt.split(':') - except: self._exit_with_error('Error separating "%s" into key:value'%opt) - #test against repeated keys - try: assert not self._opts.has_key(key) - except AssertionError: self._exit_with_error('Key "%s" already exists in option'%key) - #store the option - self._opts[key] = value - - def __str__(self): return 'Option %s(%s)'%(self.get_name(), self.get_key()) - def get_name(self): return self._name - def get_key(self): return self._key - - ############################################## - # Access Opts - ############################################## - def get_opt_keys(self): return self._opts.keys() - def get_opt(self, key): return self._opts[key] - def get_opts(self): return self._opts.values() - -class Param(Element): - - ##possible param types - TYPES = ['enum', 'raw'] - - def __init__(self, block, n): - """ - Make a new param from nested data. - @param block the parent element - @param n the nested odict - @return a new param - """ - #grab the data - self._name = n.find('name') - self._key = n.find('key') - value = n.find('value') or '' - self._type = n.find('type') - self._hide = n.find('hide') or '' - #build the param - Element.__init__(self, block) - #create the Option objects from the n data - self._options = odict() - for option in map(lambda o: Option(self, o), n.findall('option')): - key = option.get_key() - #test against repeated keys - try: assert(key not in self.get_option_keys()) - except AssertionError: self._exit_with_error('Key "%s" already exists in options'%key) - #store the option - self._options[key] = option - #test the enum options - if self.is_enum(): - #test against options with identical keys - try: assert(len(set(self.get_option_keys())) == len(self._options)) - except AssertionError: self._exit_with_error('Options keys "%s" are not unique.'%self.get_option_keys()) - #test against inconsistent keys in options - opt_keys = self._options.values()[0].get_opt_keys() - for option in self._options.values(): - try: assert(set(opt_keys) == set(option.get_opt_keys())) - except AssertionError: self._exit_with_error('Opt keys "%s" are not identical across all options.'%opt_keys) - #if a value is specified, it must be in the options keys - self._value = value or self.get_option_keys()[0] - try: assert(self.get_value() in self.get_option_keys()) - except AssertionError: self._exit_with_error('The value "%s" is not in the possible values of "%s".'%(self.get_value(), self.get_option_keys())) - else: self._value = value or '' - - def test(self): - """ - call test on all children - """ - map(lambda c: c.test(), self.get_options()) - - def validate(self): - """ - Validate the param. - The value must be evaluated and type must a possible type. - """ - try: - assert(self.get_type() in self.TYPES) - try: self.evaluate() - except: - #if the evaluate failed but added no error messages, add the generic one below - if not self.get_error_messages(): - self._add_error_message('Value "%s" cannot be evaluated.'%self.get_value()) - except AssertionError: self._add_error_message('Type "%s" is not a possible type.'%self.get_type()) - - def evaluate(self): - """ - Evaluate the value of this param. - @throw NotImplementedError - """ - raise NotImplementedError - - def to_code(self): - """ - Convert the value to code. - @throw NotImplementedError - """ - raise NotImplementedError - - 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_key(self): return self._key - def get_hide(self): return self.get_parent().resolve_dependencies(self._hide) - - def get_value(self): - value = self._value - if self.is_enum() and value not in self.get_option_keys(): - value = self.get_option_keys()[0] - self.set_value(value) - return value - - def set_value(self, value): - self.flag() - self._value = str(value) #must be a string - - def get_type(self): return self.get_parent().resolve_dependencies(self._type) - def is_enum(self): return self._type == 'enum' - - def __repr__(self): - """ - Get the repr (nice string format) for this param. - Just return the value (special case enum). - Derived classes can handle complex formatting. - @return the string representation - """ - if self.is_enum(): return self.get_option(self.get_value()).get_name() - return self.get_value() - - def get_input_class(self): - """ - Get the graphical gtk class to represent this parameter. - An enum requires and combo parameter. - A non-enum with options gets a combined entry/combo parameter. - All others get a standard entry parameter. - @return gtk input class - """ - if self.is_enum(): return EnumParam - if self.get_options(): return EnumEntryParam - return EntryParam - - ############################################## - # Access Options - ############################################## - def get_option_keys(self): return self._options.keys() - def get_option(self, key): return self._options[key] - def get_options(self): return self._options.values() - - ############################################## - # Access Opts - ############################################## - def get_opt_keys(self): return self._options[self.get_value()].get_opt_keys() - def get_opt(self, key): return self._options[self.get_value()].get_opt(key) - def get_opts(self): return self._options[self.get_value()].get_opts() - - ############################################## - ## Import/Export Methods - ############################################## - def export_data(self): - """ - Export this param's key/value. - @return a nested data odict - """ - n = odict() - n['key'] = self.get_key() - n['value'] = self.get_value() - return n diff --git a/grc/src/platforms/base/Platform.py b/grc/src/platforms/base/Platform.py deleted file mode 100644 index 35227d99f..000000000 --- a/grc/src/platforms/base/Platform.py +++ /dev/null @@ -1,143 +0,0 @@ -""" -Copyright 2008, 2009 Free Software Foundation, Inc. -This file is part of GNU Radio - -GNU Radio Companion is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or (at your option) any later version. - -GNU Radio Companion is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA -""" - -import os -from ... utils import ParseXML -from Element import Element as _Element -from FlowGraph import FlowGraph as _FlowGraph -from Connection import Connection as _Connection -from Block import Block as _Block -from Port import Port as _Port -from Param import Param as _Param -from Constants import BLOCK_TREE_DTD - -class Platform(_Element): - - def __init__(self, name, key, block_paths, block_dtd, block_tree, default_flow_graph, generator): - """ - Make a platform from the arguments. - @param name the platform name - @param key the unique platform key - @param block_paths the file paths to blocks in this platform - @param block_dtd the dtd validator for xml block wrappers - @param block_tree the nested tree of block keys and categories - @param default_flow_graph the default flow graph file path - @param load_one a single file to load into this platform or None - @return a platform object - """ - _Element.__init__(self) - self._name = name - self._key = key - self._block_paths = block_paths - self._block_dtd = block_dtd - self._block_tree = block_tree - self._default_flow_graph = default_flow_graph - self._generator = generator - #create a dummy flow graph for the blocks - self._flow_graph = _Element(self) - #load the blocks - self._blocks = dict() - self._blocks_n = dict() - for block_path in self._block_paths: - if os.path.isfile(block_path): self._load_blocks(block_path) - elif os.path.isdir(block_path): - for dirpath, dirnames, filenames in os.walk(block_path): - for filename in filter(lambda f: f.endswith('.xml'), filenames): - self._load_blocks(os.path.join(dirpath, filename)) - - def _load_blocks(self, f): - """ - Load the block wrappers from the file path. - The block wrapper must pass validation. - If any of the checks fail, exit with error. - @param f the file path - """ - try: ParseXML.validate_dtd(f, self._block_dtd) - except ParseXML.XMLSyntaxError, e: self._exit_with_error('Block definition "%s" failed: \n\t%s'%(f, e)) - n = ParseXML.from_file(f).find('block') - #inject block wrapper path - n['block_wrapper_path'] = f - block = self.Block(self._flow_graph, n) - key = block.get_key() - #test against repeated keys - try: assert(key not in self.get_block_keys()) - except AssertionError: self._exit_with_error('Key "%s" already exists in blocks'%key) - #store the block - self._blocks[key] = block - self._blocks_n[key] = n - - def load_block_tree(self, block_tree): - """ - Load a block tree with categories and blocks. - Step 1: Load all blocks from the xml specification. - Step 2: Load blocks with builtin category specifications. - @param block_tree the block tree object - """ - #recursive function to load categories and blocks - def load_category(cat_n, parent=[]): - #add this category - parent = parent + [cat_n.find('name')] - block_tree.add_block(parent) - #recursive call to load sub categories - map(lambda c: load_category(c, parent), cat_n.findall('cat')) - #add blocks in this category - for block_key in cat_n.findall('block'): - block_tree.add_block(parent, self.get_block(block_key)) - #load the block tree - f = self._block_tree - try: ParseXML.validate_dtd(f, BLOCK_TREE_DTD) - except ParseXML.XMLSyntaxError, e: self._exit_with_error('Block tree "%s" failed: \n\t%s'%(f, e)) - #add all blocks in the tree - load_category(ParseXML.from_file(f).find('cat')) - #add all other blocks, use the catgory - for block in self.get_blocks(): - #blocks with empty categories are in the xml block tree or hidden - if block.get_category(): block_tree.add_block(block.get_category(), block) - - def __str__(self): return 'Platform - %s(%s)'%(self.get_key(), self.get_name()) - - def is_platform(self): return True - - def get_new_flow_graph(self): return self.FlowGraph(self) - - def get_default_flow_graph(self): return self._default_flow_graph - - def get_generator(self): return self._generator - - ############################################## - # Access Blocks - ############################################## - def get_block_keys(self): return self._blocks.keys() - def get_block(self, key): return self._blocks[key] - def get_blocks(self): return self._blocks.values() - def get_new_block(self, flow_graph, key): return self.Block(flow_graph, n=self._blocks_n[key]) - - def get_name(self): return self._name - - def get_key(self): return self._key - - ############################################## - # Constructors - ############################################## - FlowGraph = _FlowGraph - Connection = _Connection - Block = _Block - Source = _Port - Sink = _Port - Param = _Param diff --git a/grc/src/platforms/base/Port.py b/grc/src/platforms/base/Port.py deleted file mode 100644 index f46a81195..000000000 --- a/grc/src/platforms/base/Port.py +++ /dev/null @@ -1,80 +0,0 @@ -""" -Copyright 2008, 2009 Free Software Foundation, Inc. -This file is part of GNU Radio - -GNU Radio Companion is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or (at your option) any later version. - -GNU Radio Companion is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA -""" - -from Element import Element - -class Port(Element): - - ##possible port types - TYPES = [] - - def __init__(self, block, n): - """ - Make a new port from nested data. - @param block the parent element - @param n the nested odict - @return a new port - """ - #grab the data - name = n['name'] - key = n['key'] - type = n['type'] - #build the port - Element.__init__(self, block) - self._name = name - self._key = key - self._type = type - - def validate(self): - """ - Validate the port. - The port must be non-empty and type must a possible type. - """ - try: assert(self.get_type() in self.TYPES) - except AssertionError: self._add_error_message('Type "%s" is not a possible type.'%self.get_type()) - - def __str__(self): - if self.is_source(): - return 'Source - %s(%s)'%(self.get_name(), self.get_key()) - if self.is_sink(): - return 'Sink - %s(%s)'%(self.get_name(), self.get_key()) - - def is_port(self): return True - def get_color(self): return '#FFFFFF' - def get_name(self): return self._name - def get_key(self): return self._key - def is_sink(self): return self in self.get_parent().get_sinks() - def is_source(self): return self in self.get_parent().get_sources() - def get_type(self): return self.get_parent().resolve_dependencies(self._type) - - def get_connections(self): - """ - Get all connections that use this port. - @return a list of connection objects - """ - connections = self.get_parent().get_parent().get_connections() - connections = filter(lambda c: c.get_source() is self or c.get_sink() is self, connections) - return connections - - def get_enabled_connections(self): - """ - Get all enabled connections that use this port. - @return a list of connection objects - """ - return filter(lambda c: c.get_enabled(), self.get_connections()) diff --git a/grc/src/platforms/base/__init__.py b/grc/src/platforms/base/__init__.py deleted file mode 100644 index 8b1378917..000000000 --- a/grc/src/platforms/base/__init__.py +++ /dev/null @@ -1 +0,0 @@ - diff --git a/grc/src/platforms/gui/Block.py b/grc/src/platforms/gui/Block.py deleted file mode 100644 index 862a59393..000000000 --- a/grc/src/platforms/gui/Block.py +++ /dev/null @@ -1,199 +0,0 @@ -""" -Copyright 2007, 2008, 2009 Free Software Foundation, Inc. -This file is part of GNU Radio - -GNU Radio Companion is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or (at your option) any later version. - -GNU Radio Companion is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA -""" - -from Element import Element -import Utils -import Colors -from ... utils import odict -from Constants import BORDER_PROXIMITY_SENSITIVITY -from Constants import \ - BLOCK_LABEL_PADDING, \ - PORT_SEPARATION, LABEL_SEPARATION, \ - PORT_BORDER_SEPARATION, POSSIBLE_ROTATIONS -import pygtk -pygtk.require('2.0') -import gtk - -BLOCK_MARKUP_TMPL="""\ -#set $foreground = $block.is_valid() and 'black' or 'red' -$encode($block.get_name())""" - -class Block(Element): - """The graphical signal block.""" - - def __init__(self, *args, **kwargs): - """ - Block contructor. - Add graphics related params to the block. - """ - #add the position param - self._params['_coordinate'] = self.get_parent().get_parent().Param( - self, - odict({ - 'name': 'GUI Coordinate', - 'key': '_coordinate', - 'type': 'raw', - 'value': '(0, 0)', - 'hide': 'all', - }) - ) - self._params['_rotation'] = self.get_parent().get_parent().Param( - self, - odict({ - 'name': 'GUI Rotation', - 'key': '_rotation', - 'type': 'raw', - 'value': '0', - 'hide': 'all', - }) - ) - Element.__init__(self) - - def get_coordinate(self): - """ - Get the coordinate from the position param. - @return the coordinate tuple (x, y) or (0, 0) if failure - """ - try: #should evaluate to tuple - coor = eval(self.get_param('_coordinate').get_value()) - x, y = map(int, coor) - fgW,fgH = self.get_parent().get_size() - if x <= 0: - x = 0 - elif x >= fgW - BORDER_PROXIMITY_SENSITIVITY: - x = fgW - BORDER_PROXIMITY_SENSITIVITY - if y <= 0: - y = 0 - elif y >= fgH - BORDER_PROXIMITY_SENSITIVITY: - y = fgH - BORDER_PROXIMITY_SENSITIVITY - return (x, y) - except: - self.set_coordinate((0, 0)) - return (0, 0) - - def set_coordinate(self, coor): - """ - Set the coordinate into the position param. - @param coor the coordinate tuple (x, y) - """ - self.get_param('_coordinate').set_value(str(coor)) - - def get_rotation(self): - """ - Get the rotation from the position param. - @return the rotation in degrees or 0 if failure - """ - try: #should evaluate to dict - rotation = eval(self.get_param('_rotation').get_value()) - return int(rotation) - except: - self.set_rotation(POSSIBLE_ROTATIONS[0]) - return POSSIBLE_ROTATIONS[0] - - def set_rotation(self, rot): - """ - Set the rotation into the position param. - @param rot the rotation in degrees - """ - self.get_param('_rotation').set_value(str(rot)) - - def update(self): - """Update the block, parameters, and ports when a change occurs.""" - self._bg_color = self.get_enabled() and Colors.BLOCK_ENABLED_COLOR or Colors.BLOCK_DISABLED_COLOR - self.clear() - self._create_labels() - self.W = self.label_width + 2*BLOCK_LABEL_PADDING - self.H = max(*( - [self.label_height+2*BLOCK_LABEL_PADDING] + [2*PORT_BORDER_SEPARATION + \ - sum([port.H + PORT_SEPARATION for port in ports]) - PORT_SEPARATION - for ports in (self.get_sources(), self.get_sinks())] - )) - if self.is_horizontal(): self.add_area((0, 0), (self.W, self.H)) - elif self.is_vertical(): self.add_area((0, 0), (self.H, self.W)) - map(lambda p: p.update(), self.get_ports()) - - def _create_labels(self): - """Create the labels for the signal block.""" - layouts = list() - #create the main layout - layout = gtk.DrawingArea().create_pango_layout('') - layouts.append(layout) - layout.set_markup(Utils.parse_template(BLOCK_MARKUP_TMPL, block=self)) - self.label_width, self.label_height = layout.get_pixel_size() - #display the params - for param in filter(lambda p: p.get_hide() not in ('all', 'part'), self.get_params()): - layout = param.get_layout() - layouts.append(layout) - w,h = layout.get_pixel_size() - self.label_width = max(w, self.label_width) - self.label_height = self.label_height + h + LABEL_SEPARATION - width = self.label_width - height = self.label_height - #setup the pixmap - pixmap = self.get_parent().new_pixmap(width, height) - gc = pixmap.new_gc() - gc.set_foreground(self._bg_color) - pixmap.draw_rectangle(gc, True, 0, 0, width, height) - #draw the layouts - h_off = 0 - for i,layout in enumerate(layouts): - w,h = layout.get_pixel_size() - if i == 0: w_off = (width-w)/2 - else: w_off = 0 - pixmap.draw_layout(gc, w_off, h_off, layout) - h_off = h + h_off + LABEL_SEPARATION - #create vertical and horizontal images - self.horizontal_label = image = pixmap.get_image(0, 0, width, height) - if self.is_vertical(): - self.vertical_label = vimage = gtk.gdk.Image(gtk.gdk.IMAGE_NORMAL, pixmap.get_visual(), height, width) - for i in range(width): - for j in range(height): vimage.put_pixel(j, width-i-1, image.get_pixel(i, j)) - map(lambda p: p._create_labels(), self.get_ports()) - - def draw(self, gc, window): - """ - Draw the signal block with label and inputs/outputs. - @param gc the graphics context - @param window the gtk window to draw on - """ - x, y = self.get_coordinate() - #draw main block - Element.draw( - self, gc, window, bg_color=self._bg_color, - border_color=self.is_highlighted() and Colors.HIGHLIGHT_COLOR or Colors.BORDER_COLOR, - ) - #draw label image - if self.is_horizontal(): - window.draw_image(gc, self.horizontal_label, 0, 0, x+BLOCK_LABEL_PADDING, y+(self.H-self.label_height)/2, -1, -1) - elif self.is_vertical(): - window.draw_image(gc, self.vertical_label, 0, 0, x+(self.H-self.label_height)/2, y+BLOCK_LABEL_PADDING, -1, -1) - #draw ports - for port in self.get_ports(): port.draw(gc, window) - - def what_is_selected(self, coor, coor_m=None): - """ - Get the element that is selected. - @param coor the (x,y) tuple - @param coor_m the (x_m, y_m) tuple - @return this block, a port, or None - """ - for port in self.get_ports(): - port_selected = port.what_is_selected(coor, coor_m) - if port_selected: return port_selected - return Element.what_is_selected(self, coor, coor_m) diff --git a/grc/src/platforms/gui/Colors.py b/grc/src/platforms/gui/Colors.py deleted file mode 100644 index f0b989b37..000000000 --- a/grc/src/platforms/gui/Colors.py +++ /dev/null @@ -1,37 +0,0 @@ -""" -Copyright 2008 Free Software Foundation, Inc. -This file is part of GNU Radio - -GNU Radio Companion is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or (at your option) any later version. - -GNU Radio Companion is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA -""" - -import pygtk -pygtk.require('2.0') -import gtk - -_COLORMAP = gtk.gdk.colormap_get_system() #create all of the colors -def get_color(color_code): return _COLORMAP.alloc_color(color_code, True, True) - -HIGHLIGHT_COLOR = get_color('#00FFFF') -BORDER_COLOR = get_color('black') -#flow graph color constants -FLOWGRAPH_BACKGROUND_COLOR = get_color('#FFF9FF') -#block color constants -BLOCK_ENABLED_COLOR = get_color('#F1ECFF') -BLOCK_DISABLED_COLOR = get_color('#CCCCCC') -#connection color constants -CONNECTION_ENABLED_COLOR = get_color('black') -CONNECTION_DISABLED_COLOR = get_color('#999999') -CONNECTION_ERROR_COLOR = get_color('red') diff --git a/grc/src/platforms/gui/Connection.py b/grc/src/platforms/gui/Connection.py deleted file mode 100644 index 013bcb00f..000000000 --- a/grc/src/platforms/gui/Connection.py +++ /dev/null @@ -1,140 +0,0 @@ -""" -Copyright 2007, 2008 Free Software Foundation, Inc. -This file is part of GNU Radio - -GNU Radio Companion is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or (at your option) any later version. - -GNU Radio Companion is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA -""" - -import Utils -from Element import Element -import Colors -from Constants import CONNECTOR_ARROW_BASE, CONNECTOR_ARROW_HEIGHT - -class Connection(Element): - """ - A graphical connection for ports. - The connection has 2 parts, the arrow and the wire. - The coloring of the arrow and wire exposes the status of 3 states: - enabled/disabled, valid/invalid, highlighted/non-highlighted. - The wire coloring exposes the enabled and highlighted states. - The arrow coloring exposes the enabled and valid states. - """ - - def get_coordinate(self): - """ - Get the 0,0 coordinate. - Coordinates are irrelevant in connection. - @return 0, 0 - """ - return (0, 0) - - def get_rotation(self): - """ - Get the 0 degree rotation. - Rotations are irrelevant in connection. - @return 0 - """ - return 0 - - def update(self): - """Precalculate relative coordinates.""" - self._sink_rot = None - self._source_rot = None - self._sink_coor = None - self._source_coor = None - #get the source coordinate - connector_length = self.get_source().get_connector_length() - self.x1, self.y1 = Utils.get_rotated_coordinate((connector_length, 0), self.get_source().get_rotation()) - #get the sink coordinate - connector_length = self.get_sink().get_connector_length() + CONNECTOR_ARROW_HEIGHT - self.x2, self.y2 = Utils.get_rotated_coordinate((-connector_length, 0), self.get_sink().get_rotation()) - #build the arrow - self.arrow = [(0, 0), - Utils.get_rotated_coordinate((-CONNECTOR_ARROW_HEIGHT, -CONNECTOR_ARROW_BASE/2), self.get_sink().get_rotation()), - Utils.get_rotated_coordinate((-CONNECTOR_ARROW_HEIGHT, CONNECTOR_ARROW_BASE/2), self.get_sink().get_rotation()), - ] - self._update_after_move() - if not self.get_enabled(): self._arrow_color = Colors.CONNECTION_DISABLED_COLOR - elif not self.is_valid(): self._arrow_color = Colors.CONNECTION_ERROR_COLOR - else: self._arrow_color = Colors.CONNECTION_ENABLED_COLOR - - def _update_after_move(self): - """Calculate coordinates.""" - self.clear() - #source connector - source = self.get_source() - X, Y = source.get_connector_coordinate() - x1, y1 = self.x1 + X, self.y1 + Y - self.add_line((x1, y1), (X, Y)) - #sink connector - sink = self.get_sink() - X, Y = sink.get_connector_coordinate() - x2, y2 = self.x2 + X, self.y2 + Y - self.add_line((x2, y2), (X, Y)) - #adjust arrow - self._arrow = [(x+X, y+Y) for x,y in self.arrow] - #add the horizontal and vertical lines in this connection - if abs(source.get_connector_direction() - sink.get_connector_direction()) == 180: - #2 possible point sets to create a 3-line connector - mid_x, mid_y = (x1 + x2)/2.0, (y1 + y2)/2.0 - points = [((mid_x, y1), (mid_x, y2)), ((x1, mid_y), (x2, mid_y))] - #source connector -> points[0][0] should be in the direction of source (if possible) - if Utils.get_angle_from_coordinates((x1, y1), points[0][0]) != source.get_connector_direction(): points.reverse() - #points[0][0] -> sink connector should not be in the direction of sink - if Utils.get_angle_from_coordinates(points[0][0], (x2, y2)) == sink.get_connector_direction(): points.reverse() - #points[0][0] -> source connector should not be in the direction of source - if Utils.get_angle_from_coordinates(points[0][0], (x1, y1)) == source.get_connector_direction(): points.reverse() - #create 3-line connector - p1, p2 = map(int, points[0][0]), map(int, points[0][1]) - self.add_line((x1, y1), p1) - self.add_line(p1, p2) - self.add_line((x2, y2), p2) - else: - #2 possible points to create a right-angled connector - points = [(x1, y2), (x2, y1)] - #source connector -> points[0] should be in the direction of source (if possible) - if Utils.get_angle_from_coordinates((x1, y1), points[0]) != source.get_connector_direction(): points.reverse() - #points[0] -> sink connector should not be in the direction of sink - if Utils.get_angle_from_coordinates(points[0], (x2, y2)) == sink.get_connector_direction(): points.reverse() - #points[0] -> source connector should not be in the direction of source - if Utils.get_angle_from_coordinates(points[0], (x1, y1)) == source.get_connector_direction(): points.reverse() - #create right-angled connector - self.add_line((x1, y1), points[0]) - self.add_line((x2, y2), points[0]) - - def draw(self, gc, window): - """ - Draw the connection. - @param gc the graphics context - @param window the gtk window to draw on - """ - sink = self.get_sink() - source = self.get_source() - #check for changes - if self._sink_rot != sink.get_rotation() or self._source_rot != source.get_rotation(): self.update() - elif self._sink_coor != sink.get_coordinate() or self._source_coor != source.get_coordinate(): self._update_after_move() - #cache values - self._sink_rot = sink.get_rotation() - self._source_rot = source.get_rotation() - self._sink_coor = sink.get_coordinate() - self._source_coor = source.get_coordinate() - #draw - if self.is_highlighted(): border_color = Colors.HIGHLIGHT_COLOR - elif self.get_enabled(): border_color = Colors.CONNECTION_ENABLED_COLOR - else: border_color = Colors.CONNECTION_DISABLED_COLOR - Element.draw(self, gc, window, bg_color=None, border_color=border_color) - #draw arrow on sink port - gc.set_foreground(self._arrow_color) - window.draw_polygon(gc, True, self._arrow) diff --git a/grc/src/platforms/gui/Constants.py b/grc/src/platforms/gui/Constants.py deleted file mode 100644 index 90c8c1c38..000000000 --- a/grc/src/platforms/gui/Constants.py +++ /dev/null @@ -1,44 +0,0 @@ -""" -Copyright 2008, 2009 Free Software Foundation, Inc. -This file is part of GNU Radio - -GNU Radio Companion is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or (at your option) any later version. - -GNU Radio Companion is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA -""" - -#label constraint dimensions -LABEL_SEPARATION = 3 -BLOCK_LABEL_PADDING = 7 -PORT_LABEL_PADDING = 2 -#port constraint dimensions -PORT_SEPARATION = 17 -PORT_BORDER_SEPARATION = 9 -PORT_MIN_WIDTH = 20 -#minimal length of connector -CONNECTOR_EXTENSION_MINIMAL = 11 -#increment length for connector -CONNECTOR_EXTENSION_INCREMENT = 11 -#connection arrow dimensions -CONNECTOR_ARROW_BASE = 13 -CONNECTOR_ARROW_HEIGHT = 17 -#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. -BORDER_PROXIMITY_SENSITIVITY = 50 -#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. -SCROLL_DISTANCE = 15 -#How close the mouse click can be to a line and register a connection select. -LINE_SELECT_SENSITIVITY = 5 diff --git a/grc/src/platforms/gui/Element.py b/grc/src/platforms/gui/Element.py deleted file mode 100644 index 315191723..000000000 --- a/grc/src/platforms/gui/Element.py +++ /dev/null @@ -1,226 +0,0 @@ -""" -Copyright 2007 Free Software Foundation, Inc. -This file is part of GNU Radio - -GNU Radio Companion is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or (at your option) any later version. - -GNU Radio Companion is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA -""" - -import Colors -import pygtk -pygtk.require('2.0') -import gtk -import pango -from Constants import LINE_SELECT_SENSITIVITY -from Constants import POSSIBLE_ROTATIONS - -class Element(object): - """ - GraphicalElement is the base class for all graphical elements. - It contains an X,Y coordinate, a list of rectangular areas that the element occupies, - and methods to detect selection of those areas. - """ - - def __init__(self, *args, **kwargs): - """ - Make a new list of rectangular areas and lines, and set the coordinate and the rotation. - """ - self.set_rotation(POSSIBLE_ROTATIONS[0]) - self.set_coordinate((0, 0)) - self.clear() - self.set_highlighted(False) - - def is_horizontal(self, rotation=None): - """ - Is this element horizontal? - If rotation is None, use this element's rotation. - @param rotation the optional rotation - @return true if rotation is horizontal - """ - rotation = rotation or self.get_rotation() - return rotation in (0, 180) - - def is_vertical(self, rotation=None): - """ - Is this element vertical? - If rotation is None, use this element's rotation. - @param rotation the optional rotation - @return true if rotation is vertical - """ - rotation = rotation or self.get_rotation() - return rotation in (90, 270) - - def draw(self, gc, window, border_color, bg_color): - """ - Draw in the given window. - @param gc the graphics context - @param window the gtk window to draw on - @param border_color the color for lines and rectangle borders - @param bg_color the color for the inside of the rectangle - """ - X,Y = self.get_coordinate() - for (rX,rY),(W,H) in self.areas_dict[self.get_rotation()]: - aX = X + rX - aY = Y + rY - gc.set_foreground(bg_color) - window.draw_rectangle(gc, True, aX, aY, W, H) - gc.set_foreground(border_color) - window.draw_rectangle(gc, False, aX, aY, W, H) - for (x1, y1),(x2, y2) in self.lines_dict[self.get_rotation()]: - gc.set_foreground(border_color) - window.draw_line(gc, X+x1, Y+y1, X+x2, Y+y2) - - def rotate(self, rotation): - """ - Rotate all of the areas by 90 degrees. - @param rotation multiple of 90 degrees - """ - self.set_rotation((self.get_rotation() + rotation)%360) - - def clear(self): - """Empty the lines and areas.""" - self.areas_dict = dict((rotation, list()) for rotation in POSSIBLE_ROTATIONS) - self.lines_dict = dict((rotation, list()) for rotation in POSSIBLE_ROTATIONS) - - def set_coordinate(self, coor): - """ - Set the reference coordinate. - @param coor the coordinate tuple (x,y) - """ - self.coor = coor - - def get_parent(self): - """ - Get the parent of this element. - @return the parent - """ - return self.parent - - def set_highlighted(self, highlighted): - """ - Set the highlight status. - @param highlighted true to enable highlighting - """ - self.highlighted = highlighted - - def is_highlighted(self): - """ - Get the highlight status. - @return true if highlighted - """ - return self.highlighted - - def get_coordinate(self): - """Get the coordinate. - @return the coordinate tuple (x,y) - """ - return self.coor - - def move(self, delta_coor): - """ - Move the element by adding the delta_coor to the current coordinate. - @param delta_coor (delta_x,delta_y) tuple - """ - deltaX, deltaY = delta_coor - X, Y = self.get_coordinate() - self.set_coordinate((X+deltaX, Y+deltaY)) - - def add_area(self, rel_coor, area, rotation=None): - """ - Add an area to the area list. - An area is actually a coordinate relative to the main coordinate - with a width/height pair relative to the area coordinate. - A positive width is to the right of the coordinate. - A positive height is above the coordinate. - The area is associated with a rotation. - If rotation is not specified, the element's current rotation is used. - @param rel_coor (x,y) offset from this element's coordinate - @param area (width,height) tuple - @param rotation rotation in degrees - """ - self.areas_dict[rotation or self.get_rotation()].append((rel_coor, area)) - - def add_line(self, rel_coor1, rel_coor2, rotation=None): - """ - Add a line to the line list. - A line is defined by 2 relative coordinates. - Lines must be horizontal or vertical. - The line is associated with a rotation. - If rotation is not specified, the element's current rotation is used. - @param rel_coor1 relative (x1,y1) tuple - @param rel_coor2 relative (x2,y2) tuple - @param rotation rotation in degrees - """ - self.lines_dict[rotation or self.get_rotation()].append((rel_coor1, rel_coor2)) - - def what_is_selected(self, coor, coor_m=None): - """ - One coordinate specified: - Is this element selected at given coordinate? - ie: is the coordinate encompassed by one of the areas or lines? - Both coordinates specified: - Is this element within the rectangular region defined by both coordinates? - ie: do any area corners or line endpoints fall within the region? - @param coor the selection coordinate, tuple x, y - @param coor_m an additional selection coordinate. - @return self if one of the areas/lines encompasses coor, else None. - """ - #function to test if p is between a and b (inclusive) - in_between = lambda p, a, b: p >= min(a, b) and p <= max(a, b) - #relative coordinate - x, y = [a-b for a,b in zip(coor, self.get_coordinate())] - if coor_m: - x_m, y_m = [a-b for a,b in zip(coor_m, self.get_coordinate())] - #handle rectangular areas - for (x1,y1), (w,h) in self.areas_dict[self.get_rotation()]: - if in_between(x1, x, x_m) and in_between(y1, y, y_m) or \ - in_between(x1+w, x, x_m) and in_between(y1, y, y_m) or \ - in_between(x1, x, x_m) and in_between(y1+h, y, y_m) or \ - in_between(x1+w, x, x_m) and in_between(y1+h, y, y_m): - return self - #handle horizontal or vertical lines - for (x1, y1), (x2, y2) in self.lines_dict[self.get_rotation()]: - if in_between(x1, x, x_m) and in_between(y1, y, y_m) or \ - in_between(x2, x, x_m) and in_between(y2, y, y_m): - return self - return None - else: - #handle rectangular areas - for (x1,y1), (w,h) in self.areas_dict[self.get_rotation()]: - if in_between(x, x1, x1+w) and in_between(y, y1, y1+h): return self - #handle horizontal or vertical lines - for (x1, y1), (x2, y2) in self.lines_dict[self.get_rotation()]: - if x1 == x2: x1, x2 = x1-LINE_SELECT_SENSITIVITY, x2+LINE_SELECT_SENSITIVITY - if y1 == y2: y1, y2 = y1-LINE_SELECT_SENSITIVITY, y2+LINE_SELECT_SENSITIVITY - if in_between(x, x1, x2) and in_between(y, y1, y2): return self - return None - - def get_rotation(self): - """ - Get the rotation in degrees. - @return the rotation - """ - return self.rotation - - def set_rotation(self, rotation): - """ - Set the rotation in degrees. - @param rotation the rotation""" - if rotation not in POSSIBLE_ROTATIONS: - raise Exception('"%s" is not one of the possible rotations: (%s)'%(rotation, POSSIBLE_ROTATIONS)) - self.rotation = rotation - - def update(self): - """Do nothing for the update. Dummy method.""" - pass diff --git a/grc/src/platforms/gui/FlowGraph.py b/grc/src/platforms/gui/FlowGraph.py deleted file mode 100644 index 40f391811..000000000 --- a/grc/src/platforms/gui/FlowGraph.py +++ /dev/null @@ -1,488 +0,0 @@ -""" -Copyright 2007, 2008, 2009 Free Software Foundation, Inc. -This file is part of GNU Radio - -GNU Radio Companion is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or (at your option) any later version. - -GNU Radio Companion is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA -""" - -from Constants import SCROLL_PROXIMITY_SENSITIVITY, SCROLL_DISTANCE -from ... gui.Actions import \ - ELEMENT_CREATE, ELEMENT_SELECT, \ - BLOCK_PARAM_MODIFY, BLOCK_MOVE, \ - ELEMENT_DELETE -import Colors -import Utils -from Element import Element -from .. base import FlowGraph as _FlowGraph -import pygtk -pygtk.require('2.0') -import gtk -import random -from ... gui import Messages - -class FlowGraph(Element): - """ - FlowGraph is the data structure to store graphical signal blocks, - graphical inputs and outputs, - and the connections between inputs and outputs. - """ - - def __init__(self, *args, **kwargs): - """ - FlowGraph contructor. - Create a list for signal blocks and connections. Connect mouse handlers. - """ - Element.__init__(self) - #when is the flow graph selected? (used by keyboard event handler) - self.is_selected = lambda: bool(self.get_selected_elements()) - #important vars dealing with mouse event tracking - self.element_moved = False - self.mouse_pressed = False - self.unselect() - self.press_coor = (0, 0) - #selected ports - self._old_selected_port = None - self._new_selected_port = None - - ########################################################################### - # Access Drawing Area - ########################################################################### - def get_drawing_area(self): return self.drawing_area - def queue_draw(self): self.get_drawing_area().queue_draw() - def get_size(self): return self.get_drawing_area().get_size_request() - def set_size(self, *args): self.get_drawing_area().set_size_request(*args) - def get_scroll_pane(self): return self.drawing_area.get_parent() - def get_ctrl_mask(self): return self.drawing_area.ctrl_mask - def new_pixmap(self, *args): return self.get_drawing_area().new_pixmap(*args) - - def add_new_block(self, key, coor=None): - """ - Add a block of the given key to this flow graph. - @param key the block key - @param coor an optional coordinate or None for random - """ - id = self._get_unique_id(key) - #calculate the position coordinate - h_adj = self.get_scroll_pane().get_hadjustment() - v_adj = self.get_scroll_pane().get_vadjustment() - if coor is None: coor = ( - int(random.uniform(.25, .75)*h_adj.page_size + h_adj.get_value()), - int(random.uniform(.25, .75)*v_adj.page_size + v_adj.get_value()), - ) - #get the new block - block = self.get_new_block(key) - block.set_coordinate(coor) - block.set_rotation(0) - block.get_param('id').set_value(id) - self.handle_states(ELEMENT_CREATE) - - ########################################################################### - # Copy Paste - ########################################################################### - def copy_to_clipboard(self): - """ - Copy the selected blocks and connections into the clipboard. - @return the clipboard - """ - #get selected blocks - blocks = self.get_selected_blocks() - if not blocks: return None - #calc x and y min - x_min, y_min = blocks[0].get_coordinate() - for block in blocks: - x, y = block.get_coordinate() - x_min = min(x, x_min) - y_min = min(y, y_min) - #get connections between selected blocks - connections = filter( - lambda c: c.get_source().get_parent() in blocks and c.get_sink().get_parent() in blocks, - self.get_connections(), - ) - clipboard = ( - (x_min, y_min), - [block.export_data() for block in blocks], - [connection.export_data() for connection in connections], - ) - return clipboard - - def paste_from_clipboard(self, clipboard): - """ - Paste the blocks and connections from the clipboard. - @param clipboard the nested data of blocks, connections - """ - selected = set() - (x_min, y_min), blocks_n, connections_n = clipboard - old_id2block = dict() - #recalc the position - h_adj = self.get_scroll_pane().get_hadjustment() - v_adj = self.get_scroll_pane().get_vadjustment() - x_off = h_adj.get_value() - x_min + h_adj.page_size/4 - y_off = v_adj.get_value() - y_min + v_adj.page_size/4 - #create blocks - for block_n in blocks_n: - block_key = block_n.find('key') - if block_key == 'options': continue - block = self.get_new_block(block_key) - selected.add(block) - #set params - params_n = block_n.findall('param') - for param_n in params_n: - param_key = param_n.find('key') - param_value = param_n.find('value') - #setup id parameter - if param_key == 'id': - old_id2block[param_value] = block - #if the block id is not unique, get a new block id - if param_value in [block.get_id() for block in self.get_blocks()]: - param_value = self._get_unique_id(param_value) - #set value to key - block.get_param(param_key).set_value(param_value) - #move block to offset coordinate - block.move((x_off, y_off)) - #update before creating connections - self.update() - #create connections - for connection_n in connections_n: - source = old_id2block[connection_n.find('source_block_id')].get_source(connection_n.find('source_key')) - sink = old_id2block[connection_n.find('sink_block_id')].get_sink(connection_n.find('sink_key')) - self.connect(source, sink) - #set all pasted elements selected - for block in selected: selected = selected.union(set(block.get_connections())) - self._selected_elements = list(selected) - - ########################################################################### - # Modify Selected - ########################################################################### - def type_controller_modify_selected(self, direction): - """ - Change the registered type controller for the selected signal blocks. - @param direction +1 or -1 - @return true for change - """ - return any([sb.type_controller_modify(direction) for sb in self.get_selected_blocks()]) - - def port_controller_modify_selected(self, direction): - """ - Change port controller for the selected signal blocks. - @param direction +1 or -1 - @return true for changed - """ - return any([sb.port_controller_modify(direction) for sb in self.get_selected_blocks()]) - - def enable_selected(self, enable): - """ - Enable/disable the selected blocks. - @param enable true to enable - @return true if changed - """ - changed = False - for selected_block in self.get_selected_blocks(): - if selected_block.get_enabled() != enable: - selected_block.set_enabled(enable) - changed = True - return changed - - def move_selected(self, delta_coordinate): - """ - Move the element and by the change in coordinates. - @param delta_coordinate the change in coordinates - """ - for selected_block in self.get_selected_blocks(): - selected_block.move(delta_coordinate) - self.element_moved = True - - def rotate_selected(self, rotation): - """ - Rotate the selected blocks by multiples of 90 degrees. - @param rotation the rotation in degrees - @return true if changed, otherwise false. - """ - if not self.get_selected_blocks(): return False - #initialize min and max coordinates - min_x, min_y = self.get_selected_block().get_coordinate() - max_x, max_y = self.get_selected_block().get_coordinate() - #rotate each selected block, and find min/max coordinate - for selected_block in self.get_selected_blocks(): - selected_block.rotate(rotation) - #update the min/max coordinate - x, y = selected_block.get_coordinate() - min_x, min_y = min(min_x, x), min(min_y, y) - max_x, max_y = max(max_x, x), max(max_y, y) - #calculate center point of slected blocks - ctr_x, ctr_y = (max_x + min_x)/2, (max_y + min_y)/2 - #rotate the blocks around the center point - for selected_block in self.get_selected_blocks(): - x, y = selected_block.get_coordinate() - x, y = Utils.get_rotated_coordinate((x - ctr_x, y - ctr_y), rotation) - selected_block.set_coordinate((x + ctr_x, y + ctr_y)) - return True - - def remove_selected(self): - """ - Remove selected elements - @return true if changed. - """ - changed = False - for selected_element in self.get_selected_elements(): - self.remove_element(selected_element) - changed = True - return changed - - def draw(self, gc, window): - """ - Draw the background and grid if enabled. - Draw all of the elements in this flow graph onto the pixmap. - Draw the pixmap to the drawable window of this flow graph. - """ - W,H = self.get_size() - #draw the background - gc.set_foreground(Colors.FLOWGRAPH_BACKGROUND_COLOR) - window.draw_rectangle(gc, True, 0, 0, W, H) - #draw multi select rectangle - if self.mouse_pressed and (not self.get_selected_elements() or self.get_ctrl_mask()): - #coordinates - x1, y1 = self.press_coor - x2, y2 = self.get_coordinate() - #calculate top-left coordinate and width/height - x, y = int(min(x1, x2)), int(min(y1, y2)) - w, h = int(abs(x1 - x2)), int(abs(y1 - y2)) - #draw - gc.set_foreground(Colors.HIGHLIGHT_COLOR) - window.draw_rectangle(gc, True, x, y, w, h) - gc.set_foreground(Colors.BORDER_COLOR) - window.draw_rectangle(gc, False, x, y, w, h) - #draw blocks on top of connections - for element in self.get_connections() + self.get_blocks(): - element.draw(gc, window) - #draw selected blocks on top of selected connections - for selected_element in self.get_selected_connections() + self.get_selected_blocks(): - selected_element.draw(gc, window) - - def update_selected(self): - """ - Remove deleted elements from the selected elements list. - Update highlighting so only the selected are highlighted. - """ - selected_elements = self.get_selected_elements() - elements = self.get_elements() - #remove deleted elements - for selected in selected_elements: - if selected in elements: continue - selected_elements.remove(selected) - #update highlighting - for element in elements: - element.set_highlighted(element in selected_elements) - - def update(self): - """ - Call update on all elements. - """ - for element in self.get_elements(): element.update() - - ########################################################################## - ## Get Selected - ########################################################################## - def unselect(self): - """ - Set selected elements to an empty set. - """ - self._selected_elements = [] - - def what_is_selected(self, coor, coor_m=None): - """ - What is selected? - At the given coordinate, return the elements found to be selected. - If coor_m is unspecified, return a list of only the first element found to be selected: - Iterate though the elements backwards since top elements are at the end of the list. - If an element is selected, place it at the end of the list so that is is drawn last, - and hence on top. Update the selected port information. - @param coor the coordinate of the mouse click - @param coor_m the coordinate for multi select - @return the selected blocks and connections or an empty list - """ - selected_port = None - selected = set() - #check the elements - for element in reversed(self.get_elements()): - selected_element = element.what_is_selected(coor, coor_m) - if not selected_element: continue - #update the selected port information - if selected_element.is_port(): - if not coor_m: selected_port = selected_element - selected_element = selected_element.get_parent() - selected.add(selected_element) - #place at the end of the list - self.get_elements().remove(element) - self.get_elements().append(element) - #single select mode, break - if not coor_m: break - #update selected ports - self._old_selected_port = self._new_selected_port - self._new_selected_port = selected_port - return list(selected) - - def get_selected_connections(self): - """ - Get a group of selected connections. - @return sub set of connections in this flow graph - """ - selected = set() - for selected_element in self.get_selected_elements(): - if selected_element.is_connection(): selected.add(selected_element) - return list(selected) - - def get_selected_blocks(self): - """ - Get a group of selected blocks. - @return sub set of blocks in this flow graph - """ - selected = set() - for selected_element in self.get_selected_elements(): - if selected_element.is_block(): selected.add(selected_element) - return list(selected) - - def get_selected_block(self): - """ - Get the selected block when a block or port is selected. - @return a block or None - """ - return self.get_selected_blocks() and self.get_selected_blocks()[0] or None - - def get_selected_elements(self): - """ - Get the group of selected elements. - @return sub set of elements in this flow graph - """ - return self._selected_elements - - def get_selected_element(self): - """ - Get the selected element. - @return a block, port, or connection or None - """ - return self.get_selected_elements() and self.get_selected_elements()[0] or None - - def update_selected_elements(self): - """ - Update the selected elements. - The update behavior depends on the state of the mouse button. - When the mouse button pressed the selection will change when - the control mask is set or the new selection is not in the current group. - When the mouse button is released the selection will change when - the mouse has moved and the control mask is set or the current group is empty. - Attempt to make a new connection if the old and ports are filled. - If the control mask is set, merge with the current elements. - """ - selected_elements = None - if self.mouse_pressed: - new_selections = self.what_is_selected(self.get_coordinate()) - #update the selections if the new selection is not in the current selections - #allows us to move entire selected groups of elements - if self.get_ctrl_mask() or not ( - new_selections and new_selections[0] in self.get_selected_elements() - ): selected_elements = new_selections - else: #called from a mouse release - if not self.element_moved and (not self.get_selected_elements() or self.get_ctrl_mask()): - selected_elements = self.what_is_selected(self.get_coordinate(), self.press_coor) - #this selection and the last were ports, try to connect them - if self._old_selected_port and self._new_selected_port and \ - self._old_selected_port is not self._new_selected_port: - try: - self.connect(self._old_selected_port, self._new_selected_port) - self.handle_states(ELEMENT_CREATE) - except: Messages.send_fail_connection() - self._old_selected_port = None - self._new_selected_port = None - return - #update selected elements - if selected_elements is None: return - old_elements = set(self.get_selected_elements()) - self._selected_elements = list(set(selected_elements)) - new_elements = set(self.get_selected_elements()) - #if ctrl, set the selected elements to the union - intersection of old and new - if self.get_ctrl_mask(): - self._selected_elements = list( - set.union(old_elements, new_elements) - set.intersection(old_elements, new_elements) - ) - self.handle_states(ELEMENT_SELECT) - - ########################################################################## - ## Event Handlers - ########################################################################## - def handle_mouse_button_press(self, left_click, double_click, coordinate): - """ - A mouse button is pressed, only respond to left clicks. - Find the selected element. Attempt a new connection if possible. - Open the block params window on a double click. - Update the selection state of the flow graph. - """ - if not left_click: return - self.press_coor = coordinate - self.set_coordinate(coordinate) - self.time = 0 - self.mouse_pressed = True - if double_click: self.unselect() - self.update_selected_elements() - #double click detected, bring up params dialog if possible - if double_click and self.get_selected_block(): - self.mouse_pressed = False - self.handle_states(BLOCK_PARAM_MODIFY) - - def handle_mouse_button_release(self, left_click, coordinate): - """ - A mouse button is released, record the state. - """ - if not left_click: return - self.set_coordinate(coordinate) - self.time = 0 - self.mouse_pressed = False - if self.element_moved: - self.handle_states(BLOCK_MOVE) - self.element_moved = False - self.update_selected_elements() - - def handle_mouse_motion(self, coordinate): - """ - The mouse has moved, respond to mouse dragging. - Move a selected element to the new coordinate. - Auto-scroll the scroll bars at the boundaries. - """ - #to perform a movement, the mouse must be pressed, no pending events - if gtk.events_pending() or not self.mouse_pressed: return - #perform autoscrolling - width, height = self.get_size() - x, y = coordinate - h_adj = self.get_scroll_pane().get_hadjustment() - v_adj = self.get_scroll_pane().get_vadjustment() - for pos, length, adj, adj_val, adj_len in ( - (x, width, h_adj, h_adj.get_value(), h_adj.page_size), - (y, height, v_adj, v_adj.get_value(), v_adj.page_size), - ): - #scroll if we moved near the border - if pos-adj_val > adj_len-SCROLL_PROXIMITY_SENSITIVITY and adj_val+SCROLL_DISTANCE < length-adj_len: - adj.set_value(adj_val+SCROLL_DISTANCE) - adj.emit('changed') - elif pos-adj_val < SCROLL_PROXIMITY_SENSITIVITY: - adj.set_value(adj_val-SCROLL_DISTANCE) - adj.emit('changed') - #remove the connection if selected in drag event - if len(self.get_selected_elements()) == 1 and self.get_selected_element().is_connection(): - self.handle_states(ELEMENT_DELETE) - #move the selected elements and record the new coordinate - X, Y = self.get_coordinate() - if not self.get_ctrl_mask(): self.move_selected((int(x - X), int(y - Y))) - self.set_coordinate((x, y)) - #queue draw for animation - self.queue_draw() diff --git a/grc/src/platforms/gui/Makefile.am b/grc/src/platforms/gui/Makefile.am deleted file mode 100644 index 2e3972ef3..000000000 --- a/grc/src/platforms/gui/Makefile.am +++ /dev/null @@ -1,37 +0,0 @@ -# -# Copyright 2008 Free Software Foundation, Inc. -# -# This file is part of GNU Radio -# -# GNU Radio is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 3, or (at your option) -# any later version. -# -# GNU Radio is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with GNU Radio; see the file COPYING. If not, write to -# the Free Software Foundation, Inc., 51 Franklin Street, -# Boston, MA 02110-1301, USA. -# - -include $(top_srcdir)/grc/Makefile.inc - -ourpythondir = $(grc_src_prefix)/platforms/gui - -ourpython_PYTHON = \ - Block.py \ - Colors.py \ - Constants.py \ - Connection.py \ - Element.py \ - FlowGraph.py \ - Param.py \ - Platform.py \ - Port.py \ - Utils.py \ - __init__.py diff --git a/grc/src/platforms/gui/Param.py b/grc/src/platforms/gui/Param.py deleted file mode 100644 index 33a9b1f52..000000000 --- a/grc/src/platforms/gui/Param.py +++ /dev/null @@ -1,103 +0,0 @@ -""" -Copyright 2007, 2008, 2009 Free Software Foundation, Inc. -This file is part of GNU Radio - -GNU Radio Companion is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or (at your option) any later version. - -GNU Radio Companion is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA -""" - -import Utils -from Element import Element -import pygtk -pygtk.require('2.0') -import gtk - -PARAM_MARKUP_TMPL="""\ -#set $foreground = $param.is_valid() and 'black' or 'red' -#set $value = not $param.is_valid() and 'error' or repr($param) -$encode($param.get_name()): $encode($value)""" - -PARAM_LABEL_MARKUP_TMPL="""\ -#set $foreground = $param.is_valid() and 'black' or 'red' -#set $underline = $has_cb and 'low' or 'none' -$encode($param.get_name())""" - -TIP_MARKUP_TMPL="""\ -Key: $param.get_key() -Type: $param.get_type() -#if $param.is_valid() -Value: $param.evaluate() -#elif len($param.get_error_messages()) == 1 -Error: $(param.get_error_messages()[0]) -#else -Error: - #for $error_msg in $param.get_error_messages() - * $error_msg - #end for -#end if""" - -class Param(Element): - """The graphical parameter.""" - - def update(self): - """ - Called when an external change occurs. - Update the graphical input by calling the change handler. - """ - if hasattr(self, '_input'): self._handle_changed() - - def get_input_object(self, callback=None): - """ - Get the graphical gtk object to represent this parameter. - Create the input object with this data type and the handle changed method. - @param callback a function of one argument(this param) to be called from the change handler - @return gtk input object - """ - self._callback = callback - self._input = self.get_input_class()(self, self._handle_changed) - if not self._callback: self.update() - return self._input - - def _handle_changed(self, widget=None): - """ - When the input changes, write the inputs to the data type. - Finish by calling the exteral callback. - """ - self.set_value(self._input.get_text()) - #is param is involved in a callback? #FIXME: messy - has_cb = \ - hasattr(self.get_parent(), 'get_callbacks') and \ - filter(lambda c: self.get_key() in c, self.get_parent()._callbacks) - self._input.set_markup(Utils.parse_template(PARAM_LABEL_MARKUP_TMPL, param=self, has_cb=has_cb)) - #hide/show - if self.get_hide() == 'all': self._input.hide_all() - else: self._input.show_all() - #set the color - self._input.set_color(self.get_color()) - #set the tooltip - if self._input.tp: self._input.tp.set_tip( - self._input.entry, - Utils.parse_template(TIP_MARKUP_TMPL, param=self).strip(), - ) - #execute the external callback - if self._callback: self._callback(self) - - def get_layout(self): - """ - Create a layout based on the current markup. - @return the pango layout - """ - layout = gtk.DrawingArea().create_pango_layout('') - layout.set_markup(Utils.parse_template(PARAM_MARKUP_TMPL, param=self)) - return layout diff --git a/grc/src/platforms/gui/Platform.py b/grc/src/platforms/gui/Platform.py deleted file mode 100644 index a32b0209f..000000000 --- a/grc/src/platforms/gui/Platform.py +++ /dev/null @@ -1,48 +0,0 @@ -""" -Copyright 2008 Free Software Foundation, Inc. -This file is part of GNU Radio - -GNU Radio Companion is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or (at your option) any later version. - -GNU Radio Companion is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA -""" - -from FlowGraph import FlowGraph -from Connection import Connection -from Block import Block -from Port import Port -from Param import Param - -def conjoin_classes(name, c1, c2): - exec(""" -class %s(c1, c2): - def __init__(self, *args, **kwargs): - c1.__init__(self, *args, **kwargs) - c2.__init__(self, *args, **kwargs) -"""%name, locals()) - return locals()[name] - -def Platform(platform): - #combine with gui class - for attr, value in ( - ('FlowGraph', FlowGraph), - ('Connection', Connection), - ('Block', Block), - ('Source', Port), - ('Sink', Port), - ('Param', Param), - ): - old_value = getattr(platform, attr) - c = conjoin_classes(attr, old_value, value) - setattr(platform, attr, c) - return platform diff --git a/grc/src/platforms/gui/Port.py b/grc/src/platforms/gui/Port.py deleted file mode 100644 index d1f36f8b9..000000000 --- a/grc/src/platforms/gui/Port.py +++ /dev/null @@ -1,190 +0,0 @@ -""" -Copyright 2007 Free Software Foundation, Inc. -This file is part of GNU Radio - -GNU Radio Companion is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or (at your option) any later version. - -GNU Radio Companion is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -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, \ - PORT_LABEL_PADDING, PORT_MIN_WIDTH -import Utils -import Colors -import pygtk -pygtk.require('2.0') -import gtk - -PORT_MARKUP_TMPL="""\ -$encode($port.get_name())""" - -class Port(Element): - """The graphical port.""" - - def __init__(self, *args, **kwargs): - """ - Port contructor. - Create list of connector coordinates. - """ - Element.__init__(self) - self.connector_coordinates = dict() - - def update(self): - """Create new areas and labels for the port.""" - self.clear() - #get current rotation - rotation = self.get_rotation() - #get all sibling ports - if self.is_source(): ports = self.get_parent().get_sources() - elif self.is_sink(): ports = self.get_parent().get_sinks() - #get the max width - self.W = max([port.W for port in ports] + [PORT_MIN_WIDTH]) - #get a numeric index for this port relative to its sibling ports - index = ports.index(self) - length = len(ports) - #reverse the order of ports for these rotations - if rotation in (180, 270): index = length-index-1 - offset = (self.get_parent().H - length*self.H - (length-1)*PORT_SEPARATION)/2 - #create areas and connector coordinates - if (self.is_sink() and rotation == 0) or (self.is_source() and rotation == 180): - x = -1*self.W - y = (PORT_SEPARATION+self.H)*index+offset - self.add_area((x, y), (self.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+self.H)*index+offset - self.add_area((x, y), (self.W, self.H)) - self._connector_coordinate = (x+1+self.W, y+self.H/2) - elif (self.is_source() and rotation == 90) or (self.is_sink() and rotation == 270): - y = -1*self.W - x = (PORT_SEPARATION+self.H)*index+offset - self.add_area((x, y), (self.H, self.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+self.H)*index+offset - self.add_area((x, y), (self.H, self.W)) - self._connector_coordinate = (x+self.H/2, y+1+self.W) - #the connector length - self._connector_length = CONNECTOR_EXTENSION_MINIMAL + CONNECTOR_EXTENSION_INCREMENT*index - - def _create_labels(self): - """Create the labels for the socket.""" - self._bg_color = Colors.get_color(self.get_color()) - #create the layout - layout = gtk.DrawingArea().create_pango_layout('') - layout.set_markup(Utils.parse_template(PORT_MARKUP_TMPL, port=self)) - self.w, self.h = layout.get_pixel_size() - self.W, self.H = 2*PORT_LABEL_PADDING+self.w, 2*PORT_LABEL_PADDING+self.h - #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 the images - self.horizontal_label = image = pixmap.get_image(0, 0, self.w, self.h) - if self.is_vertical(): - self.vertical_label = vimage = gtk.gdk.Image(gtk.gdk.IMAGE_NORMAL, pixmap.get_visual(), self.h, self.w) - for i in range(self.w): - for j in range(self.h): vimage.put_pixel(j, self.w-i-1, image.get_pixel(i, j)) - - def draw(self, gc, window): - """ - Draw the socket with a label. - @param gc the graphics context - @param window the gtk window to draw on - """ - Element.draw( - self, gc, window, bg_color=self._bg_color, - border_color=self.is_highlighted() and Colors.HIGHLIGHT_COLOR or Colors.BORDER_COLOR, - ) - X,Y = self.get_coordinate() - (x,y),(w,h) = self.areas_dict[self.get_rotation()][0] #use the first area's sizes to place the labels - if self.is_horizontal(): - window.draw_image(gc, self.horizontal_label, 0, 0, x+X+(self.W-self.w)/2, y+Y+(self.H-self.h)/2, -1, -1) - elif self.is_vertical(): - window.draw_image(gc, self.vertical_label, 0, 0, x+X+(self.H-self.h)/2, y+Y+(self.W-self.w)/2, -1, -1) - - def get_connector_coordinate(self): - """ - Get the coordinate where connections may attach to. - @return the connector coordinate (x, y) tuple - """ - x,y = self._connector_coordinate - X,Y = self.get_coordinate() - return (x+X, y+Y) - - def get_connector_direction(self): - """ - Get the direction that the socket points: 0,90,180,270. - This is the rotation degree if the socket is an output or - the rotation degree + 180 if the socket is an input. - @return the direction in degrees - """ - if self.is_source(): return self.get_rotation() - elif self.is_sink(): return (self.get_rotation() + 180)%360 - - def get_connector_length(self): - """ - Get the length of the connector. - The connector length increases as the port index changes. - @return the length in pixels - """ - return self._connector_length - - def get_rotation(self): - """ - Get the parent's rotation rather than self. - @return the parent's rotation - """ - return self.get_parent().get_rotation() - - def move(self, delta_coor): - """ - Move the parent rather than self. - @param delta_corr the (delta_x, delta_y) tuple - """ - self.get_parent().move(delta_coor) - - def rotate(self, direction): - """ - Rotate the parent rather than self. - @param direction degrees to rotate - """ - self.get_parent().rotate(direction) - - def get_coordinate(self): - """ - Get the parent's coordinate rather than self. - @return the parents coordinate - """ - return self.get_parent().get_coordinate() - - def set_highlighted(self, highlight): - """ - Set the parent highlight rather than self. - @param highlight true to enable highlighting - """ - self.get_parent().set_highlighted(highlight) - - def is_highlighted(self): - """ - Get the parent's is highlight rather than self. - @return the parent's highlighting status - """ - return self.get_parent().is_highlighted() diff --git a/grc/src/platforms/gui/Utils.py b/grc/src/platforms/gui/Utils.py deleted file mode 100644 index ee6dc6cdc..000000000 --- a/grc/src/platforms/gui/Utils.py +++ /dev/null @@ -1,82 +0,0 @@ -""" -Copyright 2008, 2009 Free Software Foundation, Inc. -This file is part of GNU Radio - -GNU Radio Companion is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or (at your option) any later version. - -GNU Radio Companion is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA -""" - -from Constants import POSSIBLE_ROTATIONS -from Cheetah.Template import Template - -def get_rotated_coordinate(coor, rotation): - """ - Rotate the coordinate by the given rotation. - @param coor the coordinate x, y tuple - @param rotation the angle in degrees - @return the rotated coordinates - """ - #handles negative angles - rotation = (rotation + 360)%360 - assert rotation in POSSIBLE_ROTATIONS - #determine the number of degrees to rotate - cos_r, sin_r = { - 0: (1, 0), - 90: (0, 1), - 180: (-1, 0), - 270: (0, -1), - }[rotation] - x, y = coor - return (x*cos_r + y*sin_r, -x*sin_r + y*cos_r) - -def get_angle_from_coordinates((x1,y1), (x2,y2)): - """ - Given two points, calculate the vector direction from point1 to point2, directions are multiples of 90 degrees. - @param (x1,y1) the coordinate of point 1 - @param (x2,y2) the coordinate of point 2 - @return the direction in degrees - """ - if y1 == y2:#0 or 180 - if x2 > x1: return 0 - else: return 180 - else:#90 or 270 - if y2 > y1: return 270 - else: return 90 - -def xml_encode(string): - """ - Encode a string into an xml safe string by replacing special characters. - Needed for gtk pango markup in labels. - @param string the input string - @return output string with safe characters - """ - string = str(string) - for char, safe in ( - ('&', '&'), - ('<', '<'), - ('>', '>'), - ('"', '"'), - ("'", '''), - ): string = string.replace(char, safe) - return string - -def parse_template(tmpl_str, **kwargs): - """ - Parse the template string with the given args. - Pass in the xml encode method for pango escape chars. - @param tmpl_str the template as a string - @return a string of the parsed template - """ - kwargs['encode'] = xml_encode - return str(Template(tmpl_str, kwargs)) diff --git a/grc/src/platforms/gui/__init__.py b/grc/src/platforms/gui/__init__.py deleted file mode 100644 index 8b1378917..000000000 --- a/grc/src/platforms/gui/__init__.py +++ /dev/null @@ -1 +0,0 @@ - diff --git a/grc/src/platforms/python/Block.py b/grc/src/platforms/python/Block.py deleted file mode 100644 index 341e5fdc3..000000000 --- a/grc/src/platforms/python/Block.py +++ /dev/null @@ -1,152 +0,0 @@ -""" -Copyright 2008 Free Software Foundation, Inc. -This file is part of GNU Radio - -GNU Radio Companion is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or (at your option) any later version. - -GNU Radio Companion is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA -""" - -from .. base.Block import Block as _Block -from utils import extract_docs - -class Block(_Block): - - ##for make source to keep track of indexes - _source_count = 0 - ##for make sink to keep track of indexes - _sink_count = 0 - - def __init__(self, flow_graph, n): - """ - Make a new block from nested data. - @param flow graph the parent element - @param n the nested odict - @return block a new block - """ - #grab the data - doc = n.find('doc') or '' - imports = map(lambda i: i.strip(), n.findall('import')) - make = n.find('make') - checks = n.findall('check') - callbacks = n.findall('callback') - #build the block - _Block.__init__( - self, - flow_graph=flow_graph, - n=n, - ) - self._doc = doc - self._imports = imports - self._make = make - self._callbacks = callbacks - self._checks = checks - - def validate(self): - """ - Validate this block. - Call the base class validate. - Evaluate the checks: each check must evaluate to True. - Adjust the nports. - """ - _Block.validate(self) - #evaluate the checks - for check in self._checks: - check_res = self.resolve_dependencies(check) - try: - check_eval = self.get_parent().evaluate(check_res) - try: assert check_eval - except AssertionError: self._add_error_message('Check "%s" failed.'%check) - except: self._add_error_message('Check "%s" did not evaluate.'%check) - #adjust nports - for ports, Port in ( - (self._sources, self.get_parent().get_parent().Source), - (self._sinks, self.get_parent().get_parent().Sink), - ): - #how many ports? - num_ports = len(ports) - #do nothing for 0 ports - if not num_ports: continue - #get the nports setting - port0 = ports[str(0)] - nports = port0.get_nports() - #do nothing for no nports - if not nports: continue - #do nothing if nports is already num ports - if nports == num_ports: continue - #remove excess ports and connections - if nports < num_ports: - #remove the connections - for key in map(str, range(nports, num_ports)): - port = ports[key] - for connection in port.get_connections(): - self.get_parent().remove_element(connection) - #remove the ports - for key in map(str, range(nports, num_ports)): ports.pop(key) - continue - #add more ports - if nports > num_ports: - for key in map(str, range(num_ports, nports)): - n = port0._n - n['key'] = key - port = Port(self, n) - ports[key] = port - continue - - def port_controller_modify(self, direction): - """ - Change the port controller. - @param direction +1 or -1 - @return true for change - """ - changed = False - #concat the nports string from the private nports settings of both port0 - nports_str = \ - (self.get_sinks() and self.get_sinks()[0]._nports or '') + \ - (self.get_sources() and self.get_sources()[0]._nports or '') - #modify all params whose keys appear in the nports string - for param in self.get_params(): - if param.is_enum() or param.get_key() not in nports_str: continue - #try to increment the port controller by direction - try: - value = param.evaluate() - value = value + direction - assert 0 < value - param.set_value(value) - changed = True - except: pass - return changed - - def get_doc(self): - doc = self._doc.strip('\n').replace('\\\n', '') - #merge custom doc with doxygen docs - return '\n'.join([doc, extract_docs.extract(self.get_key())]).strip('\n') - - def get_imports(self): - """ - Resolve all import statements. - Split each import statement at newlines. - Combine all import statments into a list. - Filter empty imports. - @return a list of import statements - """ - return filter(lambda i: i, sum(map(lambda i: self.resolve_dependencies(i).split('\n'), self._imports), [])) - - def get_make(self): return self.resolve_dependencies(self._make) - - def get_callbacks(self): - """ - Get a list of function callbacks for this block. - @return a list of strings - """ - return map(lambda c: self.get_id() + '.' + self.resolve_dependencies(c), self._callbacks) diff --git a/grc/src/platforms/python/Connection.py b/grc/src/platforms/python/Connection.py deleted file mode 100644 index f742ff63d..000000000 --- a/grc/src/platforms/python/Connection.py +++ /dev/null @@ -1,34 +0,0 @@ -""" -Copyright 2008 Free Software Foundation, Inc. -This file is part of GNU Radio - -GNU Radio Companion is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or (at your option) any later version. - -GNU Radio Companion is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA -""" - -from .. base.Connection import Connection as _Connection - -class Connection(_Connection): - - def validate(self): - """ - Validate the connections. - The ports must match in type and vector length. - """ - _Connection.validate(self) #checks type - #check vector length - source_vlen = self.get_source().get_vlen() - sink_vlen = self.get_sink().get_vlen() - try: assert(source_vlen == sink_vlen) - except AssertionError: self._add_error_message('Source vector length "%s" does not match sink vector length "%s".'%(source_vlen, sink_vlen)) diff --git a/grc/src/platforms/python/Constants.py.in b/grc/src/platforms/python/Constants.py.in deleted file mode 100644 index 4a43147fa..000000000 --- a/grc/src/platforms/python/Constants.py.in +++ /dev/null @@ -1,54 +0,0 @@ -""" -Copyright 2008 Free Software Foundation, Inc. -This file is part of GNU Radio - -GNU Radio Companion is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or (at your option) any later version. - -GNU Radio Companion is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA -""" - -import os -import sys -import stat -from .. base.Constants import PKG_DIR - -PYEXEC = '@PYTHONW@' - -#setup paths -DOCS_DIR = os.path.join(os.environ.get('GR_DOCDIR', '@docdir@'), 'xml') -DATA_DIR = os.path.join(PKG_DIR, '@reldatadir@') -BLOCKS_DIR = os.path.join(PKG_DIR, '@relblocksdir@') -HIER_BLOCKS_LIB_DIR = os.path.join(os.path.expanduser('~'), '.grc_gnuradio') - -#file creation modes -TOP_BLOCK_FILE_MODE = stat.S_IRUSR | stat.S_IWUSR | stat.S_IXUSR | stat.S_IRGRP | stat.S_IWGRP | stat.S_IXGRP | stat.S_IROTH -HIER_BLOCK_FILE_MODE = stat.S_IRUSR | stat.S_IWUSR | stat.S_IRGRP | stat.S_IWGRP | stat.S_IROTH - -#data files -FLOW_GRAPH_TEMPLATE = os.path.join(DATA_DIR, 'flow_graph.tmpl') -BLOCK_DTD = os.path.join(DATA_DIR, 'block.dtd') -BLOCK_TREE = os.path.join(DATA_DIR, 'block_tree.xml') -DEFAULT_FLOW_GRAPH = os.path.join(DATA_DIR, 'default_flow_graph.grc') - -#coloring -COMPLEX_COLOR_SPEC = '#3399FF' -FLOAT_COLOR_SPEC = '#FF8C69' -INT_COLOR_SPEC = '#00FF99' -SHORT_COLOR_SPEC = '#FFFF66' -BYTE_COLOR_SPEC = '#FF66FF' -COMPLEX_VECTOR_COLOR_SPEC = '#3399AA' -FLOAT_VECTOR_COLOR_SPEC = '#CC8C69' -INT_VECTOR_COLOR_SPEC = '#00CC99' -SHORT_VECTOR_COLOR_SPEC = '#CCCC33' -BYTE_VECTOR_COLOR_SPEC = '#CC66CC' -ID_COLOR_SPEC = '#DDDDDD' diff --git a/grc/src/platforms/python/FlowGraph.py b/grc/src/platforms/python/FlowGraph.py deleted file mode 100644 index d0b997a58..000000000 --- a/grc/src/platforms/python/FlowGraph.py +++ /dev/null @@ -1,162 +0,0 @@ -""" -Copyright 2008, 2009 Free Software Foundation, Inc. -This file is part of GNU Radio - -GNU Radio Companion is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or (at your option) any later version. - -GNU Radio Companion is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA -""" - -from utils import expr_utils -from .. base.FlowGraph import FlowGraph as _FlowGraph -from Block import Block -from Connection import Connection - -def _get_value_expr(variable_block): - """ - Get the expression to evaluate from the value param. - Parameter blocks need to be evaluated so the stringify flag can be determined. - @param variable_block the variable or parameter block - @return the expression string - """ - value_param = variable_block.get_param('value') - if variable_block.get_key() == 'parameter': value_param.evaluate() - return value_param.to_code() - -class FlowGraph(_FlowGraph): - - _eval_cache = dict() - def _eval(self, code, namespace): - """ - Evaluate the code with the given namespace. - @param code a string with python code - @param namespace a dict representing the namespace - @return the resultant object - """ - my_hash = hash(code + str(namespace)) - #cache if does not exist - if not self._eval_cache.has_key(my_hash): - self._eval_cache[my_hash] = eval(code, namespace, namespace) - #return from cache - return self._eval_cache[my_hash] - - def _get_io_signature(self, pad_key): - """ - Get an io signature for this flow graph. - The pad key determines the directionality of the io signature. - @param pad_key a string of pad_source or pad_sink - @return a dict with: type, nports, vlen, size - """ - pads = filter(lambda b: b.get_key() == pad_key, self.get_enabled_blocks()) - if not pads: return { - 'nports': '0', - 'type': '', - 'vlen': '0', - 'size': '0', - } - pad = pads[0] #take only the first, user should not have more than 1 - #load io signature - return { - 'nports': str(pad.get_param('nports').evaluate()), - 'type': str(pad.get_param('type').evaluate()), - 'vlen': str(pad.get_param('vlen').evaluate()), - 'size': pad.get_param('type').get_opt('size'), - } - - def get_input_signature(self): - """ - Get the io signature for the input side of this flow graph. - The io signature with be "0", "0" if no pad source is present. - @return a string tuple of type, num_ports, port_size - """ - return self._get_io_signature('pad_source') - - def get_output_signature(self): - """ - Get the io signature for the output side of this flow graph. - The io signature with be "0", "0" if no pad sink is present. - @return a string tuple of type, num_ports, port_size - """ - return self._get_io_signature('pad_sink') - - def get_imports(self): - """ - Get a set of all import statments in this flow graph namespace. - @return a set of import statements - """ - imports = sum([block.get_imports() for block in self.get_enabled_blocks()], []) - imports = sorted(set(imports)) - return imports - - def get_variables(self): - """ - Get a list of all variables in this flow graph namespace. - Exclude paramterized variables. - @return a sorted list of variable blocks in order of dependency (indep -> dep) - """ - variables = filter(lambda b: b.get_key() in ( - 'variable', 'variable_slider', 'variable_chooser', 'variable_text_box' - ), self.get_enabled_blocks()) - #map var id to variable block - id2var = dict([(var.get_id(), var) for var in variables]) - #map var id to variable code - #variable code is a concatenation of all param code (without the id param) - id2expr = dict([(var.get_id(), var.get_param('value').get_value()) for var in variables]) - #sort according to dependency - sorted_ids = expr_utils.sort_variables(id2expr) - #create list of sorted variable blocks - variables = [id2var[id] for id in sorted_ids] - return variables - - def get_parameters(self): - """ - Get a list of all paramterized variables in this flow graph namespace. - @return a list of paramterized variables - """ - parameters = filter(lambda b: b.get_key() == 'parameter', self.get_enabled_blocks()) - return parameters - - def evaluate(self, expr): - """ - Evaluate the expression. - @param expr the string expression - @throw Exception bad expression - @return the evaluated data - """ - if self.is_flagged(): - self.deflag() - #reload namespace - n = dict() - #load imports - for imp in self.get_imports(): - try: exec imp in n - except: pass - #load parameters - np = dict() - for parameter in self.get_parameters(): - try: - e = self._eval(_get_value_expr(parameter), n) - np[parameter.get_id()] = e - except: pass - n.update(np) #merge param namespace - #load variables - for variable in self.get_variables(): - try: - e = self._eval(_get_value_expr(variable), n) - n[variable.get_id()] = e - except: pass - #make namespace public - self.n = n - #evaluate - e = self._eval(expr, self.n) - return e diff --git a/grc/src/platforms/python/Generator.py b/grc/src/platforms/python/Generator.py deleted file mode 100644 index 93321404a..000000000 --- a/grc/src/platforms/python/Generator.py +++ /dev/null @@ -1,142 +0,0 @@ -""" -Copyright 2008 Free Software Foundation, Inc. -This file is part of GNU Radio - -GNU Radio Companion is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or (at your option) any later version. - -GNU Radio Companion is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA -""" - -import os -import subprocess -from Cheetah.Template import Template -from utils import expr_utils -from Constants import \ - TOP_BLOCK_FILE_MODE, HIER_BLOCK_FILE_MODE, \ - HIER_BLOCKS_LIB_DIR, PYEXEC, \ - FLOW_GRAPH_TEMPLATE -from utils import convert_hier -from ... gui import Messages - -class Generator(object): - - def __init__(self, flow_graph, file_path): - """ - Initialize the generator object. - Determine the file to generate. - @param flow_graph the flow graph object - @param file_path the path to write the file to - """ - self._flow_graph = flow_graph - self._generate_options = self._flow_graph.get_option('generate_options') - if self._generate_options == 'hb': - self._mode = HIER_BLOCK_FILE_MODE - dirname = HIER_BLOCKS_LIB_DIR - else: - self._mode = TOP_BLOCK_FILE_MODE - dirname = os.path.dirname(file_path) - filename = self._flow_graph.get_option('id') + '.py' - self._file_path = os.path.join(dirname, filename) - - def get_file_path(self): return self._file_path - - def write(self): - #do throttle warning - all_keys = ' '.join(map(lambda b: b.get_key(), self._flow_graph.get_enabled_blocks())) - if ('usrp' not in all_keys) and ('audio' not in all_keys) and ('throttle' not in all_keys) and self._generate_options != 'hb': - Messages.send_warning('''\ -This flow graph may not have flow control: no audio or usrp blocks found. \ -Add a Misc->Throttle block to your flow graph to avoid CPU congestion.''') - #generate - open(self.get_file_path(), 'w').write(str(self)) - if self._generate_options == 'hb': - #convert hier block to xml wrapper - convert_hier.convert_hier(self._flow_graph, self.get_file_path()) - os.chmod(self.get_file_path(), self._mode) - - def get_popen(self): - """ - Execute this python flow graph. - @return a popen object - """ - #execute - cmds = [PYEXEC, '-u', self.get_file_path()] #-u is unbuffered stdio - if self._generate_options == 'no_gui': - cmds = ['xterm', '-e'] + cmds - p = subprocess.Popen(args=cmds, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, shell=False, universal_newlines=True) - return p - - def __str__(self): - """ - Convert the flow graph to python code. - @return a string of python code - """ - imports = self._flow_graph.get_imports() - variables = self._flow_graph.get_variables() - parameters = self._flow_graph.get_parameters() - #list of variables with controls - controls = filter(lambda v: v.get_key().startswith('variable_'), variables) - #list of blocks not including variables and imports and parameters and disabled - blocks = sorted(self._flow_graph.get_enabled_blocks(), lambda x, y: cmp(x.get_id(), y.get_id())) - probes = filter(lambda b: b.get_key().startswith('probe_'), blocks) #ensure probes are last in the block list - blocks = filter(lambda b: b not in (imports + parameters + variables + probes), blocks) + probes - #list of connections where each endpoint is enabled - connections = self._flow_graph.get_enabled_connections() - #list of variable names - var_ids = [var.get_id() for var in parameters + variables] - #list of callbacks (prepend self.) - callbacks = [ - expr_utils.expr_prepend(cb, var_ids, 'self.') - for cb in sum([block.get_callbacks() for block in self._flow_graph.get_enabled_blocks()], []) - ] - #map var id to the expression (prepend self.) - var_id2expr = dict( - [(var.get_id(), expr_utils.expr_prepend(var.get_make().split('\n')[0], var_ids, 'self.')) - for var in parameters + variables] - ) - #create graph structure for variables - variable_graph = expr_utils.get_graph(var_id2expr) - #map var id to direct dependents - #for each var id, make a list of all 2nd order edges - #use all edges of that id that are not also 2nd order edges - #meaning: list variables the ONLY depend directly on this variable - #and not variables that also depend indirectly on this variable - var_id2deps = dict( - [(var_id, filter(lambda e: e not in sum([list(variable_graph.get_edges(edge)) - for edge in variable_graph.get_edges(var_id)], []), variable_graph.get_edges(var_id) - ) - ) - for var_id in var_ids] - ) - #map var id to callbacks - var_id2cbs = dict( - [(var_id, filter(lambda c: var_id in expr_utils.expr_split(c), callbacks)) - for var_id in var_ids] - ) - #load the namespace - namespace = { - 'imports': imports, - 'flow_graph': self._flow_graph, - 'variables': variables, - 'controls': controls, - 'parameters': parameters, - 'blocks': blocks, - 'connections': connections, - 'generate_options': self._generate_options, - 'var_id2expr': var_id2expr, - 'var_id2deps': var_id2deps, - 'var_id2cbs': var_id2cbs, - } - #build the template - t = Template(open(FLOW_GRAPH_TEMPLATE, 'r').read(), namespace) - return str(t) diff --git a/grc/src/platforms/python/Makefile.am b/grc/src/platforms/python/Makefile.am deleted file mode 100644 index c23d14792..000000000 --- a/grc/src/platforms/python/Makefile.am +++ /dev/null @@ -1,48 +0,0 @@ -# -# Copyright 2008,2009 Free Software Foundation, Inc. -# -# This file is part of GNU Radio -# -# GNU Radio is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 3, or (at your option) -# any later version. -# -# GNU Radio is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with GNU Radio; see the file COPYING. If not, write to -# the Free Software Foundation, Inc., 51 Franklin Street, -# Boston, MA 02110-1301, USA. -# - -include $(top_srcdir)/grc/Makefile.inc - -SUBDIRS = utils - -ourpythondir = $(grc_src_prefix)/platforms/python - -ourpython_PYTHON = \ - Block.py \ - Connection.py \ - Constants.py \ - FlowGraph.py \ - Generator.py \ - Param.py \ - Platform.py \ - Port.py \ - __init__.py - -Constants.py: $(srcdir)/Constants.py.in Makefile - sed \ - -e 's|@PYTHONW[@]|$(PYTHONW)|g' \ - -e 's|@reldatadir[@]|$(grc_python_data_reldir)|g' \ - -e 's|@relblocksdir[@]|$(grc_blocks_data_reldir)|g' \ - -e 's|@docdir[@]|$(gr_docdir)|g' \ - $< > $@ - -EXTRA_DIST = $(srcdir)/Constants.py.in -BUILT_SOURCES = Constants.py diff --git a/grc/src/platforms/python/Param.py b/grc/src/platforms/python/Param.py deleted file mode 100644 index e5ac1dcf6..000000000 --- a/grc/src/platforms/python/Param.py +++ /dev/null @@ -1,402 +0,0 @@ -""" -Copyright 2008, 2009 Free Software Foundation, Inc. -This file is part of GNU Radio - -GNU Radio Companion is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or (at your option) any later version. - -GNU Radio Companion is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA -""" - -from utils import expr_utils -from .. base.Param import Param as _Param, EntryParam -import Constants -import numpy -import os -import pygtk -pygtk.require('2.0') -import gtk -from gnuradio import eng_notation - -class FileParam(EntryParam): - """Provide an entry box for filename and a button to browse for a file.""" - - def __init__(self, *args, **kwargs): - EntryParam.__init__(self, *args, **kwargs) - input = gtk.Button('...') - input.connect('clicked', self._handle_clicked) - self.pack_start(input, False) - - def _handle_clicked(self, widget=None): - """ - If the button was clicked, open a file dialog in open/save format. - Replace the text in the entry with the new filename from the file dialog. - """ - #get the paths - file_path = self.param.is_valid() and self.param.evaluate() or '' - (dirname, basename) = os.path.isfile(file_path) and os.path.split(file_path) or (file_path, '') - if not os.path.exists(dirname): dirname = os.getcwd() #fix bad paths - #build the dialog - if self.param.get_type() == 'file_open': - file_dialog = gtk.FileChooserDialog('Open a Data File...', None, - gtk.FILE_CHOOSER_ACTION_OPEN, ('gtk-cancel',gtk.RESPONSE_CANCEL,'gtk-open',gtk.RESPONSE_OK)) - elif self.param.get_type() == 'file_save': - file_dialog = gtk.FileChooserDialog('Save a Data File...', None, - gtk.FILE_CHOOSER_ACTION_SAVE, ('gtk-cancel',gtk.RESPONSE_CANCEL, 'gtk-save',gtk.RESPONSE_OK)) - file_dialog.set_do_overwrite_confirmation(True) - file_dialog.set_current_name(basename) #show the current filename - file_dialog.set_current_folder(dirname) #current directory - file_dialog.set_select_multiple(False) - file_dialog.set_local_only(True) - if gtk.RESPONSE_OK == file_dialog.run(): #run the dialog - file_path = file_dialog.get_filename() #get the file path - self.entry.set_text(file_path) - self._handle_changed() - file_dialog.destroy() #destroy the dialog - -#blacklist certain ids, its not complete, but should help -import __builtin__ -ID_BLACKLIST = ['options', 'gr', 'blks2', 'wxgui', 'wx', 'math', 'forms', 'firdes'] + dir(__builtin__) -#define types, native python + numpy -VECTOR_TYPES = (tuple, list, set, numpy.ndarray) -COMPLEX_TYPES = [complex, numpy.complex, numpy.complex64, numpy.complex128] -REAL_TYPES = [float, numpy.float, numpy.float32, numpy.float64] -INT_TYPES = [int, long, numpy.int, numpy.int8, numpy.int16, numpy.int32, numpy.uint64, - numpy.uint, numpy.uint8, numpy.uint16, numpy.uint32, numpy.uint64] -#cast to tuple for isinstance, concat subtypes -COMPLEX_TYPES = tuple(COMPLEX_TYPES + REAL_TYPES + INT_TYPES) -REAL_TYPES = tuple(REAL_TYPES + INT_TYPES) -INT_TYPES = tuple(INT_TYPES) - -class Param(_Param): - - _init = False - _hostage_cells = list() - - ##possible param types - TYPES = _Param.TYPES + [ - 'complex', 'real', 'int', - 'complex_vector', 'real_vector', 'int_vector', - 'hex', 'string', - 'file_open', 'file_save', - 'id', - 'grid_pos', 'import', - ] - - def __repr__(self): - """ - Get the repr (nice string format) for this param. - @return the string representation - """ - if self.get_value() in self.get_option_keys(): return self.get_option(self.get_value()).get_name() - ################################################## - # display logic for numbers - ################################################## - def num_to_str(num): - if isinstance(num, COMPLEX_TYPES): - num = complex(num) #cast to python complex - if num == 0: return '0' #value is zero - elif num.imag == 0: return '%s'%eng_notation.num_to_str(num.real) #value is real - elif num.real == 0: return '%sj'%eng_notation.num_to_str(num.imag) #value is imaginary - elif num.imag < 0: return '%s-%sj'%(eng_notation.num_to_str(num.real), eng_notation.num_to_str(abs(num.imag))) - else: return '%s+%sj'%(eng_notation.num_to_str(num.real), eng_notation.num_to_str(num.imag)) - else: return str(num) - ################################################## - # split up formatting by type - ################################################## - truncate = 0 #default center truncate - max_len = max(27 - len(self.get_name()), 3) - e = self.evaluate() - t = self.get_type() - if isinstance(e, COMPLEX_TYPES): dt_str = num_to_str(e) - elif isinstance(e, VECTOR_TYPES): #vector types - if len(e) > 8: - dt_str = self.get_value() #large vectors use code - truncate = 1 - else: dt_str = ', '.join(map(num_to_str, e)) #small vectors use eval - elif t in ('file_open', 'file_save'): - dt_str = self.get_value() - truncate = -1 - else: dt_str = str(e) #other types - ################################################## - # truncate - ################################################## - if len(dt_str) > max_len: - if truncate < 0: #front truncate - dt_str = '...' + dt_str[3-max_len:] - elif truncate == 0: #center truncate - dt_str = dt_str[:max_len/2 -3] + '...' + dt_str[-max_len/2:] - elif truncate > 0: #rear truncate - dt_str = dt_str[:max_len-3] + '...' - return dt_str - - def get_input_class(self): - if self.get_type() in ('file_open', 'file_save'): return FileParam - return _Param.get_input_class(self) - - def get_color(self): - """ - Get the color that represents this param's type. - @return a hex color code. - """ - try: - return { - #number types - 'complex': Constants.COMPLEX_COLOR_SPEC, - 'real': Constants.FLOAT_COLOR_SPEC, - 'int': Constants.INT_COLOR_SPEC, - #vector types - 'complex_vector': Constants.COMPLEX_VECTOR_COLOR_SPEC, - 'real_vector': Constants.FLOAT_VECTOR_COLOR_SPEC, - 'int_vector': Constants.INT_VECTOR_COLOR_SPEC, - #special - 'hex': Constants.INT_COLOR_SPEC, - 'string': Constants.BYTE_VECTOR_COLOR_SPEC, - 'id': Constants.ID_COLOR_SPEC, - 'grid_pos': Constants.INT_VECTOR_COLOR_SPEC, - }[self.get_type()] - except: return _Param.get_color(self) - - def get_hide(self): - """ - Get the hide value from the base class. - Hide the ID parameter for most blocks. Exceptions below. - If the parameter controls a port type, vlen, or nports, return part. - If the parameter is an empty grid position, return part. - These parameters are redundant to display in the flow graph view. - @return hide the hide property string - """ - hide = _Param.get_hide(self) - if hide: return hide - #hide ID in non variable blocks - if self.get_key() == 'id' and self.get_parent().get_key() not in ( - 'variable', 'variable_slider', 'variable_chooser', 'variable_text_box', 'parameter', 'options' - ): return 'part' - #hide port controllers for type and nports - if self.get_key() in ' '.join(map( - lambda p: ' '.join([p._type, p._nports]), self.get_parent().get_ports()) - ): return 'part' - #hide port controllers for vlen, when == 1 - if self.get_key() in ' '.join(map( - lambda p: p._vlen, self.get_parent().get_ports()) - ): - try: - assert int(self.evaluate()) == 1 - return 'part' - except: pass - #hide empty grid positions - if self.get_key() == 'grid_pos' and not self.get_value(): return 'part' - return hide - - def evaluate(self): - """ - Evaluate the value. - @return evaluated type - """ - self._lisitify_flag = False - self._stringify_flag = False - self._hostage_cells = list() - def eval_string(v): - try: - e = self.get_parent().get_parent().evaluate(v) - assert isinstance(e, str) - return e - except: - self._stringify_flag = True - return v - t = self.get_type() - v = self.get_value() - ######################### - # Enum Type - ######################### - if self.is_enum(): return v - ######################### - # Numeric Types - ######################### - elif t in ('raw', 'complex', 'real', 'int', 'complex_vector', 'real_vector', 'int_vector', 'hex'): - #raise exception if python cannot evaluate this value - try: e = self.get_parent().get_parent().evaluate(v) - except Exception, e: - self._add_error_message('Value "%s" cannot be evaluated: %s'%(v, e)) - raise Exception - #raise an exception if the data is invalid - if t == 'raw': return e - elif t == 'complex': - try: assert(isinstance(e, COMPLEX_TYPES)) - except AssertionError: - self._add_error_message('Expression "%s" is invalid for type complex.'%str(e)) - raise Exception - return e - elif t == 'real': - try: assert(isinstance(e, REAL_TYPES)) - except AssertionError: - self._add_error_message('Expression "%s" is invalid for type real.'%str(e)) - raise Exception - return e - elif t == 'int': - try: assert(isinstance(e, INT_TYPES)) - except AssertionError: - self._add_error_message('Expression "%s" is invalid for type integer.'%str(e)) - raise Exception - return e - ######################### - # Numeric Vector Types - ######################### - elif t == 'complex_vector': - if not isinstance(e, VECTOR_TYPES): - self._lisitify_flag = True - e = [e] - try: - for ei in e: - assert(isinstance(ei, COMPLEX_TYPES)) - except AssertionError: - self._add_error_message('Expression "%s" is invalid for type complex vector.'%str(e)) - raise Exception - return e - elif t == 'real_vector': - if not isinstance(e, VECTOR_TYPES): - self._lisitify_flag = True - e = [e] - try: - for ei in e: - assert(isinstance(ei, REAL_TYPES)) - except AssertionError: - self._add_error_message('Expression "%s" is invalid for type real vector.'%str(e)) - raise Exception - return e - elif t == 'int_vector': - if not isinstance(e, VECTOR_TYPES): - self._lisitify_flag = True - e = [e] - try: - for ei in e: - assert(isinstance(ei, INT_TYPES)) - except AssertionError: - self._add_error_message('Expression "%s" is invalid for type integer vector.'%str(e)) - raise Exception - return e - elif t == 'hex': - return hex(e) - else: raise TypeError, 'Type "%s" not handled'%t - ######################### - # String Types - ######################### - elif t in ('string', 'file_open', 'file_save'): - #do not check if file/directory exists, that is a runtime issue - e = eval_string(v) - return str(e) - ######################### - # Unique ID Type - ######################### - elif t == 'id': - #can python use this as a variable? - try: - assert(len(v) > 0) - assert(v[0].isalpha()) - for c in v: assert(c.isalnum() or c in ('_',)) - except AssertionError: - self._add_error_message('ID "%s" must be alpha-numeric or underscored, and begin with a letter.'%v) - raise Exception - params = self.get_all_params('id') - keys = [param.get_value() for param in params] - try: assert keys.count(v) <= 1 #id should only appear once, or zero times if block is disabled - except: - self._add_error_message('ID "%s" is not unique.'%v) - raise Exception - try: assert v not in ID_BLACKLIST - except: - self._add_error_message('ID "%s" is blacklisted.'%v) - raise Exception - return v - ######################### - # Grid Position Type - ######################### - elif t == 'grid_pos': - if not v: return '' #allow for empty grid pos - e = self.get_parent().get_parent().evaluate(v) - try: - assert(isinstance(e, (list, tuple)) and len(e) == 4) - for ei in e: assert(isinstance(ei, int)) - except AssertionError: - self._add_error_message('A grid position must be a list of 4 integers.') - raise Exception - row, col, row_span, col_span = e - #check row, col - try: assert(row >= 0 and col >= 0) - except AssertionError: - self._add_error_message('Row and column must be non-negative.') - raise Exception - #check row span, col span - try: assert(row_span > 0 and col_span > 0) - except AssertionError: - self._add_error_message('Row and column span must be greater than zero.') - raise Exception - #calculate hostage cells - for r in range(row_span): - for c in range(col_span): - self._hostage_cells.append((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 cell in param._hostage_cells: - if cell in self._hostage_cells: - self._add_error_message('Another graphical element is using cell "%s".'%str(cell)) - raise Exception - return e - ######################### - # Import Type - ######################### - elif t == 'import': - n = dict() #new namespace - try: exec v in n - except ImportError: - self._add_error_message('Import "%s" failed.'%v) - raise Exception - except Exception: - self._add_error_message('Bad import syntax: "%s".'%v) - raise Exception - return filter(lambda k: str(k) != '__builtins__', n.keys()) - ######################### - else: raise TypeError, 'Type "%s" not handled'%t - - def to_code(self): - """ - Convert the value to code. - @return a string representing the code - """ - #run init tasks in evaluate - #such as setting flags - if not self._init: - self.evaluate() - self._init = True - v = self.get_value() - t = self.get_type() - if t in ('string', 'file_open', 'file_save'): #string types - if self._stringify_flag: - return '"%s"'%v.replace('"', '\"') - else: - return v - elif t in ('complex_vector', 'real_vector', 'int_vector'): #vector types - if self._lisitify_flag: - return '(%s, )'%v - else: - return '(%s)'%v - else: - return v - - def get_all_params(self, type): - """ - Get all the params from the flowgraph that have the given type. - @param type the specified type - @return a list of params - """ - return sum([filter(lambda p: p.get_type() == type, block.get_params()) for block in self.get_parent().get_parent().get_enabled_blocks()], []) diff --git a/grc/src/platforms/python/Platform.py b/grc/src/platforms/python/Platform.py deleted file mode 100644 index d2bb4627e..000000000 --- a/grc/src/platforms/python/Platform.py +++ /dev/null @@ -1,69 +0,0 @@ -""" -Copyright 2008 Free Software Foundation, Inc. -This file is part of GNU Radio - -GNU Radio Companion is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or (at your option) any later version. - -GNU Radio Companion is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA -""" - -import os -from .. base.Platform import Platform as _Platform -from FlowGraph import FlowGraph as _FlowGraph -from Connection import Connection as _Connection -from Block import Block as _Block -from Port import Source,Sink -from Param import Param as _Param -from Generator import Generator -from Constants import \ - HIER_BLOCKS_LIB_DIR, BLOCK_DTD, \ - BLOCK_TREE, DEFAULT_FLOW_GRAPH, \ - BLOCKS_DIR - -_critical_blocks_only = map(lambda b: os.path.join(BLOCKS_DIR, b), ['options.xml', 'usrp_probe.xml', 'usrp2_probe.xml']) - -class Platform(_Platform): - - def __init__(self, extra_blocks=[], critical_only=False): - """ - Make a platform for gnuradio. - @param extra_blocks a list of block paths to load in addition to main block library - @param critical_only only load critical blocks (used only for usrp probe scripts to speed up load time) - """ - #ensure hier dir - if not os.path.exists(HIER_BLOCKS_LIB_DIR): os.mkdir(HIER_BLOCKS_LIB_DIR) - if critical_only: block_paths = _critical_blocks_only - else: block_paths = extra_blocks + [HIER_BLOCKS_LIB_DIR, BLOCKS_DIR] - #convert block paths to absolute paths, ensure uniqueness - block_paths = set(map(os.path.abspath, block_paths)) - #init - _Platform.__init__( - self, - name='GRC', - key='grc', - block_paths=block_paths, - block_dtd=BLOCK_DTD, - block_tree=BLOCK_TREE, - default_flow_graph=DEFAULT_FLOW_GRAPH, - generator=Generator, - ) - - ############################################## - # Constructors - ############################################## - FlowGraph = _FlowGraph - Connection = _Connection - Block = _Block - Source = Source - Sink = Sink - Param = _Param diff --git a/grc/src/platforms/python/Port.py b/grc/src/platforms/python/Port.py deleted file mode 100644 index b5bc9696b..000000000 --- a/grc/src/platforms/python/Port.py +++ /dev/null @@ -1,129 +0,0 @@ -""" -Copyright 2008, 2009 Free Software Foundation, Inc. -This file is part of GNU Radio - -GNU Radio Companion is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or (at your option) any later version. - -GNU Radio Companion is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA -""" - -from .. base.Port import Port as _Port -import Constants - -class Port(_Port): - - ##possible port types - TYPES = ['complex', 'float', 'int', 'short', 'byte'] - - def __init__(self, block, n): - """ - Make a new port from nested data. - @param block the parent element - @param n the nested odict - @return a new port - """ - vlen = n.find('vlen') or '1' - nports = n.find('nports') or '' - optional = n.find('optional') or '' - #build the port - _Port.__init__( - self, - block=block, - n=n, - ) - self._nports = nports - self._vlen = vlen - self._optional = bool(optional) - - def validate(self): - _Port.validate(self) - try: assert(self.get_enabled_connections() or self.get_optional()) - except AssertionError: self._add_error_message('Port is not connected.') - try: assert(self.is_source() or len(self.get_enabled_connections()) <= 1) - except AssertionError: self._add_error_message('Port has too many connections.') - - def get_vlen(self): - """ - Get the vector length. - If the evaluation of vlen cannot be cast to an integer, return 1. - @return the vector length or 1 - """ - vlen = self.get_parent().resolve_dependencies(self._vlen) - try: return int(self.get_parent().get_parent().evaluate(vlen)) - except: return 1 - - def get_nports(self): - """ - Get the number of ports. - If already blank, return a blank - If the evaluation of nports cannot be cast to an integer, return 1. - @return the number of ports or 1 - """ - nports = self.get_parent().resolve_dependencies(self._nports) - #return blank if nports is blank - if not nports: return '' - try: - nports = int(self.get_parent().get_parent().evaluate(nports)) - assert 0 < nports - return nports - except: return 1 - - def get_optional(self): return bool(self._optional) - - def get_color(self): - """ - Get the color that represents this port's type. - Codes differ for ports where the vec length is 1 or greater than 1. - @return a hex color code. - """ - try: - if self.get_vlen() == 1: - return {#vlen is 1 - 'complex': Constants.COMPLEX_COLOR_SPEC, - 'float': Constants.FLOAT_COLOR_SPEC, - 'int': Constants.INT_COLOR_SPEC, - 'short': Constants.SHORT_COLOR_SPEC, - 'byte': Constants.BYTE_COLOR_SPEC, - }[self.get_type()] - return {#vlen is non 1 - 'complex': Constants.COMPLEX_VECTOR_COLOR_SPEC, - 'float': Constants.FLOAT_VECTOR_COLOR_SPEC, - 'int': Constants.INT_VECTOR_COLOR_SPEC, - 'short': Constants.SHORT_VECTOR_COLOR_SPEC, - 'byte': Constants.BYTE_VECTOR_COLOR_SPEC, - }[self.get_type()] - except: return _Port.get_color(self) - -class Source(Port): - - def __init__(self, block, n): - self._n = n #save n - #key is port index - n['key'] = str(block._source_count) - block._source_count = block._source_count + 1 - Port.__init__(self, block, n) - - def __del__(self): - self.get_parent()._source_count = self.get_parent()._source_count - 1 - -class Sink(Port): - - def __init__(self, block, n): - self._n = n #save n - #key is port index - n['key'] = str(block._sink_count) - block._sink_count = block._sink_count + 1 - Port.__init__(self, block, n) - - def __del__(self): - self.get_parent()._sink_count = self.get_parent()._sink_count - 1 diff --git a/grc/src/platforms/python/__init__.py b/grc/src/platforms/python/__init__.py deleted file mode 100644 index 8b1378917..000000000 --- a/grc/src/platforms/python/__init__.py +++ /dev/null @@ -1 +0,0 @@ - diff --git a/grc/src/platforms/python/utils/Makefile.am b/grc/src/platforms/python/utils/Makefile.am deleted file mode 100644 index b12e51d8e..000000000 --- a/grc/src/platforms/python/utils/Makefile.am +++ /dev/null @@ -1,30 +0,0 @@ -# -# Copyright 2008 Free Software Foundation, Inc. -# -# This file is part of GNU Radio -# -# GNU Radio is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 3, or (at your option) -# any later version. -# -# GNU Radio is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with GNU Radio; see the file COPYING. If not, write to -# the Free Software Foundation, Inc., 51 Franklin Street, -# Boston, MA 02110-1301, USA. -# - -include $(top_srcdir)/grc/Makefile.inc - -ourpythondir = $(grc_src_prefix)/platforms/python/utils - -ourpython_PYTHON = \ - convert_hier.py \ - expr_utils.py \ - extract_docs.py \ - __init__.py diff --git a/grc/src/platforms/python/utils/__init__.py b/grc/src/platforms/python/utils/__init__.py deleted file mode 100644 index 8b1378917..000000000 --- a/grc/src/platforms/python/utils/__init__.py +++ /dev/null @@ -1 +0,0 @@ - diff --git a/grc/src/platforms/python/utils/convert_hier.py b/grc/src/platforms/python/utils/convert_hier.py deleted file mode 100644 index 495358984..000000000 --- a/grc/src/platforms/python/utils/convert_hier.py +++ /dev/null @@ -1,78 +0,0 @@ -""" -Copyright 2008 Free Software Foundation, Inc. -This file is part of GNU Radio - -GNU Radio Companion is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or (at your option) any later version. - -GNU Radio Companion is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA -""" - -from .. Constants import BLOCK_DTD -from .... utils import ParseXML -from .... utils import odict - -def convert_hier(flow_graph, python_file): - #extract info from the flow graph - input_sig = flow_graph.get_input_signature() - output_sig = flow_graph.get_output_signature() - parameters = flow_graph.get_parameters() - block_key = flow_graph.get_option('id') - block_name = flow_graph.get_option('title') - block_category = flow_graph.get_option('category') - block_desc = flow_graph.get_option('description') - block_author = flow_graph.get_option('author') - #build the nested data - block_n = odict() - block_n['name'] = block_name - block_n['key'] = block_key - block_n['category'] = block_category - block_n['import'] = 'execfile("%s")'%python_file - #make data - block_n['make'] = '%s(\n\t%s,\n)'%( - block_key, - ',\n\t'.join(['%s=$%s'%(param.get_id(), param.get_id()) for param in parameters]), - ) - #callback data - block_n['callback'] = ['set_%s($%s)'%(param.get_id(), param.get_id()) for param in parameters] - #param data - params_n = list() - for param in parameters: - param_n = odict() - param_n['name'] = param.get_param('label').get_value() or param.get_id() - param_n['key'] = param.get_id() - param_n['value'] = param.get_param('value').get_value() - param_n['type'] = 'raw' - params_n.append(param_n) - block_n['param'] = params_n - #sink data - if int(input_sig['nports']): - sink_n = odict() - sink_n['name'] = 'in' - sink_n['type'] = input_sig['type'] - sink_n['vlen'] = input_sig['vlen'] - sink_n['nports'] = input_sig['nports'] - block_n['sink'] = sink_n - #source data - if int(output_sig['nports']): - source_n = odict() - source_n['name'] = 'out' - source_n['type'] = output_sig['type'] - source_n['vlen'] = output_sig['vlen'] - source_n['nports'] = output_sig['nports'] - block_n['source'] = source_n - #doc data - block_n['doc'] = "%s\n%s\n%s"%(block_author, block_desc, python_file) - #write the block_n to file - xml_file = python_file + '.xml' - ParseXML.to_file({'block': block_n}, xml_file) - ParseXML.validate_dtd(xml_file, BLOCK_DTD) diff --git a/grc/src/platforms/python/utils/expr_utils.py b/grc/src/platforms/python/utils/expr_utils.py deleted file mode 100644 index 40700993d..000000000 --- a/grc/src/platforms/python/utils/expr_utils.py +++ /dev/null @@ -1,137 +0,0 @@ -""" -Copyright 2008 Free Software Foundation, Inc. -This file is part of GNU Radio - -GNU Radio Companion is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or (at your option) any later version. - -GNU Radio Companion is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA -""" - -import string -VAR_CHARS = string.letters + string.digits + '_' - -class graph(object): - """ - Simple graph structure held in a dictionary. - """ - - def __init__(self): self._graph = dict() - - def __str__(self): return str(self._graph) - - def add_node(self, node_key): - if self._graph.has_key(node_key): return - self._graph[node_key] = set() - - def remove_node(self, node_key): - if not self._graph.has_key(node_key): return - for edges in self._graph.values(): - if node_key in edges: edges.remove(node_key) - self._graph.pop(node_key) - - def add_edge(self, src_node_key, dest_node_key): - self._graph[src_node_key].add(dest_node_key) - - def remove_edge(self, src_node_key, dest_node_key): - self._graph[src_node_key].remove(dest_node_key) - - def get_nodes(self): return self._graph.keys() - - def get_edges(self, node_key): return self._graph[node_key] - -def expr_split(expr): - """ - Split up an expression by non alphanumeric characters, including underscore. - Leave strings in-tact. - #TODO ignore escaped quotes, use raw strings. - @param expr an expression string - @return a list of string tokens that form expr - """ - toks = list() - tok = '' - quote = '' - for char in expr: - if quote or char in VAR_CHARS: - if char == quote: quote = '' - tok += char - elif char in ("'", '"'): - toks.append(tok) - tok = char - quote = char - else: - toks.append(tok) - toks.append(char) - tok = '' - toks.append(tok) - return filter(lambda t: t, toks) - -def expr_prepend(expr, vars, prepend): - """ - Search for vars in the expression and add the prepend. - @param expr an expression string - @param vars a list of variable names - @param prepend the prepend string - @return a new expression with the prepend - """ - expr_splits = expr_split(expr) - for i, es in enumerate(expr_splits): - if es in vars: expr_splits[i] = prepend + es - return ''.join(expr_splits) - -def get_variable_dependencies(expr, vars): - """ - Return a set of variables used in this expression. - @param expr an expression string - @param vars a list of variable names - @return a subset of vars used in the expression - """ - expr_toks = expr_split(expr) - return set(filter(lambda v: v in expr_toks, vars)) - -def get_graph(exprs): - """ - Get a graph representing the variable dependencies - @param exprs a mapping of variable name to expression - @return a graph of variable deps - """ - vars = exprs.keys() - #get dependencies for each expression, load into graph - var_graph = graph() - for var in vars: var_graph.add_node(var) - for var, expr in exprs.iteritems(): - for dep in get_variable_dependencies(expr, vars): - var_graph.add_edge(dep, var) - return var_graph - -def sort_variables(exprs): - """ - Get a list of variables in order of dependencies. - @param exprs a mapping of variable name to expression - @return a list of variable names - @throws AssertionError circular dependencies - """ - var_graph = get_graph(exprs) - sorted_vars = list() - #determine dependency order - while var_graph.get_nodes(): - #get a list of nodes with no edges - indep_vars = filter(lambda var: not var_graph.get_edges(var), var_graph.get_nodes()) - assert indep_vars - #add the indep vars to the end of the list - sorted_vars.extend(sorted(indep_vars)) - #remove each edge-less node from the graph - for var in indep_vars: var_graph.remove_node(var) - return reversed(sorted_vars) - -if __name__ == '__main__': - for i in sort_variables({'x':'1', 'y':'x+1', 'a':'x+y', 'b':'y+1', 'c':'a+b+x+y'}): print i diff --git a/grc/src/platforms/python/utils/extract_docs.py b/grc/src/platforms/python/utils/extract_docs.py deleted file mode 100644 index 523519f97..000000000 --- a/grc/src/platforms/python/utils/extract_docs.py +++ /dev/null @@ -1,92 +0,0 @@ -""" -Copyright 2008, 2009 Free Software Foundation, Inc. -This file is part of GNU Radio - -GNU Radio Companion is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or (at your option) any later version. - -GNU Radio Companion is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA -""" - -from .. Constants import DOCS_DIR -from lxml import etree -import os -import re - -DOXYGEN_NAME_XPATH = '/doxygen/compounddef/compoundname' -DOXYGEN_BRIEFDESC_GR_XPATH = '/doxygen/compounddef/briefdescription' -DOXYGEN_DETAILDESC_GR_XPATH = '/doxygen/compounddef/detaileddescription' - -def extract_txt(xml): - """ - Recursivly pull the text out of an xml tree. - @param xml the xml tree - @return a string - """ - text = (xml.text or '').replace('\n', '') - tail = (xml.tail or '').replace('\n', '') - if xml.tag == 'para': tail += '\n\n' - if xml.tag == 'linebreak': text += '\n' - if xml.tag == 'parametername': text += ': ' - return text + ''.join( - map(lambda x: extract_txt(x), xml) - ) + tail - -def _extract(key): - """ - Extract the documentation from the doxygen generated xml files. - If multiple files match, combine the docs. - @param key the block key - @return a string with documentation - """ - UBUNTU_DOCS_DIR = '/usr/share/doc/gnuradio-doc/xml' - if os.path.exists(DOCS_DIR): docs_dir = DOCS_DIR - elif os.path.exists(UBUNTU_DOCS_DIR): docs_dir = UBUNTU_DOCS_DIR - else: return '' - #extract matches - pattern = key.replace('_', '_*').replace('x', '\w') - prog = re.compile('^class%s\..*$'%pattern) - matches = filter(lambda f: prog.match(f), os.listdir(docs_dir)) - #combine all matches - doc_strs = list() - for match in matches: - try: - xml_file = os.path.join(docs_dir, match) - xml = etree.parse(xml_file) - #extract descriptions - comp_name = extract_txt(xml.xpath(DOXYGEN_NAME_XPATH)[0]).strip() - comp_name = ' --- ' + comp_name + ' --- ' - if re.match('(gr|usrp2|trellis)_.*', key): - brief_desc = extract_txt(xml.xpath(DOXYGEN_BRIEFDESC_GR_XPATH)[0]).strip() - detailed_desc = extract_txt(xml.xpath(DOXYGEN_DETAILDESC_GR_XPATH)[0]).strip() - else: - brief_desc = '' - detailed_desc = '' - #combine - doc_strs.append('\n\n'.join([comp_name, brief_desc, detailed_desc]).strip()) - except IndexError: pass #bad format - return '\n\n'.join(doc_strs) - -_docs_cache = dict() -def extract(key): - """ - Call the private extract and cache the result. - @param key the block key - @return a string with documentation - """ - try: assert _docs_cache.has_key(key) - except: _docs_cache[key] = _extract(key) - return _docs_cache[key] - -if __name__ == '__main__': - import sys - print extract(sys.argv[1]) -- cgit