static int graphview_curves_reveal_exec(bContext *C, wmOperator *op) { bAnimContext ac; ListBase anim_data = {NULL, NULL}; ListBase all_data = {NULL, NULL}; bAnimListElem *ale; int filter; const bool select = RNA_boolean_get(op->ptr, "select"); /* get editor data */ if (ANIM_animdata_get_context(C, &ac) == 0) return OPERATOR_CANCELLED; /* get list of all channels that selection may need to be flushed to * - hierarchy must not affect what we have access to here... */ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_CHANNELS | ANIMFILTER_NODUPLIS); ANIM_animdata_filter(&ac, &all_data, filter, ac.data, ac.datatype); /* filter data * - just go through all visible channels, ensuring that everything is set to be curve-visible */ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_NODUPLIS); ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype); for (ale = anim_data.first; ale; ale = ale->next) { /* hack: skip object channels for now, since flushing those will always flush everything, but they are always included */ /* TODO: find out why this is the case, and fix that */ if (ale->type == ANIMTYPE_OBJECT) continue; /* select if it is not visible */ if (ANIM_channel_setting_get(&ac, ale, ACHANNEL_SETTING_VISIBLE) == 0) { ANIM_channel_setting_set( &ac, ale, ACHANNEL_SETTING_SELECT, select ? ACHANNEL_SETFLAG_ADD : ACHANNEL_SETFLAG_CLEAR); } /* change the visibility setting */ ANIM_channel_setting_set(&ac, ale, ACHANNEL_SETTING_VISIBLE, ACHANNEL_SETFLAG_ADD); /* now, also flush selection status up/down as appropriate */ ANIM_flush_setting_anim_channels(&ac, &all_data, ale, ACHANNEL_SETTING_VISIBLE, true); } /* cleanup */ ANIM_animdata_freelist(&anim_data); BLI_freelistN(&all_data); /* send notifier that things have changed */ WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN | NA_EDITED, NULL); return OPERATOR_FINISHED; }
/** * Find the extents of the active channel * * \param[out] min Bottom y-extent of channel * \param[out] max Top y-extent of channel * \return Success of finding a selected channel */ static bool actkeys_channels_get_selected_extents(bAnimContext *ac, float *min, float *max) { ListBase anim_data = {NULL, NULL}; bAnimListElem *ale; int filter; short found = 0; /* NOTE: not bool, since we want prioritise individual channels over expanders */ float y; /* get all items - we need to do it this way */ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_LIST_CHANNELS); ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); /* loop through all channels, finding the first one that's selected */ y = (float)ACHANNEL_FIRST; for (ale = anim_data.first; ale; ale = ale->next) { const bAnimChannelType *acf = ANIM_channel_get_typeinfo(ale); /* must be selected... */ if (acf && acf->has_setting(ac, ale, ACHANNEL_SETTING_SELECT) && ANIM_channel_setting_get(ac, ale, ACHANNEL_SETTING_SELECT)) { /* update best estimate */ *min = (float)(y - ACHANNEL_HEIGHT_HALF); *max = (float)(y + ACHANNEL_HEIGHT_HALF); /* is this high enough priority yet? */ found = acf->channel_role; /* only stop our search when we've found an actual channel * - datablock expanders get less priority so that we don't abort prematurely */ if (found == ACHANNEL_ROLE_CHANNEL) { break; } } /* adjust y-position for next one */ y -= ACHANNEL_STEP; } /* free all temp data */ ANIM_animdata_freelist(&anim_data); return (found != 0); }
/* draw keyframes in each channel */ void draw_channel_strips(bAnimContext *ac, SpaceAction *saction, ARegion *ar) { ListBase anim_data = {NULL, NULL}; bAnimListElem *ale; int filter; View2D *v2d = &ar->v2d; bDopeSheet *ads = &saction->ads; AnimData *adt = NULL; float act_start, act_end, y; size_t items; int height; unsigned char col1[3], col2[3]; unsigned char col1a[3], col2a[3]; unsigned char col1b[3], col2b[3]; /* get theme colors */ UI_GetThemeColor3ubv(TH_BACK, col2); UI_GetThemeColor3ubv(TH_HILITE, col1); UI_GetThemeColor3ubv(TH_GROUP, col2a); UI_GetThemeColor3ubv(TH_GROUP_ACTIVE, col1a); UI_GetThemeColor3ubv(TH_DOPESHEET_CHANNELOB, col1b); UI_GetThemeColor3ubv(TH_DOPESHEET_CHANNELSUBOB, col2b); /* set view-mapping rect (only used for x-axis), for NLA-scaling mapping with less calculation */ /* if in NLA there's a strip active, map the view */ if (ac->datatype == ANIMCONT_ACTION) { /* adt= ANIM_nla_mapping_get(ac, NULL); */ /* UNUSED */ /* start and end of action itself */ calc_action_range(ac->data, &act_start, &act_end, 0); } /* build list of channels to draw */ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_LIST_CHANNELS); 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 ACHANNEL_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. */ height = ((items * ACHANNEL_STEP) + (ACHANNEL_HEIGHT * 2)); /* don't use totrect set, as the width stays the same * (NOTE: this is ok here, the configuration is pretty straightforward) */ v2d->tot.ymin = (float)(-height); /* first backdrop strips */ y = (float)(-ACHANNEL_HEIGHT); glEnable(GL_BLEND); for (ale = anim_data.first; ale; ale = ale->next) { const float yminc = (float)(y - ACHANNEL_HEIGHT_HALF); const float ymaxc = (float)(y + ACHANNEL_HEIGHT_HALF); /* check if visible */ if (IN_RANGE(yminc, v2d->cur.ymin, v2d->cur.ymax) || IN_RANGE(ymaxc, v2d->cur.ymin, v2d->cur.ymax) ) { bAnimChannelType *acf = ANIM_channel_get_typeinfo(ale); int sel = 0; /* determine if any need to draw channel */ if (ale->datatype != ALE_NONE) { /* determine if channel is selected */ if (acf->has_setting(ac, ale, ACHANNEL_SETTING_SELECT)) sel = ANIM_channel_setting_get(ac, ale, ACHANNEL_SETTING_SELECT); if (ELEM3(ac->datatype, ANIMCONT_ACTION, ANIMCONT_DOPESHEET, ANIMCONT_SHAPEKEY)) { switch (ale->type) { case ANIMTYPE_SUMMARY: { /* reddish color from NLA */ UI_ThemeColor4(TH_ANIM_ACTIVE); } break; case ANIMTYPE_SCENE: case ANIMTYPE_OBJECT: { if (sel) glColor4ub(col1b[0], col1b[1], col1b[2], 0x45); else glColor4ub(col1b[0], col1b[1], col1b[2], 0x22); } break; case ANIMTYPE_FILLACTD: case ANIMTYPE_DSSKEY: case ANIMTYPE_DSWOR: { if (sel) glColor4ub(col2b[0], col2b[1], col2b[2], 0x45); else glColor4ub(col2b[0], col2b[1], col2b[2], 0x22); } break; case ANIMTYPE_GROUP: { if (sel) glColor4ub(col1a[0], col1a[1], col1a[2], 0x22); else glColor4ub(col2a[0], col2a[1], col2a[2], 0x22); } break; default: { if (sel) glColor4ub(col1[0], col1[1], col1[2], 0x22); else glColor4ub(col2[0], col2[1], col2[2], 0x22); } break; } /* draw region twice: firstly backdrop, then the current range */ glRectf(v2d->cur.xmin, (float)y - ACHANNEL_HEIGHT_HALF, v2d->cur.xmax + EXTRA_SCROLL_PAD, (float)y + ACHANNEL_HEIGHT_HALF); if (ac->datatype == ANIMCONT_ACTION) glRectf(act_start, (float)y - ACHANNEL_HEIGHT_HALF, act_end, (float)y + ACHANNEL_HEIGHT_HALF); } else if (ac->datatype == ANIMCONT_GPENCIL) { /* frames less than one get less saturated background */ if (sel) glColor4ub(col1[0], col1[1], col1[2], 0x22); else glColor4ub(col2[0], col2[1], col2[2], 0x22); glRectf(0.0f, (float)y - ACHANNEL_HEIGHT_HALF, v2d->cur.xmin, (float)y + ACHANNEL_HEIGHT_HALF); /* frames one and higher get a saturated background */ if (sel) glColor4ub(col1[0], col1[1], col1[2], 0x44); else glColor4ub(col2[0], col2[1], col2[2], 0x44); glRectf(v2d->cur.xmin, (float)y - ACHANNEL_HEIGHT_HALF, v2d->cur.xmax + EXTRA_SCROLL_PAD, (float)y + ACHANNEL_HEIGHT_HALF); } else if (ac->datatype == ANIMCONT_MASK) { /* TODO --- this is a copy of gpencil */ /* frames less than one get less saturated background */ if (sel) glColor4ub(col1[0], col1[1], col1[2], 0x22); else glColor4ub(col2[0], col2[1], col2[2], 0x22); glRectf(0.0f, (float)y - ACHANNEL_HEIGHT_HALF, v2d->cur.xmin, (float)y + ACHANNEL_HEIGHT_HALF); /* frames one and higher get a saturated background */ if (sel) glColor4ub(col1[0], col1[1], col1[2], 0x44); else glColor4ub(col2[0], col2[1], col2[2], 0x44); glRectf(v2d->cur.xmin, (float)y - ACHANNEL_HEIGHT_HALF, v2d->cur.xmax + EXTRA_SCROLL_PAD, (float)y + ACHANNEL_HEIGHT_HALF); } } } /* Increment the step */ y -= ACHANNEL_STEP; } glDisable(GL_BLEND); /* Draw keyframes * 1) Only channels that are visible in the Action Editor get drawn/evaluated. * This is to try to optimize this for heavier data sets * 2) Keyframes which are out of view horizontally are disregarded */ y = (float)(-ACHANNEL_HEIGHT); for (ale = anim_data.first; ale; ale = ale->next) { const float yminc = (float)(y - ACHANNEL_HEIGHT_HALF); const float ymaxc = (float)(y + ACHANNEL_HEIGHT_HALF); /* check if visible */ if (IN_RANGE(yminc, v2d->cur.ymin, v2d->cur.ymax) || IN_RANGE(ymaxc, v2d->cur.ymin, v2d->cur.ymax) ) { /* check if anything to show for this channel */ if (ale->datatype != ALE_NONE) { adt = ANIM_nla_mapping_get(ac, ale); /* draw 'keyframes' for each specific datatype */ switch (ale->datatype) { case ALE_ALL: draw_summary_channel(v2d, ale->data, y); break; case ALE_SCE: draw_scene_channel(v2d, ads, ale->key_data, y); break; case ALE_OB: draw_object_channel(v2d, ads, ale->key_data, y); break; case ALE_ACT: draw_action_channel(v2d, adt, ale->key_data, y); break; case ALE_GROUP: draw_agroup_channel(v2d, adt, ale->data, y); break; case ALE_FCURVE: draw_fcurve_channel(v2d, adt, ale->key_data, y); break; case ALE_GPFRAME: draw_gpl_channel(v2d, ads, ale->data, y); break; case ALE_MASKLAY: draw_masklay_channel(v2d, ads, ale->data, y); break; } } } y -= ACHANNEL_STEP; } /* free tempolary channels used for drawing */ BLI_freelistN(&anim_data); /* black line marking 'current frame' for Time-Slide transform mode */ if (saction->flag & SACTION_MOVING) { glColor3f(0.0f, 0.0f, 0.0f); glBegin(GL_LINES); glVertex2f(saction->timeslide, v2d->cur.ymin - EXTRA_SCROLL_PAD); glVertex2f(saction->timeslide, v2d->cur.ymax); glEnd(); } }