conn, addr = sock.accept()<EOL>f = conn.makefile(conn)<EOL>self.shell = ShoebotCmd(self.bot, stdin=f, stdout=f, intro=INTRO)<EOL>print(_("<STR_LIT>"))<EOL>GObject.io_add_watch(conn, GObject.IO_IN, self.handler)<EOL>if self.shell.intro:<EOL><INDENT>self.shell.stdout.write(str(self.shell.intro)+"<STR_LIT:\n>")<EOL>self.shell.stdout.flush()<EOL><DEDENT>return True<EOL>

Asynchronous connection listener. Starts a handler for each connection.


<EOL>self.shell.stdout.write(self.shell.prompt)<EOL>line = self.shell.stdin.readline()<EOL>if not len(line):<EOL><INDENT>line = '<STR_LIT>'<EOL>return False<EOL><DEDENT>else:<EOL><INDENT>line = line.rstrip('<STR_LIT:\r\n>')<EOL>line = self.shell.precmd(line)<EOL>stop = self.shell.onecmd(line)<EOL>stop = self.shell.postcmd(stop, line)<EOL>self.shell.stdout.flush()<EOL>self.shell.postloop()<EOL>if stop:<EOL><INDENT>self.shell = None<EOL>conn.close()<EOL><DEDENT>return not stop<EOL><DEDENT>

Asynchronous connection handler. Processes each line from the socket.


def run_cmd(self, line):<EOL><INDENT>if self.trusted:<EOL><INDENT>f(self, line)<EOL><DEDENT>else:<EOL><INDENT>print("<STR_LIT>" % f.__name__[<NUM_LIT:3>:])<EOL><DEDENT><DEDENT>global trusted_cmds<EOL>trusted_cmds.add(f.__name__)<EOL>run_cmd.__doc__ = f.__doc__<EOL>return run_cmd<EOL>

Trusted commands cannot be run remotely

:param f:
:return:


def __init__(self, bot, intro=None, trusted=False, **kwargs):

cmd.Cmd.__init__(self, **kwargs)<EOL>self.bot = bot<EOL>self.pause_speed = None<EOL>self.intro = intro or INTRO<EOL>self.prompt = PROMPT<EOL>self.response_prompt = '<STR_LIT>'<EOL>self.use_rawinput = False<EOL>self.cookie = None<EOL>self.escape_nl = False<EOL>self.live_prefix = '<STR_LIT>'<EOL>self.trusted = trusted<EOL>

:param bot:
:param intro:
:param trusted: Only running from the commandline is trusted, not from sockets
                untrusted can only change variables
:param kwargs:
:return:


def print_response(self, input='<STR_LIT>', keep=False, *args, **kwargs):

cookie = kwargs.get('<STR_LIT>')<EOL>if cookie is None:<EOL><INDENT>cookie = self.cookie or '<STR_LIT>'<EOL><DEDENT>status = kwargs.get('<STR_LIT:status>')<EOL>lines = input.splitlines()<EOL>if status and not lines:<EOL><INDENT>lines = ['<STR_LIT>']<EOL><DEDENT>if cookie:<EOL><INDENT>output_template = '<STR_LIT>'<EOL><DEDENT>else:<EOL><INDENT>output_template = '<STR_LIT>'<EOL><DEDENT>for i, line in enumerate(lines):<EOL><INDENT>if i != len(lines) - <NUM_LIT:1> or keep is True:<EOL><INDENT>cookie_char = '<STR_LIT:>>'<EOL><DEDENT>else:<EOL><INDENT>cookie_char = '<STR_LIT::>'<EOL><DEDENT>print(output_template.format(<EOL>cookie_char=cookie_char,<EOL>cookie=cookie,<EOL>status=status or '<STR_LIT>',<EOL>line=line.strip()), file=self.stdout)<EOL><DEDENT>

print response, if cookie is set then print that each line
:param args:
:param keep: if True more output is to come
:param cookie: set a custom cookie,
               if set to 'None' then self.cookie will be used.
               if set to 'False' disables cookie output entirely
:return:


return "<STR_LIT>"<EOL>

Kill the default behaviour of repeating the last line.

:return:


if arg.lower() == '<STR_LIT>':<EOL><INDENT>self.escape_nl = False<EOL><DEDENT>else:<EOL><INDENT>self.escape_nl = True<EOL><DEDENT>


if arg.lower() == '<STR_LIT>':<EOL><INDENT>self.response_prompt = '<STR_LIT>'<EOL>self.prompt = '<STR_LIT>'<EOL>return<EOL><DEDENT>elif arg.lower() == '<STR_LIT>':<EOL><INDENT>self.prompt = PROMPT<EOL>self.response_prompt = RESPONSE_PROMPT<EOL><DEDENT>self.print_response('<STR_LIT>' % self.prompt, '<STR_LIT:\n>', '<STR_LIT>' % self.response_prompt)<EOL>

Enable or disable prompt
:param arg: on|off
:return:


publish_event(SET_WINDOW_TITLE, data=title)<EOL>


if speed:<EOL><INDENT>try:<EOL><INDENT>self.bot._speed = float(speed)<EOL><DEDENT>except Exception as e:<EOL><INDENT>self.print_response('<STR_LIT>' % speed)<EOL>return<EOL><DEDENT><DEDENT>self.print_response('<STR_LIT>' % self.bot._speed)<EOL>


self.bot._frame = <NUM_LIT:0><EOL>self.bot._namespace.clear()<EOL>self.bot._namespace.update(self.bot._initial_namespace)<EOL>


<EOL>if self.pause_speed is None:<EOL><INDENT>self.pause_speed = self.bot._speed<EOL>self.bot._speed = <NUM_LIT:0><EOL>self.print_response('<STR_LIT>')<EOL><DEDENT>else:<EOL><INDENT>self.bot._speed = self.pause_speed<EOL>self.pause_speed = None<EOL>self.print_response('<STR_LIT>')<EOL><DEDENT>


if self.pause_speed is None:<EOL><INDENT>self.bot._speed = self.pause_speed<EOL>self.pause_speed = None<EOL><DEDENT>self.print_response("<STR_LIT>")<EOL>


self.print_response("<STR_LIT>" % line)<EOL>self.bot._frame = int(line)<EOL>

Go to specific frame
:param line:
:return:


self.print_response("<STR_LIT>" % self.bot._frame)<EOL>self.bot._frame = <NUM_LIT:0><EOL>


if self.bot._vars:<EOL><INDENT>max_name_len = max([len(name) for name in self.bot._vars])<EOL>for i, (name, v) in enumerate(self.bot._vars.items()):<EOL><INDENT>keep = i < len(self.bot._vars) - <NUM_LIT:1><EOL>self.print_response("<STR_LIT>" % (name.ljust(max_name_len), v.value), keep=keep)<EOL><DEDENT><DEDENT>else:<EOL><INDENT>self.print_response("<STR_LIT>")<EOL><DEDENT>


cookie = self.cookie<EOL>executor = self.bot._executor<EOL>def source_good():<EOL><INDENT>self.print_response(status=RESPONSE_CODE_OK, cookie=cookie)<EOL>executor.clear_callbacks()<EOL><DEDENT>def source_bad(tb):<EOL><INDENT>if called_good:<EOL><INDENT>raise ValueError('<STR_LIT>')<EOL><DEDENT>self.print_response(status=RESPONSE_REVERTED, keep=True, cookie=cookie)<EOL>self.print_response(tb.replace('<STR_LIT:\n>', '<STR_LIT>'), cookie=cookie)<EOL>executor.clear_callbacks()<EOL><DEDENT>called_good = False<EOL>source = str(base64.b64decode(line))<EOL>publish_event(SOURCE_CHANGED_EVENT, data=source, extra_channels="<STR_LIT>")<EOL>self.bot._executor.load_edited_source(source, good_cb=source_good, bad_cb=source_bad)<EOL>

load filename=(file)
load base64=(base64 encoded)

Send new code to shoebot.

If it does not run successfully shoebot will attempt to role back.

Editors can enable livecoding by sending new code as it is edited.


return self.do_exit(line)<EOL>


if self.trusted:<EOL><INDENT>publish_event(QUIT_EVENT)<EOL><DEDENT>self.print_response('<STR_LIT>')<EOL>return True<EOL>


self.bot.canvas.sink.trigger_fullscreen_action(True)<EOL>print(self.response_prompt, file=self.stdout)<EOL>


self.bot.canvas.sink.trigger_fullscreen_action(False)<EOL>print(self.response_prompt, file=self.stdout)<EOL>


print(self.response_prompt, file=self.stdout)<EOL>return self.do_exit(line)<EOL>


print(self.response_prompt, file=self.stdout)<EOL>return cmd.Cmd.do_help(self, arg)<EOL>


try:<EOL><INDENT>name, value = [part.strip() for part in line.split('<STR_LIT:=>')]<EOL>if name not in self.bot._vars:<EOL><INDENT>self.print_response('<STR_LIT>' % name)<EOL>return<EOL><DEDENT>variable = self.bot._vars[name]<EOL>variable.value = variable.sanitize(value.strip('<STR_LIT:;>'))<EOL>success, msg = self.bot.canvas.sink.var_changed(name, variable.value)<EOL>if success:<EOL><INDENT>print('<STR_LIT>'.format(name, variable.value), file=self.stdout)<EOL><DEDENT>else:<EOL><INDENT>print('<STR_LIT>'.format(msg), file=self.stdout)<EOL><DEDENT><DEDENT>except Exception as e:<EOL><INDENT>print('<STR_LIT>', e)<EOL>return<EOL><DEDENT>


args = shlex.split(line or "<STR_LIT>")<EOL>if args and '<STR_LIT>' in args[-<NUM_LIT:1>]:<EOL><INDENT>cookie_index = line.index('<STR_LIT>')<EOL>cookie = line[cookie_index + <NUM_LIT:7>:]<EOL>line = line[:cookie_index].strip()<EOL>self.cookie = cookie<EOL><DEDENT>if line.startswith('<STR_LIT:#>'):<EOL><INDENT>return '<STR_LIT>'<EOL><DEDENT>elif '<STR_LIT:=>' in line:<EOL><INDENT>cmdname = line.partition("<STR_LIT:U+0020>")[<NUM_LIT:0>]<EOL>if hasattr(self, "<STR_LIT>" % cmdname):<EOL><INDENT>return line<EOL><DEDENT>if not line.startswith("<STR_LIT>"):<EOL><INDENT>return "<STR_LIT>" + line<EOL><DEDENT>else:<EOL><INDENT>return line<EOL><DEDENT><DEDENT>if len(args) and args[<NUM_LIT:0>] in self.shortcuts:<EOL><INDENT>return "<STR_LIT>" % (self.shortcuts[args[<NUM_LIT:0>]], "<STR_LIT:U+0020>".join(args[<NUM_LIT:1>:]))<EOL><DEDENT>else:<EOL><INDENT>return line<EOL><DEDENT>

Allow commands to have a last parameter of 'cookie=somevalue'

TODO somevalue will be prepended onto any output lines so
that editors can distinguish output from certain kinds
of events they have sent.

:param line:
:return:


self.cookie = None<EOL>return stop<EOL>

Hook method executed just after a command dispatch is finished.


def rect(self, x, y, width, height, roundness=<NUM_LIT:0.0>, draw=True, **kwargs):

path = self.BezierPath(**kwargs)<EOL>path.rect(x, y, width, height, roundness, self.rectmode)<EOL>if draw:<EOL><INDENT>path.draw()<EOL><DEDENT>return path<EOL>

Draws a rectangle with top left corner at (x,y)

        The roundness variable sets rounded corners.


def oval(self, x, y, width, height, draw=True, **kwargs):

path = self.BezierPath(**kwargs)<EOL>path.ellipse(x, y, width, height)<EOL>if draw:<EOL><INDENT>path.draw()<EOL><DEDENT>return path<EOL>

Draws an ellipse starting from (x,y) -  ovals and ellipses are not the same


def ellipse(self, x, y, width, height, draw=True, **kwargs):

path = self.BezierPath(**kwargs)<EOL>path.ellipse(x,y,width,height)<EOL>if draw:<EOL><INDENT>path.draw()<EOL><DEDENT>return path<EOL>


def line(self, x1, y1, x2, y2, draw=True):

p = self._path<EOL>self.newpath()<EOL>self.moveto(x1,y1)<EOL>self.lineto(x2,y2)<EOL>self.endpath(draw=draw)<EOL>self._path = p<EOL>return p<EOL>


if self._path is None:<EOL><INDENT>raise ShoebotError(_("<STR_LIT>"))<EOL><DEDENT>self._path.relmoveto(x,y)<EOL>


if self._path is None:<EOL><INDENT>raise ShoebotError(_("<STR_LIT>"))<EOL><DEDENT>self._path.rellineto(x,y)<EOL>


def relcurveto(self, h1x, h1y, h2x, h2y, x, y):

if self._path is None:<EOL><INDENT>raise ShoebotError(_("<STR_LIT>"))<EOL><DEDENT>self._path.relcurveto(x,y)<EOL>

Draws a curve relatively to the last point.


def image(self, path, x, y, width=None, height=None, alpha=<NUM_LIT:1.0>, data=None, draw=True, **kwargs):

return self.Image(path, x, y, width, height, alpha, data, **kwargs)<EOL>

Draws a image form path, in x,y and resize it to width, height dimensions.


def colormode(self, mode=None, crange=None):

if mode is not None:<EOL><INDENT>if mode == "<STR_LIT>":<EOL><INDENT>self.color_mode = Bot.RGB<EOL><DEDENT>elif mode == "<STR_LIT>":<EOL><INDENT>self.color_mode = Bot.HSB<EOL><DEDENT>else:<EOL><INDENT>raise NameError(_("<STR_LIT>"))<EOL><DEDENT><DEDENT>if crange is not None:<EOL><INDENT>self.color_range = crange<EOL><DEDENT>return self.color_mode<EOL>

Sets the current colormode (can be RGB or HSB) and eventually
        the color range.

        If called without arguments, it returns the current colormode.


self._fillcolor = self.color(*args)<EOL>return self._fillcolor<EOL>

Sets a fill color, applying it to new paths.


self._fillcolor = None<EOL>


self._strokecolor = self.color(*args)<EOL>return self._strokecolor<EOL>

Set a stroke color, applying it to new paths.


self._strokecolor = None<EOL>


if w is not None:<EOL><INDENT>self._strokewidth = w<EOL><DEDENT>else:<EOL><INDENT>return self._strokewidth<EOL><DEDENT>


self._canvas.background = self.color(*args)<EOL>


def font(self, fontpath=None, fontsize=None):

if fontpath is not None:<EOL><INDENT>self._canvas.fontfile = fontpath<EOL><DEDENT>else:<EOL><INDENT>return self._canvas.fontfile<EOL><DEDENT>if fontsize is not None:<EOL><INDENT>self._canvas.fontsize = fontsize<EOL><DEDENT>

Set the font to be used with new text instances.

        Accepts any font Pango can recognize


def text(self, txt, x, y, width=None, height=<NUM_LIT>, outline=False, draw=True, **kwargs):

txt = self.Text(txt, x, y, width, height, outline=outline, ctx=None, **kwargs)<EOL>if outline:<EOL><INDENT>path = txt.path<EOL>if draw:<EOL><INDENT>path.draw()<EOL><DEDENT>return path<EOL><DEDENT>else:<EOL><INDENT>return txt<EOL><DEDENT>

Draws a string of text according to current font settings.


def textpath(self, txt, x, y, width=None, height=<NUM_LIT>, enableRendering=False, **kwargs):

txt = self.Text(txt, x, y, width, height, **kwargs)<EOL>path = txt.path<EOL>if draw:<EOL><INDENT>path.draw()<EOL><DEDENT>return path<EOL>

