Exemplo n.º 1
0
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));
}
Exemplo n.º 2
0
void spdc_create_single_dot(ToolBase *ec, Geom::Point const &pt, char const *tool, guint event_state) {
    g_return_if_fail(!strcmp(tool, "/tools/freehand/pen") || !strcmp(tool, "/tools/freehand/pencil"));
    Glib::ustring tool_path = tool;

    SPDesktop *desktop = ec->desktop;
    Inkscape::XML::Document *xml_doc = desktop->doc()->getReprDoc();
    Inkscape::XML::Node *repr = xml_doc->createElement("svg:path");
    repr->setAttribute("sodipodi:type", "arc");
    SPItem *item = SP_ITEM(desktop->currentLayer()->appendChildRepr(repr));
    Inkscape::GC::release(repr);

    // apply the tool's current style
    sp_desktop_apply_style_tool(desktop, repr, tool, false);

    // find out stroke width (TODO: is there an easier way??)
    double stroke_width = 3.0;
    gchar const *style_str = repr->attribute("style");
    if (style_str) {
        SPStyle style(SP_ACTIVE_DOCUMENT);
        style.mergeString(style_str);
        stroke_width = style.stroke_width.computed;
    }

    // unset stroke and set fill color to former stroke color
    gchar * str;
    str = g_strdup_printf("fill:#%06x;stroke:none;", sp_desktop_get_color_tool(desktop, tool, false) >> 8);
    repr->setAttribute("style", str);
    g_free(str);

    // put the circle where the mouse click occurred and set the diameter to the
    // current stroke width, multiplied by the amount specified in the preferences
    Inkscape::Preferences *prefs = Inkscape::Preferences::get();

    Geom::Affine const i2d (item->i2dt_affine ());
    Geom::Point pp = pt * i2d.inverse();
    double rad = 0.5 * prefs->getDouble(tool_path + "/dot-size", 3.0);
    if (event_state & GDK_MOD1_MASK) {
        // TODO: We vary the dot size between 0.5*rad and 1.5*rad, where rad is the dot size
        // as specified in prefs. Very simple, but it might be sufficient in practice. If not,
        // we need to devise something more sophisticated.
        double s = g_random_double_range(-0.5, 0.5);
        rad *= (1 + s);
    }
    if (event_state & GDK_SHIFT_MASK) {
        // double the point size
        rad *= 2;
    }

    sp_repr_set_svg_double (repr, "sodipodi:cx", pp[Geom::X]);
    sp_repr_set_svg_double (repr, "sodipodi:cy", pp[Geom::Y]);
    sp_repr_set_svg_double (repr, "sodipodi:rx", rad * stroke_width);
    sp_repr_set_svg_double (repr, "sodipodi:ry", rad * stroke_width);
    item->updateRepr();

    desktop->getSelection()->set(item);

    desktop->messageStack()->flash(Inkscape::NORMAL_MESSAGE, _("Creating single dot"));
    DocumentUndo::done(desktop->getDocument(), SP_VERB_NONE, _("Create single dot"));
}
Exemplo n.º 3
0
static void spdc_apply_powerstroke_shape(const std::vector<Geom::Point> & points, FreehandBase *dc, SPItem *item)
{
    using namespace Inkscape::LivePathEffect;

    Effect::createAndApply(POWERSTROKE, dc->desktop->doc(), item);
    Effect* lpe = SP_LPE_ITEM(item)->getCurrentLPE();
    static_cast<LPEPowerStroke*>(lpe)->offset_points.param_set_and_write_new_value(points);

    // find out stroke width (TODO: is there an easier way??)
    SPDesktop *desktop = dc->desktop;
    Inkscape::XML::Document *xml_doc = desktop->doc()->getReprDoc();
    Inkscape::XML::Node *repr = xml_doc->createElement("svg:path");
    Inkscape::GC::release(repr);

    char const* tool = SP_IS_PEN_CONTEXT(dc) ? "/tools/freehand/pen" : "/tools/freehand/pencil";

    // apply the tool's current style
    sp_desktop_apply_style_tool(desktop, repr, tool, false);

    double stroke_width = 1.0;
    char const *style_str = NULL;
    style_str = repr->attribute("style");
    if (style_str) {
        SPStyle style(SP_ACTIVE_DOCUMENT);
        style.mergeString(style_str);
        stroke_width = style.stroke_width.computed;
    }

    std::ostringstream s;
    s.imbue(std::locale::classic());
    s << points[0][Geom::X] << "," << stroke_width / 2.;

    // write powerstroke parameters:
    lpe->getRepr()->setAttribute("start_linecap_type", "zerowidth");
    lpe->getRepr()->setAttribute("end_linecap_type", "zerowidth");
    lpe->getRepr()->setAttribute("cusp_linecap_type", "round");
    lpe->getRepr()->setAttribute("sort_points", "true");
    lpe->getRepr()->setAttribute("interpolator_type", "CubicBezierJohan");
    lpe->getRepr()->setAttribute("interpolator_beta", "0.2");
    lpe->getRepr()->setAttribute("offset_points", s.str().c_str());
}
Exemplo n.º 4
0
static gint sp_dt_ruler_event(GtkWidget *widget, GdkEvent *event, SPDesktopWidget *dtw, bool horiz)
{
    static bool clicked = false;
    static bool dragged = false;
    static SPCanvasItem *guide = NULL;
    static Geom::Point normal;
    int wx, wy;
    static gint xp = 0, yp = 0; // where drag started

    SPDesktop *desktop = dtw->desktop;
    GdkWindow *window = gtk_widget_get_window(GTK_WIDGET(dtw->canvas));

    gint width, height;

#if GTK_CHECK_VERSION(3,0,0)
    GdkDevice *device = gdk_event_get_device(event);
    gdk_window_get_device_position(window, device, &wx, &wy, NULL);
    gdk_window_get_geometry(window, NULL /*x*/, NULL /*y*/, &width, &height);
#else
    gdk_window_get_pointer(window, &wx, &wy, NULL);
    gdk_window_get_geometry(window, NULL /*x*/, NULL /*y*/, &width, &height, NULL/*depth*/);
#endif
    
    Geom::Point const event_win(wx, wy);

    switch (event->type) {
    case GDK_BUTTON_PRESS:
            if (event->button.button == 1) {
                clicked = true;
                dragged = false;
                // save click origin
                xp = (gint) event->button.x;
                yp = (gint) event->button.y;

                Geom::Point const event_w(sp_canvas_window_to_world(dtw->canvas, event_win));
                Geom::Point const event_dt(desktop->w2d(event_w));

                // calculate the normal of the guidelines when dragged from the edges of rulers.
                Geom::Point normal_bl_to_tr(-1.,1.); //bottomleft to topright
                Geom::Point normal_tr_to_bl(1.,1.); //topright to bottomleft
                normal_bl_to_tr.normalize();
                normal_tr_to_bl.normalize();
                Inkscape::CanvasGrid * grid = sp_namedview_get_first_enabled_grid(desktop->namedview);
                if (grid){
                    if (grid->getGridType() == Inkscape::GRID_AXONOMETRIC ) {
                        Inkscape::CanvasAxonomGrid *axonomgrid = dynamic_cast<Inkscape::CanvasAxonomGrid *>(grid);
                        if (event->button.state & GDK_CONTROL_MASK) {
                            // guidelines normal to gridlines
                            normal_bl_to_tr = Geom::Point::polar(-axonomgrid->angle_rad[0], 1.0);
                            normal_tr_to_bl = Geom::Point::polar(axonomgrid->angle_rad[2], 1.0);
                        } else {
                            normal_bl_to_tr = rot90(Geom::Point::polar(axonomgrid->angle_rad[2], 1.0));
                            normal_tr_to_bl = rot90(Geom::Point::polar(-axonomgrid->angle_rad[0], 1.0));
                        }
                    }
                }
                if (horiz) {
                    if (wx < 50) {
                        normal = normal_bl_to_tr;
                    } else if (wx > width - 50) {
                        normal = normal_tr_to_bl;
                    } else {
                        normal = Geom::Point(0.,1.);
                    }
                } else {
                    if (wy < 50) {
                        normal = normal_bl_to_tr;
                    } else if (wy > height - 50) {
                        normal = normal_tr_to_bl;
                    } else {
                        normal = Geom::Point(1.,0.);
                    }
                }

                guide = sp_guideline_new(desktop->guides, NULL, event_dt, normal);
                sp_guideline_set_color(SP_GUIDELINE(guide), desktop->namedview->guidehicolor);

#if GTK_CHECK_VERSION(3,0,0)
                gdk_device_grab(device,
                                gtk_widget_get_window(widget), 
                                GDK_OWNERSHIP_NONE,
                                FALSE,
                                (GdkEventMask)(GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK ),
                                NULL,
                                event->button.time);
#else
                gdk_pointer_grab(gtk_widget_get_window (widget), FALSE,
                                 (GdkEventMask)(GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK ),
                                 NULL, NULL,
                                 event->button.time);
#endif
            }
            break;
    case GDK_MOTION_NOTIFY:
            if (clicked) {
                Geom::Point const event_w(sp_canvas_window_to_world(dtw->canvas, event_win));
                Geom::Point event_dt(desktop->w2d(event_w));

                Inkscape::Preferences *prefs = Inkscape::Preferences::get();
                gint tolerance = prefs->getIntLimited("/options/dragtolerance/value", 0, 0, 100);
                if ( ( abs( (gint) event->motion.x - xp ) < tolerance )
                        && ( abs( (gint) event->motion.y - yp ) < tolerance ) ) {
                    break;
                }

                dragged = true;

                // explicitly show guidelines; if I draw a guide, I want them on
                if ((horiz ? wy : wx) >= 0) {
                    desktop->namedview->setGuides(true);
                }

                if (!(event->motion.state & GDK_SHIFT_MASK)) {
                    sp_dt_ruler_snap_new_guide(desktop, guide, event_dt, normal);
                }
                sp_guideline_set_normal(SP_GUIDELINE(guide), normal);
                sp_guideline_set_position(SP_GUIDELINE(guide), event_dt);

                desktop->set_coordinate_status(event_dt);
            }
            break;
    case GDK_BUTTON_RELEASE:
            if (clicked && event->button.button == 1) {
                sp_event_context_discard_delayed_snap_event(desktop->event_context);

#if GTK_CHECK_VERSION(3,0,0)
                gdk_device_ungrab(device, event->button.time);
#else
                gdk_pointer_ungrab(event->button.time);
#endif

                Geom::Point const event_w(sp_canvas_window_to_world(dtw->canvas, event_win));
                Geom::Point event_dt(desktop->w2d(event_w));

                if (!(event->button.state & GDK_SHIFT_MASK)) {
                    sp_dt_ruler_snap_new_guide(desktop, guide, event_dt, normal);
                }

                sp_canvas_item_destroy(guide);
                guide = NULL;
                if ((horiz ? wy : wx) >= 0) {
                    Inkscape::XML::Document *xml_doc = desktop->doc()->getReprDoc();
                    Inkscape::XML::Node *repr = xml_doc->createElement("sodipodi:guide");

                    // If root viewBox set, interpret guides in terms of viewBox (90/96)
                    double newx = event_dt.x();
                    double newy = event_dt.y();

                    SPRoot *root = desktop->doc()->getRoot();
                    if( root->viewBox_set ) {
                        newx = newx * root->viewBox.width()  / root->width.computed;
                        newy = newy * root->viewBox.height() / root->height.computed;
                    }
                    sp_repr_set_point(repr, "position", Geom::Point( newx, newy ));
                    sp_repr_set_point(repr, "orientation", normal);
                    desktop->namedview->appendChild(repr);
                    Inkscape::GC::release(repr);
                    DocumentUndo::done(desktop->getDocument(), SP_VERB_NONE,
                                     _("Create guide"));
                }
                desktop->set_coordinate_status(event_dt);

                if (!dragged) {
                    // Ruler click (without drag) toggle the guide visibility on and off
                    Inkscape::XML::Node *repr = desktop->namedview->getRepr();
                    sp_namedview_toggle_guides(desktop->getDocument(), repr);
                    
                }

                clicked = false;
                dragged = false;
            }
    default:
            break;
    }

    return FALSE;
}
Exemplo n.º 5
0
void
text_put_on_path()
{
    SPDesktop *desktop = SP_ACTIVE_DESKTOP;
    if (!desktop)
        return;

    Inkscape::Selection *selection = sp_desktop_selection(desktop);

    SPItem *text = text_or_flowtext_in_selection(selection);
    SPItem *shape = shape_in_selection(selection);

    Inkscape::XML::Document *xml_doc = sp_document_repr_doc(desktop->doc());

    if (!text || !shape || g_slist_length((GSList *) selection->itemList()) != 2) {
        sp_desktop_message_stack(desktop)->flash(Inkscape::WARNING_MESSAGE, _("Select <b>a text and a path</b> to put text on path."));
        return;
    }

    if (SP_IS_TEXT_TEXTPATH(text)) {
        sp_desktop_message_stack(desktop)->flash(Inkscape::ERROR_MESSAGE, _("This text object is <b>already put on a path</b>. Remove it from the path first. Use <b>Shift+D</b> to look up its path."));
        return;
    }

    if (SP_IS_RECT(shape)) {
        // rect is the only SPShape which is not <path> yet, and thus SVG forbids us from putting text on it
        sp_desktop_message_stack(desktop)->flash(Inkscape::ERROR_MESSAGE, _("You cannot put text on a rectangle in this version. Convert rectangle to path first."));
        return;
    }

    // if a flowed text is selected, convert it to a regular text object
    if (SP_IS_FLOWTEXT(text)) {

        if (!SP_FLOWTEXT(text)->layout.outputExists()) {
            sp_desktop_message_stack(desktop)->
                flash(Inkscape::WARNING_MESSAGE, 
                      _("The flowed text(s) must be <b>visible</b> in order to be put on a path."));
        }

        Inkscape::XML::Node *repr = SP_FLOWTEXT(text)->getAsText();

        if (!repr) return;

        Inkscape::XML::Node *parent = SP_OBJECT_REPR(text)->parent();
        parent->appendChild(repr);

        SPItem *new_item = (SPItem *) sp_desktop_document(desktop)->getObjectByRepr(repr);
        sp_item_write_transform(new_item, repr, text->transform);
        SP_OBJECT(new_item)->updateRepr();

        Inkscape::GC::release(repr);
        text->deleteObject(); // delete the orignal flowtext

        sp_document_ensure_up_to_date(sp_desktop_document(desktop));

        selection->clear();

        text = new_item; // point to the new text
    }

    Inkscape::Text::Layout const *layout = te_get_layout(text);
    Inkscape::Text::Layout::Alignment text_alignment = layout->paragraphAlignment(layout->begin());

    // 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);

    // make a list of text children
    GSList *text_reprs = NULL;
    for (SPObject *o = SP_OBJECT(text)->children; o != NULL; o = o->next) {
        text_reprs = g_slist_prepend(text_reprs, SP_OBJECT_REPR(o));
    }

    // create textPath and put it into the text
    Inkscape::XML::Node *textpath = xml_doc->createElement("svg:textPath");
    // reference the shape
    textpath->setAttribute("xlink:href", g_strdup_printf("#%s", SP_OBJECT_REPR(shape)->attribute("id")));
    if (text_alignment == Inkscape::Text::Layout::RIGHT)
        textpath->setAttribute("startOffset", "100%");
    else if (text_alignment == Inkscape::Text::Layout::CENTER)
        textpath->setAttribute("startOffset", "50%");
    SP_OBJECT_REPR(text)->addChild(textpath, NULL);

    for ( GSList *i = text_reprs ; i ; i = i->next ) {
        // Make a copy of each text child
        Inkscape::XML::Node *copy = ((Inkscape::XML::Node *) i->data)->duplicate(xml_doc);
        // We cannot have multiline in textpath, so remove line attrs from tspans
        if (!strcmp(copy->name(), "svg:tspan")) {
            copy->setAttribute("sodipodi:role", NULL);
            copy->setAttribute("x", NULL);
            copy->setAttribute("y", NULL);
        }
        // remove the old repr from under text
        SP_OBJECT_REPR(text)->removeChild((Inkscape::XML::Node *) i->data);
        // put its copy into under textPath
        textpath->addChild(copy, NULL); // fixme: copy id
    }

    // x/y are useless with textpath, and confuse Batik 1.5
    SP_OBJECT_REPR(text)->setAttribute("x", NULL);
    SP_OBJECT_REPR(text)->setAttribute("y", NULL);

    sp_document_done(sp_desktop_document(desktop), SP_VERB_CONTEXT_TEXT, 
                     _("Put text on path"));
    g_slist_free(text_reprs);
}
Exemplo n.º 6
0
/**
 *  Threaded method that does single bitmap--->path conversion
 */
