#!/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"
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 "