Draws an outlined path of the input text


def textmetrics(self, txt, width=None, height=None, **kwargs):

<EOL>txt = self.Text(txt, <NUM_LIT:0>, <NUM_LIT:0>, width, height, enableRendering=False, **kwargs)<EOL>return txt.metrics<EOL>

Returns the width and height of a string of text as a tuple
        (according to current font settings).


w = width<EOL>return self.textmetrics(txt, width=w)[<NUM_LIT:0>]<EOL>

Returns the width of a string of text according to the current
        font settings.


w = width<EOL>return self.textmetrics(txt, width=w)[<NUM_LIT:1>]<EOL>

Returns the height of a string of text according to the current
        font settings.


def __init__(self, canvas, namespace=None, vars=None):

Grammar.__init__(self, canvas, namespace=namespace, vars=vars)<EOL>canvas.set_bot(self)<EOL>self._autoclosepath = True<EOL>self._path = None<EOL>if self._input_device:<EOL><INDENT>for key_name, value in self._input_device.get_key_map().items():<EOL><INDENT>self._namespace[key_name] = value<EOL>setattr(self, key_name, value)<EOL><DEDENT><DEDENT>self._canvas.size = None<EOL>self._frame = <NUM_LIT:1><EOL>self._set_initial_defaults()<EOL>

:param canvas: Canvas implementation for output.
:param namespace: Optionally specify a dict to inject as namespace
:param vars: Optional dict containing initial values for variables


DEFAULT_WIDTH, DEFAULT_HEIGHT = self._canvas.DEFAULT_SIZE<EOL>self.WIDTH = self._namespace.get('<STR_LIT>', DEFAULT_WIDTH)<EOL>self.HEIGHT = self._namespace.get('<STR_LIT>', DEFAULT_WIDTH)<EOL>if '<STR_LIT>' in self._namespace or '<STR_LIT>' in self._namespace:<EOL><INDENT>self.size(w=self._namespace.get('<STR_LIT>'), h=self._namespace.get('<STR_LIT>'))<EOL><DEDENT>self._transformmode = Bot.CENTER<EOL>self._canvas.settings(<EOL>fontfile="<STR_LIT>",<EOL>fontsize=<NUM_LIT:16>,<EOL>align=Bot.LEFT,<EOL>lineheight=<NUM_LIT:1>,<EOL>fillcolor=self.color(<NUM_LIT>),<EOL>strokecolor=None,<EOL>strokewidth=<NUM_LIT:1.0>,<EOL>background=self.color(<NUM_LIT:1>, <NUM_LIT:1>, <NUM_LIT:1>))<EOL>

Set the default values. Called at __init__ and at the end of run(),
        do that new draw loop iterations don't take up values left over by the
        previous one.


self._namespace['<STR_LIT>'] = True<EOL>


self._namespace['<STR_LIT>'] = self._input_device.mouse_down<EOL>


self._namespace['<STR_LIT>'] = x<EOL>self._namespace['<STR_LIT>'] = y<EOL>


self._namespace['<STR_LIT:key>'] = key<EOL>self._namespace['<STR_LIT>'] = keycode<EOL>self._namespace['<STR_LIT>'] = True<EOL>


self._namespace['<STR_LIT>'] = self._input_device.key_down<EOL>


pass<EOL>


self._dynamic = False<EOL>


def _makeInstance(self, clazz, args, kwargs):

inst = clazz(self, *args, **kwargs)<EOL>return inst<EOL>

Creates an instance of a class defined in this document.
           This method sets the context of the object to the current context.


def _makeColorableInstance(self, clazz, args, kwargs):

kwargs = dict(kwargs)<EOL>fill = kwargs.get('<STR_LIT>', self._canvas.fillcolor)<EOL>if not isinstance(fill, Color):<EOL><INDENT>fill = Color(fill, mode='<STR_LIT>', color_range=<NUM_LIT:1>)<EOL><DEDENT>kwargs['<STR_LIT>'] = fill<EOL>stroke = kwargs.get('<STR_LIT>', self._canvas.strokecolor)<EOL>if not isinstance(stroke, Color):<EOL><INDENT>stroke = Color(stroke, mode='<STR_LIT>', color_range=<NUM_LIT:1>)<EOL><DEDENT>kwargs['<STR_LIT>'] = stroke<EOL>kwargs['<STR_LIT>'] = kwargs.get('<STR_LIT>', self._canvas.strokewidth)<EOL>inst = clazz(self, *args, **kwargs)<EOL>return inst<EOL>

Create an object, if fill, stroke or strokewidth
is not specified, get them from the _canvas

:param clazz:
:param args:
:param kwargs:
:return:


return self.Color(mode=self.color_mode, color_range=self.color_range, *args)<EOL>

:param args: color in a supported format.

:return: Color object containing the color.


def grid(self, cols, rows, colSize=<NUM_LIT:1>, rowSize=<NUM_LIT:1>, shuffled=False):

<EOL>from random import shuffle<EOL>rowRange = range(int(rows))<EOL>colRange = range(int(cols))<EOL>if (shuffled):<EOL><INDENT>shuffle(rowRange)<EOL>shuffle(colRange)<EOL><DEDENT>for y in rowRange:<EOL><INDENT>for x in colRange:<EOL><INDENT>yield (x * colSize, y * rowSize)<EOL><DEDENT><DEDENT>

Returns an iterator that contains coordinate tuples.
        The grid can be used to quickly create grid-like structures.
        A common way to use them is:
            for x, y in grid(10,10,12,12):
                rect(x,y, 10,10)


<EOL>return glob(path)<EOL>

Returns a list of files.
        You can use wildcards to specify which files to pick, e.g.
            f = files('*.gif')

        :param path: wildcard to use in file list.


def snapshot(self, target=None, defer=None, autonumber=False):

if autonumber:<EOL><INDENT>file_number = self._frame<EOL><DEDENT>else:<EOL><INDENT>file_number = None<EOL><DEDENT>if isinstance(target, cairo.Surface):<EOL><INDENT>if defer is None:<EOL><INDENT>self._canvas.snapshot(surface, defer)<EOL>defer = False<EOL><DEDENT>ctx = cairo.Context(target)<EOL>self._canvas._drawqueue.render(ctx)<EOL>return<EOL><DEDENT>elif target is None:<EOL><INDENT>script_file = self._namespace.get('<STR_LIT>')<EOL>if script_file:<EOL><INDENT>target = os.path.splitext(script_file)[<NUM_LIT:0>] + '<STR_LIT>'<EOL>file_number = True<EOL><DEDENT><DEDENT>if target:<EOL><INDENT>if defer is None:<EOL><INDENT>defer = True<EOL><DEDENT>self._canvas.snapshot(target, defer=defer, file_number=file_number)<EOL><DEDENT>else:<EOL><INDENT>raise ShoebotError('<STR_LIT>')<EOL><DEDENT>

Save the contents of current surface into a file or cairo surface/context

        :param filename: Can be a filename or a Cairo surface.
        :param defer: If true, buffering/threading may be employed however output will not be immediate.
        :param autonumber: If true then a number will be appended to the filename.


def show(self, format='<STR_LIT>', as_data=False):

from io import BytesIO<EOL>b = BytesIO()<EOL>if format == '<STR_LIT>':<EOL><INDENT>from IPython.display import Image<EOL>surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, self.WIDTH, self.HEIGHT)<EOL>self.snapshot(surface)<EOL>surface.write_to_png(b)<EOL>b.seek(<NUM_LIT:0>)<EOL>data = b.read()<EOL>if as_data:<EOL><INDENT>return data<EOL><DEDENT>else:<EOL><INDENT>return Image(data)<EOL><DEDENT><DEDENT>elif format == '<STR_LIT>':<EOL><INDENT>from IPython.display import SVG<EOL>surface = cairo.SVGSurface(b, self.WIDTH, self.HEIGHT)<EOL>surface.finish()<EOL>b.seek(<NUM_LIT:0>)<EOL>data = b.read()<EOL>if as_data:<EOL><INDENT>return data<EOL><DEDENT>else:<EOL><INDENT>return SVG(data)<EOL><DEDENT><DEDENT>

Returns an Image object of the current surface. Used for displaying
        output in Jupyter notebooks. Adapted from the cairo-jupyter project.


<EOL>lib = __import__(libName)<EOL>self._namespace[libName] = lib<EOL>lib._ctx = self<EOL>return lib<EOL>

Import Nodebox libraries.

The libraries get _ctx, which provides
them with the nodebox API.

:param libName: Library name to import


if not w:<EOL><INDENT>w = self._canvas.width<EOL><DEDENT>if not h:<EOL><INDENT>h = self._canvas.height<EOL><DEDENT>if not w and not h:<EOL><INDENT>return (self._canvas.width, self._canvas.height)<EOL><DEDENT>w, h = self._canvas.set_size((w, h))<EOL>self._namespace['<STR_LIT>'] = w<EOL>self._namespace['<STR_LIT>'] = h<EOL>self.WIDTH = w  <EOL>self.HEIGHT = h<EOL>

Set the canvas size

        Only the first call will actually be effective.

        :param w: Width
        :param h: height


if framerate is not None:<EOL><INDENT>self._speed = framerate<EOL>self._dynamic = True<EOL><DEDENT>else:<EOL><INDENT>return self._speed<EOL><DEDENT>

Set animation framerate.

        :param framerate: Frames per second to run bot.
        :return: Current framerate of animation.


return self.edited_source is not None<EOL>


def load_edited_source(self, source, good_cb=None, bad_cb=None, filename=None):

with LiveExecution.lock:<EOL><INDENT>self.good_cb = good_cb<EOL>self.bad_cb = bad_cb<EOL>try:<EOL><INDENT>compile(source + '<STR_LIT>', filename or self.filename, "<STR_LIT>")<EOL>self.edited_source = source<EOL><DEDENT>except Exception as e:<EOL><INDENT>if bad_cb:<EOL><INDENT>self.edited_source = None<EOL>tb = traceback.format_exc()<EOL>self.call_bad_cb(tb)<EOL><DEDENT>return<EOL><DEDENT>if filename is not None:<EOL><INDENT>self.filename = filename<EOL><DEDENT><DEDENT>

Load changed code into the execution environment.

Until the code is executed correctly, it will be
in the 'tenuous' state.


with LiveExecution.lock:<EOL><INDENT>if self.edited_source:<EOL><INDENT>tree = ast.parse(self.edited_source)<EOL>for f in [n for n in ast.walk(tree) if isinstance(n, ast.FunctionDef)]:<EOL><INDENT>self.ns[f.name].__code__ = meta.decompiler.compile_func(f, self.filename, self.ns).__code__<EOL><DEDENT><DEDENT><DEDENT>

Replace functions in namespace with functions from edited_source.


exec(source, ns)<EOL>

Override if you want to do something other than exec in ns

tenuous is True if the source has just been edited and may fail


with LiveExecution.lock:<EOL><INDENT>ns_snapshot = copy.copy(self.ns)<EOL>try:<EOL><INDENT>source = self.edited_source<EOL>self.edited_source = None<EOL>self.do_exec(source, ns_snapshot)<EOL>self.known_good = source<EOL>self.call_good_cb()<EOL>return True, None<EOL><DEDENT>except Exception as ex:<EOL><INDENT>tb = traceback.format_exc()<EOL>self.call_bad_cb(tb)<EOL>self.ns.clear()<EOL>self.ns.update(ns_snapshot)<EOL>return False, ex<EOL><DEDENT><DEDENT>

Run edited source, if no exceptions occur then it
graduates to known good.


with LiveExecution.lock:<EOL><INDENT>if self.edited_source:<EOL><INDENT>success, ex = self.run_tenuous()<EOL>if success:<EOL><INDENT>return<EOL><DEDENT><DEDENT>self.do_exec(self.known_good, self.ns)<EOL><DEDENT>

Attempt to known good or tenuous source.


with LiveExecution.lock:<EOL><INDENT>self.bad_cb = None<EOL>self.good_cb = None<EOL><DEDENT>


with LiveExecution.lock:<EOL><INDENT>if self.bad_cb and not self.bad_cb(tb):<EOL><INDENT>self.bad_cb = None<EOL><DEDENT><DEDENT>

If bad_cb returns True then keep it
:param tb: traceback that caused exception
:return:


with LiveExecution.lock:<EOL><INDENT>if self.good_cb and not self.good_cb():<EOL><INDENT>self.good_cb = None<EOL><DEDENT><DEDENT>

If good_cb returns True then keep it
:return:


with LiveExecution.lock:<EOL><INDENT>if self.edited_source is None:<EOL><INDENT>yield True, self.known_good, self.ns<EOL>return<EOL><DEDENT>ns_snapshot = copy.copy(self.ns)<EOL>try:<EOL><INDENT>yield False, self.edited_source, self.ns<EOL>self.known_good = self.edited_source<EOL>self.edited_source = None<EOL>self.call_good_cb()<EOL>return<EOL><DEDENT>except Exception as ex:<EOL><INDENT>tb = traceback.format_exc()<EOL>self.call_bad_cb(tb)<EOL>self.edited_source = None<EOL>self.ns.clear()<EOL>self.ns.update(ns_snapshot)<EOL><DEDENT><DEDENT>

Context in which the user can run the source in a custom manner.

If no exceptions occur then the source will move from 'tenuous'
to 'known good'.

>>> with run_context() as (known_good, source, ns):
>>> ...  exec source in ns
>>> ...  ns['draw']()


def _load_namespace(self, namespace, filename=None):

from shoebot import data<EOL>for name in dir(data):<EOL><INDENT>namespace[name] = getattr(data, name)<EOL><DEDENT>for name in dir(self):<EOL><INDENT>if name[<NUM_LIT:0>] != '<STR_LIT:_>':<EOL><INDENT>namespace[name] = getattr(self, name)<EOL><DEDENT><DEDENT>namespace['<STR_LIT>'] = self  <EOL>namespace['<STR_LIT>'] = filename<EOL>

Initialise bot namespace with info in shoebot.data

:param filename: Will be set to __file__ in the namespace


def _should_run(self, iteration, max_iterations):

if iteration == <NUM_LIT:0>:<EOL><INDENT>return True<EOL><DEDENT>if max_iterations:<EOL><INDENT>if iteration < max_iterations:<EOL><INDENT>return True<EOL><DEDENT><DEDENT>elif max_iterations is None:<EOL><INDENT>if self._dynamic:<EOL><INDENT>return True<EOL><DEDENT>else:<EOL><INDENT>return False<EOL><DEDENT>return True<EOL><DEDENT>if not self._dynamic:<EOL><INDENT>return False<EOL><DEDENT>return False<EOL>


if self._speed:<EOL><INDENT>completion_time = time()<EOL>exc_time = completion_time - start_time<EOL>sleep_for = (<NUM_LIT:1.0> / abs(self._speed)) - exc_time<EOL>if sleep_for > <NUM_LIT:0>:<EOL><INDENT>sleep(sleep_for)<EOL><DEDENT><DEDENT>

Limit to framerate, should be called after
rendering has completed

:param start_time: When execution started


def _run_frame(self, executor, limit=False, iteration=<NUM_LIT:0>):

