One piece of information which Inkscape sends to an extension is selected elements. The extension receives ids of selected elements as command line arguments from Inkscape.
For example, we have a drawing with 4 selected elements as shown below. When we click
the apply
button on an extension user interface, the extension receives 4 “--id=…”
values as shown in the sys.argv
variable below.
sys argv: ['hello.py', '--id=rect1125', '--id=path1149',
'--id=path1253', '--id=path1358',
'--name=inkscape', '/tmp/ink_ext_XXXXXX.svgUBQJ80']
The id values are the id attributes of selected elements. Because the id attribute is unique for each element, the extension knows which elements are selected.
The inkex
uses argparse
Python standard library module to parse arguments. The
code is in the __init__
method of SvgInputMixin
class (inkex/base.py module).
self.arg_parser.add_argument(
"--id", action="append", type=str, dest="ids", default=[],
help="id attribute of object to manipulate")
self.arg_parser.add_argument(
"--selected-nodes", action="append", type=str,
dest="selected_nodes", default=[],
help="id:subpath:position of selected nodes, if any")
The selected ids will become a list which is accessed as self.options.ids
in an
extension.
self.options : Namespace(input_file='/tmp/ink_ext_XXXXXX.svgUBQJ80',
output=None, name='inkscape',
ids=['rect1125', 'path1149',
'path1253', 'path1358'], selected_nodes=[])
When inkex
loads an SVG file, it will set an instance variable selection
on the SvgDocumentElement
class object. The selection
variable is of type
ElementList
and its value is set in the load
method of SvgInputMixin
class.
self.svg = document.getroot()
self.svg.selection.set(*self.options.ids)
The ElementList
class is defined in the inkex/elements/_selected.py
module.
Even though it is called ElementList
, it subclasses OrderedDict
so it’s a
dictionary. When we iterate through an instance variable, it iterates through
the values of the dictionary and the class acts like a list. The values of
the dictionary are the selected element objects.
We would think that keys of the dictionary are the ids of selected elements and
the values are the corresponding element objects. However, the keys are actually
xml_path
of selected element. The xml_path
is a property defined in the
BaseElement
class and it calls the getpath
method of ElementTree
class.
The lxml documentation
describes that “[getpath method] returns a structural, absolute XPath expression to find the
element”.
ElementList
key is a string value. It’s the value before the colon as shown below.
The first part /*
refers
to the svg
element. The second part /*[3]
refers to g
layer element nested inside svg
.
The g
element is listed after sodipodi:namedview
and defs
elements.
The third part /*[1]
refers to the rect element, which is the first
one nested under g
element.
# ELementList dict format: xml_path to element
/*/*[3]/*[1] : rect
/*/*[3]/*[2] : ellipse
/*/*[3]/*[3] : path
/*/*[3]/*[4] : path
The ElementList
class also defines an ids
instance variable, which is a
dictionary mapping id
to xml_path
. The class also has a method id_dict
which returns a dictionary mapping id
to element
. Why does the class choose
to use xml_path
value as the dictionary key? It is probably for the paint_order
method which returns a list of selected elements by z-order (bottom to top).
One very useful method in the ElementList
class is filter
. We can
filter out elements by type. The method return a new ElementList
object
containing only elements of certain type. The code below shows an
example, and the return value selected_elems
only contains path elements.
from inkex import PathElement
select_elems = self.svg.selection.filter(PathElement)
The bounding_box
method returns a BoundingBox
object for selected elements.
It’s useful when we need to know the size of selected elements such as
the Dimensions
extension.
Inkscape itself preserves the selection order when passing the ids to an extension.
The first element in the ElementList
is the first selected element in Inkscape.
The extension system doesn’t provide a way to transmit selected elements back to
Inkscape, so we can’t modify selections in an Inkscape extension.
Similar to selected elements, Inkscape also passes selected nodes to extensions.
In inkscape we use the node selection tool (shortcut: F2) to select nodes on a path. For example,
the drawing below shows that the first two nodes are selected (blue square dots). When
we click the apply button on an extension interface, the extension receives several
--selected-nodes=...
arguments.
The argument values are in a format shown below. The help message of add_argument
indicates it is in id:subpath:position
format. Notice the subpath
and position
values are both zero based here.
[‘path3535:0:1’, ‘path3535:0:0’]
Searching through the system extension directory, the selected-nodes
values
are not used in any extensions. However, it might be useful when we need to
deal with path nodes in extensions.
15. Selection