1
""" Defines the PlotLabel class.
3
from enthought.kiva import font_metrics_provider
4
from enthought.traits.api import Delegate, Enum, Instance
6
from abstract_overlay import AbstractOverlay
7
from label import Label
10
class PlotLabel(AbstractOverlay):
11
""" A label used by plots.
13
This class wraps a simple Label instance, and delegates some traits to it.
16
# The text of the label.
17
text = Delegate("_label")
18
# The color of the label text.
19
color = Delegate("_label", modify=True)
20
# The font for the label text.
21
font = Delegate("_label")
22
# The angle of rotation of the label.
23
angle = Delegate("_label", "rotate_angle")
25
#------------------------------------------------------------------------
26
# Layout-related traits
27
#------------------------------------------------------------------------
29
# Horizontal justification used if the label has more horizontal space
31
hjustify = Enum("center", "left", "right")
33
# Vertical justification used if the label has more vertical space than it
35
vjustify = Enum("center", "bottom", "top")
37
# The position of this label relative to the object it is overlaying.
38
overlay_position = Enum("top", "bottom", "left", "right", None)
40
# Should this PlotLabel modify the padding on its underlying component
41
# if there is not enough room to lay out the text?
42
# FIXME: This could cause cycles in layout, so not implemented for now
43
#modify_component = Bool(True)
45
# By default, this acts like a component and will render on the main
46
# "plot" layer unless its **component** attribute gets set.
49
#------------------------------------------------------------------------
51
#------------------------------------------------------------------------
53
# The label has a fixed height and can be resized horizontally. (Overrides
57
# The Label instance this plot label is wrapping.
58
_label = Instance(Label, args=())
61
def __init__(self, text="", *args, **kw):
62
super(PlotLabel, self).__init__(*args, **kw)
66
def overlay(self, component, gc, view_bounds=None, mode="normal"):
67
""" Draws this label overlaid on another component.
69
Overrides AbstractOverlay.
71
self._draw_overlay(gc, view_bounds, mode)
74
def get_preferred_size(self):
75
""" Returns the label's preferred size.
77
Overrides PlotComponent.
79
dummy_gc = font_metrics_provider()
80
size = self._label.get_bounding_box(dummy_gc)
84
""" Tells this component to do layout.
86
Overrides PlotComponent.
88
if self.component is not None:
89
self._layout_as_overlay()
91
self._layout_as_component()
94
def _draw_overlay(self, gc, view_bounds=None, mode="normal"):
95
""" Draws the overlay layer of a component.
97
Overrides PlotComponent.
100
# Perform justification and compute the correct offsets for
102
width, height = self._label.get_bounding_box(gc)
103
if self.hjustify == "left":
105
elif self.hjustify == "right":
106
x_offset = self.width - width
107
elif self.hjustify == "center":
108
x_offset = int((self.width - width) / 2)
110
if self.vjustify == "bottom":
112
elif self.vjustify == "top":
113
y_offset = self.height - height
114
elif self.vjustify == "center":
115
y_offset = int((self.height - height) / 2)
119
# XXX: Uncomment this after we fix kiva GL backend's clip stack
120
#gc.clip_to_rect(self.x, self.y, self.width, self.height)
122
# We have to translate to our position because the label
123
# tries to draw at (0,0)
124
gc.translate_ctm(self.x + x_offset, self.y + y_offset)
130
def _draw_plot(self, gc, view_bounds=None, mode="normal"):
131
if self.component is None:
132
# We are not overlaying anything else, so we should render
134
self._draw_overlay(gc, view_bounds, mode)
136
def _layout_as_component(self, size=None, force=False):
139
def _layout_as_overlay(self, size=None, force=False):
140
""" Lays out the label as an overlay on another component.
142
if self.component is not None:
143
orientation = self.overlay_position
144
if orientation in ("left", "right"):
145
self.y = self.component.y
146
self.height = self.component.height
147
if orientation == "left":
148
self.width = self.component.padding_left
149
self.x = self.component.outer_x
150
elif orientation == "right":
151
self.width = self.component.padding_right
152
self.x = self.component.x2 + 1
153
elif orientation in ("bottom", "top"):
154
self.x = self.component.x
155
self.width = self.component.width
156
if orientation == "bottom":
157
self.height = self.component.padding_bottom
158
self.y = self.component.outer_y
159
elif orientation == "top":
160
self.height = self.component.padding_top
161
self.y = self.component.y2 + 1
163
# Leave the position alone
167
def _text_changed(self, old, new):
168
self._label.text = new
172
def _font_changed(self, old, new):
173
self._label.font = new
177
def _angle_changed(self, old, new):
178
self._label.rotate_angle = new
182
def _component_changed(self, old, new):
184
self.draw_layer = "overlay"
186
self.draw_layer = "plot"