summaryrefslogtreecommitdiffstats
path: root/share/extensions/inkex/elements/_meta.py
blob: f8107ad0d3e7c3248a6b4dc780070d3c4407f082 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
# -*- coding: utf-8 -*-
#
# Copyright (c) 2020 Martin Owens <doctormo@gmail.com>
#                    Maren Hachmann <moini>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
#
# pylint: disable=arguments-differ
"""
Provide extra utility to each svg element type specific to its type.

This is useful for having a common interface for each element which can
give path, transform, and property access easily.
"""

import math

from lxml import etree

from ..styles import StyleSheet
from ..transforms import Vector2d

from ._base import BaseElement

class Defs(BaseElement):
    """A header defs element, one per document"""
    tag_name = 'defs'

class StyleElement(BaseElement):
    """A CSS style element containing multiple style definitions"""
    tag_name = 'style'

    def set_text(self, content):
        """Sets the style content text as a CDATA section"""
        self.text = etree.CDATA(str(content))

    def stylesheet(self):
        """Return the StyleSheet() object for the style tag"""
        return StyleSheet(self.text, callback=self.set_text)

class Script(BaseElement):
    """A javascript tag in SVG"""
    tag_name = 'script'

    def set_text(self, content):
        """Sets the style content text as a CDATA section"""
        self.text = etree.CDATA(str(content))

class Desc(BaseElement):
    """Description element"""
    tag_name = 'desc'

class Title(BaseElement):
    """Title element"""
    tag_name = 'title'

class NamedView(BaseElement):
    """The NamedView element is Inkscape specific metadata about the file"""
    tag_name = 'sodipodi:namedview'

    current_layer = property(lambda self: self.get('inkscape:current-layer'))

    @property
    def center(self):
        """Returns view_center in terms of document units"""
        return Vector2d(self.root.unittouu(self.get('inkscape:cx') or 0),
                        self.root.unittouu(self.get('inkscape:cy') or 0))

    def get_guides(self):
        """Returns a list of guides"""
        return self.findall('sodipodi:guide')

    def new_guide(self, position, orient=True, name=None):
        """Creates a new guide in this namedview"""
        if orient is True:
            elem = Guide().move_to(0, position, (0, 1))
        elif orient is False:
            elem = Guide().move_to(position, 0, (1, 0))
        if name:
            elem.set('inkscape:label', str(name))
        return self.add(elem)


class Guide(BaseElement):
    """An inkscape guide"""
    tag_name = 'sodipodi:guide'

    is_horizontal = property(lambda self: self.get('orientation').startswith('0,') and not
                                          self.get('orientation') == '0,0')
    is_vertical = property(lambda self: self.get('orientation').endswith(',0'))
    point = property(lambda self: Vector2d(self.get('position')))

    @classmethod
    def new(cls, pos_x, pos_y, angle, **attrs):
        guide = super(Guide, cls).new(**attrs)
        guide.move_to(pos_x, pos_y, angle=angle)
        return guide

    def move_to(self, pos_x, pos_y, angle=None):
        """
        Move this guide to the given x,y position,

        Angle may be a float or integer, which will change the orientation. Alternately,
        it may be a pair of numbers (tuple) which will set the orientation directly.
        """
        self.set('position', "{:g},{:g}".format(float(pos_x), float(pos_y)))
        if isinstance(angle, str):
            if ',' not in angle:
                angle = float(angle)

        if isinstance(angle, (float, int)):
            # Generate orientation from angle
            angle = (math.sin(math.radians(angle)), -math.cos(math.radians(angle)))

        if isinstance(angle, (tuple, list)) and len(angle) == 2:
            angle = "{:g},{:g}".format(*angle)

        self.set('orientation', angle)
        return self

class Metadata(BaseElement):
    """Inkscape Metadata element"""
    tag_name = 'metadata'

class ForeignObject(BaseElement):
    """SVG foreignObject element"""
    tag_name = 'foreignObject'

class Switch(BaseElement):
    """A switch element"""
    tag_name = 'switch'

class Grid(BaseElement):
    """A namedview grid child"""
    tag_name = 'inkscape:grid'