(On Hold) Rework Properties UI Editor #159

Open
Demeter Dzadik wants to merge 10 commits from new-props-ux into master

When changing the target branch, be careful to rebase the branch in your fork to match. See documentation.
2 changed files with 81 additions and 37 deletions
Showing only changes of commit 391b0914cc - Show all commits

View File

@ -1479,6 +1479,12 @@ class CloudRig_UIElement(PropertyGroup):
elif self == value: elif self == value:
# Trying to set self as parent, just ignore and move on. # Trying to set self as parent, just ignore and move on.
return return
elif value.element_type == 'OPERATOR':
# Operators are not allowed children.
return
elif self.element_type == 'ROW' == value.element_type:
# Rows cannot be parented to rows.
return
else: else:
self.parent_index = value.index self.parent_index = value.index
@ -1607,6 +1613,13 @@ class CloudRig_UIElement(PropertyGroup):
def children(self): def children(self):
return [elem for elem in self.rig.cloudrig_ui if elem.parent == self] return [elem for elem in self.rig.cloudrig_ui if elem.parent == self]
@property
def children_recursive(self):
ret = self.children
for child in self.children:
ret.extend(child.children_recursive)
return ret
@property @property
def should_draw(self): def should_draw(self):
if not self.parent: if not self.parent:
@ -1632,54 +1645,73 @@ class CloudRig_UIElement(PropertyGroup):
if not self.should_draw or not layouts: if not self.should_draw or not layouts:
return return
# We copy the layout stack so we can modify it without affecting the higher scope
layouts = layouts[:]
layout = layouts[-1] layout = layouts[-1]
if self.parent and self.parent.element_type == 'PROPERTY':
layouts.pop()
layout = layouts[-1]
remove_op_ui = layout
if self.element_type == 'PANEL': if self.element_type == 'PANEL':
# TODO: Figure out how to allow elements to be drawn in the header. # TODO: Figure out how to allow elements to be drawn in the header.
header, layout = layout.panel(idname=str(self.index) + self.display_name) header, layout = layout.panel(idname=str(self.index) + self.display_name)
header.label(text=self.display_name) header.label(text=self.display_name)
remove_op_ui = header self.draw_ui_edit_buttons(header)
layouts.append(layout)
elif self.element_type == 'LABEL': elif self.element_type == 'LABEL':
layout = remove_op_ui = layout.row() row = layout.row()
if self.display_name: if self.display_name:
layout.label(text=self.display_name) row.label(text=self.display_name)
self.draw_ui_edit_buttons(row)
elif self.element_type == 'ROW': elif self.element_type == 'ROW':
layout = remove_op_ui = layout.row() row = layout.row(align=True)
layouts.append(layout) layouts.append(row)
for child in self.children:
child.draw_ui_recursive(context, layouts)
if child != self.children[-1]:
row.separator()
layouts.pop()
# NOTE: We deliberately skip drawing edit buttons for a Row.
# A Row should be automatically deleted when it no longer has any elements.
return
elif self.element_type == 'PROPERTY': elif self.element_type == 'PROPERTY':
layout = remove_op_ui = layout.row(align=True) row = layout.row(align=True)
layouts.append(layout) self.draw_property(context, row)
self.draw_property(context, layout) for child in self.children:
if any([child.should_draw and child.element_type!='OPERATOR' for child in self.children]): if child.element_type == 'OPERATOR':
layout = layout.box() child.draw_ui_recursive(context, layouts + [row])
layouts.append(layout) for child in self.children:
box = None
if child.should_draw and child.element_type == 'PROPERTY':
if not box:
if self.parent.element_type == 'ROW':
layouts.pop()
box = layouts[-1].box()
layouts.append(box)
child.draw_ui_recursive(context, layouts)
self.draw_ui_edit_buttons(row)
return
elif self.element_type == 'OPERATOR': elif self.element_type == 'OPERATOR':
if not self.parent or self.parent.element_type != 'ROW': if not self.parent or self.parent.element_type != 'ROW':
layout = remove_op_ui = layout.row(align=True) layout = layout.row(align=True)
layouts.append(layout) layouts.append(layout)
self.draw_operator(context, layout) self.draw_operator(context, layout)
self.draw_ui_edit_buttons(layout)
if layout: if layout:
for child in self.children: for child in self.children:
child.draw_ui_recursive(context, layouts) child.draw_ui_recursive(context, layouts)
if self.element_type == 'ROW' and child != self.children[-1]:
layouts[-1].separator()
if self.rig.cloudrig.ui_edit_mode: def draw_ui_edit_buttons(self, layout):
remove_op_ui.operator( if not self.rig.cloudrig.ui_edit_mode:
'object.cloudrig_ui_element_edit', text="", icon='GREASEPENCIL' return
).element_index = self.index
remove_op_ui.operator(
'object.cloudrig_ui_element_remove', text="", icon='X'
).element_index = self.index
layout.operator(
'object.cloudrig_ui_element_edit', text="", icon='GREASEPENCIL'
).element_index = self.index
layout.operator(
'object.cloudrig_ui_element_remove', text="", icon='X'
).element_index = self.index
def draw_property(self, context, layout): def draw_property(self, context, layout):
prop_owner, prop_value = self.prop_owner, self.prop_value prop_owner, prop_value = self.prop_owner, self.prop_value

