standardized the Element inheritance __init__ usage in gui
[debian/gnuradio] / grc / gui / Connection.py
1 """
2 Copyright 2007, 2008 Free Software Foundation, Inc.
3 This file is part of GNU Radio
4
5 GNU Radio Companion is free software; you can redistribute it and/or
6 modify it under the terms of the GNU General Public License
7 as published by the Free Software Foundation; either version 2
8 of the License, or (at your option) any later version.
9
10 GNU Radio Companion is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
18 """
19
20 import Utils
21 from Element import Element
22 import Colors
23 from Constants import CONNECTOR_ARROW_BASE, CONNECTOR_ARROW_HEIGHT
24
25 class Connection(Element):
26         """
27         A graphical connection for ports.
28         The connection has 2 parts, the arrow and the wire.
29         The coloring of the arrow and wire exposes the status of 3 states:
30                 enabled/disabled, valid/invalid, highlighted/non-highlighted.
31         The wire coloring exposes the enabled and highlighted states.
32         The arrow coloring exposes the enabled and valid states.
33         """
34
35         def __init__(self): Element.__init__(self)
36
37         def get_coordinate(self):
38                 """
39                 Get the 0,0 coordinate.
40                 Coordinates are irrelevant in connection.
41                 @return 0, 0
42                 """
43                 return (0, 0)
44
45         def get_rotation(self):
46                 """
47                 Get the 0 degree rotation.
48                 Rotations are irrelevant in connection.
49                 @return 0
50                 """
51                 return 0
52
53         def update(self):
54                 """Precalculate relative coordinates."""
55                 self._sink_rot = None
56                 self._source_rot = None
57                 self._sink_coor = None
58                 self._source_coor = None
59                 #get the source coordinate
60                 connector_length = self.get_source().get_connector_length()
61                 self.x1, self.y1 = Utils.get_rotated_coordinate((connector_length, 0), self.get_source().get_rotation())
62                 #get the sink coordinate
63                 connector_length = self.get_sink().get_connector_length() + CONNECTOR_ARROW_HEIGHT
64                 self.x2, self.y2 = Utils.get_rotated_coordinate((-connector_length, 0), self.get_sink().get_rotation())
65                 #build the arrow
66                 self.arrow = [(0, 0),
67                         Utils.get_rotated_coordinate((-CONNECTOR_ARROW_HEIGHT, -CONNECTOR_ARROW_BASE/2), self.get_sink().get_rotation()),
68                         Utils.get_rotated_coordinate((-CONNECTOR_ARROW_HEIGHT, CONNECTOR_ARROW_BASE/2), self.get_sink().get_rotation()),
69                 ]
70                 self._update_after_move()
71                 if not self.get_enabled(): self._arrow_color = Colors.CONNECTION_DISABLED_COLOR
72                 elif not self.is_valid(): self._arrow_color = Colors.CONNECTION_ERROR_COLOR
73                 else: self._arrow_color = Colors.CONNECTION_ENABLED_COLOR
74
75         def _update_after_move(self):
76                 """Calculate coordinates."""
77                 self.clear()
78                 #source connector
79                 source = self.get_source()
80                 X, Y = source.get_connector_coordinate()
81                 x1, y1 = self.x1 + X, self.y1 + Y
82                 self.add_line((x1, y1), (X, Y))
83                 #sink connector
84                 sink = self.get_sink()
85                 X, Y = sink.get_connector_coordinate()
86                 x2, y2 = self.x2 + X, self.y2 + Y
87                 self.add_line((x2, y2), (X, Y))
88                 #adjust arrow
89                 self._arrow = [(x+X, y+Y) for x,y in self.arrow]
90                 #add the horizontal and vertical lines in this connection
91                 if abs(source.get_connector_direction() - sink.get_connector_direction()) == 180:
92                         #2 possible point sets to create a 3-line connector
93                         mid_x, mid_y = (x1 + x2)/2.0, (y1 + y2)/2.0
94                         points = [((mid_x, y1), (mid_x, y2)), ((x1, mid_y), (x2, mid_y))]
95                         #source connector -> points[0][0] should be in the direction of source (if possible)
96                         if Utils.get_angle_from_coordinates((x1, y1), points[0][0]) != source.get_connector_direction(): points.reverse()
97                         #points[0][0] -> sink connector should not be in the direction of sink
98                         if Utils.get_angle_from_coordinates(points[0][0], (x2, y2)) == sink.get_connector_direction(): points.reverse()
99                         #points[0][0] -> source connector should not be in the direction of source
100                         if Utils.get_angle_from_coordinates(points[0][0], (x1, y1)) == source.get_connector_direction(): points.reverse()
101                         #create 3-line connector
102                         p1, p2 = map(int, points[0][0]), map(int, points[0][1])
103                         self.add_line((x1, y1), p1)
104                         self.add_line(p1, p2)
105                         self.add_line((x2, y2), p2)
106                 else:
107                         #2 possible points to create a right-angled connector
108                         points = [(x1, y2), (x2, y1)]
109                         #source connector -> points[0] should be in the direction of source (if possible)
110                         if Utils.get_angle_from_coordinates((x1, y1), points[0]) != source.get_connector_direction(): points.reverse()
111                         #points[0] -> sink connector should not be in the direction of sink
112                         if Utils.get_angle_from_coordinates(points[0], (x2, y2)) == sink.get_connector_direction(): points.reverse()
113                         #points[0] -> source connector should not be in the direction of source
114                         if Utils.get_angle_from_coordinates(points[0], (x1, y1)) == source.get_connector_direction(): points.reverse()
115                         #create right-angled connector
116                         self.add_line((x1, y1), points[0])
117                         self.add_line((x2, y2), points[0])
118
119         def draw(self, gc, window):
120                 """
121                 Draw the connection.
122                 @param gc the graphics context
123                 @param window the gtk window to draw on
124                 """
125                 sink = self.get_sink()
126                 source = self.get_source()
127                 #check for changes
128                 if self._sink_rot != sink.get_rotation() or self._source_rot != source.get_rotation(): self.update()
129                 elif self._sink_coor != sink.get_coordinate() or self._source_coor != source.get_coordinate(): self._update_after_move()
130                 #cache values
131                 self._sink_rot = sink.get_rotation()
132                 self._source_rot = source.get_rotation()
133                 self._sink_coor = sink.get_coordinate()
134                 self._source_coor = source.get_coordinate()
135                 #draw
136                 if self.is_highlighted(): border_color = Colors.HIGHLIGHT_COLOR
137                 elif self.get_enabled(): border_color = Colors.CONNECTION_ENABLED_COLOR
138                 else: border_color = Colors.CONNECTION_DISABLED_COLOR
139                 Element.draw(self, gc, window, bg_color=None, border_color=border_color)
140                 #draw arrow on sink port
141                 gc.set_foreground(self._arrow_color)
142                 window.draw_polygon(gc, True, self._arrow)