summaryrefslogtreecommitdiffstats
path: root/src/ui/tools/mesh-tool.cpp
diff options
context:
space:
mode:
authorTavmjong Bah <tavmjong@free.fr>2016-11-18 19:29:57 +0000
committertavmjong-free <tavmjong@free.fr>2016-11-18 19:29:57 +0000
commit7aa5bd6f04cbc26d79239b07c6a91fbabf3015d1 (patch)
tree737f8bde623a20dc3d165eee8dc26e496364bc2b /src/ui/tools/mesh-tool.cpp
parentFix #1627817. Bug in knot LPE (diff)
downloadinkscape-7aa5bd6f04cbc26d79239b07c6a91fbabf3015d1.tar.gz
inkscape-7aa5bd6f04cbc26d79239b07c6a91fbabf3015d1.zip
Improve mouse handling for mesh:
* Double clicking an object will create a new mesh if one does not exist, otherwise clicking a line should now reliably divide the row/column. * Click-dragging will create a new mesh if one does not exist, otherwise it will do a rubberband selection of corner nodes. With Shift will add nodes, without will replace selected nodes. (bzr r15260)
Diffstat (limited to 'src/ui/tools/mesh-tool.cpp')
-rw-r--r--src/ui/tools/mesh-tool.cpp196
1 files changed, 117 insertions, 79 deletions
diff --git a/src/ui/tools/mesh-tool.cpp b/src/ui/tools/mesh-tool.cpp
index 0d2aafafc..fbde37856 100644
--- a/src/ui/tools/mesh-tool.cpp
+++ b/src/ui/tools/mesh-tool.cpp
@@ -278,32 +278,39 @@ sp_mesh_context_select_prev (ToolBase *event_context)
}
/**
-Returns true if mouse cursor over mesh edge.
+Returns vector of control lines mouse is over. Returns only first if 'first' is true.
*/
-static bool
-sp_mesh_context_is_over_line (MeshTool *rc, SPCtrlLine *line, Geom::Point event_p)
+static std::vector<SPCtrlLine *>
+sp_mesh_context_over_line (MeshTool *rc, Geom::Point event_p, bool first = true)
{
- if (!SP_IS_CTRLCURVE(line) ) {
- return false;
- }
-
SPDesktop *desktop = SP_EVENT_CONTEXT (rc)->desktop;
//Translate mouse point into proper coord system
rc->mousepoint_doc = desktop->w2d(event_p);
- SPCtrlCurve *curve = SP_CTRLCURVE(line);
- Geom::BezierCurveN<3> b( curve->p0, curve->p1, curve->p2, curve->p3 );
- Geom::Coord coord = b.nearestTime( rc->mousepoint_doc ); // Coord == double
- Geom::Point nearest = b( coord );
+ double tolerance = (double) SP_EVENT_CONTEXT(rc)->tolerance;
- double dist_screen = Geom::L2 (rc->mousepoint_doc - nearest) * desktop->current_zoom();
+ GrDrag *drag = rc->_grdrag;
- double tolerance = (double) SP_EVENT_CONTEXT(rc)->tolerance;
+ std::vector<SPCtrlLine *> selected;
+
+ for (std::vector<SPCtrlLine *>::const_iterator l = drag->lines.begin(); l != drag->lines.end(); ++l) {
+ if (!SP_IS_CTRLCURVE(*l)) continue;
- bool close = (dist_screen < tolerance);
+ SPCtrlCurve *curve = SP_CTRLCURVE(*l);
+ Geom::BezierCurveN<3> b( curve->p0, curve->p1, curve->p2, curve->p3 );
+ Geom::Coord coord = b.nearestTime( rc->mousepoint_doc ); // Coord == double
+ Geom::Point nearest = b( coord );
- return close;
+ double dist_screen = Geom::L2 (rc->mousepoint_doc - nearest) * desktop->current_zoom();
+ if (dist_screen < tolerance) {
+ selected.push_back(*l);
+ if (first) {
+ break;
+ }
+ }
+ }
+ return selected;
}
@@ -539,25 +546,42 @@ bool MeshTool::root_handler(GdkEvent* event) {
// Double click:
// If over a mesh line, divide mesh row/column
- // If not over a line, create new gradients for selected objects.
+ // If not over a line and no mesh, create new mesh for top selected object.
if ( event->button.button == 1 ) {
- // Are we over a mesh line?
- bool over_line = false;
- if (! drag->lines.empty()) {
- for (std::vector<SPCtrlLine *>::const_iterator l = drag->lines.begin(); l != drag->lines.end() && (!over_line); ++l) {
- over_line |= sp_mesh_context_is_over_line (this, *l, Geom::Point(event->motion.x, event->motion.y));
- }
- }
+ // Are we over a mesh line?
+ std::vector<SPCtrlLine *> over_line =
+ sp_mesh_context_over_line(this, Geom::Point(event->motion.x, event->motion.y));
- if (over_line) {
+ if (!over_line.empty()) {
// We take the first item in selection, because with doubleclick, the first click
// always resets selection to the single object under cursor
sp_mesh_context_split_near_point(this, selection->items().front(), this->mousepoint_doc, event->button.time);
} else {
// Create a new gradient with default coordinates.
- sp_mesh_new_default(*this);
+
+ // Check if object already has mesh... if it does,
+ // don't create new mesh with click-drag.
+ bool has_mesh = false;
+ if (!selection->isEmpty()) {
+ SPStyle *style = selection->items().front()->style;
+ if (style) {
+ Inkscape::PaintTarget fill_or_stroke =
+ (prefs->getInt("/tools/gradient/newfillorstroke", 1) != 0) ?
+ Inkscape::FOR_FILL : Inkscape::FOR_STROKE;
+ SPPaintServer *server =
+ (fill_or_stroke == Inkscape::FOR_FILL) ?
+ style->getFillPaintServer():
+ style->getStrokePaintServer();
+ if (server && SP_IS_MESHGRADIENT(server))
+ has_mesh = true;
+ }
+ }
+
+ if (!has_mesh) {
+ sp_mesh_new_default(*this);
+ }
}
ret = TRUE;
@@ -569,9 +593,10 @@ bool MeshTool::root_handler(GdkEvent* event) {
#ifdef DEBUG_MESH
std::cout << "sp_mesh_context_root_handler: GDK_BUTTON_PRESS" << std::endl;
#endif
+
// Button down
- // If Shift key down: do rubber band selection
- // Else set origin for drag. A drag creates a new gradient if one does not exist
+ // If mesh already exists, do rubber band selection.
+ // Else set origin for drag which will create a new gradient.
if ( event->button.button == 1 && !this->space_panning ) {
Geom::Point button_w(event->button.x, event->button.y);
@@ -582,7 +607,9 @@ bool MeshTool::root_handler(GdkEvent* event) {
dragging = true;
- // Check if object already has mesh... if it does, don't create new mesh with click-drag.
+ Geom::Point button_dt = desktop->w2d(button_w);
+ // Check if object already has mesh... if it does,
+ // don't create new mesh with click-drag.
bool has_mesh = false;
if (!selection->isEmpty()) {
SPStyle *style = selection->items().front()->style;
@@ -599,26 +626,25 @@ bool MeshTool::root_handler(GdkEvent* event) {
}
}
- Geom::Point button_dt = desktop->w2d(button_w);
- if (event->button.state & GDK_SHIFT_MASK || has_mesh) {
+ if (has_mesh) {
Inkscape::Rubberband::get(desktop)->start(desktop, button_dt);
- } else {
- // remember clicked item, disregarding groups, honoring Alt; do nothing with Crtl to
- // enable Ctrl+doubleclick of exactly the selected item(s)
- if (!(event->button.state & GDK_CONTROL_MASK)) {
- this->item_to_select = sp_event_context_find_item (desktop, button_w, event->button.state & GDK_MOD1_MASK, TRUE);
- }
+ }
- if (!selection->isEmpty()) {
- SnapManager &m = desktop->namedview->snap_manager;
- m.setup(desktop);
- m.freeSnapReturnByRef(button_dt, Inkscape::SNAPSOURCE_NODE_HANDLE);
- m.unSetup();
- }
+ // remember clicked item, disregarding groups, honoring Alt; do nothing with Crtl to
+ // enable Ctrl+doubleclick of exactly the selected item(s)
+ if (!(event->button.state & GDK_CONTROL_MASK)) {
+ this->item_to_select = sp_event_context_find_item (desktop, button_w, event->button.state & GDK_MOD1_MASK, TRUE);
+ }
- this->origin = button_dt;
+ if (!selection->isEmpty()) {
+ SnapManager &m = desktop->namedview->snap_manager;
+ m.setup(desktop);
+ m.freeSnapReturnByRef(button_dt, Inkscape::SNAPSOURCE_NODE_HANDLE);
+ m.unSetup();
}
+ this->origin = button_dt;
+
ret = TRUE;
}
break;
@@ -679,19 +705,14 @@ bool MeshTool::root_handler(GdkEvent* event) {
}
// Change cursor shape if over line
- bool over_line = false;
+ std::vector<SPCtrlLine *> over_line =
+ sp_mesh_context_over_line(this, Geom::Point(event->motion.x, event->motion.y));
- if (!drag->lines.empty()) {
- for (std::vector<SPCtrlLine *>::const_iterator l = drag->lines.begin(); l != drag->lines.end() ; ++l) {
- over_line |= sp_mesh_context_is_over_line (this, *l, Geom::Point(event->motion.x, event->motion.y));
- }
- }
-
- if (this->cursor_addnode && !over_line) {
+ if (this->cursor_addnode && over_line.empty()) {
this->cursor_shape = cursor_gradient_xpm;
this->sp_event_context_update_cursor();
this->cursor_addnode = false;
- } else if (!this->cursor_addnode && over_line) {
+ } else if (!this->cursor_addnode && !over_line.empty()) {
this->cursor_shape = cursor_gradient_add_xpm;
this->sp_event_context_update_cursor();
this->cursor_addnode = true;
@@ -708,23 +729,15 @@ bool MeshTool::root_handler(GdkEvent* event) {
this->xp = this->yp = 0;
if ( event->button.button == 1 && !this->space_panning ) {
- // Check if over line
- bool over_line = false;
- SPCtrlLine *line = NULL;
-
- if (!drag->lines.empty()) {
- for (std::vector<SPCtrlLine *>::const_iterator l = drag->lines.begin(); l != drag->lines.end() && (!over_line); ++l) {
- over_line = sp_mesh_context_is_over_line (this, *l, Geom::Point(event->motion.x, event->motion.y));
- if (over_line) {
- break;
- }
- }
- }
+ // Check if over line
+ std::vector<SPCtrlLine *> over_line =
+ sp_mesh_context_over_line(this, Geom::Point(event->motion.x, event->motion.y));
if ( (event->button.state & GDK_CONTROL_MASK) && (event->button.state & GDK_MOD1_MASK ) ) {
- if (over_line && line) {
- sp_mesh_context_split_near_point(this, line->item, this->mousepoint_doc, 0);
+ if (!over_line.empty()) {
+ sp_mesh_context_split_near_point(this, over_line[0]->item,
+ this->mousepoint_doc, 0);
ret = TRUE;
}
} else {
@@ -737,22 +750,47 @@ bool MeshTool::root_handler(GdkEvent* event) {
}
if (!this->within_tolerance) {
- // we've been dragging, either create a new gradient
- // or rubberband-select if we have rubberband
- Inkscape::Rubberband *r = Inkscape::Rubberband::get(desktop);
-
- if (r->is_started() && !this->within_tolerance) {
- // this was a rubberband drag
- if (r->getMode() == RUBBERBAND_MODE_RECT) {
- Geom::OptRect const b = r->getRectangle();
- drag->selectRect(*b);
+
+ // Check if object already has mesh... if it does,
+ // don't create new mesh with click-drag.
+ bool has_mesh = false;
+ if (!selection->isEmpty()) {
+ SPStyle *style = selection->items().front()->style;
+ if (style) {
+ Inkscape::PaintTarget fill_or_stroke =
+ (prefs->getInt("/tools/gradient/newfillorstroke", 1) != 0) ?
+ Inkscape::FOR_FILL : Inkscape::FOR_STROKE;
+ SPPaintServer *server =
+ (fill_or_stroke == Inkscape::FOR_FILL) ?
+ style->getFillPaintServer():
+ style->getStrokePaintServer();
+ if (server && SP_IS_MESHGRADIENT(server))
+ has_mesh = true;
}
- } else {
- // Create a new mesh gradient
+ }
+
+ if (!has_mesh) {
sp_mesh_new_default(*this);
+ } else {
+
+ // we've been dragging, either create a new gradient
+ // or rubberband-select if we have rubberband
+ Inkscape::Rubberband *r = Inkscape::Rubberband::get(desktop);
+
+ if (r->is_started() && !this->within_tolerance) {
+ // this was a rubberband drag
+ if (r->getMode() == RUBBERBAND_MODE_RECT) {
+ Geom::OptRect const b = r->getRectangle();
+ if (!(event->button.state & GDK_SHIFT_MASK)) {
+ drag->deselectAll();
+ }
+ drag->selectRect(*b);
+ }
+ }
}
+
} else if (this->item_to_select) {
- if (over_line && line) {
+ if (!over_line.empty()) {
// Clicked on an existing mesh line, don't change selection. This stops
// possible change in selection during a double click with overlapping objects
} else {
@@ -760,6 +798,7 @@ bool MeshTool::root_handler(GdkEvent* event) {
if (event->button.state & GDK_SHIFT_MASK) {
selection->toggle(this->item_to_select);
} else {
+ drag->deselectAll();
selection->set(this->item_to_select);
}
}
@@ -1081,7 +1120,6 @@ static void sp_mesh_new_default(MeshTool &rc) {
}
}
-
}
}
}