RNA/UI: Allow displaying in tooltip why RNA property isn't editable
authorJulian Eisel <eiseljulian@gmail.com>
Wed, 21 Sep 2016 22:10:53 +0000 (00:10 +0200)
committerJulian Eisel <eiseljulian@gmail.com>
Wed, 21 Sep 2016 22:10:53 +0000 (00:10 +0200)
This commit allows RNA properties to return additional info on their editable state which may then be displayed in tooltips. To show how it works, it also adds some info for the editable check of proxies. For generally un-editable properties or properties of a linked data-block, RNA returns default strings.

| {F362785} | {F362786} | {F362787} |

Reviewed by brecht, thanks!

Differential Revision: https://developer.blender.org/D2243

20 files changed:
source/blender/editors/interface/interface.c
source/blender/editors/interface/interface_regions.c
source/blender/makesrna/RNA_access.h
source/blender/makesrna/intern/rna_ID.c
source/blender/makesrna/intern/rna_access.c
source/blender/makesrna/intern/rna_animation.c
source/blender/makesrna/intern/rna_curve.c
source/blender/makesrna/intern/rna_fcurve.c
source/blender/makesrna/intern/rna_gpencil.c
source/blender/makesrna/intern/rna_internal_types.h
source/blender/makesrna/intern/rna_lattice.c
source/blender/makesrna/intern/rna_material.c
source/blender/makesrna/intern/rna_mesh.c
source/blender/makesrna/intern/rna_meta.c
source/blender/makesrna/intern/rna_nla.c
source/blender/makesrna/intern/rna_object.c
source/blender/makesrna/intern/rna_pose.c
source/blender/makesrna/intern/rna_sequencer.c
source/blender/makesrna/intern/rna_space.c
source/blender/makesrna/intern/rna_vfont.c

index aca107013aca00e3d56b91e031fa1b198573c367..6bba35e821fd7a6930f27affd2dda4c4d03fd51a 100644 (file)
@@ -3215,10 +3215,10 @@ void ui_def_but_icon(uiBut *but, const int icon, const int flag)
        }
 }
 
-static void ui_def_but_rna__disable(uiBut *but)
+static void ui_def_but_rna__disable(uiBut *but, const char *info)
 {
        but->flag |= UI_BUT_DISABLED;
-       but->disabled_info = "";
+       but->disabled_info = info;
 }
 
 static void ui_def_but_rna__menu(bContext *UNUSED(C), uiLayout *layout, void *but_p)
@@ -3483,8 +3483,9 @@ static uiBut *ui_def_but_rna(
                but->flag |= UI_BUT_ICON_SUBMENU;
        }
 
