Code

Remove double unreffing of pointer in pdf-cairo.cpp. Fixes Bug #178985 with the...
[inkscape.git] / src / gradient-context.cpp
index d829af6bf6ff3d84df469e6004f4dd0d405747fb..230072e645b5624b35f54946395c280cdfe64a14 100644 (file)
@@ -29,7 +29,6 @@
 #include "message-stack.h"
 #include "pixmaps/cursor-gradient.xpm"
 #include "pixmaps/cursor-gradient-add.xpm"
-#include "pixmaps/cursor-gradient-delete.xpm"
 #include "gradient-context.h"
 #include "gradient-chemistry.h"
 #include <glibmm/i18n.h>
@@ -155,20 +154,37 @@ gradient_selection_changed (Inkscape::Selection *, gpointer data)
     guint n_tot = drag->numDraggers();
     guint n_sel = drag->numSelected();
 
+    //The use of ngettext in the following code is intentional even if the English singular form would never be used
     if (n_sel == 1) {
         if (drag->singleSelectedDraggerNumDraggables() == 1) {
-            rc->_message_context->setF(Inkscape::NORMAL_MESSAGE,
-                    _("%s selected out of %d gradient handles on %d selected object(s)"), gr_handle_descr[drag->singleSelectedDraggerSingleDraggableType()], n_tot, n_obj);
+               gchar * message = g_strconcat(
+                       //TRANSLATORS: %s will be substituted with the point name (see previous messages); This is part of a compound message
+                       _("%s selected"),
+                       //TRANSLATORS: Mind the space in front. This is part of a compound message
+                       ngettext(" out of %d gradient handle"," out of %d gradient handles",n_tot),
+                       ngettext(" on %d selected object"," on %d selected objects",n_obj),NULL);
+               rc->_message_context->setF(Inkscape::NORMAL_MESSAGE,
+                       message,_(gr_handle_descr[drag->singleSelectedDraggerSingleDraggableType()]), n_tot, n_obj);
         } else {
-            rc->_message_context->setF(Inkscape::NORMAL_MESSAGE,
-                    _("One handle merging %d stops (drag with <b>Shift</b> to separate) selected out of %d gradient handles on %d selected object(s)"), drag->singleSelectedDraggerNumDraggables(), n_tot, n_obj);
+               gchar * message = g_strconcat(
+                       //TRANSLATORS: This is a part of a compound message (out of two more indicating: grandint handle count & object count)
+                       ngettext("One handle merging %d stop (drag with <b>Shift</b> to separate) selected",
+                               "One handle merging %d stops (drag with <b>Shift</b> to separate) selected",drag->singleSelectedDraggerNumDraggables()),
+                       ngettext(" out of %d gradient handle"," out of %d gradient handles",n_tot),
+                       ngettext(" on %d selected object"," on %d selected objects",n_obj),NULL);
+               rc->_message_context->setF(Inkscape::NORMAL_MESSAGE,message,drag->singleSelectedDraggerNumDraggables(), n_tot, n_obj);
         }
     } else if (n_sel > 1) {
-        rc->_message_context->setF(Inkscape::NORMAL_MESSAGE,
-                                   _("<b>%d</b> gradient handles selected out of %d on %d selected object(s)"), n_sel, n_tot, n_obj);
+       //TRANSLATORS: The plural refers to number of selected gradient handles. This is part of a compound message (part two indicates selected object count)
+       gchar * message = g_strconcat(ngettext("<b>%d</b> gradient handle selected out of %d","<b>%d</b> gradient handles selected out of %d",n_sel),
+                                     //TRANSLATORS: Mind the space in front. (Refers to gradient handles selected). This is part of a compound message
+                                     ngettext(" on %d selected object"," on %d selected objects",n_obj),NULL);
+        rc->_message_context->setF(Inkscape::NORMAL_MESSAGE,message, n_sel, n_tot, n_obj);
     } else if (n_sel == 0) {
         rc->_message_context->setF(Inkscape::NORMAL_MESSAGE,
-                                   _("<b>No</b> gradient handles selected out of %d on %d selected object(s)"), n_tot, n_obj);
+               //TRANSLATORS: The plural refers to number of selected objects
+                ngettext("<b>No</b> gradient handles selected out of %d on %d selected object",
+                        "<b>No</b> gradient handles selected out of %d on %d selected objects",n_obj), n_tot, n_obj);
     }
 }
 
@@ -223,20 +239,6 @@ sp_gradient_context_select_prev (SPEventContext *event_context)
     event_context->desktop->scroll_to_point(&(d->point), 1.0);
 }
 
-// FIXME: make global function in libnr or somewhere.
-static NR::Point
-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;
-
-    return (begin + r * be);
-}
-
 static bool
 sp_gradient_context_is_over_line (SPGradientContext *rc, SPItem *item, NR::Point event_p)
 {
@@ -247,7 +249,7 @@ sp_gradient_context_is_over_line (SPGradientContext *rc, SPItem *item, NR::Point
 
     SPCtrlLine* line = SP_CTRLLINE(item);
 
-    NR::Point nearest = snap_vector_midpoint (rc->mousepoint_doc, line->s, line->e);
+    NR::Point nearest = snap_vector_midpoint (rc->mousepoint_doc, line->s, line->e, 0);
     double dist_screen = NR::L2 (rc->mousepoint_doc - nearest) * desktop->current_zoom();
 
     double tolerance = (double) SP_EVENT_CONTEXT(rc)->tolerance;
@@ -257,19 +259,6 @@ sp_gradient_context_is_over_line (SPGradientContext *rc, SPItem *item, NR::Point
     return close;
 }
 
-static double
-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;
-
-    return (r / length);
-}
-
 std::vector<NR::Point>
 sp_gradient_context_get_stop_intervals (GrDrag *drag, GSList **these_stops, GSList **next_stops)
 {
@@ -333,11 +322,12 @@ sp_gradient_context_get_stop_intervals (GrDrag *drag, GSList **these_stops, GSLi
                     }
                 }
 
-                // remember the coords of the future dragger to select it
-                coords.push_back(0.5*(dragger->point + dnext->point));
-
                 // if both adjacent draggers selected,
                 if (!g_slist_find(*these_stops, this_stop) && dnext && dnext->isSelected()) {
+
+                    // remember the coords of the future dragger to select it
+                    coords.push_back(0.5*(dragger->point + dnext->point));
+
                     // do not insert a stop now, it will confuse the loop;
                     // just remember the stops
                     *these_stops = g_slist_prepend (*these_stops, this_stop);
@@ -472,9 +462,8 @@ sp_gradient_simplify(SPGradientContext *rc, double tolerance)
 }
 
 
-
 static void
-sp_gradient_context_add_stop_near_point (SPGradientContext *rc, SPItem *item,  NR::Point mouse_p, guint32 etime)
+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
 
@@ -483,96 +472,12 @@ sp_gradient_context_add_stop_near_point (SPGradientContext *rc, SPItem *item,  N
 
     double tolerance = (double) ec->tolerance;
 
-    gfloat offset; // type of SPStop.offset = gfloat
-    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);
-            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);
-            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;
-                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);
-            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;
-                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_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) ) {
-            prev_stop = next_stop;
-            next_stop = sp_next_stop(next_stop);
-        }
-        if (!next_stop) {
-            // logical error: the endstop should have offset 1 and should always be more than this offset here
-            return;
-        }
-
-
-        SPStop *newstop = sp_vector_add_stop (vector, prev_stop, next_stop, offset);
-
-        sp_document_done (SP_OBJECT_DOCUMENT (vector), SP_VERB_CONTEXT_GRADIENT,
-                  _("Add gradient stop"));
-
-        ec->_grdrag->updateDraggers();
-        sp_gradient_ensure_vector (gradient);
+    ec->get_drag()->addStopNearPoint (item, mouse_p, tolerance/desktop->current_zoom());
 
