""" 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 __future__ import absolute_import import math from gi.repository import Gtk, PangoCairo, Pango from . import Actions, Colors, Utils, Constants from .Element import Element from ..core.Element import nop_write from ..core.Port import Port as _Port class Port(_Port, Element): """The graphical port.""" def __init__(self, parent, direction, **n): """ Port constructor. Create list of connector coordinates. """ super(self.__class__, self).__init__(parent, direction, **n) Element.__init__(self) self._connector_coordinate = (0, 0) self._hovering = False self.force_show_label = False self._bg_color = (0, 0, 0) self._line_width_factor = 1.0 self.width_with_label = self.height = 0 self.connector_length = 0 self.label_layout = Gtk.DrawingArea().create_pango_layout('') self.label_layout.set_alignment(Pango.Alignment.CENTER) @property def width(self): return self.width_with_label if self._show_label else Constants.PORT_LABEL_HIDDEN_WIDTH @width.setter def width(self, value): self.width_with_label = value self.label_layout.set_width(value * Pango.SCALE) 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. Returns: a hex color code. """ color = Colors.PORT_TYPE_TO_COLOR[self.get_type()] vlen = self.get_vlen() if vlen > 1: dark = (0, 0, 30 / 255.0, 50 / 255.0, 70 / 255.0)[min(4, vlen)] color = tuple(max(c - dark, 0) for c in color) return color def create_shapes(self): """Create new areas and labels for the port.""" self.clear() if self.is_horizontal(): self.areas.append([0, 0, self.width, self.height]) elif self.is_vertical(): self.areas.append([0, 0, self.height, self.width]) self._connector_coordinate = { 0: (self.width, self.height / 2), 90: (self.height / 2, 0), 180: (0, self.height / 2), 270: (self.height / 2, self.width) }[self.get_connector_direction()] def create_labels(self): """Create the labels for the socket.""" if self.domain in (Constants.GR_MESSAGE_DOMAIN, Constants.DEFAULT_DOMAIN): self._line_width_factor = 1.0 else: self._line_width_factor = 2.0 self._bg_color = self._get_color() layout = self.label_layout layout.set_markup("""<span foreground="black" font_desc="{font}">{name}</span>""".format( name=Utils.encode(self.name), font=Constants.PORT_FONT )) label_width, label_height = self.label_layout.get_pixel_size() self.width = 2 * Constants.PORT_LABEL_PADDING + label_width self.height = 2 * Constants.PORT_LABEL_PADDING + label_height if self.get_type() == 'bus': self.height += 2 * label_height self.height += self.height % 2 # uneven height def draw(self, widget, cr, border_color, bg_color): """ Draw the socket with a label. """ cr.set_line_width(self._line_width_factor * cr.get_line_width()) Element.draw(self, widget, cr, border_color, self._bg_color) if not self._show_label: return # this port is folded (no label) if self.is_vertical(): cr.rotate(-math.pi / 2) cr.translate(-self.width, 0) cr.translate(0, Constants.PORT_LABEL_PADDING) PangoCairo.update_layout(cr, self.label_layout) PangoCairo.show_layout(cr, self.label_layout) def get_connector_coordinate(self): """ Get the coordinate where connections may attach to. Returns: the connector coordinate (x, y) tuple """ return [sum(c) for c in zip(self._connector_coordinate, self.coordinate, self.parent_block.coordinate)] 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. Returns: the direction in degrees """ if self.is_source: return self.rotation elif self.is_sink: return (self.rotation + 180) % 360 @nop_write @property def rotation(self): return self.parent_block.rotation def rotate(self, direction): """ Rotate the parent rather than self. Args: direction: degrees to rotate """ self.parent.rotate(direction) def move(self, delta_coor): """ Move the parent rather than self. Args: delta_corr: the (delta_x, delta_y) tuple """ self.parent.move(delta_coor) @property def highlighted(self): return self.parent_block.highlighted @highlighted.setter def highlighted(self, value): self.parent_block.highlighted = value @property def _show_label(self): """ Figure out if the label should be hidden Returns: true if the label should not be shown """ return self._hovering or self.force_show_label or not Actions.TOGGLE_AUTO_HIDE_PORT_LABELS.get_active() def mouse_over(self): """ Called from flow graph on mouse-over """ changed = not self._show_label self._hovering = True return changed def mouse_out(self): """ Called from flow graph on mouse-out """ label_was_shown = self._show_label self._hovering = False return label_was_shown != self._show_label