diff options
Diffstat (limited to 'grc/src/platforms/gui')
-rw-r--r-- | grc/src/platforms/gui/Block.py | 199 | ||||
-rw-r--r-- | grc/src/platforms/gui/Colors.py | 37 | ||||
-rw-r--r-- | grc/src/platforms/gui/Connection.py | 140 | ||||
-rw-r--r-- | grc/src/platforms/gui/Constants.py | 44 | ||||
-rw-r--r-- | grc/src/platforms/gui/Element.py | 226 | ||||
-rw-r--r-- | grc/src/platforms/gui/FlowGraph.py | 488 | ||||
-rw-r--r-- | grc/src/platforms/gui/Makefile.am | 37 | ||||
-rw-r--r-- | grc/src/platforms/gui/Param.py | 103 | ||||
-rw-r--r-- | grc/src/platforms/gui/Platform.py | 48 | ||||
-rw-r--r-- | grc/src/platforms/gui/Port.py | 190 | ||||
-rw-r--r-- | grc/src/platforms/gui/Utils.py | 82 | ||||
-rw-r--r-- | grc/src/platforms/gui/__init__.py | 1 |
12 files changed, 0 insertions, 1595 deletions
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' -<span foreground="$foreground" font_desc="Sans 8"><b>$encode($block.get_name())</b></span>""" - -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) -<span foreground="$foreground" font_desc="Sans 7.5"><b>$encode($param.get_name()): </b>$encode($value)</span>""" - -PARAM_LABEL_MARKUP_TMPL="""\ -#set $foreground = $param.is_valid() and 'black' or 'red' -#set $underline = $has_cb and 'low' or 'none' -<span underline="$underline" foreground="$foreground" font_desc="Sans 9">$encode($param.get_name())</span>""" - -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="""\ -<span foreground="black" font_desc="Sans 7.5">$encode($port.get_name())</span>""" - -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 @@ - |