21#include <glibmm/i18n.h>
62std::unordered_map<GrPointType, Inkscape::CanvasItemCtrlType>
const gr_knot_types = {
131 auto colors = Colors::ColorSet();
133 SPStop* selected =
nullptr;
135 for(
auto draggable : d->draggables) {
138 selected =
sp_item_gradient_get_stop(draggable->item, draggable->point_type, draggable->point_i, draggable->fill_or_stroke);
144 draggable->item->getId(),
150 if (!colors.isEmpty()) {
151 auto avg = colors.getAverage();
152 auto opacity = avg.stealOpacity();
156 style->
fill.setColor(avg);
157 style->
fill.set = TRUE;
158 style->
fill.setTag(selected);
160 style->
stroke.setColor(avg);
162 style->
stroke.setTag(selected);
168 style->
opacity.set_double(opacity);
177 Glib::ustring colorStr;
181 Glib::ustring::size_type pos = colorStr.find(
"url(#");
182 if ( pos != Glib::ustring::npos ) {
183 Glib::ustring targetName = colorStr.substr(pos + 5, colorStr.length() - 6);
185 for (
auto gradient : gradients) {
186 auto grad = cast<SPGradient>(gradient);
187 if ( targetName == grad->getId() ) {
192 if ( !stopColorStr.empty() ) {
193 colorStr = stopColorStr;
214 if (
css->attribute(
"stroke") && !
css->attribute(
"color") && !
css->attribute(
"fill")) {
224 if (
css->attribute(
"flood-color")) {
228 if (
css->attribute(
"lighting-color")) {
232 if (
css->attribute(
"color")) {
236 if (
css->attribute(
"fill") && strcmp(
css->attribute(
"fill"),
"none")) {
240 if (
css->attribute(
"stop-color")) {
246 bool stopIsNull =
false;
248 if ( !stopIsNull && !tmp.empty() ) {
254 if (
css->attribute(
"stop-opacity")) {
257 gdouble accumulated = 1.0;
267 if ((
css->attribute(
"fill") && !
css->attribute(
"stroke") && !strcmp(
css->attribute(
"fill"),
"none")) ||
268 (
css->attribute(
"stroke") && !
css->attribute(
"fill") && !strcmp(
css->attribute(
"stroke"),
"none"))) {
280 for(
auto draggable : d->draggables) {
286 if (switch_style && gradient &&
287 (is<SPLinearGradient>(gradient) || is<SPRadialGradient>(gradient))) {
304 return Color(0x000000ff);
308 for(
auto draggable : d->draggables) {
310 draggable->item->getId(),
320 gfloat new_stop_offset = 0;
326 int divide_column = -1;
327 double divide_coord = 0.5;
329 bool addknot =
false;
331 for (std::vector<Inkscape::PaintTarget>::const_iterator it = allPaintTargets().begin(); (it != allPaintTargets().end()) && !addknot; ++it)
335 if (is<SPLinearGradient>(gradient)) {
342 if ( dist_screen < tolerance ) {
348 }
else if (is<SPRadialGradient>(gradient)) {
355 if ( dist_screen < tolerance ) {
367 if ( dist_screen < tolerance ) {
375 }
else if (is<SPMeshGradient>(gradient)) {
383 auto mg = cast<SPMeshGradient>(gradient);
386 guint rows = mg->array.patch_rows();
387 guint columns = mg->array.patch_columns();
389 double closest = 1e10;
390 for( guint i = 0; i < rows; ++i ) {
391 for( guint j = 0; j < columns; ++j ) {
398 p[0] = patch.
getPoint( 0, 0 ) * transform;
399 p[1] = patch.
getPoint( 0, 1 ) * transform;
400 p[2] = patch.
getPoint( 0, 2 ) * transform;
401 p[3] = patch.
getPoint( 0, 3 ) * transform;
405 double dist_screen =
Geom::L2 ( mouse_p - nearest );
406 if ( dist_screen < closest ) {
407 closest = dist_screen;
410 divide_coord = coord;
415 if( j == columns - 1 ) {
416 p[0] = patch.
getPoint( 1, 0 ) * transform;
417 p[1] = patch.
getPoint( 1, 1 ) * transform;
418 p[2] = patch.
getPoint( 1, 2 ) * transform;
419 p[3] = patch.
getPoint( 1, 3 ) * transform;
423 double dist_screen =
Geom::L2 ( mouse_p - nearest );
424 if ( dist_screen < closest ) {
425 closest = dist_screen;
428 divide_coord = coord;
433 if( i == rows - 1 ) {
434 p[0] = patch.
getPoint( 2, 0 ) * transform;
435 p[1] = patch.
getPoint( 2, 1 ) * transform;
436 p[2] = patch.
getPoint( 2, 2 ) * transform;
437 p[3] = patch.
getPoint( 2, 3 ) * transform;
441 double dist_screen =
Geom::L2 ( mouse_p - nearest );
442 if ( dist_screen < closest ) {
443 closest = dist_screen;
446 divide_coord = 1.0 - coord;
452 p[0] = patch.
getPoint( 3, 0 ) * transform;
453 p[1] = patch.
getPoint( 3, 1 ) * transform;
454 p[2] = patch.
getPoint( 3, 2 ) * transform;
455 p[3] = patch.
getPoint( 3, 3 ) * transform;
459 double dist_screen =
Geom::L2 ( mouse_p - nearest );
460 if ( dist_screen < closest ) {
461 closest = dist_screen;
464 divide_coord = 1.0 - coord;
471 if( closest < tolerance ) {
481 if( is<SPLinearGradient>(gradient) || is<SPRadialGradient>( gradient ) ) {
486 while ( (next_stop) && (next_stop->
offset < new_stop_offset) ) {
487 prev_stop = next_stop;
504 }
else if (!next_stop) {
523 auto mg = cast<SPMeshGradient>(gradient);
525 if( divide_row > -1 ) {
526 mg->array.split_row( divide_row, divide_coord );
528 mg->array.split_column( divide_column, divide_coord );
532 mg->array.write( mg );
533 mg->array.built =
false;
536 DocumentUndo::done(
desktop->
getDocument(), _(
"Added patch row or column"), INKSCAPE_ICON(
"mesh-gradient"));
552 draggable->fill_or_stroke, stop);
572 auto const center =
draggers[0]->point;
576 if (dist_point < outer_radius) {
581 for (
int i = 1; i <
draggers.size() - 1; ++i) {
583 double const inner_radius = outer_radius;
591 if (dist_point >= inner_radius && dist_point < outer_radius) {
596 if (dist_point >= outer_radius) {
609 bool stopIsNull =
false;
611 const char *color = stopIsNull ? nullptr : toUse.c_str();
620 if (dist < minDistance) {
630 bool const onDraggerStop = minDistance <= tolerance;
633 if (!
selected.empty() && !onDraggerStop) {
634 for (
auto selected_dragger :
selected) {
642 if (!onDraggerStop && it.curve->is_line() && it.item && it.curve->contains(
desktop->
d2w(p), 5)) {
655 auto const draggable = dragger->
draggables[0];
656 if (is<SPLinearGradient>(
getGradient(draggable->item, draggable->fill_or_stroke))) {
666 keep_selection(false),
672 selection(
desktop->getSelection()),
673 sel_changed_connection(),
674 sel_modified_connection(),
675 style_set_connection(),
676 style_query_connection()
731 for (
auto dragger : this->
draggers) {
744 fill_or_stroke(fill_or_stroke)
777 if (!draggable)
return;
781 if (dragger_corner) {
792 if (state & GDK_SHIFT_MASK) {
799 std::vector<GrDraggable *>::const_iterator i = dragger->
draggables.begin();
800 for ( ++i ; i != dragger->
draggables.end(); ++i ) {
813 }
else if (!(state & GDK_CONTROL_MASK)) {
848 if (!((state & GDK_SHIFT_MASK) || (state & GDK_CONTROL_MASK))) {
856 }
else if (state & GDK_CONTROL_MASK) {
860 unsigned snaps = abs(prefs->
getInt(
"/options/rotationsnapsperpi/value", 12));
863 for (std::vector<GrDraggable *>::const_iterator i = dragger->
draggables.begin(); i != dragger->
draggables.end(); ++i) {
871 if (d_new == dragger)
873 if (d_new->
isA (draggable->
item,
877 if (state & GDK_SHIFT_MASK) {
883 dr_snap = d_new->
point;
890 if (d_new == dragger)
892 if (d_new->
isA (draggable->
item,
896 dr_snap = d_new->
point;
912 if (state & GDK_ALT_MASK) {
914 sp = m.constrainedAngularSnap(scp, dragger->
point_original, dr_snap, 2);
917 sp = m.constrainedAngularSnap(scp, std::optional<Geom::Point>(), dr_snap, snaps);
930 for (std::list<Inkscape::SnappedPoint>::const_iterator i = isr.
points.begin(); i != isr.
points.end(); ++i) {
944 bool scale_radial = (state & GDK_CONTROL_MASK) && (state & GDK_SHIFT_MASK);
968 moving.push_back(dragger);
970 guint lowest_i = draggable->
point_i;
971 guint highest_i = draggable->
point_i;
980 lowest_i = lowest_i - 1;
981 moving.insert(moving.begin(),d_add);
982 lowest_dragger = d_add;
992 highest_i = highest_i + 1;
993 moving.push_back(d_add);
994 highest_dragger = d_add;
1001 if ( is<SPLinearGradient>(server) ) {
1002 guint
num = cast<SPLinearGradient>(server)->vector.stops.size();
1004 if (lowest_i == 1) {
1010 *begin = d_temp->
point;
1013 if (d_temp ==
nullptr) {
1018 }
else if ( is<SPRadialGradient>(server) ) {
1019 guint
num = cast<SPRadialGradient>(server)->vector.stops.size();
1021 if (lowest_i == 1) {
1027 *begin = d_temp->
point;
1030 if (d_temp ==
nullptr) {
1037 *low_lim = dragger->
point - (lowest_dragger->
point - *begin);
1038 *high_lim = dragger->
point - (highest_dragger->
point - *
end);
1052 double snap_fraction = 0.1;
1060 std::vector<GrDragger *> moving;
1063 if (state & GDK_CONTROL_MASK) {
1069 if (!(state & GDK_SHIFT_MASK)) {
1080 for (
auto drg : moving) {
1081 SPKnot *drgknot = drg->knot;
1083 if (state & GDK_ALT_MASK) {
1088 this_move = (0.5 * cos (M_PI * (pow(x, alpha))) + 0.5) * this_move;
1091 this_move = (0.5 * cos (M_PI * (pow(x, alpha))) + 0.5) * this_move;
1094 drg->point += this_move;
1095 drgknot->
moveto(drg->point);
1096 drg->fireDraggables (
false);
1097 drg->updateDependencies(
false);
1112 d->highlightCorner(
false);
1117 if (dragger_corner) {
1131 if ((state & GDK_CONTROL_MASK) && (state & GDK_SHIFT_MASK)) {
1141 (*it)->fireDraggables (
true);
1164 if (!draggable)
return;
1166 if ( (state & GDK_CONTROL_MASK) && (state & GDK_ALT_MASK ) ) {
1218 if ( state & GDK_SHIFT_MASK ) {
1238 auto drag = dragger->
parent;
1240 auto gradient =
getGradient(draggable->item, draggable->fill_or_stroke);
1244 if (vector->getStopCount() == 1) {
1245 auto first_stop = vector->getFirstStop();
1246 bool is_offset_zero = first_stop->offset < 1e-4;
1247 bool is_first_dragger = dragger == drag->draggers[0];
1250 if ((is_offset_zero && is_first_dragger) || (!is_offset_zero && !is_first_dragger)) {
1255 gradient->ensureVector();
1256 drag->updateDraggers();
1257 drag->local_change =
true;
1258 drag->selectByStop(newstop);
1259 DocumentUndo::done(gradient->document, _(
"Add gradient stop"), INKSCAPE_ICON(
"color-gradient"));
1275 if (merging_focus ||
1278 sp_item_gradient_set_coords (draggable->item, draggable->point_type, draggable->point_i, this->point, draggable->fill_or_stroke, write_repr, scale_radial);
1308 if ( (draggable->point_type ==
point_type) && (draggable->point_i == point_i) && (draggable->item ==
item) && (draggable->fill_or_stroke == fill_or_stroke) ) {
1321 if ( (draggable->point_type ==
point_type) && (draggable->item ==
item) && (draggable->fill_or_stroke == fill_or_stroke) ) {
1354 if (!da1->mayMerge(da2))
1364 if (!da1->mayMerge(da2))
1401 std::map<SPGradient*, std::vector<guint> > selected_corners;
1404 const bool scale =
false;
1407 for( std::set<GrDragger *>::const_iterator it = drag->
selected.begin(); it != drag->
selected.end(); ++it ) {
1409 for (std::vector<GrDraggable *>::const_iterator it2 = dragger->
draggables.begin(); it2 != dragger->
draggables.end(); ++it2 ) {
1417 if ( !is<SPMeshGradient>( gradient ) )
continue;
1419 selected_corners[ gradient ].push_back( draggable->
point_i );
1428 std::map<SPGradient*, std::vector<guint> > dragger_corners;
1432 gint point_i = draggable->point_i;
1434 fill_or_stroke = draggable->fill_or_stroke;
1441 if ( !is<SPMeshGradient>( gradient ) )
continue;
1442 auto mg = cast<SPMeshGradient>( gradient );
1450 mg->array.update_handles( point_i, selected_corners[ gradient ], pcg_old, op );
1451 mg->array.write( mg );
1454 for( guint i = 0; i < mg->array.handles.size(); ++i ) {
1462 for( guint i = 0; i < mg->array.tensors.size(); ++i ) {
1480 g_return_if_fail(this->
knot !=
nullptr);
1482 char *tip =
nullptr;
1491 tip = g_strdup_printf (_(
"%s %d for: %s%s; drag with <b>Ctrl</b> to snap offset; click with <b>Ctrl+Alt</b> to delete stop"),
1501 tip = g_strdup_printf (_(
"%s for: %s%s"),
1508 tip = g_strdup_printf (_(
"%s for: %s%s; drag with <b>Ctrl</b> to snap angle, with <b>Ctrl+Alt</b> to preserve angle, with <b>Ctrl+Shift</b> to scale around center"),
1516 tip = g_strdup_printf (
"%s", _(
"Radial gradient <b>center</b> and <b>focus</b>; drag with <b>Shift</b> to separate focus"));
1519 tip = g_strdup_printf (ngettext(
"Gradient point shared by <b>%d</b> gradient; drag with <b>Shift</b> to separate",
1520 "Gradient point shared by <b>%d</b> gradients; drag with <b>Shift</b> to separate",
1568 if ( (da->item ==
item) &&
1570 (point_i == -1 || da->point_i == point_i) &&
1571 (da->fill_or_stroke == fill_or_stroke) ) {
1589 guint
num = cast<SPGradient>(server)->vector.stops.size();
1590 if (
num <= 2)
return;
1592 if ( is<SPLinearGradient>(server) ) {
1593 for ( guint i = 1; i <
num - 1; i++ ) {
1596 }
else if ( is<SPRadialGradient>(server) ) {
1597 for ( guint i = 1; i <
num - 1; i++ ) {
1611 switch (draggable->point_type) {
1742 for (
auto dragger : this->
draggers) {
1743 for (std::vector<GrDraggable *>::const_iterator j = dragger->draggables.begin(); j != dragger->draggables.end(); ++j ) {
1757 for (
auto dragger : this->
draggers) {
1758 for (std::vector<GrDraggable *>::const_iterator j = dragger->draggables.begin(); j != dragger->draggables.end(); ++j ) {
1762 (point_i == -1 || da2->
point_i == point_i) &&
1775 if (d && d !=
this) {
1794 auto mg = cast<SPMeshGradient>(gradient);
1796 std::vector< std::vector< SPMeshNode* > > nodes = mg->array.nodes;
1797 for (guint i = 0; i < nodes.size(); ++i) {
1798 for (guint j = 0; j < nodes[i].size(); ++j) {
1800 if (draggable->
point_i == (gint)nodes[i][j]->draggable) {
1802 if (nodes.size() > i+1 && nodes[i+1].size() > j && nodes[i+1][j]->node_type ==
MG_NODE_TYPE_CORNER) {
1806 if (j != 0 && nodes.size() > i && nodes[i].size() > j-1 && nodes[i][j-1]->node_type ==
MG_NODE_TYPE_CORNER) {
1810 if (i != 0 && nodes.size() > i-1 && nodes[i-1].size() > j && nodes[i-1][j]->node_type ==
MG_NODE_TYPE_CORNER) {
1814 if (nodes.size() > i && nodes[i].size() > j+1 && nodes[i][j+1]->node_type ==
MG_NODE_TYPE_CORNER) {
1838 if (d &&
node->draggable < G_MAXUINT) {
1846 double angl = ray.
angle();
1875 if (is<SPMeshGradient>( gradient )) {
1877 gint corner = draggable->
point_i;
1878 auto mg = cast<SPMeshGradient>( gradient );
1880 std::vector< std::vector< SPMeshNode* > > nodes = mg_arr.
nodes;
1885 guint ncorners = mcol + 1;
1887 guint crow = corner / ncorners;
1888 guint ccol = corner % ncorners;
1890 guint nrow = crow * 3;
1891 guint ncol = ccol * 3;
1894 patch[0] = patch[1] = patch[2] = patch[3] =
false;
1895 if (ccol > 0 && crow > 0 ) patch[0] =
true;
1896 if (ccol < mcol && crow > 0 ) patch[1] =
true;
1897 if (ccol < mcol && crow < mrow ) patch[2] =
true;
1898 if (ccol > 0 && crow < mrow ) patch[3] =
true;
1899 if (patch[0] || patch[1]) {
1900 highlightNode(nodes[nrow - 1][ncol], highlight, corner_point, 0);
1902 if (patch[1] || patch[2]) {
1903 highlightNode(nodes[nrow][ncol + 1], highlight, corner_point, 1);
1905 if (patch[2] || patch[3]) {
1906 highlightNode(nodes[nrow + 1][ncol], highlight, corner_point, 2);
1908 if (patch[3] || patch[0]) {
1909 highlightNode(nodes[nrow][ncol - 1], highlight, corner_point, 3);
1981 for (
auto coord : coords) {
1982 if (
Geom::L2 (d->point - coord) < 1e-4) {
1994 for (
auto dragger : this->
draggers) {
1996 for (std::vector<GrDraggable *>::const_iterator j = dragger->draggables.begin(); j != dragger->draggables.end(); ++j) {
2003 if (stop_i == stop) {
2035 if (add_to_selection) {
2036 if (!dragger)
return;
2040 seldragger = dragger;
2051 seldragger = dragger;
2059 seldragger = dragger;
2088 curve->set_name(
"GradientLine");
2089 curve->set_stroke(canvas_item_color);
2092 item_curve.item =
item;
2093 item_curve.curve = std::move(
curve);
2106 bool highlight =
false;
2121 curve->set_name(
"GradientCurve");
2122 curve->set_stroke(canvas_item_color);
2125 item_curve.item =
item;
2126 item_curve.curve = std::move(
curve);
2128 item_curve.corner0 = corner0;
2129 item_curve.corner1 = corner1;
2141 for (
auto dragger : this->
draggers) {
2142 if (dragger->mayMerge (draggable) &&
Geom::L2 (dragger->point - p) < MERGE_DIST) {
2144 dragger->addDraggable (draggable);
2145 dragger->updateKnotShape();
2152 this->
draggers.push_back(new_dragger);
2165 for ( guint i = 1; i <
num - 1; i++ ) {
2171 for ( guint i = 1; i <
num - 1; i++ ) {
2188 for ( guint i = 1; i <
num - 1; i++ ) {
2201 std::vector< std::vector< SPMeshNode* > > nodes = mg->
array.
nodes;
2206 bool show_handles = (prefs->
getBool(
"/tools/mesh/show_handles",
true));
2207 bool edit_fill = (prefs->
getBool(
"/tools/mesh/edit_fill",
true));
2208 bool edit_stroke = (prefs->
getBool(
"/tools/mesh/edit_stroke",
true));
2213 std::cerr <<
"Empty Mesh, No Draggers to Add" << std::endl;
2226 for(
auto &
node : nodes) {
2227 for(
auto & j :
node) {
2230 switch ( j->node_type ) {
2236 j->draggable = icorner;
2246 if( !show_handles || !j->set ) {
2249 j->draggable = ihandle;
2258 if( !show_handles || !j->set ) {
2261 j->draggable = itensor;
2267 std::cerr <<
"Bad Mesh draggable type" << std::endl;
2281 std::vector< std::vector< SPMeshNode* > > nodes = mg->
array.
nodes;
2284 bool show_handles = (prefs->
getBool(
"/tools/mesh/show_handles",
true));
2289 std::cerr <<
"GrDrag::refreshDraggersMesh: Empty Mesh, No Draggers to refresh!" << std::endl;
2296 for(
auto &
node : nodes) {
2297 for(
auto & j :
node) {
2301 switch ( j->node_type ) {
2313 if( !show_handles || !j->set ) {
2332 if( !show_handles || !j->set ) {
2346 std::cerr <<
"Bad Mesh draggable type" << std::endl;
2384 for (
auto dragger : this->
draggers) {
2389 g_return_if_fail(this->
selection !=
nullptr);
2391 for (
auto i = list.begin(); i != list.end(); ++i) {
2395 if (style && (style->
fill.isPaintserver())) {
2397 if (
auto gradient = cast<SPGradient>(server)) {
2398 if (gradient->isSolid() || (gradient->getVector() && gradient->getVector()->isSolid())) {
2400 }
else if (is<SPLinearGradient>(server)) {
2402 }
else if (is<SPRadialGradient>(server)) {
2404 }
else if (is<SPMeshGradient>(server)) {
2410 if (style && (style->
stroke.isPaintserver())) {
2412 if (
auto gradient = cast<SPGradient>(server)) {
2413 if (gradient->isSolid() || (gradient->getVector() && gradient->getVector()->isSolid())) {
2415 }
else if (is<SPLinearGradient>(server)) {
2417 }
else if (is<SPRadialGradient>(server)) {
2419 }
else if (is<SPMeshGradient>(server)) {
2436 g_return_if_fail(this->
selection !=
nullptr);
2438 for (
auto i = list.begin(); i != list.end(); ++i) {
2442 if (style && (style->
fill.isPaintserver())) {
2444 if ( server && is<SPGradient>( server ) ) {
2445 if ( is<SPMeshGradient>(server) ) {
2451 if (style && (style->
stroke.isPaintserver())) {
2453 if ( server && is<SPGradient>( server ) ) {
2454 if ( is<SPMeshGradient>(server) ) {
2468 static bool mouse_out =
false;
2477 if(mouse_out ==
true){
2492 g_return_if_fail(this->
selection !=
nullptr);
2495 for (
auto i = list.begin(); i != list.end(); ++i) {
2500 if (style && (style->
fill.isPaintserver())) {
2502 if (
auto gradient = cast<SPGradient>(server)) {
2503 if (gradient->isSolid() || (gradient->getVector() && gradient->getVector()->isSolid())) {
2505 }
else if (is<SPLinearGradient>(server)) {
2507 }
else if (is<SPRadialGradient>(server)) {
2511 }
else if (is<SPMeshGradient>(server)) {
2513 bool edit_fill = (prefs->
getBool(
"/tools/mesh/edit_fill",
true));
2515 auto mg = cast<SPMeshGradient>(server);
2518 guint rows = mg->array.patch_rows();
2519 guint columns = mg->array.patch_columns();
2520 for ( guint i = 0; i < rows; ++i ) {
2521 for ( guint j = 0; j < columns; ++j ) {
2523 std::vector<Geom::Point> h;
2528 int corner0 = i * (columns + 1) + j;
2529 int corner1 = corner0 + 1;
2530 int corner2 = corner1 + columns + 1;
2531 int corner3 = corner2 - 1;
2533 int handle0 = 2*j + i*(2+4*columns);
2534 int handle1 = handle0 + 1;
2535 int handle2 = j + i*(2+4*columns) + 2*columns + 1;
2536 int handle3 = j + i*(2+4*columns) + 3*columns + 2;
2537 int handle4 = handle1 + (2+4*columns);
2538 int handle5 = handle0 + (2+4*columns);
2539 int handle6 = handle3 - 1;
2540 int handle7 = handle2 - 1;
2544 for( guint p = 0; p < 4; ++p ) {
2550 if( j == columns - 1 ) {
2552 for( guint p = 0; p < 4; ++p ) {
2559 if( i == rows - 1 ) {
2561 for( guint p = 0; p < 4; ++p ) {
2569 for( guint p = 0; p < 4; ++p ) {
2580 if (style && (style->
stroke.isPaintserver())) {
2582 if (
auto gradient = cast<SPGradient>(server)) {
2583 if (gradient->isSolid() || (gradient->getVector() && gradient->getVector()->isSolid())) {
2585 }
else if (is<SPLinearGradient>(server)) {
2587 }
else if (is<SPRadialGradient>(server)) {
2591 }
else if (is<SPMeshGradient>(server)) {
2593 bool edit_stroke = (prefs->
getBool(
"/tools/mesh/edit_stroke",
true));
2598 auto mg = cast<SPMeshGradient>(server);
2600 guint rows = mg->array.patch_rows();
2601 guint columns = mg->array.patch_columns();
2602 for ( guint i = 0; i < rows; ++i ) {
2603 for ( guint j = 0; j < columns; ++j ) {
2605 std::vector<Geom::Point> h;
2610 int corner0 = i * (columns + 1) + j;
2611 int corner1 = corner0 + 1;
2612 int corner2 = corner1 + columns + 1;
2613 int corner3 = corner2 - 1;
2615 int handle0 = 2*j + i*(2+4*columns);
2616 int handle1 = handle0 + 1;
2617 int handle2 = j + i*(2+4*columns) + 2*columns + 1;
2618 int handle3 = j + i*(2+4*columns) + 3*columns + 2;
2619 int handle4 = handle1 + (2+4*columns);
2620 int handle5 = handle0 + (2+4*columns);
2621 int handle6 = handle3 - 1;
2622 int handle7 = handle2 - 1;
2626 for( guint p = 0; p < 4; ++p ) {
2632 if( j == columns - 1 ) {
2634 for( guint p = 0; p < 4; ++p ) {
2641 if( i == rows - 1 ) {
2643 for( guint p = 0; p < 4; ++p ) {
2651 for( guint p = 0; p < 4; ++p ) {
2673 g_return_if_fail (this->
selection !=
nullptr);
2676 for (
auto i = list.begin(); i != list.end(); ++i) {
2696 for(
auto draggable : (*(
selected.begin()))->draggables) {
2716 bool const rotated = prefs->getBool(
"/options/moverotated/value",
true);
2730 bool skip_radius_with_center =
false;
2732 if (d_new->isA (( d->draggables[0])->item,
2735 (d->draggables[0])->fill_or_stroke)) {
2737 skip_radius_with_center =
true;
2740 if (skip_radius_with_center)
2747 d->point_original = d->point;
2748 d->knot->moveto(d->point);
2750 d->fireDraggables (write_repr, scale_radial);
2752 d->updateDependencies(write_repr);
2756 if (write_repr && did) {
2758 DocumentUndo::maybeDone(
desktop->
getDocument(),
"grmoveh", _(
"Move gradient handle(s)"), INKSCAPE_ICON(
"color-gradient"));
2772 std::vector<GrDragger *> moving;
2779 for(
auto drg : moving) {
2780 SPKnot *drgknot = drg->knot;
2781 drg->point += displacement;
2782 drgknot->
moveto(drg->point);
2783 drg->fireDraggables (
true);
2784 drg->updateDependencies(
true);
2788 if (write_repr && did) {
2790 DocumentUndo::maybeDone(
desktop->
getDocument(),
"grmovem", _(
"Move gradient mid stop(s)"), INKSCAPE_ICON(
"color-gradient"));
2798 gdouble zx = x / zoom;
2799 gdouble zy = y / zoom;
2811 if (mod_ctrl(event)) {
2821 case GDK_KEY_KP_Left:
2833 case GDK_KEY_KP_Right:
2839 case GDK_KEY_KP_Down:
2852 if (mod_shift(event)) {
2856 if (mod_alt(event)) {
2860 auto nudge = prefs->getDoubleLimited(
"/options/nudgedistance/value", 2, 0, 1000,
"px");
2911 struct StructStopInfo {
2918 std::vector<SPStop *> midstoplist;
2919 std::vector<StructStopInfo *> endstoplist;
2927 switch (draggable->point_type) {
2934 bool present =
false;
2935 for (
auto i:midstoplist) {
2942 midstoplist.push_back(stop);
2958 StructStopInfo *stopinfo =
new StructStopInfo;
2959 stopinfo->spstop = stop;
2960 stopinfo->draggable = draggable;
2961 stopinfo->gradient = gradient;
2962 stopinfo->vector = vector;
2964 bool present =
false;
2965 for (
auto i : endstoplist) {
2966 if ( i->spstop == stopinfo->spstop ) {
2972 endstoplist.push_back(stopinfo);
2984 if ( just_one )
break;
2986 for (
auto stop:midstoplist) {
2987 document = stop->document;
2992 for (
auto stopinfo:endstoplist) {
2993 document = stopinfo->spstop->document;
2999 for (
auto&
child: stopinfo->vector->children)
3001 if ( is<SPStop>(&
child) ) {
3007 switch (stopinfo->draggable->point_type) {
3010 stopinfo->vector->getRepr()->removeChild(stopinfo->spstop->getRepr());
3012 auto lg = cast<SPLinearGradient>(stopinfo->gradient);
3015 SPStop *stop = stopinfo->vector->getFirstStop();
3018 lg->x1.computed = newbegin[
Geom::X];
3019 lg->y1.computed = newbegin[
Geom::Y];
3030 while ( stop != laststop ) {
3041 auto lg = cast<SPLinearGradient>(stopinfo->gradient);
3047 lg->x2.computed = newend[
Geom::X];
3048 lg->y2.computed = newend[
Geom::Y];
3057 SPStop *stop = stopinfo->vector->getFirstStop();
3059 while ( stop != laststop ) {
3073 stopinfo->vector->getRepr()->removeChild(stopinfo->spstop->getRepr());
3079 stopinfo->vector->getRepr()->removeChild(stopinfo->spstop->getRepr());
3081 auto rg = cast<SPRadialGradient>(stopinfo->gradient);
3082 double oldradius = rg->r.computed;
3085 double newradius =
offset * oldradius;
3086 rg->r.computed = newradius;
3094 SPStop *stop = stopinfo->vector->getFirstStop();
3096 while ( stop != laststop ) {
3113 if (unselectedrepr == stopinfo->spstop->getRepr() ) {
3114 unselectedrepr = unselectedrepr->
next();
3117 if (unselectedrepr ==
nullptr) {
3143 DocumentUndo::done( document, _(
"Delete gradient stop(s)"), INKSCAPE_ICON(
"color-gradient"));
double distance(Shape const *s, Geom::Point const &p)
3x3 matrix representing an affine transformation.
Coord nearestTime(Point const &p, Coord from=0, Coord to=1) const override
Compute a time value at which the curve comes closest to a specified point.
Point pointAt(Coord t) const override
Evaluate the curve at a specified time value.
bool contains(GenericRect< C > const &r) const
Check whether the rectangle includes all points in the given rectangle.
Axis-aligned rectangle that can be empty.
Two-dimensional point that doubles as a vector.
bool isFinite() const
Check whether both coordinates are finite.
Straight ray from a specific point to infinity.
void setPoints(Point const &a, Point const &b)
Axis aligned, non-empty rectangle.
This is the root class of the gradient dragging machinery.
GrDragger * addDragger(GrDraggable *draggable)
If there already exists a dragger within MERGE_DIST of p, add the draggable to it; otherwise create n...
void updateDraggers()
Regenerates the draggers list from the current selection; is called when selection is changed or modi...
void deselect_all()
Deselect all stops/draggers (private).
GrDrag(SPDesktop *desktop)
void refreshDraggers()
Refresh draggers, moving and toggling visibility as necessary.
GrDragger * select_prev()
Select the knot previous from the last selected one and deselect all other selected.
void updateLines()
Regenerates the lines list from the current selection; is called on each move of a dragger,...
Inkscape::Colors::Color getColor()
void deselectAll()
Deselect all stops/draggers (public; emits signal).
void addColorToDragger(GrDragger &dragger, const char *color)
void selectByStop(SPStop *stop, bool add_to_selection=true, bool override=true)
Select draggers by stop.
std::vector< double > vert_levels
void addLine(SPItem *item, Geom::Point p1, Geom::Point p2, Inkscape::PaintTarget fill_or_stroke)
Create a line from p1 to p2 and add it to the curves list.
void setDeselected(GrDragger *dragger)
Deselect a dragger.
bool dropColor(SPItem *item, gchar const *c, Geom::Point p)
void addDraggersRadial(SPRadialGradient *rg, SPItem *item, Inkscape::PaintTarget fill_or_stroke)
Add draggers for the radial gradient rg on item.
void addCurve(SPItem *item, Geom::Point p0, Geom::Point p1, Geom::Point p2, Geom::Point p3, int corner0, int corner1, int handle0, int handle1, Inkscape::PaintTarget fill_or_stroke)
Create a curve from p0 to p3 and add it to the curves list.
GrDragger * select_next()
Select the knot next to the last selected one and deselect all other selected.
bool styleSet(const SPCSSAttr *css, bool switch_style)
SPStop * addStopNearPoint(SPItem *item, Geom::Point mouse_p, double tolerance)
void selected_move_nowrite(double x, double y, bool scale_radial)
void grabKnot(GrDragger *dragger, gint x, gint y, guint32 etime)
Artificially grab the knot of this dragger; used by the gradient context.
bool key_press_handler(Inkscape::KeyPressEvent const &event)
Handle arrow key events.
bool mouseOver()
Returns true if at least one of the draggers' knots has the mouse hovering above it.
void addDraggersMesh(SPMeshGradient *mg, SPItem *item, Inkscape::PaintTarget fill_or_stroke)
Add draggers for the mesh gradient mg on item.
Inkscape::Selection * selection
void selectByCoords(std::vector< Geom::Point > coords)
Select all stops/draggers that match the coords.
Glib::ustring makeStopSafeColor(gchar const *str, bool &isNull)
sigc::connection style_query_connection
void selected_move_screen(double x, double y)
std::set< GrDragger * > selected
void dropColorOnCorrespondingRegion(const char *color, Geom::Point p)
std::vector< double > hor_levels
std::vector< ItemCurve > item_curves
void refreshDraggersMesh(SPMeshGradient *mg, SPItem *item, Inkscape::PaintTarget fill_or_stroke)
Refresh draggers, moving and toggling visibility as necessary.
sigc::connection sel_changed_connection
void deleteSelected(bool just_one=false)
void selected_reverse_vector()
sigc::connection style_set_connection
void updateLevels()
Regenerates the levels list from the current selection.
void selectAll()
Select all stops/draggers.
void selected_move(double x, double y, bool write_repr=true, bool scale_radial=false)
void setSelected(GrDragger *dragger, bool add_to_selection=false, bool override=true)
Select a dragger.
void selectRect(Geom::Rect const &r)
Select all stops/draggers that fall within the rect.
sigc::connection sel_modified_connection
std::vector< GrDragger * > draggers
GrDragger * getDraggerFor(GrDraggable *d)
Select the dragger which has the given draggable.
void addDraggersLinear(SPLinearGradient *lg, SPItem *item, Inkscape::PaintTarget fill_or_stroke)
Add draggers for the linear gradient lg on item.
A thin wrapper around std::ostringstream, but writing floating point numbers in the format required b...
bool set(Color const &color)
Remove any other colors and set to just this one color.
double getAverage(Space::Component const &c) const
Get the average value for this component across all colors.
std::string toString(bool opacity=true) const
Format the color as a css string and return it.
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.
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.
int getInt(Glib::ustring const &pref_path, int def=0)
Retrieve an integer.
The set of selected SPObjects for a given document and layer model.
sigc::connection connectModifiedFirst(sigc::slot< void(Selection *, unsigned)> slot)
Similar to connectModified, but will be run first.
sigc::connection connectChangedFirst(sigc::slot< void(Selection *)> slot)
Similar to connectChanged, but will be run first.
Class to store data for points which are snap candidates, either as a source or as a target.
double getObjectTolerance() const
Class describing the result of an attempt to snap.
void setPoint(Geom::Point const &p)
Geom::Point getPoint() const
void setTarget(SnapTargetType const target)
Interface for refcounted XML nodes.
virtual Node * parent()=0
Get the parent of this node.
virtual Node * next()=0
Get the next sibling of this node.
virtual const AttributeVector & attributeList() const =0
Get a list of the node's attributes.
virtual Node * firstChild()=0
Get the first child of this node.
bool setAttributeCssDouble(Util::const_char_ptr key, double val)
Set a property attribute to val [slightly rounded], in the format required for CSS properties: in par...
virtual char const * attribute(char const *key) const =0
Get the string representation of a node's attribute.
virtual void removeChild(Node *child)=0
Remove a child of this node.
bool setAttributeSvgDouble(Util::const_char_ptr key, double val)
For attributes where an exponent is allowed.
To do: update description of desktop.
double current_zoom() const
Inkscape::CanvasItemGroup * getCanvasControls() const
SPDocument * getDocument() const
sigc::connection connectQueryStyle(F &&slot)
Geom::Affine const & d2w() const
Transformation from desktop to window coordinates.
SPNamedView * getNamedView() const
GrPointType gr_point_type
Inkscape::PaintTarget gr_fill_or_stroke
Geom::Rotate const & current_rotation() const
Inkscape::UI::Tools::ToolBase * getTool() const
sigc::connection connectSetStyle(F &&slot)
void emit_gradient_stop_selected(SPStop *stop)
bool is_yaxisdown() const
Typed SVG document implementation.
std::vector< SPObject * > const getResourceList(char const *key)
void ensureArray()
Forces array (mesh) to be built, if not present (i.e.
SPGradientVector vector
Linear and Radial Gradients.
Geom::Affine gradientTransform
gradientTransform attribute
SPGradient * getVector(bool force_private=false)
Returns private vector of given gradient (the gradient at the end of the href chain which has stops),...
SPMeshNodeArray array
Mesh Gradients.
void ensureVector()
Forces vector to be built, if not present (i.e.
Base class for visual SVG elements.
Geom::Affine i2dt_affine() const
Returns the transformation from item to desktop coords.
Geom::OptRect desktopVisualBounds() const
Get item's visual bbox in desktop coordinate system.
char * detailedDescription() const
Returns a string suitable for status bar, formatted in pango markup language.
Desktop-bound visual control object.
sigc::signal< void(SPKnot *, unsigned int)> ungrabbed_signal
sigc::signal< void(SPKnot *, Geom::Point const &, unsigned int)> moved_signal
sigc::signal< void(SPKnot *, unsigned int)> click_signal
void setPosition(Geom::Point const &p, unsigned int state)
Move knot to new position and emits "moved" signal.
Geom::Point pos
Our desktop coordinates.
sigc::signal< void(SPKnot *, unsigned int)> mousedown_signal
sigc::signal< void(SPKnot *, unsigned int)> doubleclicked_signal
CanvasItemPtr< Inkscape::CanvasItemCtrl > ctrl
Our CanvasItemCtrl.
static void unref(SPKnot *knot)
void hide()
Hide knot on its canvas.
void show()
Show knot on its canvas.
void setTip(Glib::ustring &&tip)
void updateCtrl()
Update knot's control state.
SPDesktop * desktop
Desktop we are on.
void moveto(Geom::Point const &p)
Move knot to new position, without emitting a MOVED signal.
void selectKnot(bool select)
Select knot.
void startDragging(Geom::Point const &p, Geom::IntPoint const &xy, uint32_t etime)
Update knot for dragging and tell canvas an item was grabbed.
std::vector< std::vector< SPMeshNode * > > nodes
unsigned patch_columns()
Number of patch columns.
unsigned patch_rows()
Number of patch rows.
std::vector< Geom::Point > getPointsForSide(unsigned i)
Returns vector of points for a side in proper order for a patch (clockwise order).
Geom::Point getPoint(unsigned side, unsigned point)
Returns point for side in proper order for patch.
SPObject is an abstract base class of all of the document nodes at the SVG document level.
SPStyle * style
Represents the style properties, whether from presentation attributes, the style attribute,...
Inkscape::XML::Node * getRepr()
Returns the XML representation of tree.
SPStop * getNextStop()
Virtual write: write object attributes to repr.
Inkscape::Colors::Color getColor() const
SPPaintServer * getFillPaintServer()
T< SPAttr::FILL, SPIPaint > fill
fill
T< SPAttr::STROKE, SPIPaint > stroke
stroke
SPPaintServer * getStrokePaintServer()
T< SPAttr::FILL_OPACITY, SPIScale24 > fill_opacity
fill-opacity
T< SPAttr::STROKE_OPACITY, SPIScale24 > stroke_opacity
stroke-opacity
T< SPAttr::OPACITY, SPIScale24 > opacity
opacity
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.
Inkscape::SnapPreferences & snapprefs
A set of colors which can be modified together used for color pickers.
TODO: insert short description here.
std::shared_ptr< Css const > css
@ QUERY_STYLE_PROPERTY_FILL
@ QUERY_STYLE_PROPERTY_MASTEROPACITY
@ QUERY_STYLE_MULTIPLE_AVERAGED
Editable view implementation.
static char const *const parent
TODO: insert short description here.
SPStop * sp_get_stop_i(SPGradient *gradient, guint stop_i)
Color sp_item_gradient_stop_query_style(SPItem *item, GrPointType point_type, guint point_i, Inkscape::PaintTarget fill_or_stroke)
Geom::Point getGradientCoords(SPItem *item, GrPointType point_type, guint point_i, Inkscape::PaintTarget fill_or_stroke)
Returns the position of point point_type of the gradient applied to item (either fill_or_stroke),...
void sp_item_gradient_stop_set_style(SPItem *item, GrPointType point_type, guint point_i, Inkscape::PaintTarget fill_or_stroke, SPCSSAttr *stop)
SPStop * sp_item_gradient_get_stop(SPItem *item, GrPointType point_type, guint point_i, Inkscape::PaintTarget fill_or_stroke)
SPStop * sp_last_stop(SPGradient *gradient)
SPStop * sp_gradient_add_stop_at(SPGradient *gradient, double offset)
void sp_item_gradient_set_coords(SPItem *item, GrPointType point_type, guint point_i, Geom::Point p_w, Inkscape::PaintTarget fill_or_stroke, bool write_repr, bool scale)
Set the position of point point_type of the gradient applied to item (either fill_or_stroke) to p_w (...
SPStop * sp_vector_add_stop(SPGradient *vector, SPStop *prev_stop, SPStop *next_stop, gfloat offset)
SPStop * sp_gradient_add_stop(SPGradient *gradient, SPStop *current)
SPGradient * sp_gradient_get_forked_vector_if_necessary(SPGradient *gradient, bool force_vector)
Obtain the vector from the gradient.
SPGradient * getGradient(SPItem *item, Inkscape::PaintTarget fill_or_stroke)
Fetches either the fill or the stroke gradient from the given item.
SPGradient * sp_gradient_convert_to_userspace(SPGradient *gr, SPItem *item, gchar const *property)
Convert an item's gradient to userspace if necessary, also fork it if necessary.
void sp_item_gradient_reverse_vector(SPItem *item, Inkscape::PaintTarget fill_or_stroke)
static void gr_knot_mousedown_handler(SPKnot *, unsigned int, gpointer data)
static void gr_knot_moved_handler(SPKnot *knot, Geom::Point const &ppointer, guint state, gpointer data)
std::unordered_map< GrPointType, char const * > const gr_knot_descr
static void gr_drag_sel_modified(Inkscape::Selection *, guint, gpointer data)
static void gr_knot_ungrabbed_handler(SPKnot *knot, unsigned int state, gpointer data)
Called when the mouse releases a dragger knot; changes gradient writing to repr, updates other dragge...
static int gr_drag_style_query(SPStyle *style, int property, gpointer data)
When a _query_style_signal is received, check that property requests fill/stroke/opacity (otherwise s...
static void gr_drag_sel_changed(Inkscape::Selection *, gpointer data)
static void gr_knot_doubleclicked_handler(SPKnot *, guint, gpointer data)
Called when a dragger knot is doubleclicked;.
static void gr_midpoint_limits(GrDragger *dragger, SPObject *server, Geom::Point *begin, Geom::Point *end, Geom::Point *low_lim, Geom::Point *high_lim, std::vector< GrDragger * > &moving)
static void gr_knot_clicked_handler(SPKnot *, guint state, gpointer data)
Called when a dragger knot is clicked; selects the dragger or deletes it depending on the state of th...
std::unordered_map< GrPointType, Inkscape::CanvasItemCtrlType > const gr_knot_types
static void gr_knot_moved_midpoint_handler(SPKnot *, Geom::Point const &ppointer, guint state, gpointer data)
Called when a midpoint knot is dragged.
BezierCurveN< 1 > LineSegment
Line segment.
constexpr Coord infinity()
Get a value representing infinity.
double Coord
Floating point type used to store coordinates.
Macro for icon names used in Inkscape.
Inkscape::XML::Node * node
Declarations for SPKnot: Desktop-bound visual control object.
Angle distance(Angle const &a, Angle const &b)
SBasis L2(D2< SBasis > const &a, unsigned k)
@ SNAPSOURCE_OTHER_HANDLE
@ SNAPTARGET_CONSTRAINED_ANGLE
@ CANVAS_ITEM_CTRL_TYPE_SIZER
@ CANVAS_ITEM_CTRL_TYPE_MARKER
@ CANVAS_ITEM_CTRL_TYPE_SHAPER
@ CANVAS_ITEM_CTRL_TYPE_MESH
@ CANVAS_ITEM_CTRL_TYPE_ROTATE
std::vector< PaintTarget > const & allPaintTargets()
Convenience function to access a common vector of all enum values.
SPCSSAttr * sp_repr_css_attr_new()
Creates an empty SPCSSAttr (a class for manipulating CSS style properties).
void sp_repr_css_change(Node *repr, SPCSSAttr *css, gchar const *attr)
Creates a new SPCSAttr with the values filled from a repr, merges in properties from the given SPCSAt...
void sp_repr_css_attr_unref(SPCSSAttr *css)
Unreferences an SPCSSAttr (will be garbage collected if no references remain).
SPCSSAttr * sp_repr_css_attr(Node const *repr, gchar const *attr)
Creates a new SPCSSAttr with one attribute (i.e.
char const * sp_repr_css_property(SPCSSAttr *css, gchar const *name, gchar const *defval)
Returns a character string of the value of a given style property or a default value if the attribute...
void sp_repr_css_unset_property(SPCSSAttr *css, gchar const *name)
Set a style property to "inkscape:unset".
bool sp_repr_css_property_is_unset(SPCSSAttr *css, gchar const *name)
Returns true if a style property is present and its value is unset.
void sp_repr_css_set_property(SPCSSAttr *css, gchar const *name, gchar const *value)
Set a style property to a new value (e.g.
SPCSSAttr - interface for CSS Attributes.
TODO: insert short description here.
TODO: insert short description here.
SPObject * sp_object_unref(SPObject *object, SPObject *owner)
Decrease reference count of object, with possible debugging and finalization.
SPObject * sp_object_ref(SPObject *object, SPObject *owner)
Increase reference count of object, with possible debugging.
TODO: insert short description here.
TODO: insert short description here.
This class represents a single draggable point of a gradient.
GrDraggable(SPItem *item, GrPointType point_type, guint point_i, Inkscape::PaintTarget fill_or_stroke)
bool mayMerge(GrDraggable *da2)
Inkscape::PaintTarget fill_or_stroke
This class holds together a visible on-canvas knot and a list of draggables that need to be moved whe...
void updateTip()
Updates the statusbar tip of the dragger knot, based on its draggables.
std::vector< GrDraggable * > draggables
void updateDependencies(bool write_repr)
Moves all draggables that depend on this one.
void moveOtherToDraggable(SPItem *item, GrPointType point_type, gint point_i, Inkscape::PaintTarget fill_or_stroke, bool write_repr)
GrDragger * getMgCorner()
Find mesh corner corresponding to given dragger.
void highlightCorner(bool highlight)
Highlight handles for mesh corner corresponding to this dragger.
GrDragger(GrDrag *parent, Geom::Point p, GrDraggable *draggable)
void updateControlSizes()
sigc::connection _doubleclicked_connection
void fireDraggables(bool write_repr, bool scale_radial=false, bool merging_focus=false)
Act upon all draggables of the dragger, setting them to the dragger's point.
void addDraggable(GrDraggable *draggable)
Adds a draggable to the dragger.
sigc::connection _mousedown_connection
void highlightNode(SPMeshNode *node, bool highlight, Geom::Point corner_pos, int index)
Highlight mesh node.
void updateMidstopDependencies(GrDraggable *draggable, bool write_repr)
Moves all midstop draggables that depend on this one.
void deselect()
Draw this dragger as normal (deselected).
sigc::connection _clicked_connection
void moveMeshHandles(Geom::Point pc_old, MeshNodeOperation op)
Update mesh handles when mesh corner is moved.
bool mayMerge(GrDragger *other)
void updateKnotShape()
Adds a draggable to the dragger.
sigc::connection _moved_connection
Geom::Point point_original
bool isA(GrPointType point_type)
Checks if the dragger has a draggable with this point_type.
void select()
Draw this dragger as selected.
void moveThisToDraggable(SPItem *item, GrPointType point_type, gint point_i, Inkscape::PaintTarget fill_or_stroke, bool write_repr)
Moves this dragger to the point of the given draggable, acting upon all other draggables.
sigc::connection _ungrabbed_connection
std::list< Inkscape::SnappedPoint > points
std::vector< SPGradientStop > stops
SPStyle - a style object for SPItem objects.
double sp_svg_read_percentage(char const *str, double def)