Merge lp:~inkscape.dev/inkscape/mesh_improvements into lp:~inkscape.dev/inkscape/trunk

Proposed by Jabiertxof
Status: Merged
Merge reported by: Jabiertxof
Merged at revision: not available
Proposed branch: lp:~inkscape.dev/inkscape/mesh_improvements
Merge into: lp:~inkscape.dev/inkscape/trunk
Prerequisite: lp:~inkscape.dev/inkscape/knot_improvements
Diff against target: 732 lines (+395/-73)
4 files modified
src/gradient-drag.cpp (+372/-69)
src/gradient-drag.h (+20/-2)
src/knot.h (+1/-0)
src/ui/tools/mesh-tool.cpp (+2/-2)
To merge this branch: bzr merge lp:~inkscape.dev/inkscape/mesh_improvements
Reviewer Review Type Date Requested Status
Jabiertxof Approve
Tavmjong Bah Pending
Review via email: mp+312384@code.launchpad.net

Description of the change

This branch improve the mesh gradient code:
Update to angled triangle knots the handles of selected corners.
Highlight current line.

To post a comment you must log in.
14415. By Jabiertxof <jtx@jtx>

Force knot previously. End of split mesh_and_knot branch. knot branch requred

14416. By Jabiertxof <jtx@jtx>

Add missing knot code

14417. By Jabiertxof <jtx@jtx>

Fix indent

14418. By Jabiertxof <jtx@jtx>

Update to trunk

14419. By Jabiertxof <jtx@jtx>

Fix blank lines

14420. By Jabiertxof <jtx@jtx>

Remove knot_improvements data

14421. By Jabiertxof <jtx@jtx>

Add knot_improvements data

14422. By Jabiertxof <jtx@jtx>

Update to trunk

14423. By Jabiertxof <jtx@jtx>

Update to trunk

Revision history for this message
Jabiertxof (jabiertxof) wrote :

