X-Git-Url: https://git.tokkee.org/?a=blobdiff_plain;f=src%2Fpath-chemistry.cpp;h=9a8eb3e9237b16ed1318d8aa5cca929b9ce2270b;hb=9750c2b6fc6843862effd2be59402193fe7171a1;hp=280447b297c38f02ef81e55a9c543481dbca3d14;hpb=39119552b53c1385923e1e8a4d78297e8abe68d2;p=inkscape.git diff --git a/src/path-chemistry.cpp b/src/path-chemistry.cpp index 280447b29..9a8eb3e92 100644 --- a/src/path-chemistry.cpp +++ b/src/path-chemistry.cpp @@ -19,6 +19,7 @@ #include "xml/repr.h" #include "svg/svg.h" #include "display/curve.h" +#include #include #include "sp-path.h" #include "sp-text.h" @@ -27,343 +28,380 @@ #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" /* 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 +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) +sp_selected_path_combine(void) { - SPDesktop *desktop = SP_ACTIVE_DESKTOP; - - Inkscape::Selection *selection = SP_DT_SELECTION (desktop); - GSList *items = (GSList *) selection->itemList(); + SPDesktop *desktop = SP_ACTIVE_DESKTOP; - if (g_slist_length (items) < 2) { - SP_DT_MSGSTACK(desktop)->flash(Inkscape::WARNING_MESSAGE, _("Select at least two objects to combine.")); - return; - } + Inkscape::Selection *selection = sp_desktop_selection(desktop); + GSList *items = (GSList *) selection->itemList(); - 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 not a path, cannot combine.")); - return; - } - } + if (g_slist_length(items) < 2) { + sp_desktop_message_stack(desktop)->flash(Inkscape::WARNING_MESSAGE, _("Select at least two objects to 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 different groups or layers.")); - 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_desktop_message_stack(desktop)->flash(Inkscape::WARNING_MESSAGE, _("At least one of the objects is not a path, cannot combine.")); + return; + } + } - sp_selected_path_to_curves0 (FALSE, 0); + 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_desktop_message_stack(desktop)->flash(Inkscape::ERROR_MESSAGE, _("You cannot combine objects from different groups or layers.")); + return; + } + } - items = (GSList *) selection->itemList(); + sp_selected_path_to_curves0(FALSE, 0); - items = g_slist_copy (items); + items = (GSList *) selection->itemList(); - items = g_slist_sort (items, (GCompareFunc) sp_item_repr_compare_position); + items = g_slist_copy(items); - // remember the position of the topmost object - gint topmost = (SP_OBJECT_REPR ((SPItem *) g_slist_last(items)->data))->position(); + items = g_slist_sort(items, (GCompareFunc) sp_item_repr_compare_position); - // remember the id of the bottomost object - char const *id = SP_OBJECT_REPR ((SPItem *) items->data)->attribute("id"); + // remember the position of the topmost object + gint topmost = (SP_OBJECT_REPR((SPItem *) g_slist_last(items)->data))->position(); - // 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")); + // remember the id of the bottomost object + char const *id = SP_OBJECT_REPR((SPItem *) items->data)->attribute("id"); - GString *dstring = g_string_new(""); - for (GSList *i = items; i != NULL; i = i->next) { + // 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")); - 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); + GString *dstring = g_string_new(""); + for (GSList *i = items; i != NULL; i = i->next) { - dstring = g_string_append(dstring, str); - g_free (str); + SPPath *path = (SPPath *) i->data; + SPCurve *c = sp_shape_get_curve(SP_SHAPE(path)); - // 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(); - } + NArtBpath *abp = nr_artpath_affine(SP_CURVE_BPATH(c), SP_ITEM(path)->transform); + sp_curve_unref(c); + gchar *str = sp_svg_write_path(abp); + g_free(abp); - topmost --; - } + dstring = g_string_append(dstring, str); + g_free(str); - g_slist_free (items); + // 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(); + } - Inkscape::XML::Node *repr = sp_repr_new ("svg:path"); + topmost--; + } - // restore id - repr->setAttribute("id", id); + g_slist_free(items); - repr->setAttribute("style", style); - g_free (style); + Inkscape::XML::Document *xml_doc = sp_document_repr_doc(desktop->doc()); + Inkscape::XML::Node *repr = xml_doc->createElement("svg:path"); - repr->setAttribute("d", dstring->str); - g_string_free (dstring, TRUE); + // restore id + repr->setAttribute("id", id); - // add the new group to the group members' common parent - parent->appendChild(repr); + repr->setAttribute("style", style); + g_free(style); - // move to the position of the topmost, reduced by the number of deleted items - repr->setPosition(topmost > 0 ? topmost + 1 : 0); + repr->setAttribute("d", dstring->str); + g_string_free(dstring, TRUE); - sp_document_done (SP_DT_DOCUMENT (desktop)); + // add the new group to the group members' common parent + parent->appendChild(repr); - selection->set(repr); + // move to the position of the topmost, reduced by the number of deleted items + repr->setPosition(topmost > 0 ? topmost + 1 : 0); - Inkscape::GC::release(repr); + sp_document_done(sp_desktop_document(desktop), SP_VERB_SELECTION_COMBINE, + _("Combine")); + + selection->set(repr); + + Inkscape::GC::release(repr); } void -sp_selected_path_break_apart (void) +sp_selected_path_break_apart(void) { - SPDesktop *desktop = SP_ACTIVE_DESKTOP; - - Inkscape::Selection *selection = SP_DT_SELECTION (desktop); + SPDesktop *desktop = SP_ACTIVE_DESKTOP; + + Inkscape::Selection *selection = sp_desktop_selection(desktop); + + if (selection->isEmpty()) { + sp_desktop_message_stack(desktop)->flash(Inkscape::WARNING_MESSAGE, _("Select path(s) to break apart.")); + return; + } - if (selection->isEmpty()) { - SP_DT_MSGSTACK(desktop)->flash(Inkscape::WARNING_MESSAGE, _("Select path(s) to break apart.")); - return; - } + bool did = false; - bool did = false; + for (GSList *items = g_slist_copy((GSList *) selection->itemList()); + items != NULL; + items = items->next) { - for (GSList *items = g_slist_copy((GSList *) selection->itemList()); - items != NULL; - items = items->next) { + SPItem *item = (SPItem *) items->data; - SPItem *item = (SPItem *) items->data; + if (!SP_IS_PATH(item)) + continue; - if (!SP_IS_PATH (item)) - continue; + SPPath *path = SP_PATH(item); - SPPath *path = SP_PATH (item); + SPCurve *curve = sp_shape_get_curve(SP_SHAPE(path)); + if (curve == NULL) + continue; - SPCurve *curve = sp_shape_get_curve (SP_SHAPE (path)); - if (curve == NULL) - continue; + did = true; - did = true; + Inkscape::XML::Node *parent = SP_OBJECT_REPR(item)->parent(); + gint pos = SP_OBJECT_REPR(item)->position(); + char const *id = SP_OBJECT_REPR(item)->attribute("id"); - Inkscape::XML::Node *parent = SP_OBJECT_REPR (item)->parent(); - gint pos = SP_OBJECT_REPR (item)->position(); - char const *id = SP_OBJECT_REPR (item)->attribute("id"); + gchar *style = g_strdup(SP_OBJECT(item)->repr->attribute("style")); - gchar *style = g_strdup (SP_OBJECT (item)->repr->attribute("style")); + NArtBpath *abp = nr_artpath_affine(SP_CURVE_BPATH(curve), (SP_ITEM(path))->transform); - NArtBpath *abp = nr_artpath_affine (curve->bpath, (SP_ITEM (path))->transform); + sp_curve_unref(curve); - sp_curve_unref (curve); + // it's going to resurrect as one of the pieces, so we delete without advertisement + SP_OBJECT(item)->deleteObject(false); - // 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); - curve = sp_curve_new_from_bpath (abp); - g_assert (curve != NULL); + GSList *list = sp_curve_split(curve); - GSList *list = sp_curve_split (curve); + sp_curve_unref(curve); - sp_curve_unref (curve); + GSList *reprs = NULL; + for (GSList *l = list; l != NULL; l = l->next) { + curve = (SPCurve *) l->data; - for (GSList *l = g_slist_reverse(list); l != NULL; l = l->next) { - curve = (SPCurve *) l->data; + Inkscape::XML::Node *repr = parent->document()->createElement("svg:path"); + repr->setAttribute("style", style); - Inkscape::XML::Node *repr = sp_repr_new ("svg:path"); - repr->setAttribute("style", style); + gchar *str = sp_svg_write_path(SP_CURVE_BPATH(curve)); + repr->setAttribute("d", str); + g_free(str); - 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); - // add the new repr to the parent - parent->appendChild(repr); + // move to the saved position + repr->setPosition(pos > 0 ? pos : 0); - // 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); - // if it's the first one, restore id - if (l == list) - repr->setAttribute("id", id); + reprs = g_slist_prepend (reprs, repr); - selection->add(repr); + Inkscape::GC::release(repr); + } - Inkscape::GC::release(repr); - } + selection->setReprList(reprs); - g_slist_free (list); - g_free (style); + g_slist_free(reprs); + 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, _("No path(s) to break apart in the selection.")); - return; - } + if (did) { + sp_document_done(sp_desktop_document(desktop), SP_VERB_SELECTION_BREAK_APART, + _("Break apart")); + } else { + sp_desktop_message_stack(desktop)->flash(Inkscape::ERROR_MESSAGE, _("No path(s) 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_curves(void) { - sp_selected_path_to_curves0(TRUE, SP_TOCURVE_INTERACTIVE); + sp_selected_path_to_curves0(TRUE, SP_TOCURVE_INTERACTIVE); } static void -sp_selected_path_to_curves0 (gboolean interactive, guint32 text_grouping_policy) +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 object(s) 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 - char const *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, _("No objects to convert to path in the selection.")); - return; - } - } + SPDesktop *desktop = SP_ACTIVE_DESKTOP; + + Inkscape::Selection *selection = sp_desktop_selection(desktop); + + if (selection->isEmpty()) { + if (interactive) + sp_desktop_message_stack(desktop)->flash(Inkscape::WARNING_MESSAGE, _("Select object(s) 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 + char const *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_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 Inkscape::XML::Node * -sp_selected_item_to_curved_repr(SPItem * item, guint32 text_grouping_policy) +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; + 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::Document *xml_doc = SP_OBJECT_REPR(item)->document(); + Inkscape::XML::Node *repr = xml_doc->createElement("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); + + /* Mask */ + gchar *mask_str = (gchar *) SP_OBJECT_REPR(item)->attribute("mask"); + if ( mask_str ) + repr->setAttribute("mask", mask_str); + + /* Clip path */ + gchar *clip_path_str = (gchar *) SP_OBJECT_REPR(item)->attribute("clip-path"); + if ( clip_path_str ) + 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")); + + /* Definition */ + gchar *def_str = sp_svg_write_path(SP_CURVE_BPATH(curve)); + repr->setAttribute("d", def_str); + g_free(def_str); + sp_curve_unref(curve); + return repr; } void -sp_selected_path_reverse () +sp_selected_path_reverse() { - SPDesktop *desktop = SP_ACTIVE_DESKTOP; - - Inkscape::Selection *selection = SP_DT_SELECTION (desktop); - GSList *items = (GSList *) selection->itemList(); + SPDesktop *desktop = SP_ACTIVE_DESKTOP; - if (g_slist_length (items) == 0) { - SP_DT_MSGSTACK(desktop)->flash(Inkscape::WARNING_MESSAGE, _("Select path(s) to reverse.")); - return; - } + Inkscape::Selection *selection = sp_desktop_selection(desktop); + GSList *items = (GSList *) selection->itemList(); + if (!items) { + sp_desktop_message_stack(desktop)->flash(Inkscape::WARNING_MESSAGE, _("Select path(s) to reverse.")); + return; + } - bool did = false; - for (GSList *i = items; i != NULL; i = i->next) { - if (!SP_IS_SHAPE (items->data)) - continue; + bool did = false; + for (GSList *i = items; i != NULL; i = i->next) { - did = true; - SPShape *shape = SP_SHAPE (items->data); + if (!SP_IS_SHAPE(i->data)) + continue; - SPCurve *rcurve = sp_curve_reverse (shape->curve); + did = true; + SPShape *shape = SP_SHAPE(i->data); - char *str = sp_svg_write_path (rcurve->bpath); - SP_OBJECT_REPR (shape)->setAttribute("d", str); + SPCurve *rcurve = sp_curve_reverse(shape->curve); - sp_curve_unref (rcurve); - } + gchar *str = sp_svg_write_path(SP_CURVE_BPATH(rcurve)); + SP_OBJECT_REPR(shape)->setAttribute("d", str); + g_free(str); - if (did) { - sp_document_done (SP_DT_DOCUMENT (desktop)); - } else { - SP_DT_MSGSTACK(desktop)->flash(Inkscape::ERROR_MESSAGE, _("No paths to reverse in the selection.")); - } + sp_curve_unref(rcurve); + } + + if (did) { + sp_document_done(sp_desktop_document(desktop), SP_VERB_SELECTION_REVERSE, + _("Reverse path")); + } else { + sp_desktop_message_stack(desktop)->flash(Inkscape::ERROR_MESSAGE, _("No paths to reverse in the selection.")); + } } + +/* + 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 :