void draw_nla_main_data(bAnimContext *ac, SpaceNla *snla, ARegion *ar) { View2D *v2d = &ar->v2d; const float pixelx = BLI_rctf_size_x(&v2d->cur) / BLI_rcti_size_x(&v2d->mask); const float text_margin_x = (8 * UI_DPI_FAC) * pixelx; /* build list of channels to draw */ ListBase anim_data = {NULL, NULL}; int filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_LIST_CHANNELS); size_t items = ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); /* Update max-extent of channels here (taking into account scrollers): * - this is done to allow the channel list to be scrollable, but must be done here * to avoid regenerating the list again and/or also because channels list is drawn first * - offset of NLACHANNEL_HEIGHT*2 is added to the height of the channels, as first is for * start of list offset, and the second is as a correction for the scrollers. */ int height = NLACHANNEL_TOT_HEIGHT(ac, items); v2d->tot.ymin = -height; /* loop through channels, and set up drawing depending on their type */ float ymax = NLACHANNEL_FIRST_TOP(ac); for (bAnimListElem *ale = anim_data.first; ale; ale = ale->next, ymax -= NLACHANNEL_STEP(snla)) { float ymin = ymax - NLACHANNEL_HEIGHT(snla); float ycenter = (ymax + ymin) / 2.0f; /* check if visible */ if (IN_RANGE(ymin, v2d->cur.ymin, v2d->cur.ymax) || IN_RANGE(ymax, v2d->cur.ymin, v2d->cur.ymax)) { /* data to draw depends on the type of channel */ switch (ale->type) { case ANIMTYPE_NLATRACK: { AnimData *adt = ale->adt; NlaTrack *nlt = (NlaTrack *)ale->data; NlaStrip *strip; int index; /* draw each strip in the track (if visible) */ for (strip = nlt->strips.first, index = 1; strip; strip = strip->next, index++) { if (BKE_nlastrip_within_bounds(strip, v2d->cur.xmin, v2d->cur.xmax)) { const float xminc = strip->start + text_margin_x; const float xmaxc = strip->end + text_margin_x; /* draw the visualization of the strip */ nla_draw_strip(snla, adt, nlt, strip, v2d, ymin, ymax); /* add the text for this strip to the cache */ if (xminc < xmaxc) { nla_draw_strip_text(adt, nlt, strip, index, v2d, xminc, xmaxc, ymin, ymax); } /* if transforming strips (only real reason for temp-metas currently), * add to the cache the frame numbers of the strip's extents */ if (strip->flag & NLASTRIP_FLAG_TEMP_META) { nla_draw_strip_frames_text(nlt, strip, v2d, ymin, ymax); } } } break; } case ANIMTYPE_NLAACTION: { AnimData *adt = ale->adt; uint pos = GPU_vertformat_attr_add( immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); /* just draw a semi-shaded rect spanning the width of the viewable area if there's data, * and a second darker rect within which we draw keyframe indicator dots if there's data */ GPU_blend_set_func_separate( GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA); GPU_blend(true); /* get colors for drawing */ float color[4]; nla_action_get_color(adt, ale->data, color); immUniformColor4fv(color); /* draw slightly shifted up for greater separation from standard channels, * but also slightly shorter for some more contrast when viewing the strips */ immRectf( pos, v2d->cur.xmin, ymin + NLACHANNEL_SKIP, v2d->cur.xmax, ymax - NLACHANNEL_SKIP); /* draw 'embossed' lines above and below the strip for effect */ /* white base-lines */ GPU_line_width(2.0f); immUniformColor4f(1.0f, 1.0f, 1.0f, 0.3f); immBegin(GPU_PRIM_LINES, 4); immVertex2f(pos, v2d->cur.xmin, ymin + NLACHANNEL_SKIP); immVertex2f(pos, v2d->cur.xmax, ymin + NLACHANNEL_SKIP); immVertex2f(pos, v2d->cur.xmin, ymax - NLACHANNEL_SKIP); immVertex2f(pos, v2d->cur.xmax, ymax - NLACHANNEL_SKIP); immEnd(); /* black top-lines */ GPU_line_width(1.0f); immUniformColor3f(0.0f, 0.0f, 0.0f); immBegin(GPU_PRIM_LINES, 4); immVertex2f(pos, v2d->cur.xmin, ymin + NLACHANNEL_SKIP); immVertex2f(pos, v2d->cur.xmax, ymin + NLACHANNEL_SKIP); immVertex2f(pos, v2d->cur.xmin, ymax - NLACHANNEL_SKIP); immVertex2f(pos, v2d->cur.xmax, ymax - NLACHANNEL_SKIP); immEnd(); /* TODO: these lines but better --^ */ immUnbindProgram(); /* draw keyframes in the action */ nla_action_draw_keyframes( v2d, adt, ale->data, ycenter, ymin + NLACHANNEL_SKIP, ymax - NLACHANNEL_SKIP); GPU_blend(false); break; } } } } /* free tempolary channels */ ANIM_animdata_freelist(&anim_data); }
/* 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); } }