diff --git a/app/vectors/gimpbezierstroke.c b/app/vectors/gimpbezierstroke.c index 0fd1256bed..113664575e 100644 --- a/app/vectors/gimpbezierstroke.c +++ b/app/vectors/gimpbezierstroke.c @@ -129,6 +129,11 @@ static gboolean GimpAnchor *anchor, GimpStroke *extension, GimpAnchor *neighbor); +static gboolean + gimp_bezier_stroke_reverse (GimpStroke *stroke); +static gboolean + gimp_bezier_stroke_shift_start (GimpStroke *stroke, + GimpAnchor *anchor); static GArray * gimp_bezier_stroke_interpolate (GimpStroke *stroke, gdouble precision, @@ -176,6 +181,8 @@ gimp_bezier_stroke_class_init (GimpBezierStrokeClass *klass) stroke_class->is_extendable = gimp_bezier_stroke_is_extendable; stroke_class->extend = gimp_bezier_stroke_extend; stroke_class->connect_stroke = gimp_bezier_stroke_connect_stroke; + stroke_class->reverse = gimp_bezier_stroke_reverse; + stroke_class->shift_start = gimp_bezier_stroke_shift_start; stroke_class->interpolate = gimp_bezier_stroke_interpolate; stroke_class->make_bezier = gimp_bezier_stroke_make_bezier; stroke_class->transform = gimp_bezier_stroke_transform; @@ -1324,6 +1331,63 @@ gimp_bezier_stroke_connect_stroke (GimpStroke *stroke, } +static gboolean +gimp_bezier_stroke_reverse (GimpStroke *stroke) +{ + g_return_val_if_fail (GIMP_IS_BEZIER_STROKE (stroke), FALSE); + + g_queue_reverse (stroke->anchors); + + /* keep the first nodegroup the same for closed strokes */ + if (stroke->closed && stroke->anchors->length >= 3) + { + g_queue_push_head_link (stroke->anchors, + g_queue_pop_tail_link (stroke->anchors)); + g_queue_push_head_link (stroke->anchors, + g_queue_pop_tail_link (stroke->anchors)); + g_queue_push_head_link (stroke->anchors, + g_queue_pop_tail_link (stroke->anchors)); + } + + return TRUE; +} + + +static gboolean +gimp_bezier_stroke_shift_start (GimpStroke *stroke, + GimpAnchor *new_start) +{ + GList *link; + + g_return_val_if_fail (GIMP_IS_BEZIER_STROKE (stroke), FALSE); + g_return_val_if_fail (new_start != NULL, FALSE); + g_return_val_if_fail (new_start->type == GIMP_ANCHOR_ANCHOR, FALSE); + + link = g_queue_find (stroke->anchors, new_start); + if (!link) + return FALSE; + + /* the preceding control anchor will be the new head */ + + link = g_list_previous (link); + if (!link) + return FALSE; + + if (link == stroke->anchors->head) + return TRUE; + + stroke->anchors->tail->next = stroke->anchors->head; + stroke->anchors->head->prev = stroke->anchors->tail; + stroke->anchors->tail = link->prev; + stroke->anchors->head = link; + stroke->anchors->tail->next = NULL; + stroke->anchors->head->prev = NULL; + + return TRUE; + +} + + static void gimp_bezier_stroke_anchor_move_relative (GimpStroke *stroke, GimpAnchor *anchor, diff --git a/app/vectors/gimpstroke.c b/app/vectors/gimpstroke.c index 6d1f1159fa..a9725c5de6 100644 --- a/app/vectors/gimpstroke.c +++ b/app/vectors/gimpstroke.c @@ -123,6 +123,9 @@ gboolean gimp_stroke_real_connect_stroke (GimpStroke *stroke, static gboolean gimp_stroke_real_is_empty (GimpStroke *stroke); +static gboolean gimp_stroke_real_reverse (GimpStroke *stroke); +static gboolean gimp_stroke_real_shift_start (GimpStroke *stroke, + GimpAnchor *anchor); static gdouble gimp_stroke_real_get_length (GimpStroke *stroke, gdouble precision); @@ -213,6 +216,8 @@ gimp_stroke_class_init (GimpStrokeClass *klass) klass->connect_stroke = gimp_stroke_real_connect_stroke; klass->is_empty = gimp_stroke_real_is_empty; + klass->reverse = gimp_stroke_real_reverse; + klass->shift_start = gimp_stroke_real_shift_start; klass->get_length = gimp_stroke_real_get_length; klass->get_distance = gimp_stroke_real_get_distance; klass->get_point_at_dist = gimp_stroke_real_get_point_at_dist; @@ -893,6 +898,63 @@ gimp_stroke_real_is_empty (GimpStroke *stroke) } +gboolean +gimp_stroke_reverse (GimpStroke *stroke) +{ + g_return_val_if_fail (GIMP_IS_STROKE (stroke), FALSE); + + return GIMP_STROKE_GET_CLASS (stroke)->reverse (stroke); +} + + +static gboolean +gimp_stroke_real_reverse (GimpStroke *stroke) +{ + g_queue_reverse (stroke->anchors); + + /* keep the first node the same for closed strokes */ + if (stroke->closed && stroke->anchors->length > 0) + g_queue_push_head_link (stroke->anchors, + g_queue_pop_tail_link (stroke->anchors)); + + return TRUE; +} + + +gboolean +gimp_stroke_shift_start (GimpStroke *stroke, + GimpAnchor *new_start) +{ + g_return_val_if_fail (GIMP_IS_STROKE (stroke), FALSE); + g_return_val_if_fail (new_start != NULL, FALSE); + + return GIMP_STROKE_GET_CLASS (stroke)->shift_start (stroke, new_start); +} + +static gboolean +gimp_stroke_real_shift_start (GimpStroke *stroke, + GimpAnchor *new_start) +{ + GList *link; + + link = g_queue_find (stroke->anchors, new_start); + if (!link) + return FALSE; + + if (link == stroke->anchors->head) + return TRUE; + + stroke->anchors->tail->next = stroke->anchors->head; + stroke->anchors->head->prev = stroke->anchors->tail; + stroke->anchors->tail = link->prev; + stroke->anchors->head = link; + stroke->anchors->tail->next = NULL; + stroke->anchors->head->prev = NULL; + + return TRUE; +} + + gdouble gimp_stroke_get_length (GimpStroke *stroke, gdouble precision) diff --git a/app/vectors/gimpstroke.h b/app/vectors/gimpstroke.h index b220d77f35..69e14de74a 100644 --- a/app/vectors/gimpstroke.h +++ b/app/vectors/gimpstroke.h @@ -132,6 +132,10 @@ struct _GimpStrokeClass GimpAnchor *neighbor); gboolean (* is_empty) (GimpStroke *stroke); + gboolean (* reverse) (GimpStroke *stroke); + gboolean (* shift_start) (GimpStroke *stroke, + GimpAnchor *new_start); + gdouble (* get_length) (GimpStroke *stroke, gdouble precision); gdouble (* get_distance) (GimpStroke *stroke, @@ -289,6 +293,10 @@ gboolean gimp_stroke_connect_stroke (GimpStroke *stroke, gboolean gimp_stroke_is_empty (GimpStroke *stroke); +gboolean gimp_stroke_reverse (GimpStroke *stroke); +gboolean gimp_stroke_shift_start (GimpStroke *stroke, + GimpAnchor *new_start); + /* accessing the shape of the curve */ gdouble gimp_stroke_get_length (GimpStroke *stroke,