static void sp_arctb_startend_value_changed(GtkAdjustment *adj, GObject *tbl, gchar const *value_name, gchar const *other_name) { SPDesktop *desktop = static_cast<SPDesktop *>(g_object_get_data( tbl, "desktop" )); if (DocumentUndo::getUndoSensitive(desktop->getDocument())) { Inkscape::Preferences *prefs = Inkscape::Preferences::get(); prefs->setDouble(Glib::ustring("/tools/shapes/arc/") + value_name, gtk_adjustment_get_value(adj)); } // quit if run by the attr_changed listener if (g_object_get_data( tbl, "freeze" )) { return; } // in turn, prevent listener from responding g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE) ); gchar* namespaced_name = g_strconcat("sodipodi:", value_name, NULL); bool modmade = false; std::vector<SPItem*> itemlist=desktop->getSelection()->itemList(); for(std::vector<SPItem*>::const_iterator i=itemlist.begin();i!=itemlist.end();i++){ SPItem *item = *i; if (SP_IS_GENERICELLIPSE(item)) { SPGenericEllipse *ge = SP_GENERICELLIPSE(item); if (!strcmp(value_name, "start")) { ge->start = (gtk_adjustment_get_value(adj) * M_PI)/ 180; } else { ge->end = (gtk_adjustment_get_value(adj) * M_PI)/ 180; } ge->normalize(); (SP_OBJECT(ge))->updateRepr(); (SP_OBJECT(ge))->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); modmade = true; } } g_free(namespaced_name); GtkAdjustment *other = GTK_ADJUSTMENT( g_object_get_data( tbl, other_name ) ); sp_arctb_sensitivize( tbl, gtk_adjustment_get_value(adj), gtk_adjustment_get_value(other) ); if (modmade) { DocumentUndo::maybeDone(desktop->getDocument(), value_name, SP_VERB_CONTEXT_ARC, _("Arc: Change start/end")); } g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) ); }
static void sp_arctb_open_state_changed( EgeSelectOneAction *act, GObject *tbl ) { SPDesktop *desktop = static_cast<SPDesktop *>(g_object_get_data( tbl, "desktop" )); if (DocumentUndo::getUndoSensitive(desktop->getDocument())) { Inkscape::Preferences *prefs = Inkscape::Preferences::get(); prefs->setBool("/tools/shapes/arc/open", ege_select_one_action_get_active(act) != 0); } // quit if run by the attr_changed listener if (g_object_get_data( tbl, "freeze" )) { return; } // in turn, prevent listener from responding g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE) ); bool modmade = false; if ( ege_select_one_action_get_active(act) != 0 ) { std::vector<SPItem*> itemlist=desktop->getSelection()->itemList(); for(std::vector<SPItem*>::const_iterator i=itemlist.begin();i!=itemlist.end();i++){ SPItem *item = *i; if (SP_IS_GENERICELLIPSE(item)) { Inkscape::XML::Node *repr = item->getRepr(); repr->setAttribute("sodipodi:open", "true"); item->updateRepr(); modmade = true; } } } else { std::vector<SPItem*> itemlist=desktop->getSelection()->itemList(); for(std::vector<SPItem*>::const_iterator i=itemlist.begin();i!=itemlist.end();i++){ SPItem *item = *i; if (SP_IS_GENERICELLIPSE(item)) { Inkscape::XML::Node *repr = item->getRepr(); repr->setAttribute("sodipodi:open", NULL); item->updateRepr(); modmade = true; } } } if (modmade) { DocumentUndo::done(desktop->getDocument(), SP_VERB_CONTEXT_ARC, _("Arc: Change open/closed")); } g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) ); }
static void box3d_angle_value_changed(GtkAdjustment *adj, GObject *dataKludge, Proj::Axis axis) { SPDesktop *desktop = static_cast<SPDesktop *>(g_object_get_data( dataKludge, "desktop" )); SPDocument *document = desktop->getDocument(); // quit if run by the attr_changed or selection changed listener if (g_object_get_data( dataKludge, "freeze" )) { return; } // in turn, prevent listener from responding g_object_set_data(dataKludge, "freeze", GINT_TO_POINTER(TRUE)); std::list<Persp3D *> sel_persps = desktop->getSelection()->perspList(); if (sel_persps.empty()) { // this can happen when the document is created; we silently ignore it return; } Persp3D *persp = sel_persps.front(); persp->perspective_impl->tmat.set_infinite_direction (axis, gtk_adjustment_get_value(adj)); persp->updateRepr(); // TODO: use the correct axis here, too DocumentUndo::maybeDone(document, "perspangle", SP_VERB_CONTEXT_3DBOX, _("3D Box: Change perspective (angle of infinite axis)")); g_object_set_data( dataKludge, "freeze", GINT_TO_POINTER(FALSE) ); }
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")); }
static void sp_rtb_value_changed(GtkAdjustment *adj, GObject *tbl, gchar const *value_name, void (SPRect::*setter)(gdouble)) { SPDesktop *desktop = static_cast<SPDesktop *>(g_object_get_data( tbl, "desktop" )); UnitTracker* tracker = reinterpret_cast<UnitTracker*>(g_object_get_data( tbl, "tracker" )); Unit const *unit = tracker->getActiveUnit(); g_return_if_fail(unit != NULL); if (DocumentUndo::getUndoSensitive(desktop->getDocument())) { Inkscape::Preferences *prefs = Inkscape::Preferences::get(); prefs->setDouble(Glib::ustring("/tools/shapes/rect/") + value_name, Quantity::convert(gtk_adjustment_get_value(adj), unit, "px")); } // quit if run by the attr_changed listener if (g_object_get_data( tbl, "freeze" ) || tracker->isUpdating()) { return; } // in turn, prevent listener from responding g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE)); bool modmade = false; Inkscape::Selection *selection = desktop->getSelection(); std::vector<SPItem*> itemlist=selection->itemList(); for(std::vector<SPItem*>::const_iterator i=itemlist.begin();i!=itemlist.end();++i){ if (SP_IS_RECT(*i)) { if (gtk_adjustment_get_value(adj) != 0) { (SP_RECT(*i)->*setter)(Quantity::convert(gtk_adjustment_get_value(adj), unit, "px")); } else { (*i)->getRepr()->setAttribute(value_name, NULL); } modmade = true; } } sp_rtb_sensitivize( tbl ); if (modmade) { DocumentUndo::done(desktop->getDocument(), SP_VERB_CONTEXT_RECT, _("Change rectangle")); } g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) ); }
static void sp_spl_tb_value_changed(GtkAdjustment *adj, GObject *tbl, Glib::ustring const &value_name) { SPDesktop *desktop = static_cast<SPDesktop *>(g_object_get_data( tbl, "desktop" )); if (DocumentUndo::getUndoSensitive(desktop->getDocument())) { Inkscape::Preferences *prefs = Inkscape::Preferences::get(); prefs->setDouble("/tools/shapes/spiral/" + value_name, gtk_adjustment_get_value(adj)); } // quit if run by the attr_changed listener if (g_object_get_data( tbl, "freeze" )) { return; } // in turn, prevent listener from responding g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE) ); gchar* namespaced_name = g_strconcat("sodipodi:", value_name.data(), NULL); bool modmade = false; std::vector<SPItem*> itemlist=desktop->getSelection()->itemList(); for(std::vector<SPItem*>::const_iterator i=itemlist.begin();i!=itemlist.end(); ++i){ SPItem *item = *i; if (SP_IS_SPIRAL(item)) { Inkscape::XML::Node *repr = item->getRepr(); sp_repr_set_svg_double( repr, namespaced_name, gtk_adjustment_get_value(adj) ); item->updateRepr(); modmade = true; } } g_free(namespaced_name); if (modmade) { DocumentUndo::done(desktop->getDocument(), SP_VERB_CONTEXT_SPIRAL, _("Change spiral")); } g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) ); }
void ObjectCompositeSettings::_opacityValueChanged() { if (!_subject) { return; } SPDesktop *desktop = _subject->getDesktop(); if (!desktop) { return; } if (_blocked) return; _blocked = true; // FIXME: fix for GTK breakage, see comment in SelectedStyle::on_opacity_changed; here it results in crash 1580903 // UPDATE: crash fixed in GTK+ 2.10.7 (bug 374378), remove this as soon as it's reasonably common // (though this only fixes the crash, not the multiple change events) //sp_canvas_force_full_redraw_after_interruptions(desktop->getCanvas(), 0); SPCSSAttr *css = sp_repr_css_attr_new (); Inkscape::CSSOStringStream os; os << CLAMP (_opacity_scale.get_adjustment()->get_value() / 100, 0.0, 1.0); sp_repr_css_set_property (css, "opacity", os.str().c_str()); _subject->setCSS(css); sp_repr_css_attr_unref (css); DocumentUndo::maybeDone(desktop->getDocument(), _opacity_tag.c_str(), _verb_code, _("Change opacity")); // resume interruptibility //sp_canvas_end_forced_full_redraws(desktop->getCanvas()); _blocked = false; }
/** * Sets mesh type: Coons, Bicubic */ static void ms_type_changed(EgeSelectOneAction *act, GtkWidget *widget) { // std::cout << "ms_type_changed" << std::endl; if (blocked) { return; } SPDesktop *desktop = static_cast<SPDesktop *>(g_object_get_data(G_OBJECT(widget), "desktop")); Inkscape::Selection *selection = desktop->getSelection(); SPMesh *gradient = 0; ms_get_dt_selected_gradient(selection, gradient); if (gradient) { SPMeshType type = (SPMeshType) ege_select_one_action_get_active(act); // std::cout << " type: " << type << std::endl; gradient->type = type; gradient->type_set = true; gradient->updateRepr(); DocumentUndo::done(desktop->getDocument(), SP_VERB_CONTEXT_MESH, _("Set mesh type")); } }
static void sp_erasertb_mode_changed( EgeSelectOneAction *act, GObject *tbl ) { SPDesktop *desktop = static_cast<SPDesktop *>(g_object_get_data( tbl, "desktop" )); bool eraserMode = ege_select_one_action_get_active( act ) != 0; if (DocumentUndo::getUndoSensitive(desktop->getDocument())) { Inkscape::Preferences *prefs = Inkscape::Preferences::get(); prefs->setBool( "/tools/eraser/mode", eraserMode ); } // only take action if run by the attr_changed listener if (!g_object_get_data( tbl, "freeze" )) { // in turn, prevent listener from responding g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE) ); /* if ( eraserMode != 0 ) { } else { } */ // TODO finish implementation g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) ); } }
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; }
gint sp_dt_guide_event(SPCanvasItem *item, GdkEvent *event, gpointer data) { static bool moved = false; gint ret = FALSE; SPGuide *guide = SP_GUIDE(data); SPDesktop *desktop = static_cast<SPDesktop*>(g_object_get_data(G_OBJECT(item->canvas), "SPDesktop")); switch (event->type) { case GDK_2BUTTON_PRESS: if (event->button.button == 1) { drag_type = SP_DRAG_NONE; sp_event_context_discard_delayed_snap_event(desktop->event_context); sp_canvas_item_ungrab(item, event->button.time); Inkscape::UI::Dialogs::GuidelinePropertiesDialog::showDialog(guide, desktop); ret = TRUE; } break; case GDK_BUTTON_PRESS: if (event->button.button == 1) { Geom::Point const event_w(event->button.x, event->button.y); Geom::Point const event_dt(desktop->w2d(event_w)); // Due to the tolerance allowed when grabbing a guide, event_dt will generally // be close to the guide but not just exactly on it. The drag origin calculated // here must be exactly on the guide line though, otherwise // small errors will occur once we snap, see // https://bugs.launchpad.net/inkscape/+bug/333762 drag_origin = Geom::projection(event_dt, Geom::Line(guide->getPoint(), guide->angle())); if (event->button.state & GDK_SHIFT_MASK) { // with shift we rotate the guide drag_type = SP_DRAG_ROTATE; } else { if (event->button.state & GDK_CONTROL_MASK) { drag_type = SP_DRAG_MOVE_ORIGIN; } else { drag_type = SP_DRAG_TRANSLATE; } } if (drag_type == SP_DRAG_ROTATE || drag_type == SP_DRAG_TRANSLATE) { sp_canvas_item_grab(item, ( GDK_BUTTON_RELEASE_MASK | GDK_BUTTON_PRESS_MASK | GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK ), NULL, event->button.time); } ret = TRUE; } break; case GDK_MOTION_NOTIFY: if (drag_type != SP_DRAG_NONE) { Geom::Point const motion_w(event->motion.x, event->motion.y); Geom::Point motion_dt(desktop->w2d(motion_w)); sp_event_context_snap_delay_handler(desktop->event_context, (gpointer) item, data, (GdkEventMotion *)event, Inkscape::UI::Tools::DelayedSnapEvent::GUIDE_HANDLER); // This is for snapping while dragging existing guidelines. New guidelines, // which are dragged off the ruler, are being snapped in sp_dt_ruler_event SnapManager &m = desktop->namedview->snap_manager; m.setup(desktop, true, NULL, NULL, guide); if (drag_type == SP_DRAG_MOVE_ORIGIN) { // If we snap in guideConstrainedSnap() below, then motion_dt will // be forced to be on the guide. If we don't snap however, then // the origin should still be constrained to the guide. So let's do // that explicitly first: Geom::Line line(guide->getPoint(), guide->angle()); Geom::Coord t = line.nearestTime(motion_dt); motion_dt = line.pointAt(t); if (!(event->motion.state & GDK_SHIFT_MASK)) { m.guideConstrainedSnap(motion_dt, *guide); } } else if (!((drag_type == SP_DRAG_ROTATE) && (event->motion.state & GDK_CONTROL_MASK))) { // cannot use shift here to disable snapping, because we already use it for rotating the guide Geom::Point temp; if (drag_type == SP_DRAG_ROTATE) { temp = guide->getPoint(); m.guideFreeSnap(motion_dt, temp, true, false); guide->moveto(temp, false); } else { temp = guide->getNormal(); m.guideFreeSnap(motion_dt, temp, false, true); guide->set_normal(temp, false); } } m.unSetup(); switch (drag_type) { case SP_DRAG_TRANSLATE: { guide->moveto(motion_dt, false); break; } case SP_DRAG_ROTATE: { Geom::Point pt = motion_dt - guide->getPoint(); Geom::Angle angle(pt); if (event->motion.state & GDK_CONTROL_MASK) { Inkscape::Preferences *prefs = Inkscape::Preferences::get(); unsigned const snaps = abs(prefs->getInt("/options/rotationsnapsperpi/value", 12)); bool const relative_snaps = prefs->getBool("/options/relativeguiderotationsnap/value", false); if (snaps) { if (relative_snaps) { Geom::Angle orig_angle(guide->getNormal()); Geom::Angle snap_angle = angle - orig_angle; double sections = floor(snap_angle.radians0() * snaps / M_PI + .5); angle = (M_PI / snaps) * sections + orig_angle.radians0(); } else { double sections = floor(angle.radians0() * snaps / M_PI + .5); angle = (M_PI / snaps) * sections; } } } guide->set_normal(Geom::Point::polar(angle).cw(), false); break; } case SP_DRAG_MOVE_ORIGIN: { guide->moveto(motion_dt, false); break; } case SP_DRAG_NONE: assert(false); break; } moved = true; desktop->set_coordinate_status(motion_dt); ret = TRUE; } break; case GDK_BUTTON_RELEASE: if (drag_type != SP_DRAG_NONE && event->button.button == 1) { sp_event_context_discard_delayed_snap_event(desktop->event_context); if (moved) { Geom::Point const event_w(event->button.x, event->button.y); Geom::Point event_dt(desktop->w2d(event_w)); SnapManager &m = desktop->namedview->snap_manager; m.setup(desktop, true, NULL, NULL, guide); if (drag_type == SP_DRAG_MOVE_ORIGIN) { // If we snap in guideConstrainedSnap() below, then motion_dt will // be forced to be on the guide. If we don't snap however, then // the origin should still be constrained to the guide. So let's // do that explicitly first: Geom::Line line(guide->getPoint(), guide->angle()); Geom::Coord t = line.nearestTime(event_dt); event_dt = line.pointAt(t); if (!(event->button.state & GDK_SHIFT_MASK)) { m.guideConstrainedSnap(event_dt, *guide); } } else if (!((drag_type == SP_DRAG_ROTATE) && (event->motion.state & GDK_CONTROL_MASK))) { // cannot use shift here to disable snapping, because we already use it for rotating the guide Geom::Point temp; if (drag_type == SP_DRAG_ROTATE) { temp = guide->getPoint(); m.guideFreeSnap(event_dt, temp, true, false); guide->moveto(temp, false); } else { temp = guide->getNormal(); m.guideFreeSnap(event_dt, temp, false, true); guide->set_normal(temp, false); } } m.unSetup(); if (sp_canvas_world_pt_inside_window(item->canvas, event_w)) { switch (drag_type) { case SP_DRAG_TRANSLATE: { guide->moveto(event_dt, true); break; } case SP_DRAG_ROTATE: { Geom::Point pt = event_dt - guide->getPoint(); Geom::Angle angle(pt); if (event->motion.state & GDK_CONTROL_MASK) { Inkscape::Preferences *prefs = Inkscape::Preferences::get(); unsigned const snaps = abs(prefs->getInt("/options/rotationsnapsperpi/value", 12)); bool const relative_snaps = prefs->getBool("/options/relativeguiderotationsnap/value", false); if (snaps) { if (relative_snaps) { Geom::Angle orig_angle(guide->getNormal()); Geom::Angle snap_angle = angle - orig_angle; double sections = floor(snap_angle.radians0() * snaps / M_PI + .5); angle = (M_PI / snaps) * sections + orig_angle.radians0(); } else { double sections = floor(angle.radians0() * snaps / M_PI + .5); angle = (M_PI / snaps) * sections; } } } guide->set_normal(Geom::Point::polar(angle).cw(), true); break; } case SP_DRAG_MOVE_ORIGIN: { guide->moveto(event_dt, true); break; } case SP_DRAG_NONE: assert(false); break; } DocumentUndo::done(desktop->getDocument(), SP_VERB_NONE, _("Move guide")); } else { /* Undo movement of any attached shapes. */ guide->moveto(guide->getPoint(), false); guide->set_normal(guide->getNormal(), false); sp_guide_remove(guide); DocumentUndo::done(desktop->getDocument(), SP_VERB_NONE, _("Delete guide")); } moved = false; desktop->set_coordinate_status(event_dt); } drag_type = SP_DRAG_NONE; sp_canvas_item_ungrab(item, event->button.time); ret=TRUE; } break; case GDK_ENTER_NOTIFY: { sp_guideline_set_color(SP_GUIDELINE(item), guide->getHiColor()); // set move or rotate cursor Geom::Point const event_w(event->crossing.x, event->crossing.y); if ((event->crossing.state & GDK_SHIFT_MASK) && (drag_type != SP_DRAG_MOVE_ORIGIN)) { GdkCursor *guide_cursor; guide_cursor = gdk_cursor_new (GDK_EXCHANGE); gdk_window_set_cursor(gtk_widget_get_window (GTK_WIDGET(desktop->getCanvas())), guide_cursor); #if GTK_CHECK_VERSION(3,0,0) g_object_unref(guide_cursor); #else gdk_cursor_unref(guide_cursor); #endif } else { GdkCursor *guide_cursor; guide_cursor = gdk_cursor_new (GDK_HAND1); gdk_window_set_cursor(gtk_widget_get_window (GTK_WIDGET(desktop->getCanvas())), guide_cursor); #if GTK_CHECK_VERSION(3,0,0) g_object_unref(guide_cursor); #else gdk_cursor_unref(guide_cursor); #endif } char *guide_description = guide->description(); desktop->guidesMessageContext()->setF(Inkscape::NORMAL_MESSAGE, _("<b>Guideline</b>: %s"), guide_description); g_free(guide_description); break; } case GDK_LEAVE_NOTIFY: sp_guideline_set_color(SP_GUIDELINE(item), guide->getColor()); // restore event context's cursor gdk_window_set_cursor(gtk_widget_get_window (GTK_WIDGET(desktop->getCanvas())), desktop->event_context->cursor); desktop->guidesMessageContext()->clear(); break; case GDK_KEY_PRESS: switch (Inkscape::UI::Tools::get_group0_keyval (&event->key)) { case GDK_KEY_Delete: case GDK_KEY_KP_Delete: case GDK_KEY_BackSpace: { SPDocument *doc = guide->document; sp_guide_remove(guide); DocumentUndo::done(doc, SP_VERB_NONE, _("Delete guide")); ret = TRUE; sp_event_context_discard_delayed_snap_event(desktop->event_context); break; } case GDK_KEY_Shift_L: case GDK_KEY_Shift_R: if (drag_type != SP_DRAG_MOVE_ORIGIN) { GdkCursor *guide_cursor; guide_cursor = gdk_cursor_new (GDK_EXCHANGE); gdk_window_set_cursor(gtk_widget_get_window (GTK_WIDGET(desktop->getCanvas())), guide_cursor); #if GTK_CHECK_VERSION(3,0,0) g_object_unref(guide_cursor); #else gdk_cursor_unref(guide_cursor); #endif ret = TRUE; break; } default: // do nothing; break; } break; case GDK_KEY_RELEASE: switch (Inkscape::UI::Tools::get_group0_keyval (&event->key)) { case GDK_KEY_Shift_L: case GDK_KEY_Shift_R: GdkCursor *guide_cursor; guide_cursor = gdk_cursor_new (GDK_EXCHANGE); gdk_window_set_cursor(gtk_widget_get_window (GTK_WIDGET(desktop->getCanvas())), guide_cursor); #if GTK_CHECK_VERSION(3,0,0) g_object_unref(guide_cursor); #else gdk_cursor_unref(guide_cursor); #endif break; default: // do nothing; break; } break; default: break; } return ret; }
SPObject *get_stock_item(gchar const *urn, gboolean stock) { g_assert(urn != NULL); /* check its an inkscape URN */ if (!strncmp (urn, "urn:inkscape:", 13)) { gchar const *e = urn + 13; int a = 0; gchar * name = g_strdup(e); gchar *name_p = name; while (*name_p != ':' && *name_p != '\0'){ name_p++; a++; } if (*name_p ==':') { name_p++; } gchar * base = g_strndup(e, a); SPDesktop *desktop = SP_ACTIVE_DESKTOP; SPDocument *doc = desktop->getDocument(); SPDefs *defs = doc->getDefs(); if (!defs) { g_free(base); return NULL; } SPObject *object = NULL; if (!strcmp(base, "marker") && !stock) { for ( SPObject *child = defs->firstChild(); child; child = child->getNext() ) { if (child->getRepr()->attribute("inkscape:stockid") && !strcmp(name_p, child->getRepr()->attribute("inkscape:stockid")) && SP_IS_MARKER(child)) { object = child; } } } else if (!strcmp(base,"pattern") && !stock) { for ( SPObject *child = defs->firstChild() ; child; child = child->getNext() ) { if (child->getRepr()->attribute("inkscape:stockid") && !strcmp(name_p, child->getRepr()->attribute("inkscape:stockid")) && SP_IS_PATTERN(child)) { object = child; } } } else if (!strcmp(base,"gradient") && !stock) { for ( SPObject *child = defs->firstChild(); child; child = child->getNext() ) { if (child->getRepr()->attribute("inkscape:stockid") && !strcmp(name_p, child->getRepr()->attribute("inkscape:stockid")) && SP_IS_GRADIENT(child)) { object = child; } } } if (object == NULL) { if (!strcmp(base, "marker")) { object = sp_marker_load_from_svg(name_p, doc); } else if (!strcmp(base, "pattern")) { object = sp_pattern_load_from_svg(name_p, doc); } else if (!strcmp(base, "gradient")) { object = sp_gradient_load_from_svg(name_p, doc); } } g_free(base); g_free(name); if (object) { object->getRepr()->setAttribute("inkscape:isstock", "true"); } return object; } else { SPDesktop *desktop = SP_ACTIVE_DESKTOP; SPDocument *doc = desktop->getDocument(); SPObject *object = doc->getObjectById(urn); return object; } }
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(); }
void ObjectCompositeSettings::_blendBlurValueChanged() { if (!_subject) { return; } SPDesktop *desktop = _subject->getDesktop(); if (!desktop) { return; } SPDocument *document = desktop->getDocument(); 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(desktop->getCanvas(), 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 std::vector<SPObject*> sel=_subject->list(); for (std::vector<SPObject*>::const_iterator i = sel.begin() ; i != sel.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(desktop->getCanvas()); _blocked = false; }
void ObjectCompositeSettings::_subjectChanged() { if (!_subject) { return; } SPDesktop *desktop = _subject->getDesktop(); if (!desktop) { return; } if (_blocked) return; _blocked = true; SPStyle query(desktop->getDocument()); 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; } } _blocked = false; }
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 = desktop->getSelection(); SPDocument *document = desktop->getDocument(); 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; Unit const *unit = tracker->getActiveUnit(); g_return_if_fail(unit != NULL); 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->type == Inkscape::Util::UNIT_TYPE_LINEAR) { x0 = Quantity::convert(gtk_adjustment_get_value(a_x), unit, "px"); y0 = Quantity::convert(gtk_adjustment_get_value(a_y), unit, "px"); x1 = x0 + Quantity::convert(gtk_adjustment_get_value(a_w), unit, "px"); xrel = Quantity::convert(gtk_adjustment_get_value(a_w), unit, "px") / bbox_user->dimensions()[Geom::X]; y1 = y0 + Quantity::convert(gtk_adjustment_get_value(a_h), unit, "px");; yrel = Quantity::convert(gtk_adjustment_get_value(a_h), unit, "px") / bbox_user->dimensions()[Geom::Y]; } else { double const x0_propn = gtk_adjustment_get_value (a_x) / 100 / unit->factor; x0 = bbox_user->min()[Geom::X] * x0_propn; double const y0_propn = gtk_adjustment_get_value (a_y) / 100 / unit->factor; y0 = y0_propn * bbox_user->min()[Geom::Y]; xrel = gtk_adjustment_get_value (a_w) / (100 / unit->factor); x1 = x0 + xrel * bbox_user->dimensions()[Geom::X]; yrel = gtk_adjustment_get_value (a_h) / (100 / unit->factor); 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->type == Inkscape::Util::UNIT_TYPE_LINEAR) { mh = Quantity::convert(mh, "px", unit); sh = Quantity::convert(sh, "px", unit); mv = Quantity::convert(mv, "px", unit); sv = Quantity::convert(sv, "px", 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 desktop->getCanvas()->forceFullRedrawAfterInterruptions(0); bool transform_stroke = prefs->getBool("/options/transform/stroke", true); bool preserve = prefs->getBool("/options/preservetransform/value", false); Geom::Affine scaler; if (bbox_type == SPItem::VISUAL_BBOX) { scaler = get_scale_transform_for_variable_stroke (*bbox_vis, *bbox_geom, transform_stroke, preserve, 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, 0, false, false, x0, y0, x1, y1); } sp_selection_apply_affine(selection, scaler); DocumentUndo::maybeDone(document, actionkey, SP_VERB_CONTEXT_SELECT, _("Transform by toolbar")); // resume interruptibility desktop->getCanvas()->endForcedFullRedraws(); } g_object_set_data(G_OBJECT(spw), "update", GINT_TO_POINTER(FALSE)); }