<EOL>start_time = time()<EOL>if iteration != <NUM_LIT:0> and self._speed != <NUM_LIT:0>:<EOL><INDENT>self._canvas.reset_canvas()<EOL><DEDENT>self._set_dynamic_vars()<EOL>if iteration == <NUM_LIT:0>:<EOL><INDENT>executor.run()<EOL>executor.ns['<STR_LIT>']()<EOL>executor.ns['<STR_LIT>']()<EOL>self._canvas.flush(self._frame)<EOL><DEDENT>else:<EOL><INDENT>if self._dynamic:<EOL><INDENT>if self._speed != <NUM_LIT:0>:  <EOL><INDENT>with executor.run_context() as (known_good, source, ns):<EOL><INDENT>if not known_good:<EOL><INDENT>executor.reload_functions()<EOL>with VarListener.batch(self._vars, self._oldvars, ns):<EOL><INDENT>self._oldvars.clear()<EOL>exec(source, ns)<EOL><DEDENT><DEDENT>ns['<STR_LIT>']()<EOL>self._canvas.flush(self._frame)<EOL><DEDENT><DEDENT><DEDENT>else:<EOL><INDENT>with executor.run_context() as (known_good, source, ns):<EOL><INDENT>if not known_good:<EOL><INDENT>executor.reload_functions()<EOL>with VarListener.batch(self._vars, self._oldvars, ns):<EOL><INDENT>self._oldvars.clear()<EOL>exec(source, ns)<EOL><DEDENT><DEDENT>else:<EOL><INDENT>exec(source, ns)<EOL><DEDENT>self._canvas.flush(self._frame)<EOL><DEDENT><DEDENT><DEDENT>if limit:<EOL><INDENT>self._frame_limit(start_time)<EOL><DEDENT>if self._speed > <NUM_LIT:0>:<EOL><INDENT>self._frame += <NUM_LIT:1><EOL><DEDENT>elif self._speed < <NUM_LIT:0>:<EOL><INDENT>self._frame -= <NUM_LIT:1><EOL><DEDENT>

Run single frame of the bot

        :param source_or_code: path to code to run, or actual code.
        :param limit: Time a frame should take to run (float - seconds)


def run(self, inputcode, iterations=None, run_forever=False, frame_limiter=False, verbose=False,<EOL>break_on_error=False):

source = None<EOL>filename = None<EOL>if os.path.isfile(inputcode):<EOL><INDENT>source = open(inputcode).read()<EOL>filename = inputcode<EOL><DEDENT>elif isinstance(inputcode, str):<EOL><INDENT>filename = '<STR_LIT>'<EOL>source = inputcode<EOL><DEDENT>self._load_namespace(self._namespace, filename)<EOL>self._executor = executor = LiveExecution(source, ns=self._namespace, filename=filename)<EOL>try:<EOL><INDENT>if not iterations:<EOL><INDENT>if run_forever:<EOL><INDENT>iterations = None<EOL><DEDENT>else:<EOL><INDENT>iterations = <NUM_LIT:1><EOL><DEDENT><DEDENT>iteration = <NUM_LIT:0><EOL>event = None<EOL>while iteration != iterations and not event_is(event, QUIT_EVENT):<EOL><INDENT>self._run_frame(executor, limit=frame_limiter, iteration=iteration)<EOL>if iteration == <NUM_LIT:0>:<EOL><INDENT>self._initial_namespace = copy.copy(self._namespace)  <EOL><DEDENT>iteration += <NUM_LIT:1><EOL>while self._should_run(iteration, iterations) and event is None:<EOL><INDENT>iteration += <NUM_LIT:1><EOL>self._run_frame(executor, limit=frame_limiter, iteration=iteration)<EOL>event = next_event()<EOL>if not event:<EOL><INDENT>self._canvas.sink.main_iteration()  <EOL><DEDENT><DEDENT>while run_forever:<EOL><INDENT>while event is None:<EOL><INDENT>self._canvas.sink.main_iteration()<EOL>event = next_event(block=True, timeout=<NUM_LIT>)<EOL>if not event:<EOL><INDENT>self._canvas.sink.main_iteration()  <EOL><DEDENT><DEDENT>if event.type == QUIT_EVENT:<EOL><INDENT>break<EOL><DEDENT>elif event.type == SOURCE_CHANGED_EVENT:<EOL><INDENT>while event and event.type == SOURCE_CHANGED_EVENT:<EOL><INDENT>event = next_event(block=True, timeout=<NUM_LIT>)<EOL><DEDENT><DEDENT>elif event.type == SET_WINDOW_TITLE:<EOL><INDENT>self._canvas.sink.set_title(event.data)<EOL><DEDENT>event = None  <EOL>break<EOL><DEDENT><DEDENT><DEDENT>except Exception as e:<EOL><INDENT>import sys<EOL>if verbose:<EOL><INDENT>errmsg = traceback.format_exc()<EOL><DEDENT>else:<EOL><INDENT>errmsg = simple_traceback(e, executor.known_good or '<STR_LIT>')<EOL><DEDENT>print(errmsg, file=sys.stderr)<EOL>if break_on_error:<EOL><INDENT>raise<EOL><DEDENT><DEDENT>

Executes the contents of a Nodebox/Shoebot script
in current surface's context.

:param inputcode: Path to shoebot source or string containing source
:param iterations: None or Maximum amount of frames to run
:param run_forever: If True then run until user quits the bot
:param frame_limiter: If True then sleep between frames to respect speed() command.


oldvar = self._oldvars.get(v.name)<EOL>if oldvar is not None:<EOL><INDENT>if isinstance(oldvar, Variable):<EOL><INDENT>if oldvar.compliesTo(v):<EOL><INDENT>v.value = oldvar.value<EOL><DEDENT><DEDENT>else:<EOL><INDENT>v.value = v.sanitize(oldvar)<EOL><DEDENT><DEDENT>else:<EOL><INDENT>for listener in VarListener.listeners:<EOL><INDENT>listener.var_added(v)<EOL><DEDENT><DEDENT>self._vars[v.name] = v<EOL>self._namespace[v.name] = v.value<EOL>self._oldvars[v.name] = v<EOL>return v<EOL>

Sets a new accessible variable.

        :param v: Variable.


exc_type, exc_value, exc_tb = sys.exc_info()<EOL>exc = traceback.format_exception(exc_type, exc_value, exc_tb)<EOL>source_arr = source.splitlines()<EOL>exc_location = exc[-<NUM_LIT:2>]<EOL>for i, err in enumerate(exc):<EOL><INDENT>if '<STR_LIT>' in err:<EOL><INDENT>exc_location = exc[i + <NUM_LIT:1>]<EOL>break<EOL><DEDENT><DEDENT>fn = exc_location.split('<STR_LIT:U+002C>')[<NUM_LIT:0>][<NUM_LIT:8>:-<NUM_LIT:1>]<EOL>line_number = int(exc_location.split('<STR_LIT:U+002C>')[<NUM_LIT:1>].replace('<STR_LIT>', '<STR_LIT>').strip())<EOL>err_msgs = []<EOL>err_where = '<STR_LIT:U+0020>'.join(exc[i - <NUM_LIT:1>].split('<STR_LIT:U+002C>')[<NUM_LIT:1>:]).strip()  <EOL>err_msgs.append('<STR_LIT>' % err_where)<EOL>for i in xrange(max(<NUM_LIT:0>, line_number - <NUM_LIT:5>), line_number):<EOL><INDENT>if fn == "<STR_LIT>":<EOL><INDENT>line = source_arr[i]<EOL><DEDENT>else:<EOL><INDENT>line = linecache.getline(fn, i + <NUM_LIT:1>)<EOL><DEDENT>err_msgs.append('<STR_LIT>' % (i + <NUM_LIT:1>, line.rstrip()))<EOL><DEDENT>err_msgs.append('<STR_LIT>' % (len(str(i)) * '<STR_LIT:U+0020>', exc[-<NUM_LIT:1>].rstrip()))<EOL>err_msgs.append('<STR_LIT>')<EOL>err_msgs.append(exc[<NUM_LIT:0>].rstrip())<EOL>for err in exc[<NUM_LIT:3>:]:<EOL><INDENT>err_msgs.append(err.rstrip())<EOL><DEDENT>return '<STR_LIT:\n>'.join(err_msgs)<EOL>

Format traceback, showing line number and surrounding source.


def __init__(self, canvas=None, namespace=None, vars=None):

Bot.__init__(self, canvas, namespace=namespace, vars=vars)<EOL>canvas.mode = CORNER<EOL>self._ns = self._namespace<EOL>

Nodebot grammar constructor

:param canvas: Canvas implementation for output.
:param namespace: Optionally specify a dict to inject as namespace
:param vars: Optional dict containing initial values for variables


def image(self, path, x, y, width=None, height=None, alpha=<NUM_LIT:1.0>, data=None, draw=True, **kwargs):

return self.Image(path, x, y, width, height, alpha, data, **kwargs)<EOL>

Draws a image form path, in x,y and resize it to width, height dimensions.


img = PILImage.open(path)<EOL>return img.size<EOL>

:param: path    Path to image file.
:return: image size as tuple (width, height)


def rect(self, x, y, width, height, roundness=<NUM_LIT:0.0>, draw=True, **kwargs):

path = self.BezierPath(**kwargs)<EOL>path.rect(x, y, width, height, roundness, self.rectmode)<EOL>if draw:<EOL><INDENT>path.draw()<EOL><DEDENT>return path<EOL>

Draw a rectangle from x, y of width, height.

:param startx: top left x-coordinate
:param starty: top left y-coordinate

:param width: height  Size of rectangle.
:roundness: Corner roundness defaults to 0.0 (a right-angle).
:draw: If True draws immediately.
:fill: Optionally pass a fill color.

:return: path representing the rectangle.


if mode in (self.CORNER, self.CENTER, self.CORNERS):<EOL><INDENT>self.rectmode = mode<EOL>return self.rectmode<EOL><DEDENT>elif mode is None:<EOL><INDENT>return self.rectmode<EOL><DEDENT>else:<EOL><INDENT>raise ShoebotError(_("<STR_LIT>"))<EOL><DEDENT>

Set the current rectmode.

:param mode: CORNER, CENTER, CORNERS
:return: rectmode if mode is None or valid.


if mode in (self.CORNER, self.CENTER, self.CORNERS):<EOL><INDENT>self.ellipsemode = mode<EOL>return self.ellipsemode<EOL><DEDENT>elif mode is None:<EOL><INDENT>return self.ellipsemode<EOL><DEDENT>else:<EOL><INDENT>raise ShoebotError(_("<STR_LIT>"))<EOL><DEDENT>

Set the current ellipse drawing mode.

:param mode: CORNER, CENTER, CORNERS
:return: ellipsemode if mode is None or valid.


def oval(self, x, y, width, height, draw=True, **kwargs):

path = self.BezierPath(**kwargs)<EOL>path.ellipse(x, y, width, height, self.ellipsemode)<EOL>if draw:<EOL><INDENT>path.draw()<EOL><DEDENT>return path<EOL>

Draw an ellipse starting from (x,y) -  ovals and ellipses are not the same


def ellipse(self, x, y, width, height, draw=True, **kwargs):


def circle(self, x, y, diameter, draw=True, **kwargs):

return self.ellipse(x, y, diameter, diameter, draw, **kwargs)<EOL>

Draw a circle
        :param x: x-coordinate of the top left corner
        :param y: y-coordinate of the top left corner
        :param diameter: Diameter of circle.
        :param draw: Draw immediately (defaults to True, set to False to inhibit drawing)
        :return: Path object representing circle


def line(self, x1, y1, x2, y2, draw=True):

p = self._path<EOL>self.beginpath()<EOL>self.moveto(x1, y1)<EOL>self.lineto(x2, y2)<EOL>self.endpath(draw=draw)<EOL>self._path = p<EOL>return p<EOL>

Draw a line from (x1,y1) to (x2,y2)
        :param x1: start x-coordinate
        :param y1: start y-coordinate
        :param x2: end x-coordinate
        :param y2: end y-coordinate


def arrow(self, x, y, width, type=NORMAL, draw=True, **kwargs):

<EOL>path = self.BezierPath(**kwargs)<EOL>if type == self.NORMAL:<EOL><INDENT>head = width * <NUM_LIT><EOL>tail = width * <NUM_LIT><EOL>path.moveto(x, y)<EOL>path.lineto(x - head, y + head)<EOL>path.lineto(x - head, y + tail)<EOL>path.lineto(x - width, y + tail)<EOL>path.lineto(x - width, y - tail)<EOL>path.lineto(x - head, y - tail)<EOL>path.lineto(x - head, y - head)<EOL>path.lineto(x, y)<EOL><DEDENT>elif type == self.FORTYFIVE:<EOL><INDENT>head = <NUM_LIT><EOL>tail = <NUM_LIT:1> + head<EOL>path.moveto(x, y)<EOL>path.lineto(x, y + width * (<NUM_LIT:1> - head))<EOL>path.lineto(x - width * head, y + width)<EOL>path.lineto(x - width * head, y + width * tail * <NUM_LIT>)<EOL>path.lineto(x - width * tail * <NUM_LIT>, y + width)<EOL>path.lineto(x - width, y + width * tail * <NUM_LIT>)<EOL>path.lineto(x - width * tail * <NUM_LIT>, y + width * head)<EOL>path.lineto(x - width, y + width * head)<EOL>path.lineto(x - width * (<NUM_LIT:1> - head), y)<EOL>path.lineto(x, y)<EOL><DEDENT>else:<EOL><INDENT>raise NameError(_("<STR_LIT>"))<EOL><DEDENT>if draw:<EOL><INDENT>path.draw()<EOL><DEDENT>return path<EOL>

Draw an arrow.

        Arrows can be two types: NORMAL or FORTYFIVE.

        :param x: top left x-coordinate
        :param y: top left y-coordinate
        :param width: width of arrow
        :param type:  NORMAL or FORTYFIVE
        :draw:  If True draws arrow immediately

        :return: Path object representing the arrow.


def star(self, startx, starty, points=<NUM_LIT:20>, outer=<NUM_LIT:100>, inner=<NUM_LIT:50>, draw=True, **kwargs):

<EOL>self.beginpath(**kwargs)<EOL>self.moveto(startx, starty + outer)<EOL>for i in range(<NUM_LIT:1>, int(<NUM_LIT:2> * points)):<EOL><INDENT>angle = i * pi / points<EOL>x = sin(angle)<EOL>y = cos(angle)<EOL>if i % <NUM_LIT:2>:<EOL><INDENT>radius = inner<EOL><DEDENT>else:<EOL><INDENT>radius = outer<EOL><DEDENT>x = startx + radius * x<EOL>y = starty + radius * y<EOL>self.lineto(x, y)<EOL><DEDENT>return self.endpath(draw)<EOL>


def drawimage(self, image, x=None, y=None):

if x is None:<EOL><INDENT>x = image.x<EOL><DEDENT>if y is None:<EOL><INDENT>y = image.y<EOL><DEDENT>self.image(image.path, image.x, image.y, data=image.data)<EOL>

:param image: Image to draw
:param x: optional, x coordinate (default is image.x)
:param y: optional, y coordinate (default is image.y)
:return:


if self._path is None:<EOL><INDENT>raise ShoebotError(_("<STR_LIT>"))<EOL><DEDENT>self._path.relmoveto(x, y)<EOL>


if self._path is None:<EOL><INDENT>raise ShoebotError(_("<STR_LIT>"))<EOL><DEDENT>self._path.rellineto(x, y)<EOL>


def relcurveto(self, h1x, h1y, h2x, h2y, x, y):

if self._path is None:<EOL><INDENT>raise ShoebotError(_("<STR_LIT>"))<EOL><DEDENT>self._path.relcurveto(h1x, h1y, h2x, h2y, x, y)<EOL>

Draws a curve relatively to the last point.


def findpath(self, points, curvature=<NUM_LIT:1.0>):

