Exemple #1
0
    def test_place_in_col(self):
        p = PdPage("sample")
        seq = [self.objwh(5, 10), self.objwh(6, 12), self.objwh(7, 16)]
        p.place_in_col(seq, 0, 0)
        self.assertHeight(seq, [10, 12, 16])
        self.assertWidth(seq, [5, 6, 7])
        self.assertXPos(seq, [0, 0, 0])
        self.assertYPos(seq, [0, 10, 22])

        p.place_in_col(seq, 10)
        self.assertYPos(seq, [10, 20, 32])

        p.place_in_col(seq, 10, 5)
        self.assertYPos(seq, [10, 25, 42])
Exemple #2
0
    def test_place_bottom_left(self):
        p = PdPage("sample", 600, 500)
        o = self.objwh(100, 20)
        p.place_bottom_left(o)
        self.assertEqual(o.x, 0)
        self.assertEqual(o.y, 480)

        p.place_bottom_left(o, 20)
        self.assertEqual(o.x, 20)
        self.assertEqual(o.y, 480)

        p.place_bottom_left(o, 20, 10)
        self.assertEqual(o.x, 20)
        self.assertEqual(o.y, 470)
Exemple #3
0
    def test_place_top_right(self):
        p = PdPage("sample", 600, 500)
        o = self.objwh(100, 20)
        p.place_top_right(o)
        self.assertEqual(o.x, 500)
        self.assertEqual(o.y, 0)

        p.place_top_right(o, 10)
        self.assertEqual(o.x, 490)
        self.assertEqual(o.y, 0)

        p.place_top_right(o, 10, 15)
        self.assertEqual(o.x, 490)
        self.assertEqual(o.y, 15)
Exemple #4
0
    def test_place_in_row(self):
        p = PdPage("sample")
        seq = [self.objwh(10, 5), self.objwh(12, 6), self.objwh(16, 7)]
        p.place_in_row(seq, 0, 0)
        self.assertWidth(seq, [10, 12, 16])
        self.assertHeight(seq, [5, 6, 7])
        self.assertYPos(seq, [0, 0, 0])
        self.assertXPos(seq, [0, 10, 22])

        p.place_in_row(seq, 10)
        self.assertXPos(seq, [10, 20, 32])

        p.place_in_row(seq, 10, 5)
        self.assertXPos(seq, [10, 25, 42])
Exemple #5
0
    def test_place_right_side(self):
        p = PdPage("sample", 600, 500)
        o1 = self.obj(x=4, y=5, w=100, h=20)
        o2 = self.obj(x=2, y=100, w=100, h=20)
        p.place_right_side(o1, o2)
        self.assertEqual(o1.x, 4)
        self.assertEqual(o2.x, 104)
        self.assertEqual(o1.y, 5)
        self.assertEqual(o2.y, 100)

        p.place_right_side(o1, o2, 20)
        self.assertEqual(o1.x, 4)
        self.assertEqual(o2.x, 124)
        self.assertEqual(o1.y, 5)
        self.assertEqual(o2.y, 100)
Exemple #6
0
    def test_make_txt(self):
        p = PdPage("sample", 600, 500)

        t1 = p.make_txt(None, 10, 20)
        self.assertEqual(t1.text(), "")
        self.assertEqual(t1.x, 10)
        self.assertEqual(t1.y, 20)

        t1 = p.make_txt("       ", 0, 0)
        self.assertEqual(t1.text(), "")
        t1 = p.make_txt(" a b c ", 0, 0)
        self.assertEqual(t1.text(), "a b c")

        t1 = p.make_txt("test.", 0, 0)
        self.assertEqual(t1.text(), "test.")

        t1 = p.make_txt("10.124", 0, 0)
        self.assertEqual(t1.text(), "10.124")

        t1 = p.make_txt(".test", 0, 0)
        self.assertEqual(t1.text(), ".test")

        t1 = p.make_txt("1.", 0, 0)
        self.assertEqual(t1.text(), "1\\.")

        # test commas
        t1 = p.make_txt("a,b,c", 0, 0)
        self.assertEqual(t1.text(), "a, b, c")

        t1 = p.make_txt("a, b, c", 0, 0)
        self.assertEqual(t1.text(), "a, b, c")

        t1 = p.make_txt("a , b , c", 0, 0)
        self.assertEqual(t1.text(), "a, b, c")
Exemple #7
0
    def test_group_brect(self):
        p = PdPage("sample", 600, 500)

        o1 = self.obj(x=4, y=5, w=100, h=20)
        o2 = self.obj(x=2, y=100, w=100, h=20)
        self.assertEqual(p.group_brect([o1, o2]), (2, 5, 102, 115))
Exemple #8
0
 def __init__(self):
     DocObjectVisitor.__init__(self)
     self.current_yoff = 0
     self._pp = PdPage("obj", self.PD_WINDOW_WIDTH, self.PD_WINDOW_HEIGHT)
