UI: add description methods for `wm.context_*` operators
Generic context operators now look-up the RNA properties to extract their description (when it's available). Add `bl_rna_utils.data_path.property_definition_from_data_path()` to handle the details of accessing the RNA property definition.
This commit is contained in:
parent
88d94d89fa
commit
5a6d5d20de
|
@ -0,0 +1,80 @@
|
|||
# ##### 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
#
|
||||
# ##### END GPL LICENSE BLOCK #####
|
||||
|
||||
# <pep8 compliant>
|
||||
|
||||
__all__ = (
|
||||
"property_definition_from_data_path",
|
||||
)
|
||||
|
||||
class _TokenizeDataPath:
|
||||
"""Class to split up tokens of a data-path."""
|
||||
__slots__ = (
|
||||
"data_path",
|
||||
)
|
||||
|
||||
def __init__(self, attrs):
|
||||
self.data_path = attrs
|
||||
|
||||
def __getattr__(self, attr):
|
||||
return _TokenizeDataPath(self.data_path + ((".%s" % attr),))
|
||||
|
||||
def __getitem__(self, key):
|
||||
return _TokenizeDataPath(self.data_path + (("[%r]" % (key,)),))
|
||||
|
||||
def __call__(self, *args, **kw):
|
||||
value_str = ", ".join([
|
||||
val for val in (
|
||||
repr(args)[1:-1],
|
||||
", ".join(["%s=%r" % (key, value) for key, value in kw.items()])
|
||||
) if val])
|
||||
return _TokenizeDataPath(self.data_path + ('(%s)' % value_str, ))
|
||||
|
||||
def __iter__(self):
|
||||
return iter(self.data_path)
|
||||
|
||||
|
||||
def property_definition_from_data_path(base, data_path):
|
||||
"""
|
||||
Return an RNA property definition from an object and a data path.
|
||||
|
||||
In Blender this is often used with ``context`` as the base and a
|
||||
path that it references, for example ``.space_data.lock_camera``.
|
||||
"""
|
||||
base_tokenize = _TokenizeDataPath(())
|
||||
data = list(eval("base_tokenize" + data_path))
|
||||
del base_tokenize
|
||||
while data and (not data[-1].startswith(".")):
|
||||
data.pop()
|
||||
|
||||
if (not data) or (not data[-1].startswith(".")) or (len(data) < 2):
|
||||
return None
|
||||
|
||||
data_path_head = "".join(data[:-1])
|
||||
data_path_tail = data[-1]
|
||||
|
||||
value_head = eval("base" + data_path_head)
|
||||
value_head_rna = getattr(value_head, "bl_rna", None)
|
||||
if value_head_rna is None:
|
||||
return None
|
||||
|
||||
value_tail = value_head.bl_rna.properties.get(data_path_tail[1:])
|
||||
if not value_tail:
|
||||
return None
|
||||
|
||||
return value_tail
|
|
@ -95,6 +95,28 @@ def context_path_validate(context, data_path):
|
|||
return value
|
||||
|
||||
|
||||
def context_path_description(context, data_path):
|
||||
from bl_rna_utils.data_path import property_definition_from_data_path
|
||||
rna_prop = property_definition_from_data_path(context, "." + data_path)
|
||||
if rna_prop is not None:
|
||||
description = rna_prop.description
|
||||
if description:
|
||||
return description
|
||||
return None
|
||||
|
||||
|
||||
def description_from_data_path(base, data_path, *, prefix, value=Ellipsis):
|
||||
if context_path_validate(base, data_path) is Ellipsis:
|
||||
return None
|
||||
description = context_path_description(base, data_path)
|
||||
if description:
|
||||
description = "%s: %s" % (prefix, description)
|
||||
if value != Ellipsis:
|
||||
description = "%s\n%s: %s" % (description, iface_("Value"), str(value))
|
||||
return description
|
||||
return None
|
||||
|
||||
|
||||
def operator_value_is_undo(value):
|
||||
if value in {None, Ellipsis}:
|
||||
return False
|
||||
|
@ -168,6 +190,10 @@ class WM_OT_context_set_boolean(Operator):
|
|||
default=True,
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def description(cls, context, props):
|
||||
return description_from_data_path(context, props.data_path, prefix=iface_("Assign"), value=props.value)
|
||||
|
||||
execute = execute_context_assign
|
||||
|
||||
|
||||
|
@ -185,6 +211,10 @@ class WM_OT_context_set_int(Operator): # same as enum
|
|||
)
|
||||
relative: rna_relative_prop
|
||||
|
||||
@classmethod
|
||||
def description(cls, context, props):
|
||||
return description_from_data_path(context, props.data_path, prefix="Assign", value=props.value)
|
||||
|
||||
execute = execute_context_assign
|
||||
|
||||
|
||||
|
@ -201,6 +231,10 @@ class WM_OT_context_scale_float(Operator):
|
|||
default=1.0,
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def description(cls, context, props):
|
||||
return description_from_data_path(context, props.data_path, prefix=iface_("Scale"), value=props.value)
|
||||
|
||||
def execute(self, context):
|
||||
data_path = self.data_path
|
||||
if context_path_validate(context, data_path) is Ellipsis:
|
||||
|
@ -235,6 +269,10 @@ class WM_OT_context_scale_int(Operator):
|
|||
options={'SKIP_SAVE'},
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def description(cls, context, props):
|
||||
return description_from_data_path(context, props.data_path, prefix=iface_("Scale"), value=props.value)
|
||||
|
||||
def execute(self, context):
|
||||
data_path = self.data_path
|
||||
if context_path_validate(context, data_path) is Ellipsis:
|
||||
|
@ -274,6 +312,10 @@ class WM_OT_context_set_float(Operator): # same as enum
|
|||
)
|
||||
relative: rna_relative_prop
|
||||
|
||||
@classmethod
|
||||
def description(cls, context, props):
|
||||
return description_from_data_path(context, props.data_path, prefix="Assign", value=props.value)
|
||||
|
||||
execute = execute_context_assign
|
||||
|
||||
|
||||
|
@ -290,6 +332,10 @@ class WM_OT_context_set_string(Operator): # same as enum
|
|||
maxlen=1024,
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def description(cls, context, props):
|
||||
return description_from_data_path(context, props.data_path, prefix=iface_("Assign"), value=props.value)
|
||||
|
||||
execute = execute_context_assign
|
||||
|
||||
|
||||
|
@ -306,6 +352,10 @@ class WM_OT_context_set_enum(Operator):
|
|||
maxlen=1024,
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def description(cls, context, props):
|
||||
return description_from_data_path(context, props.data_path, prefix=iface_("Assign"), value=props.value)
|
||||
|
||||
execute = execute_context_assign
|
||||
|
||||
|
||||
|
@ -322,6 +372,10 @@ class WM_OT_context_set_value(Operator):
|
|||
maxlen=1024,
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def description(cls, context, props):
|
||||
return description_from_data_path(context, props.data_path, prefix=iface_("Assign"), value=props.value)
|
||||
|
||||
def execute(self, context):
|
||||
data_path = self.data_path
|
||||
if context_path_validate(context, data_path) is Ellipsis:
|
||||
|
@ -339,6 +393,13 @@ class WM_OT_context_toggle(Operator):
|
|||
data_path: rna_path_prop
|
||||
module: rna_module_prop
|
||||
|
||||
@classmethod
|
||||
def description(cls, context, props):
|
||||
# Currently unsupported, it might be possible to extract this.
|
||||
if props.module:
|
||||
return None
|
||||
return description_from_data_path(context, props.data_path, prefix=iface_("Toggle"))
|
||||
|
||||
def execute(self, context):
|
||||
data_path = self.data_path
|
||||
|
||||
|
@ -375,6 +436,11 @@ class WM_OT_context_toggle_enum(Operator):
|
|||
maxlen=1024,
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def description(cls, context, props):
|
||||
value = "(%r, %r)" % (props.value_1, props.value_2)
|
||||
return description_from_data_path(context, props.data_path, prefix=iface_("Toggle"), value=value)
|
||||
|
||||
def execute(self, context):
|
||||
data_path = self.data_path
|
||||
|
||||
|
@ -406,6 +472,10 @@ class WM_OT_context_cycle_int(Operator):
|
|||
reverse: rna_reverse_prop
|
||||
wrap: rna_wrap_prop
|
||||
|
||||
@classmethod
|
||||
def description(cls, context, props):
|
||||
return description_from_data_path(context, props.data_path, prefix=iface_("Cycle"))
|
||||
|
||||
def execute(self, context):
|
||||
data_path = self.data_path
|
||||
value = context_path_validate(context, data_path)
|
||||
|
@ -442,6 +512,10 @@ class WM_OT_context_cycle_enum(Operator):
|
|||
reverse: rna_reverse_prop
|
||||
wrap: rna_wrap_prop
|
||||
|
||||
@classmethod
|
||||
def description(cls, context, props):
|
||||
return description_from_data_path(context, props.data_path, prefix=iface_("Cycle"))
|
||||
|
||||
def execute(self, context):
|
||||
data_path = self.data_path
|
||||
value = context_path_validate(context, data_path)
|
||||
|
@ -498,6 +572,10 @@ class WM_OT_context_cycle_array(Operator):
|
|||
data_path: rna_path_prop
|
||||
reverse: rna_reverse_prop
|
||||
|
||||
@classmethod
|
||||
def description(cls, context, props):
|
||||
return description_from_data_path(context, props.data_path, prefix=iface_("Cycle"))
|
||||
|
||||
def execute(self, context):
|
||||
data_path = self.data_path
|
||||
value = context_path_validate(context, data_path)
|
||||
|
@ -523,6 +601,10 @@ class WM_OT_context_menu_enum(Operator):
|
|||
|
||||
data_path: rna_path_prop
|
||||
|
||||
@classmethod
|
||||
def description(cls, context, props):
|
||||
return description_from_data_path(context, props.data_path, prefix=iface_("Menu"))
|
||||
|
||||
def execute(self, context):
|
||||
data_path = self.data_path
|
||||
value = context_path_validate(context, data_path)
|
||||
|
@ -550,6 +632,10 @@ class WM_OT_context_pie_enum(Operator):
|
|||
|
||||
data_path: rna_path_prop
|
||||
|
||||
@classmethod
|
||||
def description(cls, context, props):
|
||||
return description_from_data_path(context, props.data_path, prefix=iface_("Pie Menu"))
|
||||
|
||||
def invoke(self, context, event):
|
||||
wm = context.window_manager
|
||||
data_path = self.data_path
|
||||
|
@ -587,6 +673,10 @@ class WM_OT_operator_pie_enum(Operator):
|
|||
maxlen=1024,
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def description(cls, context, props):
|
||||
return description_from_data_path(context, props.data_path, prefix=iface_("Pie Menu"))
|
||||
|
||||
def invoke(self, context, event):
|
||||
wm = context.window_manager
|
||||
|
||||
|
|
Loading…
Reference in New Issue