<EOL>for i, pt in enumerate(points):<EOL><INDENT>if type(pt) == TupleType:<EOL><INDENT>points[i] = Point(pt[<NUM_LIT:0>], pt[<NUM_LIT:1>])<EOL><DEDENT><DEDENT>if len(points) == <NUM_LIT:0>:<EOL><INDENT>return None<EOL><DEDENT>if len(points) == <NUM_LIT:1>:<EOL><INDENT>path = self.BezierPath(None)<EOL>path.moveto(points[<NUM_LIT:0>].x, points[<NUM_LIT:0>].y)<EOL>return path<EOL><DEDENT>if len(points) == <NUM_LIT:2>:<EOL><INDENT>path = self.BezierPath(None)<EOL>path.moveto(points[<NUM_LIT:0>].x, points[<NUM_LIT:0>].y)<EOL>path.lineto(points[<NUM_LIT:1>].x, points[<NUM_LIT:1>].y)<EOL>return path<EOL><DEDENT>curvature = max(<NUM_LIT:0>, min(<NUM_LIT:1>, curvature))<EOL>if curvature == <NUM_LIT:0>:<EOL><INDENT>path = self.BezierPath(None)<EOL>path.moveto(points[<NUM_LIT:0>].x, points[<NUM_LIT:0>].y)<EOL>for i in range(len(points)):<EOL><INDENT>path.lineto(points[i].x, points[i].y)<EOL><DEDENT>return path<EOL><DEDENT>curvature = <NUM_LIT:4> + (<NUM_LIT:1.0> - curvature) * <NUM_LIT><EOL>dx = {<NUM_LIT:0>: <NUM_LIT:0>, len(points) - <NUM_LIT:1>: <NUM_LIT:0>}<EOL>dy = {<NUM_LIT:0>: <NUM_LIT:0>, len(points) - <NUM_LIT:1>: <NUM_LIT:0>}<EOL>bi = {<NUM_LIT:1>: -<NUM_LIT>}<EOL>ax = {<NUM_LIT:1>: (points[<NUM_LIT:2>].x - points[<NUM_LIT:0>].x - dx[<NUM_LIT:0>]) / <NUM_LIT:4>}<EOL>ay = {<NUM_LIT:1>: (points[<NUM_LIT:2>].y - points[<NUM_LIT:0>].y - dy[<NUM_LIT:0>]) / <NUM_LIT:4>}<EOL>for i in range(<NUM_LIT:2>, len(points) - <NUM_LIT:1>):<EOL><INDENT>bi[i] = -<NUM_LIT:1> / (curvature + bi[i - <NUM_LIT:1>])<EOL>ax[i] = -(points[i + <NUM_LIT:1>].x - points[i - <NUM_LIT:1>].x - ax[i - <NUM_LIT:1>]) * bi[i]<EOL>ay[i] = -(points[i + <NUM_LIT:1>].y - points[i - <NUM_LIT:1>].y - ay[i - <NUM_LIT:1>]) * bi[i]<EOL><DEDENT>r = range(<NUM_LIT:1>, len(points) - <NUM_LIT:1>)<EOL>r.reverse()<EOL>for i in r:<EOL><INDENT>dx[i] = ax[i] + dx[i + <NUM_LIT:1>] * bi[i]<EOL>dy[i] = ay[i] + dy[i + <NUM_LIT:1>] * bi[i]<EOL><DEDENT>path = self.BezierPath(None)<EOL>path.moveto(points[<NUM_LIT:0>].x, points[<NUM_LIT:0>].y)<EOL>for i in range(len(points) - <NUM_LIT:1>):<EOL><INDENT>path.curveto(points[i].x + dx[i],<EOL>points[i].y + dy[i],<EOL>points[i + <NUM_LIT:1>].x - dx[i + <NUM_LIT:1>],<EOL>points[i + <NUM_LIT:1>].y - dy[i + <NUM_LIT:1>],<EOL>points[i + <NUM_LIT:1>].x,<EOL>points[i + <NUM_LIT:1>].y)<EOL><DEDENT>return path<EOL>

Constructs a path between the given list of points.

        Interpolates the list of points and determines
        a smooth bezier path betweem them.

        The curvature parameter offers some control on
        how separate segments are stitched together:
        from straight angles to smooth curves.
        Curvature is only useful if the path has more than  three points.


if mode:<EOL><INDENT>self._canvas.mode = mode<EOL><DEDENT>return self._canvas.mode<EOL>

Set the current transform mode.

:param mode: CENTER or CORNER


self._canvas.translate(xt, yt)<EOL>if mode:<EOL><INDENT>self._canvas.mode = mode<EOL><DEDENT>

Translate the current position by (xt, yt) and
optionally set the transform mode.

:param xt: Amount to move horizontally
:param yt: Amount to move vertically
:mode: Set the transform mode to CENTER or CORNER


def rotate(self, degrees=<NUM_LIT:0>, radians=<NUM_LIT:0>):

<EOL>if radians:<EOL><INDENT>angle = radians<EOL><DEDENT>else:<EOL><INDENT>angle = deg2rad(degrees)<EOL><DEDENT>self._canvas.rotate(-angle)<EOL>

Set the current rotation in degrees or radians.

:param degrees: Degrees to rotate
:param radians: Radians to rotate


if not y:<EOL><INDENT>y = x<EOL><DEDENT>if x == <NUM_LIT:0>:<EOL><INDENT>x = <NUM_LIT:1><EOL><DEDENT>if y == <NUM_LIT:0>:<EOL><INDENT>y = <NUM_LIT:1><EOL><DEDENT>self._canvas.scale(x, y)<EOL>

Set a scale at which to draw objects.

1.0 draws objects at their natural size

:param x: Scale on the horizontal plane
:param y: Scale on the vertical plane


raise NotImplementedError(_("<STR_LIT>"))<EOL>


def colormode(self, mode=None, crange=None):

if mode is not None:<EOL><INDENT>if mode == "<STR_LIT>":<EOL><INDENT>self.color_mode = RGB<EOL><DEDENT>elif mode == "<STR_LIT>":<EOL><INDENT>self.color_mode = HSB<EOL><DEDENT>else:<EOL><INDENT>raise NameError(_("<STR_LIT>"))<EOL><DEDENT><DEDENT>if crange is not None:<EOL><INDENT>self.color_range = crange<EOL><DEDENT>return self.color_mode<EOL>

Set the current colormode (can be RGB or HSB) and eventually
        the color range.

        If called without arguments, it returns the current colormode.

        :param mode: Color mode, either "rgb", or "hsb"
        :param crange: Maximum scale value for color, e.g. 1.0 or 255

        :return: Returns the current color mode.


self.color_range = float(crange)<EOL>

By default colors range from 0.0 - 1.0 using colorrange
        other defaults can be used, e.g. 0.0 - 255.0

        :param crange: Color range of 0.0 - 255:
        >>> colorrange(256)


if args is not None:<EOL><INDENT>self._canvas.fillcolor = self.color(*args)<EOL><DEDENT>return self._canvas.fillcolor<EOL>

Sets a fill color, applying it to new paths.

        :param args: color in supported format


self._canvas.fillcolor = None<EOL>


if args is not None:<EOL><INDENT>self._canvas.strokecolor = self.color(*args)<EOL><DEDENT>return self._canvas.strokecolor<EOL>

Set a stroke color, applying it to new paths.

        :param args: color in supported format


c = self._canvas.strokecolor<EOL>self._canvas.strokecolor = None<EOL>return c<EOL>

Stop applying strokes to new paths.

        :return: stroke color before nostroke was called.


if w is not None:<EOL><INDENT>self._canvas.strokewidth = w<EOL><DEDENT>else:<EOL><INDENT>return self._canvas.strokewidth<EOL><DEDENT>

Set the stroke width.

        :param w: Stroke width.
        :return: If no width was specified then current width is returned.


self._canvas.background = self.color(*args)<EOL>

Set the background color.

        :param color: See color() function for supported color formats.


def font(self, fontpath=None, fontsize=None):

if fontpath is not None:<EOL><INDENT>self._canvas.fontfile = fontpath<EOL><DEDENT>else:<EOL><INDENT>return self._canvas.fontfile<EOL><DEDENT>if fontsize is not None:<EOL><INDENT>self._canvas.fontsize = fontsize<EOL><DEDENT>

Set the font to be used with new text instances.

        :param fontpath: path to truetype or opentype font.
        :param fontsize: size of font

        :return: current current fontpath (if fontpath param not set)
        Accepts TrueType and OpenType files. Depends on FreeType being
        installed.


if fontsize is not None:<EOL><INDENT>self._canvas.fontsize = fontsize<EOL><DEDENT>else:<EOL><INDENT>return self._canvas.fontsize<EOL><DEDENT>

Set or return size of current font.

:param fontsize: Size of font.
:return: Size of font (if fontsize was not specified)


def text(self, txt, x, y, width=None, height=<NUM_LIT>, outline=False, draw=True, **kwargs):

txt = self.Text(txt, x, y, width, height, outline=outline, ctx=None, **kwargs)<EOL>if outline:<EOL><INDENT>path = txt.path<EOL>if draw:<EOL><INDENT>path.draw()<EOL><DEDENT>return path<EOL><DEDENT>else:<EOL><INDENT>return txt<EOL><DEDENT>

Draws a string of text according to current font settings.

:param txt: Text to output
:param x: x-coordinate of the top left corner
:param y: y-coordinate of the top left corner
:param width: text width
:param height: text height
:param outline: If True draws outline text (defaults to False)
:param draw: Set to False to inhibit immediate drawing (defaults to True)
:return: Path object representing the text.


def textpath(self, txt, x, y, width=None, height=<NUM_LIT>, draw=False, **kwargs):

txt = self.Text(txt, x, y, width, height, enableRendering=False, **kwargs)<EOL>path = txt.path<EOL>if draw:<EOL><INDENT>path.draw()<EOL><DEDENT>return path<EOL>

Generates an outlined path of the input text.

:param txt: Text to output
:param x: x-coordinate of the top left corner
:param y: y-coordinate of the top left corner
:param width: text width
:param height: text height
:param draw: Set to False to inhibit immediate drawing (defaults to False)
:return: Path object representing the text.


def textmetrics(self, txt, width=None, height=None, **kwargs):

<EOL>txt = self.Text(txt, <NUM_LIT:0>, <NUM_LIT:0>, width, height, enableRendering=False, **kwargs)<EOL>return txt.metrics<EOL>

:return: the width and height of a string of text as a tuple
according to current font settings.


w = width<EOL>return self.textmetrics(txt, width=w)[<NUM_LIT:0>]<EOL>

:return: the width of a string of text according to the current
font settings.


w = width<EOL>return self.textmetrics(txt, width=w)[<NUM_LIT:1>]<EOL>

Returns the height of a string of text according to the current
        font settings.

        :param txt: string to measure
        :param width: width of a line of text in a block


if height is not None:<EOL><INDENT>self._canvas.lineheight = height<EOL><DEDENT>

Set text lineheight.

        :param height: line height.


self._canvas.align = align<EOL>

Set text alignment

:param align: Text alignment (LEFT, CENTER, RIGHT)


return self._canvas<EOL>

Not entirely sure compatible the Shoebot 'canvas' is with Nodebox
but there you go.
:return:


if hasattr(source, "<STR_LIT>"):<EOL><INDENT>return source<EOL><DEDENT>if source == "<STR_LIT:->":<EOL><INDENT>import sys<EOL>return sys.stdin<EOL><DEDENT>import urllib.request, urllib.parse, urllib.error<EOL>try:<EOL><INDENT>return urllib.request.urlopen(source)<EOL><DEDENT>except (IOError, OSError):<EOL><INDENT>pass<EOL><DEDENT>for path in searchpaths or ['<STR_LIT:.>']:<EOL><INDENT>try:<EOL><INDENT>return open(os.path.join(path, source))<EOL><DEDENT>except (IOError, OSError):<EOL><INDENT>pass<EOL><DEDENT><DEDENT>import io<EOL>return io.StringIO(str(source))<EOL>

URI, filename, or string --> stream

    This function lets you define parsers that take any input source
    (URL, pathname to local or network file, or actual data as a string)
    and deal with it in a uniform manner.  Returned object is guaranteed
    to have all the basic stdio read methods (read, readline, readlines).
    Just .close() the object when you're done with it.

    Examples:
    >>> from xml.dom import minidom
    >>> sock = openAnything("http://localhost/kant.xml")
    >>> doc = minidom.parse(sock)
    >>> sock.close()
    >>> sock = openAnything("c:\\inetpub\\wwwroot\\kant.xml")
    >>> doc = minidom.parse(sock)
    >>> sock.close()
    >>> sock = openAnything("<ref id='conjunction'><text>and</text><text>or</text></ref>")
    >>> doc = minidom.parse(sock)
    >>> sock.close()


def _load(self, source, searchpaths=None):

sock = openAnything(source, searchpaths=searchpaths)<EOL>xmldoc = minidom.parse(sock).documentElement<EOL>sock.close()<EOL>return xmldoc<EOL>

load XML input source, return parsed XML document

        - a URL of a remote XML file ("http://diveintopython.org/kant.xml")
        - a filename of a local XML file ("~/diveintopython/common/py/kant.xml")
        - standard input ("-")
        - the actual XML document, as a string

        :param searchpaths: optional searchpaths if file is used.


def loadGrammar(self, grammar, searchpaths=None):

self.grammar = self._load(grammar, searchpaths=searchpaths)<EOL>self.refs = {}<EOL>for ref in self.grammar.getElementsByTagName("<STR_LIT>"):<EOL><INDENT>self.refs[ref.attributes["<STR_LIT:id>"].value] = ref<EOL><DEDENT>


def loadSource(self, source, searchpaths=None):

self.source = self._load(source, searchpaths=searchpaths)<EOL>


xrefs = {}<EOL>for xref in self.grammar.getElementsByTagName("<STR_LIT>"):<EOL><INDENT>xrefs[xref.attributes["<STR_LIT:id>"].value] = <NUM_LIT:1><EOL><DEDENT>xrefs = list(xrefs.keys())<EOL>standaloneXrefs = [e for e in list(self.refs.keys()) if e not in xrefs]<EOL>if not standaloneXrefs:<EOL><INDENT>raise NoSourceError("<STR_LIT>")<EOL><DEDENT>return '<STR_LIT>' % random.choice(standaloneXrefs)<EOL>

guess default source of the current grammar

        The default source will be one of the <ref>s that is not
        cross-referenced.  This sounds complicated but it's not.
        Example: The default source for kant.xml is
        "<xref id='section'/>", because 'section' is the one <ref>
        that is not <xref>'d anywhere in the grammar.
        In most grammars, the default source will produce the
        longest (and most interesting) output.


self.pieces = []<EOL>self.capitalizeNextWord = <NUM_LIT:0><EOL>


self.reset()<EOL>self.parse(self.source)<EOL>return self.output()<EOL>

reset output buffer, re-parse entire source file, and return output

        Since parsing involves a good deal of randomness, this is an
        easy way to get new output without having to reload a grammar file
        each time.


return "<STR_LIT>".join(self.pieces)<EOL>


choices = [e for e in node.childNodes<EOL>if e.nodeType == e.ELEMENT_NODE]<EOL>chosen = random.choice(choices)<EOL>if _debug:<EOL><INDENT>sys.stderr.write('<STR_LIT>' %(len(choices), [e.toxml() for e in choices]))<EOL>sys.stderr.write('<STR_LIT>' % chosen.toxml())<EOL><DEDENT>return chosen<EOL>

choose a random child element of a node

        This is a utility method used by do_xref and do_choice.


parseMethod = getattr(self, "<STR_LIT>" % node.__class__.__name__)<EOL>parseMethod(node)<EOL>

parse a single XML node

        A parsed XML document (from minidom.parse) is a tree of nodes
        of various types.  Each node is represented by an instance of the
        corresponding Python class (Element for a tag, Text for
        text data, Document for the top-level document).  The following
        statement constructs the name of a class method based on the type
        of node we're parsing ("parse_Element" for an Element node,
        "parse_Text" for a Text node, etc.) and then calls the method.


self.parse(node.documentElement)<EOL>

