Beispiel #1
0
 def draw(self, root, surface=None):
     surface = surface if surface is not None else self.screen
     points = []
     for func, args in flatten(root):
         #if func not in ["begin_region", "move_to", "line_to"]: continue
         if func == "stroke_and_fill":
             # Hack for arcs
             if len(points) <= 1: continue
             #flat_pts = [coord for point in points for coord in point]
             # Problem: with alpha, want a bbox and then translate...
             if default_get(args, "fill_color") and len(points) > 2:
                 pygame.draw.polygon(
                     surface, intcol(default_get(args, "fill_color")),
                     map(tuple, points), 0)
             if default_get(args, "stroke_color"):
                 if default_get(args, "dash"):
                     #[start*t + end*(1-t) for t in midpoints]
                     pass
                 pygame.draw.lines(
                     surface, intcol(default_get(args, "stroke_color")),
                     False, points, int(default_get(args, "line_width")))
         elif func == "text":
             font_size = args['font_size'] if numpy.array_equal(args["transform"], identity) or args['transform'][0][1] or args['transform'][1][0]\
                         else args['font_size'] * args["transform"][0][0]
             #font_size = args['font_size']
             font_param = (args.get("font_face"),
                           int(round(1.5 * font_size)))
             color = intcol(default_get(args, "stroke_color"))
             text = get_font(font_param).render(str(args["text"]), True,
                                                color)
             surface.blit(text, args["botleft"] - P(0, text.get_height()))
         elif func == "group":
             pass
         elif func == "begin_region":
             points = []
         elif func == "end_region":
             pass
         elif func in ["move_to", "line_to"]:
             points.append(args)
         elif func == "arc":
             # Doesn't work inside polygons yet.
             topleft = args["center"] - P(args["radius"], args["radius"])
             wh = P(2 * args["radius"], 2 * args["radius"])
             angles = args["angle"]
             if angles == (0, 2 * math.pi):
                 pygame.draw.circle(
                     surface,
                     intcol(default_get(args["style"], "stroke_color")),
                     map(int, args["center"]), args["radius"], 0)
             else:
                 pygame.draw.arc(
                     surface,
                     intcol(default_get(args["style"], "stroke_color")),
                     (topleft, wh), angles[0], angles[1],
                     default_get(args, "line_width"))
         else:
             raise Exception('Unknown function %s, %s' % (func, args))
Beispiel #2
0
def run_button(mod=None):
    root = doc[doc["selection.root"]]
    txy = doc["editor.mouse_txy"]
    cui = doc['custom_ui'] if default_get(doc['custom_ui'], 'visible') else []
    more = []
    for child in chain(cui, reversed(root)):
        if collide(child, txy):
            print "clicked on", child["id"], "on_click" in child, mod
            if "on_click" in child and not mod:
                run_text(child["id"], "on_click")
            elif "on_shift_click" in child and mod == "shift":
                run_text(child["id"], "on_shift_click")
            elif child.get("button_group"):
                # Wrong. Should test children right away in reverse order.
                more.extend([(gc, child.transform) for gc in child])
                print "Button group", len(more)  #[n['id'] for n in more]
                continue
            return True
    # TODO: refactor
    for child, transform in more:
        if collide(child, txy, transform=transform):
            print "clicked on", child["id"], "on_click" in child, mod
            if "on_click" in child and not mod:
                run_text(child["id"], "on_click")
            elif "on_shift_click" in child and mod == "shift":
                run_text(child["id"], "on_shift_click")
            elif child.get("button_group"):
                more.extend([(gc, child.transform) for gc in child])
                print "Button group", [n['id'] for n in more]
                continue
            return True
    return False
