2.5 - Action Editor Select Tools
authorJoshua Leung <aligorith@gmail.com>
Tue, 23 Dec 2008 23:34:19 +0000 (23:34 +0000)
committerJoshua Leung <aligorith@gmail.com>
Tue, 23 Dec 2008 23:34:19 +0000 (23:34 +0000)
Ported the following tools
* borderselect
* invert selection

Note: while porting these, I noticed a few issues with some stuff that still needs to be cleaned up.

Events handling in scrollers won't work yet, for the useful select all in frame(-range) or select all in channel(s). We should probably review ways to expose this more clearly in the UI too.

source/blender/editors/animation/anim_ops.c
source/blender/editors/animation/keyframes_edit.c
source/blender/editors/include/ED_keyframes_edit.h
source/blender/editors/space_action/action_intern.h
source/blender/editors/space_action/action_ops.c
source/blender/editors/space_action/action_select.c

index 4321c89f7300f3d5abf7b78fe16e01fb0dc945ab..be3ab0502c4f106cfed3dafb4845a9991f1934b4 100644 (file)
@@ -270,7 +270,6 @@ void ED_ANIM_OT_previewrange_define(wmOperatorType *ot)
        RNA_def_property(ot->srna, "xmin", PROP_INT, PROP_NONE);
        RNA_def_property(ot->srna, "xmax", PROP_INT, PROP_NONE);
                /* these are not used, but are needed by borderselect gesture operator stuff */
-       RNA_def_property(ot->srna, "event_type", PROP_INT, PROP_NONE);
        RNA_def_property(ot->srna, "ymin", PROP_INT, PROP_NONE);
        RNA_def_property(ot->srna, "ymax", PROP_INT, PROP_NONE);
 }
index 152d07b83f6426ae066d0be3576bd2b3c7e76064..951e91dc55ac78fc7ecdcde7acabb239b4fe4cc8 100644 (file)
@@ -613,7 +613,7 @@ int fullselect_ipo_keys(Ipo *ipo)
 }
 
 
-void borderselect_icu_key(Scene *scene, IpoCurve *icu, float xmin, float xmax, BeztEditFunc select_cb)
+void borderselect_icu_key(IpoCurve *icu, float xmin, float xmax, BeztEditFunc select_cb)
 {
        /* Selects all bezier triples in the Ipocurve 
         * between times xmin and xmax, using the selection
@@ -623,18 +623,19 @@ void borderselect_icu_key(Scene *scene, IpoCurve *icu, float xmin, float xmax, B
        int i;
        
        /* loop through all of the bezier triples in
-       * the Ipocurve -- if the triple occurs between
-       * times xmin and xmax then select it using the selection
-       * function
-       */
+        * the Ipocurve -- if the triple occurs between
+        * times xmin and xmax then select it using the selection
+        * function
+        */
        for (i=0, bezt=icu->bezt; i<icu->totvert; i++, bezt++) {
                if ((bezt->vec[1][0] > xmin) && (bezt->vec[1][0] < xmax)) {
-                       select_cb(scene, bezt);
+                       /* scene is NULL (irrelevant here) */
+                       select_cb(NULL, bezt); 
                }
        }
 }
 
-void borderselect_ipo_key(Scene *scene, Ipo *ipo, float xmin, float xmax, short selectmode)
+void borderselect_ipo_key(Ipo *ipo, float xmin, float xmax, short selectmode)
 {
        /* Selects all bezier triples in each Ipocurve of the
         * Ipo between times xmin and xmax, using the selection mode.
@@ -660,7 +661,7 @@ void borderselect_ipo_key(Scene *scene, Ipo *ipo, float xmin, float xmax, short
                * function
                */
        for (icu=ipo->curve.first; icu; icu=icu->next) {
-               borderselect_icu_key(scene, icu, xmin, xmax, select_cb);
+               borderselect_icu_key(icu, xmin, xmax, select_cb);
        }
 }
 
