summaryrefslogtreecommitdiffstats
path: root/src/helper
diff options
context:
space:
mode:
authorMenTaLguY <mental@rydia.net>2006-01-16 02:36:01 +0000
committermental <mental@users.sourceforge.net>2006-01-16 02:36:01 +0000
commit179fa413b047bede6e32109e2ce82437c5fb8d34 (patch)
treea5a6ac2c1708bd02288fbd8edb2ff500ff2e0916 /src/helper
downloadinkscape-179fa413b047bede6e32109e2ce82437c5fb8d34.tar.gz
inkscape-179fa413b047bede6e32109e2ce82437c5fb8d34.zip
moving trunk for module inkscape
(bzr r1)
Diffstat (limited to 'src/helper')
-rw-r--r--src/helper/.cvsignore9
-rw-r--r--src/helper/HACKING35
-rw-r--r--src/helper/Makefile_insert51
-rw-r--r--src/helper/action.cpp228
-rw-r--r--src/helper/action.h91
-rw-r--r--src/helper/gnome-utils.cpp108
-rw-r--r--src/helper/gnome-utils.h36
-rw-r--r--src/helper/helper-forward.h35
-rw-r--r--src/helper/makefile.in17
-rw-r--r--src/helper/png-write.cpp205
-rw-r--r--src/helper/png-write.h23
-rw-r--r--src/helper/sp-marshal.cpp.mingw520
-rw-r--r--src/helper/sp-marshal.h.mingw125
-rw-r--r--src/helper/sp-marshal.list16
-rw-r--r--src/helper/stlport.h26
-rw-r--r--src/helper/stock-items.cpp267
-rw-r--r--src/helper/stock-items.h20
-rw-r--r--src/helper/unit-menu.cpp372
-rw-r--r--src/helper/unit-menu.h59
-rw-r--r--src/helper/units-test.cpp115
-rw-r--r--src/helper/units.cpp260
-rw-r--r--src/helper/units.h146
-rw-r--r--src/helper/window.cpp47
-rw-r--r--src/helper/window.h28
24 files changed, 2839 insertions, 0 deletions
diff --git a/src/helper/.cvsignore b/src/helper/.cvsignore
new file mode 100644
index 000000000..4a5454d13
--- /dev/null
+++ b/src/helper/.cvsignore
@@ -0,0 +1,9 @@
+Makefile
+Makefile.in
+.deps
+.libs
+sp-marshal.cpp
+sp-marshal.h
+makefile
+.dirstamp
+*-test
diff --git a/src/helper/HACKING b/src/helper/HACKING
new file mode 100644
index 000000000..2e3ddcbcd
--- /dev/null
+++ b/src/helper/HACKING
@@ -0,0 +1,35 @@
+*
+* Unsystematized and temporary helper things
+*
+
+1. libspchelp
+
+Here you find:
+
+Useful add-ons to gnome-canvas, such as:
+ gnome_canvas_item_i2p_affine
+
+Canvas items useful for editing:
+Ctrl - a small rectangle, which do no scale when parent is scaled
+CtrlRect - 'rubberband' box
+CtrlLine - simple straight line
+Probably some of these will be rendered without libart at all - we do not
+need antialias for rubberband.
+
+Yet to implement:
+Guide - simple guideline.
+FastSVP, FastVpath - not decided yet, but for node editing it seems to be
+useful to have special rendering mode - fast stroking of single pixel wide
+lines without antialias.
+
+2. libgt1
+
+This is complete placeholder. All type1 parsing code is already included
+in gnome-print development version and as soon as it will be more widely
+available, I remove this.
+
+These programs are written mainly by Adobe and Raph Levien, probably others.
+I modified gt1-parset1.c to force it to display most of iso-8859-1 characters.
+
+Lauris Kaplinski
+<lauris@ariman.ee>
diff --git a/src/helper/Makefile_insert b/src/helper/Makefile_insert
new file mode 100644
index 000000000..9f061c090
--- /dev/null
+++ b/src/helper/Makefile_insert
@@ -0,0 +1,51 @@
+## Makefile.am fragment sourced by src/Makefile.am.
+
+#
+# Miscellaneous unsystematized and temporary helper utilities
+#
+# libspchelp - canvas utilities, specific canvas items
+#
+
+helper/all: helper/libspchelp.a
+
+helper/clean:
+ rm -f helper/libspchelp.a $(helper_libspchelp_a_OBJECTS)
+
+helper/unit-menu.$(OBJEXT): helper/sp-marshal.h
+
+helper_libspchelp_a_SOURCES = \
+ helper/action.cpp \
+ helper/action.h \
+ helper/gnome-utils.cpp \
+ helper/gnome-utils.h \
+ helper/helper-forward.h \
+ helper/png-write.cpp \
+ helper/png-write.h \
+ helper/sp-marshal.cpp \
+ helper/sp-marshal.h \
+ helper/stlport.h \
+ helper/unit-menu.cpp \
+ helper/unit-menu.h \
+ helper/units.cpp \
+ helper/units.h \
+ helper/window.cpp \
+ helper/window.h \
+ helper/stock-items.cpp \
+ helper/stock-items.h
+
+
+# TODO: Check that the generated sp-marshal.h is the same as before.
+helper/sp-marshal.h: helper/sp-marshal.list
+ glib-genmarshal --prefix=sp_marshal --header $(srcdir)/helper/sp-marshal.list > helper/tmp.$$$$ \
+ && mv helper/tmp.$$$$ helper/sp-marshal.h
+
+helper/sp-marshal.cpp: helper/sp-marshal.list helper/sp-marshal.h
+ ( echo '#include "helper/sp-marshal.h"' && \
+ glib-genmarshal --prefix=sp_marshal --body $(srcdir)/helper/sp-marshal.list ) \
+ > helper/tmp.$$$$ \
+ && mv helper/tmp.$$$$ helper/sp-marshal.cpp
+
+helper/sp-marshal.cpp helper/sp-marshal.h: Makefile
+
+helper_units_test_SOURCES = helper/units-test.cpp
+helper_units_test_LDADD = helper/libspchelp.a -lglib-2.0
diff --git a/src/helper/action.cpp b/src/helper/action.cpp
new file mode 100644
index 000000000..9584c5dae
--- /dev/null
+++ b/src/helper/action.cpp
@@ -0,0 +1,228 @@
+#define __SP_ACTION_C__
+
+/** \file
+ * SPAction implementation
+ *
+ * Author:
+ * Lauris Kaplinski <lauris@kaplinski.com>
+ *
+ * Copyright (C) 2003 Lauris Kaplinski
+ *
+ * This code is in public domain
+ */
+
+#include <string.h>
+
+
+#include "helper/action.h"
+
+static void sp_action_class_init (SPActionClass *klass);
+static void sp_action_init (SPAction *action);
+static void sp_action_finalize (NRObject *object);
+
+static NRActiveObjectClass *parent_class;
+
+/**
+ * Register SPAction class and return its type.
+ */
+NRType
+sp_action_get_type (void)
+{
+ static unsigned int type = 0;
+ if (!type) {
+ type = nr_object_register_type (NR_TYPE_ACTIVE_OBJECT,
+ "SPAction",
+ sizeof (SPActionClass),
+ sizeof (SPAction),
+ (void (*) (NRObjectClass *)) sp_action_class_init,
+ (void (*) (NRObject *)) sp_action_init);
+ }
+ return type;
+}
+
+/**
+ * SPAction vtable initialization.
+ */
+static void
+sp_action_class_init (SPActionClass *klass)
+{
+ NRObjectClass * object_class;
+
+ object_class = (NRObjectClass *) klass;
+
+ parent_class = (NRActiveObjectClass *) (((NRObjectClass *) klass)->parent);
+
+ object_class->finalize = sp_action_finalize;
+ object_class->cpp_ctor = NRObject::invoke_ctor<SPAction>;
+}
+
+/**
+ * Callback for SPAction object initialization.
+ */
+static void
+sp_action_init (SPAction *action)
+{
+ action->sensitive = 0;
+ action->active = 0;
+ action->view = NULL;
+ action->id = action->name = action->tip = NULL;
+ action->image = NULL;
+}
+
+/**
+ * Called before SPAction object destruction.
+ */
+static void
+sp_action_finalize (NRObject *object)
+{
+ SPAction *action;
+
+ action = (SPAction *) object;
+
+ if (action->image) free (action->image);
+ if (action->tip) free (action->tip);
+ if (action->name) free (action->name);
+ if (action->id) free (action->id);
+
+ ((NRObjectClass *) (parent_class))->finalize (object);
+}
+
+/**
+ * Create new SPAction object and set its properties.
+ */
+SPAction *
+sp_action_new(Inkscape::UI::View::View *view,
+ const gchar *id,
+ const gchar *name,
+ const gchar *tip,
+ const gchar *image,
+ Inkscape::Verb * verb)
+{
+ SPAction *action = (SPAction *)nr_object_new(SP_TYPE_ACTION);
+
+ action->view = view;
+ action->sensitive = TRUE;
+ if (id) action->id = strdup (id);
+ if (name) action->name = strdup (name);
+ if (tip) action->tip = strdup (tip);
+ if (image) action->image = strdup (image);
+ action->verb = verb;
+
+ return action;
+}
+
+/**
+ \return None
+ \brief Executes an action
+ \param action The action to be executed
+ \param data Data that is passed into the action. This depends
+ on the situation that the action is used in.
+
+ This function implements the 'action' in SPActions. It first validates
+ its parameters, making sure it got an action passed in. Then it
+ turns that action into its parent class of NRActiveObject. The
+ NRActiveObject allows for listeners to be attached to it. This
+ function goes through those listeners and calls them with the
+ vector that was attached to the listener.
+*/
+void
+sp_action_perform (SPAction *action, void * data)
+{
+ NRActiveObject *aobject;
+
+ nr_return_if_fail (action != NULL);
+ nr_return_if_fail (SP_IS_ACTION (action));
+
+ aobject = NR_ACTIVE_OBJECT(action);
+ if (aobject->callbacks) {
+ unsigned int i;
+ for (i = 0; i < aobject->callbacks->length; i++) {
+ NRObjectListener *listener;
+ SPActionEventVector *avector;
+
+ listener = &aobject->callbacks->listeners[i];
+ avector = (SPActionEventVector *) listener->vector;
+
+ if ((listener->size >= sizeof (SPActionEventVector)) && avector != NULL && avector->perform != NULL) {
+ avector->perform (action, listener->data, data);
+ }
+ }
+ }
+}
+
+/**
+ * Change activation in all actions that can be taken with the action.
+ */
+void
+sp_action_set_active (SPAction *action, unsigned int active)
+{
+ nr_return_if_fail (action != NULL);
+ nr_return_if_fail (SP_IS_ACTION (action));
+
+ if (active != action->active) {
+ NRActiveObject *aobject;
+ action->active = active;
+ aobject = (NRActiveObject *) action;
+ if (aobject->callbacks) {
+ unsigned int i;
+ for (i = 0; i < aobject->callbacks->length; i++) {
+ NRObjectListener *listener;
+ SPActionEventVector *avector;
+ listener = aobject->callbacks->listeners + i;
+ avector = (SPActionEventVector *) listener->vector;
+ if ((listener->size >= sizeof (SPActionEventVector)) && avector->set_active) {
+ avector->set_active (action, active, listener->data);
+ }
+ }
+ }
+ }
+}
+
+/**
+ * Change sensitivity in all actions that can be taken with the action.
+ */
+void
+sp_action_set_sensitive (SPAction *action, unsigned int sensitive)
+{
+ nr_return_if_fail (action != NULL);
+ nr_return_if_fail (SP_IS_ACTION (action));
+
+ if (sensitive != action->sensitive) {
+ NRActiveObject *aobject;
+ action->sensitive = sensitive;
+ aobject = (NRActiveObject *) action;
+ if (aobject->callbacks) {
+ unsigned int i;
+ for (i = 0; i < aobject->callbacks->length; i++) {
+ NRObjectListener *listener;
+ SPActionEventVector *avector;
+ listener = aobject->callbacks->listeners + i;
+ avector = (SPActionEventVector *) listener->vector;
+ if ((listener->size >= sizeof (SPActionEventVector)) && avector->set_sensitive) {
+ avector->set_sensitive (action, sensitive, listener->data);
+ }
+ }
+ }
+ }
+}
+
+/**
+ * Return View associated with the action.
+ */
+Inkscape::UI::View::View *
+sp_action_get_view (SPAction *action)
+{
+ g_return_val_if_fail (SP_IS_ACTION (action), NULL);
+ return action->view;
+}
+
+/*
+ Local Variables:
+ mode:c++
+ c-file-style:"stroustrup"
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
+ indent-tabs-mode:nil
+ fill-column:99
+ End:
+*/
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :
diff --git a/src/helper/action.h b/src/helper/action.h
new file mode 100644
index 000000000..1e3646439
--- /dev/null
+++ b/src/helper/action.h
@@ -0,0 +1,91 @@
+#ifndef __SP_ACTION_H__
+#define __SP_ACTION_H__
+
+/** \file
+ * Inkscape UI action implementation
+ */
+
+/*
+ * Author:
+ * Lauris Kaplinski <lauris@kaplinski.com>
+ *
+ * Copyright (C) 2003 Lauris Kaplinski
+ *
+ * This code is in public domain
+ */
+
+/** A macro to get the GType for actions */
+#define SP_TYPE_ACTION (sp_action_get_type())
+/** A macro to cast and check the cast of changing an object to an action */
+#define SP_ACTION(o) (NR_CHECK_INSTANCE_CAST((o), SP_TYPE_ACTION, SPAction))
+/** A macro to check whether or not something is an action */
+#define SP_IS_ACTION(o) (NR_CHECK_INSTANCE_TYPE((o), SP_TYPE_ACTION))
+
+#include "helper/helper-forward.h"
+#include "libnr/nr-object.h"
+#include "forward.h"
+
+//class Inkscape::UI::View::View;
+
+namespace Inkscape {
+class Verb;
+}
+
+
+/** This is a structure that is used to hold all the possible
+ actions that can be taken with an action. These are the
+ function pointers available. */
+struct SPActionEventVector {
+ NRObjectEventVector object_vector; /**< Parent class */
+ void (* perform)(SPAction *action, void *ldata, void *pdata); /**< Actually do the action of the event. Called by sp_perform_action */
+ void (* set_active)(SPAction *action, unsigned active, void *data); /**< Callback for activation change */
+ void (* set_sensitive)(SPAction *action, unsigned sensitive, void *data); /**< Callback for a change in sensitivity */
+ void (* set_shortcut)(SPAction *action, unsigned shortcut, void *data); /**< Callback for setting the shortcut for this function */
+};
+
+/** All the data that is required to be an action. This
+ structure identifies the action and has the data to
+ create menus and toolbars for the action */
+struct SPAction : public NRActiveObject {
+ unsigned sensitive : 1; /**< Value to track whether the action is sensitive */
+ unsigned active : 1; /**< Value to track whether the action is active */
+ Inkscape::UI::View::View *view; /**< The View to which this action is attached */
+ gchar *id; /**< The identifier for the action */
+ gchar *name; /**< Full text name of the action */
+ gchar *tip; /**< A tooltip to describe the action */
+ gchar *image; /**< An image to visually identify the action */
+ Inkscape::Verb *verb; /**< The verb that produced this action */
+};
+
+/** The action class is the same as its parent. */
+struct SPActionClass {
+ NRActiveObjectClass parent_class; /**< Parent Class */
+};
+
+NRType sp_action_get_type();
+
+SPAction *sp_action_new(Inkscape::UI::View::View *view,
+ gchar const *id,
+ gchar const *name,
+ gchar const *tip,
+ gchar const *image,
+ Inkscape::Verb *verb);
+
+void sp_action_perform(SPAction *action, void *data);
+void sp_action_set_active(SPAction *action, unsigned active);
+void sp_action_set_sensitive(SPAction *action, unsigned sensitive);
+Inkscape::UI::View::View *sp_action_get_view(SPAction *action);
+
+#endif
+
+
+/*
+ Local Variables:
+ mode:c++
+ c-file-style:"stroustrup"
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
+ indent-tabs-mode:nil
+ fill-column:99
+ End:
+*/
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :
diff --git a/src/helper/gnome-utils.cpp b/src/helper/gnome-utils.cpp
new file mode 100644
index 000000000..aa70dd1a2
--- /dev/null
+++ b/src/helper/gnome-utils.cpp
@@ -0,0 +1,108 @@
+#define __GNOME_UTILS_C__
+
+/*
+ * Helpers
+ *
+ * Author:
+ * Mitsuru Oka
+ * Lauris Kaplinski <lauris@kaplinski.com>
+ *
+ * Copyright (C) 2002 authors
+ *
+ * Released under GNU GPL, read the file 'COPYING' for more information
+ */
+
+#include <string.h>
+#include <ctype.h>
+#include <glib.h>
+
+/**
+ * gnome_uri_list_extract_uris:
+ * @uri_list: an uri-list in the standard format.
+ *
+ * Returns a GList containing strings allocated with g_malloc
+ * that have been splitted from @uri-list.
+ */
+GList*
+gnome_uri_list_extract_uris (const gchar* uri_list)
+{
+ const gchar *p, *q;
+ gchar *retval;
+ GList *result = NULL;
+
+ g_return_val_if_fail (uri_list != NULL, NULL);
+
+ p = uri_list;
+
+ /* We don't actually try to validate the URI according to RFC
+ * 2396, or even check for allowed characters - we just ignore
+ * comments and trim whitespace off the ends. We also
+ * allow LF delimination as well as the specified CRLF.
+ */
+ while (p) {
+ if (*p != '#') {
+ while (isspace(*p))
+ p++;
+
+ q = p;
+ while (*q && (*q != '\n') && (*q != '\r'))
+ q++;
+
+ if (q > p) {
+ q--;
+ while (q > p && isspace(*q))
+ q--;
+
+ retval = (gchar*)g_malloc (q - p + 2);
+ strncpy (retval, p, q - p + 1);
+ retval[q - p + 1] = '\0';
+
+ result = g_list_prepend (result, retval);
+ }
+ }
+ p = strchr (p, '\n');
+ if (p)
+ p++;
+ }
+
+ return g_list_reverse (result);
+}
+
+/**
+ * gnome_uri_list_extract_filenames:
+ * @uri_list: an uri-list in the standard format
+ *
+ * Returns a GList containing strings allocated with g_malloc
+ * that contain the filenames in the uri-list.
+ *
+ * Note that unlike gnome_uri_list_extract_uris() function, this
+ * will discard any non-file uri from the result value.
+ */
+GList*
+gnome_uri_list_extract_filenames (const gchar* uri_list)
+{
+ GList *tmp_list, *node, *result;
+
+ g_return_val_if_fail (uri_list != NULL, NULL);
+
+ result = gnome_uri_list_extract_uris (uri_list);
+
+ tmp_list = result;
+ while (tmp_list) {
+ gchar *s = (gchar*)tmp_list->data;
+
+ node = tmp_list;
+ tmp_list = tmp_list->next;
+
+ if (!strncmp (s, "file:", 5)) {
+ node->data = g_filename_from_uri (s, NULL, NULL);
+ /* not sure if this fallback is useful at all */
+ if (!node->data) node->data = g_strdup (s+5);
+ } else {
+ result = g_list_remove_link(result, node);
+ g_list_free_1 (node);
+ }
+ g_free (s);
+ }
+ return result;
+}
diff --git a/src/helper/gnome-utils.h b/src/helper/gnome-utils.h
new file mode 100644
index 000000000..0a28c95a9
--- /dev/null
+++ b/src/helper/gnome-utils.h
@@ -0,0 +1,36 @@
+/*
+ * GNOME Utils - Migration helper
+ *
+ * Author:
+ * GNOME Developer
+ * Mitsuru Oka <oka326@parkcity.ne.jp>
+ * Lauris Kaplinski <lauris@ximian.com>
+ *
+ * Copyright (C) 2001 Lauris Kaplinski and Ximian, Inc.
+ *
+ * Released under GNU GPL
+ */
+
+
+#ifndef __GNOME_UTILS_H__
+#define __GNOME_UTILS_H__
+
+#include <glib/gtypes.h>
+#include <glib/glist.h>
+
+GList *gnome_uri_list_extract_uris(gchar const *uri_list);
+
+GList *gnome_uri_list_extract_filenames(gchar const *uri_list);
+
+#endif /* __GNOME_UTILS_H__ */
+
+/*
+ Local Variables:
+ mode:c++
+ c-file-style:"stroustrup"
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
+ indent-tabs-mode:nil
+ fill-column:99
+ End:
+*/
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :
diff --git a/src/helper/helper-forward.h b/src/helper/helper-forward.h
new file mode 100644
index 000000000..7cb0cddea
--- /dev/null
+++ b/src/helper/helper-forward.h
@@ -0,0 +1,35 @@
+#ifndef __HELPER_FORWARD_H__
+#define __HELPER_FORWARD_H__
+
+/*
+ * Forward declarations
+ *
+ * Author:
+ * Lauris Kaplinski <lauris@kaplinski.com>
+ *
+ * Copyright (C) 2002 Lauris Kaplinski
+ *
+ * Released under GNU GPL, read the file 'COPYING' for more information
+ */
+
+
+struct SPAction;
+struct SPActionClass;
+struct SPActionEventVector;
+
+struct SPUnit;
+struct SPUnitSelector;
+struct SPUnitSelectorClass;
+
+#endif
+
+/*
+ Local Variables:
+ mode:c++
+ c-file-style:"stroustrup"
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
+ indent-tabs-mode:nil
+ fill-column:99
+ End:
+*/
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :
diff --git a/src/helper/makefile.in b/src/helper/makefile.in
new file mode 100644
index 000000000..edb3951aa
--- /dev/null
+++ b/src/helper/makefile.in
@@ -0,0 +1,17 @@
+# Convenience stub makefile to call the real Makefile.
+
+@SET_MAKE@
+
+# Explicit so that it's the default rule.
+all:
+ cd .. && $(MAKE) helper/all
+
+clean %.a %.o:
+ cd .. && $(MAKE) helper/$@
+
+.PHONY: all clean
+
+OBJEXT = @OBJEXT@
+
+.SUFFIXES:
+.SUFFIXES: .a .$(OBJEXT)
diff --git a/src/helper/png-write.cpp b/src/helper/png-write.cpp
new file mode 100644
index 000000000..21eca1efa
--- /dev/null
+++ b/src/helper/png-write.cpp
@@ -0,0 +1,205 @@
+#define __SP_PNG_WRITE_C__
+
+/*
+ * PNG file format utilities
+ *
+ * Authors:
+ * Lauris Kaplinski <lauris@kaplinski.com>
+ * Whoever wrote this example in libpng documentation
+ *
+ * Copyright (C) 1999-2002 authors
+ *
+ * Released under GNU GPL, read the file 'COPYING' for more information
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <glib/gmessages.h>
+#include <png.h>
+#include "png-write.h"
+#include "io/sys.h"
+
+/* This is an example of how to use libpng to read and write PNG files.
+ * The file libpng.txt is much more verbose then this. If you have not
+ * read it, do so first. This was designed to be a starting point of an
+ * implementation. This is not officially part of libpng, and therefore
+ * does not require a copyright notice.
+ *
+ * This file does not currently compile, because it is missing certain
+ * parts, like allocating memory to hold an image. You will have to
+ * supply these parts to get it to compile. For an example of a minimal
+ * working PNG reader/writer, see pngtest.c, included in this distribution.
+ */
+
+/* write a png file */
+
+typedef struct SPPNGBD {
+ const guchar *px;
+ int rowstride;
+} SPPNGBD;
+
+static int
+sp_png_get_block_stripe (const guchar **rows, int row, int num_rows, void *data)
+{
+ SPPNGBD *bd = (SPPNGBD *) data;
+
+ for (int r = 0; r < num_rows; r++) {
+ rows[r] = bd->px + (row + r) * bd->rowstride;
+ }
+
+ return num_rows;
+}
+
+int
+sp_png_write_rgba (const gchar *filename, const guchar *px, int width, int height, int rowstride)
+{
+ SPPNGBD bd;
+
+ bd.px = px;
+ bd.rowstride = rowstride;
+
+ return sp_png_write_rgba_striped (filename, width, height, sp_png_get_block_stripe, &bd);
+}
+
+int
+sp_png_write_rgba_striped (const gchar *filename, int width, int height,
+ int (* get_rows) (const guchar **rows, int row, int num_rows, void *data),
+ void *data)
+{
+ FILE *fp;
+ png_structp png_ptr;
+ png_infop info_ptr;
+ png_color_8 sig_bit;
+ png_text text_ptr[3];
+ png_uint_32 r;
+
+ g_return_val_if_fail (filename != NULL, FALSE);
+
+ /* open the file */
+
+ Inkscape::IO::dump_fopen_call(filename, "M");
+ fp = Inkscape::IO::fopen_utf8name(filename, "wb");
+ g_return_val_if_fail (fp != NULL, FALSE);
+
+ /* Create and initialize the png_struct with the desired error handler
+ * functions. If you want to use the default stderr and longjump method,
+ * you can supply NULL for the last three parameters. We also check that
+ * the library version is compatible with the one used at compile time,
+ * in case we are using dynamically linked libraries. REQUIRED.
+ */
+ png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
+
+ if (png_ptr == NULL) {
+ fclose(fp);
+ return FALSE;
+ }
+
+ /* Allocate/initialize the image information data. REQUIRED */
+ info_ptr = png_create_info_struct(png_ptr);
+ if (info_ptr == NULL) {
+ fclose(fp);
+ png_destroy_write_struct(&png_ptr, NULL);
+ return FALSE;
+ }
+
+ /* Set error handling. REQUIRED if you aren't supplying your own
+ * error hadnling functions in the png_create_write_struct() call.
+ */
+ if (setjmp(png_ptr->jmpbuf)) {
+ /* If we get here, we had a problem reading the file */
+ fclose(fp);
+ png_destroy_write_struct(&png_ptr, &info_ptr);
+ return FALSE;
+ }
+
+ /* set up the output control if you are using standard C streams */
+ png_init_io(png_ptr, fp);
+
+ /* Set the image information here. Width and height are up to 2^31,
+ * bit_depth is one of 1, 2, 4, 8, or 16, but valid values also depend on
+ * the color_type selected. color_type is one of PNG_COLOR_TYPE_GRAY,
+ * PNG_COLOR_TYPE_GRAY_ALPHA, PNG_COLOR_TYPE_PALETTE, PNG_COLOR_TYPE_RGB,
+ * or PNG_COLOR_TYPE_RGB_ALPHA. interlace is either PNG_INTERLACE_NONE or
+ * PNG_INTERLACE_ADAM7, and the compression_type and filter_type MUST
+ * currently be PNG_COMPRESSION_TYPE_BASE and PNG_FILTER_TYPE_BASE. REQUIRED
+ */
+ png_set_IHDR(png_ptr, info_ptr,
+ width,
+ height,
+ 8, /* bit_depth */
+ PNG_COLOR_TYPE_RGB_ALPHA,
+ PNG_INTERLACE_NONE,
+ PNG_COMPRESSION_TYPE_BASE,
+ PNG_FILTER_TYPE_BASE);
+
+ /* otherwise, if we are dealing with a color image then */
+ sig_bit.red = 8;
+ sig_bit.green = 8;
+ sig_bit.blue = 8;
+ /* if the image has an alpha channel then */
+ sig_bit.alpha = 8;
+ png_set_sBIT(png_ptr, info_ptr, &sig_bit);
+
+ /* Made by Inkscape comment */
+ text_ptr[0].key = "Software";
+ text_ptr[0].text = "www.inkscape.org";
+ text_ptr[0].compression = PNG_TEXT_COMPRESSION_NONE;
+ png_set_text(png_ptr, info_ptr, text_ptr, 1);
+
+ /* other optional chunks like cHRM, bKGD, tRNS, tIME, oFFs, pHYs, */
+ /* note that if sRGB is present the cHRM chunk must be ignored
+ * on read and must be written in accordance with the sRGB profile */
+
+ /* Write the file header information. REQUIRED */
+ png_write_info(png_ptr, info_ptr);
+
+ /* Once we write out the header, the compression type on the text
+ * chunks gets changed to PNG_TEXT_COMPRESSION_NONE_WR or
+ * PNG_TEXT_COMPRESSION_zTXt_WR, so it doesn't get written out again
+ * at the end.
+ */
+
+ /* set up the transformations you want. Note that these are
+ * all optional. Only call them if you want them.
+ */
+
+ /* --- CUT --- */
+
+ /* The easiest way to write the image (you may have a different memory
+ * layout, however, so choose what fits your needs best). You need to
+ * use the first method if you aren't handling interlacing yourself.
+ */
+
+ r = 0;
+ while (r < static_cast< png_uint_32 > (height) ) {
+ png_bytep row_pointers[64];
+ int h, n;
+
+ h = MIN (height - r, 64);
+ n = get_rows ((const unsigned char **) row_pointers, r, h, data);
+ if (!n) break;
+ png_write_rows (png_ptr, row_pointers, n);
+ r += n;
+ }
+
+ /* You can write optional chunks like tEXt, zTXt, and tIME at the end
+ * as well.
+ */
+
+ /* It is REQUIRED to call this to finish writing the rest of the file */
+ png_write_end(png_ptr, info_ptr);
+
+ /* if you allocated any text comments, free them here */
+
+ /* clean up after the write, and free any memory allocated */
+ png_destroy_write_struct(&png_ptr, &info_ptr);
+
+ /* close the file */
+ fclose(fp);
+
+ /* that's it */
+ return TRUE;
+}
+
diff --git a/src/helper/png-write.h b/src/helper/png-write.h
new file mode 100644
index 000000000..2d2c16544
--- /dev/null
+++ b/src/helper/png-write.h
@@ -0,0 +1,23 @@
+#ifndef __SP_PNG_WRITE_H__
+#define __SP_PNG_WRITE_H__
+
+/*
+ * PNG file format utilities
+ *
+ * Authors:
+ * Lauris Kaplinski <lauris@kaplinski.com>
+ *
+ * Copyright (C) 1999-2002 Lauris Kaplinski
+ *
+ * Released under GNU GPL, read the file 'COPYING' for more information
+ */
+
+#include <glib/gtypes.h>
+
+int sp_png_write_rgba(gchar const *filename, guchar const *px, int width, int height, int rowstride);
+
+int sp_png_write_rgba_striped(gchar const *filename, int width, int height,
+ int (* get_rows) (guchar const **rows, int row, int num_rows, void *data),
+ void *data);
+
+#endif
diff --git a/src/helper/sp-marshal.cpp.mingw b/src/helper/sp-marshal.cpp.mingw
new file mode 100644
index 000000000..8a7e7648c
--- /dev/null
+++ b/src/helper/sp-marshal.cpp.mingw
@@ -0,0 +1,520 @@
+#include "helper/sp-marshal.h"
+
+#include <glib-object.h>
+
+
+#ifdef G_ENABLE_DEBUG
+#define g_marshal_value_peek_boolean(v) g_value_get_boolean (v)
+#define g_marshal_value_peek_char(v) g_value_get_char (v)
+#define g_marshal_value_peek_uchar(v) g_value_get_uchar (v)
+#define g_marshal_value_peek_int(v) g_value_get_int (v)
+#define g_marshal_value_peek_uint(v) g_value_get_uint (v)
+#define g_marshal_value_peek_long(v) g_value_get_long (v)
+#define g_marshal_value_peek_ulong(v) g_value_get_ulong (v)
+#define g_marshal_value_peek_int64(v) g_value_get_int64 (v)
+#define g_marshal_value_peek_uint64(v) g_value_get_uint64 (v)
+#define g_marshal_value_peek_enum(v) g_value_get_enum (v)
+#define g_marshal_value_peek_flags(v) g_value_get_flags (v)
+#define g_marshal_value_peek_float(v) g_value_get_float (v)
+#define g_marshal_value_peek_double(v) g_value_get_double (v)
+#define g_marshal_value_peek_string(v) (char*) g_value_get_string (v)
+#define g_marshal_value_peek_param(v) g_value_get_param (v)
+#define g_marshal_value_peek_boxed(v) g_value_get_boxed (v)
+#define g_marshal_value_peek_pointer(v) g_value_get_pointer (v)
+#define g_marshal_value_peek_object(v) g_value_get_object (v)
+#else /* !G_ENABLE_DEBUG */
+/* WARNING: This code accesses GValues directly, which is UNSUPPORTED API.
+ * Do not access GValues directly in your code. Instead, use the
+ * g_value_get_*() functions
+ */
+#define g_marshal_value_peek_boolean(v) (v)->data[0].v_int
+#define g_marshal_value_peek_char(v) (v)->data[0].v_int
+#define g_marshal_value_peek_uchar(v) (v)->data[0].v_uint
+#define g_marshal_value_peek_int(v) (v)->data[0].v_int
+#define g_marshal_value_peek_uint(v) (v)->data[0].v_uint
+#define g_marshal_value_peek_long(v) (v)->data[0].v_long
+#define g_marshal_value_peek_ulong(v) (v)->data[0].v_ulong
+#define g_marshal_value_peek_int64(v) (v)->data[0].v_int64
+#define g_marshal_value_peek_uint64(v) (v)->data[0].v_uint64
+#define g_marshal_value_peek_enum(v) (v)->data[0].v_int
+#define g_marshal_value_peek_flags(v) (v)->data[0].v_uint
+#define g_marshal_value_peek_float(v) (v)->data[0].v_float
+#define g_marshal_value_peek_double(v) (v)->data[0].v_double
+#define g_marshal_value_peek_string(v) (v)->data[0].v_pointer
+#define g_marshal_value_peek_param(v) (v)->data[0].v_pointer
+#define g_marshal_value_peek_boxed(v) (v)->data[0].v_pointer
+#define g_marshal_value_peek_pointer(v) (v)->data[0].v_pointer
+#define g_marshal_value_peek_object(v) (v)->data[0].v_pointer
+#endif /* !G_ENABLE_DEBUG */
+
+
+/* NONE:NONE (sp-marshal.list:2) */
+
+/* NONE:UINT (sp-marshal.list:3) */
+
+/* NONE:POINTER (sp-marshal.list:4) */
+
+/* NONE:POINTER,BOOLEAN (sp-marshal.list:5) */
+void
+sp_marshal_VOID__POINTER_BOOLEAN (GClosure *closure,
+ GValue *return_value,
+ guint n_param_values,
+ const GValue *param_values,
+ gpointer invocation_hint,
+ gpointer marshal_data)
+{
+ typedef void (*GMarshalFunc_VOID__POINTER_BOOLEAN) (gpointer data1,
+ gpointer arg_1,
+ gboolean arg_2,
+ gpointer data2);
+ register GMarshalFunc_VOID__POINTER_BOOLEAN callback;
+ register GCClosure *cc = (GCClosure*) closure;
+ register gpointer data1, data2;
+
+ g_return_if_fail (n_param_values == 3);
+
+ if (G_CCLOSURE_SWAP_DATA (closure))
+ {
+ data1 = closure->data;
+ data2 = g_value_peek_pointer (param_values + 0);
+ }
+ else
+ {
+ data1 = g_value_peek_pointer (param_values + 0);
+ data2 = closure->data;
+ }
+ callback = (GMarshalFunc_VOID__POINTER_BOOLEAN) (marshal_data ? marshal_data : cc->callback);
+
+ callback (data1,
+ g_marshal_value_peek_pointer (param_values + 1),
+ g_marshal_value_peek_boolean (param_values + 2),
+ data2);
+}
+
+/* NONE:POINTER,UINT (sp-marshal.list:6) */
+void
+sp_marshal_VOID__POINTER_UINT (GClosure *closure,
+ GValue *return_value,
+ guint n_param_values,
+ const GValue *param_values,
+ gpointer invocation_hint,
+ gpointer marshal_data)
+{
+ typedef void (*GMarshalFunc_VOID__POINTER_UINT) (gpointer data1,
+ gpointer arg_1,
+ guint arg_2,
+ gpointer data2);
+ register GMarshalFunc_VOID__POINTER_UINT callback;
+ register GCClosure *cc = (GCClosure*) closure;
+ register gpointer data1, data2;
+
+ g_return_if_fail (n_param_values == 3);
+
+ if (G_CCLOSURE_SWAP_DATA (closure))
+ {
+ data1 = closure->data;
+ data2 = g_value_peek_pointer (param_values + 0);
+ }
+ else
+ {
+ data1 = g_value_peek_pointer (param_values + 0);
+ data2 = closure->data;
+ }
+ callback = (GMarshalFunc_VOID__POINTER_UINT) (marshal_data ? marshal_data : cc->callback);
+
+ callback (data1,
+ g_marshal_value_peek_pointer (param_values + 1),
+ g_marshal_value_peek_uint (param_values + 2),
+ data2);
+}
+
+/* NONE:POINTER,DOUBLE (sp-marshal.list:7) */
+void
+sp_marshal_VOID__POINTER_DOUBLE (GClosure *closure,
+ GValue *return_value,
+ guint n_param_values,
+ const GValue *param_values,
+ gpointer invocation_hint,
+ gpointer marshal_data)
+{
+ typedef void (*GMarshalFunc_VOID__POINTER_DOUBLE) (gpointer data1,
+ gpointer arg_1,
+ gdouble arg_2,
+ gpointer data2);
+ register GMarshalFunc_VOID__POINTER_DOUBLE callback;
+ register GCClosure *cc = (GCClosure*) closure;
+ register gpointer data1, data2;
+
+ g_return_if_fail (n_param_values == 3);
+
+ if (G_CCLOSURE_SWAP_DATA (closure))
+ {
+ data1 = closure->data;
+ data2 = g_value_peek_pointer (param_values + 0);
+ }
+ else
+ {
+ data1 = g_value_peek_pointer (param_values + 0);
+ data2 = closure->data;
+ }
+ callback = (GMarshalFunc_VOID__POINTER_DOUBLE) (marshal_data ? marshal_data : cc->callback);
+
+ callback (data1,
+ g_marshal_value_peek_pointer (param_values + 1),
+ g_marshal_value_peek_double (param_values + 2),
+ data2);
+}
+
+/* NONE:DOUBLE,DOUBLE (sp-marshal.list:8) */
+void
+sp_marshal_VOID__DOUBLE_DOUBLE (GClosure *closure,
+ GValue *return_value,
+ guint n_param_values,
+ const GValue *param_values,
+ gpointer invocation_hint,
+ gpointer marshal_data)
+{
+ typedef void (*GMarshalFunc_VOID__DOUBLE_DOUBLE) (gpointer data1,
+ gdouble arg_1,
+ gdouble arg_2,
+ gpointer data2);
+ register GMarshalFunc_VOID__DOUBLE_DOUBLE callback;
+ register GCClosure *cc = (GCClosure*) closure;
+ register gpointer data1, data2;
+
+ g_return_if_fail (n_param_values == 3);
+
+ if (G_CCLOSURE_SWAP_DATA (closure))
+ {
+ data1 = closure->data;
+ data2 = g_value_peek_pointer (param_values + 0);
+ }
+ else
+ {
+ data1 = g_value_peek_pointer (param_values + 0);
+ data2 = closure->data;
+ }
+ callback = (GMarshalFunc_VOID__DOUBLE_DOUBLE) (marshal_data ? marshal_data : cc->callback);
+
+ callback (data1,
+ g_marshal_value_peek_double (param_values + 1),
+ g_marshal_value_peek_double (param_values + 2),
+ data2);
+}
+
+/* NONE:STRING,BOOL (sp-marshal.list:9) */
+void
+sp_marshal_VOID__STRING_BOOLEAN (GClosure *closure,
+ GValue *return_value,
+ guint n_param_values,
+ const GValue *param_values,
+ gpointer invocation_hint,
+ gpointer marshal_data)
+{
+ typedef void (*GMarshalFunc_VOID__STRING_BOOLEAN) (gpointer data1,
+ gpointer arg_1,
+ gboolean arg_2,
+ gpointer data2);
+ register GMarshalFunc_VOID__STRING_BOOLEAN callback;
+ register GCClosure *cc = (GCClosure*) closure;
+ register gpointer data1, data2;
+
+ g_return_if_fail (n_param_values == 3);
+
+ if (G_CCLOSURE_SWAP_DATA (closure))
+ {
+ data1 = closure->data;
+ data2 = g_value_peek_pointer (param_values + 0);
+ }
+ else
+ {
+ data1 = g_value_peek_pointer (param_values + 0);
+ data2 = closure->data;
+ }
+ callback = (GMarshalFunc_VOID__STRING_BOOLEAN) (marshal_data ? marshal_data : cc->callback);
+
+ callback (data1,
+ g_marshal_value_peek_string (param_values + 1),
+ g_marshal_value_peek_boolean (param_values + 2),
+ data2);
+}
+
+/* BOOLEAN:NONE (sp-marshal.list:10) */
+void
+sp_marshal_BOOLEAN__VOID (GClosure *closure,
+ GValue *return_value,
+ guint n_param_values,
+ const GValue *param_values,
+ gpointer invocation_hint,
+ gpointer marshal_data)
+{
+ typedef gboolean (*GMarshalFunc_BOOLEAN__VOID) (gpointer data1,
+ gpointer data2);
+ register GMarshalFunc_BOOLEAN__VOID callback;
+ register GCClosure *cc = (GCClosure*) closure;
+ register gpointer data1, data2;
+ gboolean v_return;
+
+ g_return_if_fail (return_value != NULL);
+ g_return_if_fail (n_param_values == 1);
+
+ if (G_CCLOSURE_SWAP_DATA (closure))
+ {
+ data1 = closure->data;
+ data2 = g_value_peek_pointer (param_values + 0);
+ }
+ else
+ {
+ data1 = g_value_peek_pointer (param_values + 0);
+ data2 = closure->data;
+ }
+ callback = (GMarshalFunc_BOOLEAN__VOID) (marshal_data ? marshal_data : cc->callback);
+
+ v_return = callback (data1,
+ data2);
+
+ g_value_set_boolean (return_value, v_return);
+}
+
+/* BOOLEAN:UINT (sp-marshal.list:11) */
+void
+sp_marshal_BOOLEAN__UINT (GClosure *closure,
+ GValue *return_value,
+ guint n_param_values,
+ const GValue *param_values,
+ gpointer invocation_hint,
+ gpointer marshal_data)
+{
+ typedef gboolean (*GMarshalFunc_BOOLEAN__UINT) (gpointer data1,
+ guint arg_1,
+ gpointer data2);
+ register GMarshalFunc_BOOLEAN__UINT callback;
+ register GCClosure *cc = (GCClosure*) closure;
+ register gpointer data1, data2;
+ gboolean v_return;
+
+ g_return_if_fail (return_value != NULL);
+ g_return_if_fail (n_param_values == 2);
+
+ if (G_CCLOSURE_SWAP_DATA (closure))
+ {
+ data1 = closure->data;
+ data2 = g_value_peek_pointer (param_values + 0);
+ }
+ else
+ {
+ data1 = g_value_peek_pointer (param_values + 0);
+ data2 = closure->data;
+ }
+ callback = (GMarshalFunc_BOOLEAN__UINT) (marshal_data ? marshal_data : cc->callback);
+
+ v_return = callback (data1,
+ g_marshal_value_peek_uint (param_values + 1),
+ data2);
+
+ g_value_set_boolean (return_value, v_return);
+}
+
+/* BOOLEAN:POINTER (sp-marshal.list:12) */
+void
+sp_marshal_BOOLEAN__POINTER (GClosure *closure,
+ GValue *return_value,
+ guint n_param_values,
+ const GValue *param_values,
+ gpointer invocation_hint,
+ gpointer marshal_data)
+{
+ typedef gboolean (*GMarshalFunc_BOOLEAN__POINTER) (gpointer data1,
+ gpointer arg_1,
+ gpointer data2);
+ register GMarshalFunc_BOOLEAN__POINTER callback;
+ register GCClosure *cc = (GCClosure*) closure;
+ register gpointer data1, data2;
+ gboolean v_return;
+
+ g_return_if_fail (return_value != NULL);
+ g_return_if_fail (n_param_values == 2);
+
+ if (G_CCLOSURE_SWAP_DATA (closure))
+ {
+ data1 = closure->data;
+ data2 = g_value_peek_pointer (param_values + 0);
+ }
+ else
+ {
+ data1 = g_value_peek_pointer (param_values + 0);
+ data2 = closure->data;
+ }
+ callback = (GMarshalFunc_BOOLEAN__POINTER) (marshal_data ? marshal_data : cc->callback);
+
+ v_return = callback (data1,
+ g_marshal_value_peek_pointer (param_values + 1),
+ data2);
+
+ g_value_set_boolean (return_value, v_return);
+}
+
+/* BOOLEAN:POINTER,UINT (sp-marshal.list:13) */
+void
+sp_marshal_BOOLEAN__POINTER_UINT (GClosure *closure,
+ GValue *return_value,
+ guint n_param_values,
+ const GValue *param_values,
+ gpointer invocation_hint,
+ gpointer marshal_data)
+{
+ typedef gboolean (*GMarshalFunc_BOOLEAN__POINTER_UINT) (gpointer data1,
+ gpointer arg_1,
+ guint arg_2,
+ gpointer data2);
+ register GMarshalFunc_BOOLEAN__POINTER_UINT callback;
+ register GCClosure *cc = (GCClosure*) closure;
+ register gpointer data1, data2;
+ gboolean v_return;
+
+ g_return_if_fail (return_value != NULL);
+ g_return_if_fail (n_param_values == 3);
+
+ if (G_CCLOSURE_SWAP_DATA (closure))
+ {
+ data1 = closure->data;
+ data2 = g_value_peek_pointer (param_values + 0);
+ }
+ else
+ {
+ data1 = g_value_peek_pointer (param_values + 0);
+ data2 = closure->data;
+ }
+ callback = (GMarshalFunc_BOOLEAN__POINTER_UINT) (marshal_data ? marshal_data : cc->callback);
+
+ v_return = callback (data1,
+ g_marshal_value_peek_pointer (param_values + 1),
+ g_marshal_value_peek_uint (param_values + 2),
+ data2);
+
+ g_value_set_boolean (return_value, v_return);
+}
+
+/* BOOLEAN:POINTER,POINTER (sp-marshal.list:14) */
+void
+sp_marshal_BOOLEAN__POINTER_POINTER (GClosure *closure,
+ GValue *return_value,
+ guint n_param_values,
+ const GValue *param_values,
+ gpointer invocation_hint,
+ gpointer marshal_data)
+{
+ typedef gboolean (*GMarshalFunc_BOOLEAN__POINTER_POINTER) (gpointer data1,
+ gpointer arg_1,
+ gpointer arg_2,
+ gpointer data2);
+ register GMarshalFunc_BOOLEAN__POINTER_POINTER callback;
+ register GCClosure *cc = (GCClosure*) closure;
+ register gpointer data1, data2;
+ gboolean v_return;
+
+ g_return_if_fail (return_value != NULL);
+ g_return_if_fail (n_param_values == 3);
+
+ if (G_CCLOSURE_SWAP_DATA (closure))
+ {
+ data1 = closure->data;
+ data2 = g_value_peek_pointer (param_values + 0);
+ }
+ else
+ {
+ data1 = g_value_peek_pointer (param_values + 0);
+ data2 = closure->data;
+ }
+ callback = (GMarshalFunc_BOOLEAN__POINTER_POINTER) (marshal_data ? marshal_data : cc->callback);
+
+ v_return = callback (data1,
+ g_marshal_value_peek_pointer (param_values + 1),
+ g_marshal_value_peek_pointer (param_values + 2),
+ data2);
+
+ g_value_set_boolean (return_value, v_return);
+}
+
+/* INT:POINTER,POINTER (sp-marshal.list:15) */
+void
+sp_marshal_INT__POINTER_POINTER (GClosure *closure,
+ GValue *return_value,
+ guint n_param_values,
+ const GValue *param_values,
+ gpointer invocation_hint,
+ gpointer marshal_data)
+{
+ typedef gint (*GMarshalFunc_INT__POINTER_POINTER) (gpointer data1,
+ gpointer arg_1,
+ gpointer arg_2,
+ gpointer data2);
+ register GMarshalFunc_INT__POINTER_POINTER callback;
+ register GCClosure *cc = (GCClosure*) closure;
+ register gpointer data1, data2;
+ gint v_return;
+
+ g_return_if_fail (return_value != NULL);
+ g_return_if_fail (n_param_values == 3);
+
+ if (G_CCLOSURE_SWAP_DATA (closure))
+ {
+ data1 = closure->data;
+ data2 = g_value_peek_pointer (param_values + 0);
+ }
+ else
+ {
+ data1 = g_value_peek_pointer (param_values + 0);
+ data2 = closure->data;
+ }
+ callback = (GMarshalFunc_INT__POINTER_POINTER) (marshal_data ? marshal_data : cc->callback);
+
+ v_return = callback (data1,
+ g_marshal_value_peek_pointer (param_values + 1),
+ g_marshal_value_peek_pointer (param_values + 2),
+ data2);
+
+ g_value_set_int (return_value, v_return);
+}
+
+/* DOUBLE:POINTER,UINT (sp-marshal.list:16) */
+void
+sp_marshal_DOUBLE__POINTER_UINT (GClosure *closure,
+ GValue *return_value,
+ guint n_param_values,
+ const GValue *param_values,
+ gpointer invocation_hint,
+ gpointer marshal_data)
+{
+ typedef gdouble (*GMarshalFunc_DOUBLE__POINTER_UINT) (gpointer data1,
+ gpointer arg_1,
+ guint arg_2,
+ gpointer data2);
+ register GMarshalFunc_DOUBLE__POINTER_UINT callback;
+ register GCClosure *cc = (GCClosure*) closure;
+ register gpointer data1, data2;
+ gdouble v_return;
+
+ g_return_if_fail (return_value != NULL);
+ g_return_if_fail (n_param_values == 3);
+
+ if (G_CCLOSURE_SWAP_DATA (closure))
+ {
+ data1 = closure->data;
+ data2 = g_value_peek_pointer (param_values + 0);
+ }
+ else
+ {
+ data1 = g_value_peek_pointer (param_values + 0);
+ data2 = closure->data;
+ }
+ callback = (GMarshalFunc_DOUBLE__POINTER_UINT) (marshal_data ? marshal_data : cc->callback);
+
+ v_return = callback (data1,
+ g_marshal_value_peek_pointer (param_values + 1),
+ g_marshal_value_peek_uint (param_values + 2),
+ data2);
+
+ g_value_set_double (return_value, v_return);
+}
+
diff --git a/src/helper/sp-marshal.h.mingw b/src/helper/sp-marshal.h.mingw
new file mode 100644
index 000000000..9b573c523
--- /dev/null
+++ b/src/helper/sp-marshal.h.mingw
@@ -0,0 +1,125 @@
+
+#ifndef __sp_marshal_MARSHAL_H__
+#define __sp_marshal_MARSHAL_H__
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+/* NONE:NONE (sp-marshal.list:2) */
+#define sp_marshal_VOID__VOID g_cclosure_marshal_VOID__VOID
+#define sp_marshal_NONE__NONE sp_marshal_VOID__VOID
+
+/* NONE:UINT (sp-marshal.list:3) */
+#define sp_marshal_VOID__UINT g_cclosure_marshal_VOID__UINT
+#define sp_marshal_NONE__UINT sp_marshal_VOID__UINT
+
+/* NONE:POINTER (sp-marshal.list:4) */
+#define sp_marshal_VOID__POINTER g_cclosure_marshal_VOID__POINTER
+#define sp_marshal_NONE__POINTER sp_marshal_VOID__POINTER
+
+/* NONE:POINTER,BOOLEAN (sp-marshal.list:5) */
+extern void sp_marshal_VOID__POINTER_BOOLEAN (GClosure *closure,
+ GValue *return_value,
+ guint n_param_values,
+ const GValue *param_values,
+ gpointer invocation_hint,
+ gpointer marshal_data);
+#define sp_marshal_NONE__POINTER_BOOLEAN sp_marshal_VOID__POINTER_BOOLEAN
+
+/* NONE:POINTER,UINT (sp-marshal.list:6) */
+extern void sp_marshal_VOID__POINTER_UINT (GClosure *closure,
+ GValue *return_value,
+ guint n_param_values,
+ const GValue *param_values,
+ gpointer invocation_hint,
+ gpointer marshal_data);
+#define sp_marshal_NONE__POINTER_UINT sp_marshal_VOID__POINTER_UINT
+
+/* NONE:POINTER,DOUBLE (sp-marshal.list:7) */
+extern void sp_marshal_VOID__POINTER_DOUBLE (GClosure *closure,
+ GValue *return_value,
+ guint n_param_values,
+ const GValue *param_values,
+ gpointer invocation_hint,
+ gpointer marshal_data);
+#define sp_marshal_NONE__POINTER_DOUBLE sp_marshal_VOID__POINTER_DOUBLE
+
+/* NONE:DOUBLE,DOUBLE (sp-marshal.list:8) */
+extern void sp_marshal_VOID__DOUBLE_DOUBLE (GClosure *closure,
+ GValue *return_value,
+ guint n_param_values,
+ const GValue *param_values,
+ gpointer invocation_hint,
+ gpointer marshal_data);
+#define sp_marshal_NONE__DOUBLE_DOUBLE sp_marshal_VOID__DOUBLE_DOUBLE
+
+/* NONE:STRING,BOOL (sp-marshal.list:9) */
+extern void sp_marshal_VOID__STRING_BOOLEAN (GClosure *closure,
+ GValue *return_value,
+ guint n_param_values,
+ const GValue *param_values,
+ gpointer invocation_hint,
+ gpointer marshal_data);
+#define sp_marshal_NONE__STRING_BOOL sp_marshal_VOID__STRING_BOOLEAN
+
+/* BOOLEAN:NONE (sp-marshal.list:10) */
+extern void sp_marshal_BOOLEAN__VOID (GClosure *closure,
+ GValue *return_value,
+ guint n_param_values,
+ const GValue *param_values,
+ gpointer invocation_hint,
+ gpointer marshal_data);
+#define sp_marshal_BOOLEAN__NONE sp_marshal_BOOLEAN__VOID
+
+/* BOOLEAN:UINT (sp-marshal.list:11) */
+extern void sp_marshal_BOOLEAN__UINT (GClosure *closure,
+ GValue *return_value,
+ guint n_param_values,
+ const GValue *param_values,
+ gpointer invocation_hint,
+ gpointer marshal_data);
+
+/* BOOLEAN:POINTER (sp-marshal.list:12) */
+extern void sp_marshal_BOOLEAN__POINTER (GClosure *closure,
+ GValue *return_value,
+ guint n_param_values,
+ const GValue *param_values,
+ gpointer invocation_hint,
+ gpointer marshal_data);
+
+/* BOOLEAN:POINTER,UINT (sp-marshal.list:13) */
+extern void sp_marshal_BOOLEAN__POINTER_UINT (GClosure *closure,
+ GValue *return_value,
+ guint n_param_values,
+ const GValue *param_values,
+ gpointer invocation_hint,
+ gpointer marshal_data);
+
+/* BOOLEAN:POINTER,POINTER (sp-marshal.list:14) */
+extern void sp_marshal_BOOLEAN__POINTER_POINTER (GClosure *closure,
+ GValue *return_value,
+ guint n_param_values,
+ const GValue *param_values,
+ gpointer invocation_hint,
+ gpointer marshal_data);
+
+/* INT:POINTER,POINTER (sp-marshal.list:15) */
+extern void sp_marshal_INT__POINTER_POINTER (GClosure *closure,
+ GValue *return_value,
+ guint n_param_values,
+ const GValue *param_values,
+ gpointer invocation_hint,
+ gpointer marshal_data);
+
+/* DOUBLE:POINTER,UINT (sp-marshal.list:16) */
+extern void sp_marshal_DOUBLE__POINTER_UINT (GClosure *closure,
+ GValue *return_value,
+ guint n_param_values,
+ const GValue *param_values,
+ gpointer invocation_hint,
+ gpointer marshal_data);
+
+G_END_DECLS
+
+#endif /* __sp_marshal_MARSHAL_H__ */
diff --git a/src/helper/sp-marshal.list b/src/helper/sp-marshal.list
new file mode 100644
index 000000000..15ddb1ec4
--- /dev/null
+++ b/src/helper/sp-marshal.list
@@ -0,0 +1,16 @@
+# marshallers for sodipodi
+NONE:NONE
+NONE:UINT
+NONE:POINTER
+NONE:POINTER,BOOLEAN
+NONE:POINTER,UINT
+NONE:POINTER,DOUBLE
+NONE:DOUBLE,DOUBLE
+NONE:STRING,BOOL
+BOOLEAN:NONE
+BOOLEAN:UINT
+BOOLEAN:POINTER
+BOOLEAN:POINTER,UINT
+BOOLEAN:POINTER,POINTER
+INT:POINTER,POINTER
+DOUBLE:POINTER,UINT
diff --git a/src/helper/stlport.h b/src/helper/stlport.h
new file mode 100644
index 000000000..c9389e814
--- /dev/null
+++ b/src/helper/stlport.h
@@ -0,0 +1,26 @@
+#ifndef __STL_PORT_H__
+#define __STK_PORT_H__
+
+
+#include <list>
+#include <glib/glist.h>
+#include <glib/gslist.h>
+
+template <typename T>
+class StlConv {
+public :
+ static void slist(std::list<T> &stlList, const GSList *slist) {
+ for (const GSList *l = slist; l != NULL; l = l->next) {
+ T item = reinterpret_cast<T>(l->data);
+ stlList.push_back(item);
+ }
+ }
+ static void list(std::list<T> &stlList, const GList *list) {
+ for (const GList *l = list; l != NULL; l = l->next) {
+ T item = reinterpret_cast<T>(l->data);
+ stlList.push_back(item);
+ }
+ }
+};
+
+#endif
diff --git a/src/helper/stock-items.cpp b/src/helper/stock-items.cpp
new file mode 100644
index 000000000..fe2026043
--- /dev/null
+++ b/src/helper/stock-items.cpp
@@ -0,0 +1,267 @@
+#define __INK_STOCK_ITEMS__
+
+/*
+ * Stock-items
+ *
+ * Stock Item management code
+ *
+ * Authors:
+ * John Cliff <simarilius@yahoo.com>
+ *
+ * Copyright 2004 John Cliff
+ *
+ *
+ * Released under GNU GPL, read the file 'COPYING' for more information
+ */
+
+#define noSP_SS_VERBOSE
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+#include "path-prefix.h"
+
+
+#include <xml/repr.h>
+#include "sp-gradient-fns.h"
+#include "document-private.h"
+#include "sp-pattern.h"
+#include "sp-marker.h"
+#include "desktop-handles.h"
+#include "inkscape.h"
+
+#include "io/sys.h"
+
+
+
+
+static SPObject *sp_gradient_load_from_svg(gchar const *name, SPDocument *current_doc);
+static SPObject *sp_marker_load_from_svg(gchar const *name, SPDocument *current_doc);
+static SPObject *sp_gradient_load_from_svg(gchar const *name, SPDocument *current_doc);
+
+
+// FIXME: these should be merged with the icon loading code so they
+// can share a common file/doc cache. This function should just
+// take the dir to look in, and the file to check for, and cache
+// against that, rather than the existing copy/paste code seen here.
+
+static SPObject * sp_marker_load_from_svg(gchar const *name, SPDocument *current_doc)
+{
+ static SPDocument *doc = NULL;
+ static unsigned int edoc = FALSE;
+ if (!current_doc) {
+ return NULL;
+ }
+ /* Try to load from document */
+ if (!edoc && !doc) {
+ gchar *markers = g_build_filename(INKSCAPE_MARKERSDIR, "/markers.svg", NULL);
+ if (Inkscape::IO::file_test(markers, G_FILE_TEST_IS_REGULAR)) {
+ doc = sp_document_new(markers, FALSE);
+ }
+ g_free(markers);
+ if (doc) {
+ sp_document_ensure_up_to_date(doc);
+ } else {
+ edoc = TRUE;
+ }
+ }
+ if (!edoc && doc) {
+ /* Get the marker we want */
+ SPObject *object = doc->getObjectById(name);
+ if (object && SP_IS_MARKER(object)) {
+ SPDefs *defs= (SPDefs *) SP_DOCUMENT_DEFS(current_doc);
+ Inkscape::XML::Node *mark_repr = SP_OBJECT_REPR(object)->duplicate();
+ SP_OBJECT_REPR(defs)->addChild(mark_repr, NULL);
+ SPObject *cloned_item = current_doc->getObjectByRepr(mark_repr);
+ Inkscape::GC::release(mark_repr);
+ return cloned_item;
+ }
+ }
+ return NULL;
+}
+
+
+static SPObject *
+sp_pattern_load_from_svg(gchar const *name, SPDocument *current_doc)
+{
+ static SPDocument *doc = NULL;
+ static unsigned int edoc = FALSE;
+ if (!current_doc) {
+ return NULL;
+ }
+ /* Try to load from document */
+ if (!edoc && !doc) {
+ gchar *patterns = g_build_filename(INKSCAPE_PATTERNSDIR, "/patterns.svg", NULL);
+ if (Inkscape::IO::file_test(patterns, G_FILE_TEST_IS_REGULAR)) {
+ doc = sp_document_new(patterns, FALSE);
+ }
+ g_free(patterns);
+ if (doc) {
+ sp_document_ensure_up_to_date(doc);
+ } else {
+ edoc = TRUE;
+ }
+ }
+ if (!edoc && doc) {
+ /* Get the pattern we want */
+ SPObject *object = doc->getObjectById(name);
+ if (object && SP_IS_PATTERN(object)) {
+ SPDefs *defs= (SPDefs *) SP_DOCUMENT_DEFS(current_doc);
+ Inkscape::XML::Node *pat_repr = SP_OBJECT_REPR(object)->duplicate();
+ SP_OBJECT_REPR(defs)->addChild(pat_repr, NULL);
+ Inkscape::GC::release(pat_repr);
+ return object;
+ }
+ }
+ return NULL;
+}
+
+
+static SPObject *
+sp_gradient_load_from_svg(gchar const *name, SPDocument *current_doc)
+{
+ static SPDocument *doc = NULL;
+ static unsigned int edoc = FALSE;
+ if (!current_doc) {
+ return NULL;
+ }
+ /* Try to load from document */
+ if (!edoc && !doc) {
+ gchar *gradients = g_build_filename(INKSCAPE_GRADIENTSDIR, "/gradients.svg", NULL);
+ if (Inkscape::IO::file_test(gradients, G_FILE_TEST_IS_REGULAR)) {
+ doc = sp_document_new(gradients, FALSE);
+ }
+ g_free(gradients);
+ if (doc) {
+ sp_document_ensure_up_to_date(doc);
+ } else {
+ edoc = TRUE;
+ }
+ }
+ if (!edoc && doc) {
+ /* Get the gradient we want */
+ SPObject *object = doc->getObjectById(name);
+ if (object && SP_IS_GRADIENT(object)) {
+ SPDefs *defs= (SPDefs *) SP_DOCUMENT_DEFS(current_doc);
+ Inkscape::XML::Node *pat_repr = SP_OBJECT_REPR(object)->duplicate();
+ SP_OBJECT_REPR(defs)->addChild(pat_repr, NULL);
+ Inkscape::GC::release(pat_repr);
+ return object;
+ }
+ }
+ return NULL;
+}
+
+// get_stock_item returns a pointer to an instance of the desired stock object in the current doc
+// if necessary it will import the object. Copes with name clashes through use of the inkscape:stockid property
+// This should be set to be the same as the id in the libary file.
+
+SPObject *get_stock_item(gchar const *urn)
+{
+ g_assert(urn != NULL);
+
+ /* check its an inkscape URN */
+ if (!strncmp (urn, "urn:inkscape:", 13)) {
+
+ gchar const *e = urn + 13;
+ int a = 0;
+ gchar * name = g_strdup(e);
+ gchar *name_p = name;
+ while (*name_p != ':' && *name_p != '\0'){
+ name_p++;
+ a++;
+ }
+
+ if (*name_p ==':') {
+ name_p++;
+ }
+
+ gchar * base = g_strndup(e, a);
+
+ SPDesktop *desktop = inkscape_active_desktop();
+ SPDocument *doc = SP_DT_DOCUMENT(desktop);
+ SPDefs *defs= (SPDefs *) SP_DOCUMENT_DEFS(doc);
+
+ SPObject *object = NULL;
+ if (!strcmp(base, "marker")) {
+ for (SPObject *child = sp_object_first_child(SP_OBJECT(defs));
+ child != NULL;
+ child = SP_OBJECT_NEXT(child))
+ {
+ if (SP_OBJECT_REPR(child)->attribute("inkscape:stockid") &&
+ !strcmp(name_p, SP_OBJECT_REPR(child)->attribute("inkscape:stockid")) &&
+ SP_IS_MARKER(child))
+ {
+ object = child;
+ }
+ }
+
+ }
+ else if (!strcmp(base,"pattern")) {
+ for (SPObject *child = sp_object_first_child(SP_OBJECT(defs)) ;
+ child != NULL;
+ child = SP_OBJECT_NEXT(child) )
+ {
+ if (SP_OBJECT_REPR(child)->attribute("inkscape:stockid") &&
+ !strcmp(name_p, SP_OBJECT_REPR(child)->attribute("inkscape:stockid")) &&
+ SP_IS_PATTERN(child))
+ {
+ object = child;
+ }
+ }
+
+ }
+ else if (!strcmp(base,"gradient")) {
+ for (SPObject *child = sp_object_first_child(SP_OBJECT(defs));
+ child != NULL;
+ child = SP_OBJECT_NEXT(child))
+ {
+ if (SP_OBJECT_REPR(child)->attribute("inkscape:stockid") &&
+ !strcmp(name_p, SP_OBJECT_REPR(child)->attribute("inkscape:stockid")) &&
+ SP_IS_GRADIENT(child))
+ {
+ object = child;
+ }
+ }
+
+ }
+
+ if (object == NULL) {
+
+ if (!strcmp(base, "marker")) {
+ object = sp_marker_load_from_svg(name_p, doc);
+ }
+ else if (!strcmp(base, "pattern")) {
+ object = sp_pattern_load_from_svg(name_p, doc);
+ }
+ else if (!strcmp(base, "gradient")) {
+ object = sp_gradient_load_from_svg(name_p, doc);
+ }
+ }
+
+ g_free(base);
+ g_free(name);
+
+ return object;
+ }
+
+ else {
+
+ SPDesktop *desktop = inkscape_active_desktop();
+ SPDocument *doc = SP_DT_DOCUMENT(desktop);
+ SPObject *object = doc->getObjectById(urn);
+
+ return object;
+ }
+}
+
+/*
+ Local Variables:
+ mode:c++
+ c-file-style:"stroustrup"
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
+ indent-tabs-mode:nil
+ fill-column:99
+ End:
+*/
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :
diff --git a/src/helper/stock-items.h b/src/helper/stock-items.h
new file mode 100644
index 000000000..ddad55415
--- /dev/null
+++ b/src/helper/stock-items.h
@@ -0,0 +1,20 @@
+#define __INK_STOCK_ITEMS__
+
+/*
+ * Stock-items
+ *
+ * Stock Item management code
+ *
+ * Authors:
+ * John Cliff <simarilius@yahoo.com>
+ *
+ * Copyright 2004 John Cliff
+ *
+ */
+
+#include <glib/gtypes.h>
+
+#include <forward.h>
+
+SPObject *get_stock_item(gchar const *urn);
+
diff --git a/src/helper/unit-menu.cpp b/src/helper/unit-menu.cpp
new file mode 100644
index 000000000..34a2b6344
--- /dev/null
+++ b/src/helper/unit-menu.cpp
@@ -0,0 +1,372 @@
+#define __SP_UNIT_MENU_C__
+
+/*
+ * Unit selector with autupdate capability
+ *
+ * Authors:
+ * Lauris Kaplinski <lauris@kaplinski.com>
+ * bulia byak <buliabyak@users.sf.net>
+ *
+ * Copyright (C) 2000-2002 Authors
+ *
+ * Released under GNU GPL, read the file 'COPYING' for more information
+ */
+
+#define noUNIT_SELECTOR_VERBOSE
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+#include <gtk/gtksignal.h>
+#include <gtk/gtkhbox.h>
+#include <gtk/gtkmenu.h>
+#include <gtk/gtkmenuitem.h>
+#include "helper/sp-marshal.h"
+#include "helper/units.h"
+#include "unit-menu.h"
+#include "widgets/spw-utilities.h"
+
+struct SPUnitSelector {
+ GtkHBox box;
+
+ GtkWidget *menu;
+
+ guint bases;
+ GSList *units;
+ SPUnit const *unit;
+ gdouble ctmscale;
+ guint plural : 1;
+ guint abbr : 1;
+
+ guint update : 1;
+
+ GSList *adjustments;
+};
+
+struct SPUnitSelectorClass {
+ GtkHBoxClass parent_class;
+
+ gboolean (* set_unit)(SPUnitSelector *us, SPUnit const *old, SPUnit const *new_unit);
+};
+
+enum {SET_UNIT, LAST_SIGNAL};
+
+static void sp_unit_selector_class_init(SPUnitSelectorClass *klass);
+static void sp_unit_selector_init(SPUnitSelector *selector);
+static void sp_unit_selector_finalize(GObject *object);
+
+static GtkHBoxClass *unit_selector_parent_class;
+static guint signals[LAST_SIGNAL] = {0};
+
+GtkType
+sp_unit_selector_get_type(void)
+{
+ static GtkType type = 0;
+ if (!type) {
+ static GtkTypeInfo const info = {
+ "SPUnitSelector",
+ sizeof(SPUnitSelector),
+ sizeof(SPUnitSelectorClass),
+ (GtkClassInitFunc) sp_unit_selector_class_init,
+ (GtkObjectInitFunc) sp_unit_selector_init,
+ NULL, NULL, NULL
+ };
+ type = gtk_type_unique(GTK_TYPE_HBOX, &info);
+ }
+ return type;
+}
+
+static void
+sp_unit_selector_class_init(SPUnitSelectorClass *klass)
+{
+ GObjectClass *object_class;
+ GtkWidgetClass *widget_class;
+
+ object_class = G_OBJECT_CLASS(klass);
+ widget_class = GTK_WIDGET_CLASS(klass);
+
+ unit_selector_parent_class = (GtkHBoxClass*)gtk_type_class(GTK_TYPE_HBOX);
+
+ signals[SET_UNIT] = g_signal_new("set_unit",
+ G_TYPE_FROM_CLASS(klass),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET(SPUnitSelectorClass, set_unit),
+ NULL, NULL,
+ sp_marshal_BOOLEAN__POINTER_POINTER,
+ G_TYPE_BOOLEAN, 2,
+ G_TYPE_POINTER, G_TYPE_POINTER);
+
+ object_class->finalize = sp_unit_selector_finalize;
+}
+
+static void
+sp_unit_selector_init(SPUnitSelector *us)
+{
+ us->ctmscale = 1.0;
+ us->abbr = FALSE;
+ us->plural = TRUE;
+
+ us->menu = gtk_option_menu_new();
+
+ gtk_widget_show(us->menu);
+ gtk_box_pack_start(GTK_BOX(us), us->menu, TRUE, TRUE, 0);
+}
+
+static void
+sp_unit_selector_finalize(GObject *object)
+{
+ SPUnitSelector *selector = SP_UNIT_SELECTOR(object);
+
+ if (selector->menu) {
+ selector->menu = NULL;
+ }
+
+ while (selector->adjustments) {
+ gtk_object_unref(GTK_OBJECT(selector->adjustments->data));
+ selector->adjustments = g_slist_remove(selector->adjustments, selector->adjustments->data);
+ }
+
+ if (selector->units) {
+ sp_unit_free_list(selector->units);
+ }
+
+ selector->unit = NULL;
+
+ G_OBJECT_CLASS(unit_selector_parent_class)->finalize(object);
+}
+
+GtkWidget *
+sp_unit_selector_new(guint bases)
+{
+ SPUnitSelector *us = (SPUnitSelector*)gtk_type_new(SP_TYPE_UNIT_SELECTOR);
+
+ sp_unit_selector_set_bases(us, bases);
+
+ return (GtkWidget *) us;
+}
+
+void
+sp_unit_selector_setsize(GtkWidget *us, guint w, guint h)
+{
+ gtk_widget_set_size_request(((SPUnitSelector *) us)->menu, w, h);
+}
+
+SPUnit const *
+sp_unit_selector_get_unit(SPUnitSelector const *us)
+{
+ g_return_val_if_fail(us != NULL, NULL);
+ g_return_val_if_fail(SP_IS_UNIT_SELECTOR(us), NULL);
+
+ return us->unit;
+}
+
+static void
+spus_unit_activate(GtkWidget *widget, SPUnitSelector *us)
+{
+ SPUnit const *unit = (SPUnit const *) gtk_object_get_data(GTK_OBJECT(widget), "unit");
+ g_return_if_fail(unit != NULL);
+
+#ifdef UNIT_SELECTOR_VERBOSE
+ g_print("Old unit %s new unit %s\n", us->unit->name, unit->name);
+#endif
+
+ SPUnit const *old = us->unit;
+ us->unit = unit;
+
+ us->update = TRUE;
+
+ gboolean consumed = FALSE;
+ g_signal_emit(G_OBJECT(us), signals[SET_UNIT], 0, old, unit, &consumed);
+
+ if ( !consumed
+ && ( unit->base == old->base
+ || ( unit->base == SP_UNIT_ABSOLUTE && old->base == SP_UNIT_DEVICE )
+ || ( old->base == SP_UNIT_ABSOLUTE && unit->base == SP_UNIT_DEVICE ) ) ) {
+ // Either the same base, or absolute<->device:
+ /* Recalculate adjustments. */
+ for (GSList *l = us->adjustments; l != NULL; l = g_slist_next(l)) {
+ GtkAdjustment *adj = GTK_ADJUSTMENT(l->data);
+ gdouble val = adj->value;
+#ifdef UNIT_SELECTOR_VERBOSE
+ g_print("Old val %g ... ", val);
+#endif
+ val = sp_convert_distance_full(val, *old, *unit);
+#ifdef UNIT_SELECTOR_VERBOSE
+ g_print("new val %g\n", val);
+#endif
+ adj->value = val;
+ }
+ /* need to separate the value changing from the notification
+ * or else the unit changes can break the calculations */
+ for (GSList *l = us->adjustments; l != NULL; l = g_slist_next(l)) {
+ gtk_adjustment_value_changed(GTK_ADJUSTMENT(l->data));
+ }
+ } else if (!consumed && unit->base != old->base) {
+ /* when the base changes, signal all the adjustments to get them
+ * to recalculate */
+ for (GSList *l = us->adjustments; l != NULL; l = g_slist_next(l)) {
+ gtk_signal_emit_by_name(GTK_OBJECT(l->data), "value_changed");
+ }
+ }
+
+ us->update = FALSE;
+}
+
+static void
+spus_rebuild_menu(SPUnitSelector *us)
+{
+ if (GTK_OPTION_MENU(us->menu)->menu) {
+ gtk_option_menu_remove_menu(GTK_OPTION_MENU(us->menu));
+ }
+
+ GtkWidget *m = gtk_menu_new();
+
+ gtk_widget_show(m);
+
+ gint pos = 0;
+ gint p = 0;
+ for (GSList *l = us->units; l != NULL; l = l->next) {
+ SPUnit const *u = (SPUnit*)l->data;
+
+ // use only abbreviations in the menu
+ // i = gtk_menu_item_new_with_label((us->abbr) ? (us->plural) ? u->abbr_plural : u->abbr : (us->plural) ? u->plural : u->name);
+ GtkWidget *i = gtk_menu_item_new_with_label( u->abbr );
+
+ gtk_object_set_data(GTK_OBJECT(i), "unit", (gpointer) u);
+ gtk_signal_connect(GTK_OBJECT(i), "activate", GTK_SIGNAL_FUNC(spus_unit_activate), us);
+
+ sp_set_font_size_smaller (i);
+
+ gtk_widget_show(i);
+
+ gtk_menu_shell_append(GTK_MENU_SHELL(m), i);
+ if (u == us->unit) pos = p;
+ p += 1;
+ }
+
+ gtk_option_menu_set_menu(GTK_OPTION_MENU(us->menu), m);
+
+ gtk_option_menu_set_history(GTK_OPTION_MENU(us->menu), pos);
+}
+
+void
+sp_unit_selector_set_bases(SPUnitSelector *us, guint bases)
+{
+ g_return_if_fail(us != NULL);
+ g_return_if_fail(SP_IS_UNIT_SELECTOR(us));
+
+ if (bases == us->bases) return;
+
+ GSList *units = sp_unit_get_list(bases);
+ g_return_if_fail(units != NULL);
+ sp_unit_free_list(us->units);
+ us->units = units;
+ us->unit = (SPUnit*)units->data;
+
+ spus_rebuild_menu(us);
+}
+
+void
+sp_unit_selector_add_unit(SPUnitSelector *us, SPUnit const *unit, int position)
+{
+ if (!g_slist_find(us->units, (gpointer) unit)) {
+ us->units = g_slist_insert(us->units, (gpointer) unit, position);
+
+ spus_rebuild_menu(us);
+ }
+}
+
+void
+sp_unit_selector_set_unit(SPUnitSelector *us, SPUnit const *unit)
+{
+ g_return_if_fail(us != NULL);
+ g_return_if_fail(SP_IS_UNIT_SELECTOR(us));
+
+ if (unit == NULL) {
+ return; // silently return, by default a newly created selector uses pt
+ }
+ if (unit == us->unit) {
+ return;
+ }
+
+ gint const pos = g_slist_index(us->units, (gpointer) unit);
+ g_return_if_fail(pos >= 0);
+
+ gtk_option_menu_set_history(GTK_OPTION_MENU(us->menu), pos);
+
+ SPUnit const *old = us->unit;
+ us->unit = unit;
+
+ /* Recalculate adjustments */
+ for (GSList *l = us->adjustments; l != NULL; l = l->next) {
+ GtkAdjustment *adj = GTK_ADJUSTMENT(l->data);
+ gdouble const val = sp_convert_distance_full(adj->value, *old, *unit);
+ gtk_adjustment_set_value(adj, val);
+ }
+}
+
+void
+sp_unit_selector_add_adjustment(SPUnitSelector *us, GtkAdjustment *adj)
+{
+ g_return_if_fail(us != NULL);
+ g_return_if_fail(SP_IS_UNIT_SELECTOR(us));
+ g_return_if_fail(adj != NULL);
+ g_return_if_fail(GTK_IS_ADJUSTMENT(adj));
+
+ g_return_if_fail(!g_slist_find(us->adjustments, adj));
+
+ gtk_object_ref(GTK_OBJECT(adj));
+ us->adjustments = g_slist_prepend(us->adjustments, adj);
+}
+
+void
+sp_unit_selector_remove_adjustment(SPUnitSelector *us, GtkAdjustment *adj)
+{
+ g_return_if_fail(us != NULL);
+ g_return_if_fail(SP_IS_UNIT_SELECTOR(us));
+ g_return_if_fail(adj != NULL);
+ g_return_if_fail(GTK_IS_ADJUSTMENT(adj));
+
+ g_return_if_fail(g_slist_find(us->adjustments, adj));
+
+ us->adjustments = g_slist_remove(us->adjustments, adj);
+ gtk_object_unref(GTK_OBJECT(adj));
+}
+
+gboolean
+sp_unit_selector_update_test(SPUnitSelector const *selector)
+{
+ g_return_val_if_fail(selector != NULL, FALSE);
+ g_return_val_if_fail(SP_IS_UNIT_SELECTOR(selector), FALSE);
+
+ return selector->update;
+}
+
+double
+sp_unit_selector_get_value_in_pixels(SPUnitSelector const *selector, GtkAdjustment *adj)
+{
+ g_return_val_if_fail(selector != NULL, adj->value);
+ g_return_val_if_fail(SP_IS_UNIT_SELECTOR(selector), adj->value);
+
+ return sp_units_get_pixels(adj->value, *(selector->unit));
+}
+
+void
+sp_unit_selector_set_value_in_pixels(SPUnitSelector *selector, GtkAdjustment *adj, double value)
+{
+ g_return_if_fail(selector != NULL);
+ g_return_if_fail(SP_IS_UNIT_SELECTOR(selector));
+
+ gtk_adjustment_set_value(adj, sp_pixels_get_units(value, *(selector->unit)));
+}
+
+/*
+ Local Variables:
+ mode:c++
+ c-file-style:"stroustrup"
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
+ indent-tabs-mode:nil
+ fill-column:99
+ End:
+*/
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :
diff --git a/src/helper/unit-menu.h b/src/helper/unit-menu.h
new file mode 100644
index 000000000..bf5bb260e
--- /dev/null
+++ b/src/helper/unit-menu.h
@@ -0,0 +1,59 @@
+#ifndef __SP_UNIT_MENU_H__
+#define __SP_UNIT_MENU_H__
+
+/*
+ * SPUnitMenu
+ *
+ * Generic (and quite unintelligent) grid item for gnome canvas
+ *
+ * Copyright (C) Lauris Kaplinski 2000
+ *
+ */
+
+#include <glib/gtypes.h>
+#include <gtk/gtkoptionmenu.h>
+
+#include <helper/helper-forward.h>
+
+
+/* Unit selector Widget */
+
+#define SP_TYPE_UNIT_SELECTOR (sp_unit_selector_get_type())
+#define SP_UNIT_SELECTOR(o) (GTK_CHECK_CAST((o), SP_TYPE_UNIT_SELECTOR, SPUnitSelector))
+#define SP_UNIT_SELECTOR_CLASS(k) (GTK_CHECK_CLASS_CAST((k), SP_TYPE_UNIT_SELECTOR, SPUnitSelectorClass))
+#define SP_IS_UNIT_SELECTOR(o) (GTK_CHECK_TYPE((o), SP_TYPE_UNIT_SELECTOR))
+#define SP_IS_UNIT_SELECTOR_CLASS(k) (GTK_CHECK_CLASS_TYPE((k), SP_TYPE_UNIT_SELECTOR))
+
+GType sp_unit_selector_get_type(void);
+
+GtkWidget *sp_unit_selector_new(guint bases);
+void sp_unit_selector_setsize(GtkWidget *us, guint w, guint h);
+
+SPUnit const *sp_unit_selector_get_unit(SPUnitSelector const *selector);
+
+void sp_unit_selector_set_bases(SPUnitSelector *selector, guint bases);
+void sp_unit_selector_add_unit(SPUnitSelector *selector, SPUnit const *unit, int position);
+
+void sp_unit_selector_set_unit(SPUnitSelector *selector, SPUnit const *unit);
+void sp_unit_selector_add_adjustment(SPUnitSelector *selector, GtkAdjustment *adjustment);
+void sp_unit_selector_remove_adjustment(SPUnitSelector *selector, GtkAdjustment *adjustment);
+
+gboolean sp_unit_selector_update_test(SPUnitSelector const *selector);
+
+double sp_unit_selector_get_value_in_pixels(SPUnitSelector const *selector, GtkAdjustment *adj);
+void sp_unit_selector_set_value_in_pixels(SPUnitSelector *selector, GtkAdjustment *adj, double value);
+
+
+
+#endif
+
+/*
+ Local Variables:
+ mode:c++
+ c-file-style:"stroustrup"
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
+ indent-tabs-mode:nil
+ fill-column:99
+ End:
+*/
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :
diff --git a/src/helper/units-test.cpp b/src/helper/units-test.cpp
new file mode 100644
index 000000000..1a983fece
--- /dev/null
+++ b/src/helper/units-test.cpp
@@ -0,0 +1,115 @@
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+#include <math.h>
+
+#include <glibmm/i18n.h>
+#include <helper/units.h>
+#include <utest/utest.h>
+
+
+/* N.B. Wrongly returns false if both near 0. (Not a problem for current users.) */
+static bool
+approx_equal(double const x, double const y)
+{
+ return fabs(x / y - 1) < 1e-15;
+}
+
+static double
+sp_units_get_points(double const x, SPUnit const &unit)
+{
+ SPUnit const &pt_unit = sp_unit_get_by_id(SP_UNIT_PT);
+ double const px = sp_units_get_pixels(x, unit);
+ return sp_pixels_get_units(px, pt_unit);
+}
+
+static double
+sp_points_get_units(double const pts, SPUnit const &unit)
+{
+ SPUnit const &pt_unit = sp_unit_get_by_id(SP_UNIT_PT);
+ double const px = sp_units_get_pixels(pts, pt_unit);
+ return sp_pixels_get_units(px, unit);
+}
+
+static bool
+test_conversions()
+{
+ utest_start("sp_units_get_pixels, sp_pixels_get_units");
+
+ struct Case { double x; char const *abbr; double pts; } const tests[] = {
+ { 1.0, "pt", 1.0 },
+ { 5.0, "pt", 5.0 },
+ { 1.0, "in", 72.0 },
+ { 2.0, "in", 144.0 },
+ { 254., "mm", 720.0 },
+ { 254., "cm", 7200. },
+ { 254., "m", 720000. },
+ { 1.5, "mm", (15 * 72. / 254) }
+ };
+ for (unsigned i = 0; i < G_N_ELEMENTS(tests); ++i) {
+ char name[80];
+ Case const &c = tests[i];
+ SPUnit const &unit = *sp_unit_get_by_abbreviation(N_(c.abbr));
+
+ double const calc_pts = sp_units_get_points(c.x, unit);
+ snprintf(name, sizeof(name), "%.1f %s -> %.1f pt", c.x, c.abbr, c.pts);
+ UTEST_TEST(name) {
+ UTEST_ASSERT(approx_equal(calc_pts, c.pts));
+ }
+
+ double const calc_x = sp_points_get_units(c.pts, unit);
+ snprintf(name, sizeof(name), "%.1f pt -> %.1f %s", c.pts, c.x, c.abbr);
+ UTEST_TEST(name) {
+ UTEST_ASSERT(approx_equal(calc_x, c.x));
+ }
+
+ double tmp = c.x;
+ bool const converted_to_pts = sp_convert_distance(&tmp, &unit, SP_PS_UNIT);
+ snprintf(name, sizeof(name), "convert %.1f %s -> %.1f pt", c.x, c.abbr, c.pts);
+ UTEST_TEST(name) {
+ UTEST_ASSERT(converted_to_pts);
+ UTEST_ASSERT(approx_equal(tmp, c.pts));
+ }
+
+ tmp = c.pts;
+ bool const converted_from_pts = sp_convert_distance(&tmp, SP_PS_UNIT, &unit);
+ snprintf(name, sizeof(name), "convert %.1f pt -> %.1f %s", c.pts, c.x, c.abbr);
+ UTEST_TEST(name) {
+ UTEST_ASSERT(converted_from_pts);
+ UTEST_ASSERT(approx_equal(tmp, c.x));
+ }
+ }
+ return utest_end();
+}
+
+static bool
+test_unit_table()
+{
+ utest_start("unit table");
+ UTEST_TEST("sp_units_table_sane") {
+ UTEST_ASSERT(sp_units_table_sane());
+ }
+ return utest_end();
+}
+
+int
+main(int argc, char *argv[])
+{
+ int const ret = ( ( test_conversions()
+ && test_unit_table() )
+ ? EXIT_SUCCESS
+ : EXIT_FAILURE );
+ return ret;
+}
+
+
+/*
+ Local Variables:
+ mode:c++
+ c-file-style:"stroustrup"
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
+ indent-tabs-mode:nil
+ fill-column:99
+ End:
+*/
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :
diff --git a/src/helper/units.cpp b/src/helper/units.cpp
new file mode 100644
index 000000000..448f60302
--- /dev/null
+++ b/src/helper/units.cpp
@@ -0,0 +1,260 @@
+#define __SP_PAPER_C__
+
+/*
+ * SPUnit
+ *
+ * Ported from libgnomeprint
+ *
+ * Authors:
+ * Dirk Luetjens <dirk@luedi.oche.de>
+ * Yves Arrouye <Yves.Arrouye@marin.fdn.fr>
+ * Lauris Kaplinski <lauris@ximian.com>
+ * bulia byak <buliabyak@users.sf.net>
+ *
+ * Copyright 1999-2001 Ximian, Inc. and authors
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include "helper/units.h"
+#include <glibmm/i18n.h>
+#include "unit-constants.h"
+#include "svg/svg-length.h"
+
+/* todo: use some fancy unit program */
+
+/* The order determines the order of the list returned by sp_unit_get_list.
+ * (It can also affect string lookups if there are any duplicates in the
+ * current locale... hopefully none.) If you re-order this list, then you must
+ * also re-order the SPUnitId enum values accordingly. Run `make check' (which
+ * calls sp_unit_table_sane) to ensure that the two are in sync.
+ */
+SPUnit const sp_units[] = {
+ {SP_UNIT_SCALE, SP_UNIT_DIMENSIONLESS, 1.0, NONE, SVGLength::NONE, N_("Unit"), "", N_("Units"), ""},
+ {SP_UNIT_PT, SP_UNIT_ABSOLUTE, PX_PER_PT, SP_PT, SVGLength::PT, N_("Point"), N_("pt"), N_("Points"), N_("Pt")},
+ {SP_UNIT_PX, SP_UNIT_DEVICE, PX_PER_PX, SP_PX, SVGLength::PX, N_("Pixel"), N_("px"), N_("Pixels"), N_("Px")},
+ /* You can add new elements from this point forward */
+ {SP_UNIT_PERCENT, SP_UNIT_DIMENSIONLESS, 0.01, NONE, SVGLength::PERCENT, N_("Percent"), N_("%"), N_("Percents"), N_("%")},
+ {SP_UNIT_MM, SP_UNIT_ABSOLUTE, PX_PER_MM, SP_MM, SVGLength::MM, N_("Millimeter"), N_("mm"), N_("Millimeters"), N_("mm")},
+ {SP_UNIT_CM, SP_UNIT_ABSOLUTE, PX_PER_CM, SP_CM, SVGLength::CM, N_("Centimeter"), N_("cm"), N_("Centimeters"), N_("cm")},
+ {SP_UNIT_M, SP_UNIT_ABSOLUTE, PX_PER_M, SP_M, SVGLength::NONE, N_("Meter"), N_("m"), N_("Meters"), N_("m")}, // no svg_unit
+ {SP_UNIT_IN, SP_UNIT_ABSOLUTE, PX_PER_IN, SP_IN, SVGLength::INCH, N_("Inch"), N_("in"), N_("Inches"), N_("in")},
+ /* Volatiles do not have default, so there are none here */
+ // TRANSLATORS: for info, see http://www.w3.org/TR/REC-CSS2/syndata.html#length-units
+ {SP_UNIT_EM, SP_UNIT_VOLATILE, 1.0, NONE, SVGLength::EM, N_("Em square"), N_("em"), N_("Em squares"), N_("em")},
+ // TRANSLATORS: for info, see http://www.w3.org/TR/REC-CSS2/syndata.html#length-units
+ {SP_UNIT_EX, SP_UNIT_VOLATILE, 1.0, NONE, SVGLength::EX, N_("Ex square"), N_("ex"), N_("Ex squares"), N_("ex")},
+};
+
+#define sp_num_units G_N_ELEMENTS(sp_units)
+
+SPUnit const *
+sp_unit_get_by_abbreviation(gchar const *abbreviation)
+{
+ g_return_val_if_fail(abbreviation != NULL, NULL);
+
+ for (unsigned i = 0 ; i < sp_num_units ; i++) {
+ if (!g_strcasecmp(abbreviation, sp_units[i].abbr)) return &sp_units[i];
+ if (!g_strcasecmp(abbreviation, sp_units[i].abbr_plural)) return &sp_units[i];
+ }
+
+ return NULL;
+}
+
+gchar const *
+sp_unit_get_abbreviation(SPUnit const *unit)
+{
+ g_return_val_if_fail(unit != NULL, NULL);
+
+ return unit->abbr;
+}
+
+gchar const *
+sp_unit_get_plural (SPUnit const *unit)
+{
+ g_return_val_if_fail(unit != NULL, NULL);
+
+ return unit->plural;
+}
+
+SPMetric
+sp_unit_get_metric(SPUnit const *unit)
+{
+ g_return_val_if_fail(unit != NULL, NONE);
+
+ return unit->metric;
+}
+
+guint
+sp_unit_get_svg_unit(SPUnit const *unit)
+{
+ g_return_val_if_fail(unit != NULL, NONE);
+
+ return unit->svg_unit;
+}
+
+GSList *
+sp_unit_get_list(guint bases)
+{
+ g_return_val_if_fail((bases & ~SP_UNITS_ALL) == 0, NULL);
+
+ GSList *units = NULL;
+ for (unsigned i = sp_num_units ; i--; ) {
+ if (bases & sp_units[i].base) {
+ units = g_slist_prepend(units, (gpointer) &sp_units[i]);
+ }
+ }
+
+ return units;
+}
+
+void
+sp_unit_free_list(GSList *units)
+{
+ g_slist_free(units);
+}
+
+/* These are pure utility */
+/* Return TRUE if conversion is possible */
+gboolean
+sp_convert_distance(gdouble *distance, SPUnit const *from, SPUnit const *to)
+{
+ g_return_val_if_fail(distance != NULL, FALSE);
+ g_return_val_if_fail(from != NULL, FALSE);
+ g_return_val_if_fail(to != NULL, FALSE);
+
+ if (from == to) return TRUE;
+ if ((from->base == SP_UNIT_DIMENSIONLESS) || (to->base == SP_UNIT_DIMENSIONLESS)) {
+ *distance = *distance * from->unittobase / to->unittobase;
+ return TRUE;
+ }
+ if ((from->base == SP_UNIT_VOLATILE) || (to->base == SP_UNIT_VOLATILE)) return FALSE;
+
+ if ((from->base == to->base)
+ || (from->base == SP_UNIT_DEVICE) && (to->base == SP_UNIT_ABSOLUTE)
+ || (from->base == SP_UNIT_ABSOLUTE) && (to->base == SP_UNIT_DEVICE))
+ {
+ *distance = *distance * from->unittobase / to->unittobase;
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+/** @param devicetransform for device units. */
+/* TODO: Remove the ctmscale parameter given that we no longer have SP_UNIT_USERSPACE. */
+gdouble
+sp_convert_distance_full(gdouble const from_dist, SPUnit const &from, SPUnit const &to)
+{
+ if (&from == &to) {
+ return from_dist;
+ }
+ if (from.base == to.base) {
+ gdouble ret = from_dist;
+ bool const succ = sp_convert_distance(&ret, &from, &to);
+ g_assert(succ);
+ return ret;
+ }
+ if ((from.base == SP_UNIT_DIMENSIONLESS)
+ || (to.base == SP_UNIT_DIMENSIONLESS))
+ {
+ return from_dist * from.unittobase / to.unittobase;
+ }
+ g_return_val_if_fail(((from.base != SP_UNIT_VOLATILE)
+ && (to.base != SP_UNIT_VOLATILE)),
+ from_dist);
+
+ gdouble absolute;
+ switch (from.base) {
+ case SP_UNIT_ABSOLUTE:
+ case SP_UNIT_DEVICE:
+ absolute = from_dist * from.unittobase;
+ break;
+ default:
+ g_warning("file %s: line %d: Illegal unit (base 0x%x)", __FILE__, __LINE__, from.base);
+ return from_dist;
+ }
+
+ gdouble ret;
+ switch (to.base) {
+ default:
+ g_warning("file %s: line %d: Illegal unit (base 0x%x)", __FILE__, __LINE__, to.base);
+ /* FALL-THROUGH */
+ case SP_UNIT_ABSOLUTE:
+ case SP_UNIT_DEVICE:
+ ret = absolute / to.unittobase;
+ break;
+ }
+
+ return ret;
+}
+
+/* Some more convenience */
+
+gdouble
+sp_units_get_pixels(gdouble const units, SPUnit const &unit)
+{
+ if (unit.base == SP_UNIT_ABSOLUTE || unit.base == SP_UNIT_DEVICE) {
+ return units * unit.unittobase;
+ } else {
+ g_warning("Different unit bases: No exact unit conversion available");
+ return units * unit.unittobase;
+ }
+}
+
+gdouble
+sp_pixels_get_units(gdouble const pixels, SPUnit const &unit)
+{
+ if (unit.base == SP_UNIT_ABSOLUTE || unit.base == SP_UNIT_DEVICE) {
+ return pixels / unit.unittobase;
+ } else {
+ g_warning("Different unit bases: No exact unit conversion available");
+ return pixels / unit.unittobase;
+ }
+}
+
+bool
+sp_units_table_sane()
+{
+ for (unsigned i = 0; i < G_N_ELEMENTS(sp_units); ++i) {
+ if (unsigned(sp_units[i].unit_id) != i) {
+ return false;
+ }
+ }
+ return true;
+}
+
+/** Converts angle (in deg) to compass display */
+double
+angle_to_compass(double angle)
+{
+ double ret = 90 - angle;
+ if (ret < 0)
+ ret = 360 + ret;
+ return ret;
+}
+
+/** Converts angle (in deg) to compass display */
+double
+angle_from_compass(double angle)
+{
+ double ret = 90 - angle;
+ if (ret > 180)
+ ret = ret - 180;
+ return ret;
+}
+
+
+/*
+ Local Variables:
+ mode:c++
+ c-file-style:"stroustrup"
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
+ indent-tabs-mode:nil
+ fill-column:99
+ End:
+*/
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :
diff --git a/src/helper/units.h b/src/helper/units.h
new file mode 100644
index 000000000..3acb65828
--- /dev/null
+++ b/src/helper/units.h
@@ -0,0 +1,146 @@
+#ifndef __SP_UNIT_H__
+#define __SP_UNIT_H__
+
+/*
+ * SPUnit
+ *
+ * Ported from libgnomeprint
+ *
+ * Authors:
+ * Dirk Luetjens <dirk@luedi.oche.de>
+ * Yves Arrouye <Yves.Arrouye@marin.fdn.fr>
+ * Lauris Kaplinski <lauris@ximian.com>
+ *
+ * Copyright 1999-2001 Ximian, Inc. and authors
+ *
+ */
+
+#include <glib/gmessages.h>
+#include <glib/gslist.h>
+#include <glib/gtypes.h>
+#include "sp-metric.h"
+
+
+/*
+ * Units and conversion methods used by libgnomeprint.
+ *
+ * You need those for certain config keys (like paper size), if you are
+ * interested in using these (look at gnome-print-config.h for discussion,
+ * why you may NOT be interested in paper size).
+ *
+ * Unit bases define set of mutually unrelated measuring systems (numbers,
+ * paper, screen and dimesionless user coordinates). Still, you can convert
+ * between those, specifying scaling factors explicitly.
+ *
+ * Paper (i.e. output) coordinates are taken as absolute real world units.
+ * It has some justification, because screen unit (pixel) size changes,
+ * if you change screen resolution, while you cannot change output on paper
+ * as easily (unless you have thermally contracting paper, of course).
+ *
+ */
+
+struct SPUnit;
+struct SPDistance;
+
+/*
+ * The base linear ("absolute") unit is 1/72th of an inch, i.e. the base unit of postscript.
+ */
+
+/*
+ * Unit bases
+ */
+enum SPUnitBase {
+ SP_UNIT_DIMENSIONLESS = (1 << 0), /* For percentages and like */
+ SP_UNIT_ABSOLUTE = (1 << 1), /* Real world distances - i.e. mm, cm... */
+ SP_UNIT_DEVICE = (1 << 2), /* Pixels in the SVG/CSS sense. */
+ SP_UNIT_VOLATILE = (1 << 3) /* em and ex */
+};
+
+/*
+ * Units: indexes into sp_units.
+ */
+enum SPUnitId {
+ SP_UNIT_SCALE, // 1.0 == 100%
+ SP_UNIT_PT, // Postscript points: exactly 72 per inch
+ SP_UNIT_PX, // "Pixels" in the CSS sense; though Inkscape assumes a constant 90 per inch.
+ SP_UNIT_PERCENT, /* Note: In Inkscape this often means "relative to current value" (for
+ users to edit a value), rather than the SVG/CSS use of percentages. */
+ SP_UNIT_MM, // millimetres
+ SP_UNIT_CM, // centimetres
+ SP_UNIT_M, // metres
+ SP_UNIT_IN, // inches
+ SP_UNIT_EM, // font-size of relevant font
+ SP_UNIT_EX, // x-height of relevant font
+ sp_max_unit_id = SP_UNIT_EX // For bounds-checking in sp_unit_get_by_id.
+};
+
+/*
+ * Notice, that for correct menus etc. you have to use
+ * ngettext method family yourself. For that reason we
+ * do not provide translations in unit names.
+ * I also do not know, whether to allow user-created units,
+ * because this would certainly confuse textdomain.
+ */
+
+struct SPUnit {
+ SPUnitId unit_id; /* used as sanity check */
+ SPUnitBase base;
+ gdouble unittobase; /* how many base units in this unit */
+ SPMetric metric; // the corresponding SPMetric from sp-metrics.h
+ guint svg_unit; // the corresponding SVGLengthUnit
+
+ /* When using, you must call "gettext" on them so they're translated */
+ gchar const *name;
+ gchar const *abbr;
+ gchar const *plural;
+ gchar const *abbr_plural;
+};
+
+const SPUnit *sp_unit_get_by_abbreviation (const gchar *abbreviation);
+/* When using, you must call "gettext" on them so they're translated */
+const gchar *sp_unit_get_abbreviation (const SPUnit *unit);
+gchar const *sp_unit_get_plural (SPUnit const *unit);
+
+SPMetric sp_unit_get_metric(SPUnit const *unit);
+guint sp_unit_get_svg_unit(SPUnit const *unit);
+
+extern SPUnit const sp_units[];
+
+inline SPUnit const &
+sp_unit_get_by_id(SPUnitId const id)
+{
+ /* inline because the compiler should optimize away the g_return_val_if_fail test in the
+ usual case that the argument value is known at compile-time, leaving just
+ "return sp_units[constant]". */
+ unsigned const ix = unsigned(id);
+ g_return_val_if_fail(ix <= sp_max_unit_id, sp_units[SP_UNIT_PX]);
+ return sp_units[ix];
+}
+
+#define SP_PS_UNIT (&sp_unit_get_by_id(SP_UNIT_PT))
+
+
+/** Used solely by units-test.cpp. */
+bool sp_units_table_sane();
+
+#define SP_UNITS_ALL (SP_UNIT_DIMENSIONLESS | SP_UNIT_ABSOLUTE | SP_UNIT_DEVICE | SP_UNIT_VOLATILE)
+
+GSList *sp_unit_get_list (guint bases);
+void sp_unit_free_list (GSList *units);
+
+/* These are pure utility */
+/* Return TRUE if conversion is possible, FALSE if unit bases differ */
+gboolean sp_convert_distance (gdouble *distance, const SPUnit *from, const SPUnit *to);
+
+/* If either one is NULL, transconverting to/from that base fails */
+/* Generic conversion between volatile units would be useless anyways */
+gdouble sp_convert_distance_full(gdouble const from_dist, SPUnit const &from, SPUnit const &to);
+
+/* Some more convenience */
+gdouble sp_units_get_pixels(gdouble const units, SPUnit const &unit);
+gdouble sp_pixels_get_units(gdouble const pixels, SPUnit const &unit);
+
+double angle_to_compass(double angle);
+double angle_from_compass(double angle);
+
+#endif
diff --git a/src/helper/window.cpp b/src/helper/window.cpp
new file mode 100644
index 000000000..346bd19f1
--- /dev/null
+++ b/src/helper/window.cpp
@@ -0,0 +1,47 @@
+#define __SP_WINDOW_C__
+
+/*
+ * Generic window implementation
+ *
+ * Author:
+ * Lauris Kaplinski <lauris@kaplinski.com>
+ *
+ * This code is in public domain
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+#include <gtk/gtkwindow.h>
+
+#include "inkscape.h"
+#include "shortcuts.h"
+#include "desktop.h"
+#include "event-context.h"
+
+static gboolean
+sp_window_key_press (GtkWidget *widget, GdkEventKey *event)
+{
+ unsigned int shortcut;
+ shortcut = get_group0_keyval (event) |
+ ( event->state & GDK_SHIFT_MASK ?
+ SP_SHORTCUT_SHIFT_MASK : 0 ) |
+ ( event->state & GDK_CONTROL_MASK ?
+ SP_SHORTCUT_CONTROL_MASK : 0 ) |
+ ( event->state & GDK_MOD1_MASK ?
+ SP_SHORTCUT_ALT_MASK : 0 );
+ return sp_shortcut_invoke (shortcut, SP_ACTIVE_DESKTOP);
+}
+
+GtkWidget *
+sp_window_new (const gchar *title, unsigned int resizeable)
+{
+ GtkWidget *window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+ gtk_window_set_title ((GtkWindow *) window, title);
+ gtk_window_set_resizable ((GtkWindow *) window, resizeable);
+ g_signal_connect_after ((GObject *) window, "key_press_event", (GCallback) sp_window_key_press, NULL);
+
+ return window;
+}
+
+
diff --git a/src/helper/window.h b/src/helper/window.h
new file mode 100644
index 000000000..764cb0413
--- /dev/null
+++ b/src/helper/window.h
@@ -0,0 +1,28 @@
+#ifndef __SP_WINDOW_H__
+#define __SP_WINDOW_H__
+
+/*
+ * Generic window implementation
+ *
+ * Author:
+ * Lauris Kaplinski <lauris@kaplinski.com>
+ *
+ * This code is in public domain
+ */
+
+#include <gtk/gtkwidget.h>
+
+GtkWidget *sp_window_new (const gchar *title, unsigned int resizeable);
+
+#endif
+
+/*
+ Local Variables:
+ mode:c++
+ c-file-style:"stroustrup"
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
+ indent-tabs-mode:nil
+ fill-column:99
+ End:
+*/
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :