Implement asymmetric and free handles type for masks
authorSergey Sharybin <sergey.vfx@gmail.com>
Wed, 30 Oct 2013 09:38:45 +0000 (10:38 +0100)
committerSergey Sharybin <sergey.vfx@gmail.com>
Fri, 28 Mar 2014 11:54:38 +0000 (17:54 +0600)
Summary:
The title actually says it all, it's just possible to
have independent free handles for mask splines. Also
it's now possible to have aligned handles displayed
as independent handles.

Required changes in quite a few places, but they're
rather straightforward.

From user perspective there's one really visible change
which is removed Handle Type menu from the panel. With
asymmetric handles it's not clear which handle type to
display there. So now the only way to change handle type
is via V-key menu.

Rewrote normal evaluation function to make it deal
with new type of handles we support. Now it works in
the following way:

- Offset the original spline by maximal weight
- Calculate vector between corresponding U positions
  on offset and original spline
- Normalize this vector.

Seems to be giving more adequate results and doesn't
tend to self-intersect as much as old behavior used to,

There're still some changes which needed to be done, but
which are planned for further patch:

- Support colors and handle size via themes.
- Make handles color-coded, just the same as done for
  regular bezier splines in 3D viewport.

Additional changes to make roto workflow even better:
- Use circles to draw handles
- Support AA for handles
- Change click-create-drag to change curvature of the
  spline instead of adjusting point position.

Reviewers: campbellbarton

CC: sebastian_k, hype, cronk
Differential Revision: http://developer.blender.org/D121

15 files changed:
release/scripts/startup/bl_ui/properties_mask_common.py
source/blender/blenkernel/BKE_mask.h
source/blender/blenkernel/intern/curve.c
source/blender/blenkernel/intern/mask.c
source/blender/editors/interface/resources.c
source/blender/editors/mask/mask_add.c
source/blender/editors/mask/mask_draw.c
source/blender/editors/mask/mask_edit.c
source/blender/editors/mask/mask_intern.h
source/blender/editors/mask/mask_ops.c
source/blender/editors/mask/mask_select.c
source/blender/editors/transform/transform_conversions.c
source/blender/makesdna/DNA_curve_types.h
source/blender/makesrna/intern/rna_mask.c
source/blender/makesrna/intern/rna_userdef.c

index cd659e1e5fe7e07a2e433e663e36e7a4a48dd41c..eef7b00f0be426d1655b647092d3451efcdfc157 100644 (file)
@@ -172,9 +172,6 @@ class MASK_PT_point():
         point = mask.layers.active.splines.active_point
         parent = point.parent
 
-        col = layout.column()
-        col.prop(point, "handle_type")
-
         col = layout.column()
         # Currently only parenting yo movie clip is allowed, so do not
         # ver-oplicate things for now and use single template_ID
index 691afaf8f162bcc2d2dba0dbe04fc6703d100cbd..5dd0b14be6339722699b93c73569603edc676da7 100644 (file)
@@ -47,6 +47,20 @@ struct MovieClip;
 struct MovieClipUser;
 struct Scene;
 
+/* mask_ops.c */
+typedef enum {
+       MASK_WHICH_HANDLE_NONE  = 0,
+       MASK_WHICH_HANDLE_STICK = 1,
+       MASK_WHICH_HANDLE_LEFT  = 2,
+       MASK_WHICH_HANDLE_RIGHT = 3,
+       MASK_WHICH_HANDLE_BOTH  = 4,
+} eMaskWhichHandle;
+
+typedef enum {
+       MASK_HANDLE_MODE_STICK = 1,
+       MASK_HANDLE_MODE_INDIVIDUAL_HANDLES = 2,
+} eMaskhandleMode;
+
 struct MaskSplinePoint *BKE_mask_spline_point_array(struct MaskSpline *spline);
 struct MaskSplinePoint *BKE_mask_spline_point_array_from_point(struct MaskSpline *spline, struct MaskSplinePoint *point_ref);
 
@@ -87,9 +101,9 @@ float BKE_mask_spline_project_co(struct MaskSpline *spline, struct MaskSplinePoi
                                  float start_u, const float co[2], const eMaskSign sign);
 
 /* point */