parse the document node

        The document node by itself isn't interesting (to us), but
        its only child, node.documentElement, is: it's the root node
        of the grammar.


text = node.data<EOL>if self.capitalizeNextWord:<EOL><INDENT>self.pieces.append(text[<NUM_LIT:0>].upper())<EOL>self.pieces.append(text[<NUM_LIT:1>:])<EOL>self.capitalizeNextWord = <NUM_LIT:0><EOL><DEDENT>else:<EOL><INDENT>self.pieces.append(text)<EOL><DEDENT>

parse a text node

        The text of a text node is usually added to the output buffer
        verbatim.  The one exception is that <p class='sentence'> sets
        a flag to capitalize the first letter of the next word.  If
        that flag is set, we capitalize the text and reset the flag.


handlerMethod = getattr(self, "<STR_LIT>" % node.tagName)<EOL>handlerMethod(node)<EOL>

parse an element

        An XML element corresponds to an actual tag in the source:
        <xref id='...'>, <p chance='...'>, <choice>, etc.
        Each element type is handled in its own method.  Like we did in
        parse(), we construct a method name based on the name of the
        element ("do_xref" for an <xref> tag, etc.) and
        call the method.


pass<EOL>

parse a comment

        The grammar can contain XML comments, but we ignore them


id = node.attributes["<STR_LIT:id>"].value<EOL>self.parse(self.randomChildElement(self.refs[id]))<EOL>

handle <xref id='...'> tag

        An <xref id='...'> tag is a cross-reference to a <ref id='...'>
        tag.  <xref id='sentence'/> evaluates to a randomly chosen child of
        <ref id='sentence'>.


keys = list(node.attributes.keys())<EOL>if "<STR_LIT:class>" in keys:<EOL><INDENT>if node.attributes["<STR_LIT:class>"].value == "<STR_LIT>":<EOL><INDENT>self.capitalizeNextWord = <NUM_LIT:1><EOL><DEDENT><DEDENT>if "<STR_LIT>" in keys:<EOL><INDENT>chance = int(node.attributes["<STR_LIT>"].value)<EOL>doit = (chance > random.randrange(<NUM_LIT:100>))<EOL><DEDENT>else:<EOL><INDENT>doit = <NUM_LIT:1><EOL><DEDENT>if doit:<EOL><INDENT>for child in node.childNodes: self.parse(child)<EOL><DEDENT>

handle <p> tag

        The <p> tag is the core of the grammar.  It can contain almost
        anything: freeform text, <choice> tags, <xref> tags, even other
        <p> tags.  If a "class='sentence'" attribute is found, a flag
        is set and the next word will be capitalized.  If a "chance='X'"
        attribute is found, there is an X% chance that the tag will be
        evaluated (and therefore a (100-X)% chance that it will be
        completely ignored)


self.parse(self.randomChildElement(node))<EOL>

handle <choice> tag

        A <choice> tag contains one or more <p> tags.  One <p> tag
        is chosen at random and evaluated; the rest are ignored.


VarListener.active = False<EOL>yield<EOL>VarListener.active = True<EOL>

Context manager to temporarily disable all listeners

>>> with VarListener.disabled()
...     pass


@staticmethod<EOL><INDENT>@contextmanager<EOL>def batch(vars, oldvars, ns):<DEDENT>

snapshot_vars = dict(vars)<EOL>with VarListener.disabled():<EOL><INDENT>yield<EOL><DEDENT>added_vars = set(oldvars.keys()) - set(snapshot_vars.keys())<EOL>deleted_vars = set(snapshot_vars.keys()) - set(oldvars.keys())<EOL>existing_vars = set(vars.keys()) - added_vars - deleted_vars<EOL>for name in existing_vars:<EOL><INDENT>old_var = snapshot_vars[name]<EOL>new_var = vars[name]<EOL>if old_var.type != new_var.type or old_var.min != new_var.min or old_var.max != new_var.max:<EOL><INDENT>deleted_vars.add(name)<EOL>added_vars.add(name)<EOL>if old_var.type == new_var.type:<EOL><INDENT>new_var.value = old_var.value<EOL><DEDENT><DEDENT><DEDENT>for listener in VarListener.listeners:<EOL><INDENT>for name in deleted_vars:<EOL><INDENT>listener.var_deleted(snapshot_vars[name])<EOL>if ns.get(name) is snapshot_vars[name].value:<EOL><INDENT>del ns[name]<EOL><DEDENT><DEDENT>for name in added_vars:<EOL><INDENT>listener.var_added(vars[name])<EOL><DEDENT><DEDENT>

Context manager to only update listeners
at the end, in the meantime it doesn't
matter what intermediate state the vars
are in (they can be added and removed)

>>> with VarListener.batch()
...     pass


for name in self.SUPPORTED_CALLBACKS:<EOL><INDENT>func = kwargs.get(name, getattr(self, name))<EOL>setattr(self, name, func)<EOL><DEDENT>


return bool(self.keys_pressed)<EOL>


return bool(self.mouse_buttons_down)<EOL>

Return True if any mouse button is pressed


def __init__(self, target=None, format=None, multifile=False, buff=None):

DrawQueueSink.__init__(self)<EOL>if format is None:<EOL><INDENT>if target is not None and format is not '<STR_LIT>':<EOL><INDENT>format = os.path.splitext(target)[<NUM_LIT:1>][<NUM_LIT:1>:].lower()<EOL>self.filename = target<EOL><DEDENT>elif buff is not None:<EOL><INDENT>raise AttributeError("<STR_LIT>")<EOL><DEDENT>else:<EOL><INDENT>self.file_root, self.file_ext = os.path.splitext(filename)<EOL><DEDENT><DEDENT>self.buff = buff<EOL>self.format = format<EOL>self.target = target<EOL>self.multifile = multifile<EOL>

:param target:  output filename (or cairo surface if format is 'surface')
:param format:    if filename is specified this is not needed. Can be 'surface' for Cairo surfaces
:param multifile: If used with filename, then numbered files will be output for each froam.
:param buff:      optionally a file like object can be used instead of a filename
                  this is useful for streaming output.


if self.buff:<EOL><INDENT>return self.buff<EOL><DEDENT>elif self.multifile:<EOL><INDENT>return self.file_root + "<STR_LIT>" % frame + self.file_ext<EOL><DEDENT>else:<EOL><INDENT>return self.filename<EOL><DEDENT>

If filename was used output a filename, along with multifile
numbered filenames will be used.

If buff was specified it is returned.

:return: Output buff or filename.


if self.format == '<STR_LIT>':<EOL><INDENT>surface = cairo.PDFSurface(self._output_file(frame), *size)<EOL><DEDENT>elif self.format in ('<STR_LIT>', '<STR_LIT>'):<EOL><INDENT>surface = cairo.PSSurface(self._output_file(frame), *size)<EOL><DEDENT>elif self.format == '<STR_LIT>':<EOL><INDENT>surface = cairo.SVGSurface(self._output_file(frame), *size)<EOL><DEDENT>elif self.format == '<STR_LIT>':<EOL><INDENT>surface = self.target<EOL><DEDENT>else:<EOL><INDENT>surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, *size)<EOL><DEDENT>return cairo.Context(surface)<EOL>

Called when CairoCanvas needs a cairo context to draw on


def rendering_finished(self, size, frame, cairo_ctx):

surface = cairo_ctx.get_target()<EOL>if self.format == '<STR_LIT>':<EOL><INDENT>surface.write_to_png(self._output_file(frame))<EOL><DEDENT>surface.finish()<EOL>surface.flush()<EOL>

Called when CairoCanvas has rendered a bot


return cairo.Matrix()<EOL>


def output_closure(self, target, file_number=None):

def output_context(ctx):<EOL><INDENT>target_ctx = target<EOL>target_ctx.set_source_surface(ctx.get_target())<EOL>target_ctx.paint()<EOL>return target_ctx<EOL><DEDENT>def output_surface(ctx):<EOL><INDENT>target_ctx = cairo.Context(target)<EOL>target_ctx.set_source_surface(ctx.get_target())<EOL>target_ctx.paint()<EOL>return target_ctx<EOL><DEDENT>def output_file(ctx):<EOL><INDENT>root, extension = os.path.splitext(target)<EOL>if file_number:<EOL><INDENT>filename = '<STR_LIT>' % (root, file_number, extension)<EOL><DEDENT>else:<EOL><INDENT>filename = target<EOL><DEDENT>extension = extension.lower()<EOL>if extension == '<STR_LIT>':<EOL><INDENT>surface = ctx.get_target()<EOL>surface.write_to_png(target)<EOL><DEDENT>elif extension == '<STR_LIT>':<EOL><INDENT>target_ctx = cairo.Context(cairo.PDFSurface(filename, *self.size_or_default()))<EOL>target_ctx.set_source_surface(ctx.get_target())<EOL>target_ctx.paint()<EOL><DEDENT>elif extension in ('<STR_LIT>', '<STR_LIT>'):<EOL><INDENT>target_ctx = cairo.Context(cairo.PSSurface(filename, *self.size_or_default()))<EOL>if extension == '<STR_LIT>':<EOL><INDENT>target_ctx.set_eps(extension='<STR_LIT>')<EOL><DEDENT>target_ctx.set_source_surface(ctx.get_target())<EOL>target_ctx.paint()<EOL><DEDENT>elif extension == '<STR_LIT>':<EOL><INDENT>target_ctx = cairo.Context(cairo.SVGSurface(filename, *self.size_or_default()))<EOL>target_ctx.set_source_surface(ctx.get_target())<EOL>target_ctx.paint()<EOL><DEDENT>return filename<EOL><DEDENT>if isinstance(target, cairo.Context):<EOL><INDENT>return output_context<EOL><DEDENT>elif isinstance(target, cairo.Surface):<EOL><INDENT>return output_surface<EOL><DEDENT>else:<EOL><INDENT>return output_file<EOL><DEDENT>

Function to output to a cairo surface

target is a cairo Context or filename
if file_number is set, then files will be numbered
(this is usually set to the current frame number)


<EOL>cairo_ctx.set_source_rgba(*self.background)<EOL>cairo_ctx.paint()<EOL>


raise NotImplementedError('<STR_LIT>')<EOL>

In implementations of drawqueue that use buffering
this will run the whole queue up to this point


self.render_funcs.append(render_func)<EOL>


for render_func in self.render_funcs:<EOL><INDENT>render_func(r_context)<EOL><DEDENT>return r_context<EOL>

Call all the render functions with r_context

r_context, is the render_context - Set of
keyword args that should make sense to the
canvas implementation


self.bot = bot<EOL>self.sink.set_bot(bot)<EOL>


return None<EOL>

Overrides can return actual input device


return DrawQueue()<EOL>

Override to create use special kinds of draw queue


pass<EOL>

Must be overriden to create initial transform matrix


for k, v in kwargs.items():<EOL><INDENT>setattr(self, k, v)<EOL><DEDENT>


if not self.size:<EOL><INDENT>self.size = self.DEFAULT_SIZE<EOL><DEDENT>return self.size<EOL>

If size is not set, otherwise set size to DEFAULT_SIZE
and return it.

This means, only the first call to size() is valid.


if self.size is None:<EOL><INDENT>self.size = size<EOL>return size<EOL><DEDENT>else:<EOL><INDENT>return self.size<EOL><DEDENT>

Size is only set the first time it is called

Size that is set is returned


def snapshot(self, target, defer=True, file_number=None):

output_func = self.output_closure(target, file_number)<EOL>if defer:<EOL><INDENT>self._drawqueue.append(output_func)<EOL><DEDENT>else:<EOL><INDENT>self._drawqueue.append_immediate(output_func)<EOL><DEDENT>

Ask the drawqueue to output to target.

target can be anything supported by the combination
of canvas implementation and drawqueue implmentation.

If target is not supported then an exception is thrown.


self.sink.render(self.size_or_default(), frame, self._drawqueue)<EOL>self.reset_drawqueue()<EOL>

Passes the drawqueue to the sink for rendering


self._drawqueue.append(render_func)<EOL>

Add a render function to the queue for rendering later


def render(self, size, frame, drawqueue):

r_context = self.create_rcontext(size, frame)<EOL>drawqueue.render(r_context)<EOL>self.rendering_finished(size, frame, r_context)<EOL>return r_context<EOL>

Calls implmentation to get a render context,
passes it to the drawqueues render function
then calls self.rendering_finished


pass<EOL>

Returns a cairo context for drawing this
frame of the bot


pass<EOL>

Called from main loop, if your sink needs to handle GUI events
do it here.

:return:


try:<EOL><INDENT>return channel.listen(block=block, timeout=timeout).next()['<STR_LIT:data>']<EOL><DEDENT>except StopIteration:<EOL><INDENT>return None<EOL><DEDENT>

Get the next available event or None

:param block:
:param timeout:
:return: None or (event, data)


return event is not None and event.type == event_t<EOL>

Check if event type
:param event:   event to compare
:param event_t: event type
:return: bool


def publish_event(event_t, data=None, extra_channels=None, wait=None):

event = Event(event_t, data)<EOL>pubsub.publish("<STR_LIT>", event)<EOL>for channel_name in extra_channels or []:<EOL><INDENT>pubsub.publish(channel_name, event)<EOL><DEDENT>if wait is not None:<EOL><INDENT>channel = pubsub.subscribe(wait)<EOL>channel.listen(wait)<EOL><DEDENT>

Publish an event ot any subscribers.

:param event_t:  event type
:param data:     event data
:param extra_channels:
:param wait:
:return:


if not prefer:<EOL><INDENT>return options<EOL><DEDENT>return sorted(options, key=lambda x: (prefer + options).index(x))<EOL>

:param options: List of options
:param prefer: Prefered options
:return:

Pass in a list of options, return options in 'prefer' first

>>> sort_by_preference(["cairo", "cairocffi"], ["cairocffi"])
["cairocffi", "cairo"]


options = os.environ.get("<STR_LIT>")<EOL>if not options:<EOL><INDENT>return {}<EOL><DEDENT>try:<EOL><INDENT>return dict([kv.split('<STR_LIT:=>') for kv in options.split()])<EOL><DEDENT>except ValueError:<EOL><INDENT>sys.stderr.write("<STR_LIT>")<EOL>sys.stderr.write("<STR_LIT>")<EOL>sys.stderr.write("<STR_LIT>")<EOL>sys.exit(<NUM_LIT:1>)<EOL><DEDENT>


def import_libs(self, module_names, impl_name):

for name in module_names:<EOL><INDENT>try:<EOL><INDENT>module = __import__(name)<EOL>has_module = True<EOL><DEDENT>except ImportError:<EOL><INDENT>module = None<EOL>has_module = False<EOL><DEDENT>setattr(self, name, module)<EOL>setattr(self, '<STR_LIT>' % name, has_module)<EOL><DEDENT>for name in module_names:<EOL><INDENT>try:<EOL><INDENT>return name, __import__(name)<EOL><DEDENT>except ImportError:<EOL><INDENT>pass<EOL><DEDENT><DEDENT>raise ImportError('<STR_LIT>' % (impl_name, '<STR_LIT:U+0020>'.join(module_names)))<EOL>

Loop through module_names,
add has_.... booleans to class
set ..._impl to first successful import

:param module_names:  list of module names to try importing
:param impl_name:  used in error output if no modules succeed
:return: name, module from first successful implementation


if self.cairocffi and isinstance(ctx, self.cairocffi.Context):<EOL><INDENT>from shoebot.util.cairocffi.cairocffi_to_pycairo import _UNSAFE_cairocffi_context_to_pycairo<EOL>return _UNSAFE_cairocffi_context_to_pycairo(ctx)<EOL><DEDENT>else:<EOL><INDENT>return ctx<EOL><DEDENT>

If ctx is a cairocffi Context convert it to a PyCairo Context
otherwise return the original context

:param ctx:
:return:


