From 4d0239401455512530d186ecd6b5e26dda3653e8 Mon Sep 17 00:00:00 2001 From: johanengelen Date: Tue, 9 Oct 2007 18:05:31 +0000 Subject: [PATCH] apply John Cliff's patch [ 1743843 ] Create Marker from Selection Menu Item --- src/marker.cpp | 35 +++++++++++++++++ src/marker.h | 2 + src/menus-skeleton.h | 1 + src/selection-chemistry.cpp | 77 +++++++++++++++++++++++++++++++++++++ src/selection-chemistry.h | 3 ++ src/verbs.cpp | 6 +++ src/verbs.h | 1 + 7 files changed, 125 insertions(+) diff --git a/src/marker.cpp b/src/marker.cpp index 1fb758462..5cc63d9d7 100644 --- a/src/marker.cpp +++ b/src/marker.cpp @@ -26,6 +26,7 @@ #include "attributes.h" #include "marker.h" #include "document.h" +#include "document-private.h" struct SPMarkerView { SPMarkerView *next; @@ -713,3 +714,37 @@ sp_marker_view_remove (SPMarker *marker, SPMarkerView *view, unsigned int destro } g_free (view); } + +const gchar * +generate_marker (GSList *reprs, NR::Rect bounds, SPDocument *document, NR::Matrix transform, NR::Matrix move) +{ + Inkscape::XML::Document *xml_doc = sp_document_repr_doc(document); + Inkscape::XML::Node *defsrepr = SP_OBJECT_REPR (SP_DOCUMENT_DEFS (document)); + + Inkscape::XML::Node *repr = xml_doc->createElement("svg:marker"); + repr->setAttribute("markerUnits", "userSpaceOnUse"); + sp_repr_set_svg_double(repr, "markerWidth", bounds.extent(NR::X)); + sp_repr_set_svg_double(repr, "markerHeight", bounds.extent(NR::Y)); + + repr->setAttribute("orient", "auto"); + + + defsrepr->appendChild(repr); + const gchar *mark_id = repr->attribute("id"); + SPObject *mark_object = document->getObjectById(mark_id); + + for (GSList *i = reprs; i != NULL; i = i->next) { + Inkscape::XML::Node *node = (Inkscape::XML::Node *)(i->data); + SPItem *copy = SP_ITEM(mark_object->appendChildRepr(node)); + + NR::Matrix dup_transform; + if (!sp_svg_transform_read (node->attribute("transform"), &dup_transform)) + dup_transform = NR::identity(); + dup_transform *= move; + + sp_item_write_transform(copy, SP_OBJECT_REPR(copy), dup_transform); + } + + Inkscape::GC::release(repr); + return mark_id; +} diff --git a/src/marker.h b/src/marker.h index 1fba52d36..ef8fcd583 100644 --- a/src/marker.h +++ b/src/marker.h @@ -89,5 +89,7 @@ NRArenaItem *sp_marker_show_instance (SPMarker *marker, NRArenaItem *parent, unsigned int key, unsigned int pos, NR::Matrix const &base, float linewidth); void sp_marker_hide (SPMarker *marker, unsigned int key); +const gchar *generate_marker (GSList *reprs, NR::Rect bounds, SPDocument *document, NR::Matrix transform, NR::Matrix move); + #endif diff --git a/src/menus-skeleton.h b/src/menus-skeleton.h index 97b9a34ad..71c07e1f9 100644 --- a/src/menus-skeleton.h +++ b/src/menus-skeleton.h @@ -175,6 +175,7 @@ static char const menus_skeleton[] = " \n" " \n" " \n" +" \n" " \n" " \n" " \n" diff --git a/src/selection-chemistry.cpp b/src/selection-chemistry.cpp index 0d7654bb1..ec4f096dd 100644 --- a/src/selection-chemistry.cpp +++ b/src/selection-chemistry.cpp @@ -2272,6 +2272,83 @@ sp_select_clone_original() } } + +void sp_selection_to_marker(bool apply) +{ + SPDesktop *desktop = SP_ACTIVE_DESKTOP; + if (desktop == NULL) + return; + + SPDocument *doc = sp_desktop_document(desktop); + Inkscape::XML::Document *xml_doc = sp_document_repr_doc(doc); + + Inkscape::Selection *selection = sp_desktop_selection(desktop); + + // check if something is selected + if (selection->isEmpty()) { + desktop->messageStack()->flash(Inkscape::WARNING_MESSAGE, _("Select object(s) to convert to marker.")); + return; + } + + sp_document_ensure_up_to_date(doc); + NR::Maybe r = selection->bounds(); + if ( !r || r->isEmpty() ) { + return; + } + + // calculate the transform to be applied to objects to move them to 0,0 + NR::Point move_p = NR::Point(0, sp_document_height(doc)) - (r->min() + NR::Point ((r->extent(NR::X))/2, (r->extent(NR::Y))/2)); + move_p[NR::Y] = -move_p[NR::Y]; + NR::Matrix move = NR::Matrix (NR::translate (move_p)); + + GSList *items = g_slist_copy((GSList *) selection->itemList()); + + items = g_slist_sort (items, (GCompareFunc) sp_object_compare_position); + + // bottommost object, after sorting + SPObject *parent = SP_OBJECT_PARENT (items->data); + + NR::Matrix parent_transform = sp_item_i2root_affine(SP_ITEM(parent)); + + // remember the position of the first item + gint pos = SP_OBJECT_REPR (items->data)->position(); + + // create a list of duplicates + GSList *repr_copies = NULL; + for (GSList *i = items; i != NULL; i = i->next) { + Inkscape::XML::Node *dup = (SP_OBJECT_REPR (i->data))->duplicate(xml_doc); + repr_copies = g_slist_prepend (repr_copies, dup); + } + + NR::Rect bounds(desktop->dt2doc(r->min()), desktop->dt2doc(r->max())); + + if (apply) { + // delete objects so that their clones don't get alerted; this object will be restored shortly + for (GSList *i = items; i != NULL; i = i->next) { + SPObject *item = SP_OBJECT (i->data); + item->deleteObject (false); + } + } + + // Hack: Temporarily set clone compensation to unmoved, so that we can move clone-originals + // without disturbing clones. + // See ActorAlign::on_button_click() in src/ui/dialog/align-and-distribute.cpp + int saved_compensation = prefs_get_int_attribute("options.clonecompensation", "value", SP_CLONE_COMPENSATION_UNMOVED); + prefs_set_int_attribute("options.clonecompensation", "value", SP_CLONE_COMPENSATION_UNMOVED); + + const gchar *mark_id = generate_marker (repr_copies, bounds, doc, + NR::Matrix(NR::translate(desktop->dt2doc(NR::Point(r->min()[NR::X], r->max()[NR::Y])))) * parent_transform.inverse(), parent_transform * move); + + // restore compensation setting + prefs_set_int_attribute("options.clonecompensation", "value", saved_compensation); + + + g_slist_free (items); + + sp_document_done (doc, SP_VERB_EDIT_SELECTION_2_MARKER, + _("Objects to marker")); +} + void sp_selection_tile(bool apply) { diff --git a/src/selection-chemistry.h b/src/selection-chemistry.h index a132161ef..9313711cf 100644 --- a/src/selection-chemistry.h +++ b/src/selection-chemistry.h @@ -35,6 +35,8 @@ void sp_selection_clone(); void sp_selection_unlink(); void sp_select_clone_original (); +void sp_selection_to_marker(bool apply = true); + void sp_selection_tile(bool apply = true); void sp_selection_untile(); @@ -127,3 +129,4 @@ SPCycleType SP_CYCLING = SP_CYCLE_FOCUS; #endif + diff --git a/src/verbs.cpp b/src/verbs.cpp index e49263ede..a84500c44 100644 --- a/src/verbs.cpp +++ b/src/verbs.cpp @@ -930,6 +930,9 @@ EditVerb::perform(SPAction *action, void *data, void *pdata) case SP_VERB_EDIT_CLONE_ORIGINAL: sp_select_clone_original(); break; + case SP_VERB_EDIT_SELECTION_2_MARKER: + sp_selection_to_marker(); + break; case SP_VERB_EDIT_TILE: sp_selection_tile(); break; @@ -2218,6 +2221,9 @@ Verb *Verb::_base_verbs[] = { N_("Cut the selected clone's link to its original, turning it into a standalone object"), "edit_unlink_clone"), new EditVerb(SP_VERB_EDIT_CLONE_ORIGINAL, "EditCloneOriginal", N_("Select _Original"), N_("Select the object to which the selected clone is linked"), "edit_select_original"), + // TRANSLATORS: Convert selection to a line marker + new EditVerb(SP_VERB_EDIT_SELECTION_2_MARKER, "ObjectsToMarker", N_("Objects to _Marker"), + N_("Convert selection to a line marker"), NULL), // TRANSLATORS: Convert selection to a rectangle with tiled pattern fill new EditVerb(SP_VERB_EDIT_TILE, "ObjectsToPattern", N_("Objects to Patter_n"), N_("Convert selection to a rectangle with tiled pattern fill"), NULL), diff --git a/src/verbs.h b/src/verbs.h index 48bf89825..34a633b2f 100644 --- a/src/verbs.h +++ b/src/verbs.h @@ -67,6 +67,7 @@ enum { SP_VERB_EDIT_CLONE, SP_VERB_EDIT_UNLINK_CLONE, SP_VERB_EDIT_CLONE_ORIGINAL, + SP_VERB_EDIT_SELECTION_2_MARKER, SP_VERB_EDIT_TILE, SP_VERB_EDIT_UNTILE, SP_VERB_EDIT_CLEAR_ALL, -- 2.30.2