23#include <gdk/gdkkeysyms.h>
24#include <glibmm/i18n.h>
62 , cursor_addnode(false)
71 if (prefs->
getBool(
"/tools/mesh/selcue",
true)) {
92 this->
selcon->disconnect();
100 N_(
"Linear gradient <b>start</b>"),
101 N_(
"Linear gradient <b>end</b>"),
102 N_(
"Linear gradient <b>mid stop</b>"),
103 N_(
"Radial gradient <b>center</b>"),
104 N_(
"Radial gradient <b>radius</b>"),
105 N_(
"Radial gradient <b>radius</b>"),
106 N_(
"Radial gradient <b>focus</b>"),
107 N_(
"Radial gradient <b>mid stop</b>"),
108 N_(
"Radial gradient <b>mid stop</b>"),
109 N_(
"Mesh gradient <b>corner</b>"),
110 N_(
"Mesh gradient <b>handle</b>"),
111 N_(
"Mesh gradient <b>tensor</b>")
117 if (selection ==
nullptr) {
121 guint n_obj = (guint) boost::distance(selection->
items());
133 gchar * message = g_strconcat(
137 ngettext(
" out of %d mesh handle",
" out of %d mesh handles",n_tot),
138 ngettext(
" on %d selected object",
" on %d selected objects",n_obj),
nullptr);
145 ngettext(
"One handle merging %d stop (drag with <b>Shift</b> to separate) selected",
146 "One handle merging %d stops (drag with <b>Shift</b> to separate) selected",
148 ngettext(
" out of %d mesh handle",
" out of %d mesh handles",n_tot),
149 ngettext(
" on %d selected object",
" on %d selected objects",n_obj),
nullptr);
152 }
else if (n_sel > 1) {
155 g_strconcat(ngettext(
"<b>%d</b> mesh handle selected out of %d",
"<b>%d</b> mesh handles selected out of %d",n_sel),
157 ngettext(
" on %d selected object",
" on %d selected objects",n_obj),
nullptr);
159 }
else if (n_sel == 0) {
162 ngettext(
"<b>No</b> mesh handles selected out of %d on %d selected object",
163 "<b>No</b> mesh handles selected out of %d on %d selected objects",n_obj), n_tot, n_obj);
173 if (entry_name ==
"show_handles") {
175 }
else if (entry_name ==
"edit_fill") {
177 }
else if (entry_name ==
"edit_stroke") {
206 std::vector<GrDrag::ItemCurve*> selected;
209 if (it.curve->contains(event_p,
tolerance)) {
210 selected.emplace_back(&it);
225 std::cout <<
"split_near_point: entrance: " << mouse_p << std::endl;
241 std::cout <<
"sp_mesh_corner_operation: entrance: " << operation << std::endl;
246 std::map<SPMeshGradient*, std::vector<guint> > points;
247 std::map<SPMeshGradient*, SPItem*>
items;
248 std::map<SPMeshGradient*, Inkscape::PaintTarget> fill_or_stroke;
254 for (
auto d : dragger->draggables) {
259 auto gradient = cast<SPMeshGradient>(
getGradient (d->item, d->fill_or_stroke) );
262 points[gradient].push_back( d->point_i );
263 items[gradient] = d->item;
269 for( std::map<
SPMeshGradient*, std::vector<guint> >::const_iterator iter = points.begin(); iter != points.end(); ++iter) {
271 if( iter->second.size() > 0 ) {
272 guint noperation = 0;
306 std::cerr <<
"sp_mesh_corner_operation: unknown operation" << std::endl;
309 if( noperation > 0 ) {
317 DocumentUndo::done(doc, _(
"Toggled mesh path type."), INKSCAPE_ICON(
"mesh-gradient"));
322 DocumentUndo::done(doc, _(
"Approximated arc for mesh side."), INKSCAPE_ICON(
"mesh-gradient"));
332 DocumentUndo::done(doc, _(
"Smoothed mesh corner color."), INKSCAPE_ICON(
"mesh-gradient"));
337 DocumentUndo::done(doc, _(
"Picked mesh corner color."), INKSCAPE_ICON(
"mesh-gradient"));
342 DocumentUndo::done(doc, _(
"Inserted new row or column."), INKSCAPE_ICON(
"mesh-gradient"));
346 std::cerr <<
"sp_mesh_corner_operation: unknown operation" << std::endl;
361 std::cout <<
"fit_mesh_in_bbox: entrance: Entrance" << std::endl;
365 if (selection ==
nullptr) {
369 bool changed =
false;
370 auto itemlist = selection->
items();
371 for (
auto i=itemlist.begin(); i!=itemlist.end(); ++i) {
378 if (style->
fill.isPaintserver()) {
380 if ( is<SPMeshGradient>(server) ) {
383 auto gradient = cast<SPMeshGradient>(server);
384 if (gradient->array.fill_box( item_bbox )) {
390 if (style->
stroke.isPaintserver()) {
392 if ( is<SPMeshGradient>(server) ) {
395 auto gradient = cast<SPMeshGradient>(server);
396 if (gradient->array.fill_box( item_bbox )) {
416 auto fill_or_stroke_pref =
421 (fill_or_stroke_pref ==
Inkscape::FOR_FILL) ? style->getFillPaintServer() : style->getStrokePaintServer();
422 if (is<SPMeshGradient>(server)) {
439 tolerance = prefs->getIntLimited(
"/options/dragtolerance/value", 0, 0, 100);
441 bool contains_mesh =
false;
442 if (!selection->isEmpty()) {
443 contains_mesh =
has_mesh(selection->items().front());
452 if (event.num_press == 2 && event.button == 1) {
455 std::cout <<
"root_handler: GDK_2BUTTON_PRESS" << std::endl;
463 auto over_curve = this->over_curve(event.pos);
465 if (!over_curve.empty() && contains_mesh) {
468 split_near_point(selection->items().front(), mousepoint_doc);
469 }
else if (!contains_mesh) {
480 if (event.num_press == 1 && event.button == 1) {
483 std::cout <<
"root_handler: GDK_BUTTON_PRESS" << std::endl;
498 bool add = (
event.modifiers & GDK_SHIFT_MASK);
499 bool toggle = (
event.modifiers & GDK_CONTROL_MASK);
500 if ( !add && !toggle ) {
519 if (contains_mesh && !(event.
modifiers & GDK_CONTROL_MASK)) {
525 if (!(event.
modifiers & GDK_CONTROL_MASK)) {
529 if (!selection->isEmpty()) {
544 if (dragging && (event.modifiers & GDK_BUTTON1_MASK)) {
545 if (!checkDragMoved(event.pos)) {
550 std::cout <<
"root_handler: GDK_MOTION_NOTIFY: Dragging" << std::endl;
553 Geom::Point const motion_dt = _desktop->w2d(event.pos);
571 if (!_grdrag->mouseOver() && !selection->isEmpty()) {
572 auto &m = _desktop->getNamedView()->snap_manager;
575 auto const motion_dt = _desktop->w2d(event.pos);
581 if (_grdrag->mouseOver()) {
588 auto over_curve = this->over_curve(event.pos);
590 if (cursor_addnode && over_curve.empty()) {
591 set_cursor(
"mesh.svg");
592 cursor_addnode =
false;
593 }
else if (!cursor_addnode && !over_curve.empty() && contains_mesh) {
594 set_cursor(
"mesh-add.svg");
595 cursor_addnode =
true;
599 [&] (ButtonReleaseEvent
const &event) {
601 if (event.button == 1) {
604 std::cout <<
"root_handler: GDK_BUTTON_RELEASE" << std::endl;
608 auto over_curve = this->over_curve(event.pos);
610 if ( (event.modifiers & GDK_CONTROL_MASK) && (event.modifiers & GDK_ALT_MASK ) ) {
611 if (!over_curve.empty() &&
has_mesh(over_curve[0]->
item)) {
612 split_near_point(over_curve[0]->
item, mousepoint_doc);
619 if (event.modifiers & GDK_CONTROL_MASK && !(event.modifiers & GDK_SHIFT_MASK)) {
624 if (!within_tolerance) {
628 if (!contains_mesh) {
636 if (r->
isStarted() && !this->within_tolerance) {
640 if (!(event.modifiers & GDK_SHIFT_MASK)) {
641 _grdrag->deselectAll();
643 _grdrag->selectRect(*b);
648 }
else if (this->item_to_select) {
649 if (!over_curve.empty()) {
654 if (event.modifiers & GDK_SHIFT_MASK) {
655 selection->toggle(item_to_select);
657 _grdrag->deselectAll();
658 selection->set(item_to_select);
662 if (!over_curve.empty()) {
667 if (!_grdrag->selected.empty()) {
668 _grdrag->deselectAll();
675 item_to_select =
nullptr;
682 [&] (KeyPressEvent
const &event) {
685 std::cout <<
"root_handler: GDK_KEY_PRESS" << std::endl;
692 case GDK_KEY_Control_L:
693 case GDK_KEY_Control_R:
694 case GDK_KEY_Shift_L:
695 case GDK_KEY_Shift_R:
707 _grdrag->selectAll();
713 if (!_grdrag->selected.empty()) {
714 _grdrag->deselectAll();
726 case GDK_KEY_KP_Insert:
743 case GDK_KEY_KP_Delete:
744 case GDK_KEY_BackSpace:
745 if (!_grdrag->selected.empty()) {
752 if (
mod_alt(event) && _grdrag->isNonEmpty() && _grdrag->hasSelection()) {
760 if (
mod_alt(event) && _grdrag->isNonEmpty() && _grdrag->hasSelection()) {
768 if (
mod_alt(event) && _grdrag->isNonEmpty() && _grdrag->hasSelection()) {
776 if (
mod_alt(event) && _grdrag->isNonEmpty() && _grdrag->hasSelection()) {
784 if (
mod_alt(event) && _grdrag->isNonEmpty() && _grdrag->hasSelection()) {
791 ret = _grdrag->key_press_handler(event);
795 [&] (KeyReleaseEvent
const &event) {
799 case GDK_KEY_Control_L:
800 case GDK_KEY_Control_R:
801 case GDK_KEY_Shift_L:
802 case GDK_KEY_Shift_R:
805 defaultMessageContext()->clear();
811 [&] (CanvasEvent
const &event) {}
818void MeshTool::new_default()
821 SPDocument *document = _desktop->getDocument();
831 if (!_show_handles_value.
isSet()) {
832 prefs->
setBool(
"/tools/mesh/show_handles",
true);
837 prefs->
setBool(
"/tools/mesh/edit_fill",
true );
838 prefs->
setBool(
"/tools/mesh/edit_stroke",
false);
840 prefs->
setBool(
"/tools/mesh/edit_fill",
false);
841 prefs->
setBool(
"/tools/mesh/edit_stroke",
true );
870 (*i)->geometricBounds() : (*i)->visualBounds());
872 bool isText = is<SPText>(*i);
877 (*i)->requestModified(SP_OBJECT_MODIFIED_FLAG|SP_OBJECT_STYLE_MODIFIED_FLAG);
885 DocumentUndo::done(_desktop->getDocument(), _(
"Create mesh"), INKSCAPE_ICON(
"mesh-gradient"));
889 int n_objects = (int) boost::distance(selection->
items());
891 ngettext(
"<b>Gradient</b> for %d object; with <b>Ctrl</b> to snap angle",
892 "<b>Gradient</b> for %d objects; with <b>Ctrl</b> to snap angle", n_objects),
Axis-aligned rectangle that can be empty.
Two-dimensional point that doubles as a vector.
void updateDraggers()
Regenerates the draggers list from the current selection; is called when selection is changed or modi...
guint singleSelectedDraggerSingleDraggableType()
GrDragger * select_prev()
Select the knot previous from the last selected one and deselect all other selected.
void deselectAll()
Deselect all stops/draggers (public; emits signal).
guint singleSelectedDraggerNumDraggables()
GrDragger * select_next()
Select the knot next to the last selected one and deselect all other selected.
SPStop * addStopNearPoint(SPItem *item, Geom::Point mouse_p, double tolerance)
std::set< GrDragger * > selected
std::vector< ItemCurve > item_curves
void setSelected(GrDragger *dragger, bool add_to_selection=false, bool override=true)
Select a dragger.
GrDragger * getDraggerFor(GrDraggable *d)
Select the dragger which has the given draggable.
static void done(SPDocument *document, Glib::ustring const &event_description, Glib::ustring const &undo_icon, unsigned int object_modified_tag=0)
SPItemRange items()
Returns a range of selected SPItems.
bool isEmpty()
Returns true if no items are selected.
Data type representing a typeless value of a preference.
bool isSet() const
Check whether the received entry is set.
Glib::ustring getEntryName() const
Get the last component of the preference's path.
bool getBool(bool def=false) const
Interpret the preference as a Boolean value.
Preference storage class.
bool getBool(Glib::ustring const &pref_path, bool def=false)
Retrieve a Boolean value.
static Preferences * get()
Access the singleton Preferences object.
Entry const getEntry(Glib::ustring const &pref_path)
Retrieve a preference entry without specifying its type.
int getInt(Glib::ustring const &pref_path, int def=0)
Retrieve an integer.
void setBool(Glib::ustring const &pref_path, bool value)
Set a Boolean value.
void start(SPDesktop *desktop, Geom::Point const &p, bool tolerance=false)
static Rubberband * get(SPDesktop *desktop)
void move(Geom::Point const &p)
Geom::OptRect getRectangle() const
Rubberband::Mode getMode() const
The set of selected SPObjects for a given document and layer model.
sigc::connection connectChanged(sigc::slot< void(Selection *)> slot)
Connects a slot to be notified of selection changes.
Interface for refcounted XML nodes.
virtual void appendChild(Node *child)=0
Append a node as the last child of this node.
void setAttribute(Util::const_char_ptr key, Util::const_char_ptr value)
Change an attribute of this node.
To do: update description of desktop.
double current_zoom() const
SPDocument * getDocument() const
SPNamedView * getNamedView() const
Inkscape::Selection * getSelection() const
bool scroll_to_point(Geom::Point const &s_dt, double autoscrollspeed=0)
Scroll screen so as to keep point 'p' visible in window.
Geom::Affine const & w2d() const
Transformation from window to desktop coordinates (zoom/rotate).
Typed SVG document implementation.
SPDefs * getDefs()
Return the main defs object for the document.
Inkscape::XML::Document * getReprDoc()
Our Inkscape::XML::Document.
SPObject * getObjectByRepr(Inkscape::XML::Node *repr) const
SPMeshNodeArray array
Mesh Gradients.
Base class for visual SVG elements.
Geom::OptRect geometricBounds(Geom::Affine const &transform=Geom::identity()) const
Get item's geometric bounding box in this item's coordinate system.
Geom::OptRect visualBounds(Geom::Affine const &transform=Geom::identity(), bool wfilter=true, bool wclip=true, bool wmask=true) const
Get item's visual bounding box in this item's coordinate system.
unsigned insert(std::vector< unsigned > const &)
Splits selected rows and/or columns in half (according to the path 't' parameter).
unsigned color_smooth(std::vector< unsigned > const &)
Attempts to smooth color transitions across corners.
unsigned side_arc(std::vector< unsigned > const &)
Converts generic Beziers to Beziers approximating elliptical arcs, preserving handle direction.
unsigned side_toggle(std::vector< unsigned > const &)
Toggle sides between lineto and curve to if both corners selected.
void create(SPMeshGradient *mg, SPItem *item, Geom::OptRect bbox)
Create a default mesh.
unsigned tensor_toggle(std::vector< unsigned > const &)
Toggle sides between lineto and curve to if both corners selected.
void write(SPMeshGradient *mg)
Write repr using our array.
unsigned color_pick(std::vector< unsigned > const &, SPItem *)
Pick color from background for selected corners.
void requestModified(unsigned int flags)
Requests that a modification notification signal be emitted later (e.g.
SPStyle * style
Represents the style properties, whether from presentation attributes, the style attribute,...
Inkscape::XML::Node * getRepr()
Returns the XML representation of tree.
SPPaintServer * getFillPaintServer()
T< SPAttr::FILL, SPIPaint > fill
fill
T< SPAttr::STROKE, SPIPaint > stroke
stroke
SPPaintServer * getStrokePaintServer()
Class to coordinate snapping operations.
void setup(SPDesktop const *desktop, bool snapindicator=true, SPObject const *item_to_ignore=nullptr, std::vector< Inkscape::SnapCandidatePoint > *unselected_nodes=nullptr)
Convenience shortcut when there is only one item to ignore.
void freeSnapReturnByRef(Geom::Point &p, Inkscape::SnapSourceType const source_type, Geom::OptRect const &bbox_to_snap=Geom::OptRect()) const
Try to snap a point to grids, guides or objects.
std::shared_ptr< Css const > css
Editable view implementation.
TODO: insert short description here.
SPGradient * getGradient(SPItem *item, Inkscape::PaintTarget fill_or_stroke)
Fetches either the fill or the stroke gradient from the given item.
Macro for icon names used in Inkscape.
Interface for locally managing a current status message.
Raw stack of active status messages.
static R & release(R &r)
Decrements the reference count of a anchored object.
Helper class to stream background task notifications as a series of messages.
bool mod_alt(unsigned modifiers)
void inspect_event(E &&event, Fs... funcs)
Perform pattern-matching on a CanvasEvent.
@ SNAPSOURCE_OTHER_HANDLE
bool mod_ctrl_only(unsigned modifiers)
bool mod_shift_only(unsigned modifiers)
SPCSSAttr * sp_repr_css_attr_new()
Creates an empty SPCSSAttr (a class for manipulating CSS style properties).
void sp_repr_css_attr_unref(SPCSSAttr *css)
Unreferences an SPCSSAttr (will be garbage collected if no references remain).
void sp_repr_css_change_recursive(Node *repr, SPCSSAttr *css, gchar const *attr)
void sp_repr_css_set_property(SPCSSAttr *css, gchar const *name, gchar const *value)
Set a style property to a new value (e.g.
@ MG_CORNER_TENSOR_TOGGLE
TODO: insert short description here.
This class holds together a visible on-canvas knot and a list of draggables that need to be moved whe...
Abstract base class for events.
unsigned modifiers
The modifiers mask immediately before the event.
Movement of the mouse pointer.
Interface for XML documents.
virtual Node * createElement(char const *name)=0
void sp_style_set_property_url(SPObject *item, gchar const *property, SPObject *linked, bool recursive)
SPStyle - a style object for SPItem objects.