import bpy
import re
from ... utility import context_copy as fn_context_copy
from bl_ui import (
properties_object,
properties_constraint,
properties_data_modifier,
properties_data_shaderfx,
properties_data_mesh,
properties_data_curve,
properties_data_metaball,
# properties_data_gpencil,
# properties_grease_pencil_common,
properties_data_armature,
properties_data_bone,
properties_data_lattice,
properties_data_empty,
properties_data_speaker,
properties_data_camera,
properties_data_light,
properties_data_lightprobe,
properties_material,
properties_material_gpencil,
)
try:
from bl_ui import properties_data_gpencil
GPENCIL_TYPE = 'GPENCIL'
GPENCIL_MODS = 'grease_pencil_modifiers'
GPENCIL_OPS_NAME = 'gpencil'
# ui module name and type have been changed in 4.3
except:
from bl_ui import properties_data_grease_pencil
GPENCIL_TYPE = 'GREASEPENCIL'
GPENCIL_MODS = 'modifiers'
GPENCIL_OPS_NAME = 'grease_pencil'
from bl_ui.properties_animviz import (
MotionPathButtonsPanel,
MotionPathButtonsPanel_display,
)
from .. Panels import cutting_material, workflow, sharp_options, bool_options, dice_options, operator_options, mesh_clean_options, object_props, special_options, opt_ins, operators
panel_node_draw = None
from ... utility import active_tool
from . mods_data import DATA_PT_modifiers, mods_dic
from . gmods_data import DATA_PT_gpencil_modifiers, gmods_dic
from . con_data import ConstraintButtonsPanel
from ... icons import get_icon_id
def options():
wm = bpy.context.window_manager
option = wm.Hard_Ops_helper_options
if 'options' not in option.panels:
option.name = 'HardOps Helper'
new = option.panels.add()
new.name = 'options'
new.tool.add().name = 'Tool'
new.object.add().name = 'Object'
new.constraint.add().name = 'Constraint'
new.modifier.add().name = 'Modifier'
data = new.data.add()
data.name = 'Data'
data.mesh.add().name = 'Mesh'
data.curve.add().name = 'Curve'
data.surface.add().name = 'Surface'
data.meta.add().name = 'Meta'
data.font.add().name = 'Font'
data.gpencil.add().name = 'GPencil'
data.greasepencil.add().name = 'GPencil'
data.armature.add().name = 'Armature'
data.lattice.add().name = 'Lattice'
data.empty.add().name = 'Empty'
data.speaker.add().name = 'Speaker'
data.camera.add().name = 'Camera'
data.light.add().name = 'Light'
data.light_probe.add().name = 'Light_Probe'
new.shaderfx.add().name = 'ShaderFX'
new.bone.add().name = 'Bone'
new.bone_constraint.add().name = 'Bone Constraint'
new.material.add().name = 'Material'
return option
def expand(pt):
if not pt:
return
context = bpy.context
wm = context.window_manager
option = options()
obj = context.active_object
# re.split(pattern, string, maxsplit=0, flags=0)
if not hasattr(pt, 'bl_options') or 'HIDE_HEADER' not in pt.bl_options:
if option.context != 'DATA':
panel = getattr(option.panels[0], option.context.lower())[0]
return getattr(panel, F'expand_{re.split(".*_PT_", pt.__name__)[1]}')
else:
panel = getattr(option.panels[0].data[0], obj.type.lower())[0]
return getattr(panel, F'expand_{re.split(".*_PT_", pt.__name__)[1]}')
else:
return True
def header_prop(pt):
if not pt:
return
if pt.__name__ == 'OBJECT_PT_display_bounds':
return bpy.context.active_object, 'show_bounds'
elif pt.__name__ == 'DATA_PT_pathanim':
return bpy.context.active_object.data, 'use_path'
elif pt.__name__ == 'DATA_PT_camera_safe_areas':
return bpy.context.active_object.data, 'show_safe_areas'
elif pt.__name__ == 'DATA_PT_camera_safe_areas_center_cut':
return bpy.context.active_object.data, 'show_safe_center'
elif pt.__name__ == 'DATA_PT_camera_background_image':
return bpy.context.active_object.data, 'show_background_images'
elif pt.__name__ == 'DATA_PT_display_passepartout':
return bpy.context.active_object.data, 'show_passepartout'
elif pt.__name__ == 'DATA_PT_normals_auto_smooth':
return bpy.context.active_object.data, 'use_auto_smooth'
elif pt.__name__ == 'DATA_PT_EEVEE_light_distance':
return bpy.context.active_object.data, 'use_custom_distance'
elif pt.__name__ == 'DATA_PT_EEVEE_shadow':
return bpy.context.active_object.data, 'use_shadow'
elif pt.__name__ == 'DATA_PT_EEVEE_shadow_contact':
return bpy.context.active_object.data, 'use_contact_shadow'
elif pt.__name__ == 'DATA_PT_lightprobe_parallax':
return bpy.context.active_object.data, 'use_custom_parallax'
elif pt.__name__ == 'BONE_PT_deform':
if active_tool().mode == 'POSE':
bone = bpy.context.active_object.data.bones[bpy.context.active_pose_bone.name]
else:
bone = bpy.context.active_object.data.bones[bpy.context.active_bone.name]
return bone, 'use_deform'
return None
def header_presets(pt):
return None
def child_panels(pt, ot):
items = []
for panel in ot.panels[options().context]:
if hasattr(panel, 'bl_parent_id') and panel.bl_parent_id == pt.__name__:
items.append(panel)
return items
def init_panels(ot):
context = bpy.context
option = options()
ot.panels = {
'OPERATORS': [
operators.HOPS_PT_operators],
'TOOL': [
special_options.HOPS_PT_specialoptions,
workflow.HOPS_PT_workflow,
sharp_options.HOPS_PT_sharp_options,
mesh_clean_options.HOPS_PT_mesh_clean_options,
#dice_options.HOPS_PT_dice_options,
operator_options.HOPS_PT_operator_options,
bool_options.HOPS_PT_bool_options,
opt_ins.HOPS_PT_opt_ins],
'OBJECT': [],
'CONSTRAINT': [],
'MODIFIER': [],
'SHADERFX': [],
'DATA': [],
# 'BONE': [],
# 'BONE_CONSTRAINT': [],
'MATERIAL': []}
obj = context.active_object
if obj:
if bpy.app.version < (2, 90, 0):
ot.panels['OBJECT'] = [
properties_object.OBJECT_PT_context_object,
properties_object.OBJECT_PT_transform,
properties_object.OBJECT_PT_delta_transform,
properties_object.OBJECT_PT_relations,
properties_object.OBJECT_PT_display,
properties_object.OBJECT_PT_display_bounds
]
else:
ot.panels['OBJECT'] = [
object_props.HOPS_PT_context_object,
properties_object.OBJECT_PT_transform,
object_props.HOPS_PT_dimensions_options,
properties_object.OBJECT_PT_delta_transform,
properties_object.OBJECT_PT_relations,
properties_object.OBJECT_PT_display,
]
ot.panels['CONSTRAINT'] = [
properties_constraint.OBJECT_PT_constraints]
# TODO: figuere out what panels are appropriete for GREASEPENCIL type in 4.3+
if obj.type in {'MESH', 'CURVE', 'SURFACE', 'FONT', 'META', 'GPENCIL', 'GREASEPECNIL', 'LATTICE'}:
if obj.type != 'GPENCIL':
ot.panels['MODIFIER'] = [properties_data_modifier.DATA_PT_modifiers]
else:
ot.panels['MODIFIER'] = [properties_data_modifier.DATA_PT_gpencil_modifiers]
ot.panels['SHADERFX'] = [properties_data_shaderfx.DATA_PT_shader_fx]
if obj.type == 'MESH':
if bpy.app.version < (2, 90, 0):
ot.panels['DATA'] = [
properties_data_mesh.DATA_PT_context_mesh,
properties_data_mesh.DATA_PT_vertex_groups,
properties_data_mesh.DATA_PT_shape_keys,
properties_data_mesh.DATA_PT_uv_texture,
properties_data_mesh.DATA_PT_vertex_colors,
properties_data_mesh.DATA_PT_face_maps,
properties_data_mesh.DATA_PT_normals,
properties_data_mesh.DATA_PT_normals_auto_smooth,
properties_data_mesh.DATA_PT_texture_space,
getattr(properties_data_mesh, 'DATA_PT_remesh', None),
properties_data_mesh.DATA_PT_customdata]
elif bpy.app.version < (4, 0, 0):
ot.panels['DATA'] = [
properties_data_mesh.DATA_PT_context_mesh,
properties_data_mesh.DATA_PT_vertex_groups,
properties_data_mesh.DATA_PT_shape_keys,
properties_data_mesh.DATA_PT_uv_texture,
properties_data_mesh.DATA_PT_vertex_colors,
properties_data_mesh.DATA_PT_face_maps,
properties_data_mesh.DATA_PT_normals,
# properties_data_mesh.DATA_PT_normals_auto_smooth,
properties_data_mesh.DATA_PT_texture_space,
getattr(properties_data_mesh, 'DATA_PT_remesh', None),
properties_data_mesh.DATA_PT_customdata]
else:
ot.panels['DATA'] = [
properties_data_mesh.DATA_PT_context_mesh,
properties_data_mesh.DATA_PT_vertex_groups,
properties_data_mesh.DATA_PT_shape_keys,
properties_data_mesh.DATA_PT_uv_texture,
properties_data_mesh.DATA_PT_vertex_colors,
# properties_data_mesh.DATA_PT_face_maps,
# properties_data_mesh.DATA_PT_normals,
# properties_data_mesh.DATA_PT_normals_auto_smooth,
properties_data_mesh.DATA_PT_texture_space,
getattr(properties_data_mesh, 'DATA_PT_remesh', None),
properties_data_mesh.DATA_PT_customdata]
elif obj.type in {'CURVE', 'SURFACE', 'FONT'}:
ot.panels['DATA'] = [
properties_data_curve.DATA_PT_context_curve,
properties_data_curve.DATA_PT_shape_curve,
properties_data_curve.DATA_PT_geometry_curve,
properties_data_curve.DATA_PT_geometry_curve_bevel,
properties_data_curve.DATA_PT_pathanim]
if hasattr(properties_data_curve, 'DATA_PT_active_spline'):
ot.panels['DATA'].append(properties_data_curve.DATA_PT_active_spline)
ot.panels['DATA'].append(properties_data_curve.DATA_PT_curve_texture_space)
if obj.type != 'FONT':
ot.panels['DATA'].append(properties_data_mesh.DATA_PT_shape_keys)
else:
ot.panels['DATA'].append(properties_data_curve.DATA_PT_font)
ot.panels['DATA'].append(properties_data_curve.DATA_PT_font_transform)
ot.panels['DATA'].append(properties_data_curve.DATA_PT_paragraph)
ot.panels['DATA'].append(properties_data_curve.DATA_PT_paragraph_alignment)
ot.panels['DATA'].append(properties_data_curve.DATA_PT_paragraph_spacing)
ot.panels['DATA'].append(properties_data_curve.DATA_PT_text_boxes)
elif obj.type == 'META':
ot.panels['DATA'] = [
properties_data_metaball.DATA_PT_context_metaball,
properties_data_metaball.DATA_PT_metaball,
properties_data_metaball.DATA_PT_metaball_element,
properties_data_metaball.DATA_PT_mball_texture_space]
elif obj.type == GPENCIL_TYPE:
if GPENCIL_TYPE == 'GPENCIL':
ot.panels['DATA'] = [
properties_data_gpencil.DATA_PT_gpencil_layers,
properties_data_gpencil.DATA_PT_gpencil_onion_skinning,
properties_data_gpencil.DATA_PT_gpencil_vertex_groups,
properties_data_gpencil.DATA_PT_gpencil_strokes,
properties_data_gpencil.DATA_PT_gpencil_display,
properties_data_gpencil.DATA_PT_gpencil_canvas]
else:
ot.panels['DATA'] = [
properties_data_grease_pencil.DATA_PT_grease_pencil_layers,
properties_data_grease_pencil.DATA_PT_grease_pencil_onion_skinning,
properties_data_mesh.DATA_PT_vertex_groups, ##
properties_data_grease_pencil.DATA_PT_grease_pencil_settings,
# properties_data_grease_pencil.DATA_PT_grease_pencil_display,
# properties_data_grease_pencil.DATA_PT_grease_pencil_canvas
]
# if context.object.data.layers.active:
# if GPENCIL_TYPE == 'GPENCIL':
# ot.panels['DATA'].extend([
# properties_data_gpencil.DATA_PT_gpencil_layer_adjustments,
# # properties_data_gpencil.DATA_PT_gpencil_layer_relations
# ])
# else:
# ot.panels['DATA'].extend([
# properties_data_grease_pencil.DATA_PT_grease_pencil_layer_adjustments,
# # properties_data_grease_pencil.DATA_PT_grease_pencil_relations
# ])
elif obj.type == 'ARMATURE':
ot.panels['DATA'] = [
properties_data_armature.DATA_PT_context_arm,
properties_data_armature.DATA_PT_skeleton,
properties_data_armature.DATA_PT_display,
properties_data_armature.DATA_PT_bone_groups,
properties_data_armature.DATA_PT_pose_library,
properties_data_armature.DATA_PT_iksolver_itasc]
ot.panels['BONE'] = [
properties_data_bone.BONE_PT_context_bone,
properties_data_bone.BONE_PT_transform,
properties_data_bone.BONE_PT_curved,
properties_data_bone.BONE_PT_relations,
properties_data_bone.BONE_PT_display,
properties_data_bone.BONE_PT_inverse_kinematics,
properties_data_bone.BONE_PT_deform]
ot.panels['BONE_CONSTAINT'] = [properties_constraint.BONE_PT_constraints]
elif obj.type == 'LATTICE':
ot.panels['DATA'] = [
properties_data_lattice.DATA_PT_context_lattice,
properties_data_lattice.DATA_PT_lattice,
properties_data_mesh.DATA_PT_vertex_groups,
properties_data_mesh.DATA_PT_shape_keys]
elif obj.type == 'EMPTY':
ot.panels['DATA'] = [properties_data_empty.DATA_PT_empty]
elif obj.type == 'SPEAKER':
ot.panels['DATA'] = [
properties_data_speaker.DATA_PT_context_speaker,
properties_data_speaker.DATA_PT_speaker,
properties_data_speaker.DATA_PT_distance,
properties_data_speaker.DATA_PT_cone]
elif obj.type == 'CAMERA':
if context.scene.render.engine in {'BLENDER_WORKBENCH', 'BLENDER_EEVEE', 'BLENDER_EEVEE_NEXT'}:
ot.panels['DATA'] = [
properties_data_camera.DATA_PT_context_camera,
properties_data_camera.DATA_PT_lens,
properties_data_camera.DATA_PT_camera_dof,
properties_data_camera.DATA_PT_camera_dof_aperture,
properties_data_camera.DATA_PT_camera,
properties_data_camera.DATA_PT_camera_stereoscopy,
properties_data_camera.DATA_PT_camera_safe_areas,
properties_data_camera.DATA_PT_camera_safe_areas_center_cut,
properties_data_camera.DATA_PT_camera_background_image,
properties_data_camera.DATA_PT_camera_display]
# properties_data_camera.DATA_PT_camera_display_composition_guides]
else:
from cycles import ui
ot.panels['DATA'] = [
properties_data_camera.DATA_PT_context_camera,
properties_data_camera.DATA_PT_lens,
# ui.CYCLES_CAMERA_PT_dof,
# ui.CYCLES_CAMERA_PT_dof_aperture,
properties_data_camera.DATA_PT_camera_stereoscopy,
properties_data_camera.DATA_PT_camera,
properties_data_camera.DATA_PT_camera_safe_areas,
properties_data_camera.DATA_PT_camera_background_image,
properties_data_camera.DATA_PT_camera_display]
# properties_data_camera.DATA_PT_camera_display_composition_guides]
elif obj.type == 'LIGHT':
if context.scene.render.engine == 'BLENDER_WORKBENCH':
ot.panels['DATA'] = [
properties_data_light.DATA_PT_context_light,
properties_data_light.DATA_PT_preview,
properties_data_light.DATA_PT_light,
properties_data_light.DATA_PT_area,
properties_data_light.DATA_PT_falloff_curve]
elif context.scene.render.engine in {'BLENDER_EEVEE', 'BLENDER_EEVEE_NEXT'}:
ot.panels['DATA'] = [
properties_data_light.DATA_PT_context_light,
properties_data_light.DATA_PT_preview,
properties_data_light.DATA_PT_EEVEE_light,
properties_data_light.DATA_PT_EEVEE_light_distance,
properties_data_light.DATA_PT_EEVEE_shadow,
properties_data_light.DATA_PT_EEVEE_shadow_contact,
properties_data_light.DATA_PT_spot]
if bpy.context.active_object.data.type == 'SUN':
ot.panels['DATA'].append(properties_data_light.DATA_PT_EEVEE_shadow_cascaded_shadow_map)
else:
from cycles import ui
ot.panels['DATA'] = [
properties_data_light.DATA_PT_context_light,
ui.CYCLES_LIGHT_PT_preview,
ui.CYCLES_LIGHT_PT_light,
ui.CYCLES_LIGHT_PT_nodes]
elif obj.type == 'LIGHT_PROBE':
ot.panels['DATA'] = [
properties_data_lightprobe.DATA_PT_context_lightprobe,
properties_data_lightprobe.DATA_PT_lightprobe,
properties_data_lightprobe.DATA_PT_lightprobe_visibility,
properties_data_lightprobe.DATA_PT_lightprobe_parallax,
properties_data_lightprobe.DATA_PT_lightprobe_display]
if obj.type in {'MESH', 'CURVE', 'SURFACE', 'META', 'FONT', GPENCIL_TYPE}:
if obj.type != GPENCIL_TYPE:
if context.scene.render.engine == 'BLENDER_WORKBENCH':
ot.panels['MATERIAL'] = [
properties_material.EEVEE_MATERIAL_PT_context_material,
properties_material.MATERIAL_PT_viewport,
cutting_material.HOPS_PT_material_hops]
elif context.scene.render.engine in {'BLENDER_EEVEE', 'BLENDER_EEVEE_NEXT'}:
ot.panels['MATERIAL'] = [
properties_material.EEVEE_MATERIAL_PT_context_material,
properties_material.MATERIAL_PT_preview,
properties_material.EEVEE_MATERIAL_PT_surface,
properties_material.EEVEE_MATERIAL_PT_volume,
properties_material.MATERIAL_PT_viewport,
properties_material.EEVEE_MATERIAL_PT_settings,
cutting_material.HOPS_PT_material_hops]
else:
from cycles import ui
ot.panels['MATERIAL'] = [
ui.CYCLES_PT_context_material,
ui.CYCLES_MATERIAL_PT_preview,
ui.CYCLES_MATERIAL_PT_surface,
ui.CYCLES_MATERIAL_PT_volume,
ui.CYCLES_MATERIAL_PT_displacement,
properties_material.MATERIAL_PT_viewport,
ui.CYCLES_MATERIAL_PT_settings,
ui.CYCLES_MATERIAL_PT_settings_surface,
ui.CYCLES_MATERIAL_PT_settings_volume,
cutting_material.HOPS_PT_material_hops]
else:
ot.panels['MATERIAL'] = [
properties_material_gpencil.MATERIAL_PT_gpencil_slots,
properties_material_gpencil.MATERIAL_PT_gpencil_preview,
properties_material_gpencil.MATERIAL_PT_gpencil_surface,
properties_material_gpencil.MATERIAL_PT_gpencil_strokecolor,
properties_material_gpencil.MATERIAL_PT_gpencil_fillcolor,
properties_material_gpencil.MATERIAL_PT_gpencil_settings]
class context_copy:
def __init__(self):
copy = fn_context_copy(bpy.context)
obj = copy['active_object']
if obj:
copy['object'] = obj
copy['curve'] = obj.data
copy[obj.type.lower()] = obj.data
copy['material'] = obj.active_material
copy['space_data'] = None
for area in copy['workspace'].screens[0].areas:
if area.type == 'PROPERTIES':
copy['space_data'] = area.spaces[0]
if len(obj.material_slots):
copy['material_slot'] = obj.material_slots[obj.active_material_index]
else:
copy['material_slot'] = None
copy['armature'] = obj.data
copy['pose_bone'] = copy['active_pose_bone']
copy['bone'] = obj.data.bones[copy['pose_bone'].name] if active_tool().mode == 'POSE' else None
copy['edit_bone'] = copy['active_bone']
copy['lightprobe'] = obj.data if obj.type == 'LIGHT_PROBE' else None
copy['meta_ball'] = obj.data if obj.type == 'META' else None
for key in copy:
setattr(self, key, copy[key])
def __new__(self):
self.__init__(self)
return self
class draw_panel:
def __init__(self, ot, pt, layout):
if not pt:
return
context = context_copy()
self.bl_space_type = 'PROPERTIES'
if (not hasattr(pt, 'poll') or pt.poll(context)) and not hasattr(pt, 'bl_parent_id'):
if options().context not in {'MODIFIER', 'CONSTRAINT', 'BONE_CONSTAINT', 'SHADERFX', 'OPERATORS'}:
self.layout = layout.box()
else:
self.layout = layout
self.layout.operator_context = 'INVOKE_DEFAULT'
option_context = {'nothing'}
if bpy.app.version > (2, 89, 0):
option_context = {'CONSTRAINT', 'BONE_CONSTAINT'}
if options().context in option_context:
# if option_context == 'CONSTRAINT':
if context.object and context.object.type == 'ARMATURE':
layout.operator_menu_enum("pose.constraint_add", "type", text="Add Bone Constraint")
ob = context.active_pose_bone
else:
layout.operator_menu_enum("object.constraint_add", "type", text="Add Object Constraint")
ob = context.object
# OBJECT_PT_constraints
# panel = bpy.types.OBJECT_PT_constraints
panel = ConstraintButtonsPanel
# 2.9 -> light probe was breaking looking at this attribute
if hasattr(ob, 'constraints'):
for con in ob.constraints:
box = layout.column()
col = box.column(align=True)
col.separator()
row = col.row(align=True)
row.prop(con, 'show_expanded', text="")
row.template_constraint_header(con)
if con.show_expanded:
row = box.row(align=True)
getattr(panel, con.type)(panel, context, box, con)
else:
self.setup_overrides(pt)
bl_options = getattr(pt, 'bl_options') if hasattr(pt, 'bl_options') else None
if (bl_options and 'HIDE_HEADER' not in bl_options) or not bl_options:
self.header(pt, context, expand(pt), header_prop(pt), header_presets(pt))
if (bl_options and 'HIDE_HEADER' in bl_options) or expand(pt):
self.panel(pt, context)
if expand(pt):
for child in child_panels(pt, ot):
if (bl_options and 'HIDE_HEADER' not in bl_options) or not bl_options:
self.layout = layout.box()
self.header(child, context, expand(child), header_prop(child), header_presets(child))
if (bl_options and 'HIDE_HEADER' in bl_options) or expand(child):
self.panel(child, context)
def header(self, pt, context, expand, prop=None, presets=None, emboss=False):
layout = self.layout
if options().context != 'DATA':
option = getattr(options().panels[0], options().context.lower())[0]
else:
obj = context.active_object
option = getattr(options().panels[0].data[0], obj.type.lower())[0]
expand_prop = F'expand_{re.split(".*_PT_", pt.__name__)[1]}'
row = layout.row(align=True)
row.alignment = 'LEFT'
row.prop(option, expand_prop, text='', icon=F'DISCLOSURE_TRI_{"DOWN" if expand else "RIGHT"}', emboss=emboss)
if prop:
row.prop(prop[0], prop[1], text='')
row.prop(option, expand_prop, toggle=True, text=pt.bl_label, emboss=emboss)
sub = row.row(align=True)
sub.scale_x = 0.70
sub.prop(option, expand_prop, toggle=True, text=' ', emboss=emboss)
def panel(self, pt, context):
if options().context not in {'MODIFIER', 'SHADERFX'} and (options().context != 'MATERIAL' or not hasattr(self, 'draw')):
if GPENCIL_TYPE == 'GREASEPENCIL' and pt == properties_data_grease_pencil.DATA_PT_grease_pencil_layers:
properties_data_grease_pencil.DATA_PT_grease_pencil_layers.draw_settings(self.layout, context.grease_pencil)
else:
pt.draw(self, context)
else:
self.draw(self, context)
def setup_overrides(self, pt):
global panel_node_draw
option = options()
obj = bpy.context.active_object
if bpy.context.scene.render.engine in {'BLENDER_WORKBENCH', 'BLENDER_EEVEE', 'BLENDER_EEVEE_NEXT'}:
from bl_ui.properties_material import panel_node_draw
else:
from cycles.ui import panel_node_draw
if option.context in {'CONSTRAINT', 'BONE_CONSTAINT'}:
panel = ConstraintButtonsPanel
def draw_constraint(context, con):
layout = self.layout
box = layout.template_constraint(con)
if box:
getattr(panel, con.type)(panel, context, box, con)
if con.type not in {'RIGID_BODY_JOINT', 'NULL'}:
box.prop(con, 'influence')
self.draw_constraint = draw_constraint
elif option.context == 'MODIFIER' and obj.type != GPENCIL_TYPE:
def profile_buttons(layout, ob, md):
if md.type == 'BEVEL' and getattr(md, 'use_custom_profile', True) == True and getattr(md, 'profile_type', 'CUSTOM') == 'CUSTOM':
row = layout.row(align=True)
op = row.operator('hops.save_bevel_profile', text='Save Profile')
op.obj, op.mod = ob.name, md.name
op = row.operator('hops.load_bevel_profile', text='Load Profile')
op.obj, op.mod = ob.name, md.name
def draw(self, context):
layout = self.layout
ob = context.object
# layout.operator_menu_enum('object.modifier_add', 'type')
row = layout.row(align=True)
if bpy.app.version < (4, 0, 0):
row.operator_menu_enum("object.modifier_add", "type")
else:
row.operator("wm.call_menu", text="Add Modifier", icon='ADD').name = "OBJECT_MT_modifier_add"
# row.operator("hops.bool_toggle_viewport", text="", icon="HIDE_OFF")
row.operator("hops.bool_toggle_viewport", text= "", icon_value=get_icon_id("Tris")).all_modifiers = True
row.operator("hops.apply_modifiers", text="", icon_value=get_icon_id("Applyall"))
row.operator("hops.open_modifiers", text="", icon="TRIA_DOWN")
row.operator("hops.collapse_modifiers", text="", icon="TRIA_UP")
if bpy.app.version < (2, 90, 0):
panel = properties_data_modifier.DATA_PT_modifiers
for md in ob.modifiers:
box = layout.template_modifier(md)
if box:
getattr(panel, md.type)(panel, box, ob, md)
profile_buttons(box, ob, md)
else:
panel = DATA_PT_modifiers
for md in ob.modifiers:
box = layout.column()
col = box.column(align=True)
col.separator()
row = col.row(align=True)
row.prop(md, 'show_expanded', text="")
if md.type not in {'CAST', 'SCREW'}:
if hasattr(md, 'object'):
if not md.object:
row.alert = True
if hasattr(md, 'target'):
if not md.target:
row.alert = True
row.label(icon=f"{mods_dic.get(md.type)}")
row.alert = False
row.prop(md, 'name', text="")
row.prop(md, 'show_on_cage', text="")
row.prop(md, 'show_in_editmode', text="")
row.prop(md, 'show_viewport', text="")
row.prop(md, 'show_render', text="")
up = row.operator("object.modifier_move_up", text="", icon="TRIA_UP")
up.modifier = md.name
down = row.operator("object.modifier_move_down", text="", icon="TRIA_DOWN")
down.modifier = md.name
remove = row.operator("object.modifier_remove", text="", icon="X")
remove.modifier = md.name
if md.show_expanded:
row = box.row()
apply_ = row.operator("object.modifier_apply", text="Apply")
# apply_.apply_as = 'DATA'
apply_.modifier = md.name
copy = row.operator("object.modifier_copy", text="Copy")
copy.modifier = md.name
getattr(panel, md.type)(panel, box, ob, md)
self.draw = draw
elif option.context == 'MODIFIER' and obj.type == GPENCIL_TYPE:
panel = properties_data_modifier.DATA_PT_gpencil_modifiers
def draw(self, context):
layout = self.layout
ob = context.object
# layout.operator_menu_enum('object.gpencil_modifier_add', 'type')
row = layout.row(align=True)
row.operator_menu_enum(f"object.{GPENCIL_OPS_NAME}_modifier_add", "type")
# row.operator("hops.bool_toggle_viewport", text="", icon="HIDE_OFF")
row.operator("hops.open_modifiers", text="", icon="TRIA_DOWN")
row.operator("hops.collapse_modifiers", text="", icon="TRIA_UP")
if bpy.app.version < (2, 90, 0):
panel = properties_data_modifier.DATA_PT_gpencil_modifiers
for md in ob.grease_pencil_modifiers:
box = layout.template_greasepencil_modifier(md)
if box:
# match enum type to our functions, avoids a lookup table.
getattr(panel, md.type)(panel, box, ob, md)
else:
panel = DATA_PT_gpencil_modifiers
for md in getattr(ob, GPENCIL_MODS):
box = layout.column()
col = box.column(align=True)
col.separator()
row = col.row(align=True)
row.prop(md, 'show_expanded', text="")
row.label(icon=f"{gmods_dic.get(md.type)}")
row.prop(md, 'name', text="")
row.prop(md, 'show_in_editmode', text="")
row.prop(md, 'show_viewport', text="")
row.prop(md, 'show_render', text="")
up = row.operator(f"object.{GPENCIL_OPS_NAME}_modifier_move_up", text="", icon="TRIA_UP")
up.modifier = md.name
down = row.operator(f"object.{GPENCIL_OPS_NAME}_modifier_move_down", text="", icon="TRIA_DOWN")
down.modifier = md.name
remove = row.operator(f"object.{GPENCIL_OPS_NAME}_modifier_remove", text="", icon="X")
remove.modifier = md.name
if md.show_expanded:
row = box.row()
apply_ = row.operator(f"object.{GPENCIL_OPS_NAME}_modifier_apply", text="Apply")
apply_.apply_as = 'DATA'
apply_.modifier = md.name
copy = row.operator(f"object.{GPENCIL_OPS_NAME}_modifier_copy", text="Copy")
copy.modifier = md.name
getattr(panel, md.type)(panel, box, ob, md)
self.draw = draw
elif option.context == 'SHADERFX':
panel = properties_data_shaderfx.DATA_PT_shader_fx
def draw(self, context):
layout = self.layout
ob = context.object
layout.operator_menu_enum('object.shaderfx_add', 'type')
for fx in ob.shader_effects:
box = layout.template_shaderfx(fx)
if box:
# match enum type to our functions, avoids a lookup table.
getattr(panel, fx.type)(panel, box, fx)
self.draw = draw
elif option.context == 'DATA' and obj and obj.type == GPENCIL_TYPE:
def draw_layers(context, layout, gpd):
row = layout.row()
col = row.column()
layer_rows = 7
col.template_list('GPENCIL_UL_layer', '', gpd, 'layers', gpd.layers, 'active_index',
rows=layer_rows, sort_reverse=True, sort_lock=True)
gpl = context.active_gpencil_layer
if gpl:
srow = col.row(align=True)
srow.prop(gpl, 'blend_mode', text='Blend')
srow = col.row(align=True)
srow.prop(gpl, 'opacity', text='Opacity', slider=True)
srow.prop(gpl, 'mask_layer', text='',
icon='MOD_MASK' if gpl.mask_layer else 'LAYER_ACTIVE')
srow = col.row(align=True)
srow.prop(gpl, 'use_solo_mode', text='Show Only On Keyframed')
col = row.column()
sub = col.column(align=True)
sub.operator('gpencil.layer_add', icon='ADD', text='')
sub.operator('gpencil.layer_remove', icon='REMOVE', text='')
if gpl:
sub.menu('GPENCIL_MT_layer_context_menu', icon='DOWNARROW_HLT', text='')
if len(gpd.layers) > 1:
col.separator()
sub = col.column(align=True)
sub.operator('gpencil.layer_move', icon='TRIA_UP', text='').type = 'UP'
sub.operator('gpencil.layer_move', icon='TRIA_DOWN', text='').type = 'DOWN'
col.separator()
sub = col.column(align=True)
sub.operator('gpencil.layer_isolate', icon='LOCKED', text='').affect_visibility = False
sub.operator('gpencil.layer_isolate', icon='RESTRICT_VIEW_ON', text='').affect_visibility = True
self.draw_layers = draw_layers
elif option.context == 'MATERIAL':
if pt.__name__ == 'CYCLES_PT_context_material':
def draw(self, context):
layout = self.layout
mat = context.material
ob = context.object
slot = context.material_slot
space = context.space_data
if ob:
is_sortable = len(ob.material_slots) > 1
rows = 1
if (is_sortable):
rows = 4
row = layout.row()
row.template_list("MATERIAL_UL_matslots", "", ob, "material_slots", ob, "active_material_index", rows=rows)
col = row.column(align=True)
col.operator("object.material_slot_add", icon='ADD', text="")
col.operator("object.material_slot_remove", icon='REMOVE', text="")
col.menu("MATERIAL_MT_context_menu", icon='DOWNARROW_HLT', text="")
if is_sortable:
col.separator()
col.operator("object.material_slot_move", icon='TRIA_UP', text="").direction = 'UP'
col.operator("object.material_slot_move", icon='TRIA_DOWN', text="").direction = 'DOWN'
if ob.mode == 'EDIT':
row = layout.row(align=True)
row.operator("object.material_slot_assign", text="Assign")
row.operator("object.material_slot_select", text="Select")
row.operator("object.material_slot_deselect", text="Deselect")
split = layout.split(factor=0.65)
if ob:
split.template_ID(ob, "active_material", new="hops.helper_add_mat")
#split.template_ID(ob, "active_material", new="material.hops_new")
row = split.row()
if slot:
row.prop(slot, "link", text="")
else:
row.label()
elif mat:
split.template_ID(space, "pin_id")
split.separator()
self.draw = draw
elif pt.__name__ == 'EEVEE_MATERIAL_PT_context_material':
def draw(self, context):
layout = self.layout
mat = context.material
ob = context.object
slot = context.material_slot
space = context.space_data
if ob:
is_sortable = len(ob.material_slots) > 1
rows = 3
if is_sortable:
rows = 5
row = layout.row()
row.template_list("MATERIAL_UL_matslots", "", ob, "material_slots", ob, "active_material_index", rows=rows)
col = row.column(align=True)
col.operator("object.material_slot_add", icon='ADD', text="")
col.operator("object.material_slot_remove", icon='REMOVE', text="")
col.separator()
col.menu("MATERIAL_MT_context_menu", icon='DOWNARROW_HLT', text="")
if is_sortable:
col.separator()
col.operator("object.material_slot_move", icon='TRIA_UP', text="").direction = 'UP'
col.operator("object.material_slot_move", icon='TRIA_DOWN', text="").direction = 'DOWN'
row = layout.row()
if ob:
row.template_ID(ob, "active_material", new="hops.helper_add_mat")
#row.template_ID(ob, "active_material", new="material.hops_new")
if slot:
icon_link = 'MESH_DATA' if slot.link == 'DATA' else 'OBJECT_DATA'
row.prop(slot, "link", icon=icon_link, icon_only=True)
if ob.mode == 'EDIT':
row = layout.row(align=True)
row.operator("object.material_slot_assign", text="Assign")
row.operator("object.material_slot_select", text="Select")
row.operator("object.material_slot_deselect", text="Deselect")
elif mat:
row.template_ID(space, "pin_id")
self.draw = draw
elif pt.__name__ == 'MATERIAL_PT_viewport':
def draw_shared(self, mat):
layout = self.layout
layout.use_property_split = True
col = layout.column()
col.prop(mat, 'diffuse_color', text='Color')
col.prop(mat, 'metallic')
col.prop(mat, 'roughness')
self.draw_shared = draw_shared
elif pt.__name__ == 'EEVEE_MATERIAL_PT_settings':
def draw_shared(self, mat):
layout = self.layout
layout.use_property_split = True
layout.prop(mat, "blend_method")
if mat.blend_method != 'OPAQUE':
layout.prop(mat, "transparent_shadow_method")
row = layout.row()
row.active = ((mat.blend_method == 'CLIP') or (mat.transparent_shadow_method == 'CLIP'))
row.prop(mat, "alpha_threshold")
if mat.blend_method not in {'OPAQUE', 'CLIP', 'HASHED'}:
layout.prop(mat, "show_transparent_back")
layout.prop(mat, "use_screen_refraction")
layout.prop(mat, "refraction_depth")
layout.prop(mat, "use_sss_translucency")
layout.prop(mat, "pass_index")
self.draw_shared = draw_shared
class HOPS_OT_helper_add_mat(bpy.types.Operator):
bl_idname = "hops.helper_add_mat"
bl_label = "Hops Helper mat add"
bl_description = """Add a new material
Shift - Glass Material per object
Alt - Emission Material per object
"""
bl_options = {'INTERNAL', 'UNDO'}
def invoke (self, contex, event):
#blank material passthrough
bpy.ops.material.hops_new('INVOKE_DEFAULT', helper_call = True)
return {'FINISHED'}