2 Copyright 2007, 2008, 2009 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
20 from Constants import LINE_SELECT_SENSITIVITY
21 from Constants import POSSIBLE_ROTATIONS
23 class Element(object):
25 GraphicalElement is the base class for all graphical elements.
26 It contains an X,Y coordinate, a list of rectangular areas that the element occupies,
27 and methods to detect selection of those areas.
32 Make a new list of rectangular areas and lines, and set the coordinate and the rotation.
34 self.set_rotation(POSSIBLE_ROTATIONS[0])
35 self.set_coordinate((0, 0))
37 self.set_highlighted(False)
39 def is_horizontal(self, rotation=None):
41 Is this element horizontal?
42 If rotation is None, use this element's rotation.
43 @param rotation the optional rotation
44 @return true if rotation is horizontal
46 rotation = rotation or self.get_rotation()
47 return rotation in (0, 180)
49 def is_vertical(self, rotation=None):
51 Is this element vertical?
52 If rotation is None, use this element's rotation.
53 @param rotation the optional rotation
54 @return true if rotation is vertical
56 rotation = rotation or self.get_rotation()
57 return rotation in (90, 270)
59 def create_labels(self):
61 Create labels (if applicable) and call on all children.
62 Call this base method before creating labels in the element.
64 for child in self.get_children(): child.create_labels()
66 def create_shapes(self):
68 Create shapes (if applicable) and call on all children.
69 Call this base method before creating shapes in the element.
72 for child in self.get_children(): child.create_shapes()
74 def draw(self, gc, window, border_color, bg_color):
76 Draw in the given window.
77 @param gc the graphics context
78 @param window the gtk window to draw on
79 @param border_color the color for lines and rectangle borders
80 @param bg_color the color for the inside of the rectangle
82 X,Y = self.get_coordinate()
83 for (rX,rY),(W,H) in self._areas_list:
86 gc.set_foreground(bg_color)
87 window.draw_rectangle(gc, True, aX, aY, W, H)
88 gc.set_foreground(border_color)
89 window.draw_rectangle(gc, False, aX, aY, W, H)
90 for (x1, y1),(x2, y2) in self._lines_list:
91 gc.set_foreground(border_color)
92 window.draw_line(gc, X+x1, Y+y1, X+x2, Y+y2)
94 def rotate(self, rotation):
96 Rotate all of the areas by 90 degrees.
97 @param rotation multiple of 90 degrees
99 self.set_rotation((self.get_rotation() + rotation)%360)
102 """Empty the lines and areas."""
103 self._areas_list = list()
104 self._lines_list = list()
106 def set_coordinate(self, coor):
108 Set the reference coordinate.
109 @param coor the coordinate tuple (x,y)
113 def get_parent(self):
115 Get the parent of this element.
120 def set_highlighted(self, highlighted):
122 Set the highlight status.
123 @param highlighted true to enable highlighting
125 self.highlighted = highlighted
127 def is_highlighted(self):
129 Get the highlight status.
130 @return true if highlighted
132 return self.highlighted
134 def get_coordinate(self):
135 """Get the coordinate.
136 @return the coordinate tuple (x,y)
140 def move(self, delta_coor):
142 Move the element by adding the delta_coor to the current coordinate.
143 @param delta_coor (delta_x,delta_y) tuple
145 deltaX, deltaY = delta_coor
146 X, Y = self.get_coordinate()
147 self.set_coordinate((X+deltaX, Y+deltaY))
149 def add_area(self, rel_coor, area):
151 Add an area to the area list.
152 An area is actually a coordinate relative to the main coordinate
153 with a width/height pair relative to the area coordinate.
154 A positive width is to the right of the coordinate.
155 A positive height is above the coordinate.
156 The area is associated with a rotation.
157 @param rel_coor (x,y) offset from this element's coordinate
158 @param area (width,height) tuple
160 self._areas_list.append((rel_coor, area))
162 def add_line(self, rel_coor1, rel_coor2):
164 Add a line to the line list.
165 A line is defined by 2 relative coordinates.
166 Lines must be horizontal or vertical.
167 The line is associated with a rotation.
168 @param rel_coor1 relative (x1,y1) tuple
169 @param rel_coor2 relative (x2,y2) tuple
171 self._lines_list.append((rel_coor1, rel_coor2))
173 def what_is_selected(self, coor, coor_m=None):
175 One coordinate specified:
176 Is this element selected at given coordinate?
177 ie: is the coordinate encompassed by one of the areas or lines?
178 Both coordinates specified:
179 Is this element within the rectangular region defined by both coordinates?
180 ie: do any area corners or line endpoints fall within the region?
181 @param coor the selection coordinate, tuple x, y
182 @param coor_m an additional selection coordinate.
183 @return self if one of the areas/lines encompasses coor, else None.
185 #function to test if p is between a and b (inclusive)
186 in_between = lambda p, a, b: p >= min(a, b) and p <= max(a, b)
188 x, y = [a-b for a,b in zip(coor, self.get_coordinate())]
190 x_m, y_m = [a-b for a,b in zip(coor_m, self.get_coordinate())]
191 #handle rectangular areas
192 for (x1,y1), (w,h) in self._areas_list:
193 if in_between(x1, x, x_m) and in_between(y1, y, y_m) or \
194 in_between(x1+w, x, x_m) and in_between(y1, y, y_m) or \
195 in_between(x1, x, x_m) and in_between(y1+h, y, y_m) or \
196 in_between(x1+w, x, x_m) and in_between(y1+h, y, y_m):
198 #handle horizontal or vertical lines
199 for (x1, y1), (x2, y2) in self._lines_list:
200 if in_between(x1, x, x_m) and in_between(y1, y, y_m) or \
201 in_between(x2, x, x_m) and in_between(y2, y, y_m):
205 #handle rectangular areas
206 for (x1,y1), (w,h) in self._areas_list:
207 if in_between(x, x1, x1+w) and in_between(y, y1, y1+h): return self
208 #handle horizontal or vertical lines
209 for (x1, y1), (x2, y2) in self._lines_list:
210 if x1 == x2: x1, x2 = x1-LINE_SELECT_SENSITIVITY, x2+LINE_SELECT_SENSITIVITY
211 if y1 == y2: y1, y2 = y1-LINE_SELECT_SENSITIVITY, y2+LINE_SELECT_SENSITIVITY
212 if in_between(x, x1, x2) and in_between(y, y1, y2): return self
215 def get_rotation(self):
217 Get the rotation in degrees.
222 def set_rotation(self, rotation):
224 Set the rotation in degrees.
225 @param rotation the rotation"""
226 if rotation not in POSSIBLE_ROTATIONS:
227 raise Exception('"%s" is not one of the possible rotations: (%s)'%(rotation, POSSIBLE_ROTATIONS))
228 self.rotation = rotation