Graph Editor "Active Keyframe" settings
authorJoshua Leung <aligorith@gmail.com>
Sat, 6 Aug 2011 07:01:07 +0000 (07:01 +0000)
committerJoshua Leung <aligorith@gmail.com>
Sat, 6 Aug 2011 07:01:07 +0000 (07:01 +0000)
This commit makes some tweaks to the way that the "active keyframe"
settings in the Properties region in the Graph Editor work (for the
better, hopefully).

Basically, the problem was that previously, these were clunky and non-
intuitive to use, since they were just directly displaying the RNA
properties for those keyframes for editing purposes. But due to
limitations of RNA (i.e. from a RNA pointer to a keyframe, you
couldn't see which F-Curve you came from), several things were
impossible, notably:
1) Doing proper updates, including validating that the handles are in
a valid state - that requires access to the F-Curve to provide to the
F-Curve-based curve validity checking functions
2) Having the values of the keyframes display in whatever unit that
the property the F-Curve affects displays as - for this, you once
again need to know the F-Curve in order to resolve the property that
it affects; also the fact that only a single unit could be set for RNA
properties further limited things

This commit basically gets around these problems by moving away from a
layout-engine based approach to one where we attach custom update
callbacks and also override the units of the y-co widgets when
creating the widgets for these, thus allowing the buttons to work in
the ways that animators expect.

source/blender/editors/interface/interface.c
source/blender/editors/space_graph/graph_buttons.c