Beispiel #3
0
 def draw(self, root):
     points = []
     for func, args in flatten(root):
         #if func not in ["begin_region", "move_to", "line_to"]: continue
         if func == "stroke_and_fill":
             # Hack for arcs
             if len(points) <= 1: continue
             flat_pts = [coord for point in points for coord in point]
             self.canvas.create_polygon(
                 *flat_pts,
                 width=default_get(args, "line_width"),
                 dash=default_get(args, "dash")[0],
                 outline=hexcol(default_get(args, "stroke_color")),
                 fill=hexcol(default_get(args, "fill_color")))
         elif func == "text":
             font = (args["font_face"] if args.get("font_face") else
                     "TkFixedFont", int(round(args["font_size"])))
             self.canvas.create_text(*args["botleft"],
                                     font=font,
                                     fill=hexcol(
                                         default_get(args, "stroke_color")),
                                     text=args["text"],
                                     anchor="sw")
         elif func == "group":
             pass
         elif func == "begin_region":
             points = []
         elif func == "end_region":
             pass
         elif func in ["move_to", "line_to"]:
             points.append(args)
         elif func == "arc":
             # Doesn't work inside polygons yet.
             x, y = args["center"]
             r = args["radius"]
             start = args["angle"][0] * 180 / math.pi,
             angle_diff = (args["angle"][0] -
                           args["angle"][1]) * 180 / math.pi
             slice_type = Tkinter.PIESLICE if default_get(
                 args["style"], "fill_color") else Tkinter.ARC
             if angle_diff % 360 == 0:
                 #self.canvas.create_arc(x-r, y-r, x+r, y+r, start=0, extent=360, fill="red")
                 start = 0.0
                 # Must be a tkinter bug
                 angle_diff = 359
             self.canvas.create_arc(
                 x - r,
                 y - r,
                 x + r,
                 y + r,
                 start=start,
                 extent=angle_diff,
                 style=slice_type,
                 outline=hexcol(default_get(args["style"], "stroke_color")),
                 fill=hexcol(default_get(args["style"], "fill_color")))
         else:
             raise Exception('Unknown function %s, %s' % (func, args))
Beispiel #4
0
    def bbox(self, transform=identity, skip=False):
        """ Bound box. Includes self's transform."""
        # Want some way to cache the answer for children?
        # Would need transforms to be applied after instead of before.
        # Could almost make this an expression

        # transformed() already applies the last transform to points
        if not skip and self.name != "point":
            transform = transform.dot(self.transform)
        if self.name in ["group", "path"]:
            boxes = [child.bbox(transform) for child in self]
            boxes = zip(*[
                box for box in boxes
                if not numpy.array_equal(box, (None, None))
            ])
            if not boxes:
                return (None, None)
            return (numpy.min(numpy.vstack(boxes[0]),
                              0), numpy.max(numpy.vstack(boxes[1]), 0))
        elif self.name == "ref":
            return self.reference().bbox(transform, skip=True)
        elif self.name == "line":
            m = numpy.vstack([
                transformed(self["start"], transform),
                transformed(self["end"], transform)
            ])
            line_width = default_get(self, "line_width")
            return numpy.min(m, 0) - line_width, numpy.max(m, 0) + line_width
        elif self.name == "arc":
            end0, end1 = arc_endpoints(transformed(self["center"], transform),
                                       self["radius"],
                                       default_get(self, "angle"))
            m = numpy.vstack([end0, end1])
            line_width = default_get(self, "line_width")
            return numpy.min(m, 0) - line_width, numpy.max(m, 0) + line_width
        elif self.name == "point":
            point = transformed(self, transform)
            return point, point
        elif self.name == "text":
            botleft = transformed(self["botleft"], transform)
            xy, wh, dxy = extents(unicode(self["value"]),
                                  default_get(self, "font_size"),
                                  default_get(self, "font_face"))
            botright = botleft + dxy
            topleft = botleft + xy
            return topleft, botright
Beispiel #5
0
def collide(root, xy, style = {}, transform=identity, tolerance=3, skip=False):
    style = style.copy()
    for key in ["line_width", "stroke_color", "fill_color", "dash"]:
        if key in root:
            style[key] = root[key]
    if root.name in ["path", "group"]:
        if not skip:
            transform = transform.dot(root.transform)
        if root.name == "path" and style.get("fill_color"):
            # print "Testing fill"
            path = [(transformed(seg["start"], transform),
                     transformed(seg["end"], transform))
                    for seg in root if seg.name == 'line']
            # print "Input", xy, path
            if point_in_closed_path(xy, path):
                return True
        return any(collide(child, xy, style, transform, tolerance)
                   for child in root)
    elif root.name == "line":
        line = (transformed(root["start"], transform),
                transformed(root["end"], transform))
        xy = numpy.array(xy)
        dist2 = default_get(style, "line_width") + tolerance**2
        #print "dist", distance2(transform[:2,:2] * xy, line), dist2
        return distance2(xy, line) < dist2
    elif root.name == "arc":
        center=transformed(root["center"], transform)
        return distance_to_arc(xy, center, root["radius"], default_get(root, "angle")) < tolerance
    elif root.name == "point":
        point = transformed(root, transform)
        xy = numpy.array(xy)
        return norm2(xy - point) < tolerance**2
    elif root.name == "text":
        top_left, bottom_right = root.bbox(transform)
        def contains(top_left, bottom_right, xy):
            if numpy.array_equal((top_left, bottom_right), (None, None)):
                return False
            return all(top_left <= xy) and all(xy <= bottom_right)
            #return numpy.all(top_left <= xy <= bottom_right)
        tol = (tolerance, tolerance)
        return contains(top_left - tol,
                        bottom_right + tol,
                        xy)
    else:
        # Not yet implemented
        return False