index d312289ca2a29327947f55628cfb31d8f649c26e..1015de2e9e490302f1b719bb47c3493b642e8a11 100644 (file)
@@ -101,6 +101,9 @@ void select_icu_key(struct Scene *scene, struct IpoCurve *icu, float selx, short
 short is_ipo_key_selected(struct Ipo *ipo);
 void set_ipo_key_selection(struct Ipo *ipo, short sel);
 
+void borderselect_ipo_key(struct Ipo *ipo, float xmin, float xmax, short selectmode);
+void borderselect_icu_key(struct IpoCurve *icu, float xmin, float xmax, BeztEditFunc select_cb);
+
 
 /* ************************************************ */
 
index 3ea3e179a80d6b0b9de28322f31006c6bfc38ef8..788e5df2d13628b16938722de6f009c037668d91 100644 (file)
@@ -46,6 +46,7 @@ void action_header_buttons(const struct bContext *C, struct ARegion *ar);
 
 /* action_select.c */
 void ED_ACT_OT_keyframes_deselectall(struct wmOperatorType *ot);
+void ED_ACT_OT_keyframes_borderselect(struct wmOperatorType *ot);
 void ED_ACT_OT_keyframes_clickselect(struct wmOperatorType *ot);
 
 /* action_ops.c */
index 4fafb176a92884509d117f81e6bf187bd3ded215..6d6bee90171468dce8de061a051d1c9751794224 100644 (file)
@@ -64,6 +64,7 @@ void action_operatortypes(void)
        /* keyframes */
        WM_operatortype_append(ED_ACT_OT_keyframes_clickselect);
        WM_operatortype_append(ED_ACT_OT_keyframes_deselectall);
+       WM_operatortype_append(ED_ACT_OT_keyframes_borderselect);
 }
 
 /* ************************** registration - keymaps **********************************/
@@ -77,6 +78,10 @@ static void action_keymap_keyframes (ListBase *keymap)
        
                /* deselect all */
        WM_keymap_add_item(keymap, "ED_ACT_OT_keyframes_deselectall", AKEY, KM_PRESS, 0, 0);
+       RNA_boolean_set(WM_keymap_add_item(keymap, "ED_ACT_OT_keyframes_deselectall", IKEY, KM_PRESS, KM_CTRL, 0)->ptr, "invert", 1);
+       
+               /* borderselect */
+       WM_keymap_add_item(keymap, "ED_ACT_OT_keyframes_borderselect", BKEY, KM_PRESS, 0, 0);
 }
 
 /* --------------- */
