X-Git-Url: https://git.tokkee.org/?a=blobdiff_plain;f=src%2Fpath-chemistry.cpp;h=32a7968b28b76b1ed68aa91e4a654cb63596c24e;hb=d0e9733b7b0ddf2f0e7c842e19607f992eebf89a;hp=46c81fa97f48f00db01e48ce00a78029ad637423;hpb=7691e5a60e36fbdbc46342cdc4dcec54737897e1;p=inkscape.git diff --git a/src/path-chemistry.cpp b/src/path-chemistry.cpp index 46c81fa97..32a7968b2 100644 --- a/src/path-chemistry.cpp +++ b/src/path-chemistry.cpp @@ -30,18 +30,19 @@ #include "libnr/nr-path.h" #include "text-editing.h" #include "style.h" -#include "inkscape.h" #include "desktop.h" #include "document.h" #include "message-stack.h" #include "selection.h" #include "desktop-handles.h" #include "box3d.h" - +#include <2geom/pathvector.h> #include "path-chemistry.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 void sp_selected_path_to_curves0(SPDesktop *desktop, bool do_document_done, guint32 text_grouping_policy); +static bool sp_item_list_to_curves(const GSList *items, GSList **selected, GSList **to_select); + enum { /* Not used yet. This is the placeholder of Lauris's idea. */ SP_TOCURVE_INTERACTIVE = 1 << 0, @@ -51,10 +52,10 @@ enum { }; void -sp_selected_path_combine(void) +sp_selected_path_combine(SPDesktop *desktop) { - SPDesktop *desktop = SP_ACTIVE_DESKTOP; Inkscape::Selection *selection = sp_desktop_selection(desktop); + SPDocument *doc = sp_desktop_document(desktop); if (g_slist_length((GSList *) selection->itemList()) < 2) { sp_desktop_message_stack(desktop)->flash(Inkscape::WARNING_MESSAGE, _("Select at least two objects to combine.")); @@ -65,19 +66,30 @@ sp_selected_path_combine(void) // set "busy" cursor desktop->setWaitingCursor(); - sp_selected_path_to_curves0(FALSE, 0); - GSList *items = g_slist_copy((GSList *) selection->itemList()); + GSList *to_paths = NULL; + for (GSList *i = items; i != NULL; i = i->next) { + SPItem *item = (SPItem *) i->data; + if (!SP_IS_PATH(item)) + to_paths = g_slist_prepend(to_paths, item); + } + GSList *converted = NULL; + bool did = sp_item_list_to_curves(to_paths, &items, &converted); + g_slist_free(to_paths); + for (GSList *i = converted; i != NULL; i = i->next) + items = g_slist_prepend(items, doc->getObjectByRepr((Inkscape::XML::Node*)(i->data))); + items = g_slist_sort(items, (GCompareFunc) sp_item_repr_compare_position); items = g_slist_reverse(items); - // remember the position, id and style of the topmost path, they will be assigned to the combined one + // remember the position, id, transform and style of the topmost path, they will be assigned to the combined one gint position = 0; char const *id = NULL; + char const *transform = NULL; gchar *style = NULL; + gchar *path_effect = NULL; SPCurve* curve = 0; - bool did = false; SPItem *first = NULL; Inkscape::XML::Node *parent = NULL; @@ -88,21 +100,22 @@ sp_selected_path_combine(void) continue; did = true; - NArtBpath *abp = NULL; - SPCurve *c = sp_shape_get_curve(SP_SHAPE(item)); + SPCurve *c = sp_path_get_curve_for_edit(SP_PATH(item)); if (first == NULL) { // this is the topmost path first = item; parent = SP_OBJECT_REPR(first)->parent(); position = SP_OBJECT_REPR(first)->position(); id = SP_OBJECT_REPR(first)->attribute("id"); + transform = SP_OBJECT_REPR(first)->attribute("transform"); // FIXME: merge styles of combined objects instead of using the first one's style style = g_strdup(SP_OBJECT_REPR(first)->attribute("style")); - sp_curve_transform(c, item->transform); + path_effect = g_strdup(SP_OBJECT_REPR(first)->attribute("inkscape:path-effect")); + //c->transform(item->transform); curve = c; } else { - sp_curve_transform(c, item->getRelativeTransform(SP_OBJECT(first))); - sp_curve_append(curve, c, false); - sp_curve_unref(c); + c->transform(item->getRelativeTransform(SP_OBJECT(first))); + curve->append(c, false); + c->unref(); } // unless this is the topmost object, @@ -127,18 +140,23 @@ sp_selected_path_combine(void) Inkscape::XML::Document *xml_doc = sp_document_repr_doc(desktop->doc()); Inkscape::XML::Node *repr = xml_doc->createElement("svg:path"); - // restore id and style + // restore id, transform, path effect, and style repr->setAttribute("id", id); - + if (transform) repr->setAttribute("transform", transform); repr->setAttribute("style", style); g_free(style); // set path data corresponding to new curve - gchar *dstring = sp_svg_write_path(SP_CURVE_BPATH(curve)); - sp_curve_unref(curve); + gchar *dstring = sp_svg_write_path(curve->get_pathvector()); + curve->unref(); repr->setAttribute("d", dstring); + if (path_effect) + repr->setAttribute("inkscape:original-d", dstring); g_free(dstring); + repr->setAttribute("inkscape:path-effect", path_effect); + g_free(path_effect); + // add the new group to the parent of the topmost parent->appendChild(repr); @@ -160,10 +178,8 @@ sp_selected_path_combine(void) } void -sp_selected_path_break_apart(void) +sp_selected_path_break_apart(SPDesktop *desktop) { - SPDesktop *desktop = SP_ACTIVE_DESKTOP; - Inkscape::Selection *selection = sp_desktop_selection(desktop); if (selection->isEmpty()) { @@ -188,7 +204,7 @@ sp_selected_path_break_apart(void) SPPath *path = SP_PATH(item); - SPCurve *curve = sp_shape_get_curve(SP_SHAPE(path)); + SPCurve *curve = sp_path_get_curve_for_edit(SP_PATH(path)); if (curve == NULL) continue; @@ -199,20 +215,21 @@ sp_selected_path_break_apart(void) char const *id = SP_OBJECT_REPR(item)->attribute("id"); gchar *style = g_strdup(SP_OBJECT(item)->repr->attribute("style")); + gchar *path_effect = g_strdup(SP_OBJECT(item)->repr->attribute("inkscape:path-effect")); - NArtBpath *abp = nr_artpath_affine(SP_CURVE_BPATH(curve), (SP_ITEM(path))->transform); + Geom::PathVector apv = curve->get_pathvector() * SP_ITEM(path)->transform; - sp_curve_unref(curve); + curve->unref(); // 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); + curve = new SPCurve(apv); g_assert(curve != NULL); - GSList *list = sp_curve_split(curve); + GSList *list = curve->split(); - sp_curve_unref(curve); + curve->unref(); GSList *reprs = NULL; for (GSList *l = list; l != NULL; l = l->next) { @@ -221,10 +238,14 @@ sp_selected_path_break_apart(void) Inkscape::XML::Node *repr = parent->document()->createElement("svg:path"); repr->setAttribute("style", style); - gchar *str = sp_svg_write_path(SP_CURVE_BPATH(curve)); + gchar *str = sp_svg_write_path(curve->get_pathvector()); repr->setAttribute("d", str); + if (path_effect) + repr->setAttribute("inkscape:original-d", str); g_free(str); + repr->setAttribute("inkscape:path-effect", path_effect); + // add the new repr to the parent parent->appendChild(repr); @@ -260,16 +281,14 @@ sp_selected_path_break_apart(void) /* This function is an entry point from GUI */ void -sp_selected_path_to_curves(void) +sp_selected_path_to_curves(SPDesktop *desktop, bool interactive) { - sp_selected_path_to_curves0(TRUE, SP_TOCURVE_INTERACTIVE); + sp_selected_path_to_curves0(desktop, interactive, interactive ? SP_TOCURVE_INTERACTIVE : 0); } static void -sp_selected_path_to_curves0(gboolean interactive, guint32 /*text_grouping_policy*/) +sp_selected_path_to_curves0(SPDesktop *desktop, bool interactive, guint32 /*text_grouping_policy*/) { - SPDesktop *desktop = SP_ACTIVE_DESKTOP; - Inkscape::Selection *selection = sp_desktop_selection(desktop); if (selection->isEmpty()) { @@ -290,11 +309,37 @@ sp_selected_path_to_curves0(gboolean interactive, guint32 /*text_grouping_policy selection->clear(); GSList *items = g_slist_copy(selected); + did = sp_item_list_to_curves(items, &selected, &to_select); + + g_slist_free (items); + selection->setReprList(to_select); + selection->addList(selected); + g_slist_free (to_select); + g_slist_free (selected); + + if (interactive) { + desktop->clearWaitingCursor(); + if (did) { + sp_document_done(sp_desktop_document(desktop), SP_VERB_OBJECT_TO_CURVE, + _("Object to path")); + } else { + sp_desktop_message_stack(desktop)->flash(Inkscape::ERROR_MESSAGE, _("No objects to convert to path in the selection.")); + return; + } + } +} + +static bool +sp_item_list_to_curves(const GSList *items, GSList **selected, GSList **to_select) +{ + bool did = false; + for (; items != NULL; items = items->next) { SPItem *item = SP_ITEM(items->data); + SPDocument *document = item->document; if (SP_IS_PATH(item) && !SP_PATH(item)->original_curve) { continue; // already a path, and no path effect @@ -302,23 +347,40 @@ sp_selected_path_to_curves0(gboolean interactive, guint32 /*text_grouping_policy if (SP_IS_BOX3D(item)) { // convert 3D box to ordinary group of paths; replace the old element in 'selected' with the new group - Inkscape::XML::Node *repr = box3d_convert_to_group(SP_BOX3D(item)); + Inkscape::XML::Node *repr = SP_OBJECT_REPR(box3d_convert_to_group(SP_BOX3D(item))); if (repr) { - to_select = g_slist_prepend (to_select, repr); + *to_select = g_slist_prepend (*to_select, repr); did = true; - selected = g_slist_remove (selected, item); + *selected = g_slist_remove (*selected, item); } continue; } + + if (SP_IS_GROUP(item)) { + sp_lpe_item_remove_all_path_effects(SP_LPE_ITEM(item), true); + GSList *item_list = sp_item_group_item_list(SP_GROUP(item)); + + GSList *item_to_select = NULL; + GSList *item_selected = NULL; + + if (sp_item_list_to_curves(item_list, &item_selected, &item_to_select)) + did = true; + + g_slist_free(item_list); + g_slist_free(item_to_select); + g_slist_free(item_selected); + + continue; + } Inkscape::XML::Node *repr = sp_selected_item_to_curved_repr(item, 0); if (!repr) continue; did = true; - selected = g_slist_remove (selected, item); + *selected = g_slist_remove (*selected, item); // remember the position of the item gint pos = SP_OBJECT_REPR(item)->position(); @@ -326,6 +388,10 @@ sp_selected_path_to_curves0(gboolean interactive, guint32 /*text_grouping_policy Inkscape::XML::Node *parent = SP_OBJECT_REPR(item)->parent(); // remember id char const *id = SP_OBJECT_REPR(item)->attribute("id"); + // remember title + gchar *title = item->title(); + // remember description + gchar *desc = item->desc(); // It's going to resurrect, so we delete without notifying listeners. SP_OBJECT(item)->deleteObject(false); @@ -334,31 +400,26 @@ sp_selected_path_to_curves0(gboolean interactive, guint32 /*text_grouping_policy repr->setAttribute("id", id); // add the new repr to the parent parent->appendChild(repr); + SPObject* newObj = document->getObjectByRepr(repr); + if (title && newObj) { + newObj->setTitle(title); + g_free(title); + } + if (desc && newObj) { + newObj->setDesc(desc); + g_free(desc); + } + // move to the saved position repr->setPosition(pos > 0 ? pos : 0); /* Buglet: We don't re-add the (new version of the) object to the selection of any other * desktops where it was previously selected. */ - to_select = g_slist_prepend (to_select, repr); + *to_select = g_slist_prepend (*to_select, repr); Inkscape::GC::release(repr); } - - g_slist_free (items); - selection->setReprList(to_select); - selection->addList(selected); - g_slist_free (to_select); - g_slist_free (selected); - - if (interactive) { - desktop->clearWaitingCursor(); - if (did) { - sp_document_done(sp_desktop_document(desktop), SP_VERB_OBJECT_TO_CURVE, - _("Object to path")); - } else { - sp_desktop_message_stack(desktop)->flash(Inkscape::ERROR_MESSAGE, _("No objects to convert to path in the selection.")); - return; - } - } + + return did; } Inkscape::XML::Node * @@ -379,9 +440,9 @@ sp_selected_item_to_curved_repr(SPItem *item, guint32 /*text_grouping_policy*/) // Prevent empty paths from being added to the document // otherwise we end up with zomby markup in the SVG file - if(curve->end <= 0) + if(curve->is_empty()) { - sp_curve_unref(curve); + curve->unref(); return NULL; } @@ -406,24 +467,22 @@ sp_selected_item_to_curved_repr(SPItem *item, guint32 /*text_grouping_policy*/) repr->setAttribute("clip-path", clip_path_str); /* Rotation center */ - sp_repr_set_attr(repr, "inkscape:transform-center-x", SP_OBJECT_REPR(item)->attribute("inkscape:transform-center-x")); - sp_repr_set_attr(repr, "inkscape:transform-center-y", SP_OBJECT_REPR(item)->attribute("inkscape:transform-center-y")); + repr->setAttribute("inkscape:transform-center-x", SP_OBJECT_REPR(item)->attribute("inkscape:transform-center-x"), false); + repr->setAttribute("inkscape:transform-center-y", SP_OBJECT_REPR(item)->attribute("inkscape:transform-center-y"), false); /* Definition */ - gchar *def_str = sp_svg_write_path(SP_CURVE_BPATH(curve)); + gchar *def_str = sp_svg_write_path(curve->get_pathvector()); repr->setAttribute("d", def_str); g_free(def_str); - sp_curve_unref(curve); + curve->unref(); return repr; } // FIXME: THIS DOES NOT REVERSE THE NODETYPES ORDER! void -sp_selected_path_reverse() +sp_selected_path_reverse(SPDesktop *desktop) { - SPDesktop *desktop = SP_ACTIVE_DESKTOP; - Inkscape::Selection *selection = sp_desktop_selection(desktop); GSList *items = (GSList *) selection->itemList(); @@ -447,17 +506,17 @@ sp_selected_path_reverse() did = true; SPPath *path = SP_PATH(i->data); - SPCurve *rcurve = sp_curve_reverse(sp_path_get_curve_reference(path)); + SPCurve *rcurve = sp_path_get_curve_reference(path)->create_reverse(); - gchar *str = sp_svg_write_path(SP_CURVE_BPATH(rcurve)); - if ( sp_shape_has_path_effect(SP_SHAPE(path)) ) { + gchar *str = sp_svg_write_path(rcurve->get_pathvector()); + if ( sp_lpe_item_has_path_effect_recursive(SP_LPE_ITEM(path)) ) { SP_OBJECT_REPR(path)->setAttribute("inkscape:original-d", str); } else { SP_OBJECT_REPR(path)->setAttribute("d", str); } g_free(str); - sp_curve_unref(rcurve); + rcurve->unref(); } desktop->clearWaitingCursor();