-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathartist.py
230 lines (182 loc) · 7.29 KB
/
artist.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
from base import *
from color import Color
class Artist(PObject, Parent):
"""
Base class for any object that draws onto a Figure.
To draw an Artist on a Figure, it must know where to draw.
This is done by setting an origin and a position in relation
to that origin. The origin is defined in the Figure's global
coordinates, and is usually set to the origin of the Artist's
parent Plot. In this case, if the Plot is moved on the Figure,
then the Artist just needs its origin changed, and it will still
be presented in the same position relative to the Plot.
**Coordinates**
The specific canvas being used will have its own coordinates
specifying positions of items on its canvas. To convert from
PyGraphene coordinates to the canvas's coordinates, each canvas
must provide figureToScene and sceneToFigure methods.
Figure coordinates start in the bottom-left corner of the canvas
and increase up and to the right.
Plot coordinates have the same units and directions as figure
coordinates, but their origin can be offset from the Figure's
origin by an arbitrary amount. This allows for Artists to set
their position in relation to a plot, enabling vastly simplified
moving of plots around the Figure. Plot coordinates also increase
up and to the right.
====================== ================= =======
Property Possible Values Description
====================== ================= =======
color | Color The primary color to be used when drawing this Artist.
| Color format
visible bool (True) Determine whether to draw this Artist.
aliased bool (False) Whether this Artist is antialiased (False) or aliased (True).
====================== ================= =======
"""
def __init__(self, canvas, *args, **kwprops):
"""
**Constructor**
Initialize the origin and position. Also set the canvas for this Artist to draw with.
"""
initialProperties = {'color': Color('black'),
'visible': True,
'aliased': False,
}
initialProperties.update(kwprops)
Parent.__init__(self)
PObject.__init__(self, initialProperties)
self._canvas = canvas
self._item = None
self._clipPath = None
self.setOrigin()
self.setPosition()
def canvas(self):
"""
Return the canvas object.
"""
return self._canvas
def origin(self):
"""
Return the origin of this artist, in figure coordinates.
"""
return self._ox, self._oy
def setOrigin(self, x=0, y=0):
"""
Set the origin, using figure coordinates.
"""
self._ox = float(x)
self._oy = float(y)
def position(self):
"""
Return the position of this artist, in plot coordinates.
"""
return self._x, self._y
def setPosition(self, x=0, y=0):
"""
Set the position of this artist, using plot coordinates.
"""
self._x = float(x)
self._y = float(y)
def isVisible(self):
"""Return whether this Artist will be drawn."""
return self.props('visible')
def setVisible(self, v=True):
"""Set whether to draw this Artist."""
if isinstance(v, bool):
self.setProps(visible=v)
def setInvisible(self):
"""Set whether to hide this Artist."""
self.setVisible(False)
def setColor(self, color):
"""
Convenience method to set the primary color of this Artist.
color can be either a Color object or any valid Color format.
"""
if not isinstance(color, Color):
color = Color(color)
self.setProps(color=color)
def color(self):
"""Return the color of this Artist."""
color = self.props('color')
if not isinstance(color, Color):
color = Color(color)
return color
def setProps(self, props={}, **kwprops):
"""
Remove 'color' from props and/or kwprops. Then set the color, and
then set the kwprops. props takes precedence over kwprops.
"""
color = kwprops.pop('color', None)
color = props.pop('color', color)
if not isinstance(color, Color):
kwprops['color'] = Color(color)
else:
kwprops['color'] = color
PObject.setProps(self, props, **kwprops)
def setClipPath(self, clipPath):
"""
A clip path is a rectangle that the Artist will be drawn within.
If part of the Artist is intended to be drawn outside the clip path,
it will not be drawn on the screen.
clipPath should be a 4-tuple of the form (x, y, width, height). x
and y must be in figure coordinates. Alternatively, clipPath can be
None.
"""
if clipPath is None or (len(clipPath) == 4 and (isinstance(clipPath, tuple) or isinstance(clipPath, list))):
self._clipPath = clipPath
def clipPath(self):
"""
Return the clip path.
clipPath will be a 4-tuple of the form (x, y, width, height). x
and y must be in figure coordinates. Alternatively, clipPath can be
None.
"""
return self._clipPath
def resize(self, oldWidth, oldHeight, newWidth, newHeight):
"""
Reposition and (potentially) resize this Artist to correspond to a new
Figure size. The arguments correspond to the Figure's old and new size.
"""
# Relocate origin
ox, oy = self.origin()
ox = newWidth * ox / oldWidth
oy = newHeight * oy / oldHeight
self.setOrigin(ox, oy)
# Relocate position
x, y = self.position()
x = newWidth * x / oldWidth
y = newHeight * y / oldHeight
self.setPosition(x, y)
def draw(self, *args, **kwargs):
"""
Draw this Artist if it is visible. args and kwargs may be
used when drawing, but this is not guaranteed. Specifically,
kwargs is not used to update the Artist's properties.
Implementation hint: After testing whether the Artist is
visible, this method calls _draw. If subclassing Artist,
drawing should be done entirely in _draw(), and draw()
should not be overridden.
"""
self.remove()
if self.isVisible():
self._item = self._draw(*args, **kwargs)
self.canvas().update()
def _draw(self, *args, **kwargs):
"""
Does the actual drawing of this Artist.
Must be overwritten in the subclass.
"""
pass
def remove(self):
"""
Remove this Artist from the canvas, but do not delete the Artist.
"""
if self._item is not None:
try:
if isinstance(self._item, list) or isinstance(self._item, tuple):
for i in self._item:
self.canvas().remove(i)
else:
self.canvas().remove(self._item)
except:
# Don't worry if it cannot be deleted; it probably doesn't exist anymore
pass