Code

Filter effects dialog:
[inkscape.git] / src / gradient-context.cpp
index a30d674e62d869ed363bb7080ad5677e4c043416..e9192652a63675b2736a02c1e00c1f6dceb8a36a 100644 (file)
@@ -44,7 +44,8 @@
 #include "sp-stop.h"
 #include "svg/css-ostringstream.h"
 #include "svg/svg-color.h"
-
+#include "snap.h"
+#include "sp-namedview.h"
 
 
 
@@ -103,7 +104,7 @@ static void sp_gradient_context_init(SPGradientContext *gr_context)
     event_context->hot_y = 4;
     event_context->xp = 0;
     event_context->yp = 0;
-    event_context->tolerance = 4;
+    event_context->tolerance = 6;
     event_context->within_tolerance = false;
     event_context->item_to_select = NULL;
 }
@@ -139,7 +140,7 @@ static void sp_gradient_context_setup(SPEventContext *ec)
     rc->_message_context = new Inkscape::MessageContext(sp_desktop_message_stack(ec->desktop));
 }
 
-void 
+void
 sp_gradient_context_select_next (SPEventContext *event_context)
 {
     GrDrag *drag = event_context->_grdrag;
@@ -148,7 +149,7 @@ sp_gradient_context_select_next (SPEventContext *event_context)
     drag->select_next();
 }
 
-void 
+void
 sp_gradient_context_select_prev (SPEventContext *event_context)
 {
     GrDrag *drag = event_context->_grdrag;
@@ -164,10 +165,10 @@ snap_vector_midpoint (NR::Point p, NR::Point begin, NR::Point end)
     double length = NR::L2(end - begin);
     NR::Point be = (end - begin) / length;
     double r = NR::dot(p - begin, be);
-        
+
     if (r < 0.0) return begin;
-    if (r > length) return end;    
-    
+    if (r > length) return end;
+
     return (begin + r * be);
 }
 
@@ -180,13 +181,13 @@ sp_gradient_context_is_over_line (SPGradientContext *rc, SPItem *item, NR::Point
     rc->mousepoint_doc = desktop->w2d(event_p);
 
     SPCtrlLine* line = SP_CTRLLINE(item);
-   
+
     NR::Point nearest = snap_vector_midpoint (rc->mousepoint_doc, line->s, line->e);
-    NR::Point delta = rc->mousepoint_doc - nearest;
+    double dist_screen = NR::L2 (rc->mousepoint_doc - nearest) * desktop->current_zoom();
 
     double tolerance = (double) SP_EVENT_CONTEXT(rc)->tolerance;
 
-    bool close = (NR::L2 (delta) < tolerance);
+    bool close = (dist_screen < tolerance);
 
     return close;
 }
@@ -209,68 +210,70 @@ get_offset_between_points (NR::Point p, NR::Point begin, NR::Point end)
     double length = NR::L2(end - begin);
     NR::Point be = (end - begin) / length;
     double r = NR::dot(p - begin, be);
-        
+
     if (r < 0.0) return 0.0;
-    if (r > length) return 1.0;    
-    
+    if (r > length) return 1.0;
+
     return (r / length);
 }
 
 static void
 sp_gradient_context_add_stop_near_point (SPGradientContext *rc, SPItem *item,  NR::Point mouse_p, guint32 etime)
 {
-    // item is the selected item. mouse_p the location in doc coordinates of where to add the stop    
-    
+    // item is the selected item. mouse_p the location in doc coordinates of where to add the stop
+
     SPEventContext *ec = SP_EVENT_CONTEXT(rc);
+    SPDesktop *desktop = SP_EVENT_CONTEXT (rc)->desktop;
+
     double tolerance = (double) ec->tolerance;
 
     gfloat offset; // type of SPStop.offset = gfloat
-    SPGradient *gradient; 
-    bool fill_or_stroke = true; 
+    SPGradient *gradient;
+    bool fill_or_stroke = true;
     bool r1_knot = false;
-    
+
     bool addknot = false;
     do {
         gradient = sp_item_gradient (item, fill_or_stroke);
         if (SP_IS_LINEARGRADIENT(gradient)) {
             NR::Point begin   = sp_item_gradient_get_coords(item, POINT_LG_BEGIN, 0, fill_or_stroke);
             NR::Point end     = sp_item_gradient_get_coords(item, POINT_LG_END, 0, fill_or_stroke);
-                
+
             NR::Point nearest = snap_vector_midpoint (mouse_p, begin, end);
-            NR::Point delta = mouse_p - nearest;
-            if ( NR::L2 (delta) < tolerance ) {
-                // add the knot 
-                offset = get_offset_between_points(nearest, begin, end); 
-                addknot = true;              
+            double dist_screen = NR::L2 (mouse_p - nearest) * desktop->current_zoom();
+            if ( dist_screen < tolerance ) {
+                // add the knot
+                offset = get_offset_between_points(nearest, begin, end);
+                addknot = true;
                 break; // break out of the while loop: add only one knot
             }
         } else if (SP_IS_RADIALGRADIENT(gradient)) {
             NR::Point begin = sp_item_gradient_get_coords(item, POINT_RG_CENTER, 0, fill_or_stroke);
             NR::Point end   = sp_item_gradient_get_coords(item, POINT_RG_R1, 0, fill_or_stroke);
             NR::Point nearest = snap_vector_midpoint (mouse_p, begin, end);
-            NR::Point delta = mouse_p - nearest;
-            if ( NR::L2 (delta) < tolerance ) {
-                offset = get_offset_between_points(nearest, begin, end); 
+            double dist_screen = NR::L2 (mouse_p - nearest) * desktop->current_zoom();
+            if ( dist_screen < tolerance ) {
+                offset = get_offset_between_points(nearest, begin, end);
                 addknot = true;
-                r1_knot = true;              
+                r1_knot = true;
                 break; // break out of the while loop: add only one knot
             }
 
             end    = sp_item_gradient_get_coords(item, POINT_RG_R2, 0, fill_or_stroke);
             nearest = snap_vector_midpoint (mouse_p, begin, end);
-            delta = mouse_p - nearest;
-            if ( NR::L2 (delta) < tolerance ) {
-                offset = get_offset_between_points(nearest, begin, end); 
+            dist_screen = NR::L2 (mouse_p - nearest) * desktop->current_zoom();
+            if ( dist_screen < tolerance ) {
+                offset = get_offset_between_points(nearest, begin, end);
                 addknot = true;
-                r1_knot = false;              
+                r1_knot = false;
                 break; // break out of the while loop: add only one knot
             }
-        }     
+        }
         fill_or_stroke = !fill_or_stroke;
     } while (!fill_or_stroke && !addknot) ;
 
     if (addknot) {
-        SPGradient *vector = sp_gradient_get_vector (gradient, false);
+        SPGradient *vector = sp_gradient_get_forked_vector_if_necessary (gradient, false);
         SPStop* prev_stop = sp_first_stop(vector);
         SPStop* next_stop = sp_next_stop(prev_stop);
         while ( (next_stop) && (next_stop->offset < offset) ) {
@@ -281,11 +284,11 @@ sp_gradient_context_add_stop_near_point (SPGradientContext *rc, SPItem *item,  N
             // logical error: the endstop should have offset 1 and should always be more than this offset here
             return;
         }
-                    
+
         Inkscape::XML::Node *new_stop_repr = NULL;
-        new_stop_repr = SP_OBJECT_REPR(prev_stop)->duplicate();
+        new_stop_repr = SP_OBJECT_REPR(prev_stop)->duplicate(SP_OBJECT_REPR(vector)->document());
         SP_OBJECT_REPR(vector)->addChild(new_stop_repr, SP_OBJECT_REPR(prev_stop));
-    
+
         SPStop *newstop = (SPStop *) SP_OBJECT_DOCUMENT(vector)->getObjectByRepr(new_stop_repr);
         newstop->offset = offset;
         sp_repr_set_css_double( SP_OBJECT_REPR(newstop), "offset", (double)offset);
@@ -299,13 +302,13 @@ sp_gradient_context_add_stop_near_point (SPGradientContext *rc, SPItem *item,  N
         os << "stop-color:" << c << ";stop-opacity:" << opacity <<";";
         SP_OBJECT_REPR (newstop)->setAttribute("style", os.str().c_str());
 
-    
+
         Inkscape::GC::release(new_stop_repr);
         sp_document_done (SP_OBJECT_DOCUMENT (vector), SP_VERB_CONTEXT_GRADIENT,
                   _("Add gradient stop"));
 
         ec->_grdrag->updateDraggers();
-               sp_gradient_ensure_vector (gradient);
+        sp_gradient_ensure_vector (gradient);
 
         if (vector->has_stops) {
             int i = 0;
@@ -318,105 +321,31 @@ sp_gradient_context_add_stop_near_point (SPGradientContext *rc, SPItem *item,  N
                     }
                 }
             }
-            GrDragger *dragger = NULL;
+
             gradient = sp_item_gradient (item, fill_or_stroke);
-            GrPointType pointtype;
+            GrPointType pointtype = POINT_G_INVALID;
             if (SP_IS_LINEARGRADIENT(gradient)) {
-                dragger = SP_EVENT_CONTEXT(rc)->_grdrag->getDraggerFor (item, POINT_LG_MID, i, fill_or_stroke);                                                
                 pointtype = POINT_LG_MID;
-            } else if (SP_IS_RADIALGRADIENT(gradient)) {               
-                dragger = SP_EVENT_CONTEXT(rc)->_grdrag->getDraggerFor (item, r1_knot ? POINT_RG_MID1 : POINT_RG_MID2, i, fill_or_stroke);                                             
+            } else if (SP_IS_RADIALGRADIENT(gradient)) {
                 pointtype = r1_knot ? POINT_RG_MID1 : POINT_RG_MID2;
             }
-                if (dragger && (etime == 0) ) {
-                    ec->_grdrag->setSelected (dragger);
-                } else {
-                    ec->_grdrag->grabKnot (item,
-                                       pointtype,
-                                       i,
-                                       fill_or_stroke, 99999, 99999, etime);
-                }
-                ec->_grdrag->local_change = true;
-            
-        }
-    }
-}
-
-static void
-sp_gradient_context_delete_stops (SPGradientContext *rc, SPItem *item, GrDrag *drag, bool just_one) {
-    GrDragger *draggertemp = (GrDragger*) drag->selected->data;
-    GrDraggable *draggabletemp = (GrDraggable*) draggertemp->draggables->data;             
-    SPGradient *gradient = sp_item_gradient (item, draggabletemp->fill_or_stroke);
-    SPGradient *vector   = sp_gradient_get_vector (gradient, false);
-
-    // 2 is the minimum, cannot delete more than that without deleting the whole vector
-    guint num_delete = just_one ? 1 : g_list_length(drag->selected);
-    if (vector->vector.stops.size() >= (2+num_delete) ) { 
-        GSList *stoplist = NULL;
-        while (drag->selected) {
-            GrDragger *dragger = (GrDragger*) drag->selected->data;
-            GrDraggable *draggable = (GrDraggable*) dragger->draggables->data;             
-            SPStop *selstop = NULL;
-            switch (draggable->point_type) {
-                case POINT_LG_END:
-                case POINT_RG_R1:
-                case POINT_RG_R2:
-                    selstop = sp_last_stop(vector);
-                    break;
-                default: 
-                    selstop = sp_get_stop_i(vector, draggable->point_i);
-                    break;
-            }
-            if ( !g_slist_find(stoplist, selstop) ) {
-                stoplist = g_slist_append(stoplist, selstop);
-            }
-            drag->selected = g_list_remove(drag->selected, dragger);
-            if ( just_one ) break; // iterate once if just_one is set.
-        }
-        while (stoplist) {
-            SPStop *stop = (SPStop*) stoplist->data;
-            SP_OBJECT_REPR(vector)->removeChild(SP_OBJECT_REPR(stop));
-            stoplist = g_slist_remove(stoplist, stop);
-        }
-        // if we delete first or last stop, move the next/previous to the edge
-        SPStop *first = sp_first_stop (vector);
-        if (first) {
-            if (first->offset != 0) {
-                first->offset = 0;
-                sp_repr_set_css_double (SP_OBJECT_REPR (first), "offset", 0);
-            }
-        } 
-        SPStop *last = sp_last_stop (vector);
-        if (last) {
-            if (last->offset != 1) {
-                last->offset = 1;
-                sp_repr_set_css_double (SP_OBJECT_REPR (last), "offset", 1);
+            GrDragger *dragger = SP_EVENT_CONTEXT(rc)->_grdrag->getDraggerFor (item, pointtype, i, fill_or_stroke);
+            if (dragger && (etime == 0) ) {
+                ec->_grdrag->setSelected (dragger);
+            } else {
+                ec->_grdrag->grabKnot (item,
+                                   pointtype,
+                                   i,
+                                   fill_or_stroke, 99999, 99999, etime);
             }
-        } 
-        if ( just_one || (num_delete == 1) ) {
-            sp_document_done (SP_OBJECT_DOCUMENT (vector), SP_VERB_CONTEXT_GRADIENT, 
-                              _("Delete gradient stop"));
-        } else {
-            sp_document_done (SP_OBJECT_DOCUMENT (vector), SP_VERB_CONTEXT_GRADIENT, 
-                              _("Delete gradient stops"));
-        }
-    } else { // delete the gradient from the object. set fill to unset
-        SPCSSAttr *css = sp_repr_css_attr_new ();
-        if (draggabletemp->fill_or_stroke) {
-            sp_repr_css_unset_property (css, "fill");
-        } else {
-            sp_repr_css_unset_property (css, "stroke");
+            ec->_grdrag->local_change = true;
+
         }
-        sp_repr_css_change (SP_OBJECT_REPR (item), css, "style");
-        sp_repr_css_attr_unref (css);
-        sp_document_done (SP_OBJECT_DOCUMENT (vector), SP_VERB_CONTEXT_GRADIENT, 
-                          _("Remove gradient"));
     }
 }
 
 
-
-static gint 
+static gint
 sp_gradient_context_root_handler(SPEventContext *event_context, GdkEvent *event)
 {
     static bool dragging;
@@ -440,7 +369,7 @@ sp_gradient_context_root_handler(SPEventContext *event_context, GdkEvent *event)
             SPCtrlLine *line = NULL;
             if (drag->lines) {
                 for (GSList *l = drag->lines; (l != NULL) && (!over_line); l = l->next) {
-                    line = (SPCtrlLine*) l->data;                        
+                    line = (SPCtrlLine*) l->data;
                     over_line |= sp_gradient_context_is_over_line (rc, (SPItem*) line, NR::Point(event->motion.x, event->motion.y));
                 }
             }
@@ -451,13 +380,13 @@ sp_gradient_context_root_handler(SPEventContext *event_context, GdkEvent *event)
                     SPItem *item = SP_ITEM(i->data);
                     SPGradientType new_type = (SPGradientType) prefs_get_int_attribute ("tools.gradient", "newgradient", SP_GRADIENT_TYPE_LINEAR);
                     guint new_fill = prefs_get_int_attribute ("tools.gradient", "newfillorstroke", 1);
-    
+
                     SPGradient *vector = sp_gradient_vector_for_object(sp_desktop_document(desktop), desktop,                                                                                   SP_OBJECT (item), new_fill);
-    
+
                     SPGradient *priv = sp_item_set_gradient(item, vector, new_type, new_fill);
                     sp_gradient_reset_to_userspace(priv, item);
                 }
-    
+
                 sp_document_done (sp_desktop_document (desktop), SP_VERB_CONTEXT_GRADIENT,
                                   _("Create default gradient"));
             }
@@ -482,8 +411,9 @@ sp_gradient_context_root_handler(SPEventContext *event_context, GdkEvent *event)
             /* Position center */
             NR::Point const button_dt = desktop->w2d(button_w);
             /* Snap center to nearest magnetic point */
-
-            rc->origin = button_dt;
+            
+            SnapManager const &m = desktop->namedview->snap_manager;
+            rc->origin = m.freeSnap(Inkscape::Snapper::BBOX_POINT | Inkscape::Snapper::SNAP_POINT, button_dt, NULL).getPoint();
 
             ret = TRUE;
         }
@@ -536,23 +466,23 @@ sp_gradient_context_root_handler(SPEventContext *event_context, GdkEvent *event)
                 SPCtrlLine *line = NULL;
                 if (drag->lines) {
                     for (GSList *l = drag->lines; (l != NULL) && (!over_line); l = l->next) {
-                        line = (SPCtrlLine*) l->data;                        
+                        line = (SPCtrlLine*) l->data;
                         over_line |= sp_gradient_context_is_over_line (rc, (SPItem*) line, NR::Point(event->motion.x, event->motion.y));
                     }
                 }
                 if (over_line) {
-                    sp_gradient_context_add_stop_near_point(rc, SP_ITEM(selection->itemList()->data), rc->mousepoint_doc, 0);   
+                    sp_gradient_context_add_stop_near_point(rc, SP_ITEM(selection->itemList()->data), rc->mousepoint_doc, 0);
                     ret = TRUE;
                 }
-            } else {    
+            } else {
                 dragging = false;
-    
+
                 // unless clicked with Ctrl (to enable Ctrl+doubleclick).  (don't what this is for (johan))
                 if (event->button.state & GDK_CONTROL_MASK) {
                     ret = TRUE;
                     break;
                 }
-    
+
                 if (!event_context->within_tolerance) {
                     // we've been dragging, do nothing (grdrag handles that)
                 } else if (event_context->item_to_select) {
@@ -565,12 +495,12 @@ sp_gradient_context_root_handler(SPEventContext *event_context, GdkEvent *event)
                 } else {
                     // click in an empty space; do the same as Esc
                     if (drag->selected) {
-                        drag->deselect_all();
+                        drag->deselectAll();
                     } else {
                         selection->clear();
                     }
                 }
-    
+
                 event_context->item_to_select = NULL;
                 ret = TRUE;
             }