-        if (vector->has_stops) {
-            guint i = sp_number_of_stops_before_stop(vector, newstop);
+    sp_document_done (sp_desktop_document (desktop), SP_VERB_CONTEXT_GRADIENT,
+                      _("Add gradient stop"));
 
-            gradient = sp_item_gradient (item, fill_or_stroke);
-            GrPointType pointtype = POINT_G_INVALID;
-            if (SP_IS_LINEARGRADIENT(gradient)) {
-                pointtype = POINT_LG_MID;
-            } else if (SP_IS_RADIALGRADIENT(gradient)) {
-                pointtype = r1_knot ? POINT_RG_MID1 : POINT_RG_MID2;
-            }
-            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);
-            }
-            ec->_grdrag->local_change = true;
-
-        }
-    }
+    ec->get_drag()->updateDraggers();
 }
 
 
@@ -605,6 +510,8 @@ sp_gradient_context_root_handler(SPEventContext *event_context, GdkEvent *event)
                 }
             }
             if (over_line) {
+                // we take the first item in selection, because with doubleclick, the first click
+                // always resets selection to the single object under cursor
                 sp_gradient_context_add_stop_near_point(rc, SP_ITEM(selection->itemList()->data), rc->mousepoint_doc, event->button.time);
             } else {
                 for (GSList const* i = selection->itemList(); i != NULL; i = i->next) {
@@ -707,11 +614,13 @@ sp_gradient_context_root_handler(SPEventContext *event_context, GdkEvent *event)
                 if (drag->lines) {
                     for (GSList *l = drag->lines; (l != NULL) && (!over_line); l = l->next) {
                         line = (SPCtrlLine*) l->data;
-                        over_line |= sp_gradient_context_is_over_line (rc, (SPItem*) line, NR::Point(event->motion.x, event->motion.y));
+                        over_line = sp_gradient_context_is_over_line (rc, (SPItem*) line, NR::Point(event->motion.x, event->motion.y));
+                        if (over_line)
+                            break;
                     }
                 }
-                if (over_line) {
-                    sp_gradient_context_add_stop_near_point(rc, SP_ITEM(selection->itemList()->data), rc->mousepoint_doc, 0);
+                if (over_line && line) {
+                    sp_gradient_context_add_stop_near_point(rc, line->item, rc->mousepoint_doc, 0);
                     ret = TRUE;
                 }
             } else {
@@ -811,13 +720,15 @@ sp_gradient_context_root_handler(SPEventContext *event_context, GdkEvent *event)
         case GDK_KP_Left:
         case GDK_KP_4:
             if (!MOD__CTRL) { // not ctrl
+                gint mul = 1 + gobble_key_events(
+                    get_group0_keyval(&event->key), 0); // with any mask
                 if (MOD__ALT) { // alt
-                    if (MOD__SHIFT) drag->selected_move_screen(-10, 0); // shift
-                    else drag->selected_move_screen(-1, 0); // no shift
+                    if (MOD__SHIFT) drag->selected_move_screen(mul*-10, 0); // shift
+                    else drag->selected_move_screen(mul*-1, 0); // no shift
                 }
                 else { // no alt
-                    if (MOD__SHIFT) drag->selected_move(-10*nudge, 0); // shift
-                    else drag->selected_move(-nudge, 0); // no shift
+                    if (MOD__SHIFT) drag->selected_move(mul*-10*nudge, 0); // shift
+                    else drag->selected_move(mul*-nudge, 0); // no shift
                 }
                 ret = TRUE;
             }
@@ -826,13 +737,15 @@ sp_gradient_context_root_handler(SPEventContext *event_context, GdkEvent *event)
         case GDK_KP_Up:
         case GDK_KP_8:
             if (!MOD__CTRL) { // not ctrl
+                gint mul = 1 + gobble_key_events(
+                    get_group0_keyval(&event->key), 0); // with any mask
                 if (MOD__ALT) { // alt
-                    if (MOD__SHIFT) drag->selected_move_screen(0, 10); // shift
-                    else drag->selected_move_screen(0, 1); // no shift
+                    if (MOD__SHIFT) drag->selected_move_screen(0, mul*10); // shift
+                    else drag->selected_move_screen(0, mul*1); // no shift
                 }
                 else { // no alt
-                    if (MOD__SHIFT) drag->selected_move(0, 10*nudge); // shift
-                    else drag->selected_move(0, nudge); // no shift
+                    if (MOD__SHIFT) drag->selected_move(0, mul*10*nudge); // shift
+                    else drag->selected_move(0, mul*nudge); // no shift
                 }
                 ret = TRUE;
             }
@@ -841,13 +754,15 @@ sp_gradient_context_root_handler(SPEventContext *event_context, GdkEvent *event)
         case GDK_KP_Right:
         case GDK_KP_6:
             if (!MOD__CTRL) { // not ctrl
+                gint mul = 1 + gobble_key_events(
+                    get_group0_keyval(&event->key), 0); // with any mask
                 if (MOD__ALT) { // alt
-                    if (MOD__SHIFT) drag->selected_move_screen(10, 0); // shift
-                    else drag->selected_move_screen(1, 0); // no shift
+                    if (MOD__SHIFT) drag->selected_move_screen(mul*10, 0); // shift
+                    else drag->selected_move_screen(mul*1, 0); // no shift
                 }
                 else { // no alt
-                    if (MOD__SHIFT) drag->selected_move(10*nudge, 0); // shift
-                    else drag->selected_move(nudge, 0); // no shift
+                    if (MOD__SHIFT) drag->selected_move(mul*10*nudge, 0); // shift
+                    else drag->selected_move(mul*nudge, 0); // no shift
                 }
                 ret = TRUE;
             }
@@ -856,13 +771,15 @@ sp_gradient_context_root_handler(SPEventContext *event_context, GdkEvent *event)
         case GDK_KP_Down:
         case GDK_KP_2:
             if (!MOD__CTRL) { // not ctrl
+                gint mul = 1 + gobble_key_events(
+                    get_group0_keyval(&event->key), 0); // with any mask
                 if (MOD__ALT) { // alt
-                    if (MOD__SHIFT) drag->selected_move_screen(0, -10); // shift
-                    else drag->selected_move_screen(0, -1); // no shift
+                    if (MOD__SHIFT) drag->selected_move_screen(0, mul*-10); // shift
+                    else drag->selected_move_screen(0, mul*-1); // no shift
                 }
                 else { // no alt
-                    if (MOD__SHIFT) drag->selected_move(0, -10*nudge); // shift
-                    else drag->selected_move(0, -nudge); // no shift
+                    if (MOD__SHIFT) drag->selected_move(0, mul*-10*nudge); // shift
+                    else drag->selected_move(0, mul*-nudge); // no shift
                 }
                 ret = TRUE;
             }
@@ -934,7 +851,7 @@ sp_gradient_context_root_handler(SPEventContext *event_context, GdkEvent *event)
     return ret;
 }
 
-static void sp_gradient_drag(SPGradientContext &rc, NR::Point const pt, guint state, guint32 etime)
+static void sp_gradient_drag(SPGradientContext &rc, NR::Point const pt, guint /*state*/, guint32 etime)
 {
     SPDesktop *desktop = SP_EVENT_CONTEXT(&rc)->desktop;
     Inkscape::Selection *selection = sp_desktop_selection(desktop);
@@ -947,9 +864,16 @@ static void sp_gradient_drag(SPGradientContext &rc, NR::Point const pt, guint st
 
         SPGradient *vector;
         if (ec->item_to_select) {
+            // pick color from the object where drag started
             vector = sp_gradient_vector_for_object(document, desktop, ec->item_to_select, fill_or_stroke);
         } else {
-            vector = sp_gradient_vector_for_object(document, desktop, SP_ITEM(selection->itemList()->data), fill_or_stroke);
+            // Starting from empty space:
+            // Sort items so that the topmost comes last
+            GSList *items = g_slist_copy ((GSList *) selection->itemList());
+            items = g_slist_sort(items, (GCompareFunc) sp_item_repr_compare_position);
+            // take topmost
+            vector = sp_gradient_vector_for_object(document, desktop, SP_ITEM(g_slist_last(items)->data), fill_or_stroke);
+            g_slist_free (items);
         }
 
         // HACK: reset fill-opacity - that 0.75 is annoying; BUT remove this when we have an opacity slider for all tabs