Exemple #9
0
class PdDocVisitor(DocObjectVisitor):
    PD_WINDOW_WIDTH = 785
    PD_WINDOW_HEIGHT = 555
    PD_HEADER_HEIGHT = 40
    PD_HEADER_FONT_SIZE = 20
    PD_HEADER_COLOR = Color(0, 255, 255)
    PD_HEADER_BG_COLOR = Color(100, 100, 100)
    PD_EXAMPLE_YOFFSET = 30
    PD_FOOTER_HEIGHT = 48
    PD_FOOTER_COLOR = Color(180, 180, 180)
    PD_INFO_WINDOW_WIDTH = 400
    PD_INFO_WINDOW_HEIGHT = 290
    PD_XLET_INDX_XPOS = 110
    PD_XLET_TYPE_XPOS = 150
    PD_XLET_INFO_XPOS = 245
    PD_SECTION_YMARGIN = 40
    PD_PAR_INDENT = 10
    PD_ARG_NAME_COLOR = Color(240, 250, 250)

    def __init__(self):
        DocObjectVisitor.__init__(self)
        self.current_yoff = 0
        self._pp = PdPage("obj", self.PD_WINDOW_WIDTH, self.PD_WINDOW_HEIGHT)

    def meta_end(self, meta):
        self.add_header()
        self.current_yoff += self.PD_HEADER_HEIGHT
        self.current_yoff += 30

    def description_begin(self, d):
        super(self.__class__, self).description_begin(d)
        self._pp.add_description(self._description, self.PD_HEADER_HEIGHT + 10)

    def pdascii_begin(self, t):
        cnv = super(self.__class__, self).pdascii_begin(t)
        # insert only first example
        if t.id() == 'main':
            self.copy_canvas_objects(cnv)
            self.copy_canvas_connections(cnv)

            self.current_yoff += cnv.height
            # self.current_yoff += self.PD_EXAMPLE_YOFFSET

    def copy_canvas_connections(self, cnv):
        for conn in cnv.connections.values():
            self._pp.canvas.add_connection(conn[0].id, conn[1], conn[2].id,
                                           conn[3])

    def copy_canvas_objects(self, cnv):
        for obj in cnv.objects:
            obj.y += self.current_yoff
            obj.x += self.PD_EXAMPLE_YOFFSET
            self._pp.append_object(obj)

    def pdinclude_begin(self, t):
        db_path = '{0}.db'.format(self._library)
        PdObject.xlet_calculator.add_db(db_path)

        pd_parser = Parser()
        pd_parser.parse(t.file())
        cnv = pd_parser.canvas
        self.copy_canvas_objects(cnv)
        self.copy_canvas_connections(cnv)
        self.current_yoff += cnv.height

    def mouse_begin(self, m):
        self.add_section("mouse events:", self.PD_SECTION_YMARGIN)
        m.sort_by(lambda e: e.edit_mode())

    def mouse_end(self, m):
        self.current_yoff += 10
        if m.is_empty():
            self.current_yoff += 10

    def event_begin(self, e):
        click_map = {
            'left-click': 'Left-click',
            'right-click': 'Right-click',
            'middle-click': 'Middle-click',
            'double-click': 'Double-click',
            'drag': 'Mouse-drag',
            'wheel': 'Mouse-wheel'
        }

        ct = e.type()
        k = e.keys()
        if k == "":
            tmpl = "{0}"
        else:
            tmpl = "{0} + {1}"

        items = []
        t1 = self._pp.add_txt(tmpl.format(click_map[ct], k),
                              self.PD_XLET_INDX_XPOS, self.current_yoff)
        t2 = self._pp.add_txt(add_text_dot(e.text()),
                              self.PD_XLET_INFO_XPOS + 40, self.current_yoff)

        items.append(t1)
        items.append(t2)

        _, _, _, h = self._pp.group_brect(items)

        if e.edit_mode():
            lbl = self._pp.add_txt("[Edit]", 0, self.current_yoff)
            _, _, w, _ = self._pp.group_brect([lbl])
            lbl.set_x(self.PD_XLET_INDX_XPOS - w - 10)

        self.current_yoff += h + 5

    def methods_begin(self, m):
        self.add_section("methods:", self.PD_SECTION_YMARGIN)
        m.sort_by(lambda n: n.sort_name())

    def methods_end(self, m):
        self.current_yoff += 10
        if m.is_empty():
            self.current_yoff += 10

    def method_begin(self, m):
        msg_atoms = [m.name()]
        # for i in m.items():
        # msg_atoms.append(i.param_name())

        msg = Message(self.PD_XLET_INDX_XPOS, self.current_yoff, msg_atoms)
        msg.calc_brect()
        self._pp.append_object(msg)

        info_text = m.text().strip()
        info_text = add_text_dot(info_text)

        if len(m.items()) > 0:
            info_text += " Arguments are: "

        info = []
        info.append(
            self._pp.add_txt(info_text, self.PD_XLET_INFO_XPOS,
                             self.current_yoff))

        # add method arguments
        for i in m.items():
            param_name = i.param_name()
            arg_descr = param_name

            if i.text() is not None:
                arg_descr += ": " + i.text().strip()

            if i.type():
                arg_descr = "{0} Type: {1}. ".format(add_text_dot(arg_descr),
                                                     i.type())

            value_range = self.format_range(i)
            if len(value_range) > 0:
                # add dot after description
                arg_descr = add_text_dot(arg_descr)
                # add dot after the range
                arg_descr += " " + add_text_dot(value_range)

            if len(i.enum()) > 0:
                arg_descr = "{0} Allowed values: {1}.".format(
                    add_text_dot(arg_descr), ', '.join(i.enum()))

            # param name highlight with background canvas
            hl_text = self._pp.make_txt(param_name, 0, 0)
            hl_text.calc_brect()
            bg = self._pp.make_background(0,
                                          0,
                                          hl_text.width + 8,
                                          hl_text.height + 8,
                                          color=self.PD_ARG_NAME_COLOR)
            self._pp.append_object(bg)

            # param description
            txt_obj = self._pp.add_txt(add_text_dot(arg_descr),
                                       self.PD_XLET_INFO_XPOS + 10,
                                       self.current_yoff)
            # bind background to object
            setattr(txt_obj, 'background_obj', bg)

            info.append(txt_obj)

        self._pp.place_in_col(info, self.current_yoff, 8)

        # set background positions
        for obj in info:
            if hasattr(obj, 'background_obj'):
                bg = getattr(obj, 'background_obj')
                bg.x = obj.x
                bg.y = obj.y

        info.append(msg)
        _, _, _, h = self._pp.group_brect(info)
        self.current_yoff += h + 10

    def inlets_begin(self, inlets):
        super(self.__class__, self).inlets_begin(inlets)
        self.add_section("inlets:", 6)
        inlets.enumerate()

    def inlets_end(self, inlets):
        self.current_yoff += 10

        if inlets.is_empty():
            self.current_yoff += 10

    def inlet_begin(self, inlet):
        self._pp.add_txt("{0}.".format(inlet.number()), self.PD_XLET_INDX_XPOS,
                         self.current_yoff)

    def xinfo_begin(self, xinfo):
        tlist = []
        if xinfo.on():
            t1 = self._pp.add_txt("*{0}*".format(xinfo.on()),
                                  self.PD_XLET_TYPE_XPOS, self.current_yoff)
            tlist.append(t1)

        txt = add_text_dot(xinfo.text())
        rng = self.format_range(xinfo)
        if rng != "":
            txt += " " + rng

        t2 = self._pp.add_txt(add_text_dot(txt), self.PD_XLET_INFO_XPOS,
                              self.current_yoff)
        tlist.append(t2)

        _, _, _, h = self._pp.group_brect(tlist)
        self.current_yoff += h + 5

    def outlets_begin(self, outlets):
        super(self.__class__, self).outlets_begin(outlets)
        self.add_section("outlets:", 6)
        outlets.enumerate()

    def outlets_end(self, outlets):
        self.current_yoff += 10

        if outlets.is_empty():
            self.current_yoff += 10

    def outlet_begin(self, outlet):
        y = self.current_yoff
        t1 = self._pp.add_txt("{0}.".format(outlet.number()),
                              self.PD_XLET_INDX_XPOS, y)
        t2 = self._pp.add_txt(add_text_dot(outlet.text()),
                              self.PD_XLET_INFO_XPOS, y)

        _, _, _, h = self._pp.group_brect([t1, t2])
        self.current_yoff += h + 5

    def arguments_begin(self, args):
        super(self.__class__, self).arguments_begin(args)
        self.add_section("arguments:", self.PD_SECTION_YMARGIN)
        args.enumerate()

    def arguments_end(self, args):
        self.current_yoff += 10
        if args.is_empty():
            self.current_yoff += 10

    def properties_begin(self, p):
        super(self.__class__, self).properties_begin(p)
        self.add_section("properties:", self.PD_SECTION_YMARGIN)
        # sort by names
        p.sort_by(lambda n: n.sort_name())

    def properties_end(self, p):
        self.current_yoff += 10
        if p.is_empty():
            self.current_yoff += 10

    def property_begin(self, m):
        props = list()

        # add message with property name
        prop_get_name = "{0}".format(m.name())
        props.append(
            Message(self.PD_XLET_INDX_XPOS, self.current_yoff,
                    [prop_get_name]))
        self._pp.append_list(props)

        # props description
        prop_descr = ""
        if not (m.is_alias() or m.is_flag()):
            if m.readonly():
                prop_descr += "(readonly) Get "
            else:
                prop_descr += "Get/Set "

        prop_descr += m.text()

        if m.type() and not (m.is_alias() or m.is_flag()):
            prop_descr = "{0} Type: {1}. ".format(add_text_dot(prop_descr),
                                                  m.type())

        if m.units():
            prop_descr = "{0} Units: {1}. ".format(add_text_dot(prop_descr),
                                                   m.units())

        if m.default():
            prop_descr = "{0} Default value: {1}. ".format(
                add_text_dot(prop_descr), m.default())

        if m.min() and m.max():
            prop_descr = "{0} Range: {1}...{2}. ".format(
                add_text_dot(prop_descr), m.min(), m.max())
        elif m.min():
            prop_descr = "{0} Min value: {1}. ".format(
                add_text_dot(prop_descr), m.min())
        elif m.max():
            prop_descr = "{0} Max value: {1}. ".format(
                add_text_dot(prop_descr), m.max())

        if len(m.enum()) > 0:
            prop_descr = "{0} Allowed values: {1}.".format(
                add_text_dot(prop_descr), ', '.join(m.enum()))

        info = list()
        info.append(
            self._pp.add_txt(add_text_dot(prop_descr), self.PD_XLET_INFO_XPOS,
                             self.current_yoff))

        self._pp.place_in_col(info, self.current_yoff, 15)
        br = self._pp.group_brect(info + props)
        self.current_yoff += br[3] + 12

    def info_begin(self, info):
        lst = []
        XPOS = self.PD_XLET_INFO_XPOS - 30
        for p in info.items():
            if isinstance(p, DocPar):
                ind = p.indent * self.PD_PAR_INDENT
                t = self._pp.make_txt(p.text(), XPOS + ind, 0)
                lst.append(t)
            elif isinstance(p, DocA):
                a = self._pp.make_link(XPOS, 0, p.url, p.text())
                a.set_bg_color(PdPageStyle.MAIN_BG_COLOR)
                lst.append(a)
            elif isinstance(p, DocWiki):
                a = self._pp.make_link(XPOS, 0, p.url, p.text())
                a.set_bg_color(PdPageStyle.MAIN_BG_COLOR)
                lst.append(a)
                setattr(a, 'wiki_txt', True)

        self._pp.place_in_col(lst, self.PD_HEADER_HEIGHT + 40, 10)

        brect = self._pp.group_brect(lst)
        bg = self._pp.make_background(
            brect[0] - 5, brect[1],
            self._pp.width - self.PD_XLET_INFO_XPOS + 15, brect[3] + 20,
            PdPageStyle.MAIN_BG_COLOR)
        self._pp.append_object(bg)

        # place "Wiki:" before wiki link
        for obj in lst:
            if hasattr(obj, 'wiki_txt'):
                # create "Wiki:" text
                wiki_txt = self._pp.make_txt("Wiki:", obj.x, obj.y)
                self._pp.append_object(wiki_txt)
                obj.x += wiki_txt.brect()[2] + 5
                obj.y += 2

        self._pp.append_list(lst)
        self.current_yoff = brect[1] + brect[3]

    def argument_begin(self, arg):
        y = self.current_yoff
        super(self.__class__, self).argument_begin(arg)

        t1 = self._pp.add_txt("{0}.".format(arg.number()),
                              self.PD_XLET_INDX_XPOS, y)
        t2 = self._pp.add_txt(arg.type(), self.PD_XLET_TYPE_XPOS, y)
        self.add_background_for_txt(arg.main_info_prefix(),
                                    self.PD_XLET_INFO_XPOS, y,
                                    self.PD_ARG_NAME_COLOR)

        rng = self.format_range(arg)
        t3 = self._pp.add_txt("{0}. {1}".format(arg.main_info(), rng),
                              self.PD_XLET_INFO_XPOS, y)
        _, _, _, h = self._pp.group_brect([t1, t2, t3])
        self.current_yoff += h + 5

    def object_end(self, obj):
        LNK_Y = 45
        # index link
        idx_lnk = self._pp.make_link(0, LNK_Y, "../index-help.pd", "index")
        del1 = self._pp.make_txt("::", 0, LNK_Y)
        # library link
        lib_lnk = self._pp.make_link(0, LNK_Y,
                                     "{0}-help.pd".format(self._library),
                                     "{0}".format(self._library))
        del2 = self._pp.make_txt("::", 0, LNK_Y)
        # category link
        cat_lnk = self._pp.make_link(
            0, LNK_Y, "{0}.{1}-help.pd".format(self._library, self._category),
            "{0}".format(self._category))
        menu = [idx_lnk, del1, lib_lnk, del2, cat_lnk]
        self._pp.place_in_row(menu, 10, 7)
        self._pp.append_list(menu)
        self.add_footer()

    def render(self):
        return self._pp.to_string()

    @classmethod
    def format_range(cls, obj):
        r = obj.range()
        if len(r) == 2:
            if not r[0]:
                return "Max value: {0}".format(r[1])
            if not r[1]:
                return "Min value: {0}".format(r[0])

            return "Range: {0}...{1}".format(r[0], r[1])
        else:
            return ""

    def add_section(self, txt, yoff):
        hr = self._pp.make_styled_hrule(self.current_yoff)
        self._pp.append_object(hr)
        lbl = self._pp.make_section_label(self.current_yoff + 5,
                                          txt,
                                          font_size=14)
        self.current_yoff += yoff
        self._pp.append_object(lbl)

    def add_header(self):
        lbl = self.add_header_label()
        self.add_header_example_object(lbl, self._title)

    def add_header_example_object(self, lbl, title):
        seq = []
        alias_objects = filter(lambda n: n["name"] != title, self._aliases)

        for a in alias_objects:
            if 'is_link' in a and a['is_link'] is True:
                seq.append(self._pp.make_header_alias_link(title, a['name']))
            else:
                seq.append(make_by_name(a['name']))

        # append main object name
        # UI object added as link
        if self._is_gui:
            seq.append(self._pp.make_header_alias_link(title, title))
        else:
            seq.append(make_by_name(title))

        self._pp.place_in_row(seq, 0, 20)
        _, _, w, h = self._pp.group_brect(seq)
        y = (lbl.height - h) / 2
        x = (lbl.width - w) - 20
        self._pp.move_to_x(seq, x)
        self._pp.move_to_y(seq, y)
        self._pp.append_list(seq)

    def add_header_label(self):
        return self._pp.add_header("{0}".format(self._title))

    def add_footer(self):
        ft = self._pp.make_footer(self.current_yoff + 20,
                                  height=self.PD_FOOTER_HEIGHT)
        y = ft.y
        self._pp.append_object(ft)
        self.add_footer_library(y)
        self.add_also(y + 15)
        self.add_footer_more_info(y)

    def add_footer_more_info(self, y):
        # more info
        pd = self._pp.make_subpatch('info', 10, y + 22,
                                    self.PD_INFO_WINDOW_WIDTH,
                                    self.PD_INFO_WINDOW_HEIGHT)

        def add_subpatch_text(x, y, txt):
            self._pp.add_subpatch_txt('info', txt, x, y)

        bg = self._pp.make_background(1, 1, 107,
                                      self.PD_INFO_WINDOW_HEIGHT - 3,
                                      self.PD_FOOTER_COLOR)
        self._pp.add_subpatch_obj('info', bg)
        xc1 = 10
        xc2 = 120
        yrows = range(10, 300, 22)
        row = 0
        add_subpatch_text(xc1, yrows[row], "library:")
        add_subpatch_text(xc2, yrows[row], self._library)
        row += 1
        add_subpatch_text(xc1, yrows[row], "version:")
        add_subpatch_text(xc2, yrows[row], self._version)
        row += 1
        add_subpatch_text(xc1, yrows[row], "object:")
        add_subpatch_text(xc2, yrows[row], self._title)
        row += 1
        add_subpatch_text(xc1, yrows[row], "category:")
        add_subpatch_text(xc2, yrows[row], self._category)
        row += 1

        if self._since:
            add_subpatch_text(xc1, yrows[row], "since:")
            add_subpatch_text(xc2, yrows[row], self._since)
            row += 1

        add_subpatch_text(xc1, yrows[row], "authors:")
        add_subpatch_text(xc2, yrows[row], ", ".join(self._authors))
        row += 1
        add_subpatch_text(xc1, yrows[row], "license:")
        if not self._license.get('url', ' '):
            add_subpatch_text(xc2, yrows[row], self._license['name'])
        else:
            lnk = self._pp.make_link(xc2, yrows[row], self._license['url'],
                                     self._license['name'])
            pd.append_object(lnk)
        row += 1
        if self._keywords:
            add_subpatch_text(xc1, yrows[row], "keywords:")
            add_subpatch_text(xc2, yrows[row], ", ".join(self._keywords))
            row += 1
        if self._website:
            add_subpatch_text(xc1, yrows[row], "website:")
            lnk = self._pp.make_link(xc2, yrows[row], self._website,
                                     self._website)
            pd.append_object(lnk)
            row += 1
        if self._contacts:
            add_subpatch_text(xc1, yrows[row], "contacts:")
            add_subpatch_text(xc2, yrows[row], self._contacts)
            row += 1

        pd.append_object(
            PdObject("declare", x=xc2, y=yrows[row], args=["-lib", "ceammc"]))

        ypos = self.PD_INFO_WINDOW_HEIGHT - 22
        delim = self._pp.make_hrule(xc2, ypos, width=270)
        pd.append_object(delim)
        add_subpatch_text(xc2, ypos, "generated by pddoc")
        self._pp.canvas.append_subpatch(pd)

    def add_footer_library(self, y):
        # library:
        self._pp.add_txt(
            "library: {0} v{1}".format(self._library, self._version), 10,
            y + 3)

    def add_background_for_txt(self, txt, x, y, color, **kwargs):
        if len(txt) < 1:
            return

        padx = kwargs.get("padx", 5)
        pady = kwargs.get("pady", 5)

        c = Comment(x, y, txt.split(' '))
        c.calc_brect()
        bg = self._pp.make_background(x + 1, y + 1, c.width + padx,
                                      c.height + pady, color)
        self._pp.append_object(bg)

    def add_also(self, y):
        if len(self._see_also) < 1:
            return

        # see also:
        label = self._pp.make_txt("see also:", 0, 0)
        also_objects = [label]
        for see in self._see_also:
            if 'is_link' in see and see['is_link'] == True:
                lnk = self._pp.make_link(0, 0,
                                         "{0}-help.pd".format(see['name']),
                                         "[{0}]".format(see['name']))
                lnk.set_bg_color(Color(200, 200, 200))
                also_objects.append(lnk)
            else:
                also_objects.append(make_by_name(see['name']))

        self._pp.place_in_row(also_objects, 0, 10)
        _, _, w, h = self._pp.group_brect(also_objects)
        self._pp.move_to_y(also_objects, y)
        self._pp.move_to_x(also_objects, (self._pp.width - w) - 40)
        self._pp.append_list(also_objects)