Beispiel #6
0
def run_button():
    root = doc[doc["selection.root"]]
    txy = doc["editor.mouse_txy"]
    cui = doc['custom_ui'] if default_get(doc['custom_ui'], 'visible') else []
    for child in chain(cui, reversed(root)):
        if collide(child, txy):
            print "clicked on", child["id"], "on_click" in child
            if "on_click" in child:
                run_text(child["id"], "on_click")
            return True
    return False
Beispiel #7
0
def grab_point():
    root = doc[doc["selection.root"]]
    cui = doc['custom_ui'].dfs() if default_get(doc['custom_ui'],
                                                'visible') else []
    for child, transform in chain(root.dfs(), cui):
        if child.name == "point" and\
           collide(child, doc["editor.mouse_txy"], transform=transform, tolerance=8):
            doc["editor.drag_start"] = doc["editor.mouse_txy"]
            doc["editor.grabbed"] = child["id"]
            child.transforms["editor"] = Ex(
                "('translate', `editor.mouse_txy - `editor.drag_start)",
                calc='on first read')
            return True
    return False
Beispiel #8
0
def flatten_seg(root, style = {}, transform = identity):
    if root.name in ["line", "curve", "arc"]:
        if root.name in "line":
            yield ("line_to", transformed(root["end"], transform))
        elif root.name == "curve":
            yield ("curve_to", transformed(root["start_control"], transform) +\
                   transformed(root["end_control"], transform) +\
                   transformed(root["end"], transform))
        elif root.name == "arc":
            center = transformed(root["center"], transform)
            yield ("arc", {"center": center,
                           "radius": root["radius"],
                           "angle": default_get(root, "angle"),
                           "style": style})
Beispiel #9
0
 def draw(self, root):
     points = []
     for func, args in flatten(root):
         #if func not in ["begin_region", "move_to", "line_to"]: continue
         if func == "stroke_and_fill":
             # Hack for arcs
             if len(points) <= 1: continue
             if default_get(args, "fill_color"):
                 glColor3f(*default_get(args, "fill_color"))
                 glBegin(GL_POLYGON)
                 for point in points:
                     glVertex2d(*(point))
                 glEnd()
             if default_get(args, "stroke_color"):
                 glColor3f(*default_get(args, "stroke_color"))
                 glBegin(GL_LINE_LOOP)
                 for point in points:
                     glVertex2d(*(point))
                 glEnd()
         elif func == "text":
             glWindowPos2f(args["botleft"][0],
                           self.height - args["botleft"][1])
             for ch in args["text"]:
                 glutBitmapCharacter(GLUT_BITMAP_TIMES_ROMAN_24,
                                     ctypes.c_int(ord(ch)))
         elif func == "group":
             pass
         elif func == "begin_region":
             points = []
         elif func == "end_region":
             pass
         elif func in ["move_to", "line_to"]:
             points.append(args)
         elif func == "arc":
             # Doesn't work inside polygons yet.
             x, y = args["center"]
             r = args["radius"]
             start = args["angle"][0] * 180 / math.pi,
             angle_diff = (args["angle"][0] -
                           args["angle"][1]) * 180 / math.pi
             if "fill_color" in args["style"]:
                 glColor3f(*default_get(args["style"], "fill_color"))
                 glBegin(GL_POLYGON)
             else:
                 glColor3f(*default_get(args["style"], "stroke_color"))
                 glBegin(GL_LINES)
             N = 20
             for i in xrange(N):
                 theta = i * 2 * math.pi / N
                 glVertex2d(x + r * math.sin(theta),
                            y + r * math.cos(theta))
             glEnd()
         else:
             raise Exception('Unknown function %s, %s' % (func, args))
