void sp_select_context_up_one_layer(SPDesktop *desktop) { /* Click in empty place, go up one level -- but don't leave a layer to root. * * (Rationale: we don't usually allow users to go to the root, since that * detracts from the layer metaphor: objects at the root level can in front * of or behind layers. Whereas it's fine to go to the root if editing * a document that has no layers (e.g. a non-Inkscape document).) * * Once we support editing SVG "islands" (e.g. <svg> embedded in an xhtml * document), we might consider further restricting the below to disallow * leaving a layer to go to a non-layer. */ SPObject *const current_layer = desktop->currentLayer(); if (current_layer) { SPObject *const parent = SP_OBJECT_PARENT(current_layer); if ( parent && ( SP_OBJECT_PARENT(parent) || !( SP_IS_GROUP(current_layer) && ( SPGroup::LAYER == SP_GROUP(current_layer)->layerMode() ) ) ) ) { desktop->setCurrentLayer(parent); if (SP_IS_GROUP(current_layer) && SPGroup::LAYER != SP_GROUP(current_layer)->layerMode()) sp_desktop_selection(desktop)->set(current_layer); } } }
static void sp_item_create_link(GtkMenuItem *menuitem, SPItem *item) { g_assert(SP_IS_ITEM(item)); g_assert(!SP_IS_ANCHOR(item)); SPDesktop *desktop = (SPDesktop*)gtk_object_get_data(GTK_OBJECT(menuitem), "desktop"); g_return_if_fail(desktop != NULL); Inkscape::XML::Document *xml_doc = sp_document_repr_doc(desktop->doc()); Inkscape::XML::Node *repr = xml_doc->createElement("svg:a"); SP_OBJECT_REPR(SP_OBJECT_PARENT(item))->addChild(repr, SP_OBJECT_REPR(item)); SPObject *object = SP_OBJECT_DOCUMENT(item)->getObjectByRepr(repr); g_return_if_fail(SP_IS_ANCHOR(object)); const char *id = SP_OBJECT_REPR(item)->attribute("id"); Inkscape::XML::Node *child = SP_OBJECT_REPR(item)->duplicate(xml_doc); SP_OBJECT(item)->deleteObject(false); repr->addChild(child, NULL); child->setAttribute("id", id); Inkscape::GC::release(repr); Inkscape::GC::release(child); sp_document_done(SP_OBJECT_DOCUMENT(object), SP_VERB_NONE, _("Create link")); sp_object_attributes_dialog(object, "SPAnchor"); sp_desktop_selection(desktop)->set(SP_ITEM(object)); }
void sp_textpath_to_text(SPObject *tp) { SPObject *text = SP_OBJECT_PARENT(tp); NRRect bbox; sp_item_invoke_bbox(SP_ITEM(text), &bbox, sp_item_i2doc_affine(SP_ITEM(text)), TRUE); Geom::Point xy(bbox.x0, bbox.y0); // make a list of textpath children GSList *tp_reprs = NULL; for (SPObject *o = SP_OBJECT(tp)->firstChild() ; o != NULL; o = o->next) { tp_reprs = g_slist_prepend(tp_reprs, SP_OBJECT_REPR(o)); } for ( GSList *i = tp_reprs ; i ; i = i->next ) { // make a copy of each textpath child Inkscape::XML::Node *copy = ((Inkscape::XML::Node *) i->data)->duplicate(SP_OBJECT_REPR(text)->document()); // remove the old repr from under textpath SP_OBJECT_REPR(tp)->removeChild((Inkscape::XML::Node *) i->data); // put its copy under text SP_OBJECT_REPR(text)->addChild(copy, NULL); // fixme: copy id } //remove textpath tp->deleteObject(); g_slist_free(tp_reprs); // set x/y on text /* fixme: Yuck, is this really the right test? */ if (xy[Geom::X] != 1e18 && xy[Geom::Y] != 1e18) { sp_repr_set_svg_double(SP_OBJECT_REPR(text), "x", xy[Geom::X]); sp_repr_set_svg_double(SP_OBJECT_REPR(text), "y", xy[Geom::Y]); } }
static void sp_tspan_bbox(SPItem const *item, NRRect *bbox, Geom::Matrix const &transform, unsigned const /*flags*/) { // find out the ancestor text which holds our layout SPObject *parent_text = SP_OBJECT(item); for (; parent_text != NULL && !SP_IS_TEXT(parent_text); parent_text = SP_OBJECT_PARENT (parent_text)){}; if (parent_text == NULL) return; // get the bbox of our portion of the layout SP_TEXT(parent_text)->layout.getBoundingBox(bbox, transform, sp_text_get_length_upto(parent_text, item), sp_text_get_length_upto(item, NULL) - 1); // Add stroke width SPStyle* style=SP_OBJECT_STYLE (item); if (!style->stroke.isNone()) { double const scale = transform.descrim(); if ( fabs(style->stroke_width.computed * scale) > 0.01 ) { // sinon c'est 0=oon veut pas de bord double const width = MAX(0.125, style->stroke_width.computed * scale); if ( fabs(bbox->x1 - bbox->x0) > -0.00001 && fabs(bbox->y1 - bbox->y0) > -0.00001 ) { bbox->x0-=0.5*width; bbox->x1+=0.5*width; bbox->y0-=0.5*width; bbox->y1+=0.5*width; } } } }
static void sp_gradient_context_add_stops_between_selected_stops (SPGradientContext *rc) { SPDocument *doc = NULL; GrDrag *drag = rc->_grdrag; GSList *these_stops = NULL; GSList *next_stops = NULL; std::vector<Geom::Point> coords = sp_gradient_context_get_stop_intervals (drag, &these_stops, &next_stops); if (g_slist_length(these_stops) == 0 && drag->numSelected() == 1) { // if a single stop is selected, add between that stop and the next one GrDragger *dragger = (GrDragger *) drag->selected->data; for (GSList const* j = dragger->draggables; j != NULL; j = j->next) { GrDraggable *d = (GrDraggable *) j->data; SPGradient *gradient = sp_item_gradient (d->item, d->fill_or_stroke); SPGradient *vector = sp_gradient_get_forked_vector_if_necessary (gradient, false); SPStop *this_stop = sp_get_stop_i (vector, d->point_i); SPStop *next_stop = sp_next_stop (this_stop); if (this_stop && next_stop) { these_stops = g_slist_prepend (these_stops, this_stop); next_stops = g_slist_prepend (next_stops, next_stop); } } } // now actually create the new stops GSList *i = these_stops; GSList *j = next_stops; for (; i != NULL && j != NULL; i = i->next, j = j->next) { SPStop *this_stop = (SPStop *) i->data; SPStop *next_stop = (SPStop *) j->data; gfloat offset = 0.5*(this_stop->offset + next_stop->offset); SPObject *parent = SP_OBJECT_PARENT(this_stop); if (SP_IS_GRADIENT (parent)) { doc = SP_OBJECT_DOCUMENT (parent); sp_vector_add_stop (SP_GRADIENT (parent), this_stop, next_stop, offset); sp_gradient_ensure_vector (SP_GRADIENT (parent)); } } if (g_slist_length(these_stops) > 0 && doc) { sp_document_done (doc, SP_VERB_CONTEXT_GRADIENT, _("Add gradient stop")); drag->updateDraggers(); // so that it does not automatically update draggers in idle loop, as this would deselect drag->local_change = true; // select all the old selected and new created draggers drag->selectByCoords(coords); } g_slist_free (these_stops); g_slist_free (next_stops); }
bool LPEObjectReference::_acceptObject(SPObject * const obj) const { if (IS_LIVEPATHEFFECT(obj)) { SPObject * const owner = getOwner(); /* Refuse references to us or to an ancestor. */ for ( SPObject *iter = owner ; iter ; iter = SP_OBJECT_PARENT(iter) ) { if ( iter == obj ) { return false; } } return true; } else { return false; } }
/** Returns true iff \a item is suitable to be included in the selection, in particular whether it has a bounding box in the desktop coordinate system for rendering resize handles. Descendents of <defs> nodes (markers etc.) return false, for example. */ bool in_dt_coordsys(SPObject const &item) { /* Definition based on sp_item_i2doc_affine. */ SPObject const *child = &item; g_return_val_if_fail(child != NULL, false); for(;;) { if (!SP_IS_ITEM(child)) { return false; } SPObject const * const parent = SP_OBJECT_PARENT(child); if (parent == NULL) { break; } child = parent; } g_assert(SP_IS_ROOT(child)); /* Relevance: Otherwise, I'm not sure whether to return true or false. */ return true; }
/** * Writes the given transform into the repr for the given item. */ static void sp_path_write_transform (SPItem *item, SPRepr *repr, NRMatrixF *transform) { SPPath *path; SPShape *shape; NRBPath dpath, spath; double ex; gchar *svgpath; SPStyle *style; path = (SPPath *) item; shape = (SPShape *) item; /* Calculate the DF */ ex = NR_MATRIX_DF_EXPANSION (transform); /* Take the path for the shape, write it as an svgpath, and add it to the repr */ spath.path = shape->curve->bpath; nr_path_duplicate_transform (&dpath, &spath, transform); svgpath = sp_svg_write_path (dpath.path); sp_repr_set_attr (repr, "d", svgpath); g_free (svgpath); nr_free (dpath.path); /* Wrte the style info into the repr */ style = SP_OBJECT_STYLE (item); if (style->stroke.type != SP_PAINT_TYPE_NONE) { if (!NR_DF_TEST_CLOSE (ex, 1.0, NR_EPSILON_D)) { gchar *str; /* Scale changed, so we have to adjust stroke width */ style->stroke_width.computed *= ex; if (style->stroke_dash.n_dash != 0) { int i; for (i = 0; i < style->stroke_dash.n_dash; i++) style->stroke_dash.dash[i] *= ex; style->stroke_dash.offset *= ex; } str = sp_style_write_difference (style, SP_OBJECT_STYLE (SP_OBJECT_PARENT (item))); sp_repr_set_attr (repr, "style", str); g_free (str); } } sp_repr_set_attr (repr, "transform", NULL); }
static void GetDest(SPObject* child,Shape **computed) { if ( child == NULL ) return; SPCurve *curve=NULL; Geom::Matrix tr_mat; SPObject* u_child=child; if ( SP_IS_USE(u_child) ) { u_child=SP_USE(u_child)->child; tr_mat = SP_ITEM(u_child)->getRelativeTransform(SP_OBJECT_PARENT(child)); } else { tr_mat = SP_ITEM(u_child)->transform; } if ( SP_IS_SHAPE (u_child) ) { curve = sp_shape_get_curve (SP_SHAPE (u_child)); } else if ( SP_IS_TEXT (u_child) ) { curve = SP_TEXT (u_child)->getNormalizedBpath (); } if ( curve ) { Path* temp=new Path; temp->LoadPathVector(curve->get_pathvector(), tr_mat, true); Shape* n_shp=new Shape; temp->Convert(0.25); temp->Fill(n_shp,0); Shape* uncross=new Shape; SPStyle* style=SP_OBJECT_STYLE(u_child); if ( style && style->fill_rule.computed == SP_WIND_RULE_EVENODD ) { uncross->ConvertToShape(n_shp,fill_oddEven); } else { uncross->ConvertToShape(n_shp,fill_nonZero); } UnionShape(computed, uncross); delete uncross; delete n_shp; delete temp; curve->unref(); } else { // printf("no curve\n"); } }
void text_unflow () { SPDesktop *desktop = SP_ACTIVE_DESKTOP; if (!desktop) return; SPDocument *doc = sp_desktop_document (desktop); Inkscape::XML::Document *xml_doc = sp_document_repr_doc(doc); Inkscape::Selection *selection = sp_desktop_selection(desktop); if (!flowtext_in_selection(selection) || g_slist_length((GSList *) selection->itemList()) < 1) { sp_desktop_message_stack(desktop)->flash(Inkscape::WARNING_MESSAGE, _("Select <b>a flowed text</b> to unflow it.")); return; } GSList *new_objs = NULL; GSList *old_objs = NULL; for (GSList *items = g_slist_copy((GSList *) selection->itemList()); items != NULL; items = items->next) { if (!SP_IS_FLOWTEXT(SP_OBJECT(items->data))) { continue; } SPItem *flowtext = SP_ITEM(items->data); if (sp_te_get_string_multiline(flowtext) == NULL) { // flowtext is empty continue; } /* Create <text> */ Inkscape::XML::Node *rtext = xml_doc->createElement("svg:text"); rtext->setAttribute("xml:space", "preserve"); // we preserve spaces in the text objects we create /* Set style */ rtext->setAttribute("style", SP_OBJECT_REPR(flowtext)->attribute("style")); // fixme: transfer style attrs too; and from descendants NRRect bbox; sp_item_invoke_bbox(SP_ITEM(flowtext), &bbox, sp_item_i2doc_affine(SP_ITEM(flowtext)), TRUE); Geom::Point xy(bbox.x0, bbox.y0); if (xy[Geom::X] != 1e18 && xy[Geom::Y] != 1e18) { sp_repr_set_svg_double(rtext, "x", xy[Geom::X]); sp_repr_set_svg_double(rtext, "y", xy[Geom::Y]); } /* Create <tspan> */ Inkscape::XML::Node *rtspan = xml_doc->createElement("svg:tspan"); rtspan->setAttribute("sodipodi:role", "line"); // otherwise, why bother creating the tspan? rtext->addChild(rtspan, NULL); gchar *text_string = sp_te_get_string_multiline(flowtext); Inkscape::XML::Node *text_repr = xml_doc->createTextNode(text_string); // FIXME: transfer all formatting!!! free(text_string); rtspan->appendChild(text_repr); SP_OBJECT_REPR(SP_OBJECT_PARENT(flowtext))->appendChild(rtext); SPObject *text_object = doc->getObjectByRepr(rtext); new_objs = g_slist_prepend (new_objs, text_object); old_objs = g_slist_prepend (old_objs, flowtext); Inkscape::GC::release(rtext); Inkscape::GC::release(rtspan); Inkscape::GC::release(text_repr); } selection->clear(); selection->setList(new_objs); for (GSList *i = old_objs; i; i = i->next) { SP_OBJECT(i->data)->deleteObject (true); } g_slist_free (old_objs); g_slist_free (new_objs); sp_document_done(doc, SP_VERB_CONTEXT_TEXT, _("Unflow flowed text")); }
void text_flow_into_shape() { SPDesktop *desktop = SP_ACTIVE_DESKTOP; if (!desktop) return; SPDocument *doc = sp_desktop_document (desktop); Inkscape::XML::Document *xml_doc = sp_document_repr_doc(doc); Inkscape::Selection *selection = sp_desktop_selection(desktop); SPItem *text = text_or_flowtext_in_selection(selection); SPItem *shape = shape_in_selection(selection); if (!text || !shape || g_slist_length((GSList *) selection->itemList()) < 2) { sp_desktop_message_stack(desktop)->flash(Inkscape::WARNING_MESSAGE, _("Select <b>a text</b> and one or more <b>paths or shapes</b> to flow text into frame.")); return; } if (SP_IS_TEXT(text)) { // remove transform from text, but recursively scale text's fontsize by the expansion SP_TEXT(text)->_adjustFontsizeRecursive(text, NR::expansion(SP_ITEM(text)->transform)); SP_OBJECT_REPR(text)->setAttribute("transform", NULL); } Inkscape::XML::Node *root_repr = xml_doc->createElement("svg:flowRoot"); root_repr->setAttribute("xml:space", "preserve"); // we preserve spaces in the text objects we create root_repr->setAttribute("style", SP_OBJECT_REPR(text)->attribute("style")); // fixme: transfer style attrs too SP_OBJECT_REPR(SP_OBJECT_PARENT(shape))->appendChild(root_repr); SPObject *root_object = doc->getObjectByRepr(root_repr); g_return_if_fail(SP_IS_FLOWTEXT(root_object)); Inkscape::XML::Node *region_repr = xml_doc->createElement("svg:flowRegion"); root_repr->appendChild(region_repr); SPObject *object = doc->getObjectByRepr(region_repr); g_return_if_fail(SP_IS_FLOWREGION(object)); /* Add clones */ for (GSList *items = (GSList *) selection->itemList(); items != NULL; items = items->next) { SPItem *item = SP_ITEM(items->data); if (SP_IS_SHAPE(item)){ Inkscape::XML::Node *clone = xml_doc->createElement("svg:use"); clone->setAttribute("x", "0"); clone->setAttribute("y", "0"); clone->setAttribute("xlink:href", g_strdup_printf("#%s", SP_OBJECT_REPR(item)->attribute("id"))); // add the new clone to the region region_repr->appendChild(clone); } } if (SP_IS_TEXT(text)) { // flow from text, as string Inkscape::XML::Node *para_repr = xml_doc->createElement("svg:flowPara"); root_repr->appendChild(para_repr); object = doc->getObjectByRepr(para_repr); g_return_if_fail(SP_IS_FLOWPARA(object)); Inkscape::Text::Layout const *layout = te_get_layout(text); Glib::ustring text_ustring = sp_te_get_string_multiline(text, layout->begin(), layout->end()); Inkscape::XML::Node *text_repr = xml_doc->createTextNode(text_ustring.c_str()); // FIXME: transfer all formatting! and convert newlines into flowParas! para_repr->appendChild(text_repr); Inkscape::GC::release(para_repr); Inkscape::GC::release(text_repr); } else { // reflow an already flowed text, preserving paras for (SPObject *o = SP_OBJECT(text)->children; o != NULL; o = o->next) { if (SP_IS_FLOWPARA(o)) { Inkscape::XML::Node *para_repr = SP_OBJECT_REPR(o)->duplicate(xml_doc); root_repr->appendChild(para_repr); object = doc->getObjectByRepr(para_repr); g_return_if_fail(SP_IS_FLOWPARA(object)); Inkscape::GC::release(para_repr); } } } SP_OBJECT(text)->deleteObject (true); sp_document_done(doc, SP_VERB_CONTEXT_TEXT, _("Flow text into shape")); sp_desktop_selection(desktop)->set(SP_ITEM(root_object)); Inkscape::GC::release(root_repr); Inkscape::GC::release(region_repr); }
Inkscape::XML::Node * sp_selected_item_to_curved_repr(SPItem *item, guint32 /*text_grouping_policy*/) { if (!item) return NULL; Inkscape::XML::Document *xml_doc = SP_OBJECT_REPR(item)->document(); if (SP_IS_TEXT(item) || SP_IS_FLOWTEXT(item)) { // Special treatment for text: convert each glyph to separate path, then group the paths Inkscape::XML::Node *g_repr = xml_doc->createElement("svg:g"); g_repr->setAttribute("transform", SP_OBJECT_REPR(item)->attribute("transform")); /* Mask */ gchar *mask_str = (gchar *) SP_OBJECT_REPR(item)->attribute("mask"); if ( mask_str ) g_repr->setAttribute("mask", mask_str); /* Clip path */ gchar *clip_path_str = (gchar *) SP_OBJECT_REPR(item)->attribute("clip-path"); if ( clip_path_str ) g_repr->setAttribute("clip-path", clip_path_str); /* Rotation center */ g_repr->setAttribute("inkscape:transform-center-x", SP_OBJECT_REPR(item)->attribute("inkscape:transform-center-x"), false); g_repr->setAttribute("inkscape:transform-center-y", SP_OBJECT_REPR(item)->attribute("inkscape:transform-center-y"), false); /* Whole text's style */ gchar *style_str = sp_style_write_difference(SP_OBJECT_STYLE(item), SP_OBJECT_STYLE(SP_OBJECT_PARENT(item))); g_repr->setAttribute("style", style_str); g_free(style_str); Inkscape::Text::Layout::iterator iter = te_get_layout(item)->begin(); do { Inkscape::Text::Layout::iterator iter_next = iter; iter_next.nextGlyph(); // iter_next is one glyph ahead from iter if (iter == iter_next) break; /* This glyph's style */ SPObject const *pos_obj = 0; void *rawptr = 0; te_get_layout(item)->getSourceOfCharacter(iter, &rawptr); if (!rawptr || !SP_IS_OBJECT(rawptr)) // no source for glyph, abort break; pos_obj = SP_OBJECT(rawptr); while (SP_IS_STRING(pos_obj) && SP_OBJECT_PARENT(pos_obj)) { pos_obj = SP_OBJECT_PARENT(pos_obj); // SPStrings don't have style } gchar *style_str = sp_style_write_difference(SP_OBJECT_STYLE(pos_obj), SP_OBJECT_STYLE(SP_OBJECT_PARENT(pos_obj))); // get path from iter to iter_next: SPCurve *curve = te_get_layout(item)->convertToCurves(iter, iter_next); iter = iter_next; // shift to next glyph if (!curve) { // error converting this glyph g_free (style_str); continue; } if (curve->is_empty()) { // whitespace glyph? curve->unref(); g_free (style_str); continue; } Inkscape::XML::Node *p_repr = xml_doc->createElement("svg:path"); gchar *def_str = sp_svg_write_path(curve->get_pathvector()); p_repr->setAttribute("d", def_str); g_free(def_str); curve->unref(); p_repr->setAttribute("style", style_str); g_free(style_str); g_repr->appendChild(p_repr); Inkscape::GC::release(p_repr); if (iter == te_get_layout(item)->end()) break; } while (true); return g_repr; } SPCurve *curve = NULL; if (SP_IS_SHAPE(item)) { curve = sp_shape_get_curve(SP_SHAPE(item)); } if (!curve) return NULL; // Prevent empty paths from being added to the document // otherwise we end up with zomby markup in the SVG file if(curve->is_empty()) { curve->unref(); return NULL; } 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 */ 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(curve->get_pathvector()); repr->setAttribute("d", def_str); g_free(def_str); curve->unref(); return repr; }