View File

@ -38,6 +38,15 @@ def draw_parent_picking(context, layout, ui_element, operator):
parent_row.prop_search( parent_row.prop_search(
operator, 'parent_element', context.scene, 'cloudrig_ui_parent_selector' operator, 'parent_element', context.scene, 'cloudrig_ui_parent_selector'
) )
rig = find_cloudrig(context)
if operator.parent_element and operator.parent_element in context.scene.cloudrig_ui_parent_selector:
parent_ui = rig.cloudrig_ui[context.scene.cloudrig_ui_parent_selector[operator.parent_element].index]
if parent_ui and parent_ui.element_type == 'PROPERTY':
value = parent_ui.prop_value
value_type, is_array = rna_idprop_value_item_type(value)
if value_type in {bool, int}:
layout.prop(ui_element, 'parent_values')
if context.scene.cloudrig_ui_parent_selector: if context.scene.cloudrig_ui_parent_selector:
parent_row.prop(operator, 'create_new_ui', text="", icon='ADD') parent_row.prop(operator, 'create_new_ui', text="", icon='ADD')
@ -375,6 +384,7 @@ class CLOUDRIG_OT_ui_element_edit(UIElementAddMixin, Operator):
element_type: StringProperty() element_type: StringProperty()
def invoke(self, context, _event): def invoke(self, context, _event):
update_parent_selector(context)
rig = find_cloudrig(context) rig = find_cloudrig(context)
self.temp_element = get_new_ui_element(context) self.temp_element = get_new_ui_element(context)
@ -427,7 +437,7 @@ class CLOUDRIG_OT_ui_element_edit(UIElementAddMixin, Operator):
return {'FINISHED'} return {'FINISHED'}
class CLOUDRIG_OT_ui_element_remove(Operator): class CLOUDRIG_OT_ui_element_remove(Operator):
"""Remove this UI element.\n\n""" """Ctrl: Do not remove children""" """Remove this UI element.\n\nCtrl: Do not remove children"""
bl_idname = "object.cloudrig_ui_element_remove" bl_idname = "object.cloudrig_ui_element_remove"
bl_label = "Remove UI Element" bl_label = "Remove UI Element"
@ -453,19 +463,21 @@ class CLOUDRIG_OT_ui_element_remove(Operator):
element_to_remove = rig.cloudrig_ui[index] element_to_remove = rig.cloudrig_ui[index]
fallback_parent = element_to_remove.parent fallback_parent = element_to_remove.parent
indicies_to_remove = []
if self.recursive: if self.recursive:
for child in element_to_remove.children: for child in element_to_remove.children_recursive:
self.remove_element(rig, child.index) indicies_to_remove.append(child.index)
else: else:
for child in element_to_remove.children: for child in element_to_remove.children:
child.parent = fallback_parent child.parent = fallback_parent
indicies_to_remove.append(element_to_remove.index)
for element in rig.cloudrig_ui: for i in reversed(sorted(indicies_to_remove)):
if element.parent_index > index: rig.cloudrig_ui.remove(i)
element.parent_index -= 1 for elem in rig.cloudrig_ui:
if elem.parent_index > i:
rig.cloudrig_ui.remove(index) elem.parent_index -= 1
def supports_custom_props(prop_owner): def supports_custom_props(prop_owner):
return isinstance(prop_owner, ID) or type(prop_owner) in {PoseBone, BoneCollection} return isinstance(prop_owner, ID) or type(prop_owner) in {PoseBone, BoneCollection}