/* event can enterkey, then it opens/closes */ static int outliner_item_activate(bContext *C, wmOperator *op, wmEvent *event) { Scene *scene= CTX_data_scene(C); ARegion *ar= CTX_wm_region(C); SpaceOops *soops= CTX_wm_space_outliner(C); TreeElement *te; float fmval[2]; int extend= RNA_boolean_get(op->ptr, "extend"); UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], fmval, fmval+1); if ( !ELEM3(soops->outlinevis, SO_DATABLOCKS, SO_USERDEF, SO_KEYMAP) && !(soops->flag & SO_HIDE_RESTRICTCOLS) && (fmval[0] > ar->v2d.cur.xmax - OL_TOG_RESTRICT_VIEWX)) { return OPERATOR_CANCELLED; } for(te= soops->tree.first; te; te= te->next) { if(do_outliner_item_activate(C, scene, ar, soops, te, extend, fmval)) break; } if(te) { ED_undo_push(C, "Outliner click event"); } else { short selecting= -1; int row; /* get row number - 100 here is just a dummy value since we don't need the column */ UI_view2d_listview_view_to_cell(&ar->v2d, 1000, UI_UNIT_Y, 0.0f, OL_Y_OFFSET, fmval[0], fmval[1], NULL, &row); /* select relevant row */ if(outliner_select(soops, &soops->tree, &row, &selecting)) { soops->storeflag |= SO_TREESTORE_REDRAW; /* no need for undo push here, only changing outliner data which is * scene level - campbell */ /* ED_undo_push(C, "Outliner selection event"); */ } } ED_region_tag_redraw(ar); return OPERATOR_FINISHED; }
/* handle clicking */ static int nlachannels_mouseclick_invoke(bContext *C, wmOperator *op, const wmEvent *event) { bAnimContext ac; SpaceNla *snla; ARegion *ar; View2D *v2d; int channel_index; int notifierFlags = 0; short selectmode; float x, y; /* get editor data */ if (ANIM_animdata_get_context(C, &ac) == 0) return OPERATOR_CANCELLED; /* get useful pointers from animation context data */ snla = (SpaceNla *)ac.sl; ar = ac.ar; v2d = &ar->v2d; /* 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 which channel user clicked in * Note: although channels technically start at y= NLACHANNEL_FIRST, we need to adjust by half a channel's height * so that the tops of channels get caught ok. Since NLACHANNEL_FIRST is really NLACHANNEL_HEIGHT, we simply use * NLACHANNEL_HEIGHT_HALF. */ UI_view2d_region_to_view(v2d, event->mval[0], event->mval[1], &x, &y); UI_view2d_listview_view_to_cell(v2d, NLACHANNEL_NAMEWIDTH, NLACHANNEL_STEP(snla), 0, (float)NLACHANNEL_HEIGHT_HALF(snla), x, y, NULL, &channel_index); /* handle mouse-click in the relevant channel then */ notifierFlags = mouse_nla_channels(C, &ac, x, channel_index, selectmode); /* set notifier that things have changed */ WM_event_add_notifier(C, NC_ANIMATION | notifierFlags, NULL); return OPERATOR_FINISHED; }
static void mouse_action_keys(bAnimContext *ac, const int mval[2], short select_mode, bool column, bool same_channel) { ListBase anim_data = {NULL, NULL}; DLRBT_Tree anim_keys; bAnimListElem *ale; int filter; View2D *v2d = &ac->ar->v2d; bDopeSheet *ads = NULL; int channel_index; bool found = false; float frame = 0.0f; /* frame of keyframe under mouse - NLA corrections not applied/included */ float selx = 0.0f; /* frame of keyframe under mouse */ float key_hsize; float x, y; rctf rectf; /* get dopesheet info */ if (ac->datatype == ANIMCONT_DOPESHEET) ads = ac->data; /* 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, ACHANNEL_STEP(ac), 0, (float)ACHANNEL_HEIGHT_HALF(ac), x, y, NULL, &channel_index); /* x-range to check is +/- 7px for standard keyframe under standard dpi/y-scale (in screen/region-space), * on either side of mouse click (size of keyframe icon) */ key_hsize = ACHANNEL_HEIGHT(ac) * 0.8f; /* standard channel height (to allow for some slop) */ key_hsize = roundf(key_hsize / 2.0f); /* half-size (for either side), but rounded up to nearest int (for easier targetting) */ UI_view2d_region_to_view(v2d, mval[0] - (int)key_hsize, mval[1], &rectf.xmin, &rectf.ymin); UI_view2d_region_to_view(v2d, mval[0] + (int)key_hsize, mval[1], &rectf.xmax, &rectf.ymax); /* filter data */ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_LIST_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_action_keys()\n", channel_index); ANIM_animdata_freelist(&anim_data); return; } else { /* found match - must return here... */ AnimData *adt = ANIM_nla_mapping_get(ac, ale); ActKeyColumn *ak, *akn = NULL; /* make list of keyframes */ BLI_dlrbTree_init(&anim_keys); if (ale->key_data) { switch (ale->datatype) { case ALE_SCE: { Scene *scene = (Scene *)ale->key_data; scene_to_keylist(ads, scene, &anim_keys, NULL); break; } case ALE_OB: { Object *ob = (Object *)ale->key_data; ob_to_keylist(ads, ob, &anim_keys, NULL); break; } case ALE_ACT: { bAction *act = (bAction *)ale->key_data; action_to_keylist(adt, act, &anim_keys, NULL); break; } case ALE_FCURVE: { FCurve *fcu = (FCurve *)ale->key_data; fcurve_to_keylist(adt, fcu, &anim_keys, NULL); break; } } } else if (ale->type == ANIMTYPE_SUMMARY) { /* dopesheet summary covers everything */ summary_to_keylist(ac, &anim_keys, NULL); } else if (ale->type == ANIMTYPE_GROUP) { // TODO: why don't we just give groups key_data too? bActionGroup *agrp = (bActionGroup *)ale->data; agroup_to_keylist(adt, agrp, &anim_keys, NULL); } else if (ale->type == ANIMTYPE_GPLAYER) { // TODO: why don't we just give gplayers key_data too? bGPDlayer *gpl = (bGPDlayer *)ale->data; gpl_to_keylist(ads, gpl, &anim_keys); } else if (ale->type == ANIMTYPE_MASKLAYER) { // TODO: why don't we just give masklayers key_data too? MaskLayer *masklay = (MaskLayer *)ale->data; mask_to_keylist(ads, masklay, &anim_keys); } /* start from keyframe at root of BST, traversing until we find one within the range that was clicked on */ for (ak = anim_keys.root; ak; ak = akn) { if (IN_RANGE(ak->cfra, rectf.xmin, rectf.xmax)) { /* set the frame to use, and apply inverse-correction for NLA-mapping * so that the frame will get selected by the selection functions without * requiring to map each frame once again... */ selx = BKE_nla_tweakedit_remap(adt, ak->cfra, NLATIME_CONVERT_UNMAP); frame = ak->cfra; found = true; break; } else if (ak->cfra < rectf.xmin) akn = ak->right; else akn = ak->left; } /* remove active channel from list of channels for separate treatment (since it's needed later on) */ BLI_remlink(&anim_data, ale); /* cleanup temporary lists */ BLI_dlrbTree_free(&anim_keys); /* free list of channels, since it's not used anymore */ ANIM_animdata_freelist(&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 keyframes */ deselect_action_keys(ac, 0, SELECT_SUBTRACT); /* highlight channel clicked on */ if (ELEM(ac->datatype, ANIMCONT_ACTION, ANIMCONT_DOPESHEET)) { /* deselect all other channels first */ ANIM_deselect_anim_channels(ac, ac->data, ac->datatype, 0, ACHANNEL_SETFLAG_CLEAR); /* Highlight Action-Group or F-Curve? */ if (ale && ale->data) { if (ale->type == ANIMTYPE_GROUP) { bActionGroup *agrp = ale->data; agrp->flag |= AGRP_SELECTED; ANIM_set_active_channel(ac, ac->data, ac->datatype, filter, agrp, ANIMTYPE_GROUP); } else if (ELEM(ale->type, ANIMTYPE_FCURVE, ANIMTYPE_NLACURVE)) { FCurve *fcu = ale->data; fcu->flag |= FCURVE_SELECTED; ANIM_set_active_channel(ac, ac->data, ac->datatype, filter, fcu, ale->type); } } } else if (ac->datatype == ANIMCONT_GPENCIL) { /* deselect all other channels first */ ANIM_deselect_anim_channels(ac, ac->data, ac->datatype, 0, ACHANNEL_SETFLAG_CLEAR); /* Highlight GPencil Layer */ if ((ale && ale->data) && (ale->type == ANIMTYPE_GPLAYER)) { bGPDlayer *gpl = ale->data; gpl->flag |= GP_LAYER_SELECT; //gpencil_layer_setactive(gpd, gpl); } } else if (ac->datatype == ANIMCONT_MASK) { /* deselect all other channels first */ ANIM_deselect_anim_channels(ac, ac->data, ac->datatype, 0, ACHANNEL_SETFLAG_CLEAR); /* Highlight GPencil Layer */ if ((ale && ale->data) && (ale->type == ANIMTYPE_MASKLAYER)) { MaskLayer *masklay = ale->data; masklay->flag |= MASK_LAYERFLAG_SELECT; //gpencil_layer_setactive(gpd, gpl); } } } /* only select keyframes if we clicked on a valid channel and hit something */ if (ale) { if (found) { /* apply selection to keyframes */ if (column) { /* select all keyframes in the same frame as the one we hit on the active channel * [T41077]: "frame" not "selx" here (i.e. no NLA corrections yet) as the code here * does that itself again as it needs to work on multiple datablocks */ actkeys_mselect_column(ac, select_mode, frame); } else if (same_channel) { /* select all keyframes in the active channel */ actkeys_mselect_channel_only(ac, ale, select_mode); } else { /* select the nominated keyframe on the given frame */ actkeys_mselect_single(ac, ale, select_mode, selx); } } /* free this channel */ MEM_freeN(ale); } }
/* select strip directly under mouse */ static void mouse_nla_strips(bContext *C, bAnimContext *ac, const int mval[2], short select_mode) { ListBase anim_data = {NULL, NULL}; bAnimListElem *ale = NULL; int filter; SpaceNla *snla = (SpaceNla *)ac->sl; View2D *v2d = &ac->ar->v2d; Scene *scene = ac->scene; NlaStrip *strip = NULL; int channel_index; float xmin, xmax; 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(snla), 0, (float)NLACHANNEL_HEIGHT_HALF(snla), 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) */ xmin = UI_view2d_region_to_view_x(v2d, mval[0] - 7); xmax = UI_view2d_region_to_view_x(v2d, mval[0] + 7); /* filter data */ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_LIST_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); ANIM_animdata_freelist(&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 */ ANIM_animdata_freelist(&anim_data); } /* if currently in tweakmode, exit tweakmode before changing selection states * now that we've found our target... */ if (scene->flag & SCE_NLA_EDIT_ON) WM_operator_name_call(C, "NLA_OT_tweakmode_exit", WM_OP_EXEC_DEFAULT, NULL); /* 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, ac->data, ac->datatype, 0, ACHANNEL_SETFLAG_CLEAR); } /* 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); /* if we selected it, we can make it active too * - we always need to clear the active strip flag though... * - as well as selecting its track... */ deselect_nla_strips(ac, DESELECT_STRIPS_CLEARACTIVE, 0); if (strip->flag & NLASTRIP_FLAG_SELECT) { strip->flag |= NLASTRIP_FLAG_ACTIVE; /* Highlight NLA-Track */ if (ale->type == ANIMTYPE_NLATRACK) { NlaTrack *nlt = (NlaTrack *)ale->data; nlt->flag |= NLATRACK_SELECTED; ANIM_set_active_channel(ac, ac->data, ac->datatype, filter, nlt, ANIMTYPE_NLATRACK); } } } /* free this channel */ MEM_freeN(ale); } }