def create_canvas(src, format=None, outputfile=None, multifile=False, buff=None, window=False, title=None,<EOL>fullscreen=None, show_vars=False):

from core import CairoCanvas, CairoImageSink <EOL>if outputfile:<EOL><INDENT>sink = CairoImageSink(outputfile, format, multifile, buff)<EOL><DEDENT>elif window or show_vars:<EOL><INDENT>from gui import ShoebotWindow<EOL>if not title:<EOL><INDENT>if src and os.path.isfile(src):<EOL><INDENT>title = os.path.splitext(os.path.basename(src))[<NUM_LIT:0>] + '<STR_LIT>'<EOL><DEDENT>else:<EOL><INDENT>title = '<STR_LIT>'<EOL><DEDENT><DEDENT>sink = ShoebotWindow(title, show_vars, fullscreen=fullscreen)<EOL><DEDENT>else:<EOL><INDENT>if src and isinstance(src, cairo.Surface):<EOL><INDENT>outputfile = src<EOL>format = '<STR_LIT>'<EOL><DEDENT>elif src and os.path.isfile(src):<EOL><INDENT>outputfile = os.path.splitext(os.path.basename(src))[<NUM_LIT:0>] + '<STR_LIT:.>' + (format or '<STR_LIT>')<EOL><DEDENT>else:<EOL><INDENT>outputfile = '<STR_LIT>'<EOL><DEDENT>sink = CairoImageSink(outputfile, format, multifile, buff)<EOL><DEDENT>canvas = CairoCanvas(sink)<EOL>return canvas<EOL>

Create canvas and sink for attachment to a bot

canvas is what draws images, 'sink' is the final consumer of the images

:param src: Defaults for title or outputfile if not specified.

:param format: CairoImageSink image format, if using buff instead of outputfile
:param buff: CairoImageSink buffer object to send output to

:param outputfile: CairoImageSink output filename e.g. "hello.svg"
:param multifile: CairoImageSink if True,

:param title: ShoebotWindow - set window title
:param fullscreen: ShoebotWindow - set window title
:param show_vars: ShoebotWindow - display variable window

Two kinds of sink are provided: CairoImageSink and ShoebotWindow

ShoebotWindow

Displays a window to draw shoebot inside.

CairoImageSink

Output to a filename (or files if multifile is set), or a buffer object.


def create_bot(src=None, grammar=NODEBOX, format=None, outputfile=None, iterations=<NUM_LIT:1>, buff=None, window=False,<EOL>title=None, fullscreen=None, server=False, port=<NUM_LIT>, show_vars=False, vars=None, namespace=None):

canvas = create_canvas(src, format, outputfile, iterations > <NUM_LIT:1>, buff, window, title, fullscreen=fullscreen,<EOL>show_vars=show_vars)<EOL>if grammar == DRAWBOT:<EOL><INDENT>from shoebot.grammar import DrawBot<EOL>bot = DrawBot(canvas, namespace=namespace, vars=vars)<EOL><DEDENT>else:<EOL><INDENT>from shoebot.grammar import NodeBot<EOL>bot = NodeBot(canvas, namespace=namespace, vars=vars)<EOL><DEDENT>if server:<EOL><INDENT>from shoebot.sbio import SocketServer<EOL>socket_server = SocketServer(bot, "<STR_LIT>", port=port)<EOL><DEDENT>return bot<EOL>

Create a canvas and a bot with the same canvas attached to it

bot parameters
:param grammar: DRAWBOT or NODEBOX - decides what kind of bot is created
:param vars: preset dictionary of vars from the called

canvas parameters:
... everything else ...

See create_canvas for details on those parameters.


<EOL>sys.argv = [sys.argv[<EOL><NUM_LIT:0>]] + args  <EOL>create_args = [src,<EOL>grammar,<EOL>format,<EOL>outputfile,<EOL>iterations,<EOL>buff,<EOL>window,<EOL>title,<EOL>fullscreen,<EOL>server,<EOL>port,<EOL>show_vars]<EOL>create_kwargs = dict(vars=vars, namespace=namespace)<EOL>run_args = [src]<EOL>run_kwargs = dict(<EOL>iterations=iterations,<EOL>frame_limiter=window,<EOL>verbose=verbose,<EOL>run_forever=window and not (close_window or bool(outputfile)),<EOL>)<EOL>if background_thread:<EOL><INDENT>sbot_thread = ShoebotThread(<EOL>create_args=create_args,<EOL>create_kwargs=create_kwargs,<EOL>run_args=run_args,<EOL>run_kwargs=run_kwargs,<EOL>send_sigint=run_shell<EOL>)<EOL>sbot_thread.start()<EOL>sbot = sbot_thread.sbot<EOL><DEDENT>else:<EOL><INDENT>print('<STR_LIT>')<EOL>if run_shell:<EOL><INDENT>raise ValueError('<STR_LIT>')<EOL><DEDENT>sbot_thread = None<EOL>sbot = create_bot(*create_args, **create_kwargs)<EOL>sbot.run(*run_args, **run_kwargs)<EOL><DEDENT>if run_shell:<EOL><INDENT>import shoebot.sbio.shell<EOL>shell = shoebot.sbio.shell.ShoebotCmd(sbot, trusted=True)<EOL>try:<EOL><INDENT>shell.cmdloop()<EOL><DEDENT>except KeyboardInterrupt as e:<EOL><INDENT>publish_event(QUIT_EVENT)  <EOL>if verbose:<EOL><INDENT>raise<EOL><DEDENT>else:<EOL><INDENT>return<EOL><DEDENT><DEDENT><DEDENT>elif background_thread:<EOL><INDENT>try:<EOL><INDENT>while sbot_thread.is_alive():<EOL><INDENT>sleep(<NUM_LIT:1>)<EOL><DEDENT><DEDENT>except KeyboardInterrupt:<EOL><INDENT>publish_event(QUIT_EVENT)<EOL><DEDENT><DEDENT>if all((background_thread, sbot_thread)):<EOL><INDENT>sbot_thread.join()<EOL><DEDENT>return sbot<EOL>

Create and run a bot, the arguments all correspond to sanitized
commandline options.

:param background_thread: If True then use a background thread.

Other args are split into create_args and run_args

See create_bot for details on create_args

run_args are passed to bot.run - see Nodebot.run or Drawbot.run

Background thread:

readline in python is blocking, running the app in a background
thread opens up the main thread for IO on stdin/stdout, which
can be used for communication with shoebot when livecoding is
enabled.

See shoebot.io for implementation of the shell, and the gedit
plugin for an example of using livecoding.


def __init__(self, create_args, create_kwargs,<EOL>run_args, run_kwargs,<EOL>send_sigint=False):

super(ShoebotThread, self).__init__()<EOL>self.bot_ready = threading.Event()<EOL>self.create_args = create_args<EOL>self.create_kwargs = create_kwargs<EOL>self.run_args = run_args<EOL>self.run_kwargs = run_kwargs<EOL>self.send_sigint = send_sigint<EOL>self._sbot = None<EOL>

:param create_args: passed to create_bot
:param create_kwargs: passed to create_bot
:param run_args: passed to bot.run
:param run_kwargs: passed to bot.run
:param send_sigint: if True then SIGINT will be sent on bot completion
                    so the main thread can terminate


self.bot_ready.wait()<EOL>return self._sbot<EOL>


global parser<EOL>print (_("<STR_LIT>") + message)<EOL>print ()<EOL>parser.print_help()<EOL>sys.exit()<EOL>

Prints an error message, the help message and quits


print (_("<STR_LIT>") + message)<EOL>


def decorator(f):<EOL><INDENT>def run():<EOL><INDENT>from shoebot import ShoebotInstallError  <EOL>print("<STR_LIT>" % f.__name__.replace("<STR_LIT:_>", "<STR_LIT:U+0020>"))<EOL>try:<EOL><INDENT>import shoebot<EOL>outputfile = "<STR_LIT>" % f.__name__<EOL>bot = shoebot.create_bot(outputfile=outputfile)<EOL>f(bot)<EOL>bot.finish()<EOL>print('<STR_LIT>' % outputfile)<EOL>print('<STR_LIT>')<EOL><DEDENT>except ShoebotInstallError as e:<EOL><INDENT>print('<STR_LIT>', e.args[<NUM_LIT:0>])<EOL>print('<STR_LIT>')<EOL><DEDENT>except Exception:<EOL><INDENT>print('<STR_LIT>')<EOL>for line in traceback.format_exc().splitlines():<EOL><INDENT>print('<STR_LIT>' % line)<EOL><DEDENT>print('<STR_LIT>')<EOL><DEDENT><DEDENT>return run<EOL><DEDENT>return decorator<EOL>

Decorator to run some code in a bot instance.


kdict = {}<EOL>for gdk_name in dir(Gdk):<EOL><INDENT>nb_name = gdk_name.upper()<EOL>kdict[nb_name] = getattr(Gdk, gdk_name)<EOL><DEDENT>return kdict<EOL>

Return a dict in the form of

SHOEBOT_KEY_NAME, GTK_VALUE

Shoebot key names look like KEY_LEFT, whereas Gdk uses KEY_Left
- Shoebot key names are derived from Nodebox 1, which was a mac
  app.


bot_width, bot_height = self.bot_size<EOL>if self.width != bot_width or self.height != bot_height:<EOL><INDENT>if self.width < self.height:<EOL><INDENT>scale_x = float(self.width) / float(bot_width)<EOL>scale_y = scale_x<EOL>cr.translate(<NUM_LIT:0>, (self.height - (bot_height * scale_y)) / <NUM_LIT>)<EOL><DEDENT>elif self.width > self.height:<EOL><INDENT>scale_y = float(self.height) / float(bot_height)<EOL>scale_x = scale_y<EOL>cr.translate((self.width - (bot_width * scale_x)) / <NUM_LIT>, <NUM_LIT:0>)<EOL><DEDENT>else:<EOL><INDENT>scale_x = <NUM_LIT:1.0><EOL>scale_y = <NUM_LIT:1.0><EOL><DEDENT>cr.scale(scale_x, scale_y)<EOL>self.input_device.scale_x = scale_y<EOL>self.input_device.scale_y = scale_y<EOL><DEDENT>

Scale context based on difference between bot size and widget


if self.bot_size is None:<EOL><INDENT>self.draw_default_image(cr)<EOL>return<EOL><DEDENT>cr = driver.ensure_pycairo_context(cr)<EOL>surface = self.backing_store.surface<EOL>cr.set_source_surface(surface)<EOL>cr.paint()<EOL>

Draw just the exposed part of the backing store, scaled to fit


self.frame = frame<EOL>width, height = size<EOL>meta_surface = cairo.RecordingSurface(cairo.CONTENT_COLOR_ALPHA, (<NUM_LIT:0>, <NUM_LIT:0>, width, height))<EOL>ctx = cairo.Context(meta_surface)<EOL>return ctx<EOL>

Creates a recording surface for the bot to draw on

:param size: The width and height of bot


def do_drawing(self, size, frame, cairo_ctx):

if self.get_window() and not self.bot_size:<EOL><INDENT>self.set_size_request(*size)<EOL><DEDENT>self.bot_size = size<EOL>self.backing_store = BackingStore.get_backingstore(self.width, self.height)<EOL>cr = pycairo.Context(self.backing_store.surface)<EOL>if self.scale_fit:<EOL><INDENT>self.scale_context_and_center(cr)<EOL><DEDENT>cairo_ctx = driver.ensure_pycairo_context(cairo_ctx)<EOL>cr.set_source_surface(cairo_ctx.get_target())<EOL>cr.set_operator(cairo.OPERATOR_SOURCE)<EOL>cr.paint()<EOL>self.queue_draw()<EOL>while Gtk.events_pending():<EOL><INDENT>Gtk.main_iteration_do(False)<EOL><DEDENT>

Update the backing store from a cairo context and
schedule a redraw (expose event)

:param size: width, height in pixels of bot
:param frame: frame # thar was drawn
:param cairo_ctx: cairo context the bot was drawn on


def gtk_mouse_button_down(self, widget, event):

if self.menu_enabled and event.button == <NUM_LIT:3>:<EOL><INDENT>menu = self.uimanager.get_widget('<STR_LIT>')<EOL>menu.popup(None, None, None, None, event.button, event.time)<EOL><DEDENT>else:<EOL><INDENT>super(ShoebotWindow, self).gtk_mouse_button_down(widget, event)<EOL><DEDENT>


return self.sb_widget.create_rcontext(size, frame)<EOL>


if self.var_window is None and self.bot._vars:<EOL><INDENT>self.var_window = VarWindow(self, self.bot, '<STR_LIT>' % (self.title or '<STR_LIT>'))<EOL>self.var_window.window.connect("<STR_LIT>", self.var_window_closed)<EOL><DEDENT>


if self.var_window is not None:<EOL><INDENT>self.var_window.window.destroy()<EOL>self.var_window = None<EOL><DEDENT>


<EOL>self.action_group.get_action('<STR_LIT>').set_active(False)<EOL>self.show_vars = False<EOL>self.var_window = None<EOL>

Called if user clicked close button on var window
:param widget:
:return:


bot = self.bot<EOL>canvas = self.bot.canvas<EOL>script = bot._namespace['<STR_LIT>']<EOL>if script:<EOL><INDENT>filename = os.path.splitext(script)[<NUM_LIT:0>] + '<STR_LIT:.>' + format<EOL><DEDENT>else:<EOL><INDENT>filename = '<STR_LIT>' + format<EOL><DEDENT>f = canvas.output_closure(filename, self.bot._frame)<EOL>self.scheduled_snapshots.append(f)<EOL>

Tell the canvas to perform a snapshot when it's finished rendering
:param format:
:return:


self.schedule_snapshot('<STR_LIT>')<EOL>

Save an SVG file after drawing is complete.


Save an Postscript file after drawing is complete.


Save a PDF file after drawing is complete.


Save an PNG file after drawing is complete.


action = self.action_group.get_action('<STR_LIT>')<EOL>action.set_active(fullscreen)<EOL>

Toggle fullscreen from outside the GUI,
causes the GUI to updated and run all its actions.


self.fullscreen()<EOL>self.is_fullscreen = True<EOL>while Gtk.events_pending():<EOL><INDENT>Gtk.main_iteration()<EOL><DEDENT>self.bot._screen_width = Gdk.Screen.width()<EOL>self.bot._screen_height = Gdk.Screen.height()<EOL>self.bot._screen_ratio = self.bot._screen_width / self.bot._screen_height<EOL>

Widget Action to Make the window fullscreen and update the bot.


self.unfullscreen()<EOL>self.is_fullscreen = False<EOL>self.bot._screen_ratio = None<EOL>


def do_window_close(self, widget, data=None):

publish_event(QUIT_EVENT)<EOL>if self.has_server:<EOL><INDENT>self.sock.close()<EOL><DEDENT>self.hide_variables_window()<EOL>self.destroy()<EOL>self.window_open = False<EOL>

Widget Action to Close the window, triggering the quit event.


is_fullscreen = action.get_active()<EOL>if is_fullscreen:<EOL><INDENT>self.fullscreen()<EOL><DEDENT>else:<EOL><INDENT>self.unfullscreen()<EOL><DEDENT>

Widget Action to Toggle fullscreen from the GUI


<EOL>if self.pause_speed is None and not action.get_active():<EOL><INDENT>self.pause_speed = self.bot._speed<EOL>self.bot._speed = <NUM_LIT:0><EOL><DEDENT>else:<EOL><INDENT>self.bot._speed = self.pause_speed<EOL>self.pause_speed = None<EOL><DEDENT>


self.show_vars = action.get_active()<EOL>if self.show_vars:<EOL><INDENT>self.show_variables_window()<EOL><DEDENT>else:<EOL><INDENT>self.hide_variables_window()<EOL><DEDENT>

