Merging r11186:11273 from grc branch.
[debian/gnuradio] / grc / gui / Connection.py
diff --git a/grc/gui/Connection.py b/grc/gui/Connection.py
new file mode 100644 (file)
index 0000000..013bcb0
--- /dev/null
@@ -0,0 +1,140 @@
+"""
+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)