NLA SoC: Basic selection operators
authorJoshua Leung <aligorith@gmail.com>
Sun, 31 May 2009 11:14:50 +0000 (11:14 +0000)
committerJoshua Leung <aligorith@gmail.com>
Sun, 31 May 2009 11:14:50 +0000 (11:14 +0000)
* Added click-select/left-right select and deselect all/invert all selection operators. For now, these basic operators will suffice (more advanced selection operators will be coded at a later stage).

* Fixed a few bugs in DopeSheet found while coding the relevant tools for NLA.

* Added custom border-select operator for NLA channels (since the standard one assumes negative direction channel order)

* Added new API-method for NLA strips to check if the strip occurs within a given range, since this test needed to be performed in a few places...

* Tweaked the NLA Editor View2D ranges a bit to give saner default sizing. This still isn't right yet though.

source/blender/blenkernel/BKE_nla.h
source/blender/blenkernel/intern/nla.c
source/blender/editors/animation/anim_channels.c
source/blender/editors/include/ED_anim_api.h
source/blender/editors/space_action/action_select.c
source/blender/editors/space_nla/nla_channels.c
source/blender/editors/space_nla/nla_draw.c
source/blender/editors/space_nla/nla_intern.h
source/blender/editors/space_nla/nla_ops.c
source/blender/editors/space_nla/nla_select.c [new file with mode: 0644]
source/blender/editors/space_nla/space_nla.c

index ededd77a92ff77adee694f4179ceab04cd1068c9..3c3abe11da33e57b6d7b4bb74a948185ac2bd763 100644 (file)
@@ -59,6 +59,8 @@ void BKE_nlatrack_set_active(ListBase *tracks, struct NlaTrack *nlt);
 short BKE_nlatrack_has_space(struct NlaTrack *nlt, float start, float end);
 void BKE_nlatrack_sort_strips(struct NlaTrack *nlt);
 
+short BKE_nlastrip_within_bounds(struct NlaStrip *strip, float min, float max);
+
 void BKE_nla_action_pushdown(struct AnimData *adt);
 
 #endif
index 3efa823f9fee20e9a2dca2ea6f5afff4c2e8ddd2..cf115cb6faf02f8cd8699160e5672497ec08ba31 100644 (file)
@@ -455,6 +455,37 @@ void BKE_nlatrack_sort_strips (NlaTrack *nlt)
 
 /* NLA Strips -------------------------------------- */
 
+/* Does the given NLA-strip fall within the given bounds (times)? */
+short BKE_nlastrip_within_bounds (NlaStrip *strip, float min, float max)
+{
+       const float stripLen= (strip) ? strip->end - strip->start : 0.0f;
+       const float boundsLen= (float)fabs(max - min);
+       
+       /* sanity checks */
+       if ((strip == NULL) || IS_EQ(stripLen, 0.0f) || IS_EQ(boundsLen, 0.0f))
+               return 0;
+       
+       /* only ok if at least part of the strip is within the bounding window
+        *      - first 2 cases cover when the strip length is less than the bounding area
+        *      - second 2 cases cover when the strip length is greater than the bounding area
+        */
+       if ( (stripLen < boundsLen) && 
+                !(IN_RANGE(strip->start, min, max) ||
+                  IN_RANGE(strip->end, min, max)) )
+       {
+               return 0;
+       }
+       if ( (stripLen > boundsLen) && 
+                !(IN_RANGE(min, strip->start, strip->end) ||
+                  IN_RANGE(max, strip->start, strip->end)) )
+       {
+               return 0;
+       }
+       
+       /* should be ok! */
+       return 1;
+}
+
 /* Is the given NLA-strip the first one to occur for the given AnimData block */
 // TODO: make this an api method if necesary, but need to add prefix first
 short nlastrip_is_first (AnimData *adt, NlaStrip *strip)
index 5d5be87801b02e3455713e343df60a22cc7010ee..658bff739787f791cdfb82b696b9d99e2d0d997f 100644 (file)
 /* ************************************************************************** */
 /* CHANNELS API */
 
