Source code for enable.primitives.shape
# (C) Copyright 2005-2022 Enthought, Inc., Austin, TX
# All rights reserved.
#
# This software is provided without warranty under the terms of the BSD
# license included in LICENSE.txt and may be redistributed only under
# the conditions described in the aforementioned license. The license
# is also available online at http://www.enthought.com/licenses/BSD.txt
#
# Thanks for using Enthought open source!
""" The base class for moveable shapes. """
# Standard library imports.
import math
# Enthought library imports.
from enable.colors import ColorTrait
from enable.component import Component
from enable.enable_traits import Pointer
from kiva.api import MODERN, Font
from traits.api import Float, Property, Str, Tuple
[docs]class Shape(Component):
""" The base class for moveable shapes. """
# 'Component' interface ################################################
# The background color of this component.
bgcolor = "transparent"
# 'Shape' interface ####################################################
# The coordinates of the center of the shape.
center = Property(Tuple)
# The fill color.
fill_color = ColorTrait
# The pointer for the 'normal' event state.
normal_pointer = Pointer("arrow")
# The pointer for the 'moving' event state.
moving_pointer = Pointer("hand")
# The text color.
text_color = ColorTrait
# The text displayed in the shape.
text = Str
# 'Private' interface ##################################################
# The difference between the location of a mouse-click and the component's
# origin.
_offset_x = Float
_offset_y = Float
###########################################################################
# 'Interactor' interface
###########################################################################
[docs] def normal_key_pressed(self, event):
""" Event handler. """
print("normal_key_pressed", event.character)
[docs] def normal_left_down(self, event):
""" Event handler. """
if self.is_in(event.x, event.y):
self.event_state = "moving"
event.window.mouse_owner = self
event.window.set_pointer(self.moving_pointer)
self._offset_x = event.x - self.x
self._offset_y = event.y - self.y
# move this shape to the top of the z order. The components are
# drawn in order, so the last one will be drawn on top
siblings = self.container.components
if len(siblings) > 1:
siblings.remove(self)
siblings.append(self)
[docs] def moving_mouse_move(self, event):
""" Event handler. """
top = event.y + self._offset_y
bottom = event.y - self._offset_y
left = event.x - self._offset_x
right = event.x + self._offset_x
# Keep the shape fully in the container
if bottom < 0:
bottom = 0
elif top > self.container.height:
bottom = self.container.height - self.height
if left < 0:
left = 0
elif right > self.container.width:
left = self.container.width - self.width
self.position = [left, bottom]
self.request_redraw()
[docs] def moving_left_up(self, event):
""" Event handler. """
self.event_state = "normal"
event.window.set_pointer(self.normal_pointer)
event.window.mouse_owner = None
self.request_redraw()
[docs] def moving_mouse_leave(self, event):
""" Event handler. """
self.moving_left_up(event)
###########################################################################
# 'Shape' interface
###########################################################################
def _get_center(self):
""" Property getter. """
dx, dy = self.bounds
ox, oy = self.position
cx = ox + dx / 2
cy = oy + dy / 2
return cx, cy
def _text_default(self):
""" Trait initializer. """
return type(self).__name__
###########################################################################
# Protected 'Shape' interface
###########################################################################
def _distance_between(self, point_1, point_2):
""" Return the distance between two points. """
(x1, y1) = point_1
(x2, y2) = point_2
return math.sqrt(pow(x1 - x2, 2) + pow(y1 - y2, 2))
def _draw_text(self, gc):
""" Draw the shape's text. """
if len(self.text) > 0:
gc.set_fill_color(self._get_text_color(self.event_state))
gc.set_font(Font(family=MODERN, size=16))
tx, ty, tw, th = gc.get_text_extent(self.text)
dx, dy = self.bounds
x, y = self.position
gc.set_text_position(x + (dx - tw) / 2, y + (dy - th) / 2)
gc.show_text(self.text)
def _get_fill_color(self, event_state):
""" Return the fill color based on the event state. """
if event_state == "normal":
fill_color = self.fill_color_
else:
r, g, b, a = self.fill_color_
fill_color = (r, g, b, 0.5)
return fill_color
def _get_text_color(self, event_state):
""" Return the text color based on the event state. """
if event_state == "normal":
text_color = self.text_color_
else:
r, g, b, a = self.text_color_
text_color = (r, g, b, 0.5)
return text_color