2 Copyright 2007 Free Software Foundation, Inc.
3 This file is part of GNU Radio
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.
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.
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
25 from ... gui.Constants import CONNECTION_SELECT_SENSITIVITY
26 from Constants import POSSIBLE_ROTATIONS
28 class Element(object):
30 GraphicalElement is the base class for all graphical elements.
31 It contains an X,Y coordinate, a list of rectangular areas that the element occupies,
32 and methods to detect selection of those areas.
35 def __init__(self, *args, **kwargs):
37 Make a new list of rectangular areas and lines, and set the coordinate and the rotation.
39 self.set_rotation(POSSIBLE_ROTATIONS[0])
40 self.set_coordinate((0, 0))
42 self.set_highlighted(False)
44 def is_horizontal(self, rotation=None):
46 Is this element horizontal?
47 If rotation is None, use this element's rotation.
48 @param rotation the optional rotation
49 @return true if rotation is horizontal
51 rotation = rotation or self.get_rotation()
52 return rotation in (0, 180)
54 def is_vertical(self, rotation=None):
56 Is this element vertical?
57 If rotation is None, use this element's rotation.
58 @param rotation the optional rotation
59 @return true if rotation is vertical
61 rotation = rotation or self.get_rotation()
62 return rotation in (90, 270)
64 def get_gc(self): return self._gc
66 def draw(self, window, BG_color=Colors.BG_COLOR, FG_color=Colors.FG_COLOR):
68 Draw in the given window.
69 @param window the gtk window to draw on
70 @param BG_color the background color
71 @param FG_color the foreground color
73 gc = self.get_parent().get_gc()
75 X,Y = self.get_coordinate()
76 for (rX,rY),(W,H) in self.areas_dict[self.get_rotation()]:
79 gc.foreground = BG_color
80 window.draw_rectangle(gc, True, aX, aY, W, H)
81 gc.foreground = self.is_highlighted() and Colors.H_COLOR or FG_color
82 window.draw_rectangle(gc, False, aX, aY, W, H)
83 for (x1, y1),(x2, y2) in self.lines_dict[self.get_rotation()]:
84 gc.foreground = self.is_highlighted() and Colors.H_COLOR or FG_color
85 window.draw_line(gc, X+x1, Y+y1, X+x2, Y+y2)
87 def rotate(self, direction):
89 Rotate all of the areas by 90 degrees.
90 @param direction 90 or 270 degrees
92 self.set_rotation((self.get_rotation() + direction)%360)
95 """Empty the lines and areas."""
96 self.areas_dict = dict((rotation, list()) for rotation in POSSIBLE_ROTATIONS)
97 self.lines_dict = dict((rotation, list()) for rotation in POSSIBLE_ROTATIONS)
99 def set_coordinate(self, coor):
101 Set the reference coordinate.
102 @param coor the coordinate tuple (x,y)
106 def get_parent(self):
108 Get the parent of this element.
113 def set_highlighted(self, highlighted):
115 Set the highlight status.
116 @param highlighted true to enable highlighting
118 self.highlighted = highlighted
120 def is_highlighted(self):
122 Get the highlight status.
123 @return true if highlighted
125 return self.highlighted
127 def get_coordinate(self):
128 """Get the coordinate.
129 @return the coordinate tuple (x,y)
133 def move(self, delta_coor):
135 Move the element by adding the delta_coor to the current coordinate.
136 @param delta_coor (delta_x,delta_y) tuple
138 deltaX, deltaY = delta_coor
139 X, Y = self.get_coordinate()
140 self.set_coordinate((X+deltaX, Y+deltaY))
142 def add_area(self, rel_coor, area, rotation=None):
144 Add an area to the area list.
145 An area is actually a coordinate relative to the main coordinate
146 with a width/height pair relative to the area coordinate.
147 A positive width is to the right of the coordinate.
148 A positive height is above the coordinate.
149 The area is associated with a rotation.
150 If rotation is not specified, the element's current rotation is used.
151 @param rel_coor (x,y) offset from this element's coordinate
152 @param area (width,height) tuple
153 @param rotation rotation in degrees
155 self.areas_dict[rotation or self.get_rotation()].append((rel_coor, area))
157 def add_line(self, rel_coor1, rel_coor2, rotation=None):
159 Add a line to the line list.
160 A line is defined by 2 relative coordinates.
161 Lines must be horizontal or vertical.
162 The line is associated with a rotation.
163 If rotation is not specified, the element's current rotation is used.
164 @param rel_coor1 relative (x1,y1) tuple
165 @param rel_coor2 relative (x2,y2) tuple
166 @param rotation rotation in degrees
168 self.lines_dict[rotation or self.get_rotation()].append((rel_coor1, rel_coor2))
170 def what_is_selected(self, coor, coor_m=None):
172 One coordinate specified:
173 Is this element selected at given coordinate?
174 ie: is the coordinate encompassed by one of the areas or lines?
175 Both coordinates specified:
176 Is this element within the rectangular region defined by both coordinates?
177 ie: do any area corners or line endpoints fall within the region?
178 @param coor the selection coordinate, tuple x, y
179 @param coor_m an additional selection coordinate.
180 @return self if one of the areas/lines encompasses coor, else None.
182 #function to test if p is between a and b (inclusive)
183 in_between = lambda p, a, b: p >= min(a, b) and p <= max(a, b)
185 x, y = [a-b for a,b in zip(coor, self.get_coordinate())]
187 x_m, y_m = [a-b for a,b in zip(coor_m, self.get_coordinate())]
188 #handle rectangular areas
189 for (x1,y1), (w,h) in self.areas_dict[self.get_rotation()]:
190 if in_between(x1, x, x_m) and in_between(y1, y, y_m) or \
191 in_between(x1+w, x, x_m) and in_between(y1, y, y_m) or \
192 in_between(x1, x, x_m) and in_between(y1+h, y, y_m) or \
193 in_between(x1+w, x, x_m) and in_between(y1+h, y, y_m):
195 #handle horizontal or vertical lines
196 for (x1, y1), (x2, y2) in self.lines_dict[self.get_rotation()]:
197 if in_between(x1, x, x_m) and in_between(y1, y, y_m) or \
198 in_between(x2, x, x_m) and in_between(y2, y, y_m):
202 #handle rectangular areas
203 for (x1,y1), (w,h) in self.areas_dict[self.get_rotation()]:
204 if in_between(x, x1, x1+w) and in_between(y, y1, y1+h): return self
205 #handle horizontal or vertical lines
206 for (x1, y1), (x2, y2) in self.lines_dict[self.get_rotation()]:
207 if x1 == x2: x1, x2 = x1-CONNECTION_SELECT_SENSITIVITY, x2+CONNECTION_SELECT_SENSITIVITY
208 if y1 == y2: y1, y2 = y1-CONNECTION_SELECT_SENSITIVITY, y2+CONNECTION_SELECT_SENSITIVITY
209 if in_between(x, x1, x2) and in_between(y, y1, y2): return self
212 def get_rotation(self):
214 Get the rotation in degrees.
219 def set_rotation(self, rotation):
221 Set the rotation in degrees.
222 @param rotation the rotation"""
223 if rotation not in POSSIBLE_ROTATIONS:
224 raise Exception('"%s" is not one of the possible rotations: (%s)'%(rotation, POSSIBLE_ROTATIONS))
225 self.rotation = rotation
228 """Do nothing for the update. Dummy method."""