Beispiel #10
0
def rectangle_lasso_points():
    root = doc[doc["selection.root"]]
    cui = doc['custom_ui'].dfs() if default_get(doc['custom_ui'],
                                                'visible') else []

    root = doc[doc["selection"]["root"]]
    txy = doc["editor.mouse_txy"]
    for rect in reversed(root):
        if collide(rect, txy):
            topleft, botright = rect.bbox()
            print("Found rect", topleft, botright)
            for child, transform in chain(root.dfs(), cui):
                if child.name == "point" and\
                   (topleft <= child['value']).all() and\
                   (child['value'] <= botright).all():
                    if child["id"] not in doc["editor.selected"]:
                        selection_add(doc, child)
            break
Beispiel #11
0
 def draw(self, layer = "drawing", root = None):
     if root is None:
         doc, root_id = self.layers[layer]
         root = doc[root_id]
     context = self.contexts[layer]
     for func, args in flatten(root):
         if func == "stroke_and_fill":
             if default_get(args, "fill_color"):
                 context.set_source_rgb(*default_get(args, "fill_color"))
                 if args.get("stroke_color") is not None:
                     context.fill_preserve()
                 else:
                     context.fill()
             if default_get(args, "stroke_color"):
                 context.set_line_width(default_get(args, "line_width"))
                 context.set_source_rgb(*default_get(args, "stroke_color"))
                 context.set_dash(*default_get(args, "dash"))
                 context.stroke()
         elif func == "text":
             if args["text"] is None:
                 continue
             context.set_source_rgb(*default_get(args, "stroke_color"))
             context.move_to(*args["botleft"])
             context.set_font_size(1.5 * args["font_size"])
             if numpy.array_equal(args["transform"], identity):
                 context.show_text(unicode(args["text"]))
             else:
                 context.save()
                 matrix = cairo.Matrix(*args["transform"].T[:,:2].flatten())
                 context.transform(matrix)
                 context.show_text(unicode(args["text"]))
                 context.restore()
         elif func == "group":
             pass
         elif func in ["begin_region", "end_region"]:
             pass
         elif func == "arc":
             flat = list(args["center"]) + [args["radius"]] + list(args["angle"])
             context.arc(*flat)
         else:
             getattr(context, func)(*args)
Beispiel #12
0
def font_change(factor=1.2):
    factor = float(factor)
    for ref in doc['selection']:
        for node, transform in ref['ref'].dfs():
            if node.name == "text":
                node['font_size'] = default_get(node, "font_size") * factor
Beispiel #13
0
def toggle_ui_visible():
    doc['custom_ui.visible'] = not default_get(doc['custom_ui'], 'visible')
Beispiel #14
0
 def draw(self, layer="drawing", root=None):
     if root is None:
         doc, root_id = self.layers[layer]
         root = doc[root_id]
     context = self.contexts[layer]
     for func, args in flatten(root):
         if func == "stroke_and_fill":
             opacity = default_get(args, "opacity")
             if default_get(args, "fill_color"):
                 context.set_source_rgba(*default_get(args, "fill_color"),
                                         alpha=opacity)
                 if args.get("stroke_color") is not None:
                     context.fill_preserve()
                 else:
                     context.fill()
             if default_get(args, "stroke_color"):
                 context.set_line_width(default_get(args, "line_width"))
                 context.set_source_rgba(*default_get(args, "stroke_color"),
                                         alpha=opacity)
                 context.set_dash(*default_get(args, "dash"))
                 context.stroke()
         elif func == "text":
             if args["text"] is None:
                 continue
             opacity = default_get(args, "opacity")
             context.set_source_rgba(*default_get(args, "stroke_color"),
                                     alpha=opacity)
             context.move_to(*args["botleft"])
             context.set_font_size(1.5 * args["font_size"])
             if args.get("font_face"):
                 context.select_font_face(args["font_face"],
                                          cairo.FONT_SLANT_NORMAL,
                                          cairo.FONT_WEIGHT_NORMAL)
             else:
                 context.set_font_face(None)
             if numpy.array_equal(args["transform"], identity):
                 context.show_text(unicode(args["text"]))
             else:
                 context.save()
                 matrix = cairo.Matrix(
                     *args["transform"].T[:, :2].flatten())
                 context.transform(matrix)
                 context.show_text(unicode(args["text"]))
                 context.restore()
         elif func == "image":
             # PNG only for the moment
             img = cairo.ImageSurface.create_from_png(args["filename"])
             if numpy.array_equal(args["transform"], identity):
                 context.set_source_surface(img, *args["topleft"])
                 context.paint()
             else:
                 context.save()
                 matrix = cairo.Matrix(
                     *args["transform"].T[:, :2].flatten())
                 context.transform(matrix)
                 context.set_source_surface(img, *args["topleft"])
                 context.paint()
                 context.restore()
         elif func == "group":
             pass
         elif func in ["begin_region", "end_region"]:
             pass
         elif func == "arc":
             flat = list(args["center"]) + [args["radius"]] + list(
                 args["angle"])
             context.arc(*flat)
         else:
             getattr(context, func)(*args)
