[Skencil-commits] r682 - in skencil/branches/skencil-0.6: . Doc Doc/devguide Doc/usersguide Doc/usersguide/Images
scm-commit@wald.intevation.org
scm-commit at wald.intevation.org
Mon Jun 5 20:35:23 CEST 2006
Author: bh
Date: 2006-06-05 20:35:01 +0200 (Mon, 05 Jun 2006)
New Revision: 682
Added:
skencil/branches/skencil-0.6/Doc/
skencil/branches/skencil-0.6/Doc/Makefile
skencil/branches/skencil-0.6/Doc/README
skencil/branches/skencil-0.6/Doc/devguide/
skencil/branches/skencil-0.6/Doc/devguide/architecture.xml
skencil/branches/skencil-0.6/Doc/devguide/classes.xml
skencil/branches/skencil-0.6/Doc/devguide/connector.xml
skencil/branches/skencil-0.6/Doc/devguide/coordsys.xml
skencil/branches/skencil-0.6/Doc/devguide/curveobj.xml
skencil/branches/skencil-0.6/Doc/devguide/devguide.xml
skencil/branches/skencil-0.6/Doc/devguide/fileformat.xml
skencil/branches/skencil-0.6/Doc/devguide/plugins.xml
skencil/branches/skencil-0.6/Doc/devguide/remarks.xml
skencil/branches/skencil-0.6/Doc/devguide/ui.xml
skencil/branches/skencil-0.6/Doc/devguide/undo.xml
skencil/branches/skencil-0.6/Doc/usersguide/
skencil/branches/skencil-0.6/Doc/usersguide/Images/
skencil/branches/skencil-0.6/Doc/usersguide/Images/CreateCurve.png
skencil/branches/skencil-0.6/Doc/usersguide/Images/CreateEllipse.png
skencil/branches/skencil-0.6/Doc/usersguide/Images/CreatePoly.png
skencil/branches/skencil-0.6/Doc/usersguide/Images/CreateRect.png
skencil/branches/skencil-0.6/Doc/usersguide/Images/Delete.png
skencil/branches/skencil-0.6/Doc/usersguide/Images/Duplicate.png
skencil/branches/skencil-0.6/Doc/usersguide/Images/EditMode.png
skencil/branches/skencil-0.6/Doc/usersguide/Images/FlipHorizontal.png
skencil/branches/skencil-0.6/Doc/usersguide/Images/FlipVertical.png
skencil/branches/skencil-0.6/Doc/usersguide/Images/GridOn.png
skencil/branches/skencil-0.6/Doc/usersguide/Images/Group.png
skencil/branches/skencil-0.6/Doc/usersguide/Images/Image.png
skencil/branches/skencil-0.6/Doc/usersguide/Images/MiniEyeClosed.png
skencil/branches/skencil-0.6/Doc/usersguide/Images/MiniEyeOpen.png
skencil/branches/skencil-0.6/Doc/usersguide/Images/MiniPrintOff.png
skencil/branches/skencil-0.6/Doc/usersguide/Images/MiniPrintOn.png
skencil/branches/skencil-0.6/Doc/usersguide/Images/MoveOneDown.png
skencil/branches/skencil-0.6/Doc/usersguide/Images/MoveOneUp.png
skencil/branches/skencil-0.6/Doc/usersguide/Images/MoveToBottom.png
skencil/branches/skencil-0.6/Doc/usersguide/Images/MoveToTop.png
skencil/branches/skencil-0.6/Doc/usersguide/Images/NewDocument.png
skencil/branches/skencil-0.6/Doc/usersguide/Images/Open.png
skencil/branches/skencil-0.6/Doc/usersguide/Images/Redo.png
skencil/branches/skencil-0.6/Doc/usersguide/Images/Save.png
skencil/branches/skencil-0.6/Doc/usersguide/Images/SelectionMode.png
skencil/branches/skencil-0.6/Doc/usersguide/Images/Text.png
skencil/branches/skencil-0.6/Doc/usersguide/Images/Undo.png
skencil/branches/skencil-0.6/Doc/usersguide/Images/Ungroup.png
skencil/branches/skencil-0.6/Doc/usersguide/Images/Zoom.png
skencil/branches/skencil-0.6/Doc/usersguide/Images/arrow-left.png
skencil/branches/skencil-0.6/Doc/usersguide/Images/arrow-right.png
skencil/branches/skencil-0.6/Doc/usersguide/Images/arrow-up.png
skencil/branches/skencil-0.6/Doc/usersguide/Images/bullet.png
skencil/branches/skencil-0.6/Doc/usersguide/Images/gradient-conical.png
skencil/branches/skencil-0.6/Doc/usersguide/Images/gradient-linear.png
skencil/branches/skencil-0.6/Doc/usersguide/Images/gradient-radial.png
skencil/branches/skencil-0.6/Doc/usersguide/Images/layers.png
skencil/branches/skencil-0.6/Doc/usersguide/Images/selsize.png
skencil/branches/skencil-0.6/Doc/usersguide/Images/seltrafo.png
skencil/branches/skencil-0.6/Doc/usersguide/Images/sketch-logo.png
skencil/branches/skencil-0.6/Doc/usersguide/Images/textpath.png
skencil/branches/skencil-0.6/Doc/usersguide/Images/textpathrot.png
skencil/branches/skencil-0.6/Doc/usersguide/Images/textpathskew.png
skencil/branches/skencil-0.6/Doc/usersguide/concepts.xml
skencil/branches/skencil-0.6/Doc/usersguide/configuration.xml
skencil/branches/skencil-0.6/Doc/usersguide/quickint.xml
skencil/branches/skencil-0.6/Doc/usersguide/scripting.xml
skencil/branches/skencil-0.6/Doc/usersguide/usersguide.xml
Modified:
skencil/branches/skencil-0.6/ChangeLog
Log:
Add the docbook version of the documentation.
Modified: skencil/branches/skencil-0.6/ChangeLog
===================================================================
--- skencil/branches/skencil-0.6/ChangeLog 2006-06-01 15:34:15 UTC (rev 681)
+++ skencil/branches/skencil-0.6/ChangeLog 2006-06-05 18:35:01 UTC (rev 682)
@@ -1,3 +1,63 @@
+2006-06-05 Bernhard Herzog <bh at intevation.de>
+
+ Add the docbook version of the documentation.
+
+ * Doc/Makefile, Doc/README: New.
+
+ * Doc/devguide/architecture.xml, Doc/devguide/classes.xml,
+ Doc/devguide/connector.xml, Doc/devguide/coordsys.xml,
+ Doc/devguide/curveobj.xml, Doc/devguide/devguide.xml,
+ Doc/devguide/fileformat.xml, Doc/devguide/plugins.xml,
+ Doc/devguide/remarks.xml, Doc/devguide/ui.xml,
+ Doc/devguide/undo.xml:
+ New. docbook version of the developer's guide
+
+ * Doc/usersguide/concepts.xml, Doc/usersguide/configuration.xml,
+ Doc/usersguide/quickint.xml, Doc/usersguide/scripting.xml,
+ Doc/usersguide/usersguide.xml:
+ New. docbook version of the user's guide
+
+ * Doc/usersguide/Images/CreateCurve.png,
+ Doc/usersguide/Images/CreateEllipse.png,
+ Doc/usersguide/Images/CreatePoly.png,
+ Doc/usersguide/Images/CreateRect.png,
+ Doc/usersguide/Images/Delete.png,
+ Doc/usersguide/Images/Duplicate.png,
+ Doc/usersguide/Images/EditMode.png,
+ Doc/usersguide/Images/FlipHorizontal.png,
+ Doc/usersguide/Images/FlipVertical.png,
+ Doc/usersguide/Images/GridOn.png, Doc/usersguide/Images/Group.png,
+ Doc/usersguide/Images/Image.png,
+ Doc/usersguide/Images/MiniEyeClosed.png,
+ Doc/usersguide/Images/MiniEyeOpen.png,
+ Doc/usersguide/Images/MiniPrintOff.png,
+ Doc/usersguide/Images/MiniPrintOn.png,
+ Doc/usersguide/Images/MoveOneDown.png,
+ Doc/usersguide/Images/MoveOneUp.png,
+ Doc/usersguide/Images/MoveToBottom.png,
+ Doc/usersguide/Images/MoveToTop.png,
+ Doc/usersguide/Images/NewDocument.png,
+ Doc/usersguide/Images/Open.png, Doc/usersguide/Images/Redo.png,
+ Doc/usersguide/Images/Save.png,
+ Doc/usersguide/Images/SelectionMode.png,
+ Doc/usersguide/Images/Text.png, Doc/usersguide/Images/Undo.png,
+ Doc/usersguide/Images/Ungroup.png, Doc/usersguide/Images/Zoom.png,
+ Doc/usersguide/Images/arrow-left.png,
+ Doc/usersguide/Images/arrow-right.png,
+ Doc/usersguide/Images/arrow-up.png,
+ Doc/usersguide/Images/bullet.png,
+ Doc/usersguide/Images/gradient-conical.png,
+ Doc/usersguide/Images/gradient-linear.png,
+ Doc/usersguide/Images/gradient-radial.png,
+ Doc/usersguide/Images/layers.png,
+ Doc/usersguide/Images/selsize.png,
+ Doc/usersguide/Images/seltrafo.png,
+ Doc/usersguide/Images/sketch-logo.png,
+ Doc/usersguide/Images/textpath.png,
+ Doc/usersguide/Images/textpathrot.png,
+ Doc/usersguide/Images/textpathskew.png:
+ New. Images for the user's guide.
+
2006-03-18 Bernhard Herzog <bh at intevation.de>
* Sketch/Graphics/document.py (EditDocument.CanConvertToCurve)
Added: skencil/branches/skencil-0.6/Doc/Makefile
===================================================================
--- skencil/branches/skencil-0.6/Doc/Makefile 2006-06-01 15:34:15 UTC (rev 681)
+++ skencil/branches/skencil-0.6/Doc/Makefile 2006-06-05 18:35:01 UTC (rev 682)
@@ -0,0 +1,30 @@
+
+# all: usersguide devguide
+
+# usersguide devguide:
+# cd $@; $(MAKE)
+
+
+XSLTPROC=xsltproc
+XSLT_HTML_PARAMS=--stringparam base.dir html/ \
+ --stringparam use.id.as.filename 1
+XSLT_STYLESHEET=http://docbook.sourceforge.net/release/xsl/current/html/chunk.xsl
+
+HTMLINDEX=html/index.html
+
+HTML=html/index.html
+
+all: usersguide/$(HTML) devguide/$(HTML)
+
+usersguide/$(HTML): usersguide/*.xml
+devguide/$(HTML): devguide/*.xml
+
+%/$(HTML):
+ cd $*; \
+ rm -rf html ; \
+ $(XSLTPROC) $(XSLT_HTML_PARAMS) $(XSLT_STYLESHEET) $*.xml; \
+ test -d Images && (test -d html && cd html && ln -s ../Images/) || true
+
+clean:
+ cd usersguide; rm -rf html
+ cd devguide; rm -rf html
Property changes on: skencil/branches/skencil-0.6/Doc/Makefile
___________________________________________________________________
Name: svn:eol-style
+ native
Added: skencil/branches/skencil-0.6/Doc/README
===================================================================
--- skencil/branches/skencil-0.6/Doc/README 2006-06-01 15:34:15 UTC (rev 681)
+++ skencil/branches/skencil-0.6/Doc/README 2006-06-05 18:35:01 UTC (rev 682)
@@ -0,0 +1,37 @@
+Skencil documentation
+=====================
+
+The skencil documentation consists of two main parts:
+
+ User's Guide user documentation
+
+ Developer's Guide documentation of Skencil's internals for developers
+ and script authors
+
+
+Building the documentation
+--------------------------
+
+The documentation is written in DocBook XML and converted to HTML by
+docbook-xslt and xsltproc. On a debian sarge system you have to install
+the packages docbook-xml, docbook-xsl and xsltproc.
+
+With the relevant software installed and configured, it should be enough
+to simply run make in this directory. Afterwards, the HTML-version of
+the documentation should be in usersguide/html/ and devguide/html/
+respectively.
+
+
+Documentation conventions
+-------------------------
+
+Some conventions to keep in mind when modifying the documentation:
+
+ - The documents are split into several HTML files with one file being
+ generated for every chapter and sect1 element. The names of the
+ HTML files are derived from the id's of those elements. Therefore,
+ all chapter and sect1 elements should have an id attribute. Also,
+ the id of all sect1 elements of a chapter should have the same
+ prefix which is derived from the chapter's id. E.g. the scripting
+ chapter has the id "script" and all id's of the sect1's in the
+ chapter start with "script-".
Property changes on: skencil/branches/skencil-0.6/Doc/README
___________________________________________________________________
Name: svn:eol-style
+ native
Added: skencil/branches/skencil-0.6/Doc/devguide/architecture.xml
===================================================================
--- skencil/branches/skencil-0.6/Doc/devguide/architecture.xml 2006-06-01 15:34:15 UTC (rev 681)
+++ skencil/branches/skencil-0.6/Doc/devguide/architecture.xml 2006-06-05 18:35:01 UTC (rev 682)
@@ -0,0 +1,100 @@
+<chapter id="architecture"><title>The Design of Skencil</title>
+ <para>
+ Skencil is written almost completely in Python, an object oriented
+ interpreted programming language. Python can easily be extended by
+ modules written in C to increase performance and Skencil uses this
+ fact to implement some time critical functions and Python objects in
+ C.
+ </para>
+ <para>
+ The source code of Skencil can be divided roughly into these parts:
+ <variablelist>
+ <varlistentry><term>User Interface</term>
+ <listitem>
+ <para>
+ Skencil currently uses the Tk Toolkit via the Tkinter module
+ from the standard Python library. Skencil only uses some
+ generic widgets like buttons, menus and scrollbars and none
+ of the more sophisticated widgets like Tk's Text or Canvas
+ widgets. The main widget where the drawing is displayed is a
+ Tk widget that is almost entirely implemented in Python
+ using a C-module that provides GCs, Pixmaps, Fonts etc as
+ Python objects (This module is heavily based on the Xt
+ module).
+ </para>
+ <para>
+ Skencil also has some classes that provide a more abstract
+ interface to generic GUI elements like buttons and menus
+ that hopefully make it relatively simple to switch to
+ another toolkit. In fact I already switched toolkits once,
+ from Xt/Athena to Tk, which was simpler than I had
+ expected...
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry><term>Graphics Devices</term>
+ <listitem>
+ <para>
+ Skencil defines several classes for drawing into a window or
+ into a PostScript file that share a common, generic
+ interface. This allows us to use the same code for drawing
+ on the screen and for printing.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry><term>Document- and Graphics Objects</term>
+ <listitem>
+ <para>
+ These objects represent entire documents and the parts
+ thereof in an abstract way. This representation is
+ independent of any particular output device or operating
+ system.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry><term>File IO</term>
+ <listitem>
+ <para>
+ Skencil has classes and functions for reading drawings in
+ several formats (well, just three as of this
+ writing). Skencil of course defines its own special format
+ and can read and write this. In addition, there is currently
+ partial support for reading and writing SVG and Adobe
+ Illustrator (AI) files, just to name a few.
+ </para>
+ <para>
+ For reading bitmap graphics Skencil uses the Python Imaging
+ Library so that it should be able to read everything that
+ this library can read.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry><term>Miscellaneous</term>
+ <listitem>
+ <para>
+ There are a variety of support modules that provide objects
+ representing 2D points/vectors, rectangles, affine
+ transformations, fonts and font-metrics, or code to handle
+ postscript files and a generic
+ <link linkend="connector">message passing mechanism</link>.
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </para>
+ <para>
+ Skencil uses a variation of the model/view/controller concept. The
+ document and graphics object classes form the model which represents
+ the drawing in a device independent way and which can be manipulated
+ through a specific set of methods. The
+ class <literal>SketchCanvas</literal> serves both as the main view
+ and controller. It manages a window graphics device that is used to
+ display that drawing and it accepts user input in the form of mouse
+ and keyboard events and translates them into method invocations on
+ the document object.
+ </para>
+</chapter>
Added: skencil/branches/skencil-0.6/Doc/devguide/classes.xml
===================================================================
--- skencil/branches/skencil-0.6/Doc/devguide/classes.xml 2006-06-01 15:34:15 UTC (rev 681)
+++ skencil/branches/skencil-0.6/Doc/devguide/classes.xml 2006-06-05 18:35:01 UTC (rev 682)
@@ -0,0 +1,974 @@
+<chapter id="classes"><title>The Document and Graphics Classes</title>
+ <para>
+ The document is represented by a tree of graphics objects. The
+ document consists of one or more layers. Each layer consists of zero
+ or more primitives or compound objects.
+ </para>
+ <para>
+ Primitives are the leaves of the tree and contain no other graphics
+ objects, examples are Rectangles or PolyBezier objects. Most
+ primitives can have line and fill properties (Text objects currently
+ can only have fill properties and image objects have neither fill
+ nor line properties).
+ </para>
+ <para>
+ Compound objects are graphics objects that contain other graphics
+ objects, examples are the ordinary Group or the BlendGroup.
+ </para>
+
+ <sect1 id="class-hierarchy"><title>Class Hierarchy</title>
+ <para>
+ <itemizedlist>
+ <listitem>
+ <para><link linkend="class-Selectable"><classname>Selectable</classname></link></para>
+ <itemizedlist>
+ <listitem>
+ <para><link linkend="class-GraphicsObject"><classname>GraphicsObject</classname></link>
+ </para>
+ <itemizedlist>
+ <listitem>
+ <para><link linkend="class-Primitive"><classname>Primitive</classname></link></para>
+ <itemizedlist>
+ <listitem>
+ <para>
+ <classname>PolyBezier</classname>
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <classname>RectangularPrimitive</classname>
+ </para>
+ <itemizedlist>
+ <listitem>
+ <para><classname>Ellipse</classname></para>
+ </listitem>
+ <listitem>
+ <para>
+ <link linkend="class-Rectangle"><classname>Rectangle</classname></link>
+ </para>
+ </listitem>
+ </itemizedlist>
+ </listitem>
+ </itemizedlist>
+ </listitem>
+ <listitem>
+ <para>
+ <link linkend="class-Compound"><classname>Compound</classname></link>
+ </para>
+ <itemizedlist>
+ <listitem>
+ <para><classname>EditableCompound</classname></para>
+ <itemizedlist>
+ <listitem>
+ <para><classname>Group</classname></para>
+ </listitem>
+ <listitem>
+ <para><classname>Layer</classname></para>
+ <itemizedlist>
+ <listitem>
+ <para><classname>SpecialLayer</classname></para>
+ <itemizedlist>
+ <listitem>
+ <para>
+ <classname>GuideLayer</classname>
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <classname>GridLayer</classname>
+ </para>
+ </listitem>
+ </itemizedlist>
+ </listitem>
+ </itemizedlist>
+ </listitem>
+ </itemizedlist>
+ </listitem>
+ </itemizedlist>
+ </listitem>
+ </itemizedlist>
+ </listitem>
+ <listitem>
+ <para><classname>EditSelect</classname></para>
+ <itemizedlist>
+ <listitem>
+ <para><classname>SelectAndDrag</classname></para>
+ <itemizedlist>
+ <listitem>
+ <para><classname>Editor</classname></para>
+ <itemizedlist>
+ <listitem>
+ <para><classname>EllipseEditor</classname></para>
+ </listitem>
+ <listitem>
+ <para><classname>PolyBezierEditor</classname></para>
+ </listitem>
+ </itemizedlist>
+ </listitem>
+ <listitem>
+ <para><classname>Creator</classname></para>
+ <itemizedlist>
+ <listitem>
+ <para><classname>RectangularCreator</classname></para>
+ <itemizedlist>
+ <listitem>
+ <para><classname>EllipseCreator</classname></para>
+ </listitem>
+ <listitem>
+ <para><classname>RectangleCreator</classname></para>
+ </listitem>
+ </itemizedlist>
+ </listitem>
+ <listitem>
+ <para><classname>PolyBezierCreator</classname></para>
+ </listitem>
+ </itemizedlist>
+ </listitem>
+ </itemizedlist>
+ </listitem>
+ </itemizedlist>
+ </listitem>
+ </itemizedlist>
+ </listitem>
+ </itemizedlist>
+ </para>
+ </sect1>
+
+ <sect1 id="class-GraphicsObject">
+ <title>The class <classname>GraphicsObject</classname></title>
+ <para>
+ Base Classes: <link linkend="class-Bounded"><classname>Bounded</classname></link>,
+ <link linkend="class-HierarchyNode"><classname>HierarchyNode</classname></link>,
+ <link linkend="class-Selectable"><classname>Selectable</classname></link>
+ and <link linkend="class-Protocols"><classname>Protocols</classname></link>.
+ </para>
+ <para>
+ The class <classname>GraphicsObject</classname> defines the
+ interface common to all graphics objects.
+ </para>
+ <para>
+ For convenience of implementation, and because their interfaces
+ are needed elsewhere in the class hierarchy as well, some parts of
+ this interface are defined by the base classes:
+ </para>
+ <para>
+ <variablelist>
+ <varlistentry>
+ <term><link linkend="class-Bounded"><classname>Bounded</classname></link></term>
+ <listitem>
+ <para>
+ provides instance variables for the vertical and
+ horizontal dimensions of a graphics object and some
+ related methods.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><link linkend="class-HierarchyNode"><classname>HierarchyNode</classname></link></term>
+ <listitem>
+ <para>
+ provides the default behavior for all methods related to
+ the management of the object hierarchy in the document.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><link linkend="class-Selectable"><classname>Selectable</classname></link></term>
+ <listitem>
+ <para>
+ defines the generic interface and default behavior for
+ selection.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><link linkend="class-Protocols"><classname>Protocols</classname></link></term>
+ <listitem>
+ <para>
+ has some variables that describe the object's
+ capabilities.
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </para>
+
+ <sect2><title>Instance Variables</title>
+ <para>
+ <classname>GraphicsObject</classname> maintains no
+ instance variables of its own, but uses those managed by its
+ base classes.
+ </para>
+ </sect2>
+ <sect2>
+ <title>Methods</title>
+ <para>
+ Methods defined in <classname>GraphicsObject</classname>:
+ </para>
+ <para>
+ <variablelist>
+ <varlistentry id="GraphicsObject.Blend">
+ <term><literal>Blend(<parameter>other</parameter>, <parameter>frac1</parameter>, <parameter>frac2</parameter>)</literal></term>
+ <listitem>
+ <para>
+ Return the weighted average of
+ <parameter>self</parameter>
+ and <parameter>other</parameter>.
+ <parameter>frac1</parameter>
+ and <parameter>frac2</parameter> are the weights
+ (if <parameter>self</parameter> and
+ <parameter>other</parameter> were numbers this should
+ be <parameter>frac1</parameter>
+ * <parameter>self</parameter>
+ + <parameter>frac2</parameter>
+ * <parameter>other</parameter>).
+ </para>
+ <para>
+ This method is used by the function
+ <function>Blend</function> in
+ <filename>blend.py</filename>.
+ If <parameter>self</parameter>
+ and <parameter>other</parameter> can't be blended,
+ raise the <literal>blend.Mismatch</literal>
+ exception. This is the default behavior.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry id="GraphicsObject.AsBezier">
+ <term><literal>AsBezier()</literal></term>
+ <listitem>
+ <para>
+ Return self as a <classname>PolyBezier</classname>
+ object if possible. If this is not possible,
+ return <literal>None</literal>.
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </para>
+ <para>
+ The following methods are not implemented
+ in <classname>GraphicsObject</classname> directly, but must be
+ defined for every graphics object. The derived
+ classes <link
+ linkend="class-Primitive"><classname>Primitive</classname></link>
+ and <link
+ linkend="class-Compound"><classname>Compound</classname></link>
+ provide a default implementation for most objects.
+ </para>
+ <variablelist>
+ <varlistentry id="GraphicsObject.Transform">
+ <term>
+ <literal>Transform(<parameter>trafo</parameter>)</literal>
+ </term>
+ <listitem>
+ <para>
+ Apply the <link linkend="class-Trafo">transformation
+ object</link>
+ <parameter>trafo</parameter> to self. Return undo info.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry id="GraphicsObject.Translate">
+ <term>
+ <literal>Translate(<parameter>offset</parameter>)</literal>
+ </term>
+ <listitem>
+ <para>
+ Translate (move) self by <parameter>offset</parameter>.
+ <parameter>offset</parameter> is a
+ <link linkend="class-Point">point object</link>. Return
+ undo info.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry id="GraphicsObject.DrawShape">
+ <term><literal>DrawShape(<parameter>device</parameter> [, <parameter>clip</parameter>])</literal></term>
+ <listitem>
+ <para>
+ Draw self on <parameter>device</parameter>.
+ <parameter>device</parameter> is a graphics device.
+ </para>
+ <para>
+ The optional parameter <parameter>clip</parameter> is only
+ provided if the object is used as a clip mask. If it is
+ provided its value is 1. Objects that can be used as clip
+ masks (their <literal>is_clip</literal> flag is true)
+ request appropriate clipping from the graphics device.
+ Objects that cannot be used as clip masks don't need to
+ accept it.
+ </para>
+ <para>
+ (Note: The clipping interface for the high level drawing
+ operations of the graphics devices is somewhat
+ experimental)
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry id="GraphicsObject.SaveToFile">
+ <term>
+ <literal>SaveToFile(<parameter>file</parameter>)</literal>
+ </term>
+ <listitem>
+ <para>
+ Save self to file. The
+ argument <parameter>file</parameter> is currently an
+ instance of the class <classname>SKSaver</classname> which
+ provides special methods for the object types currently
+ implemented in Skencil.
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </sect2>
+ </sect1>
+
+ <sect1 id="class-Bounded">
+ <title>The class <classname>Bounded</classname></title>
+ <para>
+ In Skencil, each graphics object has a <emphasis>bounding
+ rectangle</emphasis> and a
+ <emphasis>coordinate rectangle</emphasis>. The sides of both
+ rectangles are parallel to the coordinate axes.
+ </para>
+ <para>
+ The bounding rectangle is a rectangle that contains the entire
+ object. Any marks the object or its children leave on the paper
+ when printed lie in it. Ideally it should be the smallest such
+ rectangle, but in practice it is sometimes difficult and indeed
+ not always desirable to get exactly the smallest one. In any case,
+ the bounding rectangle must contain the entire object.
+ </para>
+ <para>
+ Skencil uses the bounding rect for three purposes: to decide,
+ which parts of the screen to redraw, as an aid when deciding which
+ objects to select and to compute the BoundingBox of an EPS-File.
+ </para>
+ <para>
+ The coordinate rectangle is the smallest rectangle that contains
+ the entire object without taking the line width into
+ account. Skencil uses this rectangle for layout purposes and as
+ the reference for interactive resize- and transformation
+ operations.
+ </para>
+ <para>
+ The coordinate rectangle of an object should always lie completely
+ inside of the bounding rectangle. Both rectangles may be (and for
+ many object types they are) identical.
+ </para>
+ <para>
+ Since <classname>Bounded</classname>'s variables are used for
+ layout calculations, it provides access to and default behavior
+ for the <emphasis>layout point</emphasis>. The layout point is the
+ point of an object that should lie exactly on the grid or on other
+ special points.
+ </para>
+ <para>
+ By default, the layout point is the lower left corner of the
+ coordinate rectangle. For images this is the lower left corner of
+ the image which is not identical to the default if the image was
+ transformed. For text objects with default justification, the
+ layout point is the origin of the first letter, which is on the
+ baseline, whereas the coordinate rectangle takes the descender
+ into account.
+ </para>
+
+ <sect2><title>Instance Variables</title>
+ <para>
+ <classname>Bounded</classname> provides the following instance
+ variables
+ </para>
+ <variablelist>
+ <varlistentry><term><literal>bounding_rect</literal>:</term>
+ <listitem>
+ <para>
+ the bounding rectangle
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry><term><literal>coord_rect</literal>:</term>
+ <listitem>
+ <para>
+ the coordinate rectangle
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ <para>
+ These instance variables are public attributes. Skencil uses
+ <literal>bounding_rect</literal> to speed up the search for the
+ object a mouse click has hit (when the point the user clicked on
+ is outside of the bounding rect, the object cannot be hit). This
+ test is significantly faster when the bounding rectangle is read
+ directly from an attribute instead of accessed through a method
+ call.
+ </para>
+ </sect2>
+
+ <sect2><title>Methods</title>
+ <para>
+ <classname>Bounded</classname> implements lazy evaluation for
+ its public instance variables (<literal>bounding_rect</literal>
+ and <literal>coord_rect</literal>). When one of these variables
+ is not defined, <classname>Bounded</classname>'s
+ <link
+ linkend="Bounded.__getattr__"><function>__getattr__</function></link>
+ method invokes the
+ method <link
+ linkend="Bounded.update_rects"><function>update_rects</function></link>
+ to compute the rectangles and set the variables. To force
+ recomputation when these variables are read next, a derived
+ class may call
+ <link
+ linkend="Bounded.del_lazy_attrs"><function>del_lazy_attrs</function></link>.
+ </para>
+ <para>
+ This lazy evaluation mechanism is not limited to the instance
+ variables mentioned above. <literal>__getattr__</literal>
+ consults the dictionary <literal>self._lazy_attrs</literal> to
+ determine, whether the requested attribute is a lazy attribute:
+ if <literal>self._lazy_attrs</literal> has the attribute as a
+ key the attribute is treated as a lazy attribute. The value
+ associated with that key must be the name of the method to call
+ to recompute the value of the attribute.
+ <literal>__getattr__</literal> calls this method and expects
+ that <literal>self</literal> has that attribute after the method
+ has run.
+ </para>
+ <para>
+ <literal>_lazy_attrs</literal> is a class variable
+ of <classname>Bounded</classname>. If a derived class needs
+ additional lazy attributes, it should create its own class
+ variable <literal>_lazy_attrs</literal> as a copy of its
+ base-class' <literal>_lazy_attrs</literal> and add the
+ appropriate keys:
+ </para>
+ <para>
+<programlisting>
+class MyObject(GraphicsObject):
+
+ _lazy_attrs = GraphicsObject._lazy_attrs.copy()
+ _lazy_attrs['my_lazy_attribute'] = 'update_my_lazy_attr'
+
+ # somewhere in the class definition:
+ def update_my_lazy_attr(self):
+ # compute the new value of my_lazy_attr...
+ # ... and finally:
+ self.my_lazy_attribute = new_value
+</programlisting>
+ </para>
+ <para>
+ Thus <classname>Bounded</classname>'s methods are:
+ </para>
+ <variablelist>
+ <varlistentry id="Bounded.del_lazy_attrs">
+ <term><literal>del_lazy_attrs()</literal></term>
+ <listitem>
+ <para>
+ Delete the "lazy" instance variables. Any attempt to
+ access a lazy attribute later triggers its recomputation
+ via the <literal>__getattr__</literal> method.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry id="Bounded.update_rects">
+ <term><literal>update_rects()</literal></term>
+ <listitem>
+ <para>
+ <literal>Bounded.__getattr__</literal> invokes this method
+ whenever one of the attributes
+ <literal>bounding_rect</literal>
+ or <literal>coord_rect</literal> is not set.
+ </para>
+ <para>
+ This method <emphasis>must</emphasis> be supplied by some
+ derived class and it <emphasis>must</emphasis> compute
+ both rectangles.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry id="Bounded.__getattr__">
+ <term><literal>__getattr__(<parameter>attr</parameter>)</literal></term>
+ <listitem>
+ <para>
+ If <literal>self._lazy_attrs.has_key(attr)</literal> is
+ true, invoke
+ <literal>getattr(self, self._lazy_attrs[attr])()</literal>
+ to recompute the attribute.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry id="Bounded.LayoutPoint">
+ <term><literal>LayoutPoint()</literal></term>
+ <listitem>
+ <para>
+ Return the layout point of self as
+ a <link linkend="class-Point">point object</link>. Default
+ is the lower left corner of
+ <literal>self.coord_rect</literal>.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry id="Bounded.GetSnapPoints">
+ <term><literal>GetSnapPoints()</literal></term>
+ <listitem>
+ <para>
+ Return a list of <link linkend="class-Point">point
+ objects</link> indicating the "hot spots" of the graphics
+ object. These points are used when "Snapping to Objects"
+ is active. The default implementation returns an empty
+ list.
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </sect2>
+ </sect1>
+
+ <sect1 id="class-HierarchyNode">
+ <title>The class <classname>HierarchyNode</classname></title>
+ <para>
+ In Skencil, a document consists of a hierarchy of objects. Each
+ object has at most one parent and belongs to at most one
+ document. That is, an object may not belong to any compound object
+ or document, but if it belongs to one, it cannot be part of two
+ compound objects or two documents.
+ </para>
+ <para>
+ An object in this hierarchy knows which parent and document it
+ belongs to.
+ </para>
+ <para>
+ The class <classname>HierarchyNode</classname> provides the
+ standard interface for managing this hierarchy and the references
+ to the parent and the document for child objects. The default
+ behavior for parents is defined by the
+ class <link
+ linkend="class-Compound"><classname>Compound</classname></link>.
+ </para>
+ <para>
+ No object derived from this class should override the methods
+ defined here except as documented.
+ </para>
+
+ <sect2><title>Instance Variables</title>
+ <para>
+ <classname>HierarchyNode</classname> uses the following
+ instance variables:
+ </para>
+ <variablelist>
+ <varlistentry><term><literal>parent</literal></term>
+ <listitem>
+ <para>
+ The parent of the object. Since the parent also has a
+ reference to its child this introduces a circular
+ reference. Therefore we must make sure that these
+ references are deleted when the document is destroyed.
+ The <link
+ linkend="HierarchyNode.Destroy"><function>Destroy</function></link>
+ method takes care of this.
+ </para>
+ <para>
+ If the object is not currently the child of a compound
+ object this variable should be <literal>None</literal>.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry><term><literal>document</literal></term>
+ <listitem>
+ <para>
+ The document the object belongs to. If the object has
+ just been created and is not yet inserted into the
+ document, or when the object is stored in the
+ application's clipboard, this variable is
+ <literal>None</literal>.
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ <para>
+ In general, if <literal>parent</literal> is
+ not <literal>None</literal>, <literal>document</literal>
+ should be the same as <literal>parent.document</literal>.
+ </para>
+ </sect2>
+
+ <sect2><title>Methods</title>
+ <para>
+ Methods defined in <classname>HierarchyNode</classname>
+ (incomplete):
+ </para>
+ <variablelist>
+ <varlistentry id="HierarchyNode.__init__">
+ <term><function>__init__</function></term>
+ <listitem>
+ <para>
+ A <classname>HierarchyNode</classname>'s
+ <function>__init__</function> method (and that of all
+ derived classes) must accept an optional keyword argument
+ called <literal>duplicate</literal> with the default
+ value <literal>None</literal> and it must be callable with
+ just that argument. This is used by the standard <link
+ linkend="HierarchyNode.Duplicate"><function>Duplicate</function></link>
+ method.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry id="HierarchyNode.Destroy">
+ <term><function>Destroy()</function></term>
+ <listitem>
+ <para>
+ Called by the parent when the document is
+ destroyed. This method should delete any circular
+ references. A Compound object should call the
+ <function>Destroy</function> method of each of its
+ children.
+ </para>
+ <para>
+ The default implementation just sets
+ <literal>parent</literal> to <literal>None</literal>.
+ Derived classes should extend this method if necessary.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry id="HierarchyNode.SetParent">
+ <term>
+ <function>SetParent(<parameter>parent</parameter>)</function>
+ </term>
+ <listitem>
+ <para>
+ Set self's instance variable <literal>parent</literal>
+ to <parameter>parent</parameter>.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry id="HierarchyNode.SetDocument">
+ <term>
+ <function>SetDocument(<parameter>document</parameter>)</function>
+ </term>
+ <listitem>
+ <para>
+ Set self's instance variable <literal>document</literal>
+ to <parameter>document</parameter>.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry id="HierarchyNode.Duplicate">
+ <term><function>Duplicate()</function></term>
+ <listitem>
+ <para>
+ Return a duplicate of self. The default implementation
+ just returns
+ <literal>self.__class__(duplicate = self)</literal>.
+ Therefore, the class's constructor must be callable with
+ a single keyword argument <literal>duplicate</literal>.
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </sect2>
+ </sect1>
+
+ <sect1 id="class-Protocols">
+ <title>The class <classname>Protocols</classname></title>
+ <para>
+ While sharing a common interface, the various types of graphics
+ objects provide a variety of additional capabilities and
+ interfaces. The class <classname>Protocols</classname> defines
+ some flags that indicate the presence of certain standard
+ extensions. These flags are boolean class variables with names of
+ the form "<literal>is_</literal>*" or
+ "<literal>has_</literal>*". By default all of these flags are
+ false. Derived classes are expected to set the appropriate flags.
+ </para>
+ <para>
+ The standard flags are:
+ </para>
+ <variablelist>
+ <varlistentry>
+ <term><literal>has_properties</literal></term>
+ <listitem>
+ <para>
+ True, iff object can have properties. If true, the object
+ must implement the
+ methods <function>AddStyle</function>,
+ <function>Properties</function>,
+ <function>SetProperties</function>,
+ <function>ObjectChanged</function> and
+ <function>ObjectRemoved</function>.
+ </para>
+ <para>
+ The class <link linkend="class-Primitive"><classname>Primitive</classname></link>
+ provides this interface.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry><term><literal>has_fill</literal></term>
+ <listitem>
+ <para>
+ True, iff object can have fill properties. If true,
+ <literal>has_properties</literal> must also be true. In
+ addition, the object must implement the
+ method <function>Filled</function> and the
+ method <function>SetProperties</function> must
+ accept the fill properties.
+ </para>
+ <para>
+ The class <link linkend="class-Primitive"><classname>Primitive</classname></link>
+ provides this interface.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry><term><literal>has_line</literal></term>
+ <listitem>
+ <para>
+ True, iff object can have line properties. If true,
+ <literal>has_properties</literal> must also be true. In
+ addition, the object must implement the
+ method <function>LineWidth</function> and the
+ method <function>SetProperties</function> must
+ accept the line properties.
+ </para>
+ <para>
+ The class <link linkend="class-Primitive"><classname>Primitive</classname></link>
+ provides this interface.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry><term><literal>has_font</literal></term>
+ <listitem>
+ <para>
+ True, iff object can have a font. If
+ true, <literal>has_properties</literal> must also be
+ true. In addition, the
+ method <function>SetProperties</function> must accept the
+ font properties.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><literal>is_Bezier</literal></term>
+ <term><literal>is_Rectangle</literal></term>
+ <term><literal>is_Ellipse</literal></term>
+ <term><literal>is_Text</literal></term>
+ <term><literal>is_Image</literal></term>
+ <term><literal>is_Eps</literal></term>
+ <listitem>
+ <para>
+ Indicate the type of object.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><literal>is_Compound</literal></term>
+ <listitem>
+ <para>
+ True, iff the object is a compound object.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><literal>is_Group</literal></term>
+ <listitem>
+ <para>
+ True, iff the object is a group. A group is a compound
+ object. A group object can
+ be <emphasis>ungrouped</emphasis>, that is, the user can
+ issue a command that replaces the group with its children,
+ which become direct children of the group's parent. To this
+ end, a group must provide the
+ method <function>Ungroup</function>. (see the document
+ method <function>UngroupSelected</function>)
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><literal>is_Blend</literal></term>
+ <listitem>
+ <para>
+ True, iff the object is a blend group.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><literal>is_curve</literal></term>
+ <listitem>
+ <para>
+ True, iff the object can be converted to a
+ <classname>PolyBezier</classname> object. If true, the
+ object must implement the methods <link
+ linkend="GraphicsObject.AsBezier"><function>AsBezier</function></link>
+ and <function>Paths</function>.
+ </para>
+ <para>
+ Skencil treats the PolyBezier as a kind of "common
+ denominator" for blending. For instance, if you try to blend
+ a rectangle and an ellipse, both are converted to beziers
+ and the beziers are blended.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><literal>is_clip</literal></term>
+ <listitem>
+ <para>
+ True, iff the object may be used as a clip mask. If true,
+ the methods
+ <link
+ linkend="Selectable.Hit"><function>Hit</function></link>
+ and <link
+ linkend="GraphicsObject.DrawShape"><function>DrawShape</function></link>
+ must accept an additional boolean
+ parameter <literal>clip</literal> indicating whether the
+ object is used as a clip mask.
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </sect1>
+
+ <sect1 id="class-Selectable">
+ <title>The class <classname>Selectable</classname></title>
+ <para>
+ The class <classname>Selectable</classname> defines the interface
+ for objects that can be selected with the mouse. This includes
+ tests for whether the object is hit by a mouse click and methods
+ for the handles.
+ </para>
+
+ <sect2><title>The Selection Mechanism</title>
+ <para>
+ Yet to be written...
+ </para>
+ </sect2>
+
+ <sect2><title>Methods</title>
+ <para>
+ A <classname>Selectable</classname> object has these methods:
+ </para>
+ <variablelist>
+ <varlistentry id="Selectable.Hit">
+ <term><!-- methdef -->Hit(<parameter>p</parameter>, <parameter>rect</parameter>, <parameter>device</parameter>
+ [, <parameter>clip</parameter>])<!-- /methdef --></term>
+ <listitem>
+ <para>
+ Return true if clicking at <parameter>p</parameter>
+ (a <link linkend="class-Point">point object</link>) should
+ select the object. The
+ parameter <parameter>device</parameter> is a graphics
+ device that can convert points
+ between <link linkend="coordinatesystems">document
+ coordinates and window coordinates</link>.
+ <parameter>p</parameter> is always given in document
+ coordinates.
+ </para>
+ <para>
+ <parameter>rect</parameter> is a
+ <link linkend="class-Rect">rect object</link> in
+ doc-coordinates that describes a small area
+ around <parameter>p</parameter> (a few pixels wide). A
+ point of the object should be considered "hit" if it lies
+ inside this rectangle.
+ </para>
+ <para>
+ The <parameter>device</parameter> parameter is necessary,
+ because clicking on a special point should have some
+ tolerance, so that "missing" by a few pixels still selects
+ that point. Unfortunately, pixels are screen coordinates
+ and the object's coordinates are document coordinates, so
+ conversion between the two is sometimes necessary.
+ <parameter>device</parameter> has some methods for this
+ and also for testing if certain primitives are hit.
+ Currently <parameter>device</parameter> is an instance
+ of <classname>HitTestDevice</classname>.
+ </para>
+ <para>
+ The optional parameter <parameter>clip</parameter> is only
+ provided if the object is used as a clip mask. If it is
+ provided its value is 1. Objects that can be used as clip
+ masks (their <literal>is_clip</literal> flag is true)
+ should test whether <parameter>p</parameter> is inside of
+ the object regardless of whether they are filled or
+ not. Objects that cannot be used as clip masks don't need
+ to accept it.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry id="Selectable.SelectSubobject">
+ <term><function>SelectSubobject(<parameter>p</parameter>, <parameter>rect</parameter>, <parameter>device</parameter>[, <parameter>path</parameter>])</function></term>
+ <listitem>
+ <para>
+ When the parent decides that one of its children (or one
+ of the child's descendants) is to be selected (this is
+ determined using the children's bounding rects and
+ their <function>Hit</function> methods), it calls this
+ method to ask the child for details.
+ </para>
+ <para>
+ Normally, self should be returned (this is also the
+ default behavior). To select a subobject, return selection
+ info relative to self as a single tuple of selection
+ info. (see selinfo.py)
+ </para>
+ <para>
+ Compound objects like groups and layers override this
+ method to let the user select their children.
+ </para>
+ <para>
+ As in <link
+ linkend="Selectable.Hit"><function>Hit</function></link>,
+ <parameter>p</parameter> and <parameter>rect</parameter>
+ describe a point and a small tolerance rectangle around
+ it, and <parameter>device</parameter> is
+ a <classname>HitTestDevice</classname>. The optional
+ argument <parameter>path</parameter> is useful only for
+ compound objects but has to be accepted by all graphics
+ objects.
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </sect2>
+ </sect1>
+
+ <sect1 id="class-Primitive">
+ <title>The class <classname>Primitive</classname></title>
+ <para>
+ </para>
+ </sect1>
+
+ <sect1 id="class-Compound">
+ <title>The class <classname>Compound</classname></title>
+ <para>
+ </para>
+ </sect1>
+
+ <sect1 id="class-Rectangle">
+ <title>The class <classname>Rectangle</classname></title>
+ <para>
+ The class <classname>Rectangle</classname> represents the drawing
+ primitive of a parallelogram with optional rounded corners. When
+ drawn interactively the object is an axis aligned rectangle. After
+ applying affine transformations the rectangle may not be a
+ rectangle anymore, but it will remain a parallelogram.
+ </para>
+ <para>
+ In Skencil, a rectangle is represented by the affine
+ transformation necessary to map the unit square (opposite corners
+ (0, 0) and (1, 1)), to the parallelogram. This is an elegant and
+ convenient but also somewhat unusual representation.
+ </para>
+ <para>
+ The transformation is of course stored as
+ a <link linkend="class-Trafo">transformation object</link>.
+ </para>
+ <para>
+ The rounded corners are defined by two floating point numbers
+ radius1 and radius2. Both numbers define a radius of the ellipses
+ that make up the rounded corners of the unit square, radius1
+ defines the horizontal radius and radius2 the vertical
+ radius. Valid values lie in the range 0.0 <= radius1,radius2
+ <= 0.5.
+ </para>
+ </sect1>
+</chapter>
Added: skencil/branches/skencil-0.6/Doc/devguide/connector.xml
===================================================================
--- skencil/branches/skencil-0.6/Doc/devguide/connector.xml 2006-06-01 15:34:15 UTC (rev 681)
+++ skencil/branches/skencil-0.6/Doc/devguide/connector.xml 2006-06-05 18:35:01 UTC (rev 682)
@@ -0,0 +1,293 @@
+<chapter id="connector"><title>Message Passing</title>
+ <para>
+ In a Model-View-Controller architecture like the one used in
+ Skencil, the model has to inform the views when the data has changed
+ and the views have to be updated. Often there can be several views
+ for one model object and it is desirable to implement the model in
+ such a way that it doesn't have to know how many and what types of
+ view there actually are at any one point in time. Still, the views
+ have to be informed by the model that they should update themselves
+ whenever the model changes. In Skencil this is achieved through a
+ generic message passing mechanism similar to the signals used in Qt
+ or GTK.
+ </para>
+
+ <sect1 id="connector-concepts"><title>Concepts</title>
+ <para>
+ <emphasis>Messages</emphasis> are generated by
+ <emphasis>publishers</emphasis> and consist of a
+ <emphasis>message type</emphasis> represented by a string and an
+ arbitrary number of arguments. The message type is also called
+ a <parameter>channel</parameter>.
+ </para>
+ <para>
+ Program parts that want to receive messages subscribe to a channel
+ of a particular publisher by passing a callable object, often a
+ bound instance method, and optionally some additional arguments to
+ the publisher.
+ </para>
+ <para>
+ When the publisher issues a message all subscribers of the relevat
+ channel of the publisher all called with the message arguments and
+ the additional subscriber specific arguments.
+ </para>
+ <para>
+ The heart of this mechanism is the <link
+ linkend="class-Connector"><classname>Connector</classname></link>
+ class, whose instances manage all connections between publishers
+ and subscribers. This way, a publisher that has no subscribers
+ does not use any resources.
+ </para>
+ <para>
+ The connector module has one global
+ <classname>Connector</classname> instance and some of its methods
+ are available as globals.
+ </para>
+ <para>
+ There are two additional classes for publisher objects. <link
+ linkend="class-Publisher"><classname>Publisher</classname></link>
+ provides methods to subscribe to and unsubscribe from channels of
+ the object. <link
+ linkend="class-QueueingPublisher"><classname>QueueingPublisher</classname></link>
+ allows the publisher to accumulate messages in a queue with
+ identical messages queued only once and release them all at once.
+ </para>
+ <para>
+ Most objects that send messages are derived from one of these
+ publisher objects and in most circumstances their methods are used
+ to connect to their channels. The connector is rarely used
+ directly.
+ </para>
+ </sect1>
+
+ <sect1 id="class-Connector">
+ <title>The Class <classname>Connector</classname></title>
+ <variablelist>
+ <varlistentry id="Connector.Connect">
+ <term><function>Connect(<parameter>publisher</parameter>, <parameter>channel</parameter>, <parameter>subscriber</parameter>, <parameter>args</parameter>)</function></term>
+ <listitem>
+ <para>
+ Connect the <parameter>subscriber</parameter>, i.e. a
+ callable object and additional arguments
+ <parameter>args</parameter>, to a
+ <parameter>channel</parameter> of a
+ <parameter>publisher</parameter>.
+ </para>
+ <para>
+ The <parameter>publisher</parameter> can be any object,
+ though most of the time it's a <link
+ linkend="class-Publisher"><classname>Publisher</classname></link>
+ instance. Skencil uses the <literal>None</literal> object
+ as a publisher for global messages.
+ </para>
+ <para>
+ <parameter>args</parameter> are subscriber specific
+ arguments as a tuple.
+ </para>
+ <para>
+ The same subscriber may be registered multiple times but it
+ is only stored once in the list of subscribers. Two
+ subscribers are considered equal if the callable object and
+ the arguments are equal.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry id="Connector.Disconnect">
+ <term><function>Disconnect(<parameter>publisher</parameter>, <parameter>channel</parameter>, <parameter>subscriber</parameter>,
+ <parameter>args</parameter>)</function></term>
+ <listitem>
+ <para>
+ Disconnect <parameter>subscriber</parameter> from
+ <parameter>publisher</parameter>'s <parameter>channel</parameter>.
+ </para>
+ <para>
+ The arguments have the same meaning as in <link
+ linkend="Connector.Connect"><function>Connect</function></link>
+ and again the combination of <parameter>subscriber</parameter>
+ and <parameter>args</parameter> is used to identify one
+ particular subscriber.
+ </para>
+ <para>
+ If the subscriber isn't connected to the channel, raise a
+ <literal>ConnectorError</literal> exception.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry id="Connector.Issue">
+ <term><function>Issue(<parameter>publisher</parameter>, <parameter>channel</parameter>, *<parameter>args</parameter>)</function></term>
+ <listitem>
+ <para>
+ Issue a message on a <parameter>channel</parameter>
+ of <parameter>publisher</parameter>.
+ </para>
+ <para>
+ The third and all following arguments are passed through to
+ all subscribers as message arguments. The arguments the
+ subscribers are called with is the concatenation of the
+ message arguments and the subscriber specific arguments.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry id="Connector.RemovePublisher">
+ <term><function>RemovePublisher(<parameter>publisher</parameter>)</function></term>
+ <listitem>
+ <para>
+ Remove all subscribers from all channels of
+ <emphasis>publisher</emphasis>. It is safe to call this in a
+ __del__ method.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry id="Connector.HasSubscribers">
+ <term><function>HasSubscribers(<parameter>publisher</parameter>)</function></term>
+ <listitem>
+ <para>
+ Return true iff <parameter>publisher</parameter> has any
+ subscribers.
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ <para>
+ Note that the connector does not hold references to the publisher.
+ Publishers are identified by their id. This makes it possible to
+ automatically disconnect all subscribers of a publisher in a
+ publisher's __del__ method. This does not work however, if
+ e.g. the publisher is itself a subscriber because the connector
+ has to own the references to the subcribers.
+ </para>
+ </sect1>
+
+ <sect1 id="class-Publisher">
+ <title>The Class <classname>Publisher</classname></title>
+ <para>
+ The class <classname>Publisher</classname> serves as a base class
+ for classes that send messages. It provides convenience methods to
+ subscribe to and unsubscribe from channels. It also removes all
+ subscriptions automatically when instances are deleted through
+ the <function>__del__</function> method.
+ </para>
+ <variablelist>
+ <varlistentry id="Publisher.Subscribe">
+ <term><function>Subscribe(<parameter>channel</parameter>, <parameter>subscriber</parameter>, *<parameter>args</parameter>)</function></term>
+ <listitem>
+ <para>
+ Subscribe <parameter>subscriber</parameter> to
+ self's <parameter>channel</parameter> with the rest of the
+ positional arguments as the subscriber specific
+ parameters. See <link
+ linkend="Connector.Connect"><function>Connect</function></link>
+ for more details.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry id="Publisher.Unsubscribe">
+ <term><function>Unsubscribe(<parameter>channel</parameter>, <parameter>subscriber</parameter>, *<parameter>args</parameter>)</function></term>
+ <listitem>
+ <para>
+ Unsubscribe <parameter>subscriber</parameter> to
+ self's <parameter>channel</parameter> with the rest of the
+ positional arguments as the subscriber specific
+ parameters. See <link
+ linkend="Connector.Disconnect"><function>Disconnect</function></link>
+ for more details.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry id="Publisher.issue">
+ <term><function>issue(<parameter>channel</parameter>, *<parameter>args</parameter>)</function></term>
+ <listitem>
+ <para>
+ If the instance variable ignore_issue is false, issue the
+ message described by the second and the following arguments
+ on channel <parameter>channel</parameter>, otherwise, do
+ nothing.
+ </para>
+ <para>
+ ignore_issue defaults to false. ignore_issue will be removed
+ in 0.8.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry id="Publisher.Destroy">
+ <term><function>Destroy()</function></term>
+ <listitem>
+ <para>
+ Remove all subscribers of all of self's channels. See <link
+ linkend="Connector.RemovePublisher"><function>RemovePublisher</function></link>
+ for more details.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry id="Publisher.__del__">
+ <term><function>__del__()</function></term>
+ <listitem>
+ <para>
+ Remove all subscribers of all of self's channels. See <link
+ linkend="Connector.RemovePublisher"><function>RemovePublisher</function></link>
+ for more details.
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </sect1>
+
+ <sect1 id="class-QueueingPublisher">
+ <title>The Class <classname>QueueingPublisher</classname></title>
+ <para>
+ Sometimes it's useful to put messages in a queue and issue them
+ all in one go after a complex operation is finished. The class
+ <classname>QueueingPublisher</classname> provides such a queue and
+ the following methods:
+ </para>
+ <variablelist>
+ <varlistentry id="QueueingPublisher.queue_message">
+ <term><function>queue_message(<parameter>channel</parameter>, *<parameter>args</parameter>)</function></term>
+ <listitem>
+ <para>
+ Put message for channel <parameter>channel</parameter> in
+ the queue. The rest of the arguments are treated just as
+ in <link
+ linkend="Publisher.issue"><function>issue</function></link>
+ </para>
+ <para>
+ If the messge is already queued remove it and put it at the
+ end. This is done to make certain that no channel gets
+ called twice between two calls to flush_message_queue. If
+ the order of channel invocation is important two or more
+ queues should be used.
+ </para>
+ <para>
+ Note, that this can be very inefficient if a lot of
+ different messages are queued before the queue is flushed
+ because each new message is compared with all messages in
+ the queue sequentiually. A dictionary could speed this up
+ considerably if the order in which the messages are issued
+ isn't important and if the messages can be used as
+ dictionary keys. Especially the latter is not always the
+ case, so this isn't done by defalt.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry id="QueueingPublisher.flush_message_queue">
+ <term><function>flush_message_queue()</function></term>
+ <listitem>
+ <para>
+ Issue all queued messages until the queue is empty. The
+ process is repeated because issueing messages might result
+ in new messages being queued. This can theoretically result
+ in an infinite loop.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry id="QueueingPublisher.clear_message_queue">
+ <term><function>clear_message_queue()</function></term>
+ <listitem>
+ <para>
+ Discard all queued messages.
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </sect1>
+</chapter>
Added: skencil/branches/skencil-0.6/Doc/devguide/coordsys.xml
===================================================================
--- skencil/branches/skencil-0.6/Doc/devguide/coordsys.xml 2006-06-01 15:34:15 UTC (rev 681)
+++ skencil/branches/skencil-0.6/Doc/devguide/coordsys.xml 2006-06-05 18:35:01 UTC (rev 682)
@@ -0,0 +1,995 @@
+<chapter id="coordinatesystems"><title>Coordinate Systems</title>
+ <para>
+ All coordinates used by the document and graphics objects are given
+ in the <emphasis>document coordinate system</emphasis>. This
+ coordinate system has its origin in the lower left corner of the
+ page; x increases to the right, y increases to the top. The unit for
+ these coordinates is the DTP-point (or PostScript-point), that is,
+ 1/72 inch. Thus Skencil's document coordinate system is the same as
+ the default coordinate system of a PostScript
+ interpreter. Coordinates are stored as floats.
+ </para>
+ <para>
+ The page size is a user settable document property, usually "A4",
+ "letter" or something similar. Skencil can display the outline of
+ the page if desired to allow the user to position the drawing on the
+ page.
+ </para>
+ <para>
+ When displaying the document in a window, the canvas widget (to be
+ more precise, the graphics device object the canvas uses) converts
+ document coordinates to <emphasis>window coordinates</emphasis>.
+ These are the standard X-Window coordinates with the origin in the
+ top left corner of the window and x increasing to the right and y
+ increasing downwards. The unit is 1 pixel.
+ </para>
+ <para>
+ Skencil defines a few builtin objects to represent and manipulate
+ coordinates: Points, Rects and Transformations. All of the related
+ functions, objects and constants are exported by
+ the <literal>Sketch</literal> package.
+ </para>
+
+ <sect1 id="class-Point"><title><classname>Point</classname> Objects</title>
+ <para>
+ Point objects represent 2D points or vectors--depending on how you
+ interpret them; their internal representation is identical.
+ </para>
+ <para>
+ While such points could be represented by Python tuples, this
+ special object type requires less memory and overloads some
+ arithmetic operators. A point object is represented by two C
+ "float" numbers, one for each cartesian coordinate.
+ </para>
+ <para>
+ Point objects are immutable.
+ </para>
+ <sect2>
+ <title>Constructors</title>
+ <para>
+ There are two constructor functions:
+ </para>
+ <para>
+ <variablelist>
+ <varlistentry id="function-Point">
+ <term><function>Point(<parameter>x</parameter>, <parameter>y</parameter>)</function></term>
+ <term><function>Point(<parameter>sequence</parameter>)</function></term>
+ <listitem>
+ <para>
+ Return a point object with the coordinates
+ <parameter>x</parameter> and <parameter>y</parameter>.
+ If called with one argument, the argument must be a
+ sequence of two numbers. This form is called a
+ <link linkend="PointSpec">PointSpec</link>
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry id="function-Polar">
+ <term><function>Polar(<parameter>r</parameter>, <parameter>phi</parameter>)</function></term>
+ <term><function>Polar(<parameter>phi</parameter>)</function></term>
+ <listitem>
+ <para>
+ Return a point object for the polar coordinates
+ <parameter>r</parameter> and <parameter>phi</parameter>.
+ If <parameter>r</parameter> is omitted, it defaults to 1.0.
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </para>
+ </sect2>
+
+ <sect2><title>Attributes</title>
+ <para>
+ A point object has two (read only) attributes:
+ </para>
+ <variablelist>
+ <varlistentry>
+ <term><literal>x</literal></term>
+ <listitem>
+ <para>
+ The X-coordinate of the point as a python float
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><literal>y</literal></term>
+ <listitem>
+ <para>
+ The Y-coordinate of the point as a python float
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </sect2>
+
+ <sect2><title>Methods</title>
+ <para>
+ A point object has these methods:
+ </para>
+ <variablelist>
+ <varlistentry><term><literal>normalized()</literal></term>
+ <listitem>
+ <para>
+ Return a unit vector pointing in the same direction. If
+ the point's length is 0, raise a ZeroDivisionError.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry><term><literal>polar()</literal></term>
+ <listitem>
+ <para>
+ Return a tuple
+ <literal>(<parameter>r</parameter>, <parameter>phi</parameter>)</literal>
+ containing the polar coordinates of the
+ point. <parameter>phi</parameter> is in the range -pi to
+ pi. If <parameter>r</parameter> is 0, so
+ is <parameter>phi</parameter>.
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </sect2>
+
+ <sect2><title>Operators</title>
+ <para>
+ Point objects implement both the number and the sequence
+ protocol for Python objects. This allows the following
+ operations:
+ </para>
+ <variablelist>
+ <varlistentry>
+ <term>Number Protocol</term>
+ <listitem>
+ <variablelist>
+ <varlistentry>
+ <term><literal>+<parameter>P</parameter></literal></term>
+ <listitem>
+ <para>
+ The same as <parameter>P</parameter>.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><literal>-<parameter>P</parameter></literal></term>
+ <listitem>
+ <para>
+ The negated vector <parameter>P</parameter>. The
+ same as
+ </para>
+ <para>
+ <literal>Point(-<parameter>P</parameter>.x,
+ -<parameter>P</parameter>.y)</literal>
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><literal><parameter>P1</parameter> + <parameter>P2</parameter></literal></term>
+ <listitem>
+ <para>
+ The sum of the vectors <parameter>P1</parameter>
+ and <parameter>P2</parameter>. The same as
+ </para>
+ <para>
+ <literal>Point(<parameter>P1</parameter>.x
+ + <parameter>P2</parameter>.x, <parameter>P1</parameter>.y
+ + <parameter>P2</parameter>.y)</literal>
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><literal><parameter>P1</parameter>
+ - <parameter>P2</parameter></literal></term>
+ <listitem>
+ <para>
+ The difference of the
+ vectors <parameter>P1</parameter>
+ and <parameter>P2</parameter>. The same as
+ </para>
+ <para>
+ <literal>Point(<parameter>P1</parameter>.x
+ - <parameter>P2</parameter>.x, <parameter>P1</parameter>.y
+ - <parameter>P2</parameter>.y)</literal>
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>
+ <literal><parameter>P1</parameter> * <parameter>P2</parameter></literal></term>
+ <listitem>
+ <para>
+ The dot product of the
+ vectors <parameter>P1</parameter>
+ and <parameter>P2</parameter>. The same as
+ </para>
+ <para>
+ <literal><parameter>P1</parameter>.x * <parameter>P2</parameter>.x + <parameter>P1</parameter>.y * <parameter>P2</parameter>.y</literal>
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><literal><parameter>NUMBER</parameter> * <parameter>P</parameter></literal></term>
+ <term><literal><parameter>P</parameter> * <parameter>NUMBER</parameter></literal></term>
+ <listitem>
+ <para>
+ The same as
+ </para>
+ <para>
+ <literal>Point(<parameter>NUMBER</parameter> * <parameter>P</parameter>.x, <parameter>NUMBER</parameter> * <parameter>P</parameter>.y)</literal>
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><literal><parameter>P</parameter> / <parameter>NUMBER</parameter></literal></term>
+ <listitem>
+ <para>
+ The same as
+ </para>
+ <para>
+ <literal>Point(<parameter>P</parameter>.x / <parameter>NUMBER</parameter>, <parameter>P</parameter>.y / <parameter>NUMBER</parameter>)</literal>
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>abs(<parameter>P</parameter>)</term>
+ <listitem>
+ <para>
+ The length of the
+ vector <parameter>P</parameter>. The same as
+ <literal>math.hypot(<parameter>P</parameter>.x, <parameter>P</parameter>.y)</literal>.
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry><term>Sequence Protocol</term>
+ <listitem>
+ <variablelist>
+ <varlistentry>
+ <term><literal>len(<parameter>P</parameter>)</literal></term>
+ <listitem>
+ <para>
+ Always returns 2.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><literal><parameter>P</parameter>[<parameter>i</parameter>]</literal></term>
+ <listitem>
+ <para>
+ For <literal><parameter>i</parameter></literal>
+ either 0 or 1, this is the same as
+ <literal><parameter>P</parameter>.x</literal>
+ or <literal><parameter>P</parameter>.y</literal>
+ respectively. For other values
+ of <parameter>i</parameter> raise an IndexError
+ exception.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><literal>tuple(<parameter>P</parameter>)</literal></term>
+ <listitem>
+ <para>
+ Return the coordinates of <parameter>P</parameter>
+ as a tuple <literal>(<parameter>P</parameter>.x,
+ <parameter>P</parameter>.y)</literal>.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><literal>x, y = <parameter>P</parameter></literal></term>
+ <listitem>
+ <para>
+ Unpack the point
+ <literal><parameter>P</parameter></literal>.
+ Equivalent to
+ <literal>x, y = tuple(<parameter>P</parameter>)</literal>
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ <para>
+ <parameter>P</parameter>, <parameter>P1</parameter>
+ and <parameter>P2</parameter> are point
+ objects, <parameter>NUMBER</parameter> is any number that can be
+ converted to a float.
+ </para>
+ <para>
+ <literal>abs</literal>, <literal>tuple</literal>, <literal>len</literal>
+ and <literal>math.hypot</literal> are the standard Python
+ functions of that name.
+ </para>
+ </sect2>
+
+ <sect2><title>Constants</title>
+ <variablelist>
+ <varlistentry><term><literal>NullPoint</literal></term>
+ <listitem>
+ <para>
+ This is <literal>Point(0, 0)</literal>
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry><term><literal>PointType</literal></term>
+ <listitem>
+ <para>
+ The point type object.
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </sect2>
+
+ <sect2 id="PointSpec"><title>PointSpec</title>
+ <para>
+ While point objects are the standard representation for a point,
+ it is sometimes inconvenient (particularly if you are computing
+ the individual coordinates separately) to create a point object
+ just because a function requires that argument type. Therefore,
+ some functions also accept a <emphasis>PointSpec</emphasis>
+ instead.
+ </para>
+ <para>
+ An argument that is supposed to be a PointSpec can be either a
+ point object or any sequence of two numbers. Here, number means
+ any object that can be converted to a "double" in C. You could
+ use e. g. a tuple of floats or ints instead of a point object.
+ </para>
+ </sect2>
+ </sect1>
+
+ <sect1 id="class-Rect"><title><classname>Rect</classname> Objects</title>
+ <para>
+ Rect objects, or rects for short, represent rectangular areas of
+ the drawing whose edges are parallel to the coordinate axes. They
+ are represented by four floats for the positions of the left,
+ bottom, right and top edges. Rects are kept in a normalized state
+ where the left coordinate a less than the right coordinate and the
+ bottom coordinate less than the top coordinate.
+ </para>
+ <para>
+ The <link linkend="class-Bounded">bounding rects and coord
+ rects</link> of the graphics objects are such rect objects.
+ </para>
+ <para>
+ Rect objects provide efficient methods for boolean operations
+ (union and intersection of rects) and tests for overlapping rects
+ and contained points.
+ </para>
+ <para>
+ There are two special rect objects: <literal>InfinityRect</literal> and
+ <literal>EmptyRect</literal>. <literal>InfinityRect</literal>
+ represents the entire 2D plane while <literal>EmptyRect</literal>
+ is an empty rect. These objects behave in special ways: both
+ overlap every other rect, <literal>InfinityRect</literal> contains
+ all points while <literal>EmptyRect</literal> contains no point,
+ and so on. The particular coordinates of these objects are
+ irrelevant.
+ </para>
+ <para>
+ Rect objects are immutable.
+ </para>
+ <para>
+ Note: these rect objects have nothing to do with the rectangle
+ primitive (apart from the fact that the rectangle primitive has a
+ bounding box...).
+ </para>
+
+ <sect2><title>Constructors</title>
+ <variablelist>
+ <varlistentry id="function-Rect">
+ <term><function>Rect(<parameter>left</parameter>, <parameter>bottom</parameter>, <parameter>right</parameter>, <parameter>top</parameter>)</function></term>
+ <term><function>Rect(<parameter>llcorner</parameter>, <parameter>urcorner</parameter>)</function></term>
+ <listitem>
+ <para>
+ Return a new Rect object with the coordinates
+ <parameter>left</parameter>, <parameter>bottom</parameter>,
+ <parameter>right</parameter>
+ and <parameter>top</parameter> or the opposite corners
+ <parameter>llcorner</parameter>
+ and <parameter>urcorner</parameter> given
+ as <link linkend="class-Point">point objects</link>. The
+ rectangle is automatically normalized, so you can
+ swap <parameter>left</parameter>/<parameter>right</parameter>
+ or
+ <parameter>top</parameter>/<parameter>bottom</parameter>
+ or choose any opposite corners.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry id="function-PointsToRect">
+ <term>
+ <function>PointsToRect(<parameter>sequence</parameter>)</function>
+ </term>
+ <listitem>
+ <para>
+ Return the smallest rect that contains all points in
+ <parameter>sequence</parameter>. <parameter>sequence</parameter>
+ must be a sequence of
+ <link linkend="PointSpec">PointSpecs</link>.
+ If <parameter>sequence</parameter> is empty
+ return <literal>EmptyRect</literal>
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </sect2>
+
+ <sect2><title>Attributes</title>
+ <para>
+ A rect object has four (read only) attributes:
+ </para>
+ <variablelist>
+ <varlistentry>
+ <term><literal>left</literal></term>
+ <term><literal>bottom</literal></term>
+ <term><literal>right</literal></term>
+ <term><literal>top</literal></term>
+ <listitem>
+ <para>
+ The left, bottom, right and top coordinate of the rect as
+ python floats. For <literal>InfinityRect</literal>
+ and <literal>EmptyRect</literal> these have no real
+ meaning.
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </sect2>
+
+ <sect2><title>Methods</title>
+ <para>
+ A rect object has these methods (self refers to the rect whose
+ method is called):
+ </para>
+ <variablelist>
+ <varlistentry>
+ <term><literal>contains_point(<parameter>PointSpec</parameter>)</literal></term>
+ <term><literal>contains_point(<parameter>x</parameter>, <parameter>y</parameter>)</literal></term>
+ <listitem>
+ <para>
+ Return true, if the point given
+ by <parameter>PointSpec</parameter>
+ or <parameter>x</parameter> and <parameter>y</parameter>
+ is inside of self, false otherwise.
+ </para>
+ <para>
+ For <literal>InfinityRect</literal> this is always true,
+ for <literal>EmptyRect</literal> always false.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>
+ <literal>contains_rect(<parameter>r</parameter>)</literal>
+ </term>
+ <listitem>
+ <para>
+ Return true, if the rect <parameter>r</parameter> lies
+ completely inside of self. A rect contains itself.
+ </para>
+ <para>
+ <literal>InfinityRect</literal> contains all other rects
+ and <literal>EmptyRect</literal> is contained in all other
+ rects.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><literal>overlaps(<parameter>r</parameter>)</literal></term>
+ <listitem>
+ <para>
+ Return true if self and the rect <parameter>r</parameter>
+ overlap. A rect overlaps itself.
+ </para>
+ <para>
+ <literal>InfinityRect</literal>
+ and <literal>EmptyRect</literal> overlap all other rects
+ and each other.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><literal>translated(<parameter>PointSpec</parameter>)</literal></term>
+ <term><literal>translated(<parameter>x</parameter>, <parameter>y</parameter>)</literal></term>
+ <listitem>
+ <para>
+ Return self translated by the vector
+ <parameter>PointSpec</parameter>
+ or <parameter>x</parameter>
+ and <parameter>y</parameter>. Equivalent to
+ </para>
+ <para>
+ <literal>Rect(self.left + x, self.bottom + y, self.right + x, self.top + y)</literal>
+ </para>
+ <para>
+ For <literal>InfinityRect</literal>
+ and <literal>EmptyRect</literal>, return self.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><literal>grown(<parameter>amount</parameter>)</literal></term>
+ <listitem>
+ <para>
+ Return a rect that is larger than self
+ by <parameter>amount</parameter> in every
+ direction. Equivalent to
+ </para>
+ <para>
+ <literal>Rect(self.left - amount, self.bottom - amount,
+ self.right + amount, self.top + amount)</literal>
+ </para>
+ <para>
+ For <literal>InfinityRect</literal>
+ and <literal>EmptyRect</literal>, return self.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry><term><literal>center()</literal></term>
+ <listitem>
+ <para>
+ Return the center point of self as a point object.
+ </para>
+ <para>
+ For <literal>InfinityRect</literal>
+ and <literal>EmptyRect</literal>, return
+ <literal>Point(0, 0)</literal>.
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </sect2>
+
+ <sect2><title>Operators</title>
+ <para>
+ Rect objects implement the sequence protocol for Python
+ objects. This allows the following operations:
+ </para>
+ <variablelist>
+ <varlistentry>
+ <term><literal>len(<parameter>rect</parameter>)</literal></term>
+ <listitem>
+ <para>
+ Always returns 4.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><literal><parameter>rect</parameter>[<parameter>i</parameter>]</literal></term>
+ <listitem>
+ <para>
+ If <literal><parameter>i</parameter></literal> is one of
+ 0, 1, 2 or 3, this is the same as
+ <literal><parameter>rect</parameter>.left</literal>,
+ <literal><parameter>rect</parameter>.bottom</literal>,
+ <literal><parameter>rect</parameter>.right</literal>
+ or <literal><parameter>rect</parameter>.top</literal>
+ respectively.
+ </para>
+ <para>
+ For other values of <parameter>i</parameter> raise an
+ IndexError exception.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><literal>tuple(<parameter>rect</parameter>)</literal></term>
+ <listitem>
+ <para>
+ Return the coordinates of <parameter>rect</parameter> as a tuple
+ </para>
+ <para>
+ <literal>(<parameter>rect</parameter>.left,
+ <parameter>rect</parameter>.bottom,
+ <parameter>rect</parameter>.right,
+ <parameter>rect</parameter>.top)</literal>.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><literal>left, bottom, right, top = <parameter>rect</parameter></literal></term>
+ <listitem>
+ <para>
+ Unpack the rect
+ <literal><parameter>rect</parameter></literal>.
+ Equivalent to
+ </para>
+ <para>
+ <literal>left, bottom, right, top = tuple(<parameter>rect</parameter>)</literal>
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ <para>
+ <literal>rect</literal> is a rect object, <literal>len</literal>
+ is the builtin function.
+ </para>
+ </sect2>
+
+ <sect2>
+ <title>Functions</title>
+ <variablelist>
+ <varlistentry id="function-UnionRects">
+ <term><function>UnionRects(<parameter>rect1</parameter>, <parameter>rect2</parameter>)</function></term>
+ <listitem>
+ <para>
+ Return the union of the rects <parameter>rect1</parameter>
+ and <parameter>rect2</parameter>. The union is the
+ smallest rect containing both rects.
+ </para>
+ <para>
+ If one the arguments is <literal>InfinityRect</literal>
+ return <literal>InfinityRect</literal>, if one of the
+ arguments is <literal>EmptyRect</literal> return the other
+ argument.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry id="function-IntersectRects">
+ <term><function>IntersectRects(<parameter>rect1</parameter>, <parameter>rect2</parameter>)</function></term>
+ <listitem>
+ <para>
+ Return the intersection of the rects
+ <parameter>rect1</parameter>
+ and <parameter>rect2</parameter>. The intersection is the
+ largest rect contained in both rects.
+ </para>
+ <para>
+ If one the arguments is <literal>EmptyRect</literal>
+ return <literal>EmptyRect</literal>, if one of the
+ arguments is <literal>InfinityRect</literal> return the
+ other argument.
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </sect2>
+
+ <sect2><title>Constants</title>
+ <variablelist>
+ <varlistentry>
+ <term><literal>InfinityRect</literal></term>
+ <listitem>
+ <para>
+ Represents the entire 2D plane.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><literal>EmptyRect</literal></term>
+ <listitem>
+ <para>
+ The empty rect.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><literal>UnitRect</literal></term>
+ <listitem>
+ <para>
+ <literal>Rect(0, 0, 1, 1)</literal>
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><literal>RectType</literal></term>
+ <listitem>
+ <para>
+ The rect type object.
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </sect2>
+ </sect1>
+
+ <sect1 id="class-Trafo"><title>Transformation Objects</title>
+ <para>
+ A transformation object, a trafo object or trafo for short,
+ represents an affine 2D transformation. Such a transformation is
+ given by 6 numbers: <parameter>m11</parameter>,
+ <parameter>m21</parameter>, <parameter>m21</parameter>,
+ <parameter>m22</parameter>, <parameter>v1</parameter> and
+ <parameter>v2</parameter>. These coefficients are given in the
+ same order as for a PostScript transformation matrix.
+ </para>
+ <para>
+ To apply a trafo to an object you can simple call the trafo with
+ that object as argument. For details, see
+ the <link linkend="Trafo-operators">section "Operators"</link>
+ below.
+ </para>
+ <para>
+ Trafo objects are immutable.
+ </para>
+ <para>
+ If such a transformation <parameter>T</parameter> is applied to
+ the point (<parameter>x</parameter>, <parameter>y</parameter>) you
+ get
+ </para>
+ <para>
+<programlisting>
+ / x \ / m11 m12 \ / x \ / v1 \
+ T * | | = | | | | + | |
+ \ y / \ m21 m22 / \ y / \ v2 /
+</programlisting>
+ </para>
+ <para>
+ or, in homogeneous coordinates:
+ </para>
+ <para>
+<programlisting>
+ / x \ / m11 m12 v1 \ / x \
+ | | | | | |
+ T * | y | = | m21 m22 v2 | | y |
+ | | | | | |
+ \ 1 / \ 0 0 1 / \ 1 /
+</programlisting>
+ </para>
+
+ <sect2><title>Constructors</title>
+ <para>
+ The following functions create trafo objects:
+ </para>
+ <variablelist>
+ <varlistentry id="function-Trafo">
+ <term><function>Trafo(<parameter>m11</parameter>, <parameter>m21</parameter>, <parameter>m21</parameter>, <parameter>m22</parameter>, <parameter>v1</parameter>, <parameter>v2</parameter>)</function></term>
+ <listitem>
+ <para>
+ The generic constructor: return the transformation given
+ by the coordinates <parameter>m11</parameter>,
+ <parameter>m21</parameter>, <parameter>m21</parameter>,
+ <parameter>m22</parameter>, <parameter>v1</parameter>
+ and <parameter>v2</parameter>. These coefficients are
+ given in the same order as for a PostScript
+ transformation matrix.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry id="function-Scale">
+ <term><function>Scale(<parameter>factorx</parameter>[, <parameter>factory</parameter>])</function></term>
+ <listitem>
+ <para>
+ Return a trafo object for a scaling by the
+ factors <parameter>factorx</parameter> (in x-direction)
+ and <parameter>factory</parameter> (in y-direction). If
+ omitted, <parameter>factory</parameter> defaults to the
+ value of <parameter>factorx</parameter>.
+ </para>
+ <para>
+ Equivalent to
+ <literal>Trafo(<parameter>factorx</parameter>, 0, 0, <parameter>factory</parameter>, 0, 0)</literal>.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry id="function-Translation">
+ <term><function>Translation(<parameter>offset</parameter>)</function></term>
+ <term><function>Translation(<parameter>offset_x</parameter>, <parameter>offset_y</parameter>)</function></term>
+ <listitem>
+ <para>
+ Return a trafo object for a translation
+ by <parameter>offset</parameter>
+ (a <link linkend="PointSpec">PointSpec</link>) or
+ (<parameter>offset_x</parameter>,
+ <parameter>offset_y</parameter>).
+ Equivalent to
+ <literal>Trafo(1, 0, 0, 1, <parameter>offset_x</parameter>,
+ <parameter>offset_y</parameter>)</literal>.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry id="function-Rotation">
+ <term><function>Rotation(<parameter>angle</parameter>[, <parameter>center</parameter>])</function></term>
+ <term><function>Rotation(<parameter>angle</parameter>[, <parameter>center_x</parameter>, <parameter>center_y</parameter>])</function></term>
+ <listitem>
+ <para>
+ Return a trafo object for a rotation through the angle
+ <parameter>angle</parameter> (counter clockwise in
+ radians) about the center
+ point <parameter>center</parameter> or
+ (<parameter>center_x</parameter>, <parameter>center_y</parameter>).
+ <parameter>center</parameter> must be a <link linkend="PointSpec">PointSpec</link>. If
+ <parameter>center</parameter> is omitted it defaults to
+ the origin.
+ </para>
+ <para>
+ Equivalent to
+<programlisting>
+ s = sin(angle);
+ c = cos(angle);
+ offx = cx - c * center_x + s * center_y;
+ offy = cy - s * center_x - c * center_y;
+ Trafo(c, s, -s, c, offx, offy);
+</programlisting>
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </sect2>
+
+ <sect2><title>Attributes</title>
+ <para>
+ A trafo object has six (read only) attributes:
+ </para>
+ <variablelist>
+ <varlistentry>
+ <term><literal>m11</literal></term>
+ <term><literal>m21</literal></term>
+ <term><literal>m12</literal></term>
+ <term><literal>m22</literal></term>
+ <term><literal>v1</literal></term>
+ <term><literal>v2</literal></term>
+ <listitem>
+ <para>
+ The coefficients of the trafo as python floats.
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </sect2>
+
+ <sect2><title>Methods</title>
+ <variablelist>
+ <varlistentry>
+ <term><literal>DocToWin(<parameter>point</parameter>)</literal></term>
+ <term><literal>DocToWin(<parameter>x</parameter>, <parameter>y</parameter>)</literal></term>
+ <listitem>
+ <para>
+ Transform the point and return the result as a tuple of ints.
+ <parameter>point</parameter> is a
+ <link linkend="PointSpec">PointSpec</link>. This function
+ is used to transform document coordinates to window
+ coordinates, hence the name. (Normally, if you want to
+ transform a point, you
+ <link linkend="Trafo-operators">call the trafo object
+ directly</link>)
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><literal>DTransform(<parameter>point</parameter>)</literal></term>
+ <term><literal>DTransform(<parameter>x</parameter>, <parameter>y</parameter>)</literal></term>
+ <listitem>
+ <para>
+ Treat the point as a vector and transform it, that is, don't add
+ <literal>v1</literal> and <literal>v2</literal>.
+ <parameter>point</parameter> is
+ a <link linkend="PointSpec">PointSpec</link>.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><literal>inverse()</literal></term>
+ <listitem>
+ <para>
+ Return the inverse transformation of self. If self cannot
+ be inverted raise the <literal>SingularMatrix</literal>
+ exception.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><literal>coeff()</literal></term>
+ <listitem>
+ <para>
+ Return the coefficients of the trafo as a tuple
+ (<parameter>m11</parameter>, <parameter>m21</parameter>,
+ <parameter>m21</parameter>, <parameter>m22</parameter>,
+ <parameter>v1</parameter>, <parameter>v2</parameter>).
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><literal>matrix()</literal></term>
+ <listitem>
+ <para>
+ Return the matrix coefficients of the trafo
+ (<literal>m11</literal>, ..., <literal>m22</literal>) as a
+ tuple. The same as <literal>coeff()[:4]</literal>.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><literal>offset()</literal></term>
+ <listitem>
+ <para>
+ Return the translation coefficients as a point object.
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </sect2>
+
+ <sect2 id="Trafo-operators"><title>Operators</title>
+ <para>
+ Since a transformation is a mapping in the mathematical sense,
+ it is convenient to make trafo objects callable, so you can
+ treat them like functions or methods. Depending on the type of
+ the argument the results are different:
+ </para>
+ <variablelist>
+ <varlistentry>
+ <term><literal>trafo(<parameter>point</parameter>)</literal></term>
+ <term><literal>trafo(<parameter>x</parameter>, <parameter>y</parameter>)</literal></term>
+ <listitem>
+ <para>
+ Return the transformed point. Point can be
+ any <link linkend="PointSpec">PointSpec</link>.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><literal>trafo(<parameter>othertrafo</parameter>)</literal></term>
+ <listitem>
+ <para>
+ Return the composition of both trafos.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><literal>trafo(<parameter>rect</parameter>)</literal></term>
+ <listitem>
+ <para>
+ Return the smallest <link linkend="class-Rect">rect
+ object</link> that contains the transformed corners of
+ the rect object <parameter>rect</parameter>.
+ </para>
+ <para>
+ <literal>InfinityRect</literal>
+ and <literal>EmptyRect</literal> are returned unchanged.
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </sect2>
+
+ <sect2><title>Constants</title>
+ <variablelist>
+ <varlistentry>
+ <term><literal>Identity</literal></term>
+ <listitem>
+ <para>
+ The identity transformation
+ (<literal>Trafo(1, 0, 0, 1, 0, 0)</literal>)
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><literal>IdentityMatrix</literal></term>
+ <listitem>
+ <para>
+ A tuple containing the coefficients of the identity
+ matrix. The same as <literal>Identity.matrix()</literal>
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><literal>TrafoType</literal></term>
+ <listitem>
+ <para>
+ The trafo type object.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><literal>SingularMatrix</literal></term>
+ <listitem>
+ <para>
+ Exception raised by the <literal>inverse()</literal> method.
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </sect2>
+ </sect1>
+</chapter>
Added: skencil/branches/skencil-0.6/Doc/devguide/curveobj.xml
===================================================================
--- skencil/branches/skencil-0.6/Doc/devguide/curveobj.xml 2006-06-01 15:34:15 UTC (rev 681)
+++ skencil/branches/skencil-0.6/Doc/devguide/curveobj.xml 2006-06-05 18:35:01 UTC (rev 682)
@@ -0,0 +1,366 @@
+<chapter id="class-curveobject"><title>Curve Objects</title>
+ <para>
+ A curve object represents a single continuous curve. A curve is a
+ sequence of segments with each segment starting at the end point of
+ the preceding segment (except the first segment, of which only the
+ end point is used as the start point of the second segment).
+ </para>
+ <para>
+ There are two kinds of segments, line segments and bezier segments.
+ </para>
+ <para>
+ A line segment is defined by its end point, p, and it defines a
+ straight line from the preceding segment's end point to p.
+ </para>
+ <para>
+ A bezier segment consists of an end point, p, and two auxiliary
+ points, p1 and p2. It defines a bezier curve starting at the
+ preceding segment's end point, approximating p1 and p2 and ending at
+ p.
+ </para>
+ <para>
+ The end points of the segments are usually called
+ <emphasis>nodes</emphasis>. There are two special properties
+ associated with them.
+ </para>
+ <para>
+ The first property is the <emphasis>continuity</emphasis>. The
+ continuity can be "angle", "smooth" or "symmetrical". This results
+ in constraints in the editor when the user modifies a bezier
+ object's auxiliary points:
+ </para>
+ <variablelist>
+ <varlistentry><term>angle</term>
+ <listitem>
+ <para>
+ No constraint.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry><term>smooth</term>
+ <listitem>
+ <para>
+ The node, the auxiliary points p2 of the node's segment, and
+ p1 of the following segment must be collinear.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry><term>symmetrical</term>
+ <listitem>
+ <para>
+ The node, the auxiliary points p2 of the node's segment, and
+ p1 of the following segment must be collinear and the node is
+ the arithmetic mean of the two auxiliary points.
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+
+ <para>
+ The second property is only used during editing and has not effect
+ on the appearance of the curve. It is a flag that indicates whether
+ the node is selected or not.
+ </para>
+ <para>
+ Segments are numbered from zero, just like other sequences in
+ Python.
+ </para>
+
+ <sect2><title>Constructors</title>
+ <para>
+ <variablelist>
+ <varlistentry id="function-CreatePath">
+ <term><function>CreatePath()</function></term>
+ <listitem>
+ <para>
+ Return an empty curve object.
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </para>
+ </sect2>
+
+ <sect2><title>Attributes</title>
+ <variablelist>
+ <varlistentry><term><literal>len</literal></term>
+ <listitem>
+ <para>
+ The number of segments. An empty curve has zero length, a
+ curve with just one node has length 1.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry><term><literal>closed</literal></term>
+ <listitem>
+ <para>
+ True (1) if the curve is closed, false (0) otherwise.
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </sect2>
+
+ <sect2><title>Methods</title>
+
+ <sect3><title>Segment Construction</title>
+ <para>
+ When an empty curve has been created, segments can be appended
+ using the functions listed in this section. The first segment of
+ a curve must be a line segment.
+ </para>
+ <variablelist>
+ <varlistentry id="curve.AppendLine">
+ <term><literal>AppendLine(<parameter>p</parameter>[, <parameter>cont</parameter>])</literal></term>
+ <term><literal>AppendLine(<parameter>x</parameter>, <parameter>y</parameter>[, <parameter>cont</parameter>])</literal></term>
+ <listitem>
+ <para>
+ Append a line segment to self. <parameter>p</parameter>
+ must be a <link linkend="PointSpec">PointSpec</link>.
+ </para>
+ <para>
+ <parameter>cont</parameter> is the continuity at the end
+ node and defaults to <literal>ContAngle</literal>.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry id="curve.AppendBezier">
+ <term><literal>AppendBezier(<parameter>p1</parameter>, <parameter>p2</parameter>, <parameter>p</parameter>[, <parameter>cont</parameter>])</literal></term>
+ <term><!-- meth -->AppendBezier(<parameter>x1</parameter>, <parameter>y1</parameter>, <parameter>x2</parameter>, <parameter>y2</parameter>,
+ <parameter>x</parameter>, <parameter>y</parameter>[, <parameter>cont</parameter>])<!-- /meth --></term>
+ <listitem>
+ <para>
+ Append a bezier segment to
+ self. <parameter>p</parameter>, <parameter>p1</parameter>,
+ and <parameter>p2</parameter> must
+ be <link linkend="PointSpec">PointSpecs</link>. The
+ control points of the bezier segment are the current end
+ point of the curve,
+ <parameter>p1</parameter> and <parameter>p2</parameter>
+ (which are only approximated)
+ and <parameter>p</parameter>.
+ </para>
+ <para>
+ <parameter>cont</parameter> is the continuity at the end
+ node and defaults to <literal>ContAngle</literal>.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry id="curve.AppendSegment">
+ <term><literal>AppendSegment(CurveLine, (), <parameter>p</parameter>[, cont])</literal></term>
+ <term><!-- meth -->AppendSegment(CurveBezier, (<parameter>p1</parameter>, <parameter>p2</parameter>), <parameter>p</parameter>[,
+ <parameter>cont</parameter>])<!-- /meth --></term>
+ <listitem>
+ <para>
+ Append a segment. If the first parameter
+ is <literal>CurveLine</literal>, this method is equivalent
+ to <literal>AppendLine(<parameter>p</parameter>, <parameter>cont</parameter>)</literal>,
+ with <parameter>cont</parameter> defaulting
+ to <literal>ContAngle</literal>.
+ </para>
+ <para>
+ If the first parameter is <literal>CurveBezier</literal>,
+ this method is equivalent to
+ <literal>AppendLine(<parameter>p1</parameter>, <parameter>p2</parameter>, <parameter>p</parameter>, <parameter>cont</parameter>)</literal>,
+ with <parameter>cont</parameter> defaulting
+ to <literal>ContAngle</literal>.
+ </para>
+ <para>
+ This method is mainly supplied as the opposite of the
+ method <link
+ linkend="curve.Segment"><function>Segment</function></link>.
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </sect3>
+
+ <sect3><title>Querying the Curve Geometry</title>
+ <para>
+ The following methods usually take the index of a segment as
+ argument. This index counts from 0 to <literal>len -
+ 1</literal>. If the index is negative it counts from the end,
+ just like for other sequences.
+ </para>
+ <variablelist>
+ <varlistentry id="curve.Segment">
+ <term><literal>Segment(<parameter>i</parameter>)</literal></term>
+ <listitem>
+ <para>
+ Return the segment number <parameter>i</parameter> as a
+ 4-tuple.
+ </para>
+ <para>
+ If the segment is a line segment the result is of the
+ form:
+ </para>
+ <para>
+ <literal>(CurveLine, (), <parameter>p</parameter>, <parameter>cont</parameter>)</literal>
+ </para>
+ <para>
+ if it is a bezier segment the result has the form:
+ </para>
+ <para>
+ <literal>(CurveBezier, (<parameter>p1</parameter>, <parameter>p2</parameter>), <parameter>p</parameter>, <parameter>cont</parameter>)</literal>
+ </para>
+ <para>
+ The result is suitable as argument tuple
+ to <link
+ linkend="curve.AppendSegment"><function>AppendSegment</function></link>.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry id="curve.Node">
+ <term><literal>Node(<parameter>i</parameter>)</literal></term>
+ <listitem>
+ <para>
+ Return the <parameter>i</parameter>th node as a point
+ object.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry id="curve.Continuity">
+ <term><literal>Continuity(<parameter>i</parameter>)</literal></term>
+ <listitem>
+ <para>
+ Return the continuity at node <parameter>i</parameter>.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry id="curve.SegmentType">
+ <term><literal>SegmentType(<parameter>i</parameter>)</literal></term>
+ <listitem>
+ <para>
+ Return the type of the <parameter>i</parameter>th segment
+ (either <literal>CurveLine</literal>
+ or <literal>CurveBezier</literal>).
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </sect3>
+
+ <sect3><title>Modifying a Curve Object</title>
+ <variablelist>
+ <varlistentry id="curve.SetLine">
+ <term><literal>SetLine(<parameter>i</parameter>, <parameter>p</parameter>[, <parameter>cont</parameter>])</literal></term>
+ <term><literal>SetLine(<parameter>i</parameter>, <parameter>x</parameter>, <parameter>y</parameter>[, <parameter>cont</parameter>])</literal></term>
+ <listitem>
+ <para>
+ Replace the <parameter>i</parameter>th segment by a line
+ segment. The arguments <parameter>p</parameter>,
+ <parameter>x</parameter>, <parameter>y</parameter>
+ and <parameter>cont</parameter> are used as in
+ <link
+ linkend="curve.AppendLine"><function>AppendLine</function></link>.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry id="curve.SetBezier">
+ <term><literal>SetBezier(<parameter>i</parameter>, <parameter>p1</parameter>, <parameter>p2</parameter>, <parameter>p</parameter>[, <parameter>cont</parameter>])</literal></term>
+ <term><literal>SetBezier(<parameter>i</parameter>, <parameter>x1</parameter>, <parameter>y1</parameter>, <parameter>x2</parameter>, <parameter>y2</parameter>, <parameter>x</parameter>, <parameter>y</parameter>[, <parameter>cont</parameter>])</literal></term>
+ <listitem>
+ <para>
+ Replace the <parameter>i</parameter>th segment by a bezier
+ segment. The rest of the arguments are used as
+ in <link
+ linkend="curve.AppendBezier"><function>AppendBezier</function></link>.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry id="curve.SetSegment">
+ <term><literal>SetSegment(<parameter>i</parameter>, CurveLine, (), <parameter>p</parameter>[, cont])</literal></term>
+ <term><literal>SetSegment(<parameter>i</parameter>, CurveBezier, (<parameter>p1</parameter>, <parameter>p2</parameter>), <parameter>p</parameter>[, <parameter>cont</parameter>])</literal></term>
+ <listitem>
+ <para>
+ Replace the <parameter>i</parameter>th segment by the segment
+ described by the rest of arguments, which are used as in
+ <link
+ linkend="curve.AppendSegment"><function>AppendSegment</function></link>.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry id="curve.ClosePath">
+ <term><literal>ClosePath()</literal></term>
+ <listitem>
+ <para>
+ Close the curve.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry id="curve.Transform">
+ <term><literal>Transform(<parameter>trafo</parameter>)</literal></term>
+ <listitem>
+ <para>
+ Apply the transformation <parameter>trafo</parameter> (a
+ trafo object) to the path. The path is modified in place.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry id="curve.Translate">
+ <term><literal>Translate(<parameter>offset</parameter>)</literal></term>
+ <listitem>
+ <para>
+ Translate the path by offset, a point object. The path is
+ modified in place.
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </sect3>
+
+ <sect3><title>Managing the Selection</title>
+ <para>
+ <variablelist>
+ <varlistentry id="curve.SegmentSelected">
+ <term><literal>SegmentSelected(<parameter>i</parameter>)</literal></term>
+ <listitem>
+ <para>
+ Return true (1) if the <parameter>i</parameter>th
+ segment is selected, false (0) otherwise.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry id="curve.SelectSegment">
+ <term><literal>SelectSegment(<parameter>i</parameter>, [<parameter>flag</parameter>])</literal></term>
+ <listitem>
+ <para>
+ Mark the <parameter>i</parameter>th segment as selected
+ if <parameter>flag</parameter> is true and as unselected
+ otherwise. <parameter>flag</parameter> defaults to true.
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </para>
+ </sect3>
+ </sect2>
+
+ <sect2><title>Constants</title>
+ <para>
+ <variablelist>
+ <varlistentry>
+ <term><literal>ContAngle</literal></term>
+ <term><literal>ContSmooth</literal></term>
+ <term><literal>ContSymmetrical</literal></term>
+ <listitem>
+ <para>
+ The values for the continuity property of the nodes.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><literal>CurveLine</literal></term>
+ <term><literal>CurveBezier</literal></term>
+ <listitem>
+ <para>
+ The two different segment types. Used
+ for <link linkend="curve.AppendSegment"><function>AppendSegment</function></link>
+ and <link linkend="curve.Segment"><function>Segment</function></link>.
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </para>
+ </sect2>
+</chapter>
Added: skencil/branches/skencil-0.6/Doc/devguide/devguide.xml
===================================================================
--- skencil/branches/skencil-0.6/Doc/devguide/devguide.xml 2006-06-01 15:34:15 UTC (rev 681)
+++ skencil/branches/skencil-0.6/Doc/devguide/devguide.xml 2006-06-05 18:35:01 UTC (rev 682)
@@ -0,0 +1,62 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<!DOCTYPE book
+ PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+ "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd"
+
+[
+ <!ENTITY architecture SYSTEM "architecture.xml">
+ <!ENTITY remarks SYSTEM "remarks.xml">
+ <!ENTITY coordsys SYSTEM "coordsys.xml">
+ <!ENTITY curveobj SYSTEM "curveobj.xml">
+ <!ENTITY classes SYSTEM "classes.xml">
+ <!ENTITY undo SYSTEM "undo.xml">
+ <!ENTITY plugins SYSTEM "plugins.xml">
+ <!ENTITY ui SYSTEM "ui.xml">
+ <!ENTITY connector SYSTEM "connector.xml">
+ <!ENTITY fileformat SYSTEM "fileformat.xml">
+]>
+<book>
+ <bookinfo>
+ <title>Skencil Developer's Guide</title>
+ <author><firstname>Bernhard</firstname><surname>Herzog</surname></author>
+ </bookinfo>
+
+ <chapter id="intro"><title>Introduction</title>
+ <para>
+ This document describes the implementation of at least some parts
+ of Skencil. It is meant for anyone who wants to find out how
+ Skencil is implemented, how to extend Skencil with new object
+ types or wants to contribute to Skencil.
+ </para>
+ <para>
+ I'll assume that you are familiar with Skencil from the user's
+ point of view and that you have some experience in Python
+ programming. If you don't know Python yet, have a look at the
+ Python tutorial (contained in the standard documentation for
+ Python which is distributed as a separate package)
+ </para>
+ <para>
+ Some of the topics discussed in this document might be of interest
+ to developers of other Python applications as well. In particular,
+ these topics are the <link linkend="undo">undo mechanism</link>
+ and the <link linkend="connector">connector module</link>
+ </para>
+ <para>
+ Note that since Skencil was originally called "Skencil" that older
+ name is still used internally in a lot of places, for example in
+ some identifiers in the code.
+ </para>
+ </chapter>
+
+ &architecture;
+ &remarks;
+ &coordsys;
+ &curveobj;
+ &classes;
+ &undo;
+ &plugins;
+ &ui;
+ &connector;
+ &fileformat;
+
+</book>
Added: skencil/branches/skencil-0.6/Doc/devguide/fileformat.xml
===================================================================
--- skencil/branches/skencil-0.6/Doc/devguide/fileformat.xml 2006-06-01 15:34:15 UTC (rev 681)
+++ skencil/branches/skencil-0.6/Doc/devguide/fileformat.xml 2006-06-05 18:35:01 UTC (rev 682)
@@ -0,0 +1,163 @@
+<chapter id="fileformat"><title>File Format</title>
+ <para>
+ Skencil stores drawings in plain ASCII files using a line oriented
+ format. The main idea is that each line of an sk file looks like a
+ Python function call. Originally, this was just for convenience, as
+ the import filter just had to define all those functions in a
+ dictionary, and read and (r)eval each line.
+ </para>
+ <para>
+ That turned out to be quite slow, probably because each line is
+ compiled to bytecode and then executed just once. Skencil now uses a
+ parser written in C. This is much faster and doesn't have the
+ potential security problems of eval.
+ </para>
+ <para>
+ All function arguments are Python literals, ints, floats, strings
+ (delimited with single- or double-quotes, the usual \ escapes are
+ allowed, but no triple quoted strings or raw strings), tuples and
+ lists. Keyword arguments are also allowed.
+ </para>
+ <para>
+ Boolean values are represented as the ints 0 or 1.
+ </para>
+ <para>
+ Colors are represented by float triples describing the RGB values,
+ each in the range 0..1 (e.g. red (1.0, 0.0, 0.0)).
+ </para>
+ <para>
+ All sk files start with '##Sketch' followed by two numbers, the
+ major and minor version number of the file format.
+ </para>
+ <para>
+ Lines starting with # are comments, empty lines are ignored.
+ </para>
+
+ <sect1 id="fileformat-structure"><title>Overall structure</title>
+ <para>
+ The first function in an sk-file is always 'document()'. This
+ function takes no parameters.
+ </para>
+ <para>
+ The next part defines global parameters like the page layout and
+ objects like styles.
+ </para>
+ <para>
+ After this follow the layers from bottom to top.
+ </para>
+ </sect1>
+
+ <sect1 id="fileformat-globals"><title>Globals</title>
+ <para>
+ Functions for global parameters:
+ </para>
+ <variablelist>
+ <varlistentry>
+ <term>layout(<parameter>format</parameter>, <parameter>orientation</parameter>)</term>
+ <listitem>
+ <para>
+ <parameter>format</parameter> is either the name of a
+ predefined paper-format or a tuple
+ (<parameter>width</parameter>, <parameter>height</parameter>)
+ in pt. See Sketch/Lib/pagelayout.py for a list of predefined
+ paper-formats.
+ </para>
+ <para>
+ <parameter>orientation</parameter> is 0 for portrait or 1
+ for landscape.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>dstyle(<parameter>name</parameter>)</term>
+ <listitem>
+ <para>
+ Define the style named <parameter>name</parameter> (a
+ string). The preceding functions define the properties of
+ this style. See the section
+ on <link linkend="fileformat-properties">properties</link>
+ for details.
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </sect1>
+
+ <sect1 id="fileformat-layers"><title>Layers</title>
+ <para>
+ There are three kinds of layers, <emphasis>normal layers</emphasis>,
+ <emphasis>grid layers</emphasis> and <emphasis>guide layers</emphasis>.
+ </para>
+ <para>
+ Normal layers and guide layers can contain other objects. All
+ objects defined after a layer function are part of that layer. A
+ layer is implicitly closed by another layer function or the end of
+ file.
+ </para>
+ <para>
+ The layer functions:
+ </para>
+ <variablelist>
+ <varlistentry>
+ <term>layer(<parameter>name</parameter>, <parameter>visible</parameter>, <parameter>printable</parameter>,
+ <parameter>locked</parameter>, <parameter>outlined</parameter>, <parameter>outline_color</parameter>)</term>
+ <listitem>
+ <para>
+ Start a normal layer named <parameter>name</parameter> (a
+ string). The booleans <parameter>visible</parameter>,
+ <parameter>printable</parameter>, <parameter>locked</parameter>
+ and <parameter>outlined</parameter> determine whether the
+ layer is visible, printable, locked or only shown outlined.
+ </para>
+ <para>
+ <parameter>outline_color</parameter> defines the color used
+ for the outlines of the objects in the layer.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>grid(<parameter>geometry</parameter>)</term>
+ <listitem>
+ <para>
+ Define the grid-layer. The <parameter>geometry</parameter>
+ is a tuple of the form
+ (<parameter>xorig</parameter>, <parameter>yorig</parameter>,
+ <parameter>xwidth</parameter>, <parameter>ywidth</parameter>)
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>guidelayer(<parameter>name</parameter>, <parameter>visible</parameter>, <parameter>printable</parameter>,
+ <parameter>locked</parameter>, <parameter>outlined</parameter>, <parameter>outline_color</parameter>)</term>
+ <listitem>
+ <para>
+ Start the guide layer. The arguments are the same as for the
+ normal layer, but the arguments
+ <parameter>printable</parameter>
+ and <parameter>outlined</parameter> will be ignored and set
+ to 0 and 1 respectively.
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </sect1>
+
+ <sect1 id="fileformat-objects"><title>Objects</title>
+ <sect2>
+ <title>Primitives</title>
+ <para>
+ Primitives
+ </para>
+ </sect2>
+ <sect2>
+ <title>Compound Objects</title>
+ <para>
+ </para>
+ </sect2>
+ </sect1>
+ <sect1 id="fileformat-properties">
+ <title>Properties</title>
+ <para>
+ </para>
+ </sect1>
+</chapter>
Added: skencil/branches/skencil-0.6/Doc/devguide/plugins.xml
===================================================================
--- skencil/branches/skencil-0.6/Doc/devguide/plugins.xml 2006-06-01 15:34:15 UTC (rev 681)
+++ skencil/branches/skencil-0.6/Doc/devguide/plugins.xml 2006-06-05 18:35:01 UTC (rev 682)
@@ -0,0 +1,1028 @@
+<chapter id="plugins"><title>Plugins</title>
+ <para>
+ Plugins provide a way to extend Skencil with external modules that
+ can be maintained independently from Skencil itself. Plugin modules
+ can define import and export filters for new file formats or they
+ can define new object types.
+ </para>
+ <para>
+ For this to work, Skencil has to provide a standardized interface to
+ these modules to allow them to create and manipulate graphics
+ objects. In addition, there has to be some fall-back method if
+ someone loads a document containing objects defined by a plugin into
+ an installation where that particular plugin is not available.
+ </para>
+
+ <sect1 id="plugin-config"><title>Plugin Configuration</title>
+ <para>
+ On startup, Skencil searches for plugins on the <emphasis>plugin
+ path</emphasis>. Every Python source file found is scanned for
+ configuration information. Later, when the the plugin is needed
+ it is imported.
+ </para>
+ <para>
+ The plugin path is a list of directories stored in
+ <literal>Sketch.config.plugin_path</literal>. The directory names
+ should be absolute pathnames. Skencil uses a notation borrowed
+ from the kpathsea library (which is used by many TeX programs to
+ search files):
+ </para>
+ <itemizedlist>
+ <listitem>
+ <para>
+ If a directory name ends in a slash ('/') search in that
+ directory and in the directories immediately contained in it.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ If a directory name ends with two slashes ('//') search in
+ that directory and recursively in all subdirectories.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Else, search only in that directory
+ </para>
+ </listitem>
+ </itemizedlist>
+ <para>
+ The configuration information is a series of Python statements
+ (assignments), each on its own line, between the lines
+ '<literal>###Sketch Config</literal>' and
+ '<literal>###End</literal>'.
+ </para>
+ <para>
+ One of the assignments must be to a variable named
+ "<literal>type</literal>". This specifies the type of the plugin
+ (import filter, plugin object, etc.).
+ </para>
+ <para>
+ Another variable that may be used in the future, is
+ '<literal>version</literal>' which will be used to specify the
+ version of the plugin-config conventions used (not the version of
+ the plugin itself).
+ </para>
+ <para>
+ Other variable names are type dependent.
+ </para>
+ <para>
+ Each of the lines may be commented out.
+ </para>
+ <para>
+ Example:
+<programlisting>
+###Sketch Config
+#type = Import
+#class_name = 'SKLoader'
+#rx_magic = '^##Sketch 1 *(?P<minor>[0-9]+)'
+#tk_file_type = ('Skencil/Sketch Document', '.sk')
+format_name = 'SK-1'
+###End
+</programlisting>
+ </para>
+ <para>
+ Skencil uses this method--instead of importing every plugin module
+ and requiring that they register themselves with the plugin
+ manager--to avoid loading unnecessary modules.
+ </para>
+ <para>
+ Implementation Note: currently Skencil reads the lines between
+ '###Sketch Config' and '###End' into a single string (after
+ removing the initial '#'s if present) and exec's it with a globals
+ dictionary containing the predefined plugin types and an empty
+ locals dictionary which receives all the variables. A consequence
+ of this approach is that it is currently possible to use arbitrary
+ Python statements and not just assignments. Don't rely on this, it
+ could be changed in the future.
+ </para>
+ </sect1>
+
+ <sect1 id="plugin-import"><title>Import Filters</title>
+ <para>
+ Skencil uses import filters to read vector drawings from files.
+ </para>
+
+ <sect2 id="plugin-import-config"><title>Configuration Variables</title>
+ <para>
+ For import filter configuration, Skencil uses the following
+ variables:
+ </para>
+ <variablelist>
+ <varlistentry>
+ <term><literal>type</literal></term>
+ <listitem>
+ <para>
+ The type must be <literal>Import</literal>. This
+ identifier is defined in the globals() dictionary.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry id="plugin-import-conf:class_name">
+ <term><literal>class_name</literal></term>
+ <listitem>
+ <para>
+ A string containing the name of a Python class defined in
+ the module. See below for the interface this class has to
+ provide.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry id="plugin-import-conf:rx_magic">
+ <term><literal>rx_magic</literal></term>
+ <listitem>
+ <para>
+ A string containing a regular expression suitable for the
+ re module. This regular expression is matched against the
+ first line of the file. if it matches, the import
+ mechanism assumes that the filter understands the file's
+ format and then procedes to use that filter to load the
+ file. So, if possible, this regular expression should
+ match those files the filter can handle and only those.
+ </para>
+ <para>
+ While this method of identifying files is not really
+ sufficient to handle all file types, it works well enough
+ for now. In the future we will probably have to extend
+ this mechanism.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><literal>tk_file_type</literal></term>
+ <listitem>
+ <para>
+ A tuple containing two elements. The first is the name of
+ the file format presented to the user in the file open
+ dialog. The second element is eithe a string or a tuple of
+ strings. Each of the strings defines a file name extension
+ used for that filename.
+ </para>
+ <para>
+ Examples:
+ </para>
+ <para>
+ <literal>#tk_file_type = ('Skencil Document', '.sk')</literal>
+ </para>
+ <para>
+ <literal>#tk_file_type = ('PostScript file', ('.ps', '.eps'))</literal>
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry id="plugin-import-conf:unload">
+ <term><literal>unload</literal> (optional)</term>
+ <listitem>
+ <para>
+ A boolean. True means that the filter module should be
+ unloaded after use, false means that it shouldn't be
+ unloaded. If the module is unloaded it will be imported
+ again the next time the filter is needed. Infrequently
+ used filters should set this to true, frequently used
+ filters (like the filter for Skencil's own format) should
+ set it to true.
+ </para>
+ <para>
+ If omitted, it defaults to false.
+ </para>
+ <para>
+ It's a good idea to set this variable to true at least
+ while developing a filter because that way the filter will
+ be automatically reloaded when the source file changes.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><literal>format_name</literal></term>
+ <listitem>
+ <para>
+ The name of the format as a string. This name is currently
+ used internally to find out whether a document was loaded
+ from a file in Skencil's format or from a different format
+ (in the latter case "Save" is treated like "Save As...",
+ i.e. the user has to provide a filename).
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><literal>standard_messages</literal> (optional)</term>
+ <listitem>
+ <para>
+ A boolean indicating whether the messages in the plugin
+ are standard messages that are defined in Skencil's
+ message catalogs. For third-party plugins this should be
+ omitted.
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </sect2>
+
+ <sect2><title>The Class Interface</title>
+
+ <sect3><title>External Interface</title>
+ <para>
+ The interface a loader class presents to the document loading
+ mechanism is quite simple. The loading mechanism works roughly
+ as follows:
+ </para>
+ <orderedlist>
+ <listitem>
+ <para>
+ Read the first line of the file
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Match it in turn against all the regular expressions
+ defined for import filter plugins (defined by
+ the <link linkend="plugin-import-conf:rx_magic">rx_magic
+ variable</link>).
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ If a match is found, instantiate the plugin's class
+ (defined by the <link linkend="plugin-import-conf:class_name">class_name
+ variable</link>) with three positional
+ parameters <parameter>file</parameter>,
+ <parameter>filename</parameter> and
+ <parameter>match</parameter>.
+ <parameter>file</parameter> is the open input file object,
+ positioned just after the first line.
+ <parameter>filename</parameter> is the name of the file.
+ <parameter>match</parameter> is the match-object returned
+ from regular expression match. If possible, filters
+ should read the input file sequentially and not use
+ seeks. Skencil automatically pipes gzipped files through
+ gzip and in that case the file object is actually a pipe,
+ so seeks would be impossible. If a filter needs to access
+ the first line it can do so by using
+ <parameter>match</parameter>.string or by defing suitable
+ groups in the regular expression.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Call the instance's Load() method (without arguments).
+ This method does the actual work and returns an instance
+ of the document class.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Call the instance's Messages() method without arguments.
+ The return value is expected to be a list of strings with
+ messages that are usually presented to the user by the UI.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ If the <link linkend="plugin-import-conf:unload">unload
+ configuration variable</link> is true, unload the
+ plugin's module.
+ </para>
+ </listitem>
+ </orderedlist>
+ </sect3>
+
+ <sect3><title>Common Base Classes</title>
+ <para>
+ To make things easier, Skencil defines some base classes that
+ plugins can
+ inherit, <classname>LoaderWithComposites</classname> and,
+ derived from that, <link
+ linkend="class-GenericLoader"><classname>GenericLoader</classname></link>
+ and <classname>SimplifiedLoader</classname>, derived in turn
+ from <classname>GenericLoader</classname>.
+ </para>
+
+ <sect4 id="class-GenericLoader">
+ <title><classname>GenericLoader</classname></title>
+ <para>
+ The class <classname>GenericLoader</classname> provides a
+ default implementation of the constructor, a mechanism for
+ warning and error messages and methods to easily create
+ standard objects like rectangles, ellipses and groups.
+ </para>
+ <para>
+ <classname>GenericLoader</classname> defines these methods:
+ </para>
+ <variablelist>
+ <varlistentry id="GenericLoader.__init__">
+ <term><function>__init__(<parameter>file</parameter>, <parameter>filename</parameter>, <parameter>match</parameter>)</function></term>
+ <listitem>
+ <para>
+ Assign the arguments to <literal>self.file</literal>,
+ <literal>self.filename</literal> and
+ <literal>self.match</literal> respectively.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry id="GenericLoader.document">
+ <term><function>document()</function></term>
+ <listitem>
+ <para>
+ Start the construction of a document. This method must
+ be called before any other of the object creation
+ methods are called.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry id="GenericLoader.layer">
+ <term><function>layer([<parameter>name</parameter>])</function></term>
+ <listitem>
+ <para>
+ Start a new layer. This method must be called after
+ calling <link
+ linkend="GenericLoader.document"><function>document</function></link>
+ and before any of the other object creation methods.
+ </para>
+ <para>
+ <parameter>name</parameter> is the name of the
+ layer. If omitted, it defaults to "Layer 1".
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry id="GenericLoader.begin_group">
+ <term><function>begin_group()</function></term>
+ <listitem>
+ <para>
+ Start a new group. Groups can be arbitrarily
+ nested. Each call to <function>begin_group</function>
+ must have a corresponding call to
+ <link
+ linkend="GenericLoader.end_group"><function>end_group</function></link>.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry id="GenericLoader.end_group">
+ <term><function>end_group()</function></term>
+ <listitem>
+ <para>
+ End the current group.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry id="GenericLoader.rectangle">
+ <term><!-- methdef -->rectangle(<parameter>m11</parameter>, <parameter>m21</parameter>,
+ <parameter>m12</parameter>, <parameter>m22</parameter>, <parameter>v1</parameter>, <parameter>v2</parameter>[, <parameter>radius1</parameter> = 0][,
+ <parameter>radius2</parameter> =
+ 0])<!-- /methdef --></term>
+ <listitem>
+ <para>
+ Create a new rectangle object and append it to the
+ current compound object.
+ </para>
+ <para>
+ The first six positional parameters
+ (<parameter>m11</parameter>,
+ <parameter>m21</parameter>,
+ <parameter>m12</parameter>,
+ <parameter>m22</parameter>,
+ <parameter>v1</parameter>, <parameter>v2</parameter>)
+ define a transformation matrix that transforms the
+ unit square (opposite corners (0,0) and (1,1))
+ onto the rectangle.
+ </para>
+ <para>
+ <parameter>radius1</parameter> and
+ <parameter>radius2</parameter> define the rounded
+ corners.
+ </para>
+ <para>
+ For more details see the documentation for the
+ class <link
+ linkend="class-Rectangle"><classname>Rectangle</classname></link>
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry id="GenericLoader.ellipse">
+ <term><!-- methdef -->ellipse(<parameter>m11</parameter>, <parameter>m21</parameter>,
+ <parameter>m12</parameter>, <parameter>m22</parameter>, <parameter>v1</parameter>, <parameter>v2</parameter>[,
+ <parameter>start_angle</parameter> = 0.0][, <parameter>end_angle</parameter> = 0.0][,
+ <parameter>arc_type</parameter> = ArcPieSlice])<!-- /methdef --></term>
+ <listitem>
+ <para>
+ Create a new ellipse object and append it to the
+ current compound object.
+ </para>
+ <para>
+ The first six positional parameters
+ (<parameter>m11</parameter>,
+ <parameter>m21</parameter>,
+ <parameter>m12</parameter>,
+ <parameter>m22</parameter>,
+ <parameter>v1</parameter>, <parameter>v2</parameter>)
+ define a transformation matrix that transforms the
+ unit circle (center (0,0) and radius 1) onto the
+ ellipse.
+ </para>
+ <para>
+ <parameter>start_angle</parameter>
+ and <parameter>end_angle</parameter>, if given, define
+ the start end end angles for pie slices, arc and
+ chords.
+ </para>
+ <para>
+ <parameter>arc_type</parameter> defines whether and
+ how the arc of an incomplete ellipse is closed. Valid
+ values are <literal>ArcArc</literal>,
+ <literal>ArcPieSlice</literal>
+ and <literal>ArcChord</literal>. These constants are
+ defined in <literal>Sketch.const</literal>
+ </para>
+ <para>
+ For more details see the documentation for the
+ class <classname>Ellipse</classname>
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry id="GenericLoader.bezier">
+ <term><function>bezier(<parameter>paths</parameter>)</function></term>
+ <listitem>
+ <para>
+ Create a new bézier object in the current
+ compound object.
+ </para>
+ <para>
+ <parameter>paths</parameter> must be a tuple
+ of <link linkend="class-curveobject">curve
+ objects</link>.
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </sect4>
+ </sect3>
+ </sect2>
+ </sect1>
+
+ <sect1 id="plugin-export"><title>Export Filters</title>
+ <para>
+ Skencil uses export filters to write documents to files.
+ </para>
+
+ <sect2>
+ <title>Configuration Variables</title>
+ <para>
+ For export filter configuration, Skencil uses the following
+ variables:
+ </para>
+ <variablelist>
+ <varlistentry>
+ <term><literal>type</literal></term>
+ <listitem>
+ <para>
+ The type must be <literal>Export</literal>. This
+ identifier is defined in the globals() dictionary.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><literal>tk_file_type</literal></term>
+ <term><literal>unload</literal> (optional)</term>
+ <term><literal>format_name</literal></term>
+ <listitem>
+ <para>
+ These variables have the same meaning
+ as <link linkend="plugin-import-config">in an import
+ filter</link>.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><literal>extensions</literal></term>
+ <listitem>
+ <para>
+ A string with the standard file extension of the export
+ format. Alternatively this can be a tuple of file
+ extension strings.
+ </para>
+ <para>
+ Skencil uses the file extension to find the export filter.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><literal>standard_messages</literal> (optional)</term>
+ <listitem>
+ <para>
+ A boolean indicating whether the messages in the plugin
+ are standard messages that are defined in Skencil's
+ message catalogs. For third-party plugins this should be
+ omitted.
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </sect2>
+
+ <sect2><title>External Interface</title>
+ <para>
+ Given a document object and a filename for the output file,
+ Skencil does the following to find an export filter and to
+ export the drawing:
+ </para>
+ <orderedlist>
+ <listitem>
+ <para>
+ Take the extension of the output filename and find the
+ export filter that uses that extension.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Load the module of the plugin
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Call the module's <function>save</function> function.
+ </para>
+ </listitem>
+ </orderedlist>
+ </sect2>
+
+ <sect2><title>The <function>save</function> function</title>
+ <para>
+ The function <function>save</function> is the main entry point
+ for an export plugin. It is called with four positional
+ parameters <parameter>document</parameter>, <parameter>file</parameter>,
+ <parameter>filename</parameter>
+ and <parameter>options</parameter>.
+ </para>
+ <para>
+ <parameter>document</parameter> is the document that is to be
+ saved. <parameter>file</parameter> is the output file object
+ open for writing and <parameter>filename</parameter> is the
+ corresponding filename. Finally, <parameter>options</parameter>
+ is a dictionary with (user specified) options. Currently,
+ <parameter>options</parameter> is always an empty dictinary as
+ there is no way yet to specify such options.
+ </para>
+ </sect2>
+
+ <sect2><title>Implementation Strategy</title>
+ <para>
+ Apart from the <function>save</function> function entry point
+ Skencil requires very little from the plugin. The only other
+ thing it expects is that the plugin traverses the object tree by
+ itself and uses the interface provided by
+ the <link
+ linkend="class-Protocols"><classname>Protocols</classname></link>
+ class to distinguish the different object types.
+ </para>
+ <para>
+ In the following, the svg export filter serves as the basis for
+ a a brief outline of this technique.
+ </para>
+ <para>
+ Both the svg and the ai filter use the same basic approach. They
+ implement the filter as a class and use an instance of that
+ class to do the work:
+ </para>
+ <para>
+<programlisting>
+def save(document, file, filename, options = {}):
+ saver = SVGSaver(file, filename, document, options)
+ saver.Save()
+ saver.close()
+</programlisting>
+ </para>
+ <para>
+ The interesting parts happen in the class. The constructor
+ doesn't do much, it just saves the parameters in instance
+ variables:
+<programlisting>
+class SVGSaver:
+
+ def __init__(self, file, filename, document, options):
+ self.file = file
+ self.filename = filename
+ self.document = document
+ self.options = options
+</programlisting>
+ </para>
+ <para>
+ The Save method is where the real work begins. First it
+ writes a kind of file header:
+<programlisting>
+ def Save(self):
+ self.file.write('<?xml version="1.0" standalone="yes"?>\n')
+ left, bottom, right, top = self.document.BoundingRect()
+ width = right - left
+ height = top - bottom
+ self.trafo = Trafo(1, 0, 0, -1, -left, top)
+ self.file.write('<svg width="%g" height="%g"' % (width, height))
+ self.file.write('>\n')
+</programlisting>
+ </para>
+ <para>
+ The document method <function>BoundingRect</function> returns
+ the bounding rectangle of the entire document
+ </para>
+ <para>
+ After the header it loops over all the layers in the document...
+<programlisting>
+ for layer in self.document.Layers():
+</programlisting>
+ </para>
+ <para>
+ ...and if the layer is not a special layer, such as grid or
+ guide layers, and if the layer is printable...
+ </para>
+<programlisting>
+ if not layer.is_SpecialLayer and layer.Printable():
+</programlisting>
+ <para>
+ ... save the layer as a group:
+ </para>
+<programlisting>
+ self.BeginGroup()
+ self.save_objects(layer.GetObjects())
+ self.EndGroup()
+</programlisting>
+ <para>
+ <function>GetObjects()</function> returns a list of all objects
+ in the layer. All compound objects have this method. In the SVG
+ filter, the <function>BeginGroup</function>
+ and <function>EndGroup</function> methods write
+ the <literal><g></literal>
+ and <literal></g></literal> tags that mark groups in SVG.
+ </para>
+ <para>
+ Finally, the trailer to close the <literal><svg></literal>
+ tag.
+<programlisting>
+ self.file.write('</svg>')
+</programlisting>
+ </para>
+ <para>
+ The next interesting method is save_objects. It loops over the
+ list of objects...
+<programlisting>
+ def save_objects(self, objects):
+ for object in objects:
+</programlisting>
+ ...and if the object is a compound object...
+<programlisting>
+ if object.is_Compound:
+</programlisting>
+ ...save it as a group
+<programlisting>
+ self.BeginGroup()
+ self.save_objects(object.GetObjects())
+ self.EndGroup()
+</programlisting>
+ </para>
+ <para>
+ otherwise, if the object is a bezier object, a rectangle or an
+ ellipse...
+<programlisting>
+ elif object.is_Bezier or object.is_Rectangle or object.is_Ellipse:
+</programlisting>
+ ...save the object as bezier curves.
+<programlisting>
+ self.PolyBezier(object.Paths(), object.Properties(),
+ object.bounding_rect)
+</programlisting>
+ </para>
+ <para>
+ The <function>Paths</function> method returns a tuple
+ of <link linkend="class-curveobject">path
+ objects</link>. <function>Properties</function> returns an
+ object that has members like <literal>fill_pattern</literal>
+ and <literal>line_width</literal> that define the properties of
+ the object.
+ </para>
+ </sect2>
+ </sect1>
+
+ <sect1 id="plugin-objects"><title>Plugin Objects</title>
+ <para>
+ Plugin objects provide a way to define new types of
+ objects. Plugin objects can define how the user interacts with
+ them and they can be saved to and loaded from sk files. The design
+ of plugin objects takes the problem of loading files containing
+ plugin objects that a particular Skencil installation doesn't know
+ about into account.
+ </para>
+ <para>
+ An example of a plugin object is the regular polygon object that
+ comes with Skencil.
+ </para>
+
+ <sect2><title>Design Philosophy</title>
+ <para>
+ The idea behind plugin objects is that they're groups of builtin
+ objects with some special attributes and behavior on top of
+ that.
+ </para>
+ <para>
+ What a plugin object looks like is completely defined by the
+ children. This is the key to being able to load drawings with
+ unknown plugin objects. Because the children are builtin objects
+ Skencil can display and print them without problems by treating
+ them more or less as ordinary groups.
+ </para>
+ </sect2>
+
+ <sect2><title>Saving and Loading a Plugin Object</title>
+ <para>
+ A plugin object is saved as a special compound object together
+ with all its children. When Skencil reads an sk file with a
+ plugin object that it doesn't know about it can still treat is
+ like a normal group and since all drawing is done by the
+ children it can still display and print it.
+ </para>
+ <para>
+ Skencil is actually a bit smarter than that. It doesn't turn
+ unknown plugin objects into normal groups, it turns them into an
+ UnknownPlugin object that remembers which class the object
+ belongs to and what parameters were used. As long as the object
+ isn't changed it is saved as a plugin object again.
+ </para>
+ </sect2>
+ <sect2><title>Configuration Variables</title>
+ <para>
+ For plugin object configuration, Skencil uses the following
+ variables:
+ </para>
+ <variablelist>
+ <varlistentry>
+ <term><literal>type</literal></term>
+ <listitem>
+ <para>
+ The type must be <literal>PluginCompound</literal>. This
+ identifier is defined in the globals() dictionary.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry id="plugin-object-conf:class_name">
+ <term><literal>class_name</literal></term>
+ <listitem>
+ <para>
+ A string containing the name of a Python class defined in
+ the module. See below for the interface this class has to
+ provide.
+ </para>
+ <para>
+ Skencil uses the class_name to distinguish different
+ plugin types and should therefore be unique. A future
+ version of Skencil will probably use a different name for
+ that purpose.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><literal>menu_text</literal></term>
+ <listitem>
+ <para>
+ The text to display in the menu as a string. In the 0.6.x,
+ this text is used for the entry in the Edit->Create menu.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><literal>standard_messages</literal> (optional)</term>
+ <listitem>
+ <para>
+ A boolean indicating whether the messages in the plugin
+ are standard messages that are defined in Skencil's
+ message catalogs. For third-party plugins this should be
+ omitted.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry id="plugin-object-conf:parameters">
+ <term><literal>parameters</literal> (optional)</term>
+ <listitem>
+ <para>
+ A tuple of tuples describing the parameters of the
+ object. This information is used to create a dialog that
+ allows the user to set the parameters for new objects and
+ modify those of existing objects.
+ </para>
+ <para>
+ See below for more detail.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><literal>factory</literal> (optional)</term>
+ <listitem>
+ <para>
+ The name of a function that is to be called by the user
+ interface code instead of the class to create a new
+ object. The sk import filter always calls the class
+ directly.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><literal>uses_selection</literal> (optional)</term>
+ <listitem>
+ <para>
+ If this boolean is true, the factory, if defined, or the
+ class will be called with a list of objects as the only
+ parameter. These objects are the ones currently selected.
+ </para>
+ <para>
+ When omitted, it defaults to 0.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry id="plugin-object-conf:custom_dialog">
+ <term><literal>custom_dialog</literal> (optional)</term>
+ <listitem>
+ <para>
+ The name of a dialog class that is to be used instead of
+ the dialog automatically built from the parameters
+ information.
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </sect2>
+
+ <sect2><title>Implementation of a Plugin Object</title>
+ <para>
+ Many plugin objects have some parameters that the user can set
+ and modify and that have to be saved and read in again.
+ </para>
+ <para>
+ For the user interface part, there are two mechanism to deal
+ with parameters. They can either be defined by
+ the <link
+ linkend="plugin-object-conf:parameters"><literal>parameters</literal></link>
+ configuration variable in which case Skencil automatically
+ builds a dialog from the description or the plugin can implement
+ a custom dialog and tell Skencil to use it with
+ the <link
+ linkend="plugin-object-conf:custom_dialog"><literal>custom_dialog</literal></link>
+ configuration variable.
+ </para>
+ <para>
+ The <literal>parameters</literal> variable has to be sequence of
+ pentuples each of which defines one parameter. The pentuple has
+ the form
+ </para>
+ <para>
+ <literal> (<parameter>name</parameter>, <parameter>type</parameter>, <parameter>default</parameter>, <parameter>range</parameter>, <parameter>label</parameter>)</literal>
+ </para>
+ <para>
+ where <emphasis>label</emphasis> is text suitable for a label in
+ the dialog box. <parameter>name</parameter> is the internal name
+ for that property. The constructor of the plugin object must
+ accept a keyword argument name. Also, the plugin object must
+ have a method <parameter>Capname</parameter> to read the current
+ value of that property and a method
+ <function>SetParameters</function> accepting a
+ dictionary of parameters and returning undo information.
+ <parameter>Capname</parameter> is a "Capitalized" version of
+ the lowercase name (if <parameter>name</parameter> is
+ "the_parameter", <parameter>Capname</parameter> is
+ "TheParameter")
+ </para>
+ <para>
+ <parameter>type</parameter> describes the type of the
+ parameter, <parameter>default</parameter> is the initial value
+ and <parameter>range</parameter> describes the valid values.
+ </para>
+ <para>
+ Supported types:
+ </para>
+ <para>
+ <informaltable>
+ <tgroup cols="3">
+ <thead>
+ <row><entry>type</entry><entry>range</entry></row>
+ </thead>
+ <tbody>
+ <row>
+ <entry>int</entry>
+ <entry>
+ (<parameter>MIN</parameter>, <parameter>MAX</parameter>)
+ </entry>
+ <entry>
+ the minimal and maximal
+ value. <parameter>MIN</parameter>
+ and/or <parameter>MAX</parameter> may be None
+ indicating no limit (apart from the builtin limits).
+ </entry>
+ </row>
+ <row>
+ <entry>float</entry>
+ <entry>
+ (<parameter>MIN</parameter>, <parameter>MAX</parameter>)
+ </entry>
+ <entry>
+ same as for int
+ </entry>
+ </row>
+ <row>
+ <entry>length</entry>
+ <entry>
+ (<parameter>MIN</parameter>, <parameter>MAX</parameter>)
+ </entry>
+ <entry>
+ A length in pt. The user can change the unit.
+ </entry>
+ </row>
+ <row>
+ <entry>text</entry>
+ <entry>
+ ignored
+ </entry>
+ <entry>
+ A text string (the range should be None for now)
+ </entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </informaltable>
+ </para>
+ <para>
+ Saving of plugin objects works a little differently for sk-files
+ than for other, non-native file formats.
+ </para>
+ <para>
+ Export filters for non-native file formats treat plugin objects
+ just like groups. That means you don't have to do anything
+ special, but it also means that any extra information associated
+ with the plugin-object will be lost.
+ </para>
+ <para>
+ Saving to an sk-file is done by the
+ <function>SaveToFile</function> method which is called with
+ an <classname>SKSaver</classname> instance, customarily
+ called <literal>file</literal>. <classname>SKSaver</classname>
+ is defined by the sksaver plugin. The plugin-object is expected
+ to first call <literal>file.BeginPluginCompound</literal> with
+ appropriate arguments, then to call each child's SaveToFile
+ method with <literal>file</literal> as the only argument and
+ finally <literal>file.EndPluginCompound</literal> with no
+ arguments.
+ </para>
+ <para>
+ <function>BeginPluginCompound</function> has the following syntax:
+ </para>
+ <variablelist>
+ <varlistentry id="SKSaver.BeginPluginCompound">
+ <term>
+ <function>BeginPluginCompound(<parameter>plugin_name</parameter> [, <parameter>arg1</parameter>, ...]
+ [, <parameter>kwarg1</parameter> = <parameter>value1</parameter>, ...])</function>
+ </term>
+ <listitem>
+ <para>
+ Start a plugin compound object in the sk
+ file. <parameter>plugin_name</parameter> has to be the
+ same as the configuration
+ variable <link
+ linkend="plugin-object-conf:class_name">class_name</link>.
+ </para>
+ <para>
+ All remaining arguments, whether positional or keyword
+ arguments, should be builtin python types. They're written
+ to the file as is. The keywords if used must be names of
+ parameters if the configuration
+ variable <link
+ linkend="plugin-object-conf:parameters">parameters</link>
+ is used.
+ </para>
+ <para>
+ When the file is read in again the plugin class is called
+ with these arguments to create the instance.
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </sect2>
+
+ <sect2 id="class-PluginCompound">
+ <title>The class <classname>PluginCompound</classname></title>
+ <para>
+ To make implementation easier, Skencil provides a base class for
+ plugin objects. <classname>PluginCompound</classname> has a
+ default implementation of <function>SetParameters</function>
+ which assumes that the parameters are instance variables that
+ have the same name as the parameters.
+ </para>
+ <para>
+ Furthermore, it has an implementation
+ of <function>SaveToFile</function> that has to be extended by
+ the derived class. All the derived class has to do in its
+ implementation of <function>SaveToFile</function> is to call the
+ inherited method with the same arguments as the SKSaver
+ method <link
+ linkend="SKSaver.BeginPluginCompound"><function>BeginPluginCompound</function></link>
+ except the class name. The class name is expected to be in a
+ (class-)attribute called <literal>class_name</literal>.
+ </para>
+ <para>
+ For examples see the regular polygon and the LCD-text objects in
+ <filename>Plugin/Objects</filename>.
+ </para>
+ </sect2>
+ </sect1>
+</chapter>
Added: skencil/branches/skencil-0.6/Doc/devguide/remarks.xml
===================================================================
--- skencil/branches/skencil-0.6/Doc/devguide/remarks.xml 2006-06-01 15:34:15 UTC (rev 681)
+++ skencil/branches/skencil-0.6/Doc/devguide/remarks.xml 2006-06-05 18:35:01 UTC (rev 682)
@@ -0,0 +1,413 @@
+<chapter id="misc"><title>General Remarks</title>
+ <sect1 id="directorystructure"><title>Directory Structure</title>
+ <para>
+ The source is divided into the core sources, containing the basic
+ graphics classes, the UI code and some utility
+ modules. <link linkend="plugin-import">Import filters</link> and
+ other <link linkend="plugins">plugins</link> are maintained
+ outside of this core source. Other external packages provide
+ direct access to Xlib functions and objects
+ (<link linkend="dir-pax">Pax</link>) and stream filter objects
+ (<link linkend="dir-filter">Filter</link>).
+ </para>
+
+ <variablelist>
+ <varlistentry>
+ <term><filename>sketch-<version>/</filename></term>
+ <listitem>
+ <para>
+ The top level directory holds the main scripts
+ <filename>sketch.py</filename>
+ and <filename>sk2ps.py</filename>
+ </para>
+ <variablelist>
+ <varlistentry>
+ <term><filename>Sketch/</filename></term>
+ <listitem>
+ <para>
+ The top-level directory for the core sources. This
+ works as a Python package which exports many of the
+ commonly needed support and graphics objects (classes,
+ functions, constants etc.).
+ </para>
+ <para>
+ Ideally, the <literal>Sketch</literal> package should
+ export every thing a "normal" plugin may need. This is
+ not yet the case, as some interfaces are not very
+ stable yet and may need to be redesigned. Once they
+ have reached a certain level of stability, they will
+ be moved into <literal>Sketch</literal>.
+ </para>
+
+ <variablelist>
+ <varlistentry><term><filename>Base/</filename></term>
+ <listitem>
+ <para>
+ Contains the most fundamental modules such as
+ the modules for file IO, undo/redo, the plugin
+ manager and code for user preferences.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry><term><filename>Modules/</filename></term>
+ <listitem>
+ <para>
+ The C-Modules.
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ <para>
+ The modules in <literal>Base/</literal> and
+ <literal>Modules/</literal> are accessible as
+ <literal>Sketch.<parameter>modulename</parameter></literal>.
+ These directories are not currently subpackages.
+ </para>
+ <variablelist>
+ <varlistentry>
+ <term><filename>Graphics/</filename></term>
+ <listitem>
+ <para>
+ The subpackage for the graphics modules.
+ </para>
+ <para>
+ It contains all of the builtin graphics classes:
+ primitives, compound objects, special effects
+ (blend/mask/...), the document object, ...
+ </para>
+ <para>
+ It also holds the graphics devices for drawing
+ into the window or PostScript file.
+ </para>
+ <para>
+ The <literal>Graphics</literal> modules are
+ accesible as
+ <literal>Sketch.Graphics.<parameter>modulename</parameter></literal>.
+ Many of the objects defined in Graphics
+ modules are exported directly by the Sketch
+ module.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><filename>UI/</filename></term>
+ <listitem>
+ <para>
+ The subpackage for user interface related code.
+ </para>
+ <para>
+ Contains the user interface code including the
+ application object.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry><term><filename>Lib/</filename></term>
+ <listitem>
+ <para>
+ A subpackage for some support modules that are
+ not really Skencil specific, such as a Type 1
+ font interpreter (simply extracts the outline
+ information) and a simple parser for PostScript
+ files adhering to the DSC.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry><term><filename>Pixmaps/</filename></term>
+ <listitem>
+ <para>
+ Pixmap files used by Skencil.
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry><term><filename>Plugins/</filename></term>
+ <listitem>
+ <para>
+ The subdirectories contain the various
+ <link linkend="plugins">plugins</link>:
+ </para>
+ <variablelist>
+ <varlistentry id="dir-plugins-filters">
+ <term><filename>Filters/</filename></term>
+ <listitem>
+ <para>
+ Contains the <link linkend="plugin-import">import
+ filters</link> and export filters for SK-files
+ and other formats.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><filename>Objects/</filename></term>
+ <listitem>
+ <para>
+ <link linkend="plugin-objects">Plugin objects</link>.
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry><term><filename>Resources/</filename></term>
+ <listitem>
+ <para>
+ The subdirectories contain platform/UI independent
+ resources:
+ </para>
+ <variablelist>
+ <varlistentry>
+ <term><filename>Fontmetrics/</filename></term>
+ <listitem>
+ <para>
+ Fontmetrics (<filename>*.afm</filename>) for
+ standard PostScript fonts and "font directory
+ files" (<filename>*.sfd</filename>) that
+ describe fonts for Skencil.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><filename>Misc/</filename></term>
+ <listitem>
+ <para>
+ Files that define arrows
+ (<filename>*.arrow</filename>), dashes
+ (<filename>*.dashes</filename>), palettes
+ (<filename>*.spl</filename>) and Tk-resources.
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry id="dir-pax">
+ <term><filename>Pax/</filename></term>
+ <listitem>
+ <para>
+ Modules that allow Skencil direct access to Xlib. This
+ is a heavily modified version of the Xt-module.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term id="dir-filter"><filename>Filter/</filename></term>
+ <listitem>
+ <para>
+ A module for stream filters. A stream filter behaves
+ just like a (non seekable) file and comes in two
+ variants: An encoding filter encodes the data written
+ to it and writes the encoded data to a data target (a
+ file or another filter); a decoding filter reads data
+ from a data source (a file or another filter) and
+ provides it in decoded form.
+ </para>
+ <para>
+ These stream filters are modeled after the filters in
+ PostScript Level 2.
+ </para>
+ <para>
+ Don't confuse these filters with the Import filters in the
+ <link
+ linkend="dir-plugins-filters"><filename>Plugins/Filters/</filename></link>
+ directory (although import filters might use stream
+ filters to decode the data).
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry><term><filename>Examples/</filename></term>
+ <listitem>
+ <para>
+ Some example drawings.
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </sect1>
+
+ <sect1 id="namingconventions"><title>Naming Conventions</title>
+ <para>
+ Module names are <literal>lowercase</literal>.
+ </para>
+ <para>
+ Functions have identifiers that are either
+ <literal>lowercase_with_underscores</literal>
+ or <literal>Capitalized</literal>. This is a bit of a mess, but
+ generally the former should be preferred.
+ </para>
+ <para>
+ Variables, local or global, are
+ also <literal>lowercase_with_underscores</literal>. Module
+ internal names (for functions, variables, etc.) shouldstart with
+ an underscore ("<literal>_</literal>") (this is a Python
+ convention that affects import statements and module
+ finalization).
+ </para>
+ <para>
+ Class names are <literal>Capitalized</literal>. Public methods are also
+ <literal>Capitalized</literal>, protected methods
+ are <literal>lowercase_with_underscores</literal>, private methods
+ start with two underscores (another Python convention). Instance
+ variables are also <literal>lowercase_with_underscores</literal>.
+ </para>
+ <para>
+ Constants are often <literal>UPPERCASE</literal> (an exception are
+ the X-constants in <literal>Pax/X.py</literal>)
+ </para>
+ <para>
+ Python does not enforce encapsulation and the distinction between
+ public, protected and private methods and instance variables is
+ more or less a convention programmers are expected to adhere to.
+ </para>
+ </sect1>
+
+ <sect1 id="codingguidelines"><title>Coding Guidelines</title>
+ <para>
+ This <emphasis>not</emphasis> a "coding style" or something
+ similar you are required to adhere to, just some remarks on
+ writing maintainable and readable Python code (IMHO).
+ </para>
+ <sect2>
+ <title>Import statements</title>
+ <para>
+ Don't use <literal>from <parameter>module</parameter> import *</literal>
+ </para>
+ <para>
+ It is difficult to find out whether the code really depends on
+ objects exported by the module. Editing the source or moving
+ some parts of the code to other modules may result in code that
+ doesn't need that module any more, so the import statement
+ should be removed.
+ </para>
+ <para>
+ Using "<literal>import <parameter>module</parameter></literal>"
+ or "<literal>from <parameter>module</parameter>
+ import <parameter>foo</parameter>, <parameter>bar</parameter></literal>"
+ makes this easier.
+ </para>
+ </sect2>
+
+ <sect2><title>Multiple assignments</title>
+ <para>
+ Don't use multiple assignments.
+ </para>
+ <para>
+ Multiple assignments are assignments like this:
+ </para>
+ <para>
+<programlisting>
+ a, b = 0, 1
+</programlisting>
+ </para>
+ <para>
+ I think this is harder to read than
+ </para>
+ <para>
+<programlisting>
+ a = 0
+ b = 1
+</programlisting>
+ </para>
+ <para>
+ or, if you really want only one line,
+<programlisting>
+ a = 0; b = 1
+</programlisting>
+ </para>
+ <para>
+ In the current interpreter (Python 1.5.1) the multiple
+ assignment is even slower than two single assignments (for local
+ variables; the interpreter actually builds a tuple and unpacks
+ it immediately)
+ </para>
+ <para>
+ Multiple assignments are convenient, though, if the first
+ assignment has side effects influencing the second
+ assignment. If you want to swap the values of the
+ variables <literal>a</literal> and <literal>b</literal> you may
+ write
+<programlisting>
+ a, b = b, a
+</programlisting>
+ </para>
+ <para>
+ Note that even in this case the traditional idiom for swapping
+ variables, <literal>temp = a; a = b; b = temp</literal>
+ is <emphasis>faster</emphasis> than multiple assignment
+ (see <filename>Tools/swapbench.py</filename>).
+ </para>
+ </sect2>
+
+ <sect2>
+ <title>
+ Truth Values, <literal>__getattr__</literal> and
+ <literal>__len__</literal>
+ </title>
+ <para>
+ In various places, instance or class attributes have the
+ value <literal>None</literal> to indictate that the attribute
+ has no particular value, while, if the attribute is set, its
+ value is an instance object (one such attribute is
+ <link linkend="class-HierarchyNode"><classname>HierarchyNode</classname></link>'s
+ attribute <literal>parent</literal>). Functions and methods
+ often return <literal>None</literal> instead of an instance
+ object for similar reasons.
+ </para>
+ <para>
+ There are more cases, and, indeed, the following applies
+ whenever you have an object that may be <literal>None</literal>
+ or an instance object.
+ </para>
+ <para>
+ In all these cases, you have to test whether the object you have
+ is <literal>None</literal> or not. It is tempting to write e.g.
+<programlisting>
+ if self.parent:
+ self.parent.SomePublicMethod()
+</programlisting>
+ </para>
+ <para>
+ Don't do that. Test whether the object <emphasis>is</emphasis>
+ <literal>None</literal>:
+<programlisting>
+ if self.parent is not None:
+ self.parent.SomePublicMethod()
+</programlisting>
+ </para>
+ <para>
+ There are two reasons for this:
+ </para>
+ <para>
+ Firstly, if the object is an instance object, Python tries to
+ determine if it is true or false by calling its
+ <literal>__nonzero__</literal> method and, if it doesn't have
+ that method, its <literal>__len__</literal> method. Now, most
+ objects in Skencil don't have these methods, so Python tries to
+ call the <literal>__getattr__</literal> method, which many
+ objects, including all graphics objects, have, twice,
+ for <literal>__nonzero__</literal>
+ and <literal>__len__</literal>. This overhead can be avoided by
+ testing for identity with <literal>None</literal>.
+ </para>
+ <para>
+ Secondly, even if you know that the object has no
+ <literal>__len__</literal> or <literal>__nonzero__</literal>
+ methods (and, hence, is always considered "true"), it may have
+ them in future versions (the compound graphics objects might
+ implement the Python sequence protocol and, accordingly, the
+ <literal>__len__</literal> method). In that case, code that
+ simply tests whether the object is true would break, as the
+ object might be false even though it is <emphasis>not</emphasis>
+ <literal>None</literal>.
+ </para>
+ </sect2>
+ </sect1>
+</chapter>
Added: skencil/branches/skencil-0.6/Doc/devguide/ui.xml
===================================================================
--- skencil/branches/skencil-0.6/Doc/devguide/ui.xml 2006-06-01 15:34:15 UTC (rev 681)
+++ skencil/branches/skencil-0.6/Doc/devguide/ui.xml 2006-06-05 18:35:01 UTC (rev 682)
@@ -0,0 +1,59 @@
+<chapter id="ui"><title>User Interface</title>
+
+ <sect1 id="ui-commands">
+ <title>Commands</title>
+ <para>
+ <emphasis>Commands</emphasis> (or command objects), represent a
+ command that can be invoked by the user. Menu items and buttons
+ are not directly connected to methods of the canvas or the
+ document, but are connected to these commands.
+ </para>
+ <para>
+ A command object knows how to invoke the command (i.e. which
+ method of which object to call with which arguments) and how to
+ update itself. This update is done by calling several
+ callbacks. The following attributes are updated:
+ </para>
+ <variablelist>
+ <varlistentry><term>Menu Name</term>
+ <listitem>
+ <para>
+ The text to display in a menu entry. The only commands that
+ use this currently are Undo and Redo. They use it to
+ indicate what action would be undone or redone.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry><term>Sensitivity</term>
+ <listitem>
+ <para>
+ Whether the command is available at the moment or not. Most
+ commands have a callback for this because this attribute
+ determines whether the associated widgets (menu items or
+ buttons) are grayed out or not.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry><term>Value</term>
+ <listitem>
+ <para>
+ The value is used by check command objects to determine
+ whether they are checked or not. In the current
+ implementation this value is used as the value of a Tkinter
+ IntVar which is associated with a widget (or menu item), so
+ it should be true for "checked" and false for "unchecked".
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ <para>
+ Whenever, during an update, at least one of the attributes change,
+ all menu items or other associated widgets are notified and also
+ updated.
+ </para>
+ <para>
+ A command object can be associated with any number of widgets or
+ menu items.
+ </para>
+ </sect1>
+</chapter>
Added: skencil/branches/skencil-0.6/Doc/devguide/undo.xml
===================================================================
--- skencil/branches/skencil-0.6/Doc/devguide/undo.xml 2006-06-01 15:34:15 UTC (rev 681)
+++ skencil/branches/skencil-0.6/Doc/devguide/undo.xml 2006-06-05 18:35:01 UTC (rev 682)
@@ -0,0 +1,248 @@
+<chapter id="undo"><title>The Undo Mechanism</title>
+ <para>
+ Skencil allows the user to undo every operation that is performed on
+ a document. To achieve this, it needs to keep some information on
+ how to undo the operation. The fact that in Python objects are
+ dynamically typed and functions and (bound) methods are objects
+ allows us to store this information in a very simple and yet very
+ flexible way.
+ </para>
+ <para>
+ I'll call this information <emphasis>undo information</emphasis>,
+ or <emphasis>undoinfo</emphasis> for short.
+ </para>
+
+ <sect1 id="undo-creation"><title>Creation and Storage</title>
+ <para>
+ In Skencil, undoinfo is stored basically in a list in the
+ document object (actually in an instance of the
+ <classname>UndoRedo</classname> class owned by the document).
+ </para>
+ <para>
+ A document method that changes the document either creates the
+ undoinfo itself or requires that the functions and methods it
+ calls return the undoinfo. The latter case is the most common, as
+ most operations do not change the state of the document object
+ itself but the state of a layer or a primitive.
+ </para>
+ <para>
+ In fact, most functions that are expected to return undoinfo do
+ not perform the operation themselves, but call other methods and
+ simply pass the undoinfo they get from those methods back to their
+ caller.
+ </para>
+ <para>
+ Consider for example the method <function>SetProperties</function>
+ of a group object. A group object has no graphics properties of
+ its own, but setting, e. g., the fill pattern of a group will set
+ the fill pattern of all of the group's children (the objects
+ contained in the group). So its <function>SetProperties</function>
+ method calls the <function>SetProperties</function> method of each
+ of its children and stores the undo info it gets in a list. The
+ undoinfo it returns to its caller will basically say: "to undo the
+ operation you must undo everything in this list".
+ </para>
+ </sect1>
+ <sect1 id="undo-representation">
+ <title>Representation of Undoinfo</title>
+ <para>
+ In Skencil, undoinfo is stored as a tuple whose first element is a
+ callable object. The rest of the tuple are the arguments that the
+ callable object must be called with to actually do the undo:
+ </para>
+ <para>
+ <!-- def --><!-- thtag -->Undoinfo (1)<!-- /thtag -->
+ </para>
+ <para>
+ A tuple <literal>t</literal> is a tuple of undoinfo of an
+ operation, iff the Python expression
+ "<literal>apply(t[0], t[1:])</literal>" will undo the
+ operation.
+ </para>
+ <!-- /def -->
+ <para>
+ Example: The <function>SetRadius</function> method of the regular
+ polygon plugin:
+<programlisting>
+def SetRadius(self, radius):
+ undo = self.SetRadius, self.radius # create undoinfo
+ self.radius = radius # set the instance variable
+ # ... update internal data here ...
+ return undo # finally, return undo info
+</programlisting>
+ </para>
+ <para>
+ Undoing <function>SetRadius</function> simply means to set the
+ radius back to the old one, that is, one has to call the
+ method <function>SetRadius</function> of the same object again,
+ only this time with the old radius as parameter. Thus the undoinfo
+ returned is "<literal>(self.SetRadius, self.radius)</literal>"
+ which is executed before <literal>self.radius</literal>
+ changes. Note, that in this example the internal data get
+ recomputed automatically during the undo.
+ </para>
+ <para>
+ Closer examination reveals that performing this undo returns again
+ some undoinfo. This new undo info tells us how to undo the undo!
+ This is the information we need to perform the "redo" operation,
+ the <emphasis>redoinfo</emphasis>.
+ </para>
+ <para>
+ That means, that if we refine the requirements of the tuple of
+ undoinfo just a little bit, we get the "redo" for free:
+ </para>
+ <para>
+ <!-- def --><!-- thtag -->Undoinfo (2)<!-- /thtag -->
+ </para>
+ <para>
+ A tuple <literal>t</literal> is a tuple of undoinfo of an
+ operation, iff <literal>apply(t[0], t[1:])</literal> undoes
+ the operation and returns redoinfo.
+ </para>
+ <!-- /def -->
+ <para>
+ As it turns out, in Skencil at least, this additional demand is
+ trivial to meet.
+ </para>
+ </sect1>
+
+ <sect1 id="undo-combine"><title>Combining Undoinfo</title>
+ <para>
+ The <function>SetFillStyle</function> method of
+ the <classname>Group</classname> class has to return undoinfo that
+ describes how to undo several operations at once. To achieve this,
+ one can define a function <function>UndoList</function> as
+ follows:
+ </para>
+ <para>
+<programlisting>
+def UndoList(infos):
+ undoinfo = map(Undo, infos)
+ undoinfo.reverse()
+ return (UndoList, undoinfo)
+</programlisting>
+ </para>
+ <para>
+ Here, <function>Undo</function> is a function that executes a
+ single undoinfo (defined in <literal>undo.py</literal>).
+ </para>
+ <para>
+ Given a list "<literal>infos</literal>" of
+ undoinfos, <literal>Group.SetFillStyle</literal> can
+ return <literal>(UndoList, infos)</literal>.
+ </para>
+ <para>
+ Calling <function>reverse</function>
+ in <function>UndoList</function> is essential, as some operations
+ must be undone in exactly the reverse order in which they were
+ performed.
+ </para>
+ <para>
+ For more complex cases where several undoinfos have to be executed
+ in a certain order one can easily define similar functions. See
+ for instance <function>UndoAfter</function>
+ in <literal>undo.py</literal>
+ </para>
+ </sect1>
+
+ <sect1 id="undo-api"><title>The Undo API</title>
+ <para>
+ The module <literal>undo.py</literal> implements most functions
+ and classes necessary for handling undo in Skencil.
+ </para>
+ <para>
+ The format for a single unit of undoinfo is as described above
+ with a single extension: The first item in the tuple may be a
+ string, in which case the second item is callable and the items
+ [2:] are the arguments. The string is meant to provide a short
+ description of the operation, such as "Create Rectangle", that may
+ be displayed as a menu item like "Undo Create Rectangle".
+ Therefore, this string is only necessary at the top level undo
+ info, which is currently always created by the document object.
+ </para>
+ <para>
+ The public interface to undo handling in Skencil consists of the
+ following functions and objects which are exported by the
+ package <literal>Sketch</literal>.
+ </para>
+
+ <sect2><title>Constructors</title>
+ <para>
+ In many cases, methods that change graphics objects or are
+ otherwise expected to return undoinfo, simply create a tuple of
+ the correct format.
+ </para>
+ <para>
+ Example: The SetRadius method of the regular polygon Plugin:
+<programlisting>
+def SetRadius(self, radius):
+ undo = self.SetRadius, self.radius # create undoinfo
+ self.radius = radius # set the instance variable
+ self.compute_poly() # update the polygon
+ self._changed() # notify interested objects that self changed,
+ # and force update of bounding rects, etc.
+ return undo # finally, return undo info
+</programlisting>
+ </para>
+ <para>
+ For compound objects and methods that need to combine several
+ pieces of undo info there are two special constructors:
+ </para>
+ <variablelist>
+ <varlistentry id="function-CreateListUndo">
+ <term><function>CreateListUndo(<parameter>infos</parameter>)</function></term>
+ <listitem>
+ <para>
+ Return undo info that combines the undo infos
+ in <parameter>infos</parameter>. <parameter>infos</parameter>
+ is expected to be a sequence of undo infos listed in the
+ order in which the actions were performed. When the
+ operation is undone they are executed in reverse order.
+ </para>
+ <para>
+ <function>CreateListUndo</function> tries to simplify
+ <parameter>infos</parameter>. It builds a new list by
+ iterating over the items of <parameter>infos</parameter>
+ and inlining list undo info (as created by
+ <function>CreateListUndo</function>) and by discarding
+ empty undo info (represented by the
+ <link linkend="NullUndo">NullUndo</link> object, see
+ below). If the resulting list is empty return
+ <literal>NullUndo</literal>.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry id="function-CreateMultiUndo">
+ <term><function>CreateMultiUndo(<parameter>info1</parameter>[, <parameter>info2</parameter>[, ...]])</function></term>
+ <listitem>
+ <para>
+ Return undoinfo that undoes <parameter>info1</parameter>,
+ <parameter>info2</parameter>, etc., in reverse order.
+ This is implemented via <function>CreateListUndo</function>.
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ <para>
+ Sometimes it happens that nothing has to be undone:
+ </para>
+ <variablelist>
+ <varlistentry id="NullUndo">
+ <term><literal>NullUndo</literal></term>
+ <listitem>
+ <para>
+ <literal>NullUndo</literal> is an undo info tuple that
+ does nothing. If a method needs to return undo info, but
+ for some reason nothing needs to be undone, this object
+ should be returned.
+ </para>
+ <para>
+ The functions that combine undo info treat it specially by
+ removing it from the list of undo infos.
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </sect2>
+ </sect1>
+</chapter>
Added: skencil/branches/skencil-0.6/Doc/usersguide/Images/CreateCurve.png
===================================================================
(Binary files differ)
Property changes on: skencil/branches/skencil-0.6/Doc/usersguide/Images/CreateCurve.png
___________________________________________________________________
Name: svn:mime-type
+ image/png
Added: skencil/branches/skencil-0.6/Doc/usersguide/Images/CreateEllipse.png
===================================================================
(Binary files differ)
Property changes on: skencil/branches/skencil-0.6/Doc/usersguide/Images/CreateEllipse.png
___________________________________________________________________
Name: svn:mime-type
+ image/png
Added: skencil/branches/skencil-0.6/Doc/usersguide/Images/CreatePoly.png
===================================================================
(Binary files differ)
Property changes on: skencil/branches/skencil-0.6/Doc/usersguide/Images/CreatePoly.png
___________________________________________________________________
Name: svn:mime-type
+ image/png
Added: skencil/branches/skencil-0.6/Doc/usersguide/Images/CreateRect.png
===================================================================
(Binary files differ)
Property changes on: skencil/branches/skencil-0.6/Doc/usersguide/Images/CreateRect.png
___________________________________________________________________
Name: svn:mime-type
+ image/png
Added: skencil/branches/skencil-0.6/Doc/usersguide/Images/Delete.png
===================================================================
(Binary files differ)
Property changes on: skencil/branches/skencil-0.6/Doc/usersguide/Images/Delete.png
___________________________________________________________________
Name: svn:mime-type
+ image/png
Added: skencil/branches/skencil-0.6/Doc/usersguide/Images/Duplicate.png
===================================================================
(Binary files differ)
Property changes on: skencil/branches/skencil-0.6/Doc/usersguide/Images/Duplicate.png
___________________________________________________________________
Name: svn:mime-type
+ image/png
Added: skencil/branches/skencil-0.6/Doc/usersguide/Images/EditMode.png
===================================================================
(Binary files differ)
Property changes on: skencil/branches/skencil-0.6/Doc/usersguide/Images/EditMode.png
___________________________________________________________________
Name: svn:mime-type
+ image/png
Added: skencil/branches/skencil-0.6/Doc/usersguide/Images/FlipHorizontal.png
===================================================================
(Binary files differ)
Property changes on: skencil/branches/skencil-0.6/Doc/usersguide/Images/FlipHorizontal.png
___________________________________________________________________
Name: svn:mime-type
+ image/png
Added: skencil/branches/skencil-0.6/Doc/usersguide/Images/FlipVertical.png
===================================================================
(Binary files differ)
Property changes on: skencil/branches/skencil-0.6/Doc/usersguide/Images/FlipVertical.png
___________________________________________________________________
Name: svn:mime-type
+ image/png
Added: skencil/branches/skencil-0.6/Doc/usersguide/Images/GridOn.png
===================================================================
(Binary files differ)
Property changes on: skencil/branches/skencil-0.6/Doc/usersguide/Images/GridOn.png
___________________________________________________________________
Name: svn:mime-type
+ image/png
Added: skencil/branches/skencil-0.6/Doc/usersguide/Images/Group.png
===================================================================
(Binary files differ)
Property changes on: skencil/branches/skencil-0.6/Doc/usersguide/Images/Group.png
___________________________________________________________________
Name: svn:mime-type
+ image/png
Added: skencil/branches/skencil-0.6/Doc/usersguide/Images/Image.png
===================================================================
(Binary files differ)
Property changes on: skencil/branches/skencil-0.6/Doc/usersguide/Images/Image.png
___________________________________________________________________
Name: svn:mime-type
+ image/png
Added: skencil/branches/skencil-0.6/Doc/usersguide/Images/MiniEyeClosed.png
===================================================================
(Binary files differ)
Property changes on: skencil/branches/skencil-0.6/Doc/usersguide/Images/MiniEyeClosed.png
___________________________________________________________________
Name: svn:mime-type
+ image/png
Added: skencil/branches/skencil-0.6/Doc/usersguide/Images/MiniEyeOpen.png
===================================================================
(Binary files differ)
Property changes on: skencil/branches/skencil-0.6/Doc/usersguide/Images/MiniEyeOpen.png
___________________________________________________________________
Name: svn:mime-type
+ image/png
Added: skencil/branches/skencil-0.6/Doc/usersguide/Images/MiniPrintOff.png
===================================================================
(Binary files differ)
Property changes on: skencil/branches/skencil-0.6/Doc/usersguide/Images/MiniPrintOff.png
___________________________________________________________________
Name: svn:mime-type
+ image/png
Added: skencil/branches/skencil-0.6/Doc/usersguide/Images/MiniPrintOn.png
===================================================================
(Binary files differ)
Property changes on: skencil/branches/skencil-0.6/Doc/usersguide/Images/MiniPrintOn.png
___________________________________________________________________
Name: svn:mime-type
+ image/png
Added: skencil/branches/skencil-0.6/Doc/usersguide/Images/MoveOneDown.png
===================================================================
(Binary files differ)
Property changes on: skencil/branches/skencil-0.6/Doc/usersguide/Images/MoveOneDown.png
___________________________________________________________________
Name: svn:mime-type
+ image/png
Added: skencil/branches/skencil-0.6/Doc/usersguide/Images/MoveOneUp.png
===================================================================
(Binary files differ)
Property changes on: skencil/branches/skencil-0.6/Doc/usersguide/Images/MoveOneUp.png
___________________________________________________________________
Name: svn:mime-type
+ image/png
Added: skencil/branches/skencil-0.6/Doc/usersguide/Images/MoveToBottom.png
===================================================================
(Binary files differ)
Property changes on: skencil/branches/skencil-0.6/Doc/usersguide/Images/MoveToBottom.png
___________________________________________________________________
Name: svn:mime-type
+ image/png
Added: skencil/branches/skencil-0.6/Doc/usersguide/Images/MoveToTop.png
===================================================================
(Binary files differ)
Property changes on: skencil/branches/skencil-0.6/Doc/usersguide/Images/MoveToTop.png
___________________________________________________________________
Name: svn:mime-type
+ image/png
Added: skencil/branches/skencil-0.6/Doc/usersguide/Images/NewDocument.png
===================================================================
(Binary files differ)
Property changes on: skencil/branches/skencil-0.6/Doc/usersguide/Images/NewDocument.png
___________________________________________________________________
Name: svn:mime-type
+ image/png
Added: skencil/branches/skencil-0.6/Doc/usersguide/Images/Open.png
===================================================================
(Binary files differ)
Property changes on: skencil/branches/skencil-0.6/Doc/usersguide/Images/Open.png
___________________________________________________________________
Name: svn:mime-type
+ image/png
Added: skencil/branches/skencil-0.6/Doc/usersguide/Images/Redo.png
===================================================================
(Binary files differ)
Property changes on: skencil/branches/skencil-0.6/Doc/usersguide/Images/Redo.png
___________________________________________________________________
Name: svn:mime-type
+ image/png
Added: skencil/branches/skencil-0.6/Doc/usersguide/Images/Save.png
===================================================================
(Binary files differ)
Property changes on: skencil/branches/skencil-0.6/Doc/usersguide/Images/Save.png
___________________________________________________________________
Name: svn:mime-type
+ image/png
Added: skencil/branches/skencil-0.6/Doc/usersguide/Images/SelectionMode.png
===================================================================
(Binary files differ)
Property changes on: skencil/branches/skencil-0.6/Doc/usersguide/Images/SelectionMode.png
___________________________________________________________________
Name: svn:mime-type
+ image/png
Added: skencil/branches/skencil-0.6/Doc/usersguide/Images/Text.png
===================================================================
(Binary files differ)
Property changes on: skencil/branches/skencil-0.6/Doc/usersguide/Images/Text.png
___________________________________________________________________
Name: svn:mime-type
+ image/png
Added: skencil/branches/skencil-0.6/Doc/usersguide/Images/Undo.png
===================================================================
(Binary files differ)
Property changes on: skencil/branches/skencil-0.6/Doc/usersguide/Images/Undo.png
___________________________________________________________________
Name: svn:mime-type
+ image/png
Added: skencil/branches/skencil-0.6/Doc/usersguide/Images/Ungroup.png
===================================================================
(Binary files differ)
Property changes on: skencil/branches/skencil-0.6/Doc/usersguide/Images/Ungroup.png
___________________________________________________________________
Name: svn:mime-type
+ image/png
Added: skencil/branches/skencil-0.6/Doc/usersguide/Images/Zoom.png
===================================================================
(Binary files differ)
Property changes on: skencil/branches/skencil-0.6/Doc/usersguide/Images/Zoom.png
___________________________________________________________________
Name: svn:mime-type
+ image/png
Added: skencil/branches/skencil-0.6/Doc/usersguide/Images/arrow-left.png
===================================================================
(Binary files differ)
Property changes on: skencil/branches/skencil-0.6/Doc/usersguide/Images/arrow-left.png
___________________________________________________________________
Name: svn:mime-type
+ image/png
Added: skencil/branches/skencil-0.6/Doc/usersguide/Images/arrow-right.png
===================================================================
(Binary files differ)
Property changes on: skencil/branches/skencil-0.6/Doc/usersguide/Images/arrow-right.png
___________________________________________________________________
Name: svn:mime-type
+ image/png
Added: skencil/branches/skencil-0.6/Doc/usersguide/Images/arrow-up.png
===================================================================
(Binary files differ)
Property changes on: skencil/branches/skencil-0.6/Doc/usersguide/Images/arrow-up.png
___________________________________________________________________
Name: svn:mime-type
+ image/png
Added: skencil/branches/skencil-0.6/Doc/usersguide/Images/bullet.png
===================================================================
(Binary files differ)
Property changes on: skencil/branches/skencil-0.6/Doc/usersguide/Images/bullet.png
___________________________________________________________________
Name: svn:mime-type
+ image/png
Added: skencil/branches/skencil-0.6/Doc/usersguide/Images/gradient-conical.png
===================================================================
(Binary files differ)
Property changes on: skencil/branches/skencil-0.6/Doc/usersguide/Images/gradient-conical.png
___________________________________________________________________
Name: svn:mime-type
+ image/png
Added: skencil/branches/skencil-0.6/Doc/usersguide/Images/gradient-linear.png
===================================================================
(Binary files differ)
Property changes on: skencil/branches/skencil-0.6/Doc/usersguide/Images/gradient-linear.png
___________________________________________________________________
Name: svn:mime-type
+ image/png
Added: skencil/branches/skencil-0.6/Doc/usersguide/Images/gradient-radial.png
===================================================================
(Binary files differ)
Property changes on: skencil/branches/skencil-0.6/Doc/usersguide/Images/gradient-radial.png
___________________________________________________________________
Name: svn:mime-type
+ image/png
Added: skencil/branches/skencil-0.6/Doc/usersguide/Images/layers.png
===================================================================
(Binary files differ)
Property changes on: skencil/branches/skencil-0.6/Doc/usersguide/Images/layers.png
___________________________________________________________________
Name: svn:mime-type
+ image/png
Added: skencil/branches/skencil-0.6/Doc/usersguide/Images/selsize.png
===================================================================
(Binary files differ)
Property changes on: skencil/branches/skencil-0.6/Doc/usersguide/Images/selsize.png
___________________________________________________________________
Name: svn:mime-type
+ image/png
Added: skencil/branches/skencil-0.6/Doc/usersguide/Images/seltrafo.png
===================================================================
(Binary files differ)
Property changes on: skencil/branches/skencil-0.6/Doc/usersguide/Images/seltrafo.png
___________________________________________________________________
Name: svn:mime-type
+ image/png
Added: skencil/branches/skencil-0.6/Doc/usersguide/Images/sketch-logo.png
===================================================================
(Binary files differ)
Property changes on: skencil/branches/skencil-0.6/Doc/usersguide/Images/sketch-logo.png
___________________________________________________________________
Name: svn:mime-type
+ image/png
Added: skencil/branches/skencil-0.6/Doc/usersguide/Images/textpath.png
===================================================================
(Binary files differ)
Property changes on: skencil/branches/skencil-0.6/Doc/usersguide/Images/textpath.png
___________________________________________________________________
Name: svn:mime-type
+ image/png
Added: skencil/branches/skencil-0.6/Doc/usersguide/Images/textpathrot.png
===================================================================
(Binary files differ)
Property changes on: skencil/branches/skencil-0.6/Doc/usersguide/Images/textpathrot.png
___________________________________________________________________
Name: svn:mime-type
+ image/png
Added: skencil/branches/skencil-0.6/Doc/usersguide/Images/textpathskew.png
===================================================================
(Binary files differ)
Property changes on: skencil/branches/skencil-0.6/Doc/usersguide/Images/textpathskew.png
___________________________________________________________________
Name: svn:mime-type
+ image/png
Added: skencil/branches/skencil-0.6/Doc/usersguide/concepts.xml
===================================================================
--- skencil/branches/skencil-0.6/Doc/usersguide/concepts.xml 2006-06-01 15:34:15 UTC (rev 681)
+++ skencil/branches/skencil-0.6/Doc/usersguide/concepts.xml 2006-06-05 18:35:01 UTC (rev 682)
@@ -0,0 +1,313 @@
+<chapter id="concepts"><title>Concepts</title>
+ <para>
+ To use the full potential of Skencil, it is important to know some
+ fundamental concepts, such as the various kinds of objects that make
+ up a drawing and their relationship. This section introduces these
+ concepts and the terminology needed to talk about them. This
+ terminology is also used in the menus, the status bar and other
+ parts of Skencil's user interface.
+ </para>
+
+ <sect1 id="concept-objecttypes"><title>Object Types</title>
+ <para>
+ Skencil has two fundamentally different kinds of
+ objects: <emphasis>primitives</emphasis> and <emphasis>compound
+ objects</emphasis>.
+ </para>
+
+ <sect2 id="concept-primitives"><title>Primitives</title>
+ <para>
+ Primitives are the basic building blocks of a drawing. They are
+ the ones that actually leave marks on the paper. Among this kind
+ of object are the <!-- link
+ linkend="objects-rectangle"-->rectangle, the <!-- link
+ linkend="objects-bezier"-->bézier curve (which also
+ serves as a polygon or even as a straight line) and <!-- link
+ linkend="objects-text"-->text object.
+ </para>
+ <para>
+ Most primitives can have <emphasis>fill properties</emphasis>
+ and <emphasis>line properties</emphasis>. Properties are
+ discussed in more
+ detail <link linkend="concept-properties">below</link>.
+ </para>
+ </sect2>
+
+ <sect2 id="concept-compound"><title>Compound Objects</title>
+ <para>
+ <emphasis>Compound objects</emphasis> group several primitives
+ or other compound objects together into one object. As such,
+ compound objects are invisible, but the primitives contained in
+ them are not. Therefore, compound objects are mainly interesting
+ for editing purposes.
+ </para>
+ <para>
+ It is often convenient to group the primitives that form a
+ distinctive part of a drawing together into
+ a <emphasis><!--link linkend="objects-group"-->group</emphasis>.
+ For instance, in the sample file flags.sk each of the flags is a
+ group of several primitives (often just a few rectangles as many
+ of the flags consist of some stripes). Whenever you click on
+ one of the flags the whole group is selected not just the
+ rectangle you clicked on. Thus, most of the time the group is
+ manipulated as a whole (there are ways to work on the parts of a
+ group without ungrouping them first, but that is an advanced
+ topic).
+ </para>
+ <para>
+ There are some compound objects that behave in a special
+ way. The only example at the moment is the
+ <!--link linkend="objects-blendgroup"-->BlendGroup. This group
+ consists of two (or more) control objects and a number of
+ objects that are linear interpolations of the control
+ objects. When you edit one of the control objects all
+ interpolated objects are updated automatically.
+ </para>
+ </sect2>
+ </sect1>
+
+ <sect1 id="concept-structure"><title>Structure of a Drawing</title>
+ <para>
+ A drawing consists of
+ <link linkend="concept-primitives">primitives</link> organized
+ in <link linkend="concept-compound">compound objects</link>. The
+ entire drawing itself, the <emphasis>document</emphasis>, is a
+ compound object that contains all the others.
+ </para>
+ <para>
+ When speaking about the objects contained in a compound object,
+ it's convenient to use the terms parent and child. The compound
+ object is the <emphasis>parent</emphasis> of the object it
+ contains, the contained objects are the compound object's
+ <emphasis>children</emphasis>.
+ </para>
+ <para>
+ The objects are always drawn in the same order with the objects
+ drawn later obscuring the ones drawn earlier in case of overlap.
+ One might also say that some objects lie on top of each other and
+ that objects are drawn from bottom to top. This is the model we
+ usually use and the reason for menu items such as "Move To Top".
+ </para>
+ <para>
+ The order in which the objects are drawn changes only when the
+ user explicitly chooses a command that does so. Moving an object
+ around or changing the <link linkend="fill-properties">fill
+ properties</link> does not change this order.
+ </para>
+
+ <sect2><title>Layers</title>
+ <para>
+ The top-level compound object,
+ the <emphasis>document</emphasis>, is always divided into
+ <emphasis>layers</emphasis>. Layers are the only kind of
+ children a document can have and the parent of a layer will
+ always be a document.
+ </para>
+ <para>
+ This means that normal objects such as primitives or other types
+ of compound objects are never contained directly in the document
+ object but are always, directly or indirectly, contained in a
+ layer.
+ </para>
+ <para>
+ The layer is a special compound object with some special
+ attributes. These attributes control whether its children are
+ visible or not.
+ </para>
+ </sect2>
+ </sect1>
+
+ <sect1 id="concept-properties"><title>Properties</title>
+ <para>
+ Primitives can have <emphasis>properties</emphasis> that define
+ how they are drawn.
+ </para>
+ <para>
+ <link linkend="fill-properties">Fill properties</link> define how
+ the area defined by a primitive is drawn. Often this is just a
+ single color, but Skencil offers some more variety in the form
+ of <link linkend="patterns">patterns</link>.
+ </para>
+ <para>
+ <link linkend="line-properties">Line properties</link> define how
+ the lines of a primitive are drawn. The most important line
+ properties are probably color, width and dashes.
+ </para>
+ <para>
+ A primitive can usually have both, fill and line properties, but
+ there is no need for a primitive to have any properties. You might
+ just want to draw the outline but not the interior of a rectangle,
+ for instance.
+ </para>
+ <para>
+ Some types of primitives even cannot have fill or line
+ properties. An <!-- link linkend="objects-image"-->image object
+ for instance has neither fill nor line properties and a text
+ object doesn't have a line attribute (currently at least) but has
+ an attribute that defines its font.
+ </para>
+ <para>
+ As an advanced feature, Skencil offers
+ <emphasis><link linkend="dynamic-properties">dynamic
+ properties</link></emphasis>. These allow you to define logical
+ properties touse instead of physical properties. Whenever you
+ change the definition of a dynamic attribute, all objects that use
+ that attribute are automatically updated. This is similar to
+ logical markup versus physical markup in LaTeX or SGML.
+ </para>
+
+ <sect2 id="fill-properties"><title>Fill Properties</title>
+ <para>
+ <emphasis>Fill Properties</emphasis> define how the area of a
+ primitive is filled.
+ </para>
+ <para>
+ The simplest case is just a single color that fills the area
+ uniformly. Skencil offers more variety than that, though, in
+ the form of patterns. A single color is then viewed as a very
+ simple type of pattern.
+ </para>
+ <para>
+ A primitive may have empty fill properties or, phrased
+ differently, no fill properties. In this case the area of the
+ primitive is not changed all and the objects below the primitive
+ are not obscured. Only its line is still drawn if it has line
+ properties.
+ </para>
+
+ <sect3 id="patterns"><title>Patterns</title>
+ <para>
+ Skencil currently offers three kinds of
+ pattern: <link linkend="patterns-solid">solid</link>,
+ <link linkend="patterns-gradient">gradient</link>
+ and <link linkend="patterns-hatching">hatching pattern</link>.
+ </para>
+
+ <sect4 id="patterns-solid"><title>Solid</title>
+ <para>
+ This is the simplest pattern: Just a single color that
+ uniformly fills the area.
+ </para>
+ </sect4>
+
+ <sect4 id="patterns-gradient"><title>Gradient</title>
+ <para>
+ A gradient is the interpolation between two or more
+ colors. A gradient pattern can be either linear, radial or
+ conical.
+ </para>
+ <para>
+ <informaltable>
+ <tgroup cols="3">
+ <tbody>
+ <row>
+ <entry>
+ <inlinegraphic fileref="Images/gradient-linear.png"/>
+ </entry>
+ <entry>
+ <inlinegraphic fileref="Images/gradient-conical.png"/>
+ </entry>
+ <entry>
+ <inlinegraphic fileref="Images/gradient-radial.png"/>
+ </entry>
+ </row>
+ <row>
+ <entry>Linear Gradient</entry>
+ <entry>Conical Gradient</entry>
+ <entry>Radial Gradient</entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </informaltable>
+ </para>
+ </sect4>
+
+ <sect4 id="patterns-hatching"><title>Hatching</title>
+ <para></para>
+ </sect4>
+ </sect3>
+ </sect2>
+
+ <sect2 id="line-properties"><title>Line Properties</title>
+ <para>
+ A primitive may either have no line properties (which means that
+ only its area is filled if it has an area and nonempty fill
+ properties) or one of each of the following properties:
+ <variablelist>
+ <varlistentry>
+ <term>Pattern</term>
+ <listitem>
+ <para>
+ Currently, this can only be a solid color or the empty
+ pattern. An empty pattern means that no line is drawn.
+ Future extensions will probably allow arbitrary
+ patterns.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>Width</term>
+ <listitem>
+ <para>
+ The line width. A width of zero means that the thinnest
+ possible line is drawn.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>Dashes</term>
+ <listitem>
+ <para>
+ Whether to draw a solid line or a dashed line. A line
+ can have arbitrary dash patterns.
+ </para>
+ <para>
+ Dash patterns are represented by a list of numbers such
+ as "5.0, 2.0, 1.0, 2.0". This list describes a pattern
+ of a drawn segment of 5 units long, followed by a gap of
+ 2 units, followed by a drawn segment of 1 unit and
+ finally a gap of 2 units, after which the sequence
+ starts over. The unit used is the line width. This
+ means that a thicker line has longer dashes and gaps.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>Join Style</term>
+ <listitem>
+ <para>
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>Cap Style</term>
+ <listitem>
+ <para>
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>Arrow Heads</term>
+ <listitem>
+ <para>
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </para>
+ </sect2>
+
+ <sect2 id="font-property"><title>Font</title>
+ <para/>
+ </sect2>
+
+ <sect2 id="dynamic-properties"><title>Dynamic Properties</title>
+ <para/>
+ </sect2>
+ </sect1>
+</chapter>
Added: skencil/branches/skencil-0.6/Doc/usersguide/configuration.xml
===================================================================
--- skencil/branches/skencil-0.6/Doc/usersguide/configuration.xml 2006-06-01 15:34:15 UTC (rev 681)
+++ skencil/branches/skencil-0.6/Doc/usersguide/configuration.xml 2006-06-05 18:35:01 UTC (rev 682)
@@ -0,0 +1,209 @@
+<chapter id="configuration"><title>Configuration</title>
+
+ <sect1 id="config-fonts"><title>Fonts</title>
+ <para>
+ Fonts are a somewhat complex matter in Linux and X. Skencil's main
+ output format for printing is PostScript. Because of that, Skencil
+ identifies fonts with their PostScript names and must know how to
+ get the appropriate metrics (these tell Skencil how to place the
+ individual letters for instance) and it must know X's name for the
+ font (to be able to show the text on the screen appropriately).
+ </para>
+ <para>
+ The information Skencil needs to map the PostScript names to
+ metric-filenames (.afm-files) and X font names is stored in
+ .sfd-files.
+ </para>
+
+ <sect2><title>sfd-Files</title>
+ <para>
+ An sfd-file maps font names to the filenames of the afm-files
+ and to various font attributes like weight and width and to two
+ strings that are used to build the font name for X.
+ </para>
+ <para>
+ For example, the line concerning the Courier font in
+ <filename>Resources/Fontmetrics/std.sfd</filename> is:
+ </para>
+ <para>
+<programlisting>
+ Courier,Courier,Roman,-adobe-Courier-medium-r-normal,iso8859-1,pcrr
+</programlisting>
+ </para>
+ <para>
+ This tells Skencil that the metrics file is pcrr.afm and that
+ the first part of the X font name is
+ -adobe-Courier-medium-r-normal and its last part is
+ iso8859-1. The parts missing from the X font name describe the
+ size and transformation which are automatically filled in by
+ Skencil. Skencil assumes that fonts can be arbitrarily scaled
+ and transformed. (The XFree servers often used on Linux have
+ this capability; other servers on other platforms may not)
+ </para>
+ <para>
+ If the font is not installed in the server (either the X-server
+ or the font server), or if it is installed under a different
+ name, Skencil will not be able to display the text.
+ </para>
+ <para>
+ On start-up, Skencil reads all sfd-files it finds in the
+ directories listed in its font-path.
+ </para>
+ </sect2>
+
+ <sect2><title>The font-path</title>
+ <para>
+ Skencil maintains a list of directories where it searches for
+ font-related files like sfd-files and metrics. Note that this
+ is a skencil-specific font-path and has nothing to do with X's
+ font-path.
+ </para>
+ <para>
+ By default (as of version 0.6.2) the font-path consists of the
+ directories <filename>Resources/Fontmetrics</filename> (relative
+ to where Skencil is installed),
+ <filename>/usr/X11R6/lib/X11/fonts/Type1</filename> and
+ <filename>/usr/share/ghostscript/fonts</filename>.
+ </para>
+ <para>
+ If you need to add directories or otherwise modify the
+ font-path, you can do so in Skencil's start-up file,
+ <filename>~/.sketch/userhooks.py</filename>, which is executed
+ by Skencil if it exists. E.g. to add a directory to the
+ font-path you could put this code into
+ <filename>userhooks.py</filename>:
+ </para>
+ <para>
+<programlisting>
+from Sketch import config
+
+config.font_path.append('/usr/local/share/fonts/bitstream')
+</programlisting>
+ </para>
+ <para>
+ In case you're wondering, Skencil was originally called
+ "Sketch", hence the name of the directory and the python module
+ in the above code snippet.
+ </para>
+ </sect2>
+
+ <sect2><title>Adding Fonts</title>
+ <para>
+ If you install new Type 1 fonts on your system for use with
+ Skencil, you have to make them available to X and you have to
+ create an sfd-file for Skencil.
+ </para>
+ <para>
+ The X-specific part of this is described in the usual man-pages,
+ like mkfontdir(1) (for the format of fonts.scale and
+ fonts.alias), xset(1) (for ways to change the fontpath at
+ runtime), Xserver(1) (for general information about the X
+ server, including fonts) and XF86Config(5) (for the default
+ configuration of XFree86).
+ </para>
+ <para>
+ To help with the installation, Skencil comes with a script,
+ mkfontdb.py, that can create both Skencil's sfd-files and X's
+ fonts.scale files. In my opinion it's a good idea to generate
+ both files with mkfontdb.py to make sure the X-font-names in
+ both files match, because Skencil won't be able to display the
+ fonts otherwise.
+ </para>
+ <para>
+ The easiest way to use mkfontdb.py is:
+ </para>
+ <para>
+<programlisting>
+mkfontdb.py <dir>
+</programlisting>
+ </para>
+ <para>
+ When invoked like this, mkfontdb.py reads the afm-files in the
+ directory <dir> and creates the two files fonts.scale and
+ std.sfd in the current directory. For more information about the
+ command line options run 'mkfontdb.py -h'.
+ </para>
+ <para>
+ A good way to install new Type 1 fonts on a Linux-system, in my
+ opinion, is to put the files (pfb/pfa and afm) into a separate
+ directory, e.g. <filename>/usr/local/share/fonts</filename> and
+ create fonts.scale and an sfd file in that directory, and append
+ it to X's font-path and Skencil's font-path.
+ </para>
+ </sect2>
+
+ <sect2><title>Installing Ghostscript's Type1 fonts for X.</title>
+ <para>
+ To use the standard PostScript fonts, I recommend installing the
+ appropriate Type1 fonts from the Ghostscript distribution. They
+ are high quality fonts and distributed under the GPL.
+ </para>
+ <para>
+ The following suggestions and instructions are mainly for
+ XFree86. I don't know in how far these are applicable to other
+ X-servers or other platforms than Linux.
+ </para>
+ <para>
+ <emphasis>WARNING:</emphasis> The following instructions
+ describe how to change the configuration files of XFree86. Be
+ careful and make backup copies of the files you modify so you
+ can restore them if something goes wrong.
+ </para>
+ <para>
+ Copy or symlink the necessary files from Ghostscript's fonts
+ directory to /usr/X11R6/lib/X11/fonts/Type1/ (or wherever you
+ have X). On my system this can be done from the Type1 directory
+ with:
+ </para>
+ <para>
+<programlisting>
+$ ln -s /usr/share/ghostscript/fonts/*l.pfb .
+</programlisting>
+ </para>
+ <para>
+ Append the file <filename>Doc/fonts.scale</filename> to
+ <filename>Type1/fonts.scale</filename>. The first line in the
+ latter file contains a single number. This is the number of
+ fonts listed in that file. Update that number to reflect the
+ changes (if there are no blank lines or comments, this number is
+ the number of lines minus 1)
+ </para>
+ <para>
+ You may have noticed that the font names used in
+ <filename>Doc/fonts.scale</filename> don't match the ones in
+ in <filename>std.sfd</filename>. The reason for this is that
+ fonts you have just installed aren't the original adobe
+ PostScript fonts. Instead, they were contributed to ghostscript
+ by a company called URW. To use the standard PostScript names to
+ refer to these fonts, append
+ <filename>Doc/fonts.alias</filename> to
+ <filename>/usr/X11/lib/X11/fonts/misc/fonts.alias</filename>. There
+ is no number to update here.
+ </para>
+ <para>
+ The file <filename>Doc/fonts.scale</filename> lists
+ Ghostscript's fonts with their own name and not with the name of
+ the Adobe fonts they can replace. The
+ file <filename>Doc/fonts.alias</filename> maps the adobe names
+ to these real names.
+ </para>
+ <para>
+ Now you have to run mkfontdir(1) to update the font database:
+ </para>
+ <para>
+<programlisting>
+$ mkfontdir
+</programlisting>
+ </para>
+ <para>
+ If your X-server is running already you have to tell it to
+ reread the font databases with xset(1):
+ </para>
+ <para>
+<programlisting>
+$ xset fp rehash
+</programlisting>
+ </para>
+ </sect2>
+ </sect1>
+</chapter>
Added: skencil/branches/skencil-0.6/Doc/usersguide/quickint.xml
===================================================================
--- skencil/branches/skencil-0.6/Doc/usersguide/quickint.xml 2006-06-01 15:34:15 UTC (rev 681)
+++ skencil/branches/skencil-0.6/Doc/usersguide/quickint.xml 2006-06-05 18:35:01 UTC (rev 682)
@@ -0,0 +1,889 @@
+<chapter id="quickintro"><title>Quick Overview</title>
+ <para>
+ Since the User's Manual is quite incomplete and even a bit outdated,
+ here is a quick guide to the main features of Skencil.
+ </para>
+
+ <sect1 id="quick-mainwindow"><title>The Main Window</title>
+ <para>
+ There's not much to say about the main window, since many of its
+ components are fairly standard, like
+ the <link linkend="quick-menu">menu and toolbar</link>.
+ </para>
+ <para>
+ The status bar at the bottom indicates the
+ current <link linkend="quick-modes">mode</link>, the current
+ magnification factor, the current position of the mouse pointer
+ (you can change the unit from the context menu) and some
+ information about the current selection.
+ </para>
+ <para>
+ The palette just above the status bar allows you to easily assign
+ a fill color (click the left mouse button) or a line color (middle
+ mouse button). It also has an experimental Drag&Drop facility:
+ click on a color and drag the color to the pattern window in the
+ fill dialog or onto a color button.
+ </para>
+ </sect1>
+
+ <sect1 id="quick-menu"><title>Toolbar/Menu</title>
+ <para>
+ Here's a brief description of some menu commands. If the command
+ is also available as a button in the toolbar, the icon is also
+ shown.
+ </para>
+ <para>
+ Some commands are accessible via key strokes. The key sequence is
+ indicated in the menu. The notation for key strokes is described
+ in the section on <link linkend="quick-keystrokenotation">key
+ strokes</link>.
+ </para>
+
+ <variablelist>
+ <varlistentry><term>File Operations</term>
+ <listitem>
+ <variablelist>
+ <varlistentry>
+ <term><inlinegraphic fileref="Images/Open.png"/> Open</term>
+ <listitem>
+ <para>
+ Load a file into Skencil. Skencil tries to determine
+ the file type automatically. It recognizes its own
+ format, XFig, Adobe Illustrator, CMX (an exchange
+ format defined by Corel), SVG (the upcoming
+ web-standard for vector graphics) and WMF files.
+ </para>
+ <para>
+ The filters for the 'foreign' formats are not
+ complete. The XFig filter for instance has some
+ problems with the ordering of objects (because of the
+ "depth" feature) and ignores arrow heads and dashing.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry><term>Insert Document</term>
+ <listitem>
+ <para>
+ Insert the contents of a document as a group into
+ the current document.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><inlinegraphic fileref="Images/Save.png"/> Save</term>
+ <listitem>
+ <para>
+ Save the current file. If it was read from an
+ SK-file (Skencil's own format) it is saved under the
+ same name after Skencil has created a backup
+ file. If it was not read from a file or the file was
+ not an SK-file, you have to specify a filename. In
+ addition to its own format, Skencil can save
+ drawings in a variety of other file formats
+ including Illustrator, WMF, CGM and SVG.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry><term>Save As PostScript</term>
+ <listitem>
+ <para>
+ Save the current drawing into a PostScript file. The
+ file conforms to the EPS specification.
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry><term>Edit Commands</term>
+ <listitem>
+ <variablelist id="quick-modebuttons">
+ <varlistentry>
+ <term><inlinegraphic fileref="Images/EditMode.png"/>
+ Edit Mode</term>
+ <term><inlinegraphic fileref="Images/SelectionMode.png"/>
+ Selection Mode</term>
+ <listitem>
+ <para>
+ Switch to one of Skencil's major modes,
+ <link linkend="quick-modes"><emphasis>edit
+ mode</emphasis> and <emphasis>selection
+ mode</emphasis></link>.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><inlinegraphic fileref="Images/Undo.png"/> Undo</term>
+ <term><inlinegraphic fileref="Images/Redo.png"/> Redo</term>
+ <listitem>
+ <para>
+ Skencil allows you to undo every operation and
+ maintains a virtually unlimited undo history. If you
+ really want to limit the undo history, you can do so
+ from the
+ <!--link linkend="dialogs-preferences"-->preferences
+ dialog (File/Options...).
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>
+ <inlinegraphic fileref="Images/Delete.png"/> Delete
+ </term>
+ <listitem>
+ <para>
+ Delete the current object.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>
+ <inlinegraphic fileref="Images/Duplicate.png"/> Duplicate
+ </term>
+ <listitem>
+ <para>
+ Create a duplicate of the current object just above
+ the current object and select it. The duplicate is
+ slightly offset. You can set the duplication offset
+ in the
+ <!-- link
+ linkend="dialogs-preferences"-->preferences dialog.
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>Effects</term>
+ <listitem>
+ <variablelist>
+ <varlistentry>
+ <term>
+ <inlinegraphic fileref="Images/FlipHorizontal.png"/>
+ Flip Horizontal
+ </term>
+ <term>
+ <inlinegraphic fileref="Images/FlipVertical.png"/>
+ Flip Vertical
+ </term>
+ <listitem>
+ <para>
+ Flip the current object(s) horizontally (vertically)
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry><term>Remove Transformation</term>
+ <listitem>
+ <para>
+ Some objects have an intrinsic geometry, like text
+ objects, where the geometry is defined by the font
+ and the font size, and bitmap images or EPS
+ files. Any transformations (rotations, reflections,
+ ...) later applied are stored in the object. Remove
+ Transformation reverts these objects to their
+ natural size and orientation.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ </variablelist>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry><term>Rearranging the Stacking Order</term>
+ <listitem>
+ <variablelist>
+ <varlistentry>
+ <term>
+ <inlinegraphic fileref="Images/MoveToTop.png"/>
+ Move To Top
+ </term>
+ <listitem>
+ <para>
+ Move the current object to the top of its layer.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>
+ <inlinegraphic fileref="Images/MoveToBottom.png"/>
+ Move To Bottom
+ </term>
+ <listitem>
+ <para>
+ Move the current object to the bottom of its layer.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>
+ <inlinegraphic fileref="Images/MoveOneUp.png"/>
+ Move One Up
+ </term>
+ <listitem>
+ <para>
+ Swap the current object and the next higher one.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>
+ <inlinegraphic fileref="Images/MoveOneDown.png"/>
+ Move One Down
+ </term>
+ <listitem>
+ <para>
+ Swap the current object and the next lower one.
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry><term>Grouping Objects</term>
+ <listitem>
+ <variablelist>
+ <varlistentry>
+ <term>
+ <inlinegraphic fileref="Images/Group.png"/> Group
+ </term>
+ <listitem>
+ <para>
+ Replace the currently selected objects with a group
+ containing these objects and select it.
+ </para>
+ <para>
+ Grouped objects are usually manipulated as a whole,
+ but if needed, you can
+ <link linkend="quick-selectsubobjects">select
+ individual objects</link> with the mouse or
+ keyboard.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>
+ <inlinegraphic fileref="Images/Ungroup.png"/> Ungroup
+ </term>
+ <listitem>
+ <para>
+ Replace the currently selected group with the
+ objects it contains and select them.
+ </para>
+ <para>
+ While Group creates only normal groups, this command
+ can ungroup other
+ <link linkend="quick-specialgroups">special
+ groups</link> such as
+ <!--link linkend="objects-blendgroup"-->blend
+ groups
+ or <!-- link linkend="objects-maskgroup"-->mask
+ groups as well.
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry><term>Viewing Commands</term>
+ <listitem>
+ <variablelist>
+ <varlistentry>
+ <term><inlinegraphic fileref="Images/Zoom.png"/> Zoom</term>
+ <listitem>
+ <para>
+ After invoking the zoom command you can either
+ <itemizedlist>
+ <listitem>
+ <para>
+ Zoom into a region.
+ </para>
+ <para>
+ Click and drag <Button1> to indicate a
+ rectangular area in the main window. This area
+ will be magnified such that it just fits into
+ the window.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Double the magnification
+ </para>
+ <para>
+ Just click (and don't drag) <Button1> on
+ a point in the main window. This point will be
+ centered and the magnification factor doubled.
+ </para>
+ </listitem>
+ </itemizedlist>
+ </para>
+ <para>
+ The maximum zoom factor is 1600%.
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry><term>Arranging Objects</term>
+ <listitem>
+ <variablelist>
+ <varlistentry><term>Convert To Curve</term>
+ <listitem>
+ <para>
+ Convert the current object to a bézier
+ object. This works for béziers :-),
+ rectangles, ellipses and text. (To convert text to
+ béziers, Skencil must have access to the
+ appropriate type1 font file (either .pfa or pfb)).
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>
+ <inlinegraphic fileref="Images/GridOn.png"/> Snap To Grid
+ </term>
+ <listitem>
+ <para>
+ Turns the grid on (or off, if it's on). If gridding
+ is on, objects will snap to grid points when they
+ are edited.
+ </para>
+ <para>
+ This command doesn't affect the visibility of the
+ grid. The visibility is controlled via
+ the <!--link linkend="dialogs-layers"-->layer
+ dialog. The grid is a special layer which is
+ usually called "Grid".
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry><term>Snap To Objects</term>
+ <listitem>
+ <para>
+ If snapping to objects is active, dragged objects
+ snap to the nearest special point of any other
+ visible object. Special points are the nodes of a
+ <!-- link linkend="objects-bezier"-->bézier
+ curveor the corners of a <!-- link
+ linkend="objects-rectangle"-->rectangle.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry><term>Snap To Guide Lines</term>
+ <listitem>
+ <para>
+ If snapping to guide lines is active, dragged
+ objects snap to the nearest guide line or other
+ objects on the <!-- link
+ linkend="objects-guidelayer"-->guide layer.
+ </para>
+ <para>
+ This command doesn't affect the visibility of the
+ guide lines. The visibility can be controlled from
+ the <!--link linkend="dialogs-layers"-->layer
+ dialog. The guide layer is usually called
+ "Guide Lines".
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry id="quick-create"><term>Creating Objects</term>
+ <listitem>
+ <variablelist>
+ <varlistentry>
+ <term>
+ <inlinegraphic fileref="Images/CreateRect.png"/> Rectangle
+ </term>
+ <listitem>
+ <para>
+ Create a Rectangle by pressing the left mouse button
+ and dragging the mouse. One corner of the newly
+ created rectangle is where the button was pressed,
+ the other where it was released. Holding
+ <Ctrl> while dragging creates a square,
+ holding <Shift> creates a rectangle or square
+ centered on the starting point.
+ </para>
+ <para>
+ In <link linkend="quick-modes"><emphasis>edit
+ mode</emphasis></link>, you can drag the corners
+ of a rectangle to create rounded corners.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>
+ <inlinegraphic fileref="Images/CreateEllipse.png"/>
+ Ellipse
+ </term>
+ <listitem>
+ <para>
+ Create an Ellipse by pressing the left mouse button
+ and dragging the mouse. Holding <Ctrl> while
+ dragging creates a circle, holding <Shift>
+ creates a ellipse or circle centered on the starting
+ point.
+ </para>
+ <para>
+ In <link linkend="quick-modes"><emphasis>edit
+ mode</emphasis></link>, you can drag the handle
+ of an ellipse to create arcs.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>
+ <inlinegraphic fileref="Images/CreateCurve.png"/>
+ Bézier Curve
+ </term>
+ <listitem>
+ <para>
+ Create a Bézier curve. This requires at least
+ two click-drag-release cycles. The first cycle
+ defines the start point of the curve and its
+ tangent. The next cycles define the rest of the
+ points and tangents in the same fashion. Click
+ <Button2> or press Space to finish.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>
+ <inlinegraphic fileref="Images/CreatePoly.png"/> Polygon
+ </term>
+ <listitem>
+ <para>
+ Create a polygon. The first click-drag-release cycle
+ defines the first line segment. The next cycles
+ define the rest of the segments. Click
+ <Button2> or press Space to finish. The object
+ created is actually a Bézier curve consisting
+ only of straight lines.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><inlinegraphic fileref="Images/Text.png"/> Text</term>
+ <listitem>
+ <para>
+ Create a text object by clicking where you want the
+ text to be and type. If you click and drag you
+ create rotated text.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>
+ <inlinegraphic fileref="Images/Image.png"/>
+ Bitmap/EPS images
+ </term>
+ <listitem>
+ <para>
+ This command opens a dialog box to let you specify
+ the image file. After selecting the file, place the
+ image on the page by clicking at the desired
+ position. A dashed rectangle indicates the size and
+ position.
+ </para>
+ <para>
+ Skencil can load any image the Python Imaging
+ Library (PIL) can read. EPS files are not read by
+ the PIL, they are imported and printed
+ unmodified. Skencil uses Ghostscript to render a
+ preview image, so an EPS file looks like an ordinary
+ bitmap image on the screen.
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </sect1>
+
+ <sect1 id="quick-mousekbd"><title>Mouse and keyboard</title>
+
+ <sect2 id="quick-keystrokenotation">
+ <title>Notation of key strokes</title>
+ <para>
+ The notation of key strokes used in this manual and in the
+ menus is very similar to the one used in GNU-Emacs:
+ </para>
+
+ <informaltable>
+ <tgroup cols="2">
+ <thead>
+ <row><entry>Notation</entry><entry>Meaning</entry></row>
+ </thead>
+ <tbody>
+ <row><entry>Space</entry><entry>space</entry></row>
+ <row>
+ <entry>Right, Left, Up, Down</entry>
+ <entry>The cursor keys</entry>
+ </row>
+ <row>
+ <entry>Prev, Next, Home, End</entry>
+ </row>
+ <row>
+ <entry><Shift> <Ctrl> <Meta></entry>
+ <entry>
+ The modifier keys Shift Control and Meta (which may be
+ the Alt key)
+ </entry>
+ </row>
+ <row>
+ <entry><Button1></entry>
+ <entry>The left mouse button</entry>
+ </row>
+ <row>
+ <entry><Button2></entry>
+ <entry>The middle mouse button</entry>
+ </row>
+ <row>
+ <entry><Button3></entry>
+ <entry>The left mouse button</entry>
+ </row>
+ <row>
+ <entry>C-d</entry>
+ <entry>
+ <Ctrl> and lowercase "d", similarly S- for
+ <Shift> and M- for <Meta>
+ </entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </informaltable>
+
+ <para>
+ Unless otherwise noted, "Clicking" means a click with the left
+ mouse button.
+ </para>
+ </sect2>
+
+ <sect2 id="quick-modes"><title>Modes</title>
+ <para>
+ Most of the time, Skencil is on one of two major
+ modes: <emphasis>Selection Mode</emphasis> or <emphasis>Edit
+ Mode</emphasis>. You can switch between these modes with Space
+ or the <link linkend="quick-modebuttons">toolbar</link>.
+ </para>
+ <para>
+ In selection mode, you can select objects
+ and <link linkend="quick-transform">move and transform</link>
+ them as a whole with the mouse. Most commands operate on the
+ currently selected objects (see
+ also <link linkend="quick-mousekbd">Mouse and
+ keyboard</link>). In edit mode, you can edit individual
+ aspects of an object, like the nodes of
+ a <!-- link linkend="objects-bezier"-->bézier curve or
+ the text of a <!-- link linkend="objects-text"-->text object.
+ </para>
+ <para>
+ Sometimes, Skencil is in a temporary minor mode, for instance
+ when selecting a region for zooming, or
+ when <link linkend="quick-create">creating an object</link>.
+ </para>
+ </sect2>
+
+ <sect2><title>Selecting Objects</title>
+ <para>
+ To select...
+
+ <variablelist>
+ <varlistentry>
+ <term>...a single object:</term>
+ <listitem>
+ <para>
+ Click on it. It will become the new currently selected
+ object.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>...multiple objects:</term>
+ <listitem>
+ <para>
+ Click S-<Button1> on an object to add it to the
+ selected objects.
+ </para>
+ <para>
+ Click C-<Button1> on an object to deselect it.
+ </para>
+ <para>
+ You can also select multiple objects by
+ rubberbanding. Click and drag <Button1>, all
+ objects in the dashed rectangle will be
+ selected. Again, holding <Shift> or <Ctrl>
+ add or deselect the indicated objects.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry id="quick-selectsubobjects">
+ <term>...an object in a group:</term>
+ <listitem>
+ <orderedlist>
+ <listitem>
+ <para>Select the group.</para>
+ </listitem>
+ <listitem>
+ <para>
+ Click C-S-<Button1> on the sub-object.
+ </para>
+ </listitem>
+ </orderedlist>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </para>
+
+ <para>
+ You can also use the cursor keys to navigate through the
+ object hierarchy:
+ </para>
+ <para>
+ <informaltable>
+ <tgroup cols="2">
+ <tbody>
+ <row>
+ <entry>M-Right</entry>
+ <entry>Select the next (higher) object</entry>
+ </row>
+ <row>
+ <entry>M-Left</entry>
+ <entry>Select the previous (next lower) object</entry>
+ </row>
+ <row>
+ <entry>M-Down</entry>
+ <entry>
+ Select the first child (sub-object) of the current
+ object
+ </entry>
+ </row>
+ <row>
+ <entry>M-Up</entry>
+ <entry>
+ Select the parent of the current object (if the
+ current object is a sub-object)
+ </entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </informaltable>
+ </para>
+ </sect2>
+
+ <sect2 id="quick-transform"><title>Manipulating Objects</title>
+ <para>
+ If you're in selection mode and you've just selected an
+ object, Skencil indicates this with 8
+ rectangular <emphasis>handles</emphasis> around the object:
+ </para>
+ <para>
+ <inlinegraphic fileref="Images/selsize.png"/>
+ </para>
+ <para>
+ Clicking on a handle and dragging it will resize the
+ object. Just clicking on the object and dragging the object,
+ moves the object. Holding <Ctrl> while dragging
+ constrains the resize and move operations.
+ </para>
+ <para>
+ A single click (and no drag) on the object switches to
+ transformation mode:
+ </para>
+ <para>
+ <inlinegraphic fileref="Images/seltrafo.png"/>
+ </para>
+ <para>
+ Another single click switches back to the resize mode.
+ </para>
+ </sect2>
+ </sect1>
+
+
+ <sect1 id="quick-objecttypes"><title>Object Types</title>
+
+ <sect2 id="quick-specialgroups"><title>Special Effects</title>
+ <para>
+ Skencil currently has three special effects groups:
+ </para>
+
+ <sect3>
+ <title>Blend Groups</title>
+ <para>
+ To create a blend group:
+ <orderedlist>
+ <listitem>
+ <para>select the two objects you want to blend</para>
+ </listitem>
+ <listitem>
+ <para>open the blend panel (Effects/Blend...)</para>
+ </listitem>
+ <listitem>
+ <para>set the number of steps</para>
+ </listitem>
+ <listitem>
+ <para>and press the Apply-button</para>
+ </listitem>
+ </orderedlist>
+ </para>
+ <para>
+ If you later edit one of the control objects, the blend
+ group will be updated automatically.
+ </para>
+ <para>
+ For optimal results, the objects should have a similar
+ structure: bézier curves with the same number of
+ nodes, groups with the same number of sub objects, etc.
+ </para>
+ <para>
+ To create a blend group with more than two control objects,
+ select the start or end object of an existing blend group
+ and the new control object and press apply in the blend
+ panel.
+ </para>
+ <para>
+ It's a little awkward to change the number of steps in an
+ interpolation with the blend panel if the blend group has
+ more than two control objects (and therefore more than one
+ interpolation). In that case, you have to select the
+ interpolation itself by holding <Ctrl> and
+ <Shift> while clicking on it.
+ </para>
+ </sect3>
+
+ <sect3><title>Mask Groups</title>
+ <para>
+ A mask group is a special group where one object defines a
+ clip mask for the rest of the group. If this object is
+ e.g. an ellipse, all that is drawn of the other objects are
+ the parts that overlap the ellipse.
+ </para>
+ <para>
+ To create a mask group
+ <orderedlist>
+ <listitem>
+ <para>Select the mask.</para>
+ </listitem>
+ <listitem>
+ <para>Invoke Arrange/Move To Top</para>
+ </listitem>
+ <listitem>
+ <para>Add the other objects to the selection.</para>
+ </listitem>
+ <listitem>
+ <para>
+ Create the mask group via the menu Effects/Create Mask
+ Group
+ </para>
+ </listitem>
+ </orderedlist>
+ </para>
+ <para>
+ Note: The <emphasis>topmost</emphasis> of the selected
+ objects will become the mask, regardless of the order in
+ which you select them. (In versions prior to 0.5.3 it was
+ the lowest object)
+ </para>
+ <para>
+ If you want to edit the mask you can select it via the
+ context menu (<Button3>).
+ </para>
+ <para>
+ The mask has to be
+ a <!-- link linkend="objects-rectangle" -->rectangle,
+ an <!-- link linkend="objects-ellipse" -->ellipse,
+ a <!-- link linkend="objects-bezier" -->bézier curve
+ or an <!-- link linkend="objects-image" -->image.
+ </para>
+ </sect3>
+
+ <sect3><title>Text on a Curve</title>
+ <para>
+ In Skencil, you can align text along a curve:
+ <informaltable frame="none">
+ <tgroup cols="2">
+ <colspec colname="1" />
+ <colspec colname="2" />
+ <tbody>
+ <row>
+ <entry>
+ <inlinegraphic fileref="Images/textpathrot.png"/>
+ </entry>
+ <entry>
+ <inlinegraphic fileref="Images/textpathskew.png"/>
+ </entry>
+ </row>
+ <row>
+ <entry namest="1" nameend="2">
+ Text on a path can have either rotated letters
+ (left) or skewed letters (right).
+ </entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </informaltable>
+ </para>
+
+ <para>
+ To create this
+ <orderedlist>
+ <listitem>
+ <para>
+ Select a text object and a curve
+ (a <!-- link linkend="objects-bezier"-->bézier
+ curve, an
+ <!-- link linkend="objects-ellipse"-->ellipse or
+ a <!-- link linkend="objects-rectangle"-->rectangle)
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>Choose Effects/Create Path Text from the menu.</para>
+ </listitem>
+ </orderedlist>
+ </para>
+
+ <para>
+ To edit either the text object or the curve individually,
+ select it via the context menu if the whole group is
+ selected.
+ </para>
+ <para>
+ This way, you can hide the curves by assigning empty fill
+ and line patterns.
+ </para>
+ </sect3>
+ </sect2>
+ </sect1>
+</chapter>
Added: skencil/branches/skencil-0.6/Doc/usersguide/scripting.xml
===================================================================
--- skencil/branches/skencil-0.6/Doc/usersguide/scripting.xml 2006-06-01 15:34:15 UTC (rev 681)
+++ skencil/branches/skencil-0.6/Doc/usersguide/scripting.xml 2006-06-05 18:35:01 UTC (rev 682)
@@ -0,0 +1,923 @@
+<chapter id="script"><title>User Scripting</title>
+ <para>
+ Skencil lets you write scripts to automate tasks and add new
+ functionality. The programming language for these scripts is Python,
+ an interpreted, object oriented language.
+ </para>
+ <para>
+ This chapter explains how to write such scripts and how they end up
+ in the Scripts menu, so that you can invoke them. I'll assume that
+ you already know how to program in Python. If you don't know that
+ yet, have a look at <ulink url="http://www.python.org">Python's
+ web-page</ulink> for online documentation.
+ </para>
+ <para>
+ Some parts of this feature are still experimental and may change
+ substantially in newer releases, so watch the NEWS file and the
+ sample scripts in case this documentation is outdated.
+ </para>
+ <para>
+ Skencil itself is implemented almost completely in Python, so your
+ scripts have access to all areas of the application, including
+ internal data structures. This makes user scripts very powerful, but
+ it also means that they can mess around with Skencil's internals
+ with the result that Skencil might not be able to undo the changes
+ or even save the document. But don't worry, evading the traps is not
+ that difficult (I think) and this chapter tries to explain how to
+ avoid them.
+ </para>
+
+ <sect1 id="script-intro"><title>Introduction</title>
+
+ <sect2><title>Safe and Advanced Scripts</title>
+ <para>
+ As mentioned above user scripts in Skencil can cause data
+ loss. To make things easier for you in this regard, Skencil
+ supports two kinds of user scripts, <emphasis>safe
+ scripts</emphasis> and <emphasis>advanced scripts</emphasis>.
+ </para>
+ <para id="safe-script">
+ Safe scripts take care of undo handling for you and they
+ restrict what your script can actually do to keep you from
+ harm. The disadvantage of this approach is that you can't do
+ everything you might want to do with a safe script.
+ </para>
+ <para id="advanced-script">
+ The advanced script has no restrictions but it has to take care
+ of undo handling itself, which isn't difficult but has to be
+ done with care.
+ </para>
+ </sect2>
+
+ <sect2><title>The Script Function</title>
+ <para>
+ Regardless of whether a script is a safe script or an advanced
+ script it is just a Python function that accepts a context
+ object as parameter. The context is an instance with three
+ attributes:
+ </para>
+
+ <variablelist>
+ <varlistentry><term><literal>document</literal></term>
+ <listitem>
+ <para>The document for which the script was called.</para>
+ <para>
+ The document contains all objects that make up the drawing
+ and it manages the selection.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry><term><literal>application</literal></term>
+ <listitem>
+ <para>The application object.</para>
+ <para>
+ The application object has methods for setting and
+ retrieving the application's clipboard and to pop-up
+ message boxes and file dialogs.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry><term><literal>main_window</literal></term>
+ <listitem>
+ <para>
+ The top-level window containing the canvas widget that
+ shows the current drawing. It has methods for loading and
+ saving documents, among others.
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+
+ <para>
+ A simple 'hello world' type script might look like this:
+
+<programlisting>
+def hello_world(context):
+ context.application.MessageBox(title = "My Script",
+ message = "Hello World!")
+</programlisting>
+ </para>
+ </sect2>
+
+ <sect2><title>Registering Scripts</title>
+ <para>
+ The Script menu just shows all the scripts in
+ the <emphasis>script registry</emphasis>, so to have a script
+ appear in that menu, you have to put it into the registry.
+ </para>
+
+ <para>
+ The registry is managed in a subpackage Scripting of the
+ toplevel package Sketch (The name of the package is a leftover
+ from the time Skencil was called "Sketch", in case you're
+ wondering). The function needed here
+ is <function>AddFunction</function> and is called like this:
+ </para>
+
+ <para>
+ <function>AddFunction(<parameter>name</parameter>, <parameter>title</parameter>, <parameter>function</parameter>)</function>
+ </para>
+
+ <variablelist>
+ <varlistentry><term><parameter>name</parameter></term>
+ <listitem>
+ <para>
+ is a name for that script. This name should be unique, as
+ the scripts are identified in the registry by this
+ name. It doesn't have to be the same as the function name.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry><term><parameter>title</parameter></term>
+ <listitem>
+ <para>The text of the menu entry.</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry><term><parameter>function</parameter></term>
+ <listitem>
+ <para>
+ the function that implements the script, e.g. hello_world
+ above.
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+
+ <para>
+ There are a few optional keyword arguments, one of which is
+ type. The value of script_type must be either SafeScript (the
+ default) or AdvancedScript. Both values are defined in the
+ Scripting subpackage. The registry functions are covered in more
+ detail in the <link linkend="script-registry">script
+ registry</link> section.
+ </para>
+ <para>
+ As an example, registering the hello world script might look
+ like this:
+<programlisting>
+import Sketch.Scripting
+Sketch.Scripting.AddFunction("hello_world", "Hello World", hello_world)
+</programlisting>
+ </para>
+ <para>
+ First we import the package Sketch.Scripting and then we call
+ the AddFunction function.
+ </para>
+ <para>
+ For more information about the organization of Skencil's code
+ have a look at the <link linkend="script-skencilapi">API
+ overview</link>.
+ </para>
+ </sect2>
+
+ <sect2><title>The Startup Script</title>
+ <para>
+ The only thing left to do is to get some user supplied code to
+ run on startup, so it can define and register scripts. To do
+ that just create a file <filename>userhooks.py</filename> in the
+ directory <filename>~/.sketch/</filename>. If such a file exists
+ it is automatically executed when Skencil starts. More
+ precisely, the directory <filename>~/.sketch/</filename> is
+ inserted at the front of Python's modules search path and a
+ module <filename>userhooks.py</filename> is imported.
+ </para>
+ <para>
+ You can put arbitrary code in there not just scripts, but one
+ way to implement and register our hello_world script would be a
+ <filename>userhooks.py</filename> file like this:
+ </para>
+ <para>
+<programlisting>
+# example for ~/.sketch/userhooks.py
+
+def hello_world(context):
+context.application.MessageBox(title = "My Script",
+ message = "Hello World!")
+
+# register script
+import Sketch.Scripting
+Sketch.Scripting.AddFunction("hello_world", "Hello World", hello_world)
+</programlisting>
+ </para>
+ </sect2>
+ </sect1>
+
+ <sect1 id="script-examplescripts"><title>The Example Scripts</title>
+ <para>
+ Skencil comes with a few example scripts in
+ the <filename>Scripts/</filename> directory. This directory works
+ as a Python package, so to import a script,
+ say <filename>abut_horizontal.py</filename> just execute import
+ Script.abut_horizontal in <filename>userhooks.py</filename>.
+ </para>
+ <para>
+ Each of the modules in <filename>Script/</filename> contains one
+ script and registers this script when it is imported.
+ </para>
+ </sect1>
+
+ <sect1 id="script-registry"><title>The Script Registry</title>
+ <para>
+ The script registry contains all user scripts and its contents are
+ used to create the Script menu. The script registry is implemented
+ in the (sub-)package Sketch.Scripting. Because the Scripting
+ package is not automatically imported by the Sketch package, you
+ have to import Sketch.Scripting explicitly before accessing the
+ registry functions.
+ </para>
+ <para>
+ Functions in the registry package:
+ </para>
+
+ <variablelist>
+ <varlistentry id="function-AddFunction">
+ <term>
+ <function>AddFunction(<parameter>name</parameter>, <parameter>title</parameter>, <parameter>function</parameter>[, <parameter>kwargs</parameter>])</function>
+ </term>
+ <listitem>
+ <para>
+ Add the function function to the registry under the name
+ name. name is used internally to identify the script and
+ should be unique.
+ </para>
+ <para>
+ The parameter <parameter>title</parameter> defines the text
+ for the menu-entry.
+ </para>
+ <para>
+ The function accepts these optional keyword arguments:
+ </para>
+
+ <variablelist>
+ <varlistentry>
+ <term>
+ <parameter>script_type</parameter> = <parameter>type</parameter>
+ </term>
+ <listitem>
+ <para>
+ The type of the script. It can be either
+ <literal>SafeScript</literal>
+ or <literal>AdvancedScript</literal>. Both values
+ are defined in the <literal>Scripting</literal>
+ package. The default is
+ <literal>SafeScript</literal>.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>
+ <parameter>menu</parameter> = <parameter>menu_spec</parameter>
+ </term>
+ <listitem>
+ <para>
+ Defines the sub-menu the script should appear
+ in. The <parameter>menu_spec</parameter> can be either
+ a string or a tuple of strings. Each string is the
+ title of a sub-menu.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>
+ <parameter>args</parameter> = <parameter>argtuple</parameter>
+ </term>
+ <listitem>
+ <para>
+ Defines additional positional parameters passed to the
+ script function after the context parameter.
+ <parameter>argtuple</parameter> must be a tuple
+ containing these arguments. It defaults to the empty
+ tuple.
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+
+ <para>
+ Example: Registering the <function>abut_horizontal</function>
+ script in the sub-menu "Arrange"
+ </para>
+ <para>
+<programlisting>
+Sketch.Scripting.AddFunction('abut_horizontal', 'Abut Horizontal',
+ abut_horizontal, menu = 'Arrange')
+</programlisting>
+ </para>
+ </sect1>
+
+ <sect1 id="script-skencilapi"><title>Skencil's API</title>
+ <para>
+ If you want to write scripts for Skencil you have to know how to
+ access the objects in the document and how to manipulate
+ them. This section gives a brief introduction to the structure of
+ Skencil's modules and objects from script author's point of view.
+ </para>
+ <para>
+ A more detailed description of Skencil's internals can be found in
+ the Developer's Guide.
+ </para>
+
+ <sect2><title>Module Structure</title>
+ <para>
+ Skencil's code is organized in a hierarchy of packages. The
+ top-level package that contains all of Skencil's core components
+ is <literal>Sketch</literal>. It directly contains references
+ to most of Skencil's graphics classes and functions.
+ </para>
+ </sect2>
+
+ <sect2><title>Conventions</title>
+ <para>
+ Skencil's objects have methods that are meant for public use and
+ methods for internal purposes. Naturally, a script is expected
+ to only use the public interface. Since Python has no builtin
+ distinction between public and private/protected methods we have
+ to rely on conventions.
+ </para>
+ <para>
+ Skencil uses a naming convention for this. Methods with
+ capitalized names, e.g. <function>SetRadius</function>, are
+ public methods and Methods with lowercase name,
+ e.g. <function>set_radius</function>, are protected.
+ </para>
+ </sect2>
+
+ <sect2><title>Undo Handling</title>
+ <para>
+ As pointed out above, advanced scripts have to deal with undo
+ information. This isn't difficult, but you have to know which
+ methods return undo information and what you have to do with it.
+ </para>
+ <para>
+ You only have to deal with undo info if you modify an object
+ that is part of a document. These objects include instances of
+ classes derived from <classname>GraphicsObject</classname>
+ (<!-- href ID=devguide at ClassHierararchy -->class hierarchy) and
+ the objects that define the properties of a graphics object,
+ like patterns.
+ </para>
+ <para>
+ All methods that modify such an object return an undo info
+ object. What this object looks like is irrelevant here, all you
+ need to know for now is that you have to pass it immediately on
+ to the document method <function>AddUndo</function>.
+ </para>
+ <para>
+ A typical example:
+<programlisting>
+context.document.AddUndo(object.Translate(offset))
+</programlisting>
+ </para>
+ <para>
+ The <!-- methref --><function>Translate</function> method
+ translates an object by offset, a
+ <!-- href ID=devguide at PointObject -->point object that stands
+ for a 2D-vector.
+ </para>
+ <para>
+ There are some exceptions to the rule that methods that modify
+ the document return undo info.
+ </para>
+ <para>
+ Firstly, the document methods that modify the selection, that
+ is, that modify which objects are selected not the selected
+ objects themselves, don't return undo info because changing the
+ selection is not considered changing the document.
+ </para>
+ <para>
+ Secondly, public document methods that modify the selected
+ objects themselves already take care of undo info
+ themselves. The reason for this is that they are called directly
+ as a result of a menu command, button or key-press event.
+ </para>
+ <para>
+ For more information about undo information in Skencil, have a
+ look at the <!-- href ID=devguide at UndoMechanism -->corresponding
+ section in the Developer's Guide.
+ </para>
+ </sect2>
+
+ <sect2><title>Further Information</title>
+ <para>
+ The example scripts in the <filename>Script</filename> directory
+ contain extensive comments on what's going on.
+ </para>
+ <para>
+ The Developer's Guide covers Skencil's internals in more
+ detail. Although it's incomplete it already contains a lot of
+ information about the structure of Skencil's sources, the class
+ hierarchy and some of the base classes, coordinate systems,
+ plugins and more.
+ </para>
+ <para>
+ And, of course: Use The Source, Luke!
+ </para>
+ </sect2>
+ </sect1>
+
+ <sect1 id="script-tasks"><title>Common Tasks</title>
+ <para>
+ Unless otherwise noted, all functions and classes mentioned here
+ are directly accessible from the Sketch package. E.g. the
+ function <function>CreateRGBColor</function> is accessible either
+ with:
+<programlisting>
+import Sketch
+
+blue = Sketch.CreateRGBColor(0, 0, 1)
+</programlisting>
+ </para>
+ <para>
+ or
+ </para>
+ <para>
+<programlisting>
+from Sketch import CreateRGBColor
+
+blue = CreateRGBColor(0, 0, 1)
+</programlisting>
+ </para>
+
+ <sect2><title>Creating Objects</title>
+ <para>
+ Creating new objects for a drawing, usually takes three steps:
+ </para>
+ <orderedlist>
+ <listitem>
+ <para>
+ Create the object. This is described in this section.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Set graphics properties like fill color or line width. This
+ is described
+ <link linkend="script:changingproperties">below</link>.
+ </para>
+ </listitem>
+ <listitem>
+ <para>Insert the object into the document</para>
+ </listitem>
+ </orderedlist>
+
+ <sect3><title>Primitives</title>
+ <sect4><title>Rectangles</title>
+ <para>
+ <function>Rectangle(<parameter>trafo</parameter>)</function>
+ </para>
+ <para>
+ This function creates a rectangle object described by
+ <parameter>trafo</parameter>. <parameter>trafo</parameter>
+ is an affine transformation (represented by a <!-- href
+ ID=devguide at TrafoObject -->a transformation object that
+ transforms the unit square into the desired rectangle.
+ </para>
+ <para>
+ Transformation objects are created by the
+ functions <function>Trafo</function>, <function>Scale</function>,
+ <function>Rotation</function>
+ and <function>Translation</function>.
+ </para>
+ <para>
+ In the most common case where you want to create a rectangle
+ with a specific width and height at a specific position (x, y)
+ (the position of the lower left corner of the rectangle)
+ and edges parallel to the edges of the page, you could
+ create the rectangle like this:
+ </para>
+ <para>
+<programlisting>
+Rectangle(Trafo(width, 0, 0, height, x, y))
+</programlisting>
+ </para>
+ <para>
+ or like this
+ </para>
+ <para>
+<programlisting>
+Rectangle(Translation(x, y)(Scale(width, height)))
+</programlisting>
+ </para>
+ </sect4>
+
+ <sect4><title>Lines and Curves</title>
+ <para>
+ All line and curve-objects in Skencil are instances of the
+ class <!-- classref --><classname>PolyBezier</classname>.
+ Each <classname>PolyBezier</classname> object consists of
+ one or more paths with each path consisting of one or more
+ line or bézier segments.
+ </para>
+ <para>
+ To create a <classname>PolyBezier</classname> object you
+ have to first create the paths and then
+ the <classname>PolyBezier</classname> instance. A path is
+ created by starting with an empty path returned by the
+ function <!-- funcref --><function>CreatePath</function> and
+ then appending line- and curve-segments to construct the
+ path. How paths are constructed is covered in detail in
+ the <!-- href ID=devguide at CurveObject -->corresponding
+ section in the developer's guide.
+ </para>
+ <para>
+ Once you have constructed your paths, you create the
+ <classname>PolyBezier</classname> instance with:
+ </para>
+ <para>
+ <literal>PolyBezier(<parameter>path_tuple</parameter>)</literal>
+ </para>
+ <para>
+ The argument <parameter>path_tuple</parameter> must be a
+ tuple of paths. If you have just one path path, you can use
+ the expression <literal>(path,)</literal>.
+ </para>
+ <para>
+ For an example, see the sample script
+ <filename>create_star.py</filename>.
+ </para>
+ </sect4>
+
+ <sect4><title>Text</title>
+ <para>
+ Skencil's text capabilities are still very simple. A text
+ object consists of just one line of text in one font and
+ size, hence the class is called
+ <classname>SimpleText</classname>:
+ </para>
+ <para>
+ <literal>SimpleText(<parameter>trafo</parameter>, <parameter>text</parameter>)</literal>
+ </para>
+ <para>
+ Create a simple text object with the text
+ string <parameter>text</parameter>. The position and
+ orientation is given by <parameter>trafo</parameter>,
+ a <!-- href ID=devguide at TrafoObject -->a transformation
+ object.
+ </para>
+ <para>
+ For an example, see the sample scripts
+ <filename>create_text.py</filename>.
+ </para>
+ </sect4>
+ </sect3>
+
+ <sect3><title>Compound Objects</title>
+
+ <sect4><title>Groups</title>
+ <para>
+ Creating a normal group is very simple. First, you have to
+ construct a list of the objects to be contained in the
+ group. Then you just call the constructor:
+ </para>
+ <para>
+ <literal>Group(<parameter>children</parameter>)</literal>
+ </para>
+ <para>
+ Create a group object with the objects in the list
+ <parameter>children</parameter> as children. The children
+ must not be contained in a document.
+ </para>
+ <para>
+ If you want to create a group of objects that are already
+ contained in the document, the easiest way is to make sure
+ those objects are selected and then to call the document
+ method <function>GroupSelected</function>. Like all
+ document methods this method takes care of undo itself.
+ </para>
+ </sect4>
+ </sect3>
+
+ <sect3><title>Inserting the Object into the Document</title>
+ <para>
+ You can insert an object into the document with this document
+ method:
+ </para>
+ <variablelist>
+ <varlistentry>
+ <term>
+ <function>Insert(<parameter>object</parameter>)</function>
+ </term>
+ <listitem>
+ <para>
+ Insert the object <parameter>object</parameter> into the
+ document. The object becomes the topmost object in the
+ current layer. The selection is set to just this object.
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </sect3>
+ </sect2>
+
+ <sect2>
+ <title>Manipulating Objects</title>
+ <para>
+ Once you have created a graphics object or you have a reference
+ to an object in the document, perhaps from the selection, you
+ can manipulate them in various ways. All methods that modify an
+ object in place return undo information which you have to pass
+ to the document's <function>AddUndo</function> method if your
+ script isan <link linkend="advanced-script">advanced
+ script</link>.
+ </para>
+
+ <sect3><title>Transformations</title>
+ <para>
+ Objects have two methods that allow you move and transform
+ them.
+ </para>
+ <para>
+ <function>Translate(<parameter>offset</parameter>)</function>
+ </para>
+ <para>
+ Move the object by <parameter>offset</parameter>.
+ <parameter>offset</parameter> must be a <!-- href
+ ID=devguide at PointObject -->point object. For an example, see
+ the sample scripts
+ <filename>abut_horizontal.py</filename> and
+ <filename>abut_vertical.py</filename>.
+ </para>
+
+ <para>
+ <function>Transform(<parameter>trafo</parameter>)</function>
+ </para>
+ <para>
+ Apply the affine transformation <parameter>trafo</parameter>
+ to the object.
+ </para>
+ </sect3>
+
+ <sect3 id="script:changingproperties">
+ <title>Changing Object Properties</title>
+ <para>
+ Properties define how an object looks, i.e. they define the
+ fill and line styles and fonts.
+ </para>
+ <para>
+ The fill is defined by a pattern object. There are several
+ kinds of pattern types:
+ </para>
+
+ <variablelist>
+ <varlistentry><term><literal>EmptyPattern</literal></term>
+ <listitem>
+ <para>
+ The <parameter>EmptyPattern</parameter> is a predefined
+ object that means the object is not filled.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>
+ <literal>SolidPattern(<parameter>color</parameter>)</literal>
+ </term>
+ <listitem>
+ <para>
+ Return a solid pattern object for color
+ <parameter>color</parameter>. The solid pattern fills
+ the object uniformly.
+ </para>
+ <para>
+ color has to be a color object which can be created with
+ the following function:
+ </para>
+ <para>
+ <function>CreateRGBColor(<parameter>red</parameter>, <parameter>green</parameter>, <parameter>blue</parameter>)</function>
+ </para>
+ <para>
+ which returns a color object for the color given by the
+ RGB components <parameter>red</parameter>,
+ <parameter>green</parameter>, <parameter>blue</parameter>
+ which are floats in the range 0 - 1.
+ </para>
+ <para>
+ There are also some predefined color objects for some
+ standard colors. They are attributes of the
+ <literal>StandardColors</literal> object,
+ e.g. <literal>StandardColors.blue</literal> is blue.
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+
+ <para>
+ There are more pattern like gradients which I haven't
+ documented yet.
+ </para>
+ <para>
+ To set the properties of an object, call this method
+ </para>
+ <variablelist>
+ <varlistentry>
+ <term>
+ <function>SetProperties(<parameter>keyword_arguments</parameter>)</function>
+ </term>
+ <listitem>
+ <para>
+ Set the properties described by the keyword arguments
+ and return undo information. The accepted keyword
+ arguments are
+ </para>
+
+ <variablelist>
+ <varlistentry>
+ <term><parameter>fill_pattern</parameter></term>
+ <listitem>
+ <para>
+ The fill pattern. It can be of any pattern type.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><parameter>fill_transform</parameter></term>
+ <listitem>
+ <para>
+ A boolean (i.e. 0 or 1) that defines whether the
+ pattern is transformed as well if the object is
+ transformed.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><parameter>line_pattern</parameter></term>
+ <listitem>
+ <para>
+ The pattern for the outline. Must be either
+ <literal>EmptyPattern</literal> or a
+ <classname>SolidPattern</classname>. If it's
+ <literal>EmptyPattern</literal>, no outline is drawn.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><parameter>line_width</parameter></term>
+ <listitem>
+ <para>The line width as a float in pt.</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><parameter>line_cap</parameter></term>
+ <listitem>
+ <para>
+ The cap style. One of <literal>CapButt</literal>,
+ <literal>CapRound</literal>
+ or <literal>CapProjecting</literal>. These
+ constants are defined in
+ <literal>Sketch.const</literal>
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><parameter>line_join</parameter></term>
+ <listitem>
+ <para>
+ The join style. One of <literal>JoinMiter</literal>,
+ <literal>JoinRound</literal> or
+ <literal>JoinBevel</literal>. These constants
+ are defined in <literal>Sketch.const</literal>
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><parameter>line_dashes</parameter></term>
+ <listitem>
+ <para>
+ The dash-pattern as a tuple of floats. The items
+ of the tuple define the dashes and gaps terms of
+ the line-width. The number of items in the tuple
+ should be even.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><parameter>line_arrow1</parameter></term>
+ <term><parameter>line_arrow2</parameter></term>
+ <listitem>
+ <para>
+ The arrow heads. Arrow heads are objects you can
+ create with the function <function>Arrow</function>.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><parameter>font</parameter></term>
+ <listitem>
+ <para>
+ The font for a text object. The value must be a
+ font object which you can get with the function
+ <function>GetFont(<parameter>name</parameter>)</function>
+ where name is the PostScript-name of the font.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><parameter>font_size</parameter></term>
+ <listitem>
+ <para>The size of the font in pt.</para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </sect3>
+ </sect2>
+
+ <sect2><title>Managing the Selection</title>
+ <para>
+ In Skencil 0.6.x, the selection is managed by the document
+ object. You can use these document methods to query and change
+ the selection:
+ </para>
+
+ <variablelist>
+ <varlistentry>
+ <term><function>HasSelection()</function></term>
+ <listitem>
+ <para>Return true if the selection is not empty.</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry><term><function>CountSelected()</function></term>
+ <listitem>
+ <para>Return the number of selected objects.</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry><term><function>SelectedObjects()</function></term>
+ <listitem>
+ <para>
+ Return a list containing the currently selected objects.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry><term><function>CurrentObject()</function></term>
+ <listitem>
+ <para>
+ Return the currently selected object if exactly one object
+ is selected, return <literal>None</literal> otherwise.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry><term><function>SelectNone()</function></term>
+ <listitem>
+ <para>Make the selection empty.</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>
+ <function>SelectObject(<parameter>object</parameter>[, <parameter>mode</parameter>])</function>
+ </term>
+ <listitem>
+ <para>
+ If <parameter>mode</parameter> is
+ <literal>SelectSet</literal>, make object the selected
+ object, otherwise, if mode is
+ <literal>SelectAdd</literal>, add object to the
+ selection. <parameter>mode</parameter>
+ defaults <literal>to</literal> SelectSet.
+ </para>
+ <para>
+ <parameter>object</parameter> may be a single object or a
+ list of objects.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>
+ <function>DeselectObject(<parameter>object</parameter>)</function>
+ </term>
+ <listitem>
+ <para>
+ Remove <parameter>object</parameter> from the selection.
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+
+ </sect2>
+ </sect1>
+</chapter>
Added: skencil/branches/skencil-0.6/Doc/usersguide/usersguide.xml
===================================================================
--- skencil/branches/skencil-0.6/Doc/usersguide/usersguide.xml 2006-06-01 15:34:15 UTC (rev 681)
+++ skencil/branches/skencil-0.6/Doc/usersguide/usersguide.xml 2006-06-05 18:35:01 UTC (rev 682)
@@ -0,0 +1,54 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<!DOCTYPE book
+ PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+ "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd"
+[
+ <!ENTITY quickint SYSTEM "quickint.xml">
+ <!ENTITY concepts SYSTEM "concepts.xml">
+ <!ENTITY configuration SYSTEM "configuration.xml">
+ <!ENTITY scripting SYSTEM "scripting.xml">
+
+]>
+<book>
+ <bookinfo>
+ <title>Skencil User's Guide </title>
+ <author><firstname>Bernhard</firstname><surname>Herzog</surname></author>
+ <abstract>
+ <para>
+ This is the User's Guide of the interactive drawing program
+ "Skencil". It is quite incomplete, since I spend more time
+ coding than writing documentation (currently adding
+ functionality is more important), but some sections contain
+ useful information. You should should probably start with
+ the <link linkend="quickintro">quick introduction</link>
+ and <link linkend="configuration">configuration</link>.
+ </para>
+ </abstract>
+ </bookinfo>
+
+ <chapter id="intro"><title>Introduction</title>
+ <para>
+ Skencil is an interactive, object oriented drawing program. This
+ means that the drawing is composed of objects like rectangles,
+ lines or pieces of text. Skencil allows you to manipulate the
+ objects by moving them around, resizing them or changing their
+ color, etc.
+ </para>
+ <para>
+ This type of program is also called a <emphasis>vector drawing
+ program</emphasis> because it stores the objects internally as
+ coordinates. Apart from Skencil, there are some other (freeware)
+ programs of this type available, such as xfig or tgif and more
+ recently Sodipodi or Karbon, just to name a few.
+ </para>
+ </chapter>
+
+ &quickint;
+
+ &concepts;
+
+ &configuration;
+
+ &scripting;
+
+</book>
More information about the Skencil-commits
mailing list