-/* -------------------------- Internal Macros ------------------------------- */
-
-/* set/clear/toggle macro 
- *     - channel - channel with a 'flag' member that we're setting
- *     - smode - 0=clear, 1=set, 2=toggle
- *     - sflag - bitflag to set
- */
-#define ACHANNEL_SET_FLAG(channel, smode, sflag) \
-       { \
-               if (smode == ACHANNEL_SETFLAG_TOGGLE)   (channel)->flag ^= (sflag); \
-               else if (smode == ACHANNEL_SETFLAG_ADD) (channel)->flag |= (sflag); \
-               else                                                                    (channel)->flag &= ~(sflag); \
-       }
-       
-/* set/clear/toggle macro, where the flag is negative 
- *     - channel - channel with a 'flag' member that we're setting
- *     - smode - 0=clear, 1=set, 2=toggle
- *     - sflag - bitflag to set
- */
-#define ACHANNEL_SET_FLAG_NEG(channel, smode, sflag) \
-       { \
-               if (smode == ACHANNEL_SETFLAG_TOGGLE)   (channel)->flag ^= (sflag); \
-               else if (smode == ACHANNEL_SETFLAG_ADD) (channel)->flag &= ~(sflag); \
-               else                                                                    (channel)->flag |= (sflag); \
-       }
-
 /* -------------------------- Exposed API ----------------------------------- */
 
 /* Set the given animation-channel as the active one for the active context */
index 7629fc29352f6266fbc21b1866200cb74e11ec2f..cdd8b5c368cefffc2a9fb43180e2abb0515b2f0b 100644 (file)
@@ -317,10 +317,35 @@ void ANIM_nla_mapping_draw(struct gla2DDrawInfo *di, struct Object *ob, short re
 /* Apply/Unapply NLA mapping to all keyframes in the nominated IPO block */
 void ANIM_nla_mapping_apply_fcurve(struct Object *ob, struct FCurve *fcu, short restore, short only_keys);
 
-/* ------------- xxx macros ----------------------- */
+/* ------------- Utility macros ----------------------- */
 
+/* checks if the given BezTriple is selected */
 #define BEZSELECTED(bezt) ((bezt->f2 & SELECT) || (bezt->f1 & SELECT) || (bezt->f3 & SELECT))
 
+/* set/clear/toggle macro 
+ *     - channel - channel with a 'flag' member that we're setting
+ *     - smode - 0=clear, 1=set, 2=toggle
+ *     - sflag - bitflag to set
+ */
+#define ACHANNEL_SET_FLAG(channel, smode, sflag) \
+       { \
+               if (smode == ACHANNEL_SETFLAG_TOGGLE)   (channel)->flag ^= (sflag); \
+               else if (smode == ACHANNEL_SETFLAG_ADD) (channel)->flag |= (sflag); \
+               else                                                                    (channel)->flag &= ~(sflag); \
+       }
+       
+/* set/clear/toggle macro, where the flag is negative 
+ *     - channel - channel with a 'flag' member that we're setting
+ *     - smode - 0=clear, 1=set, 2=toggle
+ *     - sflag - bitflag to set
+ */
+#define ACHANNEL_SET_FLAG_NEG(channel, smode, sflag) \
+       { \
+               if (smode == ACHANNEL_SETFLAG_TOGGLE)   (channel)->flag ^= (sflag); \
+               else if (smode == ACHANNEL_SETFLAG_ADD) (channel)->flag &= ~(sflag); \
+               else                                                                    (channel)->flag |= (sflag); \
+       }
+
 
 /* --------- anim_deps.c, animation updates -------- */
 
index d4782418be70f774046f65c50917543a640710b1..f64cd0f707c752d25695a4eee972d93dc16d8956 100644 (file)
@@ -174,7 +174,7 @@ static int actkeys_deselectall_exec(bContext *C, wmOperator *op)
                deselect_action_keys(&ac, 1, SELECT_ADD);
        
        /* set notifier that things have changed */
-       ED_area_tag_redraw(CTX_wm_area(C)); // FIXME... should be updating 'keyframes' data context or so instead!
+       ANIM_animdata_send_notifiers(C, &ac, ANIM_CHANGED_BOTH);
        
        return OPERATOR_FINISHED;
 }