void Tracer::traceThread()
{
    //## Remember. NEVER leave this method without setting
    //## engine back to NULL

    //## Prepare our kill flag.  We will watch this later to
    //## see if the main thread wants us to stop
    keepGoing = true;

    SPDesktop *desktop = SP_ACTIVE_DESKTOP;
    if (!desktop)
        {
        g_warning("Trace: No active desktop\n");
        return;
        }

    Inkscape::MessageStack *msgStack = sp_desktop_message_stack(desktop);

    Inkscape::Selection *selection = sp_desktop_selection (desktop);

    if (!SP_ACTIVE_DOCUMENT)
        {
        char *msg = _("Trace: No active document");
        msgStack->flash(Inkscape::ERROR_MESSAGE, msg);
        //g_warning(msg);
        engine = NULL;
        return;
        }
    SPDocument *doc = SP_ACTIVE_DOCUMENT;
    sp_document_ensure_up_to_date(doc);


    SPImage *img = getSelectedSPImage();
    if (!img)
        {
        engine = NULL;
        return;
        }

    Glib::RefPtr<Gdk::Pixbuf> pixbuf = Glib::wrap(img->pixbuf, true);

    pixbuf = sioxProcessImage(img, pixbuf);

    if (!pixbuf)
        {
        char *msg = _("Trace: Image has no bitmap data");
        msgStack->flash(Inkscape::ERROR_MESSAGE, msg);
        //g_warning(msg);
        engine = NULL;
        return;
        }

    msgStack->flash(Inkscape::NORMAL_MESSAGE, _("Trace: Starting trace..."));
    desktop->updateCanvasNow();

    std::vector<TracingEngineResult> results =
                engine->trace(pixbuf);
    //printf("nrPaths:%d\n", results.size());
    int nrPaths = results.size();

    //### Check if we should stop
    if (!keepGoing || nrPaths<1)
        {
        engine = NULL;
        return;
        }

    //### Get pointers to the <image> and its parent
    Inkscape::XML::Node *imgRepr   = SP_OBJECT(img)->repr;
    Inkscape::XML::Node *par       = sp_repr_parent(imgRepr);

    //### Get some information for the new transform()
    double x      = 0.0;
    double y      = 0.0;
    double width  = 0.0;
    double height = 0.0;
    double dval   = 0.0;

    if (sp_repr_get_double(imgRepr, "x", &dval))
        x = dval;
    if (sp_repr_get_double(imgRepr, "y", &dval))
        y = dval;

    if (sp_repr_get_double(imgRepr, "width", &dval))
        width = dval;
    if (sp_repr_get_double(imgRepr, "height", &dval))
        height = dval;

    double iwidth  = (double)pixbuf->get_width();
    double iheight = (double)pixbuf->get_height();

    double iwscale = width  / iwidth;
    double ihscale = height / iheight;

    Geom::Translate trans(x, y);
    Geom::Scale scal(iwscale, ihscale);

    //# Convolve scale, translation, and the original transform
    Geom::Matrix tf(scal * trans);
    tf *= img->transform;


    //#OK.  Now let's start making new nodes

    Inkscape::XML::Document *xml_doc = sp_document_repr_doc(desktop->doc());
    Inkscape::XML::Node *groupRepr = NULL;

    //# if more than 1, make a <g>roup of <path>s
    if (nrPaths > 1)
        {
        groupRepr = xml_doc->createElement("svg:g");
        par->addChild(groupRepr, imgRepr);
        }

    long totalNodeCount = 0L;

    for (unsigned int i=0 ; i<results.size() ; i++)
        {
        TracingEngineResult result = results[i];
        totalNodeCount += result.getNodeCount();

        Inkscape::XML::Node *pathRepr = xml_doc->createElement("svg:path");
        pathRepr->setAttribute("style", result.getStyle().c_str());
        pathRepr->setAttribute("d",     result.getPathData().c_str());

        if (nrPaths > 1)
            groupRepr->addChild(pathRepr, NULL);
        else
            par->addChild(pathRepr, imgRepr);

        //### Apply the transform from the image to the new shape
        SPObject *reprobj = doc->getObjectByRepr(pathRepr);
        if (reprobj)
            {
            SPItem *newItem = SP_ITEM(reprobj);
            sp_item_write_transform(newItem, pathRepr, tf, NULL);
            }
        if (nrPaths == 1)
            {
            selection->clear();
            selection->add(pathRepr);
            }
        Inkscape::GC::release(pathRepr);
        }

    // If we have a group, then focus on, then forget it
    if (nrPaths > 1)
        {
        selection->clear();
        selection->add(groupRepr);
        Inkscape::GC::release(groupRepr);
        }

    //## inform the document, so we can undo
    sp_document_done(doc, SP_VERB_SELECTION_TRACE, _("Trace bitmap"));

    engine = NULL;

    char *msg = g_strdup_printf(_("Trace: Done. %ld nodes created"), totalNodeCount);
    msgStack->flash(Inkscape::NORMAL_MESSAGE, msg);
    g_free(msg);

}