1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 """
23 Code for graphical operations such as tile and shape drawing.
24 """
25
26
27 import os
28 import math
29 import logging
30
31 import gobject
32 import gtk
33 import cairo
34
35 import shapes
36 import preferences
37
38 log = logging.getLogger("graphics")
39
41 """
42 @rtype: RGBA
43 @return: a color representation of the background color from the gtk theme
44 """
45 style = gtk.rc_get_style_by_paths(gtk.settings_get_default(),
46 "GtkTextView", "GtkTextView", gtk.TextView)
47 c = RGBA()
48 c.setGdk(style.bg[gtk.STATE_NORMAL])
49 return c
50
51
53 """
54 @rtype: RGBA
55 @return: the foreground color from the gtk theme
56 """
57 style = gtk.rc_get_style_by_paths(gtk.settings_get_default(),
58 "GtkTextView", "GtkTextView", gtk.TextView)
59 c = RGBA()
60 c.setGdk(style.text[gtk.STATE_NORMAL])
61 return c
62
63
65 style = gtk.rc_get_style_by_paths(gtk.settings_get_default(),
66 "GtkTextView", "GtkTextView", gtk.TextView)
67 c = RGBA()
68 c.setGdk(style.bg[gtk.STATE_SELECTED])
69 return c
70
71
73 """
74 @rtype: gtk.FileFilter
75 @return: A file filter for open dialogs allowing only image formats
76 """
77 fFilter = gtk.FileFilter()
78 fFilter.add_mime_type("image/png")
79 fFilter.add_mime_type("image/x-ms-bmp")
80 fFilter.add_mime_type("image/jpeg")
81 fFilter.add_mime_type("image/x-pcx")
82 fFilter.add_mime_type("image/x-tga")
83 fFilter.add_mime_type("image/gif")
84 fFilter.set_name("Images")
85 return fFilter
86
87
89 """
90 This function is used so that images in any format supported by gdk can be
91 loaded.
92 @type fileName: string
93 @param fileName: name of file to load
94 @rtype: cairo.ImageSurface
95 @return: An image surface containing the contents of the file
96 """
97 if not os.path.exists(fileName):
98 log.error("Could not open " + fileName)
99 return None
100 else:
101 pixbuf = gtk.gdk.pixbuf_new_from_file(fileName)
102 x = pixbuf.get_width()
103 y = pixbuf.get_height()
104 surface = cairo.ImageSurface(0,x,y)
105 ct = cairo.Context(surface)
106 ct2 = gtk.gdk.CairoContext(ct)
107 ct2.set_source_pixbuf(pixbuf,0,0)
108 ct2.paint()
109 return surface
110
111
113 - def __init__(self, r = 0.0, g = 0.0, b = 0.0, a = 1.0):
114 """
115 @type r: float
116 @param r: red
117 @type g: float
118 @param g: green
119 @type b: float
120 @param b: blue
121 @type a: float
122 @param a: alpha
123 """
124 self.r = r
125 self.g = g
126 self.b = b
127 self.a = a
128
129
130 r = 0.0
131 g = 0.0
132 b = 0.0
133 a = 1.0
134
136 """
137 @return: a 32-bit unsigned integer representing the color
138 """
139 return ((int(self.r * 255) << 24) + (int(self.g * 255) << 16)
140 + (int(self.b * 255) << 8) + (int(self.a * 255)))
141
143 self.r = (u >> 24) / 255.0
144 self.g = ((u & 0x00ff0000) >> 16) / 255.0
145 self.b = ((u & 0x0000ff00) >> 8) / 255.0
146 self.a = (u & 0x000000ff) / 255.0
147
148
150 """
151 Sets this based on a gtk.gdk.Color
152 """
153 self.r = color.red / 65535.0
154 self.g = color.green / 65535.0
155 self.b = color.blue / 65535.0
156 self.a = 1.0
157
159 """
160 @rtype: a gtk.gdk.Color
161 @return: this color in gdk format
162 """
163
164 return gtk.gdk.Color(int(self.r * 65535), int(self.g * 65535),
165 int(self.b * 65535))
166
167 - def contextColor(self, context):
168 context.set_source_rgba(self.r, self.g, self.b, self.a)
169
170
172 """
173 @type ts: int
174 @param ts: size of the checker pattern in pixels
175 @rtype: cairo.SurfacePattern
176 @return: the new pattern
177 """
178
179 tso4 = ts / 4
180 tso2 = ts / 2
181 checkerboard = cairo.ImageSurface(cairo.FORMAT_ARGB32, tso2, tso2)
182 checkerContext = cairo.Context(checkerboard)
183
184 checkerContext.set_source_rgba(0.5, 0.5, 0.5, 1)
185 checkerContext.rectangle(0, 0, tso2, tso2)
186 checkerContext.fill()
187
188 checkerContext.set_source_rgba(0.25, 0.25, 0.25, 1)
189 checkerContext.rectangle(tso4, 0, tso4, tso4)
190 checkerContext.fill()
191 checkerContext.rectangle(0, tso4, tso4, tso4)
192 checkerContext.fill()
193
194 checkerPattern = cairo.SurfacePattern(checkerboard)
195 checkerPattern.set_extend(cairo.EXTEND_REPEAT)
196 return checkerPattern
197
198
199 -def drawGrid(context, tileSize, width, height):
200 """
201 Draw a grid with cells the same size as tiles on a cairo context
202 @type context: cairo.Context
203 @param context: the destination context
204 @type tileSize: int
205 @param tileSize: the size of the grid cells
206 """
207 context.save()
208 context.set_source_rgba(0.0, 0.0, 0.0, 1.0)
209 context.set_dash((preferences.visual["stipple_length"],
210 preferences.visual["stipple_gap"]))
211 context.set_line_width(1)
212 for i in range(width // tileSize):
213 context.move_to(i * tileSize + .5 , 0)
214 context.line_to(i * tileSize + .5, height)
215 context.stroke()
216 for i in range(height // tileSize):
217 context.move_to(0, i * tileSize + .5)
218 context.line_to(width, i * tileSize + .5)
219 context.stroke()
220 context.restore()
221
222
223 -def drawShape(shape, context, handles = False):
237
238
239 -def drawPolygon(context, shape, outlineColor, fillColor, handles = False):
240 """
241 @type context: cairo.Context
242 @param context: context to draw on
243 @type shape: shapes.Shape
244 @param shape: the shape to draw
245 @type outlineColor: RGBA
246 @param outlineColor: color for the outline
247 @type fillColor: RGBA
248 @param fillColor: color for the filled shape
249 @type handles: bool
250 @param handles: True if handles should be drawn on the points
251 """
252 outlineColor.contextColor(context)
253 points = shape.getPoints()
254 context.set_line_width(2.0)
255 context.move_to(points[0].x, points[0].y)
256 for point in shape.getPoints():
257
258 context.line_to(point.x, point.y)
259 context.close_path()
260 context.stroke_preserve()
261 fillColor.contextColor(context)
262 context.fill()
263
264 if handles:
265 for point in points:
266 drawPointHandle(context, point)
267 handles = False
268
269
270 -def drawCircle(context, shape, outlineColor, fillColor, handles = False):
271 """
272 @type context: cairo.Context
273 @param context: context to draw to
274 @type shape: shapes.Shape
275 @param shape: the shape to draw
276 @type outlineColor: RGBA
277 @param outlineColor: color for the outline
278 @type fillColor: RGBA
279 @param fillColor: color for the filled shape
280 @type handles: bool
281 @param handles: True if the handles should be drawn, false otherwise
282 """
283 outlineColor.contextColor(context)
284 context.set_line_width(2.0)
285 c = shape.getCenter()
286 context.arc(c.x, c.y, shape.getRadius(), 0, math.pi * 2)
287 context.stroke_preserve()
288 fillColor.contextColor(context)
289 context.fill()
290
291 if handles:
292 for point in shape.getHandles():
293 drawPointHandle(context, point)
294
295
297 """
298 @type context: cairo.Context
299 @param context: destination context
300 @type p: shapes.Point
301 @param p: the point to draw
302 """
303 size = preferences.visual["handle_size"]
304 x = p.x - int(size / 2.0)
305 y = p.y - int(size / 2.0)
306 context.rectangle(x + 0.5, y + 0.5, size, size)
307 context.set_source_rgba(0.0, 0.0, 0.0, 1.0)
308 context.set_line_width(lineWidth)
309 context.stroke()
310 context.rectangle(x + 1.5, y + 1.5, size, size)
311 context.set_source_rgba(1.0, 1.0, 1.0, 1.0)
312 context.set_line_width(lineWidth)
313 context.stroke()
314 size = -1
315 lineWidth = 1.0
316
317
319 """
320 Draws a movement handle (A four-pointed arrow)
321 @type context: cairo.Context
322 @param context: the context to draw on
323 @type p: shapes.Point
324 @param p: the point to draw the handle around
325 """
326 size = preferences.visual["handle_size"]
327
328 context.set_line_width(size / 4)
329 context.set_source_rgba(0.0, 0.0, 0.0, 1.0)
330
331 context.move_to(p.x - (size / 2) - 0.5, p.y)
332 context.line_to(p.x + (size / 2) + 0.5, p.y)
333 context.stroke()
334
335 context.move_to(p.x, p.y - (size / 2) - 0.5)
336 context.line_to(p.x, p.y + (size / 2) + 0.5)
337 context.stroke()
338
339 arrowSize = size / 2.5
340
341
342 context.move_to(p.x + (size / 2), p.y - arrowSize)
343 context.line_to(p.x + (size / 2) + arrowSize, p.y)
344 context.line_to(p.x + (size / 2), p.y + arrowSize)
345 context.close_path()
346 context.fill()
347
348
349 context.move_to(p.x - (size / 2), p.y - arrowSize)
350 context.line_to(p.x - (size / 2) - arrowSize, p.y)
351 context.line_to(p.x - (size / 2), p.y + arrowSize)
352 context.close_path()
353 context.fill()
354
355
356 context.move_to(p.x + arrowSize, p.y + (size / 2))
357 context.line_to(p.x, p.y + (size / 2) + arrowSize)
358 context.line_to(p.x - arrowSize, p.y + (size / 2))
359 context.close_path()
360 context.fill()
361
362
363 context.move_to(p.x + arrowSize, p.y - (size / 2))
364 context.line_to(p.x, p.y - (size / 2) - arrowSize)
365 context.line_to(p.x - arrowSize, p.y - (size / 2))
366 context.close_path()
367 context.fill()
368
369
370 size = -1
371
372
374 """
375 @type size: int
376 @param size: Size of the circle
377 @rtype: cairo.SurfacePattern
378 @return: a red circle with a line through it.
379 """
380 surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, size, size)
381 context = cairo.Context(surface)
382 context.set_source_rgba(1.0, 0.0, 0.0, 1.0)
383 context.arc(size / 2, size / 2, size / 2 * .8 , 0, math.pi * 2)
384 context.set_line_width(size / 8)
385 context.stroke_preserve()
386 context.clip()
387 context.move_to(0, 0)
388 context.line_to(size, size)
389 context.stroke()
390 return cairo.SurfacePattern(surface)
391
392
394 """
395 @type size: int
396 @param size: the size of the x
397 @rtype: cairo.SurfacePattern
398 @return: a red x
399 """
400 surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, size, size)
401 context = cairo.Context(surface)
402 context.set_source_rgba(1.0, 0.0, 0.0, 1.0)
403 lineWidth = size / 8
404 context.move_to(lineWidth, lineWidth)
405 context.line_to(size - lineWidth, size - lineWidth)
406 context.move_to(lineWidth, size - lineWidth)
407 context.line_to(size - lineWidth, lineWidth)
408 context.stroke()
409 return cairo.SurfacePattern(surface)
410