Widget Action to toggle showing the variables window.


if self.show_vars:<EOL><INDENT>self.show_variables_window()<EOL><DEDENT>else:<EOL><INDENT>self.hide_variables_window()<EOL><DEDENT>for snapshot_f in self.scheduled_snapshots:<EOL><INDENT>fn = snapshot_f(self.last_draw_ctx)<EOL>print("<STR_LIT>" % fn)<EOL><DEDENT>else:<EOL><INDENT>self.scheduled_snapshots = deque()<EOL><DEDENT>while Gtk.events_pending():<EOL><INDENT>Gtk.main_iteration()<EOL><DEDENT>

Called from main loop, if your sink needs to handle GUI events
do it here.

Check any GUI flags then call Gtk.main_iteration to update things.


for k, v in self.bot._vars.items():<EOL><INDENT>if not hasattr(v, '<STR_LIT:type>'):<EOL><INDENT>raise AttributeError(<EOL>'<STR_LIT>' % k)<EOL><DEDENT>self.add_variable(v)<EOL><DEDENT>

Add all widgets to specified vbox
:param container:
:return:


widget = self.widgets.get(name)<EOL>if widget is None:<EOL><INDENT>return False, '<STR_LIT>'.format(name)<EOL><DEDENT>try:<EOL><INDENT>if isinstance(widget, Gtk.CheckButton):<EOL><INDENT>widget.set_active(value)<EOL>return True, widget.get_active()<EOL><DEDENT>elif isinstance(widget, Gtk.Entry):<EOL><INDENT>widget.set_text(value)<EOL>return True, widget.get_text()<EOL><DEDENT>else:<EOL><INDENT>widget.set_value(value)<EOL>return True, widget.get_value()<EOL><DEDENT><DEDENT>except Exception as e:<EOL><INDENT>return False, str(e)<EOL><DEDENT>


<EOL>if v.type is NUMBER:<EOL><INDENT>self.bot._namespace[v.name] = widget.get_value()<EOL>self.bot._vars[v.name].value = widget.get_value()  <EOL>publish_event(VARIABLE_UPDATED_EVENT, v)  <EOL><DEDENT>elif v.type is BOOLEAN:<EOL><INDENT>self.bot._namespace[v.name] = widget.get_active()<EOL>self.bot._vars[v.name].value = widget.get_active()  <EOL>publish_event(VARIABLE_UPDATED_EVENT, v)  <EOL><DEDENT>elif v.type is TEXT:<EOL><INDENT>self.bot._namespace[v.name] = widget.get_text()<EOL>self.bot._vars[v.name].value = widget.get_text()  <EOL>publish_event(VARIABLE_UPDATED_EVENT, v)<EOL><DEDENT>


self.add_variable(v)<EOL>self.window.set_size_request(<NUM_LIT>, <NUM_LIT> * len(self.widgets.keys()))<EOL>self.window.show_all()<EOL>

var was added in the bot while it ran, possibly
by livecoding

:param v:
:return:


widget = self.widgets[v.name]<EOL>parent = widget.get_parent()<EOL>self.container.remove(parent)<EOL>del self.widgets[v.name]<EOL>self.window.set_size_request(<NUM_LIT>, <NUM_LIT> * len(self.widgets.keys()))<EOL>self.window.show_all()<EOL>

var was added in the bot

:param v:
:return:


chooser = ShoebotFileChooserDialog(_('<STR_LIT>'), None, Gtk.FileChooserAction.SAVE,<EOL>(Gtk.STOCK_SAVE, Gtk.ResponseType.ACCEPT,<EOL>Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL))<EOL>chooser.set_do_overwrite_confirmation(True)<EOL>chooser.set_transient_for(self)<EOL>saved = chooser.run() == Gtk.ResponseType.ACCEPT<EOL>if saved:<EOL><INDENT>old_filename = self.filename<EOL>self.source_buffer.filename = chooser.get_filename()<EOL>if not self.save():<EOL><INDENT>self.filename = old_filename<EOL><DEDENT><DEDENT>chooser.destroy()<EOL>return saved<EOL>


<EOL>try:<EOL><INDENT>return PangoCairo.create_context(cr)<EOL><DEDENT>except KeyError as e:<EOL><INDENT>if e.args == ('<STR_LIT>',):<EOL><INDENT>raise ShoebotInstallError("<STR_LIT>")<EOL><DEDENT>else:<EOL><INDENT>raise<EOL><DEDENT><DEDENT>

If python-gi-cairo is not installed, using PangoCairo.create_context
dies with an unhelpful KeyError, check for that and output somethig
useful.


w, h = self.layout.get_pixel_size()<EOL>x = (self.x + w / <NUM_LIT:2>)<EOL>y = (self.y + h / <NUM_LIT:2>)<EOL>return x, y<EOL>

Returns the center point of the path, disregarding transforms.


if mode == CENTER:<EOL><INDENT>self._call_transform_mode = self._center_transform<EOL><DEDENT>elif mode == CORNER:<EOL><INDENT>self._call_transform_mode = self._corner_transform<EOL><DEDENT>else:<EOL><INDENT>raise ValueError('<STR_LIT>')<EOL><DEDENT>

Sets call_transform_mode to point to the
center_transform or corner_transform


if self._pathmode is not None:<EOL><INDENT>return self._pathmode<EOL><DEDENT>else:<EOL><INDENT>return self._canvas.pathmode<EOL><DEDENT>

Return pathmode or get it from self._canvas


raise NotImplementedError()<EOL>

Implementations must return the x, y of their center


raise NotImplementedError('<STR_LIT>')<EOL>

This should never get called:
set mode, changes the value of this to point

corner_transform or center_transform


dx, dy = self._get_center()<EOL>t = cairo.Matrix()<EOL>t.translate(dx, dy)<EOL>t = transform * t<EOL>t.translate(-dx, -dy)<EOL>return t<EOL>

Works like setupTransform of a version of java nodebox
http://dev.nodebox.net/browser/nodebox-java/branches/rewrite/src/java/net/nodebox/graphics/Grob.java


return transform<EOL>

CORNER is the default, so we just return the transform


self._canvas.deferred_render(render_func or self._render)<EOL>

Pass a function to the canvas for deferred rendering,
defaults to self._render


raise NotImplementedError()<EOL>


for canvas_attr, grob_attr in STATES.items():<EOL><INDENT>if canvas_attr in ignore:<EOL><INDENT>continue<EOL><DEDENT>setattr(self, grob_attr, getattr(self._bot._canvas, canvas_attr))<EOL><DEDENT>

Doesn't store exactly the same items as Nodebox for ease of implementation,
it has enough to get the Nodebox Dentrite example working.


<EOL>while isinstance(v, (tuple, list)) and len(v) == <NUM_LIT:1>:<EOL><INDENT>v = v[<NUM_LIT:0>]<EOL><DEDENT>if isinstance(v, (int, float)):<EOL><INDENT>red = green = blue = v / color_range<EOL>alpha = <NUM_LIT:1.><EOL><DEDENT>elif isinstance(v, data.Color):<EOL><INDENT>red, green, blue, alpha = v<EOL><DEDENT>elif isinstance(v, (tuple, list)):<EOL><INDENT>color = []<EOL>for index in range(<NUM_LIT:0>, len(v)):<EOL><INDENT>color.append(v[index] / color_range)<EOL><DEDENT>if len(color) == <NUM_LIT:1>:<EOL><INDENT>red = green = blue = alpha = color[<NUM_LIT:0>]<EOL><DEDENT>elif len(color) == <NUM_LIT:2>:<EOL><INDENT>red = green = blue = color[<NUM_LIT:0>]<EOL>alpha = color[<NUM_LIT:1>]<EOL><DEDENT>elif len(color) == <NUM_LIT:3>:<EOL><INDENT>red = color[<NUM_LIT:0>]<EOL>green = color[<NUM_LIT:1>]<EOL>blue = color[<NUM_LIT:2>]<EOL>alpha = <NUM_LIT:1.><EOL><DEDENT>elif len(color) == <NUM_LIT:4>:<EOL><INDENT>red = color[<NUM_LIT:0>]<EOL>green = color[<NUM_LIT:1>]<EOL>blue = color[<NUM_LIT:2>]<EOL>alpha = color[<NUM_LIT:3>]<EOL><DEDENT><DEDENT>elif isinstance(v, str):<EOL><INDENT>v = v.strip('<STR_LIT:#>')<EOL>if len(data) == <NUM_LIT:6>:<EOL><INDENT>red = hex2dec(v[<NUM_LIT:0>:<NUM_LIT:2>]) / <NUM_LIT><EOL>green = hex2dec(v[<NUM_LIT:2>:<NUM_LIT:4>]) / <NUM_LIT><EOL>blue = hex2dec(v[<NUM_LIT:4>:<NUM_LIT:6>]) / <NUM_LIT><EOL>alpha = <NUM_LIT:1.><EOL><DEDENT>elif len(v) == <NUM_LIT:8>:<EOL><INDENT>red = hex2dec(v[<NUM_LIT:0>:<NUM_LIT:2>]) / <NUM_LIT><EOL>green = hex2dec(v[<NUM_LIT:2>:<NUM_LIT:4>]) / <NUM_LIT><EOL>blue = hex2dec(v[<NUM_LIT:4>:<NUM_LIT:6>]) / <NUM_LIT><EOL>alpha = hex2dec(v[<NUM_LIT:6>:<NUM_LIT:8>]) / <NUM_LIT><EOL><DEDENT><DEDENT>return red, green, blue, alpha<EOL>

Receives a colour definition and returns a (r,g,b,a) tuple.

    Accepts:
    - v
    - (v)
    - (v,a)
    - (r,g,b)
    - (r,g,b,a)
    - #RRGGBB
    - RRGGBB
    - #RRGGBBAA
    - RRGGBBAA

    Returns a (red, green, blue, alpha) tuple, with values ranging from
    0 to 1.

    The 'color_range' parameter sets the colour range in which the
    colour data values are specified (except in hexstrings).


hex = hex.lstrip("<STR_LIT:#>")<EOL>if len(hex) < <NUM_LIT:6>:<EOL><INDENT>hex += hex[-<NUM_LIT:1>] * (<NUM_LIT:6> - len(hex))<EOL><DEDENT>if len(hex) == <NUM_LIT:6>:<EOL><INDENT>r, g, b = hex[<NUM_LIT:0>:<NUM_LIT:2>], hex[<NUM_LIT:2>:<NUM_LIT:4>], hex[<NUM_LIT:4>:]<EOL>r, g, b = [int(n, <NUM_LIT:16>) / <NUM_LIT> for n in (r, g, b)]<EOL>a = <NUM_LIT:1.0><EOL><DEDENT>elif len(hex) == <NUM_LIT:8>:<EOL><INDENT>r, g, b, a = hex[<NUM_LIT:0>:<NUM_LIT:2>], hex[<NUM_LIT:2>:<NUM_LIT:4>], hex[<NUM_LIT:4>:<NUM_LIT:6>], hex[<NUM_LIT:6>:]<EOL>r, g, b, a = [int(n, <NUM_LIT:16>) / <NUM_LIT> for n in (r, g, b, a)]<EOL><DEDENT>return r, g, b, a<EOL>

Returns RGB values for a hex color string.


y = (l + <NUM_LIT:16>) / <NUM_LIT><EOL>x = a / <NUM_LIT> + y<EOL>z = y - b / <NUM_LIT><EOL>v = [x, y, z]<EOL>for i in _range(<NUM_LIT:3>):<EOL><INDENT>if pow(v[i], <NUM_LIT:3>) > <NUM_LIT>:<EOL><INDENT>v[i] = pow(v[i], <NUM_LIT:3>)<EOL><DEDENT>else:<EOL><INDENT>v[i] = (v[i] - <NUM_LIT:16> / <NUM_LIT>) / <NUM_LIT><EOL><DEDENT><DEDENT>x = v[<NUM_LIT:0>] * <NUM_LIT> / <NUM_LIT:100><EOL>y = v[<NUM_LIT:1>] * <NUM_LIT> / <NUM_LIT:100><EOL>z = v[<NUM_LIT:2>] * <NUM_LIT> / <NUM_LIT:100><EOL>r = x * <NUM_LIT> + y * -<NUM_LIT> + z * -<NUM_LIT><EOL>g = x * -<NUM_LIT> + y * <NUM_LIT> + z * <NUM_LIT><EOL>b = x * <NUM_LIT> + y * -<NUM_LIT> + z * <NUM_LIT><EOL>v = [r, g, b]<EOL>for i in _range(<NUM_LIT:3>):<EOL><INDENT>if v[i] > <NUM_LIT>:<EOL><INDENT>v[i] = <NUM_LIT> * pow(v[i], <NUM_LIT:1> / <NUM_LIT>) - <NUM_LIT><EOL><DEDENT>else:<EOL><INDENT>v[i] = <NUM_LIT> * v[i]<EOL><DEDENT><DEDENT>r, g, b = v[<NUM_LIT:0>], v[<NUM_LIT:1>], v[<NUM_LIT:2>]<EOL>return r, g, b<EOL>

Converts CIE Lab to RGB components.

    First we have to convert to XYZ color space.
    Conversion involves using a white point,
    in this case D65 which represents daylight illumination.

    Algorithm adopted from:
    http://www.easyrgb.com/math.php


r = <NUM_LIT:1.0> - min(<NUM_LIT:1.0>, c + k)<EOL>g = <NUM_LIT:1.0> - min(<NUM_LIT:1.0>, m + k)<EOL>b = <NUM_LIT:1.0> - min(<NUM_LIT:1.0>, y + k)<EOL>return r, g, b<EOL>

Cyan, magenta, yellow, black to red, green, blue.
    ReportLab, http://www.koders.com/python/fid5C006F554616848C01AC7CB96C21426B69D2E5A9.aspx
    Results will differ from the way NSColor converts color spaces.


if s == <NUM_LIT:0>: return v, v, v<EOL>h = h / (<NUM_LIT> / <NUM_LIT>)<EOL>i = floor(h)<EOL>f = h - i<EOL>p = v * (<NUM_LIT:1> - s)<EOL>q = v * (<NUM_LIT:1> - s * f)<EOL>t = v * (<NUM_LIT:1> - s * (<NUM_LIT:1> - f))<EOL>if i == <NUM_LIT:0>:<EOL><INDENT>r, g, b = v, t, p<EOL><DEDENT>elif i == <NUM_LIT:1>:<EOL><INDENT>r, g, b = q, v, p<EOL><DEDENT>elif i == <NUM_LIT:2>:<EOL><INDENT>r, g, b = p, v, t<EOL><DEDENT>elif i == <NUM_LIT:3>:<EOL><INDENT>r, g, b = p, q, v<EOL><DEDENT>elif i == <NUM_LIT:4>:<EOL><INDENT>r, g, b = t, p, v<EOL><DEDENT>else:<EOL><INDENT>r, g, b = v, p, q<EOL><DEDENT>return r, g, b<EOL>

Hue, saturation, brightness to red, green, blue.
    http://www.koders.com/python/fidB2FE963F658FE74D9BF74EB93EFD44DCAE45E10E.aspx
    Results will differ from the way NSColor converts color spaces.


