diff options
author | Sebastian Koslowski <koslowski@kit.edu> | 2016-09-13 11:54:56 -0600 |
---|---|---|
committer | Sebastian Koslowski <koslowski@kit.edu> | 2016-09-13 11:54:56 -0600 |
commit | bc8ee049aefb7818b82adfc24de22590ee00b23f (patch) | |
tree | 50bf5f19deb24bc8bdf911fc49283a1f0cfc81d9 /grc/gui/canvas/drawable.py | |
parent | f7cdfff6a85ce52b1d7c0b5131645fcb77405fe8 (diff) |
grc: refactor: move drawables in subpackage
Diffstat (limited to 'grc/gui/canvas/drawable.py')
-rw-r--r-- | grc/gui/canvas/drawable.py | 184 |
1 files changed, 184 insertions, 0 deletions
diff --git a/grc/gui/canvas/drawable.py b/grc/gui/canvas/drawable.py new file mode 100644 index 0000000000..d1a6f42667 --- /dev/null +++ b/grc/gui/canvas/drawable.py @@ -0,0 +1,184 @@ +""" +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 +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +GNU Radio Companion is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA +""" + +from __future__ import absolute_import +from ..Constants import LINE_SELECT_SENSITIVITY + +from six.moves import zip + + +class Drawable(object): + """ + GraphicalElement is the base class for all graphical elements. + It contains an X,Y coordinate, a list of rectangular areas that the element occupies, + 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.coordinate = (0, 0) + self.rotation = 0 + self.highlighted = False + + self._bounding_rects = [] + self._bounding_points = [] + + def is_horizontal(self, rotation=None): + """ + Is this element horizontal? + If rotation is None, use this element's rotation. + + Args: + rotation: the optional rotation + + Returns: + true if rotation is horizontal + """ + rotation = rotation or self.rotation + return rotation in (0, 180) + + def is_vertical(self, rotation=None): + """ + Is this element vertical? + If rotation is None, use this element's rotation. + + Args: + rotation: the optional rotation + + Returns: + true if rotation is vertical + """ + rotation = rotation or self.rotation + return rotation in (90, 270) + + def rotate(self, rotation): + """ + Rotate all of the areas by 90 degrees. + + Args: + rotation: multiple of 90 degrees + """ + self.rotation = (self.rotation + rotation) % 360 + + def move(self, delta_coor): + """ + Move the element by adding the delta_coor to the current coordinate. + + Args: + delta_coor: (delta_x,delta_y) tuple + """ + x, y = self.coordinate + dx, dy = delta_coor + self.coordinate = (x + dx, y + dy) + + def create_labels(self): + """ + Create labels (if applicable) and call on all children. + Call this base method before creating labels in the element. + """ + + def create_shapes(self): + """ + Create shapes (if applicable) and call on all children. + Call this base method before creating shapes in the element. + """ + + 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): + """ + One coordinate specified: + Is this element selected at given coordinate? + ie: is the coordinate encompassed by one of the areas or lines? + Both coordinates specified: + Is this element within the rectangular region defined by both coordinates? + ie: do any area corners or line endpoints fall within the region? + + Args: + coor: the selection coordinate, tuple x, y + coor_m: an additional selection coordinate. + + Returns: + self if one of the areas/lines encompasses coor, else None. + """ + 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 + else: + 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 + + @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 + + def mouse_out(self): + pass |