From cca66b9ec4e494c1d919bff0f71a820d8afab1fa Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 7 Apr 2024 20:24:48 +0200 Subject: Adding upstream version 1.2.2. Signed-off-by: Daniel Baumann --- share/extensions/docs/Makefile | 20 + share/extensions/docs/_templates/versions.html | 27 + share/extensions/docs/authors/index.rst | 29 + share/extensions/docs/authors/interpreters.rst | 114 ++++ share/extensions/docs/authors/inx-overview.rst | 238 +++++++ share/extensions/docs/authors/inx-widgets.rst | 536 +++++++++++++++ ...Lighter_extension_in_Inkscape_1.1.2_and_1.2.png | Bin 0 -> 36157 bytes .../docs/authors/samples/unit_camera.svg | 730 +++++++++++++++++++++ share/extensions/docs/authors/samples/units1.svg | 4 + share/extensions/docs/authors/samples/units2.svg | 9 + share/extensions/docs/authors/submit.rst | 97 +++ share/extensions/docs/authors/unit-tests.rst | 67 ++ share/extensions/docs/authors/units.rst | 316 +++++++++ share/extensions/docs/authors/update1.0.rst | 301 +++++++++ share/extensions/docs/authors/update1.2.rst | 229 +++++++ share/extensions/docs/authors/widgets/bool.png | Bin 0 -> 1137 bytes share/extensions/docs/authors/widgets/color.png | Bin 0 -> 10374 bytes share/extensions/docs/authors/widgets/float.png | Bin 0 -> 3267 bytes share/extensions/docs/authors/widgets/image.png | Bin 0 -> 17053 bytes share/extensions/docs/authors/widgets/integer.png | Bin 0 -> 3178 bytes share/extensions/docs/authors/widgets/label.png | Bin 0 -> 4230 bytes share/extensions/docs/authors/widgets/notebook.png | Bin 0 -> 1475 bytes .../docs/authors/widgets/optiongroup.png | Bin 0 -> 5632 bytes share/extensions/docs/authors/widgets/path.png | Bin 0 -> 1585 bytes .../extensions/docs/authors/widgets/separator.png | Bin 0 -> 2014 bytes share/extensions/docs/authors/widgets/spacer.png | Bin 0 -> 5345 bytes share/extensions/docs/authors/widgets/string.png | Bin 0 -> 4254 bytes share/extensions/docs/conf.py | 93 +++ share/extensions/docs/dev/getting-started.rst | 148 +++++ share/extensions/docs/dev/index.rst | 8 + share/extensions/docs/favicon.svg | 159 +++++ share/extensions/docs/index.rst | 35 + share/extensions/docs/make.bat | 35 + share/extensions/docs/source/index.rst | 21 + share/extensions/docs/tutorial/index.rst | 49 ++ .../docs/tutorial/my-first-effect-extension.rst | 130 ++++ .../docs/tutorial/my-first-import-extension.rst | 305 +++++++++ .../docs/tutorial/my-first-text-extension.rst | 223 +++++++ .../tutorial/resources/Call_Extension_Failure.png | Bin 0 -> 54314 bytes .../Inkscape_Recognizes_Our_Extension.gif | Bin 0 -> 457560 bytes .../docs/tutorial/resources/Smiles_Format.gif | Bin 0 -> 1015850 bytes .../resources/Text_Ext_Moment_of_truth.gif | Bin 0 -> 941111 bytes .../tutorial/resources/call_extension_success.gif | Bin 0 -> 489312 bytes .../docs/tutorial/resources/make_red_extension.zip | Bin 0 -> 1201 bytes .../tutorial/resources/stroke-parity-widget.png | Bin 0 -> 20362 bytes .../tutorial/resources/stroke_parity_extension.zip | Bin 0 -> 1628 bytes .../docs/tutorial/resources/template_effect.zip | Bin 0 -> 2582 bytes .../docs/tutorial/resources/vanillin.smi | 1 + .../docs/tutorial/simple-path-extension.rst | 162 +++++ 49 files changed, 4086 insertions(+) create mode 100644 share/extensions/docs/Makefile create mode 100644 share/extensions/docs/_templates/versions.html create mode 100644 share/extensions/docs/authors/index.rst create mode 100644 share/extensions/docs/authors/interpreters.rst create mode 100644 share/extensions/docs/authors/inx-overview.rst create mode 100644 share/extensions/docs/authors/inx-widgets.rst create mode 100644 share/extensions/docs/authors/samples/Comparison_of_Lighter_extension_in_Inkscape_1.1.2_and_1.2.png create mode 100644 share/extensions/docs/authors/samples/unit_camera.svg create mode 100644 share/extensions/docs/authors/samples/units1.svg create mode 100644 share/extensions/docs/authors/samples/units2.svg create mode 100644 share/extensions/docs/authors/submit.rst create mode 100644 share/extensions/docs/authors/unit-tests.rst create mode 100644 share/extensions/docs/authors/units.rst create mode 100644 share/extensions/docs/authors/update1.0.rst create mode 100644 share/extensions/docs/authors/update1.2.rst create mode 100644 share/extensions/docs/authors/widgets/bool.png create mode 100644 share/extensions/docs/authors/widgets/color.png create mode 100644 share/extensions/docs/authors/widgets/float.png create mode 100644 share/extensions/docs/authors/widgets/image.png create mode 100644 share/extensions/docs/authors/widgets/integer.png create mode 100644 share/extensions/docs/authors/widgets/label.png create mode 100644 share/extensions/docs/authors/widgets/notebook.png create mode 100644 share/extensions/docs/authors/widgets/optiongroup.png create mode 100644 share/extensions/docs/authors/widgets/path.png create mode 100644 share/extensions/docs/authors/widgets/separator.png create mode 100644 share/extensions/docs/authors/widgets/spacer.png create mode 100644 share/extensions/docs/authors/widgets/string.png create mode 100644 share/extensions/docs/conf.py create mode 100644 share/extensions/docs/dev/getting-started.rst create mode 100644 share/extensions/docs/dev/index.rst create mode 100644 share/extensions/docs/favicon.svg create mode 100644 share/extensions/docs/index.rst create mode 100644 share/extensions/docs/make.bat create mode 100644 share/extensions/docs/source/index.rst create mode 100644 share/extensions/docs/tutorial/index.rst create mode 100644 share/extensions/docs/tutorial/my-first-effect-extension.rst create mode 100644 share/extensions/docs/tutorial/my-first-import-extension.rst create mode 100644 share/extensions/docs/tutorial/my-first-text-extension.rst create mode 100644 share/extensions/docs/tutorial/resources/Call_Extension_Failure.png create mode 100644 share/extensions/docs/tutorial/resources/Inkscape_Recognizes_Our_Extension.gif create mode 100644 share/extensions/docs/tutorial/resources/Smiles_Format.gif create mode 100644 share/extensions/docs/tutorial/resources/Text_Ext_Moment_of_truth.gif create mode 100644 share/extensions/docs/tutorial/resources/call_extension_success.gif create mode 100644 share/extensions/docs/tutorial/resources/make_red_extension.zip create mode 100644 share/extensions/docs/tutorial/resources/stroke-parity-widget.png create mode 100644 share/extensions/docs/tutorial/resources/stroke_parity_extension.zip create mode 100644 share/extensions/docs/tutorial/resources/template_effect.zip create mode 100644 share/extensions/docs/tutorial/resources/vanillin.smi create mode 100644 share/extensions/docs/tutorial/simple-path-extension.rst (limited to 'share/extensions/docs') diff --git a/share/extensions/docs/Makefile b/share/extensions/docs/Makefile new file mode 100644 index 0000000..43276bb --- /dev/null +++ b/share/extensions/docs/Makefile @@ -0,0 +1,20 @@ +# Minimal makefile for Sphinx documentation +# + +# You can set these variables from the command line, and also +# from the environment for the first two. +SPHINXOPTS ?= +SPHINXBUILD ?= sphinx-build +SOURCEDIR = . +BUILDDIR = ../build + +# Put it first so that "make" without argument is like "make help". +help: + @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) + +.PHONY: help Makefile + +# Catch-all target: route all unknown targets to Sphinx using the new +# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). +%: Makefile + @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) diff --git a/share/extensions/docs/_templates/versions.html b/share/extensions/docs/_templates/versions.html new file mode 100644 index 0000000..476c8d1 --- /dev/null +++ b/share/extensions/docs/_templates/versions.html @@ -0,0 +1,27 @@ +{%- if current_version %} +
+ + Other Versions + v: {{ current_version.name }} + + +
+ {%- if versions.tags %} +
+
Tags
+ {%- for item in versions.tags %} +
{{ item.name }}
+ {%- endfor %} +
+ {%- endif %} + {%- if versions.branches %} +
+
Branches
+ {%- for item in versions.branches %} +
{{ item.name }}
+ {%- endfor %} +
+ {%- endif %} +
+
+{%- endif %} \ No newline at end of file diff --git a/share/extensions/docs/authors/index.rst b/share/extensions/docs/authors/index.rst new file mode 100644 index 0000000..8e7b967 --- /dev/null +++ b/share/extensions/docs/authors/index.rst @@ -0,0 +1,29 @@ +Writing Extensions: In-Depth +============================ + +.. toctree:: + :maxdepth: 2 + + inx-overview + inx-widgets + interpreters + unit-tests + submit + +Highlevel explanation of specific inkex features +---------------------------------------------------- + +.. toctree:: + :maxdepth: 2 + + units + +Update guides +------------- + +.. toctree:: + :maxdepth: 2 + + update1.0 + update1.2 + \ No newline at end of file diff --git a/share/extensions/docs/authors/interpreters.rst b/share/extensions/docs/authors/interpreters.rst new file mode 100644 index 0000000..254abd6 --- /dev/null +++ b/share/extensions/docs/authors/interpreters.rst @@ -0,0 +1,114 @@ +.. _supported_interpreters: + +Supported Interpreters +====================== + +Inkscape Script extensions can use one of the following interpreters: + ++----------+------------------+----------------------+------------------+ +| Language | Name (in INX | Name (in | Default value | +| | file) | preferences.xml) | | ++==========+==================+======================+==================+ +| Perl | "perl" | "perl-interpreter" | "perl" | +| | | | | +| | | | "wperl" (Windows;| +| | | | since Inkscape | +| | | | 1.0) | ++----------+------------------+----------------------+------------------+ +| Python | "python" | "python-interpreter" | "python" | +| | | | | +| | | | "pythonw" | +| | | | (Windows) | ++----------+------------------+----------------------+------------------+ +| Ruby | "ruby" | "ruby-interpreter" | "ruby" | ++----------+------------------+----------------------+------------------+ +| Shell | "shell" | "shell-interpreter" | "sh" | ++----------+------------------+----------------------+------------------+ + +(Code reference: `src/extension/implementation/script.cpp`_) + +.. _src/extension/implementation/script.cpp: https://gitlab.com/inkscape/inkscape/-/blob/master/src/extension/implementation/script.cpp + +.. _inx_files: + +INX files +--------- + +Within the INX file, you need to indicate the interpreter which will be +used to execute the script, using the name given in the table above: + +Example: + +:: + + + ... + + + +.. _selecting_a_specific_interpreter_version_via_preferences_file: + +Selecting a specific interpreter version (via preferences file) +--------------------------------------------------------------- + +In the preferences.xml file, a user can set a specific executable of the +interpreter that Inkscape should use to execute extensions of a specific +type. + +This is especially useful, if the system's default version of the +interpreter is incompatible with the one used by Inkscape's extension +subsystem (e.g. Inkscape extensions that rely on inkex.py will only work +with Python 2 (as of Inkscape 0.92.1), while on some recent Linux +distributions, the default Python version used is Python 3, which +results in errors during execution of extensions). + +To change the executable that will be used to run script extensions to a +different value than the default value in the above table, you need to +do the following: + +#. quit all running Inkscape processes +#. Open your perferences.xml file with a text editor (find the exact + location of the file by going to Edit -> Preferences -> System: User + Preferences) +#. search the group which holds settings for the extension system itself + and options of various extensions: + :: + + + +#. Insert a key for the interpreter, for example 'python-interpreter' + for setting the program that should be used to run python extensions, + and set the string to the absolute path to the python binary which is + compatible with Inkscape's current extension scripts (in the example + below, the path is "/usr/bin/python2.7". It will look different on + Windows systems.): + :: + + + +#. Save the preferences file, and launch Inkscape to test the + extensions. + +.. _see_also: + +See Also +-------- + +- `INX Parameters `__ +- `ScriptingHOWTO `__ + +`Category:Developer Documentation `__ +`Category:Extensions `__ diff --git a/share/extensions/docs/authors/inx-overview.rst b/share/extensions/docs/authors/inx-overview.rst new file mode 100644 index 0000000..83843d4 --- /dev/null +++ b/share/extensions/docs/authors/inx-overview.rst @@ -0,0 +1,238 @@ +INX extension descriptor format +=============================== + + +.. highlight:: xml + +Introduction +------------ + +In order for Inkscape to make use of an external script or program, you +must describe that script to inkscape using an INX file. The INX file is +an XML file with Inkscape-specific content that can be edited in a +plain-text editor. + +The INX file allows the author to: + +- Specify what type of extension it is, for example input, output, or + effect +- Identify :ref:`which interpreter ` should be used to run the extension +- List dependencies; files or other extensions required for operation +- Define parameters that can be set in the extension +- Create :ref:`a GUI with control widgets ` for those parameters +- Add a submenu to the Extensions menu for the extension to reside in +- Label strings for translation +- Chain extensions +- Etc + +Nothing beats a working example, and Inkscape includes a great number of +extensions with INX files that you can read. To find the location of +your Inkscape extensions directory, where included extensions and their +INX files are located, look in the System pane of Inkscape Preferences, +under "Inkscape extensions". + +.. _translation_of_extensions: + +Translation of extensions +------------------------- + +Extension dialog windows, described in INX files, can be prepared for +translation or localisation by adding an ``_`` (underscore) to the XML +tags or attributes. Only add underscores when text needs to be +translated (not numeric values, for example!). + +Example:: + + <_name>Some translatable extension name + +Or:: + + + +When extensions are included in the `Inkscape Extensions Repository`_, +various scripts will scan each INX file for translatable text and +prepare `translation files`_ for others to translate. + +See also: `Ted's blog`_. + +.. _attributes_description: + +Attributes description +---------------------- + ++---------------------------+-------------------------+ +| Attribute name | Allowed values | ++===========================+=========================+ +| ``implements-custom-gui`` | ``"true"`` | | +| | ``"false"`` (default) | +| .. versionadded:: 1.0 | | ++---------------------------+-------------------------+ +| If set to ``true`` **requires** an effect | +| extension to implement custom GUI. | +| | +| .. hint:: | +| *Implementation detail:* The "extension is | +| working" window is not shown for this kind of | +| extensions. This means user interaction with the | +| Inkscape interface is blocked until the | +| extension returns, with no way for the user to | +| abort the running extension! It is therefore | +| **absolutely essential** that your extension | +| provides the necessary visual feedback for the | +| user and has proper error handling, to rule out | +| any dead-locking behavior. | ++---------------------------+-------------------------+ +| ``needs-document`` | ``"true"`` (default) | | +| | ``"false"`` | +| .. versionadded:: 1.0 | | ++---------------------------+-------------------------+ +| If set to ``false`` an effect extension will not be | +| passed a document nor will a document be read back | +| ("no-op" effect). This is currently a hack to make | +| extension manager work and will likely be | +| removed/replaced in future, so use at your | +| **own risk**! | ++---------------------------+-------------------------+ +| ``needs-live-preview`` | ``"true"`` (default) | +| | ``"false"`` | ++---------------------------+-------------------------+ +| If set to ``true`` in an effect extension, it will | +| offer a "Live preview" checkbox in its GUI. When | +| the user checks that box, it will run the extension | +| in a "preview mode", visually showing the effect of | +| the extension, but not making any changes to the | +| SVG document, unless the user clicks the Apply | +| button. While "Live preview" is checked in the GUI, | +| any changes that the user makes to parameters | +| accessible in the GUI will generate an updated | +| preview. | ++---------------------------+-------------------------+ +| ``savecopyonly`` | ``"true"`` | | +| | ``"false"`` (default) | +| .. versionadded:: 1.2 | | ++---------------------------+-------------------------+ +| If set to ``true`` in an **output** extension, it | +| will limit the extension to being available only | +| in the "Save a Copy" menu. | ++---------------------------+-------------------------+ + + +Example +------- + +:: + + + + <_name>{Friendly Extension Name} + {org.domain.sub-domain.extension-name} + program.ext + + + {default value} + + + {Friendly Extension Help} + + + + [all|{element type}] + + + + + + + +More example INX files are available in the Inkscape distribution, which +takes its files from the `Inkscape Extensions Repository`_. + +For a full list of currently supported interpreters, please see +:ref:`supported_interpreters`. + +.. _dtd_xml_schema: + +DTD XML schema +-------------- + +.. warning:: This section contains slightly outdated information. + +The following XML schema may not fully describe the current INX file +structure. The actual XML schema used is described in the :ref:`next +paragraph `. + +:: + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +.. _relax_ng_xml_schema: + +RELAX NG XML schema +------------------- + +The XML schema for INX files is available in the `Inkscape extensions +Git repository`_. This is a `RELAX NG schema`_. + +.. _see_also: + +.. _next paragraph: INX_extension_descriptor_format#RELAX_NG_XML_schema +.. _Inkscape extensions Git repository: https://gitlab.com/inkscape/extensions/-/blob/master/inkscape.extension.rng +.. _RELAX NG schema: http://www.relaxng.org/ +.. _INX Parameters: Extensions:_INX_widgets_and_parameters +.. _ScriptingHOWTO: ScriptingHOWTO + +.. _Inkscape Extensions Repository: https://gitlab.com/inkscape/extensions +.. _a GUI with control widgets: Extensions:_INX_widgets_and_parameters +.. _translation files: https://gitlab.com/inkscape/inkscape/-/tree/master/po +.. _Ted's blog: http://gould.cx/ted/blog/Translating_Custom_XML \ No newline at end of file diff --git a/share/extensions/docs/authors/inx-widgets.rst b/share/extensions/docs/authors/inx-widgets.rst new file mode 100644 index 0000000..5c4e1d5 --- /dev/null +++ b/share/extensions/docs/authors/inx-widgets.rst @@ -0,0 +1,536 @@ +.. _inx-widgets: + +INX widgets and parameters +========================== + +This page contains the reference documentation for INX widgets and +parameters. Their primary goal is to make it easy to design GUIs for +`Inkscape Extensions `__ using the built-in `INX +extension descriptor format `__, +although (invisible) parameters can also be used for extensions that +don't need to show a user interface. + +Introduction +------------ + +Extension GUIs consists of an arbitrary number of GUI elements, +so-called `Widgets <#Widgets>`__. These can be simple text labels, boxes +and spacers to control layout or more complex UI elements like images. + +A special class of Widgets are `Parameters <#Parameters>`__. They differ +from other Widgets in that they have a user-settable value, for example +a boolean (implemented as checkbox) or integer (implemented as number +entry). The value of each Parameter is passed to the extension on +execution and can be used to control its behavior. + +All Widgets are described using an easy-to-learn XML schema with +predefined tags and attributes which are described in detail below. + +.. _available_widgets: + +Available Widgets +~~~~~~~~~~~~~~~~~ + +A general Widget takes the form + +.. code:: + + value + +where ``widget_name`` specifies the name of the widget and is one of the +following: + +- ``label``:sup:`since 1.0`\ +- ``hbox``:sup:`since 1.0`\ /``vbox``:sup:`since 1.0`\ +- ``separator``:sup:`since 1.0`\ /``spacer``:sup:`since 1.0`\ +- ``image``:sup:`since 1.0`\ +- ``param`` (for all Parameter types) + +.. _apt: + +Available Parameter types +~~~~~~~~~~~~~~~~~~~~~~~~~ + +A general Parameter takes the form + +.. code:: + + value + +where ``parameter_type`` specifies the type of the parameter and is one +of the following: + +- ``bool``:sup:`since 1.0`\ +- ``int`` +- ``float`` +- ``string`` +- ``path``:sup:`since 1.0`\ +- ``optiongroup`` +- ``notebook`` +- ``color`` + +If a parameter is made invisible (see ``gui-hidden`` attribute in the +`next section <#common-attributes>`__) it will not be shown in the GUI +but it's value is still passed to an extension. This is useful if you +want to hardcode parameter value the user should not be able to change. +If all parameters (and potential widgets) are invisible, Inkscape will +not show a GUI and execute the extension immediately instead, but will +still pass the values of the invisible parameters. + +.. _common_attributes: + +Common attributes +----------------- + +For all widgets +~~~~~~~~~~~~~~~ + ++------------------+------------------+------------------+------------------+ +| Attribute | Allowed | Default | Required? | +| name | value(s) | value | | ++==================+==================+==================+==================+ +| ``gui-hidden`` | ``true``, | | | +| | ``false`` | ``false`` | optional | ++------------------+------------------+------------------+------------------+ +| If set to ``true`` the Widget is hidden from the GUI (primarily used to | +| add hidden parameters that are passed to the extension but are not | +| supposed to be editable by the user.) | +| | +| *Note: If there are* **no** *visible parameters defined in a GUI, the | +| extension is executed immediately without showing a dialog.* | ++------------------+------------------+------------------+------------------+ +| ``indent`` | ``0,1,2,…`` | ``0`` | optional | ++------------------+------------------+------------------+------------------+ +| Sets indentation level of the parameter. Increasing indentation adds | +| padding to the start of the line. | ++------------------+------------------+------------------+------------------+ + + + +Only for Parameters +~~~~~~~~~~~~~~~~~~~ + ++------------------------+------------------------+------------------------+------------------------+ +| Attribute name | Allowed value(s) | Default value | Required? | ++========================+========================+========================+========================+ +| ``name`` | *(text)* | -- | required | ++------------------------+------------------------+------------------------+------------------------+ +| Used as an identifier of the parameter. It has to be unique since the value of this attribute is | +| used to save and transmit parameter values internally! | ++------------------------+------------------------+------------------------+------------------------+ +| ``type`` | see `above <#apt>`__ | -- | required | ++------------------------+------------------------+------------------------+------------------------+ +| Determines the type of the parameter, see the extensive description of | +| `Parameters <#parameters>`__ below. | ++------------------------+------------------------+------------------------+------------------------+ +| ``gui-text`` | *(text)* | -- | required *(visible | +| | | | parameters)*, optional | +| | | | *(hidden parameters* + | +| | | | ``notebooks`` *)* | ++------------------------+------------------------+------------------------+------------------------+ +| Label shown for the parameter in the GUI. | ++------------------------+------------------------+------------------------+------------------------+ +| ``gui-description`` | *(text)* | -- | optional | ++------------------------+------------------------+------------------------+------------------------+ +| Tooltip shown for the parameter when the user hovers the mouse cursor over the active area of the | +| parameter in question. | ++------------------------+------------------------+------------------------+------------------------+ + + + +Widgets +------- + +``hbox`` / ``vbox`` +~~~~~~~~~~~~~~~~~~~ + +Creates a container for other widgets. No visual rendering but provides a possibility to align and +layout other widgets. Child widgets are either added in horizontal (``hbox``) or vertical +(``vbox``) direction. + + .. code:: xml + + + + +A box can contain an arbitrary number of other widgets and parameters (including other boxes) to +fine-tune the layout of the GUI. + +*Note*: When you start with an empty extension GUI, you're basically starting with a ``vbox``. +Also ``notebook`` pages behave like vertically oriented boxes. + +.. figure:: widgets/separator.png + :alt: Rendering of hbox/vbox + + ``hbox`` and ``vbox`` + +``image`` +~~~~~~~~~ + +Creates a widget displaying an image. The content of the node specifies +the path of the image file (ideally specify a path relative to the .inx +file itself). + +.. code:: xml + + path/to/image.svg + +By default the image will be rendered at it's actual size. Use +attributes ``width/heigth`` to override the default size (in this case +*both* attributes need to be supplied; units are pixels). + +Images are aligned in the horizontal center of the current box; different alignment +can be realized by wrapping the image in a `hbox <#hbox-vbox>`__ and adding a +`spacer <#spacer>`__ with ``size=expand`` +before (for right alignment) or after (for left alignment) of the image. + +*Implementation note: Loadable image formats are determined by GdkPixbuf +and therefore system-specific. PNG should always work and is the safe +choice. SVG should mostly work and is the preferred choice for obvious +reasons.* + +.. figure:: widgets/image.png + :alt: Rendering of image + + An ``image`` + +``label`` +~~~~~~~~~ + +Creates a widget showing text. The content of the node corresponds to +the text content that will be rendered. + +.. code:: xml + + + +*Note: Labels are intended to provide additional information / help. For +labeling parameters use the ``gui-text`` attribute; for short help texts +that are specific to a single parameter prefer ``gui-description`` which +will render as a tooltip.* + +- When setting the attribute ``appearance="header"`` the text is styled + as a heading and can be used as another possibility to group + parameters. +- | When setting the attribute ``appearance="url"`` the text is rendered + as a clickable link. + | *Note: The text is escaped and used as the link target as-is. + Creating a link text that differs from the URL is prevented for + security reasons.* +- When setting the attribute ``xml:space="preserve"`` any white-space + (spaces, tabs, line-breaks, etc.) in the label will be preserved, + allowing to format the label accordingly. By default all + leading/tailing and intermediary whitespace is collapsed into a + single space character. + +.. figure:: widgets/label.png + :alt: Rendering of different labels + + Different label types (in order): default | ``appearance="header"`` | + ``appearance="url"`` | ``xml:space="preserve"`` + +``separator`` +~~~~~~~~~~~~~ + +Creates a separator for visual separation of other widgets. Renders as a +horizontal/vertical line. + +.. code:: xml + + + +The direction of the separator will automatically adjust depending on +direction of the current container (vertical for "empty" extension GUIs +and ``notebook`` pages; vertical/horizontal for ``vbox`` and ``hbox`` +respectively). + +.. figure:: widgets/separator.png + :alt: Rendering of separators + + Separators can be used in `hbox` and `vbox` environments. + +``spacer`` +~~~~~~~~~~ + +Creates a spacer for visual separation of other widgets. No visual +rendering but provides variable spacing. + +.. code:: xml + + + +The direction of the spacer will automatically adjust depending on +direction of the current container (vertical for "empty" extension GUIs +and ``notebook`` pages; vertical/horizontal for ``vbox`` and ``hbox`` +respectively). + +Use the ``size`` attribute to set the spacing in pixels (default: +``size="10"``). The special value ``expand`` results in a spacer that +grows dynamically and always uses up as much space as possible (useful +for aligning content). + +.. figure:: widgets/spacer.png + :alt: Rendering of spacers + + Different spacer types: (1) default, (2) ``size="30"``, (3) ``size="expand"`` + +Parameters +---------- + +``bool`` +~~~~~~~~ + +.. versionadded:: 1.0 + +Creates a checkbox to set a **boolean value**. Allowed values are +``true`` or ``false`` (default value: ``true``). + +.. code:: xml + + false + +.. figure:: widgets/bool.png + :alt: Checkbox + + Rendering of ``boolean`` values + + +``color`` +~~~~~~~~~ + +Creates a control to select an **RGBA color value**. Values should be +given in hexadecimal notation, e.g. ``0xff0000ff`` for red with full +opacity (default value: ``0x000000ff``) + +.. code:: xml + + 0x000000ff + +Use ``appearance="colorbutton"`` for a simple button that opens a +simplified color picker. Otherwise a full ColorNotebook will be +rendered. + +.. figure:: widgets/color.png + :alt: Rendering of color parameter + + Rendering of a full ColorNotebook for a ``color`` parameter + +.. versionchanged:: 1.0 + + *Implementation note:* colors values are internally treated as 32-bit + unsigned integers (unsigned long). Acceptable default values include + everything the standard library function ``strtoul`` [#]_ understands (since Inkscape 1.0). + Earlier Inkscape version only handled decimal numbers. The value passed + to the extension script will also be a decimal number. + + + +``float`` +~~~~~~~~~ + +Creates a input to enter a **floating point number**. Limit the input +range with the ``min`` and ``max`` attributes; set the number of decimal +places with the ``precision`` attribute. (defaults: ``min="0"``, +``max="10"`` and ``precision="1"``; default value: 0) + +.. code:: xml + + 1.234 + +Use the attribute ``appearance="full"`` to create a slider with which +the value can be adjusted dynamically over the full range. + +.. figure:: widgets/float.png + :alt: Rendering of float parameter + + Rendering of ``float`` parameters: default and with ``appearance="full"`` + +``int`` +~~~~~~~ + +Creates a textbox input to enter an **integer number**. Limit the input +range with the ``min`` and ``max`` attributes. (defaults: ``min="0"`` +and ``max="10"``; default value: 0) + +.. code:: xml + + 1 + +Use the attribute ``appearance="full"`` to create a slider with which +the value can be adjusted dynamically over the full range. + +.. figure:: widgets/integer.png + :alt: Rendering of integer parameter + + Rendering of ``int`` parameters: default and with ``appearance="full"`` + + +``notebook`` +~~~~~~~~~~~~ + +Creates a set of pages (aka tab control). The user can switch between +individual pages. Each page can contain an arbitrary set of other +Widgets and Parameters. Individual pages are created with the element. + +The **returned value** for ``notebook`` parameters is the value of the +``name`` attribute of the selected . By default the first page is +selected. + +Notebooks can be used to show widgets based on an option; that option +would be implemented as notebook. + +.. code:: xml + + + + … + + + … + + + +.. figure:: widgets/notebook.png + :alt: Rendering of notebook parameter + + Rendering of a ``notebook`` + + +``optiongroup`` +~~~~~~~~~~~~~~~ + +Creates a control that allows to select one option **one option** from a +set of multiple choices. The different choices are created with +elements. + +The **returned value** for ``optiongroup`` type parameters is the value +of the ``value`` attribute of the selected . By default the first is +selected. + +.. code:: xml + + + + + + +.. versionadded:: 1.0 + Set the attribute ``appearance="radio"``\ to render radio buttons + (default). Set the attribute ``appearance="combo"``\ to display a + drop-down list instead. + +.. figure:: widgets/optiongroup.png + :alt: Rendering of float parameter + + Rendering of ``optionsgroup`` parameters: ``appearance="radio"`` and + ``appearance="combo"``. On the bottom parameter, ``precision="1"`` + has been set. + + +``path`` +~~~~~~~~ + + +.. versionadded:: 1.0 + +Creates a control to choose a **path**. Paths can either be entered +manually or by using the file chooser that can be opened using the +ellipsis button. + +The ``mode`` attribute allows to set behavior of the file chooser (i.e. +if files or folders can be selected, if they need to exist previously +and if multiple selections are possible). The ``filetypes`` attribute +holds a comma-separated list of file extensions and restricts the +selectable file types in file picker mode. + +.. code:: + + + +Possible values for the ``mode`` attribute: + +- ``file`` - select a single existing file +- ``files`` - select multiple existing files +- ``folder`` - select a single existing folder +- ``folders`` - select multiple existing folders +- ``file_new`` - select a single new file name +- ``file_new`` - select a single new folder name + +Examples + +- Files: + + - Choose a file, with file type restriction (optional): + + .. code:: xml + + my/path/to/file.png + - Choose multiple files (file type restriction possible, too): + + .. code:: xml + + my/path/to/file.png + - Create a new file: + + .. code:: xml + + my/path/to/file.png + +- Folders: + + - Choose a folder: + + .. code:: xml + + my/path/ + - Choose multiple folders: + + .. code:: xml + + my/path/ + - Create a new folder: + + .. code:: xml + + my/path/ + + +.. figure:: widgets/path.png + :alt: Rendering of path parameter + + Rendering of ``path`` parameters + + +*Implementation note:* Existence of paths are not checked before passing +them to the extension, so extension authors need to implement suitable +error handling, especially in case of manual path entry. For multiple +selections the individual paths are joined using the pipe character +("|") and passed to the extension as a single string. + +``string`` +~~~~~~~~~~ + +Creates a input to enter a **string**. Limit the number of characters +the user is allowed to enter with the ``max-length`` attribute. +(defaults: no character limit; default value: empty string) + +.. code:: xml + + Some default text + +.. versionadded:: 1.0 + Set the attribute ``appearance="multiline"``\ to render a multi-line + input. Line-breaks will be encoded as literal ``\n`` in the value passed + to the extension. + +.. figure:: widgets/string.png + :alt: Rendering of string parameters + + Rendering of ``string`` parameters: default and + ``appearance="multiline"`` + + + +.. [#] https://en.cppreference.com/w/cpp/string/byte/strtoul \ No newline at end of file diff --git a/share/extensions/docs/authors/samples/Comparison_of_Lighter_extension_in_Inkscape_1.1.2_and_1.2.png b/share/extensions/docs/authors/samples/Comparison_of_Lighter_extension_in_Inkscape_1.1.2_and_1.2.png new file mode 100644 index 0000000..2d16fde Binary files /dev/null and b/share/extensions/docs/authors/samples/Comparison_of_Lighter_extension_in_Inkscape_1.1.2_and_1.2.png differ diff --git a/share/extensions/docs/authors/samples/unit_camera.svg b/share/extensions/docs/authors/samples/unit_camera.svg new file mode 100644 index 0000000..3a4bad4 --- /dev/null +++ b/share/extensions/docs/authors/samples/unit_camera.svg @@ -0,0 +1,730 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + canvas (infinitely large) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 25 mm + 50 mm + 75 mm + 0 mm + + + + 25 mm + 50 mm + 0 mm + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + viewport coordinate system + + diff --git a/share/extensions/docs/authors/samples/units1.svg b/share/extensions/docs/authors/samples/units1.svg new file mode 100644 index 0000000..b221eda --- /dev/null +++ b/share/extensions/docs/authors/samples/units1.svg @@ -0,0 +1,4 @@ + + + \ No newline at end of file diff --git a/share/extensions/docs/authors/samples/units2.svg b/share/extensions/docs/authors/samples/units2.svg new file mode 100644 index 0000000..cf2fe17 --- /dev/null +++ b/share/extensions/docs/authors/samples/units2.svg @@ -0,0 +1,9 @@ + + + + + + + + \ No newline at end of file diff --git a/share/extensions/docs/authors/submit.rst b/share/extensions/docs/authors/submit.rst new file mode 100644 index 0000000..c140009 --- /dev/null +++ b/share/extensions/docs/authors/submit.rst @@ -0,0 +1,97 @@ +Submitting and reviewing extensions +=================================== + +This page details how extensions can be submitted to and moderated on +the Inkscape website. + +I want to submit my extension +----------------------------- + +Go through each of these actions and check to make sure your extension +is ready to be made available in Inkscape: + +#. Check for limitations + + * Your extension must not contact the internet (unless exempted for a good reason) + * It must not self-update, or edit files in the config directory. + * It must be readable code, in English. Code in other languages or too obscure may not be accepted. + +#. Check the license of your code + + * Your code must be Free and Open Source. Using one of the available licenses such + as GPL, AGPL, MIT, Apache2 etc. + * Every included dependency must be also Free and Open Source. + +#. Check all of your dependencies + + * Your extension MUST be python based (except for template extensions) + * It MUST work with python 3.6 or later + * Any dependency not shipped with Inkscape MUST be packaged along side your + extension. For example jinja2 would be included in a folder. + +#. Create a zip file of your extension and any external depdencies. + + * Include only one copy in the root of the zip file. + * No specific versions for windows or linux, macOS. + +#. Check which versions of Inkscape it works with (each one, make a note for tagging + later) + + * set the variable "INKSCAPE_PROFILE_DIR=/tmp/folder" + * run the inkscape version + * open the extensions manager + * install the zip file you hope to submit (second tab, folder button at the bottom) + * Your extension MUST work with at least one version of Inkscape. + +#. Sign your zip file + + * Use GnuPG to sign your zip file, use the same signature as the public key you + uploaded to inkscape.org + * OR use md5hash to create a less secure md5 signature of the zip file. Make sure + you have some text in your inkscape.org gnupg key profile setting so you see the + signature field when uploading. + +#. Upload the zip file to the extensions category in the website. + + * Include the generated signature + * Title and description in English with as much detail as possible + * Add Inkscape versions as you tested above. + * Include a link to the Git repository. + * Include an icon and screenshot file. + +#. Send a message to the Inkscape extensions team on `RocketChat`_ asking for a review. + +.. _RocketChat: https://chat.inkscape.org/channel/inkscape_extensions + +I want to review a submission +----------------------------- + +Extensions Reviewer Checklist +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +- ☐ Take next popular extension [#]_ or request to review +- ☐ Check for existing verification signature +- ☐ Contact author to inform about review +- ☐ Unpack zip to extensions folder +- ☐ Check zip contents for inx and py file +- ☐ Check for license header and/or file +- ☐ Run pytest and record test coverage +- ☐ Run pylint to get code quality score +- ☐ Visually confirm no mallicious or internet code +- ☐ If no tests, add simple test upstream [#]_ +- ☐ Install zip using extensions manager +- If everything is correct … +- ☐ Add version tags and any other tags +- ☐ Edit description, title, logos to improve presentation +- ☐ contact a website administrator to complete + +If everything is correct (must be admin): +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +- ☐ Add testing and quality scores to decription +- ☐ Generate signature key and upload +- ☐ Generate md5 if package is not self-signed + +.. [#] https://inkscape.org/gallery/=extension/ + +.. [#] Add simple inkex.tester comparision test \ No newline at end of file diff --git a/share/extensions/docs/authors/unit-tests.rst b/share/extensions/docs/authors/unit-tests.rst new file mode 100644 index 0000000..3384d59 --- /dev/null +++ b/share/extensions/docs/authors/unit-tests.rst @@ -0,0 +1,67 @@ +.. _unittests: + +Writing unit tests +================== + +All Inkscape extensions should come with tests. This package provides you with +the tools needed to create tests and thus ensure that your extension continues +to work with future versions of Inkscape, the "inkex" python modules, and other +python and non-python tools you may use. + +Make sure your extension is a python extension and is using the +:py:mod:`inkex.extensions` base classes. These provide the greatest amount of +functionality for testing. + +You should start by creating a folder in your repository called ``tests`` with +an empty file inside called ``__init__.py`` to turn it into a module folder. + +For each of your extensions, you should create a file called +``test_{extension_name}.py`` where the name reflects the name of your extension. + +There are two types of tests: + +1. Full-process Comparison tests - These are tests which invoke your + extension with various arguments and attempt to compare the + output to a known good reference. These are useful for testing + that your extension would work if it was used in Inkscape. + + Good example of writing comparison tests can be found in the + Inkscape core repository, each test which inherits from + the ComparisonMixin class is running comparison tests. + +2. Unit tests - These are individual test functions which call out to + specific functions within your extension. These are typical + python unit tests and many good python documents exist + to describe how to write them well. For examples here you + can find the tests that test the inkex modules themselves + to be the most instructive. + +When running a test, it will cause a certain fraction of the code within the +extension to execute. This fraction called it's **coverage** and a higher +coverage score indicates that your test is better at exercising the various +options, features, and branches within your code. + +.. versionadded:: 1.2 + ``EXPORT_COMPARE`` environment variable + +Generating comparison output can be done using the EXPORT_COMPARE environment +variable when calling pytest and comes in 3 modes, the first of which is the +CHECK comparisons mode:: + + EXPORT_COMPARE=1 pytest tests/test_my_specific_test.py + +This will create files in ``tests/data/refs/*.{ext}`` and these files +should be manually checked to make sure they are correct. Once you are happy +with the output you can re-run the test with the WRITE comparisons mode:: + + EXPORT_COMPARE=2 pytest tests/test_my_specific_test.py + +Which will create an output file of the right name and then run the test suite +against it. But only if the file doesn't already exist. The final mode is the +OVERWRITE comparisons mode:: + + EXPORT_COMPARE=3 pytest tests/test_my_specific_test.py + +This is like mode 2, but will over-write any existing files too. This allows +you to update the test compare files. + diff --git a/share/extensions/docs/authors/units.rst b/share/extensions/docs/authors/units.rst new file mode 100644 index 0000000..055fbfd --- /dev/null +++ b/share/extensions/docs/authors/units.rst @@ -0,0 +1,316 @@ +.. _units: + +Units +================= + +If you are reading this page, you are probably confused about how units work in Inkscape, inkex and +SVG in general. This is understandable, since there's quite a bit of conflicting information online. + +Units in SVG +------------ + +SVG means "scalable vector graphics". This introduces an inherent difficulty with how to map units +to the real world. Should units be pixels? Millimeters? Something else? The answer to this depends +on the output format you're targeting. + +The authors of the SVG specification solved this problem by introducing an abstract "dimensionless" +unit called **user units**. The SVG1.1 specification [1]_ is quite clear about their definition: + + *One px unit is defined to be equal to one user unit. + Thus, a length of "5px" is the same as a length of "5".* + +So whenever you read "user unit", think "pixel". And when you encounter a coordinate without unit, +it's specified in user units, i.e. pixels. You might have heard or read something like "I can choose +the unit of a document, so that one user unit equals one millimeter". This statement is misleading, +although not entirely wrong. It will be explained below. + +An `` tag has two different properties that influence its size and the mapping of coordinates. +These are called *viewport coordinate system* and *user coordinate system*. + +And as the name indicates, **user units always refer to the user coordinate system**. So for +the next section which explains the **viewport coordinate system**, forget user units. + +Viewport coordinate system +^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The viewport coordinate system is [2]_ + + *[...] a top-level SVG viewport that establishes a mapping between the coordinate system used by the + containing environment (for example, CSS pixels in web browsers) and user units.* + +The viewport coordinate system is established by the ``width`` and ``height`` attributes of the SVG tag. +To reformulate the quote above: The viewport tells the SVG viewer how big the visible part of the +canvas should be *rendered*. It may be ``200px x 100px`` on your screen (``width="200px" height="100px"``) +or ``210mm x 297mm`` (``width="210mm" height="297mm"``), i.e. one A4 page. + + *If the width or height presentation attributes on the outermost svg element are in user units + (i.e., no unit identifier has been provided), then the value is assumed to be equivalent to the + same number of "px" units.* [3]_ + +Expressed in simple terms: if no unit has been specified in the ``width`` or ``height`` attributes, +assume the user means pixels. Otherwise, the unit is converted by the SVG viewer. Inkscape uses a +DPI of 96 px/in, and corresponding conversions for mm, yd etc. are used. + +Consider the following SVG file: + +.. code-block:: XML + + + + + +which renders as follows: + +.. image:: samples/units1.svg + +If your browser zoom is set to 100%, this image should have a size of 100 times 200 pixels, +and is filled with a grey rectangle. You can verify this by taking a screenshot. + +Likewise, in ``mm`` based documents, you might see code such as +``width="210mm" height="297mm"`` which tells an standard-compliant program that if printed or +exported to PDF, the document should span an entire A4 page. + +User coordinate system +^^^^^^^^^^^^^^^^^^^^^^^^^^ + +You may have noticed that we didn't explicitly specify in the above svg that we want to draw +everything within the area with the coordinates ``0 ≤ x ≤ 200`` and ``0 ≤ y ≤ 100``. This was +done for us automatically since we specified ``width`` and ``height``. The ``viewBox`` attribute +allows to change this. + +Again from the specification [4]_: + + *The effect of the viewBox attribute is that the user agent automatically supplies the + appropriate transformation matrix to map the specified rectangle in user coordinate system + to the bounds of a designated region (often, the SVG viewport).* + +Let's break this down. Imagine the ``viewBox`` attribute as a camera that moves over the infinite +canvas. It can zoom in or out and move around - but whatever image the camera outputs, it is +rendered in the rectangle defined by ``width`` and ``height``, i.e. the viewport. Initially, the +camera is located such that the region ``viewBox="0 0 width height"`` is pictured. We may +however modify the viewBox as we wish. + +In a ``mm`` based documents, where we specified ``width="210mm" height="297mm"``, the viewbox is +initially ``viewBox="0 0 793.7 1122.5"`` due to the conversion from mm to px. This means that the +bottom right corner is at ``(210, 297) mm * 1/25.4 in/mm * 96 px/in ≈ (793.7, 1122.5) px``. + +As already mentioned: no units means user unit means pixels. So a rectangle with +``x="793.7" y="1122.5"`` (no units specified) is at the bottom right corner of the page. It would be +nicer if unitless values would be implicitly in millimeters, so we could specify such a rectangle +with ``x="210" y="297"``. This can be done with the ``viewBox`` attribute and will be explained with +an example SVG. + +Let's say we want to design a business card that should eventually be *printed on 84mm x 56mm*, so +we specifiy ``width="84mm" height="56mm"```. We also want the user units to behave like real-world +millimeters, so we have to zoom the viewbox camera: ``viewBox="0 0 84 56"``. As mentioned above, +no units means px, so these attributes together tell the SVG viewer "move the camera in such a way +that (84, 56) in user units, i.e. px, is the bottom right corner, and scale the image such that when +printed or rendered it has a size of 84mm by 56mm". + +You can imagine this situation like this [5]_: + +.. image:: samples/unit_camera.svg + +To illustrate this, we draw a crosshair at ``(14, 21)`` (note: no units in the path specification!), +i.e. a fourth horizontally and vertically for reference. Then we draw three circles: one at +``(21, 14)``, one at ``(21px, 14px)`` and one at ``(21mm, 14mm)``. + +.. code-block:: XML + + + + + + + + + + +.. image:: samples/units2.svg + +The rendered image at 100% browser resolution should be approximatly ``85mm`` by ``56mm``, but this +highly depends on your screen resolution. + +Note that the first two circles specified without unit +(i.e. user units) and specified in px are at the correct position and identical except for radius +and stroke color. + +The third circle's coordinates, radius and stroke-width are specified in mm. It should be located +somewhere near the bottom right corner (where exactly depends on the DPI conversion of your browser, +but most browsers use ``96dpi = 96 px/in`` today, which yields a conversion factor of approx. +``3.77px/mm``). The stroke is thicker by the same factor and the radius has been reduced to be +comparable to the first circle. + +This is somewhat unintuitive. Didn't we create a mm based document? Now we can explain the +statement from the introduction +"I can choose the unit of a document, so that one user unit equals one millimeter". +We didn't change the core statement "no unit = user unit = pixels" by specifying width and +height in mm. But the special choice of the viewbox attribute - the same width and height, but +without the unit) makes the following statement true: "**One user unit looks like one millimeter on +the output device** (e.g. screen or paper)". + +Now you understand why appending "mm" to the circle's position moved it. The transformation px->mm +has been applied twice! Once in the coordinate specification itself, and once by the "camera". + + +Units in Inkex +----------------- + +As an extension autor, you may have four different questions regarding units. + +What is the position of this object [in the user coordinate system]? +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +This is a question that typically needs to be answered if you want to position an object relative +to other objects, whose coordinates may be specified in a different unit. + +The most convenient way to deal with this is to get rid of the units, and that means converting +everything to user units. + +Each :class:`BaseElement ` has a method +:meth:`to_dimensionless `. This method parses a +``length`` value and returns it, converted to px (user units). + +:meth:`~inkex.elements._base.BaseElement.to_dimensionless` fulfils the following task: +**Convert this string from the XML into a number, while processing the unit. +When using this function on any SVG attribute and replacing the +original value with the result, the output doesn't change visually.** + +In these and the following examples, the above "business card" SVG will be used. + +>>> svg = inkex.load_svg("docs/samples/units2.svg").getroot() +>>> svg.to_dimensionless(svg.getElementById("c1").get("cx")) +21.0 +>>> svg.to_dimensionless(svg.getElementById("c2").get("cx")) +21.0 +>>> svg.to_dimensionless(svg.getElementById("c3").get("cx")) +79.370078 + +For some classes, e.g. :class:`Rectangle `, convenience +properties are available which do the conversion for you, e.g. +:attr:`Rectangle.left `. Similarly there are some +properties for circles: + +>>> svg.getElementById("c3").center +Vector2d(79.3701, 52.9134) +>>> svg.getElementById("c2").radius +4.0 + +What is the dimension of an object in a specified unit in the user coordinate system? +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +You can also convert from user units to any unit. This is done using +:meth:`BaseElement.to_dimensional `. + +>>> svg.to_dimensional(svg.getElementById("c2").radius, "px") +4.0 +>>> svg.to_dimensional(svg.getElementById("c2").radius, "mm") +1.0583333333333333 + +What is the dimension of an object on the viewport in arbitrary units? +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +This is useful if you want to draw a property of a shape (for example its area) as text on the +canvas, in a unit specified by the user. The default unit to convert to is px. + +The method for this is called :meth:`BaseElement.unit_to_viewport `. + +>>> svg.unit_to_viewport(svg.getElementById("c2").radius) +15.118110236220472 +>>> svg.unit_to_viewport(svg.getElementById("c2").radius, "mm") +4.0 +>>> svg.unit_to_viewport("4", "mm") +4.0 + +In other words, ``unit_to_viewport(value, unit="px")`` answers the following +question: **What does the the width/height widget of the selection +tool (set to** ``unit`` **) show when selecting an element with width** +``value`` **as defined in the SVG?** Consider again +```` +, i.e. a "mm-based" document with scale=2. When selecting this rectangle, the rectangle tool +shows ``viewport_to_unit("100", unit="mm") = 200``, if the rectangle tool is set to mm. + +Obviously the element needs to know the viewport of its SVG document for this. This method therefore +does not work if the element is unrooted. + + +How big does an object have to be to have the specified size on the viewport? +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +This is useful if you want to draw a shape at a given location on the viewport, regardless of +what the user coordinate system is. This is done using +:meth:`BaseElement.viewport_to_unit `. + +>>> svg.viewport_to_unit("4mm", "px") +4.0 +>>> svg.viewport_to_unit("4mm", "mm") +1.0583333333333333 + +An example for this would be text elements. In order for text to show up in Inkscape's text +tool as ``9pt``, you have to user + +>>> element.style["font-size"] = self.svg.viewport_to_unit("9pt") + +Again, this method will raise an error if the element is unrooted. + +In other words, ``viewport_to_unit(value, target_unit="px")`` answers the following question: +**What is the SVG representation of entering** ``value`` **in the width/height widget of the +selection tool (set to the unit of value)?** Consider +````, +i.e. a "mm-based" SVG with scale=2. When typing ``200`` in the +rectangle tool, set to mm, the XML editor shows ``100`` = +``100px``. That's what ``viewport_to_unit("200mm") = 100`` does. + +Note that this is different than +``viewport_to_unit("200", "mm")``, which would be for a rectangle +with a width (in the width/height widget of the rectangle tool) of +200 (px), while writing the width in ``mm`` *in the SVG*: +````. + +Document dimensions +^^^^^^^^^^^^^^^^^^^^^^^^ + +* :attr:`SvgDocumentElement.viewport_width ` + and + :attr:`SvgDocumentElement.viewport_height ` + are the width and height of the viewport coordinate system, i.e. the "output screen" of the + viewBox camera, in pixels. In above example: ``(317.480314, 211.653543)`` + +.. code-block: + 84mm * 96px/in / (25.4mm/in) = 317.480314 + [output size] [resolution 96dpi] [output size in pixels] + +* :attr:`SvgDocumentElement.viewbox_width ` + and + :attr:`SvgDocumentElement.viewbox_height ` + are the width and height of the user coordinate system, i.e. for a viewport without offset, the + largest ``x`` and ``y`` values that are visible to the viewport camera. + In above example: ``(84, 56)`` + +Conversion between arbitrary units +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The functions listed above are methods of :class:`BaseElement ` +because they use properties of the root SVG. For an unrooted SVG fragment, +:meth:`BaseElement.to_dimensionless `. +:meth:`BaseElement.to_dimensional ` work as well. + +If you want to convert between arbitrary units, you can do so using the +:meth:`convert_unit ` method: + +>>> inkex.units.convert_unit("4mm", "px") +15.118110236220472 + + +Note that inkex doesn't support relative units (percentage, `em` and `ex`) yet. You will have to +implement these yourself if you want your extension to support them. + +.. [1] https://www.w3.org/TR/SVG11/coords.html#Units +.. [2] https://www.w3.org/TR/SVG2/coords.html#Introduction +.. [3] https://www.w3.org/TR/SVG2/coords.html#ViewportSpace +.. [4] https://www.w3.org/TR/SVG2/coords.html#ViewBoxAttribute +.. [5] Note that this drawing has ``width="100%" height="" viewBox="0 0 88.540985 36.87265"``. + This instructs the viewer that the SVG should span the entire width of the containing + element (in this case, an HTML div) and the height should be chosen such that the image + is scaled proportionally. Inkex doesn't support these relative units and these don't really + make sense in standalone SVGs anyway. \ No newline at end of file diff --git a/share/extensions/docs/authors/update1.0.rst b/share/extensions/docs/authors/update1.0.rst new file mode 100644 index 0000000..294af52 --- /dev/null +++ b/share/extensions/docs/authors/update1.0.rst @@ -0,0 +1,301 @@ +Updating your extension for Inkscape 1.0 +======================================== + +.. warning:: This information is partially outdated. + +This is a preliminary and incomplete list of actions to take for +updating Python extensions for Inkscape 1.0: + +.. _adjusting_folder_structure: + +Adjusting folder structure +-------------------------- + +For easier extension 'installation' by users and for having a better +overview about the installed extensions, you can now put extensions into +their own subfolders of the ``extensions`` directory. This is optional. + +When specifying the command in the .inx file, you can use the new +parameter 'location'. + +- If you set ``location="extensions"`` (de-facto default in 0.92.x), it + will assume the path is relative to either user or system extensions + folder. +- If it's ``location="inx"`` (new and recommended in 1.0), it will + assume the path is relative to the .inx file location. + +An extension that uses the following snippet: + +.. code:: xml + + + +can be put into any subfolder in ``extensions`` or into the +``extensions`` folder itself, as long as the file ``hello.py`` is in +that same folder, at the same hierarchy level. + +The old parameter ``reldir`` is deprecated. It is recommended to use +Unix style path separators (i.e. ``/``), if your script file is located +in a nested subdirectory (should be a very rare case). + +.. _updating_.inx_files: + +Updating \*.inx files +--------------------- + +.. _remove_dependency_listings: + +Remove dependency listings +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Remove the dependency listings for the following modules: + +- bezmisc.py +- coloreffect.py +- cspsubdiv.py +- cubicsuperpath.py +- ffgeom.py +- inkex.py (removal not strictly required) +- pathmodifier.py +- simplepath.py +- simplestyle.py +- simpletransform.py +- more? + +This change is backwards compatible (as long as the user has a fully +functioning Inkscape installation). Not removing these will result in +the extension not being selectable (disabled and greyed out) in Inkscape +1.0 or higher. + +.. _changes_to_parameter_definitions: + +Changes to parameter definitions +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +There are also some updates to the parameter definitions in .inx files. +While these are intended to be backwards compatible to 0.92, you may +wish to review the changes below: + +- **Underscores** in inx parameter tags and attributes for translation + **can be dropped** entirely. Use ``translatable="no"`` to make an + item (e.g. a unit name) untranslatable. +- ``boolean`` can be renamed to ``bool`` +- ```` is deprecated, instead use optiongroups. + Remember to rename ``item`` to ``option`` when replacing. +- In optiongroups ``appearance="minimal"`` is deprecated. + + - In optiongroups you can now define dropdown selections + (comboboxes) and radio buttons. + - i.e. ````, or + ````. + +- Choosing files / folders with ```` + (these return the path as a string to the Python script) +- Color choosers: make them more compact with + ``appearance="colorbutton"`` for parameters of type ``color`` +- Multiline text entry fields are available with + ``appearance="multiline"`` for parameters of type ``string`` +- The following new widgets (static, do not need to be read in by the + .py file's option parser anymore): + + - ``label``: (````), replaces parameters of type + ``description`` (which never really were parameters in the actual + sense), optionally with ``appearance="header"``. + - ``hbox``/``vbox``: for layouting purposes (allow to pack child + widgets into horizontally/vertically oriented boxes) + - ```` / ````: which add a variable space or separating line between child + widgets. + - ``my_image.svg``: which allows to display an image in the + extension UI + +See :ref:`inx-widgets` for more details. + +Example file with many of the new features: + +.. code:: xml + + + + Layout Demo + org.inkscape.test.layout_demo + pathmodifier.py + + + + + + + + true + 12345 + 1.2345 + 0x12345678 + + + + + a string value + + + + a\nmultiline\nstring\nvalue + + + + + my/path/to/file.png + + my/path/to/file.png + + my/path/to/file.png + + + + + + + + my/path/ + my/path/to/file.png + my/path/ + + + + + ink_icon.svg + + + + + + + + + + + + all + + + + + + + +.. _updating_.py_files: + +Updating \*.py files +-------------------- + +.. _collecting_the_options_of_the_extension: + +Collecting the options of the extension +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +#. Instead of ``inkex.Effect.OptionParser.add_option``, your extension + should now use ``inkex.Effect.arg_parser.add_argument``. +#. The 'type' option now works with variables instead of strings. Use + ``int`` instead of ``"int"`` (same for float,...). +#. The 'inkbool' type is now ``inkex.Boolean``. +#. ``action="store"`` can be removed. + +These changes are not backwards compatible. The old options will still +work, but are deprecated and should no longer be used when you develop +your extension for Inkscape 1.0 or higher. + +.. _replace_specific_functions: + +Replace specific functions +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +When the .inx file is valid and not greyed out (meaning: a dependency is +missing), you can start building the .py file up again. + +In the Inkscape extensions refactoring process for Inkscape 1.0, many +inkex functions have been removed, or renamed, or moved, or options have +changed. Wherever possible, Inkscape will try to replace the old +function by the new one, and will give you a deprecation warning, with +instructions what to replace them by. + +E.g. ``inkex.Effect.selected`` is replaced by +``inkex.Effect.svg.selected`` - however, most replacements do not follow +this naming scheme translation. + +These changes are not backwards compatible. + +.. _python_3_python_2_compatibility: + +Python 3 / Python 2 compatibility +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. warning:: Starting from Inkscape 1.1, only Python 3 is supported. + +Test your extension with both Python 2 and Python 3, if you want it to +work for as many users as possible. With the updated extensions, +Inkscape does no longer require Python 2, so some users will probably be +using Python 3, and may no longer have Python 2 installed on their +system. See `Extension_Interpreters `__ for how +to set the Python version for your extension in the preferences file +(for testing). + +.. _getting_your_extension_added_to_inkscapes_stock_extensions: + +Getting your extension added to Inkscape's stock extensions +----------------------------------------------------------- + +Inkscape now has a `separate repository for its Python +extensions `__, which is +included into Inkscape proper by using a Git submodule. + +.. _writing_tests: + +Writing tests +~~~~~~~~~~~~~ + +Previously Inkscape didn't require any unit testing for code. You should +now write test code if you expect your module to be included into the +Inkscape extensions repository and included in the shipped Inkscape +release. In this case, a test suite file should be made in the tests +directory for your extension. It should test each aspect of your +extension and exercise all assumptions. + +If you are writing a standalone extension that users will install +themselves, there is no strict requirement for tests. But having them +will greatly improve your code and your ability to upgrade the code +later. You can have tests in your own folders and use the extension's +setup.py as a harness to run them (a setup.py file is also useful for +installing your python code as a non-inkscape related python module, +which might be useful too). See Python documentation for creating +packages. + +.. _documenting_your_extension: + +Documenting your extension +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Docstrings +---------- + +Include docstrings in your extension, so documentation can be built from +them automatically. + +.. _submitting_your_extension_for_inclusion: + +Submitting your extension for inclusion +--------------------------------------- + +Visit https://gitlab.com/inkscape/extensions, fork the repository, and +create a merge request on GitLab. + +.. _external_links: + +External links +-------------- + +A script to perform some of the conversion steps automatically has been +contributed: https://gitlab.com/inkscape/extensions/-/issues/380 + diff --git a/share/extensions/docs/authors/update1.2.rst b/share/extensions/docs/authors/update1.2.rst new file mode 100644 index 0000000..d50323a --- /dev/null +++ b/share/extensions/docs/authors/update1.2.rst @@ -0,0 +1,229 @@ +Updating your extension for Inkscape 1.2 +========================================= + +This page is intended for extension authors who want to use the new +capabilities of inkex in Inkscape 1.2. As of the Release of 1.2alpha +(Feb 5, 2022), no more breaking changes will be introduced until the +final release of 1.2. + +There are no breaking changes in this release, but a few methods have +been deprecated. + +.. _deprecating_changes: + +Deprecating changes +------------------- + +- The Transforms multiplication operator has been changed from ``*`` + (``*=``) to ``@`` (``@=``), in accordance with + `PEP-465 `__ (`MR + extensions#389 `__, + `Issue + extensions#327 `__) +- ``svg.width`` and ``svg.height`` have been deprecated, and replaced + with ``svg.viewbox_width``, ``svg.viewport_width``, + ``svg.viewbox_height`` and ``svg.viewport_height``, see `New Units + API `__. +- ``selection.paint_order`` has been renamed to + ``selection.rendering_order`` to be conformant with the specification + (`MR + extensions#344 `__, + `Issue + extensions#310 `__) +- ``FallbackStyle`` has been deprecated in favor of ``Style``, see `New + Style API `__. + +.. _new_style_api: + +New Style API +------------- +.. figure:: samples/Comparison_of_Lighter_extension_in_Inkscape_1.1.2_and_1.2.png + + Top: W3C SVG1.1 Test suite, + test `styling-css-04-f.svg `__. + This test includes various CSS selectors, and includes group inheritance + and pseudo-selectors. It is rendered correctly in Inkscape 1.2. Bottom + left: Output of the "Lighter" extension in Inkscape 1.1.2, only two + squares are processed correctly, two squares have a wrong color and the + other 14 raise unhandled exceptions. Bottom right: Correct output in + Inkscape 1.2. This shows that inkex correctly handles different types of + CSS selectors. + +Added in `MR +extensions#294 `__, +`MR +extensions#296 `__, +`MR +extensions#298 `__, +`MR +extensions#300 `__, +`MR +extensions#352 `__, +`MR +extensions#403 `__ + +Inkex now exposes styles to extensions authors as intended by the SVG +specification. This means: + +- ``BaseElement`` now has functions ``cascaded_style``, + ``specified_style`` and ``presentation_style``. +- In most use cases, extensions querying a style will use + ``specified_style``. This computes the `effective + style `__ + of the element, including CSS classes / pseudo-selectors, inherited + styles, presentation attributes etc. +- While ``style.get()`` and ``style[key]`` has been unchaged, a new + getter has been added in form of ``style(key)`` (similar to a + function call), which attempts to parse the attribute in a reasonable + datatype. If the attribute is unset, the (parsed) default value will + be returned. For example: + + - ``style("fill")`` returns a ``Color`` / ``Gradient`` / ``Pattern`` + / ``None``, + - ``style("opacity")`` returns a value between 0 and 1, regardless + if opacity is defined as percentage or as float, is out of bounds + or undefined, + - ``style("stroke-dasharray")`` returns a list of floats of + dash/gap/dash/gap in user units. + +- Not for all attributes there is a parser defined - in that case, a + string will be returned. Additional parsers may be added in the + future, so if you handle the string value, typecheck it first! + +.. _using_the_new_style_api_in_your_extension: + +Using the new Style API in your extension +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The following calls can probably be simplified: + ++----------------------------------------------------+----------------------------------------------------+ +| Old code (pre-1.2) | New code (1.2+) | ++====================================================+====================================================+ +| .. code:: python3 | .. code:: python3 | +| | | +| if "fill-opacity" in self.style: | alpha = self.style("fill-opacity") | +| alpha = self.style["fill-opacity"] | | +| else: | | +| alpha = 1 | | ++----------------------------------------------------+----------------------------------------------------+ +| .. code:: python3 | .. code:: python3 | +| | | +| if not node.style.get(attr, '')\ | marker_node = node.style(attr) | +| .startswith('url(#'): | | +| continue | | +| | | +| marker_id = node.style[attr][5:-1] | | +| marker_node = self.svg.getElement( | | +| f'/svg:svg//svg:marker[@id="{marker_id}"]') | | ++----------------------------------------------------+----------------------------------------------------+ +| .. code:: python3 | .. code:: python3 | +| | | +| obj.style['fill'] = pattern.get_id(2) | obj.style['fill'] = pattern | ++----------------------------------------------------+----------------------------------------------------+ + +Checkout `MR +extensions#298 `__ +for additional examples of simplifications. + +.. _new_units_api: + +New Units API +------------- + +Added in `MR +extensions#329 `__, +`MR +extensions#343 `__, +`MR +extensions#415 `__ + +The existing functions ``unittouu`` and ``uutounit`` are widely used, +but for different purposes. Different extension authors try to answer +different questions using these function, and, inevitably, some answers +were incorrect (see linked issues in `MR +extensions#329 `__). + +In Inkscape 1.2, new methods have been added to make working with +dimensional values easier. These are ``to_dimensionless``, +``to_dimensional``, ``viewport_to_unit`` and ``unit_to_viewport``. The +existing functions ``unittouu`` and ``uutounit`` are not deprecated, but +discouraged; in most cases, the new functions are more reliable. + +- ``to_dimensionless(value)`` fulfills the following task: **Convert + this string from the XML into a number, while processing the unit. + When using this function on any SVG attribute and replace the + original value with the result, the output doesn't change visually.** +- ``viewport_to_unit(value, target_unit="px")`` answers the following + questions: + + - **What is the length (e.g. the length of a rectangle, without a + unit) of an object that has size** ``value`` **on the viewport?** This + is relevant because in Inkscape toolbars / tools, all dimensions + are shown in "viewport units". + - In other words: **What is the SVG representation of entering + ``value`` in the width/height widget of the selection tool (set to + the unit of value)?** Consider ```` + , i.e. a "mm-based" SVG with scale=2. When typing ``200`` in the + rectangle tool, set to mm, the XML editor shows ``100`` = + ``100px``. That's what ``viewport_to_unit("200mm") = 100`` does. + + - Note that this is different than + ``viewport_to_unit("200", "mm")``, which would be for a rectangle + with a width (in the width/height widget of the rectangle tool) of + 200 (px), while writing the width in ``mm`` *in the SVG*: \ + ````. + +- ``to_dimensional`` simply converts a float to its equivalent with + attached unit. It's the opposite of ``to_dimensionless``. +- ``unit_to_viewport(value, unit="px")`` answers the following + question: **What does the the width/height widget of the selection + tool (set to** ``unit`` **) show when selecting an element with width + ``value`` as defined in the SVG?** Consider again ```` + , i.e. a "mm-based" document with scale=2. To create this rectangle, + one has to type ``viewport_to_unit("100", unit="mm") = 200`` into the + rectangle tool, if the rectangle tool is set to mm. + +With the same spirit, the functions for width/height of the document +have been updated. ``svg.width`` and ``svg.height`` have been +deprecated, and replaced with ``svg.viewbox_width``, +``svg.viewport_width``, ``svg.viewbox_height`` and +``svg.viewport_height``. + +There is also ``svg.scale``, which returns the ratio of the viewport and +viewbox width, and ``svg.inkscape_scale`` which is the scale reported in +the Document properties dialog. + +See :ref:`units` for additional information. + +.. _other_additions_to_inkex: + +Other additions to inkex +------------------------ + +- The path conversion for arcs and stars have been added, so when + extensions create these objects, they are rendered in a browser as + well and can be processed further by the same extension. (`MR + extensions#387 `__, + `Issue + extensions#240 `__) +- ``ColorExtension``\ s can now process in RGBA space. Previously, + opacity and color were processed independently. By setting the class + variable ``pass_rgba = True``, the ``modify_color`` method gets + passed a color with alpha channel computed from matching property + pairs, e.g. ``fill`` and ``fill-opacity``. (This value takes CSS + styling and style inheritance into account. (`MR + extensions#392 `__ + , `Issue + extensions#419 `__). +- API functions for the new `multipage + feature `__ have been added: `MR + extensions#499 `__. + +.. _other_deprecations_to_inkex_1_2 + +Other deprecations to inkex +---------------------------- + +- Pre Inkscape 1.0 way of declaring the dependency on inkex in the ``*.inx`` file has been removed entirely. (It was deprecated in Inkscape 1.0. For details, see :ref:`remove_dependency_listings`) + diff --git a/share/extensions/docs/authors/widgets/bool.png b/share/extensions/docs/authors/widgets/bool.png new file mode 100644 index 0000000..dbf5588 Binary files /dev/null and b/share/extensions/docs/authors/widgets/bool.png differ diff --git a/share/extensions/docs/authors/widgets/color.png b/share/extensions/docs/authors/widgets/color.png new file mode 100644 index 0000000..1d6e894 Binary files /dev/null and b/share/extensions/docs/authors/widgets/color.png differ diff --git a/share/extensions/docs/authors/widgets/float.png b/share/extensions/docs/authors/widgets/float.png new file mode 100644 index 0000000..63ac125 Binary files /dev/null and b/share/extensions/docs/authors/widgets/float.png differ diff --git a/share/extensions/docs/authors/widgets/image.png b/share/extensions/docs/authors/widgets/image.png new file mode 100644 index 0000000..057b1d0 Binary files /dev/null and b/share/extensions/docs/authors/widgets/image.png differ diff --git a/share/extensions/docs/authors/widgets/integer.png b/share/extensions/docs/authors/widgets/integer.png new file mode 100644 index 0000000..da376db Binary files /dev/null and b/share/extensions/docs/authors/widgets/integer.png differ diff --git a/share/extensions/docs/authors/widgets/label.png b/share/extensions/docs/authors/widgets/label.png new file mode 100644 index 0000000..fb1e470 Binary files /dev/null and b/share/extensions/docs/authors/widgets/label.png differ diff --git a/share/extensions/docs/authors/widgets/notebook.png b/share/extensions/docs/authors/widgets/notebook.png new file mode 100644 index 0000000..f21dcec Binary files /dev/null and b/share/extensions/docs/authors/widgets/notebook.png differ diff --git a/share/extensions/docs/authors/widgets/optiongroup.png b/share/extensions/docs/authors/widgets/optiongroup.png new file mode 100644 index 0000000..a8d9d7d Binary files /dev/null and b/share/extensions/docs/authors/widgets/optiongroup.png differ diff --git a/share/extensions/docs/authors/widgets/path.png b/share/extensions/docs/authors/widgets/path.png new file mode 100644 index 0000000..3050182 Binary files /dev/null and b/share/extensions/docs/authors/widgets/path.png differ diff --git a/share/extensions/docs/authors/widgets/separator.png b/share/extensions/docs/authors/widgets/separator.png new file mode 100644 index 0000000..e4e7e2e Binary files /dev/null and b/share/extensions/docs/authors/widgets/separator.png differ diff --git a/share/extensions/docs/authors/widgets/spacer.png b/share/extensions/docs/authors/widgets/spacer.png new file mode 100644 index 0000000..32ab128 Binary files /dev/null and b/share/extensions/docs/authors/widgets/spacer.png differ diff --git a/share/extensions/docs/authors/widgets/string.png b/share/extensions/docs/authors/widgets/string.png new file mode 100644 index 0000000..b95ffff Binary files /dev/null and b/share/extensions/docs/authors/widgets/string.png differ diff --git a/share/extensions/docs/conf.py b/share/extensions/docs/conf.py new file mode 100644 index 0000000..62e2884 --- /dev/null +++ b/share/extensions/docs/conf.py @@ -0,0 +1,93 @@ +# Configuration file for the Sphinx documentation builder. +# +# This file only contains a selection of the most common options. For a full +# list see the documentation: +# https://www.sphinx-doc.org/en/master/usage/configuration.html + +# -- Path setup -------------------------------------------------------------- + +# If extensions (or modules to document with autodoc) are in another directory, +# add these directories to sys.path here. If the directory is relative to the +# documentation root, use os.path.abspath to make it absolute, like shown here. +# +import os +import sys + +sys.path.insert(0, os.path.abspath("../")) + +import datetime + +# -- Project information ----------------------------------------------------- + +project = "inkex documentation" +copyright = f"{datetime.datetime.now().year} The Inkscape Project" +author = "The Inkscape Project" + + +# -- General configuration --------------------------------------------------- + +# Add any Sphinx extension module names here, as strings. They can be +# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom +# ones. +extensions = [ + "sphinx.ext.autodoc", + "sphinx.ext.viewcode", + "sphinx.ext.todo", + "sphinx.ext.napoleon", +] + +# Add any paths that contain templates here, relative to this directory. +templates_path = ["_templates"] + +# The language for content autogenerated by Sphinx. Refer to documentation +# for a list of supported languages. +# +# This is also used if you do content translation via gettext catalogs. +# Usually you set "language" from the command line for these cases. +language = "en" + +# List of patterns, relative to source directory, that match files and +# directories to ignore when looking for source files. +# This pattern also affects html_static_path and html_extra_path. +exclude_patterns = ["_build", "Thumbs.db", ".DS_Store"] + + +# -- Options for HTML output ------------------------------------------------- + +# The theme to use for HTML and HTML Help pages. See the documentation for +# a list of builtin themes. +# +html_theme = "pydata_sphinx_theme" + +html_theme_options = { + "show_toc_level": 2, + "use_edit_page_button": True, + "gitlab_url": "https://gitlab.com/inkscape/extensions", +} + +html_context = { + "gitlab_user": "inkscape", + "gitlab_repo": "extensions", + "gitlab_version": "master", + "doc_path": "docs", +} + +# Add any paths that contain custom static files (such as style sheets) here, +# relative to this directory. They are copied after the builtin static files, +# so a file named "default.css" will overwrite the builtin "default.css". +# html_static_path = ["_static"] + +# -- Extension configuration ------------------------------------------------- + +always_document_param_types = True + +# -- Options for todo extension ---------------------------------------------- + +# If true, `todo` and `todoList` produce output, else they produce nothing. +todo_include_todos = True + +autodoc_member_order = "bysource" + +autodoc_preserve_defaults = True + +html_favicon = "favicon.svg" diff --git a/share/extensions/docs/dev/getting-started.rst b/share/extensions/docs/dev/getting-started.rst new file mode 100644 index 0000000..63d8a46 --- /dev/null +++ b/share/extensions/docs/dev/getting-started.rst @@ -0,0 +1,148 @@ +Getting started with developing inkex +===================================== + +.. highlight:: bash + +.. warning:: + + This document is tailored for contributors to the inkex package and core extensions. + + Extension authors should look here: :ref:`authors-tutorial` + +Repository setup +---------------- + +It is possible to synchronize a fork with the extensions repository - whenever a branch in the +mirrored repository is updated, your fork will be updated too (usually with a delay of up to one +hour). See `Settings -> Repository -> Mirroring Repositories` and add a "Pull" mirror. + +.. warning:: + + If you use this method, **do not** add commits to branches that should be synced + (such as `master`). + Depending on the exact settings of the mirroring option, you will either lose your changes, + lose the synchronisation or run into a messed up branch history. + +Always check out submodules as well:: + + git submodule update && git submodule init + +Python setup +------------ + +On every operating system, you need a working Python environment. Currently, inkex is tested +against Python 3.7-3.10. + +inkex manages its dependencies using `poetry `_. It can be installed using:: + + pip install poetry + +Install the dependencies and the pre-commit hook:: + + poetry install + pre-commit install + +Testing changes in Inkscape +--------------------------- + +Most of the time, calling the python file of the extension directly and through unit tests is +sufficient. In some cases, the interaction between Inkscape and the extension should be tested, +though. + +Assuming you have managed to make Inkscape look in the correct folder for the extensions (see hints +for different operating systems below), the python +file of an extension is reloaded every time the extension is run. For changes to the inx file or +the command line parameters of the extension (as defined in the +:func:`~inkex.base.InkscapeExtension.add_arguments` method) you need to restart Inkscape. + +Developing extensions on Windows +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +.. highlight:: batch + +To test extensions with a given Inkscape version, download the 7z archive of that version, +unarchive it and delete the ``inkscape\share\extensions`` folder. Next, create a symlink in that +folder from an administrative command prompt:: + + cd [directory of the unzipped Inkscape folder] + mklink /D share\extensions C:\path\to\your\fork + +If you start ``bin\inkscape`` now, the extensions are loaded from your fork. + +Developing extensions on Linux +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. highlight:: bash + +A very similar path to Windows can be used when working off an appimage build. + +Extract the appimage into a new folder called ``squashfs-root``:: + + /path/to/appimage --appimage-extract + squashfs-root/AppRun --system-data-directory + +This prints the location of the extensions folder. Create a symlink to your repo there and run:: + + squashfs-root/AppRun + +Trying / Changing a merge request locally +----------------------------------------- + +Add this to ``git config -e`` (only once):: + + [remote "upstream"] + url = git@gitlab.com:inkscape/extensions.git + fetch = +refs/merge-requests/*/head:refs/remotes/origin/merge-requests/* + [alias] + mr = !sh -c 'git fetch $1 merge-requests/$2/head:mr-$1-$2 && git checkout mr-$1-$2' - + +Check out the merge request !123:: + + git mr upstream 123 + +Push changes to the source branch ``source-branch-name`` of fork in the namespace (typically the +author's username) ``xyz``:: + + git push git@gitlab.com:xyz/extensions.git mr-origin-123:source-branch-name + + +Adding/Updating dependencies +---------------------------- + +.. highlight:: bash + +The *direct* dependencies of inkex are declared in the ``pyproject.toml`` file. + +There is also a lockfile named ``poetry.lock`` which has *all* the dependencies +(direct, dependencies of direct, dependencies of dependencies of direct and so on till the leaf dependencies) +pinned to specific versions (versions which were compatible the last time lockfile was updated). + +To update all the dependencies in the lockfile to latest compatible versions, enter:: + + poetry lock + +To add/update a particular dependency, add it to ``pyproject.toml`` manually. The dependency should be declared in the +``[tool.poetry.dependencies]`` TOML table, while a dependency required only during development of inkex should be declared in +``[tool.poetry.dev-dependencies]``. + +Then update the lockfile using:: + + poetry lock + +Alternatively, you can add a dependency and update the lockfile in a single command:: + + poetry add "lxml@^4.5.0" --lock + +Both the ``pyproject.toml`` and ``poetry.lock`` are to be committed to the repository. + +.. note:: + + You don't need to install the dependencies to add/update them. So, the commands above don't install anything. + However, if you are using poetry to manage the environment, and want to also install the dependencies, + remove the ``--lock`` options from the commands and use ``poetry update`` instead of ``poetry lock``. + +.. note:: + + Dependencies should be updated according to the `policy `_ defined in Inkscape wiki . + diff --git a/share/extensions/docs/dev/index.rst b/share/extensions/docs/dev/index.rst new file mode 100644 index 0000000..a38cf03 --- /dev/null +++ b/share/extensions/docs/dev/index.rst @@ -0,0 +1,8 @@ +inkex (and core Extensions) development +======================================= + +.. toctree:: + :maxdepth: 2 + + getting-started + Writing unit tests <../authors/unit-tests> \ No newline at end of file diff --git a/share/extensions/docs/favicon.svg b/share/extensions/docs/favicon.svg new file mode 100644 index 0000000..cf0292a --- /dev/null +++ b/share/extensions/docs/favicon.svg @@ -0,0 +1,159 @@ + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/share/extensions/docs/index.rst b/share/extensions/docs/index.rst new file mode 100644 index 0000000..abfc319 --- /dev/null +++ b/share/extensions/docs/index.rst @@ -0,0 +1,35 @@ +Welcome to inkex's documentation! +================================= + +.. toctree:: + :maxdepth: 1 + :hidden: + + Tutorial + authors/index + Inkex Development + API Reference + +**Useful links**: +`Source Repository `_ | +`Issue Tracker `_ | +`Chat `_ + +Inkex is: + +- a general-purpose SVG reading/writing/modification package +- an object-oriented interface for access to + many common SVG attributes, such as paths and styles +- the Python package that enables Inkscape extensions + +Furthermore, :mod:`inkex.gui` provides a way to ship GTK interfaces with extensions, and +:mod:`inkex.tester` is a package to facilitate unit testing of extensions. + +Welcome to its documentation! + +Indices and tables +================== + +* :ref:`genindex` +* :ref:`modindex` +* :ref:`search` diff --git a/share/extensions/docs/make.bat b/share/extensions/docs/make.bat new file mode 100644 index 0000000..21b58de --- /dev/null +++ b/share/extensions/docs/make.bat @@ -0,0 +1,35 @@ +@ECHO OFF + +pushd %~dp0 + +REM Command file for Sphinx documentation + +if "%SPHINXBUILD%" == "" ( + set SPHINXBUILD=sphinx-build +) +set SOURCEDIR=. +set BUILDDIR=build + +if "%1" == "" goto help + +%SPHINXBUILD% >NUL 2>NUL +if errorlevel 9009 ( + echo. + echo.The 'sphinx-build' command was not found. Make sure you have Sphinx + echo.installed, then set the SPHINXBUILD environment variable to point + echo.to the full path of the 'sphinx-build' executable. Alternatively you + echo.may add the Sphinx directory to PATH. + echo. + echo.If you don't have Sphinx installed, grab it from + echo.https://www.sphinx-doc.org/ + exit /b 1 +) + +%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% +goto end + +:help +%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% + +:end +popd diff --git a/share/extensions/docs/source/index.rst b/share/extensions/docs/source/index.rst new file mode 100644 index 0000000..b8aad2c --- /dev/null +++ b/share/extensions/docs/source/index.rst @@ -0,0 +1,21 @@ +.. inkex documentation master file, created by + sphinx-quickstart on Tue May 18 23:45:21 2021. + You can adapt this file completely to your liking, but it should at least + contain the root `toctree` directive. + +API Reference +============= + +.. toctree:: + :maxdepth: 4 + :caption: Contents: + + inkex + + +Indices and tables +================== + +* :ref:`genindex` +* :ref:`modindex` +* :ref:`search` diff --git a/share/extensions/docs/tutorial/index.rst b/share/extensions/docs/tutorial/index.rst new file mode 100644 index 0000000..0e9551a --- /dev/null +++ b/share/extensions/docs/tutorial/index.rst @@ -0,0 +1,49 @@ +.. _authors-tutorial: + +Tutorial +======== + +Introduction +------------ + +Extensions are small programs that extend Inkscape’s functionality. They +can provide features for specific tasks, experimentation, or art styles. +They can also add support for special hardware or different export +formats. While many extensions are included with Inkscape, you can also +install extensions written by third parties or write your own. + +This guide aims to provide you with enough information to write your own +extension using the python programming language and a text editor. You +should have the latest version of Inkscape installed. While Inkscape +extensions generally work across platforms, this guide will use Linux as +its default operating system. Linux is not required for writing +extensions, but you may need to modify the location of files on your +computer as you follow along. You may also need to use other “helper” +programs, for example a different text editor, depending on your +operating system. + +When a user selects an extension from the menu within Inkscape, Inkscape +opens a pop-up dialog that presents information to the user and/or +allows the user to enter any parameters that are necessary to use the +extension. An extension can also be configured to run immediately +without an intermediate dialog, for example if it does not have any +adjustable parameters. When the user clicks **Apply** in the dialog, the +parameters are passed to the extension program along with the svg file +and a list of selected objects. The extension program itself then runs, +and the data that it returns will be used to update Inkscape’s svg +canvas or to save data to disk. + +We’ve made this process easier for you by creating a set of template +extensions which you can download as the starting point for this +tutorial. If you are a beginner we recommend that you start with the +Effect Extension Template. Input, Output and other types of extensions +will be covered in the more advanced topics later. + +.. toctree:: + :maxdepth: 1 + + my-first-effect-extension + simple-path-extension + my-first-text-extension + my-first-import-extension + diff --git a/share/extensions/docs/tutorial/my-first-effect-extension.rst b/share/extensions/docs/tutorial/my-first-effect-extension.rst new file mode 100644 index 0000000..7666288 --- /dev/null +++ b/share/extensions/docs/tutorial/my-first-effect-extension.rst @@ -0,0 +1,130 @@ +.. _first-effect-extension: + +My first effect extension +========================= + +Resources +--------- + +- :download:`Template Files ` +- :download:`Example solution ` + +Introduction +------------ +Effect extensions take the svg from Inkscape, modify it in some way and +pass the modified version back to Inkscape to be rendered onto the +canvas. This can be very powerful, allowing everything from randomising +colours to manipulating path elements in external programs. + +We are going to write an effect extension that will simply change the fill +any selected object to red. + +Step One +--------- + +Extract the ``Effect Extension Template`` files into a folder on your +computer. You should have two files, one inx file and one python file. +Move or link these files into your extensions directory as you would +when installing extensions manually. This is the directory listed at +``Edit > Preferences > System: User extensions``. + +Edit the inx file in a text editor and change the name of the extension +to ``Make Red Extension`` and the id to +``org.inkscape.tutorial.make_red_extension`` by changing these lines near +the top: + +.. code:: xml + + + + Make Red Extension + org.inkscape.tutorial.make_red_extension + [...] + +Toward the end of the .inx file, change the submenu to ``Color`` +specify that this extension will be listed in the ``Color`` submenu +under the ``Extensions`` menu: + +.. code:: xml + + [...] + + + + + + + [...] + +Step Two +--------- + +Next, open ``my_effect_extension.py`` in your text editor. You can see +this is an inkex extension because it contains a python class that +inherits from ``inkex.EffectExtension``. Change the class name to +``MakeRedExtension``: + +.. code:: python + + [...] + class MakeRedExtension(inkex.EffectExtension): + [...] + +Reflect this change down in the ``__main__`` section of the code by +changing the class name to ``MakeRedExtension`` there: + +.. code:: python + + [...] + if __name__ == '__main__': + MakeRedExtension().run() + +When a standard inkex-based python effect extension is run, it will call +a method called :func:`~inkex.base.InkscapeExtension.effect` on your extension's class. So, most of the +code you need to write will go there. Edit +``my_effect_extension.py``\ 's ``effect()`` method to look like the +following, **being sure that the indentation is correct so that** +``effect()`` **is recognized as a method of the MakeRedExtension class**: + +.. code:: python + + for elem in self.svg.selection: + elem.style['fill'] = 'red' + elem.style['fill-opacity'] = 1 + elem.style['opacity'] = 1 + + + +Code Explanation +~~~~~~~~~~~~~~~~ + +We want to change the color of all selected objects to red. For this we need to loop +through each of the selected paths. The first line of :func:`inkex.base.InkscapeExtension.effect` +does this. The :attr:`~inkex.elements._svg.SvgDocumentElement.selection` attribute of ``self.svg`` +contains the currently selected objects. + +.. hint:: + ``self.svg`` contains the SVG document in its current state - passed by Inkscape - and + is already parsed for us, so we don't have to manipulate the XML manually. Instead, inkex offers + an object-oriented interface to all the SVG element types. + +Each element has a ``style`` attribute: it's one of the +:attr:`~inkex.elements._base.BaseElement.WRAPPED_ATTRS` of each element, so ``elem.style`` is a +:class:`~inkex.styles.Style` object (you can think of it as a dictionary). And in this dictionary, +we set the value for ``'fill'`` to ``'red'``. We also set the ``'fill-opacity'`` to ``1``, in case +the object was transparent previously. + + +Final Step +------------ + +That’s it! There’s no need to set, save or do anything else as we’ve +modified the style in place. + +Save your python script, and re-launch Inkscape. If inkscape was already +open, close it first. You should find your new extension available in +the ``Effect`` menu. + +Draw some shapes in Inkscape. Select some of the shapes and use the extension. +The fill of all objects should change to red. + diff --git a/share/extensions/docs/tutorial/my-first-import-extension.rst b/share/extensions/docs/tutorial/my-first-import-extension.rst new file mode 100644 index 0000000..6c296bd --- /dev/null +++ b/share/extensions/docs/tutorial/my-first-import-extension.rst @@ -0,0 +1,305 @@ +My first import extension +========================= + +Resources +--------- + +:download:`vanillin.smi ` + +Introduction +------------ + +This article will teach you the basics of writing an Import Extension for +Inkscape using the ``inkex`` Extensions API. + +Import Extensions are used to add support for a file format that +Inkscape does not support out of the box. It is rather complex to implement an entire file format, +but often there are already tools available to convert the file to a format that Inkscape can read, +such as SVG or PDF. In this case, the extension depends on external programs that convert that +specific file format to a svg that Inkscape can then read. + +The way these extensions are used is not through the ``Extensions`` menu +but instead these provide options in\ ``File``>\ ``Open`` or +``File``>\ ``Import`` dialog. + +The general flow of a Import Extension is as follows: + +1) You select the specific file format from the File Format drop down + menu of the ``File``>\ ``Open`` or ``File``>\ ``Import``\ dialog. +2) You select one or more files of that specific file format. You click + on ``Open`` button. +3) Inkscape will then either open the svg file in a new window or will + import it depending on which dialog of ``File`` menu was used. + +.. hint:: + + You can entirely skip 1) and 2) and just double click on + the file. If your extension is set up correctly, you won’t notice the + difference between opening a regular file and your file. + +In this article we will create an extension named +``Organic Bond Visualizer``. It will produce the bond structure of an +organic compound given a +`SMILES `__ +file. The extension uses an external program called ``indigo-depict`` +which has its GitHub repository +`here `__. (It is a part of the +``indigo-utils`` package in Debian/Ubuntu repositories. For other +platforms you might need to build it from source.) + +.. note:: A note on **PATH** + + Since the extension depends on external programs, it is important that + these external programs can be found by our extensions. For that to + happen, either these programs **should** be on your *system PATH* or an + absolute path for the program should be used in the code. + + Depending on the operating system, the steps required for adding + programs to the PATH might vary. + + You can get away with setting the PATH variable entirely by using an + absolute path for the program but it is almost always a bad idea to + hard-code paths in the code. + +.. hint:: + + This article assumes you create all extension related files in the + User Extensions directory which is listed at + ``Edit``>\ ``Preferences``>\ ``System`` - ``User Extensions:`` in + Inkscape. + +Step 0 : The Boilerplate +------------------------ + +Like any other Inkscape extension, this extension will also have two +files. So, create a ``organic_bond_vis.inx`` file and a +``organic_bond_vis.py`` file. + +- ``organic_bond_vis.inx`` - It will have the necessary information for + Inkscape to be able to recognize your extension as a valid Inkscape + extension. It will also have the info required to present the + extension as an option in ``File``>\ ``Open`` or + ``File``>\ ``Import`` dialog. +- ``organic_bond_vis.py`` - It will have the actual Python code your + extension will execute. + +.. hint:: + + There is another file that is worth mentioning here - the **test** + file which in our case will be ``test_organic_bond_vis.py``. It is + not required to be present for an extension per se, but as a best + practice, the extension code should always be accompanied by test + code. + +Step 1 : Populate the ``*.inx`` file +------------------------------------ + +.. code:: xml + + + + Organic Bond Visualizer + org.inkscape.input.bondvisualizer + indigo-depict + + + + +The lines below help Inkscape uniquely identify our extension. You +should modify these two lines for your own extension: + +.. code:: xml + + [...] + Organic Bond Visualizer + org.inkscape.input.bondvisualizer + [...] + +Now we declare the dependency of our extension: + +.. code:: xml + + indigo-depict + +The ``