if a in self.__dict__:<EOL><INDENT>return a<EOL><DEDENT>elif a == "<STR_LIT>":<EOL><INDENT>return self.__dict__["<STR_LIT>"]<EOL><DEDENT>elif a == "<STR_LIT>":<EOL><INDENT>return self.__dict__["<STR_LIT>"]<EOL><DEDENT>elif a in ["<STR_LIT:a>", "<STR_LIT>",<EOL>"<STR_LIT:r>", "<STR_LIT:g>", "<STR_LIT:b>", "<STR_LIT>", "<STR_LIT>", "<STR_LIT>",<EOL>"<STR_LIT:h>", "<STR_LIT:s>", "<STR_LIT>", "<STR_LIT>",<EOL>"<STR_LIT:c>", "<STR_LIT:m>", "<STR_LIT:y>", "<STR_LIT:k>", "<STR_LIT>", "<STR_LIT>", "<STR_LIT>"]:<EOL><INDENT>return self.__dict__["<STR_LIT>" + a[<NUM_LIT:0>]]<EOL><DEDENT>elif a in ["<STR_LIT:a>", "<STR_LIT>",<EOL>"<STR_LIT:r>", "<STR_LIT:g>", "<STR_LIT:b>", "<STR_LIT>", "<STR_LIT>", "<STR_LIT>",<EOL>"<STR_LIT:h>", "<STR_LIT:s>", "<STR_LIT>", "<STR_LIT>"]:<EOL><INDENT>return self.__dict__["<STR_LIT>" + a[<NUM_LIT:0>]]<EOL><DEDENT>raise AttributeError("<STR_LIT:'>" + str(self.__class__) + "<STR_LIT>" + a + "<STR_LIT:'>")<EOL>

Available properties:
        r, g, b, a or red, green, blue, alpha
        c, m, y, k or cyan, magenta, yellow, black,
        h, s or hue, saturation, brightness


return degrees(atan2(y1-y0, x1-x0))<EOL>


return sqrt(pow(x1-x0, <NUM_LIT:2>) + pow(y1-y0, <NUM_LIT:2>))<EOL>

Returns the distance between two points.


def coordinates(x0, y0, distance, angle):

return (x0 + cos(radians(angle)) * distance,<EOL>y0 + sin(radians(angle)) * distance)<EOL>

Returns the location of a point by rotating around origin (x0,y0).


x, y = x - x0, y - y0<EOL>a, b = cos(radians(angle)), sin(radians(angle))<EOL>return (x * a - y * b + x0,<EOL>y * a + x * b + y0)<EOL>

Returns the coordinates of (x,y) rotated around origin (x0,y0).


def reflect(x, y, x0, y0, d=<NUM_LIT:1.0>, a=<NUM_LIT>):

return coordinates(x0, y0, d * distance(x0, y0, x, y),<EOL>a + angle(x0, y0, x, y))<EOL>

Returns the reflection of a point through origin (x0,y0).


if t < <NUM_LIT:0.0>:<EOL><INDENT>return a<EOL><DEDENT>if t > <NUM_LIT:1.0>:<EOL><INDENT>return b<EOL><DEDENT>return a + (b - a) * t<EOL>

Returns the linear interpolation between a and b for time t between 0.0-1.0.
        For example: lerp(100, 200, 0.5) => 150.


if x < a:<EOL><INDENT>return <NUM_LIT:0.0><EOL><DEDENT>if x >= b:<EOL><INDENT>return <NUM_LIT:1.0><EOL><DEDENT>x = float(x - a) / (b - a)<EOL>return x * x * (<NUM_LIT:3> - <NUM_LIT:2> * x)<EOL>

Returns a smooth transition between 0.0 and 1.0 using Hermite interpolation (cubic spline),
        where x is a number between a and b. The return value will ease (slow down) as x nears a or b.
        For x smaller than a, returns 0.0. For x bigger than b, returns 1.0.


def line_line_intersection(x1, y1, x2, y2, x3, y3, x4, y4, infinite=False):

<EOL>ua = (x4 - x3) * (y1 - y3) - (y4 - y3) * (x1 - x3)<EOL>ub = (x2 - x1) * (y1 - y3) - (y2 - y1) * (x1 - x3)<EOL>d = (y4 - y3) * (x2 - x1) - (x4 - x3) * (y2 - y1)<EOL>if d == <NUM_LIT:0>:<EOL><INDENT>if ua == ub == <NUM_LIT:0>:<EOL><INDENT>return []<EOL><DEDENT>else:<EOL><INDENT>return []<EOL><DEDENT><DEDENT>ua /= float(d)<EOL>ub /= float(d)<EOL>if not infinite and not (<NUM_LIT:0> <= ua <= <NUM_LIT:1> and <NUM_LIT:0> <= ub <= <NUM_LIT:1>):<EOL><INDENT>return None, None<EOL><DEDENT>return [(x1 + ua * (x2 - x1),<EOL>y1 + ua * (y2 - y1))]<EOL>

Determines the intersection point of two lines, or two finite line segments if infinite=False.
        When the lines do not intersect, returns an empty list.


def circle_line_intersection(cx, cy, radius, x1, y1, x2, y2, infinite=False):

<EOL>dx = x2 - x1<EOL>dy = y2 - y1<EOL>A = dx * dx + dy * dy<EOL>B = <NUM_LIT:2> * (dx * (x1 - cx) + dy * (y1 - cy))<EOL>C = pow(x1 - cx, <NUM_LIT:2>) + pow(y1 - cy, <NUM_LIT:2>) - radius * radius<EOL>det = B * B - <NUM_LIT:4> * A * C<EOL>if A <= <NUM_LIT> or det < <NUM_LIT:0>:<EOL><INDENT>return []<EOL><DEDENT>elif det == <NUM_LIT:0>:<EOL><INDENT>t = -B / (<NUM_LIT:2> * A)<EOL>return [(x1 + t * dx, y1 + t * dy)]<EOL><DEDENT>else:<EOL><INDENT>points = []<EOL>det2 = sqrt(det)<EOL>t1 = (-B + det2) / (<NUM_LIT:2> * A)<EOL>t2 = (-B - det2) / (<NUM_LIT:2> * A)<EOL>if infinite or <NUM_LIT:0> <= t1 <= <NUM_LIT:1>:<EOL><INDENT>points.append((x1 + t1 * dx, y1 + t1 * dy))<EOL><DEDENT>if infinite or <NUM_LIT:0> <= t2 <= <NUM_LIT:1>:<EOL><INDENT>points.append((x1 + t2 * dx, y1 + t2 * dy))<EOL><DEDENT>return points<EOL><DEDENT>

Returns a list of points where the circle and the line intersect.
            Returns an empty list when the circle and the line do not intersect.


odd = False<EOL>n = len(points)<EOL>for i in range(n):<EOL><INDENT>j = i < n - <NUM_LIT:1> and i + <NUM_LIT:1> or <NUM_LIT:0><EOL>x0, y0 = points[i][<NUM_LIT:0>], points[i][<NUM_LIT:1>]<EOL>x1, y1 = points[j][<NUM_LIT:0>], points[j][<NUM_LIT:1>]<EOL>if (y0 < y and y1 >= y) or (y1 < y and y0 >= y):<EOL><INDENT>if x0 + (y - y0) / (y1 - y0) * (x1 - x0) < x:<EOL><INDENT>odd = not odd<EOL><DEDENT><DEDENT><DEDENT>return odd<EOL>

Ray casting algorithm.
        Determines how many times a horizontal ray starting from the point
        intersects with the sides of the polygon.
        If it is an even number of times, the point is outside, if odd, inside.
        The algorithm does not always report correctly when the point is very close to the boundary.
        The polygon is passed as a list of (x,y)-tuples.


if isinstance(transform, AffineTransform):<EOL><INDENT>self.matrix = list(transform.matrix)<EOL><DEDENT>else:<EOL><INDENT>self.matrix = self.identity<EOL><DEDENT>

A geometric transformation in Euclidean space (i.e. 2D)
            that preserves collinearity and ratio of distance between points.
            Linear transformations include rotation, translation, scaling, shear.


<EOL>return [<EOL>a[<NUM_LIT:0>] * b[<NUM_LIT:0>] + a[<NUM_LIT:1>] * b[<NUM_LIT:3>],<EOL>a[<NUM_LIT:0>] * b[<NUM_LIT:1>] + a[<NUM_LIT:1>] * b[<NUM_LIT:4>],<EOL><NUM_LIT:0>,<EOL>a[<NUM_LIT:3>] * b[<NUM_LIT:0>] + a[<NUM_LIT:4>] * b[<NUM_LIT:3>],<EOL>a[<NUM_LIT:3>] * b[<NUM_LIT:1>] + a[<NUM_LIT:4>] * b[<NUM_LIT:4>],<EOL><NUM_LIT:0>,<EOL>a[<NUM_LIT:6>] * b[<NUM_LIT:0>] + a[<NUM_LIT:7>] * b[<NUM_LIT:3>] + b[<NUM_LIT:6>],<EOL>a[<NUM_LIT:6>] * b[<NUM_LIT:1>] + a[<NUM_LIT:7>] * b[<NUM_LIT:4>] + b[<NUM_LIT:7>],<EOL><NUM_LIT:1><EOL>]<EOL>

Returns the 3x3 matrix multiplication of A and B.
            Note that scale(), translate(), rotate() work with premultiplication,
            e.g. the matrix A followed by B = BA and not AB.


m = self.matrix<EOL>d = m[<NUM_LIT:0>] * m[<NUM_LIT:4>] - m[<NUM_LIT:1>] * m[<NUM_LIT:3>]<EOL>self.matrix = [<EOL>m[<NUM_LIT:4>] / d, -m[<NUM_LIT:1>] / d, <NUM_LIT:0>,<EOL>-m[<NUM_LIT:3>] / d,  m[<NUM_LIT:0>] / d, <NUM_LIT:0>,<EOL>(m[<NUM_LIT:3>] * m[<NUM_LIT:7>] - m[<NUM_LIT:4>] * m[<NUM_LIT:6>]) / d,<EOL>-(m[<NUM_LIT:0>] * m[<NUM_LIT:7>] - m[<NUM_LIT:1>] * m[<NUM_LIT:6>]) / d,<EOL><NUM_LIT:1><EOL>]<EOL>

Multiplying a matrix by its inverse produces the identity matrix.


m = self.matrix<EOL>return (x*m[<NUM_LIT:0>]+y*m[<NUM_LIT:3>]+m[<NUM_LIT:6>], x*m[<NUM_LIT:1>]+y*m[<NUM_LIT:4>]+m[<NUM_LIT:7>])<EOL>

Returns the new coordinates of (x,y) after transformation.


p = path.__class__() <EOL>for pt in path:<EOL><INDENT>if pt.cmd == "<STR_LIT>":<EOL><INDENT>p.closepath()<EOL><DEDENT>elif pt.cmd == "<STR_LIT>":<EOL><INDENT>p.moveto(*self.apply(pt.x, pt.y))<EOL><DEDENT>elif pt.cmd == "<STR_LIT>":<EOL><INDENT>p.lineto(*self.apply(pt.x, pt.y))<EOL><DEDENT>elif pt.cmd == "<STR_LIT>":<EOL><INDENT>vx1, vy1 = self.apply(pt.ctrl1.x, pt.ctrl1.y)<EOL>vx2, vy2 = self.apply(pt.ctrl2.x, pt.ctrl2.y)<EOL>x, y = self.apply(pt.x, pt.y)<EOL>p.curveto(vx1, vy1, vx2, vy2, x, y)<EOL><DEDENT><DEDENT>return p<EOL>

Returns a BezierPath object with the transformation applied.


def __init__(self, x, y, width, height):

<EOL>if width == None: width = INFINITE<EOL>if height == None: height = INFINITE<EOL>if width < <NUM_LIT:0>: x, width = x+width,  -width<EOL>if height < <NUM_LIT:0>: y, height = y+height, -height<EOL>self.x = x<EOL>self.y = y<EOL>self.width = width<EOL>self.height = height<EOL>

Creates a bounding box.
            The bounding box is an untransformed rectangle that encompasses a shape or group of shapes.


return (self.x, self.y, self.width, self.height).__iter__()<EOL>

You can conveniently unpack bounds: x,y,w,h = Bounds(0,0,100,100)


return max(self.x, b.x) < min(self.x+self.width, b.x+b.width)and max(self.y, b.y) < min(self.y+self.height, b.y+b.height)<EOL>

Return True if a part of the two bounds overlaps.


if not self.intersects(b):<EOL><INDENT>return None<EOL><DEDENT>mx, my = max(self.x, b.x), max(self.y, b.y)<EOL>return Bounds(mx, my,<EOL>min(self.x+self.width, b.x+b.width) - mx,<EOL>min(self.y+self.height, b.y+b.height) - my)<EOL>

Returns bounds that encompass the intersection of the two.
            If there is no overlap between the two, None is returned.


mx, my = min(self.x, b.x), min(self.y, b.y)<EOL>return Bounds(mx, my,<EOL>max(self.x+self.width, b.x+b.width) - mx,<EOL>max(self.y+self.height, b.y+b.height) - my)<EOL>

Returns bounds that encompass the union of the two.


if len(a) == <NUM_LIT:2>: a = [Point(a[<NUM_LIT:0>], a[<NUM_LIT:1>])]<EOL>if len(a) == <NUM_LIT:1>:<EOL><INDENT>a = a[<NUM_LIT:0>]<EOL>if isinstance(a, Point):<EOL><INDENT>return a.x >= self.x and a.x <= self.x+self.widthand a.y >= self.y and a.y <= self.y+self.height<EOL><DEDENT>if isinstance(a, Bounds):<EOL><INDENT>return a.x >= self.x and a.x+a.width <= self.x+self.widthand a.y >= self.y and a.y+a.height <= self.y+self.height<EOL><DEDENT><DEDENT>

Returns True if the given point or rectangle falls within the bounds.


return self.get_matrix_with_center(<NUM_LIT:0>,<NUM_LIT:0>)<EOL>

Returns this transform's matrix. Its centerpoint is presumed to be
        (0,0), which is the Cairo default.


def __init__(self, name, type, **kwargs):

self.name = name<EOL>if not isinstance(name, basestring):<EOL><INDENT>raise AttributeError("<STR_LIT>")<EOL><DEDENT>if kwargs.get("<STR_LIT>") and kwargs.get("<STR_LIT>"):<EOL><INDENT>raise AttributeError("<STR_LIT>")  <EOL><DEDENT>self.type = type or NUMBER<EOL>self.min = None<EOL>self.max = None<EOL>self.step = None or kwargs.get("<STR_LIT>")<EOL>self.steps = kwargs.get("<STR_LIT>", DEFAULT_STEPS)<EOL>if self.type == NUMBER:<EOL><INDENT>self.min = kwargs.get("<STR_LIT>", <NUM_LIT:0.0>)<EOL>self.max = kwargs.get("<STR_LIT>", <NUM_LIT>)<EOL>if self.step is None:<EOL><INDENT>diff = max(self.min, self.max) - min(self.min, self.max)<EOL>self.step = (diff / float(self.steps))<EOL><DEDENT>self.default = kwargs.get("<STR_LIT:default>")<EOL>if self.default is None:<EOL><INDENT>self.default = self.min<EOL><DEDENT><DEDENT>elif self.type == TEXT:<EOL><INDENT>self.default = kwargs.get("<STR_LIT:default>", "<STR_LIT>")<EOL><DEDENT>elif self.type == BOOLEAN:<EOL><INDENT>self.default = kwargs.get("<STR_LIT:default>", True)<EOL><DEDENT>elif self.type == BUTTON:<EOL><INDENT>self.default = kwargs.get("<STR_LIT:default>", self.name)<EOL><DEDENT>else:<EOL><INDENT>raise AttributeError("<STR_LIT>")<EOL><DEDENT>self.value = kwargs.get("<STR_LIT:value>", self.default)<EOL>if self.value is None and self.default is not None:<EOL><INDENT>self.value = self.default<EOL><DEDENT>

:param name:     Name of variable
:param type:     NUMBER | TEXT | BOOLEAN | BUTTON
:param default:  default value
:param min:      min value if number
:param max:      max value if number
:param value:    value
:param step:     step between values - cannot specify at same time as step
:param steps:    total steps
:return: