From 5917d0892c8d73b38c2988c911341ef325a4656d Mon Sep 17 00:00:00 2001 From: Joshua Leung Date: Mon, 26 Jan 2009 23:18:27 +0000 Subject: [PATCH] Graph Editor: Added files + Bugfixes * Copied files containing code for tools from Action Editor to use as a base for the Graph Editor's tools. The toolsets are now very similar, so it should just be a case of making a few tweaks here and there. Currently all of these tools are #if-def'd out, as there are still a few things to clean up. (BUILDSYSTEM MAINTAINERS BEWARE!) * Tweaked some UI stuff (width of mode selector in header, names in the spacetype choosing menu) * Fixed a few bugs which were causing crashes when loading old files with IPO Editors open. --- source/blender/blenloader/intern/readfile.c | 6 +- .../blender/editors/animation/anim_filter.c | 8 +- source/blender/editors/screen/area.c | 4 +- source/blender/editors/space_ipo/SConscript | 2 +- source/blender/editors/space_ipo/ipo_draw.c | 17 +- source/blender/editors/space_ipo/ipo_edit.c | 1373 +++++++++++++++++ source/blender/editors/space_ipo/ipo_header.c | 3 +- source/blender/editors/space_ipo/ipo_intern.h | 5 + source/blender/editors/space_ipo/ipo_ops.c | 166 ++ source/blender/editors/space_ipo/ipo_select.c | 818 ++++++++++ source/blender/editors/space_ipo/space_ipo.c | 16 +- 11 files changed, 2386 insertions(+), 32 deletions(-) create mode 100644 source/blender/editors/space_ipo/ipo_edit.c create mode 100644 source/blender/editors/space_ipo/ipo_ops.c create mode 100644 source/blender/editors/space_ipo/ipo_select.c diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c index 85d7883de24..1ff658aa864 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -5454,11 +5454,7 @@ static void area_add_window_regions(ScrArea *sa, SpaceLink *sl, ListBase *lb) /* init mainarea view2d */ ar->v2d.scroll |= (V2D_SCROLL_BOTTOM|V2D_SCROLL_SCALE_HORIZONTAL); ar->v2d.scroll |= (V2D_SCROLL_LEFT|V2D_SCROLL_SCALE_VERTICAL); - - /* init dopesheet */ - // XXX move this elsewhere instead? - sipo->ads= MEM_callocN(sizeof(bDopeSheet), "GraphEdit DopeSheet"); - + //ar->v2d.flag |= V2D_IS_INITIALISED; break; } diff --git a/source/blender/editors/animation/anim_filter.c b/source/blender/editors/animation/anim_filter.c index 361a384cf03..6ec5c4726a5 100644 --- a/source/blender/editors/animation/anim_filter.c +++ b/source/blender/editors/animation/anim_filter.c @@ -199,6 +199,10 @@ static short actedit_get_context (bAnimContext *ac, SpaceAction *saction) /* Get data being edited in Graph Editor (depending on current 'mode') */ static short graphedit_get_context (bAnimContext *ac, SpaceIpo *sipo) { + /* init dopesheet data if non-existant (i.e. for old files) */ + if (sipo->ads == NULL) + sipo->ads= MEM_callocN(sizeof(bDopeSheet), "GraphEdit DopeSheet"); + /* sync settings with current view status, then return appropriate data */ switch (sipo->mode) { case SIPO_MODE_ANIMATION: /* Animation F-Curve Editor */ @@ -466,7 +470,7 @@ static int animdata_filter_fcurves (ListBase *anim_data, FCurve *first, bActionG */ for (fcu= first; ((fcu) && (fcu->grp==grp)); fcu= fcu->next) { /* only include if visible (Graph Editor check, not channels check) */ - if (!(filter_mode & ANIMFILTER_CURVEVISIBLE) || (fcu->flag & FCURVE_VISIBLE)) { + //if (!(filter_mode & ANIMFILTER_CURVEVISIBLE) || (fcu->flag & FCURVE_VISIBLE)) { // XXX don't do this till we have tools to set this /* only work with this channel and its subchannels if it is editable */ if (!(filter_mode & ANIMFILTER_FOREDIT) || EDITABLE_FCU(fcu)) { /* only include this curve if selected */ @@ -480,7 +484,7 @@ static int animdata_filter_fcurves (ListBase *anim_data, FCurve *first, bActionG } } } - } + //} } /* return the number of items added to the list */ diff --git a/source/blender/editors/screen/area.c b/source/blender/editors/screen/area.c index d104efef73d..95fd8bfa102 100644 --- a/source/blender/editors/screen/area.c +++ b/source/blender/editors/screen/area.c @@ -764,8 +764,8 @@ static char *windowtype_pup(void) "|%l" // 33 - "|Ipo Curve Editor %x2" //54 - "|Action Editor %x12" //73 + "|Graph Editor %x2" //54 + "|DopeSheet Editor %x12" //73 "|NLA Editor %x13" //94 "|%l" //97 diff --git a/source/blender/editors/space_ipo/SConscript b/source/blender/editors/space_ipo/SConscript index e1556efbbb3..1ff259b5757 100644 --- a/source/blender/editors/space_ipo/SConscript +++ b/source/blender/editors/space_ipo/SConscript @@ -3,7 +3,7 @@ Import ('env') sources = env.Glob('*.c') -incs = '../include ../../blenlib ../../blenkernel ../../makesdna ../../imbuf' +incs = '../include ../../blenlib ../../blenkernel ../../makesdna ../../makesrna ../../imbuf' incs += ' ../../windowmanager #/intern/guardedalloc #/extern/glew/include' env.BlenderLib ( 'bf_editors_space_ipo', sources, Split(incs), [], libtype=['core'], priority=[50] ) diff --git a/source/blender/editors/space_ipo/ipo_draw.c b/source/blender/editors/space_ipo/ipo_draw.c index f68d524d288..7b86987eced 100644 --- a/source/blender/editors/space_ipo/ipo_draw.c +++ b/source/blender/editors/space_ipo/ipo_draw.c @@ -247,9 +247,6 @@ static void draw_fcurve_handles (SpaceIpo *sipo, ARegion *ar, FCurve *fcu) { extern unsigned int nurbcol[]; unsigned int *col; - - BezTriple *bezt=fcu->bezt, *prevbezt=NULL; - float *fp; int sel, b; /* don't draw handle lines if handles are not shown */ @@ -258,6 +255,9 @@ static void draw_fcurve_handles (SpaceIpo *sipo, ARegion *ar, FCurve *fcu) /* slightly hacky, but we want to draw unselected points before selected ones*/ for (sel= 0; sel < 2; sel++) { + BezTriple *bezt=fcu->bezt, *prevbezt=NULL; + float *fp; + if (sel) col= nurbcol+4; else col= nurbcol; @@ -268,7 +268,7 @@ static void draw_fcurve_handles (SpaceIpo *sipo, ARegion *ar, FCurve *fcu) /* only draw first handle if previous segment had handles */ if ( (!prevbezt && (bezt->ipo==BEZT_IPO_BEZ)) || (prevbezt && (prevbezt->ipo==BEZT_IPO_BEZ)) ) { - cpack(col[bezt->h1]); + cpack(col[(unsigned char)bezt->h1]); glBegin(GL_LINE_STRIP); glVertex2fv(fp); glVertex2fv(fp+3); glEnd(); @@ -278,7 +278,7 @@ static void draw_fcurve_handles (SpaceIpo *sipo, ARegion *ar, FCurve *fcu) /* only draw second handle if this segment is bezier */ if (bezt->ipo == BEZT_IPO_BEZ) { - cpack(col[bezt->h2]); + cpack(col[(unsigned char)bezt->h2]); glBegin(GL_LINE_STRIP); glVertex2fv(fp+3); glVertex2fv(fp+6); glEnd(); @@ -290,7 +290,7 @@ static void draw_fcurve_handles (SpaceIpo *sipo, ARegion *ar, FCurve *fcu) ( (!prevbezt && (bezt->ipo==BEZT_IPO_BEZ)) || (prevbezt && (prevbezt->ipo==BEZT_IPO_BEZ)) ) ) { fp= bezt->vec[0]; - cpack(col[bezt->h1]); + cpack(col[(unsigned char)bezt->h1]); glBegin(GL_LINE_STRIP); glVertex2fv(fp); glVertex2fv(fp+3); @@ -302,7 +302,7 @@ static void draw_fcurve_handles (SpaceIpo *sipo, ARegion *ar, FCurve *fcu) (bezt->ipo == BEZT_IPO_BEZ) ) { fp= bezt->vec[1]; - cpack(col[bezt->h2]); + cpack(col[(unsigned char)bezt->h2]); glBegin(GL_LINE_STRIP); glVertex2fv(fp); glVertex2fv(fp+3); @@ -604,7 +604,7 @@ void graph_draw_curves (bAnimContext *ac, SpaceIpo *sipo, ARegion *ar) /* build list of curves to draw */ // XXX enable ANIMFILTER_CURVEVISIBLE when we have a method to set them - filter= (ANIMFILTER_VISIBLE|ANIMFILTER_CURVESONLY/*|ANIMFILTER_CURVEVISIBLE*/); + filter= (ANIMFILTER_VISIBLE|ANIMFILTER_CURVESONLY|ANIMFILTER_CURVEVISIBLE); items= ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); /* for each curve: @@ -630,7 +630,6 @@ void graph_draw_curves (bAnimContext *ac, SpaceIpo *sipo, ARegion *ar) draw_fcurve_handles(sipo, ar, fcu); draw_fcurve_vertices(sipo, ar, fcu); - /* undo mapping of keyframes for drawing if scaled F-Curve */ if (nob) ANIM_nla_mapping_apply_fcurve(nob, ale->key_data, 1, 1); diff --git a/source/blender/editors/space_ipo/ipo_edit.c b/source/blender/editors/space_ipo/ipo_edit.c new file mode 100644 index 00000000000..c2436c02c88 --- /dev/null +++ b/source/blender/editors/space_ipo/ipo_edit.c @@ -0,0 +1,1373 @@ +/** + * $Id: editaction.c 17746 2008-12-08 11:19:44Z aligorith $ + * + * ***** 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) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): Joshua Leung + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include +#include +#include +#include + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "MEM_guardedalloc.h" + +#include "BLI_blenlib.h" +#include "BLI_arithb.h" + +#include "DNA_anim_types.h" +#include "DNA_action_types.h" +#include "DNA_armature_types.h" +#include "DNA_camera_types.h" +#include "DNA_curve_types.h" +#include "DNA_object_types.h" +#include "DNA_screen_types.h" +#include "DNA_scene_types.h" +#include "DNA_space_types.h" +#include "DNA_constraint_types.h" +#include "DNA_key_types.h" +#include "DNA_lamp_types.h" +#include "DNA_material_types.h" +#include "DNA_userdef_types.h" +#include "DNA_gpencil_types.h" +#include "DNA_windowmanager_types.h" + +#include "RNA_access.h" +#include "RNA_define.h" + +#include "BKE_action.h" +#include "BKE_depsgraph.h" +#include "BKE_fcurve.h" +#include "BKE_key.h" +#include "BKE_material.h" +#include "BKE_object.h" +#include "BKE_context.h" +#include "BKE_utildefines.h" + +#include "UI_view2d.h" + +#include "ED_anim_api.h" +#include "ED_keyframing.h" +#include "ED_keyframes_draw.h" +#include "ED_keyframes_edit.h" +#include "ED_screen.h" +#include "ED_space_api.h" + +#include "WM_api.h" +#include "WM_types.h" + +#include "ipo_intern.h" + +#if 0 // XXX code to be sanitied for new system + +/* ************************************************************************** */ +/* KEYFRAME-RANGE STUFF */ + +/* *************************** Calculate Range ************************** */ + +/* Get the min/max keyframes*/ +static void get_keyframe_extents (bAnimContext *ac, float *xmin, float *xmax, float *ymin, float *ymax) +{ + ListBase anim_data = {NULL, NULL}; + bAnimListElem *ale; + int filter; + + /* get data to filter, from Dopesheet */ + filter= (ANIMFILTER_VISIBLE | ANIMFILTER_CURVEVISIBLE | ANIMFILTER_SEL | ANIMFILTER_FOREDIT | ANIMFILTER_CURVESONLY); + ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); + + /* set large values to try to override */ + if (xmin) *xmin= 999999999.0f; + if (xmax) *xmax= -999999999.0f; + //if (ymin) *ymin= 999999999.0f; + //if (ymax) *ymax= -999999999.0f; + + // XXX + if (ymin) *ymin= -10; + if (ymax) *ymax= 10; + + /* check if any channels to set range with */ + if (anim_data.first) { + /* go through channels, finding max extents */ + for (ale= anim_data.first; ale; ale= ale->next) { + Object *nob= ANIM_nla_mapping_get(ac, ale); + FCurve *fcu= (FCurve *)ale->key_data; + float tmin, tmax; + + /* get range and apply necessary scaling before */ + calc_fcurve_range(fcu, &tmin, &tmax); + tmin= tmax= 0.0f; // xxx + + if (nob) { + tmin= get_action_frame_inv(nob, tmin); + tmax= get_action_frame_inv(nob, tmax); + } + + /* try to set cur using these values, if they're more extreme than previously set values */ + if (xmin) *xmin= MIN2(*xmin, tmin); + if (xmax) *xmax= MAX2(*xmax, tmax); + } + + /* free memory */ + BLI_freelistN(&anim_data); + } + else { + /* set default range */ + if (ac->scene) { + if (xmin) *xmin= (float)ac->scene->r.sfra; + if (xmax) *xmax= (float)ac->scene->r.efra; + } + else { + if (xmin) *xmin= -5; + if (xmax) *xmax= 100; + } + } +} + +/* ****************** Automatic Preview-Range Operator ****************** */ + +static int graphkeys_previewrange_exec(bContext *C, wmOperator *op) +{ + bAnimContext ac; + Scene *scene; + float min, max; + + /* get editor data */ + if (ANIM_animdata_get_context(C, &ac) == 0) + return OPERATOR_CANCELLED; + if (ac.scene == NULL) + return OPERATOR_CANCELLED; + else + scene= ac.scene; + + /* set the range directly */ + get_keyframe_extents(&ac, &min, &max); + scene->r.psfra= (int)floor(min + 0.5f); + scene->r.pefra= (int)floor(max + 0.5f); + + /* set notifier that things have changed */ + // XXX err... there's nothing for frame ranges yet, but this should do fine too + WM_event_add_notifier(C, NC_SCENE|ND_FRAME, ac.scene); + + return OPERATOR_FINISHED; +} + +void GRAPHEDIT_OT_set_previewrange (wmOperatorType *ot) +{ + /* identifiers */ + ot->name= "Auto-Set Preview Range"; + ot->idname= "GRAPHEDIT_OT_set_previewrange"; + + /* api callbacks */ + ot->exec= graphkeys_previewrange_exec; + ot->poll= ED_operator_areaactive; + + /* flags */ + ot->flag= OPTYPE_REGISTER/*|OPTYPE_UNDO*/; +} + +/* ****************** View-All Operator ****************** */ + +static int graphkeys_viewall_exec(bContext *C, wmOperator *op) +{ + bAnimContext ac; + View2D *v2d; + float extra; + + /* get editor data */ + if (ANIM_animdata_get_context(C, &ac) == 0) + return OPERATOR_CANCELLED; + v2d= &ac.ar->v2d; + + /* set the horizontal range, with an extra offset so that the extreme keys will be in view */ + get_keyframe_extents(&ac, &v2d->cur.xmin, &v2d->cur.xmax, &v2d->cur.ymin, &v2d->cur.ymax); + + extra= 0.05f * (v2d->cur.xmax - v2d->cur.xmin); + v2d->cur.xmin -= extra; + v2d->cur.xmax += extra; + + extra= 0.05f * (v2d->cur.ymax - v2d->cur.ymin); + v2d->cur.ymin -= extra; + v2d->cur.ymax += extra; + + /* do View2D syncing */ + UI_view2d_sync(CTX_wm_screen(C), CTX_wm_area(C), v2d, V2D_LOCK_COPY); + + /* set notifier that things have changed */ + ED_area_tag_redraw(CTX_wm_area(C)); + + return OPERATOR_FINISHED; +} + +void GRAPHEDIT_OT_view_all (wmOperatorType *ot) +{ + /* identifiers */ + ot->name= "View All"; + ot->idname= "GRAPHEDIT_OT_view_all"; + + /* api callbacks */ + ot->exec= graphkeys_viewall_exec; + ot->poll= ED_operator_areaactive; + + /* flags */ + ot->flag= OPTYPE_REGISTER/*|OPTYPE_UNDO*/; +} + +/* ************************************************************************** */ +/* GENERAL STUFF */ + +// TODO: +// - insert key + +/* ******************** Copy/Paste Keyframes Operator ************************* */ +/* - The copy/paste buffer currently stores a set of Action Channels, with temporary + * IPO-blocks, and also temporary IpoCurves which only contain the selected keyframes. + * - Only pastes between compatable data is possible (i.e. same achan->name, ipo-curve type, etc.) + * Unless there is only one element in the buffer, names are also tested to check for compatability. + * - All pasted frames are offset by the same amount. This is calculated as the difference in the times of + * the current frame and the 'first keyframe' (i.e. the earliest one in all channels). + * - The earliest frame is calculated per copy operation. + */ + +#if 0 +/* globals for copy/paste data (like for other copy/paste buffers) */ +ListBase actcopybuf = {NULL, NULL}; +static float actcopy_firstframe= 999999999.0f; + +/* This function frees any MEM_calloc'ed copy/paste buffer data */ +// XXX find some header to put this in! +void free_actcopybuf () +{ + FCurve *fcu, *fcn; + + /* free_fcurve() frees F-Curve memory too, but we don't need to do remlink first, as we're freeing all + * channels anyway, and the freeing func only cares about the data it's given + */ + for (fcu= actcopybuf.first; fcu; fcu= fcn) { + fcn= fcu->next; + free_fcurve(fcu); + } + + actcopybuf.first= actcopybuf.last= NULL; + actcopy_firstframe= 999999999.0f; +} +#endif + +/* ------------------- */ + +/* This function adds data to the copy/paste buffer, freeing existing data first + * Only the selected action channels gets their selected keyframes copied. + */ +static short copy_graph_keys (bAnimContext *ac) +{ +#if 0 // XXX old animation system + ListBase anim_data = {NULL, NULL}; + bAnimListElem *ale; + int filter; + + /* clear buffer first */ + free_actcopybuf(); + + /* filter data */ + filter= (ANIMFILTER_VISIBLE | ANIMFILTER_CURVEVISIBLE| ANIMFILTER_SEL | ANIMFILTER_IPOKEYS); + ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); + + /* assume that each of these is an ipo-block */ + for (ale= anim_data.first; ale; ale= ale->next) { + bActionChannel *achan; + Ipo *ipo= ale->key_data; + Ipo *ipn; + IpoCurve *icu, *icn; + BezTriple *bezt; + int i; + + /* coerce an action-channel out of owner */ + if (ale->ownertype == ANIMTYPE_ACHAN) { + bActionChannel *achanO= ale->owner; + achan= MEM_callocN(sizeof(bActionChannel), "ActCopyPasteAchan"); + strcpy(achan->name, achanO->name); + } + else if (ale->ownertype == ANIMTYPE_SHAPEKEY) { + achan= MEM_callocN(sizeof(bActionChannel), "ActCopyPasteAchan"); + strcpy(achan->name, "#ACP_ShapeKey"); + } + else + continue; + BLI_addtail(&actcopybuf, achan); + + /* add constraint channel if needed, then add new ipo-block */ + if (ale->type == ANIMTYPE_CONCHAN) { + bConstraintChannel *conchanO= ale->data; + bConstraintChannel *conchan; + + conchan= MEM_callocN(sizeof(bConstraintChannel), "ActCopyPasteConchan"); + strcpy(conchan->name, conchanO->name); + BLI_addtail(&achan->constraintChannels, conchan); + + conchan->ipo= ipn= MEM_callocN(sizeof(Ipo), "ActCopyPasteIpo"); + } + else { + achan->ipo= ipn= MEM_callocN(sizeof(Ipo), "ActCopyPasteIpo"); + } + ipn->blocktype = ipo->blocktype; + + /* now loop through curves, and only copy selected keyframes */ + for (icu= ipo->curve.first; icu; icu= icu->next) { + /* allocate a new curve */ + icn= MEM_callocN(sizeof(IpoCurve), "ActCopyPasteIcu"); + icn->blocktype = icu->blocktype; + icn->adrcode = icu->adrcode; + BLI_addtail(&ipn->curve, icn); + + /* find selected BezTriples to add to the buffer (and set first frame) */ + for (i=0, bezt=icu->bezt; i < icu->totvert; i++, bezt++) { + if (BEZSELECTED(bezt)) { + /* add to buffer ipo-curve */ + //insert_bezt_icu(icn, bezt); // XXX + + /* check if this is the earliest frame encountered so far */ + if (bezt->vec[1][0] < actcopy_firstframe) + actcopy_firstframe= bezt->vec[1][0]; + } + } + } + } + + /* check if anything ended up in the buffer */ + if (ELEM(NULL, actcopybuf.first, actcopybuf.last)) + // error("Nothing copied to buffer"); + return -1; + + /* free temp memory */ + BLI_freelistN(&anim_data); +#endif // XXX old animation system + + /* everything went fine */ + return 0; +} + +static short paste_graph_keys (bAnimContext *ac) +{ +#if 0 // XXX old animation system + ListBase anim_data = {NULL, NULL}; + bAnimListElem *ale; + int filter; + + const Scene *scene= (ac->scene); + const float offset = (float)(CFRA - actcopy_firstframe); + char *actname = NULL, *conname = NULL; + short no_name= 0; + + /* check if buffer is empty */ + if (ELEM(NULL, actcopybuf.first, actcopybuf.last)) { + //error("No data in buffer to paste"); + return -1; + } + /* check if single channel in buffer (disregard names if so) */ + if (actcopybuf.first == actcopybuf.last) + no_name= 1; + + /* filter data */ + filter= (ANIMFILTER_VISIBLE | ANIMFILTER_CURVEVISIBLE| ANIMFILTER_SEL | ANIMFILTER_FOREDIT | ANIMFILTER_IPOKEYS); + ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); + + /* from selected channels */ + for (ale= anim_data.first; ale; ale= ale->next) { + Ipo *ipo_src = NULL; + bActionChannel *achan; + IpoCurve *ico, *icu; + BezTriple *bezt; + int i; + + /* find suitable IPO-block from buffer to paste from */ + for (achan= actcopybuf.first; achan; achan= achan->next) { + /* try to match data */ + if (ale->ownertype == ANIMTYPE_ACHAN) { + bActionChannel *achant= ale->owner; + + /* check if we have a corresponding action channel */ + if ((no_name) || (strcmp(achan->name, achant->name)==0)) { + actname= achant->name; + + /* check if this is a constraint channel */ + if (ale->type == ANIMTYPE_CONCHAN) { + bConstraintChannel *conchant= ale->data; + bConstraintChannel *conchan; + + for (conchan=achan->constraintChannels.first; conchan; conchan=conchan->next) { + if (strcmp(conchan->name, conchant->name)==0) { + conname= conchant->name; + ipo_src= conchan->ipo; + break; + } + } + if (ipo_src) break; + } + else { + ipo_src= achan->ipo; + break; + } + } + } + else if (ale->ownertype == ANIMTYPE_SHAPEKEY) { + /* check if this action channel is "#ACP_ShapeKey" */ + if ((no_name) || (strcmp(achan->name, "#ACP_ShapeKey")==0)) { + actname= NULL; + ipo_src= achan->ipo; + break; + } + } + } + + /* this shouldn't happen, but it might */ + if (ipo_src == NULL) + continue; + + /* loop over curves, pasting keyframes */ + for (ico= ipo_src->curve.first; ico; ico= ico->next) { + /* get IPO-curve to paste to (IPO-curve might not exist for destination, so gets created) */ + //icu= verify_ipocurve(ale->id, ico->blocktype, actname, conname, NULL, ico->adrcode, 1); + + + if (icu) { + /* just start pasting, with the the first keyframe on the current frame, and so on */ + for (i=0, bezt=ico->bezt; i < ico->totvert; i++, bezt++) { + /* temporarily apply offset to src beztriple while copying */ + bezt->vec[0][0] += offset; + bezt->vec[1][0] += offset; + bezt->vec[2][0] += offset; + + /* insert the keyframe */ + //insert_bezt_icu(icu, bezt); // XXX + + /* un-apply offset from src beztriple after copying */ + bezt->vec[0][0] -= offset; + bezt->vec[1][0] -= offset; + bezt->vec[2][0] -= offset; + } + + /* recalculate channel's handles? */ + //calchandles_fcurve(fcu); + } + } + } + + /* free temp memory */ + BLI_freelistN(&anim_data); + + /* do depsgraph updates (for 3d-view)? */ +#if 0 + if ((ob) && (G.saction->pin==0)) { + if (ob->type == OB_ARMATURE) + DAG_object_flush_update(G.scene, ob, OB_RECALC_OB|OB_RECALC_DATA); + else + DAG_object_flush_update(G.scene, ob, OB_RECALC_OB); + } +#endif + +#endif // XXX old animation system + + return 0; +} + +/* ------------------- */ + +static int graphkeys_copy_exec(bContext *C, wmOperator *op) +{ + bAnimContext ac; + + /* get editor data */ + if (ANIM_animdata_get_context(C, &ac) == 0) + return OPERATOR_CANCELLED; + + /* copy keyframes */ + if (ac.datatype == ANIMCONT_GPENCIL) { + // FIXME... + } + else { + if (copy_graph_keys(&ac)) { + // XXX errors - need a way to inform the user + printf("Action Copy: No keyframes copied to copy-paste buffer\n"); + } + } + + /* set notifier tha things have changed */ + ANIM_animdata_send_notifiers(C, &ac, ANIM_CHANGED_KEYFRAMES_VALUES); + + return OPERATOR_FINISHED; +} + +void GRAPHEDIT_OT_keyframes_copy (wmOperatorType *ot) +{ + /* identifiers */ + ot->name= "Copy Keyframes"; + ot->idname= "GRAPHEDIT_OT_keyframes_copy"; + + /* api callbacks */ + ot->exec= graphkeys_copy_exec; + ot->poll= ED_operator_areaactive; + + /* flags */ + ot->flag= OPTYPE_REGISTER/*|OPTYPE_UNDO*/; +} + + + +static int graphkeys_paste_exec(bContext *C, wmOperator *op) +{ + bAnimContext ac; + + /* get editor data */ + if (ANIM_animdata_get_context(C, &ac) == 0) + return OPERATOR_CANCELLED; + + /* paste keyframes */ + if (ac.datatype == ANIMCONT_GPENCIL) { + // FIXME... + } + else { + if (paste_graph_keys(&ac)) { + // XXX errors - need a way to inform the user + printf("Action Paste: Nothing to paste, as Copy-Paste buffer was empty.\n"); + } + } + + /* validate keyframes after editing */ + ANIM_editkeyframes_refresh(&ac); + + /* set notifier tha things have changed */ + ANIM_animdata_send_notifiers(C, &ac, ANIM_CHANGED_KEYFRAMES_VALUES); + + return OPERATOR_FINISHED; +} + +void GRAPHEDIT_OT_keyframes_paste (wmOperatorType *ot) +{ + /* identifiers */ + ot->name= "Paste Keyframes"; + ot->idname= "GRAPHEDIT_OT_keyframes_paste"; + + /* api callbacks */ + ot->exec= graphkeys_paste_exec; + ot->poll= ED_operator_areaactive; + + /* flags */ + ot->flag= OPTYPE_REGISTER/*|OPTYPE_UNDO*/; +} + +/* ******************** Delete Keyframes Operator ************************* */ + +static void delete_graph_keys (bAnimContext *ac) +{ + ListBase anim_data = {NULL, NULL}; + bAnimListElem *ale; + int filter; + + /* filter data */ + if (ac->datatype == ANIMCONT_GPENCIL) + filter= (ANIMFILTER_VISIBLE | ANIMFILTER_CURVEVISIBLE| ANIMFILTER_FOREDIT); + else + filter= (ANIMFILTER_VISIBLE | ANIMFILTER_CURVEVISIBLE| ANIMFILTER_FOREDIT | ANIMFILTER_CURVESONLY); + ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); + + /* loop through filtered data and delete selected keys */ + for (ale= anim_data.first; ale; ale= ale->next) { + //if (ale->type == ANIMTYPE_GPLAYER) + // delete_gplayer_frames((bGPDlayer *)ale->data); + //else + delete_fcurve_keys((FCurve *)ale->key_data); // XXX... this doesn't delete empty curves anymore + } + + /* free filtered list */ + BLI_freelistN(&anim_data); +} + +/* ------------------- */ + +static int graphkeys_delete_exec(bContext *C, wmOperator *op) +{ + bAnimContext ac; + + /* get editor data */ + if (ANIM_animdata_get_context(C, &ac) == 0) + return OPERATOR_CANCELLED; + + /* delete keyframes */ + delete_graph_keys(&ac); + + /* validate keyframes after editing */ + ANIM_editkeyframes_refresh(&ac); + + /* set notifier tha things have changed */ + ANIM_animdata_send_notifiers(C, &ac, ANIM_CHANGED_KEYFRAMES_VALUES); + + return OPERATOR_FINISHED; +} + +void GRAPHEDIT_OT_keyframes_delete (wmOperatorType *ot) +{ + /* identifiers */ + ot->name= "Delete Keyframes"; + ot->idname= "GRAPHEDIT_OT_keyframes_delete"; + + /* api callbacks */ + ot->exec= graphkeys_delete_exec; + ot->poll= ED_operator_areaactive; + + /* flags */ + ot->flag= OPTYPE_REGISTER/*|OPTYPE_UNDO*/; +} + +/* ******************** Clean Keyframes Operator ************************* */ + +static void clean_graph_keys (bAnimContext *ac, float thresh) +{ + ListBase anim_data = {NULL, NULL}; + bAnimListElem *ale; + int filter; + + /* filter data */ + filter= (ANIMFILTER_VISIBLE | ANIMFILTER_CURVEVISIBLE| ANIMFILTER_FOREDIT | ANIMFILTER_SEL | ANIMFILTER_CURVESONLY); + ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); + + /* loop through filtered data and clean curves */ + for (ale= anim_data.first; ale; ale= ale->next) + clean_fcurve((FCurve *)ale->key_data, thresh); + + /* free temp data */ + BLI_freelistN(&anim_data); +} + +/* ------------------- */ + +static int graphkeys_clean_exec(bContext *C, wmOperator *op) +{ + bAnimContext ac; + float thresh; + + /* get editor data */ + if (ANIM_animdata_get_context(C, &ac) == 0) + return OPERATOR_CANCELLED; + if (ac.datatype == ANIMCONT_GPENCIL) + return OPERATOR_PASS_THROUGH; + + /* get cleaning threshold */ + thresh= RNA_float_get(op->ptr, "threshold"); + + /* clean keyframes */ + clean_graph_keys(&ac, thresh); + + /* validate keyframes after editing */ + ANIM_editkeyframes_refresh(&ac); + + /* set notifier tha things have changed */ + ANIM_animdata_send_notifiers(C, &ac, ANIM_CHANGED_KEYFRAMES_VALUES); + + return OPERATOR_FINISHED; +} + +void GRAPHEDIT_OT_keyframes_clean (wmOperatorType *ot) +{ + /* identifiers */ + ot->name= "Clean Keyframes"; + ot->idname= "GRAPHEDIT_OT_keyframes_clean"; + + /* api callbacks */ + //ot->invoke= // XXX we need that number popup for this! + ot->exec= graphkeys_clean_exec; + ot->poll= ED_operator_areaactive; + + /* flags */ + ot->flag= OPTYPE_REGISTER/*|OPTYPE_UNDO*/; + + /* properties */ + RNA_def_float(ot->srna, "threshold", 0.001f, 0.0f, FLT_MAX, "Threshold", "", 0.0f, 1000.0f); +} + +/* ******************** Sample Keyframes Operator *********************** */ + +/* little cache for values... */ +typedef struct tempFrameValCache { + float frame, val; +} tempFrameValCache; + +/* Evaluates the curves between each selected keyframe on each frame, and keys the value */ +static void sample_graph_keys (bAnimContext *ac) +{ + ListBase anim_data = {NULL, NULL}; + bAnimListElem *ale; + int filter; + + /* filter data */ + filter= (ANIMFILTER_VISIBLE | ANIMFILTER_CURVEVISIBLE| ANIMFILTER_FOREDIT | ANIMFILTER_CURVESONLY); + ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); + + /* loop through filtered data and add keys between selected keyframes on every frame */ + for (ale= anim_data.first; ale; ale= ale->next) { + FCurve *fcu= (FCurve *)ale->key_data; + BezTriple *bezt, *start=NULL, *end=NULL; + tempFrameValCache *value_cache, *fp; + int sfra, range; + int i, n; + + /* find selected keyframes... once pair has been found, add keyframes */ + for (i=0, bezt=fcu->bezt; i < fcu->totvert; i++, bezt++) { + /* check if selected, and which end this is */ + if (BEZSELECTED(bezt)) { + if (start) { + /* set end */ + end= bezt; + + /* cache values then add keyframes using these values, as adding + * keyframes while sampling will affect the outcome... + */ + range= (int)( ceil(end->vec[1][0] - start->vec[1][0]) ); + sfra= (int)( floor(start->vec[1][0]) ); + + if (range) { + value_cache= MEM_callocN(sizeof(tempFrameValCache)*range, "IcuFrameValCache"); + + /* sample values */ + for (n=0, fp=value_cache; nframe= (float)(sfra + n); + fp->val= evaluate_fcurve(fcu, fp->frame); + } + + /* add keyframes with these */ + for (n=0, fp=value_cache; nframe, fp->val, 1); + } + + /* free temp cache */ + MEM_freeN(value_cache); + + /* as we added keyframes, we need to compensate so that bezt is at the right place */ + bezt = fcu->bezt + i + range - 1; + i += (range - 1); + } + + /* bezt was selected, so it now marks the start of a whole new chain to search */ + start= bezt; + end= NULL; + } + else { + /* just set start keyframe */ + start= bezt; + end= NULL; + } + } + } + + /* recalculate channel's handles? */ + calchandles_fcurve(fcu); + } + + /* admin and redraws */ + BLI_freelistN(&anim_data); +} + +/* ------------------- */ + +static int graphkeys_sample_exec(bContext *C, wmOperator *op) +{ + bAnimContext ac; + + /* get editor data */ + if (ANIM_animdata_get_context(C, &ac) == 0) + return OPERATOR_CANCELLED; + if (ac.datatype == ANIMCONT_GPENCIL) + return OPERATOR_PASS_THROUGH; + + /* sample keyframes */ + sample_graph_keys(&ac); + + /* validate keyframes after editing */ + ANIM_editkeyframes_refresh(&ac); + + /* set notifier tha things have changed */ + ANIM_animdata_send_notifiers(C, &ac, ANIM_CHANGED_KEYFRAMES_VALUES); + + return OPERATOR_FINISHED; +} + +void GRAPHEDIT_OT_keyframes_sample (wmOperatorType *ot) +{ + /* identifiers */ + ot->name= "Sample Keyframes"; + ot->idname= "GRAPHEDIT_OT_keyframes_sample"; + + /* api callbacks */ + ot->exec= graphkeys_sample_exec; + ot->poll= ED_operator_areaactive; + + /* flags */ + ot->flag= OPTYPE_REGISTER/*|OPTYPE_UNDO*/; +} + +/* ************************************************************************** */ +/* SETTINGS STUFF */ + +/* ******************** Set Extrapolation-Type Operator *********************** */ + +// XXX rename this operator... + +/* defines for set extrapolation-type for selected keyframes tool */ +EnumPropertyItem prop_graphkeys_expo_types[] = { + {FCURVE_EXTRAPOLATE_CONSTANT, "CONSTANT", "Constant Extrapolation", ""}, + {FCURVE_EXTRAPOLATE_LINEAR, "LINEAR", "Linear Extrapolation", ""}, + {0, NULL, NULL, NULL} +}; + +/* this function is responsible for setting extrapolation mode for keyframes */ +static void setexpo_graph_keys(bAnimContext *ac, short mode) +{ + ListBase anim_data = {NULL, NULL}; + bAnimListElem *ale; + int filter; + + /* filter data */ + filter= (ANIMFILTER_VISIBLE | ANIMFILTER_CURVEVISIBLE| ANIMFILTER_FOREDIT | ANIMFILTER_CURVESONLY); + ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); + + /* loop through setting mode per F-Curve */ + for (ale= anim_data.first; ale; ale= ale->next) { + FCurve *fcu= (FCurve *)ale->data; + fcu->extend= mode; + } + + /* cleanup */ + BLI_freelistN(&anim_data); +} + +/* ------------------- */ + +static int graphkeys_expo_exec(bContext *C, wmOperator *op) +{ + bAnimContext ac; + short mode; + + /* get editor data */ + if (ANIM_animdata_get_context(C, &ac) == 0) + return OPERATOR_CANCELLED; + if (ac.datatype == ANIMCONT_GPENCIL) + return OPERATOR_PASS_THROUGH; + + /* get handle setting mode */ + mode= RNA_enum_get(op->ptr, "type"); + + /* set handle type */ + setexpo_graph_keys(&ac, mode); + + /* validate keyframes after editing */ + ANIM_editkeyframes_refresh(&ac); + + /* set notifier tha things have changed */ + ANIM_animdata_send_notifiers(C, &ac, ANIM_CHANGED_KEYFRAMES_VALUES); + + return OPERATOR_FINISHED; +} + +void GRAPHEDIT_OT_keyframes_expotype (wmOperatorType *ot) +{ + /* identifiers */ + ot->name= "Set Keyframe Extrapolation"; + ot->idname= "GRAPHEDIT_OT_keyframes_expotype"; + + /* api callbacks */ + ot->invoke= WM_menu_invoke; + ot->exec= graphkeys_expo_exec; + ot->poll= ED_operator_areaactive; + + /* flags */ + ot->flag= OPTYPE_REGISTER/*|OPTYPE_UNDO*/; + + /* id-props */ + RNA_def_enum(ot->srna, "type", prop_graphkeys_expo_types, 0, "Type", ""); +} + +/* ******************** Set Interpolation-Type Operator *********************** */ + +/* defines for set ipo-type for selected keyframes tool */ +EnumPropertyItem prop_graphkeys_ipo_types[] = { + {BEZT_IPO_CONST, "CONSTANT", "Constant Interpolation", ""}, + {BEZT_IPO_LIN, "LINEAR", "Linear Interpolation", ""}, + {BEZT_IPO_BEZ, "BEZIER", "Bezier Interpolation", ""}, + {0, NULL, NULL, NULL} +}; + +/* this function is responsible for setting interpolation mode for keyframes */ +static void setipo_graph_keys(bAnimContext *ac, short mode) +{ + ListBase anim_data = {NULL, NULL}; + bAnimListElem *ale; + int filter; + BeztEditFunc set_cb= ANIM_editkeyframes_ipo(mode); + + /* filter data */ + filter= (ANIMFILTER_VISIBLE | ANIMFILTER_CURVEVISIBLE| ANIMFILTER_FOREDIT | ANIMFILTER_CURVESONLY); + ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); + + /* loop through setting BezTriple interpolation + * Note: we do not supply BeztEditData to the looper yet. Currently that's not necessary here... + */ + for (ale= anim_data.first; ale; ale= ale->next) + ANIM_fcurve_keys_bezier_loop(NULL, ale->key_data, NULL, set_cb, calchandles_fcurve); + + /* cleanup */ + BLI_freelistN(&anim_data); +} + +/* ------------------- */ + +static int graphkeys_ipo_exec(bContext *C, wmOperator *op) +{ + bAnimContext ac; + short mode; + + /* get editor data */ + if (ANIM_animdata_get_context(C, &ac) == 0) + return OPERATOR_CANCELLED; + if (ac.datatype == ANIMCONT_GPENCIL) + return OPERATOR_PASS_THROUGH; + + /* get handle setting mode */ + mode= RNA_enum_get(op->ptr, "type"); + + /* set handle type */ + setipo_graph_keys(&ac, mode); + + /* validate keyframes after editing */ + ANIM_editkeyframes_refresh(&ac); + + /* set notifier tha things have changed */ + ANIM_animdata_send_notifiers(C, &ac, ANIM_CHANGED_KEYFRAMES_VALUES); + + return OPERATOR_FINISHED; +} + +void GRAPHEDIT_OT_keyframes_ipotype (wmOperatorType *ot) +{ + /* identifiers */ + ot->name= "Set Keyframe Interpolation"; + ot->idname= "GRAPHEDIT_OT_keyframes_ipotype"; + + /* api callbacks */ + ot->invoke= WM_menu_invoke; + ot->exec= graphkeys_ipo_exec; + ot->poll= ED_operator_areaactive; + + /* flags */ + ot->flag= OPTYPE_REGISTER/*|OPTYPE_UNDO*/; + + /* id-props */ + RNA_def_enum(ot->srna, "type", prop_graphkeys_ipo_types, 0, "Type", ""); +} + +/* ******************** Set Handle-Type Operator *********************** */ + +/* defines for set handle-type for selected keyframes tool */ +EnumPropertyItem prop_graphkeys_handletype_types[] = { + {HD_AUTO, "AUTO", "Auto Handles", ""}, + {HD_VECT, "VECTOR", "Vector Handles", ""}, + {HD_FREE, "FREE", "Free Handles", ""}, + {HD_ALIGN, "ALIGN", "Aligned Handles", ""}, +// {-1, "TOGGLE", "Toggle between Free and Aligned Handles", ""}, + {0, NULL, NULL, NULL} +}; + +/* this function is responsible for setting handle-type of selected keyframes */ +static void sethandles_graph_keys(bAnimContext *ac, short mode) +{ + ListBase anim_data = {NULL, NULL}; + bAnimListElem *ale; + int filter; + BeztEditFunc set_cb= ANIM_editkeyframes_handles(mode); + + /* filter data */ + filter= (ANIMFILTER_VISIBLE | ANIMFILTER_CURVEVISIBLE| ANIMFILTER_FOREDIT | ANIMFILTER_CURVESONLY); + ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); + + /* loop through setting flags for handles + * Note: we do not supply BeztEditData to the looper yet. Currently that's not necessary here... + */ + for (ale= anim_data.first; ale; ale= ale->next) { + if (mode == -1) { + BeztEditFunc toggle_cb; + + /* check which type of handle to set (free or aligned) + * - check here checks for handles with free alignment already + */ + if (ANIM_fcurve_keys_bezier_loop(NULL, ale->key_data, NULL, set_cb, NULL)) + toggle_cb= ANIM_editkeyframes_handles(HD_FREE); + else + toggle_cb= ANIM_editkeyframes_handles(HD_ALIGN); + + /* set handle-type */ + ANIM_fcurve_keys_bezier_loop(NULL, ale->key_data, NULL, toggle_cb, calchandles_fcurve); + } + else { + /* directly set handle-type */ + ANIM_fcurve_keys_bezier_loop(NULL, ale->key_data, NULL, set_cb, calchandles_fcurve); + } + } + + /* cleanup */ + BLI_freelistN(&anim_data); +} + +/* ------------------- */ + +static int graphkeys_handletype_exec(bContext *C, wmOperator *op) +{ + bAnimContext ac; + short mode; + + /* get editor data */ + if (ANIM_animdata_get_context(C, &ac) == 0) + return OPERATOR_CANCELLED; + if (ac.datatype == ANIMCONT_GPENCIL) + return OPERATOR_PASS_THROUGH; + + /* get handle setting mode */ + mode= RNA_enum_get(op->ptr, "type"); + + /* set handle type */ + sethandles_graph_keys(&ac, mode); + + /* validate keyframes after editing */ + ANIM_editkeyframes_refresh(&ac); + + /* set notifier tha things have changed */ + ANIM_animdata_send_notifiers(C, &ac, ANIM_CHANGED_KEYFRAMES_VALUES); + + return OPERATOR_FINISHED; +} + +void GRAPHEDIT_OT_keyframes_handletype (wmOperatorType *ot) +{ + /* identifiers */ + ot->name= "Set Keyframe Handle Type"; + ot->idname= "GRAPHEDIT_OT_keyframes_handletype"; + + /* api callbacks */ + ot->invoke= WM_menu_invoke; + ot->exec= graphkeys_handletype_exec; + ot->poll= ED_operator_areaactive; + + /* flags */ + ot->flag= OPTYPE_REGISTER/*|OPTYPE_UNDO*/; + + /* id-props */ + RNA_def_enum(ot->srna, "type", prop_graphkeys_handletype_types, 0, "Type", ""); +} + +/* ************************************************************************** */ +/* TRANSFORM STUFF */ + +/* ***************** Snap Current Frame Operator *********************** */ + +/* helper callback for graphkeys_cfrasnap_exec() -> used to help get the average time of all selected beztriples */ +// TODO: if some other code somewhere needs this, it'll be time to port this over to keyframes_edit.c!!! +static short bezt_calc_average(BeztEditData *bed, BezTriple *bezt) +{ + /* only if selected */ + if (bezt->f2 & SELECT) { + /* store average time in float (only do rounding at last step */ + bed->f1 += bezt->vec[1][0]; + + /* increment number of items */ + bed->i1++; + } + + return 0; +} + +/* snap current-frame indicator to 'average time' of selected keyframe */ +static int graphkeys_cfrasnap_exec(bContext *C, wmOperator *op) +{ + bAnimContext ac; + ListBase anim_data= {NULL, NULL}; + bAnimListElem *ale; + int filter; + BeztEditData bed; + + /* get editor data */ + if (ANIM_animdata_get_context(C, &ac) == 0) + return OPERATOR_CANCELLED; + + /* init edit data */ + memset(&bed, 0, sizeof(BeztEditData)); + + /* loop over action data, averaging values */ + filter= (ANIMFILTER_VISIBLE | ANIMFILTER_CURVEVISIBLE| ANIMFILTER_CURVESONLY); + ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype); + + for (ale= anim_data.first; ale; ale= ale->next) + ANIM_fcurve_keys_bezier_loop(&bed, ale->key_data, NULL, bezt_calc_average, NULL); + + BLI_freelistN(&anim_data); + + /* set the new current frame value, based on the average time */ + if (bed.i1) { + Scene *scene= ac.scene; + CFRA= (int)floor((bed.f1 / bed.i1) + 0.5f); + } + + /* set notifier tha things have changed */ + WM_event_add_notifier(C, NC_SCENE|ND_FRAME, ac.scene); + + return OPERATOR_FINISHED; +} + +void GRAPHEDIT_OT_keyframes_cfrasnap (wmOperatorType *ot) +{ + /* identifiers */ + ot->name= "Snap Current Frame to Keys"; + ot->idname= "GRAPHEDIT_OT_keyframes_cfrasnap"; + + /* api callbacks */ + ot->exec= graphkeys_cfrasnap_exec; + ot->poll= ED_operator_areaactive; + + /* flags */ + ot->flag= OPTYPE_REGISTER/*|OPTYPE_UNDO*/; +} + +/* ******************** Snap Keyframes Operator *********************** */ + +/* defines for snap keyframes tool */ +EnumPropertyItem prop_graphkeys_snap_types[] = { + {graphkeys_SNAP_CFRA, "CFRA", "Current frame", ""}, + {graphkeys_SNAP_NEAREST_FRAME, "NEAREST_FRAME", "Nearest Frame", ""}, // XXX as single entry? + {graphkeys_SNAP_NEAREST_SECOND, "NEAREST_SECOND", "Nearest Second", ""}, // XXX as single entry? + {graphkeys_SNAP_NEAREST_MARKER, "NEAREST_MARKER", "Nearest Marker", ""}, + {0, NULL, NULL, NULL} +}; + +/* this function is responsible for snapping keyframes to frame-times */ +static void snap_graph_keys(bAnimContext *ac, short mode) +{ + ListBase anim_data = {NULL, NULL}; + bAnimListElem *ale; + int filter; + + BeztEditData bed; + BeztEditFunc edit_cb; + + /* filter data */ + if (ac->datatype == ANIMCONT_GPENCIL) + filter= (ANIMFILTER_VISIBLE | ANIMFILTER_CURVEVISIBLE| ANIMFILTER_FOREDIT); + else + filter= (ANIMFILTER_VISIBLE | ANIMFILTER_CURVEVISIBLE| ANIMFILTER_FOREDIT | ANIMFILTER_CURVESONLY); + ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); + + /* get beztriple editing callbacks */ + edit_cb= ANIM_editkeyframes_snap(mode); + + memset(&bed, 0, sizeof(BeztEditData)); + bed.scene= ac->scene; + + /* snap keyframes */ + for (ale= anim_data.first; ale; ale= ale->next) { + Object *nob= ANIM_nla_mapping_get(ac, ale); + + if (nob) { + ANIM_nla_mapping_apply_fcurve(nob, ale->key_data, 0, 1); + ANIM_fcurve_keys_bezier_loop(&bed, ale->key_data, NULL, edit_cb, calchandles_fcurve); + ANIM_nla_mapping_apply_fcurve(nob, ale->key_data, 1, 1); + } + //else if (ale->type == ACTTYPE_GPLAYER) + // snap_gplayer_frames(ale->data, mode); + else + ANIM_fcurve_keys_bezier_loop(&bed, ale->key_data, NULL, edit_cb, calchandles_fcurve); + } + BLI_freelistN(&anim_data); +} + +/* ------------------- */ + +static int graphkeys_snap_exec(bContext *C, wmOperator *op) +{ + bAnimContext ac; + short mode; + + /* get editor data */ + if (ANIM_animdata_get_context(C, &ac) == 0) + return OPERATOR_CANCELLED; + + /* get snapping mode */ + mode= RNA_enum_get(op->ptr, "type"); + + /* snap keyframes */ + snap_graph_keys(&ac, mode); + + /* validate keyframes after editing */ + ANIM_editkeyframes_refresh(&ac); + + /* set notifier tha things have changed */ + ANIM_animdata_send_notifiers(C, &ac, ANIM_CHANGED_KEYFRAMES_VALUES); + + return OPERATOR_FINISHED; +} + +void GRAPHEDIT_OT_keyframes_snap (wmOperatorType *ot) +{ + /* identifiers */ + ot->name= "Snap Keys"; + ot->idname= "GRAPHEDIT_OT_keyframes_snap"; + + /* api callbacks */ + ot->invoke= WM_menu_invoke; + ot->exec= graphkeys_snap_exec; + ot->poll= ED_operator_areaactive; + + /* flags */ + ot->flag= OPTYPE_REGISTER/*|OPTYPE_UNDO*/; + + /* id-props */ + RNA_def_enum(ot->srna, "type", prop_graphkeys_snap_types, 0, "Type", ""); +} + +/* ******************** Mirror Keyframes Operator *********************** */ + +/* defines for mirror keyframes tool */ +EnumPropertyItem prop_graphkeys_mirror_types[] = { + {graphkeys_MIRROR_CFRA, "CFRA", "Current frame", ""}, + {graphkeys_MIRROR_YAXIS, "YAXIS", "Vertical Axis", ""}, + {graphkeys_MIRROR_XAXIS, "XAXIS", "Horizontal Axis", ""}, + {graphkeys_MIRROR_MARKER, "MARKER", "First Selected Marker", ""}, + {0, NULL, NULL, NULL} +}; + +/* this function is responsible for mirroring keyframes */ +static void mirror_graph_keys(bAnimContext *ac, short mode) +{ + ListBase anim_data = {NULL, NULL}; + bAnimListElem *ale; + int filter; + + BeztEditData bed; + BeztEditFunc edit_cb; + + /* get beztriple editing callbacks */ + edit_cb= ANIM_editkeyframes_mirror(mode); + + memset(&bed, 0, sizeof(BeztEditData)); + bed.scene= ac->scene; + + /* for 'first selected marker' mode, need to find first selected marker first! */ + // XXX should this be made into a helper func in the API? + if (mode == graphkeys_MIRROR_MARKER) { + Scene *scene= ac->scene; + TimeMarker *marker= NULL; + + /* find first selected marker */ + for (marker= scene->markers.first; marker; marker=marker->next) { + if (marker->flag & SELECT) { + break; + } + } + + /* store marker's time (if available) */ + if (marker) + bed.f1= (float)marker->frame; + else + return; + } + + /* filter data */ + if (ac->datatype == ANIMCONT_GPENCIL) + filter= (ANIMFILTER_VISIBLE | ANIMFILTER_CURVEVISIBLE| ANIMFILTER_FOREDIT); + else + filter= (ANIMFILTER_VISIBLE | ANIMFILTER_CURVEVISIBLE| ANIMFILTER_FOREDIT | ANIMFILTER_CURVESONLY); + ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); + + /* mirror keyframes */ + for (ale= anim_data.first; ale; ale= ale->next) { + Object *nob= ANIM_nla_mapping_get(ac, ale); + + if (nob) { + ANIM_nla_mapping_apply_fcurve(nob, ale->key_data, 0, 1); + ANIM_fcurve_keys_bezier_loop(&bed, ale->key_data, NULL, edit_cb, calchandles_fcurve); + ANIM_nla_mapping_apply_fcurve(nob, ale->key_data, 1, 1); + } + //else if (ale->type == ACTTYPE_GPLAYER) + // snap_gplayer_frames(ale->data, mode); + else + ANIM_fcurve_keys_bezier_loop(&bed, ale->key_data, NULL, edit_cb, calchandles_fcurve); + } + BLI_freelistN(&anim_data); +} + +/* ------------------- */ + +static int graphkeys_mirror_exec(bContext *C, wmOperator *op) +{ + bAnimContext ac; + short mode; + + /* get editor data */ + if (ANIM_animdata_get_context(C, &ac) == 0) + return OPERATOR_CANCELLED; + + /* get mirroring mode */ + mode= RNA_enum_get(op->ptr, "type"); + + /* mirror keyframes */ + mirror_graph_keys(&ac, mode); + + /* validate keyframes after editing */ + ANIM_editkeyframes_refresh(&ac); + + /* set notifier tha things have changed */ + ANIM_animdata_send_notifiers(C, &ac, ANIM_CHANGED_KEYFRAMES_VALUES); + + return OPERATOR_FINISHED; +} + +void GRAPHEDIT_OT_keyframes_mirror (wmOperatorType *ot) +{ + /* identifiers */ + ot->name= "Mirror Keys"; + ot->idname= "GRAPHEDIT_OT_keyframes_mirror"; + + /* api callbacks */ + ot->invoke= WM_menu_invoke; + ot->exec= graphkeys_mirror_exec; + ot->poll= ED_operator_areaactive; + + /* flags */ + ot->flag= OPTYPE_REGISTER/*|OPTYPE_UNDO*/; + + /* id-props */ + RNA_def_enum(ot->srna, "type", prop_graphkeys_mirror_types, 0, "Type", ""); +} + +/* ************************************************************************** */ +#endif // XXX code to be sanitied for new system diff --git a/source/blender/editors/space_ipo/ipo_header.c b/source/blender/editors/space_ipo/ipo_header.c index df2dcd28914..a329fd806b8 100644 --- a/source/blender/editors/space_ipo/ipo_header.c +++ b/source/blender/editors/space_ipo/ipo_header.c @@ -141,8 +141,9 @@ void graph_header_buttons(const bContext *C, ARegion *ar) /* mode selector */ uiDefButS(block, MENU, B_REDR, "Editor Mode %t|F-Curve Editor %x0|Drivers %x1", - xco,yco,90,YIC, &sipo->mode, 0, 1, 0, 0, + xco,yco,120,YIC, &sipo->mode, 0, 1, 0, 0, "Editing modes for this editor"); + xco+= 120; /* always as last */ UI_view2d_totRect_set(&ar->v2d, xco+XIC+80, ar->v2d.tot.ymax-ar->v2d.tot.ymin); diff --git a/source/blender/editors/space_ipo/ipo_intern.h b/source/blender/editors/space_ipo/ipo_intern.h index 61fa095c157..4e58899afb6 100644 --- a/source/blender/editors/space_ipo/ipo_intern.h +++ b/source/blender/editors/space_ipo/ipo_intern.h @@ -29,6 +29,7 @@ #define ED_IPO_INTERN_H struct bContext; +struct wmWindowManager; struct bAnimContext; struct SpaceIpo; struct ARegion; @@ -42,6 +43,10 @@ void graph_draw_curves(struct bAnimContext *ac, struct SpaceIpo *sipo, struct AR /* ipo_header.c */ void graph_header_buttons(const bContext *C, struct ARegion *ar); +/* ipo_ops.c */ +void graphedit_keymap(struct wmWindowManager *wm); +void graphedit_operatortypes(void); + #endif /* ED_IPO_INTERN_H */ diff --git a/source/blender/editors/space_ipo/ipo_ops.c b/source/blender/editors/space_ipo/ipo_ops.c new file mode 100644 index 00000000000..574905460d6 --- /dev/null +++ b/source/blender/editors/space_ipo/ipo_ops.c @@ -0,0 +1,166 @@ +/** + * $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) 2008 Blender Foundation. + * All rights reserved. + * + * + * Contributor(s): Blender Foundation + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include +#include + +#include "MEM_guardedalloc.h" + +#include "DNA_listBase.h" +#include "DNA_action_types.h" +#include "DNA_scene_types.h" +#include "DNA_screen_types.h" +#include "DNA_space_types.h" +#include "DNA_windowmanager_types.h" + +#include "BLI_blenlib.h" + +#include "BKE_context.h" +#include "BKE_utildefines.h" + +#include "UI_interface.h" +#include "UI_view2d.h" + +#include "BIF_transform.h" + +#include "ipo_intern.h" + +#include "RNA_access.h" +#include "RNA_define.h" + +#include "WM_api.h" +#include "WM_types.h" + + +/* ************************** registration - operator types **********************************/ + +void graphedit_operatortypes(void) +{ +#if 0 // XXX code to be sanitied for new system + /* keyframes */ + /* selection */ + WM_operatortype_append(GRAPHEDIT_OT_keyframes_clickselect); + WM_operatortype_append(GRAPHEDIT_OT_keyframes_deselectall); + WM_operatortype_append(GRAPHEDIT_OT_keyframes_borderselect); + WM_operatortype_append(GRAPHEDIT_OT_keyframes_columnselect); + + /* editing */ + WM_operatortype_append(GRAPHEDIT_OT_keyframes_snap); + WM_operatortype_append(GRAPHEDIT_OT_keyframes_mirror); + WM_operatortype_append(GRAPHEDIT_OT_keyframes_cfrasnap); + WM_operatortype_append(GRAPHEDIT_OT_keyframes_handletype); + WM_operatortype_append(GRAPHEDIT_OT_keyframes_ipotype); + WM_operatortype_append(GRAPHEDIT_OT_keyframes_expotype); + WM_operatortype_append(GRAPHEDIT_OT_keyframes_sample); + WM_operatortype_append(GRAPHEDIT_OT_keyframes_clean); + WM_operatortype_append(GRAPHEDIT_OT_keyframes_delete); + WM_operatortype_append(GRAPHEDIT_OT_keyframes_copy); + WM_operatortype_append(GRAPHEDIT_OT_keyframes_paste); + + WM_operatortype_append(GRAPHEDIT_OT_set_previewrange); + WM_operatortype_append(GRAPHEDIT_OT_view_all); +#endif // XXX code to be sanitied for new system +} + +/* ************************** registration - keymaps **********************************/ + +static void graphedit_keymap_keyframes (wmWindowManager *wm, ListBase *keymap) +{ +#if 0 // XXX code to be sanitied for new system + /* action_select.c - selection tools */ + /* click-select */ + // TODO: column to alt, left-right to ctrl (for select-linked consistency) + WM_keymap_add_item(keymap, "GRAPHEDIT_OT_keyframes_clickselect", SELECTMOUSE, KM_PRESS, 0, 0); + RNA_boolean_set(WM_keymap_add_item(keymap, "GRAPHEDIT_OT_keyframes_clickselect", SELECTMOUSE, KM_PRESS, KM_CTRL, 0)->ptr, "column_select", 1); + RNA_boolean_set(WM_keymap_add_item(keymap, "GRAPHEDIT_OT_keyframes_clickselect", SELECTMOUSE, KM_PRESS, KM_SHIFT, 0)->ptr, "extend_select", 1); + RNA_enum_set(WM_keymap_add_item(keymap, "GRAPHEDIT_OT_keyframes_clickselect", SELECTMOUSE, KM_PRESS, KM_ALT, 0)->ptr, "left_right", ACTKEYS_LRSEL_TEST); + + /* deselect all */ + WM_keymap_add_item(keymap, "GRAPHEDIT_OT_keyframes_deselectall", AKEY, KM_PRESS, 0, 0); + RNA_boolean_set(WM_keymap_add_item(keymap, "GRAPHEDIT_OT_keyframes_deselectall", IKEY, KM_PRESS, KM_CTRL, 0)->ptr, "invert", 1); + + /* borderselect */ + WM_keymap_add_item(keymap, "GRAPHEDIT_OT_keyframes_borderselect", BKEY, KM_PRESS, 0, 0); + RNA_boolean_set(WM_keymap_add_item(keymap, "GRAPHEDIT_OT_keyframes_borderselect", BKEY, KM_PRESS, KM_ALT, 0)->ptr, "axis_range", 1); + + /* column select */ + RNA_enum_set(WM_keymap_add_item(keymap, "GRAPHEDIT_OT_keyframes_columnselect", KKEY, KM_PRESS, 0, 0)->ptr, "mode", ACTKEYS_COLUMNSEL_KEYS); + RNA_enum_set(WM_keymap_add_item(keymap, "GRAPHEDIT_OT_keyframes_columnselect", KKEY, KM_PRESS, KM_CTRL, 0)->ptr, "mode", ACTKEYS_COLUMNSEL_CFRA); + RNA_enum_set(WM_keymap_add_item(keymap, "GRAPHEDIT_OT_keyframes_columnselect", KKEY, KM_PRESS, KM_SHIFT, 0)->ptr, "mode", ACTKEYS_COLUMNSEL_MARKERS_COLUMN); + RNA_enum_set(WM_keymap_add_item(keymap, "GRAPHEDIT_OT_keyframes_columnselect", KKEY, KM_PRESS, KM_ALT, 0)->ptr, "mode", ACTKEYS_COLUMNSEL_MARKERS_BETWEEN); + + /* action_edit.c */ + /* snap - current frame to selected keys */ + WM_keymap_add_item(keymap, "GRAPHEDIT_OT_keyframes_cfrasnap", SKEY, KM_PRESS, KM_CTRL|KM_SHIFT, 0); + + /* menu + single-step transform */ + WM_keymap_add_item(keymap, "GRAPHEDIT_OT_keyframes_snap", SKEY, KM_PRESS, KM_SHIFT, 0); + WM_keymap_add_item(keymap, "GRAPHEDIT_OT_keyframes_mirror", MKEY, KM_PRESS, KM_SHIFT, 0); + + /* menu + set setting */ + WM_keymap_add_item(keymap, "GRAPHEDIT_OT_keyframes_handletype", HKEY, KM_PRESS, 0, 0); + WM_keymap_add_item(keymap, "GRAPHEDIT_OT_keyframes_ipotype", TKEY, KM_PRESS, KM_SHIFT, 0); + WM_keymap_add_item(keymap, "GRAPHEDIT_OT_keyframes_expotype", EKEY, KM_PRESS, KM_SHIFT, 0); // temp... + + /* destructive */ + WM_keymap_add_item(keymap, "GRAPHEDIT_OT_keyframes_clean", OKEY, KM_PRESS, 0, 0); + WM_keymap_add_item(keymap, "GRAPHEDIT_OT_keyframes_sample", OKEY, KM_PRESS, KM_SHIFT, 0); + + WM_keymap_add_item(keymap, "GRAPHEDIT_OT_keyframes_delete", XKEY, KM_PRESS, 0, 0); + WM_keymap_add_item(keymap, "GRAPHEDIT_OT_keyframes_delete", DELKEY, KM_PRESS, 0, 0); + + /* copy/paste */ + WM_keymap_add_item(keymap, "GRAPHEDIT_OT_keyframes_copy", CKEY, KM_PRESS, KM_CTRL, 0); + WM_keymap_add_item(keymap, "GRAPHEDIT_OT_keyframes_paste", VKEY, KM_PRESS, KM_CTRL, 0); + + /* auto-set range */ + WM_keymap_add_item(keymap, "GRAPHEDIT_OT_set_previewrange", PKEY, KM_PRESS, KM_CTRL|KM_ALT, 0); + WM_keymap_add_item(keymap, "GRAPHEDIT_OT_view_all", HOMEKEY, KM_PRESS, 0, 0); + + /* transform system */ + transform_keymap_for_space(wm, keymap, SPACE_ACTION); +#endif // XXX code to be sanitied for new system +} + +/* --------------- */ + +void graphedit_keymap(wmWindowManager *wm) +{ + ListBase *keymap; + + /* channels */ + /* Channels are not directly handled by the Graph Editor module, but are inherited from the Animation module. + * All the relevant operations, keymaps, drawing, etc. can therefore all be found in that module instead, as these + * are all used for the IPO-Editor too. + */ + + /* keyframes */ + keymap= WM_keymap_listbase(wm, "GraphEdit Keys", SPACE_IPO, 0); + graphedit_keymap_keyframes(wm, keymap); +} + diff --git a/source/blender/editors/space_ipo/ipo_select.c b/source/blender/editors/space_ipo/ipo_select.c new file mode 100644 index 00000000000..58b8a06a8c6 --- /dev/null +++ b/source/blender/editors/space_ipo/ipo_select.c @@ -0,0 +1,818 @@ +/** + * $Id: editaction.c 17746 2008-12-08 11:19:44Z aligorith $ + * + * ***** 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) 2008 Blender Foundation + * + * Contributor(s): Joshua Leung + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include +#include +#include +#include + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "MEM_guardedalloc.h" + +#include "BLI_blenlib.h" +#include "BLI_arithb.h" + +#include "DNA_anim_types.h" +#include "DNA_action_types.h" +#include "DNA_armature_types.h" +#include "DNA_camera_types.h" +#include "DNA_curve_types.h" +#include "DNA_object_types.h" +#include "DNA_screen_types.h" +#include "DNA_scene_types.h" +#include "DNA_space_types.h" +#include "DNA_constraint_types.h" +#include "DNA_key_types.h" +#include "DNA_lamp_types.h" +#include "DNA_material_types.h" +#include "DNA_userdef_types.h" +#include "DNA_gpencil_types.h" +#include "DNA_windowmanager_types.h" + +#include "RNA_access.h" +#include "RNA_define.h" + +#include "BKE_action.h" +#include "BKE_depsgraph.h" +#include "BKE_fcurve.h" +#include "BKE_key.h" +#include "BKE_material.h" +#include "BKE_object.h" +#include "BKE_context.h" +#include "BKE_utildefines.h" + +#include "UI_view2d.h" + +#include "ED_anim_api.h" +#include "ED_keyframing.h" +#include "ED_keyframes_draw.h" +#include "ED_keyframes_edit.h" +#include "ED_screen.h" +#include "ED_space_api.h" + +#include "WM_api.h" +#include "WM_types.h" + +#include "ipo_intern.h" + +#if 0 // XXX code to be sanitied for new system + +/* ************************************************************************** */ +/* 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_graph_keys (bAnimContext *ac, short test, short sel) +{ + ListBase anim_data = {NULL, NULL}; + bAnimListElem *ale; + int filter; + + BeztEditData bed; + BeztEditFunc test_cb, sel_cb; + + /* determine type-based settings */ + if (ac->datatype == ANIMCONT_GPENCIL) + filter= (ANIMFILTER_VISIBLE); + else + filter= (ANIMFILTER_VISIBLE | ANIMFILTER_CURVESONLY); + + /* filter data */ + ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); + + /* init BezTriple looping data */ + memset(&bed, 0, sizeof(BeztEditData)); + test_cb= ANIM_editkeyframes_ok(BEZT_OK_SELECTED); + + /* See if we should be selecting or deselecting */ + if (test) { + for (ale= anim_data.first; ale; ale= ale->next) { + if (ale->type == ANIMTYPE_GPLAYER) { + //if (is_gplayer_frame_selected(ale->data)) { + // sel= 0; + // break; + //} + } + else { + if (ANIM_fcurve_keys_bezier_loop(&bed, ale->key_data, NULL, test_cb, NULL)) { + sel= SELECT_SUBTRACT; + break; + } + } + } + } + + /* convert sel to selectmode, and use that to get editor */ + sel_cb= ANIM_editkeyframes_select(sel); + + /* Now set the flags */ + for (ale= anim_data.first; ale; ale= ale->next) { + //if (ale->type == ACTTYPE_GPLAYER) + // set_gplayer_frame_selection(ale->data, sel); + //else + ANIM_fcurve_keys_bezier_loop(&bed, ale->key_data, NULL, sel_cb, NULL); + } + + /* Cleanup */ + BLI_freelistN(&anim_data); +} + +/* ------------------- */ + +static int graphkeys_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_graph_keys(&ac, 0, SELECT_INVERT); + else + deselect_graph_keys(&ac, 1, SELECT_ADD); + + /* set notifier tha things have changed */ + ED_area_tag_redraw(CTX_wm_area(C)); // FIXME... should be updating 'keyframes' data context or so instead! + + return OPERATOR_FINISHED; +} + +void GRAPHEDIT_OT_keyframes_deselectall (wmOperatorType *ot) +{ + /* identifiers */ + ot->name= "Select All"; + ot->idname= "GRAPHEDIT_OT_keyframes_deselectall"; + + /* api callbacks */ + ot->exec= graphkeys_deselectall_exec; + ot->poll= ED_operator_areaactive; + + /* flags */ + ot->flag= OPTYPE_REGISTER/*|OPTYPE_UNDO*/; + + /* props */ + RNA_def_boolean(ot->srna, "invert", 0, "Invert", ""); +} + +/* ******************** Border Select Operator **************************** */ +/* This operator currently works in one of three ways: + * -> BKEY - 1) all keyframes within region are selected (graphkeys_BORDERSEL_ALLKEYS) + * -> ALT-BKEY - depending on which axis of the region was larger... + * -> 2) x-axis, so select all frames within frame range (graphkeys_BORDERSEL_FRAMERANGE) + * -> 3) y-axis, so select all frames within channels that region included (graphkeys_BORDERSEL_CHANNELS) + */ + +/* defines for borderselect mode */ +enum { + graphkeys_BORDERSEL_ALLKEYS = 0, + graphkeys_BORDERSEL_FRAMERANGE, + graphkeys_BORDERSEL_CHANNELS, +} egraphkeys_BorderSelect_Mode; + + +static void borderselect_action (bAnimContext *ac, rcti rect, short mode, short selectmode) +{ + ListBase anim_data = {NULL, NULL}; + bAnimListElem *ale; + int filter; + + BeztEditData bed; + BeztEditFunc ok_cb, select_cb; + View2D *v2d= &ac->ar->v2d; + rctf rectf; + float ymin=0, ymax=(float)(-ACHANNEL_HEIGHT); + + /* convert mouse coordinates to frame ranges and channel coordinates corrected for view pan/zoom */ + 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); + + /* get beztriple editing/validation funcs */ + select_cb= ANIM_editkeyframes_select(selectmode); + + if (ELEM(mode, graphkeys_BORDERSEL_FRAMERANGE, graphkeys_BORDERSEL_ALLKEYS)) + ok_cb= ANIM_editkeyframes_ok(BEZT_OK_FRAMERANGE); + else + ok_cb= NULL; + + /* init editing data */ + memset(&bed, 0, sizeof(BeztEditData)); + + /* loop over data, doing border select */ + for (ale= anim_data.first; ale; ale= ale->next) { + Object *nob= ANIM_nla_mapping_get(ac, ale); + + /* get new vertical minimum extent of channel */ + ymin= ymax - ACHANNEL_STEP; + + /* set horizontal range (if applicable) */ + if (ELEM(mode, graphkeys_BORDERSEL_FRAMERANGE, graphkeys_BORDERSEL_ALLKEYS)) { + /* if channel is mapped in NLA, apply correction */ + if (nob) { + bed.f1= get_action_frame(nob, rectf.xmin); + bed.f2= get_action_frame(nob, rectf.xmax); + } + else { + bed.f1= rectf.xmin; + bed.f2= rectf.xmax; + } + } + + /* perform vertical suitability check (if applicable) */ + if ( (mode == graphkeys_BORDERSEL_FRAMERANGE) || + !((ymax < rectf.ymin) || (ymin > rectf.ymax)) ) + { + /* loop over data selecting */ + if (ale->key_data) { + if (ale->datatype == ALE_FCURVE) + ANIM_fcurve_keys_bezier_loop(&bed, ale->key_data, ok_cb, select_cb, NULL); + } + else if (ale->type == ANIMTYPE_GROUP) { + bActionGroup *agrp= ale->data; + FCurve *fcu; + + for (fcu= agrp->channels.first; fcu && fcu->grp==agrp; fcu= fcu->next) + ANIM_fcurve_keys_bezier_loop(&bed, fcu, ok_cb, select_cb, NULL); + } + //else if (ale->type == ANIMTYPE_GPLAYER) { + // borderselect_gplayer_frames(ale->data, rectf.xmin, rectf.xmax, selectmode); + //} + } + + /* set minimum extent to be the maximum of the next channel */ + ymax=ymin; + } + + /* cleanup */ + BLI_freelistN(&anim_data); +} + +/* ------------------- */ + +static int graphkeys_borderselect_exec(bContext *C, wmOperator *op) +{ + bAnimContext ac; + rcti rect; + short mode=0, 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 = SELECT_ADD; + else + selectmode = SELECT_SUBTRACT; + + /* selection 'mode' depends on whether borderselect region only matters on one axis */ + if (RNA_boolean_get(op->ptr, "axis_range")) { + /* mode depends on which axis of the range is larger to determine which axis to use + * - checking this in region-space is fine, as it's fundamentally still going to be a different rect size + * - the frame-range select option is favoured over the channel one (x over y), as frame-range one is often + * used for tweaking timing when "blocking", while channels is not that useful... + */ + if ((rect.xmax - rect.xmin) >= (rect.ymax - rect.ymin)) + mode= graphkeys_BORDERSEL_FRAMERANGE; + else + mode= graphkeys_BORDERSEL_CHANNELS; + } + else + mode= graphkeys_BORDERSEL_ALLKEYS; + + /* apply borderselect action */ + borderselect_action(&ac, rect, mode, selectmode); + + return OPERATOR_FINISHED; +} + +void GRAPHEDIT_OT_keyframes_borderselect(wmOperatorType *ot) +{ + /* identifiers */ + ot->name= "Border Select"; + ot->idname= "GRAPHEDIT_OT_keyframes_borderselect"; + + /* api callbacks */ + ot->invoke= WM_border_select_invoke; + ot->exec= graphkeys_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); + + RNA_def_boolean(ot->srna, "axis_range", 0, "Axis Range", ""); +} + +/* ******************** Column Select Operator **************************** */ +/* This operator works in one of four ways: + * - 1) select all keyframes in the same frame as a selected one (KKEY) + * - 2) select all keyframes in the same frame as the current frame marker (CTRL-KKEY) + * - 3) select all keyframes in the same frame as a selected markers (SHIFT-KKEY) + * - 4) select all keyframes that occur between selected markers (ALT-KKEY) + */ + +/* defines for column-select mode */ +EnumPropertyItem prop_column_select_types[] = { + {graphkeys_COLUMNSEL_KEYS, "KEYS", "On Selected Keyframes", ""}, + {graphkeys_COLUMNSEL_CFRA, "CFRA", "On Current Frame", ""}, + {graphkeys_COLUMNSEL_MARKERS_COLUMN, "MARKERS_COLUMN", "On Selected Markers", ""}, + {graphkeys_COLUMNSEL_MARKERS_BETWEEN, "MARKERS_BETWEEN", "Between Min/Max Selected Markers", ""}, + {0, NULL, NULL, NULL} +}; + +/* ------------------- */ + +/* Selects all visible keyframes between the specified markers */ +static void markers_selectkeys_between (bAnimContext *ac) +{ + ListBase anim_data = {NULL, NULL}; + bAnimListElem *ale; + int filter; + + BeztEditFunc select_cb; + BeztEditData bed; + float min, max; + + /* get extreme markers */ + //get_minmax_markers(1, &min, &max); // FIXME... add back markers api! + min= (float)ac->scene->r.sfra; // xxx temp code + max= (float)ac->scene->r.efra; // xxx temp code + + if (min==max) return; + min -= 0.5f; + max += 0.5f; + + /* get editing funcs + data */ + select_cb= ANIM_editkeyframes_select(SELECT_ADD); + memset(&bed, 0, sizeof(BeztEditData)); + bed.f1= min; + bed.f2= max; + + /* filter data */ + filter= (ANIMFILTER_VISIBLE | ANIMFILTER_CURVESONLY); + ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); + + /* select keys in-between */ + for (ale= anim_data.first; ale; ale= ale->next) { + Object *nob= ANIM_nla_mapping_get(ac, ale); + + if (nob) { + ANIM_nla_mapping_apply_fcurve(nob, ale->key_data, 0, 1); + ANIM_fcurve_keys_bezier_loop(&bed, ale->key_data, NULL, select_cb, NULL); + ANIM_nla_mapping_apply_fcurve(nob, ale->key_data, 1, 1); + } + else { + ANIM_fcurve_keys_bezier_loop(&bed, ale->key_data, NULL, select_cb, NULL); + } + } + + /* Cleanup */ + BLI_freelistN(&anim_data); +} + + +/* helper callback for columnselect_graph_keys() -> populate list CfraElems with frame numbers from selected beztriples */ +// TODO: if some other code somewhere needs this, it'll be time to port this over to keyframes_edit.c!!! +static short bezt_to_cfraelem(BeztEditData *bed, BezTriple *bezt) +{ + /* only if selected */ + if (bezt->f2 & SELECT) { + CfraElem *ce= MEM_callocN(sizeof(CfraElem), "cfraElem"); + BLI_addtail(&bed->list, ce); + + ce->cfra= bezt->vec[1][0]; + } + + return 0; +} + +/* Selects all visible keyframes in the same frames as the specified elements */ +static void columnselect_graph_keys (bAnimContext *ac, short mode) +{ + ListBase anim_data= {NULL, NULL}; + bAnimListElem *ale; + int filter; + + Scene *scene= ac->scene; + CfraElem *ce; + BeztEditFunc select_cb, ok_cb; + BeztEditData bed; + + /* initialise keyframe editing data */ + memset(&bed, 0, sizeof(BeztEditData)); + + /* build list of columns */ + switch (mode) { + case graphkeys_COLUMNSEL_KEYS: /* list of selected keys */ + if (ac->datatype == ANIMCONT_GPENCIL) { + filter= (ANIMFILTER_VISIBLE); + ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); + + //for (ale= anim_data.first; ale; ale= ale->next) + // gplayer_make_cfra_list(ale->data, &elems, 1); + } + else { + filter= (ANIMFILTER_VISIBLE | ANIMFILTER_CURVESONLY); + ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); + + for (ale= anim_data.first; ale; ale= ale->next) + ANIM_fcurve_keys_bezier_loop(&bed, ale->key_data, NULL, bezt_to_cfraelem, NULL); + } + BLI_freelistN(&anim_data); + break; + + case graphkeys_COLUMNSEL_CFRA: /* current frame */ + /* make a single CfraElem for storing this */ + ce= MEM_callocN(sizeof(CfraElem), "cfraElem"); + BLI_addtail(&bed.list, ce); + + ce->cfra= (float)CFRA; + break; + + case graphkeys_COLUMNSEL_MARKERS_COLUMN: /* list of selected markers */ + // FIXME: markers api needs to be improved for this first! + //make_marker_cfra_list(&elems, 1); + return; // XXX currently, this does nothing! + break; + + default: /* invalid option */ + return; + } + + /* set up BezTriple edit callbacks */ + select_cb= ANIM_editkeyframes_select(SELECT_ADD); + ok_cb= ANIM_editkeyframes_ok(BEZT_OK_FRAME); + + /* loop through all of the keys and select additional keyframes + * based on the keys found to be selected above + */ + if (ac->datatype == ANIMCONT_GPENCIL) + filter= (ANIMFILTER_VISIBLE); + else + filter= (ANIMFILTER_VISIBLE | ANIMFILTER_CURVESONLY); + ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); + + for (ale= anim_data.first; ale; ale= ale->next) { + Object *nob= ANIM_nla_mapping_get(ac, ale); + + /* loop over cfraelems (stored in the BeztEditData->list) + * - we need to do this here, as we can apply fewer NLA-mapping conversions + */ + for (ce= bed.list.first; ce; ce= ce->next) { + /* set frame for validation callback to refer to */ + if (nob) + bed.f1= get_action_frame(nob, ce->cfra); + else + bed.f1= ce->cfra; + + /* select elements with frame number matching cfraelem */ + ANIM_fcurve_keys_bezier_loop(&bed, ale->key_data, ok_cb, select_cb, NULL); + +#if 0 // XXX reenable when Grease Pencil stuff is back + if (ale->type == ANIMTYPE_GPLAYER) { + bGPDlayer *gpl= (bGPDlayer *)ale->data; + bGPDframe *gpf; + + for (gpf= gpl->frames.first; gpf; gpf= gpf->next) { + if (ecfra == gpf->framenum) + gpf->flag |= GP_FRAME_SELECT; + } + } + //else... +#endif // XXX reenable when Grease Pencil stuff is back + } + } + + /* free elements */ + BLI_freelistN(&bed.list); + BLI_freelistN(&anim_data); +} + +/* ------------------- */ + +static int graphkeys_columnselect_exec(bContext *C, wmOperator *op) +{ + bAnimContext ac; + short mode; + + /* get editor data */ + if (ANIM_animdata_get_context(C, &ac) == 0) + return OPERATOR_CANCELLED; + + /* action to take depends on the mode */ + mode= RNA_enum_get(op->ptr, "mode"); + + if (mode == graphkeys_COLUMNSEL_MARKERS_BETWEEN) + markers_selectkeys_between(&ac); + else + columnselect_graph_keys(&ac, mode); + + /* set notifier tha things have changed */ + ANIM_animdata_send_notifiers(C, &ac, ANIM_CHANGED_KEYFRAMES_SELECT); + + return OPERATOR_FINISHED; +} + +void GRAPHEDIT_OT_keyframes_columnselect (wmOperatorType *ot) +{ + /* identifiers */ + ot->name= "Select All"; + ot->idname= "GRAPHEDIT_OT_keyframes_columnselect"; + + /* api callbacks */ + ot->exec= graphkeys_columnselect_exec; + ot->poll= ED_operator_areaactive; + + /* flags */ + ot->flag= OPTYPE_REGISTER/*|OPTYPE_UNDO*/; + + /* props */ + RNA_def_enum(ot->srna, "mode", prop_column_select_types, 0, "Mode", ""); +} + +/* ******************** Mouse-Click Select Operator *********************** */ +/* This operator works in one of three ways: + * - 1) keyframe under mouse - no special modifiers + * - 2) all keyframes on the same side of current frame indicator as mouse - ALT modifier + * - 3) column select all keyframes in frame under mouse - CTRL modifier + * + * In addition to these basic options, the SHIFT modifier can be used to toggle the + * selection mode between replacing the selection (without) and inverting the selection (with). + */ + +/* defines for left-right select tool */ +EnumPropertyItem prop_leftright_select_types[] = { + {graphkeys_LRSEL_TEST, "CHECK", "Check if Select Left or Right", ""}, + {graphkeys_LRSEL_NONE, "OFF", "Don't select", ""}, + {graphkeys_LRSEL_LEFT, "LEFT", "Before current frame", ""}, + {graphkeys_LRSEL_RIGHT, "RIGHT", "After current frame", ""}, + {0, NULL, NULL, NULL} +}; + +/* ------------------- */ + +/* option 1) select keyframe directly under mouse */ +static void mouse_graph_keys (bAnimContext *ac, int mval[2], short selectmode) +{ + // XXX port this... +} + +/* Option 2) Selects all the keyframes on either side of the current frame (depends on which side the mouse is on) */ +static void selectkeys_leftright (bAnimContext *ac, short leftright, short select_mode) +{ + ListBase anim_data = {NULL, NULL}; + bAnimListElem *ale; + int filter; + + BeztEditFunc ok_cb, select_cb; + BeztEditData bed; + Scene *scene= ac->scene; + + /* if select mode is replace, deselect all keyframes first */ + if (select_mode==SELECT_REPLACE) { + select_mode=SELECT_ADD; + deselect_graph_keys(ac, 0, SELECT_SUBTRACT); + } + + /* set callbacks and editing data */ + ok_cb= ANIM_editkeyframes_ok(BEZT_OK_FRAMERANGE); + select_cb= ANIM_editkeyframes_select(select_mode); + + memset(&bed, 0, sizeof(BeztEditFunc)); + if (leftright == graphkeys_LRSEL_LEFT) { + bed.f1 = -MAXFRAMEF; + bed.f2 = (float)(CFRA + 0.1f); + } + else { + bed.f1 = (float)(CFRA - 0.1f); + bed.f2 = MAXFRAMEF; + } + + /* filter data */ + if (ac->datatype == ANIMCONT_GPENCIL) + filter= (ANIMFILTER_VISIBLE); + else + filter= (ANIMFILTER_VISIBLE | ANIMFILTER_CURVESONLY); + ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); + + /* select keys on the side where most data occurs */ + for (ale= anim_data.first; ale; ale= ale->next) { + Object *nob= ANIM_nla_mapping_get(ac, ale); + + if (nob) { + ANIM_nla_mapping_apply_fcurve(nob, ale->key_data, 0, 1); + ANIM_fcurve_keys_bezier_loop(&bed, ale->key_data, ok_cb, select_cb, NULL); + ANIM_nla_mapping_apply_fcurve(nob, ale->key_data, 1, 1); + } + //else if (ale->type == ANIMTYPE_GPLAYER) + // borderselect_gplayer_frames(ale->data, min, max, SELECT_ADD); + else + ANIM_fcurve_keys_bezier_loop(&bed, ale->key_data, ok_cb, select_cb, NULL); + } + + /* Cleanup */ + BLI_freelistN(&anim_data); +} + +/* Option 3) Selects all visible keyframes in the same frame as the mouse click */ +static void mouse_columnselect_graph_keys (bAnimContext *ac, float selx) +{ + ListBase anim_data= {NULL, NULL}; + bAnimListElem *ale; + int filter; + + BeztEditFunc select_cb, ok_cb; + BeztEditData bed; + + /* initialise keyframe editing data */ + memset(&bed, 0, sizeof(BeztEditData)); + + /* set up BezTriple edit callbacks */ + select_cb= ANIM_editkeyframes_select(SELECT_ADD); + ok_cb= ANIM_editkeyframes_ok(BEZT_OK_FRAME); + + /* loop through all of the keys and select additional keyframes + * based on the keys found to be selected above + */ + if (ac->datatype == ANIMCONT_GPENCIL) + filter= (ANIMFILTER_VISIBLE); + else + filter= (ANIMFILTER_VISIBLE | ANIMFILTER_CURVESONLY); + ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); + + for (ale= anim_data.first; ale; ale= ale->next) { + Object *nob= ANIM_nla_mapping_get(ac, ale); + + /* set frame for validation callback to refer to */ + if (nob) + bed.f1= get_action_frame(nob, selx); + else + bed.f1= selx; + + /* select elements with frame number matching cfraelem */ + ANIM_fcurve_keys_bezier_loop(&bed, ale->key_data, ok_cb, select_cb, NULL); + +#if 0 // XXX reenable when Grease Pencil stuff is back + if (ale->type == ANIMTYPE_GPLAYER) { + bGPDlayer *gpl= (bGPDlayer *)ale->data; + bGPDframe *gpf; + + for (gpf= gpl->frames.first; gpf; gpf= gpf->next) { + if (ecfra == gpf->framenum) + gpf->flag |= GP_FRAME_SELECT; + } + } + //else... +#endif // XXX reenable when Grease Pencil stuff is back + } + + /* free elements */ + BLI_freelistN(&bed.list); + BLI_freelistN(&anim_data); +} + +/* ------------------- */ + +/* handle clicking */ +static int graphkeys_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 */ + // XXX this is currently only available for normal select only + if (RNA_boolean_get(op->ptr, "extend_select")) + 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", graphkeys_LRSEL_LEFT); + else + RNA_int_set(op->ptr, "left_right", graphkeys_LRSEL_RIGHT); + + selectkeys_leftright(&ac, RNA_enum_get(op->ptr, "left_right"), selectmode); + } + else if (RNA_boolean_get(op->ptr, "column_select")) { + /* select all the keyframes that occur on the same frame as where the mouse clicked */ + float x; + + /* figure out where (the frame) the mouse clicked, and set all keyframes in that frame */ + UI_view2d_region_to_view(v2d, mval[0], mval[1], &x, NULL); + mouse_columnselect_graph_keys(&ac, x); + } + else { + /* select keyframe under mouse */ + mouse_graph_keys(&ac, mval, selectmode); + // XXX activate transform... + } + + /* set notifier tha things have changed */ + ANIM_animdata_send_notifiers(C, &ac, ANIM_CHANGED_BOTH); + + return OPERATOR_FINISHED; +} + +void GRAPHEDIT_OT_keyframes_clickselect (wmOperatorType *ot) +{ + /* identifiers */ + ot->name= "Mouse Select Keys"; + ot->idname= "GRAPHEDIT_OT_keyframes_clickselect"; + + /* api callbacks */ + ot->invoke= graphkeys_clickselect_invoke; + ot->poll= ED_operator_areaactive; + + /* id-props */ + // XXX should we make this into separate operators? + RNA_def_enum(ot->srna, "left_right", NULL /* XXX prop_graphkeys_clickselect_items */, 0, "Left Right", ""); // ALTKEY + RNA_def_boolean(ot->srna, "extend_select", 0, "Extend Select", ""); // SHIFTKEY + RNA_def_boolean(ot->srna, "column_select", 0, "Column Select", ""); // CTRLKEY +} + +/* ************************************************************************** */ +#endif // XXX code to be sanitied for new system diff --git a/source/blender/editors/space_ipo/space_ipo.c b/source/blender/editors/space_ipo/space_ipo.c index 6ee3af04594..c3b93280268 100644 --- a/source/blender/editors/space_ipo/space_ipo.c +++ b/source/blender/editors/space_ipo/space_ipo.c @@ -155,7 +155,7 @@ static void graph_main_area_init(wmWindowManager *wm, ARegion *ar) UI_view2d_region_reinit(&ar->v2d, V2D_COMMONVIEW_CUSTOM, ar->winx, ar->winy); /* own keymap */ - keymap= WM_keymap_listbase(wm, "Ipo", SPACE_IPO, 0); /* XXX weak? */ + keymap= WM_keymap_listbase(wm, "GraphEdit Keys", SPACE_IPO, 0); /* XXX weak? */ WM_event_add_keymap_handler_bb(&ar->handlers, keymap, &ar->v2d.mask, &ar->winrct); } @@ -211,14 +211,6 @@ static void graph_main_area_draw(const bContext *C, ARegion *ar) UI_view2d_scrollers_free(scrollers); } -void graph_operatortypes(void) -{ -} - -void graph_keymap(struct wmWindowManager *wm) -{ -} - static void graph_channel_area_init(wmWindowManager *wm, ARegion *ar) { ListBase *keymap; @@ -375,8 +367,8 @@ void ED_spacetype_ipo(void) st->free= graph_free; st->init= graph_init; st->duplicate= graph_duplicate; - st->operatortypes= graph_operatortypes; - st->keymap= graph_keymap; + st->operatortypes= graphedit_operatortypes; + st->keymap= graphedit_keymap; st->listener= graph_listener; st->refresh= graph_refresh; @@ -386,7 +378,7 @@ void ED_spacetype_ipo(void) art->init= graph_main_area_init; art->draw= graph_main_area_draw; art->listener= graph_main_area_listener; - art->keymapflag= ED_KEYMAP_VIEW2D|ED_KEYMAP_MARKERS|ED_KEYMAP_ANIMATION; + art->keymapflag= ED_KEYMAP_VIEW2D/*|ED_KEYMAP_MARKERS*/|ED_KEYMAP_ANIMATION|ED_KEYMAP_FRAMES; BLI_addhead(&st->regiontypes, art);