@@ -602,7 +532,7 @@ sp_gradient_context_root_handler(SPEventContext *event_context, GdkEvent *event)
 
         case GDK_Escape:
             if (drag->selected) {
-                drag->deselect_all();
+                drag->deselectAll();
             } else {
                 selection->clear();
             }
@@ -688,20 +618,20 @@ sp_gradient_context_root_handler(SPEventContext *event_context, GdkEvent *event)
                 ret = TRUE;
             }
             break;
-/*                
+/*
         case GDK_Insert:
         case GDK_KP_Insert:
-            // with any modifiers
-            sp_node_selected_add_node();
+            // with any modifiers:
+            // insert mid-stops between selected stops in gradient, or between all stops if none or only one selected
             ret = TRUE;
             break;
-*/            
+*/
         case GDK_Delete:
         case GDK_KP_Delete:
         case GDK_BackSpace:
             if ( drag->selected ) {
-                sp_gradient_context_delete_stops ( rc, SP_ITEM(selection->itemList()->data), drag, MOD__CTRL_ONLY ) ;
-                ret = TRUE;            
+                drag->deleteSelected(MOD__CTRL_ONLY);
+                ret = TRUE;
             }
             break;
         default:
@@ -733,7 +663,7 @@ sp_gradient_context_root_handler(SPEventContext *event_context, GdkEvent *event)
             ret = ((SPEventContextClass *) parent_class)->root_handler(event_context, event);
         }
     }
-    
+
     return ret;
 }