merged

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'src/gradient-drag.cpp'
2--- src/gradient-drag.cpp 2016-12-01 13:05:02 +0000
3+++ src/gradient-drag.cpp 2016-12-03 19:47:59 +0000
4@@ -62,6 +62,7 @@
5 guint32 const GR_KNOT_COLOR_NORMAL = 0xffffff00;
6 guint32 const GR_KNOT_COLOR_MOUSEOVER = 0xff000000;
7 guint32 const GR_KNOT_COLOR_SELECTED = 0x0000ff00;
8+guint32 const GR_KNOT_COLOR_HIGHLIGHT = 0xffffff00;
9 guint32 const GR_KNOT_COLOR_MESHCORNER = 0xbfbfbf00;
10
11 guint32 const GR_LINE_COLOR_FILL = 0x0000ff7f;
12@@ -733,10 +734,12 @@
13 static void gr_knot_moved_handler(SPKnot *knot, Geom::Point const &ppointer, guint state, gpointer data)
14 {
15 GrDragger *dragger = (GrDragger *) data;
16- GrDrag *drag = dragger->parent;
17-
18+ GrDraggable *draggable = (GrDraggable *) dragger->draggables[0];
19+ if (!draggable) return;
20 Geom::Point p = ppointer;
21-
22+ GrDragger *dragger_corner = dragger->getMgCorner();
23+ GrDrag *drag = dragger_corner->parent;
24+ dragger_corner->highlightCorner(true);
25 SPDesktop *desktop = dragger->parent->desktop;
26 SnapManager &m = desktop->namedview->snap_manager;
27 double snap_dist = m.snapprefs.getObjectTolerance() / dragger->parent->desktop->current_zoom();
28@@ -1058,7 +1061,13 @@
29 static void gr_knot_grabbed_handler(SPKnot */*knot*/, unsigned int /*state*/, gpointer data)
30 {
31 GrDragger *dragger = (GrDragger *) data;
32-
33+ GrDragger *dragger_corner = dragger->getMgCorner();
34+ GrDrag *drag = dragger_corner->parent;
35+ for(std::vector<GrDragger *>::const_iterator it = drag->draggers.begin(); it != drag->draggers.end(); ++it) { //for all selected draggers
36+ GrDragger *d = *it;
37+ d->highlightCorner(false);
38+ }
39+ dragger_corner->highlightCorner(true);
40 dragger->parent->desktop->canvas->forceFullRedrawAfterInterruptions(5);
41 }
42
43@@ -1068,7 +1077,6 @@
44 static void gr_knot_ungrabbed_handler(SPKnot *knot, unsigned int state, gpointer data)
45 {
46 GrDragger *dragger = (GrDragger *) data;
47-
48 dragger->parent->desktop->canvas->endForcedFullRedraws();
49
50 dragger->point_original = dragger->point = knot->pos;
51@@ -1107,7 +1115,6 @@
52 GrDragger *dragger = (GrDragger *) data;
53 GrDraggable *draggable = dragger->draggables[0];
54 if (!draggable) return;
55-
56 if ( (state & GDK_CONTROL_MASK) && (state & GDK_MOD1_MASK ) ) {
57 // delete this knot from vector
58 SPGradient *gradient = getGradient(draggable->item, draggable->fill_or_stroke);
59@@ -1209,6 +1216,30 @@
60 }
61 }
62
63+void GrDragger::updateControlSizesOverload(SPKnot * knot)
64+{
65+ Inkscape::Preferences *prefs = Inkscape::Preferences::get();
66+ int sizes[] = {4, 6, 8, 10, 12, 14, 16};
67+ std::vector<int> sizeTable = std::vector<int>(sizes, sizes + (sizeof(sizes) / sizeof(sizes[0])));
68+ int size = prefs->getIntLimited("/options/grabsize/value", 3, 1, 7);
69+ int knot_size = sizeTable[size - 1];
70+ if(knot->shape == SP_KNOT_SHAPE_TRIANGLE){
71+ knot_size *= 2.2;
72+ knot_size = floor(knot_size);
73+ if ( knot_size % 2 == 0 ){
74+ knot_size += 1;
75+ }
76+ }
77+ knot->setSize(knot_size);
78+}
79+
80+void GrDragger::updateControlSizes()
81+{
82+ updateControlSizesOverload(this->knot);
83+ this->knot->updateCtrl();
84+ this->updateKnotShape();
85+}
86+
87 /**
88 * Checks if the dragger has a draggable with this point_type.
89 */
90@@ -1385,6 +1416,7 @@
91 for( guint i = 0; i < mg->array.handles.size(); ++i ) {
92 GrDragger *handle = drag->getDraggerFor( item, POINT_MG_HANDLE, i, fill_or_stroke );
93 SPKnot *knot = handle->knot;
94+ knot->setFill(GR_KNOT_COLOR_NORMAL, GR_KNOT_COLOR_MOUSEOVER, GR_KNOT_COLOR_MOUSEOVER);
95 Geom::Point pk = getGradientCoords( item, POINT_MG_HANDLE, i, fill_or_stroke );
96 knot->moveto(pk);
97
98@@ -1462,8 +1494,18 @@
99 {
100 if (draggables.empty())
101 return;
102- GrDraggable *last = draggables.back();
103+ GrDraggable *last = draggables.back();
104+ bool highlight = false;
105+ if(this->knot->shape == SP_KNOT_SHAPE_TRIANGLE){
106+ highlight = true;
107+ }
108 g_object_set (G_OBJECT (this->knot->item), "shape", gr_knot_shapes[last->point_type], NULL);
109+ if(highlight){
110+ this->knot->setFill(GR_KNOT_COLOR_HIGHLIGHT, GR_KNOT_COLOR_MOUSEOVER, GR_KNOT_COLOR_MOUSEOVER);
111+ if(gr_knot_shapes[last->point_type] == SP_KNOT_SHAPE_CIRCLE){
112+ g_object_set (G_OBJECT (this->knot->item), "shape", SP_KNOT_SHAPE_TRIANGLE, NULL);
113+ }
114+ }
115 }
116
117 /**
118@@ -1608,6 +1650,7 @@
119 }
120 this->knot->setFill(fill_color, GR_KNOT_COLOR_MOUSEOVER, GR_KNOT_COLOR_MOUSEOVER);
121 this->knot->setStroke(0x0000007f, 0x0000007f, 0x0000007f);
122+ this->updateControlSizesOverload(this->knot);
123 this->knot->updateCtrl();
124
125 // move knot to the given point
126@@ -1626,6 +1669,7 @@
127 this->_moved_connection = this->knot->moved_signal.connect(sigc::bind(sigc::ptr_fun(gr_knot_moved_handler), this));
128 }
129
130+ this->sizeUpdatedConn = ControlManager::getManager().connectCtrlSizeChanged(sigc::mem_fun(*this, &GrDragger::updateControlSizes));
131 this->_clicked_connection = this->knot->click_signal.connect(sigc::bind(sigc::ptr_fun(gr_knot_clicked_handler), this));
132 this->_doubleclicked_connection = this->knot->doubleclicked_signal.connect(sigc::bind(sigc::ptr_fun(gr_knot_doubleclicked_handler), this));
133 this->_grabbed_connection = this->knot->grabbed_signal.connect(sigc::bind(sigc::ptr_fun(gr_knot_grabbed_handler), this));
134@@ -1635,7 +1679,7 @@
135 if (draggable) {
136 this->addDraggable (draggable);
137 }
138-
139+
140 updateKnotShape();
141 }
142
143@@ -1648,6 +1692,7 @@
144 //this->parent->setDeselected(this);
145
146 // disconnect signals
147+ this->sizeUpdatedConn.disconnect();
148 this->_moved_connection.disconnect();
149 this->_clicked_connection.disconnect();
150 this->_doubleclicked_connection.disconnect();
151@@ -1708,6 +1753,180 @@
152 }
153 }
154
155+GrDragger *
156+GrDragger::getMgCorner(){
157+ GrDraggable *draggable = (GrDraggable *) this->draggables[0];
158+ if (draggable){
159+ if(draggable->point_type == POINT_MG_CORNER){
160+ return this;
161+ }
162+ SPGradient *gradient = getGradient(draggable->item, draggable->fill_or_stroke);
163+ if (SP_IS_MESHGRADIENT( gradient ) ){
164+ SPMeshGradient *mg = SP_MESHGRADIENT( gradient );
165+ std::vector< std::vector< SPMeshNode* > > nodes = mg->array.nodes;
166+ for( guint i = 0; i < nodes.size(); ++i ) {
167+ for( guint j = 0; j < nodes[i].size(); ++j ) {
168+ if( nodes[i][j]->set ) {
169+ if( nodes[i][j]->node_type == MG_NODE_TYPE_HANDLE){
170+ if(draggable->point_i == (gint)nodes[i][j]->draggable){
171+ if(nodes.size() > i+1 && nodes[i+1].size() > j && nodes[i+1][j]->node_type == MG_NODE_TYPE_CORNER){
172+ return this->parent->getDraggerFor(draggable->item, POINT_MG_CORNER, nodes[i+1][j]->draggable, draggable->fill_or_stroke);
173+ }
174+ if(j != 0 && nodes.size() > i && nodes[i].size() > j-1 && nodes[i][j-1]->node_type == MG_NODE_TYPE_CORNER){
175+ return this->parent->getDraggerFor(draggable->item, POINT_MG_CORNER, nodes[i][j-1]->draggable, draggable->fill_or_stroke);
176+ }
177+ if(i != 0 && nodes.size() > i-1 && nodes[i-1].size() > j && nodes[i-1][j]->node_type == MG_NODE_TYPE_CORNER){
178+ return this->parent->getDraggerFor(draggable->item, POINT_MG_CORNER, nodes[i-1][j]->draggable, draggable->fill_or_stroke);
179+ }
180+ if(nodes.size() > i && nodes[i].size() > j+1 && nodes[i][j+1]->node_type == MG_NODE_TYPE_CORNER){
181+ return this->parent->getDraggerFor(draggable->item, POINT_MG_CORNER, nodes[i][j+1]->draggable, draggable->fill_or_stroke);
182+ }
183+ }
184+ }
185+ }
186+ }
187+ }
188+ }
189+ }
190+ return NULL;
191+}
192+
193+mgDraggerPosition
194+GrDragger::getMgDraggerPosition(){
195+ GrDraggable *draggable = (GrDraggable *) this->draggables[0];
196+ if (draggable && draggable->point_i < G_MAXINT){
197+ NodeType type = MG_NODE_TYPE_TENSOR;
198+ if(draggable->point_type == POINT_MG_HANDLE){
199+ type = MG_NODE_TYPE_HANDLE;
200+ } else if (draggable->point_type == POINT_MG_CORNER){
201+ type = MG_NODE_TYPE_CORNER;
202+ }
203+ SPGradient *gradient = getGradient(draggable->item, draggable->fill_or_stroke);
204+ if (SP_IS_MESHGRADIENT( gradient ) ){
205+ SPMeshGradient *mg = SP_MESHGRADIENT( gradient );
206+ SPMeshNodeArray mg_arr = mg->array;
207+ std::vector< std::vector< SPMeshNode* > > nodes = mg_arr.nodes;
208+ for( guint i = 0; i < nodes.size(); ++i ) {
209+ for( guint j = 0; j < nodes[i].size(); ++j ) {
210+ if( nodes[i][j]->set) {
211+ if(draggable->point_i == (gint)nodes[i][j]->draggable && type == nodes[i][j]->node_type){
212+ if( nodes[i][j]->node_type == MG_NODE_TYPE_HANDLE){
213+ if(nodes.size() > i+1 && nodes[i+1].size() > j && nodes[i+1][j]->node_type == MG_NODE_TYPE_CORNER){
214+ return std::make_pair(MG_D_BOTTOM,std::make_pair(i,j));
215+ }
216+ if(j != 0 && nodes.size() > i && nodes[i].size() > j-1 && nodes[i][j-1]->node_type == MG_NODE_TYPE_CORNER){
217+ return std::make_pair(MG_D_LEFT,std::make_pair(i,j));
218+ }
219+ if(i != 0 && nodes.size() > i-1 && nodes[i-1].size() > j && nodes[i-1][j]->node_type == MG_NODE_TYPE_CORNER){
220+ return std::make_pair(MG_D_TOP,std::make_pair(i,j));
221+ }
222+ if(nodes.size() > i && nodes[i].size() > j+1 && nodes[i][j+1]->node_type == MG_NODE_TYPE_CORNER){
223+ return std::make_pair(MG_D_RIGHT,std::make_pair(i,j));
224+ }
225+ }
226+ if(nodes[i][j]->node_type == MG_NODE_TYPE_CORNER){
227+ return std::make_pair(MG_D_CENTER,std::make_pair(i,j));
228+ }
229+ }
230+
231+ }
232+ }
233+ }
234+ }
235+ }
236+ return std::make_pair(MG_D_NONE, std::make_pair(0,0));
237+}
238+
239+void GrDragger::highlightNode(SPMeshNode* node, bool highlight, Geom::Point corner_pos)
240+{
241+ GrPointType type = POINT_MG_TENSOR;
242+ if(node->node_type == MG_NODE_TYPE_HANDLE){
243+ type = POINT_MG_HANDLE;
244+ }
245+ GrDraggable *draggable = (GrDraggable *) this->draggables[0];
246+ GrDragger *d = this->parent->getDraggerFor(draggable->item, type, node->draggable, draggable->fill_or_stroke);
247+ if (d && node->draggable < G_MAXUINT) {
248+ Geom::Point end = d->knot->pos;
249+ double angl = Geom::Ray(corner_pos, end).angle();
250+ if(highlight && knot->fill[SP_KNOT_VISIBLE] == GR_KNOT_COLOR_HIGHLIGHT && abs(angl - knot->angle) > Geom::rad_from_deg(10.0)){
251+ return;
252+ }
253+ SPKnot *knot = d->knot;
254+ if(highlight){
255+ knot->setFill(GR_KNOT_COLOR_HIGHLIGHT, GR_KNOT_COLOR_MOUSEOVER, GR_KNOT_COLOR_MOUSEOVER);
256+ } else {
257+ knot->setFill(GR_KNOT_COLOR_NORMAL, GR_KNOT_COLOR_MOUSEOVER, GR_KNOT_COLOR_MOUSEOVER);
258+ }
259+ if(type == POINT_MG_HANDLE){
260+ if(highlight){
261+ knot->setShape(SP_KNOT_SHAPE_TRIANGLE);
262+ } else {
263+ knot->setShape(SP_KNOT_SHAPE_CIRCLE);
264+
265+ }
266+ } else {
267+ //Code for tensors
268+ return;
269+ }
270+ this->updateControlSizesOverload(knot);
271+ knot->setAngle(angl);
272+ knot->updateCtrl();
273+ d->updateKnotShape();
274+ }
275+}
276+
277+void GrDragger::highlightCorner(bool highlight)
278+{
279+ // Must be a mesh gradient
280+ GrDraggable *draggable = (GrDraggable *) this->draggables[0];
281+ if (draggable && draggable->point_type == POINT_MG_CORNER){
282+ SPGradient *gradient = getGradient(draggable->item, draggable->fill_or_stroke);
283+ if (SP_IS_MESHGRADIENT( gradient ) ){
284+ Geom::Point corner_point = this->point;
285+ gint corner = draggable->point_i;
286+ SPMeshGradient *mg = SP_MESHGRADIENT( gradient );
287+ SPMeshNodeArray mg_arr = mg->array;
288+ std::vector< std::vector< SPMeshNode* > > nodes = mg_arr.nodes;
289+ // Find number of patch rows and columns
290+ guint mrow = mg_arr.patch_rows();
291+ guint mcol = mg_arr.patch_columns();
292+ // Number of corners in a row of patches.
293+ guint ncorners = mcol + 1;
294+ // Find corner row/column
295+ guint crow = corner / ncorners;
296+ guint ccol = corner % ncorners;
297+ // Find node row/column
298+ guint nrow = crow * 3;
299+ guint ncol = ccol * 3;
300+
301+ bool patch[4];
302+ patch[0] = patch[1] = patch[2] = patch[3] = false;
303+ if( ccol > 0 && crow > 0) patch[0] = true;
304+ if( ccol < mcol && crow > 0 ) patch[1] = true;
305+ if( ccol < mcol && crow < mrow ) patch[2] = true;
306+ if( ccol > 0 && crow < mrow ) patch[3] = true;
307+ if( patch[0] || patch[1] ) {
308+ highlightNode(nodes[nrow-1][ncol ], highlight, corner_point);
309+ }
310+ if( patch[1] || patch[2] ) {
311+ highlightNode(nodes[nrow ][ncol+1], highlight, corner_point);
312+ }
313+ if( patch[2] || patch[3] ) {
314+ highlightNode(nodes[nrow+1][ncol ], highlight, corner_point);
315+ }
316+ if( patch[3] || patch[0] ) {
317+ highlightNode(nodes[nrow ][ncol-1], highlight, corner_point);
318+ }
319+ // Highlight tensors
320+ /*
321+ if( patch[0] ) highlightNode(nodes[nrow-1][ncol-1], highlight, corner_point, point_i);
322+ if( patch[1] ) highlightNode(nodes[nrow-1][ncol+1], highlight, corner_point, point_i);
323+ if( patch[2] ) highlightNode(nodes[nrow+1][ncol+1], highlight, corner_point, point_i);
324+ if( patch[3] ) highlightNode(nodes[nrow+1][ncol-1], highlight, corner_point, point_i);
325+ */
326+ }
327+ }
328+}
329
330 /**
331 * Draw this dragger as selected.
332@@ -1716,6 +1935,7 @@
333 {
334 this->knot->fill [SP_KNOT_STATE_NORMAL] = GR_KNOT_COLOR_SELECTED;
335 g_object_set (G_OBJECT (this->knot->item), "fill_color", GR_KNOT_COLOR_SELECTED, NULL);
336+ highlightCorner(true);
337 //if( isA(POINT_MG_CORNER) ) {
338 // for (GSList * drgble = this->draggables; drgble != NULL; drgble = drgble->next) {
339 // GrDraggable *draggable = (GrDraggable*) drgble->data;
340@@ -1733,6 +1953,7 @@
341 guint32 fill_color = isA(POINT_MG_CORNER) ? GR_KNOT_COLOR_MESHCORNER : GR_KNOT_COLOR_NORMAL;
342 this->knot->fill [SP_KNOT_STATE_NORMAL] = fill_color;
343 g_object_set (G_OBJECT (this->knot->item), "fill_color", fill_color, NULL);
344+ highlightCorner(false);
345 // MESH FIXME: TURN OFF CORRESPONDING SIDE/TENSOR NODE VISIBILITY
346 }
347
348@@ -1903,10 +2124,14 @@
349 * Create a curve from p0 to p3 and add it to the lines list. Used for mesh sides.
350 */
351 void GrDrag::addCurve(SPItem *item, Geom::Point p0, Geom::Point p1, Geom::Point p2, Geom::Point p3,
352- int corner0, int corner1, Inkscape::PaintTarget fill_or_stroke)
353+ int corner0, int corner1, Inkscape::PaintTarget fill_or_stroke, bool highlight)
354+
355 {
356 // CtrlLineType only sets color
357 CtrlLineType type = (fill_or_stroke == Inkscape::FOR_FILL) ? CTLINE_PRIMARY : CTLINE_SECONDARY;
358+ if(highlight){
359+ type = (fill_or_stroke == Inkscape::FOR_FILL) ? CTLINE_SECONDARY : CTLINE_PRIMARY;
360+ }
361 SPCtrlCurve *line = ControlManager::getManager().createControlCurve(this->desktop->getControls(), p0, p1, p2, p3, type);
362 line->corner0 = corner0;
363 line->corner1 = corner1;
364@@ -2265,12 +2490,20 @@
365 */
366 bool GrDrag::mouseOver()
367 {
368+ static bool mouse_out = false;
369+ // added knot mouse out for future use
370 for (std::vector<GrDragger *>::const_iterator l = this->draggers.begin(); l != this->draggers.end(); ++l) {
371 GrDragger *d = *l;
372 if (d->knot && (d->knot->flags & SP_KNOT_MOUSEOVER)) {
373+ mouse_out = true;
374+ updateLines();
375 return true;
376 }
377 }
378+ if(mouse_out == true){
379+ updateLines();
380+ mouse_out = false;
381+ }
382 return false;
383 }
384
385@@ -2284,16 +2517,22 @@
386 for (std::vector<SPCtrlLine *>::const_iterator i = this->lines.begin(); i != this->lines.end(); ++i) {
387 sp_canvas_item_destroy(SP_CANVAS_ITEM(*i));
388 }
389+ bool highlight = false;
390 this->lines.clear();
391-
392 g_return_if_fail(this->selection != NULL);
393
394+ mgDraggerPosition mg_dragger_position = std::make_pair(MG_D_NONE, std::make_pair(0,0));
395+ for (std::vector<GrDragger *>::const_iterator it = this->draggers.begin(); it != this->draggers.end() ; ++it ) {
396+ GrDragger *d = *it;
397+ if (d->knot && (d->knot->flags & SP_KNOT_MOUSEOVER)) {
398+ mg_dragger_position = d->getMgDraggerPosition();
399+ break;
400+ }
401+ }
402 auto list = this->selection->items();
403 for (auto i = list.begin(); i != list.end(); ++i) {
404 SPItem *item = *i;
405-
406 SPStyle *style = item->style;
407-
408 if (style && (style->fill.isPaintserver())) {
409 SPPaintServer *server = item->style->getFillPaintServer();
410 if ( server && SP_IS_GRADIENT( server ) ) {
411@@ -2307,62 +2546,90 @@
412 addLine(item, center, getGradientCoords(item, POINT_RG_R1, 0, Inkscape::FOR_FILL), Inkscape::FOR_FILL);
413 addLine(item, center, getGradientCoords(item, POINT_RG_R2, 0, Inkscape::FOR_FILL), Inkscape::FOR_FILL);
414 } else if ( SP_IS_MESHGRADIENT(server) ) {
415-
416 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
417 bool edit_fill = abs(prefs->getBool("/tools/mesh/edit_fill", true));
418-
419 SPMeshGradient *mg = SP_MESHGRADIENT(server);
420-
421 if (edit_fill) {
422- guint rows = mg->array.patch_rows();
423- guint columns = mg->array.patch_columns();
424- for ( guint i = 0; i < rows; ++i ) {
425- for ( guint j = 0; j < columns; ++j ) {
426-
427- std::vector<Geom::Point> h;
428-
429- SPMeshPatchI patch( &(mg->array.nodes), i, j );
430-
431- // clockwise around patch, used to find corner dragger
432- int corner0 = i * (columns + 1) + j;
433- int corner1 = corner0 + 1;
434- int corner2 = corner1 + columns + 1;
435- int corner3 = corner2 - 1;
436-
437- // Top line
438- h = patch.getPointsForSide( 0 );
439- for( guint p = 0; p < 4; ++p ) {
440- h[p] *= Geom::Affine(mg->gradientTransform) * (Geom::Affine)item->i2dt_affine();
441- }
442- addCurve (item, h[0], h[1], h[2], h[3], corner0, corner1, Inkscape::FOR_FILL );
443-
444- // Right line
445- if( j == columns - 1 ) {
446- h = patch.getPointsForSide( 1 );
447- for( guint p = 0; p < 4; ++p ) {
448- h[p] *= Geom::Affine(mg->gradientTransform) * (Geom::Affine)item->i2dt_affine();
449- }
450- addCurve (item, h[0], h[1], h[2], h[3], corner1, corner2, Inkscape::FOR_FILL );
451- }
452-
453- // Bottom line
454- if( i == rows - 1 ) {
455- h = patch.getPointsForSide( 2 );
456- for( guint p = 0; p < 4; ++p ) {
457- h[p] *= Geom::Affine(mg->gradientTransform) * (Geom::Affine)item->i2dt_affine();
458- }
459- addCurve (item, h[0], h[1], h[2], h[3], corner2, corner3, Inkscape::FOR_FILL );
460- }
461-
462- // Left line
463- h = patch.getPointsForSide( 3 );
464- for( guint p = 0; p < 4; ++p ) {
465- h[p] *= Geom::Affine(mg->gradientTransform) * (Geom::Affine)item->i2dt_affine();
466- }
467- addCurve (item, h[0], h[1], h[2], h[3], corner3, corner0, Inkscape::FOR_FILL );
468+ guint rows = mg->array.patch_rows();
469+ guint columns = mg->array.patch_columns();
470+ for ( guint i = 0; i < rows; ++i ) {
471+ for ( guint j = 0; j < columns; ++j ) {
472+ std::vector<Geom::Point> h;
473+ SPMeshPatchI patch( &(mg->array.nodes), i, j );
474+ // clockwise around patch, used to find corner dragger
475+ int corner0 = i * (columns + 1) + j;
476+ int corner1 = corner0 + 1;
477+ int corner2 = corner1 + columns + 1;
478+ int corner3 = corner2 - 1;
479+ // Top line
480+ h = patch.getPointsForSide( 0 );
481+ for( guint p = 0; p < 4; ++p ) {
482+ h[p] *= Geom::Affine(mg->gradientTransform) * (Geom::Affine)item->i2dt_affine();
483+ }
484+ highlight = false;
485+ if(mg_dragger_position.first != MG_D_NONE &&
486+ ((mg_dragger_position.first == MG_D_CENTER && mg_dragger_position.second.first/3 == i && mg_dragger_position.second.second/3 == j) ||
487+ (mg_dragger_position.first == MG_D_CENTER && mg_dragger_position.second.first/3 == i && (mg_dragger_position.second.second/3)-1 == j) ||
488+ (mg_dragger_position.first == MG_D_RIGHT && mg_dragger_position.second.first/3 == i && mg_dragger_position.second.second/3 == j) ||
489+ (mg_dragger_position.first == MG_D_LEFT && mg_dragger_position.second.first/3 == i && mg_dragger_position.second.second/3 == j)))
490+ {
491+ highlight = true;
492+ }
493+ addCurve (item, h[0], h[1], h[2], h[3], corner0, corner1, Inkscape::FOR_FILL, highlight);
494+ // Right line
495+ if( j == columns - 1 ) {
496+ h = patch.getPointsForSide( 1 );
497+ for( guint p = 0; p < 4; ++p ) {
498+ h[p] *= Geom::Affine(mg->gradientTransform) * (Geom::Affine)item->i2dt_affine();
499+ }
500+ highlight = false;
501+ if(mg_dragger_position.first != MG_D_NONE &&
502+ ((mg_dragger_position.first == MG_D_CENTER && mg_dragger_position.second.first/3 == i && (mg_dragger_position.second.second/3) >j) ||
503+ (mg_dragger_position.first == MG_D_CENTER && (mg_dragger_position.second.first/3)-1 == i && (mg_dragger_position.second.second/3) > j) ||
504+ (mg_dragger_position.first == MG_D_TOP && mg_dragger_position.second.first/3 == i && (mg_dragger_position.second.second/3) > j) ||
505+ (mg_dragger_position.first == MG_D_BOTTOM && mg_dragger_position.second.first/3 == i && (mg_dragger_position.second.second/3) > j)))
506+ {
507+ highlight = true;
508+ }
509+ addCurve (item, h[0], h[1], h[2], h[3], corner1, corner2, Inkscape::FOR_FILL, highlight);
510+ }
511+
512+ // Bottom line
513+ if( i == rows - 1 ) {
514+ h = patch.getPointsForSide( 2 );
515+ for( guint p = 0; p < 4; ++p ) {
516+ h[p] *= Geom::Affine(mg->gradientTransform) * (Geom::Affine)item->i2dt_affine();
517+ }
518+ highlight = false;
519+ if(mg_dragger_position.first != MG_D_NONE &&
520+ ((mg_dragger_position.first == MG_D_CENTER && (mg_dragger_position.second.first/3) > i && mg_dragger_position.second.second/3 == j) ||
521+ (mg_dragger_position.first == MG_D_CENTER && (mg_dragger_position.second.first/3) > i && (mg_dragger_position.second.second/3)-1 == j) ||
522+ (mg_dragger_position.first == MG_D_RIGHT && (mg_dragger_position.second.first/3) > i && mg_dragger_position.second.second/3 == j) ||
523+ (mg_dragger_position.first == MG_D_LEFT && (mg_dragger_position.second.first/3) > i && mg_dragger_position.second.second/3 == j)))
524+ {
525+ highlight = true;
526+ }
527+ addCurve (item, h[0], h[1], h[2], h[3], corner2, corner3, Inkscape::FOR_FILL, highlight );
528+ }
529+
530+ // Left line
531+ h = patch.getPointsForSide( 3 );
532+ for( guint p = 0; p < 4; ++p ) {
533+ h[p] *= Geom::Affine(mg->gradientTransform) * (Geom::Affine)item->i2dt_affine();
534+ }
535+ highlight = false;
536+ if(mg_dragger_position.first != MG_D_NONE &&
537+ ((mg_dragger_position.first == MG_D_CENTER && mg_dragger_position.second.first/3 == i && mg_dragger_position.second.second/3 == j) ||
538+ (mg_dragger_position.first == MG_D_CENTER && (mg_dragger_position.second.first/3)-1 == i && mg_dragger_position.second.second/3 == j) ||
539+ (mg_dragger_position.first == MG_D_TOP && mg_dragger_position.second.first/3 == i && mg_dragger_position.second.second/3 == j) ||
540+ (mg_dragger_position.first == MG_D_BOTTOM && mg_dragger_position.second.first/3 == i && mg_dragger_position.second.second/3 == j)))
541+ {
542+ highlight = true;
543+ }
544+ addCurve (item, h[0], h[1], h[2], h[3], corner3, corner0, Inkscape::FOR_FILL, highlight );
545+ }
546 }
547 }
548- }
549 }
550 }
551 }
552@@ -2388,14 +2655,12 @@
553
554 // MESH FIXME: TURN ROUTINE INTO FUNCTION AND CALL FOR BOTH FILL AND STROKE.
555 SPMeshGradient *mg = SP_MESHGRADIENT(server);
556-
557 guint rows = mg->array.patch_rows();
558 guint columns = mg->array.patch_columns();
559 for ( guint i = 0; i < rows; ++i ) {
560 for ( guint j = 0; j < columns; ++j ) {
561-
562+
563 std::vector<Geom::Point> h;
564-
565 SPMeshPatchI patch( &(mg->array.nodes), i, j );
566
567 // clockwise around patch, used to find corner dragger
568@@ -2409,7 +2674,17 @@
569 for( guint p = 0; p < 4; ++p ) {
570 h[p] *= Geom::Affine(mg->gradientTransform) * (Geom::Affine)item->i2dt_affine();
571 }
572- addCurve (item, h[0], h[1], h[2], h[3], corner0, corner1, Inkscape::FOR_STROKE );
573+
574+ highlight = false;
575+ if(mg_dragger_position.first != MG_D_NONE &&
576+ ((mg_dragger_position.first == MG_D_CENTER && mg_dragger_position.second.first/3 == i && mg_dragger_position.second.second/3 == j) ||
577+ (mg_dragger_position.first == MG_D_CENTER && mg_dragger_position.second.first/3 == i && (mg_dragger_position.second.second/3)-1 == j) ||
578+ (mg_dragger_position.first == MG_D_RIGHT && mg_dragger_position.second.first/3 == i && mg_dragger_position.second.second/3 == j) ||
579+ (mg_dragger_position.first == MG_D_LEFT && mg_dragger_position.second.first/3 == i && mg_dragger_position.second.second/3 == j)))
580+ {
581+ highlight = true;
582+ }
583+ addCurve (item, h[0], h[1], h[2], h[3], corner0, corner1, Inkscape::FOR_STROKE, highlight);
584
585 // Right line
586 if( j == columns - 1 ) {
587@@ -2417,7 +2692,16 @@
588 for( guint p = 0; p < 4; ++p ) {
589 h[p] *= Geom::Affine(mg->gradientTransform) * (Geom::Affine)item->i2dt_affine();
590 }
591- addCurve (item, h[0], h[1], h[2], h[3], corner1, corner2, Inkscape::FOR_STROKE );
592+ highlight = false;
593+ if(mg_dragger_position.first != MG_D_NONE &&
594+ ((mg_dragger_position.first == MG_D_CENTER && mg_dragger_position.second.first/3 == i && (mg_dragger_position.second.second/3) >j) ||
595+ (mg_dragger_position.first == MG_D_CENTER && (mg_dragger_position.second.first/3)-1 == i && (mg_dragger_position.second.second/3) > j) ||
596+ (mg_dragger_position.first == MG_D_TOP && mg_dragger_position.second.first/3 == i && (mg_dragger_position.second.second/3) > j) ||
597+ (mg_dragger_position.first == MG_D_BOTTOM && mg_dragger_position.second.first/3 == i && (mg_dragger_position.second.second/3) > j)))
598+ {
599+ highlight = true;
600+ }
601+ addCurve (item, h[0], h[1], h[2], h[3], corner1, corner2, Inkscape::FOR_STROKE, highlight );
602 }
603
604 // Bottom line
605@@ -2426,7 +2710,16 @@
606 for( guint p = 0; p < 4; ++p ) {
607 h[p] *= Geom::Affine(mg->gradientTransform) * (Geom::Affine)item->i2dt_affine();
608 }
609- addCurve (item, h[0], h[1], h[2], h[3], corner2, corner3, Inkscape::FOR_STROKE );
610+ highlight = false;
611+ if(mg_dragger_position.first != MG_D_NONE &&
612+ ((mg_dragger_position.first == MG_D_CENTER && (mg_dragger_position.second.first/3) > i && mg_dragger_position.second.second/3 == j) ||
613+ (mg_dragger_position.first == MG_D_CENTER && (mg_dragger_position.second.first/3) > i && (mg_dragger_position.second.second/3)-1 == j) ||
614+ (mg_dragger_position.first == MG_D_RIGHT && (mg_dragger_position.second.first/3) > i && mg_dragger_position.second.second/3 == j) ||
615+ (mg_dragger_position.first == MG_D_LEFT && (mg_dragger_position.second.first/3) > i && mg_dragger_position.second.second/3 == j)))
616+ {
617+ highlight = true;
618+ }
619+ addCurve (item, h[0], h[1], h[2], h[3], corner2, corner3, Inkscape::FOR_STROKE, highlight );
620 }
621
622 // Left line
623@@ -2434,7 +2727,17 @@
624 for( guint p = 0; p < 4; ++p ) {
625 h[p] *= Geom::Affine(mg->gradientTransform) * (Geom::Affine)item->i2dt_affine();
626 }
627- addCurve (item, h[0], h[1], h[2], h[3], corner3, corner0, Inkscape::FOR_STROKE );
628+ highlight = false;
629+ if(mg_dragger_position.first != MG_D_NONE &&
630+ ((mg_dragger_position.first == MG_D_CENTER && mg_dragger_position.second.first/3 == i && mg_dragger_position.second.second/3 == j) ||
631+ (mg_dragger_position.first == MG_D_CENTER && (mg_dragger_position.second.first/3)-1 == i && mg_dragger_position.second.second/3 == j) ||
632+ (mg_dragger_position.first == MG_D_TOP && mg_dragger_position.second.first/3 == i && mg_dragger_position.second.second/3 == j) ||
633+ (mg_dragger_position.first == MG_D_BOTTOM && mg_dragger_position.second.first/3 == i && mg_dragger_position.second.second/3 == j)))
634+ {
635+ highlight = true;
636+ }
637+ addCurve (item, h[0], h[1], h[2], h[3], corner3, corner0, Inkscape::FOR_STROKE, highlight );
638+
639 }
640 }
641 }
642
643=== modified file 'src/gradient-drag.h'
644--- src/gradient-drag.h 2016-11-23 09:23:22 +0000
645+++ src/gradient-drag.h 2016-12-03 19:47:59 +0000
646@@ -25,7 +25,6 @@
647 #include <glibmm/ustring.h>
648
649 #include <2geom/point.h>
650-
651 #include "sp-gradient.h" // TODO refactor enums to external .h file
652 #include "sp-mesh-array.h"
653
654@@ -44,6 +43,16 @@
655 class Selection;
656 } // namespace Inkscape
657
658+enum GrDraggerPositions {
659+ MG_D_CENTER = 0, //Corner
660+ MG_D_TOP, //Top dragger
661+ MG_D_RIGHT, //Right dragger
662+ MG_D_BOTTOM, //Bottom dragger
663+ MG_D_LEFT, // Left dragger
664+ MG_D_NONE // Invalid dragger
665+};
666+typedef std::pair<GrDraggerPositions,std::pair<guint,guint> > mgDraggerPosition;
667+
668 /**
669 This class represents a single draggable point of a gradient. It remembers the item
670 which has the gradient, whether it's fill or stroke, the point type (from the
671@@ -94,6 +103,10 @@
672 void updateKnotShape();
673 void updateTip();
674
675+ mgDraggerPosition getMgDraggerPosition();
676+ GrDragger *getMgCorner();
677+ void highlightNode(SPMeshNode* node, bool highlight, Geom::Point corner_pos);
678+ void highlightCorner(bool highlight);
679 void select();
680 void deselect();
681 bool isSelected();
682@@ -116,6 +129,11 @@
683
684 void fireDraggables(bool write_repr, bool scale_radial = false, bool merging_focus = false);
685
686+protected:
687+ void updateControlSizesOverload(SPKnot * knot);
688+ void updateControlSizes();
689+ sigc::connection sizeUpdatedConn;
690+
691 private:
692 sigc::connection _moved_connection;
693 sigc::connection _clicked_connection;
694@@ -205,7 +223,7 @@
695 void deselect_all();
696
697 void addLine( SPItem *item, Geom::Point p1, Geom::Point p2, Inkscape::PaintTarget fill_or_stroke);
698- void addCurve(SPItem *item, Geom::Point p0, Geom::Point p1, Geom::Point p2, Geom::Point p3, int corner0, int corner1, Inkscape::PaintTarget fill_or_stroke);
699+ void addCurve(SPItem *item, Geom::Point p0, Geom::Point p1, Geom::Point p2, Geom::Point p3, int corner0, int corner1, Inkscape::PaintTarget fill_or_stroke, bool highlight = false);
700
701 GrDragger *addDragger(GrDraggable *draggable);
702
703
704=== modified file 'src/knot.h'
705--- src/knot.h 2016-12-03 16:11:45 +0000
706+++ src/knot.h 2016-12-03 19:47:59 +0000
707@@ -59,6 +59,7 @@
708
709 SPKnotShapeType shape; /**< Shape type. */
710 SPKnotModeType mode;
711+ double angle;
712
713 guint32 fill[SP_KNOT_VISIBLE_STATES];
714 guint32 stroke[SP_KNOT_VISIBLE_STATES];
715
716=== modified file 'src/ui/tools/mesh-tool.cpp'
717--- src/ui/tools/mesh-tool.cpp 2016-12-02 09:15:24 +0000
718+++ src/ui/tools/mesh-tool.cpp 2016-12-03 19:47:59 +0000
719@@ -754,11 +754,11 @@
720 }
721
722 // Highlight corner node corresponding to side or tensor node
723- if( drag->mouseOver() ) {
724+ //if( drag->mouseOver() ) {
725 // MESH FIXME: Light up corresponding corner node corresponding to node we are over.
726 // See "pathflash" in ui/tools/node-tool.cpp for ideas.
727 // Use desktop->add_temporary_canvasitem( SPCanvasItem, milliseconds );
728- }
729+ //}
730
731 // Change cursor shape if over line
732 std::vector<SPCtrlCurve *> over_line =