index 887de081de87b7f5afb22fd2f8ee6eecfe685e23..0a5a2969a0f728e5eed3c2fafe9c5025b7be4aa7 100644 (file)
@@ -317,9 +317,20 @@ static void *get_nearest_action_key (bAnimContext *ac, int mval[2], float *selx,
 /* KEYFRAMES STUFF */
 
 /* ******************** Deselect All Operator ***************************** */
+/* This operator works in one of three ways:
+ *     1) (de)select all (AKEY) - test if select all or deselect all
+ *     2) invert all (CTRL-IKEY) - invert selection of all keyframes
+ *     3) (de)select all - no testing is done; only for use internal tools as normal function...
+ */
 
 /* Deselects keyframes in the action editor
  *     - This is called by the deselect all operator, as well as other ones!
+ *
+ *     - test: check if select or deselect all
+ *     - sel: how to select keyframes 
+ *             0 = deselect
+ *             1 = select
+ *             2 = invert
  */
 static void deselect_action_keys (bAnimContext *ac, short test, short sel)
 {
@@ -368,7 +379,7 @@ static void deselect_action_keys (bAnimContext *ac, short test, short sel)
 
 /* ------------------- */
 
-static int actkeys_deselectall_invoke(bContext *C, wmOperator *op, wmEvent *event)
+static int actkeys_deselectall_exec(bContext *C, wmOperator *op)
 {
        bAnimContext ac;
        
@@ -377,7 +388,10 @@ static int actkeys_deselectall_invoke(bContext *C, wmOperator *op, wmEvent *even
                return OPERATOR_CANCELLED;
                
        /* 'standard' behaviour - check if selected, then apply relevant selection */
-       deselect_action_keys(&ac, 1, 1);
+       if (RNA_boolean_get(op->ptr, "invert"))
+               deselect_action_keys(&ac, 0, 2);
+       else
+               deselect_action_keys(&ac, 1, 1);
        
        /* set notifier tha things have changed */
        ED_area_tag_redraw(CTX_wm_area(C)); // FIXME... should be updating 'keyframes' data context or so instead!
@@ -388,12 +402,223 @@ static int actkeys_deselectall_invoke(bContext *C, wmOperator *op, wmEvent *even
 void ED_ACT_OT_keyframes_deselectall (wmOperatorType *ot)
 {
        /* identifiers */
-       ot->name= "Deselect All";
+       ot->name= "Select All";
        ot->idname= "ED_ACT_OT_keyframes_deselectall";
        
        /* api callbacks */
-       ot->invoke= actkeys_deselectall_invoke;
-       //ot->poll= ED_operator_areaactive;
+       ot->exec= actkeys_deselectall_exec;
+       ot->poll= ED_operator_areaactive;
+       
+       /* props */
+       RNA_def_property(ot->srna, "invert", PROP_BOOLEAN, PROP_NONE);
+}
+
+/* ******************** Border Select Operator **************************** */
+/* This operator works in one of three ways:
+ *     1) borderselect over keys (BKEY) - mouse over main area when initialised; will select keys in region
+ *     2) borderselect over horizontal scroller - mouse over horizontal scroller when initialised; will select keys in frame range
+ *     3) borderselect over vertical scroller - mouse over vertical scroller when initialised; will select keys in row range
+ */
+
+static void borderselect_action (bAnimContext *ac, rcti rect, short in_scroller, short selectmode)
+{
+       ListBase anim_data = {NULL, NULL};
+       bAnimListElem *ale;
+       int filter;
+       
+       View2D *v2d= &ac->ar->v2d;
+       BeztEditFunc select_cb;
+       rctf rectf;
+       float ymin=0, ymax=ACHANNEL_HEIGHT;
+       
+       UI_view2d_region_to_view(v2d, rect.xmin, rect.ymin+2, &rectf.xmin, &rectf.ymin);
+       UI_view2d_region_to_view(v2d, rect.xmax, rect.ymax-2, &rectf.xmax, &rectf.ymax);
+       
+       /* filter data */
+       filter= (ANIMFILTER_VISIBLE | ANIMFILTER_CHANNELS);
+       ANIM_animdata_filter(&anim_data, filter, ac->data, ac->datatype);
+       
+       /* get selection editing func */
+       select_cb= ANIM_editkeyframes_select(selectmode);
+       
+       /* loop over data, doing border select */
+       for (ale= anim_data.first; ale; ale= ale->next) {
+               Object *nob= ANIM_nla_mapping_get(ac, ale);
+               
+               ymin= ymax - ACHANNEL_STEP;
+               
+               /* if action is mapped in NLA, it returns a correction */
+               if (nob) {
+                       rectf.xmin= get_action_frame(nob, rectf.xmin);
+                       rectf.xmax= get_action_frame(nob, rectf.xmax);
+               }
+               
+               /* what gets selected depends on the mode (based on initial position of cursor) */
+               switch (in_scroller) {
+               case 'h': /* all in frame(s) */
+                       if (ale->key_data) {
+                               if (ale->datatype == ALE_IPO)
+                                       borderselect_ipo_key(ale->key_data, rectf.xmin, rectf.xmax, selectmode);
+                               else if (ale->datatype == ALE_ICU)
+                                       borderselect_icu_key(ale->key_data, rectf.xmin, rectf.xmax, select_cb);
+                       }
+                       else if (ale->type == ANIMTYPE_GROUP) {
+                               bActionGroup *agrp= ale->data;
+                               bActionChannel *achan;
+                               bConstraintChannel *conchan;
+                               
+                               for (achan= agrp->channels.first; achan && achan->grp==agrp; achan= achan->next) {
+                                       borderselect_ipo_key(achan->ipo, rectf.xmin, rectf.xmax, selectmode);
+                                       
+                                       for (conchan=achan->constraintChannels.first; conchan; conchan=conchan->next)
+                                               borderselect_ipo_key(conchan->ipo, rectf.xmin, rectf.xmax, selectmode);
+                               }
+                       }
+                       //else if (ale->type == ANIMTYPE_GPLAYER) {
+                       //      borderselect_gplayer_frames(ale->data, rectf.xmin, rectf.xmax, selectmode);
+                       //}
+                       break;
+               case 'v': /* all in channel(s) */
+                       if (!((ymax < rectf.ymin) || (ymin > rectf.ymax))) {
+                               if (ale->key_data) {
+                                       if (ale->datatype == ALE_IPO)
+                                               ipo_keys_bezier_loop(ac->scene, ale->key_data, select_cb, NULL);
+                                       else if (ale->datatype == ALE_ICU)
+                                               icu_keys_bezier_loop(ac->scene, ale->key_data, select_cb, NULL);
+                               }
+                               else if (ale->type == ANIMTYPE_GROUP) {
+                                       bActionGroup *agrp= ale->data;
+                                       bActionChannel *achan;
+                                       bConstraintChannel *conchan;
+                                       
+                                       for (achan= agrp->channels.first; achan && achan->grp==agrp; achan= achan->next) {
+                                               ipo_keys_bezier_loop(ac->scene, achan->ipo, select_cb, NULL);
+                                               
+                                               for (conchan=achan->constraintChannels.first; conchan; conchan=conchan->next)
+                                                       ipo_keys_bezier_loop(ac->scene, conchan->ipo, select_cb, NULL);
+                                       }
+                               }
+                               //else if (ale->type == ANIMTYPE_GPLAYER) {
+                               //      select_gpencil_frames(ale->data, selectmode);
+                               //}
+                       }
+                       break;
+               default: /* any keyframe inside region defined by region */
+                       if (!((ymax < rectf.ymin) || (ymin > rectf.ymax))) {
+                               if (ale->key_data) {
+                                       if (ale->datatype == ALE_IPO)
+                                               borderselect_ipo_key(ale->key_data, rectf.xmin, rectf.xmax, selectmode);
+                                       else if (ale->datatype == ALE_ICU)
+                                               borderselect_icu_key(ale->key_data, rectf.xmin, rectf.xmax, select_cb);
+                               }
+                               else if (ale->type == ANIMTYPE_GROUP) {
+                                       // fixme: need a nicer way of dealing with summaries!
+                                       bActionGroup *agrp= ale->data;
+                                       bActionChannel *achan;
+                                       bConstraintChannel *conchan;
+                                       
+                                       for (achan= agrp->channels.first; achan && achan->grp==agrp; achan= achan->next) {
+                                               borderselect_ipo_key(achan->ipo, rectf.xmin, rectf.xmax, selectmode);
+                                               
+                                               for (conchan=achan->constraintChannels.first; conchan; conchan=conchan->next)
+                                                       borderselect_ipo_key(conchan->ipo, rectf.xmin, rectf.xmax, selectmode);
+                                       }
+                               }
+                               else if (ale->type == ANIMTYPE_ACT) {
+                                       // fixme: need a nicer way of dealing with summaries!
+                               }
+                               else if (ale->type == ANIMTYPE_OB) {
+                                       // fixme: need a nicer way of dealing with summaries!
+                               }
+                               //else if (ale->type == ANIMTYPE_GPLAYER) {
+                               ////    borderselect_gplayer_frames(ale->data, rectf.xmin, rectf.xmax, selectmode);
+                               //}
+                       }
+               }
+               
+               /* if action is mapped in NLA, unapply correction */
+               if (nob) {
+                       rectf.xmin= get_action_frame_inv(nob, rectf.xmin);
+                       rectf.xmax= get_action_frame_inv(nob, rectf.xmax);
+               }
+               
+               ymax=ymin;
+       }
+       
+       /* cleanup */
+       BLI_freelistN(&anim_data);
+}
+
+/* ------------------- */
+
+static int actkeys_borderselect_exec(bContext *C, wmOperator *op)
+{
+       bAnimContext ac;
+       rcti rect;
+       short in_scroller, selectmode;
+       int event;
+       
+       /* get editor data */
+       if ((ANIM_animdata_get_context(C, &ac) == 0) || (ac.data == NULL))
+               return OPERATOR_CANCELLED;
+       
+       /* get settings from operator */
+       rect.xmin= RNA_int_get(op->ptr, "xmin");
+       rect.ymin= RNA_int_get(op->ptr, "ymin");
+       rect.xmax= RNA_int_get(op->ptr, "xmax");
+       rect.ymax= RNA_int_get(op->ptr, "ymax");
+       
+       in_scroller= RNA_int_get(op->ptr, "in_scroller");
+       
+       event= RNA_int_get(op->ptr, "event_type");
+       if (event == LEFTMOUSE) // FIXME... hardcoded
+               selectmode = SELECT_ADD;
+       else
+               selectmode = SELECT_SUBTRACT;
+               
+       borderselect_action(&ac, rect, in_scroller, selectmode);
+       
+       return OPERATOR_FINISHED;
+} 
+
+static int actkeys_borderselect_invoke(bContext *C, wmOperator *op, wmEvent *event)
+{
+       bAnimContext ac;
+       ARegion *ar;
+       
+       /* get editor data */
+       if ((ANIM_animdata_get_context(C, &ac) == 0) || (ac.data == NULL))
+               return OPERATOR_CANCELLED;
+       ar= ac.ar;
+               
+       /* check if mouse is in a scroller */
+       // XXX move this to keymap level thing (boundbox checking)?
+       RNA_enum_set(op->ptr, "in_scroller", UI_view2d_mouse_in_scrollers(C, &ar->v2d, event->x, event->y));
+       
+       /* now init borderselect operator to handle borderselect as per normal */
+       return WM_border_select_invoke(C, op, event);
+}
+
+void ED_ACT_OT_keyframes_borderselect(wmOperatorType *ot)
+{
+       /* identifiers */
+       ot->name= "Borderselect";
+       ot->idname= "ED_ACT_OT_keyframes_borderselect";
+       
+       /* api callbacks */
+       ot->invoke= actkeys_borderselect_invoke;//WM_border_select_invoke;
+       ot->exec= actkeys_borderselect_exec;
+       ot->modal= WM_border_select_modal;
+       
+       ot->poll= ED_operator_areaactive;
+       
+       /* rna */
+       RNA_def_property(ot->srna, "in_scroller", PROP_INT, PROP_NONE); // as enum instead?
+       RNA_def_property(ot->srna, "event_type", PROP_INT, PROP_NONE);
+       RNA_def_property(ot->srna, "xmin", PROP_INT, PROP_NONE);
+       RNA_def_property(ot->srna, "xmax", PROP_INT, PROP_NONE);
+       RNA_def_property(ot->srna, "ymin", PROP_INT, PROP_NONE);
+       RNA_def_property(ot->srna, "ymax", PROP_INT, PROP_NONE);
 }
 
 /* ******************** Column Select Operator **************************** */