-       if (!RNA_property_editable(&but->rnapoin, prop)) {
-               ui_def_but_rna__disable(but);
+       const char *info;
+       if (!RNA_property_editable_info(&but->rnapoin, prop, &info)) {
+               ui_def_but_rna__disable(but, info);
        }
 
        if (but->flag & UI_BUT_UNDO && (ui_but_is_rna_undo(but) == false)) {
@@ -3515,7 +3516,7 @@ static uiBut *ui_def_but_rna_propname(uiBlock *block, int type, int retval, cons
        else {
                but = ui_def_but(block, type, retval, propname, x, y, width, height, NULL, min, max, a1, a2, tip);
 
-               ui_def_but_rna__disable(but);
+               ui_def_but_rna__disable(but, "Unknown Property.");
        }
 
        return but;
index b7f921624d988a2286503912c038cb44737bea02..5602e2b9c6d0becbcf4b0e381fbd1a5ff207cd2c 100644 (file)
@@ -467,7 +467,7 @@ static uiTooltipData *ui_tooltip_data_from_button(bContext *C, uiBut *but)
                }
                /* alternatively, buttons can store some reasoning too */
                else if (but->disabled_info) {
-                       disabled_msg = but->disabled_info;
+                       disabled_msg = TIP_(but->disabled_info);
                }
 
                if (disabled_msg && disabled_msg[0]) {
index 2893fabd1451eb15fdd89da7011bf2d7d960c990..44d1a6bfaafd5495a3a4d1f8b39c7fc27da34d63 100644 (file)
@@ -856,6 +856,7 @@ StructRNA *RNA_property_pointer_type(PointerRNA *ptr, PropertyRNA *prop);
 int RNA_property_pointer_poll(PointerRNA *ptr, PropertyRNA *prop, PointerRNA *value);
 
 bool RNA_property_editable(PointerRNA *ptr, PropertyRNA *prop);
+bool RNA_property_editable_info(PointerRNA *ptr, PropertyRNA *prop, const char **r_info);
 bool RNA_property_editable_index(PointerRNA *ptr, PropertyRNA *prop, int index);
 bool RNA_property_editable_flag(PointerRNA *ptr, PropertyRNA *prop); /* without lib check, only checks the flag */
 bool RNA_property_animateable(PointerRNA *ptr, PropertyRNA *prop);
index 7e6bdf970f6d737aa7976e412f178fdcfe13c288..280ad4aa9b14f1ba4b2acc16005174f8c874d637 100644 (file)
@@ -122,7 +122,7 @@ void rna_ID_name_set(PointerRNA *ptr, const char *value)
        BLI_libblock_ensure_unique_name(G.main, id->name);
 }
 
-static int rna_ID_name_editable(PointerRNA *ptr)
+static int rna_ID_name_editable(PointerRNA *ptr, const char **UNUSED(r_info))
 {
        ID *id = (ID *)ptr->data;
        
index 6879a0534e9ea2dcafa9a6f9286f3d02078e6322..6f054e586ecf717699eb6c171bdd030ad0898d6c 100644 (file)
@@ -1619,20 +1619,56 @@ bool RNA_property_editable(PointerRNA *ptr, PropertyRNA *prop)
 {
        ID *id = ptr->id.data;
        int flag;
+       const char *dummy_info;
 
        prop = rna_ensure_property(prop);
-       flag = prop->editable ? prop->editable(ptr) : prop->flag;
+       flag = prop->editable ? prop->editable(ptr, &dummy_info) : prop->flag;
+
        return ((flag & PROP_EDITABLE) &&
                (flag & PROP_REGISTER) == 0 &&
                (!id || !ID_IS_LINKED_DATABLOCK(id) || (prop->flag & PROP_LIB_EXCEPTION)));
 }
 
+/**
+ * Version of #RNA_property_editable that tries to return additional info in \a r_info that can be exposed in UI.
+ */
+bool RNA_property_editable_info(PointerRNA *ptr, PropertyRNA *prop, const char **r_info)
+{
+       ID *id = ptr->id.data;
+       int flag;
+
+       prop = rna_ensure_property(prop);
+       *r_info = "";
+
+       /* get flag */
+       if (prop->editable) {
+               flag = prop->editable(ptr, r_info);
+       }
+       else {
+               flag = prop->flag;
+               if ((flag & PROP_EDITABLE) == 0 || (flag & PROP_REGISTER)) {
+                       *r_info = "This property is for internal use only and can't be edited.";
+               }
+       }
+
+       /* property from linked data-block */
+       if (id && ID_IS_LINKED_DATABLOCK(id) && (prop->flag & PROP_LIB_EXCEPTION) == 0) {
+               if (!(*r_info)[0]) {
+                       *r_info = "Can't edit this property from a linked data-block.";
+               }
+               return false;
+       }
+
+       return ((flag & PROP_EDITABLE) && (flag & PROP_REGISTER) == 0);
+}
+
 bool RNA_property_editable_flag(PointerRNA *ptr, PropertyRNA *prop)
 {
        int flag;
+       const char *dummy_info;
 
        prop = rna_ensure_property(prop);
-       flag = prop->editable ? prop->editable(ptr) : prop->flag;
+       flag = prop->editable ? prop->editable(ptr, &dummy_info) : prop->flag;
        return (flag & PROP_EDITABLE) != 0;
 }
 
@@ -1647,9 +1683,11 @@ bool RNA_property_editable_index(PointerRNA *ptr, PropertyRNA *prop, int index)
        prop = rna_ensure_property(prop);
 
        flag = prop->flag;
-       
-       if (prop->editable)
-               flag &= prop->editable(ptr);
+
+       if (prop->editable) {
+               const char *dummy_info;
+               flag &= prop->editable(ptr, &dummy_info);
+       }
 
        if (prop->itemeditable)
                flag &= prop->itemeditable(ptr, index);
index e37affcf5a319074634815fb03c618f447babf40..cdbf7582fa738fabeb5abb7c9271369f599d1b65 100644 (file)
@@ -89,7 +89,7 @@ static void rna_AnimData_update(Main *UNUSED(bmain), Scene *UNUSED(scene), Point
        DAG_id_tag_update(id, OB_RECALC_OB | OB_RECALC_DATA);
 }
 
-static int rna_AnimData_action_editable(PointerRNA *ptr)
+static int rna_AnimData_action_editable(PointerRNA *ptr, const char **UNUSED(r_info))
 {
        AnimData *adt = (AnimData *)ptr->data;
        
@@ -305,7 +305,7 @@ static StructRNA *rna_ksPath_id_typef(PointerRNA *ptr)
        return ID_code_to_RNA_type(ksp->idtype);
 }
 
-static int rna_ksPath_id_editable(PointerRNA *ptr)
+static int rna_ksPath_id_editable(PointerRNA *ptr, const char **UNUSED(r_info))
 {
        KS_Path *ksp = (KS_Path *)ptr->data;
        return (ksp->idtype) ? PROP_EDITABLE : 0;
@@ -393,7 +393,7 @@ static void rna_KeyingSet_name_set(PointerRNA *ptr, const char *value)
 }
 
 
-static int rna_KeyingSet_active_ksPath_editable(PointerRNA *ptr)
+static int rna_KeyingSet_active_ksPath_editable(PointerRNA *ptr, const char **UNUSED(r_info))
 {
        KeyingSet *ks = (KeyingSet *)ptr->data;
        
index f4fb30e0793b3992e5b70519c2d3578d44770b0d..22e459647420afa73000e029b33d4d41010c39a0 100644 (file)
@@ -221,7 +221,7 @@ static void rna_Curve_texspace_set(Main *UNUSED(bmain), Scene *UNUSED(scene), Po
                BKE_curve_texspace_calc(cu);
 }
 
-static int rna_Curve_texspace_editable(PointerRNA *ptr)
+static int rna_Curve_texspace_editable(PointerRNA *ptr, const char **UNUSED(r_info))
 {
        Curve *cu = (Curve *)ptr->data;
        return (cu->texflag & CU_AUTOSPACE) ? 0 : PROP_EDITABLE;
index c521e93d33ec568809c0dfa3f4035a57d7b58fcc..1d3b65bb7bae57258cdcfb5e75644f6ea631ba86 100644 (file)
@@ -199,13 +199,13 @@ static StructRNA *rna_DriverTarget_id_typef(PointerRNA *ptr)
        return ID_code_to_RNA_type(dtar->idtype);
 }
 
-static int rna_DriverTarget_id_editable(PointerRNA *ptr)
+static int rna_DriverTarget_id_editable(PointerRNA *ptr, const char **UNUSED(r_info))
 {
        DriverTarget *dtar = (DriverTarget *)ptr->data;
        return (dtar->idtype) ? PROP_EDITABLE : 0;
 }
 
-static int rna_DriverTarget_id_type_editable(PointerRNA *ptr)
+static int rna_DriverTarget_id_type_editable(PointerRNA *ptr, const char **UNUSED(r_info))
 {
        DriverTarget *dtar = (DriverTarget *)ptr->data;
        
index 7eaf8b65902046566406f3dbe09303624aaab3dc..9b881c13347a9b8477626759da36849227d128db 100644 (file)
@@ -120,7 +120,7 @@ static char *rna_GPencilLayer_path(PointerRNA *ptr)
        return BLI_sprintfN("layers[\"%s\"]", name_esc);
 }
 
-static int rna_GPencilLayer_active_frame_editable(PointerRNA *ptr)
+static int rna_GPencilLayer_active_frame_editable(PointerRNA *ptr, const char **UNUSED(r_info))
 {
        bGPDlayer *gpl = (bGPDlayer *)ptr->data;
 
index ba0705b5caad710ff46fad50797af06b46faa082..04b85b8997eb6aee2cc2db6929c9a4dceb388ee0 100644 (file)
@@ -62,7 +62,7 @@ struct Scene;
 typedef void (*UpdateFunc)(struct Main *main, struct Scene *scene, struct PointerRNA *ptr);
 typedef void (*ContextPropUpdateFunc)(struct bContext *C, struct PointerRNA *ptr, struct PropertyRNA *prop);
 typedef void (*ContextUpdateFunc)(struct bContext *C, struct PointerRNA *ptr);
-typedef int (*EditableFunc)(struct PointerRNA *ptr);
+typedef int (*EditableFunc)(struct PointerRNA *ptr, const char **r_info);
 typedef int (*ItemEditableFunc)(struct PointerRNA *ptr, int index);
 typedef struct IDProperty *(*IDPropertiesFunc)(struct PointerRNA *ptr, bool create);
 typedef struct StructRNA *(*StructRefineFunc)(struct PointerRNA *ptr);
@@ -188,7 +188,9 @@ struct PropertyRNA {
        UpdateFunc update;
        int noteflag;
 
-       /* callback for testing if editable */
+       /* Callback for testing if editable. Its r_info parameter can be used to
+        * return info on editable state that might be shown to user. E.g. tooltips
+        * of disabled buttons can show reason why button is disabled using this. */
        EditableFunc editable;
        /* callback for testing if array-item editable (if applicable) */
        ItemEditableFunc itemeditable;
index 6bc9cc38a7da7d91fd84c680218fd320ed6baca9..9424ddf7d0ee10fc5ec2c3a08a48bbc93a566dbe 100644 (file)
@@ -171,7 +171,7 @@ static void rna_Lattice_use_outside_set(PointerRNA *ptr, int value)
        }
 }
 
-static int rna_Lattice_size_editable(PointerRNA *ptr)
+static int rna_Lattice_size_editable(PointerRNA *ptr, const char **UNUSED(r_info))
 {
        Lattice *lt = (Lattice *)ptr->data;
 
index 2a8cc073e228ad3ca9f5e27cd4fbafadc8d99d96..752f406264a4cd7e88e0d69a0a84c313bbb7dcc1 100644 (file)
@@ -233,7 +233,7 @@ static void rna_Material_active_texture_set(PointerRNA *ptr, PointerRNA value)
        set_current_material_texture(ma, value.data);
 }
 
-static int rna_Material_active_texture_editable(PointerRNA *ptr)
+static int rna_Material_active_texture_editable(PointerRNA *ptr, const char **UNUSED(r_info))
 {
        Material *ma = (Material *)ptr->id.data;
 
index 1d7348648332d5810e47085eebfdd9647a24d423..df034ed85d8f3d12c6264e20effc038d13b727fb 100644 (file)
@@ -662,7 +662,7 @@ static void rna_MeshLoopColor_color_set(PointerRNA *ptr, const float *values)
        (&mcol->r)[2] = (char)(CLAMPIS(values[2] * 255.0f, 0, 255));
 }
 
-static int rna_Mesh_texspace_editable(PointerRNA *ptr)
+static int rna_Mesh_texspace_editable(PointerRNA *ptr, const char **UNUSED(r_info))
 {
        Mesh *me = (Mesh *)ptr->data;
        return (me->texflag & ME_AUTOSPACE) ? 0 : PROP_EDITABLE;
index d3b66e4c3b4000e9fcdc21080d2195c1b9916a6c..9d13bc90e727441511066beff7add15819876968 100644 (file)
@@ -53,7 +53,7 @@
 #include "WM_types.h"
 #include "WM_api.h"
 
-static int rna_Meta_texspace_editable(PointerRNA *ptr)
+static int rna_Meta_texspace_editable(PointerRNA *ptr, const char **UNUSED(r_info))
 {
        MetaBall *mb = (MetaBall *)ptr->data;
        return (mb->texflag & MB_AUTOSPACE) ? 0 : PROP_EDITABLE;
index eb87eafe16c9e4ede719a0aeeaab36e9ead6df3a..55bc40f573ca19c9c6608324c71fb8e81dbbf95e 100644 (file)
@@ -282,7 +282,7 @@ static void rna_NlaStrip_use_auto_blend_set(PointerRNA *ptr, int value)
        }
 }
 
-static int rna_NlaStrip_action_editable(PointerRNA *ptr)
+static int rna_NlaStrip_action_editable(PointerRNA *ptr, const char **UNUSED(r_info))
 {
        NlaStrip *strip = (NlaStrip *)ptr->data;
        
index 2cbf23973c21e5eb1b1687d8b8655d931913537b..0e735350e05c3d6b4e70ce8565b8e67138cff0a3 100644 (file)
@@ -712,7 +712,7 @@ static void rna_Object_active_material_set(PointerRNA *ptr, PointerRNA value)
        assign_material(ob, value.data, ob->actcol, BKE_MAT_ASSIGN_EXISTING);
 }
 
-static int rna_Object_active_material_editable(PointerRNA *ptr)
+static int rna_Object_active_material_editable(PointerRNA *ptr, const char **UNUSED(r_info))
 {
        Object *ob = (Object *)ptr->id.data;
        bool is_editable;
index 1f34d8f23d4c8637e7f83f662c0ce2828e585c7d..0591e877634b1dc3b725508ac8fb735ac0d0faf0 100644 (file)
@@ -556,13 +556,18 @@ static void rna_PoseChannel_constraints_remove(ID *id, bPoseChannel *pchan, Repo
        }
 }
 
-static int rna_PoseChannel_proxy_editable(PointerRNA *ptr)
+static int rna_PoseChannel_proxy_editable(PointerRNA *ptr, const char **r_info)
 {
        Object *ob = (Object *)ptr->id.data;
        bArmature *arm = ob->data;
        bPoseChannel *pchan = (bPoseChannel *)ptr->data;
        
-       return (ob->proxy && pchan->bone && (pchan->bone->layer & arm->layer_protected)) ? 0 : PROP_EDITABLE;
+       if (ob->proxy && pchan->bone && (pchan->bone->layer & arm->layer_protected)) {
+               *r_info = "Can't edit property of a proxy on a protected layer";
+               return 0;
+       }
+       
+       return PROP_EDITABLE;
 }
 
 static int rna_PoseChannel_location_editable(PointerRNA *ptr, int index)
index c3a660588885460d10a0ed1e5f4240a46506febf..bb9c2a6c2fdb4dd77125de95756d616aba577cda 100644 (file)
@@ -292,7 +292,7 @@ static int rna_Sequence_frame_length_get(PointerRNA *ptr)
        return BKE_sequence_tx_get_final_right(seq, false) - BKE_sequence_tx_get_final_left(seq, false);
 }
 
-static int rna_Sequence_frame_editable(PointerRNA *ptr)
+static int rna_Sequence_frame_editable(PointerRNA *ptr, const char **UNUSED(r_info))
 {
        Sequence *seq = (Sequence *)ptr->data;
        /* Effect sequences' start frame and length must be readonly! */
index a7dab0f56f8a9c7484b496685f1fa4301500a754..375d370097e9d35b4cecbd74e7f066a83ea91bb7 100644 (file)
@@ -1645,7 +1645,7 @@ static void rna_FileBrowser_FSMenuEntry_name_set(PointerRNA *ptr, const char *va
        ED_fsmenu_entry_set_name(fsm, value);
 }
 
-static int rna_FileBrowser_FSMenuEntry_name_get_editable(PointerRNA *ptr)
+static int rna_FileBrowser_FSMenuEntry_name_get_editable(PointerRNA *ptr, const char **UNUSED(r_info))
 {
        FSMenuEntry *fsm = ptr->data;
 
index e9ba0c784396dc5cf410be9770d0053e24023337..c743751649ca1d7f397206a7540486618c9d283e 100644 (file)
@@ -44,7 +44,7 @@
 #include "WM_api.h"
 
 /* matching fnction in rna_ID.c */
-static int rna_VectorFont_filepath_editable(PointerRNA *ptr)
+static int rna_VectorFont_filepath_editable(PointerRNA *ptr, const char **UNUSED(r_info))
 {
        VFont *vfont = ptr->id.data;
        if (BKE_vfont_is_builtin(vfont)) {