#!/usr/bin/env python # -*- coding: utf-8 -*- #Copyright (c) 2009-12 Walter Bender #Permission is hereby granted, free of charge, to any person obtaining a copy #of this software and associated documentation files (the "Software"), to deal #in the Software without restriction, including without limitation the rights #to use, copy, modify, merge, publish, distribute, sublicense, and/or sell #copies of the Software, and to permit persons to whom the Software is #furnished to do so, subject to the following conditions: #The above copyright notice and this permission notice shall be included in #all copies or substantial portions of the Software. #THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR #IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, #FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE #AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER #LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, #OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN #THE SOFTWARE. ''' The basic idea is to generate SVG for the various blocks used in Turtle Art and a few other things, like the turtle itself. There is an SVG class and then lots of properties to manipulate. There are several different classes of shapes and a comment set of attributes thfor example, there are methods to generate corners, tabs and slots for vertical docking of blocks, "innies" and "outies" for horizontal docking of blocks, "clamps" for nesting blocks. Two additional complexities are expandable regions and dock positions: there are regions within some blocks that expand so that the block can grow in one dimension without distorting, so, for example, the clamp in a repeat block can grow (or shrink) to accommodate the nesting of a larger or smaller stack of blocks to repeat; dock positions are used to keep track of the absolute position of the tabs, slots, innies and outies so that the method that does the docking knows where to position blocks. ''' import pygtk pygtk.require('2.0') import gtk import os from taconstants import HIT_RED, HIT_GREEN, HIDE_WHITE, SHOW_WHITE, \ PALETTE_COLOR, TOOLBAR_COLOR class SVG: """ Interface to the graphical representation of blocks, turtles, palettes, etc. on screen terms used here: docks -- list of connection points of a block to other blocks innies -- right hand side docks of a block, argument slots outie -- left hand side dock of a block slot -- top dock of a block that can be attached to other blocks cap -- top dock of a block that cannot be attached to other blocks tab -- bottom dock of a block if other blocks can be attached tail -- bottom dock of a block if no other blocks can be attached arm -- connection point of a branching block (if-then, loops) where inner blocks are attached else -- optional second `arm' for if-then-else blocks """ def __init__(self): self._x = 0 self._y = 0 self._min_x = 10000 self._min_y = 10000 self._max_x = -10000 self._max_y = -10000 self._width = 0 self._height = 0 self.docks = [] self._scale = 1 self._orientation = 0 self._radius = 8 self._stroke_width = 1 self._innie = [False] self._outie = False self._innie_x1 = (9 - self._stroke_width) / 2 self._innie_y1 = 3 self._innie_x2 = (9 - self._stroke_width) / 2 self._innie_y2 = (9 - self._stroke_width) / 2 self._innie_spacer = 9 self._slot = True self._cap = False self._tab = True self._bool = False self._slot_x = 10 self._slot_y = 2 self._tail = False self._porch = False self._porch_x = self._innie_x1 + self._innie_x2 + \ 4 * self._stroke_width self._porch_y = self._innie_y2 self._expand_x = 0 self._expand_x2 = 0 self._expand_y = 0 self._expand_y2 = 0 self._second_clamp = False self._arm = True self._else = False self._draw_innies = True self._hide = False self._show = False self._collapsible = False self._show_x = 0 self._show_y = 0 self._hide_x = 0 self._hide_y = 0 self._dot_radius = 8 self._fill = "#00FF00" self._stroke = "#00A000" self._gradient_color = "#FFFFFF" self._gradient = False self.margins = [0, 0, 0, 0] """ The block construction methods typically start on the left side of a block and proceed clockwise around the block, first constructing a left-side connector ("outie"), a corner (1, -1), a slot or hat on along the top, a corner (1, 1), right side connectors ("innie"), possibly a "porch" to suggest an order of arguments, another corner (-1, 1), a tab or tail, and the fourth corner (-1, -1). """ def basic_block(self): ''' The most common block type: used for 0, 1, 2, or 3 argument commands, stacks, et al. ''' self.reset_min_max() (x, y) = self._calculate_x_y() self.margins[2] = 0 self.margins[3] = 0 svg = self.new_path(x, y) svg += self._corner(1, -1) svg += self._do_slot() svg += self._rline_to(self._expand_x, 0) xx = self._x svg += self._corner(1, 1) for i in range(len(self._innie)): if self._innie[i] is True: svg += self._do_innie() if i == 0: svg += self._rline_to(0, self._expand_y) if i == 0 and self._porch is True: svg += self._do_porch(False) elif len(self._innie) - 1 > i: svg += self._rline_to(0, 2 * self._innie_y2 + self._innie_spacer) # moved expand_y to just after first innie above # svg += self._rline_to(0, self._expand_y) svg += self._corner(-1, 1) svg += self.line_to(xx, self._y) svg += self._rline_to(-self._expand_x, 0) if self._tab: svg += self._do_tab() else: svg += self._do_tail() svg += self._corner(-1, -1) svg += self._rline_to(0, -self._expand_y) if True in self._innie: svg += self.line_to(x, self._radius + self._innie_y2 + self._stroke_width / 2.0) svg += self._do_outie() self.calc_w_h() svg += self._close_path() svg += self.style() if self._show is True: svg += self._show_dot() if self._hide is True: svg += self._hide_dot() svg += self.footer() return self.header() + svg def invisible(self): ''' A block that is invisible but still has connectors: used when collapsing stacks. ''' self.reset_min_max() (x, y) = self._calculate_x_y() self.margins[2] = 0 self.margins[3] = 0 # calculate shape but don't include it in the svg output self.new_path(x, y) self._corner(1, -1) self._do_slot() self._corner(1, 1) self._corner(-1, 1) self._do_tab() self._corner(-1, -1) self.calc_w_h() self._close_path() self.style() return self.header() + self.footer() def basic_flow(self): ''' A flow block includes an arm that holds a branch in the flow ''' self.reset_min_max() (x, y) = self._calculate_x_y() self.margins[2] = 0 self.margins[3] = 0 svg = self.new_path(x, y) svg += self._corner(1, -1) svg += self._do_slot() xx = self._x svg += self._rline_to(self._expand_x, 0) if self._bool: svg += self._corner(1, 1, 90, 0, 1, True, False) elif True in self._innie: svg += self._corner(1, 1) for i in range(len(self._innie)): if self._innie[i] is True: svg += self._do_innie() svg += self._rline_to(0, self._innie_spacer) else: self.margins[2] = \ int((self._x - self._stroke_width + 0.5) * self._scale) if self._bool is True: svg += self._rline_to(0, self._radius / 2.0) svg += self._do_boolean() svg += self._rline_to(0, self._stroke_width) if self._else: svg += self._rline_to(self._radius * 3 + self._slot_x * 2, 0) else: svg += self._rline_to(self._radius + self._slot_x, 0) save_y = self._y svg += self._corner(1, 1) svg += self._rline_to(-self._radius, 0) if self._else: svg += self._do_tab() svg += self._rline_to(-self._radius * 2, 0) svg += self._do_tab() svg += self._inverse_corner(-1, 1, 90, 0, 0, True, False) svg += self._rline_to(0, self._expand_y) svg += self._corner(-1, 1, 90, 0, 1, False, True) svg += self.line_to(xx, self._y) if self._tab: svg += self._do_tab() else: svg += self._do_tail() svg += self._corner(-1, -1) svg += self._rline_to(0, -self._expand_y) if True in self._innie: svg += self.line_to(x, self._radius + self._innie_y2 + self._stroke_width) svg += self._close_path() self.calc_w_h() svg += self.style() if self._hide is True: svg += self._hide_dot() if self._show is True: svg += self._show_dot() svg += self.footer() if self._bool is True: # move secondary labels to arm self.margins[2] = self._radius * 1.5 * self._scale self.margins[3] = (self._max_y - save_y - self._radius + self._stroke_width) * self._scale return self.header() + svg def portfolio(self): ''' Deprecated block ''' self.reset_min_max() (x, y) = self._calculate_x_y() self.margins[0] = int(x + 2 * self._stroke_width + 0.5) self.margins[1] = int(y + self._stroke_width + 0.5 + self._slot_y) self.margins[2] = 0 self.margins[3] = 0 x += self._innie_x1 + self._innie_x2 svg = self.new_path(x, y) svg += self._corner(1, -1) svg += self._do_slot() xx = self._x svg += self._rline_to(self._expand_x, 0) svg += self._corner(1, 1) svg += self._rline_to(0, self._expand_y) for i in range(len(self._innie)): if self._innie[i] is True and i > 0 and self._draw_innies: svg += self._do_innie() svg += self._rline_to(0, 2 * self._innie_y2 + self._innie_spacer) else: svg += self._rline_to(0, 2 * self._innie_y2 + self._innie_spacer) svg += self._corner(-1, 1) svg += self.line_to(xx, self._y) svg += self._do_tab() svg += self._corner(-1, -1) for i in range(len(self._innie)): if self._innie[len(self._innie) - i - 1] is True: svg += self._rline_to(0, -2 * self._innie_y2 - self._innie_spacer) svg += self._do_reverse_innie() else: svg += self._rline_to(0, -2 * self._innie_y2 - self._innie_spacer) svg += self._close_path() self.calc_w_h() svg += self.style() svg += self.footer() return self.header() + svg def basic_box(self): ''' Basic argument style used for numbers, text, media ''' self.reset_min_max() self.set_outie(True) x = self._stroke_width / 2.0 + self._innie_x1 + self._innie_x2 self.margins[0] = int((x + self._stroke_width + 0.5) * self._scale) self.margins[1] = int((self._stroke_width + 0.5) * self._scale) self.margins[2] = 0 self.margins[3] = 0 svg = self.new_path(x, self._stroke_width / 2.0) svg += self._rline_to(self._expand_x, 0) svg += self._rline_to(0, 2 * self._radius + self._innie_y2 + self._expand_y) svg += self._rline_to(-self._expand_x, 0) svg += self.line_to(x, self._radius + self._innie_y2 + self._stroke_width / 2.0) svg += self._do_outie() svg += self._close_path() self.calc_w_h() svg += self.style() svg += self.footer() return self.header() + svg def boolean_and_or(self): ''' Booleans are in a class of their own ''' self.reset_min_max() svg = self._start_boolean(self._stroke_width / 2.0, self._radius * 5.5 + self._stroke_width / 2.0 + self._innie_y2 + self._innie_spacer + self._expand_y) svg += self._rline_to(0, -self._radius * 3.5 - self._innie_y2 - self._innie_spacer - self._stroke_width) self._hide_x = self._x + self._radius + self._stroke_width self._hide_y = self._y self._show_x = self._x + self._radius + self._stroke_width svg += self._rarc_to(1, -1) svg += self._rline_to(self._radius / 2.0 + self._expand_x, 0) xx = self._x svg += self._rline_to(0, self._radius / 2.0) svg += self._do_boolean() svg += self._rline_to(0, self._radius * 1.5 + self._innie_y2 + self._innie_spacer) svg += self._rline_to(0, self._expand_y) svg += self._do_boolean() svg += self._rline_to(0, self._radius / 2.0) self._show_y = self._y self._show_y -= (self._innie_y1 + self._innie_y2 + self._stroke_width) svg += self.line_to(xx, self._y) svg += self._rline_to(-self._expand_x, 0) svg += self._end_boolean() self.margins[0] = int((self._radius + self._stroke_width + 0.5) * self._scale) self.margins[1] = int(self._stroke_width * self._scale) self.margins[2] = int(self._stroke_width * self._scale) self.margins[3] = int(self._stroke_width * self._scale) return self.header() + svg def boolean_not(self, notnot): ''' Booleans are in a class of their own: not and not not ''' self.reset_min_max() if self._innie[0]: svg = self._start_boolean( self._stroke_width / 2.0, self._radius * 1.25 + self._stroke_width / 2.0) elif not notnot: svg = self._start_boolean( self._stroke_width / 2.0, self._radius * 2.0 + self._stroke_width / 2.0) else: svg = self._start_boolean( self._stroke_width / 2.0, self._radius + self._stroke_width / 2.0) svg += self._rline_to(0, -self._stroke_width) if self._innie[0]: svg += self._rline_to(0, -self._radius / 4.0) elif not notnot: svg += self._rarc_to(1, -1) svg += self._rline_to(self._radius / 2.0 + self._expand_x, 0) xx = self._x if self._innie[0]: svg += self._rline_to(0, self._radius) svg += self._do_innie() svg += self._rline_to(0, self._radius) elif not notnot: svg += self._rline_to(0, self._radius / 2.0) svg += self._do_boolean() svg += self._rline_to(0, self._radius / 2.0) else: svg += self._rline_to(0, self._radius * 2) svg += self.line_to(xx, self._y) if self._innie[0]: svg += self._rline_to(-self._radius / 2.0 - self._expand_x, 0) svg += self._rline_to(0, -self._radius / 4.0) elif not notnot: svg += self._rline_to(-self._expand_x, 0) else: svg += self._rline_to(-self._radius / 2.0 - self._expand_x, 0) svg += self._end_boolean(notnot) if notnot: self.margins[0] = int((self._radius + self._stroke_width + 0.5) * self._scale) self.margins[2] = int((self._radius + self._stroke_width + 0.5) * self._scale) else: self.margins[0] = int((self._stroke_width + 0.5) * self._scale) self.margins[2] = int((self._stroke_width + 0.5) * self._scale) self.margins[1] = int(self._stroke_width * self._scale) self.margins[3] = int(self._stroke_width * self._scale) return self.header() + svg def boolean_compare(self): ''' Booleans are in a class of their own ''' self.reset_min_max() yoffset = self._radius * 2 + 2 * self._innie_y2 + \ self._innie_spacer + self._stroke_width / 2.0 + \ self._expand_y svg = self._start_boolean(self._stroke_width / 2.0, yoffset) yoffset = -2 * self._innie_y2 - self._innie_spacer - self._stroke_width svg += self._rline_to(0, yoffset) self._hide_x = self._x + self._radius + self._stroke_width self._hide_y = self._y self._show_x = self._x + self._radius + self._stroke_width svg += self._rarc_to(1, -1) svg += self._rline_to(self._radius / 2.0 + self._expand_x, 0) svg += self._rline_to(0, self._radius) xx = self._x svg += self._do_innie() svg += self._rline_to(0, self._expand_y) if self._porch is True: svg += self._do_porch(False) else: svg += self._rline_to(0, 2 * self._innie_y2 + self._innie_spacer) svg += self._do_innie() svg += self._rline_to(0, self._radius) svg += self.line_to(xx, self._y) svg += self._rline_to(-self._expand_x, 0) self._show_y = self._y self._show_y -= \ (self._innie_y1 + self._innie_y2 + self._stroke_width * 2) svg += self._end_boolean() self.margins[0] = int((self._radius + self._stroke_width) * self._scale) self.margins[1] = int(self._stroke_width * self._scale) self.margins[2] = int(self._stroke_width * self._scale) return self.header() + svg def triangle_up(self, colors): ''' A triangle that points up ''' self.reset_min_max() self._fill, self._stroke = colors[0], colors[1] self._width, self._height = 55 * self._scale, 55 * self._scale svg = self.new_path(5, 50) svg += self._rline_to(22.5, -45) svg += self._rline_to(22.5, 45) svg += self._close_path() svg += self.style() svg += self.footer() return self.header() + svg def triangle_down(self, colors): ''' A triangle that points down ''' self.reset_min_max() self._fill, self._stroke = colors[0], colors[1] self._width, self._height = 55 * self._scale, 55 * self._scale svg = self.new_path(5, 5) svg += self._rline_to(22.5, 45) svg += self._rline_to(22.5, -45) svg += self._close_path() svg += self.style() svg += self.footer() return self.header() + svg def turtle(self, colors): ''' Turtles are just another block ''' self.reset_min_max() self._fill, self._stroke = colors[1], colors[0] # Tail svg = ' \n' % (self._fill, self._stroke) # Feet x 4 svg += ' \n' % (self._fill, self._stroke) svg += ' \n' % (self._fill, self._stroke) svg += ' \n' % (self._fill, self._stroke) svg += ' \n' % (self._fill, self._stroke) # Head svg += '' % \ (self._fill, self._stroke) # Shell svg += ' \n' % (self._fill, self._stroke) svg += ' \n' % (self._stroke) svg += ' \n' % (self._stroke) svg += ' \n' % (self._stroke) svg += ' \n' % (self._stroke) svg += ' \n' % (self._stroke) svg += ' \n' % (self._stroke) self._width, self._height = 55, 55 svg += self.footer() return self.header() + svg def palette(self, width, height): ''' Just a rectangle with a hide button. ''' self.reset_min_max() self._width, self._height = width, height self._fill, self._stroke = PALETTE_COLOR, "none" svg = self._rect(width, height, 0, 0) self._hide_x = (width - self._radius) / 2 self._hide_y = (height - self._radius) / 2 svg += self._hide_dot(noscale=True) svg += self.footer() return self.header() + svg def toolbar(self, width, height): ''' Just a rectangle ''' self.reset_min_max() self._width, self._height = width, height self._fill, self._stroke = TOOLBAR_COLOR, "none" svg = self._rect(width, height, 0, 0) svg += self.footer() return self.header() + svg def clamp(self): ''' Special block for collapsible stacks; includes an 'arm" that extends down the left side of a stack and a bottom jaw to clamp the blocks. ''' self.reset_min_max() x = self._stroke_width / 2.0 y = self._stroke_width / 2.0 + self._radius self.margins[0] = int((x + self._stroke_width + 0.5) * self._scale) self.margins[1] = int((self._stroke_width + 0.5) * self._scale) self.margins[2] = 0 self.margins[3] = 0 svg = self.new_path(x, y) svg += self._corner(1, -1) svg += self._do_slot() svg += self._rline_to(self._radius + self._stroke_width, 0) svg += self._rline_to(self._expand_x, 0) xx = self._x svg += self._corner(1, 1) if self._innie[0] is True: svg += self._do_innie() else: self.margins[2] = \ int((self._x - self._stroke_width + 0.5) * self._scale) if self._bool is True: svg += self._do_boolean() svg += self._corner(-1, 1) svg += self.line_to(xx, self._y) svg += self._rline_to(-self._expand_x, 0) svg += self._do_tab() svg += self._inverse_corner(-1, 1, 90, 0, 0) svg += self._rline_to(0, self._expand_y) svg += self._inverse_corner(1, 1, 90, 0, 0) svg += self._do_slot() svg += self._rline_to(self._radius, 0) if self._second_clamp: svg += self._corner(-1, 1) svg += self.line_to(xx, self._y) svg += self._rline_to(-self._expand_x, 0) svg += self._do_tab() svg += self._inverse_corner(-1, 1, 90, 0, 0) svg += self._rline_to(0, self._expand_y2) svg += self._inverse_corner(1, 1, 90, 0, 0) svg += self._do_slot() svg += self._rline_to(self._radius, 0) svg += self._corner(-1, 1) svg += self._rline_to(-self._radius - self._stroke_width, 0) svg += self._do_tab() svg += self._corner(-1, -1) svg += self._close_path() self.calc_w_h() svg += self.style() if self._collapsible: svg += self._hide_dot() svg += self.footer() return self.header() + svg def clamp_until(self): ''' Until block is like clamp but docks are flipped ''' self.reset_min_max() x = self._stroke_width / 2.0 y = self._stroke_width / 2.0 + self._radius self.margins[0] = int((x + self._stroke_width + 0.5) * self._scale) self.margins[1] = int((self._stroke_width + 0.5) * self._scale) self.margins[2] = 0 self.margins[3] = 0 svg = self.new_path(x, y) svg += self._corner(1, -1) svg += self._do_slot() svg += self._rline_to(self._radius + self._stroke_width, 0) svg += self._rline_to(self._expand_x, 0) xx = self._x svg += self._corner(1, 1, skip=True) svg += self._corner(-1, 1, skip=True) svg += self.line_to(xx, self._y) svg += self._rline_to(-self._expand_x, 0) svg += self._do_tab() svg += self._inverse_corner(-1, 1, 90, 0, 0) svg += self._rline_to(0, self._expand_y) svg += self._inverse_corner(1, 1, 90, 0, 0) svg += self._do_slot() svg += self._rline_to(self._radius, 0) if self._innie[0] is True: svg += self._do_innie() else: self.margins[2] = \ int((self._x - self._stroke_width + 0.5) * self._scale) svg += self._rline_to(0, self._radius + self._expand_y2) if self._bool is True: svg += self._do_boolean() svg += self._corner(-1, 1) svg += self._rline_to(-self._radius - self._stroke_width, 0) svg += self._do_tab() svg += self._corner(-1, -1) svg += self._close_path() self.calc_w_h() svg += self.style() if self._collapsible: svg += self._hide_dot() svg += self.footer() return self.header() + svg def status_block(self, graphic=None): ''' Generate a status block ''' self.reset_min_max() (x, y) = self._calculate_x_y() self.margins[2] = 0 self.margins[3] = 0 svg = self.new_path(x, y) svg += self._corner(1, -1) svg += self._rline_to(self._expand_x, 0) xx = self._x svg += self._corner(1, 1) svg += self._rline_to(0, self._expand_y) svg += self._corner(-1, 1) svg += self.line_to(xx, self._y) svg += self._rline_to(-self._expand_x, 0) svg += self._corner(-1, -1) svg += self._rline_to(0, -self._expand_y) self.calc_w_h() svg += self._close_path() svg += self.style() if self._hide is True: svg += self._hide_dot() svg += self.footer() return self.header() + svg # # Utility methods # def set_tail(self, flag=True): self._tail = flag def set_draw_innies(self, flag=True): self._draw_innies = flag def set_hide(self, flag=False): self._hide = flag def set_show(self, flag=False): self._show = flag def set_collapsible(self, flag=False): self._collapsible = flag def get_width(self): return self._width def get_height(self): return self._height def get_innie_width(self): return (self._innie_x1 + self._innie_x2) * self._scale def get_slot_depth(self): return self._slot_y * self._scale def clear_docks(self): self.docks = [] def set_scale(self, scale=1): self._scale = scale def set_orientation(self, orientation=0): self._orientation = orientation def second_clamp(self, flag=False): self._second_clamp = flag def expand(self, w=0, h=0, w2=0, h2=0): self._expand_x = w self._expand_y = h self._expand_x2 = w2 self._expand_y2 = h2 def set_stroke_width(self, stroke_width=1.5): self._stroke_width = stroke_width self._calc_porch_params() def set_colors(self, colors=["#00FF00", "#00A000"]): self._fill = colors[0] self._stroke = colors[1] def set_fill_color(self, color="#00FF00"): self._fill = color def set_stroke_color(self, color="#00A000"): self._stroke = color def set_gradient(self, flag=False, color='#FFFFFF'): self._gradient = flag self._gradient_color = color def set_innie(self, innie_array=[False]): self._innie = innie_array def set_outie(self, flag=False): self._outie = flag def set_slot(self, flag=True): self._slot = flag if self._slot is True: self._cap = False def set_cap(self, flag=False): self._cap = flag if self._cap is True: self._slot = False def set_tab(self, flag=True): self._tab = flag def set_porch(self, flag=False): self._porch = flag def set_boolean(self, flag=False): self._bool = flag def set_else(self, flag=False): self._else = flag def set_arm(self, flag=True): self._arm = flag def reset_min_max(self): self._min_x = 10000 self._min_y = 10000 self._max_x = -10000 self._max_y = -10000 # # Exotic methods # def set_radius(self, radius=8): self._radius = radius def set_innie_params(self, x1=4, y1=3, x2=4, y2=4): self._innie_x1 = x1 self._innie_y1 = y1 self._innie_x2 = x2 self._innie_y2 = y2 self._calc_porch_params() def set_innie_spacer(self, innie_spacer=0): self._innie_spacer = innie_spacer def set_slot_params(self, x=12, y=4): self._slot_x = x self._slot_y = y def _calc_porch_params(self): self._porch_x = self._innie_x1 + self._innie_x2 + \ 4 * self._stroke_width self._porch_y = self._innie_y1 + self._innie_y2 + \ 4 * self._stroke_width # # SVG helper methods # def header(self, center=False): return '\n' % (self._width, self._height) + \ self._defs() + self._transform(center) def _defs(self): if self._gradient is True: return ' \n\ \n\ \n\ \n\ \n\ \n\ \n' % (self._gradient_color, self._fill, self._height / 2.0, self._width / self._scale, self._height / 2.0) else: return "" def _transform(self, center): if self._orientation != 0: orientation = "\n" % \ (self._orientation, self._width / 2.0, self._height / 2.0) else: orientation = "" if center: return "\n" % \ (-self._min_x, -self._min_y) else: return "\n%s" % \ (self._scale, self._scale, orientation) def footer(self): if self._orientation != 0: return " \n\n\n" else: return " \n\n" def style(self): if self._gradient is True: fill = "url(#linearGradient5678)" else: fill = self._fill return "%s%s;%s%s;%s%.1f;%s%s" % ( " style=\"fill:", fill, "fill-opacity:1;stroke:", self._stroke, "stroke-width:", self._stroke_width, "stroke-linecap:round;", "stroke-opacity:1;\" />\n") def text(self, x, y, size, width, string): self._x = x self._y = y self._check_min_max() self._x = x + width self._y = y - size self._check_min_max() return " %s%.1f%s%s%s%.1f%s%.1f%s%.1f%s%s%s%s%s" % ( "\n ", string, "\n \n") def image(self, x, y, w, h, path, image_data=None): self._x = x self._y = y self._check_min_max() self._x = x + w self._y = y + h self._check_min_max() if image_data is None: return " %s%.1f%s%.1f%s%.1f%s%.1f%s%s%s" % ( "\n") else: return " %s%.1f%s%.1f%s%.1f%s%.1f%s%s%s" % ( "\n") def _circle(self, r, cx, cy): return "%s%s%s%s%s%f%s%f%s%f%s" % \ ("\n") def _rect(self, w, h, x, y): return "%s%s%s%s%s%f%s%f%s%f%s%f%s" % ("\n") def background(self, fill): return "%s%s%s%s%s%f%s%f%s%f%s%f%s" % ("\n") def _check_min_max(self): if self._x < self._min_x: self._min_x = self._x if self._y < self._min_y: self._min_y = self._y if self._x > self._max_x: self._max_x = self._x if self._y > self._max_y: self._max_y = self._y def line_to(self, x, y): self._check_min_max() if self._x == x and self._y == y: return "" else: self._x = x self._y = y self._check_min_max() return "L %.1f %.1f " % (x, y) def _rline_to(self, dx, dy): if dx == 0 and dy == 0: return "" else: return self.line_to(self._x + dx, self._y + dy) def arc_to(self, x, y, r, a=90, l=0, s=1): self._check_min_max() if r == 0: return self.line_to(x, y) else: self._x = x self._y = y self._check_min_max() return "A %.1f %.1f %.1f %d %d %.1f %.1f " % ( r, r, a, l, s, x, y) def _rarc_to(self, sign_x, sign_y, a=90, l=0, s=1): if self._radius == 0: return "" else: x = self._x + sign_x * self._radius y = self._y + sign_y * self._radius return self.arc_to(x, y, self._radius, a, l, s) def _inverse_corner(self, sign_x, sign_y, a=90, l=0, s=1, start=True, end=True): r2 = self._stroke_width + self._radius / 2.0 if start: if sign_x * sign_y == -1: svg_str = self._rline_to(sign_x * (r2 - self._stroke_width), 0) else: svg_str = self._rline_to(0, sign_y * (r2 - self._stroke_width)) x = self._x + sign_x * r2 y = self._y + sign_y * r2 svg_str += self.arc_to(x, y, r2, a, l, s) if end: if sign_x * sign_y == -1: svg_str += self._rline_to(0, sign_y * (r2 - self._stroke_width)) else: svg_str += self._rline_to(sign_x * (r2 - self._stroke_width), 0) return svg_str def _corner(self, sign_x, sign_y, a=90, l=0, s=1, start=True, end=True, skip=False): svg_str = "" if sign_x == 1 and sign_y == -1: # Upper-left corner self._hide_x = self._x + self._radius + self._stroke_width self._show_x = self._x + self._radius + self._stroke_width self._hide_y = self._y + self._stroke_width elif sign_x == 1 and sign_y == 1: # Upper-right corner if len(self._innie) == 1 and self._innie[0]: self._show_x = self._x - self._radius self._show_y = self._hide_y elif sign_x == -1 and sign_y == 1: # Lower-right corner if not (len(self._innie) == 1 and self._innie[0]): self._show_y = \ self._y - self._stroke_width if self._radius > 0: r2 = self._radius / 2.0 if start: if sign_x * sign_y == 1: svg_str += self._rline_to(sign_x * r2, 0) elif not skip: svg_str += self._rline_to(0, sign_y * r2) x = self._x + sign_x * r2 y = self._y + sign_y * r2 svg_str += self.arc_to(x, y, r2, a, l, s) if end: if sign_x * sign_y == 1: svg_str += self._rline_to(0, sign_y * r2) elif not skip: svg_str += self._rline_to(sign_x * r2, 0) return svg_str def new_path(self, x, y): """ self._min_x = x self._min_y = y self._max_x = x self._max_y = y """ self._x = x self._y = y return "