Beispiel #15
0
def _flatten(root, style={}, transform=identity, skip_transform=False):
    """ Flatten tree into drawing commands."""
    assert(root.doc is not None)
    if not default_get(root, "visible"):
        return
    style = style.copy()
    for key in ["line_width", "stroke_color", "fill_color", "dash",
                "skip_points"]:
        if key in root:
            style[key] = root[key]
    if "opacity" in root:
        style["opacity"] = default_get(style, "opacity") * root["opacity"]
    if not skip_transform:
        transform = transform.dot(root.transform)
    if root.name in ["line", "curve", "arc", "path"]:
        if not default_get(root, "visible"):
            return
        children = root if root.name == "path" else [root]
        border = []
        if children:
            yield ("begin_region", ())
            if children[0].name == "arc":
                yield ("move_to", transformed(children[0]["center"], transform))
            else:
                yield ("move_to", transformed(children[0]["start"], transform))
        for child in children:
            for segment in flatten_seg(child, style = style,
                                       transform = transform):
                yield segment
        yield ("end_region", ())
        yield ("stroke_and_fill", style)
        if not default_get(style, "skip_points"):
            for child in children:
                for grandchild in child:
                    for elem in flatten(grandchild, style = style,
                                        transform = transform):
                        yield elem
    elif root.name in ["clip"]:
        # Clipping needs to specify both the clipped region and
        # the clipped elements!
        # Maybe only allow clipped rectangles at first?
        yield ("begin_clipped", ())
        for child in root["clip_path"]:
            for segment in flatten_seg(child, style = style,
                                       transform = transform):
                yield segment
        yield ("end_clip", ())
        yield ("end_clipped", ())
    elif root.name == "point":
        if default_get(style, "skip_points"):
            return
        matrix = numpy.array([[1, 0, root["value"][0]],
                              [0, 1, root["value"][1]],
                              [0, 0,       1]])
        transform = transform.dot(matrix)
        for elem in flatten(root.doc[default_get(root, "icon")],
                            transform=transform, style={"skip_points":True}):
            yield elem
    elif root.name == "text":
        if "value" in root:
            value = root["value"]
        elif "ref_id" in root:
            value = str(root.doc[root["ref_id"]][root["ref_param"]])
        else:
            raise Exception('Text node with no value or ref_id: %s' % root)
        yield ("text", {"text": value,
                        "transform": transform,
                        "font_size": default_get(root, "font_size"),
                        "font_face": default_get(root, "font_face"),
                        "stroke_color": default_get(style, "stroke_color"),
                        "botleft": transformed(root["botleft"], transform),
                        "opacity": default_get(style, "opacity")})
    elif root.name == "image":
        yield ("image", {"filename": root['filename'],
                         "topleft": default_get(root, "topleft")['value'],
                         "transform": transform})
    elif root.name == "group":
        yield ("group", ())
    if root.name in ["group", "text", "image"]:
        #if default_get(root, "visible"):
        for child in root:
            for elem in flatten(child, style = style,
                                transform = transform):
                yield elem
        if default_get(root, "render"):
            for child in root["render"]:
                for elem in flatten(child, style = style,
                                    transform = transform):
                    yield elem