From: Diederik van Lierop Date: Sat, 30 Jan 2010 22:04:33 +0000 (+0100) Subject: Finally introducing the pre-snap indicator X-Git-Url: https://git.tokkee.org/?p=inkscape.git;a=commitdiff_plain;h=b26887f4a85399d9d5598b8523d56da89dc385fd Finally introducing the pre-snap indicator --- diff --git a/src/arc-context.cpp b/src/arc-context.cpp index 9cb6e8222..ccaaedd14 100644 --- a/src/arc-context.cpp +++ b/src/arc-context.cpp @@ -116,15 +116,15 @@ static void sp_arc_context_init(SPArcContext *arc_context) static void sp_arc_context_finish(SPEventContext *ec) { SPArcContext *ac = SP_ARC_CONTEXT(ec); - SPDesktop *desktop = ec->desktop; + SPDesktop *desktop = ec->desktop; - sp_canvas_item_ungrab(SP_CANVAS_ITEM(desktop->acetate), GDK_CURRENT_TIME); - sp_arc_finish(ac); + sp_canvas_item_ungrab(SP_CANVAS_ITEM(desktop->acetate), GDK_CURRENT_TIME); + sp_arc_finish(ac); ac->sel_changed_connection.disconnect(); if (((SPEventContextClass *) parent_class)->finish) { - ((SPEventContextClass *) parent_class)->finish(ec); - } + ((SPEventContextClass *) parent_class)->finish(ec); + } } static void sp_arc_context_dispose(GObject *object) @@ -274,6 +274,13 @@ static gint sp_arc_context_root_handler(SPEventContext *event_context, GdkEvent gobble_motion_events(GDK_BUTTON1_MASK); ret = TRUE; + } else if (sp_event_context_knot_mouseover(ac)){ + SnapManager &m = desktop->namedview->snap_manager; + m.setup(desktop); + + Geom::Point const motion_w(event->motion.x, event->motion.y); + Geom::Point motion_dt(desktop->w2d(motion_w)); + m.preSnap(Inkscape::SnapCandidatePoint(motion_dt, Inkscape::SNAPSOURCE_NODE_HANDLE)); } break; case GDK_BUTTON_RELEASE: @@ -283,7 +290,7 @@ static gint sp_arc_context_root_handler(SPEventContext *event_context, GdkEvent sp_event_context_discard_delayed_snap_event(event_context); if (!event_context->within_tolerance) { // we've been dragging, finish the arc - sp_arc_finish(ac); + sp_arc_finish(ac); } else if (event_context->item_to_select) { // no dragging, select clicked item if any if (event->button.state & GDK_SHIFT_MASK) { @@ -335,14 +342,14 @@ static gint sp_arc_context_root_handler(SPEventContext *event_context, GdkEvent } break; case GDK_Escape: - if (dragging) { - dragging = false; - sp_event_context_discard_delayed_snap_event(event_context); - // if drawing, cancel, otherwise pass it up for deselecting - sp_arc_cancel(ac); - ret = TRUE; - } - break; + if (dragging) { + dragging = false; + sp_event_context_discard_delayed_snap_event(event_context); + // if drawing, cancel, otherwise pass it up for deselecting + sp_arc_cancel(ac); + ret = TRUE; + } + break; case GDK_space: if (dragging) { sp_canvas_item_ungrab(SP_CANVAS_ITEM(desktop->acetate), @@ -480,13 +487,13 @@ static void sp_arc_finish(SPArcContext *ac) if (ac->item != NULL) { - SPGenericEllipse *ge = SP_GENERICELLIPSE(SP_ARC(ac->item)); - if (ge->rx.computed == 0 || ge->ry.computed == 0) { - sp_arc_cancel(ac); // Don't allow the creating of zero sized arc, for example when the start and and point snap to the snap grid point - return; - } + SPGenericEllipse *ge = SP_GENERICELLIPSE(SP_ARC(ac->item)); + if (ge->rx.computed == 0 || ge->ry.computed == 0) { + sp_arc_cancel(ac); // Don't allow the creating of zero sized arc, for example when the start and and point snap to the snap grid point + return; + } - SPDesktop *desktop = SP_EVENT_CONTEXT(ac)->desktop; + SPDesktop *desktop = SP_EVENT_CONTEXT(ac)->desktop; SP_OBJECT(ac->item)->updateRepr(); @@ -502,14 +509,14 @@ static void sp_arc_finish(SPArcContext *ac) static void sp_arc_cancel(SPArcContext *ac) { - SPDesktop *desktop = SP_EVENT_CONTEXT(ac)->desktop; + SPDesktop *desktop = SP_EVENT_CONTEXT(ac)->desktop; - sp_desktop_selection(desktop)->clear(); - sp_canvas_item_ungrab(SP_CANVAS_ITEM(desktop->acetate), 0); + sp_desktop_selection(desktop)->clear(); + sp_canvas_item_ungrab(SP_CANVAS_ITEM(desktop->acetate), 0); if (ac->item != NULL) { - SP_OBJECT(ac->item)->deleteObject(); - ac->item = NULL; + SP_OBJECT(ac->item)->deleteObject(); + ac->item = NULL; } ac->within_tolerance = false; diff --git a/src/box3d-context.cpp b/src/box3d-context.cpp index ad9c51f0f..bf9bd7b6f 100644 --- a/src/box3d-context.cpp +++ b/src/box3d-context.cpp @@ -358,8 +358,8 @@ static gint sp_box3d_context_root_handler(SPEventContext *event_context, GdkEven } if (!bc->extruded) { - bc->drag_ptB = from_2geom(motion_dt); - bc->drag_ptC = from_2geom(motion_dt); + bc->drag_ptB = from_2geom(motion_dt); + bc->drag_ptC = from_2geom(motion_dt); bc->drag_ptB_proj = cur_persp->perspective_impl->tmat.preimage (from_2geom(motion_dt), 0, Proj::Z); bc->drag_ptC_proj = bc->drag_ptB_proj; @@ -387,6 +387,13 @@ static gint sp_box3d_context_root_handler(SPEventContext *event_context, GdkEven sp_box3d_drag(*bc, event->motion.state); ret = TRUE; + } else if (sp_event_context_knot_mouseover(bc)) { + SnapManager &m = desktop->namedview->snap_manager; + m.setup(desktop); + + Geom::Point const motion_w(event->motion.x, event->motion.y); + Geom::Point motion_dt(desktop->w2d(motion_w)); + m.preSnap(Inkscape::SnapCandidatePoint(motion_dt, Inkscape::SNAPSOURCE_NODE_HANDLE)); } break; case GDK_BUTTON_RELEASE: diff --git a/src/connector-context.cpp b/src/connector-context.cpp index bfdef1032..294e129b3 100644 --- a/src/connector-context.cpp +++ b/src/connector-context.cpp @@ -976,6 +976,9 @@ connector_handle_motion_notify(SPConnectorContext *const cc, GdkEventMotion cons /* This is perfectly valid */ break; default: + if (sp_event_context_knot_mouseover(cc)) { + m.preSnap(Inkscape::SnapCandidatePoint(p, Inkscape::SNAPSOURCE_OTHER_HANDLE)); + } break; } } diff --git a/src/display/snap-indicator.cpp b/src/display/snap-indicator.cpp index dd80524f1..b135dd9fe 100644 --- a/src/display/snap-indicator.cpp +++ b/src/display/snap-indicator.cpp @@ -43,7 +43,7 @@ SnapIndicator::~SnapIndicator() } void -SnapIndicator::set_new_snaptarget(Inkscape::SnappedPoint const &p) +SnapIndicator::set_new_snaptarget(Inkscape::SnappedPoint const &p, bool pre_snap) { remove_snaptarget(); //only display one snaptarget at a time @@ -220,7 +220,7 @@ SnapIndicator::set_new_snaptarget(Inkscape::SnappedPoint const &p) "anchor", GTK_ANCHOR_CENTER, "size", 10.0, "stroked", TRUE, - "stroke_color", 0xff0000ff, + "stroke_color", pre_snap ? 0x7f7f7fff : 0xff0000ff, "mode", SP_KNOT_MODE_XOR, "shape", SP_KNOT_SHAPE_DIAMOND, NULL ); @@ -230,7 +230,7 @@ SnapIndicator::set_new_snaptarget(Inkscape::SnappedPoint const &p) "anchor", GTK_ANCHOR_CENTER, "size", 10.0, "stroked", TRUE, - "stroke_color", 0xff0000ff, + "stroke_color", pre_snap ? 0x7f7f7fff : 0xff0000ff, "mode", SP_KNOT_MODE_XOR, "shape", SP_KNOT_SHAPE_CROSS, NULL ); @@ -241,15 +241,20 @@ SnapIndicator::set_new_snaptarget(Inkscape::SnappedPoint const &p) SP_CTRL(canvasitem)->moveto(p.getPoint()); _snaptarget = _desktop->add_temporary_canvasitem(canvasitem, timeout_val); + // Display the tooltip, which reveals the type of snap source and the type of snap target gchar *tooltip_str = g_strconcat(source_name, _(" to "), target_name, NULL); Geom::Point tooltip_pos = p.getPoint() + _desktop->w2d(Geom::Point(15, -15)); SPCanvasItem *canvas_tooltip = sp_canvastext_new(sp_desktop_tempgroup(_desktop), _desktop, tooltip_pos, tooltip_str); + if (pre_snap) { + SP_CANVASTEXT(canvas_tooltip)->rgba = 0x7f7f7fff; + } g_free(tooltip_str); sp_canvastext_set_anchor((SPCanvasText* )canvas_tooltip, -1, 1); _snaptarget_tooltip = _desktop->add_temporary_canvasitem(canvas_tooltip, timeout_val); + // Display the bounding box, if we snapped to one Geom::OptRect const bbox = p.getTargetBBox(); if (bbox) { SPCanvasItem* box = sp_canvas_item_new(sp_desktop_tempgroup (_desktop), @@ -257,7 +262,7 @@ SnapIndicator::set_new_snaptarget(Inkscape::SnappedPoint const &p) NULL); SP_CTRLRECT(box)->setRectangle(*bbox); - SP_CTRLRECT(box)->setColor(0xff0000ff, 0, 0); + SP_CTRLRECT(box)->setColor(pre_snap ? 0x7f7f7fff : 0xff0000ff, 0, 0); SP_CTRLRECT(box)->setDashed(true); sp_canvas_item_move_to_z(box, 0); _snaptarget_bbox = _desktop->add_temporary_canvasitem(box, timeout_val); diff --git a/src/display/snap-indicator.h b/src/display/snap-indicator.h index feb118baa..259af8ae6 100644 --- a/src/display/snap-indicator.h +++ b/src/display/snap-indicator.h @@ -26,7 +26,7 @@ public: SnapIndicator(SPDesktop *desktop); virtual ~SnapIndicator(); - void set_new_snaptarget(Inkscape::SnappedPoint const &p); + void set_new_snaptarget(Inkscape::SnappedPoint const &p, bool pre_snap = false); void remove_snaptarget(); void set_new_snapsource(Inkscape::SnapCandidatePoint const &p); diff --git a/src/event-context.cpp b/src/event-context.cpp index 5592741d9..1e47b9d9d 100644 --- a/src/event-context.cpp +++ b/src/event-context.cpp @@ -58,6 +58,7 @@ #include "selcue.h" #include "lpe-tool-context.h" #include "ui/tool/control-point.h" +#include "shape-editor.h" static void sp_event_context_class_init(SPEventContextClass *klass); static void sp_event_context_init(SPEventContext *event_context); @@ -743,6 +744,15 @@ gint sp_event_context_private_item_handler(SPEventContext *ec, SPItem *item, return ret; } +bool sp_event_context_knot_mouseover(SPEventContext *ec) +{ + if (ec->shape_editor) { + return !(ec->shape_editor->knot_mouseover()); + } + + return false; +} + /** * @brief An observer that relays pref changes to the derived classes */ diff --git a/src/event-context.h b/src/event-context.h index 97abee0d5..be06f0a34 100644 --- a/src/event-context.h +++ b/src/event-context.h @@ -171,6 +171,7 @@ SPItem *sp_event_context_find_item (SPDesktop *desktop, Geom::Point const &p, bo SPItem *sp_event_context_over_item (SPDesktop *desktop, SPItem *item, Geom::Point const &p); ShapeEditor *sp_event_context_get_shape_editor (SPEventContext *ec); +bool sp_event_context_knot_mouseover(SPEventContext *ec); void ec_shape_event_attr_changed(Inkscape::XML::Node *shape_repr, gchar const *name, gchar const *old_value, gchar const *new_value, diff --git a/src/gradient-context.cpp b/src/gradient-context.cpp index a1fcf582b..b73d258fd 100644 --- a/src/gradient-context.cpp +++ b/src/gradient-context.cpp @@ -593,6 +593,15 @@ sp_gradient_context_root_handler(SPEventContext *event_context, GdkEvent *event) ret = TRUE; } else { + if (sp_event_context_knot_mouseover(event_context)) { + SnapManager &m = desktop->namedview->snap_manager; + m.setup(desktop); + + Geom::Point const motion_w(event->motion.x, event->motion.y); + Geom::Point const motion_dt = event_context->desktop->w2d(motion_w); + m.preSnap(Inkscape::SnapCandidatePoint(motion_dt, Inkscape::SNAPSOURCE_NODE_HANDLE)); + } + bool over_line = false; if (drag->lines) { for (GSList *l = drag->lines; l != NULL; l = l->next) { diff --git a/src/knot.cpp b/src/knot.cpp index b17e41b24..cc26653e5 100644 --- a/src/knot.cpp +++ b/src/knot.cpp @@ -284,7 +284,7 @@ void sp_knot_start_dragging(SPKnot *knot, Geom::Point const &p, gint x, gint y, */ static int sp_knot_handler(SPCanvasItem */*item*/, GdkEvent *event, SPKnot *knot) { - g_assert(knot != NULL); + g_assert(knot != NULL); g_assert(SP_IS_KNOT(knot)); /* Run client universal event handler, if present */ @@ -302,7 +302,7 @@ static int sp_knot_handler(SPCanvasItem */*item*/, GdkEvent *event, SPKnot *knot tolerance = prefs->getIntLimited("/options/dragtolerance/value", 0, 0, 100); switch (event->type) { - case GDK_2BUTTON_PRESS: + case GDK_2BUTTON_PRESS: if (event->button.button == 1) { g_signal_emit(knot, knot_signals[DOUBLECLICKED], 0, event->button.state); @@ -311,23 +311,23 @@ static int sp_knot_handler(SPCanvasItem */*item*/, GdkEvent *event, SPKnot *knot consumed = TRUE; } break; - case GDK_BUTTON_PRESS: + case GDK_BUTTON_PRESS: if (event->button.button == 1 && !knot->desktop->event_context->space_panning) { Geom::Point const p = knot->desktop->w2d(Geom::Point(event->button.x, event->button.y)); sp_knot_start_dragging(knot, p, (gint) event->button.x, (gint) event->button.y, event->button.time); - consumed = TRUE; + consumed = TRUE; } break; - case GDK_BUTTON_RELEASE: - if (event->button.button == 1 && !knot->desktop->event_context->space_panning) { - // If we have any pending snap event, then invoke it now - if (knot->desktop->event_context->_delayed_snap_event) { - sp_event_context_snap_watchdog_callback(knot->desktop->event_context->_delayed_snap_event); - } + case GDK_BUTTON_RELEASE: + if (event->button.button == 1 && !knot->desktop->event_context->space_panning) { + // If we have any pending snap event, then invoke it now + if (knot->desktop->event_context->_delayed_snap_event) { + sp_event_context_snap_watchdog_callback(knot->desktop->event_context->_delayed_snap_event); + } - sp_event_context_discard_delayed_snap_event(knot->desktop->event_context); + sp_event_context_discard_delayed_snap_event(knot->desktop->event_context); - knot->pressure = 0; + knot->pressure = 0; if (transform_escaped) { transform_escaped = false; consumed = TRUE; @@ -356,7 +356,7 @@ static int sp_knot_handler(SPCanvasItem */*item*/, GdkEvent *event, SPKnot *knot } } break; - case GDK_MOTION_NOTIFY: + case GDK_MOTION_NOTIFY: if (grabbed && !knot->desktop->event_context->space_panning) { consumed = TRUE; @@ -389,7 +389,7 @@ static int sp_knot_handler(SPCanvasItem */*item*/, GdkEvent *event, SPKnot *knot moved = TRUE; } break; - case GDK_ENTER_NOTIFY: + case GDK_ENTER_NOTIFY: sp_knot_set_flag(knot, SP_KNOT_MOUSEOVER, TRUE); sp_knot_set_flag(knot, SP_KNOT_GRABBED, FALSE); @@ -401,7 +401,7 @@ static int sp_knot_handler(SPCanvasItem */*item*/, GdkEvent *event, SPKnot *knot moved = FALSE; consumed = TRUE; break; - case GDK_LEAVE_NOTIFY: + case GDK_LEAVE_NOTIFY: sp_knot_set_flag(knot, SP_KNOT_MOUSEOVER, FALSE); sp_knot_set_flag(knot, SP_KNOT_GRABBED, FALSE); @@ -413,35 +413,35 @@ static int sp_knot_handler(SPCanvasItem */*item*/, GdkEvent *event, SPKnot *knot moved = FALSE; consumed = TRUE; break; - case GDK_KEY_PRESS: // keybindings for knot + case GDK_KEY_PRESS: // keybindings for knot switch (get_group0_keyval(&event->key)) { - case GDK_Escape: - sp_knot_set_flag(knot, SP_KNOT_GRABBED, FALSE); - if (!nograb) { - sp_canvas_item_ungrab(knot->item, event->button.time); - } - if (moved) { - sp_knot_set_flag(knot, - SP_KNOT_DRAGGING, - FALSE); - g_signal_emit(knot, - knot_signals[UNGRABBED], 0, - event->button.state); - sp_document_undo(sp_desktop_document(knot->desktop)); - knot->desktop->messageStack()->flash(Inkscape::NORMAL_MESSAGE, _("Node or handle drag canceled.")); - transform_escaped = true; - consumed = TRUE; - } - grabbed = FALSE; - moved = FALSE; - sp_event_context_discard_delayed_snap_event(knot->desktop->event_context); - break; - default: - consumed = FALSE; - break; - } - break; - default: + case GDK_Escape: + sp_knot_set_flag(knot, SP_KNOT_GRABBED, FALSE); + if (!nograb) { + sp_canvas_item_ungrab(knot->item, event->button.time); + } + if (moved) { + sp_knot_set_flag(knot, + SP_KNOT_DRAGGING, + FALSE); + g_signal_emit(knot, + knot_signals[UNGRABBED], 0, + event->button.state); + sp_document_undo(sp_desktop_document(knot->desktop)); + knot->desktop->messageStack()->flash(Inkscape::NORMAL_MESSAGE, _("Node or handle drag canceled.")); + transform_escaped = true; + consumed = TRUE; + } + grabbed = FALSE; + moved = FALSE; + sp_event_context_discard_delayed_snap_event(knot->desktop->event_context); + break; + default: + consumed = FALSE; + break; + } + break; + default: break; } @@ -452,14 +452,14 @@ static int sp_knot_handler(SPCanvasItem */*item*/, GdkEvent *event, SPKnot *knot void sp_knot_handler_request_position(GdkEvent *event, SPKnot *knot) { - Geom::Point const motion_w(event->motion.x, event->motion.y); - Geom::Point const motion_dt = knot->desktop->w2d(motion_w); - Geom::Point p = motion_dt - knot->grabbed_rel_pos; - sp_knot_request_position (knot, p, event->motion.state); - knot->desktop->scroll_to_point (motion_dt); - knot->desktop->set_coordinate_status(knot->pos); // display the coordinate of knot, not cursor - they may be different! - if (event->motion.state & GDK_BUTTON1_MASK) - gobble_motion_events(GDK_BUTTON1_MASK); + Geom::Point const motion_w(event->motion.x, event->motion.y); + Geom::Point const motion_dt = knot->desktop->w2d(motion_w); + Geom::Point p = motion_dt - knot->grabbed_rel_pos; + sp_knot_request_position (knot, p, event->motion.state); + knot->desktop->scroll_to_point (motion_dt); + knot->desktop->set_coordinate_status(knot->pos); // display the coordinate of knot, not cursor - they may be different! + if (event->motion.state & GDK_BUTTON1_MASK) + gobble_motion_events(GDK_BUTTON1_MASK); } /** @@ -620,20 +620,20 @@ void sp_knot_set_flag(SPKnot *knot, guint flag, bool set) } switch (flag) { - case SP_KNOT_VISIBLE: + case SP_KNOT_VISIBLE: if (set) { sp_canvas_item_show(knot->item); } else { sp_canvas_item_hide(knot->item); } break; - case SP_KNOT_MOUSEOVER: - case SP_KNOT_DRAGGING: + case SP_KNOT_MOUSEOVER: + case SP_KNOT_DRAGGING: sp_knot_set_ctrl_state(knot); break; - case SP_KNOT_GRABBED: + case SP_KNOT_GRABBED: break; - default: + default: g_assert_not_reached(); break; } diff --git a/src/knotholder.cpp b/src/knotholder.cpp index 45cb140c0..314ad807c 100644 --- a/src/knotholder.cpp +++ b/src/knotholder.cpp @@ -91,6 +91,21 @@ KnotHolder::update_knots() } } +/** + * \brief Returns true if at least one of the KnotHolderEntities has the mouse hovering above it + */ +bool KnotHolder::knot_mouseover() +{ + for(std::list::iterator i = entity.begin(); i != entity.end(); ++i) { + SPKnot *knot = (*i)->knot; + if (knot && (knot->flags & SP_KNOT_MOUSEOVER)) { + return true; + } + } + + return false; +} + void KnotHolder::knot_clicked_handler(SPKnot *knot, guint state) { diff --git a/src/knotholder.h b/src/knotholder.h index fa1abd071..0b37d211c 100644 --- a/src/knotholder.h +++ b/src/knotholder.h @@ -49,6 +49,8 @@ public: const SPItem *getItem() { return item; } + bool knot_mouseover(); + friend class ShapeEditor; protected: diff --git a/src/object-edit.cpp b/src/object-edit.cpp index 6b83413e4..1d81aa7f5 100644 --- a/src/object-edit.cpp +++ b/src/object-edit.cpp @@ -194,7 +194,7 @@ RectKnotHolderEntityRY::knot_set(Geom::Point const &p, Geom::Point const &/*orig Geom::Point const s = snap_knot_position_constrained(p, Inkscape::Snapper::ConstraintLine(Geom::Point(rect->x.computed + rect->width.computed, rect->y.computed), Geom::Point(0, 1))); if (state & GDK_CONTROL_MASK) { // When holding control then rx will be kept equal to ry, - // resulting in a perfect circle (and not an ellipse) + // resulting in a perfect circle (and not an ellipse) gdouble temp = MIN(rect->height.computed, rect->width.computed) / 2.0; rect->rx.computed = rect->ry.computed = CLAMP(s[Geom::Y] - rect->y.computed, 0.0, temp); rect->ry._set = rect->rx._set = true; @@ -277,19 +277,19 @@ RectKnotHolderEntityWH::set_internal(Geom::Point const &p, Geom::Point const &or Geom::Point p_handle(rect->x.computed + rect->width.computed, rect->y.computed + rect->height.computed); if (fabs(minx) > fabs(miny)) { - // snap to horizontal or diagonal + // snap to horizontal or diagonal if (minx != 0 && fabs(miny/minx) > 0.5 * 1/ratio && (SGN(minx) == SGN(miny))) { // closer to the diagonal and in same-sign quarters, change both using ratio - s = snap_knot_position_constrained(p, Inkscape::Snapper::ConstraintLine(p_handle, Geom::Point(-ratio, -1))); - minx = s[Geom::X] - origin[Geom::X]; - miny = s[Geom::Y] - origin[Geom::Y]; - rect->height.computed = MAX(h_orig + minx / ratio, 0); + s = snap_knot_position_constrained(p, Inkscape::Snapper::ConstraintLine(p_handle, Geom::Point(-ratio, -1))); + minx = s[Geom::X] - origin[Geom::X]; + miny = s[Geom::Y] - origin[Geom::Y]; + rect->height.computed = MAX(h_orig + minx / ratio, 0); } else { // closer to the horizontal, change only width, height is h_orig - s = snap_knot_position_constrained(p, Inkscape::Snapper::ConstraintLine(p_handle, Geom::Point(-1, 0))); - minx = s[Geom::X] - origin[Geom::X]; - miny = s[Geom::Y] - origin[Geom::Y]; - rect->height.computed = MAX(h_orig, 0); + s = snap_knot_position_constrained(p, Inkscape::Snapper::ConstraintLine(p_handle, Geom::Point(-1, 0))); + minx = s[Geom::X] - origin[Geom::X]; + miny = s[Geom::Y] - origin[Geom::Y]; + rect->height.computed = MAX(h_orig, 0); } rect->width.computed = MAX(w_orig + minx, 0); @@ -297,16 +297,16 @@ RectKnotHolderEntityWH::set_internal(Geom::Point const &p, Geom::Point const &or // snap to vertical or diagonal if (miny != 0 && fabs(minx/miny) > 0.5 * ratio && (SGN(minx) == SGN(miny))) { // closer to the diagonal and in same-sign quarters, change both using ratio - s = snap_knot_position_constrained(p, Inkscape::Snapper::ConstraintLine(p_handle, Geom::Point(-ratio, -1))); - minx = s[Geom::X] - origin[Geom::X]; - miny = s[Geom::Y] - origin[Geom::Y]; - rect->width.computed = MAX(w_orig + miny * ratio, 0); + s = snap_knot_position_constrained(p, Inkscape::Snapper::ConstraintLine(p_handle, Geom::Point(-ratio, -1))); + minx = s[Geom::X] - origin[Geom::X]; + miny = s[Geom::Y] - origin[Geom::Y]; + rect->width.computed = MAX(w_orig + miny * ratio, 0); } else { // closer to the vertical, change only height, width is w_orig - s = snap_knot_position_constrained(p, Inkscape::Snapper::ConstraintLine(p_handle, Geom::Point(0, -1))); - minx = s[Geom::X] - origin[Geom::X]; - miny = s[Geom::Y] - origin[Geom::Y]; - rect->width.computed = MAX(w_orig, 0); + s = snap_knot_position_constrained(p, Inkscape::Snapper::ConstraintLine(p_handle, Geom::Point(0, -1))); + minx = s[Geom::X] - origin[Geom::X]; + miny = s[Geom::Y] - origin[Geom::Y]; + rect->width.computed = MAX(w_orig, 0); } rect->height.computed = MAX(h_orig + miny, 0); @@ -316,8 +316,8 @@ RectKnotHolderEntityWH::set_internal(Geom::Point const &p, Geom::Point const &or } else { // move freely - s = snap_knot_position(p); - rect->width.computed = MAX(s[Geom::X] - rect->x.computed, 0); + s = snap_knot_position(p); + rect->width.computed = MAX(s[Geom::X] - rect->x.computed, 0); rect->height.computed = MAX(s[Geom::Y] - rect->y.computed, 0); rect->width._set = rect->height._set = true; } @@ -367,54 +367,54 @@ RectKnotHolderEntityXY::knot_set(Geom::Point const &p, Geom::Point const &origin gdouble ratio = (w_orig / h_orig); if (fabs(minx) > fabs(miny)) { - // snap to horizontal or diagonal + // snap to horizontal or diagonal if (minx != 0 && fabs(miny/minx) > 0.5 * 1/ratio && (SGN(minx) == SGN(miny))) { // closer to the diagonal and in same-sign quarters, change both using ratio - s = snap_knot_position_constrained(p, Inkscape::Snapper::ConstraintLine(p_handle, Geom::Point(-ratio, -1))); - minx = s[Geom::X] - origin[Geom::X]; - miny = s[Geom::Y] - origin[Geom::Y]; - rect->y.computed = MIN(origin[Geom::Y] + minx / ratio, opposite_y); + s = snap_knot_position_constrained(p, Inkscape::Snapper::ConstraintLine(p_handle, Geom::Point(-ratio, -1))); + minx = s[Geom::X] - origin[Geom::X]; + miny = s[Geom::Y] - origin[Geom::Y]; + rect->y.computed = MIN(origin[Geom::Y] + minx / ratio, opposite_y); rect->height.computed = MAX(h_orig - minx / ratio, 0); } else { // closer to the horizontal, change only width, height is h_orig - s = snap_knot_position_constrained(p, Inkscape::Snapper::ConstraintLine(p_handle, Geom::Point(-1, 0))); - minx = s[Geom::X] - origin[Geom::X]; - miny = s[Geom::Y] - origin[Geom::Y]; - rect->y.computed = MIN(origin[Geom::Y], opposite_y); + s = snap_knot_position_constrained(p, Inkscape::Snapper::ConstraintLine(p_handle, Geom::Point(-1, 0))); + minx = s[Geom::X] - origin[Geom::X]; + miny = s[Geom::Y] - origin[Geom::Y]; + rect->y.computed = MIN(origin[Geom::Y], opposite_y); rect->height.computed = MAX(h_orig, 0); } rect->x.computed = MIN(s[Geom::X], opposite_x); rect->width.computed = MAX(w_orig - minx, 0); } else { // snap to vertical or diagonal - if (miny != 0 && fabs(minx/miny) > 0.5 *ratio && (SGN(minx) == SGN(miny))) { + if (miny != 0 && fabs(minx/miny) > 0.5 *ratio && (SGN(minx) == SGN(miny))) { // closer to the diagonal and in same-sign quarters, change both using ratio - s = snap_knot_position_constrained(p, Inkscape::Snapper::ConstraintLine(p_handle, Geom::Point(-ratio, -1))); - minx = s[Geom::X] - origin[Geom::X]; - miny = s[Geom::Y] - origin[Geom::Y]; - rect->x.computed = MIN(origin[Geom::X] + miny * ratio, opposite_x); + s = snap_knot_position_constrained(p, Inkscape::Snapper::ConstraintLine(p_handle, Geom::Point(-ratio, -1))); + minx = s[Geom::X] - origin[Geom::X]; + miny = s[Geom::Y] - origin[Geom::Y]; + rect->x.computed = MIN(origin[Geom::X] + miny * ratio, opposite_x); rect->width.computed = MAX(w_orig - miny * ratio, 0); } else { // closer to the vertical, change only height, width is w_orig - s = snap_knot_position_constrained(p, Inkscape::Snapper::ConstraintLine(p_handle, Geom::Point(0, -1))); - minx = s[Geom::X] - origin[Geom::X]; - miny = s[Geom::Y] - origin[Geom::Y]; - rect->x.computed = MIN(origin[Geom::X], opposite_x); + s = snap_knot_position_constrained(p, Inkscape::Snapper::ConstraintLine(p_handle, Geom::Point(0, -1))); + minx = s[Geom::X] - origin[Geom::X]; + miny = s[Geom::Y] - origin[Geom::Y]; + rect->x.computed = MIN(origin[Geom::X], opposite_x); rect->width.computed = MAX(w_orig, 0); } rect->y.computed = MIN(s[Geom::Y], opposite_y); - rect->height.computed = MAX(h_orig - miny, 0); + rect->height.computed = MAX(h_orig - miny, 0); } rect->width._set = rect->height._set = rect->x._set = rect->y._set = true; } else { // move freely - s = snap_knot_position(p); - minx = s[Geom::X] - origin[Geom::X]; - miny = s[Geom::Y] - origin[Geom::Y]; + s = snap_knot_position(p); + minx = s[Geom::X] - origin[Geom::X]; + miny = s[Geom::Y] - origin[Geom::Y]; - rect->x.computed = MIN(s[Geom::X], opposite_x); + rect->x.computed = MIN(s[Geom::X], opposite_x); rect->width.computed = MAX(w_orig - minx, 0); rect->y.computed = MIN(s[Geom::Y], opposite_y); rect->height.computed = MAX(h_orig - miny, 0); diff --git a/src/pen-context.cpp b/src/pen-context.cpp index b71bc2e54..9cf4d5420 100644 --- a/src/pen-context.cpp +++ b/src/pen-context.cpp @@ -469,7 +469,7 @@ static gint pen_handle_button_press(SPPenContext *const pc, GdkEventButton const if (pc->npoints == 0) { Geom::Point p; - if ((bevent.state & GDK_CONTROL_MASK) && (pc->polylines_only || pc->polylines_paraxial)) { + if ((bevent.state & GDK_CONTROL_MASK) && (pc->polylines_only || pc->polylines_paraxial)) { p = event_dt; if (!(bevent.state & GDK_SHIFT_MASK)) { SnapManager &m = desktop->namedview->snap_manager; @@ -479,7 +479,7 @@ static gint pen_handle_button_press(SPPenContext *const pc, GdkEventButton const spdc_create_single_dot(event_context, p, "/tools/freehand/pen", bevent.state); ret = TRUE; break; - } + } // TODO: Perhaps it would be nicer to rearrange the following case // distinction so that the case of a waiting LPE is treated separately @@ -632,6 +632,10 @@ pen_handle_motion_notify(SPPenContext *const pc, GdkEventMotion const &mevent) spdc_endpoint_snap(pc, p, mevent.state); spdc_pen_set_subsequent_point(pc, p, true); ret = TRUE; + } else if (sp_event_context_knot_mouseover(pc)) { + SnapManager &m = dt->namedview->snap_manager; + m.setup(dt); + m.preSnap(Inkscape::SnapCandidatePoint(p, Inkscape::SNAPSOURCE_NODE_HANDLE)); } break; case SP_PEN_CONTEXT_CONTROL: @@ -677,6 +681,11 @@ pen_handle_motion_notify(SPPenContext *const pc, GdkEventMotion const &mevent) pc->_message_context->clear(); pc->anchor_statusbar = false; } + if (sp_event_context_knot_mouseover(pc)) { + SnapManager &m = dt->namedview->snap_manager; + m.setup(dt); + m.preSnap(Inkscape::SnapCandidatePoint(p, Inkscape::SNAPSOURCE_NODE_HANDLE)); + } } break; case SP_PEN_CONTEXT_CONTROL: @@ -698,6 +707,11 @@ pen_handle_motion_notify(SPPenContext *const pc, GdkEventMotion const &mevent) /* This is perfectly valid */ break; default: + if (sp_event_context_knot_mouseover(pc)) { + SnapManager &m = dt->namedview->snap_manager; + m.setup(dt); + m.preSnap(Inkscape::SnapCandidatePoint(p, Inkscape::SNAPSOURCE_NODE_HANDLE)); + } break; } break; diff --git a/src/pencil-context.cpp b/src/pencil-context.cpp index acdd4d6e5..5aa9efbd9 100644 --- a/src/pencil-context.cpp +++ b/src/pencil-context.cpp @@ -295,7 +295,7 @@ pencil_handle_button_press(SPPencilContext *const pc, GdkEventButton const &beve static gint pencil_handle_motion_notify(SPPencilContext *const pc, GdkEventMotion const &mevent) { - SPDesktop *const dt = pc->desktop; + SPDesktop *const dt = pc->desktop; if ((mevent.state & GDK_CONTROL_MASK) && (mevent.state & GDK_BUTTON1_MASK)) { // mouse was accidentally moved during Ctrl+click; @@ -395,6 +395,11 @@ pencil_handle_motion_notify(SPPencilContext *const pc, GdkEventMotion const &mev pc->_message_context->clear(); pc->anchor_statusbar = false; } + if (sp_event_context_knot_mouseover(pc)) { + SnapManager &m = dt->namedview->snap_manager; + m.setup(dt); + m.preSnap(Inkscape::SnapCandidatePoint(p, Inkscape::SNAPSOURCE_NODE_HANDLE)); + } } break; } diff --git a/src/rect-context.cpp b/src/rect-context.cpp index dcc1f0aa1..9eab188dd 100644 --- a/src/rect-context.cpp +++ b/src/rect-context.cpp @@ -317,6 +317,13 @@ static gint sp_rect_context_root_handler(SPEventContext *event_context, GdkEvent sp_rect_drag(*rc, motion_dt, event->motion.state); // this will also handle the snapping gobble_motion_events(GDK_BUTTON1_MASK); ret = TRUE; + } else if (sp_event_context_knot_mouseover(rc)) { + SnapManager &m = desktop->namedview->snap_manager; + m.setup(desktop); + + Geom::Point const motion_w(event->motion.x, event->motion.y); + Geom::Point motion_dt(desktop->w2d(motion_w)); + m.preSnap(Inkscape::SnapCandidatePoint(motion_dt, Inkscape::SNAPSOURCE_NODE_HANDLE)); } break; case GDK_BUTTON_RELEASE: diff --git a/src/shape-editor.cpp b/src/shape-editor.cpp index 7002c9723..e3b6d65c2 100644 --- a/src/shape-editor.cpp +++ b/src/shape-editor.cpp @@ -226,6 +226,16 @@ bool ShapeEditor::has_selection() { return false; // so far, knotholder cannot have selection } +/** + * \brief Returns true if this ShapeEditor has a knot above which the mouse currently hovers + */ +bool ShapeEditor::knot_mouseover() +{ + if (this->knotholder) { + return knotholder->knot_mouseover(); + } +} + /* Local Variables: mode:c++ diff --git a/src/shape-editor.h b/src/shape-editor.h index 2374d6ac6..f400244b3 100644 --- a/src/shape-editor.h +++ b/src/shape-editor.h @@ -62,6 +62,8 @@ public: // this one is only public because it's called from non-C++ repr changed callback void shapeeditor_event_attr_changed(gchar const *name); + bool knot_mouseover(); + private: bool has_knotholder (); void reset_item (SubType type, bool keep_knotholder = true); diff --git a/src/snap.cpp b/src/snap.cpp index 4727c7b3e..9ee575e22 100644 --- a/src/snap.cpp +++ b/src/snap.cpp @@ -214,6 +214,22 @@ Inkscape::SnappedPoint SnapManager::freeSnap(Inkscape::SnapCandidatePoint const return findBestSnap(p, sc, false); } +void SnapManager::preSnap(Inkscape::SnapCandidatePoint const &p) +{ + // setup() must have been called before calling this method! + + if (_snapindicator) { + _snapindicator = false; // prevent other methods from drawing a snap indicator; we want to control this here + Inkscape::SnappedPoint s = freeSnap(p); + if (s.getSnapped()) { + _desktop->snapindicator->set_new_snaptarget(s, true); + } else { + _desktop->snapindicator->remove_snaptarget(); + } + _snapindicator = true; // restore the original value + } +} + /** * \brief Snap to the closest multiple of a grid pitch * diff --git a/src/snap.h b/src/snap.h index 24a60eaf0..613550376 100644 --- a/src/snap.h +++ b/src/snap.h @@ -105,6 +105,8 @@ public: Inkscape::SnappedPoint freeSnap(Inkscape::SnapCandidatePoint const &p, Geom::OptRect const &bbox_to_snap = Geom::OptRect() ) const; + void preSnap(Inkscape::SnapCandidatePoint const &p); + Geom::Point multipleOfGridPitch(Geom::Point const &t) const; // constrainedSnapReturnByRef() is preferred over constrainedSnap(), because it only returns a diff --git a/src/spiral-context.cpp b/src/spiral-context.cpp index d751fae6d..f8a4bddfb 100644 --- a/src/spiral-context.cpp +++ b/src/spiral-context.cpp @@ -277,6 +277,13 @@ sp_spiral_context_root_handler(SPEventContext *event_context, GdkEvent *event) gobble_motion_events(GDK_BUTTON1_MASK); ret = TRUE; + } else if (sp_event_context_knot_mouseover(sc)) { + SnapManager &m = desktop->namedview->snap_manager; + m.setup(desktop); + + Geom::Point const motion_w(event->motion.x, event->motion.y); + Geom::Point motion_dt(desktop->w2d(motion_w)); + m.preSnap(Inkscape::SnapCandidatePoint(motion_dt, Inkscape::SNAPSOURCE_NODE_HANDLE)); } break; case GDK_BUTTON_RELEASE: diff --git a/src/star-context.cpp b/src/star-context.cpp index f67ca434d..693d51888 100644 --- a/src/star-context.cpp +++ b/src/star-context.cpp @@ -291,6 +291,13 @@ static gint sp_star_context_root_handler(SPEventContext *event_context, GdkEvent gobble_motion_events(GDK_BUTTON1_MASK); ret = TRUE; + } else if (sp_event_context_knot_mouseover(event_context)) { + SnapManager &m = desktop->namedview->snap_manager; + m.setup(desktop); + + Geom::Point const motion_w(event->motion.x, event->motion.y); + Geom::Point motion_dt(desktop->w2d(motion_w)); + m.preSnap(Inkscape::SnapCandidatePoint(motion_dt, Inkscape::SNAPSOURCE_NODE_HANDLE)); } break; case GDK_BUTTON_RELEASE: @@ -472,13 +479,13 @@ sp_star_finish (SPStarContext * sc) sc->_message_context->clear(); if (sc->item != NULL) { - SPStar *star = SP_STAR(sc->item); - if (star->r[1] == 0) { - sp_star_cancel(sc); // Don't allow the creating of zero sized arc, for example when the start and and point snap to the snap grid point - return; - } + SPStar *star = SP_STAR(sc->item); + if (star->r[1] == 0) { + sp_star_cancel(sc); // Don't allow the creating of zero sized arc, for example when the start and and point snap to the snap grid point + return; + } - SPDesktop *desktop = SP_EVENT_CONTEXT(sc)->desktop; + SPDesktop *desktop = SP_EVENT_CONTEXT(sc)->desktop; SPObject *object = SP_OBJECT(sc->item); sp_shape_set_shape(SP_SHAPE(sc->item)); @@ -497,14 +504,14 @@ sp_star_finish (SPStarContext * sc) static void sp_star_cancel(SPStarContext *sc) { - SPDesktop *desktop = SP_EVENT_CONTEXT(sc)->desktop; + SPDesktop *desktop = SP_EVENT_CONTEXT(sc)->desktop; - sp_desktop_selection(desktop)->clear(); - sp_canvas_item_ungrab(SP_CANVAS_ITEM(desktop->acetate), 0); + sp_desktop_selection(desktop)->clear(); + sp_canvas_item_ungrab(SP_CANVAS_ITEM(desktop->acetate), 0); if (sc->item != NULL) { - SP_OBJECT(sc->item)->deleteObject(); - sc->item = NULL; + SP_OBJECT(sc->item)->deleteObject(); + sc->item = NULL; } sc->within_tolerance = false; diff --git a/src/star-context.h b/src/star-context.h index 6db29ec42..024bf8d74 100644 --- a/src/star-context.h +++ b/src/star-context.h @@ -28,27 +28,27 @@ class SPStarContext; class SPStarContextClass; struct SPStarContext : public SPEventContext { - SPItem *item; - Geom::Point center; - - /* Number of corners */ - gint magnitude; - /* Outer/inner radius ratio */ - gdouble proportion; - /* flat sides or not? */ - bool isflatsided; - /* rounded corners ratio */ - gdouble rounded; - // randomization - gdouble randomized; + SPItem *item; + Geom::Point center; + + /* Number of corners */ + gint magnitude; + /* Outer/inner radius ratio */ + gdouble proportion; + /* flat sides or not? */ + bool isflatsided; + /* rounded corners ratio */ + gdouble rounded; + // randomization + gdouble randomized; sigc::connection sel_changed_connection; - Inkscape::MessageContext *_message_context; + Inkscape::MessageContext *_message_context; }; struct SPStarContextClass { - SPEventContextClass parent_class; + SPEventContextClass parent_class; }; GtkType sp_star_context_get_type (void);