diff options
Diffstat (limited to 'grc/gui/Connection.py')
-rw-r--r-- | grc/gui/Connection.py | 260 |
1 files changed, 143 insertions, 117 deletions
diff --git a/grc/gui/Connection.py b/grc/gui/Connection.py index 50361c19d0..9862328d6a 100644 --- a/grc/gui/Connection.py +++ b/grc/gui/Connection.py @@ -17,18 +17,17 @@ along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA """ -import gtk +from __future__ import absolute_import -import Colors -import Utils -from Constants import CONNECTOR_ARROW_BASE, CONNECTOR_ARROW_HEIGHT -from Element import Element +from . import Colors, Utils +from .Constants import CONNECTOR_ARROW_BASE, CONNECTOR_ARROW_HEIGHT, GR_MESSAGE_DOMAIN +from .Element import Element -from ..core.Constants import GR_MESSAGE_DOMAIN -from ..core.Connection import Connection as _Connection +from ..core.Element import nop_write +from ..core.Connection import Connection as CoreConnection -class Connection(Element, _Connection): +class Connection(CoreConnection, Element): """ A graphical connection for ports. The connection has 2 parts, the arrow and the wire. @@ -38,23 +37,25 @@ class Connection(Element, _Connection): The arrow coloring exposes the enabled and valid states. """ - def __init__(self, **kwargs): + def __init__(self, *args, **kwargs): + super(self.__class__, self).__init__(*args, **kwargs) Element.__init__(self) - _Connection.__init__(self, **kwargs) - # can't use Colors.CONNECTION_ENABLED_COLOR here, might not be defined (grcc) - self._bg_color = self._arrow_color = self._color = None - def get_coordinate(self): - """ - Get the 0,0 coordinate. - Coordinates are irrelevant in connection. + self._line = [] + self._line_width_factor = 1.0 + self._color = self._color2 = self._arrow_color = None - Returns: - 0, 0 - """ - return 0, 0 + self._sink_rot = self._source_rot = None + self._sink_coor = self._source_coor = None - def get_rotation(self): + @nop_write + @property + def coordinate(self): + return self.source_port.get_connector_coordinate() + + @nop_write + @property + def rotation(self): """ Get the 0 degree rotation. Rotations are irrelevant in connection. @@ -65,117 +66,142 @@ class Connection(Element, _Connection): return 0 def create_shapes(self): - """Precalculate relative coordinates.""" - Element.create_shapes(self) + """Pre-calculate relative coordinates.""" self._sink_rot = None self._source_rot = None self._sink_coor = None self._source_coor = None #get the source coordinate try: - connector_length = self.get_source().get_connector_length() + connector_length = self.source_port.connector_length except: - return - self.x1, self.y1 = Utils.get_rotated_coordinate((connector_length, 0), self.get_source().get_rotation()) + return # todo: why? + self.x1, self.y1 = Utils.get_rotated_coordinate((connector_length, 0), self.source_port.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()) + connector_length = self.sink_port.connector_length + CONNECTOR_ARROW_HEIGHT + self.x2, self.y2 = Utils.get_rotated_coordinate((-connector_length, 0), self.sink_port.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()), - ] - source_domain = self.get_source().get_domain() - sink_domain = self.get_sink().get_domain() - self.line_attributes[0] = 2 if source_domain != sink_domain else 0 - self.line_attributes[1] = gtk.gdk.LINE_DOUBLE_DASH \ - if not source_domain == sink_domain == GR_MESSAGE_DOMAIN \ - else gtk.gdk.LINE_ON_OFF_DASH - get_domain_color = lambda d: Colors.get_color(( - self.get_parent().get_parent().domains.get(d, {}) - ).get('color') or Colors.DEFAULT_DOMAIN_COLOR_CODE) - self._color = get_domain_color(source_domain) - self._bg_color = get_domain_color(sink_domain) - self._arrow_color = self._bg_color if self.is_valid() else Colors.CONNECTION_ERROR_COLOR + self._arrow_base = [ + (0, 0), + Utils.get_rotated_coordinate((-CONNECTOR_ARROW_HEIGHT, -CONNECTOR_ARROW_BASE/2), self.sink_port.rotation), + Utils.get_rotated_coordinate((-CONNECTOR_ARROW_HEIGHT, CONNECTOR_ARROW_BASE/2), self.sink_port.rotation), + ] if self.sink_block.state != 'bypassed' else [] + source_domain = self.source_port.domain + sink_domain = self.sink_port.domain + + def get_domain_color(domain_name): + domain = self.parent_platform.domains.get(domain_name, {}) + color_spec = domain.get('color') + return Colors.get_color(color_spec) if color_spec else Colors.DEFAULT_DOMAIN_COLOR + + if source_domain == GR_MESSAGE_DOMAIN: + self._line_width_factor = 1.0 + self._color = None + self._color2 = Colors.CONNECTION_ENABLED_COLOR + else: + if source_domain != sink_domain: + self._line_width_factor = 2.0 + self._color = get_domain_color(source_domain) + self._color2 = get_domain_color(sink_domain) + self._arrow_color = self._color2 if self.is_valid() else Colors.CONNECTION_ERROR_COLOR self._update_after_move() def _update_after_move(self): """Calculate coordinates.""" - self.clear() #FIXME do i want this here? - #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) + source = self.source_port + sink = self.sink_port + source_dir = source.get_connector_direction() + sink_dir = sink.get_connector_direction() + + x_pos, y_pos = self.coordinate + x_start, y_start = source.get_connector_coordinate() + x_end, y_end = sink.get_connector_coordinate() + + p3 = x3, y3 = x_end - x_pos, y_end - y_pos + p2 = x2, y2 = self.x2 + x3, self.y2 + y3 + p1 = x1, y1 = self.x1, self.y1 + p0 = x_start - x_pos, y_start - y_pos + self._arrow = [(x + x3, y + y3) for x, y in self._arrow_base] + + if abs(source_dir - 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)) + alt = ((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(p1, points[0]) != source_dir: + points, alt = alt, points + # points[0] -> sink connector should not be in the direction of sink + if Utils.get_angle_from_coordinates(points[0], p2) == sink_dir: + points, alt = alt, points + # points[0] -> source connector should not be in the direction of source + if Utils.get_angle_from_coordinates(points[0], p1) == source_dir: + points, alt = alt, points + # create 3-line connector + i1, i2 = points + self._line = [p0, p1, i1, i2, p2, p3] 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): + # 2 possible points to create a right-angled connector + point, alt = [(x1, y2), (x2, y1)] + # source connector -> point should be in the direction of source (if possible) + if Utils.get_angle_from_coordinates(p1, point) != source_dir: + point, alt = alt, point + # point -> sink connector should not be in the direction of sink + if Utils.get_angle_from_coordinates(point, p2) == sink_dir: + point, alt = alt, point + # point -> source connector should not be in the direction of source + if Utils.get_angle_from_coordinates(point, p1) == source_dir: + point, alt = alt, point + # create right-angled connector + self._line = [p0, p1, point, p2, p3] + self.bounds_from_line(self._line) + + def draw(self, cr): """ Draw the connection. - - Args: - gc: the graphics context - 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.create_shapes() - elif self._sink_coor != sink.get_coordinate() or self._source_coor != source.get_coordinate(): - try: - self._update_after_move() - except: - return - #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 - mod_color = lambda color: ( - Colors.HIGHLIGHT_COLOR if self.is_highlighted() else - Colors.CONNECTION_DISABLED_COLOR if not self.get_enabled() else - color + sink = self.sink_port + source = self.source_port + # check for changes + if self._sink_rot != sink.rotation or self._source_rot != source.rotation: + self.create_shapes() + self._sink_rot = sink.rotation + self._source_rot = source.rotation + + elif self._sink_coor != sink.parent_block.coordinate or self._source_coor != source.parent_block.coordinate: + self._update_after_move() + self._sink_coor = sink.parent_block.coordinate + self._source_coor = source.parent_block.coordinate + # draw + color1, color2, arrow_color = ( + None if color is None else + Colors.HIGHLIGHT_COLOR if self.highlighted else + Colors.CONNECTION_DISABLED_COLOR if not self.enabled else color + for color in (self._color, self._color2, self._arrow_color) ) - Element.draw(self, gc, window, mod_color(self._color), mod_color(self._bg_color)) - # draw arrow on sink port - try: - gc.set_foreground(mod_color(self._arrow_color)) - gc.set_line_attributes(0, gtk.gdk.LINE_SOLID, gtk.gdk.CAP_BUTT, gtk.gdk.JOIN_MITER) - window.draw_polygon(gc, True, self._arrow) - except: - pass + + cr.translate(*self.coordinate) + cr.set_line_width(self._line_width_factor * cr.get_line_width()) + for point in self._line: + cr.line_to(*point) + + if color1: # not a message connection + cr.set_source_rgba(*color1) + cr.stroke_preserve() + + if color1 != color2: + cr.save() + cr.set_dash([5.0, 5.0], 5.0 if color1 else 0.0) + cr.set_source_rgba(*color2) + cr.stroke() + cr.restore() + else: + cr.new_path() + + if self._arrow: + cr.set_source_rgba(*arrow_color) + cr.move_to(*self._arrow[0]) + cr.line_to(*self._arrow[1]) + cr.line_to(*self._arrow[2]) + cr.close_path() + cr.fill() |