Exemplo n.º 1
0
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));
}
Exemplo n.º 2
0
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);
    }
}