diff options
Diffstat (limited to 'TurtleArt/tacanvas.py')
-rw-r--r-- | TurtleArt/tacanvas.py | 313 |
1 files changed, 159 insertions, 154 deletions
diff --git a/TurtleArt/tacanvas.py b/TurtleArt/tacanvas.py index bf22248..6a78a17 100644 --- a/TurtleArt/tacanvas.py +++ b/TurtleArt/tacanvas.py @@ -73,7 +73,8 @@ def calc_gray(c, g, invert=False): colors = {} -DEGTOR = 2 * pi / 360 +DEGTOR = pi / 180. +RTODEG = 180. / pi COLOR_TABLE = ( 0xFF0000, 0xFF0D00, 0xFF1A00, 0xFF2600, 0xFF3300, @@ -106,12 +107,12 @@ class TurtleGraphics: self.tw = tw self.width = width self.height = height - + # Build a cairo.Context from a cairo.XlibSurface self.canvas = cairo.Context(self.tw.turtle_canvas) cr = gtk.gdk.CairoContext(self.canvas) cr.set_line_cap(1) # Set the line cap to be round - + self.cr_svg = None # Surface used for saving to SVG self.cx = 0 self.cy = 0 self.fgrgb = [255, 0, 0] @@ -127,16 +128,24 @@ class TurtleGraphics: self.gray = 100 self.fill = False self.poly_points = [] - self.svg = SVG() - self.svg.set_fill_color('none') - self.tw.svg_string = '' + + def setup_svg_surface(self): + ''' Set up a surface for saving to SVG ''' + if self.tw.running_sugar: + svg_surface = cairo.SVGSurface( + os.path.join(get_path(self.tw.activity, 'instance'), + 'output.svg'), self.width, self.height) + else: + svg_surface = cairo.SVGSurface( + os.path.join(os.getcwd(), 'output.svg'), + self.width, self.height) + self.cr_svg = cairo.Context(svg_surface) + self.cr_svg.set_line_cap(1) # Set the line cap to be round def start_fill(self): ''' Start accumulating points of a polygon to fill. ''' self.fill = True self.poly_points = [] - if self.tw.saving_svg: - self.tw.svg_string += '<g>' def stop_fill(self): ''' Fill the polygon. ''' @@ -153,52 +162,48 @@ class TurtleGraphics: shared_poly_points])) self.tw.send_event(event) self.poly_points = [] - if self.tw.saving_svg: - self.tw.svg_string += '</g>' def fill_polygon(self, poly_points): ''' Draw the polygon... ''' - self.canvas.new_path() - for i, p in enumerate(poly_points): - if p[0] == 'move': - self.canvas.move_to(p[1], p[2]) - elif p[0] == 'rarc': - self.canvas.arc(p[1], p[2], p[3], p[4], p[5]) - elif p[0] == 'larc': - self.canvas.arc_negative(p[1], p[2], p[3], p[4], p[5]) - else: # line - self.canvas.line_to(p[1], p[2]) - self.canvas.close_path() - self.canvas.fill() - if self.tw.saving_svg and self.pendown: - self.svg.set_fill_color('#%02x%02x%02x' % (self.fgrgb[0], - self.fgrgb[1], - self.fgrgb[2])) - self.tw.svg_string += self.svg.new_path(poly_points[0][0], - poly_points[0][1]) - for p in range(len(poly_points)): - if p > 0: - self.tw.svg_string += self.svg.line_to(poly_points[p][0], - poly_points[p][1]) - self.tw.svg_string += '"\n' - self.tw.svg_string += self.svg.style() - self.svg.set_fill_color('none') + def _fill_polygon(cr, poly_points): + cr.new_path() + for i, p in enumerate(poly_points): + if p[0] == 'move': + cr.move_to(p[1], p[2]) + elif p[0] == 'rarc': + cr.arc(p[1], p[2], p[3], p[4], p[5]) + elif p[0] == 'larc': + cr.arc_negative(p[1], p[2], p[3], p[4], p[5]) + else: # line + cr.line_to(p[1], p[2]) + cr.close_path() + cr.fill() + + _fill_polygon(self.canvas, poly_points) + self.inval() + if self.cr_svg is not None: + _fill_polygon(self.cr_svg, poly_points) def clearscreen(self, share=True): '''Clear the canvas and reset most graphics attributes to defaults.''' - self.canvas.move_to(0, 0) - self.canvas.set_source_rgb(self.bgrgb[0] / 255., - self.bgrgb[1] / 255., - self.bgrgb[2] / 255.) - self.canvas.rectangle(0, 0, self.width * 2, self.height * 2) - self.canvas.fill() + + def _clearscreen(cr): + cr.move_to(0, 0) + cr.set_source_rgb(self.bgrgb[0] / 255., + self.bgrgb[1] / 255., + self.bgrgb[2] / 255.) + cr.rectangle(0, 0, self.width * 2, self.height * 2) + cr.fill() + + _clearscreen(self.canvas) self.inval() + if self.cr_svg is not None: + _clearscreen(self.cr_svg) + self.setpensize(5, share) self.setgray(100, share) self.setcolor(0, share) self.setshade(50, share) - self.tw.svg_string = '' - self.svg.reset_min_max() self.fill = False self.poly_points = [] for turtle_key in iter(self.tw.turtles.dict): @@ -222,6 +227,10 @@ class TurtleGraphics: nn = n * self.tw.coord_scale self.canvas.set_source_rgb(self.fgrgb[0] / 255., self.fgrgb[1] / 255., self.fgrgb[2] / 255.) + if self.cr_svg is not None: + debug_output('in forward', True) + self.cr_svg.set_source_rgb(self.fgrgb[0] / 255., + self.fgrgb[1] / 255., self.fgrgb[2] / 255.) oldx, oldy = self.xcor, self.ycor try: self.xcor += nn * sin(self.heading * DEGTOR) @@ -274,6 +283,9 @@ class TurtleGraphics: ''' Draw an arc ''' self.canvas.set_source_rgb(self.fgrgb[0] / 255., self.fgrgb[1] / 255., self.fgrgb[2] / 255.) + if self.cr_svg is not None: + self.cr_svg.set_source_rgb(self.fgrgb[0] / 255., + self.fgrgb[1] / 255., self.fgrgb[2] / 255.) try: if a < 0: self.larc(-a, r) @@ -303,11 +315,15 @@ class TurtleGraphics: cy = self.ycor - r * sin(self.heading * DEGTOR) if self.pendown: x, y = self.turtle_to_screen_coordinates(cx, cy) - self.canvas.arc(x, y, r, - (self.heading - 180) * DEGTOR, - (self.heading - 180 + a) * DEGTOR) - self.canvas.stroke() + + def _rarc(cr, x, y, r, a, h): + cr.arc(x, y, r, (h - 180) * DEGTOR, (h - 180 + a) * DEGTOR) + cr.stroke() + + _rarc(self.canvas, x, y, r, a, self.heading) self.inval() + if self.cr_svg is not None: + _rarc(self.cr_svg, x, y, r, a, self.heading) if self.fill: if self.poly_points == []: @@ -319,13 +335,6 @@ class TurtleGraphics: self.right(a, False) self.xcor = cx - r * cos(self.heading * DEGTOR) self.ycor = cy + r * sin(self.heading * DEGTOR) - if self.tw.saving_svg and self.pendown: - x, y = self.turtle_to_screen_coordinates(oldx, oldy) - self.tw.svg_string += self.svg.new_path(x, y) - x, y = self.turtle_to_screen_coordinates(self.xcor, self.ycor) - self.tw.svg_string += self.svg.arc_to(x, y, r, a, 0, s) - self.tw.svg_string += '"\n' - self.tw.svg_string += self.svg.style() def larc(self, a, r): ''' draw a counter-clockwise arc ''' @@ -341,11 +350,15 @@ class TurtleGraphics: cy = self.ycor + r * sin(self.heading * DEGTOR) if self.pendown: x, y = self.turtle_to_screen_coordinates(cx, cy) - self.canvas.arc_negative(x, y, r, - (self.heading) * DEGTOR, - (self.heading - a) * DEGTOR) - self.canvas.stroke() + + def _larc(cr, x, y, r, a, h): + cr.arc_negative(x, y, r, h * DEGTOR, (h - a) * DEGTOR) + cr.stroke() + + _larc(self.canvas, x, y, r, a, self.heading) self.inval() + if self.cr_svg is not None: + _larc(self.cr_svg, x, y, r, a, self.heading) if self.fill: if self.poly_points == []: @@ -357,13 +370,6 @@ class TurtleGraphics: self.right(-a, False) self.xcor = cx + r * cos(self.heading * DEGTOR) self.ycor = cy - r * sin(self.heading * DEGTOR) - if self.tw.saving_svg and self.pendown: - x, y = self.turtle_to_screen_coordinates(oldx, oldy) - self.tw.svg_string += self.svg.new_path(x, y) - x, y = self.turtle_to_screen_coordinates(self.xcor, self.ycor) - self.tw.svg_string += self.svg.arc_to(x, y, r, a, 0, s) - self.tw.svg_string += '"\n' - self.tw.svg_string += self.svg.style() def setxy(self, x, y, share=True, pendown=True): ''' Move turtle to position x,y ''' @@ -381,6 +387,10 @@ class TurtleGraphics: self.canvas.set_source_rgb(self.fgrgb[0] / 255., self.fgrgb[1] / 255., self.fgrgb[2] / 255.) + if self.cr_svg is not None: + self.cr_svg.set_source_rgb(self.fgrgb[0] / 255., + self.fgrgb[1] / 255., + self.fgrgb[2] / 255.) self.draw_line(oldx, oldy, self.xcor, self.ycor) self.inval() self.move_turtle() @@ -402,7 +412,8 @@ class TurtleGraphics: return self.tw.active_turtle.set_pen_size(ps) self.canvas.set_line_width(ps) - self.svg.set_stroke_width(self.pensize) + if self.cr_svg is not None: + self.cr_svg.set_line_width(ps) if self.tw.sharing() and share: event = 'w|%s' % (data_to_string([self._get_my_nick(), round_int(ps)])) @@ -478,17 +489,19 @@ class TurtleGraphics: oldc, olds = self.color, self.shade self.setcolor(c, False) self.setshade(s, False) - self.canvas.set_source_rgb(self.fgrgb[0] / 255., - self.fgrgb[1] / 255., - self.fgrgb[2] / 255.) self.bgrgb = self.fgrgb[:] - self.canvas.rectangle(0, 0, self.width * 2, self.height * 2) - self.canvas.fill() + + def _fillscreen(cr, rgb, w, h): + cr.set_source_rgb(rgb[0] / 255., rgb[1] / 255., rgb[2] / 255.) + cr.rectangle(0, 0, w * 2, h * 2) + cr.fill() + + _fillscreen(self.canvas, self.fgrgb, self.width, self.height) self.inval() + if self.cr_svg is not None: + _fillscreen(self.cr_svg, self.fgrgb, self.width, self.height) self.setcolor(oldc, False) self.setshade(olds, False) - self.tw.svg_string = '' - self.svg.reset_min_max() self.fill = False self.poly_points = [] @@ -515,9 +528,6 @@ class TurtleGraphics: b = calc_gray(b, self.gray) b = calc_shade(b, sh) self.fgrgb = [r >> 8, g >> 8, b >> 8] - self.svg.set_stroke_color('#%02x%02x%02x' % (self.fgrgb[0], - self.fgrgb[1], - self.fgrgb[2])) def setpen(self, bool, share=True): ''' Lower or raise the pen ''' @@ -529,42 +539,39 @@ class TurtleGraphics: def draw_surface(self, surface, x, y, w, h): ''' Draw a surface ''' - cr = gtk.gdk.CairoContext(self.canvas) - cr.set_source_surface(surface, x, y) - cr.rectangle(x, y, w, h) - cr.fill() + + def _draw_surface(cr, surface, x, y, w, h): + cc = gtk.gdk.CairoContext(cr) + cc.set_source_surface(surface, x, y) + cc.rectangle(x, y, w, h) + cc.fill() + + _draw_surface(self.canvas, surface, x, y, w, h) self.inval() + if self.cr_svg is not None: + _draw_surface(self.cr_svg, surface, x, y, w, h) def draw_pixbuf(self, pixbuf, a, b, x, y, w, h, path, share=True): ''' Draw a pixbuf ''' - # Build a gtk.gdk.CairoContext from a cairo.Context to access - # the set_source_pixbuf attribute. - cr = gtk.gdk.CairoContext(self.canvas) - cr.save() - # center the rotation on the center of the image - cr.translate(x + w / 2., y + h / 2.) - cr.rotate(self.heading * DEGTOR) - cr.translate(-x - w / 2., -y - h / 2.) - cr.set_source_pixbuf(pixbuf, x, y) - cr.rectangle(x, y, w, h) - cr.fill() - cr.restore() + + def _draw_pixbuf(cr, pixbuf, a, b, x, y, w, h, heading): + # Build a gtk.gdk.CairoContext from a cairo.Context to access + # the set_source_pixbuf attribute. + cc = gtk.gdk.CairoContext(cr) + cc.save() + # center the rotation on the center of the image + cc.translate(x + w / 2., y + h / 2.) + cc.rotate(heading * DEGTOR) + cc.translate(-x - w / 2., -y - h / 2.) + cc.set_source_pixbuf(pixbuf, x, y) + cc.rectangle(x, y, w, h) + cc.fill() + cc.restore() + + _draw_pixbuf(self.canvas, pixbuf, a, b, x, y, w, h, self.heading) self.inval() - if self.tw.saving_svg: - if self.tw.running_sugar: - # In Sugar, we embed the images inside the SVG - tmp_file = os.path.join(get_path(self.tw.activity, 'instance'), - 'tmpfile.png') - pixbuf.save(tmp_file, 'png', {'quality': '100'}) - self.tw.svg_string += self.svg.image( - x, y, w, h, path, - image_to_base64(tmp_file, - get_path(self.tw.activity, 'instance'))) - os.remove(tmp_file) - else: - # In GNOME, we embed a path - self.tw.svg_string += self.svg.image( - x - self.width / 2, y, w, h, path) + if self.cr_svg is not None: + _draw_pixbuf(self.cr_svg, pixbuf, a, b, x, y, w, h, self.heading) if self.tw.sharing() and share: if self.tw.running_sugar: tmp_path = get_path(self.tw.activity, 'instance') @@ -590,31 +597,34 @@ class TurtleGraphics: def draw_text(self, label, x, y, size, w, share=True): ''' Draw text ''' w *= self.tw.coord_scale - cr = pangocairo.CairoContext(self.canvas) - pl = cr.create_layout() - fd = pango.FontDescription('Sans') - fd.set_size(int(size * self.tw.coord_scale) * pango.SCALE) - pl.set_font_description(fd) - if type(label) == str or type(label) == unicode: - pl.set_text(label.replace('\0', ' ')) - elif type(label) == float or type(label) == int: - pl.set_text(str(label)) - else: - pl.set_text(str(label)) - pl.set_width(int(w) * pango.SCALE) - cr.save() - cr.translate(x, y) - cr.rotate(self.heading * DEGTOR) - self.canvas.set_source_rgb(self.fgrgb[0] / 255., - self.fgrgb[1] / 255., - self.fgrgb[2] / 255.) - cr.update_layout(pl) - cr.show_layout(pl) - cr.restore() + + def _draw_text(cr, label, x, y, size, w, scale, heading, rgb): + cc = pangocairo.CairoContext(cr) + pl = cc.create_layout() + fd = pango.FontDescription('Sans') + fd.set_size(int(size * scale) * pango.SCALE) + pl.set_font_description(fd) + if type(label) == str or type(label) == unicode: + pl.set_text(label.replace('\0', ' ')) + elif type(label) == float or type(label) == int: + pl.set_text(str(label)) + else: + pl.set_text(str(label)) + pl.set_width(int(w) * pango.SCALE) + cc.save() + cc.translate(x, y) + cc.rotate(heading * DEGTOR) + cr.set_source_rgb(rgb[0] / 255., rgb[1] / 255., rgb[2] / 255.) + cc.update_layout(pl) + cc.show_layout(pl) + cc.restore() + + _draw_text(self.canvas, label, x, y, size, w, self.tw.coord_scale, + self.heading, self.fgrgb) self.inval() - if self.tw.saving_svg: # and self.pendown: - self.tw.svg_string += self.svg.text(x, # - self.width / 2, - y + size, size, w, label) + if self.cr_svg is not None: # and self.pendown: + _draw_text(self.cr_svg, label, x, y, size, w, self.tw.coord_scale, + self.heading, self.fgrgb) if self.tw.sharing() and share: event = 'W|%s' % (data_to_string([self._get_my_nick(), [label, round_int(x), @@ -640,21 +650,19 @@ class TurtleGraphics: x1, y1 = self.turtle_to_screen_coordinates(x1, y1) x2, y2 = self.turtle_to_screen_coordinates(x2, y2) - self.canvas.move_to(x1, y1) - self.canvas.line_to(x2, y2) - self.canvas.stroke() + def _draw_line(cr, x1, y1, x2, y2): + cr.move_to(x1, y1) + cr.line_to(x2, y2) + cr.stroke() + _draw_line(self.canvas, x1, y1, x2, y2) + if self.cr_svg is not None: + _draw_line(self.cr_svg, x1, y1, x2, y2) if self.fill: if self.poly_points == []: self.poly_points.append(('move', x1, y1)) self.poly_points.append(('line', x2, y2)) - if self.tw.saving_svg and self.pendown: - self.tw.svg_string += self.svg.new_path(x1, y1) - self.tw.svg_string += self.svg.line_to(x2, y2) - self.tw.svg_string += '"\n' - self.tw.svg_string += self.svg.style() - def turn_turtle(self): ''' Change the orientation of the turtle ''' self.tw.active_turtle.set_heading(self.heading) @@ -665,7 +673,8 @@ class TurtleGraphics: if self.tw.interactive_mode: self.tw.active_turtle.move( (int(self.cx + x - self.tw.active_turtle.spr.rect.width / 2.), - int(self.cy + y - self.tw.active_turtle.spr.rect.height / 2.))) + int(self.cy + y - self.tw.active_turtle.spr.rect.height / 2.)) + ) else: self.tw.active_turtle.move((int(self.cx + x), int(self.cy + y))) @@ -713,15 +722,14 @@ class TurtleGraphics: if x < 0 or x > (w - 1) or y < 0 or y > (h - 1): return(-1, -1, -1, -1) # create a new 1x1 cairo surface - cs = cairo.ImageSurface(cairo.FORMAT_RGB24, 1, 1); + cs = cairo.ImageSurface(cairo.FORMAT_RGB24, 1, 1) cr = cairo.Context(cs) cr.set_source_surface(self.tw.turtle_canvas, -x, -y) - cr.rectangle(0,0,1,1) + cr.rectangle(0, 0, 1, 1) cr.set_operator(cairo.OPERATOR_SOURCE) cr.fill() - cs.flush() # ensure all writing is done - # Read the pixel - pixels = cs.get_data() + cs.flush() # ensure all writing is done + pixels = cs.get_data() # Read the pixel return (ord(pixels[2]), ord(pixels[1]), ord(pixels[0]), 0) else: return(-1, -1, -1, -1) @@ -754,14 +762,11 @@ class TurtleGraphics: def svg_close(self): ''' Close current SVG graphic ''' - if self.tw.svg_string == '': - return - self.svg.calc_w_h(False) - self.tw.svg_string = '%s %s %s %s' % ( - self.svg.header(True), - self.svg.background('#%02x%02x%02x' % ( - self.bgrgb[0], self.bgrgb[1], self.bgrgb[2])), - self.tw.svg_string, self.svg.footer()) + self.cr_svg.show_page() + + def svg_reset(self): + ''' Reset svg flags ''' + self.cr_svg = None def _get_my_nick(self): return self.tw.nick |