static void perform_document_update(SPDocument &doc) { sp_repr_begin_transaction(doc.rdoc); doc.ensureUpToDate(); Inkscape::XML::Event *update_log=sp_repr_commit_undoable(doc.rdoc); if (update_log != NULL) { g_warning("Document was modified while being updated after undo operation"); sp_repr_debug_print_log(update_log); //Coalesce the update changes with the last action performed by user if (!doc.priv->undo.empty()) { Inkscape::Event* undo_stack_top = doc.priv->undo.back(); undo_stack_top->event = sp_repr_coalesce_log(undo_stack_top->event, update_log); } else { sp_repr_free_log(update_log); } } }
static void spdc_flush_white(FreehandBase *dc, SPCurve *gc) { SPCurve *c; if (dc->white_curves) { g_assert(dc->white_item); c = SPCurve::concat(dc->white_curves); g_slist_free(dc->white_curves); dc->white_curves = NULL; if (gc) { c->append(gc, FALSE); } } else if (gc) { c = gc; c->ref(); } else { return; } // Now we have to go back to item coordinates at last c->transform( dc->white_item ? (dc->white_item)->dt2i_affine() : dc->desktop->dt2doc() ); SPDesktop *desktop = dc->desktop; SPDocument *doc = desktop->getDocument(); Inkscape::XML::Document *xml_doc = doc->getReprDoc(); if ( c && !c->is_empty() ) { // We actually have something to write bool has_lpe = false; Inkscape::XML::Node *repr; if (dc->white_item) { repr = dc->white_item->getRepr(); has_lpe = SP_LPE_ITEM(dc->white_item)->hasPathEffectRecursive(); } else { repr = xml_doc->createElement("svg:path"); // Set style sp_desktop_apply_style_tool(desktop, repr, tool_name(dc).data(), false); } gchar *str = sp_svg_write_path( c->get_pathvector() ); g_assert( str != NULL ); if (has_lpe) repr->setAttribute("inkscape:original-d", str); else repr->setAttribute("d", str); g_free(str); if (!dc->white_item) { // Attach repr SPItem *item = SP_ITEM(desktop->currentLayer()->appendChildRepr(repr)); spdc_check_for_and_apply_waiting_LPE(dc, item, c); if(previous_shape_type != BEND_CLIPBOARD){ dc->selection->set(repr); } Inkscape::GC::release(repr); item->transform = SP_ITEM(desktop->currentLayer())->i2doc_affine().inverse(); item->updateRepr(); item->doWriteTransform(item->getRepr(), item->transform, NULL, true); if(previous_shape_type == BEND_CLIPBOARD){ repr->parent()->removeChild(repr); } } DocumentUndo::done(doc, SP_IS_PEN_CONTEXT(dc)? SP_VERB_CONTEXT_PEN : SP_VERB_CONTEXT_PENCIL, _("Draw path")); // When quickly drawing several subpaths with Shift, the next subpath may be finished and // flushed before the selection_modified signal is fired by the previous change, which // results in the tool losing all of the selected path's curve except that last subpath. To // fix this, we force the selection_modified callback now, to make sure the tool's curve is // in sync immediately. spdc_selection_modified(desktop->getSelection(), 0, dc); } c->unref(); // Flush pending updates doc->ensureUpToDate(); }
static void sp_object_layout_any_value_changed(GtkAdjustment *adj, SPWidget *spw) { if (g_object_get_data(G_OBJECT(spw), "update")) { return; } UnitTracker *tracker = reinterpret_cast<UnitTracker*>(g_object_get_data(G_OBJECT(spw), "tracker")); if ( !tracker || tracker->isUpdating() ) { /* * When only units are being changed, don't treat changes * to adjuster values as object changes. */ return; } g_object_set_data(G_OBJECT(spw), "update", GINT_TO_POINTER(TRUE)); SPDesktop *desktop = SP_ACTIVE_DESKTOP; Inkscape::Selection *selection = sp_desktop_selection(desktop); SPDocument *document = sp_desktop_document(desktop); document->ensureUpToDate (); Inkscape::Preferences *prefs = Inkscape::Preferences::get(); Geom::OptRect bbox_vis = selection->visualBounds(); Geom::OptRect bbox_geom = selection->geometricBounds(); int prefs_bbox = prefs->getInt("/tools/bounding_box"); SPItem::BBoxType bbox_type = (prefs_bbox == 0)? SPItem::VISUAL_BBOX : SPItem::GEOMETRIC_BBOX; Geom::OptRect bbox_user = selection->bounds(bbox_type); if ( !bbox_user ) { g_object_set_data(G_OBJECT(spw), "update", GINT_TO_POINTER(FALSE)); return; } gdouble x0 = 0; gdouble y0 = 0; gdouble x1 = 0; gdouble y1 = 0; gdouble xrel = 0; gdouble yrel = 0; SPUnit const &unit = *tracker->getActiveUnit(); GtkAdjustment* a_x = GTK_ADJUSTMENT( g_object_get_data( G_OBJECT(spw), "X" ) ); GtkAdjustment* a_y = GTK_ADJUSTMENT( g_object_get_data( G_OBJECT(spw), "Y" ) ); GtkAdjustment* a_w = GTK_ADJUSTMENT( g_object_get_data( G_OBJECT(spw), "width" ) ); GtkAdjustment* a_h = GTK_ADJUSTMENT( g_object_get_data( G_OBJECT(spw), "height" ) ); if (unit.base == SP_UNIT_ABSOLUTE || unit.base == SP_UNIT_DEVICE) { x0 = sp_units_get_pixels (gtk_adjustment_get_value (a_x), unit); y0 = sp_units_get_pixels (gtk_adjustment_get_value (a_y), unit); x1 = x0 + sp_units_get_pixels (gtk_adjustment_get_value (a_w), unit); xrel = sp_units_get_pixels (gtk_adjustment_get_value (a_w), unit) / bbox_user->dimensions()[Geom::X]; y1 = y0 + sp_units_get_pixels (gtk_adjustment_get_value (a_h), unit); yrel = sp_units_get_pixels (gtk_adjustment_get_value (a_h), unit) / bbox_user->dimensions()[Geom::Y]; } else { double const x0_propn = gtk_adjustment_get_value (a_x) * unit.unittobase; x0 = bbox_user->min()[Geom::X] * x0_propn; double const y0_propn = gtk_adjustment_get_value (a_y) * unit.unittobase; y0 = y0_propn * bbox_user->min()[Geom::Y]; xrel = gtk_adjustment_get_value (a_w) * unit.unittobase; x1 = x0 + xrel * bbox_user->dimensions()[Geom::X]; yrel = gtk_adjustment_get_value (a_h) * unit.unittobase; y1 = y0 + yrel * bbox_user->dimensions()[Geom::Y]; } // Keep proportions if lock is on GtkToggleAction *lock = GTK_TOGGLE_ACTION( g_object_get_data(G_OBJECT(spw), "lock") ); if ( gtk_toggle_action_get_active(lock) ) { if (adj == a_h) { x1 = x0 + yrel * bbox_user->dimensions()[Geom::X]; } else if (adj == a_w) { y1 = y0 + xrel * bbox_user->dimensions()[Geom::Y]; } } // scales and moves, in px double mh = fabs(x0 - bbox_user->min()[Geom::X]); double sh = fabs(x1 - bbox_user->max()[Geom::X]); double mv = fabs(y0 - bbox_user->min()[Geom::Y]); double sv = fabs(y1 - bbox_user->max()[Geom::Y]); // unless the unit is %, convert the scales and moves to the unit if (unit.base == SP_UNIT_ABSOLUTE || unit.base == SP_UNIT_DEVICE) { mh = sp_pixels_get_units (mh, unit); sh = sp_pixels_get_units (sh, unit); mv = sp_pixels_get_units (mv, unit); sv = sp_pixels_get_units (sv, unit); } // do the action only if one of the scales/moves is greater than half the last significant // digit in the spinbox (currently spinboxes have 3 fractional digits, so that makes 0.0005). If // the value was changed by the user, the difference will be at least that much; otherwise it's // just rounding difference between the spinbox value and actual value, so no action is // performed char const * const actionkey = ( mh > 5e-4 ? "selector:toolbar:move:horizontal" : sh > 5e-4 ? "selector:toolbar:scale:horizontal" : mv > 5e-4 ? "selector:toolbar:move:vertical" : sv > 5e-4 ? "selector:toolbar:scale:vertical" : NULL ); if (actionkey != NULL) { // FIXME: fix for GTK breakage, see comment in SelectedStyle::on_opacity_changed sp_desktop_canvas(desktop)->forceFullRedrawAfterInterruptions(0); int transform_stroke = prefs->getBool("/options/transform/stroke", true) ? 1 : 0; Geom::Affine scaler; if (bbox_type == SPItem::VISUAL_BBOX) { scaler = get_scale_transform_for_variable_stroke (*bbox_vis, *bbox_geom, transform_stroke, x0, y0, x1, y1); } else { // 1) We could have use the newer get_scale_transform_for_variable_stroke() here, but to avoid regressions // we'll just use the old get_scale_transform_for_uniform_stroke() for now. // 2) get_scale_transform_for_uniform_stroke() is intended for visual bounding boxes, not geometrical ones! // we'll trick it into using a geometric bounding box though, by setting the stroke width to zero scaler = get_scale_transform_for_uniform_stroke (*bbox_geom, 0, false, x0, y0, x1, y1); } sp_selection_apply_affine(selection, scaler); DocumentUndo::maybeDone(document, actionkey, SP_VERB_CONTEXT_SELECT, _("Transform by toolbar")); // resume interruptibility sp_desktop_canvas(desktop)->endForcedFullRedraws(); } g_object_set_data(G_OBJECT(spw), "update", GINT_TO_POINTER(FALSE)); }
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 = desktop->getMessageStack(); Inkscape::Selection *selection = desktop->getSelection(); 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; doc->ensureUpToDate(); SPImage *img = getSelectedSPImage(); if (!img) { engine = NULL; return; } GdkPixbuf *trace_pb = gdk_pixbuf_copy(img->pixbuf->getPixbufRaw(false)); if (img->pixbuf->pixelFormat() == Inkscape::Pixbuf::PF_CAIRO) { convert_pixels_argb32_to_pixbuf( gdk_pixbuf_get_pixels(trace_pb), gdk_pixbuf_get_width(trace_pb), gdk_pixbuf_get_height(trace_pb), gdk_pixbuf_get_rowstride(trace_pb)); } Glib::RefPtr<Gdk::Pixbuf> pixbuf = Glib::wrap(trace_pb, false); 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 //XML Tree being used directly here while it shouldn't be. Inkscape::XML::Node *imgRepr = SP_OBJECT(img)->getRepr(); Inkscape::XML::Node *par = imgRepr->parent(); //### 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::Affine tf(scal * trans); tf *= img->transform; //#OK. Now let's start making new nodes Inkscape::XML::Document *xml_doc = desktop->doc()->getReprDoc(); 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); newItem->doWriteTransform(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 DocumentUndo::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); }