Code

Gradient nodes progress...
authorjohanengelen <johanengelen@users.sourceforge.net>
Sun, 7 Jan 2007 18:26:31 +0000 (18:26 +0000)
committerjohanengelen <johanengelen@users.sourceforge.net>
Sun, 7 Jan 2007 18:26:31 +0000 (18:26 +0000)
src/desktop.cpp
src/desktop.h
src/gradient-chemistry.cpp
src/gradient-chemistry.h
src/gradient-context.cpp
src/gradient-drag.cpp
src/gradient-drag.h
src/sp-gradient.h

index bf4b0ba6524e1d928e1d085ae8e6fcacafcdf66d..903a6bd7c90c46e3ea7980fc54b6d4e2f7f43b54 100644 (file)
@@ -128,7 +128,8 @@ SPDesktop::SPDesktop()
     is_fullscreen = false;
 
     gr_item = NULL;
-    gr_point_num = 0;
+    gr_point_type = 0;
+    gr_point_i = 0;
     gr_fill_or_stroke = true;
 
     _layer_hierarchy = NULL;
index e9e2f638e764d5388ba433ea12bf6fdae8a55e29..8f2fac1e8d00758086aae87e9897db179a875237 100644 (file)
@@ -104,8 +104,10 @@ struct SPDesktop : public Inkscape::UI::View::View
     // storage for selected dragger used by GrDrag as it's 
     // created and deleted by tools
     SPItem *gr_item;
-    guint  gr_point_num;
+    guint  gr_point_type;
+    guint  gr_point_i;
     bool   gr_fill_or_stroke;   
+    
 
     Inkscape::ObjectHierarchy *_layer_hierarchy;
     gchar * _reconstruction_old_layer_id;
index 6a485e573d392f57840579e733e85f10de9b3eda..0f57ed901691cfcb2a903fa32e9a1b9d1dcf9cb9 100644 (file)
@@ -19,6 +19,7 @@
 #include "desktop-style.h"
 
 #include "sp-gradient-reference.h"
+#include "sp-gradient-vector.h"
 #include "sp-linear-gradient.h"
 #include "sp-radial-gradient.h"
 #include "sp-stop.h"
@@ -498,11 +499,24 @@ sp_last_stop(SPGradient *gradient)
                return stop;
   }
   return NULL;
+} 
+
+SPStop*
+sp_get_stop_i(SPGradient *gradient, guint stop_i)
+{            
+  SPStop *stop = sp_first_stop (gradient);
+  
+  for (guint i=0; i < stop_i; i++) {
+    if (!stop) return NULL;  
+    stop = sp_next_stop (stop);    
+  }  
+    
+  return stop;
 }
 
 
 void
