diff options
| author | MenTaLguY <mental@rydia.net> | 2006-01-16 02:36:01 +0000 |
|---|---|---|
| committer | mental <mental@users.sourceforge.net> | 2006-01-16 02:36:01 +0000 |
| commit | 179fa413b047bede6e32109e2ce82437c5fb8d34 (patch) | |
| tree | a5a6ac2c1708bd02288fbd8edb2ff500ff2e0916 /src/path-chemistry.cpp | |
| download | inkscape-179fa413b047bede6e32109e2ce82437c5fb8d34.tar.gz inkscape-179fa413b047bede6e32109e2ce82437c5fb8d34.zip | |
moving trunk for module inkscape
(bzr r1)
Diffstat (limited to 'src/path-chemistry.cpp')
| -rw-r--r-- | src/path-chemistry.cpp | 369 |
1 files changed, 369 insertions, 0 deletions
diff --git a/src/path-chemistry.cpp b/src/path-chemistry.cpp new file mode 100644 index 000000000..6a5d876d6 --- /dev/null +++ b/src/path-chemistry.cpp @@ -0,0 +1,369 @@ +#define __SP_PATH_CHEMISTRY_C__ + +/* + * Here are handlers for modifying selections, specific to paths + * + * Authors: + * Lauris Kaplinski <lauris@kaplinski.com> + * bulia byak <buliabyak@users.sf.net> + * + * Copyright (C) 1999-2004 Authors + * Copyright (C) 2001-2002 Ximian, Inc. + * + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif +#include "xml/repr.h" +#include "svg/svg.h" +#include "display/curve.h" +#include <glibmm/i18n.h> +#include "sp-path.h" +#include "sp-text.h" +#include "sp-flowtext.h" +#include "libnr/nr-path.h" +#include "text-editing.h" +#include "style.h" +#include "inkscape.h" +#include "document.h" +#include "message-stack.h" +#include "selection.h" +#include "desktop-handles.h" + +/* Helper functions for sp_selected_path_to_curves */ +static void sp_selected_path_to_curves0 (gboolean do_document_done, guint32 text_grouping_policy); +static Inkscape::XML::Node * sp_selected_item_to_curved_repr(SPItem * item, guint32 text_grouping_policy); +enum { + /* Not used yet. This is the placeholder of Lauris's idea. */ + SP_TOCURVE_INTERACTIVE = 1 << 0, + SP_TOCURVE_GROUPING_BY_WORD = 1 << 1, + SP_TOCURVE_GROUPING_BY_LINE = 1 << 2, + SP_TOCURVE_GROUPING_BY_WHOLE = 1 << 3 +}; + +void +sp_selected_path_combine (void) +{ + SPDesktop *desktop = SP_ACTIVE_DESKTOP; + + Inkscape::Selection *selection = SP_DT_SELECTION (desktop); + GSList *items = (GSList *) selection->itemList(); + + if (g_slist_length (items) < 2) { + SP_DT_MSGSTACK(desktop)->flash(Inkscape::WARNING_MESSAGE, _("Select <b>at least two objects</b> to combine.")); + return; + } + + for (GSList *i = items; i != NULL; i = i->next) { + SPItem *item = (SPItem *) i->data; + if (!SP_IS_SHAPE (item) && !SP_IS_TEXT(item)) { + SP_DT_MSGSTACK(desktop)->flash(Inkscape::WARNING_MESSAGE, _("At least one of the objects is <b>not a path</b>, cannot combine.")); + return; + } + } + + Inkscape::XML::Node *parent = SP_OBJECT_REPR ((SPItem *) items->data)->parent(); + for (GSList *i = items; i != NULL; i = i->next) { + if ( SP_OBJECT_REPR ((SPItem *) i->data)->parent() != parent ) { + SP_DT_MSGSTACK(desktop)->flash(Inkscape::ERROR_MESSAGE, _("You cannot combine objects from <b>different groups</b> or <b>layers</b>.")); + return; + } + } + + sp_selected_path_to_curves0 (FALSE, 0); + + items = (GSList *) selection->itemList(); + + items = g_slist_copy (items); + + items = g_slist_sort (items, (GCompareFunc) sp_item_repr_compare_position); + + // remember the position of the topmost object + gint topmost = (SP_OBJECT_REPR ((SPItem *) g_slist_last(items)->data))->position(); + + // remember the id of the bottomost object + const char *id = SP_OBJECT_REPR ((SPItem *) items->data)->attribute("id"); + + // FIXME: merge styles of combined objects instead of using the first one's style + gchar *style = g_strdup (SP_OBJECT_REPR ((SPItem *) items->data)->attribute("style")); + + GString *dstring = g_string_new(""); + for (GSList *i = items; i != NULL; i = i->next) { + + SPPath *path = (SPPath *) i->data; + SPCurve *c = sp_shape_get_curve (SP_SHAPE (path)); + + NArtBpath *abp = nr_artpath_affine(c->bpath, SP_ITEM(path)->transform); + sp_curve_unref (c); + gchar *str = sp_svg_write_path (abp); + nr_free (abp); + + dstring = g_string_append(dstring, str); + g_free (str); + + // if this is the bottommost object, + if (!strcmp (SP_OBJECT_REPR (path)->attribute("id"), id)) { + // delete it so that its clones don't get alerted; this object will be restored shortly, with the same id + SP_OBJECT (path)->deleteObject(false); + } else { + // delete the object for real, so that its clones can take appropriate action + SP_OBJECT (path)->deleteObject(); + } + + topmost --; + } + + g_slist_free (items); + + Inkscape::XML::Node *repr = sp_repr_new ("svg:path"); + + // restore id + repr->setAttribute("id", id); + + repr->setAttribute("style", style); + g_free (style); + + repr->setAttribute("d", dstring->str); + g_string_free (dstring, TRUE); + + // add the new group to the group members' common parent + parent->appendChild(repr); + + // move to the position of the topmost, reduced by the number of deleted items + repr->setPosition(topmost > 0 ? topmost + 1 : 0); + + sp_document_done (SP_DT_DOCUMENT (desktop)); + + selection->set(repr); + + Inkscape::GC::release(repr); +} + +void +sp_selected_path_break_apart (void) +{ + SPDesktop *desktop = SP_ACTIVE_DESKTOP; + + Inkscape::Selection *selection = SP_DT_SELECTION (desktop); + + if (selection->isEmpty()) { + SP_DT_MSGSTACK(desktop)->flash(Inkscape::WARNING_MESSAGE, _("Select <b>path(s)</b> to break apart.")); + return; + } + + bool did = false; + + for (GSList *items = g_slist_copy((GSList *) selection->itemList()); + items != NULL; + items = items->next) { + + SPItem *item = (SPItem *) items->data; + + if (!SP_IS_PATH (item)) + continue; + + SPPath *path = SP_PATH (item); + + SPCurve *curve = sp_shape_get_curve (SP_SHAPE (path)); + if (curve == NULL) + continue; + + did = true; + + Inkscape::XML::Node *parent = SP_OBJECT_REPR (item)->parent(); + gint pos = SP_OBJECT_REPR (item)->position(); + const char *id = SP_OBJECT_REPR (item)->attribute("id"); + + gchar *style = g_strdup (SP_OBJECT (item)->repr->attribute("style")); + + NArtBpath *abp = nr_artpath_affine (curve->bpath, (SP_ITEM (path))->transform); + + sp_curve_unref (curve); + + // it's going to resurrect as one of the pieces, so we delete without advertisement + SP_OBJECT (item)->deleteObject(false); + + curve = sp_curve_new_from_bpath (abp); + g_assert (curve != NULL); + + GSList *list = sp_curve_split (curve); + + sp_curve_unref (curve); + + for (GSList *l = g_slist_reverse(list); l != NULL; l = l->next) { + curve = (SPCurve *) l->data; + + Inkscape::XML::Node *repr = sp_repr_new ("svg:path"); + repr->setAttribute("style", style); + + gchar *str = sp_svg_write_path (curve->bpath); + repr->setAttribute("d", str); + g_free (str); + + // add the new repr to the parent + parent->appendChild(repr); + + // move to the saved position + repr->setPosition(pos > 0 ? pos : 0); + + // if it's the first one, restore id + if (l == list) + repr->setAttribute("id", id); + + selection->add(repr); + + Inkscape::GC::release(repr); + } + + g_slist_free (list); + g_free (style); + + } + + if (did) { + sp_document_done (SP_DT_DOCUMENT (desktop)); + } else { + SP_DT_MSGSTACK(desktop)->flash(Inkscape::ERROR_MESSAGE, _("<b>No path(s)</b> to break apart in the selection.")); + return; + } +} + +/* This function is an entry point from GUI */ +void +sp_selected_path_to_curves (void) +{ + sp_selected_path_to_curves0(TRUE, SP_TOCURVE_INTERACTIVE); +} + +static void +sp_selected_path_to_curves0 (gboolean interactive, guint32 text_grouping_policy) +{ + SPDesktop *desktop = SP_ACTIVE_DESKTOP; + + Inkscape::Selection *selection = SP_DT_SELECTION (desktop); + + if (selection->isEmpty()) { + if (interactive) + SP_DT_MSGSTACK(desktop)->flash(Inkscape::WARNING_MESSAGE, _("Select <b>object(s)</b> to convert to path.")); + return; + } + + bool did = false; + + for (GSList *items = g_slist_copy((GSList *) selection->itemList()); + items != NULL; + items = items->next) { + + SPItem *item = SP_ITEM (items->data); + + Inkscape::XML::Node *repr = sp_selected_item_to_curved_repr (item, 0); + if (!repr) + continue; + + did = true; + + // remember the position of the item + gint pos = SP_OBJECT_REPR (item)->position(); + // remember parent + Inkscape::XML::Node *parent = SP_OBJECT_REPR (item)->parent(); + // remember id + const char *id = SP_OBJECT_REPR (item)->attribute("id"); + + selection->remove(item); + + // it's going to resurrect, so we delete without advertisement + SP_OBJECT (item)->deleteObject(false); + + // restore id + repr->setAttribute("id", id); + // add the new repr to the parent + parent->appendChild(repr); + // move to the saved position + repr->setPosition(pos > 0 ? pos : 0); + + selection->add(repr); + Inkscape::GC::release(repr); + } + + if (interactive) { + if (did) { + sp_document_done (SP_DT_DOCUMENT (desktop)); + } else { + SP_DT_MSGSTACK(desktop)->flash(Inkscape::ERROR_MESSAGE, _("<b>No objects</b> to convert to path in the selection.")); + return; + } + } +} + +static Inkscape::XML::Node * +sp_selected_item_to_curved_repr(SPItem * item, guint32 text_grouping_policy) +{ + if (!item) + return NULL; + + SPCurve *curve = NULL; + if (SP_IS_SHAPE (item)) { + curve = sp_shape_get_curve (SP_SHAPE (item)); + } else if (SP_IS_TEXT (item) || SP_IS_FLOWTEXT (item)) { + curve = te_get_layout(item)->convertToCurves (); + } + + if (!curve) + return NULL; + + Inkscape::XML::Node *repr = sp_repr_new ("svg:path"); + /* Transformation */ + repr->setAttribute("transform", SP_OBJECT_REPR (item)->attribute("transform")); + /* Style */ + gchar *style_str = sp_style_write_difference (SP_OBJECT_STYLE (item), + SP_OBJECT_STYLE (SP_OBJECT_PARENT (item))); + repr->setAttribute("style", style_str); + g_free (style_str); + + /* Definition */ + gchar *def_str = sp_svg_write_path (curve->bpath); + repr->setAttribute("d", def_str); + g_free (def_str); + sp_curve_unref (curve); + return repr; +} + +void +sp_selected_path_reverse () +{ + SPDesktop *desktop = SP_ACTIVE_DESKTOP; + + Inkscape::Selection *selection = SP_DT_SELECTION (desktop); + GSList *items = (GSList *) selection->itemList(); + + if (g_slist_length (items) == 0) { + SP_DT_MSGSTACK(desktop)->flash(Inkscape::WARNING_MESSAGE, _("Select <b>path(s)</b> to reverse.")); + return; + } + + + bool did = false; + for (GSList *i = items; i != NULL; i = i->next) { + + if (!SP_IS_SHAPE (items->data)) + continue; + + did = true; + SPShape *shape = SP_SHAPE (items->data); + + SPCurve *rcurve = sp_curve_reverse (shape->curve); + + char *str = sp_svg_write_path (rcurve->bpath); + SP_OBJECT_REPR (shape)->setAttribute("d", str); + + sp_curve_unref (rcurve); + } + + if (did) { + sp_document_done (SP_DT_DOCUMENT (desktop)); + } else { + SP_DT_MSGSTACK(desktop)->flash(Inkscape::ERROR_MESSAGE, _("<b>No paths</b> to reverse in the selection.")); + } +} |
