static void sp_selection_layout_widget_update(SPWidget *spw, Inkscape::Selection *sel) { if (g_object_get_data(G_OBJECT(spw), "update")) { return; } g_object_set_data(G_OBJECT(spw), "update", GINT_TO_POINTER(TRUE)); Inkscape::Preferences *prefs = Inkscape::Preferences::get(); using Geom::X; using Geom::Y; if ( sel && !sel->isEmpty() ) { int prefs_bbox = prefs->getInt("/tools/bounding_box", 0); SPItem::BBoxType bbox_type = (prefs_bbox ==0)? SPItem::VISUAL_BBOX : SPItem::GEOMETRIC_BBOX; Geom::OptRect const bbox(sel->bounds(bbox_type)); if ( bbox ) { UnitTracker *tracker = reinterpret_cast<UnitTracker*>(g_object_get_data(G_OBJECT(spw), "tracker")); Unit const *unit = tracker->getActiveUnit(); g_return_if_fail(unit != NULL); struct { char const *key; double val; } const keyval[] = { { "X", bbox->min()[X] }, { "Y", bbox->min()[Y] }, { "width", bbox->dimensions()[X] }, { "height", bbox->dimensions()[Y] } }; if (unit->type == Inkscape::Util::UNIT_TYPE_DIMENSIONLESS) { double const val = unit->factor * 100; for (unsigned i = 0; i < G_N_ELEMENTS(keyval); ++i) { GtkAdjustment *a = GTK_ADJUSTMENT(g_object_get_data(G_OBJECT(spw), keyval[i].key)); gtk_adjustment_set_value(a, val); tracker->setFullVal( a, keyval[i].val ); } } else { for (unsigned i = 0; i < G_N_ELEMENTS(keyval); ++i) { GtkAdjustment *a = GTK_ADJUSTMENT(g_object_get_data(G_OBJECT(spw), keyval[i].key)); gtk_adjustment_set_value(a, Quantity::convert(keyval[i].val, "px", unit)); } } } } g_object_set_data(G_OBJECT(spw), "update", GINT_TO_POINTER(FALSE)); }
static Geom::Point unclump_wh (SPItem *item) { Geom::Point wh; std::map<const gchar *, Geom::Point>::iterator i = wh_cache.find(item->getId()); if ( i != wh_cache.end() ) { wh = i->second; } else { Geom::OptRect r = item->desktopVisualBounds(); if (r) { wh = r->dimensions(); wh_cache[item->getId()] = wh; } else { wh = Geom::Point(0, 0); } } return wh; }
void ObjectCompositeSettings::_subjectChanged() { if (!_subject) { return; } SPDesktop *desktop = _subject->getDesktop(); if (!desktop) { return; } if (_blocked) return; _blocked = true; SPStyle *query = sp_style_new (sp_desktop_document(desktop)); int result = _subject->queryStyle(query, QUERY_STYLE_PROPERTY_MASTEROPACITY); switch (result) { case QUERY_STYLE_NOTHING: _opacity_vbox.set_sensitive(false); // gtk_widget_set_sensitive (opa, FALSE); break; case QUERY_STYLE_SINGLE: case QUERY_STYLE_MULTIPLE_AVERAGED: // TODO: treat this slightly differently case QUERY_STYLE_MULTIPLE_SAME: _opacity_vbox.set_sensitive(true); _opacity_scale.get_adjustment()->set_value(100 * SP_SCALE24_TO_FLOAT(query->opacity.value)); break; } //query now for current filter mode and average blurring of selection const int blend_result = _subject->queryStyle(query, QUERY_STYLE_PROPERTY_BLEND); switch(blend_result) { case QUERY_STYLE_NOTHING: _fe_cb.set_sensitive(false); break; case QUERY_STYLE_SINGLE: case QUERY_STYLE_MULTIPLE_SAME: _fe_cb.set_blend_mode(query->filter_blend_mode.value); _fe_cb.set_sensitive(true); break; case QUERY_STYLE_MULTIPLE_DIFFERENT: // TODO: set text _fe_cb.set_sensitive(false); break; } if(blend_result == QUERY_STYLE_SINGLE || blend_result == QUERY_STYLE_MULTIPLE_SAME) { int blur_result = _subject->queryStyle(query, QUERY_STYLE_PROPERTY_BLUR); switch (blur_result) { case QUERY_STYLE_NOTHING: //no blurring _fe_cb.set_blur_sensitive(false); break; case QUERY_STYLE_SINGLE: case QUERY_STYLE_MULTIPLE_AVERAGED: case QUERY_STYLE_MULTIPLE_SAME: Geom::OptRect bbox = _subject->getBounds(SPItem::GEOMETRIC_BBOX); if (bbox) { double perimeter = bbox->dimensions()[Geom::X] + bbox->dimensions()[Geom::Y]; // fixme: this is only half the perimeter, is that correct? _fe_cb.set_blur_sensitive(true); //update blur widget value float radius = query->filter_gaussianBlur_deviation.value; float percent = radius * 400 / perimeter; // so that for a square, 100% == half side _fe_cb.set_blur_value(percent); } break; } } sp_style_unref(query); _blocked = false; }
void ObjectCompositeSettings::_blendBlurValueChanged() { if (!_subject) { return; } SPDesktop *desktop = _subject->getDesktop(); if (!desktop) { return; } SPDocument *document = sp_desktop_document (desktop); if (_blocked) return; _blocked = true; // FIXME: fix for GTK breakage, see comment in SelectedStyle::on_opacity_changed; here it results in crash 1580903 //sp_canvas_force_full_redraw_after_interruptions(sp_desktop_canvas(desktop), 0); Geom::OptRect bbox = _subject->getBounds(SPItem::GEOMETRIC_BBOX); double radius; if (bbox) { double perimeter = bbox->dimensions()[Geom::X] + bbox->dimensions()[Geom::Y]; // fixme: this is only half the perimeter, is that correct? radius = _fe_cb.get_blur_value() * perimeter / 400; } else { radius = 0; } const Glib::ustring blendmode = _fe_cb.get_blend_mode(); //apply created filter to every selected item for (StyleSubject::iterator i = _subject->begin() ; i != _subject->end() ; ++i ) { if (!SP_IS_ITEM(*i)) { continue; } SPItem * item = SP_ITEM(*i); SPStyle *style = item->style; g_assert(style != NULL); if (blendmode != "normal") { SPFilter *filter = new_filter_simple_from_item(document, item, blendmode.c_str(), radius); sp_style_set_property_url(item, "filter", filter, false); } else { sp_style_set_property_url(item, "filter", NULL, false); } if (radius == 0 && item->style->filter.set && filter_is_single_gaussian_blur(SP_FILTER(item->style->getFilter()))) { remove_filter(item, false); } else if (radius != 0) { SPFilter *filter = modify_filter_gaussian_blur_from_item(document, item, radius); sp_style_set_property_url(item, "filter", filter, false); } //request update item->requestDisplayUpdate(( SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_STYLE_MODIFIED_FLAG )); } DocumentUndo::maybeDone(document, _blur_tag.c_str(), _verb_code, _("Change blur")); // resume interruptibility //sp_canvas_end_forced_full_redraws(sp_desktop_canvas(desktop)); _blocked = false; }
void SPOffset::set_shape() { if ( this->originalPath == NULL ) { // oops : no path?! (the offset object should do harakiri) return; } #ifdef OFFSET_VERBOSE g_print ("rad=%g\n", offset->rad); #endif // au boulot if ( fabs(this->rad) < 0.01 ) { // grosso modo: 0 // just put the source this as the offseted one, no one will notice // it's also useless to compute the offset with a 0 radius //XML Tree being used directly here while it shouldn't be. const char *res_d = this->getRepr()->attribute("inkscape:original"); if ( res_d ) { Geom::PathVector pv = sp_svg_read_pathv(res_d); SPCurve *c = new SPCurve(pv); g_assert(c != NULL); this->setCurveInsync (c, TRUE); this->setCurveBeforeLPE(c); c->unref(); } return; } // extra paraniac careful check. the preceding if () should take care of this case if (fabs (this->rad) < 0.01) { this->rad = (this->rad < 0) ? -0.01 : 0.01; } Path *orig = new Path; orig->Copy ((Path *)this->originalPath); if ( use_slow_but_correct_offset_method == false ) { // version par outline Shape *theShape = new Shape; Shape *theRes = new Shape; Path *originaux[1]; Path *res = new Path; res->SetBackData (false); // and now: offset float o_width; if (this->rad >= 0) { o_width = this->rad; orig->OutsideOutline (res, o_width, join_round, butt_straight, 20.0); } else { o_width = -this->rad; orig->OutsideOutline (res, -o_width, join_round, butt_straight, 20.0); } if (o_width >= 1.0) { // res->ConvertForOffset (1.0, orig, offset->rad); res->ConvertWithBackData (1.0); } else { // res->ConvertForOffset (o_width, orig, offset->rad); res->ConvertWithBackData (o_width); } res->Fill (theShape, 0); theRes->ConvertToShape (theShape, fill_positive); originaux[0] = res; theRes->ConvertToForme (orig, 1, originaux); Geom::OptRect bbox = this->desktopVisualBounds(); if ( bbox ) { gdouble size = L2(bbox->dimensions()); gdouble const exp = this->transform.descrim(); if (exp != 0) { size /= exp; } orig->Coalesce (size * 0.001); //g_print ("coa %g exp %g item %p\n", size * 0.001, exp, item); } // if (o_width >= 1.0) // { // orig->Coalesce (0.1); // small treshhold, since we only want to get rid of small segments // the curve should already be computed by the Outline() function // orig->ConvertEvenLines (1.0); // orig->Simplify (0.5); // } // else // { // orig->Coalesce (0.1*o_width); // orig->ConvertEvenLines (o_width); // orig->Simplify (0.5 * o_width); // } delete theShape; delete theRes; delete res; } else { // version par makeoffset Shape *theShape = new Shape; Shape *theRes = new Shape; // and now: offset float o_width; if (this->rad >= 0) { o_width = this->rad; } else { o_width = -this->rad; } // one has to have a measure of the details if (o_width >= 1.0) { orig->ConvertWithBackData (0.5); } else { orig->ConvertWithBackData (0.5*o_width); } orig->Fill (theShape, 0); theRes->ConvertToShape (theShape, fill_positive); Path *originaux[1]; originaux[0]=orig; Path *res = new Path; theRes->ConvertToForme (res, 1, originaux); int nbPart=0; Path** parts=res->SubPaths(nbPart,true); char *holes=(char*)malloc(nbPart*sizeof(char)); // we offset contours separately, because we can. // this way, we avoid doing a unique big ConvertToShape when dealing with big shapes with lots of holes { Shape* onePart=new Shape; Shape* oneCleanPart=new Shape; theShape->Reset(); for (int i=0; i<nbPart; i++) { double partSurf=parts[i]->Surface(); parts[i]->Convert(1.0); { // raffiner si besoin double bL,bT,bR,bB; parts[i]->PolylineBoundingBox(bL,bT,bR,bB); double mesure=((bR-bL)+(bB-bT))*0.5; if ( mesure < 10.0 ) { parts[i]->Convert(0.02*mesure); } } if ( partSurf < 0 ) { // inverse par rapport a la realite // plein holes[i]=0; parts[i]->Fill(oneCleanPart,0); onePart->ConvertToShape(oneCleanPart,fill_positive); // there aren't intersections in that one, but maybe duplicate points and null edges oneCleanPart->MakeOffset(onePart,this->rad,join_round,20.0); onePart->ConvertToShape(oneCleanPart,fill_positive); onePart->CalcBBox(); double typicalSize=0.5*((onePart->rightX-onePart->leftX)+(onePart->bottomY-onePart->topY)); if ( typicalSize < 0.05 ) { typicalSize=0.05; } typicalSize*=0.01; if ( typicalSize > 1.0 ) { typicalSize=1.0; } onePart->ConvertToForme (parts[i]); parts[i]->ConvertEvenLines (typicalSize); parts[i]->Simplify (typicalSize); double nPartSurf=parts[i]->Surface(); if ( nPartSurf >= 0 ) { // inversion de la surface -> disparait delete parts[i]; parts[i]=NULL; } else { } /* int firstP=theShape->nbPt; for (int j=0;j<onePart->nbPt;j++) theShape->AddPoint(onePart->pts[j].x); for (int j=0;j<onePart->nbAr;j++) theShape->AddEdge(firstP+onePart->aretes[j].st,firstP+onePart->aretes[j].en);*/ } else { // trou holes[i]=1; parts[i]->Fill(oneCleanPart,0,false,true,true); onePart->ConvertToShape(oneCleanPart,fill_positive); oneCleanPart->MakeOffset(onePart,-this->rad,join_round,20.0); onePart->ConvertToShape(oneCleanPart,fill_positive); // for (int j=0;j<onePart->nbAr;j++) onePart->Inverse(j); // pas oublier de reinverser onePart->CalcBBox(); double typicalSize=0.5*((onePart->rightX-onePart->leftX)+(onePart->bottomY-onePart->topY)); if ( typicalSize < 0.05 ) { typicalSize=0.05; } typicalSize*=0.01; if ( typicalSize > 1.0 ) { typicalSize=1.0; } onePart->ConvertToForme (parts[i]); parts[i]->ConvertEvenLines (typicalSize); parts[i]->Simplify (typicalSize); double nPartSurf=parts[i]->Surface(); if ( nPartSurf >= 0 ) { // inversion de la surface -> disparait delete parts[i]; parts[i]=NULL; } else { } /* int firstP=theShape->nbPt; for (int j=0;j<onePart->nbPt;j++) theShape->AddPoint(onePart->pts[j].x); for (int j=0;j<onePart->nbAr;j++) theShape->AddEdge(firstP+onePart->aretes[j].en,firstP+onePart->aretes[j].st);*/ } // delete parts[i]; } // theShape->MakeOffset(theRes,offset->rad,join_round,20.0); delete onePart; delete oneCleanPart; } if ( nbPart > 1 ) { theShape->Reset(); for (int i=0; i<nbPart; i++) { if ( parts[i] ) { parts[i]->ConvertWithBackData(1.0); if ( holes[i] ) { parts[i]->Fill(theShape,i,true,true,true); } else { parts[i]->Fill(theShape,i,true,true,false); } } } theRes->ConvertToShape (theShape, fill_positive); theRes->ConvertToForme (orig,nbPart,parts); for (int i=0; i<nbPart; i++) { if ( parts[i] ) { delete parts[i]; } } } else if ( nbPart == 1 ) { orig->Copy(parts[0]); for (int i=0; i<nbPart; i++) { if ( parts[i] ) { delete parts[i]; } } } else { orig->Reset(); } // theRes->ConvertToShape (theShape, fill_positive); // theRes->ConvertToForme (orig); /* if (o_width >= 1.0) { orig->ConvertEvenLines (1.0); orig->Simplify (1.0); } else { orig->ConvertEvenLines (1.0*o_width); orig->Simplify (1.0 * o_width); }*/ if ( parts ) { free(parts); } if ( holes ) { free(holes); } delete res; delete theShape; delete theRes; } { char *res_d = NULL; if (orig->descr_cmd.size() <= 1) { // Aie.... nothing left. res_d = strdup ("M 0 0 L 0 0 z"); //printf("%s\n",res_d); } else { res_d = orig->svg_dump_path (); } delete orig; Geom::PathVector pv = sp_svg_read_pathv(res_d); SPCurve *c = new SPCurve(pv); g_assert(c != NULL); this->setCurveInsync (c, TRUE); this->setCurveBeforeLPE(c); c->unref(); free (res_d); } }