def register(): for cls in classes: register_class(cls) for mod in Modifier.bl_rna.properties['type'].enum_items: modifiers.append(mod) for mod in GpencilModifier.bl_rna.properties['type'].enum_items: modifiers.append(mod) DATA_PT_modifiers.prepend(draw_favorite_modifiers) DATA_PT_gpencil_modifiers.prepend(draw_favorite_modifiers)
def LATTICE(layout, ob, md): context = bpy.context gizmo_ob = get_gizmo_object() if gizmo_ob: lat = gizmo_ob.data row = layout.row() row.enabled = not gizmo_ob.hide_viewport depress = gizmo_ob.mode == 'EDIT' if context.area.type == 'PROPERTIES': row.operator("object.lattice_toggle_editmode_prop_editor", text="Edit Lattice", depress=depress) else: row.operator("object.lattice_toggle_editmode", text="Edit Lattice", depress=depress) layout.separator() row = layout.row() sub = row.column(align=True) sub.prop(lat, "points_u") sub.prop(lat, "points_v") sub.prop(lat, "points_w") sub = row.column(align=True) sub.prop(lat, "interpolation_type_u", text="") sub.prop(lat, "interpolation_type_v", text="") sub.prop(lat, "interpolation_type_w", text="") layout.separator() layout.prop(lat, "use_outside", text="Outside Only") layout.separator() mp = DATA_PT_modifiers(context) mp.LATTICE(layout, ob, md)
def BOOLEAN(layout, ob, md): context = bpy.context mp = DATA_PT_modifiers(context) mp.BOOLEAN(layout, ob, md) if not md.object: return layout.separator() layout.label(text="Boolean Object:") layout.separator() is_hidden = md.object.hide_get() depress = is_hidden icon = 'HIDE_ON' if is_hidden else 'HIDE_OFF' layout.operator("object.ml_toggle_visibility_on_view_layer", text="Hide", icon=icon, depress=depress).object_name = md.object.name layout.separator() layout.prop(md.object, "display_type") layout.separator() op = layout.operator("object.ml_smooth_shading_set", text="Shade Smooth") op.object_name = md.object.name op.shade_smooth = True op = layout.operator("object.ml_smooth_shading_set", text="Shade Flat") op.object_name = md.object.name op.shade_smooth = False layout.separator() layout.operator("object.ml_select", text="Select").object_name = md.object.name
def draw(self, context): layout = self.layout col = layout.column(align=True) object = bpy.context.active_object if not checkSel(): colrow = col.row(align=True) colrow.alignment = "CENTER" colrow.label("No active object", icon="INFO") return layout.operator_menu_enum("object.modifier_add", "type") modifiers_panel = DATA_PT_modifiers(bpy.context) for modifier in object.modifiers: box = layout.template_modifier(modifier) if box: getattr(modifiers_panel, modifier.type)(box, object, modifier)
def draw_modifier_tab(self, layout): row = layout.row() object = bpy.context.active_object if object is None: row.alignment = "CENTER" row.label("No active object", icon="INFO") return row.operator_menu_enum("object.modifier_add", "type") row.operator("object.make_links_data", text="Copy Modifiers From").type = "MODIFIERS" modifiers_panel = DATA_PT_modifiers(bpy.context) for modifier in object.modifiers: box = layout.template_modifier(modifier) if box: getattr(modifiers_panel, modifier.type)(box, object, modifier)
def draw_modifier_tab(self, layout): col = layout.column(align=True) object = bpy.context.active_object if object is None: colrow = col.row(align=True) colrow.alignment = "CENTER" colrow.label(text="No active object", icon="INFO") return colrow = col.row(align=True) colrow.operator_menu_enum("object.modifier_add", "type") colrow.operator("object.make_links_data", text="Copy Modifiers").type = "MODIFIERS" colrow.operator("hops.open_modifiers", text="", icon="TRIA_DOWN") colrow.operator("hops.collapse_modifiers", text="", icon="TRIA_UP") modifiers_panel = DATA_PT_modifiers(bpy.context) for modifier in object.modifiers: box = layout.template_modifier(modifier) if box: getattr(modifiers_panel, modifier.type)(box, object, modifier)
def modifiers_ui_with_list(context, layout, num_of_rows=False, use_in_popup=False): ob = get_ml_active_object() active_mod_index = ob.ml_modifier_active_index prefs = bpy.context.preferences.addons["modifier_list"].preferences pcoll = get_icons() if ob.modifiers: # This makes operators work without passing the active modifier # to them manually as an argument. layout.context_pointer_set("modifier", ob.modifiers[ob.ml_modifier_active_index]) # === Favourite modifiers === col = layout.column(align=True) _favourite_modifier_buttons(col) # === Modifier search and menu === col = layout.column() _modifier_search_and_menu(col, ob) # === Modifier list === layout.template_list("OBJECT_UL_ml_modifier_list", "", ob, "modifiers", ob, "ml_modifier_active_index", rows=num_of_rows, sort_reverse=prefs.reverse_list) # When sub.scale_x is 1.5 and the area/region is narrow, the buttons # don't align properly, so some manual work is needed. if use_in_popup: align_button_groups = prefs.popup_width <= 250 elif context.area.type == 'VIEW_3D': align_button_groups = context.region.width <= 283 else: align_button_groups = context.area.width <= 291 row = layout.row(align=align_button_groups) # === Modifier batch operators and modifier extras menu === sub = row.row(align=True) sub.scale_x = 3 if align_button_groups else 1.34 _batch_operators(sub, pcoll) sub_sub = sub.row(align=True) sub_sub.scale_x = 0.65 if align_button_groups else 0.85 _modifier_extras_button(context, sub_sub, use_in_popup=use_in_popup) # === List manipulation === sub = row.row(align=True) sub.scale_x = 3 if align_button_groups else 1.5 if not align_button_groups: sub.alignment = 'RIGHT' move_up_icon = 'TRIA_DOWN' if prefs.reverse_list else 'TRIA_UP' move_down_icon = 'TRIA_UP' if prefs.reverse_list else 'TRIA_DOWN' if not prefs.reverse_list: sub.operator("object.ml_modifier_move_up", icon=move_up_icon, text="") sub.operator("object.ml_modifier_move_down", icon=move_down_icon, text="") else: sub.operator("object.ml_modifier_move_down", icon=move_down_icon, text="") sub.operator("object.ml_modifier_move_up", icon=move_up_icon, text="") sub.operator("object.ml_modifier_remove", icon='REMOVE', text="") # === Modifier settings === if not ob.modifiers: return active_mod = ob.modifiers[active_mod_index] all_mods = modifier_categories.ALL_MODIFIERS_NAMES_ICONS_TYPES active_mod_icon = next(icon for _, icon, mod in all_mods if mod == active_mod.type) is_active_mod_local = is_modifier_local(ob, active_mod) col = layout.column(align=True) # === General settings === box = col.box() if not prefs.hide_general_settings_region: row = box.row() sub = row.row() sub.alert = is_modifier_disabled(active_mod) sub.label(text="", icon=active_mod_icon) sub.prop(active_mod, "name", text="") _modifier_visibility_buttons(active_mod, row, pcoll) row = box.row() sub = row.row(align=True) if active_mod.type == 'PARTICLE_SYSTEM': ps = active_mod.particle_system if ps.settings.render_type in {'COLLECTION', 'OBJECT'}: sub.operator("object.duplicates_make_real", text="Convert") elif ps.settings.render_type == 'PATH': sub.operator("object.modifier_convert", text="Convert").modifier = active_mod.name else: sub.scale_x = 5 icon = pcoll['APPLY_MODIFIER'] sub.operator("object.ml_modifier_apply", text="", icon_value=icon.icon_id) if active_mod.type in modifier_categories.SUPPORT_APPLY_AS_SHAPE_KEY: icon = pcoll['APPLY_MODIFIER_AS_SHAPEKEY'] sub.operator("object.ml_modifier_apply_as_shapekey", text="", icon_value=icon.icon_id) icon = pcoll['SAVE_MODIFIER_AS_SHAPEKEY'] sub.operator("object.ml_modifier_save_as_shapekey", text="", icon_value=icon.icon_id) if active_mod.type not in modifier_categories.DONT_SUPPORT_COPY: sub.operator("object.ml_modifier_copy", text="", icon='DUPLICATE').modifier = active_mod.name # === Gizmo object settings === if ob.type in {'CURVE', 'FONT', 'LATTICE', 'MESH', 'SURFACE'}: if (active_mod.type in modifier_categories.HAVE_GIZMO_PROPERTY or active_mod.type == 'UV_PROJECT'): gizmo_ob = get_gizmo_object_from_modifier(active_mod) sub = row.row(align=True) sub.alignment = 'RIGHT' sub.enabled = is_active_mod_local if not gizmo_ob: sub_sub = sub.row() sub_sub.scale_x = 4 icon = pcoll['ADD_GIZMO'] sub_sub.operator( "object.ml_gizmo_object_add", text="", icon_value=icon.icon_id).modifier = active_mod.name else: sub_sub = sub.row(align=True) sub_sub.scale_x = 1.2 depress = not gizmo_ob.hide_viewport sub_sub.operator("object.ml_gizmo_object_toggle_visibility", text="", icon='EMPTY_ARROWS', depress=depress) sub.popover("OBJECT_PT_ml_gizmo_object_settings", text="") # === Modifier specific settings === box = col.box() # Disable layout for linked modifiers here manually so in custom # layouts all operators/settings are greyed out. box.enabled = is_active_mod_local # A column is needed here to keep the layout more compact, # because in a box separators give an unnecessarily big space. col = box.column() # Some modifiers have an improved layout with additional settings. have_custom_layout = ('BOOLEAN', 'LATTICE') if active_mod.type in have_custom_layout: getattr(ml_modifier_layouts, active_mod.type)(col, ob, active_mod) else: mp = DATA_PT_modifiers(context) getattr(mp, active_mod.type)(col, ob, active_mod)
def modifiers_ui(context, layout, num_of_rows=False, use_in_popup=False): ml_props = bpy.context.window_manager.modifier_list ob = get_ml_active_object() active_mod_index = ob.ml_modifier_active_index prefs = bpy.context.preferences.addons["modifier_list"].preferences pcoll = icons.preview_collections["main"] # Ensure the active index is never out of range. That can happen if # a modifier gets deleted without using Modifier List, e.g. when # removing a Cloth modifier from within the physics panel. if ob.modifiers and active_mod_index > len(ob.modifiers) - 1: layout.label( text="The active modifier index has gotten out of range...") layout.operator("object.ml_reset_modifier_active_index") return if ob.modifiers: # This makes operators work without passing the active modifier # to them manually as an argument. layout.context_pointer_set("modifier", ob.modifiers[ob.ml_modifier_active_index]) # === Favourite modifiers === col = layout.column(align=True) # Check if an item or the next item in # favourite_modifiers_names_icons_types has a value and add rows # and buttons accordingly (2 or 3 buttons per row). fav_names_icons_types_iter = favourite_modifiers_names_icons_types() place_three_per_row = prefs.favourites_per_row == '3' for name, icon, mod in fav_names_icons_types_iter: next_mod_1 = next(fav_names_icons_types_iter) if place_three_per_row: next_mod_2 = next(fav_names_icons_types_iter) if name or next_mod_1[0] or (place_three_per_row and next_mod_2[0]): row = col.row(align=True) if name: icon = icon if prefs.use_icons_in_favourites else 'NONE' row.operator("object.ml_modifier_add", text=name, icon=icon).modifier_type = mod else: row.label(text="") if next_mod_1[0]: icon = next_mod_1[ 1] if prefs.use_icons_in_favourites else 'NONE' row.operator("object.ml_modifier_add", text=next_mod_1[0], icon=icon).modifier_type = next_mod_1[2] else: row.label(text="") if place_three_per_row: if next_mod_2[0]: icon = next_mod_2[ 1] if prefs.use_icons_in_favourites else 'NONE' row.operator("object.ml_modifier_add", text=next_mod_2[0], icon=icon).modifier_type = next_mod_2[2] else: row.label(text="") # === Modifier search and menu === col = layout.column() row = col.split(factor=0.59) row.enabled = ob.library is None or ob.override_library is not None if ob.type == 'MESH': row.prop_search(ml_props, "modifier_to_add_from_search", ml_props, "mesh_modifiers", text="", icon='MODIFIER') row.menu("MESH_MT_ml_add_modifier_menu") elif ob.type in {'CURVE', 'SURFACE', 'FONT'}: row.prop_search(ml_props, "modifier_to_add_from_search", ml_props, "curve_modifiers", text="", icon='MODIFIER') row.menu("CURVE_MT_ml_add_modifier_menu") elif ob.type == 'LATTICE': row.prop_search(ml_props, "modifier_to_add_from_search", ml_props, "lattice_modifiers", text="", icon='MODIFIER') row.menu("LATTICE_MT_ml_add_modifier_menu") elif ob.type == 'POINTCLOUD': row.prop_search(ml_props, "modifier_to_add_from_search", ml_props, "pointcloud_modifiers", text="", icon='MODIFIER') row.menu("POINTCLOUD_MT_ml_add_modifier_menu") elif ob.type == 'VOLUME': row.prop_search(ml_props, "modifier_to_add_from_search", ml_props, "volume_modifiers", text="", icon='MODIFIER') row.menu("VOLUME_MT_ml_add_modifier_menu") # === Modifier list === # Get the list index from # ml_props.ml_active_object_modifier_active_index instead of # ob.ml_modifier_active_index because library overrides prevent # editing that value directly. # ml_props.ml_active_object_modifier_active_index has get and set # methods for accessing ob.ml_modifier_active_index indirectly. layout.template_list("OBJECT_UL_ml_modifier_list", "", ob, "modifiers", ml_props, "active_object_modifier_active_index", rows=num_of_rows, sort_reverse=prefs.reverse_list) # When sub.scale_x is 1.5 and the area/region is narrow, the buttons # don't align properly, so some manual work is needed. if use_in_popup: align_button_groups = prefs.popup_width <= 250 elif context.area.type == 'VIEW_3D': align_button_groups = context.region.width <= 283 else: align_button_groups = context.area.width <= 291 row = layout.row(align=align_button_groups) # === Modifier batch operators === sub = row.row(align=True) sub.scale_x = 3 if align_button_groups else 1.34 icon = pcoll['TOGGLE_ALL_MODIFIERS_VISIBILITY'] sub.operator("view3d.ml_toggle_all_modifiers", icon_value=icon.icon_id, text="") icon = pcoll['APPLY_ALL_MODIFIERS'] sub.operator("view3d.ml_apply_all_modifiers", icon_value=icon.icon_id, text="") icon = pcoll['DELETE_ALL_MODIFIERS'] sub.operator("view3d.ml_remove_all_modifiers", icon_value=icon.icon_id, text="") sub_sub = sub.row(align=True) sub_sub.scale_x = 0.65 if align_button_groups else 0.85 sub_sub.popover("OBJECT_PT_ml_modifier_extras", icon='DOWNARROW_HLT', text="") # === List manipulation === sub = row.row(align=True) sub.scale_x = 3 if align_button_groups else 1.5 if not align_button_groups: sub.alignment = 'RIGHT' move_up_icon = 'TRIA_DOWN' if prefs.reverse_list else 'TRIA_UP' move_down_icon = 'TRIA_UP' if prefs.reverse_list else 'TRIA_DOWN' if not prefs.reverse_list: sub.operator("object.ml_modifier_move_up", icon=move_up_icon, text="") sub.operator("object.ml_modifier_move_down", icon=move_down_icon, text="") else: sub.operator("object.ml_modifier_move_down", icon=move_down_icon, text="") sub.operator("object.ml_modifier_move_up", icon=move_up_icon, text="") sub.operator("object.ml_modifier_remove", icon='REMOVE', text="") # === Modifier settings === if not ob.modifiers: return active_mod = ob.modifiers[active_mod_index] all_mods = modifier_categories.ALL_MODIFIERS_NAMES_ICONS_TYPES active_mod_icon = next(icon for _, icon, mod in all_mods if mod == active_mod.type) is_active_mod_local = is_modifier_local(ob, active_mod) col = layout.column(align=True) # === General settings === box = col.box() if not prefs.hide_general_settings_region: row = box.row() sub = row.row() sub.alert = is_modifier_disabled(active_mod) sub.label(text="", icon=active_mod_icon) sub.prop(active_mod, "name", text="") modifier_visibility_buttons(active_mod, row) row = box.row() sub = row.row(align=True) if active_mod.type == 'PARTICLE_SYSTEM': ps = active_mod.particle_system if ps.settings.render_type in {'COLLECTION', 'OBJECT'}: sub.operator("object.duplicates_make_real", text="Convert") elif ps.settings.render_type == 'PATH': sub.operator("object.modifier_convert", text="Convert").modifier = active_mod.name else: sub.scale_x = 5 icon = pcoll['APPLY_MODIFIER'] sub.operator("object.ml_modifier_apply", text="", icon_value=icon.icon_id) if active_mod.type in modifier_categories.SUPPORT_APPLY_AS_SHAPE_KEY: icon = pcoll['APPLY_MODIFIER_AS_SHAPEKEY'] sub.operator("object.ml_modifier_apply_as_shapekey", text="", icon_value=icon.icon_id) if BLENDER_VERSION_MAJOR_POINT_MINOR >= 2.90: icon = pcoll['SAVE_MODIFIER_AS_SHAPEKEY'] sub.operator("object.ml_modifier_save_as_shapekey", text="", icon_value=icon.icon_id) if active_mod.type not in modifier_categories.DONT_SUPPORT_COPY: sub.operator("object.ml_modifier_copy", text="", icon='DUPLICATE').modifier = active_mod.name # === Gizmo object settings === if ob.type in {'CURVE', 'FONT', 'LATTICE', 'MESH', 'SURFACE'}: if (active_mod.type in modifier_categories.HAVE_GIZMO_PROPERTY or active_mod.type == 'UV_PROJECT'): gizmo_ob = get_gizmo_object_from_modifier(active_mod) sub = row.row(align=True) sub.alignment = 'RIGHT' sub.enabled = is_active_mod_local if not gizmo_ob: sub_sub = sub.row() sub_sub.scale_x = 4 icon = pcoll['ADD_GIZMO'] sub_sub.operator( "object.ml_gizmo_object_add", text="", icon_value=icon.icon_id).modifier = active_mod.name else: sub_sub = sub.row(align=True) sub_sub.scale_x = 1.2 depress = not gizmo_ob.hide_viewport sub_sub.operator("object.ml_gizmo_object_toggle_visibility", text="", icon='EMPTY_ARROWS', depress=depress) sub.popover("OBJECT_PT_ml_gizmo_object_settings", text="") # === Modifier specific settings === box = col.box() # Disable layout for linked modifiers here manually so in custom # layouts all operators/settings are greyed out. box.enabled = is_active_mod_local # A column is needed here to keep the layout more compact, # because in a box separators give an unnecessarily big space. col = box.column() # Some modifiers have an improved layout with additional settings. have_custom_layout = ('BOOLEAN', 'LATTICE') if active_mod.type in have_custom_layout: getattr(ml_modifier_layouts, active_mod.type)(col, ob, active_mod) else: mp = DATA_PT_modifiers(context) getattr(mp, active_mod.type)(col, ob, active_mod)
def draw(self, context): mp = DATA_PT_modifiers(context) ob = context.object layout = self.layout row = layout.row() # if context.active_object is None: # row.alignment = 'CENTER' # row.label("No Object!", icon = 'INFO') # return ################################################################ col = layout.column(align=True) # col.label(text="Hello World!!") view = context.space_data scene = context.scene obj = context.object obj_type = obj.type ################################################################ ################################################################ ### Amaranth Toolset のフレームオンシェード(displayWireframe) row = col.row(align=True) row.operator("object.amth_wire_toggle", icon="MOD_WIREFRAME", text="Wire").clear = False row.operator("object.amth_wire_toggle", icon="X", text="Clear").clear = True row = col.row(align=True) row.operator("mesh.presel", text="PreSel", icon="LOOPSEL") row.operator("presel.stop", text="PreSel", icon="X") ################################################################ ################################################################ ### その他いろいろ col = layout.column(align=True) layout.separator() row = layout.row() ### 透視/並行投影 row.operator("view3d.view_persportho", icon="OUTLINER_OB_CAMERA", text="") ### ワールドの背景 row.prop(view, "show_world", text="World.", icon="WORLD") ### レンズ view = context.space_data row.active = bool(view.region_3d.view_perspective != 'CAMERA' or view.region_quadviews) row.prop(view, "lens", icon="SCENE") ### 描画タイプ obj = context.object row = layout.row() row.prop(obj, "draw_type", text="", icon="TEXTURE_SHADED") # col.prop(view, "show_only_render") row = layout.row() ### X-Ray row.prop(obj, "show_x_ray", text="X-Ray.", icon="VISIBLE_IPO_ON") ### バックフェースカーリング row.prop(view, "show_backface_culling", text="B.cul", icon="FACESEL") ### ワイヤーフレーム表示 row.prop(obj, "show_wire", text="Wire.", icon="OUTLINER_OB_LATTICE") ### AO rd = scene.render ### AO col = layout.column(align=True) fx_settings = view.fx_settings # if fx_settings.use_ssao: # ssao_settings = fx_settings.ssao # subcol = col.column(align=True) # subcol.prop(ssao_settings, "factor") # subcol.prop(ssao_settings, "distance_max") # subcol.prop(ssao_settings, "attenuation") # subcol.prop(ssao_settings, "samples") # subcol.prop(ssao_settings, "color") # # if view.viewport_shade not in {'BOUNDBOX', 'WIREFRAME'}: row = col.row(align=True) row.prop(fx_settings, "use_ssao", text="AO", icon="PINNED") ### Matcap row.prop(view, "use_matcap", icon="COLOR_RED") ### 被写界深度 row = col.row(align=True) if view.viewport_shade not in {'BOUNDBOX', 'WIREFRAME'}: row.active = view.region_3d.view_perspective == 'CAMERA' row.prop(fx_settings, "use_dof", text="dof", icon="FORCE_HARMONIC") ### Matcap アイコン if view.use_matcap: row = col.row(align=True) row.template_icon_view(view, "matcap_icon")
def BOOLEAN(layout, ob, md): context = bpy.context mp = DATA_PT_modifiers(context) mp.BOOLEAN(layout, ob, md) if BLENDER_VERSION_MAJOR_POINT_MINOR < 2.91: if not md.object: return else: if ((md.operand_type == 'OBJECT' and not md.object) or (md.operand_type == 'COLLECTION' and not md.collection)): return layout.separator() # Option to use a collection as the operand was added in # Blender 2.91. if BLENDER_VERSION_MAJOR_POINT_MINOR < 2.91 or md.operand_type == 'OBJECT': layout.label(text="Boolean Object:") layout.separator() is_hidden = md.object.hide_get() depress = is_hidden icon = 'HIDE_ON' if is_hidden else 'HIDE_OFF' layout.operator("object.ml_toggle_visibility_on_view_layer", text="Hide", icon=icon, depress=depress).object_name = md.object.name layout.separator() layout.prop(md.object, "display_type") layout.separator() op = layout.operator("object.ml_smooth_shading_set", text="Shade Smooth") op.object_name = md.object.name op.shade_smooth = True op = layout.operator("object.ml_smooth_shading_set", text="Shade Flat") op.object_name = md.object.name op.shade_smooth = False layout.separator() layout.operator("object.ml_select", text="Select").object_name = md.object.name elif md.operand_type == 'COLLECTION': layout.label(text="Boolean Collection:") layout.separator() layer_collection = context.view_layer.layer_collection.children[ md.collection.name] layout.prop(layer_collection, "hide_viewport", text="Hide") layout.separator() layout.label(text="Set Objects To Display As:") row = layout.row(align=True) op = row.operator("collection.objects_display_type_set", text="Textured") op.collection_name = md.collection.name op.display_type = 'TEXTURED' op = row.operator("collection.objects_display_type_set", text="Solid") op.collection_name = md.collection.name op.display_type = 'SOLID' op = row.operator("collection.objects_display_type_set", text="Wire") op.collection_name = md.collection.name op.display_type = 'WIRE' op = row.operator("collection.objects_display_type_set", text="Bounds") op.collection_name = md.collection.name op.display_type = 'BOUNDS' layout.separator() op = layout.operator("collection.ml_objects_smooth_shading_set", text="Shade Objects Smooth") op.collection_name = md.collection.name op.shade_smooth = True op = layout.operator("collection.ml_objects_smooth_shading_set", text="Shade Objects Flat") op.collection_name = md.collection.name op.shade_smooth = False layout.separator() op = layout.operator("collection.ml_select_objects", text="Select Objects") op.collection_name = md.collection.name
def modifiers_ui(context, layout, num_of_rows=False, use_in_popup=False): ob = context.object if context.area.type == 'PROPERTIES' else get_ml_active_object( ) prefs = bpy.context.preferences.addons["modifier_list"].preferences pcoll = icons.preview_collections["main"] # === Favourite modifiers === col = layout.column(align=True) # Check if an item or the next item in # favourite_modifiers_names_icons_types has a value and add rows # and buttons accordingly (2 or 3 buttons per row). fav_names_icons_types_iter = modifier_categories.favourite_modifiers_names_icons_types( ) place_three_per_row = prefs.favourites_per_row == '3' for name, icon, mod in fav_names_icons_types_iter: next_mod_1 = next(fav_names_icons_types_iter) if place_three_per_row: next_mod_2 = next(fav_names_icons_types_iter) if name or next_mod_1[0] or (place_three_per_row and next_mod_2[0]): row = col.row(align=True) if name: icon = icon if prefs.use_icons_in_favourites else 'NONE' row.operator("object.ml_modifier_add", text=name, icon=icon).modifier_type = mod else: row.label(text="") if next_mod_1[0]: icon = next_mod_1[ 1] if prefs.use_icons_in_favourites else 'NONE' row.operator("object.ml_modifier_add", text=next_mod_1[0], icon=icon).modifier_type = next_mod_1[2] else: row.label(text="") if place_three_per_row: if next_mod_2[0]: icon = next_mod_2[ 1] if prefs.use_icons_in_favourites else 'NONE' row.operator("object.ml_modifier_add", text=next_mod_2[0], icon=icon).modifier_type = next_mod_2[2] else: row.label(text="") # === Modifier search and menu === col = layout.column() row = col.split(factor=0.59) wm = bpy.context.window_manager if ob.type == 'MESH': row.prop_search(wm, "ml_mod_to_add", wm, "ml_mesh_modifiers", text="", icon='MODIFIER') row.menu("MESH_MT_ml_add_modifier_menu") elif ob.type in {'CURVE', 'SURFACE', 'FONT'}: row.prop_search(wm, "ml_mod_to_add", wm, "ml_curve_modifiers", text="", icon='MODIFIER') row.menu("CURVE_MT_ml_add_modifier_menu") elif ob.type == 'LATTICE': row.prop_search(wm, "ml_mod_to_add", wm, "ml_lattice_modifiers", text="", icon='MODIFIER') row.menu("LATTICE_MT_ml_add_modifier_menu") # === Modifier list === global properties_list_info properties_list_info.clear() layout.template_list( "OBJECT_UL_modifier_list", "", ob, "modifiers", ob, "ml_modifier_active_index", rows=num_of_rows, sort_reverse=prefs.reverse_list, ) # When sub.scale_x is 1.5 and the area/region is narrow, the buttons # don't align properly, so some manual work is needed. if use_in_popup: align_button_groups = prefs.popup_width <= 278 elif context.area.type == 'VIEW_3D': align_button_groups = context.region.width <= 308 else: align_button_groups = context.area.width <= 308 sub_scale = 3 if align_button_groups else 1.5 row = layout.row(align=align_button_groups) # === Modifier batch operators === sub = row.row(align=True) # Note: In 2.79, this is what scale 2.0 looks like. Here 2.0 causes list ordering # buttons to get tiny. 2.8 Bug? sub.scale_x = sub_scale icon = pcoll['TOGGLE_ALL_MODIFIERS_VISIBILITY'] sub.operator("object.ml_toggle_all_modifiers", icon_value=icon.icon_id, text="") icon = pcoll['APPLY_ALL_MODIFIERS'] sub.operator("object.ml_apply_all_modifiers", icon_value=icon.icon_id, text="") icon = pcoll['DELETE_ALL_MODIFIERS'] sub.operator("object.ml_remove_all_modifiers", icon_value=icon.icon_id, text="") # === List manipulation === sub = row.row(align=True) # Note: In 2.79, this is what scale 2.0 looks like. Here 2.0 causes list ordering # buttons to get tiny. 2.8 Bug? sub.scale_x = sub_scale if not align_button_groups: sub.alignment = 'RIGHT' move_up_icon = 'TRIA_DOWN' if prefs.reverse_list else 'TRIA_UP' move_down_icon = 'TRIA_UP' if prefs.reverse_list else 'TRIA_DOWN' if not prefs.reverse_list: sub.operator("object.ml_modifier_move_up", icon=move_up_icon, text="") sub.operator("object.ml_modifier_move_down", icon=move_down_icon, text="") else: sub.operator("object.ml_modifier_move_down", icon=move_down_icon, text="") sub.operator("object.ml_modifier_move_up", icon=move_up_icon, text="") sub.operator("object.ml_modifier_remove", icon='REMOVE', text="") # === Modifier settings === if not ob.modifiers: return active_mod_index = ob.ml_modifier_active_index active_mod = ob.modifiers[active_mod_index] all_modifier_names_icons_types = modifier_categories.all_modifier_names_icons_types active_mod_icon = [ icon for name, icon, mod in all_modifier_names_icons_types() if mod == active_mod.type ].pop() col = layout.column(align=True) # === General settings === box = col.box() if not prefs.hide_general_settings_region: row = box.row() sub = row.row() sub.alert = is_modifier_disabled(active_mod) sub.label(text="", icon=active_mod_icon) sub.prop(active_mod, "name", text="") sub = row.row(align=True) sub_sub = sub.row(align=True) sub_sub.scale_x = 1.1 # Hide visibility toggles for collision modifier as they are not used # in the regular UI either (apparently can cause problems in some scenes). if active_mod.type != 'COLLISION': sub_sub.prop(active_mod, "show_render", text="") sub_sub.prop(active_mod, "show_viewport", text="") mod_show_editmode_and_cage(active_mod, sub, scale_x=1.1) row = box.row() sub = row.row(align=True) if active_mod.type == 'PARTICLE_SYSTEM': ps = active_mod.particle_system if ps.settings.render_type in {'COLLECTION', 'OBJECT'}: sub.operator("object.duplicates_make_real", text="Convert") elif ps.settings.render_type == 'PATH': sub.operator("object.modifier_convert", text="Convert").modifier = active_mod.name else: sub.scale_x = 5 icon = pcoll['APPLY_MODIFIER'] sub.operator("object.ml_modifier_apply", text="", icon_value=icon.icon_id).modifier = active_mod.name if active_mod.type in modifier_categories.support_apply_as_shape_key: icon = pcoll['APPLY_MODIFIER_AS_SHAPEKEY'] sub.operator("object.ml_modifier_apply_as_shapekey", text="", icon_value=icon.icon_id).modifier = active_mod.name if active_mod.type not in modifier_categories.dont_support_copy: sub.operator("object.ml_modifier_copy", text="", icon='DUPLICATE').modifier = active_mod.name # === Gizmo object settings === if ob.type == 'MESH': if (active_mod.type in modifier_categories.have_gizmo_property or active_mod.type == 'UV_PROJECT'): gizmo_ob = get_gizmo_object() sub = row.row(align=True) sub.alignment = 'RIGHT' if not gizmo_ob: sub_sub = sub.row() sub_sub.scale_x = 4 icon = pcoll['ADD_GIZMO'] sub_sub.operator( "object.ml_gizmo_object_add", text="", icon_value=icon.icon_id).modifier = active_mod.name else: sub_sub = sub.row(align=True) sub_sub.scale_x = 1.2 depress = not gizmo_ob.hide_viewport sub_sub.operator("object.ml_gizmo_object_toggle_visibility", text="", icon='EMPTY_ARROWS', depress=depress) sub.popover("OBJECT_PT_Gizmo_object_settings", text="") # === Modifier specific settings === box = col.box() # A column is needed here to keep the layout more compact, # because in a box separators give an unnecessarily big space. col = box.column() # Some mofifiers require a custom layout because otherwise their # operators don't work. Lattice on the other hand has an improved # layout. have_custom_layout = ('CORRECTIVE_SMOOTH', 'DATA_TRANSFER', 'EXPLODE', 'HOOK', 'LAPLACIANDEFORM', 'LATTICE', 'MESH_DEFORM', 'MULTIRES', 'OCEAN', 'SKIN', 'SURFACE_DEFORM') if active_mod.type in have_custom_layout: getattr(ml_modifier_layouts, active_mod.type)(col, ob, active_mod) elif active_mod.type == 'REMESH' and str( bpy.app.build_branch) == "b'sculpt-mode-features'": ml_modifier_layouts.REMESH(col, ob, active_mod) else: mp = DATA_PT_modifiers(context) getattr(mp, active_mod.type)(col, ob, active_mod)
def unregister(): for cls in classes: unregister_class(cls) DATA_PT_modifiers.remove(draw_favorite_modifiers) DATA_PT_gpencil_modifiers.remove(draw_favorite_modifiers)
def modifiers_ui(context, layout, num_of_rows=False): # === Favourite modifiers === col = layout.column(align=True) # Check if an item or the next item in fav_name_icon_type has a value # and add rows and buttons accordingly (two buttons per row). fav_name_icon_type_iter = fav_name_icon_type() for name, icon, mod in fav_name_icon_type_iter: next_mod = next(fav_name_icon_type_iter) if name or next_mod[0] is not None: row = col.split(factor=0.5, align=True) if name is not None: row.operator("object.ml_modifier_add", text=name, icon=icon).modifier_type = mod else: row.label(text="") if next_mod[0] is not None: row.operator("object.ml_modifier_add", text=next_mod[0], icon=next_mod[1]).modifier_type = next_mod[2] else: row.label(text="") # === Modifier search and menu === col = layout.column() row = col.split(factor=0.59) wm = bpy.context.window_manager row.prop_search(wm, "mod_to_add", wm, "all_modifiers", text="", icon='MODIFIER') row.menu("OBJECT_MT_ml_add_modifier_menu") # === Modifier list === ob = context.object layout.template_list("OBJECT_UL_modifier_list", "", ob, "modifiers", ob, "modifier_active_index", rows=num_of_rows) row = layout.row() # === Modifier tools (from the addon) === is_loaded, is_enabled = addon_utils.check("space_view3d_modifier_tools") if is_loaded and is_enabled: sub = row.row(align=True) # Note: In 2.79, this is what scale 2.0 looks like. Here 2.0 causes list ordering # buttons to get tiny. 2.8 Bug? sub.scale_x = 1.5 pcoll = icons.preview_collections["main"] icon = pcoll['TOGGLE_ALL_MODIFIERS_VISIBILITY'] sub.operator("object.toggle_apply_modifiers_view", icon_value=icon.icon_id, text="") icon = pcoll['APPLY_ALL_MODIFIERS'] sub.operator("object.apply_all_modifiers", icon_value=icon.icon_id, text="") icon = pcoll['DELETE_ALL_MODIFIERS'] sub.operator("object.delete_all_modifiers", icon_value=icon.icon_id, text="") # === List manipulation === sub = row.row(align=True) # Note: In 2.79, this is what scale 2.0 looks like. Here 2.0 causes list ordering # buttons to get tiny. 2.8 Bug? sub.scale_x = 1.5 sub.alignment = 'RIGHT' sub.operator(OBJECT_OT_ml_modifier_move_up.bl_idname, icon='TRIA_UP', text="") sub.operator(OBJECT_OT_ml_modifier_move_down.bl_idname, icon='TRIA_DOWN', text="") sub.operator(OBJECT_OT_ml_modifier_remove.bl_idname, icon='REMOVE', text="") # === Modifier settings === ob = context.object if ob: if ob.modifiers: active_mod_index = ob.modifier_active_index active_mod = ob.modifiers[active_mod_index] active_mod_icon = [ icon for name, icon, mod in all_name_icon_type() if mod == active_mod.type ].pop() col = layout.column(align=True) # === General settings === box = col.box() row = box.row() sub = row.row() sub.label(text="", icon=active_mod_icon) sub.prop(active_mod, "name", text="") sub = row.row(align=True) sub_sub = sub.row(align=True) sub_sub.scale_x = 1.1 # Hide visibility toggles for collision modifier as they are not used # in the regular UI either (apparently can cause problems in some scenes). if active_mod.type != 'COLLISION': sub_sub.prop(active_mod, "show_render", text="") sub_sub.prop(active_mod, "show_viewport", text="") mod_show_editmode_and_cage(active_mod, sub, scale_x=1.1) row = box.row() row.operator("object.ml_modifier_apply", text="Apply").modifier = active_mod.name sub = row.row() # Cloth and Soft Body have "Apply As Shape Key" but no "Copy Modifier" . # In those cases "Apply As Shape Key" doesn't need to be scaled up. if active_mod.type not in {'CLOTH', 'SOFT_BODY'}: sub.scale_x = 1.3 deform_mods = { mod for name, icon, mod in all_name_icon_type()[26:42] } other_shape_key_mods = {'CLOTH', 'SOFT_BODY', 'MESH_CACHE'} has_shape_key = deform_mods.union(other_shape_key_mods) if active_mod.type in has_shape_key: apply_as_shape_key = sub.operator("object.ml_modifier_apply", text="Apply as Shape Key") apply_as_shape_key.modifier = active_mod.name apply_as_shape_key.apply_as = 'SHAPE' has_no_copy = { 'CLOTH', 'COLLISION', 'DYNAMIC_PAINT', 'FLUID_SIMULATION', 'PARTICLE_SYSTEM', 'SMOKE', 'SOFT_BODY' } if active_mod.type not in has_no_copy: row.operator("object.ml_modifier_copy", text="Copy").modifier = active_mod.name # === Modifier specific settings === box = col.box() # A column is needed here to keep the layout more compact, # because in a box separators give an unnecessarily big space. col = box.column() mp = DATA_PT_modifiers(context) getattr(mp, active_mod.type)(col, ob, active_mod)