Commit: c10359cb81e5d2bc4c7647dc1987ae73f45dcd7b
Author: Joshua Leung
Date:   Sat Oct 11 11:29:23 2014 +1300
Branches: GPencil_EditStrokes
https://developer.blender.org/rBc10359cb81e5d2bc4c7647dc1987ae73f45dcd7b

GPencil: Added operator to allow directly clicking on strokes to select them 
and their points

* D RMB       = Select the stroke point under the cursor
* D Shift RMB = Select the stroke point udner the cursor, while retaining 
existing selection
* D W         = Select whole stroke

As a result of these changes, the eraser has had to be moved to another binding,
i.e. D X.  This doesn't really work that great since it starts working 
immediately.

===================================================================

M       source/blender/editors/gpencil/gpencil_intern.h
M       source/blender/editors/gpencil/gpencil_ops.c
M       source/blender/editors/gpencil/gpencil_select.c

===================================================================

diff --git a/source/blender/editors/gpencil/gpencil_intern.h 
b/source/blender/editors/gpencil/gpencil_intern.h
index 2f91bff..e69afa9 100644
--- a/source/blender/editors/gpencil/gpencil_intern.h
+++ b/source/blender/editors/gpencil/gpencil_intern.h
@@ -115,6 +115,7 @@ typedef enum eGPencil_PaintModes {
 
 /* stroke editing ----- */
 
+void GPENCIL_OT_select(struct wmOperatorType *ot);
 void GPENCIL_OT_select_all(struct wmOperatorType *ot);
 void GPENCIL_OT_select_circle(struct wmOperatorType *ot);
 
diff --git a/source/blender/editors/gpencil/gpencil_ops.c 
b/source/blender/editors/gpencil/gpencil_ops.c
index 46f9810..70d1f56 100644
--- a/source/blender/editors/gpencil/gpencil_ops.c
+++ b/source/blender/editors/gpencil/gpencil_ops.c
@@ -68,7 +68,7 @@ void ED_keymap_gpencil(wmKeyConfig *keyconf)
        RNA_enum_set(kmi->ptr, "mode", GP_PAINTMODE_DRAW_POLY);
        
        /* erase */
-       kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_draw", RIGHTMOUSE, 
KM_PRESS, 0, DKEY);
+       kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_draw", XKEY, KM_PRESS, 0, 
DKEY);
        RNA_enum_set(kmi->ptr, "mode", GP_PAINTMODE_ERASER);
        
        /* Selection ------------------------------------- */
@@ -83,6 +83,17 @@ void ED_keymap_gpencil(wmKeyConfig *keyconf)
        /* circle select */
        WM_keymap_add_item(keymap, "GPENCIL_OT_select_circle", CKEY, KM_PRESS, 
0, DKEY);
        
+       /* normal select */
+       WM_keymap_add_item(keymap, "GPENCIL_OT_select", RIGHTMOUSE, KM_PRESS, 
0, DKEY);
+       
+       kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_select", RIGHTMOUSE, 
KM_PRESS, KM_SHIFT, DKEY);
+       RNA_boolean_set(kmi->ptr, "extend", true);
+       
+       /* whole stroke select */
+       kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_select", WKEY, KM_PRESS, 
0, DKEY);
+       RNA_boolean_set(kmi->ptr, "entire_strokes", true);
+       
+       
        /* Editing ----------------------------------------- */
        WM_keymap_add_item(keymap, "GPENCIL_OT_strokes_duplicate", EKEY, 
KM_PRESS, 0, DKEY);
        
@@ -109,6 +120,7 @@ void ED_operatortypes_gpencil(void)
        
        /* Editing (Strokes) ------------ */
        
+       WM_operatortype_append(GPENCIL_OT_select);
        WM_operatortype_append(GPENCIL_OT_select_all);
        WM_operatortype_append(GPENCIL_OT_select_circle);
        
diff --git a/source/blender/editors/gpencil/gpencil_select.c 
b/source/blender/editors/gpencil/gpencil_select.c
index 6875014..6088c63 100644
--- a/source/blender/editors/gpencil/gpencil_select.c
+++ b/source/blender/editors/gpencil/gpencil_select.c
@@ -362,5 +362,216 @@ void GPENCIL_OT_select_circle(wmOperatorType *ot)
 }
 
 /* ********************************************** */