Exemple #10
0
 def __init__(self):
     DocObjectVisitor.__init__(self)
     self.current_yoff = 0
     self._pp = PdPage("obj", self.PD_WINDOW_WIDTH, self.PD_WINDOW_HEIGHT)
Exemple #11
0
class PdDocVisitor(DocObjectVisitor):
    PD_WINDOW_WIDTH = 785
    PD_WINDOW_HEIGHT = 555
    PD_HEADER_HEIGHT = 40
    PD_HEADER_FONT_SIZE = 20
    PD_HEADER_COLOR = Color(0, 255, 255)
    PD_HEADER_BG_COLOR = Color(100, 100, 100)
    PD_EXAMPLE_YOFFSET = 30
    PD_FOOTER_HEIGHT = 48
    PD_FOOTER_COLOR = Color(180, 180, 180)
    PD_INFO_WINDOW_WIDTH = 400
    PD_INFO_WINDOW_HEIGHT = 290
    PD_XLET_INDX_XPOS = 110
    PD_XLET_TYPE_XPOS = 150
    PD_XLET_INFO_XPOS = 245
    PD_SECTION_YMARGIN = 40
    PD_ARG_NAME_COLOR = Color(240, 250, 250)

    def __init__(self):
        DocObjectVisitor.__init__(self)
        self.current_yoff = 0
        self._pp = PdPage("obj", self.PD_WINDOW_WIDTH, self.PD_WINDOW_HEIGHT)

    def meta_end(self, meta):
        self.add_header()
        self.current_yoff += self.PD_HEADER_HEIGHT
        self.current_yoff += 30

    def description_begin(self, d):
        super(self.__class__, self).description_begin(d)
        self._pp.add_description(self._description, self.PD_HEADER_HEIGHT + 10)

    def pdascii_begin(self, t):
        cnv = super(self.__class__, self).pdascii_begin(t)
        self.copy_canvas_objects(cnv)
        self.copy_canvas_connections(cnv)

        self.current_yoff += cnv.height
        self.current_yoff += self.PD_EXAMPLE_YOFFSET

    def copy_canvas_connections(self, cnv):
        for conn in cnv.connections.values():
            self._pp.canvas.add_connection(conn[0].id, conn[1], conn[2].id, conn[3])

    def copy_canvas_objects(self, cnv):
        for obj in cnv.objects:
            obj.y += self.current_yoff
            obj.x += self.PD_EXAMPLE_YOFFSET
            self._pp.append_object(obj)

    def pdinclude_begin(self, t):
        db_path = '{0}.db'.format(self._library)
        PdObject.xlet_calculator.add_db(db_path)

        pd_parser = Parser()
        pd_parser.parse(t.file())
        cnv = pd_parser.canvas
        self.copy_canvas_objects(cnv)
        self.copy_canvas_connections(cnv)
        self.current_yoff += cnv.height

    def mouse_begin(self, m):
        self.add_section("mouse events:", self.PD_SECTION_YMARGIN)
        m.sort_by(lambda e: e.edit_mode())

    def mouse_end(self, m):
        self.current_yoff += 10
        if m.is_empty():
            self.current_yoff += 10

    def event_begin(self, e):
        click_map = {
            'left-click': 'Left-click',
            'right-click': 'Right-click',
            'middle-click': 'Middle-click',
            'double-click': 'Double-click',
            'drag': 'Mouse-drag'
        }

        ct = e.type()
        k = e.keys()
        if k == "":
            tmpl = "{0}"
        else:
            tmpl = "{0} + {1}"

        items = []
        t1 = self._pp.add_txt(tmpl.format(click_map[ct], k), self.PD_XLET_INDX_XPOS, self.current_yoff)
        t2 = self._pp.add_txt(add_text_dot(e.text()), self.PD_XLET_INFO_XPOS + 40, self.current_yoff)

        items.append(t1)
        items.append(t2)

        _, _, _, h = self._pp.group_brect(items)

        if e.edit_mode():
            lbl = self._pp.add_txt("[Edit]", 0, self.current_yoff)
            _, _, w, _ = self._pp.group_brect([lbl])
            lbl.set_x(self.PD_XLET_INDX_XPOS - w - 10)

        self.current_yoff += h + 5

    def methods_begin(self, m):
        self.add_section("methods:", self.PD_SECTION_YMARGIN)
        m.sort_by(lambda n: n.sort_name())

    def methods_end(self, m):
        self.current_yoff += 10
        if m.is_empty():
            self.current_yoff += 10

    def method_begin(self, m):
        msg_atoms = [m.name()]
        # for i in m.items():
        # msg_atoms.append(i.param_name())

        msg = Message(self.PD_XLET_INDX_XPOS, self.current_yoff, msg_atoms)
        msg.calc_brect()
        self._pp.append_object(msg)

        info_text = m.text().strip()
        info_text = add_text_dot(info_text)

        if len(m.items()) > 0:
            info_text += " Arguments are: "

        info = []
        info.append(self._pp.add_txt(info_text, self.PD_XLET_INFO_XPOS, self.current_yoff))

        # add method arguments
        for i in m.items():
            param_name = i.param_name()
            arg_descr = param_name

            if i.text() is not None:
                arg_descr += ": " + i.text().strip()

            if i.type():
                arg_descr = "{0} Type: {1}. ".format(add_text_dot(arg_descr), i.type())

            value_range = self.format_range(i)
            if len(value_range) > 0:
                # add dot after description
                arg_descr = add_text_dot(arg_descr)
                # add dot after the range
                arg_descr += " " + add_text_dot(value_range)

            if len(i.enum()) > 0:
                arg_descr = "{0} Allowed values: {1}.".format(add_text_dot(arg_descr), ', '.join(i.enum()))

            # param name highlight with background canvas
            hl_text = self._pp.make_txt(param_name, 0, 0)
            hl_text.calc_brect()
            bg = self._pp.make_background(0, 0, hl_text.width + 8, hl_text.height + 8, color=self.PD_ARG_NAME_COLOR)
            self._pp.append_object(bg)

            # param description
            txt_obj = self._pp.add_txt(add_text_dot(arg_descr), self.PD_XLET_INFO_XPOS + 10, self.current_yoff)
            # bind background to object
            setattr(txt_obj, 'background_obj', bg)

            info.append(txt_obj)

        self._pp.place_in_col(info, self.current_yoff, 8)

        # set background positions
        for obj in info:
            if hasattr(obj, 'background_obj'):
                bg = getattr(obj, 'background_obj')
                bg.x = obj.x
                bg.y = obj.y

        info.append(msg)
        _, _, _, h = self._pp.group_brect(info)
        self.current_yoff += h + 10

    def inlets_begin(self, inlets):
        super(self.__class__, self).inlets_begin(inlets)
        self.add_section("inlets:", 6)
        inlets.enumerate()

    def inlets_end(self, inlets):
        self.current_yoff += 10

        if inlets.is_empty():
            self.current_yoff += 10

    def inlet_begin(self, inlet):
        self._pp.add_txt("{0}.".format(inlet.number()), self.PD_XLET_INDX_XPOS, self.current_yoff)

    def xinfo_begin(self, xinfo):
        tlist = []
        if xinfo.on():
            t1 = self._pp.add_txt("*{0}*".format(xinfo.on()), self.PD_XLET_TYPE_XPOS, self.current_yoff)
            tlist.append(t1)

        txt = add_text_dot(xinfo.text())
        rng = self.format_range(xinfo)
        if rng != "":
            txt += " " + rng

        t2 = self._pp.add_txt(add_text_dot(txt), self.PD_XLET_INFO_XPOS, self.current_yoff)
        tlist.append(t2)

        _, _, _, h = self._pp.group_brect(tlist)
        self.current_yoff += h + 5

    def outlets_begin(self, outlets):
        super(self.__class__, self).outlets_begin(outlets)
        self.add_section("outlets:", 6)
        outlets.enumerate()

    def outlets_end(self, outlets):
        self.current_yoff += 10

        if outlets.is_empty():
            self.current_yoff += 10

    def outlet_begin(self, outlet):
        y = self.current_yoff
        t1 = self._pp.add_txt("{0}.".format(outlet.number()), self.PD_XLET_INDX_XPOS, y)
        t2 = self._pp.add_txt(add_text_dot(outlet.text()), self.PD_XLET_INFO_XPOS, y)

        _, _, _, h = self._pp.group_brect([t1, t2])
        self.current_yoff += h + 5

    def arguments_begin(self, args):
        super(self.__class__, self).arguments_begin(args)
        self.add_section("arguments:", self.PD_SECTION_YMARGIN)
        args.enumerate()

    def arguments_end(self, args):
        self.current_yoff += 10
        if args.is_empty():
            self.current_yoff += 10

    def properties_begin(self, p):
        super(self.__class__, self).properties_begin(p)
        self.add_section("properties:", self.PD_SECTION_YMARGIN)
        # sort by names
        p.sort_by(lambda n: n.sort_name())

    def properties_end(self, p):
        self.current_yoff += 10
        if p.is_empty():
            self.current_yoff += 10

    def property_begin(self, m):
        props = list()

        # add message with property name
        prop_get_name = "{0}".format(m.name())
        props.append(Message(self.PD_XLET_INDX_XPOS, self.current_yoff, [prop_get_name]))
        self._pp.append_list(props)

        # props description
        prop_descr = ""
        if not (m.is_alias() or m.is_flag()):
            if m.readonly():
                prop_descr += "(readonly) Get "
            else:
                prop_descr += "Get/Set "

        prop_descr += m.text()

        if m.type() and not (m.is_alias() or m.is_flag()):
            prop_descr = "{0} Type: {1}. ".format(add_text_dot(prop_descr), m.type())

        if m.units():
            prop_descr = "{0} Units: {1}. ".format(add_text_dot(prop_descr), m.units())

        if m.default():
            prop_descr = "{0} Default value: {1}. ".format(add_text_dot(prop_descr), m.default())

        if m.min() and m.max():
            prop_descr = "{0} Range: {1}...{2}. ".format(add_text_dot(prop_descr), m.min(), m.max())
        elif m.min():
            prop_descr = "{0} Min value: {1}. ".format(add_text_dot(prop_descr), m.min())
        elif m.max():
            prop_descr = "{0} Max value: {1}. ".format(add_text_dot(prop_descr), m.max())

        if len(m.enum()) > 0:
            prop_descr = "{0} Allowed values: {1}.".format(add_text_dot(prop_descr), ', '.join(m.enum()))

        info = list()
        info.append(self._pp.add_txt(add_text_dot(prop_descr), self.PD_XLET_INFO_XPOS, self.current_yoff))

        self._pp.place_in_col(info, self.current_yoff, 15)
        br = self._pp.group_brect(info + props)
        self.current_yoff += br[3] + 12

    def info_begin(self, info):
        lst = []
        XPOS = self.PD_XLET_INFO_XPOS - 30
        for p in info.items():
            if isinstance(p, DocPar):
                t = self._pp.make_txt(p.text(), XPOS, 0)
                lst.append(t)
            elif isinstance(p, DocA):
                a = self._pp.make_link(XPOS, 0, p.url, p.text())
                a.set_bg_color(PdPageStyle.MAIN_BG_COLOR)
                lst.append(a)
            elif isinstance(p, DocWiki):
                a = self._pp.make_link(XPOS, 0, p.url, p.text())
                a.set_bg_color(PdPageStyle.MAIN_BG_COLOR)
                lst.append(a)
                setattr(a, 'wiki_txt', True)

        self._pp.place_in_col(lst, self.PD_HEADER_HEIGHT + 40, 10)

        brect = self._pp.group_brect(lst)
        bg = self._pp.make_background(brect[0] - 5, brect[1],
                                      self._pp.width - self.PD_XLET_INFO_XPOS + 15,
                                      brect[3] + 20, PdPageStyle.MAIN_BG_COLOR)
        self._pp.append_object(bg)

        # place "Wiki:" before wiki link
        for obj in lst:
            if hasattr(obj, 'wiki_txt'):
                # create "Wiki:" text
                wiki_txt = self._pp.make_txt("Wiki:", obj.x, obj.y)
                self._pp.append_object(wiki_txt)
                obj.x += wiki_txt.brect()[2] + 5
                obj.y += 2

        self._pp.append_list(lst)
        self.current_yoff = brect[1] + brect[3]

    def argument_begin(self, arg):
        y = self.current_yoff
        super(self.__class__, self).argument_begin(arg)

        t1 = self._pp.add_txt("{0}.".format(arg.number()), self.PD_XLET_INDX_XPOS, y)
        t2 = self._pp.add_txt(arg.type(), self.PD_XLET_TYPE_XPOS, y)
        self.add_background_for_txt(arg.main_info_prefix(),
                                    self.PD_XLET_INFO_XPOS,
                                    y,
                                    self.PD_ARG_NAME_COLOR)

        rng = self.format_range(arg)
        t3 = self._pp.add_txt("{0}. {1}".format(arg.main_info(), rng), self.PD_XLET_INFO_XPOS, y)
        _, _, _, h = self._pp.group_brect([t1, t2, t3])
        self.current_yoff += h + 5

    def object_end(self, obj):
        LNK_Y = 45
        # index link
        idx_lnk = self._pp.make_link(0, LNK_Y, "../index-help.pd", "index")
        del1 = self._pp.make_txt("::", 0, LNK_Y)
        # library link
        lib_lnk = self._pp.make_link(0, LNK_Y,
                                     "{0}-help.pd".format(self._library),
                                     "{0}".format(self._library))
        del2 = self._pp.make_txt("::", 0, LNK_Y)
        # category link
        cat_lnk = self._pp.make_link(0, LNK_Y,
                                     "{0}.{1}-help.pd".format(self._library, self._category),
                                     "{0}".format(self._category))
        menu = [idx_lnk, del1, lib_lnk, del2, cat_lnk]
        self._pp.place_in_row(menu, 10, 7)
        self._pp.append_list(menu)
        self.add_footer()

    def render(self):
        return self._pp.to_string()

    @classmethod
    def format_range(cls, obj):
        r = obj.range()
        if len(r) == 2:
            if not r[0]:
                return "Max value: {0}".format(r[1])
            if not r[1]:
                return "Min value: {0}".format(r[0])

            return "Range: {0}...{1}".format(r[0], r[1])
        else:
            return ""

    def add_section(self, txt, yoff):
        hr = self._pp.make_styled_hrule(self.current_yoff)
        self._pp.append_object(hr)
        lbl = self._pp.make_section_label(self.current_yoff + 5, txt, font_size=14)
        self.current_yoff += yoff
        self._pp.append_object(lbl)

    def add_header(self):
        lbl = self.add_header_label()
        self.add_header_example_object(lbl, self._title)

    def add_header_example_object(self, lbl, title):
        seq = []
        alias_objects = filter(lambda n: n["name"] != title, self._aliases)

        for a in alias_objects:
            if 'is_link' in a and a['is_link'] is True:
                seq.append(self._pp.make_header_alias_link(title, a['name']))
            else:
                seq.append(make_by_name(a['name']))

        # append main object name
        # UI object added as link
        if self._is_gui:
            seq.append(self._pp.make_header_alias_link(title, title))
        else:
            seq.append(make_by_name(title))

        self._pp.place_in_row(seq, 0, 20)
        _, _, w, h = self._pp.group_brect(seq)
        y = (lbl.height - h) / 2
        x = (lbl.width - w) - 20
        self._pp.move_to_x(seq, x)
        self._pp.move_to_y(seq, y)
        self._pp.append_list(seq)

    def add_header_label(self):
        return self._pp.add_header("{0}".format(self._title))

    def add_footer(self):
        ft = self._pp.make_footer(self.current_yoff + 20, height=self.PD_FOOTER_HEIGHT)
        y = ft.y
        self._pp.append_object(ft)
        self.add_footer_library(y)
        self.add_also(y + 15)
        self.add_footer_more_info(y)

    def add_footer_more_info(self, y):
        # more info
        pd = self._pp.make_subpatch('info', 10, y + 22, self.PD_INFO_WINDOW_WIDTH, self.PD_INFO_WINDOW_HEIGHT)

        def add_subpatch_text(x, y, txt):
            self._pp.add_subpatch_txt('info', txt, x, y)

        bg = self._pp.make_background(1, 1, 107, self.PD_INFO_WINDOW_HEIGHT - 3, self.PD_FOOTER_COLOR)
        self._pp.add_subpatch_obj('info', bg)
        xc1 = 10
        xc2 = 120
        yrows = range(10, 300, 22)
        row = 0
        add_subpatch_text(xc1, yrows[row], "library:")
        add_subpatch_text(xc2, yrows[row], self._library)
        row += 1
        add_subpatch_text(xc1, yrows[row], "version:")
        add_subpatch_text(xc2, yrows[row], self._version)
        row += 1
        add_subpatch_text(xc1, yrows[row], "object:")
        add_subpatch_text(xc2, yrows[row], self._title)
        row += 1
        add_subpatch_text(xc1, yrows[row], "category:")
        add_subpatch_text(xc2, yrows[row], self._category)
        row += 1

        if self._since:
            add_subpatch_text(xc1, yrows[row], "since:")
            add_subpatch_text(xc2, yrows[row], self._since)
            row += 1

        add_subpatch_text(xc1, yrows[row], "authors:")
        add_subpatch_text(xc2, yrows[row], ", ".join(self._authors))
        row += 1
        add_subpatch_text(xc1, yrows[row], "license:")
        if not self._license.get('url', ' '):
            add_subpatch_text(xc2, yrows[row], self._license['name'])
        else:
            lnk = self._pp.make_link(xc2, yrows[row], self._license['url'], self._license['name'])
            pd.append_object(lnk)
        row += 1
        if self._keywords:
            add_subpatch_text(xc1, yrows[row], "keywords:")
            add_subpatch_text(xc2, yrows[row], ", ".join(self._keywords))
            row += 1
        if self._website:
            add_subpatch_text(xc1, yrows[row], "website:")
            lnk = self._pp.make_link(xc2, yrows[row], self._website, self._website)
            pd.append_object(lnk)
            row += 1
        if self._contacts:
            add_subpatch_text(xc1, yrows[row], "contacts:")
            add_subpatch_text(xc2, yrows[row], self._contacts)
            row += 1

        pd.append_object(PdObject("declare", x=xc2, y=yrows[row], args=["-lib", "ceammc"]))

        ypos = self.PD_INFO_WINDOW_HEIGHT - 22
        delim = self._pp.make_hrule(xc2, ypos, width=270)
        pd.append_object(delim)
        add_subpatch_text(xc2, ypos, "generated by pddoc")
        self._pp.canvas.append_subpatch(pd)

    def add_footer_library(self, y):
        # library:
        self._pp.add_txt("library: {0} v{1}".format(self._library, self._version), 10, y + 3)

    def add_background_for_txt(self, txt, x, y, color, **kwargs):
        if len(txt) < 1:
            return

        padx = kwargs.get("padx", 5)
        pady = kwargs.get("pady", 5)

        c = Comment(x, y, txt.split(' '))
        c.calc_brect()
        bg = self._pp.make_background(x + 1, y + 1, c.width + padx, c.height + pady, color)
        self._pp.append_object(bg)

    def add_also(self, y):
        if len(self._see_also) < 1:
            return

        # see also:
        label = self._pp.make_txt("see also:", 0, 0)
        also_objects = [label]
        for see in self._see_also:
            if 'is_link' in see and see['is_link'] == True:
                lnk = self._pp.make_link(0, 0,
                                         "{0}-help.pd".format(see['name']),
                                         "[{0}]".format(see['name']))
                lnk.set_bg_color(Color(200, 200, 200))
                also_objects.append(lnk)
            else:
                also_objects.append(make_by_name(see['name']))

        self._pp.place_in_row(also_objects, 0, 10)
        _, _, w, h = self._pp.group_brect(also_objects)
        self._pp.move_to_y(also_objects, y)
        self._pp.move_to_x(also_objects, (self._pp.width - w) - 40)
        self._pp.append_list(also_objects)