-bool BKE_mask_point_has_handle(struct MaskSplinePoint *point);
-void BKE_mask_point_handle(struct MaskSplinePoint *point, float handle[2]);
-void BKE_mask_point_set_handle(struct MaskSplinePoint *point, float loc[2], bool keep_direction,
+eMaskhandleMode BKE_mask_point_handles_mode_get(struct MaskSplinePoint *point);
+void BKE_mask_point_handle(struct MaskSplinePoint *point, eMaskWhichHandle which_handle, float handle[2]);
+void BKE_mask_point_set_handle(struct MaskSplinePoint *point, eMaskWhichHandle which_handle, float loc[2], bool keep_direction,
                                float orig_handle[2], float orig_vec[3][3]);
 
 void BKE_mask_point_segment_co(struct MaskSpline *spline, struct MaskSplinePoint *point, float u, float co[2]);
@@ -101,7 +115,7 @@ struct MaskSplinePointUW *BKE_mask_point_sort_uw(struct MaskSplinePoint *point,
 void BKE_mask_point_add_uw(struct MaskSplinePoint *point, float u, float w);
 
 void BKE_mask_point_select_set(struct MaskSplinePoint *point, const bool do_select);
-void BKE_mask_point_select_set_handle(struct MaskSplinePoint *point, const bool do_select);
+void BKE_mask_point_select_set_handle(struct MaskSplinePoint *point, const eMaskWhichHandle which_handle, const bool do_select);
 
 /* general */
 struct Mask *BKE_mask_new(struct Main *bmain, const char *name);
@@ -176,16 +190,18 @@ void BKE_mask_clipboard_paste_to_layer(struct Main *bmain, struct MaskLayer *mas
 
 #define MASKPOINT_ISSEL_ANY(p)          ( ((p)->bezt.f1 | (p)->bezt.f2 | (p)->bezt.f3) & SELECT)
 #define MASKPOINT_ISSEL_KNOT(p)         ( (p)->bezt.f2 & SELECT)
-#define MASKPOINT_ISSEL_HANDLE_ONLY(p)  ( (((p)->bezt.f1 | (p)->bezt.f3) & SELECT) && (((p)->bezt.f2 & SELECT) == 0) )
-#define MASKPOINT_ISSEL_HANDLE(p)       ( (((p)->bezt.f1 | (p)->bezt.f3) & SELECT) )
+
+#define MASKPOINT_ISSEL_HANDLE(point, which_handle) \
+       ((which_handle == MASK_WHICH_HANDLE_STICK) ? \
+       ((((point)->bezt.f1 | (point)->bezt.f3) & SELECT)) : \
+       ((which_handle == MASK_WHICH_HANDLE_LEFT) ? \
+       ((point)->bezt.f1 & SELECT) : \
+       ((point)->bezt.f3 & SELECT)))
 
 #define MASKPOINT_SEL_ALL(p)    { (p)->bezt.f1 |=  SELECT; (p)->bezt.f2 |=  SELECT; (p)->bezt.f3 |=  SELECT; } (void)0
 #define MASKPOINT_DESEL_ALL(p)  { (p)->bezt.f1 &= ~SELECT; (p)->bezt.f2 &= ~SELECT; (p)->bezt.f3 &= ~SELECT; } (void)0
 #define MASKPOINT_INVSEL_ALL(p) { (p)->bezt.f1 ^=  SELECT; (p)->bezt.f2 ^=  SELECT; (p)->bezt.f3 ^=  SELECT; } (void)0
 
-#define MASKPOINT_SEL_HANDLE(p)     { (p)->bezt.f1 |=  SELECT; (p)->bezt.f3 |=  SELECT; } (void)0
-#define MASKPOINT_DESEL_HANDLE(p)   { (p)->bezt.f1 &= ~SELECT; (p)->bezt.f3 &= ~SELECT; } (void)0
-
 #define MASK_RESOL_MAX 128
 
 
index 44c9bc9ebbe095129fc64513f50e3d2ff0ee08f6..0ce2953a2e3d23a8b99cb7f9b7d5e6feee69aa95 100644 (file)
@@ -3080,7 +3080,7 @@ static void calchandleNurb_intern(BezTriple *bezt, BezTriple *prev, BezTriple *n
                madd_v3_v3v3fl(p2_h2, p2, dvec_b,  1.0f / 3.0f);
        }
 
-       if (skip_align || !ELEM(HD_ALIGN, bezt->h1, bezt->h2)) {
+       if (skip_align || (!ELEM(HD_ALIGN, bezt->h1, bezt->h2) && !ELEM(HD_ALIGN_DOUBLESIDE, bezt->h1, bezt->h2))) {
                /* handles need to be updated during animation and applying stuff like hooks,
                 * but in such situations it's quite difficult to distinguish in which order
                 * align handles should be aligned so skip them for now */
@@ -3095,7 +3095,7 @@ static void calchandleNurb_intern(BezTriple *bezt, BezTriple *prev, BezTriple *n
                len_b = 1.0f;
 
        if (bezt->f1 & SELECT) { /* order of calculation */
-               if (bezt->h2 == HD_ALIGN) { /* aligned */
+               if (ELEM(bezt->h2, HD_ALIGN, HD_ALIGN_DOUBLESIDE)) { /* aligned */
                        if (len_a > eps) {
                                len = len_b / len_a;
                                p2_h2[0] = p2[0] + len * (p2[0] - p2_h1[0]);
@@ -3103,7 +3103,7 @@ static void calchandleNurb_intern(BezTriple *bezt, BezTriple *prev, BezTriple *n
                                p2_h2[2] = p2[2] + len * (p2[2] - p2_h1[2]);
                        }
                }
-               if (bezt->h1 == HD_ALIGN) {
+               if (ELEM(bezt->h1, HD_ALIGN, HD_ALIGN_DOUBLESIDE)) {
                        if (len_b > eps) {
                                len = len_a / len_b;
                                p2_h1[0] = p2[0] + len * (p2[0] - p2_h2[0]);
@@ -3113,7 +3113,7 @@ static void calchandleNurb_intern(BezTriple *bezt, BezTriple *prev, BezTriple *n
                }
        }
        else {
-               if (bezt->h1 == HD_ALIGN) {
+               if (ELEM(bezt->h1, HD_ALIGN, HD_ALIGN_DOUBLESIDE)) {
                        if (len_b > eps) {
                                len = len_a / len_b;
                                p2_h1[0] = p2[0] + len * (p2[0] - p2_h2[0]);
@@ -3121,7 +3121,7 @@ static void calchandleNurb_intern(BezTriple *bezt, BezTriple *prev, BezTriple *n
                                p2_h1[2] = p2[2] + len * (p2[2] - p2_h2[2]);
                        }
                }
-               if (bezt->h2 == HD_ALIGN) {   /* aligned */
+               if (ELEM(bezt->h2, HD_ALIGN, HD_ALIGN_DOUBLESIDE)) {   /* aligned */
                        if (len_a > eps) {
                                len = len_b / len_a;
                                p2_h2[0] = p2[0] + len * (p2[0] - p2_h1[0]);
index d08b7316e612d5b9c621670b6c43ad3844ef5809..8ea035e3249e947794e9ed92777ce143c0097cc6 100644 (file)
@@ -435,58 +435,87 @@ float BKE_mask_spline_project_co(MaskSpline *spline, MaskSplinePoint *point,
 
 /* point */
 
-bool BKE_mask_point_has_handle(MaskSplinePoint *point)
+eMaskhandleMode BKE_mask_point_handles_mode_get(MaskSplinePoint *point)
 {
        BezTriple *bezt = &point->bezt;
 
-       return bezt->h1 == HD_ALIGN;
+       if (bezt->h1 == bezt->h2 && bezt->h1 == HD_ALIGN) {
+               return MASK_HANDLE_MODE_STICK;
+       }
+
+       return MASK_HANDLE_MODE_INDIVIDUAL_HANDLES;
 }
 
-void BKE_mask_point_handle(MaskSplinePoint *point, float handle[2])
+void BKE_mask_point_handle(MaskSplinePoint *point, eMaskWhichHandle which_handle, float handle[2])
 {
-       float vec[2];
+       BezTriple *bezt = &point->bezt;
+
+       if (which_handle == MASK_WHICH_HANDLE_STICK) {
+               float vec[2];
 
-       sub_v2_v2v2(vec, point->bezt.vec[0], point->bezt.vec[1]);
+               sub_v2_v2v2(vec, bezt->vec[0], bezt->vec[1]);
 
-       handle[0] = (point->bezt.vec[1][0] + vec[1]);
-       handle[1] = (point->bezt.vec[1][1] - vec[0]);
+               handle[0] = (bezt->vec[1][0] + vec[1]);
+               handle[1] = (bezt->vec[1][1] - vec[0]);
+       }
+       else if (which_handle == MASK_WHICH_HANDLE_LEFT) {
+               copy_v2_v2(handle, bezt->vec[0]);
+       }
+       else if (which_handle == MASK_WHICH_HANDLE_RIGHT) {
+               copy_v2_v2(handle, bezt->vec[2]);
+       }
+       else {
+               BLI_assert(!"Unknown handle passed to BKE_mask_point_handle");
+       }
 }
 
-void BKE_mask_point_set_handle(MaskSplinePoint *point, float loc[2], bool keep_direction,
+void BKE_mask_point_set_handle(MaskSplinePoint *point, eMaskWhichHandle which_handle,
+                               float loc[2], bool keep_direction,
                                float orig_handle[2], float orig_vec[3][3])
 {
        BezTriple *bezt = &point->bezt;
-       float v1[2], v2[2], vec[2];
 
-       if (keep_direction) {
-               sub_v2_v2v2(v1, loc, orig_vec[1]);
-               sub_v2_v2v2(v2, orig_handle, orig_vec[1]);
+       if (which_handle == MASK_WHICH_HANDLE_STICK) {
+               float v1[2], v2[2], vec[2];
+               if (keep_direction) {
+                       sub_v2_v2v2(v1, loc, orig_vec[1]);
+                       sub_v2_v2v2(v2, orig_handle, orig_vec[1]);
 
-               project_v2_v2v2(vec, v1, v2);
+                       project_v2_v2v2(vec, v1, v2);
 
-               if (dot_v2v2(v2, vec) > 0) {
-                       float len = len_v2(vec);
+                       if (dot_v2v2(v2, vec) > 0) {
+                               float len = len_v2(vec);
 
-                       sub_v2_v2v2(v1, orig_vec[0], orig_vec[1]);
+                               sub_v2_v2v2(v1, orig_vec[0], orig_vec[1]);
 
-                       mul_v2_fl(v1, len / len_v2(v1));
+                               mul_v2_fl(v1, len / len_v2(v1));
 
-                       add_v2_v2v2(bezt->vec[0], bezt->vec[1], v1);
-                       sub_v2_v2v2(bezt->vec[2], bezt->vec[1], v1);
+                               add_v2_v2v2(bezt->vec[0], bezt->vec[1], v1);
+                               sub_v2_v2v2(bezt->vec[2], bezt->vec[1], v1);
+                       }
+                       else {
+                               copy_v3_v3(bezt->vec[0], bezt->vec[1]);
+                               copy_v3_v3(bezt->vec[2], bezt->vec[1]);
+                       }
                }
                else {
-                       copy_v3_v3(bezt->vec[0], bezt->vec[1]);
-                       copy_v3_v3(bezt->vec[2], bezt->vec[1]);
+                       sub_v2_v2v2(v1, loc, bezt->vec[1]);
+
+                       v2[0] = -v1[1];
+                       v2[1] =  v1[0];
+
+                       add_v2_v2v2(bezt->vec[0], bezt->vec[1], v2);
+                       sub_v2_v2v2(bezt->vec[2], bezt->vec[1], v2);
                }
        }
+       else if (which_handle == MASK_WHICH_HANDLE_LEFT) {
+               copy_v2_v2(bezt->vec[0], loc);
+       }
+       else if (which_handle == MASK_WHICH_HANDLE_RIGHT) {
+               copy_v2_v2(bezt->vec[2], loc);
+       }
        else {
-               sub_v2_v2v2(v1, loc, bezt->vec[1]);
-
-               v2[0] = -v1[1];
-               v2[1] =  v1[0];
-
-               add_v2_v2v2(bezt->vec[0], bezt->vec[1], v2);
-               sub_v2_v2v2(bezt->vec[2], bezt->vec[1], v2);
+               BLI_assert(!"unknown handle passed to BKE_mask_point_set_handle");
        }
 }
 
@@ -514,36 +543,68 @@ void BKE_mask_point_segment_co(MaskSpline *spline, MaskSplinePoint *point, float
        interp_v2_v2v2(co, r0, r1, u);
 }
 
+BLI_INLINE void orthogonal_direction_get(float vec[2], float result[2])
+{
+       result[0] = -vec[1];
+       result[1] = vec[0];
+       normalize_v2(result);
+}
+
+/* TODO(sergey): This function will re-calculate loads of stuff again and again
+ *               when differentiating feather points. This might be easily cached
+ *               in the callee function for this case.
+ */
 void BKE_mask_point_normal(MaskSpline *spline, MaskSplinePoint *point, float u, float n[2])
 {
-       MaskSplinePoint *points_array = BKE_mask_spline_point_array_from_point(spline, point);
 
-       BezTriple *bezt = &point->bezt, *bezt_next;
-       float q0[2], q1[2], q2[2], r0[2], r1[2], vec[2];
+       MaskSplinePoint *point_prev, *point_next;
 
-       bezt_next = BKE_mask_spline_point_next_bezt(spline, points_array, point);
+       /* TODO(sergey): This actually depends on a resolution. */
+       const float du = 0.05f;
 
-       if (!bezt_next) {
-               BKE_mask_point_handle(point, vec);
+       BKE_mask_get_handle_point_adjacent(spline, point, &point_prev, &point_next);
 
-               sub_v2_v2v2(n, vec, bezt->vec[1]);
-               normalize_v2(n);
-               return;
+       if (u - du < 0.0f && point_prev == NULL) {
+               float co[2], dir[2];
+               BKE_mask_point_segment_co(spline, point, u + du, co);
+               sub_v2_v2v2(dir, co, point->bezt.vec[1]);
+               orthogonal_direction_get(dir, n);
+       }
+       else if (u + du > 1.0f && point_next == NULL) {
+               float co[2], dir[2];
+               BKE_mask_point_segment_co(spline, point, u - du, co);
+               sub_v2_v2v2(dir, point->bezt.vec[1], co);
+               orthogonal_direction_get(dir, n);
        }
+       else {
+               float prev_co[2], next_co[2], co[2];
+               float dir1[2], dir2[2], dir[2];
 
-       interp_v2_v2v2(q0, bezt->vec[1], bezt->vec[2], u);
-       interp_v2_v2v2(q1, bezt->vec[2], bezt_next->vec[0], u);
-       interp_v2_v2v2(q2, bezt_next->vec[0], bezt_next->vec[1], u);
+               if (u - du < 0.0f) {
+                       BKE_mask_point_segment_co(spline, point_prev, 1.0f + (u - du), prev_co);
+               }
+               else {
+                       BKE_mask_point_segment_co(spline, point, u - du, prev_co);
+               }
 
-       interp_v2_v2v2(r0, q0, q1, u);
-       interp_v2_v2v2(r1, q1, q2, u);
+               BKE_mask_point_segment_co(spline, point, u, co);
+
+               if (u + du > 1.0f) {
+                       BKE_mask_point_segment_co(spline, point_next, u + du - 1.0f, next_co);
+               }
+               else {
+                       BKE_mask_point_segment_co(spline, point, u + du, next_co);
+               }
 
-       sub_v2_v2v2(vec, r1, r0);
+               sub_v2_v2v2(dir1, co, prev_co);
+               sub_v2_v2v2(dir2, next_co, co);
 
-       n[0] = -vec[1];
-       n[1] =  vec[0];
+               normalize_v2(dir1);
+               normalize_v2(dir2);
+               add_v2_v2v2(dir, dir1, dir2);
 
-       normalize_v2(n);
+               orthogonal_direction_get(dir, n);
+       }
 }
 
 static float mask_point_interp_weight(BezTriple *bezt, BezTriple *bezt_next, const float u)
@@ -693,13 +754,37 @@ void BKE_mask_point_select_set(MaskSplinePoint *point, const bool do_select)
        }
 }
 
-void BKE_mask_point_select_set_handle(MaskSplinePoint *point, const bool do_select)
+void BKE_mask_point_select_set_handle(MaskSplinePoint *point, const eMaskWhichHandle which_handle, const bool do_select)
 {
        if (do_select) {
-               MASKPOINT_SEL_HANDLE(point);
+               if (ELEM(which_handle, MASK_WHICH_HANDLE_STICK, MASK_WHICH_HANDLE_BOTH)) {
+                       point->bezt.f1 |= SELECT;
+                       point->bezt.f3 |= SELECT;
+               }
+               else if (which_handle == MASK_WHICH_HANDLE_LEFT) {
+                       point->bezt.f1 |= SELECT;
+               }
+               else if (which_handle == MASK_WHICH_HANDLE_RIGHT) {
+                       point->bezt.f3 |= SELECT;
+               }
+               else {
+                       BLI_assert(!"Wrong which_handle passed to BKE_mask_point_select_set_handle");
+               }
        }
        else {
-               MASKPOINT_DESEL_HANDLE(point);
+               if (ELEM(which_handle, MASK_WHICH_HANDLE_STICK, MASK_WHICH_HANDLE_BOTH)) {
+                       point->bezt.f1 &= ~SELECT;
+                       point->bezt.f3 &= ~SELECT;
+               }
+               else if (which_handle == MASK_WHICH_HANDLE_LEFT) {
+                       point->bezt.f1 &= ~SELECT;
+               }
+               else if (which_handle == MASK_WHICH_HANDLE_RIGHT) {
+                       point->bezt.f3 &= ~SELECT;
+               }
+               else {
+                       BLI_assert(!"Wrong which_handle passed to BKE_mask_point_select_set_handle");
+               }
        }
 }
 
@@ -1170,7 +1255,7 @@ static void mask_calc_point_handle(MaskSplinePoint *point, MaskSplinePoint *poin
        else if (handle_type == HD_AUTO) {
                BKE_nurb_handle_calc(bezt, bezt_prev, bezt_next, 0);
        }
-       else if (handle_type == HD_ALIGN) {
+       else if (handle_type == HD_ALIGN || handle_type == HD_ALIGN_DOUBLESIDE) {
                float v1[3], v2[3];
                float vec[3], h[3];
 
index a112106620fb6e3a15edc291104d1b2fb87f2a60..8e53f9d233235ea2d4ac94d3c7729b77a1252b33 100644 (file)
@@ -763,6 +763,18 @@ static void ui_theme_init_new(bTheme *btheme)
        }
 }
 
+static void ui_theme_space_init_handles_color(ThemeSpace *theme_space)
+{
+       rgba_char_args_set(theme_space->handle_free, 0, 0, 0, 255);
+       rgba_char_args_set(theme_space->handle_auto, 0x90, 0x90, 0x00, 255);
+       rgba_char_args_set(theme_space->handle_vect, 0x40, 0x90, 0x30, 255);
+       rgba_char_args_set(theme_space->handle_align, 0x80, 0x30, 0x60, 255);
+       rgba_char_args_set(theme_space->handle_sel_free, 0, 0, 0, 255);
+       rgba_char_args_set(theme_space->handle_sel_auto, 0xf0, 0xff, 0x40, 255);
+       rgba_char_args_set(theme_space->handle_sel_vect, 0x40, 0xc0, 0x30, 255);
+       rgba_char_args_set(theme_space->handle_sel_align, 0xf0, 0x90, 0xa0, 255);
+       rgba_char_args_set(theme_space->act_spline, 0xdb, 0x25, 0x12, 255);
+}
 
 /* initialize default theme
  * Note: when you add new colors, created & saved themes need initialized
@@ -873,14 +885,7 @@ void ui_theme_init_default(void)
        rgba_char_args_set(btheme->tv3d.nurb_sel_uline, 0xf0, 0xff, 0x40, 255);
        rgba_char_args_set(btheme->tv3d.nurb_sel_vline, 0xf0, 0x90, 0xa0, 255);
 
-       rgba_char_args_set(btheme->tv3d.handle_free, 0, 0, 0, 255);
-       rgba_char_args_set(btheme->tv3d.handle_auto, 0x90, 0x90, 0x00, 255);
-       rgba_char_args_set(btheme->tv3d.handle_vect, 0x40, 0x90, 0x30, 255);
-       rgba_char_args_set(btheme->tv3d.handle_align, 0x80, 0x30, 0x60, 255);
-       rgba_char_args_set(btheme->tv3d.handle_sel_free, 0, 0, 0, 255);
-       rgba_char_args_set(btheme->tv3d.handle_sel_auto, 0xf0, 0xff, 0x40, 255);
-       rgba_char_args_set(btheme->tv3d.handle_sel_vect, 0x40, 0xc0, 0x30, 255);
-       rgba_char_args_set(btheme->tv3d.handle_sel_align, 0xf0, 0x90, 0xa0, 255);
+       ui_theme_space_init_handles_color(&btheme->tv3d);
 
        rgba_char_args_set(btheme->tv3d.act_spline, 0xdb, 0x25, 0x12, 255);
        rgba_char_args_set(btheme->tv3d.lastsel_point,  0xff, 0xff, 0xff, 255);
@@ -1023,6 +1028,9 @@ void ui_theme_init_default(void)
        rgba_char_args_test_set(btheme->tima.uv_others, 96, 96, 96, 255);
        rgba_char_args_test_set(btheme->tima.uv_shadow, 112, 112, 112, 255);
 
+       ui_theme_space_init_handles_color(&btheme->tima);
+       btheme->tima.handle_vertex_size = 5;
+
        /* space text */
        btheme->text = btheme->tv3d;
        rgba_char_args_set(btheme->text.back,   153, 153, 153, 255);
@@ -1125,7 +1133,8 @@ void ui_theme_init_default(void)
        rgba_char_args_set(btheme->tclip.list, 0x66, 0x66, 0x66, 0xff);
        rgba_char_args_set(btheme->tclip.strip, 0x0c, 0x0a, 0x0a, 0x80);
        rgba_char_args_set(btheme->tclip.strip_select, 0xff, 0x8c, 0x00, 0xff);
-       btheme->tclip.handle_vertex_size = 4;
+       btheme->tclip.handle_vertex_size = 5;
+       ui_theme_space_init_handles_color(&btheme->tclip);
 }
 
 void ui_style_init_default(void)
@@ -1885,27 +1894,9 @@ void init_userdef_do_versions(void)
                
                /* init new curve colors */
                for (btheme = U.themes.first; btheme; btheme = btheme->next) {
-                       /* init colors used for handles in 3D-View  */
-                       rgba_char_args_set(btheme->tv3d.handle_free, 0, 0, 0, 255);
-                       rgba_char_args_set(btheme->tv3d.handle_auto, 0x90, 0x90, 0x00, 255);
-                       rgba_char_args_set(btheme->tv3d.handle_vect, 0x40, 0x90, 0x30, 255);
-                       rgba_char_args_set(btheme->tv3d.handle_align, 0x80, 0x30, 0x60, 255);
-                       rgba_char_args_set(btheme->tv3d.handle_sel_free, 0, 0, 0, 255);
-                       rgba_char_args_set(btheme->tv3d.handle_sel_auto, 0xf0, 0xff, 0x40, 255);
-                       rgba_char_args_set(btheme->tv3d.handle_sel_vect, 0x40, 0xc0, 0x30, 255);
-                       rgba_char_args_set(btheme->tv3d.handle_sel_align, 0xf0, 0x90, 0xa0, 255);
-                       rgba_char_args_set(btheme->tv3d.act_spline, 0xdb, 0x25, 0x12, 255);
-                       
-                       /* same colors again for Graph Editor... */
-                       rgba_char_args_set(btheme->tipo.handle_free, 0, 0, 0, 255);
-                       rgba_char_args_set(btheme->tipo.handle_auto, 0x90, 0x90, 0x00, 255);
-                       rgba_char_args_set(btheme->tipo.handle_vect, 0x40, 0x90, 0x30, 255);
-                       rgba_char_args_set(btheme->tipo.handle_align, 0x80, 0x30, 0x60, 255);
-                       rgba_char_args_set(btheme->tipo.handle_sel_free, 0, 0, 0, 255);
-                       rgba_char_args_set(btheme->tipo.handle_sel_auto, 0xf0, 0xff, 0x40, 255);
-                       rgba_char_args_set(btheme->tipo.handle_sel_vect, 0x40, 0xc0, 0x30, 255);
-                       rgba_char_args_set(btheme->tipo.handle_sel_align, 0xf0, 0x90, 0xa0, 255);
-                       
+                       ui_theme_space_init_handles_color(&btheme->tv3d);
+                       ui_theme_space_init_handles_color(&btheme->tipo);
+
                        /* edge crease */
                        rgba_char_args_set_fl(btheme->tv3d.edge_crease, 0.8, 0, 0.6, 1.0);
                }
@@ -2010,7 +2001,7 @@ void init_userdef_do_versions(void)
                                rgba_char_args_set(btheme->tclip.cframe, 0x60, 0xc0, 0x40, 255);
                                rgba_char_args_set(btheme->tclip.handle_vertex, 0x00, 0x00, 0x00, 0xff);
                                rgba_char_args_set(btheme->tclip.handle_vertex_select, 0xff, 0xff, 0, 0xff);
-                               btheme->tclip.handle_vertex_size = 4;
+                               btheme->tclip.handle_vertex_size = 5;
                        }
                        
                        /* auto-clamped handles -> based on auto */
@@ -2423,7 +2414,17 @@ void init_userdef_do_versions(void)
                        }
                }
        }
-       
+
+       {
+               bTheme *btheme;
+               for (btheme = U.themes.first; btheme; btheme = btheme->next) {
+                       ui_theme_space_init_handles_color(&btheme->tclip);
+                       ui_theme_space_init_handles_color(&btheme->tima);
+                       btheme->tima.handle_vertex_size = 5;
+                       btheme->tclip.handle_vertex_size = 5;
+               }
+       }
+
        if (U.pixelsize == 0.0f)
                U.pixelsize = 1.0f;
        
index 7fa41c361bbd368cefe6f3c4858dd8c41eea85f2..2e1d5221b56621fc6ab5014730b498a74bb810e0 100644 (file)
@@ -182,15 +182,13 @@ static int find_nearest_diff_point(const bContext *C, Mask *mask, const float no
 /******************** add vertex *********************/
 
 static void setup_vertex_point(Mask *mask, MaskSpline *spline, MaskSplinePoint *new_point,
-                               const float point_co[2], const float tangent[2], const float u,
-                               MaskSplinePoint *reference_point, const short reference_adjacent,
-                               const float view_zoom)
+                               const float point_co[2], const float u,
+                               MaskSplinePoint *reference_point, const short reference_adjacent)
 {
        MaskSplinePoint *prev_point = NULL;
        MaskSplinePoint *next_point = NULL;
        BezTriple *bezt;
        float co[3];
-       const float len = 10.0; /* default length of handle in pixel space */
 
        copy_v2_v2(co, point_co);
        co[2] = 0.0f;
@@ -201,7 +199,41 @@ static void setup_vertex_point(Mask *mask, MaskSpline *spline, MaskSplinePoint *
        bezt->h1 = bezt->h2 = HD_ALIGN;
 
        if (reference_point) {
-               bezt->h1 = bezt->h2 = MAX2(reference_point->bezt.h2, reference_point->bezt.h1);
+               if (reference_point->bezt.h1 == HD_VECT && reference_point->bezt.h2 == HD_VECT) {
+                       /* If the reference point is sharp try using some smooth point as reference
+                        * for handles.
+                        */
+                       int point_index = reference_point - spline->points;
+                       int delta = new_point == spline->points ? 1 : -1;
+                       int i = 0;
+                       for (i = 0; i < spline->tot_point - 1; ++i) {
+                               MaskSplinePoint *current_point;
+
+                               point_index += delta;
+                               if (point_index == -1 || point_index >= spline->tot_point) {
+                                       if (spline->flag & MASK_SPLINE_CYCLIC) {
+                                               if (point_index == -1) {
+                                                       point_index = spline->tot_point - 1;
+                                               }
+                                               else if (point_index >= spline->tot_point) {
+                                                       point_index = 0;
+                                               }
+                                       }
+                                       else {
+                                               break;
+                                       }
+                               }
+
+                               current_point = &spline->points[point_index];
+                               if (current_point->bezt.h1 != HD_VECT || current_point->bezt.h2 != HD_VECT) {
+                                       bezt->h1 = bezt->h2 = MAX2(current_point->bezt.h2, current_point->bezt.h1);
+                                       break;
+                               }
+                       }
+               }
+               else {
+                       bezt->h1 = bezt->h2 = MAX2(reference_point->bezt.h2, reference_point->bezt.h1);
+               }
        }
        else if (reference_adjacent) {
                if (spline->tot_point != 1) {
@@ -219,83 +251,11 @@ static void setup_vertex_point(Mask *mask, MaskSpline *spline, MaskSplinePoint *
        copy_v3_v3(bezt->vec[1], co);
        copy_v3_v3(bezt->vec[2], co);
 
-       /* initial offset for handles */
-       if (spline->tot_point == 1) {
-               /* first point of splien is aligned horizontally */
-               bezt->vec[0][0] -= len * view_zoom;
-               bezt->vec[2][0] += len * view_zoom;
-       }
-       else if (tangent) {
-               float vec[2];
-
-               copy_v2_v2(vec, tangent);
-
-               mul_v2_fl(vec, len);
-
-               sub_v2_v2(bezt->vec[0], vec);
-               add_v2_v2(bezt->vec[2], vec);
-
-               if (reference_adjacent) {
-                       BKE_mask_calc_handle_adjacent_interp(spline, new_point, u);
-               }
-       }
-       else {
-
-               /* calculating auto handles works much nicer */
-#if 0
-               /* next points are aligning in the direction of previous/next point */
-               MaskSplinePoint *point;
-               float v1[2], v2[2], vec[2];
-               float dir = 1.0f;
-
-               if (new_point == spline->points) {
-                       point = new_point + 1;
-                       dir = -1.0f;
-               }
-               else
-                       point = new_point - 1;
-
-               if (spline->tot_point < 3) {
-                       v1[0] = point->bezt.vec[1][0] * width;
-                       v1[1] = point->bezt.vec[1][1] * height;
-
-                       v2[0] = new_point->bezt.vec[1][0] * width;
-                       v2[1] = new_point->bezt.vec[1][1] * height;
-               }
-               else {
-                       if (new_point == spline->points) {
-                               v1[0] = spline->points[1].bezt.vec[1][0] * width;
-                               v1[1] = spline->points[1].bezt.vec[1][1] * height;
-
-                               v2[0] = spline->points[spline->tot_point - 1].bezt.vec[1][0] * width;
-                               v2[1] = spline->points[spline->tot_point - 1].bezt.vec[1][1] * height;
-                       }
-                       else {
-                               v1[0] = spline->points[0].bezt.vec[1][0] * width;
-                               v1[1] = spline->points[0].bezt.vec[1][1] * height;
-
-                               v2[0] = spline->points[spline->tot_point - 2].bezt.vec[1][0] * width;
-                               v2[1] = spline->points[spline->tot_point - 2].bezt.vec[1][1] * height;
-                       }
-               }
-
-               sub_v2_v2v2(vec, v1, v2);
-               mul_v2_fl(vec, len * dir / len_v2(vec));
-
-               vec[0] /= width;
-               vec[1] /= height;
-
-               add_v2_v2(bezt->vec[0], vec);
-               sub_v2_v2(bezt->vec[2], vec);
-#else
-               BKE_mask_calc_handle_point_auto(spline, new_point, TRUE);
+       BKE_mask_parent_init(&new_point->parent);
+       if (spline->tot_point != 1) {
                BKE_mask_calc_handle_adjacent_interp(spline, new_point, u);
-
-#endif
        }
 
-       BKE_mask_parent_init(&new_point->parent);
-
        /* select new point */
        MASKPOINT_SEL_ALL(new_point);
        ED_mask_select_flush_all(mask);
@@ -382,7 +342,7 @@ static int add_vertex_subdivide(const bContext *C, Mask *mask, const float co[2]
 
                new_point = &spline->points[point_index + 1];
 
-               setup_vertex_point(mask, spline, new_point, co, tangent, u, NULL, TRUE, 1.0f);
+               setup_vertex_point(mask, spline, new_point, co, u, NULL, TRUE);
 
                /* TODO - we could pass the spline! */
                BKE_mask_layer_shape_changed_add(masklay, BKE_mask_layer_shape_spline_to_index(masklay, spline) + point_index + 1, true, true);
@@ -409,7 +369,6 @@ static int add_vertex_extrude(const bContext *C, Mask *mask, MaskLayer *masklay,
        float tangent_point[2];
        float tangent_co[2];
        bool do_cyclic_correct = false;
-       bool do_recalc_src = false;  /* when extruding from endpoints only */
        bool do_prev;                /* use prev point rather then next?? */
 
        if (!masklay) {
@@ -440,11 +399,9 @@ static int add_vertex_extrude(const bContext *C, Mask *mask, MaskLayer *masklay,
        }
        else if (((spline->flag & MASK_SPLINE_CYCLIC) == 0) && (point_index == 0)) {
                do_prev = TRUE;
-               do_recalc_src = TRUE;
        }
        else if (((spline->flag & MASK_SPLINE_CYCLIC) == 0) && (point_index == spline->tot_point - 1)) {
                do_prev = FALSE;
-               do_recalc_src = TRUE;
        }
        else {
                do_prev = FALSE;  /* quiet warning */
@@ -482,18 +439,13 @@ static int add_vertex_extrude(const bContext *C, Mask *mask, MaskLayer *masklay,
 
        masklay->act_point = new_point;
 
-       setup_vertex_point(mask, spline, new_point, co, NULL, 0.5f, ref_point, FALSE, 1.0f);
+       setup_vertex_point(mask, spline, new_point, co, 0.5f, ref_point, FALSE);
 
        if (masklay->splines_shapes.first) {
                point_index = (((int)(new_point - spline->points) + 0) % spline->tot_point);
                BKE_mask_layer_shape_changed_add(masklay, BKE_mask_layer_shape_spline_to_index(masklay, spline) + point_index, true, true);
        }
 
-       if (do_recalc_src) {
-               /* TODO, update keyframes in time */
-               BKE_mask_calc_handle_point_auto(spline, ref_point, FALSE);
-       }
-
        WM_event_add_notifier(C, NC_MASK | NA_EDITED, mask);
 
        return TRUE;
@@ -504,7 +456,6 @@ static int add_vertex_new(const bContext *C, Mask *mask, MaskLayer *masklay, con
        MaskSpline *spline;
        MaskSplinePoint *point;
        MaskSplinePoint *new_point = NULL, *ref_point = NULL;
-       float view_zoom;
 
        if (!masklay) {
                /* if there's no masklay currently operationg on, create new one */
@@ -529,22 +480,7 @@ static int add_vertex_new(const bContext *C, Mask *mask, MaskLayer *masklay, con
 
        masklay->act_point = new_point;
 
-       {
-               ScrArea *sa = CTX_wm_area(C);
-               ARegion *ar = CTX_wm_region(C);
-
-               float zoom_x, zoom_y;
-               /* calc view zoom in a simplistic way */
-               ED_mask_zoom(sa, ar, &zoom_x, &zoom_y);
-
-               view_zoom = zoom_x + zoom_y / 2.0f;
-               view_zoom = 1.0f / view_zoom;
-
-               /* arbitrary but gives good results */
-               view_zoom /= 500.0f;
-       }
-
-       setup_vertex_point(mask, spline, new_point, co, NULL, 0.5f, ref_point, FALSE, view_zoom);
+       setup_vertex_point(mask, spline, new_point, co, 0.5f, ref_point, FALSE);
 
        {
                int point_index = (((int)(new_point - spline->points) + 0) % spline->tot_point);
index 24fcbd19fc1f6c51cd70abe23b8ab287b0b83f3b..12fcd3c14598e5dcabcaa6ba2753086f8b64de60 100644 (file)
@@ -132,29 +132,122 @@ static void mask_point_undistort_pos(SpaceClip *sc, float r_co[2], const float c
        BKE_mask_coord_from_movieclip(sc->clip, &sc->user, r_co, r_co);
 }
 
+static void draw_circle(const float x, const float y,
+                        const float size, const float xscale, const float yscale)
+{
+       static GLuint displist = 0;
+
+       /* Initialize round circle shape. */
+       if (displist == 0) {
+               GLUquadricObj *qobj;
+
+               displist = glGenLists(1);
+               glNewList(displist, GL_COMPILE);
+
+               qobj = gluNewQuadric();
+               gluQuadricDrawStyle(qobj, GLU_SILHOUETTE);
+               gluDisk(qobj, 0,  0.7, 8, 1);
+               gluDeleteQuadric(qobj);
+
+               glEndList();
+       }
+
+       glPushMatrix();
+       glTranslatef(x, y, 0.0f);
+       glScalef(1.0f / xscale * size, 1.0f / yscale * size, 1.0f);
+       glCallList(displist);
+       glPopMatrix();
+}
+
+static void draw_single_handle(const MaskLayer *mask_layer, const MaskSplinePoint *point,
+                               const eMaskWhichHandle which_handle, const int draw_type,
+                               const float handle_size, const float xscale, const float yscale,
+                               const float point_pos[2], const float handle_pos[2])
+{
+       const BezTriple *bezt = &point->bezt;
+       char handle_type;
+
+       if (which_handle == MASK_WHICH_HANDLE_STICK || which_handle == MASK_WHICH_HANDLE_LEFT) {
+               handle_type = bezt->h1;
+       }
+       else {
+               handle_type = bezt->h2;
+       }
+
+       if (handle_type == HD_VECT) {
+               return;
+       }
+
+       /* this could be split into its own loop */
+       if (draw_type == MASK_DT_OUTLINE) {
+               const unsigned char rgb_gray[4] = {0x60, 0x60, 0x60, 0xff};
+               glLineWidth(3);
+               glColor4ubv(rgb_gray);
+               glBegin(GL_LINES);
+               glVertex2fv(point_pos);
+               glVertex2fv(handle_pos);
+               glEnd();
+               glLineWidth(1);
+       }
+
+       switch (handle_type) {
+               case HD_FREE:
+                       UI_ThemeColor(TH_HANDLE_FREE);
+                       break;
+               case HD_AUTO:
+                       UI_ThemeColor(TH_HANDLE_AUTO);
+                       break;
+               case HD_ALIGN:
+               case HD_ALIGN_DOUBLESIDE:
+                       UI_ThemeColor(TH_HANDLE_ALIGN);
+                       break;
+       }
+
+       glBegin(GL_LINES);
+       glVertex2fv(point_pos);
+       glVertex2fv(handle_pos);
+       glEnd();
+
+       /* draw handle points */
+       if (MASKPOINT_ISSEL_HANDLE(point, which_handle)) {
+               if (point == mask_layer->act_point)
+                       glColor3f(1.0f, 1.0f, 1.0f);
+               else
+                       glColor3f(1.0f, 1.0f, 0.0f);
+       }
+       else {
+               glColor3f(0.5f, 0.5f, 0.0f);
+       }
+
+       draw_circle(handle_pos[0], handle_pos[1], handle_size, xscale, yscale);
+}
+
 /* return non-zero if spline is selected */
 static void draw_spline_points(const bContext *C, MaskLayer *masklay, MaskSpline *spline,
-                               const char UNUSED(draw_flag), const char draw_type)
+                               const char draw_flag, const char draw_type,
+                               const float xscale, const float yscale)
 {
        const bool is_spline_sel = (spline->flag & SELECT) && (masklay->restrictflag & MASK_RESTRICT_SELECT) == 0;
+       const bool is_smooth = (draw_flag & MASK_DRAWFLAG_SMOOTH) != 0;
+
        unsigned char rgb_spline[4];
        MaskSplinePoint *points_array = BKE_mask_spline_point_array(spline);
        SpaceClip *sc = CTX_wm_space_clip(C);
-       int undistort = FALSE;
+       bool undistort = false;
 
-       int i, hsize, tot_feather_point;
+       int i, handle_size, tot_feather_point;
        float (*feather_points)[2], (*fp)[2];
 
        if (!spline->tot_point)
                return;
 
        if (sc)
-               undistort = sc->clip && sc->user.render_flag & MCLIP_PROXY_RENDER_UNDISTORT;
+               undistort = sc->clip && (sc->user.render_flag & MCLIP_PROXY_RENDER_UNDISTORT) != 0;
 
        /* TODO, add this to sequence editor */
-       hsize = 4; /* UI_GetThemeValuef(TH_HANDLE_VERTEX_SIZE); */
+       handle_size = UI_GetThemeValuef(TH_HANDLE_VERTEX_SIZE) * U.pixelsize;
 
-       glPointSize(hsize);
+       glPointSize(handle_size);
 
        mask_spline_color_get(masklay, spline, is_spline_sel, rgb_spline);
 
@@ -202,6 +295,12 @@ static void draw_spline_points(const bContext *C, MaskLayer *masklay, MaskSpline
        }
        MEM_freeN(feather_points);
 
+       if (is_smooth) {
+               glEnable(GL_LINE_SMOOTH);
+               glEnable(GL_BLEND);
+               glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+       }
+
        /* control points */
        for (i = 0; i < spline->tot_point; i++) {
 
@@ -210,38 +309,36 @@ static void draw_spline_points(const bContext *C, MaskLayer *masklay, MaskSpline
                MaskSplinePoint *point_deform = &points_array[i];
                BezTriple *bezt = &point_deform->bezt;
 
-               float handle[2];
                float vert[2];
-               const bool has_handle = BKE_mask_point_has_handle(point);
 
                copy_v2_v2(vert, bezt->vec[1]);
-               BKE_mask_point_handle(point_deform, handle);
 
                if (undistort) {
                        mask_point_undistort_pos(sc, vert, vert);
-                       mask_point_undistort_pos(sc, handle, handle);
                }
 
                /* draw handle segment */
-               if (has_handle) {
-
-                       /* this could be split into its own loop */
-                       if (draw_type == MASK_DT_OUTLINE) {
-                               const unsigned char rgb_gray[4] = {0x60, 0x60, 0x60, 0xff};
-                               glLineWidth(3);
-                               glColor4ubv(rgb_gray);
-                               glBegin(GL_LINES);
-                               glVertex2fv(vert);
-                               glVertex2fv(handle);
-                               glEnd();
-                               glLineWidth(1);
+               if (BKE_mask_point_handles_mode_get(point) == MASK_HANDLE_MODE_STICK) {
+                       float handle[2];
+                       BKE_mask_point_handle(point_deform, MASK_WHICH_HANDLE_STICK, handle);
+                       if (undistort) {
+                               mask_point_undistort_pos(sc, handle, handle);
                        }
-
-                       glColor3ubv(rgb_spline);
-                       glBegin(GL_LINES);
-                       glVertex2fv(vert);
-                       glVertex2fv(handle);
-                       glEnd();
+                       draw_single_handle(masklay, point, MASK_WHICH_HANDLE_STICK,
+                                          draw_type, handle_size, xscale, yscale, vert, handle);
+               }
+               else {
+                       float handle_left[2], handle_right[2];
+                       BKE_mask_point_handle(point_deform, MASK_WHICH_HANDLE_LEFT, handle_left);
+                       BKE_mask_point_handle(point_deform, MASK_WHICH_HANDLE_RIGHT, handle_right);
+                       if (undistort) {
+                               mask_point_undistort_pos(sc, handle_left, handle_left);
+                               mask_point_undistort_pos(sc, handle_left, handle_left);
+                       }
+                       draw_single_handle(masklay, point, MASK_WHICH_HANDLE_LEFT,
+                                          draw_type, handle_size, xscale, yscale, vert, handle_left);
+                       draw_single_handle(masklay, point, MASK_WHICH_HANDLE_RIGHT,
+                                          draw_type, handle_size, xscale, yscale, vert, handle_right);
                }
 
                /* draw CV point */
@@ -257,26 +354,14 @@ static void draw_spline_points(const bContext *C, MaskLayer *masklay, MaskSpline
                glBegin(GL_POINTS);
                glVertex2fv(vert);
                glEnd();
-
-               /* draw handle points */
-               if (has_handle) {
-                       if (MASKPOINT_ISSEL_HANDLE(point)) {
-                               if (point == masklay->act_point)
-                                       glColor3f(1.0f, 1.0f, 1.0f);
-                               else
-                                       glColor3f(1.0f, 1.0f, 0.0f);
-                       }
-                       else {
-                               glColor3f(0.5f, 0.5f, 0.0f);
-                       }
-
-                       glBegin(GL_POINTS);
-                       glVertex2fv(handle);
-                       glEnd();
-               }
        }
 
        glPointSize(1.0f);
+
+       if (is_smooth) {
+               glDisable(GL_LINE_SMOOTH);
+               glDisable(GL_BLEND);
+       }
 }
 
 /* #define USE_XOR */
@@ -408,7 +493,7 @@ static void mask_draw_curve_type(const bContext *C, MaskSpline *spline, float (*
 static void draw_spline_curve(const bContext *C, MaskLayer *masklay, MaskSpline *spline,
                               const char draw_flag, const char draw_type,
                               const bool is_active,
-                              int width, int height)
+                              const int width, const int height)
 {
        const unsigned int resol = max_ii(BKE_mask_spline_feather_resolution(spline, width, height),
                                          BKE_mask_spline_resolution(spline, width, height));
@@ -482,7 +567,7 @@ static void draw_spline_curve(const bContext *C, MaskLayer *masklay, MaskSpline
 }
 
 static void draw_masklays(const bContext *C, Mask *mask, const char draw_flag, const char draw_type,
-                          int width, int height)
+                          const int width, const int height, const float xscale, const float yscale)
 {
        MaskLayer *masklay;
        int i;
@@ -504,7 +589,7 @@ static void draw_masklays(const bContext *C, Mask *mask, const char draw_flag, c
 
                        if (!(masklay->restrictflag & MASK_RESTRICT_SELECT)) {
                                /* ...and then handles over the curve so they're nicely visible */
-                               draw_spline_points(C, masklay, spline, draw_flag, draw_type);
+                               draw_spline_points(C, masklay, spline, draw_flag, draw_type, xscale, yscale);
                        }
 
                        /* show undeform for testing */
@@ -514,7 +599,7 @@ static void draw_masklays(const bContext *C, Mask *mask, const char draw_flag, c
                                spline->points_deform = NULL;
                                draw_spline_curve(C, masklay, spline, draw_flag, draw_type, is_active, width, height);
 //                             draw_spline_parents(masklay, spline);
-                               draw_spline_points(C, masklay, spline, draw_flag, draw_type);
+                               draw_spline_points(C, masklay, spline, draw_flag, draw_type, xscale, yscale);
                                spline->points_deform = back;
                        }
                }
@@ -525,16 +610,21 @@ void ED_mask_draw(const bContext *C,
                   const char draw_flag, const char draw_type)
 {
        ScrArea *sa = CTX_wm_area(C);
+       ARegion *ar = CTX_wm_region(C);
 
        Mask *mask = CTX_data_edit_mask(C);
        int width, height;
+       float aspx, aspy;
+       float xscale, yscale;
 
        if (!mask)
                return;
 
        ED_mask_get_size(sa, &width, &height);
+       ED_mask_get_aspect(sa, ar, &aspx, &aspy);
+       UI_view2d_getscale(&ar->v2d, &xscale, &yscale);
 
-       draw_masklays(C, mask, draw_flag, draw_type, width, height);
+       draw_masklays(C, mask, draw_flag, draw_type, width, height, xscale * aspx, yscale * aspy);
 }
 
 typedef struct ThreadedMaskRasterizeState {
@@ -719,7 +809,7 @@ void ED_mask_draw_region(Mask *mask, ARegion *ar,
        }
 
        /* draw! */
-       draw_masklays(C, mask, draw_flag, draw_type, width, height);
+       draw_masklays(C, mask, draw_flag, draw_type, width, height, maxdim * zoomx, maxdim * zoomy);
 
        if (do_draw_cb) {
                ED_region_draw_cb_draw(C, ar, REGION_DRAW_POST_VIEW);
index ad287a3af9ffbb13a18c6601f2bcf08cd494a684..af4645e31ece36032850cd4725c00ea8c87fc71b 100644 (file)
@@ -570,8 +570,8 @@ void ED_operatormacros_mask(void)
                                          "Add new vertex and slide it", OPTYPE_UNDO | OPTYPE_REGISTER);
        ot->description = "Add new vertex and slide it";
        WM_operatortype_macro_define(ot, "MASK_OT_add_vertex");
-       otmacro = WM_operatortype_macro_define(ot, "TRANSFORM_OT_translate");
-       RNA_boolean_set(otmacro->ptr, "release_confirm", TRUE);
+       otmacro = WM_operatortype_macro_define(ot, "MASK_OT_slide_point");
+       RNA_boolean_set(otmacro->ptr, "is_new_point", TRUE);
 
        ot = WM_operatortype_append_macro("MASK_OT_add_feather_vertex_slide", "Add Feather Vertex and Slide",
                                          "Add new vertex to feather and slide it", OPTYPE_UNDO | OPTYPE_REGISTER);
index 62872e72cb47c2e5f82da6ed8d75ffbd07f05308..d95e07f043a6677ce0b5ed20dd3b74bc0308da2c 100644 (file)
@@ -73,7 +73,7 @@ bool ED_mask_feather_find_nearest(
 
 struct MaskSplinePoint *ED_mask_point_find_nearest(
         const struct bContext *C, struct Mask *mask, const float normal_co[2], const float threshold,
-        struct MaskLayer **masklay_r, struct MaskSpline **spline_r, bool *is_handle_r,
+        struct MaskLayer **masklay_r, struct MaskSpline **spline_r, eMaskWhichHandle *which_handle_r,
         float *score);
 
 void MASK_OT_layer_move(struct wmOperatorType *ot);
index b9b456177ead1b778f68722362ad3894d32811d3..da91c59a0946cf457a32df6cebd0ed0fa2a0ce78 100644 (file)
 
 /******************** utility functions *********************/
 
+static void mask_point_scaled_handle(/*const*/ MaskSplinePoint *point, /*const*/ eMaskWhichHandle which_handle,
+                                     const float scalex, const float scaley, float handle[2])
+{
+       BKE_mask_point_handle(point, which_handle, handle);
+       handle[0] *= scalex;
+       handle[1] *= scaley;
+}
+
 MaskSplinePoint *ED_mask_point_find_nearest(const bContext *C, Mask *mask, const float normal_co[2], const float threshold,
-                                            MaskLayer **masklay_r, MaskSpline **spline_r, bool *is_handle_r,
-                                            float *score)
+                                            MaskLayer **masklay_r, MaskSpline **spline_r,
+                                            eMaskWhichHandle *which_handle_r, float *score)
 {
        ScrArea *sa = CTX_wm_area(C);
        ARegion *ar = CTX_wm_region(C);
@@ -72,8 +80,9 @@ MaskSplinePoint *ED_mask_point_find_nearest(const bContext *C, Mask *mask, const
        MaskSplinePoint *point = NULL;
        float co[2];
        const float threshold_sq = threshold * threshold;
-       float len_sq = FLT_MAX, scalex, scaley;
-       int is_handle = FALSE, width, height;
+       float len_sq= FLT_MAX, scalex, scaley;
+       eMaskWhichHandle which_handle = MASK_WHICH_HANDLE_NONE;
+       int width, height;
 
        ED_mask_get_size(sa, &width, &height);
        ED_mask_pixelspace_factor(sa, ar, &scalex, &scaley);
@@ -96,35 +105,64 @@ MaskSplinePoint *ED_mask_point_find_nearest(const bContext *C, Mask *mask, const
                        for (i = 0; i < spline->tot_point; i++) {
                                MaskSplinePoint *cur_point = &spline->points[i];
                                MaskSplinePoint *cur_point_deform = &points_array[i];
-                               float cur_len_sq, vec[2], handle[2];
+                               eMaskWhichHandle cur_which_handle;
+                               float cur_len_sq, vec[2];
 
                                vec[0] = cur_point_deform->bezt.vec[1][0] * scalex;
                                vec[1] = cur_point_deform->bezt.vec[1][1] * scaley;
 
-                               if (BKE_mask_point_has_handle(cur_point)) {
-                                       BKE_mask_point_handle(cur_point_deform, handle);
-                                       handle[0] *= scalex;
-                                       handle[1] *= scaley;
+                               cur_len_sq = len_squared_v2v2(co, vec);
 
-                                       cur_len_sq = len_squared_v2v2(co, handle);
+                               if (cur_len_sq < len_sq) {
+                                       point_spline = spline;
+                                       point_masklay = masklay;
+                                       point = cur_point;
+                                       len_sq = cur_len_sq;
+                                       which_handle = MASK_WHICH_HANDLE_NONE;
+                               }
 
-                                       if (cur_len_sq < len_sq) {
-                                               point_masklay = masklay;
-                                               point_spline = spline;
-                                               point = cur_point;
-                                               len_sq = cur_len_sq;
-                                               is_handle = TRUE;
+                               if (BKE_mask_point_handles_mode_get(cur_point_deform) == MASK_HANDLE_MODE_STICK) {
+                                       float handle[2];
+                                       mask_point_scaled_handle(cur_point_deform, MASK_WHICH_HANDLE_STICK, scalex, scaley, handle);
+                                       cur_len_sq = len_squared_v2v2(co, handle);
+                                       cur_which_handle = MASK_WHICH_HANDLE_STICK;
+                               }
+                               else {
+                                       float handle_left[2], handle_right[2];
+                                       float len_left_sq, len_right_sq;
+                                       mask_point_scaled_handle(cur_point_deform, MASK_WHICH_HANDLE_LEFT, scalex, scaley, handle_left);
+                                       mask_point_scaled_handle(cur_point_deform, MASK_WHICH_HANDLE_RIGHT, scalex, scaley, handle_right);
+
+                                       len_left_sq = len_squared_v2v2(co, handle_left);
+                                       len_right_sq = len_squared_v2v2(co, handle_right);
+                                       if (i == 0) {
+                                               if (len_left_sq <= len_right_sq) {
+                                                       cur_which_handle = MASK_WHICH_HANDLE_LEFT;
+                                                       cur_len_sq = len_left_sq;
+                                               }
+                                               else {
+                                                       cur_which_handle = MASK_WHICH_HANDLE_RIGHT;
+                                                       cur_len_sq = len_right_sq;
+                                               }
+                                       }
+                                       else {
+                                               if (len_right_sq <= len_left_sq) {
+                                                       cur_which_handle = MASK_WHICH_HANDLE_RIGHT;
+                                                       cur_len_sq = len_right_sq;
+                                               }
+                                               else {
+                                                       cur_which_handle = MASK_WHICH_HANDLE_LEFT;
+                                                       cur_len_sq = len_left_sq;
+                                               }
                                        }
                                }
 
-                               cur_len_sq = len_squared_v2v2(co, vec);
-
-                               if (cur_len_sq < len_sq) {
-                                       point_spline = spline;
+                               if (cur_len_sq <= len_sq) {
                                        point_masklay = masklay;
+                                       point_spline = spline;
                                        point = cur_point;
                                        len_sq = cur_len_sq;
-                                       is_handle = FALSE;
+                                       which_handle = cur_which_handle;
                                }
                        }
                }
@@ -137,8 +175,8 @@ MaskSplinePoint *ED_mask_point_find_nearest(const bContext *C, Mask *mask, const
                if (spline_r)
                        *spline_r = point_spline;
 
-               if (is_handle_r)
-                       *is_handle_r = is_handle;
+               if (which_handle_r)
+                       *which_handle_r = which_handle;
 
                if (score)
                        *score = sqrtf(len_sq);
@@ -152,8 +190,8 @@ MaskSplinePoint *ED_mask_point_find_nearest(const bContext *C, Mask *mask, const
        if (spline_r)
                *spline_r = NULL;
 
-       if (is_handle_r)
-               *is_handle_r = FALSE;
+       if (which_handle_r)
+               *which_handle_r = MASK_WHICH_HANDLE_NONE;
 
        return NULL;
 }
@@ -423,18 +461,22 @@ typedef struct SlidePointData {
 
        float co[2];
        float vec[3][3];
+       char old_h1, old_h2;
 
        Mask *mask;
        MaskLayer *masklay;
        MaskSpline *spline, *orig_spline;
        MaskSplinePoint *point;
        MaskSplinePointUW *uw;
+       eMaskWhichHandle which_handle;
        float handle[2], no[2], feather[2];
        int width, height;
        float weight, weight_scalar;
 
        short curvature_only, accurate;
        short initial_feather, overall_feather;
+
+       bool is_sliding_new_point;
 } SlidePointData;
 
 static bool slide_point_check_initial_feather(MaskSpline *spline)
@@ -460,6 +502,41 @@ static bool slide_point_check_initial_feather(MaskSpline *spline)
        return TRUE;
 }
 
+static void select_sliding_point(Mask *mask, MaskLayer *mask_layer, MaskSpline *spline,
+                                 MaskSplinePoint *point)
+{
+       ED_mask_select_toggle_all(mask, SEL_DESELECT);
+       BKE_mask_point_select_set(point, TRUE);
+
+       mask_layer->act_spline = spline;
+       mask_layer->act_point = point;
+       ED_mask_select_flush_all(mask);
+}
+
+static void check_sliding_handle_type(MaskSplinePoint *point, eMaskWhichHandle which_handle)
+{
+       BezTriple *bezt = &point->bezt;
+
+       if (which_handle == MASK_WHICH_HANDLE_LEFT) {
+               if (bezt->h1 == HD_VECT) {
+                       bezt->h1 = HD_FREE;
+               }
+               else if (bezt->h1 == HD_AUTO) {
+                       bezt->h1 = HD_ALIGN_DOUBLESIDE;
+                       bezt->h2 = HD_ALIGN_DOUBLESIDE;
+               }
+       }
+       else if (which_handle == MASK_WHICH_HANDLE_RIGHT) {
+               if (bezt->h2 == HD_VECT) {
+                       bezt->h2 = HD_FREE;
+               }
+               else if (bezt->h2 == HD_AUTO) {
+                       bezt->h1 = HD_ALIGN_DOUBLESIDE;
+                       bezt->h2 = HD_ALIGN_DOUBLESIDE;
+               }
+       }
+}
+
 static void *slide_point_customdata(bContext *C, wmOperator *op, const wmEvent *event)
 {
        ScrArea *sa = CTX_wm_area(C);
@@ -472,15 +549,15 @@ static void *slide_point_customdata(bContext *C, wmOperator *op, const wmEvent *
        MaskSplinePoint *point, *cv_point, *feather_point;
        MaskSplinePointUW *uw = NULL;
        int width, height, action = SLIDE_ACTION_NONE;
-       bool is_handle = false;
        const bool slide_feather = RNA_boolean_get(op->ptr, "slide_feather");
        float co[2], cv_score, feather_score;
        const float threshold = 19;
+       eMaskWhichHandle which_handle;
 
        ED_mask_mouse_pos(sa, ar, event->mval, co);
        ED_mask_get_size(sa, &width, &height);
 
-       cv_point = ED_mask_point_find_nearest(C, mask, co, threshold, &cv_masklay, &cv_spline, &is_handle, &cv_score);
+       cv_point = ED_mask_point_find_nearest(C, mask, co, threshold, &cv_masklay, &cv_spline, &which_handle, &cv_score);
 
        if (ED_mask_feather_find_nearest(C, mask, co, threshold, &feather_masklay, &feather_spline, &feather_point, &uw, &feather_score)) {
                if (slide_feather || !cv_point || feather_score < cv_score) {
@@ -493,7 +570,7 @@ static void *slide_point_customdata(bContext *C, wmOperator *op, const wmEvent *
        }
 
        if (cv_point && action == SLIDE_ACTION_NONE) {
-               if (is_handle)
+               if (which_handle != MASK_WHICH_HANDLE_NONE)
                        action = SLIDE_ACTION_HANDLE;
                else
                        action = SLIDE_ACTION_POINT;
@@ -504,6 +581,8 @@ static void *slide_point_customdata(bContext *C, wmOperator *op, const wmEvent *
        }
 
        if (action != SLIDE_ACTION_NONE) {
+               select_sliding_point(mask, masklay, spline, point);
+
                customdata = MEM_callocN(sizeof(SlidePointData), "mask slide point data");
 
                customdata->mask = mask;
@@ -515,6 +594,13 @@ static void *slide_point_customdata(bContext *C, wmOperator *op, const wmEvent *
                customdata->action = action;
                customdata->uw = uw;
 
+               customdata->old_h1 = point->bezt.h1;
+               customdata->old_h2 = point->bezt.h2;
+
+               customdata->is_sliding_new_point = RNA_boolean_get(op->ptr, "is_new_point");
+
+               check_sliding_handle_type(point, which_handle);
+
                if (uw) {
                        float co_uw[2];
                        float weight_scalar = BKE_mask_point_weight_scalar(spline, point, uw->u);
@@ -540,8 +626,10 @@ static void *slide_point_customdata(bContext *C, wmOperator *op, const wmEvent *
                        customdata->initial_feather = slide_point_check_initial_feather(spline);
 
                copy_m3_m3(customdata->vec, point->bezt.vec);
-               if (BKE_mask_point_has_handle(point))
-                       BKE_mask_point_handle(point, customdata->handle);
+               if (which_handle != MASK_WHICH_HANDLE_NONE) {
+                       BKE_mask_point_handle(point, which_handle, customdata->handle);
+               }
+               customdata->which_handle = which_handle;
                ED_mask_mouse_pos(sa, ar, event->mval, customdata->co);
        }
 
@@ -550,11 +638,16 @@ static void *slide_point_customdata(bContext *C, wmOperator *op, const wmEvent *
 
 static int slide_point_invoke(bContext *C, wmOperator *op, const wmEvent *event)
 {
-       SlidePointData *slidedata = slide_point_customdata(C, op, event);
+       Mask *mask = CTX_data_edit_mask(C);
+       SlidePointData *slidedata;
 
-       if (slidedata) {
-               Mask *mask = CTX_data_edit_mask(C);
+       if (mask == NULL) {
+               return OPERATOR_CANCELLED;
+       }
 
+       slidedata = slide_point_customdata(C, op, event);
+
+       if (slidedata) {
                op->customdata = slidedata;
 
                WM_event_add_modal_handler(C, op);
@@ -645,6 +738,8 @@ static void cancel_slide_point(SlidePointData *data)
                }
                else {
                        copy_m3_m3(data->point->bezt.vec, data->vec);
+                       data->point->bezt.h1 = data->old_h1;
+                       data->point->bezt.h2 = data->old_h2;
                }
        }
 }
@@ -695,10 +790,34 @@ static int slide_point_modal(bContext *C, wmOperator *op, const wmEvent *event)
                                sub_v2_v2v2(offco, co, data->co);
                                if (data->accurate)
                                        mul_v2_fl(offco, 0.2f);
+
+                               if (data->is_sliding_new_point && data->which_handle == MASK_WHICH_HANDLE_STICK) {
+                                       if (ELEM(data->point, &data->spline->points[0],
+                                                             &data->spline->points[data->spline->tot_point - 1]))
+                                       {
+                                               SWAP(float, offco[0], offco[1]);
+                                               offco[1] *= -1;
+                                       }
+                               }
+
                                add_v2_v2(offco, data->co);
                                add_v2_v2(offco, delta);
 
-                               BKE_mask_point_set_handle(data->point, offco, data->curvature_only, data->handle, data->vec);
+                               BKE_mask_point_set_handle(data->point, data->which_handle,
+                                                         offco, data->curvature_only,
+                                                         data->handle, data->vec);
+
+                               if (data->is_sliding_new_point) {
+                                       if (ELEM(data->which_handle, MASK_WHICH_HANDLE_LEFT, MASK_WHICH_HANDLE_RIGHT)) {
+                                               BezTriple *bezt = &data->point->bezt;
+                                               float vec[2];
+                                               short self_handle = (data->which_handle == MASK_WHICH_HANDLE_LEFT) ? 0 : 2;
+                                               short other_handle = (data->which_handle == MASK_WHICH_HANDLE_LEFT) ? 2 : 0;
+
+                                               sub_v2_v2v2(vec, bezt->vec[1], bezt->vec[self_handle]);
+                                               add_v2_v2v2(bezt->vec[other_handle], bezt->vec[1], vec);
+                                       }
+                               }
                        }
                        else if (data->action == SLIDE_ACTION_POINT) {
                                float delta[2];
@@ -826,6 +945,16 @@ static int slide_point_modal(bContext *C, wmOperator *op, const wmEvent *event)
                                        }
                                }
 
+                               if (data->is_sliding_new_point) {
+                                       BezTriple *bezt = &data->point->bezt;
+                                       if (len_squared_v2v2(bezt->vec[0], bezt->vec[1]) < FLT_EPSILON) {
+                                               bezt->h1 = HD_VECT;
+                                       }
+                                       if (len_squared_v2v2(bezt->vec[2], bezt->vec[1]) < FLT_EPSILON) {
+                                               bezt->h2 = HD_VECT;
+                                       }
+                               }
+
                                WM_event_add_notifier(C, NC_MASK | NA_EDITED, data->mask);
                                DAG_id_tag_update(&data->mask->id, 0);
 
@@ -850,6 +979,8 @@ static int slide_point_modal(bContext *C, wmOperator *op, const wmEvent *event)
 
 void MASK_OT_slide_point(wmOperatorType *ot)
 {
+       PropertyRNA *prop;
+
        /* identifiers */
        ot->name = "Slide Point";
        ot->description = "Slide control points";
@@ -858,12 +989,15 @@ void MASK_OT_slide_point(wmOperatorType *ot)
        /* api callbacks */
        ot->invoke = slide_point_invoke;
        ot->modal = slide_point_modal;
-       ot->poll = ED_maskedit_mask_poll;
+       ot->poll = ED_operator_mask;
 
        /* flags */
        ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
 
        RNA_def_boolean(ot->srna, "slide_feather", 0, "Slide Feather", "First try to slide feather instead of vertex");
+
+       prop = RNA_def_boolean(ot->srna, "is_new_point", 0, "Slide New Point", "Newly created vertex is being slided");
+       RNA_def_property_flag(prop, PROP_SKIP_SAVE);
 }
 
 /******************** toggle cyclic *********************/
@@ -887,6 +1021,7 @@ static int cyclic_toggle_exec(bContext *C, wmOperator *UNUSED(op))
                }
        }
 
+       DAG_id_tag_update(&mask->id, 0);
        WM_event_add_notifier(C, NC_MASK | NA_EDITED, mask);
 
        return OPERATOR_FINISHED;
@@ -1218,7 +1353,25 @@ static int set_handle_type_exec(bContext *C, wmOperator *op)
                                if (MASKPOINT_ISSEL_ANY(point)) {
                                        BezTriple *bezt = &point->bezt;
 
-                                       bezt->h1 = bezt->h2 = handle_type;
+                                       if (bezt->f2 & SELECT) {
+                                               bezt->h1 = handle_type;
+                                               bezt->h2 = handle_type;
+                                       }
+                                       else {
+                                               if (bezt->f1 & SELECT) {
+                                                       bezt->h1 = handle_type;
+                                               }
+                                               if (bezt->f3 & SELECT) {
+                                                       bezt->h2 = handle_type;
+                                               }
+                                       }
+
+                                       if (handle_type == HD_ALIGN) {
+                                               float vec[3];
+                                               sub_v3_v3v3(vec, bezt->vec[0], bezt->vec[1]);
+                                               add_v3_v3v3(bezt->vec[2], bezt->vec[1], vec);
+                                       }
+
                                        changed = true;
                                }
                        }
@@ -1239,7 +1392,9 @@ void MASK_OT_handle_type_set(wmOperatorType *ot)
        static EnumPropertyItem editcurve_handle_type_items[] = {
                {HD_AUTO, "AUTO", 0, "Auto", ""},
                {HD_VECT, "VECTOR", 0, "Vector", ""},
-               {HD_ALIGN, "ALIGNED", 0, "Aligned", ""},
+               {HD_ALIGN, "ALIGNED", 0, "Aligned Single", ""},
+               {HD_ALIGN_DOUBLESIDE, "ALIGNED_DOUBLESIDE", 0, "Aligned", ""},
+               {HD_FREE, "FREE", 0, "Free", ""},
                {0, NULL, 0, NULL, NULL}
        };
 
index 16fd8414f22db0938612ef176a0efd327a9bf9ab..29b5714be59d7e30ce6f19b787d9629f0d5d9c7c 100644 (file)
@@ -255,38 +255,36 @@ static int select_exec(bContext *C, wmOperator *op)
        bool extend = RNA_boolean_get(op->ptr, "extend");
        bool deselect = RNA_boolean_get(op->ptr, "deselect");
        bool toggle = RNA_boolean_get(op->ptr, "toggle");
-
-       bool is_handle = 0;
+       eMaskWhichHandle which_handle;
        const float threshold = 19;
 
        RNA_float_get_array(op->ptr, "location", co);
 
-       point = ED_mask_point_find_nearest(C, mask, co, threshold, &masklay, &spline, &is_handle, NULL);
+       point = ED_mask_point_find_nearest(C, mask, co, threshold, &masklay, &spline, &which_handle, NULL);
 
        if (extend == false && deselect == false && toggle == false)
                ED_mask_select_toggle_all(mask, SEL_DESELECT);
 
        if (point) {
-
-               if (is_handle) {
+               if (which_handle != MASK_WHICH_HANDLE_NONE) {
                        if (extend) {
                                masklay->act_spline = spline;
                                masklay->act_point = point;
 
-                               BKE_mask_point_select_set_handle(point, TRUE);
+                               BKE_mask_point_select_set_handle(point, which_handle, TRUE);
                        }
                        else if (deselect) {
-                               BKE_mask_point_select_set_handle(point, FALSE);
+                               BKE_mask_point_select_set_handle(point, which_handle, FALSE);
                        }
                        else {
                                masklay->act_spline = spline;
                                masklay->act_point = point;
 
-                               if (!MASKPOINT_ISSEL_HANDLE(point)) {
-                                       BKE_mask_point_select_set_handle(point, TRUE);
+                               if (!MASKPOINT_ISSEL_HANDLE(point, which_handle)) {
+                                       BKE_mask_point_select_set_handle(point, which_handle, TRUE);
                                }
                                else if (toggle) {
-                                       BKE_mask_point_select_set_handle(point, FALSE);
+                                       BKE_mask_point_select_set_handle(point, which_handle, FALSE);
                                }
                        }
                }
@@ -444,11 +442,11 @@ static int border_select_exec(bContext *C, wmOperator *op)
 
                                if (BLI_rctf_isect_pt_v(&rectf, point_deform->bezt.vec[1])) {
                                        BKE_mask_point_select_set(point, mode == GESTURE_MODAL_SELECT);
-                                       BKE_mask_point_select_set_handle(point, mode == GESTURE_MODAL_SELECT);
+                                       BKE_mask_point_select_set_handle(point, MASK_WHICH_HANDLE_BOTH, mode == GESTURE_MODAL_SELECT);
                                }
                                else if (!extend) {
                                        BKE_mask_point_select_set(point, FALSE);
-                                       BKE_mask_point_select_set_handle(point, FALSE);
+                                       BKE_mask_point_select_set_handle(point, MASK_WHICH_HANDLE_BOTH, FALSE);
                                }
 
                                changed = true;
@@ -531,7 +529,7 @@ static bool do_lasso_select_mask(bContext *C, const int mcords[][2], short moves
                                    BLI_lasso_is_point_inside(mcords, moves, screen_co[0], screen_co[1], INT_MAX))
                                {
                                        BKE_mask_point_select_set(point, select);
-                                       BKE_mask_point_select_set_handle(point, select);
+                                       BKE_mask_point_select_set_handle(point, MASK_WHICH_HANDLE_BOTH, select);
                                }
 
                                changed = true;
@@ -649,7 +647,7 @@ static int circle_select_exec(bContext *C, wmOperator *op)
 
                                if (mask_spline_point_inside_ellipse(&point_deform->bezt, offset, ellipse)) {
                                        BKE_mask_point_select_set(point, mode == GESTURE_MODAL_SELECT);
-                                       BKE_mask_point_select_set_handle(point, mode == GESTURE_MODAL_SELECT);
+                                       BKE_mask_point_select_set_handle(point, MASK_WHICH_HANDLE_BOTH, mode == GESTURE_MODAL_SELECT);
 
                                        changed = true;
                                }
@@ -702,14 +700,12 @@ static int mask_select_linked_pick_invoke(bContext *C, wmOperator *op, const wmE
        MaskSplinePoint *point = NULL;
        float co[2];
        int do_select = !RNA_boolean_get(op->ptr, "deselect");
-
-       bool is_handle = false;
        const float threshold = 19;
        bool changed = false;
 
        ED_mask_mouse_pos(sa, ar, event->mval, co);
 
-       point = ED_mask_point_find_nearest(C, mask, co, threshold, &masklay, &spline, &is_handle, NULL);
+       point = ED_mask_point_find_nearest(C, mask, co, threshold, &masklay, &spline, NULL, NULL);
 
        if (point) {
                ED_mask_spline_select_set(spline, do_select);
index 886dea2e34b064654ed749f32ec898eb39a22347..0b3238c7d1eaad25c6f1afac4b0035741bbdbb59 100644 (file)
@@ -6584,8 +6584,67 @@ typedef struct TransDataMasking {
        MaskSplinePoint *point;
        float parent_matrix[3][3];
        float parent_inverse_matrix[3][3];
+       char orig_handle_type;
+
+       eMaskWhichHandle which_handle;
 } TransDataMasking;
 
+static void MaskHandleToTransData(MaskSplinePoint *point, eMaskWhichHandle which_handle,
+                                  TransData *td, TransData2D *td2d, TransDataMasking *tdm,
+                                  const float asp[2],
+                                  /*const*/ float parent_matrix[3][3],
+                                  /*const*/ float parent_inverse_matrix[3][3])
+{
+       BezTriple *bezt = &point->bezt;
+       short is_sel_any = MASKPOINT_ISSEL_ANY(point);
+
+       tdm->point = point;
+       copy_m3_m3(tdm->vec, bezt->vec);
+
+       tdm->is_handle = TRUE;
+       copy_m3_m3(tdm->parent_matrix, parent_matrix);
+       copy_m3_m3(tdm->parent_inverse_matrix, parent_inverse_matrix);
+
+       BKE_mask_point_handle(point, which_handle, tdm->handle);
+       tdm->which_handle = which_handle;
+
+       copy_v2_v2(tdm->orig_handle, tdm->handle);
+
+       mul_v2_m3v2(td2d->loc, parent_matrix, tdm->handle);
+       td2d->loc[0] *= asp[0];
+       td2d->loc[1] *= asp[1];
+       td2d->loc[2] = 0.0f;
+
+       td2d->loc2d = tdm->handle;
+
+       td->flag = 0;
+       td->loc = td2d->loc;
+       mul_v2_m3v2(td->center, parent_matrix, bezt->vec[1]);
+       copy_v3_v3(td->iloc, td->loc);
+
+       memset(td->axismtx, 0, sizeof(td->axismtx));
+       td->axismtx[2][2] = 1.0f;
+
+       td->ext = NULL;
+       td->val = NULL;
+
+       if (is_sel_any) {
+               td->flag |= TD_SELECTED;
+       }
+
+       td->dist = 0.0;
+
+       unit_m3(td->mtx);
+       unit_m3(td->smtx);
+
+       if (which_handle == MASK_WHICH_HANDLE_LEFT) {
+               tdm->orig_handle_type = bezt->h1;
+       }
+       else if (which_handle == MASK_WHICH_HANDLE_RIGHT) {
+               tdm->orig_handle_type = bezt->h2;
+       }
+}
+
 static void MaskPointToTransData(Scene *scene, MaskSplinePoint *point,
                                  TransData *td, TransData2D *td2d, TransDataMasking *tdm,
                                  const int propmode, const float asp[2])
@@ -6595,14 +6654,15 @@ static void MaskPointToTransData(Scene *scene, MaskSplinePoint *point,
        const bool is_sel_any = MASKPOINT_ISSEL_ANY(point);
        float parent_matrix[3][3], parent_inverse_matrix[3][3];
 
-       tdm->point = point;
-       copy_m3_m3(tdm->vec, bezt->vec);
-
        BKE_mask_point_parent_matrix_get(point, CFRA, parent_matrix);
        invert_m3_m3(parent_inverse_matrix, parent_matrix);
 
        if (propmode || is_sel_point) {
                int i;
+
+               tdm->point = point;
+               copy_m3_m3(tdm->vec, bezt->vec);
+
                for (i = 0; i < 3; i++) {
                        copy_m3_m3(tdm->parent_matrix, parent_matrix);
                        copy_m3_m3(tdm->parent_inverse_matrix, parent_inverse_matrix);
@@ -6645,49 +6705,64 @@ static void MaskPointToTransData(Scene *scene, MaskSplinePoint *point,
                        unit_m3(td->mtx);
                        unit_m3(td->smtx);
 
+                       if (i == 0) {
+                               tdm->orig_handle_type = bezt->h1;
+                       }
+                       else if (i == 3) {
+                               tdm->orig_handle_type = bezt->h2;
+                       }
+
                        td++;
                        td2d++;
                        tdm++;
                }
        }
        else {
-               tdm->is_handle = TRUE;
-               copy_m3_m3(tdm->parent_matrix, parent_matrix);
-               copy_m3_m3(tdm->parent_inverse_matrix, parent_inverse_matrix);
-
-               BKE_mask_point_handle(point, tdm->handle);
-
-               copy_v2_v2(tdm->orig_handle, tdm->handle);
-
-               mul_v2_m3v2(td2d->loc, parent_matrix, tdm->handle);
-               td2d->loc[0] *= asp[0];
-               td2d->loc[1] *= asp[1];
-               td2d->loc[2] = 0.0f;
+               if (BKE_mask_point_handles_mode_get(point) == MASK_HANDLE_MODE_STICK) {
+                       MaskHandleToTransData(point, MASK_WHICH_HANDLE_STICK,
+                                             td, td2d, tdm, asp, parent_matrix,
+                                             parent_inverse_matrix);
 
-               td2d->loc2d = tdm->handle;
+                       td++;
+                       td2d++;
+                       tdm++;
+               }
+               else {
+                       if (bezt->f1 & SELECT) {
+                               MaskHandleToTransData(point, MASK_WHICH_HANDLE_LEFT,
+                                                     td, td2d, tdm, asp, parent_matrix,
+                                                     parent_inverse_matrix);
 
-               td->flag = 0;
-               td->loc = td2d->loc;
-               mul_v2_m3v2(td->center, parent_matrix, bezt->vec[1]);
-               copy_v3_v3(td->iloc, td->loc);
+                               if (bezt->h1 == HD_VECT) {
+                                       bezt->h1 = HD_FREE;
+                               }
+                               else if (bezt->h1 == HD_AUTO) {
+                                       bezt->h1 = HD_ALIGN_DOUBLESIDE;
+                                       bezt->h2 = HD_ALIGN_DOUBLESIDE;
+                               }
 
-               memset(td->axismtx, 0, sizeof(td->axismtx));
-               td->axismtx[2][2] = 1.0f;
+                               td++;
+                               td2d++;
+                               tdm++;
+                       }
+                       if (bezt->f3 & SELECT) {
+                               MaskHandleToTransData(point, MASK_WHICH_HANDLE_RIGHT,
+                                                     td, td2d, tdm, asp, parent_matrix,
+                                                     parent_inverse_matrix);
 
-               td->ext = NULL;
-               td->val = NULL;
+                               if (bezt->h2 == HD_VECT) {
+                                       bezt->h2 = HD_FREE;
+                               }
+                               else if (bezt->h2 == HD_AUTO) {
+                                       bezt->h1 = HD_ALIGN_DOUBLESIDE;
+                                       bezt->h2 = HD_ALIGN_DOUBLESIDE;
+                               }
 
-               if (is_sel_any) {
-                       td->flag |= TD_SELECTED;
+                               td++;
+                               td2d++;
+                               tdm++;
+                       }
                }
-
-               td->dist = 0.0;
-
-               unit_m3(td->mtx);
-               unit_m3(td->smtx);
-
-               td++;
-               td2d++;
        }
 }
 
@@ -6731,10 +6806,23 @@ static void createTransMaskingData(bContext *C, TransInfo *t)
                                MaskSplinePoint *point = &spline->points[i];
 
                                if (MASKPOINT_ISSEL_ANY(point)) {
-                                       if (MASKPOINT_ISSEL_KNOT(point))
+                                       if (MASKPOINT_ISSEL_KNOT(point)) {
                                                countsel += 3;
-                                       else
-                                               countsel += 1;
+                                       }
+                                       else {
+                                               if (BKE_mask_point_handles_mode_get(point) == MASK_HANDLE_MODE_STICK) {
+                                                       countsel += 1;
+                                               }
+                                               else {
+                                                       BezTriple *bezt = &point->bezt;
+                                                       if (bezt->f1 & SELECT) {
+                                                               countsel++;
+                                                       }
+                                                       if (bezt->f3 & SELECT) {
+                                                               countsel++;
+                                                       }
+                                               }
+                                       }
                                }
 
                                if (propmode)
@@ -6782,9 +6870,24 @@ static void createTransMaskingData(bContext *C, TransInfo *t)
                                                tdm += 3;
                                        }
                                        else {
-                                               td++;
-                                               td2d++;
-                                               tdm++;
+                                               if (BKE_mask_point_handles_mode_get(point) == MASK_HANDLE_MODE_STICK) {
+                                                       td++;
+                                                       td2d++;
+                                                       tdm++;
+                                               }
+                                               else {
+                                                       BezTriple *bezt = &point->bezt;
+                                                       if (bezt->f1 & SELECT) {
+                                                               td++;
+                                                               td2d++;
+                                                               tdm++;
+                                                       }
+                                                       if (bezt->f3 & SELECT) {
+                                                               td++;
+                                                               td2d++;
+                                                               tdm++;
+                                                       }
+                                               }
                                        }
                                }
                        }
@@ -6810,10 +6913,20 @@ void flushTransMasking(TransInfo *t)
                mul_m3_v2(tdm->parent_inverse_matrix, td->loc2d);
 
                if (tdm->is_handle) {
-                       BKE_mask_point_set_handle(tdm->point, td->loc2d,
+                       BKE_mask_point_set_handle(tdm->point, tdm->which_handle,
+                                                 td->loc2d,
                                                  (t->flag & T_ALT_TRANSFORM) != 0,
                                                  tdm->orig_handle, tdm->vec);
                }
+
+               if (t->state == TRANS_CANCEL) {
+                       if (tdm->which_handle == MASK_WHICH_HANDLE_LEFT) {
+                               tdm->point->bezt.h1 = tdm->orig_handle_type;
+                       }
+                       else if (tdm->which_handle == MASK_WHICH_HANDLE_RIGHT) {
+                               tdm->point->bezt.h2 = tdm->orig_handle_type;
+                       }
+               }
        }
 }
 
index 0c9e9b01a76c5a58e5c3115ef3dbeb2a370d86a2..2d3a28fbd41b5bf3e6f2a34186f85fcc03d64ea0 100644 (file)
@@ -354,7 +354,8 @@ typedef enum eBezTriple_Handle {
        HD_AUTO = 1,
        HD_VECT = 2,
        HD_ALIGN = 3,
-       HD_AUTO_ANIM = 4        /* auto-clamped handles for animation */
+       HD_AUTO_ANIM = 4,         /* auto-clamped handles for animation */
+       HD_ALIGN_DOUBLESIDE = 5,  /* align handles, displayed both of them. used for masks */
 } eBezTriple_Handle;
 
 /* interpolation modes (used only for BezTriple->ipo) */
index 31e6b0e48e2d9f178b41a605a2977b5d1fb87c66..29bc15f1dbef6a0dc1a85ad935d607e8673ef199 100644 (file)
@@ -312,12 +312,83 @@ static int rna_MaskSplinePoint_handle_type_get(PointerRNA *ptr)
        return bezt->h1;
 }
 
+static MaskSpline *mask_spline_from_point(Mask *mask, MaskSplinePoint *point)
+{
+       MaskLayer *mask_layer;
+       for (mask_layer = mask->masklayers.first;
+            mask_layer;
+            mask_layer = mask_layer->next)
+       {
+               MaskSpline *spline;
+               for (spline = mask_layer->splines.first;
+                    spline;
+                    spline = spline->next)
+               {
+                       if (point >= spline->points && point < spline->points + spline->tot_point) {
+                               return spline;
+                       }
+               }
+       }
+       return NULL;
+}
+
+static void mask_point_check_stick(MaskSplinePoint *point)
+{
+       BezTriple *bezt = &point->bezt;
+       if (bezt->h1 == HD_ALIGN && bezt->h2 == HD_ALIGN) {
+               float vec[3];
+               sub_v3_v3v3(vec, bezt->vec[0], bezt->vec[1]);
+               add_v3_v3v3(bezt->vec[2], bezt->vec[1], vec);
+       }
+}
+
 static void rna_MaskSplinePoint_handle_type_set(PointerRNA *ptr, int value)
 {
        MaskSplinePoint *point = (MaskSplinePoint *) ptr->data;
        BezTriple *bezt = &point->bezt;
+       MaskSpline *spline = mask_spline_from_point((Mask *) ptr->id.data, point);
 
        bezt->h1 = bezt->h2 = value;
+       mask_point_check_stick(point);
+       BKE_mask_calc_handle_point(spline, point);
+}
+
+static int rna_MaskSplinePoint_handle_left_type_get(PointerRNA *ptr)
+{
+       MaskSplinePoint *point = (MaskSplinePoint *) ptr->data;
+       BezTriple *bezt = &point->bezt;
+
+       return bezt->h1;
+}
+
+static void rna_MaskSplinePoint_handle_left_type_set(PointerRNA *ptr, int value)
+{
+       MaskSplinePoint *point = (MaskSplinePoint *) ptr->data;
+       BezTriple *bezt = &point->bezt;
+       MaskSpline *spline = mask_spline_from_point((Mask *) ptr->id.data, point);
+
+       bezt->h1 = value;
+       mask_point_check_stick(point);
+       BKE_mask_calc_handle_point(spline, point);
+}
+
+static int rna_MaskSplinePoint_handle_right_type_get(PointerRNA *ptr)
+{
+       MaskSplinePoint *point = (MaskSplinePoint *) ptr->data;
+       BezTriple *bezt = &point->bezt;
+
+       return bezt->h2;
+}
+
+static void rna_MaskSplinePoint_handle_right_type_set(PointerRNA *ptr, int value)
+{
+       MaskSplinePoint *point = (MaskSplinePoint *) ptr->data;
+       BezTriple *bezt = &point->bezt;
+       MaskSpline *spline = mask_spline_from_point((Mask *) ptr->id.data, point);
+
+       bezt->h2 = value;
+       mask_point_check_stick(point);
+       BKE_mask_calc_handle_point(spline, point);
 }
 
 /* ** API **  */
@@ -608,7 +679,9 @@ static void rna_def_maskSplinePoint(BlenderRNA *brna)
        static EnumPropertyItem handle_type_items[] = {
                {HD_AUTO, "AUTO", 0, "Auto", ""},
                {HD_VECT, "VECTOR", 0, "Vector", ""},
-               {HD_ALIGN, "ALIGNED", 0, "Aligned", ""},
+               {HD_ALIGN, "ALIGNED", 0, "Aligned Single", ""},
+               {HD_ALIGN_DOUBLESIDE, "ALIGNED_DOUBLESIDE", 0, "Aligned", ""},
+               {HD_FREE, "FREE", 0, "Free", ""},
                {0, NULL, 0, NULL, NULL}};
 
        rna_def_maskSplinePointUW(brna);
@@ -642,6 +715,27 @@ static void rna_def_maskSplinePoint(BlenderRNA *brna)
        RNA_def_property_ui_text(prop, "Handle Type", "Handle type");
        RNA_def_property_update(prop, 0, "rna_Mask_update_data");
 
+       /* handle_type */
+       prop = RNA_def_property(srna, "handle_left_type", PROP_ENUM, PROP_NONE);
+       RNA_def_property_enum_funcs(prop, "rna_MaskSplinePoint_handle_left_type_get", "rna_MaskSplinePoint_handle_left_type_set", NULL);
+       RNA_def_property_enum_items(prop, handle_type_items);
+       RNA_def_property_ui_text(prop, "Handle 1 Type", "Handle type");
+       RNA_def_property_update(prop, 0, "rna_Mask_update_data");
+
+       /* handle_right */
+       prop = RNA_def_property(srna, "handle_right_type", PROP_ENUM, PROP_NONE);
+       RNA_def_property_enum_funcs(prop, "rna_MaskSplinePoint_handle_right_type_get", "rna_MaskSplinePoint_handle_right_type_set", NULL);
+       RNA_def_property_enum_items(prop, handle_type_items);
+       RNA_def_property_ui_text(prop, "Handle 2 Type", "Handle type");
+       RNA_def_property_update(prop, 0, "rna_Mask_update_data");
+
+       /* weight */
+       prop = RNA_def_property(srna, "weight", PROP_FLOAT, PROP_NONE);
+       RNA_def_property_float_sdna(prop, NULL, "bezt.weight");
+       RNA_def_property_range(prop, 0.0, 1.0);
+       RNA_def_property_ui_text(prop, "Weight", "Weight of the point");
+       RNA_def_property_update(prop, 0, "rna_Mask_update_data");
+
        /* select */
        prop = RNA_def_property(srna, "select", PROP_BOOLEAN, PROP_NONE);
        RNA_def_property_boolean_sdna(prop, NULL, "bezt.f1", SELECT);
index 41953fb02394ee440c1ce55d71aba80908204e95..fd8d8aede878746b8821ede16aa63117e908964c 100644 (file)
@@ -1292,7 +1292,7 @@ static void rna_def_userdef_theme_spaces_face(StructRNA *srna)
        RNA_def_property_update(prop, 0, "rna_userdef_update");
 }
 
-static void rna_def_userdef_theme_spaces_curves(StructRNA *srna, short incl_nurbs)
+static void rna_def_userdef_theme_spaces_curves(StructRNA *srna, bool incl_nurbs, bool incl_lastsel, bool incl_vector)
 {
        PropertyRNA *prop;
        
@@ -1340,11 +1340,19 @@ static void rna_def_userdef_theme_spaces_curves(StructRNA *srna, short incl_nurb
        RNA_def_property_ui_text(prop, "Auto handle color", "");
        RNA_def_property_update(prop, 0, "rna_userdef_update");
 
-       prop = RNA_def_property(srna, "handle_vect", PROP_FLOAT, PROP_COLOR_GAMMA);
-       RNA_def_property_float_sdna(prop, NULL, "handle_vect");
-       RNA_def_property_array(prop, 3);
-       RNA_def_property_ui_text(prop, "Vector handle color", "");
-       RNA_def_property_update(prop, 0, "rna_userdef_update");
+       if (incl_vector) {
+               prop = RNA_def_property(srna, "handle_vect", PROP_FLOAT, PROP_COLOR_GAMMA);
+               RNA_def_property_float_sdna(prop, NULL, "handle_vect");
+               RNA_def_property_array(prop, 3);
+               RNA_def_property_ui_text(prop, "Vector handle color", "");
+               RNA_def_property_update(prop, 0, "rna_userdef_update");
+
+               prop = RNA_def_property(srna, "handle_sel_vect", PROP_FLOAT, PROP_COLOR_GAMMA);
+               RNA_def_property_float_sdna(prop, NULL, "handle_sel_vect");
+               RNA_def_property_array(prop, 3);
+               RNA_def_property_ui_text(prop, "Vector handle selected color", "");
+               RNA_def_property_update(prop, 0, "rna_userdef_update");
+       }
 
        prop = RNA_def_property(srna, "handle_align", PROP_FLOAT, PROP_COLOR_GAMMA);
        RNA_def_property_float_sdna(prop, NULL, "handle_align");
@@ -1364,19 +1372,13 @@ static void rna_def_userdef_theme_spaces_curves(StructRNA *srna, short incl_nurb
        RNA_def_property_ui_text(prop, "Auto handle selected color", "");
        RNA_def_property_update(prop, 0, "rna_userdef_update");
 
-       prop = RNA_def_property(srna, "handle_sel_vect", PROP_FLOAT, PROP_COLOR_GAMMA);
-       RNA_def_property_float_sdna(prop, NULL, "handle_sel_vect");
-       RNA_def_property_array(prop, 3);
-       RNA_def_property_ui_text(prop, "Vector handle selected color", "");
-       RNA_def_property_update(prop, 0, "rna_userdef_update");
-
        prop = RNA_def_property(srna, "handle_sel_align", PROP_FLOAT, PROP_COLOR_GAMMA);
        RNA_def_property_float_sdna(prop, NULL, "handle_sel_align");
        RNA_def_property_array(prop, 3);
        RNA_def_property_ui_text(prop, "Align handle selected color", "");
        RNA_def_property_update(prop, 0, "rna_userdef_update");
        
-       if (incl_nurbs == 0) {
+       if (incl_nurbs == false) {
                /* assume that when nurbs are off, this is for 2D (i.e. anim) editors */
                prop = RNA_def_property(srna, "handle_auto_clamped", PROP_FLOAT, PROP_COLOR_GAMMA);
                RNA_def_property_float_sdna(prop, NULL, "handle_auto_clamped");
@@ -1391,11 +1393,13 @@ static void rna_def_userdef_theme_spaces_curves(StructRNA *srna, short incl_nurb
                RNA_def_property_update(prop, 0, "rna_userdef_update");
        }
 
-       prop = RNA_def_property(srna, "lastsel_point", PROP_FLOAT, PROP_COLOR_GAMMA);
-       RNA_def_property_float_sdna(prop, NULL, "lastsel_point");
-       RNA_def_property_array(prop, 3);
-       RNA_def_property_ui_text(prop, "Last selected point", "");
-       RNA_def_property_update(prop, 0, "rna_userdef_update");
+       if (incl_lastsel) {
+               prop = RNA_def_property(srna, "lastsel_point", PROP_FLOAT, PROP_COLOR_GAMMA);
+               RNA_def_property_float_sdna(prop, NULL, "lastsel_point");
+               RNA_def_property_array(prop, 3);
+               RNA_def_property_ui_text(prop, "Last selected point", "");
+               RNA_def_property_update(prop, 0, "rna_userdef_update");
+       }
 }
 
 static void rna_def_userdef_theme_space_view3d(BlenderRNA *brna)
@@ -1484,7 +1488,7 @@ static void rna_def_userdef_theme_space_view3d(BlenderRNA *brna)
        rna_def_userdef_theme_spaces_vertex(srna);
        rna_def_userdef_theme_spaces_edge(srna);
        rna_def_userdef_theme_spaces_face(srna);
-       rna_def_userdef_theme_spaces_curves(srna, 1);
+       rna_def_userdef_theme_spaces_curves(srna, true, true, true);
 
        prop = RNA_def_property(srna, "extra_edge_len", PROP_FLOAT, PROP_COLOR_GAMMA);
        RNA_def_property_array(prop, 3);
@@ -1628,7 +1632,7 @@ static void rna_def_userdef_theme_space_graph(BlenderRNA *brna)
        RNA_def_property_update(prop, 0, "rna_userdef_update");
        
        rna_def_userdef_theme_spaces_vertex(srna);
-       rna_def_userdef_theme_spaces_curves(srna, 0);
+       rna_def_userdef_theme_spaces_curves(srna, false, true, true);
        
        prop = RNA_def_property(srna, "handle_vertex", PROP_FLOAT, PROP_COLOR_GAMMA);
        RNA_def_property_array(prop, 3);
@@ -2247,6 +2251,8 @@ static void rna_def_userdef_theme_space_image(BlenderRNA *brna)
        RNA_def_property_array(prop, 4);
        RNA_def_property_ui_text(prop, "Other Object UVs", "");
        RNA_def_property_update(prop, 0, "rna_userdef_update");
+
+       rna_def_userdef_theme_spaces_curves(srna, false, false, false);
 }
 
 static void rna_def_userdef_theme_space_seq(BlenderRNA *brna)
@@ -2759,6 +2765,8 @@ static void rna_def_userdef_theme_space_clip(BlenderRNA *brna)
        RNA_def_property_array(prop, 3);
        RNA_def_property_ui_text(prop, "Strips Selected", "");
        RNA_def_property_update(prop, 0, "rna_userdef_update");
+
+       rna_def_userdef_theme_spaces_curves(srna, false, false, false);
 }
 
 static void rna_def_userdef_themes(BlenderRNA *brna)