@@ -766,6 +766,7 @@ static void mouse_action_keys (bAnimContext *ac, int mval[2], short select_mode,
        if (ale == NULL) {
                /* channel not found */
                printf("Error: animation channel (index = %d) not found in mouse_action_keys() \n", channel_index);
+               BLI_freelistN(&anim_data);
                return;
        }
        else {
index 658ce69cc100e789fefa51874be48c4aa92166f3..a839ccbf3d6e8cf785ab0a337039c4f9d0b2c166 100644 (file)
 /* *********************************************** */
 /* Operators for NLA channels-list which need to be different from the standard Animation Editor ones */
 
-// TODO: implemented borderselect too, since that also relies on ranges of buttons
+/* ******************** Borderselect Operator *********************** */
+
+static void borderselect_nla_channels (bAnimContext *ac, rcti *rect, short selectmode)
+{
+       ListBase anim_data = {NULL, NULL};
+       bAnimListElem *ale;
+       int filter;
+       
+       View2D *v2d= &ac->ar->v2d;
+       rctf rectf;
+       float ymin=(float)(-NLACHANNEL_HEIGHT), ymax=0;
+       
+       /* convert border-region to view coordinates */
+       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(ac, &anim_data, filter, ac->data, ac->datatype);
+       
+       /* loop over data, doing border select */
+       for (ale= anim_data.first; ale; ale= ale->next) {
+               ymax= ymin + NLACHANNEL_STEP;
+               
+               /* if channel is within border-select region, alter it */
+               if (!((ymax < rectf.ymin) || (ymin > rectf.ymax))) {
+                       /* only the following types can be selected */
+                       switch (ale->type) {
+                               case ANIMTYPE_OBJECT: /* object */
+                               {
+                                       Base *base= (Base *)ale->data;
+                                       Object *ob= base->object;
+                                       
+                                       ACHANNEL_SET_FLAG(base, selectmode, SELECT);
+                                       ACHANNEL_SET_FLAG(ob, selectmode, SELECT);
+                               }
+                                       break;
+                               case ANIMTYPE_NLATRACK: /* nla-track */
+                               {
+                                       NlaTrack *nlt= (NlaTrack *)ale->data;
+                                       
+                                       ACHANNEL_SET_FLAG(nlt, selectmode, NLATRACK_SELECTED);
+                               }
+                                       break;
+                       }
+               }
+               
+               /* set maximum extent to be the minimum of the next channel */
+               ymin= ymax;
+       }
+       
+       /* cleanup */
+       BLI_freelistN(&anim_data);
+}
+
+/* ------------------- */
+
+static int nlachannels_borderselect_exec(bContext *C, wmOperator *op)
+{
+       bAnimContext ac;
+       rcti rect;
+       short selectmode=0;
+       int event;
+       
+       /* get editor data */
+       if (ANIM_animdata_get_context(C, &ac) == 0)
+               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");
+       
+       event= RNA_int_get(op->ptr, "event_type");
+       if (event == LEFTMOUSE) // FIXME... hardcoded
+               selectmode = ACHANNEL_SETFLAG_ADD;
+       else
+               selectmode = ACHANNEL_SETFLAG_CLEAR;
+       
+       /* apply borderselect animation channels */
+       borderselect_nla_channels(&ac, &rect, selectmode);
+       
+       return OPERATOR_FINISHED;
+} 
+
+void NLA_OT_channels_select_border(wmOperatorType *ot)
+{
+       /* identifiers */
+       ot->name= "Border Select";
+       ot->idname= "NLA_OT_channels_select_border";
+       
+       /* api callbacks */
+       ot->invoke= WM_border_select_invoke;
+       ot->exec= nlachannels_borderselect_exec;
+       ot->modal= WM_border_select_modal;
+       
+       ot->poll= ED_operator_areaactive;
+       
+       /* flags */
+       ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+       
+       /* rna */
+       RNA_def_int(ot->srna, "event_type", 0, INT_MIN, INT_MAX, "Event Type", "", INT_MIN, INT_MAX);
+       RNA_def_int(ot->srna, "xmin", 0, INT_MIN, INT_MAX, "X Min", "", INT_MIN, INT_MAX);
+       RNA_def_int(ot->srna, "xmax", 0, INT_MIN, INT_MAX, "X Max", "", INT_MIN, INT_MAX);
+       RNA_def_int(ot->srna, "ymin", 0, INT_MIN, INT_MAX, "Y Min", "", INT_MIN, INT_MAX);
+       RNA_def_int(ot->srna, "ymax", 0, INT_MIN, INT_MAX, "Y Max", "", INT_MIN, INT_MAX);
+}
 
 /* ******************** Mouse-Click Operator *********************** */
 /* Depending on the channel that was clicked on, the mouse click will activate whichever
index 1a289d8436b5e06a120a12469e596423bc70c7bb..def490211602a9742159b6e3eafe8d9511640547 100644 (file)
@@ -137,7 +137,6 @@ void draw_nla_main_data (bAnimContext *ac, SpaceNla *snla, ARegion *ar)
        int filter;
        
        View2D *v2d= &ar->v2d;
-       float viewWidth = v2d->cur.xmax - v2d->cur.xmin;
        float y= 0.0f;
        int items, height;
        
@@ -180,29 +179,10 @@ void draw_nla_main_data (bAnimContext *ac, SpaceNla *snla, ARegion *ar)
                                        /* draw backdrop? */
                                        // TODO...
                                        
-                                       /* draw each strip in the track */
+                                       /* draw each strip in the track (if visible) */
                                        for (strip=nlt->strips.first; strip; strip= strip->next) {
-                                               float stripLen= strip->end - strip->start;
-                                               
-                                               /* only draw if at least part of the strip is within view 
-                                                *      - first 2 cases cover when the strip length is less than the viewable area
-                                                *      - second 2 cases cover when the strip length is greater than the viewable area
-                                                */
-                                               if ( (stripLen < viewWidth) && 
-                                                        !(IN_RANGE(strip->start, v2d->cur.xmin, v2d->cur.xmax) ||
-                                                          IN_RANGE(strip->end, v2d->cur.xmin, v2d->cur.xmax)) )
-                                               {
-                                                       continue;
-                                               }
-                                               if ( (stripLen > viewWidth) && 
-                                                        !(IN_RANGE(v2d->cur.xmin, strip->start, strip->end) ||
-                                                          IN_RANGE(v2d->cur.xmax, strip->start, strip->end)) )
-                                               {
-                                                       continue;
-                                               }
-                                               
-                                               /* we're still here, so ok... */
-                                               nla_draw_strip(nlt, strip, v2d, yminc, ymaxc);
+                                               if (BKE_nlastrip_within_bounds(strip, v2d->cur.xmin, v2d->cur.xmax))
+                                                       nla_draw_strip(nlt, strip, v2d, yminc, ymaxc);
                                        }
                                }
                                        break;
index 37eb7774696a98d76a182e075c84c6bcb2e00518..448b823bd4bfb4dc3852fa32a6fe28a34d454552 100644 (file)
  * along with this program; if not, write to the Free Software Foundation,
  * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  *
- * The Original Code is Copyright (C) 2008 Blender Foundation.
+ * The Original Code is Copyright (C) 2009 Blender Foundation, Joshua Leung.
  * All rights reserved.
  *
  * 
- * Contributor(s): Blender Foundation
+ * Contributor(s): Blender Foundation, Joshua Leung
  *
  * ***** END GPL LICENSE BLOCK *****
  */
@@ -60,6 +60,18 @@ void nla_header_buttons(const bContext *C, ARegion *ar);
 /* **************************************** */
 /* nla_select.c */
 
+/* defines for left-right select tool */
+enum {
+       NLAEDIT_LRSEL_TEST      = -1,
+       NLAEDIT_LRSEL_NONE,
+       NLAEDIT_LRSEL_LEFT,
+       NLAEDIT_LRSEL_RIGHT,
+} eNlaEdit_LeftRightSelect_Mode;
+
+/* --- */
+
+void NLAEDIT_OT_select_all_toggle(wmOperatorType *ot);
+void NLAEDIT_OT_click_select(wmOperatorType *ot);
 
 /* **************************************** */
 /* nla_edit.c */
@@ -67,6 +79,7 @@ void nla_header_buttons(const bContext *C, ARegion *ar);
 /* **************************************** */
 /* nla_channels.c */
 
+void NLA_OT_channels_select_border(wmOperatorType *ot);
 void NLA_OT_channels_click(wmOperatorType *ot);
 
 /* **************************************** */
index ea450a0847548c8c857a535ea02d148e30e2e413..167686c99f9a306f78067723746c327ee4d4a1eb 100644 (file)
@@ -72,9 +72,11 @@ void nla_operatortypes(void)
 {
        /* channels */
        WM_operatortype_append(NLA_OT_channels_click);
+       WM_operatortype_append(NLA_OT_channels_select_border);
        
        /* select */
-       // ...
+       WM_operatortype_append(NLAEDIT_OT_click_select);
+       WM_operatortype_append(NLAEDIT_OT_select_all_toggle);
 }
 
 /* ************************** registration - keymaps **********************************/
@@ -88,14 +90,14 @@ static void nla_keymap_channels (wmWindowManager *wm, ListBase *keymap)
        WM_keymap_add_item(keymap, "NLA_OT_channels_click", LEFTMOUSE, KM_PRESS, 0, 0);
        RNA_boolean_set(WM_keymap_add_item(keymap, "NLA_OT_channels_click", LEFTMOUSE, KM_PRESS, KM_SHIFT, 0)->ptr, "extend", 1);
        
+       /* borderselect */ 
+       WM_keymap_add_item(keymap, "NLA_OT_channels_select_border", BKEY, KM_PRESS, 0, 0);
+       
        /* General Animation Channels keymap (see anim_channels.c) ----------------------- */
                /* deselect all */
        WM_keymap_add_item(keymap, "ANIM_OT_channels_select_all_toggle", AKEY, KM_PRESS, 0, 0);
        RNA_boolean_set(WM_keymap_add_item(keymap, "ANIM_OT_channels_select_all_toggle", IKEY, KM_PRESS, KM_CTRL, 0)->ptr, "invert", 1);
        
-               /* borderselect */
-       WM_keymap_add_item(keymap, "ANIM_OT_channels_select_border", BKEY, KM_PRESS, 0, 0);
-       
        /* settings */
        WM_keymap_add_item(keymap, "ANIM_OT_channels_setting_toggle", WKEY, KM_PRESS, KM_SHIFT, 0);
        WM_keymap_add_item(keymap, "ANIM_OT_channels_setting_enable", WKEY, KM_PRESS, KM_CTRL|KM_SHIFT, 0);
@@ -114,8 +116,19 @@ static void nla_keymap_channels (wmWindowManager *wm, ListBase *keymap)
 
 static void nla_keymap_main (wmWindowManager *wm, ListBase *keymap)
 {
-       //wmKeymapItem *kmi;
+       wmKeymapItem *kmi;
        
+       /* selection */
+               /* click select */
+       WM_keymap_add_item(keymap, "NLAEDIT_OT_click_select", SELECTMOUSE, KM_PRESS, 0, 0);
+       kmi= WM_keymap_add_item(keymap, "NLAEDIT_OT_click_select", SELECTMOUSE, KM_PRESS, KM_SHIFT, 0);
+               RNA_boolean_set(kmi->ptr, "extend", 1);
+       kmi= WM_keymap_add_item(keymap, "NLAEDIT_OT_click_select", SELECTMOUSE, KM_PRESS, KM_CTRL, 0);
+               RNA_enum_set(kmi->ptr, "left_right", NLAEDIT_LRSEL_TEST);       
+       
+               /* deselect all */
+       WM_keymap_add_item(keymap, "NLAEDIT_OT_select_all_toggle", AKEY, KM_PRESS, 0, 0);
+       RNA_boolean_set(WM_keymap_add_item(keymap, "NLAEDIT_OT_select_all_toggle", IKEY, KM_PRESS, KM_CTRL, 0)->ptr, "invert", 1);
        
        
        /* transform system */
diff --git a/source/blender/editors/space_nla/nla_select.c b/source/blender/editors/space_nla/nla_select.c
new file mode 100644 (file)
index 0000000..5d9fe5f
--- /dev/null
@@ -0,0 +1,440 @@
+/**
+ * $Id:
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. 
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2009 Blender Foundation, Joshua Leung
+ * All rights reserved.
+ *
+ * 
+ * Contributor(s): Joshua Leung (major recode)
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include <string.h>
+#include <stdio.h>
+
+#include "DNA_anim_types.h"
+#include "DNA_action_types.h"
+#include "DNA_nla_types.h"
+#include "DNA_object_types.h"
+#include "DNA_space_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_windowmanager_types.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_arithb.h"
+#include "BLI_rand.h"
+
+#include "BKE_animsys.h"
+#include "BKE_nla.h"
+#include "BKE_context.h"
+#include "BKE_report.h"
+#include "BKE_screen.h"
+
+#include "ED_anim_api.h"
+#include "ED_keyframes_edit.h"
+#include "ED_markers.h"
+#include "ED_space_api.h"
+#include "ED_screen.h"
+
+#include "RNA_access.h"
+#include "RNA_define.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+#include "UI_view2d.h"
+
+#include "nla_intern.h"        // own include
+
+/* ******************** Utilities ***************************************** */
+
+/* Convert SELECT_* flags to ACHANNEL_SETFLAG_* flags */
+static short selmodes_to_flagmodes (short sel)
+{
+       /* convert selection modes to selection modes */
+       switch (sel) {
+               case SELECT_SUBTRACT:
+                       return ACHANNEL_SETFLAG_CLEAR;
+                       break;
+                       
+               case SELECT_INVERT:
+                       return ACHANNEL_SETFLAG_TOGGLE;
+                       break;
+                       
+               case SELECT_ADD:
+               default:
+                       return ACHANNEL_SETFLAG_ADD;
+                       break;
+       }
+}
+
+
+/* ******************** 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 strips in the NLA 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_nla_strips (bAnimContext *ac, short test, short sel)
+{
+       ListBase anim_data = {NULL, NULL};
+       bAnimListElem *ale;
+       int filter;
+       short smode;
+       
+       /* determine type-based settings - curvesonly eliminates all the unnecessary channels... */
+       filter= (ANIMFILTER_VISIBLE|ANIMFILTER_CURVESONLY);
+       
+       /* filter data */
+       ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
+       
+       /* See if we should be selecting or deselecting */
+       if (test) {
+               for (ale= anim_data.first; ale; ale= ale->next) {
+                       NlaTrack *nlt= (NlaTrack *)ale->data;
+                       NlaStrip *strip;
+                       
+                       /* if any strip is selected, break out, since we should now be deselecting */
+                       for (strip= nlt->strips.first; strip; strip= strip->next) {
+                               if (strip->flag & NLASTRIP_FLAG_SELECT) {
+                                       sel= SELECT_SUBTRACT;
+                                       break;
+                               }
+                       }
+                       
+                       if (sel == SELECT_SUBTRACT)
+                               break;
+               }
+       }
+       
+       /* convert selection modes to selection modes */
+       smode= selmodes_to_flagmodes(sel);
+       
+       /* Now set the flags */
+       for (ale= anim_data.first; ale; ale= ale->next) {
+               NlaTrack *nlt= (NlaTrack *)ale->data;
+               NlaStrip *strip;
+               
+               /* apply same selection to all strips */
+               for (strip= nlt->strips.first; strip; strip= strip->next) {
+                       /* set selection */
+                       ACHANNEL_SET_FLAG(strip, smode, NLASTRIP_FLAG_SELECT);
+                       
+                       /* clear active flag */
+                       strip->flag &= ~NLASTRIP_FLAG_ACTIVE;
+               }
+       }
+       
+       /* Cleanup */
+       BLI_freelistN(&anim_data);
+}
+
+/* ------------------- */
+
+static int nlaedit_deselectall_exec(bContext *C, wmOperator *op)
+{
+       bAnimContext ac;
+       
+       /* get editor data */
+       if (ANIM_animdata_get_context(C, &ac) == 0)
+               return OPERATOR_CANCELLED;
+               
+       /* 'standard' behaviour - check if selected, then apply relevant selection */
+       if (RNA_boolean_get(op->ptr, "invert"))
+               deselect_nla_strips(&ac, 0, SELECT_INVERT);
+       else
+               deselect_nla_strips(&ac, 1, SELECT_ADD);
+       
+       /* set notifier that things have changed */
+       ANIM_animdata_send_notifiers(C, &ac, ANIM_CHANGED_BOTH);
+       
+       return OPERATOR_FINISHED;
+}
+void NLAEDIT_OT_select_all_toggle (wmOperatorType *ot)
+{
+       /* identifiers */
+       ot->name= "Select All";
+       ot->idname= "NLAEDIT_OT_select_all_toggle";
+       
+       /* api callbacks */
+       ot->exec= nlaedit_deselectall_exec;
+       ot->poll= ED_operator_areaactive;
+       
+       /* flags */
+       ot->flag= OPTYPE_REGISTER/*|OPTYPE_UNDO*/;
+       
+       /* props */
+       RNA_def_boolean(ot->srna, "invert", 0, "Invert", "");
+}
+
+/* ******************** Mouse-Click Select Operator *********************** */
+/* This operator works in one of 2 ways:
+ *     1) Select the strip directly under the mouse
+ *     2) Select all the strips to one side of the mouse
+ */
+
+/* defines for left-right select tool */
+static EnumPropertyItem prop_nlaedit_leftright_select_types[] = {
+       {NLAEDIT_LRSEL_TEST, "CHECK", "Check if Select Left or Right", ""},
+       {NLAEDIT_LRSEL_NONE, "OFF", "Don't select", ""},
+       {NLAEDIT_LRSEL_LEFT, "LEFT", "Before current frame", ""},
+       {NLAEDIT_LRSEL_RIGHT, "RIGHT", "After current frame", ""},
+       {0, NULL, NULL, NULL}
+};
+
+/* sensitivity factor for frame-selections */
+#define FRAME_CLICK_THRESH             0.1f
+
+
+/* ------------------- */
+
+/* option 1) select strip directly under mouse */
+static void mouse_nla_strips (bAnimContext *ac, int mval[2], short select_mode)
+{
+       ListBase anim_data = {NULL, NULL};
+       bAnimListElem *ale = NULL;
+       int filter;
+       
+       View2D *v2d= &ac->ar->v2d;
+       NlaStrip *strip = NULL;
+       int channel_index;
+       float xmin, xmax, dummy;
+       float x, y;
+       
+       
+       /* use View2D to determine the index of the channel (i.e a row in the list) where keyframe was */
+       UI_view2d_region_to_view(v2d, mval[0], mval[1], &x, &y);
+       UI_view2d_listview_view_to_cell(v2d, 0, NLACHANNEL_STEP, 0, 0, x, y, NULL, &channel_index);
+       
+       /* x-range to check is +/- 7 (in screen/region-space) on either side of mouse click 
+        * (that is the size of keyframe icons, so user should be expecting similar tolerances) 
+        */
+       UI_view2d_region_to_view(v2d, mval[0]-7, mval[1], &xmin, &dummy);
+       UI_view2d_region_to_view(v2d, mval[0]+7, mval[1], &xmax, &dummy);
+       
+       /* filter data */
+       filter= (ANIMFILTER_VISIBLE | ANIMFILTER_CHANNELS);
+       ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
+       
+       /* try to get channel */
+       ale= BLI_findlink(&anim_data, channel_index);
+       if (ale == NULL) {
+               /* channel not found */
+               printf("Error: animation channel (index = %d) not found in mouse_nla_strips() \n", channel_index);
+               BLI_freelistN(&anim_data);
+               return;
+       }
+       else {
+               /* found some channel - we only really should do somethign when its an Nla-Track */
+               if (ale->type == ANIMTYPE_NLATRACK) {
+                       NlaTrack *nlt= (NlaTrack *)ale->data;
+                       
+                       /* loop over NLA-strips in this track, trying to find one which occurs in the necessary bounds */
+                       for (strip= nlt->strips.first; strip; strip= strip->next) {
+                               if (BKE_nlastrip_within_bounds(strip, xmin, xmax))
+                                       break;
+                       }
+               }
+               
+               /* remove active channel from list of channels for separate treatment (since it's needed later on) */
+               BLI_remlink(&anim_data, ale);
+               
+               /* free list of channels, since it's not used anymore */
+               BLI_freelistN(&anim_data);
+       }
+       
+       /* for replacing selection, firstly need to clear existing selection */
+       if (select_mode == SELECT_REPLACE) {
+               /* reset selection mode for next steps */
+               select_mode = SELECT_ADD;
+               
+               /* deselect all strips */
+               deselect_nla_strips(ac, 0, SELECT_SUBTRACT);
+               
+               /* deselect all other channels first */
+               ANIM_deselect_anim_channels(ac->data, ac->datatype, 0, ACHANNEL_SETFLAG_CLEAR);
+               
+               /* Highlight NLA-Track */
+               if (ale->type == ANIMTYPE_NLATRACK) {   
+                       NlaTrack *nlt= (NlaTrack *)ale->data;
+                       
+                       nlt->flag |= NLATRACK_SELECTED;
+                       ANIM_set_active_channel(ac->data, ac->datatype, filter, nlt, ANIMTYPE_NLATRACK);
+               }
+       }
+       
+       /* only select strip if we clicked on a valid channel and hit something */
+       if (ale) {
+               /* select the strip accordingly (if a matching one was found) */
+               if (strip) {
+                       select_mode= selmodes_to_flagmodes(select_mode);
+                       ACHANNEL_SET_FLAG(strip, select_mode, NLASTRIP_FLAG_SELECT);
+               }
+               
+               /* free this channel */
+               MEM_freeN(ale);
+       }
+}
+
+/* Option 2) Selects all the strips on either side of the current frame (depends on which side the mouse is on) */
+static void nlaedit_mselect_leftright (bAnimContext *ac, short leftright, short select_mode)
+{
+       ListBase anim_data = {NULL, NULL};
+       bAnimListElem *ale;
+       int filter;
+       
+       Scene *scene= ac->scene;
+       float xmin, xmax;
+       
+       /* if select mode is replace, deselect all keyframes (and channels) first */
+       if (select_mode==SELECT_REPLACE) {
+               select_mode= SELECT_ADD;
+               
+               /* deselect all other channels and keyframes */
+               ANIM_deselect_anim_channels(ac->data, ac->datatype, 0, ACHANNEL_SETFLAG_CLEAR);
+               deselect_nla_strips(ac, 0, SELECT_SUBTRACT);
+       }
+       
+       /* get range, and get the right flag-setting mode */
+       if (leftright == NLAEDIT_LRSEL_LEFT) {
+               xmin = -MAXFRAMEF;
+               xmax = (float)(CFRA + FRAME_CLICK_THRESH);
+       } 
+       else {
+               xmin = (float)(CFRA - FRAME_CLICK_THRESH);
+               xmax = MAXFRAMEF;
+       }
+       
+       select_mode= selmodes_to_flagmodes(select_mode);
+       
+       
+       /* filter data */
+       filter= (ANIMFILTER_VISIBLE | ANIMFILTER_CURVESONLY);
+       ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
+       
+       /* select strips on the side where most data occurs */
+       for (ale= anim_data.first; ale; ale= ale->next) {
+               NlaTrack *nlt= (NlaTrack *)ale->data;
+               NlaStrip *strip;
+               
+               /* check each strip to see if it is appropriate */
+               for (strip= nlt->strips.first; strip; strip= strip->next) {
+                       if (BKE_nlastrip_within_bounds(strip, xmin, xmax)) {
+                               ACHANNEL_SET_FLAG(strip, select_mode, NLASTRIP_FLAG_SELECT);
+                       }
+               }
+       }
+       
+       /* Cleanup */
+       BLI_freelistN(&anim_data);
+}
+
+/* ------------------- */
+
+/* handle clicking */
+static int nlaedit_clickselect_invoke(bContext *C, wmOperator *op, wmEvent *event)
+{
+       bAnimContext ac;
+       Scene *scene;
+       ARegion *ar;
+       View2D *v2d;
+       short selectmode;
+       int mval[2];
+       
+       /* get editor data */
+       if (ANIM_animdata_get_context(C, &ac) == 0)
+               return OPERATOR_CANCELLED;
+               
+       /* get useful pointers from animation context data */
+       scene= ac.scene;
+       ar= ac.ar;
+       v2d= &ar->v2d;
+       
+       /* get mouse coordinates (in region coordinates) */
+       mval[0]= (event->x - ar->winrct.xmin);
+       mval[1]= (event->y - ar->winrct.ymin);
+       
+       /* select mode is either replace (deselect all, then add) or add/extend */
+       if (RNA_boolean_get(op->ptr, "extend"))
+               selectmode= SELECT_INVERT;
+       else
+               selectmode= SELECT_REPLACE;
+       
+       /* figure out action to take */
+       if (RNA_enum_get(op->ptr, "left_right")) {
+               /* select all keys on same side of current frame as mouse */
+               float x;
+               
+               UI_view2d_region_to_view(v2d, mval[0], mval[1], &x, NULL);
+               if (x < CFRA)
+                       RNA_int_set(op->ptr, "left_right", NLAEDIT_LRSEL_LEFT);
+               else    
+                       RNA_int_set(op->ptr, "left_right", NLAEDIT_LRSEL_RIGHT);
+               
+               nlaedit_mselect_leftright(&ac, RNA_enum_get(op->ptr, "left_right"), selectmode);
+       }
+       else {
+               /* select strips based upon mouse position */
+               mouse_nla_strips(&ac, mval, selectmode);
+       }
+       
+       /* set notifier that things have changed */
+       ANIM_animdata_send_notifiers(C, &ac, ANIM_CHANGED_BOTH);
+       
+       /* for tweak grab to work */
+       return OPERATOR_FINISHED|OPERATOR_PASS_THROUGH;
+}
+void NLAEDIT_OT_click_select (wmOperatorType *ot)
+{
+       /* identifiers */
+       ot->name= "Mouse Select";
+       ot->idname= "NLAEDIT_OT_click_select";
+       
+       /* api callbacks - absolutely no exec() this yet... */
+       ot->invoke= nlaedit_clickselect_invoke;
+       ot->poll= ED_operator_areaactive;
+       
+       /* flags */
+       ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+       
+       /* id-props */
+       // XXX should we make this into separate operators?
+       RNA_def_enum(ot->srna, "left_right", prop_nlaedit_leftright_select_types, 0, "Left Right", ""); // CTRLKEY
+       RNA_def_boolean(ot->srna, "extend", 0, "Extend Select", ""); // SHIFTKEY
+}
+
+/* *********************************************** */
index 1313b4d915dff9a0291e0b3d73d353d718c26231..024b23c51b8587b5524552b9dfc4ebb20e12e9e1 100644 (file)
@@ -105,12 +105,12 @@ static SpaceLink *nla_new(const bContext *C)
        ar->v2d.tot.xmin= 1.0f;
        ar->v2d.tot.ymin=       0.0f;
        ar->v2d.tot.xmax= 1000.0f;
-       ar->v2d.tot.ymax= 1000.0f;
+       ar->v2d.tot.ymax= 500.0f;
        
        ar->v2d.cur.xmin= -5.0f;
        ar->v2d.cur.ymin= 0.0f;
        ar->v2d.cur.xmax= 65.0f;
-       ar->v2d.cur.ymax= 1000.0f;
+       ar->v2d.cur.ymax= 250.0f;
        
        ar->v2d.min[0]= 0.0f;
        ar->v2d.min[1]= 0.0f;