index 40d86ec..c7c2235 100644 (file)
@@ -3216,11 +3216,17 @@ void uiButSetUnitType(uiBut *but, const int unit_type)
 
 int uiButGetUnitType(uiBut *but)
 {
-       if(but->rnaprop) {
-               return RNA_SUBTYPE_UNIT(RNA_property_subtype(but->rnaprop));
+       int ownUnit = (int)but->unit_type;
+       
+       /* own unit define always takes precidence over RNA provided, allowing for overriding 
+        * default value provided in RNA in a few special cases (i.e. Active Keyframe in Graph Edit)
+        */
+       // XXX: this doesn't allow clearing unit completely, though the same could be said for icons
+       if ((ownUnit != 0) || (but->rnaprop == NULL)) {
+               return ownUnit << 16;
        }
        else {
-               return ((int)but->unit_type)<<16;
+               return RNA_SUBTYPE_UNIT(RNA_property_subtype(but->rnaprop));
        }
 }
 
index 3073ff1..d8fd53b 100644 (file)
@@ -53,6 +53,7 @@
 #include "BKE_fcurve.h"
 #include "BKE_main.h"
 #include "BKE_screen.h"
+#include "BKE_unit.h"
 
 
 #include "WM_api.h"
@@ -77,8 +78,7 @@
 
 /* ******************* graph editor space & buttons ************** */
 
-#define B_NOP          1
-#define B_REDR         2
+#define B_REDR 1
 
 /* -------------- */
 
@@ -244,6 +244,35 @@ static short get_active_fcurve_keyframe_edit(FCurve *fcu, BezTriple **bezt, BezT
        return 0;
 }
 
+/* update callback for active keyframe properties - base updates stuff */
+static void graphedit_activekey_update_cb(bContext *UNUSED(C), void *fcu_ptr, void *UNUSED(bezt_ptr))
+{
+       FCurve *fcu = (FCurve *)fcu_ptr;
+       
+       /* make sure F-Curve and its handles are still valid after this editing */
+       sort_time_fcurve(fcu);
+       testhandles_fcurve(fcu);
+}
+
+/* update callback for active keyframe properties - handle-editing wrapper */
+static void graphedit_activekey_handles_cb(bContext *C, void *fcu_ptr, void *bezt_ptr)
+{
+       FCurve *fcu = (FCurve *)fcu_ptr;
+       BezTriple *bezt = (BezTriple *)bezt_ptr;
+       
+       /* since editing the handles, make sure they're set to types which are receptive to editing 
+        * see transform_conversions.c :: createTransGraphEditData(), last step in second loop
+        */
+       if (ELEM(bezt->h1, HD_AUTO, HD_AUTO_ANIM) && ELEM(bezt->h2, HD_AUTO, HD_AUTO_ANIM)) {
+               /* by changing to aligned handles, these can now be moved... */
+               bezt->h1= HD_ALIGN;
+               bezt->h2= HD_ALIGN;
+       }
+       
+       /* now call standard updates */
+       graphedit_activekey_update_cb(C, fcu_ptr, bezt_ptr);
+}
+
 static void graph_panel_key_properties(const bContext *C, Panel *pa)
 {
        bAnimListElem *ale;
@@ -262,27 +291,66 @@ static void graph_panel_key_properties(const bContext *C, Panel *pa)
        
        /* only show this info if there are keyframes to edit */
        if (get_active_fcurve_keyframe_edit(fcu, &bezt, &prevbezt)) {
-               PointerRNA bezt_ptr;
+               PointerRNA bezt_ptr, id_ptr, fcu_prop_ptr;
+               PropertyRNA *fcu_prop = NULL;
+               uiBut *but;
+               int unit = B_UNIT_NONE;
                
                /* RNA pointer to keyframe, to allow editing */
                RNA_pointer_create(ale->id, &RNA_Keyframe, bezt, &bezt_ptr);
                
+               /* get property that F-Curve affects, for some unit-conversion magic */
+               RNA_id_pointer_create(ale->id, &id_ptr);
+               if (RNA_path_resolve(&id_ptr, fcu->rna_path, &fcu_prop_ptr, &fcu_prop) && fcu_prop) {
+                       /* determine the unit for this property */
+                       unit = RNA_SUBTYPE_UNIT(RNA_property_subtype(fcu_prop));
+               }               
+               
                /* interpolation */
                col= uiLayoutColumn(layout, 0);
                        uiItemR(col, &bezt_ptr, "interpolation", 0, NULL, ICON_NONE);
                        
-               /* numerical coordinate editing */
+               /* numerical coordinate editing 
+                *      - we use the button-versions of the calls so that we can attach special update handlers
+                *        and unit conversion magic that cannot be achieved using a purely RNA-approach
+                */
+               // XXX: 
                col= uiLayoutColumn(layout, 1);
                        /* keyframe itself */
-                       uiItemR(col, &bezt_ptr, "co", 0, "Key", ICON_NONE);
+                       {
+                               uiItemL(col, "Key:", ICON_NONE);
+                               
+                               but = uiDefButR(block, NUM, B_REDR, "Frame", 0, 0, UI_UNIT_X, UI_UNIT_Y, &bezt_ptr, "co", 0, 0, 0, -1, -1, NULL);
+                               uiButSetFunc(but, graphedit_activekey_update_cb, fcu, bezt);
+                               
+                               but = uiDefButR(block, NUM, B_REDR, "Value", 0, 0, UI_UNIT_X, UI_UNIT_Y, &bezt_ptr, "co", 1, 0, 0, -1, -1, NULL);
+                               uiButSetFunc(but, graphedit_activekey_update_cb, fcu, bezt);
+                               uiButSetUnitType(but, unit);
+                       }
                        
                        /* previous handle - only if previous was Bezier interpolation */
-                       if ((prevbezt) && (prevbezt->ipo == BEZT_IPO_BEZ))
-                               uiItemR(col, &bezt_ptr, "handle_left", 0, NULL, ICON_NONE);
+                       if ((prevbezt) && (prevbezt->ipo == BEZT_IPO_BEZ)) {
+                               uiItemL(col, "Left Handle:", ICON_NONE);
+                               
+                               but = uiDefButR(block, NUM, B_REDR, "X", 0, 0, UI_UNIT_X, UI_UNIT_Y, &bezt_ptr, "handle_left", 0, 0, 0, -1, -1, NULL);
+                               uiButSetFunc(but, graphedit_activekey_handles_cb, fcu, bezt);           
+                               
+                               but = uiDefButR(block, NUM, B_REDR, "Y", 0, 0, UI_UNIT_X, UI_UNIT_Y, &bezt_ptr, "handle_left", 1, 0, 0, -1, -1, NULL);
+                               uiButSetFunc(but, graphedit_activekey_handles_cb, fcu, bezt);
+                               uiButSetUnitType(but, unit);
+                       }
                        
                        /* next handle - only if current is Bezier interpolation */
-                       if (bezt->ipo == BEZT_IPO_BEZ)
-                               uiItemR(col, &bezt_ptr, "handle_right", 0, NULL, ICON_NONE);
+                       if (bezt->ipo == BEZT_IPO_BEZ) {
+                               uiItemL(col, "Right Handle:", ICON_NONE);
+                               
+                               but = uiDefButR(block, NUM, B_REDR, "X", 0, 0, UI_UNIT_X, UI_UNIT_Y, &bezt_ptr, "handle_right", 0, 0, 0, -1, -1, NULL);
+                               uiButSetFunc(but, graphedit_activekey_handles_cb, fcu, bezt);
+                               
+                               but = uiDefButR(block, NUM, B_REDR, "Y", 0, 0, UI_UNIT_X, UI_UNIT_Y, &bezt_ptr, "handle_right", 1, 0, 0, -1, -1, NULL);
+                               uiButSetFunc(but, graphedit_activekey_handles_cb, fcu, bezt);
+                               uiButSetUnitType(but, unit);
+                       }
        }
        else {
                if ((fcu->bezt == NULL) && (fcu->modifiers.first)) {
@@ -659,7 +727,6 @@ static void graph_panel_drivers(const bContext *C, Panel *pa)
 static void do_graph_region_modifier_buttons(bContext *C, void *UNUSED(arg), int event)
 {
        switch (event) {
-               case B_REDR:
                case B_FMODIFIER_REDRAW: // XXX this should send depsgraph updates too
                        WM_event_add_notifier(C, NC_ANIMATION, NULL); // XXX need a notifier specially for F-Modifiers
                        break;