Esempio n. 1
0
void
sp_selected_path_combine(SPDesktop *desktop)
{
    Inkscape::Selection *selection = desktop->getSelection();
    SPDocument *doc = desktop->getDocument();

    std::vector<SPItem*> items(selection->itemList());
    
    if (items.size() < 1) {
        desktop->getMessageStack()->flash(Inkscape::WARNING_MESSAGE, _("Select <b>object(s)</b> to combine."));
        return;
    }

    desktop->messageStack()->flash(Inkscape::IMMEDIATE_MESSAGE, _("Combining paths..."));
    // set "busy" cursor
    desktop->setWaitingCursor();

    items = sp_degroup_list (items); // descend into any groups in selection

    std::vector<SPItem*> to_paths;
    for (std::vector<SPItem*>::const_reverse_iterator i = items.rbegin(); i != items.rend(); ++i) {
        if (!dynamic_cast<SPPath *>(*i) && !dynamic_cast<SPGroup *>(*i)) {
            to_paths.push_back(*i);
        }
    }
    std::vector<Inkscape::XML::Node*> converted;
    bool did = sp_item_list_to_curves(to_paths, items, converted);
    for (std::vector<Inkscape::XML::Node*>::const_iterator i = converted.begin(); i != converted.end(); ++i)
        items.push_back((SPItem*)doc->getObjectByRepr(*i));

    items = sp_degroup_list (items); // converting to path may have added more groups, descend again

    sort(items.begin(),items.end(),less_than_items);
    assert(!items.empty()); // cannot be NULL because of list length check at top of function

    // 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;
    char const *style = NULL;
    char const *path_effect = NULL;

    SPCurve* curve = NULL;
    SPItem *first = NULL;
    Inkscape::XML::Node *parent = NULL; 

    if (did) {
        selection->clear();
    }

    for (std::vector<SPItem*>::const_reverse_iterator i = items.rbegin(); i != items.rend(); ++i){

        SPItem *item = *i;
        SPPath *path = dynamic_cast<SPPath *>(item);
        if (!path) {
            continue;
        }

        if (!did) {
            selection->clear();
            did = true;
        }

        SPCurve *c = path->get_curve_for_edit();
        if (first == NULL) {  // this is the topmost path
            first = item;
            parent = first->getRepr()->parent();
            position = first->getRepr()->position();
            id = first->getRepr()->attribute("id");
            transform = first->getRepr()->attribute("transform");
            // FIXME: merge styles of combined objects instead of using the first one's style
            style = first->getRepr()->attribute("style");
            path_effect = first->getRepr()->attribute("inkscape:path-effect");
            //c->transform(item->transform);
            curve = c;
        } else {
            c->transform(item->getRelativeTransform(first));
            curve->append(c, false);
            c->unref();

            // reduce position only if the same parent
            if (item->getRepr()->parent() == parent) {
                position--;
            }
            // delete the object for real, so that its clones can take appropriate action
            item->deleteObject();
        }
    }


    if (did) {
        first->deleteObject(false);
        // delete the topmost.

        Inkscape::XML::Document *xml_doc = desktop->doc()->getReprDoc();
        Inkscape::XML::Node *repr = xml_doc->createElement("svg:path");

        // restore id, transform, path effect, and style
        repr->setAttribute("id", id);
        if (transform) {
            repr->setAttribute("transform", transform);
        }
        repr->setAttribute("style", style);

        repr->setAttribute("inkscape:path-effect", path_effect);

        // set path data corresponding to new curve
        gchar *dstring = sp_svg_write_path(curve->get_pathvector());
        curve->unref();
        if (path_effect) {
            repr->setAttribute("inkscape:original-d", dstring);
        } else {
            repr->setAttribute("d", dstring);
        }
        g_free(dstring);

        // add the new group to the parent of the topmost
        parent->appendChild(repr);

        // move to the position of the topmost, reduced by the number of deleted items
        repr->setPosition(position > 0 ? position : 0);

        DocumentUndo::done(desktop->getDocument(), SP_VERB_SELECTION_COMBINE, 
                           _("Combine"));

        selection->set(repr);

        Inkscape::GC::release(repr);

    } else {
        desktop->getMessageStack()->flash(Inkscape::ERROR_MESSAGE, _("<b>No path(s)</b> to combine in the selection."));
    }

    desktop->clearWaitingCursor();
}
void
sp_selected_path_break_apart(SPDesktop *desktop)
{
    Inkscape::Selection *selection = sp_desktop_selection(desktop);

    if (selection->isEmpty()) {
        sp_desktop_message_stack(desktop)->flash(Inkscape::WARNING_MESSAGE, _("Select <b>path(s)</b> to break apart."));
        return;
    }

    desktop->messageStack()->flash(Inkscape::IMMEDIATE_MESSAGE, _("Breaking apart paths..."));
    // set "busy" cursor
    desktop->setWaitingCursor();

    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 = path->get_curve_for_edit();
        if (curve == NULL) {
            continue;
        }

        did = true;

        Inkscape::XML::Node *parent = item->getRepr()->parent();
        gint pos = item->getRepr()->position();
        char const *id = item->getRepr()->attribute("id");

        // XML Tree being used directly here while it shouldn't be...
        gchar *style = g_strdup(item->getRepr()->attribute("style"));
        // XML Tree being used directly here while it shouldn't be...
        gchar *path_effect = g_strdup(item->getRepr()->attribute("inkscape:path-effect"));

        Geom::PathVector apv = curve->get_pathvector() * path->transform;

        curve->unref();

        // it's going to resurrect as one of the pieces, so we delete without advertisement
        item->deleteObject(false);

        curve = new SPCurve(apv);
        g_assert(curve != NULL);

        GSList *list = curve->split();

        curve->unref();

        GSList *reprs = NULL;
        for (GSList *l = list; l != NULL; l = l->next) {
            curve = (SPCurve *) l->data;

            Inkscape::XML::Node *repr = parent->document()->createElement("svg:path");
            repr->setAttribute("style", style);

            repr->setAttribute("inkscape:path-effect", path_effect);

            gchar *str = sp_svg_write_path(curve->get_pathvector());
            if (path_effect)
                repr->setAttribute("inkscape:original-d", str);
            else
                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);

            reprs = g_slist_prepend (reprs, repr);

            Inkscape::GC::release(repr);
        }

        selection->setReprList(reprs);

        g_slist_free(reprs);
        g_slist_free(list);
        g_free(style);
        g_free(path_effect);
    }

    desktop->clearWaitingCursor();

    if (did) {
        DocumentUndo::done(sp_desktop_document(desktop), SP_VERB_SELECTION_BREAK_APART, 
                           _("Break apart"));
    } else {
        sp_desktop_message_stack(desktop)->flash(Inkscape::ERROR_MESSAGE, _("<b>No path(s)</b> to break apart in the selection."));
    }
}
Esempio n. 3
0
void
sp_selected_path_break_apart(SPDesktop *desktop, bool skip_undo)
{
    Inkscape::Selection *selection = desktop->getSelection();

    if (selection->isEmpty()) {
        desktop->getMessageStack()->flash(Inkscape::WARNING_MESSAGE, _("Select <b>path(s)</b> to break apart."));
        return;
    }

    desktop->messageStack()->flash(Inkscape::IMMEDIATE_MESSAGE, _("Breaking apart paths..."));
    // set "busy" cursor
    desktop->setWaitingCursor();

    bool did = false;

    std::vector<SPItem*> itemlist(selection->itemList());
    for (std::vector<SPItem*>::const_iterator i = itemlist.begin(); i != itemlist.end(); ++i){

        SPItem *item = *i;

        SPPath *path = dynamic_cast<SPPath *>(item);
        if (!path) {
            continue;
        }

        SPCurve *curve = path->get_curve_for_edit();
        if (curve == NULL) {
            continue;
        }
        did = true;

        Inkscape::XML::Node *parent = item->getRepr()->parent();
        gint pos = item->getRepr()->position();
        char const *id = item->getRepr()->attribute("id");

        // XML Tree being used directly here while it shouldn't be...
        gchar *style = g_strdup(item->getRepr()->attribute("style"));
        // XML Tree being used directly here while it shouldn't be...
        gchar *path_effect = g_strdup(item->getRepr()->attribute("inkscape:path-effect"));
        Geom::Affine transform = path->transform;
        // it's going to resurrect as one of the pieces, so we delete without advertisement
        item->deleteObject(false);


        GSList *list = curve->split();

        curve->unref();

        std::vector<Inkscape::XML::Node*> reprs;
        for (GSList *l = list; l != NULL; l = l->next) {
            curve = (SPCurve *) l->data;

            Inkscape::XML::Node *repr = parent->document()->createElement("svg:path");
            repr->setAttribute("style", style);

            repr->setAttribute("inkscape:path-effect", path_effect);

            gchar *str = sp_svg_write_path(curve->get_pathvector());
            if (path_effect)
                repr->setAttribute("inkscape:original-d", str);
            else
                repr->setAttribute("d", str);
            g_free(str);
            repr->setAttribute("transform", sp_svg_transform_write(transform));
            
            // 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);

            reprs.push_back(repr);

            Inkscape::GC::release(repr);
        }
        selection->setReprList(reprs);

        g_slist_free(list);
        g_free(style);
        g_free(path_effect);
    }

    desktop->clearWaitingCursor();

    if (did) {
        if ( !skip_undo ) {
            DocumentUndo::done(desktop->getDocument(), SP_VERB_SELECTION_BREAK_APART, 
                               _("Break apart"));
        }
    } else {
        desktop->getMessageStack()->flash(Inkscape::ERROR_MESSAGE, _("<b>No path(s)</b> to break apart in the selection."));
    }
}