sp-use.cpp revision 270b69ca36e41cd79cebee871d1ca4e8c7b75539
/*
* SVG <use> implementation
*
* Authors:
* Lauris Kaplinski <lauris@kaplinski.com>
* bulia byak <buliabyak@users.sf.net>
* Jon A. Cruz <jon@joncruz.org>
* Abhishek Sharma
*
* Copyright (C) 1999-2005 authors
* Copyright (C) 2000-2001 Ximian, Inc.
*
* Released under GNU GPL, read the file 'COPYING' for more information
*/
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include <cstring>
#include <string>
#include "display/drawing-group.h"
#include "attributes.h"
#include "document.h"
#include "sp-factory.h"
#include "sp-flowregion.h"
#include "uri.h"
#include "print.h"
#include "preferences.h"
#include "style.h"
#include "sp-symbol.h"
#include "sp-use.h"
#include "sp-use-reference.h"
namespace {
return new SPUse();
}
}
: SPItem()
, ref(new SPUseReference(this))
{
this->x.unset();
this->y.unset();
);
}
if (this->child) {
}
delete this->ref;
this->ref = 0;
}
this->readAttr( "x" );
this->readAttr( "y" );
this->readAttr( "width" );
this->readAttr( "height" );
this->readAttr( "xlink:href" );
// We don't need to create child here:
// reading xlink:href will attach ref, and that will cause the changed signal to be emitted,
// which will call sp_use_href_changed, and that will take care of the child
}
if (this->child) {
}
this->_delete_connection.disconnect();
this->_changed_connection.disconnect();
this->_transformed_connection.disconnect();
}
switch (key) {
case SP_ATTR_X:
this->x.readOrUnset(value);
break;
case SP_ATTR_Y:
this->y.readOrUnset(value);
break;
case SP_ATTR_WIDTH:
break;
case SP_ATTR_HEIGHT:
break;
case SP_ATTR_XLINK_HREF: {
/* No change, do nothing. */
} else {
if (value) {
// First, set the href field, because sp_use_href_changed will need it.
// Now do the attaching, which emits the changed signal.
try {
} catch (Inkscape::BadURIException &e) {
}
} else {
}
}
break;
}
default:
break;
}
}
Inkscape::XML::Node* SPUse::write(Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, guint flags) {
}
}
return repr;
}
if (this->child) {
Geom::Affine const ct(child->transform * Geom::Translate(this->x.computed, this->y.computed) * transform );
}
return bbox;
}
bool translated = false;
translated = true;
}
if (this->child) {
}
if (translated) {
}
}
const char* SPUse::displayName() const {
return _("Symbol");
}
return _("Clone");
}
if (this->child) {
if( SP_IS_SYMBOL( this->child ) ) {
}
static unsigned recursion_depth = 0;
if (recursion_depth >= 4) {
/* TRANSLATORS: Used for statusbar description for long <use> chains:
* "Clone of: Clone of: ... in Layer 1". */
return g_strdup(_("..."));
/* We could do better, e.g. chasing the href chain until we reach something other than
* a <use>, and giving its description. */
}
return ret;
} else {
return g_strdup(_("[orphaned]"));
}
}
Inkscape::DrawingItem* SPUse::show(Inkscape::Drawing &drawing, unsigned int key, unsigned int flags) {
ai->setPickChildren(false);
if (this->child) {
if (ac) {
}
ai->setChildTransform(t);
}
return ai;
}
if (this->child) {
}
// SPItem::onHide(key);
}
/**
* Returns the ultimate original of a SPUse (i.e. the first object in the chain of its originals
* which is not an SPUse). If no original is found, NULL is returned (it is the responsibility
* of the caller to make sure that this is handled correctly).
*
* Note that the returned is the clone object, i.e. the child of an SPUse (of the argument one for
* the trivial case) and not the "true original".
*/
}
if (!orig) {
return NULL;
}
return orig;
}
}
/**
* Get the number of dereferences or calls to get_original() needed to get an object
* which is not an svg:use. Returns -1 if there is no original object.
*/
int SPUse::cloneDepth() const {
unsigned depth = 1;
++depth;
}
if (!orig) return -1;
return depth;
}
/**
* Returns the effective transform that goes from the ultimate original to given SPUse, both ends
* included.
*/
//track the ultimate source of a chain of uses
}
// calculate the accummulated transform, starting from the original
// "An additional transformation translate(x,y) is appended to the end (i.e.,
// right-side) of the transform attribute on the generated 'g', where x and y
// represent the values of the x and y attributes on the 'use' element." - http://www.w3.org/TR/SVG11/struct.html#UseElement
t = t * Geom::Translate(i_use->x._set ? i_use->x.computed : 0, i_use->y._set ? i_use->y.computed : 0);
}
}
}
return t;
}
/**
* Returns the transform that leads to the use from its immediate original.
* Does not inlcude the original's transform if any.
*/
}
t *= this->transform;
return t;
}
/**
* Sensing a movement of the original, this function attempts to compensate for it in such a way
* that the clone stays unmoved or moves in parallel (depending on user setting) regardless of the
* clone's transform.
*/
// the clone is orphaned; or this is not a real use, but a clone of another use;
// we skip it, otherwise duplicate compensation will occur
if (this->cloned) {
return;
}
// never compensate uses which are used in flowtext
return;
}
// user wants no compensation
if (mode == SP_CLONE_COMPENSATION_NONE)
return;
// this is not a simple move, do not try to compensate
if (!(m.isTranslation()))
return;
// restore item->transform field from the repr, in case it was changed by seltrans
this->readAttr ("transform");
// calculate the compensation matrix and the advertized movement matrix
if (mode == SP_CLONE_COMPENSATION_PARALLEL) {
advertized_move = m;
} else if (mode == SP_CLONE_COMPENSATION_UNMOVED) {
} else {
}
// commit the compensation
this->transform *= clone_move;
}
void SPUse::href_changed() {
this->_delete_connection.disconnect();
this->_transformed_connection.disconnect();
if (this->child) {
}
if (this->href) {
if (refobj) {
if (SP_IS_ITEM(obj)) {
sp_object_unref(this->child, this);
if (ai) {
}
}
} else {
delete obj;
g_warning("Tried to create svg:use from invalid object");
}
);
);
}
}
}
void SPUse::delete_self() {
// always delete uses which are used in flowtext
this->deleteObject();
return;
}
if (mode == SP_CLONE_ORPHANS_UNLINK) {
this->unlink();
} else if (mode == SP_CLONE_ORPHANS_DELETE) {
this->deleteObject();
}
}
unsigned childflags = flags;
if (flags & SP_OBJECT_MODIFIED_FLAG) {
}
/* Set up child viewport */
}
}
}
}
if (this->child) {
sp_object_ref(this->child);
if (childflags || (this->child->uflags & (SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_CHILD_MODIFIED_FLAG))) {
}
sp_object_unref(this->child);
}
if (flags & SP_OBJECT_STYLE_MODIFIED_FLAG) {
}
}
/* As last step set additional transform of arena group */
g->setChildTransform(t);
}
}
if (flags & SP_OBJECT_MODIFIED_FLAG) {
}
if (flags & SP_OBJECT_STYLE_MODIFIED_FLAG) {
}
}
if (child) {
}
}
}
if (!repr) {
return NULL;
}
// Track the ultimate source of a chain of uses.
if (!orig) {
return NULL;
}
// Calculate the accumulated transform, starting from the original.
for (Inkscape::XML::Node *child = orig->getRepr()->firstChild() ; child != NULL; child = child->next()) {
}
} else { // just copy
}
// Add the duplicate repr just after the existing one.
// Retrieve the SPItem of the resulting repr.
// Merge style from the use.
unlinked->updateRepr();
// Hold onto our SPObject and repr for now.
sp_object_ref(this, NULL);
// Remove ourselves, not propagating delete events to avoid a
// chain-reaction with other elements that might reference us.
this->deleteObject(false);
// Give the copy our old id and let go of our old repr.
// Remove tiled clone attrs.
// Establish the succession and let go of our object.
this->setSuccessor(unlinked);
sp_object_unref(this, NULL);
// Set the accummulated transform.
{
// Advertise ourselves as not moving.
}
return item;
}
if (this->ref){
}
return ref;
}
void SPUse::snappoints(std::vector<Inkscape::SnapCandidatePoint> &p, Inkscape::SnapPreferences const *snapprefs) const {
if (!root) {
return;
}
}
/*
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 :