-sp_item_gradient_edit_stop (SPItem *item, guint point_num, bool fill_or_stroke)
+sp_item_gradient_edit_stop (SPItem *item, guint point_type, guint point_i, bool fill_or_stroke)
 {
     SPGradient *gradient = sp_item_gradient (item, fill_or_stroke);
 
@@ -510,8 +524,8 @@ sp_item_gradient_edit_stop (SPItem *item, guint point_num, bool fill_or_stroke)
         return;
 
     SPGradient *vector = sp_gradient_get_vector (gradient, false);
-    switch (point_num) {
-        case POINT_LG_P1:
+    switch (point_type) {
+        case POINT_LG_BEGIN:
         case POINT_RG_CENTER:
         case POINT_RG_FOCUS:
         {
@@ -520,7 +534,7 @@ sp_item_gradient_edit_stop (SPItem *item, guint point_num, bool fill_or_stroke)
         }
         break;
 
-        case POINT_LG_P2:
+        case POINT_LG_END:
         case POINT_RG_R1:
         case POINT_RG_R2:
         {
@@ -528,13 +542,20 @@ sp_item_gradient_edit_stop (SPItem *item, guint point_num, bool fill_or_stroke)
             gtk_widget_show (dialog);
         }
         break;
+        
+        case POINT_LG_MID:
+        {
+            GtkWidget *dialog = sp_gradient_vector_editor_new (vector, sp_get_stop_i (vector, point_i));
+            gtk_widget_show (dialog);
+        }
+        break;
         default:
             break;
     }
 }
 
 guint32
-sp_item_gradient_stop_query_style (SPItem *item, guint point_num, bool fill_or_stroke)
+sp_item_gradient_stop_query_style (SPItem *item, guint point_type, guint point_i, bool fill_or_stroke)
 {
     SPGradient *gradient = sp_item_gradient (item, fill_or_stroke);
 
@@ -546,8 +567,8 @@ sp_item_gradient_stop_query_style (SPItem *item, guint point_num, bool fill_or_s
     if (!vector) // orphan!
         return 0; // what else to do?
 
-    switch (point_num) {
-        case POINT_LG_P1:
+    switch (point_type) {
+        case POINT_LG_BEGIN:
         case POINT_RG_CENTER:
         case POINT_RG_FOCUS:
         {
@@ -558,7 +579,7 @@ sp_item_gradient_stop_query_style (SPItem *item, guint point_num, bool fill_or_s
         }
         break;
 
-        case POINT_LG_P2:
+        case POINT_LG_END:
         case POINT_RG_R1:
         case POINT_RG_R2:
         {
@@ -568,6 +589,16 @@ sp_item_gradient_stop_query_style (SPItem *item, guint point_num, bool fill_or_s
             }
         }
         break;
+        
+        case POINT_LG_MID:
+        {
+            SPStop *stopi = sp_get_stop_i (vector, point_i);
+            if (stopi) {
+                return sp_stop_get_rgba32(stopi);
+            }
+        }
+        break;
+
         default:
             break;
     }
@@ -575,7 +606,7 @@ sp_item_gradient_stop_query_style (SPItem *item, guint point_num, bool fill_or_s
 }
 
 void
-sp_item_gradient_stop_set_style (SPItem *item, guint point_num, bool fill_or_stroke, SPCSSAttr *stop)
+sp_item_gradient_stop_set_style (SPItem *item, guint point_type, guint point_i, bool fill_or_stroke, SPCSSAttr *stop)
 {
     SPGradient *gradient = sp_item_gradient (item, fill_or_stroke);
 
@@ -592,8 +623,8 @@ sp_item_gradient_stop_set_style (SPItem *item, guint point_num, bool fill_or_str
         sp_gradient_repr_set_link(SP_OBJECT_REPR(gradient), vector);
     }
 
-    switch (point_num) {
-        case POINT_LG_P1:
+    switch (point_type) {
+        case POINT_LG_BEGIN:
         case POINT_RG_CENTER:
         case POINT_RG_FOCUS:
         {
@@ -604,7 +635,7 @@ sp_item_gradient_stop_set_style (SPItem *item, guint point_num, bool fill_or_str
         }
         break;
 
-        case POINT_LG_P2:
+        case POINT_LG_END:
         case POINT_RG_R1:
         case POINT_RG_R2:
         {
@@ -614,6 +645,16 @@ sp_item_gradient_stop_set_style (SPItem *item, guint point_num, bool fill_or_str
             }
         }
         break;
+        
+        case POINT_LG_MID:
+        {
+            SPStop *stopi = sp_get_stop_i (vector, point_i);
+            if (stopi) {
+                sp_repr_css_change (SP_OBJECT_REPR (stopi), stop, "style");
+            }
+        }
+        break;
+           
         default:
             break;
     }
@@ -674,11 +715,11 @@ sp_item_gradient_reverse_vector (SPItem *item, bool fill_or_stroke)
 
 
 /**
-Set the position of point point_num of the gradient applied to item (either fill_or_stroke) to
+Set the position of point point_type of the gradient applied to item (either fill_or_stroke) to
 p_w (in desktop coordinates). Write_repr if you want the change to become permanent.
 */
 void
-sp_item_gradient_set_coords (SPItem *item, guint point_num, NR::Point p_w, bool fill_or_stroke, bool write_repr, bool scale)
+sp_item_gradient_set_coords (SPItem *item, guint point_type, guint point_i, NR::Point p_w, bool fill_or_stroke, bool write_repr, bool scale)
 {
     SPGradient *gradient = sp_item_gradient (item, fill_or_stroke);
 
@@ -696,8 +737,8 @@ sp_item_gradient_set_coords (SPItem *item, guint point_num, NR::Point p_w, bool
 
     if (SP_IS_LINEARGRADIENT(gradient)) {
         SPLinearGradient *lg = SP_LINEARGRADIENT(gradient);
-        switch (point_num) {
-            case POINT_LG_P1:
+        switch (point_type) {
+            case POINT_LG_BEGIN:
                 if (scale) {
                     lg->x2.computed += (lg->x1.computed - p[NR::X]);
                     lg->y2.computed += (lg->y1.computed - p[NR::Y]);
@@ -715,7 +756,7 @@ sp_item_gradient_set_coords (SPItem *item, guint point_num, NR::Point p_w, bool
                     SP_OBJECT (gradient)->requestModified(SP_OBJECT_MODIFIED_FLAG);
                 }
                 break;
-            case POINT_LG_P2:
+            case POINT_LG_END:
                 if (scale) {
                     lg->x1.computed += (lg->x2.computed - p[NR::X]);
                     lg->y1.computed += (lg->y2.computed - p[NR::Y]);
@@ -733,6 +774,11 @@ sp_item_gradient_set_coords (SPItem *item, guint point_num, NR::Point p_w, bool
                     SP_OBJECT (gradient)->requestModified(SP_OBJECT_MODIFIED_FLAG);
                 }
                        break;
+            case POINT_LG_MID:
+            {
+                //do stuff!
+            }
+            break;
                default:
                        break;
                }
@@ -741,14 +787,14 @@ sp_item_gradient_set_coords (SPItem *item, guint point_num, NR::Point p_w, bool
                SPRadialGradient *rg = SP_RADIALGRADIENT(gradient);
                NR::Point c (rg->cx.computed, rg->cy.computed);
                NR::Point c_w = c * gradient->gradientTransform * i2d; // now in desktop coords
-           if ((point_num == POINT_RG_R1 || point_num == POINT_RG_R2) && NR::L2 (p_w - c_w) < 1e-3) {
+           if ((point_type == POINT_RG_R1 || point_type == POINT_RG_R2) && NR::L2 (p_w - c_w) < 1e-3) {
                // prevent setting a radius too close to the center
                return;
            }
                NR::Matrix new_transform;
                bool transform_set = false;
 
-               switch (point_num) {
+               switch (point_type) {
                case POINT_RG_CENTER:
                        rg->fx.computed = p[NR::X] + (rg->fx.computed - rg->cx.computed);
                        rg->fy.computed = p[NR::Y] + (rg->fy.computed - rg->cy.computed);
@@ -852,12 +898,12 @@ sp_item_gradient_get_spread (SPItem *item, bool fill_or_stroke)
 
 
 /**
-Returns the position of point point_num of the gradient applied to item (either fill_or_stroke),
+Returns the position of point point_type of the gradient applied to item (either fill_or_stroke),
 in desktop coordinates.
 */
 
 NR::Point
-sp_item_gradient_get_coords (SPItem *item, guint point_num, bool fill_or_stroke)
+sp_item_gradient_get_coords (SPItem *item, guint point_type, guint point_i, bool fill_or_stroke)
 {
     SPGradient *gradient = sp_item_gradient (item, fill_or_stroke);
 
@@ -868,17 +914,22 @@ sp_item_gradient_get_coords (SPItem *item, guint point_num, bool fill_or_stroke)
 
     if (SP_IS_LINEARGRADIENT(gradient)) {
         SPLinearGradient *lg = SP_LINEARGRADIENT(gradient);
-        switch (point_num) {
-            case POINT_LG_P1:
+        switch (point_type) {
+            case POINT_LG_BEGIN:
                 p = NR::Point (lg->x1.computed, lg->y1.computed);
                 break;
-            case POINT_LG_P2:
+            case POINT_LG_END:
                 p = NR::Point (lg->x2.computed, lg->y2.computed);
                 break;
+            case POINT_LG_MID:
+                //p = somewhere in between (x1,y1)-(x2,y2) defined by percentage of point[point_i];
+                gdouble offset = lg->vector.stops.at(point_i).offset;
+                p = (1-offset) * NR::Point(lg->x1.computed, lg->y1.computed) + offset * NR::Point(lg->x2.computed, lg->y2.computed);
+                break;
         }
     } else     if (SP_IS_RADIALGRADIENT(gradient)) {
         SPRadialGradient *rg = SP_RADIALGRADIENT(gradient);
-        switch (point_num) {
+        switch (point_type) {
             case POINT_RG_CENTER:
                 p = NR::Point (rg->cx.computed, rg->cy.computed);
                 break;
index b649a22ec78f76e1e265ccc0e9bf217ccb85d496..b95c5025e57c0b1f388336ee022b8aa3bc33e90e 100644 (file)
@@ -54,18 +54,19 @@ SPStop* sp_first_stop(SPGradient *gradient);
 SPStop* sp_last_stop(SPGradient *gradient);
 SPStop* sp_prev_stop(SPStop *stop, SPGradient *gradient);
 SPStop* sp_next_stop(SPStop *stop);
+SPStop* sp_get_stop_i(SPGradient *gradient, guint i);
 
 void sp_gradient_transform_multiply (SPGradient *gradient, NR::Matrix postmul, bool set);
 
-void sp_item_gradient_set_coords (SPItem *item, guint point_num, NR::Point p_desk, bool fill_or_stroke, bool write_repr, bool scale);
-NR::Point sp_item_gradient_get_coords (SPItem *item, guint point_num, bool fill_or_stroke);
+void sp_item_gradient_set_coords (SPItem *item, guint point_type, guint point_i, NR::Point p_desk, bool fill_or_stroke, bool write_repr, bool scale);
+NR::Point sp_item_gradient_get_coords (SPItem *item, guint point_type, guint point_i, bool fill_or_stroke);
 SPGradient *sp_item_gradient_get_vector (SPItem *item, bool fill_or_stroke);
 SPGradientSpread sp_item_gradient_get_spread (SPItem *item, bool fill_or_stroke);
 
 struct SPCSSAttr;
-void sp_item_gradient_stop_set_style (SPItem *item, guint point_num, bool fill_or_stroke, SPCSSAttr *stop);
-guint32 sp_item_gradient_stop_query_style (SPItem *item, guint point_num, bool fill_or_stroke);
-void sp_item_gradient_edit_stop (SPItem *item, guint point_num, bool fill_or_stroke);
+void sp_item_gradient_stop_set_style (SPItem *item, guint point_type, guint point_i, bool fill_or_stroke, SPCSSAttr *stop);
+guint32 sp_item_gradient_stop_query_style (SPItem *item, guint point_type, guint point_i, bool fill_or_stroke);
+void sp_item_gradient_edit_stop (SPItem *item, guint point_type, guint point_i, bool fill_or_stroke);
 void sp_item_gradient_reverse_vector (SPItem *item, bool fill_or_stroke);
 
 #endif
index ad1dd873066873f5e58d2ee198837464c1f5b9c5..c54041a8222c6fb2f9165dbbbc168b1a3f71bae3 100644 (file)
@@ -433,11 +433,15 @@ static void sp_gradient_drag(SPGradientContext &rc, NR::Point const pt, guint st
             sp_item_set_gradient(SP_ITEM(i->data), vector, (SPGradientType) type, fill_or_stroke);
 
             if (type == SP_GRADIENT_TYPE_LINEAR) {
-                sp_item_gradient_set_coords (SP_ITEM(i->data), POINT_LG_P1, rc.origin, fill_or_stroke, true, false);
-                sp_item_gradient_set_coords (SP_ITEM(i->data), POINT_LG_P2, pt, fill_or_stroke, true, false);
+                sp_item_gradient_set_coords (SP_ITEM(i->data), POINT_LG_BEGIN, 0, rc.origin, fill_or_stroke, true, false);
+/* FIXGRADIENT
+   Add sensible code to handle the midpoints, or maybe not necessary?
+   not necessary i think because this only creates default gradient?
+*/                
+                sp_item_gradient_set_coords (SP_ITEM(i->data), POINT_LG_END, 0, pt, fill_or_stroke, true, false);
             } else if (type == SP_GRADIENT_TYPE_RADIAL) {
-                sp_item_gradient_set_coords (SP_ITEM(i->data), POINT_RG_CENTER, rc.origin, fill_or_stroke, true, false);
-                sp_item_gradient_set_coords (SP_ITEM(i->data), POINT_RG_R1, pt, fill_or_stroke, true, false);
+                sp_item_gradient_set_coords (SP_ITEM(i->data), POINT_RG_CENTER, 0, rc.origin, fill_or_stroke, true, false);
+                sp_item_gradient_set_coords (SP_ITEM(i->data), POINT_RG_R1, 0, pt, fill_or_stroke, true, false);
             }
             SP_OBJECT (i->data)->requestModified(SP_OBJECT_MODIFIED_FLAG);
         }
@@ -449,7 +453,8 @@ static void sp_gradient_drag(SPGradientContext &rc, NR::Point const pt, guint st
             // give the grab out-of-bounds values of xp/yp because we're already dragging
             // and therefore are already out of tolerance
             ec->_grdrag->grabKnot (SP_ITEM(selection->itemList()->data),
-                                   type == SP_GRADIENT_TYPE_LINEAR? POINT_LG_P2 : POINT_RG_R1,
+                                   type == SP_GRADIENT_TYPE_LINEAR? POINT_LG_END : POINT_RG_R1,
+                                   0, //point_i
                                    fill_or_stroke, 99999, 99999, etime);
         }
         // We did an undoable action, but sp_document_done will be called by the knot when released
index 465f57b86e373407db3b9da53945aa842eedb636..763e5bdb4c8064aa5aa0edd9625e54959b9c3c76 100644 (file)
 // absolute distance between gradient points for them to become a single dragger when the drag is created:
 #define MERGE_DIST 0.1
 
-// knot shapes corresponding to GrPoint enum
+// knot shapes corresponding to GrPointType enum
 SPKnotShapeType gr_knot_shapes [] = {
-        SP_KNOT_SHAPE_SQUARE, //POINT_LG_P1
-        SP_KNOT_SHAPE_SQUARE,
+        SP_KNOT_SHAPE_SQUARE, //POINT_LG_BEGIN
+        SP_KNOT_SHAPE_CIRCLE,  //POINT_LG_END
+        SP_KNOT_SHAPE_DIAMOND, //POINT_LG_MID
         SP_KNOT_SHAPE_DIAMOND,
         SP_KNOT_SHAPE_CIRCLE,
         SP_KNOT_SHAPE_CIRCLE,
@@ -58,8 +59,9 @@ SPKnotShapeType gr_knot_shapes [] = {
 };
 
 const gchar *gr_knot_descr [] = {
-    N_("Linear gradient <b>start</b>"), //POINT_LG_P1
+    N_("Linear gradient <b>start</b>"), //POINT_LG_BEGIN
     N_("Linear gradient <b>end</b>"),
+    N_("Linear gradient <b>mid</b>"),
     N_("Radial gradient <b>center</b>"),
     N_("Radial gradient <b>radius</b>"),
     N_("Radial gradient <b>radius</b>"),
@@ -121,7 +123,7 @@ gr_drag_style_query (SPStyle *style, int property, gpointer data)
                 ret = QUERY_STYLE_MULTIPLE_AVERAGED;
             }
 
-            guint32 c = sp_item_gradient_stop_query_style (draggable->item, draggable->point_num, draggable->fill_or_stroke);
+            guint32 c = sp_item_gradient_stop_query_style (draggable->item, draggable->point_type, draggable->point_i, draggable->fill_or_stroke);
             cf[0] += SP_RGBA32_R_F (c);
             cf[1] += SP_RGBA32_G_F (c);
             cf[2] += SP_RGBA32_B_F (c);
@@ -215,7 +217,7 @@ gr_drag_style_set (const SPCSSAttr *css, gpointer data)
            GrDraggable *draggable = (GrDraggable *) i->data;
 
            drag->local_change = true;
-           sp_item_gradient_stop_set_style (draggable->item, draggable->point_num, draggable->fill_or_stroke, stop);
+           sp_item_gradient_stop_set_style (draggable->item, draggable->point_type, draggable->point_i, draggable->fill_or_stroke, stop);
     }
 
     //sp_repr_css_print(stop);
@@ -267,7 +269,7 @@ GrDrag::GrDrag(SPDesktop *desktop) {
     this->updateLevels ();
 
     if (desktop->gr_item) {
-        this->setSelected (getDraggerFor (desktop->gr_item, desktop->gr_point_num, desktop->gr_fill_or_stroke));
+        this->setSelected (getDraggerFor (desktop->gr_item, desktop->gr_point_type, desktop->gr_point_i, desktop->gr_fill_or_stroke));
     }
 }
 
@@ -281,11 +283,13 @@ GrDrag::~GrDrag()
     if (this->selected) {
         GrDraggable *draggable = (GrDraggable *) this->selected->draggables->data;
         desktop->gr_item = draggable->item;
-        desktop->gr_point_num = draggable->point_num;
+        desktop->gr_point_type = draggable->point_type;
+        desktop->gr_point_i = draggable->point_i;
         desktop->gr_fill_or_stroke = draggable->fill_or_stroke;
     } else {
         desktop->gr_item = NULL;
-        desktop->gr_point_num = 0;
+        desktop->gr_point_type = 0;
+        desktop->gr_point_i = 0;
         desktop->gr_fill_or_stroke = true;
     }
 
@@ -303,10 +307,11 @@ GrDrag::~GrDrag()
     this->lines = NULL;
 }
 
-GrDraggable::GrDraggable (SPItem *item, guint point_num, bool fill_or_stroke)
+GrDraggable::GrDraggable (SPItem *item, guint point_type, guint point_i, bool fill_or_stroke)
 {
     this->item = item;
-    this->point_num = point_num;
+    this->point_type = point_type;
+    this->point_i = point_i;
     this->fill_or_stroke = fill_or_stroke;
 
     g_object_ref (G_OBJECT (this->item));
@@ -367,7 +372,7 @@ gr_knot_moved_handler(SPKnot *knot, NR::Point const *ppointer, guint state, gpoi
                 for (GSList const* i = dragger->draggables; i != NULL; i = i->next) { // for all draggables of dragger
                     GrDraggable *draggable = (GrDraggable *) i->data;
                     // copy draggable to d_new:
-                    GrDraggable *da_new = new GrDraggable (draggable->item, draggable->point_num, draggable->fill_or_stroke);
+                    GrDraggable *da_new = new GrDraggable (draggable->item, draggable->point_type, draggable->point_i, draggable->fill_or_stroke);
                     d_new->addDraggable (da_new);
                 }
 
@@ -417,13 +422,14 @@ gr_knot_moved_handler(SPKnot *knot, NR::Point const *ppointer, guint state, gpoi
 
             NR::Point *dr_snap = NULL;
 
-            if (draggable->point_num == POINT_LG_P1 || draggable->point_num == POINT_LG_P2) {
+            if (draggable->point_type == POINT_LG_BEGIN || draggable->point_type == POINT_LG_END) {
                 for (GList *di = dragger->parent->draggers; di != NULL; di = di->next) {
                     GrDragger *d_new = (GrDragger *) di->data;
                     if (d_new == dragger)
                         continue;
                     if (d_new->isA (draggable->item,
-                                    draggable->point_num == POINT_LG_P1? POINT_LG_P2 : POINT_LG_P1,
+                                    draggable->point_type == POINT_LG_BEGIN? POINT_LG_END : POINT_LG_BEGIN,
+                                    draggable->point_i,
                                     draggable->fill_or_stroke)) {
                         // found the other end of the linear gradient;
                         if (state & GDK_SHIFT_MASK) {
@@ -436,19 +442,20 @@ gr_knot_moved_handler(SPKnot *knot, NR::Point const *ppointer, guint state, gpoi
                         }
                     }
                 }
-            } else if (draggable->point_num == POINT_RG_R1 || draggable->point_num == POINT_RG_R2 || draggable->point_num == POINT_RG_FOCUS) {
+            } else if (draggable->point_type == POINT_RG_R1 || draggable->point_type == POINT_RG_R2 || draggable->point_type == POINT_RG_FOCUS) {
                 for (GList *di = dragger->parent->draggers; di != NULL; di = di->next) {
                     GrDragger *d_new = (GrDragger *) di->data;
                     if (d_new == dragger)
                         continue;
                     if (d_new->isA (draggable->item,
                                     POINT_RG_CENTER,
+                                    draggable->point_i,
                                     draggable->fill_or_stroke)) {
                         // found the center of the radial gradient;
                         dr_snap = &(d_new->point);
                     }
                 }
-            } else if (draggable->point_num == POINT_RG_CENTER) {
+            } else if (draggable->point_type == POINT_RG_CENTER) {
                 // radial center snaps to hor/vert relative to its original position
                 dr_snap = &(dragger->point_original);
             }
@@ -545,7 +552,7 @@ gr_knot_doubleclicked_handler (SPKnot *knot, guint state, gpointer data)
        return;
 
    GrDraggable *draggable = (GrDraggable *) dragger->draggables->data;
-   sp_item_gradient_edit_stop (draggable->item, draggable->point_num, draggable->fill_or_stroke);
+   sp_item_gradient_edit_stop (draggable->item, draggable->point_type, draggable->point_i, draggable->fill_or_stroke);
 }
 
 /**
@@ -563,20 +570,20 @@ GrDragger::fireDraggables (bool write_repr, bool scale_radial, bool merging_focu
         // change gradient, optionally writing to repr; prevent focus from moving if it's snapped
         // to the center, unless it's the first update upon merge when we must snap it to the point
         if (merging_focus ||
-            !(draggable->point_num == POINT_RG_FOCUS && this->isA(draggable->item, POINT_RG_CENTER, draggable->fill_or_stroke)))
-            sp_item_gradient_set_coords (draggable->item, draggable->point_num, this->point, draggable->fill_or_stroke, write_repr, scale_radial);
+            !(draggable->point_type == POINT_RG_FOCUS && this->isA(draggable->item, POINT_RG_CENTER, draggable->point_i, draggable->fill_or_stroke)))
+            sp_item_gradient_set_coords (draggable->item, draggable->point_type, draggable->point_i, this->point, draggable->fill_or_stroke, write_repr, scale_radial);
     }
 }
 
 /**
-Checks if the dragger has a draggable with this point_num
+Checks if the dragger has a draggable with this point_type
  */
 bool
-GrDragger::isA (guint point_num)
+GrDragger::isA (guint point_type)
 {
     for (GSList const* i = this->draggables; i != NULL; i = i->next) {
         GrDraggable *draggable = (GrDraggable *) i->data;
-        if (draggable->point_num == point_num) {
+        if (draggable->point_type == point_type) {
             return true;
         }
     }
@@ -584,14 +591,14 @@ GrDragger::isA (guint point_num)
 }
 
 /**
-Checks if the dragger has a draggable with this item, point_num, fill_or_stroke
+Checks if the dragger has a draggable with this item, point_type, fill_or_stroke
  */
 bool
-GrDragger::isA (SPItem *item, guint point_num, bool fill_or_stroke)
+GrDragger::isA (SPItem *item, guint point_type, guint point_i, bool fill_or_stroke)
 {
     for (GSList const* i = this->draggables; i != NULL; i = i->next) {
         GrDraggable *draggable = (GrDraggable *) i->data;
-        if (draggable->point_num == point_num && draggable->item == item && draggable->fill_or_stroke == fill_or_stroke) {
+        if ( (draggable->point_type == point_type) && (draggable->point_i == point_i) && (draggable->item == item) && (draggable->fill_or_stroke == fill_or_stroke) ) {
             return true;
         }
     }
@@ -603,8 +610,8 @@ GrDraggable::mayMerge (GrDraggable *da2)
 {
     if ((this->item == da2->item) && (this->fill_or_stroke == da2->fill_or_stroke)) {
         // we must not merge the points of the same gradient!
-        if (!((this->point_num == POINT_RG_FOCUS && da2->point_num == POINT_RG_CENTER) ||
-              (this->point_num == POINT_RG_CENTER && da2->point_num == POINT_RG_FOCUS))) {
+        if (!((this->point_type == POINT_RG_FOCUS && da2->point_type == POINT_RG_CENTER) ||
+              (this->point_type == POINT_RG_CENTER && da2->point_type == POINT_RG_FOCUS))) {
             // except that we can snap center and focus together
             return false;
         }
@@ -655,7 +662,7 @@ GrDragger::updateTip ()
         GrDraggable *draggable = (GrDraggable *) this->draggables->data;
         char *item_desc = sp_item_description(draggable->item);
         this->knot->tip = g_strdup_printf (_("%s for: %s%s; drag with <b>Ctrl</b> to snap angle, with <b>Ctrl+Alt</b> to preserve angle, with <b>Ctrl+Shift</b> to scale around center"),
-                                           _(gr_knot_descr[draggable->point_num]),
+                                           _(gr_knot_descr[draggable->point_type]),
                                            item_desc,
                                            draggable->fill_or_stroke == false ? _(" (stroke)") : "");
         g_free(item_desc);
@@ -679,7 +686,7 @@ GrDragger::updateKnotShape ()
     if (!draggables)
         return;
     GrDraggable *last = (GrDraggable *) g_slist_last(draggables)->data;
-    g_object_set (G_OBJECT (this->knot->item), "shape", gr_knot_shapes[last->point_num], NULL);
+    g_object_set (G_OBJECT (this->knot->item), "shape", gr_knot_shapes[last->point_type], NULL);
 }
 
 /**
@@ -698,19 +705,19 @@ GrDragger::addDraggable (GrDraggable *draggable)
 Moves this dragger to the point of the given draggable, acting upon all other draggables
  */
 void
-GrDragger::moveThisToDraggable (SPItem *item, guint point_num, bool fill_or_stroke, bool write_repr)
+GrDragger::moveThisToDraggable (SPItem *item, guint point_type, guint point_i, bool fill_or_stroke, bool write_repr)
 {
-    this->point = sp_item_gradient_get_coords (item, point_num, fill_or_stroke);
+    this->point = sp_item_gradient_get_coords (item, point_type, point_i, fill_or_stroke);
     this->point_original = this->point;
 
     sp_knot_moveto (this->knot, &(this->point));
 
     for (GSList const* i = this->draggables; i != NULL; i = i->next) {
         GrDraggable *da = (GrDraggable *) i->data;
-        if (da->item == item && da->point_num == point_num && da->fill_or_stroke == fill_or_stroke) {
+        if ( (da->item == item) && (da->point_type == point_type) && (da->point_i == point_i) && (da->fill_or_stroke == fill_or_stroke) ) {
             continue;
         }
-        sp_item_gradient_set_coords (da->item, da->point_num, this->point, da->fill_or_stroke, write_repr, false);
+        sp_item_gradient_set_coords (da->item, da->point_type, da->point_i, this->point, da->fill_or_stroke, write_repr, false);
     }
     // FIXME: here we should also call this->updateDependencies(write_repr); to propagate updating, but how to prevent loops?
 }
@@ -724,26 +731,52 @@ GrDragger::updateDependencies (bool write_repr)
 {
     for (GSList const* i = this->draggables; i != NULL; i = i->next) {
         GrDraggable *draggable = (GrDraggable *) i->data;
-        switch (draggable->point_num) {
-            case POINT_LG_P1:
-                // the other point is dependent only when dragging with ctrl+shift
-                this->moveOtherToDraggable (draggable->item, POINT_LG_P2, draggable->fill_or_stroke, write_repr);
+        switch (draggable->point_type) {
+            case POINT_LG_BEGIN:
+                {
+                    // the end point is dependent only when dragging with ctrl+shift
+                    this->moveOtherToDraggable (draggable->item, POINT_LG_END, 0, draggable->fill_or_stroke, write_repr);
+                    
+                    // update all midpoints.
+                    SPObject *server = SP_OBJECT_STYLE_FILL_SERVER (draggable->item);
+                    guint num = SP_GRADIENT(server)->vector.stops.size();
+                    if (num > 2) {
+                        for ( guint i = 1; i < num - 1; i++ ) {
+                            this->moveOtherToDraggable (draggable->item, POINT_LG_MID, i, draggable->fill_or_stroke, write_repr);
+                        }
+                    }
+                }
                 break;
-            case POINT_LG_P2:
-                this->moveOtherToDraggable (draggable->item, POINT_LG_P1, draggable->fill_or_stroke, write_repr);
+            case POINT_LG_END:
+                {
+                    // the begin point is dependent only when dragging with ctrl+shift
+                    this->moveOtherToDraggable (draggable->item, POINT_LG_BEGIN, 0, draggable->fill_or_stroke, write_repr);
+    
+                    // update all midpoints.
+                    SPObject *server = SP_OBJECT_STYLE_FILL_SERVER (draggable->item);
+                    guint num = SP_GRADIENT(server)->vector.stops.size();
+                    if (num > 2) {
+                        for ( guint i = 1; i < num - 1; i++ ) {
+                            this->moveOtherToDraggable (draggable->item, POINT_LG_MID, i, draggable->fill_or_stroke, write_repr);
+                        }
+                    } 
+                }
+                break;
+            case POINT_LG_MID:
+                // no other nodes depend on mid points.
                 break;
             case POINT_RG_R2:
-                this->moveOtherToDraggable (draggable->item, POINT_RG_R1, draggable->fill_or_stroke, write_repr);
-                this->moveOtherToDraggable (draggable->item, POINT_RG_FOCUS, draggable->fill_or_stroke, write_repr);
+                this->moveOtherToDraggable (draggable->item, POINT_RG_R1, 0, draggable->fill_or_stroke, write_repr);
+                this->moveOtherToDraggable (draggable->item, POINT_RG_FOCUS, 0, draggable->fill_or_stroke, write_repr);
                 break;
             case POINT_RG_R1:
-                this->moveOtherToDraggable (draggable->item, POINT_RG_R2, draggable->fill_or_stroke, write_repr);
-                this->moveOtherToDraggable (draggable->item, POINT_RG_FOCUS, draggable->fill_or_stroke, write_repr);
+                this->moveOtherToDraggable (draggable->item, POINT_RG_R2, 0, draggable->fill_or_stroke, write_repr);
+                this->moveOtherToDraggable (draggable->item, POINT_RG_FOCUS, 0, draggable->fill_or_stroke, write_repr);
                 break;
             case POINT_RG_CENTER:
-                this->moveOtherToDraggable (draggable->item, POINT_RG_R1, draggable->fill_or_stroke, write_repr);
-                this->moveOtherToDraggable (draggable->item, POINT_RG_R2, draggable->fill_or_stroke, write_repr);
-                this->moveOtherToDraggable (draggable->item, POINT_RG_FOCUS, draggable->fill_or_stroke, write_repr);
+                this->moveOtherToDraggable (draggable->item, POINT_RG_R1, 0, draggable->fill_or_stroke, write_repr);
+                this->moveOtherToDraggable (draggable->item, POINT_RG_R2, 0, draggable->fill_or_stroke, write_repr);
+                this->moveOtherToDraggable (draggable->item, POINT_RG_FOCUS, 0, draggable->fill_or_stroke, write_repr);
                 break;
             case POINT_RG_FOCUS:
                 // nothing can depend on that
@@ -809,13 +842,13 @@ GrDragger::~GrDragger ()
 Select the dragger which has the given draggable.
 */
 GrDragger *
-GrDrag::getDraggerFor (SPItem *item, guint point_num, bool fill_or_stroke)
+GrDrag::getDraggerFor (SPItem *item, guint point_type, guint point_i, bool fill_or_stroke)
 {
     for (GList const* i = this->draggers; i != NULL; i = i->next) {
         GrDragger *dragger = (GrDragger *) i->data;
         for (GSList const* j = dragger->draggables; j != NULL; j = j->next) {
             GrDraggable *da2 = (GrDraggable *) j->data;
-            if (da2->item == item && da2->point_num == point_num && da2->fill_or_stroke == fill_or_stroke) {
+            if ( (da2->item == item) && (da2->point_type == point_type) && (da2->point_i == point_i) && (da2->fill_or_stroke == fill_or_stroke)) {
                 return (dragger);
             }
         }
@@ -825,11 +858,11 @@ GrDrag::getDraggerFor (SPItem *item, guint point_num, bool fill_or_stroke)
 
 
 void
-GrDragger::moveOtherToDraggable (SPItem *item, guint point_num, bool fill_or_stroke, bool write_repr)
+GrDragger::moveOtherToDraggable (SPItem *item, guint point_type, guint point_i, bool fill_or_stroke, bool write_repr)
 {
-    GrDragger *d = this->parent->getDraggerFor (item, point_num, fill_or_stroke);
+    GrDragger *d = this->parent->getDraggerFor (item, point_type, point_i, fill_or_stroke);
     if (d && d !=  this) {
-        d->moveThisToDraggable (item, point_num, fill_or_stroke, write_repr);
+        d->moveThisToDraggable (item, point_type, point_i, fill_or_stroke, write_repr);
     }
 }
 
@@ -875,7 +908,7 @@ new dragger and add it to draggers list
 void
 GrDrag::addDragger (GrDraggable *draggable)
 {
-    NR::Point p = sp_item_gradient_get_coords (draggable->item, draggable->point_num, draggable->fill_or_stroke);
+    NR::Point p = sp_item_gradient_get_coords (draggable->item, draggable->point_type, draggable->point_i, draggable->fill_or_stroke);
 
     for (GList *i = this->draggers; i != NULL; i = i->next) {
         GrDragger *dragger = (GrDragger *) i->data;
@@ -897,10 +930,10 @@ Add draggers for the radial gradient rg on item
 void
 GrDrag::addDraggersRadial (SPRadialGradient *rg, SPItem *item, bool fill_or_stroke)
 {
-    addDragger (new GrDraggable (item, POINT_RG_CENTER, fill_or_stroke));
-    addDragger (new GrDraggable (item, POINT_RG_FOCUS, fill_or_stroke));
-    addDragger (new GrDraggable (item, POINT_RG_R1, fill_or_stroke));
-    addDragger (new GrDraggable (item, POINT_RG_R2, fill_or_stroke));
+    addDragger (new GrDraggable (item, POINT_RG_CENTER, 0, fill_or_stroke));
+    addDragger (new GrDraggable (item, POINT_RG_FOCUS, 0, fill_or_stroke));
+    addDragger (new GrDraggable (item, POINT_RG_R1, 0, fill_or_stroke));
+    addDragger (new GrDraggable (item, POINT_RG_R2, 0, fill_or_stroke));
 }
 
 /**
@@ -909,17 +942,26 @@ Add draggers for the linear gradient lg on item
 void
 GrDrag::addDraggersLinear (SPLinearGradient *lg, SPItem *item, bool fill_or_stroke)
 {
-    addDragger (new GrDraggable (item, POINT_LG_P1, fill_or_stroke));
-    addDragger (new GrDraggable (item, POINT_LG_P2, fill_or_stroke));
+    addDragger (new GrDraggable (item, POINT_LG_BEGIN, 0, fill_or_stroke));
+    
+    // add midstops if any:
+    guint num = lg->vector.stops.size();
+    if (num > 2) {
+        for ( guint i = 1; i < num - 1; i++ ) {
+            addDragger (new GrDraggable (item, POINT_LG_MID, i, fill_or_stroke));
+        }
+    }
+
+    addDragger (new GrDraggable (item, POINT_LG_END, 0, fill_or_stroke));
 }
 
 /**
 Artificially grab the knot of the dragger with this draggable; used by the gradient context
 */
 void
-GrDrag::grabKnot (SPItem *item, guint point_num, bool fill_or_stroke, gint x, gint y, guint32 etime)
+GrDrag::grabKnot (SPItem *item, guint point_type, guint point_i, bool fill_or_stroke, gint x, gint y, guint32 etime)
 {
-    GrDragger *dragger = getDraggerFor (item, point_num, fill_or_stroke);
+    GrDragger *dragger = getDraggerFor (item, point_type, point_i, fill_or_stroke);
     if (dragger) {
         sp_knot_start_dragging (dragger->knot, dragger->point, x, y, etime);
     }
@@ -994,22 +1036,22 @@ GrDrag::updateLines ()
         if (style && (style->fill.type == SP_PAINT_TYPE_PAINTSERVER)) {
             SPObject *server = SP_OBJECT_STYLE_FILL_SERVER (item);
             if (SP_IS_LINEARGRADIENT (server)) {
-                this->addLine (sp_item_gradient_get_coords (item, POINT_LG_P1, true), sp_item_gradient_get_coords (item, POINT_LG_P2, true), GR_LINE_COLOR_FILL);
+                this->addLine (sp_item_gradient_get_coords (item, POINT_LG_BEGIN, 0, true), sp_item_gradient_get_coords (item, POINT_LG_END, 0, true), GR_LINE_COLOR_FILL);
             } else if (SP_IS_RADIALGRADIENT (server)) {
-                NR::Point center = sp_item_gradient_get_coords (item, POINT_RG_CENTER, true);
-                this->addLine (center, sp_item_gradient_get_coords (item, POINT_RG_R1, true), GR_LINE_COLOR_FILL);
-                this->addLine (center, sp_item_gradient_get_coords (item, POINT_RG_R2, true), GR_LINE_COLOR_FILL);
+                NR::Point center = sp_item_gradient_get_coords (item, POINT_RG_CENTER, 0, true);
+                this->addLine (center, sp_item_gradient_get_coords (item, POINT_RG_R1, 0, true), GR_LINE_COLOR_FILL);
+                this->addLine (center, sp_item_gradient_get_coords (item, POINT_RG_R2, 0, true), GR_LINE_COLOR_FILL);
             }
         }
 
         if (style && (style->stroke.type == SP_PAINT_TYPE_PAINTSERVER)) {
             SPObject *server = SP_OBJECT_STYLE_STROKE_SERVER (item);
             if (SP_IS_LINEARGRADIENT (server)) {
-                this->addLine (sp_item_gradient_get_coords (item, POINT_LG_P1, false), sp_item_gradient_get_coords (item, POINT_LG_P2, false), GR_LINE_COLOR_STROKE);
+                this->addLine (sp_item_gradient_get_coords (item, POINT_LG_BEGIN, 0, false), sp_item_gradient_get_coords (item, POINT_LG_END, 0, false), GR_LINE_COLOR_STROKE);
             } else if (SP_IS_RADIALGRADIENT (server)) {
-                NR::Point center = sp_item_gradient_get_coords (item, POINT_RG_CENTER, false);
-                this->addLine (center, sp_item_gradient_get_coords (item, POINT_RG_R1, false), GR_LINE_COLOR_STROKE);
-                this->addLine (center, sp_item_gradient_get_coords (item, POINT_RG_R2, false), GR_LINE_COLOR_STROKE);
+                NR::Point center = sp_item_gradient_get_coords (item, POINT_RG_CENTER, 0, false);
+                this->addLine (center, sp_item_gradient_get_coords (item, POINT_RG_R1, 0, false), GR_LINE_COLOR_STROKE);
+                this->addLine (center, sp_item_gradient_get_coords (item, POINT_RG_R2, 0, false), GR_LINE_COLOR_STROKE);
             }
         }
     }
index 365da9b9253beb43b7a6221aa23daca0f2c94754..72e9ce0dd5a31d30d6b87f4ad8becf0306edaf03 100644 (file)
@@ -27,21 +27,22 @@ class Point;
 
 /**
 This class represents a single draggable point of a gradient. It remembers the item
-which has the gradient, whether it's fill or stroke, and the point number (from the
-GrPoint enum).
+which has the gradient, whether it's fill or stroke, the point type (from the
+GrPointType enum), and the point number (needed if more than 2 stops are present).
 */
 struct GrDraggable {
-       GrDraggable(SPItem *item, guint point_num, bool fill_or_stroke);
+       GrDraggable(SPItem *item, guint point_type, guint point_i, bool fill_or_stroke);
        ~GrDraggable();
 
        SPItem *item;
-       guint point_num;
+       guint point_type;
+       guint point_i;  // the stop number of this point ( = 0 for all types except POINT_LG_MID)
        bool fill_or_stroke;
 
        bool mayMerge (GrDraggable *da2);
 
     inline int equals (GrDraggable *other) {
-               return ((item == other->item) && (point_num == other->point_num) && (fill_or_stroke == other->fill_or_stroke));
+               return ((item == other->item) && (point_type == other->point_type) && (point_i == other->point_i) && (fill_or_stroke == other->fill_or_stroke));
     }
 };
 
@@ -75,15 +76,15 @@ struct GrDragger {
        void updateKnotShape();
        void updateTip();
 
-       void moveThisToDraggable (SPItem *item, guint point_num, bool fill_or_stroke, bool write_repr);
-       void moveOtherToDraggable (SPItem *item, guint point_num, bool fill_or_stroke, bool write_repr);
+       void moveThisToDraggable (SPItem *item, guint point_type, guint point_i, bool fill_or_stroke, bool write_repr);
+       void moveOtherToDraggable (SPItem *item, guint point_type, guint point_i, bool fill_or_stroke, bool write_repr);
        void updateDependencies (bool write_repr);
 
        bool mayMerge (GrDragger *other);
        bool mayMerge (GrDraggable *da2);
 
-       bool isA (guint point_num);
-       bool isA (SPItem *item, guint point_num, bool fill_or_stroke);
+       bool isA (guint point_type);
+       bool isA (SPItem *item, guint point_type, guint point_i, bool fill_or_stroke);
 
        void fireDraggables (bool write_repr, bool scale_radial = false, bool merging_focus = false);
 };
@@ -106,9 +107,9 @@ struct GrDrag {
        GrDragger *selected;
        void setSelected (GrDragger *dragger);
 
-       GrDragger *getDraggerFor (SPItem *item, guint point_num, bool fill_or_stroke);
+       GrDragger *getDraggerFor (SPItem *item, guint point_type, guint point_i, bool fill_or_stroke);
 
-       void grabKnot (SPItem *item, guint point_num, bool fill_or_stroke, gint x, gint y, guint32 etime);
+       void grabKnot (SPItem *item, guint point_type, guint point_i, bool fill_or_stroke, gint x, gint y, guint32 etime);
 
        bool local_change;
 
index b0ed49c0023d8205c8c6202da7870899eda718cb..de5247c1c57fc2499a1353a05d8772c708b13fcb 100644 (file)
@@ -37,13 +37,14 @@ typedef enum {
 } SPGradientState;
 
 typedef enum {
-    POINT_LG_P1,
-    POINT_LG_P2,
+    POINT_LG_BEGIN,
+    POINT_LG_END,
+    POINT_LG_MID,
     POINT_RG_CENTER,
     POINT_RG_R1,
     POINT_RG_R2,
     POINT_RG_FOCUS
-} GrPoint;
+} GrPointType;
 
 /**
  * Gradient