diff options
Diffstat (limited to 'grc/gui/Element.py')
-rw-r--r-- | grc/gui/Element.py | 250 |
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 |