Package arcmap :: Module graphics
[hide private]
[frames] | no frames]

Source Code for Module arcmap.graphics

  1  ################################################################################ 
  2  # Authors: Brian Schott (Sir Alaran) 
  3  # Copyright: Brian Schott (Sir Alaran) 
  4  # Date: Sep 29 2009 
  5  # License: 
  6  # 
  7  # This program is free software: you can redistribute it and/or modify 
  8  # it under the terms of the GNU General Public License as published by 
  9  # the Free Software Foundation, either version 3 of the License, or 
 10  # (at your option) any later version. 
 11  # 
 12  # This program is distributed in the hope that it will be useful, 
 13  # but WITHOUT ANY WARRANTY; without even the implied warranty of 
 14  # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 
 15  # GNU General Public License for more details. 
 16  # 
 17  # You should have received a copy of the GNU General Public License 
 18  # along with this program.  If not, see <http://www.gnu.org/licenses/>. 
 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   
40 -def getBackgroundColor():
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
52 -def getForegroundColor():
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
64 -def getHighlightColor():
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
72 -def getFileFilter():
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") # Preffered 79 fFilter.add_mime_type("image/x-ms-bmp") # Also works 80 fFilter.add_mime_type("image/jpeg") # a bad idea for pixel-art... 81 fFilter.add_mime_type("image/x-pcx") 82 fFilter.add_mime_type("image/x-tga") 83 fFilter.add_mime_type("image/gif") # TODO: Test this with an animation 84 fFilter.set_name("Images") 85 return fFilter
86 87
88 -def loadImage(fileName):
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
112 -class RGBA(object):
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 # Silly Python 130 r = 0.0 131 g = 0.0 132 b = 0.0 133 a = 1.0
134
135 - def toU32(self):
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
142 - def fromU32(self, u):
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
149 - def setGdk(self, color):
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
158 - def getGdk(self):
159 """ 160 @rtype: a gtk.gdk.Color 161 @return: this color in gdk format 162 """ 163 # 2**16 = 65536 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
171 -def getCheckerPattern(ts):
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 # tso = tile size over ... 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):
224 outlineColor = RGBA() 225 outlineColor.fromU32(preferences.visual["valid_outline"]) 226 fillColor = RGBA() 227 fillColor.fromU32(preferences.visual["valid_fill"]) 228 if hasattr(shape, "getRadius"): 229 drawCircle(context, shape, outlineColor, 230 fillColor, handles) 231 else: 232 if shape.convex() == False: 233 outlineColor.fromU32(preferences.visual["invalid_outline"]) 234 fillColor.fromU32(preferences.visual["invalid_fill"]) 235 drawPolygon(context, shape, outlineColor, fillColor, handles) 236 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 # 0.5 to align the points to pixels 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
296 -def drawPointHandle(context, p, lineWidth = 1.0):
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
318 -def drawMoveHandle(context, p):
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 # Right arrow 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 # Left arrow 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 # Bottom arrow 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 # Top arrow 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 # reset default argument 370 size = -1
371 372
373 -def getDeleteCirclePattern(size):
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
393 -def getDeletePattern(size):
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