+/* Mouse Click to Select */
+
+static int gpencil_select_exec(bContext *C, wmOperator *op)
+{
+       ScrArea *sa = CTX_wm_area(C);
+       ARegion *ar = CTX_wm_region(C);
+       View2D *v2d = &ar->v2d;
+       
+       Scene *scene = CTX_data_scene(C);
+       bGPdata *gpd = ED_gpencil_data_get_active(C);
+       
+       /* "radius" is simply a threshold (screen space) to make it easier to 
test with a tolerance */
+       const float radius = 0.35f * U.widget_unit;
+       const int radius_squared = (int)(radius * radius);
+       
+       rctf *subrect = NULL;       /* for using the camera rect within the 3d 
view */
+       rctf subrect_data = {0.0f};
+       
+       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 whole = RNA_boolean_get(op->ptr, "entire_strokes");
+       
+       int location[2] = {0};
+       int mx, my;
+       
+       bGPDstroke *hit_stroke = NULL;
+       bGPDspoint *hit_point = NULL;
+       
+       /* sanity checks */
+       if (gpd == NULL) {
+               BKE_report(op->reports, RPT_ERROR, "No Grease Pencil data");
+               return OPERATOR_CANCELLED;
+       }
+       if (sa == NULL) {
+               BKE_report(op->reports, RPT_ERROR, "No active area");
+               return OPERATOR_CANCELLED;
+       }
+       
+       /* for 3D View, init depth buffer stuff used for 3D projections... */
+       if (sa->spacetype == SPACE_VIEW3D) {
+               wmWindow *win = CTX_wm_window(C);
+               View3D *v3d = (View3D *)CTX_wm_space_data(C);
+               RegionView3D *rv3d = ar->regiondata;
+               
+               /* init 3d depth buffers */
+               view3d_operator_needs_opengl(C);
+               view3d_region_operator_needs_opengl(win, ar);
+               ED_view3d_autodist_init(scene, ar, v3d, 0);
+               
+               /* for camera view set the subrect */
+               if (rv3d->persp == RV3D_CAMOB) {
+                       ED_view3d_calc_camera_border(scene, ar, v3d, rv3d, 
&subrect_data, true); /* no shift */
+                       subrect = &subrect_data;
+               }
+       }
+       
+       /* get mouse location */
+       RNA_int_get_array(op->ptr, "location", location);
+       
+       mx = location[0];
+       my = location[1];
+       
+       /* First Pass: Find stroke point which gets hit */
+       /* XXX: maybe we should go from the top of the stack down instead... */
+       GP_VISIBLE_STROKES_ITER_BEGIN(gpd, gps)
+       {
+               bGPDspoint *pt;
+               int i;
+               int hit_index = -1;
+               
+               /* firstly, check for hit-point */
+               for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
+                       int x0, y0;
+                       
+                       gp_point_to_xy(ar, v2d, subrect, gps, pt, &x0, &y0);
+               
+                       /* do boundbox check first */
+                       if (!ELEM(V2D_IS_CLIPPED, x0, x0)) {
+                               /* only check if point is inside */
+                               if (((x0 - mx) * (x0 - mx) + (y0 - my) * (y0 - 
my)) <= radius_squared) {                                
+                                       hit_stroke = gps;
+                                       hit_point  = pt;
+                                       break;
+                               }
+                       }
+               }
+               
+               /* skip to next stroke if nothing found */
+               if (hit_index == -1) 
+                       continue;
+       }
+       GP_STROKES_ITER_END;
+       
+       /* Abort if nothing hit... */
+       if (ELEM(NULL, hit_stroke, hit_point)) {
+               return OPERATOR_CANCELLED;
+       }
+       
+       /* adjust selection behaviour - for toggle option */
+       if (toggle) {
+               deselect = (hit_point->flag & GP_SPOINT_SELECT) != 0;
+       }
+       
+       /* If not extending selection, deselect everything else */
+       if (extend == false) {
+               GP_VISIBLE_STROKES_ITER_BEGIN(gpd, gps)
+               {                       
+                       /* deselect stroke and its points if selected */
+                       if (gps->flag & GP_STROKE_SELECT) {
+                               bGPDspoint *pt;
+                               int i;
+                       
+                               /* deselect points */
+                               for (i = 0, pt = gps->points; i < 
gps->totpoints; i++, pt++) {
+                                       pt->flag &= ~GP_SPOINT_SELECT;
+                               }
+                               
+                               /* deselect stroke itself too */
+                               gps->flag &= ~GP_STROKE_SELECT;
+                       }
+               }
+               GP_STROKES_ITER_END;
+       }
+       
+       /* Perform selection operations... */
+       if (whole) {
+               bGPDspoint *pt;
+               int i;
+               
+               /* entire stroke's points */
+               for (i = 0, pt = hit_stroke->points; i < hit_stroke->totpoints; 
i++, pt++) {
+                       if (deselect == false)
+                               pt->flag |= GP_SPOINT_SELECT;
+                       else
+                               pt->flag &= ~GP_SPOINT_SELECT;
+               }
+               
+               /* stroke too... */
+               if (deselect == false)
+                       hit_stroke->flag |= GP_STROKE_SELECT;
+               else
+                       hit_stroke->flag &= ~GP_STROKE_SELECT;
+       }
+       else {
+               /* just the point (and the stroke) */
+               if (deselect == false) {
+                       /* we're adding selection, so selection must be true */
+                       hit_point->flag  |= GP_SPOINT_SELECT;
+                       hit_stroke->flag |= GP_STROKE_SELECT;
+               }
+               else {
+                       bGPDspoint *pt;
+                       int i;
+                       
+                       /* deselect point */
+                       hit_point->flag &= ~GP_SPOINT_SELECT;
+                       
+                       /* ensure that stroke is selected correctly */
+                       hit_stroke->flag &= ~GP_STROKE_SELECT;
+                       
+                       for (i = 0, pt = hit_stroke->points; i < 
hit_stroke->totpoints; i++, pt++) {
+                               if (pt->flag & GP_SPOINT_SELECT) {
+                                       hit_stroke->flag |= GP_STROKE_SELECT;
+                                       break;
+                               }
+                       }
+               }
+       }
+       
+       /* updates */
+       if (hit_point != NULL) {
+               WM_event_add_notifier(C, NC_GPENCIL | NA_SELECTED, NULL);
+       }
+       
+       return OPERATOR_FINISHED;
+}
+
+static int gpencil_select_invoke(bContext *C, wmOperator *op, const wmEvent 
*event)
+{
+       RNA_int_set_array(op->ptr, "location", event->mval);
+       return gpencil_select_exec(C, op);
+}
+
+void GPENCIL_OT_select(wmOperatorType *ot)
+{
+       PropertyRNA *prop;
+       
+       /* identifiers */
+       ot->name = "Select";
+       ot->description = "Select Grease Pencil strokes and/or stroke points";
+       ot->idname = "GPENCIL_OT_select";
+       
+       /* callbacks */
+       ot->invoke = gpencil_select_invoke;
+       ot->exec = gpencil_select_exec;
+       ot->poll = gpencil_select_poll;
+       
+       /* flag */
+       ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+       
+       /* properties */
+       WM_operator_properties_mouse_select(ot);
+       
+       RNA_def_boolean(ot->srna, "entire_strokes", false, "Entire Strokes", 
"Select entire strokes instead of just the nearest stroke vertex");
+       
+       prop = RNA_def_int_vector(ot->srna, "location", 2, NULL, INT_MIN, 
INT_MAX, "Location", "Mouse location", INT_MIN, INT_MAX);
+       RNA_def_property_flag(prop, PROP_HIDDEN);
+}
+
+/* ********************************************** */
 
  
\ No newline at end of file

_______________________________________________
Bf-blender-cvs mailing list
[email protected]
http://lists.blender.org/mailman/listinfo/bf-blender-cvs

Reply via email to