summaryrefslogtreecommitdiff
path: root/grc/gui/Element.py
diff options
context:
space:
mode:
Diffstat (limited to 'grc/gui/Element.py')
-rw-r--r--grc/gui/Element.py250
1 files changed, 78 insertions, 172 deletions
diff --git a/grc/gui/Element.py b/grc/gui/Element.py
index 9385424772..17cd6ddd92 100644
--- a/grc/gui/Element.py
+++ b/grc/gui/Element.py
@@ -1,5 +1,5 @@
"""
-Copyright 2007, 2008, 2009 Free Software Foundation, Inc.
+Copyright 2007, 2008, 2009, 2016 Free Software Foundation, Inc.
This file is part of GNU Radio
GNU Radio Companion is free software; you can redistribute it and/or
@@ -17,10 +17,10 @@ along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
"""
-from Constants import LINE_SELECT_SENSITIVITY
-from Constants import POSSIBLE_ROTATIONS
+from __future__ import absolute_import
+from .Constants import LINE_SELECT_SENSITIVITY
-import gtk
+from six.moves import zip
class Element(object):
@@ -30,17 +30,23 @@ class Element(object):
and methods to detect selection of those areas.
"""
+ @classmethod
+ def make_cls_with_base(cls, super_cls):
+ name = super_cls.__name__
+ bases = (super_cls,) + cls.__bases__[1:]
+ namespace = cls.__dict__.copy()
+ return type(name, bases, namespace)
+
def __init__(self):
"""
Make a new list of rectangular areas and lines, and set the coordinate and the rotation.
"""
- self.set_rotation(POSSIBLE_ROTATIONS[0])
- self.set_coordinate((0, 0))
- self.clear()
- self.set_highlighted(False)
- self.line_attributes = [
- 0, gtk.gdk.LINE_SOLID, gtk.gdk.CAP_BUTT, gtk.gdk.JOIN_MITER
- ]
+ self.coordinate = (0, 0)
+ self.rotation = 0
+ self.highlighted = False
+
+ self._bounding_rects = []
+ self._bounding_points = []
def is_horizontal(self, rotation=None):
"""
@@ -53,7 +59,7 @@ class Element(object):
Returns:
true if rotation is horizontal
"""
- rotation = rotation or self.get_rotation()
+ rotation = rotation or self.rotation
return rotation in (0, 180)
def is_vertical(self, rotation=None):
@@ -67,48 +73,9 @@ class Element(object):
Returns:
true if rotation is vertical
"""
- rotation = rotation or self.get_rotation()
+ rotation = rotation or self.rotation
return rotation in (90, 270)
- def create_labels(self):
- """
- Create labels (if applicable) and call on all children.
- Call this base method before creating labels in the element.
- """
- for child in self.get_children():child.create_labels()
-
- def create_shapes(self):
- """
- Create shapes (if applicable) and call on all children.
- Call this base method before creating shapes in the element.
- """
- self.clear()
- for child in self.get_children(): child.create_shapes()
-
- def draw(self, gc, window, border_color, bg_color):
- """
- Draw in the given window.
-
- Args:
- gc: the graphics context
- window: the gtk window to draw on
- border_color: the color for lines and rectangle borders
- bg_color: the color for the inside of the rectangle
- """
- X, Y = self.get_coordinate()
- gc.set_line_attributes(*self.line_attributes)
- for (rX, rY), (W, H) in self._areas_list:
- aX = X + rX
- aY = Y + rY
- gc.set_foreground(bg_color)
- window.draw_rectangle(gc, True, aX, aY, W, H)
- gc.set_foreground(border_color)
- window.draw_rectangle(gc, False, aX, aY, W, H)
- for (x1, y1), (x2, y2) in self._lines_list:
- gc.set_foreground(border_color)
- gc.set_background(bg_color)
- window.draw_line(gc, X+x1, Y+y1, X+x2, Y+y2)
-
def rotate(self, rotation):
"""
Rotate all of the areas by 90 degrees.
@@ -116,56 +83,7 @@ class Element(object):
Args:
rotation: multiple of 90 degrees
"""
- self.set_rotation((self.get_rotation() + rotation)%360)
-
- def clear(self):
- """Empty the lines and areas."""
- self._areas_list = list()
- self._lines_list = list()
-
- def set_coordinate(self, coor):
- """
- Set the reference coordinate.
-
- Args:
- coor: the coordinate tuple (x,y)
- """
- self.coor = coor
-
- # def get_parent(self):
- # """
- # Get the parent of this element.
- #
- # Returns:
- # the parent
- # """
- # return self.parent
-
- def set_highlighted(self, highlighted):
- """
- Set the highlight status.
-
- Args:
- highlighted: true to enable highlighting
- """
- self.highlighted = highlighted
-
- def is_highlighted(self):
- """
- Get the highlight status.
-
- Returns:
- true if highlighted
- """
- return self.highlighted
-
- def get_coordinate(self):
- """Get the coordinate.
-
- Returns:
- the coordinate tuple (x,y)
- """
- return self.coor
+ self.rotation = (self.rotation + rotation) % 360
def move(self, delta_coor):
"""
@@ -174,37 +92,48 @@ class Element(object):
Args:
delta_coor: (delta_x,delta_y) tuple
"""
- deltaX, deltaY = delta_coor
- X, Y = self.get_coordinate()
- self.set_coordinate((X+deltaX, Y+deltaY))
+ x, y = self.coordinate
+ dx, dy = delta_coor
+ self.coordinate = (x + dx, y + dy)
- def add_area(self, rel_coor, area):
+ def create_labels(self):
"""
- Add an area to the area list.
- An area is actually a coordinate relative to the main coordinate
- with a width/height pair relative to the area coordinate.
- A positive width is to the right of the coordinate.
- A positive height is above the coordinate.
- The area is associated with a rotation.
-
- Args:
- rel_coor: (x,y) offset from this element's coordinate
- area: (width,height) tuple
+ Create labels (if applicable) and call on all children.
+ Call this base method before creating labels in the element.
"""
- self._areas_list.append((rel_coor, area))
- def add_line(self, rel_coor1, rel_coor2):
+ def create_shapes(self):
"""
- Add a line to the line list.
- A line is defined by 2 relative coordinates.
- Lines must be horizontal or vertical.
- The line is associated with a rotation.
-
- Args:
- rel_coor1: relative (x1,y1) tuple
- rel_coor2: relative (x2,y2) tuple
+ Create shapes (if applicable) and call on all children.
+ Call this base method before creating shapes in the element.
"""
- self._lines_list.append((rel_coor1, rel_coor2))
+
+ def draw(self, cr):
+ raise NotImplementedError()
+
+ def bounds_from_area(self, area):
+ x1, y1, w, h = area
+ x2 = x1 + w
+ y2 = y1 + h
+ self._bounding_rects = [(x1, y1, x2, y2)]
+ self._bounding_points = [(x1, y1), (x2, y1), (x1, y2), (x2, y2)]
+
+ def bounds_from_line(self, line):
+ self._bounding_rects = rects = []
+ self._bounding_points = list(line)
+ last_point = line[0]
+ for x2, y2 in line[1:]:
+ (x1, y1), last_point = last_point, (x2, y2)
+ if x1 == x2:
+ x1, x2 = x1 - LINE_SELECT_SENSITIVITY, x2 + LINE_SELECT_SENSITIVITY
+ if y2 < y1:
+ y1, y2 = y2, y1
+ elif y1 == y2:
+ y1, y2 = y1 - LINE_SELECT_SENSITIVITY, y2 + LINE_SELECT_SENSITIVITY
+ if x2 < x1:
+ x1, x2 = x2, x1
+
+ rects.append((x1, y1, x2, y2))
def what_is_selected(self, coor, coor_m=None):
"""
@@ -222,54 +151,31 @@ class Element(object):
Returns:
self if one of the areas/lines encompasses coor, else None.
"""
- #function to test if p is between a and b (inclusive)
- in_between = lambda p, a, b: p >= min(a, b) and p <= max(a, b)
- #relative coordinate
- x, y = [a-b for a,b in zip(coor, self.get_coordinate())]
- if coor_m:
- x_m, y_m = [a-b for a,b in zip(coor_m, self.get_coordinate())]
- #handle rectangular areas
- for (x1,y1), (w,h) in self._areas_list:
- if in_between(x1, x, x_m) and in_between(y1, y, y_m) or \
- in_between(x1+w, x, x_m) and in_between(y1, y, y_m) or \
- in_between(x1, x, x_m) and in_between(y1+h, y, y_m) or \
- in_between(x1+w, x, x_m) and in_between(y1+h, y, y_m):
- return self
- #handle horizontal or vertical lines
- for (x1, y1), (x2, y2) in self._lines_list:
- if in_between(x1, x, x_m) and in_between(y1, y, y_m) or \
- in_between(x2, x, x_m) and in_between(y2, y, y_m):
+ x, y = [a - b for a, b in zip(coor, self.coordinate)]
+
+ if not coor_m:
+ for x1, y1, x2, y2 in self._bounding_rects:
+ if x1 <= x <= x2 and y1 <= y <= y2:
return self
- return None
else:
- #handle rectangular areas
- for (x1,y1), (w,h) in self._areas_list:
- if in_between(x, x1, x1+w) and in_between(y, y1, y1+h): return self
- #handle horizontal or vertical lines
- for (x1, y1), (x2, y2) in self._lines_list:
- if x1 == x2: x1, x2 = x1-LINE_SELECT_SENSITIVITY, x2+LINE_SELECT_SENSITIVITY
- if y1 == y2: y1, y2 = y1-LINE_SELECT_SENSITIVITY, y2+LINE_SELECT_SENSITIVITY
- if in_between(x, x1, x2) and in_between(y, y1, y2): return self
- return None
-
- def get_rotation(self):
- """
- Get the rotation in degrees.
-
- Returns:
- the rotation
- """
- return self.rotation
-
- def set_rotation(self, rotation):
- """
- Set the rotation in degrees.
+ x_m, y_m = [a - b for a, b in zip(coor_m, self.coordinate)]
+ if y_m < y:
+ y, y_m = y_m, y
+ if x_m < x:
+ x, x_m = x_m, x
+
+ for x1, y1 in self._bounding_points:
+ if x <= x1 <= x_m and y <= y1 <= y_m:
+ return self
- Args:
- rotation: the rotation"""
- if rotation not in POSSIBLE_ROTATIONS:
- raise Exception('"%s" is not one of the possible rotations: (%s)'%(rotation, POSSIBLE_ROTATIONS))
- self.rotation = rotation
+ @property
+ def extend(self):
+ x_min, y_min = x_max, y_max = self.coordinate
+ x_min += min(x for x, y in self._bounding_points)
+ y_min += min(y for x, y in self._bounding_points)
+ x_max += max(x for x, y in self._bounding_points)
+ y_max += max(y for x, y in self._bounding_points)
+ return x_min, y_min, x_max, y_max
def mouse_over(self):
pass